10 changed files with 2874 additions and 311 deletions
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,86 @@ |
|||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <Windows.h> |
||||||
|
|
||||||
|
#include <memsafe.h> |
||||||
|
|
||||||
|
template<typename T> |
||||||
|
class CTContainer_PolicyUnOwned |
||||||
|
{ |
||||||
|
public: |
||||||
|
static void Destroy(T* p) {} |
||||||
|
}; |
||||||
|
|
||||||
|
template<typename T> |
||||||
|
class CTContainer_PolicyRelease |
||||||
|
{ |
||||||
|
public: |
||||||
|
static void Destroy(T* p) |
||||||
|
{ |
||||||
|
if (p) |
||||||
|
p->Release(); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
class CTContainer_PolicyNewMem |
||||||
|
{ |
||||||
|
public: |
||||||
|
template<typename T> |
||||||
|
static void Destroy(T* p) |
||||||
|
{ |
||||||
|
delete p; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
class CTContainer_PolicyCoTaskMem |
||||||
|
{ |
||||||
|
public: |
||||||
|
static void Destroy(void* p) |
||||||
|
{ |
||||||
|
CoTaskMemFree(p); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
class CTContainer_PolicyLocalMem |
||||||
|
{ |
||||||
|
public: |
||||||
|
static void Destroy(void* p) |
||||||
|
{ |
||||||
|
DestroyMem(p); |
||||||
|
} |
||||||
|
|
||||||
|
static BOOL DestroyMem(void* p) |
||||||
|
{ |
||||||
|
return !LocalFree(p); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
class CTPolicyCoTaskMem : CTContainer_PolicyCoTaskMem |
||||||
|
{ |
||||||
|
public: |
||||||
|
static void Destroy(void* p) |
||||||
|
{ |
||||||
|
CTContainer_PolicyCoTaskMem::Destroy(p); |
||||||
|
} |
||||||
|
|
||||||
|
static HRESULT ReallocArray(T* pv, size_t cItems, T** ppv) |
||||||
|
{ |
||||||
|
return CoReallocArray(pv, cItems, ppv); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
class CTPolicyLocalMem : CTContainer_PolicyLocalMem |
||||||
|
{ |
||||||
|
public: |
||||||
|
static void Destroy(void* p) |
||||||
|
{ |
||||||
|
DestroyMem(p); |
||||||
|
} |
||||||
|
|
||||||
|
static HRESULT ReallocArray(T* pv, size_t cItems, T** ppv) |
||||||
|
{ |
||||||
|
return LocalReallocArray(pv, cItems, ppv); |
||||||
|
} |
||||||
|
}; |
||||||
@ -0,0 +1,906 @@ |
|||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <intsafe.h> |
||||||
|
#include <strsafe.h> |
||||||
|
|
||||||
|
#include "ResultUtils.h" |
||||||
|
|
||||||
|
namespace Windows::Internal |
||||||
|
{ |
||||||
|
class ResourceString |
||||||
|
{ |
||||||
|
public: |
||||||
|
static bool FindAndSize(HINSTANCE hInstance, UINT uId, WORD wLanguage, const WCHAR** ppch, WORD* plen) |
||||||
|
{ |
||||||
|
bool fRet = false; |
||||||
|
*ppch = nullptr; |
||||||
|
if (plen) |
||||||
|
*plen = 0; |
||||||
|
HRSRC hRes = FindResourceExW(hInstance, RT_STRING, MAKEINTRESOURCEW((uId >> 4) + 1), wLanguage); |
||||||
|
if (hRes) |
||||||
|
{ |
||||||
|
HGLOBAL hStringSeg = LoadResource(hInstance, hRes); |
||||||
|
if (hStringSeg) |
||||||
|
{ |
||||||
|
WCHAR* pch = (WCHAR*)LockResource(hStringSeg); |
||||||
|
if (pch) |
||||||
|
{ |
||||||
|
for (uId = (char)uId & 0xF; uId; --uId) |
||||||
|
pch += *pch + 1; |
||||||
|
*ppch = *pch ? pch + 1 : L""; |
||||||
|
if (plen) |
||||||
|
*plen = *pch; |
||||||
|
fRet = true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return fRet; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
template <typename ElementType> |
||||||
|
class CoTaskMemPolicy |
||||||
|
{ |
||||||
|
public: |
||||||
|
static ElementType* Alloc(size_t bytes) |
||||||
|
{ |
||||||
|
return (ElementType*)CoTaskMemAlloc(bytes); |
||||||
|
} |
||||||
|
|
||||||
|
static ElementType* Realloc(ElementType* p, size_t bytes) |
||||||
|
{ |
||||||
|
return (ElementType*)CoTaskMemRealloc(p, bytes); |
||||||
|
} |
||||||
|
|
||||||
|
static void Free(ElementType* p) |
||||||
|
{ |
||||||
|
CoTaskMemFree(p); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
template <typename ElementType> |
||||||
|
class LocalMemPolicy |
||||||
|
{ |
||||||
|
public: |
||||||
|
static ElementType* Alloc(size_t bytes) |
||||||
|
{ |
||||||
|
return (ElementType*)LocalAlloc(LMEM_FIXED, bytes); |
||||||
|
} |
||||||
|
|
||||||
|
static ElementType* Realloc(ElementType* p, size_t bytes) |
||||||
|
{ |
||||||
|
return (ElementType*)LocalReAlloc(p, bytes, LMEM_MOVEABLE); |
||||||
|
} |
||||||
|
|
||||||
|
static void Free(ElementType* p) |
||||||
|
{ |
||||||
|
LocalFree(p); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
template <typename Allocator> |
||||||
|
class NativeString |
||||||
|
{ |
||||||
|
public: |
||||||
|
NativeString() : _pszStringData(nullptr), _cchStringData(0), _cchStringDataCapacity(0) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
NativeString(NativeString&& other) noexcept |
||||||
|
: _pszStringData(other._pszStringData) |
||||||
|
, _cchStringData(other._cchStringData) |
||||||
|
, _cchStringDataCapacity(other._cchStringDataCapacity) |
||||||
|
{ |
||||||
|
other._pszStringData = nullptr; |
||||||
|
other._cchStringData = 0; |
||||||
|
other._cchStringDataCapacity = 0; |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
NativeString(const NativeString&) = delete; |
||||||
|
|
||||||
|
public: |
||||||
|
~NativeString() |
||||||
|
{ |
||||||
|
Free(); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT Initialize(const WCHAR* psz, const size_t cch) |
||||||
|
{ |
||||||
|
return _Initialize(psz, cch); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT Initialize(const WCHAR* psz) |
||||||
|
{ |
||||||
|
return _Initialize(psz, s_cchUnknown); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT Initialize(const NativeString& other) |
||||||
|
{ |
||||||
|
return _Initialize(other._pszStringData, other.GetCount()); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT Initialize(HINSTANCE hInstance, UINT uId, WORD wLanguage) |
||||||
|
{ |
||||||
|
HRESULT hr; |
||||||
|
const WCHAR* rgch; |
||||||
|
WORD cch; |
||||||
|
if (ResourceString::FindAndSize(hInstance, uId, wLanguage, &rgch, &cch)) |
||||||
|
{ |
||||||
|
hr = _Initialize(rgch, cch); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
hr = E_FAIL; |
||||||
|
} |
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT Initialize(HINSTANCE hInstance, UINT uId) |
||||||
|
{ |
||||||
|
return Initialize(hInstance, uId, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT Initialize(HKEY hKey, const WCHAR* pszValueName) |
||||||
|
{ |
||||||
|
return _InitializeFromRegistry(hKey, pszValueName, true); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT Initialize(HKEY hKey, const WCHAR* pszSubKey, const WCHAR* pszValueName) |
||||||
|
{ |
||||||
|
HKEY hkeySub; |
||||||
|
HRESULT hr = HRESULT_FROM_WIN32(RegOpenKeyExW(hKey, pszSubKey, 0, KEY_READ, &hkeySub)); |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
hr = Initialize(hkeySub, pszValueName); |
||||||
|
RegCloseKey(hkeySub); |
||||||
|
} |
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT InitializeNoExpand(HKEY hKey, const WCHAR* pszValueName) |
||||||
|
{ |
||||||
|
return _InitializeFromRegistry(hKey, pszValueName, false); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT InitializeNoExpand(HKEY hKey, const WCHAR* pszSubKey, const WCHAR* pszValueName) |
||||||
|
{ |
||||||
|
HKEY hkeySub; |
||||||
|
HRESULT hr = HRESULT_FROM_WIN32(RegOpenKeyExW(hKey, pszSubKey, 0, KEY_READ, &hkeySub)); |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
hr = InitializeNoExpand(hkeySub, pszValueName); |
||||||
|
RegCloseKey(hkeySub); |
||||||
|
} |
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT InitializeFormat(const WCHAR* pszFormat, va_list argList) |
||||||
|
{ |
||||||
|
return _InitializeHelper(pszFormat, argList, [](const WCHAR* pszFormat, va_list argList, WCHAR* pszStringData, size_t cchStringData) -> HRESULT |
||||||
|
{ |
||||||
|
_set_errno(0); |
||||||
|
HRESULT hr = StringCchVPrintfW(pszStringData, cchStringData, pszFormat, argList); |
||||||
|
if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) |
||||||
|
{ |
||||||
|
errno_t err; |
||||||
|
_get_errno(&err); |
||||||
|
if (err == EINVAL) |
||||||
|
{ |
||||||
|
hr = E_INVALIDARG; |
||||||
|
} |
||||||
|
} |
||||||
|
return hr; |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT InitializeFormat(const WCHAR* pszFormat, ...) |
||||||
|
{ |
||||||
|
va_list args; |
||||||
|
va_start(args, pszFormat); |
||||||
|
return InitializeFormat(pszFormat, args); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT InitializeResFormat(HINSTANCE hInstance, UINT uId, ...) |
||||||
|
{ |
||||||
|
va_list argList; |
||||||
|
va_start(argList, uId); |
||||||
|
NativeString spszFormat; |
||||||
|
HRESULT hr = spszFormat.Initialize(hInstance, uId); |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
hr = InitializeFormat(spszFormat._pszStringData, argList); |
||||||
|
} |
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT InitializeResMessage(HINSTANCE hInstance, UINT uId, ...) |
||||||
|
{ |
||||||
|
va_list argList; |
||||||
|
va_start(argList, uId); |
||||||
|
NativeString spszFormat; |
||||||
|
HRESULT hr = spszFormat.Initialize(hInstance, uId); |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
hr = _InitializeHelper(spszFormat._pszStringData, argList, [](const WCHAR* pszFormat, va_list argList, WCHAR* pszStringData, size_t cchStringData) -> HRESULT |
||||||
|
{ |
||||||
|
va_list argListT = argList; |
||||||
|
DWORD cchResult = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, pszFormat, 0, 0, pszStringData, (DWORD)cchStringData, &argListT); |
||||||
|
return ResultFromWin32Bool(cchResult); |
||||||
|
}); |
||||||
|
} |
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
void Free() |
||||||
|
{ |
||||||
|
_Free(); |
||||||
|
} |
||||||
|
|
||||||
|
void Attach(WCHAR* psz) |
||||||
|
{ |
||||||
|
_Attach(psz); |
||||||
|
} |
||||||
|
|
||||||
|
void Attach(WCHAR* psz, const size_t cch) |
||||||
|
{ |
||||||
|
_Attach(psz, cch); |
||||||
|
} |
||||||
|
|
||||||
|
WCHAR* Detach() |
||||||
|
{ |
||||||
|
return _Detach(); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT DetachInitializeIfEmpty(WCHAR** ppsz) |
||||||
|
{ |
||||||
|
*ppsz = nullptr; |
||||||
|
HRESULT hr = S_OK; |
||||||
|
|
||||||
|
if (_pszStringData) |
||||||
|
{ |
||||||
|
hr = Initialize(L""); |
||||||
|
} |
||||||
|
|
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
*ppsz = Detach(); |
||||||
|
} |
||||||
|
|
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
WCHAR** FreeAndGetAddressOf() |
||||||
|
{ |
||||||
|
return _FreeAndGetAddressOf(); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT CopyTo(WCHAR** ppszDest) const |
||||||
|
{ |
||||||
|
HRESULT hr; |
||||||
|
*ppszDest = nullptr; |
||||||
|
if (_pszStringData) |
||||||
|
{ |
||||||
|
NativeString spszT; |
||||||
|
hr = spszT.Initialize(*this); |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
*ppszDest = spszT.Detach(); |
||||||
|
} |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); |
||||||
|
} |
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT CopyTo(WCHAR* pszDest, size_t cchDest) const |
||||||
|
{ |
||||||
|
if (!_pszStringData) |
||||||
|
{ |
||||||
|
if (cchDest) |
||||||
|
*pszDest = 0; |
||||||
|
return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); |
||||||
|
} |
||||||
|
return StringCchCopyW(pszDest, cchDest, _pszStringData); |
||||||
|
} |
||||||
|
|
||||||
|
const WCHAR* Get() const |
||||||
|
{ |
||||||
|
return _Get(); |
||||||
|
} |
||||||
|
|
||||||
|
const WCHAR* GetNonNull() const |
||||||
|
{ |
||||||
|
return _pszStringData ? _pszStringData : L""; |
||||||
|
} |
||||||
|
|
||||||
|
size_t GetCount() |
||||||
|
{ |
||||||
|
return _GetCount(); |
||||||
|
} |
||||||
|
|
||||||
|
size_t GetCount() const |
||||||
|
{ |
||||||
|
return _GetCount(); |
||||||
|
} |
||||||
|
|
||||||
|
bool IsEmpty() const |
||||||
|
{ |
||||||
|
return _IsEmpty(); |
||||||
|
} |
||||||
|
|
||||||
|
bool HasLength() const |
||||||
|
{ |
||||||
|
return !_IsEmpty(); |
||||||
|
} |
||||||
|
|
||||||
|
int CompareOrdinal(const WCHAR* psz, const size_t cch) const |
||||||
|
{ |
||||||
|
return CompareStringOrdinal(GetNonNull(), (int)GetCount(), psz ? psz : L"", psz ? (int)cch : 0, FALSE); |
||||||
|
} |
||||||
|
|
||||||
|
int CompareOrdinal(const WCHAR* psz) const |
||||||
|
{ |
||||||
|
return CompareOrdinal(psz, s_cchUnknown); |
||||||
|
} |
||||||
|
|
||||||
|
int CompareOrdinal(const NativeString& other) const |
||||||
|
{ |
||||||
|
return CompareOrdinal(other.GetNonNull(), other.GetCount()); |
||||||
|
} |
||||||
|
|
||||||
|
int CompareOrdinalIgnoreCase(const WCHAR* psz, const size_t cch) const |
||||||
|
{ |
||||||
|
return CompareStringOrdinal(GetNonNull(), (int)GetCount(), psz ? psz : L"", psz ? (int)cch : 0, TRUE); |
||||||
|
} |
||||||
|
|
||||||
|
int CompareOrdinalIgnoreCase(const WCHAR* psz) const |
||||||
|
{ |
||||||
|
return CompareOrdinalIgnoreCase(psz, s_cchUnknown); |
||||||
|
} |
||||||
|
|
||||||
|
int CompareOrdinalIgnoreCase(const NativeString& other) const |
||||||
|
{ |
||||||
|
return CompareOrdinalIgnoreCase(other.GetNonNull(), other.GetCount()); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT Concat(const WCHAR* psz, const size_t cch) |
||||||
|
{ |
||||||
|
return _Concat(psz, cch); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT Concat(WCHAR c) |
||||||
|
{ |
||||||
|
return _Concat(c); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT Concat(const WCHAR* psz) |
||||||
|
{ |
||||||
|
return _Concat(psz, psz ? wcslen(psz) : 0); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT Concat(const NativeString& other) |
||||||
|
{ |
||||||
|
return _Concat(other.Get(), other.GetCount()); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT Concat(HINSTANCE hInstance, UINT uId, WORD wLanguage) |
||||||
|
{ |
||||||
|
HRESULT hr; |
||||||
|
const WCHAR* rgch; |
||||||
|
WORD cch; |
||||||
|
if (ResourceString::FindAndSize(hInstance, uId, wLanguage, &rgch, &cch)) |
||||||
|
{ |
||||||
|
hr = _Concat(rgch, cch); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); |
||||||
|
} |
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT Concat(HINSTANCE hInstance, UINT uId) |
||||||
|
{ |
||||||
|
return Concat(hInstance, uId, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT ConcatFormat(const WCHAR* pszFormat, va_list argList) |
||||||
|
{ |
||||||
|
if (IsEmpty()) |
||||||
|
{ |
||||||
|
return InitializeFormat(pszFormat, argList); |
||||||
|
} |
||||||
|
NativeString strT; |
||||||
|
HRESULT hr = strT.InitializeFormat(pszFormat, argList); |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
hr = Concat(strT); |
||||||
|
} |
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT ConcatFormat(const WCHAR* pszFormat, ...) |
||||||
|
{ |
||||||
|
va_list argList; |
||||||
|
va_start(argList, pszFormat); |
||||||
|
return ConcatFormat(pszFormat, argList); |
||||||
|
} |
||||||
|
|
||||||
|
bool RemoveAt(size_t iElem, size_t cchElem) |
||||||
|
{ |
||||||
|
return _RemoveAt(iElem, cchElem); |
||||||
|
} |
||||||
|
|
||||||
|
bool TrimStart(const WCHAR* pszTrim) |
||||||
|
{ |
||||||
|
return _TrimStart(pszTrim); |
||||||
|
} |
||||||
|
|
||||||
|
bool TrimEnd(const WCHAR* pszTrim) |
||||||
|
{ |
||||||
|
return _TrimEnd(pszTrim); |
||||||
|
} |
||||||
|
|
||||||
|
inline static const WCHAR* const s_pszTrimWhitespaceCharacterSet = |
||||||
|
L"\u0020" // Space
|
||||||
|
L"\u0009" // Tab
|
||||||
|
L"\u3000" // Ideographic Space
|
||||||
|
L"\u17D2" // Khmer Sign Coeng
|
||||||
|
L"\u0F0B" // Tibetan Mark Intersyllabic Tsheg
|
||||||
|
L"\u1680" // Ogham Space Mark
|
||||||
|
L"\u180E" // Mongolian Vowel Separator
|
||||||
|
; |
||||||
|
|
||||||
|
bool TrimWhitespace() |
||||||
|
{ |
||||||
|
bool fWasCharacterTrimmedEnd = _TrimEnd(s_pszTrimWhitespaceCharacterSet); |
||||||
|
bool fWasCharacterTrimmedStart = _TrimStart(s_pszTrimWhitespaceCharacterSet); |
||||||
|
return fWasCharacterTrimmedStart || fWasCharacterTrimmedEnd; |
||||||
|
} |
||||||
|
|
||||||
|
void ReplaceChars(const WCHAR wcFind, const WCHAR wcReplace) |
||||||
|
{ |
||||||
|
_EnsureCount(); |
||||||
|
for (size_t i = 0; i < _cchStringData; i++) |
||||||
|
{ |
||||||
|
if (_pszStringData[i] == wcFind) |
||||||
|
_pszStringData[i] = wcReplace; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
NativeString& operator=(NativeString&& other) noexcept |
||||||
|
{ |
||||||
|
_Free(); |
||||||
|
_pszStringData = other._pszStringData; |
||||||
|
_cchStringData = other._cchStringData; |
||||||
|
_cchStringDataCapacity = other._cchStringDataCapacity; |
||||||
|
other._pszStringData = nullptr; |
||||||
|
other._cchStringData = 0; |
||||||
|
other._cchStringDataCapacity = 0; |
||||||
|
return *this; |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
NativeString& operator=(const NativeString& other) = delete; |
||||||
|
|
||||||
|
public: |
||||||
|
WCHAR** operator&() |
||||||
|
{ |
||||||
|
return FreeAndGetAddressOf(); |
||||||
|
} |
||||||
|
|
||||||
|
/*WCHAR* operator*() const
|
||||||
|
{ |
||||||
|
return Get(); |
||||||
|
}*/ |
||||||
|
|
||||||
|
bool operator==(const WCHAR* pszOther) const |
||||||
|
{ |
||||||
|
return pszOther ? CompareOrdinal(pszOther) == CSTR_EQUAL : !_pszStringData; |
||||||
|
} |
||||||
|
|
||||||
|
bool operator!=(const WCHAR* pszOther) const |
||||||
|
{ |
||||||
|
return !operator==(pszOther); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT AppendMayTruncate(const WCHAR* psz, size_t cchMaxCapacity) |
||||||
|
{ |
||||||
|
return _ConcatMayTruncate(psz, cchMaxCapacity); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT EnsureCapacity(size_t cchDesired) |
||||||
|
{ |
||||||
|
return _EnsureCapacity(cchDesired); |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
void _EnsureCount() |
||||||
|
{ |
||||||
|
if (_cchStringData == s_cchUnknown) |
||||||
|
{ |
||||||
|
_cchStringData = _pszStringData ? wcslen(_pszStringData) : 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT _EnsureCapacity(size_t cchDesired) |
||||||
|
{ |
||||||
|
size_t cchCapacityCur; |
||||||
|
HRESULT hr = SizeTAdd(cchDesired, 1, &cchCapacityCur); |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
if (_cchStringDataCapacity == s_cchUnknown) |
||||||
|
{ |
||||||
|
_EnsureCount(); |
||||||
|
_cchStringDataCapacity = _pszStringData ? _cchStringData + 1 : 0; |
||||||
|
} |
||||||
|
if (_cchStringDataCapacity == 0) // First allocation
|
||||||
|
{ |
||||||
|
size_t cbDesired; |
||||||
|
hr = SizeTMult(cchCapacityCur, sizeof(WCHAR), &cbDesired); |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
WCHAR* pvArrayT = Allocator::Alloc(cbDesired); |
||||||
|
hr = pvArrayT ? S_OK : E_OUTOFMEMORY; |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
_cchStringDataCapacity = cchCapacityCur; |
||||||
|
_pszStringData = pvArrayT; |
||||||
|
pvArrayT[0] = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
else if (cchCapacityCur > _cchStringDataCapacity) // Growing
|
||||||
|
{ |
||||||
|
size_t celemNew; |
||||||
|
hr = SizeTMult(_cchStringDataCapacity, 2, &celemNew); // Double the capacity
|
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
if (celemNew - _cchStringDataCapacity > 2048) |
||||||
|
celemNew = _cchStringDataCapacity + 2048; // Make sure it doesn't grow too much; TODO Check disassembly
|
||||||
|
if (cchCapacityCur <= celemNew) |
||||||
|
cchCapacityCur = celemNew; |
||||||
|
WCHAR* pvArrayT = Allocator::Realloc(_pszStringData, sizeof(WCHAR) * cchCapacityCur); |
||||||
|
hr = pvArrayT ? S_OK : E_OUTOFMEMORY; |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
_cchStringDataCapacity = cchCapacityCur; |
||||||
|
_pszStringData = pvArrayT; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
bool _IsEmpty() const |
||||||
|
{ |
||||||
|
return !_pszStringData || !_pszStringData[0]; |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT _Initialize(const WCHAR* psz, size_t cch) |
||||||
|
{ |
||||||
|
size_t cchDesired = cch; |
||||||
|
size_t cchStringData; |
||||||
|
HRESULT hr = S_OK; |
||||||
|
if (psz) |
||||||
|
{ |
||||||
|
if (cchDesired == s_cchUnknown) |
||||||
|
{ |
||||||
|
cchDesired = wcslen(psz); |
||||||
|
cchStringData = cchDesired; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
cchStringData = _NativeString_Min<size_t>(cchDesired, wcslen(psz)); // @MOD Prevent double evaluation
|
||||||
|
} |
||||||
|
hr = _EnsureCapacity(cchDesired); |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
StringCchCopyNW(_pszStringData, cchDesired + 1, psz, cchStringData); |
||||||
|
_cchStringData = cchStringData; |
||||||
|
} |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
_Free(); |
||||||
|
} |
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
HRESULT _InitializeHelper(const WCHAR* pszFormat, va_list argList, const T& callback) |
||||||
|
{ |
||||||
|
HRESULT hr; |
||||||
|
size_t cchCapacityGuess = 32; |
||||||
|
do |
||||||
|
{ |
||||||
|
hr = _EnsureCapacity(cchCapacityGuess); |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
hr = callback(pszFormat, argList, _pszStringData, _cchStringDataCapacity); |
||||||
|
if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) |
||||||
|
{ |
||||||
|
size_t cchCapacityT; |
||||||
|
hr = SizeTAdd(_cchStringDataCapacity, 32, &cchCapacityT); |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
cchCapacityGuess = cchCapacityT; |
||||||
|
} |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
while (SUCCEEDED(hr)); |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
_cchStringData = s_cchUnknown; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
_Free(); |
||||||
|
} |
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT _InitializeFromRegistry(HKEY hKey, const WCHAR* pszValueName, bool fExpand) |
||||||
|
{ |
||||||
|
DWORD dwType; |
||||||
|
DWORD cbT = 0; |
||||||
|
LSTATUS lRes = RegQueryValueExW(hKey, pszValueName, nullptr, &dwType, nullptr, &cbT); |
||||||
|
HRESULT hr = HRESULT_FROM_WIN32(lRes); |
||||||
|
if (SUCCEEDED(hr) && ((dwType != REG_SZ && dwType != REG_EXPAND_SZ) || cbT == 0 || (cbT & 1) != 0)) |
||||||
|
{ |
||||||
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); |
||||||
|
} |
||||||
|
|
||||||
|
WCHAR* pszT = nullptr; |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
pszT = Allocator::Alloc(cbT); |
||||||
|
hr = pszT ? S_OK : E_OUTOFMEMORY; |
||||||
|
} |
||||||
|
|
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
lRes = RegQueryValueExW(hKey, pszValueName, nullptr, &dwType, (LPBYTE)pszT, &cbT); |
||||||
|
hr = HRESULT_FROM_WIN32(lRes); |
||||||
|
} |
||||||
|
|
||||||
|
DWORD cchT = 0; |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
cchT = (cbT / sizeof(WCHAR)) - 1; |
||||||
|
if (dwType == REG_EXPAND_SZ && fExpand) |
||||||
|
{ |
||||||
|
DWORD cchBuffer = ExpandEnvironmentStringsW(pszT, nullptr, 0); |
||||||
|
if (cchBuffer != 0) |
||||||
|
{ |
||||||
|
WCHAR* pszExpand = Allocator::Alloc(sizeof(WCHAR) * cchBuffer); |
||||||
|
hr = pszExpand ? S_OK : E_OUTOFMEMORY; |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
DWORD cchResult = ExpandEnvironmentStringsW(pszT, pszExpand, cchBuffer); |
||||||
|
hr = ResultFromWin32Count(cchResult, cchBuffer); |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
Allocator::Free(pszT); |
||||||
|
pszT = pszExpand; |
||||||
|
cchT = cchResult - 1; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
Allocator::Free(pszExpand); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
if (!pszT[cchT]) |
||||||
|
{ |
||||||
|
_Attach(pszT, cchT + 1); |
||||||
|
pszT = nullptr; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Allocator::Free(pszT); |
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
size_t _GetCount() |
||||||
|
{ |
||||||
|
_EnsureCount(); |
||||||
|
return _cchStringData; |
||||||
|
} |
||||||
|
|
||||||
|
size_t _GetCount() const |
||||||
|
{ |
||||||
|
if (_cchStringData != s_cchUnknown) |
||||||
|
return _cchStringData; |
||||||
|
return _pszStringData ? wcslen(_pszStringData) : 0; |
||||||
|
} |
||||||
|
|
||||||
|
const WCHAR* _Get() const |
||||||
|
{ |
||||||
|
return _pszStringData; |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT _Concat(const WCHAR c) |
||||||
|
{ |
||||||
|
WCHAR sz[2] = { c, 0 }; |
||||||
|
return _Concat(sz, 1); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT _Concat(const WCHAR* psz, const size_t cch) |
||||||
|
{ |
||||||
|
HRESULT hr = S_OK; |
||||||
|
if (psz) |
||||||
|
{ |
||||||
|
_EnsureCount(); |
||||||
|
hr = _EnsureCapacity(cch + _cchStringData); |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
StringCchCopyNW(&_pszStringData[_cchStringData], cch + 1, psz, cch); |
||||||
|
_cchStringData += cch; |
||||||
|
} |
||||||
|
} |
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT _ConcatMayTruncate(const WCHAR* psz, size_t cchMaxCapacity) |
||||||
|
{ |
||||||
|
_EnsureCount(); |
||||||
|
HRESULT hr = S_OK; |
||||||
|
if (cchMaxCapacity > _cchStringData) |
||||||
|
{ |
||||||
|
size_t cchDesired = _NativeString_Min<size_t>(cchMaxCapacity - _cchStringData, wcslen(psz)); // @MOD Prevent double evaluation
|
||||||
|
hr = _Concat(psz, cchDesired); |
||||||
|
} |
||||||
|
else if (cchMaxCapacity < _cchStringData) |
||||||
|
{ |
||||||
|
_cchStringData = cchMaxCapacity; |
||||||
|
_pszStringData[cchMaxCapacity] = 0; |
||||||
|
} |
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
bool _RemoveAt(size_t iElem, size_t cchElem) |
||||||
|
{ |
||||||
|
_EnsureCount(); |
||||||
|
|
||||||
|
bool fRet = false; |
||||||
|
|
||||||
|
if (iElem < _cchStringData) |
||||||
|
{ |
||||||
|
cchElem = _NativeString_Min<size_t>(cchElem, _cchStringData - iElem); // @MOD Prevent double evaluation
|
||||||
|
if (cchElem) |
||||||
|
{ |
||||||
|
memmove(&_pszStringData[iElem], &_pszStringData[iElem + cchElem], sizeof(WCHAR) * (_cchStringData - iElem - cchElem)); |
||||||
|
_cchStringData -= cchElem; |
||||||
|
} |
||||||
|
_pszStringData[_cchStringData] = 0; |
||||||
|
fRet = true; |
||||||
|
} |
||||||
|
|
||||||
|
return fRet; |
||||||
|
} |
||||||
|
|
||||||
|
bool _TrimStart(const WCHAR* pszTrim) |
||||||
|
{ |
||||||
|
_EnsureCount(); |
||||||
|
|
||||||
|
bool fNeedsTrimming = false; |
||||||
|
|
||||||
|
size_t cch; |
||||||
|
for (cch = 0; cch < _cchStringData; ++cch) |
||||||
|
{ |
||||||
|
if (!wcschr(pszTrim, _pszStringData[cch])) |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
if (cch) |
||||||
|
{ |
||||||
|
fNeedsTrimming = true; |
||||||
|
memmove(_pszStringData, &_pszStringData[cch], sizeof(WCHAR) * (_cchStringData - cch) + sizeof(WCHAR)); |
||||||
|
_cchStringData -= cch; |
||||||
|
} |
||||||
|
|
||||||
|
return fNeedsTrimming; |
||||||
|
} |
||||||
|
|
||||||
|
bool _TrimEnd(const WCHAR* pszTrim) |
||||||
|
{ |
||||||
|
_EnsureCount(); |
||||||
|
|
||||||
|
size_t cch; |
||||||
|
for (cch = _cchStringData; cch; --cch) |
||||||
|
{ |
||||||
|
if (!wcschr(pszTrim, _pszStringData[cch - 1])) |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
bool fNeedsTrimming = false; |
||||||
|
|
||||||
|
if (cch != _cchStringData) |
||||||
|
{ |
||||||
|
fNeedsTrimming = true; |
||||||
|
_pszStringData[cch] = 0; |
||||||
|
_cchStringData = cch; |
||||||
|
} |
||||||
|
|
||||||
|
return fNeedsTrimming; |
||||||
|
} |
||||||
|
|
||||||
|
void _Free() |
||||||
|
{ |
||||||
|
if (_pszStringData) |
||||||
|
{ |
||||||
|
Allocator::Free(_pszStringData); |
||||||
|
_pszStringData = nullptr; |
||||||
|
} |
||||||
|
_cchStringData = 0; |
||||||
|
_cchStringDataCapacity = 0; |
||||||
|
} |
||||||
|
|
||||||
|
void _Attach(WCHAR* psz) |
||||||
|
{ |
||||||
|
return _Attach(psz, wcslen(psz) + 1); |
||||||
|
} |
||||||
|
|
||||||
|
void _Attach(WCHAR* psz, const size_t cch) |
||||||
|
{ |
||||||
|
_Free(); |
||||||
|
if (psz && cch) |
||||||
|
{ |
||||||
|
_pszStringData = psz; |
||||||
|
_cchStringData = cch - 1; |
||||||
|
_cchStringDataCapacity = cch; |
||||||
|
psz[cch - 1] = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
WCHAR* _Detach() |
||||||
|
{ |
||||||
|
WCHAR* pszStringData = _pszStringData; |
||||||
|
_pszStringData = nullptr; |
||||||
|
_cchStringData = 0; |
||||||
|
_cchStringDataCapacity = 0; |
||||||
|
return pszStringData; |
||||||
|
} |
||||||
|
|
||||||
|
WCHAR** _FreeAndGetAddressOf() |
||||||
|
{ |
||||||
|
_Free(); |
||||||
|
_cchStringData = s_cchUnknown; |
||||||
|
_cchStringDataCapacity = s_cchUnknown; |
||||||
|
return &_pszStringData; |
||||||
|
} |
||||||
|
|
||||||
|
static const size_t s_cchUnknown = -1; |
||||||
|
|
||||||
|
WCHAR* _pszStringData; |
||||||
|
size_t _cchStringData; |
||||||
|
size_t _cchStringDataCapacity; |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
static FORCEINLINE constexpr const T& (_NativeString_Min)(const T& a, const T& b) |
||||||
|
{ |
||||||
|
return a < b ? a : b; |
||||||
|
} |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
typedef Windows::Internal::NativeString<Windows::Internal::CoTaskMemPolicy<WCHAR>> CoTaskMemNativeString; |
||||||
@ -0,0 +1,46 @@ |
|||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <wrl/client.h> |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
class CRefCountedObject : public IUnknown, public T |
||||||
|
{ |
||||||
|
public: |
||||||
|
template <typename ...TArgs> |
||||||
|
CRefCountedObject(TArgs&& ...args) |
||||||
|
: T(std::forward<TArgs>(args)...) |
||||||
|
, _cRef(0) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
virtual ~CRefCountedObject() |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject) override |
||||||
|
{ |
||||||
|
*ppvObject = nullptr; |
||||||
|
return E_NOTIMPL; |
||||||
|
} |
||||||
|
|
||||||
|
STDMETHODIMP_(ULONG) AddRef() override |
||||||
|
{ |
||||||
|
return InterlockedIncrement(&_cRef); |
||||||
|
} |
||||||
|
|
||||||
|
STDMETHODIMP_(ULONG) Release() override |
||||||
|
{ |
||||||
|
ULONG refCount = InterlockedDecrement(&_cRef); |
||||||
|
if (refCount == 0) |
||||||
|
delete this; |
||||||
|
return refCount; |
||||||
|
} |
||||||
|
|
||||||
|
ULONG _cRef; |
||||||
|
}; |
||||||
|
|
||||||
|
template <typename T, typename ...TArgs> |
||||||
|
Microsoft::WRL::ComPtr<CRefCountedObject<T>> CreateRefCountedObj(TArgs&& ...args) |
||||||
|
{ |
||||||
|
return new(std::nothrow) CRefCountedObject<T>(std::forward<TArgs>(args)...); |
||||||
|
} |
||||||
@ -0,0 +1,29 @@ |
|||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <Windows.h> |
||||||
|
|
||||||
|
inline HRESULT ResultFromWin32(__in DWORD dwErr) |
||||||
|
{ |
||||||
|
return HRESULT_FROM_WIN32(dwErr); |
||||||
|
} |
||||||
|
|
||||||
|
inline HRESULT ResultFromLastError() |
||||||
|
{ |
||||||
|
return ResultFromWin32(GetLastError()); |
||||||
|
} |
||||||
|
|
||||||
|
inline HRESULT ResultFromKnownLastError() |
||||||
|
{ |
||||||
|
HRESULT hr = ResultFromLastError(); |
||||||
|
return (SUCCEEDED(hr) ? E_FAIL : hr); |
||||||
|
} |
||||||
|
|
||||||
|
inline HRESULT ResultFromWin32Bool(BOOL b) |
||||||
|
{ |
||||||
|
return b ? S_OK : ResultFromKnownLastError(); |
||||||
|
} |
||||||
|
|
||||||
|
inline HRESULT ResultFromWin32Count(UINT cchResult, UINT cchBuffer) |
||||||
|
{ |
||||||
|
return cchResult && cchResult <= cchBuffer ? S_OK : ResultFromWin32(ERROR_INSUFFICIENT_BUFFER); |
||||||
|
} |
||||||
@ -0,0 +1,583 @@ |
|||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <Windows.h> |
||||||
|
#include <type_traits> |
||||||
|
|
||||||
|
#include "ContainerPolicies.h" |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
class CSimpleArrayStandardCompareHelper |
||||||
|
{ |
||||||
|
public: |
||||||
|
int Compare(const T& t1, const T& t2) const |
||||||
|
{ |
||||||
|
return t2 == t1 ? 0 : t2 < t1 ? 1 : -1; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
class CSimpleArrayCaseInsensitiveOrdinalStringCompareHelper |
||||||
|
{ |
||||||
|
public: |
||||||
|
int Compare(const WCHAR* psz1, const WCHAR* psz2) const |
||||||
|
{ |
||||||
|
return CompareStringOrdinal(psz1, -1, psz2, -1, TRUE) - CSTR_EQUAL; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
class CSimpleArrayStandardMergeHelper |
||||||
|
{ |
||||||
|
}; |
||||||
|
|
||||||
|
template < |
||||||
|
typename T, |
||||||
|
typename CompareHelper |
||||||
|
> |
||||||
|
class CTSimpleFixedArray |
||||||
|
{ |
||||||
|
public: |
||||||
|
T* _parray; |
||||||
|
size_t _celem; |
||||||
|
|
||||||
|
CTSimpleFixedArray() |
||||||
|
: _parray(nullptr) |
||||||
|
, _celem(0) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
size_t GetSize() const { return _celem; } |
||||||
|
|
||||||
|
T& operator[](size_t iElem) { return _parray[iElem]; } |
||||||
|
const T& operator[](size_t iElem) const { return _parray[iElem]; } |
||||||
|
|
||||||
|
HRESULT GetAt(size_t iElem, T& tOut) const |
||||||
|
{ |
||||||
|
HRESULT hr = TYPE_E_OUTOFBOUNDS; |
||||||
|
if (iElem < _celem) |
||||||
|
{ |
||||||
|
tOut = _parray[iElem]; |
||||||
|
hr = S_OK; |
||||||
|
} |
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
T* GetData() const { return _parray; } |
||||||
|
T* begin() { return _parray; } |
||||||
|
T* begin() const { return _parray; } |
||||||
|
T* end() { return _parray + _celem; } |
||||||
|
T* end() const { return _parray + _celem; } |
||||||
|
|
||||||
|
HRESULT Find(const T& t, size_t* piElem, size_t iStartAt = 0) const |
||||||
|
{ |
||||||
|
return FindEx(CompareHelper(), t, piElem, iStartAt); |
||||||
|
} |
||||||
|
|
||||||
|
template <typename Comparer> |
||||||
|
HRESULT FindEx(const Comparer& tcompare, const T& t, size_t* piElem, size_t iStartAt = 0) const |
||||||
|
{ |
||||||
|
*piElem = 0; |
||||||
|
for (size_t i = iStartAt; i < _celem; ++i) |
||||||
|
{ |
||||||
|
if (tcompare.Compare(_parray[i], t) == 0) |
||||||
|
{ |
||||||
|
*piElem = i; |
||||||
|
return S_OK; |
||||||
|
} |
||||||
|
} |
||||||
|
return TYPE_E_ELEMENTNOTFOUND; |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT BinarySearch(const T& t, size_t* piElem) const |
||||||
|
{ |
||||||
|
return BinarySearchEx(CompareHelper(), t, piElem); |
||||||
|
} |
||||||
|
|
||||||
|
template <typename Comparer> |
||||||
|
HRESULT BinarySearchEx(const Comparer& tcompare, const T& t, size_t* piElem) const |
||||||
|
{ |
||||||
|
*piElem = 0; |
||||||
|
|
||||||
|
HRESULT hr = TYPE_E_ELEMENTNOTFOUND; |
||||||
|
|
||||||
|
if (_celem != 0) |
||||||
|
{ |
||||||
|
hr = S_OK; |
||||||
|
|
||||||
|
size_t iLow = 0; |
||||||
|
size_t iHigh = _celem - 1; |
||||||
|
while (true) |
||||||
|
{ |
||||||
|
size_t iMid = (iLow + iHigh) / 2; |
||||||
|
|
||||||
|
int compare = tcompare.Compare(_parray[iMid], t); |
||||||
|
if (compare > 0) |
||||||
|
{ |
||||||
|
if (iMid != 0) |
||||||
|
{ |
||||||
|
iHigh = iMid - 1; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
hr = TYPE_E_ELEMENTNOTFOUND; |
||||||
|
} |
||||||
|
} |
||||||
|
else if (compare < 0) |
||||||
|
{ |
||||||
|
iLow = iMid + 1; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
for (; iMid != 0; --iMid) |
||||||
|
{ |
||||||
|
if (tcompare.Compare(_parray[iMid - 1], t) != 0) |
||||||
|
break; |
||||||
|
} |
||||||
|
*piElem = iMid; |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
if (iHigh < iLow) |
||||||
|
hr = TYPE_E_ELEMENTNOTFOUND; |
||||||
|
|
||||||
|
if (FAILED(hr)) |
||||||
|
{ |
||||||
|
*piElem = compare < 0 ? iLow : iMid; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
template <typename TCallback> |
||||||
|
void ForEach(const TCallback& callback) const // @MOD Pass callback by reference
|
||||||
|
{ |
||||||
|
for (size_t iElement = 0; iElement < _celem; ++iElement) |
||||||
|
{ |
||||||
|
callback(iElement, _parray[iElement]); |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
template < |
||||||
|
typename T, |
||||||
|
size_t MaxSize, |
||||||
|
typename Allocator, |
||||||
|
typename CompareHelper, |
||||||
|
typename MergeHelper = CSimpleArrayStandardMergeHelper<T> |
||||||
|
> |
||||||
|
class CTSimpleArray : public CTSimpleFixedArray<T, CompareHelper> |
||||||
|
{ |
||||||
|
public: |
||||||
|
T* _parrayT; |
||||||
|
size_t _celemCapacity; |
||||||
|
|
||||||
|
CTSimpleArray() |
||||||
|
: CTSimpleFixedArray<T, CompareHelper>() |
||||||
|
, _parrayT(nullptr) |
||||||
|
, _celemCapacity(0) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
~CTSimpleArray() |
||||||
|
{ |
||||||
|
RemoveAll(); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT Add(const T& t, size_t* piElemInsertedAt = nullptr) |
||||||
|
{ |
||||||
|
return _Add(t, piElemInsertedAt); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT Add(T&& t, size_t* piElemInsertedAt = nullptr) |
||||||
|
{ |
||||||
|
return _Add(std::move(t), piElemInsertedAt); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT InsertAt(const T& t, size_t iElem) |
||||||
|
{ |
||||||
|
return _InsertAt(t, iElem); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT InsertAt(T&& t, size_t iElem) |
||||||
|
{ |
||||||
|
return _InsertAt(std::move(t), iElem); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT SetAtIndex(size_t iElem, const T& t) |
||||||
|
{ |
||||||
|
return _SetAtIndex(iElem, t); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT SetAtIndex(size_t iElem, T&& t) |
||||||
|
{ |
||||||
|
return _SetAtIndex(iElem, std::move(t)); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT Remove(const T& t, size_t* piElemRemovedAt = nullptr) |
||||||
|
{ |
||||||
|
if (piElemRemovedAt) |
||||||
|
*piElemRemovedAt = 0; |
||||||
|
|
||||||
|
size_t iElem; |
||||||
|
HRESULT hr = this->Find(t, &iElem); |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
hr = RemoveAt(iElem); |
||||||
|
if (SUCCEEDED(hr) && piElemRemovedAt) |
||||||
|
{ |
||||||
|
*piElemRemovedAt = iElem; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT RemoveAt(size_t iElem) |
||||||
|
{ |
||||||
|
if (iElem >= this->_celem) |
||||||
|
return TYPE_E_OUTOFBOUNDS; |
||||||
|
if constexpr (!std::is_trivially_destructible_v<T>) |
||||||
|
this->_parray[iElem].~T(); |
||||||
|
if (iElem != this->_celem - 1) |
||||||
|
memmove(std::addressof(this->_parray[iElem]), std::addressof(this->_parray[iElem + 1]), sizeof(T) * (this->_celem - iElem - 1)); |
||||||
|
--this->_celem; |
||||||
|
return S_OK; |
||||||
|
} |
||||||
|
|
||||||
|
void RemoveAll() |
||||||
|
{ |
||||||
|
if (this->_parray) |
||||||
|
{ |
||||||
|
if constexpr (!std::is_trivially_destructible_v<T>) |
||||||
|
{ |
||||||
|
for (size_t i = 0; i < this->_celem; ++i) |
||||||
|
this->_parray[i].~T(); |
||||||
|
} |
||||||
|
Allocator::Destroy(this->_parray); |
||||||
|
this->_parray = nullptr; |
||||||
|
} |
||||||
|
this->_celem = 0; |
||||||
|
_celemCapacity = 0; |
||||||
|
} |
||||||
|
|
||||||
|
void TransferData(CTSimpleArray* other) |
||||||
|
{ |
||||||
|
RemoveAll(); |
||||||
|
this->_parray = other->_parray; |
||||||
|
this->_celem = other->_celem; |
||||||
|
this->_parrayT = other->_parrayT; |
||||||
|
this->_celemCapacity = other->_celemCapacity; |
||||||
|
other->_parray = nullptr; |
||||||
|
other->_celem = 0; |
||||||
|
other->_parrayT = nullptr; |
||||||
|
other->_celemCapacity = 0; |
||||||
|
} |
||||||
|
|
||||||
|
size_t GetCapacity() const |
||||||
|
{ |
||||||
|
return _celemCapacity; |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT Sort() |
||||||
|
{ |
||||||
|
return SortEx(CompareHelper()); |
||||||
|
} |
||||||
|
|
||||||
|
template <typename Comparer> |
||||||
|
HRESULT SortEx(const Comparer& tcompare) |
||||||
|
{ |
||||||
|
HRESULT hr = S_OK; |
||||||
|
|
||||||
|
if (this->_celem > 1) |
||||||
|
{ |
||||||
|
_parrayT = nullptr; |
||||||
|
hr = Allocator::ReallocArray(nullptr, this->_celem / 2, &_parrayT); |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
_MergeSort(tcompare, 0, this->_celem); |
||||||
|
Allocator::Destroy(_parrayT); |
||||||
|
_parrayT = nullptr; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT _EnsureCapacity(size_t celemCapacityDesired, size_t celemMaxCapacity = 4096) |
||||||
|
{ |
||||||
|
HRESULT hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); |
||||||
|
if (celemCapacityDesired > MaxSize) |
||||||
|
return hr; |
||||||
|
|
||||||
|
// If we have enough capacity, we're done
|
||||||
|
hr = S_OK; |
||||||
|
size_t celemCapacityCur = _celemCapacity; |
||||||
|
if (celemCapacityDesired <= celemCapacityCur) |
||||||
|
return hr; |
||||||
|
|
||||||
|
// Double the capacity
|
||||||
|
size_t celemCapacityT; |
||||||
|
hr = SizeTMult(celemCapacityCur, 2, &celemCapacityT); |
||||||
|
if (FAILED(hr)) |
||||||
|
return hr; |
||||||
|
|
||||||
|
// Make sure we don't grow too much
|
||||||
|
celemCapacityT = celemCapacityT - celemCapacityCur > celemMaxCapacity ? celemCapacityCur + celemMaxCapacity : celemCapacityT; |
||||||
|
|
||||||
|
// Cap at desired capacity and max capacity
|
||||||
|
celemCapacityT = celemCapacityDesired > celemCapacityT || celemCapacityT <= MaxSize ? max(celemCapacityDesired, celemCapacityT) : MaxSize; |
||||||
|
|
||||||
|
// Realloc
|
||||||
|
T* pvArrayT; |
||||||
|
hr = Allocator::ReallocArray(this->_parray, celemCapacityT, &pvArrayT); |
||||||
|
if (FAILED(hr)) |
||||||
|
return hr; |
||||||
|
|
||||||
|
_celemCapacity = celemCapacityT; |
||||||
|
this->_parray = pvArrayT; |
||||||
|
|
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT _MakeRoomAt(size_t iElem) |
||||||
|
{ |
||||||
|
HRESULT hr = S_OK; |
||||||
|
|
||||||
|
size_t cElemGrowTo = max(this->_celem, iElem) + 1; |
||||||
|
if (cElemGrowTo > _celemCapacity) |
||||||
|
{ |
||||||
|
hr = _EnsureCapacity(cElemGrowTo); |
||||||
|
} |
||||||
|
|
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
if (iElem < this->_celem) |
||||||
|
memmove(std::addressof(this->_parray[iElem + 1]), std::addressof(this->_parray[iElem]), sizeof(T) * (this->_celem - iElem)); |
||||||
|
this->_celem = cElemGrowTo; |
||||||
|
} |
||||||
|
|
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
template <typename ArgType> |
||||||
|
void _InternalSetAtIndex(size_t iElem, ArgType&& t) |
||||||
|
{ |
||||||
|
T* newPos = std::addressof(this->_parray[iElem]); |
||||||
|
if (newPos) |
||||||
|
new(newPos) T(std::forward<ArgType>(t)); |
||||||
|
} |
||||||
|
|
||||||
|
template <typename ArgType> |
||||||
|
HRESULT _Add(ArgType&& t, size_t* piElemInsertedAt) |
||||||
|
{ |
||||||
|
if (piElemInsertedAt) |
||||||
|
*piElemInsertedAt = 0; |
||||||
|
|
||||||
|
HRESULT hr = S_OK; |
||||||
|
|
||||||
|
if (this->_celem == _celemCapacity) |
||||||
|
{ |
||||||
|
hr = _EnsureCapacity(_celemCapacity + 1); |
||||||
|
} |
||||||
|
|
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
_InternalSetAtIndex(this->_celem++, std::forward<ArgType>(t)); |
||||||
|
if (piElemInsertedAt) |
||||||
|
*piElemInsertedAt = this->_celem - 1; |
||||||
|
} |
||||||
|
|
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
template <typename ArgType> |
||||||
|
HRESULT _InsertAt(ArgType&& t, size_t iElem) |
||||||
|
{ |
||||||
|
HRESULT hr = _MakeRoomAt(iElem); |
||||||
|
|
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
_InternalSetAtIndex(iElem, std::forward<ArgType>(t)); |
||||||
|
} |
||||||
|
|
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
template <typename ArgType> |
||||||
|
HRESULT _SetAtIndex(size_t iElem, ArgType&& t) |
||||||
|
{ |
||||||
|
HRESULT hr = TYPE_E_OUTOFBOUNDS; |
||||||
|
|
||||||
|
if (iElem < this->_celem) |
||||||
|
{ |
||||||
|
_InternalSetAtIndex(iElem, std::forward<ArgType>(t)); |
||||||
|
hr = S_OK; |
||||||
|
} |
||||||
|
|
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
template <typename Comparer> |
||||||
|
void _MergeThem(const Comparer& tcompare, size_t iFirst, size_t cElems) |
||||||
|
{ |
||||||
|
size_t cHalf = cElems / 2; |
||||||
|
T* parraySrc = &this->_parray[iFirst]; |
||||||
|
memcpy(_parrayT, parraySrc, sizeof(T) * cHalf); |
||||||
|
|
||||||
|
size_t iIn1 = 0; |
||||||
|
size_t iIn2 = cHalf; |
||||||
|
size_t iOut = 0; |
||||||
|
bool fDone = false; |
||||||
|
while (!fDone) |
||||||
|
{ |
||||||
|
if (tcompare.Compare(_parrayT[iIn1], parraySrc[iIn2]) > 0) |
||||||
|
{ |
||||||
|
memmove(&parraySrc[iOut], &parraySrc[iIn2], sizeof(T)); |
||||||
|
++iOut; |
||||||
|
if (++iIn2 == cElems) |
||||||
|
{ |
||||||
|
memcpy(&parraySrc[iOut], &_parrayT[iIn1], sizeof(T) * (cElems - iOut)); |
||||||
|
fDone = true; |
||||||
|
} |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
memmove(&parraySrc[iOut], &_parrayT[iIn1], sizeof(T)); |
||||||
|
++iOut; |
||||||
|
if (++iIn1 == cHalf) |
||||||
|
{ |
||||||
|
fDone = true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
template <typename Comparer> |
||||||
|
void _MergeSort(const Comparer& tcompare, size_t iFirst, size_t cElems) |
||||||
|
{ |
||||||
|
if (cElems == 1) |
||||||
|
return; |
||||||
|
|
||||||
|
if (cElems == 2) |
||||||
|
{ |
||||||
|
if (tcompare.Compare(this->_parray[iFirst], this->_parray[iFirst + 1]) > 0) |
||||||
|
{ |
||||||
|
memmove(_parrayT, &this->_parray[iFirst], sizeof(T)); |
||||||
|
memmove(&this->_parray[iFirst], &this->_parray[iFirst + 1], sizeof(T)); |
||||||
|
memmove(&this->_parray[iFirst + 1], _parrayT, sizeof(T)); |
||||||
|
} |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
size_t cHalf = cElems >> 1; |
||||||
|
_MergeSort(tcompare, iFirst, cHalf); |
||||||
|
_MergeSort(tcompare, iFirst + cHalf, cElems - cHalf); |
||||||
|
_MergeThem(tcompare, iFirst, cElems); |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
template < |
||||||
|
typename T, |
||||||
|
size_t MaxSize = UINT_MAX - 1, |
||||||
|
typename CompareHelper = CSimpleArrayStandardCompareHelper<T> |
||||||
|
> |
||||||
|
class CCoSimpleArray : public CTSimpleArray<T, MaxSize, CTPolicyCoTaskMem<T>, CompareHelper> |
||||||
|
{ |
||||||
|
public: |
||||||
|
CCoSimpleArray() |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
CCoSimpleArray(CCoSimpleArray&& other) noexcept |
||||||
|
{ |
||||||
|
this->TransferData(&other); |
||||||
|
} |
||||||
|
|
||||||
|
CCoSimpleArray& operator=(CCoSimpleArray&& other) noexcept |
||||||
|
{ |
||||||
|
if (this != &other) |
||||||
|
{ |
||||||
|
this->TransferData(&other); |
||||||
|
} |
||||||
|
return *this; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
template < |
||||||
|
typename T, |
||||||
|
size_t MaxSize = UINT_MAX - 1, |
||||||
|
typename CompareHelper = CSimpleArrayStandardCompareHelper<T> |
||||||
|
> |
||||||
|
class CLocalSimpleArray : public CTSimpleArray<T, MaxSize, CTPolicyLocalMem<T>, CompareHelper> |
||||||
|
{ |
||||||
|
}; |
||||||
|
|
||||||
|
template < |
||||||
|
typename T, |
||||||
|
typename ElementAllocator, |
||||||
|
typename CompareHelper = CSimpleArrayStandardCompareHelper<T> |
||||||
|
> |
||||||
|
class CSimplePointerArray : public CCoSimpleArray<T*, UINT_MAX - 1, CompareHelper> |
||||||
|
{ |
||||||
|
public: |
||||||
|
~CSimplePointerArray() |
||||||
|
{ |
||||||
|
RemoveAndReleaseAll(); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT RemoveAndReleaseAt(size_t iElem) |
||||||
|
{ |
||||||
|
T* pT; |
||||||
|
HRESULT hr = this->GetAt(iElem, pT); |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
hr = this->RemoveAt(iElem); |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
ElementAllocator::Destroy(pT); |
||||||
|
} |
||||||
|
} |
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
void RemoveAndReleaseAll() |
||||||
|
{ |
||||||
|
for (size_t i = 0; i < this->_celem; ++i) |
||||||
|
{ |
||||||
|
ElementAllocator::Destroy(this->_parray[i]); |
||||||
|
} |
||||||
|
this->RemoveAll(); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
template < |
||||||
|
typename T, |
||||||
|
typename CompareHelper = CSimpleArrayStandardCompareHelper<T*> |
||||||
|
> |
||||||
|
class CSimplePointerArrayNewMem : public CSimplePointerArray<T, CTContainer_PolicyNewMem, CompareHelper> |
||||||
|
{ |
||||||
|
}; |
||||||
|
|
||||||
|
template < |
||||||
|
typename T, |
||||||
|
typename CompareHelper = CSimpleArrayStandardCompareHelper<T*> |
||||||
|
> |
||||||
|
class CSimplePointerArrayCoTaskMem : public CSimplePointerArray<T, CTPolicyCoTaskMem<T>, CompareHelper> |
||||||
|
{ |
||||||
|
}; |
||||||
|
|
||||||
|
template < |
||||||
|
typename T, |
||||||
|
typename CompareHelper = CSimpleArrayStandardCompareHelper<T*> |
||||||
|
> |
||||||
|
class CSimplePointerArrayLocalMem : public CSimplePointerArray<T, CTPolicyLocalMem<T>, CompareHelper> |
||||||
|
{ |
||||||
|
}; |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
class CSimplePointerArrayRelease : public CSimplePointerArray<T, CTContainer_PolicyRelease<T>> |
||||||
|
{ |
||||||
|
}; |
||||||
@ -0,0 +1,720 @@ |
|||||||
|
// Downloaded from:
|
||||||
|
// https://github.com/namealt/winsdk10/blob/d1acc505c51b11a6ceafb0f93c9dc584b8b4a9d3/Include/10.0.16299.0/um/memsafe.h
|
||||||
|
//
|
||||||
|
// Copyright (C) Microsoft. All rights reserved.
|
||||||
|
//
|
||||||
|
#if (_MSC_VER > 1000) |
||||||
|
#pragma once |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifndef __memsafe_h__ |
||||||
|
#define __memsafe_h__ |
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
|
||||||
|
//
|
||||||
|
// Various heap allocation helpers, featuring
|
||||||
|
// - Fully annotated
|
||||||
|
// - HRESULT return values
|
||||||
|
// - Integer overflow checks via intsafe.h
|
||||||
|
// - Type safety via templates (no typecasting required)
|
||||||
|
// - Zero initialization
|
||||||
|
//
|
||||||
|
// CoAllocBytes
|
||||||
|
// CoReallocBytes
|
||||||
|
// CoAllocObject
|
||||||
|
// CoAllocArray
|
||||||
|
// CoReallocArray
|
||||||
|
//
|
||||||
|
// CoAllocString
|
||||||
|
// CoAllocStringLen
|
||||||
|
// CoAllocStringDoubleNullTerminate
|
||||||
|
// CoAllocStringOpt
|
||||||
|
//
|
||||||
|
// LocalAllocBytes
|
||||||
|
// LocalReallocBytes
|
||||||
|
// LocalAllocObject
|
||||||
|
// LocalAllocArray
|
||||||
|
// LocalReallocArray
|
||||||
|
//
|
||||||
|
// LocalAllocString
|
||||||
|
// LocalAllocStringLen
|
||||||
|
// LocalAllocStringDoubleNullTerminate
|
||||||
|
// LocalAllocStringOpt
|
||||||
|
//
|
||||||
|
// HeapAllocBytes
|
||||||
|
// HeapReallocBytes
|
||||||
|
// HeapAllocObject
|
||||||
|
// HeapAllocArray
|
||||||
|
// HeapReallocArray
|
||||||
|
//
|
||||||
|
// HeapAllocString
|
||||||
|
// HeapAllocStringLen
|
||||||
|
// HeapAllocStringDoubleNullTerminate
|
||||||
|
// HeapAllocStringOpt
|
||||||
|
//
|
||||||
|
// GlobalAllocBytes
|
||||||
|
// GlobalReallocBytes
|
||||||
|
// GlobalAllocObject
|
||||||
|
// GlobalAllocArray
|
||||||
|
// GlobalReallocArray
|
||||||
|
//
|
||||||
|
// GlobalAllocString
|
||||||
|
// GlobalAllocStringLen
|
||||||
|
// GlobalAllocStringDoubleNullTerminate
|
||||||
|
// GlobalAllocStringOpt
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <intsafe.h> |
||||||
|
#include <strsafe.h> |
||||||
|
|
||||||
|
// Flag for inhibiting zero-initialization
|
||||||
|
#define NO_ZERO_INIT 0x00000000 |
||||||
|
|
||||||
|
// Templates for isolating T* <--> void* conversions and integer arithmetic
|
||||||
|
|
||||||
|
template <class T, class TAllocPolicy> |
||||||
|
inline HRESULT _AllocBytes(_In_opt_ HANDLE hHeap, _In_ DWORD dwFlags, _In_ size_t cb, _Outptr_result_bytebuffer_(cb) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return TAllocPolicy::Alloc(hHeap, dwFlags, cb, (void**)ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T, class TAllocPolicy> |
||||||
|
inline HRESULT _ReallocBytes(_In_opt_ HANDLE hHeap, _In_ DWORD dwFlags, _In_opt_ T *pv, _In_ size_t cb, _Outptr_result_bytebuffer_(cb) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return TAllocPolicy::Realloc(hHeap, dwFlags, pv, cb, (void**)ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T, class TAllocPolicy> |
||||||
|
inline HRESULT _AllocArray(_In_opt_ HANDLE hHeap, _In_ DWORD dwFlags, _In_ size_t cItems, _Outptr_result_buffer_(cItems) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
*ppv = NULL; |
||||||
|
size_t cb; |
||||||
|
HRESULT hr = SizeTMult(cItems, sizeof(T), &cb); |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
hr = TAllocPolicy::Alloc(hHeap, dwFlags, cb, (void**)ppv); |
||||||
|
} |
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
template <class T, class TAllocPolicy> |
||||||
|
inline HRESULT _ReallocArray(_In_opt_ HANDLE hHeap, _In_ DWORD dwFlags, _In_opt_ T *pv, _In_ size_t cItems, _Outptr_result_buffer_(cItems) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
*ppv = NULL; |
||||||
|
size_t cb; |
||||||
|
HRESULT hr = SizeTMult(cItems, sizeof(T), &cb); |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
hr = TAllocPolicy::Realloc(hHeap, dwFlags, pv, cb, (void**)ppv); |
||||||
|
} |
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
// Templates for isolating string-specific functionality
|
||||||
|
|
||||||
|
template <class TAllocPolicy> |
||||||
|
inline HRESULT _AllocStringWorker(_In_opt_ HANDLE hHeap, _In_ DWORD dwFlags, _In_reads_opt_(cch) PCNZWCH pszSource, _In_ size_t cch, _In_ size_t cchExtra, _Outptr_result_buffer_(cch+cchExtra) _On_failure_(_Post_satisfies_(*ppsz == 0)) PWSTR *ppsz) |
||||||
|
{ |
||||||
|
*ppsz = NULL; |
||||||
|
size_t cchTotal; |
||||||
|
HRESULT hr = SizeTAdd(cch, cchExtra, &cchTotal); |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
// Note that we do not require dwFlags to include the allocator-specific
|
||||||
|
// zero-initialization flag here.
|
||||||
|
hr = _AllocArray<WCHAR,TAllocPolicy>(hHeap, dwFlags, cchTotal, ppsz); |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
// The source string may be shorter than cch, so zero-initialize
|
||||||
|
// the entire buffer using STRSAFE_FILL_BEHIND_NULL.
|
||||||
|
//
|
||||||
|
// Note that _AllocStringDoubleNullTerminate relies on
|
||||||
|
// zero-initialization to provide the 2nd NULL terminator.
|
||||||
|
StringCchCopyNExW(*ppsz, cchTotal, pszSource, cch, NULL, NULL, STRSAFE_IGNORE_NULLS | STRSAFE_FILL_BEHIND_NULL); |
||||||
|
} |
||||||
|
} |
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
template <class TAllocPolicy> |
||||||
|
inline HRESULT _AllocString(_In_opt_ HANDLE hHeap, _In_ DWORD dwFlags, _In_ PCWSTR pszSource, _Outptr_result_nullonfailure_ PWSTR *ppsz) |
||||||
|
{ |
||||||
|
// pszSource must be valid (non-NULL)
|
||||||
|
return _AllocStringWorker<TAllocPolicy>(hHeap, dwFlags, pszSource, wcslen(pszSource), 1, ppsz); |
||||||
|
} |
||||||
|
|
||||||
|
template <class TAllocPolicy> |
||||||
|
inline HRESULT _AllocStringLen(_In_opt_ HANDLE hHeap, _In_ DWORD dwFlags, _In_reads_or_z_opt_(cch) PCNZWCH pszSource, _In_ size_t cch, _Outptr_result_buffer_(cch+1) _On_failure_(_Post_satisfies_(*ppsz == 0)) PWSTR *ppsz) |
||||||
|
{ |
||||||
|
// pszSource is optional (may be NULL)
|
||||||
|
return _AllocStringWorker<TAllocPolicy>(hHeap, dwFlags, pszSource, cch, 1, ppsz); |
||||||
|
} |
||||||
|
|
||||||
|
// Takes a single-null terminated string and allocates a double-null terminated string.
|
||||||
|
template <class TAllocPolicy> |
||||||
|
inline HRESULT _AllocStringDoubleNullTerminate(_In_opt_ HANDLE hHeap, _In_ DWORD dwFlags, _In_ PCWSTR pszSource, _Outptr_result_nullonfailure_ PZZWSTR *ppsz) |
||||||
|
{ |
||||||
|
// pszSource must be valid (non-NULL)
|
||||||
|
return _AllocStringWorker<TAllocPolicy>(hHeap, dwFlags, pszSource, wcslen(pszSource), 2, ppsz); |
||||||
|
} |
||||||
|
|
||||||
|
template <class TAllocPolicy> |
||||||
|
inline HRESULT _AllocStringOpt(_In_opt_ HANDLE hHeap, _In_ DWORD dwFlags, _In_opt_ PCWSTR pszSource, _Outptr_result_maybenull_ _On_failure_(_Post_satisfies_(*ppsz == 0)) PWSTR *ppsz) |
||||||
|
{ |
||||||
|
// pszSource is optional (may be NULL)
|
||||||
|
if (pszSource != NULL) |
||||||
|
{ |
||||||
|
return _AllocString<TAllocPolicy>(hHeap, dwFlags, pszSource, ppsz); |
||||||
|
} |
||||||
|
*ppsz = NULL; |
||||||
|
return S_OK; |
||||||
|
} |
||||||
|
|
||||||
|
#ifndef NO_COALLOC_HELPERS |
||||||
|
|
||||||
|
#include <objbase.h> |
||||||
|
|
||||||
|
// CoTaskMemAlloc does not zero-initialize by default. Define a flag to enable
|
||||||
|
// zero-init behavior.
|
||||||
|
#define CO_MEM_ZERO_INIT 0x00000001 |
||||||
|
|
||||||
|
class CTCoAllocPolicy |
||||||
|
{ |
||||||
|
private: |
||||||
|
#if (NTDDI_VERSION < NTDDI_WIN10_RS1) || defined(COM_SUPPORT_MALLOC_SPIES) |
||||||
|
static size_t _CoTaskMemSize(_In_ _Post_writable_byte_size_(return) void *pv) |
||||||
|
{ |
||||||
|
size_t cb = 0; |
||||||
|
IMalloc *pMalloc; |
||||||
|
if (SUCCEEDED(CoGetMalloc(1, &pMalloc))) // should never fail (static v-table)
|
||||||
|
{ |
||||||
|
// Returns (size_t)-1 if pv is NULL.
|
||||||
|
// Result is indeterminate if pv does not belong to CoTaskMemAlloc.
|
||||||
|
cb = pMalloc->GetSize(pv); |
||||||
|
pMalloc->Release(); |
||||||
|
} |
||||||
|
return cb; |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
public: |
||||||
|
static HRESULT Alloc(_In_opt_ HANDLE /*hHeap*/, _In_ DWORD dwFlags, _In_ size_t cb, _Outptr_result_bytebuffer_(cb) _On_failure_(_Post_satisfies_(*ppv == 0)) void **ppv) |
||||||
|
{ |
||||||
|
*ppv = CoTaskMemAlloc(cb); |
||||||
|
if (*ppv) |
||||||
|
{ |
||||||
|
if (dwFlags & CO_MEM_ZERO_INIT) |
||||||
|
{ |
||||||
|
#ifdef COM_SUPPORT_MALLOC_SPIES |
||||||
|
// Zero-initialize the buffer
|
||||||
|
// The actual size might be larger than cb due to spies present.
|
||||||
|
// Initialize to the actual size in case of realloc later,
|
||||||
|
// or there might be an uninitialized gap in between.
|
||||||
|
size_t cbActual = _CoTaskMemSize(*ppv); |
||||||
|
ZeroMemory(*ppv, cbActual); |
||||||
|
#else |
||||||
|
ZeroMemory(*ppv, cb); |
||||||
|
#endif |
||||||
|
} |
||||||
|
return S_OK; |
||||||
|
} |
||||||
|
return E_OUTOFMEMORY; |
||||||
|
} |
||||||
|
|
||||||
|
static HRESULT Realloc(_In_opt_ HANDLE /*hHeap*/, _In_ DWORD dwFlags, _In_opt_ void *pv, _In_ size_t cb, _Outptr_result_bytebuffer_(cb) _On_failure_(_Post_satisfies_(*ppv == 0)) void **ppv) |
||||||
|
{ |
||||||
|
#if (NTDDI_VERSION < NTDDI_WIN10_RS1) |
||||||
|
size_t cbKeepIntact = 0; |
||||||
|
|
||||||
|
if (pv && (dwFlags & CO_MEM_ZERO_INIT)) |
||||||
|
{ |
||||||
|
// Get the current size, so we know how much to zero-initialize
|
||||||
|
cbKeepIntact = _CoTaskMemSize(pv); |
||||||
|
if (cb < cbKeepIntact) |
||||||
|
{ |
||||||
|
// Shrinking the buffer, only keep the new size
|
||||||
|
cbKeepIntact = cb; |
||||||
|
} |
||||||
|
} |
||||||
|
#else |
||||||
|
// As of Redstone CoTaskMemRealloc always zero-initializes
|
||||||
|
// the tail of the allocation.
|
||||||
|
size_t cbKeepIntact = cb; |
||||||
|
#endif |
||||||
|
|
||||||
|
// If pv is NULL, CoTaskMemRealloc allocates a new block
|
||||||
|
*ppv = CoTaskMemRealloc(pv, cb); |
||||||
|
|
||||||
|
if (*ppv) |
||||||
|
{ |
||||||
|
if (dwFlags & CO_MEM_ZERO_INIT) |
||||||
|
{ |
||||||
|
// Zero-initialize the trailing part of the buffer
|
||||||
|
#ifdef COM_SUPPORT_MALLOC_SPIES |
||||||
|
// The actual size might be larger than cb due to due to spies present.
|
||||||
|
size_t cbActual = _CoTaskMemSize(*ppv); |
||||||
|
#else |
||||||
|
size_t cbActual = cb; |
||||||
|
#endif |
||||||
|
if (cbActual > cbKeepIntact) |
||||||
|
{ |
||||||
|
ZeroMemory(((BYTE*)*ppv) + cbKeepIntact, cbActual - cbKeepIntact); |
||||||
|
} |
||||||
|
} |
||||||
|
return S_OK; |
||||||
|
} |
||||||
|
return E_OUTOFMEMORY; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
// CoTaskMemAlloc helpers
|
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT CoAllocBytes(_In_ DWORD dwFlags, _In_ size_t cb, _Outptr_result_bytebuffer_(cb) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return _AllocBytes<T, CTCoAllocPolicy>(NULL, dwFlags, cb, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT CoReallocBytes(_In_ DWORD dwFlags, _In_opt_ T *pv, _In_ size_t cb, _Outptr_result_bytebuffer_(cb) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return _ReallocBytes<T, CTCoAllocPolicy>(NULL, dwFlags, pv, cb, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT CoAllocObject(_In_ DWORD dwFlags, _Outptr_result_buffer_(1) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return _AllocBytes<T, CTCoAllocPolicy>(NULL, dwFlags, sizeof(T), ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT CoAllocArray(_In_ DWORD dwFlags, _In_ size_t cItems, _Outptr_result_buffer_(cItems) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return _AllocArray<T, CTCoAllocPolicy>(NULL, dwFlags, cItems, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT CoReallocArray(_In_ DWORD dwFlags, _In_opt_ T *pv, _In_ size_t cItems, _Outptr_result_buffer_(cItems) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return _ReallocArray<T, CTCoAllocPolicy>(NULL, dwFlags, pv, cItems, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
// Zero-initializing CoTaskMemAlloc helpers
|
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT CoAllocBytes(_In_ size_t cb, _Outptr_result_bytebuffer_(cb) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return CoAllocBytes(CO_MEM_ZERO_INIT, cb, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT CoReallocBytes(_In_opt_ T *pv, _In_ size_t cb, _Outptr_result_bytebuffer_(cb) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return CoReallocBytes(CO_MEM_ZERO_INIT, pv, cb, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT CoAllocObject(_Outptr_result_buffer_(1) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return CoAllocObject(CO_MEM_ZERO_INIT, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT CoAllocArray(_In_ size_t cItems, _Outptr_result_buffer_(cItems) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return CoAllocArray(CO_MEM_ZERO_INIT, cItems, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT CoReallocArray(_In_opt_ T *pv, _In_ size_t cItems, _Outptr_result_buffer_(cItems) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return CoReallocArray(CO_MEM_ZERO_INIT, pv, cItems, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
// CoTaskMemAlloc string helpers
|
||||||
|
|
||||||
|
inline HRESULT CoAllocString(_In_ PCWSTR pszSource, _Outptr_result_nullonfailure_ PWSTR *ppsz) |
||||||
|
{ |
||||||
|
return _AllocString<CTCoAllocPolicy>(NULL, NO_ZERO_INIT, pszSource, ppsz); |
||||||
|
} |
||||||
|
|
||||||
|
inline HRESULT CoAllocStringLen( _In_reads_or_z_opt_(cch) PCNZWCH pszSource, _In_ size_t cch, _Outptr_result_buffer_(cch+1) _On_failure_(_Post_satisfies_(*ppsz == 0)) PWSTR *ppsz) |
||||||
|
{ |
||||||
|
return _AllocStringLen<CTCoAllocPolicy>(NULL, NO_ZERO_INIT, pszSource, cch, ppsz); |
||||||
|
} |
||||||
|
|
||||||
|
inline HRESULT CoAllocStringDoubleNullTerminate(_In_ PCWSTR pszSource, _Outptr_result_nullonfailure_ PZZWSTR *ppsz) |
||||||
|
{ |
||||||
|
return _AllocStringDoubleNullTerminate<CTCoAllocPolicy>(NULL, NO_ZERO_INIT, pszSource, ppsz); |
||||||
|
} |
||||||
|
|
||||||
|
inline HRESULT CoAllocStringOpt(_In_opt_ PCWSTR pszSource, _Outptr_result_maybenull_ _On_failure_(_Post_satisfies_(*ppsz == 0)) PWSTR *ppsz) |
||||||
|
{ |
||||||
|
return _AllocStringOpt<CTCoAllocPolicy>(NULL, NO_ZERO_INIT, pszSource, ppsz); |
||||||
|
} |
||||||
|
|
||||||
|
#endif // NO_COALLOC_HELPERS
|
||||||
|
|
||||||
|
#ifndef NO_LOCALALLOC_HELPERS |
||||||
|
|
||||||
|
class CTLocalAllocPolicy |
||||||
|
{ |
||||||
|
public: |
||||||
|
static HRESULT Alloc(_In_opt_ HANDLE /*hHeap*/, _In_ DWORD dwFlags, _In_ size_t cb, _Outptr_result_bytebuffer_(cb) _On_failure_(_Post_satisfies_(*ppv == 0)) void **ppv) |
||||||
|
{ |
||||||
|
// ignore flags other than zero-init, assume fixed
|
||||||
|
*ppv = LocalAlloc(LMEM_FIXED | (dwFlags & LMEM_ZEROINIT), cb); |
||||||
|
return (*ppv) ? S_OK : E_OUTOFMEMORY; |
||||||
|
} |
||||||
|
|
||||||
|
static HRESULT Realloc(_In_opt_ HANDLE hHeap, _In_ DWORD dwFlags, _In_opt_ void *pv, _In_ size_t cb, _Outptr_result_bytebuffer_(cb) _On_failure_(_Post_satisfies_(*ppv == 0)) void **ppv) |
||||||
|
{ |
||||||
|
if (pv == NULL) |
||||||
|
{ |
||||||
|
return Alloc(hHeap, dwFlags, cb, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
// LMEM_MOVEABLE is correct when reallocating LMEM_FIXED buffers
|
||||||
|
*ppv = LocalReAlloc(pv, cb, LMEM_MOVEABLE | (dwFlags & LMEM_ZEROINIT)); |
||||||
|
return (*ppv) ? S_OK : E_OUTOFMEMORY; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
// LocalAlloc helpers
|
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT LocalAllocBytes(_In_ DWORD dwFlags, _In_ size_t cb, _Outptr_result_bytebuffer_(cb) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return _AllocBytes<T, CTLocalAllocPolicy>(NULL, dwFlags, cb, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT LocalReallocBytes(_In_ DWORD dwFlags, _In_opt_ T *pv, _In_ size_t cb, _Outptr_result_bytebuffer_(cb) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return _ReallocBytes<T, CTLocalAllocPolicy>(NULL, dwFlags, pv, cb, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT LocalAllocObject(_In_ DWORD dwFlags, _Outptr_result_buffer_(1) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return _AllocBytes<T, CTLocalAllocPolicy>(NULL, dwFlags, sizeof(T), ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT LocalAllocArray(_In_ DWORD dwFlags, _In_ size_t cItems, _Outptr_result_buffer_(cItems) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return _AllocArray<T, CTLocalAllocPolicy>(NULL, dwFlags, cItems, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT LocalReallocArray(_In_ DWORD dwFlags, _In_opt_ T *pv, _In_ size_t cItems, _Outptr_result_buffer_(cItems) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return _ReallocArray<T, CTLocalAllocPolicy>(NULL, dwFlags, pv, cItems, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
// Zero-initializing LocalAlloc helpers
|
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT LocalAllocBytes(_In_ size_t cb, _Outptr_result_bytebuffer_(cb) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return LocalAllocBytes(LMEM_ZEROINIT, cb, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT LocalReallocBytes(_In_opt_ T *pv, _In_ size_t cb, _Outptr_result_bytebuffer_(cb) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return LocalReallocBytes(LMEM_ZEROINIT, pv, cb, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT LocalAllocObject(_Outptr_result_buffer_(1) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return LocalAllocObject(LMEM_ZEROINIT, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT LocalAllocArray(_In_ size_t cItems, _Outptr_result_buffer_(cItems) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return LocalAllocArray(LMEM_ZEROINIT, cItems, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT LocalReallocArray(_In_opt_ T *pv, _In_ size_t cItems, _Outptr_result_buffer_(cItems) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return LocalReallocArray(LMEM_ZEROINIT, pv, cItems, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
// LocalAlloc string helpers
|
||||||
|
|
||||||
|
inline HRESULT LocalAllocString(_In_ PCWSTR pszSource, _Outptr_result_nullonfailure_ PWSTR *ppsz) |
||||||
|
{ |
||||||
|
return _AllocString<CTLocalAllocPolicy>(NULL, NO_ZERO_INIT, pszSource, ppsz); |
||||||
|
} |
||||||
|
|
||||||
|
inline HRESULT LocalAllocStringLen( _In_reads_or_z_opt_(cch) PCNZWCH pszSource, _In_ size_t cch, _Outptr_result_buffer_(cch+1) _On_failure_(_Post_satisfies_(*ppsz == 0)) PWSTR *ppsz) |
||||||
|
{ |
||||||
|
return _AllocStringLen<CTLocalAllocPolicy>(NULL, NO_ZERO_INIT, pszSource, cch, ppsz); |
||||||
|
} |
||||||
|
|
||||||
|
inline HRESULT LocalAllocStringDoubleNullTerminate(_In_ PCWSTR pszSource, _Outptr_result_nullonfailure_ PZZWSTR *ppsz) //todo sal 00?
|
||||||
|
{ |
||||||
|
return _AllocStringDoubleNullTerminate<CTLocalAllocPolicy>(NULL, NO_ZERO_INIT, pszSource, ppsz); |
||||||
|
} |
||||||
|
|
||||||
|
inline HRESULT LocalAllocStringOpt(_In_opt_ PCWSTR pszSource, _Outptr_result_maybenull_ _On_failure_(_Post_satisfies_(*ppsz == 0)) PWSTR *ppsz) |
||||||
|
{ |
||||||
|
return _AllocStringOpt<CTLocalAllocPolicy>(NULL, NO_ZERO_INIT, pszSource, ppsz); |
||||||
|
} |
||||||
|
|
||||||
|
#endif // NO_LOCALALLOC_HELPERS
|
||||||
|
|
||||||
|
#ifndef NO_HEAPALLOC_HELPERS |
||||||
|
|
||||||
|
class CTHeapAllocPolicy |
||||||
|
{ |
||||||
|
public: |
||||||
|
static HRESULT Alloc(_In_ HANDLE hHeap, _In_ DWORD dwFlags, _In_ size_t cb, _Outptr_result_bytebuffer_(cb) _On_failure_(_Post_satisfies_(*ppv == 0)) void **ppv) |
||||||
|
{ |
||||||
|
*ppv = HeapAlloc(hHeap, dwFlags, cb); |
||||||
|
return (*ppv) ? S_OK : E_OUTOFMEMORY; |
||||||
|
} |
||||||
|
|
||||||
|
static HRESULT Realloc(_In_ HANDLE hHeap, _In_ DWORD dwFlags, _In_opt_ void *pv, _In_ size_t cb, _Outptr_result_bytebuffer_(cb) _On_failure_(_Post_satisfies_(*ppv == 0)) void **ppv) |
||||||
|
{ |
||||||
|
if (pv == NULL) |
||||||
|
{ |
||||||
|
return Alloc(hHeap, dwFlags, cb, ppv); |
||||||
|
} |
||||||
|
*ppv = HeapReAlloc(hHeap, dwFlags, pv, cb); |
||||||
|
return (*ppv) ? S_OK : E_OUTOFMEMORY; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
// HeapAlloc helpers
|
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT HeapAllocBytes(_In_ HANDLE hHeap, _In_ DWORD dwFlags, _In_ size_t cb, _Outptr_result_bytebuffer_(cb) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return _AllocBytes<T, CTHeapAllocPolicy>(hHeap, dwFlags, cb, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT HeapReallocBytes(_In_ HANDLE hHeap, _In_ DWORD dwFlags, _In_opt_ T *pv, _In_ size_t cb, _Outptr_result_bytebuffer_(cb) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return _ReallocBytes<T, CTHeapAllocPolicy>(hHeap, dwFlags, pv, cb, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT HeapAllocObject(_In_ HANDLE hHeap, _In_ DWORD dwFlags, _Outptr_result_buffer_(1) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return _AllocBytes<T, CTHeapAllocPolicy>(hHeap, dwFlags, sizeof(T), ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT HeapAllocArray(_In_ HANDLE hHeap, _In_ DWORD dwFlags, _In_ size_t cItems, _Outptr_result_buffer_(cItems) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return _AllocArray<T, CTHeapAllocPolicy>(hHeap, dwFlags, cItems, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT HeapReallocArray(_In_ HANDLE hHeap, _In_ DWORD dwFlags, _In_opt_ T *pv, _In_ size_t cItems, _Outptr_result_buffer_(cItems) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return _ReallocArray<T, CTHeapAllocPolicy>(hHeap, dwFlags, pv, cItems, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
// Zero-initializing HeapAlloc helpers (process heap)
|
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT HeapAllocBytes(_In_ size_t cb, _Outptr_result_bytebuffer_(cb) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return HeapAllocBytes(GetProcessHeap(), HEAP_ZERO_MEMORY, cb, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT HeapReallocBytes(_In_opt_ T *pv, _In_ size_t cb, _Outptr_result_bytebuffer_(cb) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return HeapReallocBytes(GetProcessHeap(), HEAP_ZERO_MEMORY, pv, cb, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT HeapAllocObject(_Outptr_result_buffer_(1) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return HeapAllocObject(GetProcessHeap(), HEAP_ZERO_MEMORY, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT HeapAllocArray(_In_ size_t cItems, _Outptr_result_buffer_(cItems) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return HeapAllocArray(GetProcessHeap(), HEAP_ZERO_MEMORY, cItems, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT HeapReallocArray(_In_opt_ T *pv, _In_ size_t cItems, _Outptr_result_buffer_(cItems) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return HeapReallocArray(GetProcessHeap(), HEAP_ZERO_MEMORY, pv, cItems, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
// HeapAlloc string helpers
|
||||||
|
|
||||||
|
inline HRESULT HeapAllocString(_In_ HANDLE hHeap, _In_ DWORD dwFlags, _In_ PCWSTR pszSource, _Outptr_result_nullonfailure_ PWSTR *ppsz) |
||||||
|
{ |
||||||
|
return _AllocString<CTHeapAllocPolicy>(hHeap, dwFlags, pszSource, ppsz); |
||||||
|
} |
||||||
|
|
||||||
|
inline HRESULT HeapAllocStringLen(_In_ HANDLE hHeap, _In_ DWORD dwFlags, _In_reads_or_z_opt_(cch) PCNZWCH pszSource, _In_ size_t cch, _Outptr_result_buffer_(cch+1) _On_failure_(_Post_satisfies_(*ppsz == 0)) PWSTR *ppsz) |
||||||
|
{ |
||||||
|
return _AllocStringLen<CTHeapAllocPolicy>(hHeap, dwFlags, pszSource, cch, ppsz); |
||||||
|
} |
||||||
|
|
||||||
|
inline HRESULT HeapAllocStringDoubleNullTerminate(_In_ HANDLE hHeap, _In_ DWORD dwFlags, _In_ PCWSTR pszSource, _Outptr_result_nullonfailure_ PZZWSTR *ppsz) |
||||||
|
{ |
||||||
|
return _AllocStringDoubleNullTerminate<CTHeapAllocPolicy>(hHeap, dwFlags, pszSource, ppsz); |
||||||
|
} |
||||||
|
|
||||||
|
inline HRESULT HeapAllocStringOpt(_In_ HANDLE hHeap, _In_ DWORD dwFlags, _In_opt_ PCWSTR pszSource, _Outptr_result_maybenull_ _On_failure_(_Post_satisfies_(*ppsz == 0)) PWSTR *ppsz) |
||||||
|
{ |
||||||
|
return _AllocStringOpt<CTHeapAllocPolicy>(hHeap, dwFlags, pszSource, ppsz); |
||||||
|
} |
||||||
|
|
||||||
|
// HeapAlloc string helpers (process heap)
|
||||||
|
|
||||||
|
inline HRESULT HeapAllocString(_In_ PCWSTR pszSource, _Outptr_result_nullonfailure_ PWSTR *ppsz) |
||||||
|
{ |
||||||
|
return HeapAllocString(GetProcessHeap(), NO_ZERO_INIT, pszSource, ppsz); |
||||||
|
} |
||||||
|
|
||||||
|
inline HRESULT HeapAllocStringLen(_In_reads_opt_(cch) PCNZWCH pszSource, _In_ size_t cch, _Outptr_result_buffer_(cch+1) _On_failure_(_Post_satisfies_(*ppsz == 0)) PWSTR *ppsz) |
||||||
|
{ |
||||||
|
return HeapAllocStringLen(GetProcessHeap(), NO_ZERO_INIT, pszSource, cch, ppsz); |
||||||
|
} |
||||||
|
|
||||||
|
inline HRESULT HeapAllocStringDoubleNullTerminate(_In_ PCWSTR pszSource, _Outptr_result_nullonfailure_ PZZWSTR *ppsz) |
||||||
|
{ |
||||||
|
return HeapAllocStringDoubleNullTerminate(GetProcessHeap(), NO_ZERO_INIT, pszSource, ppsz); |
||||||
|
} |
||||||
|
|
||||||
|
inline HRESULT HeapAllocStringOpt(_In_opt_ PCWSTR pszSource, _Outptr_result_maybenull_ _On_failure_(_Post_satisfies_(*ppsz == 0)) PWSTR *ppsz) |
||||||
|
{ |
||||||
|
return HeapAllocStringOpt(GetProcessHeap(), NO_ZERO_INIT, pszSource, ppsz); |
||||||
|
} |
||||||
|
|
||||||
|
#endif // NO_HEAPALLOC_HELPERS
|
||||||
|
|
||||||
|
#ifndef NO_GLOBALALLOC_HELPERS |
||||||
|
|
||||||
|
class CTGlobalAllocPolicy |
||||||
|
{ |
||||||
|
public: |
||||||
|
static HRESULT Alloc(_In_opt_ HANDLE /*hHeap*/, _In_ DWORD dwFlags, _In_ size_t cb, _Outptr_result_bytebuffer_(cb) _On_failure_(_Post_satisfies_(*ppv == 0)) void **ppv) |
||||||
|
{ |
||||||
|
// ignore flags other than zero-init, assume fixed
|
||||||
|
*ppv = GlobalAlloc(GMEM_FIXED | (dwFlags & GMEM_ZEROINIT), cb); |
||||||
|
return (*ppv) ? S_OK : E_OUTOFMEMORY; |
||||||
|
} |
||||||
|
|
||||||
|
static HRESULT Realloc(_In_opt_ HANDLE hHeap, _In_ DWORD dwFlags, _In_opt_ void *pv, _In_ size_t cb, _Outptr_result_bytebuffer_(cb) _On_failure_(_Post_satisfies_(*ppv == 0)) void **ppv) |
||||||
|
{ |
||||||
|
if (pv == NULL) |
||||||
|
{ |
||||||
|
return Alloc(hHeap, dwFlags, cb, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
// GMEM_MOVEABLE is correct when reallocating GMEM_FIXED buffers
|
||||||
|
*ppv = GlobalReAlloc(pv, cb, GMEM_MOVEABLE | (dwFlags & GMEM_ZEROINIT)); |
||||||
|
return (*ppv) ? S_OK : E_OUTOFMEMORY; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
// GlobalAlloc helpers
|
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT GlobalAllocBytes(_In_ DWORD dwFlags, _In_ size_t cb, _Outptr_result_bytebuffer_(cb) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return _AllocBytes<T, CTGlobalAllocPolicy>(NULL, dwFlags, cb, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT GlobalReallocBytes(_In_ DWORD dwFlags, _In_opt_ T *pv, _In_ size_t cb, _Outptr_result_bytebuffer_(cb) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return _ReallocBytes<T, CTGlobalAllocPolicy>(NULL, dwFlags, pv, cb, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT GlobalAllocObject(_In_ DWORD dwFlags, _Outptr_result_buffer_(1) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return _AllocBytes<T, CTGlobalAllocPolicy>(NULL, dwFlags, sizeof(T), ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT GlobalAllocArray(_In_ DWORD dwFlags, _In_ size_t cItems, _Outptr_result_buffer_(cItems) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return _AllocArray<T, CTGlobalAllocPolicy>(NULL, dwFlags, cItems, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT GlobalReallocArray(_In_ DWORD dwFlags, _In_opt_ T *pv, _In_ size_t cItems, _Outptr_result_buffer_(cItems) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return _ReallocArray<T, CTGlobalAllocPolicy>(NULL, dwFlags, pv, cItems, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
// Zero-initializing GlobalAlloc helpers
|
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT GlobalAllocBytes(_In_ size_t cb, _Outptr_result_bytebuffer_(cb) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return GlobalAllocBytes<T>(GMEM_ZEROINIT, cb, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT GlobalReallocBytes(_In_opt_ T *pv, _In_ size_t cb, _Outptr_result_bytebuffer_(cb) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return GlobalReallocBytes<T>(GMEM_ZEROINIT, pv, cb, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT GlobalAllocObject(_Outptr_result_buffer_(1) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return GlobalAllocObject<T>(GMEM_ZEROINIT, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT GlobalAllocArray(_In_ size_t cItems, _Outptr_result_buffer_(cItems) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return GlobalAllocArray<T>(GMEM_ZEROINIT, cItems, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
template <class T> |
||||||
|
inline HRESULT GlobalReallocArray(_In_opt_ T *pv, _In_ size_t cItems, _Outptr_result_buffer_(cItems) _On_failure_(_Post_satisfies_(*ppv == 0)) T **ppv) |
||||||
|
{ |
||||||
|
return GlobalReallocArray<T>(GMEM_ZEROINIT, pv, cItems, ppv); |
||||||
|
} |
||||||
|
|
||||||
|
// GlobalAlloc string helpers
|
||||||
|
|
||||||
|
inline HRESULT GlobalAllocString(_In_ PCWSTR pszSource, _Outptr_result_nullonfailure_ PWSTR *ppsz) |
||||||
|
{ |
||||||
|
return _AllocString<CTGlobalAllocPolicy>(NULL, NO_ZERO_INIT, pszSource, ppsz); |
||||||
|
} |
||||||
|
|
||||||
|
inline HRESULT GlobalAllocStringLen( _In_reads_or_z_opt_(cch) PCNZWCH pszSource, _In_ size_t cch, _Outptr_result_buffer_(cch+1) _On_failure_(_Post_satisfies_(*ppsz == 0)) PWSTR *ppsz) |
||||||
|
{ |
||||||
|
return _AllocStringLen<CTGlobalAllocPolicy>(NULL, NO_ZERO_INIT, pszSource, cch, ppsz); |
||||||
|
} |
||||||
|
|
||||||
|
inline HRESULT GlobalAllocStringDoubleNullTerminate(_In_ PCWSTR pszSource, _Outptr_result_nullonfailure_ PZZWSTR *ppsz) |
||||||
|
{ |
||||||
|
return _AllocStringDoubleNullTerminate<CTGlobalAllocPolicy>(NULL, NO_ZERO_INIT, pszSource, ppsz); |
||||||
|
} |
||||||
|
|
||||||
|
inline HRESULT GlobalAllocStringOpt(_In_opt_ PCWSTR pszSource, _Outptr_result_maybenull_ _On_failure_(_Post_satisfies_(*ppsz == 0)) PWSTR *ppsz) |
||||||
|
{ |
||||||
|
return _AllocStringOpt<CTGlobalAllocPolicy>(NULL, NO_ZERO_INIT, pszSource, ppsz); |
||||||
|
} |
||||||
|
|
||||||
|
#endif // NO_GLOBALALLOC_HELPERS
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // __memsafe_h__
|
||||||
|
|
||||||
Loading…
Reference in new issue