Hi,
ich bin im Rahmen eines größeren Projektes mit AutoIt auf ein kleines Problem gestoßen. Konkret betrifft das das Thema Subclassing, also Veränderung der internen Nachrichtenverarbeitung eines Fensters (und damit Controls). Dazu gibt es grundsätzlich mehrere Möglichkeiten. Man kann einmal die Subclassing-API verwenden, man kann aber auch simpel über SetWindowLong die WndProc verändern (siehe Code). Ich präferiere eigentlich die zweitere Möglichkeit, weil die Subclassing-API bei mir immer mal wieder Probleme verursacht hat.
Nun stehe ich jedoch vor dem Problem, dass beim Ersetzen der WndProc scheinbar AutoIts internes Nachrichtenhandling nicht mehr greift. Das heißt, ich kriege weder im OnEvent-Modus noch über GUIGetMsg() irgendwelche Aktionen mit dem Control mit. Auch ein Minimalbeispiel zeigt, dass das Problem nur beim Ersetzen der WndProc auftritt, nicht beim Nutzen der Subclassing-API. In den jeweiligen WndProcs/SubclassingProcs kommt jedoch die entsprechende Klick-Nachricht korrekt an. Übersehe ich etwas, oder geht hier AutoIt-Intern was gewaltig schief?
#include <WinAPI.au3>
#include <WinAPIShellEx.au3>
#include <ButtonConstants.au3>
#include <WindowsConstants.au3>
Opt("GUIOnEventMode", True)
$hWnd = GUICreate("Subclassing Example", 600, 400)
GUISetOnEvent(-3, onClosePressed)
$cButton1 = GUICtrlCreateButton("Button 1" & @CRLF & "AutoIt Internal", 0, 0, 200, 200, $BS_MULTILINE)
GUICtrlSetOnEvent(-1, onButtonPressed)
$cButton2 = GUICtrlCreateButton("Button 2" & @CRLF & "Subclassing", 200, 0, 200, 200, $BS_MULTILINE)
GUICtrlSetOnEvent(-1, onButtonPressed)
$cButton3 = GUICtrlCreateButton("Button 3" & @CRLF & "Replaced WndProc", 400, 0, 200, 200, $BS_MULTILINE)
GUICtrlSetOnEvent(-1, onButtonPressed)
$cLog = GUICtrlCreateEdit("=== Action Log ===", 0, 200, 600, 200)
;subclassing
$hSCCB = DllCallbackRegister(subclassProc, "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr")
$pSCCB = DllCallbackGetPtr($hSCCB)
_WinAPI_SetWindowSubclass(GUICtrlGetHandle($cButton2), $pSCCB, 1000, 0)
;replacing wndproc
$hRWCB = DllCallbackRegister(wndProc, "lresult", "hwnd;uint;wparam;lparam")
$pRWCB = DllCallbackGetPtr($hRWCB)
$pOldWndProc = _WinAPI_GetWindowLong(GUICtrlGetHandle($cButton3), $GWL_WNDPROC)
_WinAPI_SetWindowLong(GUICtrlGetHandle($cButton3), $GWL_USERDATA, $pOldWndProc)
_WinAPI_SetWindowLong(GUICtrlGetHandle($cButton3), $GWL_WNDPROC, $pRWCB)
;exit routine to free resources
OnAutoItExitRegister(onExitApp)
GUISetState()
While True
Sleep(20)
WEnd
Func onClosePressed()
Exit
EndFunc
Func onButtonPressed()
writeLog("AutoIt: Button with ID " & @GUI_CtrlId & " pressed!")
EndFunc
Func onExitApp()
_WinAPI_RemoveWindowSubclass(GUICtrlGetHandle($cButton2), $pSCCB, 1000)
DllCallbackFree($hSCCB)
_WinAPI_SetWindowLong(GUICtrlGetHandle($cButton3), $GWL_WNDPROC, $pOldWndProc)
DllCallbackFree($hRWCB)
EndFunc
Func writeLog($s)
GUICtrlSetData($cLog, GUICtrlRead($cLog) & @CRLF & StringFormat("[%02d:%02d:%02d.%03d] %s", @HOUR, @MIN, @SEC, @MSEC, $s))
EndFunc
;external called functions
Func subclassProc($hWnd, $iMsg, $iWParam, $iLParam, $iID, $pData)
If $iMsg = $WM_LBUTTONDOWN Then writeLog("subclassProc: Button pressed")
Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $iWParam, $iLParam)
EndFunc
Func wndProc($hWnd, $iMsg, $iWParam, $iLParam)
If $iMsg = $WM_LBUTTONDOWN Then writeLog("wndProc: Button pressed")
$pOldWndProc = _WinAPI_GetWindowLong($hWnd, $GWL_USERDATA)
Return _WinAPI_CallWindowProc($pOldWndProc, $hWnd, $iMsg, $iWParam, $iLParam)
EndFunc
Alles anzeigen