Improve registry enumeration performance (#40828)

* Improve registry enumeration performance - Extend QueryInfo to expose subkey and value counts from RegQueryInfoKeyW, enabling callers to pre-allocate collections. - Add reserve() calls in EnumGuidKeys and EnumValues to eliminate vector reallocations during registry enumeration. These functions are on the critical path for distro listing and plugin loading. - Replace emplace_back(std::make_pair(...)) with direct emplace_back in EnumGuidKeys to avoid unnecessary pair construction overhead. - Eliminate temporary std::wstring allocations in ReportErrorIfFailed by appending a char literal and the LPCWSTR directly instead of constructing intermediate wstring objects for concatenation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Use _Out_opt_ for QueryInfo subkey/value count out-params Address PR review feedback: the new SubKeyCount/ValueCount parameters are output values filled by RegQueryInfoKeyW, so annotate them with _Out_opt_ rather than _In_opt_ for correct SAL/static analysis. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Ben Hillis committed Jun 17, 2026 at 20:11 UTC c85e6ab40a35760f75adca587bc5a0ada7d9efe8
2 files changed +26 -7
src/windows/common/registry.cpp
+19 -6
@@ -76,12 +76,14 @@ void ReportErrorIfFailed(_In_ LSTATUS Error, _In_ HKEY Key, _In_opt_ LPCWSTR Sub
76 auto path = GetKeyPath(Key);
77 if (Subkey != nullptr)
78 {
79 - path += L"\\" + std::wstring(Subkey);
79 + path += L'\\';
80 + path += Subkey;
81 }
82
83 if (Value != nullptr)
84 {
84 - path += L"\\" + std::wstring(Value);
85 + path += L'\\';
86 + path += Value;
87 }
88
89 if (wsl::windows::common::ExecutionContext::ShouldCollectErrorMessage())
@@ -174,6 +176,9 @@ std::vector<std::pair<GUID, std::wstring>> wsl::windows::common::registry::EnumG
176 // Iterate through the provided keys and return a list of all sub-keys that are GUIDs.
177 WCHAR buffer[39];
178 std::vector<std::pair<GUID, std::wstring>> subKeys;
179 + DWORD subKeyCount = 0;
180 + QueryInfo(Key, nullptr, nullptr, nullptr, &subKeyCount);
181 + subKeys.reserve(subKeyCount);
182 DWORD index = 0;
183 for (;;)
184 {
@@ -198,7 +203,7 @@ std::vector<std::pair<GUID, std::wstring>> wsl::windows::common::registry::EnumG
203 continue;
204 }
205
201 - subKeys.emplace_back(std::make_pair(guid.value(), std::wstring(buffer)));
206 + subKeys.emplace_back(guid.value(), std::wstring(buffer));
207 }
208
209 return subKeys;
@@ -208,7 +213,9 @@ std::vector<std::pair<std::wstring, DWORD>> wsl::windows::common::registry::Enum
213 {
214 std::vector<std::pair<std::wstring, DWORD>> values;
215 DWORD maxValueNameSize = 0;
211 - QueryInfo(Key, nullptr, &maxValueNameSize);
216 + DWORD valueCount = 0;
217 + QueryInfo(Key, nullptr, &maxValueNameSize, nullptr, nullptr, &valueCount);
218 + values.reserve(valueCount);
219
220 for (DWORD Index = 0;; Index++)
221 {
@@ -314,10 +321,16 @@ wil::unique_hkey wsl::windows::common::registry::OpenOrCreateLxssDiskMountsKey(_
321 return CreateKey(HKEY_LOCAL_MACHINE, path.c_str(), KEY_ALL_ACCESS, nullptr, REG_OPTION_VOLATILE);
322 }
323
317 -void wsl::windows::common::registry::QueryInfo(_In_ HKEY Key, _In_opt_ DWORD* MaxSubKeySize, _In_opt_ DWORD* MaxValueNameSize, _In_opt_ DWORD* MaxValueDataSize)
324 +void wsl::windows::common::registry::QueryInfo(
325 + _In_ HKEY Key,
326 + _In_opt_ DWORD* MaxSubKeySize,
327 + _In_opt_ DWORD* MaxValueNameSize,
328 + _In_opt_ DWORD* MaxValueDataSize,
329 + _Out_opt_ DWORD* SubKeyCount,
330 + _Out_opt_ DWORD* ValueCount)
331 {
332 const auto error = (RegQueryInfoKeyW(
320 - Key, nullptr, nullptr, nullptr, nullptr, MaxSubKeySize, nullptr, nullptr, MaxValueNameSize, MaxValueDataSize, nullptr, nullptr));
333 + Key, nullptr, nullptr, nullptr, SubKeyCount, MaxSubKeySize, nullptr, ValueCount, MaxValueNameSize, MaxValueDataSize, nullptr, nullptr));
334
335 ReportErrorIfFailed(error, Key, nullptr, nullptr);
336 }
src/windows/common/registry.hpp
+7 -1
@@ -53,7 +53,13 @@ wil::unique_hkey OpenLxssUserKey();
53
54 wil::unique_hkey OpenOrCreateLxssDiskMountsKey(_In_ PSID UserSid);
55
56 -void QueryInfo(_In_ HKEY Key, _In_opt_ DWORD* MaxSubKeySize = nullptr, _In_opt_ DWORD* MaxValueNameSize = nullptr, _In_opt_ DWORD* MaxValueDataSize = nullptr);
56 +void QueryInfo(
57 + _In_ HKEY Key,
58 + _In_opt_ DWORD* MaxSubKeySize = nullptr,
59 + _In_opt_ DWORD* MaxValueNameSize = nullptr,
60 + _In_opt_ DWORD* MaxValueDataSize = nullptr,
61 + _Out_opt_ DWORD* SubKeyCount = nullptr,
62 + _Out_opt_ DWORD* ValueCount = nullptr);
63
64 DWORD
65 ReadDword(_In_ HKEY Key, _In_opt_ LPCWSTR KeyName, _In_opt_ LPCWSTR ValueName, _In_ DWORD DefaultValue);