summaryrefslogtreecommitdiffstats
path: root/widget/windows/WinRegistry.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--widget/windows/WinRegistry.h235
1 files changed, 235 insertions, 0 deletions
diff --git a/widget/windows/WinRegistry.h b/widget/windows/WinRegistry.h
new file mode 100644
index 0000000000..8ab221928e
--- /dev/null
+++ b/widget/windows/WinRegistry.h
@@ -0,0 +1,235 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_widget_WinRegistry_h__
+#define mozilla_widget_WinRegistry_h__
+
+#include <windows.h>
+#include <functional>
+#include "nsCOMPtr.h"
+#include "nsString.h"
+#include "nsTArray.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/Span.h"
+
+class nsISerialEventTarget;
+
+namespace mozilla::widget::WinRegistry {
+
+// According to MSDN, the following limits apply (in characters excluding room
+// for terminating null character):
+static constexpr size_t kMaxKeyNameLen = 255;
+static constexpr size_t kMaxValueNameLen = 16383;
+
+/// https://learn.microsoft.com/en-us/windows/win32/shell/regsam
+enum class KeyMode : uint32_t {
+ AllAccess = KEY_ALL_ACCESS,
+ QueryValue = KEY_QUERY_VALUE,
+ CreateLink = KEY_CREATE_LINK,
+ CreateSubKey = KEY_CREATE_SUB_KEY,
+ EnumerateSubkeys = KEY_ENUMERATE_SUB_KEYS,
+ Execute = KEY_EXECUTE,
+ Notify = KEY_NOTIFY,
+ Read = KEY_READ,
+ SetValue = KEY_SET_VALUE,
+ Write = KEY_WRITE,
+};
+
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(KeyMode);
+
+enum class StringFlags : uint32_t {
+ // Whether to allow REG_SZ strings.
+ Sz = 1 << 0,
+ // Whether to read EXPAND_SZ strings.
+ ExpandSz = 1 << 1,
+ // Whether to treat MULTI_SZ values as strings. This is a historical
+ // idiosyncrasy of the nsIWindowsRegKey, but most likely not what you want.
+ LegacyMultiSz = 1 << 2,
+ // Whether to expand environment variables in EXPAND_SZ values.
+ // Only makes sense along with the ExpandSz variable.
+ ExpandEnvironment = 1 << 3,
+ // By default, only allow regular Sz, and don't perform environment expansion.
+ Default = Sz,
+};
+
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(StringFlags);
+
+// Convenience alias for legacy WinUtils callers, to preserve behavior.
+// Chances are users of these flags could just look at Sz strings, tho.
+static constexpr auto kLegacyWinUtilsStringFlags =
+ StringFlags::Sz | StringFlags::ExpandSz;
+
+// https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-value-types
+enum class ValueType : uint32_t {
+ Binary = REG_BINARY,
+ Dword = REG_DWORD,
+ ExpandSz = REG_EXPAND_SZ,
+ Link = REG_LINK,
+ MultiSz = REG_MULTI_SZ,
+ None = REG_NONE,
+ Qword = REG_QWORD,
+ Sz = REG_SZ,
+};
+
+class Key {
+ public:
+ enum CreateFlag {
+ Create,
+ };
+
+ Key() = default;
+ Key(const Key&) = delete;
+ Key(Key&& aOther) { std::swap(mKey, aOther.mKey); }
+
+ Key& operator=(const Key&) = delete;
+ Key& operator=(Key&& aOther) {
+ std::swap(mKey, aOther.mKey);
+ return *this;
+ }
+
+ Key(HKEY aParent, const nsString& aPath, KeyMode aMode, CreateFlag);
+ Key(HKEY aParent, const nsString& aPath, KeyMode aMode);
+
+ Key(const Key& aParent, const nsString& aPath, KeyMode aMode, CreateFlag)
+ : Key(aParent.mKey, aPath, aMode, Create) {}
+ Key(const Key& aParent, const nsString& aPath, KeyMode aMode)
+ : Key(aParent.mKey, aPath, aMode) {}
+
+ ~Key() {
+ if (mKey) {
+ ::RegCloseKey(mKey);
+ }
+ }
+
+ explicit operator bool() const { return !!mKey; }
+
+ uint32_t GetChildCount() const;
+ [[nodiscard]] bool GetChildName(uint32_t aIndex, nsAString& aResult) const;
+ [[nodiscard]] bool RemoveChildKey(const nsString& aName) const;
+
+ uint32_t GetValueCount() const;
+ [[nodiscard]] bool GetValueName(uint32_t aIndex, nsAString& aResult) const;
+ ValueType GetValueType(const nsString& aName) const;
+ bool RemoveValue(const nsString& aName) const;
+
+ Maybe<uint32_t> GetValueAsDword(const nsString& aName) const;
+ bool WriteValueAsDword(const nsString& aName, uint32_t aValue);
+
+ Maybe<uint64_t> GetValueAsQword(const nsString& aName) const;
+ [[nodiscard]] bool WriteValueAsQword(const nsString& aName, uint64_t aValue);
+
+ [[nodiscard]] bool GetValueAsBinary(const nsString& aName,
+ nsTArray<uint8_t>&) const;
+ Maybe<nsTArray<uint8_t>> GetValueAsBinary(const nsString& aName) const;
+ [[nodiscard]] bool WriteValueAsBinary(const nsString& aName,
+ Span<const uint8_t> aValue);
+
+ [[nodiscard]] bool GetValueAsString(const nsString& aName, nsString& aResult,
+ StringFlags = StringFlags::Default) const;
+ Maybe<nsString> GetValueAsString(const nsString& aName,
+ StringFlags = StringFlags::Default) const;
+ // Reads a string value into a buffer. Returns Some(length) if the string is
+ // read fully, in which case the passed memory region contains a
+ // null-terminated string.
+ // Doesn't perform environment expansion (and asserts if you pass the
+ // ExpandEnvironment flag).
+ [[nodiscard]] Maybe<uint32_t> GetValueAsString(
+ const nsString& aName, Span<char16_t>,
+ StringFlags = StringFlags::Default) const;
+ [[nodiscard]] Maybe<uint32_t> GetValueAsString(
+ const nsString& aName, Span<wchar_t> aBuffer,
+ StringFlags aFlags = StringFlags::Default) const {
+ return GetValueAsString(
+ aName, Span<char16_t>((char16_t*)aBuffer.data(), aBuffer.Length()),
+ aFlags);
+ }
+
+ [[nodiscard]] bool WriteValueAsString(const nsString& aName,
+ const nsString& aValue) {
+ MOZ_ASSERT(mKey);
+ return SUCCEEDED(RegSetValueExW(mKey, aName.get(), 0, REG_SZ,
+ (const BYTE*)aValue.get(),
+ (aValue.Length() + 1) * sizeof(char16_t)));
+ }
+
+ HKEY RawKey() const { return mKey; }
+
+ private:
+ HKEY mKey = nullptr;
+};
+
+inline bool HasKey(HKEY aRootKey, const nsString& aKeyName) {
+ return !!Key(aRootKey, aKeyName, KeyMode::Read);
+}
+
+// Returns a single string value from the registry into a buffer.
+[[nodiscard]] inline bool GetString(HKEY aRootKey, const nsString& aKeyName,
+ const nsString& aValueName,
+ Span<char16_t> aBuffer,
+ StringFlags aFlags = StringFlags::Default) {
+ Key k(aRootKey, aKeyName, KeyMode::QueryValue);
+ return k && k.GetValueAsString(aValueName, aBuffer, aFlags);
+}
+[[nodiscard]] inline bool GetString(HKEY aRootKey, const nsString& aKeyName,
+ const nsString& aValueName,
+ Span<wchar_t> aBuffer,
+ StringFlags aFlags = StringFlags::Default) {
+ return GetString(aRootKey, aKeyName, aValueName,
+ Span<char16_t>((char16_t*)aBuffer.data(), aBuffer.Length()),
+ aFlags);
+}
+[[nodiscard]] inline bool GetString(HKEY aRootKey, const nsString& aKeyName,
+ const nsString& aValueName,
+ nsString& aBuffer,
+ StringFlags aFlags = StringFlags::Default) {
+ Key k(aRootKey, aKeyName, KeyMode::QueryValue);
+ return k && k.GetValueAsString(aValueName, aBuffer, aFlags);
+}
+inline Maybe<nsString> GetString(HKEY aRootKey, const nsString& aKeyName,
+ const nsString& aValueName,
+ StringFlags aFlags = StringFlags::Default) {
+ Key k(aRootKey, aKeyName, KeyMode::QueryValue);
+ if (!k) {
+ return Nothing();
+ }
+ return k.GetValueAsString(aValueName, aFlags);
+}
+
+class KeyWatcher final {
+ public:
+ using Callback = std::function<void()>;
+
+ KeyWatcher(const KeyWatcher&) = delete;
+
+ const Key& GetKey() const { return mKey; }
+
+ // Start watching a key. The watching is recursive (the whole key subtree is
+ // watched), and the callback is executed every time the key or any of its
+ // descendants change until the watcher is destroyed.
+ //
+ // @param aKey the key to watch. Must have been opened with the
+ // KeyMode::Notify flag.
+ // @param aTargetSerialEventTarget the target event target to dispatch the
+ // callback to.
+ // @param aCallback the closure to run every time that registry key changes.
+ KeyWatcher(Key&& aKey, nsISerialEventTarget* aTargetSerialEventTarget,
+ Callback&& aCallback);
+
+ ~KeyWatcher();
+
+ private:
+ static void CALLBACK WatchCallback(void* aContext, BOOLEAN);
+ bool Register();
+
+ Key mKey;
+ nsCOMPtr<nsISerialEventTarget> mEventTarget;
+ Callback mCallback;
+ HANDLE mEvent = nullptr;
+ HANDLE mWaitObject = nullptr;
+};
+
+} // namespace mozilla::widget::WinRegistry
+
+#endif