Jump to content
Sign in to follow this  
crashdemons

Another desktop positions restore script

Recommended Posts

crashdemons

Posted Image

Posted Image

Background

My desktop icons shift around often when I extend my screen or connect a higher resolution monitor to my laptop, or when a game crashes in an awkward resolution.

Recently I've not been having very much luck with programs and scripts that save desktop icon positions. I know there are various examples on this forum - but I've been frustrated by them as well as other options (eg: an outdated layout.dll shell extension)

For the record, I use Windows 7 64-bit ; I haven't tested this on anything else, but that was probably part of the problem. From some research it appears desktop positions can be saved in one of several different registry keys; older programs may not be searching for them all.

So, I decided to write my own crappy program that *did* search multiple locations for position settings.

TL;DR

Made a program to save desktop icon positions; checks for multiple settings before attempting.

Sauce

Anyway, here's my badly-informed bug-ridden spaghetti code that does what I need:

Note: See slightly cleaned-up code in a reply below!

#RequireAdmin
#include <GUIConstantsEx.au3>
#include <EditConstants.au3>
#include <WindowsConstants.au3>
#include <StaticConstants.au3>
#include <Array.au3>
Global $results[11];elements are array[5]= 0:$display_name 1:$bag_key 2:$bag 3:$valueName 4:$valueDisplayName
Global $ctrls[11][5]

Global $selected = Int(IniRead("itempos.ini", "settings", "selected", -1))
Global $uiOps = GUICreate("Desktop Position Options", 350 + 20, 100)
Global $txSel = GUICtrlCreateInput("Not Selected", 0, 0, 350, 20, $ES_READONLY)
Global $btSel = GUICtrlCreateButton("...", 350, 0, 20, 20)
Global $btSav = GUICtrlCreateButton("Save", 0, 20, 350 + 20, 40)
Global $btRes = GUICtrlCreateButton("Restore", 0, 60, 350 + 20, 40)
uiResetOptions()
Global $uiSel, $btRef
Local $hadSettings = load()
uiPopulate($results, $ctrls, $uiSel, $btRef, (Not $hadSettings));refresh if didn't cache settings
GUISetState(@SW_SHOW, $uiOps)
If (Not $hadSettings) Or $selected < 1 Then
    GUISetState(@SW_SHOW, $uiSel)
    WinActivate($uiSel)
Else
    GUISetState(@SW_HIDE, $uiSel)
    WinActivate($uiOps)
EndIf
;------------------------------------



While 1
    $amsg = GUIGetMsg(1)
    $msg = $amsg[0]
    Switch $msg
        Case $GUI_EVENT_CLOSE
            If $amsg[1] = $uiOps Then Quit()
            GUISetState(@SW_HIDE, $uiSel)
            WinActivate($uiOps)
        Case $btRef
            uiPopulate($results, $ctrls, $uiSel, $btRef)
            ContinueCase
        Case $btSel
            GUISetState(@SW_SHOW, $uiSel)
            WinActivate($uiSel)
        Case $btSav
            save()
            uiResetOptions()
        Case $btRes
            restore()
            uiResetOptions()
        Case $ctrls[0][0]
            MsgBox(0, "Position Information Locations", "This window lists system icon position settings" & @CRLF & "This selection may help if restoring settings does not work. If you do not know what to select, try `Current User`.  ")
    EndSwitch
    For $n = 1 To 10
        If $msg = $ctrls[$n][0] And $ctrls[$n][0] <> 0 Then
            uiSelect($n)
            ExitLoop
        EndIf
    Next
WEnd


;------------------------

Func load()
    Global $selected
    Global $results

    Local $hadSettings = False
    For $i = 0 To 10
        Local $entry[5]
        If IniRead("itempos.ini", "cache", $i, "") = "array" Then
            For $j = 0 To 4
                $entry[$j] = IniRead("itempos.ini", "cache", $i & '_' & $j, "")
            Next
            $results[$i] = $entry
            $hadSettings = True
        Else
            $results[$i] = IniRead("itempos.ini", "cache", $i, "")
        EndIf
    Next

    Local $n = Int(IniRead("itempos.ini", "settings", "selected", -1))
    If Not $hadSettings Then $n = -1
    uiSelect($n)

    Return $hadSettings
EndFunc   ;==>load

Func Quit()
    IniWrite("itempos.ini", "settings", "selected", $selected)
    For $i = 0 To 10
        Local $entry = $results[$i]
        If IsArray($entry) Then
            IniWrite("itempos.ini", "cache", $i, "array")
            For $j = 0 To 4
                IniWrite("itempos.ini", "cache", $i & '_' & $j, $entry[$j])
            Next
        Else
            IniWrite("itempos.ini", "cache", $i, $entry)
        EndIf
    Next
    Exit
EndFunc   ;==>quit


Func uiResetOptions()
    If $selected > 0 Then
        GUICtrlSetState($btSav, $GUI_ENABLE)
        If isSaved() Then
            GUICtrlSetState($btRes, $GUI_ENABLE)
        Else
            GUICtrlSetState($btRes, $GUI_DISABLE)
        EndIf
    Else
        GUICtrlSetState($btSav, $GUI_DISABLE)
        GUICtrlSetState($btRes, $GUI_DISABLE)
    EndIf
EndFunc   ;==>uiResetOptions

