Jump to content

WinClose & WinKill


pixelsearch
 Share

Recommended Posts

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

///////////////////////////////////////////////////////////////////////////////
// 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 :D

#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 by pixelsearch
forgot to add a [ Sleep(250) ] in AutoIt code to match C++ code [ _Sleep(m_nWinWaitDelay) ]
Link to comment
Share on other sites

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)

wm_destroy.png.bf4c2ee9e228cddc55813873a0d2ae45.png

Edit: msdn link : "Here is a flow chart showing the typical way to process WM_CLOSE and WM_DESTROY messages" :

wmclose01.png.828edd80b5a7c9e4ace0161fa994ec4e.png

 

Edited by pixelsearch
added msdn pic
Link to comment
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...