Hi John, I don't have time to take a look at the code, but take a look at System.Runtime.InteropServices.HandleRef and GC.KeepAlive and see if you're having a premature GC problem.
Cheers, Stoyan On 7/7/06, John Whattam <[EMAIL PROTECTED]> wrote:
I have written a Combobox-based control for displaying all the raster and truetype fonts available on the user's system. It makes extensive use of the EnumFontFamiliesEx API for two purposes: 1.When InitialiseFontCombo is called in the dialog's load event, EnumFontFamiliesEx is called to enumerate all fonts on the system and determine which are raster and which are truetype. 2. When the user then selects a given font, I again call EnumFontFamiliesEx to retrieve all valid sizes, styles and scripts for the selected font name. The actual calls to EnumFontFamiliesEx appear to work well, giving back the expected information. To stress test this control, I ran a test whereby I looped through all 58 fonts listed on my system a total of 5000 times so that EnumFontFamiliesEx was called 300,000 times and the information collected by this call printed to the immediate window. This worked without problems however during use of the dialog, I occasionally get random errors – sometimes after 10 minutes of use and sometimes after hours of use. The FatalExecutionError exception MDA is displayed telling me I have a fatal error with code 0xC0000005 and the thread and therefore the application is then aborted. This always occurs on the call to EnumFontFamiliesEx for determining sizes, styles etc for the selected font. I have the following code: At the class level I have declared the API call itself and a delegate type for the callbacks as follows: Private Declare Auto Function EnumFontFamiliesEx Lib "gdi32.dll" (<InAttribute()> ByVal hdc As IntPtr, <InAttribute()> ByRef lpLogfont As LOGFONT, <InAttribute()> ByVal lpEnumFontFamExProc As EnumFontFamExProcDelegate, <InAttribute()> ByVal lParam As IntPtr, ByVal dwFlags As UInteger) As Integer Private Delegate Function EnumFontFamExProcDelegate(<InAttribute() > ByRef lpelfe As ENUMLOGFONTEXDV, <InAttribute()> ByRef lpntme As ENUMTEXTMETRIC, <InAttribute()> ByVal FontType As FontTypes, <InAttribute() > ByVal lParam As IntPtr) As Integer At the class level there are two delegate instances pointing to the appropriate functions to use for enumerating font names and font information: Private mEnumFontInfoCallback As EnumFontFamExProcDelegate = New EnumFontFamExProcDelegate(AddressOf EnumFontInfoCallback) Private mEnumFontNamesCallback As EnumFontFamExProcDelegate = New EnumFontFamExProcDelegate(AddressOf EnumFontNamesCallback) In the InitialiseFontCombo function I call to obtain the font names as follows (note I have removed all indenting): Private Sub GetAvailableNames() Dim pGraphics As Graphics = Nothing Dim phDC As IntPtr Dim pResult As Integer = 0 Dim pLogFont As LOGFONT = New LOGFONT Try pGraphics = Graphics.FromHwnd(MyBase.Handle) mVerticalResolution = pGraphics.DpiY phDC = pGraphics.GetHdc ' The following is a custom collection which stores font name and ' font type – raster or truetype. mFontInfo.Clear() ' Enumerate all fonts and all styles. With pLogFont .lfCharSet = CharSets.Default_CharSet .lfFaceName = Nothing .lfPitchAndFamily = 0 End With ' The callback function fills the collection with names and raster or truetype. pResult = EnumFontFamiliesEx(phDC, pLogFont, mEnumFontNamesCallback, IntPtr.Zero, 0) ' Then there is code to fill combobox from the collection. Finally If Not phDC.Equals(IntPtr.Zero) Then pGraphics.ReleaseHdc(phDC) End If If pGraphics IsNot Nothing Then pGraphics.Dispose() End If End Try End Sub In the SelectedIndexChanged event I call to obtain the font information for the selected font as follows: Private Overloads Sub GetAvailableFontInfo(ByVal FontName As String) Dim pLogFont As LOGFONT = New LOGFONT Dim pGraphics As Graphics = Nothing Dim phDC As IntPtr Dim pResult As Integer = 0 Dim pRegular As Boolean = False Dim pBold As Boolean = False Dim pItalic As Boolean = False Dim pBoldItalic As Boolean = False Try pGraphics = Graphics.FromHwnd(MyBase.Handle) mVerticalResolution = pGraphics.DpiY phDC = pGraphics.GetHdc ' Clear three class level arrays for holding iszes, styles and scripts. With pLogFont .lfCharSet = CharSets.Default_CharSet .lfPitchAndFamily = 0 .lfFaceName = FontName End With ' The callback fills arrays with all available font information including font styles, font sizes and available scripts. ' ***************** THIS IS WHERE IT STOPS ************************** pResult = EnumFontFamiliesEx(phDC, pLogFont, mEnumFontInfoCallback, IntPtr.Zero, 0) Finally If Not phDC.Equals(IntPtr.Zero) Then pGraphics.ReleaseHdc(phDC) End If If pGraphics IsNot Nothing Then pGraphics.Dispose() End If End Try End Sub For the life of me, I cannot figure out what is causing this error - I feel it may be either a timing issue or the GC is collecting a portion of the memory which the callback is using. Is there anything obviously wrong with what I am doing? Can anyone give me some pointers on how to go about solving this problem? Like I said, the error is random in nature and the MDA doesn't provide much information. Regards, John Whattam.
=================================== This list is hosted by DevelopMentor® http://www.develop.com View archives and manage your subscription(s) at http://discuss.develop.com