#include-once ; corz registry functions v0.3.2 ; (c) corz.org 2006->tomorrow! #cs Miscelleneous Registry Comands @Extended values.. 0 = directory (key) 1 = REG_SZ 2 = REG_EXPAND_SZ 3 = REG_BINARY 4 = REG_DWORD 7 = REG_MULTI_SZ Function List.. MakeLongRegPaths() GetContextCommands() KeyIsEmpty() ReturnAllSubkeys() ReturnAllValueNames() ReturnAllPairs() SetExplorerContextMenu SetExplorerDirectoryContextMenu() CopyRegistryTree() #ce ; switch short (i.e "HKCU") registry paths, for "long" (i.e. "HKEY_CURRENT_USER") paths ; (doesn't AutoIt do this automatically yet?).. func MakeLongRegPaths($reg_key) $reg_key = StringReplace($reg_key, "HKCR", "HKEY_CLASSES_ROOT") $reg_key = StringReplace($reg_key, "HKCU", "HKEY_CURRENT_USER") $reg_key = StringReplace($reg_key, "HKU", "HKEY_USERS") $reg_key = StringReplace($reg_key, "HKLM", "HKEY_LOCAL_MACHINE") $reg_key = StringReplace($reg_key, "HKCC", "HKEY_CURRENT_CONFIG") return $reg_key endfunc ; ; GetContextCommands() ; ; return names of the context (right-click) commands ; of a particular file type as an "AutoIt array", that is, ; an array where the first value is the number of real ; values in the array (integer). ; ; $array = GetContextCommands("txtfile") ; func GetContextCommands($file_type) $file_type = "HKEY_CLASSES_ROOT\" & $file_type & "\Shell" local $dirs = "" local $y = 1 while $y local $var = RegEnumKey($file_type, $y) if @error <> 0 then exitloop if @extended = 0 then ; directory $dirs &= $var & "|" endif $y += 1 wend if $dirs <> "" then $dirs = StringTrimRight($dirs, 1) return StringSplit($dirs, "|") endif endfunc ; returns true is a given registry key is empty.. ; ; requires ReturnAllSubkeys() & ReturnAllValueNames() ; func KeyIsEmpty($key) local $reg_test_array_k = ReturnAllSubkeys($key) local $reg_test_array_v = ReturnAllValueNames($key) if $reg_test_array_k[1] = "" and $reg_test_array_v[1] = "" then return 1 endif endfunc ; ReturnAllSubkeys() ; returns all the subkeys of a registry key as an "AutoIt array" of key names.. ; eg. $array = ReturnAllSubkeys("HKCU\SOFTWARE\corz") ; ; requires MakeLongRegPaths($reg_key) ; func ReturnAllSubkeys($key) $key = MakeLongRegPaths($key) local $keys = "" local $x = 1 while $x local $var = RegEnumKey($key, $x) if @error <> 0 then exitloop if $var <> "" then $keys &= $var & "|" $x += 1 wend $keys = StringTrimRight($keys, 1) return StringSplit($keys, "|") endfunc ; ReturnAllValueNames() ; returns all the names of a registry key as an "AutoIt array" of names.. ; eg. $array = ReturnAllValueNames("HKCU\SOFTWARE\corz") ; ; requires MakeLongRegPaths($reg_key) ; func ReturnAllValueNames($key) $key = MakeLongRegPaths($key) local $names = "" local $x = 1 while $x local $var = RegEnumVal($key, $x) if @error <> 0 then exitloop if $var <> "" then $names &= $var & "|" $x += 1 wend ;if $names <> "" then $names = StringTrimRight($names, 1) return StringSplit($names, "|") ;endif endfunc ; ; ReturnAllPairs() ; ; returns all the name/value pairs from a registry key as a ; 2-dimensional "AutoIt array" of name/value pairs, starting at ; array[1][0]. array[0][0] contains the total number of pairs ; returned. Empty registry values can be skipped by passing the ; optional second parameter as true. ; ; ReturnAllPairs("HKCU\SOFTWARE\corz") ; #cs ReturnAllPairs example: ; ; display programs that run at startup for all users.. #include "corzRegistry.au3" $str = "" $foo = ReturnAllPairs("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run") for $i = 1 to $foo[0][0] $str &= "key: " & $foo[$i][0] & " value: " & $foo[$i][1] & " " & @LF next MsgBox (0, "These programs run at startup..", $str) exit ; or the whole lot.. dim $startup_places[4] = _ [ "HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run", _ "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run", _ "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce", _ "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnceEx" ] for $place in $startup_places $foo = ReturnAllPairs($place) for $i = 1 to $foo[0][0] $str &= $foo[$i][0] & " : " & $foo[$i][1] & " " & @LF next next MsgBox (0, "These programs run at startup..", $str) #ce ; Collects every value name and data pair under one registry key into a counted ; 2D array, skipping empties on request. Used to read startup and association ; keys. ; func ReturnAllPairs($key, $skip_empties=false) local $x = 1 local $y = 1 local $pairs[1][2] while $x local $var = RegEnumVal($key, $x) if @error <> 0 then exitloop local $this_value = RegRead($key, $var) if (not $skip_empties) or ($skip_empties and $this_value <> "") then redim $pairs[$y+1][2] $pairs[$y][0] = $var $pairs[$y][1] = $this_value $y += 1 endif $x += 1 wend $pairs[0][0] = $y - 1 return $pairs endfunc ; ; SetExplorerContextMenu ; ; This sets an Explorer context item for an application. It can be either the default ; command for a particular filetype, or else simply another command on the context menu. ; ; Pass the application name explicitly for menu defaults, backup subkeys and ; the uncompiled executable fallback. ; ; Uses KeyIsEmpty() - Also in this collection. ; ; Parameters.. ; ; 1. $app_name Application name (required) ; 2. $ext File Type extension to work with (minus the dot) ; 3. $switch $ON or $OFF, $GUI_CHECKED & $GUI_UNCHECKED, 1 or 4, whatever ; This switch enables or disables the explorer menu item, depending. ; 4. $default True if you wish to set the Explorer default command $ON/$OFF ; 5. $menu_item The string of text that will appear in the Explorer context menu ; Defaults to "Open with " & $app_name, with $app_name as the key ; You can force the key name by putting it after a pipe character.. ; e.g.. "Edit KeyBind Script|Edit" ; 6. $fallback If no file type has been set for this file extension, you can ; specify one here. Will only be used if the file extension ; doesn't already have a type. It will not steal an extension. ; 7. $switches Any switches you would like to place in the command-line ; (they are placed between & , with a space added at either side) ; ; 8. $app_override Sets a different app as the default app. specify the full path to the app. ; Or provide the short name if the app is in the path, e.g. "notepad.exe" ; ; 9. $icon Specify the full string: "C:\path\to\resource.exe,0" ; ; ; You can use Default as any value except the first two. ; ; If there are any issues, the function will set @Error to some non-zero value and return ; a useful message as the return value, which you can use directly. Successful operartions ; also return a message letting you know exactly what happened. ; ; ; Here is an example of setting TWO context commands.. ; ; SetExplorerContextMenu($my_name, "kc", $associate_kc_files, true, "Run The Script", _ ; "KeyBind Commands File", "", @ScriptFullPath, @ScriptFullPath & ",4") ; SetExplorerContextMenu($my_name, "kc", $associate_kc_files, false, "Edit KeyBind Script|Edit", "", "", $user_editor) ; ; ; Note the $associate_kc_files variable. This variable would be set by the ; calling app and is either $ON or $OFF, a simple switch. If this is set to $ON ; and we run the two commands above we setup the context menu. Set that variable ; to $OFF and the entire registry structure will be cleanly removed. ; func SetExplorerContextMenu($app_name, $ext, $switch=default, $default=default, $menu_item=default, _ $fallback=default, $switches=default, $app_override=default, $icon=default) if $switch = default then $switch = $OFF if $default = default then $default = $OFF if $menu_item = default or $menu_item = "" then $menu_item = "Open with " & $app_name & "|" & $app_name if $fallback = default then $fallback = "my-unique-key" if $switches = default then $switches = "" if $app_override = default then $app_override = "" if $icon = default then $icon = "" if not $ext then return SetError(1, 0, "no extension given") local $key if $default = $ON then $key = "open" ; set the default app for this file type else local $menu_array = StringSplit($menu_item, "|") ; debug_PrintArray($menu_array, "$menu_array:", @ScriptLineNumber, 0);debug $menu_item = $menu_array[1] $key = $menu_array[2] endif local $reg1, $reg2, $reg3, $reg4 local $filextkey = "HKEY_CLASSES_ROOT\." & $ext local $file_type = RegRead($filextkey, "") if not $file_type then $file_type = $fallback local $regbase = "HKEY_CLASSES_ROOT\" & $file_type local $shell = $regbase & "\shell" local $shellkey = $shell & "\" & $key local $BAX_key = $regbase & "\" & $app_name & "_Backup" local $my_app if $app_override then $my_app = $app_override else if @Compiled then $my_app = @ScriptFullPath else $my_app = ".\" & $app_name & ".exe" endif endif ; user has this enabled. ; if $switch = $ON then debug("Adding Context Menu (" & $menu_item & ") for.. =>" & $ext & "<=", @ScriptLineNumber);debug local $extexist = RegRead($filextkey, "") if not $extexist then RegWrite($filextkey, "", "REG_SZ", $file_type) endif ; check if it's still enabled.. local $regexist = RegRead($shellkey & "\command", "") if StringInStr($regexist, $my_app) then return SetError(2, 0, "still enabled!") ; backup current key.. local $bax1, $bax2, $bax3, $bax4, $old_val, $old_key ; default shell command: "open" ; we don't simply set this to the \my_name command, because they could be two different commands. ; this is more flexible ; replacing default shell command.. if $default = $ON then $old_key = RegRead($shell, "") ; "open" or "02.other_command", etc. $bax1 = RegWrite($BAX_key, "", "REG_SZ", $old_key) $old_val = RegRead($shell & "\" & $old_key, "") ; "DO THIS.." $bax2 = RegWrite($BAX_key, "menu", "REG_SZ", $old_val) $old_val = RegRead($shell & "\" & $old_key & "\command", "") ; C:\Program Files\other-apps\some-app.exe "%1" $bax3 = RegWrite($BAX_key, "cmd", "REG_SZ", $old_val) ; "cmd" because "command" is reserved! $old_val = RegRead($regbase & "\defaulticon", "") $bax4 = RegWrite($BAX_key, "icon", "REG_SZ", $old_val) if not $old_key then RegWrite($BAX_key, "created", "REG_SZ", "yes") if not $bax1 or not $bax2 or not $bax3 or not $bax4 then return SetError(3, 0, "no backup") endif ; write new key.. $reg1 = RegWrite($shellkey, "", "REG_SZ", $menu_item) $reg2 = RegWrite($shellkey & "\command", "", "REG_SZ", '"' & $my_app & '" ' & $switches & ' "%1"') if $default = $ON then RegWrite($shell, "", "REG_SZ", "open") if $icon then RegWrite($regbase & "\defaulticon", "", "REG_SZ", $icon) if $reg1 and $reg2 then return SetError(0, 0, "Written OK!") else ; Switch OFF.. debug("Removing Context Menu for.. =>" & $ext & "<=", @ScriptLineNumber);debug $regexist = RegRead($shellkey & "\command", "") if not StringInstr($regexist, $my_app) then return SetError(4, 0, "already off!") ; okay, reg is in place, let's restore backup, if available, or delete keys.. local $old_key1, $old_key2, $old_key3, $old_key4, $old_key5 ; default command.. if $default = $ON then $old_key1 = RegRead($BAX_key, "") $old_key2 = RegRead($BAX_key, "menu") $old_key3 = RegRead($BAX_key, "cmd") $old_key4 = RegRead($BAX_key, "icon") $old_key5 = RegRead($BAX_key, "created") ; restore backup registry values.. if ($old_key1 and ($old_key2 or $old_key3 or $old_key4)) or $old_key5 then if $old_key5 <> "yes" then if $old_key1 then $reg1 = RegWrite($shell, "", "REG_SZ", $old_key1) if $old_key2 then $reg2 = RegWrite($shell & "\" & $old_key1, "", "REG_SZ", $old_key2) if $old_key3 then $reg3 = RegWrite($shell & "\" & $old_key1 & "\command", "", "REG_SZ", $old_key3) if $old_key4 then $reg4 = RegWrite("HKEY_CLASSES_ROOT\" & $old_key1 & "\defaulticon", "", "REG_SZ", $old_key4) endif endif if $reg1 and $reg2 and $reg3 and $reg4 then RegDelete($BAX_key) if $old_key5 = "yes" then RegDelete($regbase) RegDelete($filextkey) endif return SetError(0, 0, "SUCCESS!") endif else ; regular menu item, simply delete it.. local $restored = RegDelete($shellkey) if $restored then return SetError(0, 0, "Deleted!") endif endif return SetError(-1, 0, "nothing happened!") endfunc ; SetExplorerDirectoryContextMenu ; ; Add or remove an Explorer context command for folders, drives and folder backgrounds. ; These are per-user entries and do not require elevation. ; ; Put a custom registry key after a pipe in $menu_item, e.g. "Open Here|open_here". ; func SetExplorerDirectoryContextMenu($app_name, $switch=default, $menu_item=default, _ $switches=default, $app_override=default, $icon=default) if $switch = default then $switch = $OFF if $menu_item = default or $menu_item = "" then $menu_item = "Open with " & $app_name if $switches = default then $switches = "" if $app_override = default then $app_override = "" if $icon = default then $icon = "" if not $app_name then return SetError(1, 0, "no application name given") local $key = $app_name local $menu_array = StringSplit($menu_item, "|") $menu_item = $menu_array[1] if $menu_array[0] > 1 then $key = $menu_array[2] local $my_app if $app_override then $my_app = $app_override else if @Compiled then $my_app = @ScriptFullPath else $my_app = ".\" & $app_name & ".exe" endif endif local const $CONTEXT_CLASS_COUNT = 3 local $context_classes[$CONTEXT_CLASS_COUNT] = ["Directory", "Drive", "Directory\Background"] local $context_targets[$CONTEXT_CLASS_COUNT] = ["%1", "%1", "%V"] local $success = true for $i = 0 to $CONTEXT_CLASS_COUNT - 1 local $reg_key = "HKEY_CURRENT_USER\Software\Classes\" & $context_classes[$i] & "\shell\" & $key if $switch = $ON then local $reg_menu = RegWrite($reg_key, "", "REG_SZ", $menu_item) local $reg_command = RegWrite($reg_key & "\command", "", "REG_SZ", _ '"' & $my_app & '" ' & $switches & ' "' & $context_targets[$i] & '"') local $reg_icon = true if $icon then $reg_icon = RegWrite($reg_key, "Icon", "REG_SZ", $icon) if not $reg_menu or not $reg_command or not $reg_icon then $success = false else local $existing_command = RegRead($reg_key & "\command", "") if @Error then continueloop if not StringInStr($existing_command, $my_app) then $success = false continueloop endif if not RegDelete($reg_key) then $success = false endif next if $success then return SetError(0, 0, "Updated OK!") return SetError(2, 0, "one or more context commands could not be updated") endfunc ; Copies all values then recurses through subkeys from one registry path to ; another, preserving value types. Used to back up and move file-association ; trees. ; func CopyRegistryTree($source_path, $target_path) local $index = 1 local $value_name, $value_data, $value_type, $type_string, $key_name ; Create the base target key RegWrite($target_path) ; 1. Copy all values at the current path while 1 $value_name = RegEnumVal($source_path, $index) if @Error then exitloop $value_data = RegRead($source_path, $value_name) $value_type = @Extended $type_string = "REG_SZ" switch $value_type case 1 $type_string = "REG_SZ" case 2 $type_string = "REG_EXPAND_SZ" case 3 $type_string = "REG_BINARY" case 4 $type_string = "REG_DWORD" case 7 $type_string = "REG_MULTI_SZ" case 11 $type_string = "REG_QWORD" endswitch RegWrite($target_path, $value_name, $type_string, $value_data) $index += 1 wend ; 2. Recursively copy all subkeys $index = 1 while 1 $key_name = RegEnumKey($source_path, $index) if @Error then exitloop CopyRegistryTree($source_path & "\" & $key_name, $target_path & "\" & $key_name) $index += 1 wend endfunc #cs Changes: 0.3 Added CopyRegistryTree() 0.2 Added.. SetExplorerContextMenu() which I cooked up for LoopDropZ & MangleeZee. All yours! 0.1 A small selection of useful registry functions.. MakeLongRegPaths() GetContextCommands() KeyIsEmpty() ReturnAllSubkeys() ReturnAllValueNames() ReturnAllPairs() #ce