4#include "Stroika/Foundation/StroikaPreComp.h"
6#if qStroika_Platform_Windows
9#error "WINDOWS REQUIRED FOR THIS MODULE"
12#include "Stroika/Foundation/Execution/DLLSupport.h"
13#include "Stroika/Foundation/Execution/Platform/Windows/Exception.h"
21using namespace Stroika::Foundation::Common::Platform::Windows;
23using namespace Stroika::Foundation::Debug;
26using Memory::MakeSharedPtr;
36RegistryKey::RegistryKey (HKEY parentKey,
const String& path, REGSAM samDesired)
37 : fKey_{OpenPath_ (parentKey, path, samDesired)}
46HKEY RegistryKey::OpenPath_ (HKEY parentKey,
const String& path, REGSAM samDesired)
48#if USE_NOISY_TRACE_IN_THIS_MODULE_
52 Require (parentKey !=
nullptr);
53 Require (parentKey != INVALID_HANDLE_VALUE);
55 Require ((samDesired & ~(KEY_WOW64_64KEY | KEY_WOW64_32KEY)) == KEY_READ);
58 Ensure (result !=
nullptr and result != INVALID_HANDLE_VALUE);
65 VariantValue ExtractValue_ (HKEY key,
const TCHAR* path,
bool missingReturnsEmpty)
68 DWORD dwCountInBytes = 0;
69 LONG lResult = ::RegQueryValueExW (key, path,
nullptr, &dwType,
nullptr, &dwCountInBytes);
70 if (lResult == ERROR_SUCCESS) {
75 if (dwCountInBytes != 0) {
76 Assert (dwCountInBytes %
sizeof (
wchar_t) == 0);
77 size_t nChars = dwCountInBytes / 2 - 1;
78 strValue.resize (nChars);
79 ThrowIfNotERROR_SUCCESS (::RegQueryValueExW (key, path,
nullptr, &dwType, (LPBYTE) & (*strValue.begin ()), &dwCountInBytes));
80 Assert (strValue[nChars] ==
'\0');
86 Assert (dwCountInBytes ==
sizeof (DWORD));
88 Assert (dwCountInBytes ==
sizeof (DWORD));
98 else if (lResult == ERROR_FILE_NOT_FOUND and missingReturnsEmpty) {
109#if USE_NOISY_TRACE_IN_THIS_MODULE_
114 using NTSTATUS = LONG;
115#ifndef STATUS_SUCCESS
116 const auto STATUS_SUCCESS{((NTSTATUS)0x00000000L)};
118#ifndef STATUS_BUFFER_TOO_SMALL
119 constexpr auto STATUS_BUFFER_TOO_SMALL{(NTSTATUS)0xC0000023L};
121 std::wstring keyPath;
124 using NtQueryKeyType = DWORD (__stdcall*) (HANDLE KeyHandle,
int KeyInformationClass, PVOID KeyInformation, ULONG Length, PULONG ResultLength);
125 NtQueryKeyType func =
reinterpret_cast<NtQueryKeyType
> (dll.GetProcAddress (
"NtQueryKey"));
127 DWORD result = func (fKey_, 3, 0, 0, &size);
128 if (result == STATUS_BUFFER_TOO_SMALL) {
130 wchar_t* buffer =
new (std::nothrow)
wchar_t[size /
sizeof (
wchar_t)];
131 if (buffer != NULL) {
132 result = func (fKey_, 3, buffer, size, &size);
133 if (result == STATUS_SUCCESS) {
134 buffer[size /
sizeof (wchar_t)] = L
'\0';
135 keyPath = std::wstring (buffer + 2);
146 Require (fKey_ != INVALID_HANDLE_VALUE);
150 size_t lastBackSlash = valuePath.
rfind (
'\\');
151 if (lastBackSlash != SDKString::npos) {
157 catch (
const system_error& e) {
166 return ExtractValue_ (fKey_, valuePath.
As<wstring> ().c_str (),
true);
171 Require (fKey_ != INVALID_HANDLE_VALUE);
178 auto myContext = MakeSharedPtr<Context_> ();
179 myContext->fParentKey = fKey_;
180 auto getNext = [myContext] () -> optional<shared_ptr<RegistryKey>> {
182 DWORD cbName =
static_cast<DWORD
> (achKeyBuf.size ());
184 auto retCode = ::RegEnumKeyEx (myContext->fParentKey, myContext->fCurIndex, achKeyBuf.begin (), &cbName,
nullptr,
nullptr,
nullptr,
nullptr);
185 if (retCode == ERROR_NO_MORE_ITEMS) {
188 if (retCode == ERROR_MORE_DATA) {
189 achKeyBuf.GrowToSize (achKeyBuf.size () * 2);
193 myContext->fCurIndex++;
194 Assert (cbName <= achKeyBuf.size ());
195 achKeyBuf.resize (cbName);
196#if USE_NOISY_TRACE_IN_THIS_MODULE_
197 DbgTrace (
"returning next child key: {}"_f, achKeyBuf);
201 return Traversal::CreateGenerator<shared_ptr<RegistryKey>> (getNext);
207 for (
int i = 0;; ++i) {
209 DWORD cbName =
static_cast<DWORD
> (achKeyBuf.size ());
211 auto retCode = ::RegEnumValue (fKey_, i, achKeyBuf.begin (), &cbName,
nullptr,
nullptr,
nullptr,
nullptr);
212 if (retCode == ERROR_NO_MORE_ITEMS) {
215 if (retCode == ERROR_MORE_DATA) {
216 achKeyBuf.GrowToSize (achKeyBuf.size () * 2);
#define WeakAssert(c)
A WeakAssert() is for things that aren't guaranteed to be true, but are overwhelmingly likely to be t...
#define Stroika_Foundation_Debug_OptionalizeTraceArgs(...)
String is like std::u32string, except it is much easier to use, often much more space efficient,...
static String FromSDKString(const SDKChar *from)
nonvirtual size_t rfind(Character c) const
nonvirtual SDKString AsSDKString() const
nonvirtual String substr(size_t from, size_t count=npos) const
A Mapping uniquely associates two elements: a key and a value (use Assocation to allow multiple value...
nonvirtual bool Add(ArgByValueType< key_type > key, ArgByValueType< mapped_type > newElt, AddReplaceMode addReplaceMode=AddReplaceMode::eAddReplaces)
Simple variant-value (case variant union) object, with (variant) basic types analogous to a value in ...
Exception<> is a replacement (subclass) for any std c++ exception class (e.g. the default 'std::excep...
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
span< CHAR_T, EXTENT > AdjustNulTerminatedStringSpan(span< CHAR_T, EXTENT > s)
often apply this adjustment to return the non-nul string prefix from a span of characters.
void Throw(T &&e2Throw)
like the builtin C++ 'throw', but stamps in the current Activity context and does helpful,...
bool IsA(const error_code &ec, error_condition cond) noexcept
Does this error MEAN the given condition - regardless of how it happens to be represented?