jugador Posted Thursday at 10:21 AM Posted Thursday at 10:21 AM (edited) GUIRegisterMsg20 is an extended version of GUIRegisterMsg, and GUIRegisterMsgEx is an extended version of GUIRegisterMsg20. Example A: #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include "GUIRegisterMsgEx.au3" __ExampleA() Func __ExampleA() Local $hGUI1 = GUICreate("Window A", 300, 200, 100, 100) GUISetState(@SW_SHOW, $hGUI1) Local $hGUI2 = GUICreate("Window B", 300, 200, 450, 100) GUISetState(@SW_SHOW, $hGUI2) GUIRegisterMsgEx($hGUI1, $WM_LBUTTONDOWN, __OnLeftClickWindowA) GUIRegisterMsgEx($hGUI2, $WM_LBUTTONDOWN, __OnLeftClickWindowB) While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE Exit EndSwitch WEnd GUIDelete($hGUI2) GUIDelete($hGUI1) EndFunc Func __OnLeftClickWindowA($hWnd, $iMsg, $wParam, $lParam, $iid, $Pdata) ConsoleWrite("-> Clicked on Window A! (Handle: " & $hWnd & ")" & @CRLF) Return 0xCAFEBABE EndFunc Func __OnLeftClickWindowB($hWnd, $iMsg, $wParam, $lParam, $iid, $Pdata) ConsoleWrite("-> Clicked on Window B! (Handle: " & $hWnd & ")" & @CRLF) Return 0xCAFEBABE EndFunc Example B: expandcollapse popup#include <GuiConstants.au3> #include <GuiHeader.au3> #include <WinAPI.au3> #include <Misc.au3> #include <WinAPITheme.au3> #include <GuiListView.au3> #include "GUIRegisterMsgEx.au3" AutoItSetOption("MustDeclareVars", 1) __ExampleB() Func __ExampleB() Local $hGUI = GUICreate("Header Subclass Framework Test", 500, 400) GUISetBkColor(0x000000) Local $idListView_A = GUICtrlCreateListView("Items List|SubItems1|SubItems2", 10, 10, 480, 150, $LVS_REPORT, _ BitOR($LVS_EX_DOUBLEBUFFER, $LVS_EX_FULLROWSELECT, $LVS_EX_HEADERDRAGDROP)) GUICtrlSetBkColor($idListView_A, 0x121212) GUICtrlSetColor($idListView_A, 0xFFFFFF) Local $hListView_A = GUICtrlGetHandle($idListView_A) Local $hHeader_A = _GUICtrlListView_GetHeader($hListView_A) GUICtrlCreateListViewItem("item_A1|item_B1|item_C1", $idListView_A) GUICtrlCreateListViewItem("item_A2|item_B2|item_C2", $idListView_A) GUICtrlCreateListViewItem("item_A3|item_B3|item_C3", $idListView_A) _GUICtrlListView_SetColumnWidth($idListView_A, 2, $LVSCW_AUTOSIZE_USEHEADER) GUIRegisterMsgEx($hListView_A, $WM_NOTIFY, "MY_WM_NOTIFY", $hHeader_A) GUIRegisterMsgEx($hHeader_A, $WM_MOUSEMOVE, "MY_WM_NOTIFY", $hHeader_A) GUIRegisterMsgEx($hHeader_A, $WM_MOUSELEAVE, "MY_WM_NOTIFY", $hHeader_A) GUISetState(@SW_SHOW, $hGUI) Do Until GUIGetMsg() = $GUI_EVENT_CLOSE GUIDelete($hGUI) EndFunc Func MY_WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam, $iID, $pData) Local Static $bHover = False, $tPoint Local $hBrush Switch $iMsg Case $WM_NOTIFY Local $tNMHDR = DllStructCreate($tagNMHDR, $lParam) Local $hFrom = $tNMHDR.hWndFrom Switch $tNMHDR.Code Case $NM_CUSTOMDRAW If _WinAPI_GetClassName($hFrom) = "sysheader32" Then Local $tCustDraw = DllStructCreate($tagNMLVCUSTOMDRAW, $lParam) Switch $tCustDraw.dwDrawStage Case $CDDS_PREPAINT Return $CDRF_NOTIFYITEMDRAW Case $CDDS_ITEMPREPAINT Local $tRect = DllStructCreate($tagRECT, DllStructGetPtr($tCustDraw, "Left")) _WinAPI_SetBkMode($tCustDraw.hDC, 1) _WinAPI_SetTextColor($tCustDraw.hDC, 0xFFFFFF) If $bHover And _WinAPI_PtInRect($tRect, $tPoint) Then $hBrush = _WinAPI_CreateSolidBrush(_IsPressed(0x01) ? 0x00008B : 0x0000FF) Else $hBrush = _WinAPI_CreateSolidBrush(0x202020) EndIf _WinAPI_InflateRect($tRect, -1, 0) _WinAPI_FillRect($tCustDraw.hDC, $tRect, $hBrush) _WinAPI_DeleteObject($hBrush) _WinAPI_InflateRect($tRect, -5, -2) GUIRegisterMsgEx_Bypass($tCustDraw.hWndFrom, True) ;~~ same as doing _WinAPI_RemoveWindowSubclass() to prevent crashes.... Local $text = _GUICtrlHeader_GetItemText($tCustDraw.hWndFrom, $tCustDraw.dwItemSpec) GUIRegisterMsgEx_Bypass($tCustDraw.hWndFrom, False, $pData) ;~~ same as doing _WinAPI_SetWindowSubclass() _WinAPI_DrawText($tCustDraw.hDC, $text, $tRect, BitOR($DT_LEFT, $DT_NOCLIP)) Return $CDRF_SKIPDEFAULT EndSwitch EndIf EndSwitch Case $WM_MOUSEMOVE If $pData = $hWnd Then $bHover = True $tPoint = _WinAPI_GetMousePos(True, $hWnd) _WinAPI_InvalidateRect($hWnd, 0, False) _WinAPI_TrackMouseEvent($hWnd, $TME_LEAVE) EndIf Case $WM_MOUSELEAVE If $pData = $hWnd Then $bHover = False _WinAPI_InvalidateRect($hWnd, 0, False) EndIf EndSwitch Return 0xCAFEBABE EndFunc GUIRegisterMsgEx.au3 Edited 9 hours ago by jugador pixelsearch and WildByDesign 1 1
WildByDesign Posted Thursday at 10:51 AM Posted Thursday at 10:51 AM This is really neat. I do feel like if you are extending something, you should give a few points about what has been improved over the previous UDF. I like the technique that you use with $__g_bThreadLocked to call DefSubclassProc if the procedure is still within the user function/proc. This is clearly intended to prevent subclass procedure lockups/crashes. Very smart. The GUIRegisterMsgEx_Bypass() is nice too. I assume this was related to the subclass crashes that we talked about before with the Header. I'm glad that you found a way to avoid those subclass lockups.
jugador Posted 9 hours ago Author Posted 9 hours ago (edited) @WildByDesign I used $__g_bThreadLocked as an extra precautionary measure. The code runs fine without it and shows no abnormalities. Need to remove $__g_bThreadLocked or else _DateProc will not work. also changed "GUI_RUNDEFMSG" to 0xCAFEBABE in this version. Example C: expandcollapse popup;~ https://www.autoitscript.com/forum/topic/213268-samplecontrolsau3-in-dark-mode/ #include <WindowsConstants.au3> #include <GuiConstants.au3> #include <GuiDateTimePicker.au3> #include <GuiMonthCal.au3> #include <WinAPI.au3> #include <WinAPISysWin.au3> #include <WinAPITheme.au3> #include "GUIRegisterMsgEx.au3" Opt("MustDeclareVars", True) Global Const $PRF_CLIENT = 0x0004, $COLOR_BORDER = 0x404040, $COLOR_BG_DARK = 0x202020, $COLOR_TEXT_LIGHT = 0xFFFFFF, $COLOR_BORDER_LIGHT = 0xD8D8D8 Global $g_bHover = False __ExampleC() Func __ExampleC() Local $hGUI = GUICreate("Sample GUI", 400, 240) Local $idDate = GUICtrlCreateDate("", 15, 15, 200, 24) Local $hDate = GUICtrlGetHandle($idDate) GUIRegisterMsgEx($hGUI, $WM_NOTIFY, "_WM_NOTIFY") GUIRegisterMsgEx($hDate, $WM_PAINT, "_DateProc") GUIRegisterMsgEx($hDate, $WM_ERASEBKGND, "_DateProc") GUIRegisterMsgEx($hDate, $WM_SETFOCUS, "_DateProc") GUIRegisterMsgEx($hDate, $WM_KILLFOCUS, "_DateProc") GUIRegisterMsgEx($hDate, $WM_MOUSEMOVE, "_DateProc") GUIRegisterMsgEx($hDate, $WM_MOUSELEAVE, "_DateProc") GUISetState() While True Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd GUIDelete() EndFunc ;==>Example Func _DateProc($hWnd, $iMsg, $wParam, $lParam, $iid, $Pdata) Switch $iMsg Case $WM_PAINT Local $tPaint = DllStructCreate($tagPAINTSTRUCT) Local $hDC = _WinAPI_BeginPaint($hWnd, $tPaint) Local $tClient = _WinAPI_GetClientRect($hWnd) Local $iW = $tClient.Right Local $iH = $tClient.Bottom ; --- Memory DC for flicker-free rendering --- Local $hMemDC = _WinAPI_CreateCompatibleDC($hDC) Local $hBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $iW, $iH) Local $hOldBmp = _WinAPI_SelectObject($hMemDC, $hBitmap) ; 1. Let Windows draw the light-mode control into memory DC _WinAPI_DefSubclassProc($hWnd, $WM_PRINTCLIENT, $hMemDC, $PRF_CLIENT) ; 2. Invert all pixels (background becomes black, text white, selection orange) Local $tRect = DllStructCreate($tagRECT) $tRect.right = $iW $tRect.bottom = $iH _WinAPI_InvertRect($hMemDC, $tRect) ; --- 3. PIXEL HACK: destroy orange highlight & set background color --- Local $iSize = $iW * $iH Local $tPixels = DllStructCreate("dword c[" & $iSize & "]") ; Load pixel array directly from bitmap memory Local $iBytes = DllCall("gdi32.dll", "long", "GetBitmapBits", "handle", $hBitmap, "long", $iSize * 4, "ptr", DllStructGetPtr($tPixels))[0] If $iBytes = $iSize * 4 Then Local $iPixel, $r, $g, $b, $iGray For $i = 1 To $iSize $iPixel = $tPixels.c(($i)) ; Split into color channels $b = BitAND($iPixel, 0xFF) $g = BitAND(BitShift($iPixel, 8), 0xFF) $r = BitAND(BitShift($iPixel, 16), 0xFF) ; Convert to grayscale (orange becomes mid-gray) $iGray = Int(($r + $g + $b) / 3) ; Very dark pixel = inverted white background If $iGray < 15 Then $iPixel = $COLOR_BG_DARK ; Replace with exact GUI background color Else ; Grayscale value for text (white) and selection (gray) $iPixel = BitOR(BitShift($iGray, -16), BitShift($iGray, -8), $iGray) EndIf $tPixels.c(($i)) = $iPixel Next ; Write cleaned pixels back into the bitmap DllCall("gdi32.dll", "long", "SetBitmapBits", "handle", $hBitmap, "long", $iSize * 4, "ptr", DllStructGetPtr($tPixels)) EndIf ; --- END PIXEL HACK --- ; --- Border color (hover effect) --- Local $iBorderColor = $COLOR_BORDER If _WinAPI_GetFocus() = $hWnd Then $iBorderColor = $COLOR_BORDER Local $tCursorPos = DllStructCreate($tagPOINT) DllCall("user32.dll", "bool", "GetCursorPos", "struct*", $tCursorPos) DllCall("user32.dll", "bool", "ScreenToClient", "hwnd", $hWnd, "struct*", $tCursorPos) If $tCursorPos.X >= 0 And $tCursorPos.X <= $iW And $tCursorPos.Y >= 0 And $tCursorPos.Y <= $iH Then $iBorderColor = $COLOR_BORDER_LIGHT EndIf ; --- Draw border --- Local $hPen = _WinAPI_CreatePen(0, 1, _ColorToCOLORREF($iBorderColor)) Local $hNullBr = _WinAPI_GetStockObject(5) Local $hOldPen = _WinAPI_SelectObject($hMemDC, $hPen) Local $hOldBr = _WinAPI_SelectObject($hMemDC, $hNullBr) DllCall("gdi32.dll", "bool", "Rectangle", "handle", $hMemDC, "int", 0, "int", 0, "int", $iW, "int", $iH) _WinAPI_SelectObject($hMemDC, $hOldPen) _WinAPI_SelectObject($hMemDC, $hOldBr) _WinAPI_DeleteObject($hPen) ; --- Copy finished result to screen in one step (no flicker) --- _WinAPI_BitBlt($hDC, 0, 0, $iW, $iH, $hMemDC, 0, 0, $SRCCOPY) ; --- Cleanup --- _WinAPI_SelectObject($hMemDC, $hOldBmp) _WinAPI_DeleteObject($hBitmap) _WinAPI_DeleteDC($hMemDC) _WinAPI_EndPaint($hWnd, $tPaint) Return 0 Case $WM_ERASEBKGND Return 1 Case $WM_SETFOCUS, $WM_KILLFOCUS _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) _WinAPI_InvalidateRect($hWnd, 0, False) Return 0 Case $WM_MOUSEMOVE _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) If Not $g_bHover Then $g_bHover = True _WinAPI_InvalidateRect($hWnd, 0, False) EndIf Return 0 Case $WM_MOUSELEAVE $g_bHover = False _WinAPI_InvalidateRect($hWnd, 0, False) EndSwitch Return 0xCAFEBABE EndFunc ;==>_DateProc Func _WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam, $iid, $Pdata) Local $tNMHDR = DllStructCreate($tagNMHDR, $lParam) Local $hWndFrom = HWnd($tNMHDR.hWndFrom) Local $iCode = $tNMHDR.Code If _WinAPI_GetClassName($hWndFrom) = "SysDateTimePick32" Then Switch $iCode Case $NM_SETFOCUS _WinAPI_SetThemeAppProperties(0) Case $DTN_DROPDOWN _WinAPI_SetWindowTheme($hWndFrom, "", "") _SendMessage($hWndFrom, $DTM_SETMCCOLOR, 4, $COLOR_BG_DARK) Local $iCtrl = _GUICtrlDTP_GetMonthCal($hWndFrom) _GUICtrlMonthCal_SetColor($iCtrl, $MCSC_TEXT, $COLOR_TEXT_LIGHT) _GUICtrlMonthCal_SetColor($iCtrl, $MCSC_TITLEBK, $COLOR_BG_DARK) _GUICtrlMonthCal_SetColor($iCtrl, $MCSC_TITLETEXT, $COLOR_TEXT_LIGHT) _GUICtrlMonthCal_SetColor($iCtrl, $MCSC_MONTHBK, $COLOR_BG_DARK) _GUICtrlMonthCal_SetColor($iCtrl, $MCSC_TRAILINGTEXT, $COLOR_TEXT_LIGHT) EndSwitch EndIf Return 0xCAFEBABE EndFunc ;==>_WM_NOTIFY Func _ColorToCOLORREF($iColor) ;RGB to BGR Local $iR = BitAND(BitShift($iColor, 16), 0xFF) Local $iG = BitAND(BitShift($iColor, 8), 0xFF) Local $iB = BitAND($iColor, 0xFF) Return BitOR(BitShift($iB, -16), BitShift($iG, -8), $iR) EndFunc ;==>_ColorToCOLORREF Example D: expandcollapse popup;~ https://www.autoitscript.com/forum/topic/212545-resizable-dragable-windows-controls/page/2/#findComment-1539579 #include <guiConstants.au3> #include <winapi.au3> #include <MenuConstants.au3> #include "GUIRegisterMsgEx.au3" Opt("MustDeclareVars", True) Global $bRestore __ExampleD() Func __ExampleD() Local $hGUI = GUICreate("WM_NCHITTEST", 300, 200, -1, -1, $WS_OVERLAPPEDWINDOW) Local $idBtn = GUICtrlCreateButton("Button 1", 4, 4, 80, 80, $WS_CLIPSIBLINGS) Local $idBtn2 = GUICtrlCreateButton("Button 2", 90, 4, 80, 80, $WS_CLIPSIBLINGS) Local $idLockButtons = GUICtrlCreateCheckbox("Lock Buttons", 200, 20, 80, 20) GUIRegisterMsgEx($hGUI, $WM_SYSCOMMAND, "WM_SYSCOMMAND") GUIRegisterMsgEx($idBtn, $WM_NCHITTEST, "ButtonMoveProc") GUIRegisterMsgEx($idBtn, $WM_SETCURSOR, "ButtonMoveProc") GUIRegisterMsgEx($idBtn, $WM_WINDOWPOSCHANGING, "ButtonMoveProc", $hGUI) GUIRegisterMsgEx($idBtn2, $WM_NCHITTEST, "ButtonMoveProc") GUIRegisterMsgEx($idBtn2, $WM_SETCURSOR, "ButtonMoveProc") GUIRegisterMsgEx($idBtn2, $WM_WINDOWPOSCHANGING, "ButtonMoveProc", $hGUI) GUISetState() Local $iMsg While True $iMsg = GUIGetMsg() Switch $iMsg Case $GUI_EVENT_CLOSE ExitLoop Case $idLockButtons If GUICtrlRead($iMsg) = $GUI_CHECKED Then ; True to disable GUIRegisterMsgEx_Bypass($idBtn, True) GUIRegisterMsgEx_Bypass($idBtn2, True) Else ; False to re-enable GUIRegisterMsgEx_Bypass($idBtn, False) GUIRegisterMsgEx_Bypass($idBtn2, False) EndIf Case $idBtn, $idBtn2 ConsoleWrite("Click " & GUICtrlRead($iMsg) & @CRLF) Case $GUI_EVENT_RESTORE $bRestore = False EndSwitch WEnd GUIDelete() EndFunc ;==>Example Func ButtonMoveProc($hWnd, $iMsg, $wParam, $lParam, $iid, $Pdata) Local $tPos, $aPos, $iRet, $aPoint[2], $iSrc, $iEvent, $hCursor Switch $iMsg Case $WM_NCHITTEST $aPos = WinGetPos($hWnd) $aPoint[0] = BitAND($lParam, 0xFFFF) $aPoint[1] = BitShift($lParam, 16) $iRet = $HTCAPTION If $aPoint[0] - $aPos[0] < 10 Then $iRet = $HTLEFT If $aPoint[0] - $aPos[0] > ($aPos[2] - 10) Then $iRet = $HTRIGHT If $aPoint[1] - $aPos[1] < 10 Then Switch $iRet Case $HTLEFT $iRet = $HTTOPLEFT Case $HTRIGHT $iRet = $HTTOPRIGHT Case Else $iRet = $HTTOP EndSwitch ElseIf $aPoint[1] - $aPos[1] > ($aPos[3] - 10) Then Switch $iRet Case $HTLEFT $iRet = $HTBOTTOMLEFT Case $HTRIGHT $iRet = $HTBOTTOMRIGHT Case Else $iRet = $HTBOTTOM EndSwitch EndIf Return $iRet Case $WM_SETCURSOR $iSrc = BitAND($lParam, 0xFFFF) $iEvent = BitShift($lParam, 16) If $iSrc = $HTCAPTION And $iEvent = $WM_LBUTTONDOWN Then _WinAPI_RedrawWindow($hWnd, 0, 0, $RDW_INVALIDATE + $RDW_FRAME) $hCursor = _WinAPI_LoadCursor(0, $OCR_SIZEALL) _WinAPI_SetCursor($hCursor) Return True EndIf Case $WM_WINDOWPOSCHANGING If $bRestore Then ConsoleWrite("WM_WINDOWPOSCHANGING" & @CRLF) $tPos = DllStructCreate($tagWINDOWPOS, $lParam) $aPos = ControlGetPos($Pdata, "", $hWnd) ConsoleWrite($aPos[0] & "/" & $aPos[1] & "/" & $aPos[2] & "/" & $aPos[3] & @CRLF) $tPos.X = $aPos[0] $tPos.Y = $aPos[1] $tPos.CX = $aPos[2] $tPos.CY = $aPos[3] Return 0 EndIf EndSwitch Return 0xCAFEBABE EndFunc ;==>ButtonMoveProc Func WM_SYSCOMMAND($hWnd, $iMsg, $wParam, $lParam, $iid, $Pdata) If $wParam = $SC_RESTORE Then ConsoleWrite("---Start Restore---" & @CRLF) $bRestore = True EndIf Return 0xCAFEBABE EndFunc ;==>WM_SYSCOMMAND Edited 8 hours ago by jugador WildByDesign 1
argumentum Posted 8 hours ago Posted 8 hours ago 34 minutes ago, jugador said: also changed "GUI_RUNDEFMSG" to 0xCAFEBABE in this version. ..would that be a reference to @0xC0FFEE or @0xcafebabe 🤔 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
WildByDesign Posted 7 hours ago Posted 7 hours ago (edited) 1 hour ago, jugador said: I used $__g_bThreadLocked as an extra precautionary measure. The code runs fine without it and shows no abnormalities I was shocked by how often it would hit $__g_bThreadLocked when I tried it with GUIDarkTheme UDF. It hit it often enough to cause flickering of controls. Sometimes they would be left with light mode color. Especially the WM_CTLCOLOR* messages. In particular, it would hit it constantly during GUI resizing. AutoIt does not handle GUI resizing very well in general even without subclassing. Edited 7 hours ago by WildByDesign jugador 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