Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mRemoteNG/PuTTYNG.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'windows/utils/registry.c')
-rw-r--r--windows/utils/registry.c184
1 files changed, 184 insertions, 0 deletions
diff --git a/windows/utils/registry.c b/windows/utils/registry.c
new file mode 100644
index 00000000..1f50e67a
--- /dev/null
+++ b/windows/utils/registry.c
@@ -0,0 +1,184 @@
+/*
+ * Implement convenience wrappers on the awkward low-level functions
+ * for accessing the Windows registry.
+ */
+
+#include "putty.h"
+
+HKEY open_regkey_fn(bool create, HKEY hk, const char *path, ...)
+{
+ HKEY toret = NULL;
+ bool hk_needs_close = false;
+ va_list ap;
+ va_start(ap, path);
+
+ for (; path; path = va_arg(ap, const char *)) {
+ HKEY hk_sub = NULL;
+
+ LONG status;
+ if (create)
+ status = RegCreateKeyEx(
+ hk, path, 0, NULL, REG_OPTION_NON_VOLATILE,
+ KEY_READ | KEY_WRITE, NULL, &hk_sub, NULL);
+ else
+ status = RegOpenKeyEx(
+ hk, path, 0, KEY_READ | KEY_WRITE, &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)
+{
+ RegCloseKey(key);
+}
+
+void del_regkey(HKEY key, const char *name)
+{
+ RegDeleteKey(key, name);
+}
+
+char *enum_regkey(HKEY key, int index)
+{
+ size_t regbuf_size = MAX_PATH + 1;
+ char *regbuf = snewn(regbuf_size, char);
+
+ 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;
+ 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)
+{
+ 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 (RegQueryValueEx(key, name, 0, &type, NULL,
+ &size) != ERROR_SUCCESS || type != REG_SZ)
+ return NULL; /* not a string */
+
+ 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;
+}
+
+bool put_reg_sz(HKEY key, const char *name, const char *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;
+}
+
+/*
+ * 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(false, key, name);
+ if (!subkey)
+ return NULL;
+ char *toret = get_reg_sz(subkey, leaf);
+ RegCloseKey(subkey);
+ return toret;
+}