KaFu Posted November 26, 2022 Share Posted November 26, 2022 (edited) Hiho Team, attached a small example for a self-centering FileOpenDialog() using a self-terminating timer call. In the past I used _Timer_SetTimer() with a callback function, which works on x86, but does not under x64. So here's an example working for x64 too, using a global variable and WM_TIMER calls. What I just realized is that the doc for _WinAPI_SetTimer(), but also the MSDN doc for SetTimer, seem to be false. Success: The timer identifier. An application can pass this value to the _WinAPI_KillTimer() function to destroy the timer. _WinAPI_KillTimer() does not work when used with a hWnd and no callback func, _WinAPI_SetTimer() needs to be fed a dedicated TimerID (see "9876" used below). When I use the TimerID returned by _WinAPI_SetTimer() then _WinAPI_KillTimer() does not work. Hopefully useful for someone 😉. Edit: Replace fixed TimerID value 9876 with a TimerInit() call, I like the idea of a unique ID more. expandcollapse popup#Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_UseX64=y #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <WinAPISysWin.au3> Global $a_Global_FileOpenDialog_Wrapper[3] ; 0 = Title, 1 = hWnd, 2 = TimerID Local $s_Selected_File = _FileOpenDialog_Wrapper("Select File", @ScriptDir, "All (*.*)", 1 + 2 + 4) If Not @error Then MsgBox(0, "", $s_Selected_File) Func _FileOpenDialog_Wrapper($sTitle, $sInitDir, $sFilter, $iOptions = 0, $sDefaultName = "", $hWnd = 0) ; https://groups.google.com/forum/?hl=en&fromgroups=#!topic/microsoft.public.vc.mfc/HafQr4gIRY0 ; The problem is that GetOpenFileName changes the current directory to the last browsed one. The current directory and any of its parents cannot be deleted. If Not $sInitDir Then $sInitDir = "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" ; CLSID for "My Computer" Local $sWorkingDir = @WorkingDir $a_Global_FileOpenDialog_Wrapper[0] = $sTitle Local $old_GUISwitch = GUISwitch(0) $a_Global_FileOpenDialog_Wrapper[1] = GUICreate("_FileOpenDialog_Wrapper") GUISwitch($old_GUISwitch) GUIRegisterMsg($WM_TIMER, "WM_TIMER") $a_Global_FileOpenDialog_Wrapper[2] = _WinAPI_SetTimer($a_Global_FileOpenDialog_Wrapper[1], TimerInit(), 10, 0) Local $sFilename = FileOpenDialog($sTitle, $sInitDir, $sFilter, $iOptions, $sDefaultName, $hWnd) Local $iError = @error ConsoleWrite("_WinAPI_KillTimer-2= " & _WinAPI_KillTimer($a_Global_FileOpenDialog_Wrapper[1], $a_Global_FileOpenDialog_Wrapper[2]) & @CRLF) GUIRegisterMsg($WM_TIMER, "") GUIDelete($a_Global_FileOpenDialog_Wrapper[1]) FileChangeDir($sWorkingDir) If Not $iError Then If StringInStr($sFilename, "|", 2) Then ; multiple selection Local $aFilename = StringSplit($sFilename, "|") Else Local $sPath = StringTrimRight($sFilename, StringLen($sFilename) - StringInStr($sFilename, "\", 2, -1)) EndIf EndIf Return SetError($iError, 0, $sFilename) EndFunc ;==>_FileOpenDialog_Wrapper Func WM_TIMER($hWnd, $iMsg, $iwParam, $ilParam) #forceref $hWnd, $iMsg, $iwParam, $ilParam ConsoleWrite("WM_TIMER " & @TAB & TimerInit() & @TAB & $hWnd & @TAB & $iMsg & @TAB & $iwParam & @TAB & $ilParam & @CRLF) Local $hWnd_Timer_Move_FileOpenDialog = WinGetHandle("[TITLE:" & $a_Global_FileOpenDialog_Wrapper[0] & ";CLASS:#32770]", "") If IsHWnd($hWnd_Timer_Move_FileOpenDialog) Then ConsoleWrite("WinMove= " & WinMove($hWnd_Timer_Move_FileOpenDialog, "", (@DesktopWidth - (@DesktopWidth / 4 * 3)) / 2, (@DesktopHeight - (@DesktopHeight / 4 * 3)) / 2, @DesktopWidth / 4 * 3, @DesktopHeight / 4 * 3) & @CRLF) ConsoleWrite("_WinAPI_KillTimer-1= " & _WinAPI_KillTimer($a_Global_FileOpenDialog_Wrapper[1], $a_Global_FileOpenDialog_Wrapper[2]) & @CRLF) ConsoleWrite(_WinAPI_GetLastErrorMessage() & @CRLF) EndIf Return $GUI_RUNDEFMSG EndFunc ;==>WM_TIMER Different approach, same result as with Edited November 29, 2022 by KaFu Danyfirex, argumentum and pixelsearch 3 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 November 30, 2022 Share Posted November 30, 2022 On 11/26/2022 at 3:54 PM, KaFu said: _WinAPI_KillTimer() does not work when used with a hWnd and no callback func, _WinAPI_SetTimer() needs to be fed a dedicated TimerID (see "9876" used below). When I use the TimerID returned by _WinAPI_SetTimer() then _WinAPI_KillTimer() does not work. I guess you wrote this in case the 2nd parameter in _WinAPI_SetTimer is set to 0 ($iTimerID) then the function returns 1 (tested) and _WinAPI_KillTimer() fails because of this 0/1 discrepancy. msdn SetTimer adds 4 crucial words at the very beginning of this 2nd parameter description : A nonzero timer identifier. Unfortunately these 4 words aren't found in AutoIt help file, topic _WinAPI_SetTimer, maybe because at the very end of the description, we also read the following sentence, where this 2nd parameter can sometimes be = 0 in a special case : If the call is not intended to replace an existing timer, $iTimerID should be 0 if the $hWnd is 0. Nevertheless (imho) this important short sentence "A nonzero timer identifier" should be indicated in AutoIt help file, at the same place where it's found on msdn, making it clearer for the user. KaFu 1 Link to comment Share on other sites More sharing options...
KaFu Posted November 30, 2022 Author Share Posted November 30, 2022 Good point, I'll report that in bug tracker and also ask for a second example for this different scenario, e.g. #include <GUIConstantsEx.au3> #include <Misc.au3> #include <WinAPISysWin.au3> #include <WindowsConstants.au3> Opt('TrayAutoPause', 0) Global $g_iCount = 0 Local $iTimerID = 999 Local $hGUI = GUICreate("Example") GUIRegisterMsg($WM_TIMER, "WM_TIMER") $iTimerID = _WinAPI_SetTimer($hGUI, $iTimerID, 1000, 0) Do Sleep(100) Until _IsPressed('1B') _WinAPI_KillTimer($hGUI, $iTimerID) Func WM_TIMER($hWnd, $iMsg, $iwParam, $ilParam) #forceref $hWnd, $iMsg, $iwParam, $ilParam ConsoleWrite($g_iCount & @CRLF) $g_iCount += 1 Return $GUI_RUNDEFMSG EndFunc ;==>WM_TIMER 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 December 1, 2022 Share Posted December 1, 2022 @KaFu this topic you created here was inspiring so thanks for that, especially I never used _WinAPI_SetTimer() until now. It helped me to add a functionality in TimRude's script (a tooltip constantly updated in a script when there is no GUI created by the user) KaFu 1 Link to comment Share on other sites More sharing options...
KaFu Posted December 1, 2022 Author Share Posted December 1, 2022 I used AdlibRegister() for that in the past. The great advantage of the TImers is, that they work even if a blocking function is called 😉. expandcollapse popup#include <GUIConstantsEx.au3> #include <Misc.au3> #include <WinAPISysWin.au3> #include <WindowsConstants.au3> ToolTip("1a53da04-c3d6-48fb-819f-6cf3dbe01c4c") Global $hWnd_ToolTip = WinGetHandle("1a53da04-c3d6-48fb-819f-6cf3dbe01c4c") ToolTip("") Sleep(1000) ; Tooltip doesn't flash! ToolTip("AdlibRegister") AdlibRegister("_Move_Tooltip", 10) ; Does move Tooltip Do Sleep(100) Until _IsPressed('1B') AdlibUnRegister("_Move_Tooltip") AdlibRegister("_Move_Tooltip", 10) ; Does NOT move Tooltip because of blocking function MsgBox(262144, "", "Blocks") AdlibUnRegister("_Move_Tooltip") ToolTip("_WinAPI_SetTimer") Local $hTimerProc = DllCallbackRegister('_TimerProc', 'none', 'hwnd;uint;uint_ptr;dword') Local $iTimerID = _WinAPI_SetTimer(0, 0, 10, DllCallbackGetPtr($hTimerProc)) ; Does move Tooltip, even with blocking function Do Sleep(100) Until _IsPressed('1B') MsgBox(262144, "", "Does not block") _WinAPI_KillTimer(0, $iTimerID) DllCallbackFree($hTimerProc) Func _TimerProc($hWnd, $iMsg, $iTimerID, $iTime) #forceref $hWnd, $iMsg, $iTimerId, $iTime _Move_Tooltip() EndFunc ;==>_TimerProc Func _Move_Tooltip() Local $aMousePos = MouseGetPos() If Not @error Then WinMove($hWnd_ToolTip, "", $aMousePos[0] + 20, $aMousePos[1] + 20) EndIf EndFunc ;==>_Move_Tooltip 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 December 1, 2022 Share Posted December 1, 2022 16 minutes ago, KaFu said: The great advantage of the TImers is, that they work even if a blocking function is called That's the main reason I was happy to discover your thread 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