Recently I needed to query registry values from within Emacs. Emacs, being a cross-platform application mostly tailored to work on UNIX-like operating systems, lacks this functionality. As you can expect, I ended up writing a code which accomplishes the task.

One might need this functionality to configure Emacs to automatically find installation paths of the other tools. For example, I use it to get the git installation path to configure Magit properly.

Although I needed to query only string values ( REG_SZ ), there is support for the other registry value types as well. The provided code uses standard reg.exe command line utility to read values from the registry.

( defun win-reg-read (regkey &optional value access-64-bit) "Read a value in the Windows registry. If the value does not exist, it returns nil. For an empty REG_BINARY value it returns T." ( when (string-equal system-type "windows-nt" ) ( let* ((regkey (encode-coding-string regkey locale-coding-system)) (value (encode-coding-string value locale-coding-system)) (reg-exe (concat (getenv "WinDir" ) "\\System32\\reg.exe" )) (bits-64-param ( if access-64-bit "/reg:64" "/reg:32" )) (reg-value ( let ((output ( with-output-to-string ( with-current-buffer standard-output ( if value (process-file reg-exe nil t nil "query" regkey "/v" value bits-64-param) (process-file reg-exe nil t nil "query" regkey "/ve" bits-64-param)))))) (set-text-properties 0 (length output) nil output) output))) ( let* ((lines (split-string reg-value "

" nil nil)) (result-line (nth 2 lines))) ( when (> (length lines) 4) ( let* ((result-line ( if value (subseq result-line (+ 8 (length value))) (replace-regexp-in-string "^[ ]+[ \ (][ ^ \ )]+[ \ )][ ]+" "" result-line))) (tokens (split-string result-line " " t)) (type-string (car tokens)) (result (subseq result-line (+ 4 (length type-string))))) ( cond (( or (string-equal type-string "REG_DWORD" ) (string-equal type-string "REG_QWORD" )) (string-to-number (subseq result 2) 16)) (( or (string-equal type-string "REG_SZ" ) (string-equal type-string "REG_EXPAND_SZ" )) result) ((string-equal type-string "REG_MULTI_SZ" ) (split-string result (regexp-quote "\\0" ) t)) ((string-equal type-string "REG_BINARY" ) ( let ((res) (pos 0) (size (/ (length result) 2))) ( if (zerop size) t ( progn ( dotimes (i size) ( push (string-to-number (subseq result pos (+ pos 2)) 16) res) (incf pos 2)) (reverse res))))) (t nil))))))))

The function above accepts three arguments:

Registry key name;

Registry value name (optional). If omitted, the default value of the registry key is queried;

The last parameter helps to handle registry virtualisation on 64-bit versions of Windows. If true, it queries the 64-bit branch of the registry, 32-bit one otherwise.

The code returns the value on success, NIL otherwise. For values, which by their nature hold multiple data items ( REG_MULTISTRING_SZ , REG_BINARY ) the lists of values are returned.

N.B. Eli Zaretskii pointed out that there were some problems with handling text encodings in the older version of the code. Hopefully, they are fixed now.

Limitations I should make a couple of notes about accessing the multi-string ( REG_MULTISTRING_SZ ) values and binary values ( REG_BINARY ). The reg.exe utility reports information for multi-string values in such a way that the strings are separated by the "\0" sequence. If there is this sequence somewhere in the data the code below will return incorrect results. Empty binary registry values are reported in a somewhat weird way: the code returns T for them. I doubt that these limitations would bite you in practice.

Dealing with Registry Virtualisation On 64-bit versions of Windows, the access to some registry keys is virtualised for 32-bit applications. As many applications exist in both 32-bit and 64-bit variants often it makes sense to check for both values in the registry. The code below does just that. On 64-bit versions of Windows, it tries to query value in the 64-bit section of the registry at first and, if it is absent, it tries to query the 32-bit one. I guess that in most cases it is what you want. ( defun win-reg-read-64-or-32 (regkey &optional value) "Read a value in the Windows registry. If the value does not exist, it returns nil. Checks both 32-bit and 64-nit keys, considers system bitness when searching for a value." ( let ((check (getenv "ProgramW6432" ))) ( if ( or (null check) (zerop (length check))) (win-reg-read regkey value nil) ( or (win-reg-read regkey value t) (win-reg-read regkey value nil)))))