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
25#define WINSTD_WINHANDLE_IMPL(C, INVAL) \
26public: \
27 C ( ) noexcept { } \
28 C (_In_opt_ handle_type h) noexcept : win_handle<INVAL>( h ) { } \
29 C (_Inout_ C &&h) noexcept : win_handle<INVAL>(std::move(h)) { } \
30 C& operator=(_In_opt_ handle_type h) noexcept { win_handle<INVAL>::operator=( h ); return *this; } \
31 C& operator=(_Inout_ C &&h) noexcept { win_handle<INVAL>::operator=(std::move(h)); return *this; } \
32WINSTD_NONCOPYABLE(C)
33
35template<class _Traits, class _Ax>
36static DWORD GetModuleFileNameA(_In_opt_ HMODULE hModule, _Out_ std::basic_string<char, _Traits, _Ax> &sValue) noexcept
37{
38 assert(0); // TODO: Test this code.
39
40 char szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(char)];
41
42 // Try with stack buffer first.
43 DWORD dwResult = ::GetModuleFileNameA(hModule, szStackBuffer, _countof(szStackBuffer));
44 if (dwResult < _countof(szStackBuffer)) {
45 // Copy from stack.
46 sValue.assign(szStackBuffer, dwResult);
47 return dwResult;
48 } else {
49 for (DWORD dwCapacity = 2*WINSTD_STACK_BUFFER_BYTES/sizeof(char);; dwCapacity *= 2) {
50 // Allocate on heap and retry.
51 std::unique_ptr<char[]> szBuffer(new char[dwCapacity]);
52 dwResult = ::GetModuleFileNameA(hModule, szBuffer.get(), dwCapacity);
53 if (dwResult < dwCapacity) {
54 sValue.assign(szBuffer.get(), dwResult);
55 return dwResult;
56 }
57 }
58 }
59}
60
66template<class _Traits, class _Ax>
67static DWORD GetModuleFileNameW(_In_opt_ HMODULE hModule, _Out_ std::basic_string<wchar_t, _Traits, _Ax> &sValue) noexcept
68{
69 wchar_t szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t)];
70
71 // Try with stack buffer first.
72 DWORD dwResult = ::GetModuleFileNameW(hModule, szStackBuffer, _countof(szStackBuffer));
73 if (dwResult < _countof(szStackBuffer)) {
74 // Copy from stack.
75 sValue.assign(szStackBuffer, dwResult);
76 return dwResult;
77 } else {
78 for (DWORD dwCapacity = 2*WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t);; dwCapacity *= 2) {
79 // Allocate on heap and retry.
80 std::unique_ptr<wchar_t[]> szBuffer(new wchar_t[dwCapacity]);
81 dwResult = ::GetModuleFileNameW(hModule, szBuffer.get(), dwCapacity);
82 if (dwResult < dwCapacity) {
83 sValue.assign(szBuffer.get(), dwResult);
84 return dwResult;
85 }
86 }
87 }
88}
89
91template<class _Traits, class _Ax>
92static _Success_(return != 0) int GetWindowTextA(_In_ HWND hWnd, _Out_ std::basic_string<char, _Traits, _Ax> &sValue) noexcept
93{
94 assert(0); // TODO: Test this code.
95
96 int iResult;
97
98 // Query the final string length first.
99 iResult = ::GetWindowTextLengthA(hWnd);
100 if (iResult > 0) {
101 if (++iResult < WINSTD_STACK_BUFFER_BYTES/sizeof(char)) {
102 // Read string data to stack.
103 char szBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(char)];
104 iResult = ::GetWindowTextA(hWnd, szBuffer, _countof(szBuffer));
105 sValue.assign(szBuffer, iResult);
106 } else {
107 // Allocate buffer on heap and read the string data into it.
108 std::unique_ptr<char[]> szBuffer(new char[++iResult]);
109 iResult = ::GetWindowTextA(hWnd, szBuffer.get(), iResult);
110 sValue.assign(szBuffer.get(), iResult);
111 }
112 return iResult;
113 }
114
115 sValue.clear();
116 return 0;
117}
118
124template<class _Traits, class _Ax>
125static _Success_(return != 0) int GetWindowTextW(_In_ HWND hWnd, _Out_ std::basic_string<wchar_t, _Traits, _Ax> &sValue) noexcept
126{
127 assert(0); // TODO: Test this code.
128
129 int iResult;
130
131 // Query the final string length first.
132 iResult = ::GetWindowTextLengthW(hWnd);
133 if (iResult > 0) {
134 if (++iResult < WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t)) {
135 // Read string data to stack.
136 wchar_t szBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t)];
137 iResult = ::GetWindowTextW(hWnd, szBuffer, _countof(szBuffer));
138 sValue.assign(szBuffer, iResult);
139 } else {
140 // Allocate buffer on heap and read the string data into it.
141 std::unique_ptr<wchar_t[]> szBuffer(new wchar_t[++iResult]);
142 iResult = ::GetWindowTextW(hWnd, szBuffer.get(), iResult);
143 sValue.assign(szBuffer.get(), iResult);
144 }
145 return iResult;
146 }
147
148 sValue.clear();
149 return 0;
150}
151
153template<class _Ty, class _Ax>
154static _Success_(return != 0) BOOL GetFileVersionInfoA(_In_z_ LPCSTR lptstrFilename, __reserved DWORD dwHandle, _Out_ std::vector<_Ty, _Ax> &aValue) noexcept
155{
156 assert(0); // TODO: Test this code.
157
158 // Get version info size.
159 DWORD dwVerInfoSize = ::GetFileVersionInfoSizeA(lptstrFilename, &dwHandle);
160 if (dwVerInfoSize != 0) {
161 // Read version info.
162 aValue.resize((dwVerInfoSize + sizeof(_Ty) - 1) / sizeof(_Ty));
163 return ::GetFileVersionInfoA(lptstrFilename, dwHandle, dwVerInfoSize, aValue.data());
164 } else
165 return FALSE;
166}
167
173template<class _Ty, class _Ax>
174static _Success_(return != 0) BOOL GetFileVersionInfoW(_In_z_ LPCWSTR lptstrFilename, __reserved DWORD dwHandle, _Out_ std::vector<_Ty, _Ax> &aValue) noexcept
175{
176 assert(0); // TODO: Test this code.
177
178 // Get version info size.
179 DWORD dwVerInfoSize = ::GetFileVersionInfoSizeW(lptstrFilename, &dwHandle);
180 if (dwVerInfoSize != 0) {
181 // Read version info.
182 aValue.resize((dwVerInfoSize + sizeof(_Ty) - 1) / sizeof(_Ty));
183 return ::GetFileVersionInfoW(lptstrFilename, dwHandle, dwVerInfoSize, aValue.data());
184 } else
185 return FALSE;
186}
187
189template<class _Traits, class _Ax>
190static _Success_(return != 0) DWORD ExpandEnvironmentStringsA(_In_z_ LPCSTR lpSrc, _Out_ std::basic_string<char, _Traits, _Ax> &sValue) noexcept
191{
192 assert(0); // TODO: Test this code.
193
194 for (DWORD dwSizeOut = (DWORD)strlen(lpSrc) + 0x100;;) {
195 DWORD dwSizeIn = dwSizeOut;
196 std::unique_ptr<char[]> szBuffer(new char[(size_t)dwSizeIn + 2]); // Note: ANSI version requires one extra char.
197 dwSizeOut = ::ExpandEnvironmentStringsA(lpSrc, szBuffer.get(), dwSizeIn);
198 if (dwSizeOut == 0) {
199 // Error or zero-length input.
200 break;
201 } else if (dwSizeOut <= dwSizeIn) {
202 // The buffer was sufficient.
203 sValue.assign(szBuffer.get(), dwSizeOut - 1);
204 return dwSizeOut;
205 }
206 }
207
208 sValue.clear();
209 return 0;
210}
211
217template<class _Traits, class _Ax>
218static _Success_(return != 0) DWORD ExpandEnvironmentStringsW(_In_z_ LPCWSTR lpSrc, _Out_ std::basic_string<wchar_t, _Traits, _Ax> &sValue) noexcept
219{
220 for (DWORD dwSizeOut = (DWORD)wcslen(lpSrc) + 0x100;;) {
221 DWORD dwSizeIn = dwSizeOut;
222 std::unique_ptr<wchar_t[]> szBuffer(new wchar_t[(size_t)dwSizeIn + 1]);
223 dwSizeOut = ::ExpandEnvironmentStringsW(lpSrc, szBuffer.get(), dwSizeIn);
224 if (dwSizeOut == 0) {
225 // Error or zero-length input.
226 break;
227 } else if (dwSizeOut <= dwSizeIn) {
228 // The buffer was sufficient.
229 sValue.assign(szBuffer.get(), dwSizeOut - 1);
230 return dwSizeOut;
231 }
232 }
233
234 sValue.clear();
235 return 0;
236}
237
239template<class _Traits, class _Ax>
240static VOID GuidToStringA(_In_ LPCGUID lpGuid, _Out_ std::basic_string<char, _Traits, _Ax> &str) noexcept
241{
242 assert(0); // TODO: Test this code.
243
244 sprintf(str, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
245 lpGuid->Data1,
246 lpGuid->Data2,
247 lpGuid->Data3,
248 lpGuid->Data4[0], lpGuid->Data4[1],
249 lpGuid->Data4[2], lpGuid->Data4[3], lpGuid->Data4[4], lpGuid->Data4[5], lpGuid->Data4[6], lpGuid->Data4[7]);
250}
251
258template<class _Traits, class _Ax>
259static VOID GuidToStringW(_In_ LPCGUID lpGuid, _Out_ std::basic_string<wchar_t, _Traits, _Ax> &str) noexcept
260{
261 assert(0); // TODO: Test this code.
262
263 sprintf(str, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
264 lpGuid->Data1,
265 lpGuid->Data2,
266 lpGuid->Data3,
267 lpGuid->Data4[0], lpGuid->Data4[1],
268 lpGuid->Data4[2], lpGuid->Data4[3], lpGuid->Data4[4], lpGuid->Data4[5], lpGuid->Data4[6], lpGuid->Data4[7]);
269}
270
272#ifdef _UNICODE
273#define GuidToString GuidToStringW
274#else
275#define GuidToString GuidToStringA
276#endif
277
279static _Success_(return) BOOL StringToGuidA(_In_z_ LPCSTR lpszGuid, _Out_ LPGUID lpGuid, _Out_opt_ LPCSTR *lpszGuidEnd = NULL) noexcept
280{
281 GUID g;
282 LPSTR lpszEnd;
283 unsigned long ulTmp;
284 unsigned long long ullTmp;
285
286 if (!lpszGuid || !lpGuid || *lpszGuid != '{') return FALSE;
287 lpszGuid++;
288
289 g.Data1 = strtoul(lpszGuid, &lpszEnd, 16);
290 if (errno == ERANGE) return FALSE;
291 lpszGuid = lpszEnd;
292
293 if (*lpszGuid != '-') return FALSE;
294 lpszGuid++;
295
296 ulTmp = strtoul(lpszGuid, &lpszEnd, 16);
297 if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE;
298 g.Data2 = static_cast<unsigned short>(ulTmp);
299 lpszGuid = lpszEnd;
300
301 if (*lpszGuid != '-') return FALSE;
302 lpszGuid++;
303
304 ulTmp = strtoul(lpszGuid, &lpszEnd, 16);
305 if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE;
306 g.Data3 = static_cast<unsigned short>(ulTmp);
307 lpszGuid = lpszEnd;
308
309 if (*lpszGuid != '-') return FALSE;
310 lpszGuid++;
311
312 ulTmp = strtoul(lpszGuid, &lpszEnd, 16);
313 if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE;
314 g.Data4[0] = static_cast<unsigned char>((ulTmp >> 8) & 0xff);
315 g.Data4[1] = static_cast<unsigned char>( ulTmp & 0xff);
316 lpszGuid = lpszEnd;
317
318 if (*lpszGuid != '-') return FALSE;
319 lpszGuid++;
320
321 ullTmp = _strtoui64(lpszGuid, &lpszEnd, 16);
322 if (errno == ERANGE || ullTmp > 0xFFFFFFFFFFFF) return FALSE;
323 g.Data4[2] = static_cast<unsigned char>((ullTmp >> 40) & 0xff);
324 g.Data4[3] = static_cast<unsigned char>((ullTmp >> 32) & 0xff);
325 g.Data4[4] = static_cast<unsigned char>((ullTmp >> 24) & 0xff);
326 g.Data4[5] = static_cast<unsigned char>((ullTmp >> 16) & 0xff);
327 g.Data4[6] = static_cast<unsigned char>((ullTmp >> 8) & 0xff);
328 g.Data4[7] = static_cast<unsigned char>( ullTmp & 0xff);
329 lpszGuid = lpszEnd;
330
331 if (*lpszGuid != '}') return FALSE;
332 lpszGuid++;
333
334 if (lpszGuidEnd)
335 *lpszGuidEnd = lpszGuid;
336
337 *lpGuid = g;
338 return TRUE;
339}
340
352static _Success_(return) BOOL StringToGuidW(_In_z_ LPCWSTR lpszGuid, _Out_ LPGUID lpGuid, _Out_opt_ LPCWSTR *lpszGuidEnd = NULL) noexcept
353{
354 GUID g;
355 LPWSTR lpszEnd;
356 unsigned long ulTmp;
357 unsigned long long ullTmp;
358
359 if (!lpszGuid || !lpGuid || *lpszGuid != '{') return FALSE;
360 lpszGuid++;
361
362 g.Data1 = wcstoul(lpszGuid, &lpszEnd, 16);
363 if (errno == ERANGE) return FALSE;
364 lpszGuid = lpszEnd;
365
366 if (*lpszGuid != '-') return FALSE;
367 lpszGuid++;
368
369 ulTmp = wcstoul(lpszGuid, &lpszEnd, 16);
370 if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE;
371 g.Data2 = static_cast<unsigned short>(ulTmp);
372 lpszGuid = lpszEnd;
373
374 if (*lpszGuid != '-') return FALSE;
375 lpszGuid++;
376
377 ulTmp = wcstoul(lpszGuid, &lpszEnd, 16);
378 if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE;
379 g.Data3 = static_cast<unsigned short>(ulTmp);
380 lpszGuid = lpszEnd;
381
382 if (*lpszGuid != '-') return FALSE;
383 lpszGuid++;
384
385 ulTmp = wcstoul(lpszGuid, &lpszEnd, 16);
386 if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE;
387 g.Data4[0] = static_cast<unsigned char>((ulTmp >> 8) & 0xff);
388 g.Data4[1] = static_cast<unsigned char>( ulTmp & 0xff);
389 lpszGuid = lpszEnd;
390
391 if (*lpszGuid != '-') return FALSE;
392 lpszGuid++;
393
394 ullTmp = _wcstoui64(lpszGuid, &lpszEnd, 16);
395 if (errno == ERANGE || ullTmp > 0xFFFFFFFFFFFF) return FALSE;
396 g.Data4[2] = static_cast<unsigned char>((ullTmp >> 40) & 0xff);
397 g.Data4[3] = static_cast<unsigned char>((ullTmp >> 32) & 0xff);
398 g.Data4[4] = static_cast<unsigned char>((ullTmp >> 24) & 0xff);
399 g.Data4[5] = static_cast<unsigned char>((ullTmp >> 16) & 0xff);
400 g.Data4[6] = static_cast<unsigned char>((ullTmp >> 8) & 0xff);
401 g.Data4[7] = static_cast<unsigned char>( ullTmp & 0xff);
402 lpszGuid = lpszEnd;
403
404 if (*lpszGuid != '}') return FALSE;
405 lpszGuid++;
406
407 if (lpszGuidEnd)
408 *lpszGuidEnd = lpszGuid;
409
410 *lpGuid = g;
411 return TRUE;
412}
413
415#ifdef _UNICODE
416#define StringToGuid StringToGuidW
417#else
418#define StringToGuid StringToGuidA
419#endif
420
439template<class _Traits, class _Ax>
440static LSTATUS RegQueryStringValue(_In_ HKEY hReg, _In_z_ LPCSTR pszName, _Out_ std::basic_string<char, _Traits, _Ax> &sValue) noexcept
441{
442 LSTATUS lResult;
443 BYTE aStackBuffer[WINSTD_STACK_BUFFER_BYTES];
444 DWORD dwSize = sizeof(aStackBuffer), dwType;
445
446 // Try with stack buffer first.
447 lResult = ::RegQueryValueExA(hReg, pszName, NULL, &dwType, aStackBuffer, &dwSize);
448 if (lResult == ERROR_SUCCESS) {
449 if (dwType == REG_SZ || dwType == REG_MULTI_SZ) {
450 // The value is REG_SZ or REG_MULTI_SZ.
451 dwSize /= sizeof(CHAR);
452 sValue.assign(reinterpret_cast<LPCSTR>(aStackBuffer), dwSize && reinterpret_cast<LPCSTR>(aStackBuffer)[dwSize - 1] == 0 ? dwSize - 1 : dwSize);
453 } else if (dwType == REG_EXPAND_SZ) {
454 // The value is REG_EXPAND_SZ. Expand it from stack buffer.
455 if (::ExpandEnvironmentStringsA(reinterpret_cast<LPCSTR>(aStackBuffer), sValue) == 0)
456 lResult = ::GetLastError();
457 } else {
458 // The value is not a string type.
459 lResult = ERROR_INVALID_DATA;
460 }
461 } else if (lResult == ERROR_MORE_DATA) {
462 if (dwType == REG_SZ || dwType == REG_MULTI_SZ) {
463 // The value is REG_SZ or REG_MULTI_SZ. Read it now.
464 std::unique_ptr<CHAR[]> szBuffer(new CHAR[dwSize / sizeof(CHAR)]);
465 if ((lResult = ::RegQueryValueExA(hReg, pszName, NULL, NULL, reinterpret_cast<LPBYTE>(szBuffer.get()), &dwSize)) == ERROR_SUCCESS) {
466 dwSize /= sizeof(CHAR);
467 sValue.assign(szBuffer.get(), dwSize && szBuffer[dwSize - 1] == 0 ? dwSize - 1 : dwSize);
468 }
469 } else if (dwType == REG_EXPAND_SZ) {
470 // The value is REG_EXPAND_SZ. Read it and expand environment variables.
471 std::unique_ptr<CHAR[]> szBuffer(new CHAR[dwSize / sizeof(CHAR)]);
472 if ((lResult = ::RegQueryValueExA(hReg, pszName, NULL, NULL, reinterpret_cast<LPBYTE>(szBuffer.get()), &dwSize)) == ERROR_SUCCESS) {
473 if (::ExpandEnvironmentStringsA(szBuffer.get(), sValue) == 0)
474 lResult = ::GetLastError();
475 }
476 } else {
477 // The value is not a string type.
478 lResult = ERROR_INVALID_DATA;
479 }
480 }
481
482 return lResult;
483}
484
503template<class _Traits, class _Ax>
504static LSTATUS RegQueryStringValue(_In_ HKEY hReg, _In_z_ LPCWSTR pszName, _Out_ std::basic_string<wchar_t, _Traits, _Ax> &sValue) noexcept
505{
506 LSTATUS lResult;
507 BYTE aStackBuffer[WINSTD_STACK_BUFFER_BYTES];
508 DWORD dwSize = sizeof(aStackBuffer), dwType;
509
510 // Try with stack buffer first.
511 lResult = ::RegQueryValueExW(hReg, pszName, NULL, &dwType, aStackBuffer, &dwSize);
512 if (lResult == ERROR_SUCCESS) {
513 if (dwType == REG_SZ || dwType == REG_MULTI_SZ) {
514 // The value is REG_SZ or REG_MULTI_SZ.
515 dwSize /= sizeof(WCHAR);
516 sValue.assign(reinterpret_cast<LPCWSTR>(aStackBuffer), dwSize && reinterpret_cast<LPCWSTR>(aStackBuffer)[dwSize - 1] == 0 ? dwSize - 1 : dwSize);
517 } else if (dwType == REG_EXPAND_SZ) {
518 // The value is REG_EXPAND_SZ. Expand it from stack buffer.
519 if (::ExpandEnvironmentStringsW(reinterpret_cast<LPCWSTR>(aStackBuffer), sValue) == 0)
520 lResult = ::GetLastError();
521 } else {
522 // The value is not a string type.
523 lResult = ERROR_INVALID_DATA;
524 }
525 } else if (lResult == ERROR_MORE_DATA) {
526 if (dwType == REG_SZ || dwType == REG_MULTI_SZ) {
527 // The value is REG_SZ or REG_MULTI_SZ. Read it now.
528 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[dwSize / sizeof(WCHAR)]);
529 if ((lResult = ::RegQueryValueExW(hReg, pszName, NULL, NULL, reinterpret_cast<LPBYTE>(szBuffer.get()), &dwSize)) == ERROR_SUCCESS) {
530 dwSize /= sizeof(WCHAR);
531 sValue.assign(szBuffer.get(), dwSize && szBuffer[dwSize - 1] == 0 ? dwSize - 1 : dwSize);
532 }
533 } else if (dwType == REG_EXPAND_SZ) {
534 // The value is REG_EXPAND_SZ. Read it and expand environment variables.
535 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[dwSize / sizeof(WCHAR)]);
536 if ((lResult = ::RegQueryValueExW(hReg, pszName, NULL, NULL, reinterpret_cast<LPBYTE>(szBuffer.get()), &dwSize)) == ERROR_SUCCESS) {
537 if (::ExpandEnvironmentStringsW(szBuffer.get(), sValue) == 0)
538 lResult = ::GetLastError();
539 }
540 } else {
541 // The value is not a string type.
542 lResult = ERROR_INVALID_DATA;
543 }
544 }
545
546 return lResult;
547}
548
550template<class _Ty, class _Ax>
551static LSTATUS RegQueryValueExA(_In_ HKEY hKey, _In_opt_z_ LPCSTR lpValueName, __reserved LPDWORD lpReserved, _Out_opt_ LPDWORD lpType, _Out_ std::vector<_Ty, _Ax> &aData) noexcept
552{
553 LSTATUS lResult;
554 BYTE aStackBuffer[WINSTD_STACK_BUFFER_BYTES];
555 DWORD dwSize = sizeof(aStackBuffer);
556
557 // Try with stack buffer first.
558 lResult = RegQueryValueExA(hKey, lpValueName, lpReserved, lpType, aStackBuffer, &dwSize);
559 if (lResult == ERROR_SUCCESS) {
560 // Copy from stack buffer.
561 aData.resize((dwSize + sizeof(_Ty) - 1) / sizeof(_Ty));
562 memcpy(aData.data(), aStackBuffer, dwSize);
563 } else if (lResult == ERROR_MORE_DATA) {
564 // Allocate buffer on heap and retry.
565 aData.resize((dwSize + sizeof(_Ty) - 1) / sizeof(_Ty));
566 lResult = RegQueryValueExA(hKey, lpValueName, lpReserved, NULL, aData.data(), &dwSize);
567 }
568
569 return lResult;
570}
571
577template<class _Ty, class _Ax>
578static LSTATUS RegQueryValueExW(_In_ HKEY hKey, _In_opt_z_ LPCWSTR lpValueName, __reserved LPDWORD lpReserved, _Out_opt_ LPDWORD lpType, _Out_ std::vector<_Ty, _Ax> &aData) noexcept
579{
580 LSTATUS lResult;
581 BYTE aStackBuffer[WINSTD_STACK_BUFFER_BYTES];
582 DWORD dwSize = sizeof(aStackBuffer);
583
584 // Try with stack buffer first.
585 lResult = RegQueryValueExW(hKey, lpValueName, lpReserved, lpType, aStackBuffer, &dwSize);
586 if (lResult == ERROR_SUCCESS) {
587 // Copy from stack buffer.
588 aData.resize((dwSize + sizeof(_Ty) - 1) / sizeof(_Ty));
589 memcpy(aData.data(), aStackBuffer, dwSize);
590 } else if (lResult == ERROR_MORE_DATA) {
591 // Allocate buffer on heap and retry.
592 aData.resize((dwSize + sizeof(_Ty) - 1) / sizeof(_Ty));
593 lResult = RegQueryValueExW(hKey, lpValueName, lpReserved, NULL, aData.data(), &dwSize);
594 }
595
596 return lResult;
597}
598
599#if _WIN32_WINNT >= _WIN32_WINNT_VISTA
600
602template<class _Traits, class _Ax>
603static 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
604{
605 // According to "Remarks" section in MSDN documentation of RegLoadMUIString(),
606 // this function is defined but not implemented as ANSI variation.
607 assert(0);
608 return ERROR_CALL_NOT_IMPLEMENTED;
609}
610
616template<class _Traits, class _Ax>
617static 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
618{
619 LSTATUS lResult;
620 wchar_t szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t)];
621 DWORD dwSize;
622
623 Flags &= ~REG_MUI_STRING_TRUNCATE;
624
625 // Try with stack buffer first.
626 lResult = RegLoadMUIStringW(hKey, pszValue, szStackBuffer, sizeof(szStackBuffer), &dwSize, Flags, pszDirectory);
627 if (lResult == ERROR_SUCCESS) {
628 // Copy from stack buffer.
629 sOut.assign(szStackBuffer, wcsnlen(szStackBuffer, dwSize/sizeof(wchar_t)));
630 } else if (lResult == ERROR_MORE_DATA) {
631 // Allocate buffer on heap and retry.
632 std::unique_ptr<wchar_t[]> szBuffer(new wchar_t[(dwSize + sizeof(wchar_t) - 1)/sizeof(wchar_t)]);
633 sOut.assign(szBuffer.get(), (lResult = RegLoadMUIStringW(hKey, pszValue, szBuffer.get(), dwSize, &dwSize, Flags, pszDirectory)) == ERROR_SUCCESS ? wcsnlen(szBuffer.get(), dwSize/sizeof(wchar_t)) : 0);
634 }
635
636 return lResult;
637}
638
639#endif
640
646template<class _Traits, class _Ax>
647static _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
648{
649 CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)];
650
651 // Try to convert to stack buffer first.
652 int cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar);
653 if (cch) {
654 // Copy from stack. Be careful not to include zero terminator.
655 sMultiByteStr.assign(szStackBuffer, cchWideChar != -1 ? strnlen(szStackBuffer, cch) : (size_t)cch - 1);
656 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
657 // Query the required output size. Allocate buffer. Then convert again.
658 cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, NULL, 0, lpDefaultChar, lpUsedDefaultChar);
659 std::unique_ptr<CHAR[]> szBuffer(new CHAR[cch]);
660 cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szBuffer.get(), cch, lpDefaultChar, lpUsedDefaultChar);
661 sMultiByteStr.assign(szBuffer.get(), cchWideChar != -1 ? strnlen(szBuffer.get(), cch) : (size_t)cch - 1);
662 }
663
664 return cch;
665}
666
672template<class _Ax>
673static _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
674{
675 CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)];
676
677 // Try to convert to stack buffer first.
678 int cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar);
679 if (cch) {
680 // Copy from stack.
681 sMultiByteStr.assign(szStackBuffer, szStackBuffer + cch);
682 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
683 // Query the required output size. Allocate buffer. Then convert again.
684 cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, NULL, 0, lpDefaultChar, lpUsedDefaultChar);
685 sMultiByteStr.resize(cch);
686 cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, sMultiByteStr.data(), cch, lpDefaultChar, lpUsedDefaultChar);
687 }
688
689 return cch;
690}
691
697template<class _Traits1, class _Ax1, class _Traits2, class _Ax2>
698static _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
699{
700 CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)];
701
702 // Try to convert to stack buffer first.
703 int cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar);
704 if (cch) {
705 // Copy from stack.
706 sMultiByteStr.assign(szStackBuffer, cch);
707 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
708 // Query the required output size. Allocate buffer. Then convert again.
709 cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), NULL, 0, lpDefaultChar, lpUsedDefaultChar);
710 std::unique_ptr<CHAR[]> szBuffer(new CHAR[cch]);
711 cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), szBuffer.get(), cch, lpDefaultChar, lpUsedDefaultChar);
712 sMultiByteStr.assign(szBuffer.get(), cch);
713 }
714
715 return cch;
716}
717
725template<class _Traits, class _Ax>
726static _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
727{
728 CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)];
729
730 // Try to convert to stack buffer first.
731 int cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar);
732 if (cch) {
733 // Copy from stack. Be careful not to include zero terminator.
734 sMultiByteStr.assign(szStackBuffer, cchWideChar != -1 ? strnlen(szStackBuffer, cch) : (size_t)cch - 1);
735 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
736 // Query the required output size. Allocate buffer. Then convert again.
737 cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, NULL, 0, lpDefaultChar, lpUsedDefaultChar);
738 std::unique_ptr<CHAR[]> szBuffer(new CHAR[cch]);
739 cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szBuffer.get(), cch, lpDefaultChar, lpUsedDefaultChar);
740 sMultiByteStr.assign(szBuffer.get(), cchWideChar != -1 ? strnlen(szBuffer.get(), cch) : (size_t)cch - 1);
741 SecureZeroMemory(szBuffer.get(), sizeof(CHAR)*cch);
742 }
743
744 SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer));
745
746 return cch;
747}
748
756template<class _Ax>
757static _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
758{
759 CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)];
760
761 // Try to convert to stack buffer first.
762 int cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar);
763 if (cch) {
764 // Copy from stack.
765 sMultiByteStr.assign(szStackBuffer, szStackBuffer + cch);
766 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
767 // Query the required output size. Allocate buffer. Then convert again.
768 cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, NULL, 0, lpDefaultChar, lpUsedDefaultChar);
769 sMultiByteStr.resize(cch);
770 cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, sMultiByteStr.data(), cch, lpDefaultChar, lpUsedDefaultChar);
771 }
772
773 SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer));
774
775 return cch;
776}
777
785template<class _Traits1, class _Ax1, class _Traits2, class _Ax2>
786static _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
787{
788 CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)];
789
790 // Try to convert to stack buffer first.
791 int cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar);
792 if (cch) {
793 // Copy from stack.
794 sMultiByteStr.assign(szStackBuffer, cch);
795 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
796 // Query the required output size. Allocate buffer. Then convert again.
797 cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), NULL, 0, lpDefaultChar, lpUsedDefaultChar);
798 std::unique_ptr<CHAR[]> szBuffer(new CHAR[cch]);
799 cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), szBuffer.get(), cch, lpDefaultChar, lpUsedDefaultChar);
800 sMultiByteStr.assign(szBuffer.get(), cch);
801 SecureZeroMemory(szBuffer.get(), sizeof(CHAR)*cch);
802 }
803
804 SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer));
805
806 return cch;
807}
808
814template<class _Traits, class _Ax>
815static _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
816{
817 WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)];
818
819 // Try to convert to stack buffer first.
820 int cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szStackBuffer, _countof(szStackBuffer));
821 if (cch) {
822 // Copy from stack.
823 sWideCharStr.assign(szStackBuffer, cbMultiByte != -1 ? wcsnlen(szStackBuffer, cch) : (size_t)cch - 1);
824 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
825 // Query the required output size. Allocate buffer. Then convert again.
826 cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, NULL, 0);
827 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[cch]);
828 cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szBuffer.get(), cch);
829 sWideCharStr.assign(szBuffer.get(), cbMultiByte != -1 ? wcsnlen(szBuffer.get(), cch) : (size_t)cch - 1);
830 }
831
832 return cch;
833}
834
840template<class _Ax>
841static _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
842{
843 WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)];
844
845 // Try to convert to stack buffer first.
846 int cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szStackBuffer, _countof(szStackBuffer));
847 if (cch) {
848 // Copy from stack.
849 sWideCharStr.assign(szStackBuffer, szStackBuffer + cch);
850 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
851 // Query the required output size. Allocate buffer. Then convert again.
852 cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, NULL, 0);
853 sWideCharStr.resize(cch);
854 cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, sWideCharStr.data(), cch);
855 }
856
857 return cch;
858}
859
865template<class _Traits1, class _Ax1, class _Traits2, class _Ax2>
866static _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
867{
868 WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)];
869
870 // Try to convert to stack buffer first.
871 int cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), szStackBuffer, _countof(szStackBuffer));
872 if (cch) {
873 // Copy from stack.
874 sWideCharStr.assign(szStackBuffer, cch);
875 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
876 // Query the required output size. Allocate buffer. Then convert again.
877 cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), NULL, 0);
878 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[cch]);
879 cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), szBuffer.get(), cch);
880 sWideCharStr.assign(szBuffer.get(), cch);
881 }
882
883 return cch;
884}
885
893template<class _Traits, class _Ax>
894static _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
895{
896 WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)];
897
898 // Try to convert to stack buffer first.
899 int cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szStackBuffer, _countof(szStackBuffer));
900 if (cch) {
901 // Copy from stack.
902 sWideCharStr.assign(szStackBuffer, cbMultiByte != -1 ? wcsnlen(szStackBuffer, cch) : (size_t)cch - 1);
903 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
904 // Query the required output size. Allocate buffer. Then convert again.
905 cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, NULL, 0);
906 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[cch]);
907 cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szBuffer.get(), cch);
908 sWideCharStr.assign(szBuffer.get(), cbMultiByte != -1 ? wcsnlen(szBuffer.get(), cch) : (size_t)cch - 1);
909 SecureZeroMemory(szBuffer.get(), sizeof(WCHAR)*cch);
910 }
911
912 SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer));
913
914 return cch;
915}
916
924template<class _Ax>
925static _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
926{
927 WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)];
928
929 // Try to convert to stack buffer first.
930 int cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szStackBuffer, _countof(szStackBuffer));
931 if (cch) {
932 // Copy from stack.
933 sWideCharStr.assign(szStackBuffer, szStackBuffer + cch);
934 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
935 // Query the required output size. Allocate buffer. Then convert again.
936 cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, NULL, 0);
937 sWideCharStr.resize(cch);
938 cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, sWideCharStr.data(), cch);
939 }
940
941 SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer));
942
943 return cch;
944}
945
953template<class _Traits1, class _Ax1, class _Traits2, class _Ax2>
954static _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
955{
956 WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)];
957
958 // Try to convert to stack buffer first.
959 int cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), szStackBuffer, _countof(szStackBuffer));
960 if (cch) {
961 // Copy from stack.
962 sWideCharStr.assign(szStackBuffer, cch);
963 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
964 // Query the required output size. Allocate buffer. Then convert again.
965 cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), NULL, 0);
966 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[cch]);
967 cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), szBuffer.get(), cch);
968 sWideCharStr.assign(szBuffer.get(), cch);
969 SecureZeroMemory(szBuffer.get(), sizeof(WCHAR)*cch);
970 }
971
972 SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer));
973
974 return cch;
975}
976
982template<class _Traits, class _Ax>
983static _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
984{
985 WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)];
986
987 // Try to convert to stack buffer first.
988 int cch = ::NormalizeString(NormForm, lpSrcString, cwSrcLength, szStackBuffer, _countof(szStackBuffer));
989 if (cch > 0) {
990 // Copy from stack.
991 sDstString.assign(szStackBuffer, cwSrcLength != -1 ? wcsnlen(szStackBuffer, cch) : (size_t)cch - 1);
992 } else {
993 switch (::GetLastError()) {
994 case ERROR_INSUFFICIENT_BUFFER:
995 for (int i = 10; i--;) {
996 // Allocate buffer. Then convert again.
997 cch = -cch;
998 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[cch]);
999 cch = ::NormalizeString(NormForm, lpSrcString, cwSrcLength, szBuffer.get(), cch);
1000 if (cch > 0) {
1001 sDstString.assign(szBuffer.get(), cwSrcLength != -1 ? wcsnlen(szStackBuffer, cch) : (size_t)cch - 1);
1002 break;
1003 }
1004 if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1005 sDstString.clear();
1006 break;
1007 }
1008 }
1009 break;
1010
1011 case ERROR_SUCCESS:
1012 sDstString.clear();
1013 break;
1014 }
1015 }
1016
1017 return cch;
1018}
1019
1025template<class _Traits1, class _Ax1, class _Traits2, class _Ax2>
1026static _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
1027{
1028 WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)];
1029
1030 // Try to convert to stack buffer first.
1031 int cch = ::NormalizeString(NormForm, sSrcString.c_str(), (int)sSrcString.length(), szStackBuffer, _countof(szStackBuffer));
1032 if (cch > 0) {
1033 // Copy from stack.
1034 sDstString.assign(szStackBuffer, cch);
1035 } else {
1036 switch (::GetLastError()) {
1037 case ERROR_INSUFFICIENT_BUFFER:
1038 for (int i = 10; i--;) {
1039 // Allocate buffer. Then convert again.
1040 cch = -cch;
1041 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[cch]);
1042 cch = ::NormalizeString(NormForm, sSrcString.c_str(), (int)sSrcString.length(), szBuffer.get(), cch);
1043 if (cch > 0) {
1044 sDstString.assign(szBuffer.get(), cch);
1045 break;
1046 }
1047 if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1048 sDstString.clear();
1049 break;
1050 }
1051 }
1052 break;
1053
1054 case ERROR_SUCCESS:
1055 sDstString.clear();
1056 break;
1057 }
1058 }
1059
1060 return cch;
1061}
1062
1064template<class _Traits, class _Ax>
1065static _Success_(return != 0) int WINAPI LoadStringA(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_ std::basic_string<char, _Traits, _Ax> &sBuffer) noexcept
1066{
1067 // Get read-only pointer to string resource.
1068 LPCSTR pszStr;
1069 int i = LoadStringA(hInstance, uID, reinterpret_cast<LPSTR>(&pszStr), 0);
1070 if (i) {
1071 sBuffer.assign(pszStr, i);
1072 return i;
1073 } else
1074 return 0;
1075}
1076
1082template<class _Traits, class _Ax>
1083static _Success_(return != 0) int WINAPI LoadStringW(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_ std::basic_string<wchar_t, _Traits, _Ax> &sBuffer) noexcept
1084{
1085 // Get read-only pointer to string resource.
1086 LPCWSTR pszStr;
1087 int i = LoadStringW(hInstance, uID, reinterpret_cast<LPWSTR>(&pszStr), 0);
1088 if (i) {
1089 sBuffer.assign(pszStr, i);
1090 return i;
1091 } else
1092 return 0;
1093}
1094
1100static VOID OutputDebugStrV(_In_z_ LPCSTR lpOutputString, _In_ va_list arg) noexcept
1101{
1102 std::string str;
1103 try { vsprintf(str, lpOutputString, arg); } catch (...) { return; }
1104 OutputDebugStringA(str.c_str());
1105}
1106
1112static VOID OutputDebugStrV(_In_z_ LPCWSTR lpOutputString, _In_ va_list arg) noexcept
1113{
1114 std::wstring str;
1115 try { vsprintf(str, lpOutputString, arg); } catch (...) { return; }
1116 OutputDebugStringW(str.c_str());
1117}
1118
1124static VOID OutputDebugStr(_In_z_ LPCSTR lpOutputString, ...) noexcept
1125{
1126 va_list arg;
1127 va_start(arg, lpOutputString);
1128 OutputDebugStrV(lpOutputString, arg);
1129 va_end(arg);
1130}
1131
1137static VOID OutputDebugStr(_In_z_ LPCWSTR lpOutputString, ...) noexcept
1138{
1139 va_list arg;
1140 va_start(arg, lpOutputString);
1141 OutputDebugStrV(lpOutputString, arg);
1142 va_end(arg);
1143}
1144
1146template<class _Traits, class _Ax>
1147static _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
1148{
1149 int iResult = GetDateFormatA(Locale, dwFlags, lpDate, lpFormat, NULL, 0);
1150 if (iResult) {
1151 // Allocate buffer on heap and retry.
1152 std::unique_ptr<char[]> szBuffer(new char[iResult]);
1153 iResult = GetDateFormatA(Locale, dwFlags, lpDate, lpFormat, szBuffer.get(), iResult);
1154 sDate.assign(szBuffer.get(), iResult ? iResult - 1 : 0);
1155 return iResult;
1156 }
1157
1158 return iResult;
1159}
1160
1166template<class _Traits, class _Ax>
1167static _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
1168{
1169 int iResult = GetDateFormatW(Locale, dwFlags, lpDate, lpFormat, NULL, 0);
1170 if (iResult) {
1171 // Allocate buffer on heap and retry.
1172 std::unique_ptr<wchar_t[]> szBuffer(new wchar_t[iResult]);
1173 iResult = GetDateFormatW(Locale, dwFlags, lpDate, lpFormat, szBuffer.get(), iResult);
1174 sDate.assign(szBuffer.get(), iResult ? iResult - 1 : 0);
1175 return iResult;
1176 }
1177
1178 return iResult;
1179}
1180
1182template<class _Traits, class _Ax>
1183static _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
1184{
1185 assert(0); // TODO: Test this code.
1186
1187 DWORD dwNameLen = 0, dwRefDomainLen = 0;
1188
1189 if (LookupAccountSidA(lpSystemName, lpSid,
1190 NULL, &dwNameLen ,
1191 NULL, &dwRefDomainLen,
1192 peUse))
1193 {
1194 // Name and domain is blank.
1195 if (sName ) sName ->clear();
1196 if (sReferencedDomainName) sReferencedDomainName->clear();
1197 return TRUE;
1198 } else if (GetLastError() == ERROR_MORE_DATA) {
1199 // Allocate on heap and retry.
1200 std::unique_ptr<char[]> bufName (new char[dwNameLen ]);
1201 std::unique_ptr<char[]> bufRefDomain(new char[dwRefDomainLen]);
1202 if (LookupAccountSidA(lpSystemName, lpSid,
1203 bufName .get(), &dwNameLen ,
1204 bufRefDomain.get(), &dwRefDomainLen,
1205 peUse))
1206 {
1207 if (sName ) sName ->assign(bufName .get(), dwNameLen - 1);
1208 if (sReferencedDomainName) sReferencedDomainName->assign(bufRefDomain.get(), dwRefDomainLen - 1);
1209 return TRUE;
1210 }
1211 }
1212
1213 return FALSE;
1214}
1215
1221template<class _Traits, class _Ax>
1222static _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
1223{
1224 assert(0); // TODO: Test this code.
1225
1226 DWORD dwNameLen = 0, dwRefDomainLen = 0;
1227
1228 if (LookupAccountSidW(lpSystemName, lpSid,
1229 NULL, &dwNameLen ,
1230 NULL, &dwRefDomainLen,
1231 peUse))
1232 {
1233 // Name and domain is blank.
1234 if (sName ) sName ->clear();
1235 if (sReferencedDomainName) sReferencedDomainName->clear();
1236 return TRUE;
1237 } else if (GetLastError() == ERROR_MORE_DATA) {
1238 // Allocate on heap and retry.
1239 std::unique_ptr<wchar_t[]> bufName (new wchar_t[dwNameLen ]);
1240 std::unique_ptr<wchar_t[]> bufRefDomain(new wchar_t[dwRefDomainLen]);
1241 if (LookupAccountSidW(lpSystemName, lpSid,
1242 bufName .get(), &dwNameLen ,
1243 bufRefDomain.get(), &dwRefDomainLen,
1244 peUse))
1245 {
1246 if (sName ) sName ->assign(bufName .get(), dwNameLen - 1);
1247 if (sReferencedDomainName) sReferencedDomainName->assign(bufRefDomain.get(), dwRefDomainLen - 1);
1248 return TRUE;
1249 }
1250 }
1251
1252 return FALSE;
1253}
1254
1260template<class _Ty>
1261static _Success_(return != 0) BOOL GetTokenInformation(_In_ HANDLE TokenHandle, _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, _Out_ std::unique_ptr<_Ty> &TokenInformation) noexcept
1262{
1263 BYTE szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(BYTE)];
1264 DWORD dwSize;
1265
1266 if (GetTokenInformation(TokenHandle, TokenInformationClass, szStackBuffer, sizeof(szStackBuffer), &dwSize)) {
1267 // The stack buffer was big enough to retrieve complete data. Alloc and copy.
1268 TokenInformation.reset((_Ty*)(new BYTE[dwSize / sizeof(BYTE)]));
1269 if (!TokenInformation) {
1270 SetLastError(ERROR_OUTOFMEMORY);
1271 return FALSE;
1272 }
1273 memcpy(TokenInformation.get(), szStackBuffer, dwSize);
1274 return TRUE;
1275 } else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
1276 // The stack buffer was too small to retrieve complete data. Alloc and retry.
1277 TokenInformation.reset((_Ty*)(new BYTE[dwSize / sizeof(BYTE)]));
1278 if (!TokenInformation) {
1279 SetLastError(ERROR_OUTOFMEMORY);
1280 return FALSE;
1281 }
1282 return GetTokenInformation(TokenHandle, TokenInformationClass, TokenInformation.get(), dwSize, &dwSize);
1283 } else
1284 return FALSE;
1285}
1286
1292template<class _Traits, class _Ax>
1293static _Success_(return != 0) BOOL QueryFullProcessImageNameA(_In_ HANDLE hProcess, _In_ DWORD dwFlags, _Inout_ std::basic_string<char, _Traits, _Ax>& sExeName)
1294{
1295 char szStackBuffer[WINSTD_STACK_BUFFER_BYTES / sizeof(char)];
1296 DWORD dwSize = _countof(szStackBuffer);
1297
1298 // Try with stack buffer first.
1299 if (::QueryFullProcessImageNameA(hProcess, dwFlags, szStackBuffer, &dwSize)) {
1300 // Copy from stack.
1301 sExeName.assign(szStackBuffer, dwSize);
1302 return TRUE;
1303 }
1304 for (DWORD dwCapacity = 2 * WINSTD_STACK_BUFFER_BYTES / sizeof(char); GetLastError() == ERROR_INSUFFICIENT_BUFFER; dwCapacity *= 2) {
1305 // Allocate on heap and retry.
1306 std::unique_ptr<char[]> szBuffer(new char[dwCapacity]);
1307 dwSize = dwCapacity;
1308 if (::QueryFullProcessImageNameA(hProcess, dwFlags, szBuffer.get(), &dwSize)) {
1309 sExeName.assign(szBuffer.get(), dwSize);
1310 return TRUE;
1311 }
1312 }
1313 return FALSE;
1314}
1315
1321template<class _Traits, class _Ax>
1322static _Success_(return != 0) BOOL QueryFullProcessImageNameW(_In_ HANDLE hProcess, _In_ DWORD dwFlags, _Inout_ std::basic_string<wchar_t, _Traits, _Ax>& sExeName)
1323{
1324 wchar_t szStackBuffer[WINSTD_STACK_BUFFER_BYTES / sizeof(wchar_t)];
1325 DWORD dwSize = _countof(szStackBuffer);
1326
1327 // Try with stack buffer first.
1328 if (::QueryFullProcessImageNameW(hProcess, dwFlags, szStackBuffer, &dwSize)) {
1329 // Copy from stack.
1330 sExeName.assign(szStackBuffer, dwSize);
1331 return TRUE;
1332 }
1333 for (DWORD dwCapacity = 2 * WINSTD_STACK_BUFFER_BYTES / sizeof(wchar_t); GetLastError() == ERROR_INSUFFICIENT_BUFFER; dwCapacity *= 2) {
1334 // Allocate on heap and retry.
1335 std::unique_ptr<wchar_t[]> szBuffer(new wchar_t[dwCapacity]);
1336 dwSize = dwCapacity;
1337 if (::QueryFullProcessImageNameW(hProcess, dwFlags, szBuffer.get(), &dwSize)) {
1338 sExeName.assign(szBuffer.get(), dwSize);
1339 return TRUE;
1340 }
1341 }
1342 return FALSE;
1343}
1344
1346
1347#pragma warning(pop)
1348
1349namespace winstd
1350{
1353
1357 template<HANDLE INVALID>
1358 class win_handle : public handle<HANDLE, INVALID>
1359 {
1361
1362 public:
1368 virtual ~win_handle()
1369 {
1370 if (m_h != invalid)
1371 free_internal();
1372 }
1373
1374 protected:
1380 void free_internal() noexcept override
1381 {
1382 CloseHandle(m_h);
1383 }
1384 };
1385
1389 class library : public handle<HMODULE, NULL>
1390 {
1392
1393 public:
1399 virtual ~library()
1400 {
1401 if (m_h != invalid)
1402 free_internal();
1403 }
1404
1414 __declspec(deprecated("Use LoadLibraryEx"))
1415 bool load(_In_z_ LPCTSTR lpFileName, __reserved handle_type hFile, _In_ DWORD dwFlags) noexcept
1416 {
1417 handle_type h = LoadLibraryEx(lpFileName, hFile, dwFlags);
1418 if (h != invalid) {
1419 attach(h);
1420 return true;
1421 } else
1422 return false;
1423 }
1424
1425 protected:
1431 void free_internal() noexcept override
1432 {
1433 FreeLibrary(m_h);
1434 }
1435 };
1436
1440 class process : public win_handle<NULL>
1441 {
1443
1444 public:
1454 __declspec(deprecated("Use OpenProcess"))
1455 bool open(_In_ DWORD dwDesiredAccess, _In_ BOOL bInheritHandle, _In_ DWORD dwProcessId) noexcept
1456 {
1457 handle_type h = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
1458 if (h != invalid) {
1459 attach(h);
1460 return true;
1461 } else
1462 return false;
1463 }
1464 };
1465
1472
1479
1483 class file : public win_handle<INVALID_HANDLE_VALUE>
1484 {
1485 WINSTD_WINHANDLE_IMPL(file, INVALID_HANDLE_VALUE)
1486
1487 public:
1497 __declspec(deprecated("Use CreateFile"))
1498 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
1499 {
1500 handle_type h = CreateFile(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
1501 if (h != invalid) {
1502 attach(h);
1503 return true;
1504 } else
1505 return false;
1506 }
1507 };
1508
1512 class file_mapping : public win_handle<NULL>
1513 {
1515
1516 public:
1526 __declspec(deprecated("Use CreateFileMapping"))
1527 bool create(_In_ HANDLE hFile, _In_ DWORD flProtect, _In_ DWORD dwMaximumSizeHigh, _In_ DWORD dwMaximumSizeLow, _In_opt_ LPSECURITY_ATTRIBUTES lpFileMappingAttributes = NULL, _In_opt_ LPCTSTR lpName = NULL) noexcept
1528 {
1529 handle_type h = CreateFileMapping(hFile, lpFileMappingAttributes, flProtect, dwMaximumSizeHigh, dwMaximumSizeLow, lpName);
1530 if (h != invalid) {
1531 attach(h);
1532 return true;
1533 } else
1534 return false;
1535 }
1536 };
1537
1541 template <class _Ty> struct UnmapViewOfFile_delete
1542 {
1544
1549
1554
1558 void operator()(_Ty* _Ptr) const
1559 {
1560 if (!UnmapViewOfFile(_Ptr))
1561 throw win_runtime_error("UnmapViewOfFile failed");
1562 }
1563 };
1564
1568 template <class _Ty> struct UnmapViewOfFile_delete<_Ty[]>
1569 {
1571
1576
1580 void operator()(_Ty* _Ptr) const
1581 {
1582 if (!UnmapViewOfFile(_Ptr))
1583 throw win_runtime_error("UnmapViewOfFile failed");
1584 }
1585
1589 template<class _Other>
1590 void operator()(_Other*) const
1591 {
1592 if (!UnmapViewOfFile(_Ptr))
1593 throw win_runtime_error("UnmapViewOfFile failed");
1594 }
1595 };
1596
1600 class event : public win_handle<NULL>
1601 {
1603
1604 public:
1614 __declspec(deprecated("Use CreateEvent"))
1615 bool create(_In_ BOOL bManualReset, _In_ BOOL bInitialState, _In_opt_ LPSECURITY_ATTRIBUTES lpEventAttributes = NULL, _In_opt_z_ LPCTSTR lpName = NULL) noexcept
1616 {
1617 handle_type h = CreateEvent(lpEventAttributes, bManualReset, bInitialState, lpName);
1618 if (h != invalid) {
1619 attach(h);
1620 return true;
1621 } else
1622 return false;
1623 }
1624
1634 __declspec(deprecated("Use OpenEvent"))
1635 bool open(_In_ DWORD dwDesiredAccess, _In_ BOOL bInheritHandle, _In_z_ LPCTSTR lpName) noexcept
1636 {
1637 handle_type h = OpenEvent(dwDesiredAccess, bInheritHandle, lpName);
1638 if (h != invalid) {
1639 attach(h);
1640 return true;
1641 } else
1642 return false;
1643 }
1644 };
1645
1650 {
1653
1654 public:
1661 {
1662 __try {
1663 InitializeCriticalSection(&m_data);
1664 } __except(EXCEPTION_EXECUTE_HANDLER) {
1665 throw std::runtime_error("InitializeCriticalSection failed");
1666 }
1667 }
1668
1675 {
1676 DeleteCriticalSection(&m_data);
1677 }
1678
1684 operator LPCRITICAL_SECTION() noexcept
1685 {
1686 return &m_data;
1687 }
1688
1689 protected:
1690 CRITICAL_SECTION m_data;
1691 };
1692
1696 class find_file : public handle<HANDLE, INVALID_HANDLE_VALUE>
1697 {
1698 WINSTD_HANDLE_IMPL(find_file, INVALID_HANDLE_VALUE)
1699
1700 public:
1706 virtual ~find_file()
1707 {
1708 if (m_h != invalid)
1709 free_internal();
1710 }
1711
1721 __declspec(deprecated("Use FindFirstFile"))
1722 bool find(_In_ LPCTSTR lpFileName, _Out_ LPWIN32_FIND_DATA lpFindFileData) noexcept
1723 {
1724 handle_type h = FindFirstFile(lpFileName, lpFindFileData);
1725 if (h != invalid) {
1726 attach(h);
1727 return true;
1728 } else
1729 return false;
1730 }
1731
1732 protected:
1738 void free_internal() noexcept override
1739 {
1740 FindClose(m_h);
1741 }
1742 };
1743
1747 class heap : public handle<HANDLE, NULL>
1748 {
1750
1751 public:
1757 virtual ~heap()
1758 {
1759 if (m_h != invalid)
1760 free_internal();
1761 }
1762
1772 __declspec(deprecated("Use HeapCreate"))
1773 bool create(_In_ DWORD flOptions, _In_ SIZE_T dwInitialSize, _In_ SIZE_T dwMaximumSize) noexcept
1774 {
1775 handle_type h = HeapCreate(flOptions, dwInitialSize, dwMaximumSize);
1776 if (h != invalid) {
1777 attach(h);
1778 return true;
1779 } else
1780 return false;
1781 }
1782
1790 bool enumerate() noexcept
1791 {
1792 assert(m_h != invalid);
1793
1794 bool found = false;
1795
1796 // Lock the heap for exclusive access.
1797 HeapLock(m_h);
1798
1799 PROCESS_HEAP_ENTRY e;
1800 e.lpData = NULL;
1801 while (HeapWalk(m_h, &e) != FALSE) {
1802 if ((e.wFlags & PROCESS_HEAP_ENTRY_BUSY) != 0) {
1803 OutputDebugStr(
1804 _T("Allocated block%s%s\n")
1805 _T(" Data portion begins at: %#p\n Size: %d bytes\n")
1806 _T(" Overhead: %d bytes\n Region index: %d\n"),
1807 (e.wFlags & PROCESS_HEAP_ENTRY_MOVEABLE) != 0 ? tstring_printf(_T(", movable with HANDLE %#p"), e.Block.hMem).c_str() : _T(""),
1808 (e.wFlags & PROCESS_HEAP_ENTRY_DDESHARE) != 0 ? _T(", DDESHARE") : _T(""),
1809 e.lpData,
1810 e.cbData,
1811 e.cbOverhead,
1812 e.iRegionIndex);
1813
1814 found = true;
1815 }
1816 }
1817
1818 const DWORD dwResult = GetLastError();
1819 if (dwResult != ERROR_NO_MORE_ITEMS)
1820 OutputDebugStr(_T("HeapWalk failed (error %u).\n"), dwResult);
1821
1822 // Unlock the heap.
1823 HeapUnlock(m_h);
1824
1825 return found;
1826 }
1827
1828 protected:
1834 void free_internal() noexcept override
1835 {
1836 enumerate();
1837 HeapDestroy(m_h);
1838 }
1839 };
1840
1844 template <class _Ty>
1846 {
1847 public:
1848 typedef typename _Ty value_type;
1849
1850 typedef _Ty *pointer;
1851 typedef _Ty& reference;
1852 typedef const _Ty *const_pointer;
1853 typedef const _Ty& const_reference;
1854
1855 typedef SIZE_T size_type;
1856 typedef ptrdiff_t difference_type;
1857
1861 template <class _Other>
1862 struct rebind
1863 {
1865 };
1866
1867 public:
1874 {
1875 }
1876
1882 template <class _Other>
1884 {
1885 }
1886
1895 {
1896 assert(m_heap);
1897 return (pointer)HeapAlloc(m_heap, 0, count * sizeof(_Ty));
1898 }
1899
1906 void deallocate(_In_ pointer ptr, _In_ size_type size)
1907 {
1908 UNREFERENCED_PARAMETER(size);
1909 assert(m_heap);
1910 HeapFree(m_heap, 0, ptr);
1911 }
1912
1919 void construct(_Inout_ pointer ptr, _In_ const _Ty& val)
1920 {
1921 ::new ((void*)ptr) _Ty(val);
1922 }
1923
1930 void construct(_Inout_ pointer ptr, _Inout_ _Ty&& val)
1931 {
1932 ::new ((void*)ptr) _Ty(std::forward<_Ty>(val));
1933 }
1934
1940 void destroy(_Inout_ pointer ptr)
1941 {
1942 ptr->_Ty::~_Ty();
1943 }
1944
1949 {
1950 return (SIZE_T)-1;
1951 }
1952
1953 public:
1954 HANDLE m_heap;
1955 };
1956
1961 {
1964
1965 public:
1973 actctx_activator(_In_ HANDLE hActCtx) noexcept
1974 {
1975 if (!ActivateActCtx(hActCtx, &m_cookie))
1976 m_cookie = 0;
1977 }
1978
1985 {
1986 if (m_cookie)
1987 DeactivateActCtx(0, m_cookie);
1988 }
1989
1990 protected:
1991 ULONG_PTR m_cookie;
1992 };
1993
1998 {
2001
2002 public:
2010 user_impersonator(_In_opt_ HANDLE hToken) noexcept
2011 {
2012 m_cookie = hToken && ImpersonateLoggedOnUser(hToken);
2013 }
2014
2021 {
2022 if (m_cookie)
2023 RevertToSelf();
2024 }
2025
2026 protected:
2028 };
2029
2034 {
2037
2038 public:
2046 console_ctrl_handler(_In_opt_ PHANDLER_ROUTINE HandlerRoutine) noexcept : m_handler(HandlerRoutine)
2047 {
2048 m_cookie = SetConsoleCtrlHandler(m_handler, TRUE);
2049 }
2050
2057 {
2058 if (m_cookie)
2059 SetConsoleCtrlHandler(m_handler, FALSE);
2060 }
2061
2062 protected:
2064 PHANDLER_ROUTINE m_handler;
2065 };
2066
2070 class vmemory : public handle<LPVOID, NULL>
2071 {
2073
2074 public:
2078 vmemory() noexcept : m_proc(NULL)
2079 {
2080 }
2081
2088 vmemory(_In_ handle_type h, _In_ HANDLE proc) noexcept :
2089 m_proc(proc),
2091 {
2092 }
2093
2099 vmemory(_Inout_ vmemory &&h) noexcept :
2100 m_proc(std::move(h.m_proc)),
2101 handle<LPVOID, NULL>(std::move(h))
2102 {
2103 }
2104
2110 virtual ~vmemory()
2111 {
2112 if (m_h != invalid)
2113 VirtualFreeEx(m_proc, m_h, 0, MEM_RELEASE);
2114 }
2115
2121 vmemory& operator=(_Inout_ vmemory &&other) noexcept
2122 {
2123 if (this != std::addressof(other)) {
2124 (handle<handle_type, NULL>&&)*this = std::move(other);
2125 m_proc = std::move(other.m_proc);
2126 }
2127 return *this;
2128 }
2129
2138 void attach(_In_ HANDLE proc, _In_opt_ handle_type h) noexcept
2139 {
2140 m_proc = proc;
2141 if (m_h != invalid)
2142 free_internal();
2143 m_h = h;
2144 }
2145
2155 bool alloc(
2156 _In_ HANDLE hProcess,
2157 _In_opt_ LPVOID lpAddress,
2158 _In_ SIZE_T dwSize,
2159 _In_ DWORD flAllocationType,
2160 _In_ DWORD flProtect) noexcept
2161 {
2162 handle_type h = VirtualAllocEx(hProcess, lpAddress, dwSize, flAllocationType, flProtect);
2163 if (h != invalid) {
2164 attach(hProcess, h);
2165 return true;
2166 } else
2167 return false;
2168 }
2169
2170 protected:
2176 void free_internal() noexcept override
2177 {
2178 VirtualFreeEx(m_proc, m_h, 0, MEM_RELEASE);
2179 }
2180
2181 protected:
2182 HANDLE m_proc;
2183 };
2184
2188 class reg_key : public handle<HKEY, NULL>
2189 {
2191
2192 public:
2198 virtual ~reg_key()
2199 {
2200 if (m_h != invalid)
2201 free_internal();
2202 }
2203
2213 __declspec(deprecated("Use RegCreateKeyEx - mind it returns error number rather than SetLastError"))
2214 bool create(
2215 _In_ HKEY hKey,
2216 _In_z_ LPCTSTR lpSubKey,
2217 _In_opt_ LPTSTR lpClass,
2218 _In_ DWORD dwOptions,
2219 _In_ REGSAM samDesired,
2220 _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes = NULL,
2221 _Out_opt_ LPDWORD lpdwDisposition = NULL) noexcept
2222 {
2223 handle_type h;
2224 const LSTATUS s = RegCreateKeyEx(hKey, lpSubKey, 0, lpClass, dwOptions, samDesired, lpSecurityAttributes, &h, lpdwDisposition);
2225 if (s == ERROR_SUCCESS) {
2226 attach(h);
2227 return true;
2228 } else {
2229 SetLastError(s);
2230 return false;
2231 }
2232 }
2233
2243 __declspec(deprecated("Use RegOpenKeyEx - mind it returns error number rather than SetLastError"))
2244 bool open(
2245 _In_ HKEY hKey,
2246 _In_opt_z_ LPCTSTR lpSubKey,
2247 _In_ DWORD ulOptions,
2248 _In_ REGSAM samDesired) noexcept
2249 {
2250 handle_type h;
2251 const LSTATUS s = RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired, &h);
2252 if (s == ERROR_SUCCESS) {
2253 attach(h);
2254 return true;
2255 } else {
2256 SetLastError(s);
2257 return false;
2258 }
2259 }
2260
2270 bool delete_subkey(_In_z_ LPCTSTR szSubkey)
2271 {
2272 LSTATUS s;
2273
2274 s = RegDeleteKey(m_h, szSubkey);
2275 if (s == ERROR_SUCCESS || s == ERROR_FILE_NOT_FOUND)
2276 return true;
2277
2278 {
2279 reg_key k;
2280 handle_type h;
2281 s = RegOpenKeyEx(m_h, szSubkey, 0, KEY_ENUMERATE_SUB_KEYS, &h);
2282 if (s == ERROR_SUCCESS)
2283 k.attach(h);
2284 else {
2285 SetLastError(s);
2286 return false;
2287 }
2288 for (;;) {
2289 TCHAR szName[MAX_PATH];
2290 DWORD dwSize = _countof(szName);
2291 s = RegEnumKeyEx(k, 0, szName, &dwSize, NULL, NULL, NULL, NULL);
2292 if (s == ERROR_SUCCESS)
2293 k.delete_subkey(szName);
2294 else if (s == ERROR_NO_MORE_ITEMS)
2295 break;
2296 else {
2297 SetLastError(s);
2298 return false;
2299 }
2300 }
2301 }
2302
2303 s = RegDeleteKey(m_h, szSubkey);
2304 if (s == ERROR_SUCCESS)
2305 return true;
2306 else {
2307 SetLastError(s);
2308 return false;
2309 }
2310 }
2311
2312 protected:
2318 void free_internal() noexcept override
2319 {
2320 RegCloseKey(m_h);
2321 }
2322 };
2323
2327 class security_id : public handle<PSID, NULL>
2328 {
2330
2331 public:
2338 {
2339 if (m_h != invalid)
2340 free_internal();
2341 }
2342
2343 protected:
2349 void free_internal() noexcept override
2350 {
2351 FreeSid(m_h);
2352 }
2353 };
2354
2358 class process_information : public PROCESS_INFORMATION
2359 {
2362
2363 public:
2368 {
2369 hProcess = INVALID_HANDLE_VALUE;
2370 hThread = INVALID_HANDLE_VALUE;
2371 dwProcessId = 0;
2372 dwThreadId = 0;
2373 }
2374
2379 {
2380 #pragma warning(push)
2381 #pragma warning(disable: 6001) // Using uninitialized memory '*this'. << ???
2382
2383 if (hProcess != INVALID_HANDLE_VALUE)
2384 CloseHandle(hProcess);
2385
2386 if (hThread != INVALID_HANDLE_VALUE)
2387 CloseHandle(hThread);
2388
2389 #pragma warning(pop)
2390 }
2391 };
2392
2396 class event_log : public handle<HANDLE, NULL>
2397 {
2399
2400 public:
2406 virtual ~event_log()
2407 {
2408 if (m_h != invalid)
2409 free_internal();
2410 }
2411
2421 __declspec(deprecated("Use RegisterEventSource"))
2422 bool open(_In_z_ LPCTSTR lpUNCServerName, _In_z_ LPCTSTR lpSourceName) noexcept
2423 {
2424 handle_type h = RegisterEventSource(lpUNCServerName, lpSourceName);
2425 if (h != invalid) {
2426 attach(h);
2427 return true;
2428 } else
2429 return false;
2430 }
2431
2432 protected:
2438 void free_internal() noexcept override
2439 {
2440 DeregisterEventSource(m_h);
2441 }
2442 };
2443
2445}
2446
2449
2450#pragma warning(push)
2451#pragma warning(disable: 4505) // Don't warn on unused code
2452
2454static LSTATUS RegCreateKeyExA(
2455 _In_ HKEY hKey,
2456 _In_ LPCSTR lpSubKey,
2457 _Reserved_ DWORD Reserved,
2458 _In_opt_ LPSTR lpClass,
2459 _In_ DWORD dwOptions,
2460 _In_ REGSAM samDesired,
2461 _In_opt_ CONST LPSECURITY_ATTRIBUTES lpSecurityAttributes,
2462 _Inout_ winstd::reg_key &result,
2463 _Out_opt_ LPDWORD lpdwDisposition)
2464{
2465 HKEY h;
2466 LSTATUS s = RegCreateKeyExA(hKey, lpSubKey, Reserved, lpClass, dwOptions, samDesired, lpSecurityAttributes, &h, lpdwDisposition);
2467 if (s == ERROR_SUCCESS)
2468 result.attach(h);
2469 return s;
2470}
2471
2477static LSTATUS RegCreateKeyExW(
2478 _In_ HKEY hKey,
2479 _In_ LPCWSTR lpSubKey,
2480 _Reserved_ DWORD Reserved,
2481 _In_opt_ LPWSTR lpClass,
2482 _In_ DWORD dwOptions,
2483 _In_ REGSAM samDesired,
2484 _In_opt_ CONST LPSECURITY_ATTRIBUTES lpSecurityAttributes,
2485 _Inout_ winstd::reg_key &result,
2486 _Out_opt_ LPDWORD lpdwDisposition)
2487{
2488 HKEY h;
2489 LSTATUS s = RegCreateKeyExW(hKey, lpSubKey, Reserved, lpClass, dwOptions, samDesired, lpSecurityAttributes, &h, lpdwDisposition);
2490 if (s == ERROR_SUCCESS)
2491 result.attach(h);
2492 return s;
2493}
2494
2496static LSTATUS RegOpenKeyExA(
2497 _In_ HKEY hKey,
2498 _In_opt_ LPCSTR lpSubKey,
2499 _In_opt_ DWORD ulOptions,
2500 _In_ REGSAM samDesired,
2501 _Inout_ winstd::reg_key &result)
2502{
2503 HKEY h;
2504 LSTATUS s = RegOpenKeyExA(hKey, lpSubKey, ulOptions, samDesired, &h);
2505 if (s == ERROR_SUCCESS)
2506 result.attach(h);
2507 return s;
2508}
2509
2519static LSTATUS RegOpenKeyExW(
2520 _In_ HKEY hKey,
2521 _In_opt_ LPCWSTR lpSubKey,
2522 _In_opt_ DWORD ulOptions,
2523 _In_ REGSAM samDesired,
2524 _Inout_ winstd::reg_key &result)
2525{
2526 HKEY h;
2527 LSTATUS s = RegOpenKeyExW(hKey, lpSubKey, ulOptions, samDesired, &h);
2528 if (s == ERROR_SUCCESS)
2529 result.attach(h);
2530 return s;
2531}
2532
2533#pragma warning(pop)
2534
Activates given activation context in constructor and deactivates it in destructor.
Definition: Win.h:1961
actctx_activator(HANDLE hActCtx) noexcept
Construct the activator and activates the given activation context.
Definition: Win.h:1973
virtual ~actctx_activator()
Deactivates activation context and destructs the activator.
Definition: Win.h:1984
ULONG_PTR m_cookie
Cookie for context deactivation.
Definition: Win.h:1991
Base template class to support string formatting using printf() style templates.
Definition: Common.h:1114
Console control handler stack management.
Definition: Win.h:2034
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:2046
virtual ~console_ctrl_handler()
Pops console control handler from the console control handler stack.
Definition: Win.h:2056
PHANDLER_ROUTINE m_handler
Pointer to console control handler.
Definition: Win.h:2064
BOOL m_cookie
Did pushing the console control handler succeed?
Definition: Win.h:2063
Critical section wrapper.
Definition: Win.h:1650
CRITICAL_SECTION m_data
Critical section struct.
Definition: Win.h:1690
virtual ~critical_section()
Releases all resources used by an unowned critical section object.
Definition: Win.h:1674
critical_section()
Construct the object and initializes a critical section object.
Definition: Win.h:1660
Event log handle wrapper.
Definition: Win.h:2397
void free_internal() noexcept override
Closes an event log handle.
Definition: Win.h:2438
virtual ~event_log()
Closes an event log handle.
Definition: Win.h:2406
__declspec(deprecated("Use RegisterEventSource")) bool open(LPCTSTR lpUNCServerName
Retrieves a registered handle to the specified event log.
Event handle wrapper.
Definition: Win.h:1601
__declspec(deprecated("Use CreateEvent")) bool create(BOOL bManualReset
Creates or opens a named or unnamed event object.
File mapping.
Definition: Win.h:1513
__declspec(deprecated("Use CreateFileMapping")) bool create(HANDLE hFile
Creates or opens a named or unnamed file mapping object for a specified file.
File handle wrapper.
Definition: Win.h:1484
__declspec(deprecated("Use CreateFile")) bool create(LPCTSTR lpFileName
Opens file handle.
Find-file handle wrapper.
Definition: Win.h:1697
__declspec(deprecated("Use FindFirstFile")) bool find(LPCTSTR lpFileName
Searches a directory for a file or subdirectory with a name that matches a specific name (or partial ...
virtual ~find_file()
Closes a file search handle.
Definition: Win.h:1706
void free_internal() noexcept override
Closes a file search handle.
Definition: Win.h:1738
Base abstract template class to support generic object handle keeping.
Definition: Common.h:603
virtual void free_internal() noexcept=0
Abstract member function that must be implemented by child classes to do the actual object destructio...
HMODULE 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:1846
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:1855
_Ty value_type
A type that is managed by the allocator.
Definition: Win.h:1848
heap_allocator(const heap_allocator< _Other > &other)
Constructs allocator from another type.
Definition: Win.h:1883
HANDLE m_heap
Heap handle.
Definition: Win.h:1954
pointer allocate(size_type count)
Allocates a new memory block.
Definition: Win.h:1894
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:1856
heap_allocator(HANDLE heap)
Constructs allocator.
Definition: Win.h:1873
_Ty & reference
A type that provides a reference to the type of object managed by the allocator.
Definition: Win.h:1851
void construct(pointer ptr, _Ty &&val)
Calls moving constructor for the element.
Definition: Win.h:1930
void deallocate(pointer ptr, size_type size)
Frees memory block.
Definition: Win.h:1906
size_type max_size() const
Returns maximum memory block size.
Definition: Win.h:1948
void construct(pointer ptr, const _Ty &val)
Calls copying constructor for the element.
Definition: Win.h:1919
const _Ty & const_reference
A type that provides a constant reference to type of object managed by the allocator.
Definition: Win.h:1853
const _Ty * const_pointer
A type that provides a constant pointer to the type of object managed by the allocator.
Definition: Win.h:1852
_Ty * pointer
A type that provides a pointer to the type of object managed by the allocator.
Definition: Win.h:1850
void destroy(pointer ptr)
Calls destructor for the element.
Definition: Win.h:1940
Heap handle wrapper.
Definition: Win.h:1748
bool enumerate() noexcept
Enumerates allocated heap blocks using OutputDebugString()
Definition: Win.h:1790
__declspec(deprecated("Use HeapCreate")) bool create(DWORD flOptions
Creates the heap.
void free_internal() noexcept override
Destroys the heap.
Definition: Win.h:1834
virtual ~heap()
Destroys the heap.
Definition: Win.h:1757
Module handle wrapper.
Definition: Win.h:1390
void free_internal() noexcept override
Frees the module.
Definition: Win.h:1431
__declspec(deprecated("Use LoadLibraryEx")) bool load(LPCTSTR lpFileName
Loads the specified module into the address space of the calling process.
virtual ~library()
Frees the module.
Definition: Win.h:1399
PROCESS_INFORMATION struct wrapper.
Definition: Win.h:2359
~process_information()
Closes process and thread handles.
Definition: Win.h:2378
process_information() noexcept
Constructs blank PROCESS_INFORMATION.
Definition: Win.h:2367
Process handle wrapper.
Definition: Win.h:1441
__declspec(deprecated("Use OpenProcess")) bool open(DWORD dwDesiredAccess
Opens process handle.
Registry wrapper class.
Definition: Win.h:2189
__declspec(deprecated("Use RegCreateKeyEx - mind it returns error number rather than SetLastError")) bool create(HKEY hKey
Creates the specified registry key. If the key already exists, the function opens it.
virtual ~reg_key()
Closes a handle to the registry key.
Definition: Win.h:2198
SID wrapper class.
Definition: Win.h:2328
void free_internal() noexcept override
Closes a handle to the SID.
Definition: Win.h:2349
virtual ~security_id()
Closes a handle to the SID.
Definition: Win.h:2337
Lets the calling thread impersonate the security context of a logged-on user.
Definition: Win.h:1998
BOOL m_cookie
Did impersonation succeed?
Definition: Win.h:2027
user_impersonator(HANDLE hToken) noexcept
Construct the impersonator and impersonates the given user.
Definition: Win.h:2010
virtual ~user_impersonator()
Reverts to current user and destructs the impersonator.
Definition: Win.h:2020
Memory in virtual address space of a process handle wrapper.
Definition: Win.h:2071
vmemory & operator=(vmemory &&other) noexcept
Move assignment.
Definition: Win.h:2121
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:2155
void free_internal() noexcept override
Frees the memory.
Definition: Win.h:2176
void attach(HANDLE proc, handle_type h) noexcept
Sets a new memory handle for the class.
Definition: Win.h:2138
virtual ~vmemory()
Frees the memory.
Definition: Win.h:2110
vmemory(handle_type h, HANDLE proc) noexcept
Initializes a new class instance with an already available object handle.
Definition: Win.h:2088
vmemory() noexcept
Initializes a new class instance with the memory handle set to INVAL.
Definition: Win.h:2078
vmemory(vmemory &&h) noexcept
Move constructor.
Definition: Win.h:2099
HANDLE m_proc
Handle of memory's process.
Definition: Win.h:2182
Windows HANDLE wrapper class.
Definition: Win.h:1359
void free_internal() noexcept override
Closes an open object handle.
Definition: Win.h:1380
virtual ~win_handle()
Closes an open object handle.
Definition: Win.h:1368
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 > process_snapshot
Process snapshot handle wrapper.
Definition: Win.h:1478
#define WINSTD_WINHANDLE_IMPL(C, INVAL)
Implements default constructors and operators to prevent their auto-generation by compiler.
Definition: Win.h:25
win_handle< NULL > thread
Thread handle wrapper.
Definition: Win.h:1471
UnmapViewOfFile_delete()
Default construct.
Definition: Win.h:1575
void operator()(_Other *) const
Delete a pointer of another type.
Definition: Win.h:1590
void operator()(_Ty *_Ptr) const
Delete a pointer.
Definition: Win.h:1580
UnmapViewOfFile_delete< _Ty > _Myt
This type.
Definition: Win.h:1570
Deleter for unique_ptr using UnmapViewOfFile.
Definition: Win.h:1542
UnmapViewOfFile_delete(const UnmapViewOfFile_delete< _Ty2 > &)
Construct from another UnmapViewOfFile_delete.
Definition: Win.h:1553
void operator()(_Ty *_Ptr) const
Delete a pointer.
Definition: Win.h:1558
UnmapViewOfFile_delete< _Ty > _Myt
This type.
Definition: Win.h:1543
UnmapViewOfFile_delete()
Default construct.
Definition: Win.h:1548
A structure that enables an allocator for objects of one type to allocate storage for objects of anot...
Definition: Win.h:1863
heap_allocator< _Other > other
Other allocator type.
Definition: Win.h:1864