#NoTrayIcon #RequireAdmin #Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_icon=ProcRespawn.ico #AutoIt3Wrapper_Compression=4 #AutoIt3Wrapper_UseX64=y #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #include #include #include #include #include #include #include #include Opt('GUIOnEventMode', 1) Opt('MustDeclareVars', 1) Opt('TrayMenuMode', 1+2) Opt('TrayOnEventMode', 1) Global Const $sRunOnceID = 'therksoft.ProcRespawn.RunOnceID' If WinExists($sRunOnceID) Then Exit AutoItWinSetTitle($sRunOnceID) Global $sAppTitle = 'Process Respawn', $bHideNotify = 0, $bHideUnreadable = 1, _ $hMainWindow, $lv_Monitor, $bt_Add, $bt_Remove, $bt_Params, $in_Interval, $bt_Shortcut, $bt_Exit, _ $cm_Shortcut, $me_Startup, $mi_StartHide, $mi_StartShow, $me_Desktop, $mi_DeskHide, $mi_DeskShow, _ $sConfigPath = @AppDataDir & '\therksoft-' & $sAppTitle & '.ini', $iCheckTime = Int(IniRead($sConfigPath, 'Config', 'Time', 5)) If $iCheckTime < 1 Then $iCheckTime = 1 If $CmdLine[0] And $CmdLine[1] = '/hide' Then $bHideNotify = 1 Main() Func Main() TraySetState() TraySetToolTip($sAppTitle) TraySetClick(16) TraySetOnEvent($TRAY_EVENT_PRIMARYDOUBLE, '_TrayShow') TrayCreateItem('&Settings') TrayItemSetState(-1, 512) TrayItemSetOnEvent(-1, '_TrayShow') TrayCreateItem('E&xit') TrayItemSetOnEvent(-1, '_ProgramExit') $hMainWindow = GUICreate($sAppTitle, 400, 250, Default, Default, $WS_OVERLAPPEDWINDOW) GUISetOnEvent($GUI_EVENT_CLOSE, '_GenHandler') $lv_Monitor = GUICtrlCreateListView('Name|PID|Path|Parameters', 5, 5, 290, 240, BitOR($GUI_SS_DEFAULT_LISTVIEW, $LVS_NOSORTHEADER)) GUICtrlSetResizing(-1, $GUI_DOCKBORDERS) Opt('GUIResizeMode', $GUI_DOCKSIZE+$GUI_DOCKTOP+$GUI_DOCKRIGHT) $bt_Add = GUICtrlCreateButton('&Add Process', 300, 5, 95, 25) GUICtrlSetOnEvent(-1, '_AddProcess') $bt_Remove = GUICtrlCreateButton('&Remove Process', 300, 35, 95, 25) GUICtrlSetOnEvent(-1, '_GenHandler') $bt_Params = GUICtrlCreateButton('Set &Parameters', 300, 65, 95, 25) GUICtrlSetOnEvent(-1, '_GenHandler') GUICtrlCreateLabel('&Frequency:', 300, 95, 55, 20, $SS_CENTERIMAGE) $in_Interval = GUICtrlCreateInput($iCheckTime, 355, 95, 20, 20) GUICtrlSetTip(-1, 'How frequently to check if processes are running.') GUICtrlSetOnEvent(-1, '_GenHandler') GUICtrlCreateLabel(' sec', 375, 95, 40, 20, $SS_CENTERIMAGE) Opt('GUIResizeMode', $GUI_DOCKSIZE+$GUI_DOCKBOTTOM+$GUI_DOCKRIGHT) $bt_Shortcut = GUICtrlCreateButton('Create Shortcut', 300, 190, 95, 25) GUICtrlSetOnEvent(-1, '_GenHandler') $bt_Exit = GUICtrlCreateButton('E&xit', 300, 220, 95, 25) GUICtrlSetOnEvent(-1, '_ProgramExit') $cm_Shortcut = GUICtrlCreateContextMenu(GUICtrlCreateDummy()) $me_Startup = GUICtrlCreateMenu('Create shortcut in &Startup', $cm_Shortcut) $mi_StartShow = GUICtrlCreateMenuItem('&Show program window when launched', $me_Startup) GUICtrlSetOnEvent(-1, '_MakeShortcut') $mi_StartHide = GUICtrlCreateMenuItem('&Hide program window when launched', $me_Startup) GUICtrlSetOnEvent(-1, '_MakeShortcut') $me_Desktop = GUICtrlCreateMenu('Create shortcut on &Desktop', $cm_Shortcut) $mi_DeskShow = GUICtrlCreateMenuItem('&Show program window when launched', $me_Desktop) GUICtrlSetOnEvent(-1, '_MakeShortcut') $mi_DeskHide = GUICtrlCreateMenuItem('&Hide program window when launched', $me_Desktop) GUICtrlSetOnEvent(-1, '_MakeShortcut') _RefreshMonitorList() AdlibRegister('_RefreshMonitorList', $iCheckTime * 1000) If Not $bHideNotify Then GUISetState() ProcessWaitClose(@AutoItPID) EndFunc Func _TrayShow() GUISetState(@SW_SHOW, $hMainWindow) WinActivate($hMainWindow) EndFunc Func _ProgramExit() If MsgBox(0x2134, $sAppTitle, 'Are you sure you want to exit this program?' & @LF & '(Processes will not be monitored/restarted)') = 6 Then Exit EndFunc Func _GenHandler() Switch @GUI_CtrlId Case $in_Interval $iCheckTime = Int(GUICtrlRead($in_Interval)) If $iCheckTime < 1 Then MsgBox(0x2030, $sAppTitle, 'Check time cannot be less than 1 second.') GUICtrlSetData($in_Interval, '1') $iCheckTime = 1 EndIf IniWrite($sConfigPath, 'Config', 'Time', $iCheckTime) AdlibRegister('_RefreshMonitorList', $iCheckTime * 1000) Case $bt_Remove Local $iSel = _GUICtrlListView_GetNextItem($lv_Monitor) If $iSel = -1 Then Return Local $sProcName = _GUICtrlListView_GetItemText($lv_Monitor, $iSel, 0) If MsgBox(0x2124, $sAppTitle, 'Are you sure you want to stop monitoring this process? (' & $sProcName & ')', 0, $hMainWindow) = 6 Then IniDelete($sConfigPath, 'Processes', $sProcName) IniDelete($sConfigPath, 'ProcessParams', $sProcName) _RefreshMonitorList() EndIf Case $bt_Params Local $iSel = _GUICtrlListView_GetNextItem($lv_Monitor) If $iSel = -1 Then Return Local $sProcName = _GUICtrlListView_GetItemText($lv_Monitor, $iSel, 0) Local $sParams = _GUICtrlListView_GetItemText($lv_Monitor, $iSel, 3) $sParams = InputBox($sAppTitle, 'Enter parameters for process: ' & $sProcName, $sParams, '', 300, 120, Default, Default, 0, $hMainWindow) If $sParams Then IniWrite($sConfigPath, 'ProcessParams', $sProcName, $sParams) _RefreshMonitorList() EndIf Case $bt_Shortcut Local $aPos = WinGetPos(GUICtrlGetHandle($bt_Shortcut)) If Not @error Then _GUICtrlMenu_TrackPopupMenu(GUICtrlGetHandle($cm_Shortcut), $hMainWindow, $aPos[0], $aPos[1] + $aPos[3]) Case $GUI_EVENT_CLOSE GUISetState(@SW_HIDE, $hMainWindow) If Not $bHideNotify Then TrayTip($sAppTitle, 'The program window has been hidden. Double click this icon to see it again or right-click to choose Exit.', 5, 1) $bHideNotify = 1 EndIf EndSwitch EndFunc Func _MakeShortcut() Local $sHide, $sPath = @DesktopDir Switch @GUI_CtrlId Case $mi_DeskHide $sHide = '/hide' Case $mi_StartShow $sPath = @StartupDir Case $mi_StartHide $sHide = '/hide' $sPath = @StartupDir EndSwitch FileCreateShortcut(@ScriptFullPath, $sPath & '\' & $sAppTitle & '.lnk', @ScriptDir, $sHide, '', @ScriptFullPath) EndFunc Func _AddProcess() Opt('GUIOnEventMode', 0) Local $gm, $hListWindow, $bt_ListAdd, $ch_ListRefresh $hListWindow = GUICreate($sAppTitle, 300, 300, Default, Default, BitOR($WS_MAXIMIZEBOX, $WS_CAPTION, $WS_POPUP, $WS_SYSMENU, $WS_SIZEBOX), Default, $hMainWindow) Global $lv_ListProcess = GUICtrlCreateListView('Name|PID|Path', 5, 5, 290, 265, BitOR($GUI_SS_DEFAULT_LISTVIEW, $LVS_NOSORTHEADER)) GUICtrlSetResizing(-1, $GUI_DOCKBORDERS) Opt('GUIResizeMode', $GUI_DOCKSIZE+$GUI_DOCKBOTTOM+$GUI_DOCKLEFT) $bt_ListAdd = GUICtrlCreateButton('Add to Monitor', 5, 270, 90, 25) $ch_ListRefresh = GUICtrlCreateCheckbox('Refresh', 100, 270, 110, 25) _RefreshProcList() GUISetState() WinSetState($hMainWindow, '', @SW_DISABLE) While 1 $gm = GUIGetMsg() Switch $gm Case $bt_ListAdd Local $iSel = _GUICtrlListView_GetNextItem($lv_ListProcess) Local $sProcName = _GUICtrlListView_GetItemText($lv_ListProcess, $iSel, 0) Local $sProcPath = _GUICtrlListView_GetItemText($lv_ListProcess, $iSel, 2) IniWrite($sConfigPath, 'Processes', $sProcName, $sProcPath) ExitLoop Case $ch_ListRefresh If BitAND(GUICtrlRead($ch_ListRefresh), $GUI_CHECKED) Then _RefreshProcList() AdlibRegister('_RefreshProcList', 1000) Else AdlibUnRegister('_RefreshProcList') EndIf Case $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd AdlibUnRegister('_RefreshProcList') _RefreshMonitorList() GUIDelete($hListWindow) WinSetState($hMainWindow, '', @SW_ENABLE) WinActivate($hMainWindow) Opt('GUIOnEventMode', 1) EndFunc Func _RefreshMonitorList() Local $iSel = _GUICtrlListView_GetNextItem($lv_Monitor) _GUICtrlListView_BeginUpdate($lv_Monitor) _GUICtrlListView_DeleteAllItems($lv_Monitor) Local $aMonList = IniReadSection($sConfigPath, 'Processes') If @error Then _GUICtrlListView_EndUpdate($lv_Monitor) Return EndIf _ArraySort($aMonList, 0, 1, 0, 0) For $forMonList = 1 To $aMonList[0][0] Local $sParams = IniReadRaw($sConfigPath, 'ProcessParams', $aMonList[$forMonList][0], @LF) Local $iPID = _CheckProcessByPath($aMonList[$forMonList][1]) If Not $iPID Then If $sParams <> @LF Then $iPID = Run('"' & $aMonList[$forMonList][1] & '"' & ' ' & $sParams) Else $iPID = Run('"' & $aMonList[$forMonList][1] & '"') EndIf EndIf GUICtrlCreateListViewItem($aMonList[$forMonList][0] & '|' & $iPID & '|' & $aMonList[$forMonList][1] & '|' & StringStripWS($sParams, 3), $lv_Monitor) Next _GUICtrlListView_EndUpdate($lv_Monitor) _GUICtrlListView_SetColumnWidth($lv_Monitor, 0, $LVSCW_AUTOSIZE) _GUICtrlListView_SetColumnWidth($lv_Monitor, 1, $LVSCW_AUTOSIZE) _GUICtrlListView_SetColumnWidth($lv_Monitor, 2, $LVSCW_AUTOSIZE) If $iSel <> -1 Then _GUICtrlListView_SetItemSelected($lv_Monitor, $iSel) EndFunc Func _RefreshProcList() Local $iSel = _GUICtrlListView_GetNextItem($lv_ListProcess) Local $aProcList = _ProcessListProperties() _ArraySort($aProcList, 0, 1, 0, 0) _GUICtrlListView_BeginUpdate($lv_ListProcess) _GUICtrlListView_DeleteAllItems($lv_ListProcess) For $forProcs = 1 To $aProcList[0][0] GUICtrlCreateListViewItem($aProcList[$forProcs][0] & '|' & $aProcList[$forProcs][1] & '|' & $aProcList[$forProcs][2], $lv_ListProcess) Next _GUICtrlListView_EndUpdate($lv_ListProcess) _GUICtrlListView_SetColumnWidth($lv_ListProcess, 0, $LVSCW_AUTOSIZE) _GUICtrlListView_SetColumnWidth($lv_ListProcess, 1, $LVSCW_AUTOSIZE) _GUICtrlListView_SetColumnWidth($lv_ListProcess, 2, $LVSCW_AUTOSIZE) If $iSel <> -1 Then _GUICtrlListView_SetItemSelected($lv_ListProcess, $iSel) EndFunc Func _CheckProcessByPath($sPath) Local $iReturn, $oWMI, $oResult $sPath = StringReplace($sPath, "\", "\\") $sPath = StringReplace($sPath, "'", "\'") $sPath = StringReplace($sPath, '"', '\"') ; Connect to WMI and get process objects $oWMI = ObjGet("winmgmts:{impersonationLevel=impersonate,authenticationLevel=pktPrivacy, (Debug)}!\\.\root\cimv2") If IsObj($oWMI) Then $oResult = $oWMI.ExecQuery("select ProcessId from win32_process where ExecutablePath = '" & $sPath & "'") If IsObj($oResult) Then ; Return for no matches If $oResult.count = 0 Then Return SetError(3, 0, 0) ; For each process... For $oProc In $oResult $iReturn = $oProc.ProcessId Next Else SetError(2); Error getting process collection from WMI EndIf ; release the collection object $oResult = 0 Else SetError(1); Error connecting to WMI EndIf ; Return array Return $iReturn EndFunc Func _ProcessListProperties() Local $sReturn, $oWMI, $oResult, $aProcList[1][1], $n = 1 ; Connect to WMI and get process objects $oWMI = ObjGet("winmgmts:{impersonationLevel=impersonate,authenticationLevel=pktPrivacy, (Debug)}!\\.\root\cimv2") If IsObj($oWMI) Then $oResult = $oWMI.ExecQuery("select name,ProcessId,ExecutablePath from win32_process") If IsObj($oResult) Then ; Return for no matches If $oResult.count = 0 Then Return $aProcList ; Size the array ReDim $aProcList[$oResult.count + 1][3] $aProcList[0][0] = UBound($aProcList) - 1 ; For each process... For $oProc In $oResult If Not $oProc.ExecutablePath Then ContinueLoop $aProcList[$n][0] = $oProc.name $aProcList[$n][1] = $oProc.ProcessId $aProcList[$n][2] = $oProc.ExecutablePath $n += 1 Next ReDim $aProcList[$n][3] $aProcList[0][0] = $n-1 Else SetError(2); Error getting process collection from WMI EndIf ; release the collection object $oResult = 0 Else SetError(1); Error connecting to WMI EndIf ; Return array Return $aProcList EndFunc Func IniReadRaw($sFile, $sSection, $sKey, $sDefault) Local $aSection = IniReadSection($sFile, $sSection) If @error Then Return $sDefault For $i = 1 To $aSection[0][0] If $aSection[$i][0] = $sKey Then Return $aSection[$i][1] Next Return $sDefault EndFunc