diff options
author | dotnet-bot <dotnet-bot@microsoft.com> | 2015-01-30 14:14:42 -0800 |
---|---|---|
committer | dotnet-bot <dotnet-bot@microsoft.com> | 2015-01-30 14:14:42 -0800 |
commit | ef1e2ab328087c61a6878c1e84f4fc5d710aebce (patch) | |
tree | dee1bbb89e9d722e16b0d1485e3cdd1b6c8e2cfa /src/inc/winrt | |
download | coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.gz coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.bz2 coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.zip |
Initial commit to populate CoreCLR repo
[tfs-changeset: 1407945]
Diffstat (limited to 'src/inc/winrt')
-rw-r--r-- | src/inc/winrt/ntassert.h | 213 | ||||
-rw-r--r-- | src/inc/winrt/paraminstanceapi.h | 1750 | ||||
-rw-r--r-- | src/inc/winrt/windowsruntime.h | 66 | ||||
-rw-r--r-- | src/inc/winrt/windowsstring.h | 775 |
4 files changed, 2804 insertions, 0 deletions
diff --git a/src/inc/winrt/ntassert.h b/src/inc/winrt/ntassert.h new file mode 100644 index 0000000000..24d7cb2bde --- /dev/null +++ b/src/inc/winrt/ntassert.h @@ -0,0 +1,213 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +/*++ + +Copyright (c) 2009 Microsoft Corporation. All rights reserved. + +Module Name: + + ntassert.h + +Abstract: + + Defines DbgRaiseAssertionFailure, and the NT_ASSERT and NT_VERIFY macros. + + Note that normally platform-specific definitions like + DbgRaiseAssertionFailure would go to platform-specific subheaders (nti386_x, + etc.), they are placed here instead for convenience. + +--*/ + +#pragma once + +// begin_wdm begin_winnt begin_ntminiport + +#ifdef __cplusplus +extern "C" { +#endif + +// +// Assert exception. +// + +#if !defined(_DBGRAISEASSERTIONFAILURE_) && !defined(RC_INVOKED) && !defined(MIDL_PASS) + +#define _DBGRAISEASSERTIONFAILURE_ + +#if defined(_PREFAST_) + +__analysis_noreturn +FORCEINLINE +VOID +DbgRaiseAssertionFailure ( + VOID + ); + +#endif + +#if defined(_AMD64_) + +#if defined(_M_AMD64) + +VOID +__int2c ( + VOID + ); + +#pragma intrinsic(__int2c) + +#if !defined(_PREFAST_) + +#define DbgRaiseAssertionFailure() __int2c() + +#endif // !defined(_PREFAST_) + +#endif // defined(_M_AMD64) + +#elif defined(_X86_) + +#if defined(_M_IX86) + +#if _MSC_FULL_VER >= 140030222 + +VOID +__int2c ( + VOID + ); + +#pragma intrinsic(__int2c) + +#if !defined(_PREFAST_) + +#define DbgRaiseAssertionFailure() __int2c() + +#endif // !defined(_PREFAST_) + +#else // _MSC_FULL_VER >= 140030222 + +#pragma warning( push ) +#pragma warning( disable : 4793 ) + +#if !defined(_PREFAST_) + +__analysis_noreturn +FORCEINLINE +VOID +DbgRaiseAssertionFailure ( + VOID + ) + +{ + __asm int 0x2c +} + +#endif // !defined(_PREFAST_) + +#pragma warning( pop ) + +#endif // _MSC_FULL_VER >= 140030222 + +#endif // defined(_M_IX86) + +#elif defined(_IA64_) + +#if defined(_M_IA64) + +void +__break( + _In_ int StIIM + ); + +#pragma intrinsic (__break) + +#define BREAK_DEBUG_BASE 0x080000 +#define ASSERT_BREAKPOINT (BREAK_DEBUG_BASE+3) // Cause a STATUS_ASSERTION_FAILURE exception to be raised. + +#if !defined(_PREFAST_) + +#define DbgRaiseAssertionFailure() __break(ASSERT_BREAKPOINT) + +#endif // !defined(_PREFAST_) + +#endif // defined(_M_IA64) + +#elif defined(_ARM_) + +#if defined(_M_ARM) + +VOID +__emit( + const unsigned __int32 opcode + ); + +#pragma intrinsic(__emit) + +#if !defined(_PREFAST_) + +#define DbgRaiseAssertionFailure() __emit(0xdefc) // THUMB_ASSERT + +#endif // !defined(_PREFAST_) + +#endif // defined(_M_ARM) + +#endif // _AMD64_, _X86_, _IA64_, _ARM_ +#endif // !defined(_DBGRAISEASSERTIONFAILURE_) && !defined(RC_INVOKED) && !defined(MIDL_PASS) + +#ifdef __cplusplus +} +#endif + +// end_wdm end_winnt end_ntminiport + +// begin_wdm begin_ntminiport + +#if _MSC_VER >= 1300 +#if DBG + +#define NT_ASSERT(_exp) \ + ((!(_exp)) ? \ + (__annotation(L"Debug", L"AssertFail", L#_exp), \ + DbgRaiseAssertionFailure(), FALSE) : \ + TRUE) + +#define NT_ASSERTMSG(_msg, _exp) \ + ((!(_exp)) ? \ + (__annotation(L"Debug", L"AssertFail", L##_msg), \ + DbgRaiseAssertionFailure(), FALSE) : \ + TRUE) + +#define NT_ASSERTMSGW(_msg, _exp) \ + ((!(_exp)) ? \ + (__annotation(L"Debug", L"AssertFail", _msg), \ + DbgRaiseAssertionFailure(), FALSE) : \ + TRUE) + +#define NT_VERIFY NT_ASSERT +#define NT_VERIFYMSG NT_ASSERTMSG +#define NT_VERIFYMSGW NT_ASSERTMSGW + +#else // DBG + +#define NT_ASSERT(_exp) ((void) 0) +#define NT_ASSERTMSG(_msg, _exp) ((void) 0) +#define NT_ASSERTMSGW(_msg, _exp) ((void) 0) + +#define NT_VERIFY(_exp) ((_exp) ? TRUE : FALSE) +#define NT_VERIFYMSG(_msg, _exp ) ((_exp) ? TRUE : FALSE) +#define NT_VERIFYMSGW(_msg, _exp) ((_exp) ? TRUE : FALSE) + +#endif // DBG +#endif // _MSC_VER >= 1300 + +// end_wdm end_ntminiport + +#define WIN_ASSERT NT_ASSERT +#define WIN_ASSERTMSG NT_ASSERTMSG +#define WIN_ASSERTMSGW NT_ASSERTMSGW +#define WIN_VERIFY NT_VERIFY +#define WIN_VERIFYMSG NT_ASSERTMSG +#define WIN_VERIFYMSGW NT_ASSERTMSGW + diff --git a/src/inc/winrt/paraminstanceapi.h b/src/inc/winrt/paraminstanceapi.h new file mode 100644 index 0000000000..f2a15e115a --- /dev/null +++ b/src/inc/winrt/paraminstanceapi.h @@ -0,0 +1,1750 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +/*************************************************************** + +* +* Portions of this header fall under the following +* copyrights and/or licenses: +* +* rfc4122 and supporting functions +* * Algorithm from RFC 4122 - A Universally Unique IDentifier (UUID) URN Namespace +* * By Paul J. Leach, Michael Mealling and Rich Sals, July 2005. +* * +* * This function is adapted from the routines in the document +* * uuid_create_sha1_from_name and format_uuid_v3or5 +* * +* * +* * Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. +* * Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & +* * Digital Equipment Corporation, Maynard, Mass. +* * Copyright (c) 1998 Microsoft. +* * To anyone who acknowledges that this file is provided "AS IS" +* * without any express or implied warranty: permission to use, copy, +* * modify, and distribute this file for any purpose is hereby +* * granted without fee, provided that the above copyright notices and +* * this notice appears in all source code copies, and that none of +* * the names of Open Software Foundation, Inc., Hewlett-Packard +* * Company, Microsoft, or Digital Equipment Corporation be used in +* * advertising or publicity pertaining to distribution of the software +* * without specific, written prior permission. Neither Open Software +* * Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital +* * Equipment Corporation makes any representations about the +* * suitability of this software for any purpose. +* * +*/ + +#ifdef _MSC_VER +#pragma once +#endif /* _MSC_VER */ + +#ifndef WINRT_PARAMINSTANCEAPI_H +#define WINRT_PARAMINSTANCEAPI_H + +#ifdef __cplusplus + +#ifdef _MSC_VER +#pragma warning( push ) +#pragma warning( disable : 4180 ) // qualifier applied to function type has no meaning; ignored +#endif + +#include <wtypes.h> +#include <ntassert.h> +#include <sal.h> +#include <stdlib.h> +#include <string.h> +#include <objbase.h> +#include <limits.h> + +//#ifdef _MSC_VER +//#include <new.h> +//#else +//#include <new> +//#endif + +#ifndef WINRT_PARAMINSTANCE_NOCRYPT_SHA1 +#include <bcrypt.h> +#endif + +#ifdef _MSC_VER +#pragma push_macro("CHKHR") +#pragma push_macro("CHKNT") +#endif + +namespace Ro { namespace detail { + + // + // Debugging aide. Set breakpoint on _FailedHR + // to see HRESULT propogation. + // + #ifdef DBG + inline HRESULT __declspec(noinline) _FailedHR(HRESULT hr) { static HRESULT _hr = hr; return hr; } + #else + inline HRESULT _FailedHR(HRESULT hr) { return hr; } + #endif +}} + +#undef CHKHR +// +// Call HRESULT returning code and propogate any errors. +// Note: only use in code that is exception-safe / uses RAII. +// +#define CHKHR(expr) \ + { HRESULT _zzhr; \ + _zzhr = expr; \ + if (FAILED(_zzhr)) return Ro::detail::_FailedHR(_zzhr); } + +#undef CHKNT +// +// Call NTSTATUS returning code and propogate any errors, as HRESULTs. +// Note: +// - only use in code that is exception-safe / uses RAII / RRID. +// - HRESULT_FROM_NT does safely convert STATUS_SUCCESS into +// a SUCCEEDED hr. +// +#define CHKNT(expr) \ + CHKHR( HRESULT_FROM_NT( expr ) ) + +namespace Ro { namespace detail { + + // + // Runtime check for an invariant. This check executes in release builds. + // + + inline HRESULT Verify(bool invariant, HRESULT defaultHr = E_UNEXPECTED) + { + if (!invariant) + { + CHKHR(defaultHr); + } + return S_OK; + } +}} + + +extern "C" { + + +// sha1 adaptor +// create hash instance + +HRESULT _RoSha1Create( + __out void** handle); + + +// sha1 adaptor +// append more data to the input stream + +HRESULT _RoSha1AppendData( + __in void* handle, + __in size_t numBytes, + __in_bcount(numBytes) const void* data); + + +// sha1 adaptor +// return the first 16 bytes of SHA1 hash + +HRESULT _RoSha1Finish( + __in void* handle, + __out BYTE (*hashValue)[20]); + + +// sha1 adaptor +// free this instance + +void _RoSha1Release(__in void* handle); + +} + +struct IRoSimpleMetaDataBuilder; +struct IRoMetaDataLocator; + +// The 'detail' namespace includes implementation details that +// are subject to change without notice. +namespace Ro { namespace detail +{ + struct SimpleMetaDataBuffer; +}} + + +// +// Purpose: +// Given a parameterized type instance name and metadata, +// computes the IID for that instance. +// +// Parameters: +// +// nameElementCount +// number of elements in nameElements +// nameElements +// a parsed WinRt type name, as would be returned by RoParseTypeName. +// Eg: ["W.F.C.IVector`1", "N1.N2.IFoo"] +// metaDataLocator +// A callback to use for resolving metadata. +// +// An implementation could, for example, forward all calls +// to RoGetMetaData, then passing the results to +// RoWriteImporterToPushSimpleMetaData. As RoGetMetadata does +// not cache results, such an implementation would be inefficient. +// A better implementation will cache the results to RoGetMetaData, +// as appropriate. +// +// The Locator helper function can be used to wrap a lambda +// expression, or function pointer. eg: +// RoGetParameterizedTypeInstanceIID( +// ..., +// Locate([&](PCWSTR* name, IRoSimpleMetaDataBuilder& push){...}), +// ...); +// iid +// out param. Returns the iid for the parameterized type specified +// by nameElements +// extra +// out param. returns a handle that holds extra information about the +// IID result, for diagnostic purposes. If this handle is not desired, +// provide nullptr instead. +// +// Notes: +// - This function is stateless. IRoMetaDataLocator will not be preserved +// between calls. +// - This function does not perform deep semantic analysis. For instance, +// if IRoSimpleMetaDataBuilder specifies that a struct contains an interface pointer, +// this API will return success, even though such metadata is semantically +// invalid. The value of the IID returned is unspecified in such cases. +// - This function does introduce reentrancy. Its implementation +// of IRoSimpleMetaDataBuilder may make reentrant calls to IRoMetaDataLocator. +// - If a call to IRoSimpleMetaDataBuilder fails, this function will return that +// failure code. +// + + +DECLARE_HANDLE(ROPARAMIIDHANDLE); + +inline HRESULT RoGetParameterizedTypeInstanceIID( + UINT32 nameElementCount, + __in_ecount(nameElementCount) PCWSTR* nameElements, + __in const IRoMetaDataLocator& metaDataLocator, + __out GUID* iid, + __deref_opt_out ROPARAMIIDHANDLE* pExtra = nullptr); + +// Frees the 'extra' handle allocated +// by RoGetParameterizedTypeInstanceIID +inline void RoFreeParameterizedTypeExtra(__in ROPARAMIIDHANDLE extra); + +// Fetches the TypeSignature used to compute the IID by the last +// call to RoGetParameterizedTypeInstanceIID on this extra handle. +// The string contains ASCII code only, and the string is valid +// until RoFreeParameterizedTypeExtra is called on the extra pointer. +inline PCSTR RoParameterizedTypeExtraGetTypeSignature(__in ROPARAMIIDHANDLE extra); + +namespace Ro { namespace detail +{ + + // private type used in helper function + + template <typename Fn> + struct _Locator; +}} // namespace Ro::detail + +namespace Ro +{ + + // helper function to create IRoMetaDataLocator from lambda expression + + template <typename Fn> + Ro::detail::_Locator<Fn> Locator(const Fn& fn); +} // namespace Ro + + +// +// Purpose: +// Destination for IRoMetaDataLocator::Locate to write parsed metadata to. +// 'Locate' should set the appropriate Windows Runtime metadata information gleaned +// from Windows Runtime metadata file, or other appropriate source. +// +// Notes: +// - Methods for base types and COM interfaces (eg, Int32 and IInspectable +// respectively) are not needed -- RoGetParameterizedTypeInstanceIID already +// knows the WinRT base type names, so will not invoke IMetDataLocator +// to discover them. +// - This is not a COM interface. It does not derive from IUnknown. +// + +struct IRoSimpleMetaDataBuilder +{ + + // Notes: + // IInspectable and other non-WinRT interfaces are not permissible. + // Not for use with parameterized type instances. See SetParameterizedInterface + + STDMETHOD(SetWinRtInterface)( + GUID iid) = 0; + + + // Notes: + // Not for use with parameterized type instances. See SetParameterizedDelegate + + STDMETHOD(SetDelegate)( + GUID iid) = 0; + + + // Notes: + // Call this method when an interface group has a default interface + // that is a non-parametric type. + + STDMETHOD(SetInterfaceGroupSimpleDefault)( + PCWSTR name, + PCWSTR defaultInterfaceName, + __in_opt const GUID* defaultInterfaceIID) = 0; + + + // Notes: + // Call this method when an interface group has a parameterized + // interface as its default interface. + + STDMETHOD(SetInterfaceGroupParameterizedDefault)( + PCWSTR name, + UINT32 elementCount, + __in_ecount(elementCount) PCWSTR* defaultInterfaceNameElements) = 0; + + STDMETHOD(SetRuntimeClassSimpleDefault)( + PCWSTR name, + PCWSTR defaultInterfaceName, + __in_opt const GUID* defaultInterfaceIID) = 0; + + STDMETHOD(SetRuntimeClassParameterizedDefault)( + PCWSTR name, + UINT32 elementCount, + __in_ecount(elementCount) PCWSTR* defaultInterfaceNameElements) = 0; + + STDMETHOD(SetStruct)( + PCWSTR name, + UINT32 numFields, + __in_ecount(numFields) PCWSTR* fieldTypeNames) = 0; + + STDMETHOD(SetEnum)( + PCWSTR name, + PCWSTR baseType) = 0; + + + // Notes: + // This is only for the 'non-instantiated' parameterized interface itself - + // instances are handled by RoGetParameterizedTypeInstanceIID, and the + // caller need not parse them. + + STDMETHOD(SetParameterizedInterface)( + GUID piid, + UINT32 numArgs) = 0; + + STDMETHOD(SetParameterizedDelegate)( + GUID piid, + UINT32 numArgs) = 0; +}; + + +// +// Purpose: +// Callback for resolving metadata. +// + +struct IRoMetaDataLocator +{ + + // + // Parameters: + // nameElement + // a metadata typeref name to resolve. + // Eg: "N1.N2.IFoo", or "W.F.C.IVector`1". + // pushMetaData + // data sink for providing information about the + // type information for nameElement + // + + STDMETHOD(Locate)( + PCWSTR nameElement, + __in IRoSimpleMetaDataBuilder& metaDataDestination + ) const = 0; +}; + +namespace Ro { namespace detail { + + + // + // helper function, moves range of elements + // + + template <typename T> + void _VecMoveRange( + __in_ecount(size) T* dst, + __in_ecount(size) T* src, + size_t size) + { + for (size_t i = 0; i != size; ++i) + { + dst[i] = static_cast<T&&>(src[i]); + } + } + + // + // specializations to move strings more efficiently + // + + inline void _VecMoveRange( + __in_ecount(size) char* dst, + __in_ecount(size) char* src, + size_t size) + { + errno_t err = memcpy_s(dst, size*sizeof(*dst), src, size*sizeof(*dst)); + NT_ASSERT(!err); + (void)err; + } + inline void _VecMoveRange( + __in_ecount(size) wchar_t* dst, + __in_ecount(size) wchar_t* src, + size_t size) + { + errno_t err = memcpy_s(dst, size*sizeof(*dst), src, size*sizeof(*dst)); + NT_ASSERT(!err); + (void)err; + } + + + // + // helper function, moves range of elements + // + + template <typename T> + void _VecCopyRange( + __in_ecount(size) T* dst, + __in_ecount(size) const T* src, + size_t size) + { + for (size_t i = 0; i != _size; ++i) + { + dst[i] = src[i]; + } + } + + // + // specializations to move strings more efficiently + // + + inline void _VecCopyRange( + __in_ecount(size) char* dst, + __in_ecount(size) const char* src, + size_t size) + { + errno_t err = memcpy_s(dst, size*sizeof(*dst), const_cast<char*>(src), size*sizeof(*dst)); + NT_ASSERT(!err); + (void)err; + } + inline void _VecCopyRange( + __in_ecount(size) wchar_t* dst, + __in_ecount(size) const wchar_t* src, + size_t size) + { + errno_t err = memcpy_s(dst, size*sizeof(*dst), const_cast<wchar_t*>(src), size*sizeof(*dst)); + NT_ASSERT(!err); + (void)err; + } + + // + // Single-owner smart pointer for arrays + // + + template <class T> + struct ArrayHolder + { + ArrayHolder() : _value(NULL) + { + } + T* Value() const + { + return _value; + } + T*& Value() + { + return _value; + } + T* Detach() + { + T* tmp = _value; + _value = NULL; + return tmp; + } + ~ArrayHolder() + { + delete[] _value; + } + + private: + T* _value; + }; + + // + // Single-owner smart pointer for object pointer + // + + template <class T> + struct ElementHolder + { + ElementHolder() : _value(NULL) + { + } + T* operator->() const + { + return _value; + } + T* Value() const + { + return _value; + } + T*& Value() + { + return _value; + } + T* Detach() + { + T* tmp = _value; + _value = NULL; + return tmp; + } + ~ElementHolder() + { + delete _value; + } + + private: + T* _value; + }; + + + + // + // simple vector, with small vector optimization + // T - must be default constructable and movable. + // const input overload of AppendN requires copyable. + // FixedBufSize - number of bytes to use for small array + // optimization, to avoid heap allocation in case of + // small vectors. Defaults to at least one element, + // otherwise the largest value such that <= 64 bytes + // are used. + // + + template < + typename T, + size_t FixedBufSize = 0 + > + class Vec + { + private: + static const size_t _fixedBufSize = + FixedBufSize/sizeof(T) + ? FixedBufSize/sizeof(T) + : (((64/sizeof(T)) > 0) ? (64/sizeof(T)) + : 1); + public: + Vec() : + _size(0), + _cap(_countof(_fixedBuf)), + _buf(_fixedBuf) + { + } + + + // Appends an element, or a default value if one + // it not specified. If called with an rvalue, + // it uses move assignment instead of copy. + + HRESULT Append(T value = T()) + { + if (_cap - _size < 1) + { + CHKHR(_Grow()); + } + _buf[_size] = static_cast<T&&>(value); + ++_size; + + return S_OK; + } + + // Moves elements (move assignment) into array. + + HRESULT MoveN(__in_ecount(n) T* values, size_t n) + { + if (_cap - _size < n) + { + CHKHR(_Grow(n - (_cap - _size))); + } + _VecMoveRange(_buf + _size, values, n); + _size += n; + + return S_OK; + } + + + // Appends elements. Does not invoke move assignment. + + HRESULT AppendN(__in_ecount(n) const T* values, size_t n) + { + if (_cap - _size < n) + { + CHKHR(_Grow(n - (_cap - _size))); + } + _VecCopyRange(_buf + _size, values, n); + _size += n; + + return S_OK; + } + + HRESULT Pop() + { + CHKHR(Verify( _size > 0 )); + --_size; + return S_OK; + } + + HRESULT Resize(size_t newSize) + { + if (_cap < newSize) + { + CHKHR(_Grow(newSize - _cap)); + } + _size = newSize; + return S_OK; + } + + size_t Size() const + { + return _size; + } + + T& operator[](size_t index) + { + NT_ASSERT(index < _size); + return _buf[index]; + } + + T& Last() + { + return (*this)[_size-1]; + } + + ~Vec() + { + if (_buf != _fixedBuf) + { + delete[] _buf; + } + } + + private: + + // + // growth factor (does not check for overflow) -- returns ammount to grow by + // + + static size_t _GrowthIncrement(size_t n) + { + return n / 2; + } + + HRESULT _Grow(size_t byAtLeast = 4) + { + size_t increase = _GrowthIncrement(_cap); + if (increase < byAtLeast) + { + increase = byAtLeast; + } + size_t newCap = _cap + increase; + if (newCap <= _cap) + { + CHKHR(E_OUTOFMEMORY); + } + ArrayHolder<T> newBuf; + + void* p = (newBuf.Value() = new (std::nothrow) T[newCap]); + if (!p) + { + CHKHR(E_OUTOFMEMORY); + } + + _VecMoveRange( newBuf.Value(), _buf, _size ); + + if (_buf != _fixedBuf) + { + delete _buf; + } + _buf = newBuf.Detach(); + _cap = newCap; + + return S_OK; + } + + size_t _size; + size_t _cap; + T* _buf; + T _fixedBuf[_fixedBufSize]; + }; + + struct SimpleMetaDataBuilder : IRoSimpleMetaDataBuilder + { + public: + SimpleMetaDataBuilder(SimpleMetaDataBuffer& buffer, const IRoMetaDataLocator& locator) + : _buffer(&buffer), _locator(&locator), _invoked(false) + { + } + IFACEMETHOD(SetWinRtInterface)(GUID iid); + IFACEMETHOD(SetDelegate)(GUID iid); + IFACEMETHOD(SetInterfaceGroupSimpleDefault)(PCWSTR name, PCWSTR defaultInterfaceName, __in_opt const GUID *defaultInterfaceIID); + IFACEMETHOD(SetInterfaceGroupParameterizedDefault)(PCWSTR name, UINT32 elementCount, __in_ecount(elementCount) PCWSTR *defaultInterfaceNameElements); + IFACEMETHOD(SetRuntimeClassSimpleDefault)(PCWSTR name, PCWSTR defaultInterfaceName, __in_opt const GUID *defaultInterfaceIID); + IFACEMETHOD(SetRuntimeClassParameterizedDefault)(PCWSTR name, UINT32 elementCount, __in_ecount(elementCount) PCWSTR *defaultInterfaceNameElements); + IFACEMETHOD(SetStruct)(PCWSTR name, UINT32 numFields, __in_ecount(numFields) PCWSTR *fieldTypeNames); + IFACEMETHOD(SetEnum)(PCWSTR name, PCWSTR baseType); + IFACEMETHOD(SetParameterizedInterface)(GUID piid, UINT32 numArgs); + IFACEMETHOD(SetParameterizedDelegate)(GUID piid, UINT32 numArgs); + + + // Runs the locating process for a parameterized type. + // Notes: + // _buffer->_nestingLevel is used to determine the number of + // arguments left to consume for nested parameterized types. + + HRESULT SendArguments(UINT32 nameElementCount, __in_ecount(nameElementCount) PCWSTR *nameElements); + + private: + + + // Writes the type signature for the type 'name' + // Notes: + // - If a builtin type, writes the type directly. + // - Otherwise, uses the IRoMetaDataLocator to + // write the type signature into _buffer + // - As the sole function to call + // IRoMetaDataLocator, it also performs the check + // on recursion depth bounds. + + HRESULT _WriteType(PCWSTR name); + + + // The tail portion of IG and RC formats is the same. This + // function implements the shared portion of that format. + + HRESULT _CommonInterfaceGroupSimple(PCWSTR name, PCWSTR defaultInterfaceName, __in_opt const GUID *defaultInterfaceIID); + + + // Called at the begining of every 'Set' method. Set must only be called once. + + HRESULT _OnSet(); + + + // Called at the end of every 'Set' method, only if successful. + + void _Completed(); + + static char _AsciiLower(char ch) + { + if ('A' <= ch && ch <= 'Z') + { + return ch + ('a' - 'A'); + } + else + { + return ch; + } + } + + + // Writes a guid into the type signature being built, in lower case. + + HRESULT _WriteGuid(const GUID& iid); + HRESULT _WriteString(PCSTR str); + HRESULT _WriteChar(char c); + HRESULT _WriteWideString(PCWSTR str); + + SimpleMetaDataBuilder(); + SimpleMetaDataBuilder(const SimpleMetaDataBuilder&); + void operator=(const SimpleMetaDataBuilder&); + + SimpleMetaDataBuffer* _buffer; + const IRoMetaDataLocator* _locator; + bool _invoked; + }; + + + // If the type string describes a built-in type, modifies + // this instance to use builtin type table entry instead of name. + + inline bool _IsBuiltin(__in PCWSTR name, __out PCSTR * typeSignature) + { + *typeSignature = nullptr; + + struct BuiltinEntry { PCWSTR name; PCSTR typeSignature; }; + static const BuiltinEntry entries[] = { + + { L"UInt8", "u1" }, + { L"Int16", "i2" }, + { L"UInt16", "u2" }, + { L"Int32", "i4" }, + { L"UInt32", "u4" }, + { L"Int64", "i8" }, + { L"UInt64", "u8" }, + { L"Single", "f4" }, + { L"Double", "f8" }, + { L"Boolean", "b1" }, + { L"Char16", "c2" }, + { L"String", "string" }, + { L"Guid", "g16" }, + { L"Object", "cinterface(IInspectable)" }, + }; + for (const BuiltinEntry* tip = entries; + tip != &entries[_countof(entries)]; + ++tip) + { + if (wcscmp(tip->name, name) == 0) + { + *typeSignature = tip->typeSignature; + return true; + } + } + + // if not found, assume is a normal type name + + return false; + } + + + // Linked list (stack allocated) of type resolution calls, + // used to detect if an InterfaceGroup/RuntimeClass type + // signature depends on itself. In that case, we use "*" + // in the type signature instead of recurring further. + + struct ResolutionPathEntry + { + ResolutionPathEntry* _next; + PCWSTR _typeName; + + ResolutionPathEntry(PCWSTR typeName) + : _next(nullptr) + , _typeName(typeName) + { + } + }; + + inline void Push(ResolutionPathEntry*& top, ResolutionPathEntry* item) + { + item->_next = top; + top = item; + } + inline HRESULT Pop(ResolutionPathEntry*& top) + { + if (!top) + { + return E_UNEXPECTED; + } + top = top->_next; + return S_OK; + } + + + // Holds metadata state that is shared between RoGetParamInstanceIID and SimpleMetaDataBuilder + + struct SimpleMetaDataBuffer + { + SimpleMetaDataBuffer() + { + Clear(); + } + + // reset all tables + void Clear() + { + _recursionDepth = 0; + _topLevelTypes = 0; + _resolutionPath = nullptr; + _outputStream.Resize(0); + } + + static const size_t _maxTypeName = 256; + + + // Estimate of 'reasonable' level of Interface Group / Runtime + // Class / Parameterized Type nesting. + + static const size_t _maxRecursionDepth = 64; + + Vec<char, _maxTypeName> _outputStream; + ResolutionPathEntry* _resolutionPath; + + + // RAII object, places an item on the resolution path, and pops it on destruction + + class ResolutionPathGuard + { + private: + ResolutionPathEntry _entry; + SimpleMetaDataBuffer* _buffer; + + public: + ResolutionPathGuard(PCWSTR typeName, SimpleMetaDataBuffer* buffer) + : _buffer(buffer) + , _entry(typeName) + { + Push(buffer->_resolutionPath, &_entry); + } + ~ResolutionPathGuard() + { + HRESULT hr = Pop(_buffer->_resolutionPath); + NT_ASSERT(SUCCEEDED(hr)); + (void)hr; + } + }; + + + // Searches the resolution path for 'name' returning true if exists + + bool ExistsCycle(PCWSTR typeName) + { + for (auto pTip = _resolutionPath; pTip; pTip = pTip->_next) + { + if (wcscmp(typeName, pTip->_typeName) == 0) + { + return true; + } + } + return false; + } + + + // Indicates the nesting level of compound types, used + // to properly balance parenthesis on parameterized types, + // and used to bound recursion depth. + // + // - Pinterfaces + // : push 'numArgs' on to _nestingLevel + // - A compound type that doesn't know number of arguments + // eg, RoGetParameterizedInstanceIID arguments, or + // SetIG..Parameterized + // : will 0) note nesting level + // 1) iteratate calling Locate on the compound arguments. + // 2) the above should cause exactly one push of _nestingLevel + // 3) reduce nexting level back to original nesting level, + // inserting the difference in closing parens + // - Compount types that do know number of arguments (eg SetStruct) + // : will 1) increase nesting level by 1 + // 2) iteratate calling Locate on arguments + // 3) decreate nesting level again + // + // + + Vec<size_t> _nestedArgs; + + // topLevelTypes should be incremented once, by the initial + // parameterized type, then never again. + + size_t _topLevelTypes; + size_t _recursionDepth; + }; +}} // namespace Ro::detail + +namespace Ro { namespace detail +{ + template <typename Fn> + struct _Locator : IRoMetaDataLocator + { + Fn _fn; + + _Locator(const Fn& fn) + : _fn(fn) + { + } + + IFACEMETHOD(Locate)( + PCWSTR name, + IRoSimpleMetaDataBuilder& pushMetaData) const + { + return _fn(name, pushMetaData); + } + }; +}} // namespace Ro::detail + +namespace Ro +{ + template <typename Fn> + Ro::detail::_Locator<Fn> Locator(const Fn& fn) + { + return Ro::detail::_Locator<Fn>(fn); + } +} + +namespace Ro { namespace detail +{ + + // Figure out if we're compiling for a big- or little-endian machine. + + inline bool BigEndian() + { + unsigned long n = 0xff000000L; + + return 0 != *reinterpret_cast<unsigned char *>(&n); + } + + + // HostToNetworkLong converts a 32-bit long to network byte order + + inline ULONG HostToNetworkLong(ULONG hostlong) + { + if (BigEndian()) + return hostlong; + else + return ( (hostlong >> 24) & 0x000000FFL) | + ( (hostlong >> 8) & 0x0000FF00L) | + ( (hostlong << 8) & 0x00FF0000L) | + ( (hostlong << 24) & 0xFF000000L); + } + + + // HostToNetworkLong converts a 16-bit short to network byte order + + inline USHORT HostToNetworkShort(USHORT hostshort) + { + if (BigEndian()) + return hostshort; + else + return ((hostshort >> 8) & 0x00FF) | ((hostshort << 8) & 0xFF00); + } + + + // NetworkToHostLong converts a 32-bit long to local host byte order + + inline ULONG NetworkToHostLong(ULONG netlong) + { + if (BigEndian()) + return netlong; + else + return ( (netlong >> 24) & 0x000000FFL) | + ( (netlong >> 8) & 0x0000FF00L) | + ( (netlong << 8) & 0x00FF0000L) | + ( (netlong << 24) & 0xFF000000L); + } + + + // NetworkToHostShort converts a 16-bit short to local host byte order + + inline USHORT NetworkToHostShort(USHORT netshort) + { + if (BigEndian()) + return netshort; + else + return ((netshort >> 8) & 0x00FF) | ((netshort << 8) & 0xFF00); + } + + + // smart pointer for Sha1 handle + + struct Sha1Holder + { + Sha1Holder() : _handle(nullptr) + { + } + void*& Value() + { + return _handle; + } + ~Sha1Holder() + { + if (_handle) + { + _RoSha1Release(_handle); + } + } + private: + void* _handle; + }; + + + + // + // Computes the rfc4122 v5 UUID from GUID,name pair. + // + // Notes: + // - see copyright at begining of file. + // + + inline HRESULT + GuidFromName( + __in const GUID& guidNamespace, + __in_bcount(dwcbSize) const void* pbName, + __in DWORD dwcbSize, + __out GUID* pGuid) + { + Sha1Holder sha1; + + CHKHR( _RoSha1Create(&sha1.Value()) ); + { + GUID networkOrderGuidNamespace = guidNamespace; + + // Put name space ID in network byte order so it hashes the same + // no matter what endian machine we're on + + if (!BigEndian()) + { + networkOrderGuidNamespace.Data1 = HostToNetworkLong (networkOrderGuidNamespace.Data1); + networkOrderGuidNamespace.Data2 = HostToNetworkShort(networkOrderGuidNamespace.Data2); + networkOrderGuidNamespace.Data3 = HostToNetworkShort(networkOrderGuidNamespace.Data3); + } + CHKHR( _RoSha1AppendData(sha1.Value(), sizeof(networkOrderGuidNamespace), reinterpret_cast<BYTE*>(&networkOrderGuidNamespace)) ); + } + CHKHR( _RoSha1AppendData(sha1.Value(), dwcbSize, pbName) ); + + { + BYTE sha1Result[20]; + CHKHR( _RoSha1Finish(sha1.Value(), &sha1Result) ); + + errno_t err = memcpy_s(pGuid, sizeof(GUID), &sha1Result[0], sizeof(GUID)); + CHKHR(Verify( 0 == err )); + + + // Restore the byte order + + if (!BigEndian()) + { + pGuid->Data1 = NetworkToHostLong (pGuid->Data1); + pGuid->Data2 = NetworkToHostShort(pGuid->Data2); + pGuid->Data3 = NetworkToHostShort(pGuid->Data3); + } + + + // set version number + // 1: clear version number nibble + // 2: set version 5 = name-based SHA1 + + pGuid->Data3 &= 0x0FFF; + pGuid->Data3 |= (5 << 12); + + + // set variant field by clearing variant bits. + + pGuid->Data4[0] &= 0x3F; + pGuid->Data4[0] |= 0x80; + } + return S_OK; + } +}} // namespace Ro::detail + +inline HRESULT RoGetParameterizedTypeInstanceIID( + UINT32 nameElementCount, + __in_ecount(nameElementCount) PCWSTR* nameElements, + __in const IRoMetaDataLocator& metaDataLocator, + __out GUID* iid, + __deref_opt_out ROPARAMIIDHANDLE* pExtra) +{ + using namespace Ro::detail; + memset(iid, 0, sizeof(*iid)); + + SimpleMetaDataBuffer reserveBuffer; + SimpleMetaDataBuffer *pBuffer = &reserveBuffer; + + // if user wishes to hold on to the result value, + // dynamically allocate this buffer. + if (pExtra) + { + pBuffer = new (std::nothrow) SimpleMetaDataBuffer; + *pExtra = static_cast<ROPARAMIIDHANDLE>(static_cast<void*>(pBuffer)); + } + SimpleMetaDataBuffer& buffer = *pBuffer; + SimpleMetaDataBuilder builder(*pBuffer, metaDataLocator); + + // send initial arguments + CHKHR(builder.SendArguments(nameElementCount, nameElements)); + + // verify that precisely one type was resolved, to completion. + CHKHR(Verify(buffer._topLevelTypes == 1 + && buffer._nestedArgs.Size() == 0, + E_INVALIDARG)); + + // compute type signature hash + static const GUID guidPinterfaceNamespace + = { 0x11f47ad5, 0x7b73, 0x42c0, { 0xab, 0xae, 0x87, 0x8b, 0x1e, 0x16, 0xad, 0xee }}; + + CHKHR(Ro::detail::Verify( buffer._outputStream.Size() <= DWORD(-1) )); + + // null terminate + CHKHR( buffer._outputStream.Append('\0') ); + + + // + // Unit test logging, to verify proper signatures + // + #ifdef UNITTEST_TRACE + { + CHKHR( UNITTEST_TRACE("type signature", &buffer._outputStream[0]) ); + } + #endif + + + CHKHR( GuidFromName(guidPinterfaceNamespace, + &buffer._outputStream[0], + DWORD(buffer._outputStream.Size() - 1), // does not include terminator + iid) ); + return S_OK; +} + +inline void RoFreeParameterizedTypeExtra(__in ROPARAMIIDHANDLE extra) +{ + using namespace Ro::detail; + delete static_cast<SimpleMetaDataBuffer*>(static_cast<void*>(extra)); +} +inline PCSTR RoParameterizedTypeExtraGetTypeSignature(__in ROPARAMIIDHANDLE extra) +{ + using namespace Ro::detail; + SimpleMetaDataBuffer* pBuffer = static_cast<SimpleMetaDataBuffer*>(static_cast<void*>(extra)); + + return &pBuffer->_outputStream[0]; +} + +namespace Ro { namespace detail +{ + + inline HRESULT SimpleMetaDataBuilder::_WriteType(PCWSTR name) + { + PCSTR builtInName = nullptr; + SimpleMetaDataBuilder builder(*_buffer, *_locator); + + if (_IsBuiltin(name, &builtInName)) + { + CHKHR(builder._OnSet()); + CHKHR(builder._WriteString(builtInName)); + builder._Completed(); + } + else + { + size_t newDepth = ++_buffer->_recursionDepth; + size_t pinterfaceNesting = _buffer->_nestedArgs.Size(); + if (newDepth + pinterfaceNesting > _buffer->_maxRecursionDepth) + { + + // Terminate recursion; bounds call stack consumption + + CHKHR(E_UNEXPECTED); + } + CHKHR(_locator->Locate(name, builder)); + + // Note, buffers aren't reusable, so it's fine that we don't + // unwind this value on return. Also note, we do not unwind + // this value if the user provides inconsitent data either + // (eg, if they provide only 1 argument to a 2 parameter + // parameterized type). + + --_buffer->_recursionDepth; + } + return S_OK; + } + + inline HRESULT SimpleMetaDataBuilder::_OnSet() + { + if (_invoked) + { + CHKHR(E_INVALIDARG); + } + _invoked = true; + + + // Reduce the number of arguments left for this compound type. + + if(_buffer->_nestedArgs.Size() > 0) + { + --(_buffer->_nestedArgs.Last()); + } + else + { + + // Increase number of top level types in signature + // string. (should never exceed one) + + ++_buffer->_topLevelTypes; + } + + return S_OK; + } + + inline void SimpleMetaDataBuilder::_Completed() + { + } + inline HRESULT SimpleMetaDataBuilder::SendArguments(UINT32 nameElementCount, __in_ecount(nameElementCount) PCWSTR *nameElements) + { + CHKHR(Verify(nameElementCount > 0)); + + CHKHR(Verify(_buffer->_nestedArgs.Size() <= UINT32(-1))); + UINT32 previousLevel = UINT32(_buffer->_nestedArgs.Size()); + + for (UINT32 i = 0; i < nameElementCount; ++i) + { + CHKHR(_WriteType(nameElements[i])); + + + // Close any nested parameterized types that are complete + + while (_buffer->_nestedArgs.Size() > previousLevel + && _buffer->_nestedArgs.Last() == 0) + { + CHKHR(_buffer->_nestedArgs.Pop()); + CHKHR(_WriteChar(')')); + } + + // insert separator between parameterized type arguments + + CHKHR(_WriteChar(';')); + } + + // remove final separator + + CHKHR(_buffer->_outputStream.Pop()); + + + // Verify that all the arguments were consumed. + + CHKHR(Verify(_buffer->_nestedArgs.Size() == previousLevel, + E_INVALIDARG)); + return S_OK; + } + + inline HRESULT SimpleMetaDataBuilder::_WriteGuid(const GUID& iid) + { + static const size_t guidStringLength = _countof("{11223344-1122-1122-1122-334455667788}") - 1; + WCHAR tmpString[guidStringLength+1]; + + int numWritten = StringFromGUID2(iid, tmpString, guidStringLength + 1); + CHKHR(Verify( numWritten == guidStringLength + 1 )); + NT_ASSERT( numWritten == guidStringLength + 1 ); + + size_t offset = _buffer->_outputStream.Size(); + CHKHR(Verify( offset + guidStringLength > offset )) + CHKHR( _buffer->_outputStream.Resize(offset + guidStringLength) ); + char* writePtr = &_buffer->_outputStream[offset]; + + + // All characters are ascii. Just truncate. + + for(size_t i = 0; i < guidStringLength; ++i) + { + writePtr[i] = _AsciiLower(char(tmpString[i])); + } + return S_OK; + } + inline HRESULT SimpleMetaDataBuilder::_WriteString(PCSTR str) + { + CHKHR( _buffer->_outputStream.AppendN(str, strlen(str)) ); + return S_OK; + } + inline HRESULT SimpleMetaDataBuilder::_WriteChar(char c) + { + CHKHR( _buffer->_outputStream.Append(c) ); + return S_OK; + } + inline HRESULT SimpleMetaDataBuilder::_WriteWideString(PCWSTR str) + { + size_t len = wcslen(str); + size_t offset = _buffer->_outputStream.Size(); + int written; + + + // provision enough space for conversion to take place + + size_t provision = len + 1; + for(;;) + { + CHKHR( _buffer->_outputStream.Resize(offset+provision)); + char* writePtr = &_buffer->_outputStream[offset]; + + CHKHR(Verify(len <= INT_MAX)); + CHKHR(Verify(provision <= INT_MAX)); + + written = WideCharToMultiByte( + CP_UTF8, + 0, + str, + int(len), + writePtr, + int(provision), + nullptr, + nullptr + ); + + if (written > 0) + { + break; + } + else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + { + CHKHR(HRESULT_FROM_WIN32(GetLastError())); + } + else + { + provision *= 2; + CHKHR(Verify( offset + provision > offset )); + } + } + + // reduce size to reflect number of characters actually written. + // Note that since we specified string length, no null terminator + // was injected, so we don't have to remove it. + + CHKHR( _buffer->_outputStream.Resize(offset+written) ); + + return S_OK; + } + + inline __override HRESULT STDMETHODCALLTYPE SimpleMetaDataBuilder::SetWinRtInterface( + GUID iid) + { + CHKHR(_OnSet()); + + CHKHR(_WriteGuid(iid)); + + _Completed(); + return S_OK; + } + + inline __override HRESULT STDMETHODCALLTYPE SimpleMetaDataBuilder::SetDelegate( + GUID iid) + { + CHKHR(_OnSet()); + + CHKHR(_WriteString("delegate(")); + CHKHR(_WriteGuid(iid)); + CHKHR(_WriteChar(')')); + + _Completed(); + return S_OK; + } + + inline HRESULT SimpleMetaDataBuilder::_CommonInterfaceGroupSimple( + PCWSTR name, + PCWSTR defaultInterfaceName, + __in_opt const GUID * defaultInterfaceIID) + { + CHKHR(_WriteWideString(name)); + CHKHR(_WriteChar(';')); + + + // InterfaceGroups and RuntimeClasses take one nested argument + + CHKHR(_buffer->_nestedArgs.Append(1)); + if (!defaultInterfaceIID) + { + CHKHR(_WriteType(defaultInterfaceName)); + } + else + { + + // complete the type signature immediately; no nested + // call needed to resolve the interface. + + SimpleMetaDataBuilder builder(*_buffer, *_locator); + CHKHR(builder.SetWinRtInterface(*defaultInterfaceIID)) + } + CHKHR(_WriteChar(')')); + CHKHR(_buffer->_nestedArgs.Pop()); + return S_OK; + } + + inline __override HRESULT STDMETHODCALLTYPE SimpleMetaDataBuilder::SetInterfaceGroupSimpleDefault( + PCWSTR name, + PCWSTR defaultInterfaceName, + __in_opt const GUID* defaultInterfaceIID) + { + CHKHR(_OnSet()); + + CHKHR(_WriteString("ig(")); + CHKHR(_CommonInterfaceGroupSimple(name, defaultInterfaceName, defaultInterfaceIID)); + + _Completed(); + return S_OK; + } + + + inline __override HRESULT STDMETHODCALLTYPE SimpleMetaDataBuilder::SetInterfaceGroupParameterizedDefault( + PCWSTR name, + UINT32 elementCount, + __in_ecount(elementCount) PCWSTR* defaultInterfaceNameElements) + { + CHKHR(_OnSet()); + + + // If an inteface group or runtime class has a compount type as its default, and that + // type directly or indirectly refers to itself, the second occurance instead used '*' + // to signal that the default interface has already been specified earlier up the call + // stack. This prevents unbounded recursion. + + if (_buffer->ExistsCycle(name)) + { + CHKHR( _WriteString("ig(") ); + CHKHR( _WriteWideString(name) ); + CHKHR( _WriteString(";*)") ); + } + else + { + SimpleMetaDataBuffer::ResolutionPathGuard guard(name, _buffer); + + CHKHR( _WriteString("ig(") ); + CHKHR( _WriteWideString(name) ); + CHKHR( _WriteChar(';') ); + + + // InterfaceGroups and RuntimeClasses take one nested argument + + CHKHR( _buffer->_nestedArgs.Append(1) ); + CHKHR( SendArguments(elementCount, defaultInterfaceNameElements) ); + CHKHR( _buffer->_nestedArgs.Pop() ); + CHKHR( _WriteChar(')') );; + + } + _Completed(); + return S_OK; + } + + inline __override HRESULT STDMETHODCALLTYPE SimpleMetaDataBuilder::SetRuntimeClassSimpleDefault( + PCWSTR name, + PCWSTR defaultInterfaceName, + __in_opt const GUID* defaultInterfaceIID) + { + CHKHR(_OnSet()); + + CHKHR(_WriteString("rc(")); + CHKHR(_CommonInterfaceGroupSimple(name, defaultInterfaceName, defaultInterfaceIID)); + + _Completed(); + return S_OK; + } + + + inline __override HRESULT STDMETHODCALLTYPE SimpleMetaDataBuilder::SetRuntimeClassParameterizedDefault( + PCWSTR name, + UINT32 elementCount, + __in_ecount(elementCount) PCWSTR* defaultInterfaceNameElements) + { + CHKHR(_OnSet()); + + if (_buffer->ExistsCycle(name)) + { + CHKHR(_WriteString("rc(")); + CHKHR(_WriteWideString(name)); + CHKHR(_WriteString(";*)")); + } + else + { + SimpleMetaDataBuffer::ResolutionPathGuard guard(name, _buffer); + + CHKHR(_WriteString("rc(")); + CHKHR(_WriteWideString(name)); + CHKHR(_WriteChar(';')); + + + // InterfaceGroups and RuntimeClasses take one nested argument + + CHKHR(_buffer->_nestedArgs.Append(1)); + CHKHR(SendArguments(elementCount, defaultInterfaceNameElements)); + CHKHR(_buffer->_nestedArgs.Pop()); + + CHKHR(_WriteChar(')')); + } + _Completed(); + return S_OK; + } + + inline __override HRESULT STDMETHODCALLTYPE SimpleMetaDataBuilder::SetStruct( + PCWSTR name, + UINT32 numFields, + __in_ecount(numFields) PCWSTR* fieldTypeNames) + { + CHKHR(_OnSet()); + CHKHR(_WriteString("struct(")); + CHKHR(_WriteWideString(name)); + CHKHR(_WriteChar(';')); + + CHKHR(_buffer->_nestedArgs.Append(1)); + CHKHR(SendArguments(numFields, fieldTypeNames)); + CHKHR(_buffer->_nestedArgs.Pop()); + + CHKHR(_WriteChar(')')); + + _Completed(); + return S_OK; + } + + inline __override HRESULT STDMETHODCALLTYPE SimpleMetaDataBuilder::SetEnum( + PCWSTR name, + PCWSTR baseType) + { + CHKHR(_OnSet()); + + CHKHR(_WriteString("enum(")); + CHKHR(_WriteWideString(name)); + CHKHR(_WriteChar(';')); + CHKHR(_buffer->_nestedArgs.Append(1)); + CHKHR(_WriteType(baseType)); + CHKHR(_buffer->_nestedArgs.Pop()); + CHKHR(_WriteChar(')')); + + _Completed(); + return S_OK; + } + + inline __override HRESULT STDMETHODCALLTYPE SimpleMetaDataBuilder::SetParameterizedInterface( + GUID piid, + UINT32 numArgs) + { + CHKHR(_OnSet()); + + CHKHR(_WriteString("pinterface(")); + CHKHR(_WriteGuid(piid)); + + + // Note the number of arguments. The SendArguments + // function will append the ')' after that number of + // arguments are consumed. + + CHKHR(_buffer->_nestedArgs.Append(numArgs)); + + _Completed(); + return S_OK; + } + + inline __override HRESULT STDMETHODCALLTYPE SimpleMetaDataBuilder::SetParameterizedDelegate( + GUID piid, + UINT32 numArgs) + { + + // Parameterized interfaces and parameterized delegates use the same signature scheme. + + return SetParameterizedInterface(piid, numArgs); + } + +}} // namespace Ro::detail + +#ifndef WINRT_PARAMINSTANCE_NOCRYPT_SHA1 + +namespace Ro { namespace detail { + + class Sha1 + { + public: + Sha1() + : _hAlg(nullptr) + , _hHash(nullptr) + { + } + + HRESULT Initialize() + { + DWORD dwcb; + DWORD dwcbResult; + + CHKNT(BCryptOpenAlgorithmProvider(&_hAlg, BCRYPT_SHA1_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0)); + + CHKNT(BCryptGetProperty(_hAlg, BCRYPT_OBJECT_LENGTH, reinterpret_cast<PBYTE>(&dwcb), sizeof(dwcb), &dwcbResult, 0)); + + _ahBuf.Value() = new (std::nothrow) BYTE[dwcb]; + if (nullptr == _ahBuf.Value()) + { + CHKHR( E_OUTOFMEMORY ); + } + + CHKNT(BCryptCreateHash(_hAlg, &_hHash, _ahBuf.Value(), dwcb, NULL, 0, 0)); + return S_OK; + } + HRESULT AppendData(size_t numBytes, __in_bcount(numBytes) const void* bytes) + { + CHKHR(Verify(numBytes <= DWORD(-1))); + CHKNT(BCryptHashData(_hHash, reinterpret_cast<UCHAR*>(const_cast<void*>(bytes)), DWORD(numBytes), 0)); + return S_OK;; + } + HRESULT GetResult(__out BYTE (*hashValue)[20]) + { + + // Sha1 hash result is fixed size, at 20 bytes. + + CHKNT(BCryptFinishHash(_hHash, reinterpret_cast<PUCHAR>(&hashValue[0]), _countof(*hashValue), 0)); + return S_OK; + } + ~Sha1() + { + if (_hHash) + { + BCryptDestroyHash(_hHash); + } + if (_hAlg) + { + BCryptCloseAlgorithmProvider(_hAlg, 0); + } + } + private: + + ArrayHolder<BYTE> _ahBuf; + BCRYPT_ALG_HANDLE _hAlg; + BCRYPT_HASH_HANDLE _hHash; + }; +}} // namespace Ro::detail + +extern "C" +{ + +inline HRESULT _RoSha1Create( + __out void** handle) +{ + *handle = nullptr; + + Ro::detail::ElementHolder<Ro::detail::Sha1> sha1Instance; + sha1Instance.Value() = new (std::nothrow) Ro::detail::Sha1; + if (!sha1Instance.Value()) + { + CHKHR(E_OUTOFMEMORY); + } + CHKHR(sha1Instance->Initialize()); + + *handle = sha1Instance.Detach(); + return S_OK; +} + + +inline HRESULT _RoSha1AppendData( + __in void* handle, + __in size_t numBytes, + __in_bcount(numBytes) const void* data) +{ + Ro::detail::Sha1* sha1Instance = static_cast<Ro::detail::Sha1*>(handle); + CHKHR(sha1Instance->AppendData(numBytes, data)); + return S_OK; +} + + +inline HRESULT _RoSha1Finish( + __in void* handle, + __out BYTE (*hashValue)[20]) +{ + Ro::detail::Sha1* sha1Instance = static_cast<Ro::detail::Sha1*>(handle); + CHKHR(sha1Instance->GetResult(hashValue)); + return S_OK; +} + +inline void _RoSha1Release(__in void* handle) +{ + Ro::detail::Sha1* sha1Instance = static_cast<Ro::detail::Sha1*>(handle); + delete sha1Instance; +} + +} + +#endif /* ifdef WINRT_PARAMINSTANCE_NOCRYPT_SHA1 */ + +#ifdef _MSC_VER +#pragma pop_macro("CHKNT") +#pragma pop_macro("CHKHR") +#pragma warning( pop ) +#endif + +#endif /* ifdef __cplusplus */ +#endif /* ifndef WINRT_PARAMINSTANCEAPI_H */ diff --git a/src/inc/winrt/windowsruntime.h b/src/inc/winrt/windowsruntime.h new file mode 100644 index 0000000000..42f3b37e2d --- /dev/null +++ b/src/inc/winrt/windowsruntime.h @@ -0,0 +1,66 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#ifndef WindowsRuntime_h +#define WindowsRuntime_h + +#include <roapi.h> +#include <windowsstring.h> +#include "holder.h" + +#ifdef FEATURE_LEAVE_RUNTIME_HOLDER + #define HR_LEAVE_RUNTIME_HOLDER(X) \ + GCX_PREEMP(); \ + LeaveRuntimeHolderNoThrow lrh(X); \ + if (FAILED(lrh.GetHR())) \ + { \ + return lrh.GetHR(); \ + } +#else + #define HR_LEAVE_RUNTIME_HOLDER(X) (void *)0; +#endif + +#ifndef IID_INS_ARGS + #define IID_INS_ARGS(ppType) __uuidof(**(ppType)), IID_INS_ARGS_Helper(ppType) +#endif + +HRESULT StringCchLength( + __in LPCWSTR wz, + __out UINT32 *pcch); + +#ifndef CROSSGEN_COMPILE +namespace clr +{ + namespace winrt + { + using ABI::Windows::Foundation::GetActivationFactory; + + template <typename ItfT> inline + HRESULT GetActivationFactory( + __in WinRtStringRef const & wzActivatableClassId, + __deref_out ItfT** ppItf) + { + LIMITED_METHOD_CONTRACT; + HR_LEAVE_RUNTIME_HOLDER(::RoGetActivationFactory); + return GetActivationFactory(wzActivatableClassId.Get(), ppItf); + } + + template <typename ItfT> + HRESULT GetActivationFactory( + __in WinRtStringRef const & wzActivatableClassId, + __in typename ReleaseHolder<ItfT>& hItf) + { + LIMITED_METHOD_CONTRACT; + HR_LEAVE_RUNTIME_HOLDER(::RoGetActivationFactory); + return GetActivationFactory(wzActivatableClassId.Get(), (ItfT**)&hItf); + } + } // namespace winrt +} // namespace clr +#endif //CROSSGEN_COMPILE +#undef HR_LEAVE_RUNTIME_HOLDER + +#endif // WindowsRuntime_h + + diff --git a/src/inc/winrt/windowsstring.h b/src/inc/winrt/windowsstring.h new file mode 100644 index 0000000000..ff5fcfe811 --- /dev/null +++ b/src/inc/winrt/windowsstring.h @@ -0,0 +1,775 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +// +// + +#pragma once + +#ifndef WindowsString_h +#define WindowsString_h + +#include <tchar.h> // Required by strsafe.h +#include <intsafe.h> // For SizeTToUInt32 +#include <strsafe.h> // For StringCchLengthW. +#include <winstring.h> // The Windows SDK header file for HSTRING and HSTRING_HEADER. + +//--------------------------------------------------------------------------------------------------------------------------- +// Forward declarations +void DECLSPEC_NORETURN ThrowHR(HRESULT hr); + +//--------------------------------------------------------------------------------------------------------------------------- +namespace clr +{ + namespace winrt + { + //------------------------------------------------------------------------------------------------------------------- + // The internal Windows Runtime String wrapper class which doesn't throw exception when a failure occurs + // Note String class doesn't provide copy constructor and copy assigment. This is because the *fast* string duplicate + // can fail, which makes the copy constructor unusable in contexts where exceptions are not expected because it would + // need to throw on failure. However, a move constructor and move assignment are provided. These require a String && + // argument, which prevents a *fast* string from being moved (StringReference can be cast to const String&, but not + // String&&). + class String + { + public: + String() throw() : _hstring(nullptr) + { + STATIC_CONTRACT_LIMITED_METHOD; + } + + // Move Constructor + String(__inout String&& other) throw() + : _hstring(other._hstring) + { + STATIC_CONTRACT_LIMITED_METHOD; + other._hstring = nullptr; + } + + // Move assignment + String & operator = (__inout String&& other) throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + Release(); + _hstring = other._hstring; + other._hstring = nullptr; + return *this; + } + + // Initialize this string from a source string. A copy is made in this call. + // The str parameter doesn't need to be null terminated, and it may have embedded NUL characters. + HRESULT Initialize(_In_reads_opt_(length) const wchar_t *str, UINT32 length) throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + HSTRING local; + HRESULT hr = WindowsCreateString(str, length, &local); + return FreeAndAssignOnSuccess(hr, local, &_hstring); + } + + // Initialize this string from a source string. A copy is made in this call. The input string must have a terminating NULL. + HRESULT Initialize(__in PCWSTR str) throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + HRESULT hr = S_OK; + + if (nullptr == str) + { // HSTRING functions promote null string pointers to the empty string, so we should too. + str = L""; + } + + size_t length = 0; + if (SUCCEEDED(hr)) + { + hr = StringCchLengthW(str, STRSAFE_MAX_CCH, &length); + } + + HSTRING local = nullptr; + if (SUCCEEDED(hr)) + { + hr = WindowsCreateString(str, static_cast<UINT32>(length), &local); + } + + return FreeAndAssignOnSuccess(hr, local, &_hstring); + } + + // Initialize this string from an HSTRING. A copy is made in this call. + HRESULT Initialize(const HSTRING& other) throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + HSTRING local; + HRESULT hr = WindowsDuplicateString(other, &local); + return FreeAndAssignOnSuccess(hr, local, &_hstring); + } + + ~String() throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + if (_hstring) + { + WindowsDeleteString(_hstring); + } + } + + // Release the current HSTRING object and reset the member variable to empty + void Release() throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + if (_hstring) + { + WindowsDeleteString(_hstring); + _hstring = nullptr; + } + } + + // Detach the current HSTRING + void Detach(__out HSTRING *phstring) throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + *phstring = _hstring; + _hstring = nullptr; + } + + // Duplicate from another String. + HRESULT Duplicate(__in const String& other) throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + HSTRING local; + HRESULT hr = WindowsDuplicateString(other, &local); + return FreeAndAssignOnSuccess(hr, local, &_hstring); + } + + // Copy/duplicate into a bare HSTRING + HRESULT CopyTo(__out HSTRING *phstring) const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + return WindowsDuplicateString(this->_hstring, phstring); + } + + // HSTRING operator + operator const HSTRING&() const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + return _hstring; + } + + // Explicit conversion to HSTRING + HSTRING Get() const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + return _hstring; + } + + // Retrieve the address of the held hstring + HSTRING* Address() + { + STATIC_CONTRACT_LIMITED_METHOD; + return &_hstring; + } + + // Return the address of the internal HSTRING so that the caller can overwrite it, + // trusting that the caller will not leak the previously held value + HSTRING* GetAddressOf() + { + STATIC_CONTRACT_LIMITED_METHOD; + return &_hstring; + } + + // Return the address of the internal HSTRING so that the caller can overwrite it, + // but release the previous HSTRING to prevent a leak + HSTRING* ReleaseAndGetAddressOf() + { + STATIC_CONTRACT_LIMITED_METHOD; + if (_hstring != nullptr) + { + WindowsDeleteString(_hstring); + _hstring = nullptr; + } + return &_hstring; + } + + // Allow the wrapper to assign a new HSTRING to this wrapper, releasing the old HSTRING + void Attach(__in_opt HSTRING string) + { + STATIC_CONTRACT_LIMITED_METHOD; + WindowsDeleteString(_hstring); + _hstring = string; + } + + // Data Access + UINT32 length() const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + return WindowsGetStringLen(_hstring); + } + + // The size() function is an alias for length(), included to parallel stl conventions. + // The length() function is preferred. + UINT32 size() const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + return length(); + } + + BOOL IsEmpty() const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + return WindowsIsStringEmpty(_hstring); + } + + BOOL HasEmbeddedNull() const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + BOOL answer; + // Not capturing HRESULT + WindowsStringHasEmbeddedNull(_hstring, &answer); + return answer; + } + + LPCWSTR GetRawBuffer(__out_opt UINT32 *length = nullptr) const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + return WindowsGetStringRawBuffer(_hstring, length); + } + + HRESULT GetLpcwstr(__deref_out LPCWSTR *ppsz) const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + if (HasEmbeddedNull()) + { + *ppsz = nullptr; + return E_INVALIDARG; + } + *ppsz = WindowsGetStringRawBuffer(_hstring, nullptr); + return S_OK; + } + + // CompareOrdinal + INT32 CompareOrdinal(const String& other) const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + INT32 result = 0; + + // Ignore the HRESULT from the following call. + WindowsCompareStringOrdinal(_hstring, other, &result); + + return result; + } + + // Concatenation + HRESULT Concat(const String& string, __out String& newString) const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + HSTRING local; + HRESULT hr = WindowsConcatString(_hstring, string, &local); + return FreeAndAssignOnSuccess(hr, local, &newString._hstring); + } + + // Trim + HRESULT TrimStart(const String& trimString, __out String& newString) const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + HSTRING local; + HRESULT hr = WindowsTrimStringStart(_hstring, trimString, &local); + return FreeAndAssignOnSuccess(hr, local, &newString._hstring); + } + + HRESULT TrimEnd(const String& trimString, __out String& newString) const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + HSTRING local; + HRESULT hr = WindowsTrimStringEnd(_hstring, trimString, &local); + return FreeAndAssignOnSuccess(hr, local, &newString._hstring); + } + + // Substring + HRESULT Substring(UINT32 startIndex, __out String& newString) const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + HSTRING local; + HRESULT hr = WindowsSubstring(_hstring, startIndex, &local); + return FreeAndAssignOnSuccess(hr, local, &newString._hstring); + } + + HRESULT Substring(UINT32 startIndex, UINT32 length, __out String& newString) const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + HSTRING local; + HRESULT hr = WindowsSubstringWithSpecifiedLength(_hstring, startIndex, length, &local); + return FreeAndAssignOnSuccess(hr, local, &newString._hstring); + } + + // Replace + HRESULT Replace(const String& stringReplaced, const String& stringReplaceWith, __out String& newString) const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + HSTRING local; + HRESULT hr = WindowsReplaceString(_hstring, stringReplaced, stringReplaceWith, &local); + return FreeAndAssignOnSuccess(hr, local, &newString._hstring); + } + + private: + + // No Copy Constructor + String(const String& other); + + // No Copy assignment because if it can fail + String & operator = (const String& other); + + // + // helper function, always returns the passed in HRESULT + // + // if the HRESULT indicates success, frees any previous *target string, + // and over-writes it with newValue + // + // if the HRESULT indicates failure, does nothing + // + static HRESULT FreeAndAssignOnSuccess(HRESULT hr, HSTRING newValue, __out HSTRING *target) + { + STATIC_CONTRACT_LIMITED_METHOD; + if (SUCCEEDED(hr)) + { + // InterlockedExchangePointer wouldn't have much value, unless we also modified + // all readers of *target to insert a ReadBarrier. + HSTRING oldValue = *target; + *target = newValue; + WindowsDeleteString(oldValue); + } + return hr; + } + + HSTRING _hstring; + }; + + static_assert(sizeof(String[2]) == sizeof(HSTRING[2]), "clr::winrt::String must be same size as HSTRING!"); + + //------------------------------------------------------------------------------------------------------------------- + // String Comparison Operators + inline + bool operator == (const String& left, const String& right) throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + INT32 result = 0; + // Ignore the HRESULT from the following call. + WindowsCompareStringOrdinal(left, right, &result); + + return 0 == result; + } + + inline + bool operator != (const String& left, const String& right) throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + INT32 result = 0; + // Ignore the HRESULT from the following call. + WindowsCompareStringOrdinal(left, right, &result); + + return 0 != result; + } + + inline + bool operator < (const String& left, const String& right) throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + INT32 result = 0; + // Ignore the HRESULT from the following call. + WindowsCompareStringOrdinal(left, right, &result); + + return -1 == result; + } + + inline + bool operator <= (const String& left, const String& right) throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + INT32 result = 0; + // Ignore the HRESULT from the following call. + WindowsCompareStringOrdinal(left, right, &result); + + return -1 == result || 0 == result; + } + + inline + bool operator > (const String& left, const String& right) throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + INT32 result = 0; + // Ignore the HRESULT from the following call. + WindowsCompareStringOrdinal(left, right, &result); + + return 1 == result; + } + + inline + bool operator >= (const String& left, const String& right) throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + INT32 result = 0; + // Ignore the HRESULT from the following call. + WindowsCompareStringOrdinal(left, right, &result); + + return 1 == result || 0 == result; + } + + + //------------------------------------------------------------------------------------------------------------------- + // The internal Windows Runtime String wrapper class for passing a reference of an existing string buffer. + // This class is allocated on stack. + class StringReference + { + public: + + // Constructor which takes an existing string buffer and its length as the parameters. + // It fills an HSTRING_HEADER struct with the parameter. + // + // Warning: The caller must ensure the lifetime of the buffer outlives this + // object as it does not make a copy of the wide string memory. + StringReference(__in_opt PCWSTR stringRef, UINT32 length) throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + HRESULT hr = WindowsCreateStringReference(stringRef, length, &_header, &_hstring); + + // Failfast if internal developers try to create a reference to a non-NUL terminated string + if (FAILED(hr)) + { + RaiseException(static_cast<DWORD>(STATUS_INVALID_PARAMETER), EXCEPTION_NONCONTINUABLE, 0, nullptr); + } + } + + // Constructor for use with string literals. + // It fills an HSTRING_HEADER struct with the parameter. + template <UINT32 N> + StringReference(__in WCHAR const (&stringRef)[N]) throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + + HRESULT hr = WindowsCreateStringReference(stringRef, N - 1 /* remove terminating NUL from length */, &_header, &_hstring); + + // Failfast if internal developers try to create a reference to a non-NUL terminated string. This constructor + // should only be used with string literals, but someone could mistakenly use this with a local WCHAR array and + // forget to NUL-terminate it. + if (FAILED(hr)) + { + RaiseException(static_cast<DWORD>(STATUS_INVALID_PARAMETER), EXCEPTION_NONCONTINUABLE, 0, nullptr); + } + } + + // Contructor which takes an HSTRING as the parameter. The new StringReference will not create a new copy of the original HSTRING. + // + // Warning: The caller must ensure the lifetime of the hstring argument outlives this + // object as it does not make a copy. + explicit StringReference(const HSTRING& hstring) throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + // Create the StringReference without using the _header member, but instead with whatever header is used in hstring so that we + // prevent copying when Duplicate() is called on this object. There is no addref, nor decrement in the destructor, since we + // don't know or care if it's refcounted or truly a stack allocated reference. + _hstring = hstring; + } + + // const String& operator + operator const String&() const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + return _AsString(); + } + + // const HSTRING& operator + operator const HSTRING&() const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + return _hstring; + } + + // Explicit conversion to HSTRING + HSTRING Get() const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + return _hstring; + } + + // CompareOrdinal + INT32 CompareOrdinal(const String& other) const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + return _AsString().CompareOrdinal(other); + } + + // Data Access + UINT32 length() const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + return _AsString().length(); + } + + UINT32 size() const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + return _AsString().size(); + } + + BOOL IsEmpty() const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + return _AsString().IsEmpty(); + } + + BOOL HasEmbeddedNull() const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + return _AsString().HasEmbeddedNull(); + } + + LPCWSTR GetRawBuffer(__out_opt UINT32 *length) const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + return _AsString().GetRawBuffer(length); + } + + HRESULT GetLpcwstr(__deref_out LPCWSTR *ppsz) const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + return _AsString().GetLpcwstr(ppsz); + } + + HRESULT CopyTo(__out HSTRING *phstring) const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + return WindowsDuplicateString(this->_hstring, phstring); + } + + // Concatenation + HRESULT Concat(const String& otherString, __out String& newString) const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + return _AsString().Concat(otherString, newString); + } + + // Trim + HRESULT TrimStart(const String& trimString, __out String& newString) const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + return _AsString().TrimStart(trimString, newString); + } + + HRESULT TrimEnd(const String& trimString, __out String& newString) const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + return _AsString().TrimEnd(trimString, newString); + } + + // Substring + HRESULT Substring(UINT32 startIndex, __out String& newString) const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + return _AsString().Substring(startIndex, newString); + } + + HRESULT Substring(UINT32 startIndex, UINT32 length, __out String& newString) const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + return _AsString().Substring(startIndex, length, newString); + } + + // Replace + HRESULT Replace(const String& stringReplaced, const String& stringReplaceWith, __out String& newString) const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + return _AsString().Replace(stringReplaced, stringReplaceWith, newString); + } + + private: + // No Copy Constructor + StringReference(const String& other); + + // No non-const WCHAR array constructor + template <UINT32 N> + StringReference(__in WCHAR (&stringRef)[N]); + + // No Copy assigment + const StringReference & operator = (const String& other); + + // No new operator + static void * operator new(size_t size); + + // No delete operator + static void operator delete(void *p, size_t size); + + // const String& operator + const String& _AsString() const throw() + { + STATIC_CONTRACT_LIMITED_METHOD; + return reinterpret_cast<const String&>(_hstring); + } + + HSTRING _hstring; + HSTRING_HEADER _header; + }; + } // namespace winrt +} // namespace clr + +typedef clr::winrt::String WinRtString; +typedef clr::winrt::StringReference WinRtStringRef; + +// ========================================================== +// WinRT-specific DuplicateString variations. + +LPWSTR DuplicateString( + LPCWSTR wszString, + size_t cchString); + +LPWSTR DuplicateStringThrowing( + LPCWSTR wszString, + size_t cchString); + +inline +LPWSTR DuplicateString(WinRtString const & str) +{ + STATIC_CONTRACT_NOTHROW; + UINT32 cchStr; + LPCWSTR wzStr = str.GetRawBuffer(&cchStr); + return DuplicateString(wzStr, cchStr); +} + +inline +LPWSTR DuplicateStringThrowing(WinRtString const & str) +{ + STATIC_CONTRACT_THROWS; + UINT32 cchStr; + LPCWSTR wzStr = str.GetRawBuffer(&cchStr); + return DuplicateStringThrowing(wzStr, cchStr); +} + +inline +LPWSTR DuplicateString(HSTRING const & hStr) +{ + STATIC_CONTRACT_NOTHROW; + WinRtStringRef str(hStr); + UINT32 cchStr; + LPCWSTR wzStr = str.GetRawBuffer(&cchStr); + return DuplicateString(wzStr, cchStr); +} + +inline +LPWSTR DuplicateStringThrowing(HSTRING const & hStr) +{ + STATIC_CONTRACT_THROWS; + WinRtStringRef str(hStr); + UINT32 cchStr; + LPCWSTR wzStr = str.GetRawBuffer(&cchStr); + return DuplicateStringThrowing(wzStr, cchStr); +} + +// ========================================================== +// Convenience overloads of StringCchLength + +// A convenience overload that assumes cchMax is STRSAFE_MAX_CCH. +inline +HRESULT StringCchLength( + __in LPCWSTR wz, + __out size_t *pcch) +{ + // To align with HSTRING functionality (which always promotes null + // string pointers to the empty string), this wrapper also promotes + // null string pointers to empty string before forwarding to Windows' + // implementation. Don't skip the call to StringCchLength for null + // pointers because we want to continue to align with the return value + // when passed a null length out parameter. + return StringCchLengthW(wz == nullptr ? L"" : wz, size_t(STRSAFE_MAX_CCH), pcch); +} + +#ifdef _WIN64 + // A UINT32-specific overload with built-in overflow check. + inline + HRESULT StringCchLength( + __in LPCWSTR wz, + __out UINT32 *pcch) + { + if (pcch == nullptr) + return E_INVALIDARG; + + size_t cch; + HRESULT hr = StringCchLength(wz, &cch); + if (FAILED(hr)) + return hr; + + return SizeTToUInt32(cch, pcch); + } +#endif // _WIN64 + +#ifndef DACCESS_COMPILE + //===================================================================================================================== + // Holder of CoTaskMem-allocated array of HSTRING (helper class for WinRT binders - e.g. code:CLRPrivBinderWinRT::GetFileNameListForNamespace). + class CoTaskMemHSTRINGArrayHolder + { + public: + CoTaskMemHSTRINGArrayHolder() + { + LIMITED_METHOD_CONTRACT; + + m_cValues = 0; + m_rgValues = nullptr; + } + ~CoTaskMemHSTRINGArrayHolder() + { + LIMITED_METHOD_CONTRACT; + Destroy(); + } + + // Destroys current array and holds new array rgValues of size cValues. + void Init(HSTRING * rgValues, DWORD cValues) + { + LIMITED_METHOD_CONTRACT; + + Destroy(); + _ASSERTE(m_cValues == 0); + + _ASSERTE(((cValues == 0) && (rgValues == nullptr)) || + ((cValues > 0) && (rgValues != nullptr))); + + m_rgValues = rgValues; + m_cValues = cValues; + } + + HSTRING GetAt(DWORD index) const + { + LIMITED_METHOD_CONTRACT; + return m_rgValues[index]; + } + + DWORD GetCount() + { + LIMITED_METHOD_CONTRACT; + return m_cValues; + } + + private: + void Destroy() + { + LIMITED_METHOD_CONTRACT; + + for (DWORD i = 0; i < m_cValues; i++) + { + if (m_rgValues[i] != nullptr) + { + WindowsDeleteString(m_rgValues[i]); + } + } + m_cValues = 0; + + if (m_rgValues != nullptr) + { + CoTaskMemFree(m_rgValues); + m_rgValues = nullptr; + } + } + + private: + DWORD m_cValues; + HSTRING * m_rgValues; + }; // class CoTaskMemHSTRINGArrayHolder +#endif //!DACCESS_COMPILE + + +#endif // WindowsString_h + |