pixelsearch Posted October 19, 2022 Share Posted October 19, 2022 Hi everybody I'd like to share with you a little problem I had with the WM_ACTIVATEAPP message when used in AutoIt, because of a possible missing function (maybe it's there but I didn't find it) WM_ACTIVATEAPP message (msdn) : Sent when a window belonging to a different application than the active window is about to be activated. The message is sent to the application whose window is being activated and to the application whose window is being deactivated. expandcollapse popup#include <MsgBoxConstants.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <WinAPISysWin.au3> Example() Func Example() Local $hGUI = GUICreate("Testing WM_ACTIVATEAPP", 400, 60, -1, -1, $WS_OVERLAPPEDWINDOW) Local $idButton_1 = GUICtrlCreateButton("Button 1", 100, 15, 80, 25) Local $idButton_Close = GUICtrlCreateButton("Close", 215, 15, 80, 25) ConsoleWrite("$hGUI = " & $hGUI & @crlf & @crlf) GUIRegisterMsg($WM_ACTIVATEAPP, "WM_ACTIVATEAPP") GUISetState(@SW_SHOW, $hGUI) While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $idButton_Close ExitLoop Case $idButton_1 MsgBox($MB_TOPMOST, "Title", "Button_1 pressed") EndSwitch WEnd GUIDelete($hGUI) EndFunc ;==>Example ;================================================= Func WM_ACTIVATEAPP($hWnd, $iMsg, $wParam, $lParam) Local Static $iCount $iCount += 1 ConsoleWrite($iCount & " WM_ACTIVATEAPP : $hWnd = " & $hWnd & " $wParam = " & $wParam & " $lParam = " & $lParam & @crlf) Local $aData = _WinAPI_EnumThreadWindows($lParam) ; personal function If $lParam <> 0 And IsArray($aData) Then For $i = 1 To UBound($aData) - 1 ; no need of row 0 (contains the number of results) ConsoleWrite("0x" & Hex($aData[$i][0], 8) & " " & $aData[$i][1] & _ " " & WinGetTitle(HWnd($aData[$i][0])) & @crlf) Next ConsoleWrite(@crlf) EndIf Return $GUI_RUNDEFMSG EndFunc ;==>WM_ACTIVATEAPP ;================================================= Func _WinAPI_EnumThreadWindows($idThread, $bVisible = True) Local $hEnumProc = DllCallbackRegister('__EnumWindowsProc', 'bool', 'dword;lparam') ; note: _WinAPI_EnumChildWindows (in WinAPISysWin.au3) uses the same callback function __EnumWindowsProc (in WinAPIInternals.au3) Dim $__g_vEnum[101][2] = [[0]] DllCall('user32.dll', 'bool', 'EnumThreadWindows', 'dword', $idThread, 'ptr', DllCallbackGetPtr($hEnumProc), 'lparam', $bVisible) If @error Or Not $__g_vEnum[0][0] Then $__g_vEnum = @error + 10 EndIf DllCallbackFree($hEnumProc) If $__g_vEnum Then Return SetError($__g_vEnum, 0, 0) __Inc($__g_vEnum, -1) ; function __Inc found in WinAPIInternals.au3 Return $__g_vEnum EndFunc ;==>_WinAPI_EnumThreadWindows Wh en the preceding script is run from Scite, I have 3 visible windows on the desktop as you can see in the 1st pic above : 1) Scite (its console mainly) 2) The GUI created by the script (GUI handle = 0x0062062A) 3) The AutoIt help file (squeezed !) The 3 clicks which activated the 3 WM_ACTIVATEAPP messages are : 1) Click on Scite menu => Tools => Go (to execute the script) : 1 WM_ACTIVATEAPP : $hWnd = 0x0062062A $wParam = 0x00000001 $lParam = 0x00000954 0x000F056A SciTEWindow C:\Temp8\329c.au3 - SciTE-Lite 2) Now that the GUI is active, click on AutoIt help file Window : 2 WM_ACTIVATEAPP : $hWnd = 0x0062062A $wParam = 0x00000000 $lParam = 0x00000D28 0x007B06CC HH Parent AutoIt Help (v3.3.14.5) 3) Now that AutoIt help file Window is active, click back on the GUI and make it active : 3 WM_ACTIVATEAPP : $hWnd = 0x0062062A $wParam = 0x00000001 $lParam = 0x00000000 My issue is that $lparam corresponds to a thread ID. But how to get the handle corresponding to this thread ID (and then the corresponding Windows title) in AutoIt ? As I didn't find an AutoIt function for that, I tried to create one in the script, named _WinAPI_EnumThreadWindows(), that's how we see in AutoIt console the corresponding handle, class name and Window title of the external applications for the first 2 WM_ACTIVATEAPP (when $lParam <> 0) The 2nd pic above (WinLister) is a freeware from NirSoft (those guys got incredible freeware stuff since ages) and it shows that the results of the function _WinAPI_EnumThreadWindows() seem correct. So my question is : does AutoIt have already a way to link a thread ID to a handle ? If yes, then the function _WinAPI_EnumThreadWindows() wasn't needed in the script. For the record, I used the existing _WinAPI_EnumChildWindows() as a guide to script _WinAPI_EnumThreadWindows(), replacing for example the [in] HWND parameter found in _WinAPI_EnumChildWindows() with [in] DWORD ThreadId as found in the msdn EnumThreadWindows link Please advise if you think something is wrong in the function _WinAPI_EnumThreadWindows() found in the preceding script. Thanks for reading ! Link to comment Share on other sites More sharing options...
KaFu Posted October 19, 2022 Share Posted October 19, 2022 How about this? expandcollapse popup#include <MsgBoxConstants.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <WinAPISysWin.au3> Example() Func Example() Local $hGUI = GUICreate("Testing WM_ACTIVATEAPP", 400, 60, -1, -1, $WS_OVERLAPPEDWINDOW) Local $idButton_1 = GUICtrlCreateButton("Button 1", 100, 15, 80, 25) Local $idButton_Close = GUICtrlCreateButton("Close", 215, 15, 80, 25) ConsoleWrite("$hGUI = " & $hGUI & @CRLF & @CRLF) GUIRegisterMsg($WM_ACTIVATEAPP, "WM_ACTIVATEAPP") GUISetState(@SW_SHOW, $hGUI) While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $idButton_Close ExitLoop Case $idButton_1 MsgBox($MB_TOPMOST, "Title", "Button_1 pressed") EndSwitch WEnd GUIDelete($hGUI) EndFunc ;==>Example ;================================================= Func WM_ACTIVATEAPP($hWnd, $iMsg, $wParam, $lParam) Local Static $iCount $iCount += 1 ConsoleWrite($iCount & " WM_ACTIVATEAPP : $hWnd = " & $hWnd & " $wParam = " & $wParam & " $lParam = " & $lParam & @CRLF) Local $hWnd_Active = WinGetHandle("[ACTIVE]", "") ConsoleWrite($hWnd_Active & @TAB & WinGetTitle($hWnd_Active) & @CRLF) Return $GUI_RUNDEFMSG EndFunc ;==>WM_ACTIVATEAPP pixelsearch 1 OS: Win10-22H2 - 64bit - German, AutoIt Version: 3.3.16.1, AutoIt Editor: SciTE, Website: https://funk.eu AMT - Auto-Movie-Thumbnailer (2024-Oct-13) BIC - Batch-Image-Cropper (2023-Apr-01) COP - Color Picker (2009-May-21) DCS - Dynamic Cursor Selector (2024-Oct-13) HMW - Hide my Windows (2024-Oct-19) HRC - HotKey Resolution Changer (2012-May-16) ICU - Icon Configuration Utility (2018-Sep-16) SMF - Search my Files (2024-Oct-20) - THE file info and duplicates search tool SSD - Set Sound Device (2017-Sep-16) Link to comment Share on other sites More sharing options...
KaFu Posted October 19, 2022 Share Posted October 19, 2022 Here's a version that even works if the AutoIt window is not involved. expandcollapse popup#include <GuiMenu.au3> #include <SendMessage.au3> #include <WinAPIGdi.au3> #include <WinAPIMisc.au3> #include <WinAPIProc.au3> #include <WinAPISys.au3> #include <WindowsConstants.au3> Local $hEventProc = DllCallbackRegister('_EventProc', 'none', 'ptr;dword;hwnd;long;long;dword;dword') Global $g_tRECT, $g_iIndex, $g_hMenu = 0 OnAutoItExitRegister('OnAutoItExit') Local $hEventHook = _WinAPI_SetWinEventHook($EVENT_SYSTEM_FOREGROUND, $EVENT_SYSTEM_FOREGROUND, DllCallbackGetPtr($hEventProc)) Run(@SystemDir & '\notepad.exe') While 1 Sleep(1000) WEnd Func OnAutoItExit() _WinAPI_UnhookWinEvent($hEventHook) DllCallbackFree($hEventProc) EndFunc ;==>OnAutoItExit Func _EventProc($hEventHook, $iEvent, $hWnd, $iObjectID, $iChildID, $iThreadId, $iEventTime) #forceref $hEventHook, $iObjectID, $iChildID, $iThreadId, $iEventTime Switch $iEvent Case $EVENT_SYSTEM_FOREGROUND ConsoleWrite(TimerInit() & @CRLF) Local $hWnd_Active = WinGetHandle("[ACTIVE]", "") ConsoleWrite($hWnd_Active & @TAB & WinGetTitle($hWnd_Active) & @CRLF) EndSwitch EndFunc ;==>_EventProc pixelsearch 1 OS: Win10-22H2 - 64bit - German, AutoIt Version: 3.3.16.1, AutoIt Editor: SciTE, Website: https://funk.eu AMT - Auto-Movie-Thumbnailer (2024-Oct-13) BIC - Batch-Image-Cropper (2023-Apr-01) COP - Color Picker (2009-May-21) DCS - Dynamic Cursor Selector (2024-Oct-13) HMW - Hide my Windows (2024-Oct-19) HRC - HotKey Resolution Changer (2012-May-16) ICU - Icon Configuration Utility (2018-Sep-16) SMF - Search my Files (2024-Oct-20) - THE file info and duplicates search tool SSD - Set Sound Device (2017-Sep-16) Link to comment Share on other sites More sharing options...
pixelsearch Posted October 19, 2022 Author Share Posted October 19, 2022 @KaFu Thanks for your both working suggestions Have a great day Link to comment Share on other sites More sharing options...
pixelsearch Posted October 19, 2022 Author Share Posted October 19, 2022 @KaFu (or a reader that may have an idea about what follows) As I'm always curious, there is something I don't understand about this WM_ACTIVATEAPP message, maybe someone got the answer ? This is what msdn stipulates about the WM_ACTIVATEAPP message, concerning $wParam and $lParam WM_ACTIVATEAPP wParam Indicates whether the window is being activated or deactivated. This parameter is TRUE if the window is being activated; it is FALSE if the window is being deactivated. lParam The thread identifier. If the wParam parameter is TRUE, lParam is the identifier of the thread that owns the window being deactivated. If wParam is FALSE, lParam is the identifier of the thread that owns the window being activated. Let's see if this worked in the 1st pic of my preceding post, where WM_ACTIVATEAPP was triggered 3 times : 1) I run the script from Scite => it creates the AutoIt Gui (which is now the active window, as shown by KaFu's scripts as they use "[ACTIVE]") . What shows WM_ACTIVATEAPP is also correct, let's paste its result again below : 1 WM_ACTIVATEAPP : $hWnd = 0x0062062A $wParam = 0x00000001 $lParam = 0x00000954 0x000F056A SciTEWindow C:\Temp8\329c.au3 - SciTE-Lite As $wParam is True (0x0001, indicating the Gui is being activated) then $lParam indicates the thread of the window being deactivated... and it's correctly SciTEWindow (thread id = 0x0954) that was deactivated as we read it 2 lines above. So far so good. 2) Now that the GUI is active, we click on AutoIt Help file window and this is the result of the 2nd WM_ACTIVATEAPP, which is also correct : 2 WM_ACTIVATEAPP : $hWnd = 0x0062062A $wParam = 0x00000000 $lParam = 0x00000D28 0x007B06CC HH Parent AutoIt Help (v3.3.14.5) As $wParam is False (0x0000, indicating the Gui is being deactivated) then $lParam indicates the thread of the window being activated and it's correctly AutoIt help window (thread ID = 0x0D28) that is activated as we read it 2 lines above. Again, so far so good. 3) But now that AutoIt Help file window is active, we're clicking back on the GUI, which triggers WM_ACTIVATEAPP for the 3rd and last time : 3 WM_ACTIVATEAPP : $hWnd = 0x0062062A $wParam = 0x00000001 $lParam = 0x00000000 As $wParam is True (0x0001, indicating the Gui is being activated) then $lParam indicates the thread of the window being deactivated... but wait a minute : why does $lParam = 0x0000 ? $lParam should be equal to 0x0D28 (the thread ID of the AutoIt help window being deactivated) but it's now equal to 0 ? If you compare phase 1) with phase 3) , you'll notice that in both cases the AutoIt GUI is being activated, but when everything looks correct in phase 1) [where $lparam = Scite window thread ID being deactivated] is now becoming incorrect in phase 3) [where $lparam is equal to 0 instead of being equal to AutoIt help file thread ID being deactivated] Also, in msdn doc concerning WM_ACTIVATEAPP, it's never mentioned that $lparam can be equal to 0 Lucky me (?) I found 2 msdn web links stipulating that $lparam could be equal to 0, in a function which is not too far from WM_ACTIVATEAPP, here are the 2 links : WM_ACTIVATE message : lParam A handle to the window being activated or deactivated, depending on the value of the wParam parameter [...] This handle can be NULL. [thanks guys for the 'clear' explanation !] WM_ACTIVATE message (Windows CE 5.0) : hwndPrevious = (HWND)lParam; Handle to the window being activated or deactivated, depending on the value of the fActive parameter [...] This handle can be NULL, and is always NULL when the window being activated and the window being deactivated are in separate processes. I have no idea if this last comment found in WM_ACTIVATE (Windows CE 5.0) can also be applied to WM_ACTIVATEAPP and if it could explain the behavior of phase 3) ... but let's not forget that if it could explain the behavior of phase 3) then it won't maybe explain the behavior of phase 1) (?) That was a long post and I'm really thirsty now Thanks for reading Link to comment Share on other sites More sharing options...
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