b180015640313d2ca3df39250bbf66750604bf8e
[reactos.git] / reactos / sdk / lib / 3rdparty / atlex / atlwin.h
1 /*
2 Copyright 1991-2017 Amebis
3
4 This file is part of atlex.
5
6 atlex is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 2 of the License, or
9 (at your option) any later version.
10
11 atlex is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with atlex. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #pragma once
21
22 #include "atlex.h"
23 #include <atlcoll.h>
24 #include <atlstr.h>
25 #include <Windows.h>
26
27 ///
28 /// \defgroup ATLWinAPI Windows API
29 /// Integrates ATL classes with Microsoft Windows API
30 ///
31 /// @{
32
33 ///
34 /// Retrieves the fully qualified path for the file that contains the specified module and stores it in a ATL::CAtlStringA string.
35 ///
36 /// \sa [GetModuleFileName function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms683197.aspx)
37 ///
38 inline DWORD GetModuleFileNameA(_In_opt_ HMODULE hModule, _Out_ ATL::CAtlStringA &sValue)
39 {
40 DWORD dwSize = 0;
41
42 for (;;) {
43 // Increment size and allocate buffer.
44 LPSTR szBuffer = sValue.GetBuffer(dwSize += 1024);
45 if (!szBuffer) {
46 ::SetLastError(ERROR_OUTOFMEMORY);
47 return 0;
48 }
49
50 // Try!
51 DWORD dwResult = ::GetModuleFileNameA(hModule, szBuffer, dwSize);
52 if (dwResult == 0) {
53 // Error.
54 sValue.ReleaseBuffer(0);
55 return 0;
56 } else if (dwResult < dwSize) {
57 DWORD dwLength = (DWORD)strnlen(szBuffer, dwSize);
58 sValue.ReleaseBuffer(dwLength++);
59 if (dwLength == dwSize) {
60 // Buffer was long exactly enough.
61 return dwResult;
62 } if (dwLength < dwSize) {
63 // Buffer was long enough to get entire string, and has some extra space left.
64 sValue.FreeExtra();
65 return dwResult;
66 }
67 }
68 }
69 }
70
71
72 ///
73 /// Retrieves the fully qualified path for the file that contains the specified module and stores it in a ATL::CAtlStringW string.
74 ///
75 /// \sa [GetModuleFileName function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms683197.aspx)
76 ///
77 inline DWORD GetModuleFileNameW(_In_opt_ HMODULE hModule, _Out_ ATL::CAtlStringW &sValue)
78 {
79 DWORD dwSize = 0;
80
81 for (;;) {
82 // Increment size and allocate buffer.
83 LPWSTR szBuffer = sValue.GetBuffer(dwSize += 1024);
84 if (!szBuffer) {
85 ::SetLastError(ERROR_OUTOFMEMORY);
86 return 0;
87 }
88
89 // Try!
90 DWORD dwResult = ::GetModuleFileNameW(hModule, szBuffer, dwSize);
91 if (dwResult == 0) {
92 // Error.
93 sValue.ReleaseBuffer(0);
94 return 0;
95 } else if (dwResult < dwSize) {
96 DWORD dwLength = (DWORD)wcsnlen(szBuffer, dwSize);
97 sValue.ReleaseBuffer(dwLength++);
98 if (dwLength == dwSize) {
99 // Buffer was long exactly enough.
100 return dwResult;
101 } if (dwLength < dwSize) {
102 // Buffer was long enough to get entire string, and has some extra space left.
103 sValue.FreeExtra();
104 return dwResult;
105 }
106 }
107 }
108 }
109
110
111 ///
112 /// Copies the text of the specified window's title bar (if it has one) into a ATL::CAtlStringA string.
113 ///
114 /// \sa [GetWindowText function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633520.aspx)
115 ///
116 inline int GetWindowTextA(_In_ HWND hWnd, _Out_ ATL::CAtlStringA &sValue)
117 {
118 int iResult;
119
120 // Query the final string length first.
121 iResult = ::GetWindowTextLengthA(hWnd);
122 if (iResult > 0) {
123 // Allocate buffer on heap and read the string data into it.
124 LPSTR szBuffer = sValue.GetBuffer(iResult++);
125 if (!szBuffer) {
126 SetLastError(ERROR_OUTOFMEMORY);
127 return 0;
128 }
129 iResult = ::GetWindowTextA(hWnd, szBuffer, iResult);
130 sValue.ReleaseBuffer(iResult);
131 return iResult;
132 } else {
133 // The result is empty.
134 sValue.Empty();
135 return 0;
136 }
137 }
138
139
140 ///
141 /// Copies the text of the specified window's title bar (if it has one) into a ATL::CAtlStringW string.
142 ///
143 /// \sa [GetWindowText function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633520.aspx)
144 ///
145 inline int GetWindowTextW(_In_ HWND hWnd, _Out_ ATL::CAtlStringW &sValue)
146 {
147 int iResult;
148
149 // Query the final string length first.
150 iResult = ::GetWindowTextLengthW(hWnd);
151 if (iResult > 0) {
152 // Allocate buffer on heap and read the string data into it.
153 LPWSTR szBuffer = sValue.GetBuffer(iResult++);
154 if (!szBuffer) {
155 SetLastError(ERROR_OUTOFMEMORY);
156 return 0;
157 }
158 iResult = ::GetWindowTextW(hWnd, szBuffer, iResult);
159 sValue.ReleaseBuffer(iResult);
160 return iResult;
161 } else {
162 // The result is empty.
163 sValue.Empty();
164 return 0;
165 }
166 }
167
168
169 ///
170 /// Retrieves version information for the specified file and stores it in a ATL::CAtlStringA string.
171 ///
172 /// \sa [GetFileVersionInfo function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms647003.aspx)
173 ///
174 inline BOOL GetFileVersionInfoA(_In_ LPCSTR lptstrFilename, __reserved DWORD dwHandle, _Out_ ATL::CAtlArray<BYTE> &aValue)
175 {
176 // Get version info size.
177 DWORD dwVerInfoSize = ::GetFileVersionInfoSizeA(lptstrFilename, &dwHandle);
178 if (dwVerInfoSize != 0) {
179 if (aValue.SetCount(dwVerInfoSize)) {
180 // Read version info.
181 return ::GetFileVersionInfoA(lptstrFilename, dwHandle, dwVerInfoSize, aValue.GetData());
182 } else {
183 ::SetLastError(ERROR_OUTOFMEMORY);
184 return FALSE;
185 }
186 } else
187 return FALSE;
188 }
189
190
191 ///
192 /// Retrieves version information for the specified file and stores it in a ATL::CAtlStringW string.
193 ///
194 /// \sa [GetFileVersionInfo function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms647003.aspx)
195 ///
196 inline BOOL GetFileVersionInfoW(_In_ LPCWSTR lptstrFilename, __reserved DWORD dwHandle, _Out_ ATL::CAtlArray<BYTE> &aValue)
197 {
198 // Get version info size.
199 DWORD dwVerInfoSize = ::GetFileVersionInfoSizeW(lptstrFilename, &dwHandle);
200 if (dwVerInfoSize != 0) {
201 if (aValue.SetCount(dwVerInfoSize)) {
202 // Read version info.
203 return ::GetFileVersionInfoW(lptstrFilename, dwHandle, dwVerInfoSize, aValue.GetData());
204 } else {
205 ::SetLastError(ERROR_OUTOFMEMORY);
206 return FALSE;
207 }
208 } else
209 return FALSE;
210 }
211
212
213 ///
214 /// Expands environment-variable strings, replaces them with the values defined for the current user, and stores it in a ATL::CAtlStringA string.
215 ///
216 /// \sa [ExpandEnvironmentStrings function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724265.aspx)
217 ///
218 inline DWORD ExpandEnvironmentStringsA(_In_ LPCSTR lpSrc, ATL::CAtlStringA &sValue)
219 {
220 DWORD dwBufferSizeEst = (DWORD)strlen(lpSrc) + 0x100; // Initial estimate
221
222 for (;;) {
223 DWORD dwBufferSize = dwBufferSizeEst;
224 LPSTR szBuffer = sValue.GetBuffer(dwBufferSize);
225 if (!szBuffer) {
226 ::SetLastError(ERROR_OUTOFMEMORY);
227 return FALSE;
228 }
229 dwBufferSizeEst = ::ExpandEnvironmentStringsA(lpSrc, szBuffer, dwBufferSize);
230 if (dwBufferSizeEst > dwBufferSize) {
231 // The buffer was to small. Repeat with a bigger one.
232 sValue.ReleaseBuffer(0);
233 } else if (dwBufferSizeEst == 0) {
234 // Error.
235 sValue.ReleaseBuffer(0);
236 return 0;
237 } else {
238 // The buffer was sufficient. Break.
239 sValue.ReleaseBuffer();
240 sValue.FreeExtra();
241 return dwBufferSizeEst;
242 }
243 }
244 }
245
246
247 ///
248 /// Expands environment-variable strings, replaces them with the values defined for the current user, and stores it in a ATL::CAtlStringW string.
249 ///
250 /// \sa [ExpandEnvironmentStrings function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724265.aspx)
251 ///
252 inline DWORD ExpandEnvironmentStringsW(_In_ LPCWSTR lpSrc, ATL::CAtlStringW &sValue)
253 {
254 DWORD dwBufferSizeEst = (DWORD)wcslen(lpSrc) + 0x100; // Initial estimate
255
256 for (;;) {
257 DWORD dwBufferSize = dwBufferSizeEst;
258 LPWSTR szBuffer = sValue.GetBuffer(dwBufferSize);
259 if (!szBuffer) {
260 ::SetLastError(ERROR_OUTOFMEMORY);
261 return FALSE;
262 }
263 dwBufferSizeEst = ::ExpandEnvironmentStringsW(lpSrc, szBuffer, dwBufferSize);
264 if (dwBufferSizeEst > dwBufferSize) {
265 // The buffer was to small. Repeat with a bigger one.
266 sValue.ReleaseBuffer(0);
267 } else if (dwBufferSizeEst == 0) {
268 // Error.
269 sValue.ReleaseBuffer(0);
270 return 0;
271 } else {
272 // The buffer was sufficient. Break.
273 sValue.ReleaseBuffer();
274 sValue.FreeExtra();
275 return dwBufferSizeEst;
276 }
277 }
278 }
279
280
281 ///
282 /// Formats GUID and stores it in a ATL::CAtlStringA string.
283 ///
284 /// \param[in] lpGuid Pointer to GUID
285 /// \param[out] str String to store the result to
286 ///
287 inline VOID GuidToString(_In_ LPCGUID lpGuid, _Out_ ATL::CAtlStringA &str)
288 {
289 str.Format("{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
290 lpGuid->Data1,
291 lpGuid->Data2,
292 lpGuid->Data3,
293 lpGuid->Data4[0], lpGuid->Data4[1],
294 lpGuid->Data4[2], lpGuid->Data4[3], lpGuid->Data4[4], lpGuid->Data4[5], lpGuid->Data4[6], lpGuid->Data4[7]);
295 }
296
297
298 ///
299 /// Formats GUID and stores it in a ATL::CAtlStringW string.
300 ///
301 /// \param[in] lpGuid Pointer to GUID
302 /// \param[out] str String to store the result to
303 ///
304 inline VOID GuidToString(_In_ LPCGUID lpGuid, _Out_ ATL::CAtlStringW &str)
305 {
306 str.Format(L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
307 lpGuid->Data1,
308 lpGuid->Data2,
309 lpGuid->Data3,
310 lpGuid->Data4[0], lpGuid->Data4[1],
311 lpGuid->Data4[2], lpGuid->Data4[3], lpGuid->Data4[4], lpGuid->Data4[5], lpGuid->Data4[6], lpGuid->Data4[7]);
312 }
313
314
315 ///
316 /// Queries for a string value in the registry and stores it in a ATL::CAtlStringA string.
317 ///
318 /// `REG_EXPAND_SZ` are expanded using `ExpandEnvironmentStrings()` before storing to sValue.
319 ///
320 /// \param[in] hReg A handle to an open registry key. The key must have been opened with the KEY_QUERY_VALUE access right.
321 /// \param[in] pszName The name of the registry value. If lpValueName is NULL or an empty string, "", the function retrieves the type and data for the key's unnamed or default value, if any.
322 /// \param[out] sValue String to store the value to
323 /// \return
324 /// - `ERROR_SUCCESS` when query succeeds;
325 /// - `ERROR_INVALID_DATA` when the registy value type is not `REG_SZ`, `REG_MULTI_SZ`, or `REG_EXPAND_SZ`;
326 /// - `ERROR_OUTOFMEMORY` when the memory allocation for the sValue buffer fails;
327 /// - Error code when query fails. See `RegQueryValueEx()` for the list of error codes.
328 /// \sa [RegQueryValueEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724911.aspx)
329 /// \sa [ExpandEnvironmentStrings function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724265.aspx)
330 ///
331 inline LSTATUS RegQueryStringValue(_In_ HKEY hReg, _In_z_ LPCSTR pszName, _Out_ ATL::CAtlStringA &sValue)
332 {
333 LSTATUS lResult;
334 BYTE aStackBuffer[ATL_STACK_BUFFER_BYTES];
335 DWORD dwSize = sizeof(aStackBuffer), dwType;
336
337 // Try with stack buffer first.
338 lResult = ::RegQueryValueExA(hReg, pszName, NULL, &dwType, aStackBuffer, &dwSize);
339 if (lResult == ERROR_SUCCESS) {
340 if (dwType == REG_SZ || dwType == REG_MULTI_SZ) {
341 // The value is REG_SZ or REG_MULTI_SZ. Allocate buffer on heap, copy from stack buffer.
342 LPSTR szBuffer = sValue.GetBuffer(dwSize / sizeof(CHAR));
343 if (!szBuffer) return ERROR_OUTOFMEMORY;
344 memcpy(szBuffer, aStackBuffer, dwSize);
345 sValue.ReleaseBuffer();
346 } else if (dwType == REG_EXPAND_SZ) {
347 // The value is REG_EXPAND_SZ. Expand it from stack buffer.
348 if (::ExpandEnvironmentStringsA((const CHAR*)aStackBuffer, sValue) == 0)
349 lResult = ::GetLastError();
350 } else {
351 // The value is not a string type.
352 lResult = ERROR_INVALID_DATA;
353 }
354 } else if (lResult == ERROR_MORE_DATA) {
355 if (dwType == REG_SZ || dwType == REG_MULTI_SZ) {
356 // The value is REG_SZ or REG_MULTI_SZ. Read it now.
357 LPSTR szBuffer = sValue.GetBuffer(dwSize / sizeof(CHAR));
358 if (!szBuffer) return ERROR_OUTOFMEMORY;
359 if ((lResult = ::RegQueryValueExA(hReg, pszName, NULL, NULL, (LPBYTE)szBuffer, &dwSize)) == ERROR_SUCCESS) {
360 sValue.ReleaseBuffer();
361 } else {
362 // Reading of the value failed.
363 sValue.ReleaseBuffer(0);
364 }
365 } else if (dwType == REG_EXPAND_SZ) {
366 // The value is REG_EXPAND_SZ. Read it and expand environment variables.
367 ATL::CTempBuffer<CHAR> sTemp(dwSize / sizeof(CHAR));
368 if ((lResult = ::RegQueryValueExA(hReg, pszName, NULL, NULL, (LPBYTE)(CHAR*)sTemp, &dwSize)) == ERROR_SUCCESS)
369 if (::ExpandEnvironmentStringsA((const CHAR*)sTemp, sValue) == 0)
370 lResult = ::GetLastError();
371 } else {
372 // The value is not a string type.
373 lResult = ERROR_INVALID_DATA;
374 }
375 }
376
377 return lResult;
378 }
379
380
381 ///
382 /// Queries for a string value in the registry and stores it in a ATL::CAtlStringW string.
383 ///
384 /// `REG_EXPAND_SZ` are expanded using `ExpandEnvironmentStrings()` before storing to sValue.
385 ///
386 /// \param[in] hReg A handle to an open registry key. The key must have been opened with the KEY_QUERY_VALUE access right.
387 /// \param[in] pszName The name of the registry value. If lpValueName is NULL or an empty string, "", the function retrieves the type and data for the key's unnamed or default value, if any.
388 /// \param[out] sValue String to store the value to
389 /// \return
390 /// - `ERROR_SUCCESS` when query succeeds;
391 /// - `ERROR_INVALID_DATA` when the registy value type is not `REG_SZ`, `REG_MULTI_SZ`, or `REG_EXPAND_SZ`;
392 /// - `ERROR_OUTOFMEMORY` when the memory allocation for the sValue buffer fails;
393 /// - Error code when query fails. See `RegQueryValueEx()` for the list of error codes.
394 /// \sa [RegQueryValueEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724911.aspx)
395 /// \sa [ExpandEnvironmentStrings function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724265.aspx)
396 ///
397 inline LSTATUS RegQueryStringValue(_In_ HKEY hReg, _In_z_ LPCWSTR pszName, _Out_ ATL::CAtlStringW &sValue)
398 {
399 LSTATUS lResult;
400 BYTE aStackBuffer[ATL_STACK_BUFFER_BYTES];
401 DWORD dwSize = sizeof(aStackBuffer), dwType;
402
403 // Try with stack buffer first.
404 lResult = ::RegQueryValueExW(hReg, pszName, NULL, &dwType, aStackBuffer, &dwSize);
405 if (lResult == ERROR_SUCCESS) {
406 if (dwType == REG_SZ || dwType == REG_MULTI_SZ) {
407 // The value is REG_SZ or REG_MULTI_SZ. Allocate buffer on heap, copy from stack buffer.
408 LPWSTR szBuffer = sValue.GetBuffer(dwSize / sizeof(WCHAR));
409 if (!szBuffer) return ERROR_OUTOFMEMORY;
410 memcpy(szBuffer, aStackBuffer, dwSize);
411 sValue.ReleaseBuffer();
412 } else if (dwType == REG_EXPAND_SZ) {
413 // The value is REG_EXPAND_SZ. Expand it from stack buffer.
414 if (::ExpandEnvironmentStringsW((const WCHAR*)aStackBuffer, sValue) == 0)
415 lResult = ::GetLastError();
416 } else {
417 // The value is not a string type.
418 lResult = ERROR_INVALID_DATA;
419 }
420 } else if (lResult == ERROR_MORE_DATA) {
421 if (dwType == REG_SZ || dwType == REG_MULTI_SZ) {
422 // The value is REG_SZ or REG_MULTI_SZ. Read it now.
423 LPWSTR szBuffer = sValue.GetBuffer(dwSize / sizeof(WCHAR));
424 if (!szBuffer) return ERROR_OUTOFMEMORY;
425 if ((lResult = ::RegQueryValueExW(hReg, pszName, NULL, NULL, (LPBYTE)szBuffer, &dwSize)) == ERROR_SUCCESS) {
426 sValue.ReleaseBuffer();
427 } else {
428 // Reading of the value failed.
429 sValue.ReleaseBuffer(0);
430 }
431 } else if (dwType == REG_EXPAND_SZ) {
432 // The value is REG_EXPAND_SZ. Read it and expand environment variables.
433 ATL::CTempBuffer<WCHAR> sTemp(dwSize / sizeof(WCHAR));
434 if ((lResult = ::RegQueryValueExW(hReg, pszName, NULL, NULL, (LPBYTE)(WCHAR*)sTemp, &dwSize)) == ERROR_SUCCESS)
435 if (::ExpandEnvironmentStringsW((const WCHAR*)sTemp, sValue) == 0)
436 lResult = ::GetLastError();
437 } else {
438 // The value is not a string type.
439 lResult = ERROR_INVALID_DATA;
440 }
441 }
442
443 return lResult;
444 }
445
446
447 ///
448 /// Retrieves the type and data for the specified value name associated with an open registry key and stores the data in a ATL::CAtlArray<BYTE> buffer.
449 ///
450 /// \sa [RegQueryValueEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724911.aspx)
451 ///
452 inline LSTATUS RegQueryValueExA(_In_ HKEY hKey, _In_opt_ LPCSTR lpValueName, __reserved LPDWORD lpReserved, _Out_opt_ LPDWORD lpType, _Out_ ATL::CAtlArray<BYTE> &aData)
453 {
454 LSTATUS lResult;
455 BYTE aStackBuffer[ATL_STACK_BUFFER_BYTES];
456 DWORD dwSize = sizeof(aStackBuffer);
457
458 // Try with stack buffer first.
459 lResult = RegQueryValueExA(hKey, lpValueName, lpReserved, NULL, aStackBuffer, &dwSize);
460 if (lResult == ERROR_SUCCESS) {
461 // Allocate buffer on heap, copy from stack buffer.
462 if (!aData.SetCount(dwSize)) return ERROR_OUTOFMEMORY;
463 memcpy(aData.GetData(), aStackBuffer, dwSize);
464 } else if (lResult == ERROR_MORE_DATA) {
465 // Allocate buffer on heap and retry.
466 if (!aData.SetCount(dwSize)) return ERROR_OUTOFMEMORY;
467 if ((lResult = RegQueryValueExA(hKey, lpValueName, lpReserved, lpType, aData.GetData(), &dwSize)) != ERROR_SUCCESS)
468 aData.SetCount(0);
469 }
470
471 return lResult;
472 }
473
474
475 ///
476 /// Retrieves the type and data for the specified value name associated with an open registry key and stores the data in a ATL::CAtlArray<BYTE> buffer.
477 ///
478 /// \sa [RegQueryValueEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724911.aspx)
479 ///
480 inline LSTATUS RegQueryValueExW(_In_ HKEY hKey, _In_opt_ LPCWSTR lpValueName, __reserved LPDWORD lpReserved, _Out_opt_ LPDWORD lpType, _Out_ ATL::CAtlArray<BYTE> &aData)
481 {
482 LSTATUS lResult;
483 BYTE aStackBuffer[ATL_STACK_BUFFER_BYTES];
484 DWORD dwSize = sizeof(aStackBuffer);
485
486 // Try with stack buffer first.
487 lResult = RegQueryValueExW(hKey, lpValueName, lpReserved, NULL, aStackBuffer, &dwSize);
488 if (lResult == ERROR_SUCCESS) {
489 // Allocate buffer on heap, copy from stack buffer.
490 if (!aData.SetCount(dwSize)) return ERROR_OUTOFMEMORY;
491 memcpy(aData.GetData(), aStackBuffer, dwSize);
492 } else if (lResult == ERROR_MORE_DATA) {
493 // Allocate buffer on heap and retry.
494 if (!aData.SetCount(dwSize)) return ERROR_OUTOFMEMORY;
495 if ((lResult = RegQueryValueExW(hKey, lpValueName, lpReserved, lpType, aData.GetData(), &dwSize)) != ERROR_SUCCESS)
496 aData.SetCount(0);
497 }
498
499 return lResult;
500 }
501
502
503 #if _WIN32_WINNT >= _WIN32_WINNT_VISTA
504
505 ///
506 /// Loads the specified string from the specified key and subkey, and stores it in a ATL::CAtlStringA string.
507 ///
508 /// \sa [RegLoadMUIString function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724890.aspx)
509 ///
510 inline LSTATUS RegLoadMUIStringA(_In_ HKEY hKey, _In_opt_ LPCSTR pszValue, _Out_ ATL::CAtlStringA &sOut, _In_ DWORD Flags, _In_opt_ LPCSTR pszDirectory)
511 {
512 LSTATUS lResult;
513 CHAR szStackBuffer[ATL_STACK_BUFFER_BYTES/sizeof(CHAR)];
514 DWORD dwSize;
515
516 Flags &= ~REG_MUI_STRING_TRUNCATE;
517
518 // Try with stack buffer first.
519 lResult = RegLoadMUIStringA(hKey, pszValue, szStackBuffer, _countof(szStackBuffer), &dwSize, Flags, pszDirectory);
520 if (lResult == ERROR_SUCCESS) {
521 // Allocate buffer on heap, copy from stack buffer.
522 LPSTR szBuffer = sOut.GetBuffer(dwSize);
523 if (!szBuffer) return ERROR_OUTOFMEMORY;
524 memcpy(szBuffer, szStackBuffer, dwSize);
525 sOut.ReleaseBuffer(dwSize);
526 } else if (lResult == ERROR_MORE_DATA) {
527 // Allocate buffer on heap and retry.
528 LPSTR szBuffer = sOut.GetBuffer(dwSize);
529 if (!szBuffer) return ERROR_OUTOFMEMORY;
530 sOut.ReleaseBuffer((lResult = RegLoadMUIStringA(hKey, pszValue, szBuffer, dwSize, &dwSize, Flags, pszDirectory)) == ERROR_SUCCESS ? dwSize : 0);
531 }
532
533 return lResult;
534 }
535
536
537 ///
538 /// Loads the specified string from the specified key and subkey, and stores it in a ATL::CAtlStringW string.
539 ///
540 /// \sa [RegLoadMUIString function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724890.aspx)
541 ///
542 inline LSTATUS RegLoadMUIStringW(_In_ HKEY hKey, _In_opt_ LPCWSTR pszValue, _Out_ ATL::CAtlStringW &sOut, _In_ DWORD Flags, _In_opt_ LPCWSTR pszDirectory)
543 {
544 LSTATUS lResult;
545 WCHAR szStackBuffer[ATL_STACK_BUFFER_BYTES/sizeof(WCHAR)];
546 DWORD dwSize;
547
548 Flags &= ~REG_MUI_STRING_TRUNCATE;
549
550 // Try with stack buffer first.
551 lResult = RegLoadMUIStringW(hKey, pszValue, szStackBuffer, _countof(szStackBuffer), &dwSize, Flags, pszDirectory);
552 if (lResult == ERROR_SUCCESS) {
553 // Allocate buffer on heap, copy from stack buffer.
554 LPWSTR szBuffer = sOut.GetBuffer(dwSize);
555 if (!szBuffer) return ERROR_OUTOFMEMORY;
556 wmemcpy(szBuffer, szStackBuffer, dwSize);
557 sOut.ReleaseBuffer(dwSize);
558 } else if (lResult == ERROR_MORE_DATA) {
559 // Allocate buffer on heap and retry.
560 LPWSTR szBuffer = sOut.GetBuffer(dwSize);
561 if (!szBuffer) return ERROR_OUTOFMEMORY;
562 sOut.ReleaseBuffer((lResult = RegLoadMUIStringW(hKey, pszValue, szBuffer, dwSize, &dwSize, Flags, pszDirectory)) == ERROR_SUCCESS ? dwSize : 0);
563 }
564
565 return lResult;
566 }
567
568 #endif
569
570 /// @}
571
572
573 namespace ATL
574 {
575 /// \addtogroup ATLWinAPI
576 /// @{
577
578 ///
579 /// Module handle wrapper
580 ///
581 class CAtlLibrary : public CObjectWithHandleT<HMODULE>
582 {
583 public:
584 ///
585 /// Frees the module.
586 ///
587 /// \sa [FreeLibrary](https://msdn.microsoft.com/en-us/library/windows/desktop/ms683152.aspx)
588 ///
589 virtual ~CAtlLibrary()
590 {
591 if (m_h)
592 FreeLibrary(m_h);
593 }
594
595 ///
596 /// Loads the specified module into the address space of the calling process.
597 ///
598 /// \sa [LoadLibraryEx](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179.aspx)
599 ///
600 inline BOOL Load(_In_ LPCTSTR lpFileName, __reserved HANDLE hFile, _In_ DWORD dwFlags)
601 {
602 HANDLE h = LoadLibraryEx(lpFileName, hFile, dwFlags);
603 if (h) {
604 Attach(h);
605 return TRUE;
606 } else
607 return FALSE;
608 }
609
610 protected:
611 ///
612 /// Frees the module.
613 ///
614 /// \sa [FreeLibrary](https://msdn.microsoft.com/en-us/library/windows/desktop/ms683152.aspx)
615 ///
616 virtual void InternalFree()
617 {
618 FreeLibrary(m_h);
619 }
620 };
621
622 /// @}
623 }