#NoTrayIcon #Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Icon=DDDA-SaveMan.ico #AutoIt3Wrapper_Outfile_x64=DDDA-SaveMan.exe #AutoIt3Wrapper_Compression=4 #AutoIt3Wrapper_UseUpx=y #AutoIt3Wrapper_UseX64=y #AutoIt3Wrapper_Res_Description=Save Manager for Dragon's Dogma Dark Arisen #AutoIt3Wrapper_Res_Fileversion=1.2.0.1 #AutoIt3Wrapper_Res_Fileversion_AutoIncrement=p #AutoIt3Wrapper_Res_LegalCopyright=n/a #AutoIt3Wrapper_Res_SaveSource=y #AutoIt3Wrapper_Res_Field=ProductName|DDDA Save Manager #AutoIt3Wrapper_Res_Field=OriginalFilename|DDDA-SaveMan.exe #AutoIt3Wrapper_Res_Field=AutoItVersion|3.3.14.2 #pragma compile(AutoItExecuteAllowed, True) #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #region - Document #include #include #include ;~ #include Global Const $BS_ICON = 0x0040 #include #include #include #include #include #include ;~ If $CmdLine[0] And $CmdLine[1] = 'DEBUG' Then ;~ FileInstall(@ScriptFullPath, @ScriptDir & '\script.au3') ;~ FileInstall('launchButtonOut.ico', @ScriptDir & '\launchButtonOut.ico') ;~ FileInstall('launchButtonOver.ico', @ScriptDir & '\launchButtonOver.ico') ;~ Run(FileGetShortName(@AutoItExe) & ' /AutoIt3ExecuteScript ' & FileGetShortName(@ScriptDir & '\script.au3')) ;~ Exit ;~ EndIf Opt('WinTitleMatchMode', 3) Global Const $APP_TITLE = 'DDDA Save Manager', $UNIQUE_APP_ID = 'UNIQUE_IDENTIFIER_DDDA_SAVEMAN' If ControlGetText($APP_TITLE, '', $UNIQUE_APP_ID) = $UNIQUE_APP_ID Then Exit ControlSetText($APP_TITLE, '', $UNIQUE_APP_ID, 'activate') Opt('GUICloseOnESC', 0) Opt('MustDeclareVars', 1) Opt('TrayOnEventMode', 1) Opt('TrayMenuMode', 1+2) Global Const $sButtonIconOut = _TempFile() Global Const $sButtonIconOver = _TempFile() FileInstall('launchButtonOut.ico', $sButtonIconOut) FileInstall('launchButtonOver.ico', $sButtonIconOver) Global Const $sReg32Node = @AutoItX64 ? 'WOW6432Node\' : '' Global Const $sSteamUserDir = RegRead('HKLM\SOFTWARE\' & $sReg32Node & 'Valve\Steam', 'InstallPath') & '\UserData\' Global Const $sActiveSaveFile = 'DDDA.sav' Global Const $sBackupExtension = '.sav.bak' Global Const $sConfigFile = @ScriptDir & '\DDDA-SaveMan.ini' Global Const $sConfigFolders = 'Folders:' & @ComputerName Global $sConfigSound = IniRead($sConfigFile, 'Config', 'Sound', @WindowsDir & '\media\tada.wav') Global $aReadFolders = IniReadSection($sConfigFile, $sConfigFolders) If @error Then Global $aReadFolders[1][1] = [ [ 0 ] ] Global $bShowTrayTipOnce = False #region - Main window build Global $hGUIMain = GUICreate($APP_TITLE, 500, 400, Default, Default, BitOR($GUI_SS_DEFAULT_GUI, $WS_MAXIMIZEBOX, $WS_SIZEBOX)) Opt('GUIResizeMode', $GUI_DOCKALL) Global $lb_Activator = GUICtrlCreateLabel($UNIQUE_APP_ID, 0, 0, 0, 0) ; <-- Must be first control (ID 3) for unique run process to work Global $bt_QuickExit = GUICtrlCreateButton('&x', -10, -10, 0, 0) GUICtrlCreateLabel('&Monitoring folders:', 5, 5, 100, 15) Global $li_FolderList = GUICtrlCreateList('', 5, 20, 305, 65, BitOR($LBS_SORT, $LBS_NOINTEGRALHEIGHT, $WS_BORDER, $WS_VSCROLL)) GUICtrlSetResizing(-1, BitOR($GUI_DOCKMENUBAR, $GUI_DOCKLEFT, $GUI_DOCKRIGHT)) For $i = 1 To $aReadFolders[0][0] GUICtrlSetData(-1, $aReadFolders[$i][1]) Next Global $cm_FolderMenu = GUICtrlCreateContextMenu($li_FolderList) Global $mi_Folder = GUICtrlCreateMenuItem('Open &folder', $cm_FolderMenu) GUICtrlSetState(-1, $GUI_DEFBUTTON) Global $mi_Remove = GUICtrlCreateMenuItem('&Remove folder', $cm_FolderMenu) Global $mi_Cleanup1 = GUICtrlCreateMenuItem('&Cleanup folder', $cm_FolderMenu) Opt('GUIResizeMode', BitOR($GUI_DOCKSIZE, $GUI_DOCKRIGHT, $GUI_DOCKTOP)) Global $bt_AddFolder = GUICtrlCreateButton('&Add folder', 315, 20, 85, 30) Global $bt_RemFolder = GUICtrlCreateButton('&Remove folder', 315, 55, 85, 30) Global $bt_Game = GUICtrlCreateButton('&Launch Game', 410, 5, 80, 80, $BS_ICON) GUICtrlSetImage(-1, $sButtonIconOut, -1) GUICtrlSetCursor(-1, 0) GUICtrlSetTip(-1, 'Launch game (Alt+L)') Global Enum $idxFileList_Active, $idxFileList_Count, $idxFileList_Time, $idxFileList_Filename, $idxFileList_Hash, $idxFileList_Fullpath Global $lv_SaveList = GUICtrlCreateListView('>|#|Timestamp|Filename|Hash', 0, 90, 500, 290, BitOR($LVS_SINGLESEL, $LVS_NOSORTHEADER)) GUICtrlSetTip(-1, 'Double-click to set active') GUICtrlSetResizing(-1, $GUI_DOCKBORDERS) Global $cm_FileMenu = GUICtrlCreateContextMenu($lv_SaveList) Global $mi_Active = GUICtrlCreateMenuItem('Set as &active', $cm_FileMenu) GUICtrlSetState(-1, $GUI_DEFBUTTON) Global $mi_Rename = GUICtrlCreateMenuItem('Rena&me file', $cm_FileMenu) Global $mi_Delete = GUICtrlCreateMenuItem('&Delete file', $cm_FileMenu) GUICtrlCreateMenuItem('', $cm_FileMenu) Global $mi_Cleanup2 = GUICtrlCreateMenuItem('&Cleanup folder', $cm_FileMenu) GUICtrlCreateMenuItem('', $cm_FileMenu) Global $mi_Refresh = GUICtrlCreateMenuItem('R&efresh list', $cm_FileMenu) Global $lb_Status = GUICtrlCreateLabel(' ', 0, 380, 410, 20, $SS_CENTERIMAGE, $WS_EX_STATICEDGE) GUICtrlSetResizing(-1, BitOR($GUI_DOCKSTATEBAR, $GUI_DOCKLEFT, $GUI_DOCKRIGHT)) Global $ch_Notify = GUICtrlCreateCheckbox('&Notify on save', 410, 380, 90, 20, Default, $WS_EX_STATICEDGE) GUICtrlSetResizing(-1, BitOR($GUI_DOCKSIZE, $GUI_DOCKBOTTOM, $GUI_DOCKRIGHT)) GUICtrlSetTip(-1, 'Play a sound whenever save files are updated') If Int(IniRead($sConfigFile, 'Config', 'Notify', 0)) Then GUICtrlSetState(-1, $GUI_CHECKED) #endregion - Main window GUIRegisterMsg($WM_NOTIFY, 'WM_NOTIFY') GUIRegisterMsg($WM_COMMAND, 'WM_COMMAND') Global $lv_AutoList If Not $aReadFolders[0][0] Then _AutoDetect() GUICtrlSetState($li_FolderList, $GUI_FOCUS) _GUICtrlListBox_SetCurSel($li_FolderList, 0) _ListFiles() AdlibRegister('_FileMonitor', 1000) #region - tray setup Global $ti_Show = TrayCreateItem('Show') TrayItemSetOnEvent(-1, '_ShowWindow') TrayItemSetState(-1, $TRAY_DEFAULT) Global $ti_Exit = TrayCreateItem('Exit') TrayItemSetOnEvent(-1, '_Exit') #endregion _Crypt_Startup() TraySetState($TRAY_ICONSTATE_SHOW) TraySetToolTip($APP_TITLE) GUISetState() #region - main loop While 1 If GUICtrlRead($lb_Activator) <> $UNIQUE_APP_ID Then GUICtrlSetData($lb_Activator, $UNIQUE_APP_ID) _ShowWindow() EndIf Global $aGM = GUIGetMsg(1) If $aGM[1] <> $hGUIMain Then ContinueLoop Switch $aGM[0] Case $bt_QuickExit _Exit() Case $GUI_EVENT_CLOSE GUISetState(@SW_HIDE) If Not $bShowTrayTipOnce Then TrayTip($APP_TITLE, 'Minimized to tray', 5, $TIP_ICONASTERISK) $bShowTrayTipOnce = True EndIf Case $GUI_EVENT_MOUSEMOVE Global $aGC = GUIGetCursorInfo() If Not @error Then _Hover($aGC[4]) Case $mi_Active _SetActive() Case $mi_Folder If GUICtrlRead($li_FolderList) Then ShellExecute(GUICtrlRead($li_FolderList)) Case $mi_Cleanup1, $mi_Cleanup2 _CleanupFolder() Case $mi_Rename _RenameFile() Case $mi_Delete _DeleteSave() Case $mi_Refresh, $li_FolderList _ListFiles() Case $bt_Game ShellExecute('steam://rungameid/367500') Case $bt_AddFolder Global $sSelectFolder = FileSelectFolder('Select folder', $sSteamUserDir, 0, '', $hGUIMain) If Not @error Then GUICtrlSetData($li_FolderList, $sSelectFolder) Case $bt_RemFolder, $mi_Remove If _GUICtrlListBox_GetCurSel($li_FolderList) <> -1 And MsgBox(0x124, 'Confirm', 'Stop monitoring this folder?' & @LF & GUICtrlRead($li_FolderList), 0, $hGUIMain) = 6 Then _GUICtrlListBox_DeleteString($li_FolderList, _GUICtrlListBox_GetCurSel($li_FolderList)) _ListFiles() EndIf Case $ch_Notify If BitAND(GUICtrlRead($ch_Notify), $GUI_CHECKED) Then Global $sSelectSound = FileOpenDialog('Select sound file', '', 'Sound files (*.wav;*.mp3)|All files (*.*)', 1, $sConfigSound, $hGUIMain) If @error Then GUICtrlSetState($ch_Notify, $GUI_UNCHECKED) Else $sConfigSound = $sSelectSound EndIf EndIf EndSwitch WEnd #endregion main loop Func _AutoDetect() Local $aFolderList = _FileListToArray($sSteamUserDir, '*', $FLTA_FOLDERS) If @error Then Return Local $hGUIAuto = GUICreate('DDDA Save Manager', 400, 160, Default, Default, BitOR($WS_CAPTION, $WS_POPUP, $WS_SYSMENU)) GUICtrlCreateLabel('Auto-detect found these potential save file folders:', 5, 5, 390, 15) Global $lv_AutoList = GUICtrlCreateListView('|', 0, 20, 400, 80, $LVS_NOCOLUMNHEADER) _GUICtrlListView_SetExtendedListViewStyle($lv_AutoList, BitOR($LVS_EX_CHECKBOXES, $LVS_EX_FULLROWSELECT)) GUICtrlCreateLabel('Please mark each folder that you would like to monitor and click continue.', 5, 105, 390, 15) Local $bt_Continue = GUICtrlCreateButton('Continue', 150, 125, 100, 30) For $i = 1 To $aFolderList[0] Local $sPotential = $sSteamUserDir & $aFolderList[$i] & '\367500\remote' If FileExists($sPotential) Then GUICtrlCreateListViewItem($sPotential, $lv_AutoList) EndIf Next _GUICtrlListView_SetColumnWidth($lv_AutoList, 0, $LVSCW_AUTOSIZE) GUISetState() While 1 Local $aGM = GUIGetMsg(1) If $aGM[1] <> $hGUIAuto Then ContinueLoop Switch $aGM[0] Case $bt_Continue For $i = 0 To _GUICtrlListView_GetItemCount($lv_AutoList) If _GUICtrlListView_GetItemChecked($lv_AutoList, $i) Then GUICtrlSetData($li_FolderList, _GUICtrlListView_GetItemText($lv_AutoList, $i)) EndIf Next ExitLoop Case $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd GUIDelete($hGUIAuto) GUISwitch($hGUIMain) EndFunc Func _FileMonitor() Local $sFolder, $sTime, $sCopyFile, $sSaveFile, $iCount = _GUICtrlListBox_GetCount($li_FolderList) For $i = 0 To $iCount-1 $sFolder = _GUICtrlListBox_GetText($li_FolderList, $i) $sSaveFile = $sFolder & '\' & $sActiveSaveFile If FileExists($sSaveFile) Then $sTime = FileGetTime($sSaveFile) $sCopyFile = $sFolder & '\DDDA ' & _LegibleTime($sTime, 1) & $sBackupExtension If Not FileExists($sCopyFile) Then FileCopy($sSaveFile, $sCopyFile) If BitAND(GUICtrlRead($ch_Notify), $GUI_CHECKED) Then SoundPlay($sConfigSound) EndIf _ListFiles() EndIf EndIf Next EndFunc Func _SetActive() Local $sFolder = GUICtrlRead($li_FolderList) If Not $sFolder Then Return Local $iSel = _GUICtrlListView_GetNextItem($lv_SaveList) If $iSel > -1 Then If _GUICtrlListView_GetItemText($lv_SaveList, $iSel, $idxFileList_Active) = '>' Then Return Local $sReplaceFile = $sFolder & '\' & _GUICtrlListView_GetItemText($lv_SaveList, $iSel, $idxFileList_Filename) & $sBackupExtension If FileExists($sReplaceFile) Then Local $sCurrentFile = $sFolder & '\' & $sActiveSaveFile If FileExists($sCurrentFile) Then Local $iMsgBox = MsgBox(0x124, 'Confirm', _ 'Are you sure you want to replace your current save file?' & @LF & @LF & _ 'Current file time:' & @LF & _ ' ' & _LegibleTime(FileGetTime($sCurrentFile)) & @LF & _ 'Replacement file time:' & @LF & _ ' ' & _LegibleTime(FileGetTime($sReplaceFile)), 0, $hGUIMain) If $iMsgBox = 7 Then Return EndIf Local $iCopy = FileCopy($sReplaceFile, $sFolder & '\' & $sActiveSaveFile, 1) If Not $iCopy Then Return MsgBox(0x10, 'Error', 'Unable to copy file.', 0, $hGUIMain) Else MsgBox(0x30, 'Notice', 'File no longer exists:' & @LF & $sReplaceFile, 0, $hGUIMain) EndIf _ListFiles() _GUICtrlListView_SetItemSelected($lv_SaveList, $iSel) EndIf EndFunc Func _DeleteSave() Local $sFolder = GUICtrlRead($li_FolderList) If Not $sFolder Then Return Local $iSel = _GUICtrlListView_GetNextItem($lv_SaveList) If $iSel > -1 Then Local $sFileName = _GUICtrlListView_GetItemText($lv_SaveList, $iSel, $idxFileList_Filename) & $sBackupExtension If FileExists($sFolder & '\' & $sFileName) Then If MsgBox(0x124, 'Confirm', 'Are you sure you want to delete this file?' & @LF & _ $sFileName, 0, $hGUIMain) = 6 Then FileDelete($sFolder & '\' & $sFileName) EndIf EndIf _ListFiles() EndIf EndFunc Func _RenameFile() Local $sFolder = GUICtrlRead($li_FolderList) If Not $sFolder Then Return Local $iSel = _GUICtrlListView_GetNextItem($lv_SaveList) If $iSel > -1 Then Local $sFileName = _GUICtrlListView_GetItemText($lv_SaveList, $iSel, $idxFileList_Filename) If FileExists($sFolder & '\' & $sFileName & $sBackupExtension) Then While 1 Local $sNewName = InputBox('Rename file...', 'Enter the new file name:', $sFileName, '', 250, 120, Default, Default, 0, $hGUIMain) If @error Or ($sNewName And Not StringRegExp($sNewName, '[\\/\:\*\?"\<\>\|]')) Then ExitLoop MsgBox(0x30, 'Warning', 'Filenames cannot be blank and cannot contain any of the following:' & @LF & @TAB & '\ / : * ? " < > |', 0, $hGUIMain) ; OK: 1 WEnd If $sNewName And $sNewName <> $sFileName Then If Not FileMove($sFolder & '\' & $sFileName & $sBackupExtension, $sFolder & '\' & $sNewName & $sBackupExtension) Then MsgBox(0x30, 'Warning', 'Unable to rename file', 0, $hGUIMain) EndIf EndIf EndIf _ListFiles() EndIf EndFunc Func _CleanupFolder() Local $sFolder = GUICtrlRead($li_FolderList) If $sFolder And _GUICtrlListView_GetItemCount($lv_SaveList) > 5 Then If MsgBox(0x44, 'Notice', 'Cleanup will move your old save files into a separate folder,' & @LF & _ 'leaving only the 5 latest files. Do you wish to continue?', 0, $hGUIMain) = 6 Then Local $aCleanupList = _FileListToArray($sFolder, '*' & $sBackupExtension, $FLTA_FILES) If Not @error Then Local $sCleanupDir = $sFolder & '\cleanup' & @YEAR & @MON & @MDAY If DirCreate($sCleanupDir) Then _ArrayColInsert($aCleanupList, 1) For $i = 1 To $aCleanupList[0][0] $aCleanupList[$i][1] = FileGetTime($sFolder & '\' & $aCleanupList[$i][0], 0, 1) Next _ArraySort($aCleanupList, 1, 1, 0, 1) Local $sMoveError = '' For $i = 6 To $aCleanupList[0][0] If Not FileMove($sFolder & '\' & $aCleanupList[$i][0], $sCleanupDir) Then $sMoveError &= @LF & $aCleanupList[$i][0] Next If $sMoveError Then MsgBox(0x30, 'Warning', 'Some files could not be moved:' & $sMoveError, 0, $hGUIMain) EndIf _ListFiles() Else MsgBox(0x30, 'Warning', 'Unable to create cleanup folder', 0, $hGUIMain) EndIf EndIf EndIf EndIf EndFunc Func _ListFiles() Local $iSel = _GUICtrlListView_GetNextItem($lv_SaveList) GUICtrlSetData($lb_Status, ' Reading files...') _GUICtrlListView_DeleteAllItems($lv_SaveList) Local $sFolder = GUICtrlRead($li_FolderList) If $sFolder Then Local $aFileList = _FileListToArray($sFolder, '*' & $sBackupExtension, $FLTA_FILES) If Not @error Then Local $aListViewArray[$aFileList[0]][5], $sItemFullPath Local $sCurrentTime = _LegibleTime(FileGetTime($sFolder & '\' & $sActiveSaveFile)) For $i = 0 To $aFileList[0]-1 ; Full path for utility sake $sItemFullPath = $sFolder & '\' & $aFileList[$i+1] $aListViewArray[$i][$idxFileList_Hash] = _HashCache($sItemFullPath, $aListViewArray[$i][$idxFileList_Time]) $aListViewArray[$i][$idxFileList_Filename] = StringTrimRight($aFileList[$i+1], StringLen($sBackupExtension)) $aListViewArray[$i][$idxFileList_Time] = _LegibleTime(FileGetTime($sItemFullPath)) $aListViewArray[$i][$idxFileList_Active] = $sCurrentTime = $aListViewArray[$i][$idxFileList_Time] ? '>' : '' Next _ArraySort($aListViewArray, 1, 0, 0, $idxFileList_Time) For $i = 0 To $aFileList[0]-1 $aListViewArray[$i][$idxFileList_Count] = $i+1 Next _GUICtrlListView_DeleteAllItems($lv_SaveList) _GUICtrlListView_BeginUpdate($lv_SaveList) _GUICtrlListView_AddArray($lv_SaveList, $aListViewArray) For $i = 0 To _GUICtrlListView_GetColumnCount($lv_SaveList)-1 _GUICtrlListView_SetColumnWidth($lv_SaveList, $i, $LVSCW_AUTOSIZE) Next _GUICtrlListView_SetItemSelected($lv_SaveList, -1, False) _GUICtrlListView_EndUpdate($lv_SaveList) GUICtrlSetData($lb_Status, $aFileList[0] & ' file' & ($aFileList[0] = 1 ? '' : 's')) Else GUICtrlSetData($lb_Status, 'No files detected') EndIf Else GUICtrlSetData($lb_Status, 'No folder selected') EndIf If $iSel <> -1 Then _GUICtrlListView_SetItemSelected($lv_SaveList, $iSel) EndFunc Func _ShowWindow() GUISetState(@SW_SHOWNORMAL, $hGUIMain) WinActivate($hGUIMain) EndFunc Func _Exit() AdlibUnRegister('_FileMonitor') GUISetState(@SW_HIDE) _Crypt_Shutdown() Local $iCount = _GUICtrlListBox_GetCount($li_FolderList) Local $aFolders[$iCount][2] For $i = 0 To $iCount-1 $aFolders[$i][0] = 'Folder' & $i $aFolders[$i][1] = _GUICtrlListBox_GetText($li_FolderList, $i) Next IniWriteSection($sConfigFile, $sConfigFolders, $aFolders, 0) Local $bNotify = BitAND(GUICtrlRead($ch_Notify), $GUI_CHECKED) ? 1 : 0 IniWrite($sConfigFile, 'Config', 'Notify', $bNotify) IniWrite($sConfigFile, 'Config', 'Sound', $sConfigSound) FileDelete($sButtonIconOut) FileDelete($sButtonIconOver) Exit EndFunc Func _Hover($iCtrl) Global $iHoverMem If $iCtrl <> $iHoverMem Then $iHoverMem = $iCtrl If $iCtrl = $bt_Game Then GUICtrlSetImage($bt_Game, $sButtonIconOver, -1) Else GUICtrlSetImage($bt_Game, $sButtonIconOut, -1) EndIf EndIf EndFunc Func _LegibleTime($aTime, $iFormat = 0) If IsArray($aTime) And UBound($aTime) >= 5 Then Local $sFormat = StringFormat('%04d-%02d-%02d %02d:%02d:%02d', $aTime[0], $aTime[1], $aTime[2], $aTime[3], $aTime[4], $aTime[5]) If $iFormat Then Return StringReplace($sFormat, ':', '.') Return $sFormat Else Return '' EndIf EndFunc Func _HashCache($sFilePath, $sFileTime) If Not IsDeclared('HASH_CACHE') Then Global $HASH_CACHE[100][3] EndIf For $i = 1 To $HASH_CACHE[0][0] If $HASH_CACHE[$i][0] = $sFilePath Then If $HASH_CACHE[$i][1] <> $sFileTime Then $HASH_CACHE[$i][1] = $sFileTime $HASH_CACHE[$i][2] = StringTrimLeft(_Crypt_HashFile($sFilePath, $CALG_SHA1), 2) EndIf Return $HASH_CACHE[$i][2] EndIf Next $HASH_CACHE[0][0] += 1 If $HASH_CACHE[0][0] >= UBound($HASH_CACHE, 2) Then ReDim $HASH_CACHE[$HASH_CACHE[0][0]+100][3] EndIf $HASH_CACHE[$HASH_CACHE[0][0]][0] = $sFilePath $HASH_CACHE[$HASH_CACHE[0][0]][1] = $sFileTime $HASH_CACHE[$HASH_CACHE[0][0]][2] = StringTrimLeft(_Crypt_HashFile($sFilePath, $CALG_SHA1), 2) Return $HASH_CACHE[$HASH_CACHE[0][0]][2] EndFunc #region - Windows messages Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam) Local Const $tagNMHDR = 'struct;hwnd hWndFrom;uint_ptr IDFrom;INT Code;endstruct' Local Const $NM_DBLCLK = -3 Local $iIDFrom = BitAND($wParam, 0xFFFF) Local $tNMHDR = DllStructCreate($tagNMHDR, $lParam) Local $iCode = DllStructGetData($tNMHDR, 'Code') If $iCode = $NM_DBLCLK Then If $iIDFrom = $lv_SaveList Then _SetActive() ElseIf $iIDFrom = $lv_AutoList Then Local $iSel = _GUICtrlListView_GetNextItem($lv_AutoList) _GUICtrlListView_SetItemChecked($lv_AutoList, $iSel, Not _GUICtrlListView_GetItemChecked($lv_AutoList, $iSel)) EndIf EndIf Return $GUI_RUNDEFMSG EndFunc Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam) Local Const $LBN_DBLCLK = 2 Local $iIDFrom = BitAND($wParam, 0xFFFF) ; Low Word Local $iCode = BitShift($wParam, 16) ; Hi Word If $iIDFrom = $li_FolderList And $iCode = $LBN_DBLCLK Then If GUICtrlRead($li_FolderList) Then ShellExecute(GUICtrlRead($li_FolderList)) EndIf Return $GUI_RUNDEFMSG EndFunc #endregion windows messages #endregion - Document