From 921aa9f4e944e60ea4c8049d063dba1317831b63 Mon Sep 17 00:00:00 2001 From: Simon Rozman Date: Fri, 4 Feb 2022 11:33:08 +0100 Subject: [PATCH] Discontinue forward declarations They are pain to maintain. We'll use them only if really needed (cyclic dependencies). Signed-off-by: Simon Rozman --- include/WinStd/COM.h | 48 +- include/WinStd/Common.h | 554 ++++------ include/WinStd/Cred.h | 230 ++-- include/WinStd/Crypt.h | 393 +++---- include/WinStd/EAP.h | 148 +-- include/WinStd/ETW.h | 247 ++--- include/WinStd/GDI.h | 27 +- include/WinStd/MSI.h | 133 +-- include/WinStd/Sec.h | 148 +-- include/WinStd/SetupAPI.h | 23 +- include/WinStd/Shell.h | 37 +- include/WinStd/WLAN.h | 81 +- include/WinStd/Win.h | 2203 +++++++++++++++++-------------------- include/WinStd/WinSock2.h | 28 +- include/WinStd/WinTrust.h | 19 +- 15 files changed, 1776 insertions(+), 2543 deletions(-) diff --git a/include/WinStd/COM.h b/include/WinStd/COM.h index 6c66a08e..dbdddc77 100644 --- a/include/WinStd/COM.h +++ b/include/WinStd/COM.h @@ -4,36 +4,15 @@ Copyright © 2016 GÉANT */ -/// -/// \defgroup WinStdCOM COM object management -/// Provides helper templates for Windows COM object manipulation -/// +#pragma once #include "Common.h" - +#include #include namespace winstd { - class com_runtime_error; - struct CoTaskMemFree_delete; - template class com_obj; - class bstr; - class variant; - class com_initializer; -} - -#pragma once - -#include - -namespace winstd -{ - - /// - /// \defgroup WinStdExceptions Exceptions - /// Additional exceptions - /// + /// \addtogroup WinStdExceptions /// @{ /// @@ -54,7 +33,6 @@ namespace winstd { } - /// /// Constructs an exception /// @@ -67,7 +45,11 @@ namespace winstd }; /// @} - /// \addtogroup WinStdCOM + + /// + /// \defgroup WinStdCOM COM object management + /// Provides helper templates for Windows COM object manipulation + /// /// @{ /// @@ -111,7 +93,6 @@ namespace winstd CoCreateInstance(rclsid, pUnkOuter, dwClsContext, __uuidof(T), (LPVOID*)&m_h); } - /// /// Queries the object for another interface and creates new class with it /// @@ -124,7 +105,6 @@ namespace winstd other->QueryInterface(__uuidof(T), (void**)&m_h); } - /// /// Queries the object for another interface and creates new class with it /// @@ -136,7 +116,6 @@ namespace winstd other->QueryInterface(__uuidof(T), (void**)&m_h); } - /// /// Releases object /// @@ -146,7 +125,6 @@ namespace winstd free_internal(); } - /// /// Creates a new object /// @@ -161,7 +139,6 @@ namespace winstd return hr; } - /// /// Queries the object for another interface /// @@ -175,7 +152,6 @@ namespace winstd return m_h->QueryInterface(__uuidof(_Other), (void**)h); } - /// /// Queries the object for another interface /// @@ -203,7 +179,6 @@ namespace winstd m_h->Release(); } - /// /// Duplicates the object by incrementing the reference counter /// @@ -220,7 +195,6 @@ namespace winstd } }; - /// /// BSTR string wrapper /// @@ -301,7 +275,6 @@ namespace winstd } }; - /// /// VARIANT struct wrapper /// @@ -680,7 +653,6 @@ namespace winstd return *this; } - /// /// Copy from long long value /// @@ -1057,7 +1029,6 @@ namespace winstd }; #pragma warning(pop) - /// /// Context scope automatic COM (un)initialization /// @@ -1077,7 +1048,6 @@ namespace winstd m_result = CoInitialize(pvReserved); } - /// /// Initializes the COM library for use by the calling thread, sets the thread's concurrency model, and creates a new apartment for the thread if one is required. /// @@ -1088,7 +1058,6 @@ namespace winstd m_result = CoInitializeEx(pvReserved, dwCoInit); } - /// /// Uninitializes COM. /// @@ -1100,7 +1069,6 @@ namespace winstd CoUninitialize(); } - /// /// Return result of `CoInitialize()` call. /// diff --git a/include/WinStd/Common.h b/include/WinStd/Common.h index 891aeb3d..62885d85 100644 --- a/include/WinStd/Common.h +++ b/include/WinStd/Common.h @@ -4,41 +4,23 @@ Copyright © 2016 GÉANT */ -/// -/// \defgroup WinStdGeneral General -/// General API -/// -/// \defgroup WinStdSysHandles System Handles -/// Simplifies work with object handles of various type -/// -/// \defgroup WinStdExceptions Exceptions -/// Additional exceptions -/// -/// \defgroup WinStdStrFormat String Formatting -/// Formatted string generation -/// -/// \par Example -/// \code -/// // Please note the PCSTR typecasting invokes an operator to return -/// // pointer to formatted buffer rather than class reference itself. -/// cout << (PCSTR)(winstd::string_printf("%i is less than %i.\n", 1, 5)); -/// \endcode -/// -/// \defgroup WinStdMemSanitize Auto-sanitize Memory Management -/// Sanitizes memory before dismissed -/// +#pragma once #define _WINSOCKAPI_ // Prevent inclusion of winsock.h in windows.h. #include - +#include #include - +#include #include #include #include #include +#include -/// \addtogroup WinStdGeneral +/// +/// \defgroup WinStdGeneral General +/// General API +/// /// @{ /// @@ -81,10 +63,35 @@ private: \ C (_Inout_ C &&h) noexcept; \ C& operator=(_Inout_ C &&h) noexcept; +#ifndef WINSTD_STACK_BUFFER_BYTES +/// +/// Size of the stack buffer in bytes used for initial system function call +/// +/// Some system functions with variable length output data fail for +/// insufficient buffer sizes, and return an exact buffer length required. +/// The function helpers use a fixed size stack buffer first. If the stack +/// buffer really prooved sufficient, the helper allocates the exact length +/// output on heap and copies the data without calling the system function +/// again. Otherwise it allocates the exact length output on heap and retries. +/// +/// \note +/// Decrease this value in case of stack overflow. +/// +#define WINSTD_STACK_BUFFER_BYTES 1024 +#endif + /// @} - -/// \addtogroup WinStdStrFormat +/// \defgroup WinStdStrFormat String Formatting +/// Formatted string generation +/// +/// \par Example +/// \code +/// // Please note the PCSTR typecasting invokes an operator to return +/// // pointer to formatted buffer rather than class reference itself. +/// cout << (PCSTR)(winstd::string_printf("%i is less than %i.\n", 1, 5)); +/// \endcode +/// /// @{ /// @@ -119,8 +126,10 @@ private: \ /// @} - -/// \addtogroup WinStdSysHandles +/// +/// \defgroup WinStdSysHandles System Handles +/// Simplifies work with object handles of various type +/// /// @{ /// @@ -151,166 +160,21 @@ private: /// @} - #ifndef _FormatMessage_format_string_ #define _FormatMessage_format_string_ _In_z_ #endif - #ifndef _LPCBYTE_DEFINED #define _LPCBYTE_DEFINED typedef const BYTE *LPCBYTE; #endif - -namespace winstd -{ - /// \addtogroup WinStdStrFormat - /// @{ - - /// - /// Multi-byte / Wide-character string (according to _UNICODE) - /// -#ifdef _UNICODE - typedef std::wstring tstring; -#else - typedef std::string tstring; -#endif - - /// @} - - template struct LocalFree_delete; - template struct LocalFree_delete<_Ty[]>; - template> class ref_unique_ptr; - template class ref_unique_ptr<_Ty[], _Dx>; - template class handle; - template class dplhandle; - template class vector_queue; - template class num_runtime_error; - class win_runtime_error; - - /// \addtogroup WinStdGeneral - /// @{ - - /// - /// Helper function template for returning pointers to std::unique_ptr - /// - /// \param[inout] owner Original owner of the pointer - /// - /// \returns A helper wrapper class to handle returning a reference to the pointer - /// - template ref_unique_ptr<_Ty, _Dx> get_ptr(_Inout_ std::unique_ptr<_Ty, _Dx> &owner) noexcept; - - /// - /// Helper function template for returning pointers to std::unique_ptr - /// (specialization for arrays) - /// - /// \param[inout] owner Original owner of the pointer - /// - /// \returns A helper wrapper class to handle returning a reference to the pointer - /// - template ref_unique_ptr<_Ty[], _Dx> get_ptr(_Inout_ std::unique_ptr<_Ty[], _Dx> &owner) noexcept; - - /// @} - - - /// \addtogroup WinStdStrFormat - /// @{ - - template, class _Ax = std::allocator<_Elem> > class basic_string_printf; - - /// - /// Single-byte character implementation of a class to support string formatting using `printf()` style templates - /// - typedef basic_string_printf, std::allocator > string_printf; - - /// - /// Wide character implementation of a class to support string formatting using `printf()` style templates - /// - typedef basic_string_printf, std::allocator > wstring_printf; - - /// - /// Multi-byte / Wide-character formatted string (according to _UNICODE) - /// -#ifdef _UNICODE - typedef wstring_printf tstring_printf; -#else - typedef string_printf tstring_printf; -#endif - - template, class _Ax = std::allocator<_Elem> > class basic_string_msg; - - /// - /// Single-byte character implementation of a class to support string formatting using `FormatMessage()` style templates - /// - typedef basic_string_msg, std::allocator > string_msg; - - /// - /// Wide character implementation of a class to support string formatting using `FormatMessage()` style templates - /// - typedef basic_string_msg, std::allocator > wstring_msg; - - /// - /// Multi-byte / Wide-character formatted string (according to _UNICODE) - /// -#ifdef _UNICODE - typedef wstring_msg tstring_msg; -#else - typedef string_msg tstring_msg; -#endif - - template, class _Ax = std::allocator<_Elem> > class basic_string_guid; - - class string_guid; - class wstring_guid; - - /// - /// Multi-byte / Wide-character string GUID (according to _UNICODE) - /// -#ifdef _UNICODE - typedef wstring_guid tstring_guid; -#else - typedef string_guid tstring_guid; -#endif - - /// @} - - /// \addtogroup WinStdMemSanitize - /// @{ - - template class sanitizing_allocator; - template class sanitizing_blob; - - - /// - /// A sanitizing variant of std::string - /// - /// \note - /// `sanitizing_string` introduces a performance penalty. However, it provides an additional level of security. - /// Use for security sensitive data memory storage only. - /// - typedef std::basic_string, sanitizing_allocator > sanitizing_string; - - /// - /// A sanitizing variant of std::wstring - /// - /// \note - /// `sanitizing_wstring` introduces a performance penalty. However, it provides an additional level of security. - /// Use for security sensitive data memory storage only. - /// - typedef std::basic_string, sanitizing_allocator > sanitizing_wstring; - - /// - /// Multi-byte / Wide-character sanitizing string (according to _UNICODE) - /// -#ifdef _UNICODE - typedef sanitizing_wstring sanitizing_tstring; -#else - typedef sanitizing_string sanitizing_tstring; -#endif - - /// @} -} +#pragma warning(push) +// Do not use _vsnprintf_s/_vsnwprintf_s(), since it terminates string by force even when we explicitly want to write unterminated string. +// Threfore turn off compiler warning instead. ;) +#pragma warning(disable: 4995) +#pragma warning(disable: 4996) +#pragma warning(disable: 4505) // Don't warn on unused code /// \addtogroup WinStdStrFormat /// @{ @@ -326,7 +190,10 @@ namespace winstd /// \returns Number of characters in result. /// #if _MSC_VER <= 1600 -static int vsnprintf(_Out_z_cap_(capacity) char *str, _In_ size_t capacity, _In_z_ _Printf_format_string_ const char *format, _In_ va_list arg); +static int vsnprintf(_Out_z_cap_(capacity) char *str, _In_ size_t capacity, _In_z_ _Printf_format_string_ const char *format, _In_ va_list arg) +{ + return _vsnprintf(str, capacity, format, arg); +} #endif /// @@ -339,7 +206,10 @@ static int vsnprintf(_Out_z_cap_(capacity) char *str, _In_ size_t capacity, _In_ /// /// \returns Number of characters in result. /// -static int vsnprintf(_Out_z_cap_(capacity) wchar_t *str, _In_ size_t capacity, _In_z_ _Printf_format_string_ const wchar_t *format, _In_ va_list arg) noexcept; +static int vsnprintf(_Out_z_cap_(capacity) wchar_t *str, _In_ size_t capacity, _In_z_ _Printf_format_string_ const wchar_t *format, _In_ va_list arg) noexcept +{ + return _vsnwprintf(str, capacity, format, arg); +} /// /// Formats string using `printf()`. @@ -351,7 +221,29 @@ static int vsnprintf(_Out_z_cap_(capacity) wchar_t *str, _In_ size_t capacity, _ /// \returns Number of characters in result. /// template -static int vsprintf(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_ const _Elem *format, _In_ va_list arg); +static int vsprintf(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_ const _Elem *format, _In_ va_list arg) +{ + _Elem buf[WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem)]; + + // Try with stack buffer first. + int count = vsnprintf(buf, _countof(buf) - 1, format, arg); + if (count >= 0) { + // Copy from stack. + str.assign(buf, count); + } else { + for (size_t capacity = 2*WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem);; capacity *= 2) { + // Allocate on heap and retry. + auto buf_dyn = std::make_unique<_Elem[]>(capacity); + count = vsnprintf(buf_dyn.get(), capacity - 1, format, arg); + if (count >= 0) { + str.assign(buf_dyn.get(), count); + break; + } + } + } + + return count; +} /// /// Formats string using `printf()`. @@ -362,7 +254,14 @@ static int vsprintf(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ /// \returns Number of characters in result. /// template -static int sprintf(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_ const _Elem *format, ...); +static int sprintf(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_ const _Elem *format, ...) +{ + va_list arg; + va_start(arg, format); + const int res = vsprintf(str, format, arg); + va_end(arg); + return res; +} /// /// Formats a message string. @@ -370,7 +269,14 @@ static int sprintf(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _ /// \sa [FormatMessage function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351.aspx) /// template -static DWORD FormatMessage(_In_ DWORD dwFlags, _In_opt_ LPCVOID lpSource, _In_ DWORD dwMessageId, _In_ DWORD dwLanguageId, _Inout_ std::basic_string &str, _In_opt_ va_list *Arguments); +static DWORD FormatMessage(_In_ DWORD dwFlags, _In_opt_ LPCVOID lpSource, _In_ DWORD dwMessageId, _In_ DWORD dwLanguageId, _Inout_ std::basic_string &str, _In_opt_ va_list *Arguments) +{ + std::unique_ptr > lpBuffer; + DWORD dwResult = FormatMessageA(dwFlags | FORMAT_MESSAGE_ALLOCATE_BUFFER, lpSource, dwMessageId, dwLanguageId, reinterpret_cast((LPSTR*)get_ptr(lpBuffer)), 0, Arguments); + if (dwResult) + str.assign(lpBuffer.get(), dwResult); + return dwResult; +} /// /// Formats a message string. @@ -378,47 +284,33 @@ static DWORD FormatMessage(_In_ DWORD dwFlags, _In_opt_ LPCVOID lpSource, _In_ D /// \sa [FormatMessage function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351.aspx) /// template -static DWORD FormatMessage(_In_ DWORD dwFlags, _In_opt_ LPCVOID lpSource, _In_ DWORD dwMessageId, _In_ DWORD dwLanguageId, _Inout_ std::basic_string &str, _In_opt_ va_list *Arguments); - -/// @} - -#pragma once - -#include -#include - -#include -#include - - -/// \addtogroup WinStdGeneral -/// @{ - -#ifndef WINSTD_STACK_BUFFER_BYTES -/// -/// Size of the stack buffer in bytes used for initial system function call -/// -/// Some system functions with variable length output data fail for -/// insufficient buffer sizes, and return an exact buffer length required. -/// The function helpers use a fixed size stack buffer first. If the stack -/// buffer really prooved sufficient, the helper allocates the exact length -/// output on heap and copies the data without calling the system function -/// again. Otherwise it allocates the exact length output on heap and retries. -/// -/// \note -/// Decrease this value in case of stack overflow. -/// -#define WINSTD_STACK_BUFFER_BYTES 1024 -#endif +static DWORD FormatMessage(_In_ DWORD dwFlags, _In_opt_ LPCVOID lpSource, _In_ DWORD dwMessageId, _In_ DWORD dwLanguageId, _Inout_ std::basic_string &str, _In_opt_ va_list *Arguments) +{ + std::unique_ptr > lpBuffer; + DWORD dwResult = FormatMessageW(dwFlags | FORMAT_MESSAGE_ALLOCATE_BUFFER, lpSource, dwMessageId, dwLanguageId, reinterpret_cast((LPWSTR*)get_ptr(lpBuffer)), 0, Arguments); + if (dwResult) + str.assign(lpBuffer.get(), dwResult); + return dwResult; +} /// @} +#pragma warning(pop) namespace winstd { /// \addtogroup WinStdGeneral /// @{ + /// + /// Multi-byte / Wide-character string (according to _UNICODE) + /// +#ifdef _UNICODE + typedef std::wstring tstring; +#else + typedef std::string tstring; +#endif + /// /// Deleter for unique_ptr using LocalFree /// @@ -448,7 +340,6 @@ namespace winstd } }; - /// /// Deleter for unique_ptr to array of unknown size using LocalFree /// @@ -482,7 +373,6 @@ namespace winstd } }; - /// /// Helper class for returning pointers to std::unique_ptr /// @@ -546,6 +436,32 @@ namespace winstd _Ty *m_ptr; ///< Pointer }; + /// + /// Helper function template for returning pointers to std::unique_ptr + /// + /// \param[inout] owner Original owner of the pointer + /// + /// \returns A helper wrapper class to handle returning a reference to the pointer + /// + template + ref_unique_ptr<_Ty, _Dx> get_ptr(_Inout_ std::unique_ptr<_Ty, _Dx> &owner) noexcept + { + return ref_unique_ptr<_Ty, _Dx>(owner); + } + + /// + /// Helper function template for returning pointers to std::unique_ptr + /// (specialization for arrays) + /// + /// \param[inout] owner Original owner of the pointer + /// + /// \returns A helper wrapper class to handle returning a reference to the pointer + /// + template + ref_unique_ptr<_Ty[], _Dx> get_ptr(_Inout_ std::unique_ptr<_Ty[], _Dx> &owner) noexcept + { + return ref_unique_ptr<_Ty[], _Dx>(owner); + } /// /// Helper class for returning pointers to std::unique_ptr @@ -649,21 +565,8 @@ namespace winstd }; #pragma warning(pop) - template - ref_unique_ptr<_Ty, _Dx> get_ptr(_Inout_ std::unique_ptr<_Ty, _Dx> &owner) noexcept - { - return ref_unique_ptr<_Ty, _Dx>(owner); - } - - template - ref_unique_ptr<_Ty[], _Dx> get_ptr(_Inout_ std::unique_ptr<_Ty[], _Dx> &owner) noexcept - { - return ref_unique_ptr<_Ty[], _Dx>(owner); - } - /// @} - /// \addtogroup WinStdSysHandles /// @{ @@ -930,11 +833,9 @@ namespace winstd handle_type m_h; ///< Object handle }; - template const T handle::invalid = INVAL; - /// /// Base abstract template class to support object handle keeping for objects that support handle duplication /// @@ -1475,7 +1376,10 @@ namespace winstd /// @} - /// \addtogroup WinStdExceptions + /// + /// \defgroup WinStdExceptions Exceptions + /// Additional exceptions + /// /// @{ /// @@ -1500,7 +1404,6 @@ namespace winstd { } - /// /// Constructs an exception /// @@ -1513,7 +1416,6 @@ namespace winstd { } - /// /// Returns the Windows error number /// @@ -1526,7 +1428,6 @@ namespace winstd error_type m_num; ///< Numeric error code }; - /// /// Windows runtime error /// @@ -1543,7 +1444,6 @@ namespace winstd { } - /// /// Constructs an exception /// @@ -1554,7 +1454,6 @@ namespace winstd { } - /// /// Constructs an exception using `GetLastError()` /// @@ -1564,7 +1463,6 @@ namespace winstd { } - /// /// Constructs an exception using `GetLastError()` /// @@ -1574,7 +1472,6 @@ namespace winstd { } - /// /// Returns a user-readable Windows error message /// @@ -1663,6 +1560,24 @@ namespace winstd /// }@ }; + /// + /// Single-byte character implementation of a class to support string formatting using `printf()` style templates + /// + typedef basic_string_printf, std::allocator > string_printf; + + /// + /// Wide character implementation of a class to support string formatting using `printf()` style templates + /// + typedef basic_string_printf, std::allocator > wstring_printf; + + /// + /// Multi-byte / Wide-character formatted string (according to _UNICODE) + /// +#ifdef _UNICODE + typedef wstring_printf tstring_printf; +#else + typedef string_printf tstring_printf; +#endif /// /// Base template class to support string formatting using `FormatMessage()` style templates @@ -1729,7 +1644,6 @@ namespace winstd /// @} - /// /// Initializes a new string and formats its contents using `FormatMessage()` style. /// @@ -1740,7 +1654,6 @@ namespace winstd FormatMessage(dwFlags & ~FORMAT_MESSAGE_ARGUMENT_ARRAY, lpSource, dwMessageId, dwLanguageId, *this, Arguments); } - /// /// Initializes a new string and formats its contents using `FormatMessage()` style. /// @@ -1751,7 +1664,6 @@ namespace winstd FormatMessage(dwFlags | FORMAT_MESSAGE_ARGUMENT_ARRAY, lpSource, dwMessageId, dwLanguageId, *this, (va_list*)Arguments); } - /// /// Initializes a new string and formats its contents using `FormatMessage()` style. /// @@ -1762,7 +1674,6 @@ namespace winstd FormatMessage(dwFlags & ~FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_STRING, pszFormat, 0, 0, *this, Arguments); } - /// /// Initializes a new string and formats its contents using `FormatMessage()` style. /// @@ -1774,6 +1685,24 @@ namespace winstd } }; + /// + /// Single-byte character implementation of a class to support string formatting using `FormatMessage()` style templates + /// + typedef basic_string_msg, std::allocator > string_msg; + + /// + /// Wide character implementation of a class to support string formatting using `FormatMessage()` style templates + /// + typedef basic_string_msg, std::allocator > wstring_msg; + + /// + /// Multi-byte / Wide-character formatted string (according to _UNICODE) + /// +#ifdef _UNICODE + typedef wstring_msg tstring_msg; +#else + typedef string_msg tstring_msg; +#endif /// /// Base template class to support converting GUID to string @@ -1804,7 +1733,6 @@ namespace winstd /// @} }; - /// /// Single-byte character implementation of a class to support converting GUID to string /// @@ -1827,7 +1755,6 @@ namespace winstd /// @} }; - /// /// Wide character implementation of a class to support converting GUID to string /// @@ -1850,9 +1777,21 @@ namespace winstd /// @} }; + /// + /// Multi-byte / Wide-character string GUID (according to _UNICODE) + /// +#ifdef _UNICODE + typedef wstring_guid tstring_guid; +#else + typedef string_guid tstring_guid; +#endif + /// @} - /// \addtogroup WinStdMemSanitize + /// + /// \defgroup WinStdMemSanitize Auto-sanitize Memory Management + /// Sanitizes memory before dismissed + /// /// @{ // winstd::sanitizing_allocator::destroy() member generates _Ptr parameter not used warning for primitive datatypes _Ty. @@ -1881,7 +1820,6 @@ namespace winstd typedef sanitizing_allocator<_Other> other; ///< Other type }; - /// /// Construct default allocator /// @@ -1889,7 +1827,6 @@ namespace winstd { } - /// /// Construct by copying /// @@ -1897,7 +1834,6 @@ namespace winstd { } - /// /// Construct from a related allocator /// @@ -1906,7 +1842,6 @@ namespace winstd { } - /// /// Deallocate object at _Ptr sanitizing its content first /// @@ -1920,6 +1855,33 @@ namespace winstd #pragma warning(pop) + /// + /// A sanitizing variant of std::string + /// + /// \note + /// `sanitizing_string` introduces a performance penalty. However, it provides an additional level of security. + /// Use for security sensitive data memory storage only. + /// + typedef std::basic_string, sanitizing_allocator > sanitizing_string; + + /// + /// A sanitizing variant of std::wstring + /// + /// \note + /// `sanitizing_wstring` introduces a performance penalty. However, it provides an additional level of security. + /// Use for security sensitive data memory storage only. + /// + typedef std::basic_string, sanitizing_allocator > sanitizing_wstring; + + /// + /// Multi-byte / Wide-character sanitizing string (according to _UNICODE) + /// +#ifdef _UNICODE + typedef sanitizing_wstring sanitizing_tstring; +#else + typedef sanitizing_string sanitizing_tstring; +#endif + /// /// Sanitizing BLOB /// @@ -1949,87 +1911,3 @@ namespace winstd /// @} } - - -#pragma warning(push) -// Do not use _vsnprintf_s/_vsnwprintf_s(), since it terminates string by force even when we explicitly want to write unterminated string. -// Threfore turn off compiler warning instead. ;) -#pragma warning(disable: 4995) -#pragma warning(disable: 4996) -#pragma warning(disable: 4505) // Don't warn on unused code - -#if _MSC_VER <= 1600 - -static int vsnprintf(_Out_z_cap_(capacity) char *str, _In_ size_t capacity, _In_z_ _Printf_format_string_ const char *format, _In_ va_list arg) -{ - return _vsnprintf(str, capacity, format, arg); -} - -#endif - - -static int vsnprintf(_Out_z_cap_(capacity) wchar_t *str, _In_ size_t capacity, _In_z_ _Printf_format_string_ const wchar_t *format, _In_ va_list arg) noexcept -{ - return _vsnwprintf(str, capacity, format, arg); -} - - -template -static int vsprintf(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_ const _Elem *format, _In_ va_list arg) -{ - _Elem buf[WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem)]; - - // Try with stack buffer first. - int count = vsnprintf(buf, _countof(buf) - 1, format, arg); - if (count >= 0) { - // Copy from stack. - str.assign(buf, count); - } else { - for (size_t capacity = 2*WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem);; capacity *= 2) { - // Allocate on heap and retry. - auto buf_dyn = std::make_unique<_Elem[]>(capacity); - count = vsnprintf(buf_dyn.get(), capacity - 1, format, arg); - if (count >= 0) { - str.assign(buf_dyn.get(), count); - break; - } - } - } - - return count; -} - - -template -static int sprintf(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_ const _Elem *format, ...) -{ - va_list arg; - va_start(arg, format); - const int res = vsprintf(str, format, arg); - va_end(arg); - return res; -} - - -template -static DWORD FormatMessage(_In_ DWORD dwFlags, _In_opt_ LPCVOID lpSource, _In_ DWORD dwMessageId, _In_ DWORD dwLanguageId, _Inout_ std::basic_string &str, _In_opt_ va_list *Arguments) -{ - std::unique_ptr > lpBuffer; - DWORD dwResult = FormatMessageA(dwFlags | FORMAT_MESSAGE_ALLOCATE_BUFFER, lpSource, dwMessageId, dwLanguageId, reinterpret_cast((LPSTR*)get_ptr(lpBuffer)), 0, Arguments); - if (dwResult) - str.assign(lpBuffer.get(), dwResult); - return dwResult; -} - - -template -static DWORD FormatMessage(_In_ DWORD dwFlags, _In_opt_ LPCVOID lpSource, _In_ DWORD dwMessageId, _In_ DWORD dwLanguageId, _Inout_ std::basic_string &str, _In_opt_ va_list *Arguments) -{ - std::unique_ptr > lpBuffer; - DWORD dwResult = FormatMessageW(dwFlags | FORMAT_MESSAGE_ALLOCATE_BUFFER, lpSource, dwMessageId, dwLanguageId, reinterpret_cast((LPWSTR*)get_ptr(lpBuffer)), 0, Arguments); - if (dwResult) - str.assign(lpBuffer.get(), dwResult); - return dwResult; -} - -#pragma warning(pop) diff --git a/include/WinStd/Cred.h b/include/WinStd/Cred.h index ce647ba1..b3ee9328 100644 --- a/include/WinStd/Cred.h +++ b/include/WinStd/Cred.h @@ -4,37 +4,41 @@ Copyright © 2016 GÉANT */ -/// -/// \defgroup WinStdCryptoAPI Cryptography API -/// Integrates WinStd classes with Microsoft Cryptography API -/// +#pragma once #include "Common.h" - #include - #include -namespace winstd -{ - template struct CredFree_delete; - template struct CredFree_delete<_Ty[]>; -} - - -/// \addtogroup WinStdCryptoAPI +/// +/// \defgroup WinStdCredAPI Credentials API +/// Integrates WinStd classes with Microsoft Credentials API +/// /// @{ -/// -/// Enumerates the credentials from the user's credential set. The credential set used is the one associated with the logon session of the current token. The token must not have the user's SID disabled. -/// -/// \sa [CredEnumerate function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa374794.aspx) -/// -static BOOL CredEnumerate(_In_z_ LPCTSTR Filter, _Reserved_ DWORD Flags, _Out_ DWORD *Count, _Inout_ std::unique_ptr > &cCredentials) noexcept; - /// @copydoc CredProtectW() template -static BOOL CredProtectA(_In_ BOOL fAsSelf, _In_count_(cchCredentials) LPCSTR pszCredentials, _In_ DWORD cchCredentials, _Inout_ std::basic_string &sProtectedCredentials, _Out_ CRED_PROTECTION_TYPE *ProtectionType); +static BOOL CredProtectA(_In_ BOOL fAsSelf, _In_count_(cchCredentials) LPCSTR pszCredentials, _In_ DWORD cchCredentials, _Inout_ std::basic_string &sProtectedCredentials, _Out_ CRED_PROTECTION_TYPE *ProtectionType) +{ + char buf[WINSTD_STACK_BUFFER_BYTES/sizeof(char)]; + DWORD dwSize = _countof(buf); + + // Try with the stack buffer first. + if (CredProtectA(fAsSelf, const_cast(pszCredentials), cchCredentials, buf, &dwSize, ProtectionType)) { + // Copy from stack. + sProtectedCredentials.assign(buf, dwSize - 1); + return TRUE; + } else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + // Allocate on heap and retry. + std::unique_ptr buf(new char[dwSize]); + if (CredProtectA(fAsSelf, const_cast(pszCredentials), cchCredentials, buf.get(), &dwSize, ProtectionType)) { + sProtectedCredentials.assign(buf.get(), dwSize - 1); + return TRUE; + } + } + + return FALSE; +} /// /// Encrypts the specified credentials so that only the current security context can decrypt them. @@ -42,11 +46,51 @@ static BOOL CredProtectA(_In_ BOOL fAsSelf, _In_count_(cchCredentials) LPCSTR ps /// \sa [CredProtect function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa374803.aspx) /// template -static BOOL CredProtectW(_In_ BOOL fAsSelf, _In_count_(cchCredentials) LPCWSTR pszCredentials, _In_ DWORD cchCredentials, _Inout_ std::basic_string &sProtectedCredentials, _Out_ CRED_PROTECTION_TYPE *ProtectionType); +static BOOL CredProtectW(_In_ BOOL fAsSelf, _In_count_(cchCredentials) LPCWSTR pszCredentials, _In_ DWORD cchCredentials, _Inout_ std::basic_string &sProtectedCredentials, _Out_ CRED_PROTECTION_TYPE *ProtectionType) +{ + wchar_t buf[WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t)]; + DWORD dwSize = _countof(buf); + + // Try with the stack buffer first. + if (CredProtectW(fAsSelf, const_cast(pszCredentials), cchCredentials, buf, &dwSize, ProtectionType)) { + // Copy from stack. + sProtectedCredentials.assign(buf, dwSize - 1); + return TRUE; + } else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + // Allocate on heap and retry. + std::unique_ptr buf(new wchar_t[dwSize]); + if (CredProtectW(fAsSelf, const_cast(pszCredentials), cchCredentials, buf.get(), &dwSize, ProtectionType)) { + sProtectedCredentials.assign(buf.get(), dwSize - 1); + return TRUE; + } + } + + return FALSE; +} /// @copydoc CredUnprotectW() template -static BOOL CredUnprotectA(_In_ BOOL fAsSelf, _In_count_(cchCredentials) LPCSTR pszProtectedCredentials, _In_ DWORD cchCredentials, _Inout_ std::basic_string &sCredentials); +static BOOL CredUnprotectA(_In_ BOOL fAsSelf, _In_count_(cchCredentials) LPCSTR pszProtectedCredentials, _In_ DWORD cchCredentials, _Inout_ std::basic_string &sCredentials) +{ + char buf[WINSTD_STACK_BUFFER_BYTES/sizeof(char)]; + DWORD dwSize = _countof(buf); + + // Try with the stack buffer first. + if (CredUnprotectA(fAsSelf, const_cast(pszProtectedCredentials), cchCredentials, buf, &dwSize)) { + // Copy from stack. + sCredentials.assign(buf, dwSize); + return TRUE; + } else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + // Allocate on heap and retry. + std::unique_ptr buf(new char[dwSize]); + if (CredUnprotectA(fAsSelf, const_cast(pszProtectedCredentials), cchCredentials, buf.get(), &dwSize)) { + sCredentials.assign(buf.get(), dwSize); + return TRUE; + } + } + + return FALSE; +} /// /// Decrypts credentials that were previously encrypted by using the CredProtect function. @@ -54,16 +98,33 @@ static BOOL CredUnprotectA(_In_ BOOL fAsSelf, _In_count_(cchCredentials) LPCSTR /// \sa [CredUnprotect function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa375186.aspx) /// template -static BOOL CredUnprotectW(_In_ BOOL fAsSelf, _In_count_(cchCredentials) LPCWSTR pszProtectedCredentials, _In_ DWORD cchCredentials, _Inout_ std::basic_string &sCredentials); +static BOOL CredUnprotectW(_In_ BOOL fAsSelf, _In_count_(cchCredentials) LPCWSTR pszProtectedCredentials, _In_ DWORD cchCredentials, _Inout_ std::basic_string &sCredentials) +{ + wchar_t buf[WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t)]; + DWORD dwSize = _countof(buf); + + // Try with the stack buffer first. + if (CredUnprotectW(fAsSelf, const_cast(pszProtectedCredentials), cchCredentials, buf, &dwSize)) { + // Copy from stack. + sCredentials.assign(buf, dwSize); + return TRUE; + } else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + // Allocate on heap and retry. + std::unique_ptr buf(new wchar_t[dwSize]); + if (CredUnprotectW(fAsSelf, const_cast(pszProtectedCredentials), cchCredentials, buf.get(), &dwSize)) { + sCredentials.assign(buf.get(), dwSize); + return TRUE; + } + } + + return FALSE; +} /// @} -#pragma once - - namespace winstd { - /// \addtogroup WinStdCryptoAPI + /// \addtogroup WinStdCredAPI /// @{ /// @@ -94,7 +155,6 @@ namespace winstd } }; - /// /// Deleter for unique_ptr to array of unknown size using CredFree /// @@ -132,11 +192,15 @@ namespace winstd /// @} } +/// \addtogroup WinStdCredAPI +/// @{ -#pragma warning(push) -#pragma warning(disable: 4505) // Don't warn on unused code - - +/// +/// Enumerates the credentials from the user's credential set. The credential set used is the one associated with the logon session of the current token. The token must not have the user's SID disabled. +/// +/// \sa [CredEnumerate function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa374794.aspx) +/// +#pragma warning(suppress: 4505) // Don't warn on unused code static BOOL CredEnumerate(_In_z_ LPCTSTR Filter, _Reserved_ DWORD Flags, _Out_ DWORD *Count, _Inout_ std::unique_ptr > &cCredentials) noexcept { PCREDENTIAL *pCredentials; @@ -148,100 +212,4 @@ static BOOL CredEnumerate(_In_z_ LPCTSTR Filter, _Reserved_ DWORD Flags, _Out_ D return FALSE; } - -template -static BOOL CredProtectA(_In_ BOOL fAsSelf, _In_count_(cchCredentials) LPCSTR pszCredentials, _In_ DWORD cchCredentials, _Inout_ std::basic_string &sProtectedCredentials, _Out_ CRED_PROTECTION_TYPE *ProtectionType) -{ - char buf[WINSTD_STACK_BUFFER_BYTES/sizeof(char)]; - DWORD dwSize = _countof(buf); - - // Try with the stack buffer first. - if (CredProtectA(fAsSelf, const_cast(pszCredentials), cchCredentials, buf, &dwSize, ProtectionType)) { - // Copy from stack. - sProtectedCredentials.assign(buf, dwSize - 1); - return TRUE; - } else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - // Allocate on heap and retry. - std::unique_ptr buf(new char[dwSize]); - if (CredProtectA(fAsSelf, const_cast(pszCredentials), cchCredentials, buf.get(), &dwSize, ProtectionType)) { - sProtectedCredentials.assign(buf.get(), dwSize - 1); - return TRUE; - } - } - - return FALSE; -} - - -template -static BOOL CredProtectW(_In_ BOOL fAsSelf, _In_count_(cchCredentials) LPCWSTR pszCredentials, _In_ DWORD cchCredentials, _Inout_ std::basic_string &sProtectedCredentials, _Out_ CRED_PROTECTION_TYPE *ProtectionType) -{ - wchar_t buf[WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t)]; - DWORD dwSize = _countof(buf); - - // Try with the stack buffer first. - if (CredProtectW(fAsSelf, const_cast(pszCredentials), cchCredentials, buf, &dwSize, ProtectionType)) { - // Copy from stack. - sProtectedCredentials.assign(buf, dwSize - 1); - return TRUE; - } else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - // Allocate on heap and retry. - std::unique_ptr buf(new wchar_t[dwSize]); - if (CredProtectW(fAsSelf, const_cast(pszCredentials), cchCredentials, buf.get(), &dwSize, ProtectionType)) { - sProtectedCredentials.assign(buf.get(), dwSize - 1); - return TRUE; - } - } - - return FALSE; -} - - -template -static BOOL CredUnprotectA(_In_ BOOL fAsSelf, _In_count_(cchCredentials) LPCSTR pszProtectedCredentials, _In_ DWORD cchCredentials, _Inout_ std::basic_string &sCredentials) -{ - char buf[WINSTD_STACK_BUFFER_BYTES/sizeof(char)]; - DWORD dwSize = _countof(buf); - - // Try with the stack buffer first. - if (CredUnprotectA(fAsSelf, const_cast(pszProtectedCredentials), cchCredentials, buf, &dwSize)) { - // Copy from stack. - sCredentials.assign(buf, dwSize); - return TRUE; - } else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - // Allocate on heap and retry. - std::unique_ptr buf(new char[dwSize]); - if (CredUnprotectA(fAsSelf, const_cast(pszProtectedCredentials), cchCredentials, buf.get(), &dwSize)) { - sCredentials.assign(buf.get(), dwSize); - return TRUE; - } - } - - return FALSE; -} - - -template -static BOOL CredUnprotectW(_In_ BOOL fAsSelf, _In_count_(cchCredentials) LPCWSTR pszProtectedCredentials, _In_ DWORD cchCredentials, _Inout_ std::basic_string &sCredentials) -{ - wchar_t buf[WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t)]; - DWORD dwSize = _countof(buf); - - // Try with the stack buffer first. - if (CredUnprotectW(fAsSelf, const_cast(pszProtectedCredentials), cchCredentials, buf, &dwSize)) { - // Copy from stack. - sCredentials.assign(buf, dwSize); - return TRUE; - } else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - // Allocate on heap and retry. - std::unique_ptr buf(new wchar_t[dwSize]); - if (CredUnprotectW(fAsSelf, const_cast(pszProtectedCredentials), cchCredentials, buf.get(), &dwSize)) { - sCredentials.assign(buf.get(), dwSize); - return TRUE; - } - } - - return FALSE; -} - -#pragma warning(pop) +/// @} diff --git a/include/WinStd/Crypt.h b/include/WinStd/Crypt.h index 4e7395a5..5c51de9f 100644 --- a/include/WinStd/Crypt.h +++ b/include/WinStd/Crypt.h @@ -4,35 +4,34 @@ Copyright © 2016 GÉANT */ +#pragma once + +#include "Common.h" +#include +#include +#include +#include +#include + /// /// \defgroup WinStdCryptoAPI Cryptography API /// Integrates WinStd classes with Microsoft Cryptography API /// - -#include "Common.h" - -#include - -#include -#include - -namespace winstd -{ - class cert_context; - class cert_chain_context; - class cert_store; - class crypt_prov; - class crypt_hash; - class crypt_key; - class data_blob; -} - -/// \addtogroup WinStdCryptoAPI /// @{ /// @copydoc CertGetNameStringW() template -static DWORD CertGetNameStringA(_In_ PCCERT_CONTEXT pCertContext, _In_ DWORD dwType, _In_ DWORD dwFlags, _In_opt_ void *pvTypePara, _Out_ std::basic_string &sNameString); +static DWORD CertGetNameStringA(_In_ PCCERT_CONTEXT pCertContext, _In_ DWORD dwType, _In_ DWORD dwFlags, _In_opt_ void *pvTypePara, _Out_ std::basic_string &sNameString) +{ + // Query the final string length first. + DWORD dwSize = ::CertGetNameStringA(pCertContext, dwType, dwFlags, pvTypePara, NULL, 0); + + // Allocate buffer on heap to format the string data into and read it. + std::unique_ptr szBuffer(new char[dwSize]); + dwSize = ::CertGetNameStringA(pCertContext, dwType, dwFlags, pvTypePara, szBuffer.get(), dwSize); + sNameString.assign(szBuffer.get(), dwSize - 1); + return dwSize; +} /// /// Obtains the subject or issuer name from a certificate [CERT_CONTEXT](https://msdn.microsoft.com/en-us/library/windows/desktop/aa377189.aspx) structure and stores it in a std::wstring string. @@ -40,7 +39,17 @@ static DWORD CertGetNameStringA(_In_ PCCERT_CONTEXT pCertContext, _In_ DWORD dwT /// \sa [CertGetNameString function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376086.aspx) /// template -static DWORD CertGetNameStringW(_In_ PCCERT_CONTEXT pCertContext, _In_ DWORD dwType, _In_ DWORD dwFlags, _In_opt_ void *pvTypePara, _Out_ std::basic_string &sNameString); +static DWORD CertGetNameStringW(_In_ PCCERT_CONTEXT pCertContext, _In_ DWORD dwType, _In_ DWORD dwFlags, _In_opt_ void *pvTypePara, _Out_ std::basic_string &sNameString) +{ + // Query the final string length first. + DWORD dwSize = ::CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara, NULL, 0); + + // Allocate buffer on heap to format the string data into and read it. + std::unique_ptr szBuffer(new wchar_t[dwSize]); + dwSize = ::CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara, szBuffer.get(), dwSize); + sNameString.assign(szBuffer.get(), dwSize - 1); + return dwSize; +} /// /// Retrieves the information contained in an extended property of a certificate context. @@ -48,7 +57,24 @@ static DWORD CertGetNameStringW(_In_ PCCERT_CONTEXT pCertContext, _In_ DWORD dwT /// \sa [CertGetCertificateContextProperty function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376079.aspx) /// template -static _Success_(return != 0) BOOL WINAPI CertGetCertificateContextProperty(_In_ PCCERT_CONTEXT pCertContext, _In_ DWORD dwPropId, _Out_ std::vector<_Ty, _Ax> &aData); +static _Success_(return != 0) BOOL WINAPI CertGetCertificateContextProperty(_In_ PCCERT_CONTEXT pCertContext, _In_ DWORD dwPropId, _Out_ std::vector<_Ty, _Ax> &aData) +{ + BYTE buf[WINSTD_STACK_BUFFER_BYTES]; + DWORD dwSize = WINSTD_STACK_BUFFER_BYTES; + + // Try with the stack buffer first. + if (CertGetCertificateContextProperty(pCertContext, dwPropId, buf, &dwSize)) { + // Copy from stack. + aData.assign((const _Ty*)buf, (const _Ty*)buf + (dwSize + sizeof(_Ty) - 1) / sizeof(_Ty)); + return TRUE; + } else if (GetLastError() == ERROR_MORE_DATA) { + aData.resize((dwSize + sizeof(_Ty) - 1) / sizeof(_Ty)); + if (CertGetCertificateContextProperty(pCertContext, dwPropId, (BYTE*)aData.data(), &dwSize)) + return TRUE; + } + + return FALSE; +} /// /// Retrieves data that governs the operations of a hash object. The actual hash value can be retrieved by using this function. @@ -56,7 +82,36 @@ static _Success_(return != 0) BOOL WINAPI CertGetCertificateContextProperty(_In_ /// \sa [CryptGetHashParam function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379947.aspx) /// template -static _Success_(return != 0) BOOL CryptGetHashParam(_In_ HCRYPTHASH hHash, _In_ DWORD dwParam, _Out_ std::vector<_Ty, _Ax> &aData, _In_ DWORD dwFlags); +static _Success_(return != 0) BOOL CryptGetHashParam(_In_ HCRYPTHASH hHash, _In_ DWORD dwParam, _Out_ std::vector<_Ty, _Ax> &aData, _In_ DWORD dwFlags) +{ + BYTE buf[WINSTD_STACK_BUFFER_BYTES]; + DWORD dwSize = WINSTD_STACK_BUFFER_BYTES; + + // Try with the stack buffer first. + if (CryptGetHashParam(hHash, dwParam, buf, &dwSize, dwFlags)) { + // Copy from stack. + aData.assign((const _Ty*)buf, (const _Ty*)buf + (dwSize + sizeof(_Ty) - 1) / sizeof(_Ty)); + return TRUE; + } else if (GetLastError() == ERROR_MORE_DATA) { + aData.resize((dwSize + sizeof(_Ty) - 1) / sizeof(_Ty)); + if (CryptGetHashParam(hHash, dwParam, (BYTE*)aData.data(), &dwSize, dwFlags)) + return TRUE; + } + + return FALSE; +} + +/// +/// Retrieves data that governs the operations of a hash object. The actual hash value can be retrieved by using this function. +/// +/// \sa [CryptGetHashParam function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379947.aspx) +/// +template +static _Success_(return != 0) BOOL CryptGetHashParam(_In_ HCRYPTHASH hHash, _In_ DWORD dwParam, _Out_ T &data, _In_ DWORD dwFlags) +{ + DWORD dwSize = sizeof(T); + return CryptGetHashParam(hHash, dwParam, (BYTE*)&data, &dwSize, dwFlags); +} /// /// Retrieves data that governs the operations of a key. @@ -64,7 +119,24 @@ static _Success_(return != 0) BOOL CryptGetHashParam(_In_ HCRYPTHASH hHash, _In_ /// \sa [CryptGetKeyParam function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379949.aspx) /// template -static _Success_(return != 0) BOOL CryptGetKeyParam(_In_ HCRYPTKEY hKey, _In_ DWORD dwParam, _Out_ std::vector<_Ty, _Ax> &aData, _In_ DWORD dwFlags); +static _Success_(return != 0) BOOL CryptGetKeyParam(_In_ HCRYPTKEY hKey, _In_ DWORD dwParam, _Out_ std::vector<_Ty, _Ax> &aData, _In_ DWORD dwFlags) +{ + BYTE buf[WINSTD_STACK_BUFFER_BYTES]; + DWORD dwSize = WINSTD_STACK_BUFFER_BYTES; + + // Try with the stack buffer first. + if (CryptGetKeyParam(hKey, dwParam, buf, &dwSize, dwFlags)) { + // Copy from stack. + aData.assign((const _Ty*)buf, (const _Ty*)buf + (dwSize + sizeof(_Ty) - 1) / sizeof(_Ty)); + return TRUE; + } else if (GetLastError() == ERROR_MORE_DATA) { + aData.resize((dwSize + sizeof(_Ty) - 1) / sizeof(_Ty)); + if (CryptGetKeyParam(hKey, dwParam, (BYTE*)aData.data(), &dwSize, dwFlags)) + return TRUE; + } + + return FALSE; +} /// /// Retrieves data that governs the operations of a key. @@ -72,7 +144,11 @@ static _Success_(return != 0) BOOL CryptGetKeyParam(_In_ HCRYPTKEY hKey, _In_ DW /// \sa [CryptGetKeyParam function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379949.aspx) /// template -static _Success_(return != 0) BOOL CryptGetKeyParam(_In_ HCRYPTKEY hKey, _In_ DWORD dwParam, _Out_ T &data, _In_ DWORD dwFlags); +static BOOL CryptGetKeyParam(_In_ HCRYPTKEY hKey, _In_ DWORD dwParam, _Out_ T &data, _In_ DWORD dwFlags) +{ + DWORD dwSize = sizeof(T); + return CryptGetKeyParam(hKey, dwParam, (BYTE*)&data, &dwSize, dwFlags); +} /// /// Exports a cryptographic key or a key pair from a cryptographic service provider (CSP) in a secure manner. @@ -80,7 +156,18 @@ static _Success_(return != 0) BOOL CryptGetKeyParam(_In_ HCRYPTKEY hKey, _In_ DW /// \sa [CryptExportKey function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379931.aspx) /// template -static _Success_(return != 0) BOOL CryptExportKey(_In_ HCRYPTKEY hKey, _In_ HCRYPTKEY hExpKey, _In_ DWORD dwBlobType, _In_ DWORD dwFlags, _Out_ std::vector<_Ty, _Ax> &aData); +static _Success_(return != 0) BOOL CryptExportKey(_In_ HCRYPTKEY hKey, _In_ HCRYPTKEY hExpKey, _In_ DWORD dwBlobType, _In_ DWORD dwFlags, _Out_ std::vector<_Ty, _Ax> &aData) +{ + DWORD dwKeyBLOBSize = 0; + + if (CryptExportKey(hKey, hExpKey, dwBlobType, dwFlags, NULL, &dwKeyBLOBSize)) { + aData.resize((dwKeyBLOBSize + sizeof(_Ty) - 1) / sizeof(_Ty)); + if (CryptExportKey(hKey, hExpKey, dwBlobType, dwFlags, aData.data(), &dwKeyBLOBSize)) + return TRUE; + } + + return FALSE; +} /// /// Encrypts data. @@ -88,7 +175,49 @@ static _Success_(return != 0) BOOL CryptExportKey(_In_ HCRYPTKEY hKey, _In_ HCRY /// \sa [CryptEncrypt function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379924.aspx) /// template -static _Success_(return != 0) BOOL CryptEncrypt(_In_ HCRYPTKEY hKey, _In_opt_ HCRYPTHASH hHash, _In_ BOOL Final, _In_ DWORD dwFlags, _Inout_ std::vector<_Ty, _Ax> &aData); +static _Success_(return != 0) BOOL CryptEncrypt(_In_ HCRYPTKEY hKey, _In_opt_ HCRYPTHASH hHash, _In_ BOOL Final, _In_ DWORD dwFlags, _Inout_ std::vector<_Ty, _Ax> &aData) +{ + DWORD + dwDataLen = (DWORD)(aData.size() * sizeof(_Ty)), + dwBufLen = (DWORD)(aData.capacity() * sizeof(_Ty)), + dwEncLen = dwDataLen, + dwResult; + + if (dwBufLen) { + aData.resize(dwBufLen); + if (CryptEncrypt(hKey, hHash, Final, dwFlags, (BYTE*)aData.data(), &dwEncLen, dwBufLen)) { + // Encryption succeeded. + assert(dwEncLen <= dwBufLen); + if (dwEncLen < dwBufLen) + aData.resize((dwEncLen + sizeof(_Ty) - 1) / sizeof(_Ty)); + return TRUE; + } else + dwResult = GetLastError(); + } else if (CryptEncrypt(hKey, NULL, Final, dwFlags, NULL, &dwEncLen, 0)) { + // CryptEncrypt() always succeeds for output data size queries. + // dwEncLen contains required output data size. Continue as if the buffer was to small. Actually, the output buffer _was_ too small! + dwResult = ERROR_MORE_DATA; + } else + dwResult = GetLastError(); + + if (dwResult == ERROR_MORE_DATA) { + // Encrypted data will be longer. Reserve more space and retry. + aData.resize(((dwBufLen = dwEncLen) + sizeof(_Ty) - 1) / sizeof(_Ty)); + dwEncLen = dwDataLen; + if (CryptEncrypt(hKey, hHash, Final, dwFlags, (BYTE*)aData.data(), &dwEncLen, dwBufLen)) { + // Encryption succeeded. + assert(dwEncLen <= dwBufLen); + if (dwEncLen < dwBufLen) + aData.resize((dwEncLen + sizeof(_Ty) - 1) / sizeof(_Ty)); + return TRUE; + } + } else { + // Resize back to data length. + aData.resize((dwDataLen + sizeof(_Ty) - 1) / sizeof(_Ty)); + } + + return FALSE; +} /// /// Decrypts data previously encrypted by using the CryptEncrypt function. @@ -96,17 +225,21 @@ static _Success_(return != 0) BOOL CryptEncrypt(_In_ HCRYPTKEY hKey, _In_opt_ HC /// \sa [CryptDecrypt function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379913.aspx) /// template -static _Success_(return != 0) BOOL CryptDecrypt(_In_ HCRYPTKEY hKey, _In_opt_ HCRYPTHASH hHash, _In_ BOOL Final, _In_ DWORD dwFlags, _Inout_ std::vector<_Ty, _Ax> &aData); +static _Success_(return != 0) BOOL CryptDecrypt(_In_ HCRYPTKEY hKey, _In_opt_ HCRYPTHASH hHash, _In_ BOOL Final, _In_ DWORD dwFlags, _Inout_ std::vector<_Ty, _Ax> &aData) +{ + DWORD dwDataLen = (DWORD)(aData.size() * sizeof(_Ty)); + + if (CryptDecrypt(hKey, hHash, Final, dwFlags, (BYTE*)aData.data(), &dwDataLen)) { + // Decryption succeeded. + aData.resize((dwDataLen + sizeof(_Ty) - 1) / sizeof(_Ty)); + return TRUE; + } + + return FALSE; +} /// @} -#pragma once - -#include - -#include - - namespace winstd { /// \addtogroup WinStdCryptoAPI @@ -261,7 +394,6 @@ namespace winstd } }; - /// /// PCCERT_CHAIN_CONTEXT wrapper class /// @@ -326,7 +458,6 @@ namespace winstd } }; - /// /// HCERTSTORE wrapper class /// @@ -396,7 +527,6 @@ namespace winstd } }; - /// /// HCRYPTPROV wrapper class /// @@ -447,7 +577,6 @@ namespace winstd } }; - /// /// HCRYPTHASH wrapper class /// @@ -513,7 +642,6 @@ namespace winstd } }; - /// /// HCRYPTKEY wrapper class /// @@ -815,186 +943,3 @@ namespace winstd /// @} } - - -template -static DWORD CertGetNameStringA(_In_ PCCERT_CONTEXT pCertContext, _In_ DWORD dwType, _In_ DWORD dwFlags, _In_opt_ void *pvTypePara, _Out_ std::basic_string &sNameString) -{ - // Query the final string length first. - DWORD dwSize = ::CertGetNameStringA(pCertContext, dwType, dwFlags, pvTypePara, NULL, 0); - - // Allocate buffer on heap to format the string data into and read it. - std::unique_ptr szBuffer(new char[dwSize]); - dwSize = ::CertGetNameStringA(pCertContext, dwType, dwFlags, pvTypePara, szBuffer.get(), dwSize); - sNameString.assign(szBuffer.get(), dwSize - 1); - return dwSize; -} - - -template -static DWORD CertGetNameStringW(_In_ PCCERT_CONTEXT pCertContext, _In_ DWORD dwType, _In_ DWORD dwFlags, _In_opt_ void *pvTypePara, _Out_ std::basic_string &sNameString) -{ - // Query the final string length first. - DWORD dwSize = ::CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara, NULL, 0); - - // Allocate buffer on heap to format the string data into and read it. - std::unique_ptr szBuffer(new wchar_t[dwSize]); - dwSize = ::CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara, szBuffer.get(), dwSize); - sNameString.assign(szBuffer.get(), dwSize - 1); - return dwSize; -} - - -template -static _Success_(return != 0) BOOL WINAPI CertGetCertificateContextProperty(_In_ PCCERT_CONTEXT pCertContext, _In_ DWORD dwPropId, _Out_ std::vector<_Ty, _Ax> &aData) -{ - BYTE buf[WINSTD_STACK_BUFFER_BYTES]; - DWORD dwSize = WINSTD_STACK_BUFFER_BYTES; - - // Try with the stack buffer first. - if (CertGetCertificateContextProperty(pCertContext, dwPropId, buf, &dwSize)) { - // Copy from stack. - aData.assign((const _Ty*)buf, (const _Ty*)buf + (dwSize + sizeof(_Ty) - 1) / sizeof(_Ty)); - return TRUE; - } else if (GetLastError() == ERROR_MORE_DATA) { - aData.resize((dwSize + sizeof(_Ty) - 1) / sizeof(_Ty)); - if (CertGetCertificateContextProperty(pCertContext, dwPropId, (BYTE*)aData.data(), &dwSize)) - return TRUE; - } - - return FALSE; -} - - -template -static _Success_(return != 0) BOOL CryptGetHashParam(_In_ HCRYPTHASH hHash, _In_ DWORD dwParam, _Out_ std::vector<_Ty, _Ax> &aData, _In_ DWORD dwFlags) -{ - BYTE buf[WINSTD_STACK_BUFFER_BYTES]; - DWORD dwSize = WINSTD_STACK_BUFFER_BYTES; - - // Try with the stack buffer first. - if (CryptGetHashParam(hHash, dwParam, buf, &dwSize, dwFlags)) { - // Copy from stack. - aData.assign((const _Ty*)buf, (const _Ty*)buf + (dwSize + sizeof(_Ty) - 1) / sizeof(_Ty)); - return TRUE; - } else if (GetLastError() == ERROR_MORE_DATA) { - aData.resize((dwSize + sizeof(_Ty) - 1) / sizeof(_Ty)); - if (CryptGetHashParam(hHash, dwParam, (BYTE*)aData.data(), &dwSize, dwFlags)) - return TRUE; - } - - return FALSE; -} - - -template -static BOOL CryptGetHashParam(_In_ HCRYPTHASH hHash, _In_ DWORD dwParam, _Out_ T &data, _In_ DWORD dwFlags) -{ - DWORD dwSize = sizeof(T); - return CryptGetHashParam(hHash, dwParam, (BYTE*)&data, &dwSize, dwFlags); -} - - -template -static _Success_(return != 0) BOOL CryptGetKeyParam(_In_ HCRYPTKEY hKey, _In_ DWORD dwParam, _Out_ std::vector<_Ty, _Ax> &aData, _In_ DWORD dwFlags) -{ - BYTE buf[WINSTD_STACK_BUFFER_BYTES]; - DWORD dwSize = WINSTD_STACK_BUFFER_BYTES; - - // Try with the stack buffer first. - if (CryptGetKeyParam(hKey, dwParam, buf, &dwSize, dwFlags)) { - // Copy from stack. - aData.assign((const _Ty*)buf, (const _Ty*)buf + (dwSize + sizeof(_Ty) - 1) / sizeof(_Ty)); - return TRUE; - } else if (GetLastError() == ERROR_MORE_DATA) { - aData.resize((dwSize + sizeof(_Ty) - 1) / sizeof(_Ty)); - if (CryptGetKeyParam(hKey, dwParam, (BYTE*)aData.data(), &dwSize, dwFlags)) - return TRUE; - } - - return FALSE; -} - - -template -static BOOL CryptGetKeyParam(_In_ HCRYPTKEY hKey, _In_ DWORD dwParam, _Out_ T &data, _In_ DWORD dwFlags) -{ - DWORD dwSize = sizeof(T); - return CryptGetKeyParam(hKey, dwParam, (BYTE*)&data, &dwSize, dwFlags); -} - - -template -static _Success_(return != 0) BOOL CryptExportKey(_In_ HCRYPTKEY hKey, _In_ HCRYPTKEY hExpKey, _In_ DWORD dwBlobType, _In_ DWORD dwFlags, _Out_ std::vector<_Ty, _Ax> &aData) -{ - DWORD dwKeyBLOBSize = 0; - - if (CryptExportKey(hKey, hExpKey, dwBlobType, dwFlags, NULL, &dwKeyBLOBSize)) { - aData.resize((dwKeyBLOBSize + sizeof(_Ty) - 1) / sizeof(_Ty)); - if (CryptExportKey(hKey, hExpKey, dwBlobType, dwFlags, aData.data(), &dwKeyBLOBSize)) - return TRUE; - } - - return FALSE; -} - - -template -static _Success_(return != 0) BOOL CryptEncrypt(_In_ HCRYPTKEY hKey, _In_opt_ HCRYPTHASH hHash, _In_ BOOL Final, _In_ DWORD dwFlags, _Inout_ std::vector<_Ty, _Ax> &aData) -{ - DWORD - dwDataLen = (DWORD)(aData.size() * sizeof(_Ty)), - dwBufLen = (DWORD)(aData.capacity() * sizeof(_Ty)), - dwEncLen = dwDataLen, - dwResult; - - if (dwBufLen) { - aData.resize(dwBufLen); - if (CryptEncrypt(hKey, hHash, Final, dwFlags, (BYTE*)aData.data(), &dwEncLen, dwBufLen)) { - // Encryption succeeded. - assert(dwEncLen <= dwBufLen); - if (dwEncLen < dwBufLen) - aData.resize((dwEncLen + sizeof(_Ty) - 1) / sizeof(_Ty)); - return TRUE; - } else - dwResult = GetLastError(); - } else if (CryptEncrypt(hKey, NULL, Final, dwFlags, NULL, &dwEncLen, 0)) { - // CryptEncrypt() always succeeds for output data size queries. - // dwEncLen contains required output data size. Continue as if the buffer was to small. Actually, the output buffer _was_ too small! - dwResult = ERROR_MORE_DATA; - } else - dwResult = GetLastError(); - - if (dwResult == ERROR_MORE_DATA) { - // Encrypted data will be longer. Reserve more space and retry. - aData.resize(((dwBufLen = dwEncLen) + sizeof(_Ty) - 1) / sizeof(_Ty)); - dwEncLen = dwDataLen; - if (CryptEncrypt(hKey, hHash, Final, dwFlags, (BYTE*)aData.data(), &dwEncLen, dwBufLen)) { - // Encryption succeeded. - assert(dwEncLen <= dwBufLen); - if (dwEncLen < dwBufLen) - aData.resize((dwEncLen + sizeof(_Ty) - 1) / sizeof(_Ty)); - return TRUE; - } - } else { - // Resize back to data length. - aData.resize((dwDataLen + sizeof(_Ty) - 1) / sizeof(_Ty)); - } - - return FALSE; -} - - -template -static _Success_(return != 0) BOOL CryptDecrypt(_In_ HCRYPTKEY hKey, _In_opt_ HCRYPTHASH hHash, _In_ BOOL Final, _In_ DWORD dwFlags, _Inout_ std::vector<_Ty, _Ax> &aData) -{ - DWORD dwDataLen = (DWORD)(aData.size() * sizeof(_Ty)); - - if (CryptDecrypt(hKey, hHash, Final, dwFlags, (BYTE*)aData.data(), &dwDataLen)) { - // Decryption succeeded. - aData.resize((dwDataLen + sizeof(_Ty) - 1) / sizeof(_Ty)); - return TRUE; - } - - return FALSE; -} diff --git a/include/WinStd/EAP.h b/include/WinStd/EAP.h index 9a8b3cba..72a01025 100644 --- a/include/WinStd/EAP.h +++ b/include/WinStd/EAP.h @@ -4,59 +4,27 @@ Copyright © 2016 GÉANT */ +#pragma once + +#include "Common.h" +#include +#include +#include +#include +#include +#include +#include + +#pragma warning(push) +#pragma warning(disable: 26812) // Windows EAP API is using unscoped enums + +#pragma warning(push) +#pragma warning(disable: 4505) // Don't warn on unused code + /// /// \defgroup WinStdEAPAPI Extensible Authentication Protocol API /// Integrates WinStd classes with Microsoft EAP API /// - -#include "Common.h" - -#include -#include - -#include - -namespace winstd -{ - enum class eap_type_t : unsigned char; - struct EapHostPeerFreeMemory_delete; - struct EapHostPeerFreeRuntimeMemory_delete; - struct EapHostPeerFreeErrorMemory_delete; - struct EapHostPeerFreeEapError_delete; - class eap_attr; - class eap_method_prop; - class eap_packet; - class eap_method_info_array; - class eap_runtime_error; - - /// \addtogroup WinStdEAPAPI - /// @{ - - /// - /// EapHost BLOB wrapper class - /// - typedef std::unique_ptr eap_blob; - - /// - /// EapHost BLOB wrapper class - /// - typedef std::unique_ptr eap_blob_runtime; - - /// - /// EAP_ERROR wrapper class - /// - typedef std::unique_ptr eap_error; - - /// - /// EAP_ERROR wrapper class - /// - typedef std::unique_ptr eap_error_runtime; - - /// @} -} - - -/// \addtogroup WinStdEAPAPI /// @{ /// @@ -69,7 +37,14 @@ namespace winstd /// - Non zero when \p a is equal to \p b; /// - Zero otherwise. /// -static bool operator==(_In_ const EAP_METHOD_TYPE &a, _In_ const EAP_METHOD_TYPE &b) noexcept; +static bool operator==(_In_ const EAP_METHOD_TYPE &a, _In_ const EAP_METHOD_TYPE &b) noexcept +{ + return + a.eapType.type == b.eapType.type && + a.eapType.dwVendorId == b.eapType.dwVendorId && + a.eapType.dwVendorType == b.eapType.dwVendorType && + a.dwAuthorId == a.dwAuthorId; +} /// /// Are EAP method types non-equal? @@ -81,19 +56,14 @@ static bool operator==(_In_ const EAP_METHOD_TYPE &a, _In_ const EAP_METHOD_TYPE /// - Non zero when \p a is not equal to \p b; /// - Zero otherwise. /// -static bool operator!=(_In_ const EAP_METHOD_TYPE &a, _In_ const EAP_METHOD_TYPE &b) noexcept; +static bool operator!=(_In_ const EAP_METHOD_TYPE &a, _In_ const EAP_METHOD_TYPE &b) noexcept +{ + return !operator==(a, b); +} /// @} -#pragma once - -#include -#include -#include -#include - -#pragma warning(push) -#pragma warning(disable: 26812) // Windows EAP API is using unscoped enums +#pragma warning(pop) namespace winstd { @@ -131,7 +101,6 @@ namespace winstd noneap_end = 254, ///< End of non-EAP methods (non-inclusive) }; - /// /// Deleter for unique_ptr using EapHostPeerFreeMemory /// @@ -154,6 +123,10 @@ namespace winstd } }; + /// + /// EapHost BLOB wrapper class + /// + typedef std::unique_ptr eap_blob; /// /// Deleter for unique_ptr using EapHostPeerFreeRuntimeMemory @@ -175,6 +148,10 @@ namespace winstd } }; + /// + /// EapHost BLOB wrapper class + /// + typedef std::unique_ptr eap_blob_runtime; /// /// Deleter for unique_ptr to EAP_ERROR using EapHostPeerFreeErrorMemory @@ -197,6 +174,10 @@ namespace winstd } }; + /// + /// EAP_ERROR wrapper class + /// + typedef std::unique_ptr eap_error; /// /// Deleter for unique_ptr to EAP_ERROR using EapHostPeerFreeEapError @@ -219,6 +200,10 @@ namespace winstd } }; + /// + /// EAP_ERROR wrapper class + /// + typedef std::unique_ptr eap_error_runtime; /// /// EAP_ATTRIBUTE wrapper class @@ -371,7 +356,6 @@ namespace winstd /// static const EAP_ATTRIBUTE blank_eap_attr = {}; - /// /// EAP_METHOD_PROPERTY wrapper class /// @@ -392,7 +376,6 @@ namespace winstd eapMethodPropertyValue.empvBool.value = value; } - /// /// Constructs a DWORD method property /// @@ -407,7 +390,6 @@ namespace winstd eapMethodPropertyValue.empvDword.value = value; } - /// /// Constructs a Unicode string method property /// @@ -423,7 +405,6 @@ namespace winstd } }; - /// /// EapPacket wrapper class /// @@ -441,7 +422,6 @@ namespace winstd free_internal(); } - /// /// Create new EAP packet /// @@ -473,7 +453,6 @@ namespace winstd } } - /// /// Returns total EAP packet size in bytes. /// @@ -482,7 +461,6 @@ namespace winstd return m_h != NULL ? ntohs(*(WORD*)m_h->Length) : 0; } - protected: /// /// Destroys the EAP packet. @@ -508,7 +486,6 @@ namespace winstd } }; - /// /// EAP_METHOD_INFO_ARRAY wrapper class /// @@ -591,10 +568,7 @@ namespace winstd /// @} - /// - /// \defgroup WinStdExceptions Exceptions - /// Additional exceptions - /// + /// \addtogroup WinStdExceptions /// @{ /// @@ -623,7 +597,6 @@ namespace winstd { } - /// /// Constructs an exception /// @@ -642,7 +615,6 @@ namespace winstd { } - /// /// Returns EAP method type /// @@ -651,7 +623,6 @@ namespace winstd return m_type; } - /// /// Returns the reason code for error /// @@ -660,7 +631,6 @@ namespace winstd return m_reason; } - /// /// Returns root cause ID /// @@ -669,7 +639,6 @@ namespace winstd return m_root_cause_id; } - /// /// Returns root cause ID /// @@ -678,7 +647,6 @@ namespace winstd return m_root_cause_desc.c_str(); } - /// /// Returns repair ID /// @@ -687,7 +655,6 @@ namespace winstd return m_repair_id; } - /// /// Returns root cause ID /// @@ -696,7 +663,6 @@ namespace winstd return m_repair_desc.c_str(); } - /// /// Returns help_link ID /// @@ -722,24 +688,4 @@ namespace winstd /// @} } - -#pragma warning(push) -#pragma warning(disable: 4505) // Don't warn on unused code - -static bool operator==(_In_ const EAP_METHOD_TYPE &a, _In_ const EAP_METHOD_TYPE &b) noexcept -{ - return - a.eapType.type == b.eapType.type && - a.eapType.dwVendorId == b.eapType.dwVendorId && - a.eapType.dwVendorType == b.eapType.dwVendorType && - a.dwAuthorId == a.dwAuthorId; -} - - -static bool operator!=(_In_ const EAP_METHOD_TYPE &a, _In_ const EAP_METHOD_TYPE &b) noexcept -{ - return !operator==(a, b); -} - -#pragma warning(pop) #pragma warning(pop) diff --git a/include/WinStd/ETW.h b/include/WinStd/ETW.h index 171f2631..e3c89464 100644 --- a/include/WinStd/ETW.h +++ b/include/WinStd/ETW.h @@ -4,64 +4,108 @@ Copyright © 2016 GÉANT */ -/// -/// \defgroup WinStdETWAPI Event Tracing for Windows API -/// Integrates WinStd classes with Event Tracing for Windows API -/// +#pragma once #include "Common.h" - #include #include #include #include #include - #include #include #include -namespace winstd -{ - class event_data; - class event_rec; - class event_provider; - class event_session; - class event_trace; - class event_trace_enabler; - class event_fn_auto; - template class event_fn_auto_ret; -} +#pragma warning(push) +#pragma warning(disable: 4505) // Don't warn on unused code -/// \addtogroup WinStdCryptoAPI +/// +/// \defgroup WinStdETWAPI Event Tracing for Windows API +/// Integrates WinStd classes with Event Tracing for Windows API +/// /// @{ -/// -/// Retrieves metadata about an event. -/// -/// \sa [TdhGetEventInformation function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa964840.aspx) -/// -static _Success_(return == ERROR_SUCCESS) ULONG TdhGetEventInformation(_In_ PEVENT_RECORD pEvent, _In_ ULONG TdhContextCount, _In_reads_opt_(TdhContextCount) PTDH_CONTEXT pTdhContext, _Out_ std::unique_ptr &info); - -/// -/// Retrieves information about the event map contained in the event. -/// -/// \sa [TdhGetEventMapInformation function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa964841.aspx) -/// -static _Success_(return == ERROR_SUCCESS) ULONG TdhGetEventMapInformation(_In_ PEVENT_RECORD pEvent, _In_ LPWSTR pMapName, _Inout_ std::unique_ptr &info); - /// /// Retrieves a property value from the event data. /// /// \sa [TdhGetProperty function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa964843.aspx) /// template -static _Success_(return == ERROR_SUCCESS) ULONG TdhGetProperty(_In_ PEVENT_RECORD pEvent, _In_ ULONG TdhContextCount, _In_reads_opt_(TdhContextCount) PTDH_CONTEXT pTdhContext, _In_ ULONG PropertyDataCount, _In_reads_(PropertyDataCount) PPROPERTY_DATA_DESCRIPTOR pPropertyData, _Inout_ std::vector<_Ty, _Ax> &aData); +static _Success_(return == ERROR_SUCCESS) ULONG TdhGetProperty(_In_ PEVENT_RECORD pEvent, _In_ ULONG TdhContextCount, _In_reads_opt_(TdhContextCount) PTDH_CONTEXT pTdhContext, _In_ ULONG PropertyDataCount, _In_reads_(PropertyDataCount) PPROPERTY_DATA_DESCRIPTOR pPropertyData, _Inout_ std::vector<_Ty, _Ax> &aData) +{ + ULONG ulSize, ulResult; + + // Query property size. + ulResult = TdhGetPropertySize(pEvent, TdhContextCount, pTdhContext, PropertyDataCount, pPropertyData, &ulSize); + if (ulResult == ERROR_SUCCESS) { + if (ulSize) { + // Query property value. + aData.resize((ulSize + sizeof(_Ty) - 1) / sizeof(_Ty)); + ulResult = TdhGetProperty(pEvent, TdhContextCount, pTdhContext, PropertyDataCount, pPropertyData, ulSize, reinterpret_cast(aData.data())); + } else { + // Property value size is zero. + aData.clear(); + } + } + + return ulResult; +} + +/// +/// Retrieves metadata about an event. +/// +/// \sa [TdhGetEventInformation function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa964840.aspx) +/// +static _Success_(return == ERROR_SUCCESS) ULONG TdhGetEventInformation(_In_ PEVENT_RECORD pEvent, _In_ ULONG TdhContextCount, _In_reads_opt_(TdhContextCount) PTDH_CONTEXT pTdhContext, _Out_ std::unique_ptr &info) +{ + BYTE szBuffer[WINSTD_STACK_BUFFER_BYTES]; + ULONG ulSize = sizeof(szBuffer), ulResult; + + // Try with stack buffer first. + ulResult = TdhGetEventInformation(pEvent, TdhContextCount, pTdhContext, (PTRACE_EVENT_INFO)szBuffer, &ulSize); + if (ulResult == ERROR_SUCCESS) { + // Copy from stack. + info.reset(reinterpret_cast(new char[ulSize])); + memcpy(info.get(), szBuffer, ulSize); + return ERROR_SUCCESS; + } else if (ulResult == ERROR_INSUFFICIENT_BUFFER) { + // Create buffer on heap and retry. + info.reset(reinterpret_cast(new char[ulSize])); + return TdhGetEventInformation(pEvent, TdhContextCount, pTdhContext, info.get(), &ulSize); + } + + return ulResult; +} + +/// +/// Retrieves information about the event map contained in the event. +/// +/// \sa [TdhGetEventMapInformation function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa964841.aspx) +/// +static _Success_(return == ERROR_SUCCESS) ULONG TdhGetEventMapInformation(_In_ PEVENT_RECORD pEvent, _In_ LPWSTR pMapName, _Inout_ std::unique_ptr &info) +{ + BYTE szBuffer[WINSTD_STACK_BUFFER_BYTES]; + ULONG ulSize = sizeof(szBuffer), ulResult; + + // Try with stack buffer first. + ulResult = TdhGetEventMapInformation(pEvent, pMapName, (PEVENT_MAP_INFO)szBuffer, &ulSize); + if (ulResult == ERROR_SUCCESS) { + // Copy from stack. + info.reset(reinterpret_cast(new char[ulSize])); + memcpy(info.get(), szBuffer, ulSize); + return ERROR_SUCCESS; + } else if (ulResult == ERROR_INSUFFICIENT_BUFFER) { + // Create buffer on heap and retry. + info.reset(reinterpret_cast(new char[ulSize])); + return TdhGetEventMapInformation(pEvent, pMapName, info.get(), &ulSize); + } + + return ulResult; +} /// @} -#pragma once - +#pragma warning(pop) namespace winstd { @@ -84,7 +128,6 @@ namespace winstd Reserved = (ULONG)-1; // Used for varadic argument terminator. } - /// /// Construct class pointing to an `char`. /// @@ -98,7 +141,6 @@ namespace winstd EventDataDescCreate(this, &data, (ULONG)(sizeof(data))); } - /// /// Construct class pointing to an `unsigned char`. /// @@ -112,7 +154,6 @@ namespace winstd EventDataDescCreate(this, &data, (ULONG)(sizeof(data))); } - /// /// Construct class pointing to an `int`. /// @@ -126,7 +167,6 @@ namespace winstd EventDataDescCreate(this, &data, (ULONG)(sizeof(data))); } - /// /// Construct class pointing to an `unsigned int`. /// @@ -140,7 +180,6 @@ namespace winstd EventDataDescCreate(this, &data, (ULONG)(sizeof(data))); } - /// /// Construct class pointing to a `long`. /// @@ -154,7 +193,6 @@ namespace winstd EventDataDescCreate(this, &data, (ULONG)(sizeof(data))); } - /// /// Construct class pointing to an `unsigned long`. /// @@ -168,7 +206,6 @@ namespace winstd EventDataDescCreate(this, &data, (ULONG)(sizeof(data))); } - /// /// Construct class pointing to a `GUID`. /// @@ -182,7 +219,6 @@ namespace winstd EventDataDescCreate(this, &data, (ULONG)(sizeof(data))); } - /// /// Construct class pointing to a string. /// @@ -202,7 +238,6 @@ namespace winstd } } - /// /// Construct class pointing to a wide string. /// @@ -222,7 +257,6 @@ namespace winstd } } - /// /// Template to construct pointing to a `std::basic_string<>`. /// @@ -237,7 +271,6 @@ namespace winstd EventDataDescCreate(this, data.c_str(), (ULONG)((data.length() + 1) * sizeof(_Elem))); } - /// /// Construct class pointing to binary data. /// @@ -258,7 +291,6 @@ namespace winstd /// static const event_data blank_event_data; - /// /// EVENT_RECORD wrapper /// @@ -273,7 +305,6 @@ namespace winstd memset((EVENT_RECORD*)this, 0, sizeof(EVENT_RECORD)); } - /// /// Copies an existing event record. /// @@ -285,7 +316,6 @@ namespace winstd set_user_data_internal(other.UserDataLength, other.UserData); } - /// /// Copies an existing event record. /// @@ -297,7 +327,6 @@ namespace winstd set_user_data_internal(other.UserDataLength, other.UserData); } - /// /// Moves the event record. /// @@ -308,7 +337,6 @@ namespace winstd memset((EVENT_RECORD*)&other, 0, sizeof(EVENT_RECORD)); } - /// /// Destroys event record data and frees the allocated memory. /// @@ -321,7 +349,6 @@ namespace winstd delete reinterpret_cast(UserData); } - /// /// Copies an existing event record. /// @@ -338,7 +365,6 @@ namespace winstd return *this; } - /// /// Copies an existing event record. /// @@ -355,7 +381,6 @@ namespace winstd return *this; } - /// /// Moves the event record. /// @@ -371,7 +396,6 @@ namespace winstd return *this; } - /// /// Sets event record extended data. /// @@ -386,7 +410,6 @@ namespace winstd set_extended_data_internal(count, data); } - /// /// Sets event record user data. /// @@ -463,7 +486,6 @@ namespace winstd } }; - /// /// ETW event provider /// @@ -483,7 +505,6 @@ namespace winstd free_internal(); } - /// /// Registers the event provider. /// @@ -502,7 +523,6 @@ namespace winstd return ulRes; } - /// /// Writes an event with no parameters. /// @@ -518,7 +538,6 @@ namespace winstd return EventWrite(m_h, EventDescriptor, 0, NULL); } - /// /// Writes an event with parameters stored in array. /// @@ -534,7 +553,6 @@ namespace winstd return EventWrite(m_h, EventDescriptor, UserDataCount, UserData); } - /// /// Writes an event with one or more parameter. /// @@ -589,7 +607,6 @@ namespace winstd #pragma warning(pop) } - /// /// Writes an event with variable number of parameters. /// @@ -634,7 +651,6 @@ namespace winstd #pragma warning(pop) } - /// /// Writes a string event. /// @@ -671,7 +687,6 @@ namespace winstd EventUnregister(m_h); } - /// /// Receive enable or disable notification requests /// @@ -687,7 +702,6 @@ namespace winstd UNREFERENCED_PARAMETER(FilterData); } - /// /// Receive enable or disable notification requests /// @@ -702,7 +716,6 @@ namespace winstd } }; - /// /// ETW session /// @@ -718,7 +731,6 @@ namespace winstd { } - /// /// Initializes a new session with an already available object handle. /// @@ -732,7 +744,6 @@ namespace winstd memcpy(m_prop.get(), prop, prop->Wnode.BufferSize); } - /// /// Move constructor /// @@ -744,7 +755,6 @@ namespace winstd { } - /// /// Closes the session. /// @@ -756,7 +766,6 @@ namespace winstd free_internal(); } - /// /// Move assignment /// @@ -771,7 +780,6 @@ namespace winstd return *this; } - /// /// Auto-typecasting operator /// @@ -782,7 +790,6 @@ namespace winstd return m_prop.get(); } - /// /// Auto-typecasting operator /// @@ -794,7 +801,6 @@ namespace winstd return reinterpret_cast(reinterpret_cast(prop) + prop->LoggerNameOffset); } - /// /// Sets a new session handle for the class /// @@ -809,7 +815,6 @@ namespace winstd m_prop.reset(prop); } - /// /// Registers and starts an event tracing session. /// @@ -830,7 +835,6 @@ namespace winstd return ulRes; } - /// /// Enables the specified event trace provider. /// @@ -855,7 +859,6 @@ namespace winstd EnableFilterDesc); } - /// /// Disables the specified event trace provider. /// @@ -880,7 +883,6 @@ namespace winstd EnableFilterDesc); } - protected: /// /// Releases the session. @@ -896,7 +898,6 @@ namespace winstd std::unique_ptr m_prop; ///< Session properties }; - /// /// ETW trace /// @@ -916,7 +917,6 @@ namespace winstd free_internal(); } - /// /// Opens a real-time trace session or log file for consuming. /// @@ -948,7 +948,6 @@ namespace winstd } }; - /// /// Helper class to enable event provider in constructor and disables it in destructor /// @@ -990,7 +989,6 @@ namespace winstd m_enable_filter_desc); } - /// /// Enables event trace /// @@ -1025,7 +1023,6 @@ namespace winstd m_enable_filter_desc); } - /// /// Return result of `EnableTraceEx()` call. /// @@ -1036,7 +1033,6 @@ namespace winstd return m_status; } - /// /// Disables event trace. /// @@ -1069,7 +1065,6 @@ namespace winstd PEVENT_FILTER_DESCRIPTOR m_enable_filter_desc; ///< Event filter descriptor }; - /// /// Helper class to write an event on entry/exit of scope. /// @@ -1089,7 +1084,6 @@ namespace winstd m_ep.write(event_cons, 1, &m_fn_name); } - /// /// Copies the object /// @@ -1100,7 +1094,6 @@ namespace winstd { } - /// /// Moves the object /// @@ -1112,7 +1105,6 @@ namespace winstd other.m_event_dest = NULL; } - /// /// Writes the `event_dest` event /// @@ -1122,7 +1114,6 @@ namespace winstd m_ep.write(m_event_dest, 1, &m_fn_name); } - /// /// Copies the object /// @@ -1137,7 +1128,6 @@ namespace winstd return *this; } - /// /// Moves the object /// @@ -1153,14 +1143,12 @@ namespace winstd return *this; } - protected: event_provider &m_ep; ///< Reference to event provider in use const EVENT_DESCRIPTOR *m_event_dest; ///< Event descriptor at destruction EVENT_DATA_DESCRIPTOR m_fn_name; ///< Function name }; - /// /// Helper template to write an event on entry/exit of scope with one parameter (typically result). /// @@ -1182,7 +1170,6 @@ namespace winstd m_ep.write(event_cons, 1, m_desc); } - /// /// Copies the object /// @@ -1194,7 +1181,6 @@ namespace winstd m_desc[0] = other.m_desc[0]; } - /// /// Moves the object /// @@ -1207,7 +1193,6 @@ namespace winstd other.m_event_dest = NULL; } - /// /// Writes the `event_dest` event /// @@ -1219,7 +1204,6 @@ namespace winstd } } - /// /// Copies the object /// @@ -1235,7 +1219,6 @@ namespace winstd return *this; } - /// /// Moves the object /// @@ -1252,7 +1235,6 @@ namespace winstd return *this; } - protected: event_provider &m_ep; ///< Reference to event provider in use const EVENT_DESCRIPTOR *m_event_dest; ///< Event descriptor at destruction @@ -1262,74 +1244,3 @@ namespace winstd /// @} } - - -#pragma warning(push) -#pragma warning(disable: 4505) // Don't warn on unused code - -static _Success_(return == ERROR_SUCCESS) ULONG TdhGetEventInformation(_In_ PEVENT_RECORD pEvent, _In_ ULONG TdhContextCount, _In_reads_opt_(TdhContextCount) PTDH_CONTEXT pTdhContext, _Out_ std::unique_ptr &info) -{ - BYTE szBuffer[WINSTD_STACK_BUFFER_BYTES]; - ULONG ulSize = sizeof(szBuffer), ulResult; - - // Try with stack buffer first. - ulResult = TdhGetEventInformation(pEvent, TdhContextCount, pTdhContext, (PTRACE_EVENT_INFO)szBuffer, &ulSize); - if (ulResult == ERROR_SUCCESS) { - // Copy from stack. - info.reset(reinterpret_cast(new char[ulSize])); - memcpy(info.get(), szBuffer, ulSize); - return ERROR_SUCCESS; - } else if (ulResult == ERROR_INSUFFICIENT_BUFFER) { - // Create buffer on heap and retry. - info.reset(reinterpret_cast(new char[ulSize])); - return TdhGetEventInformation(pEvent, TdhContextCount, pTdhContext, info.get(), &ulSize); - } - - return ulResult; -} - - -static _Success_(return == ERROR_SUCCESS) ULONG TdhGetEventMapInformation(_In_ PEVENT_RECORD pEvent, _In_ LPWSTR pMapName, _Inout_ std::unique_ptr &info) -{ - BYTE szBuffer[WINSTD_STACK_BUFFER_BYTES]; - ULONG ulSize = sizeof(szBuffer), ulResult; - - // Try with stack buffer first. - ulResult = TdhGetEventMapInformation(pEvent, pMapName, (PEVENT_MAP_INFO)szBuffer, &ulSize); - if (ulResult == ERROR_SUCCESS) { - // Copy from stack. - info.reset(reinterpret_cast(new char[ulSize])); - memcpy(info.get(), szBuffer, ulSize); - return ERROR_SUCCESS; - } else if (ulResult == ERROR_INSUFFICIENT_BUFFER) { - // Create buffer on heap and retry. - info.reset(reinterpret_cast(new char[ulSize])); - return TdhGetEventMapInformation(pEvent, pMapName, info.get(), &ulSize); - } - - return ulResult; -} - - -template -static _Success_(return == ERROR_SUCCESS) ULONG TdhGetProperty(_In_ PEVENT_RECORD pEvent, _In_ ULONG TdhContextCount, _In_reads_opt_(TdhContextCount) PTDH_CONTEXT pTdhContext, _In_ ULONG PropertyDataCount, _In_reads_(PropertyDataCount) PPROPERTY_DATA_DESCRIPTOR pPropertyData, _Inout_ std::vector<_Ty, _Ax> &aData) -{ - ULONG ulSize, ulResult; - - // Query property size. - ulResult = TdhGetPropertySize(pEvent, TdhContextCount, pTdhContext, PropertyDataCount, pPropertyData, &ulSize); - if (ulResult == ERROR_SUCCESS) { - if (ulSize) { - // Query property value. - aData.resize((ulSize + sizeof(_Ty) - 1) / sizeof(_Ty)); - ulResult = TdhGetProperty(pEvent, TdhContextCount, pTdhContext, PropertyDataCount, pPropertyData, ulSize, reinterpret_cast(aData.data())); - } else { - // Property value size is zero. - aData.clear(); - } - } - - return ulResult; -} - -#pragma warning(pop) diff --git a/include/WinStd/GDI.h b/include/WinStd/GDI.h index f6597b9b..f4db9d64 100644 --- a/include/WinStd/GDI.h +++ b/include/WinStd/GDI.h @@ -3,28 +3,16 @@ Copyright © 1991-2022 Amebis */ -/// -/// \defgroup WinStdGdiAPI GDI API -/// Integrates WinStd classes with Microsoft Windows GDI -/// +#pragma once #include "Common.h" namespace winstd { - template class gdi_handle; - class dc; - class window_dc; - class dc_selector; -} - - -#pragma once - - -namespace winstd -{ - /// \addtogroup WinStdGdiAPI + /// + /// \defgroup WinStdGdiAPI GDI API + /// Integrates WinStd classes with Microsoft Windows GDI + /// /// @{ /// @@ -59,7 +47,6 @@ namespace winstd } }; - /// /// Device context wrapper class /// @@ -91,7 +78,6 @@ namespace winstd } }; - /// /// Device context wrapper class /// @@ -148,7 +134,6 @@ namespace winstd HWND m_hwnd; ///< Window handle }; - /// /// Context scope DC object restorer /// @@ -169,7 +154,6 @@ namespace winstd { } - /// /// Restores original object. /// @@ -181,7 +165,6 @@ namespace winstd SelectObject(m_hdc, m_orig); } - /// /// Return result of `SelectObject()` call. /// diff --git a/include/WinStd/MSI.h b/include/WinStd/MSI.h index e8ffff4f..168af330 100644 --- a/include/WinStd/MSI.h +++ b/include/WinStd/MSI.h @@ -4,94 +4,21 @@ Copyright © 2016 GÉANT */ +#pragma once + +#include "Common.h" +#include +#include +#include + /// /// \defgroup WinStdMSIAPI Microsoft Installer API /// Integrates WinStd classes with Microsoft Installer API /// - -#include "Common.h" - -#include - -#include -#include - /// \addtogroup WinStdMSIAPI /// @{ /// @copydoc MsiGetPropertyW() -template -static UINT MsiGetPropertyA(_In_ MSIHANDLE hInstall, _In_z_ LPCSTR szName, _Inout_ std::basic_string &sValue); - -/// -/// Gets the value for an installer property and stores it in a std::wstring string. -/// -/// \sa [MsiGetProperty function](https://msdn.microsoft.com/en-us/library/aa370134.aspx) -/// -template -static UINT MsiGetPropertyW(_In_ MSIHANDLE hInstall, _In_z_ LPCWSTR szName, _Inout_ std::basic_string &sValue); - -/// @copydoc MsiRecordGetStringW() -template -static UINT MsiRecordGetStringA(_In_ MSIHANDLE hRecord, _In_ unsigned int iField, _Inout_ std::basic_string &sValue); - -/// -/// Returns the string value of a record field and stores it in a std::wstring string. -/// -/// \sa [MsiRecordGetString function](https://msdn.microsoft.com/en-us/library/aa370368.aspx) -/// -template -static UINT MsiRecordGetStringW(_In_ MSIHANDLE hRecord, _In_ unsigned int iField, _Inout_ std::basic_string &sValue); - -/// @copydoc MsiFormatRecordW() -template -static UINT MsiFormatRecordA(_In_ MSIHANDLE hInstall, _In_ MSIHANDLE hRecord, _Inout_ std::basic_string &sValue); - -/// -/// Formats record field data and properties using a format string and stores it in a std::wstring string. -/// -/// \sa [MsiFormatRecord function](https://msdn.microsoft.com/en-us/library/aa370109.aspx) -/// -template -static UINT MsiFormatRecordW(_In_ MSIHANDLE hInstall, _In_ MSIHANDLE hRecord, _Inout_ std::basic_string &sValue); - -/// -/// Reads bytes from a record stream field into a std::vector buffer. -/// -/// \sa [MsiRecordReadStream function](https://msdn.microsoft.com/en-us/library/aa370370.aspx) -/// -template -static UINT MsiRecordReadStream(_In_ MSIHANDLE hRecord, _In_ unsigned int iField, _Inout_ std::vector<_Ty, _Ax> &binData); - -/// @copydoc MsiGetTargetPathW() -template -static UINT MsiGetTargetPathA(_In_ MSIHANDLE hInstall, _In_z_ LPCSTR szFolder, _Inout_ std::basic_string &sValue); - -/// -/// Returns the full target path for a folder in the Directory table and stores it in a std::wstring string. -/// -/// \sa [MsiGetTargetPath function](https://msdn.microsoft.com/en-us/library/aa370303.aspx) -/// -template -static UINT MsiGetTargetPathW(_In_ MSIHANDLE hInstall, _In_z_ LPCWSTR szFolder, _Inout_ std::basic_string &sValue); - -/// @copydoc MsiGetComponentPathW() -template -static INSTALLSTATE MsiGetComponentPathA(_In_z_ LPCSTR szProduct, _In_z_ LPCSTR szComponent, _Inout_ std::basic_string &sValue); - -/// -/// Returns the full path to an installed component. If the key path for the component is a registry key then the registry key is returned. -/// -/// \sa [MsiGetComponentPath function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa370112.aspx) -/// -template -static INSTALLSTATE MsiGetComponentPathW(_In_z_ LPCWSTR szProduct, _In_z_ LPCWSTR szComponent, _Inout_ std::basic_string &sValue); - -/// @} - -#pragma once - - template static UINT MsiGetPropertyA(_In_ MSIHANDLE hInstall, _In_z_ LPCSTR szName, _Inout_ std::basic_string &sValue) { @@ -119,7 +46,11 @@ static UINT MsiGetPropertyA(_In_ MSIHANDLE hInstall, _In_z_ LPCSTR szName, _Inou } } - +/// +/// Gets the value for an installer property and stores it in a std::wstring string. +/// +/// \sa [MsiGetProperty function](https://msdn.microsoft.com/en-us/library/aa370134.aspx) +/// template static UINT MsiGetPropertyW(_In_ MSIHANDLE hInstall, _In_z_ LPCWSTR szName, _Inout_ std::basic_string &sValue) { @@ -145,7 +76,7 @@ static UINT MsiGetPropertyW(_In_ MSIHANDLE hInstall, _In_z_ LPCWSTR szName, _Ino } } - +/// @copydoc MsiRecordGetStringW() template static UINT MsiRecordGetStringA(_In_ MSIHANDLE hRecord, _In_ unsigned int iField, _Inout_ std::basic_string &sValue) { @@ -173,7 +104,11 @@ static UINT MsiRecordGetStringA(_In_ MSIHANDLE hRecord, _In_ unsigned int iField } } - +/// +/// Returns the string value of a record field and stores it in a std::wstring string. +/// +/// \sa [MsiRecordGetString function](https://msdn.microsoft.com/en-us/library/aa370368.aspx) +/// template static UINT MsiRecordGetStringW(_In_ MSIHANDLE hRecord, _In_ unsigned int iField, _Inout_ std::basic_string &sValue) { @@ -199,7 +134,7 @@ static UINT MsiRecordGetStringW(_In_ MSIHANDLE hRecord, _In_ unsigned int iField } } - +/// @copydoc MsiFormatRecordW() template static UINT MsiFormatRecordA(_In_ MSIHANDLE hInstall, _In_ MSIHANDLE hRecord, _Inout_ std::basic_string &sValue) { @@ -227,7 +162,11 @@ static UINT MsiFormatRecordA(_In_ MSIHANDLE hInstall, _In_ MSIHANDLE hRecord, _I } } - +/// +/// Formats record field data and properties using a format string and stores it in a std::wstring string. +/// +/// \sa [MsiFormatRecord function](https://msdn.microsoft.com/en-us/library/aa370109.aspx) +/// template static UINT MsiFormatRecordW(_In_ MSIHANDLE hInstall, _In_ MSIHANDLE hRecord, _Inout_ std::basic_string &sValue) { @@ -253,7 +192,11 @@ static UINT MsiFormatRecordW(_In_ MSIHANDLE hInstall, _In_ MSIHANDLE hRecord, _I } } - +/// +/// Reads bytes from a record stream field into a std::vector buffer. +/// +/// \sa [MsiRecordReadStream function](https://msdn.microsoft.com/en-us/library/aa370370.aspx) +/// template static UINT MsiRecordReadStream(_In_ MSIHANDLE hRecord, _In_ unsigned int iField, _Inout_ std::vector<_Ty, _Ax> &binData) { @@ -273,7 +216,7 @@ static UINT MsiRecordReadStream(_In_ MSIHANDLE hRecord, _In_ unsigned int iField } } - +/// @copydoc MsiGetTargetPathW() template static UINT MsiGetTargetPathA(_In_ MSIHANDLE hInstall, _In_z_ LPCSTR szFolder, _Out_ std::basic_string &sValue) { @@ -301,7 +244,11 @@ static UINT MsiGetTargetPathA(_In_ MSIHANDLE hInstall, _In_z_ LPCSTR szFolder, _ } } - +/// +/// Returns the full target path for a folder in the Directory table and stores it in a std::wstring string. +/// +/// \sa [MsiGetTargetPath function](https://msdn.microsoft.com/en-us/library/aa370303.aspx) +/// template static UINT MsiGetTargetPathW(_In_ MSIHANDLE hInstall, _In_z_ LPCWSTR szFolder, _Inout_ std::basic_string &sValue) { @@ -327,7 +274,7 @@ static UINT MsiGetTargetPathW(_In_ MSIHANDLE hInstall, _In_z_ LPCWSTR szFolder, } } - +/// @copydoc MsiGetComponentPathW() template static INSTALLSTATE MsiGetComponentPathA(_In_z_ LPCSTR szProduct, _In_z_ LPCSTR szComponent, _Inout_ std::basic_string &sValue) { @@ -353,7 +300,11 @@ static INSTALLSTATE MsiGetComponentPathA(_In_z_ LPCSTR szProduct, _In_z_ LPCSTR } } - +/// +/// Returns the full path to an installed component. If the key path for the component is a registry key then the registry key is returned. +/// +/// \sa [MsiGetComponentPath function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa370112.aspx) +/// template static INSTALLSTATE MsiGetComponentPathW(_In_z_ LPCWSTR szProduct, _In_z_ LPCWSTR szComponent, _Inout_ std::basic_string &sValue) { @@ -378,3 +329,5 @@ static INSTALLSTATE MsiGetComponentPathW(_In_z_ LPCWSTR szProduct, _In_z_ LPCWST return state; } } + +/// @} diff --git a/include/WinStd/Sec.h b/include/WinStd/Sec.h index 9a24501b..5481d23d 100644 --- a/include/WinStd/Sec.h +++ b/include/WinStd/Sec.h @@ -4,33 +4,47 @@ Copyright © 2016 GÉANT */ +#pragma once + +#include "Common.h" +#include +#include + /// /// \defgroup WinStdSecurityAPI Security API /// Integrates WinStd classes with Microsoft Security API /// - -#include "Common.h" - -#include - -#include - -namespace winstd -{ - class sec_credentials; - class sec_context; - class sec_buffer_desc; - class sec_runtime_error; -} +/// @{ #if defined(SECURITY_WIN32) || defined(SECURITY_KERNEL) -/// \addtogroup WinStdSecurityAPI -/// @{ - /// @copydoc GetUserNameExW() template -static BOOLEAN GetUserNameExA(_In_ EXTENDED_NAME_FORMAT NameFormat, _Inout_ std::basic_string &sName); +static BOOLEAN GetUserNameExA(_In_ EXTENDED_NAME_FORMAT NameFormat, _Inout_ std::basic_string &sName) +{ + assert(0); // TODO: Test this code. + + char szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(char)]; + ULONG ulSize = _countof(szStackBuffer); + + // Try with stack buffer first. + if (::GetUserNameExA(NameFormat, szStackBuffer, &ulSize)) { + // Copy from stack. + sName.assign(szStackBuffer, ulSize); + return TRUE; + } else { + if (::GetLastError() == ERROR_MORE_DATA) { + // Allocate buffer on heap and retry. + std::unique_ptr szBuffer(new char[ulSize]); + if (::GetUserNameExA(NameFormat, szBuffer.get(), &ulSize)) { + sName.assign(szBuffer.get(), ulSize); + return TRUE; + } + } + } + + return FALSE; +} /// /// Retrieves the name of the user or other security principal associated with the calling thread and stores it in a std::wstring string. @@ -38,15 +52,36 @@ static BOOLEAN GetUserNameExA(_In_ EXTENDED_NAME_FORMAT NameFormat, _Inout_ std: /// \sa [GetUserNameEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724435.aspx) /// template -static BOOLEAN GetUserNameExW(_In_ EXTENDED_NAME_FORMAT NameFormat, _Inout_ std::basic_string &sName); +static BOOLEAN GetUserNameExW(_In_ EXTENDED_NAME_FORMAT NameFormat, _Inout_ std::basic_string &sName) +{ + assert(0); // TODO: Test this code. + + wchar_t szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t)]; + ULONG ulSize = _countof(szStackBuffer); + + // Try with stack buffer first. + if (::GetUserNameExW(NameFormat, szStackBuffer, &ulSize)) { + // Copy from stack. + sName.assign(szStackBuffer, ulSize); + return TRUE; + } else { + if (::GetLastError() == ERROR_MORE_DATA) { + // Allocate buffer on heap and retry. + std::unique_ptr szBuffer(new wchar_t[ulSize]); + if (::GetUserNameExW(NameFormat, szBuffer.get(), &ulSize)) { + sName.assign(szBuffer.get(), ulSize); + return TRUE; + } + } + } + + return FALSE; +} #endif /// @} -#pragma once - - namespace winstd { /// \addtogroup WinStdSecurityAPI @@ -161,7 +196,6 @@ namespace winstd TimeStamp m_expires; ///< Credentials expiration time }; - /// /// PCtxtHandle wrapper class /// @@ -285,7 +319,6 @@ namespace winstd TimeStamp m_expires; ///< Context expiration time }; - /// /// SecBufferDesc wrapper class /// @@ -318,10 +351,7 @@ namespace winstd /// @} - /// - /// \defgroup WinStdExceptions Exceptions - /// Additional exceptions - /// + /// \addtogroup WinStdExceptions /// @{ /// @@ -342,7 +372,6 @@ namespace winstd { } - /// /// Constructs an exception /// @@ -353,7 +382,6 @@ namespace winstd { } - /// /// Copies an exception /// @@ -366,63 +394,3 @@ namespace winstd /// @} } - - -#if defined(SECURITY_WIN32) || defined(SECURITY_KERNEL) - -template -static BOOLEAN GetUserNameExA(_In_ EXTENDED_NAME_FORMAT NameFormat, _Inout_ std::basic_string &sName) -{ - assert(0); // TODO: Test this code. - - char szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(char)]; - ULONG ulSize = _countof(szStackBuffer); - - // Try with stack buffer first. - if (::GetUserNameExA(NameFormat, szStackBuffer, &ulSize)) { - // Copy from stack. - sName.assign(szStackBuffer, ulSize); - return TRUE; - } else { - if (::GetLastError() == ERROR_MORE_DATA) { - // Allocate buffer on heap and retry. - std::unique_ptr szBuffer(new char[ulSize]); - if (::GetUserNameExA(NameFormat, szBuffer.get(), &ulSize)) { - sName.assign(szBuffer.get(), ulSize); - return TRUE; - } - } - } - - return FALSE; -} - - -template -static BOOLEAN GetUserNameExW(_In_ EXTENDED_NAME_FORMAT NameFormat, _Inout_ std::basic_string &sName) -{ - assert(0); // TODO: Test this code. - - wchar_t szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t)]; - ULONG ulSize = _countof(szStackBuffer); - - // Try with stack buffer first. - if (::GetUserNameExW(NameFormat, szStackBuffer, &ulSize)) { - // Copy from stack. - sName.assign(szStackBuffer, ulSize); - return TRUE; - } else { - if (::GetLastError() == ERROR_MORE_DATA) { - // Allocate buffer on heap and retry. - std::unique_ptr szBuffer(new wchar_t[ulSize]); - if (::GetUserNameExW(NameFormat, szBuffer.get(), &ulSize)) { - sName.assign(szBuffer.get(), ulSize); - return TRUE; - } - } - } - - return FALSE; -} - -#endif diff --git a/include/WinStd/SetupAPI.h b/include/WinStd/SetupAPI.h index cf423c6c..c27e203a 100644 --- a/include/WinStd/SetupAPI.h +++ b/include/WinStd/SetupAPI.h @@ -4,28 +4,17 @@ Copyright © 2016 GÉANT */ - /// - /// \defgroup SetupAPI Setup API - /// Integrates WinStd classes with Microsoft Setup API - /// - -#include "Common.h" - -namespace winstd -{ - class setup_device_info_list; - class setup_driver_info_list_builder; -} - - #pragma once +#include "Common.h" #include - namespace winstd { - /// \addtogroup SetupAPI + /// + /// \defgroup SetupAPI Setup API + /// Integrates WinStd classes with Microsoft Setup API + /// /// @{ /// @@ -108,7 +97,6 @@ namespace winstd } }; - /// /// Builds a list of drivers in constructor and deletes it in destructor /// @@ -145,7 +133,6 @@ namespace winstd SetupDiDestroyDriverInfoList(m_DeviceInfoSet, m_DeviceInfoData, m_DriverType); } - /// /// Return result of `SetupDiBuildDriverInfoList()` call. /// diff --git a/include/WinStd/Shell.h b/include/WinStd/Shell.h index 9c837378..c2ad58c5 100644 --- a/include/WinStd/Shell.h +++ b/include/WinStd/Shell.h @@ -4,36 +4,19 @@ Copyright © 2016 GÉANT */ +#pragma once + +#include "Common.h" +#include +#include + /// /// \defgroup WinStdShellWAPI Shell API /// Integrates WinStd classes with Microsoft Shell API /// -#include "Common.h" - -#include - -#include - -/// \addtogroup WinStdShellWAPI /// @{ /// @copydoc PathCanonicalizeW() -template -static BOOL PathCanonicalizeA(_Inout_ std::basic_string &sValue, _In_ LPCSTR pszPath); - -/// -/// Simplifies a path by removing navigation elements such as "." and ".." to produce a direct, well-formed path, and stores it in a std::wstring string. -/// -/// \sa [PathCanonicalize function](https://msdn.microsoft.com/en-us/library/windows/desktop/bb773569.aspx) -/// -template -static BOOL PathCanonicalizeW(_Inout_ std::basic_string &sValue, _In_ LPCWSTR pszPath); - -/// @} - -#pragma once - - template static BOOL PathCanonicalizeA(_Inout_ std::basic_string &sValue, _In_ LPCSTR pszPath) { @@ -46,7 +29,11 @@ static BOOL PathCanonicalizeA(_Inout_ std::basic_string &sVa return bResult; } - +/// +/// Simplifies a path by removing navigation elements such as "." and ".." to produce a direct, well-formed path, and stores it in a std::wstring string. +/// +/// \sa [PathCanonicalize function](https://msdn.microsoft.com/en-us/library/windows/desktop/bb773569.aspx) +/// template static BOOL PathCanonicalizeW(_Inout_ std::basic_string &sValue, _In_ LPCWSTR pszPath) { @@ -57,3 +44,5 @@ static BOOL PathCanonicalizeW(_Inout_ std::basic_string & sValue.assign(szBuffer, bResult ? MAX_PATH : 0); return bResult; } + +/// @} diff --git a/include/WinStd/WLAN.h b/include/WinStd/WLAN.h index 6370466b..bb167f0e 100644 --- a/include/WinStd/WLAN.h +++ b/include/WinStd/WLAN.h @@ -4,28 +4,20 @@ Copyright © 2016 GÉANT */ -/// -/// \defgroup WinStdWLANAPI WLAN API -/// Integrates WinStd classes with Microsoft WLAN API -/// +#pragma once #include "Common.h" - #include - #include // Must not statically link to Wlanapi.dll as it is not available on Windows // without a WLAN interface. extern DWORD (WINAPI *pfnWlanReasonCodeToString)(__in DWORD dwReasonCode, __in DWORD dwBufferSize, __in_ecount(dwBufferSize) PWCHAR pStringBuffer, __reserved PVOID pReserved); -namespace winstd { - template struct WlanFreeMemory_delete; - template struct WlanFreeMemory_delete<_Ty[]>; - class wlan_handle; -} - -/// \addtogroup WinStdWLANAPI +/// +/// \defgroup WinStdWLANAPI WLAN API +/// Integrates WinStd classes with Microsoft WLAN API +/// /// @{ /// @@ -38,13 +30,36 @@ namespace winstd { /// function must be loaded dynamically. /// template -static DWORD WlanReasonCodeToString(_In_ DWORD dwReasonCode, _Inout_ std::basic_string &sValue, __reserved PVOID pReserved); +static DWORD WlanReasonCodeToString(_In_ DWORD dwReasonCode, _Inout_ std::basic_string &sValue, __reserved PVOID pReserved) +{ + DWORD dwSize = 0; + + if (!::pfnWlanReasonCodeToString) + return ERROR_CALL_NOT_IMPLEMENTED; + + for (;;) { + // Increment size and allocate buffer. + dwSize += 1024; + std::unique_ptr szBuffer(new wchar_t[dwSize]); + + // Try! + DWORD dwResult = ::pfnWlanReasonCodeToString(dwReasonCode, dwSize, szBuffer.get(), pReserved); + if (dwResult == ERROR_SUCCESS) { + DWORD dwLength = (DWORD)wcsnlen(szBuffer.get(), dwSize); + if (dwLength < dwSize - 1) { + // Buffer was long enough. + sValue.assign(szBuffer.get(), dwLength); + return ERROR_SUCCESS; + } + } else { + // Return error code. + return dwResult; + } + } +} /// @} -#pragma once - - namespace winstd { /// \addtogroup WinStdWLANAPI @@ -76,7 +91,6 @@ namespace winstd } }; - /// /// Deleter for unique_ptr to array of unknown size using WlanFreeMemory /// @@ -107,7 +121,6 @@ namespace winstd } }; - /// /// WLAN handle wrapper /// @@ -163,33 +176,3 @@ namespace winstd /// @} } - - -template -static DWORD WlanReasonCodeToString(_In_ DWORD dwReasonCode, _Inout_ std::basic_string &sValue, __reserved PVOID pReserved) -{ - DWORD dwSize = 0; - - if (!::pfnWlanReasonCodeToString) - return ERROR_CALL_NOT_IMPLEMENTED; - - for (;;) { - // Increment size and allocate buffer. - dwSize += 1024; - std::unique_ptr szBuffer(new wchar_t[dwSize]); - - // Try! - DWORD dwResult = ::pfnWlanReasonCodeToString(dwReasonCode, dwSize, szBuffer.get(), pReserved); - if (dwResult == ERROR_SUCCESS) { - DWORD dwLength = (DWORD)wcsnlen(szBuffer.get(), dwSize); - if (dwLength < dwSize - 1) { - // Buffer was long enough. - sValue.assign(szBuffer.get(), dwLength); - return ERROR_SUCCESS; - } - } else { - // Return error code. - return dwResult; - } - } -} diff --git a/include/WinStd/Win.h b/include/WinStd/Win.h index 51e17f08..6ca3fb31 100644 --- a/include/WinStd/Win.h +++ b/include/WinStd/Win.h @@ -4,42 +4,47 @@ Copyright © 2016 GÉANT */ +#pragma once + +#include "Common.h" +#include +#include + +#pragma warning(push) +#pragma warning(disable: 4505) // Don't warn on unused code + /// /// \defgroup WinStdWinAPI Windows API /// Integrates WinStd classes with Microsoft Windows API /// - -#include "Common.h" - -#include -#include - -namespace winstd -{ - template class win_handle; - class library; - class process; - class file; - class event; - class critical_section; - class heap; - template class heap_allocator; - class actctx_activator; - class user_impersonator; - class console_ctrl_handler; - class vmemory; - class reg_key; - class security_id; - class process_information; -} - - -/// \addtogroup WinStdWinAPI /// @{ /// @copydoc GetModuleFileNameW() template -static DWORD GetModuleFileNameA(_In_opt_ HMODULE hModule, _Out_ std::basic_string &sValue) noexcept; +static DWORD GetModuleFileNameA(_In_opt_ HMODULE hModule, _Out_ std::basic_string &sValue) noexcept +{ + assert(0); // TODO: Test this code. + + char szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(char)]; + + // Try with stack buffer first. + DWORD dwResult = ::GetModuleFileNameA(hModule, szStackBuffer, _countof(szStackBuffer)); + if (dwResult < _countof(szStackBuffer)) { + // Copy from stack. + sValue.assign(szStackBuffer, dwResult); + return dwResult; + } else { + for (DWORD dwCapacity = 2*WINSTD_STACK_BUFFER_BYTES/sizeof(char);; dwCapacity *= 2) { + // Allocate on heap and retry. + std::unique_ptr szBuffer(new char[dwCapacity]); + dwResult = ::GetModuleFileNameA(hModule, szBuffer.get(), dwCapacity); + if (dwResult < dwCapacity) { + sValue.assign(szBuffer.get(), dwResult); + return dwResult; + } + } + } +} /// /// Retrieves the fully qualified path for the file that contains the specified module and stores it in a std::wstring string. @@ -47,11 +52,57 @@ static DWORD GetModuleFileNameA(_In_opt_ HMODULE hModule, _Out_ std::basic_strin /// \sa [GetModuleFileName function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms683197.aspx) /// template -static DWORD GetModuleFileNameW(_In_opt_ HMODULE hModule, _Out_ std::basic_string &sValue) noexcept; +static DWORD GetModuleFileNameW(_In_opt_ HMODULE hModule, _Out_ std::basic_string &sValue) noexcept +{ + wchar_t szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t)]; + + // Try with stack buffer first. + DWORD dwResult = ::GetModuleFileNameW(hModule, szStackBuffer, _countof(szStackBuffer)); + if (dwResult < _countof(szStackBuffer)) { + // Copy from stack. + sValue.assign(szStackBuffer, dwResult); + return dwResult; + } else { + for (DWORD dwCapacity = 2*WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t);; dwCapacity *= 2) { + // Allocate on heap and retry. + std::unique_ptr szBuffer(new wchar_t[dwCapacity]); + dwResult = ::GetModuleFileNameW(hModule, szBuffer.get(), dwCapacity); + if (dwResult < dwCapacity) { + sValue.assign(szBuffer.get(), dwResult); + return dwResult; + } + } + } +} /// @copydoc GetWindowTextW() template -static _Success_(return != 0) int GetWindowTextA(_In_ HWND hWnd, _Out_ std::basic_string &sValue) noexcept; +static _Success_(return != 0) int GetWindowTextA(_In_ HWND hWnd, _Out_ std::basic_string &sValue) noexcept +{ + assert(0); // TODO: Test this code. + + int iResult; + + // Query the final string length first. + iResult = ::GetWindowTextLengthA(hWnd); + if (iResult > 0) { + if (++iResult < WINSTD_STACK_BUFFER_BYTES/sizeof(char)) { + // Read string data to stack. + char szBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(char)]; + iResult = ::GetWindowTextA(hWnd, szBuffer, _countof(szBuffer)); + sValue.assign(szBuffer, iResult); + } else { + // Allocate buffer on heap and read the string data into it. + std::unique_ptr szBuffer(new char[++iResult]); + iResult = ::GetWindowTextA(hWnd, szBuffer.get(), iResult); + sValue.assign(szBuffer.get(), iResult); + } + return iResult; + } + + sValue.clear(); + return 0; +} /// /// Copies the text of the specified window's title bar (if it has one) into a std::wstring string. @@ -59,11 +110,48 @@ static _Success_(return != 0) int GetWindowTextA(_In_ HWND hWnd, _Out_ std::basi /// \sa [GetWindowText function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633520.aspx) /// template -static _Success_(return != 0) int GetWindowTextW(_In_ HWND hWnd, _Out_ std::basic_string &sValue) noexcept; +static _Success_(return != 0) int GetWindowTextW(_In_ HWND hWnd, _Out_ std::basic_string &sValue) noexcept +{ + assert(0); // TODO: Test this code. + + int iResult; + + // Query the final string length first. + iResult = ::GetWindowTextLengthW(hWnd); + if (iResult > 0) { + if (++iResult < WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t)) { + // Read string data to stack. + wchar_t szBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t)]; + iResult = ::GetWindowTextW(hWnd, szBuffer, _countof(szBuffer)); + sValue.assign(szBuffer, iResult); + } else { + // Allocate buffer on heap and read the string data into it. + std::unique_ptr szBuffer(new wchar_t[++iResult]); + iResult = ::GetWindowTextW(hWnd, szBuffer.get(), iResult); + sValue.assign(szBuffer.get(), iResult); + } + return iResult; + } + + sValue.clear(); + return 0; +} /// @copydoc GetFileVersionInfoW() template -static _Success_(return != 0) BOOL GetFileVersionInfoA(_In_z_ LPCSTR lptstrFilename, __reserved DWORD dwHandle, _Out_ std::vector<_Ty, _Ax> &aValue) noexcept; +static _Success_(return != 0) BOOL GetFileVersionInfoA(_In_z_ LPCSTR lptstrFilename, __reserved DWORD dwHandle, _Out_ std::vector<_Ty, _Ax> &aValue) noexcept +{ + assert(0); // TODO: Test this code. + + // Get version info size. + DWORD dwVerInfoSize = ::GetFileVersionInfoSizeA(lptstrFilename, &dwHandle); + if (dwVerInfoSize != 0) { + // Read version info. + aValue.resize((dwVerInfoSize + sizeof(_Ty) - 1) / sizeof(_Ty)); + return ::GetFileVersionInfoA(lptstrFilename, dwHandle, dwVerInfoSize, aValue.data()); + } else + return FALSE; +} /// /// Retrieves version information for the specified file and stores it in a std::vector buffer. @@ -71,11 +159,43 @@ static _Success_(return != 0) BOOL GetFileVersionInfoA(_In_z_ LPCSTR lptstrFilen /// \sa [GetFileVersionInfo function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms647003.aspx) /// template -static _Success_(return != 0) BOOL GetFileVersionInfoW(_In_z_ LPCWSTR lptstrFilename, __reserved DWORD dwHandle, _Out_ std::vector<_Ty, _Ax> &aValue) noexcept; +static _Success_(return != 0) BOOL GetFileVersionInfoW(_In_z_ LPCWSTR lptstrFilename, __reserved DWORD dwHandle, _Out_ std::vector<_Ty, _Ax> &aValue) noexcept +{ + assert(0); // TODO: Test this code. + + // Get version info size. + DWORD dwVerInfoSize = ::GetFileVersionInfoSizeW(lptstrFilename, &dwHandle); + if (dwVerInfoSize != 0) { + // Read version info. + aValue.resize((dwVerInfoSize + sizeof(_Ty) - 1) / sizeof(_Ty)); + return ::GetFileVersionInfoW(lptstrFilename, dwHandle, dwVerInfoSize, aValue.data()); + } else + return FALSE; +} /// @copydoc ExpandEnvironmentStringsW() template -static _Success_(return != 0) DWORD ExpandEnvironmentStringsA(_In_z_ LPCSTR lpSrc, _Out_ std::basic_string &sValue) noexcept; +static _Success_(return != 0) DWORD ExpandEnvironmentStringsA(_In_z_ LPCSTR lpSrc, _Out_ std::basic_string &sValue) noexcept +{ + assert(0); // TODO: Test this code. + + for (DWORD dwSizeOut = (DWORD)strlen(lpSrc) + 0x100;;) { + DWORD dwSizeIn = dwSizeOut; + std::unique_ptr szBuffer(new char[(size_t)dwSizeIn + 2]); // Note: ANSI version requires one extra char. + dwSizeOut = ::ExpandEnvironmentStringsA(lpSrc, szBuffer.get(), dwSizeIn); + if (dwSizeOut == 0) { + // Error or zero-length input. + break; + } else if (dwSizeOut <= dwSizeIn) { + // The buffer was sufficient. + sValue.assign(szBuffer.get(), dwSizeOut - 1); + return dwSizeOut; + } + } + + sValue.clear(); + return 0; +} /// /// Expands environment-variable strings, replaces them with the values defined for the current user, and stores it in a std::wstring string. @@ -83,11 +203,39 @@ static _Success_(return != 0) DWORD ExpandEnvironmentStringsA(_In_z_ LPCSTR lpSr /// \sa [ExpandEnvironmentStrings function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724265.aspx) /// template -static _Success_(return != 0) DWORD ExpandEnvironmentStringsW(_In_z_ LPCWSTR lpSrc, _Out_ std::basic_string &sValue) noexcept; +static _Success_(return != 0) DWORD ExpandEnvironmentStringsW(_In_z_ LPCWSTR lpSrc, _Out_ std::basic_string &sValue) noexcept +{ + for (DWORD dwSizeOut = (DWORD)wcslen(lpSrc) + 0x100;;) { + DWORD dwSizeIn = dwSizeOut; + std::unique_ptr szBuffer(new wchar_t[(size_t)dwSizeIn + 1]); + dwSizeOut = ::ExpandEnvironmentStringsW(lpSrc, szBuffer.get(), dwSizeIn); + if (dwSizeOut == 0) { + // Error or zero-length input. + break; + } else if (dwSizeOut <= dwSizeIn) { + // The buffer was sufficient. + sValue.assign(szBuffer.get(), dwSizeOut - 1); + return dwSizeOut; + } + } + + sValue.clear(); + return 0; +} /// @copydoc GuidToStringW() template -static VOID GuidToStringA(_In_ LPCGUID lpGuid, _Out_ std::basic_string &str) noexcept; +static VOID GuidToStringA(_In_ LPCGUID lpGuid, _Out_ std::basic_string &str) noexcept +{ + assert(0); // TODO: Test this code. + + sprintf(str, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", + lpGuid->Data1, + lpGuid->Data2, + lpGuid->Data3, + lpGuid->Data4[0], lpGuid->Data4[1], + lpGuid->Data4[2], lpGuid->Data4[3], lpGuid->Data4[4], lpGuid->Data4[5], lpGuid->Data4[6], lpGuid->Data4[7]); +} /// /// Formats GUID and stores it in a std::wstring string. @@ -96,7 +244,17 @@ static VOID GuidToStringA(_In_ LPCGUID lpGuid, _Out_ std::basic_string -static VOID GuidToStringW(_In_ LPCGUID lpGuid, _Out_ std::basic_string &str) noexcept; +static VOID GuidToStringW(_In_ LPCGUID lpGuid, _Out_ std::basic_string &str) noexcept +{ + assert(0); // TODO: Test this code. + + sprintf(str, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", + lpGuid->Data1, + lpGuid->Data2, + lpGuid->Data3, + lpGuid->Data4[0], lpGuid->Data4[1], + lpGuid->Data4[2], lpGuid->Data4[3], lpGuid->Data4[4], lpGuid->Data4[5], lpGuid->Data4[6], lpGuid->Data4[7]); +} /// @copydoc GuidToStringW() #ifdef _UNICODE @@ -106,7 +264,67 @@ static VOID GuidToStringW(_In_ LPCGUID lpGuid, _Out_ std::basic_string 0xFFFF) return FALSE; + g.Data2 = static_cast(ulTmp); + lpszGuid = lpszEnd; + + if (*lpszGuid != '-') return FALSE; + lpszGuid++; + + ulTmp = strtoul(lpszGuid, &lpszEnd, 16); + if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE; + g.Data3 = static_cast(ulTmp); + lpszGuid = lpszEnd; + + if (*lpszGuid != '-') return FALSE; + lpszGuid++; + + ulTmp = strtoul(lpszGuid, &lpszEnd, 16); + if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE; + g.Data4[0] = static_cast((ulTmp >> 8) & 0xff); + g.Data4[1] = static_cast( ulTmp & 0xff); + lpszGuid = lpszEnd; + + if (*lpszGuid != '-') return FALSE; + lpszGuid++; + + ullTmp = _strtoui64(lpszGuid, &lpszEnd, 16); + if (errno == ERANGE || ullTmp > 0xFFFFFFFFFFFF) return FALSE; + g.Data4[2] = static_cast((ullTmp >> 40) & 0xff); + g.Data4[3] = static_cast((ullTmp >> 32) & 0xff); + g.Data4[4] = static_cast((ullTmp >> 24) & 0xff); + g.Data4[5] = static_cast((ullTmp >> 16) & 0xff); + g.Data4[6] = static_cast((ullTmp >> 8) & 0xff); + g.Data4[7] = static_cast( ullTmp & 0xff); + lpszGuid = lpszEnd; + + if (*lpszGuid != '}') return FALSE; + lpszGuid++; + + if (lpszGuidEnd) + *lpszGuidEnd = lpszGuid; + + *lpGuid = g; + return TRUE; +} /// /// Parses string with GUID and stores it to GUID @@ -119,7 +337,67 @@ static _Success_(return) BOOL StringToGuidA(_In_z_ LPCSTR lpszGuid, _Out_ LPGUID /// - `TRUE` if GUID successfuly parsed; /// - `FALSE` otherwise. /// -static _Success_(return) BOOL StringToGuidW(_In_z_ LPCWSTR lpszGuid, _Out_ LPGUID lpGuid, _Out_opt_ LPCWSTR *lpszGuidEnd = NULL) noexcept; +static _Success_(return) BOOL StringToGuidW(_In_z_ LPCWSTR lpszGuid, _Out_ LPGUID lpGuid, _Out_opt_ LPCWSTR *lpszGuidEnd = NULL) noexcept +{ + GUID g; + LPWSTR lpszEnd; + unsigned long ulTmp; + unsigned long long ullTmp; + + if (!lpszGuid || !lpGuid || *lpszGuid != '{') return FALSE; + lpszGuid++; + + g.Data1 = wcstoul(lpszGuid, &lpszEnd, 16); + if (errno == ERANGE) return FALSE; + lpszGuid = lpszEnd; + + if (*lpszGuid != '-') return FALSE; + lpszGuid++; + + ulTmp = wcstoul(lpszGuid, &lpszEnd, 16); + if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE; + g.Data2 = static_cast(ulTmp); + lpszGuid = lpszEnd; + + if (*lpszGuid != '-') return FALSE; + lpszGuid++; + + ulTmp = wcstoul(lpszGuid, &lpszEnd, 16); + if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE; + g.Data3 = static_cast(ulTmp); + lpszGuid = lpszEnd; + + if (*lpszGuid != '-') return FALSE; + lpszGuid++; + + ulTmp = wcstoul(lpszGuid, &lpszEnd, 16); + if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE; + g.Data4[0] = static_cast((ulTmp >> 8) & 0xff); + g.Data4[1] = static_cast( ulTmp & 0xff); + lpszGuid = lpszEnd; + + if (*lpszGuid != '-') return FALSE; + lpszGuid++; + + ullTmp = _wcstoui64(lpszGuid, &lpszEnd, 16); + if (errno == ERANGE || ullTmp > 0xFFFFFFFFFFFF) return FALSE; + g.Data4[2] = static_cast((ullTmp >> 40) & 0xff); + g.Data4[3] = static_cast((ullTmp >> 32) & 0xff); + g.Data4[4] = static_cast((ullTmp >> 24) & 0xff); + g.Data4[5] = static_cast((ullTmp >> 16) & 0xff); + g.Data4[6] = static_cast((ullTmp >> 8) & 0xff); + g.Data4[7] = static_cast( ullTmp & 0xff); + lpszGuid = lpszEnd; + + if (*lpszGuid != '}') return FALSE; + lpszGuid++; + + if (lpszGuidEnd) + *lpszGuidEnd = lpszGuid; + + *lpGuid = g; + return TRUE; +} /// @copydoc StringToGuidW() #ifdef _UNICODE @@ -147,7 +425,50 @@ static _Success_(return) BOOL StringToGuidW(_In_z_ LPCWSTR lpszGuid, _Out_ LPGUI /// \sa [ExpandEnvironmentStrings function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724265.aspx) /// template -static LSTATUS RegQueryStringValue(_In_ HKEY hReg, _In_z_ LPCSTR pszName, _Out_ std::basic_string &sValue) noexcept; +static LSTATUS RegQueryStringValue(_In_ HKEY hReg, _In_z_ LPCSTR pszName, _Out_ std::basic_string &sValue) noexcept +{ + LSTATUS lResult; + BYTE aStackBuffer[WINSTD_STACK_BUFFER_BYTES]; + DWORD dwSize = sizeof(aStackBuffer), dwType; + + // Try with stack buffer first. + lResult = ::RegQueryValueExA(hReg, pszName, NULL, &dwType, aStackBuffer, &dwSize); + if (lResult == ERROR_SUCCESS) { + if (dwType == REG_SZ || dwType == REG_MULTI_SZ) { + // The value is REG_SZ or REG_MULTI_SZ. + dwSize /= sizeof(CHAR); + sValue.assign(reinterpret_cast(aStackBuffer), dwSize && reinterpret_cast(aStackBuffer)[dwSize - 1] == 0 ? dwSize - 1 : dwSize); + } else if (dwType == REG_EXPAND_SZ) { + // The value is REG_EXPAND_SZ. Expand it from stack buffer. + if (::ExpandEnvironmentStringsA(reinterpret_cast(aStackBuffer), sValue) == 0) + lResult = ::GetLastError(); + } else { + // The value is not a string type. + lResult = ERROR_INVALID_DATA; + } + } else if (lResult == ERROR_MORE_DATA) { + if (dwType == REG_SZ || dwType == REG_MULTI_SZ) { + // The value is REG_SZ or REG_MULTI_SZ. Read it now. + std::unique_ptr szBuffer(new CHAR[dwSize / sizeof(CHAR)]); + if ((lResult = ::RegQueryValueExA(hReg, pszName, NULL, NULL, reinterpret_cast(szBuffer.get()), &dwSize)) == ERROR_SUCCESS) { + dwSize /= sizeof(CHAR); + sValue.assign(szBuffer.get(), dwSize && szBuffer[dwSize - 1] == 0 ? dwSize - 1 : dwSize); + } + } else if (dwType == REG_EXPAND_SZ) { + // The value is REG_EXPAND_SZ. Read it and expand environment variables. + std::unique_ptr szBuffer(new CHAR[dwSize / sizeof(CHAR)]); + if ((lResult = ::RegQueryValueExA(hReg, pszName, NULL, NULL, reinterpret_cast(szBuffer.get()), &dwSize)) == ERROR_SUCCESS) { + if (::ExpandEnvironmentStringsA(szBuffer.get(), sValue) == 0) + lResult = ::GetLastError(); + } + } else { + // The value is not a string type. + lResult = ERROR_INVALID_DATA; + } + } + + return lResult; +} /// /// Queries for a string value in the registry and stores it in a std::wstring string. @@ -168,11 +489,73 @@ static LSTATUS RegQueryStringValue(_In_ HKEY hReg, _In_z_ LPCSTR pszName, _Out_ /// \sa [ExpandEnvironmentStrings function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724265.aspx) /// template -static LSTATUS RegQueryStringValue(_In_ HKEY hReg, _In_z_ LPCWSTR pszName, _Out_ std::basic_string &sValue) noexcept; +static LSTATUS RegQueryStringValue(_In_ HKEY hReg, _In_z_ LPCWSTR pszName, _Out_ std::basic_string &sValue) noexcept +{ + LSTATUS lResult; + BYTE aStackBuffer[WINSTD_STACK_BUFFER_BYTES]; + DWORD dwSize = sizeof(aStackBuffer), dwType; + + // Try with stack buffer first. + lResult = ::RegQueryValueExW(hReg, pszName, NULL, &dwType, aStackBuffer, &dwSize); + if (lResult == ERROR_SUCCESS) { + if (dwType == REG_SZ || dwType == REG_MULTI_SZ) { + // The value is REG_SZ or REG_MULTI_SZ. + dwSize /= sizeof(WCHAR); + sValue.assign(reinterpret_cast(aStackBuffer), dwSize && reinterpret_cast(aStackBuffer)[dwSize - 1] == 0 ? dwSize - 1 : dwSize); + } else if (dwType == REG_EXPAND_SZ) { + // The value is REG_EXPAND_SZ. Expand it from stack buffer. + if (::ExpandEnvironmentStringsW(reinterpret_cast(aStackBuffer), sValue) == 0) + lResult = ::GetLastError(); + } else { + // The value is not a string type. + lResult = ERROR_INVALID_DATA; + } + } else if (lResult == ERROR_MORE_DATA) { + if (dwType == REG_SZ || dwType == REG_MULTI_SZ) { + // The value is REG_SZ or REG_MULTI_SZ. Read it now. + std::unique_ptr szBuffer(new WCHAR[dwSize / sizeof(WCHAR)]); + if ((lResult = ::RegQueryValueExW(hReg, pszName, NULL, NULL, reinterpret_cast(szBuffer.get()), &dwSize)) == ERROR_SUCCESS) { + dwSize /= sizeof(WCHAR); + sValue.assign(szBuffer.get(), dwSize && szBuffer[dwSize - 1] == 0 ? dwSize - 1 : dwSize); + } + } else if (dwType == REG_EXPAND_SZ) { + // The value is REG_EXPAND_SZ. Read it and expand environment variables. + std::unique_ptr szBuffer(new WCHAR[dwSize / sizeof(WCHAR)]); + if ((lResult = ::RegQueryValueExW(hReg, pszName, NULL, NULL, reinterpret_cast(szBuffer.get()), &dwSize)) == ERROR_SUCCESS) { + if (::ExpandEnvironmentStringsW(szBuffer.get(), sValue) == 0) + lResult = ::GetLastError(); + } + } else { + // The value is not a string type. + lResult = ERROR_INVALID_DATA; + } + } + + return lResult; +} /// @copydoc RegQueryValueExW() template -static LSTATUS RegQueryValueExA(_In_ HKEY hKey, _In_opt_z_ LPCSTR lpValueName, __reserved LPDWORD lpReserved, _Out_opt_ LPDWORD lpType, _Out_ std::vector<_Ty, _Ax> &aData) noexcept; +static LSTATUS RegQueryValueExA(_In_ HKEY hKey, _In_opt_z_ LPCSTR lpValueName, __reserved LPDWORD lpReserved, _Out_opt_ LPDWORD lpType, _Out_ std::vector<_Ty, _Ax> &aData) noexcept +{ + LSTATUS lResult; + BYTE aStackBuffer[WINSTD_STACK_BUFFER_BYTES]; + DWORD dwSize = sizeof(aStackBuffer); + + // Try with stack buffer first. + lResult = RegQueryValueExA(hKey, lpValueName, lpReserved, lpType, aStackBuffer, &dwSize); + if (lResult == ERROR_SUCCESS) { + // Copy from stack buffer. + aData.resize((dwSize + sizeof(_Ty) - 1) / sizeof(_Ty)); + memcpy(aData.data(), aStackBuffer, dwSize); + } else if (lResult == ERROR_MORE_DATA) { + // Allocate buffer on heap and retry. + aData.resize((dwSize + sizeof(_Ty) - 1) / sizeof(_Ty)); + lResult = RegQueryValueExA(hKey, lpValueName, lpReserved, NULL, aData.data(), &dwSize); + } + + return lResult; +} /// /// Retrieves the type and data for the specified value name associated with an open registry key and stores the data in a std::vector buffer. @@ -180,13 +563,38 @@ static LSTATUS RegQueryValueExA(_In_ HKEY hKey, _In_opt_z_ LPCSTR lpValueName, _ /// \sa [RegQueryValueEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724911.aspx) /// template -static LSTATUS RegQueryValueExW(_In_ HKEY hKey, _In_opt_z_ LPCWSTR lpValueName, __reserved LPDWORD lpReserved, _Out_opt_ LPDWORD lpType, _Out_ std::vector<_Ty, _Ax> &aData) noexcept; +static LSTATUS RegQueryValueExW(_In_ HKEY hKey, _In_opt_z_ LPCWSTR lpValueName, __reserved LPDWORD lpReserved, _Out_opt_ LPDWORD lpType, _Out_ std::vector<_Ty, _Ax> &aData) noexcept +{ + LSTATUS lResult; + BYTE aStackBuffer[WINSTD_STACK_BUFFER_BYTES]; + DWORD dwSize = sizeof(aStackBuffer); + + // Try with stack buffer first. + lResult = RegQueryValueExW(hKey, lpValueName, lpReserved, lpType, aStackBuffer, &dwSize); + if (lResult == ERROR_SUCCESS) { + // Copy from stack buffer. + aData.resize((dwSize + sizeof(_Ty) - 1) / sizeof(_Ty)); + memcpy(aData.data(), aStackBuffer, dwSize); + } else if (lResult == ERROR_MORE_DATA) { + // Allocate buffer on heap and retry. + aData.resize((dwSize + sizeof(_Ty) - 1) / sizeof(_Ty)); + lResult = RegQueryValueExW(hKey, lpValueName, lpReserved, NULL, aData.data(), &dwSize); + } + + return lResult; +} #if _WIN32_WINNT >= _WIN32_WINNT_VISTA /// @copydoc RegLoadMUIStringW() template -static LSTATUS RegLoadMUIStringA(_In_ HKEY hKey, _In_opt_z_ LPCSTR pszValue, _Out_ std::basic_string &sOut, _In_ DWORD Flags, _In_opt_z_ LPCSTR pszDirectory) noexcept; +static LSTATUS RegLoadMUIStringA(_In_ HKEY hKey, _In_opt_z_ LPCSTR pszValue, _Out_ std::basic_string &sOut, _In_ DWORD Flags, _In_opt_z_ LPCSTR pszDirectory) noexcept +{ + // According to "Remarks" section in MSDN documentation of RegLoadMUIString(), + // this function is defined but not implemented as ANSI variation. + assert(0); + return ERROR_CALL_NOT_IMPLEMENTED; +} /// /// Loads the specified string from the specified key and subkey, and stores it in a std::wstring string. @@ -194,7 +602,27 @@ static LSTATUS RegLoadMUIStringA(_In_ HKEY hKey, _In_opt_z_ LPCSTR pszValue, _Ou /// \sa [RegLoadMUIString function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724890.aspx) /// template -static LSTATUS RegLoadMUIStringW(_In_ HKEY hKey, _In_opt_z_ LPCWSTR pszValue, _Out_ std::basic_string &sOut, _In_ DWORD Flags, _In_opt_z_ LPCWSTR pszDirectory) noexcept; +static LSTATUS RegLoadMUIStringW(_In_ HKEY hKey, _In_opt_z_ LPCWSTR pszValue, _Out_ std::basic_string &sOut, _In_ DWORD Flags, _In_opt_z_ LPCWSTR pszDirectory) noexcept +{ + LSTATUS lResult; + wchar_t szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t)]; + DWORD dwSize; + + Flags &= ~REG_MUI_STRING_TRUNCATE; + + // Try with stack buffer first. + lResult = RegLoadMUIStringW(hKey, pszValue, szStackBuffer, sizeof(szStackBuffer), &dwSize, Flags, pszDirectory); + if (lResult == ERROR_SUCCESS) { + // Copy from stack buffer. + sOut.assign(szStackBuffer, wcsnlen(szStackBuffer, dwSize/sizeof(wchar_t))); + } else if (lResult == ERROR_MORE_DATA) { + // Allocate buffer on heap and retry. + std::unique_ptr szBuffer(new wchar_t[(dwSize + sizeof(wchar_t) - 1)/sizeof(wchar_t)]); + sOut.assign(szBuffer.get(), (lResult = RegLoadMUIStringW(hKey, pszValue, szBuffer.get(), dwSize, &dwSize, Flags, pszDirectory)) == ERROR_SUCCESS ? wcsnlen(szBuffer.get(), dwSize/sizeof(wchar_t)) : 0); + } + + return lResult; +} #endif @@ -204,7 +632,25 @@ static LSTATUS RegLoadMUIStringW(_In_ HKEY hKey, _In_opt_z_ LPCWSTR pszValue, _O /// \sa [WideCharToMultiByte function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd374130.aspx) /// template -static _Success_(return != 0) int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cchWideChar) LPCWSTR lpWideCharStr, _In_ int cchWideChar, _Out_ std::basic_string &sMultiByteStr, _In_opt_z_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) noexcept; +static _Success_(return != 0) int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cchWideChar) LPCWSTR lpWideCharStr, _In_ int cchWideChar, _Out_ std::basic_string &sMultiByteStr, _In_opt_z_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) noexcept +{ + CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)]; + + // Try to convert to stack buffer first. + int cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar); + if (cch) { + // Copy from stack. Be careful not to include zero terminator. + sMultiByteStr.assign(szStackBuffer, cchWideChar != -1 ? strnlen(szStackBuffer, cch) : (size_t)cch - 1); + } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + // Query the required output size. Allocate buffer. Then convert again. + cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, NULL, 0, lpDefaultChar, lpUsedDefaultChar); + std::unique_ptr szBuffer(new CHAR[cch]); + cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szBuffer.get(), cch, lpDefaultChar, lpUsedDefaultChar); + sMultiByteStr.assign(szBuffer.get(), cchWideChar != -1 ? strnlen(szBuffer.get(), cch) : (size_t)cch - 1); + } + + return cch; +} /// /// Maps a UTF-16 (wide character) string to a std::vector. The new character vector is not necessarily from a multibyte character set. @@ -212,7 +658,24 @@ static _Success_(return != 0) int WideCharToMultiByte(_In_ UINT CodePage, _In_ D /// \sa [WideCharToMultiByte function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd374130.aspx) /// template -static _Success_(return != 0) int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cchWideChar) LPCWSTR lpWideCharStr, _In_ int cchWideChar, _Out_ std::vector &sMultiByteStr, _In_opt_z_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) noexcept; +static _Success_(return != 0) int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cchWideChar) LPCWSTR lpWideCharStr, _In_ int cchWideChar, _Out_ std::vector &sMultiByteStr, _In_opt_z_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) noexcept +{ + CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)]; + + // Try to convert to stack buffer first. + int cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar); + if (cch) { + // Copy from stack. + sMultiByteStr.assign(szStackBuffer, szStackBuffer + cch); + } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + // Query the required output size. Allocate buffer. Then convert again. + cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, NULL, 0, lpDefaultChar, lpUsedDefaultChar); + sMultiByteStr.resize(cch); + cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, sMultiByteStr.data(), cch, lpDefaultChar, lpUsedDefaultChar); + } + + return cch; +} /// /// Maps a UTF-16 (wide character) string to a std::string. The new character string is not necessarily from a multibyte character set. @@ -220,7 +683,25 @@ static _Success_(return != 0) int WideCharToMultiByte(_In_ UINT CodePage, _In_ D /// \sa [WideCharToMultiByte function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd374130.aspx) /// template -static _Success_(return != 0) int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _Out_ std::basic_string sWideCharStr, _Out_ std::basic_string &sMultiByteStr, _In_opt_z_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) noexcept; +static _Success_(return != 0) int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_ std::basic_string sWideCharStr, _Out_ std::basic_string &sMultiByteStr, _In_opt_z_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) noexcept +{ + CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)]; + + // Try to convert to stack buffer first. + int cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar); + if (cch) { + // Copy from stack. + sMultiByteStr.assign(szStackBuffer, cch); + } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + // Query the required output size. Allocate buffer. Then convert again. + cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), NULL, 0, lpDefaultChar, lpUsedDefaultChar); + std::unique_ptr szBuffer(new CHAR[cch]); + cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), szBuffer.get(), cch, lpDefaultChar, lpUsedDefaultChar); + sMultiByteStr.assign(szBuffer.get(), cch); + } + + return cch; +} /// /// Maps a UTF-16 (wide character) string to a std::string. The new character string is not necessarily from a multibyte character set. @@ -230,7 +711,28 @@ static _Success_(return != 0) int WideCharToMultiByte(_In_ UINT CodePage, _In_ D /// \sa [WideCharToMultiByte function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd374130.aspx) /// template -static _Success_(return != 0) int SecureWideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cchWideChar) LPCWSTR lpWideCharStr, _In_ int cchWideChar, _Out_ std::basic_string &sMultiByteStr, _In_opt_z_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) noexcept; +static _Success_(return != 0) int SecureWideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cchWideChar) LPCWSTR lpWideCharStr, _In_ int cchWideChar, _Out_ std::basic_string &sMultiByteStr, _In_opt_z_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) noexcept +{ + CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)]; + + // Try to convert to stack buffer first. + int cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar); + if (cch) { + // Copy from stack. Be careful not to include zero terminator. + sMultiByteStr.assign(szStackBuffer, cchWideChar != -1 ? strnlen(szStackBuffer, cch) : (size_t)cch - 1); + } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + // Query the required output size. Allocate buffer. Then convert again. + cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, NULL, 0, lpDefaultChar, lpUsedDefaultChar); + std::unique_ptr szBuffer(new CHAR[cch]); + cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szBuffer.get(), cch, lpDefaultChar, lpUsedDefaultChar); + sMultiByteStr.assign(szBuffer.get(), cchWideChar != -1 ? strnlen(szBuffer.get(), cch) : (size_t)cch - 1); + SecureZeroMemory(szBuffer.get(), sizeof(CHAR)*cch); + } + + SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer)); + + return cch; +} /// /// Maps a UTF-16 (wide character) string to a std::vector. The new character vector is not necessarily from a multibyte character set. @@ -240,7 +742,26 @@ static _Success_(return != 0) int SecureWideCharToMultiByte(_In_ UINT CodePage, /// \sa [WideCharToMultiByte function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd374130.aspx) /// template -static _Success_(return != 0) int SecureWideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cchWideChar) LPCWSTR lpWideCharStr, _In_ int cchWideChar, _Out_ std::vector &sMultiByteStr, _In_opt_z_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) noexcept; +static _Success_(return != 0) int SecureWideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cchWideChar) LPCWSTR lpWideCharStr, _In_ int cchWideChar, _Out_ std::vector &sMultiByteStr, _In_opt_z_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) noexcept +{ + CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)]; + + // Try to convert to stack buffer first. + int cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar); + if (cch) { + // Copy from stack. + sMultiByteStr.assign(szStackBuffer, szStackBuffer + cch); + } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + // Query the required output size. Allocate buffer. Then convert again. + cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, NULL, 0, lpDefaultChar, lpUsedDefaultChar); + sMultiByteStr.resize(cch); + cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, sMultiByteStr.data(), cch, lpDefaultChar, lpUsedDefaultChar); + } + + SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer)); + + return cch; +} /// /// Maps a UTF-16 (wide character) string to a std::string. The new character string is not necessarily from a multibyte character set. @@ -250,7 +771,28 @@ static _Success_(return != 0) int SecureWideCharToMultiByte(_In_ UINT CodePage, /// \sa [WideCharToMultiByte function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd374130.aspx) /// template -static _Success_(return != 0) int SecureWideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _Out_ std::basic_string sWideCharStr, _Out_ std::basic_string &sMultiByteStr, _In_opt_z_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) noexcept; +static _Success_(return != 0) int SecureWideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _Out_ std::basic_string sWideCharStr, _Out_ std::basic_string &sMultiByteStr, _In_opt_z_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) noexcept +{ + CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)]; + + // Try to convert to stack buffer first. + int cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar); + if (cch) { + // Copy from stack. + sMultiByteStr.assign(szStackBuffer, cch); + } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + // Query the required output size. Allocate buffer. Then convert again. + cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), NULL, 0, lpDefaultChar, lpUsedDefaultChar); + std::unique_ptr szBuffer(new CHAR[cch]); + cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), szBuffer.get(), cch, lpDefaultChar, lpUsedDefaultChar); + sMultiByteStr.assign(szBuffer.get(), cch); + SecureZeroMemory(szBuffer.get(), sizeof(CHAR)*cch); + } + + SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer)); + + return cch; +} /// /// Maps a character string to a UTF-16 (wide character) std::wstring. The character string is not necessarily from a multibyte character set. @@ -258,7 +800,25 @@ static _Success_(return != 0) int SecureWideCharToMultiByte(_In_ UINT CodePage, /// \sa [MultiByteToWideChar function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd319072.aspx) /// template -static _Success_(return != 0) int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cbMultiByte) LPCSTR lpMultiByteStr, _In_ int cbMultiByte, _Out_ std::basic_string &sWideCharStr) noexcept; +static _Success_(return != 0) int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cbMultiByte) LPCSTR lpMultiByteStr, _In_ int cbMultiByte, _Out_ std::basic_string &sWideCharStr) noexcept +{ + WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)]; + + // Try to convert to stack buffer first. + int cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szStackBuffer, _countof(szStackBuffer)); + if (cch) { + // Copy from stack. + sWideCharStr.assign(szStackBuffer, cbMultiByte != -1 ? wcsnlen(szStackBuffer, cch) : (size_t)cch - 1); + } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + // Query the required output size. Allocate buffer. Then convert again. + cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, NULL, 0); + std::unique_ptr szBuffer(new WCHAR[cch]); + cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szBuffer.get(), cch); + sWideCharStr.assign(szBuffer.get(), cbMultiByte != -1 ? wcsnlen(szBuffer.get(), cch) : (size_t)cch - 1); + } + + return cch; +} /// /// Maps a character string to a UTF-16 (wide character) std::vector. The character vector is not necessarily from a multibyte character set. @@ -266,7 +826,24 @@ static _Success_(return != 0) int MultiByteToWideChar(_In_ UINT CodePage, _In_ D /// \sa [MultiByteToWideChar function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd319072.aspx) /// template -static _Success_(return != 0) int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cbMultiByte) LPCSTR lpMultiByteStr, _In_ int cbMultiByte, _Out_ std::vector &sWideCharStr) noexcept; +static _Success_(return != 0) int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cbMultiByte) LPCSTR lpMultiByteStr, _In_ int cbMultiByte, _Out_ std::vector &sWideCharStr) noexcept +{ + WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)]; + + // Try to convert to stack buffer first. + int cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szStackBuffer, _countof(szStackBuffer)); + if (cch) { + // Copy from stack. + sWideCharStr.assign(szStackBuffer, szStackBuffer + cch); + } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + // Query the required output size. Allocate buffer. Then convert again. + cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, NULL, 0); + sWideCharStr.resize(cch); + cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, sWideCharStr.data(), cch); + } + + return cch; +} /// /// Maps a character string to a UTF-16 (wide character) std::wstring. The character string is not necessarily from a multibyte character set. @@ -274,7 +851,25 @@ static _Success_(return != 0) int MultiByteToWideChar(_In_ UINT CodePage, _In_ D /// \sa [MultiByteToWideChar function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd319072.aspx) /// template -static _Success_(return != 0) int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_ const std::basic_string &sMultiByteStr, _Out_ std::basic_string &sWideCharStr) noexcept; +static _Success_(return != 0) int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_ const std::basic_string &sMultiByteStr, _Out_ std::basic_string &sWideCharStr) noexcept +{ + WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)]; + + // Try to convert to stack buffer first. + int cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), szStackBuffer, _countof(szStackBuffer)); + if (cch) { + // Copy from stack. + sWideCharStr.assign(szStackBuffer, cch); + } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + // Query the required output size. Allocate buffer. Then convert again. + cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), NULL, 0); + std::unique_ptr szBuffer(new WCHAR[cch]); + cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), szBuffer.get(), cch); + sWideCharStr.assign(szBuffer.get(), cch); + } + + return cch; +} /// /// Maps a character string to a UTF-16 (wide character) std::wstring. The character string is not necessarily from a multibyte character set. @@ -284,7 +879,28 @@ static _Success_(return != 0) int MultiByteToWideChar(_In_ UINT CodePage, _In_ D /// \sa [MultiByteToWideChar function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd319072.aspx) /// template -static _Success_(return != 0) int SecureMultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cbMultiByte) LPCSTR lpMultiByteStr, _In_ int cbMultiByte, _Out_ std::basic_string &sWideCharStr) noexcept; +static _Success_(return != 0) int SecureMultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cbMultiByte) LPCSTR lpMultiByteStr, _In_ int cbMultiByte, _Out_ std::basic_string &sWideCharStr) noexcept +{ + WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)]; + + // Try to convert to stack buffer first. + int cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szStackBuffer, _countof(szStackBuffer)); + if (cch) { + // Copy from stack. + sWideCharStr.assign(szStackBuffer, cbMultiByte != -1 ? wcsnlen(szStackBuffer, cch) : (size_t)cch - 1); + } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + // Query the required output size. Allocate buffer. Then convert again. + cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, NULL, 0); + std::unique_ptr szBuffer(new WCHAR[cch]); + cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szBuffer.get(), cch); + sWideCharStr.assign(szBuffer.get(), cbMultiByte != -1 ? wcsnlen(szBuffer.get(), cch) : (size_t)cch - 1); + SecureZeroMemory(szBuffer.get(), sizeof(WCHAR)*cch); + } + + SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer)); + + return cch; +} /// /// Maps a character string to a UTF-16 (wide character) std::vector. The character vector is not necessarily from a multibyte character set. @@ -294,7 +910,26 @@ static _Success_(return != 0) int SecureMultiByteToWideChar(_In_ UINT CodePage, /// \sa [MultiByteToWideChar function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd319072.aspx) /// template -static _Success_(return != 0) int SecureMultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cbMultiByte) LPCSTR lpMultiByteStr, _In_ int cbMultiByte, _Out_ std::vector &sWideCharStr) noexcept; +static _Success_(return != 0) int SecureMultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cbMultiByte) LPCSTR lpMultiByteStr, _In_ int cbMultiByte, _Out_ std::vector &sWideCharStr) noexcept +{ + WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)]; + + // Try to convert to stack buffer first. + int cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szStackBuffer, _countof(szStackBuffer)); + if (cch) { + // Copy from stack. + sWideCharStr.assign(szStackBuffer, szStackBuffer + cch); + } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + // Query the required output size. Allocate buffer. Then convert again. + cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, NULL, 0); + sWideCharStr.resize(cch); + cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, sWideCharStr.data(), cch); + } + + SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer)); + + return cch; +} /// /// Maps a character string to a UTF-16 (wide character) std::wstring. The character string is not necessarily from a multibyte character set. @@ -304,7 +939,28 @@ static _Success_(return != 0) int SecureMultiByteToWideChar(_In_ UINT CodePage, /// \sa [MultiByteToWideChar function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd319072.aspx) /// template -static _Success_(return != 0) int SecureMultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_ const std::basic_string &sMultiByteStr, _Out_ std::basic_string &sWideCharStr) noexcept; +static _Success_(return != 0) int SecureMultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_ const std::basic_string &sMultiByteStr, _Out_ std::basic_string &sWideCharStr) noexcept +{ + WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)]; + + // Try to convert to stack buffer first. + int cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), szStackBuffer, _countof(szStackBuffer)); + if (cch) { + // Copy from stack. + sWideCharStr.assign(szStackBuffer, cch); + } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + // Query the required output size. Allocate buffer. Then convert again. + cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), NULL, 0); + std::unique_ptr szBuffer(new WCHAR[cch]); + cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), szBuffer.get(), cch); + sWideCharStr.assign(szBuffer.get(), cch); + SecureZeroMemory(szBuffer.get(), sizeof(WCHAR)*cch); + } + + SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer)); + + return cch; +} /// /// Normalizes characters of a text string according to Unicode 4.0 TR#15. @@ -312,7 +968,42 @@ static _Success_(return != 0) int SecureMultiByteToWideChar(_In_ UINT CodePage, /// \sa [NormalizeString function](https://docs.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-normalizestring) /// template -static _Success_(return > 0) int NormalizeString(_In_ NORM_FORM NormForm, _In_ LPCWSTR lpSrcString, _In_ int cwSrcLength, _Out_ std::basic_string &sDstString) noexcept; +static _Success_(return > 0) int NormalizeString(_In_ NORM_FORM NormForm, _In_ LPCWSTR lpSrcString, _In_ int cwSrcLength, _Out_ std::basic_string &sDstString) noexcept +{ + WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)]; + + // Try to convert to stack buffer first. + int cch = ::NormalizeString(NormForm, lpSrcString, cwSrcLength, szStackBuffer, _countof(szStackBuffer)); + if (cch > 0) { + // Copy from stack. + sDstString.assign(szStackBuffer, cwSrcLength != -1 ? wcsnlen(szStackBuffer, cch) : (size_t)cch - 1); + } else { + switch (::GetLastError()) { + case ERROR_INSUFFICIENT_BUFFER: + for (int i = 10; i--;) { + // Allocate buffer. Then convert again. + cch = -cch; + std::unique_ptr szBuffer(new WCHAR[cch]); + cch = ::NormalizeString(NormForm, lpSrcString, cwSrcLength, szBuffer.get(), cch); + if (cch > 0) { + sDstString.assign(szBuffer.get(), cwSrcLength != -1 ? wcsnlen(szStackBuffer, cch) : (size_t)cch - 1); + break; + } + if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + sDstString.clear(); + break; + } + } + break; + + case ERROR_SUCCESS: + sDstString.clear(); + break; + } + } + + return cch; +} /// /// Normalizes characters of a text string according to Unicode 4.0 TR#15. @@ -320,11 +1011,56 @@ static _Success_(return > 0) int NormalizeString(_In_ NORM_FORM NormForm, _In_ L /// \sa [NormalizeString function](https://docs.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-normalizestring) /// template -static _Success_(return > 0) int NormalizeString(_In_ NORM_FORM NormForm, _In_ const std::basic_string &sSrcString, _Out_ std::basic_string &sDstString) noexcept; +static _Success_(return > 0) int NormalizeString(_In_ NORM_FORM NormForm, _In_ const std::basic_string &sSrcString, _Out_ std::basic_string &sDstString) noexcept +{ + WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)]; + + // Try to convert to stack buffer first. + int cch = ::NormalizeString(NormForm, sSrcString.c_str(), (int)sSrcString.length(), szStackBuffer, _countof(szStackBuffer)); + if (cch > 0) { + // Copy from stack. + sDstString.assign(szStackBuffer, cch); + } else { + switch (::GetLastError()) { + case ERROR_INSUFFICIENT_BUFFER: + for (int i = 10; i--;) { + // Allocate buffer. Then convert again. + cch = -cch; + std::unique_ptr szBuffer(new WCHAR[cch]); + cch = ::NormalizeString(NormForm, sSrcString.c_str(), (int)sSrcString.length(), szBuffer.get(), cch); + if (cch > 0) { + sDstString.assign(szBuffer.get(), cch); + break; + } + if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + sDstString.clear(); + break; + } + } + break; + + case ERROR_SUCCESS: + sDstString.clear(); + break; + } + } + + return cch; +} /// @copydoc LoadStringW template -static _Success_(return != 0) int WINAPI LoadStringA(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_ std::basic_string &sBuffer) noexcept; +static _Success_(return != 0) int WINAPI LoadStringA(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_ std::basic_string &sBuffer) noexcept +{ + // Get read-only pointer to string resource. + LPCSTR pszStr; + int i = LoadStringA(hInstance, uID, reinterpret_cast(&pszStr), 0); + if (i) { + sBuffer.assign(pszStr, i); + return i; + } else + return 0; +} /// /// Loads a string resource from the executable file associated with a specified module. @@ -332,39 +1068,83 @@ static _Success_(return != 0) int WINAPI LoadStringA(_In_opt_ HINSTANCE hInstanc /// \sa [LoadString function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms647486.aspx) /// template -static _Success_(return != 0) int WINAPI LoadStringW(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_ std::basic_string &sBuffer) noexcept; +static _Success_(return != 0) int WINAPI LoadStringW(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_ std::basic_string &sBuffer) noexcept +{ + // Get read-only pointer to string resource. + LPCWSTR pszStr; + int i = LoadStringW(hInstance, uID, reinterpret_cast(&pszStr), 0); + if (i) { + sBuffer.assign(pszStr, i); + return i; + } else + return 0; +} /// /// Formats and sends a string to the debugger for display. /// /// \sa [OutputDebugString function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363362.aspx) /// -static VOID OutputDebugStrV(_In_z_ LPCSTR lpOutputString, _In_ va_list arg) noexcept; +static VOID OutputDebugStrV(_In_z_ LPCSTR lpOutputString, _In_ va_list arg) noexcept +{ + std::string str; + try { vsprintf(str, lpOutputString, arg); } catch (...) { return; } + OutputDebugStringA(str.c_str()); +} /// /// Formats and sends a string to the debugger for display. /// /// \sa [OutputDebugString function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363362.aspx) /// -static VOID OutputDebugStrV(_In_z_ LPCWSTR lpOutputString, _In_ va_list arg) noexcept; +static VOID OutputDebugStrV(_In_z_ LPCWSTR lpOutputString, _In_ va_list arg) noexcept +{ + std::wstring str; + try { vsprintf(str, lpOutputString, arg); } catch (...) { return; } + OutputDebugStringW(str.c_str()); +} /// /// Formats and sends a string to the debugger for display. /// /// \sa [OutputDebugString function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363362.aspx) /// -static VOID OutputDebugStr(_In_z_ LPCSTR lpOutputString, ...) noexcept; +static VOID OutputDebugStr(_In_z_ LPCSTR lpOutputString, ...) noexcept +{ + va_list arg; + va_start(arg, lpOutputString); + OutputDebugStrV(lpOutputString, arg); + va_end(arg); +} /// /// Formats and sends a string to the debugger for display. /// /// \sa [OutputDebugString function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363362.aspx) /// -static VOID OutputDebugStr(_In_z_ LPCWSTR lpOutputString, ...) noexcept; +static VOID OutputDebugStr(_In_z_ LPCWSTR lpOutputString, ...) noexcept +{ + va_list arg; + va_start(arg, lpOutputString); + OutputDebugStrV(lpOutputString, arg); + va_end(arg); +} /// @copydoc GetDateFormatW() template -static _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 &sDate) noexcept; +static _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 &sDate) noexcept +{ + int iResult = GetDateFormatA(Locale, dwFlags, lpDate, lpFormat, NULL, 0); + if (iResult) { + // Allocate buffer on heap and retry. + std::unique_ptr szBuffer(new char[iResult]); + iResult = GetDateFormatA(Locale, dwFlags, lpDate, lpFormat, szBuffer.get(), iResult); + sDate.assign(szBuffer.get(), iResult ? iResult - 1 : 0); + return iResult; + } + + return iResult; +} /// /// Formats a date as a date string for a locale specified by the locale identifier. The function formats either a specified date or the local system date. @@ -372,11 +1152,54 @@ static _Success_(return != 0) int GetDateFormatA(_In_ LCID Locale, _In_ DWORD dw /// \sa [GetDateFormat function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd318086.aspx) /// template -static _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 &sDate) noexcept; +static _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 &sDate) noexcept +{ + int iResult = GetDateFormatW(Locale, dwFlags, lpDate, lpFormat, NULL, 0); + if (iResult) { + // Allocate buffer on heap and retry. + std::unique_ptr szBuffer(new wchar_t[iResult]); + iResult = GetDateFormatW(Locale, dwFlags, lpDate, lpFormat, szBuffer.get(), iResult); + sDate.assign(szBuffer.get(), iResult ? iResult - 1 : 0); + return iResult; + } + + return iResult; +} /// @copydoc LookupAccountSidW() template -static _Success_(return != 0) BOOL LookupAccountSidA(_In_opt_z_ LPCSTR lpSystemName, _In_ PSID lpSid, _Out_opt_ std::basic_string *sName, _Out_opt_ std::basic_string *sReferencedDomainName, _Out_ PSID_NAME_USE peUse) noexcept; +static _Success_(return != 0) BOOL LookupAccountSidA(_In_opt_z_ LPCSTR lpSystemName, _In_ PSID lpSid, _Out_opt_ std::basic_string *sName, _Out_opt_ std::basic_string *sReferencedDomainName, _Out_ PSID_NAME_USE peUse) noexcept +{ + assert(0); // TODO: Test this code. + + DWORD dwNameLen = 0, dwRefDomainLen = 0; + + if (LookupAccountSidA(lpSystemName, lpSid, + NULL, &dwNameLen , + NULL, &dwRefDomainLen, + peUse)) + { + // Name and domain is blank. + if (sName ) sName ->clear(); + if (sReferencedDomainName) sReferencedDomainName->clear(); + return TRUE; + } else if (GetLastError() == ERROR_MORE_DATA) { + // Allocate on heap and retry. + std::unique_ptr bufName (new char[dwNameLen ]); + std::unique_ptr bufRefDomain(new char[dwRefDomainLen]); + if (LookupAccountSidA(lpSystemName, lpSid, + bufName .get(), &dwNameLen , + bufRefDomain.get(), &dwRefDomainLen, + peUse)) + { + if (sName ) sName ->assign(bufName .get(), dwNameLen - 1); + if (sReferencedDomainName) sReferencedDomainName->assign(bufRefDomain.get(), dwRefDomainLen - 1); + return TRUE; + } + } + + return FALSE; +} /// /// Retrieves the name of the account for this SID and the name of the first domain on which this SID is found. @@ -384,7 +1207,38 @@ static _Success_(return != 0) BOOL LookupAccountSidA(_In_opt_z_ LPCSTR lpSystemN /// \sa [LookupAccountSid function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379166.aspx) /// template -static _Success_(return != 0) BOOL LookupAccountSidW(_In_opt_z_ LPCWSTR lpSystemName, _In_ PSID lpSid, _Out_opt_ std::basic_string *sName, _Out_opt_ std::basic_string *sReferencedDomainName, _Out_ PSID_NAME_USE peUse) noexcept; +static _Success_(return != 0) BOOL LookupAccountSidW(_In_opt_z_ LPCWSTR lpSystemName, _In_ PSID lpSid, _Out_opt_ std::basic_string *sName, _Out_opt_ std::basic_string *sReferencedDomainName, _Out_ PSID_NAME_USE peUse) noexcept +{ + assert(0); // TODO: Test this code. + + DWORD dwNameLen = 0, dwRefDomainLen = 0; + + if (LookupAccountSidW(lpSystemName, lpSid, + NULL, &dwNameLen , + NULL, &dwRefDomainLen, + peUse)) + { + // Name and domain is blank. + if (sName ) sName ->clear(); + if (sReferencedDomainName) sReferencedDomainName->clear(); + return TRUE; + } else if (GetLastError() == ERROR_MORE_DATA) { + // Allocate on heap and retry. + std::unique_ptr bufName (new wchar_t[dwNameLen ]); + std::unique_ptr bufRefDomain(new wchar_t[dwRefDomainLen]); + if (LookupAccountSidW(lpSystemName, lpSid, + bufName .get(), &dwNameLen , + bufRefDomain.get(), &dwRefDomainLen, + peUse)) + { + if (sName ) sName ->assign(bufName .get(), dwNameLen - 1); + if (sReferencedDomainName) sReferencedDomainName->assign(bufRefDomain.get(), dwRefDomainLen - 1); + return TRUE; + } + } + + return FALSE; +} /// /// Retrieves a specified type of information about an access token. The calling process must have appropriate access rights to obtain the information. @@ -392,7 +1246,31 @@ static _Success_(return != 0) BOOL LookupAccountSidW(_In_opt_z_ LPCWSTR lpSystem /// \sa [GetTokenInformation function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa446671.aspx) /// template -static _Success_(return != 0) BOOL GetTokenInformation(_In_ HANDLE TokenHandle, _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, _Out_ std::unique_ptr<_Ty> &TokenInformation) noexcept; +static _Success_(return != 0) BOOL GetTokenInformation(_In_ HANDLE TokenHandle, _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, _Out_ std::unique_ptr<_Ty> &TokenInformation) noexcept +{ + BYTE szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(BYTE)]; + DWORD dwSize; + + if (GetTokenInformation(TokenHandle, TokenInformationClass, szStackBuffer, sizeof(szStackBuffer), &dwSize)) { + // The stack buffer was big enough to retrieve complete data. Alloc and copy. + TokenInformation.reset((_Ty*)(new BYTE[dwSize / sizeof(BYTE)])); + if (!TokenInformation) { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + memcpy(TokenInformation.get(), szStackBuffer, dwSize); + return TRUE; + } else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + // The stack buffer was too small to retrieve complete data. Alloc and retry. + TokenInformation.reset((_Ty*)(new BYTE[dwSize / sizeof(BYTE)])); + if (!TokenInformation) { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + return GetTokenInformation(TokenHandle, TokenInformationClass, TokenInformation.get(), dwSize, &dwSize); + } else + return FALSE; +} /// /// Retrieves the full name of the executable image for the specified process. @@ -400,7 +1278,28 @@ static _Success_(return != 0) BOOL GetTokenInformation(_In_ HANDLE TokenHandle, /// \sa [QueryFullProcessImageNameA function](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-queryfullprocessimagenamea) /// template -static _Success_(return != 0) BOOL QueryFullProcessImageNameA(_In_ HANDLE hProcess, _In_ DWORD dwFlags, _Inout_ std::basic_string& sExeName); +static _Success_(return != 0) BOOL QueryFullProcessImageNameA(_In_ HANDLE hProcess, _In_ DWORD dwFlags, _Inout_ std::basic_string& sExeName) +{ + char szStackBuffer[WINSTD_STACK_BUFFER_BYTES / sizeof(char)]; + DWORD dwSize = _countof(szStackBuffer); + + // Try with stack buffer first. + if (::QueryFullProcessImageNameA(hProcess, dwFlags, szStackBuffer, &dwSize)) { + // Copy from stack. + sExeName.assign(szStackBuffer, dwSize); + return TRUE; + } + for (DWORD dwCapacity = 2 * WINSTD_STACK_BUFFER_BYTES / sizeof(char); GetLastError() == ERROR_INSUFFICIENT_BUFFER; dwCapacity *= 2) { + // Allocate on heap and retry. + std::unique_ptr szBuffer(new char[dwCapacity]); + dwSize = dwCapacity; + if (::QueryFullProcessImageNameA(hProcess, dwFlags, szBuffer.get(), &dwSize)) { + sExeName.assign(szBuffer.get(), dwSize); + return TRUE; + } + } + return FALSE; +} /// /// Retrieves the full name of the executable image for the specified process. @@ -408,12 +1307,32 @@ static _Success_(return != 0) BOOL QueryFullProcessImageNameA(_In_ HANDLE hProce /// \sa [QueryFullProcessImageNameW function](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-queryfullprocessimagenamew) /// template -static _Success_(return != 0) BOOL QueryFullProcessImageNameW(_In_ HANDLE hProcess, _In_ DWORD dwFlags, _Inout_ std::basic_string& sExeName); +static _Success_(return != 0) BOOL QueryFullProcessImageNameW(_In_ HANDLE hProcess, _In_ DWORD dwFlags, _Inout_ std::basic_string& sExeName) +{ + wchar_t szStackBuffer[WINSTD_STACK_BUFFER_BYTES / sizeof(wchar_t)]; + DWORD dwSize = _countof(szStackBuffer); + + // Try with stack buffer first. + if (::QueryFullProcessImageNameW(hProcess, dwFlags, szStackBuffer, &dwSize)) { + // Copy from stack. + sExeName.assign(szStackBuffer, dwSize); + return TRUE; + } + for (DWORD dwCapacity = 2 * WINSTD_STACK_BUFFER_BYTES / sizeof(wchar_t); GetLastError() == ERROR_INSUFFICIENT_BUFFER; dwCapacity *= 2) { + // Allocate on heap and retry. + std::unique_ptr szBuffer(new wchar_t[dwCapacity]); + dwSize = dwCapacity; + if (::QueryFullProcessImageNameW(hProcess, dwFlags, szBuffer.get(), &dwSize)) { + sExeName.assign(szBuffer.get(), dwSize); + return TRUE; + } + } + return FALSE; +} /// @} -#pragma once - +#pragma warning(pop) namespace winstd { @@ -452,7 +1371,6 @@ namespace winstd } }; - /// /// Module handle wrapper /// @@ -503,7 +1421,6 @@ namespace winstd } }; - /// /// Process handle wrapper /// @@ -530,7 +1447,6 @@ namespace winstd } }; - /// /// File handle wrapper /// @@ -557,7 +1473,6 @@ namespace winstd } }; - /// /// Event handle wrapper /// @@ -603,7 +1518,6 @@ namespace winstd } }; - /// /// Critical section wrapper /// @@ -651,7 +1565,6 @@ namespace winstd CRITICAL_SECTION m_data; ///< Critical section struct }; - /// /// Find-file handle wrapper /// @@ -702,7 +1615,6 @@ namespace winstd } }; - /// /// Heap handle wrapper /// @@ -799,7 +1711,6 @@ namespace winstd } }; - /// /// HeapAlloc allocator /// @@ -916,7 +1827,6 @@ namespace winstd HANDLE m_heap; ///< Heap handle }; - /// /// Activates given activation context in constructor and deactivates it in destructor /// @@ -954,7 +1864,6 @@ namespace winstd ULONG_PTR m_cookie; ///< Cookie for context deactivation }; - /// /// Lets the calling thread impersonate the security context of a logged-on user /// @@ -991,7 +1900,6 @@ namespace winstd BOOL m_cookie; ///< Did impersonation succeed? }; - /// /// Console control handler stack management /// @@ -1029,7 +1937,6 @@ namespace winstd PHANDLER_ROUTINE m_handler; ///< Pointer to console control handler }; - /// /// Memory in virtual address space of a process handle wrapper /// @@ -1148,7 +2055,6 @@ namespace winstd HANDLE m_proc; ///< Handle of memory's process }; - /// /// Registry wrapper class /// @@ -1280,7 +2186,6 @@ namespace winstd } }; - /// /// SID wrapper class /// @@ -1312,7 +2217,6 @@ namespace winstd } }; - /// /// PROCESS_INFORMATION struct wrapper /// @@ -1353,1124 +2257,3 @@ namespace winstd /// @} } - - -#pragma warning(push) -#pragma warning(disable: 4505) // Don't warn on unused code - -template -static DWORD GetModuleFileNameA(_In_opt_ HMODULE hModule, _Out_ std::basic_string &sValue) noexcept -{ - assert(0); // TODO: Test this code. - - char szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(char)]; - - // Try with stack buffer first. - DWORD dwResult = ::GetModuleFileNameA(hModule, szStackBuffer, _countof(szStackBuffer)); - if (dwResult < _countof(szStackBuffer)) { - // Copy from stack. - sValue.assign(szStackBuffer, dwResult); - return dwResult; - } else { - for (DWORD dwCapacity = 2*WINSTD_STACK_BUFFER_BYTES/sizeof(char);; dwCapacity *= 2) { - // Allocate on heap and retry. - std::unique_ptr szBuffer(new char[dwCapacity]); - dwResult = ::GetModuleFileNameA(hModule, szBuffer.get(), dwCapacity); - if (dwResult < dwCapacity) { - sValue.assign(szBuffer.get(), dwResult); - return dwResult; - } - } - } -} - - -template -static DWORD GetModuleFileNameW(_In_opt_ HMODULE hModule, _Out_ std::basic_string &sValue) noexcept -{ - wchar_t szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t)]; - - // Try with stack buffer first. - DWORD dwResult = ::GetModuleFileNameW(hModule, szStackBuffer, _countof(szStackBuffer)); - if (dwResult < _countof(szStackBuffer)) { - // Copy from stack. - sValue.assign(szStackBuffer, dwResult); - return dwResult; - } else { - for (DWORD dwCapacity = 2*WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t);; dwCapacity *= 2) { - // Allocate on heap and retry. - std::unique_ptr szBuffer(new wchar_t[dwCapacity]); - dwResult = ::GetModuleFileNameW(hModule, szBuffer.get(), dwCapacity); - if (dwResult < dwCapacity) { - sValue.assign(szBuffer.get(), dwResult); - return dwResult; - } - } - } -} - - -template -static _Success_(return != 0) int GetWindowTextA(_In_ HWND hWnd, _Out_ std::basic_string &sValue) noexcept -{ - assert(0); // TODO: Test this code. - - int iResult; - - // Query the final string length first. - iResult = ::GetWindowTextLengthA(hWnd); - if (iResult > 0) { - if (++iResult < WINSTD_STACK_BUFFER_BYTES/sizeof(char)) { - // Read string data to stack. - char szBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(char)]; - iResult = ::GetWindowTextA(hWnd, szBuffer, _countof(szBuffer)); - sValue.assign(szBuffer, iResult); - } else { - // Allocate buffer on heap and read the string data into it. - std::unique_ptr szBuffer(new char[++iResult]); - iResult = ::GetWindowTextA(hWnd, szBuffer.get(), iResult); - sValue.assign(szBuffer.get(), iResult); - } - return iResult; - } - - sValue.clear(); - return 0; -} - - -template -static _Success_(return != 0) int GetWindowTextW(_In_ HWND hWnd, _Out_ std::basic_string &sValue) noexcept -{ - assert(0); // TODO: Test this code. - - int iResult; - - // Query the final string length first. - iResult = ::GetWindowTextLengthW(hWnd); - if (iResult > 0) { - if (++iResult < WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t)) { - // Read string data to stack. - wchar_t szBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t)]; - iResult = ::GetWindowTextW(hWnd, szBuffer, _countof(szBuffer)); - sValue.assign(szBuffer, iResult); - } else { - // Allocate buffer on heap and read the string data into it. - std::unique_ptr szBuffer(new wchar_t[++iResult]); - iResult = ::GetWindowTextW(hWnd, szBuffer.get(), iResult); - sValue.assign(szBuffer.get(), iResult); - } - return iResult; - } - - sValue.clear(); - return 0; -} - - -template -static _Success_(return != 0) BOOL GetFileVersionInfoA(_In_z_ LPCSTR lptstrFilename, __reserved DWORD dwHandle, _Out_ std::vector<_Ty, _Ax> &aValue) noexcept -{ - assert(0); // TODO: Test this code. - - // Get version info size. - DWORD dwVerInfoSize = ::GetFileVersionInfoSizeA(lptstrFilename, &dwHandle); - if (dwVerInfoSize != 0) { - // Read version info. - aValue.resize((dwVerInfoSize + sizeof(_Ty) - 1) / sizeof(_Ty)); - return ::GetFileVersionInfoA(lptstrFilename, dwHandle, dwVerInfoSize, aValue.data()); - } else - return FALSE; -} - - -template -static _Success_(return != 0) BOOL GetFileVersionInfoW(_In_z_ LPCWSTR lptstrFilename, __reserved DWORD dwHandle, _Out_ std::vector<_Ty, _Ax> &aValue) noexcept -{ - assert(0); // TODO: Test this code. - - // Get version info size. - DWORD dwVerInfoSize = ::GetFileVersionInfoSizeW(lptstrFilename, &dwHandle); - if (dwVerInfoSize != 0) { - // Read version info. - aValue.resize((dwVerInfoSize + sizeof(_Ty) - 1) / sizeof(_Ty)); - return ::GetFileVersionInfoW(lptstrFilename, dwHandle, dwVerInfoSize, aValue.data()); - } else - return FALSE; -} - - -template -static _Success_(return != 0) DWORD ExpandEnvironmentStringsA(_In_z_ LPCSTR lpSrc, _Out_ std::basic_string &sValue) noexcept -{ - assert(0); // TODO: Test this code. - - for (DWORD dwSizeOut = (DWORD)strlen(lpSrc) + 0x100;;) { - DWORD dwSizeIn = dwSizeOut; - std::unique_ptr szBuffer(new char[(size_t)dwSizeIn + 2]); // Note: ANSI version requires one extra char. - dwSizeOut = ::ExpandEnvironmentStringsA(lpSrc, szBuffer.get(), dwSizeIn); - if (dwSizeOut == 0) { - // Error or zero-length input. - break; - } else if (dwSizeOut <= dwSizeIn) { - // The buffer was sufficient. - sValue.assign(szBuffer.get(), dwSizeOut - 1); - return dwSizeOut; - } - } - - sValue.clear(); - return 0; -} - - -template -static _Success_(return != 0) DWORD ExpandEnvironmentStringsW(_In_z_ LPCWSTR lpSrc, _Out_ std::basic_string &sValue) noexcept -{ - for (DWORD dwSizeOut = (DWORD)wcslen(lpSrc) + 0x100;;) { - DWORD dwSizeIn = dwSizeOut; - std::unique_ptr szBuffer(new wchar_t[(size_t)dwSizeIn + 1]); - dwSizeOut = ::ExpandEnvironmentStringsW(lpSrc, szBuffer.get(), dwSizeIn); - if (dwSizeOut == 0) { - // Error or zero-length input. - break; - } else if (dwSizeOut <= dwSizeIn) { - // The buffer was sufficient. - sValue.assign(szBuffer.get(), dwSizeOut - 1); - return dwSizeOut; - } - } - - sValue.clear(); - return 0; -} - - -template -static VOID GuidToStringA(_In_ LPCGUID lpGuid, _Out_ std::basic_string &str) noexcept -{ - assert(0); // TODO: Test this code. - - sprintf(str, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", - lpGuid->Data1, - lpGuid->Data2, - lpGuid->Data3, - lpGuid->Data4[0], lpGuid->Data4[1], - lpGuid->Data4[2], lpGuid->Data4[3], lpGuid->Data4[4], lpGuid->Data4[5], lpGuid->Data4[6], lpGuid->Data4[7]); -} - - -template -static VOID GuidToStringW(_In_ LPCGUID lpGuid, _Out_ std::basic_string &str) noexcept -{ - assert(0); // TODO: Test this code. - - sprintf(str, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", - lpGuid->Data1, - lpGuid->Data2, - lpGuid->Data3, - lpGuid->Data4[0], lpGuid->Data4[1], - lpGuid->Data4[2], lpGuid->Data4[3], lpGuid->Data4[4], lpGuid->Data4[5], lpGuid->Data4[6], lpGuid->Data4[7]); -} - - -static _Success_(return) BOOL StringToGuidA(_In_z_ LPCSTR lpszGuid, _Out_ LPGUID lpGuid, _Out_opt_ LPCSTR *lpszGuidEnd) noexcept -{ - GUID g; - LPSTR lpszEnd; - unsigned long ulTmp; - unsigned long long ullTmp; - - if (!lpszGuid || !lpGuid || *lpszGuid != '{') return FALSE; - lpszGuid++; - - g.Data1 = strtoul(lpszGuid, &lpszEnd, 16); - if (errno == ERANGE) return FALSE; - lpszGuid = lpszEnd; - - if (*lpszGuid != '-') return FALSE; - lpszGuid++; - - ulTmp = strtoul(lpszGuid, &lpszEnd, 16); - if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE; - g.Data2 = static_cast(ulTmp); - lpszGuid = lpszEnd; - - if (*lpszGuid != '-') return FALSE; - lpszGuid++; - - ulTmp = strtoul(lpszGuid, &lpszEnd, 16); - if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE; - g.Data3 = static_cast(ulTmp); - lpszGuid = lpszEnd; - - if (*lpszGuid != '-') return FALSE; - lpszGuid++; - - ulTmp = strtoul(lpszGuid, &lpszEnd, 16); - if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE; - g.Data4[0] = static_cast((ulTmp >> 8) & 0xff); - g.Data4[1] = static_cast( ulTmp & 0xff); - lpszGuid = lpszEnd; - - if (*lpszGuid != '-') return FALSE; - lpszGuid++; - - ullTmp = _strtoui64(lpszGuid, &lpszEnd, 16); - if (errno == ERANGE || ullTmp > 0xFFFFFFFFFFFF) return FALSE; - g.Data4[2] = static_cast((ullTmp >> 40) & 0xff); - g.Data4[3] = static_cast((ullTmp >> 32) & 0xff); - g.Data4[4] = static_cast((ullTmp >> 24) & 0xff); - g.Data4[5] = static_cast((ullTmp >> 16) & 0xff); - g.Data4[6] = static_cast((ullTmp >> 8) & 0xff); - g.Data4[7] = static_cast( ullTmp & 0xff); - lpszGuid = lpszEnd; - - if (*lpszGuid != '}') return FALSE; - lpszGuid++; - - if (lpszGuidEnd) - *lpszGuidEnd = lpszGuid; - - *lpGuid = g; - return TRUE; -} - - -static _Success_(return) BOOL StringToGuidW(_In_z_ LPCWSTR lpszGuid, _Out_ LPGUID lpGuid, _Out_opt_ LPCWSTR *lpszGuidEnd) noexcept -{ - GUID g; - LPWSTR lpszEnd; - unsigned long ulTmp; - unsigned long long ullTmp; - - if (!lpszGuid || !lpGuid || *lpszGuid != '{') return FALSE; - lpszGuid++; - - g.Data1 = wcstoul(lpszGuid, &lpszEnd, 16); - if (errno == ERANGE) return FALSE; - lpszGuid = lpszEnd; - - if (*lpszGuid != '-') return FALSE; - lpszGuid++; - - ulTmp = wcstoul(lpszGuid, &lpszEnd, 16); - if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE; - g.Data2 = static_cast(ulTmp); - lpszGuid = lpszEnd; - - if (*lpszGuid != '-') return FALSE; - lpszGuid++; - - ulTmp = wcstoul(lpszGuid, &lpszEnd, 16); - if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE; - g.Data3 = static_cast(ulTmp); - lpszGuid = lpszEnd; - - if (*lpszGuid != '-') return FALSE; - lpszGuid++; - - ulTmp = wcstoul(lpszGuid, &lpszEnd, 16); - if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE; - g.Data4[0] = static_cast((ulTmp >> 8) & 0xff); - g.Data4[1] = static_cast( ulTmp & 0xff); - lpszGuid = lpszEnd; - - if (*lpszGuid != '-') return FALSE; - lpszGuid++; - - ullTmp = _wcstoui64(lpszGuid, &lpszEnd, 16); - if (errno == ERANGE || ullTmp > 0xFFFFFFFFFFFF) return FALSE; - g.Data4[2] = static_cast((ullTmp >> 40) & 0xff); - g.Data4[3] = static_cast((ullTmp >> 32) & 0xff); - g.Data4[4] = static_cast((ullTmp >> 24) & 0xff); - g.Data4[5] = static_cast((ullTmp >> 16) & 0xff); - g.Data4[6] = static_cast((ullTmp >> 8) & 0xff); - g.Data4[7] = static_cast( ullTmp & 0xff); - lpszGuid = lpszEnd; - - if (*lpszGuid != '}') return FALSE; - lpszGuid++; - - if (lpszGuidEnd) - *lpszGuidEnd = lpszGuid; - - *lpGuid = g; - return TRUE; -} - - -template -static LSTATUS RegQueryStringValue(_In_ HKEY hReg, _In_z_ LPCSTR pszName, _Out_ std::basic_string &sValue) noexcept -{ - LSTATUS lResult; - BYTE aStackBuffer[WINSTD_STACK_BUFFER_BYTES]; - DWORD dwSize = sizeof(aStackBuffer), dwType; - - // Try with stack buffer first. - lResult = ::RegQueryValueExA(hReg, pszName, NULL, &dwType, aStackBuffer, &dwSize); - if (lResult == ERROR_SUCCESS) { - if (dwType == REG_SZ || dwType == REG_MULTI_SZ) { - // The value is REG_SZ or REG_MULTI_SZ. - dwSize /= sizeof(CHAR); - sValue.assign(reinterpret_cast(aStackBuffer), dwSize && reinterpret_cast(aStackBuffer)[dwSize - 1] == 0 ? dwSize - 1 : dwSize); - } else if (dwType == REG_EXPAND_SZ) { - // The value is REG_EXPAND_SZ. Expand it from stack buffer. - if (::ExpandEnvironmentStringsA(reinterpret_cast(aStackBuffer), sValue) == 0) - lResult = ::GetLastError(); - } else { - // The value is not a string type. - lResult = ERROR_INVALID_DATA; - } - } else if (lResult == ERROR_MORE_DATA) { - if (dwType == REG_SZ || dwType == REG_MULTI_SZ) { - // The value is REG_SZ or REG_MULTI_SZ. Read it now. - std::unique_ptr szBuffer(new CHAR[dwSize / sizeof(CHAR)]); - if ((lResult = ::RegQueryValueExA(hReg, pszName, NULL, NULL, reinterpret_cast(szBuffer.get()), &dwSize)) == ERROR_SUCCESS) { - dwSize /= sizeof(CHAR); - sValue.assign(szBuffer.get(), dwSize && szBuffer[dwSize - 1] == 0 ? dwSize - 1 : dwSize); - } - } else if (dwType == REG_EXPAND_SZ) { - // The value is REG_EXPAND_SZ. Read it and expand environment variables. - std::unique_ptr szBuffer(new CHAR[dwSize / sizeof(CHAR)]); - if ((lResult = ::RegQueryValueExA(hReg, pszName, NULL, NULL, reinterpret_cast(szBuffer.get()), &dwSize)) == ERROR_SUCCESS) { - if (::ExpandEnvironmentStringsA(szBuffer.get(), sValue) == 0) - lResult = ::GetLastError(); - } - } else { - // The value is not a string type. - lResult = ERROR_INVALID_DATA; - } - } - - return lResult; -} - - -template -static LSTATUS RegQueryStringValue(_In_ HKEY hReg, _In_z_ LPCWSTR pszName, _Out_ std::basic_string &sValue) noexcept -{ - LSTATUS lResult; - BYTE aStackBuffer[WINSTD_STACK_BUFFER_BYTES]; - DWORD dwSize = sizeof(aStackBuffer), dwType; - - // Try with stack buffer first. - lResult = ::RegQueryValueExW(hReg, pszName, NULL, &dwType, aStackBuffer, &dwSize); - if (lResult == ERROR_SUCCESS) { - if (dwType == REG_SZ || dwType == REG_MULTI_SZ) { - // The value is REG_SZ or REG_MULTI_SZ. - dwSize /= sizeof(WCHAR); - sValue.assign(reinterpret_cast(aStackBuffer), dwSize && reinterpret_cast(aStackBuffer)[dwSize - 1] == 0 ? dwSize - 1 : dwSize); - } else if (dwType == REG_EXPAND_SZ) { - // The value is REG_EXPAND_SZ. Expand it from stack buffer. - if (::ExpandEnvironmentStringsW(reinterpret_cast(aStackBuffer), sValue) == 0) - lResult = ::GetLastError(); - } else { - // The value is not a string type. - lResult = ERROR_INVALID_DATA; - } - } else if (lResult == ERROR_MORE_DATA) { - if (dwType == REG_SZ || dwType == REG_MULTI_SZ) { - // The value is REG_SZ or REG_MULTI_SZ. Read it now. - std::unique_ptr szBuffer(new WCHAR[dwSize / sizeof(WCHAR)]); - if ((lResult = ::RegQueryValueExW(hReg, pszName, NULL, NULL, reinterpret_cast(szBuffer.get()), &dwSize)) == ERROR_SUCCESS) { - dwSize /= sizeof(WCHAR); - sValue.assign(szBuffer.get(), dwSize && szBuffer[dwSize - 1] == 0 ? dwSize - 1 : dwSize); - } - } else if (dwType == REG_EXPAND_SZ) { - // The value is REG_EXPAND_SZ. Read it and expand environment variables. - std::unique_ptr szBuffer(new WCHAR[dwSize / sizeof(WCHAR)]); - if ((lResult = ::RegQueryValueExW(hReg, pszName, NULL, NULL, reinterpret_cast(szBuffer.get()), &dwSize)) == ERROR_SUCCESS) { - if (::ExpandEnvironmentStringsW(szBuffer.get(), sValue) == 0) - lResult = ::GetLastError(); - } - } else { - // The value is not a string type. - lResult = ERROR_INVALID_DATA; - } - } - - return lResult; -} - - -template -static LSTATUS RegQueryValueExA(_In_ HKEY hKey, _In_opt_z_ LPCSTR lpValueName, __reserved LPDWORD lpReserved, _Out_opt_ LPDWORD lpType, _Out_ std::vector<_Ty, _Ax> &aData) noexcept -{ - LSTATUS lResult; - BYTE aStackBuffer[WINSTD_STACK_BUFFER_BYTES]; - DWORD dwSize = sizeof(aStackBuffer); - - // Try with stack buffer first. - lResult = RegQueryValueExA(hKey, lpValueName, lpReserved, lpType, aStackBuffer, &dwSize); - if (lResult == ERROR_SUCCESS) { - // Copy from stack buffer. - aData.resize((dwSize + sizeof(_Ty) - 1) / sizeof(_Ty)); - memcpy(aData.data(), aStackBuffer, dwSize); - } else if (lResult == ERROR_MORE_DATA) { - // Allocate buffer on heap and retry. - aData.resize((dwSize + sizeof(_Ty) - 1) / sizeof(_Ty)); - lResult = RegQueryValueExA(hKey, lpValueName, lpReserved, NULL, aData.data(), &dwSize); - } - - return lResult; -} - - -template -static LSTATUS RegQueryValueExW(_In_ HKEY hKey, _In_opt_z_ LPCWSTR lpValueName, __reserved LPDWORD lpReserved, _Out_opt_ LPDWORD lpType, _Out_ std::vector<_Ty, _Ax> &aData) noexcept -{ - LSTATUS lResult; - BYTE aStackBuffer[WINSTD_STACK_BUFFER_BYTES]; - DWORD dwSize = sizeof(aStackBuffer); - - // Try with stack buffer first. - lResult = RegQueryValueExW(hKey, lpValueName, lpReserved, lpType, aStackBuffer, &dwSize); - if (lResult == ERROR_SUCCESS) { - // Copy from stack buffer. - aData.resize((dwSize + sizeof(_Ty) - 1) / sizeof(_Ty)); - memcpy(aData.data(), aStackBuffer, dwSize); - } else if (lResult == ERROR_MORE_DATA) { - // Allocate buffer on heap and retry. - aData.resize((dwSize + sizeof(_Ty) - 1) / sizeof(_Ty)); - lResult = RegQueryValueExW(hKey, lpValueName, lpReserved, NULL, aData.data(), &dwSize); - } - - return lResult; -} - - -#if _WIN32_WINNT >= _WIN32_WINNT_VISTA - -template -static LSTATUS RegLoadMUIStringA(_In_ HKEY hKey, _In_opt_z_ LPCSTR pszValue, _Out_ std::basic_string &sOut, _In_ DWORD Flags, _In_opt_z_ LPCSTR pszDirectory) noexcept -{ - // According to "Remarks" section in MSDN documentation of RegLoadMUIString(), - // this function is defined but not implemented as ANSI variation. - assert(0); - return ERROR_CALL_NOT_IMPLEMENTED; -} - - -template -static LSTATUS RegLoadMUIStringW(_In_ HKEY hKey, _In_opt_z_ LPCWSTR pszValue, _Out_ std::basic_string &sOut, _In_ DWORD Flags, _In_opt_z_ LPCWSTR pszDirectory) noexcept -{ - LSTATUS lResult; - wchar_t szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(wchar_t)]; - DWORD dwSize; - - Flags &= ~REG_MUI_STRING_TRUNCATE; - - // Try with stack buffer first. - lResult = RegLoadMUIStringW(hKey, pszValue, szStackBuffer, sizeof(szStackBuffer), &dwSize, Flags, pszDirectory); - if (lResult == ERROR_SUCCESS) { - // Copy from stack buffer. - sOut.assign(szStackBuffer, wcsnlen(szStackBuffer, dwSize/sizeof(wchar_t))); - } else if (lResult == ERROR_MORE_DATA) { - // Allocate buffer on heap and retry. - std::unique_ptr szBuffer(new wchar_t[(dwSize + sizeof(wchar_t) - 1)/sizeof(wchar_t)]); - sOut.assign(szBuffer.get(), (lResult = RegLoadMUIStringW(hKey, pszValue, szBuffer.get(), dwSize, &dwSize, Flags, pszDirectory)) == ERROR_SUCCESS ? wcsnlen(szBuffer.get(), dwSize/sizeof(wchar_t)) : 0); - } - - return lResult; -} - -#endif - - -template -static _Success_(return != 0) int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cchWideChar) LPCWSTR lpWideCharStr, _In_ int cchWideChar, _Out_ std::basic_string &sMultiByteStr, _In_opt_z_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) noexcept -{ - CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)]; - - // Try to convert to stack buffer first. - int cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar); - if (cch) { - // Copy from stack. Be careful not to include zero terminator. - sMultiByteStr.assign(szStackBuffer, cchWideChar != -1 ? strnlen(szStackBuffer, cch) : (size_t)cch - 1); - } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - // Query the required output size. Allocate buffer. Then convert again. - cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, NULL, 0, lpDefaultChar, lpUsedDefaultChar); - std::unique_ptr szBuffer(new CHAR[cch]); - cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szBuffer.get(), cch, lpDefaultChar, lpUsedDefaultChar); - sMultiByteStr.assign(szBuffer.get(), cchWideChar != -1 ? strnlen(szBuffer.get(), cch) : (size_t)cch - 1); - } - - return cch; -} - - -template -static _Success_(return != 0) int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cchWideChar) LPCWSTR lpWideCharStr, _In_ int cchWideChar, _Out_ std::vector &sMultiByteStr, _In_opt_z_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) noexcept -{ - CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)]; - - // Try to convert to stack buffer first. - int cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar); - if (cch) { - // Copy from stack. - sMultiByteStr.assign(szStackBuffer, szStackBuffer + cch); - } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - // Query the required output size. Allocate buffer. Then convert again. - cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, NULL, 0, lpDefaultChar, lpUsedDefaultChar); - sMultiByteStr.resize(cch); - cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, sMultiByteStr.data(), cch, lpDefaultChar, lpUsedDefaultChar); - } - - return cch; -} - - -template -static _Success_(return != 0) int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_ std::basic_string sWideCharStr, _Out_ std::basic_string &sMultiByteStr, _In_opt_z_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) noexcept -{ - CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)]; - - // Try to convert to stack buffer first. - int cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar); - if (cch) { - // Copy from stack. - sMultiByteStr.assign(szStackBuffer, cch); - } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - // Query the required output size. Allocate buffer. Then convert again. - cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), NULL, 0, lpDefaultChar, lpUsedDefaultChar); - std::unique_ptr szBuffer(new CHAR[cch]); - cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), szBuffer.get(), cch, lpDefaultChar, lpUsedDefaultChar); - sMultiByteStr.assign(szBuffer.get(), cch); - } - - return cch; -} - - -template -static _Success_(return != 0) int SecureWideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cchWideChar) LPCWSTR lpWideCharStr, _In_ int cchWideChar, _Out_ std::basic_string &sMultiByteStr, _In_opt_z_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) noexcept -{ - CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)]; - - // Try to convert to stack buffer first. - int cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar); - if (cch) { - // Copy from stack. Be careful not to include zero terminator. - sMultiByteStr.assign(szStackBuffer, cchWideChar != -1 ? strnlen(szStackBuffer, cch) : (size_t)cch - 1); - } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - // Query the required output size. Allocate buffer. Then convert again. - cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, NULL, 0, lpDefaultChar, lpUsedDefaultChar); - std::unique_ptr szBuffer(new CHAR[cch]); - cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szBuffer.get(), cch, lpDefaultChar, lpUsedDefaultChar); - sMultiByteStr.assign(szBuffer.get(), cchWideChar != -1 ? strnlen(szBuffer.get(), cch) : (size_t)cch - 1); - SecureZeroMemory(szBuffer.get(), sizeof(CHAR)*cch); - } - - SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer)); - - return cch; -} - - -template -static _Success_(return != 0) int SecureWideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cchWideChar) LPCWSTR lpWideCharStr, _In_ int cchWideChar, _Out_ std::vector &sMultiByteStr, _In_opt_z_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) noexcept -{ - CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)]; - - // Try to convert to stack buffer first. - int cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar); - if (cch) { - // Copy from stack. - sMultiByteStr.assign(szStackBuffer, szStackBuffer + cch); - } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - // Query the required output size. Allocate buffer. Then convert again. - cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, NULL, 0, lpDefaultChar, lpUsedDefaultChar); - sMultiByteStr.resize(cch); - cch = ::WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, sMultiByteStr.data(), cch, lpDefaultChar, lpUsedDefaultChar); - } - - SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer)); - - return cch; -} - - -template -static _Success_(return != 0) int SecureWideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_ std::basic_string sWideCharStr, _Out_ std::basic_string &sMultiByteStr, _In_opt_z_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) noexcept -{ - CHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(CHAR)]; - - // Try to convert to stack buffer first. - int cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), szStackBuffer, _countof(szStackBuffer), lpDefaultChar, lpUsedDefaultChar); - if (cch) { - // Copy from stack. - sMultiByteStr.assign(szStackBuffer, cch); - } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - // Query the required output size. Allocate buffer. Then convert again. - cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), NULL, 0, lpDefaultChar, lpUsedDefaultChar); - std::unique_ptr szBuffer(new CHAR[cch]); - cch = ::WideCharToMultiByte(CodePage, dwFlags, sWideCharStr.c_str(), (int)sWideCharStr.length(), szBuffer.get(), cch, lpDefaultChar, lpUsedDefaultChar); - sMultiByteStr.assign(szBuffer.get(), cch); - SecureZeroMemory(szBuffer.get(), sizeof(CHAR)*cch); - } - - SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer)); - - return cch; -} - - -template -static _Success_(return != 0) int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cbMultiByte) LPCSTR lpMultiByteStr, _In_ int cbMultiByte, _Out_ std::basic_string &sWideCharStr) noexcept -{ - WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)]; - - // Try to convert to stack buffer first. - int cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szStackBuffer, _countof(szStackBuffer)); - if (cch) { - // Copy from stack. - sWideCharStr.assign(szStackBuffer, cbMultiByte != -1 ? wcsnlen(szStackBuffer, cch) : (size_t)cch - 1); - } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - // Query the required output size. Allocate buffer. Then convert again. - cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, NULL, 0); - std::unique_ptr szBuffer(new WCHAR[cch]); - cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szBuffer.get(), cch); - sWideCharStr.assign(szBuffer.get(), cbMultiByte != -1 ? wcsnlen(szBuffer.get(), cch) : (size_t)cch - 1); - } - - return cch; -} - - -template -static _Success_(return != 0) int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cbMultiByte) LPCSTR lpMultiByteStr, _In_ int cbMultiByte, _Out_ std::vector &sWideCharStr) noexcept -{ - WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)]; - - // Try to convert to stack buffer first. - int cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szStackBuffer, _countof(szStackBuffer)); - if (cch) { - // Copy from stack. - sWideCharStr.assign(szStackBuffer, szStackBuffer + cch); - } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - // Query the required output size. Allocate buffer. Then convert again. - cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, NULL, 0); - sWideCharStr.resize(cch); - cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, sWideCharStr.data(), cch); - } - - return cch; -} - - -template -static _Success_(return != 0) int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_ const std::basic_string &sMultiByteStr, _Out_ std::basic_string &sWideCharStr) noexcept -{ - WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)]; - - // Try to convert to stack buffer first. - int cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), szStackBuffer, _countof(szStackBuffer)); - if (cch) { - // Copy from stack. - sWideCharStr.assign(szStackBuffer, cch); - } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - // Query the required output size. Allocate buffer. Then convert again. - cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), NULL, 0); - std::unique_ptr szBuffer(new WCHAR[cch]); - cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), szBuffer.get(), cch); - sWideCharStr.assign(szBuffer.get(), cch); - } - - return cch; -} - - -template -static _Success_(return != 0) int SecureMultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cbMultiByte) LPCSTR lpMultiByteStr, _In_ int cbMultiByte, _Out_ std::basic_string &sWideCharStr) noexcept -{ - WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)]; - - // Try to convert to stack buffer first. - int cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szStackBuffer, _countof(szStackBuffer)); - if (cch) { - // Copy from stack. - sWideCharStr.assign(szStackBuffer, cbMultiByte != -1 ? wcsnlen(szStackBuffer, cch) : (size_t)cch - 1); - } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - // Query the required output size. Allocate buffer. Then convert again. - cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, NULL, 0); - std::unique_ptr szBuffer(new WCHAR[cch]); - cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szBuffer.get(), cch); - sWideCharStr.assign(szBuffer.get(), cbMultiByte != -1 ? wcsnlen(szBuffer.get(), cch) : (size_t)cch - 1); - SecureZeroMemory(szBuffer.get(), sizeof(WCHAR)*cch); - } - - SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer)); - - return cch; -} - - -template -static _Success_(return != 0) int SecureMultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cbMultiByte) LPCSTR lpMultiByteStr, _In_ int cbMultiByte, _Out_ std::vector &sWideCharStr) noexcept -{ - WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)]; - - // Try to convert to stack buffer first. - int cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, szStackBuffer, _countof(szStackBuffer)); - if (cch) { - // Copy from stack. - sWideCharStr.assign(szStackBuffer, szStackBuffer + cch); - } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - // Query the required output size. Allocate buffer. Then convert again. - cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, NULL, 0); - sWideCharStr.resize(cch); - cch = ::MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, sWideCharStr.data(), cch); - } - - SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer)); - - return cch; -} - - -template -static _Success_(return != 0) int SecureMultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_ const std::basic_string &sMultiByteStr, _Out_ std::basic_string &sWideCharStr) noexcept -{ - WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)]; - - // Try to convert to stack buffer first. - int cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), szStackBuffer, _countof(szStackBuffer)); - if (cch) { - // Copy from stack. - sWideCharStr.assign(szStackBuffer, cch); - } else if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - // Query the required output size. Allocate buffer. Then convert again. - cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), NULL, 0); - std::unique_ptr szBuffer(new WCHAR[cch]); - cch = ::MultiByteToWideChar(CodePage, dwFlags, sMultiByteStr.c_str(), (int)sMultiByteStr.length(), szBuffer.get(), cch); - sWideCharStr.assign(szBuffer.get(), cch); - SecureZeroMemory(szBuffer.get(), sizeof(WCHAR)*cch); - } - - SecureZeroMemory(szStackBuffer, sizeof(szStackBuffer)); - - return cch; -} - - -template -static _Success_(return > 0) int NormalizeString(_In_ NORM_FORM NormForm, _In_ LPCWSTR lpSrcString, _In_ int cwSrcLength, _Out_ std::basic_string &sDstString) noexcept -{ - WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)]; - - // Try to convert to stack buffer first. - int cch = ::NormalizeString(NormForm, lpSrcString, cwSrcLength, szStackBuffer, _countof(szStackBuffer)); - if (cch > 0) { - // Copy from stack. - sDstString.assign(szStackBuffer, cwSrcLength != -1 ? wcsnlen(szStackBuffer, cch) : (size_t)cch - 1); - } else { - switch (::GetLastError()) { - case ERROR_INSUFFICIENT_BUFFER: - for (int i = 10; i--;) { - // Allocate buffer. Then convert again. - cch = -cch; - std::unique_ptr szBuffer(new WCHAR[cch]); - cch = ::NormalizeString(NormForm, lpSrcString, cwSrcLength, szBuffer.get(), cch); - if (cch > 0) { - sDstString.assign(szBuffer.get(), cwSrcLength != -1 ? wcsnlen(szStackBuffer, cch) : (size_t)cch - 1); - break; - } - if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) { - sDstString.clear(); - break; - } - } - break; - - case ERROR_SUCCESS: - sDstString.clear(); - break; - } - } - - return cch; -} - - -template -static _Success_(return > 0) int NormalizeString(_In_ NORM_FORM NormForm, _In_ const std::basic_string &sSrcString, _Out_ std::basic_string &sDstString) noexcept -{ - WCHAR szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(WCHAR)]; - - // Try to convert to stack buffer first. - int cch = ::NormalizeString(NormForm, sSrcString.c_str(), (int)sSrcString.length(), szStackBuffer, _countof(szStackBuffer)); - if (cch > 0) { - // Copy from stack. - sDstString.assign(szStackBuffer, cch); - } else { - switch (::GetLastError()) { - case ERROR_INSUFFICIENT_BUFFER: - for (int i = 10; i--;) { - // Allocate buffer. Then convert again. - cch = -cch; - std::unique_ptr szBuffer(new WCHAR[cch]); - cch = ::NormalizeString(NormForm, sSrcString.c_str(), (int)sSrcString.length(), szBuffer.get(), cch); - if (cch > 0) { - sDstString.assign(szBuffer.get(), cch); - break; - } - if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) { - sDstString.clear(); - break; - } - } - break; - - case ERROR_SUCCESS: - sDstString.clear(); - break; - } - } - - return cch; -} - - -template -static _Success_(return != 0) int WINAPI LoadStringA(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_ std::basic_string &sBuffer) noexcept -{ - // Get read-only pointer to string resource. - LPCSTR pszStr; - int i = LoadStringA(hInstance, uID, reinterpret_cast(&pszStr), 0); - if (i) { - sBuffer.assign(pszStr, i); - return i; - } else - return 0; -} - - -template -static _Success_(return != 0) int WINAPI LoadStringW(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_ std::basic_string &sBuffer) noexcept -{ - // Get read-only pointer to string resource. - LPCWSTR pszStr; - int i = LoadStringW(hInstance, uID, reinterpret_cast(&pszStr), 0); - if (i) { - sBuffer.assign(pszStr, i); - return i; - } else - return 0; -} - - -static VOID OutputDebugStrV(_In_z_ LPCSTR lpOutputString, _In_ va_list arg) noexcept -{ - std::string str; - try { vsprintf(str, lpOutputString, arg); } catch (...) { return; } - OutputDebugStringA(str.c_str()); -} - - -static VOID OutputDebugStrV(_In_z_ LPCWSTR lpOutputString, _In_ va_list arg) noexcept -{ - std::wstring str; - try { vsprintf(str, lpOutputString, arg); } catch (...) { return; } - OutputDebugStringW(str.c_str()); -} - - -static VOID OutputDebugStr(_In_z_ LPCSTR lpOutputString, ...) noexcept -{ - va_list arg; - va_start(arg, lpOutputString); - OutputDebugStrV(lpOutputString, arg); - va_end(arg); -} - - -static VOID OutputDebugStr(_In_z_ LPCWSTR lpOutputString, ...) noexcept -{ - va_list arg; - va_start(arg, lpOutputString); - OutputDebugStrV(lpOutputString, arg); - va_end(arg); -} - - -template -static _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 &sDate) noexcept -{ - int iResult = GetDateFormatA(Locale, dwFlags, lpDate, lpFormat, NULL, 0); - if (iResult) { - // Allocate buffer on heap and retry. - std::unique_ptr szBuffer(new char[iResult]); - iResult = GetDateFormatA(Locale, dwFlags, lpDate, lpFormat, szBuffer.get(), iResult); - sDate.assign(szBuffer.get(), iResult ? iResult - 1 : 0); - return iResult; - } - - return iResult; -} - - -template -static _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 &sDate) noexcept -{ - int iResult = GetDateFormatW(Locale, dwFlags, lpDate, lpFormat, NULL, 0); - if (iResult) { - // Allocate buffer on heap and retry. - std::unique_ptr szBuffer(new wchar_t[iResult]); - iResult = GetDateFormatW(Locale, dwFlags, lpDate, lpFormat, szBuffer.get(), iResult); - sDate.assign(szBuffer.get(), iResult ? iResult - 1 : 0); - return iResult; - } - - return iResult; -} - - -template -static _Success_(return != 0) BOOL LookupAccountSidA(_In_opt_z_ LPCSTR lpSystemName, _In_ PSID lpSid, _Out_opt_ std::basic_string *sName, _Out_opt_ std::basic_string *sReferencedDomainName, _Out_ PSID_NAME_USE peUse) noexcept -{ - assert(0); // TODO: Test this code. - - DWORD dwNameLen = 0, dwRefDomainLen = 0; - - if (LookupAccountSidA(lpSystemName, lpSid, - NULL, &dwNameLen , - NULL, &dwRefDomainLen, - peUse)) - { - // Name and domain is blank. - if (sName ) sName ->clear(); - if (sReferencedDomainName) sReferencedDomainName->clear(); - return TRUE; - } else if (GetLastError() == ERROR_MORE_DATA) { - // Allocate on heap and retry. - std::unique_ptr bufName (new char[dwNameLen ]); - std::unique_ptr bufRefDomain(new char[dwRefDomainLen]); - if (LookupAccountSidA(lpSystemName, lpSid, - bufName .get(), &dwNameLen , - bufRefDomain.get(), &dwRefDomainLen, - peUse)) - { - if (sName ) sName ->assign(bufName .get(), dwNameLen - 1); - if (sReferencedDomainName) sReferencedDomainName->assign(bufRefDomain.get(), dwRefDomainLen - 1); - return TRUE; - } - } - - return FALSE; -} - - -template -static _Success_(return != 0) BOOL LookupAccountSidW(_In_opt_z_ LPCWSTR lpSystemName, _In_ PSID lpSid, _Out_opt_ std::basic_string *sName, _Out_opt_ std::basic_string *sReferencedDomainName, _Out_ PSID_NAME_USE peUse) noexcept -{ - assert(0); // TODO: Test this code. - - DWORD dwNameLen = 0, dwRefDomainLen = 0; - - if (LookupAccountSidW(lpSystemName, lpSid, - NULL, &dwNameLen , - NULL, &dwRefDomainLen, - peUse)) - { - // Name and domain is blank. - if (sName ) sName ->clear(); - if (sReferencedDomainName) sReferencedDomainName->clear(); - return TRUE; - } else if (GetLastError() == ERROR_MORE_DATA) { - // Allocate on heap and retry. - std::unique_ptr bufName (new wchar_t[dwNameLen ]); - std::unique_ptr bufRefDomain(new wchar_t[dwRefDomainLen]); - if (LookupAccountSidW(lpSystemName, lpSid, - bufName .get(), &dwNameLen , - bufRefDomain.get(), &dwRefDomainLen, - peUse)) - { - if (sName ) sName ->assign(bufName .get(), dwNameLen - 1); - if (sReferencedDomainName) sReferencedDomainName->assign(bufRefDomain.get(), dwRefDomainLen - 1); - return TRUE; - } - } - - return FALSE; -} - - -template -static _Success_(return != 0) BOOL GetTokenInformation(_In_ HANDLE TokenHandle, _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, _Out_ std::unique_ptr<_Ty> &TokenInformation) noexcept -{ - BYTE szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(BYTE)]; - DWORD dwSize; - - if (GetTokenInformation(TokenHandle, TokenInformationClass, szStackBuffer, sizeof(szStackBuffer), &dwSize)) { - // The stack buffer was big enough to retrieve complete data. Alloc and copy. - TokenInformation.reset((_Ty*)(new BYTE[dwSize / sizeof(BYTE)])); - if (!TokenInformation) { - SetLastError(ERROR_OUTOFMEMORY); - return FALSE; - } - memcpy(TokenInformation.get(), szStackBuffer, dwSize); - return TRUE; - } else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - // The stack buffer was too small to retrieve complete data. Alloc and retry. - TokenInformation.reset((_Ty*)(new BYTE[dwSize / sizeof(BYTE)])); - if (!TokenInformation) { - SetLastError(ERROR_OUTOFMEMORY); - return FALSE; - } - return GetTokenInformation(TokenHandle, TokenInformationClass, TokenInformation.get(), dwSize, &dwSize); - } else - return FALSE; -} - - -template -static _Success_(return != 0) BOOL QueryFullProcessImageNameA(_In_ HANDLE hProcess, _In_ DWORD dwFlags, _Inout_ std::basic_string& sExeName) -{ - char szStackBuffer[WINSTD_STACK_BUFFER_BYTES / sizeof(char)]; - DWORD dwSize = _countof(szStackBuffer); - - // Try with stack buffer first. - if (::QueryFullProcessImageNameA(hProcess, dwFlags, szStackBuffer, &dwSize)) { - // Copy from stack. - sExeName.assign(szStackBuffer, dwSize); - return TRUE; - } - for (DWORD dwCapacity = 2 * WINSTD_STACK_BUFFER_BYTES / sizeof(char); GetLastError() == ERROR_INSUFFICIENT_BUFFER; dwCapacity *= 2) { - // Allocate on heap and retry. - std::unique_ptr szBuffer(new char[dwCapacity]); - dwSize = dwCapacity; - if (::QueryFullProcessImageNameA(hProcess, dwFlags, szBuffer.get(), &dwSize)) { - sExeName.assign(szBuffer.get(), dwSize); - return TRUE; - } - } - return FALSE; -} - - -template -static _Success_(return != 0) BOOL QueryFullProcessImageNameW(_In_ HANDLE hProcess, _In_ DWORD dwFlags, _Inout_ std::basic_string& sExeName) -{ - wchar_t szStackBuffer[WINSTD_STACK_BUFFER_BYTES / sizeof(wchar_t)]; - DWORD dwSize = _countof(szStackBuffer); - - // Try with stack buffer first. - if (::QueryFullProcessImageNameW(hProcess, dwFlags, szStackBuffer, &dwSize)) { - // Copy from stack. - sExeName.assign(szStackBuffer, dwSize); - return TRUE; - } - for (DWORD dwCapacity = 2 * WINSTD_STACK_BUFFER_BYTES / sizeof(wchar_t); GetLastError() == ERROR_INSUFFICIENT_BUFFER; dwCapacity *= 2) { - // Allocate on heap and retry. - std::unique_ptr szBuffer(new wchar_t[dwCapacity]); - dwSize = dwCapacity; - if (::QueryFullProcessImageNameW(hProcess, dwFlags, szBuffer.get(), &dwSize)) { - sExeName.assign(szBuffer.get(), dwSize); - return TRUE; - } - } - return FALSE; -} - -#pragma warning(pop) diff --git a/include/WinStd/WinSock2.h b/include/WinStd/WinSock2.h index f0044307..f607e5b0 100644 --- a/include/WinStd/WinSock2.h +++ b/include/WinStd/WinSock2.h @@ -4,31 +4,19 @@ Copyright © 2016 GÉANT */ -/// -/// \defgroup WinSock2API WinSock2 API -/// Integrates WinStd classes with Microsoft WinSock2 API -/// - -#include "Common.h" - -namespace winstd -{ - class ws2_runtime_error; -#if (NTDDI_VERSION >= NTDDI_WINXPSP2) || (_WIN32_WINNT >= 0x0502) - class addrinfo; -#endif -} - #pragma once +#include "Common.h" #include #include #include - namespace winstd { - /// \addtogroup WinStdExceptions + /// + /// \defgroup WinSock2API WinSock2 API + /// Integrates WinStd classes with Microsoft WinSock2 API + /// /// @{ /// @@ -47,7 +35,6 @@ namespace winstd { } - /// /// Constructs an exception /// @@ -58,7 +45,6 @@ namespace winstd { } - /// /// Constructs an exception using `WSAGetLastError()` /// @@ -68,7 +54,6 @@ namespace winstd { } - /// /// Constructs an exception using `WSAGetLastError()` /// @@ -78,7 +63,6 @@ namespace winstd { } - /// /// Returns a user-readable Windows error message /// @@ -98,7 +82,6 @@ namespace winstd /// @} - /// \addtogroup WinSock2API /// @{ @@ -141,7 +124,6 @@ namespace winstd free_internal(); } - protected: /// /// Frees address information diff --git a/include/WinStd/WinTrust.h b/include/WinStd/WinTrust.h index 02e15e4d..ab5c64c7 100644 --- a/include/WinStd/WinTrust.h +++ b/include/WinStd/WinTrust.h @@ -6,26 +6,15 @@ #pragma once -/// -/// \defgroup WinTrustAPI WinTrust API -/// Integrates WinStd classes with Microsoft WinTrust API -/// - #include "Common.h" - #include namespace winstd { - class wintrust; -} - -#pragma once - - -namespace winstd -{ - /// \addtogroup WinTrustAPI + /// + /// \defgroup WinTrustAPI WinTrust API + /// Integrates WinStd classes with Microsoft WinTrust API + /// /// @{ ///