WildByDesign Posted Tuesday at 11:09 PM Posted Tuesday at 11:09 PM I'm using _WinAPI_CreateFontIndirect and DllStructCreate($tagLOGFONT) within $WM_PAINT and $WM_DRAWITEM to continuously create fonts of various fonts from the ChooseFont dialog. So they are repeatedly creating these fonts. I am deleting the fonts after each is drawn with _WinAPI_DrawText and also my own _WinAPI_ExtTextOut function using _WinAPI_DeleteObject($hFont). My question refers to DllStructCreate and whether or not I need to be cleaning up after those. My LOGFONT code looks like this: Local $tFont = DllStructCreate($tagLOGFONT) $tFont.FaceName = $sFont $tFont.Height = -(9 * _WinAPI_GetDeviceCaps($hDC, $LOGPIXELSY) / 72) $tFont.CharSet = $iCharset $tFont.Italic = $bItalic $tFont.Underline = 0 $tFont.Weight = 400 $hFont = _WinAPI_CreateFontIndirect($tFont) $hOldFont = _WinAPI_SelectObject($hDC, $hFont) It gets followed up by _WinAPI_DrawText or my own _WinAPI_ExtTextOut function depending on the situation. The docs for DllStructCreate suggest cleaning up the resources after: ; Release the resources used by the structure. $tSTRUCT1 = 0 In my case, that would be $tFont. Should I be releasing this DllStruct LOGFONT resource at the end of each $WM_PAINT and $WM_DRAWITEM cycle? Thank you for your time.
WildByDesign Posted Tuesday at 11:14 PM Author Posted Tuesday at 11:14 PM (edited) Oh by the way, if anyone has any need for the _WinAPI_ExtTextOut() function, it performs much faster than _WinAPI_DrawText. Particularly in the case of the ChooseFont dialog where it is constantly drawing hundreds of unique fonts. But keep in mind that you might need to do some magic with _WinAPI_SetTextAlign first because it utilizes the alignment set by that function. Enjoy! Func _WinAPI_ExtTextOut($hDC, $iX, $iY, $iOptions, $sText, $tRECT = 0) Local $iLength = StringLen($sText) ; Pointer to the RECT structure, or NULL if no RECT is passed Local $pRECT = 0 If IsDllStruct($tRECT) Then $pRECT = DllStructGetPtr($tRECT) Local $aResult = DllCall("gdi32.dll", "bool", "ExtTextOutW", _ "handle", $hDC, _ "int", $iX, _ "int", $iY, _ "uint", $iOptions, _ "ptr", $pRECT, _ "wstr", $sText, _ "uint", $iLength, _ "ptr", 0) ; lpDx array is omitted (NULL) If @error Or Not $aResult[0] Then Return SetError(1, 0, False) Return True EndFunc ;==>_WinAPI_ExtTextOut Edited Tuesday at 11:14 PM by WildByDesign
Solution MattyD Posted Wednesday at 01:30 AM Solution Posted Wednesday at 01:30 AM 1 hour ago, WildByDesign said: Should I be releasing this DllStruct LOGFONT resource at the end of each $WM_PAINT and $WM_DRAWITEM cycle? Nah, as long as the $tLogfont is local to the func it will release automatically when it goes out of scope. If possible, I'd try to reuse fonts rather than creating/releasing every time WM_PAINT is called. Maybe keep them as a local static until something changes . WildByDesign 1
WildByDesign Posted Wednesday at 09:47 AM Author Posted Wednesday at 09:47 AM 7 hours ago, MattyD said: Nah, as long as the $tLogfont is local to the func it will release automatically when it goes out of scope. Thanks for confirming, Matty. I don't think that I've ever seen anybody zero out the struct like that before which is why I was confused when I saw that in the docs. That makes sense that it releases automatically once it goes out of scope. 8 hours ago, MattyD said: If possible, I'd try to reuse fonts rather than creating/releasing every time WM_PAINT is called. Maybe keep them as a local static until something changes . I agree with you. That would help overall performance and efficiency as well. But the problem is that I'm not sure exactly how to do that. I don't install any extra fonts and yet my ChooseFont dialog shows something like 177 fonts. The font handles could be stored in an array but I ran into a problem there. I had successfully created an array that as populated by _GUICtrlComboBox_GetListArray() from the Font combo which is where I got the 177 count from. I added a second column to the array for CHARSET because I needed that to reference quickly. So I could also add a third column for font handles. But realistically, that 177 font count would go way up because it has to account for all of the styles from the Font Styles combo for each font. Anyway, $WM_PAINT was able to keep up with the array easily because $WM_PAINT only got hit up once anytime you made a change. The problem was $WM_DRAWITEM is so busy in a ChooseFont dialog that it can't keep up with the array. If I added a simple: ConsoleWrite("value: " & $array[$i][1]) - $i being the itemID - it would successfully get the value from the array about a dozen times and then the subclass would lockup. I don't think that AutoIt can handle accessing an array and $WM_DRAWITEM at the same time when $WM_DRAWITEM is already quite busy. I think it hammers 10-12 fonts at a time. Basically, whatever is in view within the ComboLBox at the time gets put through $WM_DRAWITEM from what I can tell. And I'm pretty sure that any single change in the Fonts combo also fires of $WM_DRAWITEM for the Font Styles and Size combos as well. So that would be closer to 20 fonts per click or possibly more. Do you have any ideas for how to store that many font handles? Would a map be faster than an array in this case? I should note that AutoIt is actually handling this quite smoothly (without the array). For some reason, my dark mode ChooseFont renders faster, smoother and aligned better in comparison to Microsoft's own ChooseFont. I was not expecting that at all, but I'll take it.
WildByDesign Posted Wednesday at 09:56 AM Author Posted Wednesday at 09:56 AM By the way, I ended up discovering a clever way to deal with the $CBS_OWNERDRAWFIXED for each of the comboboxes from ChooseFont. I had originally thought that I would have to use a custom dialog template. But I quickly realized that since Microsoft already had $CBS_OWNERDRAWFIXED set, I could simply just handle $WM_DRAWITEM. Sure enough, we got the message as well. I could handle it and make it dark since we got the message first. The system handling ChooseFont got $WM_DRAWITEM second and would undo any of my dark mode changes. That is when I realized that if I Return 1 (instead of returning default), it blocks the system from ever getting the $WM_DRAWITEM message. Therefore, I get to handle all of the drawing and the dark mode changes persist.
WildByDesign Posted Wednesday at 10:51 AM Author Posted Wednesday at 10:51 AM 1 hour ago, WildByDesign said: The problem was $WM_DRAWITEM is so busy in a ChooseFont dialog that it can't keep up with the array. If I added a simple: ConsoleWrite("value: " & $array[$i][1]) - $i being the itemID - it would successfully get the value from the array about a dozen times and then the subclass would lockup. I don't think that AutoIt can handle accessing an array and $WM_DRAWITEM at the same time when $WM_DRAWITEM is already quite busy. I just wanted to clarify that I made the mistake on this part when accessing the array. I just realized that now. I have the following line to filter out "itemID" with -1 value: If $iID = -1 Then Return __WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) I made the mistake of trying to get data from the array before that line. So my array $i value was getting hit with -1 which clearly does not exist and likely was the source of locking up the subclass. I should have accessed the array just after that line. Now the array is working. MattyD 1
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now