pixelsearch Posted September 25 Share Posted September 25 (edited) Hello everybody Now that I have received approval from a moderator [ as there are below some references to the last downloadable source of AutoIt written in C++, version 3.1.0 from 2005 ] then I post this script where I tried to understand what exactly WinKill() is doing, when compared to WinClose() It was interesting to "rewrite" the WinKill function, using the AutoIt functions that match Jon's C++ code. First the C++ code corresponding to WinKill, as found on Stackoverflow site and GitHub expandcollapse popup/////////////////////////////////////////////////////////////////////////////// // WinKill() // Closes a window - uses more force than WinClose /////////////////////////////////////////////////////////////////////////////// AUT_RESULT AutoIt_Script::F_WinKill(VectorVariant &vParams, Variant &vResult) { Win_WindowSearchInit(vParams); if (Win_WindowSearch() == false) return AUT_OK; // Required window not found Util_WinKill(m_WindowSearchHWND); Util_Sleep(m_nWinWaitDelay); // Briefly pause before continuing return AUT_OK; } // WinKill() /////////////////////////////////////////////////////////////////////////////// // Util_WinKill() // // Closes a window with extreme predjudice // /////////////////////////////////////////////////////////////////////////////// void Util_WinKill(HWND hWnd) { DWORD dwResult; LRESULT lResult = SendMessageTimeout(hWnd, WM_CLOSE, 0, 0, SMTO_ABORTIFHUNG, 500, &dwResult); // wait 500ms if( !lResult ) { // Use more force - Mwuahaha // Get the ProcessId for this window. DWORD pid; GetWindowThreadProcessId( hWnd, &pid ); // Open the process with all access. HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); // Terminate the process. TerminateProcess(hProcess, 0); CloseHandle(hProcess); } } // Util_WinKill() Then the AutoIt script... and its numerous comments expandcollapse popup#include <APISysConstants.au3> #include <MsgBoxConstants.au3> #include <ProcessConstants.au3> #include <WinAPIProc.au3> #include <WinAPISysWin.au3> #include <WindowsConstants.au3> Example() Func Example() ; Run Notepad Run("notepad.exe") ; Wait 10 seconds for the Notepad window to appear. WinWait("[CLASS:Notepad]", "", 10) ; Retrieve the handle of the Notepad window using the classname of Notepad. Local $hWnd = WinGetHandle("[CLASS:Notepad]") If @error Then MsgBox($MB_TOPMOST, "", "An error occurred when trying to retrieve the window handle of Notepad.") Exit EndIf MsgBox($MB_TOPMOST, "Close me #1", "Before NotePad closure") ; To close NotePad, 3 possible scenarios have been tested below : ;~ ; ======================================================= ;~ ; Close the Notepad window using the handle returned by WinGetHandle. ;~ ; Local $iRet = WinClose($hWnd) ;~ ; ConsoleWrite("WinClose = " & $iRet & @crlf) ;~ ; Or ;~ Local $iRet = _WinAPI_PostMessage($hWnd, $WM_CLOSE, 0, 0) ; as in AutoIt C++ source 3.1.0 "script_win.cpp" part WinClose() ;~ Sleep(250) ; i.e. Util_Sleep(m_nWinWaitDelay) in AutoIt C++ Winclose() source, with m_nWinWaitDelay = 250 in "script.cpp" ;~ ConsoleWrite("_WinAPI_PostMessage = " & $iRet & @crlf) ;~ ; ======================================================= ; ======================================================= ; WinKill($hWnd) ; would be ok but not really recommended as more agressive ; ONE TRY below (succeeded) : let's replace the Winkill() function with the AutoIt functions matching Jon's C++ code : ; see code in AutoIt C++ source 3.1.0 "script_win.cpp" part WinKill() and "utility.cpp" part Util_WinKill() _WinAPI_SendMessageTimeout($hWnd, $WM_CLOSE, 0, 0, 500, $SMTO_ABORTIFHUNG) ; + $SMTO_NOTIMEOUTIFNOTHUNG seems interesting too. ; _WinAPI_SendMessageTimeout is not easy : what is returned is not $aCall[0] but $aCall[7], so we'll check @error and not $aCall[0] ; Test: let's change timeout from 500 to a shorter one (10 or 1), then @error <> 0 and "If $iError Then" part is processed below. ; Test: type something in NotePad, then close the displayed MsgBox : we don't have time to save what was typed : WinKill in action ! Local $iError = @error, $iExtended = @extended ConsoleWrite("_WinAPI_SendMessageTimeout : @error = " & $iError & " @extended = " & $iExtended & @crlf) ConsoleWrite(_WinAPI_GetLastErrorMessage() & @crlf) If $iError Then Local $iPID = 0 Local $iThread = _WinAPI_GetWindowThreadProcessId($hWnd, $iPID) ; no need of $iThread in this script ConsoleWrite("$iPID = " & $iPID & " (0x" & Hex($iPID, 8) & ")" & @crlf) Local $hProcess = _WinAPI_OpenProcess($PROCESS_ALL_ACCESS, False, $iPID) ConsoleWrite("$hProcess = " & $hProcess & @crlf) ; ex. 0x000006B8 ok Local $iRet = _WinAPI_TerminateProcess($hProcess, 0) ConsoleWrite("Terminate Process = " & $iRet & @crlf) ; 1 = ok (Notepad window is no more on screen) Local $iRet = _WinAPI_CloseHandle($hProcess) ConsoleWrite("Close Handle = " & $iRet & @crlf) ; 1 = ok EndIf Sleep(250) ; i.e. Util_Sleep(m_nWinWaitDelay) ; ======================================================= ;~ ; ======================================================= ;~ ; Impossible to use _WinAPI_DestroyWindow because the Notepad window was created in a different thread (msdn & AutoIt helpfile) ;~ Local $iRet = _WinAPI_DestroyWindow($hWnd) ;~ Local $iError = _WinAPI_GetLastError() ;~ Local $iErrMsg = _WinAPI_GetLastErrorMessage() ;~ ConsoleWrite("DestroyWindow = " & $iRet & " $iError = " & $iError & " $iErrMsg = " & $iErrMsg & @crlf) ;~ ; ======================================================= MsgBox($MB_TOPMOST, "Close me #2", "After NotePad was closed") EndFunc ;==>Example ; Personal tests in this script, related to AutoIt C++ source 3.1.0 (2005) , functions WinClose & WinKill ; 1) First link found at Stackoverflow : ; https://stackoverflow.com/questions/32336995/winkill-source-code ; 2) Second link (indicated by the Stackoverflow post) concerns GitHub : ; https://github.com/ellysh/au3src/ ; 3) Interesting discussion in the link below, concerning _WinAPI_SendMessageTimeout : ; "What happens if the timeout occurs at the very moment the message is still processing ? ; https://comp.os.ms-windows.programmer.win32.narkive.com/y5Xv3I7v/sendmessagetimeout-what-happens-if-timeout-occurs The _WinAPI_SendMessageTimeout function (found in the include file WinAPISysWin.au3) was a bit tricky, as it returns $aCall[7] and not $aCall[0] so @error was the key to know what to do on Return It was interesting for me to learn some new functions this way, hoping it will be same for the interested users. Edited September 26 by pixelsearch forgot to add a [ Sleep(250) ] in AutoIt code to match C++ code [ _Sleep(m_nWinWaitDelay) ] argumentum 1 Link to comment Share on other sites More sharing options...
argumentum Posted September 25 Share Posted September 25 "// Use more force - Mwuahaha" So one is WinClose and the other KillTheProcessForTheWindow, interesting. I never knew. Thanks for posting. pixelsearch 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting. Link to comment Share on other sites More sharing options...
pixelsearch Posted September 26 Author Share Posted September 26 (edited) 4 hours ago, argumentum said: Interesting, I never knew. Me neither A couple of days ago, before finding Jon's code, I thought maybe WinKill was sending a WM_DESTROY message. But when I tried to send a WM_DESTROY message (instead of WinKill) the results were not good at all, then came this french link which indicated why it was a wrong way (translation in English below) Edit: msdn link : "Here is a flow chart showing the typical way to process WM_CLOSE and WM_DESTROY messages" : Edited September 26 by pixelsearch added msdn pic argumentum 1 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