Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 08/15/2025 in all areas

  1. v2: Added AutoStart functionality ; =============================================================================================================================== ; SCRIPT: Controller-Worker-Task Manager Framework ; AUTHOR: Dao Van Trong - TRONG.PRO ; VERSION: 2.0 (Added AutoStart functionality) ; DESCRIPTION: This script implements a robust Controller-Worker-Task architecture for running background processes. ; It is designed to be a flexible framework for automation tasks. ; ; ARCHITECTURE: ; - Controller: The main process that runs persistently. It has no GUI and is controlled entirely via a system tray icon. ; Its responsibilities include: ; 1. Reading the configuration from 'Configs.ini'. ; 2. Creating and managing the tray menu. ; 3. Starting, stopping, and monitoring Worker processes. ; 4. Launching one-shot Task processes. ; 5. Automatically reloading the configuration when 'Configs.ini' is modified. ; 6. Auto-starting specified Workers and Tasks on launch. ; ; - Workers: Long-running background processes that perform recurring tasks (e.g., monitoring, syncing). ; They are started and stopped by the Controller and run completely hidden. ; Each worker monitors the Controller and will self-terminate if the Controller exits. ; ; - Tasks: Short-lived background processes that perform a single, one-shot action (e.g., generate a report). ; They can be configured to run exclusively (locking all other tasks) or concurrently. ; They can also be configured to run as a separate sub-process or directly within the Controller's process. ; ; HOW IT WORKS: ; - IPC (Inter-Process Communication): Communication between the Controller and Workers is handled via the Windows Registry. ; The Controller writes a signal to a specific registry key to gracefully shut down a Worker. ; - Asynchronous Operations: All monitoring (process status, config file changes) and Worker functions are handled ; asynchronously using AdlibRegister, ensuring the Controller remains responsive. ; - Configuration: All Workers and Tasks are defined in the master arrays within this script, but they are enabled, ; disabled, and configured via an external 'Configs.ini' file. This allows for easy customization without ; modifying the source code. ; - Logging: The script generates a detailed log file ('manager.log') in the same directory, recording all major ; events like startup, shutdown, worker status changes, and errors. ; ; PERFORMANCE IMPROVEMENTS: ; - Optimized tray menu handling with reduced event processing overhead ; - Faster exit processing with immediate cleanup ; - Reduced Adlib function frequency for better responsiveness ; - Improved memory management and array operations ; ; NEW FEATURES: ; - On/Off declaration for MasterWorkers and MasterTasks ; - Au3Stripper compatibility with proper function protection ; - Enhanced configuration system ; - AutoStart option for Workers and Tasks ; =============================================================================================================================== #include <TrayConstants.au3> #include <Array.au3> #include <File.au3> #include <FileConstants.au3> ; Au3Stripper protection directives #Au3Stripper_Ignore_Funcs=Worker1Function,Worker2Function,Worker3Function,Worker4Function,Worker5Function,Worker6Function,Worker7Function,Worker8Function,Worker9Function,Worker10Function #Au3Stripper_Ignore_Funcs=TaskA_Function,TaskB_Function,TaskC_Function,TaskD_Function,TaskE_Function,TaskF_Function,TaskG_Function,TaskH_Function,TaskI_Function,TaskJ_Function #Au3Stripper_Ignore_Funcs=_CheckStatus_Adlib,_CheckForConfigChanges_Adlib,_WorkerHeartbeat_Adlib #Au3Stripper_Ignore_Variables=$g_aMasterWorkers,$g_aMasterTasks,$g_aWorkers,$g_aTasks,$g_aWorkerTrayItems,$g_aTaskTrayItems ; =============================================================================================================================== ; --- GLOBAL CONSTANTS AND VARIABLES ; =============================================================================================================================== ; --- Settings --- Global Const $g_sConfigFile = @ScriptDir & "\Configs.ini" Global Const $g_sLogFile = @ScriptDir & "\Manager.log" Global $g_sAppName = "Controller-Worker-Task Manager" Global $g_iCheckConfigInterval = 15000 ; Increased for better performance Global $g_sLastConfigModDate = "" ; --- Registry & IPC --- Global Const $g_sRegBase = "HKCU\Software\ControllerWorkerApp" Global Const $g_iAdlibCheckInterval = 2000 ; Reduced frequency for better performance Global Const $g_iGracefulShutdownTimeout = 2000 ; Reduced for faster exit ; --- Status Constants for internal logic --- Global Const $STATUS_STOPPED = 0, $STATUS_RUNNING = 1, $STATUS_ERROR = 2 ; --- Task Execution Mode & Type Constants --- Global Const $TASK_MODE_EXCLUSIVE = 0, $TASK_MODE_CONCURRENT = 1 Global Const $TASK_RUN_TYPE_SUBAPP = 0, $TASK_RUN_TYPE_DIRECT = 1 ; --- Menu Type Constants --- Global Const $MENU_TYPE_MAIN = 0, $MENU_TYPE_SUB = 1 ; --- Performance optimization flags --- Global $g_bShuttingDown = False Global $g_bConfigReloading = False ; --- MASTER DATA STRUCTURES (Hard-coded definitions) --- ; [InternalName, DisplayName, FunctionName, MenuType, Status(On/Off), AutoStart(On/Off)] Global Const $g_aMasterWorkers[10][6] = [ _ ["CheckResources", "Check Resources", "Worker1Function", $MENU_TYPE_MAIN, "On", "On"], _ ; AutoStart Enabled ["SyncFiles", "Sync Files", "Worker2Function", $MENU_TYPE_MAIN, "On", "Off"], _ ["MonitorNetwork", "Monitor Network", "Worker3Function", $MENU_TYPE_MAIN, "On", "On"], _ ; AutoStart Enabled ["BackupDB", "Backup DB", "Worker4Function", $MENU_TYPE_SUB, "On", "Off"], _ ["CleanupLogs", "Cleanup Logs", "Worker5Function", $MENU_TYPE_SUB, "On", "Off"], _ ["ProcessEmails", "Process Emails", "Worker6Function", $MENU_TYPE_SUB, "On", "Off"], _ ["AutoScreenshot", "Auto Screenshot", "Worker7Function", $MENU_TYPE_SUB, "Off", "Off"], _ ["MonitorTemp", "Monitor Temp", "Worker8Function", $MENU_TYPE_SUB, "Off", "Off"], _ ["CheckUpdates", "Check Updates", "Worker9Function", $MENU_TYPE_SUB, "On", "Off"], _ ["SecurityScan", "Security Scan", "Worker10Function", $MENU_TYPE_SUB, "Off", "Off"] _ ] ; [InternalName, DisplayName, FunctionName, MenuType, ExecutionMode, RunType, Status(On/Off), AutoStart(On/Off)] Global Const $g_aMasterTasks[10][8] = [ _ ["QuickCleanup", "Quick Cleanup", "TaskA_Function", $MENU_TYPE_MAIN, $TASK_MODE_EXCLUSIVE, $TASK_RUN_TYPE_SUBAPP, "On", "Off"], _ ["GenerateReport", "Generate Report", "TaskB_Function", $MENU_TYPE_MAIN, $TASK_MODE_EXCLUSIVE, $TASK_RUN_TYPE_SUBAPP, "On", "On"], _ ; AutoStart Enabled ["SendNotification", "Send Notification (Direct)", "TaskJ_Function", $MENU_TYPE_MAIN, $TASK_MODE_EXCLUSIVE, $TASK_RUN_TYPE_DIRECT, "On", "Off"], _ ["TaskC", "Run Task C (Direct)", "TaskC_Function", $MENU_TYPE_SUB, $TASK_MODE_CONCURRENT, $TASK_RUN_TYPE_DIRECT, "On", "Off"], _ ["TaskD", "Run Task D", "TaskD_Function", $MENU_TYPE_SUB, $TASK_MODE_CONCURRENT, $TASK_RUN_TYPE_SUBAPP, "Off", "Off"], _ ["TaskE", "Run Task E", "TaskE_Function", $MENU_TYPE_SUB, $TASK_MODE_CONCURRENT, $TASK_RUN_TYPE_SUBAPP, "Off", "Off"], _ ["TaskF", "Run Task F", "TaskF_Function", $MENU_TYPE_SUB, $TASK_MODE_CONCURRENT, $TASK_RUN_TYPE_SUBAPP, "On", "Off"], _ ["TaskG", "Run Task G", "TaskG_Function", $MENU_TYPE_SUB, $TASK_MODE_CONCURRENT, $TASK_RUN_TYPE_SUBAPP, "Off", "Off"], _ ["TaskH", "Run Task H", "TaskH_Function", $MENU_TYPE_SUB, $TASK_MODE_CONCURRENT, $TASK_RUN_TYPE_SUBAPP, "On", "Off"], _ ["TaskI", "Run Task I", "TaskI_Function", $MENU_TYPE_SUB, $TASK_MODE_CONCURRENT, $TASK_RUN_TYPE_SUBAPP, "Off", "Off"] _ ] ; --- Dynamic Data Structures (Populated from Master based on INI) --- Global $g_aWorkers, $g_iNumWorkers Global $g_aTasks, $g_iNumTasks ; --- Tray Menu Control Variables --- Global $g_aWorkerTrayItems[1], $g_aTaskTrayItems[1], $g_iTrayExit ; --- Shared Global Variables for Worker processes --- Global $g_sWorkerInternalName, $g_iControllerPID, $g_sWorkerRegKey ; --- Performance optimization variables --- Global $g_iLastStatusCheck = 0 Global $g_iLastConfigCheck = 0 ; =============================================================================================================================== ; --- MAIN SCRIPT LOGIC ; =============================================================================================================================== _Main() ;/** ; * @brief Main entry point of the script. ; * ; * Determines whether to run as the Controller or as a sub-process (Worker/Task) ; * based on the command-line arguments. ; */ Func _Main() If $CmdLine[0] > 0 Then Local $aCmd = StringSplit($CmdLine[1], ":") If $aCmd[0] < 2 Then Exit Local $sType = $aCmd[1], $sInternalName = $aCmd[2], $iControllerPID = ($CmdLine[0] > 1 ? $CmdLine[2] : 0) Switch $sType Case "worker" _RunAsWorker($sInternalName, $iControllerPID) Case "task" _RunAsTask($sInternalName) EndSwitch Else _RunAsController() EndIf EndFunc ;==>_Main ; =============================================================================================================================== ; --- CONTROLLER FUNCTIONS ; =============================================================================================================================== ;/** ; * @brief Initializes the Controller process. ; * ; * This function sets up the entire Controller environment: ; * 1. Cleans up any leftover registry keys from previous runs. ; * 2. Loads the configuration from Configs.ini. ; * 3. Creates the tray menu. ; * 4. Auto-starts any configured items. ; * 5. Registers Adlib functions for background monitoring. ; * 6. Starts the main event loop. ; */ Func _RunAsController() ; Performance optimization: Batch initialization _CleanupAllRegistryKeys() _LoadConfiguration() _CreateTrayMenu() ; Auto-start configured items _AutoStartItems() ; Optimized Adlib registration with performance flags $g_iLastStatusCheck = TimerInit() $g_iLastConfigCheck = TimerInit() AdlibRegister("_CheckStatus_Adlib", $g_iAdlibCheckInterval) AdlibRegister("_CheckForConfigChanges_Adlib", $g_iCheckConfigInterval) _WriteLog("INFO: Controller started successfully.") _ControllerMainLoop() EndFunc ;==>_RunAsController ;/** ; * @brief Loads and parses the configuration from Configs.ini. ; * ; * Enhanced version with On/Off status checking for master arrays. ; * If Configs.ini exists, it reads the settings and the disable lists. ; * If not, it uses the default configuration (all master items with "On" status enabled). ; * It then populates the dynamic $g_aWorkers and $g_aTasks arrays with only the enabled items. ; */ Func _LoadConfiguration() $g_bConfigReloading = True Local $sDisabledWorkers = "", $sDisabledTasks = "" If FileExists($g_sConfigFile) Then $g_sLastConfigModDate = FileGetTime($g_sConfigFile, $FT_MODIFIED, $FT_STRING) $g_sAppName = IniRead($g_sConfigFile, "Settings", "AppName", "Controller Framework") $g_iCheckConfigInterval = IniRead($g_sConfigFile, "Settings", "CheckConfigInterval", 15000) $sDisabledWorkers = "," & IniRead($g_sConfigFile, "Workers", "Disable", "") & "," $sDisabledTasks = "," & IniRead($g_sConfigFile, "Tasks", "Disable", "") & "," Else $g_sLastConfigModDate = "" $sDisabledWorkers = "," $sDisabledTasks = "," EndIf ; Enhanced filtering: Check both INI disable list and master array On/Off status Local $iWorkerCount = 0, $iTaskCount = 0 For $i = 0 To UBound($g_aMasterWorkers) - 1 If $g_aMasterWorkers[$i][4] = "On" And Not StringInStr($sDisabledWorkers, "," & $g_aMasterWorkers[$i][0] & ",") Then $iWorkerCount += 1 EndIf Next For $i = 0 To UBound($g_aMasterTasks) - 1 If $g_aMasterTasks[$i][6] = "On" And Not StringInStr($sDisabledTasks, "," & $g_aMasterTasks[$i][0] & ",") Then $iTaskCount += 1 EndIf Next $g_iNumWorkers = $iWorkerCount $g_iNumTasks = $iTaskCount ; Performance optimization: Only create arrays if needed If $g_iNumWorkers > 0 Then Dim $g_aWorkers[$g_iNumWorkers][8] ; UPDATED: Increased size for AutoStart flag Local $iWorkerIdx = 0 For $i = 0 To UBound($g_aMasterWorkers) - 1 Local $sInternalName = $g_aMasterWorkers[$i][0] If $g_aMasterWorkers[$i][4] = "Off" Or StringInStr($sDisabledWorkers, "," & $sInternalName & ",") Then ContinueLoop $g_aWorkers[$iWorkerIdx][0] = $sInternalName $g_aWorkers[$iWorkerIdx][1] = $g_aMasterWorkers[$i][1] $g_aWorkers[$iWorkerIdx][2] = $g_aMasterWorkers[$i][2] $g_aWorkers[$iWorkerIdx][3] = 0 $g_aWorkers[$iWorkerIdx][4] = False $g_aWorkers[$iWorkerIdx][5] = $STATUS_STOPPED $g_aWorkers[$iWorkerIdx][6] = $g_aMasterWorkers[$i][3] $g_aWorkers[$iWorkerIdx][7] = $g_aMasterWorkers[$i][5] ; NEW: Copy AutoStart flag $iWorkerIdx += 1 Next Else Dim $g_aWorkers[0][0] ; Empty array EndIf If $g_iNumTasks > 0 Then Dim $g_aTasks[$g_iNumTasks][8] ; UPDATED: Increased size for AutoStart flag Local $iTaskIdx = 0 For $i = 0 To UBound($g_aMasterTasks) - 1 Local $sInternalName = $g_aMasterTasks[$i][0] If $g_aMasterTasks[$i][6] = "Off" Or StringInStr($sDisabledTasks, "," & $sInternalName & ",") Then ContinueLoop $g_aTasks[$iTaskIdx][0] = $sInternalName $g_aTasks[$iTaskIdx][1] = $g_aMasterTasks[$i][1] $g_aTasks[$iTaskIdx][2] = $g_aMasterTasks[$i][2] $g_aTasks[$iTaskIdx][3] = 0 $g_aTasks[$iTaskIdx][4] = $g_aMasterTasks[$i][4] $g_aTasks[$iTaskIdx][5] = $g_aMasterTasks[$i][5] $g_aTasks[$iTaskIdx][6] = $g_aMasterTasks[$i][3] $g_aTasks[$iTaskIdx][7] = $g_aMasterTasks[$i][7] ; NEW: Copy AutoStart flag $iTaskIdx += 1 Next Else Dim $g_aTasks[0][0] ; Empty array EndIf $g_bConfigReloading = False EndFunc ;==>_LoadConfiguration ;/** ; * @brief Creates the entire tray menu structure based on the loaded configuration. ; * ; * Enhanced version with better performance and empty array handling. ; */ Func _CreateTrayMenu() Opt("TrayMenuMode", 3) TraySetToolTip($g_sAppName) ; Performance optimization: Only create arrays if needed If $g_iNumWorkers > 0 Then ReDim $g_aWorkerTrayItems[$g_iNumWorkers] Local $hSubWorkersMenu = 0 For $i = 0 To $g_iNumWorkers - 1 If $g_aWorkers[$i][6] = $MENU_TYPE_MAIN Then $g_aWorkerTrayItems[$i] = TrayCreateItem("[OFF] " & $g_aWorkers[$i][1]) Else If $hSubWorkersMenu = 0 Then $hSubWorkersMenu = TrayCreateMenu("Sub Workers") $g_aWorkerTrayItems[$i] = TrayCreateItem("[OFF] " & $g_aWorkers[$i][1], $hSubWorkersMenu) EndIf Next Else ReDim $g_aWorkerTrayItems[0] EndIf TrayCreateItem("") If $g_iNumTasks > 0 Then ReDim $g_aTaskTrayItems[$g_iNumTasks] Local $hSubTasksMenu = 0 For $i = 0 To $g_iNumTasks - 1 If $g_aTasks[$i][6] = $MENU_TYPE_MAIN Then $g_aTaskTrayItems[$i] = TrayCreateItem($g_aTasks[$i][1]) Else If $hSubTasksMenu = 0 Then $hSubTasksMenu = TrayCreateMenu("Sub Tasks") $g_aTaskTrayItems[$i] = TrayCreateItem($g_aTasks[$i][1], $hSubTasksMenu) EndIf Next Else ReDim $g_aTaskTrayItems[0] EndIf TrayCreateItem("") $g_iTrayExit = TrayCreateItem("Exit") TraySetState(1) EndFunc ;==>_CreateTrayMenu ;/** ; * @brief The main event loop for the Controller. ; * ; * Enhanced with performance optimizations and faster exit handling. ; */ Func _ControllerMainLoop() While Not $g_bShuttingDown Local $iTrayMsg = TrayGetMsg() Switch $iTrayMsg Case 0 ; No message - continue Case $g_iTrayExit ; Immediate exit handling for better responsiveness $g_bShuttingDown = True _ExitController() Case Else ; Performance optimization: Early exit if reloading config If $g_bConfigReloading Then ContinueLoop Local $iIndex = _GetIndexFromTrayID($iTrayMsg, $g_aWorkerTrayItems) If $iIndex <> -1 Then _HandleWorkerClick($iIndex) ContinueLoop EndIf $iIndex = _GetIndexFromTrayID($iTrayMsg, $g_aTaskTrayItems) If $iIndex <> -1 Then _HandleTaskClick($iIndex) ContinueLoop EndIf EndSwitch Sleep(50) ; Reduced sleep for better responsiveness WEnd EndFunc ;==>_ControllerMainLoop ;/** ; * @brief Handles a click on a Worker menu item. ; * @param $iIndex The index of the clicked worker in the $g_aWorkers array. ; */ Func _HandleWorkerClick($iIndex) If $g_bShuttingDown Or $g_bConfigReloading Then Return _UpdateWorkerState($iIndex, Not $g_aWorkers[$iIndex][4]) EndFunc ;==>_HandleWorkerClick ;/** ; * @brief Handles a click on a Task menu item. ; * @param $iIndex The index of the clicked task in the $g_aTasks array. ; */ Func _HandleTaskClick($iIndex) If $g_bShuttingDown Or $g_bConfigReloading Then Return _RunTask($iIndex) EndFunc ;==>_HandleTaskClick ;/** ; * @brief Central function to change a worker's state (on/off). ; * @param $iIndex The index of the worker. ; * @param $bNewState The new state to apply (True for ON, False for OFF). ; */ Func _UpdateWorkerState($iIndex, $bNewState) If $g_iNumWorkers = 0 Or $iIndex < 0 Or $iIndex >= $g_iNumWorkers Then Return $g_aWorkers[$iIndex][4] = $bNewState If $bNewState Then _StartWorker($iIndex) Else _StopWorker($iIndex) EndIf _UpdateTrayItemForWorker($iIndex) EndFunc ;==>_UpdateWorkerState ;/** ; * @brief Updates a worker's tray menu item text and checked state. ; * @param $iIndex The index of the worker. ; */ Func _UpdateTrayItemForWorker($iIndex) If $g_iNumWorkers = 0 Or $iIndex < 0 Or $iIndex >= $g_iNumWorkers Then Return Local $sPrefix, $iTrayState If $g_aWorkers[$iIndex][4] Then $sPrefix = "[ON] " $iTrayState = $TRAY_CHECKED Else $sPrefix = "[OFF] " $iTrayState = $TRAY_UNCHECKED EndIf TrayItemSetText($g_aWorkerTrayItems[$iIndex], $sPrefix & $g_aWorkers[$iIndex][1]) TrayItemSetState($g_aWorkerTrayItems[$iIndex], $iTrayState) EndFunc ;==>_UpdateTrayItemForWorker ;/** ; * @brief Starts a worker sub-process. ; * @param $iIndex The index of the worker. ; */ Func _StartWorker($iIndex) If $g_iNumWorkers = 0 Or $iIndex < 0 Or $iIndex >= $g_iNumWorkers Then Return If ProcessExists($g_aWorkers[$iIndex][3]) Then Return Local $sCommand = 'worker:' & $g_aWorkers[$iIndex][0] _WriteLog("INFO: Starting Worker '" & $g_aWorkers[$iIndex][1] & "'...") Local $iPID = _RunScript($sCommand) If $iPID > 0 Then $g_aWorkers[$iIndex][3] = $iPID $g_aWorkers[$iIndex][5] = $STATUS_RUNNING Else _WriteLog("ERROR: Failed to start Worker '" & $g_aWorkers[$iIndex][1] & "'.") $g_aWorkers[$iIndex][4] = False $g_aWorkers[$iIndex][5] = $STATUS_ERROR EndIf EndFunc ;==>_StartWorker ;/** ; * @brief Stops a worker sub-process gracefully. ; * @param $iIndex The index of the worker. ; */ Func _StopWorker($iIndex) If $g_iNumWorkers = 0 Or $iIndex < 0 Or $iIndex >= $g_iNumWorkers Then Return Local $iPID = $g_aWorkers[$iIndex][3] If $iPID = 0 Or Not ProcessExists($iPID) Then $g_aWorkers[$iIndex][3] = 0 $g_aWorkers[$iIndex][5] = $STATUS_STOPPED Return EndIf _WriteLog("INFO: Stopping Worker '" & $g_aWorkers[$iIndex][1] & "' (PID: " & $iPID & ")...") Local $sRegKey = $g_sRegBase & "\" & $g_aWorkers[$iIndex][0] RegWrite($sRegKey, "Signal", "REG_SZ", "exit") If @error Then _WriteLog("ERROR: Failed to write exit signal to registry for " & $g_aWorkers[$iIndex][0]) Local $iResult = ProcessWaitClose($iPID, $g_iGracefulShutdownTimeout / 1000) If $iResult = 0 Then _WriteLog("WARN: Worker PID " & $iPID & " did not respond. Forcing shutdown.") ProcessClose($iPID) EndIf RegDelete($sRegKey) $g_aWorkers[$iIndex][3] = 0 $g_aWorkers[$iIndex][5] = $STATUS_STOPPED EndFunc ;==>_StopWorker ;/** ; * @brief Runs a task either directly or as a sub-process. ; * @param $iIndex The index of the task. ; */ Func _RunTask($iIndex) If $g_iNumTasks = 0 Or $iIndex < 0 Or $iIndex >= $g_iNumTasks Then Return Local $sTaskName = $g_aTasks[$iIndex][1] _WriteLog("INFO: Running Task '" & $sTaskName & "'...") If $g_aTasks[$iIndex][5] = $TASK_RUN_TYPE_DIRECT Then TrayItemSetState($g_aTaskTrayItems[$iIndex], $TRAY_DISABLE) Call($g_aTasks[$iIndex][2], $sTaskName) TrayItemSetState($g_aTaskTrayItems[$iIndex], $TRAY_ENABLE) _WriteLog("INFO: Direct Task '" & $sTaskName & "' has completed.") Else If $g_aTasks[$iIndex][3] <> 0 And ProcessExists($g_aTasks[$iIndex][3]) Then Return Local $sCommand = 'task:' & $g_aTasks[$iIndex][0] Local $iPID = _RunScript($sCommand, False) If $iPID > 0 Then $g_aTasks[$iIndex][3] = $iPID _UpdateAllTaskMenusState() Else _WriteLog("ERROR: Failed to run Task '" & $sTaskName & "'.") EndIf EndIf EndFunc ;==>_RunTask ;/** ; * @brief Automatically starts workers and tasks that are configured to run on startup. ; */ Func _AutoStartItems() _WriteLog("INFO: Checking for items to auto-start...") ; Auto-start workers If $g_iNumWorkers > 0 Then For $i = 0 To $g_iNumWorkers - 1 If $g_aWorkers[$i][7] = "On" Then _WriteLog("INFO: Auto-starting Worker '" & $g_aWorkers[$i][1] & "'...") _UpdateWorkerState($i, True) EndIf Next EndIf ; Auto-start tasks If $g_iNumTasks > 0 Then For $i = 0 To $g_iNumTasks - 1 If $g_aTasks[$i][7] = "On" Then _WriteLog("INFO: Auto-starting Task '" & $g_aTasks[$i][1] & "'...") _RunTask($i) EndIf Next EndIf EndFunc ;==>_AutoStartItems ;/** ; * @brief Optimized Adlib function to monitor the status of running workers and tasks. ; */ Func _CheckStatus_Adlib() ; Performance optimization: Skip if shutting down or reloading If $g_bShuttingDown Or $g_bConfigReloading Then Return ; Rate limiting for better performance If TimerDiff($g_iLastStatusCheck) < $g_iAdlibCheckInterval Then Return $g_iLastStatusCheck = TimerInit() ; Check workers only if we have any If $g_iNumWorkers > 0 Then For $i = 0 To $g_iNumWorkers - 1 If $g_aWorkers[$i][4] And Not ProcessExists($g_aWorkers[$i][3]) Then _WriteLog("WARN: Worker '" & $g_aWorkers[$i][1] & "' died. Restarting...") $g_aWorkers[$i][5] = $STATUS_ERROR _UpdateTrayItemForWorker($i) _StartWorker($i) EndIf Next EndIf ; Check tasks only if we have any If $g_iNumTasks > 0 Then Local $bTaskStateChanged = False For $i = 0 To $g_iNumTasks - 1 If $g_aTasks[$i][5] = $TASK_RUN_TYPE_SUBAPP And $g_aTasks[$i][3] > 0 And Not ProcessExists($g_aTasks[$i][3]) Then $g_aTasks[$i][3] = 0 $bTaskStateChanged = True EndIf Next If $bTaskStateChanged Then _UpdateAllTaskMenusState() EndIf EndFunc ;==>_CheckStatus_Adlib ;/** ; * @brief Checks if any exclusive task is currently running as a sub-process. ; * @return True if an exclusive task is running, otherwise False. ; */ Func _IsExclusiveTaskRunning() If $g_iNumTasks = 0 Then Return False For $i = 0 To $g_iNumTasks - 1 If $g_aTasks[$i][4] = $TASK_MODE_EXCLUSIVE And $g_aTasks[$i][3] > 0 And ProcessExists($g_aTasks[$i][3]) Then Return True EndIf Next Return False EndFunc ;==>_IsExclusiveTaskRunning ;/** ; * @brief Updates the enabled/disabled state of all task menu items based on current activity. ; */ Func _UpdateAllTaskMenusState() If $g_iNumTasks = 0 Then Return Local $bExclusiveRunning = _IsExclusiveTaskRunning() For $i = 0 To $g_iNumTasks - 1 If $bExclusiveRunning Then TrayItemSetState($g_aTaskTrayItems[$i], $TRAY_DISABLE) Else If $g_aTasks[$i][3] > 0 And ProcessExists($g_aTasks[$i][3]) Then TrayItemSetState($g_aTaskTrayItems[$i], $TRAY_DISABLE) Else TrayItemSetState($g_aTaskTrayItems[$i], $TRAY_ENABLE) EndIf EndIf Next EndFunc ;==>_UpdateAllTaskMenusState ;/** ; * @brief Optimized Adlib function to check for modifications to the Configs.ini file. ; */ Func _CheckForConfigChanges_Adlib() ; Performance optimization: Skip if shutting down If $g_bShuttingDown Then Return ; Rate limiting for better performance If TimerDiff($g_iLastConfigCheck) < $g_iCheckConfigInterval Then Return $g_iLastConfigCheck = TimerInit() Local $sCurrentModDate = FileGetTime($g_sConfigFile, $FT_MODIFIED, $FT_STRING) If $sCurrentModDate <> $g_sLastConfigModDate And $sCurrentModDate <> "" Then _WriteLog("INFO: Configuration file change detected. Reloading...") $g_bConfigReloading = True _UnregisterAllMasterAdlibs() _StopAllWorkers() TraySetState(2) _LoadConfiguration() _CreateTrayMenu() ; Re-register Adlib functions after config reload AdlibRegister("_CheckStatus_Adlib", $g_iAdlibCheckInterval) AdlibRegister("_CheckForConfigChanges_Adlib", $g_iCheckConfigInterval) _WriteLog("INFO: Configuration reloaded and menu recreated.") EndIf EndFunc ;==>_CheckForConfigChanges_Adlib ;/** ; * @brief Stops all currently active workers with performance optimization. ; */ Func _StopAllWorkers() If $g_iNumWorkers = 0 Then Return _WriteLog("INFO: Stopping all workers...") ; Performance optimization: Parallel shutdown approach Local $aWorkerPIDs[$g_iNumWorkers] Local $aWorkerRegKeys[$g_iNumWorkers] ; First pass: Send exit signals to all workers For $i = 0 To $g_iNumWorkers - 1 If $g_aWorkers[$i][4] And $g_aWorkers[$i][3] > 0 And ProcessExists($g_aWorkers[$i][3]) Then $aWorkerPIDs[$i] = $g_aWorkers[$i][3] $aWorkerRegKeys[$i] = $g_sRegBase & "\" & $g_aWorkers[$i][0] RegWrite($aWorkerRegKeys[$i], "Signal", "REG_SZ", "exit") If @error Then _WriteLog("ERROR: Failed to write exit signal for " & $g_aWorkers[$i][0]) Else $aWorkerPIDs[$i] = 0 EndIf Next ; Wait for graceful shutdown Sleep(500) ; Second pass: Force close any remaining processes For $i = 0 To $g_iNumWorkers - 1 If $aWorkerPIDs[$i] > 0 Then If ProcessExists($aWorkerPIDs[$i]) Then _WriteLog("WARN: Force closing Worker PID " & $aWorkerPIDs[$i]) ProcessClose($aWorkerPIDs[$i]) EndIf RegDelete($aWorkerRegKeys[$i]) $g_aWorkers[$i][3] = 0 $g_aWorkers[$i][4] = False $g_aWorkers[$i][5] = $STATUS_STOPPED EndIf Next EndFunc ;==>_StopAllWorkers ;/** ; * @brief A generic function to run the script as a sub-process. ; * @param $sArgument The argument to pass to the new process (e.g., "worker:MyWorker"). ; * @param $bPassControllerPID If True, the current controller's PID is passed as the second argument. ; * @return The PID of the new process, or 0 on failure. ; */ Func _RunScript($sArgument, $bPassControllerPID = True) Local $sControllerPID = ($bPassControllerPID ? " " & @AutoItPID : "") Local $sCommand = '"' & @ScriptFullPath & '" "' & $sArgument & '"' & $sControllerPID Local $sExecutable = (@Compiled ? "" : '"' & @AutoItExe & '" ') Return Run($sExecutable & $sCommand, @ScriptDir, @SW_HIDE) EndFunc ;==>_RunScript ;/** ; * @brief Performs all necessary cleanup before the Controller exits. ; * Enhanced with faster shutdown process. ; */ Func _ExitController() $g_bShuttingDown = True _WriteLog("INFO: Controller shutting down...") ; Immediate cleanup for faster exit _UnregisterAllMasterAdlibs() _StopAllWorkers() _CleanupAllRegistryKeys() _WriteLog("INFO: Controller shutdown complete.") Exit EndFunc ;==>_ExitController ;/** ; * @brief Enhanced function to unregister all possible Adlib callbacks. ; * Now includes protection for Au3Stripper and handles empty arrays. ; */ Func _UnregisterAllMasterAdlibs() AdlibUnRegister("_CheckStatus_Adlib") AdlibUnRegister("_CheckForConfigChanges_Adlib") ; Unregister all master worker functions (protected from Au3Stripper) For $i = 0 To UBound($g_aMasterWorkers) - 1 AdlibUnRegister($g_aMasterWorkers[$i][2]) Next EndFunc ;==>_UnregisterAllMasterAdlibs ;/** ; * @brief Deletes the entire registry key used by the application for IPC. ; */ Func _CleanupAllRegistryKeys() RegDelete($g_sRegBase) If @error Then _WriteLog("WARN: Registry key cleanup - base key may not exist: " & $g_sRegBase) EndFunc ;==>_CleanupAllRegistryKeys ;/** ; * @brief Enhanced function to find array index with bounds checking. ; * @param $nID The tray item ID to find. ; * @param $aTrayItems The array of tray item IDs to search in. ; * @return The array index if found, otherwise -1. ; */ Func _GetIndexFromTrayID($nID, ByRef $aTrayItems) Local $iUBound = UBound($aTrayItems) If $iUBound = 0 Then Return -1 For $i = 0 To $iUBound - 1 If $aTrayItems[$i] = $nID Then Return $i Next Return -1 EndFunc ;==>_GetIndexFromTrayID ;/** ; * @brief Enhanced logging function with better performance and error handling. ; * @param $sMessage The message to log. ; */ Func _WriteLog($sMessage) Local $sTimeStamp = @YEAR & "/" & @MON & "/" & @MDAY & " " & @HOUR & ":" & @MIN & ":" & @SEC Local $sFormattedMessage = $sTimeStamp & " - " & $sMessage & @CRLF ConsoleWrite($sFormattedMessage) ; Performance optimization: Non-blocking file write Local $hFile = FileOpen($g_sLogFile, $FO_APPEND + $FO_UTF8_NOBOM) If $hFile <> -1 Then FileWrite($hFile, $sFormattedMessage) FileClose($hFile) EndIf EndFunc ;==>_WriteLog ; =============================================================================================================================== ; --- WORKER / TASK SUB-PROCESS EXECUTION ; =============================================================================================================================== ;/** ; * @brief Initializes the script when run as a Worker sub-process. ; * @param $sInternalName The internal name of the worker to run. ; * @param $iControllerPID The PID of the parent Controller process to monitor. ; */ Func _RunAsWorker($sInternalName, $iControllerPID) $g_sWorkerInternalName = $sInternalName $g_iControllerPID = $iControllerPID $g_sWorkerRegKey = $g_sRegBase & "\" & $sInternalName RegDelete($g_sWorkerRegKey) Local $sFunction = "" For $i = 0 To UBound($g_aMasterWorkers) - 1 If $g_aMasterWorkers[$i][0] = $sInternalName Then $sFunction = $g_aMasterWorkers[$i][2] ExitLoop EndIf Next If $sFunction = "" Then Exit ; Performance optimization: Longer intervals for worker processes AdlibRegister($sFunction, 1000) AdlibRegister("_WorkerHeartbeat_Adlib", 3000) ; Reduced frequency While 1 Sleep(200) ; Slightly longer sleep for worker processes WEnd EndFunc ;==>_RunAsWorker ;/** ; * @brief Enhanced Adlib function for workers to monitor the Controller and exit signals. ; */ Func _WorkerHeartbeat_Adlib() ; Check if controller is still running If $g_iControllerPID > 0 And Not ProcessExists($g_iControllerPID) Then _WorkerExitGracefully() Return EndIf ; Check for exit signal from registry Local $sSignal = RegRead($g_sWorkerRegKey, "Signal") If @error Then _WorkerExitGracefully() Return EndIf If $sSignal = "exit" Then _WorkerExitGracefully() EndIf EndFunc ;==>_WorkerHeartbeat_Adlib ;/** ; * @brief Enhanced cleanup function for Workers before exit. ; */ Func _WorkerExitGracefully() AdlibUnRegister("_WorkerHeartbeat_Adlib") ; Find and unregister the specific worker function Local $sFunction = "" For $i = 0 To UBound($g_aMasterWorkers) - 1 If $g_aMasterWorkers[$i][0] = $g_sWorkerInternalName Then $sFunction = $g_aMasterWorkers[$i][2] ExitLoop EndIf Next If $sFunction <> "" Then AdlibUnRegister($sFunction) RegDelete($g_sWorkerRegKey) Exit EndFunc ;==>_WorkerExitGracefully ;/** ; * @brief Initializes the script when run as a Task sub-process. ; * @param $sInternalName The internal name of the task to run. ; */ Func _RunAsTask($sInternalName) Local $sFunction, $sDisplayName For $i = 0 To UBound($g_aMasterTasks) - 1 If $g_aMasterTasks[$i][0] = $sInternalName Then $sDisplayName = $g_aMasterTasks[$i][1] $sFunction = $g_aMasterTasks[$i][2] ExitLoop EndIf Next If $sFunction = "" Then Exit Call($sFunction, $sDisplayName) Exit EndFunc ;==>_RunAsTask ; =============================================================================================================================== ; --- SPECIFIC WORKER/TASK FUNCTIONS (IMPLEMENTATION) ; --- These functions are protected by Au3Stripper directives ; =============================================================================================================================== Func Worker1Function() _WriteLog("Worker 'Check Resources' is running...") ; This is PlaceHoder - Your Code Replace Here EndFunc ;==>Worker1Function Func Worker2Function() _WriteLog("Worker 'Sync Files' is running...") ; This is PlaceHoder - Your Code Replace Here EndFunc ;==>Worker2Function Func Worker3Function() _WriteLog("Worker 'Monitor Network' is running...") ; This is PlaceHoder - Your Code Replace Here EndFunc ;==>Worker3Function Func Worker4Function() _WriteLog("Worker 'Backup DB' is running...") ; This is PlaceHoder - Your Code Replace Here EndFunc ;==>Worker4Function Func Worker5Function() _WriteLog("Worker 'Cleanup Logs' is running...") ; This is PlaceHoder - Your Code Replace Here EndFunc ;==>Worker5Function Func Worker6Function() _WriteLog("Worker 'Process Emails' is running...") ; This is PlaceHoder - Your Code Replace Here EndFunc ;==>Worker6Function Func Worker7Function() _WriteLog("Worker 'Auto Screenshot' is running...") ; This is PlaceHoder - Your Code Replace Here EndFunc ;==>Worker7Function Func Worker8Function() _WriteLog("Worker 'Monitor Temp' is running...") ; This is PlaceHoder - Your Code Replace Here EndFunc ;==>Worker8Function Func Worker9Function() _WriteLog("Worker 'Check Updates' is running...") ; This is PlaceHoder - Your Code Replace Here EndFunc ;==>Worker9Function Func Worker10Function() _WriteLog("Worker 'Security Scan' is running...") ; This is PlaceHoder - Your Code Replace Here EndFunc ;==>Worker10Function Func TaskA_Function($sName) _WriteLog("Task '" & $sName & "' is running...") ; This is PlaceHoder - Your Code Replace Here Sleep(2000) EndFunc ;==>TaskA_Function Func TaskB_Function($sName) _WriteLog("Task '" & $sName & "' is running...") ; This is PlaceHoder - Your Code Replace Here Sleep(3000) EndFunc ;==>TaskB_Function Func TaskC_Function($sName) _WriteLog("Task '" & $sName & "' is running...") ; This is PlaceHoder - Your Code Replace Here EndFunc ;==>TaskC_Function Func TaskD_Function($sName) _WriteLog("Task '" & $sName & "' is running...") ; This is PlaceHoder - Your Code Replace Here Sleep(1000) EndFunc ;==>TaskD_Function Func TaskE_Function($sName) _WriteLog("Task '" & $sName & "' is running...") ; This is PlaceHoder - Your Code Replace Here Sleep(1000) EndFunc ;==>TaskE_Function Func TaskF_Function($sName) _WriteLog("Task '" & $sName & "' is running...") ; This is PlaceHoder - Your Code Replace Here Sleep(1000) EndFunc ;==>TaskF_Function Func TaskG_Function($sName) _WriteLog("Task '" & $sName & "' is running...") ; This is PlaceHoder - Your Code Replace Here Sleep(1000) EndFunc ;==>TaskG_Function Func TaskH_Function($sName) _WriteLog("Task '" & $sName & "' is running...") ; This is PlaceHoder - Your Code Replace Here Sleep(1000) EndFunc ;==>TaskH_Function Func TaskI_Function($sName) _WriteLog("Task '" & $sName & "' is running...") ; This is PlaceHoder - Your Code Replace Here Sleep(1000) EndFunc ;==>TaskI_Function Func TaskJ_Function($sName) _WriteLog("Task '" & $sName & "' is running...") ; This is PlaceHoder - Your Code Replace Here Sleep(1000) EndFunc ;==>TaskJ_Function Eg: Configs.ini ; ====================================================================== ; Configuration file for the Controller-Worker-Task Manager ; ; Instructions: ; - To enable an option, remove the semicolon (;) from the beginning of the line. ; - Changes made to this file will be automatically detected and ; applied by the program without requiring a restart. ; ====================================================================== [Settings] ; The application name that will be displayed in the system tray tooltip. AppName=My Custom Automation Suite ; The interval (in milliseconds) for checking this configuration file for changes. ; The default value in the script is 15000 (which is 15 seconds). CheckConfigInterval=15000 [Workers] ; List the InternalName of the Workers you want to DISABLE, separated by commas (with no spaces). ; Even if a Worker is set to "On" in the script's master array, listing it here ; will prevent it from being loaded and appearing in the tray menu. ; ; Example: Disable=SyncFiles,CleanupLogs ; ; Available Workers (InternalName from the script): ; CheckResources, SyncFiles, MonitorNetwork, BackupDB, CleanupLogs, ProcessEmails, ; AutoScreenshot, MonitorTemp, CheckUpdates, SecurityScan ; ; This example will disable the "Backup DB" and "Process Emails" workers. Disable=BackupDB,ProcessEmails [Tasks] ; List the InternalName of the Tasks you want to DISABLE, separated by commas. ; Similar to Workers, any Task listed here will be disabled. ; ; Available Tasks (InternalName from the script): ; QuickCleanup, GenerateReport, SendNotification, TaskC, TaskD, TaskE, ; TaskF, TaskG, TaskH, TaskI ; ; This example will disable "Run Task F" and "Run Task H". Disable=TaskF,TaskH
    2 points
  2. orbs

    math puzzle

    Goal: select the squares to match every row and column results (screenshot below). you can change the puzzle type (addition or multiplication), grid size (3x3 to 9x9), and other preferences. Dependency: this app is also a showcase for the WinPose UDF (which was actually developed for it). Script: #Region wrapper directives #AutoIt3Wrapper_Au3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #AutoIt3Wrapper_UseX64=N #AutoIt3Wrapper_Compile_both=N #AutoIt3Wrapper_Icon=MagicMath.ico #AutoIt3Wrapper_UseUpx=N #AutoIt3Wrapper_Res_Description=Magic Math #AutoIt3Wrapper_Res_Fileversion=1.0.0.0 #AutoIt3Wrapper_Res_ProductVersion=1.0.0.0 #AutoIt3Wrapper_Res_LegalCopyright=Or Ben Shabat (or.ben.shabat@gmail.com) #AutoIt3Wrapper_Run_Au3Stripper=y #Au3Stripper_Parameters=/SO /RM #EndRegion wrapper directives #NoTrayIcon #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <StaticConstants.au3> #include <ColorConstants.au3> #include <FontConstants.au3> #include <AutoItConstants.au3> #include <EditConstants.au3> #include <Math.au3> #include 'WinPose.au3' ; init ; - general Global Const $sAppName = 'Magic Math' ; - colors Global Const $iDefaultSqrSize = 45 Global Const $iDefaultColCount = 5 Global Const $iDefaultRowCount = 5 Global Const $iDefaultResizeSpeed = 50 Global Const $iColor_BoxText = $COLOR_BLACK Global Const $iColor_BoxTextError = $COLOR_RED Global Const $iColor_BoxUnchecked = $COLOR_LIGHTGRAY Global Const $iColor_BoxChecked = $COLOR_LIGHTGREEN Global Const $iColor_BoxEliminated = $COLOR_DARKGRAY Global Const $iColor_BoxResult = $COLOR_PEACHPUFF Global Const $iColor_MenuItem = $COLOR_DARKBLUE Global Const $iColor_MenuItemPressed = $COLOR_LIGHTGRAY Global Const $iColor_MenuItemEmphasis = $COLOR_WHITE Global Const $iColor_Vprimary = $COLOR_LIMEGREEN Global Const $iColor_Vsecondary = $COLOR_AQUA ; - symbols Global Const $symSetup = Chr(64) ; Webdings Global Const $symRenew = Chr(81) ; Wingdings 3 Global Const $symSolve = Chr(97) ; Webdings Global Const $symHelp = Chr(115) ; Webdings Global Const $symP = Chr(200) ; Wingdings 2 Global Const $symX = Chr(208) ; Wingdings 2 Global Const $symV = Chr(252) ; Wingdings ; declare variables Global $bPuzzleTypeIsAddition = True Global $iColCount = $iDefaultColCount, $iRowCount = $iDefaultRowCount, $iSqrSize = $iDefaultSqrSize, $iResizeSpeed = $iDefaultResizeSpeed Global $iGUI_Width, $iGUI_Height, $hGUI Global $aPos, $iWDiff, $iHDiff ; - main GUI Global $gMenu_New, $gMenu_Solve, $gMenu_Pref, $gMenu_Help, $gdGUIStart, $gdGUIEnd, $gdGridStart, $gdGridEnd Global Enum $iGrid_iValue, $iGrid_gID, $iGrid_bSelected, $iGrid_bChecked, $iGrid_bEliminated, $iGrid_iDimCount Global $aGrid[$iColCount][$iRowCount][$iGrid_iDimCount] Global Enum $iResult_iValue, $iResult_iDiff, $iResult_iDimCount Global $aResultOfRow[$iRowCount][$iResult_iDimCount] Global $aResultOfCol[$iColCount][$iResult_iDimCount] Global $gPuzzleType Global $bUserInputAllowed Global $bCheckForVictory ; - pref GUI Global $gPuzzleType_Addition, $gPuzzleType_Multiplication, _ $gGridWidth_Down, $gGridWidth_Data, $gGridWidth_Up, _ $gGridHeight_Down, $gGridHeight_Data, $gGridHeight_Up, _ $gSqrSize_Down, $gSqrSize_Data, $gSqrSize_Up, _ $gResizeSpeed_data, _ $gOK ; GUI $iGUI_Width = $iSqrSize * ($iColCount + 3) + 2 $iGUI_Height = $iSqrSize * ($iRowCount + 2) + 2 $hGUI = GUICreate($sAppName, $iGUI_Width, $iGUI_Height) $aPos = WinGetPos($hGUI) $iWDiff = $aPos[2] - $iGUI_Width $iHDiff = $aPos[3] - $iGUI_Height BuildGUI() GUISetState(@SW_SHOW, $hGUI) ; main loop Global $msg Global $aCursorInfo $bCheckForVictory = False While True $msg = GUIGetMsg() Switch $msg Case $gMenu_New GUICtrlSetBkColor($gMenu_New, $iColor_MenuItemPressed) Sleep(100) Renew() Sleep(100) GUICtrlSetBkColor($gMenu_New, $GUI_BKCOLOR_TRANSPARENT) Case $gMenu_Solve GUICtrlSetBkColor($gMenu_Solve, $iColor_MenuItemPressed) Sleep(100) Solve() Sleep(100) GUICtrlSetBkColor($gMenu_Solve, $GUI_BKCOLOR_TRANSPARENT) Case $gMenu_Pref GUICtrlSetBkColor($gMenu_Pref, $iColor_MenuItemPressed) Sleep(100) BuildGUI(Pref()) Sleep(100) GUICtrlSetBkColor($gMenu_Pref, $GUI_BKCOLOR_TRANSPARENT) Case $gMenu_Help GUICtrlSetBkColor($gMenu_Help, $iColor_MenuItemPressed) Sleep(100) BuildGUI(Help()) Sleep(100) GUICtrlSetBkColor($gMenu_Help, $GUI_BKCOLOR_TRANSPARENT) Case $gdGridStart To $gdGridEnd If $bUserInputAllowed Then For $iRow = 0 To $iRowCount - 1 For $iCol = 0 To $iColCount - 1 If $msg = $aGrid[$iCol][$iRow][$iGrid_gID] Then $aGrid[$iCol][$iRow][$iGrid_bEliminated] = False $aGrid[$iCol][$iRow][$iGrid_bChecked] = Not $aGrid[$iCol][$iRow][$iGrid_bChecked] GUICtrlSetBkColor($aGrid[$iCol][$iRow][$iGrid_gID], $aGrid[$iCol][$iRow][$iGrid_bChecked] ? $iColor_BoxChecked : $iColor_BoxUnchecked) EndIf Next Next $bCheckForVictory = True EndIf Case $GUI_EVENT_SECONDARYUP $aCursorInfo = GUIGetCursorInfo() If $aCursorInfo[4] > $gdGridStart And $aCursorInfo[4] < $gdGridEnd Then If $bUserInputAllowed Then For $iRow = 0 To $iRowCount - 1 For $iCol = 0 To $iColCount - 1 If $aCursorInfo[4] = $aGrid[$iCol][$iRow][$iGrid_gID] Then $aGrid[$iCol][$iRow][$iGrid_bChecked] = False $aGrid[$iCol][$iRow][$iGrid_bEliminated] = Not $aGrid[$iCol][$iRow][$iGrid_bEliminated] GUICtrlSetBkColor($aGrid[$iCol][$iRow][$iGrid_gID], $aGrid[$iCol][$iRow][$iGrid_bEliminated] ? $iColor_BoxEliminated : $iColor_BoxUnchecked) EndIf Next Next $bCheckForVictory = True EndIf EndIf Case $GUI_EVENT_CLOSE ExitLoop EndSwitch If $bCheckForVictory Then If IsVictoryAchieved() Then ShowVictory() GUICtrlSetBkColor($gMenu_New, $iColor_MenuItemEmphasis) Sleep(125) Renew() Sleep(125) GUICtrlSetBkColor($gMenu_New, $GUI_BKCOLOR_TRANSPARENT) EndIf $bCheckForVictory = False EndIf WEnd Func Renew($bNew = True) $bUserInputAllowed = True Local $bNoZeroResults GUISetState(@SW_LOCK) Do $bNoZeroResults = True For $iRow = 0 To $iRowCount - 1 For $iCol = 0 To $iColCount - 1 If $bNew Then $aGrid[$iCol][$iRow][$iGrid_iValue] = $bPuzzleTypeIsAddition ? Random(1, 9, 1) : Random(2, 9, 1) $aGrid[$iCol][$iRow][$iGrid_bSelected] = (Random() < 0.5) $aGrid[$iCol][$iRow][$iGrid_bChecked] = False $aGrid[$iCol][$iRow][$iGrid_bEliminated] = False EndIf GUICtrlSetData($aGrid[$iCol][$iRow][$iGrid_gID], $aGrid[$iCol][$iRow][$iGrid_iValue]) GUICtrlSetColor($aGrid[$iCol][$iRow][$iGrid_gID], $iColor_BoxText) Select Case $aGrid[$iCol][$iRow][$iGrid_bChecked] GUICtrlSetBkColor($aGrid[$iCol][$iRow][$iGrid_gID], $iColor_BoxChecked) Case $aGrid[$iCol][$iRow][$iGrid_bEliminated] GUICtrlSetBkColor($aGrid[$iCol][$iRow][$iGrid_gID], $iColor_BoxEliminated) Case Else GUICtrlSetBkColor($aGrid[$iCol][$iRow][$iGrid_gID], $iColor_BoxUnchecked) EndSelect GUICtrlSetCursor($aGrid[$iCol][$iRow][$iGrid_gID], $MCID_ARROW) Next Next Local $iResult For $iRow = 0 To $iRowCount - 1 $iResult = 0 For $iCol = 0 To $iColCount - 1 If $aGrid[$iCol][$iRow][$iGrid_bSelected] Then $iResult = Accumulate($iResult, $aGrid[$iCol][$iRow][$iGrid_iValue]) Next If $iResult = 0 Then $bNoZeroResults = False GUICtrlSetData($aResultOfRow[$iRow][$iResult_iValue], $iResult) GUICtrlSetFont($aResultOfRow[$iRow][$iResult_iValue], _Min($iSqrSize / 3, $iSqrSize / StringLen($iResult))) Next For $iCol = 0 To $iColCount - 1 $iResult = 0 For $iRow = 0 To $iRowCount - 1 If $aGrid[$iCol][$iRow][$iGrid_bSelected] Then $iResult = Accumulate($iResult, $aGrid[$iCol][$iRow][$iGrid_iValue]) Next If $iResult = 0 Then $bNoZeroResults = False GUICtrlSetData($aResultOfCol[$iCol][$iResult_iValue], $iResult) GUICtrlSetFont($aResultOfCol[$iCol][$iResult_iValue], _Min($iSqrSize / 3, $iSqrSize / StringLen($iResult))) Next Until $bNoZeroResults GUISetState(@SW_UNLOCK) EndFunc ;==>Renew Func Accumulate(ByRef $iBase, $iDelta) If $iBase = 0 Then Return $iDelta If $bPuzzleTypeIsAddition Then Return $iBase + $iDelta Else Return $iBase * $iDelta EndIf EndFunc ;==>Accumulate Func Solve() $bUserInputAllowed = False For $iRow = 0 To $iRowCount - 1 For $iCol = 0 To $iColCount - 1 GUICtrlSetBkColor($aGrid[$iCol][$iRow][$iGrid_gID], $aGrid[$iCol][$iRow][$iGrid_bSelected] ? $iColor_BoxChecked : $iColor_BoxEliminated) If $aGrid[$iCol][$iRow][$iGrid_bSelected] <> $aGrid[$iCol][$iRow][$iGrid_bChecked] Then GUICtrlSetColor($aGrid[$iCol][$iRow][$iGrid_gID], $iColor_BoxTextError) GUICtrlSetCursor($aGrid[$iCol][$iRow][$iGrid_gID], $MCID_NO) Next Next EndFunc ;==>Solve Func IsVictoryAchieved() Local $iResult For $iRow = 0 To $iRowCount - 1 $iResult = 0 For $iCol = 0 To $iColCount - 1 If $aGrid[$iCol][$iRow][$iGrid_bChecked] Then $iResult = Accumulate($iResult, $aGrid[$iCol][$iRow][$iGrid_iValue]) Next If GUICtrlRead($aResultOfRow[$iRow][$iResult_iValue]) <> $iResult Then Return False Next For $iCol = 0 To $iColCount - 1 $iResult = 0 For $iRow = 0 To $iRowCount - 1 If $aGrid[$iCol][$iRow][$iGrid_bChecked] Then $iResult = Accumulate($iResult, $aGrid[$iCol][$iRow][$iGrid_iValue]) Next If GUICtrlRead($aResultOfCol[$iCol][$iResult_iValue]) <> $iResult Then Return False Next Return True EndFunc ;==>IsVictoryAchieved Func ShowVictory() Sleep(150) Local $gV = GUICtrlCreateLabel($symV, 0, 0, $iGUI_Width, $iGUI_Height, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetFont($gV, _Min($iGUI_Height, $iGUI_Width) * 0.6, Default, Default, 'Wingdings') GUICtrlSetBkColor($gV, $GUI_BKCOLOR_TRANSPARENT) GUICtrlSetColor($gV, $iColor_Vprimary) For $i = 1 To 2 Sleep(125) GUICtrlSetColor($gV, $iColor_Vsecondary) Sleep(125) GUICtrlSetColor($gV, $iColor_Vprimary) Next Sleep(1000) GUICtrlDelete($gV) Sleep(250) EndFunc ;==>ShowVictory Func BuildGUI($bNew = True) GUISetFont($iSqrSize / 3, Default, Default, 'Tahoma') ; GUI contents $gdGUIStart = GUICtrlCreateDummy() ; - menu $gMenu_Pref = GUICtrlCreateLabel($symSetup, 1, 1 + $iSqrSize / 2, $iSqrSize * 1.5 - 2, $iSqrSize - 2, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetTip(-1, 'Set your preferences and construct a new puzzle', 'Setup') GUICtrlSetFont(-1, $iSqrSize / 2, Default, Default, 'Webdings') GUICtrlSetColor(-1, $iColor_MenuItem) GUICtrlSetCursor(-1, $MCID_HAND) $gMenu_New = GUICtrlCreateLabel($symRenew, 1, $iSqrSize + 1 + $iSqrSize / 2, $iSqrSize * 1.5 - 2, $iSqrSize - 2, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetTip(-1, 'Construct a new puzzle using current preferences', 'New Puzzle') GUICtrlSetFont(-1, $iSqrSize / 2, Default, Default, 'Wingdings 3') GUICtrlSetColor(-1, $iColor_MenuItem) GUICtrlSetCursor(-1, $MCID_HAND) $gMenu_Solve = GUICtrlCreateLabel($symV, 1, $iSqrSize * 2 + 1 + $iSqrSize / 2, $iSqrSize * 1.5 - 2, $iSqrSize - 2, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetTip(-1, 'I give up :(', 'Show Solution') GUICtrlSetFont(-1, $iSqrSize / 2, Default, Default, 'Wingdings') GUICtrlSetColor(-1, $iColor_MenuItem) GUICtrlSetCursor(-1, $MCID_HAND) $gMenu_Help = GUICtrlCreateLabel($symHelp, 1, $iSqrSize * 3 + 1 + $iSqrSize / 2, $iSqrSize * 1.5 - 2, $iSqrSize - 2, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetTip(-1, 'What do I do here?', 'Instructions') GUICtrlSetFont(-1, $iSqrSize / 2, Default, Default, 'Webdings') GUICtrlSetColor(-1, $iColor_MenuItem) GUICtrlSetCursor(-1, $MCID_HAND) ; - grid ; -- center part ReDim $aGrid[$iColCount][$iRowCount][$iGrid_iDimCount] $gdGridStart = GUICtrlCreateDummy() For $iRow = 0 To $iRowCount - 1 For $iCol = 0 To $iColCount - 1 $aGrid[$iCol][$iRow][$iGrid_gID] = GUICtrlCreateLabel('', ($iCol + 1) * $iSqrSize + 2 + $iSqrSize / 2, $iRow * $iSqrSize + 2 + $iSqrSize / 2, $iSqrSize - 2, $iSqrSize - 2, BitOR($SS_CENTER, $SS_CENTERIMAGE)) Next Next $gdGridEnd = GUICtrlCreateDummy() ; -- results of rows ReDim $aResultOfRow[$iRowCount][$iResult_iDimCount] For $iRow = 0 To $iRowCount - 1 $aResultOfRow[$iRow][$iResult_iValue] = GUICtrlCreateLabel('', ($iColCount + 1) * $iSqrSize + 2 + $iSqrSize / 2, $iRow * $iSqrSize + 2 + $iSqrSize / 2, $iSqrSize - 2, $iSqrSize - 2, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetBkColor(-1, $iColor_BoxResult) Next ; -- results of cols ReDim $aResultOfCol[$iColCount][$iResult_iDimCount] For $iCol = 0 To $iColCount - 1 $aResultOfCol[$iCol][$iResult_iValue] = GUICtrlCreateLabel('', ($iCol + 1) * $iSqrSize + 2 + $iSqrSize / 2, $iRowCount * $iSqrSize + 2 + $iSqrSize / 2, $iSqrSize - 2, $iSqrSize - 2, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetBkColor(-1, $iColor_BoxResult) Next ; -- puzzle type GUICtrlCreateLabel($bPuzzleTypeIsAddition ? $symP : $symX, ($iColCount + 1) * $iSqrSize + 2 + $iSqrSize / 2, $iRowCount * $iSqrSize + 2 + $iSqrSize / 2, $iSqrSize - 2, $iSqrSize - 2, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetFont(-1, Default, Default, Default, 'Wingdings 2') GUICtrlSetBkColor(-1, $iColor_MenuItemEmphasis) GUICtrlSetTip(-1, ($bPuzzleTypeIsAddition ? 'Addition' : 'Multplication'), 'Puzzle Type:') ; - populate grid Renew($bNew) ; finalize GUI $gdGUIEnd = GUICtrlCreateDummy() EndFunc ;==>BuildGUI Func Pref() Local Const $iSUI_W = 200, $iSUI_H = 280, $iSUI_ButtonH = 30, $iSUI_ButtonSpacing = 10 GUISetFont(9.5, Default, Default, 'Tahoma') Local $x = 10, $y = 10, $dy = 25 ; delete all controls DeleteAllControls() ; resize GUI WinSetTrans($hGUI, '', 192) WinSetTitle($hGUI, '', $sAppName & ' Setup') _WinPoseAroundCenter($hGUI, $iSUI_W + $iWDiff, $iSUI_H + $iHDiff, $iResizeSpeed) WinSetTrans($hGUI, '', 255) ; generate controls $gdGUIStart = GUICtrlCreateDummy() GUICtrlCreateLabel('Puzzle', $x, $y, 85, Default, $SS_CENTERIMAGE) GUICtrlSetFont(-1, Default, 600) $x += 5 $y += $dy GUICtrlCreateLabel('Puzzle Type:', $x, $y, 80, Default, $SS_CENTERIMAGE) $x += 90 $gPuzzleType_Addition = GUICtrlCreateLabel($symP, $x, $y, 41, 22, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetFont(-1, 12, Default, Default, 'Wingdings 2') $x += 42 $gPuzzleType_Multiplication = GUICtrlCreateLabel($symX, $x, $y, 41, 22, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetFont(-1, 12, Default, Default, 'Wingdings 2') Pref_RefreshPuzzleTypeButtons($gPuzzleType_Addition, $gPuzzleType_Multiplication) $x -= 42 $x -= 90 $y += $dy GUICtrlCreateLabel('Columns:', $x, $y, 80, Default, $SS_CENTERIMAGE) $x += 90 $gGridWidth_Down = GUICtrlCreateLabel('-', $x, $y, 23, 22, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetFont(-1, 13, 800) GUICtrlSetBkColor(-1, $COLOR_LIGHTGRAY) GUICtrlSetCursor(-1, $MCID_HAND) $x += 25 $gGridWidth_Data = GUICtrlCreateLabel($iColCount, $x, $y, 33, 22, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetBkColor(-1, $COLOR_LIGHTBLUE) $x += 35 $gGridWidth_Up = GUICtrlCreateLabel('+', $x, $y, 23, 22, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetFont(-1, 13, 800) GUICtrlSetBkColor(-1, $COLOR_LIGHTGRAY) GUICtrlSetCursor(-1, $MCID_HAND) $x -= 35 $x -= 25 $x -= 90 $y += $dy GUICtrlCreateLabel('Rows:', $x, $y, Default, Default, $SS_CENTERIMAGE) $x += 90 $gGridHeight_Down = GUICtrlCreateLabel('-', $x, $y, 23, 22, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetFont(-1, 13, 800) GUICtrlSetBkColor(-1, $COLOR_LIGHTGRAY) GUICtrlSetCursor(-1, $MCID_HAND) $x += 25 $gGridHeight_Data = GUICtrlCreateLabel($iRowCount, $x, $y, 33, 22, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetBkColor(-1, $COLOR_LIGHTBLUE) $x += 35 $gGridHeight_Up = GUICtrlCreateLabel('+', $x, $y, 23, 22, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetFont(-1, 13, 800) GUICtrlSetBkColor(-1, $COLOR_LIGHTGRAY) GUICtrlSetCursor(-1, $MCID_HAND) $x -= 35 $x -= 25 $x -= 90 $y += $dy $x -= 5 $y += $dy GUICtrlCreateLabel('Appearance', $x, $y, 85, Default, $SS_CENTERIMAGE) GUICtrlSetFont(-1, Default, 600) $y += $dy $x += 5 GUICtrlCreateLabel('Square Size:', $x, $y, Default, Default, $SS_CENTERIMAGE) $x += 90 $gSqrSize_Down = GUICtrlCreateLabel('-', $x, $y, 23, 22, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetFont(-1, 13, 800) GUICtrlSetBkColor(-1, $COLOR_LIGHTGRAY) GUICtrlSetCursor(-1, $MCID_HAND) $x += 25 $gSqrSize_Data = GUICtrlCreateLabel($iSqrSize, $x, $y, 33, 22, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetBkColor(-1, $COLOR_LIGHTBLUE) $x += 35 $gSqrSize_Up = GUICtrlCreateLabel('+', $x, $y, 23, 22, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetFont(-1, 13, 800) GUICtrlSetBkColor(-1, $COLOR_LIGHTGRAY) GUICtrlSetCursor(-1, $MCID_HAND) $x -= 35 $x -= 25 $x -= 90 $y += $dy GUICtrlCreateLabel('Resize speed:', $x, $y, Default, Default, $SS_CENTERIMAGE) $x += 90 $gResizeSpeed_data = GUICtrlCreateSlider($x, $y, 80) GUICtrlSetLimit(-1, 100) GUICtrlSetData(-1, $iResizeSpeed) $x -= 90 #cs FUTURE DEVELOPMENT ----- BUILD PHASE: allow zero sum/prod use 8 & 9 in multiplication puzzle (HARDER) increase/decrease target squares count (determine probability of a square to participate) allow negative numbers (HARDER) ----- GAME PHASE: show target squares count show current/target squares count allow marking cols & rows as balanced automatically mark cols & rows as balanced automatically mark invalid selection (div creating mod, sum/prod exceeding result) show diff calc allow hints allow real-time switch puzzle type #ce Local $gOK = GUICtrlCreateButton('Done', $iSUI_ButtonSpacing, $iSUI_H - $iSUI_ButtonH - $iSUI_ButtonSpacing, $iSUI_W - $iSUI_ButtonSpacing * 2, $iSUI_ButtonH) $gdGUIEnd = GUICtrlCreateDummy() ; user interaction While True $msg = GUIGetMsg() Switch $msg Case $gPuzzleType_Addition If Not $bPuzzleTypeIsAddition Then $bPuzzleTypeIsAddition = True Pref_RefreshPuzzleTypeButtons($gPuzzleType_Addition, $gPuzzleType_Multiplication) EndIf Case $gPuzzleType_Multiplication If $bPuzzleTypeIsAddition Then $bPuzzleTypeIsAddition = False Pref_RefreshPuzzleTypeButtons($gPuzzleType_Addition, $gPuzzleType_Multiplication) EndIf Case $gGridWidth_Up $iColCount = _Min($iColCount + 1, 9) GUICtrlSetData($gGridWidth_Data, $iColCount) Case $gGridWidth_Down $iColCount = _Max($iColCount - 1, 3) GUICtrlSetData($gGridWidth_Data, $iColCount) Case $gGridHeight_Up $iRowCount = _Min($iRowCount + 1, 9) GUICtrlSetData($gGridHeight_Data, $iRowCount) Case $gGridHeight_Down $iRowCount = _Max($iRowCount - 1, 3) GUICtrlSetData($gGridHeight_Data, $iRowCount) Case $gSqrSize_Up $iSqrSize = _Min($iSqrSize + 5, 60) GUICtrlSetData($gSqrSize_Data, $iSqrSize) Case $gSqrSize_Down $iSqrSize = _Max($iSqrSize - 5, 20) GUICtrlSetData($gSqrSize_Data, $iSqrSize) Case $gOK, $GUI_EVENT_CLOSE $iResizeSpeed = GUICtrlRead($gResizeSpeed_data) ExitLoop EndSwitch WEnd ; delete all controls DeleteAllControls() ; - resize GUI WinSetTrans($hGUI, '', 192) WinSetTitle($hGUI, '', $sAppName) $iGUI_Width = $iSqrSize * ($iColCount + 3) + 2 $iGUI_Height = $iSqrSize * ($iRowCount + 2) + 2 _WinPoseAroundCenter($hGUI, $iGUI_Width + $iWDiff, $iGUI_Height + $iHDiff, $iResizeSpeed) WinSetTrans($hGUI, '', 255) Return True EndFunc ;==>Pref Func Pref_RefreshPuzzleTypeButtons($gPuzzleType_Addition, $gPuzzleType_Multiplication) GUICtrlSetBkColor($gPuzzleType_Addition, $bPuzzleTypeIsAddition ? $COLOR_LIGHTBLUE : $COLOR_LIGHTGRAY) GUICtrlSetCursor($gPuzzleType_Addition, $bPuzzleTypeIsAddition ? $MCID_ARROW : $MCID_HAND) GUICtrlSetBkColor($gPuzzleType_Multiplication, $bPuzzleTypeIsAddition ? $COLOR_LIGHTGRAY : $COLOR_LIGHTBLUE) GUICtrlSetCursor($gPuzzleType_Multiplication, $bPuzzleTypeIsAddition ? $MCID_HAND : $MCID_ARROW) EndFunc ;==>Pref_RefreshPuzzleTypeButtons Func Help() Local Const $iSUI_W = 410, $iSUI_H = 350, $iSUI_ButtonH = 30, $iSUI_ButtonSpacing = 10 GUISetFont(9.5, Default, Default, 'Tahoma') Local $x = 15, $y = 10, $dy = 25 ; delete all controls DeleteAllControls() ; resize GUI WinSetTrans($hGUI, '', 192) WinSetTitle($hGUI, '', $sAppName & ' Instructions') _WinPoseAroundCenter($hGUI, $iSUI_W + $iWDiff, $iSUI_H + $iHDiff, $iResizeSpeed) WinSetTrans($hGUI, '', 255) ; generate controls $gdGUIStart = GUICtrlCreateDummy() GUICtrlCreateLabel('WARNING! This game may be highly addictive :-)' & @CRLF & @CRLF & _ 'Click the gray squares in the middle to select them and paint them green. The selected squares in every row must match the result of the row, displayed on the right-hand side; the selected squares in every column must match the result of the column, displayed at the bottom.' & @CRLF & @CRLF & _ 'If you eliminate a square, you may right-click it to paint it dark gray.' & @CRLF & @CRLF & _ 'The type of the puzzle - Addition or Multiplication - is indicated in the white square at the bottom-right corner.' & @CRLF & @CRLF & _ 'Click the "Tools" icon on the upper-left corner to change puzzle type, grid size and other preferences.' & @CRLF & @CRLF & _ 'Enjoy :-)', $x, $y, $iSUI_W - $x * 2, $iSUI_H - 60) $y += $dy $gOK = GUICtrlCreateButton('OK, I think I got it...', $iSUI_ButtonSpacing, $iSUI_H - $iSUI_ButtonH - $iSUI_ButtonSpacing, $iSUI_W - $iSUI_ButtonSpacing * 2, $iSUI_ButtonH) $gdGUIEnd = GUICtrlCreateDummy() ; user interaction While True $msg = GUIGetMsg() Switch $msg Case $gOK, $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd ; delete all controls DeleteAllControls() ; resize GUI WinSetTrans($hGUI, '', 192) WinSetTitle($hGUI, '', $sAppName) _WinPoseAroundCenter($hGUI, $iGUI_Width + $iWDiff, $iGUI_Height + $iHDiff, $iResizeSpeed) WinSetTrans($hGUI, '', 255) Return False EndFunc ;==>Help Func GuiCtrlDeleteAndZero(ByRef $gID) If GUICtrlDelete($gID) Then $gID = 0 Return 1 Else Return 0 EndIf EndFunc ;==>GuiCtrlDeleteAndZero Func DeleteAllControls() Local $gIDStart = $gdGUIStart Local $gIDEnd = $gdGUIEnd For $gID = $gIDStart To $gIDEnd GuiCtrlDeleteAndZero($gID) Next EndFunc ;==>DeleteAllControls Func _WinPoseAroundCenter($hGUI, $iNewWidth, $iNewHeight, $iSpeed = 0) Local $aPos = WinGetPos($hGUI) Local $x = $aPos[0] + $aPos[2] / 2 - $iNewWidth / 2 If $x < 0 Then $x = 0 If $x + $iNewWidth > @DesktopWidth Then $x = @DesktopWidth - $iNewWidth Local $y = $aPos[1] + $aPos[3] / 2 - $iNewHeight / 2 If $y < 0 Then $y = 0 If $y + $iNewHeight > @DesktopHeight Then $y = @DesktopHeight - $iNewHeight _WinPose($hGUI, '', $x, $y, $iNewWidth, $iNewHeight, $iSpeed) EndFunc ;==>_WinPoseAroundCenter enjoy! MagicMath.ico
    2 points
  3. Thanks for the explanation ! For the record, I am scripting the following, to access easily any of your examples : #include <GUIConstantsEx.au3> #include <MsgBoxConstants.au3> Opt("MustDeclareVars", 1) If _Doubleton("AutoIt - UEZ WebP all examples") Then Exit ; script already launched + user wants to quit Example() ;============================================== Func Example() Local $hGUI, $idMenu, $iPID, $nMsg, $sFileName Local $aExample[][3] = [ _ ["01", "WebP Example01.au3", "View WebP image (from file, shrinked at 75%)"], _ ["02", "WebP Example02.au3", "View WebP image (from memory, full size)"], _ ["03", "WebP Example03.au3", "WebP image information"], _ ["04", "WebP Example04.au3", "Convert to WebP lossless && lossy (simple), save"], _ ["05", "WebP Example05.au3", "Convert to WebP lossy (advanced), no save"], _ ["05.1", "WebP Example05.1.au3", "Convert to WebP lossy (advanced), save"], _ ["06", "WebP Example06.au3", "Extract all frames from an animated WebP file"], _ ["07", "WebP Example07.au3", "Play an animated WebP file in GUI (same thread)"], _ ["08.1", "WebP Example08.1.au3", "Create WebP animation from GDI+ image files"], _ ["09", "WebP Example09.au3", "Create WebP animation from screen capture"], _ ["10.1", "WebP Example10.1.au3", "Converts GIF animation to WebP animation"], _ ["11", "WebP Example11.au3", "Display the differences of 2 WebP images (same dimension"], _ ["12", "WebP Example12.au3", "Resize a WebP image"], _ ["13", "WebP Example13.au3", "Estimate the quality of a WebP image"], _ ["14.1", "WebP Example14.1.au3", "Play an animated WebP file on Desktop (separated thread)"], _ ["15", "WebP Example15.au3", "Play an animated WebP file in GUI (separated thread)"], _ ["16.1", "WebP Example16.1.au3", "Converts a PNG animation to a WebP animation"], _ ["17", "WebP Example17.au3", "Re-encode a WebP image"], _ ["18", "WebP Example18.au3", "Re-encode an animated WebP file"] ] $hGUI = GUICreate("UEZ WebP all examples", 400, 200) $idMenu = GUICtrlCreateMenu("Examples") ; create all menu items immediately after this line (+++) For $i = 0 To Ubound($aExample) - 1 GUICtrlCreateMenuItem($aExample[$i][0] & @TAB & $aExample[$i][2], $idMenu, -1, 1) ; last param. 1 = create a menuradioitem Next GUISetState(@SW_SHOW) While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE ExitLoop Case $idMenu + 1 To $idMenu + Ubound($aExample) $sFileName = @ScriptDir & "\" & $aExample[$nMsg - ($idMenu + 1)][1] If Not FileExists($sFileName) Then Msgbox($MB_TOPMOST, "Script not found", $sFileName) Else $iPID = Run(@AutoItExe & " /AutoIt3ExecuteScript " & chr(34) & $sFileName & chr(34)) ; chr(34) is " If $iPID = 0 Then MsgBox($MB_TOPMOST, "Run issue : $iPID = 0 , @error = " & @error, $sFileName) EndIf EndSwitch WEnd GUIDelete($hGUI) EndFunc ;==>Example ;============================================== Func _Doubleton($sTitle) If WinExists($sTitle) Then Local $iChoice = Msgbox(BitOr($MB_YESNO, $MB_DEFBUTTON2, $MB_ICONQUESTION, $MB_TOPMOST), $sTitle, _ "This script is already running. Launch another instance ?") If $iChoice = $IDNO Then Return True EndIf AutoItWinSetTitle($sTitle) ; remember the AutoIt window is always hidden EndFunc ;==>_Doubleton
    1 point
  4. MattyD

    WinRT - WinUI3

    Hi guys, apologies in advance for the wall of text! Just an update as to where things are ATM - I've have gone on a tangent re: resolving IIDs for paramatised interfaces. This is more of a core WinRT thing - but I thought I'd take whoever is interested along on the ride... So I attempted to create a grid (Microsoft.UI.Xaml.Controls.Grid) which should theoretically allows us drop other controls within it. Basically its a layout thing to divide up the window. Want an "OK" button down the bottom right? Just nest the button in the cell that is down there!. Creating a grid, then extracting the row and column definitions is easy enough. #include "Include\Classes\Microsoft.UI.Xaml.Controls.Grid.au3" ;-- Setup window etc. -- Local $pGrid_Fact = _WinRT_GetActivationFactory("Microsoft.UI.Xaml.Controls.Grid", $sIID_IGridFactory) Local $pGrid = IGridFactory_CreateInstance($pGrid_Fact, 0, $pInner) Local $pColDefs = IGrid_GetColumnDefinitions($pGrid) Local $pRowDefs = IGrid_GetRowDefinitions($pGrid) Looking at $pColDefs, we can determine its a "Microsoft.UI.Xaml.Controls.ColumnDefinitionCollection". We know this by inspecting Microsoft.UI.Xaml.Controls.Grid in the class explorer. Otherwise _WinRT_DisplayInterfaces($pColDefs ) or _WinRT_DisplayClass($pColDefs ) will get you to the same place. Method : get_ColumnDefinitions Fn : value = get_ColumnDefinitions() P0 : value type: Microsoft.UI.Xaml.Controls.ColumnDefinitionCollection After digging in the metadata we can resolve some IIDs of $pColDefs, but at best _WinRT_DisplayInterfaces() only gives us: Class: Microsoft.UI.Xaml.Controls.ColumnDefinitionCollection {CDFBA81A-54FA-557D-A712-21640F16C534} {749BC47C-1743-5C21-9CED-C8A1134C7BA7} {80741C8F-A401-5C63-B6C4-15D165E541C7} {E7BEAEE7-160E-50F7-8789-D63463F979FA} - IDependencyObject {EB24C20B-9816-4AC7-8CFF-36F67A118F4E} {00000038-0000-0000-C000-000000000046} - IWeakReferenceSource {DF0B3D60-548F-101B-8E65-08002B2BD119} - ISupportErrorInfo {00000000-0000-0000-C000-000000000046} - IUnknown {AF86E2E0-B12D-4C6A-9C5A-D7AA65101E90} - IInspectable But what we're looking for is these collection interfaces. TypeDef : Microsoft.UI.Xaml.Controls.ColumnDefinitionCollection Extends : System.Object Interface : Windows.Foundation.Collections.IVector`1<Microsoft.UI.Xaml.Controls.ColumnDefinition> Interface : Windows.Foundation.Collections.IIterable`1<Microsoft.UI.Xaml.Controls.ColumnDefinition> The class explorer tells us IVector should be there. Windows.Foundation.Collections.IVector`1 has a GUID defined as "{913337E9-11A1-4345-A3A2-4E7F956E222D}". so what gives? It does not appear in our list because the IVector`1 GUID is NOT an IID, it is something else called a PIID. It needs to be combined with the datatype in order to give us the IID for Windows.Foundation.Collections.IVector`1<Microsoft.UI.Xaml.Controls.ColumnDefinition>. We can probably just assume the top GUID maps to this... but we really need a way to resolve it properly. The IIDs for paramatiesed interfaces are calculated at runtime so we can't just dig in the metadata for them. Enter RoGetParameterizedTypeInstanceIID. This is the can of worms that I'm still trying to nail down - so stay tuned for part 2! Once all that is sorted I'll also need to fix the WinRT Library generator. At the moment methods involving arrays don't generate correctly, which is kinda important when dealing with collections!!!
    1 point
×
×
  • Create New...