Bug 1931425 - Limit how often moz-label's #setStyles runs r=reusable-components-revie...
[gecko.git] / widget / windows / WinRegistry.h
blob8ab221928ea85933ec643db472027cd1eaa01d4d
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef mozilla_widget_WinRegistry_h__
7 #define mozilla_widget_WinRegistry_h__
9 #include <windows.h>
10 #include <functional>
11 #include "nsCOMPtr.h"
12 #include "nsString.h"
13 #include "nsTArray.h"
14 #include "mozilla/Maybe.h"
15 #include "mozilla/Span.h"
17 class nsISerialEventTarget;
19 namespace mozilla::widget::WinRegistry {
21 // According to MSDN, the following limits apply (in characters excluding room
22 // for terminating null character):
23 static constexpr size_t kMaxKeyNameLen = 255;
24 static constexpr size_t kMaxValueNameLen = 16383;
26 /// https://learn.microsoft.com/en-us/windows/win32/shell/regsam
27 enum class KeyMode : uint32_t {
28 AllAccess = KEY_ALL_ACCESS,
29 QueryValue = KEY_QUERY_VALUE,
30 CreateLink = KEY_CREATE_LINK,
31 CreateSubKey = KEY_CREATE_SUB_KEY,
32 EnumerateSubkeys = KEY_ENUMERATE_SUB_KEYS,
33 Execute = KEY_EXECUTE,
34 Notify = KEY_NOTIFY,
35 Read = KEY_READ,
36 SetValue = KEY_SET_VALUE,
37 Write = KEY_WRITE,
40 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(KeyMode);
42 enum class StringFlags : uint32_t {
43 // Whether to allow REG_SZ strings.
44 Sz = 1 << 0,
45 // Whether to read EXPAND_SZ strings.
46 ExpandSz = 1 << 1,
47 // Whether to treat MULTI_SZ values as strings. This is a historical
48 // idiosyncrasy of the nsIWindowsRegKey, but most likely not what you want.
49 LegacyMultiSz = 1 << 2,
50 // Whether to expand environment variables in EXPAND_SZ values.
51 // Only makes sense along with the ExpandSz variable.
52 ExpandEnvironment = 1 << 3,
53 // By default, only allow regular Sz, and don't perform environment expansion.
54 Default = Sz,
57 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(StringFlags);
59 // Convenience alias for legacy WinUtils callers, to preserve behavior.
60 // Chances are users of these flags could just look at Sz strings, tho.
61 static constexpr auto kLegacyWinUtilsStringFlags =
62 StringFlags::Sz | StringFlags::ExpandSz;
64 // https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-value-types
65 enum class ValueType : uint32_t {
66 Binary = REG_BINARY,
67 Dword = REG_DWORD,
68 ExpandSz = REG_EXPAND_SZ,
69 Link = REG_LINK,
70 MultiSz = REG_MULTI_SZ,
71 None = REG_NONE,
72 Qword = REG_QWORD,
73 Sz = REG_SZ,
76 class Key {
77 public:
78 enum CreateFlag {
79 Create,
82 Key() = default;
83 Key(const Key&) = delete;
84 Key(Key&& aOther) { std::swap(mKey, aOther.mKey); }
86 Key& operator=(const Key&) = delete;
87 Key& operator=(Key&& aOther) {
88 std::swap(mKey, aOther.mKey);
89 return *this;
92 Key(HKEY aParent, const nsString& aPath, KeyMode aMode, CreateFlag);
93 Key(HKEY aParent, const nsString& aPath, KeyMode aMode);
95 Key(const Key& aParent, const nsString& aPath, KeyMode aMode, CreateFlag)
96 : Key(aParent.mKey, aPath, aMode, Create) {}
97 Key(const Key& aParent, const nsString& aPath, KeyMode aMode)
98 : Key(aParent.mKey, aPath, aMode) {}
100 ~Key() {
101 if (mKey) {
102 ::RegCloseKey(mKey);
106 explicit operator bool() const { return !!mKey; }
108 uint32_t GetChildCount() const;
109 [[nodiscard]] bool GetChildName(uint32_t aIndex, nsAString& aResult) const;
110 [[nodiscard]] bool RemoveChildKey(const nsString& aName) const;
112 uint32_t GetValueCount() const;
113 [[nodiscard]] bool GetValueName(uint32_t aIndex, nsAString& aResult) const;
114 ValueType GetValueType(const nsString& aName) const;
115 bool RemoveValue(const nsString& aName) const;
117 Maybe<uint32_t> GetValueAsDword(const nsString& aName) const;
118 bool WriteValueAsDword(const nsString& aName, uint32_t aValue);
120 Maybe<uint64_t> GetValueAsQword(const nsString& aName) const;
121 [[nodiscard]] bool WriteValueAsQword(const nsString& aName, uint64_t aValue);
123 [[nodiscard]] bool GetValueAsBinary(const nsString& aName,
124 nsTArray<uint8_t>&) const;
125 Maybe<nsTArray<uint8_t>> GetValueAsBinary(const nsString& aName) const;
126 [[nodiscard]] bool WriteValueAsBinary(const nsString& aName,
127 Span<const uint8_t> aValue);
129 [[nodiscard]] bool GetValueAsString(const nsString& aName, nsString& aResult,
130 StringFlags = StringFlags::Default) const;
131 Maybe<nsString> GetValueAsString(const nsString& aName,
132 StringFlags = StringFlags::Default) const;
133 // Reads a string value into a buffer. Returns Some(length) if the string is
134 // read fully, in which case the passed memory region contains a
135 // null-terminated string.
136 // Doesn't perform environment expansion (and asserts if you pass the
137 // ExpandEnvironment flag).
138 [[nodiscard]] Maybe<uint32_t> GetValueAsString(
139 const nsString& aName, Span<char16_t>,
140 StringFlags = StringFlags::Default) const;
141 [[nodiscard]] Maybe<uint32_t> GetValueAsString(
142 const nsString& aName, Span<wchar_t> aBuffer,
143 StringFlags aFlags = StringFlags::Default) const {
144 return GetValueAsString(
145 aName, Span<char16_t>((char16_t*)aBuffer.data(), aBuffer.Length()),
146 aFlags);
149 [[nodiscard]] bool WriteValueAsString(const nsString& aName,
150 const nsString& aValue) {
151 MOZ_ASSERT(mKey);
152 return SUCCEEDED(RegSetValueExW(mKey, aName.get(), 0, REG_SZ,
153 (const BYTE*)aValue.get(),
154 (aValue.Length() + 1) * sizeof(char16_t)));
157 HKEY RawKey() const { return mKey; }
159 private:
160 HKEY mKey = nullptr;
163 inline bool HasKey(HKEY aRootKey, const nsString& aKeyName) {
164 return !!Key(aRootKey, aKeyName, KeyMode::Read);
167 // Returns a single string value from the registry into a buffer.
168 [[nodiscard]] inline bool GetString(HKEY aRootKey, const nsString& aKeyName,
169 const nsString& aValueName,
170 Span<char16_t> aBuffer,
171 StringFlags aFlags = StringFlags::Default) {
172 Key k(aRootKey, aKeyName, KeyMode::QueryValue);
173 return k && k.GetValueAsString(aValueName, aBuffer, aFlags);
175 [[nodiscard]] inline bool GetString(HKEY aRootKey, const nsString& aKeyName,
176 const nsString& aValueName,
177 Span<wchar_t> aBuffer,
178 StringFlags aFlags = StringFlags::Default) {
179 return GetString(aRootKey, aKeyName, aValueName,
180 Span<char16_t>((char16_t*)aBuffer.data(), aBuffer.Length()),
181 aFlags);
183 [[nodiscard]] inline bool GetString(HKEY aRootKey, const nsString& aKeyName,
184 const nsString& aValueName,
185 nsString& aBuffer,
186 StringFlags aFlags = StringFlags::Default) {
187 Key k(aRootKey, aKeyName, KeyMode::QueryValue);
188 return k && k.GetValueAsString(aValueName, aBuffer, aFlags);
190 inline Maybe<nsString> GetString(HKEY aRootKey, const nsString& aKeyName,
191 const nsString& aValueName,
192 StringFlags aFlags = StringFlags::Default) {
193 Key k(aRootKey, aKeyName, KeyMode::QueryValue);
194 if (!k) {
195 return Nothing();
197 return k.GetValueAsString(aValueName, aFlags);
200 class KeyWatcher final {
201 public:
202 using Callback = std::function<void()>;
204 KeyWatcher(const KeyWatcher&) = delete;
206 const Key& GetKey() const { return mKey; }
208 // Start watching a key. The watching is recursive (the whole key subtree is
209 // watched), and the callback is executed every time the key or any of its
210 // descendants change until the watcher is destroyed.
212 // @param aKey the key to watch. Must have been opened with the
213 // KeyMode::Notify flag.
214 // @param aTargetSerialEventTarget the target event target to dispatch the
215 // callback to.
216 // @param aCallback the closure to run every time that registry key changes.
217 KeyWatcher(Key&& aKey, nsISerialEventTarget* aTargetSerialEventTarget,
218 Callback&& aCallback);
220 ~KeyWatcher();
222 private:
223 static void CALLBACK WatchCallback(void* aContext, BOOLEAN);
224 bool Register();
226 Key mKey;
227 nsCOMPtr<nsISerialEventTarget> mEventTarget;
228 Callback mCallback;
229 HANDLE mEvent = nullptr;
230 HANDLE mWaitObject = nullptr;
233 } // namespace mozilla::widget::WinRegistry
235 #endif