marc0v Posted November 20, 2009 Share Posted November 20, 2009 If an autoit script tries to do WinGetTitle, WinSetState, WinActivate, WinSetOnTop... on a suspended or hanged window the script will freeze until the target window (process or thread) un-freeze or disappear.A workaround, if you suspect a window to get sometimes hanged, is to do asynchronous calls or time-outed calls.Asynchronous/time-outed calls can fail if the target window is hanged, but your script won't be frozen. So you get a chance to take further action.It is noticeable that WinGetState works on suspended/hanged window (seemingly), so you can make a loop after an asynchronous call to check if your action succeded or failed in changing the state of the window.This is related to 'Bug' or 'Not a Bug' (this isn't yet decided)http://www.autoitscript.com/trac/autoit/ticket/1294Here are 3 examples1. time-outed call to get the window title (changing the window title could also be done with WM_SETTEXT in place of WM_GETTEXT) http://msdn.microsoft.com/en-us/library/ms644952(VS.85).aspx2. asynchronous call to change the window state : minimize, maximize, restore, show, hide, activate http://msdn.microsoft.com/en-us/library/ms633549(VS.85).aspx3. asynchronous call to change the window position : show, hide, window pos, window size, zorder, topmost attibute http://msdn.microsoft.com/en-us/library/ms633545(VS.85).aspxIn each example you need to provide a valid window title (or an advanced window identifier) in the "$wintitle" variable.1 : get the window title with a time-outexpandcollapse popup; Messages Global Const $WM_GETTEXTLENGTH = 0x000E Global Const $WM_GETTEXT = 0x000D ; Abort get title operation if target window is not responding, a time-out (ms) must be provided Global Const $SMTO_ABORTIFHUNG = 0x0002 $wintitle = "provide_valid_window_title_here" $infourl = "http://msdn.microsoft.com/en-us/library/ms644952(VS.85).aspx" $ms_gettitle_timeout = 250 ; if time-out is really short (just a few ms), the window might not have the time to return its title even if it is not hanged ; in such case an empty string is returned, and error is 'hung window' (5) ; ; on the other hand, an un-responding window can however returns its title in some cases... ; with something like [ (not responding)] appended at the end of the title (langage-dependant suffix) ; in such case no error is returned (so it is not a reliable test to check if a process/thread is hanged) $gottitle = WINGETTITLE_TIMEOUT($wintitle, $ms_gettitle_timeout) $err = @error $exterr = @extended ClipPut($infourl) msgbox(0,"Finished", _ "Done with:" & $wintitle & @CR & _ "handle:" & WinGetHandle($wintitle) & @CR & _ @CR & _ "got title:[" & StringReplace($gottitle, Chr(0), "{NULL}") & "]" & @CR & _ "error:" & $err & @CR & _ "extended error:" & $exterr & @CR & _ @CR & _ "more infos at:" & $infourl & @CR & _ "this URL has been copied to your clipboard to be easily pasted in your Internet Browser") ; same syntax as WinGetTitle plus a time-out Func WINGETTITLE_TIMEOUT( _ $id_window, _ $mstimeout = 500) Local $hwnd, $arrdll, $ilen, $vout, $sfulltitle Local Const $inowinexterror = 4 ; no window Local Const $ihungwinexterror = 5 ; hung window $hwnd = WinGetHandle($id_window) If $hwnd = "" Then Return SetError($inowinexterror, 0, "") $arrdll = SENDMESSAGE_TIMEOUT($ilen, $hwnd, $WM_GETTEXTLENGTH, 0, 0, $SMTO_ABORTIFHUNG, $mstimeout, - 1, "int", "int") If @error Then Return SetError(@error, @extended, "") If $arrdll[1] = 0 Then Return SetError($inowinexterror, 0, "") If $arrdll[0] = 0 Then Return SetError($ihungwinexterror, 0, "") $arrdll = SENDMESSAGE_TIMEOUT($vout, $hwnd, $WM_GETTEXT, $ilen + 1, "", $SMTO_ABORTIFHUNG, $mstimeout, - 1, "int", "str") If @error Then Return SetError(@error, @extended, "") If $arrdll[1] = 0 Then Return SetError($inowinexterror, 0, "") If $arrdll[0] = 0 Then Return SetError($ihungwinexterror, 0, "") Return $arrdll[4] EndFunc ; used by WINGETTITLE_TIMEOUT, can be used to send other kind of messages with a time-out Func SENDMESSAGE_TIMEOUT( _ ByRef $vout, _ $hwnd, _ $imsg, _ $wparam, _ $lparam, _ $nflags, _ $mstimeout, _ $r = 0, _ $t1 = "int", _ $t2 = "int") Local $arrdll, $dllerror, $dllexterror $arrdll = DllCall("user32.dll", "long", "SendMessageTimeout", "hwnd", $hwnd, "int", $imsg, _ $t1, $wparam, $t2, $lparam, "int", $nflags, "int", $mstimeout, "int*", "") $dllerror = @error $dllexterror = @extended If $dllerror <> 0 Then $vout = 0 Return SetError($dllerror, $dllexterror, 0) EndIf $vout = $arrdll[7] If $r >= 0 And $r <= 4 Then Return $arrdll[$r] Return $arrdll EndFunc2 : asynchronously change the window state : minimize, maximize, restore, show, hide, activateexpandcollapse popup$wintitle = "provide_valid_window_title_here" $infourl = "http://msdn.microsoft.com/en-us/library/ms633549(VS.85).aspx" ; this will un-minimize and activate a window, workarounded a bit since there is no SW_ACTIVATE state ; the window will retain its maximized state if it was maximized ; this will also show the window if hidden (?) WINSETSTATE_ASYNC($wintitle, @SW_MINIMIZE) WINSETSTATE_ASYNC($wintitle, @SW_RESTORE) Sleep(2000) ; this will hide the window WINSETSTATE_ASYNC($wintitle, @SW_HIDE) Sleep(1000) ; this will minimize the window, works on hidden windows WINSETSTATE_ASYNC($wintitle, @SW_MINIMIZE) Sleep(500) ; this will just show the window (but not restore it or activate it if minimized) WINSETSTATE_ASYNC($wintitle, @SW_SHOW) Sleep(1000) ClipPut($infourl) msgbox(0,"Finished", _ "Done with:" & $wintitle & @CR & _ "handle:" & WinGetHandle($wintitle) & @CR & _ @CR & _ "more infos at:" & $infourl & @CR & _ "this URL has been copied to your clipboard to be easily pasted in your Internet Browser") ; same syntax as WinSetState less the "text" parameter Func WINSETSTATE_ASYNC( _ $id_window, _ $winstate) Local $aRet, $hwnd Local Const $inowinexterror = 4 $hwnd = WinGetHandle($id_window) If $hwnd = "" Then Return SetError($inowinexterror, 0, 0) $aRet = DllCall("user32.dll", "int", "ShowWindowAsync", "hwnd", $hwnd, "int", $winstate) If @error Then Return SetError(@error, @extended, 0) Return $aRet[0] EndFunc3 : asynchronously change the window position : show, hide, window pos, window size, zorder, topmost attibuteexpandcollapse popup; =============================================================================================================================== ; SetWindowPos Constants, SetWindowPos does not seem fitted to activate a window (look at ASynchronous WinSetState instead) ; =============================================================================================================================== Global Const $SWP_NOSIZE = 0x0001 Global Const $SWP_NOMOVE = 0x0002 Global Const $SWP_NOZORDER = 0x0004 Global Const $SWP_NOREDRAW = 0x0008 ; seems to avoid activating the last active control inside the window rather than the window itself (?) ; this may avoid to have the cursor appearing inside an edit control within a non-active window Global Const $SWP_NOACTIVATE = 0x0010 Global Const $SWP_FRAMECHANGED = 0x0020 Global Const $SWP_DRAWFRAME = 0x0020 ; if the SWP_SHOWWINDOW or SWP_HIDEWINDOW flag is set, the window cannot be moved or sized Global Const $SWP_SHOWWINDOW = 0x0040 Global Const $SWP_HIDEWINDOW = 0x0080 Global Const $SWP_NOCOPYBITS = 0x0100 Global Const $SWP_NOOWNERZORDER = 0x0200 Global Const $SWP_NOREPOSITION = 0x0200 Global Const $SWP_NOSENDCHANGING = 0x0400 Global Const $SWP_DEFERERASE = 0x2000 ; the most important flag to target possibly hanged/suspended processes ; if the targeted process is hanged/suspended nothing will happen, but your script won't be frozen ; check the result of your action with WinGetState (which works on hanged/suspended processes) Global Const $SWP_ASYNCWINDOWPOS = 0x4000 ; =============================================================================================================================== ; End of SetWindowPos Constants ; =============================================================================================================================== ; =============================================================================================================================== ; Z order Constants, Z order is the order in which windows are piled on the desktop ; =============================================================================================================================== Global Const $HWND_BOTTOM = 1 ; Places the window at the bottom of the Z order (seems buggy, see workaround in example) Global Const $HWND_NOTOPMOST = -2 ; Places the window above all non-topmost windows Global Const $HWND_TOP = 0 ; Places the window at the top of the Z order (seems buggy, see workaround in example) Global Const $HWND_TOPMOST = -1 ; Places the window above all non-topmost windows ; =============================================================================================================================== ; End of Z order Constants ; =============================================================================================================================== $wintitle = "provide_valid_window_title_here" $infourl = "http://msdn.microsoft.com/en-us/library/ms633545(VS.85).aspx" ; example 1 ; place a visible window at the bottom of $zorder (under all windows) ; workarounded since $HWND_BOTTOM does not always seem to work WINDOWSTATE($wintitle, $HWND_BOTTOM, 0, 0, 0, 0, $SWP_ASYNCWINDOWPOS + $SWP_NOSIZE + $SWP_NOMOVE + $SWP_HIDEWINDOW + $SWP_NOACTIVATE) WINDOWSTATE($wintitle, $HWND_BOTTOM, 0, 0, 0, 0, $SWP_ASYNCWINDOWPOS + $SWP_NOSIZE + $SWP_NOMOVE + $SWP_SHOWWINDOW + $SWP_NOACTIVATE) Sleep(2000) ; example 2 ; place a visible window at the top of $zorder (above all not 'always on top' windows, this does not activate the window) ; workarounded since $HWND_TOP does not seem to work WINDOWSTATE($wintitle, $HWND_TOPMOST, 0, 0, 0, 0, $SWP_ASYNCWINDOWPOS + $SWP_NOSIZE + $SWP_NOMOVE + $SWP_SHOWWINDOW + $SWP_NOACTIVATE) WINDOWSTATE($wintitle, $HWND_NOTOPMOST, 0, 0, 0, 0, $SWP_ASYNCWINDOWPOS + $SWP_NOSIZE + $SWP_NOMOVE + $SWP_SHOWWINDOW + $SWP_NOACTIVATE) Sleep(2000) ; example 3 ; move a window (visible or not, does not work if window is minimized : window must be restored before being moved) WINDOWSTATE($wintitle, $HWND_TOP, 40, 40, 0, 0, $SWP_ASYNCWINDOWPOS + $SWP_NOSIZE + $SWP_NOACTIVATE) Sleep(1000) WINDOWSTATE($wintitle, $HWND_TOP, 20, 20, 0, 0, $SWP_ASYNCWINDOWPOS + $SWP_NOSIZE + $SWP_NOACTIVATE) Sleep(1000) ClipPut($infourl) msgbox(0,"Finished", _ "Done with:" & $wintitle & @CR & _ "handle:" & WinGetHandle($wintitle) & @CR & _ @CR & _ "more infos at:" & $infourl & @CR & _ "this URL has been copied to your clipboard to be easily pasted in your Internet Browser") Func WINDOWSTATE( _ $id_window, _ $zorder, _ $left, _ $top, _ $width, _ $height, _ $flag) Local $aRet, $hwnd Local Const $inowinexterror = 4 $hwnd = WinGetHandle($id_window) If $hwnd = "" Then Return SetError($inowinexterror, 0, 0) $aRet = DllCall("user32.dll", "int", "SetWindowPos", "hwnd", $hwnd, "hwnd", $zorder, _ "int", $left, "int", $top, "int", $width, "int", $height, "uint", $flag) If @error Then Return SetError(@error, @extended, 0) Return $aRet[0] EndFunc 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