Func isSaved()
    Local $entry = $results[$selected]
    If Not IsArray($entry) Then Return False
    Return StringLen(IniRead("itempos.ini", safename($entry[0] & '-' & $entry[2] & '-' & $entry[4]), safename($entry[3]), "")) > 0
EndFunc   ;==>isSaved


Func save()
    GUICtrlSetState($btSav, $GUI_DISABLE)
    GUICtrlSetState($btRes, $GUI_DISABLE)
    WinActivate("Program Manager")
    Sleep(250)
    Send("{F5}")
    Sleep(1000)
    WinActivate($uiOps)

    Local $entry = $results[$selected]
    Local $nameSafe = safename($entry[0] & '-' & $entry[2] & '-' & $entry[4])
    Local $bag_key = $entry[1]
    Local $valueName = $entry[3]
    Local $valueNameSafe = safename($valueName)
    Local $value = RegRead($bag_key, $valueName)
    ConsoleWrite("Saving to " & $nameSafe & @CRLF)

    IniWrite("itempos.ini", $nameSafe, $valueNameSafe, $value)
EndFunc   ;==>save

Func restore()
    Local $entry = $results[$selected]
    Local $nameSafe = safename($entry[0] & '-' & $entry[2] & '-' & $entry[4])
    Local $bag_key = $entry[1]
    Local $valueName = $entry[3]
    Local $valueNameSafe = safename($valueName)
    Local $value = IniRead("itempos.ini", $nameSafe, $valueNameSafe, "")
    ConsoleWrite("Restoring from " & $nameSafe & @CRLF)

    If StringLen($value) = 0 Then Return MsgBox(0, 'Restore Error', "No data is available for this entry to be restored.")

    ProcessKill('explorer.exe')
    ProcessWaitClose('explorer.exe')
    RegWrite($bag_key, $valueName, "REG_BINARY", Binary($value))
    Run('explorer.exe')
EndFunc   ;==>restore

;--------------------------------------------------

Func uiSelect($n)
    Global $selected
    Global $results
    $selected = $n

    Local $entry = ""
    If $selected > 0 Then $entry = $results[$n]

    If IsArray($entry) Then
        GUICtrlSetData($txSel, $entry[0] & '-' & $entry[2] & '-' & $entry[4])
        If IsHWnd($uiSel) Then GUISetState(@SW_HIDE, $uiSel)
        WinActivate($uiOps)
        uiResetOptions()
        Return True
    Else
        GUICtrlSetData($txSel, "Nothing Selected")
        uiResetOptions()
        If IsHWnd($uiSel) Then GUISetState(@SW_SHOW, $uiSel)
        WinActivate($uiSel)
    EndIf
    Return False
EndFunc   ;==>uiSelect

Func uiPopulate(ByRef $results, ByRef $ctrls, ByRef $ui, ByRef $button, $doRefresh = True)
    ;results and ctrls must have the same UBound.
    ProgressOn("Refreshing...", "Refreshing...")
    ProgressSet(1, "Cleaning up...")
    Sleep(250)

    Local $x = UBound($ctrls) - 1

    GUISwitch($ui)
    GUICtrlDelete($button)
    For $n = 0 To $x
        For $i = 0 To 3
            If $ctrls[$n][$i] Then GUICtrlDelete($ctrls[$n][$i])
        Next
    Next
    If IsHWnd($ui) Then GUIDelete($ui)

    If $doRefresh Then
        For $i = 0 To UBound($results) - 1
            $results[$i] = ''
        Next
        ProgressSet(5, "Finding folder information sources...")
        searchhive($results)
    EndIf
    ProgressSet(95, "Creating User Interface...")
    Sleep(250)


    Local $count = 0
    For $n = 1 To $x
        Local $y = ($n - 1) * 20
        If IsArray($results[$n]) Then $count += 1
    Next

    $ui = GUICreate("Select system setting to use...", 450, 20 * ($count + 2) + 10)
    $ctrls[0][0] = GUICtrlCreateButton("??", 0, 0, 20, 20)
    $ctrls[0][1] = GUICtrlCreateLabel("Profile", 020, 5, 250, 20)
    $ctrls[0][2] = GUICtrlCreateLabel("Bag", 270, 5, 050, 20)
    $ctrls[0][3] = GUICtrlCreateLabel("ItemPos", 320, 5, 150, 20)
    $ctrls[0][4] = GUICtrlCreateLabel("-----------------------------------", 0, 20, 450, 5, $SS_ETCHEDHORZ)


    $count = 0
    For $n = 1 To $x
        Local $y = $n * 20 + 5
        Local $entry = $results[$n]
        If IsArray($entry) Then
            $count += 1
            $ctrls[$n][0] = GUICtrlCreateButton($count & '.', 0, $y, 20, 20)
            $y += 5
            $ctrls[$n][1] = GUICtrlCreateLabel($entry[0], 020, $y, 250, 20)
            $ctrls[$n][2] = GUICtrlCreateLabel($entry[2], 270, $y, 050, 20)
            $ctrls[$n][3] = GUICtrlCreateLabel($entry[4], 320, $y, 150, 20)
        EndIf
    Next
    $ctrls[$x][4] = GUICtrlCreateButton("Refresh", 0, 20 * ($count + 1) + 10, 450, 20)
    $button = $ctrls[$x][4]
    GUISwitch($ui)

    ProgressSet(100, "Showing off...")
    Sleep(250)
    ProgressOff()
    Return $ui
