WinStd
Windows Win32 API using Standard C++
Win.h
1/*
2 SPDX-License-Identifier: MIT
3 Copyright © 1991-2022 Amebis
4 Copyright © 2016 GÉANT
5*/
6
8
9#pragma once
10
11#include "Common.h"
12#include <string>
13#include <vector>
14
15#pragma warning(push)
16#pragma warning(disable: 4505) // Don't warn on unused code
17
20
22template<class _Traits, class _Ax>
23static DWORD GetModuleFileNameA(_In_opt_ HMODULE hModule, _Out_ std::basic_string<char, _Traits, _Ax> &sValue) noexcept
24{
25 assert(0); // TODO: Test this code.
26
27 char szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(char)];
28
29 // Try with stack buffer first.
30 DWORD dwResult = ::GetModuleFileNameA(hModule, szStackBuffer, _countof(szStackBuffer));
31 if (dwResult < _countof(szStackBuffer)) {
32 // Copy from stack.
33 sValue.assign(szStackBuffer, dwResult);
34 return dwResult;
35 } else {
36 for (DWORD dwCapacity = 2*WINSTD_STACK_BUFFER_BYTES/sizeof(char);; dwCapacity *= 2) {
37 // Allocate on heap and retry.
38 std::unique_ptr<char[]> szBuffer(new char[dwCapacity]);
39 dwResult = ::GetModuleFileNameA(hModule, szBuffer.get(), dwCapacity);
40 if (dwResult < dwCapacity) {
41 sValue.assign(szBuffer.get(), dwResult);
42 return dwResult;
43 }
44 }
45 }
46}
47
53template<class _Traits, class _Ax>
54static DWORD GetModuleFileNameW(_In_opt_ HMODULE hModule, _Out_ std::basic_string<wchar_t, _Traits, _Ax> &sValue) noexcept
55{
56 wchar_t szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t)];
57
58 // Try with stack buffer first.
59 DWORD dwResult = ::GetModuleFileNameW(hModule, szStackBuffer, _countof(szStackBuffer));
60 if (dwResult < _countof(szStackBuffer)) {
61 // Copy from stack.
62 sValue.assign(szStackBuffer, dwResult);
63 return dwResult;
64 } else {
65 for (DWORD dwCapacity = 2*WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t);; dwCapacity *= 2) {
66 // Allocate on heap and retry.
67 std::unique_ptr<wchar_t[]> szBuffer(new wchar_t[dwCapacity]);
68 dwResult = ::GetModuleFileNameW(hModule, szBuffer.get(), dwCapacity);
69 if (dwResult < dwCapacity) {
70 sValue.assign(szBuffer.get(), dwResult);
71 return dwResult;
72 }
73 }
74 }
75}
76
78template<class _Traits, class _Ax>
79static _Success_(return != 0) int GetWindowTextA(_In_ HWND hWnd, _Out_ std::basic_string<char, _Traits, _Ax> &sValue) noexcept
80{
81 assert(0); // TODO: Test this code.
82
83 int iResult;
84
85 // Query the final string length first.
86 iResult = ::GetWindowTextLengthA(hWnd);
87 if (iResult > 0) {
88 if (++iResult < WINSTD_STACK_BUFFER_BYTES/sizeof(char)) {
89 // Read string data to stack.
90 char szBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(char)];
91 iResult = ::GetWindowTextA(hWnd, szBuffer, _countof(szBuffer));
92 sValue.assign(szBuffer, iResult);
93 } else {
94 // Allocate buffer on heap and read the string data into it.
95 std::unique_ptr<char[]> szBuffer(new char[++iResult]);
96 iResult = ::GetWindowTextA(hWnd, szBuffer.get(), iResult);
97 sValue.assign(szBuffer.get(), iResult);
98 }
99 return iResult;
100 }
101
102 sValue.clear();
103 return 0;
104}
105
111template<class _Traits, class _Ax>
112static _Success_(return != 0) int GetWindowTextW(_In_ HWND hWnd, _Out_ std::basic_string<wchar_t, _Traits, _Ax> &sValue) noexcept
113{
114 assert(0); // TODO: Test this code.
115
116 int iResult;
117
118 // Query the final string length first.
119 iResult = ::GetWindowTextLengthW(hWnd);
120 if (iResult > 0) {
121 if (++iResult < WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t)) {
122 // Read string data to stack.
123 wchar_t szBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t)];
124 iResult = ::GetWindowTextW(hWnd, szBuffer, _countof(szBuffer));
125 sValue.assign(szBuffer, iResult);
126 } else {
127 // Allocate buffer on heap and read the string data into it.
128 std::unique_ptr<wchar_t[]> szBuffer(new wchar_t[++iResult]);
129 iResult = ::GetWindowTextW(hWnd, szBuffer.get(), iResult);
130 sValue.assign(szBuffer.get(), iResult);
131 }
132 return iResult;
133 }
134
135 sValue.clear();
136 return 0;
137}
138
140template<class _Ty, class _Ax>
141static _Success_(return != 0) BOOL GetFileVersionInfoA(_In_z_ LPCSTR lptstrFilename, __reserved DWORD dwHandle, _Out_ std::vector<_Ty, _Ax> &aValue) noexcept
142{
143 assert(0); // TODO: Test this code.
144
145 // Get version info size.
146 DWORD dwVerInfoSize = ::GetFileVersionInfoSizeA(lptstrFilename, &dwHandle);
147 if (dwVerInfoSize != 0) {
148 // Read version info.
149 aValue.resize((dwVerInfoSize + sizeof(_Ty) - 1) / sizeof(_Ty));
150 return ::GetFileVersionInfoA(lptstrFilename, dwHandle, dwVerInfoSize, aValue.data());
151 } else
152 return FALSE;
153}
154
160template<class _Ty, class _Ax>
161static _Success_(return != 0) BOOL GetFileVersionInfoW(_In_z_ LPCWSTR lptstrFilename, __reserved DWORD dwHandle, _Out_ std::vector<_Ty, _Ax> &aValue) noexcept
162{
163 assert(0); // TODO: Test this code.
164
165 // Get version info size.
166 DWORD dwVerInfoSize = ::GetFileVersionInfoSizeW(lptstrFilename, &dwHandle);
167 if (dwVerInfoSize != 0) {
168 // Read version info.
169 aValue.resize((dwVerInfoSize + sizeof(_Ty) - 1) / sizeof(_Ty));
170 return ::GetFileVersionInfoW(lptstrFilename, dwHandle, dwVerInfoSize, aValue.data());
171 } else
172 return FALSE;
173}
174
176template<class _Traits, class _Ax>
177static _Success_(return != 0) DWORD ExpandEnvironmentStringsA(_In_z_ LPCSTR lpSrc, _Out_ std::basic_string<char, _Traits, _Ax> &sValue) noexcept
178{
179 assert(0); // TODO: Test this code.
180
181 for (DWORD dwSizeOut = (DWORD)strlen(lpSrc) + 0x100;;) {
182 DWORD dwSizeIn = dwSizeOut;
183 std::unique_ptr<char[]> szBuffer(new char[(size_t)dwSizeIn + 2]); // Note: ANSI version requires one extra char.
184 dwSizeOut = ::ExpandEnvironmentStringsA(lpSrc, szBuffer.get(), dwSizeIn);
185 if (dwSizeOut == 0) {
186 // Error or zero-length input.
187 break;
188 } else if (dwSizeOut <= dwSizeIn) {
189 // The buffer was sufficient.
190 sValue.assign(szBuffer.get(), dwSizeOut - 1);
191 return dwSizeOut;
192 }
193 }
194
195 sValue.clear();
196 return 0;
197}
198
204template<class _Traits, class _Ax>
205static _Success_(return != 0) DWORD ExpandEnvironmentStringsW(_In_z_ LPCWSTR lpSrc, _Out_ std::basic_string<wchar_t, _Traits, _Ax> &sValue) noexcept
206{
207 for (DWORD dwSizeOut = (DWORD)wcslen(lpSrc) + 0x100;;) {
208 DWORD dwSizeIn = dwSizeOut;
209 std::unique_ptr<wchar_t[]> szBuffer(new wchar_t[(size_t)dwSizeIn + 1]);
210 dwSizeOut = ::ExpandEnvironmentStringsW(lpSrc, szBuffer.get(), dwSizeIn);
211 if (dwSizeOut == 0) {
212 // Error or zero-length input.
213 break;
214 } else if (dwSizeOut <= dwSizeIn) {
215 // The buffer was sufficient.
216 sValue.assign(szBuffer.get(), dwSizeOut - 1);
217 return dwSizeOut;
218 }
219 }
220
221 sValue.clear();
222 return 0;
223}
224
226template<class _Traits, class _Ax>
227static VOID GuidToStringA(_In_ LPCGUID lpGuid, _Out_ std::basic_string<char, _Traits, _Ax> &str) noexcept
228{
229 assert(0); // TODO: Test this code.
230
231 sprintf(str, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
232 lpGuid->Data1,
233 lpGuid->Data2,
234 lpGuid->Data3,
235 lpGuid->Data4[0], lpGuid->Data4[1],
236 lpGuid->Data4[2], lpGuid->Data4[3], lpGuid->Data4[4], lpGuid->Data4[5], lpGuid->Data4[6], lpGuid->Data4[7]);
237}
238
245template<class _Traits, class _Ax>
246static VOID GuidToStringW(_In_ LPCGUID lpGuid, _Out_ std::basic_string<wchar_t, _Traits, _Ax> &str) noexcept
247{
248 assert(0); // TODO: Test this code.
249
250 sprintf(str, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
251 lpGuid->Data1,
252 lpGuid->Data2,
253 lpGuid->Data3,
254 lpGuid->Data4[0], lpGuid->Data4[1],
255 lpGuid->Data4[2], lpGuid->Data4[3], lpGuid->Data4[4], lpGuid->Data4[5], lpGuid->Data4[6], lpGuid->Data4[7]);
256}
257
259#ifdef _UNICODE
260#define GuidToString GuidToStringW
261#else
262#define GuidToString GuidToStringA
263#endif
264
266static _Success_(return) BOOL StringToGuidA(_In_z_ LPCSTR lpszGuid, _Out_ LPGUID lpGuid, _Out_opt_ LPCSTR *lpszGuidEnd = NULL) noexcept
267{
268 GUID g;
269 LPSTR lpszEnd;
270 unsigned long ulTmp;
271 unsigned long long ullTmp;
272
273 if (!lpszGuid || !lpGuid || *lpszGuid != '{') return FALSE;
274 lpszGuid++;
275
276 g.Data1 = strtoul(lpszGuid, &lpszEnd, 16);
277 if (errno == ERANGE) return FALSE;
278 lpszGuid = lpszEnd;
279
280 if (*lpszGuid != '-') return FALSE;
281 lpszGuid++;
282
283 ulTmp = strtoul(lpszGuid, &lpszEnd, 16);
284 if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE;
285 g.Data2 = static_cast<unsigned short>(ulTmp);
286 lpszGuid = lpszEnd;
287
288 if (*lpszGuid != '-') return FALSE;
289 lpszGuid++;
290
291 ulTmp = strtoul(lpszGuid, &lpszEnd, 16);
292 if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE;
293 g.Data3 = static_cast<unsigned short>(ulTmp);
294 lpszGuid = lpszEnd;
295
296 if (*lpszGuid != '-') return FALSE;
297 lpszGuid++;
298
299 ulTmp = strtoul(lpszGuid, &lpszEnd, 16);
300 if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE;
301 g.Data4[0] = static_cast<unsigned char>((ulTmp >> 8) & 0xff);
302 g.Data4[1] = static_cast<unsigned char>( ulTmp & 0xff);
303 lpszGuid = lpszEnd;
304
305 if (*lpszGuid != '-') return FALSE;
306 lpszGuid++;
307
308 ullTmp = _strtoui64(lpszGuid, &lpszEnd, 16);
309 if (errno == ERANGE || ullTmp > 0xFFFFFFFFFFFF) return FALSE;
310 g.Data4[2] = static_cast<unsigned char>((ullTmp >> 40) & 0xff);
311 g.Data4[3] = static_cast<unsigned char>((ullTmp >> 32) & 0xff);
312 g.Data4[4] = static_cast<unsigned char>((ullTmp >> 24) & 0xff);
313 g.Data4[5] = static_cast<unsigned char>((ullTmp >> 16) & 0xff);
314 g.Data4[6] = static_cast<unsigned char>((ullTmp >> 8) & 0xff);
315 g.Data4[7] = static_cast<unsigned char>( ullTmp & 0xff);
316 lpszGuid = lpszEnd;
317
318 if (*lpszGuid != '}') return FALSE;
319 lpszGuid++;
320
321 if (lpszGuidEnd)
322 *lpszGuidEnd = lpszGuid;
323
324 *lpGuid = g;
325 return TRUE;
326}
327
339static _Success_(return) BOOL StringToGuidW(_In_z_ LPCWSTR lpszGuid, _Out_ LPGUID lpGuid, _Out_opt_ LPCWSTR *lpszGuidEnd = NULL) noexcept
340{
341 GUID g;
342 LPWSTR lpszEnd;
343 unsigned long ulTmp;
344 unsigned long long ullTmp;
345
346 if (!lpszGuid || !lpGuid || *lpszGuid != '{') return FALSE;
347 lpszGuid++;
348
349 g.Data1 = wcstoul(lpszGuid, &lpszEnd, 16);
350 if (errno == ERANGE) return FALSE;
351 lpszGuid = lpszEnd;
352
353 if (*lpszGuid != '-') return FALSE;
354 lpszGuid++;
355
356 ulTmp = wcstoul(lpszGuid, &lpszEnd, 16);
357 if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE;
358 g.Data2 = static_cast<unsigned short>(ulTmp);
359 lpszGuid = lpszEnd;
360
361 if (*lpszGuid != '-') return FALSE;
362 lpszGuid++;
363
364 ulTmp = wcstoul(lpszGuid, &lpszEnd, 16);
365 if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE;
366 g.Data3 = static_cast<unsigned short>(ulTmp);
367 lpszGuid = lpszEnd;
368
369 if (*lpszGuid != '-') return FALSE;
370 lpszGuid++;
371
372 ulTmp = wcstoul(lpszGuid, &lpszEnd, 16);
373 if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE;
374 g.Data4[0] = static_cast<unsigned char>((ulTmp >> 8) & 0xff);
375 g.Data4[1] = static_cast<unsigned char>( ulTmp & 0xff);
376 lpszGuid = lpszEnd;
377
378 if (*lpszGuid != '-') return FALSE;
379 lpszGuid++;
380
381 ullTmp = _wcstoui64(lpszGuid, &lpszEnd, 16);
382 if (errno == ERANGE || ullTmp > 0xFFFFFFFFFFFF) return FALSE;
383 g.Data4[2] = static_cast<unsigned char>((ullTmp >> 40) & 0xff);
384 g.Data4[3] = static_cast<unsigned char>((ullTmp >> 32) & 0xff);
385 g.Data4[4] = static_cast<unsigned char>((ullTmp >> 24) & 0xff);
386 g.Data4[5] = static_cast<unsigned char>((ullTmp >> 16) & 0xff);
387 g.Data4[6] = static_cast<unsigned char>((ullTmp >> 8) & 0xff);
388 g.Data4[7] = static_cast<unsigned char>( ullTmp & 0xff);
389 lpszGuid = lpszEnd;
390
391 if (*lpszGuid != '}') return FALSE;
392 lpszGuid++;
393
394 if (lpszGuidEnd)
395 *lpszGuidEnd = lpszGuid;
396
397 *lpGuid = g;
398 return TRUE;
399}
400
402#ifdef _UNICODE
403#define StringToGuid StringToGuidW
404#else
405#define StringToGuid StringToGuidA
406#endif
407
426template<class _Traits, class _Ax>
427static LSTATUS RegQueryStringValue(_In_ HKEY hReg, _In_z_ LPCSTR pszName, _Out_ std::basic_string<char, _Traits, _Ax> &sValue) noexcept
428{
429 LSTATUS lResult;
430 BYTE aStackBuffer[WINSTD_STACK_BUFFER_BYTES];
431 DWORD dwSize = sizeof(aStackBuffer), dwType;
432
433 // Try with stack buffer first.
434 lResult = ::RegQueryValueExA(hReg, pszName, NULL, &dwType, aStackBuffer, &dwSize);
435 if (lResult == ERROR_SUCCESS) {
436 if (dwType == REG_SZ || dwType == REG_MULTI_SZ) {
437 // The value is REG_SZ or REG_MULTI_SZ.
438 dwSize /= sizeof(CHAR);
439 sValue.assign(reinterpret_cast<LPCSTR>(aStackBuffer), dwSize && reinterpret_cast<LPCSTR>(aStackBuffer)[dwSize - 1] == 0 ? dwSize - 1 : dwSize);
440 } else if (dwType == REG_EXPAND_SZ) {
441 // The value is REG_EXPAND_SZ. Expand it from stack buffer.
442 if (::ExpandEnvironmentStringsA(reinterpret_cast<LPCSTR>(aStackBuffer), sValue) == 0)
443 lResult = ::GetLastError();
444 } else {
445 // The value is not a string type.
446 lResult = ERROR_INVALID_DATA;
447 }
448 } else if (lResult == ERROR_MORE_DATA) {
449 if (dwType == REG_SZ || dwType == REG_MULTI_SZ) {
450 // The value is REG_SZ or REG_MULTI_SZ. Read it now.
451 std::unique_ptr<CHAR[]> szBuffer(new CHAR[dwSize / sizeof(CHAR)]);
452 if ((lResult = ::RegQueryValueExA(hReg, pszName, NULL, NULL, reinterpret_cast<LPBYTE>(szBuffer.get()), &dwSize)) == ERROR_SUCCESS) {
453 dwSize /= sizeof(CHAR);
454 sValue.assign(szBuffer.get(), dwSize && szBuffer[dwSize - 1] == 0 ? dwSize - 1 : dwSize);
455 }
456 } else if (dwType == REG_EXPAND_SZ) {
457 // The value is REG_EXPAND_SZ. Read it and expand environment variables.
458 std::unique_ptr<CHAR[]> szBuffer(new CHAR[dwSize / sizeof(CHAR)]);
459 if ((lResult = ::RegQueryValueExA(hReg, pszName, NULL, NULL, reinterpret_cast<LPBYTE>(szBuffer.get()), &dwSize)) == ERROR_SUCCESS) {
460 if (::ExpandEnvironmentStringsA(szBuffer.get(), sValue) == 0)
461 lResult = ::GetLastError();
462 }
463 } else {
464 // The value is not a string type.
465 lResult = ERROR_INVALID_DATA;
466 }
467 }
468
469 return lResult;
470}
471
490template<class _Traits, class _Ax>
491static LSTATUS RegQueryStringValue(_In_ HKEY hReg, _In_z_ LPCWSTR pszName, _Out_ std::basic_string<wchar_t, _Traits, _Ax> &sValue) noexcept
492{
493 LSTATUS lResult;
494 BYTE aStackBuffer[WINSTD_STACK_BUFFER_BYTES];
495 DWORD dwSize = sizeof(aStackBuffer), dwType;
496
497 // Try with stack buffer first.
498 lResult = ::RegQueryValueExW(hReg, pszName, NULL, &dwType, aStackBuffer, &dwSize);
499 if (lResult == ERROR_SUCCESS) {
500 if (dwType == REG_SZ || dwType == REG_MULTI_SZ) {
501 // The value is REG_SZ or REG_MULTI_SZ.
502 dwSize /= sizeof(WCHAR);
503 sValue.assign(reinterpret_cast<LPCWSTR>(aStackBuffer), dwSize && reinterpret_cast<LPCWSTR>(aStackBuffer)[dwSize - 1] == 0 ? dwSize - 1 : dwSize);
504 } else if (dwType == REG_EXPAND_SZ) {
505 // The value is REG_EXPAND_SZ. Expand it from stack buffer.
506 if (::ExpandEnvironmentStringsW(reinterpret_cast<LPCWSTR>(aStackBuffer), sValue) == 0)
507 lResult = ::GetLastError();
508 } else {
509 // The value is not a string type.
510 lResult = ERROR_INVALID_DATA;
511 }
512 } else if (lResult == ERROR_MORE_DATA) {
513 if (dwType == REG_SZ || dwType == REG_MULTI_SZ) {
514 // The value is REG_SZ or REG_MULTI_SZ. Read it now.
515 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[dwSize / sizeof(WCHAR)]);
516 if ((lResult = ::RegQueryValueExW(hReg, pszName, NULL, NULL, reinterpret_cast<LPBYTE>(szBuffer.get()), &dwSize)) == ERROR_SUCCESS) {
517 dwSize /= sizeof(WCHAR);
518 sValue.assign(szBuffer.get(), dwSize && szBuffer[dwSize - 1] == 0 ? dwSize - 1 : dwSize);
519 }
520 } else if (dwType == REG_EXPAND_SZ) {
521 // The value is REG_EXPAND_SZ. Read it and expand environment variables.
522 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[dwSize / sizeof(WCHAR)]);
523 if ((lResult = ::RegQueryValueExW(hReg, pszName, NULL, NULL, reinterpret_cast<LPBYTE>(szBuffer.get()), &dwSize)) == ERROR_SUCCESS) {
524 if (::ExpandEnvironmentStringsW(szBuffer.get(), sValue) == 0)
525 lResult = ::GetLastError();
526 }
527 } else {
528 // The value is not a string type.
529 lResult = ERROR_INVALID_DATA;
530 }
531 }
532
533 return lResult;
534}
535
537template<class _Ty, class _Ax>
538static LSTATUS RegQueryValueExA(_In_ HKEY hKey, _In_opt_z_ LPCSTR lpValueName, __reserved LPDWORD lpReserved, _Out_opt_ LPDWORD lpType, _Out_ std::vector<_Ty, _Ax> &aData) noexcept
539{
540 LSTATUS lResult;
541 BYTE aStackBuffer[WINSTD_STACK_BUFFER_BYTES];
542 DWORD dwSize = sizeof(aStackBuffer);
543
544 // Try with stack buffer first.
545 lResult = RegQueryValueExA(hKey, lpValueName, lpReserved, lpType, aStackBuffer, &dwSize);
546 if (lResult == ERROR_SUCCESS) {
547 // Copy from stack buffer.
548 aData.resize((dwSize + sizeof(_Ty) - 1) / sizeof(_Ty));
549 memcpy(aData.data(), aStackBuffer, dwSize);
550 } else if (lResult == ERROR_MORE_DATA) {
551 // Allocate buffer on heap and retry.
552 aData.resize((dwSize + sizeof(_Ty) - 1) / sizeof(_Ty));
553 lResult = RegQueryValueExA(hKey, lpValueName, lpReserved, NULL, aData.data(), &dwSize);
554 }
555
556 return lResult;
557}
558
564template<class _Ty, class _Ax>
565static LSTATUS RegQueryValueExW(_In_ HKEY hKey, _In_opt_z_ LPCWSTR lpValueName, __reserved LPDWORD lpReserved, _Out_opt_ LPDWORD lpType, _Out_ std::vector<_Ty, _Ax> &aData) noexcept
566{
567 LSTATUS lResult;
568 BYTE aStackBuffer[WINSTD_STACK_BUFFER_BYTES];
569 DWORD dwSize = sizeof(aStackBuffer);
570
571 // Try with stack buffer first.
572 lResult = RegQueryValueExW(hKey, lpValueName, lpReserved, lpType, aStackBuffer, &dwSize);
573 if (lResult == ERROR_SUCCESS) {
574 // Copy from stack buffer.
575 aData.resize((dwSize + sizeof(_Ty) - 1) / sizeof(_Ty));
576 memcpy(aData.data(), aStackBuffer, dwSize);
577 } else if (lResult == ERROR_MORE_DATA) {
578 // Allocate buffer on heap and retry.
579 aData.resize((dwSize + sizeof(_Ty) - 1) / sizeof(_Ty));
580 lResult = RegQueryValueExW(hKey, lpValueName, lpReserved, NULL, aData.data(), &dwSize);
581 }
582
583 return lResult;
584}
585
586#if _WIN32_WINNT >= _WIN32_WINNT_VISTA
587
589template<class _Traits, class _Ax>
590static 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
591{
592 // According to "Remarks" section in MSDN documentation of RegLoadMUIString(),
593 // this function is defined but not implemented as ANSI variation.
594 assert(0);
595 return ERROR_CALL_NOT_IMPLEMENTED;
596}
597
603template<class _Traits, class _Ax>
604static 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
605{
606 LSTATUS lResult;
607 wchar_t szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t)];
608 DWORD dwSize;
609
610 Flags &= ~REG_MUI_STRING_TRUNCATE;
611
612 // Try with stack buffer first.
613 lResult = RegLoadMUIStringW(hKey, pszValue, szStackBuffer, sizeof(szStackBuffer), &dwSize, Flags, pszDirectory);
614 if (lResult == ERROR_SUCCESS) {
615 // Copy from stack buffer.
616 sOut.assign(szStackBuffer, wcsnlen(szStackBuffer, dwSize/sizeof(wchar_t)));
617 } else if (lResult == ERROR_MORE_DATA) {
618 // Allocate buffer on heap and retry.
619 std::unique_ptr<wchar_t[]> szBuffer(new wchar_t[(dwSize + sizeof(wchar_t) - 1)/sizeof(wchar_t)]);
620 sOut.assign(szBuffer.get(), (lResult = RegLoadMUIStringW(hKey, pszValue, szBuffer.get(), dwSize, &dwSize, Flags, pszDirectory)) == ERROR_SUCCESS ? wcsnlen(szBuffer.get(), dwSize/sizeof(wchar_t)) : 0);
621 }
622
623 return lResult;
624}
625
626#endif
627
633template<class _Traits, class _Ax>
634static _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
635{
636 CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)];
637
638 // Try to convert to stack buffer first.
639 int cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar);
640 if (cch) {
641 // Copy from stack. Be careful not to include zero terminator.
642 sMultiByteStr.assign(szStackBuffer, cchWideChar != -1 ? strnlen(szStackBuffer, cch) : (size_t)cch - 1);
643 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
644 // Query the required output size. Allocate buffer. Then convert again.
645 cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, NULL, 0, lpDefaultChar, lpUsedDefaultChar);
646 std::unique_ptr<CHAR[]> szBuffer(new CHAR[cch]);
647 cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szBuffer.get(), cch, lpDefaultChar, lpUsedDefaultChar);
648 sMultiByteStr.assign(szBuffer.get(), cchWideChar != -1 ? strnlen(szBuffer.get(), cch) : (size_t)cch - 1);
649 }
650
651 return cch;
652}
653
659template<class _Ax>
660static _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
661{
662 CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)];
663
664 // Try to convert to stack buffer first.
665 int cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar);
666 if (cch) {
667 // Copy from stack.
668 sMultiByteStr.assign(szStackBuffer, szStackBuffer + cch);
669 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
670 // Query the required output size. Allocate buffer. Then convert again.
671 cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, NULL, 0, lpDefaultChar, lpUsedDefaultChar);
672 sMultiByteStr.resize(cch);
673 cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, sMultiByteStr.data(), cch, lpDefaultChar, lpUsedDefaultChar);
674 }
675
676 return cch;
677}
678
684template<class _Traits1, class _Ax1, class _Traits2, class _Ax2>
685static _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
686{
687 CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)];
688
689 // Try to convert to stack buffer first.
690 int cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar);
691 if (cch) {
692 // Copy from stack.
693 sMultiByteStr.assign(szStackBuffer, cch);
694 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
695 // Query the required output size. Allocate buffer. Then convert again.
696 cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), NULL, 0, lpDefaultChar, lpUsedDefaultChar);
697 std::unique_ptr<CHAR[]> szBuffer(new CHAR[cch]);
698 cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), szBuffer.get(), cch, lpDefaultChar, lpUsedDefaultChar);
699 sMultiByteStr.assign(szBuffer.get(), cch);
700 }
701
702 return cch;
703}
704
712template<class _Traits, class _Ax>
713static _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
714{
715 CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)];
716
717 // Try to convert to stack buffer first.
718 int cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar);
719 if (cch) {
720 // Copy from stack. Be careful not to include zero terminator.
721 sMultiByteStr.assign(szStackBuffer, cchWideChar != -1 ? strnlen(szStackBuffer, cch) : (size_t)cch - 1);
722 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
723 // Query the required output size. Allocate buffer. Then convert again.
724 cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, NULL, 0, lpDefaultChar, lpUsedDefaultChar);
725 std::unique_ptr<CHAR[]> szBuffer(new CHAR[cch]);
726 cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szBuffer.get(), cch, lpDefaultChar, lpUsedDefaultChar);
727 sMultiByteStr.assign(szBuffer.get(), cchWideChar != -1 ? strnlen(szBuffer.get(), cch) : (size_t)cch - 1);
728 SecureZeroMemory(szBuffer.get(), sizeof(CHAR)*cch);
729 }
730
731 SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer));
732
733 return cch;
734}
735
743template<class _Ax>
744static _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
745{
746 CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)];
747
748 // Try to convert to stack buffer first.
749 int cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar);
750 if (cch) {
751 // Copy from stack.
752 sMultiByteStr.assign(szStackBuffer, szStackBuffer + cch);
753 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
754 // Query the required output size. Allocate buffer. Then convert again.
755 cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, NULL, 0, lpDefaultChar, lpUsedDefaultChar);
756 sMultiByteStr.resize(cch);
757 cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, sMultiByteStr.data(), cch, lpDefaultChar, lpUsedDefaultChar);
758 }
759
760 SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer));
761
762 return cch;
763}
764
772template<class _Traits1, class _Ax1, class _Traits2, class _Ax2>
773static _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
774{
775 CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)];
776
777 // Try to convert to stack buffer first.
778 int cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar);
779 if (cch) {
780 // Copy from stack.
781 sMultiByteStr.assign(szStackBuffer, cch);
782 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
783 // Query the required output size. Allocate buffer. Then convert again.
784 cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), NULL, 0, lpDefaultChar, lpUsedDefaultChar);
785 std::unique_ptr<CHAR[]> szBuffer(new CHAR[cch]);
786 cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), szBuffer.get(), cch, lpDefaultChar, lpUsedDefaultChar);
787 sMultiByteStr.assign(szBuffer.get(), cch);
788 SecureZeroMemory(szBuffer.get(), sizeof(CHAR)*cch);
789 }
790
791 SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer));
792
793 return cch;
794}
795
801template<class _Traits, class _Ax>
802static _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
803{
804 WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)];
805
806 // Try to convert to stack buffer first.
807 int cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szStackBuffer, _countof(szStackBuffer));
808 if (cch) {
809 // Copy from stack.
810 sWideCharStr.assign(szStackBuffer, cbMultiByte != -1 ? wcsnlen(szStackBuffer, cch) : (size_t)cch - 1);
811 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
812 // Query the required output size. Allocate buffer. Then convert again.
813 cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, NULL, 0);
814 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[cch]);
815 cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szBuffer.get(), cch);
816 sWideCharStr.assign(szBuffer.get(), cbMultiByte != -1 ? wcsnlen(szBuffer.get(), cch) : (size_t)cch - 1);
817 }
818
819 return cch;
820}
821
827template<class _Ax>
828static _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
829{
830 WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)];
831
832 // Try to convert to stack buffer first.
833 int cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szStackBuffer, _countof(szStackBuffer));
834 if (cch) {
835 // Copy from stack.
836 sWideCharStr.assign(szStackBuffer, szStackBuffer + cch);
837 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
838 // Query the required output size. Allocate buffer. Then convert again.
839 cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, NULL, 0);
840 sWideCharStr.resize(cch);
841 cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, sWideCharStr.data(), cch);
842 }
843
844 return cch;
845}
846
852template<class _Traits1, class _Ax1, class _Traits2, class _Ax2>
853static _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
854{
855 WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)];
856
857 // Try to convert to stack buffer first.
858 int cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), szStackBuffer, _countof(szStackBuffer));
859 if (cch) {
860 // Copy from stack.
861 sWideCharStr.assign(szStackBuffer, cch);
862 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
863 // Query the required output size. Allocate buffer. Then convert again.
864 cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), NULL, 0);
865 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[cch]);
866 cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), szBuffer.get(), cch);
867 sWideCharStr.assign(szBuffer.get(), cch);
868 }
869
870 return cch;
871}
872
880template<class _Traits, class _Ax>
881static _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
882{
883 WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)];
884
885 // Try to convert to stack buffer first.
886 int cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szStackBuffer, _countof(szStackBuffer));
887 if (cch) {
888 // Copy from stack.
889 sWideCharStr.assign(szStackBuffer, cbMultiByte != -1 ? wcsnlen(szStackBuffer, cch) : (size_t)cch - 1);
890 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
891 // Query the required output size. Allocate buffer. Then convert again.
892 cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, NULL, 0);
893 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[cch]);
894 cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szBuffer.get(), cch);
895 sWideCharStr.assign(szBuffer.get(), cbMultiByte != -1 ? wcsnlen(szBuffer.get(), cch) : (size_t)cch - 1);
896 SecureZeroMemory(szBuffer.get(), sizeof(WCHAR)*cch);
897 }
898
899 SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer));
900
901 return cch;
902}
903
911template<class _Ax>
912static _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
913{
914 WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)];
915
916 // Try to convert to stack buffer first.
917 int cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szStackBuffer, _countof(szStackBuffer));
918 if (cch) {
919 // Copy from stack.
920 sWideCharStr.assign(szStackBuffer, szStackBuffer + cch);
921 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
922 // Query the required output size. Allocate buffer. Then convert again.
923 cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, NULL, 0);
924 sWideCharStr.resize(cch);
925 cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, sWideCharStr.data(), cch);
926 }
927
928 SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer));
929
930 return cch;
931}
932
940template<class _Traits1, class _Ax1, class _Traits2, class _Ax2>
941static _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
942{
943 WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)];
944
945 // Try to convert to stack buffer first.
946 int cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), szStackBuffer, _countof(szStackBuffer));
947 if (cch) {
948 // Copy from stack.
949 sWideCharStr.assign(szStackBuffer, cch);
950 } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
951 // Query the required output size. Allocate buffer. Then convert again.
952 cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), NULL, 0);
953 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[cch]);
954 cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), szBuffer.get(), cch);
955 sWideCharStr.assign(szBuffer.get(), cch);
956 SecureZeroMemory(szBuffer.get(), sizeof(WCHAR)*cch);
957 }
958
959 SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer));
960
961 return cch;
962}
963
969template<class _Traits, class _Ax>
970static _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
971{
972 WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)];
973
974 // Try to convert to stack buffer first.
975 int cch = ::NormalizeString(NormForm, lpSrcString, cwSrcLength, szStackBuffer, _countof(szStackBuffer));
976 if (cch > 0) {
977 // Copy from stack.
978 sDstString.assign(szStackBuffer, cwSrcLength != -1 ? wcsnlen(szStackBuffer, cch) : (size_t)cch - 1);
979 } else {
980 switch (::GetLastError()) {
981 case ERROR_INSUFFICIENT_BUFFER:
982 for (int i = 10; i--;) {
983 // Allocate buffer. Then convert again.
984 cch = -cch;
985 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[cch]);
986 cch = ::NormalizeString(NormForm, lpSrcString, cwSrcLength, szBuffer.get(), cch);
987 if (cch > 0) {
988 sDstString.assign(szBuffer.get(), cwSrcLength != -1 ? wcsnlen(szStackBuffer, cch) : (size_t)cch - 1);
989 break;
990 }
991 if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
992 sDstString.clear();
993 break;
994 }
995 }
996 break;
997
998 case ERROR_SUCCESS:
999 sDstString.clear();
1000 break;
1001 }
1002 }
1003
1004 return cch;
1005}
1006
1012template<class _Traits1, class _Ax1, class _Traits2, class _Ax2>
1013static _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
1014{
1015 WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)];
1016
1017 // Try to convert to stack buffer first.
1018 int cch = ::NormalizeString(NormForm, sSrcString.c_str(), (int)sSrcString.length(), szStackBuffer, _countof(szStackBuffer));
1019 if (cch > 0) {
1020 // Copy from stack.
1021 sDstString.assign(szStackBuffer, cch);
1022 } else {
1023 switch (::GetLastError()) {
1024 case ERROR_INSUFFICIENT_BUFFER:
1025 for (int i = 10; i--;) {
1026 // Allocate buffer. Then convert again.
1027 cch = -cch;
1028 std::unique_ptr<WCHAR[]> szBuffer(new WCHAR[cch]);
1029 cch = ::NormalizeString(NormForm, sSrcString.c_str(), (int)sSrcString.length(), szBuffer.get(), cch);
1030 if (cch > 0) {
1031 sDstString.assign(szBuffer.get(), cch);
1032 break;
1033 }
1034 if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1035 sDstString.clear();
1036 break;
1037 }
1038 }
1039 break;
1040
1041 case ERROR_SUCCESS:
1042 sDstString.clear();
1043 break;
1044 }
1045 }
1046
1047 return cch;
1048}
1049
1051template<class _Traits, class _Ax>
1052static _Success_(return != 0) int WINAPI LoadStringA(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_ std::basic_string<char, _Traits, _Ax> &sBuffer) noexcept
1053{
1054 // Get read-only pointer to string resource.
1055 LPCSTR pszStr;
1056 int i = LoadStringA(hInstance, uID, reinterpret_cast<LPSTR>(&pszStr), 0);
1057 if (i) {
1058 sBuffer.assign(pszStr, i);
1059 return i;
1060 } else
1061 return 0;
1062}
1063
1069template<class _Traits, class _Ax>
1070static _Success_(return != 0) int WINAPI LoadStringW(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_ std::basic_string<wchar_t, _Traits, _Ax> &sBuffer) noexcept
1071{
1072 // Get read-only pointer to string resource.
1073 LPCWSTR pszStr;
1074 int i = LoadStringW(hInstance, uID, reinterpret_cast<LPWSTR>(&pszStr), 0);
1075 if (i) {
1076 sBuffer.assign(pszStr, i);
1077 return i;
1078 } else
1079 return 0;
1080}
1081
1087static VOID OutputDebugStrV(_In_z_ LPCSTR lpOutputString, _In_ va_list arg) noexcept
1088{
1089 std::string str;
1090 try { vsprintf(str, lpOutputString, arg); } catch (...) { return; }
1091 OutputDebugStringA(str.c_str());
1092}
1093
1099static VOID OutputDebugStrV(_In_z_ LPCWSTR lpOutputString, _In_ va_list arg) noexcept
1100{
1101 std::wstring str;
1102 try { vsprintf(str, lpOutputString, arg); } catch (...) { return; }
1103 OutputDebugStringW(str.c_str());
1104}
1105
1111static VOID OutputDebugStr(_In_z_ LPCSTR lpOutputString, ...) noexcept
1112{
1113 va_list arg;
1114 va_start(arg, lpOutputString);
1115 OutputDebugStrV(lpOutputString, arg);
1116 va_end(arg);
1117}
1118
1124static VOID OutputDebugStr(_In_z_ LPCWSTR lpOutputString, ...) noexcept
1125{
1126 va_list arg;
1127 va_start(arg, lpOutputString);
1128 OutputDebugStrV(lpOutputString, arg);
1129 va_end(arg);
1130}
1131
1133template<class _Traits, class _Ax>
1134static _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
1135{
1136 int iResult = GetDateFormatA(Locale, dwFlags, lpDate, lpFormat, NULL, 0);
1137 if (iResult) {
1138 // Allocate buffer on heap and retry.
1139 std::unique_ptr<char[]> szBuffer(new char[iResult]);
1140 iResult = GetDateFormatA(Locale, dwFlags, lpDate, lpFormat, szBuffer.get(), iResult);
1141 sDate.assign(szBuffer.get(), iResult ? iResult - 1 : 0);
1142 return iResult;
1143 }
1144
1145 return iResult;
1146}
1147
1153template<class _Traits, class _Ax>
1154static _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
1155{
1156 int iResult = GetDateFormatW(Locale, dwFlags, lpDate, lpFormat, NULL, 0);
1157 if (iResult) {
1158 // Allocate buffer on heap and retry.
1159 std::unique_ptr<wchar_t[]> szBuffer(new wchar_t[iResult]);
1160 iResult = GetDateFormatW(Locale, dwFlags, lpDate, lpFormat, szBuffer.get(), iResult);
1161 sDate.assign(szBuffer.get(), iResult ? iResult - 1 : 0);
1162 return iResult;
1163 }
1164
1165 return iResult;
1166}
1167
1169template<class _Traits, class _Ax>
1170static _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
1171{
1172 assert(0); // TODO: Test this code.
1173
1174 DWORD dwNameLen = 0, dwRefDomainLen = 0;
1175
1176 if (LookupAccountSidA(lpSystemName, lpSid,
1177 NULL, &dwNameLen ,
1178 NULL, &dwRefDomainLen,
1179 peUse))
1180 {
1181 // Name and domain is blank.
1182 if (sName ) sName ->clear();
1183 if (sReferencedDomainName) sReferencedDomainName->clear();
1184 return TRUE;
1185 } else if (GetLastError() == ERROR_MORE_DATA) {
1186 // Allocate on heap and retry.
1187 std::unique_ptr<char[]> bufName (new char[dwNameLen ]);
1188 std::unique_ptr<char[]> bufRefDomain(new char[dwRefDomainLen]);
1189 if (LookupAccountSidA(lpSystemName, lpSid,
1190 bufName .get(), &dwNameLen ,
1191 bufRefDomain.get(), &dwRefDomainLen,
1192 peUse))
1193 {
1194 if (sName ) sName ->assign(bufName .get(), dwNameLen - 1);
1195 if (sReferencedDomainName) sReferencedDomainName->assign(bufRefDomain.get(), dwRefDomainLen - 1);
1196 return TRUE;
1197 }
1198 }
1199
1200 return FALSE;
1201}
1202
1208template<class _Traits, class _Ax>
1209static _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
1210{
1211 assert(0); // TODO: Test this code.
1212
1213 DWORD dwNameLen = 0, dwRefDomainLen = 0;
1214
1215 if (LookupAccountSidW(lpSystemName, lpSid,
1216 NULL, &dwNameLen ,
1217 NULL, &dwRefDomainLen,
1218 peUse))
1219 {
1220 // Name and domain is blank.
1221 if (sName ) sName ->clear();
1222 if (sReferencedDomainName) sReferencedDomainName->clear();
1223 return TRUE;
1224 } else if (GetLastError() == ERROR_MORE_DATA) {
1225 // Allocate on heap and retry.
1226 std::unique_ptr<wchar_t[]> bufName (new wchar_t[dwNameLen ]);
1227 std::unique_ptr<wchar_t[]> bufRefDomain(new wchar_t[dwRefDomainLen]);
1228 if (LookupAccountSidW(lpSystemName, lpSid,
1229 bufName .get(), &dwNameLen ,
1230 bufRefDomain.get(), &dwRefDomainLen,
1231 peUse))
1232 {
1233 if (sName ) sName ->assign(bufName .get(), dwNameLen - 1);
1234 if (sReferencedDomainName) sReferencedDomainName->assign(bufRefDomain.get(), dwRefDomainLen - 1);
1235 return TRUE;
1236 }
1237 }
1238
1239 return FALSE;
1240}
1241
1247template<class _Ty>
1248static _Success_(return != 0) BOOL GetTokenInformation(_In_ HANDLE TokenHandle, _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, _Out_ std::unique_ptr<_Ty> &TokenInformation) noexcept
1249{
1250 BYTE szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(BYTE)];
1251 DWORD dwSize;
1252
1253 if (GetTokenInformation(TokenHandle, TokenInformationClass, szStackBuffer, sizeof(szStackBuffer), &dwSize)) {
1254 // The stack buffer was big enough to retrieve complete data. Alloc and copy.
1255 TokenInformation.reset((_Ty*)(new BYTE[dwSize / sizeof(BYTE)]));
1256 if (!TokenInformation) {
1257 SetLastError(ERROR_OUTOFMEMORY);
1258 return FALSE;
1259 }
1260 memcpy(TokenInformation.get(), szStackBuffer, dwSize);
1261 return TRUE;
1262 } else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
1263 // The stack buffer was too small to retrieve complete data. Alloc and retry.
1264 TokenInformation.reset((_Ty*)(new BYTE[dwSize / sizeof(BYTE)]));
1265 if (!TokenInformation) {
1266 SetLastError(ERROR_OUTOFMEMORY);
1267 return FALSE;
1268 }
1269 return GetTokenInformation(TokenHandle, TokenInformationClass, TokenInformation.get(), dwSize, &dwSize);
1270 } else
1271 return FALSE;
1272}
1273
1279template<class _Traits, class _Ax>
1280static _Success_(return != 0) BOOL QueryFullProcessImageNameA(_In_ HANDLE hProcess, _In_ DWORD dwFlags, _Inout_ std::basic_string<char, _Traits, _Ax>& sExeName)
1281{
1282 char szStackBuffer[WINSTD_STACK_BUFFER_BYTES / sizeof(char)];
1283 DWORD dwSize = _countof(szStackBuffer);
1284
1285 // Try with stack buffer first.
1286 if (::QueryFullProcessImageNameA(hProcess, dwFlags, szStackBuffer, &dwSize)) {
1287 // Copy from stack.
1288 sExeName.assign(szStackBuffer, dwSize);
1289 return TRUE;
1290 }
1291 for (DWORD dwCapacity = 2 * WINSTD_STACK_BUFFER_BYTES / sizeof(char); GetLastError() == ERROR_INSUFFICIENT_BUFFER; dwCapacity *= 2) {
1292 // Allocate on heap and retry.
1293 std::unique_ptr<char[]> szBuffer(new char[dwCapacity]);
1294 dwSize = dwCapacity;
1295 if (::QueryFullProcessImageNameA(hProcess, dwFlags, szBuffer.get(), &dwSize)) {
1296 sExeName.assign(szBuffer.get(), dwSize);
1297 return TRUE;
1298 }
1299 }
1300 return FALSE;
1301}
1302
1308template<class _Traits, class _Ax>
1309static _Success_(return != 0) BOOL QueryFullProcessImageNameW(_In_ HANDLE hProcess, _In_ DWORD dwFlags, _Inout_ std::basic_string<wchar_t, _Traits, _Ax>& sExeName)
1310{
1311 wchar_t szStackBuffer[WINSTD_STACK_BUFFER_BYTES / sizeof(wchar_t)];
1312 DWORD dwSize = _countof(szStackBuffer);
1313
1314 // Try with stack buffer first.
1315 if (::QueryFullProcessImageNameW(hProcess, dwFlags, szStackBuffer, &dwSize)) {
1316 // Copy from stack.
1317 sExeName.assign(szStackBuffer, dwSize);
1318 return TRUE;
1319 }
1320 for (DWORD dwCapacity = 2 * WINSTD_STACK_BUFFER_BYTES / sizeof(wchar_t); GetLastError() == ERROR_INSUFFICIENT_BUFFER; dwCapacity *= 2) {
1321 // Allocate on heap and retry.
1322 std::unique_ptr<wchar_t[]> szBuffer(new wchar_t[dwCapacity]);
1323 dwSize = dwCapacity;
1324 if (::QueryFullProcessImageNameW(hProcess, dwFlags, szBuffer.get(), &dwSize)) {
1325 sExeName.assign(szBuffer.get(), dwSize);
1326 return TRUE;
1327 }
1328 }
1329 return FALSE;
1330}
1331
1333
1334#pragma warning(pop)
1335
1336namespace winstd
1337{
1340
1344 template<HANDLE INVALID>
1345 class win_handle : public handle<HANDLE, INVALID>
1346 {
1348
1349 public:
1355 virtual ~win_handle()
1356 {
1357 if (m_h != invalid)
1358 free_internal();
1359 }
1360
1361 protected:
1367 void free_internal() noexcept override
1368 {
1369 CloseHandle(m_h);
1370 }
1371 };
1372
1378 class library : public handle<HMODULE, NULL>
1379 {
1381
1382 public:
1388 virtual ~library()
1389 {
1390 if (m_h != invalid)
1391 free_internal();
1392 }
1393
1394 protected:
1400 void free_internal() noexcept override
1401 {
1402 FreeLibrary(m_h);
1403 }
1404 };
1405
1412
1419
1426
1433
1440
1444 template <class _Ty> struct UnmapViewOfFile_delete
1445 {
1447
1452
1457
1461 void operator()(_Ty* _Ptr) const
1462 {
1463 if (!UnmapViewOfFile(_Ptr))
1464 throw win_runtime_error("UnmapViewOfFile failed");
1465 }
1466 };
1467
1471 template <class _Ty> struct UnmapViewOfFile_delete<_Ty[]>
1472 {
1474
1479
1483 void operator()(_Ty* _Ptr) const
1484 {
1485 if (!UnmapViewOfFile(_Ptr))
1486 throw win_runtime_error("UnmapViewOfFile failed");
1487 }
1488
1492 template<class _Other>
1493 void operator()(_Other*) const
1494 {
1495 if (!UnmapViewOfFile(_Ptr))
1496 throw win_runtime_error("UnmapViewOfFile failed");
1497 }
1498 };
1499
1507
1512 {
1515
1516 public:
1523 {
1524 InitializeCriticalSection(&m_data);
1525 }
1526
1533 {
1534 DeleteCriticalSection(&m_data);
1535 }
1536
1542 operator LPCRITICAL_SECTION() noexcept
1543 {
1544 return &m_data;
1545 }
1546
1547 protected:
1548 CRITICAL_SECTION m_data;
1549 };
1550
1556 class find_file : public handle<HANDLE, INVALID_HANDLE_VALUE>
1557 {
1558 WINSTD_HANDLE_IMPL(find_file, INVALID_HANDLE_VALUE)
1559
1560 public:
1566 virtual ~find_file()
1567 {
1568 if (m_h != invalid)
1569 free_internal();
1570 }
1571
1572 protected:
1578 void free_internal() noexcept override
1579 {
1580 FindClose(m_h);
1581 }
1582 };
1583
1589 class heap : public handle<HANDLE, NULL>
1590 {
1592
1593 public:
1599 virtual ~heap()
1600 {
1601 if (m_h != invalid)
1602 free_internal();
1603 }
1604
1612 bool enumerate() noexcept
1613 {
1614 assert(m_h != invalid);
1615
1616 bool found = false;
1617
1618 // Lock the heap for exclusive access.
1619 HeapLock(m_h);
1620
1621 PROCESS_HEAP_ENTRY e;
1622 e.lpData = NULL;
1623 while (HeapWalk(m_h, &e) != FALSE) {
1624 if ((e.wFlags & PROCESS_HEAP_ENTRY_BUSY) != 0) {
1626 _T("Allocated block%s%s\n")
1627 _T(" Data portion begins at: %#p\n Size: %d bytes\n")
1628 _T(" Overhead: %d bytes\n Region index: %d\n"),
1629 (e.wFlags & PROCESS_HEAP_ENTRY_MOVEABLE) != 0 ? tstring_printf(_T(", movable with HANDLE %#p"), e.Block.hMem).c_str() : _T(""),
1630 (e.wFlags & PROCESS_HEAP_ENTRY_DDESHARE) != 0 ? _T(", DDESHARE") : _T(""),
1631 e.lpData,
1632 e.cbData,
1633 e.cbOverhead,
1634 e.iRegionIndex);
1635
1636 found = true;
1637 }
1638 }
1639
1640 const DWORD dwResult = GetLastError();
1641 if (dwResult != ERROR_NO_MORE_ITEMS)
1642 OutputDebugStr(_T("HeapWalk failed (error %u).\n"), dwResult);
1643
1644 // Unlock the heap.
1645 HeapUnlock(m_h);
1646
1647 return found;
1648 }
1649
1650 protected:
1656 void free_internal() noexcept override
1657 {
1658 enumerate();
1659 HeapDestroy(m_h);
1660 }
1661 };
1662
1666 template <class _Ty>
1668 {
1669 public:
1670 typedef typename _Ty value_type;
1671
1672 typedef _Ty *pointer;
1673 typedef _Ty& reference;
1674 typedef const _Ty *const_pointer;
1675 typedef const _Ty& const_reference;
1676
1677 typedef SIZE_T size_type;
1678 typedef ptrdiff_t difference_type;
1679
1683 template <class _Other>
1684 struct rebind
1685 {
1687 };
1688
1689 public:
1696 {
1697 }
1698
1704 template <class _Other>
1706 {
1707 }
1708
1717 {
1718 assert(m_heap);
1719 return (pointer)HeapAlloc(m_heap, 0, count * sizeof(_Ty));
1720 }
1721
1728 void deallocate(_In_ pointer ptr, _In_ size_type size)
1729 {
1730 UNREFERENCED_PARAMETER(size);
1731 assert(m_heap);
1732 HeapFree(m_heap, 0, ptr);
1733 }
1734
1741 void construct(_Inout_ pointer ptr, _In_ const _Ty& val)
1742 {
1743 ::new ((void*)ptr) _Ty(val);
1744 }
1745
1752 void construct(_Inout_ pointer ptr, _Inout_ _Ty&& val)
1753 {
1754 ::new ((void*)ptr) _Ty(std::forward<_Ty>(val));
1755 }
1756
1762 void destroy(_Inout_ pointer ptr)
1763 {
1764 ptr->_Ty::~_Ty();
1765 }
1766
1771 {
1772 return (SIZE_T)-1;
1773 }
1774
1775 public:
1776 HANDLE m_heap;
1777 };
1778
1783 {
1786
1787 public:
1795 actctx_activator(_In_ HANDLE hActCtx) noexcept
1796 {
1797 if (!ActivateActCtx(hActCtx, &m_cookie))
1798 m_cookie = 0;
1799 }
1800
1807 {
1808 if (m_cookie)
1809 DeactivateActCtx(0, m_cookie);
1810 }
1811
1812 protected:
1813 ULONG_PTR m_cookie;
1814 };
1815
1820 {
1823
1824 public:
1832 user_impersonator(_In_opt_ HANDLE hToken) noexcept
1833 {
1834 m_cookie = hToken && ImpersonateLoggedOnUser(hToken);
1835 }
1836
1843 {
1844 if (m_cookie)
1845 RevertToSelf();
1846 }
1847
1848 protected:
1850 };
1851
1856 {
1859
1860 public:
1868 console_ctrl_handler(_In_opt_ PHANDLER_ROUTINE HandlerRoutine) noexcept : m_handler(HandlerRoutine)
1869 {
1870 m_cookie = SetConsoleCtrlHandler(m_handler, TRUE);
1871 }
1872
1879 {
1880 if (m_cookie)
1881 SetConsoleCtrlHandler(m_handler, FALSE);
1882 }
1883
1884 protected:
1886 PHANDLER_ROUTINE m_handler;
1887 };
1888
1892 class vmemory : public handle<LPVOID, NULL>
1893 {
1895
1896 public:
1900 vmemory() noexcept : m_proc(NULL)
1901 {
1902 }
1903
1910 vmemory(_In_ handle_type h, _In_ HANDLE proc) noexcept :
1911 m_proc(proc),
1913 {
1914 }
1915
1921 vmemory(_Inout_ vmemory &&h) noexcept :
1922 m_proc(std::move(h.m_proc)),
1923 handle<LPVOID, NULL>(std::move(h))
1924 {
1925 }
1926
1932 virtual ~vmemory()
1933 {
1934 if (m_h != invalid)
1935 VirtualFreeEx(m_proc, m_h, 0, MEM_RELEASE);
1936 }
1937
1943 vmemory& operator=(_Inout_ vmemory &&other) noexcept
1944 {
1945 if (this != std::addressof(other)) {
1946 (handle<handle_type, NULL>&&)*this = std::move(other);
1947 m_proc = std::move(other.m_proc);
1948 }
1949 return *this;
1950 }
1951
1960 void attach(_In_ HANDLE proc, _In_opt_ handle_type h) noexcept
1961 {
1962 m_proc = proc;
1963 if (m_h != invalid)
1964 free_internal();
1965 m_h = h;
1966 }
1967
1977 bool alloc(
1978 _In_ HANDLE hProcess,
1979 _In_opt_ LPVOID lpAddress,
1980 _In_ SIZE_T dwSize,
1981 _In_ DWORD flAllocationType,
1982 _In_ DWORD flProtect) noexcept
1983 {
1984 handle_type h = VirtualAllocEx(hProcess, lpAddress, dwSize, flAllocationType, flProtect);
1985 if (h != invalid) {
1986 attach(hProcess, h);
1987 return true;
1988 } else
1989 return false;
1990 }
1991
1992 protected:
1998 void free_internal() noexcept override
1999 {
2000 VirtualFreeEx(m_proc, m_h, 0, MEM_RELEASE);
2001 }
2002
2003 protected:
2004 HANDLE m_proc;
2005 };
2006
2013 class reg_key : public handle<HKEY, NULL>
2014 {
2016
2017 public:
2023 virtual ~reg_key()
2024 {
2025 if (m_h != invalid)
2026 free_internal();
2027 }
2028
2038 bool delete_subkey(_In_z_ LPCTSTR szSubkey)
2039 {
2040 LSTATUS s;
2041
2042 s = RegDeleteKey(m_h, szSubkey);
2043 if (s == ERROR_SUCCESS || s == ERROR_FILE_NOT_FOUND)
2044 return true;
2045
2046 {
2047 reg_key k;
2048 handle_type h;
2049 s = RegOpenKeyEx(m_h, szSubkey, 0, KEY_ENUMERATE_SUB_KEYS, &h);
2050 if (s == ERROR_SUCCESS)
2051 k.attach(h);
2052 else {
2053 SetLastError(s);
2054 return false;
2055 }
2056 for (;;) {
2057 TCHAR szName[MAX_PATH];
2058 DWORD dwSize = _countof(szName);
2059 s = RegEnumKeyEx(k, 0, szName, &dwSize, NULL, NULL, NULL, NULL);
2060 if (s == ERROR_SUCCESS)
2061 k.delete_subkey(szName);
2062 else if (s == ERROR_NO_MORE_ITEMS)
2063 break;
2064 else {
2065 SetLastError(s);
2066 return false;
2067 }
2068 }
2069 }
2070
2071 s = RegDeleteKey(m_h, szSubkey);
2072 if (s == ERROR_SUCCESS)
2073 return true;
2074 else {
2075 SetLastError(s);
2076 return false;
2077 }
2078 }
2079
2080 protected:
2086 void free_internal() noexcept override
2087 {
2088 RegCloseKey(m_h);
2089 }
2090 };
2091
2095 class security_id : public handle<PSID, NULL>
2096 {
2098
2099 public:
2106 {
2107 if (m_h != invalid)
2108 free_internal();
2109 }
2110
2111 protected:
2117 void free_internal() noexcept override
2118 {
2119 FreeSid(m_h);
2120 }
2121 };
2122
2126 class process_information : public PROCESS_INFORMATION
2127 {
2130
2131 public:
2136 {
2137 hProcess = INVALID_HANDLE_VALUE;
2138 hThread = INVALID_HANDLE_VALUE;
2139 dwProcessId = 0;
2140 dwThreadId = 0;
2141 }
2142
2147 {
2148 #pragma warning(push)
2149 #pragma warning(disable: 6001) // Using uninitialized memory '*this'. << ???
2150
2151 if (hProcess != INVALID_HANDLE_VALUE)
2152 CloseHandle(hProcess);
2153
2154 if (hThread != INVALID_HANDLE_VALUE)
2155 CloseHandle(hThread);
2156
2157 #pragma warning(pop)
2158 }
2159 };
2160
2166 class event_log : public handle<HANDLE, NULL>
2167 {
2169
2170 public:
2176 virtual ~event_log()
2177 {
2178 if (m_h != invalid)
2179 free_internal();
2180 }
2181
2182 protected:
2188 void free_internal() noexcept override
2189 {
2190 DeregisterEventSource(m_h);
2191 }
2192 };
2193
2195}
2196
2199
2200#pragma warning(push)
2201#pragma warning(disable: 4505) // Don't warn on unused code
2202
2204static LSTATUS RegCreateKeyExA(
2205 _In_ HKEY hKey,
2206 _In_ LPCSTR lpSubKey,
2207 _Reserved_ DWORD Reserved,
2208 _In_opt_ LPSTR lpClass,
2209 _In_ DWORD dwOptions,
2210 _In_ REGSAM samDesired,
2211 _In_opt_ CONST LPSECURITY_ATTRIBUTES lpSecurityAttributes,
2212 _Inout_ winstd::reg_key &result,
2213 _Out_opt_ LPDWORD lpdwDisposition)
2214{
2215 HKEY h;
2216 LSTATUS s = RegCreateKeyExA(hKey, lpSubKey, Reserved, lpClass, dwOptions, samDesired, lpSecurityAttributes, &h, lpdwDisposition);
2217 if (s == ERROR_SUCCESS)
2218 result.attach(h);
2219 return s;
2220}
2221
2227static LSTATUS RegCreateKeyExW(
2228 _In_ HKEY hKey,
2229 _In_ LPCWSTR lpSubKey,
2230 _Reserved_ DWORD Reserved,
2231 _In_opt_ LPWSTR lpClass,
2232 _In_ DWORD dwOptions,
2233 _In_ REGSAM samDesired,
2234 _In_opt_ CONST LPSECURITY_ATTRIBUTES lpSecurityAttributes,
2235 _Inout_ winstd::reg_key &result,
2236 _Out_opt_ LPDWORD lpdwDisposition)
2237{
2238 HKEY h;
2239 LSTATUS s = RegCreateKeyExW(hKey, lpSubKey, Reserved, lpClass, dwOptions, samDesired, lpSecurityAttributes, &h, lpdwDisposition);
2240 if (s == ERROR_SUCCESS)
2241 result.attach(h);
2242 return s;
2243}
2244
2246static LSTATUS RegOpenKeyExA(
2247 _In_ HKEY hKey,
2248 _In_opt_ LPCSTR lpSubKey,
2249 _In_opt_ DWORD ulOptions,
2250 _In_ REGSAM samDesired,
2251 _Inout_ winstd::reg_key &result)
2252{
2253 HKEY h;
2254 LSTATUS s = RegOpenKeyExA(hKey, lpSubKey, ulOptions, samDesired, &h);
2255 if (s == ERROR_SUCCESS)
2256 result.attach(h);
2257 return s;
2258}
2259
2269static LSTATUS RegOpenKeyExW(
2270 _In_ HKEY hKey,
2271 _In_opt_ LPCWSTR lpSubKey,
2272 _In_opt_ DWORD ulOptions,
2273 _In_ REGSAM samDesired,
2274 _Inout_ winstd::reg_key &result)
2275{
2276 HKEY h;
2277 LSTATUS s = RegOpenKeyExW(hKey, lpSubKey, ulOptions, samDesired, &h);
2278 if (s == ERROR_SUCCESS)
2279 result.attach(h);
2280 return s;
2281}
2282
2283#pragma warning(pop)
2284
Activates given activation context in constructor and deactivates it in destructor.
Definition: Win.h:1783
actctx_activator(HANDLE hActCtx) noexcept
Construct the activator and activates the given activation context.
Definition: Win.h:1795
virtual ~actctx_activator()
Deactivates activation context and destructs the activator.
Definition: Win.h:1806
ULONG_PTR m_cookie
Cookie for context deactivation.
Definition: Win.h:1813
Base template class to support string formatting using printf() style templates.
Definition: Common.h:1115
Console control handler stack management.
Definition: Win.h:1856
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:1868
virtual ~console_ctrl_handler()
Pops console control handler from the console control handler stack.
Definition: Win.h:1878
PHANDLER_ROUTINE m_handler
Pointer to console control handler.
Definition: Win.h:1886
BOOL m_cookie
Did pushing the console control handler succeed?
Definition: Win.h:1885
Critical section wrapper.
Definition: Win.h:1512
critical_section() noexcept
Construct the object and initializes a critical section object.
Definition: Win.h:1522
CRITICAL_SECTION m_data
Critical section struct.
Definition: Win.h:1548
virtual ~critical_section()
Releases all resources used by an unowned critical section object.
Definition: Win.h:1532
Event log handle wrapper.
Definition: Win.h:2167
void free_internal() noexcept override
Closes an event log handle.
Definition: Win.h:2188
virtual ~event_log()
Closes an event log handle.
Definition: Win.h:2176
Find-file handle wrapper.
Definition: Win.h:1557
virtual ~find_file()
Closes a file search handle.
Definition: Win.h:1566
void free_internal() noexcept override
Closes a file search handle.
Definition: Win.h:1578
Base abstract template class to support generic object handle keeping.
Definition: Common.h:607
LPVOID handle_type
Datatype of the object handle this template class handles.
Definition: Common.h:612
handle_type m_h
Object handle.
Definition: Common.h:858
void attach(handle_type h) noexcept
Sets a new object handle for the class.
Definition: Common.h:821
HeapAlloc allocator.
Definition: Win.h:1668
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:1677
_Ty value_type
A type that is managed by the allocator.
Definition: Win.h:1670
heap_allocator(const heap_allocator< _Other > &other)
Constructs allocator from another type.
Definition: Win.h:1705
HANDLE m_heap
Heap handle.
Definition: Win.h:1776
pointer allocate(size_type count)
Allocates a new memory block.
Definition: Win.h:1716
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:1678
heap_allocator(HANDLE heap)
Constructs allocator.
Definition: Win.h:1695
_Ty & reference
A type that provides a reference to the type of object managed by the allocator.
Definition: Win.h:1673
void construct(pointer ptr, _Ty &&val)
Calls moving constructor for the element.
Definition: Win.h:1752
void deallocate(pointer ptr, size_type size)
Frees memory block.
Definition: Win.h:1728
size_type max_size() const
Returns maximum memory block size.
Definition: Win.h:1770
void construct(pointer ptr, const _Ty &val)
Calls copying constructor for the element.
Definition: Win.h:1741
const _Ty & const_reference
A type that provides a constant reference to type of object managed by the allocator.
Definition: Win.h:1675
const _Ty * const_pointer
A type that provides a constant pointer to the type of object managed by the allocator.
Definition: Win.h:1674
_Ty * pointer
A type that provides a pointer to the type of object managed by the allocator.
Definition: Win.h:1672
void destroy(pointer ptr)
Calls destructor for the element.
Definition: Win.h:1762
Heap handle wrapper.
Definition: Win.h:1590
bool enumerate() noexcept
Enumerates allocated heap blocks using OutputDebugString()
Definition: Win.h:1612
void free_internal() noexcept override
Destroys the heap.
Definition: Win.h:1656
virtual ~heap()
Destroys the heap.
Definition: Win.h:1599
Module handle wrapper.
Definition: Win.h:1379
void free_internal() noexcept override
Frees the module.
Definition: Win.h:1400
virtual ~library()
Frees the module.
Definition: Win.h:1388
PROCESS_INFORMATION struct wrapper.
Definition: Win.h:2127
~process_information()
Closes process and thread handles.
Definition: Win.h:2146
process_information() noexcept
Constructs blank PROCESS_INFORMATION.
Definition: Win.h:2135
Registry key wrapper class.
Definition: Win.h:2014
void free_internal() noexcept override
Closes a handle to the registry key.
Definition: Win.h:2086
bool delete_subkey(LPCTSTR szSubkey)
Deletes the specified registry subkey.
Definition: Win.h:2038
virtual ~reg_key()
Closes a handle to the registry key.
Definition: Win.h:2023
SID wrapper class.
Definition: Win.h:2096
void free_internal() noexcept override
Closes a handle to the SID.
Definition: Win.h:2117
virtual ~security_id()
Closes a handle to the SID.
Definition: Win.h:2105
Lets the calling thread impersonate the security context of a logged-on user.
Definition: Win.h:1820
BOOL m_cookie
Did impersonation succeed?
Definition: Win.h:1849
user_impersonator(HANDLE hToken) noexcept
Construct the impersonator and impersonates the given user.
Definition: Win.h:1832
virtual ~user_impersonator()
Reverts to current user and destructs the impersonator.
Definition: Win.h:1842
Memory in virtual address space of a process handle wrapper.
Definition: Win.h:1893
vmemory & operator=(vmemory &&other) noexcept
Move assignment.
Definition: Win.h:1943
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:1977
void free_internal() noexcept override
Frees the memory.
Definition: Win.h:1998
void attach(HANDLE proc, handle_type h) noexcept
Sets a new memory handle for the class.
Definition: Win.h:1960
virtual ~vmemory()
Frees the memory.
Definition: Win.h:1932
vmemory(handle_type h, HANDLE proc) noexcept
Initializes a new class instance with an already available object handle.
Definition: Win.h:1910
vmemory() noexcept
Initializes a new class instance with the memory handle set to INVAL.
Definition: Win.h:1900
vmemory(vmemory &&h) noexcept
Move constructor.
Definition: Win.h:1921
HANDLE m_proc
Handle of memory's process.
Definition: Win.h:2004
Windows HANDLE wrapper class.
Definition: Win.h:1346
void free_internal() noexcept override
Closes an open object handle.
Definition: Win.h:1367
virtual ~win_handle()
Closes an open object handle.
Definition: Win.h:1355
Windows runtime error.
Definition: Common.h:1048
#define WINSTD_NONCOPYABLE(C)
Declares a class as non-copyable.
Definition: Common.h:66
#define WINSTD_STACK_BUFFER_BYTES
Size of the stack buffer in bytes used for initial system function call.
Definition: Common.h:93
#define WINSTD_NONMOVABLE(C)
Declares a class as non-movable.
Definition: Common.h:74
static int vsprintf(std::basic_string< _Elem, _Traits, _Ax > &str, const _Elem *format, va_list arg)
Formats string using printf().
Definition: Common.h:251
static int sprintf(std::basic_string< _Elem, _Traits, _Ax > &str, const _Elem *format,...)
Formats string using printf().
Definition: Common.h:284
#define WINSTD_HANDLE_IMPL(C, INVAL)
Implements default constructors and operators to prevent their auto-generation by compiler.
Definition: Common.h:163
static const HANDLE invalid
Invalid handle value.
Definition: Common.h:617
static int NormalizeString(NORM_FORM NormForm, LPCWSTR lpSrcString, int cwSrcLength, std::basic_string< wchar_t, _Traits, _Ax > &sDstString) noexcept
Normalizes characters of a text string according to Unicode 4.0 TR#15.
Definition: Win.h:970
static int SecureWideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, std::basic_string< char, _Traits, _Ax > &sMultiByteStr, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar) noexcept
Maps a UTF-16 (wide character) string to a std::string. The new character string is not necessarily f...
Definition: Win.h:713
static DWORD ExpandEnvironmentStringsA(LPCSTR lpSrc, std::basic_string< char, _Traits, _Ax > &sValue) noexcept
Expands environment-variable strings, replaces them with the values defined for the current user,...
Definition: Win.h:177
static BOOL StringToGuidA(LPCSTR lpszGuid, LPGUID lpGuid, LPCSTR *lpszGuidEnd=NULL) noexcept
Parses string with GUID and stores it to GUID.
Definition: Win.h:266
static int GetWindowTextA(HWND hWnd, std::basic_string< char, _Traits, _Ax > &sValue) noexcept
Copies the text of the specified window's title bar (if it has one) into a std::wstring string.
Definition: Win.h:79
static LSTATUS RegCreateKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass, DWORD dwOptions, REGSAM samDesired, CONST LPSECURITY_ATTRIBUTES lpSecurityAttributes, winstd::reg_key &result, LPDWORD lpdwDisposition)
Creates the specified registry key. If the key already exists, the function opens it.
Definition: Win.h:2227
static int WINAPI LoadStringA(HINSTANCE hInstance, UINT uID, std::basic_string< char, _Traits, _Ax > &sBuffer) noexcept
Loads a string resource from the executable file associated with a specified module.
Definition: Win.h:1052
win_handle< INVALID_HANDLE_VALUE > file
File handle wrapper.
Definition: Win.h:1432
static BOOL GetFileVersionInfoA(LPCSTR lptstrFilename, __reserved DWORD dwHandle, std::vector< _Ty, _Ax > &aValue) noexcept
Retrieves version information for the specified file and stores it in a std::vector buffer.
Definition: Win.h:141
static int MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, std::basic_string< wchar_t, _Traits, _Ax > &sWideCharStr) noexcept
Maps a character string to a UTF-16 (wide character) std::wstring. The character string is not necess...
Definition: Win.h:802
static LSTATUS RegCreateKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD Reserved, LPSTR lpClass, DWORD dwOptions, REGSAM samDesired, CONST LPSECURITY_ATTRIBUTES lpSecurityAttributes, winstd::reg_key &result, LPDWORD lpdwDisposition)
Creates the specified registry key. If the key already exists, the function opens it.
Definition: Win.h:2204
static LSTATUS RegOpenKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, winstd::reg_key &result)
Opens the specified registry key.
Definition: Win.h:2246
static LSTATUS RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, winstd::reg_key &result)
Opens the specified registry key.
Definition: Win.h:2269
static VOID GuidToStringA(LPCGUID lpGuid, std::basic_string< char, _Traits, _Ax > &str) noexcept
Formats GUID and stores it in a std::wstring string.
Definition: Win.h:227
static BOOL StringToGuidW(LPCWSTR lpszGuid, LPGUID lpGuid, LPCWSTR *lpszGuidEnd=NULL) noexcept
Parses string with GUID and stores it to GUID.
Definition: Win.h:339
static LSTATUS RegLoadMUIStringW(HKEY hKey, LPCWSTR pszValue, std::basic_string< wchar_t, _Traits, _Ax > &sOut, DWORD Flags, LPCWSTR pszDirectory) noexcept
Loads the specified string from the specified key and subkey, and stores it in a std::wstring string.
Definition: Win.h:604
static BOOL LookupAccountSidA(LPCSTR lpSystemName, PSID lpSid, std::basic_string< char, _Traits, _Ax > *sName, std::basic_string< char, _Traits, _Ax > *sReferencedDomainName, PSID_NAME_USE peUse) noexcept
Retrieves the name of the account for this SID and the name of the first domain on which this SID is ...
Definition: Win.h:1170
static DWORD GetModuleFileNameW(HMODULE hModule, std::basic_string< wchar_t, _Traits, _Ax > &sValue) noexcept
Retrieves the fully qualified path for the file that contains the specified module and stores it in a...
Definition: Win.h:54
static BOOL LookupAccountSidW(LPCWSTR lpSystemName, PSID lpSid, std::basic_string< wchar_t, _Traits, _Ax > *sName, std::basic_string< wchar_t, _Traits, _Ax > *sReferencedDomainName, PSID_NAME_USE peUse) noexcept
Retrieves the name of the account for this SID and the name of the first domain on which this SID is ...
Definition: Win.h:1209
win_handle< INVALID_HANDLE_VALUE > process_snapshot
Process snapshot handle wrapper.
Definition: Win.h:1425
static DWORD GetModuleFileNameA(HMODULE hModule, std::basic_string< char, _Traits, _Ax > &sValue) noexcept
Retrieves the fully qualified path for the file that contains the specified module and stores it in a...
Definition: Win.h:23
static int GetDateFormatW(LCID Locale, DWORD dwFlags, const SYSTEMTIME *lpDate, LPCWSTR lpFormat, std::basic_string< wchar_t, _Traits, _Ax > &sDate) noexcept
Formats a date as a date string for a locale specified by the locale identifier. The function formats...
Definition: Win.h:1154
static int WINAPI LoadStringW(HINSTANCE hInstance, UINT uID, std::basic_string< wchar_t, _Traits, _Ax > &sBuffer) noexcept
Loads a string resource from the executable file associated with a specified module.
Definition: Win.h:1070
static BOOL GetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, std::unique_ptr< _Ty > &TokenInformation) noexcept
Retrieves a specified type of information about an access token. The calling process must have approp...
Definition: Win.h:1248
static LSTATUS RegQueryValueExW(HKEY hKey, LPCWSTR lpValueName, __reserved LPDWORD lpReserved, LPDWORD lpType, std::vector< _Ty, _Ax > &aData) noexcept
Retrieves the type and data for the specified value name associated with an open registry key and sto...
Definition: Win.h:565
static BOOL GetFileVersionInfoW(LPCWSTR lptstrFilename, __reserved DWORD dwHandle, std::vector< _Ty, _Ax > &aValue) noexcept
Retrieves version information for the specified file and stores it in a std::vector buffer.
Definition: Win.h:161
win_handle< NULL > event
Event handle wrapper.
Definition: Win.h:1506
static LSTATUS RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, std::basic_string< char, _Traits, _Ax > &sOut, DWORD Flags, LPCSTR pszDirectory) noexcept
Loads the specified string from the specified key and subkey, and stores it in a std::wstring string.
Definition: Win.h:590
static VOID OutputDebugStr(LPCSTR lpOutputString,...) noexcept
Formats and sends a string to the debugger for display.
Definition: Win.h:1111
static BOOL QueryFullProcessImageNameA(HANDLE hProcess, DWORD dwFlags, std::basic_string< char, _Traits, _Ax > &sExeName)
Retrieves the full name of the executable image for the specified process.
Definition: Win.h:1280
win_handle< NULL > file_mapping
File mapping.
Definition: Win.h:1439
static int SecureMultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, std::basic_string< wchar_t, _Traits, _Ax > &sWideCharStr) noexcept
Maps a character string to a UTF-16 (wide character) std::wstring. The character string is not necess...
Definition: Win.h:881
static int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, std::basic_string< char, _Traits, _Ax > &sMultiByteStr, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar) noexcept
Maps a UTF-16 (wide character) string to a std::string. The new character string is not necessarily f...
Definition: Win.h:634
static BOOL QueryFullProcessImageNameW(HANDLE hProcess, DWORD dwFlags, std::basic_string< wchar_t, _Traits, _Ax > &sExeName)
Retrieves the full name of the executable image for the specified process.
Definition: Win.h:1309
win_handle< NULL > process
Process handle wrapper.
Definition: Win.h:1411
static LSTATUS RegQueryValueExA(HKEY hKey, LPCSTR lpValueName, __reserved LPDWORD lpReserved, LPDWORD lpType, std::vector< _Ty, _Ax > &aData) noexcept
Retrieves the type and data for the specified value name associated with an open registry key and sto...
Definition: Win.h:538
static LSTATUS RegQueryStringValue(HKEY hReg, LPCSTR pszName, std::basic_string< char, _Traits, _Ax > &sValue) noexcept
Queries for a string value in the registry and stores it in a std::string string.
Definition: Win.h:427
static int GetWindowTextW(HWND hWnd, std::basic_string< wchar_t, _Traits, _Ax > &sValue) noexcept
Copies the text of the specified window's title bar (if it has one) into a std::wstring string.
Definition: Win.h:112
static int GetDateFormatA(LCID Locale, DWORD dwFlags, const SYSTEMTIME *lpDate, LPCSTR lpFormat, std::basic_string< char, _Traits, _Ax > &sDate) noexcept
Formats a date as a date string for a locale specified by the locale identifier. The function formats...
Definition: Win.h:1134
static DWORD ExpandEnvironmentStringsW(LPCWSTR lpSrc, std::basic_string< wchar_t, _Traits, _Ax > &sValue) noexcept
Expands environment-variable strings, replaces them with the values defined for the current user,...
Definition: Win.h:205
static VOID GuidToStringW(LPCGUID lpGuid, std::basic_string< wchar_t, _Traits, _Ax > &str) noexcept
Formats GUID and stores it in a std::wstring string.
Definition: Win.h:246
static VOID OutputDebugStrV(LPCSTR lpOutputString, va_list arg) noexcept
Formats and sends a string to the debugger for display.
Definition: Win.h:1087
win_handle< NULL > thread
Thread handle wrapper.
Definition: Win.h:1418
UnmapViewOfFile_delete()
Default construct.
Definition: Win.h:1478
void operator()(_Other *) const
Delete a pointer of another type.
Definition: Win.h:1493
void operator()(_Ty *_Ptr) const
Delete a pointer.
Definition: Win.h:1483
UnmapViewOfFile_delete< _Ty > _Myt
This type.
Definition: Win.h:1473
Deleter for unique_ptr using UnmapViewOfFile.
Definition: Win.h:1445
UnmapViewOfFile_delete(const UnmapViewOfFile_delete< _Ty2 > &)
Construct from another UnmapViewOfFile_delete.
Definition: Win.h:1456
void operator()(_Ty *_Ptr) const
Delete a pointer.
Definition: Win.h:1461
UnmapViewOfFile_delete< _Ty > _Myt
This type.
Definition: Win.h:1446
UnmapViewOfFile_delete()
Default construct.
Definition: Win.h:1451
A structure that enables an allocator for objects of one type to allocate storage for objects of anot...
Definition: Win.h:1685
heap_allocator< _Other > other
Other allocator type.
Definition: Win.h:1686