From aa7cd261f2f79720aa379ea590932deb08f3f7b4 Mon Sep 17 00:00:00 2001 From: Simon Rozman Date: Tue, 18 Dec 2018 09:05:00 +0100 Subject: [PATCH] Resolve code analysis reported warnings --- include/WinStd/Base64.h | 567 +++--- include/WinStd/COM.h | 2187 +++++++++++----------- include/WinStd/Common.h | 3910 +++++++++++++++++++-------------------- include/WinStd/Cred.h | 499 +++-- include/WinStd/Crypt.h | 1768 +++++++++--------- include/WinStd/EAP.h | 1338 +++++++------- include/WinStd/ETW.h | 2388 ++++++++++++------------ include/WinStd/Hex.h | 382 ++-- include/WinStd/Win.h | 3082 +++++++++++++++--------------- src/EAP.cpp | 277 +-- src/StdAfx.h | 82 +- src/Win.cpp | 656 +++---- 12 files changed, 8580 insertions(+), 8556 deletions(-) diff --git a/include/WinStd/Base64.h b/include/WinStd/Base64.h index 1c90a379..596578e3 100644 --- a/include/WinStd/Base64.h +++ b/include/WinStd/Base64.h @@ -1,280 +1,287 @@ -/* - Copyright 1991-2018 Amebis - Copyright 2016 GÉANT - - This file is part of WinStd. - - Setup is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Setup is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Setup. If not, see . -*/ - -/// -/// \defgroup WinStdBase64 Base64 conversion -/// Provides Base64 conversion for WinStd classes -/// - -#include "Common.h" - -#include -#include - -namespace winstd -{ - class WINSTD_API base64_enc; - class WINSTD_API base64_dec; -} - -#pragma once - - -namespace winstd -{ - /// \addtogroup WinStdBase64 - /// @{ - - /// - /// Base64 encoding session - /// - class WINSTD_API base64_enc - { - public: - /// - /// Constructs blank encoding session - /// - inline base64_enc() : num(0) - { - } - - - /// - /// Encodes one block of information, and _appends_ it to the output - /// - /// \param[out] out Output - /// \param[in ] data Data to encode - /// \param[in ] size Length of `data` in bytes - /// \param[in ] is_last Is this the last block of data? - /// - template - inline void encode(_Out_ std::basic_string<_Elem, _Traits, _Ax> &out, _In_bytecount_(size) const void *data, _In_ size_t size, _In_opt_ bool is_last = true) - { - assert(data || !size); - - // Preallocate output - out.reserve(out.size() + enc_size(size)); - - // Convert data character by character. - for (size_t i = 0;; i++) { - if (num >= 3) { - encode(out); - num = 0; - } - - if (i >= size) - break; - - buf[num++] = reinterpret_cast(data)[i]; - } - - // If this is the last block, flush the buffer. - if (is_last && num) { - encode(out, num); - num = 0; - } - } - - - /// - /// Resets encoding session - /// - inline void clear() - { - num = 0; - } - - - /// - /// Returns maximum encoded size - /// - /// \param size Number of bytes to encode - /// - /// \returns Maximum number of bytes for the encoded data of `size` length - /// - inline size_t enc_size(size_t size) const - { - return ((num + size + 2)/3)*4; - } - - - protected: - /// - /// Encodes one complete internal buffer of data - /// - template - inline void encode(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &out) - { - out += lookup[ buf[0] >> 2 ]; - out += lookup[((buf[0] << 4) | (buf[1] >> 4)) & 0x3f]; - out += lookup[((buf[1] << 2) | (buf[2] >> 6)) & 0x3f]; - out += lookup[ buf[2] & 0x3f]; - } - - - /// - /// Encodes partial internal buffer of data - /// - template - inline void encode(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &out, _In_ size_t size) - { - if (size > 0) { - out += lookup[buf[0] >> 2]; - if (size > 1) { - out += lookup[((buf[0] << 4) | (buf[1] >> 4)) & 0x3f]; - if (size > 2) { - out += lookup[((buf[1] << 2) | (buf[2] >> 6)) & 0x3f]; - out += lookup[buf[2] & 0x3f]; - } else { - out += lookup[(buf[1] << 2) & 0x3f]; - out += '='; - } - } else { - out += lookup[(buf[0] << 4) & 0x3f]; - out += '='; - out += '='; - } - } else { - out += '='; - out += '='; - out += '='; - out += '='; - } - } - - - protected: - unsigned char buf[3]; ///< Internal buffer - size_t num; ///< Number of bytes used in `buf` - - /// \cond internal - static const char lookup[64]; - /// \endcond - }; - - - /// - /// Base64 decoding session - /// - class WINSTD_API base64_dec - { - public: - /// - /// Constructs blank decoding session - /// - inline base64_dec() : num(0) - { - } - - - /// - /// Decodes one block of information, and _appends_ it to the output - /// - /// \param[out] out Output - /// \param[in ] is_last Was this the last block of data? - /// \param[in ] data Data to decode - /// \param[in ] size Length of `data` in bytes - /// - template - inline void decode(_Out_ std::vector<_Ty, _Ax> &out, _Out_ bool &is_last, _In_z_count_(size) const _Tchr *data, _In_ size_t size) - { - is_last = false; - - // Trim data size to first terminator. - for (size_t k = 0; k < size; k++) - if (!data[k]) { size = k; break; } - - // Preallocate output - out.reserve(out.size() + dec_size(size)); - - for (size_t i = 0;; i++) { - if (num >= 4) { - // Buffer full; decode it. - size_t nibbles = decode(out); - num = 0; - if (nibbles < 3) { - is_last = true; - break; - } - } - - if (i >= size) - break; - - int x = data[i]; - if ((buf[num] = x < _countof(lookup) ? lookup[x] : 255) != 255) - num++; - } - } - - - /// - /// Resets decoding session - /// - inline void clear() - { - num = 0; - } - - - /// - /// Returns maximum decoded size - /// - /// \param size Number of bytes to decode - /// - /// \returns Maximum number of bytes for the decoded data of `size` length - /// - inline size_t dec_size(size_t size) const - { - return ((num + size + 3)/4)*3; - } - - - protected: - /// - /// Decodes one complete internal buffer of data - /// - template - inline size_t decode(_Inout_ std::vector<_Ty, _Ax> &out) - { - out.push_back((_Ty)(((buf[0] << 2) | (buf[1] >> 4)) & 0xff)); - if (buf[2] < 64) { - out.push_back((_Ty)(((buf[1] << 4) | (buf[2] >> 2)) & 0xff)); - if (buf[3] < 64) { - out.push_back((_Ty)(((buf[2] << 6) | buf[3]) & 0xff)); - return 3; - } else - return 2; - } else - return 1; - } - - - protected: - unsigned char buf[4]; ///< Internal buffer - size_t num; ///< Number of bytes used in `buf` - - /// \cond internal - static const unsigned char lookup[256]; - /// \endcond - }; - - /// @} -} +/* + Copyright 1991-2018 Amebis + Copyright 2016 GÉANT + + This file is part of WinStd. + + Setup is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Setup is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Setup. If not, see . +*/ + +/// +/// \defgroup WinStdBase64 Base64 conversion +/// Provides Base64 conversion for WinStd classes +/// + +#include "Common.h" + +#include +#include + +namespace winstd +{ + class WINSTD_API base64_enc; + class WINSTD_API base64_dec; +} + +#pragma once + + +namespace winstd +{ + /// \addtogroup WinStdBase64 + /// @{ + + /// + /// Base64 encoding session + /// + class WINSTD_API base64_enc + { + public: + /// + /// Constructs blank encoding session + /// + inline base64_enc() : num(0) + { + buf[0] = 0; + buf[1] = 0; + buf[2] = 0; + } + + + /// + /// Encodes one block of information, and _appends_ it to the output + /// + /// \param[out] out Output + /// \param[in ] data Data to encode + /// \param[in ] size Length of `data` in bytes + /// \param[in ] is_last Is this the last block of data? + /// + template + inline void encode(_Out_ std::basic_string<_Elem, _Traits, _Ax> &out, _In_bytecount_(size) const void *data, _In_ size_t size, _In_opt_ bool is_last = true) + { + assert(data || !size); + + // Preallocate output + out.reserve(out.size() + enc_size(size)); + + // Convert data character by character. + for (size_t i = 0;; i++) { + if (num >= 3) { + encode(out); + num = 0; + } + + if (i >= size) + break; + + buf[num++] = reinterpret_cast(data)[i]; + } + + // If this is the last block, flush the buffer. + if (is_last && num) { + encode(out, num); + num = 0; + } + } + + + /// + /// Resets encoding session + /// + inline void clear() + { + num = 0; + } + + + /// + /// Returns maximum encoded size + /// + /// \param size Number of bytes to encode + /// + /// \returns Maximum number of bytes for the encoded data of `size` length + /// + inline size_t enc_size(size_t size) const + { + return ((num + size + 2)/3)*4; + } + + + protected: + /// + /// Encodes one complete internal buffer of data + /// + template + inline void encode(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &out) + { + out += lookup[ buf[0] >> 2 ]; + out += lookup[((buf[0] << 4) | (buf[1] >> 4)) & 0x3f]; + out += lookup[((buf[1] << 2) | (buf[2] >> 6)) & 0x3f]; + out += lookup[ buf[2] & 0x3f]; + } + + + /// + /// Encodes partial internal buffer of data + /// + template + inline void encode(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &out, _In_ size_t size) + { + if (size > 0) { + out += lookup[buf[0] >> 2]; + if (size > 1) { + out += lookup[((buf[0] << 4) | (buf[1] >> 4)) & 0x3f]; + if (size > 2) { + out += lookup[((buf[1] << 2) | (buf[2] >> 6)) & 0x3f]; + out += lookup[buf[2] & 0x3f]; + } else { + out += lookup[(buf[1] << 2) & 0x3f]; + out += '='; + } + } else { + out += lookup[(buf[0] << 4) & 0x3f]; + out += '='; + out += '='; + } + } else { + out += '='; + out += '='; + out += '='; + out += '='; + } + } + + + protected: + unsigned char buf[3]; ///< Internal buffer + size_t num; ///< Number of bytes used in `buf` + + /// \cond internal + static const char lookup[64]; + /// \endcond + }; + + + /// + /// Base64 decoding session + /// + class WINSTD_API base64_dec + { + public: + /// + /// Constructs blank decoding session + /// + inline base64_dec() : num(0) + { + buf[0] = 0; + buf[1] = 0; + buf[2] = 0; + buf[3] = 0; + } + + + /// + /// Decodes one block of information, and _appends_ it to the output + /// + /// \param[out] out Output + /// \param[in ] is_last Was this the last block of data? + /// \param[in ] data Data to decode + /// \param[in ] size Length of `data` in bytes + /// + template + inline void decode(_Out_ std::vector<_Ty, _Ax> &out, _Out_ bool &is_last, _In_z_count_(size) const _Tchr *data, _In_ size_t size) + { + is_last = false; + + // Trim data size to first terminator. + for (size_t k = 0; k < size; k++) + if (!data[k]) { size = k; break; } + + // Preallocate output + out.reserve(out.size() + dec_size(size)); + + for (size_t i = 0;; i++) { + if (num >= 4) { + // Buffer full; decode it. + size_t nibbles = decode(out); + num = 0; + if (nibbles < 3) { + is_last = true; + break; + } + } + + if (i >= size) + break; + + int x = data[i]; + if ((buf[num] = x < _countof(lookup) ? lookup[x] : 255) != 255) + num++; + } + } + + + /// + /// Resets decoding session + /// + inline void clear() + { + num = 0; + } + + + /// + /// Returns maximum decoded size + /// + /// \param size Number of bytes to decode + /// + /// \returns Maximum number of bytes for the decoded data of `size` length + /// + inline size_t dec_size(size_t size) const + { + return ((num + size + 3)/4)*3; + } + + + protected: + /// + /// Decodes one complete internal buffer of data + /// + template + inline size_t decode(_Inout_ std::vector<_Ty, _Ax> &out) + { + out.push_back((_Ty)(((buf[0] << 2) | (buf[1] >> 4)) & 0xff)); + if (buf[2] < 64) { + out.push_back((_Ty)(((buf[1] << 4) | (buf[2] >> 2)) & 0xff)); + if (buf[3] < 64) { + out.push_back((_Ty)(((buf[2] << 6) | buf[3]) & 0xff)); + return 3; + } else + return 2; + } else + return 1; + } + + + protected: + unsigned char buf[4]; ///< Internal buffer + size_t num; ///< Number of bytes used in `buf` + + /// \cond internal + static const unsigned char lookup[256]; + /// \endcond + }; + + /// @} +} diff --git a/include/WinStd/COM.h b/include/WinStd/COM.h index ef48db1f..c6b632c4 100644 --- a/include/WinStd/COM.h +++ b/include/WinStd/COM.h @@ -1,1091 +1,1096 @@ -/* - Copyright 1991-2018 Amebis - Copyright 2016 GÉANT - - This file is part of WinStd. - - Setup is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Setup is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Setup. If not, see . -*/ - -/// -/// \defgroup WinStdCOM COM object management -/// Provides helper templates for Windows COM object manipulation -/// - -#include "Common.h" - -#include - -namespace winstd -{ - template class com_obj; - class WINSTD_API bstr; - class WINSTD_API variant; - class WINSTD_API com_initializer; - class WINSTD_API com_runtime_error; -} - -#pragma once - - -namespace winstd -{ - /// \addtogroup WinStdCOM - /// @{ - - /// - /// COM object wrapper template - /// - template - class com_obj : public dplhandle - { - DPLHANDLE_IMPL(com_obj) - - public: - /// - /// Constructs a new object and creates a new class with it - /// - /// \sa [CoCreateInstance function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686615.aspx) - /// - inline com_obj(_In_ REFCLSID rclsid, _In_opt_ LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL) - { - CoCreateInstance(rclsid, pUnkOuter, dwClsContext, __uuidof(T), (LPVOID*)&m_h); - } - - - /// - /// Queries the object for another interface and creates new class with it - /// - /// \sa [IUnknown::QueryInterface method](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682521.aspx) - /// - template - inline com_obj(_Out_ _Other **other) - { - assert(other); - other->QueryInterface(__uuidof(T), (void**)&m_h); - } - - - /// - /// Queries the object for another interface and creates new class with it - /// - /// \sa [IUnknown::QueryInterface method](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682521.aspx) - /// - template - inline com_obj(_Out_ com_obj<_Other> &other) - { - assert(other); - other->QueryInterface(__uuidof(T), (void**)&m_h); - } - - - /// - /// Releases object - /// - virtual ~com_obj() - { - if (m_h) - m_h->Release(); - } - - - /// - /// Creates a new object - /// - /// \sa [CoCreateInstance function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686615.aspx) - /// - inline HRESULT create(_In_ REFCLSID rclsid, _In_opt_ LPUNKNOWN pUnkOuter = NULL, _In_ DWORD dwClsContext = CLSCTX_ALL) - { - handle_type h; - HRESULT hr = CoCreateInstance(rclsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&h); - if (SUCCEEDED(hr)) - attach(h); - return hr; - } - - - /// - /// Queries the object for another interface - /// - /// \sa [IUnknown::QueryInterface method](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682521.aspx) - /// - template - HRESULT query_interface(_Out_ _Other **h) const - { - assert(h); - assert(m_h); - return m_h->QueryInterface(__uuidof(_Other), (void**)h); - } - - - /// - /// Queries the object for another interface - /// - /// \sa [IUnknown::QueryInterface method](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682521.aspx) - /// - template - HRESULT query_interface(_Out_ com_obj<_Other> &h) const - { - assert(m_h); - _Other *_h; - HRESULT hr = m_h->QueryInterface(__uuidof(_Other), (void**)&_h); - if (SUCCEEDED(hr)) - h.attach(_h); - return hr; - } - - protected: - /// - /// Releases the object by decrementing reference counter - /// - /// \sa [IUnknown::Release method](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682317.aspx) - /// - virtual void free_internal() - { - m_h->Release(); - } - - - /// - /// Duplicates the object by incrementing the reference counter - /// - /// \sa [IUnknown::AddRef method](https://msdn.microsoft.com/en-us/library/windows/desktop/ms691379.aspx) - /// - /// \param[in] h Object handle of existing object - /// - /// \return Duplicated object handle - /// - virtual handle_type duplicate_internal(_In_ handle_type h) const - { - h->AddRef(); - return h; - } - }; - - - /// - /// BSTR string wrapper - /// - class WINSTD_API bstr : public dplhandle - { - DPLHANDLE_IMPL(bstr) - - public: - /// - /// Constructs BSTR from OLE string - /// - inline bstr(_In_ LPCOLESTR src) - { - m_h = SysAllocString(src); - } - - /// - /// Constructs BSTR from OLE string with length - /// - inline bstr(_In_ LPCOLESTR src, _In_ UINT len) - { - m_h = SysAllocStringLen(src, len); - } - - /// - /// Constructs BSTR from std::basic_string - /// - template - inline bstr(_In_ const std::basic_string &src) - { - m_h = SysAllocStringLen(src.c_str(), (UINT)src.length()); - } - - /// - /// Destroys the string - /// - /// \sa [SysFreeString function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms221481.aspx) - /// - virtual ~bstr(); - - /// - /// Returns the length of the string - /// - /// \sa [SysStringLen function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms221240.aspx) - /// - inline UINT length() const - { - return SysStringLen(m_h); - } - - protected: - /// - /// Destroys the string - /// - /// \sa [SysFreeString function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms221481.aspx) - /// - virtual void free_internal(); - - /// - /// Duplicates the string - /// - /// \param[in] h Existing string - /// - /// \return Duplicated string - /// - /// \sa [SysAllocString function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms221458.aspx) - /// - virtual handle_type duplicate_internal(_In_ handle_type h) const; - }; - - - /// - /// VARIANT struct wrapper - /// - class WINSTD_API variant : public VARIANT - { - public: - /// - /// Constructs blank VARIANT - /// - inline variant() - { - VariantInit(this); - } - - /// - /// Constructs VARIANT from another - /// - inline variant(_In_ const VARIANT& varSrc) - { - vt = VT_EMPTY; - VariantCopy(this, &varSrc); - } - - /// - /// Moves VARIANT from another - /// - inline variant(_Inout_ VARIANT&& varSrc) - { - memcpy(this, &varSrc, sizeof(VARIANT)); - varSrc.vt = VT_EMPTY; - } - - /// - /// Constructs VARIANT from bool - /// - inline variant(_In_ bool bSrc) - { - vt = VT_BOOL; - boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE; - } - - /// - /// Constructs VARIANT from character - /// - inline variant(_In_ char cSrc) - { - vt = VT_I1; - cVal = cSrc; - } - - /// - /// Constructs VARIANT from byte - /// - inline variant(_In_ unsigned char nSrc) - { - vt = VT_UI1; - bVal = nSrc; - } - - /// - /// Constructs VARIANT from short - /// - inline variant(_In_ short nSrc) - { - vt = VT_I2; - iVal = nSrc; - } - - /// - /// Constructs VARIANT from unsigned short - /// - inline variant(_In_ unsigned short nSrc) - { - vt = VT_UI2; - uiVal = nSrc; - } - - /// - /// Constructs VARIANT from integer - /// - inline variant(_In_ int nSrc, _In_ VARTYPE vtSrc = VT_I4) - { - assert(vtSrc == VT_I4 || vtSrc == VT_INT); - vt = vtSrc; - intVal = nSrc; - } - - /// - /// Constructs VARIANT from unsigned integer - /// - inline variant(_In_ unsigned int nSrc, _In_ VARTYPE vtSrc = VT_UI4) - { - assert(vtSrc == VT_UI4 || vtSrc == VT_UINT); - vt = vtSrc; - uintVal= nSrc; - } - - /// - /// Constructs VARIANT from long - /// - inline variant(_In_ long nSrc, _In_ VARTYPE vtSrc = VT_I4) - { - assert(vtSrc == VT_I4 || vtSrc == VT_ERROR); - vt = vtSrc; - lVal = nSrc; - } - - /// - /// Constructs VARIANT from unsigned long - /// - inline variant(_In_ unsigned long nSrc) - { - vt = VT_UI4; - ulVal = nSrc; - } - - /// - /// Constructs VARIANT from float - /// - inline variant(_In_ float fltSrc) - { - vt = VT_R4; - fltVal = fltSrc; - } - - /// - /// Constructs VARIANT from double or variant date - /// - inline variant(_In_ double dblSrc, _In_ VARTYPE vtSrc = VT_R8) - { - assert(vtSrc == VT_R8 || vtSrc == VT_DATE); - vt = vtSrc; - dblVal = dblSrc; - } - - /// - /// Constructs VARIANT from 64-bit integer - /// - inline variant(_In_ long long nSrc) - { - vt = VT_I8; - llVal = nSrc; - } - - /// - /// Constructs VARIANT from unsigned integer - /// - inline variant(_In_ unsigned long long nSrc) - { - vt = VT_UI8; - ullVal = nSrc; - } - - /// - /// Constructs VARIANT from CY (64-bit integer) - /// - inline variant(_In_ CY cySrc) - { - vt = VT_CY; - cyVal.Hi = cySrc.Hi; - cyVal.Lo = cySrc.Lo; - } - - /// - /// Constructs VARIANT from OLE string - /// - inline variant(_In_z_ LPCOLESTR lpszSrc) - { - vt = VT_EMPTY; - *this = lpszSrc; - } - - /// - /// Constructs VARIANT from BSTR - /// - inline variant(_In_z_ BSTR bstr) - { - vt = VT_EMPTY; - *this = bstr; - } - - /// - /// Constructs VARIANT from IDispatch - /// - inline variant(_In_opt_ IDispatch* pSrc) - { - vt = VT_DISPATCH; - pdispVal = pSrc; - - if (pdispVal != NULL) - pdispVal->AddRef(); - } - - /// - /// Constructs VARIANT from IUnknown - /// - inline variant(_In_opt_ IUnknown* pSrc) - { - vt = VT_UNKNOWN; - punkVal = pSrc; - - if (punkVal != NULL) - punkVal->AddRef(); - } - - /// - /// Constructs VARIANT from SAFEARRAY - /// - inline variant(_In_ const SAFEARRAY *pSrc) - { - assert(pSrc != NULL); - - LPSAFEARRAY pCopy; - HRESULT hRes = SafeArrayCopy((LPSAFEARRAY)pSrc, &pCopy); - if (SUCCEEDED(hRes)) { - SafeArrayGetVartype((LPSAFEARRAY)pSrc, &vt); - vt |= VT_ARRAY; - parray = pCopy; - } else - assert(0); - } - - /// - /// Destroys VARIANT - /// - virtual ~variant(); - - /// - /// Copy from another VARIANT - /// - inline variant& operator=(_In_ const VARIANT& varSrc) - { - if (this != &varSrc) - VariantCopy(this, &varSrc); - return *this; - } - - /// - /// Moves from another VARIANT - /// - inline variant& operator=(_Inout_ VARIANT&& varSrc) - { - if (this != &varSrc) { - VariantClear(this); - memcpy(this, &varSrc, sizeof(VARIANT)); - varSrc.vt = VT_EMPTY; - } - return *this; - } - - /// - /// Copy from bool value - /// - inline variant& operator=(_In_ bool bSrc) - { - if (vt != VT_BOOL) { - VariantClear(this); - vt = VT_BOOL; - } - boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE; - return *this; - } - - /// - /// Copy from char value - /// - inline variant& operator=(_In_ char cSrc) - { - if (vt != VT_I1) { - VariantClear(this); - vt = VT_I1; - } - cVal = cSrc; - return *this; - } - - /// - /// Copy from unsigned char value - /// - inline variant& operator=(_In_ unsigned char nSrc) - { - if (vt != VT_UI1) { - VariantClear(this); - vt = VT_UI1; - } - bVal = nSrc; - return *this; - } - - /// - /// Copy from short value - /// - inline variant& operator=(_In_ short nSrc) - { - if (vt != VT_I2) { - VariantClear(this); - vt = VT_I2; - } - iVal = nSrc; - return *this; - } - - /// - /// Copy from unsigned short value - /// - inline variant& operator=(_In_ unsigned short nSrc) - { - if (vt != VT_UI2) { - VariantClear(this); - vt = VT_UI2; - } - uiVal = nSrc; - return *this; - } - - /// - /// Copy from int value - /// - inline variant& operator=(_In_ int nSrc) - { - if (vt != VT_I4) { - VariantClear(this); - vt = VT_I4; - } - intVal = nSrc; - return *this; - } - - /// - /// Copy from unsigned int value - /// - inline variant& operator=(_In_ unsigned int nSrc) - { - if (vt != VT_UI4) { - VariantClear(this); - vt = VT_UI4; - } - uintVal= nSrc; - return *this; - } - - /// - /// Copy from long value - /// - inline variant& operator=(_In_ long nSrc) - { - if (vt != VT_I4) { - VariantClear(this); - vt = VT_I4; - } - lVal = nSrc; - return *this; - } - - /// - /// Copy from unsigned long value - /// - inline variant& operator=(_In_ unsigned long nSrc) - { - if (vt != VT_UI4) { - VariantClear(this); - vt = VT_UI4; - } - ulVal = nSrc; - return *this; - } - - - /// - /// Copy from long long value - /// - inline variant& operator=(_In_ long long nSrc) - { - if (vt != VT_I8) { - VariantClear(this); - vt = VT_I8; - } - llVal = nSrc; - return *this; - } - - /// - /// Copy from unsigned long long value - /// - inline variant& operator=(_In_ unsigned long long nSrc) - { - if (vt != VT_UI8) { - VariantClear(this); - vt = VT_UI8; - } - ullVal = nSrc; - - return *this; - } - - /// - /// Copy from float value - /// - inline variant& operator=(_In_ float fltSrc) - { - if (vt != VT_R4) { - VariantClear(this); - vt = VT_R4; - } - fltVal = fltSrc; - return *this; - } - - /// - /// Copy from double value - /// - inline variant& operator=(_In_ double dblSrc) - { - if (vt != VT_R8) { - VariantClear(this); - vt = VT_R8; - } - dblVal = dblSrc; - return *this; - } - - /// - /// Copy from CY value - /// - inline variant& operator=(_In_ CY cySrc) - { - if (vt != VT_CY) { - VariantClear(this); - vt = VT_CY; - } - cyVal.Hi = cySrc.Hi; - cyVal.Lo = cySrc.Lo; - return *this; - } - - /// - /// Copy from OLE string value - /// - inline variant& operator=(_In_z_ LPCOLESTR lpszSrc) - { - VariantClear(this); - vt = VT_BSTR; - bstrVal = SysAllocString(lpszSrc); - return *this; - } - - /// - /// Copy from IDispatch - /// - inline variant& operator=(_Inout_opt_ IDispatch* pSrc) - { - VariantClear(this); - vt = VT_DISPATCH; - pdispVal = pSrc; - if (pdispVal != NULL) - pdispVal->AddRef(); - return *this; - } - - /// - /// Copy from IUnknown - /// - inline variant& operator=(_Inout_opt_ IUnknown* pSrc) - { - VariantClear(this); - vt = VT_UNKNOWN; - punkVal = pSrc; - if (punkVal != NULL) - punkVal->AddRef(); - return *this; - } - - /// - /// Copy from unsigned char reference - /// - inline variant& operator=(_In_ unsigned char* pbSrc) - { - if (vt != (VT_UI1|VT_BYREF)) { - VariantClear(this); - vt = VT_UI1|VT_BYREF; - } - pbVal = pbSrc; - return *this; - } - - /// - /// Copy from short reference - /// - inline variant& operator=(_In_ short* pnSrc) - { - if (vt != (VT_I2|VT_BYREF)) { - VariantClear(this); - vt = VT_I2|VT_BYREF; - } - piVal = pnSrc; - return *this; - } - - /// - /// Copy from unsigned short reference - /// - inline variant& operator=(_In_ unsigned short* pnSrc) - { - if (vt != (VT_UI2|VT_BYREF)) { - VariantClear(this); - vt = VT_UI2|VT_BYREF; - } - puiVal = pnSrc; - return *this; - } - - /// - /// Copy from int reference - /// - inline variant& operator=(_In_ int* pnSrc) - { - if (vt != (VT_I4|VT_BYREF)) { - VariantClear(this); - vt = VT_I4|VT_BYREF; - } - pintVal = pnSrc; - return *this; - } - - /// - /// Copy from unsigned int reference - /// - inline variant& operator=(_In_ unsigned int* pnSrc) - { - if (vt != (VT_UI4|VT_BYREF)) { - VariantClear(this); - vt = VT_UI4|VT_BYREF; - } - puintVal = pnSrc; - return *this; - } - - /// - /// Copy from long reference - /// - inline variant& operator=(_In_ long* pnSrc) - { - if (vt != (VT_I4|VT_BYREF)) { - VariantClear(this); - vt = VT_I4|VT_BYREF; - } - plVal = pnSrc; - return *this; - } - - /// - /// Copy from unsigned long reference - /// - inline variant& operator=(_In_ unsigned long* pnSrc) - { - if (vt != (VT_UI4|VT_BYREF)) { - VariantClear(this); - vt = VT_UI4|VT_BYREF; - } - pulVal = pnSrc; - return *this; - } - - /// - /// Copy from long long reference - /// - inline variant& operator=(_In_ long long* pnSrc) - { - if (vt != (VT_I8|VT_BYREF)) { - VariantClear(this); - vt = VT_I8|VT_BYREF; - } - pllVal = pnSrc; - return *this; - } - - /// - /// Copy from unsigned long long reference - /// - inline variant& operator=(_In_ unsigned long long* pnSrc) - { - if (vt != (VT_UI8|VT_BYREF)) { - VariantClear(this); - vt = VT_UI8|VT_BYREF; - } - pullVal = pnSrc; - return *this; - } - - /// - /// Copy from float reference - /// - inline variant& operator=(_In_ float* pfSrc) - { - if (vt != (VT_R4|VT_BYREF)) { - VariantClear(this); - vt = VT_R4|VT_BYREF; - } - pfltVal = pfSrc; - return *this; - } - - /// - /// Copy from double reference - /// - inline variant& operator=(_In_ double* pfSrc) - { - if (vt != (VT_R8|VT_BYREF)) { - VariantClear(this); - vt = VT_R8|VT_BYREF; - } - pdblVal = pfSrc; - return *this; - } - - /// - /// Copy from SAFEARRAY - /// - inline variant& operator=(_In_ const SAFEARRAY *pSrc) - { - assert(pSrc != NULL); - VariantClear(this); - - LPSAFEARRAY pCopy; - HRESULT hr = SafeArrayCopy((LPSAFEARRAY)pSrc, &pCopy); - if (SUCCEEDED(hr)) { - SafeArrayGetVartype((LPSAFEARRAY)pSrc, &vt); - vt |= VT_ARRAY; - parray = pCopy; - } else - assert(0); - - return *this; - } - - public: - /// - /// Is variant equal to? - /// - /// \param[in] varSrc Variant to compare against - /// \return - /// - Non zero when variant is equal to \p varSrc; - /// - Zero otherwise. - /// - inline bool operator==(_In_ const VARIANT& varSrc) const - { - if (vt == VT_NULL && varSrc.vt == VT_NULL) return true; - if (vt != varSrc.vt) return false; - return compare(static_cast(*this), varSrc, LOCALE_USER_DEFAULT, 0) == static_cast(VARCMP_EQ); - } - - /// - /// Is variant not equal to? - /// - /// \param[in] varSrc Variant to compare against - /// \return - /// - Non zero when variant is not equal to \p varSrc; - /// - Zero otherwise. - /// - inline bool operator!=(_In_ const VARIANT& varSrc) const - { - return !operator==(varSrc); - } - - /// - /// Is variant less than? - /// - /// \param[in] varSrc Variant to compare against - /// \return - /// - Non zero when variant is less than \p varSrc; - /// - Zero otherwise. - /// - inline bool operator<(_In_ const VARIANT& varSrc) const - { - if (vt == VT_NULL && varSrc.vt == VT_NULL) return false; - return compare(static_cast(*this), varSrc, LOCALE_USER_DEFAULT, 0)== static_cast(VARCMP_LT); - } - - /// - /// Is variant greater than? - /// - /// \param[in] varSrc Variant to compare against - /// \return - /// - Non zero when variant is greater than \p varSrc; - /// - Zero otherwise. - /// - inline bool operator>(_In_ const VARIANT& varSrc) const - { - if (vt == VT_NULL && varSrc.vt == VT_NULL) return false; - return compare(static_cast(*this), varSrc, LOCALE_USER_DEFAULT, 0)== static_cast(VARCMP_GT); - } - - /// - /// Is variant less than or equal to? - /// - /// \param[in] varSrc Variant to compare against - /// \return - /// - Non zero when variant is less than or equal to \p varSrc; - /// - Zero otherwise. - /// - inline bool operator<=(_In_ const VARIANT& varSrc) const - { - return !operator>(varSrc); - } - - /// - /// Is variant greater than or equal to? - /// - /// \param[in] varSrc Variant to compare against - /// \return - /// - Non zero when variant is greater than or equal to \p varSrc; - /// - Zero otherwise. - /// - inline bool operator>=(_In_ const VARIANT& varSrc) const - { - return !operator<(varSrc); - } - - /// - /// Converts a variant from one type to another. - /// - /// \sa [VariantChangeType function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms221258.aspx) - /// - inline HRESULT change_type(_In_ VARTYPE _vt, _In_opt_ USHORT wFlags = 0) - { - return VariantChangeType(this, this, wFlags, _vt); - } - - private: - /// \cond internal - inline HRESULT compare(_In_ const VARIANT &varLeft, _In_ const VARIANT &varRight, _In_ LCID lcid, _In_ ULONG dwFlags) const - { - switch(vt) { - case VT_I1: return varLeft.cVal == varRight.cVal ? VARCMP_EQ : varLeft.cVal > varRight.cVal ? VARCMP_GT : VARCMP_LT; - case VT_UI2: return varLeft.uiVal == varRight.uiVal ? VARCMP_EQ : varLeft.uiVal > varRight.uiVal ? VARCMP_GT : VARCMP_LT; - case VT_UI4: return varLeft.uintVal == varRight.uintVal ? VARCMP_EQ : varLeft.uintVal > varRight.uintVal ? VARCMP_GT : VARCMP_LT; - case VT_UI8: return varLeft.ullVal == varRight.ullVal ? VARCMP_EQ : varLeft.ullVal > varRight.ullVal ? VARCMP_GT : VARCMP_LT; - default: return VarCmp(const_cast(&varLeft), const_cast(&varRight), lcid, dwFlags); - } - } - /// \endcond - }; - - - /// - /// Context scope automatic COM (un)initialization - /// - class WINSTD_API com_initializer - { - public: - /// - /// Initializes the COM library on the current thread and identifies the concurrency model as single-thread apartment (STA). - /// - /// \sa [CoInitialize function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms678543.aspx) - /// - inline com_initializer(_In_opt_ LPVOID pvReserved) - { - 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. - /// - /// \sa [CoInitializeEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms695279.aspx) - /// - inline com_initializer(_In_opt_ LPVOID pvReserved, _In_ DWORD dwCoInit) - { - m_result = CoInitializeEx(pvReserved, dwCoInit); - } - - - /// - /// Uninitializes COM. - /// - /// \sa [CoUninitialize function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms688715.aspx) - /// - virtual ~com_initializer(); - - - /// - /// Return result of `CoInitialize()` call. - /// - /// \sa [CoInitialize function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms678543.aspx) - /// - inline HRESULT status() const - { - return m_result; - } - - protected: - HRESULT m_result; ///< Result of CoInitialize call - }; - - /// @} - - /// - /// \defgroup WinStdExceptions Exceptions - /// Additional exceptions - /// - /// @{ - - /// - /// COM runtime error - /// - /// \note Must be defined as derived class from num_runtime_error<> to allow correct type info for dynamic typecasting and prevent folding with other derivates of num_runtime_error<>. - /// - class WINSTD_API com_runtime_error : public num_runtime_error - { - public: - /// - /// Constructs an exception - /// - /// \param[in] num COM error code - /// \param[in] msg Error message - /// - inline com_runtime_error(_In_ error_type num, _In_ const std::string& msg) : num_runtime_error(num, msg.c_str()) - { - } - - - /// - /// Constructs an exception - /// - /// \param[in] num COM error code - /// \param[in] msg Error message - /// - inline com_runtime_error(_In_ error_type num, _In_z_ const char *msg) : num_runtime_error(num, msg) - { - } - - - /// - /// Copies an exception - /// - /// \param[in] other Exception to copy from - /// - inline com_runtime_error(const com_runtime_error &other) : num_runtime_error(other) - { - } - }; - - /// @} -} +/* + Copyright 1991-2018 Amebis + Copyright 2016 GÉANT + + This file is part of WinStd. + + Setup is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Setup is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Setup. If not, see . +*/ + +/// +/// \defgroup WinStdCOM COM object management +/// Provides helper templates for Windows COM object manipulation +/// + +#include "Common.h" + +#include + +namespace winstd +{ + class WINSTD_API com_runtime_error; + template class com_obj; + class WINSTD_API bstr; + class WINSTD_API variant; + class WINSTD_API com_initializer; +} + +#pragma once + + +namespace winstd +{ + + /// + /// \defgroup WinStdExceptions Exceptions + /// Additional exceptions + /// + /// @{ + + /// + /// COM runtime error + /// + /// \note Must be defined as derived class from num_runtime_error<> to allow correct type info for dynamic typecasting and prevent folding with other derivates of num_runtime_error<>. + /// + class WINSTD_API com_runtime_error : public num_runtime_error + { + public: + /// + /// Constructs an exception + /// + /// \param[in] num COM error code + /// \param[in] msg Error message + /// + inline com_runtime_error(_In_ error_type num, _In_ const std::string& msg) : num_runtime_error(num, msg.c_str()) + { + } + + + /// + /// Constructs an exception + /// + /// \param[in] num COM error code + /// \param[in] msg Error message + /// + inline com_runtime_error(_In_ error_type num, _In_z_ const char *msg) : num_runtime_error(num, msg) + { + } + + + /// + /// Copies an exception + /// + /// \param[in] other Exception to copy from + /// + inline com_runtime_error(const com_runtime_error &other) : num_runtime_error(other) + { + } + }; + + /// @} + /// \addtogroup WinStdCOM + /// @{ + + /// + /// COM object wrapper template + /// + template + class com_obj : public dplhandle + { + DPLHANDLE_IMPL(com_obj) + + public: + /// + /// Constructs a new object and creates a new class with it + /// + /// \sa [CoCreateInstance function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686615.aspx) + /// + inline com_obj(_In_ REFCLSID rclsid, _In_opt_ LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL) + { + CoCreateInstance(rclsid, pUnkOuter, dwClsContext, __uuidof(T), (LPVOID*)&m_h); + } + + + /// + /// Queries the object for another interface and creates new class with it + /// + /// \sa [IUnknown::QueryInterface method](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682521.aspx) + /// + template + inline com_obj(_Out_ _Other **other) + { + assert(other); + other->QueryInterface(__uuidof(T), (void**)&m_h); + } + + + /// + /// Queries the object for another interface and creates new class with it + /// + /// \sa [IUnknown::QueryInterface method](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682521.aspx) + /// + template + inline com_obj(_Out_ com_obj<_Other> &other) + { + assert(other); + other->QueryInterface(__uuidof(T), (void**)&m_h); + } + + + /// + /// Releases object + /// + virtual ~com_obj() + { + if (m_h) + m_h->Release(); + } + + + /// + /// Creates a new object + /// + /// \sa [CoCreateInstance function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686615.aspx) + /// + inline HRESULT create(_In_ REFCLSID rclsid, _In_opt_ LPUNKNOWN pUnkOuter = NULL, _In_ DWORD dwClsContext = CLSCTX_ALL) + { + handle_type h; + HRESULT hr = CoCreateInstance(rclsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&h); + if (SUCCEEDED(hr)) + attach(h); + return hr; + } + + + /// + /// Queries the object for another interface + /// + /// \sa [IUnknown::QueryInterface method](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682521.aspx) + /// + template + HRESULT query_interface(_Out_ _Other **h) const + { + assert(h); + assert(m_h); + return m_h->QueryInterface(__uuidof(_Other), (void**)h); + } + + + /// + /// Queries the object for another interface + /// + /// \sa [IUnknown::QueryInterface method](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682521.aspx) + /// + template + HRESULT query_interface(_Out_ com_obj<_Other> &h) const + { + assert(m_h); + _Other *_h; + HRESULT hr = m_h->QueryInterface(__uuidof(_Other), (void**)&_h); + if (SUCCEEDED(hr)) + h.attach(_h); + return hr; + } + + protected: + /// + /// Releases the object by decrementing reference counter + /// + /// \sa [IUnknown::Release method](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682317.aspx) + /// + virtual void free_internal() + { + m_h->Release(); + } + + + /// + /// Duplicates the object by incrementing the reference counter + /// + /// \sa [IUnknown::AddRef method](https://msdn.microsoft.com/en-us/library/windows/desktop/ms691379.aspx) + /// + /// \param[in] h Object handle of existing object + /// + /// \return Duplicated object handle + /// + virtual handle_type duplicate_internal(_In_ handle_type h) const + { + h->AddRef(); + return h; + } + }; + + + /// + /// BSTR string wrapper + /// + class WINSTD_API bstr : public dplhandle + { + DPLHANDLE_IMPL(bstr) + + public: + /// + /// Constructs BSTR from OLE string + /// + inline bstr(_In_ LPCOLESTR src) + { + m_h = SysAllocString(src); + } + + /// + /// Constructs BSTR from OLE string with length + /// + inline bstr(_In_ LPCOLESTR src, _In_ UINT len) + { + m_h = SysAllocStringLen(src, len); + } + + /// + /// Constructs BSTR from std::basic_string + /// + template + inline bstr(_In_ const std::basic_string &src) + { + m_h = SysAllocStringLen(src.c_str(), (UINT)src.length()); + } + + /// + /// Destroys the string + /// + /// \sa [SysFreeString function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms221481.aspx) + /// + virtual ~bstr(); + + /// + /// Returns the length of the string + /// + /// \sa [SysStringLen function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms221240.aspx) + /// + inline UINT length() const + { + return SysStringLen(m_h); + } + + protected: + /// + /// Destroys the string + /// + /// \sa [SysFreeString function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms221481.aspx) + /// + virtual void free_internal(); + + /// + /// Duplicates the string + /// + /// \param[in] h Existing string + /// + /// \return Duplicated string + /// + /// \sa [SysAllocString function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms221458.aspx) + /// + virtual handle_type duplicate_internal(_In_ handle_type h) const; + }; + + + /// + /// VARIANT struct wrapper + /// + class WINSTD_API variant : public VARIANT + { + public: + /// + /// Constructs blank VARIANT + /// + inline variant() + { + VariantInit(this); + } + + /// + /// Constructs VARIANT from another + /// + inline variant(_In_ const VARIANT& varSrc) + { + vt = VT_EMPTY; + HRESULT hr = VariantCopy(this, &varSrc); + if (FAILED(hr)) + throw winstd::com_runtime_error(hr, "VariantCopy failed."); + } + + /// + /// Moves VARIANT from another + /// + inline variant(_Inout_ VARIANT&& varSrc) + { + memcpy(this, &varSrc, sizeof(VARIANT)); + varSrc.vt = VT_EMPTY; + } + + /// + /// Constructs VARIANT from bool + /// + inline variant(_In_ bool bSrc) + { + vt = VT_BOOL; + boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE; + } + + /// + /// Constructs VARIANT from character + /// + inline variant(_In_ char cSrc) + { + vt = VT_I1; + cVal = cSrc; + } + + /// + /// Constructs VARIANT from byte + /// + inline variant(_In_ unsigned char nSrc) + { + vt = VT_UI1; + bVal = nSrc; + } + + /// + /// Constructs VARIANT from short + /// + inline variant(_In_ short nSrc) + { + vt = VT_I2; + iVal = nSrc; + } + + /// + /// Constructs VARIANT from unsigned short + /// + inline variant(_In_ unsigned short nSrc) + { + vt = VT_UI2; + uiVal = nSrc; + } + + /// + /// Constructs VARIANT from integer + /// + inline variant(_In_ int nSrc, _In_ VARTYPE vtSrc = VT_I4) + { + assert(vtSrc == VT_I4 || vtSrc == VT_INT); + vt = vtSrc; + intVal = nSrc; + } + + /// + /// Constructs VARIANT from unsigned integer + /// + inline variant(_In_ unsigned int nSrc, _In_ VARTYPE vtSrc = VT_UI4) + { + assert(vtSrc == VT_UI4 || vtSrc == VT_UINT); + vt = vtSrc; + uintVal= nSrc; + } + + /// + /// Constructs VARIANT from long + /// + inline variant(_In_ long nSrc, _In_ VARTYPE vtSrc = VT_I4) + { + assert(vtSrc == VT_I4 || vtSrc == VT_ERROR); + vt = vtSrc; + lVal = nSrc; + } + + /// + /// Constructs VARIANT from unsigned long + /// + inline variant(_In_ unsigned long nSrc) + { + vt = VT_UI4; + ulVal = nSrc; + } + + /// + /// Constructs VARIANT from float + /// + inline variant(_In_ float fltSrc) + { + vt = VT_R4; + fltVal = fltSrc; + } + + /// + /// Constructs VARIANT from double or variant date + /// + inline variant(_In_ double dblSrc, _In_ VARTYPE vtSrc = VT_R8) + { + assert(vtSrc == VT_R8 || vtSrc == VT_DATE); + vt = vtSrc; + dblVal = dblSrc; + } + + /// + /// Constructs VARIANT from 64-bit integer + /// + inline variant(_In_ long long nSrc) + { + vt = VT_I8; + llVal = nSrc; + } + + /// + /// Constructs VARIANT from unsigned integer + /// + inline variant(_In_ unsigned long long nSrc) + { + vt = VT_UI8; + ullVal = nSrc; + } + + /// + /// Constructs VARIANT from CY (64-bit integer) + /// + inline variant(_In_ CY cySrc) + { + vt = VT_CY; + cyVal.Hi = cySrc.Hi; + cyVal.Lo = cySrc.Lo; + } + + /// + /// Constructs VARIANT from OLE string + /// + inline variant(_In_z_ LPCOLESTR lpszSrc) + { + vt = VT_EMPTY; + *this = lpszSrc; + } + + /// + /// Constructs VARIANT from BSTR + /// + inline variant(_In_z_ BSTR bstr) + { + vt = VT_EMPTY; + *this = bstr; + } + + /// + /// Constructs VARIANT from IDispatch + /// + inline variant(_In_opt_ IDispatch* pSrc) + { + vt = VT_DISPATCH; + pdispVal = pSrc; + + if (pdispVal != NULL) + pdispVal->AddRef(); + } + + /// + /// Constructs VARIANT from IUnknown + /// + inline variant(_In_opt_ IUnknown* pSrc) + { + vt = VT_UNKNOWN; + punkVal = pSrc; + + if (punkVal != NULL) + punkVal->AddRef(); + } + + /// + /// Constructs VARIANT from SAFEARRAY + /// + inline variant(_In_ const SAFEARRAY *pSrc) + { + assert(pSrc != NULL); + + LPSAFEARRAY pCopy; + HRESULT hRes = SafeArrayCopy((LPSAFEARRAY)pSrc, &pCopy); + if (SUCCEEDED(hRes)) { + SafeArrayGetVartype((LPSAFEARRAY)pSrc, &vt); + vt |= VT_ARRAY; + parray = pCopy; + } else + assert(0); + } + + /// + /// Destroys VARIANT + /// + virtual ~variant(); + + /// + /// Copy from another VARIANT + /// + inline variant& operator=(_In_ const VARIANT& varSrc) + { + if (this != &varSrc) { + HRESULT hr = VariantCopy(this, &varSrc); + if (FAILED(hr)) + throw winstd::com_runtime_error(hr, "VariantCopy failed."); + } + return *this; + } + + /// + /// Moves from another VARIANT + /// + inline variant& operator=(_Inout_ VARIANT&& varSrc) + { + if (this != &varSrc) { + VariantClear(this); + memcpy(this, &varSrc, sizeof(VARIANT)); + varSrc.vt = VT_EMPTY; + } + return *this; + } + + /// + /// Copy from bool value + /// + inline variant& operator=(_In_ bool bSrc) + { + if (vt != VT_BOOL) { + VariantClear(this); + vt = VT_BOOL; + } + boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE; + return *this; + } + + /// + /// Copy from char value + /// + inline variant& operator=(_In_ char cSrc) + { + if (vt != VT_I1) { + VariantClear(this); + vt = VT_I1; + } + cVal = cSrc; + return *this; + } + + /// + /// Copy from unsigned char value + /// + inline variant& operator=(_In_ unsigned char nSrc) + { + if (vt != VT_UI1) { + VariantClear(this); + vt = VT_UI1; + } + bVal = nSrc; + return *this; + } + + /// + /// Copy from short value + /// + inline variant& operator=(_In_ short nSrc) + { + if (vt != VT_I2) { + VariantClear(this); + vt = VT_I2; + } + iVal = nSrc; + return *this; + } + + /// + /// Copy from unsigned short value + /// + inline variant& operator=(_In_ unsigned short nSrc) + { + if (vt != VT_UI2) { + VariantClear(this); + vt = VT_UI2; + } + uiVal = nSrc; + return *this; + } + + /// + /// Copy from int value + /// + inline variant& operator=(_In_ int nSrc) + { + if (vt != VT_I4) { + VariantClear(this); + vt = VT_I4; + } + intVal = nSrc; + return *this; + } + + /// + /// Copy from unsigned int value + /// + inline variant& operator=(_In_ unsigned int nSrc) + { + if (vt != VT_UI4) { + VariantClear(this); + vt = VT_UI4; + } + uintVal= nSrc; + return *this; + } + + /// + /// Copy from long value + /// + inline variant& operator=(_In_ long nSrc) + { + if (vt != VT_I4) { + VariantClear(this); + vt = VT_I4; + } + lVal = nSrc; + return *this; + } + + /// + /// Copy from unsigned long value + /// + inline variant& operator=(_In_ unsigned long nSrc) + { + if (vt != VT_UI4) { + VariantClear(this); + vt = VT_UI4; + } + ulVal = nSrc; + return *this; + } + + + /// + /// Copy from long long value + /// + inline variant& operator=(_In_ long long nSrc) + { + if (vt != VT_I8) { + VariantClear(this); + vt = VT_I8; + } + llVal = nSrc; + return *this; + } + + /// + /// Copy from unsigned long long value + /// + inline variant& operator=(_In_ unsigned long long nSrc) + { + if (vt != VT_UI8) { + VariantClear(this); + vt = VT_UI8; + } + ullVal = nSrc; + + return *this; + } + + /// + /// Copy from float value + /// + inline variant& operator=(_In_ float fltSrc) + { + if (vt != VT_R4) { + VariantClear(this); + vt = VT_R4; + } + fltVal = fltSrc; + return *this; + } + + /// + /// Copy from double value + /// + inline variant& operator=(_In_ double dblSrc) + { + if (vt != VT_R8) { + VariantClear(this); + vt = VT_R8; + } + dblVal = dblSrc; + return *this; + } + + /// + /// Copy from CY value + /// + inline variant& operator=(_In_ CY cySrc) + { + if (vt != VT_CY) { + VariantClear(this); + vt = VT_CY; + } + cyVal.Hi = cySrc.Hi; + cyVal.Lo = cySrc.Lo; + return *this; + } + + /// + /// Copy from OLE string value + /// + inline variant& operator=(_In_z_ LPCOLESTR lpszSrc) + { + VariantClear(this); + vt = VT_BSTR; + bstrVal = SysAllocString(lpszSrc); + return *this; + } + + /// + /// Copy from IDispatch + /// + inline variant& operator=(_Inout_opt_ IDispatch* pSrc) + { + VariantClear(this); + vt = VT_DISPATCH; + pdispVal = pSrc; + if (pdispVal != NULL) + pdispVal->AddRef(); + return *this; + } + + /// + /// Copy from IUnknown + /// + inline variant& operator=(_Inout_opt_ IUnknown* pSrc) + { + VariantClear(this); + vt = VT_UNKNOWN; + punkVal = pSrc; + if (punkVal != NULL) + punkVal->AddRef(); + return *this; + } + + /// + /// Copy from unsigned char reference + /// + inline variant& operator=(_In_ unsigned char* pbSrc) + { + if (vt != (VT_UI1|VT_BYREF)) { + VariantClear(this); + vt = VT_UI1|VT_BYREF; + } + pbVal = pbSrc; + return *this; + } + + /// + /// Copy from short reference + /// + inline variant& operator=(_In_ short* pnSrc) + { + if (vt != (VT_I2|VT_BYREF)) { + VariantClear(this); + vt = VT_I2|VT_BYREF; + } + piVal = pnSrc; + return *this; + } + + /// + /// Copy from unsigned short reference + /// + inline variant& operator=(_In_ unsigned short* pnSrc) + { + if (vt != (VT_UI2|VT_BYREF)) { + VariantClear(this); + vt = VT_UI2|VT_BYREF; + } + puiVal = pnSrc; + return *this; + } + + /// + /// Copy from int reference + /// + inline variant& operator=(_In_ int* pnSrc) + { + if (vt != (VT_I4|VT_BYREF)) { + VariantClear(this); + vt = VT_I4|VT_BYREF; + } + pintVal = pnSrc; + return *this; + } + + /// + /// Copy from unsigned int reference + /// + inline variant& operator=(_In_ unsigned int* pnSrc) + { + if (vt != (VT_UI4|VT_BYREF)) { + VariantClear(this); + vt = VT_UI4|VT_BYREF; + } + puintVal = pnSrc; + return *this; + } + + /// + /// Copy from long reference + /// + inline variant& operator=(_In_ long* pnSrc) + { + if (vt != (VT_I4|VT_BYREF)) { + VariantClear(this); + vt = VT_I4|VT_BYREF; + } + plVal = pnSrc; + return *this; + } + + /// + /// Copy from unsigned long reference + /// + inline variant& operator=(_In_ unsigned long* pnSrc) + { + if (vt != (VT_UI4|VT_BYREF)) { + VariantClear(this); + vt = VT_UI4|VT_BYREF; + } + pulVal = pnSrc; + return *this; + } + + /// + /// Copy from long long reference + /// + inline variant& operator=(_In_ long long* pnSrc) + { + if (vt != (VT_I8|VT_BYREF)) { + VariantClear(this); + vt = VT_I8|VT_BYREF; + } + pllVal = pnSrc; + return *this; + } + + /// + /// Copy from unsigned long long reference + /// + inline variant& operator=(_In_ unsigned long long* pnSrc) + { + if (vt != (VT_UI8|VT_BYREF)) { + VariantClear(this); + vt = VT_UI8|VT_BYREF; + } + pullVal = pnSrc; + return *this; + } + + /// + /// Copy from float reference + /// + inline variant& operator=(_In_ float* pfSrc) + { + if (vt != (VT_R4|VT_BYREF)) { + VariantClear(this); + vt = VT_R4|VT_BYREF; + } + pfltVal = pfSrc; + return *this; + } + + /// + /// Copy from double reference + /// + inline variant& operator=(_In_ double* pfSrc) + { + if (vt != (VT_R8|VT_BYREF)) { + VariantClear(this); + vt = VT_R8|VT_BYREF; + } + pdblVal = pfSrc; + return *this; + } + + /// + /// Copy from SAFEARRAY + /// + inline variant& operator=(_In_ const SAFEARRAY *pSrc) + { + assert(pSrc != NULL); + VariantClear(this); + + LPSAFEARRAY pCopy; + HRESULT hr = SafeArrayCopy((LPSAFEARRAY)pSrc, &pCopy); + if (SUCCEEDED(hr)) { + SafeArrayGetVartype((LPSAFEARRAY)pSrc, &vt); + vt |= VT_ARRAY; + parray = pCopy; + } else + assert(0); + + return *this; + } + + public: + /// + /// Is variant equal to? + /// + /// \param[in] varSrc Variant to compare against + /// \return + /// - Non zero when variant is equal to \p varSrc; + /// - Zero otherwise. + /// + inline bool operator==(_In_ const VARIANT& varSrc) const + { + if (vt == VT_NULL && varSrc.vt == VT_NULL) return true; + if (vt != varSrc.vt) return false; + return compare(static_cast(*this), varSrc, LOCALE_USER_DEFAULT, 0) == static_cast(VARCMP_EQ); + } + + /// + /// Is variant not equal to? + /// + /// \param[in] varSrc Variant to compare against + /// \return + /// - Non zero when variant is not equal to \p varSrc; + /// - Zero otherwise. + /// + inline bool operator!=(_In_ const VARIANT& varSrc) const + { + return !operator==(varSrc); + } + + /// + /// Is variant less than? + /// + /// \param[in] varSrc Variant to compare against + /// \return + /// - Non zero when variant is less than \p varSrc; + /// - Zero otherwise. + /// + inline bool operator<(_In_ const VARIANT& varSrc) const + { + if (vt == VT_NULL && varSrc.vt == VT_NULL) return false; + return compare(static_cast(*this), varSrc, LOCALE_USER_DEFAULT, 0)== static_cast(VARCMP_LT); + } + + /// + /// Is variant greater than? + /// + /// \param[in] varSrc Variant to compare against + /// \return + /// - Non zero when variant is greater than \p varSrc; + /// - Zero otherwise. + /// + inline bool operator>(_In_ const VARIANT& varSrc) const + { + if (vt == VT_NULL && varSrc.vt == VT_NULL) return false; + return compare(static_cast(*this), varSrc, LOCALE_USER_DEFAULT, 0)== static_cast(VARCMP_GT); + } + + /// + /// Is variant less than or equal to? + /// + /// \param[in] varSrc Variant to compare against + /// \return + /// - Non zero when variant is less than or equal to \p varSrc; + /// - Zero otherwise. + /// + inline bool operator<=(_In_ const VARIANT& varSrc) const + { + return !operator>(varSrc); + } + + /// + /// Is variant greater than or equal to? + /// + /// \param[in] varSrc Variant to compare against + /// \return + /// - Non zero when variant is greater than or equal to \p varSrc; + /// - Zero otherwise. + /// + inline bool operator>=(_In_ const VARIANT& varSrc) const + { + return !operator<(varSrc); + } + + /// + /// Converts a variant from one type to another. + /// + /// \sa [VariantChangeType function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms221258.aspx) + /// + inline HRESULT change_type(_In_ VARTYPE _vt, _In_opt_ USHORT wFlags = 0) + { + return VariantChangeType(this, this, wFlags, _vt); + } + + private: + /// \cond internal + inline HRESULT compare(_In_ const VARIANT &varLeft, _In_ const VARIANT &varRight, _In_ LCID lcid, _In_ ULONG dwFlags) const + { + switch(vt) { + case VT_I1: return varLeft.cVal == varRight.cVal ? VARCMP_EQ : varLeft.cVal > varRight.cVal ? VARCMP_GT : VARCMP_LT; + case VT_UI2: return varLeft.uiVal == varRight.uiVal ? VARCMP_EQ : varLeft.uiVal > varRight.uiVal ? VARCMP_GT : VARCMP_LT; + case VT_UI4: return varLeft.uintVal == varRight.uintVal ? VARCMP_EQ : varLeft.uintVal > varRight.uintVal ? VARCMP_GT : VARCMP_LT; + case VT_UI8: return varLeft.ullVal == varRight.ullVal ? VARCMP_EQ : varLeft.ullVal > varRight.ullVal ? VARCMP_GT : VARCMP_LT; + default: return VarCmp(const_cast(&varLeft), const_cast(&varRight), lcid, dwFlags); + } + } + /// \endcond + }; + + + /// + /// Context scope automatic COM (un)initialization + /// + class WINSTD_API com_initializer + { + public: + /// + /// Initializes the COM library on the current thread and identifies the concurrency model as single-thread apartment (STA). + /// + /// \sa [CoInitialize function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms678543.aspx) + /// + inline com_initializer(_In_opt_ LPVOID pvReserved) + { + 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. + /// + /// \sa [CoInitializeEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms695279.aspx) + /// + inline com_initializer(_In_opt_ LPVOID pvReserved, _In_ DWORD dwCoInit) + { + m_result = CoInitializeEx(pvReserved, dwCoInit); + } + + + /// + /// Uninitializes COM. + /// + /// \sa [CoUninitialize function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms688715.aspx) + /// + virtual ~com_initializer(); + + + /// + /// Return result of `CoInitialize()` call. + /// + /// \sa [CoInitialize function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms678543.aspx) + /// + inline HRESULT status() const + { + return m_result; + } + + protected: + HRESULT m_result; ///< Result of CoInitialize call + }; + + /// @} +} diff --git a/include/WinStd/Common.h b/include/WinStd/Common.h index b0f21b15..68bb7d85 100644 --- a/include/WinStd/Common.h +++ b/include/WinStd/Common.h @@ -1,1955 +1,1955 @@ -/* - Copyright 1991-2018 Amebis - Copyright 2016 GÉANT - - This file is part of WinStd. - - Setup is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Setup is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Setup. If not, see . -*/ - -/// -/// \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 -/// - -#include - -#include - -#include -#include -#include - -/// \addtogroup WinStdGeneral -/// @{ - -/// -/// Public function calling convention -/// -#ifndef WINSTD_API -#if defined(WINSTD_DLL) -#define WINSTD_API __declspec(dllexport) -#elif defined(WINSTD_DLLIMP) -#define WINSTD_API __declspec(dllimport) -#else -#define WINSTD_API -#endif -#endif - -/// -/// Class/struct with no virtual table declaration -/// -/// Use for storing flat data. -/// -/// This macro bypasses Doxygen limitation to parse class/struct declarations with parentheses. -/// -#define WINSTD_NOVTABLE __declspec(novtable) - -/// -/// "L" stringizing macro -/// -#ifndef __L -#define __L(x) L ## x -#endif - -/// -/// Makes string Unicode -/// -#ifndef _L -#define _L(x) __L(x) -#endif - -/// -/// Stringizing macro helper -/// -#define STRING_IMPL(x) #x - -/// -/// Stringizing macro -/// -#define STRING(x) STRING_IMPL(x) - -/// -/// Declares a class as non-copyable -/// -#define WINSTD_NONCOPYABLE(C) \ -private: \ - inline C (_In_ const C &h); \ - inline C& operator=(_In_ const C &h); - -/// @} - -/// \addtogroup WinStdSysHandles -/// @{ - -/// -/// Implements default constructors and operators to prevent their auto-generation by compiler. -/// -#define HANDLE_IMPL(C) \ -public: \ - inline C ( ) { } \ - inline C (_In_ handle_type h) : handle( h ) { } \ - inline C (_Inout_ C &&h) : handle(std::move(h)) { } \ - inline C& operator=(_In_ handle_type h) { handle::operator=( h ); return *this; } \ - inline C& operator=(_Inout_ C &&h) { handle::operator=(std::move(h)); return *this; } \ -WINSTD_NONCOPYABLE(C) - -/// -/// Implements default constructors and operators to prevent their auto-generation by compiler. -/// -#define DPLHANDLE_IMPL(C) \ -public: \ - inline C ( ) { } \ - inline C (_In_ handle_type h) : dplhandle( h ) { } \ - inline C (_In_ const C &h) : dplhandle(duplicate_internal(h.m_h)) { } \ - inline C (_Inout_ C &&h) : dplhandle(std::move (h )) { } \ - inline C& operator=(_In_ handle_type h) { dplhandle::operator=( h ); return *this; } \ - inline C& operator=(_In_ const C &h) { dplhandle::operator=( h ); return *this; } \ - inline C& operator=(_Inout_ C &&h) { dplhandle::operator=(std::move(h)); return *this; } \ -private: - -/// @} - - -#ifndef _FormatMessage_format_string_ -#define _FormatMessage_format_string_ -#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 WINSTD_API 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 inline ref_unique_ptr<_Ty, _Dx> get_ptr(_Inout_ std::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 inline ref_unique_ptr<_Ty[], _Dx> get_ptr(_Inout_ std::unique_ptr<_Ty[], _Dx> &owner); - - /// @} - - - /// \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 WINSTD_API string_guid; - class WINSTD_API 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; - - /// - /// 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 - - /// @} -} - -/// \addtogroup WinStdStrFormat -/// @{ - -/// -/// Formats string using `printf()`. -/// -/// \param[out] str Buffer to receive string -/// \param[in ] capacity Size of `str` in characters -/// \param[in ] format String template using `printf()` style -/// \param[in ] arg Arguments to `format` -/// -/// \returns Number of characters in result. -/// -#if _MSC_VER <= 1600 -inline int vsnprintf(_Out_z_cap_(capacity) char *str, _In_ size_t capacity, _In_z_ _Printf_format_string_ const char *format, _In_ va_list arg); -#endif - -/// -/// Formats string using `printf()`. -/// -/// \param[out] str Buffer to receive string -/// \param[in ] capacity Size of `str` in characters -/// \param[in ] format String template using `printf()` style -/// \param[in ] arg Arguments to `format` -/// -/// \returns Number of characters in result. -/// -inline 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); - -/// -/// Formats string using `printf()`. -/// -/// \param[out] str Formatted string -/// \param[in ] format String template using `printf()` style -/// \param[in ] arg Arguments to `format` -/// -/// \returns Number of characters in result. -/// -template inline int vsprintf(_Out_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_ const _Elem *format, _In_ va_list arg); - -/// -/// Formats string using `printf()`. -/// -/// \param[out] str Formatted string -/// \param[in ] format String template using `printf()` style -/// -/// \returns Number of characters in result. -/// -template inline int sprintf(_Out_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_ const _Elem *format, ...); - -/// -/// Formats a message string. -/// -/// \sa [FormatMessage function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351.aspx) -/// -template inline DWORD FormatMessage(_In_ DWORD dwFlags, _In_opt_ LPCVOID lpSource, _In_ DWORD dwMessageId, _In_ DWORD dwLanguageId, _Out_ std::basic_string &str, _In_opt_ va_list *Arguments); - -/// -/// Formats a message string. -/// -/// \sa [FormatMessage function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351.aspx) -/// -template inline DWORD FormatMessage(_In_ DWORD dwFlags, _In_opt_ LPCVOID lpSource, _In_ DWORD dwMessageId, _In_ DWORD dwLanguageId, _Out_ std::basic_string &str, _In_opt_ va_list *Arguments); - -/// @} - -#pragma once - -#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 - -/// @} - - -namespace winstd -{ - /// \addtogroup WinStdGeneral - /// @{ - - /// - /// Deleter for unique_ptr using LocalFree - /// - template - struct LocalFree_delete - { - typedef LocalFree_delete<_Ty> _Myt; ///< This type - - /// - /// Default construct - /// - LocalFree_delete() {} - - /// - /// Construct from another LocalFree_delete - /// - template LocalFree_delete(const LocalFree_delete<_Ty2>&) {} - - /// - /// Delete a pointer - /// - /// \sa [LocalFree function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa366730.aspx) - /// - void operator()(_Ty *_Ptr) const - { - LocalFree(_Ptr); - } - }; - - - /// - /// Deleter for unique_ptr to array of unknown size using LocalFree - /// - template - struct LocalFree_delete<_Ty[]> - { - typedef LocalFree_delete<_Ty> _Myt; ///< This type - - /// - /// Default construct - /// - LocalFree_delete() {} - - /// - /// Delete a pointer - /// - void operator()(_Ty *_Ptr) const - { - LocalFree(_Ptr); - } - - /// - /// Delete a pointer of another type - /// - /// \sa [LocalFree function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa366730.aspx) - /// - template - void operator()(_Other *) const - { - LocalFree(_Ptr); - } - }; - - - /// - /// Helper class for returning pointers to std::unique_ptr - /// - template - class ref_unique_ptr - { - public: - /// - /// Takes ownership of the pointer - /// - /// \param[inout] owner Object to attach helper to - /// - inline ref_unique_ptr(_Inout_ std::unique_ptr<_Ty, _Dx> &owner) : - m_own(owner), - m_ptr(owner.release()) - {} - - /// - /// Moves object - /// - /// \param[inout] other Source object - /// - inline ref_unique_ptr(_Inout_ ref_unique_ptr<_Ty, _Dx> &&other) : - m_own(other.m_own), - m_ptr(other.m_ptr) - { - other.m_ptr = nullptr; - } - - /// - /// Returns ownership of the pointer - /// - inline ~ref_unique_ptr() - { - if (m_ptr != nullptr) - m_own.reset(m_ptr); - } - - /// - /// Operator for pointer-to-pointer parameters by value use-cases. - /// - /// \return Pointer to the pointer - /// - inline operator typename _Ty**() - { - return &m_ptr; - } - - /// - /// Operator for reverence-to-pointer parameters by value use-cases. - /// - /// \return Reference to the pointer - /// - inline operator typename _Ty*&() - { - return m_ptr; - } - - protected: - std::unique_ptr<_Ty, _Dx> &m_own; ///< Original owner of the pointer - _Ty *m_ptr; ///< Pointer - }; - - - /// - /// Helper class for returning pointers to std::unique_ptr - /// (specialization for arrays) - /// - template - class ref_unique_ptr<_Ty[], _Dx> - { - public: - /// - /// Takes ownership of the pointer - /// - /// \param[inout] owner Object to attach helper to - /// - inline ref_unique_ptr(_Inout_ std::unique_ptr<_Ty[], _Dx> &owner) : - m_own(owner), - m_ptr(owner.release()) - {} - - /// - /// Moves object - /// - /// \param[inout] other Source object - /// - inline ref_unique_ptr(_Inout_ ref_unique_ptr<_Ty[], _Dx> &&other) : - m_own(other.m_own), - m_ptr(other.m_ptr) - { - other.m_ptr = nullptr; - } - - /// - /// Returns ownership of the pointer - /// - inline ~ref_unique_ptr() - { - if (m_ptr != nullptr) - m_own.reset(m_ptr); - } - - /// - /// Operator for pointer-to-pointer parameters by value use-cases. - /// - /// \return Pointer to the pointer - /// - inline operator typename _Ty**() - { - return &m_ptr; - } - - /// - /// Operator for reverence-to-pointer parameters by value use-cases. - /// - /// \return Reference to the pointer - /// - inline operator typename _Ty*&() - { - return m_ptr; - } - - protected: - std::unique_ptr<_Ty[], _Dx> &m_own; ///< Original owner of the pointer - _Ty *m_ptr; ///< Pointer - }; - - template - inline ref_unique_ptr<_Ty, _Dx> get_ptr(_Inout_ std::unique_ptr<_Ty, _Dx> &owner) - { - return ref_unique_ptr<_Ty, _Dx>(owner); - } - - template - inline ref_unique_ptr<_Ty[], _Dx> get_ptr(_Inout_ std::unique_ptr<_Ty[], _Dx> &owner) - { - return ref_unique_ptr<_Ty[], _Dx>(owner); - } - - /// @} - - - /// \addtogroup WinStdSysHandles - /// @{ - - /// - /// Base abstract template class to support generic object handle keeping - /// - /// It provides basic operators and methods common to all descendands of this class establishing a base to ease the replacement of native object handle type with classes in object-oriented approach. - /// - template - class handle - { - public: - /// - /// Datatype of the object handle this template class handles - /// - typedef T handle_type; - - /// - /// Initializes a new class instance with the object handle set to NULL. - /// - inline handle() : m_h(NULL) - { - } - - /// - /// Initializes a new class instance with an already available object handle. - /// - /// \param[in] h Initial object handle value - /// - inline handle(_In_ handle_type h) : m_h(h) - { - } - - /// - /// Move constructor - /// - /// \param[inout] h A rvalue reference of another object - /// - inline handle(_Inout_ handle &&h) - { - // Transfer handle. - m_h = h.m_h; - h.m_h = NULL; - } - - private: - // This class is noncopyable. - handle(_In_ const handle &h); - handle& operator=(_In_ const handle &h); - - public: - /// - /// Attaches already available object handle. - /// - /// \param[in] h Object handle value - /// - inline handle& operator=(_In_ handle_type h) - { - attach(h); - return *this; - } - - /// - /// Move assignment - /// - /// \param[inout] h A rvalue reference of another object - /// - inline handle& operator=(_Inout_ handle &&h) - { - if (this != std::addressof(h)) { - // Transfer handle. - if (m_h) - free_internal(); - m_h = h.m_h; - h.m_h = NULL; - } - return *this; - } - - /// - /// Auto-typecasting operator - /// - /// \return Object handle - /// - inline operator handle_type() const - { - return m_h; - } - - /// - /// Returns the object handle value when the object handle is a pointer to a value (class, struct, etc.). - /// - /// \return Object handle value - /// - inline handle_type*& operator*() const - { - assert(m_h != NULL); - return *m_h; - } - - /// - /// Returns the object handle reference. - /// \return Object handle reference - /// - inline handle_type* operator&() - { - assert(m_h == NULL); - return &m_h; - } - - /// - /// Provides object handle member access when the object handle is a pointer to a class or struct. - /// - /// \return Object handle - /// - inline handle_type operator->() const - { - assert(m_h != NULL); - return m_h; - } - - /// - /// Tests if the object handle is NULL. - /// - /// \return - /// - Non zero when object handle is NULL; - /// - Zero otherwise. - /// - inline bool operator!() const - { - return m_h == NULL; - } - - /// - /// Is handle less than? - /// - /// \param[in] h Object handle to compare against - /// \return - /// - Non zero when object handle is less than h; - /// - Zero otherwise. - /// - inline bool operator<(_In_ handle_type h) const - { - return m_h < h; - } - - /// - /// Is handle less than or equal to? - /// - /// \param[in] h Object handle to compare against - /// \return - /// - Non zero when object handle is less than or equal to h; - /// - Zero otherwise. - /// - inline bool operator<=(_In_ handle_type h) const - { - return !operator>(h); - } - - /// - /// Is handle greater than or equal to? - /// - /// \param[in] h Object handle to compare against - /// \return - /// - Non zero when object handle is greater than or equal to h; - /// - Zero otherwise. - /// - inline bool operator>=(_In_ handle_type h) const - { - return !operator<(h); - } - - /// - /// Is handle greater than? - /// - /// \param[in] h Object handle to compare against - /// \return - /// - Non zero when object handle is greater than h; - /// - Zero otherwise. - /// - inline bool operator>(_In_ handle_type h) const - { - return h < m_h; - } - - /// - /// Is handle not equal to? - /// - /// \param[in] h Object handle to compare against - /// \return - /// - Non zero when object handle is not equal to h; - /// - Zero otherwise. - /// - inline bool operator!=(_In_ handle_type h) const - { - return !operator==(h); - } - - /// - /// Is handle equal to? - /// - /// \param[in] h Object handle to compare against - /// \return - /// - Non zero when object handle is equal to h; - /// - Zero otherwise. - /// - inline bool operator==(_In_ handle_type h) const - { - return m_h == h; - } - - /// - /// Sets a new object handle for the class - /// - /// When the current object handle of the class is non-NULL, the object is destroyed first. - /// - /// \param[in] h New object handle - /// - inline void attach(_In_ handle_type h) - { - if (m_h) - free_internal(); - m_h = h; - } - - /// - /// Dismisses the object handle from this class - /// - /// \return Object handle - /// - inline handle_type detach() - { - handle_type h = m_h; - m_h = NULL; - return h; - } - - /// - /// Destroys the object - /// - inline void free() - { - if (m_h) { - free_internal(); - m_h = NULL; - } - } - - /// @} - - protected: - /// - /// Abstract member function that must be implemented by child classes to do the actual object destruction. - /// - virtual void free_internal() = 0; - - protected: - handle_type m_h; ///< Object handle - }; - - - /// - /// Base abstract template class to support object handle keeping for objects that support handle duplication - /// - template - class dplhandle : public handle - { - public: - /// - /// Initializes a new class instance with the object handle set to NULL. - /// - inline dplhandle() - { - } - - /// - /// Initializes a new class instance with an already available object handle. - /// - /// \param[in] h Initial object handle value - /// - inline dplhandle(_In_ handle_type h) : handle(h) - { - } - - /// - /// Copy constructor - /// - /// \param[inout] h A reference of another object - /// - inline dplhandle(_In_ const dplhandle &h) : handle(internal_duplicate(h.m_h)) - { - } - - /// - /// Move constructor - /// - /// \param[inout] h A rvalue reference of another object - /// - inline dplhandle(_Inout_ dplhandle &&h) : handle(std::move(h)) - { - } - - /// - /// Attaches already available object handle. - /// - /// \param[in] h Object handle value - /// - inline dplhandle& operator=(_In_ handle_type h) - { - handle::operator=(h); - return *this; - } - - /// - /// Duplicates the object. - /// - /// \param[in] h Object - /// - inline dplhandle& operator=(_In_ const dplhandle &h) - { - if (this != std::addressof(h)) { - if (h.m_h) { - handle_type h_new = duplicate_internal(h.m_h); - if (h_new) { - if (m_h) - free_internal(); - - m_h = h_new; - } else - assert(0); // Could not duplicate the handle - } else { - if (m_h) - free_internal(); - - m_h = NULL; - } - } - return *this; - } - - /// - /// Moves the object. - /// - /// \param[inout] h A rvalue reference of another object - /// - inline dplhandle& operator=(_Inout_ dplhandle &&h) - { - handle::operator=(std::move(h)); - return *this; - } - - /// - /// Duplicates and returns a new object handle. - /// - /// \return Duplicated object handle - /// - inline handle_type duplicate() const - { - return m_h ? duplicate_internal(m_h) : NULL; - } - - /// - /// Duplicates an object handle and sets a new object handle. - /// - /// \param[in] h Object handle of existing object - /// - /// \return - /// - true when duplication succeeds; - /// - false when duplication fails. In case of failure obtaining the extended error information is object type specific (for example: `GetLastError()`). - /// - inline bool attach_duplicated(_In_ handle_type h) - { - if (m_h) - free_internal(); - - return h ? (m_h = duplicate_internal(h)) != NULL : (m_h = NULL, true); - } - - protected: - /// - /// Abstract member function that must be implemented by child classes to do the actual object handle duplication. - /// - /// \param[in] h Object handle of existing object - /// - /// \return Duplicated object handle - /// - virtual handle_type duplicate_internal(_In_ handle_type h) const = 0; - }; - - /// @} - - /// \addtogroup WinStdGeneral - /// @{ - - /// - /// Helper class to allow limited size FIFO queues implemented as vector of elements - /// - template - class vector_queue - { - public: - /// - /// Type to measure element count and indices in - /// - typedef size_t size_type; - - /// - /// Element type - /// - typedef T value_type; - - /// - /// Reference to element type - /// - typedef T& reference; - - /// - /// Constant reference to element type - /// - typedef const T& const_reference; - - /// - /// Pointer to element - /// - typedef T* pointer; - - /// - /// Constant pointer to element - /// - typedef const T* const_pointer; - - public: - /// - /// Construct queue of fixed size. - /// - /// \param[in] size_max Maximum number of elements. Please note this cannot be changed later. - /// - inline vector_queue(_In_ size_type size_max) : - m_data(new value_type[size_max]), - m_head(0), - m_count(0), - m_size_max(size_max) - { - } - - /// - /// Copies existing queue. - /// - /// \param[in] other Queue to copy from - /// - inline vector_queue(_In_ const vector_queue &other) : - m_data(new value_type[other.m_size_max]), - m_head(other.m_head), - m_count(other.m_count), - m_size_max(other.m_size_max) - { - // Copy elements. - for (size_type i = 0; i < m_count; i++) { - size_type i_l = abs(i); - m_data[i_l] = other.m_data[i_l]; - } - } - - /// - /// Destroys the queue - /// - virtual ~vector_queue() - { - if (m_data) delete [] m_data; - } - - /// - /// Moves existing queue. - /// - /// \param[inout] other Queue to move - /// - inline vector_queue(_Inout_ vector_queue &&other) : - m_data (std::move(other.m_data )), - m_head (std::move(other.m_head )), - m_count (std::move(other.m_count )), - m_size_max(std::move(other.m_size_max)) - { - // Reset other to consistent state. - other.m_data = NULL; - other.m_head = 0; - other.m_count = 0; - other.m_size_max = 0; - } - - /// - /// Copies existing queue. - /// - /// \param[in] other Queue to copy from - /// - inline vector_queue& operator=(_In_ const vector_queue &other) - { - if (this != std::addressof(other)) { - m_head = other.m_head; - m_count = other.m_count; - m_size_max = other.m_size_max; - - // Copy elements. - if (m_data) delete [] m_data; - m_data = new value_type[other.m_size_max]; - for (size_type i = 0; i < m_count; i++) { - size_type i_l = abs(i); - m_data[i_l] = other.m_data[i_l]; - } - } - - return *this; - } - - /// - /// Moves existing queue. - /// - /// \param[inout] other Queue to move - /// - inline vector_queue& operator=(_Inout_ vector_queue &&other) - { - if (this != std::addressof(other)) { - m_data = std::move(other.m_data ); - m_head = std::move(other.m_head ); - m_count = std::move(other.m_count ); - m_size_max = std::move(other.m_size_max); - - // Reset other to consistent state. - other.m_data = NULL; - other.m_head = 0; - other.m_count = 0; - other.m_size_max = 0; - } - - return *this; - } - - /// - /// Returns the number of elements in the vector. - /// - inline size_type size() const - { - return m_count; - } - - /// - /// Returns the number of elements that the queue can contain before overwriting head ones. - /// - inline size_type capacity() const - { - return m_size_max; - } - - /// - /// Erases the elements of the queue. - /// - inline void clear() - { - m_count = 0; - } - - /// - /// Tests if the queue is empty. - /// - inline bool empty() const - { - return m_count == 0; - } - - /// - /// Returns a reference to the element at a specified location in the queue. - /// - /// \param[in] pos The subscript or position number of the element to reference in the queue. - /// - inline reference at(_In_ size_type pos) - { - if (pos >= m_count) throw std::invalid_argument("Invalid subscript"); - return m_data[abs(pos)]; - } - - /// - /// Returns a reference to the element at a specified location in the queue. - /// - /// \param[in] pos The subscript or position number of the element to reference in the queue. - /// - inline reference operator[](_In_ size_type pos) - { - if (pos >= m_count) throw std::invalid_argument("Invalid subscript"); - return m_data[abs(pos)]; - } - - /// - /// Returns a constant reference to the element at a specified location in the queue. - /// - /// \param[in] pos The subscript or position number of the element to reference in the queue. - /// - inline const_reference at(_In_ size_type pos) const - { - if (pos >= m_count) throw std::invalid_argument("Invalid subscript"); - return m_data[abs(pos)]; - } - - /// - /// Returns a constant reference to the element at a specified location in the queue. - /// - /// \param[in] pos The subscript or position number of the element to reference in the queue. - /// - inline const_reference operator[](_In_ size_type pos) const - { - if (pos >= m_count) throw std::invalid_argument("Invalid subscript"); - return m_data[abs(pos)]; - } - - /// - /// Returns a reference to the element at the absolute location in the queue. - /// - /// \note Absolute means "measured from the beginning of the storage". - /// - /// \param[in] pos The absolute subscript or position number of the element to reference in the queue. - /// - inline reference at_abs(_In_ size_type pos) - { - if (pos >= m_size_max) throw std::invalid_argument("Invalid subscript"); - return m_data[pos]; - } - - /// - /// Returns a constant reference to the element at the absolute location in the queue: measured from the beginning of the storage. - /// - /// \note Absolute means "measured from the beginning of the storage". - /// - /// \param[in] pos The absolute subscript or position number of the element to reference in the queue. - /// - inline const_reference at_abs(_In_ size_type pos) const - { - if (pos >= m_size_max) throw std::invalid_argument("Invalid subscript"); - return m_data[pos]; - } - - /// - /// Copies an existing element to the end of the queue, overriding the first one when queue is out of space. - /// - /// \param[in] v Element to copy to the end of the queue. - /// - /// \returns The absolute subscript or position number the element was copied to. - /// - inline size_type push_back(_In_ const value_type &v) - { - if (m_count < m_size_max) { - size_type pos = abs(m_count); - m_data[pos] = v; - m_count++; - return pos; - } else { - size_type pos = m_head; - m_data[pos] = v; - m_head = abs(1); - return pos; - } - } - - /// - /// Moves the element to the end of the queue, overriding the first one when queue is out of space. - /// - /// \param[in] v Element to move to the end of the queue. - /// - /// \returns The absolute subscript or position number the element was moved to. - /// - inline size_type push_back(_Inout_ value_type&&v) - { - if (m_count < m_size_max) { - size_type pos = abs(m_count); - m_data[pos] = std::move(v); - m_count++; - return pos; - } else { - size_type pos = m_head; - m_data[pos] = std::move(v); - m_head = abs(1); - return pos; - } - } - - /// - /// Removes (dequeues) the last element of the queue. - /// - inline void pop_back() - { - if (!m_count) throw std::invalid_argument("Empty storage"); - m_count--; - } - - /// - /// Copies an existing element to the head of the queue, overriding the last one when queue is out of space and moving all others one place right. - /// - /// \param[in] v Element to copy to the head of the queue. - /// - /// \returns The absolute subscript or position number the element was copied to. - /// - inline size_type push_front(_In_ const value_type &v) - { - m_head = abs(-1); - if (m_count < m_size_max) - m_count++; - m_data[m_head] = v; - return m_head; - } - - /// - /// Moves the element to the head of the queue, overriding the last one when queue is out of space and moving all others one place right. - /// - /// \param[in] v Element to move to the head of the queue. - /// - /// \returns The absolute subscript or position number the element was moved to. - /// - inline size_type push_front(_Inout_ value_type&&v) - { - m_head = abs(-1); - if (m_count < m_size_max) - m_count++; - m_data[m_head] = std::move(v); - return m_head; - } - - /// - /// Removes (dequeues) the head element of the queue. - /// - inline void pop_front() - { - if (!m_count) throw std::invalid_argument("Empty storage"); - m_head = abs(1); - m_count--; - } - - /// - /// Returns a reference to the head element in the queue. - /// - inline reference front() - { - if (!m_count) throw std::invalid_argument("Empty storage"); - return m_data[m_head]; - } - - /// - /// Returns a constant reference to the head element in the queue. - /// - inline const_reference front() const - { - if (!m_count) throw std::invalid_argument("Empty storage"); - return m_data[m_head]; - } - - /// - /// Returns a reference to the last element in the queue. - /// - inline reference back() - { - return m_data[tail()]; - } - - /// - /// Returns a constant reference to the last element in the queue. - /// - inline const_reference back() const - { - return m_data[tail()]; - } - - /// - /// Returns absolute subscript or position number of the head element in the queue. The element does not need to exist. - /// - inline size_type head() const - { - return m_head; - } - - /// - /// Returns absolute subscript or position number of the last element in the queue. The element must exist. - /// - inline size_type tail() const - { - if (!m_count) throw std::invalid_argument("Empty storage"); - return abs(m_count - 1); - } - - /// - /// Returns absolute subscript or position number of the given element in the queue. - inline size_type abs(_In_ size_type pos) const - { - return (m_head + pos) % m_size_max; - } - - protected: - value_type *m_data; ///< Underlying data container - size_type m_head; ///< Index of the first element - size_type m_count; ///< Number of elements - size_type m_size_max; ///< Maximum size - }; - - /// @} - - /// \addtogroup WinStdExceptions - /// @{ - - /// - /// Numerical runtime error - /// - template - class num_runtime_error : public std::runtime_error - { - public: - typedef _Tn error_type; ///< Error number type - - public: - /// - /// Constructs an exception - /// - /// \param[in] num Numeric error code - /// \param[in] msg Error message - /// - inline num_runtime_error(_In_ error_type num, _In_ const std::string& msg) : - m_num(num), - runtime_error(msg.c_str()) - { - } - - - /// - /// Constructs an exception - /// - /// \param[in] num Numeric error code - /// \param[in] msg Error message - /// - inline num_runtime_error(_In_ error_type num, _In_z_ const char *msg) : - m_num(num), - runtime_error(msg) - { - } - - - /// - /// Copies an exception - /// - /// \param[in] other Exception to copy from - /// - inline num_runtime_error(const num_runtime_error<_Tn> &other) : - m_num(other.m_num), - runtime_error(other) - { - } - - - /// - /// Copies an exception - /// - /// \param[in] other Exception to copy from - /// - inline num_runtime_error& operator=(const num_runtime_error<_Tn> &other) - { - if (this != addressof(other)) { - *(runtime_error*)this = other; - m_num = other.m_num; - } - - return *this; - } - - - /// - /// Returns the Windows error number - /// - inline error_type number() const - { - return m_num; - } - - protected: - error_type m_num; ///< Numeric error code - }; - - - /// - /// Windows runtime error - /// - class WINSTD_API win_runtime_error : public num_runtime_error - { - public: - /// - /// Constructs an exception - /// - /// \param[in] num Windows error code - /// \param[in] msg Error message - /// - inline win_runtime_error(_In_ error_type num, _In_ const std::string& msg) : num_runtime_error(num, msg.c_str()) - { - } - - - /// - /// Constructs an exception - /// - /// \param[in] num Windows error code - /// \param[in] msg Error message - /// - inline win_runtime_error(_In_ error_type num, _In_z_ const char *msg) : num_runtime_error(num, msg) - { - } - - - /// - /// Constructs an exception using `GetLastError()` - /// - /// \param[in] msg Error message - /// - inline win_runtime_error(_In_ const std::string& msg) : num_runtime_error(GetLastError(), msg.c_str()) - { - } - - - /// - /// Constructs an exception using `GetLastError()` - /// - /// \param[in] msg Error message - /// - inline win_runtime_error(_In_z_ const char *msg) : num_runtime_error(GetLastError(), msg) - { - } - - - /// - /// Copies an exception - /// - /// \param[in] other Exception to copy from - /// - inline win_runtime_error(const win_runtime_error &other) : num_runtime_error(other) - { - } - }; - - /// @} - - /// \addtogroup WinStdStrFormat - /// @{ - - /// - /// Base template class to support string formatting using `printf()` style templates - /// - template - class basic_string_printf : public std::basic_string<_Elem, _Traits, _Ax> - { - public: - /// \name Initializing string using template in memory - /// @{ - - /// - /// Initializes a new string and formats its contents using `printf()` style template. - /// - /// \param[in] format String template using `printf()` style - /// - inline basic_string_printf(_In_z_ _Printf_format_string_ const _Elem *format, ...) - { - va_list arg; - va_start(arg, format); - vsprintf(*this, format, arg); - va_end(arg); - } - - /// @} - - /// \name Initializing string using template in resources - /// @{ - - /// - /// Initializes a new string and formats its contents using `printf()` style template in resources. - /// - /// \param[in] hInstance Resource module handle - /// \param[in] nFormatID Resource ID of the string template using `printf()` style - /// - inline basic_string_printf(_In_ HINSTANCE hInstance, _In_ UINT nFormatID, ...) - { - _Myt format; - ATLENSURE(format.LoadString(hInstance, nFormatID)); - - va_list arg; - va_start(arg, nFormatID); - vsprintf(*this, format, arg); - va_end(arg); - } - - /// - /// Initializes a new string and formats its contents using `printf()` style template in resources. - /// - /// \param[in] hInstance Resource module handle - /// \param[in] wLanguageID Resource language - /// \param[in] nFormatID Resource ID of the string template using `printf()` style - /// - inline basic_string_printf(_In_ HINSTANCE hInstance, _In_ WORD wLanguageID, _In_ UINT nFormatID, ...) - { - _Myt format; - ATLENSURE(format.LoadString(hInstance, nFormatID, wLanguageID)); - - va_list arg; - va_start(arg, nFormatID); - vsprintf(*this, format, arg); - va_end(arg); - } - - /// }@ - }; - - - /// - /// Base template class to support string formatting using `FormatMessage()` style templates - /// - template - class basic_string_msg : public std::basic_string<_Elem, _Traits, _Ax> - { - public: - /// \name Initializing string using template in memory - /// @{ - - /// - /// Initializes a new string and formats its contents using `FormatMessage()` style template. - /// - /// \param[in] format String template using `FormatMessage()` style - /// - inline basic_string_msg(_In_z_ _FormatMessage_format_string_ const _Elem *format, ...) - { - va_list arg; - va_start(arg, format); - FormatMessage(FORMAT_MESSAGE_FROM_STRING, format, 0, 0, *this, &arg); - va_end(arg); - } - - /// @} - - /// \name Initializing string using template in resources - /// @{ - - /// - /// Initializes a new string and formats its contents using `FormatMessage()` style template in resources. - /// - /// \param[in] hInstance Resource module handle - /// \param[in] nFormatID Resource ID of the string template using `FormatMessage()` style - /// - inline basic_string_msg(_In_ HINSTANCE hInstance, _In_ UINT nFormatID, ...) - { - _Myt format(GetManager()); - ATLENSURE(format.LoadString(hInstance, nFormatID)); - - va_list arg; - va_start(arg, nFormatID); - FormatMessage(FORMAT_MESSAGE_FROM_STRING, format, 0, 0, *this, &arg); - va_end(arg); - } - - /// - /// Initializes a new string and formats its contents using `FormatMessage()` style template in resources. - /// - /// \param[in] hInstance Resource module handle - /// \param[in] wLanguageID Resource language - /// \param[in] nFormatID Resource ID of the string template using `FormatMessage()` style - /// - inline basic_string_msg(_In_ HINSTANCE hInstance, _In_ WORD wLanguageID, _In_ UINT nFormatID, ...) - { - _Myt format(GetManager()); - ATLENSURE(format.LoadString(hInstance, nFormatID, wLanguageID)); - - va_list arg; - va_start(arg, nFormatID); - FormatMessage(FORMAT_MESSAGE_FROM_STRING, format, 0, 0, *this, &arg); - va_end(arg); - } - - /// @} - - - /// - /// Initializes a new string and formats its contents using `FormatMessage()` style. - /// - /// \sa [FormatMessage function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351.aspx) - /// - inline basic_string_msg(_In_ DWORD dwFlags, _In_opt_ LPCVOID lpSource, _In_ DWORD dwMessageId, _In_ DWORD dwLanguageId, _In_opt_ va_list *Arguments) - { - FormatMessage(dwFlags & ~FORMAT_MESSAGE_ARGUMENT_ARRAY, lpSource, dwMessageId, dwLanguageId, *this, Arguments); - } - - - /// - /// Initializes a new string and formats its contents using `FormatMessage()` style. - /// - /// \sa [FormatMessage function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351.aspx) - /// - inline basic_string_msg(_In_ DWORD dwFlags, _In_opt_ LPCVOID lpSource, _In_ DWORD dwMessageId, _In_ DWORD dwLanguageId, _In_opt_ DWORD_PTR *Arguments) - { - FormatMessage(dwFlags | FORMAT_MESSAGE_ARGUMENT_ARRAY, lpSource, dwMessageId, dwLanguageId, *this, (va_list*)Arguments); - } - - - /// - /// Initializes a new string and formats its contents using `FormatMessage()` style. - /// - /// \sa [FormatMessage function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351.aspx) - /// - inline basic_string_msg(_In_ DWORD dwFlags, _In_z_ LPCTSTR pszFormat, _In_opt_ va_list *Arguments) - { - 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. - /// - /// \sa [FormatMessage function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351.aspx) - /// - inline basic_string_msg(_In_ DWORD dwFlags, _In_z_ LPCTSTR pszFormat, _In_opt_ DWORD_PTR *Arguments) - { - FormatMessage(dwFlags | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_STRING, pszFormat, 0, 0, *this, (va_list*)Arguments); - } - }; - - - /// - /// Base template class to support converting GUID to string - /// - template - class basic_string_guid : public std::basic_string<_Elem, _Traits, _Ax> - { - public: - /// \name Initializing string using template in memory - /// @{ - - /// - /// Initializes a new string and formats its contents to string representation of given GUID. - /// - /// \param[in] guid GUID to convert - /// \param[in] format A `printf()` syntax template to convert GUID to string (i.e. `"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"`) - /// - inline basic_string_guid(_In_ const GUID &guid, _In_opt_z_ _Printf_format_string_ const _Elem *format) - { - sprintf<_Elem, _Traits, _Ax>(*this, format, - guid.Data1, - guid.Data2, - guid.Data3, - guid.Data4[0], guid.Data4[1], - guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); - } - - /// @} - }; - - - /// - /// Single-byte character implementation of a class to support converting GUID to string - /// - class WINSTD_API string_guid : public basic_string_guid, std::allocator > - { - public: - /// \name Initializing string using template in memory - /// @{ - - /// - /// Initializes a new string and formats its contents to string representation of given GUID. - /// - /// \param[in] guid GUID to convert - /// - inline string_guid(_In_ const GUID &guid) : - basic_string_guid, std::allocator >(guid, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}") - { - } - - /// @} - }; - - - /// - /// Wide character implementation of a class to support converting GUID to string - /// - class WINSTD_API wstring_guid : public basic_string_guid, std::allocator > - { - public: - /// \name Initializing string using template in memory - /// @{ - - /// - /// Initializes a new string and formats its contents to string representation of given GUID. - /// - /// \param[in] guid GUID to convert - /// - inline wstring_guid(_In_ const GUID &guid) : - basic_string_guid, std::allocator >(guid, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}") - { - } - - /// @} - }; - - /// @} - - /// \addtogroup WinStdMemSanitize - /// @{ - - // winstd::sanitizing_allocator::destroy() member generates _Ptr parameter not used warning for primitive datatypes _Ty. - #pragma warning(push) - #pragma warning(disable: 4100) - - /// - /// An allocator template that sanitizes each memory block before it is destroyed or reallocated - /// - /// \note - /// `sanitizing_allocator` introduces a performance penalty. However, it provides an additional level of security. - /// Use for security sensitive data memory storage only. - /// - template - class sanitizing_allocator : public std::allocator<_Ty> - { - public: - typedef std::allocator<_Ty> _Mybase; ///< Base type - - /// - /// Convert this type to sanitizing_allocator<_Other> - /// - template - struct rebind - { - typedef sanitizing_allocator<_Other> other; ///< Other type - }; - - - /// - /// Construct default allocator - /// - inline sanitizing_allocator() : _Mybase() - { - } - - - /// - /// Construct by copying - /// - inline sanitizing_allocator(_In_ const sanitizing_allocator<_Ty> &_Othr) : _Mybase(_Othr) - { - } - - - /// - /// Construct from a related allocator - /// - template - inline sanitizing_allocator(_In_ const sanitizing_allocator<_Other> &_Othr) : _Mybase(_Othr) - { - } - - - /// - /// Deallocate object at _Ptr sanitizing its content first - /// - inline void deallocate(_In_ pointer _Ptr, _In_ size_type _Size) - { - // Sanitize then free. - SecureZeroMemory(_Ptr, _Size); - _Mybase::deallocate(_Ptr, _Size); - } - }; - - #pragma warning(pop) - - /// @} -} - - -// 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(push) -#pragma warning(disable: 4995) -#pragma warning(disable: 4996) - -#if _MSC_VER <= 1600 - -inline 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 - - -inline 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) -{ - return _vsnwprintf(str, capacity, format, arg); -} - - -template -inline int vsprintf(_Out_ 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. - std::unique_ptr<_Elem[]> buf_dyn(new _Elem[capacity]); - count = vsnprintf(buf_dyn.get(), capacity - 1, format, arg); - if (count >= 0) { - str.assign(buf_dyn.get(), count); - break; - } - } - } - - return count; -} - -#pragma warning(pop) - - -template -inline int sprintf(_Out_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_ const _Elem *format, ...) -{ - va_list arg; - va_start(arg, format); - int res = vsprintf(str, format, arg); - va_end(arg); - return res; -} - - -template -inline DWORD FormatMessage(_In_ DWORD dwFlags, _In_opt_ LPCVOID lpSource, _In_ DWORD dwMessageId, _In_ DWORD dwLanguageId, _Out_ 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 -inline DWORD FormatMessage(_In_ DWORD dwFlags, _In_opt_ LPCVOID lpSource, _In_ DWORD dwMessageId, _In_ DWORD dwLanguageId, _Out_ 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; -} +/* + Copyright 1991-2018 Amebis + Copyright 2016 GÉANT + + This file is part of WinStd. + + Setup is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Setup is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Setup. If not, see . +*/ + +/// +/// \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 +/// + +#include + +#include + +#include +#include +#include + +/// \addtogroup WinStdGeneral +/// @{ + +/// +/// Public function calling convention +/// +#ifndef WINSTD_API +#if defined(WINSTD_DLL) +#define WINSTD_API __declspec(dllexport) +#elif defined(WINSTD_DLLIMP) +#define WINSTD_API __declspec(dllimport) +#else +#define WINSTD_API +#endif +#endif + +/// +/// Class/struct with no virtual table declaration +/// +/// Use for storing flat data. +/// +/// This macro bypasses Doxygen limitation to parse class/struct declarations with parentheses. +/// +#define WINSTD_NOVTABLE __declspec(novtable) + +/// +/// "L" stringizing macro +/// +#ifndef __L +#define __L(x) L ## x +#endif + +/// +/// Makes string Unicode +/// +#ifndef _L +#define _L(x) __L(x) +#endif + +/// +/// Stringizing macro helper +/// +#define STRING_IMPL(x) #x + +/// +/// Stringizing macro +/// +#define STRING(x) STRING_IMPL(x) + +/// +/// Declares a class as non-copyable +/// +#define WINSTD_NONCOPYABLE(C) \ +private: \ + inline C (_In_ const C &h); \ + inline C& operator=(_In_ const C &h); + +/// @} + +/// \addtogroup WinStdSysHandles +/// @{ + +/// +/// Implements default constructors and operators to prevent their auto-generation by compiler. +/// +#define HANDLE_IMPL(C) \ +public: \ + inline C ( ) { } \ + inline C (_In_ handle_type h) : handle( h ) { } \ + inline C (_Inout_ C &&h) noexcept : handle(std::move(h)) { } \ + inline C& operator=(_In_ handle_type h) { handle::operator=( h ); return *this; } \ + inline C& operator=(_Inout_ C &&h) noexcept { handle::operator=(std::move(h)); return *this; } \ +WINSTD_NONCOPYABLE(C) + +/// +/// Implements default constructors and operators to prevent their auto-generation by compiler. +/// +#define DPLHANDLE_IMPL(C) \ +public: \ + inline C ( ) { } \ + inline C (_In_ handle_type h) : dplhandle( h ) { } \ + inline C (_In_ const C &h) : dplhandle(duplicate_internal(h.m_h)) { } \ + inline C (_Inout_ C &&h) noexcept : dplhandle(std::move (h )) { } \ + inline C& operator=(_In_ handle_type h) { dplhandle::operator=( h ); return *this; } \ + inline C& operator=(_In_ const C &h) { dplhandle::operator=( h ); return *this; } \ + inline C& operator=(_Inout_ C &&h) noexcept { dplhandle::operator=(std::move(h)); return *this; } \ +private: + +/// @} + + +#ifndef _FormatMessage_format_string_ +#define _FormatMessage_format_string_ +#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 WINSTD_API 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 inline ref_unique_ptr<_Ty, _Dx> get_ptr(_Inout_ std::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 inline ref_unique_ptr<_Ty[], _Dx> get_ptr(_Inout_ std::unique_ptr<_Ty[], _Dx> &owner); + + /// @} + + + /// \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 WINSTD_API string_guid; + class WINSTD_API 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; + + /// + /// 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 + + /// @} +} + +/// \addtogroup WinStdStrFormat +/// @{ + +/// +/// Formats string using `printf()`. +/// +/// \param[out] str Buffer to receive string +/// \param[in ] capacity Size of `str` in characters +/// \param[in ] format String template using `printf()` style +/// \param[in ] arg Arguments to `format` +/// +/// \returns Number of characters in result. +/// +#if _MSC_VER <= 1600 +inline int vsnprintf(_Out_z_cap_(capacity) char *str, _In_ size_t capacity, _In_z_ _Printf_format_string_ const char *format, _In_ va_list arg); +#endif + +/// +/// Formats string using `printf()`. +/// +/// \param[out] str Buffer to receive string +/// \param[in ] capacity Size of `str` in characters +/// \param[in ] format String template using `printf()` style +/// \param[in ] arg Arguments to `format` +/// +/// \returns Number of characters in result. +/// +inline 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); + +/// +/// Formats string using `printf()`. +/// +/// \param[out] str Formatted string +/// \param[in ] format String template using `printf()` style +/// \param[in ] arg Arguments to `format` +/// +/// \returns Number of characters in result. +/// +template inline int vsprintf(_Out_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_ const _Elem *format, _In_ va_list arg); + +/// +/// Formats string using `printf()`. +/// +/// \param[out] str Formatted string +/// \param[in ] format String template using `printf()` style +/// +/// \returns Number of characters in result. +/// +template inline int sprintf(_Out_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_ const _Elem *format, ...); + +/// +/// Formats a message string. +/// +/// \sa [FormatMessage function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351.aspx) +/// +template inline DWORD FormatMessage(_In_ DWORD dwFlags, _In_opt_ LPCVOID lpSource, _In_ DWORD dwMessageId, _In_ DWORD dwLanguageId, _Out_ std::basic_string &str, _In_opt_ va_list *Arguments); + +/// +/// Formats a message string. +/// +/// \sa [FormatMessage function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351.aspx) +/// +template inline DWORD FormatMessage(_In_ DWORD dwFlags, _In_opt_ LPCVOID lpSource, _In_ DWORD dwMessageId, _In_ DWORD dwLanguageId, _Out_ std::basic_string &str, _In_opt_ va_list *Arguments); + +/// @} + +#pragma once + +#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 + +/// @} + + +namespace winstd +{ + /// \addtogroup WinStdGeneral + /// @{ + + /// + /// Deleter for unique_ptr using LocalFree + /// + template + struct LocalFree_delete + { + typedef LocalFree_delete<_Ty> _Myt; ///< This type + + /// + /// Default construct + /// + LocalFree_delete() {} + + /// + /// Construct from another LocalFree_delete + /// + template LocalFree_delete(const LocalFree_delete<_Ty2>&) {} + + /// + /// Delete a pointer + /// + /// \sa [LocalFree function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa366730.aspx) + /// + void operator()(_Ty *_Ptr) const + { + LocalFree(_Ptr); + } + }; + + + /// + /// Deleter for unique_ptr to array of unknown size using LocalFree + /// + template + struct LocalFree_delete<_Ty[]> + { + typedef LocalFree_delete<_Ty> _Myt; ///< This type + + /// + /// Default construct + /// + LocalFree_delete() {} + + /// + /// Delete a pointer + /// + void operator()(_Ty *_Ptr) const + { + LocalFree(_Ptr); + } + + /// + /// Delete a pointer of another type + /// + /// \sa [LocalFree function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa366730.aspx) + /// + template + void operator()(_Other *) const + { + LocalFree(_Ptr); + } + }; + + + /// + /// Helper class for returning pointers to std::unique_ptr + /// + template + class ref_unique_ptr + { + public: + /// + /// Takes ownership of the pointer + /// + /// \param[inout] owner Object to attach helper to + /// + inline ref_unique_ptr(_Inout_ std::unique_ptr<_Ty, _Dx> &owner) : + m_own(owner), + m_ptr(owner.release()) + {} + + /// + /// Moves object + /// + /// \param[inout] other Source object + /// + inline ref_unique_ptr(_Inout_ ref_unique_ptr<_Ty, _Dx> &&other) : + m_own(other.m_own), + m_ptr(other.m_ptr) + { + other.m_ptr = nullptr; + } + + /// + /// Returns ownership of the pointer + /// + inline ~ref_unique_ptr() + { + if (m_ptr != nullptr) + m_own.reset(m_ptr); + } + + /// + /// Operator for pointer-to-pointer parameters by value use-cases. + /// + /// \return Pointer to the pointer + /// + inline operator typename _Ty**() + { + return &m_ptr; + } + + /// + /// Operator for reverence-to-pointer parameters by value use-cases. + /// + /// \return Reference to the pointer + /// + inline operator typename _Ty*&() + { + return m_ptr; + } + + protected: + std::unique_ptr<_Ty, _Dx> &m_own; ///< Original owner of the pointer + _Ty *m_ptr; ///< Pointer + }; + + + /// + /// Helper class for returning pointers to std::unique_ptr + /// (specialization for arrays) + /// + template + class ref_unique_ptr<_Ty[], _Dx> + { + public: + /// + /// Takes ownership of the pointer + /// + /// \param[inout] owner Object to attach helper to + /// + inline ref_unique_ptr(_Inout_ std::unique_ptr<_Ty[], _Dx> &owner) : + m_own(owner), + m_ptr(owner.release()) + {} + + /// + /// Moves object + /// + /// \param[inout] other Source object + /// + inline ref_unique_ptr(_Inout_ ref_unique_ptr<_Ty[], _Dx> &&other) : + m_own(other.m_own), + m_ptr(other.m_ptr) + { + other.m_ptr = nullptr; + } + + /// + /// Returns ownership of the pointer + /// + inline ~ref_unique_ptr() + { + if (m_ptr != nullptr) + m_own.reset(m_ptr); + } + + /// + /// Operator for pointer-to-pointer parameters by value use-cases. + /// + /// \return Pointer to the pointer + /// + inline operator typename _Ty**() + { + return &m_ptr; + } + + /// + /// Operator for reverence-to-pointer parameters by value use-cases. + /// + /// \return Reference to the pointer + /// + inline operator typename _Ty*&() + { + return m_ptr; + } + + protected: + std::unique_ptr<_Ty[], _Dx> &m_own; ///< Original owner of the pointer + _Ty *m_ptr; ///< Pointer + }; + + template + inline ref_unique_ptr<_Ty, _Dx> get_ptr(_Inout_ std::unique_ptr<_Ty, _Dx> &owner) + { + return ref_unique_ptr<_Ty, _Dx>(owner); + } + + template + inline ref_unique_ptr<_Ty[], _Dx> get_ptr(_Inout_ std::unique_ptr<_Ty[], _Dx> &owner) + { + return ref_unique_ptr<_Ty[], _Dx>(owner); + } + + /// @} + + + /// \addtogroup WinStdSysHandles + /// @{ + + /// + /// Base abstract template class to support generic object handle keeping + /// + /// It provides basic operators and methods common to all descendands of this class establishing a base to ease the replacement of native object handle type with classes in object-oriented approach. + /// + template + class handle + { + public: + /// + /// Datatype of the object handle this template class handles + /// + typedef T handle_type; + + /// + /// Initializes a new class instance with the object handle set to NULL. + /// + inline handle() : m_h(NULL) + { + } + + /// + /// Initializes a new class instance with an already available object handle. + /// + /// \param[in] h Initial object handle value + /// + inline handle(_In_ handle_type h) : m_h(h) + { + } + + /// + /// Move constructor + /// + /// \param[inout] h A rvalue reference of another object + /// + inline handle(_Inout_ handle &&h) noexcept + { + // Transfer handle. + m_h = h.m_h; + h.m_h = NULL; + } + + private: + // This class is noncopyable. + handle(_In_ const handle &h); + handle& operator=(_In_ const handle &h); + + public: + /// + /// Attaches already available object handle. + /// + /// \param[in] h Object handle value + /// + inline handle& operator=(_In_ handle_type h) + { + attach(h); + return *this; + } + + /// + /// Move assignment + /// + /// \param[inout] h A rvalue reference of another object + /// + inline handle& operator=(_Inout_ handle &&h) noexcept + { + if (this != std::addressof(h)) { + // Transfer handle. + if (m_h) + free_internal(); + m_h = h.m_h; + h.m_h = NULL; + } + return *this; + } + + /// + /// Auto-typecasting operator + /// + /// \return Object handle + /// + inline operator handle_type() const + { + return m_h; + } + + /// + /// Returns the object handle value when the object handle is a pointer to a value (class, struct, etc.). + /// + /// \return Object handle value + /// + inline handle_type*& operator*() const + { + assert(m_h != NULL); + return *m_h; + } + + /// + /// Returns the object handle reference. + /// \return Object handle reference + /// + inline handle_type* operator&() + { + assert(m_h == NULL); + return &m_h; + } + + /// + /// Provides object handle member access when the object handle is a pointer to a class or struct. + /// + /// \return Object handle + /// + inline handle_type operator->() const + { + assert(m_h != NULL); + return m_h; + } + + /// + /// Tests if the object handle is NULL. + /// + /// \return + /// - Non zero when object handle is NULL; + /// - Zero otherwise. + /// + inline bool operator!() const + { + return m_h == NULL; + } + + /// + /// Is handle less than? + /// + /// \param[in] h Object handle to compare against + /// \return + /// - Non zero when object handle is less than h; + /// - Zero otherwise. + /// + inline bool operator<(_In_ handle_type h) const + { + return m_h < h; + } + + /// + /// Is handle less than or equal to? + /// + /// \param[in] h Object handle to compare against + /// \return + /// - Non zero when object handle is less than or equal to h; + /// - Zero otherwise. + /// + inline bool operator<=(_In_ handle_type h) const + { + return !operator>(h); + } + + /// + /// Is handle greater than or equal to? + /// + /// \param[in] h Object handle to compare against + /// \return + /// - Non zero when object handle is greater than or equal to h; + /// - Zero otherwise. + /// + inline bool operator>=(_In_ handle_type h) const + { + return !operator<(h); + } + + /// + /// Is handle greater than? + /// + /// \param[in] h Object handle to compare against + /// \return + /// - Non zero when object handle is greater than h; + /// - Zero otherwise. + /// + inline bool operator>(_In_ handle_type h) const + { + return h < m_h; + } + + /// + /// Is handle not equal to? + /// + /// \param[in] h Object handle to compare against + /// \return + /// - Non zero when object handle is not equal to h; + /// - Zero otherwise. + /// + inline bool operator!=(_In_ handle_type h) const + { + return !operator==(h); + } + + /// + /// Is handle equal to? + /// + /// \param[in] h Object handle to compare against + /// \return + /// - Non zero when object handle is equal to h; + /// - Zero otherwise. + /// + inline bool operator==(_In_ handle_type h) const + { + return m_h == h; + } + + /// + /// Sets a new object handle for the class + /// + /// When the current object handle of the class is non-NULL, the object is destroyed first. + /// + /// \param[in] h New object handle + /// + inline void attach(_In_ handle_type h) + { + if (m_h) + free_internal(); + m_h = h; + } + + /// + /// Dismisses the object handle from this class + /// + /// \return Object handle + /// + inline handle_type detach() + { + handle_type h = m_h; + m_h = NULL; + return h; + } + + /// + /// Destroys the object + /// + inline void free() + { + if (m_h) { + free_internal(); + m_h = NULL; + } + } + + /// @} + + protected: + /// + /// Abstract member function that must be implemented by child classes to do the actual object destruction. + /// + virtual void free_internal() = 0; + + protected: + handle_type m_h; ///< Object handle + }; + + + /// + /// Base abstract template class to support object handle keeping for objects that support handle duplication + /// + template + class dplhandle : public handle + { + public: + /// + /// Initializes a new class instance with the object handle set to NULL. + /// + inline dplhandle() + { + } + + /// + /// Initializes a new class instance with an already available object handle. + /// + /// \param[in] h Initial object handle value + /// + inline dplhandle(_In_ handle_type h) : handle(h) + { + } + + /// + /// Copy constructor + /// + /// \param[inout] h A reference of another object + /// + inline dplhandle(_In_ const dplhandle &h) : handle(internal_duplicate(h.m_h)) + { + } + + /// + /// Move constructor + /// + /// \param[inout] h A rvalue reference of another object + /// + inline dplhandle(_Inout_ dplhandle &&h) noexcept : handle(std::move(h)) + { + } + + /// + /// Attaches already available object handle. + /// + /// \param[in] h Object handle value + /// + inline dplhandle& operator=(_In_ handle_type h) + { + handle::operator=(h); + return *this; + } + + /// + /// Duplicates the object. + /// + /// \param[in] h Object + /// + inline dplhandle& operator=(_In_ const dplhandle &h) + { + if (this != std::addressof(h)) { + if (h.m_h) { + handle_type h_new = duplicate_internal(h.m_h); + if (h_new) { + if (m_h) + free_internal(); + + m_h = h_new; + } else + assert(0); // Could not duplicate the handle + } else { + if (m_h) + free_internal(); + + m_h = NULL; + } + } + return *this; + } + + /// + /// Moves the object. + /// + /// \param[inout] h A rvalue reference of another object + /// + inline dplhandle& operator=(_Inout_ dplhandle &&h) noexcept + { + handle::operator=(std::move(h)); + return *this; + } + + /// + /// Duplicates and returns a new object handle. + /// + /// \return Duplicated object handle + /// + inline handle_type duplicate() const + { + return m_h ? duplicate_internal(m_h) : NULL; + } + + /// + /// Duplicates an object handle and sets a new object handle. + /// + /// \param[in] h Object handle of existing object + /// + /// \return + /// - true when duplication succeeds; + /// - false when duplication fails. In case of failure obtaining the extended error information is object type specific (for example: `GetLastError()`). + /// + inline bool attach_duplicated(_In_ handle_type h) + { + if (m_h) + free_internal(); + + return h ? (m_h = duplicate_internal(h)) != NULL : (m_h = NULL, true); + } + + protected: + /// + /// Abstract member function that must be implemented by child classes to do the actual object handle duplication. + /// + /// \param[in] h Object handle of existing object + /// + /// \return Duplicated object handle + /// + virtual handle_type duplicate_internal(_In_ handle_type h) const = 0; + }; + + /// @} + + /// \addtogroup WinStdGeneral + /// @{ + + /// + /// Helper class to allow limited size FIFO queues implemented as vector of elements + /// + template + class vector_queue + { + public: + /// + /// Type to measure element count and indices in + /// + typedef size_t size_type; + + /// + /// Element type + /// + typedef T value_type; + + /// + /// Reference to element type + /// + typedef T& reference; + + /// + /// Constant reference to element type + /// + typedef const T& const_reference; + + /// + /// Pointer to element + /// + typedef T* pointer; + + /// + /// Constant pointer to element + /// + typedef const T* const_pointer; + + public: + /// + /// Construct queue of fixed size. + /// + /// \param[in] size_max Maximum number of elements. Please note this cannot be changed later. + /// + inline vector_queue(_In_ size_type size_max) : + m_data(new value_type[size_max]), + m_head(0), + m_count(0), + m_size_max(size_max) + { + } + + /// + /// Copies existing queue. + /// + /// \param[in] other Queue to copy from + /// + inline vector_queue(_In_ const vector_queue &other) : + m_data(new value_type[other.m_size_max]), + m_head(other.m_head), + m_count(other.m_count), + m_size_max(other.m_size_max) + { + // Copy elements. + for (size_type i = 0; i < m_count; i++) { + size_type i_l = abs(i); + m_data[i_l] = other.m_data[i_l]; + } + } + + /// + /// Destroys the queue + /// + virtual ~vector_queue() + { + if (m_data) delete [] m_data; + } + + /// + /// Moves existing queue. + /// + /// \param[inout] other Queue to move + /// + inline vector_queue(_Inout_ vector_queue &&other) : + m_data (std::move(other.m_data )), + m_head (std::move(other.m_head )), + m_count (std::move(other.m_count )), + m_size_max(std::move(other.m_size_max)) + { + // Reset other to consistent state. + other.m_data = NULL; + other.m_head = 0; + other.m_count = 0; + other.m_size_max = 0; + } + + /// + /// Copies existing queue. + /// + /// \param[in] other Queue to copy from + /// + inline vector_queue& operator=(_In_ const vector_queue &other) + { + if (this != std::addressof(other)) { + m_head = other.m_head; + m_count = other.m_count; + m_size_max = other.m_size_max; + + // Copy elements. + if (m_data) delete [] m_data; + m_data = new value_type[other.m_size_max]; + for (size_type i = 0; i < m_count; i++) { + size_type i_l = abs(i); + m_data[i_l] = other.m_data[i_l]; + } + } + + return *this; + } + + /// + /// Moves existing queue. + /// + /// \param[inout] other Queue to move + /// + inline vector_queue& operator=(_Inout_ vector_queue &&other) + { + if (this != std::addressof(other)) { + m_data = std::move(other.m_data ); + m_head = std::move(other.m_head ); + m_count = std::move(other.m_count ); + m_size_max = std::move(other.m_size_max); + + // Reset other to consistent state. + other.m_data = NULL; + other.m_head = 0; + other.m_count = 0; + other.m_size_max = 0; + } + + return *this; + } + + /// + /// Returns the number of elements in the vector. + /// + inline size_type size() const + { + return m_count; + } + + /// + /// Returns the number of elements that the queue can contain before overwriting head ones. + /// + inline size_type capacity() const + { + return m_size_max; + } + + /// + /// Erases the elements of the queue. + /// + inline void clear() + { + m_count = 0; + } + + /// + /// Tests if the queue is empty. + /// + inline bool empty() const + { + return m_count == 0; + } + + /// + /// Returns a reference to the element at a specified location in the queue. + /// + /// \param[in] pos The subscript or position number of the element to reference in the queue. + /// + inline reference at(_In_ size_type pos) + { + if (pos >= m_count) throw std::invalid_argument("Invalid subscript"); + return m_data[abs(pos)]; + } + + /// + /// Returns a reference to the element at a specified location in the queue. + /// + /// \param[in] pos The subscript or position number of the element to reference in the queue. + /// + inline reference operator[](_In_ size_type pos) + { + if (pos >= m_count) throw std::invalid_argument("Invalid subscript"); + return m_data[abs(pos)]; + } + + /// + /// Returns a constant reference to the element at a specified location in the queue. + /// + /// \param[in] pos The subscript or position number of the element to reference in the queue. + /// + inline const_reference at(_In_ size_type pos) const + { + if (pos >= m_count) throw std::invalid_argument("Invalid subscript"); + return m_data[abs(pos)]; + } + + /// + /// Returns a constant reference to the element at a specified location in the queue. + /// + /// \param[in] pos The subscript or position number of the element to reference in the queue. + /// + inline const_reference operator[](_In_ size_type pos) const + { + if (pos >= m_count) throw std::invalid_argument("Invalid subscript"); + return m_data[abs(pos)]; + } + + /// + /// Returns a reference to the element at the absolute location in the queue. + /// + /// \note Absolute means "measured from the beginning of the storage". + /// + /// \param[in] pos The absolute subscript or position number of the element to reference in the queue. + /// + inline reference at_abs(_In_ size_type pos) + { + if (pos >= m_size_max) throw std::invalid_argument("Invalid subscript"); + return m_data[pos]; + } + + /// + /// Returns a constant reference to the element at the absolute location in the queue: measured from the beginning of the storage. + /// + /// \note Absolute means "measured from the beginning of the storage". + /// + /// \param[in] pos The absolute subscript or position number of the element to reference in the queue. + /// + inline const_reference at_abs(_In_ size_type pos) const + { + if (pos >= m_size_max) throw std::invalid_argument("Invalid subscript"); + return m_data[pos]; + } + + /// + /// Copies an existing element to the end of the queue, overriding the first one when queue is out of space. + /// + /// \param[in] v Element to copy to the end of the queue. + /// + /// \returns The absolute subscript or position number the element was copied to. + /// + inline size_type push_back(_In_ const value_type &v) + { + if (m_count < m_size_max) { + size_type pos = abs(m_count); + m_data[pos] = v; + m_count++; + return pos; + } else { + size_type pos = m_head; + m_data[pos] = v; + m_head = abs(1); + return pos; + } + } + + /// + /// Moves the element to the end of the queue, overriding the first one when queue is out of space. + /// + /// \param[in] v Element to move to the end of the queue. + /// + /// \returns The absolute subscript or position number the element was moved to. + /// + inline size_type push_back(_Inout_ value_type&&v) + { + if (m_count < m_size_max) { + size_type pos = abs(m_count); + m_data[pos] = std::move(v); + m_count++; + return pos; + } else { + size_type pos = m_head; + m_data[pos] = std::move(v); + m_head = abs(1); + return pos; + } + } + + /// + /// Removes (dequeues) the last element of the queue. + /// + inline void pop_back() + { + if (!m_count) throw std::invalid_argument("Empty storage"); + m_count--; + } + + /// + /// Copies an existing element to the head of the queue, overriding the last one when queue is out of space and moving all others one place right. + /// + /// \param[in] v Element to copy to the head of the queue. + /// + /// \returns The absolute subscript or position number the element was copied to. + /// + inline size_type push_front(_In_ const value_type &v) + { + m_head = abs(-1); + if (m_count < m_size_max) + m_count++; + m_data[m_head] = v; + return m_head; + } + + /// + /// Moves the element to the head of the queue, overriding the last one when queue is out of space and moving all others one place right. + /// + /// \param[in] v Element to move to the head of the queue. + /// + /// \returns The absolute subscript or position number the element was moved to. + /// + inline size_type push_front(_Inout_ value_type&&v) + { + m_head = abs(-1); + if (m_count < m_size_max) + m_count++; + m_data[m_head] = std::move(v); + return m_head; + } + + /// + /// Removes (dequeues) the head element of the queue. + /// + inline void pop_front() + { + if (!m_count) throw std::invalid_argument("Empty storage"); + m_head = abs(1); + m_count--; + } + + /// + /// Returns a reference to the head element in the queue. + /// + inline reference front() + { + if (!m_count) throw std::invalid_argument("Empty storage"); + return m_data[m_head]; + } + + /// + /// Returns a constant reference to the head element in the queue. + /// + inline const_reference front() const + { + if (!m_count) throw std::invalid_argument("Empty storage"); + return m_data[m_head]; + } + + /// + /// Returns a reference to the last element in the queue. + /// + inline reference back() + { + return m_data[tail()]; + } + + /// + /// Returns a constant reference to the last element in the queue. + /// + inline const_reference back() const + { + return m_data[tail()]; + } + + /// + /// Returns absolute subscript or position number of the head element in the queue. The element does not need to exist. + /// + inline size_type head() const + { + return m_head; + } + + /// + /// Returns absolute subscript or position number of the last element in the queue. The element must exist. + /// + inline size_type tail() const + { + if (!m_count) throw std::invalid_argument("Empty storage"); + return abs(m_count - 1); + } + + /// + /// Returns absolute subscript or position number of the given element in the queue. + inline size_type abs(_In_ size_type pos) const + { + return (m_head + pos) % m_size_max; + } + + protected: + value_type *m_data; ///< Underlying data container + size_type m_head; ///< Index of the first element + size_type m_count; ///< Number of elements + size_type m_size_max; ///< Maximum size + }; + + /// @} + + /// \addtogroup WinStdExceptions + /// @{ + + /// + /// Numerical runtime error + /// + template + class num_runtime_error : public std::runtime_error + { + public: + typedef _Tn error_type; ///< Error number type + + public: + /// + /// Constructs an exception + /// + /// \param[in] num Numeric error code + /// \param[in] msg Error message + /// + inline num_runtime_error(_In_ error_type num, _In_ const std::string& msg) : + m_num(num), + runtime_error(msg.c_str()) + { + } + + + /// + /// Constructs an exception + /// + /// \param[in] num Numeric error code + /// \param[in] msg Error message + /// + inline num_runtime_error(_In_ error_type num, _In_z_ const char *msg) : + m_num(num), + runtime_error(msg) + { + } + + + /// + /// Copies an exception + /// + /// \param[in] other Exception to copy from + /// + inline num_runtime_error(const num_runtime_error<_Tn> &other) : + m_num(other.m_num), + runtime_error(other) + { + } + + + /// + /// Copies an exception + /// + /// \param[in] other Exception to copy from + /// + inline num_runtime_error& operator=(const num_runtime_error<_Tn> &other) + { + if (this != addressof(other)) { + *(runtime_error*)this = other; + m_num = other.m_num; + } + + return *this; + } + + + /// + /// Returns the Windows error number + /// + inline error_type number() const + { + return m_num; + } + + protected: + error_type m_num; ///< Numeric error code + }; + + + /// + /// Windows runtime error + /// + class WINSTD_API win_runtime_error : public num_runtime_error + { + public: + /// + /// Constructs an exception + /// + /// \param[in] num Windows error code + /// \param[in] msg Error message + /// + inline win_runtime_error(_In_ error_type num, _In_ const std::string& msg) : num_runtime_error(num, msg.c_str()) + { + } + + + /// + /// Constructs an exception + /// + /// \param[in] num Windows error code + /// \param[in] msg Error message + /// + inline win_runtime_error(_In_ error_type num, _In_z_ const char *msg) : num_runtime_error(num, msg) + { + } + + + /// + /// Constructs an exception using `GetLastError()` + /// + /// \param[in] msg Error message + /// + inline win_runtime_error(_In_ const std::string& msg) : num_runtime_error(GetLastError(), msg.c_str()) + { + } + + + /// + /// Constructs an exception using `GetLastError()` + /// + /// \param[in] msg Error message + /// + inline win_runtime_error(_In_z_ const char *msg) : num_runtime_error(GetLastError(), msg) + { + } + + + /// + /// Copies an exception + /// + /// \param[in] other Exception to copy from + /// + inline win_runtime_error(const win_runtime_error &other) : num_runtime_error(other) + { + } + }; + + /// @} + + /// \addtogroup WinStdStrFormat + /// @{ + + /// + /// Base template class to support string formatting using `printf()` style templates + /// + template + class basic_string_printf : public std::basic_string<_Elem, _Traits, _Ax> + { + public: + /// \name Initializing string using template in memory + /// @{ + + /// + /// Initializes a new string and formats its contents using `printf()` style template. + /// + /// \param[in] format String template using `printf()` style + /// + inline basic_string_printf(_In_z_ _Printf_format_string_ const _Elem *format, ...) + { + va_list arg; + va_start(arg, format); + vsprintf(*this, format, arg); + va_end(arg); + } + + /// @} + + /// \name Initializing string using template in resources + /// @{ + + /// + /// Initializes a new string and formats its contents using `printf()` style template in resources. + /// + /// \param[in] hInstance Resource module handle + /// \param[in] nFormatID Resource ID of the string template using `printf()` style + /// + inline basic_string_printf(_In_ HINSTANCE hInstance, _In_ UINT nFormatID, ...) + { + _Myt format; + ATLENSURE(format.LoadString(hInstance, nFormatID)); + + va_list arg; + va_start(arg, nFormatID); + vsprintf(*this, format, arg); + va_end(arg); + } + + /// + /// Initializes a new string and formats its contents using `printf()` style template in resources. + /// + /// \param[in] hInstance Resource module handle + /// \param[in] wLanguageID Resource language + /// \param[in] nFormatID Resource ID of the string template using `printf()` style + /// + inline basic_string_printf(_In_ HINSTANCE hInstance, _In_ WORD wLanguageID, _In_ UINT nFormatID, ...) + { + _Myt format; + ATLENSURE(format.LoadString(hInstance, nFormatID, wLanguageID)); + + va_list arg; + va_start(arg, nFormatID); + vsprintf(*this, format, arg); + va_end(arg); + } + + /// }@ + }; + + + /// + /// Base template class to support string formatting using `FormatMessage()` style templates + /// + template + class basic_string_msg : public std::basic_string<_Elem, _Traits, _Ax> + { + public: + /// \name Initializing string using template in memory + /// @{ + + /// + /// Initializes a new string and formats its contents using `FormatMessage()` style template. + /// + /// \param[in] format String template using `FormatMessage()` style + /// + inline basic_string_msg(_In_z_ _FormatMessage_format_string_ const _Elem *format, ...) + { + va_list arg; + va_start(arg, format); + FormatMessage(FORMAT_MESSAGE_FROM_STRING, format, 0, 0, *this, &arg); + va_end(arg); + } + + /// @} + + /// \name Initializing string using template in resources + /// @{ + + /// + /// Initializes a new string and formats its contents using `FormatMessage()` style template in resources. + /// + /// \param[in] hInstance Resource module handle + /// \param[in] nFormatID Resource ID of the string template using `FormatMessage()` style + /// + inline basic_string_msg(_In_ HINSTANCE hInstance, _In_ UINT nFormatID, ...) + { + _Myt format(GetManager()); + ATLENSURE(format.LoadString(hInstance, nFormatID)); + + va_list arg; + va_start(arg, nFormatID); + FormatMessage(FORMAT_MESSAGE_FROM_STRING, format, 0, 0, *this, &arg); + va_end(arg); + } + + /// + /// Initializes a new string and formats its contents using `FormatMessage()` style template in resources. + /// + /// \param[in] hInstance Resource module handle + /// \param[in] wLanguageID Resource language + /// \param[in] nFormatID Resource ID of the string template using `FormatMessage()` style + /// + inline basic_string_msg(_In_ HINSTANCE hInstance, _In_ WORD wLanguageID, _In_ UINT nFormatID, ...) + { + _Myt format(GetManager()); + ATLENSURE(format.LoadString(hInstance, nFormatID, wLanguageID)); + + va_list arg; + va_start(arg, nFormatID); + FormatMessage(FORMAT_MESSAGE_FROM_STRING, format, 0, 0, *this, &arg); + va_end(arg); + } + + /// @} + + + /// + /// Initializes a new string and formats its contents using `FormatMessage()` style. + /// + /// \sa [FormatMessage function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351.aspx) + /// + inline basic_string_msg(_In_ DWORD dwFlags, _In_opt_ LPCVOID lpSource, _In_ DWORD dwMessageId, _In_ DWORD dwLanguageId, _In_opt_ va_list *Arguments) + { + FormatMessage(dwFlags & ~FORMAT_MESSAGE_ARGUMENT_ARRAY, lpSource, dwMessageId, dwLanguageId, *this, Arguments); + } + + + /// + /// Initializes a new string and formats its contents using `FormatMessage()` style. + /// + /// \sa [FormatMessage function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351.aspx) + /// + inline basic_string_msg(_In_ DWORD dwFlags, _In_opt_ LPCVOID lpSource, _In_ DWORD dwMessageId, _In_ DWORD dwLanguageId, _In_opt_ DWORD_PTR *Arguments) + { + FormatMessage(dwFlags | FORMAT_MESSAGE_ARGUMENT_ARRAY, lpSource, dwMessageId, dwLanguageId, *this, (va_list*)Arguments); + } + + + /// + /// Initializes a new string and formats its contents using `FormatMessage()` style. + /// + /// \sa [FormatMessage function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351.aspx) + /// + inline basic_string_msg(_In_ DWORD dwFlags, _In_z_ LPCTSTR pszFormat, _In_opt_ va_list *Arguments) + { + 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. + /// + /// \sa [FormatMessage function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351.aspx) + /// + inline basic_string_msg(_In_ DWORD dwFlags, _In_z_ LPCTSTR pszFormat, _In_opt_ DWORD_PTR *Arguments) + { + FormatMessage(dwFlags | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_STRING, pszFormat, 0, 0, *this, (va_list*)Arguments); + } + }; + + + /// + /// Base template class to support converting GUID to string + /// + template + class basic_string_guid : public std::basic_string<_Elem, _Traits, _Ax> + { + public: + /// \name Initializing string using template in memory + /// @{ + + /// + /// Initializes a new string and formats its contents to string representation of given GUID. + /// + /// \param[in] guid GUID to convert + /// \param[in] format A `printf()` syntax template to convert GUID to string (i.e. `"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"`) + /// + inline basic_string_guid(_In_ const GUID &guid, _In_z_ _Printf_format_string_ const _Elem *format) + { + sprintf<_Elem, _Traits, _Ax>(*this, format, + guid.Data1, + guid.Data2, + guid.Data3, + guid.Data4[0], guid.Data4[1], + guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); + } + + /// @} + }; + + + /// + /// Single-byte character implementation of a class to support converting GUID to string + /// + class WINSTD_API string_guid : public basic_string_guid, std::allocator > + { + public: + /// \name Initializing string using template in memory + /// @{ + + /// + /// Initializes a new string and formats its contents to string representation of given GUID. + /// + /// \param[in] guid GUID to convert + /// + inline string_guid(_In_ const GUID &guid) : + basic_string_guid, std::allocator >(guid, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}") + { + } + + /// @} + }; + + + /// + /// Wide character implementation of a class to support converting GUID to string + /// + class WINSTD_API wstring_guid : public basic_string_guid, std::allocator > + { + public: + /// \name Initializing string using template in memory + /// @{ + + /// + /// Initializes a new string and formats its contents to string representation of given GUID. + /// + /// \param[in] guid GUID to convert + /// + inline wstring_guid(_In_ const GUID &guid) : + basic_string_guid, std::allocator >(guid, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}") + { + } + + /// @} + }; + + /// @} + + /// \addtogroup WinStdMemSanitize + /// @{ + + // winstd::sanitizing_allocator::destroy() member generates _Ptr parameter not used warning for primitive datatypes _Ty. + #pragma warning(push) + #pragma warning(disable: 4100) + + /// + /// An allocator template that sanitizes each memory block before it is destroyed or reallocated + /// + /// \note + /// `sanitizing_allocator` introduces a performance penalty. However, it provides an additional level of security. + /// Use for security sensitive data memory storage only. + /// + template + class sanitizing_allocator : public std::allocator<_Ty> + { + public: + typedef std::allocator<_Ty> _Mybase; ///< Base type + + /// + /// Convert this type to sanitizing_allocator<_Other> + /// + template + struct rebind + { + typedef sanitizing_allocator<_Other> other; ///< Other type + }; + + + /// + /// Construct default allocator + /// + inline sanitizing_allocator() : _Mybase() + { + } + + + /// + /// Construct by copying + /// + inline sanitizing_allocator(_In_ const sanitizing_allocator<_Ty> &_Othr) : _Mybase(_Othr) + { + } + + + /// + /// Construct from a related allocator + /// + template + inline sanitizing_allocator(_In_ const sanitizing_allocator<_Other> &_Othr) : _Mybase(_Othr) + { + } + + + /// + /// Deallocate object at _Ptr sanitizing its content first + /// + inline void deallocate(_In_ pointer _Ptr, _In_ size_type _Size) + { + // Sanitize then free. + SecureZeroMemory(_Ptr, _Size); + _Mybase::deallocate(_Ptr, _Size); + } + }; + + #pragma warning(pop) + + /// @} +} + + +// 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(push) +#pragma warning(disable: 4995) +#pragma warning(disable: 4996) + +#if _MSC_VER <= 1600 + +inline 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 + + +inline 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) +{ + return _vsnwprintf(str, capacity, format, arg); +} + + +template +inline int vsprintf(_Out_ 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. + std::unique_ptr<_Elem[]> buf_dyn(new _Elem[capacity]); + count = vsnprintf(buf_dyn.get(), capacity - 1, format, arg); + if (count >= 0) { + str.assign(buf_dyn.get(), count); + break; + } + } + } + + return count; +} + +#pragma warning(pop) + + +template +inline int sprintf(_Out_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_ const _Elem *format, ...) +{ + va_list arg; + va_start(arg, format); + int res = vsprintf(str, format, arg); + va_end(arg); + return res; +} + + +template +inline DWORD FormatMessage(_In_ DWORD dwFlags, _In_opt_ LPCVOID lpSource, _In_ DWORD dwMessageId, _In_ DWORD dwLanguageId, _Out_ 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 +inline DWORD FormatMessage(_In_ DWORD dwFlags, _In_opt_ LPCVOID lpSource, _In_ DWORD dwMessageId, _In_ DWORD dwLanguageId, _Out_ 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; +} diff --git a/include/WinStd/Cred.h b/include/WinStd/Cred.h index f528e15f..e6658660 100644 --- a/include/WinStd/Cred.h +++ b/include/WinStd/Cred.h @@ -1,251 +1,248 @@ -/* - Copyright 1991-2018 Amebis - Copyright 2016 GÉANT - - This file is part of WinStd. - - Setup is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Setup is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Setup. If not, see . -*/ - -/// -/// \defgroup WinStdCryptoAPI Cryptography API -/// Integrates WinStd classes with Microsoft Cryptography API -/// - -#include "Common.h" - -#include - -#include - -namespace winstd -{ - template struct CredFree_delete; - template struct CredFree_delete<_Ty[]>; -} - - -/// \addtogroup WinStdCryptoAPI -/// @{ - -/// -/// 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) -/// -inline BOOL CredEnumerate(_In_ LPCTSTR Filter, _In_ DWORD Flags, _Out_ DWORD *Count, _Out_ std::unique_ptr > &cCredentials); - -/// @copydoc CredProtectW() -template inline BOOL CredProtectA(_In_ BOOL fAsSelf, _In_ LPCSTR pszCredentials, _In_ DWORD cchCredentials, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sProtectedCredentials, _Out_ CRED_PROTECTION_TYPE *ProtectionType); - -/// -/// Encrypts the specified credentials so that only the current security context can decrypt them. -/// -/// \sa [CredProtect function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa374803.aspx) -/// -template inline BOOL CredProtectW(_In_ BOOL fAsSelf, _In_ LPCWSTR pszCredentials, _In_ DWORD cchCredentials, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sProtectedCredentials, _Out_ CRED_PROTECTION_TYPE *ProtectionType); - -/// @copydoc CredUnprotectW() -template inline BOOL CredUnprotectA(_In_ BOOL fAsSelf, _In_ LPCSTR pszProtectedCredentials, _In_ DWORD cchCredentials, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sCredentials); - -/// -/// Decrypts credentials that were previously encrypted by using the CredProtect function. -/// -/// \sa [CredUnprotect function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa375186.aspx) -/// -template inline BOOL CredUnprotectW(_In_ BOOL fAsSelf, _In_ LPCWSTR pszProtectedCredentials, _In_ DWORD cchCredentials, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sCredentials); - -/// @} - -#pragma once - - -namespace winstd -{ - /// \addtogroup WinStdCryptoAPI - /// @{ - - /// - /// Deleter for unique_ptr using CredFree - /// - template struct CredFree_delete - { - typedef CredFree_delete<_Ty> _Myt; ///< This type - - /// - /// Default construct - /// - CredFree_delete() {} - - /// - /// Construct from another CredFree_delete - /// - template CredFree_delete(const CredFree_delete<_Ty2>&) {} - - /// - /// Delete a pointer - /// - /// \sa [CredFree function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa374796.aspx) - /// - void operator()(_Ty *_Ptr) const - { - CredFree(_Ptr); - } - }; - - - /// - /// Deleter for unique_ptr to array of unknown size using CredFree - /// - template struct CredFree_delete<_Ty[]> - { - typedef CredFree_delete<_Ty> _Myt; ///< This type - - /// - /// Default construct - /// - CredFree_delete() {} - - /// - /// Delete a pointer - /// - /// \sa [CredFree function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa374796.aspx) - /// - void operator()(_Ty *_Ptr) const - { - CredFree(_Ptr); - } - - /// - /// Delete a pointer of another type - /// - /// \sa [CredFree function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa374796.aspx) - /// - template - void operator()(_Other *) const - { - CredFree(_Ptr); - } - }; - - /// @} -} - - -inline BOOL CredEnumerate(_In_ LPCTSTR Filter, _In_ DWORD Flags, _Out_ DWORD *Count, _Out_ std::unique_ptr > &cCredentials) -{ - PCREDENTIAL *pCredentials; - if (CredEnumerate(Filter, Flags, Count, &pCredentials)) { - std::unique_ptr > cred(pCredentials); - cCredentials.swap(cred); - return TRUE; - } else - return FALSE; -} - - -template -inline BOOL CredProtectA(_In_ BOOL fAsSelf, _In_ LPCSTR pszCredentials, _In_ DWORD cchCredentials, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sProtectedCredentials, _Out_ CRED_PROTECTION_TYPE *ProtectionType) -{ - _Elem buf[WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem)]; - 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<_Elem[]> buf(new _Elem[dwSize]); - if (CredProtectA(fAsSelf, const_cast(pszCredentials), cchCredentials, buf.get(), &dwSize, ProtectionType)) { - sProtectedCredentials.assign(buf.get(), dwSize - 1); - return TRUE; - } - } - - return FALSE; -} - - -template -inline BOOL CredProtectW(_In_ BOOL fAsSelf, _In_ LPCWSTR pszCredentials, _In_ DWORD cchCredentials, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sProtectedCredentials, _Out_ CRED_PROTECTION_TYPE *ProtectionType) -{ - _Elem buf[WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem)]; - 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<_Elem[]> buf(new _Elem[dwSize]); - if (CredProtectW(fAsSelf, const_cast(pszCredentials), cchCredentials, buf.get(), &dwSize, ProtectionType)) { - sProtectedCredentials.assign(buf.get(), dwSize - 1); - return TRUE; - } - } - - return FALSE; -} - - -template -inline BOOL CredUnprotectA(_In_ BOOL fAsSelf, _In_ LPCSTR pszProtectedCredentials, _In_ DWORD cchCredentials, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sCredentials) -{ - _Elem buf[WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem)]; - 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<_Elem[]> buf(new _Elem[dwSize]); - if (CredUnprotectA(fAsSelf, const_cast(pszProtectedCredentials), cchCredentials, buf.get(), &dwSize)) { - sCredentials.assign(buf.get(), dwSize); - return TRUE; - } - } - - return FALSE; -} - - -template -inline BOOL CredUnprotectW(_In_ BOOL fAsSelf, _In_ LPCWSTR pszProtectedCredentials, _In_ DWORD cchCredentials, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sCredentials) -{ - _Elem buf[WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem)]; - 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<_Elem[]> buf(new _Elem[dwSize]); - if (CredUnprotectW(fAsSelf, const_cast(pszProtectedCredentials), cchCredentials, buf.get(), &dwSize)) { - sCredentials.assign(buf.get(), dwSize); - return TRUE; - } - } - - return FALSE; -} +/* + Copyright 1991-2018 Amebis + Copyright 2016 GÉANT + + This file is part of WinStd. + + Setup is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Setup is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Setup. If not, see . +*/ + +/// +/// \defgroup WinStdCryptoAPI Cryptography API +/// Integrates WinStd classes with Microsoft Cryptography API +/// + +#include "Common.h" + +#include + +#include + +namespace winstd +{ + template struct CredFree_delete; + template struct CredFree_delete<_Ty[]>; +} + + +/// \addtogroup WinStdCryptoAPI +/// @{ + +/// +/// 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) +/// +inline BOOL CredEnumerate(_In_ LPCTSTR Filter, _Reserved_ DWORD Flags, _Out_ DWORD *Count, _Out_ std::unique_ptr > &cCredentials); + +/// @copydoc CredProtectW() +template inline BOOL CredProtectA(_In_ BOOL fAsSelf, _In_ LPCSTR pszCredentials, _In_ DWORD cchCredentials, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sProtectedCredentials, _Out_ CRED_PROTECTION_TYPE *ProtectionType); + +/// +/// Encrypts the specified credentials so that only the current security context can decrypt them. +/// +/// \sa [CredProtect function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa374803.aspx) +/// +template inline BOOL CredProtectW(_In_ BOOL fAsSelf, _In_ LPCWSTR pszCredentials, _In_ DWORD cchCredentials, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sProtectedCredentials, _Out_ CRED_PROTECTION_TYPE *ProtectionType); + +/// @copydoc CredUnprotectW() +template inline BOOL CredUnprotectA(_In_ BOOL fAsSelf, _In_ LPCSTR pszProtectedCredentials, _In_ DWORD cchCredentials, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sCredentials); + +/// +/// Decrypts credentials that were previously encrypted by using the CredProtect function. +/// +/// \sa [CredUnprotect function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa375186.aspx) +/// +template inline BOOL CredUnprotectW(_In_ BOOL fAsSelf, _In_ LPCWSTR pszProtectedCredentials, _In_ DWORD cchCredentials, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sCredentials); + +/// @} + +#pragma once + + +namespace winstd +{ + /// \addtogroup WinStdCryptoAPI + /// @{ + + /// + /// Deleter for unique_ptr using CredFree + /// + template struct CredFree_delete + { + typedef CredFree_delete<_Ty> _Myt; ///< This type + + /// + /// Default construct + /// + CredFree_delete() {} + + /// + /// Construct from another CredFree_delete + /// + template CredFree_delete(const CredFree_delete<_Ty2>&) {} + + /// + /// Delete a pointer + /// + /// \sa [CredFree function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa374796.aspx) + /// + void operator()(_Ty *_Ptr) const + { + CredFree(_Ptr); + } + }; + + + /// + /// Deleter for unique_ptr to array of unknown size using CredFree + /// + template struct CredFree_delete<_Ty[]> + { + typedef CredFree_delete<_Ty> _Myt; ///< This type + + /// + /// Default construct + /// + CredFree_delete() {} + + /// + /// Delete a pointer + /// + /// \sa [CredFree function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa374796.aspx) + /// + void operator()(_Ty *_Ptr) const + { + CredFree(_Ptr); + } + + /// + /// Delete a pointer of another type + /// + /// \sa [CredFree function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa374796.aspx) + /// + template + void operator()(_Other *) const + { + CredFree(_Ptr); + } + }; + + /// @} +} + + +inline BOOL CredEnumerate(_In_ LPCTSTR Filter, _Reserved_ DWORD Flags, _Out_ DWORD *Count, _Out_ std::unique_ptr > &cCredentials) +{ + PCREDENTIAL *pCredentials = NULL; + BOOL bResult = CredEnumerate(Filter, Flags, Count, &pCredentials); + cCredentials.reset(pCredentials); + return bResult; +} + + +template +inline BOOL CredProtectA(_In_ BOOL fAsSelf, _In_ LPCSTR pszCredentials, _In_ DWORD cchCredentials, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sProtectedCredentials, _Out_ CRED_PROTECTION_TYPE *ProtectionType) +{ + _Elem buf[WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem)]; + 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<_Elem[]> buf(new _Elem[dwSize]); + if (CredProtectA(fAsSelf, const_cast(pszCredentials), cchCredentials, buf.get(), &dwSize, ProtectionType)) { + sProtectedCredentials.assign(buf.get(), dwSize - 1); + return TRUE; + } + } + + return FALSE; +} + + +template +inline BOOL CredProtectW(_In_ BOOL fAsSelf, _In_ LPCWSTR pszCredentials, _In_ DWORD cchCredentials, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sProtectedCredentials, _Out_ CRED_PROTECTION_TYPE *ProtectionType) +{ + _Elem buf[WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem)]; + 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<_Elem[]> buf(new _Elem[dwSize]); + if (CredProtectW(fAsSelf, const_cast(pszCredentials), cchCredentials, buf.get(), &dwSize, ProtectionType)) { + sProtectedCredentials.assign(buf.get(), dwSize - 1); + return TRUE; + } + } + + return FALSE; +} + + +template +inline BOOL CredUnprotectA(_In_ BOOL fAsSelf, _In_ LPCSTR pszProtectedCredentials, _In_ DWORD cchCredentials, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sCredentials) +{ + _Elem buf[WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem)]; + 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<_Elem[]> buf(new _Elem[dwSize]); + if (CredUnprotectA(fAsSelf, const_cast(pszProtectedCredentials), cchCredentials, buf.get(), &dwSize)) { + sCredentials.assign(buf.get(), dwSize); + return TRUE; + } + } + + return FALSE; +} + + +template +inline BOOL CredUnprotectW(_In_ BOOL fAsSelf, _In_ LPCWSTR pszProtectedCredentials, _In_ DWORD cchCredentials, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sCredentials) +{ + _Elem buf[WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem)]; + 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<_Elem[]> buf(new _Elem[dwSize]); + if (CredUnprotectW(fAsSelf, const_cast(pszProtectedCredentials), cchCredentials, buf.get(), &dwSize)) { + sCredentials.assign(buf.get(), dwSize); + return TRUE; + } + } + + return FALSE; +} diff --git a/include/WinStd/Crypt.h b/include/WinStd/Crypt.h index 4e53755a..4860b8c6 100644 --- a/include/WinStd/Crypt.h +++ b/include/WinStd/Crypt.h @@ -1,884 +1,884 @@ -/* - Copyright 1991-2018 Amebis - Copyright 2016 GÉANT - - This file is part of WinStd. - - Setup is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Setup is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Setup. If not, see . -*/ - -/// -/// \defgroup WinStdCryptoAPI Cryptography API -/// Integrates WinStd classes with Microsoft Cryptography API -/// - -#include "Common.h" - -#include - -#include -#include - -namespace winstd -{ - class WINSTD_API cert_context; - class WINSTD_API cert_chain_context; - class WINSTD_API cert_store; - class WINSTD_API crypt_prov; - class WINSTD_API crypt_hash; - class WINSTD_API crypt_key; - class WINSTD_API data_blob; -} - -/// \addtogroup WinStdCryptoAPI -/// @{ - -/// @copydoc CertGetNameStringW() -template inline DWORD CertGetNameStringA(_In_ PCCERT_CONTEXT pCertContext, _In_ DWORD dwType, _In_ DWORD dwFlags, _In_ void *pvTypePara, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sNameString); - -/// -/// 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. -/// -/// \sa [CertGetNameString function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376086.aspx) -/// -template inline DWORD CertGetNameStringW(_In_ PCCERT_CONTEXT pCertContext, _In_ DWORD dwType, _In_ DWORD dwFlags, _In_ void *pvTypePara, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sNameString); - -/// -/// Retrieves the information contained in an extended property of a certificate context. -/// -/// \sa [CertGetCertificateContextProperty function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376079.aspx) -/// -template inline BOOL WINAPI CertGetCertificateContextProperty(_In_ PCCERT_CONTEXT pCertContext, _In_ DWORD dwPropId, _Out_ std::vector<_Ty, _Ax> &aData); - -/// -/// 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 inline BOOL CryptGetHashParam(_In_ HCRYPTHASH hHash, _In_ DWORD dwParam, _Out_ std::vector<_Ty, _Ax> &aData, _In_ DWORD dwFlags); - -/// -/// Retrieves data that governs the operations of a key. -/// -/// \sa [CryptGetKeyParam function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379949.aspx) -/// -template inline BOOL CryptGetKeyParam(_In_ HCRYPTKEY hKey, _In_ DWORD dwParam, _Out_ std::vector<_Ty, _Ax> &aData, _In_ DWORD dwFlags); - -/// -/// Retrieves data that governs the operations of a key. -/// -/// \sa [CryptGetKeyParam function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379949.aspx) -/// -template inline BOOL CryptGetKeyParam(_In_ HCRYPTKEY hKey, _In_ DWORD dwParam, _Out_ T &data, _In_ DWORD dwFlags); - -/// -/// Exports a cryptographic key or a key pair from a cryptographic service provider (CSP) in a secure manner. -/// -/// \sa [CryptExportKey function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379931.aspx) -/// -template inline BOOL CryptExportKey(_In_ HCRYPTKEY hKey, _In_ HCRYPTKEY hExpKey, _In_ DWORD dwBlobType, _In_ DWORD dwFlags, _Out_ std::vector<_Ty, _Ax> &aData); - -/// -/// Encrypts data. -/// -/// \sa [CryptEncrypt function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379924.aspx) -/// -template inline BOOL CryptEncrypt(_In_ HCRYPTKEY hKey, _In_opt_ HCRYPTHASH hHash, _In_ BOOL Final, _In_ DWORD dwFlags, _Inout_ std::vector<_Ty, _Ax> &aData); - -/// -/// Decrypts data previously encrypted by using the CryptEncrypt function. -/// -/// \sa [CryptDecrypt function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379913.aspx) -/// -template inline BOOL CryptDecrypt(_In_ HCRYPTKEY hKey, _In_opt_ HCRYPTHASH hHash, _In_ BOOL Final, _In_ DWORD dwFlags, _Inout_ std::vector<_Ty, _Ax> &aData); - -/// @} - -#pragma once - -#include - -#include - - -namespace winstd -{ - /// \addtogroup WinStdCryptoAPI - /// @{ - - /// - /// PCCERT_CONTEXT wrapper class - /// - class WINSTD_API cert_context : public dplhandle - { - DPLHANDLE_IMPL(cert_context) - - public: - /// - /// Destroys the certificate context. - /// - /// \sa [CertFreeCertificateContext function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376075.aspx) - /// - virtual ~cert_context(); - - /// - /// Creates the certificate context. - /// - /// \return - /// - true when creation succeeds; - /// - false when creation fails. For extended error information, call `GetLastError()`. - /// - /// \sa [CertCreateCertificateContext function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376033.aspx) - /// - inline bool create(_In_ DWORD dwCertEncodingType, _In_ const BYTE *pbCertEncoded, _In_ DWORD cbCertEncoded) - { - handle_type h = CertCreateCertificateContext(dwCertEncodingType, pbCertEncoded, cbCertEncoded); - if (h) { - attach(h); - return true; - } else - return false; - } - - /// - /// Is certificate equal to? - /// - /// \param[in] other Certificate to compare against - /// \return - /// - Non zero when certificate is equal to \p other; - /// - Zero otherwise. - /// - inline bool operator==(_In_ const handle_type &other) const - { - return - m_h == other || - m_h->cbCertEncoded == other->cbCertEncoded && memcmp(m_h->pbCertEncoded, other->pbCertEncoded, m_h->cbCertEncoded) == 0; - } - - /// - /// Is certificate not equal to? - /// - /// \param[in] other Certificate to compare against - /// \return - /// - Non zero when certificate is not equal to \p other; - /// - Zero otherwise. - /// - inline bool operator!=(_In_ const handle_type &other) const - { - return !operator==(other); - } - - /// - /// Is certificate less than? - /// - /// \param[in] other Certificate to compare against - /// \return - /// - Non zero when certificate is less than \p other; - /// - Zero otherwise. - /// - inline bool operator<(_In_ const handle_type &other) const - { - int r = memcmp(m_h->pbCertEncoded, other->pbCertEncoded, std::min(m_h->cbCertEncoded, other->cbCertEncoded)); - return r < 0 || r == 0 && m_h->cbCertEncoded < other->cbCertEncoded; - } - - /// - /// Is certificate greater than? - /// - /// \param[in] other Certificate to compare against - /// \return - /// - Non zero when certificate is greater than \p other; - /// - Zero otherwise. - /// - inline bool operator>(_In_ const handle_type &other) const - { - int r = memcmp(m_h->pbCertEncoded, other->pbCertEncoded, std::min(m_h->cbCertEncoded, other->cbCertEncoded)); - return r > 0 || r == 0 && m_h->cbCertEncoded > other->cbCertEncoded; - } - - /// - /// Is certificate less than or equal? - /// - /// \param[in] other Certificate to compare against - /// \return - /// - Non zero when certificate is less than \p other; - /// - Zero otherwise. - /// - inline bool operator<=(_In_ const handle_type &other) const - { - return !operator>(other); - } - - /// - /// Is certificate greater than or equal? - /// - /// \param[in] other Certificate to compare against - /// \return - /// - Non zero when certificate is greater than \p other; - /// - Zero otherwise. - /// - inline bool operator>=(_In_ const handle_type &other) const - { - return !operator<(other); - } - - protected: - /// - /// Destroys the certificate context. - /// - /// \sa [CertFreeCertificateContext function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376075.aspx) - /// - virtual void free_internal(); - - /// - /// Duplicates the certificate context. - /// - /// \param[in] h Object handle of existing certificate context - /// - /// \return Duplicated certificate context handle - /// - /// \sa [CertDuplicateCertificateContext function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376045.aspx) - /// - virtual handle_type duplicate_internal(_In_ handle_type h) const; - }; - - - /// - /// PCCERT_CHAIN_CONTEXT wrapper class - /// - class WINSTD_API cert_chain_context : public dplhandle - { - DPLHANDLE_IMPL(cert_chain_context) - - public: - /// - /// Destroys the certificate chain context. - /// - /// \sa [CertFreeCertificateChain function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376073.aspx) - /// - virtual ~cert_chain_context(); - - /// - /// Creates the certificate chain context. - /// - /// \return - /// - true when creation succeeds; - /// - false when creation fails. For extended error information, call `GetLastError()`. - /// - /// \sa [CertGetCertificateChain function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376078.aspx) - /// - inline bool create(_In_opt_ HCERTCHAINENGINE hChainEngine, _In_ PCCERT_CONTEXT pCertContext, _In_opt_ LPFILETIME pTime, _In_opt_ HCERTSTORE hAdditionalStore, _In_ PCERT_CHAIN_PARA pChainPara, _In_ DWORD dwFlags, __reserved LPVOID pvReserved = NULL) - { - handle_type h; - if (CertGetCertificateChain(hChainEngine, pCertContext, pTime, hAdditionalStore, pChainPara, dwFlags, pvReserved, &h)) { - attach(h); - return true; - } else - return false; - } - - protected: - /// - /// Destroys the certificate chain context. - /// - /// \sa [CertFreeCertificateChain function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376073.aspx) - /// - virtual void free_internal(); - - /// - /// Duplicates the certificate chain context. - /// - /// \param[in] h Object handle of existing certificate chain context - /// - /// \return Duplicated certificate chain context handle - /// - /// \sa [CertDuplicateCertificateContext function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376045.aspx) - /// - virtual handle_type duplicate_internal(_In_ handle_type h) const; - }; - - - /// - /// HCERTSTORE wrapper class - /// - class WINSTD_API cert_store : public handle - { - HANDLE_IMPL(cert_store) - - public: - /// - /// Closes the certificate store. - /// - /// \sa [CertCloseStore function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376026.aspx) - /// - virtual ~cert_store(); - - /// - /// Opens the certificate store. - /// - /// \return - /// - true when creation succeeds; - /// - false when creation fails. For extended error information, call `GetLastError()`. - /// - /// \sa [CertOpenStore function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376559.aspx) - /// - inline bool create(_In_ LPCSTR lpszStoreProvider, _In_ DWORD dwEncodingType, _In_opt_ HCRYPTPROV_LEGACY hCryptProv, _In_ DWORD dwFlags, _In_opt_ const void *pvPara) - { - handle_type h = CertOpenStore(lpszStoreProvider, dwEncodingType, hCryptProv, dwFlags, pvPara); - if (h) { - attach(h); - return true; - } else - return false; - } - - /// - /// Opens the most common system certificate store. To open certificate stores with more complex requirements, such as file-based or memory-based stores, use `create()`. - /// - /// \return - /// - true when creation succeeds; - /// - false when creation fails. For extended error information, call `GetLastError()`. - /// - /// \sa [CertOpenSystemStore function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376560.aspx) - /// - inline bool create(_In_opt_ HCRYPTPROV_LEGACY hCryptProv, _In_ LPCTSTR szSubsystemProtocol) - { - handle_type h = CertOpenSystemStore(hCryptProv, szSubsystemProtocol); - if (h) { - attach(h); - return true; - } else - return false; - } - - protected: - /// - /// Closes the certificate store. - /// - /// \sa [CertCloseStore function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376026.aspx) - /// - virtual void free_internal(); - }; - - - /// - /// HCRYPTPROV wrapper class - /// - class WINSTD_API crypt_prov : public handle - { - HANDLE_IMPL(crypt_prov) - - public: - /// - /// Releases the cryptographic context. - /// - /// \sa [CryptReleaseContext function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa380268.aspx) - /// - virtual ~crypt_prov(); - - /// - /// Acquires the cryptographic context. - /// - /// \return - /// - true when creation succeeds; - /// - false when creation fails. For extended error information, call `GetLastError()`. - /// - /// \sa [CryptAcquireContext function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379886.aspx) - /// - inline bool create(_In_opt_ LPCTSTR szContainer, _In_opt_ LPCTSTR szProvider, _In_ DWORD dwProvType, _In_ DWORD dwFlags = 0) - { - handle_type h; - if (CryptAcquireContext(&h, szContainer, szProvider, dwProvType, dwFlags)) { - attach(h); - return true; - } else - return false; - } - - protected: - /// - /// Releases the cryptographic context. - /// - /// \sa [CryptReleaseContext function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa380268.aspx) - /// - virtual void free_internal(); - }; - - - /// - /// HCRYPTHASH wrapper class - /// - class WINSTD_API crypt_hash : public dplhandle - { - DPLHANDLE_IMPL(crypt_hash) - - public: - /// - /// Destroys the hash context. - /// - /// \sa [CryptDestroyHash function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379917.aspx) - /// - virtual ~crypt_hash(); - - /// - /// Creates the hash context. - /// - /// \return - /// - true when creation succeeds; - /// - false when creation fails. For extended error information, call `GetLastError()`. - /// - /// \sa [CryptCreateHash function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379908.aspx) - /// - inline bool create(_In_ HCRYPTPROV hProv, _In_ ALG_ID Algid, _In_opt_ HCRYPTKEY hKey = NULL, _In_opt_ DWORD dwFlags = 0) - { - handle_type h; - if (CryptCreateHash(hProv, Algid, hKey, dwFlags, &h)) { - attach(h); - return true; - } else - return false; - } - - protected: - /// - /// Destroys the hash context. - /// - /// \sa [CryptDestroyHash function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379917.aspx) - /// - virtual void free_internal(); - - /// - /// Duplicates the hash context. - /// - /// \param[in] h Object handle of existing hash context - /// - /// \return Duplicated hash context handle - /// - /// \sa [CryptDuplicateHash function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379919.aspx) - /// - virtual handle_type duplicate_internal(_In_ handle_type h) const; - }; - - - /// - /// HCRYPTKEY wrapper class - /// - class WINSTD_API crypt_key : public dplhandle - { - DPLHANDLE_IMPL(crypt_key) - - public: - /// - /// Destroys the key. - /// - /// \sa [CryptDestroyKey function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379918.aspx) - /// - virtual ~crypt_key(); - - /// - /// Generates the key. - /// - /// \sa [CryptGenKey function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379941.aspx) - /// - inline bool generate(_In_ HCRYPTPROV hProv, _In_ ALG_ID Algid, _In_ DWORD dwFlags) - { - handle_type h; - if (CryptGenKey(hProv, Algid, dwFlags, &h)) { - attach(h); - return true; - } else - return false; - } - - /// - /// Imports the key. - /// - /// \sa [CryptImportKey function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa380207.aspx) - /// - inline bool import(_In_ HCRYPTPROV hProv, __in_bcount(dwDataLen) const BYTE *pbData, _In_ DWORD dwDataLen, _In_ HCRYPTKEY hPubKey, _In_ DWORD dwFlags) - { - handle_type h; - if (CryptImportKey(hProv, pbData, dwDataLen, hPubKey, dwFlags, &h)) { - attach(h); - return true; - } else - return false; - } - - /// - /// Imports the public key. - /// - /// \sa [CryptImportPublicKeyInfo function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa380209.aspx) - /// - inline bool import_public(_In_ HCRYPTPROV hCryptProv, _In_ DWORD dwCertEncodingType, _In_ PCERT_PUBLIC_KEY_INFO pInfo) - { - handle_type h; - if (CryptImportPublicKeyInfo(hCryptProv, dwCertEncodingType, pInfo, &h)) { - attach(h); - return true; - } else - return false; - } - - /// - /// Generates cryptographic session keys derived from a base data value. - /// - /// \sa [CryptDeriveKey function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379916.aspx) - /// - inline bool derive(_In_ HCRYPTPROV hProv, _In_ ALG_ID Algid, _In_ HCRYPTHASH hBaseData, _In_ DWORD dwFlags) - { - handle_type h; - if (CryptDeriveKey(hProv, Algid, hBaseData, dwFlags, &h)) { - attach(h); - return true; - } else - return false; - } - - /// - /// Creates Exponent-of-one key - /// - /// \sa [How to export and import plain text session keys by using CryptoAPI](https://support.microsoft.com/en-us/kb/228786) - /// - /// \param[in] hProv Handle of cryptographics provider to use - /// \param[in] dwKeySpec Key specification (`AT_KEYEXCHANGE` or `AT_SIGNATURE`) - /// - bool create_exp1(_In_ HCRYPTPROV hProv, _In_ DWORD dwKeySpec); - - protected: - /// - /// Destroys the key. - /// - /// \sa [CryptDestroyKey function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379918.aspx) - /// - virtual void free_internal(); - - /// - /// Duplicates the key. - /// - /// \param[in] h Object handle of existing key - /// - /// \return Duplicated key handle - /// - /// \sa [CryptDuplicateKey function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379920.aspx) - /// - virtual handle_type duplicate_internal(_In_ handle_type h) const; - }; - - - /// - /// DATA_BLOB wrapper class - /// - class WINSTD_API data_blob : public DATA_BLOB - { - public: - /// - /// Initializes an empty BLOB. - /// - inline data_blob() - { - cbData = 0; - pbData = NULL; - } - - /// - /// Initializes a BLOB from existing data. - /// - inline data_blob(_In_count_(size) BYTE *data, _In_ DWORD size) - { - cbData = size; - pbData = data; - } - - /// - /// Duplicate an existing BLOB. - /// - inline data_blob(_In_ const DATA_BLOB &other) - { - cbData = other.cbData; - if (cbData) { - pbData = (BYTE*)LocalAlloc(LMEM_FIXED, other.cbData); - assert(pbData); - memcpy(pbData, other.pbData, other.cbData); - } else - pbData = NULL; - } - - /// - /// Move an existing BLOB. - /// - inline data_blob(_Inout_ DATA_BLOB &&other) - { - cbData = other.cbData; - pbData = other.pbData; - other.cbData = 0; - other.pbData = NULL; - } - - /// - /// Destroys the BLOB. - /// - virtual ~data_blob(); - - /// - /// Copy an existing BLOB. - /// - inline data_blob& operator=(_In_ const DATA_BLOB &other) - { - if (this != &other) { - cbData = other.cbData; - if (pbData) - LocalFree(pbData); - if (cbData) { - pbData = (BYTE*)LocalAlloc(LMEM_FIXED, other.cbData); - assert(pbData); - memcpy(pbData, other.pbData, other.cbData); - } else - pbData = NULL; - } - - return *this; - } - - /// - /// Move an existing BLOB. - /// - inline data_blob& operator=(_Inout_ DATA_BLOB &&other) - { - if (this != &other) { - cbData = other.cbData; - if (pbData) - LocalFree(pbData); - pbData = other.pbData; - other.cbData = 0; - other.pbData = NULL; - } - - return *this; - } - - /// - /// Get BLOB size. - /// - inline DWORD size() const - { - return cbData; - } - - /// - /// Get BLOB buffer. - /// - inline const BYTE* data() const - { - return pbData; - } - - /// - /// Get BLOB buffer. - /// - inline BYTE* data() - { - return pbData; - } - }; - - /// @} -} - - -template -inline DWORD CertGetNameStringA(_In_ PCCERT_CONTEXT pCertContext, _In_ DWORD dwType, _In_ DWORD dwFlags, _In_ void *pvTypePara, _Out_ std::basic_string<_Elem, _Traits, _Ax> &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<_Elem[]> szBuffer(new _Elem[dwSize]); - dwSize = ::CertGetNameStringA(pCertContext, dwType, dwFlags, pvTypePara, szBuffer.get(), dwSize); - sNameString.assign(szBuffer.get(), dwSize - 1); - return dwSize; -} - - -template -inline DWORD CertGetNameStringW(_In_ PCCERT_CONTEXT pCertContext, _In_ DWORD dwType, _In_ DWORD dwFlags, _In_ void *pvTypePara, _Out_ std::basic_string<_Elem, _Traits, _Ax> &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<_Elem[]> szBuffer(new _Elem[dwSize]); - dwSize = ::CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara, szBuffer.get(), dwSize); - sNameString.assign(szBuffer.get(), dwSize - 1); - return dwSize; -} - - -template -inline 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; - } - - aData.clear(); - return FALSE; -} - - -template -inline 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; - } - - aData.clear(); - return FALSE; -} - - -template -inline 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 -inline 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; - } - - aData.clear(); - return FALSE; -} - - -template -inline 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 -inline BOOL CryptExportKey(_In_ HCRYPTKEY hKey, _In_ HCRYPTKEY hExpKey, _In_ DWORD dwBlobType, _In_ DWORD dwFlags, _Out_ std::vector<_Ty, _Ax> &aData) -{ - DWORD dwKeyBLOBSize; - - 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; - } - - aData.clear(); - return FALSE; -} - - -template -inline 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 -inline 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; -} +/* + Copyright 1991-2018 Amebis + Copyright 2016 GÉANT + + This file is part of WinStd. + + Setup is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Setup is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Setup. If not, see . +*/ + +/// +/// \defgroup WinStdCryptoAPI Cryptography API +/// Integrates WinStd classes with Microsoft Cryptography API +/// + +#include "Common.h" + +#include + +#include +#include + +namespace winstd +{ + class WINSTD_API cert_context; + class WINSTD_API cert_chain_context; + class WINSTD_API cert_store; + class WINSTD_API crypt_prov; + class WINSTD_API crypt_hash; + class WINSTD_API crypt_key; + class WINSTD_API data_blob; +} + +/// \addtogroup WinStdCryptoAPI +/// @{ + +/// @copydoc CertGetNameStringW() +template inline DWORD CertGetNameStringA(_In_ PCCERT_CONTEXT pCertContext, _In_ DWORD dwType, _In_ DWORD dwFlags, _In_ void *pvTypePara, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sNameString); + +/// +/// 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. +/// +/// \sa [CertGetNameString function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376086.aspx) +/// +template inline DWORD CertGetNameStringW(_In_ PCCERT_CONTEXT pCertContext, _In_ DWORD dwType, _In_ DWORD dwFlags, _In_ void *pvTypePara, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sNameString); + +/// +/// Retrieves the information contained in an extended property of a certificate context. +/// +/// \sa [CertGetCertificateContextProperty function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376079.aspx) +/// +template inline BOOL WINAPI CertGetCertificateContextProperty(_In_ PCCERT_CONTEXT pCertContext, _In_ DWORD dwPropId, _Out_ std::vector<_Ty, _Ax> &aData); + +/// +/// 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 inline BOOL CryptGetHashParam(_In_ HCRYPTHASH hHash, _In_ DWORD dwParam, _Out_ std::vector<_Ty, _Ax> &aData, _In_ DWORD dwFlags); + +/// +/// Retrieves data that governs the operations of a key. +/// +/// \sa [CryptGetKeyParam function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379949.aspx) +/// +template inline BOOL CryptGetKeyParam(_In_ HCRYPTKEY hKey, _In_ DWORD dwParam, _Out_ std::vector<_Ty, _Ax> &aData, _In_ DWORD dwFlags); + +/// +/// Retrieves data that governs the operations of a key. +/// +/// \sa [CryptGetKeyParam function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379949.aspx) +/// +template inline BOOL CryptGetKeyParam(_In_ HCRYPTKEY hKey, _In_ DWORD dwParam, _Out_ T &data, _In_ DWORD dwFlags); + +/// +/// Exports a cryptographic key or a key pair from a cryptographic service provider (CSP) in a secure manner. +/// +/// \sa [CryptExportKey function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379931.aspx) +/// +template inline BOOL CryptExportKey(_In_ HCRYPTKEY hKey, _In_ HCRYPTKEY hExpKey, _In_ DWORD dwBlobType, _In_ DWORD dwFlags, _Out_ std::vector<_Ty, _Ax> &aData); + +/// +/// Encrypts data. +/// +/// \sa [CryptEncrypt function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379924.aspx) +/// +template inline BOOL CryptEncrypt(_In_ HCRYPTKEY hKey, _In_opt_ HCRYPTHASH hHash, _In_ BOOL Final, _In_ DWORD dwFlags, _Inout_ std::vector<_Ty, _Ax> &aData); + +/// +/// Decrypts data previously encrypted by using the CryptEncrypt function. +/// +/// \sa [CryptDecrypt function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379913.aspx) +/// +template inline BOOL CryptDecrypt(_In_ HCRYPTKEY hKey, _In_opt_ HCRYPTHASH hHash, _In_ BOOL Final, _In_ DWORD dwFlags, _Inout_ std::vector<_Ty, _Ax> &aData); + +/// @} + +#pragma once + +#include + +#include + + +namespace winstd +{ + /// \addtogroup WinStdCryptoAPI + /// @{ + + /// + /// PCCERT_CONTEXT wrapper class + /// + class WINSTD_API cert_context : public dplhandle + { + DPLHANDLE_IMPL(cert_context) + + public: + /// + /// Destroys the certificate context. + /// + /// \sa [CertFreeCertificateContext function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376075.aspx) + /// + virtual ~cert_context(); + + /// + /// Creates the certificate context. + /// + /// \return + /// - true when creation succeeds; + /// - false when creation fails. For extended error information, call `GetLastError()`. + /// + /// \sa [CertCreateCertificateContext function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376033.aspx) + /// + inline bool create(_In_ DWORD dwCertEncodingType, _In_ const BYTE *pbCertEncoded, _In_ DWORD cbCertEncoded) + { + handle_type h = CertCreateCertificateContext(dwCertEncodingType, pbCertEncoded, cbCertEncoded); + if (h) { + attach(h); + return true; + } else + return false; + } + + /// + /// Is certificate equal to? + /// + /// \param[in] other Certificate to compare against + /// \return + /// - Non zero when certificate is equal to \p other; + /// - Zero otherwise. + /// + inline bool operator==(_In_ const handle_type &other) const + { + return + m_h == other || + m_h->cbCertEncoded == other->cbCertEncoded && memcmp(m_h->pbCertEncoded, other->pbCertEncoded, m_h->cbCertEncoded) == 0; + } + + /// + /// Is certificate not equal to? + /// + /// \param[in] other Certificate to compare against + /// \return + /// - Non zero when certificate is not equal to \p other; + /// - Zero otherwise. + /// + inline bool operator!=(_In_ const handle_type &other) const + { + return !operator==(other); + } + + /// + /// Is certificate less than? + /// + /// \param[in] other Certificate to compare against + /// \return + /// - Non zero when certificate is less than \p other; + /// - Zero otherwise. + /// + inline bool operator<(_In_ const handle_type &other) const + { + int r = memcmp(m_h->pbCertEncoded, other->pbCertEncoded, std::min(m_h->cbCertEncoded, other->cbCertEncoded)); + return r < 0 || r == 0 && m_h->cbCertEncoded < other->cbCertEncoded; + } + + /// + /// Is certificate greater than? + /// + /// \param[in] other Certificate to compare against + /// \return + /// - Non zero when certificate is greater than \p other; + /// - Zero otherwise. + /// + inline bool operator>(_In_ const handle_type &other) const + { + int r = memcmp(m_h->pbCertEncoded, other->pbCertEncoded, std::min(m_h->cbCertEncoded, other->cbCertEncoded)); + return r > 0 || r == 0 && m_h->cbCertEncoded > other->cbCertEncoded; + } + + /// + /// Is certificate less than or equal? + /// + /// \param[in] other Certificate to compare against + /// \return + /// - Non zero when certificate is less than \p other; + /// - Zero otherwise. + /// + inline bool operator<=(_In_ const handle_type &other) const + { + return !operator>(other); + } + + /// + /// Is certificate greater than or equal? + /// + /// \param[in] other Certificate to compare against + /// \return + /// - Non zero when certificate is greater than \p other; + /// - Zero otherwise. + /// + inline bool operator>=(_In_ const handle_type &other) const + { + return !operator<(other); + } + + protected: + /// + /// Destroys the certificate context. + /// + /// \sa [CertFreeCertificateContext function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376075.aspx) + /// + virtual void free_internal(); + + /// + /// Duplicates the certificate context. + /// + /// \param[in] h Object handle of existing certificate context + /// + /// \return Duplicated certificate context handle + /// + /// \sa [CertDuplicateCertificateContext function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376045.aspx) + /// + virtual handle_type duplicate_internal(_In_ handle_type h) const; + }; + + + /// + /// PCCERT_CHAIN_CONTEXT wrapper class + /// + class WINSTD_API cert_chain_context : public dplhandle + { + DPLHANDLE_IMPL(cert_chain_context) + + public: + /// + /// Destroys the certificate chain context. + /// + /// \sa [CertFreeCertificateChain function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376073.aspx) + /// + virtual ~cert_chain_context(); + + /// + /// Creates the certificate chain context. + /// + /// \return + /// - true when creation succeeds; + /// - false when creation fails. For extended error information, call `GetLastError()`. + /// + /// \sa [CertGetCertificateChain function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376078.aspx) + /// + inline bool create(_In_opt_ HCERTCHAINENGINE hChainEngine, _In_ PCCERT_CONTEXT pCertContext, _In_opt_ LPFILETIME pTime, _In_opt_ HCERTSTORE hAdditionalStore, _In_ PCERT_CHAIN_PARA pChainPara, _In_ DWORD dwFlags, __reserved LPVOID pvReserved = NULL) + { + handle_type h; + if (CertGetCertificateChain(hChainEngine, pCertContext, pTime, hAdditionalStore, pChainPara, dwFlags, pvReserved, &h)) { + attach(h); + return true; + } else + return false; + } + + protected: + /// + /// Destroys the certificate chain context. + /// + /// \sa [CertFreeCertificateChain function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376073.aspx) + /// + virtual void free_internal(); + + /// + /// Duplicates the certificate chain context. + /// + /// \param[in] h Object handle of existing certificate chain context + /// + /// \return Duplicated certificate chain context handle + /// + /// \sa [CertDuplicateCertificateContext function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376045.aspx) + /// + virtual handle_type duplicate_internal(_In_ handle_type h) const; + }; + + + /// + /// HCERTSTORE wrapper class + /// + class WINSTD_API cert_store : public handle + { + HANDLE_IMPL(cert_store) + + public: + /// + /// Closes the certificate store. + /// + /// \sa [CertCloseStore function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376026.aspx) + /// + virtual ~cert_store(); + + /// + /// Opens the certificate store. + /// + /// \return + /// - true when creation succeeds; + /// - false when creation fails. For extended error information, call `GetLastError()`. + /// + /// \sa [CertOpenStore function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376559.aspx) + /// + inline bool create(_In_ LPCSTR lpszStoreProvider, _In_ DWORD dwEncodingType, _In_opt_ HCRYPTPROV_LEGACY hCryptProv, _In_ DWORD dwFlags, _In_opt_ const void *pvPara) + { + handle_type h = CertOpenStore(lpszStoreProvider, dwEncodingType, hCryptProv, dwFlags, pvPara); + if (h) { + attach(h); + return true; + } else + return false; + } + + /// + /// Opens the most common system certificate store. To open certificate stores with more complex requirements, such as file-based or memory-based stores, use `create()`. + /// + /// \return + /// - true when creation succeeds; + /// - false when creation fails. For extended error information, call `GetLastError()`. + /// + /// \sa [CertOpenSystemStore function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376560.aspx) + /// + inline bool create(_In_opt_ HCRYPTPROV_LEGACY hCryptProv, _In_ LPCTSTR szSubsystemProtocol) + { + handle_type h = CertOpenSystemStore(hCryptProv, szSubsystemProtocol); + if (h) { + attach(h); + return true; + } else + return false; + } + + protected: + /// + /// Closes the certificate store. + /// + /// \sa [CertCloseStore function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376026.aspx) + /// + virtual void free_internal(); + }; + + + /// + /// HCRYPTPROV wrapper class + /// + class WINSTD_API crypt_prov : public handle + { + HANDLE_IMPL(crypt_prov) + + public: + /// + /// Releases the cryptographic context. + /// + /// \sa [CryptReleaseContext function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa380268.aspx) + /// + virtual ~crypt_prov(); + + /// + /// Acquires the cryptographic context. + /// + /// \return + /// - true when creation succeeds; + /// - false when creation fails. For extended error information, call `GetLastError()`. + /// + /// \sa [CryptAcquireContext function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379886.aspx) + /// + inline bool create(_In_opt_ LPCTSTR szContainer, _In_opt_ LPCTSTR szProvider, _In_ DWORD dwProvType, _In_ DWORD dwFlags = 0) + { + handle_type h; + if (CryptAcquireContext(&h, szContainer, szProvider, dwProvType, dwFlags)) { + attach(h); + return true; + } else + return false; + } + + protected: + /// + /// Releases the cryptographic context. + /// + /// \sa [CryptReleaseContext function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa380268.aspx) + /// + virtual void free_internal(); + }; + + + /// + /// HCRYPTHASH wrapper class + /// + class WINSTD_API crypt_hash : public dplhandle + { + DPLHANDLE_IMPL(crypt_hash) + + public: + /// + /// Destroys the hash context. + /// + /// \sa [CryptDestroyHash function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379917.aspx) + /// + virtual ~crypt_hash(); + + /// + /// Creates the hash context. + /// + /// \return + /// - true when creation succeeds; + /// - false when creation fails. For extended error information, call `GetLastError()`. + /// + /// \sa [CryptCreateHash function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379908.aspx) + /// + inline bool create(_In_ HCRYPTPROV hProv, _In_ ALG_ID Algid, _In_opt_ HCRYPTKEY hKey = NULL, _In_opt_ DWORD dwFlags = 0) + { + handle_type h; + if (CryptCreateHash(hProv, Algid, hKey, dwFlags, &h)) { + attach(h); + return true; + } else + return false; + } + + protected: + /// + /// Destroys the hash context. + /// + /// \sa [CryptDestroyHash function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379917.aspx) + /// + virtual void free_internal(); + + /// + /// Duplicates the hash context. + /// + /// \param[in] h Object handle of existing hash context + /// + /// \return Duplicated hash context handle + /// + /// \sa [CryptDuplicateHash function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379919.aspx) + /// + virtual handle_type duplicate_internal(_In_ handle_type h) const; + }; + + + /// + /// HCRYPTKEY wrapper class + /// + class WINSTD_API crypt_key : public dplhandle + { + DPLHANDLE_IMPL(crypt_key) + + public: + /// + /// Destroys the key. + /// + /// \sa [CryptDestroyKey function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379918.aspx) + /// + virtual ~crypt_key(); + + /// + /// Generates the key. + /// + /// \sa [CryptGenKey function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379941.aspx) + /// + inline bool generate(_In_ HCRYPTPROV hProv, _In_ ALG_ID Algid, _In_ DWORD dwFlags) + { + handle_type h; + if (CryptGenKey(hProv, Algid, dwFlags, &h)) { + attach(h); + return true; + } else + return false; + } + + /// + /// Imports the key. + /// + /// \sa [CryptImportKey function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa380207.aspx) + /// + inline bool import(_In_ HCRYPTPROV hProv, __in_bcount(dwDataLen) const BYTE *pbData, _In_ DWORD dwDataLen, _In_ HCRYPTKEY hPubKey, _In_ DWORD dwFlags) + { + handle_type h; + if (CryptImportKey(hProv, pbData, dwDataLen, hPubKey, dwFlags, &h)) { + attach(h); + return true; + } else + return false; + } + + /// + /// Imports the public key. + /// + /// \sa [CryptImportPublicKeyInfo function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa380209.aspx) + /// + inline bool import_public(_In_ HCRYPTPROV hCryptProv, _In_ DWORD dwCertEncodingType, _In_ PCERT_PUBLIC_KEY_INFO pInfo) + { + handle_type h; + if (CryptImportPublicKeyInfo(hCryptProv, dwCertEncodingType, pInfo, &h)) { + attach(h); + return true; + } else + return false; + } + + /// + /// Generates cryptographic session keys derived from a base data value. + /// + /// \sa [CryptDeriveKey function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379916.aspx) + /// + inline bool derive(_In_ HCRYPTPROV hProv, _In_ ALG_ID Algid, _In_ HCRYPTHASH hBaseData, _In_ DWORD dwFlags) + { + handle_type h; + if (CryptDeriveKey(hProv, Algid, hBaseData, dwFlags, &h)) { + attach(h); + return true; + } else + return false; + } + + /// + /// Creates Exponent-of-one key + /// + /// \sa [How to export and import plain text session keys by using CryptoAPI](https://support.microsoft.com/en-us/kb/228786) + /// + /// \param[in] hProv Handle of cryptographics provider to use + /// \param[in] dwKeySpec Key specification (`AT_KEYEXCHANGE` or `AT_SIGNATURE`) + /// + bool create_exp1(_In_ HCRYPTPROV hProv, _In_ DWORD dwKeySpec); + + protected: + /// + /// Destroys the key. + /// + /// \sa [CryptDestroyKey function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379918.aspx) + /// + virtual void free_internal(); + + /// + /// Duplicates the key. + /// + /// \param[in] h Object handle of existing key + /// + /// \return Duplicated key handle + /// + /// \sa [CryptDuplicateKey function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379920.aspx) + /// + virtual handle_type duplicate_internal(_In_ handle_type h) const; + }; + + + /// + /// DATA_BLOB wrapper class + /// + class WINSTD_API data_blob : public DATA_BLOB + { + public: + /// + /// Initializes an empty BLOB. + /// + inline data_blob() + { + cbData = 0; + pbData = NULL; + } + + /// + /// Initializes a BLOB from existing data. + /// + inline data_blob(_In_count_(size) BYTE *data, _In_ DWORD size) + { + cbData = size; + pbData = data; + } + + /// + /// Duplicate an existing BLOB. + /// + inline data_blob(_In_ const DATA_BLOB &other) + { + cbData = other.cbData; + if (cbData) { + pbData = (BYTE*)LocalAlloc(LMEM_FIXED, other.cbData); + assert(pbData); + memcpy(pbData, other.pbData, other.cbData); + } else + pbData = NULL; + } + + /// + /// Move an existing BLOB. + /// + inline data_blob(_Inout_ DATA_BLOB &&other) + { + cbData = other.cbData; + pbData = other.pbData; + other.cbData = 0; + other.pbData = NULL; + } + + /// + /// Destroys the BLOB. + /// + virtual ~data_blob(); + + /// + /// Copy an existing BLOB. + /// + inline data_blob& operator=(_In_ const DATA_BLOB &other) + { + if (this != &other) { + cbData = other.cbData; + if (pbData) + LocalFree(pbData); + if (cbData) { + pbData = (BYTE*)LocalAlloc(LMEM_FIXED, other.cbData); + assert(pbData); + memcpy(pbData, other.pbData, other.cbData); + } else + pbData = NULL; + } + + return *this; + } + + /// + /// Move an existing BLOB. + /// + inline data_blob& operator=(_Inout_ DATA_BLOB &&other) + { + if (this != &other) { + cbData = other.cbData; + if (pbData) + LocalFree(pbData); + pbData = other.pbData; + other.cbData = 0; + other.pbData = NULL; + } + + return *this; + } + + /// + /// Get BLOB size. + /// + inline DWORD size() const + { + return cbData; + } + + /// + /// Get BLOB buffer. + /// + inline const BYTE* data() const + { + return pbData; + } + + /// + /// Get BLOB buffer. + /// + inline BYTE* data() + { + return pbData; + } + }; + + /// @} +} + + +template +inline DWORD CertGetNameStringA(_In_ PCCERT_CONTEXT pCertContext, _In_ DWORD dwType, _In_ DWORD dwFlags, _In_ void *pvTypePara, _Out_ std::basic_string<_Elem, _Traits, _Ax> &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<_Elem[]> szBuffer(new _Elem[dwSize]); + dwSize = ::CertGetNameStringA(pCertContext, dwType, dwFlags, pvTypePara, szBuffer.get(), dwSize); + sNameString.assign(szBuffer.get(), dwSize - 1); + return dwSize; +} + + +template +inline DWORD CertGetNameStringW(_In_ PCCERT_CONTEXT pCertContext, _In_ DWORD dwType, _In_ DWORD dwFlags, _In_ void *pvTypePara, _Out_ std::basic_string<_Elem, _Traits, _Ax> &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<_Elem[]> szBuffer(new _Elem[dwSize]); + dwSize = ::CertGetNameStringW(pCertContext, dwType, dwFlags, pvTypePara, szBuffer.get(), dwSize); + sNameString.assign(szBuffer.get(), dwSize - 1); + return dwSize; +} + + +template +inline 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; + } + + aData.clear(); + return FALSE; +} + + +template +inline 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; + } + + aData.clear(); + return FALSE; +} + + +template +inline 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 +inline 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; + } + + aData.clear(); + return FALSE; +} + + +template +inline 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 +inline 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; + } + + aData.clear(); + return FALSE; +} + + +template +inline 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 +inline 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 6d552419..abc28145 100644 --- a/include/WinStd/EAP.h +++ b/include/WinStd/EAP.h @@ -1,669 +1,669 @@ -/* - Copyright 1991-2018 Amebis - Copyright 2016 GÉANT - - This file is part of WinStd. - - Setup is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Setup is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Setup. If not, see . -*/ - -/// -/// \defgroup WinStdEAPAPI Extensible Authentication Protocol API -/// Integrates WinStd classes with Microsoft EAP API -/// - -#include "Common.h" - -#include -#include -#include // Must include after - -#include - -namespace winstd -{ - enum eap_type_t; - struct WINSTD_API EapHostPeerFreeMemory_delete; - struct WINSTD_API EapHostPeerFreeRuntimeMemory_delete; - struct WINSTD_API EapHostPeerFreeErrorMemory_delete; - struct WINSTD_API EapHostPeerFreeEapError_delete; - class WINSTD_API WINSTD_NOVTABLE eap_attr; - class WINSTD_API WINSTD_NOVTABLE eap_method_prop; - class WINSTD_API eap_packet; - class WINSTD_API WINSTD_NOVTABLE eap_method_info_array; - class WINSTD_API eap_runtime_error; - - /// \addtogroup WinStdEAPAPI - /// @{ - - /// - /// EapHost BLOB wrapper class - /// - typedef std::unique_ptr WINSTD_API eap_blob; - - /// - /// EapHost BLOB wrapper class - /// - typedef std::unique_ptr WINSTD_API eap_blob_runtime; - - /// - /// EAP_ERROR wrapper class - /// - typedef std::unique_ptr WINSTD_API eap_error; - - /// - /// EAP_ERROR wrapper class - /// - typedef std::unique_ptr WINSTD_API eap_error_runtime; - - /// @} -} - - -/// \addtogroup WinStdEAPAPI -/// @{ - -/// -/// Are EAP method types equal? -/// -/// \param[in] a First EAP method type -/// \param[in] b Second EAP method type -/// -/// \returns -/// - Non zero when \p a is equal to \p b; -/// - Zero otherwise. -/// -inline bool operator==(_In_ const EAP_METHOD_TYPE &a, _In_ const EAP_METHOD_TYPE &b); - -/// -/// Are EAP method types non-equal? -/// -/// \param[in] a First EAP method type -/// \param[in] b Second EAP method type -/// -/// \returns -/// - Non zero when \p a is not equal to \p b; -/// - Zero otherwise. -/// -inline bool operator!=(_In_ const EAP_METHOD_TYPE &a, _In_ const EAP_METHOD_TYPE &b); - -/// @} - -#pragma once - -#include -#include -#include - - -namespace winstd -{ - /// \addtogroup WinStdEAPAPI - /// @{ - - /// - /// EAP method numbers - /// - /// \sa [Extensible Authentication Protocol (EAP) Registry (Chapter: Method Types)](https://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml#eap-numbers-4) - /// - #pragma warning(suppress: 4480) - enum eap_type_t : unsigned char { - eap_type_undefined = 0, ///< Undefined EAP type - eap_type_identity = 1, ///< Identity - eap_type_notification = 2, ///< Notification - eap_type_nak = 3, ///< Legacy Nak - eap_type_md5_challenge = 4, ///< MD5-Challenge - eap_type_otp = 5, ///< One-Time Password (OTP) - eap_type_gtc = 6, ///< Generic Token Card (GTC) - eap_type_tls = 13, ///< EAP-TLS - eap_type_ttls = 21, ///< EAP-TTLS - eap_type_peap = 25, ///< EAP-PEAP - eap_type_mschapv2 = 26, ///< EAP-MSCHAPv2 - - eap_type_gtcp = 128 + eap_type_gtc, ///< EAP-GTC using a password - - eap_type_legacy_pap = 192, ///< PAP (Not actually an EAP method; Moved to the Unassigned area) - eap_type_legacy_mschapv2 = 193, ///< MSCHAPv2 (Not actually an EAP method; Moved to the Unassigned area) - - eap_type_start = 1, ///< Start of EAP methods - eap_type_end = 192, ///< End of EAP methods (non-inclusive) - eap_type_noneap_start = 192, ///< Start of non-EAP methods - eap_type_noneap_end = 254, ///< End of non-EAP methods (non-inclusive) - }; - - - /// - /// Deleter for unique_ptr using EapHostPeerFreeMemory - /// - struct WINSTD_API EapHostPeerFreeMemory_delete - { - /// - /// Default constructor - /// - EapHostPeerFreeMemory_delete() {} - - /// - /// Delete a pointer - /// - /// \sa [EapHostPeerFreeMemory function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363558.aspx) - /// - template - void operator()(_T *_Ptr) const - { - EapHostPeerFreeMemory((BYTE*)_Ptr); - } - }; - - - /// - /// Deleter for unique_ptr using EapHostPeerFreeRuntimeMemory - /// - struct WINSTD_API EapHostPeerFreeRuntimeMemory_delete - { - /// - /// Default constructor - /// - EapHostPeerFreeRuntimeMemory_delete() {} - - /// - /// Delete a pointer - /// - template - void operator()(_T *_Ptr) const - { - EapHostPeerFreeRuntimeMemory((BYTE*)_Ptr); - } - }; - - - /// - /// Deleter for unique_ptr to EAP_ERROR using EapHostPeerFreeErrorMemory - /// - struct WINSTD_API EapHostPeerFreeErrorMemory_delete - { - /// - /// Default constructor - /// - EapHostPeerFreeErrorMemory_delete() {} - - /// - /// Delete a pointer - /// - /// \sa [EapHostPeerFreeErrorMemory function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363557.aspx) - /// - void operator()(EAP_ERROR *_Ptr) const - { - EapHostPeerFreeErrorMemory(_Ptr); - } - }; - - - /// - /// Deleter for unique_ptr to EAP_ERROR using EapHostPeerFreeEapError - /// - struct WINSTD_API EapHostPeerFreeEapError_delete - { - /// - /// Default constructor - /// - EapHostPeerFreeEapError_delete() {} - - /// - /// Delete a pointer - /// - /// \sa [EapHostPeerFreeEapError function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363556.aspx) - /// - void operator()(EAP_ERROR *_Ptr) const - { - EapHostPeerFreeEapError(_Ptr); - } - }; - - - /// - /// EAP_ATTRIBUTE wrapper class - /// - class WINSTD_API WINSTD_NOVTABLE eap_attr : public EAP_ATTRIBUTE - { - public: - /// - /// Initializes a new EAP attribute set to eatReserved. - /// - inline eap_attr() - { - eaType = eatReserved; - dwLength = 0; - pValue = NULL; - } - - /// - /// Copies an existing EAP attribute. - /// - inline eap_attr(_In_ const EAP_ATTRIBUTE &a) - { - eaType = a.eaType; - dwLength = a.dwLength; - if (a.dwLength) { - pValue = new BYTE[a.dwLength]; - assert(pValue); - memcpy(pValue, a.pValue, a.dwLength); - } else - pValue = NULL; - } - - /// - /// Moves an existing EAP attribute. - /// - inline eap_attr(_Inout_ eap_attr &&a) - { - eaType = a.eaType; - dwLength = a.dwLength; - if (a.dwLength) { - pValue = a.pValue; - a.dwLength = 0; - a.pValue = NULL; - } else - pValue = NULL; - } - - /// - /// Destroys the EAP attribute. - /// - ~eap_attr(); - - /// - /// Copies an existing EAP attribute. - /// - inline eap_attr& operator=(_In_ const EAP_ATTRIBUTE &a) - { - if (this != &a) { - eaType = a.eaType; - dwLength = a.dwLength; - if (a.dwLength) { - BYTE *pValueNew = new BYTE[a.dwLength]; - if (pValueNew) { - if (pValue) - delete [] pValue; - memcpy(pValueNew, a.pValue, a.dwLength); - pValue = pValueNew; - } else - assert(0); // Could not allocate memory - } else - pValue = NULL; - } - return *this; - } - - /// - /// Moves an existing EAP attribute. - /// - inline eap_attr& operator=(_Inout_ eap_attr &&a) - { - if (this != &a) { - eaType = a.eaType; - dwLength = a.dwLength; - if (pValue) - delete [] pValue; - if (a.dwLength) { - pValue = a.pValue; - a.dwLength = 0; - a.pValue = NULL; - } else - pValue = NULL; - } - return *this; - } - - /// - /// Creates MS-MPPE-Send-Key or MS-MPPE-Recv-Key - /// - /// \sa [RADIUS Vendor-Specific](https://tools.ietf.org/html/rfc2865#section-5.26) - /// \sa [MS-MPPE-Send-Key](https://tools.ietf.org/html/rfc2548#section-2.4.2) - /// \sa [MS-MPPE-Recv-Key](https://tools.ietf.org/html/rfc2548#section-2.4.3) - /// - void create_ms_mppe_key(_In_ BYTE bVendorType, _In_count_(nKeySize) LPCBYTE pbKey, _In_ BYTE nKeySize); - - public: - static const EAP_ATTRIBUTE blank; ///< Blank EAP attribute - }; - - - /// - /// EAP_METHOD_PROPERTY wrapper class - /// - class WINSTD_API WINSTD_NOVTABLE eap_method_prop : public EAP_METHOD_PROPERTY - { - public: - /// - /// Constructs a BOOL method property - /// - /// \param[in] type EAP method property type - /// \param[in] value Property value - /// - inline eap_method_prop(_In_ EAP_METHOD_PROPERTY_TYPE type, _In_ BOOL value) - { - eapMethodPropertyType = type; - eapMethodPropertyValueType = empvtBool; - eapMethodPropertyValue.empvBool.length = sizeof(BOOL); - eapMethodPropertyValue.empvBool.value = value; - } - - - /// - /// Constructs a DWORD method property - /// - /// \param[in] type EAP method property type - /// \param[in] value Property value - /// - inline eap_method_prop(_In_ EAP_METHOD_PROPERTY_TYPE type, _In_ DWORD value) - { - eapMethodPropertyType = type; - eapMethodPropertyValueType = empvtDword; - eapMethodPropertyValue.empvDword.length = sizeof(DWORD); - eapMethodPropertyValue.empvDword.value = value; - } - - - /// - /// Constructs a Unicode string method property - /// - /// \param[in] type EAP method property type - /// \param[in] value Property value - /// - inline eap_method_prop(_In_ EAP_METHOD_PROPERTY_TYPE type, _In_z_ LPCWSTR value) - { - eapMethodPropertyType = type; - eapMethodPropertyValueType = empvtString; - eapMethodPropertyValue.empvString.length = (DWORD)(sizeof(WCHAR)*(wcslen(value) + 1)); - eapMethodPropertyValue.empvString.value = (BYTE*)value; - } - }; - - - /// - /// EapPacket wrapper class - /// - class WINSTD_API eap_packet : public dplhandle - { - DPLHANDLE_IMPL(eap_packet) - - public: - /// - /// Destroys the EAP packet. - /// - virtual ~eap_packet(); - - - /// - /// Create new EAP packet - /// - /// \param[in] code EAP code (one of EapCode enum values) - /// \param[in] id Packet ID - /// \param[in] size Total packet size in bytes, including header. Must be at least 4B. - /// - /// \note Packet data (beyond first 4B) is not initialized. - /// - /// \return - /// - true when creation succeeds; - /// - false when creation fails. For extended error information, call `GetLastError()`. - /// - inline bool create(_In_ EapCode code, _In_ BYTE id, _In_ WORD size) - { - assert(size >= 4); // EAP packets must contain at least Code, Id, and Length fields: 4B. - - handle_type h = (handle_type)HeapAlloc(GetProcessHeap(), 0, size); - if (h) { - h->Code = (BYTE) code ; - h->Id = id ; - *(WORD*)h->Length = htons(size); - - attach(h); - return true; - } else { - SetLastError(ERROR_OUTOFMEMORY); - return false; - } - } - - - /// - /// Returns total EAP packet size in bytes. - /// - inline WORD size() const - { - return m_h ? ntohs(*(WORD*)m_h->Length) : 0; - } - - - protected: - /// - /// Destroys the EAP packet. - /// - virtual void free_internal(); - - /// - /// Duplicates the EAP packet. - /// - virtual handle_type duplicate_internal(_In_ handle_type h) const; - }; - - - /// - /// EAP_METHOD_INFO_ARRAY wrapper class - /// - class WINSTD_API WINSTD_NOVTABLE eap_method_info_array : public EAP_METHOD_INFO_ARRAY - { - WINSTD_NONCOPYABLE(eap_method_info_array) - - public: - /// - /// Constructs an empty array - /// - inline eap_method_info_array() - { - dwNumberOfMethods = 0; - pEapMethods = NULL; - } - - /// - /// Move constructor - /// - /// \param[inout] other A rvalue reference of another object - /// - inline eap_method_info_array(_Inout_ eap_method_info_array &&other) - { - dwNumberOfMethods = other.dwNumberOfMethods; - pEapMethods = other.pEapMethods; - other.dwNumberOfMethods = 0; - other.pEapMethods = NULL; - } - - /// - /// Destructor - /// - ~eap_method_info_array(); - - /// - /// Move assignment - /// - /// \param[inout] other A rvalue reference of another object - /// - inline eap_method_info_array& operator=(_Inout_ eap_method_info_array &&other) - { - if (this != std::addressof(other)) { - if (pEapMethods) - free_internal(); - dwNumberOfMethods = other.dwNumberOfMethods; - pEapMethods = other.pEapMethods; - other.dwNumberOfMethods = 0; - other.pEapMethods = NULL; - } - return *this; - } - - protected: - /// \cond internal - void free_internal(); - static void free_internal(_In_ EAP_METHOD_INFO *pMethodInfo); - /// \endcond - }; - - /// @} - - /// - /// \defgroup WinStdExceptions Exceptions - /// Additional exceptions - /// - /// @{ - - /// - /// EapHost runtime error - /// - /// \sa [EAP_ERROR structure](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363699.aspx) - /// - class WINSTD_API eap_runtime_error : public win_runtime_error - { - public: - /// - /// Constructs an exception - /// - /// \param[in] err EapHost error descriptor - /// \param[in] msg Error message - /// - inline eap_runtime_error(_In_ const EAP_ERROR &err, _In_ const std::string& msg) : - m_type (err.type ), - m_reason (err.dwReasonCode ), - m_root_cause_id (err.rootCauseGuid ), - m_root_cause_desc(err.pRootCauseString ), - m_repair_id (err.repairGuid ), - m_repair_desc (err.pRepairString ), - m_help_link_id (err.helpLinkGuid ), - win_runtime_error(err.dwWinError, msg.c_str()) - { - } - - - /// - /// Constructs an exception - /// - /// \param[in] err EapHost error descriptor - /// \param[in] msg Error message - /// - inline eap_runtime_error(_In_ const EAP_ERROR &err, _In_z_ const char *msg) : - m_type (err.type ), - m_reason (err.dwReasonCode ), - m_root_cause_id (err.rootCauseGuid ), - m_root_cause_desc(err.pRootCauseString), - m_repair_id (err.repairGuid ), - m_repair_desc (err.pRepairString ), - m_help_link_id (err.helpLinkGuid ), - win_runtime_error(err.dwWinError, msg ) - { - } - - - /// - /// Returns EAP method type - /// - inline const EAP_METHOD_TYPE& type() const - { - return m_type; - } - - - /// - /// Returns the reason code for error - /// - inline DWORD reason() const - { - return m_reason; - } - - - /// - /// Returns root cause ID - /// - inline const GUID& root_cause_id() const - { - return m_root_cause_id; - } - - - /// - /// Returns root cause ID - /// - inline const wchar_t* root_cause() const - { - return m_root_cause_desc.c_str(); - } - - - /// - /// Returns repair ID - /// - inline const GUID& repair_id() const - { - return m_repair_id; - } - - - /// - /// Returns root cause ID - /// - inline const wchar_t* repair() const - { - return m_repair_desc.c_str(); - } - - - /// - /// Returns help_link ID - /// - inline const GUID& help_link_id() const - { - return m_help_link_id; - } - - protected: - EAP_METHOD_TYPE m_type; ///< Structure that identifies the EAP method that raised the error - - DWORD m_reason; ///< The reason code for the error - - GUID m_root_cause_id; ///< A unique ID that identifies cause of error in EAPHost - std::wstring m_root_cause_desc; ///< A localized and readable string that describes the root cause of the error - - GUID m_repair_id; ///< A unique ID that maps to a localizable string that identifies the repair action that can be taken to fix the reported error - std::wstring m_repair_desc; ///< A localized and readable string that describes the possible repair action - - GUID m_help_link_id; ///< A unique ID that maps to a localizable string that specifies an URL for a page that contains additional information about an error or repair message - }; - - /// @} -} - - -inline bool operator==(_In_ const EAP_METHOD_TYPE &a, _In_ const EAP_METHOD_TYPE &b) -{ - return - a.eapType.type == b.eapType.type && - a.eapType.dwVendorId == b.eapType.dwVendorId && - a.eapType.dwVendorType == b.eapType.dwVendorType && - a.dwAuthorId == a.dwAuthorId; -} - - -inline bool operator!=(_In_ const EAP_METHOD_TYPE &a, _In_ const EAP_METHOD_TYPE &b) -{ - return !operator==(a, b); -} +/* + Copyright 1991-2018 Amebis + Copyright 2016 GÉANT + + This file is part of WinStd. + + Setup is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Setup is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Setup. If not, see . +*/ + +/// +/// \defgroup WinStdEAPAPI Extensible Authentication Protocol API +/// Integrates WinStd classes with Microsoft EAP API +/// + +#include "Common.h" + +#include +#include +#include // Must include after + +#include + +namespace winstd +{ + enum eap_type_t; + struct WINSTD_API EapHostPeerFreeMemory_delete; + struct WINSTD_API EapHostPeerFreeRuntimeMemory_delete; + struct WINSTD_API EapHostPeerFreeErrorMemory_delete; + struct WINSTD_API EapHostPeerFreeEapError_delete; + class WINSTD_API WINSTD_NOVTABLE eap_attr; + class WINSTD_API WINSTD_NOVTABLE eap_method_prop; + class WINSTD_API eap_packet; + class WINSTD_API WINSTD_NOVTABLE eap_method_info_array; + class WINSTD_API eap_runtime_error; + + /// \addtogroup WinStdEAPAPI + /// @{ + + /// + /// EapHost BLOB wrapper class + /// + typedef std::unique_ptr WINSTD_API eap_blob; + + /// + /// EapHost BLOB wrapper class + /// + typedef std::unique_ptr WINSTD_API eap_blob_runtime; + + /// + /// EAP_ERROR wrapper class + /// + typedef std::unique_ptr WINSTD_API eap_error; + + /// + /// EAP_ERROR wrapper class + /// + typedef std::unique_ptr WINSTD_API eap_error_runtime; + + /// @} +} + + +/// \addtogroup WinStdEAPAPI +/// @{ + +/// +/// Are EAP method types equal? +/// +/// \param[in] a First EAP method type +/// \param[in] b Second EAP method type +/// +/// \returns +/// - Non zero when \p a is equal to \p b; +/// - Zero otherwise. +/// +inline bool operator==(_In_ const EAP_METHOD_TYPE &a, _In_ const EAP_METHOD_TYPE &b); + +/// +/// Are EAP method types non-equal? +/// +/// \param[in] a First EAP method type +/// \param[in] b Second EAP method type +/// +/// \returns +/// - Non zero when \p a is not equal to \p b; +/// - Zero otherwise. +/// +inline bool operator!=(_In_ const EAP_METHOD_TYPE &a, _In_ const EAP_METHOD_TYPE &b); + +/// @} + +#pragma once + +#include +#include +#include + + +namespace winstd +{ + /// \addtogroup WinStdEAPAPI + /// @{ + + /// + /// EAP method numbers + /// + /// \sa [Extensible Authentication Protocol (EAP) Registry (Chapter: Method Types)](https://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml#eap-numbers-4) + /// + #pragma warning(suppress: 4480) + enum eap_type_t : unsigned char { + eap_type_undefined = 0, ///< Undefined EAP type + eap_type_identity = 1, ///< Identity + eap_type_notification = 2, ///< Notification + eap_type_nak = 3, ///< Legacy Nak + eap_type_md5_challenge = 4, ///< MD5-Challenge + eap_type_otp = 5, ///< One-Time Password (OTP) + eap_type_gtc = 6, ///< Generic Token Card (GTC) + eap_type_tls = 13, ///< EAP-TLS + eap_type_ttls = 21, ///< EAP-TTLS + eap_type_peap = 25, ///< EAP-PEAP + eap_type_mschapv2 = 26, ///< EAP-MSCHAPv2 + + eap_type_gtcp = 128 + eap_type_gtc, ///< EAP-GTC using a password + + eap_type_legacy_pap = 192, ///< PAP (Not actually an EAP method; Moved to the Unassigned area) + eap_type_legacy_mschapv2 = 193, ///< MSCHAPv2 (Not actually an EAP method; Moved to the Unassigned area) + + eap_type_start = 1, ///< Start of EAP methods + eap_type_end = 192, ///< End of EAP methods (non-inclusive) + eap_type_noneap_start = 192, ///< Start of non-EAP methods + eap_type_noneap_end = 254, ///< End of non-EAP methods (non-inclusive) + }; + + + /// + /// Deleter for unique_ptr using EapHostPeerFreeMemory + /// + struct WINSTD_API EapHostPeerFreeMemory_delete + { + /// + /// Default constructor + /// + EapHostPeerFreeMemory_delete() {} + + /// + /// Delete a pointer + /// + /// \sa [EapHostPeerFreeMemory function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363558.aspx) + /// + template + void operator()(_T *_Ptr) const + { + EapHostPeerFreeMemory((BYTE*)_Ptr); + } + }; + + + /// + /// Deleter for unique_ptr using EapHostPeerFreeRuntimeMemory + /// + struct WINSTD_API EapHostPeerFreeRuntimeMemory_delete + { + /// + /// Default constructor + /// + EapHostPeerFreeRuntimeMemory_delete() {} + + /// + /// Delete a pointer + /// + template + void operator()(_T *_Ptr) const + { + EapHostPeerFreeRuntimeMemory((BYTE*)_Ptr); + } + }; + + + /// + /// Deleter for unique_ptr to EAP_ERROR using EapHostPeerFreeErrorMemory + /// + struct WINSTD_API EapHostPeerFreeErrorMemory_delete + { + /// + /// Default constructor + /// + EapHostPeerFreeErrorMemory_delete() {} + + /// + /// Delete a pointer + /// + /// \sa [EapHostPeerFreeErrorMemory function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363557.aspx) + /// + void operator()(EAP_ERROR *_Ptr) const + { + EapHostPeerFreeErrorMemory(_Ptr); + } + }; + + + /// + /// Deleter for unique_ptr to EAP_ERROR using EapHostPeerFreeEapError + /// + struct WINSTD_API EapHostPeerFreeEapError_delete + { + /// + /// Default constructor + /// + EapHostPeerFreeEapError_delete() {} + + /// + /// Delete a pointer + /// + /// \sa [EapHostPeerFreeEapError function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363556.aspx) + /// + void operator()(EAP_ERROR *_Ptr) const + { + EapHostPeerFreeEapError(_Ptr); + } + }; + + + /// + /// EAP_ATTRIBUTE wrapper class + /// + class WINSTD_API WINSTD_NOVTABLE eap_attr : public EAP_ATTRIBUTE + { + public: + /// + /// Initializes a new EAP attribute set to eatReserved. + /// + inline eap_attr() + { + eaType = eatReserved; + dwLength = 0; + pValue = NULL; + } + + /// + /// Copies an existing EAP attribute. + /// + inline eap_attr(_In_ const EAP_ATTRIBUTE &a) + { + eaType = a.eaType; + dwLength = a.dwLength; + if (a.dwLength) { + pValue = new BYTE[a.dwLength]; + assert(pValue); + memcpy(pValue, a.pValue, a.dwLength); + } else + pValue = NULL; + } + + /// + /// Moves an existing EAP attribute. + /// + inline eap_attr(_Inout_ eap_attr &&a) noexcept + { + eaType = a.eaType; + dwLength = a.dwLength; + if (a.dwLength) { + pValue = a.pValue; + a.dwLength = 0; + a.pValue = NULL; + } else + pValue = NULL; + } + + /// + /// Destroys the EAP attribute. + /// + ~eap_attr(); + + /// + /// Copies an existing EAP attribute. + /// + inline eap_attr& operator=(_In_ const EAP_ATTRIBUTE &a) + { + if (this != &a) { + eaType = a.eaType; + dwLength = a.dwLength; + if (a.dwLength) { + BYTE *pValueNew = new BYTE[a.dwLength]; + if (pValueNew) { + if (pValue) + delete [] pValue; + memcpy(pValueNew, a.pValue, a.dwLength); + pValue = pValueNew; + } else + assert(0); // Could not allocate memory + } else + pValue = NULL; + } + return *this; + } + + /// + /// Moves an existing EAP attribute. + /// + inline eap_attr& operator=(_Inout_ eap_attr &&a) noexcept + { + if (this != &a) { + eaType = a.eaType; + dwLength = a.dwLength; + if (pValue) + delete [] pValue; + if (a.dwLength) { + pValue = a.pValue; + a.dwLength = 0; + a.pValue = NULL; + } else + pValue = NULL; + } + return *this; + } + + /// + /// Creates MS-MPPE-Send-Key or MS-MPPE-Recv-Key + /// + /// \sa [RADIUS Vendor-Specific](https://tools.ietf.org/html/rfc2865#section-5.26) + /// \sa [MS-MPPE-Send-Key](https://tools.ietf.org/html/rfc2548#section-2.4.2) + /// \sa [MS-MPPE-Recv-Key](https://tools.ietf.org/html/rfc2548#section-2.4.3) + /// + void create_ms_mppe_key(_In_ BYTE bVendorType, _In_count_(nKeySize) LPCBYTE pbKey, _In_ BYTE nKeySize); + + public: + static const EAP_ATTRIBUTE blank; ///< Blank EAP attribute + }; + + + /// + /// EAP_METHOD_PROPERTY wrapper class + /// + class WINSTD_API WINSTD_NOVTABLE eap_method_prop : public EAP_METHOD_PROPERTY + { + public: + /// + /// Constructs a BOOL method property + /// + /// \param[in] type EAP method property type + /// \param[in] value Property value + /// + inline eap_method_prop(_In_ EAP_METHOD_PROPERTY_TYPE type, _In_ BOOL value) + { + eapMethodPropertyType = type; + eapMethodPropertyValueType = empvtBool; + eapMethodPropertyValue.empvBool.length = sizeof(BOOL); + eapMethodPropertyValue.empvBool.value = value; + } + + + /// + /// Constructs a DWORD method property + /// + /// \param[in] type EAP method property type + /// \param[in] value Property value + /// + inline eap_method_prop(_In_ EAP_METHOD_PROPERTY_TYPE type, _In_ DWORD value) + { + eapMethodPropertyType = type; + eapMethodPropertyValueType = empvtDword; + eapMethodPropertyValue.empvDword.length = sizeof(DWORD); + eapMethodPropertyValue.empvDword.value = value; + } + + + /// + /// Constructs a Unicode string method property + /// + /// \param[in] type EAP method property type + /// \param[in] value Property value + /// + inline eap_method_prop(_In_ EAP_METHOD_PROPERTY_TYPE type, _In_z_ LPCWSTR value) + { + eapMethodPropertyType = type; + eapMethodPropertyValueType = empvtString; + eapMethodPropertyValue.empvString.length = (DWORD)(sizeof(WCHAR)*(wcslen(value) + 1)); + eapMethodPropertyValue.empvString.value = (BYTE*)value; + } + }; + + + /// + /// EapPacket wrapper class + /// + class WINSTD_API eap_packet : public dplhandle + { + DPLHANDLE_IMPL(eap_packet) + + public: + /// + /// Destroys the EAP packet. + /// + virtual ~eap_packet(); + + + /// + /// Create new EAP packet + /// + /// \param[in] code EAP code (one of EapCode enum values) + /// \param[in] id Packet ID + /// \param[in] size Total packet size in bytes, including header. Must be at least 4B. + /// + /// \note Packet data (beyond first 4B) is not initialized. + /// + /// \return + /// - true when creation succeeds; + /// - false when creation fails. For extended error information, call `GetLastError()`. + /// + inline bool create(_In_ EapCode code, _In_ BYTE id, _In_ WORD size) + { + assert(size >= 4); // EAP packets must contain at least Code, Id, and Length fields: 4B. + + handle_type h = (handle_type)HeapAlloc(GetProcessHeap(), 0, size); + if (h) { + h->Code = (BYTE) code ; + h->Id = id ; + *(WORD*)h->Length = htons(size); + + attach(h); + return true; + } else { + SetLastError(ERROR_OUTOFMEMORY); + return false; + } + } + + + /// + /// Returns total EAP packet size in bytes. + /// + inline WORD size() const + { + return m_h ? ntohs(*(WORD*)m_h->Length) : 0; + } + + + protected: + /// + /// Destroys the EAP packet. + /// + virtual void free_internal(); + + /// + /// Duplicates the EAP packet. + /// + virtual handle_type duplicate_internal(_In_ handle_type h) const; + }; + + + /// + /// EAP_METHOD_INFO_ARRAY wrapper class + /// + class WINSTD_API WINSTD_NOVTABLE eap_method_info_array : public EAP_METHOD_INFO_ARRAY + { + WINSTD_NONCOPYABLE(eap_method_info_array) + + public: + /// + /// Constructs an empty array + /// + inline eap_method_info_array() + { + dwNumberOfMethods = 0; + pEapMethods = NULL; + } + + /// + /// Move constructor + /// + /// \param[inout] other A rvalue reference of another object + /// + inline eap_method_info_array(_Inout_ eap_method_info_array &&other) noexcept + { + dwNumberOfMethods = other.dwNumberOfMethods; + pEapMethods = other.pEapMethods; + other.dwNumberOfMethods = 0; + other.pEapMethods = NULL; + } + + /// + /// Destructor + /// + ~eap_method_info_array(); + + /// + /// Move assignment + /// + /// \param[inout] other A rvalue reference of another object + /// + inline eap_method_info_array& operator=(_Inout_ eap_method_info_array &&other) noexcept + { + if (this != std::addressof(other)) { + if (pEapMethods) + free_internal(); + dwNumberOfMethods = other.dwNumberOfMethods; + pEapMethods = other.pEapMethods; + other.dwNumberOfMethods = 0; + other.pEapMethods = NULL; + } + return *this; + } + + protected: + /// \cond internal + void free_internal(); + static void free_internal(_In_ EAP_METHOD_INFO *pMethodInfo); + /// \endcond + }; + + /// @} + + /// + /// \defgroup WinStdExceptions Exceptions + /// Additional exceptions + /// + /// @{ + + /// + /// EapHost runtime error + /// + /// \sa [EAP_ERROR structure](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363699.aspx) + /// + class WINSTD_API eap_runtime_error : public win_runtime_error + { + public: + /// + /// Constructs an exception + /// + /// \param[in] err EapHost error descriptor + /// \param[in] msg Error message + /// + inline eap_runtime_error(_In_ const EAP_ERROR &err, _In_ const std::string& msg) : + m_type (err.type ), + m_reason (err.dwReasonCode ), + m_root_cause_id (err.rootCauseGuid ), + m_root_cause_desc(err.pRootCauseString ), + m_repair_id (err.repairGuid ), + m_repair_desc (err.pRepairString ), + m_help_link_id (err.helpLinkGuid ), + win_runtime_error(err.dwWinError, msg.c_str()) + { + } + + + /// + /// Constructs an exception + /// + /// \param[in] err EapHost error descriptor + /// \param[in] msg Error message + /// + inline eap_runtime_error(_In_ const EAP_ERROR &err, _In_z_ const char *msg) : + m_type (err.type ), + m_reason (err.dwReasonCode ), + m_root_cause_id (err.rootCauseGuid ), + m_root_cause_desc(err.pRootCauseString), + m_repair_id (err.repairGuid ), + m_repair_desc (err.pRepairString ), + m_help_link_id (err.helpLinkGuid ), + win_runtime_error(err.dwWinError, msg ) + { + } + + + /// + /// Returns EAP method type + /// + inline const EAP_METHOD_TYPE& type() const + { + return m_type; + } + + + /// + /// Returns the reason code for error + /// + inline DWORD reason() const + { + return m_reason; + } + + + /// + /// Returns root cause ID + /// + inline const GUID& root_cause_id() const + { + return m_root_cause_id; + } + + + /// + /// Returns root cause ID + /// + inline const wchar_t* root_cause() const + { + return m_root_cause_desc.c_str(); + } + + + /// + /// Returns repair ID + /// + inline const GUID& repair_id() const + { + return m_repair_id; + } + + + /// + /// Returns root cause ID + /// + inline const wchar_t* repair() const + { + return m_repair_desc.c_str(); + } + + + /// + /// Returns help_link ID + /// + inline const GUID& help_link_id() const + { + return m_help_link_id; + } + + protected: + EAP_METHOD_TYPE m_type; ///< Structure that identifies the EAP method that raised the error + + DWORD m_reason; ///< The reason code for the error + + GUID m_root_cause_id; ///< A unique ID that identifies cause of error in EAPHost + std::wstring m_root_cause_desc; ///< A localized and readable string that describes the root cause of the error + + GUID m_repair_id; ///< A unique ID that maps to a localizable string that identifies the repair action that can be taken to fix the reported error + std::wstring m_repair_desc; ///< A localized and readable string that describes the possible repair action + + GUID m_help_link_id; ///< A unique ID that maps to a localizable string that specifies an URL for a page that contains additional information about an error or repair message + }; + + /// @} +} + + +inline bool operator==(_In_ const EAP_METHOD_TYPE &a, _In_ const EAP_METHOD_TYPE &b) +{ + return + a.eapType.type == b.eapType.type && + a.eapType.dwVendorId == b.eapType.dwVendorId && + a.eapType.dwVendorType == b.eapType.dwVendorType && + a.dwAuthorId == a.dwAuthorId; +} + + +inline bool operator!=(_In_ const EAP_METHOD_TYPE &a, _In_ const EAP_METHOD_TYPE &b) +{ + return !operator==(a, b); +} diff --git a/include/WinStd/ETW.h b/include/WinStd/ETW.h index 05681a3d..9102093b 100644 --- a/include/WinStd/ETW.h +++ b/include/WinStd/ETW.h @@ -1,1190 +1,1198 @@ -/* - Copyright 1991-2018 Amebis - Copyright 2016 GÉANT - - This file is part of WinStd. - - Setup is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Setup is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Setup. If not, see . -*/ - -/// -/// \defgroup WinStdETWAPI Event Tracing for Windows API -/// Integrates WinStd classes with Event Tracing for Windows API -/// - -#include "Common.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace winstd -{ - class WINSTD_API WINSTD_NOVTABLE event_data; - class WINSTD_API WINSTD_NOVTABLE event_rec; - class WINSTD_API event_provider; - class WINSTD_API event_session; - class WINSTD_API event_trace; - class WINSTD_API event_trace_enabler; - class WINSTD_API event_fn_auto; - template class event_fn_auto_ret; -} - -/// \addtogroup WinStdCryptoAPI -/// @{ - -/// -/// Retrieves metadata about an event. -/// -/// \sa [TdhGetEventInformation function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa964840.aspx) -/// -inline ULONG TdhGetEventInformation(_In_ PEVENT_RECORD pEvent, _In_ ULONG TdhContextCount, _In_ 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) -/// -inline ULONG TdhGetEventMapInformation(_In_ PEVENT_RECORD pEvent, _In_ LPWSTR pMapName, _Out_ 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 inline ULONG TdhGetProperty(_In_ PEVENT_RECORD pEvent, _In_ ULONG TdhContextCount, _In_ PTDH_CONTEXT pTdhContext, _In_ ULONG PropertyDataCount, _In_ PPROPERTY_DATA_DESCRIPTOR pPropertyData, _Out_ std::vector<_Ty, _Ax> &aData); - -/// @} - -#pragma once - - -namespace winstd -{ - /// \addtogroup WinStdETWAPI - /// @{ - - /// - /// EVENT_DATA_DESCRIPTOR wrapper - /// - class WINSTD_API WINSTD_NOVTABLE event_data : public EVENT_DATA_DESCRIPTOR - { - public: - /// - /// Construct empty class. - /// - inline event_data() - { - Ptr = 0; - Size = 0; - Reserved = (ULONG)-1; // Used for varadic argument terminator. - } - - - /// - /// Construct class pointing to an `int`. - /// - /// \param[in] data Event data - /// - /// \note This class saves a reference to the data only. Therefore, data must be kept available. - /// - inline event_data(_In_ const int &data) - { - EventDataDescCreate(this, &data, (ULONG)(sizeof(data))); - } - - - /// - /// Construct class pointing to an `unsigned int`. - /// - /// \param[in] data Event data - /// - /// \note This class saves a reference to the data only. Therefore, data must be kept available. - /// - inline event_data(_In_ const unsigned int &data) - { - EventDataDescCreate(this, &data, (ULONG)(sizeof(data))); - } - - - /// - /// Construct class pointing to a `long`. - /// - /// \param[in] data Event data - /// - /// \note This class saves a reference to the data only. Therefore, data must be kept available. - /// - inline event_data(_In_ const long &data) - { - EventDataDescCreate(this, &data, (ULONG)(sizeof(data))); - } - - - /// - /// Construct class pointing to an `unsigned long`. - /// - /// \param[in] data Event data - /// - /// \note This class saves a reference to the data only. Therefore, data must be kept available. - /// - inline event_data(_In_ const unsigned long &data) - { - EventDataDescCreate(this, &data, (ULONG)(sizeof(data))); - } - - - /// - /// Construct class pointing to a `GUID`. - /// - /// \param[in] data Event data - /// - /// \note This class saves a reference to the data only. Therefore, data must be kept available. - /// - inline event_data(_In_ const GUID &data) - { - EventDataDescCreate(this, &data, (ULONG)(sizeof(data))); - } - - - /// - /// Construct class pointing to a string. - /// - /// \param[in] data Event data. When `NULL`, the event data will be `"(null)"`. - /// - /// \note This class saves a reference to the data only. Therefore, data must be kept available. - /// - inline event_data(_In_ const char *data) - { - if (data) - EventDataDescCreate(this, data, (ULONG)((strlen(data) + 1) * sizeof(*data))); - else { - // Writing NULL pointer with 0B length causes trouble in Event Viewer: message template string is displayed only, parameters are not rendered. - static const char null[] = "(null)"; - EventDataDescCreate(this, null, sizeof(null)); - } - } - - - /// - /// Construct class pointing to a wide string. - /// - /// \param[in] data Event data. When `NULL`, the event data will be `"(null)"`. - /// - /// \note This class saves a reference to the data only. Therefore, data must be kept available. - /// - inline event_data(_In_ const wchar_t *data) - { - if (data) - EventDataDescCreate(this, data, (ULONG)((wcslen(data) + 1) * sizeof(*data))); - else { - // Writing NULL pointer with 0B length causes trouble in Event Viewer: message template string is displayed only, parameters are not rendered. - static const wchar_t null[] = L"(null)"; - EventDataDescCreate(this, null, sizeof(null)); - } - } - - - /// - /// Template to construct pointing to a `std::basic_string<>`. - /// - /// \param[in] data Event data - /// - /// \note This class saves a reference to the data only. Therefore, data must be kept available. - /// - template - inline event_data(_In_ const std::basic_string<_Elem, _Traits, _Ax> &data) - { - EventDataDescCreate(this, data.c_str(), (ULONG)((data.length() + 1) * sizeof(_Elem))); - } - - - /// - /// Construct class pointing to binary data. - /// - /// \param[in] data Pointer to event data - /// \param[in] size Size of \p data in bytes - /// - /// \note This class saves a reference to the data only. Therefore, data must be kept available. - /// - inline event_data(_In_bytecount_(size) const void *data, _In_ ULONG size) - { - EventDataDescCreate(this, data, size); - } - - - /// - /// Blank event data used as terminator. - /// - static const event_data blank; - }; - - - /// - /// EVENT_RECORD wrapper - /// - class WINSTD_API WINSTD_NOVTABLE event_rec : public EVENT_RECORD - { - public: - /// - /// Constructs a blank event record. - /// - inline event_rec() - { - memset((EVENT_RECORD*)this, 0, sizeof(EVENT_RECORD)); - } - - - /// - /// Copies an existing event record. - /// - /// \param[in] other Event record to copy from - /// - inline event_rec(_In_ const event_rec &other) : EVENT_RECORD(other) - { - set_extended_data_internal(other.ExtendedDataCount, other.ExtendedData); - set_user_data_internal(other.UserDataLength, other.UserData); - } - - - /// - /// Copies an existing event record. - /// - /// \param[in] other Event record to copy from - /// - inline event_rec(_In_ const EVENT_RECORD &other) : EVENT_RECORD(other) - { - set_extended_data_internal(other.ExtendedDataCount, other.ExtendedData); - set_user_data_internal(other.UserDataLength, other.UserData); - } - - - /// - /// Moves the event record. - /// - /// \param[in] other Event record to move - /// - inline event_rec(_Inout_ event_rec&& other) : EVENT_RECORD(other) - { - memset((EVENT_RECORD*)&other, 0, sizeof(EVENT_RECORD)); - } - - - /// - /// Destroys event record data and frees the allocated memory. - /// - ~event_rec(); - - - /// - /// Copies an existing event record. - /// - /// \param[in] other Event record to copy from - /// - inline event_rec& operator=(_In_ const event_rec &other) - { - if (this != std::addressof(other)) { - (EVENT_RECORD&)*this = other; - set_extended_data_internal(other.ExtendedDataCount, other.ExtendedData); - set_user_data_internal(other.UserDataLength, other.UserData); - } - - return *this; - } - - - /// - /// Copies an existing event record. - /// - /// \param[in] other Event record to copy from - /// - inline event_rec& operator=(_In_ const EVENT_RECORD &other) - { - if (this != std::addressof(other)) { - (EVENT_RECORD&)*this = other; - set_extended_data_internal(other.ExtendedDataCount, other.ExtendedData); - set_user_data_internal(other.UserDataLength, other.UserData); - } - - return *this; - } - - - /// - /// Moves the event record. - /// - /// \param[in] other Event record to move - /// - inline event_rec& operator=(_Inout_ event_rec&& other) - { - if (this != std::addressof(other)) { - (EVENT_RECORD&)*this = other; - memset((EVENT_RECORD*)&other, 0, sizeof(EVENT_RECORD)); - } - - return *this; - } - - - /// - /// Sets event record extended data. - /// - /// \param[in] count \p data size (in number of elements) - /// \param[in] data Record extended data - /// - void set_extended_data(_In_ USHORT count, _In_count_(count) const EVENT_HEADER_EXTENDED_DATA_ITEM *data); - - - /// - /// Sets event record user data. - /// - /// \param[in] size \p data size (in bytes) - /// \param[in] data Record user data - /// - void set_user_data(_In_ USHORT size, _In_bytecount_(size) LPCVOID data); - - protected: - /// - /// Sets event record extended data. - /// - /// \param[in] count \p data size (in number of elements) - /// \param[in] data Record extended data - /// - void set_extended_data_internal(_In_ USHORT count, _In_count_(count) const EVENT_HEADER_EXTENDED_DATA_ITEM *data); - - /// - /// Sets event record user data. - /// - /// \param[in] size \p data size (in bytes) - /// \param[in] data Record user data - /// - void set_user_data_internal(_In_ USHORT size, _In_bytecount_(size) LPCVOID data); - }; - - - /// - /// ETW event provider - /// - class WINSTD_API event_provider : public handle - { - HANDLE_IMPL(event_provider) - - public: - /// - /// Closes the event provider. - /// - /// \sa [EventUnregister function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363749.aspx) - /// - virtual ~event_provider(); - - - /// - /// Registers the event provider. - /// - /// \return - /// - `ERROR_SUCCESS` when creation succeeds; - /// - error code otherwise. - /// - /// \sa [EventRegister function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363744.aspx) - /// - inline ULONG create(_In_ LPCGUID ProviderId) - { - handle_type h; - ULONG ulRes = EventRegister(ProviderId, enable_callback, this, &h); - if (ulRes == ERROR_SUCCESS) - attach(h); - return ulRes; - } - - - /// - /// Writes an event with no parameters. - /// - /// \return - /// - `ERROR_SUCCESS` when write succeeds; - /// - error code otherwise. - /// - /// \sa [EventWrite function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363752.aspx) - /// - inline ULONG write(_In_ PCEVENT_DESCRIPTOR EventDescriptor) - { - assert(m_h); - return EventWrite(m_h, EventDescriptor, 0, NULL); - } - - - /// - /// Writes an event with parameters stored in array. - /// - /// \return - /// - `ERROR_SUCCESS` when write succeeds; - /// - error code otherwise. - /// - /// \sa [EventWrite function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363752.aspx) - /// - inline ULONG write(_In_ PCEVENT_DESCRIPTOR EventDescriptor, _In_ ULONG UserDataCount = 0, _In_opt_count_(UserDataCount) PEVENT_DATA_DESCRIPTOR UserData = NULL) - { - assert(m_h); - return EventWrite(m_h, EventDescriptor, UserDataCount, UserData); - } - - - /// - /// Writes an event with one or more parameter. - /// - /// \note The list must be terminated with `winstd::event_data::blank`. - /// - /// \return - /// - `ERROR_SUCCESS` when write succeeds; - /// - error code otherwise. - /// - /// \sa [EventWrite function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363752.aspx) - /// - inline ULONG write(_In_ PCEVENT_DESCRIPTOR EventDescriptor, _In_ const EVENT_DATA_DESCRIPTOR param1, ...) - { - assert(m_h); - - // The first argument (param1) is outside of varadic argument list. - if (param1.Ptr == winstd::event_data::blank.Ptr && - param1.Size == winstd::event_data::blank.Size && - param1.Reserved == winstd::event_data::blank.Reserved) - return EventWrite(m_h, EventDescriptor, 0, NULL); - - va_list arg; - va_start(arg, param1); - va_list arg_start = arg; - std::vector params; - ULONG param_count; - - // Preallocate array. - for (param_count = 1;; param_count++) { - const EVENT_DATA_DESCRIPTOR &p = va_arg(arg, const EVENT_DATA_DESCRIPTOR); - if (p.Ptr == winstd::event_data::blank.Ptr && - p.Size == winstd::event_data::blank.Size && - p.Reserved == winstd::event_data::blank.Reserved) break; - } - params.reserve(param_count); - - // Copy parameters to array. - arg = arg_start; - params.push_back(param1); - for (;;) { - const EVENT_DATA_DESCRIPTOR &p = va_arg(arg, const EVENT_DATA_DESCRIPTOR); - if (p.Ptr == winstd::event_data::blank.Ptr && - p.Size == winstd::event_data::blank.Size && - p.Reserved == winstd::event_data::blank.Reserved) break; - params.push_back(p); - } - - va_end(arg); - return EventWrite(m_h, EventDescriptor, param_count, params.data()); - } - - - /// - /// Writes an event with variable number of parameters. - /// - /// \note The list must be terminated with `winstd::event_data::blank`. - /// - /// \return - /// - `ERROR_SUCCESS` when write succeeds; - /// - error code otherwise. - /// - /// \sa [EventWrite function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363752.aspx) - /// - inline ULONG write(_In_ PCEVENT_DESCRIPTOR EventDescriptor, _In_ va_list arg) - { - assert(m_h); - - va_list arg_start = arg; - std::vector params; - ULONG param_count; - - // Preallocate array. - for (param_count = 0;; param_count++) { - const EVENT_DATA_DESCRIPTOR &p = va_arg(arg, const EVENT_DATA_DESCRIPTOR); - if (p.Ptr == winstd::event_data::blank.Ptr && - p.Size == winstd::event_data::blank.Size && - p.Reserved == winstd::event_data::blank.Reserved) break; - } - params.reserve(param_count); - - // Copy parameters to array. - arg = arg_start; - for (;;) { - const EVENT_DATA_DESCRIPTOR &p = va_arg(arg, const EVENT_DATA_DESCRIPTOR); - if (p.Ptr == winstd::event_data::blank.Ptr && - p.Size == winstd::event_data::blank.Size && - p.Reserved == winstd::event_data::blank.Reserved) break; - params.push_back(p); - } - - return EventWrite(m_h, EventDescriptor, param_count, params.data()); - } - - - /// - /// Writes a string event. - /// - /// \return - /// - `ERROR_SUCCESS` when write succeeds; - /// - error code otherwise. - /// - /// \sa [EventWriteString function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363750v=vs.85.aspx) - /// - inline ULONG write(_In_ UCHAR Level, _In_ ULONGLONG Keyword, _In_ _Printf_format_string_ PCWSTR String, ...) - { - assert(m_h); - - std::wstring msg; - va_list arg; - - // Format message. - va_start(arg, String); - vsprintf(msg, String, arg); - va_end(arg); - - // Write string event. - return EventWriteString(m_h, Level, Keyword, msg.c_str()); - } - - protected: - /// - /// Releases the event provider. - /// - /// \sa [EventUnregister function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363749.aspx) - /// - virtual void free_internal(); - - - /// - /// Receive enable or disable notification requests - /// - /// \sa [EnableCallback callback function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363707.aspx) - /// - virtual void enable_callback(_In_ LPCGUID SourceId, _In_ ULONG IsEnabled, _In_ UCHAR Level, _In_ ULONGLONG MatchAnyKeyword, _In_ ULONGLONG MatchAllKeyword, _In_opt_ PEVENT_FILTER_DESCRIPTOR FilterData); - - - /// - /// Receive enable or disable notification requests - /// - /// \sa [EnableCallback callback function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363707.aspx) - /// - static VOID NTAPI enable_callback(_In_ LPCGUID SourceId, _In_ ULONG IsEnabled, _In_ UCHAR Level, _In_ ULONGLONG MatchAnyKeyword, _In_ ULONGLONG MatchAllKeyword, _In_opt_ PEVENT_FILTER_DESCRIPTOR FilterData, _Inout_opt_ PVOID CallbackContext); - }; - - - /// - /// ETW session - /// - class WINSTD_API event_session : public handle - { - WINSTD_NONCOPYABLE(event_session) - - public: - /// - /// Initializes a new empty session. - /// - inline event_session() - { - } - - - /// - /// Initializes a new session with an already available object handle. - /// - /// \param[in] h Initial session handle value - /// \param[in] prop Session properties - /// - inline event_session(_In_opt_ handle_type h, _In_ const EVENT_TRACE_PROPERTIES *prop) : - m_prop(reinterpret_cast(new char[prop->Wnode.BufferSize])), - handle(h) - { - memcpy(m_prop.get(), prop, prop->Wnode.BufferSize); - } - - - /// - /// Move constructor - /// - /// \param[inout] other A rvalue reference of another session - /// - inline event_session(_Inout_ event_session &&other) : - m_prop(std::move(other.m_prop)), - handle(std::move(other)) - { - } - - - /// - /// Closes the session. - /// - /// \sa [ControlTrace function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363696.aspx) - /// - virtual ~event_session(); - - - /// - /// Move assignment - /// - /// \param[inout] other A rvalue reference of another object - /// - inline event_session& operator=(_Inout_ event_session &&other) - { - if (this != std::addressof(other)) { - (handle&&)*this = std::move(other); - m_prop = std::move(other.m_prop); - } - return *this; - } - - - /// - /// Auto-typecasting operator - /// - /// \return Session properties - /// - inline operator const EVENT_TRACE_PROPERTIES*() const - { - return m_prop.get(); - } - - - /// - /// Auto-typecasting operator - /// - /// \return Session properties - /// - inline LPCTSTR name() const - { - const EVENT_TRACE_PROPERTIES *prop = m_prop.get(); - return reinterpret_cast(reinterpret_cast(prop) + prop->LoggerNameOffset); - } - - - /// - /// Sets a new session handle for the class - /// - /// When the current session handle of the class is non-NULL, the session is destroyed first. - /// - /// \param[in] h New session handle - /// \param[in] prop Session properties - /// - inline void attach(_In_opt_ handle_type h, _In_ EVENT_TRACE_PROPERTIES *prop) - { - handle::attach(h); - m_prop.reset(prop); - } - - - /// - /// Registers and starts an event tracing session. - /// - /// \return - /// - `ERROR_SUCCESS` when creation succeeds; - /// - error code otherwise. - /// - /// \sa [StartTrace function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa364117.aspx) - /// - inline ULONG create(_In_ LPCTSTR SessionName, _In_ const EVENT_TRACE_PROPERTIES *Properties) - { - handle_type h; - std::unique_ptr prop(reinterpret_cast(new char[Properties->Wnode.BufferSize])); - memcpy(prop.get(), Properties, Properties->Wnode.BufferSize); - ULONG ulRes = StartTrace(&h, SessionName, prop.get()); - if (ulRes == ERROR_SUCCESS) - attach(h, prop.release()); - return ulRes; - } - - - /// - /// Enables the specified event trace provider. - /// - /// \return - /// - `ERROR_SUCCESS` when succeeds; - /// - error code otherwise. - /// - /// \sa [EnableTraceEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363711.aspx) - /// - inline ULONG enable_trace(_In_ LPCGUID ProviderId, _In_ UCHAR Level, _In_opt_ ULONGLONG MatchAnyKeyword = 0, _In_opt_ ULONGLONG MatchAllKeyword = 0, _In_opt_ ULONG EnableProperty = 0, _In_opt_ PEVENT_FILTER_DESCRIPTOR EnableFilterDesc = NULL) - { - assert(m_h); - return EnableTraceEx( - ProviderId, - &m_prop->Wnode.Guid, - m_h, - EVENT_CONTROL_CODE_ENABLE_PROVIDER, - Level, - MatchAnyKeyword, - MatchAllKeyword, - EnableProperty, - EnableFilterDesc); - } - - - /// - /// Disables the specified event trace provider. - /// - /// \return - /// - `ERROR_SUCCESS` when succeeds; - /// - error code otherwise. - /// - /// \sa [EnableTraceEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363711.aspx) - /// - inline ULONG disable_trace(_In_ LPCGUID ProviderId, _In_ UCHAR Level, _In_opt_ ULONGLONG MatchAnyKeyword = 0, _In_opt_ ULONGLONG MatchAllKeyword = 0, _In_opt_ ULONG EnableProperty = 0, _In_opt_ PEVENT_FILTER_DESCRIPTOR EnableFilterDesc = NULL) - { - assert(m_h); - return EnableTraceEx( - ProviderId, - &m_prop->Wnode.Guid, - m_h, - EVENT_CONTROL_CODE_DISABLE_PROVIDER, - Level, - MatchAnyKeyword, - MatchAllKeyword, - EnableProperty, - EnableFilterDesc); - } - - - protected: - /// - /// Releases the session. - /// - /// \sa [ControlTrace function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363696.aspx) - /// - virtual void free_internal(); - - protected: - std::unique_ptr m_prop; ///< Session properties - }; - - - /// - /// ETW trace - /// - class WINSTD_API event_trace : public handle - { - HANDLE_IMPL(event_trace) - - public: - /// - /// Closes the trace. - /// - /// \sa [CloseTrace function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363686.aspx) - /// - virtual ~event_trace(); - - - /// - /// Opens a real-time trace session or log file for consuming. - /// - /// \return - /// - `ERROR_SUCCESS` when creation succeeds; - /// - error code otherwise. - /// - /// \sa [OpenTrace function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa364089.aspx) - /// - inline bool create(_Inout_ PEVENT_TRACE_LOGFILE Logfile) - { - handle_type h = OpenTrace(Logfile); - if (h != (TRACEHANDLE)INVALID_HANDLE_VALUE) { - attach(h); - return true; - } else - return false; - } - - protected: - /// - /// Closes the trace. - /// - /// \sa [CloseTrace function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363686.aspx) - /// - virtual void free_internal(); - }; - - - /// - /// Helper class to enable event provider in constructor and disables it in destructor - /// - class WINSTD_API event_trace_enabler - { - public: - /// - /// Enables event trace - /// - /// \sa [EnableTraceEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363711.aspx) - /// - inline event_trace_enabler( - _In_opt_ LPCGUID SourceId, - _In_ TRACEHANDLE TraceHandle, - _In_ LPCGUID ProviderId, - _In_ UCHAR Level, - _In_opt_ ULONGLONG MatchAnyKeyword = 0, - _In_opt_ ULONGLONG MatchAllKeyword = 0, - _In_opt_ ULONG EnableProperty = 0, - _In_opt_ PEVENT_FILTER_DESCRIPTOR EnableFilterDesc = NULL) : - m_provider_id(ProviderId), - m_source_id(SourceId), - m_trace_handle(TraceHandle), - m_level(Level), - m_match_any_keyword(MatchAnyKeyword), - m_match_all_keyword(MatchAllKeyword), - m_enable_property(EnableProperty), - m_enable_filter_desc(EnableFilterDesc) - { - m_status = EnableTraceEx( - m_provider_id, - m_source_id, - m_trace_handle, - EVENT_CONTROL_CODE_ENABLE_PROVIDER, - m_level, - m_match_any_keyword, - m_match_all_keyword, - m_enable_property, - m_enable_filter_desc); - } - - - /// - /// Enables event trace - /// - /// \sa [EnableTraceEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363711.aspx) - /// - inline event_trace_enabler( - _In_ const event_session &session, - _In_ LPCGUID ProviderId, - _In_ UCHAR Level, - _In_opt_ ULONGLONG MatchAnyKeyword = 0, - _In_opt_ ULONGLONG MatchAllKeyword = 0, - _In_opt_ ULONG EnableProperty = 0, - _In_opt_ PEVENT_FILTER_DESCRIPTOR EnableFilterDesc = NULL) : - m_provider_id(ProviderId), - m_source_id(&((const EVENT_TRACE_PROPERTIES*)session)->Wnode.Guid), - m_trace_handle(session), - m_level(Level), - m_match_any_keyword(MatchAnyKeyword), - m_match_all_keyword(MatchAllKeyword), - m_enable_property(EnableProperty), - m_enable_filter_desc(EnableFilterDesc) - { - m_status = EnableTraceEx( - m_provider_id, - m_source_id, - m_trace_handle, - EVENT_CONTROL_CODE_ENABLE_PROVIDER, - m_level, - m_match_any_keyword, - m_match_all_keyword, - m_enable_property, - m_enable_filter_desc); - } - - - /// - /// Return result of `EnableTraceEx()` call. - /// - /// \sa [EnableTraceEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363711.aspx) - /// - inline ULONG status() const - { - return m_status; - } - - - /// - /// Disables event trace. - /// - /// \sa [EnableTraceEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363711.aspx) - /// - virtual ~event_trace_enabler(); - - protected: - ULONG m_status; ///< Result of EnableTraceEx call - LPCGUID m_provider_id; ///< Provider ID - LPCGUID m_source_id; ///< Session ID - TRACEHANDLE m_trace_handle; ///< Trace handle - UCHAR m_level; ///< Logging level - ULONGLONG m_match_any_keyword; ///< Keyword match mask (any) - ULONGLONG m_match_all_keyword; ///< Keyword match mask (all) - ULONG m_enable_property; ///< Enable property - PEVENT_FILTER_DESCRIPTOR m_enable_filter_desc; ///< Event filter descriptor - }; - - - /// - /// Helper class to write an event on entry/exit of scope. - /// - /// It writes one string event at creation and another at destruction. - /// - class WINSTD_API event_fn_auto - { - public: - /// - /// Writes the `event_cons` event - /// - inline event_fn_auto(_In_ event_provider &ep, _In_ const EVENT_DESCRIPTOR *event_cons, _In_ const EVENT_DESCRIPTOR *event_dest, _In_z_ LPCSTR pszFnName) : - m_ep(ep), - m_event_dest(event_dest) - { - EventDataDescCreate(&m_fn_name, pszFnName, (ULONG)(strlen(pszFnName) + 1)*sizeof(*pszFnName)); - m_ep.write(event_cons, 1, &m_fn_name); - } - - - /// - /// Copies the object - /// - inline event_fn_auto(_In_ const event_fn_auto &other) : - m_ep(other.m_ep), - m_event_dest(other.m_event_dest), - m_fn_name(other.m_fn_name) - { - } - - - /// - /// Moves the object - /// - inline event_fn_auto(_Inout_ event_fn_auto &&other) : - m_ep(other.m_ep), - m_event_dest(other.m_event_dest), - m_fn_name(std::move(other.m_fn_name)) - { - other.m_event_dest = NULL; - } - - - /// - /// Writes the `event_dest` event - /// - inline ~event_fn_auto() - { - if (m_event_dest) - m_ep.write(m_event_dest, 1, &m_fn_name); - } - - - /// - /// Copies the object - /// - inline event_fn_auto& operator=(_In_ const event_fn_auto &other) - { - if (this != &other) { - assert(&m_ep == &other.m_ep); - m_event_dest = other.m_event_dest; - m_fn_name = other.m_fn_name; - } - - return *this; - } - - - /// - /// Moves the object - /// - inline event_fn_auto& operator=(_Inout_ event_fn_auto &&other) - { - if (this != &other) { - assert(&m_ep == &other.m_ep); - m_event_dest = other.m_event_dest; - m_fn_name = std::move(other.m_fn_name); - other.m_event_dest = NULL; - } - - 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). - /// - /// It writes one string event at creation and another at destruction, with allowing one sprintf type parameter for string event at destruction. - /// - template - class event_fn_auto_ret - { - public: - /// - /// Writes the `event_cons` event - /// - inline event_fn_auto_ret(_In_ event_provider &ep, _In_ const EVENT_DESCRIPTOR *event_cons, _In_ const EVENT_DESCRIPTOR *event_dest, _In_z_ LPCSTR pszFnName, T &result) : - m_ep(ep), - m_event_dest(event_dest), - m_result(result) - { - EventDataDescCreate(m_desc + 0, pszFnName, (ULONG)(strlen(pszFnName) + 1)*sizeof(*pszFnName)); - m_ep.write(event_cons, 1, m_desc); - } - - - /// - /// Copies the object - /// - inline event_fn_auto_ret(_In_ const event_fn_auto_ret &other) : - m_ep(other.m_ep), - m_event_dest(other.m_event_dest), - m_result(other.m_result) - { - m_desc[0] = other.m_desc[0]; - } - - - /// - /// Moves the object - /// - inline event_fn_auto_ret(_Inout_ event_fn_auto_ret &&other) : - m_ep(other.m_ep), - m_event_dest(other.m_event_dest), - m_result(other.m_result) - { - m_desc[0] = std::move(other.m_desc[0]); - other.m_event_dest = NULL; - } - - - /// - /// Writes the `event_dest` event - /// - inline ~event_fn_auto_ret() - { - if (m_event_dest) { - EventDataDescCreate(m_desc + 1, &m_result, sizeof(T)); - m_ep.write(m_event_dest, 2, m_desc); - } - } - - - /// - /// Copies the object - /// - inline event_fn_auto_ret& operator=(_In_ const event_fn_auto_ret &other) - { - if (this != &other) { - assert(&m_ep == &other.m_ep); - m_event_dest = other.m_event_dest; - m_desc[0] = other.m_desc[0]; - assert(&m_result == &other.m_result); - } - - return *this; - } - - - /// - /// Moves the object - /// - inline event_fn_auto_ret& operator=(_Inout_ event_fn_auto_ret &&other) - { - if (this != &other) { - assert(&m_ep == &other.m_ep); - m_event_dest = other.m_event_dest; - m_desc[0] = std::move(other.m_desc[0]); - assert(&m_result == &other.m_result); - other.m_event_dest = NULL; - } - - 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_desc[2]; ///< Function name and return value - T &m_result; ///< Function result - }; - - /// @} -} - - -inline ULONG TdhGetEventInformation(_In_ PEVENT_RECORD pEvent, _In_ ULONG TdhContextCount, _In_ 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; -} - - -inline ULONG TdhGetEventMapInformation(_In_ PEVENT_RECORD pEvent, _In_ LPWSTR pMapName, _Out_ 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 -inline ULONG TdhGetProperty(_In_ PEVENT_RECORD pEvent, _In_ ULONG TdhContextCount, _In_ PTDH_CONTEXT pTdhContext, _In_ ULONG PropertyDataCount, _In_ PPROPERTY_DATA_DESCRIPTOR pPropertyData, _Out_ 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; -} +/* + Copyright 1991-2018 Amebis + Copyright 2016 GÉANT + + This file is part of WinStd. + + Setup is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Setup is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Setup. If not, see . +*/ + +/// +/// \defgroup WinStdETWAPI Event Tracing for Windows API +/// Integrates WinStd classes with Event Tracing for Windows API +/// + +#include "Common.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace winstd +{ + class WINSTD_API WINSTD_NOVTABLE event_data; + class WINSTD_API WINSTD_NOVTABLE event_rec; + class WINSTD_API event_provider; + class WINSTD_API event_session; + class WINSTD_API event_trace; + class WINSTD_API event_trace_enabler; + class WINSTD_API event_fn_auto; + template class event_fn_auto_ret; +} + +/// \addtogroup WinStdCryptoAPI +/// @{ + +/// +/// Retrieves metadata about an event. +/// +/// \sa [TdhGetEventInformation function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa964840.aspx) +/// +inline ULONG TdhGetEventInformation(_In_ PEVENT_RECORD pEvent, _In_ ULONG TdhContextCount, _In_ 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) +/// +inline ULONG TdhGetEventMapInformation(_In_ PEVENT_RECORD pEvent, _In_ LPWSTR pMapName, _Out_ 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 inline ULONG TdhGetProperty(_In_ PEVENT_RECORD pEvent, _In_ ULONG TdhContextCount, _In_ PTDH_CONTEXT pTdhContext, _In_ ULONG PropertyDataCount, _In_ PPROPERTY_DATA_DESCRIPTOR pPropertyData, _Out_ std::vector<_Ty, _Ax> &aData); + +/// @} + +#pragma once + + +namespace winstd +{ + /// \addtogroup WinStdETWAPI + /// @{ + + /// + /// EVENT_DATA_DESCRIPTOR wrapper + /// + class WINSTD_API WINSTD_NOVTABLE event_data : public EVENT_DATA_DESCRIPTOR + { + public: + /// + /// Construct empty class. + /// + inline event_data() + { + Ptr = 0; + Size = 0; + Reserved = (ULONG)-1; // Used for varadic argument terminator. + } + + + /// + /// Construct class pointing to an `int`. + /// + /// \param[in] data Event data + /// + /// \note This class saves a reference to the data only. Therefore, data must be kept available. + /// + inline event_data(_In_ const int &data) + { + EventDataDescCreate(this, &data, (ULONG)(sizeof(data))); + } + + + /// + /// Construct class pointing to an `unsigned int`. + /// + /// \param[in] data Event data + /// + /// \note This class saves a reference to the data only. Therefore, data must be kept available. + /// + inline event_data(_In_ const unsigned int &data) + { + EventDataDescCreate(this, &data, (ULONG)(sizeof(data))); + } + + + /// + /// Construct class pointing to a `long`. + /// + /// \param[in] data Event data + /// + /// \note This class saves a reference to the data only. Therefore, data must be kept available. + /// + inline event_data(_In_ const long &data) + { + EventDataDescCreate(this, &data, (ULONG)(sizeof(data))); + } + + + /// + /// Construct class pointing to an `unsigned long`. + /// + /// \param[in] data Event data + /// + /// \note This class saves a reference to the data only. Therefore, data must be kept available. + /// + inline event_data(_In_ const unsigned long &data) + { + EventDataDescCreate(this, &data, (ULONG)(sizeof(data))); + } + + + /// + /// Construct class pointing to a `GUID`. + /// + /// \param[in] data Event data + /// + /// \note This class saves a reference to the data only. Therefore, data must be kept available. + /// + inline event_data(_In_ const GUID &data) + { + EventDataDescCreate(this, &data, (ULONG)(sizeof(data))); + } + + + /// + /// Construct class pointing to a string. + /// + /// \param[in] data Event data. When `NULL`, the event data will be `"(null)"`. + /// + /// \note This class saves a reference to the data only. Therefore, data must be kept available. + /// + inline event_data(_In_ const char *data) + { + if (data) + EventDataDescCreate(this, data, (ULONG)((strlen(data) + 1) * sizeof(*data))); + else { + // Writing NULL pointer with 0B length causes trouble in Event Viewer: message template string is displayed only, parameters are not rendered. + static const char null[] = "(null)"; + EventDataDescCreate(this, null, sizeof(null)); + } + } + + + /// + /// Construct class pointing to a wide string. + /// + /// \param[in] data Event data. When `NULL`, the event data will be `"(null)"`. + /// + /// \note This class saves a reference to the data only. Therefore, data must be kept available. + /// + inline event_data(_In_ const wchar_t *data) + { + if (data) + EventDataDescCreate(this, data, (ULONG)((wcslen(data) + 1) * sizeof(*data))); + else { + // Writing NULL pointer with 0B length causes trouble in Event Viewer: message template string is displayed only, parameters are not rendered. + static const wchar_t null[] = L"(null)"; + EventDataDescCreate(this, null, sizeof(null)); + } + } + + + /// + /// Template to construct pointing to a `std::basic_string<>`. + /// + /// \param[in] data Event data + /// + /// \note This class saves a reference to the data only. Therefore, data must be kept available. + /// + template + inline event_data(_In_ const std::basic_string<_Elem, _Traits, _Ax> &data) + { + EventDataDescCreate(this, data.c_str(), (ULONG)((data.length() + 1) * sizeof(_Elem))); + } + + + /// + /// Construct class pointing to binary data. + /// + /// \param[in] data Pointer to event data + /// \param[in] size Size of \p data in bytes + /// + /// \note This class saves a reference to the data only. Therefore, data must be kept available. + /// + inline event_data(_In_bytecount_(size) const void *data, _In_ ULONG size) + { + EventDataDescCreate(this, data, size); + } + + + /// + /// Blank event data used as terminator. + /// + static const event_data blank; + }; + + + /// + /// EVENT_RECORD wrapper + /// + class WINSTD_API WINSTD_NOVTABLE event_rec : public EVENT_RECORD + { + public: + /// + /// Constructs a blank event record. + /// + inline event_rec() + { + memset((EVENT_RECORD*)this, 0, sizeof(EVENT_RECORD)); + } + + + /// + /// Copies an existing event record. + /// + /// \param[in] other Event record to copy from + /// + inline event_rec(_In_ const event_rec &other) : EVENT_RECORD(other) + { + set_extended_data_internal(other.ExtendedDataCount, other.ExtendedData); + set_user_data_internal(other.UserDataLength, other.UserData); + } + + + /// + /// Copies an existing event record. + /// + /// \param[in] other Event record to copy from + /// + inline event_rec(_In_ const EVENT_RECORD &other) : EVENT_RECORD(other) + { + set_extended_data_internal(other.ExtendedDataCount, other.ExtendedData); + set_user_data_internal(other.UserDataLength, other.UserData); + } + + + /// + /// Moves the event record. + /// + /// \param[in] other Event record to move + /// + inline event_rec(_Inout_ event_rec&& other) noexcept : EVENT_RECORD(other) + { + memset((EVENT_RECORD*)&other, 0, sizeof(EVENT_RECORD)); + } + + + /// + /// Destroys event record data and frees the allocated memory. + /// + ~event_rec(); + + + /// + /// Copies an existing event record. + /// + /// \param[in] other Event record to copy from + /// + inline event_rec& operator=(_In_ const event_rec &other) + { + if (this != std::addressof(other)) { + (EVENT_RECORD&)*this = other; + set_extended_data_internal(other.ExtendedDataCount, other.ExtendedData); + set_user_data_internal(other.UserDataLength, other.UserData); + } + + return *this; + } + + + /// + /// Copies an existing event record. + /// + /// \param[in] other Event record to copy from + /// + inline event_rec& operator=(_In_ const EVENT_RECORD &other) + { + if (this != std::addressof(other)) { + (EVENT_RECORD&)*this = other; + set_extended_data_internal(other.ExtendedDataCount, other.ExtendedData); + set_user_data_internal(other.UserDataLength, other.UserData); + } + + return *this; + } + + + /// + /// Moves the event record. + /// + /// \param[in] other Event record to move + /// + inline event_rec& operator=(_Inout_ event_rec&& other) noexcept + { + if (this != std::addressof(other)) { + (EVENT_RECORD&)*this = other; + memset((EVENT_RECORD*)&other, 0, sizeof(EVENT_RECORD)); + } + + return *this; + } + + + /// + /// Sets event record extended data. + /// + /// \param[in] count \p data size (in number of elements) + /// \param[in] data Record extended data + /// + void set_extended_data(_In_ USHORT count, _In_count_(count) const EVENT_HEADER_EXTENDED_DATA_ITEM *data); + + + /// + /// Sets event record user data. + /// + /// \param[in] size \p data size (in bytes) + /// \param[in] data Record user data + /// + void set_user_data(_In_ USHORT size, _In_bytecount_(size) LPCVOID data); + + protected: + /// + /// Sets event record extended data. + /// + /// \param[in] count \p data size (in number of elements) + /// \param[in] data Record extended data + /// + void set_extended_data_internal(_In_ USHORT count, _In_count_(count) const EVENT_HEADER_EXTENDED_DATA_ITEM *data); + + /// + /// Sets event record user data. + /// + /// \param[in] size \p data size (in bytes) + /// \param[in] data Record user data + /// + void set_user_data_internal(_In_ USHORT size, _In_bytecount_(size) LPCVOID data); + }; + + + /// + /// ETW event provider + /// + class WINSTD_API event_provider : public handle + { + HANDLE_IMPL(event_provider) + + public: + /// + /// Closes the event provider. + /// + /// \sa [EventUnregister function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363749.aspx) + /// + virtual ~event_provider(); + + + /// + /// Registers the event provider. + /// + /// \return + /// - `ERROR_SUCCESS` when creation succeeds; + /// - error code otherwise. + /// + /// \sa [EventRegister function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363744.aspx) + /// + inline ULONG create(_In_ LPCGUID ProviderId) + { + handle_type h; + ULONG ulRes = EventRegister(ProviderId, enable_callback, this, &h); + if (ulRes == ERROR_SUCCESS) + attach(h); + return ulRes; + } + + + /// + /// Writes an event with no parameters. + /// + /// \return + /// - `ERROR_SUCCESS` when write succeeds; + /// - error code otherwise. + /// + /// \sa [EventWrite function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363752.aspx) + /// + inline ULONG write(_In_ PCEVENT_DESCRIPTOR EventDescriptor) + { + assert(m_h); + return EventWrite(m_h, EventDescriptor, 0, NULL); + } + + + /// + /// Writes an event with parameters stored in array. + /// + /// \return + /// - `ERROR_SUCCESS` when write succeeds; + /// - error code otherwise. + /// + /// \sa [EventWrite function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363752.aspx) + /// + inline ULONG write(_In_ PCEVENT_DESCRIPTOR EventDescriptor, _In_ ULONG UserDataCount = 0, _In_opt_count_(UserDataCount) PEVENT_DATA_DESCRIPTOR UserData = NULL) + { + assert(m_h); + return EventWrite(m_h, EventDescriptor, UserDataCount, UserData); + } + + + /// + /// Writes an event with one or more parameter. + /// + /// \note The list must be terminated with `winstd::event_data::blank`. + /// + /// \return + /// - `ERROR_SUCCESS` when write succeeds; + /// - error code otherwise. + /// + /// \sa [EventWrite function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363752.aspx) + /// + inline ULONG write(_In_ PCEVENT_DESCRIPTOR EventDescriptor, _In_ const EVENT_DATA_DESCRIPTOR param1, ...) + { + assert(m_h); + + // The first argument (param1) is outside of varadic argument list. + if (param1.Ptr == winstd::event_data::blank.Ptr && + param1.Size == winstd::event_data::blank.Size && + param1.Reserved == winstd::event_data::blank.Reserved) + return EventWrite(m_h, EventDescriptor, 0, NULL); + + va_list arg; + va_start(arg, param1); + va_list arg_start = arg; + std::vector params; + ULONG param_count; + + // Preallocate array. + for (param_count = 1; param_count < MAX_EVENT_DATA_DESCRIPTORS; param_count++) { + const EVENT_DATA_DESCRIPTOR &p = va_arg(arg, const EVENT_DATA_DESCRIPTOR); + if (p.Ptr == winstd::event_data::blank.Ptr && + p.Size == winstd::event_data::blank.Size && + p.Reserved == winstd::event_data::blank.Reserved) break; + } + params.reserve(param_count); + + // Copy parameters to array. + arg = arg_start; + params.push_back(param1); + for (;;) { + const EVENT_DATA_DESCRIPTOR &p = va_arg(arg, const EVENT_DATA_DESCRIPTOR); + if (p.Ptr == winstd::event_data::blank.Ptr && + p.Size == winstd::event_data::blank.Size && + p.Reserved == winstd::event_data::blank.Reserved) break; + params.push_back(p); + } + + va_end(arg); +#pragma warning(push) +#pragma warning(disable: 28020) + return EventWrite(m_h, EventDescriptor, param_count, params.data()); +#pragma warning(pop) + } + + + /// + /// Writes an event with variable number of parameters. + /// + /// \note The list must be terminated with `winstd::event_data::blank`. + /// + /// \return + /// - `ERROR_SUCCESS` when write succeeds; + /// - error code otherwise. + /// + /// \sa [EventWrite function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363752.aspx) + /// + inline ULONG write(_In_ PCEVENT_DESCRIPTOR EventDescriptor, _In_ va_list arg) + { + assert(m_h); + + va_list arg_start = arg; + std::vector params; + ULONG param_count; + + // Preallocate array. + for (param_count = 0; param_count < MAX_EVENT_DATA_DESCRIPTORS; param_count++) { + const EVENT_DATA_DESCRIPTOR &p = va_arg(arg, const EVENT_DATA_DESCRIPTOR); + if (p.Ptr == winstd::event_data::blank.Ptr && + p.Size == winstd::event_data::blank.Size && + p.Reserved == winstd::event_data::blank.Reserved) break; + } + params.reserve(param_count); + + // Copy parameters to array. + arg = arg_start; + for (;;) { + const EVENT_DATA_DESCRIPTOR &p = va_arg(arg, const EVENT_DATA_DESCRIPTOR); + if (p.Ptr == winstd::event_data::blank.Ptr && + p.Size == winstd::event_data::blank.Size && + p.Reserved == winstd::event_data::blank.Reserved) break; + params.push_back(p); + } + +#pragma warning(push) +#pragma warning(disable: 28020) + return EventWrite(m_h, EventDescriptor, param_count, params.data()); +#pragma warning(pop) + } + + + /// + /// Writes a string event. + /// + /// \return + /// - `ERROR_SUCCESS` when write succeeds; + /// - error code otherwise. + /// + /// \sa [EventWriteString function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363750v=vs.85.aspx) + /// + inline ULONG write(_In_ UCHAR Level, _In_ ULONGLONG Keyword, _In_z_ _Printf_format_string_ PCWSTR String, ...) + { + assert(m_h); + + std::wstring msg; + va_list arg; + + // Format message. + va_start(arg, String); + vsprintf(msg, String, arg); + va_end(arg); + + // Write string event. + return EventWriteString(m_h, Level, Keyword, msg.c_str()); + } + + protected: + /// + /// Releases the event provider. + /// + /// \sa [EventUnregister function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363749.aspx) + /// + virtual void free_internal(); + + + /// + /// Receive enable or disable notification requests + /// + /// \sa [EnableCallback callback function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363707.aspx) + /// + virtual void enable_callback(_In_ LPCGUID SourceId, _In_ ULONG IsEnabled, _In_ UCHAR Level, _In_ ULONGLONG MatchAnyKeyword, _In_ ULONGLONG MatchAllKeyword, _In_opt_ PEVENT_FILTER_DESCRIPTOR FilterData); + + + /// + /// Receive enable or disable notification requests + /// + /// \sa [EnableCallback callback function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363707.aspx) + /// + static VOID NTAPI enable_callback(_In_ LPCGUID SourceId, _In_ ULONG IsEnabled, _In_ UCHAR Level, _In_ ULONGLONG MatchAnyKeyword, _In_ ULONGLONG MatchAllKeyword, _In_opt_ PEVENT_FILTER_DESCRIPTOR FilterData, _Inout_opt_ PVOID CallbackContext); + }; + + + /// + /// ETW session + /// + class WINSTD_API event_session : public handle + { + WINSTD_NONCOPYABLE(event_session) + + public: + /// + /// Initializes a new empty session. + /// + inline event_session() + { + } + + + /// + /// Initializes a new session with an already available object handle. + /// + /// \param[in] h Initial session handle value + /// \param[in] prop Session properties + /// + inline event_session(_In_opt_ handle_type h, _In_ const EVENT_TRACE_PROPERTIES *prop) : + m_prop(reinterpret_cast(new char[prop->Wnode.BufferSize])), + handle(h) + { + memcpy(m_prop.get(), prop, prop->Wnode.BufferSize); + } + + + /// + /// Move constructor + /// + /// \param[inout] other A rvalue reference of another session + /// + inline event_session(_Inout_ event_session &&other) noexcept : + m_prop(std::move(other.m_prop)), + handle(std::move(other)) + { + } + + + /// + /// Closes the session. + /// + /// \sa [ControlTrace function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363696.aspx) + /// + virtual ~event_session(); + + + /// + /// Move assignment + /// + /// \param[inout] other A rvalue reference of another object + /// + inline event_session& operator=(_Inout_ event_session &&other) noexcept + { + if (this != std::addressof(other)) { + (handle&&)*this = std::move(other); + m_prop = std::move(other.m_prop); + } + return *this; + } + + + /// + /// Auto-typecasting operator + /// + /// \return Session properties + /// + inline operator const EVENT_TRACE_PROPERTIES*() const + { + return m_prop.get(); + } + + + /// + /// Auto-typecasting operator + /// + /// \return Session properties + /// + inline LPCTSTR name() const + { + const EVENT_TRACE_PROPERTIES *prop = m_prop.get(); + return reinterpret_cast(reinterpret_cast(prop) + prop->LoggerNameOffset); + } + + + /// + /// Sets a new session handle for the class + /// + /// When the current session handle of the class is non-NULL, the session is destroyed first. + /// + /// \param[in] h New session handle + /// \param[in] prop Session properties + /// + inline void attach(_In_opt_ handle_type h, _In_ EVENT_TRACE_PROPERTIES *prop) + { + handle::attach(h); + m_prop.reset(prop); + } + + + /// + /// Registers and starts an event tracing session. + /// + /// \return + /// - `ERROR_SUCCESS` when creation succeeds; + /// - error code otherwise. + /// + /// \sa [StartTrace function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa364117.aspx) + /// + inline ULONG create(_In_ LPCTSTR SessionName, _In_ const EVENT_TRACE_PROPERTIES *Properties) + { + handle_type h; + std::unique_ptr prop(reinterpret_cast(new char[Properties->Wnode.BufferSize])); + memcpy(prop.get(), Properties, Properties->Wnode.BufferSize); + ULONG ulRes = StartTrace(&h, SessionName, prop.get()); + if (ulRes == ERROR_SUCCESS) + attach(h, prop.release()); + return ulRes; + } + + + /// + /// Enables the specified event trace provider. + /// + /// \return + /// - `ERROR_SUCCESS` when succeeds; + /// - error code otherwise. + /// + /// \sa [EnableTraceEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363711.aspx) + /// + inline ULONG enable_trace(_In_ LPCGUID ProviderId, _In_ UCHAR Level, _In_opt_ ULONGLONG MatchAnyKeyword = 0, _In_opt_ ULONGLONG MatchAllKeyword = 0, _In_opt_ ULONG EnableProperty = 0, _In_opt_ PEVENT_FILTER_DESCRIPTOR EnableFilterDesc = NULL) + { + assert(m_h); + return EnableTraceEx( + ProviderId, + &m_prop->Wnode.Guid, + m_h, + EVENT_CONTROL_CODE_ENABLE_PROVIDER, + Level, + MatchAnyKeyword, + MatchAllKeyword, + EnableProperty, + EnableFilterDesc); + } + + + /// + /// Disables the specified event trace provider. + /// + /// \return + /// - `ERROR_SUCCESS` when succeeds; + /// - error code otherwise. + /// + /// \sa [EnableTraceEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363711.aspx) + /// + inline ULONG disable_trace(_In_ LPCGUID ProviderId, _In_ UCHAR Level, _In_opt_ ULONGLONG MatchAnyKeyword = 0, _In_opt_ ULONGLONG MatchAllKeyword = 0, _In_opt_ ULONG EnableProperty = 0, _In_opt_ PEVENT_FILTER_DESCRIPTOR EnableFilterDesc = NULL) + { + assert(m_h); + return EnableTraceEx( + ProviderId, + &m_prop->Wnode.Guid, + m_h, + EVENT_CONTROL_CODE_DISABLE_PROVIDER, + Level, + MatchAnyKeyword, + MatchAllKeyword, + EnableProperty, + EnableFilterDesc); + } + + + protected: + /// + /// Releases the session. + /// + /// \sa [ControlTrace function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363696.aspx) + /// + virtual void free_internal(); + + protected: + std::unique_ptr m_prop; ///< Session properties + }; + + + /// + /// ETW trace + /// + class WINSTD_API event_trace : public handle + { + HANDLE_IMPL(event_trace) + + public: + /// + /// Closes the trace. + /// + /// \sa [CloseTrace function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363686.aspx) + /// + virtual ~event_trace(); + + + /// + /// Opens a real-time trace session or log file for consuming. + /// + /// \return + /// - `ERROR_SUCCESS` when creation succeeds; + /// - error code otherwise. + /// + /// \sa [OpenTrace function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa364089.aspx) + /// + inline bool create(_Inout_ PEVENT_TRACE_LOGFILE Logfile) + { + handle_type h = OpenTrace(Logfile); + if (h != (TRACEHANDLE)INVALID_HANDLE_VALUE) { + attach(h); + return true; + } else + return false; + } + + protected: + /// + /// Closes the trace. + /// + /// \sa [CloseTrace function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363686.aspx) + /// + virtual void free_internal(); + }; + + + /// + /// Helper class to enable event provider in constructor and disables it in destructor + /// + class WINSTD_API event_trace_enabler + { + public: + /// + /// Enables event trace + /// + /// \sa [EnableTraceEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363711.aspx) + /// + inline event_trace_enabler( + _In_opt_ LPCGUID SourceId, + _In_ TRACEHANDLE TraceHandle, + _In_ LPCGUID ProviderId, + _In_ UCHAR Level, + _In_opt_ ULONGLONG MatchAnyKeyword = 0, + _In_opt_ ULONGLONG MatchAllKeyword = 0, + _In_opt_ ULONG EnableProperty = 0, + _In_opt_ PEVENT_FILTER_DESCRIPTOR EnableFilterDesc = NULL) : + m_provider_id(ProviderId), + m_source_id(SourceId), + m_trace_handle(TraceHandle), + m_level(Level), + m_match_any_keyword(MatchAnyKeyword), + m_match_all_keyword(MatchAllKeyword), + m_enable_property(EnableProperty), + m_enable_filter_desc(EnableFilterDesc) + { + m_status = EnableTraceEx( + m_provider_id, + m_source_id, + m_trace_handle, + EVENT_CONTROL_CODE_ENABLE_PROVIDER, + m_level, + m_match_any_keyword, + m_match_all_keyword, + m_enable_property, + m_enable_filter_desc); + } + + + /// + /// Enables event trace + /// + /// \sa [EnableTraceEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363711.aspx) + /// + inline event_trace_enabler( + _In_ const event_session &session, + _In_ LPCGUID ProviderId, + _In_ UCHAR Level, + _In_opt_ ULONGLONG MatchAnyKeyword = 0, + _In_opt_ ULONGLONG MatchAllKeyword = 0, + _In_opt_ ULONG EnableProperty = 0, + _In_opt_ PEVENT_FILTER_DESCRIPTOR EnableFilterDesc = NULL) : + m_provider_id(ProviderId), + m_source_id(&((const EVENT_TRACE_PROPERTIES*)session)->Wnode.Guid), + m_trace_handle(session), + m_level(Level), + m_match_any_keyword(MatchAnyKeyword), + m_match_all_keyword(MatchAllKeyword), + m_enable_property(EnableProperty), + m_enable_filter_desc(EnableFilterDesc) + { + m_status = EnableTraceEx( + m_provider_id, + m_source_id, + m_trace_handle, + EVENT_CONTROL_CODE_ENABLE_PROVIDER, + m_level, + m_match_any_keyword, + m_match_all_keyword, + m_enable_property, + m_enable_filter_desc); + } + + + /// + /// Return result of `EnableTraceEx()` call. + /// + /// \sa [EnableTraceEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363711.aspx) + /// + inline ULONG status() const + { + return m_status; + } + + + /// + /// Disables event trace. + /// + /// \sa [EnableTraceEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363711.aspx) + /// + virtual ~event_trace_enabler(); + + protected: + ULONG m_status; ///< Result of EnableTraceEx call + LPCGUID m_provider_id; ///< Provider ID + LPCGUID m_source_id; ///< Session ID + TRACEHANDLE m_trace_handle; ///< Trace handle + UCHAR m_level; ///< Logging level + ULONGLONG m_match_any_keyword; ///< Keyword match mask (any) + ULONGLONG m_match_all_keyword; ///< Keyword match mask (all) + ULONG m_enable_property; ///< Enable property + PEVENT_FILTER_DESCRIPTOR m_enable_filter_desc; ///< Event filter descriptor + }; + + + /// + /// Helper class to write an event on entry/exit of scope. + /// + /// It writes one string event at creation and another at destruction. + /// + class WINSTD_API event_fn_auto + { + public: + /// + /// Writes the `event_cons` event + /// + inline event_fn_auto(_In_ event_provider &ep, _In_ const EVENT_DESCRIPTOR *event_cons, _In_ const EVENT_DESCRIPTOR *event_dest, _In_z_ LPCSTR pszFnName) : + m_ep(ep), + m_event_dest(event_dest) + { + EventDataDescCreate(&m_fn_name, pszFnName, (ULONG)(strlen(pszFnName) + 1)*sizeof(*pszFnName)); + m_ep.write(event_cons, 1, &m_fn_name); + } + + + /// + /// Copies the object + /// + inline event_fn_auto(_In_ const event_fn_auto &other) : + m_ep(other.m_ep), + m_event_dest(other.m_event_dest), + m_fn_name(other.m_fn_name) + { + } + + + /// + /// Moves the object + /// + inline event_fn_auto(_Inout_ event_fn_auto &&other) noexcept : + m_ep(other.m_ep), + m_event_dest(other.m_event_dest), + m_fn_name(std::move(other.m_fn_name)) + { + other.m_event_dest = NULL; + } + + + /// + /// Writes the `event_dest` event + /// + inline ~event_fn_auto() + { + if (m_event_dest) + m_ep.write(m_event_dest, 1, &m_fn_name); + } + + + /// + /// Copies the object + /// + inline event_fn_auto& operator=(_In_ const event_fn_auto &other) + { + if (this != &other) { + assert(&m_ep == &other.m_ep); + m_event_dest = other.m_event_dest; + m_fn_name = other.m_fn_name; + } + + return *this; + } + + + /// + /// Moves the object + /// + inline event_fn_auto& operator=(_Inout_ event_fn_auto &&other) noexcept + { + if (this != &other) { + assert(&m_ep == &other.m_ep); + m_event_dest = other.m_event_dest; + m_fn_name = std::move(other.m_fn_name); + other.m_event_dest = NULL; + } + + 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). + /// + /// It writes one string event at creation and another at destruction, with allowing one sprintf type parameter for string event at destruction. + /// + template + class event_fn_auto_ret + { + public: + /// + /// Writes the `event_cons` event + /// + inline event_fn_auto_ret(_In_ event_provider &ep, _In_ const EVENT_DESCRIPTOR *event_cons, _In_ const EVENT_DESCRIPTOR *event_dest, _In_z_ LPCSTR pszFnName, T &result) : + m_ep(ep), + m_event_dest(event_dest), + m_result(result) + { + EventDataDescCreate(m_desc + 0, pszFnName, (ULONG)(strlen(pszFnName) + 1)*sizeof(*pszFnName)); + m_ep.write(event_cons, 1, m_desc); + } + + + /// + /// Copies the object + /// + inline event_fn_auto_ret(_In_ const event_fn_auto_ret &other) : + m_ep(other.m_ep), + m_event_dest(other.m_event_dest), + m_result(other.m_result) + { + m_desc[0] = other.m_desc[0]; + } + + + /// + /// Moves the object + /// + inline event_fn_auto_ret(_Inout_ event_fn_auto_ret &&other) : + m_ep(other.m_ep), + m_event_dest(other.m_event_dest), + m_result(other.m_result) + { + m_desc[0] = std::move(other.m_desc[0]); + other.m_event_dest = NULL; + } + + + /// + /// Writes the `event_dest` event + /// + inline ~event_fn_auto_ret() + { + if (m_event_dest) { + EventDataDescCreate(m_desc + 1, &m_result, sizeof(T)); + m_ep.write(m_event_dest, 2, m_desc); + } + } + + + /// + /// Copies the object + /// + inline event_fn_auto_ret& operator=(_In_ const event_fn_auto_ret &other) + { + if (this != &other) { + assert(&m_ep == &other.m_ep); + m_event_dest = other.m_event_dest; + m_desc[0] = other.m_desc[0]; + assert(&m_result == &other.m_result); + } + + return *this; + } + + + /// + /// Moves the object + /// + inline event_fn_auto_ret& operator=(_Inout_ event_fn_auto_ret &&other) + { + if (this != &other) { + assert(&m_ep == &other.m_ep); + m_event_dest = other.m_event_dest; + m_desc[0] = std::move(other.m_desc[0]); + assert(&m_result == &other.m_result); + other.m_event_dest = NULL; + } + + 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_desc[2]; ///< Function name and return value + T &m_result; ///< Function result + }; + + /// @} +} + + +inline ULONG TdhGetEventInformation(_In_ PEVENT_RECORD pEvent, _In_ ULONG TdhContextCount, _In_ 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); + } + + info.reset(nullptr); + return ulResult; +} + + +inline ULONG TdhGetEventMapInformation(_In_ PEVENT_RECORD pEvent, _In_ LPWSTR pMapName, _Out_ 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); + } + + info.reset(nullptr); + return ulResult; +} + + +template +inline ULONG TdhGetProperty(_In_ PEVENT_RECORD pEvent, _In_ ULONG TdhContextCount, _In_ PTDH_CONTEXT pTdhContext, _In_ ULONG PropertyDataCount, _In_ PPROPERTY_DATA_DESCRIPTOR pPropertyData, _Out_ 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; +} diff --git a/include/WinStd/Hex.h b/include/WinStd/Hex.h index 0e53e637..3805a171 100644 --- a/include/WinStd/Hex.h +++ b/include/WinStd/Hex.h @@ -1,190 +1,192 @@ -/* - Copyright 1991-2018 Amebis - Copyright 2016 GÉANT - - This file is part of WinStd. - - Setup is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Setup is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Setup. If not, see . -*/ - -/// -/// \defgroup WinStdHexadecimal Hexadecimal conversion -/// Provides Hexadecimal conversion for WinStd classes -/// - -#include "Common.h" - -#include -#include - -namespace winstd -{ - class WINSTD_API hex_enc; - class WINSTD_API hex_dec; -} - -#pragma once - - -namespace winstd -{ - /// \addtogroup WinStdHexadecimal - /// @{ - - /// - /// Hexadecimal encoding session - /// - class WINSTD_API hex_enc - { - public: - /// - /// Constructs blank encoding session - /// - inline hex_enc() - { - } - - - /// - /// Encodes one block of information, and _appends_ it to the output - /// - /// \param[out] out Output - /// \param[in ] data Data to encode - /// \param[in ] size Length of `data` in bytes - /// - template - inline void encode(_Out_ std::basic_string<_Elem, _Traits, _Ax> &out, _In_bytecount_(size) const void *data, _In_ size_t size) - { - assert(data || !size); - - // Preallocate output - out.reserve(out.size() + enc_size(size)); - - // Convert data character by character. - for (size_t i = 0; i < size; i++) { - unsigned char - x = reinterpret_cast(data)[i], - x_h = ((x & 0xf0) >> 4), - x_l = ((x & 0x0f) ); - - out += x_h < 10 ? '0' + x_h : 'A' - 10 + x_h; - out += x_l < 10 ? '0' + x_l : 'A' - 10 + x_l; - } - } - - - /// - /// Returns maximum encoded size - /// - /// \param size Number of bytes to encode - /// - /// \returns Maximum number of bytes for the encoded data of `size` length - /// - inline size_t enc_size(size_t size) const - { - return size*2; - } - }; - - - /// - /// Hexadecimal decoding session - /// - class WINSTD_API hex_dec - { - public: - /// - /// Constructs blank decoding session - /// - inline hex_dec() : num(0) - { - } - - - /// - /// Decodes one block of information, and _appends_ it to the output - /// - /// \param[out] out Output - /// \param[out] is_last Was this the last block of data? Actually, is this block of data complete? - /// \param[in ] data Data to decode - /// \param[in ] size Length of `data` in bytes - /// - template - inline void decode(_Out_ std::vector<_Ty, _Ax> &out, _Out_ bool &is_last, _In_z_count_(size) const _Tchr *data, _In_ size_t size) - { - is_last = false; - - // Trim data size to first terminator. - for (size_t k = 0; k < size; k++) - if (!data[k]) { size = k; break; } - - // Preallocate output - out.reserve(out.size() + dec_size(size)); - - for (size_t i = 0;; i++) { - if (num >= 2) { - // Buffer full. - out.push_back(buf); - num = 0; - is_last = true; - } else - is_last = false; - - if (i >= size) - break; - - int x = data[i]; - if ('0' <= x && x <= '9') { - buf = ((buf & 0xf) << 4) | (unsigned char)(x - '0'); - num++; - } else if ('A' <= x && x <= 'F') { - buf = ((buf & 0xf) << 4) | (unsigned char)(x - ('A' - 10)); - num++; - } else if ('a' <= x && x <= 'f') { - buf = ((buf & 0xf) << 4) | (unsigned char)(x - ('a' - 10)); - num++; - } - } - } - - - /// - /// Resets decoding session - /// - inline void clear() - { - num = 0; - } - - - /// - /// Returns maximum decoded size - /// - /// \param size Number of bytes to decode - /// - /// \returns Maximum number of bytes for the decoded data of `size` length - /// - inline size_t dec_size(size_t size) const - { - return (size + 1)/2; - } - - - protected: - unsigned char buf; ///< Internal buffer - size_t num; ///< Number of nibbles used in `buf` - }; - - /// @} -} +/* + Copyright 1991-2018 Amebis + Copyright 2016 GÉANT + + This file is part of WinStd. + + Setup is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Setup is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Setup. If not, see . +*/ + +/// +/// \defgroup WinStdHexadecimal Hexadecimal conversion +/// Provides Hexadecimal conversion for WinStd classes +/// + +#include "Common.h" + +#include +#include + +namespace winstd +{ + class WINSTD_API hex_enc; + class WINSTD_API hex_dec; +} + +#pragma once + + +namespace winstd +{ + /// \addtogroup WinStdHexadecimal + /// @{ + + /// + /// Hexadecimal encoding session + /// + class WINSTD_API hex_enc + { + public: + /// + /// Constructs blank encoding session + /// + inline hex_enc() + { + } + + + /// + /// Encodes one block of information, and _appends_ it to the output + /// + /// \param[out] out Output + /// \param[in ] data Data to encode + /// \param[in ] size Length of `data` in bytes + /// + template + inline void encode(_Out_ std::basic_string<_Elem, _Traits, _Ax> &out, _In_bytecount_(size) const void *data, _In_ size_t size) + { + assert(data || !size); + + // Preallocate output + out.reserve(out.size() + enc_size(size)); + + // Convert data character by character. + for (size_t i = 0; i < size; i++) { + unsigned char + x = reinterpret_cast(data)[i], + x_h = ((x & 0xf0) >> 4), + x_l = ((x & 0x0f) ); + + out += x_h < 10 ? '0' + x_h : 'A' - 10 + x_h; + out += x_l < 10 ? '0' + x_l : 'A' - 10 + x_l; + } + } + + + /// + /// Returns maximum encoded size + /// + /// \param size Number of bytes to encode + /// + /// \returns Maximum number of bytes for the encoded data of `size` length + /// + inline size_t enc_size(size_t size) const + { + return size*2; + } + }; + + + /// + /// Hexadecimal decoding session + /// + class WINSTD_API hex_dec + { + public: + /// + /// Constructs blank decoding session + /// + inline hex_dec() : + buf(0), + num(0) + { + } + + + /// + /// Decodes one block of information, and _appends_ it to the output + /// + /// \param[inout] out Output + /// \param[out ] is_last Was this the last block of data? Actually, is this block of data complete? + /// \param[in ] data Data to decode + /// \param[in ] size Length of `data` in bytes + /// + template + inline void decode(_Inout_ std::vector<_Ty, _Ax> &out, _Out_ bool &is_last, _In_z_count_(size) const _Tchr *data, _In_ size_t size) + { + is_last = false; + + // Trim data size to first terminator. + for (size_t k = 0; k < size; k++) + if (!data[k]) { size = k; break; } + + // Preallocate output + out.reserve(out.size() + dec_size(size)); + + for (size_t i = 0;; i++) { + if (num >= 2) { + // Buffer full. + out.push_back(buf); + num = 0; + is_last = true; + } else + is_last = false; + + if (i >= size) + break; + + int x = data[i]; + if ('0' <= x && x <= '9') { + buf = ((buf & 0xf) << 4) | (unsigned char)(x - '0'); + num++; + } else if ('A' <= x && x <= 'F') { + buf = ((buf & 0xf) << 4) | (unsigned char)(x - ('A' - 10)); + num++; + } else if ('a' <= x && x <= 'f') { + buf = ((buf & 0xf) << 4) | (unsigned char)(x - ('a' - 10)); + num++; + } + } + } + + + /// + /// Resets decoding session + /// + inline void clear() + { + num = 0; + } + + + /// + /// Returns maximum decoded size + /// + /// \param size Number of bytes to decode + /// + /// \returns Maximum number of bytes for the decoded data of `size` length + /// + inline size_t dec_size(size_t size) const + { + return (size + 1)/2; + } + + + protected: + unsigned char buf; ///< Internal buffer + size_t num; ///< Number of nibbles used in `buf` + }; + + /// @} +} diff --git a/include/WinStd/Win.h b/include/WinStd/Win.h index f0287a9f..9bfeff30 100644 --- a/include/WinStd/Win.h +++ b/include/WinStd/Win.h @@ -1,1541 +1,1541 @@ -/* - Copyright 1991-2018 Amebis - Copyright 2016 GÉANT - - This file is part of WinStd. - - Setup is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Setup is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Setup. If not, see . -*/ - -/// -/// \defgroup WinStdWinAPI Windows API -/// Integrates WinStd classes with Microsoft Windows API -/// - -#include "Common.h" - -#include - -#include -#include - -namespace winstd -{ - class WINSTD_API win_handle; - class WINSTD_API library; - class WINSTD_API process; - class WINSTD_API file; - class WINSTD_API heap; - template class heap_allocator; - class WINSTD_API actctx_activator; - class WINSTD_API user_impersonator; - class WINSTD_API vmemory; - class WINSTD_API reg_key; - class WINSTD_API security_id; -} - - -/// \addtogroup WinStdWinAPI -/// @{ - -/// @copydoc GetModuleFileNameW() -template inline DWORD GetModuleFileNameA(_In_opt_ HMODULE hModule, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sValue); - -/// -/// Retrieves the fully qualified path for the file that contains the specified module and stores it in a std::wstring string. -/// -/// \sa [GetModuleFileName function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms683197.aspx) -/// -template inline DWORD GetModuleFileNameW(_In_opt_ HMODULE hModule, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sValue); - -/// @copydoc GetWindowTextW() -template inline int GetWindowTextA(_In_ HWND hWnd, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sValue); - -/// -/// Copies the text of the specified window's title bar (if it has one) into a std::wstring string. -/// -/// \sa [GetWindowText function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633520.aspx) -/// -template inline int GetWindowTextW(_In_ HWND hWnd, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sValue); - -/// @copydoc GetFileVersionInfoW() -template inline BOOL GetFileVersionInfoA(_In_ LPCSTR lptstrFilename, __reserved DWORD dwHandle, _Out_ std::vector<_Ty, _Ax> &aValue); - -/// -/// Retrieves version information for the specified file and stores it in a std::vector buffer. -/// -/// \sa [GetFileVersionInfo function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms647003.aspx) -/// -template inline BOOL GetFileVersionInfoW(_In_ LPCWSTR lptstrFilename, __reserved DWORD dwHandle, _Out_ std::vector<_Ty, _Ax> &aValue); - -/// @copydoc ExpandEnvironmentStringsW() -template inline DWORD ExpandEnvironmentStringsA(_In_ LPCSTR lpSrc, std::basic_string<_Elem, _Traits, _Ax> &sValue); - -/// -/// Expands environment-variable strings, replaces them with the values defined for the current user, and stores it in a std::wstring string. -/// -/// \sa [ExpandEnvironmentStrings function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724265.aspx) -/// -template inline DWORD ExpandEnvironmentStringsW(_In_ LPCWSTR lpSrc, std::basic_string<_Elem, _Traits, _Ax> &sValue); - -/// @copydoc GuidToStringW() -template inline VOID GuidToStringA(_In_ LPCGUID lpGuid, _Out_ std::basic_string<_Elem, _Traits, _Ax> &str); - -/// -/// Formats GUID and stores it in a std::wstring string. -/// -/// \param[in ] lpGuid Pointer to GUID -/// \param[out] str String to store the result to -/// -template inline VOID GuidToStringW(_In_ LPCGUID lpGuid, _Out_ std::basic_string<_Elem, _Traits, _Ax> &str); -/// @copydoc GuidToStringW() -#ifdef _UNICODE -#define GuidToString GuidToStringW -#else -#define GuidToString GuidToStringA -#endif - -/// @copydoc StringToGuidW() -BOOL WINSTD_API StringToGuidA(_In_z_ LPCSTR lpszGuid, _Out_ LPGUID lpGuid, _Out_opt_ LPCSTR *lpszGuidEnd = NULL); - -/// -/// Parses string with GUID and stores it to GUID -/// -/// \param[in ] lpszGuid String with GUID -/// \param[out] lpGuid GUID to store the result to -/// \param[out] lpszGuidEnd If non-NULL the pointer to the end of parsed GUID within `lpszGuid` is returned -/// -/// \returns -/// - `TRUE` if GUID successfuly parsed; -/// - `FALSE` otherwise. -/// -BOOL WINSTD_API StringToGuidW(_In_z_ LPCWSTR lpszGuid, _Out_ LPGUID lpGuid, _Out_opt_ LPCWSTR *lpszGuidEnd = NULL); -/// @copydoc StringToGuidW() -#ifdef _UNICODE -#define StringToGuid StringToGuidW -#else -#define StringToGuid StringToGuidA -#endif - -/// -/// Queries for a string value in the registry and stores it in a std::string string. -/// -/// `REG_EXPAND_SZ` are expanded using `ExpandEnvironmentStrings()` before storing to sValue. -/// -/// \param[in ] hReg A handle to an open registry key. The key must have been opened with the KEY_QUERY_VALUE access right. -/// \param[in ] pszName The name of the registry value. If lpValueName is NULL or an empty string, "", the function retrieves the type and data for the key's unnamed or default value, if any. -/// \param[out] sValue String to store the value to -/// -/// \return -/// - `ERROR_SUCCESS` when query succeeds; -/// - `ERROR_INVALID_DATA` when the registy value type is not `REG_SZ`, `REG_MULTI_SZ`, or `REG_EXPAND_SZ`; -/// - `ERROR_OUTOFMEMORY` when the memory allocation for the sValue buffer fails; -/// - Error code when query fails. See `RegQueryValueEx()` for the list of error codes. -/// -/// \sa [RegQueryValueEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724911.aspx) -/// \sa [ExpandEnvironmentStrings function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724265.aspx) -/// -template inline LSTATUS RegQueryStringValue(_In_ HKEY hReg, _In_z_ LPCSTR pszName, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sValue); - -/// -/// Queries for a string value in the registry and stores it in a std::wstring string. -/// -/// `REG_EXPAND_SZ` are expanded using `ExpandEnvironmentStrings()` before storing to sValue. -/// -/// \param[in ] hReg A handle to an open registry key. The key must have been opened with the KEY_QUERY_VALUE access right. -/// \param[in ] pszName The name of the registry value. If lpValueName is NULL or an empty string, "", the function retrieves the type and data for the key's unnamed or default value, if any. -/// \param[out] sValue String to store the value to -/// -/// \return -/// - `ERROR_SUCCESS` when query succeeds; -/// - `ERROR_INVALID_DATA` when the registy value type is not `REG_SZ`, `REG_MULTI_SZ`, or `REG_EXPAND_SZ`; -/// - `ERROR_OUTOFMEMORY` when the memory allocation for the sValue buffer fails; -/// - Error code when query fails. See `RegQueryValueEx()` for the list of error codes. -/// -/// \sa [RegQueryValueEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724911.aspx) -/// \sa [ExpandEnvironmentStrings function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724265.aspx) -/// -template inline LSTATUS RegQueryStringValue(_In_ HKEY hReg, _In_z_ LPCWSTR pszName, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sValue); - -/// @copydoc RegQueryValueExW() -template inline LSTATUS RegQueryValueExA(_In_ HKEY hKey, _In_opt_ LPCSTR lpValueName, __reserved LPDWORD lpReserved, _Out_opt_ LPDWORD lpType, _Out_ std::vector<_Ty, _Ax> &aData); - -/// -/// 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. -/// -/// \sa [RegQueryValueEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724911.aspx) -/// -template inline LSTATUS RegQueryValueExW(_In_ HKEY hKey, _In_opt_ LPCWSTR lpValueName, __reserved LPDWORD lpReserved, _Out_opt_ LPDWORD lpType, _Out_ std::vector<_Ty, _Ax> &aData); - -#if _WIN32_WINNT >= _WIN32_WINNT_VISTA - -/// @copydoc RegLoadMUIStringW() -template inline LSTATUS RegLoadMUIStringA(_In_ HKEY hKey, _In_opt_ LPCSTR pszValue, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sOut, _In_ DWORD Flags, _In_opt_ LPCSTR pszDirectory); - -/// -/// Loads the specified string from the specified key and subkey, and stores it in a std::wstring string. -/// -/// \sa [RegLoadMUIString function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724890.aspx) -/// -template inline LSTATUS RegLoadMUIStringW(_In_ HKEY hKey, _In_opt_ LPCWSTR pszValue, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sOut, _In_ DWORD Flags, _In_opt_ LPCWSTR pszDirectory); - -#endif - -/// -/// Maps a UTF-16 (wide character) string to a std::string. The new character string is not necessarily from a multibyte character set. -/// -/// \sa [WideCharToMultiByte function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd374130.aspx) -/// -template inline int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cchWideChar) LPCWSTR lpWideCharStr, _In_ int cchWideChar, _Out_ std::basic_string &sMultiByteStr, _In_opt_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar); - -/// -/// Maps a UTF-16 (wide character) string to a std::string. The new character string is not necessarily from a multibyte character set. -/// -/// \sa [WideCharToMultiByte function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd374130.aspx) -/// -template inline int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_ std::basic_string sWideCharStr, _Out_ std::basic_string &sMultiByteStr, _In_opt_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar); - -/// -/// Maps a character string to a UTF-16 (wide character) std::wstring. The character string is not necessarily from a multibyte character set. -/// -/// \sa [MultiByteToWideChar function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd319072.aspx) -/// -template inline int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cbMultiByte) LPCSTR lpMultiByteStr, _In_ int cbMultiByte, _Out_ std::basic_string &sWideCharStr); - -/// -/// Maps a character string to a UTF-16 (wide character) std::wstring. The character string is not necessarily from a multibyte character set. -/// -/// \sa [MultiByteToWideChar function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd319072.aspx) -/// -template inline int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_ std::basic_string sMultiByteStr, _Out_ std::basic_string &sWideCharStr); - -/// @copydoc LoadStringW -template inline int WINAPI LoadStringA(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_ std::basic_string &sBuffer); - -/// -/// Loads a string resource from the executable file associated with a specified module. -/// -/// \sa [LoadString function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms647486.aspx) -/// -template inline int WINAPI LoadStringW(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_ std::basic_string &sBuffer); - -/// -/// Formats and sends a string to the debugger for display. -/// -/// \sa [OutputDebugString function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363362.aspx) -/// -inline VOID OutputDebugStrV(_In_ LPCSTR lpOutputString, _In_ va_list 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) -/// -inline VOID OutputDebugStrV(_In_ LPCWSTR lpOutputString, _In_ va_list 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) -/// -inline VOID OutputDebugStr(_In_ LPCSTR lpOutputString, ...); - -/// -/// Formats and sends a string to the debugger for display. -/// -/// \sa [OutputDebugString function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363362.aspx) -/// -inline VOID OutputDebugStr(_In_ LPCWSTR lpOutputString, ...); - -/// @copydoc GetDateFormatW() -template inline int GetDateFormatA(_In_ LCID Locale, _In_ DWORD dwFlags, _In_opt_ const SYSTEMTIME *lpDate, _In_opt_ LPCSTR lpFormat, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sDate); - -/// -/// 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. -/// -/// \sa [GetDateFormat function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd318086.aspx) -/// -template inline int GetDateFormatW(_In_ LCID Locale, _In_ DWORD dwFlags, _In_opt_ const SYSTEMTIME *lpDate, _In_opt_ LPCWSTR lpFormat, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sDate); - -/// @copydoc LookupAccountSidW() -template inline BOOL LookupAccountSidA(_In_opt_ LPCSTR lpSystemName, _In_ PSID lpSid, _Out_opt_ std::basic_string<_Elem, _Traits, _Ax> *sName, _Out_opt_ std::basic_string<_Elem, _Traits, _Ax> *sReferencedDomainName, _Out_ PSID_NAME_USE peUse); - -/// -/// Retrieves the name of the account for this SID and the name of the first domain on which this SID is found. -/// -/// \sa [LookupAccountSid function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379166.aspx) -/// -template inline BOOL LookupAccountSidW(_In_opt_ LPCWSTR lpSystemName, _In_ PSID lpSid, _Out_opt_ std::basic_string<_Elem, _Traits, _Ax> *sName, _Out_opt_ std::basic_string<_Elem, _Traits, _Ax> *sReferencedDomainName, _Out_ PSID_NAME_USE peUse); - -/// -/// Retrieves a specified type of information about an access token. The calling process must have appropriate access rights to obtain the information. -/// -/// \sa [GetTokenInformation function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa446671.aspx) -/// -template inline BOOL GetTokenInformation(_In_ HANDLE TokenHandle, _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, _Out_ std::unique_ptr<_Ty> &TokenInformation); - -/// @} - -#pragma once - - -namespace winstd -{ - /// \addtogroup WinStdWinAPI - /// @{ - - /// - /// Windows HANDLE wrapper class - /// - class WINSTD_API win_handle : public handle - { - HANDLE_IMPL(win_handle) - - public: - /// - /// Closes an open object handle. - /// - /// \sa [CloseHandle function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724211.aspx) - /// - virtual ~win_handle(); - - protected: - /// - /// Closes an open object handle. - /// - /// \sa [CloseHandle function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724211.aspx) - /// - virtual void free_internal(); - }; - - - /// - /// Module handle wrapper - /// - class WINSTD_API library : public handle - { - HANDLE_IMPL(library) - - public: - /// - /// Frees the module. - /// - /// \sa [FreeLibrary function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms683152.aspx) - /// - virtual ~library(); - - /// - /// Loads the specified module into the address space of the calling process. - /// - /// \sa [LoadLibraryEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179.aspx) - /// - /// \return - /// - \c true when succeeds; - /// - \c false when fails. Use `GetLastError()` for failure reason. - /// - inline bool load(_In_ LPCTSTR lpFileName, __reserved handle_type hFile, _In_ DWORD dwFlags) - { - handle_type h = LoadLibraryEx(lpFileName, hFile, dwFlags); - if (h) { - attach(h); - return true; - } else - return false; - } - - protected: - /// - /// Frees the module. - /// - /// \sa [FreeLibrary function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms683152.aspx) - /// - virtual void free_internal(); - }; - - - /// - /// Process handle wrapper - /// - class WINSTD_API process : public win_handle - { - public: - /// - /// Opens process handle. - /// - /// \sa [OpenProcess function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684320.aspx) - /// - /// \return - /// - \c true when succeeds; - /// - \c false when fails. Use `GetLastError()` for failure reason. - /// - inline bool open(_In_ DWORD dwDesiredAccess, _In_ BOOL bInheritHandle, _In_ DWORD dwProcessId) - { - handle_type h = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId); - if (h) { - attach(h); - return true; - } else - return false; - } - }; - - - /// - /// File handle wrapper - /// - class WINSTD_API file : public win_handle - { - public: - /// - /// Opens file handle. - /// - /// \sa [CreateFile function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx) - /// - /// \return - /// - \c true when succeeds; - /// - \c false when fails. Use `GetLastError()` for failure reason. - /// - inline bool create(_In_ LPCTSTR lpFileName, _In_ DWORD dwDesiredAccess, _In_ DWORD dwShareMode, _In_ DWORD dwCreationDisposition, _In_opt_ DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes = NULL, _In_opt_ HANDLE hTemplateFile = NULL) - { - handle_type h = CreateFile(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); - if (h) { - attach(h); - return true; - } else - return false; - } - }; - - - /// - /// Heap handle wrapper - /// - class WINSTD_API heap : public handle - { - HANDLE_IMPL(heap) - - public: - /// - /// Destroys the heap. - /// - /// \sa [HeapDestroy function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa366700.aspx) - /// - virtual ~heap(); - - /// - /// Creates the heap. - /// - /// \sa [HeapCreate function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa366599.aspx) - /// - /// \return - /// - \c true when succeeds; - /// - \c false when fails. Use `GetLastError()` for failure reason. - /// - inline bool create(_In_ DWORD flOptions, _In_ SIZE_T dwInitialSize, _In_ SIZE_T dwMaximumSize) - { - handle_type h = HeapCreate(flOptions, dwInitialSize, dwMaximumSize); - if (h) { - attach(h); - return true; - } else - return false; - } - - /// - /// Enumerates allocated heap blocks using `OutputDebugString()` - /// - /// \returns - /// - `true` if any blocks found; - /// - `false` otherwise. - /// - bool enumerate(); - - protected: - /// - /// Destroys the heap. - /// - /// \sa [HeapDestroy function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa366700.aspx) - /// - virtual void free_internal(); - }; - - - /// - /// HeapAlloc allocator - /// - template - class heap_allocator - { - public: - typedef typename _Ty value_type; ///< A type that is managed by the allocator - - typedef _Ty *pointer; ///< A type that provides a pointer to the type of object managed by the allocator - typedef _Ty& reference; ///< A type that provides a reference to the type of object managed by the allocator - typedef const _Ty *const_pointer; ///< A type that provides a constant pointer to the type of object managed by the allocator - typedef const _Ty& const_reference; ///< A type that provides a constant reference to type of object managed by the allocator - - typedef SIZE_T size_type; ///< An unsigned integral type that can represent the length of any sequence that an object of template class `heap_allocator` can allocate - typedef ptrdiff_t difference_type; ///< A signed integral type that can represent the difference between values of pointers to the type of object managed by the allocator - - /// - /// A structure that enables an allocator for objects of one type to allocate storage for objects of another type. - /// - template - struct rebind - { - typedef heap_allocator<_Other> other; ///< Other allocator type - }; - - public: - /// - /// Constructs allocator - /// - /// \param[in] heap Handle to existing heap - /// - inline heap_allocator(_In_ HANDLE heap) : m_heap(heap) - { - } - - /// - /// Constructs allocator from another type - /// - /// \param[in] other Another allocator of the heap_allocator kind - /// - template - inline heap_allocator(_In_ const heap_allocator<_Other> &other) : m_heap(other.m_heap) - { - } - - /// - /// Allocates a new memory block - /// - /// \param[in] count Number of elements - /// - /// \returns Pointer to new memory block - /// - inline pointer allocate(_In_ size_type count) - { - assert(m_heap); - return (pointer)HeapAlloc(m_heap, 0, count * sizeof(_Ty)); - } - - /// - /// Frees memory block - /// - /// \param[in] ptr Pointer to memory block - /// \param[in] size Size of memory block (in bytes) - /// - inline void deallocate(_In_ pointer ptr, _In_ size_type size) - { - UNREFERENCED_PARAMETER(size); - assert(m_heap); - HeapFree(m_heap, 0, ptr); - } - - /// - /// Calls copying constructor for the element - /// - /// \param[in] ptr Pointer to memory block - /// \param[in] val Source element - /// - inline void construct(_Inout_ pointer ptr, _In_ const _Ty& val) - { - ::new ((void*)ptr) _Ty(val); - } - - /// - /// Calls moving constructor for the element - /// - /// \param[in] ptr Pointer to memory block - /// \param[in] val Source element - /// - inline void construct(_Inout_ pointer ptr, _Inout_ _Ty&& val) - { - ::new ((void*)ptr) _Ty(std::forward<_Ty>(val)); - } - - /// - /// Calls destructor for the element - /// - /// \param[in] ptr Pointer to memory block - /// - inline void destroy(_Inout_ pointer ptr) - { - ptr->_Ty::~_Ty(); - } - - /// - /// Returns maximum memory block size - /// - inline size_type max_size() const - { - return (SIZE_T)-1; - } - - public: - HANDLE m_heap; ///< Heap handle - }; - - - /// - /// Activates given activation context in constructor and deactivates it in destructor - /// - class WINSTD_API actctx_activator - { - public: - /// - /// Construct the activator and activates the given activation context - /// - /// \param[in] hActCtx Activation context - /// - /// \sa [ActivateActCtx function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa374151.aspx) - /// - actctx_activator(_In_ HANDLE hActCtx); - - /// - /// Deactivates activation context and destructs the activator - /// - /// \sa [DeactivateActCtx function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa375140.aspx) - /// - virtual ~actctx_activator(); - - protected: - ULONG_PTR m_cookie; ///< Cookie for context deactivation - }; - - - /// - /// Lets the calling thread impersonate the security context of a logged-on user - /// - class WINSTD_API user_impersonator - { - public: - /// - /// Construct the impersonator and impersonates the given user - /// - /// \param[in] hToken A handle to a primary or impersonation access token that represents a logged-on user - /// - /// \sa [ImpersonateLoggedOnUser function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa378612.aspx) - /// - user_impersonator(_In_ HANDLE hToken); - - /// - /// Reverts to current user and destructs the impersonator - /// - /// \sa [RevertToSelf function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379317.aspx) - /// - virtual ~user_impersonator(); - - protected: - BOOL m_cookie; ///< Did impersonation succeed? - }; - - - /// - /// Memory in virtual address space of a process handle wrapper - /// - class WINSTD_API vmemory : public handle - { - WINSTD_NONCOPYABLE(vmemory) - - public: - /// - /// Initializes a new class instance with the memory handle set to NULL. - /// - inline vmemory() : m_proc(NULL) - { - } - - /// - /// Initializes a new class instance with an already available object handle. - /// - /// \param[in] proc Handle of process the memory belongs to - /// \param[in] h Initial object handle value - /// - inline vmemory(_In_opt_ handle_type h, _In_ HANDLE proc) : - m_proc(proc), - handle(h) - { - } - - /// - /// Move constructor - /// - /// \param[inout] h A rvalue reference of another object - /// - inline vmemory(_Inout_ vmemory &&h) : - m_proc(std::move(h.m_proc)), - handle(std::move(h)) - { - } - - /// - /// Frees the memory. - /// - /// \sa [VirtualFreeEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa366894.aspx) - /// - virtual ~vmemory(); - - /// - /// Move assignment - /// - /// \param[inout] other A rvalue reference of another object - /// - inline vmemory& operator=(_Inout_ vmemory &&other) - { - if (this != std::addressof(other)) { - (handle&&)*this = std::move(other); - m_proc = std::move(other.m_proc); - } - return *this; - } - - /// - /// Sets a new memory handle for the class - /// - /// When the current object handle of the class is non-NULL, the object is destroyed first. - /// - /// \param[in] proc Handle of process the memory belongs to - /// \param[in] h Initial object handle value - /// - inline void attach(_In_ HANDLE proc, _In_opt_ handle_type h) - { - m_proc = proc; - if (m_h) - free_internal(); - m_h = h; - } - - /// - /// Reserves, commits, or changes the state of a region of memory within the virtual address space of a specified process. The function initializes the memory it allocates to zero. - /// - /// \sa [VirtualAllocEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa366890.aspx) - /// - /// \return - /// - \c true when succeeds; - /// - \c false when fails. Use `GetLastError()` for failure reason. - /// - inline bool alloc( - _In_ HANDLE hProcess, - _In_opt_ LPVOID lpAddress, - _In_ SIZE_T dwSize, - _In_ DWORD flAllocationType, - _In_ DWORD flProtect) - { - handle_type h = VirtualAllocEx(hProcess, lpAddress, dwSize, flAllocationType, flProtect); - if (h) { - attach(hProcess, h); - return true; - } else - return false; - } - - protected: - /// - /// Frees the memory. - /// - /// \sa [VirtualFreeEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa366894.aspx) - /// - virtual void free_internal(); - - protected: - HANDLE m_proc; ///< Handle of memory's process - }; - - - /// - /// Registry wrapper class - /// - class WINSTD_API reg_key : public handle - { - HANDLE_IMPL(reg_key) - - public: - /// - /// Closes a handle to the registry key. - /// - /// \sa [RegCloseKey function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724837.aspx) - /// - virtual ~reg_key(); - - /// - /// Creates the specified registry key. If the key already exists, the function opens it. - /// - /// \return - /// - true when creation succeeds; - /// - false when creation fails. For extended error information, call `GetLastError()`. - /// - /// \sa [RegCreateKeyEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724844.aspx) - /// - inline bool create( - _In_ HKEY hKey, - _In_ LPCTSTR lpSubKey, - _In_opt_ LPTSTR lpClass, - _In_ DWORD dwOptions, - _In_ REGSAM samDesired, - _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes = NULL, - _Out_opt_ LPDWORD lpdwDisposition = NULL) - { - handle_type h; - LSTATUS s = RegCreateKeyEx(hKey, lpSubKey, 0, lpClass, dwOptions, samDesired, lpSecurityAttributes, &h, lpdwDisposition); - if (s == ERROR_SUCCESS) { - attach(h); - return true; - } else { - SetLastError(s); - return false; - } - } - - /// - /// Opens the specified registry key. - /// - /// \return - /// - true when creation succeeds; - /// - false when creation fails. For extended error information, call `GetLastError()`. - /// - /// \sa [RegOpenKeyEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724897.aspx) - /// - inline bool open( - _In_ HKEY hKey, - _In_opt_ LPCTSTR lpSubKey, - _In_ DWORD ulOptions, - _In_ REGSAM samDesired) - { - handle_type h; - LONG s = RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired, &h); - if (s == ERROR_SUCCESS) { - attach(h); - return true; - } else { - SetLastError(s); - return false; - } - } - - protected: - /// - /// Closes a handle to the registry key. - /// - /// \sa [RegCloseKey function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724837.aspx) - /// - virtual void free_internal(); - }; - - - /// - /// SID wrapper class - /// - class WINSTD_API security_id : public handle - { - HANDLE_IMPL(security_id) - - public: - /// - /// Closes a handle to the SID. - /// - /// \sa [FreeSid function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa446631.aspx) - /// - virtual ~security_id(); - - protected: - /// - /// Closes a handle to the SID. - /// - /// \sa [FreeSid function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa446631.aspx) - /// - virtual void free_internal(); - }; - - /// @} -} - - -template -inline DWORD GetModuleFileNameA(_In_opt_ HMODULE hModule, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sValue) -{ - assert(0); // TODO: Test this code. - - _Elem szBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem)]; - - // Try with stack buffer first. - DWORD dwResult = ::GetModuleFileNameA(hModule, szBuffer, _countof(szBuffer)); - if (dwResult < _countof(szBuffer)) { - // Copy from stack. - sValue.assign(szBuffer, dwResult); - return dwResult; - } else { - for (DWORD dwCapacity = 2*WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem);; dwCapacity *= 2) { - // Allocate on heap and retry. - std::unique_ptr<_Elem[]> szBuffer(new _Elem[dwCapacity]); - dwResult = ::GetModuleFileNameA(hModule, szBuffer.get(), dwCapacity); - if (dwResult < dwCapacity) { - sValue.assign(szBuffer.get(), dwResult); - return dwResult; - } - } - } -} - - -template -inline DWORD GetModuleFileNameW(_In_opt_ HMODULE hModule, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sValue) -{ - _Elem szBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem)]; - - // Try with stack buffer first. - DWORD dwResult = ::GetModuleFileNameW(hModule, szBuffer, _countof(szBuffer)); - if (dwResult < _countof(szBuffer)) { - // Copy from stack. - sValue.assign(szBuffer, dwResult); - return dwResult; - } else { - for (DWORD dwCapacity = 2*WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem);; dwCapacity *= 2) { - // Allocate on heap and retry. - std::unique_ptr<_Elem[]> szBuffer(new _Elem[dwCapacity]); - dwResult = ::GetModuleFileNameW(hModule, szBuffer.get(), dwCapacity); - if (dwResult < dwCapacity) { - sValue.assign(szBuffer.get(), dwResult); - return dwResult; - } - } - } -} - - -template -inline int GetWindowTextA(_In_ HWND hWnd, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sValue) -{ - 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(_Elem)) { - // Read string data to stack. - _Elem szBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem)]; - 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<_Elem[]> szBuffer(new _Elem[++iResult]); - iResult = ::GetWindowTextA(hWnd, szBuffer.get(), iResult); - sValue.assign(szBuffer.get(), iResult); - } - return iResult; - } - - sValue.clear(); - return 0; -} - - -template -inline int GetWindowTextW(_In_ HWND hWnd, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sValue) -{ - 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(_Elem)) { - // Read string data to stack. - _Elem szBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem)]; - 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<_Elem[]> szBuffer(new _Elem[++iResult]); - iResult = ::GetWindowTextW(hWnd, szBuffer.get(), iResult); - sValue.assign(szBuffer.get(), iResult); - } - return iResult; - } - - sValue.clear(); - return 0; -} - - -template -inline BOOL GetFileVersionInfoA(_In_ LPCSTR lptstrFilename, __reserved DWORD dwHandle, _Out_ std::vector<_Ty, _Ax> &aValue) -{ - 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 -inline BOOL GetFileVersionInfoW(_In_ LPCWSTR lptstrFilename, __reserved DWORD dwHandle, _Out_ std::vector<_Ty, _Ax> &aValue) -{ - 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 -inline DWORD ExpandEnvironmentStringsA(_In_ LPCSTR lpSrc, std::basic_string<_Elem, _Traits, _Ax> &sValue) -{ - assert(0); // TODO: Test this code. - - for (DWORD dwSizeOut = (DWORD)strlen(lpSrc) + 0x100;;) { - DWORD dwSizeIn = dwSizeOut; - std::unique_ptr<_Elem[]> szBuffer(new _Elem[dwSizeIn + 2]); // Note: ANSI version requires one extra char. - dwSizeOut = ::ExpandEnvironmentStringsA(lpSrc, szBuffer.get(), dwSizeIn); - if (dwSizeOut == 0) { - // Error. - break; - } else if (dwSizeOut <= dwSizeIn) { - // The buffer was sufficient. - sValue.assign(szBuffer.get(), dwSizeOut); - return dwSizeOut; - } - } - - sValue.clear(); - return 0; -} - - -template -inline DWORD ExpandEnvironmentStringsW(_In_ LPCWSTR lpSrc, std::basic_string<_Elem, _Traits, _Ax> &sValue) -{ - assert(0); // TODO: Test this code. - - for (DWORD dwSizeOut = (DWORD)wcslen(lpSrc) + 0x100;;) { - DWORD dwSizeIn = dwSizeOut; - std::unique_ptr<_Elem[]> szBuffer(new _Elem[dwSizeIn + 1]); - dwSizeOut = ::ExpandEnvironmentStringsW(lpSrc, szBuffer.get(), dwSizeIn); - if (dwSizeOut == 0) { - // Error. - break; - } else if (dwSizeOut <= dwSizeIn) { - // The buffer was sufficient. - sValue.assign(szBuffer.get(), dwSizeOut); - return dwSizeOut; - } - } - - sValue.clear(); - return 0; -} - - -template -inline VOID GuidToStringA(_In_ LPCGUID lpGuid, _Out_ std::basic_string<_Elem, _Traits, _Ax> &str) -{ - 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 -inline VOID GuidToStringW(_In_ LPCGUID lpGuid, _Out_ std::basic_string<_Elem, _Traits, _Ax> &str) -{ - 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]); -} - - -template -inline LSTATUS RegQueryStringValue(_In_ HKEY hReg, _In_z_ LPCSTR pszName, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sValue) -{ - 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 - sValue.clear(); - } 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 - sValue.clear(); - } else { - // The value is not a string type. - lResult = ERROR_INVALID_DATA; - } - } - - return lResult; -} - - -template -inline LSTATUS RegQueryStringValue(_In_ HKEY hReg, _In_z_ LPCWSTR pszName, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sValue) -{ - 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 - sValue.clear(); - } 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 - sValue.clear(); - } else { - // The value is not a string type. - lResult = ERROR_INVALID_DATA; - } - } - - return lResult; -} - - -template -inline LSTATUS RegQueryValueExA(_In_ HKEY hKey, _In_opt_ LPCSTR lpValueName, __reserved LPDWORD lpReserved, _Out_opt_ LPDWORD lpType, _Out_ std::vector<_Ty, _Ax> &aData) -{ - LSTATUS lResult; - BYTE aStackBuffer[WINSTD_STACK_BUFFER_BYTES]; - DWORD dwSize = sizeof(aStackBuffer); - - // Try with stack buffer first. - lResult = RegQueryValueExA(hKey, lpValueName, lpReserved, NULL, 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)); - if ((lResult = RegQueryValueExA(hKey, lpValueName, lpReserved, lpType, aData.data(), &dwSize)) != ERROR_SUCCESS) - aData.clear(); - } - - return lResult; -} - - -template -inline LSTATUS RegQueryValueExW(_In_ HKEY hKey, _In_opt_ LPCWSTR lpValueName, __reserved LPDWORD lpReserved, _Out_opt_ LPDWORD lpType, _Out_ std::vector<_Ty, _Ax> &aData) -{ - LSTATUS lResult; - BYTE aStackBuffer[WINSTD_STACK_BUFFER_BYTES]; - DWORD dwSize = sizeof(aStackBuffer); - - // Try with stack buffer first. - lResult = RegQueryValueExW(hKey, lpValueName, lpReserved, NULL, 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)); - if ((lResult = RegQueryValueExW(hKey, lpValueName, lpReserved, lpType, aData.data(), &dwSize)) != ERROR_SUCCESS) - aData.clear(); - } - - return lResult; -} - - -#if _WIN32_WINNT >= _WIN32_WINNT_VISTA - -template -inline LSTATUS RegLoadMUIStringA(_In_ HKEY hKey, _In_opt_ LPCSTR pszValue, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sOut, _In_ DWORD Flags, _In_opt_ LPCSTR pszDirectory) -{ - // 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 -inline LSTATUS RegLoadMUIStringW(_In_ HKEY hKey, _In_opt_ LPCWSTR pszValue, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sOut, _In_ DWORD Flags, _In_opt_ LPCWSTR pszDirectory) -{ - LSTATUS lResult; - _Elem szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem)]; - 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(_Elem))); - } else if (lResult == ERROR_MORE_DATA) { - // Allocate buffer on heap and retry. - std::unique_ptr<_Elem[]> szBuffer(new _Elem[(dwSize + sizeof(_Elem) - 1)/sizeof(_Elem)]); - sOut.assign(szBuffer.get(), (lResult = RegLoadMUIStringW(hKey, pszValue, szBuffer.get(), dwSize, &dwSize, Flags, pszDirectory)) == ERROR_SUCCESS ? wcsnlen(szBuffer.get(), dwSize/sizeof(_Elem)) : 0); - } - - return lResult; -} - -#endif - - -template -inline int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cchWideChar) LPCWSTR lpWideCharStr, _In_ int cchWideChar, _Out_ std::basic_string &sMultiByteStr, _In_opt_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) -{ - 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) : 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) : cch - 1); - } - - return cch; -} - - -template -inline int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_ std::basic_string sWideCharStr, _Out_ std::basic_string &sMultiByteStr, _In_opt_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) -{ - 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 -inline int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cbMultiByte) LPCSTR lpMultiByteStr, _In_ int cbMultiByte, _Out_ std::basic_string &sWideCharStr) -{ - 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) : 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) : cch - 1); - } - - return cch; -} - - -template inline int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_ std::basic_string sMultiByteStr, _Out_ std::basic_string &sWideCharStr) -{ - 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 -inline int WINAPI LoadStringA(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_ std::basic_string &sBuffer) -{ - // 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 -inline int WINAPI LoadStringW(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_ std::basic_string &sBuffer) -{ - // 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; -} - - -inline VOID OutputDebugStrV(_In_ LPCSTR lpOutputString, _In_ va_list arg) -{ - std::string str; - vsprintf(str, lpOutputString, arg); - OutputDebugStringA(str.c_str()); -} - - -inline VOID OutputDebugStrV(_In_ LPCWSTR lpOutputString, _In_ va_list arg) -{ - std::wstring str; - vsprintf(str, lpOutputString, arg); - OutputDebugStringW(str.c_str()); -} - - -inline VOID OutputDebugStr(_In_ LPCSTR lpOutputString, ...) -{ - va_list arg; - va_start(arg, lpOutputString); - OutputDebugStrV(lpOutputString, arg); - va_end(arg); -} - - -inline VOID OutputDebugStr(_In_ LPCWSTR lpOutputString, ...) -{ - va_list arg; - va_start(arg, lpOutputString); - OutputDebugStrV(lpOutputString, arg); - va_end(arg); -} - - -template inline int GetDateFormatA(_In_ LCID Locale, _In_ DWORD dwFlags, _In_opt_ const SYSTEMTIME *lpDate, _In_opt_ LPCSTR lpFormat, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sDate) -{ - int iResult = GetDateFormatA(Locale, dwFlags, lpDate, lpFormat, NULL, 0); - if (iResult) { - // Allocate buffer on heap and retry. - std::unique_ptr<_Elem[]> szBuffer(new _Elem[iResult]); - iResult = GetDateFormatA(Locale, dwFlags, lpDate, lpFormat, szBuffer.get(), iResult); - sDate.assign(szBuffer.get(), iResult ? iResult - 1 : 0); - return iResult; - } - - return iResult; -} - - -template inline int GetDateFormatW(_In_ LCID Locale, _In_ DWORD dwFlags, _In_opt_ const SYSTEMTIME *lpDate, _In_opt_ LPCWSTR lpFormat, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sDate) -{ - int iResult = GetDateFormatW(Locale, dwFlags, lpDate, lpFormat, NULL, 0); - if (iResult) { - // Allocate buffer on heap and retry. - std::unique_ptr<_Elem[]> szBuffer(new _Elem[iResult]); - iResult = GetDateFormatW(Locale, dwFlags, lpDate, lpFormat, szBuffer.get(), iResult); - sDate.assign(szBuffer.get(), iResult ? iResult - 1 : 0); - return iResult; - } - - return iResult; -} - - -template -inline BOOL LookupAccountSidA(_In_opt_ LPCSTR lpSystemName, _In_ PSID lpSid, _Out_opt_ std::basic_string<_Elem, _Traits, _Ax> *sName, _Out_opt_ std::basic_string<_Elem, _Traits, _Ax> *sReferencedDomainName, _Out_ PSID_NAME_USE peUse) -{ - assert(0); // TODO: Test this code. - - DWORD dwNameLen = 0, dwRefDomainLen = 0; - - if (LookupAccountSidA(lpSystemName, lpSid, - NULL, sName ? &dwNameLen : NULL, - NULL, sReferencedDomainName ? &dwRefDomainLen : NULL, - 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<_Elem[]> bufName (new _Elem[dwNameLen ]); - std::unique_ptr<_Elem[]> bufRefDomain(new _Elem[dwRefDomainLen]); - if (LookupAccountSidA(lpSystemName, lpSid, - bufName .get(), sName ? &dwNameLen : NULL, - bufRefDomain.get(), sReferencedDomainName ? &dwRefDomainLen : NULL, - peUse)) - { - if (sName ) sName ->assign(bufName .get(), dwNameLen - 1); - if (sReferencedDomainName) sReferencedDomainName->assign(bufRefDomain.get(), dwRefDomainLen - 1); - return TRUE; - } - } - - return FALSE; -} - - -template -inline BOOL LookupAccountSidW(_In_opt_ LPCWSTR lpSystemName, _In_ PSID lpSid, _Out_opt_ std::basic_string<_Elem, _Traits, _Ax> *sName, _Out_opt_ std::basic_string<_Elem, _Traits, _Ax> *sReferencedDomainName, _Out_ PSID_NAME_USE peUse) -{ - assert(0); // TODO: Test this code. - - DWORD dwNameLen = 0, dwRefDomainLen = 0; - - if (LookupAccountSidW(lpSystemName, lpSid, - NULL, sName ? &dwNameLen : NULL, - NULL, sReferencedDomainName ? &dwRefDomainLen : NULL, - 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<_Elem[]> bufName (new _Elem[dwNameLen ]); - std::unique_ptr<_Elem[]> bufRefDomain(new _Elem[dwRefDomainLen]); - if (LookupAccountSidW(lpSystemName, lpSid, - bufName .get(), sName ? &dwNameLen : NULL, - bufRefDomain.get(), sReferencedDomainName ? &dwRefDomainLen : NULL, - peUse)) - { - if (sName ) sName ->assign(bufName .get(), dwNameLen - 1); - if (sReferencedDomainName) sReferencedDomainName->assign(bufRefDomain.get(), dwRefDomainLen - 1); - return TRUE; - } - } - - return FALSE; -} - - -template -inline BOOL GetTokenInformation(_In_ HANDLE TokenHandle, _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, _Out_ std::unique_ptr<_Ty> &TokenInformation) -{ - 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; -} +/* + Copyright 1991-2018 Amebis + Copyright 2016 GÉANT + + This file is part of WinStd. + + Setup is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Setup is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Setup. If not, see . +*/ + +/// +/// \defgroup WinStdWinAPI Windows API +/// Integrates WinStd classes with Microsoft Windows API +/// + +#include "Common.h" + +#include + +#include +#include + +namespace winstd +{ + class WINSTD_API win_handle; + class WINSTD_API library; + class WINSTD_API process; + class WINSTD_API file; + class WINSTD_API heap; + template class heap_allocator; + class WINSTD_API actctx_activator; + class WINSTD_API user_impersonator; + class WINSTD_API vmemory; + class WINSTD_API reg_key; + class WINSTD_API security_id; +} + + +/// \addtogroup WinStdWinAPI +/// @{ + +/// @copydoc GetModuleFileNameW() +template inline DWORD GetModuleFileNameA(_In_opt_ HMODULE hModule, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sValue); + +/// +/// Retrieves the fully qualified path for the file that contains the specified module and stores it in a std::wstring string. +/// +/// \sa [GetModuleFileName function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms683197.aspx) +/// +template inline DWORD GetModuleFileNameW(_In_opt_ HMODULE hModule, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sValue); + +/// @copydoc GetWindowTextW() +template inline int GetWindowTextA(_In_ HWND hWnd, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sValue); + +/// +/// Copies the text of the specified window's title bar (if it has one) into a std::wstring string. +/// +/// \sa [GetWindowText function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633520.aspx) +/// +template inline int GetWindowTextW(_In_ HWND hWnd, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sValue); + +/// @copydoc GetFileVersionInfoW() +template inline BOOL GetFileVersionInfoA(_In_ LPCSTR lptstrFilename, __reserved DWORD dwHandle, _Out_ std::vector<_Ty, _Ax> &aValue); + +/// +/// Retrieves version information for the specified file and stores it in a std::vector buffer. +/// +/// \sa [GetFileVersionInfo function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms647003.aspx) +/// +template inline BOOL GetFileVersionInfoW(_In_ LPCWSTR lptstrFilename, __reserved DWORD dwHandle, _Out_ std::vector<_Ty, _Ax> &aValue); + +/// @copydoc ExpandEnvironmentStringsW() +template inline DWORD ExpandEnvironmentStringsA(_In_ LPCSTR lpSrc, std::basic_string<_Elem, _Traits, _Ax> &sValue); + +/// +/// Expands environment-variable strings, replaces them with the values defined for the current user, and stores it in a std::wstring string. +/// +/// \sa [ExpandEnvironmentStrings function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724265.aspx) +/// +template inline DWORD ExpandEnvironmentStringsW(_In_ LPCWSTR lpSrc, std::basic_string<_Elem, _Traits, _Ax> &sValue); + +/// @copydoc GuidToStringW() +template inline VOID GuidToStringA(_In_ LPCGUID lpGuid, _Out_ std::basic_string<_Elem, _Traits, _Ax> &str); + +/// +/// Formats GUID and stores it in a std::wstring string. +/// +/// \param[in ] lpGuid Pointer to GUID +/// \param[out] str String to store the result to +/// +template inline VOID GuidToStringW(_In_ LPCGUID lpGuid, _Out_ std::basic_string<_Elem, _Traits, _Ax> &str); +/// @copydoc GuidToStringW() +#ifdef _UNICODE +#define GuidToString GuidToStringW +#else +#define GuidToString GuidToStringA +#endif + +/// @copydoc StringToGuidW() +_Success_(return) BOOL WINSTD_API StringToGuidA(_In_z_ LPCSTR lpszGuid, _Out_ LPGUID lpGuid, _Out_opt_ LPCSTR *lpszGuidEnd = NULL); + +/// +/// Parses string with GUID and stores it to GUID +/// +/// \param[in ] lpszGuid String with GUID +/// \param[out] lpGuid GUID to store the result to +/// \param[out] lpszGuidEnd If non-NULL the pointer to the end of parsed GUID within `lpszGuid` is returned +/// +/// \returns +/// - `TRUE` if GUID successfuly parsed; +/// - `FALSE` otherwise. +/// +_Success_(return) BOOL WINSTD_API StringToGuidW(_In_z_ LPCWSTR lpszGuid, _Out_ LPGUID lpGuid, _Out_opt_ LPCWSTR *lpszGuidEnd = NULL); +/// @copydoc StringToGuidW() +#ifdef _UNICODE +#define StringToGuid StringToGuidW +#else +#define StringToGuid StringToGuidA +#endif + +/// +/// Queries for a string value in the registry and stores it in a std::string string. +/// +/// `REG_EXPAND_SZ` are expanded using `ExpandEnvironmentStrings()` before storing to sValue. +/// +/// \param[in ] hReg A handle to an open registry key. The key must have been opened with the KEY_QUERY_VALUE access right. +/// \param[in ] pszName The name of the registry value. If lpValueName is NULL or an empty string, "", the function retrieves the type and data for the key's unnamed or default value, if any. +/// \param[out] sValue String to store the value to +/// +/// \return +/// - `ERROR_SUCCESS` when query succeeds; +/// - `ERROR_INVALID_DATA` when the registy value type is not `REG_SZ`, `REG_MULTI_SZ`, or `REG_EXPAND_SZ`; +/// - `ERROR_OUTOFMEMORY` when the memory allocation for the sValue buffer fails; +/// - Error code when query fails. See `RegQueryValueEx()` for the list of error codes. +/// +/// \sa [RegQueryValueEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724911.aspx) +/// \sa [ExpandEnvironmentStrings function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724265.aspx) +/// +template inline LSTATUS RegQueryStringValue(_In_ HKEY hReg, _In_z_ LPCSTR pszName, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sValue); + +/// +/// Queries for a string value in the registry and stores it in a std::wstring string. +/// +/// `REG_EXPAND_SZ` are expanded using `ExpandEnvironmentStrings()` before storing to sValue. +/// +/// \param[in ] hReg A handle to an open registry key. The key must have been opened with the KEY_QUERY_VALUE access right. +/// \param[in ] pszName The name of the registry value. If lpValueName is NULL or an empty string, "", the function retrieves the type and data for the key's unnamed or default value, if any. +/// \param[out] sValue String to store the value to +/// +/// \return +/// - `ERROR_SUCCESS` when query succeeds; +/// - `ERROR_INVALID_DATA` when the registy value type is not `REG_SZ`, `REG_MULTI_SZ`, or `REG_EXPAND_SZ`; +/// - `ERROR_OUTOFMEMORY` when the memory allocation for the sValue buffer fails; +/// - Error code when query fails. See `RegQueryValueEx()` for the list of error codes. +/// +/// \sa [RegQueryValueEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724911.aspx) +/// \sa [ExpandEnvironmentStrings function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724265.aspx) +/// +template inline LSTATUS RegQueryStringValue(_In_ HKEY hReg, _In_z_ LPCWSTR pszName, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sValue); + +/// @copydoc RegQueryValueExW() +template inline LSTATUS RegQueryValueExA(_In_ HKEY hKey, _In_opt_ LPCSTR lpValueName, __reserved LPDWORD lpReserved, _Out_opt_ LPDWORD lpType, _Out_ std::vector<_Ty, _Ax> &aData); + +/// +/// 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. +/// +/// \sa [RegQueryValueEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724911.aspx) +/// +template inline LSTATUS RegQueryValueExW(_In_ HKEY hKey, _In_opt_ LPCWSTR lpValueName, __reserved LPDWORD lpReserved, _Out_opt_ LPDWORD lpType, _Out_ std::vector<_Ty, _Ax> &aData); + +#if _WIN32_WINNT >= _WIN32_WINNT_VISTA + +/// @copydoc RegLoadMUIStringW() +template inline LSTATUS RegLoadMUIStringA(_In_ HKEY hKey, _In_opt_ LPCSTR pszValue, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sOut, _In_ DWORD Flags, _In_opt_ LPCSTR pszDirectory); + +/// +/// Loads the specified string from the specified key and subkey, and stores it in a std::wstring string. +/// +/// \sa [RegLoadMUIString function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724890.aspx) +/// +template inline LSTATUS RegLoadMUIStringW(_In_ HKEY hKey, _In_opt_ LPCWSTR pszValue, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sOut, _In_ DWORD Flags, _In_opt_ LPCWSTR pszDirectory); + +#endif + +/// +/// Maps a UTF-16 (wide character) string to a std::string. The new character string is not necessarily from a multibyte character set. +/// +/// \sa [WideCharToMultiByte function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd374130.aspx) +/// +template inline int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cchWideChar) LPCWSTR lpWideCharStr, _In_ int cchWideChar, _Out_ std::basic_string &sMultiByteStr, _In_opt_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar); + +/// +/// Maps a UTF-16 (wide character) string to a std::string. The new character string is not necessarily from a multibyte character set. +/// +/// \sa [WideCharToMultiByte function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd374130.aspx) +/// +template inline int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_ std::basic_string sWideCharStr, _Out_ std::basic_string &sMultiByteStr, _In_opt_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar); + +/// +/// Maps a character string to a UTF-16 (wide character) std::wstring. The character string is not necessarily from a multibyte character set. +/// +/// \sa [MultiByteToWideChar function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd319072.aspx) +/// +template inline int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cbMultiByte) LPCSTR lpMultiByteStr, _In_ int cbMultiByte, _Out_ std::basic_string &sWideCharStr); + +/// +/// Maps a character string to a UTF-16 (wide character) std::wstring. The character string is not necessarily from a multibyte character set. +/// +/// \sa [MultiByteToWideChar function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd319072.aspx) +/// +template inline int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_ std::basic_string sMultiByteStr, _Out_ std::basic_string &sWideCharStr); + +/// @copydoc LoadStringW +template inline int WINAPI LoadStringA(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_ std::basic_string &sBuffer); + +/// +/// Loads a string resource from the executable file associated with a specified module. +/// +/// \sa [LoadString function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms647486.aspx) +/// +template inline int WINAPI LoadStringW(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_ std::basic_string &sBuffer); + +/// +/// Formats and sends a string to the debugger for display. +/// +/// \sa [OutputDebugString function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363362.aspx) +/// +inline VOID OutputDebugStrV(_In_ LPCSTR lpOutputString, _In_ va_list 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) +/// +inline VOID OutputDebugStrV(_In_ LPCWSTR lpOutputString, _In_ va_list 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) +/// +inline VOID OutputDebugStr(_In_ LPCSTR lpOutputString, ...); + +/// +/// Formats and sends a string to the debugger for display. +/// +/// \sa [OutputDebugString function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363362.aspx) +/// +inline VOID OutputDebugStr(_In_ LPCWSTR lpOutputString, ...); + +/// @copydoc GetDateFormatW() +template inline int GetDateFormatA(_In_ LCID Locale, _In_ DWORD dwFlags, _In_opt_ const SYSTEMTIME *lpDate, _In_opt_ LPCSTR lpFormat, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sDate); + +/// +/// 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. +/// +/// \sa [GetDateFormat function](https://msdn.microsoft.com/en-us/library/windows/desktop/dd318086.aspx) +/// +template inline int GetDateFormatW(_In_ LCID Locale, _In_ DWORD dwFlags, _In_opt_ const SYSTEMTIME *lpDate, _In_opt_ LPCWSTR lpFormat, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sDate); + +/// @copydoc LookupAccountSidW() +template inline BOOL LookupAccountSidA(_In_opt_ LPCSTR lpSystemName, _In_ PSID lpSid, _Out_opt_ std::basic_string<_Elem, _Traits, _Ax> *sName, _Out_opt_ std::basic_string<_Elem, _Traits, _Ax> *sReferencedDomainName, _Out_ PSID_NAME_USE peUse); + +/// +/// Retrieves the name of the account for this SID and the name of the first domain on which this SID is found. +/// +/// \sa [LookupAccountSid function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379166.aspx) +/// +template inline BOOL LookupAccountSidW(_In_opt_ LPCWSTR lpSystemName, _In_ PSID lpSid, _Out_opt_ std::basic_string<_Elem, _Traits, _Ax> *sName, _Out_opt_ std::basic_string<_Elem, _Traits, _Ax> *sReferencedDomainName, _Out_ PSID_NAME_USE peUse); + +/// +/// Retrieves a specified type of information about an access token. The calling process must have appropriate access rights to obtain the information. +/// +/// \sa [GetTokenInformation function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa446671.aspx) +/// +template inline BOOL GetTokenInformation(_In_ HANDLE TokenHandle, _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, _Out_ std::unique_ptr<_Ty> &TokenInformation); + +/// @} + +#pragma once + + +namespace winstd +{ + /// \addtogroup WinStdWinAPI + /// @{ + + /// + /// Windows HANDLE wrapper class + /// + class WINSTD_API win_handle : public handle + { + HANDLE_IMPL(win_handle) + + public: + /// + /// Closes an open object handle. + /// + /// \sa [CloseHandle function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724211.aspx) + /// + virtual ~win_handle(); + + protected: + /// + /// Closes an open object handle. + /// + /// \sa [CloseHandle function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724211.aspx) + /// + virtual void free_internal(); + }; + + + /// + /// Module handle wrapper + /// + class WINSTD_API library : public handle + { + HANDLE_IMPL(library) + + public: + /// + /// Frees the module. + /// + /// \sa [FreeLibrary function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms683152.aspx) + /// + virtual ~library(); + + /// + /// Loads the specified module into the address space of the calling process. + /// + /// \sa [LoadLibraryEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179.aspx) + /// + /// \return + /// - \c true when succeeds; + /// - \c false when fails. Use `GetLastError()` for failure reason. + /// + inline bool load(_In_ LPCTSTR lpFileName, __reserved handle_type hFile, _In_ DWORD dwFlags) + { + handle_type h = LoadLibraryEx(lpFileName, hFile, dwFlags); + if (h) { + attach(h); + return true; + } else + return false; + } + + protected: + /// + /// Frees the module. + /// + /// \sa [FreeLibrary function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms683152.aspx) + /// + virtual void free_internal(); + }; + + + /// + /// Process handle wrapper + /// + class WINSTD_API process : public win_handle + { + public: + /// + /// Opens process handle. + /// + /// \sa [OpenProcess function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684320.aspx) + /// + /// \return + /// - \c true when succeeds; + /// - \c false when fails. Use `GetLastError()` for failure reason. + /// + inline bool open(_In_ DWORD dwDesiredAccess, _In_ BOOL bInheritHandle, _In_ DWORD dwProcessId) + { + handle_type h = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId); + if (h) { + attach(h); + return true; + } else + return false; + } + }; + + + /// + /// File handle wrapper + /// + class WINSTD_API file : public win_handle + { + public: + /// + /// Opens file handle. + /// + /// \sa [CreateFile function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx) + /// + /// \return + /// - \c true when succeeds; + /// - \c false when fails. Use `GetLastError()` for failure reason. + /// + inline bool create(_In_ LPCTSTR lpFileName, _In_ DWORD dwDesiredAccess, _In_ DWORD dwShareMode, _In_ DWORD dwCreationDisposition, _In_opt_ DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes = NULL, _In_opt_ HANDLE hTemplateFile = NULL) + { + handle_type h = CreateFile(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); + if (h) { + attach(h); + return true; + } else + return false; + } + }; + + + /// + /// Heap handle wrapper + /// + class WINSTD_API heap : public handle + { + HANDLE_IMPL(heap) + + public: + /// + /// Destroys the heap. + /// + /// \sa [HeapDestroy function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa366700.aspx) + /// + virtual ~heap(); + + /// + /// Creates the heap. + /// + /// \sa [HeapCreate function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa366599.aspx) + /// + /// \return + /// - \c true when succeeds; + /// - \c false when fails. Use `GetLastError()` for failure reason. + /// + inline bool create(_In_ DWORD flOptions, _In_ SIZE_T dwInitialSize, _In_ SIZE_T dwMaximumSize) + { + handle_type h = HeapCreate(flOptions, dwInitialSize, dwMaximumSize); + if (h) { + attach(h); + return true; + } else + return false; + } + + /// + /// Enumerates allocated heap blocks using `OutputDebugString()` + /// + /// \returns + /// - `true` if any blocks found; + /// - `false` otherwise. + /// + bool enumerate(); + + protected: + /// + /// Destroys the heap. + /// + /// \sa [HeapDestroy function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa366700.aspx) + /// + virtual void free_internal(); + }; + + + /// + /// HeapAlloc allocator + /// + template + class heap_allocator + { + public: + typedef typename _Ty value_type; ///< A type that is managed by the allocator + + typedef _Ty *pointer; ///< A type that provides a pointer to the type of object managed by the allocator + typedef _Ty& reference; ///< A type that provides a reference to the type of object managed by the allocator + typedef const _Ty *const_pointer; ///< A type that provides a constant pointer to the type of object managed by the allocator + typedef const _Ty& const_reference; ///< A type that provides a constant reference to type of object managed by the allocator + + typedef SIZE_T size_type; ///< An unsigned integral type that can represent the length of any sequence that an object of template class `heap_allocator` can allocate + typedef ptrdiff_t difference_type; ///< A signed integral type that can represent the difference between values of pointers to the type of object managed by the allocator + + /// + /// A structure that enables an allocator for objects of one type to allocate storage for objects of another type. + /// + template + struct rebind + { + typedef heap_allocator<_Other> other; ///< Other allocator type + }; + + public: + /// + /// Constructs allocator + /// + /// \param[in] heap Handle to existing heap + /// + inline heap_allocator(_In_ HANDLE heap) : m_heap(heap) + { + } + + /// + /// Constructs allocator from another type + /// + /// \param[in] other Another allocator of the heap_allocator kind + /// + template + inline heap_allocator(_In_ const heap_allocator<_Other> &other) : m_heap(other.m_heap) + { + } + + /// + /// Allocates a new memory block + /// + /// \param[in] count Number of elements + /// + /// \returns Pointer to new memory block + /// + inline pointer allocate(_In_ size_type count) + { + assert(m_heap); + return (pointer)HeapAlloc(m_heap, 0, count * sizeof(_Ty)); + } + + /// + /// Frees memory block + /// + /// \param[in] ptr Pointer to memory block + /// \param[in] size Size of memory block (in bytes) + /// + inline void deallocate(_In_ pointer ptr, _In_ size_type size) + { + UNREFERENCED_PARAMETER(size); + assert(m_heap); + HeapFree(m_heap, 0, ptr); + } + + /// + /// Calls copying constructor for the element + /// + /// \param[in] ptr Pointer to memory block + /// \param[in] val Source element + /// + inline void construct(_Inout_ pointer ptr, _In_ const _Ty& val) + { + ::new ((void*)ptr) _Ty(val); + } + + /// + /// Calls moving constructor for the element + /// + /// \param[in] ptr Pointer to memory block + /// \param[in] val Source element + /// + inline void construct(_Inout_ pointer ptr, _Inout_ _Ty&& val) + { + ::new ((void*)ptr) _Ty(std::forward<_Ty>(val)); + } + + /// + /// Calls destructor for the element + /// + /// \param[in] ptr Pointer to memory block + /// + inline void destroy(_Inout_ pointer ptr) + { + ptr->_Ty::~_Ty(); + } + + /// + /// Returns maximum memory block size + /// + inline size_type max_size() const + { + return (SIZE_T)-1; + } + + public: + HANDLE m_heap; ///< Heap handle + }; + + + /// + /// Activates given activation context in constructor and deactivates it in destructor + /// + class WINSTD_API actctx_activator + { + public: + /// + /// Construct the activator and activates the given activation context + /// + /// \param[in] hActCtx Activation context + /// + /// \sa [ActivateActCtx function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa374151.aspx) + /// + actctx_activator(_In_ HANDLE hActCtx); + + /// + /// Deactivates activation context and destructs the activator + /// + /// \sa [DeactivateActCtx function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa375140.aspx) + /// + virtual ~actctx_activator(); + + protected: + ULONG_PTR m_cookie; ///< Cookie for context deactivation + }; + + + /// + /// Lets the calling thread impersonate the security context of a logged-on user + /// + class WINSTD_API user_impersonator + { + public: + /// + /// Construct the impersonator and impersonates the given user + /// + /// \param[in] hToken A handle to a primary or impersonation access token that represents a logged-on user + /// + /// \sa [ImpersonateLoggedOnUser function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa378612.aspx) + /// + user_impersonator(_In_ HANDLE hToken); + + /// + /// Reverts to current user and destructs the impersonator + /// + /// \sa [RevertToSelf function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379317.aspx) + /// + virtual ~user_impersonator(); + + protected: + BOOL m_cookie; ///< Did impersonation succeed? + }; + + + /// + /// Memory in virtual address space of a process handle wrapper + /// + class WINSTD_API vmemory : public handle + { + WINSTD_NONCOPYABLE(vmemory) + + public: + /// + /// Initializes a new class instance with the memory handle set to NULL. + /// + inline vmemory() : m_proc(NULL) + { + } + + /// + /// Initializes a new class instance with an already available object handle. + /// + /// \param[in] proc Handle of process the memory belongs to + /// \param[in] h Initial object handle value + /// + inline vmemory(_In_ handle_type h, _In_ HANDLE proc) : + m_proc(proc), + handle(h) + { + } + + /// + /// Move constructor + /// + /// \param[inout] h A rvalue reference of another object + /// + inline vmemory(_Inout_ vmemory &&h) noexcept : + m_proc(std::move(h.m_proc)), + handle(std::move(h)) + { + } + + /// + /// Frees the memory. + /// + /// \sa [VirtualFreeEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa366894.aspx) + /// + virtual ~vmemory(); + + /// + /// Move assignment + /// + /// \param[inout] other A rvalue reference of another object + /// + inline vmemory& operator=(_Inout_ vmemory &&other) noexcept + { + if (this != std::addressof(other)) { + (handle&&)*this = std::move(other); + m_proc = std::move(other.m_proc); + } + return *this; + } + + /// + /// Sets a new memory handle for the class + /// + /// When the current object handle of the class is non-NULL, the object is destroyed first. + /// + /// \param[in] proc Handle of process the memory belongs to + /// \param[in] h Initial object handle value + /// + inline void attach(_In_ HANDLE proc, _In_opt_ handle_type h) + { + m_proc = proc; + if (m_h) + free_internal(); + m_h = h; + } + + /// + /// Reserves, commits, or changes the state of a region of memory within the virtual address space of a specified process. The function initializes the memory it allocates to zero. + /// + /// \sa [VirtualAllocEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa366890.aspx) + /// + /// \return + /// - \c true when succeeds; + /// - \c false when fails. Use `GetLastError()` for failure reason. + /// + inline bool alloc( + _In_ HANDLE hProcess, + _In_opt_ LPVOID lpAddress, + _In_ SIZE_T dwSize, + _In_ DWORD flAllocationType, + _In_ DWORD flProtect) + { + handle_type h = VirtualAllocEx(hProcess, lpAddress, dwSize, flAllocationType, flProtect); + if (h) { + attach(hProcess, h); + return true; + } else + return false; + } + + protected: + /// + /// Frees the memory. + /// + /// \sa [VirtualFreeEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa366894.aspx) + /// + virtual void free_internal(); + + protected: + HANDLE m_proc; ///< Handle of memory's process + }; + + + /// + /// Registry wrapper class + /// + class WINSTD_API reg_key : public handle + { + HANDLE_IMPL(reg_key) + + public: + /// + /// Closes a handle to the registry key. + /// + /// \sa [RegCloseKey function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724837.aspx) + /// + virtual ~reg_key(); + + /// + /// Creates the specified registry key. If the key already exists, the function opens it. + /// + /// \return + /// - true when creation succeeds; + /// - false when creation fails. For extended error information, call `GetLastError()`. + /// + /// \sa [RegCreateKeyEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724844.aspx) + /// + inline bool create( + _In_ HKEY hKey, + _In_ LPCTSTR lpSubKey, + _In_opt_ LPTSTR lpClass, + _In_ DWORD dwOptions, + _In_ REGSAM samDesired, + _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes = NULL, + _Out_opt_ LPDWORD lpdwDisposition = NULL) + { + handle_type h; + LSTATUS s = RegCreateKeyEx(hKey, lpSubKey, 0, lpClass, dwOptions, samDesired, lpSecurityAttributes, &h, lpdwDisposition); + if (s == ERROR_SUCCESS) { + attach(h); + return true; + } else { + SetLastError(s); + return false; + } + } + + /// + /// Opens the specified registry key. + /// + /// \return + /// - true when creation succeeds; + /// - false when creation fails. For extended error information, call `GetLastError()`. + /// + /// \sa [RegOpenKeyEx function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724897.aspx) + /// + inline bool open( + _In_ HKEY hKey, + _In_opt_ LPCTSTR lpSubKey, + _In_ DWORD ulOptions, + _In_ REGSAM samDesired) + { + handle_type h; + LONG s = RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired, &h); + if (s == ERROR_SUCCESS) { + attach(h); + return true; + } else { + SetLastError(s); + return false; + } + } + + protected: + /// + /// Closes a handle to the registry key. + /// + /// \sa [RegCloseKey function](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724837.aspx) + /// + virtual void free_internal(); + }; + + + /// + /// SID wrapper class + /// + class WINSTD_API security_id : public handle + { + HANDLE_IMPL(security_id) + + public: + /// + /// Closes a handle to the SID. + /// + /// \sa [FreeSid function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa446631.aspx) + /// + virtual ~security_id(); + + protected: + /// + /// Closes a handle to the SID. + /// + /// \sa [FreeSid function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa446631.aspx) + /// + virtual void free_internal(); + }; + + /// @} +} + + +template +inline DWORD GetModuleFileNameA(_In_opt_ HMODULE hModule, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sValue) +{ + assert(0); // TODO: Test this code. + + _Elem szBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem)]; + + // Try with stack buffer first. + DWORD dwResult = ::GetModuleFileNameA(hModule, szBuffer, _countof(szBuffer)); + if (dwResult < _countof(szBuffer)) { + // Copy from stack. + sValue.assign(szBuffer, dwResult); + return dwResult; + } else { + for (DWORD dwCapacity = 2*WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem);; dwCapacity *= 2) { + // Allocate on heap and retry. + std::unique_ptr<_Elem[]> szBuffer(new _Elem[dwCapacity]); + dwResult = ::GetModuleFileNameA(hModule, szBuffer.get(), dwCapacity); + if (dwResult < dwCapacity) { + sValue.assign(szBuffer.get(), dwResult); + return dwResult; + } + } + } +} + + +template +inline DWORD GetModuleFileNameW(_In_opt_ HMODULE hModule, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sValue) +{ + _Elem szBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem)]; + + // Try with stack buffer first. + DWORD dwResult = ::GetModuleFileNameW(hModule, szBuffer, _countof(szBuffer)); + if (dwResult < _countof(szBuffer)) { + // Copy from stack. + sValue.assign(szBuffer, dwResult); + return dwResult; + } else { + for (DWORD dwCapacity = 2*WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem);; dwCapacity *= 2) { + // Allocate on heap and retry. + std::unique_ptr<_Elem[]> szBuffer(new _Elem[dwCapacity]); + dwResult = ::GetModuleFileNameW(hModule, szBuffer.get(), dwCapacity); + if (dwResult < dwCapacity) { + sValue.assign(szBuffer.get(), dwResult); + return dwResult; + } + } + } +} + + +template +inline int GetWindowTextA(_In_ HWND hWnd, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sValue) +{ + 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(_Elem)) { + // Read string data to stack. + _Elem szBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem)]; + 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<_Elem[]> szBuffer(new _Elem[++iResult]); + iResult = ::GetWindowTextA(hWnd, szBuffer.get(), iResult); + sValue.assign(szBuffer.get(), iResult); + } + return iResult; + } + + sValue.clear(); + return 0; +} + + +template +inline int GetWindowTextW(_In_ HWND hWnd, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sValue) +{ + 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(_Elem)) { + // Read string data to stack. + _Elem szBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem)]; + 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<_Elem[]> szBuffer(new _Elem[++iResult]); + iResult = ::GetWindowTextW(hWnd, szBuffer.get(), iResult); + sValue.assign(szBuffer.get(), iResult); + } + return iResult; + } + + sValue.clear(); + return 0; +} + + +template +inline BOOL GetFileVersionInfoA(_In_ LPCSTR lptstrFilename, __reserved DWORD dwHandle, _Out_ std::vector<_Ty, _Ax> &aValue) +{ + 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 +inline BOOL GetFileVersionInfoW(_In_ LPCWSTR lptstrFilename, __reserved DWORD dwHandle, _Out_ std::vector<_Ty, _Ax> &aValue) +{ + 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 +inline DWORD ExpandEnvironmentStringsA(_In_ LPCSTR lpSrc, std::basic_string<_Elem, _Traits, _Ax> &sValue) +{ + assert(0); // TODO: Test this code. + + for (DWORD dwSizeOut = (DWORD)strlen(lpSrc) + 0x100;;) { + DWORD dwSizeIn = dwSizeOut; + std::unique_ptr<_Elem[]> szBuffer(new _Elem[dwSizeIn + 2]); // Note: ANSI version requires one extra char. + dwSizeOut = ::ExpandEnvironmentStringsA(lpSrc, szBuffer.get(), dwSizeIn); + if (dwSizeOut == 0) { + // Error. + break; + } else if (dwSizeOut <= dwSizeIn) { + // The buffer was sufficient. + sValue.assign(szBuffer.get(), dwSizeOut); + return dwSizeOut; + } + } + + sValue.clear(); + return 0; +} + + +template +inline DWORD ExpandEnvironmentStringsW(_In_ LPCWSTR lpSrc, std::basic_string<_Elem, _Traits, _Ax> &sValue) +{ + assert(0); // TODO: Test this code. + + for (DWORD dwSizeOut = (DWORD)wcslen(lpSrc) + 0x100;;) { + DWORD dwSizeIn = dwSizeOut; + std::unique_ptr<_Elem[]> szBuffer(new _Elem[dwSizeIn + 1]); + dwSizeOut = ::ExpandEnvironmentStringsW(lpSrc, szBuffer.get(), dwSizeIn); + if (dwSizeOut == 0) { + // Error. + break; + } else if (dwSizeOut <= dwSizeIn) { + // The buffer was sufficient. + sValue.assign(szBuffer.get(), dwSizeOut); + return dwSizeOut; + } + } + + sValue.clear(); + return 0; +} + + +template +inline VOID GuidToStringA(_In_ LPCGUID lpGuid, _Out_ std::basic_string<_Elem, _Traits, _Ax> &str) +{ + 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 +inline VOID GuidToStringW(_In_ LPCGUID lpGuid, _Out_ std::basic_string<_Elem, _Traits, _Ax> &str) +{ + 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]); +} + + +template +inline LSTATUS RegQueryStringValue(_In_ HKEY hReg, _In_z_ LPCSTR pszName, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sValue) +{ + 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 + sValue.clear(); + } 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 + sValue.clear(); + } else { + // The value is not a string type. + lResult = ERROR_INVALID_DATA; + } + } + + return lResult; +} + + +template +inline LSTATUS RegQueryStringValue(_In_ HKEY hReg, _In_z_ LPCWSTR pszName, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sValue) +{ + 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 + sValue.clear(); + } 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 + sValue.clear(); + } else { + // The value is not a string type. + lResult = ERROR_INVALID_DATA; + } + } + + return lResult; +} + + +template +inline LSTATUS RegQueryValueExA(_In_ HKEY hKey, _In_opt_ LPCSTR lpValueName, __reserved LPDWORD lpReserved, _Out_opt_ LPDWORD lpType, _Out_ std::vector<_Ty, _Ax> &aData) +{ + LSTATUS lResult; + BYTE aStackBuffer[WINSTD_STACK_BUFFER_BYTES]; + DWORD dwSize = sizeof(aStackBuffer); + + // Try with stack buffer first. + lResult = RegQueryValueExA(hKey, lpValueName, lpReserved, NULL, 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)); + if ((lResult = RegQueryValueExA(hKey, lpValueName, lpReserved, lpType, aData.data(), &dwSize)) != ERROR_SUCCESS) + aData.clear(); + } + + return lResult; +} + + +template +inline LSTATUS RegQueryValueExW(_In_ HKEY hKey, _In_opt_ LPCWSTR lpValueName, __reserved LPDWORD lpReserved, _Out_opt_ LPDWORD lpType, _Out_ std::vector<_Ty, _Ax> &aData) +{ + LSTATUS lResult; + BYTE aStackBuffer[WINSTD_STACK_BUFFER_BYTES]; + DWORD dwSize = sizeof(aStackBuffer); + + // Try with stack buffer first. + lResult = RegQueryValueExW(hKey, lpValueName, lpReserved, NULL, 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)); + if ((lResult = RegQueryValueExW(hKey, lpValueName, lpReserved, lpType, aData.data(), &dwSize)) != ERROR_SUCCESS) + aData.clear(); + } + + return lResult; +} + + +#if _WIN32_WINNT >= _WIN32_WINNT_VISTA + +template +inline LSTATUS RegLoadMUIStringA(_In_ HKEY hKey, _In_opt_ LPCSTR pszValue, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sOut, _In_ DWORD Flags, _In_opt_ LPCSTR pszDirectory) +{ + // 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 +inline LSTATUS RegLoadMUIStringW(_In_ HKEY hKey, _In_opt_ LPCWSTR pszValue, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sOut, _In_ DWORD Flags, _In_opt_ LPCWSTR pszDirectory) +{ + LSTATUS lResult; + _Elem szStackBuffer[WINSTD_STACK_BUFFER_BYTES/sizeof(_Elem)]; + 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(_Elem))); + } else if (lResult == ERROR_MORE_DATA) { + // Allocate buffer on heap and retry. + std::unique_ptr<_Elem[]> szBuffer(new _Elem[(dwSize + sizeof(_Elem) - 1)/sizeof(_Elem)]); + sOut.assign(szBuffer.get(), (lResult = RegLoadMUIStringW(hKey, pszValue, szBuffer.get(), dwSize, &dwSize, Flags, pszDirectory)) == ERROR_SUCCESS ? wcsnlen(szBuffer.get(), dwSize/sizeof(_Elem)) : 0); + } + + return lResult; +} + +#endif + + +template +inline int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cchWideChar) LPCWSTR lpWideCharStr, _In_ int cchWideChar, _Out_ std::basic_string &sMultiByteStr, _In_opt_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) +{ + 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) : 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) : cch - 1); + } + + return cch; +} + + +template +inline int WideCharToMultiByte(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_ std::basic_string sWideCharStr, _Out_ std::basic_string &sMultiByteStr, _In_opt_ LPCSTR lpDefaultChar, _Out_opt_ LPBOOL lpUsedDefaultChar) +{ + 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 +inline int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_z_count_(cbMultiByte) LPCSTR lpMultiByteStr, _In_ int cbMultiByte, _Out_ std::basic_string &sWideCharStr) +{ + 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) : 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) : cch - 1); + } + + return cch; +} + + +template inline int MultiByteToWideChar(_In_ UINT CodePage, _In_ DWORD dwFlags, _In_ std::basic_string sMultiByteStr, _Out_ std::basic_string &sWideCharStr) +{ + 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 +inline int WINAPI LoadStringA(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_ std::basic_string &sBuffer) +{ + // 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 +inline int WINAPI LoadStringW(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_ std::basic_string &sBuffer) +{ + // 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; +} + + +inline VOID OutputDebugStrV(_In_ LPCSTR lpOutputString, _In_ va_list arg) +{ + std::string str; + vsprintf(str, lpOutputString, arg); + OutputDebugStringA(str.c_str()); +} + + +inline VOID OutputDebugStrV(_In_ LPCWSTR lpOutputString, _In_ va_list arg) +{ + std::wstring str; + vsprintf(str, lpOutputString, arg); + OutputDebugStringW(str.c_str()); +} + + +inline VOID OutputDebugStr(_In_ LPCSTR lpOutputString, ...) +{ + va_list arg; + va_start(arg, lpOutputString); + OutputDebugStrV(lpOutputString, arg); + va_end(arg); +} + + +inline VOID OutputDebugStr(_In_ LPCWSTR lpOutputString, ...) +{ + va_list arg; + va_start(arg, lpOutputString); + OutputDebugStrV(lpOutputString, arg); + va_end(arg); +} + + +template inline int GetDateFormatA(_In_ LCID Locale, _In_ DWORD dwFlags, _In_opt_ const SYSTEMTIME *lpDate, _In_opt_ LPCSTR lpFormat, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sDate) +{ + int iResult = GetDateFormatA(Locale, dwFlags, lpDate, lpFormat, NULL, 0); + if (iResult) { + // Allocate buffer on heap and retry. + std::unique_ptr<_Elem[]> szBuffer(new _Elem[iResult]); + iResult = GetDateFormatA(Locale, dwFlags, lpDate, lpFormat, szBuffer.get(), iResult); + sDate.assign(szBuffer.get(), iResult ? iResult - 1 : 0); + return iResult; + } + + return iResult; +} + + +template inline int GetDateFormatW(_In_ LCID Locale, _In_ DWORD dwFlags, _In_opt_ const SYSTEMTIME *lpDate, _In_opt_ LPCWSTR lpFormat, _Out_ std::basic_string<_Elem, _Traits, _Ax> &sDate) +{ + int iResult = GetDateFormatW(Locale, dwFlags, lpDate, lpFormat, NULL, 0); + if (iResult) { + // Allocate buffer on heap and retry. + std::unique_ptr<_Elem[]> szBuffer(new _Elem[iResult]); + iResult = GetDateFormatW(Locale, dwFlags, lpDate, lpFormat, szBuffer.get(), iResult); + sDate.assign(szBuffer.get(), iResult ? iResult - 1 : 0); + return iResult; + } + + return iResult; +} + + +template +inline BOOL LookupAccountSidA(_In_opt_ LPCSTR lpSystemName, _In_ PSID lpSid, _Out_opt_ std::basic_string<_Elem, _Traits, _Ax> *sName, _Out_opt_ std::basic_string<_Elem, _Traits, _Ax> *sReferencedDomainName, _Out_ PSID_NAME_USE peUse) +{ + assert(0); // TODO: Test this code. + + DWORD dwNameLen = 0, dwRefDomainLen = 0; + + if (LookupAccountSidA(lpSystemName, lpSid, + NULL, sName ? &dwNameLen : NULL, + NULL, sReferencedDomainName ? &dwRefDomainLen : NULL, + 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<_Elem[]> bufName (new _Elem[dwNameLen ]); + std::unique_ptr<_Elem[]> bufRefDomain(new _Elem[dwRefDomainLen]); + if (LookupAccountSidA(lpSystemName, lpSid, + bufName .get(), sName ? &dwNameLen : NULL, + bufRefDomain.get(), sReferencedDomainName ? &dwRefDomainLen : NULL, + peUse)) + { + if (sName ) sName ->assign(bufName .get(), dwNameLen - 1); + if (sReferencedDomainName) sReferencedDomainName->assign(bufRefDomain.get(), dwRefDomainLen - 1); + return TRUE; + } + } + + return FALSE; +} + + +template +inline BOOL LookupAccountSidW(_In_opt_ LPCWSTR lpSystemName, _In_ PSID lpSid, _Out_opt_ std::basic_string<_Elem, _Traits, _Ax> *sName, _Out_opt_ std::basic_string<_Elem, _Traits, _Ax> *sReferencedDomainName, _Out_ PSID_NAME_USE peUse) +{ + assert(0); // TODO: Test this code. + + DWORD dwNameLen = 0, dwRefDomainLen = 0; + + if (LookupAccountSidW(lpSystemName, lpSid, + NULL, sName ? &dwNameLen : NULL, + NULL, sReferencedDomainName ? &dwRefDomainLen : NULL, + 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<_Elem[]> bufName (new _Elem[dwNameLen ]); + std::unique_ptr<_Elem[]> bufRefDomain(new _Elem[dwRefDomainLen]); + if (LookupAccountSidW(lpSystemName, lpSid, + bufName .get(), sName ? &dwNameLen : NULL, + bufRefDomain.get(), sReferencedDomainName ? &dwRefDomainLen : NULL, + peUse)) + { + if (sName ) sName ->assign(bufName .get(), dwNameLen - 1); + if (sReferencedDomainName) sReferencedDomainName->assign(bufRefDomain.get(), dwRefDomainLen - 1); + return TRUE; + } + } + + return FALSE; +} + + +template +inline BOOL GetTokenInformation(_In_ HANDLE TokenHandle, _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, _Out_ std::unique_ptr<_Ty> &TokenInformation) +{ + 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; +} diff --git a/src/EAP.cpp b/src/EAP.cpp index 5e4273d3..013d29d2 100644 --- a/src/EAP.cpp +++ b/src/EAP.cpp @@ -1,137 +1,140 @@ -/* - Copyright 1991-2018 Amebis - Copyright 2016 GÉANT - - This file is part of WinStd. - - Setup is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Setup is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Setup. If not, see . -*/ - -#include "StdAfx.h" - -#pragma comment(lib, "Eappcfg.lib") - - -////////////////////////////////////////////////////////////////////// -// winstd::eap_attr -////////////////////////////////////////////////////////////////////// - -winstd::eap_attr::~eap_attr() -{ - if (pValue) - delete []pValue; -} - - -void winstd::eap_attr::create_ms_mppe_key(_In_ BYTE bVendorType, _In_count_(nKeySize) LPCBYTE pbKey, _In_ BYTE nKeySize) -{ - BYTE nPaddingLength = (BYTE)((16 - (1 + (DWORD)nKeySize)) % 16); - DWORD dwLengthNew = - 4 + // Vendor-Id - 1 + // Vendor type - 1 + // Vendor length - 2 + // Salt - 1 + // Key-Length - nKeySize + // Key - nPaddingLength; // Padding - - LPBYTE p = new BYTE[dwLengthNew]; - p[0] = 0x00; // Vendor-Id (0x137 = 311 = Microsoft) - p[1] = 0x00; // --| - p[2] = 0x01; // --| - p[3] = 0x37; // --^ - p[4] = bVendorType; // Vendor type - p[5] = (BYTE)(dwLengthNew - 4); // Vendor length - p[6] = 0x00; // Salt - p[7] = 0x00; // --^ - p[8] = nKeySize; // Key-Length - memcpy(p + 9, pbKey, nKeySize); // Key - memset(p + 9 + nKeySize, 0, nPaddingLength); // Padding - - if (pValue) - delete [] pValue; - - eaType = eatVendorSpecific; - dwLength = dwLengthNew; - pValue = p; -} - - -const EAP_ATTRIBUTE winstd::eap_attr::blank = {}; - - -////////////////////////////////////////////////////////////////////// -// winstd::eap_packet -////////////////////////////////////////////////////////////////////// - -winstd::eap_packet::~eap_packet() -{ - if (m_h) - HeapFree(GetProcessHeap(), 0, m_h); -} - - -void winstd::eap_packet::free_internal() -{ - HeapFree(GetProcessHeap(), 0, m_h); -} - - -winstd::eap_packet::handle_type winstd::eap_packet::duplicate_internal(_In_ handle_type h) const -{ - WORD n = ntohs(*(WORD*)h->Length); - handle_type h2 = (handle_type)HeapAlloc(GetProcessHeap(), 0, n); - if (!h2) { - SetLastError(ERROR_OUTOFMEMORY); - return NULL; - } - - memcpy(h2, h, n); - - return h2; -} - - -////////////////////////////////////////////////////////////////////// -// winstd::eap_method_info_array -////////////////////////////////////////////////////////////////////// - -winstd::eap_method_info_array::~eap_method_info_array() -{ - if (pEapMethods) - free_internal(); -} - - -/// \cond internal - -void winstd::eap_method_info_array::free_internal() -{ - for (DWORD i = 0; i < dwNumberOfMethods; i++) - free_internal(pEapMethods + i); - - EapHostPeerFreeMemory((BYTE*)pEapMethods); -} - - -void winstd::eap_method_info_array::free_internal(_In_ EAP_METHOD_INFO *pMethodInfo) -{ - if (pMethodInfo->pInnerMethodInfo) - free_internal(pMethodInfo->pInnerMethodInfo); - - EapHostPeerFreeMemory((BYTE*)pMethodInfo->pwszAuthorName); - EapHostPeerFreeMemory((BYTE*)pMethodInfo->pwszFriendlyName); -} - -/// \endcond +/* + Copyright 1991-2018 Amebis + Copyright 2016 GÉANT + + This file is part of WinStd. + + Setup is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Setup is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Setup. If not, see . +*/ + +#include "StdAfx.h" + +#pragma comment(lib, "Eappcfg.lib") + + +////////////////////////////////////////////////////////////////////// +// winstd::eap_attr +////////////////////////////////////////////////////////////////////// + +winstd::eap_attr::~eap_attr() +{ + if (pValue) + delete []pValue; +} + + +void winstd::eap_attr::create_ms_mppe_key(_In_ BYTE bVendorType, _In_count_(nKeySize) LPCBYTE pbKey, _In_ BYTE nKeySize) +{ + BYTE nPaddingLength = (BYTE)((16 - (1 + (DWORD)nKeySize)) % 16); + DWORD dwLengthNew = + 4 + // Vendor-Id + 1 + // Vendor type + 1 + // Vendor length + 2 + // Salt + 1 + // Key-Length + nKeySize + // Key + nPaddingLength; // Padding + +#pragma warning(push) +#pragma warning(disable: 6386) + LPBYTE p = new BYTE[dwLengthNew]; + p[0] = 0x00; // Vendor-Id (0x137 = 311 = Microsoft) + p[1] = 0x00; // --| + p[2] = 0x01; // --| + p[3] = 0x37; // --^ + p[4] = bVendorType; // Vendor type + p[5] = (BYTE)(dwLengthNew - 4); // Vendor length + p[6] = 0x00; // Salt + p[7] = 0x00; // --^ + p[8] = nKeySize; // Key-Length +#pragma warning(pop) + memcpy(p + 9, pbKey, nKeySize); // Key + memset(p + 9 + nKeySize, 0, nPaddingLength); // Padding + + if (pValue) + delete [] pValue; + + eaType = eatVendorSpecific; + dwLength = dwLengthNew; + pValue = p; +} + + +const EAP_ATTRIBUTE winstd::eap_attr::blank = {}; + + +////////////////////////////////////////////////////////////////////// +// winstd::eap_packet +////////////////////////////////////////////////////////////////////// + +winstd::eap_packet::~eap_packet() +{ + if (m_h) + HeapFree(GetProcessHeap(), 0, m_h); +} + + +void winstd::eap_packet::free_internal() +{ + HeapFree(GetProcessHeap(), 0, m_h); +} + + +winstd::eap_packet::handle_type winstd::eap_packet::duplicate_internal(_In_ handle_type h) const +{ + WORD n = ntohs(*(WORD*)h->Length); + handle_type h2 = (handle_type)HeapAlloc(GetProcessHeap(), 0, n); + if (!h2) { + SetLastError(ERROR_OUTOFMEMORY); + return NULL; + } + + memcpy(h2, h, n); + + return h2; +} + + +////////////////////////////////////////////////////////////////////// +// winstd::eap_method_info_array +////////////////////////////////////////////////////////////////////// + +winstd::eap_method_info_array::~eap_method_info_array() +{ + if (pEapMethods) + free_internal(); +} + + +/// \cond internal + +void winstd::eap_method_info_array::free_internal() +{ + for (DWORD i = 0; i < dwNumberOfMethods; i++) + free_internal(pEapMethods + i); + + EapHostPeerFreeMemory((BYTE*)pEapMethods); +} + + +void winstd::eap_method_info_array::free_internal(_In_ EAP_METHOD_INFO *pMethodInfo) +{ + if (pMethodInfo->pInnerMethodInfo) + free_internal(pMethodInfo->pInnerMethodInfo); + + EapHostPeerFreeMemory((BYTE*)pMethodInfo->pwszAuthorName); + EapHostPeerFreeMemory((BYTE*)pMethodInfo->pwszFriendlyName); +} + +/// \endcond diff --git a/src/StdAfx.h b/src/StdAfx.h index 14ca5383..c01fc7bd 100644 --- a/src/StdAfx.h +++ b/src/StdAfx.h @@ -1,40 +1,42 @@ -/* - Copyright 1991-2018 Amebis - Copyright 2016 GÉANT - - This file is part of WinStd. - - Setup is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Setup is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Setup. If not, see . -*/ - -#pragma once - -#include "../include/WinStd/Base64.h" -#include "../include/WinStd/COM.h" -#include "../include/WinStd/Cred.h" -#include "../include/WinStd/Crypt.h" -#include "../include/WinStd/EAP.h" -#if _WIN32_WINNT >= _WIN32_WINNT_VISTA -#include "../include/WinStd/ETW.h" -#endif -#include "../include/WinStd/Common.h" -#include "../include/WinStd/MSI.h" -#if defined(SECURITY_WIN32) || defined(SECURITY_KERNEL) || defined(SECURITY_MAC) -#include "../include/WinStd/Sec.h" -#endif -#include "../include/WinStd/Shell.h" -#include "../include/WinStd/Win.h" -#include "../include/WinStd/WLAN.h" - -#include +/* + Copyright 1991-2018 Amebis + Copyright 2016 GÉANT + + This file is part of WinStd. + + Setup is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Setup is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Setup. If not, see . +*/ + +#pragma once + +#include "../include/WinStd/Base64.h" +#include "../include/WinStd/COM.h" +#include "../include/WinStd/Cred.h" +#include "../include/WinStd/Crypt.h" +#include "../include/WinStd/EAP.h" +#if _WIN32_WINNT >= _WIN32_WINNT_VISTA +#include "../include/WinStd/ETW.h" +#endif +#include "../include/WinStd/Hex.h" +#include "../include/WinStd/MSI.h" +#if defined(SECURITY_WIN32) || defined(SECURITY_KERNEL) || defined(SECURITY_MAC) +#include "../include/WinStd/Sec.h" +#endif +#include "../include/WinStd/Shell.h" +#include "../include/WinStd/Win.h" +#include "../include/WinStd/WinTrust.h" +#include "../include/WinStd/WLAN.h" +#include "../include/WinStd/Common.h" + +#include diff --git a/src/Win.cpp b/src/Win.cpp index 207fed0a..665a4075 100644 --- a/src/Win.cpp +++ b/src/Win.cpp @@ -1,328 +1,328 @@ -/* - Copyright 1991-2018 Amebis - Copyright 2016 GÉANT - - This file is part of WinStd. - - Setup is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Setup is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Setup. If not, see . -*/ - -#include "StdAfx.h" - - -////////////////////////////////////////////////////////////////////// -// StringToGuidA -////////////////////////////////////////////////////////////////////// - -BOOL WINSTD_API StringToGuidA(_In_z_ LPCSTR lpszGuid, _Out_ LPGUID lpGuid, _Out_opt_ LPCSTR *lpszGuidEnd) -{ - 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 = (unsigned short)ulTmp; - lpszGuid = lpszEnd; - - if (*lpszGuid != '-') return FALSE; - lpszGuid++; - - ulTmp = strtoul(lpszGuid, &lpszEnd, 16); - if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE; - g.Data3 = (unsigned short)ulTmp; - lpszGuid = lpszEnd; - - if (*lpszGuid != '-') return FALSE; - lpszGuid++; - - ulTmp = strtoul(lpszGuid, &lpszEnd, 16); - if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE; - g.Data4[0] = (unsigned char)((ulTmp >> 8) & 0xff); - g.Data4[1] = (unsigned char)( ulTmp & 0xff); - lpszGuid = lpszEnd; - - if (*lpszGuid != '-') return FALSE; - lpszGuid++; - - ullTmp = _strtoui64(lpszGuid, &lpszEnd, 16); - if (errno == ERANGE || ullTmp > 0xFFFFFFFFFFFF) return FALSE; - g.Data4[2] = (unsigned char)((ullTmp >> 40) & 0xff); - g.Data4[3] = (unsigned char)((ullTmp >> 32) & 0xff); - g.Data4[4] = (unsigned char)((ullTmp >> 24) & 0xff); - g.Data4[5] = (unsigned char)((ullTmp >> 16) & 0xff); - g.Data4[6] = (unsigned char)((ullTmp >> 8) & 0xff); - g.Data4[7] = (unsigned char)( ullTmp & 0xff); - lpszGuid = lpszEnd; - - if (*lpszGuid != '}') return FALSE; - lpszGuid++; - - if (lpszGuidEnd) - *lpszGuidEnd = lpszGuid; - - *lpGuid = g; - return TRUE; -} - - -BOOL WINSTD_API StringToGuidW(_In_z_ LPCWSTR lpszGuid, _Out_ LPGUID lpGuid, _Out_opt_ LPCWSTR *lpszGuidEnd) -{ - 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 = (unsigned short)ulTmp; - lpszGuid = lpszEnd; - - if (*lpszGuid != '-') return FALSE; - lpszGuid++; - - ulTmp = wcstoul(lpszGuid, &lpszEnd, 16); - if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE; - g.Data3 = (unsigned short)ulTmp; - lpszGuid = lpszEnd; - - if (*lpszGuid != '-') return FALSE; - lpszGuid++; - - ulTmp = wcstoul(lpszGuid, &lpszEnd, 16); - if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE; - g.Data4[0] = (unsigned char)((ulTmp >> 8) & 0xff); - g.Data4[1] = (unsigned char)( ulTmp & 0xff); - lpszGuid = lpszEnd; - - if (*lpszGuid != '-') return FALSE; - lpszGuid++; - - ullTmp = _wcstoui64(lpszGuid, &lpszEnd, 16); - if (errno == ERANGE || ullTmp > 0xFFFFFFFFFFFF) return FALSE; - g.Data4[2] = (unsigned char)((ullTmp >> 40) & 0xff); - g.Data4[3] = (unsigned char)((ullTmp >> 32) & 0xff); - g.Data4[4] = (unsigned char)((ullTmp >> 24) & 0xff); - g.Data4[5] = (unsigned char)((ullTmp >> 16) & 0xff); - g.Data4[6] = (unsigned char)((ullTmp >> 8) & 0xff); - g.Data4[7] = (unsigned char)( ullTmp & 0xff); - lpszGuid = lpszEnd; - - if (*lpszGuid != '}') return FALSE; - lpszGuid++; - - if (lpszGuidEnd) - *lpszGuidEnd = lpszGuid; - - *lpGuid = g; - return TRUE; -} - - -////////////////////////////////////////////////////////////////////// -// winstd::win_handle -////////////////////////////////////////////////////////////////////// - -winstd::win_handle::~win_handle() -{ - if (m_h) - CloseHandle(m_h); -} - - -void winstd::win_handle::free_internal() -{ - CloseHandle(m_h); -} - - -////////////////////////////////////////////////////////////////////// -// winstd::library -////////////////////////////////////////////////////////////////////// - -winstd::library::~library() -{ - if (m_h) - FreeLibrary(m_h); -} - - -void winstd::library::free_internal() -{ - FreeLibrary(m_h); -} - - -////////////////////////////////////////////////////////////////////// -// winstd::heap -////////////////////////////////////////////////////////////////////// - -winstd::heap::~heap() -{ - if (m_h) { - enumerate(); - HeapDestroy(m_h); - } -} - - -bool winstd::heap::enumerate() -{ - bool found = false; - - // Lock the heap for exclusive access. - HeapLock(m_h); - - PROCESS_HEAP_ENTRY e; - e.lpData = NULL; - while (HeapWalk(m_h, &e) != FALSE) { - if ((e.wFlags & PROCESS_HEAP_ENTRY_BUSY) != 0) { - OutputDebugStr( - _T("Allocated block%s%s\n") - _T(" Data portion begins at: %#p\n Size: %d bytes\n") - _T(" Overhead: %d bytes\n Region index: %d\n"), - (e.wFlags & PROCESS_HEAP_ENTRY_MOVEABLE) != 0 ? tstring_printf(_T(", movable with HANDLE %#p"), e.Block.hMem).c_str() : _T(""), - (e.wFlags & PROCESS_HEAP_ENTRY_DDESHARE) != 0 ? _T(", DDESHARE") : _T(""), - e.lpData, - e.cbData, - e.cbOverhead, - e.iRegionIndex); - - found = true; - } - } - - DWORD dwResult = GetLastError(); - if (dwResult != ERROR_NO_MORE_ITEMS) - OutputDebugStr(_T("HeapWalk failed (error %u).\n"), dwResult); - - // Unlock the heap. - HeapUnlock(m_h); - - return found; -} - - -void winstd::heap::free_internal() -{ - enumerate(); - HeapDestroy(m_h); -} - - -////////////////////////////////////////////////////////////////////// -// winstd::actctx_activator -////////////////////////////////////////////////////////////////////// - -winstd::actctx_activator::actctx_activator(_In_ HANDLE hActCtx) -{ - if (!ActivateActCtx(hActCtx, &m_cookie)) - m_cookie = 0; -} - - -winstd::actctx_activator::~actctx_activator() -{ - if (m_cookie) - DeactivateActCtx(0, m_cookie); -} - - -////////////////////////////////////////////////////////////////////// -// winstd::user_impersonator -////////////////////////////////////////////////////////////////////// - -winstd::user_impersonator::user_impersonator(_In_ HANDLE hToken) -{ - m_cookie = ImpersonateLoggedOnUser(hToken); -} - - -winstd::user_impersonator::~user_impersonator() -{ - if (m_cookie) - RevertToSelf(); -} - - -////////////////////////////////////////////////////////////////////// -// winstd::vmemory -////////////////////////////////////////////////////////////////////// - -winstd::vmemory::~vmemory() -{ - if (m_h) - VirtualFreeEx(m_proc, m_h, 0, MEM_RELEASE); -} - - -void winstd::vmemory::free_internal() -{ - VirtualFreeEx(m_proc, m_h, 0, MEM_RELEASE); -} - - -////////////////////////////////////////////////////////////////////// -// winstd::reg_key -////////////////////////////////////////////////////////////////////// - -winstd::reg_key::~reg_key() -{ - if (m_h) - RegCloseKey(m_h); -} - - -void winstd::reg_key::free_internal() -{ - RegCloseKey(m_h); -} - - -////////////////////////////////////////////////////////////////////// -// winstd::security_id -////////////////////////////////////////////////////////////////////// - -winstd::security_id::~security_id() -{ - if (m_h) - FreeSid(m_h); -} - - -void winstd::security_id::free_internal() -{ - FreeSid(m_h); -} +/* + Copyright 1991-2018 Amebis + Copyright 2016 GÉANT + + This file is part of WinStd. + + Setup is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Setup is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Setup. If not, see . +*/ + +#include "StdAfx.h" + + +////////////////////////////////////////////////////////////////////// +// StringToGuidA +////////////////////////////////////////////////////////////////////// + +_Success_(return) BOOL WINSTD_API StringToGuidA(_In_z_ LPCSTR lpszGuid, _Out_ LPGUID lpGuid, _Out_opt_ LPCSTR *lpszGuidEnd) +{ + 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 = (unsigned short)ulTmp; + lpszGuid = lpszEnd; + + if (*lpszGuid != '-') return FALSE; + lpszGuid++; + + ulTmp = strtoul(lpszGuid, &lpszEnd, 16); + if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE; + g.Data3 = (unsigned short)ulTmp; + lpszGuid = lpszEnd; + + if (*lpszGuid != '-') return FALSE; + lpszGuid++; + + ulTmp = strtoul(lpszGuid, &lpszEnd, 16); + if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE; + g.Data4[0] = (unsigned char)((ulTmp >> 8) & 0xff); + g.Data4[1] = (unsigned char)( ulTmp & 0xff); + lpszGuid = lpszEnd; + + if (*lpszGuid != '-') return FALSE; + lpszGuid++; + + ullTmp = _strtoui64(lpszGuid, &lpszEnd, 16); + if (errno == ERANGE || ullTmp > 0xFFFFFFFFFFFF) return FALSE; + g.Data4[2] = (unsigned char)((ullTmp >> 40) & 0xff); + g.Data4[3] = (unsigned char)((ullTmp >> 32) & 0xff); + g.Data4[4] = (unsigned char)((ullTmp >> 24) & 0xff); + g.Data4[5] = (unsigned char)((ullTmp >> 16) & 0xff); + g.Data4[6] = (unsigned char)((ullTmp >> 8) & 0xff); + g.Data4[7] = (unsigned char)( ullTmp & 0xff); + lpszGuid = lpszEnd; + + if (*lpszGuid != '}') return FALSE; + lpszGuid++; + + if (lpszGuidEnd) + *lpszGuidEnd = lpszGuid; + + *lpGuid = g; + return TRUE; +} + + +_Success_(return) BOOL WINSTD_API StringToGuidW(_In_z_ LPCWSTR lpszGuid, _Out_ LPGUID lpGuid, _Out_opt_ LPCWSTR *lpszGuidEnd) +{ + 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 = (unsigned short)ulTmp; + lpszGuid = lpszEnd; + + if (*lpszGuid != '-') return FALSE; + lpszGuid++; + + ulTmp = wcstoul(lpszGuid, &lpszEnd, 16); + if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE; + g.Data3 = (unsigned short)ulTmp; + lpszGuid = lpszEnd; + + if (*lpszGuid != '-') return FALSE; + lpszGuid++; + + ulTmp = wcstoul(lpszGuid, &lpszEnd, 16); + if (errno == ERANGE || ulTmp > 0xFFFF) return FALSE; + g.Data4[0] = (unsigned char)((ulTmp >> 8) & 0xff); + g.Data4[1] = (unsigned char)( ulTmp & 0xff); + lpszGuid = lpszEnd; + + if (*lpszGuid != '-') return FALSE; + lpszGuid++; + + ullTmp = _wcstoui64(lpszGuid, &lpszEnd, 16); + if (errno == ERANGE || ullTmp > 0xFFFFFFFFFFFF) return FALSE; + g.Data4[2] = (unsigned char)((ullTmp >> 40) & 0xff); + g.Data4[3] = (unsigned char)((ullTmp >> 32) & 0xff); + g.Data4[4] = (unsigned char)((ullTmp >> 24) & 0xff); + g.Data4[5] = (unsigned char)((ullTmp >> 16) & 0xff); + g.Data4[6] = (unsigned char)((ullTmp >> 8) & 0xff); + g.Data4[7] = (unsigned char)( ullTmp & 0xff); + lpszGuid = lpszEnd; + + if (*lpszGuid != '}') return FALSE; + lpszGuid++; + + if (lpszGuidEnd) + *lpszGuidEnd = lpszGuid; + + *lpGuid = g; + return TRUE; +} + + +////////////////////////////////////////////////////////////////////// +// winstd::win_handle +////////////////////////////////////////////////////////////////////// + +winstd::win_handle::~win_handle() +{ + if (m_h) + CloseHandle(m_h); +} + + +void winstd::win_handle::free_internal() +{ + CloseHandle(m_h); +} + + +////////////////////////////////////////////////////////////////////// +// winstd::library +////////////////////////////////////////////////////////////////////// + +winstd::library::~library() +{ + if (m_h) + FreeLibrary(m_h); +} + + +void winstd::library::free_internal() +{ + FreeLibrary(m_h); +} + + +////////////////////////////////////////////////////////////////////// +// winstd::heap +////////////////////////////////////////////////////////////////////// + +winstd::heap::~heap() +{ + if (m_h) { + enumerate(); + HeapDestroy(m_h); + } +} + + +bool winstd::heap::enumerate() +{ + bool found = false; + + // Lock the heap for exclusive access. + HeapLock(m_h); + + PROCESS_HEAP_ENTRY e; + e.lpData = NULL; + while (HeapWalk(m_h, &e) != FALSE) { + if ((e.wFlags & PROCESS_HEAP_ENTRY_BUSY) != 0) { + OutputDebugStr( + _T("Allocated block%s%s\n") + _T(" Data portion begins at: %#p\n Size: %d bytes\n") + _T(" Overhead: %d bytes\n Region index: %d\n"), + (e.wFlags & PROCESS_HEAP_ENTRY_MOVEABLE) != 0 ? tstring_printf(_T(", movable with HANDLE %#p"), e.Block.hMem).c_str() : _T(""), + (e.wFlags & PROCESS_HEAP_ENTRY_DDESHARE) != 0 ? _T(", DDESHARE") : _T(""), + e.lpData, + e.cbData, + e.cbOverhead, + e.iRegionIndex); + + found = true; + } + } + + DWORD dwResult = GetLastError(); + if (dwResult != ERROR_NO_MORE_ITEMS) + OutputDebugStr(_T("HeapWalk failed (error %u).\n"), dwResult); + + // Unlock the heap. + HeapUnlock(m_h); + + return found; +} + + +void winstd::heap::free_internal() +{ + enumerate(); + HeapDestroy(m_h); +} + + +////////////////////////////////////////////////////////////////////// +// winstd::actctx_activator +////////////////////////////////////////////////////////////////////// + +winstd::actctx_activator::actctx_activator(_In_ HANDLE hActCtx) +{ + if (!ActivateActCtx(hActCtx, &m_cookie)) + m_cookie = 0; +} + + +winstd::actctx_activator::~actctx_activator() +{ + if (m_cookie) + DeactivateActCtx(0, m_cookie); +} + + +////////////////////////////////////////////////////////////////////// +// winstd::user_impersonator +////////////////////////////////////////////////////////////////////// + +winstd::user_impersonator::user_impersonator(_In_ HANDLE hToken) +{ + m_cookie = ImpersonateLoggedOnUser(hToken); +} + + +winstd::user_impersonator::~user_impersonator() +{ + if (m_cookie) + RevertToSelf(); +} + + +////////////////////////////////////////////////////////////////////// +// winstd::vmemory +////////////////////////////////////////////////////////////////////// + +winstd::vmemory::~vmemory() +{ + if (m_h) + VirtualFreeEx(m_proc, m_h, 0, MEM_RELEASE); +} + + +void winstd::vmemory::free_internal() +{ + VirtualFreeEx(m_proc, m_h, 0, MEM_RELEASE); +} + + +////////////////////////////////////////////////////////////////////// +// winstd::reg_key +////////////////////////////////////////////////////////////////////// + +winstd::reg_key::~reg_key() +{ + if (m_h) + RegCloseKey(m_h); +} + + +void winstd::reg_key::free_internal() +{ + RegCloseKey(m_h); +} + + +////////////////////////////////////////////////////////////////////// +// winstd::security_id +////////////////////////////////////////////////////////////////////// + +winstd::security_id::~security_id() +{ + if (m_h) + FreeSid(m_h); +} + + +void winstd::security_id::free_internal() +{ + FreeSid(m_h); +}