2 Copyright 1991-2017 Amebis
4 This file is part of atlex.
6 Setup 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 3 of the License, or
9 (at your option) any later version.
11 Setup 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.
16 You should have received a copy of the GNU General Public License
17 along with Setup. If not, see <http://www.gnu.org/licenses/>.
28 /// \defgroup ATLWinAPI Windows API
29 /// Integrates ATL classes with Microsoft Windows API
34 /// Retrieves the fully qualified path for the file that contains the specified module and stores it in a ATL::CAtlStringA string.
36 /// \sa [GetModuleFileName function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms683197.aspx)
38 inline DWORD
GetModuleFileNameA(_In_opt_ HMODULE hModule
, _Out_
ATL::CAtlStringA
&sValue
)
43 // Increment size and allocate buffer.
44 LPSTR szBuffer
= sValue
.GetBuffer(dwSize
+= 1024);
46 ::SetLastError(ERROR_OUTOFMEMORY
);
51 DWORD dwResult
= ::GetModuleFileNameA(hModule
, szBuffer
, dwSize
);
54 sValue
.ReleaseBuffer(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.
62 } if (dwLength
< dwSize
) {
63 // Buffer was long enough to get entire string, and has some extra space left.
73 /// Retrieves the fully qualified path for the file that contains the specified module and stores it in a ATL::CAtlStringW string.
75 /// \sa [GetModuleFileName function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms683197.aspx)
77 inline DWORD
GetModuleFileNameW(_In_opt_ HMODULE hModule
, _Out_
ATL::CAtlStringW
&sValue
)
82 // Increment size and allocate buffer.
83 LPWSTR szBuffer
= sValue
.GetBuffer(dwSize
+= 1024);
85 ::SetLastError(ERROR_OUTOFMEMORY
);
90 DWORD dwResult
= ::GetModuleFileNameW(hModule
, szBuffer
, dwSize
);
93 sValue
.ReleaseBuffer(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.
101 } if (dwLength
< dwSize
) {
102 // Buffer was long enough to get entire string, and has some extra space left.
112 /// Copies the text of the specified window's title bar (if it has one) into a ATL::CAtlStringA string.
114 /// \sa [GetWindowText function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633520.aspx)
116 inline int GetWindowTextA(_In_ HWND hWnd
, _Out_
ATL::CAtlStringA
&sValue
)
120 // Query the final string length first.
121 iResult
= ::GetWindowTextLengthA(hWnd
);
123 // Allocate buffer on heap and read the string data into it.
124 LPSTR szBuffer
= sValue
.GetBuffer(iResult
++);
126 SetLastError(ERROR_OUTOFMEMORY
);
129 iResult
= ::GetWindowTextA(hWnd
, szBuffer
, iResult
);
130 sValue
.ReleaseBuffer(iResult
);
133 // The result is empty.
141 /// Copies the text of the specified window's title bar (if it has one) into a ATL::CAtlStringW string.
143 /// \sa [GetWindowText function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633520.aspx)
145 inline int GetWindowTextW(_In_ HWND hWnd
, _Out_
ATL::CAtlStringW
&sValue
)
149 // Query the final string length first.
150 iResult
= ::GetWindowTextLengthW(hWnd
);
152 // Allocate buffer on heap and read the string data into it.
153 LPWSTR szBuffer
= sValue
.GetBuffer(iResult
++);
155 SetLastError(ERROR_OUTOFMEMORY
);
158 iResult
= ::GetWindowTextW(hWnd
, szBuffer
, iResult
);
159 sValue
.ReleaseBuffer(iResult
);
162 // The result is empty.
170 /// Retrieves version information for the specified file and stores it in a ATL::CAtlStringA string.
172 /// \sa [GetFileVersionInfo function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms647003.aspx)
174 inline BOOL
GetFileVersionInfoA(_In_ LPCSTR lptstrFilename
, __reserved DWORD dwHandle
, _Out_
ATL::CAtlArray
<BYTE
> &aValue
)
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());
183 ::SetLastError(ERROR_OUTOFMEMORY
);
192 /// Retrieves version information for the specified file and stores it in a ATL::CAtlStringW string.
194 /// \sa [GetFileVersionInfo function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms647003.aspx)
196 inline BOOL
GetFileVersionInfoW(_In_ LPCWSTR lptstrFilename
, __reserved DWORD dwHandle
, _Out_
ATL::CAtlArray
<BYTE
> &aValue
)
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());
205 ::SetLastError(ERROR_OUTOFMEMORY
);
214 /// Expands environment-variable strings, replaces them with the values defined for the current user, and stores it in a ATL::CAtlStringA string.
216 /// \sa [ExpandEnvironmentStrings function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724265.aspx)
218 inline DWORD
ExpandEnvironmentStringsA(_In_ LPCSTR lpSrc
, ATL::CAtlStringA
&sValue
)
220 DWORD dwBufferSizeEst
= (DWORD
)strlen(lpSrc
) + 0x100; // Initial estimate
223 DWORD dwBufferSize
= dwBufferSizeEst
;
224 LPSTR szBuffer
= sValue
.GetBuffer(dwBufferSize
);
226 ::SetLastError(ERROR_OUTOFMEMORY
);
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) {
235 sValue
.ReleaseBuffer(0);
238 // The buffer was sufficient. Break.
239 sValue
.ReleaseBuffer();
241 return dwBufferSizeEst
;
248 /// Expands environment-variable strings, replaces them with the values defined for the current user, and stores it in a ATL::CAtlStringW string.
250 /// \sa [ExpandEnvironmentStrings function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724265.aspx)
252 inline DWORD
ExpandEnvironmentStringsW(_In_ LPCWSTR lpSrc
, ATL::CAtlStringW
&sValue
)
254 DWORD dwBufferSizeEst
= (DWORD
)wcslen(lpSrc
) + 0x100; // Initial estimate
257 DWORD dwBufferSize
= dwBufferSizeEst
;
258 LPWSTR szBuffer
= sValue
.GetBuffer(dwBufferSize
);
260 ::SetLastError(ERROR_OUTOFMEMORY
);
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) {
269 sValue
.ReleaseBuffer(0);
272 // The buffer was sufficient. Break.
273 sValue
.ReleaseBuffer();
275 return dwBufferSizeEst
;
282 /// Formats GUID and stores it in a ATL::CAtlStringA string.
284 /// \param[in] lpGuid Pointer to GUID
285 /// \param[out] str String to store the result to
287 inline VOID
GuidToString(_In_ LPCGUID lpGuid
, _Out_
ATL::CAtlStringA
&str
)
289 str
.Format("{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
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]);
299 /// Formats GUID and stores it in a ATL::CAtlStringW string.
301 /// \param[in] lpGuid Pointer to GUID
302 /// \param[out] str String to store the result to
304 inline VOID
GuidToString(_In_ LPCGUID lpGuid
, _Out_
ATL::CAtlStringW
&str
)
306 str
.Format(L
"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
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]);
316 /// Queries for a string value in the registry and stores it in a ATL::CAtlStringA string.
318 /// `REG_EXPAND_SZ` are expanded using `ExpandEnvironmentStrings()` before storing to sValue.
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
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)
331 inline LSTATUS
RegQueryStringValue(_In_ HKEY hReg
, _In_z_ LPCSTR pszName
, _Out_
ATL::CAtlStringA
&sValue
)
334 BYTE aStackBuffer
[ATL_STACK_BUFFER_BYTES
];
335 DWORD dwSize
= sizeof(aStackBuffer
), dwType
;
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();
351 // The value is not a string type.
352 lResult
= ERROR_INVALID_DATA
;
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();
362 // Reading of the value failed.
363 sValue
.ReleaseBuffer(0);
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();
372 // The value is not a string type.
373 lResult
= ERROR_INVALID_DATA
;
382 /// Queries for a string value in the registry and stores it in a ATL::CAtlStringW string.
384 /// `REG_EXPAND_SZ` are expanded using `ExpandEnvironmentStrings()` before storing to sValue.
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
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)
397 inline LSTATUS
RegQueryStringValue(_In_ HKEY hReg
, _In_z_ LPCWSTR pszName
, _Out_
ATL::CAtlStringW
&sValue
)
400 BYTE aStackBuffer
[ATL_STACK_BUFFER_BYTES
];
401 DWORD dwSize
= sizeof(aStackBuffer
), dwType
;
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();
417 // The value is not a string type.
418 lResult
= ERROR_INVALID_DATA
;
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();
428 // Reading of the value failed.
429 sValue
.ReleaseBuffer(0);
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();
438 // The value is not a string type.
439 lResult
= ERROR_INVALID_DATA
;
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.
450 /// \sa [RegQueryValueEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724911.aspx)
452 inline LSTATUS
RegQueryValueExA(_In_ HKEY hKey
, _In_opt_ LPCSTR lpValueName
, __reserved LPDWORD lpReserved
, _Out_opt_ LPDWORD lpType
, _Out_
ATL::CAtlArray
<BYTE
> &aData
)
455 BYTE aStackBuffer
[ATL_STACK_BUFFER_BYTES
];
456 DWORD dwSize
= sizeof(aStackBuffer
);
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
)
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.
478 /// \sa [RegQueryValueEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724911.aspx)
480 inline LSTATUS
RegQueryValueExW(_In_ HKEY hKey
, _In_opt_ LPCWSTR lpValueName
, __reserved LPDWORD lpReserved
, _Out_opt_ LPDWORD lpType
, _Out_
ATL::CAtlArray
<BYTE
> &aData
)
483 BYTE aStackBuffer
[ATL_STACK_BUFFER_BYTES
];
484 DWORD dwSize
= sizeof(aStackBuffer
);
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
)
503 #if _WIN32_WINNT >= _WIN32_WINNT_VISTA
506 /// Loads the specified string from the specified key and subkey, and stores it in a ATL::CAtlStringA string.
508 /// \sa [RegLoadMUIString function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724890.aspx)
510 inline LSTATUS
RegLoadMUIStringA(_In_ HKEY hKey
, _In_opt_ LPCSTR pszValue
, _Out_
ATL::CAtlStringA
&sOut
, _In_ DWORD Flags
, _In_opt_ LPCSTR pszDirectory
)
513 CHAR szStackBuffer
[ATL_STACK_BUFFER_BYTES
/sizeof(CHAR
)];
516 Flags
&= ~REG_MUI_STRING_TRUNCATE
;
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);
538 /// Loads the specified string from the specified key and subkey, and stores it in a ATL::CAtlStringW string.
540 /// \sa [RegLoadMUIString function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724890.aspx)
542 inline LSTATUS
RegLoadMUIStringW(_In_ HKEY hKey
, _In_opt_ LPCWSTR pszValue
, _Out_
ATL::CAtlStringW
&sOut
, _In_ DWORD Flags
, _In_opt_ LPCWSTR pszDirectory
)
545 WCHAR szStackBuffer
[ATL_STACK_BUFFER_BYTES
/sizeof(WCHAR
)];
548 Flags
&= ~REG_MUI_STRING_TRUNCATE
;
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);
575 /// \addtogroup ATLWinAPI
579 /// Module handle wrapper
581 class CAtlLibrary
: public CObjectWithHandleT
<HMODULE
>
585 /// Frees the module.
587 /// \sa [FreeLibrary](https://msdn.microsoft.com/en-us/library/windows/desktop/ms683152.aspx)
589 virtual ~CAtlLibrary()
596 /// Loads the specified module into the address space of the calling process.
598 /// \sa [LoadLibraryEx](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179.aspx)
600 inline BOOL
Load(_In_ LPCTSTR lpFileName
, __reserved HANDLE hFile
, _In_ DWORD dwFlags
)
602 HANDLE h
= LoadLibraryEx(lpFileName
, hFile
, dwFlags
);
612 /// Frees the module.
614 /// \sa [FreeLibrary](https://msdn.microsoft.com/en-us/library/windows/desktop/ms683152.aspx)
616 virtual void InternalFree()