WinStd
Additional templates and function helpers for Microsoft Windows using Standard C++ classes
Win.h
1/*
2 SPDX-License-Identifier: MIT
3 Copyright © 1991-2022 Amebis
4 Copyright © 2016 GÉANT
5*/
6
7#pragma once
8
9#include "Common.h"
10#include <string>
11#include <vector>
12
13#pragma warning(push)
14#pragma warning(disable: 4505) // Don't warn on unused code
15
21
23template<class _Traits, class _Ax>
24static DWORD GetModuleFileNameA(_In_opt_ HMODULE hModule, _Out_ std::basic_string<char, _Traits, _Ax> &sValue) noexcept
25{
26 assert(0); // TODO: Test this code.
27
28 char szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(char)];
29
30 // Try with stack buffer first.
31 DWORD dwResult = ::GetModuleFileNameA(hModule, szStackBuffer, _countof(szStackBuffer));
32 if (dwResult < _countof(szStackBuffer)) {
33 // Copy from stack.
34 sValue.assign(szStackBuffer, dwResult);
35 return dwResult;
36 } else {
37 for (DWORD dwCapacity = 2*WINSTD_STACK_BUFFER_BYTES/sizeof(char);; dwCapacity *= 2) {
38 // Allocate on heap and retry.
39 std::unique_ptr<char[]> szBuffer(new char[dwCapacity]);
40 dwResult = ::GetModuleFileNameA(hModule, szBuffer.get(), dwCapacity);
41 if (dwResult < dwCapacity) {
42 sValue.assign(szBuffer.get(), dwResult);
43 return dwResult;
44 }
45 }
46 }
47}
48
54template<class _Traits, class _Ax>
55static DWORD GetModuleFileNameW(_In_opt_ HMODULE hModule, _Out_ std::basic_string<wchar_t, _Traits, _Ax> &sValue) noexcept
56{
57 wchar_t szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t)];
58
59 // Try with stack buffer first.
60 DWORD dwResult = ::GetModuleFileNameW(hModule, szStackBuffer, _countof(szStackBuffer));
61 if (dwResult < _countof(szStackBuffer)) {
62 // Copy from stack.
63 sValue.assign(szStackBuffer, dwResult);
64 return dwResult;
65 } else {
66 for (DWORD dwCapacity = 2*WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t);; dwCapacity *= 2) {
67 // Allocate on heap and retry.
68 std::unique_ptr<wchar_t[]> szBuffer(new wchar_t[dwCapacity]);
69 dwResult = ::GetModuleFileNameW(hModule, szBuffer.get(), dwCapacity);
70 if (dwResult < dwCapacity) {
71 sValue.assign(szBuffer.get(), dwResult);
72 return dwResult;
73 }
74 }
75 }
76}
77
79template<class _Traits, class _Ax>
80static _Success_(return != 0) int GetWindowTextA(_In_ HWND hWnd, _Out_ std::basic_string<char, _Traits, _Ax> &sValue) noexcept
81{
82 assert(0); // TODO: Test this code.
83
84 int iResult;
85
86 // Query the final string length first.
87 iResult = ::GetWindowTextLengthA(hWnd);
88 if (iResult > 0) {
89 if (++iResult < WINSTD_STACK_BUFFER_BYTES/sizeof(char)) {
90 // Read string data to stack.
91 char szBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(char)];
92 iResult = ::GetWindowTextA(hWnd, szBuffer, _countof(szBuffer));
93 sValue.assign(szBuffer, iResult);
94 } else {
95 // Allocate buffer on heap and read the string data into it.
96 std::unique_ptr<char[]> szBuffer(new char[++iResult]);
97 iResult = ::GetWindowTextA(hWnd, szBuffer.get(), iResult);
98 sValue.assign(szBuffer.get(), iResult);
99 }
100 return iResult;
101 }
102
103 sValue.clear();
104 return 0;
105}
106
112template<class _Traits, class _Ax>
113static _Success_(return != 0) int GetWindowTextW(_In_ HWND hWnd, _Out_ std::basic_string<wchar_t, _Traits, _Ax> &sValue) noexcept
114{
115 assert(0); // TODO: Test this code.
116
117 int iResult;
118
119 // Query the final string length first.
120 iResult = ::GetWindowTextLengthW(hWnd);
121 if (iResult > 0) {
122 if (++iResult < WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t)) {
123 // Read string data to stack.
124 wchar_t szBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t)];
125 iResult = ::GetWindowTextW(hWnd, szBuffer, _countof(szBuffer));
126 sValue.assign(szBuffer, iResult);
127 } else {
128 // Allocate buffer on heap and read the string data into it.
129 std::unique_ptr<wchar_t[]> szBuffer(new wchar_t[++iResult]);
130 iResult = ::GetWindowTextW(hWnd, szBuffer.get(), iResult);
131 sValue.assign(szBuffer.get(), iResult);
132 }
133 return iResult;
134 }
135
136 sValue.clear();
137 return 0;
138}
139
141template<class _Ty, class _Ax>
142static _Success_(return != 0) BOOL GetFileVersionInfoA(_In_z_ LPCSTR lptstrFilename, __reserved DWORD dwHandle, _Out_ std::vector<_Ty, _Ax> &aValue) noexcept
143{
144 assert(0); // TODO: Test this code.
145
146 // Get version info size.
147 DWORD dwVerInfoSize = ::GetFileVersionInfoSizeA(lptstrFilename, &dwHandle);
148 if (dwVerInfoSize != 0) {
149 // Read version info.
150 aValue.resize((dwVerInfoSize + sizeof(_Ty) - 1) / sizeof(_Ty));
151 return ::GetFileVersionInfoA(lptstrFilename, dwHandle, dwVerInfoSize, aValue.data());
152 } else
153 return FALSE;
154}
155
161template<class _Ty, class _Ax>
162static _Success_(return != 0) BOOL GetFileVersionInfoW(_In_z_ LPCWSTR lptstrFilename, __reserved DWORD dwHandle, _Out_ std::vector<_Ty, _Ax> &aValue) noexcept
163{
164 assert(0); // TODO: Test this code.
165
166 // Get version info size.
167 DWORD dwVerInfoSize = ::GetFileVersionInfoSizeW(lptstrFilename, &dwHandle);
168 if (dwVerInfoSize != 0) {
169 // Read version info.
170 aValue.resize((dwVerInfoSize + sizeof(_Ty) - 1) / sizeof(_Ty));
171 return ::GetFileVersionInfoW(lptstrFilename, dwHandle, dwVerInfoSize, aValue.data());
172 } else
173 return FALSE;
174}
175
177template<class _Traits, class _Ax>
178static _Success_(return != 0) DWORD ExpandEnvironmentStringsA(_In_z_ LPCSTR lpSrc, _Out_ std::basic_string<char, _Traits, _Ax> &sValue) noexcept
179{
180 assert(0); // TODO: Test this code.
181
182 for (DWORD dwSizeOut = (DWORD)strlen(lpSrc) + 0x100;;) {
183 DWORD dwSizeIn = dwSizeOut;
184 std::unique_ptr<char[]> szBuffer(new char[(size_t)dwSizeIn + 2]); // Note: ANSI version requires one extra char.
185 dwSizeOut = ::ExpandEnvironmentStringsA(lpSrc, szBuffer.get(), dwSizeIn);
186 if (dwSizeOut == 0) {
187 // Error or zero-length input.
188 break;
189 } else if (dwSizeOut <= dwSizeIn) {
190 // The buffer was sufficient.
191 sValue.assign(szBuffer.get(), dwSizeOut - 1);
192 return dwSizeOut;
193 }
194 }
195
196 sValue.clear();
197 return 0;
198}
199
205template<class _Traits, class _Ax>
206static _Success_(return != 0) DWORD ExpandEnvironmentStringsW(_In_z_ LPCWSTR lpSrc, _Out_ std::basic_string<wchar_t, _Traits, _Ax> &sValue) noexcept
207{
208 for (DWORD dwSizeOut = (DWORD)wcslen(lpSrc) + 0x100;;) {
209 DWORD dwSizeIn = dwSizeOut;
210 std::unique_ptr<wchar_t[]> szBuffer(new wchar_t[(size_t)dwSizeIn + 1]);
211 dwSizeOut = ::ExpandEnvironmentStringsW(lpSrc, szBuffer.get(), dwSizeIn);
212 if (dwSizeOut == 0) {
213 // Error or zero-length input.
214 break;
215 } else if (dwSizeOut <= dwSizeIn) {
216 // The buffer was sufficient.
217 sValue.assign(szBuffer.get(), dwSizeOut - 1);
218 return dwSizeOut;
219 }
220 }
221
222 sValue.clear();
223 return 0;
224}
225
227template<class _Traits, class _Ax>
228static VOID GuidToStringA(_In_ LPCGUID lpGuid, _Out_ std::basic_string<char, _Traits, _Ax> &str) noexcept
229{
230 assert(0); // TODO: Test this code.
231
232 sprintf(str, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
233 lpGuid->Data1,
234 lpGuid->Data2,
235 lpGuid->Data3,
236 lpGuid->Data4[0], lpGuid->Data4[1],
237 lpGuid->Data4[2], lpGuid->Data4[3], lpGuid->Data4[4], lpGuid->Data4[5], lpGuid->Data4[6], lpGuid->Data4[7]);
238}
239
246template<class _Traits, class _Ax>
247static VOID GuidToStringW(_In_ LPCGUID lpGuid, _Out_ std::basic_string<wchar_t, _Traits, _Ax> &str) noexcept
248{
249 assert(0); // TODO: Test this code.
250
251 sprintf(str, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
252 lpGuid->Data1,
253 lpGuid->Data2,
254 lpGuid->Data3,
255 lpGuid->Data4[0], lpGuid->Data4[1],
256 lpGuid->Data4[2], lpGuid->Data4[3], lpGuid->Data4[4], lpGuid->Data4[5], lpGuid->Data4[6], lpGuid->Data4[7]);
257}
258
260#ifdef _UNICODE
261#define GuidToString GuidToStringW
262#else
263#define GuidToString GuidToStringA
264#endif
265
267static _Success_(return) BOOL StringToGuidA(_In_z_ LPCSTR lpszGuid, _Out_ LPGUID lpGuid, _Out_opt_ LPCSTR *lpszGuidEnd = NULL) noexcept
268{
269 GUID g;
270 LPSTR lpszEnd;
271 unsigned long ulTmp;
272 unsigned long long ullTmp;
273
274 if (!lpszGuid || !lpGuid || *lpszGuid != '{') return FALSE;
275 lpszGuid++;
276
277 g.Data1 = strtoul(lpszGuid, &lpszEnd, 16);
278 if (errno == ERANGE) return FALSE;
279 lpszGuid = lpszEnd;
280
281 if (*lpszGuid != '-') return FALSE;
282 lpszGuid++;
283
284 ulTmp = strtoul(lpszGuid, &lpszEnd, 16);
285 if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE;
286 g.Data2 = static_cast<unsigned short>(ulTmp);
287 lpszGuid = lpszEnd;
288
289 if (*lpszGuid != '-') return FALSE;
290 lpszGuid++;
291
292 ulTmp = strtoul(lpszGuid, &lpszEnd, 16);
293 if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE;
294 g.Data3 = static_cast<unsigned short>(ulTmp);
295 lpszGuid = lpszEnd;
296
297 if (*lpszGuid != '-') return FALSE;
298 lpszGuid++;
299
300 ulTmp = strtoul(lpszGuid, &lpszEnd, 16);
301 if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE;
302 g.Data4[0] = static_cast<unsigned char>((ulTmp >> 8) & 0xff);
303 g.Data4[1] = static_cast<unsigned char>( ulTmp & 0xff);
304 lpszGuid = lpszEnd;
305
306 if (*lpszGuid != '-') return FALSE;
307 lpszGuid++;
308
309 ullTmp = _strtoui64(lpszGuid, &lpszEnd, 16);
310 if (errno == ERANGE || ullTmp > 0xFFFFFFFFFFFF) return FALSE;
311 g.Data4[2] = static_cast<unsigned char>((ullTmp >> 40) & 0xff);
312 g.Data4[3] = static_cast<unsigned char>((ullTmp >> 32) & 0xff);
313 g.Data4[4] = static_cast<unsigned char>((ullTmp >> 24) & 0xff);
314 g.Data4[5] = static_cast<unsigned char>((ullTmp >> 16) & 0xff);
315 g.Data4[6] = static_cast<unsigned char>((ullTmp >> 8) & 0xff);
316 g.Data4[7] = static_cast<unsigned char>( ullTmp & 0xff);
317 lpszGuid = lpszEnd;
318
319 if (*lpszGuid != '}') return FALSE;
320 lpszGuid++;
321
322 if (lpszGuidEnd)
323 *lpszGuidEnd = lpszGuid;
324
325 *lpGuid = g;
326 return TRUE;
327}
328
340static _Success_(return) BOOL StringToGuidW(_In_z_ LPCWSTR lpszGuid, _Out_ LPGUID lpGuid, _Out_opt_ LPCWSTR *lpszGuidEnd = NULL) noexcept
341{
342 GUID g;
343 LPWSTR lpszEnd;
344 unsigned long ulTmp;
345 unsigned long long ullTmp;
346
347 if (!lpszGuid || !lpGuid || *lpszGuid != '{') return FALSE;
348 lpszGuid++;
349
350 g.Data1 = wcstoul(lpszGuid, &lpszEnd, 16);
351 if (errno == ERANGE) return FALSE;
352 lpszGuid = lpszEnd;
353
354 if (*lpszGuid != '-') return FALSE;
355 lpszGuid++;
356
357 ulTmp = wcstoul(lpszGuid, &lpszEnd, 16);
358 if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE;
359 g.Data2 = static_cast<unsigned short>(ulTmp);
360 lpszGuid = lpszEnd;
361
362 if (*lpszGuid != '-') return FALSE;
363 lpszGuid++;
364
365 ulTmp = wcstoul(lpszGuid, &lpszEnd, 16);
366 if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE;
367 g.Data3 = static_cast<unsigned short>(ulTmp);
368 lpszGuid = lpszEnd;
369
370 if (*lpszGuid != '-') return FALSE;
371 lpszGuid++;
372
373 ulTmp = wcstoul(lpszGuid, &lpszEnd, 16);
374 if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE;
375 g.Data4[0] = static_cast<unsigned char>((ulTmp >> 8) & 0xff);
376 g.Data4[1] = static_cast<unsigned char>( ulTmp & 0xff);
377 lpszGuid = lpszEnd;
378
379 if (*lpszGuid != '-') return FALSE;
380 lpszGuid++;
381
382 ullTmp = _wcstoui64(lpszGuid, &lpszEnd, 16);
383 if (errno == ERANGE || ullTmp > 0xFFFFFFFFFFFF) return FALSE;
384 g.Data4[2] = static_cast<unsigned char>((ullTmp >> 40) & 0xff);
385 g.Data4[3] = static_cast<unsigned char>((ullTmp >> 32) & 0xff);
386 g.Data4[4] = static_cast<unsigned char>((ullTmp >> 24) & 0xff);
387 g.Data4[5] = static_cast<unsigned char>((ullTmp >> 16) & 0xff);
388 g.Data4[6] = static_cast<unsigned char>((ullTmp >> 8) & 0xff);
389 g.Data4[7] = static_cast<unsigned char>( ullTmp & 0xff);
390 lpszGuid = lpszEnd;
391
392 if (*lpszGuid != '}') return FALSE;
393 lpszGuid++;
394
395 if (lpszGuidEnd)
396 *lpszGuidEnd = lpszGuid;
397
398 *lpGuid = g;
399 return TRUE;
400}
401
403#ifdef _UNICODE
404#define StringToGuid StringToGuidW
405#else
406#define StringToGuid StringToGuidA
407#endif
408
427template<class _Traits, class _Ax>
428static LSTATUS RegQueryStringValue(_In_ HKEY hReg, _In_z_ LPCSTR pszName, _Out_ std::basic_string<char, _Traits, _Ax> &sValue) noexcept
429{
430 LSTATUS lResult;
431 BYTE aStackBuffer[WINSTD_STACK_BUFFER_BYTES];
432 DWORD dwSize = sizeof(aStackBuffer), dwType;
433
434 // Try with stack buffer first.
435 lResult = ::RegQueryValueExA(hReg, pszName, NULL, &dwType, aStackBuffer, &dwSize);
436 if (lResult == ERROR_SUCCESS) {
437 if (dwType == REG_SZ || dwType == REG_MULTI_SZ) {
438 // The value is REG_SZ or REG_MULTI_SZ.
439 dwSize /= sizeof(CHAR);
440 sValue.assign(reinterpret_cast<LPCSTR>(aStackBuffer), dwSize && reinterpret_cast<LPCSTR>(aStackBuffer)[dwSize - 1] == 0 ? dwSize - 1 : dwSize);
441 } else if (dwType == REG_EXPAND_SZ) {
442 // The value is REG_EXPAND_SZ. Expand it from stack buffer.
443 if (::ExpandEnvironmentStringsA(reinterpret_cast<LPCSTR>(aStackBuffer), sValue) == 0)
444 lResult = ::GetLastError();
445 } else {
446 // The value is not a string type.
447 lResult = ERROR_INVALID_DATA;
448 }
449 } else if (lResult == ERROR_MORE_DATA) {
450 if (dwType == REG_SZ || dwType == REG_MULTI_SZ) {
451 // The value is REG_SZ or REG_MULTI_SZ. Read it now.
452 std::unique_ptr<CHAR[]> szBuffer(new CHAR[dwSize / sizeof(CHAR)]);
453 if ((lResult = ::RegQueryValueExA(hReg, pszName, NULL, NULL, reinterpret_cast<LPBYTE>(szBuffer.get()), &dwSize)) == ERROR_SUCCESS) {
454 dwSize /= sizeof(CHAR);
455 sValue.assign(szBuffer.get(), dwSize && szBuffer[dwSize - 1] == 0 ? dwSize - 1 : dwSize);
456 }
457 } else if (dwType == REG_EXPAND_SZ) {
458 // The value is REG_EXPAND_SZ. Read it and expand environment variables.
459 std::unique_ptr<CHAR[]> szBuffer(new CHAR[dwSize / sizeof(CHAR)]);
460 if ((lResult = ::RegQueryValueExA(hReg, pszName, NULL, NULL, reinterpret_cast<LPBYTE>(szBuffer.get()), &dwSize)) == ERROR_SUCCESS) {
461 if (::ExpandEnvironmentStringsA(szBuffer.get(), sValue) == 0)
462 lResult = ::GetLastError();
463 }
464 } else {
465 // The value is not a string type.
466 lResult = ERROR_INVALID_DATA;
467 }
468 }
469
470 return lResult;
471}
472
491template<class _Traits, class _Ax>
492static LSTATUS RegQueryStringValue(_In_ HKEY hReg, _In_z_ LPCWSTR pszName, _Out_ std::basic_string<wchar_t, _Traits, _Ax> &sValue) noexcept
493{
494 LSTATUS lResult;
495 BYTE aStackBuffer[WINSTD_STACK_BUFFER_BYTES];
496 DWORD dwSize = sizeof(aStackBuffer), dwType;
497
498 // Try with stack buffer first.
499 lResult = ::RegQueryValueExW(hReg, pszName, NULL, &dwType, aStackBuffer, &dwSize);
500 if (lResult == ERROR_SUCCESS) {
501 if (dwType == REG_SZ || dwType == REG_MULTI_SZ) {
502 // The value is REG_SZ or REG_MULTI_SZ.
503 dwSize /= sizeof(WCHAR);
504 sValue.assign(reinterpret_cast<LPCWSTR>(aStackBuffer), dwSize && reinterpret_cast<LPCWSTR>(aStackBuffer)[dwSize - 1] == 0 ? dwSize - 1 : dwSize);
505 } else if (dwType == REG_EXPAND_SZ) {
506 // The value is REG_EXPAND_SZ. Expand it from stack buffer.
507 if (::ExpandEnvironmentStringsW(reinterpret_cast<LPCWSTR>(aStackBuffer), sValue) == 0)
508 lResult = ::GetLastError();
509 } else {
510 // The value is not a string type.
511 lResult = ERROR_INVALID_DATA;
512 }
513 } else if (lResult == ERROR_MORE_DATA) {
514 if (dwType == REG_SZ || dwType == REG_MULTI_SZ) {
515 // The value is REG_SZ or REG_MULTI_SZ. Read it now.
516 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[dwSize / sizeof(WCHAR)]);
517 if ((lResult = ::RegQueryValueExW(hReg, pszName, NULL, NULL, reinterpret_cast<LPBYTE>(szBuffer.get()), &dwSize)) == ERROR_SUCCESS) {
518 dwSize /= sizeof(WCHAR);
519 sValue.assign(szBuffer.get(), dwSize && szBuffer[dwSize - 1] == 0 ? dwSize - 1 : dwSize);
520 }
521 } else if (dwType == REG_EXPAND_SZ) {
522 // The value is REG_EXPAND_SZ. Read it and expand environment variables.
523 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[dwSize / sizeof(WCHAR)]);
524 if ((lResult = ::RegQueryValueExW(hReg, pszName, NULL, NULL, reinterpret_cast<LPBYTE>(szBuffer.get()), &dwSize)) == ERROR_SUCCESS) {
525 if (::ExpandEnvironmentStringsW(szBuffer.get(), sValue) == 0)
526 lResult = ::GetLastError();
527 }
528 } else {
529 // The value is not a string type.
530 lResult = ERROR_INVALID_DATA;
531 }
532 }
533
534 return lResult;
535}
536
538template<class _Ty, class _Ax>
539static LSTATUS RegQueryValueExA(_In_ HKEY hKey, _In_opt_z_ LPCSTR lpValueName, __reserved LPDWORD lpReserved, _Out_opt_ LPDWORD lpType, _Out_ std::vector<_Ty, _Ax> &aData) noexcept
540{
541 LSTATUS lResult;
542 BYTE aStackBuffer[WINSTD_STACK_BUFFER_BYTES];
543 DWORD dwSize = sizeof(aStackBuffer);
544
545 // Try with stack buffer first.
546 lResult = RegQueryValueExA(hKey, lpValueName, lpReserved, lpType, aStackBuffer, &dwSize);
547 if (lResult == ERROR_SUCCESS) {
548 // Copy from stack buffer.
549 aData.resize((dwSize + sizeof(_Ty) - 1) / sizeof(_Ty));
550 memcpy(aData.data(), aStackBuffer, dwSize);
551 } else if (lResult == ERROR_MORE_DATA) {
552 // Allocate buffer on heap and retry.
553 aData.resize((dwSize + sizeof(_Ty) - 1) / sizeof(_Ty));
554 lResult = RegQueryValueExA(hKey, lpValueName, lpReserved, NULL, aData.data(), &dwSize);
555 }
556
557 return lResult;
558}
559
565template<class _Ty, class _Ax>
566static LSTATUS RegQueryValueExW(_In_ HKEY hKey, _In_opt_z_ LPCWSTR lpValueName, __reserved LPDWORD lpReserved, _Out_opt_ LPDWORD lpType, _Out_ std::vector<_Ty, _Ax> &aData) noexcept
567{
568 LSTATUS lResult;
569 BYTE aStackBuffer[WINSTD_STACK_BUFFER_BYTES];
570 DWORD dwSize = sizeof(aStackBuffer);
571
572 // Try with stack buffer first.
573 lResult = RegQueryValueExW(hKey, lpValueName, lpReserved, lpType, aStackBuffer, &dwSize);
574 if (lResult == ERROR_SUCCESS) {
575 // Copy from stack buffer.
576 aData.resize((dwSize + sizeof(_Ty) - 1) / sizeof(_Ty));
577 memcpy(aData.data(), aStackBuffer, dwSize);
578 } else if (lResult == ERROR_MORE_DATA) {
579 // Allocate buffer on heap and retry.
580 aData.resize((dwSize + sizeof(_Ty) - 1) / sizeof(_Ty));
581 lResult = RegQueryValueExW(hKey, lpValueName, lpReserved, NULL, aData.data(), &dwSize);
582 }
583
584 return lResult;
585}
586
587#if _WIN32_WINNT >= _WIN32_WINNT_VISTA
588
590template<class _Traits, class _Ax>
591static LSTATUS RegLoadMUIStringA(_In_ HKEY hKey, _In_opt_z_ LPCSTR pszValue, _Out_ std::basic_string<char, _Traits, _Ax> &sOut, _In_ DWORD Flags, _In_opt_z_ LPCSTR pszDirectory) noexcept
592{
593 // According to "Remarks" section in MSDN documentation of RegLoadMUIString(),
594 // this function is defined but not implemented as ANSI variation.
595 assert(0);
596 return ERROR_CALL_NOT_IMPLEMENTED;
597}
598
604template<class _Traits, class _Ax>
605static LSTATUS RegLoadMUIStringW(_In_ HKEY hKey, _In_opt_z_ LPCWSTR pszValue, _Out_ std::basic_string<wchar_t, _Traits, _Ax> &sOut, _In_ DWORD Flags, _In_opt_z_ LPCWSTR pszDirectory) noexcept
606{
607 LSTATUS lResult;
608 wchar_t szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t)];
609 DWORD dwSize;
610
611 Flags &= ~REG_MUI_STRING_TRUNCATE;
612
613 // Try with stack buffer first.
614 lResult = RegLoadMUIStringW(hKey, pszValue, szStackBuffer, sizeof(szStackBuffer), &dwSize, Flags, pszDirectory);
615 if (lResult == ERROR_SUCCESS) {
616 // Copy from stack buffer.
617 sOut.assign(szStackBuffer, wcsnlen(szStackBuffer, dwSize/sizeof(wchar_t)));
618 } else if (lResult == ERROR_MORE_DATA) {
619 // Allocate buffer on heap and retry.
620 std::unique_ptr<wchar_t[]> szBuffer(new wchar_t[(dwSize + sizeof(wchar_t) - 1)/sizeof(wchar_t)]);
621 sOut.assign(szBuffer.get(), (lResult = RegLoadMUIStringW(hKey, pszValue, szBuffer.get(), dwSize, &dwSize, Flags, pszDirectory)) == ERROR_SUCCESS ? wcsnlen(szBuffer.get(), dwSize/sizeof(wchar_t)) : 0);
622 }
623
624 return lResult;
625}
626
627#endif
628
634template<class _Traits, class _Ax>
635static _Success_(return != 0) int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cchWideChar) LPCWSTR lpWideCharStr, _In_ int cchWideChar, _Out_ std::basic_string<char, _Traits, _Ax> &sMultiByteStr, _In_opt_z_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) noexcept
636{
637 CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)];
638
639 // Try to convert to stack buffer first.
640 int cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar);
641 if (cch) {
642 // Copy from stack. Be careful not to include zero terminator.
643 sMultiByteStr.assign(szStackBuffer, cchWideChar != -1 ? strnlen(szStackBuffer, cch) : (size_t)cch - 1);
644 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
645 // Query the required output size. Allocate buffer. Then convert again.
646 cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, NULL, 0, lpDefaultChar, lpUsedDefaultChar);
647 std::unique_ptr<CHAR[]> szBuffer(new CHAR[cch]);
648 cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szBuffer.get(), cch, lpDefaultChar, lpUsedDefaultChar);
649 sMultiByteStr.assign(szBuffer.get(), cchWideChar != -1 ? strnlen(szBuffer.get(), cch) : (size_t)cch - 1);
650 }
651
652 return cch;
653}
654
660template<class _Ax>
661static _Success_(return != 0) int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cchWideChar) LPCWSTR lpWideCharStr, _In_ int cchWideChar, _Out_ std::vector<char, _Ax> &sMultiByteStr, _In_opt_z_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) noexcept
662{
663 CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)];
664
665 // Try to convert to stack buffer first.
666 int cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar);
667 if (cch) {
668 // Copy from stack.
669 sMultiByteStr.assign(szStackBuffer, szStackBuffer + cch);
670 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
671 // Query the required output size. Allocate buffer. Then convert again.
672 cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, NULL, 0, lpDefaultChar, lpUsedDefaultChar);
673 sMultiByteStr.resize(cch);
674 cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, sMultiByteStr.data(), cch, lpDefaultChar, lpUsedDefaultChar);
675 }
676
677 return cch;
678}
679
685template<class _Traits1, class _Ax1, class _Traits2, class _Ax2>
686static _Success_(return != 0) int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_ std::basic_string<wchar_t, _Traits1, _Ax1> sWideCharStr, _Out_ std::basic_string<char, _Traits2, _Ax2> &sMultiByteStr, _In_opt_z_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) noexcept
687{
688 CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)];
689
690 // Try to convert to stack buffer first.
691 int cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar);
692 if (cch) {
693 // Copy from stack.
694 sMultiByteStr.assign(szStackBuffer, cch);
695 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
696 // Query the required output size. Allocate buffer. Then convert again.
697 cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), NULL, 0, lpDefaultChar, lpUsedDefaultChar);
698 std::unique_ptr<CHAR[]> szBuffer(new CHAR[cch]);
699 cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), szBuffer.get(), cch, lpDefaultChar, lpUsedDefaultChar);
700 sMultiByteStr.assign(szBuffer.get(), cch);
701 }
702
703 return cch;
704}
705
713template<class _Traits, class _Ax>
714static _Success_(return != 0) int SecureWideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cchWideChar) LPCWSTR lpWideCharStr, _In_ int cchWideChar, _Out_ std::basic_string<char, _Traits, _Ax> &sMultiByteStr, _In_opt_z_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) noexcept
715{
716 CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)];
717
718 // Try to convert to stack buffer first.
719 int cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar);
720 if (cch) {
721 // Copy from stack. Be careful not to include zero terminator.
722 sMultiByteStr.assign(szStackBuffer, cchWideChar != -1 ? strnlen(szStackBuffer, cch) : (size_t)cch - 1);
723 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
724 // Query the required output size. Allocate buffer. Then convert again.
725 cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, NULL, 0, lpDefaultChar, lpUsedDefaultChar);
726 std::unique_ptr<CHAR[]> szBuffer(new CHAR[cch]);
727 cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szBuffer.get(), cch, lpDefaultChar, lpUsedDefaultChar);
728 sMultiByteStr.assign(szBuffer.get(), cchWideChar != -1 ? strnlen(szBuffer.get(), cch) : (size_t)cch - 1);
729 SecureZeroMemory(szBuffer.get(), sizeof(CHAR)*cch);
730 }
731
732 SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer));
733
734 return cch;
735}
736
744template<class _Ax>
745static _Success_(return != 0) int SecureWideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cchWideChar) LPCWSTR lpWideCharStr, _In_ int cchWideChar, _Out_ std::vector<char, _Ax> &sMultiByteStr, _In_opt_z_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) noexcept
746{
747 CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)];
748
749 // Try to convert to stack buffer first.
750 int cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar);
751 if (cch) {
752 // Copy from stack.
753 sMultiByteStr.assign(szStackBuffer, szStackBuffer + cch);
754 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
755 // Query the required output size. Allocate buffer. Then convert again.
756 cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, NULL, 0, lpDefaultChar, lpUsedDefaultChar);
757 sMultiByteStr.resize(cch);
758 cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, sMultiByteStr.data(), cch, lpDefaultChar, lpUsedDefaultChar);
759 }
760
761 SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer));
762
763 return cch;
764}
765
773template<class _Traits1, class _Ax1, class _Traits2, class _Ax2>
774static _Success_(return != 0) int SecureWideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _Out_ std::basic_string<wchar_t, _Traits1, _Ax1> sWideCharStr, _Out_ std::basic_string<char, _Traits2, _Ax2> &sMultiByteStr, _In_opt_z_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) noexcept
775{
776 CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)];
777
778 // Try to convert to stack buffer first.
779 int cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar);
780 if (cch) {
781 // Copy from stack.
782 sMultiByteStr.assign(szStackBuffer, cch);
783 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
784 // Query the required output size. Allocate buffer. Then convert again.
785 cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), NULL, 0, lpDefaultChar, lpUsedDefaultChar);
786 std::unique_ptr<CHAR[]> szBuffer(new CHAR[cch]);
787 cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), szBuffer.get(), cch, lpDefaultChar, lpUsedDefaultChar);
788 sMultiByteStr.assign(szBuffer.get(), cch);
789 SecureZeroMemory(szBuffer.get(), sizeof(CHAR)*cch);
790 }
791
792 SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer));
793
794 return cch;
795}
796
802template<class _Traits, class _Ax>
803static _Success_(return != 0) int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cbMultiByte) LPCSTR lpMultiByteStr, _In_ int cbMultiByte, _Out_ std::basic_string<wchar_t, _Traits, _Ax> &sWideCharStr) noexcept
804{
805 WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)];
806
807 // Try to convert to stack buffer first.
808 int cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szStackBuffer, _countof(szStackBuffer));
809 if (cch) {
810 // Copy from stack.
811 sWideCharStr.assign(szStackBuffer, cbMultiByte != -1 ? wcsnlen(szStackBuffer, cch) : (size_t)cch - 1);
812 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
813 // Query the required output size. Allocate buffer. Then convert again.
814 cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, NULL, 0);
815 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[cch]);
816 cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szBuffer.get(), cch);
817 sWideCharStr.assign(szBuffer.get(), cbMultiByte != -1 ? wcsnlen(szBuffer.get(), cch) : (size_t)cch - 1);
818 }
819
820 return cch;
821}
822
828template<class _Ax>
829static _Success_(return != 0) int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cbMultiByte) LPCSTR lpMultiByteStr, _In_ int cbMultiByte, _Out_ std::vector<wchar_t, _Ax> &sWideCharStr) noexcept
830{
831 WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)];
832
833 // Try to convert to stack buffer first.
834 int cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szStackBuffer, _countof(szStackBuffer));
835 if (cch) {
836 // Copy from stack.
837 sWideCharStr.assign(szStackBuffer, szStackBuffer + cch);
838 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
839 // Query the required output size. Allocate buffer. Then convert again.
840 cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, NULL, 0);
841 sWideCharStr.resize(cch);
842 cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, sWideCharStr.data(), cch);
843 }
844
845 return cch;
846}
847
853template<class _Traits1, class _Ax1, class _Traits2, class _Ax2>
854static _Success_(return != 0) int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_ const std::basic_string<char, _Traits1, _Ax1> &sMultiByteStr, _Out_ std::basic_string<wchar_t, _Traits2, _Ax2> &sWideCharStr) noexcept
855{
856 WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)];
857
858 // Try to convert to stack buffer first.
859 int cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), szStackBuffer, _countof(szStackBuffer));
860 if (cch) {
861 // Copy from stack.
862 sWideCharStr.assign(szStackBuffer, cch);
863 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
864 // Query the required output size. Allocate buffer. Then convert again.
865 cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), NULL, 0);
866 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[cch]);
867 cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), szBuffer.get(), cch);
868 sWideCharStr.assign(szBuffer.get(), cch);
869 }
870
871 return cch;
872}
873
881template<class _Traits, class _Ax>
882static _Success_(return != 0) int SecureMultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cbMultiByte) LPCSTR lpMultiByteStr, _In_ int cbMultiByte, _Out_ std::basic_string<wchar_t, _Traits, _Ax> &sWideCharStr) noexcept
883{
884 WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)];
885
886 // Try to convert to stack buffer first.
887 int cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szStackBuffer, _countof(szStackBuffer));
888 if (cch) {
889 // Copy from stack.
890 sWideCharStr.assign(szStackBuffer, cbMultiByte != -1 ? wcsnlen(szStackBuffer, cch) : (size_t)cch - 1);
891 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
892 // Query the required output size. Allocate buffer. Then convert again.
893 cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, NULL, 0);
894 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[cch]);
895 cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szBuffer.get(), cch);
896 sWideCharStr.assign(szBuffer.get(), cbMultiByte != -1 ? wcsnlen(szBuffer.get(), cch) : (size_t)cch - 1);
897 SecureZeroMemory(szBuffer.get(), sizeof(WCHAR)*cch);
898 }
899
900 SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer));
901
902 return cch;
903}
904
912template<class _Ax>
913static _Success_(return != 0) int SecureMultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cbMultiByte) LPCSTR lpMultiByteStr, _In_ int cbMultiByte, _Out_ std::vector<wchar_t, _Ax> &sWideCharStr) noexcept
914{
915 WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)];
916
917 // Try to convert to stack buffer first.
918 int cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szStackBuffer, _countof(szStackBuffer));
919 if (cch) {
920 // Copy from stack.
921 sWideCharStr.assign(szStackBuffer, szStackBuffer + cch);
922 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
923 // Query the required output size. Allocate buffer. Then convert again.
924 cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, NULL, 0);
925 sWideCharStr.resize(cch);
926 cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, sWideCharStr.data(), cch);
927 }
928
929 SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer));
930
931 return cch;
932}
933
941template<class _Traits1, class _Ax1, class _Traits2, class _Ax2>
942static _Success_(return != 0) int SecureMultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_ const std::basic_string<char, _Traits1, _Ax1> &sMultiByteStr, _Out_ std::basic_string<wchar_t, _Traits2, _Ax2> &sWideCharStr) noexcept
943{
944 WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)];
945
946 // Try to convert to stack buffer first.
947 int cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), szStackBuffer, _countof(szStackBuffer));
948 if (cch) {
949 // Copy from stack.
950 sWideCharStr.assign(szStackBuffer, cch);
951 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
952 // Query the required output size. Allocate buffer. Then convert again.
953 cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), NULL, 0);
954 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[cch]);
955 cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), szBuffer.get(), cch);
956 sWideCharStr.assign(szBuffer.get(), cch);
957 SecureZeroMemory(szBuffer.get(), sizeof(WCHAR)*cch);
958 }
959
960 SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer));
961
962 return cch;
963}
964
970template<class _Traits, class _Ax>
971static _Success_(return > 0) int NormalizeString(_In_ NORM_FORM NormForm, _In_ LPCWSTR lpSrcString, _In_ int cwSrcLength, _Out_ std::basic_string<wchar_t, _Traits, _Ax> &sDstString) noexcept
972{
973 WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)];
974
975 // Try to convert to stack buffer first.
976 int cch = ::NormalizeString(NormForm, lpSrcString, cwSrcLength, szStackBuffer, _countof(szStackBuffer));
977 if (cch > 0) {
978 // Copy from stack.
979 sDstString.assign(szStackBuffer, cwSrcLength != -1 ? wcsnlen(szStackBuffer, cch) : (size_t)cch - 1);
980 } else {
981 switch (::GetLastError()) {
982 case ERROR_INSUFFICIENT_BUFFER:
983 for (int i = 10; i--;) {
984 // Allocate buffer. Then convert again.
985 cch = -cch;
986 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[cch]);
987 cch = ::NormalizeString(NormForm, lpSrcString, cwSrcLength, szBuffer.get(), cch);
988 if (cch > 0) {
989 sDstString.assign(szBuffer.get(), cwSrcLength != -1 ? wcsnlen(szStackBuffer, cch) : (size_t)cch - 1);
990 break;
991 }
992 if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
993 sDstString.clear();
994 break;
995 }
996 }
997 break;
998
999 case ERROR_SUCCESS:
1000 sDstString.clear();
1001 break;
1002 }
1003 }
1004
1005 return cch;
1006}
1007
1013template<class _Traits1, class _Ax1, class _Traits2, class _Ax2>
1014static _Success_(return > 0) int NormalizeString(_In_ NORM_FORM NormForm, _In_ const std::basic_string<wchar_t, _Traits1, _Ax1> &sSrcString, _Out_ std::basic_string<wchar_t, _Traits2, _Ax2> &sDstString) noexcept
1015{
1016 WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)];
1017
1018 // Try to convert to stack buffer first.
1019 int cch = ::NormalizeString(NormForm, sSrcString.c_str(), (int)sSrcString.length(), szStackBuffer, _countof(szStackBuffer));
1020 if (cch > 0) {
1021 // Copy from stack.
1022 sDstString.assign(szStackBuffer, cch);
1023 } else {
1024 switch (::GetLastError()) {
1025 case ERROR_INSUFFICIENT_BUFFER:
1026 for (int i = 10; i--;) {
1027 // Allocate buffer. Then convert again.
1028 cch = -cch;
1029 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[cch]);
1030 cch = ::NormalizeString(NormForm, sSrcString.c_str(), (int)sSrcString.length(), szBuffer.get(), cch);
1031 if (cch > 0) {
1032 sDstString.assign(szBuffer.get(), cch);
1033 break;
1034 }
1035 if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1036 sDstString.clear();
1037 break;
1038 }
1039 }
1040 break;
1041
1042 case ERROR_SUCCESS:
1043 sDstString.clear();
1044 break;
1045 }
1046 }
1047
1048 return cch;
1049}
1050
1052template<class _Traits, class _Ax>
1053static _Success_(return != 0) int WINAPI LoadStringA(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_ std::basic_string<char, _Traits, _Ax> &sBuffer) noexcept
1054{
1055 // Get read-only pointer to string resource.
1056 LPCSTR pszStr;
1057 int i = LoadStringA(hInstance, uID, reinterpret_cast<LPSTR>(&pszStr), 0);
1058 if (i) {
1059 sBuffer.assign(pszStr, i);
1060 return i;
1061 } else
1062 return 0;
1063}
1064
1070template<class _Traits, class _Ax>
1071static _Success_(return != 0) int WINAPI LoadStringW(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_ std::basic_string<wchar_t, _Traits, _Ax> &sBuffer) noexcept
1072{
1073 // Get read-only pointer to string resource.
1074 LPCWSTR pszStr;
1075 int i = LoadStringW(hInstance, uID, reinterpret_cast<LPWSTR>(&pszStr), 0);
1076 if (i) {
1077 sBuffer.assign(pszStr, i);
1078 return i;
1079 } else
1080 return 0;
1081}
1082
1088static VOID OutputDebugStrV(_In_z_ LPCSTR lpOutputString, _In_ va_list arg) noexcept
1089{
1090 std::string str;
1091 try { vsprintf(str, lpOutputString, arg); } catch (...) { return; }
1092 OutputDebugStringA(str.c_str());
1093}
1094
1100static VOID OutputDebugStrV(_In_z_ LPCWSTR lpOutputString, _In_ va_list arg) noexcept
1101{
1102 std::wstring str;
1103 try { vsprintf(str, lpOutputString, arg); } catch (...) { return; }
1104 OutputDebugStringW(str.c_str());
1105}
1106
1112static VOID OutputDebugStr(_In_z_ LPCSTR lpOutputString, ...) noexcept
1113{
1114 va_list arg;
1115 va_start(arg, lpOutputString);
1116 OutputDebugStrV(lpOutputString, arg);
1117 va_end(arg);
1118}
1119
1125static VOID OutputDebugStr(_In_z_ LPCWSTR lpOutputString, ...) noexcept
1126{
1127 va_list arg;
1128 va_start(arg, lpOutputString);
1129 OutputDebugStrV(lpOutputString, arg);
1130 va_end(arg);
1131}
1132
1134template<class _Traits, class _Ax>
1135static _Success_(return != 0) int GetDateFormatA(_In_ LCID Locale, _In_ DWORD dwFlags, _In_opt_ const SYSTEMTIME *lpDate, _In_opt_z_ LPCSTR lpFormat, _Out_ std::basic_string<char, _Traits, _Ax> &sDate) noexcept
1136{
1137 int iResult = GetDateFormatA(Locale, dwFlags, lpDate, lpFormat, NULL, 0);
1138 if (iResult) {
1139 // Allocate buffer on heap and retry.
1140 std::unique_ptr<char[]> szBuffer(new char[iResult]);
1141 iResult = GetDateFormatA(Locale, dwFlags, lpDate, lpFormat, szBuffer.get(), iResult);
1142 sDate.assign(szBuffer.get(), iResult ? iResult - 1 : 0);
1143 return iResult;
1144 }
1145
1146 return iResult;
1147}
1148
1154template<class _Traits, class _Ax>
1155static _Success_(return != 0) int GetDateFormatW(_In_ LCID Locale, _In_ DWORD dwFlags, _In_opt_ const SYSTEMTIME *lpDate, _In_opt_z_ LPCWSTR lpFormat, _Out_ std::basic_string<wchar_t, _Traits, _Ax> &sDate) noexcept
1156{
1157 int iResult = GetDateFormatW(Locale, dwFlags, lpDate, lpFormat, NULL, 0);
1158 if (iResult) {
1159 // Allocate buffer on heap and retry.
1160 std::unique_ptr<wchar_t[]> szBuffer(new wchar_t[iResult]);
1161 iResult = GetDateFormatW(Locale, dwFlags, lpDate, lpFormat, szBuffer.get(), iResult);
1162 sDate.assign(szBuffer.get(), iResult ? iResult - 1 : 0);
1163 return iResult;
1164 }
1165
1166 return iResult;
1167}
1168
1170template<class _Traits, class _Ax>
1171static _Success_(return != 0) BOOL LookupAccountSidA(_In_opt_z_ LPCSTR lpSystemName, _In_ PSID lpSid, _Out_opt_ std::basic_string<char, _Traits, _Ax> *sName, _Out_opt_ std::basic_string<char, _Traits, _Ax> *sReferencedDomainName, _Out_ PSID_NAME_USE peUse) noexcept
1172{
1173 assert(0); // TODO: Test this code.
1174
1175 DWORD dwNameLen = 0, dwRefDomainLen = 0;
1176
1177 if (LookupAccountSidA(lpSystemName, lpSid,
1178 NULL, &dwNameLen ,
1179 NULL, &dwRefDomainLen,
1180 peUse))
1181 {
1182 // Name and domain is blank.
1183 if (sName ) sName ->clear();
1184 if (sReferencedDomainName) sReferencedDomainName->clear();
1185 return TRUE;
1186 } else if (GetLastError() == ERROR_MORE_DATA) {
1187 // Allocate on heap and retry.
1188 std::unique_ptr<char[]> bufName (new char[dwNameLen ]);
1189 std::unique_ptr<char[]> bufRefDomain(new char[dwRefDomainLen]);
1190 if (LookupAccountSidA(lpSystemName, lpSid,
1191 bufName .get(), &dwNameLen ,
1192 bufRefDomain.get(), &dwRefDomainLen,
1193 peUse))
1194 {
1195 if (sName ) sName ->assign(bufName .get(), dwNameLen - 1);
1196 if (sReferencedDomainName) sReferencedDomainName->assign(bufRefDomain.get(), dwRefDomainLen - 1);
1197 return TRUE;
1198 }
1199 }
1200
1201 return FALSE;
1202}
1203
1209template<class _Traits, class _Ax>
1210static _Success_(return != 0) BOOL LookupAccountSidW(_In_opt_z_ LPCWSTR lpSystemName, _In_ PSID lpSid, _Out_opt_ std::basic_string<wchar_t, _Traits, _Ax> *sName, _Out_opt_ std::basic_string<wchar_t, _Traits, _Ax> *sReferencedDomainName, _Out_ PSID_NAME_USE peUse) noexcept
1211{
1212 assert(0); // TODO: Test this code.
1213
1214 DWORD dwNameLen = 0, dwRefDomainLen = 0;
1215
1216 if (LookupAccountSidW(lpSystemName, lpSid,
1217 NULL, &dwNameLen ,
1218 NULL, &dwRefDomainLen,
1219 peUse))
1220 {
1221 // Name and domain is blank.
1222 if (sName ) sName ->clear();
1223 if (sReferencedDomainName) sReferencedDomainName->clear();
1224 return TRUE;
1225 } else if (GetLastError() == ERROR_MORE_DATA) {
1226 // Allocate on heap and retry.
1227 std::unique_ptr<wchar_t[]> bufName (new wchar_t[dwNameLen ]);
1228 std::unique_ptr<wchar_t[]> bufRefDomain(new wchar_t[dwRefDomainLen]);
1229 if (LookupAccountSidW(lpSystemName, lpSid,
1230 bufName .get(), &dwNameLen ,
1231 bufRefDomain.get(), &dwRefDomainLen,
1232 peUse))
1233 {
1234 if (sName ) sName ->assign(bufName .get(), dwNameLen - 1);
1235 if (sReferencedDomainName) sReferencedDomainName->assign(bufRefDomain.get(), dwRefDomainLen - 1);
1236 return TRUE;
1237 }
1238 }
1239
1240 return FALSE;
1241}
1242
1248template<class _Ty>
1249static _Success_(return != 0) BOOL GetTokenInformation(_In_ HANDLE TokenHandle, _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, _Out_ std::unique_ptr<_Ty> &TokenInformation) noexcept
1250{
1251 BYTE szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(BYTE)];
1252 DWORD dwSize;
1253
1254 if (GetTokenInformation(TokenHandle, TokenInformationClass, szStackBuffer, sizeof(szStackBuffer), &dwSize)) {
1255 // The stack buffer was big enough to retrieve complete data. Alloc and copy.
1256 TokenInformation.reset((_Ty*)(new BYTE[dwSize / sizeof(BYTE)]));
1257 if (!TokenInformation) {
1258 SetLastError(ERROR_OUTOFMEMORY);
1259 return FALSE;
1260 }
1261 memcpy(TokenInformation.get(), szStackBuffer, dwSize);
1262 return TRUE;
1263 } else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
1264 // The stack buffer was too small to retrieve complete data. Alloc and retry.
1265 TokenInformation.reset((_Ty*)(new BYTE[dwSize / sizeof(BYTE)]));
1266 if (!TokenInformation) {
1267 SetLastError(ERROR_OUTOFMEMORY);
1268 return FALSE;
1269 }
1270 return GetTokenInformation(TokenHandle, TokenInformationClass, TokenInformation.get(), dwSize, &dwSize);
1271 } else
1272 return FALSE;
1273}
1274
1280template<class _Traits, class _Ax>
1281static _Success_(return != 0) BOOL QueryFullProcessImageNameA(_In_ HANDLE hProcess, _In_ DWORD dwFlags, _Inout_ std::basic_string<char, _Traits, _Ax>& sExeName)
1282{
1283 char szStackBuffer[WINSTD_STACK_BUFFER_BYTES / sizeof(char)];
1284 DWORD dwSize = _countof(szStackBuffer);
1285
1286 // Try with stack buffer first.
1287 if (::QueryFullProcessImageNameA(hProcess, dwFlags, szStackBuffer, &dwSize)) {
1288 // Copy from stack.
1289 sExeName.assign(szStackBuffer, dwSize);
1290 return TRUE;
1291 }
1292 for (DWORD dwCapacity = 2 * WINSTD_STACK_BUFFER_BYTES / sizeof(char); GetLastError() == ERROR_INSUFFICIENT_BUFFER; dwCapacity *= 2) {
1293 // Allocate on heap and retry.
1294 std::unique_ptr<char[]> szBuffer(new char[dwCapacity]);
1295 dwSize = dwCapacity;
1296 if (::QueryFullProcessImageNameA(hProcess, dwFlags, szBuffer.get(), &dwSize)) {
1297 sExeName.assign(szBuffer.get(), dwSize);
1298 return TRUE;
1299 }
1300 }
1301 return FALSE;
1302}
1303
1309template<class _Traits, class _Ax>
1310static _Success_(return != 0) BOOL QueryFullProcessImageNameW(_In_ HANDLE hProcess, _In_ DWORD dwFlags, _Inout_ std::basic_string<wchar_t, _Traits, _Ax>& sExeName)
1311{
1312 wchar_t szStackBuffer[WINSTD_STACK_BUFFER_BYTES / sizeof(wchar_t)];
1313 DWORD dwSize = _countof(szStackBuffer);
1314
1315 // Try with stack buffer first.
1316 if (::QueryFullProcessImageNameW(hProcess, dwFlags, szStackBuffer, &dwSize)) {
1317 // Copy from stack.
1318 sExeName.assign(szStackBuffer, dwSize);
1319 return TRUE;
1320 }
1321 for (DWORD dwCapacity = 2 * WINSTD_STACK_BUFFER_BYTES / sizeof(wchar_t); GetLastError() == ERROR_INSUFFICIENT_BUFFER; dwCapacity *= 2) {
1322 // Allocate on heap and retry.
1323 std::unique_ptr<wchar_t[]> szBuffer(new wchar_t[dwCapacity]);
1324 dwSize = dwCapacity;
1325 if (::QueryFullProcessImageNameW(hProcess, dwFlags, szBuffer.get(), &dwSize)) {
1326 sExeName.assign(szBuffer.get(), dwSize);
1327 return TRUE;
1328 }
1329 }
1330 return FALSE;
1331}
1332
1334
1335#pragma warning(pop)
1336
1337namespace winstd
1338{
1341
1345 template<HANDLE INVALID>
1346 class win_handle : public handle<HANDLE, INVALID>
1347 {
1349
1350 public:
1356 virtual ~win_handle()
1357 {
1358 if (m_h != invalid)
1359 free_internal();
1360 }
1361
1362 protected:
1368 void free_internal() noexcept override
1369 {
1370 CloseHandle(m_h);
1371 }
1372 };
1373
1379 class library : public handle<HMODULE, NULL>
1380 {
1382
1383 public:
1389 virtual ~library()
1390 {
1391 if (m_h != invalid)
1392 free_internal();
1393 }
1394
1395 protected:
1401 void free_internal() noexcept override
1402 {
1403 FreeLibrary(m_h);
1404 }
1405 };
1406
1413
1420
1427
1434
1441
1445 template <class _Ty> struct UnmapViewOfFile_delete
1446 {
1448
1453
1458
1462 void operator()(_Ty* _Ptr) const
1463 {
1464 if (!UnmapViewOfFile(_Ptr))
1465 throw win_runtime_error("UnmapViewOfFile failed");
1466 }
1467 };
1468
1472 template <class _Ty> struct UnmapViewOfFile_delete<_Ty[]>
1473 {
1475
1480
1484 void operator()(_Ty* _Ptr) const
1485 {
1486 if (!UnmapViewOfFile(_Ptr))
1487 throw win_runtime_error("UnmapViewOfFile failed");
1488 }
1489
1493 template<class _Other>
1494 void operator()(_Other*) const
1495 {
1496 if (!UnmapViewOfFile(_Ptr))
1497 throw win_runtime_error("UnmapViewOfFile failed");
1498 }
1499 };
1500
1508
1513 {
1516
1517 public:
1524 {
1525 __try {
1526 InitializeCriticalSection(&m_data);
1527 } __except(EXCEPTION_EXECUTE_HANDLER) {
1528 throw std::runtime_error("InitializeCriticalSection failed");
1529 }
1530 }
1531
1538 {
1539 DeleteCriticalSection(&m_data);
1540 }
1541
1547 operator LPCRITICAL_SECTION() noexcept
1548 {
1549 return &m_data;
1550 }
1551
1552 protected:
1553 CRITICAL_SECTION m_data;
1554 };
1555
1561 class find_file : public handle<HANDLE, INVALID_HANDLE_VALUE>
1562 {
1563 WINSTD_HANDLE_IMPL(find_file, INVALID_HANDLE_VALUE)
1564
1565 public:
1571 virtual ~find_file()
1572 {
1573 if (m_h != invalid)
1574 free_internal();
1575 }
1576
1577 protected:
1583 void free_internal() noexcept override
1584 {
1585 FindClose(m_h);
1586 }
1587 };
1588
1594 class heap : public handle<HANDLE, NULL>
1595 {
1597
1598 public:
1604 virtual ~heap()
1605 {
1606 if (m_h != invalid)
1607 free_internal();
1608 }
1609
1617 bool enumerate() noexcept
1618 {
1619 assert(m_h != invalid);
1620
1621 bool found = false;
1622
1623 // Lock the heap for exclusive access.
1624 HeapLock(m_h);
1625
1626 PROCESS_HEAP_ENTRY e;
1627 e.lpData = NULL;
1628 while (HeapWalk(m_h, &e) != FALSE) {
1629 if ((e.wFlags & PROCESS_HEAP_ENTRY_BUSY) != 0) {
1630 OutputDebugStr(
1631 _T("Allocated block%s%s\n")
1632 _T(" Data portion begins at: %#p\n Size: %d bytes\n")
1633 _T(" Overhead: %d bytes\n Region index: %d\n"),
1634 (e.wFlags & PROCESS_HEAP_ENTRY_MOVEABLE) != 0 ? tstring_printf(_T(", movable with HANDLE %#p"), e.Block.hMem).c_str() : _T(""),
1635 (e.wFlags & PROCESS_HEAP_ENTRY_DDESHARE) != 0 ? _T(", DDESHARE") : _T(""),
1636 e.lpData,
1637 e.cbData,
1638 e.cbOverhead,
1639 e.iRegionIndex);
1640
1641 found = true;
1642 }
1643 }
1644
1645 const DWORD dwResult = GetLastError();
1646 if (dwResult != ERROR_NO_MORE_ITEMS)
1647 OutputDebugStr(_T("HeapWalk failed (error %u).\n"), dwResult);
1648
1649 // Unlock the heap.
1650 HeapUnlock(m_h);
1651
1652 return found;
1653 }
1654
1655 protected:
1661 void free_internal() noexcept override
1662 {
1663 enumerate();
1664 HeapDestroy(m_h);
1665 }
1666 };
1667
1671 template <class _Ty>
1673 {
1674 public:
1675 typedef typename _Ty value_type;
1676
1677 typedef _Ty *pointer;
1678 typedef _Ty& reference;
1679 typedef const _Ty *const_pointer;
1680 typedef const _Ty& const_reference;
1681
1682 typedef SIZE_T size_type;
1683 typedef ptrdiff_t difference_type;
1684
1688 template <class _Other>
1689 struct rebind
1690 {
1692 };
1693
1694 public:
1701 {
1702 }
1703
1709 template <class _Other>
1711 {
1712 }
1713
1722 {
1723 assert(m_heap);
1724 return (pointer)HeapAlloc(m_heap, 0, count * sizeof(_Ty));
1725 }
1726
1733 void deallocate(_In_ pointer ptr, _In_ size_type size)
1734 {
1735 UNREFERENCED_PARAMETER(size);
1736 assert(m_heap);
1737 HeapFree(m_heap, 0, ptr);
1738 }
1739
1746 void construct(_Inout_ pointer ptr, _In_ const _Ty& val)
1747 {
1748 ::new ((void*)ptr) _Ty(val);
1749 }
1750
1757 void construct(_Inout_ pointer ptr, _Inout_ _Ty&& val)
1758 {
1759 ::new ((void*)ptr) _Ty(std::forward<_Ty>(val));
1760 }
1761
1767 void destroy(_Inout_ pointer ptr)
1768 {
1769 ptr->_Ty::~_Ty();
1770 }
1771
1776 {
1777 return (SIZE_T)-1;
1778 }
1779
1780 public:
1781 HANDLE m_heap;
1782 };
1783
1788 {
1791
1792 public:
1800 actctx_activator(_In_ HANDLE hActCtx) noexcept
1801 {
1802 if (!ActivateActCtx(hActCtx, &m_cookie))
1803 m_cookie = 0;
1804 }
1805
1812 {
1813 if (m_cookie)
1814 DeactivateActCtx(0, m_cookie);
1815 }
1816
1817 protected:
1818 ULONG_PTR m_cookie;
1819 };
1820
1825 {
1828
1829 public:
1837 user_impersonator(_In_opt_ HANDLE hToken) noexcept
1838 {
1839 m_cookie = hToken && ImpersonateLoggedOnUser(hToken);
1840 }
1841
1848 {
1849 if (m_cookie)
1850 RevertToSelf();
1851 }
1852
1853 protected:
1855 };
1856
1861 {
1864
1865 public:
1873 console_ctrl_handler(_In_opt_ PHANDLER_ROUTINE HandlerRoutine) noexcept : m_handler(HandlerRoutine)
1874 {
1875 m_cookie = SetConsoleCtrlHandler(m_handler, TRUE);
1876 }
1877
1884 {
1885 if (m_cookie)
1886 SetConsoleCtrlHandler(m_handler, FALSE);
1887 }
1888
1889 protected:
1891 PHANDLER_ROUTINE m_handler;
1892 };
1893
1897 class vmemory : public handle<LPVOID, NULL>
1898 {
1900
1901 public:
1905 vmemory() noexcept : m_proc(NULL)
1906 {
1907 }
1908
1915 vmemory(_In_ handle_type h, _In_ HANDLE proc) noexcept :
1916 m_proc(proc),
1918 {
1919 }
1920
1926 vmemory(_Inout_ vmemory &&h) noexcept :
1927 m_proc(std::move(h.m_proc)),
1928 handle<LPVOID, NULL>(std::move(h))
1929 {
1930 }
1931
1937 virtual ~vmemory()
1938 {
1939 if (m_h != invalid)
1940 VirtualFreeEx(m_proc, m_h, 0, MEM_RELEASE);
1941 }
1942
1948 vmemory& operator=(_Inout_ vmemory &&other) noexcept
1949 {
1950 if (this != std::addressof(other)) {
1951 (handle<handle_type, NULL>&&)*this = std::move(other);
1952 m_proc = std::move(other.m_proc);
1953 }
1954 return *this;
1955 }
1956
1965 void attach(_In_ HANDLE proc, _In_opt_ handle_type h) noexcept
1966 {
1967 m_proc = proc;
1968 if (m_h != invalid)
1969 free_internal();
1970 m_h = h;
1971 }
1972
1982 bool alloc(
1983 _In_ HANDLE hProcess,
1984 _In_opt_ LPVOID lpAddress,
1985 _In_ SIZE_T dwSize,
1986 _In_ DWORD flAllocationType,
1987 _In_ DWORD flProtect) noexcept
1988 {
1989 handle_type h = VirtualAllocEx(hProcess, lpAddress, dwSize, flAllocationType, flProtect);
1990 if (h != invalid) {
1991 attach(hProcess, h);
1992 return true;
1993 } else
1994 return false;
1995 }
1996
1997 protected:
2003 void free_internal() noexcept override
2004 {
2005 VirtualFreeEx(m_proc, m_h, 0, MEM_RELEASE);
2006 }
2007
2008 protected:
2009 HANDLE m_proc;
2010 };
2011
2018 class reg_key : public handle<HKEY, NULL>
2019 {
2021
2022 public:
2028 virtual ~reg_key()
2029 {
2030 if (m_h != invalid)
2031 free_internal();
2032 }
2033
2043 bool delete_subkey(_In_z_ LPCTSTR szSubkey)
2044 {
2045 LSTATUS s;
2046
2047 s = RegDeleteKey(m_h, szSubkey);
2048 if (s == ERROR_SUCCESS || s == ERROR_FILE_NOT_FOUND)
2049 return true;
2050
2051 {
2052 reg_key k;
2053 handle_type h;
2054 s = RegOpenKeyEx(m_h, szSubkey, 0, KEY_ENUMERATE_SUB_KEYS, &h);
2055 if (s == ERROR_SUCCESS)
2056 k.attach(h);
2057 else {
2058 SetLastError(s);
2059 return false;
2060 }
2061 for (;;) {
2062 TCHAR szName[MAX_PATH];
2063 DWORD dwSize = _countof(szName);
2064 s = RegEnumKeyEx(k, 0, szName, &dwSize, NULL, NULL, NULL, NULL);
2065 if (s == ERROR_SUCCESS)
2066 k.delete_subkey(szName);
2067 else if (s == ERROR_NO_MORE_ITEMS)
2068 break;
2069 else {
2070 SetLastError(s);
2071 return false;
2072 }
2073 }
2074 }
2075
2076 s = RegDeleteKey(m_h, szSubkey);
2077 if (s == ERROR_SUCCESS)
2078 return true;
2079 else {
2080 SetLastError(s);
2081 return false;
2082 }
2083 }
2084
2085 protected:
2091 void free_internal() noexcept override
2092 {
2093 RegCloseKey(m_h);
2094 }
2095 };
2096
2100 class security_id : public handle<PSID, NULL>
2101 {
2103
2104 public:
2111 {
2112 if (m_h != invalid)
2113 free_internal();
2114 }
2115
2116 protected:
2122 void free_internal() noexcept override
2123 {
2124 FreeSid(m_h);
2125 }
2126 };
2127
2131 class process_information : public PROCESS_INFORMATION
2132 {
2135
2136 public:
2141 {
2142 hProcess = INVALID_HANDLE_VALUE;
2143 hThread = INVALID_HANDLE_VALUE;
2144 dwProcessId = 0;
2145 dwThreadId = 0;
2146 }
2147
2152 {
2153 #pragma warning(push)
2154 #pragma warning(disable: 6001) // Using uninitialized memory '*this'. << ???
2155
2156 if (hProcess != INVALID_HANDLE_VALUE)
2157 CloseHandle(hProcess);
2158
2159 if (hThread != INVALID_HANDLE_VALUE)
2160 CloseHandle(hThread);
2161
2162 #pragma warning(pop)
2163 }
2164 };
2165
2171 class event_log : public handle<HANDLE, NULL>
2172 {
2174
2175 public:
2181 virtual ~event_log()
2182 {
2183 if (m_h != invalid)
2184 free_internal();
2185 }
2186
2187 protected:
2193 void free_internal() noexcept override
2194 {
2195 DeregisterEventSource(m_h);
2196 }
2197 };
2198
2200}
2201
2204
2205#pragma warning(push)
2206#pragma warning(disable: 4505) // Don't warn on unused code
2207
2209static LSTATUS RegCreateKeyExA(
2210 _In_ HKEY hKey,
2211 _In_ LPCSTR lpSubKey,
2212 _Reserved_ DWORD Reserved,
2213 _In_opt_ LPSTR lpClass,
2214 _In_ DWORD dwOptions,
2215 _In_ REGSAM samDesired,
2216 _In_opt_ CONST LPSECURITY_ATTRIBUTES lpSecurityAttributes,
2217 _Inout_ winstd::reg_key &result,
2218 _Out_opt_ LPDWORD lpdwDisposition)
2219{
2220 HKEY h;
2221 LSTATUS s = RegCreateKeyExA(hKey, lpSubKey, Reserved, lpClass, dwOptions, samDesired, lpSecurityAttributes, &h, lpdwDisposition);
2222 if (s == ERROR_SUCCESS)
2223 result.attach(h);
2224 return s;
2225}
2226
2232static LSTATUS RegCreateKeyExW(
2233 _In_ HKEY hKey,
2234 _In_ LPCWSTR lpSubKey,
2235 _Reserved_ DWORD Reserved,
2236 _In_opt_ LPWSTR lpClass,
2237 _In_ DWORD dwOptions,
2238 _In_ REGSAM samDesired,
2239 _In_opt_ CONST LPSECURITY_ATTRIBUTES lpSecurityAttributes,
2240 _Inout_ winstd::reg_key &result,
2241 _Out_opt_ LPDWORD lpdwDisposition)
2242{
2243 HKEY h;
2244 LSTATUS s = RegCreateKeyExW(hKey, lpSubKey, Reserved, lpClass, dwOptions, samDesired, lpSecurityAttributes, &h, lpdwDisposition);
2245 if (s == ERROR_SUCCESS)
2246 result.attach(h);
2247 return s;
2248}
2249
2251static LSTATUS RegOpenKeyExA(
2252 _In_ HKEY hKey,
2253 _In_opt_ LPCSTR lpSubKey,
2254 _In_opt_ DWORD ulOptions,
2255 _In_ REGSAM samDesired,
2256 _Inout_ winstd::reg_key &result)
2257{
2258 HKEY h;
2259 LSTATUS s = RegOpenKeyExA(hKey, lpSubKey, ulOptions, samDesired, &h);
2260 if (s == ERROR_SUCCESS)
2261 result.attach(h);
2262 return s;
2263}
2264
2274static LSTATUS RegOpenKeyExW(
2275 _In_ HKEY hKey,
2276 _In_opt_ LPCWSTR lpSubKey,
2277 _In_opt_ DWORD ulOptions,
2278 _In_ REGSAM samDesired,
2279 _Inout_ winstd::reg_key &result)
2280{
2281 HKEY h;
2282 LSTATUS s = RegOpenKeyExW(hKey, lpSubKey, ulOptions, samDesired, &h);
2283 if (s == ERROR_SUCCESS)
2284 result.attach(h);
2285 return s;
2286}
2287
2288#pragma warning(pop)
2289
Activates given activation context in constructor and deactivates it in destructor.
Definition: Win.h:1788
actctx_activator(HANDLE hActCtx) noexcept
Construct the activator and activates the given activation context.
Definition: Win.h:1800
virtual ~actctx_activator()
Deactivates activation context and destructs the activator.
Definition: Win.h:1811
ULONG_PTR m_cookie
Cookie for context deactivation.
Definition: Win.h:1818
Base template class to support string formatting using printf() style templates.
Definition: Common.h:1114
Console control handler stack management.
Definition: Win.h:1861
console_ctrl_handler(PHANDLER_ROUTINE HandlerRoutine) noexcept
Construct the console control handler object and pushes the given handler to the console control hand...
Definition: Win.h:1873
virtual ~console_ctrl_handler()
Pops console control handler from the console control handler stack.
Definition: Win.h:1883
PHANDLER_ROUTINE m_handler
Pointer to console control handler.
Definition: Win.h:1891
BOOL m_cookie
Did pushing the console control handler succeed?
Definition: Win.h:1890
Critical section wrapper.
Definition: Win.h:1513
CRITICAL_SECTION m_data
Critical section struct.
Definition: Win.h:1553
virtual ~critical_section()
Releases all resources used by an unowned critical section object.
Definition: Win.h:1537
critical_section()
Construct the object and initializes a critical section object.
Definition: Win.h:1523
Event log handle wrapper.
Definition: Win.h:2172
void free_internal() noexcept override
Closes an event log handle.
Definition: Win.h:2193
virtual ~event_log()
Closes an event log handle.
Definition: Win.h:2181
Find-file handle wrapper.
Definition: Win.h:1562
virtual ~find_file()
Closes a file search handle.
Definition: Win.h:1571
void free_internal() noexcept override
Closes a file search handle.
Definition: Win.h:1583
Base abstract template class to support generic object handle keeping.
Definition: Common.h:603
LPVOID handle_type
Datatype of the object handle this template class handles.
Definition: Common.h:608
handle_type m_h
Object handle.
Definition: Common.h:854
void attach(handle_type h) noexcept
Sets a new object handle for the class.
Definition: Common.h:817
HeapAlloc allocator.
Definition: Win.h:1673
SIZE_T size_type
An unsigned integral type that can represent the length of any sequence that an object of template cl...
Definition: Win.h:1682
_Ty value_type
A type that is managed by the allocator.
Definition: Win.h:1675
heap_allocator(const heap_allocator< _Other > &other)
Constructs allocator from another type.
Definition: Win.h:1710
HANDLE m_heap
Heap handle.
Definition: Win.h:1781
pointer allocate(size_type count)
Allocates a new memory block.
Definition: Win.h:1721
ptrdiff_t difference_type
A signed integral type that can represent the difference between values of pointers to the type of ob...
Definition: Win.h:1683
heap_allocator(HANDLE heap)
Constructs allocator.
Definition: Win.h:1700
_Ty & reference
A type that provides a reference to the type of object managed by the allocator.
Definition: Win.h:1678
void construct(pointer ptr, _Ty &&val)
Calls moving constructor for the element.
Definition: Win.h:1757
void deallocate(pointer ptr, size_type size)
Frees memory block.
Definition: Win.h:1733
size_type max_size() const
Returns maximum memory block size.
Definition: Win.h:1775
void construct(pointer ptr, const _Ty &val)
Calls copying constructor for the element.
Definition: Win.h:1746
const _Ty & const_reference
A type that provides a constant reference to type of object managed by the allocator.
Definition: Win.h:1680
const _Ty * const_pointer
A type that provides a constant pointer to the type of object managed by the allocator.
Definition: Win.h:1679
_Ty * pointer
A type that provides a pointer to the type of object managed by the allocator.
Definition: Win.h:1677
void destroy(pointer ptr)
Calls destructor for the element.
Definition: Win.h:1767
Heap handle wrapper.
Definition: Win.h:1595
bool enumerate() noexcept
Enumerates allocated heap blocks using OutputDebugString()
Definition: Win.h:1617
void free_internal() noexcept override
Destroys the heap.
Definition: Win.h:1661
virtual ~heap()
Destroys the heap.
Definition: Win.h:1604
Module handle wrapper.
Definition: Win.h:1380
void free_internal() noexcept override
Frees the module.
Definition: Win.h:1401
virtual ~library()
Frees the module.
Definition: Win.h:1389
PROCESS_INFORMATION struct wrapper.
Definition: Win.h:2132
~process_information()
Closes process and thread handles.
Definition: Win.h:2151
process_information() noexcept
Constructs blank PROCESS_INFORMATION.
Definition: Win.h:2140
Registry key wrapper class.
Definition: Win.h:2019
void free_internal() noexcept override
Closes a handle to the registry key.
Definition: Win.h:2091
bool delete_subkey(LPCTSTR szSubkey)
Deletes the specified registry subkey.
Definition: Win.h:2043
virtual ~reg_key()
Closes a handle to the registry key.
Definition: Win.h:2028
SID wrapper class.
Definition: Win.h:2101
void free_internal() noexcept override
Closes a handle to the SID.
Definition: Win.h:2122
virtual ~security_id()
Closes a handle to the SID.
Definition: Win.h:2110
Lets the calling thread impersonate the security context of a logged-on user.
Definition: Win.h:1825
BOOL m_cookie
Did impersonation succeed?
Definition: Win.h:1854
user_impersonator(HANDLE hToken) noexcept
Construct the impersonator and impersonates the given user.
Definition: Win.h:1837
virtual ~user_impersonator()
Reverts to current user and destructs the impersonator.
Definition: Win.h:1847
Memory in virtual address space of a process handle wrapper.
Definition: Win.h:1898
vmemory & operator=(vmemory &&other) noexcept
Move assignment.
Definition: Win.h:1948
bool alloc(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) noexcept
Reserves, commits, or changes the state of a region of memory within the virtual address space of a s...
Definition: Win.h:1982
void free_internal() noexcept override
Frees the memory.
Definition: Win.h:2003
void attach(HANDLE proc, handle_type h) noexcept
Sets a new memory handle for the class.
Definition: Win.h:1965
virtual ~vmemory()
Frees the memory.
Definition: Win.h:1937
vmemory(handle_type h, HANDLE proc) noexcept
Initializes a new class instance with an already available object handle.
Definition: Win.h:1915
vmemory() noexcept
Initializes a new class instance with the memory handle set to INVAL.
Definition: Win.h:1905
vmemory(vmemory &&h) noexcept
Move constructor.
Definition: Win.h:1926
HANDLE m_proc
Handle of memory's process.
Definition: Win.h:2009
Windows HANDLE wrapper class.
Definition: Win.h:1347
void free_internal() noexcept override
Closes an open object handle.
Definition: Win.h:1368
virtual ~win_handle()
Closes an open object handle.
Definition: Win.h:1356
Windows runtime error.
Definition: Common.h:1047
#define WINSTD_NONCOPYABLE(C)
Declares a class as non-copyable.
Definition: Common.h:52
#define WINSTD_STACK_BUFFER_BYTES
Size of the stack buffer in bytes used for initial system function call.
Definition: Common.h:79
#define WINSTD_NONMOVABLE(C)
Declares a class as non-movable.
Definition: Common.h:60
#define WINSTD_HANDLE_IMPL(C, INVAL)
Implements default constructors and operators to prevent their auto-generation by compiler.
Definition: Common.h:161
static const HANDLE invalid
Invalid handle value.
Definition: Common.h:613
win_handle< INVALID_HANDLE_VALUE > file
File handle wrapper.
Definition: Win.h:1433
win_handle< INVALID_HANDLE_VALUE > process_snapshot
Process snapshot handle wrapper.
Definition: Win.h:1426
win_handle< NULL > event
Event handle wrapper.
Definition: Win.h:1507
win_handle< NULL > file_mapping
File mapping.
Definition: Win.h:1440
win_handle< NULL > process
Process handle wrapper.
Definition: Win.h:1412
win_handle< NULL > thread
Thread handle wrapper.
Definition: Win.h:1419
UnmapViewOfFile_delete()
Default construct.
Definition: Win.h:1479
void operator()(_Other *) const
Delete a pointer of another type.
Definition: Win.h:1494
void operator()(_Ty *_Ptr) const
Delete a pointer.
Definition: Win.h:1484
UnmapViewOfFile_delete< _Ty > _Myt
This type.
Definition: Win.h:1474
Deleter for unique_ptr using UnmapViewOfFile.
Definition: Win.h:1446
UnmapViewOfFile_delete(const UnmapViewOfFile_delete< _Ty2 > &)
Construct from another UnmapViewOfFile_delete.
Definition: Win.h:1457
void operator()(_Ty *_Ptr) const
Delete a pointer.
Definition: Win.h:1462
UnmapViewOfFile_delete< _Ty > _Myt
This type.
Definition: Win.h:1447
UnmapViewOfFile_delete()
Default construct.
Definition: Win.h:1452
A structure that enables an allocator for objects of one type to allocate storage for objects of anot...
Definition: Win.h:1690
heap_allocator< _Other > other
Other allocator type.
Definition: Win.h:1691