Re: WIN32 Registry anyone?
I wrote:
> Could somebody out there provide some sample code for accessing Windows
> registry keys with LWW? I see a couple of relevant functions exported
> from the WIN32 package but haven't yet figured out how to use them.
OK, here are some things I've found out by playing in the listener. Of
course, this comes without any warranty and you shouldn't try this at
home. However, until Xanalys is going to release more documentation -
probably in the next release -, you might save a few minutes by
reading this.
This was tested with LispWorks 4.2.7 pro on Windows XP pro.
The following registry-related symbols are exported from the WIN32
package. WITH-REGISTRY-KEY is a macro, the other ones are functions.
close-registry-key
collect-registry-subkeys
create-registry-key
delete-registry-key
enum-registry-value
open-registry-key
query-registry-key-info
query-registry-value
registry-value
set-registry-value
with-registry-key
All of this seems to be a thin wrapper around FLI calls which is
exemplified by the fact that the first value of, e.g., calling
OPEN-REGISTRY-KEY is a fixnum. It certainly helps if you know a thing
or two about the WIN32 registry C API.
To simply read a key's value from the registry you can use
QUERY-REGISTRY-VALUE:
CL-USER 211 > (win32:query-registry-value
"Software\\Xanalys\\LispWorks\\4\\2\\Environment\\LISPWORKS-TOOLS\\GLOBAL-DEFAULTS\\"
"Init Filename")
"\"C:\\\\cygwin\\\\home\\\\edi\\\\.lispworks\""
T
The first argument is a path to the key starting from the root key
(see below), the second one is the name of the key.
The function accepts a keyword argument :ROOT which describes where
the path will start from. This can be an already open key or it can be
a symbol from the keyword package denoting one of the root keys. By
trial and error I found out that the following keyword symbols are
acceptable:
:ROOT for HKEY_CLASSES_ROOT
:USER for HKEY_CURRENT_USER
:LOCAL-MACHINE for HKEY_LOCAL_MACHINE
:USERS for HKEY_USERS
No idea if there are others. :USER seems to be the default value.
Here's an example on how to use an already open key which also
showcases the WITH-REGISTRY-KEY macro:
CL-USER 212 > (win32:with-registry-key (system-key
"HARDWARE\\DESCRIPTION\\System\\" :root :local-machine)
(win32:query-registry-value "CentralProcessor\\0\\"
"ProcessorNameString" :root system-key))
"Intel(R) Pentium(R) III Mobile CPU 1200MHz"
T
Use NIL as the path if the root key is already where you wanted to go:
CL-USER 218 > (win32:with-registry-key (processor-key
"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0\\" :root :local-machine)
(win32:query-registry-value nil "ProcessorNameString"
:root processor-key))
"Intel(R) Pentium(R) III Mobile CPU 1200MHz"
T
Use NIL as the key's name if you want to get at the default value:
CL-USER 219 > (win32:query-registry-value ".html" nil :root :root)
"MozillaHTML"
T
As you might have expected this is all case-insensitive:
CL-USER 213 > (win32:query-registry-value
"HARDWARE\\DESCRIPTION\\SYSTEM\\CentralProcessor\\0\\"
"PROCESSORNAMESTRING" :root :local-machine)
"Intel(R) Pentium(R) III Mobile CPU 1200MHz"
T
Another keyword argument is ERRORP the use of which should be obvious:
CL-USER 223 > (win32:query-registry-value ".htmlx" nil :root :root)
Error: Failed to open registry subkey .htmlx (type ROOT) - Win32
Error #x2.
1 (abort) Return to level 0.
2 Return to top loop level 0.
Type :b for backtrace, :c <option number> to proceed, or :? for
other options
CL-USER 224 : 1 > :a
CL-USER 225 > (win32:query-registry-value ".htmlx" nil :root :root
:errorp nil)
NIL
COLLECT-REGISTRY-SUBKEYS will allow you to descend into the registry
tree:
CL-USER 226 > (win32:collect-registry-subkeys ".html" :root :root)
("OpenWithList" "PersistentHandler")
OPEN-REGISTRY-KEY basically accepts the same arguments as
QUERY-REGISTRY-VALUE except for the key's name. This function has its
counterpart in CLOSE-REGISTRY-KEY.
CL-USER 231 > (win32:open-registry-key ".html" :root :root)
310
T
CL-USER 232 > (win32:close-registry-key 310)
0
It's probably wiser to use the WITH-REGISTRY-KEY macro. If you
macroexpand this macro you'll also get a hint at what the second
return value of OPEN-REGISTRY-KEY is supposed to mean:
CL-USER 240 > (pprint (macroexpand-1 '(win32:with-registry-key
(my-key ".html" :root :root) my-body)))
(MULTIPLE-VALUE-BIND (MY-KEY #:CLOSEP612)
(WIN32:OPEN-REGISTRY-KEY ".html" :ROOT :ROOT :ERRORP T)
(WHEN MY-KEY (UNWIND-PROTECT (PROGN MY-BODY) (WHEN #:CLOSEP612
(WIN32::REG-CLOSE-KEY MY-KEY)))))
Now, if you want to go wild and create, change and delete registry
entries, here are some more examples:
CL-USER 241 > (win32:create-registry-key "Foo" :root :user)
312
:CREATED-NEW-KEY
CL-USER 242 > (win32:create-registry-key "Foo" :root :user)
308
:OPEND-EXISTING-KEY ;;; sic!
CL-USER 243 > (setf (win32:registry-value "Foo" "Bar" :root :user
:expected-type :integer) 42)
0
CL-USER 244 > (setf (win32:registry-value "Foo" "Baz" :root :user
:expected-type :string) "Frob")
0
CL-USER 245 > (win32:registry-value "Foo" "Bar" :root :user
:expected-type :integer)
42
T
CL-USER 246 > (win32:enum-registry-value "Foo" 0 :root :user)
"Bar"
:INTEGER
42
CL-USER 247 > (win32:registry-value "Foo" "Bar" :root :user)
42
T
CL-USER 248 > (win32:delete-registry-key "Foo" :root :user)
T
For the EXPECTED-TYPE keyword above the following list might come in
handy.
CL-USER 252 > (pprint win32::*registry-type-values*)
((:NONE . 0)
(:STRING . 1)
(:ENVIRONMENT-STRING . 2)
(:BINARY . 3)
(:INTEGER . 4)
(:LITTLE-ENDIAN-INTEGER . 4)
(:BIG-ENDIAN-INTEGER . 5)
(:SYMBOLIC-LINK . 6)
(:STRING-ARRAY . 7)
(:RESOURCE-LIST . 8)
(:HARDWARE-RESOURCE-LIST . 9))
That's it for now. I can only repeat what you already know: Playing
with the Windows Registry is _very_ dangerous and you shouldn't rely
on anything I've written here. I'd be happy if someone who knows more
about this would chime in.
Cheers,
Edi.