mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 10:18:41 +02:00 
			
		
		
		
	In order to fix MinGW32 builds, which can't cope with the pointer conversion to stdcall apparently? Differential Revision: https://phabricator.services.mozilla.com/D194118
		
			
				
	
	
		
			235 lines
		
	
	
	
		
			8.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			235 lines
		
	
	
	
		
			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
 |