EndFunc   ;==>uiPopulate
;--------------------------------------------------------------------
Func searchhive(ByRef $results)
    ;ConsoleWrite('Current'&@CRLF)
    ProgressInitial(5)
    searchuser($results, 'HKEY_CURRENT_USER', 'Current User')
    ProgressSet(25)
    For $i = 1 To 9999
        Local $u = RegEnumKey("HKEY_USERS\", $i)
        If @error <> 0 Then ExitLoop
        ;ConsoleWrite($u&@CRLF)
        searchuser($results, "HKEY_USERS\" & $u, $u)
        ProgressSet(25 + $i * 10)
    Next
EndFunc   ;==>searchhive
Func searchuser(ByRef $results, $user_key, $display_name)
    Local $software_key[2] = ["Software\Microsoft\Windows", "Software\Classes\Local Settings\Software\Microsoft\Windows"]
    Local $shell_key[2] = ["Shell", "ShellNoRoam"]
    Local $name_suffix

    For $sw In $software_key
        $name_suffix = ""
        If StringInStr($sw, "Local") Then $name_suffix = "L"
        For $shell In $shell_key
            If StringInStr($shell, "NoRoam") Then $name_suffix &= "NR"
            Local $bags_key = $user_key & "\" & $sw & "\" & $shell & "\Bags"
            For $i = 1 To 9999
                ProgressIncrement(0.01)
                Local $bag = RegEnumKey($bags_key, $i)
                If @error <> 0 Then ExitLoop
                If StringLen($name_suffix) > 0 Then $name_suffix = "(" & $name_suffix & ")"
                searchbag($results, $bags_key, $bag, $display_name & $name_suffix)
            Next
        Next
    Next
EndFunc   ;==>searchuser
Func searchbag(ByRef $results, $bags_key, $bag, $display_name)
    Local $bag_key = $bags_key & '\' & $bag & '\Shell'
    For $i = 1 To 9999
        Local $value = RegEnumVal($bag_key, $i)
        If @error <> 0 Then ExitLoop
        If StringInStr($value, 'ItemPos') Then
            Local $entry[5] = [$display_name, $bag_key, $bag, $value, StringTrimLeft($value, 7)]
            _Array_Fixed_Push($results, $entry)
        EndIf
    Next
    $bag_key = $bags_key & '\' & $bag & '\Desktop'
    For $i = 1 To 9999
        Local $value = RegEnumVal($bag_key, $i)
        If @error <> 0 Then ExitLoop
        ;ConsoleWrite($value&@CRLF)
        If StringInStr($value, 'ItemPos') Then
            Local $entry[5] = [$display_name, $bag_key, $bag, $value, StringTrimLeft($value, 7)]
            _Array_Fixed_Push($results, $entry)
        EndIf
    Next
EndFunc   ;==>searchbag
Func _Array_Fixed_Push(ByRef $array, $value);adds an item, overwriting the oldest item | NOTE: Edited from original intent, see comments
    Local $x = UBound($array) - 1
    If $array[0] = $x Then Return False; *** decided later that overwriting sucked for systems with many profiles.
    Local $i = Mod($array[0], $x); values from 0 to x-1
    Local $n = $i + 1;(0 to x-1)+1 = 1 to x
    $array[0] = $n; this is also the nonadjusted index for the next item :)
    $array[$n] = $value
EndFunc   ;==>_Array_Fixed_Push


Func ProgressInitial($n = 0)
    Global $ProgressIncrement
    $ProgressIncrement = $n
    ProgressSet($n)
EndFunc   ;==>ProgressInitial
Func ProgressIncrement($n = 1)
    Global $ProgressIncrement
    $ProgressIncrement += $n
    ProgressSet($ProgressIncrement)
EndFunc   ;==>ProgressIncrement

Func safename($s)
    Return StringRegExpReplace($s, "[^a-zA-Z0-9_\-]", "_")
EndFunc   ;==>safename


Func ProcessKill($p); I should probably credit someone for this function
    $Kernel32 = DllOpen("kernel32.dll")
    $hproc = DllCall($Kernel32, 'int', 'OpenProcess', 'int', 0x1F0FFF, 'int', True, 'int', ProcessExists($p))
    DllCall($Kernel32, "int", "TerminateProcess", "int", $hproc[0], "dword", 1)
    DllClose($Kernel32)
EndFunc   ;==>ProcessKill

Other Notes

This only scans for settings/prompts you on the first run, it should keep that information for the next run. It also limits you to using one of the first 10 profiles the scan results in.

Sorry about having to kill/restart explorer when restoring positions - nothing else worked for me.

Clarification for the ItemPos text: from what I've read, it is <Resolution>(<Monitor>). I'm unsure how settings behave when you have icons dragged from one screen to the next and restore one of the screens.

Edited by crashdemons

My Projects - WindowDarken (Darken except the active window) Yahsmosis Chat Client (Discontinued) StarShooter Game (Red alert! All hands to battlestations!) YMSG Protocol Support (Discontinued) Circular Keyboard and OSK example. (aka Iris KB) Target Screensaver Drive Toolbar Thingy Rollup Pro (Minimize-to-Titlebar & More!) 2D Launcher physics example Ascii Screenshot AutoIt3 Quine Example ("Is a Quine" is a Quine.) USB Lock (Another system keydrive - with a toast.)

Share this post


Link to post
Share on other sites
crashdemons

Here is a ZIP for the compiled executables (x86 and x64). DesktopPos.zip

Note: I encountered issues trying to run the script or compiled versions as x86 under a 64-bit platform - please choose executable and interpreter platform appropriately.

Specifically, launching explorer with Run() does not seem to have the desired effect from a 32-bit executable ran on a 64-bit OS. There could be Registry differences also that effect this program's function.

Edited by crashdemons

My Projects - WindowDarken (Darken except the active window) Yahsmosis Chat Client (Discontinued) StarShooter Game (Red alert! All hands to battlestations!) YMSG Protocol Support (Discontinued) Circular Keyboard and OSK example. (aka Iris KB) Target Screensaver Drive Toolbar Thingy Rollup Pro (Minimize-to-Titlebar & More!) 2D Launcher physics example Ascii Screenshot AutoIt3 Quine Example ("Is a Quine" is a Quine.) USB Lock (Another system keydrive - with a toast.)

Share this post


Link to post
Share on other sites
crashdemons

Did some spring-cleaning on the source code:

#RequireAdmin
#region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_UseUpx=n
#AutoIt3Wrapper_AU3Check_Stop_OnWarning=y
#AutoIt3Wrapper_AU3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
#endregion ;**** Directives created by AutoIt3Wrapper_GUI ****
#include <GUIConstantsEx.au3>
#include <EditConstants.au3>
#include <WindowsConstants.au3>
#include <StaticConstants.au3>
#include <Array.au3>


Global Enum $UIO_HWND = 0, $UIO_TEXT, $UIO_SELECT, $UIO_SAVE, $UIO_RESTORE
Global Enum $UIS_HWND = 0, $UIS_HELP, $UIS_REFRESH = 6, $UIS_DYNAMIC = 7, $UIS_DYNCTRLS = 4, $UIS_DYNBUTTONMOD = Mod($UIS_DYNAMIC, $UIS_DYNCTRLS)


Global $ProgressIncrement

Global $bag_entries[11];elements are array[5]= 0:$display_name 1:$bag_key 2:$bag 3:$valueName 4:$valueDisplayName
Global $selected = -1


Global $uiInfo_Ops = uiCreateOptions()
uiOptions_Reset($bag_entries, $selected, $uiInfo_Ops)
Global $uiInfo_Sel[60]
Global $hadSettings = load($uiInfo_Ops, $uiInfo_Sel, $selected, $bag_entries)
uiSelector_Populate($uiInfo_Sel, $bag_entries, Not $hadSettings);refresh if didn't cache settings


GUISetState(@SW_SHOW, $uiInfo_Ops[$UIO_HWND])
If (Not $hadSettings) Or $selected < 1 Then
    GUISetState(@SW_SHOW, $uiInfo_Sel[$UIS_HWND])
    WinActivate($uiInfo_Sel[$UIS_HWND])
Else
    GUISetState(@SW_HIDE, $uiInfo_Sel[$UIS_HWND])
    WinActivate($uiInfo_Ops[$UIO_HWND])
EndIf


;------------------------------------


Global $amsg, $msg
While 1
    $amsg = GUIGetMsg(1)
    Switch $amsg[0]
        Case $GUI_EVENT_CLOSE
            If $amsg[1] = $uiInfo_Ops[$UIO_HWND] Then Quit($selected, $bag_entries)
            GUISetState(@SW_HIDE, $uiInfo_Sel[$UIS_HWND])
            WinActivate($uiInfo_Ops[$UIO_HWND])
        Case $uiInfo_Sel[$UIS_REFRESH]
            uiSelector_Populate($uiInfo_Sel, $bag_entries)
            ContinueCase
        Case $uiInfo_Ops[$UIO_SELECT]
            GUISetState(@SW_SHOW, $uiInfo_Sel[$UIS_HWND])
            WinActivate($uiInfo_Sel[$UIS_HWND])
        Case $uiInfo_Ops[$UIO_SAVE]
            uiOptions_Save($uiInfo_Ops, $bag_entries, $selected)
            uiOptions_Reset($bag_entries, $selected, $uiInfo_Ops)
        Case $uiInfo_Ops[$UIO_RESTORE]
            uiOptions_Restore($uiInfo_Ops, $bag_entries, $selected)
            uiOptions_Reset($bag_entries, $selected, $uiInfo_Ops)
        Case $uiInfo_Sel[$UIS_HELP]
            MsgBox(0, "Position Information Locations", "This window lists system icon position settings" & @CRLF & "This selection may help if restoring settings does not work. If you do not know what to select, try `Current User`.  ")
    EndSwitch
    For $i = $UIS_DYNAMIC To UBound($uiInfo_Sel) - 1
        If $amsg[0] = $uiInfo_Sel[$i] And $uiInfo_Sel[$i] <> 0 And Mod($i, $UIS_DYNCTRLS) = $UIS_DYNBUTTONMOD Then
            uiSelector_Submit(Int(GUICtrlRead($uiInfo_Sel[$i])), $uiInfo_Ops, $uiInfo_Sel, $selected, $bag_entries); the displayed count number will also be the 1-based index of the item, since they're inserted sequentially without gaps.
            ExitLoop
        EndIf
    Next
WEnd


;------------------------

Func load(ByRef $uiInfo_Options, ByRef $uiInfo_Selector, ByRef $iSelected_out, ByRef $bags)

    Local $hadSettings = False
    For $i = 0 To UBound($bags)-1
        Local $entry[5]
        If IniRead("itempos.ini", "cache", $i, "") = "array" Then
            For $j = 0 To 4
                $entry[$j] = IniRead("itempos.ini", "cache", $i & '_' & $j, "")
            Next
            $bags[$i] = $entry
            $hadSettings = True
        Else
            $bags[$i] = IniRead("itempos.ini", "cache", $i, "")
        EndIf
    Next

    Local $n = Int(IniRead("itempos.ini", "settings", "selected", -1))
    If Not $hadSettings Then $n = -1
    uiSelector_Submit($n, $uiInfo_Options, $uiInfo_Selector, $iSelected_out, $bags)

    Return $hadSettings
EndFunc   ;==>load

Func Quit(ByRef $iSelected_in, ByRef $bags_in)
    IniWrite("itempos.ini", "settings", "selected", $iSelected_in)
    For $i = 0 To UBound($bags_in)-1
        Local $entry = $bags_in[$i]
        If IsArray($entry) Then
            IniWrite("itempos.ini", "cache", $i, "array")
            For $j = 0 To 4
                IniWrite("itempos.ini", "cache", $i & '_' & $j, $entry[$j])
            Next
        Else
            IniWrite("itempos.ini", "cache", $i, $entry)
        EndIf
    Next
    Exit
EndFunc   ;==>Quit


Func isSaved(ByRef $iSelected, ByRef $bags_in)
    Local $entry = $bags_in[$iSelected]
    If Not IsArray($entry) Then Return False
    Return StringLen(IniRead("itempos.ini", safename($entry[0] & '-' & $entry[2]), safename($entry[3]), "")) > 0
EndFunc   ;==>isSaved


Func uiOptions_Save(ByRef $uiInfo_Options, ByRef $bags, ByRef $iSelected)
    GUICtrlSetState($uiInfo_Options[$UIO_SAVE], $GUI_DISABLE)
    GUICtrlSetState($uiInfo_Options[$UIO_RESTORE], $GUI_DISABLE)
    WinActivate("Program Manager")
    Sleep(250)
    Send("{F5}")
    Sleep(1000)
    WinActivate($uiInfo_Options[$UIO_HWND])

    Local $entry = $bags[$iSelected]
    Local $nameSafe = safename($entry[0] & '-' & $entry[2])
    Local $bag_key = $entry[1]
    Local $valueName = $entry[3]
    Local $valueNameSafe = safename($valueName)
    Local $value = RegRead($bag_key, $valueName)
    ConsoleWrite("Saving to " & $nameSafe & @CRLF)

    IniWrite("itempos.ini", $nameSafe, $valueNameSafe, $value)
EndFunc   ;==>uiOptions_Save

Func uiOptions_Restore(ByRef $uiInfo_Options, ByRef $bags, ByRef $iSelected)
    GUICtrlSetState($uiInfo_Options[$UIO_SAVE], $GUI_DISABLE)
    GUICtrlSetState($uiInfo_Options[$UIO_RESTORE], $GUI_DISABLE)
    Local $entry = $bags[$iSelected]
    Local $nameSafe = safename($entry[0] & '-' & $entry[2])
    Local $bag_key = $entry[1]
    Local $valueName = $entry[3]
    Local $valueNameSafe = safename($valueName)
    Local $value = IniRead("itempos.ini", $nameSafe, $valueNameSafe, "")
    ConsoleWrite("Restoring from " & $nameSafe & @CRLF)

    If StringLen($value) = 0 Then Return MsgBox(0, 'Restore Error', "No data is available for this entry to be restored.")

    ProcessKill('explorer.exe')
    ProcessWaitClose('explorer.exe')
    RegWrite($bag_key, $valueName, "REG_BINARY", Binary($value))
    Run('explorer.exe')
EndFunc   ;==>restore

;--------------------------------------------------

Func uiCreateOptions()
    Local $uiInfo[5]
    $uiInfo[0] = GUICreate("Desktop Position Options", 350 + 20, 100)
    $uiInfo[1] = GUICtrlCreateInput("Not Selected", 0, 0, 350, 20, $ES_READONLY)
    $uiInfo[2] = GUICtrlCreateButton("...", 350, 0, 20, 20)
    $uiInfo[3] = GUICtrlCreateButton("Save", 0, 20, 350 + 20, 40)
    $uiInfo[4] = GUICtrlCreateButton("Restore", 0, 60, 350 + 20, 40)
    Return $uiInfo
EndFunc   ;==>uiCreateOptions


Func uiOptions_Reset(ByRef $bags, ByRef $iSelected_in, ByRef $uiInfo_Options)
    If $iSelected_in > 0 Then
        GUICtrlSetState($uiInfo_Options[3], $GUI_ENABLE)
        If isSaved($iSelected_in, $bags) Then
            GUICtrlSetState($uiInfo_Options[4], $GUI_ENABLE)
        Else
            GUICtrlSetState($uiInfo_Options[4], $GUI_DISABLE)
        EndIf
    Else
        GUICtrlSetState($uiInfo_Options[3], $GUI_DISABLE)
        GUICtrlSetState($uiInfo_Options[4], $GUI_DISABLE)
    EndIf
EndFunc   ;==>uiOptions_Reset



Func uiSelector_Submit($n, ByRef $uiInfo_Options, ByRef $uiInfo_Selector, ByRef $iSelected, ByRef $bags_in)
    $iSelected = $n

    Local $entry = ""
    If $iSelected > 0 Then $entry = $bags_in[$n]

    If IsArray($entry) Then
        GUICtrlSetData($uiInfo_Options[1], $entry[0] & '-' & $entry[2] & '-' & $entry[4])
        If IsHWnd($uiInfo_Selector[0]) Then GUISetState(@SW_HIDE, $uiInfo_Selector[0])
        WinActivate($uiInfo_Options[$UIO_HWND])
        uiOptions_Reset($bags_in, $iSelected, $uiInfo_Options)
        Return True
    Else
        GUICtrlSetData($uiInfo_Options[1], "Nothing Selected")
        uiOptions_Reset($bags_in, $iSelected, $uiInfo_Options)
        If IsHWnd($uiInfo_Selector[0]) Then
            GUISetState(@SW_SHOW, $uiInfo_Selector[0])
            WinActivate($uiInfo_Selector[0])
        EndIf
    EndIf
    Return False
EndFunc   ;==>uiSelector_Submit

Func uiSelector_Populate(ByRef $uiInfo, ByRef $bags, $doRefresh = True);; NOTE: uiInfo must be a 60-element array (ah hell, lets just give ourselves room to develop the UI a bit, the max dynamic controls will be 4*10 at this time)
    ProgressOn("Refreshing...", "Refreshing...")
    Local $maxCtrl = UBound($uiInfo) - 1
    Local $maxBags = UBound($bags) - 1

    ;to produce a UI without alot of extra Globals, we need to dynamically create our UI. So we need to discard of the old one.  Sizing is also much easier this way.
    ProgressSet(1, "Cleaning up...")
    Sleep(250)
    For $n = 1 To $maxCtrl
        If $uiInfo[$n] Then GUICtrlDelete($uiInfo[$n])
    Next
    If IsHWnd($uiInfo[0]) Then GUIDelete($uiInfo[0])

    ;reset data
    If $doRefresh Then
        For $i = 0 To $maxBags
            $bags[$i] = ''
        Next
        ProgressSet(5, "Finding folder information sources...")
        searchhive($bags)
    EndIf
    ProgressSet(95, "Creating User Interface...")
    Sleep(250)

    ;get the count of dynamic entries so that we can determine UI dimensions.
    Local $count = 0
    For $n = 1 To $maxBags
        If IsArray($bags[$n]) Then $count += 1
    Next

    ;creating our UI and static elements first.
    $uiInfo[0] = GUICreate("Select system setting to use...", 450, 20 * ($count + 2) + 10)
    $uiInfo[1] = GUICtrlCreateButton("??", 0, 0, 20, 20)
    $uiInfo[2] = GUICtrlCreateLabel("Profile", 020, 5, 250, 20)
    $uiInfo[3] = GUICtrlCreateLabel("Bag", 270, 5, 050, 20)
    $uiInfo[4] = GUICtrlCreateLabel("ItemPos", 320, 5, 150, 20)
    $uiInfo[5] = GUICtrlCreateLabel("-----------------------------------", 0, 20, 450, 5, $SS_ETCHEDHORZ)
    $uiInfo[6] = GUICtrlCreateButton("Refresh", 0, 20 * ($count + 1) + 10, 450, 20)

    ;  creating dynamic elements
    $count = 0
    For $n = 1 To $maxBags
        Local $entry = $bags[$n]
        If IsArray($entry) Then
            Local $y = ($count + 1) * 20 + 5;back-to-back rows of 20px with an initial offset of 5
            $count += 1
            $uiInfo[07 + ($count - 1) * 4] = GUICtrlCreateButton($count & '.', 0, $y, 20, 20)
            $y += 5;offset labels slightly so that they look centered on the buttons instead of top-aligned.
            $uiInfo[08 + ($count - 1) * 4] = GUICtrlCreateLabel($entry[0], 020, $y, 250, 20)
            $uiInfo[09 + ($count - 1) * 4] = GUICtrlCreateLabel($entry[2], 270, $y, 050, 20)
            $uiInfo[10 + ($count - 1) * 4] = GUICtrlCreateLabel($entry[4], 320, $y, 150, 20)
        EndIf
    Next

    ProgressSet(100, "Showing off...")
    Sleep(250)
    GUISwitch($uiInfo[0])
    ProgressOff()
    Return $uiInfo
EndFunc   ;==>uiSelector_Populate
;--------------------------------------------------------------------
Func searchhive(ByRef $results)
    ;ConsoleWrite('Current'&@CRLF)
    ProgressInitial(5)
    searchuser($results, 'HKEY_CURRENT_USER', 'Current User')
    ProgressSet(25)
    For $i = 1 To 9999; this looks bad, but substituting a While loop creates unnecessary lines for an index variable, and introduces an exhaustive search (limited by Signed Int maximum)
        Local $u = RegEnumKey("HKEY_USERS\", $i)
        If @error <> 0 Then ExitLoop
        ;ConsoleWrite($u&@CRLF)
        searchuser($results, "HKEY_USERS\" & $u, $u)
        ProgressSet(25 + $i * 10)
    Next
EndFunc   ;==>searchhive
Func searchuser(ByRef $results, $user_key, $display_name)
    Local $software_key[2] = ["Software\Microsoft\Windows", "Software\Classes\Local Settings\Software\Microsoft\Windows"]
    Local $shell_key[2] = ["Shell", "ShellNoRoam"]
    Local $name_suffix

    For $sw In $software_key
        $name_suffix = ""
        If StringInStr($sw, "Local") Then $name_suffix = "L"
        For $shell In $shell_key
            If StringInStr($shell, "NoRoam") Then $name_suffix &= "NR"
            Local $bags_key = $user_key & "\" & $sw & "\" & $shell & "\Bags"
            For $i = 1 To 9999; this looks bad, but substituting a While loop creates unnecessary lines for an index variable, and introduces an exhaustive search (limited by Signed Int maximum)
                ProgressIncrement(0.01)
                Local $bag = RegEnumKey($bags_key, $i)
                If @error <> 0 Then ExitLoop
                If StringLen($name_suffix) > 0 Then $name_suffix = "(" & $name_suffix & ")"
                searchbag($results, $bags_key, $bag, $display_name & $name_suffix)
            Next
        Next
    Next
EndFunc   ;==>searchuser
Func searchbag(ByRef $results, $bags_key, $bag, $display_name)
    Local $bag_key = $bags_key & '\' & $bag & '\Shell'
    Local $value
    For $i = 1 To 9999; this looks bad, but substituting a While loop creates unnecessary lines for an index variable, and introduces an exhaustive search (limited by Signed Int maximum)
        $value = RegEnumVal($bag_key, $i)
        If @error <> 0 Then ExitLoop
        If StringInStr($value, 'ItemPos') Then
            Local $entry[5] = [$display_name, $bag_key, $bag, $value, StringTrimLeft($value, 7)]
            _ArrayFixed_Add($results, $entry)
        EndIf
    Next
    $bag_key = $bags_key & '\' & $bag & '\Desktop'
    For $i = 1 To 9999; this looks bad, but substituting a While loop creates unnecessary lines for an index variable, and introduces an exhaustive search (limited by Signed Int maximum)
        $value = RegEnumVal($bag_key, $i)
        If @error <> 0 Then ExitLoop
        ;ConsoleWrite($value&@CRLF)
        If StringInStr($value, 'ItemPos') Then
            Local $entry[5] = [$display_name, $bag_key, $bag, $value, StringTrimLeft($value, 7)]
            _ArrayFixed_Add($results, $entry)
        EndIf
    Next
EndFunc   ;==>searchbag
Func _ArrayFixed_Add(ByRef $array, $value);adds an item, overwriting the oldest item | NOTE: Edited from original intent, see comments
    Local $x = UBound($array) - 1
    If $array[0] = $x Then Return False; *** decided later that overwriting sucked for systems with many profiles.
    Local $i = Mod($array[0], $x); values from 0 to x-1
    Local $n = $i + 1;(0 to x-1)+1 = 1 to x
    $array[0] = $n; this is also the nonadjusted index for the next item :)
    $array[$n] = $value
EndFunc   ;==>_Array_Fixed_Push


Func ProgressInitial($n = 0)
    $ProgressIncrement = $n
    ProgressSet($n)
EndFunc   ;==>ProgressInitial
Func ProgressIncrement($n = 1)
    $ProgressIncrement += $n
    ProgressSet($ProgressIncrement)
EndFunc   ;==>ProgressIncrement

Func safename($s)
    Return StringRegExpReplace($s, "[^a-zA-Z0-9_\-]", "_")
EndFunc   ;==>safename


Func ProcessKill($p); I should probably credit someone for this function
    Local $Kernel32 = DllOpen("kernel32.dll")
    Local $hproc = DllCall($Kernel32, 'int', 'OpenProcess', 'int', 0x1F0FFF, 'int', True, 'int', ProcessExists($p))
    DllCall($Kernel32, "int", "TerminateProcess", "int", $hproc[0], "dword", 1)
    DllClose($Kernel32)
EndFunc   ;==>ProcessKill

UI Arrays were absolutely necessary to maintain conciseness while eliminating Global references.

Edited by crashdemons

My Projects - WindowDarken (Darken except the active window) Yahsmosis Chat Client (Discontinued) StarShooter Game (Red alert! All hands to battlestations!) YMSG Protocol Support (Discontinued) Circular Keyboard and OSK example. (aka Iris KB) Target Screensaver Drive Toolbar Thingy Rollup Pro (Minimize-to-Titlebar & More!) 2D Launcher physics example Ascii Screenshot AutoIt3 Quine Example ("Is a Quine" is a Quine.) USB Lock (Another system keydrive - with a toast.)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Similar Content

    • mar3011
      By mar3011
      Hey, I have a problem I tried to look for it but it didn't solve the problem, I can't add an icon to the exe, I already know there were such topics I tried to all add exclusion C: \ Users \ Marcin \ AppData \ Local \ AutoIt v3 \ aut472.tm.exe to antivirus but after compilation, the name of the file changes, I uninstalled the anti-virus, but it didn't works, except that when I add the example icons from AutoIT it works, I downloaded icons using Firefox Developer Edition also don't works, just the downloaded graphics don't works also. Is there any solution to this problem?  
    • Jefrey
      By Jefrey
      Needed a way to store global temporary & permanent information and came up with this.
      This is inspired by NodeJS's store and store2 packages, as well as W3 specs' localStorage and sessionStorage, offering multiple ways of usage.
      This is not related to any browser's storage, nor will allow you to access or modify browsers storage - although this is possible and not a hard task, this is not what this UDF is intended to do.
      This UDF offers functions for temporary storage (that gets cleaned up once the application is shutdown) that is kept on memory using ScriptingDictionary, as well as for permanent storage, that is saved on the harddisk as an encrypted file.
      sessionStorage (temporary storage)
      It's useful to keep application state and temporary settings accessible by any part of your script (although it could also be done with a global variable, I still prefer this method).
      You have multiple ways, at your choice, to:
      ; add or modify a key sessionStorage("foo", "bar") store("foo", "bar") sessionStorage_set("foo", "bar") sessionStorage_setItem("foo", "bar") ; read a key (returns false if key does not exist) $read = sessionStorage("foo") $read = store("foo") $read = sessionStorage_get("foo") $read = sessionStorage_getItem("foo") ; delete a key sessionStorage_remove("foo") ; delete all keys sessionStorage_clear() sessionStorage_clearAll() localStorage (permanent storage)
      It's useful to store user-defined settings.
      ; initialize ; this is optional, but allows you to control ; how things are going to be saved localStorage_startup([file where you want the settings to be saved], [crypt password]) ; by default, if not supplied, if supplied the "Default" keyword (or if you dont initialize), ; the file will be a random-named file (based on @ScriptFullPath) at user's %APPDATA% ; and the password will also be based on @ScriptFullPath ; you can set only the crypt password if you want: ; localStorage_startup(Default, "mypassword") ; the usage is the same as sessionStorage ; add or modify a key localStorage("foo", "bar") store2("foo", "bar") ; notice the '2' localStorage_set("foo", "bar") localStorage_setItem("foo", "bar") ; read a key (returns false if key does not exist) $read = localStorage("foo") $read = store2("foo") $read = localStorage_get("foo") $read = localStorage_getItem("foo") ; delete a key localStorage_remove("foo") ; delete all keys localStorage_clear() localStorage_clearAll() Download
    • amimemeami
      By amimemeami
      I have learned how to use TraySetIcon icon and toggle between icons that I added as resources using 
      #AutoIt3Wrapper_Res_Icon_Add=C:\Program Files (x86)\AutoIt3\Icons\au3.ico My current work around is 
      Doit() Func Doit() Local $TestIcon = @ScriptDir&"\Test.ico" Local $ProdIcon = @ScriptDir&"\Prod.ico" Local $Test = "Test" Local $Prod = "Prod" Local $Current = RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\My Program","Location") If $Current = $Prod Then FileCreateShortcut($Test,@DesktopCommonDir&"\TestLink.lnky",Default,Default,"Test Link",$TestIcon) RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\My Program",$Test) Else FileCreateShortcut($Test,@DesktopCommonDir&"\TestLink.lnky",Default,Default,"Test Link",$ProdIcon) RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\My Program",$Prod) EndIf EndFunc I did a bit of quick cutting, from my working program. Basically it creates an link on the desktop, and then deletes it and creates a new one each time it is run. If you where wondering, I made it a .lnky file so that I could add a custom right click menu for it. 
      This example came from a something I am using to switch between prod and test environments, so the actual link created does not launch the script. You can right-click on the link and run the script to change environments. The icon lets me know at a glance which environment I am currently set for. 
       
      What I am trying to figure out is if there is a way to change the icon of the executable of the script only using the resources compiled within that script. What would be nice would be to have a ScriptSetIcon function.
    • natedog102
      By natedog102
      This small UDF helps you save any text to speech to a .wav file. 
      UDF:
      #AutoIt3Wrapper_Au3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w- 4 -w 5 -w 6 -w- 7 #include-once ; #INDEX# ======================================================================================================================= ; Title .........: _TTStoWav() ; AutoIt Version : 3.3.14.2 ; Language ......: English ; Author(s) .....: natedog102 ; Modifiers .....: ; Forum link ....: https://www.autoitscript.com/forum/topic/191573-tts-text-to-speech-to-wav-file-using-sapi/ ; Description ...: TTS to .wav file using SAPI ; =============================================================================================================================== ; #FUNCTION# ==================================================================================================================== ; Name...........: _TTStoWav ; Description ...: TTS to .wav file using SAPI ; Syntax.........: _TTStoWav($sText, $sLocation[, $iRate = 1[, $iVolume = 100]]) ; Parameters ....: $sText - String you want converted to a .wav ; $sLocation - Save location + file name, example: "C:\folder\sample.wav" ; $iRate - TTS speak rate between -10 and 10 ; $iVolume - Volume of the TTS between 0 and 100 ; Return values .: Success - Returns one ; Failure - Returns zero ; Author ........: natedog102 ; Modified.......: ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func _TTStoWav($sText, $sLocation, $iRate = 1, $iVolume = 100) $oFileStream = ObjCreate("SAPI.SpFileStream") If @error Then Return 0 EndIf $oFileStream.Format.Type = 39 $oFileStream.Open($sLocation, 3) $oSpeech = ObjCreate('SAPI.SpVoice') If @error Then Return 0 EndIf $oSpeech.AudioOutputStream = $oFileStream $oSpeech.Rate = $iRate $oSpeech.Volume = $iVolume $oSpeech.Speak($sText, 3) $oSpeech.WaitUntilDone(10000) $oFileStream.Close() Return 1 EndFunc ;==>_TTStoWav And here's example usage:
      _TTStoWav("This is a test", "C:\folder-must-exist\sample2.wav") I have never made a UDF before so I don't know if I coded it correctly or if I followed all the recommended guidelines. Apologies if I haven't.
      DOWNLOAD:
       _TTStoWav.au3
    • Miliardsto
      By Miliardsto
      Hello. How to make GUI restore from tray with slower speed or effect?
×