summaryrefslogtreecommitdiff
path: root/base/win
diff options
context:
space:
mode:
authorCronet Mainline Eng <cronet-mainline-eng+copybara@google.com>2023-08-14 17:15:38 +0000
committerMohannad Farrag <aymanm@google.com>2023-08-14 17:22:36 +0000
commitec3a8e8db24bb3ce4b078106b358ca1c4389c14f (patch)
tree823f64849ad509483bfebb2252199a5fe79b8e43 /base/win
parentd12afe756882b2521faa0b33cbd4813fcea04c22 (diff)
downloadcronet-ec3a8e8db24bb3ce4b078106b358ca1c4389c14f.tar.gz
Import Cronet version 117.0.5938.0
Project import generated by Copybara. FolderOrigin-RevId: /tmp/copybara-origin/src Change-Id: Ib7683d0ed240e11ed9068152600c8092afba4571
Diffstat (limited to 'base/win')
-rw-r--r--base/win/com_init_util.cc12
-rw-r--r--base/win/message_window_unittest.cc5
-rw-r--r--base/win/nt_status.cc14
-rw-r--r--base/win/registry.cc572
-rw-r--r--base/win/registry.h102
-rw-r--r--base/win/registry_unittest.cc244
-rw-r--r--base/win/scoped_handle_unittest.cc5
-rw-r--r--base/win/scoped_safearray.h5
8 files changed, 229 insertions, 730 deletions
diff --git a/base/win/com_init_util.cc b/base/win/com_init_util.cc
index b7b973c95..9867c1540 100644
--- a/base/win/com_init_util.cc
+++ b/base/win/com_init_util.cc
@@ -4,11 +4,11 @@
#include "base/win/com_init_util.h"
+#include <stdint.h>
#include <windows.h>
-
#include <winternl.h>
+
#include "base/logging.h"
-#include "base/memory/raw_ptr_exclusion.h"
#include "base/notreached.h"
namespace base {
@@ -28,12 +28,8 @@ struct OleTlsData {
MTA = 0x140,
};
- // This field is not a raw_ptr<> because it was filtered by the rewriter for:
- // #reinterpret-cast-trivial-type
- RAW_PTR_EXCLUSION void* thread_base;
- // This field is not a raw_ptr<> because it was filtered by the rewriter for:
- // #reinterpret-cast-trivial-type
- RAW_PTR_EXCLUSION void* sm_allocator;
+ uintptr_t thread_base;
+ uintptr_t sm_allocator;
DWORD apartment_id;
DWORD apartment_flags;
// There are many more fields than this, but for our purposes, we only care
diff --git a/base/win/message_window_unittest.cc b/base/win/message_window_unittest.cc
index c158559fe..9568f0b2f 100644
--- a/base/win/message_window_unittest.cc
+++ b/base/win/message_window_unittest.cc
@@ -7,8 +7,8 @@
#include <windows.h>
#include "base/functional/bind.h"
-#include "base/guid.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/uuid.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -57,7 +57,8 @@ TEST(MessageWindowTest, SendMessage) {
// Verifies that a named window can be found by name.
TEST(MessageWindowTest, FindWindow) {
- std::wstring name = UTF8ToWide(base::GenerateGUID());
+ std::wstring name =
+ UTF8ToWide(base::Uuid::GenerateRandomV4().AsLowercaseString());
win::MessageWindow window;
EXPECT_TRUE(window.CreateNamed(base::BindRepeating(&HandleMessage), name));
diff --git a/base/win/nt_status.cc b/base/win/nt_status.cc
index fc7444292..4dbeb6208 100644
--- a/base/win/nt_status.cc
+++ b/base/win/nt_status.cc
@@ -5,14 +5,8 @@
#include "base/win/nt_status.h"
#include <windows.h>
-#include <winternl.h>
-#include "base/check.h"
-
-using GetLastNtStatusFn = NTSTATUS NTAPI (*)();
-
-constexpr const wchar_t kNtDllName[] = L"ntdll.dll";
-constexpr const char kLastStatusFnName[] = "RtlGetLastNtStatus";
+extern "C" NTSTATUS WINAPI RtlGetLastNtStatus();
namespace base {
namespace win {
@@ -22,10 +16,8 @@ NTSTATUS GetLastNtStatus() {
// LastStatusValue from the returned _TEB structure, except that the public
// _TEB struct definition does not actually specify the location of the
// LastStatusValue field. We avoid depending on such a definition by
- // internally using RtGetLastNtStatus() from ntdll.dll instead.
- static auto* get_last_nt_status = reinterpret_cast<GetLastNtStatusFn>(
- ::GetProcAddress(::GetModuleHandle(kNtDllName), kLastStatusFnName));
- return get_last_nt_status();
+ // internally using RtlGetLastNtStatus() from ntdll.dll instead.
+ return ::RtlGetLastNtStatus();
}
} // namespace win
diff --git a/base/win/registry.cc b/base/win/registry.cc
index 473f5fdc8..9e67b3596 100644
--- a/base/win/registry.cc
+++ b/base/win/registry.cc
@@ -14,16 +14,12 @@
#include <vector>
#include "base/check_op.h"
-#include "base/containers/fixed_flat_map.h"
#include "base/functional/callback.h"
-#include "base/native_library.h"
#include "base/notreached.h"
-#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/string_util_win.h"
#include "base/threading/thread_restrictions.h"
#include "base/win/object_watcher.h"
-#include "base/win/pe_image.h"
#include "base/win/scoped_handle.h"
#include "base/win/shlwapi.h"
@@ -50,326 +46,8 @@ constexpr DWORD kInvalidIterValue = static_cast<DWORD>(-1);
} // namespace
-namespace internal {
-
-// A forwarder to the normal delayloaded Windows Registry API.
-class Standard {
- public:
- static inline LSTATUS CreateKey(HKEY hKey,
- LPCWSTR lpSubKey,
- DWORD Reserved,
- LPWSTR lpClass,
- DWORD dwOptions,
- REGSAM samDesired,
- CONST LPSECURITY_ATTRIBUTES
- lpSecurityAttributes,
- PHKEY phkResult,
- LPDWORD lpdwDisposition) {
- return ::RegCreateKeyExW(hKey, lpSubKey, Reserved, lpClass, dwOptions,
- samDesired, lpSecurityAttributes, phkResult,
- lpdwDisposition);
- }
-
- static inline LSTATUS OpenKey(HKEY hKey,
- LPCWSTR lpSubKey,
- DWORD ulOptions,
- REGSAM samDesired,
- PHKEY phkResult) {
- return ::RegOpenKeyExW(hKey, lpSubKey, ulOptions, samDesired, phkResult);
- }
-
- static inline LSTATUS DeleteKey(HKEY hKey,
- LPCWSTR lpSubKey,
- REGSAM samDesired,
- DWORD Reserved) {
- return ::RegDeleteKeyExW(hKey, lpSubKey, samDesired, Reserved);
- }
-
- static inline LSTATUS QueryInfoKey(HKEY hKey,
- LPWSTR lpClass,
- LPDWORD lpcchClass,
- LPDWORD lpReserved,
- LPDWORD lpcSubKeys,
- LPDWORD lpcbMaxSubKeyLen,
- LPDWORD lpcbMaxClassLen,
- LPDWORD lpcValues,
- LPDWORD lpcbMaxValueNameLen,
- LPDWORD lpcbMaxValueLen,
- LPDWORD lpcbSecurityDescriptor,
- PFILETIME lpftLastWriteTime) {
- return ::RegQueryInfoKeyW(hKey, lpClass, lpcchClass, lpReserved, lpcSubKeys,
- lpcbMaxSubKeyLen, lpcbMaxClassLen, lpcValues,
- lpcbMaxValueNameLen, lpcbMaxValueLen,
- lpcbSecurityDescriptor, lpftLastWriteTime);
- }
-
- static inline LSTATUS EnumKey(HKEY hKey,
- DWORD dwIndex,
- LPWSTR lpName,
- LPDWORD lpcchName,
- LPDWORD lpReserved,
- LPWSTR lpClass,
- LPDWORD lpcchClass,
- PFILETIME lpftLastWriteTime) {
- return ::RegEnumKeyExW(hKey, dwIndex, lpName, lpcchName, lpReserved,
- lpClass, lpcchClass, lpftLastWriteTime);
- }
-
- static inline LSTATUS CloseKey(HKEY hKey) { return ::RegCloseKey(hKey); }
-
- static inline LSTATUS QueryValue(HKEY hKey,
- LPCWSTR lpValueName,
- LPDWORD lpReserved,
- LPDWORD lpType,
- LPBYTE lpData,
- LPDWORD lpcbData) {
- return ::RegQueryValueExW(hKey, lpValueName, lpReserved, lpType, lpData,
- lpcbData);
- }
-
- static inline LSTATUS SetValue(HKEY hKey,
- LPCWSTR lpValueName,
- DWORD Reserved,
- DWORD dwType,
- CONST BYTE* lpData,
- DWORD cbData) {
- return ::RegSetValueExW(hKey, lpValueName, Reserved, dwType, lpData,
- cbData);
- }
-
- static inline LSTATUS DeleteValue(HKEY hKey, LPCWSTR lpValueName) {
- return ::RegDeleteValueW(hKey, lpValueName);
- }
-
- static inline LSTATUS EnumValue(HKEY hKey,
- DWORD dwIndex,
- LPWSTR lpValueName,
- LPDWORD lpcchValueName,
- LPDWORD lpReserved,
- LPDWORD lpType,
- LPBYTE lpData,
- LPDWORD lpcbData) {
- return ::RegEnumValueW(hKey, dwIndex, lpValueName, lpcchValueName,
- lpReserved, lpType, lpData, lpcbData);
- }
-};
-
-// An implementation derived from the export table of advapi32.
-class ExportDerived {
- public:
- static LSTATUS CreateKey(HKEY hKey,
- LPCWSTR lpSubKey,
- DWORD Reserved,
- LPWSTR lpClass,
- DWORD dwOptions,
- REGSAM samDesired,
- CONST LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- PHKEY phkResult,
- LPDWORD lpdwDisposition) {
- if (!ResolveRegistryFunctions() || !reg_create_key_ex_) {
- return ERROR_ERRORS_ENCOUNTERED;
- }
- return reg_create_key_ex_(hKey, lpSubKey, Reserved, lpClass, dwOptions,
- samDesired, lpSecurityAttributes, phkResult,
- lpdwDisposition);
- }
-
- static LSTATUS OpenKey(HKEY hKey,
- LPCWSTR lpSubKey,
- DWORD ulOptions,
- REGSAM samDesired,
- PHKEY phkResult) {
- if (!ResolveRegistryFunctions() || !reg_open_key_ex_) {
- return ERROR_ERRORS_ENCOUNTERED;
- }
- return reg_open_key_ex_(hKey, lpSubKey, ulOptions, samDesired, phkResult);
- }
-
- static LSTATUS DeleteKey(HKEY hKey,
- LPCWSTR lpSubKey,
- REGSAM samDesired,
- DWORD Reserved) {
- if (!ResolveRegistryFunctions() || !reg_delete_key_ex_) {
- return ERROR_ERRORS_ENCOUNTERED;
- }
- return reg_delete_key_ex_(hKey, lpSubKey, samDesired, Reserved);
- }
-
- static LSTATUS QueryInfoKey(HKEY hKey,
- LPWSTR lpClass,
- LPDWORD lpcchClass,
- LPDWORD lpReserved,
- LPDWORD lpcSubKeys,
- LPDWORD lpcbMaxSubKeyLen,
- LPDWORD lpcbMaxClassLen,
- LPDWORD lpcValues,
- LPDWORD lpcbMaxValueNameLen,
- LPDWORD lpcbMaxValueLen,
- LPDWORD lpcbSecurityDescriptor,
- PFILETIME lpftLastWriteTime) {
- if (!ResolveRegistryFunctions() || !reg_query_info_key_) {
- return ERROR_ERRORS_ENCOUNTERED;
- }
- return reg_query_info_key_(hKey, lpClass, lpcchClass, lpReserved,
- lpcSubKeys, lpcbMaxSubKeyLen, lpcbMaxClassLen,
- lpcValues, lpcbMaxValueNameLen, lpcbMaxValueLen,
- lpcbSecurityDescriptor, lpftLastWriteTime);
- }
-
- static LSTATUS EnumKey(HKEY hKey,
- DWORD dwIndex,
- LPWSTR lpName,
- LPDWORD lpcchName,
- LPDWORD lpReserved,
- LPWSTR lpClass,
- LPDWORD lpcchClass,
- PFILETIME lpftLastWriteTime) {
- if (!ResolveRegistryFunctions() || !reg_enum_key_ex_) {
- return ERROR_ERRORS_ENCOUNTERED;
- }
- return reg_enum_key_ex_(hKey, dwIndex, lpName, lpcchName, lpReserved,
- lpClass, lpcchClass, lpftLastWriteTime);
- }
-
- static LSTATUS CloseKey(HKEY hKey) {
- if (!ResolveRegistryFunctions() || !reg_close_key_) {
- return ERROR_ERRORS_ENCOUNTERED;
- }
- return reg_close_key_(hKey);
- }
-
- static LSTATUS QueryValue(HKEY hKey,
- LPCWSTR lpValueName,
- LPDWORD lpReserved,
- LPDWORD lpType,
- LPBYTE lpData,
- LPDWORD lpcbData) {
- if (!ResolveRegistryFunctions() || !reg_query_value_ex_) {
- return ERROR_ERRORS_ENCOUNTERED;
- }
- return reg_query_value_ex_(hKey, lpValueName, lpReserved, lpType, lpData,
- lpcbData);
- }
-
- static LSTATUS SetValue(HKEY hKey,
- LPCWSTR lpValueName,
- DWORD Reserved,
- DWORD dwType,
- CONST BYTE* lpData,
- DWORD cbData) {
- if (!ResolveRegistryFunctions() || !reg_set_value_ex_) {
- return ERROR_ERRORS_ENCOUNTERED;
- }
- return reg_set_value_ex_(hKey, lpValueName, Reserved, dwType, lpData,
- cbData);
- }
-
- static LSTATUS DeleteValue(HKEY hKey, LPCWSTR lpValueName) {
- if (!ResolveRegistryFunctions() || !reg_delete_value_) {
- return ERROR_ERRORS_ENCOUNTERED;
- }
- return reg_delete_value_(hKey, lpValueName);
- }
- static LSTATUS EnumValue(HKEY hKey,
- DWORD dwIndex,
- LPWSTR lpValueName,
- LPDWORD lpcchValueName,
- LPDWORD lpReserved,
- LPDWORD lpType,
- LPBYTE lpData,
- LPDWORD lpcbData) {
- if (!ResolveRegistryFunctions() || !reg_enum_value_) {
- return ERROR_ERRORS_ENCOUNTERED;
- }
-
- return reg_enum_value_(hKey, dwIndex, lpValueName, lpcchValueName,
- lpReserved, lpType, lpData, lpcbData);
- }
-
- private:
- static bool ProcessOneExport(const base::win::PEImage& image,
- DWORD ordinal,
- DWORD hint,
- LPCSTR name,
- PVOID function_addr,
- LPCSTR forward,
- PVOID cookie) {
- if (!name || !function_addr) {
- return true;
- }
-
- static const auto kMap =
- base::MakeFixedFlatMapSorted<base::StringPiece, void**>({
- {"RegCloseKey", reinterpret_cast<void**>(&reg_close_key_)},
- {"RegCreateKeyExW", reinterpret_cast<void**>(&reg_create_key_ex_)},
- {"RegDeleteKeyExW", reinterpret_cast<void**>(&reg_delete_key_ex_)},
- {"RegDeleteValueW", reinterpret_cast<void**>(&reg_delete_value_)},
- {"RegEnumKeyExW", reinterpret_cast<void**>(&reg_enum_key_ex_)},
- {"RegEnumValueW", reinterpret_cast<void**>(&reg_enum_value_)},
- {"RegOpenKeyExW", reinterpret_cast<void**>(&reg_open_key_ex_)},
- {"RegQueryInfoKeyW",
- reinterpret_cast<void**>(&reg_query_info_key_)},
- {"RegQueryValueExW",
- reinterpret_cast<void**>(&reg_query_value_ex_)},
- {"RegSetValueExW", reinterpret_cast<void**>(&reg_set_value_ex_)},
- });
-
- auto* entry = kMap.find(name);
- if (entry == kMap.end()) {
- return true;
- }
-
- static size_t num_init_functions = 0;
- if (!std::exchange(*(entry->second), function_addr)) {
- ++num_init_functions;
- }
-
- bool& fully_resolved = *static_cast<bool*>(cookie);
- fully_resolved = num_init_functions == kMap.size();
- return !fully_resolved;
- }
-
- static bool ResolveRegistryFunctions() {
- static bool initialized = []() {
- base::NativeLibraryLoadError error;
- HMODULE advapi32 = base::PinSystemLibrary(L"advapi32.dll", &error);
- if (!advapi32 || error.code) {
- return false;
- }
- bool fully_resolved = false;
- base::win::PEImage(advapi32).EnumExports(&ProcessOneExport,
- &fully_resolved);
- return fully_resolved;
- }();
- return initialized;
- }
-
- static decltype(::RegCreateKeyExW)* reg_create_key_ex_;
- static decltype(::RegOpenKeyExW)* reg_open_key_ex_;
- static decltype(::RegDeleteKeyExW)* reg_delete_key_ex_;
- static decltype(::RegQueryInfoKeyW)* reg_query_info_key_;
- static decltype(::RegEnumKeyExW)* reg_enum_key_ex_;
- static decltype(::RegCloseKey)* reg_close_key_;
- static decltype(::RegQueryValueExW)* reg_query_value_ex_;
- static decltype(::RegSetValueExW)* reg_set_value_ex_;
- static decltype(::RegDeleteValueW)* reg_delete_value_;
- static decltype(::RegEnumValueW)* reg_enum_value_;
-};
-
-decltype(::RegCreateKeyEx)* ExportDerived::reg_create_key_ex_ = nullptr;
-decltype(::RegOpenKeyExW)* ExportDerived::reg_open_key_ex_ = nullptr;
-decltype(::RegDeleteKeyExW)* ExportDerived::reg_delete_key_ex_ = nullptr;
-decltype(::RegQueryInfoKeyW)* ExportDerived::reg_query_info_key_ = nullptr;
-decltype(::RegEnumKeyExW)* ExportDerived::reg_enum_key_ex_ = nullptr;
-decltype(::RegCloseKey)* ExportDerived::reg_close_key_ = nullptr;
-decltype(::RegQueryValueEx)* ExportDerived::reg_query_value_ex_ = nullptr;
-decltype(::RegSetValueExW)* ExportDerived::reg_set_value_ex_ = nullptr;
-decltype(::RegDeleteValueW)* ExportDerived::reg_delete_value_ = nullptr;
-decltype(::RegEnumValueW)* ExportDerived::reg_enum_value_ = nullptr;
-
// Watches for modifications to a key.
-template <typename Reg>
-class GenericRegKey<Reg>::Watcher : public ObjectWatcher::Delegate {
+class RegKey::Watcher : public ObjectWatcher::Delegate {
public:
Watcher() = default;
@@ -393,9 +71,7 @@ class GenericRegKey<Reg>::Watcher : public ObjectWatcher::Delegate {
ChangeCallback callback_;
};
-template <typename Reg>
-bool GenericRegKey<Reg>::Watcher::StartWatching(HKEY key,
- ChangeCallback callback) {
+bool RegKey::Watcher::StartWatching(HKEY key, ChangeCallback callback) {
DCHECK(key);
DCHECK(callback_.is_null());
@@ -423,24 +99,18 @@ bool GenericRegKey<Reg>::Watcher::StartWatching(HKEY key,
return object_watcher_.StartWatchingOnce(watch_event_.get(), this);
}
-// GenericRegKey<Reg>
-// ----------------------------------------------------------------------
+// RegKey ----------------------------------------------------------------------
-template <typename Reg>
-GenericRegKey<Reg>::GenericRegKey() = default;
+RegKey::RegKey() = default;
-template <typename Reg>
-GenericRegKey<Reg>::GenericRegKey(HKEY key) : key_(key) {}
+RegKey::RegKey(HKEY key) : key_(key) {}
-template <typename Reg>
-GenericRegKey<Reg>::GenericRegKey(HKEY rootkey,
- const wchar_t* subkey,
- REGSAM access) {
+RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
if (rootkey) {
if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK)) {
- Create(rootkey, subkey, access);
+ (void)Create(rootkey, subkey, access);
} else {
- Open(rootkey, subkey, access);
+ (void)Open(rootkey, subkey, access);
}
} else {
DCHECK(!subkey);
@@ -448,8 +118,7 @@ GenericRegKey<Reg>::GenericRegKey(HKEY rootkey,
}
}
-template <typename Reg>
-GenericRegKey<Reg>::GenericRegKey(GenericRegKey<Reg>&& other) noexcept
+RegKey::RegKey(RegKey&& other) noexcept
: key_(other.key_),
wow64access_(other.wow64access_),
key_watcher_(std::move(other.key_watcher_)) {
@@ -457,8 +126,7 @@ GenericRegKey<Reg>::GenericRegKey(GenericRegKey<Reg>&& other) noexcept
other.wow64access_ = 0;
}
-template <typename Reg>
-GenericRegKey<Reg>& GenericRegKey<Reg>::operator=(GenericRegKey<Reg>&& other) {
+RegKey& RegKey::operator=(RegKey&& other) {
Close();
std::swap(key_, other.key_);
std::swap(wow64access_, other.wow64access_);
@@ -466,28 +134,23 @@ GenericRegKey<Reg>& GenericRegKey<Reg>::operator=(GenericRegKey<Reg>&& other) {
return *this;
}
-template <typename Reg>
-GenericRegKey<Reg>::~GenericRegKey() {
+RegKey::~RegKey() {
Close();
}
-template <typename Reg>
-LONG GenericRegKey<Reg>::Create(HKEY rootkey,
- const wchar_t* subkey,
- REGSAM access) {
+LONG RegKey::Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
DWORD disposition_value;
return CreateWithDisposition(rootkey, subkey, &disposition_value, access);
}
-template <typename Reg>
-LONG GenericRegKey<Reg>::CreateWithDisposition(HKEY rootkey,
- const wchar_t* subkey,
- DWORD* disposition,
- REGSAM access) {
+LONG RegKey::CreateWithDisposition(HKEY rootkey,
+ const wchar_t* subkey,
+ DWORD* disposition,
+ REGSAM access) {
DCHECK(rootkey && subkey && access && disposition);
HKEY subhkey = nullptr;
LONG result =
- Reg::CreateKey(rootkey, subkey, 0, nullptr, REG_OPTION_NON_VOLATILE,
+ RegCreateKeyEx(rootkey, subkey, 0, nullptr, REG_OPTION_NON_VOLATILE,
access, nullptr, &subhkey, disposition);
if (result == ERROR_SUCCESS) {
Close();
@@ -498,9 +161,14 @@ LONG GenericRegKey<Reg>::CreateWithDisposition(HKEY rootkey,
return result;
}
-template <typename Reg>
-LONG GenericRegKey<Reg>::CreateKey(const wchar_t* name, REGSAM access) {
+LONG RegKey::CreateKey(const wchar_t* name, REGSAM access) {
DCHECK(name && access);
+
+ if (!Valid()) {
+ // The parent key has not been opened or created.
+ return ERROR_INVALID_HANDLE;
+ }
+
// After the application has accessed an alternate registry view using one
// of the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent
// operations (create, delete, or open) on child registry keys must
@@ -512,7 +180,7 @@ LONG GenericRegKey<Reg>::CreateKey(const wchar_t* name, REGSAM access) {
return ERROR_INVALID_PARAMETER;
}
HKEY subkey = nullptr;
- LONG result = Reg::CreateKey(key_, name, 0, nullptr, REG_OPTION_NON_VOLATILE,
+ LONG result = RegCreateKeyEx(key_, name, 0, nullptr, REG_OPTION_NON_VOLATILE,
access, nullptr, &subkey, nullptr);
if (result == ERROR_SUCCESS) {
Close();
@@ -523,14 +191,11 @@ LONG GenericRegKey<Reg>::CreateKey(const wchar_t* name, REGSAM access) {
return result;
}
-template <typename Reg>
-LONG GenericRegKey<Reg>::Open(HKEY rootkey,
- const wchar_t* subkey,
- REGSAM access) {
+LONG RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
DCHECK(rootkey && subkey && access);
HKEY subhkey = nullptr;
- LONG result = Reg::OpenKey(rootkey, subkey, 0, access, &subhkey);
+ LONG result = RegOpenKeyEx(rootkey, subkey, 0, access, &subhkey);
if (result == ERROR_SUCCESS) {
Close();
key_ = subhkey;
@@ -540,10 +205,14 @@ LONG GenericRegKey<Reg>::Open(HKEY rootkey,
return result;
}
-template <typename Reg>
-LONG GenericRegKey<Reg>::OpenKey(const wchar_t* relative_key_name,
- REGSAM access) {
+LONG RegKey::OpenKey(const wchar_t* relative_key_name, REGSAM access) {
DCHECK(relative_key_name && access);
+
+ if (!Valid()) {
+ // The parent key has not been opened or created.
+ return ERROR_INVALID_HANDLE;
+ }
+
// After the application has accessed an alternate registry view using one
// of the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent
// operations (create, delete, or open) on child registry keys must
@@ -555,7 +224,7 @@ LONG GenericRegKey<Reg>::OpenKey(const wchar_t* relative_key_name,
return ERROR_INVALID_PARAMETER;
}
HKEY subkey = nullptr;
- LONG result = Reg::OpenKey(key_, relative_key_name, 0, access, &subkey);
+ LONG result = RegOpenKeyEx(key_, relative_key_name, 0, access, &subkey);
// We have to close the current opened key before replacing it with the new
// one.
@@ -567,62 +236,54 @@ LONG GenericRegKey<Reg>::OpenKey(const wchar_t* relative_key_name,
return result;
}
-template <typename Reg>
-void GenericRegKey<Reg>::Close() {
+void RegKey::Close() {
if (key_) {
- Reg::CloseKey(key_);
+ ::RegCloseKey(key_);
key_ = nullptr;
wow64access_ = 0;
}
}
-// TODO(wfh): Remove this and other unsafe methods. See
-// http://crbug.com/375400
-template <typename Reg>
-void GenericRegKey<Reg>::Set(HKEY key) {
+// TODO(wfh): Remove this and other unsafe methods. See http://crbug.com/375400
+void RegKey::Set(HKEY key) {
if (key_ != key) {
Close();
key_ = key;
}
}
-template <typename Reg>
-HKEY GenericRegKey<Reg>::Take() {
+HKEY RegKey::Take() {
DCHECK_EQ(wow64access_, 0u);
HKEY key = key_;
key_ = nullptr;
return key;
}
-template <typename Reg>
-bool GenericRegKey<Reg>::HasValue(const wchar_t* name) const {
- return Reg::QueryValue(key_, name, nullptr, nullptr, nullptr, nullptr) ==
+bool RegKey::HasValue(const wchar_t* name) const {
+ return RegQueryValueEx(key_, name, nullptr, nullptr, nullptr, nullptr) ==
ERROR_SUCCESS;
}
-template <typename Reg>
-DWORD GenericRegKey<Reg>::GetValueCount() const {
+DWORD RegKey::GetValueCount() const {
DWORD count = 0;
LONG result =
- Reg::QueryInfoKey(key_, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, &count, nullptr, nullptr, nullptr, nullptr);
+ RegQueryInfoKey(key_, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, &count, nullptr, nullptr, nullptr, nullptr);
return (result == ERROR_SUCCESS) ? count : 0;
}
-template <typename Reg>
-FILETIME GenericRegKey<Reg>::GetLastWriteTime() const {
+FILETIME RegKey::GetLastWriteTime() const {
FILETIME last_write_time;
- LONG result = Reg::QueryInfoKey(key_, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, &last_write_time);
+ LONG result = RegQueryInfoKey(key_, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, &last_write_time);
return (result == ERROR_SUCCESS) ? last_write_time : FILETIME{};
}
-template <typename Reg>
-LONG GenericRegKey<Reg>::GetValueNameAt(DWORD index, std::wstring* name) const {
+LONG RegKey::GetValueNameAt(DWORD index, std::wstring* name) const {
wchar_t buf[256];
DWORD bufsize = std::size(buf);
- LONG r = Reg::EnumValue(key_, index, buf, &bufsize, nullptr, nullptr, nullptr,
+ LONG r = ::RegEnumValue(key_, index, buf, &bufsize, nullptr, nullptr, nullptr,
nullptr);
if (r == ERROR_SUCCESS) {
name->assign(buf, bufsize);
@@ -631,8 +292,7 @@ LONG GenericRegKey<Reg>::GetValueNameAt(DWORD index, std::wstring* name) const {
return r;
}
-template <typename Reg>
-LONG GenericRegKey<Reg>::DeleteKey(const wchar_t* name) {
+LONG RegKey::DeleteKey(const wchar_t* name) {
DCHECK(name);
// Verify the key exists before attempting delete to replicate previous
@@ -640,23 +300,22 @@ LONG GenericRegKey<Reg>::DeleteKey(const wchar_t* name) {
// `RegOpenKeyEx()` will return an error if `key_` is invalid.
HKEY subkey = nullptr;
LONG result =
- Reg::OpenKey(key_, name, 0, READ_CONTROL | wow64access_, &subkey);
+ RegOpenKeyEx(key_, name, 0, READ_CONTROL | wow64access_, &subkey);
if (result != ERROR_SUCCESS) {
return result;
}
- Reg::CloseKey(subkey);
+ RegCloseKey(subkey);
return RegDelRecurse(key_, name, wow64access_);
}
-template <typename Reg>
-LONG GenericRegKey<Reg>::DeleteEmptyKey(const wchar_t* name) {
+LONG RegKey::DeleteEmptyKey(const wchar_t* name) {
DCHECK(name);
// `RegOpenKeyEx()` will return an error if `key_` is invalid.
HKEY target_key = nullptr;
LONG result =
- Reg::OpenKey(key_, name, 0, KEY_READ | wow64access_, &target_key);
+ RegOpenKeyEx(key_, name, 0, KEY_READ | wow64access_, &target_key);
if (result != ERROR_SUCCESS) {
return result;
@@ -664,10 +323,10 @@ LONG GenericRegKey<Reg>::DeleteEmptyKey(const wchar_t* name) {
DWORD count = 0;
result =
- Reg::QueryInfoKey(target_key, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, &count, nullptr, nullptr, nullptr, nullptr);
+ RegQueryInfoKey(target_key, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, &count, nullptr, nullptr, nullptr, nullptr);
- Reg::CloseKey(target_key);
+ RegCloseKey(target_key);
if (result != ERROR_SUCCESS) {
return result;
@@ -680,16 +339,13 @@ LONG GenericRegKey<Reg>::DeleteEmptyKey(const wchar_t* name) {
return ERROR_DIR_NOT_EMPTY;
}
-template <typename Reg>
-LONG GenericRegKey<Reg>::DeleteValue(const wchar_t* value_name) {
+LONG RegKey::DeleteValue(const wchar_t* value_name) {
// `RegDeleteValue()` will return an error if `key_` is invalid.
- LONG result = Reg::DeleteValue(key_, value_name);
+ LONG result = RegDeleteValue(key_, value_name);
return result;
}
-template <typename Reg>
-LONG GenericRegKey<Reg>::ReadValueDW(const wchar_t* name,
- DWORD* out_value) const {
+LONG RegKey::ReadValueDW(const wchar_t* name, DWORD* out_value) const {
DCHECK(out_value);
DWORD type = REG_DWORD;
DWORD size = sizeof(DWORD);
@@ -706,9 +362,7 @@ LONG GenericRegKey<Reg>::ReadValueDW(const wchar_t* name,
return result;
}
-template <typename Reg>
-LONG GenericRegKey<Reg>::ReadInt64(const wchar_t* name,
- int64_t* out_value) const {
+LONG RegKey::ReadInt64(const wchar_t* name, int64_t* out_value) const {
DCHECK(out_value);
DWORD type = REG_QWORD;
int64_t local_value = 0;
@@ -726,9 +380,7 @@ LONG GenericRegKey<Reg>::ReadInt64(const wchar_t* name,
return result;
}
-template <typename Reg>
-LONG GenericRegKey<Reg>::ReadValue(const wchar_t* name,
- std::wstring* out_value) const {
+LONG RegKey::ReadValue(const wchar_t* name, std::wstring* out_value) const {
DCHECK(out_value);
const size_t kMaxStringLength = 1024; // This is after expansion.
// Use the one of the other forms of ReadValue if 1024 is too small for you.
@@ -758,19 +410,17 @@ LONG GenericRegKey<Reg>::ReadValue(const wchar_t* name,
return result;
}
-template <typename Reg>
-LONG GenericRegKey<Reg>::ReadValue(const wchar_t* name,
- void* data,
- DWORD* dsize,
- DWORD* dtype) const {
- LONG result = Reg::QueryValue(key_, name, nullptr, dtype,
+LONG RegKey::ReadValue(const wchar_t* name,
+ void* data,
+ DWORD* dsize,
+ DWORD* dtype) const {
+ LONG result = RegQueryValueEx(key_, name, nullptr, dtype,
reinterpret_cast<LPBYTE>(data), dsize);
return result;
}
-template <typename Reg>
-LONG GenericRegKey<Reg>::ReadValues(const wchar_t* name,
- std::vector<std::wstring>* values) {
+LONG RegKey::ReadValues(const wchar_t* name,
+ std::vector<std::wstring>* values) {
values->clear();
DWORD type = REG_MULTI_SZ;
@@ -791,8 +441,8 @@ LONG GenericRegKey<Reg>::ReadValues(const wchar_t* name,
}
// Parse the double-null-terminated list of strings.
- // Note: This code is paranoid to not read outside of |buf|, in the case
- // where it may not be properly terminated.
+ // Note: This code is paranoid to not read outside of |buf|, in the case where
+ // it may not be properly terminated.
auto entry = buffer.cbegin();
auto buffer_end = buffer.cend();
while (entry < buffer_end && *entry != '\0') {
@@ -803,15 +453,12 @@ LONG GenericRegKey<Reg>::ReadValues(const wchar_t* name,
return 0;
}
-template <typename Reg>
-LONG GenericRegKey<Reg>::WriteValue(const wchar_t* name, DWORD in_value) {
+LONG RegKey::WriteValue(const wchar_t* name, DWORD in_value) {
return WriteValue(name, &in_value, static_cast<DWORD>(sizeof(in_value)),
REG_DWORD);
}
-template <typename Reg>
-LONG GenericRegKey<Reg>::WriteValue(const wchar_t* name,
- const wchar_t* in_value) {
+LONG RegKey::WriteValue(const wchar_t* name, const wchar_t* in_value) {
return WriteValue(
name, in_value,
static_cast<DWORD>(sizeof(*in_value) *
@@ -819,21 +466,19 @@ LONG GenericRegKey<Reg>::WriteValue(const wchar_t* name,
REG_SZ);
}
-template <typename Reg>
-LONG GenericRegKey<Reg>::WriteValue(const wchar_t* name,
- const void* data,
- DWORD dsize,
- DWORD dtype) {
+LONG RegKey::WriteValue(const wchar_t* name,
+ const void* data,
+ DWORD dsize,
+ DWORD dtype) {
DCHECK(data || !dsize);
LONG result =
- Reg::SetValue(key_, name, 0, dtype,
+ RegSetValueEx(key_, name, 0, dtype,
reinterpret_cast<LPBYTE>(const_cast<void*>(data)), dsize);
return result;
}
-template <typename Reg>
-bool GenericRegKey<Reg>::StartWatching(ChangeCallback callback) {
+bool RegKey::StartWatching(ChangeCallback callback) {
if (!key_watcher_) {
key_watcher_ = std::make_unique<Watcher>();
}
@@ -846,18 +491,15 @@ bool GenericRegKey<Reg>::StartWatching(ChangeCallback callback) {
}
// static
-template <typename Reg>
-LONG GenericRegKey<Reg>::RegDelRecurse(HKEY root_key,
- const wchar_t* name,
- REGSAM access) {
+LONG RegKey::RegDelRecurse(HKEY root_key, const wchar_t* name, REGSAM access) {
// First, see if the key can be deleted without having to recurse.
- LONG result = Reg::DeleteKey(root_key, name, access, 0);
+ LONG result = RegDeleteKeyEx(root_key, name, access, 0);
if (result == ERROR_SUCCESS) {
return result;
}
HKEY target_key = nullptr;
- result = Reg::OpenKey(root_key, name, 0, KEY_ENUMERATE_SUB_KEYS | access,
+ result = RegOpenKeyEx(root_key, name, 0, KEY_ENUMERATE_SUB_KEYS | access,
&target_key);
if (result == ERROR_FILE_NOT_FOUND) {
@@ -881,7 +523,7 @@ LONG GenericRegKey<Reg>::RegDelRecurse(HKEY root_key,
while (result == ERROR_SUCCESS) {
DWORD key_size = kMaxKeyNameLength;
result =
- Reg::EnumKey(target_key, 0, WriteInto(&key_name, kMaxKeyNameLength),
+ RegEnumKeyEx(target_key, 0, WriteInto(&key_name, kMaxKeyNameLength),
&key_size, nullptr, nullptr, nullptr, nullptr);
if (result != ERROR_SUCCESS) {
@@ -897,54 +539,14 @@ LONG GenericRegKey<Reg>::RegDelRecurse(HKEY root_key,
}
}
- Reg::CloseKey(target_key);
+ RegCloseKey(target_key);
// Try again to delete the key.
- result = Reg::DeleteKey(root_key, name, access, 0);
+ result = RegDeleteKeyEx(root_key, name, access, 0);
return result;
}
-// Instantiate the only two allowed versions of GenericRegKey for use by the
-// public base::win::RegKey and base::win::ExportDerivedRegKey.
-template class GenericRegKey<internal::Standard>;
-template class GenericRegKey<internal::ExportDerived>;
-
-} // namespace internal
-
-RegKey::RegKey() : GenericRegKey<internal::Standard>() {}
-RegKey::RegKey(HKEY key) : GenericRegKey<internal::Standard>(key) {}
-RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access)
- : GenericRegKey<internal::Standard>(rootkey, subkey, access) {}
-
-RegKey::RegKey(RegKey&& other) noexcept
- : GenericRegKey<internal::Standard>(std::move(other)) {}
-RegKey& RegKey::operator=(RegKey&& other) {
- GenericRegKey<internal::Standard>::operator=(std::move(other));
- return *this;
-}
-
-RegKey::~RegKey() = default;
-
-ExportDerivedRegKey::ExportDerivedRegKey()
- : GenericRegKey<internal::ExportDerived>() {}
-ExportDerivedRegKey::ExportDerivedRegKey(HKEY key)
- : GenericRegKey<internal::ExportDerived>(key) {}
-ExportDerivedRegKey::ExportDerivedRegKey(HKEY rootkey,
- const wchar_t* subkey,
- REGSAM access)
- : GenericRegKey<internal::ExportDerived>(rootkey, subkey, access) {}
-
-ExportDerivedRegKey::ExportDerivedRegKey(ExportDerivedRegKey&& other) noexcept
- : GenericRegKey<internal::ExportDerived>(std::move(other)) {}
-ExportDerivedRegKey& ExportDerivedRegKey::operator=(
- ExportDerivedRegKey&& other) {
- GenericRegKey<internal::ExportDerived>::operator=(std::move(other));
- return *this;
-}
-
-ExportDerivedRegKey::~ExportDerivedRegKey() = default;
-
// RegistryValueIterator ------------------------------------------------------
RegistryValueIterator::RegistryValueIterator(HKEY root_key,
diff --git a/base/win/registry.h b/base/win/registry.h
index 8e6372a40..4c7b1ae0e 100644
--- a/base/win/registry.h
+++ b/base/win/registry.h
@@ -13,11 +13,8 @@
#include "base/base_export.h"
#include "base/functional/callback_forward.h"
-#include "base/gtest_prod_util.h"
#include "base/win/windows_types.h"
-class ShellUtil;
-
namespace base {
namespace win {
@@ -30,47 +27,43 @@ namespace win {
// is not touched in case of failure.
// * Functions returning LONG indicate success as ERROR_SUCCESS or an
// error as a (non-zero) win32 error code.
-//
-// Most developers should use base::win::RegKey subclass below.
-namespace internal {
-
-class Standard;
-class ExportDerived;
-template <typename T>
-class RegTestTraits;
-
-template <typename Reg>
-class GenericRegKey {
+class BASE_EXPORT RegKey {
public:
// Called from the MessageLoop when the key changes.
using ChangeCallback = OnceCallback<void()>;
- GenericRegKey();
- explicit GenericRegKey(HKEY key);
- GenericRegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access);
- GenericRegKey(GenericRegKey&& other) noexcept;
- GenericRegKey& operator=(GenericRegKey&& other);
+ RegKey();
+ explicit RegKey(HKEY key);
+ RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access);
+ RegKey(RegKey&& other) noexcept;
+ RegKey& operator=(RegKey&& other);
- GenericRegKey(const GenericRegKey&) = delete;
- GenericRegKey& operator=(const GenericRegKey&) = delete;
+ RegKey(const RegKey&) = delete;
+ RegKey& operator=(const RegKey&) = delete;
- virtual ~GenericRegKey();
+ ~RegKey();
- LONG Create(HKEY rootkey, const wchar_t* subkey, REGSAM access);
+ // Creates a new reg key, replacing `this` with a reference to the
+ // newly-opened key. In case of error, `this` is unchanged.
+ [[nodiscard]] LONG Create(HKEY rootkey, const wchar_t* subkey, REGSAM access);
- LONG CreateWithDisposition(HKEY rootkey,
- const wchar_t* subkey,
- DWORD* disposition,
- REGSAM access);
+ // Creates a new reg key, replacing `this` with a reference to the
+ // newly-opened key. In case of error, `this` is unchanged.
+ [[nodiscard]] LONG CreateWithDisposition(HKEY rootkey,
+ const wchar_t* subkey,
+ DWORD* disposition,
+ REGSAM access);
- // Creates a subkey or open it if it already exists.
- LONG CreateKey(const wchar_t* name, REGSAM access);
+ // Creates a subkey or opens it if it already exists. In case of error, `this`
+ // is unchanged.
+ [[nodiscard]] LONG CreateKey(const wchar_t* name, REGSAM access);
- // Opens an existing reg key.
- LONG Open(HKEY rootkey, const wchar_t* subkey, REGSAM access);
+ // Opens an existing reg key, replacing `this` with a reference to the
+ // newly-opened key. In case of error, `this` is unchanged.
+ [[nodiscard]] LONG Open(HKEY rootkey, const wchar_t* subkey, REGSAM access);
// Opens an existing reg key, given the relative key name.
- LONG OpenKey(const wchar_t* relative_key_name, REGSAM access);
+ [[nodiscard]] LONG OpenKey(const wchar_t* relative_key_name, REGSAM access);
// Closes this reg key.
void Close();
@@ -152,8 +145,8 @@ class GenericRegKey {
// Starts watching the key to see if any of its values have changed.
// The key must have been opened with the KEY_NOTIFY access privilege.
// Returns true on success.
- // To stop watching, delete this GenericRegKey object. To continue watching
- // the object after the callback is invoked, call StartWatching again.
+ // To stop watching, delete this RegKey object. To continue watching the
+ // object after the callback is invoked, call StartWatching again.
bool StartWatching(ChangeCallback callback);
HKEY Handle() const { return key_; }
@@ -169,47 +162,6 @@ class GenericRegKey {
std::unique_ptr<Watcher> key_watcher_;
};
-} // namespace internal
-
-// The Windows registry utility class most developers should use.
-class BASE_EXPORT RegKey : public internal::GenericRegKey<internal::Standard> {
- public:
- RegKey();
- explicit RegKey(HKEY key);
- RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access);
- RegKey(RegKey&& other) noexcept;
- RegKey& operator=(RegKey&& other);
-
- RegKey(const RegKey&) = delete;
- RegKey& operator=(const RegKey&) = delete;
-
- ~RegKey() override;
-};
-
-// A Windows registry class that derives its calls directly from advapi32.dll.
-// Generally, you should use RegKey above. Note that use of this API will pin
-// advapi32.dll. If you need to use this class, please reach out to the
-// base/win/OWNERS first.
-class BASE_EXPORT ExportDerivedRegKey
- : public internal::GenericRegKey<internal::ExportDerived> {
- public:
- ExportDerivedRegKey(ExportDerivedRegKey&& other) noexcept;
- ExportDerivedRegKey& operator=(ExportDerivedRegKey&& other);
-
- ExportDerivedRegKey(const ExportDerivedRegKey&) = delete;
- ExportDerivedRegKey& operator=(const ExportDerivedRegKey&) = delete;
-
- ~ExportDerivedRegKey() override;
-
- private:
- friend class ::ShellUtil;
- friend class internal::RegTestTraits<ExportDerivedRegKey>;
-
- ExportDerivedRegKey();
- explicit ExportDerivedRegKey(HKEY key);
- ExportDerivedRegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access);
-};
-
// Iterates the entries found in a particular folder on the registry.
class BASE_EXPORT RegistryValueIterator {
public:
diff --git a/base/win/registry_unittest.cc b/base/win/registry_unittest.cc
index 030d01e02..219144315 100644
--- a/base/win/registry_unittest.cc
+++ b/base/win/registry_unittest.cc
@@ -11,7 +11,6 @@
#include <cstring>
#include <iterator>
-#include <type_traits>
#include <utility>
#include "base/compiler_specific.h"
@@ -20,6 +19,7 @@
#include "base/location.h"
#include "base/memory/scoped_refptr.h"
#include "base/run_loop.h"
+#include "base/strings/strcat.h"
#include "base/test/bind.h"
#include "base/test/mock_callback.h"
#include "base/test/task_environment.h"
@@ -38,7 +38,6 @@ constexpr wchar_t kRootKey[] = L"Base_Registry_Unittest";
// A test harness for registry tests that operate in HKCU. Each test is given
// a valid key distinct from that used by other tests.
-template <typename Traits>
class RegistryTest : public testing::Test {
protected:
RegistryTest() : root_key_(std::wstring(L"Software\\") + kRootKey) {}
@@ -48,8 +47,7 @@ class RegistryTest : public testing::Test {
registry_override_.OverrideRegistry(HKEY_CURRENT_USER));
// Create the test's root key.
- typename Traits::RegType key(
- Traits::Create(HKEY_CURRENT_USER, L"", KEY_CREATE_SUB_KEY));
+ RegKey key(HKEY_CURRENT_USER, L"", KEY_CREATE_SUB_KEY);
ASSERT_NE(ERROR_SUCCESS,
key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_READ));
ASSERT_EQ(ERROR_SUCCESS,
@@ -67,48 +65,10 @@ class RegistryTest : public testing::Test {
} // namespace
-namespace internal {
+TEST_F(RegistryTest, ValueTest) {
+ RegKey key;
-template <typename T>
-class RegTestTraits {
- public:
- using RegType = T;
-
- static T Create() { return T(); }
-
- static T Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
- return T(rootkey, subkey, access);
- }
-};
-
-} // namespace internal
-
-namespace {
-
-class RegistryTypeNames {
- public:
- template <typename T>
- static std::string GetName(int index) {
- if (std::is_same<typename T::RegType, RegKey>()) {
- return "RegKey";
- }
- if (std::is_same<typename T::RegType, ExportDerivedRegKey>()) {
- return "ExportDerivedRegKey";
- }
- }
-};
-
-} // namespace
-
-using RegistryTypes =
- ::testing::Types<internal::RegTestTraits<RegKey>,
- internal::RegTestTraits<ExportDerivedRegKey>>;
-TYPED_TEST_SUITE(RegistryTest, RegistryTypes, RegistryTypeNames);
-
-TYPED_TEST(RegistryTest, ValueTest) {
- typename TypeParam::RegType key(TypeParam::Create());
-
- ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, this->root_key().c_str(),
+ ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, root_key().c_str(),
KEY_READ | KEY_SET_VALUE));
ASSERT_TRUE(key.Valid());
@@ -159,9 +119,9 @@ TYPED_TEST(RegistryTest, ValueTest) {
EXPECT_FALSE(key.HasValue(kInt64ValueName));
}
-TYPED_TEST(RegistryTest, BigValueIteratorTest) {
- typename TypeParam::RegType key(TypeParam::Create());
- ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, this->root_key().c_str(),
+TEST_F(RegistryTest, BigValueIteratorTest) {
+ RegKey key;
+ ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, root_key().c_str(),
KEY_READ | KEY_SET_VALUE));
ASSERT_TRUE(key.Valid());
@@ -170,7 +130,7 @@ TYPED_TEST(RegistryTest, BigValueIteratorTest) {
ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(data.c_str(), data.c_str()));
- RegistryValueIterator iterator(HKEY_CURRENT_USER, this->root_key().c_str());
+ RegistryValueIterator iterator(HKEY_CURRENT_USER, root_key().c_str());
ASSERT_TRUE(iterator.Valid());
EXPECT_EQ(data, iterator.Name());
EXPECT_EQ(data, iterator.Value());
@@ -180,9 +140,9 @@ TYPED_TEST(RegistryTest, BigValueIteratorTest) {
EXPECT_FALSE(iterator.Valid());
}
-TYPED_TEST(RegistryTest, TruncatedCharTest) {
- typename TypeParam::RegType key(TypeParam::Create());
- ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, this->root_key().c_str(),
+TEST_F(RegistryTest, TruncatedCharTest) {
+ RegKey key;
+ ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, root_key().c_str(),
KEY_READ | KEY_SET_VALUE));
ASSERT_TRUE(key.Valid());
@@ -193,7 +153,7 @@ TYPED_TEST(RegistryTest, TruncatedCharTest) {
ASSERT_EQ(ERROR_SUCCESS,
key.WriteValue(kName, kData, std::size(kData), REG_BINARY));
- RegistryValueIterator iterator(HKEY_CURRENT_USER, this->root_key().c_str());
+ RegistryValueIterator iterator(HKEY_CURRENT_USER, root_key().c_str());
ASSERT_TRUE(iterator.Valid());
// Avoid having to use EXPECT_STREQ here by leveraging StringPiece's
// operator== to perform a deep comparison.
@@ -210,20 +170,19 @@ TYPED_TEST(RegistryTest, TruncatedCharTest) {
}
// Tests that the value iterator is okay with an empty key.
-TYPED_TEST(RegistryTest, ValueIteratorEmptyKey) {
- RegistryValueIterator iterator(HKEY_CURRENT_USER, this->root_key().c_str());
+TEST_F(RegistryTest, ValueIteratorEmptyKey) {
+ RegistryValueIterator iterator(HKEY_CURRENT_USER, root_key().c_str());
EXPECT_EQ(iterator.ValueCount(), 0U);
EXPECT_FALSE(iterator.Valid());
}
// Tests that the default value is seen by a value iterator.
-TYPED_TEST(RegistryTest, ValueIteratorDefaultValue) {
+TEST_F(RegistryTest, ValueIteratorDefaultValue) {
const WStringPiece kTestString(L"i miss you");
- ASSERT_EQ(TypeParam::Create(HKEY_CURRENT_USER, this->root_key().c_str(),
- KEY_SET_VALUE)
+ ASSERT_EQ(RegKey(HKEY_CURRENT_USER, root_key().c_str(), KEY_SET_VALUE)
.WriteValue(nullptr, kTestString.data()),
ERROR_SUCCESS);
- RegistryValueIterator iterator(HKEY_CURRENT_USER, this->root_key().c_str());
+ RegistryValueIterator iterator(HKEY_CURRENT_USER, root_key().c_str());
EXPECT_EQ(iterator.ValueCount(), 1U);
ASSERT_TRUE(iterator.Valid());
EXPECT_EQ(WStringPiece(iterator.Name()), WStringPiece());
@@ -234,8 +193,8 @@ TYPED_TEST(RegistryTest, ValueIteratorDefaultValue) {
EXPECT_FALSE(iterator.Valid());
}
-TYPED_TEST(RegistryTest, RecursiveDelete) {
- typename TypeParam::RegType key(TypeParam::Create());
+TEST_F(RegistryTest, RecursiveDelete) {
+ RegKey key;
// Create root_key()
// \->Bar (TestValue)
// \->Foo (TestValue)
@@ -244,7 +203,7 @@ TYPED_TEST(RegistryTest, RecursiveDelete) {
// \->Moo
// \->Foo
// and delete root_key()
- std::wstring key_path = this->root_key();
+ std::wstring key_path = root_key();
ASSERT_EQ(ERROR_SUCCESS,
key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_CREATE_SUB_KEY));
ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Bar", KEY_WRITE));
@@ -266,7 +225,7 @@ TYPED_TEST(RegistryTest, RecursiveDelete) {
key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_READ));
ASSERT_EQ(ERROR_SUCCESS,
- key.Open(HKEY_CURRENT_USER, this->root_key().c_str(), KEY_WRITE));
+ key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_WRITE));
ASSERT_NE(ERROR_SUCCESS, key.DeleteEmptyKey(L""));
ASSERT_NE(ERROR_SUCCESS, key.DeleteEmptyKey(L"Bar\\Foo"));
ASSERT_NE(ERROR_SUCCESS, key.DeleteEmptyKey(L"Bar"));
@@ -283,33 +242,49 @@ TYPED_TEST(RegistryTest, RecursiveDelete) {
key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_READ));
ASSERT_EQ(ERROR_SUCCESS,
- key.Open(HKEY_CURRENT_USER, this->root_key().c_str(), KEY_WRITE));
+ key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_WRITE));
ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(L"Bar"));
ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(L"Bar"));
ASSERT_NE(ERROR_SUCCESS,
key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_READ));
}
-TYPED_TEST(RegistryTest, OpenSubKey) {
- typename TypeParam::RegType key(TypeParam::Create());
- ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, this->root_key().c_str(),
+TEST_F(RegistryTest, OpenSubKey) {
+ RegKey key;
+ ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, root_key().c_str(),
KEY_READ | KEY_CREATE_SUB_KEY));
ASSERT_NE(ERROR_SUCCESS, key.OpenKey(L"foo", KEY_READ));
ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"foo", KEY_READ));
ASSERT_EQ(ERROR_SUCCESS,
- key.Open(HKEY_CURRENT_USER, this->root_key().c_str(), KEY_READ));
+ key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_READ));
ASSERT_EQ(ERROR_SUCCESS, key.OpenKey(L"foo", KEY_READ));
- std::wstring foo_key = this->root_key() + L"\\Foo";
+ std::wstring foo_key = root_key() + L"\\Foo";
ASSERT_EQ(ERROR_SUCCESS,
key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ));
ASSERT_EQ(ERROR_SUCCESS,
- key.Open(HKEY_CURRENT_USER, this->root_key().c_str(), KEY_WRITE));
+ key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_WRITE));
ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(L"foo"));
}
+TEST_F(RegistryTest, InvalidRelativeKeyCreate) {
+ RegKey key(HKEY_CURRENT_USER,
+ base::StrCat({this->root_key(), L"_DoesNotExist"}).c_str(),
+ KEY_WOW64_32KEY | KEY_READ);
+ ASSERT_EQ(key.CreateKey(L"SomeSubKey", KEY_WOW64_32KEY | KEY_WRITE),
+ ERROR_INVALID_HANDLE);
+}
+
+TEST_F(RegistryTest, InvalidRelativeKeyOpen) {
+ RegKey key(HKEY_CURRENT_USER,
+ base::StrCat({this->root_key(), L"_DoesNotExist"}).c_str(),
+ KEY_WOW64_32KEY | KEY_READ);
+ ASSERT_EQ(key.OpenKey(L"SomeSubKey", KEY_WOW64_32KEY | KEY_READ),
+ ERROR_INVALID_HANDLE);
+}
+
namespace {
class TestChangeDelegate {
@@ -334,23 +309,22 @@ class TestChangeDelegate {
} // namespace
-TYPED_TEST(RegistryTest, ChangeCallback) {
- typename TypeParam::RegType key(TypeParam::Create());
+TEST_F(RegistryTest, ChangeCallback) {
+ RegKey key;
TestChangeDelegate delegate;
test::TaskEnvironment task_environment;
ASSERT_EQ(ERROR_SUCCESS,
- key.Open(HKEY_CURRENT_USER, this->root_key().c_str(), KEY_READ));
+ key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_READ));
ASSERT_TRUE(key.StartWatching(
BindOnce(&TestChangeDelegate::OnKeyChanged, Unretained(&delegate))));
EXPECT_FALSE(delegate.WasCalled());
// Make some change.
- typename TypeParam::RegType key2(TypeParam::Create());
- ASSERT_EQ(ERROR_SUCCESS,
- key2.Open(HKEY_CURRENT_USER, this->root_key().c_str(),
- KEY_READ | KEY_SET_VALUE));
+ RegKey key2;
+ ASSERT_EQ(ERROR_SUCCESS, key2.Open(HKEY_CURRENT_USER, root_key().c_str(),
+ KEY_READ | KEY_SET_VALUE));
ASSERT_TRUE(key2.Valid());
EXPECT_EQ(ERROR_SUCCESS, key2.WriteValue(L"name", L"data"));
@@ -395,21 +369,20 @@ class RegistryWatcherThread : public SimpleThread {
} // namespace
-TYPED_TEST(RegistryTest, WatcherNotSignaledOnInitiatingThreadExit) {
- typename TypeParam::RegType key(TypeParam::Create());
+TEST_F(RegistryTest, WatcherNotSignaledOnInitiatingThreadExit) {
+ RegKey key;
- ASSERT_EQ(key.Open(HKEY_CURRENT_USER, this->root_key().c_str(), KEY_READ),
+ ASSERT_EQ(key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_READ),
ERROR_SUCCESS);
auto test_task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(
base::TestMockTimeTaskRunner::Type::kBoundToThread);
- ::testing::StrictMock<
- base::MockCallback<typename TypeParam::RegType::ChangeCallback>>
+ ::testing::StrictMock<base::MockCallback<base::win::RegKey::ChangeCallback>>
change_cb;
- test_task_runner->PostTask(
- FROM_HERE, BindOnce(IgnoreResult(&TypeParam::RegType::StartWatching),
- Unretained(&key), change_cb.Get()));
+ test_task_runner->PostTask(FROM_HERE,
+ BindOnce(IgnoreResult(&RegKey::StartWatching),
+ Unretained(&key), change_cb.Get()));
{
// Start the watch on a thread that then goes away.
@@ -429,8 +402,8 @@ TYPED_TEST(RegistryTest, WatcherNotSignaledOnInitiatingThreadExit) {
EXPECT_CALL(change_cb, Run).WillOnce([&run_loop]() { run_loop.Quit(); });
// Make some change.
- typename TypeParam::RegType key2(TypeParam::Create());
- ASSERT_EQ(key2.Open(HKEY_CURRENT_USER, this->root_key().c_str(),
+ RegKey key2;
+ ASSERT_EQ(key2.Open(HKEY_CURRENT_USER, root_key().c_str(),
KEY_READ | KEY_SET_VALUE),
ERROR_SUCCESS);
ASSERT_TRUE(key2.Valid());
@@ -440,13 +413,12 @@ TYPED_TEST(RegistryTest, WatcherNotSignaledOnInitiatingThreadExit) {
run_loop.Run();
}
-TYPED_TEST(RegistryTest, TestMoveConstruct) {
- typename TypeParam::RegType key(TypeParam::Create());
+TEST_F(RegistryTest, TestMoveConstruct) {
+ RegKey key;
- ASSERT_EQ(
- key.Open(HKEY_CURRENT_USER, this->root_key().c_str(), KEY_SET_VALUE),
- ERROR_SUCCESS);
- typename TypeParam::RegType key2(std::move(key));
+ ASSERT_EQ(key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_SET_VALUE),
+ ERROR_SUCCESS);
+ RegKey key2(std::move(key));
// The old key should be meaningless now.
EXPECT_EQ(key.Handle(), nullptr);
@@ -456,17 +428,17 @@ TYPED_TEST(RegistryTest, TestMoveConstruct) {
EXPECT_EQ(key2.WriteValue(L"foo", 1U), ERROR_SUCCESS);
}
-TYPED_TEST(RegistryTest, TestMoveAssign) {
- typename TypeParam::RegType key(TypeParam::Create());
- typename TypeParam::RegType key2(TypeParam::Create());
+TEST_F(RegistryTest, TestMoveAssign) {
+ RegKey key;
+ RegKey key2;
const wchar_t kFooValueName[] = L"foo";
- ASSERT_EQ(key.Open(HKEY_CURRENT_USER, this->root_key().c_str(),
+ ASSERT_EQ(key.Open(HKEY_CURRENT_USER, root_key().c_str(),
KEY_SET_VALUE | KEY_QUERY_VALUE),
ERROR_SUCCESS);
ASSERT_EQ(key.WriteValue(kFooValueName, 1U), ERROR_SUCCESS);
- ASSERT_EQ(key2.Create(HKEY_CURRENT_USER,
- (this->root_key() + L"\\child").c_str(), KEY_SET_VALUE),
+ ASSERT_EQ(key2.Create(HKEY_CURRENT_USER, (root_key() + L"\\child").c_str(),
+ KEY_SET_VALUE),
ERROR_SUCCESS);
key2 = std::move(key);
@@ -482,8 +454,8 @@ TYPED_TEST(RegistryTest, TestMoveAssign) {
// Verify that either the platform, or the API-integration, causes deletion
// attempts via an invalid handle to fail with the expected error code.
-TYPED_TEST(RegistryTest, DeleteWithInvalidRegKey) {
- typename TypeParam::RegType key(TypeParam::Create());
+TEST_F(RegistryTest, DeleteWithInvalidRegKey) {
+ RegKey key;
static const wchar_t kFooName[] = L"foo";
@@ -492,12 +464,9 @@ TYPED_TEST(RegistryTest, DeleteWithInvalidRegKey) {
EXPECT_EQ(key.DeleteValue(kFooName), ERROR_INVALID_HANDLE);
}
-namespace {
-
// A test harness for tests that use HKLM to test WoW redirection and such.
// TODO(https://crbug.com/377917): The tests here that write to the registry are
// disabled because they need work to handle parallel runs of different tests.
-template <typename Traits>
class RegistryTestHKLM : public ::testing::Test {
protected:
enum : REGSAM {
@@ -524,17 +493,10 @@ class RegistryTestHKLM : public ::testing::Test {
const std::wstring foo_software_key_;
};
-} // namespace
-
-TYPED_TEST_SUITE(RegistryTestHKLM, RegistryTypes, RegistryTypeNames);
-
-namespace {
-
-template <typename Traits>
-class RegistryTestHKLMAdmin : public RegistryTestHKLM<Traits> {
+class RegistryTestHKLMAdmin : public RegistryTestHKLM {
protected:
void SetUp() override {
- if (!this->IsRedirectorPresent()) {
+ if (!IsRedirectorPresent()) {
GTEST_SKIP();
}
if (!::IsUserAnAdmin()) {
@@ -543,52 +505,50 @@ class RegistryTestHKLMAdmin : public RegistryTestHKLM<Traits> {
// Clean up any stale registry keys.
for (const REGSAM mask :
{this->kNativeViewMask, this->kRedirectedViewMask}) {
- typename Traits::RegType key(Traits::Create());
- key.Open(HKEY_LOCAL_MACHINE, L"Software", KEY_SET_VALUE | mask);
- key.DeleteKey(kRootKey);
+ RegKey key;
+ if (key.Open(HKEY_LOCAL_MACHINE, L"Software", KEY_SET_VALUE | mask) ==
+ ERROR_SUCCESS) {
+ key.DeleteKey(kRootKey);
+ }
}
}
};
-} // namespace
-
-TYPED_TEST_SUITE(RegistryTestHKLMAdmin, RegistryTypes, RegistryTypeNames);
-
// This test requires running as an Administrator as it tests redirected
// registry writes to HKLM\Software
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa384253.aspx
-TYPED_TEST(RegistryTestHKLMAdmin, Wow64RedirectedFromNative) {
- typename TypeParam::RegType key(TypeParam::Create());
+TEST_F(RegistryTestHKLMAdmin, Wow64RedirectedFromNative) {
+ RegKey key;
// Test redirected key access from non-redirected.
ASSERT_EQ(ERROR_SUCCESS,
- key.Create(HKEY_LOCAL_MACHINE, this->foo_software_key_.c_str(),
- KEY_WRITE | this->kRedirectedViewMask));
- ASSERT_NE(ERROR_SUCCESS, key.Open(HKEY_LOCAL_MACHINE,
- this->foo_software_key_.c_str(), KEY_READ));
+ key.Create(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(),
+ KEY_WRITE | kRedirectedViewMask));
ASSERT_NE(ERROR_SUCCESS,
- key.Open(HKEY_LOCAL_MACHINE, this->foo_software_key_.c_str(),
- KEY_READ | this->kNativeViewMask));
+ key.Open(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(), KEY_READ));
+ ASSERT_NE(ERROR_SUCCESS,
+ key.Open(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(),
+ KEY_READ | kNativeViewMask));
// Open the non-redirected view of the parent and try to delete the test key.
ASSERT_EQ(ERROR_SUCCESS,
key.Open(HKEY_LOCAL_MACHINE, L"Software", KEY_SET_VALUE));
ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey));
ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_LOCAL_MACHINE, L"Software",
- KEY_SET_VALUE | this->kNativeViewMask));
+ KEY_SET_VALUE | kNativeViewMask));
ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey));
// Open the redirected view and delete the key created above.
ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_LOCAL_MACHINE, L"Software",
- KEY_SET_VALUE | this->kRedirectedViewMask));
+ KEY_SET_VALUE | kRedirectedViewMask));
ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey));
}
// Test for the issue found in http://crbug.com/384587 where OpenKey would call
// Close() and reset wow64_access_ flag to 0 and cause a NOTREACHED to hit on a
// subsequent OpenKey call.
-TYPED_TEST(RegistryTestHKLM, SameWowFlags) {
- typename TypeParam::RegType key(TypeParam::Create());
+TEST_F(RegistryTestHKLM, SameWowFlags) {
+ RegKey key;
ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_LOCAL_MACHINE, L"Software",
KEY_READ | KEY_WOW64_64KEY));
@@ -597,27 +557,27 @@ TYPED_TEST(RegistryTestHKLM, SameWowFlags) {
ASSERT_EQ(ERROR_SUCCESS, key.OpenKey(L"Windows", KEY_READ | KEY_WOW64_64KEY));
}
-TYPED_TEST(RegistryTestHKLMAdmin, Wow64NativeFromRedirected) {
- typename TypeParam::RegType key(TypeParam::Create());
+TEST_F(RegistryTestHKLMAdmin, Wow64NativeFromRedirected) {
+ RegKey key;
// Test non-redirected key access from redirected.
ASSERT_EQ(ERROR_SUCCESS,
- key.Create(HKEY_LOCAL_MACHINE, this->foo_software_key_.c_str(),
- KEY_WRITE | this->kNativeViewMask));
- ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_LOCAL_MACHINE,
- this->foo_software_key_.c_str(), KEY_READ));
+ key.Create(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(),
+ KEY_WRITE | kNativeViewMask));
+ ASSERT_EQ(ERROR_SUCCESS,
+ key.Open(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(), KEY_READ));
ASSERT_NE(ERROR_SUCCESS,
- key.Open(HKEY_LOCAL_MACHINE, this->foo_software_key_.c_str(),
- KEY_READ | this->kRedirectedViewMask));
+ key.Open(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(),
+ KEY_READ | kRedirectedViewMask));
// Open the redirected view of the parent and try to delete the test key
// from the non-redirected view.
ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_LOCAL_MACHINE, L"Software",
- KEY_SET_VALUE | this->kRedirectedViewMask));
+ KEY_SET_VALUE | kRedirectedViewMask));
ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey));
ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_LOCAL_MACHINE, L"Software",
- KEY_SET_VALUE | this->kNativeViewMask));
+ KEY_SET_VALUE | kNativeViewMask));
ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey));
}
diff --git a/base/win/scoped_handle_unittest.cc b/base/win/scoped_handle_unittest.cc
index 42aefebfa..364254277 100644
--- a/base/win/scoped_handle_unittest.cc
+++ b/base/win/scoped_handle_unittest.cc
@@ -9,7 +9,6 @@
#include <string>
#include <utility>
-#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/scoped_native_library.h"
@@ -153,11 +152,7 @@ TEST_F(ScopedHandleDeathTest, HandleVerifierUntrackedHandle) {
#endif
TEST_F(ScopedHandleTest, MAYBE_MultiProcess) {
- // Initializing ICU in the child process causes a scoped handle to be created
- // before the test gets a chance to test the race condition, so disable ICU
- // for the child process here.
CommandLine command_line(base::GetMultiProcessTestChildBaseCommandLine());
- command_line.AppendSwitch(switches::kTestDoNotInitializeIcu);
base::Process test_child_process = base::SpawnMultiProcessTestChild(
"HandleVerifierChildProcess", command_line, LaunchOptions());
diff --git a/base/win/scoped_safearray.h b/base/win/scoped_safearray.h
index d83fdf998..ab604ff63 100644
--- a/base/win/scoped_safearray.h
+++ b/base/win/scoped_safearray.h
@@ -107,8 +107,9 @@ class BASE_EXPORT ScopedSafearray {
array_size_ = 0U;
}
- // This field is not a raw_ptr<> because it was filtered by the rewriter
- // for: #union
+ // Cannot rewrite this pointer to raw_ptr<>, because this pointer
+ // comes from the operating system and may have been laundered
+ // if rewritten it may generate incorrect DPD error.
RAW_PTR_EXCLUSION SAFEARRAY* safearray_ = nullptr;
VARTYPE vartype_ = VT_EMPTY;
pointer array_ = nullptr;