From ef1e2ab328087c61a6878c1e84f4fc5d710aebce Mon Sep 17 00:00:00 2001 From: dotnet-bot Date: Fri, 30 Jan 2015 14:14:42 -0800 Subject: Initial commit to populate CoreCLR repo [tfs-changeset: 1407945] --- src/md/winmd/adapter.cpp | 2689 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2689 insertions(+) create mode 100644 src/md/winmd/adapter.cpp (limited to 'src/md/winmd/adapter.cpp') diff --git a/src/md/winmd/adapter.cpp b/src/md/winmd/adapter.cpp new file mode 100644 index 0000000000..0a93f88d58 --- /dev/null +++ b/src/md/winmd/adapter.cpp @@ -0,0 +1,2689 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +#include "stdafx.h" +#include "sigparser.h" +#include "sigbuilder.h" +#include "inc/adapter.h" + +//#CLRRuntimeHostInternal_GetImageVersionString +// External implementation of call to code:ICLRRuntimeHostInternal::GetImageVersionString. +// Implemented in clr.dll and mscordbi.dll. +HRESULT +CLRRuntimeHostInternal_GetImageVersionString( + __out_ecount(*pcchBuffer) + LPWSTR wszBuffer, + DWORD * pcchBuffer); + +//---------------------------------------------------------------------------------------------------- +// The name prefixes used by WinMD to hide/unhide WinRT and CLR versions of RuntimeClasses. +//---------------------------------------------------------------------------------------------------- + +static const char s_szWinRTPrefix[] = ""; +//static const size_t s_ncWinRTPrefix = sizeof(s_szWinRTPrefix) - 1; + +static const char s_szCLRPrefix[] = ""; +static const size_t s_ncCLRPrefix = sizeof(s_szCLRPrefix) - 1; + +// the public key token of the ecma key used by some framework assemblies (mscorlib, system, etc). +// note that some framework assemblies use a different key: b03f5f7f11d50a3a +static const BYTE s_pbFrameworkPublicKeyToken[] = {0xB7,0x7A,0x5C,0x56,0x19,0x34,0xE0,0x89}; + + +//----------------------------------------------------------------------------------------------------- +// Returns: +// S_OK: if WinMD adapter should be used. +// S_FALSE: if not +//----------------------------------------------------------------------------------------------------- +HRESULT CheckIfWinMDAdapterNeeded(IMDCommon *pRawMDCommon) +{ + HRESULT hr; + _ASSERTE(pRawMDCommon != NULL); + + LPCSTR szMetadataVersionString = NULL; + +#ifndef DACCESS_COMPILE +#ifdef _DEBUG + //--------------------------------------------------------------------------------------------------------- + // set COMPLUS_INTERNAL_MD_WinMD_AssertOnIllegalUsage=1 + // + // to turn the WinMD adapter off universally. + //--------------------------------------------------------------------------------------------------------- + if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_WinMD_Disable)) + { + hr = S_FALSE; + goto ErrExit; + } +#endif //_DEBUG +#endif + + //--------------------------------------------------------------------------------------------------------- + // This is the real check: activate WinMD based on metadata version string. + //--------------------------------------------------------------------------------------------------------- + static const LPCSTR g_szWindowsRuntimeVersion = "WindowsRuntime "; + IfFailGo(pRawMDCommon->GetVersionString(&szMetadataVersionString)); + if (0 == strncmp(szMetadataVersionString, g_szWindowsRuntimeVersion, strlen(g_szWindowsRuntimeVersion))) + { + hr = S_OK; + goto ErrExit; + } + else + { + hr = S_FALSE; + goto ErrExit; + } + + ErrExit: + return hr; +} + + +//------------------------------------------------------------------------------ + +// +// Factory for WinMDAdapters. Caller must use "delete" to destroy adapter when done. +// +/*static*/ HRESULT WinMDAdapter::Create(IMDCommon *pRawMDCommon, /*[out]*/ WinMDAdapter **ppAdapter) +{ + HRESULT hr; + LPWSTR wszCorVersion = NULL; + WinMDAdapter* pNewAdapter = NULL; + + *ppAdapter = NULL; + + pNewAdapter = new (nothrow) WinMDAdapter(pRawMDCommon); + if (!pNewAdapter) + { + IfFailGo(E_OUTOFMEMORY); + } + + //------------------------------------------------------------------------------------------------ + // Create a stored string to hold our phantom metadata version string. + //------------------------------------------------------------------------------------------------ + LPCSTR szVersion; + IfFailGo(pRawMDCommon->GetVersionString(&szVersion)); + const char *szClrPortion = strchr(szVersion, ';'); + if (szClrPortion) + { + pNewAdapter->m_scenario = kWinMDExp; + szClrPortion++; + + // skip the "CLR" prefix if present + if ((szClrPortion[0] == 'c' || szClrPortion[0] == 'C') && + (szClrPortion[1] == 'l' || szClrPortion[1] == 'L') && + (szClrPortion[2] == 'r' || szClrPortion[2] == 'R')) + { + szClrPortion += 3; + } + while (szClrPortion[0] == ' ') + { + szClrPortion++; + } + + size_t ncClrPortion = strlen(szClrPortion); + pNewAdapter->m_pRedirectedVersionString = new (nothrow) char[ncClrPortion + 1]; + IfNullGo(pNewAdapter->m_pRedirectedVersionString); + memcpy(pNewAdapter->m_pRedirectedVersionString, szClrPortion, ncClrPortion + 1); + } + else + { + pNewAdapter->m_scenario = kWinMDNormal; +#ifndef DACCESS_COMPILE + WCHAR wszCorVersion[_MAX_PATH]; + DWORD cchWszCorVersion = _countof(wszCorVersion); + IfFailGo(CLRRuntimeHostInternal_GetImageVersionString (wszCorVersion, &cchWszCorVersion)); + MAKE_UTF8PTR_FROMWIDE_NOTHROW(szCorVersion, wszCorVersion); + IfNullGo(szCorVersion); + size_t nch = strlen(szCorVersion) + 1; + pNewAdapter->m_pRedirectedVersionString = new (nothrow) char[nch]; + IfNullGo(pNewAdapter->m_pRedirectedVersionString); + memcpy(pNewAdapter->m_pRedirectedVersionString, szCorVersion, nch); +#else + pNewAdapter->m_pRedirectedVersionString = new (nothrow) char[1]; + pNewAdapter->m_pRedirectedVersionString[0] = 0; +#endif + } + + + //------------------------------------------------------------------------------------------------ + // Find an assemblyRef to mscorlib (required to exist in .winmd files precisely to make the adapter's job easier. + //------------------------------------------------------------------------------------------------ + ULONG numAssemblyRefs = pNewAdapter->m_pRawMetaModelCommonRO->CommonGetRowCount(mdtAssemblyRef); + pNewAdapter->m_assemblyRefMscorlib = 0; + pNewAdapter->m_fReferencesMscorlibV4 = FALSE; + for (ULONG rid = 1; rid <= numAssemblyRefs; rid++) + { + mdAssemblyRef mdar = mdtAssemblyRef|rid; + LPCSTR arefName; + USHORT usMajorVersion; + IfFailGo(pNewAdapter->m_pRawMetaModelCommonRO->CommonGetAssemblyRefProps(mdar, &usMajorVersion, NULL, NULL, NULL, NULL, NULL, NULL, &arefName, NULL, NULL, NULL)); + if (0 == strcmp(arefName, "mscorlib")) + { + pNewAdapter->m_assemblyRefMscorlib = mdar; + + if (usMajorVersion == 4) + { + // Older WinMDExp used to incorrectly generate an assemblyRef to 4.0.0.0 mscorlib. + // We use this flag to implement back-compat quirks. + pNewAdapter->m_fReferencesMscorlibV4 = TRUE; + } + + break; + } + } + if (pNewAdapter->m_assemblyRefMscorlib == 0) + { + // .winmd files are required to have an assemblyRef to mscorlib. + IfFailGo(COR_E_BADIMAGEFORMAT); + } + + + //------------------------------------------------------------------------------------------------ + // All initialization tasks done. + //------------------------------------------------------------------------------------------------ + *ppAdapter = pNewAdapter; + hr = S_OK; + + ErrExit: + delete wszCorVersion; + if (FAILED(hr)) + delete pNewAdapter; + return hr; +} + + +//------------------------------------------------------------------------------ + +WinMDAdapter::WinMDAdapter(IMDCommon *pRawMDCommon) + : m_typeRefTreatmentMemoTable(pRawMDCommon->GetMetaModelCommonRO()->CommonGetRowCount(mdtTypeRef), kTrNotYetInitialized) + , m_typeDefTreatmentMemoTable(pRawMDCommon->GetMetaModelCommonRO()->CommonGetRowCount(mdtTypeDef), kTdNotYetInitialized) + , m_methodDefTreatmentMemoTable(pRawMDCommon->GetMetaModelCommonRO()->CommonGetRowCount(mdtMethodDef), kMdNotYetInitialized) + , m_redirectedCABlobsMemoTable(pRawMDCommon->GetMetaModelCommonRO()->CommonGetRowCount(mdtCustomAttribute), NULL) + , m_redirectedMethodDefSigMemoTable(pRawMDCommon->GetMetaModelCommonRO()->CommonGetRowCount(mdtMethodDef), NULL) + , m_redirectedFieldDefSigMemoTable(pRawMDCommon->GetMetaModelCommonRO()->CommonGetRowCount(mdtFieldDef), NULL) + , m_redirectedMemberRefSigMemoTable(pRawMDCommon->GetMetaModelCommonRO()->CommonGetRowCount(mdtMemberRef), NULL) + , m_redirectedPropertySigMemoTable(pRawMDCommon->GetMetaModelCommonRO()->CommonGetRowCount(mdtProperty), NULL) + , m_redirectedTypeSpecSigMemoTable(pRawMDCommon->GetMetaModelCommonRO()->CommonGetRowCount(mdtTypeSpec), NULL) + , m_redirectedMethodSpecSigMemoTable(pRawMDCommon->GetMetaModelCommonRO()->CommonGetRowCount(mdtMethodSpec), NULL) + , m_mangledTypeNameTable(pRawMDCommon->GetMetaModelCommonRO()->CommonGetRowCount(mdtTypeDef), NULL) +{ + m_rawAssemblyRefCount = pRawMDCommon->GetMetaModelCommonRO()->CommonGetRowCount(mdtAssemblyRef); + m_pRedirectedVersionString = NULL; + m_pRawMetaModelCommonRO = pRawMDCommon->GetMetaModelCommonRO(); +} + +//------------------------------------------------------------------------------ + +WinMDAdapter::~WinMDAdapter() +{ + delete m_pRedirectedVersionString; +} + + +//------------------------------------------------------------------------------ +// Hides projected jupiter struct helper class & interfaces + +struct HiddenWinRTTypeInfo +{ + LPCSTR szWinRTNamespace; + LPCSTR szWinRTName; +}; + +#define DEFINE_PROJECTED_JUPITER_STRUCT(szWinRTNamespace, szWinRTName, szClrNamespace, szClrName, nClrAssemblyIndex, nContractAssemblyIndex, WinRTRedirectedTypeIndex, ClrRedirectedTypeIndex, fieldSizes) \ + { \ + szWinRTNamespace, \ + szWinRTName "Helper" \ + }, + +#define DEFINE_HIDDEN_WINRT_TYPE(szWinRTNamespace, szWinRTName) \ + { \ + szWinRTNamespace, \ + szWinRTName \ + }, + +#define DEFINE_PROJECTED_TYPE(szWinRTNS, szWinRTName, szClrNS, szClrName, nClrAsmIdx, nContractAsmIdx, nWinRTIndex, nClrIndex, nWinMDTypeKind) + +static const HiddenWinRTTypeInfo g_rgHiddenWinRTTypes[] = +{ + #include "WinRTProjectedTypes.h" +}; + +#undef DEFINE_PROJECTED_JUPITER_STRUCT +#undef DEFINE_HIDDEN_WINRT_TYPE +#undef DEFINE_PROJECTED_TYPE + +// Whether the WinRT type should be hidden from managed code +// Example: helper class for projected jupiter structs +// (helper class interfaces are already private by default) +BOOL WinMDAdapter::IsHiddenWinRTType(LPCSTR szWinRTNamespace, LPCSTR szWinRTName) +{ + _ASSERTE(szWinRTNamespace && szWinRTName); + + for (UINT i = 0; i < _countof(g_rgHiddenWinRTTypes); i++) + { + if (0 == strcmp(szWinRTNamespace, g_rgHiddenWinRTTypes[i].szWinRTNamespace)) + { + if (0 == strcmp(szWinRTName, g_rgHiddenWinRTTypes[i].szWinRTName)) + { + return TRUE; + } + } + } + + return FALSE; +} + +//------------------------------------------------------------------------------ + +struct RedirectedTypeInfo +{ + LPCSTR szWinRTNamespace; + LPCSTR szWinRTName; + LPCSTR szWinRTFullName; + LPCWSTR wszWinRTFullName; + LPCSTR szClrNamespace; + LPCSTR szClrName; + LPCSTR szClrFullName; + LPCWSTR wszClrFullName; + const WinMDAdapter::FrameworkAssemblyIndex nClrAssemblyIndex; + const WinMDAdapter::ContractAssemblyIndex nContractAssemblyIndex; + const WinMDAdapter::WinMDTypeKind nTypeKind; +#ifdef _DEBUG + // Indexes for verification of constants RedirectedTypeIndex_* + const UINT dbg_nIndex1; + const UINT dbg_nIndex2; +#endif +}; + +#define DEFINE_PROJECTED_TYPE(szWinRTNS, szWinRTName, szClrNS, szClrName, nClrAsmIdx, nContractAsmIdx, nWinRTIndex, nClrIndex, nWinMDTypeKind) \ + { \ + szWinRTNS, \ + szWinRTName, \ + szWinRTNS "." szWinRTName, \ + L##szWinRTNS W(".") L##szWinRTName, \ + szClrNS, \ + szClrName, \ + szClrNS "." szClrName, \ + L##szClrNS W(".") L##szClrName, \ + WinMDAdapter::FrameworkAssembly_ ## nClrAsmIdx, \ + WinMDAdapter::ContractAssembly_ ## nContractAsmIdx, \ + WinMDAdapter::WinMDTypeKind_ ## nWinMDTypeKind \ + COMMA_INDEBUG(WinMDAdapter::RedirectedTypeIndex_ ## nWinRTIndex) \ + COMMA_INDEBUG(WinMDAdapter::RedirectedTypeIndex_ ## nClrIndex) \ + }, + +static const RedirectedTypeInfo +g_rgRedirectedTypes[WinMDAdapter::RedirectedTypeIndex_Count] = +{ +#include "WinRTProjectedTypes.h" + + +}; +#undef SCAT +#undef DEFINE_PROJECTED_TYPE + +//------------------------------------------------------------------------------ + +/*static*/ BOOL WinMDAdapter::ConvertWellKnownTypeNameFromWinRTToClr(LPCSTR *pszNamespace, LPCSTR *pszName) +{ + return ConvertWellKnownTypeNameFromWinRTToClr(pszNamespace, pszName, NULL); +} + + +// Maps well-known WinRT typenames to CLR typename. If the incoming name is not a well-known WinRT typename, +// this function leaves *pszNamespace and *pszName alone and returns FALSE. Otherwise, it overwrites +// them with pointers to const strings, returns the index into the rewrite table in *pIndex and returns TRUE. +// +// (Note: munged names from WinMDExp are not "well-known" names. Since the idea of munging them is to hide them, +// this function will not transform such names. Not to mention, it would be hard to return such strings +// in a function that no error return mechanism.) +// +/*static*/ BOOL WinMDAdapter::ConvertWellKnownTypeNameFromWinRTToClr(LPCSTR *pszNamespace, LPCSTR *pszName, UINT *pIndex) +{ + _ASSERTE(pszNamespace && pszName); + for (UINT i = 0; i < RedirectedTypeIndex_Count; i++) + { + _ASSERTE(g_rgRedirectedTypes[i].dbg_nIndex1 == i); + _ASSERTE(g_rgRedirectedTypes[i].dbg_nIndex2 == i); + + if (0 == strcmp(*pszNamespace, g_rgRedirectedTypes[i].szWinRTNamespace)) + { + if (0 == strcmp(*pszName, g_rgRedirectedTypes[i].szWinRTName)) + { + *pszNamespace = g_rgRedirectedTypes[i].szClrNamespace; + *pszName = g_rgRedirectedTypes[i].szClrName; + if (pIndex) + *pIndex = i; + return TRUE; + } + } + } + return FALSE; +} + +/*static*/ BOOL WinMDAdapter::ConvertWellKnownFullTypeNameFromWinRTToClr(LPCWSTR *pwszFullName, RedirectedTypeIndex *pIndex) +{ + _ASSERTE(pwszFullName); + for (UINT i = 0; i < RedirectedTypeIndex_Count; i++) + { + _ASSERTE(g_rgRedirectedTypes[i].dbg_nIndex1 == i); + _ASSERTE(g_rgRedirectedTypes[i].dbg_nIndex2 == i); + + if (0 == wcscmp(*pwszFullName, g_rgRedirectedTypes[i].wszWinRTFullName)) + { + *pwszFullName = g_rgRedirectedTypes[i].wszClrFullName; + if (pIndex) + *pIndex = static_cast(i); + return TRUE; + } + } + return FALSE; +} + +//------------------------------------------------------------------------------ + +// Maps well-known CLR typenames to WinRT typename. If the incoming name is not a well-known CLR typename, +// this function leaves *pszNamespace and *pszName alone and returns FALSE. Otherwise, it overwrites +// them with pointers to const strings and returns TRUE. +// +// (Note: munged names from WinMDExp are not "well-known" names. Since the idea of munging them is to hide them, +// this function will not transform such names. Not to mention, it would be hard to return such strings +// in a function that no error return mechanism.) +// +/*static*/ BOOL WinMDAdapter::ConvertWellKnownTypeNameFromClrToWinRT(LPCSTR *pszFullName) +{ + _ASSERTE(pszFullName); + + for (UINT i = 0; i < RedirectedTypeIndex_Count; i++) + { + if (0 == strcmp(g_rgRedirectedTypes[i].szClrFullName, *pszFullName)) + { + *pszFullName = g_rgRedirectedTypes[i].szWinRTFullName; + return TRUE; + } + } + return FALSE; +} + +/*static*/ BOOL WinMDAdapter::ConvertWellKnownTypeNameFromClrToWinRT(LPCSTR *pszNamespace, LPCSTR *pszName) +{ + _ASSERTE(pszNamespace); + _ASSERTE(pszName); + + for (UINT i = 0; i < RedirectedTypeIndex_Count; i++) + { + if (0 == strcmp(g_rgRedirectedTypes[i].szClrNamespace, *pszNamespace) && + 0 == strcmp(g_rgRedirectedTypes[i].szClrName, *pszName)) + { + *pszNamespace = g_rgRedirectedTypes[i].szWinRTNamespace; + *pszName = g_rgRedirectedTypes[i].szWinRTName; + + return TRUE; + } + } + return FALSE; +} + +//--------------------------------------------------------------------------------------- +// +// Returns names of redirected type 'index'. +// +//static +void +WinMDAdapter::GetRedirectedTypeInfo( + RedirectedTypeIndex index, + LPCSTR * pszClrNamespace, + LPCSTR * pszClrName, + LPCSTR * pszFullWinRTName, + FrameworkAssemblyIndex * pFrameworkAssemblyIdx, + ContractAssemblyIndex * pContractAssemblyIdx, + WinMDTypeKind * pWinMDTypeKind) +{ + _ASSERTE(index < RedirectedTypeIndex_Count); + + if (pszClrName != nullptr) + { + *pszClrName = g_rgRedirectedTypes[index].szClrName; + } + if (pszClrNamespace != nullptr) + { + *pszClrNamespace = g_rgRedirectedTypes[index].szClrNamespace; + } + if (pszFullWinRTName != nullptr) + { + *pszFullWinRTName = g_rgRedirectedTypes[index].szWinRTFullName; + } + if (pFrameworkAssemblyIdx != nullptr) + { + *pFrameworkAssemblyIdx = g_rgRedirectedTypes[index].nClrAssemblyIndex; + } + if (pContractAssemblyIdx != nullptr) + { + *pContractAssemblyIdx = g_rgRedirectedTypes[index].nContractAssemblyIndex; + } + if (pWinMDTypeKind != nullptr) + { + *pWinMDTypeKind = g_rgRedirectedTypes[index].nTypeKind; + } +} + +//--------------------------------------------------------------------------------------- +// +// Returns WinRT name of redirected type 'index'. +// +//static +LPCWSTR +WinMDAdapter::GetRedirectedTypeFullWinRTName( + RedirectedTypeIndex index) +{ + _ASSERTE(index < RedirectedTypeIndex_Count); + + return g_rgRedirectedTypes[index].wszWinRTFullName; +} + +//--------------------------------------------------------------------------------------- +// +// Returns CLR name of redirected type 'index'. +// +//static +LPCSTR +WinMDAdapter::GetRedirectedTypeFullCLRName( + RedirectedTypeIndex index) +{ + _ASSERTE(index < RedirectedTypeIndex_Count); + + return g_rgRedirectedTypes[index].szClrFullName; +} + +//------------------------------------------------------------------------------ +// +// Get TypeRefTreatment value for a TypeRef +// +HRESULT + WinMDAdapter::GetTypeDefTreatment( + mdTypeDef tkTypeDef, + ULONG * pTypeDefTreatment) +{ + HRESULT hr; + + _ASSERTE(pTypeDefTreatment != NULL); + _ASSERTE(TypeFromToken(tkTypeDef) == mdtTypeDef); + + ULONG typeDefIndex = RidFromToken(tkTypeDef) - 1; + ULONG treatment; + IfFailGo(m_typeDefTreatmentMemoTable.GetEntry(typeDefIndex, &treatment)); + if (hr == S_FALSE) + { + LPCSTR szNamespace; + LPCSTR szName; + ULONG dwFlags; + mdToken extends; + IfFailGo(m_pRawMetaModelCommonRO->CommonGetTypeDefProps(tkTypeDef, &szNamespace, &szName, &dwFlags, &extends, NULL)); + treatment = kTdOther; + ULONG baseTypeRefTreatment = kTrNotYetInitialized; + + // We only want to treat this type special if it has metadata that was encoded as WinRT metadata + if (IsTdWindowsRuntime(dwFlags)) + { + // We need to know whether the typeDef is an Enum/Struct/Delegate/Attribute + if (TypeFromToken(extends) == mdtTypeRef) + { + IfFailGo(GetTypeRefTreatment(extends, &baseTypeRefTreatment)); + } + // Force tdWindowsRuntime flag on (@todo: WinMDExp already does this on its own - if AppModel could do so, we could get rid of this code) + if (m_scenario == kWinMDNormal) + { + BOOL isAttribute = FALSE; + if (TypeFromToken(extends) == mdtTypeRef) + { + ULONG treatment; + IfFailGo(GetTypeRefTreatment(extends, &treatment)); + if (treatment == kTrSystemAttribute) + { + isAttribute = TRUE; + } + } + + if (!isAttribute) + { + treatment = kTdNormalNonAttribute; + } + else + { + treatment = kTdNormalAttribute; + } + } + + // Windows.Foundation.WinMD: Hide any type defs that define well-known types that we'd redirect to mscorlib equivalents. + LPCSTR szTempNamespace = szNamespace; + LPCSTR szTempName = szName; + if ((treatment != kTdOther) && ConvertWellKnownTypeNameFromWinRTToClr(&szTempNamespace, &szTempName)) + { + if (treatment == kTdNormalNonAttribute) + treatment = kTdRedirectedToCLRType; + else + treatment = kTdRedirectedToCLRAttribute; + } + else + { + // WinMDExp emits two versions of RuntimeClasses and Enums: + // + // public class Foo {} // the WinRT reference class + // internal class Foo {} // the implementation class that we want WinRT consumers to ignore + // + // The adapter's job is to undo WinMDExp's transformations. I.e. turn the above into: + // + // internal class Foo {} // the WinRT reference class that we want CLR consumers to ignore + // public class Foo {} // the implementation class + // + // We only add the prefix here since the WinRT view is the only view that is marked tdWindowsRuntime + // De-mangling the CLR name is done below. + if (m_scenario == kWinMDExp && !IsTdNested(dwFlags) && IsTdPublic(dwFlags) && !IsTdInterface(dwFlags)) + { + switch (baseTypeRefTreatment) + { + case kTrSystemDelegate: + case kTrSystemAttribute: + case kTrSystemValueType: + { + // Delegates, Attributes, and Structs have only one version + break; + } + + case kTrSystemEnum: + { + if (m_fReferencesMscorlibV4 && !IsTdSpecialName(dwFlags)) + { + // This is a back-compat quirk. Enums exported with an older WinMDExp have only one version + // not marked with tdSpecialName. These enums should *not* be mangled and flipped to private. + break; + } + // fall-thru + } + default: + { + // Prepend "" and flip the visibility to private + treatment = kTdPrefixWinRTName; + } + } + } + } + + // Scan through Custom Attributes on type, looking for interesting bits. We only need to do this for RuntimeClasses. (The if check below is conservative.) + if (!IsTdInterface(dwFlags) && ((treatment == kTdPrefixWinRTName) || (treatment == kTdNormalNonAttribute))) + { + HRESULT hrCA; + hrCA = m_pRawMetaModelCommonRO->CommonGetCustomAttributeByNameEx(tkTypeDef, "Windows.UI.Xaml.TreatAsAbstractComposableClassAttribute", NULL, NULL, NULL); + if (hrCA == S_OK) + { + treatment |= kTdMarkAbstractFlag; + } + } + + if ((treatment == kTdNormalNonAttribute || treatment == kTdNormalAttribute) && // native WinMD, not redirected + IsHiddenWinRTType(szTempNamespace, szTempName) // hidden type + ) + { + // Hide those WinRT types. Examples of those WinRT types that we need to hide are Jupiter struct helpers + treatment |= kTdMarkInternalFlag; + } + } + else if (m_scenario == kWinMDExp && !IsTdNested(dwFlags)) + { + // implementation classes are not marked tdWindowsRuntime, but still need to be modified + // by the adapter. See if we have one of those here. + LPCSTR szUnmangledName; + IfFailGo(CheckIfClrImplementationType(szName, dwFlags, &szUnmangledName)); + if (hr == S_OK) + { + treatment = kTdUnmangleWinRTName; + } + } + + if (baseTypeRefTreatment == kTrSystemEnum) + { + // The typeDef is an Enum. We need to store the treatment. + treatment |= kTdEnum; + } + + IfFailGo(m_typeDefTreatmentMemoTable.InitEntry(typeDefIndex, &treatment)); + } + _ASSERTE(treatment != kTdNotYetInitialized); + + *pTypeDefTreatment = treatment; + hr = S_OK; + +ErrExit: + return hr; +} // WinMDAdapter::GetTypeDefTreatment + +//------------------------------------------------------------------------------ +// Returns renamed typedefs +HRESULT WinMDAdapter::GetTypeDefProps(mdTypeDef tkTypeDef, // [IN] given typedef + LPCUTF8 *pszNamespace, // [OUT] return typedef namespace + LPCUTF8 *pszName, // [OUT] return typedef name + DWORD *pdwFlags, // [OUT] return typedef flags + mdToken *ptkExtends // [OUT] Put base class TypeDef/TypeRef here. + ) +{ + HRESULT hr; + + _ASSERTE(TypeFromToken(tkTypeDef) == mdtTypeDef); + + LPCSTR szNamespace; + LPCSTR szName; + ULONG dwFlags; + mdToken extends; + ULONG treatment; + IfFailGo(m_pRawMetaModelCommonRO->CommonGetTypeDefProps(tkTypeDef, &szNamespace, &szName, &dwFlags, &extends, NULL)); + IfFailGo(GetTypeDefTreatment(tkTypeDef, &treatment)); + + switch (treatment & kTdTreatmentMask) + { + case kTdOther: + break; + + case kTdNormalNonAttribute: + // Force tdWindowsRuntime flag on (@todo: WinMDExp already does this on its own - if AppModel could do so, we could get rid of this code) + dwFlags |= tdWindowsRuntime | tdImport; + break; + + case kTdNormalAttribute: + // Attribute types don't really exist, so we don't want to allow derivation from them either + dwFlags |= tdWindowsRuntime | tdSealed; + break; + + case kTdUnmangleWinRTName: + szName = szName + s_ncCLRPrefix; + dwFlags |= tdPublic; + dwFlags &= ~tdSpecialName; + break; + + case kTdPrefixWinRTName: + { + // Prepend "" and flip the visibility to private + LPCSTR szPrefixedName; + ULONG index = RidFromToken(tkTypeDef) - 1; + IfFailGo(m_mangledTypeNameTable.GetEntry(index, &szPrefixedName)); + if (hr == S_FALSE) + { + IfFailGo(CreatePrefixedName(s_szWinRTPrefix, szName, &szPrefixedName)); + IfFailGo(m_mangledTypeNameTable.InitEntry(index, &szPrefixedName)); + } + szName = szPrefixedName; + dwFlags &= ~tdPublic; + dwFlags |= tdImport; + break; + } + + case kTdRedirectedToCLRType: + dwFlags &= ~tdPublic; + dwFlags |= tdImport; + break; + + case kTdRedirectedToCLRAttribute: + dwFlags &= ~tdPublic; + break; + + default: + UNREACHABLE(); + } + + if ((treatment & kTdMarkAbstractFlag) == kTdMarkAbstractFlag) + { + dwFlags |= tdAbstract; + } + if ((treatment & kTdMarkInternalFlag) == kTdMarkInternalFlag) + { + dwFlags &= ~tdPublic; + } + + if (pszNamespace) + *pszNamespace = szNamespace; + if (pszName) + *pszName = szName; + if (pdwFlags) + *pdwFlags = dwFlags; + if (ptkExtends) + *ptkExtends = extends; + + hr = S_OK; + + ErrExit: + return hr; +} + +//------------------------------------------------------------------------------ + +// Find TypeDef by name +HRESULT WinMDAdapter::FindTypeDef( + LPCSTR szTypeDefNamespace, // [IN] Namespace for the TypeDef. + LPCSTR szTypeDefName, // [IN] Name of the TypeDef. + mdToken tkEnclosingClass, // [IN] TypeDef/TypeRef of enclosing class. + mdTypeDef * ptkTypeDef // [OUT] return typedef +) +{ + HRESULT hr = S_OK; + + _ASSERTE((szTypeDefName != NULL) && (ptkTypeDef != NULL)); + _ASSERTE((TypeFromToken(tkEnclosingClass) == mdtTypeRef) || + (TypeFromToken(tkEnclosingClass) == mdtTypeDef) || + IsNilToken(tkEnclosingClass)); + + // initialize the output parameter + *ptkTypeDef = mdTypeDefNil; + + // Treat no namespace as empty string. + if (szTypeDefNamespace == NULL) + szTypeDefNamespace = ""; + + // Do a linear search + ULONG cTypeDefRecs = m_pRawMetaModelCommonRO->CommonGetRowCount(mdtTypeDef); + + // Get TypeDef of the tkEnclosingClass passed in + if (TypeFromToken(tkEnclosingClass) == mdtTypeRef) + { + LPCUTF8 szNamespace; + LPCUTF8 szName; + mdToken tkResolutionScope; + + IfFailRet(this->GetTypeRefProps(tkEnclosingClass, &szNamespace, &szName, &tkResolutionScope)); + // Update tkEnclosingClass to TypeDef + IfFailRet(this->FindTypeDef( + szNamespace, + szName, + (TypeFromToken(tkResolutionScope) == mdtTypeRef) ? tkResolutionScope : mdTokenNil, + &tkEnclosingClass)); + _ASSERTE(TypeFromToken(tkEnclosingClass) == mdtTypeDef); + } + + // Search for the TypeDef + for (ULONG i = 1; i <= cTypeDefRecs; i++) + { + LPCUTF8 szNamespace; + LPCUTF8 szName; + ULONG dwFlags; + + mdTypeDef tkTypeDefCandidate = TokenFromRid(i, mdtTypeDef); + + IfFailRet(this->GetTypeDefProps(tkTypeDefCandidate, &szNamespace, &szName, &dwFlags, NULL)); + if (!IsTdNested(dwFlags) && !IsNilToken(tkEnclosingClass)) + { + // If the class is not Nested and EnclosingClass passed in is not nil + continue; + } + else if (IsTdNested(dwFlags) && IsNilToken(tkEnclosingClass)) + { + // If the class is nested and EnclosingClass passed is nil + continue; + } + else if (!IsNilToken(tkEnclosingClass)) + { + _ASSERTE(TypeFromToken(tkEnclosingClass) == mdtTypeDef); + + mdTypeDef enclosingTypeDef; + IfFailRet(m_pRawMetaModelCommonRO->CommonGetEnclosingClassOfTypeDef(tkTypeDefCandidate, &enclosingTypeDef)); + if (enclosingTypeDef != tkEnclosingClass) + { + // Type was not nested by tkEnclosingClass + continue; + } + } + + if (strcmp(szTypeDefName, szName) == 0) + { + if (strcmp(szTypeDefNamespace, szNamespace) == 0) + { + *ptkTypeDef = TokenFromRid(i, mdtTypeDef); + return S_OK; + } + } + } + // Cannot find the TypeDef by name + return CLDB_E_RECORD_NOTFOUND; +} + +//------------------------------------------------------------------------------ +// +// Modifies TypeRef names and resolution scope. +// +HRESULT +WinMDAdapter::GetTypeRefProps( + mdTypeRef tkTypeRef, + LPCSTR * pszNamespace, + LPCSTR * pszName, + mdToken * ptkResolutionScope) +{ + + HRESULT hr; + ULONG treatment; + IfFailGo(GetTypeRefTreatment(tkTypeRef, &treatment)); + _ASSERTE(treatment != kTrNotYetInitialized); + + ULONG treatmentClass = treatment & kTrClassMask; + if (treatmentClass == kTrClassWellKnownRedirected) + { + ULONG nRewritePairIndex = treatment & ~kTrClassMask; + if (pszNamespace != NULL) + *pszNamespace = g_rgRedirectedTypes[nRewritePairIndex].szClrNamespace; + if (pszName != NULL) + *pszName = g_rgRedirectedTypes[nRewritePairIndex].szClrName; + if (ptkResolutionScope != NULL) + { + ContractAssemblyIndex assemblyIndex = g_rgRedirectedTypes[nRewritePairIndex].nContractAssemblyIndex; + _ASSERTE(assemblyIndex < ContractAssembly_Count); + *ptkResolutionScope = mdtAssemblyRef | (m_rawAssemblyRefCount + assemblyIndex + 1); + } + } + else + { + _ASSERTE(treatmentClass == kTrClassMisc); + switch (treatment) + { + case kTrNoRewriteNeeded: + case kTrSystemValueType: + case kTrSystemEnum: + IfFailGo(m_pRawMetaModelCommonRO->CommonGetTypeRefProps(tkTypeRef, pszNamespace, pszName, ptkResolutionScope)); + break; + + case kTrSystemDelegate: + if (pszNamespace != NULL) *pszNamespace = "System"; + if (pszName != NULL) *pszName = "MulticastDelegate"; + if (ptkResolutionScope) *ptkResolutionScope = mdtAssemblyRef | (m_rawAssemblyRefCount + ContractAssembly_SystemRuntime + 1); + break; + + case kTrSystemAttribute: + if (pszNamespace != NULL) *pszNamespace = "System"; + if (pszName != NULL) *pszName = "Attribute"; + if (ptkResolutionScope != NULL) *ptkResolutionScope = mdtAssemblyRef | (m_rawAssemblyRefCount + ContractAssembly_SystemRuntime + 1); + break; + + default: + _ASSERTE(!"Unknown treatment value."); + break; + + } + } + hr = S_OK; + +ErrExit: + return hr; +} // WinMDAdapter::GetTypeRefProps + +//------------------------------------------------------------------------------ +// +// Get TypeRefTreatment value for a TypeRef +// +HRESULT +WinMDAdapter::GetTypeRefTreatment( + mdTypeRef tkTypeRef, + ULONG * pTypeRefTreatment) +{ + HRESULT hr; + + _ASSERTE(pTypeRefTreatment != NULL); + _ASSERTE(TypeFromToken(tkTypeRef) == mdtTypeRef); + + ULONG typeRefIndex = RidFromToken(tkTypeRef) - 1; + ULONG treatment; + IfFailGo(m_typeRefTreatmentMemoTable.GetEntry(typeRefIndex, &treatment)); + if (hr == S_FALSE) + { + LPCSTR szFromNamespace; + LPCSTR szFromName; + mdToken tkResolutionScope; + IfFailGo(m_pRawMetaModelCommonRO->CommonGetTypeRefProps(tkTypeRef, &szFromNamespace, &szFromName, &tkResolutionScope)); + treatment = kTrNoRewriteNeeded; + UINT redirIndex; + if (ConvertWellKnownTypeNameFromWinRTToClr(&szFromNamespace, &szFromName, &redirIndex)) + { + treatment = kTrClassWellKnownRedirected | redirIndex; + } + else + { + if (0 == strcmp(szFromNamespace, "System")) + { + if (0 == strcmp(szFromName, "MulticastDelegate")) + { + treatment = kTrSystemDelegate; + } + else if (0 == strcmp(szFromName, "Attribute")) + { + treatment = kTrSystemAttribute; + } + else if (0 == strcmp(szFromName, "Enum")) + { + treatment = kTrSystemEnum; + } + else if (0 == strcmp(szFromName, "ValueType")) + { + treatment = kTrSystemValueType; + } + } + } + + // Note that we intentionally do not mangle names of TypeRef's pointing to mangled TypeDef's + // in the same module. This allows WinMDExp to generate "conditional TypeRef's", i.e. references + // to the WinMD view or CLR view, depending on whether the adapter is on. + + IfFailGo(m_typeRefTreatmentMemoTable.InitEntry(typeRefIndex, &treatment)); + } + _ASSERTE(treatment != kTrNotYetInitialized); + + *pTypeRefTreatment = treatment; + hr = S_OK; + +ErrExit: + return hr; +} // WinMDAdapter::GetTypeRefTreatment + + +//------------------------------------------------------------------------------ +// +// Get TypeRef's index in array code:g_rgRedirectedTypes. +// Returns S_OK if TypeRef is redirected and fills its index (*pIndex). +// Returns S_FALSE if type is not well known redirected type (*pIndex is not initialized). + +// +HRESULT +WinMDAdapter::GetTypeRefRedirectedInfo( + mdTypeRef tkTypeRef, + RedirectedTypeIndex * pIndex) +{ + _ASSERTE(TypeFromToken(tkTypeRef) == mdtTypeRef); + _ASSERTE(pIndex != NULL); + + HRESULT hr; + ULONG treatment; + IfFailGo(GetTypeRefTreatment(tkTypeRef, &treatment)); + + ULONG treatmentClass = treatment & kTrClassMask; + if (treatmentClass == kTrClassWellKnownRedirected) + { + *pIndex = (RedirectedTypeIndex)(treatment & ~kTrClassMask); + _ASSERTE(*pIndex < RedirectedTypeIndex_Count); + hr = S_OK; + } + else + { + // Do not initialize *pIndex + hr = S_FALSE; + } + +ErrExit: + return hr; +} + +//------------------------------------------------------------------------------ +// +// Finds a typeref by its (transformed) name +// +HRESULT WinMDAdapter::FindTypeRef( // S_OK or error. + LPCSTR szNamespace, // [IN] Namespace for the TypeRef. + LPCSTR szName, // [IN] Name of the TypeRef. + mdToken tkResolutionScope, // [IN] Resolution Scope fo the TypeRef. + mdTypeRef *ptk) // [OUT] TypeRef token returned. +{ + HRESULT hr; + + _ASSERTE(szName); // Crash on NULL pszName (just like the real metadata importer) + _ASSERTE(ptk); // Crash on NULL ptk (just like the real metadata importer) + + + // initialize the output parameter + *ptk = mdTypeRefNil; + + // Treat no namespace as empty string. + if (!szNamespace) + szNamespace = ""; + + ULONG cTypeRefRecs = m_pRawMetaModelCommonRO->CommonGetRowCount(mdtTypeRef); + + for (ULONG i = 1; i <= cTypeRefRecs; i++) + { + LPCUTF8 szNamespaceTmp; + LPCUTF8 szNameTmp; + mdToken tkRes; + + mdTypeRef tr = TokenFromRid(i, mdtTypeRef); + IfFailGo(GetTypeRefProps(tr, &szNamespaceTmp, &szNameTmp, &tkRes)); + if (IsNilToken(tkRes)) + { + if (!IsNilToken(tkResolutionScope)) + continue; + } + else if (tkRes != tkResolutionScope) + continue; + + if (strcmp(szNamespace, szNamespaceTmp)) + continue; + + if (!strcmp(szNameTmp, szName)) + { + *ptk = tr; + hr = S_OK; + goto ErrExit; + } + } + + // cannot find the typedef + hr = CLDB_E_RECORD_NOTFOUND; +ErrExit: + return hr; +} + +//------------------------------------------------------------------------------ + +HRESULT WinMDAdapter::ModifyExportedTypeName( + mdExportedType tkExportedType, // [IN] exportedType token + LPCSTR *pszNamespace, // [IN,OUT,OPTIONAL] namespace to modify + LPCSTR *pszName // [IN,OUT,OPTIONAL] name to modify +) +{ + _ASSERTE(TypeFromToken(tkExportedType) == mdtExportedType); + + if (m_scenario == kWinMDExp) + { + if (pszName && 0 == strncmp(*pszName, s_szCLRPrefix, s_ncCLRPrefix)) + { + (*pszName) += s_ncCLRPrefix; + } + } + return S_OK; +} + +//------------------------------------------------------------------------------ + +/*static*/ +void WinMDAdapter::GetExtraAssemblyRefProps(FrameworkAssemblyIndex index, + LPCSTR* ppName, + AssemblyMetaDataInternal* pContext, + PCBYTE * ppPublicKeytoken, + DWORD* pTokenLength, + DWORD* pdwFlags) +{ + _ASSERTE(index >= 0 && index < FrameworkAssembly_Count); + _ASSERTE(index != FrameworkAssembly_Mscorlib); + + if (ppName) + { + *ppName = GetExtraAssemblyRefNameFromIndex((FrameworkAssemblyIndex)index); + } + + if (pContext) + { + ::memset(pContext, 0, sizeof(AssemblyMetaDataInternal)); + + pContext->usMajorVersion = VER_ASSEMBLYMAJORVERSION; + pContext->usMinorVersion = VER_ASSEMBLYMINORVERSION; + pContext->usBuildNumber = VER_ASSEMBLYBUILD; + pContext->usRevisionNumber = VER_ASSEMBLYBUILD_QFE; + + pContext->szLocale = ""; + } + + if (ppPublicKeytoken) + { +#ifdef FEATURE_CORECLR + if (index == FrameworkAssembly_System || index == FrameworkAssembly_Mscorlib) + { + *ppPublicKeytoken = g_rbTheSilverlightPlatformKeyToken; + *pTokenLength = sizeof(g_rbTheSilverlightPlatformKeyToken); + } + else +#endif + { + if (index == FrameworkAssembly_SystemNumericsVectors) + { + *ppPublicKeytoken = s_pbContractPublicKeyToken; + *pTokenLength = sizeof(s_pbContractPublicKeyToken); + } + else + { + *ppPublicKeytoken = s_pbFrameworkPublicKeyToken; + *pTokenLength = sizeof(s_pbFrameworkPublicKeyToken); + } + } + } + + if (pdwFlags) + { + // ppPublicKeytoken contains the public key token, not the whole key. + *pdwFlags = 0; + } +} + +//-------------------------------------------------------------------------------- + +HRESULT WinMDAdapter::FindExportedType( + LPCUTF8 szNamespace, // [IN] expected namespace + LPCUTF8 szName, // [IN] expected name + mdToken tkEnclosingType, // [IN] expected tkEnclosingType + mdExportedType *ptkExportedType // [OUT] ExportedType token returned. +) +{ + HRESULT hr; + + _ASSERTE(szName && ptkExportedType); + + // Set NULL namespace to empty string. + if (!szNamespace) + szNamespace = ""; + + // Set output to Nil. + *ptkExportedType = mdTokenNil; + + ULONG ulCount = m_pRawMetaModelCommonRO->CommonGetRowCount(mdtExportedType); + while (ulCount) + { + mdExportedType tkCandidateExportedType = TokenFromRid(ulCount--, mdtExportedType); + + LPCSTR szCandidateNamespace; + LPCSTR szCandidateName; + mdToken tkCandidateImpl; + + IfFailRet(m_pRawMetaModelCommonRO->CommonGetExportedTypeProps(tkCandidateExportedType, &szCandidateNamespace, &szCandidateName, &tkCandidateImpl)); + IfFailRet(this->ModifyExportedTypeName(tkCandidateExportedType, &szCandidateNamespace, &szCandidateName)); + // Handle the case of nested vs. non-nested classes. + if (TypeFromToken(tkCandidateImpl) == mdtExportedType && !IsNilToken(tkCandidateImpl)) + { + // Current ExportedType being looked at is a nested type, so + // comparing the implementation token. + if (tkCandidateImpl != tkEnclosingType) + continue; + } + else if (TypeFromToken(tkEnclosingType) == mdtExportedType && + !IsNilToken(tkEnclosingType)) + { + // ExportedType passed in is nested but the current ExportedType is not. + continue; + } + + if (0 != strcmp(szName, szCandidateName)) + continue; + + if (0 != strcmp(szNamespace, szCandidateNamespace)) + continue; + + *ptkExportedType = tkCandidateExportedType; + return S_OK; + } + return CLDB_E_RECORD_NOTFOUND; +} + + +//------------------------------------------------------------------------------ + +// Modifies methodDef flags and RVA +HRESULT WinMDAdapter::ModifyMethodProps(mdMethodDef tkMethodDef, /*[in, out]*/ DWORD *pdwAttr, /* [in,out] */ DWORD *pdwImplFlags, /* [in,out] */ ULONG *pulRVA, /* [in, out] */ LPCSTR *pszName) +{ + HRESULT hr; + _ASSERTE(TypeFromToken(tkMethodDef) == mdtMethodDef); + + ULONG mdTreatment; + IfFailGo(GetMethodDefTreatment(tkMethodDef, &mdTreatment)); + + DWORD dwAttr = pdwAttr ? *pdwAttr: 0; + DWORD dwImplFlags = pdwImplFlags ? *pdwImplFlags : 0; + ULONG ulRVA = pulRVA ? *pulRVA : 0; + + switch (mdTreatment & kMdTreatmentMask) + { + case kMdInterface: + // Method is declared on an interface + dwImplFlags |= miRuntime|miInternalCall; + break; + + case kMdDelegate: + // Method is declared on a delegate + dwAttr &= ~mdMemberAccessMask; + dwAttr |= mdPublic; + ulRVA = 0; + dwImplFlags |= miRuntime; + break; + + case kMdAttribute: + // Method is declared on an attribute + ulRVA = 0; + dwImplFlags |= miRuntime|miInternalCall; + break; + + case kMdImplementation: + // CLR implementation class. Needs no adjustment. + break; + + case kMdHiddenImpl: + dwAttr &= ~mdMemberAccessMask; + dwAttr |= mdPrivate; + // fall-through + + case kMdOther: + + // All other cases + ulRVA = 0; + dwImplFlags |= miRuntime|miInternalCall; + + if (mdTreatment & kMdMarkAbstractFlag) + { + dwAttr |= mdAbstract; + } + + if (mdTreatment & kMdMarkPublicFlag) + { + dwAttr &= ~mdMemberAccessMask; + dwAttr |= mdPublic; + } + + break; + + case kMdRenameToDisposeMethod: + ulRVA = 0; + dwImplFlags |= miRuntime|miInternalCall; + if(pszName) + { + *pszName = "Dispose"; + } + break; + + default: + UNREACHABLE(); + + } + + dwAttr |= mdHideBySig; + + if (pdwAttr) + (*pdwAttr) = dwAttr; + if (pdwImplFlags) + (*pdwImplFlags) = dwImplFlags; + if (pulRVA) + *pulRVA = ulRVA; + hr = S_OK; + + ErrExit: + return hr; +} + +HRESULT WinMDAdapter::ModifyFieldProps (mdToken tkField, mdToken tkParent, LPCSTR szFieldName, DWORD *pdwFlags) +{ + _ASSERTE(szFieldName != NULL); + + HRESULT hr; + if (pdwFlags && IsFdPrivate(*pdwFlags) && (0 == strcmp(szFieldName, "value__"))) + { + ULONG treatment; + BOOL isEnum = FALSE; + if(TypeFromToken(tkParent) == mdtTypeDef) + { + IfFailGo(GetTypeDefTreatment(tkParent, &treatment)); + + if ((treatment & kTdEnum) == kTdEnum) + { + isEnum = TRUE; + } + } + + if (isEnum) + { + // We have found the value__ field of the enum. + // We need to change its flags from private to public + *pdwFlags = (*pdwFlags & ~fdPrivate) | fdPublic; + } + } + + hr = S_OK; + +ErrExit: + return hr; +} + + +HRESULT WinMDAdapter::ModifyFieldDefProps (mdFieldDef tkFielddDef, DWORD *pdwFlags) +{ + HRESULT hr; + + if (pdwFlags) + { + mdTypeDef tkParent; + LPCSTR szName; + IfFailGo(m_pRawMetaModelCommonRO->CommonGetFieldDefProps(tkFielddDef, &tkParent, &szName, pdwFlags)); + IfFailGo(ModifyFieldProps(tkFielddDef, tkParent, szName, pdwFlags)); + } + + hr = S_OK; +ErrExit: + return hr; +} + +//------------------------------------------------------------------------------ + +HRESULT WinMDAdapter::ModifyMemberProps(mdToken tkMember, /*[in, out]*/ DWORD *pdwAttr, /* [in,out] */ DWORD *pdwImplFlags, /* [in,out] */ ULONG *pulRVA, LPCSTR *pszNewName) +{ + HRESULT hr; + switch(TypeFromToken(tkMember)) + { + case mdtMethodDef: IfFailGo(ModifyMethodProps(tkMember, pdwAttr, pdwImplFlags, pulRVA, pszNewName)); + break; + + case mdtMemberRef: + { + // + // We need to rename the MemberRef for IClosable.Close as well + // so that the MethodImpl for Dispose method can correctly be shown as IDisposable.Dispose + // instead of IDisposable.Close + // + UINT nIndex = WinMDAdapter::RedirectedTypeIndex_Invalid; + if (pszNewName && + CheckIfMethodImplImplementsARedirectedInterface(tkMember, &nIndex) == S_OK && + nIndex == WinMDAdapter::RedirectedTypeIndex_Windows_Foundation_IClosable) + { + *pszNewName = "Dispose"; + } + } + break; + + case mdtFieldDef: + IfFailGo(ModifyFieldDefProps(tkMember, pdwAttr)); + break; + } + + hr = S_OK; +ErrExit: + return hr; +} + +//------------------------------------------------------------------------------ + +// Get MethodTreatment value for a methodDef +HRESULT WinMDAdapter::GetMethodDefTreatment(mdMethodDef tkMethodDef, ULONG *ppMethodDefTreatment) +{ + HRESULT hr; + + _ASSERTE(TypeFromToken(tkMethodDef) == mdtMethodDef); + ULONG index = RidFromToken(tkMethodDef) - 1; + + // Thread-safety: No lock is needed to update this table as we're monotonically advancing a kMdNotYetInitialized to + // some other fixed byte. The work to decide this value is idempotent and side-effect free so + // there's no harm if two threads do it concurrently. + ULONG mdTreatment; + IfFailGo(m_methodDefTreatmentMemoTable.GetEntry(index, &mdTreatment)); + if (hr == S_FALSE) + { + mdTypeDef declaringTypeDef; + IfFailGo(m_pRawMetaModelCommonRO->FindParentOfMethodHelper(tkMethodDef, &declaringTypeDef)); + ULONG firstMethodRid; + IfFailGo(m_pRawMetaModelCommonRO->CommonGetTypeDefProps(declaringTypeDef, NULL, NULL, NULL, NULL, &firstMethodRid)); + IfFailGo(ComputeMethodDefTreatment(tkMethodDef, declaringTypeDef, &mdTreatment)); + _ASSERTE(mdTreatment != kMdNotYetInitialized); + IfFailGo(m_methodDefTreatmentMemoTable.InitEntry(index, &mdTreatment)); + + // Since the mdTreatment is only a function of the declaring type in most cases, cache it for all the declared method since + // we took the time to look up the declaring type. Do enough validity checks to avoid corrupting the heap + // or table but otherwise, swallow validity errors as this is just an optimization. + // Methods on RuntimeClasses need to get treatment data per method. + if (((mdTreatment & kMdTreatmentMask) != kMdOther) && + ((mdTreatment & kMdTreatmentMask) != kMdHiddenImpl) && + ((mdTreatment & kMdTreatmentMask) != kMdRenameToDisposeMethod)) + { + const ULONG methodDefCount = m_pRawMetaModelCommonRO->CommonGetRowCount(mdtMethodDef); + const ULONG startIndex = RidFromToken(firstMethodRid) - 1; + if (startIndex < methodDefCount) + { + const ULONG typeDefCount = m_pRawMetaModelCommonRO->CommonGetRowCount(mdtTypeDef); + if (RidFromToken(declaringTypeDef) < typeDefCount) + { + ULONG stopMethodRid; + if (S_OK == m_pRawMetaModelCommonRO->CommonGetTypeDefProps(declaringTypeDef + 1, NULL, NULL, NULL, NULL, &stopMethodRid)) + { + ULONG stopIndex = RidFromToken(stopMethodRid) - 1; + if (startIndex < methodDefCount && stopIndex <= methodDefCount) + { + ULONG walkIndex = startIndex; + while (walkIndex < stopIndex) + { + IfFailGo(m_methodDefTreatmentMemoTable.InitEntry(walkIndex++, &mdTreatment)); + } + } + } + } + else + { + // This was final typeDef - blast the mdTreatment into the rest of the table. + for (ULONG i = startIndex; i < methodDefCount; i++) + { + IfFailGo(m_methodDefTreatmentMemoTable.InitEntry(i, &mdTreatment)); + } + } + } + } + } + + *ppMethodDefTreatment = mdTreatment; + hr = S_OK; + + ErrExit: + return hr; +} + +//------------------------------------------------------------------------------ + +// Compute MethodTreatment value for a methodDef (unlike GetMethodDefTreatment, this +// does not cache.) +// +HRESULT WinMDAdapter::ComputeMethodDefTreatment(mdMethodDef tkMethodDef, mdTypeDef tkDeclaringTypeDef, ULONG *ppMethodDefTreatment) +{ + HRESULT hr; + + BYTE mdTreatment = kMdImplementation; + + LPCSTR szDeclaringTypeName; + DWORD parentTdAttr; + mdToken extends; + IfFailGo(m_pRawMetaModelCommonRO->CommonGetTypeDefProps(tkDeclaringTypeDef, NULL, &szDeclaringTypeName, &parentTdAttr, &extends, NULL)); + + // We only want to treat this method special if it has metadata exposed to WinRT + if (IsTdWindowsRuntime(parentTdAttr)) + { + LPCSTR szUnmangledName; + IfFailGo(CheckIfClrImplementationType(szDeclaringTypeName, parentTdAttr, &szUnmangledName)); + if (hr == S_OK) + { + mdTreatment = kMdImplementation; + } + else if (IsTdNested(parentTdAttr)) + { + // nested types are implementation + mdTreatment = kMdImplementation; + } + else if (parentTdAttr & tdInterface) + { + // Method is declared on an interface. + mdTreatment = kMdInterface; + } + else if (m_scenario == kWinMDExp && (parentTdAttr & tdPublic) == 0) + { + // internal classes generated by WinMDExp are implementation + mdTreatment = kMdImplementation; + } + else + { + mdTreatment = kMdOther; + + if (TypeFromToken(extends) == mdtTypeRef) + { + ULONG trTreatment; + IfFailGo(GetTypeRefTreatment(extends, &trTreatment)); + if (trTreatment == kTrSystemDelegate) + { + // Method is declared on a delegate + mdTreatment = kMdDelegate; + } + else if (trTreatment == kTrSystemAttribute) + { + // Method is declared on a attribute + mdTreatment = kMdAttribute; + } + } + } + } + if (mdTreatment == kMdOther) + { + // we want to hide the method if it implements only redirected interfaces + // Also we want to check if the methodImpl is IClosable.Close then we will change the name. + bool fSeenRedirectedInterfaces = false; + bool fSeenNonRedirectedInterfaces = false; + + bool isIClosableCloseMethod = false; + + mdToken tkMethodImplFirst; + ULONG count; + mdTypeRef mtTypeRef; + IfFailGo(m_pRawMetaModelCommonRO->CommonGetMethodImpls(tkDeclaringTypeDef, &tkMethodImplFirst, &count)); + for (ULONG i = 0; i < count; i++) + { + mdToken tkMethodImpl = tkMethodImplFirst + i; + mdToken tkBody, tkDecl; + IfFailGo(m_pRawMetaModelCommonRO->CommonGetMethodImplProps(tkMethodImpl, &tkBody, &tkDecl)); + + if (tkBody == tkMethodDef) + { + // See if this MethodImpl implements a redirected interface + UINT nIndex; + IfFailGo(CheckIfMethodImplImplementsARedirectedInterface(tkDecl, &nIndex)); + if (hr == S_FALSE) + { + // Now we know this implements a non-redirected interface + // But we need to keep looking, just in case we got a MethodImpl that implements + // the IClosable.Close method and needs to be renamed + fSeenNonRedirectedInterfaces = true; + } + else if (SUCCEEDED(hr)) + { + fSeenRedirectedInterfaces = true; + if (nIndex == WinMDAdapter::RedirectedTypeIndex_Windows_Foundation_IClosable) + { + // This method implements IClosable.Close + // Let's rename it to Dispose later + // Once we know this implements IClosable.Close, we are done looking as we know + // we won't hide it + isIClosableCloseMethod = true; + break; + } + } + } + } + + if (isIClosableCloseMethod) + { + // Rename IClosable.Close to Dispose + mdTreatment = kMdRenameToDisposeMethod; + } + else if (fSeenRedirectedInterfaces && !fSeenNonRedirectedInterfaces) + { + // Only hide if all the interfaces implemented are redirected + mdTreatment = kMdHiddenImpl; + } + } + + // If treatment is other, then this is a non-managed WinRT runtime class definition. Find out about various bits that we apply via attrubtes and name parsing. + if (mdTreatment == kMdOther) + { + // Scan through Custom Attributes on type, looking for interesting bits. + HRESULT hrCA; + hrCA = m_pRawMetaModelCommonRO->CommonGetCustomAttributeByNameEx(tkMethodDef, "Windows.UI.Xaml.TreatAsPublicMethodAttribute", NULL, NULL, NULL); + if (hrCA == S_OK) + { + mdTreatment |= kMdMarkPublicFlag; + } + + + hrCA = m_pRawMetaModelCommonRO->CommonGetCustomAttributeByNameEx(tkMethodDef, "Windows.UI.Xaml.TreatAsAbstractMethodAttribute", NULL, NULL, NULL); + if (hrCA == S_OK) + { + mdTreatment |= kMdMarkAbstractFlag; + } + + LPCSTR szName; + DWORD dwFlags; + IfFailRet(m_pRawMetaModelCommonRO->CommonGetMethodDefProps(tkMethodDef, &szName, &dwFlags, NULL, NULL)); + } + *ppMethodDefTreatment = mdTreatment; + hr = S_OK; + +ErrExit: + return hr; +} + +//------------------------------------------------------------------------------ + +// +// Finds a CA by its (transformed) name +// +HRESULT WinMDAdapter::GetCustomAttributeByName( // S_OK or error. + mdToken tkObj, // [IN] Object with Custom Attribute. + LPCUTF8 szName, // [IN] Name of desired Custom Attribute. + mdCustomAttribute *ptkCA, // [OUT] Put custom attribute token here + const void **ppData, // [OUT] Put pointer to data here. + ULONG *pcbData) // [OUT] Put size of data here. +{ + HRESULT hr; + _ASSERTE(szName); + + if (ConvertWellKnownTypeNameFromClrToWinRT(&szName)) + { + mdCustomAttribute tkCA; + IfFailGo(m_pRawMetaModelCommonRO->CommonGetCustomAttributeByNameEx(tkObj, szName, &tkCA, NULL, NULL)); + if (hr == S_FALSE) + goto ErrExit; + if (ptkCA) + *ptkCA = tkCA; + IfFailGo(GetCustomAttributeBlob(tkCA, ppData, pcbData)); + } + else + { + IfFailGo(m_pRawMetaModelCommonRO->CommonGetCustomAttributeByNameEx(tkObj, szName, ptkCA, ppData, pcbData)); + } + ErrExit: + return hr; +} + +//------------------------------------------------------------------------------ + +// +// Modify CA blobs +// +HRESULT WinMDAdapter::GetCustomAttributeBlob( + mdCustomAttribute tkCA, + const void **ppData, // [OUT] Put pointer to data here. + ULONG *pcbData) // [OUT] Put size of data here. +{ + HRESULT hr; + + _ASSERTE(TypeFromToken(tkCA) == mdtCustomAttribute); + ULONG index = RidFromToken(tkCA) - 1; + + // If someone already queried this CA, use the previous result. + CABlob * pCABlob; + IfFailGo(m_redirectedCABlobsMemoTable.GetEntry(index, &pCABlob)); + if (hr == S_FALSE) + { + // No, we're the first. Initialize the entry (keeping in mind we may be racing with other threads.) + pCABlob = CABlob::NOREDIRECT; + mdToken tkOwner; + mdToken tkCtor; + IfFailGo(m_pRawMetaModelCommonRO->CommonGetCustomAttributeProps(tkCA, &tkOwner, &tkCtor, NULL, NULL)); + if (TypeFromToken(tkOwner) == mdtTypeDef) // AttributeUsageAttribute only goes on a typeDef, so if the owner isn't a typeDef, no point in going further. + { + if (TypeFromToken(tkCtor) == mdtMemberRef) // REX has promised to use a memberRef (not Def) here. + { + mdToken tkCtorType; + IfFailGo(m_pRawMetaModelCommonRO->CommonGetMemberRefProps(tkCtor, &tkCtorType)); + if (TypeFromToken(tkCtorType) == mdtTypeRef) // REX has promised to use a typeRef (not a Def, or heavens forbid, a Spec) here + { + RedirectedTypeIndex redirectedTypeIndex; + IfFailGo(GetTypeRefRedirectedInfo(tkCtorType, &redirectedTypeIndex)); + _ASSERTE((hr == S_OK) || (hr == S_FALSE)); + + if ((hr == S_OK) && (redirectedTypeIndex == RedirectedTypeIndex_Windows_Foundation_Metadata_AttributeUsageAttribute)) + { + // We found a Windows.Foundation.Metadata.AttributeUsageAttribute. The TypeRef redirection already makes this + // look like a System.AttributeUsageAttribute. Must munge the blob so that it matches the CLR expections. + BOOL allowMultiple; + DWORD clrTargetValue; + IfFailGo(TranslateWinMDAttributeUsageAttribute(tkOwner, &clrTargetValue, &allowMultiple)); + if (hr == S_OK) + { + CABlob *pNewCABlob = NULL; + IfFailGo(CreateClrAttributeUsageAttributeCABlob(clrTargetValue, allowMultiple, &pNewCABlob)); + pCABlob = pNewCABlob; + } + } + } + } + } + + IfFailGo(m_redirectedCABlobsMemoTable.InitEntry(index, &pCABlob)); + } + + _ASSERTE(pCABlob != NULL); + const void *pData; + ULONG cbData; + if (pCABlob == CABlob::NOREDIRECT) + { + // The normal case: don't rewrite the blob. + IfFailGo(m_pRawMetaModelCommonRO->CommonGetCustomAttributeProps(tkCA, NULL, NULL, &pData, &cbData)); + } + else + { + // The special cases: Blob was rewritten, return the rewritten blob. + pData = pCABlob->data; + cbData = pCABlob->cbBlob; + } + if (ppData) + *ppData = pData; + if (pcbData) + *pcbData = cbData; + + hr = S_OK; + ErrExit: + return hr; +} + +//------------------------------------------------------------------------------ + +// Note: This method will look in a cache for the reinterpreted signature, but does not add any values to +// the cache or do any work on failure. If we can't find it then it returns S_FALSE. +HRESULT WinMDAdapter::GetCachedSigForToken( + mdToken token, // [IN] given token + MemoTable &memoTable, // [IN] the MemoTable to use + ULONG *pcbSigBlob, // [OUT] count of bytes in the signature blob + PCCOR_SIGNATURE *ppSig, // [OUT] new signature + BOOL *pfPassThrough // [OUT] did the cache say we don't need to reinterpret this sig? +) +{ + _ASSERTE(pfPassThrough != NULL); + + HRESULT hr; + + ULONG index = RidFromToken(token) - 1; + + // If someone already queried this method signature, use the previous result. + SigData *pSigData = NULL; + IfFailGo(memoTable.GetEntry(index, &pSigData)); + if (hr == S_FALSE) + { + *pfPassThrough = FALSE; + return S_FALSE; + } + + _ASSERTE(pSigData != NULL); + + if (pSigData == SigData::NOREDIRECT) + { + // The normal case: don't rewrite the signature. + *pfPassThrough = TRUE; + return S_FALSE; + } + else + { + *pfPassThrough = FALSE; + // The signature was rewritten, return the rewritten sig. + if (ppSig) + *ppSig = (PCCOR_SIGNATURE) pSigData->data; + if (pcbSigBlob) + *pcbSigBlob = pSigData->cbSig; + } + + hr = S_OK; + + ErrExit: + return hr; +} + +//------------------------------------------------------------------------------ +// static +HRESULT WinMDAdapter::InsertCachedSigForToken( + mdToken token, // [IN] given token + MemoTable &memoTable, // [IN] the MemoTable to use + SigData **ppSigData // [IN, OUT] new signature or SigData::NOREDIRECT if the signature didn't need to be reparsed, +) // will be updated with another (but identical) SigData* if this thread lost the race +{ + _ASSERTE(ppSigData != NULL && *ppSigData != NULL); + + HRESULT hr; + ULONG index = RidFromToken(token) - 1; + + IfFailGo(memoTable.InitEntry(index, ppSigData)); + hr = S_OK; + + ErrExit: + return hr; +} + +//------------------------------------------------------------------------------ +static HRESULT FinalizeSignatureRewrite( + SigBuilder & newSig, + BOOL fChangedSig, + WinMDAdapter::SigData **ppSigData + DEBUG_ARG(ULONG cbOrigSigBlob) + ) +{ + // Make sure we didn't lose anything, since we wrote out the full signature. + ULONG cbNewSigLen; + BYTE * pNewSigBytes = (BYTE *) newSig.GetSignature(&cbNewSigLen); + _ASSERTE(cbNewSigLen == cbOrigSigBlob); // Didn't lose any data nor add anything + + // Set the output SigData appropriately. + if (fChangedSig) + { + *ppSigData = WinMDAdapter::SigData::Create(cbNewSigLen, pNewSigBytes); + + if (*ppSigData == NULL) + { + return E_OUTOFMEMORY; + } + } + else + { + *ppSigData = WinMDAdapter::SigData::NOREDIRECT; + } + return S_OK; +} + +//------------------------------------------------------------------------------ + +// Purpose: Translate method signatures containing classes that we're projecting as value types, and vice versa. +// Example: ELEMENT_TYPE_CLASS [IReference] to ELEMENT_TYPE_VALUETYPE [Nullable] +// Example: ELEMENT_TYPE_VALUETYPE [Windows.Foundation.HResult] to ELEMENT_TYPE_CLASS [Exception] +HRESULT WinMDAdapter::ReinterpretMethodSignature( + ULONG cbOrigSigBlob, // [IN] count of bytes in the original signature blob + PCCOR_SIGNATURE pOrigSig, // [IN] original signature + SigData **ppSigData // [OUT] new signature or SigData::NOREDIRECT +) +{ + _ASSERTE(pOrigSig != NULL); + _ASSERTE(ppSigData != NULL); + + HRESULT hr; + + // @REVISIT_TODO: Need to allocate memory here. We cannot take a lock though (such as any lock needed by 'new'), or we can get + // into deadlocks from profilers that need to inspect metadata to walk the stack. Needs some help from some loader/ngen experts. + + BOOL fChangedSig = FALSE; + + // The following implements MethodDef signature parsing, per ECMA CLI spec, section 23.2.1. + SigParser sigParser(pOrigSig, cbOrigSigBlob); + SigBuilder newSig(cbOrigSigBlob); // We will not change the signature size, just modify it a bit (E_T_CLASS <-> E_T_VALUETYPE) + + // Read calling convention info - Note: Calling convention is always one byte + ULONG callingConvention; + IfFailGo(sigParser.GetCallingConvInfo(&callingConvention)); + _ASSERTE((callingConvention & 0xff) == callingConvention); + newSig.AppendByte((BYTE)callingConvention); + + // If it is generic, read the generic parameter count + if ((callingConvention & CORINFO_CALLCONV_GENERIC) != 0) + { + ULONG genericArgsCount; + IfFailGo(sigParser.GetData(&genericArgsCount)); + newSig.AppendData(genericArgsCount); + } + + // Read number of locals / method parameters + ULONG cParameters; + IfFailGo(sigParser.GetData(&cParameters)); + newSig.AppendData(cParameters); + + if (callingConvention != CORINFO_CALLCONV_LOCAL_SIG) + { + // Read return type + IfFailGo(RewriteTypeInSignature(&sigParser, &newSig, &fChangedSig)); + } + + // Visit each local / parameter + for (ULONG i = 0; i < cParameters; i++) + { + IfFailGo(RewriteTypeInSignature(&sigParser, &newSig, &fChangedSig)); + } + + IfFailGo(FinalizeSignatureRewrite(newSig, fChangedSig, ppSigData DEBUG_ARG(cbOrigSigBlob))); + return S_OK; + +ErrExit: + Debug_ReportError("Couldn't parse a signature in WinMDAdapter::ReinterpretMethodSignature!"); + return hr; +} // WinMDAdapter::ReinterpretMethodSignature + + +//------------------------------------------------------------------------------ + +// Purpose: Translate FieldDef signatures containing classes that we're projecting as value types, and vice versa. +// Example: ELEMENT_TYPE_VALUETYPE [Windows.Foundation.HResult] to ELEMENT_TYPE_CLASS [Exception] +HRESULT WinMDAdapter::ReinterpretFieldSignature( + ULONG cbOrigSigBlob, // [IN] count of bytes in the original signature blob + PCCOR_SIGNATURE pOrigSig, // [IN] original signature + SigData **ppSigData // [OUT] new signature or SigData::NOREDIRECT +) +{ + _ASSERTE(pOrigSig != NULL); + _ASSERTE(ppSigData != NULL); + + HRESULT hr = S_OK; + BOOL fChangedSig = FALSE; + + // The following implements FieldDef signature parsing, per ECMA CLI spec, section 23.2.4. + // Format is FIELD [custom modifiers]* Type + SigParser sigParser(pOrigSig, cbOrigSigBlob); + SigBuilder newSig(cbOrigSigBlob); // We will not change the signature size, just modify it a bit (E_T_CLASS <-> E_T_VALUETYPE) + + // Read calling convention info - this should be IMAGE_CEE_CS_CALLCONV_FIELD. + ULONG callingConvention; + IfFailGo(sigParser.GetCallingConvInfo(&callingConvention)); + _ASSERTE((callingConvention & 0xff) == callingConvention); + _ASSERTE(callingConvention == IMAGE_CEE_CS_CALLCONV_FIELD); + newSig.AppendByte((BYTE)callingConvention); + + // Rewrite field type + IfFailGo(RewriteTypeInSignature(&sigParser, &newSig, &fChangedSig)); + + IfFailGo(FinalizeSignatureRewrite(newSig, fChangedSig, ppSigData DEBUG_ARG(cbOrigSigBlob))); + return S_OK; + +ErrExit: + Debug_ReportError("Couldn't parse a signature in WinMDAdapter::ReinterpretFieldSignature!"); + return hr; +} // WinMDAdapter::ReinterpretFieldSignature + + +//------------------------------------------------------------------------------ + +// Purpose: Translate TypeSpec signatures containing classes that we're projecting as value types, and vice versa. +HRESULT WinMDAdapter::ReinterpretTypeSpecSignature( + ULONG cbOrigSigBlob, // [IN] count of bytes in the original signature blob + PCCOR_SIGNATURE pOrigSig, // [IN] original signature + SigData **ppSigData // [OUT] new signature or SigData::NOREDIRECT +) +{ + _ASSERTE(pOrigSig != NULL); + _ASSERTE(ppSigData != NULL); + + HRESULT hr = S_OK; + BOOL fChangedSig = FALSE; + + // The following implements TypeSpec signature parsing, per ECMA CLI spec, section 23.2.14. + // Format is [custom modifiers]* Type + SigParser sigParser(pOrigSig, cbOrigSigBlob); + SigBuilder newSig(cbOrigSigBlob); // We will not change the signature size, just modify it a bit (E_T_CLASS <-> E_T_VALUETYPE) + + // Rewrite the type + IfFailGo(RewriteTypeInSignature(&sigParser, &newSig, &fChangedSig)); + + IfFailGo(FinalizeSignatureRewrite(newSig, fChangedSig, ppSigData DEBUG_ARG(cbOrigSigBlob))); + return S_OK; + +ErrExit: + Debug_ReportError("Couldn't parse a signature in WinMDAdapter::ReinterpretTypeSpecSignature!"); + return hr; +} // WinMDAdapter::ReinterpretTypeSpecSignature + + +//------------------------------------------------------------------------------ + +// Purpose: Translate MethodSpec signatures containing classes that we're projecting as value types, and vice versa. +HRESULT WinMDAdapter::ReinterpretMethodSpecSignature( + ULONG cbOrigSigBlob, // [IN] count of bytes in the original signature blob + PCCOR_SIGNATURE pOrigSig, // [IN] original signature + SigData **ppSigData // [OUT] new signature or SigData::NOREDIRECT +) +{ + _ASSERTE(pOrigSig != NULL); + _ASSERTE(ppSigData != NULL); + + HRESULT hr = S_OK; + BOOL fChangedSig = FALSE; + + // The following implements MethodSpec signature parsing, per ECMA CLI spec, section 23.2.15. + // Format is GENERICINST GenArgCount Type+ + SigParser sigParser(pOrigSig, cbOrigSigBlob); + SigBuilder newSig(cbOrigSigBlob); // We will not change the signature size, just modify it a bit (E_T_CLASS <-> E_T_VALUETYPE) + + // Read calling convention info - this should be IMAGE_CEE_CS_CALLCONV_GENERICINST. + ULONG callingConvention; + IfFailGo(sigParser.GetCallingConvInfo(&callingConvention)); + _ASSERTE((callingConvention & 0xff) == callingConvention); + _ASSERTE(callingConvention == IMAGE_CEE_CS_CALLCONV_GENERICINST); + newSig.AppendByte((BYTE)callingConvention); + + // Read number of generic arguments + ULONG cArguments; + IfFailGo(sigParser.GetData(&cArguments)); + newSig.AppendData(cArguments); + + // Rewrite each argument + for (ULONG i = 0; i < cArguments; i++) + { + IfFailGo(RewriteTypeInSignature(&sigParser, &newSig, &fChangedSig)); + } + + IfFailGo(FinalizeSignatureRewrite(newSig, fChangedSig, ppSigData DEBUG_ARG(cbOrigSigBlob))); + return S_OK; + +ErrExit: + Debug_ReportError("Couldn't parse a signature in WinMDAdapter::ReinterpretMethodSpecSignature!"); + return hr; +} // WinMDAdapter::ReinterpretMethodSpecSignature + + +//------------------------------------------------------------------------------ +// +// We expose some WinRT types to managed as CLR types, while changing reference type <-> value type: +// E_T_CLASS Windows.Foundation.IReference ---> E_T_VALUETYPE System.Nullable +// E_T_CLASS Windows.Foundation.Collections.IKeyValuePair ---> E_T_VALUETYPE System.Collections.Generic.KeyValuePair +// E_T_VALUETYPE Windows.UI.Xaml.Interop.TypeName ---> E_T_CLASS System.Type +// E_T_VALUETYPE Windows.Foundation.HResult ---> E_T_CLASS System.Exception +HRESULT WinMDAdapter::RewriteTypeInSignature( + SigParser * pSigParser, + SigBuilder * pSigBuilder, + BOOL * pfChangedSig) +{ + HRESULT hr; + + BYTE elementType; + IfFailGo(pSigParser->GetByte(&elementType)); + + switch (elementType) + { + // Simple types with no additional data in the signature + case ELEMENT_TYPE_VOID: + case ELEMENT_TYPE_BOOLEAN: + case ELEMENT_TYPE_CHAR: + case ELEMENT_TYPE_I1: + case ELEMENT_TYPE_U1: + case ELEMENT_TYPE_I2: + case ELEMENT_TYPE_U2: + case ELEMENT_TYPE_I4: + case ELEMENT_TYPE_U4: + case ELEMENT_TYPE_I8: + case ELEMENT_TYPE_U8: + case ELEMENT_TYPE_R4: + case ELEMENT_TYPE_R8: + case ELEMENT_TYPE_STRING: + case ELEMENT_TYPE_I: + case ELEMENT_TYPE_U: + case ELEMENT_TYPE_OBJECT: + case ELEMENT_TYPE_TYPEDBYREF: // TYPEDREF (it takes no args) a typed reference to some other type + { + pSigBuilder->AppendByte(elementType); + break; + } + + // Read a token + case ELEMENT_TYPE_CLASS: + { + mdToken token; + IfFailGo(pSigParser->GetToken(&token)); + + if (TypeFromToken(token) == mdtTypeRef) + { + RedirectedTypeIndex nRedirectedTypeIndex; + IfFailGo(this->GetTypeRefRedirectedInfo(token, &nRedirectedTypeIndex)); + _ASSERTE((hr == S_OK) || (hr == S_FALSE)); + + if (hr == S_OK) + { // TypeRef is well known redirectetd type (with index in array code:g_rgRedirectedTypes) + if (nRedirectedTypeIndex == RedirectedTypeIndex_Windows_Foundation_IReference || + nRedirectedTypeIndex == RedirectedTypeIndex_Windows_Foundation_Collections_IKeyValuePair) + { // The TypeRef name was changed to System.Nullable or System.Collections.Generic.KeyValuePair`2 (value type, not class) + elementType = ELEMENT_TYPE_VALUETYPE; + *pfChangedSig = TRUE; + } + } + // We do not want to return S_FALSE + hr = S_OK; + } + + pSigBuilder->AppendByte(elementType); + pSigBuilder->AppendToken(token); + + break; + } + case ELEMENT_TYPE_VALUETYPE: + { + mdToken token; + IfFailGo(pSigParser->GetToken(&token)); + + if (TypeFromToken(token) == mdtTypeRef) + { + RedirectedTypeIndex nRedirectedTypeIndex; + IfFailGo(this->GetTypeRefRedirectedInfo(token, &nRedirectedTypeIndex)); + _ASSERTE((hr == S_OK) || (hr == S_FALSE)); + + if (hr == S_OK) + { // TypeRef is well known redirectetd type (with index in array code:g_rgRedirectedTypes) + if (nRedirectedTypeIndex == RedirectedTypeIndex_Windows_UI_Xaml_Interop_TypeName || + nRedirectedTypeIndex == RedirectedTypeIndex_Windows_Foundation_HResult) + { + // TypeIdentifier and HResult are all value types in winmd and are mapped to reference + // types in CLR: Type, and Exception. + elementType = ELEMENT_TYPE_CLASS; + *pfChangedSig = TRUE; + } + } + // We do not want to return S_FALSE + hr = S_OK; + } + + pSigBuilder->AppendByte(elementType); + pSigBuilder->AppendToken(token); + + break; + } + + // Read a type + case ELEMENT_TYPE_SZARRAY: // SZARRAY + case ELEMENT_TYPE_PTR: // PTR + case ELEMENT_TYPE_BYREF: // BYREF + case ELEMENT_TYPE_SENTINEL: // sentinel for VARARGS ("..." in the parameter list), it behaves as prefix to next arg + { + pSigBuilder->AppendByte(elementType); + + IfFailGo(RewriteTypeInSignature(pSigParser, pSigBuilder, pfChangedSig)); + break; + } + + // Read a token then a type. That type could be another custom modifier. + case ELEMENT_TYPE_CMOD_REQD: // required C modifier : E_T_CMOD_REQD [followed by a type, or another custom modifier] + case ELEMENT_TYPE_CMOD_OPT: // optional C modifier : E_T_CMOD_OPT + { + pSigBuilder->AppendByte(elementType); + + mdToken token; + IfFailGo(pSigParser->GetToken(&token)); + pSigBuilder->AppendToken(token); + + // Process next type or custom modifier + IfFailGo(RewriteTypeInSignature(pSigParser, pSigBuilder, pfChangedSig)); + break; + } + + // Read a number + case ELEMENT_TYPE_VAR: // a class type variable VAR + case ELEMENT_TYPE_MVAR: // a method type variable MVAR + { + pSigBuilder->AppendByte(elementType); + + ULONG number; + IfFailGo(pSigParser->GetData(&number)); + pSigBuilder->AppendData(number); + break; + } + + case ELEMENT_TYPE_ARRAY: // MDARRAY ... ... + { + pSigBuilder->AppendByte(elementType); + + // Read array type + IfFailGo(RewriteTypeInSignature(pSigParser, pSigBuilder, pfChangedSig)); + + // Read rank + ULONG rank; + IfFailGo(pSigParser->GetData(&rank)); + pSigBuilder->AppendData(rank); + + // If rank is 0, then there's nothing else in the array signature + if (rank != 0) + { + // Read number of dimension sizes + ULONG cDimensionSizes; + IfFailGo(pSigParser->GetData(&cDimensionSizes)); + pSigBuilder->AppendData(cDimensionSizes); + + // Read all dimension sizes + for (ULONG i = 0; i < cDimensionSizes; i++) + { + ULONG dimensionSize; + IfFailGo(pSigParser->GetData(&dimensionSize)); + pSigBuilder->AppendData(dimensionSize); + } + + // Read number of lower bounds + ULONG cLowerBounds; + IfFailGo(pSigParser->GetData(&cLowerBounds)); + pSigBuilder->AppendData(cLowerBounds); + + // Read all lower bounds + for (ULONG i = 0; i < cLowerBounds; i++) + { + ULONG lowerBound; + IfFailGo(pSigParser->GetData(&lowerBound)); + pSigBuilder->AppendData(lowerBound); + } + } + break; + } + + case ELEMENT_TYPE_GENERICINST: // GENERICINST ... + { + pSigBuilder->AppendByte(elementType); + + // Read the generic type + IfFailGo(RewriteTypeInSignature(pSigParser, pSigBuilder, pfChangedSig)); + + // Read arg count + ULONG cGenericTypeArguments; + IfFailGo(pSigParser->GetData(&cGenericTypeArguments)); + pSigBuilder->AppendData(cGenericTypeArguments); + + // Read each type argument + for (ULONG i = 0; i < cGenericTypeArguments; i++) + { + IfFailGo(RewriteTypeInSignature(pSigParser, pSigBuilder, pfChangedSig)); + } + break; + } + + case ELEMENT_TYPE_FNPTR: // FNPTR + /* + // FNPTR is not supported in C#/VB, thefore this is not a main scenario. + // This implementation was late during .NET 4.5, but may be useful in future releases when we decide to support more languages for managed WinMD implementation. + { + pSigBuilder->AppendByte(elementType); + + // Read calling convention + DWORD callingConvention; + IfFailGo(pSigParser->GetData(&callingConvention)); + pSigBuilder->AppendData(callingConvention); + + // Read arg count + ULONG cArgs; + IfFailGo(pSigParser->GetData(&cArgs)); + pSigBuilder->AppendData(cArgs); + + // Read return argument + IfFailGo(RewriteTypeInSignature(pSigParser, pSigBuilder, pfChangedSig)); + + // Read each argument + for (ULONG i = 0; i < cArgs; i++) + { + IfFailGo(RewriteTypeInSignature(pSigParser, pSigBuilder, pfChangedSig)); + } + break; + } + */ + Debug_ReportError("ELEMENT_TYPE_FNPTR signature parsing in WinMD Adapter is NYI."); + IfFailGo(E_FAIL); + + case ELEMENT_TYPE_END: + case ELEMENT_TYPE_INTERNAL: // INTERNAL (Only in ngen images, but not reachable from MetaData - no sig rewriting) + case ELEMENT_TYPE_PINNED: // PINNED , used only in LocalSig (no sig rewriting) + Debug_ReportError("Unexpected CorElementType in a signature. Sig parsing failing."); + IfFailGo(E_FAIL); + + default: + Debug_ReportError("Unknown CorElementType."); + IfFailGo(E_FAIL); + } + _ASSERTE(hr == S_OK); + return hr; + +ErrExit: + Debug_ReportError("Sig parsing failed."); + return hr; +} // WinMDAdapter::RewriteTypeInSignature + +//------------------------------------------------------------------------------ + + + +//--------------------------------------------------------------------------------- +// Windows.Foundation.Metadata.AttributeTarget and System.AttributeTarget enum +// define different bits for everything (@todo: Be nice to change that before we ship.) +// Do the conversion here. +//--------------------------------------------------------------------------------- +static DWORD ConvertToClrAttributeTarget(DWORD winRTTarget) +{ + struct AttributeTargetsPair + { + DWORD WinRTValue; + DWORD ClrValue; + }; + + static const AttributeTargetsPair s_attributeTargetPairs[] = + { +#define DEFINE_PROJECTED_TYPE(a,b,c,d,e,f,g,h,i) +#define DEFINE_PROJECTED_ATTRIBUTETARGETS_VALUE(winrt, clr) { winrt, clr }, +#include "WinRTProjectedTypes.h" +#undef DEFINE_PROJECTED_ATTRIBUTETARGETS_VALUES +#undef DEFINE_PROJECTED_TYPE + }; + + if (winRTTarget == 0xffffffff /* Windows.Foundation.Metadata.AttributeTargets.All */) + return 0x00007fff; /* System.AttributeTargets.All */ + DWORD clrTarget = 0; + for (UINT i = 0; i < sizeof(s_attributeTargetPairs)/sizeof(*s_attributeTargetPairs); i++) + { + if (winRTTarget & s_attributeTargetPairs[i].WinRTValue) + { + clrTarget |= s_attributeTargetPairs[i].ClrValue; + } + } + return clrTarget; +} + + +//------------------------------------------------------------------------------ + + +// Search a typeDef for WF.AttributeUsageAttribute and WF.AllowMultipleAttribute, and compute +// +// *pClrTargetValue - the equivalent System.AttributeTargets enum value +// *pAllowMultiple - where multiple instances of the CA are allowed. +// +// Returns: +// S_OK: a WF.AttributeUsageAttribute CA exists (this is the one that we will rewrite) +// S_FALSE: no WF.AttributeUsageAttribute CA exists +// +HRESULT WinMDAdapter::TranslateWinMDAttributeUsageAttribute(mdTypeDef tkTypeDefOfCA, /*[out]*/ DWORD *pClrTargetValue, /*[out]*/ BOOL *pAllowMultiple) +{ + HRESULT hr; + _ASSERTE(TypeFromToken(tkTypeDefOfCA) == mdtTypeDef); + _ASSERTE(pClrTargetValue != NULL); + _ASSERTE(pAllowMultiple != NULL); + + const BYTE *pbWFUsageBlob; + ULONG cbWFUsageBlob; + IfFailGo(m_pRawMetaModelCommonRO->CommonGetCustomAttributeByName(tkTypeDefOfCA, "Windows.Foundation.Metadata.AttributeUsageAttribute", (const void **)&pbWFUsageBlob, &cbWFUsageBlob)); + if (hr == S_FALSE) + goto ErrExit; + // Expected blob format: + // 01 00 - Fixed prolog for CA's + // xx xx xx xx - The Windows.Foundation.Metadata.AttributeTarget value + // 00 00 - Indicates 0 name/value pairs following. + if (cbWFUsageBlob != 2 + sizeof(DWORD) + 2) + { + IfFailGo(COR_E_BADIMAGEFORMAT); + } + DWORD wfTargetValue = *(DWORD*)(pbWFUsageBlob + 2); + *pClrTargetValue = ConvertToClrAttributeTarget(wfTargetValue); + + // add AttributeTargets.Method, AttributeTargets.Constructor , AttributeTargets.Property, and AttributeTargets.Event if this is the VersionAttribute + LPCSTR szNamespace; + LPCSTR szName; + IfFailGo(m_pRawMetaModelCommonRO->CommonGetTypeDefProps(tkTypeDefOfCA, &szNamespace, &szName, NULL, NULL, NULL)); + + if ((strcmp(szName, "VersionAttribute") == 0 || strcmp(szName, "DeprecatedAttribute") == 0) && strcmp(szNamespace, "Windows.Foundation.Metadata") == 0) + { + *pClrTargetValue |= 0x2E0; + } + + const BYTE *pbWFAllowMultipleBlob; + ULONG cbWFAllowMultipleBlob; + IfFailGo(m_pRawMetaModelCommonRO->CommonGetCustomAttributeByName(tkTypeDefOfCA, "Windows.Foundation.Metadata.AllowMultipleAttribute", (const void **)&pbWFAllowMultipleBlob, &cbWFAllowMultipleBlob)); + *pAllowMultiple = (hr == S_OK); + hr = S_OK; + + ErrExit: + return hr; +} + +//------------------------------------------------------------------------------ + +/*static*/ HRESULT WinMDAdapter::CreateClrAttributeUsageAttributeCABlob(DWORD clrTargetValue, BOOL allowMultiple, CABlob **ppCABlob) +{ + // Emit the blob format corresponding to: + // [System.AttributeUsage(System.AttributeTargets.xx, AllowMultiple=yy)] + // + // 01 00 - Fixed prolog for CA's + // xx xx xx xx - The System.AttributeTarget value + // 01 00 - Indicates 1 name/value pair following. + // 54 - SERIALIZATION_TYPE_PROPERTY + // 02 - ELEMENT_TYPE_BOOLEAN + // 0d - strlen("AllowMultiple") - 1 + // 41 6c ... 65 - "A" "l" "l" "o" "w" "M" "u" "l" "t" "i" "p" "l" "e" + // yy - The boolean selection for "AllowMultiple" + + BYTE blob[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x54, 0x02, 0x0D, 0x41, 0x6C, 0x6C, 0x6F, 0x77, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x6C, 0x65, 0x00 }; + blob[sizeof(blob) - 1] = allowMultiple ? 1 : 0; + *((DWORD*)(blob+2)) = clrTargetValue; + CABlob *pCABlob; + IfNullRet(pCABlob = CABlob::Create(blob, sizeof(blob))); + *ppCABlob = pCABlob; + return S_OK; +} + + +//------------------------------------------------------------------------------ + +// Gets Guid from Windows.Foundation.Metadata.Guid +HRESULT WinMDAdapter::GetItemGuid(mdToken tkObj, CLSID *pGuid) +{ + HRESULT hr; + _ASSERTE(pGuid); + *pGuid = GUID_NULL; + const BYTE *pBlob; + ULONG cbBlob; + IfFailGo(m_pRawMetaModelCommonRO->CommonGetCustomAttributeByName(tkObj, "Windows.Foundation.Metadata.GuidAttribute", (const void**)&pBlob, &cbBlob)); + if (hr == S_OK) + { + if (cbBlob == 2 + sizeof(GUID) + 2) + { + memcpy(pGuid, pBlob + 2, sizeof(GUID)); + hr = S_OK; + goto ErrExit; + } + } + hr = S_FALSE; + ErrExit: + return hr; + +} + + +//------------------------------------------------------------------------------ + +//---------------------------------------------------------------------------- +// Gets filtered methodImpl list and adds it to an existing DynamicArray enum. +// +// This is used to hide implementations of methods on redirected interfaces after +// we've replaced them with their CLR counterparts in the interface implementation list. +// +// Each filtered methodImpl adds two elements to the enum: the body and decl values +// in that order. +//---------------------------------------------------------------------------- +HRESULT WinMDAdapter::AddMethodImplsToEnum(mdTypeDef tkTypeDef, HENUMInternal *henum) +{ + _ASSERTE(henum != NULL); + _ASSERTE(henum->m_EnumType == MDDynamicArrayEnum); + _ASSERTE(TypeFromToken(tkTypeDef) == mdtTypeDef); + + HRESULT hr; + + mdToken tkMethodImplFirst; + ULONG count; + IfFailGo(m_pRawMetaModelCommonRO->CommonGetMethodImpls(tkTypeDef, &tkMethodImplFirst, &count)); + for (ULONG i = 0; i < count; i++) + { + mdToken tkMethodImpl = tkMethodImplFirst + i; + mdToken tkBody, tkDecl; + IfFailGo(m_pRawMetaModelCommonRO->CommonGetMethodImplProps(tkMethodImpl, &tkBody, &tkDecl)); + UINT nIndex; + IfFailGo(CheckIfMethodImplImplementsARedirectedInterface(tkDecl, &nIndex)); + if (hr == S_FALSE || + (SUCCEEDED(hr) && nIndex == WinMDAdapter::RedirectedTypeIndex_Windows_Foundation_IClosable)) + { + // Keep MethodImpl for IClosable methods and non-redirected interfaces + IfFailGo(HENUMInternal::AddElementToEnum(henum, tkBody)); + IfFailGo(HENUMInternal::AddElementToEnum(henum, tkDecl)); + } + } + + hr = S_OK; + ErrExit: + return hr; +} + +//------------------------------------------------------------------------------ + +// S_OK if this is a CLR implementation type that was mangled and hidden by WinMDExp +// +// Logically, this function takes a mdTypeDef, but since the caller has already extracted the +// row data for other purposes, we'll take the row data. +HRESULT WinMDAdapter::CheckIfClrImplementationType(LPCSTR szName, DWORD dwAttr, LPCSTR *pszUnmangledName) +{ + if (m_scenario != kWinMDExp) + return S_FALSE; // Input file not produced by WinMDExp + if (IsTdNested(dwAttr)) + return S_FALSE; // Type is nested in another type + if ((dwAttr & (tdPublic|tdSpecialName)) != tdSpecialName) + return S_FALSE; // Type public or not SpecialName + if (0 != strncmp(szName, s_szCLRPrefix, s_ncCLRPrefix)) + return S_FALSE; // Name does not begin with "" + + // Ran out of reasons. + *pszUnmangledName = szName + s_ncCLRPrefix; + return S_OK; +} + + +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------------- +// Returns: S_OK if tkDecl of a methodImpl is a reference to a method on a redirected interface. +//------------------------------------------------------------------------------------- +HRESULT WinMDAdapter::CheckIfMethodImplImplementsARedirectedInterface(mdToken tkDecl, UINT *pIndex) +{ + + HRESULT hr; + if (TypeFromToken(tkDecl) != mdtMemberRef) + return S_FALSE; // REX will always use memberRef and typeRefs to refer to redirected interfaces, even if in same module. + + mdToken tkParent; + IfFailRet(m_pRawMetaModelCommonRO->CommonGetMemberRefProps(tkDecl, &tkParent)); + + mdTypeRef tkTypeRef; + if (TypeFromToken(tkParent) == mdtTypeRef) + { + tkTypeRef = tkParent; + } + else if (TypeFromToken(tkParent) == mdtTypeSpec) + { + PCCOR_SIGNATURE pvSig; + ULONG cbSig; + IfFailRet(m_pRawMetaModelCommonRO->CommonGetTypeSpecProps(tkParent, &pvSig, &cbSig)); + static const BYTE expectedSigStart[] = {ELEMENT_TYPE_GENERICINST, ELEMENT_TYPE_CLASS}; + if (cbSig < sizeof(expectedSigStart) + 1) + return S_FALSE; + if (0 != memcmp(pvSig, expectedSigStart, sizeof(expectedSigStart))) + return S_FALSE; + const BYTE *pCodedToken = pvSig + sizeof(expectedSigStart); + if (cbSig < sizeof(expectedSigStart) + CorSigUncompressedDataSize(pCodedToken)) + return S_FALSE; + mdToken genericType = CorSigUncompressToken(/*modifies*/pCodedToken); + if (TypeFromToken(genericType) != mdtTypeRef) + return S_FALSE; + tkTypeRef = genericType; + } + else + { + return S_FALSE; + } + + ULONG treatment; + IfFailRet(GetTypeRefTreatment(tkTypeRef, &treatment)); + if ((treatment & kTrClassMask) != kTrClassWellKnownRedirected) + return S_FALSE; + + if (pIndex) + *pIndex = (treatment & ~kTrClassMask); + + return S_OK; +} + +//----------------------------------------------------------------------------------------------------- + +/*static*/ HRESULT WinMDAdapter::CreatePrefixedName(LPCSTR szPrefix, LPCSTR szName, LPCSTR *ppOut) +{ + // This can cause allocations (thus entering the host) during a profiler stackwalk. + // But we're ok since we're not supporting SQL/F1 profiling with WinMDs. FUTURE: + // Would be nice to eliminate allocations on stack walks regardless. + PERMANENT_CONTRACT_VIOLATION(HostViolation, ReasonUnsupportedForSQLF1Profiling); + + size_t ncPrefix = strlen(szPrefix); + size_t ncName = strlen(szName); + if (ncPrefix + ncName < ncPrefix || ncPrefix + ncName + 1 < ncPrefix + ncName) + return E_OUTOFMEMORY; + LPSTR szResult = new (nothrow) char[ncPrefix + ncName + 1]; + IfNullRet(szResult); + memcpy(szResult, szPrefix, ncPrefix); + memcpy(szResult + ncPrefix, szName, ncName); + szResult[ncPrefix + ncName] = '\0'; + *ppOut = szResult; + return S_OK; +} + +//----------------------------------------------------------------------------------------------------- + +// Sentinel value in m_redirectedCABlobsMemoTable table. Means "do no blob rewriting. Return the one from the underlying importer." +/*static*/ WinMDAdapter::CABlob * const WinMDAdapter::CABlob::NOREDIRECT = ((WinMDAdapter::CABlob *)(0x1)); + +//----------------------------------------------------------------------------------------------------- + +/*static*/ WinMDAdapter::CABlob* WinMDAdapter::CABlob::Create(const BYTE *pBlob, ULONG cbBlob) +{ + // This can cause allocations (thus entering the host) during a profiler stackwalk. + // But we're ok since we're not supporting SQL/F1 profiling with WinMDs. FUTURE: + // Would be nice to eliminate allocations on stack walks regardless. + PERMANENT_CONTRACT_VIOLATION(HostViolation, ReasonUnsupportedForSQLF1Profiling); + + size_t cbAlloc = sizeof(CABlob) + cbBlob; // This overestimates the needed size a bit - no biggie + if (cbAlloc < sizeof(CABlob)) + return NULL; + + CABlob *pNewCABlob = (CABlob*)(new (nothrow) BYTE[cbAlloc]); + if (!pNewCABlob) + return NULL; + + pNewCABlob->cbBlob = cbBlob; + memcpy(pNewCABlob->data, pBlob, cbBlob); + return pNewCABlob; +} + +//----------------------------------------------------------------------------------------------------- + +/*static*/ void WinMDAdapter::CABlob::Destroy(WinMDAdapter::CABlob *pCABlob) +{ + if (pCABlob != CABlob::NOREDIRECT) + delete [] (BYTE*)pCABlob; +} + +//----------------------------------------------------------------------------------------------------- + +// Sentinel value in m_redirectedMethodSigMemoTable or m_redirectedFieldMemoTable. +// Means "do no signature rewriting. Return the one from the underlying importer." +/*static*/ WinMDAdapter::SigData * const WinMDAdapter::SigData::NOREDIRECT = ((WinMDAdapter::SigData *)(0x1)); + +//----------------------------------------------------------------------------------------------------- + +/*static*/ WinMDAdapter::SigData* WinMDAdapter::SigData::Create(ULONG cbSig, PCCOR_SIGNATURE pSig) +{ + // This can cause allocations (thus entering the host) during a profiler stackwalk. + // But we're ok since we're not supporting SQL/F1 profiling with WinMDs. FUTURE: + // Would be nice to eliminate allocations on stack walks regardless. + PERMANENT_CONTRACT_VIOLATION(HostViolation, ReasonUnsupportedForSQLF1Profiling); + + _ASSERTE(pSig != NULL); + size_t cbAlloc = sizeof(SigData) + cbSig; // This overestimates the needed size a bit - no biggie + if (cbAlloc < sizeof(SigData)) + return NULL; + + SigData *pNewSigData = (SigData*)(new (nothrow) BYTE[cbAlloc]); + if (!pNewSigData) + return NULL; + + pNewSigData->cbSig = cbSig; + memcpy(pNewSigData->data, pSig, cbSig); + return pNewSigData; +} + +//----------------------------------------------------------------------------------------------------- + +/*static*/ void WinMDAdapter::SigData::Destroy(WinMDAdapter::SigData *pSigData) +{ + if (pSigData != SigData::NOREDIRECT) + delete [] (BYTE*)pSigData; +} + +//----------------------------------------------------------------------------------------------------- + +//----------------------------------------------------------------------------------------------------- +// S_OK if pUnknown is really a WinMD wrapper. This is just a polite way of asking "is it bad to +// to static cast pUnknown to RegMeta/MDInternalRO." +//----------------------------------------------------------------------------------------------------- +HRESULT CheckIfImportingWinMD(IUnknown *pUnknown) +{ + IUnknown *pIgnore = NULL; + HRESULT hr = pUnknown->QueryInterface(IID_IWinMDImport, (void**)&pIgnore); + if (hr == S_OK) + { + pIgnore->Release(); + } + if (hr == E_NOINTERFACE) + { + hr = S_FALSE; + } + return hr; +} + + +//----------------------------------------------------------------------------------------------------- +// E_NOTIMPL if pUnknown is really a WinMD wrapper. +//----------------------------------------------------------------------------------------------------- +HRESULT VerifyNotWinMDHelper(IUnknown *pUnknown +#ifdef _DEBUG + ,LPCSTR assertMsg + ,LPCSTR file + ,int line +#endif //_DEBUG + ) +{ + HRESULT hr = CheckIfImportingWinMD(pUnknown); + if (FAILED(hr)) + return hr; + if (hr == S_FALSE) + { + return S_OK; + } +#ifdef _DEBUG +#ifndef DACCESS_COMPILE + if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_WinMD_AssertOnIllegalUsage)) + { + DbgAssertDialog(file, line, assertMsg); + } +#endif +#endif + return E_NOTIMPL; +} + + + -- cgit v1.2.3