Modify

Opened 10 years ago

Closed 10 years ago

Last modified 10 years ago

#935 closed Bug (No Bug)

WinSetState() lags

Reported by: trancexx Owned by:
Milestone: Component: AutoIt
Version: 3.3.0.0 Severity: None
Keywords: Cc:

Description

I tested this on various systems and the result is the same. This function lags for some reason. I read the documentation and couldn't find explanation for this strange behaviour. So, if someone would check if this is intended because it's really unexpected and kind of weird (probably there is some better word to describe it).
I wrote a little script to demonstrate it. Did try to be as far away as I could from native functions made for making guis to eliminate possible shortcuts and still to be compact:

Global $hGui = GUICreate("Test", 300, 300, 20, 100)

GUICtrlCreateLabel("WinSetState functions:", 15, 70, 130)
Global $hButtonShowWindow_AutoIt = GUICtrlCreateButton("ShowWindow", 20, 100, 100, 25)
Global $hButtonHideWindow_AutoIt = GUICtrlCreateButton("HideWindow", 20, 150, 100, 25)

GUICtrlCreateLabel("DllCall:", 190, 70, 130)
Global $hButtonShowWindow_DllCall = GUICtrlCreateButton("ShowWindow", 170, 100, 100, 25)
Global $hButtonHideWindow_DllCall = GUICtrlCreateButton("HideWindow", 170, 150, 100, 25)

;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Global $bDialog = "0x0100FFFF00000000000004004C0ACC80040000000000A2005F00000000004100" & _
		"750074006F0049007400200049006E00700075007400200042006F0078000000" & _
		"0800000000014D00530020005300680065006C006C00200044006C0067000000" & _
		"0000000000000000000002500700070093002C00EA030000FFFF820050007200" & _
		"6F006D0070007400000000000000000000000000800081500700380093000C00" & _
		"E9030000FFFF8100000000000000000000000000010001501000490032000E00" & _
		"01000000FFFF80004F004B000000000000000000000000000000015057004900" & _
		"32000E0002000000FFFF8000430061006E00630065006C0000000000"

Global $tDialog = DllStructCreate("byte[" & BinaryLen($bDialog) & "]")
DllStructSetData($tDialog, 1, $bDialog)

Global $aCall = DllCall("user32.dll", "hwnd", "CreateDialogIndirectParamW", _
		"hwnd", 0, _
		"ptr", DllStructGetPtr($tDialog), _
		"hwnd", $hGui, _
		"ptr", 0, _
		"lparam", 0)

Global $hDialog = $aCall[0]
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX


GUISetState()

While 1
	Switch GUIGetMsg()
		Case - 3
			Exit
		Case $hButtonShowWindow_AutoIt
			WinSetState($hDialog, 0, @SW_SHOW)
		Case $hButtonShowWindow_DllCall
			DllCall("user32.dll", "int", "ShowWindow", "hwnd", $hDialog, "int", @SW_SHOW)
		Case $hButtonHideWindow_AutoIt
			WinSetState($hDialog, 0, @SW_HIDE)
		Case $hButtonHideWindow_DllCall
			DllCall("user32.dll", "int", "ShowWindow", "hwnd", $hDialog, "int", @SW_HIDE)
	EndSwitch
WEnd

I did manage to find out that WinSetState() eventually calls ShowWindow function the same way I did in that script and that the lag is likely with what comes after that.

Thanks.

Attachments (0)

Change History (4)

comment:1 Changed 10 years ago by Jpm

Cannot you explain for a non english native what the difference of behavior you demonstrate?
I don't understand "lag"
For me clicking winsetstate buttons or dllcall ones do the same under Vista.

comment:2 Changed 10 years ago by trancexx

Yes, sory for me not being more descriptive.
It's not the same for me. When I click ShowWindow on the left window shows and after some time controls are drawn (there is some short time when window is without controls).

... it's that sleep 250 that you call for some reason. I guess that makes it intended behaviour and my original question is answered.

Is that sleep needed?

comment:3 Changed 10 years ago by Jpm

  • Resolution set to No Bug
  • Status changed from new to closed

