Jump to content

Recommended Posts

It's been requested in the past to have multithreading to which the response was "It would take too much redesigning of Autoit" but what about Async? Multithreading and Async are two different things. This way we could put tasks in the background without having to fork processes. Right? Also better event handling would be nice rather than throwing everything in a while loop we could have some functionality like javascript which seems to be far more responsive and reliable as the more you add to your while loop the less change there is of your "event" getting caught for some reason (At least in my experience).

Link to post
Share on other sites

There is always GuiEventMode.

Any chance you could explain how they are different?

To me, they are by definition, the exact same thing.

 

The difference is that an async operation happens on the same thread. Lookup Javascript's async (Which is not multithreading) or even better C# async/await vs thread. Also, I think you were referring to OnEvent? OnEvent will help if it does what it says it does and continues executing the program loop while executing the event function. Thanks because I didn't know that existed but yeah, async is generally not the same as what you would consider multithreading and when asked about multithreading I'm sure that's what the Autoit devs are thinking of, not async.

Since there's already this OnEvent for GUI elements it wouldn't be a stretch to add async/await functionality beyond just executing a function when a GUI event happens.

Link to post
Share on other sites
Multithreading is different parts of a program running, typcially called threads.
 
Asynchronous programming uses threads to kick off a piece of code.   So asynchronous programming relies on multithreading to work.

 

 

https://social.msdn.microsoft.com/Forums/en-US/3de8670c-49ca-400f-a1dc-ce3a3619357d/difference-between-multithreading-and-asynchronous-programming?forum=csharplanguage

AutoIt Absolute Beginners    Require a serial    Pause Script    Video Tutorials by Morthawt   ipify 

Monkey's are, like, natures humans.

