зеркало из https://github.com/mozilla/gecko-dev.git
236 строки
8.3 KiB
C++
236 строки
8.3 KiB
C++
/* -*- 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
|