123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- /*
- * Implement convenience wrappers on the awkward low-level functions
- * for accessing the Windows registry.
- */
- #include "putty.h"
- HKEY open_regkey_fn(bool create, bool write, HKEY hk, const char *path, ...)
- {
- HKEY toret = NULL;
- bool hk_needs_close = false;
- va_list ap;
- va_start(ap, path);
- assert(!reg_override_winscp());
- for (; path; path = va_arg(ap, const char *)) {
- HKEY hk_sub = NULL;
- DWORD access = KEY_READ | (write ? KEY_WRITE : 0);
- LONG status;
- if (create)
- status = RegCreateKeyEx(
- hk, path, 0, NULL, REG_OPTION_NON_VOLATILE,
- access, NULL, &hk_sub, NULL);
- else
- status = RegOpenKeyEx(hk, path, 0, access, &hk_sub);
- if (status != ERROR_SUCCESS)
- goto out;
- if (hk_needs_close)
- RegCloseKey(hk);
- hk = hk_sub;
- hk_needs_close = true;
- }
- toret = hk;
- hk = NULL;
- hk_needs_close = false;
- out:
- va_end(ap);
- if (hk_needs_close)
- RegCloseKey(hk);
- return toret;
- }
- void close_regkey(HKEY key)
- {
- if (reg_override_winscp())
- {
- close_regkey_winscp(key);
- return;
- }
- RegCloseKey(key);
- }
- #ifndef WINSCP
- void del_regkey(HKEY key, const char *name)
- {
- RegDeleteKey(key, name);
- }
- #endif
- char *enum_regkey(HKEY key, int index)
- {
- size_t regbuf_size = MAX_PATH + 1;
- char *regbuf = snewn(regbuf_size, char);
- assert(!reg_override_winscp());
- while (1) {
- LONG status = RegEnumKey(key, index, regbuf, regbuf_size);
- if (status == ERROR_SUCCESS)
- return regbuf;
- if (status != ERROR_MORE_DATA) {
- sfree(regbuf);
- return NULL;
- }
- sgrowarray(regbuf, regbuf_size, regbuf_size);
- }
- }
- bool get_reg_dword(HKEY key, const char *name, DWORD *out)
- {
- DWORD type, size;
- if (reg_override_winscp())
- {
- return get_reg_dword_winscp(key, name, out);
- }
- size = sizeof(*out);
- if (RegQueryValueEx(key, name, 0, &type,
- (BYTE *)out, &size) != ERROR_SUCCESS ||
- size != sizeof(*out) || type != REG_DWORD)
- return false;
- else
- return true;
- }
- bool put_reg_dword(HKEY key, const char *name, DWORD value)
- {
- if (reg_override_winscp())
- {
- return put_reg_dword_winscp(key, name, value);
- }
- return RegSetValueEx(key, name, 0, REG_DWORD, (CONST BYTE *) &value,
- sizeof(value)) == ERROR_SUCCESS;
- }
- char *get_reg_sz(HKEY key, const char *name)
- {
- DWORD type, size;
- if (reg_override_winscp())
- {
- return get_reg_sz_winscp(key, name);
- }
- if (RegQueryValueEx(key, name, 0, &type, NULL,
- &size) != ERROR_SUCCESS || type != REG_SZ)
- return NULL; /* not a string */
- { // WINSCP
- size_t allocsize = size+1; /* allow for an extra NUL if needed */
- char *toret = snewn(allocsize, char);
- if (RegQueryValueEx(key, name, 0, &type, (BYTE *)toret,
- &size) != ERROR_SUCCESS || type != REG_SZ) {
- sfree(toret);
- return NULL;
- }
- assert(size < allocsize);
- toret[size] = '\0'; /* add an extra NUL in case RegQueryValueEx
- * didn't supply one */
- return toret;
- } // WINSCP
- }
- bool put_reg_sz(HKEY key, const char *name, const char *str)
- {
- if (reg_override_winscp())
- {
- return put_reg_sz_winscp(key, name, str);
- }
- /* You have to store the trailing NUL as well */
- return RegSetValueEx(key, name, 0, REG_SZ, (CONST BYTE *)str,
- 1 + strlen(str)) == ERROR_SUCCESS;
- }
- #ifndef WINSCP
- /*
- * REG_MULTI_SZ items are stored as a concatenation of NUL-terminated
- * strings, terminated in turn with an empty string, i.e. a second
- * consecutive NUL.
- *
- * We represent these in their storage format, as a strbuf - but
- * *without* the second consecutive NUL.
- *
- * So you can build up a new MULTI_SZ value in a strbuf by calling
- * put_asciz once per output string and then put_reg_multi_sz; and you
- * can consume one by initialising a BinarySource to the result of
- * get_reg_multi_sz, and then calling get_asciz on it and assuming
- * that !get_err(src) means you have a real output string.
- *
- * Also, calling strbuf_to_str on one of these will give you back a
- * bare 'char *' with the same double-NUL termination, to pass back to
- * a caller.
- */
- strbuf *get_reg_multi_sz(HKEY key, const char *name)
- {
- DWORD type, size;
- if (RegQueryValueEx(key, name, 0, &type, NULL,
- &size) != ERROR_SUCCESS || type != REG_MULTI_SZ)
- return NULL; /* not a string */
- strbuf *toret = strbuf_new();
- void *ptr = strbuf_append(toret, (size_t)size + 2);
- if (RegQueryValueEx(key, name, 0, &type, (BYTE *)ptr,
- &size) != ERROR_SUCCESS || type != REG_MULTI_SZ) {
- strbuf_free(toret);
- return NULL;
- }
- strbuf_shrink_to(toret, size);
- /* Ensure we end with exactly one \0 */
- while (strbuf_chomp(toret, '\0'));
- put_byte(toret, '\0');
- return toret;
- }
- bool put_reg_multi_sz(HKEY key, const char *name, strbuf *str)
- {
- /*
- * Of course, to write our string list into the registry, we _do_
- * have to include both trailing NULs. But this is easy, because a
- * strbuf is also designed to hold a single string and make it
- * conveniently accessible in NUL-terminated form, so it stores a
- * NUL in its buffer just beyond its formal length. So we just
- * include that extra byte in the data we write.
- */
- return RegSetValueEx(key, name, 0, REG_MULTI_SZ, (CONST BYTE *)str->s,
- str->len + 1) == ERROR_SUCCESS;
- }
- char *get_reg_sz_simple(HKEY key, const char *name, const char *leaf)
- {
- HKEY subkey = open_regkey_ro(key, name);
- if (!subkey)
- return NULL;
- char *toret = get_reg_sz(subkey, leaf);
- RegCloseKey(subkey);
- return toret;
- }
- #endif // WINSCP
|