In fact all Win...() are suppose to respect the Opt("WinWaitDelay") which is 250 by default.
That's the reason you get the Sleep(250).
use Op('"WinWaitDelay",0) if you don't like it.

I am curious to see how you find a sleep(250) was occuring.

comment:4 Changed 10 years ago by trancexx

Well, if I tell you I will have to kill you. And that's bad because likely I'm gonna need you more.

... no I used method described by monoceres in this topic http://www.autoitscript.com/forum/index.php?showtopic=84936
This is the code that suited my needs to intercept AutoIt's calls to Sleep:

#NoTrayIcon
#include <WinAPI.au3>

;Opt("WinWaitDelay", 0)

Global $hSleepCallback = DllCallbackRegister("_Intercept_Sleep", "none", "dword")

If _AddHookApi("kernel32.dll", "Sleep", DllCallbackGetPtr($hSleepCallback)) Then
	ConsoleWrite("All OK. Sleep is caught. Calls other than 0 or 10 follows:" & @CRLF)
Else
	ConsoleWrite("!Failed to intercept calls to Sleep function." & @CRLF)
EndIf


Global $hGui = GUICreate("Test", 300, 300, 20, 100)

GUICtrlCreateLabel("WinSetState functions:", 15, 70, 130)
Global $hButtonShowWindow_AutoIt = GUICtrlCreateButton("ShowWindow", 20, 100, 100, 25)
Global $hButtonHideWindow_AutoIt = GUICtrlCreateButton("HideWindow", 20, 150, 100, 25)

GUICtrlCreateLabel("DllCall:", 190, 70, 130)
Global $hButtonShowWindow_DllCall = GUICtrlCreateButton("ShowWindow", 170, 100, 100, 25)
Global $hButtonHideWindow_DllCall = GUICtrlCreateButton("HideWindow", 170, 150, 100, 25)


;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Global $bDialog = "0x0100FFFF00000000000004004C0ACC80040000000000A2005F00000000004100" & _
		"750074006F0049007400200049006E00700075007400200042006F0078000000" & _
		"0800000000014D00530020005300680065006C006C00200044006C0067000000" & _
		"0000000000000000000002500700070093002C00EA030000FFFF820050007200" & _
		"6F006D0070007400000000000000000000000000800081500700380093000C00" & _
		"E9030000FFFF8100000000000000000000000000010001501000490032000E00" & _
		"01000000FFFF80004F004B000000000000000000000000000000015057004900" & _
		"32000E0002000000FFFF8000430061006E00630065006C0000000000"

Global $tDialog = DllStructCreate("byte[" & BinaryLen($bDialog) & "]")
DllStructSetData($tDialog, 1, $bDialog)

Global $aCall = DllCall("user32.dll", "hwnd", "CreateDialogIndirectParamW", _
		"hwnd", 0, _
		"ptr", DllStructGetPtr($tDialog), _
		"hwnd", 0, _
		"ptr", 0, _
		"lparam", 0)

Global $hDialog = $aCall[0]
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

GUISetState()


While 1
	Switch GUIGetMsg()
		Case - 3
			Exit
		Case $hButtonShowWindow_AutoIt
			WinSetState($hDialog, 0, @SW_SHOW)
		Case $hButtonShowWindow_DllCall
			DllCall("user32.dll", "int", "ShowWindow", "hwnd", $hDialog, "int", @SW_SHOW)
		Case $hButtonHideWindow_AutoIt
			WinSetState($hDialog, 0, @SW_HIDE)
		Case $hButtonHideWindow_DllCall
			DllCall("user32.dll", "int", "ShowWindow", "hwnd", $hDialog, "int", @SW_HIDE)
	EndSwitch
WEnd

;DllCallbackFree($hSleepCallback)

;The End



Func _Intercept_Sleep($iMilisec)

	ToolTip("Sleep(" & $iMilisec & ")")

	If $iMilisec And $iMilisec <> 10 Then
		ConsoleWrite("! Sleep(" & $iMilisec & ")" & @CRLF)
	EndIf

	DllCall("kernel32.dll", "none", "Sleep", "dword", $iMilisec)

EndFunc   ;==>_Intercept_Sleep


Func _AddHookApi($sModuleName, $sFunctionName, $pNewProcAddress)

	Local $hInstance = _WinAPI_GetModuleHandle(0)

	Local $aCall = DllCall("Dbghelp.dll", "ptr", "ImageDirectoryEntryToData", _
			"ptr", $hInstance, _
			"int", 1, _ ; as an image
			"ushort", 1, _ ; IMAGE_DIRECTORY_ENTRY_IMPORT
			"dword*", 0)

	Local $pImportDirectory = $aCall[0]

	Local $tIMAGE_IMPORT_MODULE_DIRECTORY
	Local $tModuleName

	While 1

		$tIMAGE_IMPORT_MODULE_DIRECTORY = DllStructCreate("dword RVAOriginalFirstThunk;" & _
				"dword TimeDateStamp;" & _
				"dword ForwarderChain;" & _
				"dword RVAModuleName;" & _
				"dword RVAFirstThunk", _
				$pImportDirectory)

		If Not DllStructGetData($tIMAGE_IMPORT_MODULE_DIRECTORY, "RVAFirstThunk") Then ; the end
			ExitLoop
		EndIf

		$tModuleName = DllStructCreate("char Name[64]", $hInstance + DllStructGetData($tIMAGE_IMPORT_MODULE_DIRECTORY, "RVAModuleName"))

		If DllStructGetData($tModuleName, "Name") = $sModuleName Then ; function from this module

			Local $iInitialOffset = $hInstance + DllStructGetData($tIMAGE_IMPORT_MODULE_DIRECTORY, "RVAFirstThunk")
			Local $iInitialOffset2 = $hInstance + DllStructGetData($tIMAGE_IMPORT_MODULE_DIRECTORY, "RVAOriginalFirstThunk")

			Local $iOffset2 = 0
			Local $tBufferOffset2, $iBufferOffset2
			Local $tBuffer

			While 1

				$tBufferOffset2 = DllStructCreate("dword", $iInitialOffset2 + $iOffset2)

				$iBufferOffset2 = DllStructGetData($tBufferOffset2, 1)
				If Not $iBufferOffset2 Then ; zero value is the end
					ExitLoop
				EndIf

				$tBuffer = DllStructCreate("ushort Ordinal; char Name[64]", $hInstance + $iBufferOffset2)

				If DllStructGetData($tBuffer, 2) == $sFunctionName Then ; wanted function

					Local $tBufferOffset = DllStructCreate("dword", $iInitialOffset + $iOffset2)

					;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

					Local $tMEMORY_BASIC_INFORMATION = DllStructCreate("ptr BaseAddress;" & _
							"ptr AllocationBase;" & _
							"ptr AllocationProtect;" & _
							"dword RegionSize;" & _
							"dword State;" & _
							"dword Protect;" & _
							"dword Type")

					DllCall("kernel32.dll", "dword", "VirtualQuery", _
							"ptr", DllStructGetPtr($tBufferOffset), _
							"ptr", DllStructGetPtr($tMEMORY_BASIC_INFORMATION), _
							"dword", DllStructGetSize($tMEMORY_BASIC_INFORMATION))

					DllCall("kernel32.dll", "int", "VirtualProtect", _
							"ptr", DllStructGetData($tMEMORY_BASIC_INFORMATION, "BaseAddress"), _
							"dword", DllStructGetData($tMEMORY_BASIC_INFORMATION, "RegionSize"), _
							"dword", 4, _ ; PAGE_READWRITE
							"dword*", 0)

					DllStructSetData($tBufferOffset, 1, $pNewProcAddress)

					;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

					Return 1 ; All OK!

				EndIf

				$iOffset2 += 4 ; size of $tBufferOffset2

			WEnd

			ExitLoop

		EndIf

		$pImportDirectory += 20 ; size of $tIMAGE_IMPORT_MODULE_DIRECTORY

	WEnd

EndFunc   ;==>_AddHookApi

Btw, thanks for the explanation and solution of course. Sometimes even the obvious things are not so obvious at all.

Guidelines for posting comments:

  • You cannot re-open a ticket but you may still leave a comment if you have additional information to add.
  • In-depth discussions should take place on the forum.

For more information see the full version of the ticket guidelines here.

Add Comment

Modify Ticket

Action
as closed The ticket will remain with no owner.
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.