summaryrefslogtreecommitdiff
path: root/src/inc/winrt
diff options
context:
space:
mode:
authordotnet-bot <dotnet-bot@microsoft.com>2015-01-30 14:14:42 -0800
committerdotnet-bot <dotnet-bot@microsoft.com>2015-01-30 14:14:42 -0800
commitef1e2ab328087c61a6878c1e84f4fc5d710aebce (patch)
treedee1bbb89e9d722e16b0d1485e3cdd1b6c8e2cfa /src/inc/winrt
downloadcoreclr-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.h213
-rw-r--r--src/inc/winrt/paraminstanceapi.h1750
-rw-r--r--src/inc/winrt/windowsruntime.h66
-rw-r--r--src/inc/winrt/windowsstring.h775
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
+