Link to post
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
  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Mbee
      I've been researching this topic for about three weeks, but I'm still very confused. What I'm trying to do is to add a menu item to an arbitrary, third- party applications title bar system menu and process user events relating to it. The main problem I'm having is that there appears to be  a wealth of UDFs and other techniques to accomplish this, and I can't figure out which to concentrate on as a good solution.  For example, I've looked closely at @BrewManNHB 's  GUIRegisterMsg replacement for GUICtrlSetOnEvent and GUIGetMsg, and @LarsJJ 's stunning product GUIRegisterMsg20 UDF, as well as standard build- in AutoIt functions and WinAPI functions, But before I ask for recommendations, I'll elaborate my needs in more detail...

      I'm nearing completion of my muilt-monitor UDF and AutoWinSwitch stand-alone application, but one tricky issue remains. The purpose of the application is to automatically move newly arisen windows and context menus and the like from a monitor which is being used for some other purpose (like playing a game or watching videos) to the other monitor so that the user can see them and act upon them.
      The feature I need all this for is to allow the user to prevent a user-designated window from being moved, even though it exists on the "blocked" or used monitor so that it would normally require moving. In my testing, I've run into this situation often enough that a solution is necessary.
      So what I've done so far is to call _GUICtrlMenu_GetSystemMenu() for the window in question, then called  _GUICtrlMenu_AddMenuItem() to add a new menu item named "Pinned". This is working perfectly, but of course that's far from sufficient. Because obviously I need to establish some kind of event handler so that when the user selects that item, I can then toggle or alter the state and style of that item to show whether it's pinned or not.
      I've tried simply adding an on-event handler when I created the menu item, but even with the proper "Opt" value for On Event mode, the handler is never invoked.
      I also tried BrewmanNH's UDF and then LarsJ's, but even though I get no errors, again the handlers are never invoked.
      Finally, before I post the code of my last try using -- probably erroneously -- LarsJ's GUIRegisterMsg20 UDF, may I please ask for each of your recommendations and advice as to what approach you would favor? It's clear I don't know the most apt solution. Thanks!
      When you examine my code snippets, please overlook the mistakes and false starts that still remain there until I'm in the final stages of cleanup. Note also that the code depends vitally on Maps, so it will only run properly on the latest Beta version of AutoIt. But I guess that's actually irrelevant, since the posted code won't pass syntax checking...
       
      #AutoIt3Wrapper_Res_Fileversion=1.3 #AutoIt3Wrapper_icon=iPulse.ico #AutoIt3Wrapper_UseX64=Y #AutoIt3Wrapper_Run_After=copy "%out%" AutoWinSwitch.exe #include <WinAPIGdi.au3> #include <APIGdiConstants.au3> #include <GUIConstants.au3> #include <Misc.au3> #include <MsgBoxConstants.au3> #include <Process.au3> #include <String.au3> #include <StringConstants.au3> #include <Timers.au3> #include <WinAPIProc.au3> #include <GUIConstantsEx.au3> #include <GuiMenu.au3> ;~ #include <TrayConstants.au3> #include "LocalIncludes\GetMonitorTables_v1.1.au3" #include "LocalIncludes\_GetHwndFromPID.au3" #include "LocalIncludes\GUIRegisterMsg20.au3" AutoItSetOption("MustDeclareVars", 1) ; Variables must be declared before use AutoItSetOption("GUIOnEventMode", 1) ; We will temporarily disable this later for StateChange GUI AutoItSetOption("WinTitleMatchMode", 1) ; 1 = Matches partial titles from the start AutoItSetOption("MouseCoordMode", 0) ; 0 = Coords are relative to window (not screen) AutoItSetOption("GUICloseOnESC", 1 ) ; Close if user presses ESC AutoItSetOption("TrayOnEventMode", 0) ; We will enable this later ; ; Const $C_ThisAppName = "AutoWinSwitch" Const $C_VersionStr = "v1.3 Beta" Global Const $C_Title = $C_ThisAppName & " " & $C_VersionStr ; ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; Const $C_AutoSwitchRegRootKey = "HKCU\Environment" Const $C_AutoSwitchRegValName = "AUTOWINSWITCHSTATE" Const $C_PathToTestApp = "B:\AutoIt Scripts\!ISN My Folder\My Projects\NFS Mounter\NFS_Mounter.exe" Const $C_StateDisabled=1, $C_StateBlockPrimary=2, $C_StateBlockSecondary=3, $C_StateUnset=4, $C_NumStateStrs=8 Const $C_ValidStateStrAra[$C_NumStateStrs] = [ "DIS", "TOP", "TOS", "DISABL", "BLOCKN", "BLOCKS", "BLOCKP", "NOTSET" ] Const $C_MoveTblNumCols=8 Global Enum $C_MoveTblHdlIx, $C_MoveTblMonIxIx, $C_MoveTblTitleIx, $C_MoveTblClassIx, $C_MoveTblProcIx, _ $C_MoveTblTypeIx, $C_MoveTblWinLocIx, $C_MoveTblDimsIx Const $C_NumDimCols=6 Global Enum $C_DimsWidthIx, $C_DimsHeightIx, $C_DimsLeftIx, $C_DimsTopIx, $C_DimsRightIx, $C_DimsBottomIx Const $C_CalcAbsLeft=1, $C_CalcAbsRight=2, $C_CalcAbsTop=3, $C_CalcAbsBot=4 Const $C_WinTypeMain=1, $C_WinTypePopup=2 Const $C_OnOpenMon = 1, $C_OnBlockedMon = 2, $C_SpansMon = 3 Const $C_TitlesToIgnoreAraCount = 7 Const $C_TitlesToIgnoreAra[$C_TitlesToIgnoreAraCount] = [ "Microsoft Text Input", _ "Program Manager", _ "*AutoIt", _ "Settings", _ "WorkerW", _ "*Debugger", _ "*DBUG" ] ;- - - - - - Global $G_GenMonTbl[$Gc_GMTblNumCols], $G_MMonitorTbl[1][$Gc_MMTblNumCols] Global $G_CurWinMap[], $G_PrevWinMap[], $G_PinnedMap[], $L_EmptyMap[] Global $G_MoveTimerAra[1][2], $G_MoveTimerAraIdx=-1, $G_AWS_HidWinHdl = -1 Global $G_MutexHdl, $G_WeOwnMutex, $G_Gid_PriRadioBtn, $G_Gid_SecRadioBtn, $G_Gid_DisabledRadioBtn Global $G_MonIxToShowGUI = 0 Global $G_SwitchStateStr, $G_SwitchStateCode, $G_SwitchStateChanged = False Global $G_NumValidMons=0, $G_TestAppPID, $G_TestAppWinHdl, $G_TestAppTitle="NFS_Mounter", $G_TestAppPosAra[2] ;~ $WM_CLOSE = 0x0010 ;~ $WM_MENUCOMMAND = 0x0126 ;~ $WM_MENUSELECT = 0x011F ;~ $WM_MOVE = 0x0003 ;~ $WM_MOVING = 0x0216 Global Enum $C_UseExtWinHdl, $C_UseExtCtrlHdl Global $G_SysWinMsgCodesRegAraCount = 5 Global $G_SysWinMsgCodesRegAra[$G_SysWinMsgCodesRegAraCount][3] = [ _ [ $C_UseExtWinHdl, $WM_CLOSE, __ExtCloseCmdHandler ], _ [ $C_UseExtWinHdl, $WM_MOVE, __ExtMoveWinHandler ], _ [ $C_UseExtWinHdl, $WM_MOVING, __ExtMovIngWinHandler ], _ [ $C_UseExtCtrlHdl, $WM_MENUCOMMAND, __ExtMenuCmdHandler ], _ [ $C_UseExtCtrlHdl, $WM_MENUSELECT, __ExtMenuSelectHandler ] ] ; ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; Local $L_WorkDir = "B:\ISN AutoIt Studio\Projects\AutoWinSwitch\AutoWinSwitch Release 1.3 Beta" $L_RptPath = _UniqueOutFilePath( "WinReport", "txt", $L_WorkDir, 99 ) If @error <> 0 Then MsgBox($MB_OK, $C_Title, "Error: Unable to generate unique output filepath -- Exiting...") Exit 0 EndIf Global $G_RptFileHdl = FileOpen( $L_RptPath, $FO_OVERWRITE + $FO_UTF8_NOBOM ) If $G_RptFileHdl = -1 Then MsgBox($MB_OK, $C_Title, "ERROR - Unable to open report file -- Exiting...") Exit EndIf OnAutoItExitRegister("_ExitCapture") FileWriteLine( $G_RptFileHdl, "-- Begin run --" & @CRLF ) ; ;=================================================================================================================== ; ; ; The following code ensures that no other instance of AutoWinSwitch is running. ; ;~ $G_RptFileHdl = FileOpen( $L_RptPath, "About to check Mutex") ;~ $G_MutexHdl = _Singleton( "Global\AutoWinSwitchMUTEX", 3 ) ;~ If $G_MutexHdl = 0 Then ;~ FileWriteLine( $G_RptFileHdl, "We do NOT own the Mutex -- Exiting" ) ;~ MsgBox($MB_OK + $MB_TOPMOST, $C_Title, "Another copy of this tool is already running -- This copy will now exit") ;~ Exit 47 ;~ EndIf $G_WeOwnMutex = True ; ; Setup all the information about whatever monitors are present in this system ; ;~ <snip> <snip> <snip> ; ;=================================================================================================================== ; $G_SwitchStateStr = RegRead( $C_AutoSwitchRegRootKey, $C_AutoSwitchRegValName ) If @error <> 0 Then FileWriteLine( $G_RptFileHdl, "Error reading Switch State -- Setting Reg to DIS for now" ) $L_Stat = RegWrite( $C_AutoSwitchRegRootKey, $C_AutoSwitchRegValName, "REG_SZ", "DIS" ) ; Set registry to disabled $G_SwitchStateStr = "NOTSET" $G_SwitchStateCode = $C_StateUnset Else FileWriteLine( $G_RptFileHdl, "Switch State read from Registry is: " & $G_SwitchStateStr ) EndIf $G_SwitchStateCode = _StateStrToCode( $G_SwitchStateStr ) If @error <> 0 Then FileWriteLine( $G_RptFileHdl, "_StateStrToCode() Returned @error = " & @error & " -- Exiting") MsgBox($MB_OK + $MB_TOPMOST, $C_Title, "AutoWinSwitch - ERROR: Unrecognizable State in Registry - Exiting") Exit 6 EndIf $L_VerboseStateStr = _StateCodeToStr( $G_SwitchStateCode, "Verbose" ) If @error <> 0 Then FileWriteLine( $G_RptFileHdl, "_StateCodeToStr() Returned @error = " & @error & " -- Exiting") MsgBox($MB_OK + $MB_TOPMOST, $C_Title, "_StateCodeToStr() Returned @error = " & @error & " -- Exiting") Exit 7 EndIf $L_SpashMonIdx = $L_PrimaryMonTblIdx If $G_SwitchStateCode = $C_StateBlockPrimary Then $L_SpashMonIdx = $L_SecondaryMonTblIdx EndIf $L_SplashStr = "Initial State: " & $L_VerboseStateStr $L_SplashStrLen = StringLen( $L_SplashStr ) $L_SplashX = $G_MMonitorTbl[$L_SpashMonIdx][$Gc_MMTblCenterXIx] - Floor($L_SplashStrLen / 2) $L_SplashY = $G_MMonitorTbl[$L_SpashMonIdx][$Gc_MMTblTopIx] + 4 ;~ For $i = 1 To 2 $L_SplashHdl = SplashTextOn( "AutoWinSwitch Current State", $L_SplashStr, 400, 40, $L_SplashX, $L_SplashY, _ $DLG_CENTERONTOP + $DLG_MOVEABLE, "Lucida Sans Unicode", 11, $FW_SEMIBOLD ) Sleep( 1000 ) SplashOff() ;~ Sleep( 500 ) ;~ Next $L_OrigStateCode = $G_SwitchStateCode If ($L_OrigStateCode = $C_StateDisabled) Or ($L_OrigStateCode = $C_StateUnset) Then $G_SwitchStateCode = _ShowSwitchStateChangeGUI() If $G_SwitchStateChanged Then If $G_SwitchStateCode = $C_StateDisabled Then FileWriteLine( $G_RptFileHdl, "The GUI told us to disable and exit. Code = " & $G_SwitchStateCode ) MsgBox($MB_OK + $MB_TOPMOST, $C_Title, "The GUI told us to disable and exit!") Exit 5 EndIf EndIf $G_SwitchStateChanged = False EndIf Switch $G_SwitchStateCode Case $C_StateBlockPrimary $L_BlockedMonIdx = $L_PrimaryMonTblIdx $L_OpenMonIdx = $L_SecondaryMonTblIdx $L_CurMonTblIdx = $L_SecondaryMonTblIdx $G_MonIxToShowGUI = $L_OpenMonIdx Case $C_StateBlockSecondary $L_BlockedMonIdx = $L_SecondaryMonTblIdx $L_OpenMonIdx = $L_PrimaryMonTblIdx $L_CurMonTblIdx = $L_PrimaryMonTblIdx $G_MonIxToShowGUI = $L_OpenMonIdx EndSwitch $L_MoveTblCount = -1 ; We'll increment this when we want to add new windows to be moved $L_NumPrevWins = 0 $L_NumPrevPopups = 0 ; ; Begin Primary Operations... ; $G_TestAppWinHdl = WinGetHandle( $G_TestAppTitle ) If $G_TestAppWinHdl = 0 Then $G_TestAppPID = ShellExecute( $C_PathToTestApp ) ; This launches the test app asynchronously If $G_TestAppPID = 0 Then ; If the launch failed... MsgBox($MB_OK, $C_Title, "Fatal Error: Unable to launch test app -- Exiting") Exit 12121 EndIf $G_TestAppWinHdl = _GetHwndFromPID( $G_TestAppPID ) $G_TestAppTitle = WinGetTitle( $G_TestAppWinHdl ) Else $G_TestAppPID = WinGetProcess( $G_TestAppWinHdl ) EndIf $L_Stat = _AddPinMenuItem( $G_TestAppWinHdl ) ;~ <snip> <snip> <snip> $L_Stat = HotKeySet( "+!a", "_ShowSwitchStateGUIWrapper" ) ; Shift-Alt-A brings up the State Change GUI While True Local $L_CurTopWinAra = _WinAPI_EnumWindowsTop() $L_NumCurWins = $L_CurTopWinAra[0][0] If $L_NumPrevWins = 0 Then ; If this is the first time through this watch loop... For $i = 1 To $L_NumCurWins ; Build the Map of all top-level wins, to provide a basis for later comparison $L_CurWinHdl = $L_CurTopWinAra[$i][0] If WinExists( $L_CurWinHdl ) <> 1 Then ; This window may have been closed by this time ContinueLoop EndIf If ($L_CurWinHdl <> 0) And (IsHWnd($L_CurWinHdl) = 1) Then $L_ThisClass = $L_CurTopWinAra[$i][1] EndIf Next $L_NumPrevWins = $L_NumCurWins Else ; If we've been through this loop more than once, we'll have something to compare against $G_PrevWinMap = $G_CurWinMap ; Move the contents of the "current" Map (from from the previous pass) here. $G_CurWinMap = $L_EmptyMap ; We must empty that old Map so that we can load it up with ONLY the current windows $L_NumPrevWins = $L_NumCurWins ; That count now represents the number of top-level windows from previous pass For $i = 1 To $L_NumCurWins ; Re-build the current window Map $L_CurWinHdl = $L_CurTopWinAra[$i][0] If WinExists( $L_CurWinHdl ) <> 1 Then ; This window may have been closed by this time ContinueLoop EndIf If ($L_CurWinHdl <> 0) And (IsHWnd($L_CurWinHdl) = 1) Then $L_ThisClass = $L_CurTopWinAra[$i][1] ;~ If MapExists( $G_PinnedMap, $L_CurWinHdl ) Then ; If we're supposed to leave this win where it is ;~ ContinueLoop ;~ EndIf ;~ _Add2Map( $L_CurSpclMap, $L_CurWinHdl, $L_ThisClass ) ;~ If @error <> 0 Then ;~ FileWriteLine( $G_RptFileHdl, "ERROR - _Add2Map( #2 = " & Hex($L_CurWinHdl) * " ) Failed -- Aborting") ;~ MsgBox($MB_OK, $C_Title, "ERROR - _Add2Map( #2 = " & Hex($L_CurWinHdl) * " ) Failed -- Aborting") ;~ Exit 6 ;~ EndIf EndIf Next ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - For $i = 1 To $L_NumCurWins ; Now that we have the NEW Cur Map built, we can compare it to Previous Map $L_CurWinHdl = $L_CurTopWinAra[$i][0] If ($L_CurWinHdl <> 0) And (IsHWnd($L_CurWinHdl) = 1) Then If WinExists( $L_CurWinHdl ) <> 1 Then ; This window may have been closed by this time ContinueLoop EndIf If MapExists( $G_PinnedMap, $L_CurWinHdl ) Then ; If we're supposed to leave this win where it is ContinueLoop EndIf $L_ThisClass = $L_CurTopWinAra[$i][1] If Not MapExists( $G_PrevWinMap, $L_CurWinHdl ) Then ; If this window wasn't in the prev list, i'ts new $L_Stat = _AnalyzeNewWin( $G_PrevWinMap, $L_CurWinHdl, $L_ThisClass ) If $L_Stat <> 0 Then ; If this window is new & has been added to the table of wins to be moved $L_ThisClass = $G_PrevWinMap[$L_CurWinHdl] MapRemove( $G_CurWinMap, $L_CurWinHdl ) ; Ensure that this win doesn't look like a fresh one MapRemove( $G_PrevWinMap, $L_CurWinHdl ) ; ... either past or present EndIf EndIf EndIf Next EndIf ; ; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; If $L_MoveTblCount >= 0 Then ; IF we need to move at least 1 win (valid indices/count start at 0) $L_Stat = _RelocateWins( ) $L_MoveTblCount = -1 EndIf ;;~ <snip> <snip> <snip> Sleep( 1000 ) WEnd Exit 12 ; ;=================================================================================================================== ; ; This function was kindly contributed by jchd ; See: https://www.autoitscript.com/forum/topic/204187-please-review-my-usage-of-scripting-dictionaries/?do=findComment&comment=1467804 ; Func _Add2Map(ByRef $map, $key, $value) If MapExists($map, $key) Then ; same as If $m[$key] = Null Then If IsMap($map[$key]) Then MapAppend($map[$key], $value) Else Local $m2[] ; an empty map $m2[1] = $map[$key] $m2[2] = $value $map[$key] = $m2 EndIf Else $map[$key] = $value EndIf EndFunc ;==>_Add2Map ; ;=================================================================================================================== ; ; _AnalyzeNewWin -- Analyze a newly discovered window to see if it should be moved to the other monitor. ; ; Return code: 0 = Ignore this window. ; 1 = This is an intruding window entirely on a blocked monitor, so it must be moved ; 2 = This is an intruding window partially on a blocked monitor, so it might need to be moved ; -1 = An error occurred during processing ; Func _AnalyzeNewWin( ByRef $arg_Map, $arg_WinHdl, $arg_Class ) ;~ <snip> <snip> <snip> Return 2 EndFunc ;==>_AnalyzeNewWin ; ;=================================================================================================================== ; ; We now know that there's at least one window (normal or popup) that needs to be relocated to a ; different monitor. ; ; Currently, there's no need to distinguish between the two window types (normal or popup), but ; there might need to be in the future, so I've decided to prepare for this eventuality. ; Func _RelocateWins() Const $Lfc_MoveFull = 1, $Lfc_MovePartial = 2 ;~ <snip> <snip> <snip> Return 1 EndFunc ;==>_RelocateWins ; ;= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; Func _AddIfUnseenWin( ByRef $arg_Map, ByRef $arg_MoveTblWinInfoRow ) ; ; This function determines if we've seen this window before, and if NOT, then it ; gets added to the appropriate Map. ; ;~ <snip> <snip> <snip> Return 1 EndFunc ;==>_AddIfUnseenWin ; ;= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; Func _AddPinMenuItem( $arg_ExtWinHdl ) Local $Lf_Stat, $Lf_ExtPID, $Lf_ExtSysMenuHdl, $Lf_ExtPinMenuHdl, $Lf_PinMenuItemIndex, $Lf_PinMenuItemID Local $Lf_InPinnedMap, $Lf_PinMenuItemExists, $Lf_SysMsgCodeMin, $Lf_SysMsgCodeMax If MapExists( $G_PinnedMap, $arg_ExtWinHdl ) Then $Lf_InPinnedMap = True Else $Lf_InPinnedMap = False EndIf $Lf_ExtPID = WinGetProcess( $arg_ExtWinHdl ) $Lf_ExtSysMenuHdl = _GUICtrlMenu_GetSystemMenu( $arg_ExtWinHdl, False ) $Lf_PinMenuItemIndex = _GUICtrlMenu_FindItem( $Lf_ExtSysMenuHdl, "Pinned", True ) If $Lf_PinMenuItemIndex = -1 Then $Lf_PinMenuItemExists = False Else $Lf_PinMenuItemExists = True $Lf_PinMenuItemID = _GUICtrlMenu_GetItemID( $Lf_ExtSysMenuHdl, $Lf_PinMenuItemIndex, True ) EndIf If Not $Lf_PinMenuItemExists Then If $Lf_InPinnedMap Then MapRemove( $G_PinnedMap, $arg_ExtWinHdl ) Return SetError( 0, 0, 2 ) EndIf $Lf_PinMenuItemIndex = _GUICtrlMenu_AddMenuItem( $Lf_ExtSysMenuHdl, "Pinned", 47 ) If $Lf_PinMenuItemIndex = -1 Then Return SetError( 17226, 0, 0 ) EndIf $Lf_PinMenuItemID = _GUICtrlMenu_GetItemID( $Lf_ExtSysMenuHdl, $Lf_PinMenuItemIndex, True ) _Add2Map( $G_PinnedMap, $arg_ExtWinHdl, $Lf_PinMenuItemID) $Lf_ExtPinMenuHdl = GUICtrlGetHandle( $Lf_PinMenuItemID ) $Lf_Stat = _SetupExtWinMsgRegs( $arg_ExtWinHdl, $Lf_ExtPinMenuHdl ) Return SetError( @error, 0, $Lf_Stat ) EndIf Return SetError( 0, 0, 1 ) EndFunc Func __PinMenuCmdHandler() Local $Lf_ControlID, $Lf_SendingWinHdl, $Lf_ControlHdl, $Lf_ExtSysMenuHdl Local $Lf_Enabled, $Lf_Highlighted $Lf_ControlID = @GUI_CtrlId $Lf_SendingWinHdl = @GUI_WinHandle $Lf_ControlHdl = @GUI_CtrlHandle $Lf_ExtSysMenuHdl = _GUICtrlMenu_GetSystemMenu( $Lf_SendingWinHdl, False ) $Lf_Enabled = _GUICtrlMenu_GetItemDisabled( $Lf_ExtSysMenuHdl, $Lf_ControlID, False ) $Lf_Highlighted = _GUICtrlMenu_GetItemHighlighted( $Lf_ExtSysMenuHdl, $Lf_ControlID, False ) If $Lf_Enabled Or $Lf_Highlighted Then _GUICtrlMenu_SetItemEnabled( $Lf_ExtSysMenuHdl, $Lf_ControlID, False, False ) _GUICtrlMenu_SetItemHighlighted( $Lf_ExtSysMenuHdl, $Lf_ControlID, False, False ) _GUICtrlMenu_EnableMenuItem( $Lf_ExtSysMenuHdl, $Lf_ControlID, 2, False ) If MapExists( $G_PinnedMap, $Lf_ExtSysMenuHdl) Then MapRemove( $G_PinnedMap, $Lf_ExtSysMenuHdl ) EndIf Else _GUICtrlMenu_SetItemEnabled( $Lf_ExtSysMenuHdl, $Lf_ControlID, True, False ) _GUICtrlMenu_SetItemHighlighted( $Lf_ExtSysMenuHdl, $Lf_ControlID, True, False ) _GUICtrlMenu_EnableMenuItem( $Lf_ExtSysMenuHdl, $Lf_ControlID, 0, False ) _GUICtrlMenu_DrawMenuBar( $Lf_ExtSysMenuHdl ) _Add2Map( $G_PinnedMap, $Lf_ExtSysMenuHdl, $Lf_ControlID ) EndIf _GUICtrlMenu_DrawMenuBar( $Lf_ExtSysMenuHdl ) Return EndFunc ; ;= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; Func _IsMonitorBlocked( ByRef $arg_MoveTblWinInfoRow ) ; ; This func determines if the passed window is currently presented on a "blocked" monitor ; ; Returns: $C_OnOpenMon (=1) If the window in the passed Move Table Window Info Row is on an Open monitor ; $C_OnBlockedMon (=2) If ... on Blocked mon ; $C_SpansMon (=3) If the window spans across both open and blocked mon ; ;~ <snip> <snip> <snip> EndFunc ;==>_IsMonitorBlocked ; ; = = = = = = = = = = = = = = = = = = = ; Func _SetupExtWinMsgRegs( $arg_ExtWinHdl, $arg_ExtControlHdl ) Local $Lf_Stat For $i = 0 To $G_SysWinMsgCodesRegAraCount -1 If $G_SysWinMsgCodesRegAra[$i][0] = $C_UseExtWinHdl Then $Lf_Stat = GUIRegisterMsg20( $arg_ExtWinHdl, $G_SysWinMsgCodesRegAra[$i][1], $G_SysWinMsgCodesRegAra[$i][2] ) Else $Lf_Stat = GUIRegisterMsg20( $arg_ExtControlHdl, $G_SysWinMsgCodesRegAra[$i][1], $G_SysWinMsgCodesRegAra[$i][2] ) EndIf If $Lf_Stat <> 1 Then Return SetError( @error, 0, 1 ) EndIf Next Return SetError( 0, 0, 0 ) EndFunc ; ; = = = = = = = = = = = = = = = = = = = ; Func __ExtCloseCmdHandler( $arg_hWnd, $arg_Msg, $arg_wParam, $arg_lParam ) #forceref $arg_hWnd, $arg_Msg, $arg_wParam, $arg_lParam Return $GUI_RUNDEFMSG EndFunc ; ; - - - - - - - - - - - - - - - - - - - ; Func __ExtMoveWinHandler( $arg_hWnd, $arg_Msg, $arg_wParam, $arg_lParam ) #forceref $arg_hWnd, $arg_Msg, $arg_wParam, $arg_lParam FileWriteLine( $G_RptFileHdl, "In __ExtMoveWinHandler()" ) Return $GUI_RUNDEFMSG EndFunc ; ; - - - - - - - - - - - - - - - - - - - ; Func __ExtMovIngWinHandler( $arg_hWnd, $arg_Msg, $arg_wParam, $arg_lParam ) #forceref $arg_hWnd, $arg_Msg, $arg_wParam, $arg_lParam FileWriteLine( $G_RptFileHdl, "In __ExtMovIngWinHandler()" ) Return $GUI_RUNDEFMSG EndFunc ; ; - - - - - - - - - - - - - - - - - - - ; Func __ExtMenuCmdHandler( $arg_hWnd, $arg_Msg, $arg_wParam, $arg_lParam ) #forceref $arg_hWnd, $arg_Msg, $arg_wParam, $arg_lParam FileWriteLine( $G_RptFileHdl, "In __ExtMenuCmdHandler()" ) Return $GUI_RUNDEFMSG EndFunc ; ; - - - - - - - - - - - - - - - - - - - ; Func __ExtMenuSelectHandler( $arg_hWnd, $arg_Msg, $arg_wParam, $arg_lParam ) #forceref $arg_hWnd, $arg_Msg, $arg_wParam, $arg_lParam FileWriteLine( $G_RptFileHdl, "In __ExtMenuSelectHandler()" ) Return $GUI_RUNDEFMSG EndFunc  
    • By guinness
      So asynchronous programming is something quite difficult to do in JavaScript, but since we now have Promises and async/await, it's becoming increasingly less complicated. Plus there is no need for "callback hell".
      So I will assume you understand what Promise.all() is and why it can sometimes be problematic, as it will not wait for all requests to complete and just fails on the first rejected Promise. The following function will still reject on a failed Promise, but the difference being it will wait for all the Promises to complete before resolving or rejecting. If no failure occurred, then the resolved value is the same as Promise.all(), an array of resolved values; otherwise, it returns a completed object (see below for details). Also note that the array might contain empty slots, this is so it's easier to debug which Promise failed in the array, as they're inserted in the same index slot
      Promise.allComplete = (iterable) => { if (!Array.isArray(iterable)) { throw new TypeError('Invalid argument, expected "iterable" to be an array'); } const completed = { resolved: [], rejected: [], }; const wrapResolutionOrRejection = (type, index) => valueOrReason => (completed[type][index] = valueOrReason); const wrappedIterable = iterable.map((value, index) => Promise.resolve(value) // The rejected wrapper function could be put in the catch, but it's wasteful for our purposes .then(wrapResolutionOrRejection('resolved', index), wrapResolutionOrRejection('rejected', index)) ) return Promise.all(wrappedIterable) .then(() => completed.rejected.length === 0 ? Promise.resolve(completed.resolved) : Promise.reject(completed)); }; // Example const requests = [ createPromise(true, 10), createPromise(false, 10), createPromise(true, 200), createPromise(true, 1000), ]; // Rejects on the first Promise which fails, but if you check in the console, it didn't wait // for the third Promise to successfully complete, as the console log came after the error log was displayed // Promise.all(requests) // .then(values => console.log('Successfully completed', values)) // .catch(err => console.error('Not successfully completed', err)) // "allComplete" is different, in that it will wait for all the Promises to be completed i.e. resolve and reject, // then resolve if all Promises were successful or reject if one Promise failed. // It returns the following data structure: // { // resolved: [...Promises which resolved, and inserted by the associated Promise's index], // rejected: [..Promises which rejected, and inserted by the associated Promise's index], // } Promise.allComplete(requests) .then(completed => console.log('Successfully completed', completed)) .catch(completed => console.log('Not successfully completed', completed)) function createPromise(isResolved, delay) { return new Promise((resolve, reject) => { setTimeout(() => { console.log(`Promise: "${delay}"`); if (isResolved) { resolve(delay); } else { reject(new Error('An unexpected error occurred')); } }, delay); }); }  
    • By AutID
      I have some nested async methods calling each other and it is confusing. I am trying to convert a project which downloads the files in an async download. On the click of the download button this is the method triggered:
      private async void enableOfflineModeToolStripMenuItem_Click(object sender, EventArgs e) { for(int i = 0; i < _playlists.Count; i++) { DoubleDimList.Add(new List<String>()); for(int j = 0; j < 5; j++) { string sMp3 = IniReadValue(_playlists[i], "Track " + j); DoubleDimList[i].Add(sMp3); } await Task.Run(() => _InetGetHTMLSearchAsyncs(DoubleDimList[i])); } } It creates a 2d List which at the end looks like this DoubleDimList[3][20]. At the end of each sublist I am doing an async download as you can see. The method looks like this
      private async Task _InetGetHTMLSearchAsyncs(List<string> urlList) { foreach (var url in urlList) { await Task.Run(() => _InetGetHTMLSearchAsync(url)); } } the _InetGetHTMLSearchAsync method looks like this and here is where it gets tricky
      private async Task _InetGetHTMLSearchAsync(string sTitle) { Runs++; if (AudioDumpQuery == string.Empty) { //return string.Empty; } string sResearchURL = "http://www.audiodump.biz/music.html?" + AudioDumpQuery + sTitle.Replace(" ", "+"); try { using (var client = new WebClient()) { client.Headers.Add("Referer", @"http://www.audiodump.com/"); client.Headers.Add("user-agent", "Mozilla / 5.0(Macintosh; Intel Mac OS X 10_9_3) AppleWebKit / 537.75.14(KHTML, like Gecko) Version / 7.0.3 Safari / 7046A194A"); client.DownloadStringCompleted += Client_DownloadStringCompleted; await Task.Run(() => client.DownloadStringAsync(new Uri(sResearchURL))); } } catch (Exception ex) { Console.WriteLine("Debug message: " + ex.Message + "InnerEx: " + ex.StackTrace); Console.WriteLine("Runs: " + Runs); //throw exception return; } } On Client_DownloadStringCompleted there is another async method called. Here it is
      private async void Client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) { string[] sStringArray; string aRet = e.Result; string[] aTable = _StringBetween(aRet, "<BR><table", "table><BR>", RegexOptions.Singleline); if (aTable != null) { string[] aInfos = _StringBetween(aTable[0], ". <a href=\"", "<a href=\""); if (aInfos != null) { for (int i = 0; i < 1; i++) { sStringArray = aInfos[i].Split('*'); sStringArray[0] = sStringArray[0].Replace("&#39;", "'"); aLinks.Add(sStringArray[0]); } await Task.Run(() => DownloadFile(aLinks[FilesDownloaded])); } } } From there, surprise! Another async call.
      private async Task DownloadFile(string url) { try { using (var client = new WebClient()) { client.Headers.Add("Referer", @"http://www.audiodump.biz/"); client.Headers.Add("user-agent", "Mozilla / 5.0(Macintosh; Intel Mac OS X 10_9_3) AppleWebKit / 537.75.14(KHTML, like Gecko) Version / 7.0.3 Safari / 7046A194A"); client.DownloadFileCompleted += Client_DownloadFileCompleted; await Task.Run(() => client.DownloadFileTaskAsync(url, mp3Path + "\\" + count + ".mp3")); } } catch (Exception Ex) { Console.WriteLine("File download error: " + Ex.StackTrace); //throw exception } } Now the first part after the creation of the 2d List is to retrieve the download links of the mp3s. The second part is to download the mp3 as soon as a valid URL was provided. It works but in a bizarre way. Instead of downloading the file normally(1st, 2nd, 3rd...), it will download randomly the files(1st, 5th, 8th...).
      Where am I messing this up because I definitely am!?
    • By JakeJohnson74
      Hey Guys, this is somewhat related to another post in here but my specific question was "answered" and so I thought I would make a new post that is referencing the same code, with slightly different issues. 
      Problem 1
      Setup: I am using a label docked to the main GUI to set the size of a child GUI. 
      Issue: When I slowly drag the borders, I can see my green label kind of peeking out from behind the GUI, not a huge problem I guess. If I drag the border very quicky I can get the offset to be really big (200-300 pixels)
      ** Edit - I just realized that the child of the child GUI actually does not display this same "lag" or difference in sizing. hmmmm
      Problem 2
      *discaimer! - Melba if you see this, I know you have Aero disabled so I understand if you don't want anything to do with this one! haha
      Setup: Using windows message WM_WINDOWPOSCHANGING. This should give me a message "While" the window is changing. There is a WM_WINDOWPOSCHANGED, which should fire after the change happens. 
      Issue: Upon a normal maximize/restore methods (double clicking title bar, or using the buttons) the window behaves. Upon an Aero Snap maximize/restore the update only happens AFTER I let go of my left click. So while dragging the window down from its maximized state the child GUI's remain maximized until I let go of the left click  mouse button and it resizes. I really want this to resize the second it unsnaps from the maximized state. 
      **Edit - This is due to the way I am handling the flags parameter of the WINDOWPOS Struct. I'm masking only using 1 of the members and it only sees that once the LMB is released. So I am basically misusing the message because im not very familiar with it I have experimented with bitOR(member1, member2, member3) because im thinking SWP_FRAMECHANGED is not the only member I should be masking against "flags" (although it works somewhat)
      Here is my code. 
      #include <GuiConstantsEx.au3> #include <WindowsConstants.au3> #include <WinAPI.au3> $iGuiWidth = 660 $iGUIHeight = 320 $DividerOffset = 244 Global $aGUIPos[6] Global $hgui, $hgui1, $hguiInner1, $cLabel_1, $cLabel_2, $cLabel_3, $iOFfset_X1, $iOFfset_Y1 Global $bSysMsg = False GUI() GUIRegisterMsg($WM_SIZE, "_WM_SIZE") GUIRegisterMsg($WM_WINDOWPOSCHANGING, "_WM_WINDOWPOSCHANGING") Func GUI() $hgui = GUICreate("test", $iGuiWidth, $iGUIHeight, -1, -1, BitOR($WS_OVERLAPPEDWINDOW, $WS_POPUP)) GUISetBkColor(0x666666) $cLabel_1 = GUICtrlCreateLabel("I am the label", 4, 65, $iGuiWidth - 7, 250) GUICtrlSetBkColor(-1, 0x00FF00) GUICtrlSetResizing(-1, BitOR($GUI_DOCKLEFT, $GUI_DOCKTOP, $GUI_DOCKBOTTOM, $GUI_DOCKWIDTH, $GUI_DOCKRIGHT)) GUICtrlSetState(-1, $GUI_DISABLE) GUISetState() $hgui1 = GUICreate("", $iGuiWidth - 7, $iGUIHeight - 70, -1, 60, $WS_POPUP, $WS_EX_MDICHILD, $hgui) GUISetBkColor(0x888888) GUISetState() $Divider = GUICtrlCreateLabel('', $DividerOffset, 0, 5, 250) GUICtrlSetBkColor(-1, 0xFF0000) GUICtrlSetResizing(-1, BitOR($GUI_DOCKWIDTH, $GUI_DOCKLEFT, $GUI_DOCKTOP, $GUI_DOCKBOTTOM)) GUICtrlSetCursor(-1, 13) GUISetState() $cLabel_2 = GUICtrlCreateLabel("I am the label", 249, 25, 403, 225) GUICtrlSetBkColor(-1, 0x0000FF) GUICtrlSetResizing(-1, BitOR($GUI_DOCKLEFT, $GUI_DOCKTOP, $GUI_DOCKBOTTOM, $GUI_DOCKWIDTH, $GUI_DOCKRIGHT)) GUICtrlSetState(-1, $GUI_DISABLE) GUISetState() $hGuiInner1 = GUICreate("", 403, 225, 252,28, $WS_POPUP, $WS_EX_MDICHILD, $hgui1) GUISetBkColor(0x555555) GUISetState() _GetGuiPos($hgui,0,1) _GetGuiPos($hgui1,2,3) ;~ _GetGuiPos(hgui2,3,4) For $i = 0 to 5 ConsoleWrite("$aguipos[" & $i & "]:=" & $aguipos[$i] & @LF) Next EndFunc ;==>GUI While 1 $msg = GUIGetMsg() Switch $msg Case $GUI_EVENT_CLOSE Quit() EndSwitch If $bSysMsg Then $bSysMsg = False _Resize_GUIs() EndIf WEnd Func Quit() Exit EndFunc ;==>Quit Func _Resize_GUIs() ;GUI1 $aWin1 = WinGetPos($hgui) $aRet1 = ControlGetPos($hgui, "", $cLabel_1) WinMove($hgui1, "", $aWin1[0] + $aGUIPos[0] + $aRet1[0], $aWin1[1] + $aGUIPos[1] + $aRet1[1], $aRet1[2], $aRet1[3]) $aWin2 = WinGetPos($hgui1) $aRet2 = ControlGetPos($hgui1, "", $cLabel_2) WinMove($hguiInner1, "", $aWin2[0] + $aGUIPos[2] + $aRet2[0], $aWin2[1] + $aGUIPos[3] + $aRet2[1], $aRet2[2], $aRet2[3]) ;~ $aWin3 = WinGetPos($hgui) ;~ $aRet3 = ControlGetPos($hgui, "", $cLabel_3) ;~ WinMove($hgui1, "", $aWin3[0] + $aGUIPos[4] + $aRet3[0], $aWin3[1] + $aGUIPos[5] + $aRet3[1], $aRet3[2], $aRet3[3]) EndFunc ;==>_Resize_GUIs func _WM_WINDOWPOSCHANGING($hWnd, $msg, $wParam, $lParam) Local $winpos_Struct = DllStructCreate("hwnd hwnd;hwnd hwndInsertAfter;int x;int y;int cx;int cy;uint flags", $lParam) $MaximizeOrRestore = bitand(DllStructGetData($winpos_Struct, "flags"), $SWP_FRAMECHANGED) if $MaximizeOrRestore > 0 then $bSysMsg = True endif EndFunc Func _WM_SIZE($hWnd, $msg, $wParam, $lParam) _Resize_GUIs() Return $GUI_RUNDEFMSG EndFunc ;==>_WM_SIZE Func _Exit($s_Msg) MsgBox(0, "Error", $s_Msg) Exit EndFunc Func _GetGuiPos($hTargGUI,$iArrayEle1,$iArrayEle2) $aWin = WinGetPos($hTargGUI) Local $tPoint = DllStructCreate("int X;int Y") DllStructSetData($tPoint, "X", 0) DllStructSetData($tPoint, "Y", 0) _WinAPI_ClientToScreen($hTargGUI, $tPoint) $aGUIPos[$iArrayEle1] = DllStructGetData($tPoint, "X") - $aWin[0] $aGUIPos[$iArrayEle2] = DllStructGetData($tPoint, "Y") - $aWin[1] EndFunc
    • By lbsl
      Hi folks,
      I've been happily abusing this forum resources (and many others as well) for over three years now to get stuff done in AutoIT3.
      I'm currently stuck at a point where i need to fake some sort of multithreading.
      I know AutoIT3 does not and will not support it, but if there only was a good way to tap into the full event trapping cycle of the AU3 engine, i could at least add in some of the routines that need a checkup.
      I figured so far that using the GuiOnEventMode and TrayOnEventMode should allow me to give me this opportunity, but unfortunately, it doesn't.
      I have extended the existing Au3 examples for both options with a counter to show what i mean:
      #include <GUIConstantsEx.au3> #include <Constants.au3> #NoTrayIcon Global $x = 1 Example() Func Example() Opt("GUICoordMode", 2) Opt("GUIResizeMode", 1) Opt("GUIOnEventMode", 1) Opt("TrayOnEventMode", 1) Opt("TrayMenuMode", 1) ; Default tray menu items (Script Paused/Exit) will not be shown. TrayCreateItem("Exit") TrayItemSetOnEvent(-1, "ExitEvent") TraySetOnEvent($TRAY_EVENT_PRIMARYDOUBLE, "SpecialEvent") TraySetOnEvent($TRAY_EVENT_SECONDARYDOUBLE, "SpecialEvent") TraySetOnEvent($TRAY_EVENT_MOUSEOVER, "SpecialEvent") TraySetOnEvent($TRAY_EVENT_PRIMARYDOWN, "SpecialEvent") TraySetOnEvent($TRAY_EVENT_PRIMARYUP, "SpecialEvent") TraySetOnEvent($TRAY_EVENT_SECONDARYDOWN, "SpecialEvent") TraySetOnEvent($TRAY_EVENT_SECONDARYUP, "SpecialEvent") TraySetState() Local $WinHandle = GUICreate("Parent1") ConsoleWrite("WinHandle:" & Hex($WinHandle, 8) & @CRLF) GUISetOnEvent($GUI_EVENT_CLOSE, "SpecialEvents") GUISetOnEvent($GUI_EVENT_MINIMIZE, "SpecialEvents") GUISetOnEvent($GUI_EVENT_RESTORE, "SpecialEvents") GUICtrlCreateButton("OK", 10, 30, 50) GUICtrlSetOnEvent(-1, "OKPressed") GUICtrlCreateButton("Cancel", 0, -1) GUICtrlSetOnEvent(-1, "CancelPressed") GUICtrlCreateEdit("A small text box with some text in it to test the scrollbar clicking" & @CRLF & @CRLF & @CRLF & @CRLF & "and a couple of lines, click and drag the scrollbars to stop the counter", 80, 80, 180, 100) GUICtrlSetOnEvent(-1, "EditTouched") GUISetState(@SW_SHOW) ; Just idle around While 1 Sleep(500) ConsoleWrite("Testing message loop:" & $x & @CRLF) $x += 1 WEnd EndFunc ;==>Example Func EditTouched() ConsoleWrite("Testing message loop:" & $x & @CRLF) $x += 1 MsgBox(0, "OK Pressed", "ID=" & @GUI_CtrlId & " WinHandle=" & @GUI_WinHandle & " CtrlHandle=" & @GUI_CtrlHandle) EndFunc ;==>EditTouched Func OKPressed() ConsoleWrite("Testing message loop:" & $x & @CRLF) $x += 1 MsgBox(0, "OK Pressed", "ID=" & @GUI_CtrlId & " WinHandle=" & @GUI_WinHandle & " CtrlHandle=" & @GUI_CtrlHandle) EndFunc ;==>OKPressed Func CancelPressed() ConsoleWrite("Testing message loop:" & $x & @CRLF) $x += 1 MsgBox(0, "Cancel Pressed", "ID=" & @GUI_CtrlId & " WinHandle=" & @GUI_WinHandle & " CtrlHandle=" & @GUI_CtrlHandle) EndFunc ;==>CancelPressed Func SpecialEvents() ConsoleWrite("Testing message loop:" & $x & @CRLF) $x += 1 Select Case @GUI_CtrlId = $GUI_EVENT_CLOSE ConsoleWrite("Testing message loop:" & $x & @CRLF) $x += 1 MsgBox(0, "Close Pressed", "ID=" & @GUI_CtrlId & " WinHandle=" & @GUI_WinHandle) Exit Case @GUI_CtrlId = $GUI_EVENT_MINIMIZE ConsoleWrite("Testing message loop:" & $x & @CRLF) $x += 1 MsgBox(0, "Window Minimized", "ID=" & @GUI_CtrlId & " WinHandle=" & @GUI_WinHandle) Case @GUI_CtrlId = $GUI_EVENT_RESTORE ConsoleWrite("Testing message loop:" & $x & @CRLF) $x += 1 MsgBox(0, "Window Restored", "ID=" & @GUI_CtrlId & " WinHandle=" & @GUI_WinHandle) EndSelect EndFunc ;==>SpecialEvents Func SpecialEvent() Select Case @TRAY_ID = $TRAY_EVENT_PRIMARYDOUBLE MsgBox(64, "SpecialEvent-Info", "Primary mouse button double clicked.") Case @TRAY_ID = $TRAY_EVENT_SECONDARYUP MsgBox(64, "SpecialEvent-Info", "Secondary mouse button clicked.") EndSelect EndFunc ;==>SpecialEvent Func ExitEvent() Exit EndFunc ;==>ExitEvent The counter keeps updating the console output, until you hover above a Tray context menu or you click and hold down any of the scrollbars.
      The counter that i am running in the background here is in my real life a network process that needs to clear a message buffer from time to time.
      I have two applications in Autoit3 running, one server that is doing all the network activity and no GUI related stuff at all and i attach a client to it that has to exchange messages with the server to at least be able to command it up to some level.
      However whenever that message buffer of this client stalls, the server that is broadcasting the ACK messages will also stall eventually because his buffers do not get cleared.
      I have considered using an Sqlite database in WAL mode to exchange messages between the two apps and even if that can work mighty fast, it looks clumsy, but it ensures me that my client app will not crash on partial messages or miss out on messages.
      But if anyone can guide me to a trick where i could at least have all functions called in a processing loop without the AutoIT engine being able to stall that process, in other words:how can i keep that counter "running" at all cost?
      Thanks in advance!
×
×
  • Create New...