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
1377 class library : public handle<HMODULE, NULL>
1378 {
1380
1381 public:
1387 virtual ~library()
1388 {
1389 if (m_h != invalid)
1390 free_internal();
1391 }
1392
1402 bool load(_In_z_ LPCTSTR lpFileName, __reserved handle_type hFile, _In_ DWORD dwFlags) noexcept
1403 {
1404 handle_type h = LoadLibraryEx(lpFileName, hFile, dwFlags);
1405 if (h != invalid) {
1406 attach(h);
1407 return true;
1408 } else
1409 return false;
1410 }
1411
1412 protected:
1418 void free_internal() noexcept override
1419 {
1420 FreeLibrary(m_h);
1421 }
1422 };
1423
1427 class process : public win_handle<NULL>
1428 {
1429 public:
1439 bool open(_In_ DWORD dwDesiredAccess, _In_ BOOL bInheritHandle, _In_ DWORD dwProcessId) noexcept
1440 {
1441 handle_type h = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
1442 if (h != invalid) {
1443 attach(h);
1444 return true;
1445 } else
1446 return false;
1447 }
1448 };
1449
1453 class file : public win_handle<INVALID_HANDLE_VALUE>
1454 {
1455 public:
1465 bool create(_In_z_ LPCTSTR lpFileName, _In_ DWORD dwDesiredAccess, _In_ DWORD dwShareMode, _In_ DWORD dwCreationDisposition, _In_opt_ DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes = NULL, _In_opt_ HANDLE hTemplateFile = NULL) noexcept
1466 {
1467 handle_type h = CreateFile(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
1468 if (h != invalid) {
1469 attach(h);
1470 return true;
1471 } else
1472 return false;
1473 }
1474 };
1475
1479 class event : public win_handle<NULL>
1480 {
1481 public:
1491 bool create(_In_ BOOL bManualReset, _In_ BOOL bInitialState, _In_opt_ LPSECURITY_ATTRIBUTES lpEventAttributes = NULL, _In_opt_z_ LPCTSTR lpName = NULL) noexcept
1492 {
1493 handle_type h = CreateEvent(lpEventAttributes, bManualReset, bInitialState, lpName);
1494 if (h != invalid) {
1495 attach(h);
1496 return true;
1497 } else
1498 return false;
1499 }
1500
1510 bool open(_In_ DWORD dwDesiredAccess, _In_ BOOL bInheritHandle, _In_z_ LPCTSTR lpName) noexcept
1511 {
1512 handle_type h = OpenEvent(dwDesiredAccess, bInheritHandle, lpName);
1513 if (h != invalid) {
1514 attach(h);
1515 return true;
1516 } else
1517 return false;
1518 }
1519 };
1520
1525 {
1528
1529 public:
1536 {
1537 __try {
1538 InitializeCriticalSection(&m_data);
1539 } __except(EXCEPTION_EXECUTE_HANDLER) {
1540 throw std::runtime_error("InitializeCriticalSection failed");
1541 }
1542 }
1543
1550 {
1551 DeleteCriticalSection(&m_data);
1552 }
1553
1559 operator LPCRITICAL_SECTION() noexcept
1560 {
1561 return &m_data;
1562 }
1563
1564 protected:
1565 CRITICAL_SECTION m_data;
1566 };
1567
1571 class find_file : public handle<HANDLE, INVALID_HANDLE_VALUE>
1572 {
1573 WINSTD_HANDLE_IMPL(find_file, INVALID_HANDLE_VALUE)
1574
1575 public:
1581 virtual ~find_file()
1582 {
1583 if (m_h != invalid)
1584 free_internal();
1585 }
1586
1596 bool find(_In_ LPCTSTR lpFileName, _Out_ LPWIN32_FIND_DATA lpFindFileData) noexcept
1597 {
1598 handle_type h = FindFirstFile(lpFileName, lpFindFileData);
1599 if (h != invalid) {
1600 attach(h);
1601 return true;
1602 } else
1603 return false;
1604 }
1605
1606 protected:
1612 void free_internal() noexcept override
1613 {
1614 FindClose(m_h);
1615 }
1616 };
1617
1621 class heap : public handle<HANDLE, NULL>
1622 {
1624
1625 public:
1631 virtual ~heap()
1632 {
1633 if (m_h != invalid)
1634 free_internal();
1635 }
1636
1646 bool create(_In_ DWORD flOptions, _In_ SIZE_T dwInitialSize, _In_ SIZE_T dwMaximumSize) noexcept
1647 {
1648 handle_type h = HeapCreate(flOptions, dwInitialSize, dwMaximumSize);
1649 if (h != invalid) {
1650 attach(h);
1651 return true;
1652 } else
1653 return false;
1654 }
1655
1663 bool enumerate() noexcept
1664 {
1665 assert(m_h != invalid);
1666
1667 bool found = false;
1668
1669 // Lock the heap for exclusive access.
1670 HeapLock(m_h);
1671
1672 PROCESS_HEAP_ENTRY e;
1673 e.lpData = NULL;
1674 while (HeapWalk(m_h, &e) != FALSE) {
1675 if ((e.wFlags & PROCESS_HEAP_ENTRY_BUSY) != 0) {
1676 OutputDebugStr(
1677 _T("Allocated block%s%s\n")
1678 _T(" Data portion begins at: %#p\n Size: %d bytes\n")
1679 _T(" Overhead: %d bytes\n Region index: %d\n"),
1680 (e.wFlags & PROCESS_HEAP_ENTRY_MOVEABLE) != 0 ? tstring_printf(_T(", movable with HANDLE %#p"), e.Block.hMem).c_str() : _T(""),
1681 (e.wFlags & PROCESS_HEAP_ENTRY_DDESHARE) != 0 ? _T(", DDESHARE") : _T(""),
1682 e.lpData,
1683 e.cbData,
1684 e.cbOverhead,
1685 e.iRegionIndex);
1686
1687 found = true;
1688 }
1689 }
1690
1691 const DWORD dwResult = GetLastError();
1692 if (dwResult != ERROR_NO_MORE_ITEMS)
1693 OutputDebugStr(_T("HeapWalk failed (error %u).\n"), dwResult);
1694
1695 // Unlock the heap.
1696 HeapUnlock(m_h);
1697
1698 return found;
1699 }
1700
1701 protected:
1707 void free_internal() noexcept override
1708 {
1709 enumerate();
1710 HeapDestroy(m_h);
1711 }
1712 };
1713
1717 template <class _Ty>
1719 {
1720 public:
1721 typedef typename _Ty value_type;
1722
1723 typedef _Ty *pointer;
1724 typedef _Ty& reference;
1725 typedef const _Ty *const_pointer;
1726 typedef const _Ty& const_reference;
1727
1728 typedef SIZE_T size_type;
1729 typedef ptrdiff_t difference_type;
1730
1734 template <class _Other>
1735 struct rebind
1736 {
1738 };
1739
1740 public:
1747 {
1748 }
1749
1755 template <class _Other>
1757 {
1758 }
1759
1768 {
1769 assert(m_heap);
1770 return (pointer)HeapAlloc(m_heap, 0, count * sizeof(_Ty));
1771 }
1772
1779 void deallocate(_In_ pointer ptr, _In_ size_type size)
1780 {
1781 UNREFERENCED_PARAMETER(size);
1782 assert(m_heap);
1783 HeapFree(m_heap, 0, ptr);
1784 }
1785
1792 void construct(_Inout_ pointer ptr, _In_ const _Ty& val)
1793 {
1794 ::new ((void*)ptr) _Ty(val);
1795 }
1796
1803 void construct(_Inout_ pointer ptr, _Inout_ _Ty&& val)
1804 {
1805 ::new ((void*)ptr) _Ty(std::forward<_Ty>(val));
1806 }
1807
1813 void destroy(_Inout_ pointer ptr)
1814 {
1815 ptr->_Ty::~_Ty();
1816 }
1817
1822 {
1823 return (SIZE_T)-1;
1824 }
1825
1826 public:
1827 HANDLE m_heap;
1828 };
1829
1834 {
1837
1838 public:
1846 actctx_activator(_In_ HANDLE hActCtx) noexcept
1847 {
1848 if (!ActivateActCtx(hActCtx, &m_cookie))
1849 m_cookie = 0;
1850 }
1851
1858 {
1859 if (m_cookie)
1860 DeactivateActCtx(0, m_cookie);
1861 }
1862
1863 protected:
1864 ULONG_PTR m_cookie;
1865 };
1866
1871 {
1874
1875 public:
1883 user_impersonator(_In_opt_ HANDLE hToken) noexcept
1884 {
1885 m_cookie = hToken && ImpersonateLoggedOnUser(hToken);
1886 }
1887
1894 {
1895 if (m_cookie)
1896 RevertToSelf();
1897 }
1898
1899 protected:
1901 };
1902
1907 {
1910
1911 public:
1919 console_ctrl_handler(_In_opt_ PHANDLER_ROUTINE HandlerRoutine) noexcept : m_handler(HandlerRoutine)
1920 {
1921 m_cookie = SetConsoleCtrlHandler(m_handler, TRUE);
1922 }
1923
1930 {
1931 if (m_cookie)
1932 SetConsoleCtrlHandler(m_handler, FALSE);
1933 }
1934
1935 protected:
1937 PHANDLER_ROUTINE m_handler;
1938 };
1939
1943 class vmemory : public handle<LPVOID, NULL>
1944 {
1946
1947 public:
1951 vmemory() noexcept : m_proc(NULL)
1952 {
1953 }
1954
1961 vmemory(_In_ handle_type h, _In_ HANDLE proc) noexcept :
1962 m_proc(proc),
1964 {
1965 }
1966
1972 vmemory(_Inout_ vmemory &&h) noexcept :
1973 m_proc(std::move(h.m_proc)),
1974 handle<LPVOID, NULL>(std::move(h))
1975 {
1976 }
1977
1983 virtual ~vmemory()
1984 {
1985 if (m_h != invalid)
1986 VirtualFreeEx(m_proc, m_h, 0, MEM_RELEASE);
1987 }
1988
1994 vmemory& operator=(_Inout_ vmemory &&other) noexcept
1995 {
1996 if (this != std::addressof(other)) {
1997 (handle<handle_type, NULL>&&)*this = std::move(other);
1998 m_proc = std::move(other.m_proc);
1999 }
2000 return *this;
2001 }
2002
2011 void attach(_In_ HANDLE proc, _In_opt_ handle_type h) noexcept
2012 {
2013 m_proc = proc;
2014 if (m_h != invalid)
2015 free_internal();
2016 m_h = h;
2017 }
2018
2028 bool alloc(
2029 _In_ HANDLE hProcess,
2030 _In_opt_ LPVOID lpAddress,
2031 _In_ SIZE_T dwSize,
2032 _In_ DWORD flAllocationType,
2033 _In_ DWORD flProtect) noexcept
2034 {
2035 handle_type h = VirtualAllocEx(hProcess, lpAddress, dwSize, flAllocationType, flProtect);
2036 if (h != invalid) {
2037 attach(hProcess, h);
2038 return true;
2039 } else
2040 return false;
2041 }
2042
2043 protected:
2049 void free_internal() noexcept override
2050 {
2051 VirtualFreeEx(m_proc, m_h, 0, MEM_RELEASE);
2052 }
2053
2054 protected:
2055 HANDLE m_proc;
2056 };
2057
2061 class reg_key : public handle<HKEY, NULL>
2062 {
2064
2065 public:
2071 virtual ~reg_key()
2072 {
2073 if (m_h != invalid)
2074 free_internal();
2075 }
2076
2087 _In_ HKEY hKey,
2088 _In_z_ LPCTSTR lpSubKey,
2089 _In_opt_ LPTSTR lpClass,
2090 _In_ DWORD dwOptions,
2091 _In_ REGSAM samDesired,
2092 _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes = NULL,
2093 _Out_opt_ LPDWORD lpdwDisposition = NULL) noexcept
2094 {
2095 handle_type h;
2096 const LSTATUS s = RegCreateKeyEx(hKey, lpSubKey, 0, lpClass, dwOptions, samDesired, lpSecurityAttributes, &h, lpdwDisposition);
2097 if (s == ERROR_SUCCESS) {
2098 attach(h);
2099 return true;
2100 } else {
2101 SetLastError(s);
2102 return false;
2103 }
2104 }
2105
2115 bool open(
2116 _In_ HKEY hKey,
2117 _In_opt_z_ LPCTSTR lpSubKey,
2118 _In_ DWORD ulOptions,
2119 _In_ REGSAM samDesired) noexcept
2120 {
2121 handle_type h;
2122 const LONG s = RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired, &h);
2123 if (s == ERROR_SUCCESS) {
2124 attach(h);
2125 return true;
2126 } else {
2127 SetLastError(s);
2128 return false;
2129 }
2130 }
2131
2141 bool delete_subkey(_In_z_ LPCTSTR szSubkey)
2142 {
2143 LSTATUS s;
2144
2145 s = RegDeleteKey(m_h, szSubkey);
2146 if (s == ERROR_SUCCESS || s == ERROR_FILE_NOT_FOUND)
2147 return true;
2148
2149 {
2150 reg_key k;
2151 if (!k.open(m_h, szSubkey, 0, KEY_ENUMERATE_SUB_KEYS))
2152 return false;
2153 for (;;) {
2154 TCHAR szName[MAX_PATH];
2155 DWORD dwSize = _countof(szName);
2156 s = RegEnumKeyEx(k, 0, szName, &dwSize, NULL, NULL, NULL, NULL);
2157 if (s == ERROR_SUCCESS)
2158 k.delete_subkey(szName);
2159 else if (s == ERROR_NO_MORE_ITEMS)
2160 break;
2161 else {
2162 SetLastError(s);
2163 return false;
2164 }
2165 }
2166 }
2167
2168 s = RegDeleteKey(m_h, szSubkey);
2169 if (s == ERROR_SUCCESS)
2170 return true;
2171 else {
2172 SetLastError(s);
2173 return false;
2174 }
2175 }
2176
2177 protected:
2183 void free_internal() noexcept override
2184 {
2185 RegCloseKey(m_h);
2186 }
2187 };
2188
2192 class security_id : public handle<PSID, NULL>
2193 {
2195
2196 public:
2203 {
2204 if (m_h != invalid)
2205 free_internal();
2206 }
2207
2208 protected:
2214 void free_internal() noexcept override
2215 {
2216 FreeSid(m_h);
2217 }
2218 };
2219
2223 class process_information : public PROCESS_INFORMATION
2224 {
2227
2228 public:
2233 {
2234 hProcess = INVALID_HANDLE_VALUE;
2235 hThread = INVALID_HANDLE_VALUE;
2236 dwProcessId = 0;
2237 dwThreadId = 0;
2238 }
2239
2244 {
2245 #pragma warning(push)
2246 #pragma warning(disable: 6001) // Using uninitialized memory '*this'. << ???
2247
2248 if (hProcess != INVALID_HANDLE_VALUE)
2249 CloseHandle(hProcess);
2250
2251 if (hThread != INVALID_HANDLE_VALUE)
2252 CloseHandle(hThread);
2253
2254 #pragma warning(pop)
2255 }
2256 };
2257
2259}
Activates given activation context in constructor and deactivates it in destructor.
Definition: Win.h:1834
actctx_activator(_In_ HANDLE hActCtx) noexcept
Construct the activator and activates the given activation context.
Definition: Win.h:1846
virtual ~actctx_activator()
Deactivates activation context and destructs the activator.
Definition: Win.h:1857
ULONG_PTR m_cookie
Cookie for context deactivation.
Definition: Win.h:1864
Base template class to support string formatting using printf() style templates.
Definition: Common.h:1502
Console control handler stack management.
Definition: Win.h:1907
virtual ~console_ctrl_handler()
Pops console control handler from the console control handler stack.
Definition: Win.h:1929
PHANDLER_ROUTINE m_handler
Pointer to console control handler.
Definition: Win.h:1937
console_ctrl_handler(_In_opt_ PHANDLER_ROUTINE HandlerRoutine) noexcept
Construct the console control handler object and pushes the given handler to the console control hand...
Definition: Win.h:1919
BOOL m_cookie
Did pushing the console control handler succeed?
Definition: Win.h:1936
Critical section wrapper.
Definition: Win.h:1525
CRITICAL_SECTION m_data
Critical section struct.
Definition: Win.h:1565
virtual ~critical_section()
Releases all resources used by an unowned critical section object.
Definition: Win.h:1549
critical_section()
Construct the object and initializes a critical section object.
Definition: Win.h:1535
Event handle wrapper.
Definition: Win.h:1480
bool create(_In_ BOOL bManualReset, _In_ BOOL bInitialState, _In_opt_ LPSECURITY_ATTRIBUTES lpEventAttributes=NULL, _In_opt_z_ LPCTSTR lpName=NULL) noexcept
Creates or opens a named or unnamed event object.
Definition: Win.h:1491
bool open(_In_ DWORD dwDesiredAccess, _In_ BOOL bInheritHandle, _In_z_ LPCTSTR lpName) noexcept
Opens an existing named event object.
Definition: Win.h:1510
File handle wrapper.
Definition: Win.h:1454
bool create(_In_z_ LPCTSTR lpFileName, _In_ DWORD dwDesiredAccess, _In_ DWORD dwShareMode, _In_ DWORD dwCreationDisposition, _In_opt_ DWORD dwFlagsAndAttributes=FILE_ATTRIBUTE_NORMAL, _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes=NULL, _In_opt_ HANDLE hTemplateFile=NULL) noexcept
Opens file handle.
Definition: Win.h:1465
Find-file handle wrapper.
Definition: Win.h:1572
virtual ~find_file()
Closes a file search handle.
Definition: Win.h:1581
void free_internal() noexcept override
Closes a file search handle.
Definition: Win.h:1612
bool find(_In_ LPCTSTR lpFileName, _Out_ LPWIN32_FIND_DATA lpFindFileData) noexcept
Searches a directory for a file or subdirectory with a name that matches a specific name (or partial ...
Definition: Win.h:1596
Base abstract template class to support generic object handle keeping.
Definition: Common.h:580
HMODULE handle_type
Datatype of the object handle this template class handles.
Definition: Common.h:585
void attach(_In_opt_ handle_type h) noexcept
Sets a new object handle for the class.
Definition: Common.h:794
handle_type m_h
Object handle.
Definition: Common.h:833
HeapAlloc allocator.
Definition: Win.h:1719
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:1728
_Ty value_type
A type that is managed by the allocator.
Definition: Win.h:1721
void deallocate(_In_ pointer ptr, _In_ size_type size)
Frees memory block.
Definition: Win.h:1779
void construct(_Inout_ pointer ptr, _In_ const _Ty &val)
Calls copying constructor for the element.
Definition: Win.h:1792
HANDLE m_heap
Heap handle.
Definition: Win.h:1827
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:1729
_Ty & reference
A type that provides a reference to the type of object managed by the allocator.
Definition: Win.h:1724
pointer allocate(_In_ size_type count)
Allocates a new memory block.
Definition: Win.h:1767
heap_allocator(_In_ const heap_allocator< _Other > &other)
Constructs allocator from another type.
Definition: Win.h:1756
size_type max_size() const
Returns maximum memory block size.
Definition: Win.h:1821
heap_allocator(_In_ HANDLE heap)
Constructs allocator.
Definition: Win.h:1746
void construct(_Inout_ pointer ptr, _Inout_ _Ty &&val)
Calls moving constructor for the element.
Definition: Win.h:1803
const _Ty & const_reference
A type that provides a constant reference to type of object managed by the allocator.
Definition: Win.h:1726
const _Ty * const_pointer
A type that provides a constant pointer to the type of object managed by the allocator.
Definition: Win.h:1725
_Ty * pointer
A type that provides a pointer to the type of object managed by the allocator.
Definition: Win.h:1723
void destroy(_Inout_ pointer ptr)
Calls destructor for the element.
Definition: Win.h:1813
Heap handle wrapper.
Definition: Win.h:1622
bool create(_In_ DWORD flOptions, _In_ SIZE_T dwInitialSize, _In_ SIZE_T dwMaximumSize) noexcept
Creates the heap.
Definition: Win.h:1646
bool enumerate() noexcept
Enumerates allocated heap blocks using OutputDebugString()
Definition: Win.h:1663
void free_internal() noexcept override
Destroys the heap.
Definition: Win.h:1707
virtual ~heap()
Destroys the heap.
Definition: Win.h:1631
Module handle wrapper.
Definition: Win.h:1378
void free_internal() noexcept override
Frees the module.
Definition: Win.h:1418
bool load(_In_z_ LPCTSTR lpFileName, __reserved handle_type hFile, _In_ DWORD dwFlags) noexcept
Loads the specified module into the address space of the calling process.
Definition: Win.h:1402
virtual ~library()
Frees the module.
Definition: Win.h:1387
PROCESS_INFORMATION struct wrapper.
Definition: Win.h:2224
~process_information()
Closes process and thread handles.
Definition: Win.h:2243
process_information() noexcept
Constructs blank PROCESS_INFORMATION.
Definition: Win.h:2232
Process handle wrapper.
Definition: Win.h:1428
bool open(_In_ DWORD dwDesiredAccess, _In_ BOOL bInheritHandle, _In_ DWORD dwProcessId) noexcept
Opens process handle.
Definition: Win.h:1439
Registry wrapper class.
Definition: Win.h:2062
bool open(_In_ HKEY hKey, _In_opt_z_ LPCTSTR lpSubKey, _In_ DWORD ulOptions, _In_ REGSAM samDesired) noexcept
Opens the specified registry key.
Definition: Win.h:2115
bool delete_subkey(_In_z_ LPCTSTR szSubkey)
Deletes the specified registry subkey.
Definition: Win.h:2141
void free_internal() noexcept override
Closes a handle to the registry key.
Definition: Win.h:2183
bool create(_In_ HKEY hKey, _In_z_ LPCTSTR lpSubKey, _In_opt_ LPTSTR lpClass, _In_ DWORD dwOptions, _In_ REGSAM samDesired, _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes=NULL, _Out_opt_ LPDWORD lpdwDisposition=NULL) noexcept
Creates the specified registry key. If the key already exists, the function opens it.
Definition: Win.h:2086
virtual ~reg_key()
Closes a handle to the registry key.
Definition: Win.h:2071
SID wrapper class.
Definition: Win.h:2193
void free_internal() noexcept override
Closes a handle to the SID.
Definition: Win.h:2214
virtual ~security_id()
Closes a handle to the SID.
Definition: Win.h:2202
Lets the calling thread impersonate the security context of a logged-on user.
Definition: Win.h:1871
BOOL m_cookie
Did impersonation succeed?
Definition: Win.h:1900
user_impersonator(_In_opt_ HANDLE hToken) noexcept
Construct the impersonator and impersonates the given user.
Definition: Win.h:1883
virtual ~user_impersonator()
Reverts to current user and destructs the impersonator.
Definition: Win.h:1893
Memory in virtual address space of a process handle wrapper.
Definition: Win.h:1944
vmemory(_Inout_ vmemory &&h) noexcept
Move constructor.
Definition: Win.h:1972
void attach(_In_ HANDLE proc, _In_opt_ handle_type h) noexcept
Sets a new memory handle for the class.
Definition: Win.h:2011
void free_internal() noexcept override
Frees the memory.
Definition: Win.h:2049
vmemory & operator=(_Inout_ vmemory &&other) noexcept
Move assignment.
Definition: Win.h:1994
bool alloc(_In_ HANDLE hProcess, _In_opt_ LPVOID lpAddress, _In_ SIZE_T dwSize, _In_ DWORD flAllocationType, _In_ 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:2028
virtual ~vmemory()
Frees the memory.
Definition: Win.h:1983
vmemory(_In_ handle_type h, _In_ HANDLE proc) noexcept
Initializes a new class instance with an already available object handle.
Definition: Win.h:1961
vmemory() noexcept
Initializes a new class instance with the memory handle set to INVAL.
Definition: Win.h:1951
HANDLE m_proc
Handle of memory's process.
Definition: Win.h:2055
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
#define WINSTD_NONCOPYABLE(C)
Declares a class as non-copyable.
Definition: Common.h:53
#define WINSTD_STACK_BUFFER_BYTES
Size of the stack buffer in bytes used for initial system function call.
Definition: Common.h:80
#define WINSTD_NONMOVABLE(C)
Declares a class as non-movable.
Definition: Common.h:61
#define WINSTD_HANDLE_IMPL(C, INVAL)
Implements default constructors and operators to prevent their auto-generation by compiler.
Definition: Common.h:138
static const HANDLE invalid
Invalid handle value.
Definition: Common.h:590
A structure that enables an allocator for objects of one type to allocate storage for objects of anot...
Definition: Win.h:1736
heap_allocator< _Other > other
Other allocator type.
Definition: Win.h:1737