diff options
Diffstat (limited to 'src/md/winmd')
26 files changed, 8086 insertions, 0 deletions
diff --git a/src/md/winmd/.gitmirror b/src/md/winmd/.gitmirror new file mode 100644 index 0000000000..f507630f94 --- /dev/null +++ b/src/md/winmd/.gitmirror @@ -0,0 +1 @@ +Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror.
\ No newline at end of file diff --git a/src/md/winmd/CMakeLists.txt b/src/md/winmd/CMakeLists.txt new file mode 100644 index 0000000000..9fb7d839ac --- /dev/null +++ b/src/md/winmd/CMakeLists.txt @@ -0,0 +1,18 @@ +set(MDWINMD_SOURCES + adapter.cpp + winmdimport.cpp + winmdinternalimportro.cpp +) + +convert_to_absolute_path(MDWINMD_SOURCES ${MDWINMD_SOURCES}) + +if(CLR_CMAKE_PLATFORM_UNIX) + add_compile_options(-fPIC) +endif(CLR_CMAKE_PLATFORM_UNIX) + +add_subdirectory(dac) +add_subdirectory(wks) +if(WIN32) + add_subdirectory(dbi) + add_subdirectory(crossgen) +endif(WIN32) diff --git a/src/md/winmd/WinMD.settings.targets b/src/md/winmd/WinMD.settings.targets new file mode 100644 index 0000000000..58fa8ee682 --- /dev/null +++ b/src/md/winmd/WinMD.settings.targets @@ -0,0 +1,49 @@ +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + + <!-- + We build MetaData in several flavors: + - Full version (wks) - part of clr.dll/coreclr.dll. + - dac version - does not need Emit APIs. + - Standalone versions for: + * mscordbi.dll (hands the interfaces over to debugger client (e.g. VS) - does not need Emit APIs. + * CorDbg - does not need Emit APIs. + * WinRT + - Read-Only version (ships in Windows) - does not need Emit and Internal APIs. + - Read-Writer version (ships as private component of MidlRt.exe SDK tool) - does not need Internal APIs. + --> + + <!--Import the settings--> + <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\src\MD\MD.props" /> + + <PropertyGroup> + <MDWinMDSrcDirectory>$(ClrSrcDirectory)\MD\WinMD\</MDWinMDSrcDirectory> + <UserIncludes> + $(UserIncludes); + $(ClrSrcDirectory)\MD\inc; + $(ClrSrcDirectory)\vm; + $(ClrSrcDirectory)\strongname\inc + </UserIncludes> + <ClAdditionalOptions>$(ClAdditionalOptions) -DUNICODE -D_UNICODE</ClAdditionalOptions> + <!--OK to delete NO_NTDLL for devdiv builds.--> + <OutputPath>$(ClrLibDest)</OutputPath> + <TargetType>LIBRARY</TargetType> + <PCHHeader>stdafx.h</PCHHeader> + <EnableCxxPCHHeaders>true</EnableCxxPCHHeaders> + <!--PCH: Both precompiled header and cpp are on the same ..\ path this is likely to be wrong.--> + <PCHCompile>$(MDWinMDSrcDirectory)\stdafx.cpp</PCHCompile> + <PCHObject>stdafx_winmd.obj</PCHObject> + <LinkUseCMT>false</LinkUseCMT> + </PropertyGroup> + + <ItemGroup> + <ProjectReference Include="$(ClrSrcDirectory)inc\corguids.nativeproj"> + <Comment>clrinternal.h</Comment> + </ProjectReference> + </ItemGroup> + + <ItemGroup> + <CppCompile Include="$(MDWinMDSrcDirectory)\Adapter.cpp" /> + <CppCompile Include="$(MDWinMDSrcDirectory)\WinMDImport.cpp" /> + <CppCompile Include="$(MDWinMDSrcDirectory)\WinMDInternalImportRO.cpp" /> + </ItemGroup> +</Project> diff --git a/src/md/winmd/adapter.cpp b/src/md/winmd/adapter.cpp new file mode 100644 index 0000000000..5b4d95cc7c --- /dev/null +++ b/src/md/winmd/adapter.cpp @@ -0,0 +1,2745 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more 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[] = "<WinRT>"; +//static const size_t s_ncWinRTPrefix = sizeof(s_szWinRTPrefix) - 1; + +static const char s_szCLRPrefix[] = "<CLR>"; +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)); + + // We check for legacy Core library name since Windows.winmd references mscorlib and not System.Private.CoreLib + if (0 == strcmp(arefName, LegacyCoreLibName_A)) + { + 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_extraAssemblyRefCount(-1) +{ + 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<RedirectedTypeIndex>(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 <CLR>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 <WinRT>Foo {} // the WinRT reference class that we want CLR consumers to ignore + // public class Foo {} // the implementation class + // + // We only add the <WinRT> 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 "<WinRT>" 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)) + { + // <CLR> 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 "<WinRT>" 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; +} + +//------------------------------------------------------------------------------ + +// We must optionaly add an assembly ref for System.Numerics.Vectors.dll since this assembly is not available +// on downlevel platforms. +// +// This function assumes that System.Numerics.Vectors.dll is the last assembly that +// we add so if we find a reference then we return ContractAssembly_Count otherwise we return +// ContractAssembly_Count - 1. +int WinMDAdapter::GetExtraAssemblyRefCount() +{ + HRESULT hr; + + if (m_extraAssemblyRefCount == -1) + { + mdAssemblyRef tkSystemNumericsVectors = TokenFromRid(m_rawAssemblyRefCount + ContractAssembly_SystemNumericsVectors + 1, mdtAssemblyRef); + ULONG cTypeRefRecs = m_pRawMetaModelCommonRO->CommonGetRowCount(mdtTypeRef); + BOOL systemNumericsVectorsTypeFound = FALSE; + + for (ULONG i = 1; i <= cTypeRefRecs; i++) + { + mdToken tkResolutionScope; + mdTypeRef tkTypeRef = TokenFromRid(i, mdtTypeRef); + + // Get the resolution scope(AssemblyRef) token for the type. GetTypeRefProps does the type redirection. + IfFailGo(GetTypeRefProps(tkTypeRef, nullptr, nullptr, &tkResolutionScope)); + + if (tkResolutionScope == tkSystemNumericsVectors) + { + systemNumericsVectorsTypeFound = TRUE; + break; + } + } + + if (systemNumericsVectorsTypeFound) + { + m_extraAssemblyRefCount = ContractAssembly_Count; + } + else + { + m_extraAssemblyRefCount = ContractAssembly_Count - 1; + } + } + +ErrExit: + if (m_extraAssemblyRefCount == -1) + { + // Setting m_extraAssemblyRefCount to ContractAssembly_Count so that this function returns a stable value and + // that if there is a System.Numerics type ref that it does not have a dangling assembly ref + m_extraAssemblyRefCount = ContractAssembly_Count; + } + + return m_extraAssemblyRefCount; +} + +//------------------------------------------------------------------------------ + +/*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_Mscorlib) + { + *ppPublicKeytoken = g_rbTheSilverlightPlatformKeyToken; + *pTokenLength = sizeof(g_rbTheSilverlightPlatformKeyToken); + } + else +#endif + { + if (index == FrameworkAssembly_SystemNumericsVectors || index == FrameworkAssembly_SystemRuntime || index == FrameworkAssembly_SystemObjectModel) + { + *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<SigData*, SigData::Destroy> &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<SigData*, SigData::Destroy> &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<T>] to ELEMENT_TYPE_VALUETYPE [Nullable<T>] +// 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<T> ---> E_T_VALUETYPE System.Nullable<T> +// E_T_CLASS Windows.Foundation.Collections.IKeyValuePair<U,V> ---> E_T_VALUETYPE System.Collections.Generic.KeyValuePair<U,V> +// 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 <type> + case ELEMENT_TYPE_PTR: // PTR <type> + case ELEMENT_TYPE_BYREF: // BYREF <type> + 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 <mdTypeRef/mdTypeDef> [followed by a type, or another custom modifier] + case ELEMENT_TYPE_CMOD_OPT: // optional C modifier : E_T_CMOD_OPT <mdTypeRef/mdTypeDef> + { + 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 <number> + case ELEMENT_TYPE_MVAR: // a method type variable MVAR <number> + { + pSigBuilder->AppendByte(elementType); + + ULONG number; + IfFailGo(pSigParser->GetData(&number)); + pSigBuilder->AppendData(number); + break; + } + + case ELEMENT_TYPE_ARRAY: // MDARRAY <type> <rank> <bcount> <bound1> ... <lbcount> <lb1> ... + { + 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 <generic type> <argCnt> <arg1> ... <argn> + { + 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 <complete sig for the function including calling convention> + /* + // 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 <typehandle> (Only in ngen images, but not reachable from MetaData - no sig rewriting) + case ELEMENT_TYPE_PINNED: // PINNED <type>, 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 "<CLR>" + + // 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; +} + + + diff --git a/src/md/winmd/crossgen/.gitmirror b/src/md/winmd/crossgen/.gitmirror new file mode 100644 index 0000000000..f507630f94 --- /dev/null +++ b/src/md/winmd/crossgen/.gitmirror @@ -0,0 +1 @@ +Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror.
\ No newline at end of file diff --git a/src/md/winmd/crossgen/CMakeLists.txt b/src/md/winmd/crossgen/CMakeLists.txt new file mode 100644 index 0000000000..30859c30ae --- /dev/null +++ b/src/md/winmd/crossgen/CMakeLists.txt @@ -0,0 +1,5 @@ +include(${CLR_DIR}/crossgen.cmake) +include(../../md_wks.cmake) + +add_precompiled_header(stdafx.h ../stdafx.cpp MDWINMD_SOURCES) +add_library_clr(mdwinmd_crossgen ${MDWINMD_SOURCES}) diff --git a/src/md/winmd/crossgen/MDWinMD_crossgen.nativeproj b/src/md/winmd/crossgen/MDWinMD_crossgen.nativeproj new file mode 100644 index 0000000000..88520924f6 --- /dev/null +++ b/src/md/winmd/crossgen/MDWinMD_crossgen.nativeproj @@ -0,0 +1,14 @@ +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood"> + <PropertyGroup> + <!-- All features are set in file:..\..\MD.props --> + <MetadataFlavor>wks</MetadataFlavor> + <OutputName>mdwinmd_crossgen</OutputName> + </PropertyGroup> + + <!--Import the settings--> + <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\xplat\SetCrossGen.props" /> + <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\src\MD\WinMD\WinMD.settings.targets" /> + + <!--Import the targets--> + <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" /> +</Project> diff --git a/src/md/winmd/dac/.gitmirror b/src/md/winmd/dac/.gitmirror new file mode 100644 index 0000000000..f507630f94 --- /dev/null +++ b/src/md/winmd/dac/.gitmirror @@ -0,0 +1 @@ +Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror.
\ No newline at end of file diff --git a/src/md/winmd/dac/CMakeLists.txt b/src/md/winmd/dac/CMakeLists.txt new file mode 100644 index 0000000000..aca5cb581d --- /dev/null +++ b/src/md/winmd/dac/CMakeLists.txt @@ -0,0 +1,6 @@ + +include(${CLR_DIR}/dac.cmake) +include(../../md_dbi.cmake) + +add_precompiled_header(stdafx.h ../stdafx.cpp MDWINMD_SOURCES) +add_library_clr(mdwinmd_dac ${MDWINMD_SOURCES}) diff --git a/src/md/winmd/dac/dirs.proj b/src/md/winmd/dac/dirs.proj new file mode 100644 index 0000000000..c73e2390db --- /dev/null +++ b/src/md/winmd/dac/dirs.proj @@ -0,0 +1,19 @@ +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <!--Import the settings--> + <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" /> + + <PropertyGroup> + <BuildInPhase1>true</BuildInPhase1> + <BuildInPhaseDefault>false</BuildInPhaseDefault> + <BuildCoreBinaries>true</BuildCoreBinaries> + <BuildSysBinaries>true</BuildSysBinaries> + </PropertyGroup> + + <!--The following projects will build during PHASE 1--> + <ItemGroup Condition="'$(BuildExePhase)' == '1'"> + <ProjectFile Include="HostLocal\mdwinmd_dac.nativeproj" /> + </ItemGroup> + + <!--Import the targets--> + <Import Project="$(_NTDRIVE)$(_NTROOT)\tools\Microsoft.DevDiv.Traversal.targets" /> +</Project> diff --git a/src/md/winmd/dbi/.gitmirror b/src/md/winmd/dbi/.gitmirror new file mode 100644 index 0000000000..f507630f94 --- /dev/null +++ b/src/md/winmd/dbi/.gitmirror @@ -0,0 +1 @@ +Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror.
\ No newline at end of file diff --git a/src/md/winmd/dbi/CMakeLists.txt b/src/md/winmd/dbi/CMakeLists.txt new file mode 100644 index 0000000000..89a39d3d9b --- /dev/null +++ b/src/md/winmd/dbi/CMakeLists.txt @@ -0,0 +1,4 @@ +include(../../md_dbi.cmake) + +add_precompiled_header(stdafx.h ../stdafx.cpp MDWINMD_SOURCES) +add_library_clr(mdwinmd_dbi ${MDWINMD_SOURCES})
\ No newline at end of file diff --git a/src/md/winmd/dbi/MDWinMD-dbi.props b/src/md/winmd/dbi/MDWinMD-dbi.props new file mode 100644 index 0000000000..829e1d7c6d --- /dev/null +++ b/src/md/winmd/dbi/MDWinMD-dbi.props @@ -0,0 +1,9 @@ +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood"> + <PropertyGroup> + <!-- All features are set in file:..\..\MD.props --> + <MetadataFlavor>mscordbi</MetadataFlavor> + </PropertyGroup> + + <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\src\MD\WinMD\WinMD.settings.targets" /> + +</Project> diff --git a/src/md/winmd/dbi/MDWinMD_dbi.nativeproj b/src/md/winmd/dbi/MDWinMD_dbi.nativeproj new file mode 100644 index 0000000000..3223689415 --- /dev/null +++ b/src/md/winmd/dbi/MDWinMD_dbi.nativeproj @@ -0,0 +1,17 @@ +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood"> + <PropertyGroup> + <!-- All features are set in file:..\..\MD.props --> + <MetadataFlavor>mscordbi</MetadataFlavor> + </PropertyGroup> + + <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\src\MD\WinMD\WinMD.settings.targets" /> + + <PropertyGroup> + <BuildCoreBinaries>true</BuildCoreBinaries> + <BuildSysBinaries>true</BuildSysBinaries> + <OutputName>MDWinMD_dbi</OutputName> + </PropertyGroup> + + <!--Import the targets--> + <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" /> +</Project> diff --git a/src/md/winmd/dbi/dirs.proj b/src/md/winmd/dbi/dirs.proj new file mode 100644 index 0000000000..88863b561f --- /dev/null +++ b/src/md/winmd/dbi/dirs.proj @@ -0,0 +1,19 @@ +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <!--Import the settings--> + <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" /> + + <PropertyGroup> + <BuildInPhase1>true</BuildInPhase1> + <BuildInPhaseDefault>false</BuildInPhaseDefault> + <BuildCoreBinaries>true</BuildCoreBinaries> + <BuildSysBinaries>true</BuildSysBinaries> + </PropertyGroup> + + <!--The following projects will build during PHASE 1--> + <ItemGroup Condition="'$(BuildExePhase)' == '1'"> + <ProjectFile Condition="'$(FeatureDbiDebugging)'=='true'" Include="HostLocal\MDWinMD-dbi.nativeproj" /> + </ItemGroup> + + <!--Import the targets--> + <Import Project="$(_NTDRIVE)$(_NTROOT)\tools\Microsoft.DevDiv.Traversal.targets" /> +</Project> diff --git a/src/md/winmd/dirs.proj b/src/md/winmd/dirs.proj new file mode 100644 index 0000000000..7788116cc7 --- /dev/null +++ b/src/md/winmd/dirs.proj @@ -0,0 +1,21 @@ +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <!--Import the settings--> + <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" /> + + <PropertyGroup> + <BuildInPhase1>true</BuildInPhase1> + <BuildInPhaseDefault>false</BuildInPhaseDefault> + <BuildCoreBinaries>true</BuildCoreBinaries> + <BuildSysBinaries>true</BuildSysBinaries> + </PropertyGroup> + + <!--The following projects will build during PHASE 1--> + <ItemGroup Condition="'$(BuildExePhase)' == '1'"> + <ProjectFile Include="wks\mdwinmd_wks.nativeproj" /> + <ProjectFile Include="dbi\dirs.proj" /> + <ProjectFile Include="dac\dirs.proj" /> + </ItemGroup> + + <!--Import the targets--> + <Import Project="$(_NTDRIVE)$(_NTROOT)\tools\Microsoft.DevDiv.Traversal.targets" /> +</Project> diff --git a/src/md/winmd/inc/.gitmirror b/src/md/winmd/inc/.gitmirror new file mode 100644 index 0000000000..f507630f94 --- /dev/null +++ b/src/md/winmd/inc/.gitmirror @@ -0,0 +1 @@ +Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror.
\ No newline at end of file diff --git a/src/md/winmd/inc/adapter.h b/src/md/winmd/inc/adapter.h new file mode 100644 index 0000000000..e69b620938 --- /dev/null +++ b/src/md/winmd/inc/adapter.h @@ -0,0 +1,951 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +#ifndef __MDWinMDAdapter__h__ +#define __MDWinMDAdapter__h__ + +#include "memotable.h" +#include "../../inc/winmdinterfaces.h" +#include "thekey.h" +#include "ecmakey.h" + +// Instantiation of template in holder.h +template void DoNothing<ULONG>(ULONG); + +class SigBuilder; +class SigParser; + +typedef const BYTE * PCBYTE; +static const BYTE s_pbContractPublicKeyToken[] = {0xB0,0x3F,0x5F,0x7F,0x11,0xD5,0x0A,0x3A}; +static const BYTE s_pbContractPublicKey[] = {0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x06, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x52, 0x53, 0x41, 0x31, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x07, 0xD1, 0xFA, 0x57, 0xC4, 0xAE, 0xD9, 0xF0, 0xA3, 0x2E, 0x84, 0xAA, 0x0F, 0xAE, 0xFD, 0x0D, 0xE9, 0xE8, 0xFD, 0x6A, 0xEC, 0x8F, 0x87, 0xFB, 0x03, 0x76, 0x6C, 0x83, 0x4C, 0x99, 0x92, 0x1E, 0xB2, 0x3B, 0xE7, 0x9A, 0xD9, 0xD5, 0xDC, 0xC1, 0xDD, 0x9A, 0xD2, 0x36, 0x13, 0x21, 0x02, 0x90, 0x0B, 0x72, 0x3C, 0xF9, 0x80, 0x95, 0x7F, 0xC4, 0xE1, 0x77, 0x10, 0x8F, 0xC6, 0x07, 0x77, 0x4F, 0x29, 0xE8, 0x32, 0x0E, 0x92, 0xEA, 0x05, 0xEC, 0xE4, 0xE8, 0x21, 0xC0, 0xA5, 0xEF, 0xE8, 0xF1, 0x64, 0x5C, 0x4C, 0x0C, 0x93, 0xC1, 0xAB, 0x99, 0x28, 0x5D, 0x62, 0x2C, 0xAA, 0x65, 0x2C, 0x1D, 0xFA, 0xD6, 0x3D, 0x74, 0x5D, 0x6F, 0x2D, 0xE5, 0xF1, 0x7E, 0x5E, 0xAF, 0x0F, 0xC4, 0x96, 0x3D, 0x26, 0x1C, 0x8A, 0x12, 0x43, 0x65, 0x18, 0x20, 0x6D, 0xC0, 0x93, 0x34, 0x4D, 0x5A, 0xD2, 0x93}; + +class DECLSPEC_UUID("996AA908-5606-476d-9985-48607B2DA076") IWinMDImport : public IUnknown +{ +public : + STDMETHOD(IsScenarioWinMDExp)(BOOL *pbResult) = 0; + STDMETHOD(IsRuntimeClassImplementation)(mdTypeDef tkTypeDef, BOOL *pbResult) = 0; +}; + +//======================================================================================== +// Only IWinMDImport and IWinMDImportInternalRO QI successfully for this guid - for cases where we need to +// tell the difference between the classic MD importers and the WinMD wrappers. +//======================================================================================== +// {996AA908-5606-476d-9985-48607B2DA076} +extern const IID DECLSPEC_SELECTANY IID_IWinMDImport = __uuidof(IWinMDImport); + +//======================================================================================== +// Popup an assert box if COMPLUS_MD_WinMD_AssertOnIllegalUsage=1 +//======================================================================================== +#if defined(_DEBUG) && !defined(DACCESS_COMPILE) +#define WINMD_COMPAT_ASSERT(assertMsg) if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_WinMD_AssertOnIllegalUsage)) DbgAssertDialog(__FILE__, __LINE__, assertMsg) +#else +#define WINMD_COMPAT_ASSERT(assertMsg) +#endif + + +//======================================================================================== +// class WinMDAdapter +// +// This object performs typeref redirection and any other chores involved in +// masquerading WinMD files as .NET assemblies. +// +// WinMDAdapters act as internal helper objects to WinMDImport and WinMDInternalImportRO +// and factor out as much common code as is practical given that these two importers +// expose wildly different interfaces. +// +// The main input to this object is a standard .NET metadata importer (the "raw" importer.) Since +// the two importers have no common public interface, we use the internal (non-COM) IMetaModelCommon +// interface that both imports have internally and expose through the private IMDCommon +// interface. +// +// Methods on this class follow the IMDInternalImport philosophy (i.e. validation? what validation?, +// return strings as direct UTF8 pointers to internal strings allocated for the lifetime +// of WinMDAdapter.) When used by the public IMetaDataImport adapter, it's important that the caller +// validate parameters before invoking WinMDAdapter. +//======================================================================================== +class WinMDAdapter +{ +public: +#define DEFINE_PROJECTED_TYPE(szWinRTNS, szWinRTName, szClrNS, szClrName, ClrAsmIdx, nContractAsmIdx, WinRTIndex, ClrIndex, TypeKind) \ + RedirectedTypeIndex_ ## WinRTIndex, \ + RedirectedTypeIndex_ ## ClrIndex = RedirectedTypeIndex_ ## WinRTIndex, \ + + // Indexes of well-known redirected types into array code:g_rgRedirectedTypes + enum RedirectedTypeIndex + { +#include "WinRTProjectedTypes.h" + RedirectedTypeIndex_Count, + RedirectedTypeIndex_Invalid = -1, + }; +#undef DEFINE_PROJECTED_TYPE + + enum FrameworkAssemblyIndex + { + FrameworkAssembly_Mscorlib, + FrameworkAssembly_SystemObjectModel, + FrameworkAssembly_SystemRuntime, + FrameworkAssembly_SystemRuntimeWindowsRuntime, + FrameworkAssembly_SystemRuntimeWindowsRuntimeUIXaml, + FrameworkAssembly_SystemNumericsVectors, + + FrameworkAssembly_Count, + }; + + // If new contract assemblies need to be added, they must be appended to the end of the following list. + // Also, don't remove or change any existing assemblies in this list. + // Not following these rules will break existing MDIL images generated in the Store. + enum ContractAssemblyIndex + { + ContractAssembly_SystemRuntime, + ContractAssembly_SystemRuntimeInteropServicesWindowsRuntime, + ContractAssembly_SystemObjectModel, + ContractAssembly_SystemRuntimeWindowsRuntime, + ContractAssembly_SystemRuntimeWindowsRuntimeUIXaml, + ContractAssembly_SystemNumericsVectors, // GetExtraAssemblyRefCount assumes SystemNumericsVectors is the last assembly. + // If you add an assembly you must update GetActualExtraAssemblyRefCount. + + ContractAssembly_Count, + }; + + + enum WinMDTypeKind + { + WinMDTypeKind_Attribute, + WinMDTypeKind_Enum, + WinMDTypeKind_Delegate, + WinMDTypeKind_Interface, + WinMDTypeKind_PDelegate, + WinMDTypeKind_PInterface, + WinMDTypeKind_Struct, + WinMDTypeKind_Runtimeclass, + }; + + int GetExtraAssemblyRefCount(); + + // Factory and destructor + static HRESULT Create(IMDCommon *pRawMDCommon, /*[out]*/ WinMDAdapter **ppAdapter); + ~WinMDAdapter(); + + // Map a well-known WinRT typename to CLR typename + static BOOL ConvertWellKnownTypeNameFromWinRTToClr(LPCSTR *pszNamespace, LPCSTR *pszName); + + // Map a well-known WinRT full typename to CLR full typename + static BOOL ConvertWellKnownFullTypeNameFromWinRTToClr(LPCWSTR *pszFullName, RedirectedTypeIndex *pIndex); + + // Map a well-known CLR typename to WinRT typename + static BOOL ConvertWellKnownTypeNameFromClrToWinRT(LPCSTR *pszFullName); + + // Map a well-known CLR typename to WinRT typename + static BOOL WinMDAdapter::ConvertWellKnownTypeNameFromClrToWinRT(LPCSTR *pszNamespace, LPCSTR *pszName); + + // Returns names of redirected type 'index'. + static void GetRedirectedTypeInfo( + RedirectedTypeIndex index, + LPCSTR * pszClrNamespace, + LPCSTR * pszClrName, + LPCSTR * pszFullWinRTName, + FrameworkAssemblyIndex * pFrameworkAssemblyIdx, + ContractAssemblyIndex * pContractAssemblyIdx, + WinMDTypeKind * pWinMDTypeKind); + + // Returns name of redirected type 'index'. + static LPCWSTR GetRedirectedTypeFullWinRTName(RedirectedTypeIndex index); + static LPCSTR GetRedirectedTypeFullCLRName(RedirectedTypeIndex index); + + // Returns renamed typedefs + HRESULT GetTypeDefProps( + mdTypeDef typeDef, // [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. + ); + + // Find TypeDef by name + HRESULT 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 + ); + + // Returns redirected typerefs + HRESULT GetTypeRefProps( + mdTypeRef typeref, // [IN] given typeref + LPCSTR *psznamespace, // [OUT] return typeref namespace + LPCSTR *pszname, // [OUT] return typeref name + mdToken *ptkResolutionScope // [OUT] return typeref resolutionscope + ); + + // Find TypeRef by name + HRESULT FindTypeRef( + LPCSTR szNamespace, // [IN] Namespace for the TypeRef (NULL for standalone names) + LPCSTR szName, // [IN] Name of the TypeRef. + mdToken tkResolutionScope, // [IN] Resolution Scope fo the TypeRef. + mdTypeRef *ptk // [OUT] TypeRef token returned. + ); + + // Modify an ExportedType name + HRESULT ModifyExportedTypeName( + mdExportedType tkExportedType, // [IN] exportedType token + LPCSTR *pszNamespace, // [IN,OUT,OPTIONAL] namespace to modify + LPCSTR *pszName // [IN,OUT,OPTIONAL] name to modify + ); + + // Find ExportedType by name + HRESULT FindExportedType( + LPCUTF8 szNamespace, // [IN] expected namespace + LPCUTF8 szName, // [IN] expected name + mdToken tkEnclosingType, // [IN] expected tkEnclosingType + mdExportedType *ptkExportedType // [OUT] ExportedType token returned. + ); + + // Returns rewritten metadata version string + HRESULT GetVersionString( + LPCSTR *pszVersion // [OUT] return metadata version string + ) + { + _ASSERTE(pszVersion != NULL); + *pszVersion = m_pRedirectedVersionString; + return S_OK; + } + + void ModifyAssemblyRefProps( + mdAssemblyRef mdar, + const void **ppbPublicKeyOrToken, + ULONG *pcbPublicKeyOrToken, + LPCSTR *pszName, + USHORT *pusMajorVersion, + USHORT *pusMinorVersion, + USHORT *pusBuildNumber, + USHORT *pusRevisionNumber, + const void **ppbHashValue, + ULONG *pcbHashValue) + { + _ASSERTE(TypeFromToken(mdar) == mdtAssemblyRef); + + // The version of the mscorlib should be 4.0.0.0 + if (m_assemblyRefMscorlib == mdar) + { + if (pusMajorVersion != nullptr) + *pusMajorVersion = VER_ASSEMBLYMAJORVERSION; + if (pusMinorVersion != nullptr) + *pusMinorVersion = VER_ASSEMBLYMINORVERSION; + if (pusBuildNumber != nullptr) + *pusBuildNumber = VER_ASSEMBLYBUILD; + if (pusRevisionNumber != nullptr) + *pusRevisionNumber = VER_ASSEMBLYBUILD_QFE; + +#ifdef FEATURE_CORECLR + // Under CoreCLR, we replace the ECMA key in the mscorlib assembly ref with the CoreCLR platform public key token + if (ppbPublicKeyOrToken != nullptr) + { + *ppbPublicKeyOrToken = g_rbTheSilverlightPlatformKeyToken; + *pcbPublicKeyOrToken = _countof(g_rbTheSilverlightPlatformKeyToken); + } +#endif + } + else if (RidFromToken(mdar) > m_rawAssemblyRefCount) + { + // This is one of the assemblies that we inject + UINT index = RidFromToken(mdar) - m_rawAssemblyRefCount - 1; + + if (ppbPublicKeyOrToken != nullptr) + { + if (index != ContractAssemblyIndex::ContractAssembly_SystemRuntimeWindowsRuntime && + index != ContractAssemblyIndex::ContractAssembly_SystemRuntimeWindowsRuntimeUIXaml) + { + // The assembly ref is a contract/facade assembly. System.Runtime.WindowsRuntime and + // System.Runtime.WindowsRuntime.UI.Xaml are special cased because the contract and the implementation + // assembly share the same identity and use mscorlib's public key/token that ppbPublicKeyOrToken + // alredy contains since the raw GetAssemblyRefProps was called with mscorlib's token before this + // function was called. + if (*pcbPublicKeyOrToken == sizeof(s_pbContractPublicKeyToken)) + *ppbPublicKeyOrToken = s_pbContractPublicKeyToken; + else if (*pcbPublicKeyOrToken == sizeof(s_pbContractPublicKey)) + *ppbPublicKeyOrToken = s_pbContractPublicKey; + } +#ifdef FEATURE_WINDOWSPHONE + // System.Runtime.WindowsRuntime uses the ECMA key on Windows Phone. + // The WinRT adapter's policy of using mscorlib's assembly references for all the additional + // assembly references doesn't work here since mscorlib uses the Silverlight Platform key. + else + { + if (*pcbPublicKeyOrToken == sizeof(g_rbNeutralPublicKeyToken)) + *ppbPublicKeyOrToken = g_rbNeutralPublicKeyToken; + else if (*pcbPublicKeyOrToken == sizeof(g_rbNeutralPublicKey)) + *ppbPublicKeyOrToken = g_rbNeutralPublicKey; + } +#endif + } + + if (pszName != nullptr) + *pszName = GetExtraAssemblyRefName(mdar); + + if (pusMajorVersion != nullptr) + *pusMajorVersion = VER_ASSEMBLYMAJORVERSION; + if (pusMinorVersion != nullptr) + *pusMinorVersion = VER_ASSEMBLYMINORVERSION; + if (pusBuildNumber != nullptr) + *pusBuildNumber = VER_ASSEMBLYBUILD; + if (pusRevisionNumber != nullptr) + *pusRevisionNumber = VER_ASSEMBLYBUILD_QFE; + + if (ppbHashValue) + *ppbHashValue = NULL; + + if (pcbHashValue) + *pcbHashValue = 0; + } + } + + // Modifes the FieldDefProps. + HRESULT ModifyFieldDefProps (mdFieldDef tkFielddDef, DWORD *pdwFlags); + + // Modifies FieldProps + HRESULT ModifyFieldProps (mdToken tkField, mdToken tkParent, LPCSTR szFieldName, DWORD *pdwFlags); + + // Modifies methodDef flags and RVA + HRESULT ModifyMethodProps(mdMethodDef tkMethodDef, /*[in, out]*/ DWORD *pdwAttr, /* [in,out] */ DWORD *pdwImplFlags, /* [in,out] */ ULONG *pulRVA, LPCSTR *pszName); + + // Modifies member flags and RVA + HRESULT ModifyMemberProps(mdToken tkMember, /*[in, out]*/ DWORD *pdwAttr, /* [in,out] */ DWORD *pdwImplFlags, /* [in,out] */ ULONG *pulRVA, LPCSTR *pszNewName); + + // Modifies CA's + HRESULT 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. + + // Modify CA blobs + HRESULT GetCustomAttributeBlob( + mdCustomAttribute tkCA, + const void **ppData, // [OUT] Put pointer to data here. + ULONG *pcbData); // [OUT] Put size of data here. + + // Gets the GUID used for COM interop purposes. + HRESULT GetItemGuid(mdToken tkObj, CLSID *pGuid); + + // Gets filtered methodImpl list + HRESULT AddMethodImplsToEnum(mdTypeDef tkTypeDef, HENUMInternal *henum); + + //----------------------------------------------------------------------------------- + // For each token, we cache the signature that the adapter reports to callers. + //----------------------------------------------------------------------------------- + struct SigData + { + ULONG cbSig; // Length of sig in bytes + BYTE data[1]; // Signature + + static SigData* Create(ULONG cbSig, PCCOR_SIGNATURE pSig); + static void Destroy(SigData *pSigData); + + // Sentinel value meaning we did not need to rewrite the signature; use the underlying importer's signature + static SigData* const NOREDIRECT; + }; + + // Gets a method/field/TypeSpec/MethodSpec signature, with appropriate WinMD changes. + HRESULT ReinterpretMethodSignature (ULONG cbOrigSigBlob, PCCOR_SIGNATURE pOrigSig, SigData **ppSigData); + HRESULT ReinterpretFieldSignature (ULONG cbOrigSigBlob, PCCOR_SIGNATURE pOrigSig, SigData **ppSigData); + HRESULT ReinterpretTypeSpecSignature (ULONG cbOrigSigBlob, PCCOR_SIGNATURE pOrigSig, SigData **ppSigData); + HRESULT ReinterpretMethodSpecSignature (ULONG cbOrigSigBlob, PCCOR_SIGNATURE pOrigSig, SigData **ppSigData); + + template<mdToken TOKENTYPE> + HRESULT ReinterpretSignature( + ULONG cbOrigSigBlob, // [IN] count of bytes in original signature blob + PCCOR_SIGNATURE pOrigSig, // [IN] original signature + SigData **ppSigData // [OUT] new signature or SigData::NOREDIRECT + ) + { + UNREACHABLE_MSG("You should create a specialized version of ReinterpretSignature for this token type"); + } + + // Explicit specializations of ReinterpretSignature for all supported token types + template<> // mdMethodDef + HRESULT ReinterpretSignature<mdtMethodDef>(ULONG cbOrigSigBlob, PCCOR_SIGNATURE pOrigSig, SigData **ppSigData) + { + return ReinterpretMethodSignature(cbOrigSigBlob, pOrigSig, ppSigData); + } + + template<> // mdFieldDef + HRESULT ReinterpretSignature<mdtFieldDef>(ULONG cbOrigSigBlob, PCCOR_SIGNATURE pOrigSig, SigData **ppSigData) + { + return ReinterpretFieldSignature(cbOrigSigBlob, pOrigSig, ppSigData); + } + + template<> // mdMemberRef + HRESULT ReinterpretSignature<mdtMemberRef>(ULONG cbOrigSigBlob, PCCOR_SIGNATURE pOrigSig, SigData **ppSigData) + { + if (cbOrigSigBlob == 0) + { + *ppSigData = SigData::NOREDIRECT; + + return META_E_BAD_SIGNATURE; + } + + // MemberRef references either a field or a method + return (*pOrigSig == IMAGE_CEE_CS_CALLCONV_FIELD) ? + ReinterpretFieldSignature(cbOrigSigBlob, pOrigSig, ppSigData) : + ReinterpretMethodSignature(cbOrigSigBlob, pOrigSig, ppSigData); + } + + template<> // mdProperty + HRESULT ReinterpretSignature<mdtProperty>(ULONG cbOrigSigBlob, PCCOR_SIGNATURE pOrigSig, SigData **ppSigData) + { + // Per ECMA CLI spec, section 23.2.5 PropertySig is just an ordinary method (getter) signature + return ReinterpretMethodSignature(cbOrigSigBlob, pOrigSig, ppSigData); + } + + template<> // mdTypeSpec + HRESULT ReinterpretSignature<mdtTypeSpec>(ULONG cbOrigSigBlob, PCCOR_SIGNATURE pOrigSig, SigData **ppSigData) + { + return ReinterpretTypeSpecSignature(cbOrigSigBlob, pOrigSig, ppSigData); + } + + template<> // mdMethodSpec + HRESULT ReinterpretSignature<mdtMethodSpec>(ULONG cbOrigSigBlob, PCCOR_SIGNATURE pOrigSig, SigData **ppSigData) + { + return ReinterpretMethodSpecSignature(cbOrigSigBlob, pOrigSig, ppSigData); + } + + // 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. + static HRESULT GetCachedSigForToken( + mdToken token, // [IN] given token + MemoTable<SigData*, SigData::Destroy> &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? + ); + + static HRESULT InsertCachedSigForToken( + mdToken token, // [IN] given token + MemoTable<SigData*, SigData::Destroy> &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 + + template<typename T, mdToken TOKENTYPE> + HRESULT GetOriginalSigForToken( + T *pImport, + mdToken token, // [IN] Token. + PCCOR_SIGNATURE *ppvSig, // [OUT] return pointer to signature. + ULONG *pcbSig // [OUT] return size of signature. + ) + { + UNREACHABLE_MSG("You should create a specialized version of GetOriginalSigForToken for this interface/token type"); + } + + template<mdToken TOKENTYPE> + MemoTable<SigData*, SigData::Destroy> &GetSignatureMemoTable() + { + UNREACHABLE_MSG("You should create a specialized version of GetSignatureMemoTable for this token type"); + } + + // Explicit specializations of GetOriginalSigForToken for all supported token types (IMetaDataImport2) + template<> // mdMethodDef + HRESULT GetOriginalSigForToken<IMetaDataImport2, mdtMethodDef>(IMetaDataImport2 *pImport, mdMethodDef tk, PCCOR_SIGNATURE *ppvSig, ULONG *pcbSig) + { + return pImport->GetMethodProps(tk, NULL, NULL, 0, NULL, NULL, ppvSig, pcbSig, NULL, NULL); + } + + template<> // mdFieldDef + HRESULT GetOriginalSigForToken<IMetaDataImport2, mdtFieldDef>(IMetaDataImport2 *pImport, mdFieldDef tk, PCCOR_SIGNATURE *ppvSig, ULONG *pcbSig) + { + return pImport->GetFieldProps(tk, NULL, NULL, 0, NULL, NULL, ppvSig, pcbSig, NULL, NULL, NULL); + } + + template<> // mdMemberRef + HRESULT GetOriginalSigForToken<IMetaDataImport2, mdtMemberRef>(IMetaDataImport2 *pImport, mdMemberRef tk, PCCOR_SIGNATURE *ppvSig, ULONG *pcbSig) + { + return pImport->GetMemberRefProps(tk, NULL, NULL, 0, NULL, ppvSig, pcbSig); + } + + template<> // mdProperty + HRESULT GetOriginalSigForToken<IMetaDataImport2, mdtProperty>(IMetaDataImport2 *pImport, mdProperty tk, PCCOR_SIGNATURE *ppvSig, ULONG *pcbSig) + { + return pImport->GetPropertyProps(tk, NULL, NULL, 0, NULL, NULL, ppvSig, pcbSig, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL); + } + + template<> // mdTypeSpec + HRESULT GetOriginalSigForToken<IMetaDataImport2, mdtTypeSpec>(IMetaDataImport2 *pImport, mdTypeSpec tk, PCCOR_SIGNATURE *ppvSig, ULONG *pcbSig) + { + return pImport->GetTypeSpecFromToken(tk, ppvSig, pcbSig); + } + + template<> // mdMethodSpec + HRESULT GetOriginalSigForToken<IMetaDataImport2, mdtMethodSpec>(IMetaDataImport2 *pImport, mdMethodSpec tk, PCCOR_SIGNATURE *ppvSig, ULONG *pcbSig) + { + return pImport->GetMethodSpecProps(tk, NULL, ppvSig, pcbSig); + } + + // Explicit specializations of GetOriginalSigForToken for all supported token types (IMDInternalImport) + template<> // mdMethodDef + HRESULT GetOriginalSigForToken<IMDInternalImport, mdtMethodDef>(IMDInternalImport *pImport, mdMethodDef tk, PCCOR_SIGNATURE *ppvSig, ULONG *pcbSig) + { + return pImport->GetSigOfMethodDef(tk, pcbSig, ppvSig); + } + + template<> // mdFieldDef + HRESULT GetOriginalSigForToken<IMDInternalImport, mdtFieldDef>(IMDInternalImport *pImport, mdFieldDef tk, PCCOR_SIGNATURE *ppvSig, ULONG *pcbSig) + { + return pImport->GetSigOfFieldDef(tk, pcbSig, ppvSig); + } + + template<> // mdMemberRef + HRESULT GetOriginalSigForToken<IMDInternalImport, mdtMemberRef>(IMDInternalImport *pImport, mdMemberRef tk, PCCOR_SIGNATURE *ppvSig, ULONG *pcbSig) + { + LPCSTR szMemberRefName; + return pImport->GetNameAndSigOfMemberRef(tk, ppvSig, pcbSig, &szMemberRefName); + } + + template<> // mdProperty + HRESULT GetOriginalSigForToken<IMDInternalImport, mdtProperty>(IMDInternalImport *pImport, mdProperty tk, PCCOR_SIGNATURE *ppvSig, ULONG *pcbSig) + { + return pImport->GetPropertyProps(tk, NULL, NULL, ppvSig, pcbSig); + } + + template<> // mdTypeSpec + HRESULT GetOriginalSigForToken<IMDInternalImport, mdtTypeSpec>(IMDInternalImport *pImport, mdTypeSpec tk, PCCOR_SIGNATURE *ppvSig, ULONG *pcbSig) + { + return pImport->GetSigFromToken(tk, pcbSig, ppvSig); + } + + template<> // mdMethodSpec + HRESULT GetOriginalSigForToken<IMDInternalImport, mdtMethodSpec>(IMDInternalImport *pImport, mdMethodSpec tk, PCCOR_SIGNATURE *ppvSig, ULONG *pcbSig) + { + return pImport->GetMethodSpecProps(tk, NULL, ppvSig, pcbSig); + } + + + // Returns signature for the given MethodDef, FieldDef, MemberRef, standalone Signature, Property, TypeSpec, or MethodSpec token. + // Performs cache lookup, computes the new reinterpreted signature if needed, and inserts it into the cache. Be sure to instantiate + // the method with right template arguments. T is the underlying metadata interface that should be used to retrieve the original + // signature if not passed in ppOrigSig/pcbOrigSigBlob. TOKENTYPE an mdt* constants corresponding to the type of the token. + template<typename T, mdToken TOKENTYPE> + HRESULT GetSignatureForToken( + mdToken token, + PCCOR_SIGNATURE *ppOrigSig, // [IN] pointer to count of bytes in the original signature blob, NULL if we need to retrieve from GetOriginalSigForToken + ULONG *pcbOrigSigBlob, // [IN] pointer to original signature, NULL if we need to retrieve from GetOriginalSigForToken + PCCOR_SIGNATURE *ppSig, // [OUT] new signature + ULONG *pcbSigBlob, // [OUT] count of bytes in the signature blob + T *pImport) + { + _ASSERTE(TypeFromToken(token) == TOKENTYPE); + if ((ppSig == NULL) && (pcbSigBlob == NULL)) + { + return S_OK; + } + + // When loading NGen images we go through code paths that expect no faults and no + // throws. We will need to take a look at how we use the winmd metadata with ngen, + // potentially storing the post-mangled metadata in the NI because as the adapter grows + // we'll see more of these. + CONTRACT_VIOLATION(ThrowsViolation | FaultViolation); + + HRESULT hr = S_OK; + ULONG cbOrigSigBlob = (ULONG)(-1); + PCCOR_SIGNATURE pOrigSig = NULL; + BOOL fPassThrough = FALSE; + + MemoTable<SigData*, SigData::Destroy> &memoTable = GetSignatureMemoTable<TOKENTYPE>(); + + // Get from cache + IfFailRet(GetCachedSigForToken(token, memoTable, pcbSigBlob, ppSig, &fPassThrough)); + if (hr == S_FALSE) + { + // We do not want to leak S_FALSE from this function + hr = S_OK; + + // Original signature has already been provided? + if ((pcbOrigSigBlob == NULL) || (ppOrigSig == NULL)) + { + // Not provided, we need to get one by ourselves + IfFailRet((GetOriginalSigForToken<T, TOKENTYPE>(pImport, token, &pOrigSig, &cbOrigSigBlob))); + } + else + { + // Provided, use that + pOrigSig = *ppOrigSig; + cbOrigSigBlob = *pcbOrigSigBlob; + } + + if (fPassThrough) // We cached that we don't need to reinterpret anything. + { + if (ppSig != NULL) + *ppSig = pOrigSig; + if (pcbSigBlob != NULL) + *pcbSigBlob = cbOrigSigBlob; + } + else + { + SigData *pSigData; + IfFailRet(ReinterpretSignature<TOKENTYPE>(cbOrigSigBlob, pOrigSig, &pSigData)); + IfFailRet(InsertCachedSigForToken(token, memoTable, &pSigData)); + + fPassThrough = (pSigData == SigData::NOREDIRECT); + + if (ppSig != NULL) + *ppSig = (fPassThrough ? pOrigSig : (PCCOR_SIGNATURE)pSigData->data); + if (pcbSigBlob != NULL) + *pcbSigBlob = (fPassThrough ? cbOrigSigBlob : pSigData->cbSig); + } + } + else + { + _ASSERTE(!fPassThrough); + // Already wrote to our output parameters. + } + // We should return error (via IfFailRet macro) or S_OK here + _ASSERTE(hr == S_OK); + + return hr; + } + + // + // Support for extra assembly refs inserted into this assembly + // + ULONG GetRawAssemblyRefCount() { return m_rawAssemblyRefCount; } + + mdAssemblyRef GetAssemblyRefMscorlib() { return m_assemblyRefMscorlib; } + + LPCSTR GetExtraAssemblyRefName(mdAssemblyRef mda) + { + UINT index = RidFromToken(mda) - m_rawAssemblyRefCount - 1; + return WinMDAdapter::GetExtraAssemblyRefNameFromIndex((ContractAssemblyIndex)index); + } + + + static LPCSTR GetExtraAssemblyRefNameFromIndex(FrameworkAssemblyIndex index) + { + _ASSERTE(index >= 0 && index < FrameworkAssembly_Count); + _ASSERTE(index != FrameworkAssembly_Mscorlib); + switch(index) + { + case FrameworkAssembly_SystemObjectModel: + return "System.ObjectModel"; + case FrameworkAssembly_SystemRuntime: + return "System.Runtime"; + case FrameworkAssembly_SystemRuntimeWindowsRuntime: + return "System.Runtime.WindowsRuntime"; + case FrameworkAssembly_SystemRuntimeWindowsRuntimeUIXaml: + return "System.Runtime.WindowsRuntime.UI.Xaml"; + case FrameworkAssembly_SystemNumericsVectors: +#ifdef FEATURE_CORECLR + return "System.Numerics.Vectors"; +#else + return "System.Numerics"; +#endif + default: + _ASSERTE(!"Invalid AssemblyRef token!"); + return NULL; + } + } + + static LPCSTR GetExtraAssemblyRefNameFromIndex(ContractAssemblyIndex index) + { + _ASSERTE(index >= 0 && index < ContractAssembly_Count); + switch(index) + { + case ContractAssembly_SystemRuntime: + return "System.Runtime"; + case ContractAssembly_SystemRuntimeInteropServicesWindowsRuntime: + return "System.Runtime.InteropServices.WindowsRuntime"; + case ContractAssembly_SystemObjectModel: + return "System.ObjectModel"; + case ContractAssembly_SystemRuntimeWindowsRuntime: + return "System.Runtime.WindowsRuntime"; + case ContractAssembly_SystemRuntimeWindowsRuntimeUIXaml: + return "System.Runtime.WindowsRuntime.UI.Xaml"; + case ContractAssembly_SystemNumericsVectors: + return "System.Numerics.Vectors"; + default: + _ASSERTE(!"Invalid AssemblyRef token!"); + return NULL; + } + } + + LPCWSTR GetExtraAssemblyRefNameW(mdAssemblyRef mda) + { + UINT index = RidFromToken(mda) - m_rawAssemblyRefCount - 1; + return WinMDAdapter::GetExtraAssemblyRefNameFromIndexW((ContractAssemblyIndex)index); + } + + static LPCWSTR GetExtraAssemblyRefNameFromIndexW(ContractAssemblyIndex index) + { + _ASSERTE(index >= 0 && index < ContractAssembly_Count); + switch(index) + { + case ContractAssembly_SystemRuntime: + return W("System.Runtime"); + case ContractAssembly_SystemRuntimeInteropServicesWindowsRuntime: + return W("System.Runtime.InteropServices.WindowsRuntime"); + case ContractAssembly_SystemObjectModel: + return W("System.ObjectModel"); + case ContractAssembly_SystemRuntimeWindowsRuntime: + return W("System.Runtime.WindowsRuntime"); + case ContractAssembly_SystemRuntimeWindowsRuntimeUIXaml: + return W("System.Runtime.WindowsRuntime.UI.Xaml"); + case ContractAssembly_SystemNumericsVectors: + return W("System.Numerics.Vectors"); + default: + _ASSERTE(!"Invalid AssemblyRef token!"); + return NULL; + } + } + + BOOL IsValidAssemblyRefToken(mdAssemblyRef tk) + { + _ASSERTE(TypeFromToken(tk) == mdtAssemblyRef); + + RID rid = RidFromToken(tk); + if (rid > 0 && + rid <= m_rawAssemblyRefCount + GetExtraAssemblyRefCount()) + { + return TRUE; + } + + return FALSE; + } + + static void GetExtraAssemblyRefProps(FrameworkAssemblyIndex index, + LPCSTR* ppName, + AssemblyMetaDataInternal* pContext, + PCBYTE * ppPublicKeytoken, + DWORD* pTokenLength, + DWORD* pdwFlags); + + BOOL IsScenarioWinMDExp() + { + return (m_scenario == kWinMDExp); + } + + HRESULT IsRuntimeClassImplementation(mdTypeDef tkTypeDef, BOOL *pbResult) + { + _ASSERTE(pbResult != NULL); + + ULONG typeDefTreatment; + HRESULT hr = GetTypeDefTreatment(tkTypeDef, &typeDefTreatment); + + if (SUCCEEDED(hr)) + { + // kTdUnmangleWinRTName treatment means it is a <CLR> implementation class + *pbResult = (typeDefTreatment == kTdUnmangleWinRTName); + } + + return hr; + } + +private: + struct CABlob; + +private: + + WinMDAdapter(IMDCommon * pRawMDCommon); + + // S_OK if this is a CLR implementation type that was mangled and hidden by WinMDExp + HRESULT CheckIfClrImplementationType(LPCSTR szName, DWORD dwAttr, LPCSTR *pszUnmangledName); + + // Get TypeRefTreatment value for a typeRef + HRESULT GetTypeRefTreatment(mdTypeRef typeRef, ULONG *ppTypeRefTreatment); + + // Get TypeRef's index in array code:g_rgRedirectedTypes or return S_FALSE. + HRESULT GetTypeRefRedirectedInfo( + mdTypeRef tkTypeRef, + RedirectedTypeIndex * pIndex); + + // Get TypeDefTreatment value for a typeDef + HRESULT GetTypeDefTreatment(mdTypeDef typeDef, ULONG *ppTypeRefTreatment); + + // Get MethodTreatment value for a methodDef + HRESULT GetMethodDefTreatment(mdMethodDef methodDef, ULONG *ppMethodDefTreatment); + + // Compute MethodTreatment value for a methodDef (unlike GetMethodDefTreatment, this + // does not cache.) + HRESULT ComputeMethodDefTreatment(mdMethodDef tkMethodDef, mdTypeDef tkDeclaringTypeDef, ULONG *ppMethodDefTreatment); + + HRESULT CheckIfMethodImplImplementsARedirectedInterface(mdToken tkDecl, UINT *pIndex); + + HRESULT TranslateWinMDAttributeUsageAttribute(mdTypeDef tkTypeDefOfCA, DWORD *pClrTargetValue, BOOL *pAllowMultiple); + + static HRESULT CreateClrAttributeUsageAttributeCABlob(DWORD clrTargetValue, BOOL allowMultiple, CABlob **ppCABlob); + + // Whether the WinRT type should be hidden from managed code + // Example: helper class/interface for projected jupiter structs + static BOOL IsHiddenWinRTType(LPCSTR szWinRTNamespace, LPCSTR szWinRTName); + + // Map a WinRT typename to CLR typename + static BOOL ConvertWellKnownTypeNameFromWinRTToClr(LPCSTR *pszNamespace, LPCSTR *pszName, UINT *pIndex); + + static HRESULT CreatePrefixedName(LPCSTR szPrefix, LPCSTR szName, LPCSTR *ppOut); + + template <typename T> static void Delete(T* ptr) + { + delete [] ptr; + } + + HRESULT RewriteTypeInSignature(SigParser * pSigParser, SigBuilder * pSigBuilder, BOOL * pfChangedSig); + + private: + //----------------------------------------------------------------------------------- + // Pointer to the raw view of the metadata. + //----------------------------------------------------------------------------------- + IMetaModelCommonRO *m_pRawMetaModelCommonRO; + + + private: + //----------------------------------------------------------------------------------- + // Stores whether the file is a pure .winmd file or one that combines WinRT and CLR code. + //----------------------------------------------------------------------------------- + enum WinMDScenario + { + kWinMDNormal = 1, // File is normal Windows .winmd file (Version string = "Windows Runtime nnn") + kWinMDExp = 2, // File is output of winmdexp (Version string = "Windows Runtime nnn;<dotnetVersion>") + }; + + WinMDScenario m_scenario; + + + private: + + //----------------------------------------------------------------------------------- + // Every WinMD file is required to have an assemblyRef to mscorlib - this field caches that assemblyRef + //----------------------------------------------------------------------------------- + mdAssemblyRef m_assemblyRefMscorlib; + BOOL m_fReferencesMscorlibV4; // m_assemblyRefMscorlib is a version=4.0.0.0 AssemblyRef + ULONG m_rawAssemblyRefCount; // the raw assembly ref count not including the extra ones. + LONG m_extraAssemblyRefCount; // the assembly ref count to return from IMetaDataAssemblyImport::EnumAssemblyRefs + + + private: + //----------------------------------------------------------------------------------- + // For each typeref token, we cache an enum that determines how the adapter treats it. + //----------------------------------------------------------------------------------- + enum TypeRefTreatment + { + // The upper 8 bits determine how to interpret the lower 24-bits: + kTrClassMask = 0xff000000, + + // Lower 24-bits represent fixed values (defined in rest of enum) + kTrClassMisc = 0x00000000, + + // TypeRef is one of a small # of hard-coded Windows.Foundation types that we redirect to mscorlib counterparts. + // Lower 24-bits is index into typeref redirection table. + kTrClassWellKnownRedirected = 0x01000000, + + kTrNotYetInitialized = kTrClassMisc|0x000000, // Entry has not yet been initialized. + kTrNoRewriteNeeded = kTrClassMisc|0x000001, // Do not mangle the name. + kTrSystemDelegate = kTrClassMisc|0x000002, // Fast-recognition code for System.Delegate + kTrSystemAttribute = kTrClassMisc|0x000003, // Fast-recognition code for System.Attribute + kTrSystemEnum = kTrClassMisc|0x000004, // Fast-recognition code for System.Enum + kTrSystemValueType = kTrClassMisc|0x000005, // Fast-recognition code for System.ValueType + }; + MemoTable<ULONG, DoNothing<ULONG> > m_typeRefTreatmentMemoTable; // Holds index into typeRef rename array or member of TypeRefTreatment enum + + private: + //----------------------------------------------------------------------------------- + // For each typedef token, we cache an enum that determines how the adapter treats it. + //----------------------------------------------------------------------------------- + enum TypeDefTreatment + { + kTdNotYetInitialized = 0x00, + + kTdTreatmentMask = 0x0f, + kTdOther = 0x01, // Anything not covered below, and not affected by the treatment flags + kTdNormalNonAttribute = 0x02, // non-attribute TypeDef from non-managed winmd assembly + kTdNormalAttribute = 0x03, // Attribute TypeDef from non-managed winmd assembly + kTdUnmangleWinRTName = 0x04, // Type in managed winmd that should be renamed from <CLR>Foo to Foo + kTdPrefixWinRTName = 0x05, // Type in managed winmd that should be renamed from Foo to <WinRT>Foo + kTdRedirectedToCLRType = 0x06, // Type is redirected to a CLR type implementation. + kTdRedirectedToCLRAttribute = 0x07, // Type is redirected to a CLR type implementation that is an attribute. + + kTdMarkAbstractFlag = 0x10, // Type should be marked as abstract + kTdMarkInternalFlag = 0x20, // Type should be hidden from managed code - examples are struct helpers + // for redirected Jupiter structs + kTdEnum = 0x40, // Type is an enum from managed\non-managed winmd assembly. + }; + MemoTable<ULONG, DoNothing<ULONG> > m_typeDefTreatmentMemoTable; // Holds member of TypeDefTreatment enum + + private: + //----------------------------------------------------------------------------------- + // For each methoddef token, we cache an enum that determines how the adapter treats it. + //----------------------------------------------------------------------------------- + enum MethodDefTreatment + { + kMdNotYetInitialized = 0x00, + kMdTreatmentMask = 0x0f, // Mask of various options + kMdOther = 0x01, // Anything not covered below + kMdDelegate = 0x02, // Declared by delegate + kMdAttribute = 0x03, // Declared by an attribute + kMdInterface = 0x04, // Is member of interface + kMdImplementation = 0x05, // CLR implementation of RuntimeClass + kMdHiddenImpl = 0x06, // Implements a redirected (hidden) interface + kMdtUnusedFlag = 0x07, // UnUnsed flag. + kMdRenameToDisposeMethod = 0x08, // Rename IClosable.Close to Dispose + + kMdMarkAbstractFlag = 0x10, // Method should be marked as abstract + kMdMarkPublicFlag = 0x20, // Method visibility should be marked as public + }; + MemoTable<ULONG, DoNothing<ULONG> > m_methodDefTreatmentMemoTable; // Holds member of MethodDefTreatment enum + + private: + //----------------------------------------------------------------------------------- + // The version string we report to callers. + //----------------------------------------------------------------------------------- + LPSTR m_pRedirectedVersionString; + + private: + //----------------------------------------------------------------------------------- + // For each customattribute token, we cache the blob that the adapter reports to callers. + // The special pointer value CABlob::NOREDIRECT indicates that the raw blob is to be + // passed unchanged. + //----------------------------------------------------------------------------------- + + // Represents a custom attribute blob + struct CABlob + { + ULONG cbBlob; // Length of blob in bytes. + BYTE data[1]; // Start of variable-length blob (cbBlob indicates length in bytes.) + + static CABlob* Create(const BYTE *pBlob, ULONG cbBlob); + static void Destroy(CABlob *pCABlob); + + // Sentinel value in m_redirectedCABlobsMemoTable table. Means "do no blob rewriting. Return the one from the underlying importer." + static CABlob* const NOREDIRECT; + }; + + MemoTable<CABlob*, CABlob::Destroy> m_redirectedCABlobsMemoTable; // Array of rewritten CA blobs + + private: + //----------------------------------------------------------------------------------- + // For each token, we cache the signature that the adapter reports to callers. + //----------------------------------------------------------------------------------- + MemoTable<SigData*, SigData::Destroy> m_redirectedMethodDefSigMemoTable; // Array of rewritten MethodDef signatures + MemoTable<SigData*, SigData::Destroy> m_redirectedFieldDefSigMemoTable; // Array of rewritten FieldDef signatures + MemoTable<SigData*, SigData::Destroy> m_redirectedMemberRefSigMemoTable; // Array of rewritten MemberRef signatures + MemoTable<SigData*, SigData::Destroy> m_redirectedPropertySigMemoTable; // Array of rewritten Property signatures + MemoTable<SigData*, SigData::Destroy> m_redirectedTypeSpecSigMemoTable; // Array of rewritten TypeSpec signatures + MemoTable<SigData*, SigData::Destroy> m_redirectedMethodSpecSigMemoTable; // Array of rewritten MethodSpec signatures + + // Explicit specializations of GetSignatureMemoTable for all supported token types + template<> MemoTable<SigData*, SigData::Destroy> &GetSignatureMemoTable<mdtMethodDef>() { return m_redirectedMethodDefSigMemoTable; } + template<> MemoTable<SigData*, SigData::Destroy> &GetSignatureMemoTable<mdtFieldDef>() { return m_redirectedFieldDefSigMemoTable; } + template<> MemoTable<SigData*, SigData::Destroy> &GetSignatureMemoTable<mdtMemberRef>() { return m_redirectedMemberRefSigMemoTable; } + template<> MemoTable<SigData*, SigData::Destroy> &GetSignatureMemoTable<mdtProperty>() { return m_redirectedPropertySigMemoTable; } + template<> MemoTable<SigData*, SigData::Destroy> &GetSignatureMemoTable<mdtTypeSpec>() { return m_redirectedTypeSpecSigMemoTable; } + template<> MemoTable<SigData*, SigData::Destroy> &GetSignatureMemoTable<mdtMethodSpec>() { return m_redirectedMethodSpecSigMemoTable; } + + private: + //----------------------------------------------------------------------------------- + // For each typedef whose name we mangle, we cache the mangled name that we report to callers. (The "name" + // is the "name" half of the namespace/name pair. We don't mangle namespaces.) + // + // Currently, the adapter used the tdAttr value to determine whether a typedef name needs + // be mangled at all - thus, we don't have a sentinel for "don't mangle." + //----------------------------------------------------------------------------------- + MemoTable<LPCSTR, Delete<const char> > m_mangledTypeNameTable; // Array of mangled typedef names +}; + + +#endif // __MDWinMDAdapter__h__ diff --git a/src/md/winmd/inc/memotable.h b/src/md/winmd/inc/memotable.h new file mode 100644 index 0000000000..df6823d184 --- /dev/null +++ b/src/md/winmd/inc/memotable.h @@ -0,0 +1,205 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +#ifndef __MDMemoTable__h__ +#define __MDMemoTable__h__ + + +//======================================================================================== +// A MemoTable is a 0-based N element array designed for safe multithreaded access +// and single-initialization rules (e.g. multiple threads can race to initialize an entry +// but only the first one actually modifies the table.) +// +// Template parameters: +// +// ELEMTYPE - Type of the data stored in the array. This type must be small enough +// to be supported by InterlockedCompareExchange. +// +// INITVALUE - Sentinel that indicates that InitEntry() has not been called for that entry yet. +// This is the "initial value" for all elements of the array. +// +// ELEMDELETER - (set to NULL if ELEMTYPE does not represent allocated storage.) +// A function that deallocates the memory referenced by a pointer-typed ELEMTYPE. +// MemoTable will never pass INITVALUE to this function. +// +// Restriction: if ELEMDELETER != NULL, ELEMTYPE must be a C++ pointer type +// (annoying template weirdness with InterlockedCompareExchangeT that +// life is too short to disentangle.) +//======================================================================================== +template <typename ELEMTYPE, void (*ELEMDELETER)(ELEMTYPE)> +class MemoTable +{ +public: + MemoTable(ULONG numElems, ELEMTYPE initValue); + ~MemoTable(); + HRESULT GetEntry(ULONG index, /* [out] */ ELEMTYPE *pElem); + HRESULT InitEntry(ULONG index, /* [in,out] */ ELEMTYPE *pElem); + +private: + MemoTable(const MemoTable &other); + MemoTable& operator=(const MemoTable &other); + + const ULONG m_numElems; + const ELEMTYPE m_initValue; + ELEMTYPE *m_pTable; // Lazily allocated 0-based array with m_numElems elements. +}; + + + + +//============================================================================== +// MemoTable::MemoTable() +//============================================================================== +template <typename ELEMTYPE, void (*ELEMDELETER)(ELEMTYPE)> +MemoTable<ELEMTYPE, ELEMDELETER>::MemoTable(ULONG numElems, ELEMTYPE initValue) : + m_numElems(numElems), + m_initValue(initValue) +{ + m_pTable = NULL; +} + + + +//============================================================================== +// MemoTable::~MemoTable() +//============================================================================== +template <typename ELEMTYPE, void (*ELEMDELETER)(ELEMTYPE)> +MemoTable<ELEMTYPE, ELEMDELETER>::~MemoTable() +{ + if (m_pTable != NULL) + { + if (ELEMDELETER != NULL) + { + for (ULONG index = 0; index < m_numElems; index++) + { + if (m_pTable[index] != m_initValue) + { + ELEMDELETER(m_pTable[index]); + } + } + } + delete [] m_pTable; + } +} + +//============================================================================== +// HRESULT MemoTable::GetEntry(ULONG index, [out] ELEMTYPE *pElem) +// +// Retrieves the element at the specified index. +// +// Returns: +// S_OK if returned element is not INITVALUE +// S_FALSE if returned element is INITVALUE +// CDLB_E_INDEX_NOT_FOUND if index is out of range. +//============================================================================== +template <typename ELEMTYPE, void (*ELEMDELETER)(ELEMTYPE)> +HRESULT MemoTable<ELEMTYPE, ELEMDELETER>::GetEntry(ULONG index, /* [out] */ ELEMTYPE *pElem) +{ + _ASSERTE(pElem); + if (index >= m_numElems) + { + return CLDB_E_INDEX_NOTFOUND; + } + if (m_pTable == NULL) + { + *pElem = m_initValue; + return S_FALSE; + } + ELEMTYPE elem = m_pTable[index]; + *pElem = elem; + return (elem == m_initValue) ? S_FALSE : S_OK; +} + +//============================================================================== +// HRESULT MemoTable::InitEntry(ULONG index, [in, out] ELEMTYPE *pElem) +// +// Initalizes the elment at the specified index. It is illegal to attempt +// to initialize to INITVALUE. For scalar tables, it is illegal to attempt +// to overwrite a previously initialized entry with a different value. +// For pointer tables, the entry will be initialized using InterlockedCompareExchangeT +// and your new value thrown away via ELEMDELETER if you lose the race to initialize. +// +// Returns: +// *pElem overwritten with the actual value written into the table +// (for pointer tables, this may not be the original pointer you passed +// due to races.) +// +// S_OK is the only success value. +//============================================================================== +template <typename ELEMTYPE, void (*ELEMDELETER)(ELEMTYPE)> +HRESULT MemoTable<ELEMTYPE, ELEMDELETER>::InitEntry(ULONG index, /* [in,out] */ ELEMTYPE *pElem) +{ + // 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); + + HRESULT hr = S_OK; + _ASSERTE(pElem); + ELEMTYPE incomingElem = *pElem; + + if (index >= m_numElems) + { + IfFailGo(CLDB_E_INDEX_NOTFOUND); + } + _ASSERTE(incomingElem != m_initValue); + + // If this is first call to InitEntry(), must initialize the table itself. + if (m_pTable == NULL) + { + NewHolder<ELEMTYPE> pNewTable = NULL; + + if ((((size_t)(-1)) / sizeof(ELEMTYPE)) < m_numElems) + { + IfFailGo(E_OUTOFMEMORY); + } + + // When loading NGen images we go through code paths that expect no faults and no + // throws. We will need to take a look at how we use the winmd metadata with ngen, + // potentially storing the post-mangled metadata in the NI because as the adapter grows + // we'll see more of these. + CONTRACT_VIOLATION(FaultViolation); + pNewTable = new (nothrow) ELEMTYPE[m_numElems]; + IfNullGo(pNewTable); + + for (ULONG walk = 0; walk < m_numElems; walk++) + { + pNewTable[walk] = m_initValue; + } + if (InterlockedCompareExchangeT<ELEMTYPE *>(&m_pTable, pNewTable, NULL) == NULL) + { // We won the initialization race + pNewTable.SuppressRelease(); + } + } + + + //------------------------------------------------------------------------- + // Cannot fail after this point, or we may delete *pElem after entering it into table. + //------------------------------------------------------------------------- + hr = S_OK; + if (ELEMDELETER == NULL) + { + _ASSERTE(m_pTable[index] == m_initValue || m_pTable[index] == incomingElem); + m_pTable[index] = incomingElem; + } + else + { + ELEMTYPE winner = InterlockedCompareExchangeT((ELEMTYPE volatile *)&m_pTable[index], incomingElem, m_initValue); + if (winner != m_initValue) + { + ELEMDELETER(incomingElem); // Lost the race + *pElem = winner; + } + } + _ASSERTE(*pElem != m_initValue); + +ErrExit: + if (ELEMDELETER != NULL && FAILED(hr)) + { + ELEMDELETER(*pElem); + *pElem = m_initValue; + } + return hr; +} + +#endif // __MDMemoTable__h__ diff --git a/src/md/winmd/stdafx.cpp b/src/md/winmd/stdafx.cpp new file mode 100644 index 0000000000..ff341e19a7 --- /dev/null +++ b/src/md/winmd/stdafx.cpp @@ -0,0 +1,12 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +//***************************************************************************** +// stdafx.cpp +// + +// +// Precompiled headers. +// +//***************************************************************************** +#include "stdafx.h" diff --git a/src/md/winmd/stdafx.h b/src/md/winmd/stdafx.h new file mode 100644 index 0000000000..7b662bcf38 --- /dev/null +++ b/src/md/winmd/stdafx.h @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +//***************************************************************************** +// stdafx.h +// + +// +// Precompiled headers. +// +//***************************************************************************** +#ifndef __STDAFX_H_ +#define __STDAFX_H_ + +#include <crtwrap.h> +#include <winwrap.h> +#include <utilcode.h> + +#include <cor.h> +#include <corpriv.h> + +#include <ndpversion.h> +#include "nsutilpriv.h" + +#include "utsem.h" + +#endif // __STDAFX_H_ diff --git a/src/md/winmd/winmdimport.cpp b/src/md/winmd/winmdimport.cpp new file mode 100644 index 0000000000..fe80bf0b04 --- /dev/null +++ b/src/md/winmd/winmdimport.cpp @@ -0,0 +1,2132 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + + + +#include "stdafx.h" +#include "winmdinterfaces.h" +#include "metadataexports.h" +#include "inc/adapter.h" +#include "strsafe.h" + +//======================================================================================== +// This metadata importer is exposed publically via CoCreateInstance(CLSID_CorMetaDataDispenser...). +// when the target is a .winmd file. It applies a small number of on-the-fly +// conversions to make the .winmd file look like a regular .NET assembly. +// +// Despite what the MSDN docs say, this importer only supports the reader interfaces and +// a subset of them at that. Supporting the whole set would not be practical with an +// on-the-fly translation strategy. +//======================================================================================== +class WinMDImport : public IMetaDataImport2 + , IMetaDataAssemblyImport + , IMetaDataWinMDImport + , IMetaDataValidate + , IMDCommon + , IMetaModelCommon + , IWinMDImport +#ifdef FEATURE_METADATA_INTERNAL_APIS + , IGetIMDInternalImport +#endif //FEATURE_METADATA_INTERNAL_APIS +{ + public: + //========================================================= + // Factory + //========================================================= + static HRESULT Create(IMDCommon *pRawMDCommon, WinMDImport **ppWinMDImport) + { + HRESULT hr; + *ppWinMDImport = NULL; + + WinMDImport *pNewWinMDImport = new (nothrow) WinMDImport(pRawMDCommon); + + IfFailGo(pNewWinMDImport->m_pRawMDCommon->QueryInterface(IID_IMetaDataImport2, (void**)&pNewWinMDImport->m_pRawImport)); + IfFailGo(pNewWinMDImport->m_pRawImport->QueryInterface(IID_IMetaDataAssemblyImport, (void**)&pNewWinMDImport->m_pRawAssemblyImport)); + + if (FAILED(pNewWinMDImport->m_pRawImport->QueryInterface(IID_IMetaDataValidate, (void**)&pNewWinMDImport->m_pRawValidate))) + { + pNewWinMDImport->m_pRawValidate = nullptr; + } + + pNewWinMDImport->m_pRawMetaModelCommonRO = pRawMDCommon->GetMetaModelCommonRO(); + + IfFailGo(WinMDAdapter::Create(pRawMDCommon, &pNewWinMDImport->m_pWinMDAdapter)); + + (*ppWinMDImport = pNewWinMDImport)->AddRef(); + hr = S_OK; + + ErrExit: + if (pNewWinMDImport) + pNewWinMDImport->Release(); + return hr; + } + + + private: + //========================================================= + // Ctors, Dtors + //========================================================= + WinMDImport(IMDCommon * pRawMDCommon) + { + m_cRef = 1; + m_pRawImport = NULL; + m_pWinMDAdapter = NULL; + m_pRawAssemblyImport = NULL; + m_pFreeThreadedMarshaler = NULL; + (m_pRawMDCommon = pRawMDCommon)->AddRef(); + } + + //--------------------------------------------------------- + ~WinMDImport() + { + if (m_pRawMDCommon) + m_pRawMDCommon->Release(); + if (m_pRawImport) + m_pRawImport->Release(); + if (m_pRawAssemblyImport) + m_pRawAssemblyImport->Release(); + if (m_pRawValidate) + m_pRawValidate->Release(); + if (m_pFreeThreadedMarshaler) + m_pFreeThreadedMarshaler->Release(); + delete m_pWinMDAdapter; + } + + //--------------------------------------------------------- + BOOL IsValidNonNilToken(mdToken token, DWORD tkKind) + { + DWORD tkKindActual = TypeFromToken(token); + DWORD rid = RidFromToken(token); + + if (tkKindActual != tkKind) + return FALSE; + + if (rid == 0) + return FALSE; + + ULONG ulRowCount = m_pRawMetaModelCommonRO->CommonGetRowCount(tkKind); + if (tkKind == mdtAssemblyRef) + return rid <= ulRowCount + m_pWinMDAdapter->GetExtraAssemblyRefCount(); + else + return rid <= ulRowCount; + } + + public: + //========================================================= + // IUnknown methods + //========================================================= + STDMETHODIMP QueryInterface(REFIID riid, void** ppUnk) + { + HRESULT hr; + + *ppUnk = 0; + if (riid == IID_IUnknown || riid == IID_IWinMDImport) + *ppUnk = (IWinMDImport*)this; + else if (riid == IID_IMetaDataImport || riid == IID_IMetaDataImport2) + *ppUnk = (IMetaDataImport*)this; + else if (riid == IID_IMetaDataWinMDImport) + *ppUnk = (IMetaDataWinMDImport*)this; + else if (riid == IID_IMetaDataAssemblyImport) + *ppUnk = (IMetaDataAssemblyImport*)this; + else if (riid == IID_IMDCommon) + *ppUnk = (IMDCommon*)this; + else if (riid == IID_IMetaDataValidate) + { + if (m_pRawValidate == NULL) + { + return E_NOINTERFACE; + } + + *ppUnk = (IMetaDataValidate*)this; + } +#ifdef FEATURE_METADATA_INTERNAL_APIS + else if (riid == IID_IGetIMDInternalImport) + *ppUnk = (IGetIMDInternalImport*)this; +#endif // FEATURE_METADATA_INTERNAL_APIS + else if (riid == IID_IMarshal) + { + if (m_pFreeThreadedMarshaler == NULL) + { + ReleaseHolder<IUnknown> pFreeThreadedMarshaler = NULL; + IfFailRet(CoCreateFreeThreadedMarshaler((IUnknown *)(IMetaDataImport *)this, &pFreeThreadedMarshaler)); + if (InterlockedCompareExchangeT<IUnknown *>(&m_pFreeThreadedMarshaler, pFreeThreadedMarshaler, NULL) == NULL) + { // We won the initialization race + pFreeThreadedMarshaler.SuppressRelease(); + } + } + return m_pFreeThreadedMarshaler->QueryInterface(riid, ppUnk); + } + else + { +#ifndef DACCESS_COMPILE +#ifdef _DEBUG + if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_WinMD_AssertOnIllegalUsage)) + { + if (riid == IID_IMetaDataTables) + _ASSERTE(!"WinMDImport::QueryInterface(IID_IMetaDataTables) returning E_NOINTERFACE"); + else if (riid == IID_IMetaDataTables2) + _ASSERTE(!"WinMDImport::QueryInterface(IID_IMetaDataTables2) returning E_NOINTERFACE"); + else if (riid == IID_IMetaDataInfo) + _ASSERTE(!"WinMDImport::QueryInterface(IID_IMetaDataInfo) returning E_NOINTERFACE"); + else if (riid == IID_IMetaDataEmit) + _ASSERTE(!"WinMDImport::QueryInterface(IID_IMetaDataEmit) returning E_NOINTERFACE"); + else if (riid == IID_IMetaDataEmit2) + _ASSERTE(!"WinMDImport::QueryInterface(IID_IMetaDataEmit2) returning E_NOINTERFACE"); + else if (riid == IID_IMetaDataAssemblyEmit) + _ASSERTE(!"WinMDImport::QueryInterface(IID_IMetaDataAssemblyEmit) returning E_NOINTERFACE"); + else if (riid == IID_IMetaDataValidate) + _ASSERTE(!"WinMDImport::QueryInterface(IID_IMetaDataValidate) returning E_NOINTERFACE"); + else if (riid == IID_IMetaDataFilter) + _ASSERTE(!"WinMDImport::QueryInterface(IID_IMetaDataFilter) returning E_NOINTERFACE"); + else if (riid == IID_IMetaDataHelper) + _ASSERTE(!"WinMDImport::QueryInterface(IID_IMetaDataHelper) returning E_NOINTERFACE"); + else if (riid == IID_IMDInternalEmit) + _ASSERTE(!"WinMDImport::QueryInterface(IID_IMDInternalEmit) returning E_NOINTERFACE"); + else if (riid == IID_IMetaDataEmitHelper) + _ASSERTE(!"WinMDImport::QueryInterface(IID_IMetaDataEmitHelper) returning E_NOINTERFACE"); + else if (riid == IID_IMetaDataCorProfileData) + _ASSERTE(!"WinMDImport::QueryInterface(IID_IMetaDataCorProfileData) returning E_NOINTERFACE"); + else if (riid == IID_IMDInternalMetadataReorderingOptions) + _ASSERTE(!"WinMDImport::QueryInterface(IID_IMDInternalMetadataReorderingOptions) returning E_NOINTERFACE"); + else + _ASSERTE(!"WinMDImport::QueryInterface() returning E_NOINTERFACE"); + } +#endif //_DEBUG +#endif + return E_NOINTERFACE; + } + AddRef(); + return S_OK; + } + //--------------------------------------------------------- + STDMETHODIMP_(ULONG) AddRef(void) + { + return InterlockedIncrement(&m_cRef); + } + //--------------------------------------------------------- + STDMETHODIMP_(ULONG) Release(void) + { + ULONG cRef = InterlockedDecrement(&m_cRef); + if (!cRef) + delete this; + return cRef; + } + + public: + //========================================================= + // IWinMDImport methods + //========================================================= + STDMETHODIMP IsScenarioWinMDExp(BOOL *pbResult) + { + if (pbResult == NULL) + return E_POINTER; + + *pbResult = m_pWinMDAdapter->IsScenarioWinMDExp(); + return S_OK; + } + + STDMETHODIMP IsRuntimeClassImplementation(mdTypeDef tkTypeDef, BOOL *pbResult) + { + if (pbResult == NULL) + return E_POINTER; + + return m_pWinMDAdapter->IsRuntimeClassImplementation(tkTypeDef, pbResult); + } + + //========================================================= + // IMetaDataImport methods + //========================================================= + STDMETHODIMP_(void) CloseEnum(HCORENUM hEnum) + { + m_pRawImport->CloseEnum(hEnum); + } + + STDMETHODIMP CountEnum(HCORENUM hEnum, ULONG *pulCount) + { + _ASSERTE(pulCount != NULL); // Crash on NULL pulCount (just like real RegMeta) + if (hEnum != NULL) + { + HENUMInternal *henuminternal = static_cast<HENUMInternal*>(hEnum); + // Special case: We hijack MethodImpl enum's + if (henuminternal->m_tkKind == (TBL_MethodImpl << 24)) + { + *pulCount = henuminternal->m_ulCount / 2; // MethodImpl enum's are weird - their entries are body/decl pairs so the internal count is twice the number the caller wants to see. + return S_OK; + } + } + + return m_pRawImport->CountEnum(hEnum, pulCount); + } + + STDMETHODIMP ResetEnum(HCORENUM hEnum, ULONG ulPos) + { + return m_pRawImport->ResetEnum(hEnum, ulPos); + } + + STDMETHODIMP EnumTypeDefs(HCORENUM *phEnum, mdTypeDef rTypeDefs[], + ULONG cMax, ULONG *pcTypeDefs) + { + return m_pRawImport->EnumTypeDefs(phEnum, rTypeDefs, cMax, pcTypeDefs); + } + + STDMETHODIMP EnumInterfaceImpls(HCORENUM *phEnum, mdTypeDef td, + mdInterfaceImpl rImpls[], ULONG cMax, + ULONG* pcImpls) + { + return m_pRawImport->EnumInterfaceImpls(phEnum, td, rImpls, cMax, pcImpls); + } + + STDMETHODIMP EnumTypeRefs(HCORENUM *phEnum, mdTypeRef rTypeRefs[], + ULONG cMax, ULONG* pcTypeRefs) + { + // No trick needed: a previous call to EnumTypeRefs must have already taken care of the + // extra type refs. + return m_pRawImport->EnumTypeRefs(phEnum, rTypeRefs, cMax, pcTypeRefs); + } + + STDMETHODIMP FindTypeDefByName( // S_OK or error. + LPCWSTR wszTypeDef, // [IN] Name of the Type. + mdToken tkEnclosingClass, // [IN] TypeDef/TypeRef for Enclosing class. + mdTypeDef *ptd) // [OUT] Put the TypeDef token here. + { + if (wszTypeDef == NULL) // E_INVALIDARG on NULL szTypeDef (just like real RegMeta) + return E_INVALIDARG; + _ASSERTE(ptd != NULL); // AV on NULL ptd (just like real RegMeta) + *ptd = mdTypeDefNil; + + LPUTF8 szFullName; + LPCUTF8 szNamespace; + LPCUTF8 szName; + // Convert the name to UTF8. + UTF8STR(wszTypeDef, szFullName); + ns::SplitInline(szFullName, szNamespace, szName); + + return m_pWinMDAdapter->FindTypeDef(szNamespace, szName, tkEnclosingClass, ptd); + } + + + STDMETHODIMP GetScopeProps( // S_OK or error. + __out_ecount_part_opt(cchName, *pchName) + LPWSTR szName, // [OUT] Put the name here. + ULONG cchName, // [IN] Size of name buffer in wide chars. + ULONG *pchName, // [OUT] Put size of name (wide chars) here. + GUID *pmvid) // [OUT, OPTIONAL] Put MVID here. + { + // Returns error code from name filling (may be CLDB_S_TRUNCTATION) + return m_pRawImport->GetScopeProps(szName, cchName, pchName, pmvid); + } + + + STDMETHODIMP GetModuleFromScope( // S_OK. + mdModule *pmd) // [OUT] Put mdModule token here. + { + return m_pRawImport->GetModuleFromScope(pmd); + } + + + STDMETHODIMP GetTypeDefProps( // S_OK or error. + mdTypeDef td, // [IN] TypeDef token for inquiry. + __out_ecount_part_opt(cchTypeDef, *pchTypeDef) + LPWSTR szTypeDef, // [OUT] Put name here. + ULONG cchTypeDef, // [IN] size of name buffer in wide chars. + ULONG *pchTypeDef, // [OUT] put size of name (wide chars) here. + DWORD *pdwTypeDefFlags, // [OUT] Put flags here. + mdToken *ptkExtends) // [OUT] Put base class TypeDef/TypeRef here. + { + HRESULT hr; + LPCSTR szNamespace; + LPCSTR szName; + if (!IsValidNonNilToken(td, mdtTypeDef)) + { + // Idiosyncractic edge cases - delegate straight through to inherit the correct idiosyncractic edge results + return m_pRawImport->GetTypeDefProps(td, szTypeDef, cchTypeDef, pchTypeDef, pdwTypeDefFlags, ptkExtends); + } + IfFailRet(m_pWinMDAdapter->GetTypeDefProps(td, &szNamespace, &szName, pdwTypeDefFlags, ptkExtends)); + // Returns error code from name filling (may be CLDB_S_TRUNCTATION) + return DeliverUtf8NamespaceAndName(szNamespace, szName, szTypeDef, cchTypeDef, pchTypeDef); + } + + + STDMETHODIMP GetInterfaceImplProps( // S_OK or error. + mdInterfaceImpl iiImpl, // [IN] InterfaceImpl token. + mdTypeDef *pClass, // [OUT] Put implementing class token here. + mdToken *ptkIface) // [OUT] Put implemented interface token here. + { + return m_pRawImport->GetInterfaceImplProps(iiImpl, pClass, ptkIface); + } + + + STDMETHODIMP GetTypeRefProps( // S_OK or error. + mdTypeRef tr, // [IN] TypeRef token. + mdToken *ptkResolutionScope, // [OUT] Resolution scope, ModuleRef or AssemblyRef. + __out_ecount_part_opt(cchName, *pchName) + LPWSTR szName, // [OUT] Name of the TypeRef. + ULONG cchName, // [IN] Size of buffer. + ULONG *pchName) // [OUT] Size of Name. + { + HRESULT hr; + if (!IsValidNonNilToken(tr, mdtTypeRef)) + { + // Idiosyncratic edge cases - delegate straight through to inherit the correct idiosyncratic edge result + return m_pRawImport->GetTypeRefProps(tr, ptkResolutionScope, szName, cchName, pchName); + } + + LPCUTF8 szUtf8Namespace; + LPCUTF8 szUtf8Name; + mdToken tkResolutionScope; + IfFailRet(CommonGetTypeRefProps(tr, &szUtf8Namespace, &szUtf8Name, &tkResolutionScope)); + if (ptkResolutionScope != NULL) + { + *ptkResolutionScope = tkResolutionScope; + } + // Returns error code from name filling (may be CLDB_S_TRUNCTATION) + return DeliverUtf8NamespaceAndName(szUtf8Namespace, szUtf8Name, szName, cchName, pchName); + } + + + STDMETHODIMP ResolveTypeRef(mdTypeRef tr, REFIID riid, IUnknown **ppIScope, mdTypeDef *ptd) + { + WINMD_COMPAT_ASSERT("IMetaDataImport::ResolveTypeRef() not supported on .winmd files."); + return E_NOTIMPL; + } + + + STDMETHODIMP EnumMembers( // S_OK, S_FALSE, or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdTypeDef cl, // [IN] TypeDef to scope the enumeration. + mdToken rMembers[], // [OUT] Put MemberDefs here. + ULONG cMax, // [IN] Max MemberDefs to put. + ULONG *pcTokens) // [OUT] Put # put here. + { + return m_pRawImport->EnumMembers(phEnum, cl, rMembers, cMax, pcTokens); + } + + + STDMETHODIMP EnumMembersWithName( // S_OK, S_FALSE, or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdTypeDef cl, // [IN] TypeDef to scope the enumeration. + LPCWSTR szName, // [IN] Limit results to those with this name. + mdToken rMembers[], // [OUT] Put MemberDefs here. + ULONG cMax, // [IN] Max MemberDefs to put. + ULONG *pcTokens) // [OUT] Put # put here. + { + return m_pRawImport->EnumMembersWithName(phEnum, cl, szName, rMembers, cMax, pcTokens); + } + + + STDMETHODIMP EnumMethods( // S_OK, S_FALSE, or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdTypeDef cl, // [IN] TypeDef to scope the enumeration. + mdMethodDef rMethods[], // [OUT] Put MethodDefs here. + ULONG cMax, // [IN] Max MethodDefs to put. + ULONG *pcTokens) // [OUT] Put # put here. + { + return m_pRawImport->EnumMethods(phEnum, cl, rMethods, cMax, pcTokens); + } + + + STDMETHODIMP EnumMethodsWithName( // S_OK, S_FALSE, or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdTypeDef cl, // [IN] TypeDef to scope the enumeration. + LPCWSTR szName, // [IN] Limit results to those with this name. + mdMethodDef rMethods[], // [OU] Put MethodDefs here. + ULONG cMax, // [IN] Max MethodDefs to put. + ULONG *pcTokens) // [OUT] Put # put here. + { + return m_pRawImport->EnumMethodsWithName(phEnum, cl, szName, rMethods, cMax, pcTokens); + } + + + STDMETHODIMP EnumFields( // S_OK, S_FALSE, or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdTypeDef cl, // [IN] TypeDef to scope the enumeration. + mdFieldDef rFields[], // [OUT] Put FieldDefs here. + ULONG cMax, // [IN] Max FieldDefs to put. + ULONG *pcTokens) // [OUT] Put # put here. + { + return m_pRawImport->EnumFields(phEnum, cl, rFields, cMax, pcTokens); + } + + + STDMETHODIMP EnumFieldsWithName( // S_OK, S_FALSE, or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdTypeDef cl, // [IN] TypeDef to scope the enumeration. + LPCWSTR szName, // [IN] Limit results to those with this name. + mdFieldDef rFields[], // [OUT] Put MemberDefs here. + ULONG cMax, // [IN] Max MemberDefs to put. + ULONG *pcTokens) // [OUT] Put # put here. + { + return m_pRawImport->EnumFieldsWithName(phEnum, cl, szName, rFields, cMax, pcTokens); + } + + + + STDMETHODIMP EnumParams( // S_OK, S_FALSE, or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdMethodDef mb, // [IN] MethodDef to scope the enumeration. + mdParamDef rParams[], // [OUT] Put ParamDefs here. + ULONG cMax, // [IN] Max ParamDefs to put. + ULONG *pcTokens) // [OUT] Put # put here. + { + return m_pRawImport->EnumParams(phEnum, mb, rParams, cMax, pcTokens); + } + + + STDMETHODIMP EnumMemberRefs( // S_OK, S_FALSE, or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdToken tkParent, // [IN] Parent token to scope the enumeration. + mdMemberRef rMemberRefs[], // [OUT] Put MemberRefs here. + ULONG cMax, // [IN] Max MemberRefs to put. + ULONG *pcTokens) // [OUT] Put # put here. + { + return m_pRawImport->EnumMemberRefs(phEnum, tkParent, rMemberRefs, cMax, pcTokens); + } + + + STDMETHODIMP EnumMethodImpls( // S_OK, S_FALSE, or error + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdTypeDef td, // [IN] TypeDef to scope the enumeration. + mdToken rMethodBody[], // [OUT] Put Method Body tokens here. + mdToken rMethodDecl[], // [OUT] Put Method Declaration tokens here. + ULONG cMax, // [IN] Max tokens to put. + ULONG *pcTokens) // [OUT] Put # put here. + { + // Note: This wrapper emulates the underlying RegMeta's parameter validation semantics: + // Pass a bad phEnum: Instant AV + // Pass out of range typedef: returns S_FALSE (i.e. generates empty list) + // Pass non-typedef: returns S_FALSE with assert + // Pass bad output ptr for bodies or decls, AV + // Pass bad output ptr for pcTokens, AV (but NULL is allowed.) + + HRESULT hr; + HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); + HENUMInternal *pEnum = *ppmdEnum; + + if ( pEnum == 0 ) + { + // Create the enumerator, DynamicArrayEnum does not use the token type. + IfFailGo( HENUMInternal::CreateDynamicArrayEnum( (TBL_MethodImpl << 24), &pEnum) ); + IfFailGo( m_pWinMDAdapter->AddMethodImplsToEnum(td, pEnum)); + // set the output parameter + *ppmdEnum = pEnum; + } + + // fill the output token buffer + hr = HENUMInternal::EnumWithCount(pEnum, cMax, rMethodBody, rMethodDecl, pcTokens); + + ErrExit: + HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); + return hr; + } + + + STDMETHODIMP EnumPermissionSets( // S_OK, S_FALSE, or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdToken tk, // [IN] if !NIL, token to scope the enumeration. + DWORD dwActions, // [IN] if !0, return only these actions. + mdPermission rPermission[], // [OUT] Put Permissions here. + ULONG cMax, // [IN] Max Permissions to put. + ULONG *pcTokens) // [OUT] Put # put here. + { + return m_pRawImport->EnumPermissionSets(phEnum, tk, dwActions, rPermission, cMax, pcTokens); + } + + + STDMETHODIMP FindMember( + mdTypeDef td, // [IN] given typedef + LPCWSTR szName, // [IN] member name + PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of CLR signature + ULONG cbSigBlob, // [IN] count of bytes in the signature blob + mdToken *pmb) // [OUT] matching memberdef + { + HRESULT hr = FindMethod( + td, + szName, + pvSigBlob, + cbSigBlob, + pmb); + + if (hr == CLDB_E_RECORD_NOTFOUND) + { + // now try field table + hr = FindField( + td, + szName, + pvSigBlob, + cbSigBlob, + pmb); + } + + return hr; + } + + + STDMETHODIMP FindMethod( + mdTypeDef td, // [IN] given typedef + LPCWSTR szName, // [IN] member name + PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of CLR signature + ULONG cbSigBlob, // [IN] count of bytes in the signature blob + mdMethodDef *pmb) // [OUT] matching memberdef + { + if (pvSigBlob == NULL || cbSigBlob == 0) + { + // if signature matching is not needed, we can delegate to the underlying implementation + return m_pRawImport->FindMethod(td, szName, pvSigBlob, cbSigBlob, pmb); + } + + // The following code emulates RegMeta::FindMethod. We cannot call the underlying + // implementation because we need to compare pvSigBlob to reinterpreted signatures. + HRESULT hr = S_OK; + HCORENUM hEnum = NULL; + + CQuickBytes qbSig; // holds non-varargs signature + CQuickArray<WCHAR> rName; + + if (szName == NULL || pmb == NULL) + IfFailGo(E_INVALIDARG); + + *pmb = mdMethodDefNil; + + // check to see if this is a vararg signature + PCCOR_SIGNATURE pvSigTemp = pvSigBlob; + if (isCallConv(CorSigUncompressCallingConv(pvSigTemp), IMAGE_CEE_CS_CALLCONV_VARARG)) + { + // Get the fixed part of VARARG signature + IfFailGo(_GetFixedSigOfVarArg(pvSigBlob, cbSigBlob, &qbSig, &cbSigBlob)); + pvSigBlob = (PCCOR_SIGNATURE) qbSig.Ptr(); + } + + // now iterate all methods in td and compare name and signature + IfNullGo(rName.AllocNoThrow(wcslen(szName) + 1)); + + mdMethodDef md; + ULONG count; + while ((hr = EnumMethods(&hEnum, td, &md, 1, &count)) == S_OK) + { + PCCOR_SIGNATURE pvMethodSigBlob; + ULONG cbMethodSigBlob; + ULONG chMethodName; + DWORD dwMethodAttr; + + IfFailGo(GetMethodProps(md, NULL, rName.Ptr(), (ULONG)rName.Size(), &chMethodName, &dwMethodAttr, &pvMethodSigBlob, &cbMethodSigBlob, NULL, NULL)); + + if (chMethodName == rName.Size() && wcscmp(szName, rName.Ptr()) == 0) + { + // we have a name match, check signature + if (cbSigBlob != cbMethodSigBlob || memcmp(pvSigBlob, pvMethodSigBlob, cbSigBlob) != 0) + continue; + + // ignore PrivateScope methods + if (IsMdPrivateScope(dwMethodAttr)) + continue; + + // we found the method + *pmb = md; + goto ErrExit; + } + } + IfFailGo(hr); + hr = CLDB_E_RECORD_NOTFOUND; + + ErrExit: + if (hEnum != NULL) + CloseEnum(hEnum); + + return hr; + } + + + STDMETHODIMP FindField( + mdTypeDef td, // [IN] given typedef + LPCWSTR szName, // [IN] member name + PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of CLR signature + ULONG cbSigBlob, // [IN] count of bytes in the signature blob + mdFieldDef *pmb) // [OUT] matching memberdef + { + if (pvSigBlob == NULL || cbSigBlob == 0) + { + // if signature matching is not needed, we can delegate to the underlying implementation + return m_pRawImport->FindField(td, szName, pvSigBlob, cbSigBlob, pmb); + } + + // The following code emulates RegMeta::FindField. We cannot call the underlying + // implementation because we need to compare pvSigBlob to reinterpreted signatures. + HRESULT hr = S_OK; + HCORENUM hEnum = NULL; + + CQuickArray<WCHAR> rName; + + if (szName == NULL || pmb == NULL) + IfFailGo(E_INVALIDARG); + + *pmb = mdFieldDefNil; + + // now iterate all fields in td and compare name and signature + IfNullGo(rName.AllocNoThrow(wcslen(szName) + 1)); + + mdFieldDef fd; + ULONG count; + while ((hr = EnumFields(&hEnum, td, &fd, 1, &count)) == S_OK) + { + PCCOR_SIGNATURE pvFieldSigBlob; + ULONG cbFieldSigBlob; + ULONG chFieldName; + DWORD dwFieldAttr; + + IfFailGo(GetFieldProps(fd, NULL, rName.Ptr(), (ULONG)rName.Size(), &chFieldName, &dwFieldAttr, &pvFieldSigBlob, &cbFieldSigBlob, NULL, NULL, NULL)); + + if (chFieldName == rName.Size() && wcscmp(szName, rName.Ptr()) == 0) + { + // we have a name match, check signature + if (cbSigBlob != cbFieldSigBlob || memcmp(pvSigBlob, pvFieldSigBlob, cbSigBlob) != 0) + continue; + + // ignore PrivateScope fields + if (IsFdPrivateScope(dwFieldAttr)) + continue; + + // we found the field + *pmb = fd; + goto ErrExit; + } + } + IfFailGo(hr); + hr = CLDB_E_RECORD_NOTFOUND; + + ErrExit: + if (hEnum != NULL) + CloseEnum(hEnum); + + return hr; + } + + + STDMETHODIMP FindMemberRef( + mdTypeRef td, // [IN] given typeRef + LPCWSTR szName, // [IN] member name + PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of CLR signature + ULONG cbSigBlob, // [IN] count of bytes in the signature blob + mdMemberRef *pmr) // [OUT] matching memberref + { + if (pvSigBlob == NULL || cbSigBlob == 0) + { + // if signature matching is not needed, we can delegate to the underlying implementation + return m_pRawImport->FindMemberRef(td, szName, pvSigBlob, cbSigBlob, pmr); + } + + // The following code emulates RegMeta::FindMemberRef. We cannot call the underlying + // implementation because we need to compare pvSigBlob to reinterpreted signatures. + HRESULT hr = S_OK; + HCORENUM hEnum = NULL; + + CQuickArray<WCHAR> rName; + + if (szName == NULL || pmr == NULL) + IfFailGo(CLDB_E_RECORD_NOTFOUND); + + *pmr = mdMemberRefNil; + + // now iterate all members in td and compare name and signature + IfNullGo(rName.AllocNoThrow(wcslen(szName) + 1)); + + mdMemberRef rd; + ULONG count; + while ((hr = EnumMemberRefs(&hEnum, td, &rd, 1, &count)) == S_OK) + { + PCCOR_SIGNATURE pvMemberSigBlob; + ULONG cbMemberSigBlob; + ULONG chMemberName; + + IfFailGo(GetMemberRefProps(rd, NULL, rName.Ptr(), (ULONG)rName.Size(), &chMemberName, &pvMemberSigBlob, &cbMemberSigBlob)); + + if (chMemberName == rName.Size() && wcscmp(szName, rName.Ptr()) == 0) + { + // we have a name match, check signature + if (cbSigBlob != cbMemberSigBlob || memcmp(pvSigBlob, pvMemberSigBlob, cbSigBlob) != 0) + continue; + + // we found the member + *pmr = rd; + goto ErrExit; + } + } + IfFailGo(hr); + hr = CLDB_E_RECORD_NOTFOUND; + + ErrExit: + if (hEnum != NULL) + CloseEnum(hEnum); + + return hr; + } + + + STDMETHODIMP GetMethodProps( + mdMethodDef mb, // The method for which to get props. + mdTypeDef *pClass, // Put method's class here. + __out_ecount_part_opt(cchMethod, *pchMethod) + LPWSTR szMethod, // Put method's name here. + ULONG cchMethod, // Size of szMethod buffer in wide chars. + ULONG *pchMethod, // Put actual size here + DWORD *pdwAttr, // Put flags here. + PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to the blob value of meta data + ULONG *pcbSigBlob, // [OUT] actual size of signature blob + ULONG *pulCodeRVA, // [OUT] codeRVA + DWORD *pdwImplFlags) // [OUT] Impl. Flags + { + HRESULT hr; + HRESULT hrNameTruncation; + if (!IsValidNonNilToken(mb, mdtMethodDef)) + { + // Idiosyncratic edge cases - delegate straight through to inherit the correct idiosyncratic edge result + return m_pRawImport->GetMethodProps(mb, pClass, szMethod, cchMethod, pchMethod, pdwAttr, ppvSigBlob, pcbSigBlob, pulCodeRVA, pdwImplFlags); + } + + ULONG cbOrigSigBlob = (ULONG)(-1); + PCCOR_SIGNATURE pOrigSig = NULL; + IfFailRet(hrNameTruncation = m_pRawImport->GetMethodProps(mb, pClass, szMethod, cchMethod, pchMethod, pdwAttr, &pOrigSig, &cbOrigSigBlob, pulCodeRVA, pdwImplFlags)); + + IfFailRet((m_pWinMDAdapter->GetSignatureForToken<IMetaDataImport2, mdtMethodDef>( + mb, + &pOrigSig, // ppOrigSig + &cbOrigSigBlob, // pcbOrigSig + ppvSigBlob, + pcbSigBlob, + m_pRawImport))); + + LPCSTR szNewName = NULL; + IfFailRet(m_pWinMDAdapter->ModifyMethodProps(mb, pdwAttr, pdwImplFlags, pulCodeRVA, &szNewName)); + if (szNewName != NULL) + { + // We want to return name truncation status from the method that really fills the output buffer, rewrite the previous value + IfFailRet(hrNameTruncation = DeliverUtf8String(szNewName, szMethod, cchMethod, pchMethod)); + } + + // Return the success code from name filling (S_OK or CLDB_S_TRUNCATION) + return hrNameTruncation; + } + + + STDMETHODIMP GetMemberRefProps( // S_OK or error. + mdMemberRef mr, // [IN] given memberref + mdToken *ptk, // [OUT] Put classref or classdef here. + __out_ecount_part_opt(cchMember, *pchMember) + LPWSTR szMember, // [OUT] buffer to fill for member's name + ULONG cchMember, // [IN] the count of char of szMember + ULONG *pchMember, // [OUT] actual count of char in member name + PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to meta data blob value + ULONG *pbSig) // [OUT] actual size of signature blob + { + HRESULT hr = S_OK; + HRESULT hrNameTruncation; + + ULONG cbOrigSigBlob = (ULONG)(-1); + PCCOR_SIGNATURE pOrigSig = NULL; + IfFailRet(hrNameTruncation = m_pRawImport->GetMemberRefProps(mr, ptk, szMember, cchMember, pchMember, &pOrigSig, &cbOrigSigBlob)); + LPCSTR szNewName = NULL; + IfFailRet(m_pWinMDAdapter->ModifyMemberProps(mr, NULL, NULL, NULL, &szNewName)); + IfFailRet((m_pWinMDAdapter->GetSignatureForToken<IMetaDataImport2, mdtMemberRef>( + mr, + &pOrigSig, // ppOrigSig + &cbOrigSigBlob, // pcbOrigSig + ppvSigBlob, + pbSig, + m_pRawImport))); + if (szNewName != NULL) + { + // We want to return name truncation status from the method that really fills the output buffer, rewrite the previous value + IfFailRet(hrNameTruncation = DeliverUtf8String(szNewName, szMember, cchMember, pchMember)); + } + // Return the success code from name filling (S_OK or CLDB_S_TRUNCATION) + return hrNameTruncation; + } + + + STDMETHODIMP EnumProperties( // S_OK, S_FALSE, or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdTypeDef td, // [IN] TypeDef to scope the enumeration. + mdProperty rProperties[], // [OUT] Put Properties here. + ULONG cMax, // [IN] Max properties to put. + ULONG *pcProperties) // [OUT] Put # put here. + { + return m_pRawImport->EnumProperties(phEnum, td, rProperties, cMax, pcProperties); + } + + + STDMETHODIMP EnumEvents( // S_OK, S_FALSE, or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdTypeDef td, // [IN] TypeDef to scope the enumeration. + mdEvent rEvents[], // [OUT] Put events here. + ULONG cMax, // [IN] Max events to put. + ULONG *pcEvents) // [OUT] Put # put here. + { + return m_pRawImport->EnumEvents(phEnum, td, rEvents, cMax, pcEvents); + } + + + STDMETHODIMP GetEventProps( // S_OK, S_FALSE, or error. + mdEvent ev, // [IN] event token + mdTypeDef *pClass, // [OUT] typedef containing the event declarion. + LPCWSTR szEvent, // [OUT] Event name + ULONG cchEvent, // [IN] the count of wchar of szEvent + ULONG *pchEvent, // [OUT] actual count of wchar for event's name + DWORD *pdwEventFlags, // [OUT] Event flags. + mdToken *ptkEventType, // [OUT] EventType class + mdMethodDef *pmdAddOn, // [OUT] AddOn method of the event + mdMethodDef *pmdRemoveOn, // [OUT] RemoveOn method of the event + mdMethodDef *pmdFire, // [OUT] Fire method of the event + mdMethodDef rmdOtherMethod[], // [OUT] other method of the event + ULONG cMax, // [IN] size of rmdOtherMethod + ULONG *pcOtherMethod) // [OUT] total number of other method of this event + { + // Returns error code from name filling (may be CLDB_S_TRUNCTATION) + return m_pRawImport->GetEventProps(ev, pClass, szEvent, cchEvent, pchEvent, pdwEventFlags, ptkEventType, pmdAddOn, pmdRemoveOn, pmdFire, rmdOtherMethod, cMax, pcOtherMethod); + } + + + STDMETHODIMP EnumMethodSemantics( // S_OK, S_FALSE, or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdMethodDef mb, // [IN] MethodDef to scope the enumeration. + mdToken rEventProp[], // [OUT] Put Event/Property here. + ULONG cMax, // [IN] Max properties to put. + ULONG *pcEventProp) // [OUT] Put # put here. + { + return m_pRawImport->EnumMethodSemantics(phEnum, mb, rEventProp, cMax, pcEventProp); + } + + STDMETHODIMP GetMethodSemantics( // S_OK, S_FALSE, or error. + mdMethodDef mb, // [IN] method token + mdToken tkEventProp, // [IN] event/property token. + DWORD *pdwSemanticsFlags) // [OUT] the role flags for the method/propevent pair + { + return m_pRawImport->GetMethodSemantics(mb, tkEventProp, pdwSemanticsFlags); + } + + + STDMETHODIMP GetClassLayout( + mdTypeDef td, // [IN] give typedef + DWORD *pdwPackSize, // [OUT] 1, 2, 4, 8, or 16 + COR_FIELD_OFFSET rFieldOffset[], // [OUT] field offset array + ULONG cMax, // [IN] size of the array + ULONG *pcFieldOffset, // [OUT] needed array size + ULONG *pulClassSize) // [OUT] the size of the class + { + return m_pRawImport->GetClassLayout(td, pdwPackSize, rFieldOffset, cMax, pcFieldOffset, pulClassSize); + } + + + STDMETHODIMP GetFieldMarshal( + mdToken tk, // [IN] given a field's memberdef + PCCOR_SIGNATURE *ppvNativeType, // [OUT] native type of this field + ULONG *pcbNativeType) // [OUT] the count of bytes of *ppvNativeType + { + return m_pRawImport->GetFieldMarshal(tk, ppvNativeType, pcbNativeType); + } + + + STDMETHODIMP GetRVA( // S_OK or error. + mdToken tk, // Member for which to set offset + ULONG *pulCodeRVA, // The offset + DWORD *pdwImplFlags) // the implementation flags + { + HRESULT hr; + if (!IsValidNonNilToken(tk, mdtMethodDef)) + { + // Idiosyncratic edge cases - delegate straight through to inherit the correct idiosyncratic edge result + return m_pRawImport->GetRVA(tk, pulCodeRVA, pdwImplFlags); + } + + IfFailRet(m_pRawImport->GetRVA(tk, pulCodeRVA, pdwImplFlags)); + IfFailRet(m_pWinMDAdapter->ModifyMethodProps(tk, NULL, pdwImplFlags, pulCodeRVA, NULL)); + return hr; + } + + + STDMETHODIMP GetPermissionSetProps( + mdPermission pm, // [IN] the permission token. + DWORD *pdwAction, // [OUT] CorDeclSecurity. + void const **ppvPermission, // [OUT] permission blob. + ULONG *pcbPermission) // [OUT] count of bytes of pvPermission. + { + return m_pRawImport->GetPermissionSetProps(pm, pdwAction, ppvPermission, pcbPermission); + } + + + STDMETHODIMP GetSigFromToken( // S_OK or error. + mdSignature mdSig, // [IN] Signature token. + PCCOR_SIGNATURE *ppvSig, // [OUT] return pointer to token. + ULONG *pcbSig) // [OUT] return size of signature. + { + // mdSignature is not part of public WinMD surface, so it does not need signature rewriting + return m_pRawImport->GetSigFromToken(mdSig, ppvSig, pcbSig); + } + + STDMETHODIMP GetModuleRefProps( // S_OK or error. + mdModuleRef mur, // [IN] moduleref token. + __out_ecount_part_opt(cchName, *pchName) + LPWSTR szName, // [OUT] buffer to fill with the moduleref name. + ULONG cchName, // [IN] size of szName in wide characters. + ULONG *pchName) // [OUT] actual count of characters in the name. + { + // Returns error code from name filling (may be CLDB_S_TRUNCTATION) + return m_pRawImport->GetModuleRefProps(mur, szName, cchName, pchName); + } + + + STDMETHODIMP EnumModuleRefs( // S_OK or error. + HCORENUM *phEnum, // [IN|OUT] pointer to the enum. + mdModuleRef rModuleRefs[], // [OUT] put modulerefs here. + ULONG cmax, // [IN] max memberrefs to put. + ULONG *pcModuleRefs) // [OUT] put # put here. + { + return m_pRawImport->EnumModuleRefs(phEnum, rModuleRefs, cmax, pcModuleRefs); + } + + + STDMETHODIMP GetTypeSpecFromToken( // S_OK or error. + mdTypeSpec typespec, // [IN] TypeSpec token. + PCCOR_SIGNATURE *ppvSig, // [OUT] return pointer to TypeSpec signature + ULONG *pcbSig) // [OUT] return size of signature. + { + return m_pWinMDAdapter->GetSignatureForToken<IMetaDataImport2, mdtTypeSpec>( + typespec, + NULL, // ppOrigSig + NULL, // pcbOrigSig + ppvSig, + pcbSig, + m_pRawImport); + } + + + STDMETHODIMP GetNameFromToken( // Not Recommended! May be removed! + mdToken tk, // [IN] Token to get name from. Must have a name. + MDUTF8CSTR *pszUtf8NamePtr) // [OUT] Return pointer to UTF8 name in heap. + { + HRESULT hr; + + if (!IsValidNonNilToken(tk, mdtTypeRef)) + { + // Handle corner error case + IfFailGo(m_pRawImport->GetNameFromToken(tk, pszUtf8NamePtr)); + } + else + { + IfFailGo(m_pWinMDAdapter->GetTypeRefProps(tk, NULL, pszUtf8NamePtr, NULL)); + } + + ErrExit: + return hr; + } + + + STDMETHODIMP EnumUnresolvedMethods( // S_OK, S_FALSE, or error. + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdToken rMethods[], // [OUT] Put MemberDefs here. + ULONG cMax, // [IN] Max MemberDefs to put. + ULONG *pcTokens) // [OUT] Put # put here. + { + return m_pRawImport->EnumUnresolvedMethods(phEnum, rMethods, cMax, pcTokens); + } + + + STDMETHODIMP GetUserString( // S_OK or error. + mdString stk, // [IN] String token. + __out_ecount_part_opt(cchString, *pchString) + LPWSTR szString, // [OUT] Copy of string. + ULONG cchString, // [IN] Max chars of room in szString. + ULONG *pchString) // [OUT] How many chars in actual string. + { + // Returns error code from name filling (may be CLDB_S_TRUNCTATION) + return m_pRawImport->GetUserString(stk, szString, cchString, pchString); + } + + + STDMETHODIMP GetPinvokeMap( // S_OK or error. + mdToken tk, // [IN] FieldDef or MethodDef. + DWORD *pdwMappingFlags, // [OUT] Flags used for mapping. + __out_ecount_part_opt(cchImportName, *pchImportName) + LPWSTR szImportName, // [OUT] Import name. + ULONG cchImportName, // [IN] Size of the name buffer. + ULONG *pchImportName, // [OUT] Actual number of characters stored. + mdModuleRef *pmrImportDLL) // [OUT] ModuleRef token for the target DLL. + { + // Returns error code from name filling (may be CLDB_S_TRUNCTATION) + return m_pRawImport->GetPinvokeMap(tk, pdwMappingFlags, szImportName, cchImportName, pchImportName, pmrImportDLL); + } + + + STDMETHODIMP EnumSignatures( // S_OK or error. + HCORENUM *phEnum, // [IN|OUT] pointer to the enum. + mdSignature rSignatures[], // [OUT] put signatures here. + ULONG cmax, // [IN] max signatures to put. + ULONG *pcSignatures) // [OUT] put # put here. + { + return m_pRawImport->EnumSignatures(phEnum, rSignatures, cmax, pcSignatures); + } + + + STDMETHODIMP EnumTypeSpecs( // S_OK or error. + HCORENUM *phEnum, // [IN|OUT] pointer to the enum. + mdTypeSpec rTypeSpecs[], // [OUT] put TypeSpecs here. + ULONG cmax, // [IN] max TypeSpecs to put. + ULONG *pcTypeSpecs) // [OUT] put # put here. + { + return m_pRawImport->EnumTypeSpecs(phEnum, rTypeSpecs, cmax, pcTypeSpecs); + } + + + STDMETHODIMP EnumUserStrings( // S_OK or error. + HCORENUM *phEnum, // [IN/OUT] pointer to the enum. + mdString rStrings[], // [OUT] put Strings here. + ULONG cmax, // [IN] max Strings to put. + ULONG *pcStrings) // [OUT] put # put here. + { + return m_pRawImport->EnumUserStrings(phEnum, rStrings, cmax, pcStrings); + } + + + STDMETHODIMP GetParamForMethodIndex( // S_OK or error. + mdMethodDef md, // [IN] Method token. + ULONG ulParamSeq, // [IN] Parameter sequence. + mdParamDef *ppd) // [IN] Put Param token here. + { + return m_pRawImport->GetParamForMethodIndex(md, ulParamSeq, ppd); + } + + + STDMETHODIMP EnumCustomAttributes( // S_OK or error. + HCORENUM *phEnum, // [IN, OUT] COR enumerator. + mdToken tk, // [IN] Token to scope the enumeration, 0 for all. + mdToken tkType, // [IN] Type of interest, 0 for all. + mdCustomAttribute rCustomAttributes[], // [OUT] Put custom attribute tokens here. + ULONG cMax, // [IN] Size of rCustomAttributes. + ULONG *pcCustomAttributes) // [OUT, OPTIONAL] Put count of token values here. + { + return m_pRawImport->EnumCustomAttributes(phEnum, tk, tkType, rCustomAttributes, cMax, pcCustomAttributes); + } + + + STDMETHODIMP GetCustomAttributeProps( // S_OK or error. + mdCustomAttribute cv, // [IN] CustomAttribute token. + mdToken *ptkObj, // [OUT, OPTIONAL] Put object token here. + mdToken *ptkType, // [OUT, OPTIONAL] Put AttrType token here. + void const **ppBlob, // [OUT, OPTIONAL] Put pointer to data here. + ULONG *pcbSize) // [OUT, OPTIONAL] Put size of date here. + { + HRESULT hr; + if (!IsValidNonNilToken(cv, mdtCustomAttribute)) + { + // Idiosyncratic edge cases - delegate straight through to inherit the correct idiosyncratic edge result + return m_pRawImport->GetCustomAttributeProps(cv, ptkObj, ptkType, ppBlob, pcbSize); + } + IfFailRet(m_pRawImport->GetCustomAttributeProps(cv, ptkObj, ptkType, NULL, NULL)); + IfFailRet(m_pWinMDAdapter->GetCustomAttributeBlob(cv, ppBlob, pcbSize)); + return hr; + } + + + STDMETHODIMP FindTypeRef( + mdToken tkResolutionScope, // [IN] ModuleRef, AssemblyRef or TypeRef. + LPCWSTR wzTypeName, // [IN] TypeRef Name. + mdTypeRef *ptr) // [OUT] matching TypeRef. + { + + HRESULT hr; + LPUTF8 szFullName; + LPCUTF8 szNamespace; + LPCUTF8 szName; + + _ASSERTE(wzTypeName && ptr); + *ptr = mdTypeRefNil; // AV if caller passes NULL: just like the real RegMeta. + + // Convert the name to UTF8. + PREFIX_ASSUME(wzTypeName != NULL); // caller might pass NULL, but they'll AV (just like the real RegMeta) + UTF8STR(wzTypeName, szFullName); + ns::SplitInline(szFullName, szNamespace, szName); + hr = m_pWinMDAdapter->FindTypeRef(szNamespace, szName, tkResolutionScope, ptr); + + return hr; + } + + + STDMETHODIMP GetMemberProps( + mdToken mb, // The member for which to get props. + mdTypeDef *pClass, // Put member's class here. + __out_ecount_part_opt(cchMember, *pchMember) + LPWSTR szMember, // Put member's name here. + ULONG cchMember, // Size of szMember buffer in wide chars. + ULONG *pchMember, // Put actual size here + DWORD *pdwAttr, // Put flags here. + PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to the blob value of meta data + ULONG *pcbSigBlob, // [OUT] actual size of signature blob + ULONG *pulCodeRVA, // [OUT] codeRVA + DWORD *pdwImplFlags, // [OUT] Impl. Flags + DWORD *pdwCPlusTypeFlag, // [OUT] flag for value type. selected ELEMENT_TYPE_* + UVCP_CONSTANT *ppValue, // [OUT] constant value + ULONG *pcchValue) // [OUT] size of constant string in chars, 0 for non-strings. + { + HRESULT hr; + HRESULT hrNameTruncation; + if (!IsValidNonNilToken(mb, mdtMethodDef) && !IsValidNonNilToken(mb, mdtFieldDef)) + { + // Idiosyncratic edge cases - delegate straight through to inherit the correct idiosyncratic edge result + return m_pRawImport->GetMemberProps(mb, pClass, szMember, cchMember, pchMember, pdwAttr, ppvSigBlob, pcbSigBlob, pulCodeRVA, pdwImplFlags, pdwCPlusTypeFlag, ppValue, pcchValue); + } + + PCCOR_SIGNATURE pOrigSig; + ULONG cbOrigSig; + + IfFailRet(hrNameTruncation = m_pRawImport->GetMemberProps(mb, pClass, szMember, cchMember, pchMember, pdwAttr, &pOrigSig, &cbOrigSig, pulCodeRVA, pdwImplFlags, pdwCPlusTypeFlag, ppValue, pcchValue)); + + LPCSTR szNewName = NULL; + IfFailRet(m_pWinMDAdapter->ModifyMemberProps(mb, pdwAttr, pdwImplFlags, pulCodeRVA, &szNewName)); + + if (IsValidNonNilToken(mb, mdtMethodDef)) + { + IfFailRet((m_pWinMDAdapter->GetSignatureForToken<IMetaDataImport2, mdtMethodDef>( + mb, + &pOrigSig, // ppOrigSig + &cbOrigSig, // pcbOrigSig + ppvSigBlob, + pcbSigBlob, + m_pRawImport))); + } + else if (IsValidNonNilToken(mb, mdtFieldDef)) + { + IfFailRet((m_pWinMDAdapter->GetSignatureForToken<IMetaDataImport2, mdtFieldDef>( + mb, + &pOrigSig, // ppOrigSig + &cbOrigSig, // pcbOrigSig + ppvSigBlob, + pcbSigBlob, + m_pRawImport))); + } + else + { + if (ppvSigBlob != NULL) + *ppvSigBlob = pOrigSig; + + if (pcbSigBlob != NULL) + *pcbSigBlob = cbOrigSig; + } + + if (szNewName != NULL) + { + // We want to return name truncation status from the method that really fills the output buffer, rewrite the previous value + IfFailRet(hrNameTruncation = DeliverUtf8String(szNewName, szMember, cchMember, pchMember)); + } + + // Return the success code from name filling (S_OK or CLDB_S_TRUNCATION) + return hrNameTruncation; + } + + + STDMETHODIMP GetFieldProps( + mdFieldDef mb, // The field for which to get props. + mdTypeDef *pClass, // Put field's class here. + __out_ecount_part_opt(cchField, *pchField) + LPWSTR szField, // Put field's name here. + ULONG cchField, // Size of szField buffer in wide chars. + ULONG *pchField, // Put actual size here + DWORD *pdwAttr, // Put flags here. + PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to the blob value of meta data + ULONG *pcbSigBlob, // [OUT] actual size of signature blob + DWORD *pdwCPlusTypeFlag, // [OUT] flag for value type. selected ELEMENT_TYPE_* + UVCP_CONSTANT *ppValue, // [OUT] constant value + ULONG *pcchValue) // [OUT] size of constant string in chars, 0 for non-strings. + { + HRESULT hr; + HRESULT hrNameTruncation; + + PCCOR_SIGNATURE pOrigSig; + ULONG cbOrigSig; + IfFailRet(hrNameTruncation = m_pRawImport->GetFieldProps(mb, pClass, szField, cchField, pchField, pdwAttr, &pOrigSig, &cbOrigSig, pdwCPlusTypeFlag, ppValue, pcchValue)); + + IfFailRet(m_pWinMDAdapter->ModifyFieldDefProps(mb, pdwAttr)); + IfFailRet((m_pWinMDAdapter->GetSignatureForToken<IMetaDataImport2, mdtFieldDef>( + mb, + &pOrigSig, + &cbOrigSig, + ppvSigBlob, + pcbSigBlob, + m_pRawImport))); + + // Return the success code from name filling (S_OK or CLDB_S_TRUNCATION) + return hrNameTruncation; + } + + + STDMETHODIMP GetPropertyProps( // S_OK, S_FALSE, or error. + mdProperty prop, // [IN] property token + mdTypeDef *pClass, // [OUT] typedef containing the property declarion. + LPCWSTR szProperty, // [OUT] Property name + ULONG cchProperty, // [IN] the count of wchar of szProperty + ULONG *pchProperty, // [OUT] actual count of wchar for property name + DWORD *pdwPropFlags, // [OUT] property flags. + PCCOR_SIGNATURE *ppvSig, // [OUT] property type. pointing to meta data internal blob + ULONG *pbSig, // [OUT] count of bytes in *ppvSig + DWORD *pdwCPlusTypeFlag, // [OUT] flag for value type. selected ELEMENT_TYPE_* + UVCP_CONSTANT *ppDefaultValue, // [OUT] constant value + ULONG *pcchDefaultValue, // [OUT] size of constant string in chars, 0 for non-strings. + mdMethodDef *pmdSetter, // [OUT] setter method of the property + mdMethodDef *pmdGetter, // [OUT] getter method of the property + mdMethodDef rmdOtherMethod[], // [OUT] other method of the property + ULONG cMax, // [IN] size of rmdOtherMethod + ULONG *pcOtherMethod) // [OUT] total number of other method of this property + { + HRESULT hr = S_OK; + HRESULT hrNameTruncation; + + ULONG cbOrigSigBlob = (ULONG)(-1); + PCCOR_SIGNATURE pOrigSig = NULL; + IfFailRet(hrNameTruncation = m_pRawImport->GetPropertyProps(prop, pClass, szProperty, cchProperty, pchProperty, pdwPropFlags, &pOrigSig, &cbOrigSigBlob, pdwCPlusTypeFlag, ppDefaultValue, pcchDefaultValue, pmdSetter, pmdGetter, rmdOtherMethod, cMax, pcOtherMethod)); + + IfFailRet((m_pWinMDAdapter->GetSignatureForToken<IMetaDataImport2, mdtProperty>( + prop, + &pOrigSig, // ppOrigSig + &cbOrigSigBlob, // pcbOrigSig + ppvSig, + pbSig, + m_pRawImport))); + // Return the success code from name filling (S_OK or CLDB_S_TRUNCATION) + return hrNameTruncation; + } + + + STDMETHODIMP GetParamProps( // S_OK or error. + mdParamDef tk, // [IN]The Parameter. + mdMethodDef *pmd, // [OUT] Parent Method token. + ULONG *pulSequence, // [OUT] Parameter sequence. + __out_ecount_part_opt(cchName, *pchName) + LPWSTR szName, // [OUT] Put name here. + ULONG cchName, // [OUT] Size of name buffer. + ULONG *pchName, // [OUT] Put actual size of name here. + DWORD *pdwAttr, // [OUT] Put flags here. + DWORD *pdwCPlusTypeFlag, // [OUT] Flag for value type. selected ELEMENT_TYPE_*. + UVCP_CONSTANT *ppValue, // [OUT] Constant value. + ULONG *pcchValue) // [OUT] size of constant string in chars, 0 for non-strings. + { + // Returns error code from name filling (may be CLDB_S_TRUNCTATION) + return m_pRawImport->GetParamProps(tk, pmd, pulSequence, szName, cchName, pchName, pdwAttr, pdwCPlusTypeFlag, ppValue, pcchValue); + } + + + STDMETHODIMP GetCustomAttributeByName( // S_OK or error. + mdToken tkObj, // [IN] Object with Custom Attribute. + LPCWSTR wszName, // [IN] Name of desired Custom Attribute. + const void **ppData, // [OUT] Put pointer to data here. + ULONG *pcbData) // [OUT] Put size of data here. + { + HRESULT hr; + if (wszName == NULL) + { + hr = S_FALSE; // Questionable response but maintains compatibility with RegMeta + } + else + { + MAKE_UTF8PTR_FROMWIDE_NOTHROW(szName, wszName); + IfNullGo(szName); + IfFailGo(CommonGetCustomAttributeByName(tkObj, szName, ppData, pcbData)); + } + ErrExit: + return hr; + } + + + STDMETHODIMP_(BOOL) IsValidToken( // True or False. + mdToken tk) // [IN] Given token. + { + mdToken tokenType = TypeFromToken(tk); + if (tokenType == mdtAssemblyRef) + return m_pWinMDAdapter->IsValidAssemblyRefToken(tk); + + return m_pRawImport->IsValidToken(tk); + } + + + STDMETHODIMP GetNestedClassProps( // S_OK or error. + mdTypeDef tdNestedClass, // [IN] NestedClass token. + mdTypeDef *ptdEnclosingClass) // [OUT] EnclosingClass token. + { + return m_pRawImport->GetNestedClassProps(tdNestedClass, ptdEnclosingClass); + } + + + STDMETHODIMP GetNativeCallConvFromSig( // S_OK or error. + void const *pvSig, // [IN] Pointer to signature. + ULONG cbSig, // [IN] Count of signature bytes. + ULONG *pCallConv) // [OUT] Put calling conv here (see CorPinvokemap). + { + return m_pRawImport->GetNativeCallConvFromSig(pvSig, cbSig, pCallConv); + } + + + STDMETHODIMP IsGlobal( // S_OK or error. + mdToken pd, // [IN] Type, Field, or Method token. + int *pbGlobal) // [OUT] Put 1 if global, 0 otherwise. + { + return m_pRawImport->IsGlobal(pd, pbGlobal); + } + + public: + + // ======================================================== + // IMetaDataWinMDImport methods + // ======================================================== + + // This method returns the RAW view of the metadata. Essentially removing the Adapter's projection support for the typeRef. + STDMETHODIMP GetUntransformedTypeRefProps( + mdTypeRef tr, // [IN] TypeRef token. + mdToken *ptkResolutionScope, // [OUT] Resolution scope, ModuleRef or AssemblyRef. + __out_ecount_part_opt(cchName, *pchName) + LPWSTR szName, // [OUT] Unprojected name of the TypeRef. + ULONG cchName, // [IN] Size of buffer. + ULONG *pchName) // [OUT] Size of Name. + { + // By-pass the call to the raw importer, removing the adapter layer. + return m_pRawImport->GetTypeRefProps(tr, ptkResolutionScope, szName, cchName, pchName); + } + + //========================================================= + // IMetaDataImport2 methods + //========================================================= + STDMETHODIMP EnumGenericParams( + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdToken tk, // [IN] TypeDef or MethodDef whose generic parameters are requested + mdGenericParam rGenericParams[], // [OUT] Put GenericParams here. + ULONG cMax, // [IN] Max GenericParams to put. + ULONG *pcGenericParams) // [OUT] Put # put here. + { + return m_pRawImport->EnumGenericParams(phEnum, tk, rGenericParams, cMax, pcGenericParams); + } + + + STDMETHODIMP GetGenericParamProps( // S_OK or error. + mdGenericParam gp, // [IN] GenericParam + ULONG *pulParamSeq, // [OUT] Index of the type parameter + DWORD *pdwParamFlags, // [OUT] Flags, for future use (e.g. variance) + mdToken *ptOwner, // [OUT] Owner (TypeDef or MethodDef) + DWORD *reserved, // [OUT] For future use (e.g. non-type parameters) + __out_ecount_part_opt(cchName, *pchName) + LPWSTR wzname, // [OUT] Put name here + ULONG cchName, // [IN] Size of buffer + ULONG *pchName) // [OUT] Put size of name (wide chars) here. + { + // Returns error code from name filling (may be CLDB_S_TRUNCTATION) + return m_pRawImport->GetGenericParamProps(gp, pulParamSeq, pdwParamFlags, ptOwner, reserved, wzname, cchName, pchName); + } + + + STDMETHODIMP GetMethodSpecProps( + mdMethodSpec mi, // [IN] The method instantiation + mdToken *tkParent, // [OUT] MethodDef or MemberRef + PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to the blob value of meta data + ULONG *pcbSigBlob) // [OUT] actual size of signature blob + { + HRESULT hr = S_OK; + + ULONG cbOrigSigBlob = (ULONG)(-1); + PCCOR_SIGNATURE pOrigSig = NULL; + IfFailRet(m_pRawImport->GetMethodSpecProps(mi, tkParent, &pOrigSig, &cbOrigSigBlob)); + + return m_pWinMDAdapter->GetSignatureForToken<IMetaDataImport2, mdtMethodSpec>( + mi, + &pOrigSig, // ppOrigSig + &cbOrigSigBlob, // pcbOrigSig + ppvSigBlob, + pcbSigBlob, + m_pRawImport); + } + + + STDMETHODIMP EnumGenericParamConstraints( + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdGenericParam tk, // [IN] GenericParam whose constraints are requested + mdGenericParamConstraint rGenericParamConstraints[], // [OUT] Put GenericParamConstraints here. + ULONG cMax, // [IN] Max GenericParamConstraints to put. + ULONG *pcGenericParamConstraints) // [OUT] Put # put here. + { + return m_pRawImport->EnumGenericParamConstraints(phEnum, tk, rGenericParamConstraints, cMax, pcGenericParamConstraints); + } + + + STDMETHODIMP GetGenericParamConstraintProps( // S_OK or error. + mdGenericParamConstraint gpc, // [IN] GenericParamConstraint + mdGenericParam *ptGenericParam, // [OUT] GenericParam that is constrained + mdToken *ptkConstraintType) // [OUT] TypeDef/Ref/Spec constraint + { + return m_pRawImport->GetGenericParamConstraintProps(gpc, ptGenericParam, ptkConstraintType); + } + + + STDMETHODIMP GetPEKind( // S_OK or error. + DWORD* pdwPEKind, // [OUT] The kind of PE (0 - not a PE) + DWORD* pdwMachine) // [OUT] Machine as defined in NT header + { + return m_pRawImport->GetPEKind(pdwPEKind, pdwMachine); + } + + + STDMETHODIMP GetVersionString( // S_OK or error. + __out_ecount_part_opt(ccBufSize, *pccBufSize) + LPWSTR pwzBuf, // [OUT] Put version string here. + DWORD ccBufSize, // [IN] size of the buffer, in wide chars + DWORD *pccBufSize) // [OUT] Size of the version string, wide chars, including terminating nul. + { + HRESULT hr; + LPCSTR szVersion; + IfFailRet(GetVersionString(&szVersion)); + // Returns error code from name filling (may be CLDB_S_TRUNCTATION) + return DeliverUtf8String(szVersion, pwzBuf, ccBufSize, pccBufSize); + } + + + STDMETHODIMP EnumMethodSpecs( + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdToken tk, // [IN] MethodDef or MemberRef whose MethodSpecs are requested + mdMethodSpec rMethodSpecs[], // [OUT] Put MethodSpecs here. + ULONG cMax, // [IN] Max tokens to put. + ULONG *pcMethodSpecs) // [OUT] Put actual count here. + { + return m_pRawImport->EnumMethodSpecs(phEnum, tk, rMethodSpecs, cMax, pcMethodSpecs); + } + + + public: + //========================================================= + // IMetaDataAssemblyImport methods + //========================================================= + + STDMETHODIMP GetAssemblyProps( // S_OK or error. + mdAssembly mda, // [IN] The Assembly for which to get the properties. + const void **ppbPublicKey, // [OUT] Pointer to the public key. + ULONG *pcbPublicKey, // [OUT] Count of bytes in the public key. + ULONG *pulHashAlgId, // [OUT] Hash Algorithm. + __out_ecount_part_opt(cchName, *pchName) LPWSTR szName, // [OUT] Buffer to fill with assembly's simply name. + ULONG cchName, // [IN] Size of buffer in wide chars. + ULONG *pchName, // [OUT] Actual # of wide chars in name. + ASSEMBLYMETADATA *pMetaData, // [OUT] Assembly MetaData. + DWORD *pdwAssemblyFlags) // [OUT] Flags. + { + return m_pRawAssemblyImport->GetAssemblyProps(mda, ppbPublicKey, pcbPublicKey, pulHashAlgId, szName, cchName, pchName, pMetaData, pdwAssemblyFlags); + } + + + STDMETHODIMP GetAssemblyRefProps( // S_OK or error. + mdAssemblyRef mdar, // [IN] The AssemblyRef for which to get the properties. + const void **ppbPublicKeyOrToken, // [OUT] Pointer to the public key or token. + ULONG *pcbPublicKeyOrToken, // [OUT] Count of bytes in the public key or token. + __out_ecount_part_opt(cchName, *pchName)LPWSTR szName, // [OUT] Buffer to fill with name. + ULONG cchName, // [IN] Size of buffer in wide chars. + ULONG *pchName, // [OUT] Actual # of wide chars in name. + ASSEMBLYMETADATA *pMetaData, // [OUT] Assembly MetaData. + const void **ppbHashValue, // [OUT] Hash blob. + ULONG *pcbHashValue, // [OUT] Count of bytes in the hash blob. + DWORD *pdwAssemblyRefFlags) // [OUT] Flags. + { + HRESULT hr; + HRESULT hrNameTruncation; + + if (!IsValidNonNilToken(mdar, mdtAssemblyRef)) + { + // Idiosyncratic edge cases - delegate straight through to inherit the correct idiosyncratic edge result + return m_pRawAssemblyImport->GetAssemblyRefProps(mdar, ppbPublicKeyOrToken, pcbPublicKeyOrToken, szName, cchName, pchName, pMetaData, ppbHashValue, pcbHashValue, pdwAssemblyRefFlags); + } + + mdAssemblyRef md = mdar; + if (RidFromToken(md) > m_pWinMDAdapter->GetRawAssemblyRefCount()) + { + // The extra framework assemblies we add references to should all have the + // same verion, key, culture, etc as those of mscorlib. + // So we retrieve the mscorlib properties and change the name. + md = m_pWinMDAdapter->GetAssemblyRefMscorlib(); + } + + IfFailRet(hrNameTruncation = m_pRawAssemblyImport->GetAssemblyRefProps(md, ppbPublicKeyOrToken, pcbPublicKeyOrToken, szName, cchName, pchName, pMetaData, ppbHashValue, pcbHashValue, pdwAssemblyRefFlags)); + + LPCSTR szNewName = nullptr; + USHORT *pusMajorVersion = nullptr; + USHORT *pusMinorVersion = nullptr; + USHORT *pusBuildNumber = nullptr; + USHORT *pusRevisionNumber = nullptr; + + if (pMetaData != nullptr) + { + pusMajorVersion = &pMetaData->usMajorVersion; + pusMinorVersion = &pMetaData->usMinorVersion; + pusBuildNumber = &pMetaData->usBuildNumber; + pusRevisionNumber = &pMetaData->usRevisionNumber; + } + + m_pWinMDAdapter->ModifyAssemblyRefProps( + mdar, + ppbPublicKeyOrToken, + pcbPublicKeyOrToken, + &szNewName, + pusMajorVersion, + pusMinorVersion, + pusBuildNumber, + pusRevisionNumber, + ppbHashValue, + pcbHashValue); + + if (szNewName != nullptr) + { + IfFailRet(hrNameTruncation = DeliverUtf8String(szNewName, szName, cchName, pchName)); + } + + // Return the success code from name filling (S_OK or CLDB_S_TRUNCATION) + return hrNameTruncation; + } + + + STDMETHODIMP GetFileProps( // S_OK or error. + mdFile mdf, // [IN] The File for which to get the properties. + __out_ecount_part_opt(cchName, *pchName) LPWSTR szName, // [OUT] Buffer to fill with name. + ULONG cchName, // [IN] Size of buffer in wide chars. + ULONG *pchName, // [OUT] Actual # of wide chars in name. + const void **ppbHashValue, // [OUT] Pointer to the Hash Value Blob. + ULONG *pcbHashValue, // [OUT] Count of bytes in the Hash Value Blob. + DWORD *pdwFileFlags) // [OUT] Flags. + { + // Returns error code from name filling (may be CLDB_S_TRUNCTATION) + return m_pRawAssemblyImport->GetFileProps(mdf, szName, cchName, pchName, ppbHashValue, pcbHashValue, pdwFileFlags); + } + + + STDMETHODIMP GetExportedTypeProps( // S_OK or error. + mdExportedType mdct, // [IN] The ExportedType for which to get the properties. + __out_ecount_part_opt(cchName, *pchName) LPWSTR szName, // [OUT] Buffer to fill with name. + ULONG cchName, // [IN] Size of buffer in wide chars. + ULONG *pchName, // [OUT] Actual # of wide chars in name. + mdToken *ptkImplementation, // [OUT] mdFile or mdAssemblyRef or mdExportedType. + mdTypeDef *ptkTypeDef, // [OUT] TypeDef token within the file. + DWORD *pdwExportedTypeFlags) // [OUT] Flags. + { + HRESULT hr; + LPCSTR szUtf8Namespace; + LPCSTR szUtf8Name; + if (!IsValidNonNilToken(mdct, mdtExportedType)) + { + // Idiosyncractic edge cases - delegate straight through to inherit the correct idiosyncractic edge results + return m_pRawAssemblyImport->GetExportedTypeProps(mdct, szName, cchName, pchName, ptkImplementation, ptkTypeDef, pdwExportedTypeFlags); + } + IfFailRet(m_pRawAssemblyImport->GetExportedTypeProps(mdct, NULL, 0, NULL, NULL, ptkTypeDef, pdwExportedTypeFlags)); + IfFailRet(this->CommonGetExportedTypeProps(mdct, &szUtf8Namespace, &szUtf8Name, ptkImplementation)); + // Returns error code from name filling (may be CLDB_S_TRUNCTATION) + return DeliverUtf8NamespaceAndName(szUtf8Namespace, szUtf8Name, szName, cchName, pchName); + } + + + STDMETHODIMP GetManifestResourceProps( // S_OK or error. + mdManifestResource mdmr, // [IN] The ManifestResource for which to get the properties. + __out_ecount_part_opt(cchName, *pchName)LPWSTR szName, // [OUT] Buffer to fill with name. + ULONG cchName, // [IN] Size of buffer in wide chars. + ULONG *pchName, // [OUT] Actual # of wide chars in name. + mdToken *ptkImplementation, // [OUT] mdFile or mdAssemblyRef that provides the ManifestResource. + DWORD *pdwOffset, // [OUT] Offset to the beginning of the resource within the file. + DWORD *pdwResourceFlags) // [OUT] Flags. + { + // Returns error code from name filling (may be CLDB_S_TRUNCTATION) + return m_pRawAssemblyImport->GetManifestResourceProps(mdmr, szName, cchName, pchName, ptkImplementation, pdwOffset, pdwResourceFlags); + } + + + STDMETHODIMP EnumAssemblyRefs( // S_OK or error + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdAssemblyRef rAssemblyRefs[], // [OUT] Put AssemblyRefs here. + ULONG cMax, // [IN] Max AssemblyRefs to put. + ULONG *pcTokens) // [OUT] Put # put here. + { + if (*phEnum != NULL) + { + // No trick needed: a previous call to EnumAssemblyRefs must have already taken care of the + // extra assembly refs. + return m_pRawAssemblyImport->EnumAssemblyRefs(phEnum, rAssemblyRefs, cMax, pcTokens); + } + else + { + // if *phEnum is NULL, we need create the HENUMInternal, adjust the assembly ref count, + // and enumerate the number of assembly refs requested. This is done in three steps: + HRESULT hr; + + // Step 1: Call EnumAssemblyRefs with an empty buffer to create the HENUMInternal + IfFailGo(m_pRawAssemblyImport->EnumAssemblyRefs(phEnum, NULL, 0, NULL)); + + // Step 2: Increment the cound to include the extra assembly refs + HENUMInternal *phInternalEnum = static_cast<HENUMInternal*>(*phEnum); + + _ASSERTE(phInternalEnum->m_EnumType == MDSimpleEnum); + + _ASSERTE( phInternalEnum->m_ulCount == m_pWinMDAdapter->GetRawAssemblyRefCount()); + int n = m_pWinMDAdapter->GetExtraAssemblyRefCount(); + phInternalEnum->m_ulCount += n; + phInternalEnum->u.m_ulEnd += n; + + // Step 3: Call EnumAssemblyRefs again and pass in the modifed HENUMInternal and the real buffer + IfFailGo(m_pRawAssemblyImport->EnumAssemblyRefs(phEnum, rAssemblyRefs, cMax, pcTokens)); + +ErrExit: + return hr; + } + } + + + STDMETHODIMP EnumFiles( // S_OK or error + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdFile rFiles[], // [OUT] Put Files here. + ULONG cMax, // [IN] Max Files to put. + ULONG *pcTokens) // [OUT] Put # put here. + { + return m_pRawAssemblyImport->EnumFiles(phEnum, rFiles, cMax, pcTokens); + } + + + STDMETHODIMP EnumExportedTypes( // S_OK or error + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdExportedType rExportedTypes[], // [OUT] Put ExportedTypes here. + ULONG cMax, // [IN] Max ExportedTypes to put. + ULONG *pcTokens) // [OUT] Put # put here. + { + return m_pRawAssemblyImport->EnumExportedTypes(phEnum, rExportedTypes, cMax, pcTokens); + } + + + STDMETHODIMP EnumManifestResources( // S_OK or error + HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. + mdManifestResource rManifestResources[], // [OUT] Put ManifestResources here. + ULONG cMax, // [IN] Max Resources to put. + ULONG *pcTokens) // [OUT] Put # put here. + { + return m_pRawAssemblyImport->EnumManifestResources(phEnum, rManifestResources, cMax, pcTokens); + } + + + STDMETHODIMP GetAssemblyFromScope( // S_OK or error + mdAssembly *ptkAssembly) // [OUT] Put token here. + { + return m_pRawAssemblyImport->GetAssemblyFromScope(ptkAssembly); + } + + + STDMETHODIMP FindExportedTypeByName( // S_OK or error + LPCWSTR wszName, // [IN] Name of the ExportedType. + mdToken mdtExportedType, // [IN] ExportedType for the enclosing class. + mdExportedType *ptkExportedType) // [OUT] Put the ExportedType token here. + { + if (wszName == NULL) + return E_INVALIDARG; + + LPUTF8 szFullName; + LPCUTF8 szNamespace; + LPCUTF8 szName; + // Convert the name to UTF8. + UTF8STR(wszName, szFullName); + ns::SplitInline(szFullName, szNamespace, szName); + return this->CommonFindExportedType(szNamespace, szName, mdtExportedType, ptkExportedType); + } + + + STDMETHODIMP FindManifestResourceByName( // S_OK or error + LPCWSTR szName, // [IN] Name of the ManifestResource. + mdManifestResource *ptkManifestResource) // [OUT] Put the ManifestResource token here. + { + return m_pRawAssemblyImport->FindManifestResourceByName(szName, ptkManifestResource); + } + + + + STDMETHODIMP FindAssembliesByName( // S_OK or error + LPCWSTR szAppBase, // [IN] optional - can be NULL + LPCWSTR szPrivateBin, // [IN] optional - can be NULL + LPCWSTR szAssemblyName, // [IN] required - this is the assembly you are requesting + IUnknown *ppIUnk[], // [OUT] put IMetaDataAssemblyImport pointers here + ULONG cMax, // [IN] The max number to put + ULONG *pcAssemblies) // [OUT] The number of assemblies returned. + { + return m_pRawAssemblyImport->FindAssembliesByName(szAppBase, szPrivateBin, szAssemblyName, ppIUnk, cMax, pcAssemblies); + } + + //========================================================= + // IMetaDataValidate + //========================================================= + STDMETHODIMP ValidatorInit( // S_OK or error. + DWORD dwModuleType, // [IN] Specifies the type of the module. + IUnknown *pUnk) // [IN] Validation error handler. + { + if (m_pRawValidate == nullptr) + return E_NOTIMPL; + + return m_pRawValidate->ValidatorInit(dwModuleType, pUnk); + } + + STDMETHODIMP ValidateMetaData() // S_OK or error. + { + if (m_pRawValidate == nullptr) + return E_NOTIMPL; + + return m_pRawValidate->ValidateMetaData(); + } + + //========================================================= + // IMDCommon methods + //========================================================= + STDMETHODIMP_(IMetaModelCommon*) GetMetaModelCommon() + { + return this; + } + + STDMETHODIMP_(IMetaModelCommonRO*) GetMetaModelCommonRO() + { + _ASSERTE(!"WinMDImport does not support GetMetaModelCommonRO(). The most likely cause of this assert is that you're trying to wrap a WinMD adapter around another WinMD adapter."); + return NULL; + } + + STDMETHODIMP GetVersionString(LPCSTR *pszVersionString) + { + return m_pWinMDAdapter->GetVersionString(pszVersionString); + } + + + //========================================================= + // IMetaModelCommon methods + //========================================================= + __checkReturn + virtual HRESULT CommonGetScopeProps( + LPCUTF8 *pszName, + GUID *pMvid) + { + return m_pRawMetaModelCommonRO->CommonGetScopeProps(pszName, pMvid); + } + + __checkReturn + virtual HRESULT CommonGetTypeRefProps( + mdTypeRef tr, + LPCUTF8 *pszNamespace, + LPCUTF8 *pszName, + mdToken *ptkResolution) + { + return m_pWinMDAdapter->GetTypeRefProps(tr, pszNamespace, pszName, ptkResolution); + } + + + __checkReturn + virtual HRESULT CommonGetTypeDefProps( + mdTypeDef td, + LPCUTF8 *pszNameSpace, + LPCUTF8 *pszName, + DWORD *pdwFlags, + mdToken *pdwExtends, + ULONG *pMethodList) + { + HRESULT hr; + IfFailGo(m_pRawMetaModelCommonRO->CommonGetTypeDefProps(td, NULL, NULL, NULL, NULL, pMethodList)); + IfFailGo(m_pWinMDAdapter->GetTypeDefProps(td, pszNameSpace, pszName, pdwFlags, pdwExtends)); + ErrExit: + return hr; + } + + + __checkReturn + virtual HRESULT CommonGetTypeSpecProps( + mdTypeSpec ts, + PCCOR_SIGNATURE *ppvSig, + ULONG *pcbSig) + { + return m_pWinMDAdapter->GetSignatureForToken<IMetaDataImport2, mdtTypeSpec>( + ts, + NULL, // ppOrigSig + NULL, // pcbOrigSig + ppvSig, + pcbSig, + m_pRawImport); + } + + + __checkReturn + virtual HRESULT CommonGetEnclosingClassOfTypeDef( + mdTypeDef td, + mdTypeDef *ptkEnclosingTypeDef) + { + return m_pRawMetaModelCommonRO->CommonGetEnclosingClassOfTypeDef(td, ptkEnclosingTypeDef); + } + + + __checkReturn + virtual HRESULT CommonGetAssemblyProps( + USHORT *pusMajorVersion, + USHORT *pusMinorVersion, + USHORT *pusBuildNumber, + USHORT *pusRevisionNumber, + DWORD *pdwFlags, + const void **ppbPublicKey, + ULONG *pcbPublicKey, + LPCUTF8 *pszName, + LPCUTF8 *pszLocale) + { + return m_pRawMetaModelCommonRO->CommonGetAssemblyProps(pusMajorVersion, pusMinorVersion, pusBuildNumber, pusRevisionNumber, pdwFlags, ppbPublicKey, pcbPublicKey, pszName, pszLocale); + } + + + __checkReturn + virtual HRESULT CommonGetAssemblyRefProps( + mdAssemblyRef tkAssemRef, + USHORT *pusMajorVersion, + USHORT *pusMinorVersion, + USHORT *pusBuildNumber, + USHORT *pusRevisionNumber, + DWORD *pdwFlags, + const void **ppbPublicKeyOrToken, + ULONG *pcbPublicKeyOrToken, + LPCUTF8 *pszName, + LPCUTF8 *pszLocale, + const void **ppbHashValue, + ULONG *pcbHashValue) + { + HRESULT hr; + + mdAssemblyRef md = tkAssemRef; + if (RidFromToken(md) > m_pWinMDAdapter->GetRawAssemblyRefCount()) + { + // The extra framework assemblies we add references to should all have the + // same verion, key, culture, etc as those of mscorlib. + // So we retrieve the mscorlib properties and change the name. + md = m_pWinMDAdapter->GetAssemblyRefMscorlib(); + } + + IfFailRet(m_pRawMetaModelCommonRO->CommonGetAssemblyRefProps( + md, + pusMajorVersion, + pusMinorVersion, + pusBuildNumber, + pusRevisionNumber, + pdwFlags, + ppbPublicKeyOrToken, + pcbPublicKeyOrToken, + pszName, + pszLocale, + ppbHashValue, + pcbHashValue)); + + m_pWinMDAdapter->ModifyAssemblyRefProps( + tkAssemRef, + ppbPublicKeyOrToken, + pcbPublicKeyOrToken, + pszName, + pusMajorVersion, + pusMinorVersion, + pusBuildNumber, + pusRevisionNumber, + ppbHashValue, + pcbHashValue); + + return hr; + } + + + __checkReturn + virtual HRESULT CommonGetModuleRefProps( + mdModuleRef tkModuleRef, + LPCUTF8 *pszName) + { + return m_pRawMetaModelCommonRO->CommonGetModuleRefProps(tkModuleRef, pszName); + } + + + __checkReturn + virtual HRESULT CommonFindExportedType( + LPCUTF8 szNamespace, + LPCUTF8 szName, + mdToken tkEnclosingType, + mdExportedType *ptkExportedType) + { + return m_pWinMDAdapter->FindExportedType(szNamespace, szName, tkEnclosingType, ptkExportedType); + } + + + __checkReturn + virtual HRESULT CommonGetExportedTypeProps( + mdToken tkExportedType, + LPCUTF8 *pszNamespace, + LPCUTF8 *pszName, + mdToken *ptkImpl) + { + HRESULT hr; + IfFailRet(m_pRawMetaModelCommonRO->CommonGetExportedTypeProps(tkExportedType, pszNamespace, pszName, ptkImpl)); + IfFailRet(m_pWinMDAdapter->ModifyExportedTypeName(tkExportedType, pszNamespace, pszName)); + return hr; + } + + + virtual int CommonIsRo() + { + return m_pRawMetaModelCommonRO->CommonIsRo(); + } + + + __checkReturn + virtual HRESULT CommonGetCustomAttributeByNameEx( // 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. + { + return m_pWinMDAdapter->GetCustomAttributeByName(tkObj, szName, ptkCA, ppData, pcbData); + } + + + __checkReturn + virtual HRESULT FindParentOfMethodHelper(mdMethodDef md, mdTypeDef *ptd) + { + return m_pRawMetaModelCommonRO->FindParentOfMethodHelper(md, ptd); + } + + + + public: + //========================================================= + // IGetIMDInternalImport methods + //========================================================= + STDMETHODIMP GetIMDInternalImport(IMDInternalImport ** ppIMDInternalImport) + { + HRESULT hr = S_OK; + ReleaseHolder<IMDCommon> pMDCommon; + ReleaseHolder<IUnknown> pRawMDInternalImport; + + *ppIMDInternalImport = NULL; + // Get the raw IMDInternalImport + IfFailGo(GetMDInternalInterfaceFromPublic(m_pRawImport, IID_IMDInternalImport, (LPVOID*)(&pRawMDInternalImport))); + + // Create an adapter around the internal raw interface + IfFailGo(pRawMDInternalImport->QueryInterface(IID_IMDCommon, (LPVOID*)(&pMDCommon))); + IfFailGo(CreateWinMDInternalImportRO(pMDCommon, IID_IMDInternalImport, (void**)ppIMDInternalImport)); + + ErrExit: + return hr; + } + + + //========================================================= + // Private methods + //========================================================= + + //------------------------------------------------------------------------------------------------------ + // Deliver a result string (Unicode) to a caller's sized output buffer using the standard convention + // followed by all metadata api. + //------------------------------------------------------------------------------------------------------ + static HRESULT DeliverUnicodeString(LPCWSTR wszResult, __out_ecount_part(cchCallerBuffer, *pchSizeNeeded) LPWSTR wszCallerBuffer, ULONG cchCallerBuffer, ULONG *pchSizeNeeded) + { + ULONG cchActual = (ULONG)(wcslen(wszResult) + 1); + if (pchSizeNeeded) + { + *pchSizeNeeded = cchActual; + } + if (wszCallerBuffer == NULL || cchCallerBuffer < cchActual) + { + if (wszCallerBuffer != NULL) + { + memcpy(wszCallerBuffer, wszResult, cchCallerBuffer * sizeof(WCHAR)); // If buffer too small, return truncated result to be compatible with metadata api conventions + if (cchCallerBuffer > 0) + { // null-terminate the truncated output string + wszCallerBuffer[cchCallerBuffer - 1] = W('\0'); + } + } + return CLDB_S_TRUNCATION; + } + else + { + memcpy(wszCallerBuffer, wszResult, cchActual * sizeof(WCHAR)); + return S_OK; + } + } + + //------------------------------------------------------------------------------------------------------ + // Deliver a result string (Utf8) to a caller's sized output buffer using the standard convention + // followed by all metadata api. + //------------------------------------------------------------------------------------------------------ + static HRESULT DeliverUtf8String(LPCSTR szUtf8Result, __out_ecount_part(cchCallerBuffer, *pchSizeNeeded) LPWSTR wszCallerBuffer, ULONG cchCallerBuffer, ULONG *pchSizeNeeded) + { + MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzResult, szUtf8Result); + if (wzResult == NULL) + return E_OUTOFMEMORY; + return DeliverUnicodeString(wzResult, wszCallerBuffer, cchCallerBuffer, pchSizeNeeded); + } + + //------------------------------------------------------------------------------------------------------ + // Combine a result namespace/name string pair (Utf8) to a Unicode fullname and deliver to a caller's + // sized output buffer using the standard convention followed by all metadata api. + //------------------------------------------------------------------------------------------------------ + static HRESULT DeliverUtf8NamespaceAndName(LPCSTR szUtf8Namespace, LPCSTR szUtf8Name, __out_ecount_part(cchCallerBuffer, *pchSizeNeeded) LPWSTR wszCallerBuffer, ULONG cchCallerBuffer, ULONG *pchSizeNeeded) + { + HRESULT hr; + if (wszCallerBuffer != NULL || pchSizeNeeded != NULL) + { + MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzNamespace, szUtf8Namespace); + IfNullRet(wzNamespace); + MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzName, szUtf8Name); + IfNullRet(wzName); + + BOOL fTruncation = FALSE; + if (wszCallerBuffer != NULL) + { + fTruncation = !(ns::MakePath(wszCallerBuffer, cchCallerBuffer, wzNamespace, wzName)); + if (fTruncation && (cchCallerBuffer > 0)) + { // null-terminate the truncated output string + wszCallerBuffer[cchCallerBuffer - 1] = W('\0'); + } + } + if (pchSizeNeeded != NULL) + { + if (fTruncation || (wszCallerBuffer == NULL)) + { + *pchSizeNeeded = ns::GetFullLength(wzNamespace, wzName); + } + else + { + *pchSizeNeeded = (ULONG)(wcslen(wszCallerBuffer) + 1); + } + } + hr = fTruncation ? CLDB_S_TRUNCATION : S_OK; + } + else + { + hr = S_OK; // Caller did not request name back. + } + return hr; + } + + private: + //========================================================= + // Private instance data + //========================================================= + IMDCommon *m_pRawMDCommon; + IMetaDataImport2 *m_pRawImport; + IMetaDataAssemblyImport *m_pRawAssemblyImport; + IMetaDataValidate *m_pRawValidate; + IMetaModelCommonRO *m_pRawMetaModelCommonRO; + IUnknown *m_pFreeThreadedMarshaler; + WinMDAdapter *m_pWinMDAdapter; + LONG m_cRef; + +}; // class WinMDImport + + + +//======================================================================================== +// Entrypoint called by IMetaDataDispenser::OpenScope() +//======================================================================================== +HRESULT CreateWinMDImport(IMDCommon * pRawMDCommon, REFIID riid, /*[out]*/ void **ppWinMDImport) +{ + HRESULT hr; + *ppWinMDImport = NULL; + WinMDImport *pWinMDImport = NULL; + IfFailGo(WinMDImport::Create(pRawMDCommon, &pWinMDImport)); + IfFailGo(pWinMDImport->QueryInterface(riid, ppWinMDImport)); + hr = S_OK; + ErrExit: + if (pWinMDImport) + pWinMDImport->Release(); + return hr; +} diff --git a/src/md/winmd/winmdinternalimportro.cpp b/src/md/winmd/winmdinternalimportro.cpp new file mode 100644 index 0000000000..70a54b88b3 --- /dev/null +++ b/src/md/winmd/winmdinternalimportro.cpp @@ -0,0 +1,1804 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + + + +#include "stdafx.h" +#include "winmdinterfaces.h" +#include "inc/adapter.h" + + +#ifdef FEATURE_METADATA_INTERNAL_APIS + + +__checkReturn +HRESULT TranslateSigHelper( // S_OK or error. + IMDInternalImport *pImport, // [IN] import scope. + IMDInternalImport *pAssemImport, // [IN] import assembly scope. + const void *pbHashValue, // [IN] hash value for the import assembly. + ULONG cbHashValue, // [IN] count of bytes in the hash value. + PCCOR_SIGNATURE pbSigBlob, // [IN] signature in the importing scope + ULONG cbSigBlob, // [IN] count of bytes of signature + IMetaDataAssemblyEmit *pAssemEmit, // [IN] assembly emit scope. + IMetaDataEmit *emit, // [IN] emit interface + CQuickBytes *pqkSigEmit, // [OUT] buffer to hold translated signature + ULONG *pcbSig); // [OUT] count of bytes in the translated signature + + +//======================================================================================== +// This metadata importer is used internally by the runtime and exposes an +// IMDInternalImport* on .winmd files. It applies a small number of on-the-fly +// conversions to make the .winmd file look like a regular .NET assembly. +// +// All those places in src\vm where the runtime calls an IMDInternalImport* +// pointer, it may now be talking to a WinMDInternalImportRO. Ideally, the +// runtime will never know the difference (but this being an internal interface, +// we may tolerate the occasional leakiness in the name of expediency.) +//======================================================================================== +class WinMDInternalImportRO : public IMDInternalImport, IWinMDImport, IMetaModelCommon +{ + public: + //========================================================= + // Factory + //========================================================= + static HRESULT Create(IMDCommon *pRawMDCommon, WinMDInternalImportRO **ppWinMDInternalImportRO) + { + HRESULT hr; + *ppWinMDInternalImportRO = NULL; + WinMDInternalImportRO *pNewWinMDInternalImport = new (nothrow) WinMDInternalImportRO(pRawMDCommon); + IfFailGo(pRawMDCommon->QueryInterface(IID_IMDInternalImport, (void**)&(pNewWinMDInternalImport->m_pRawInternalImport))); + IfFailGo(WinMDAdapter::Create(pNewWinMDInternalImport->m_pRawMDCommon, &(pNewWinMDInternalImport->m_pWinMDAdapter))); + (*ppWinMDInternalImportRO = pNewWinMDInternalImport)->AddRef(); + hr = S_OK; + + ErrExit: + if (pNewWinMDInternalImport) + pNewWinMDInternalImport->Release(); + return hr; + } + + private: + //========================================================= + // Ctors, Dtors + //========================================================= + WinMDInternalImportRO(IMDCommon * pRawMDCommon) + : m_cRef(1) + , m_pWinMDAdapter(NULL) + , m_pRawInternalImport(NULL) + , m_pRawMDCommon(pRawMDCommon) + , m_pRawMetaModelCommon(pRawMDCommon->GetMetaModelCommon()) + { + m_pRawMDCommon->AddRef(); + } + + //--------------------------------------------------------- + ~WinMDInternalImportRO() + { + m_pRawMDCommon->Release(); + m_pRawInternalImport->Release(); + delete m_pWinMDAdapter; + } + + public: + //========================================================= + // IUnknown methods + //========================================================= + STDMETHODIMP QueryInterface(REFIID riid, void** ppUnk) + { + *ppUnk = 0; + if (riid == IID_IUnknown || riid == IID_IWinMDImport) + *ppUnk = (IWinMDImport *) this; + else if (riid == IID_IMDInternalImport) + *ppUnk = (IMDInternalImport *) this; + else + { +#ifndef DACCESS_COMPILE +#ifdef _DEBUG + if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_WinMD_AssertOnIllegalUsage)) + { + if (riid == IID_IMDInternalImportENC) + _ASSERTE(!"WinMDInternalImportRO::QueryInterface(IID_IMDInternalImportENC) returning E_NOINTERFACE"); + else if (riid == IID_IMarshal) + _ASSERTE(!"WinMDInternalImportRO::QueryInterface(IID_IMarshal) returning E_NOINTERFACE"); + else + _ASSERTE(!"WinMDInternalImportRO::QueryInterface() returning E_NOINTERFACE"); + } +#endif //_DEBUG +#endif + return E_NOINTERFACE; + } + AddRef(); + return S_OK; + } + //--------------------------------------------------------- + STDMETHODIMP_(ULONG) AddRef(void) + { + return InterlockedIncrement(&m_cRef); + } + //--------------------------------------------------------- + STDMETHODIMP_(ULONG) Release(void) + { + ULONG cRef = InterlockedDecrement(&m_cRef); + if (!cRef) + delete this; + return cRef; + } + + public: + //========================================================= + // IWinMDImport methods + //========================================================= + STDMETHODIMP IsScenarioWinMDExp(BOOL *pbResult) + { + if (pbResult == NULL) + return E_POINTER; + + *pbResult = m_pWinMDAdapter->IsScenarioWinMDExp(); + return S_OK; + } + + STDMETHODIMP IsRuntimeClassImplementation(mdTypeDef tkTypeDef, BOOL *pbResult) + { + if (pbResult == NULL) + return E_POINTER; + + return m_pWinMDAdapter->IsRuntimeClassImplementation(tkTypeDef, pbResult); + } + + //========================================================= + // IMDInternalImport methods + //========================================================= + //***************************************************************************** + // return the count of entries of a given kind in a scope + // For example, pass in mdtMethodDef will tell you how many MethodDef + // contained in a scope + //***************************************************************************** + STDMETHODIMP_(ULONG) GetCountWithTokenKind(// return hresult + DWORD tkKind) // [IN] pass in the kind of token. + { + if (tkKind == mdtAssemblyRef) + { + return m_pRawInternalImport->GetCountWithTokenKind(tkKind) + m_pWinMDAdapter->GetExtraAssemblyRefCount(); + } + else + { + return m_pRawInternalImport->GetCountWithTokenKind(tkKind); + } + } + + //***************************************************************************** + // enumerator for typedef + //***************************************************************************** + __checkReturn + STDMETHODIMP EnumTypeDefInit( // return hresult + HENUMInternal *phEnum) // [OUT] buffer to fill for enumerator data + { + return m_pRawInternalImport->EnumTypeDefInit(phEnum); + } + + STDMETHODIMP_(ULONG) EnumTypeDefGetCount( + HENUMInternal *phEnum) // [IN] the enumerator to retrieve information + { + return m_pRawInternalImport->EnumTypeDefGetCount(phEnum); + } + + STDMETHODIMP_(void) EnumTypeDefReset( + HENUMInternal *phEnum) // [IN] the enumerator to retrieve information + { + return m_pRawInternalImport->EnumTypeDefReset(phEnum); + } + + STDMETHODIMP_(bool) EnumTypeDefNext( // return hresult + HENUMInternal *phEnum, // [IN] input enum + mdTypeDef *ptd) // [OUT] return token + { + return m_pRawInternalImport->EnumTypeDefNext(phEnum, ptd); + } + + STDMETHODIMP_(void) EnumTypeDefClose( + HENUMInternal *phEnum) // [IN] the enumerator to retrieve information + { + return m_pRawInternalImport->EnumTypeDefClose(phEnum); + } + + //***************************************************************************** + // enumerator for MethodImpl + //***************************************************************************** + __checkReturn + STDMETHODIMP EnumMethodImplInit( // return hresult + mdTypeDef td, // [IN] TypeDef over which to scope the enumeration. + HENUMInternal *phEnumBody, // [OUT] buffer to fill for enumerator data for MethodBody tokens. + HENUMInternal *) // [OUT] used only on RW imports + { + HRESULT hr; + HENUMInternal::InitDynamicArrayEnum(phEnumBody); + phEnumBody->m_tkKind = TBL_MethodImpl << 24; + IfFailGo(m_pWinMDAdapter->AddMethodImplsToEnum(td, phEnumBody)); + hr = S_OK; + + ErrExit: + if (FAILED(hr)) + { + HENUMInternal::ClearEnum(phEnumBody); + INDEBUG(memset(phEnumBody, 0xcc, sizeof(HENUMInternal))); + } + return hr; + } + + STDMETHODIMP_(ULONG) EnumMethodImplGetCount( + HENUMInternal *phEnumBody, // [IN] MethodBody enumerator. + HENUMInternal *) // [IN] used only on RW imports + + { + return phEnumBody->m_ulCount / 2; + } + + STDMETHODIMP_(void) EnumMethodImplReset( + HENUMInternal *phEnumBody, // [IN] MethodBody enumerator. + HENUMInternal *) // [IN] used only on RW imports + { + phEnumBody->u.m_ulCur = phEnumBody->u.m_ulStart; + return; + } + + __checkReturn + STDMETHODIMP EnumMethodImplNext( // return hresult (S_OK = TRUE, S_FALSE = FALSE or error code) + HENUMInternal *phEnumBody, // [IN] input enum for MethodBody + HENUMInternal *, // [IN] used only on RW imports + mdToken *ptkBody, // [OUT] return token for MethodBody + mdToken *ptkDecl) // [OUT] return token for MethodDecl + { + _ASSERTE(ptkBody && ptkDecl); + return HENUMInternal::EnumWithCount(phEnumBody, 1, ptkBody, ptkDecl, NULL); + } + + STDMETHODIMP_(void) EnumMethodImplClose( + HENUMInternal *phEnumBody, // [IN] MethodBody enumerator. + HENUMInternal *) // [IN] used only on RW imports + { + HENUMInternal::ClearEnum(phEnumBody); + } + + //***************************************** + // Enumerator helpers for memberdef, memberref, interfaceimp, + // event, property, exception, param + //***************************************** + + __checkReturn + STDMETHODIMP EnumGlobalFunctionsInit( // return hresult + HENUMInternal *phEnum) // [OUT] buffer to fill for enumerator data + { + return m_pRawInternalImport->EnumGlobalFunctionsInit(phEnum); + } + + __checkReturn + STDMETHODIMP EnumGlobalFieldsInit( // return hresult + HENUMInternal *phEnum) // [OUT] buffer to fill for enumerator data + { + return m_pRawInternalImport->EnumGlobalFieldsInit(phEnum); + } + + __checkReturn + STDMETHODIMP EnumInit( // return S_FALSE if record not found + DWORD tkKind, // [IN] which table to work on + mdToken tkParent, // [IN] token to scope the search + HENUMInternal *phEnum) // [OUT] the enumerator to fill + { + if (tkKind == (TBL_MethodImpl << 24)) + return EnumMethodImplInit(tkParent, phEnum, NULL); + + HRESULT hr; + IfFailGo(m_pRawInternalImport->EnumInit(tkKind, tkParent, phEnum)); + + _ASSERTE(phEnum->m_EnumType == MDSimpleEnum); + + if (tkKind == mdtAssemblyRef) + { + _ASSERTE( phEnum->m_ulCount == m_pWinMDAdapter->GetRawAssemblyRefCount()); + int n = m_pWinMDAdapter->GetExtraAssemblyRefCount(); + phEnum->m_ulCount += n; + phEnum->u.m_ulEnd += n; + } + + +ErrExit: + return hr; + } + + __checkReturn + STDMETHODIMP EnumAllInit( // return S_FALSE if record not found + DWORD tkKind, // [IN] which table to work on + HENUMInternal *phEnum) // [OUT] the enumerator to fill + { + HRESULT hr; + IfFailGo(m_pRawInternalImport->EnumAllInit(tkKind, phEnum)); + + _ASSERTE(phEnum->m_EnumType == MDSimpleEnum); + + if (tkKind == mdtAssemblyRef) + { + _ASSERTE( phEnum->m_ulCount == m_pWinMDAdapter->GetRawAssemblyRefCount()); + int n = m_pWinMDAdapter->GetExtraAssemblyRefCount(); + phEnum->m_ulCount += n; + phEnum->u.m_ulEnd += n; + } + +ErrExit: + return hr; + } + + STDMETHODIMP_(bool) EnumNext( + HENUMInternal *phEnum, // [IN] the enumerator to retrieve information + mdToken *ptk) // [OUT] token to scope the search + { + return m_pRawInternalImport->EnumNext(phEnum, ptk); + } + + STDMETHODIMP_(ULONG) EnumGetCount( + HENUMInternal *phEnum) // [IN] the enumerator to retrieve information + { + return m_pRawInternalImport->EnumGetCount(phEnum); + } + + STDMETHODIMP_(void) EnumReset( + HENUMInternal *phEnum) // [IN] the enumerator to be reset + { + return m_pRawInternalImport->EnumReset(phEnum); + } + + STDMETHODIMP_(void) EnumClose( + HENUMInternal *phEnum) // [IN] the enumerator to be closed + { + return m_pRawInternalImport->EnumClose(phEnum); + } + + //***************************************** + // Enumerator helpers for declsecurity. + //***************************************** + __checkReturn + STDMETHODIMP EnumPermissionSetsInit( // return S_FALSE if record not found + mdToken tkParent, // [IN] token to scope the search + CorDeclSecurity Action, // [IN] Action to scope the search + HENUMInternal *phEnum) // [OUT] the enumerator to fill + { + return m_pRawInternalImport->EnumPermissionSetsInit(tkParent, Action, phEnum); + } + + //***************************************** + // Enumerator helpers for CustomAttribute + //***************************************** + __checkReturn + STDMETHODIMP EnumCustomAttributeByNameInit(// return S_FALSE if record not found + mdToken tkParent, // [IN] token to scope the search + LPCSTR szName, // [IN] CustomAttribute's name to scope the search + HENUMInternal *phEnum) // [OUT] the enumerator to fill + { + WinMDAdapter::ConvertWellKnownTypeNameFromClrToWinRT(&szName); + return m_pRawInternalImport->EnumCustomAttributeByNameInit(tkParent, szName, phEnum); + } + + //***************************************** + // Nagivator helper to navigate back to the parent token given a token. + // For example, given a memberdef token, it will return the containing typedef. + // + // the mapping is as following: + // ---given child type---------parent type + // mdMethodDef mdTypeDef + // mdFieldDef mdTypeDef + // mdInterfaceImpl mdTypeDef + // mdParam mdMethodDef + // mdProperty mdTypeDef + // mdEvent mdTypeDef + // + //***************************************** + __checkReturn + STDMETHODIMP GetParentToken( + mdToken tkChild, // [IN] given child token + mdToken *ptkParent) // [OUT] returning parent + { + return m_pRawInternalImport->GetParentToken(tkChild, ptkParent); + } + + //***************************************** + // Custom value helpers + //***************************************** + __checkReturn + STDMETHODIMP GetCustomAttributeProps( // S_OK or error. + mdCustomAttribute at, // [IN] The attribute. + mdToken *ptkType) // [OUT] Put attribute type here. + { + return m_pRawInternalImport->GetCustomAttributeProps(at, ptkType); + } + + __checkReturn + STDMETHODIMP GetCustomAttributeAsBlob( + mdCustomAttribute cv, // [IN] given custom value token + void const **ppBlob, // [OUT] return the pointer to internal blob + ULONG *pcbSize) // [OUT] return the size of the blob + { + return m_pWinMDAdapter->GetCustomAttributeBlob(cv, ppBlob, pcbSize); + } + + // returned void in v1.0/v1.1 + __checkReturn + STDMETHODIMP GetScopeProps( + LPCSTR *pszName, // [OUT] scope name + GUID *pmvid) // [OUT] version id + { + return m_pRawInternalImport->GetScopeProps(pszName, pmvid); + } + + // The default signature comparison function. + static BOOL CompareSignatures(PCCOR_SIGNATURE pvFirstSigBlob, // First signature + DWORD cbFirstSigBlob, // + PCCOR_SIGNATURE pvSecondSigBlob, // Second signature + DWORD cbSecondSigBlob, // + void * SigArguments) // No additional arguments required + { + if (cbFirstSigBlob != cbSecondSigBlob || memcmp(pvFirstSigBlob, pvSecondSigBlob, cbSecondSigBlob)) + return FALSE; + else + return TRUE; + } + + // finding a particular method + __checkReturn + STDMETHODIMP FindMethodDef( + mdTypeDef classdef, // [IN] given typedef + LPCSTR szName, // [IN] member name + PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of CLR signature + ULONG cbSigBlob, // [IN] count of bytes in the signature blob + mdMethodDef *pmd) // [OUT] matching memberdef + { + return FindMethodDefUsingCompare(classdef, + szName, + pvSigBlob, + cbSigBlob, + CompareSignatures, + NULL, + pmd); + } + + // return a iSeq's param given a MethodDef + __checkReturn + STDMETHODIMP FindParamOfMethod( // S_OK or error. + mdMethodDef md, // [IN] The owning method of the param. + ULONG iSeq, // [IN] The sequence # of the param. + mdParamDef *pparamdef) // [OUT] Put ParamDef token here. + { + return m_pRawInternalImport->FindParamOfMethod(md, iSeq, pparamdef); + } + + //***************************************** + // + // GetName* functions + // + //***************************************** + + // return the name and namespace of typedef + __checkReturn + STDMETHODIMP GetNameOfTypeDef( + mdTypeDef classdef, // given classdef + LPCSTR *pszname, // return class name(unqualified) + LPCSTR *psznamespace) // return the name space name + { + if (TypeFromToken(classdef) != mdtTypeDef) + return CLDB_E_INTERNALERROR; + + HRESULT hr; + IfFailRet(m_pWinMDAdapter->GetTypeDefProps(classdef, psznamespace, pszname, NULL, NULL)); + return hr; + } + + __checkReturn + STDMETHODIMP GetIsDualOfTypeDef( + mdTypeDef classdef, // [IN] given classdef. + ULONG *pDual) // [OUT] return dual flag here. + { + return m_pRawInternalImport->GetIsDualOfTypeDef(classdef, pDual); + } + + __checkReturn + STDMETHODIMP GetIfaceTypeOfTypeDef( + mdTypeDef classdef, // [IN] given classdef. + ULONG *pIface) // [OUT] 0=dual, 1=vtable, 2=dispinterface + { + return m_pRawInternalImport->GetIfaceTypeOfTypeDef(classdef, pIface); + } + + // get the name of either methoddef + __checkReturn + STDMETHODIMP GetNameOfMethodDef( // return the name of the memberdef in UTF8 + mdMethodDef md, // given memberdef + LPCSTR *pszName) + { + HRESULT hr = S_OK; + IfFailRet(m_pRawInternalImport->GetNameOfMethodDef(md, pszName)); + return m_pWinMDAdapter->ModifyMethodProps(md, NULL, NULL, NULL, pszName); + } + + __checkReturn + STDMETHODIMP GetNameAndSigOfMethodDef( + mdMethodDef methoddef, // [IN] given memberdef + PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to a blob value of CLR signature + ULONG *pcbSigBlob, // [OUT] count of bytes in the signature blob + LPCSTR *pszName) + { + PCCOR_SIGNATURE pOrigSig; + ULONG cbOrigSig; + HRESULT hr = S_OK; + IfFailRet(m_pRawInternalImport->GetNameAndSigOfMethodDef(methoddef, &pOrigSig, &cbOrigSig, pszName)); + IfFailRet(m_pWinMDAdapter->ModifyMethodProps(methoddef, NULL, NULL, NULL, pszName)); + + return m_pWinMDAdapter->GetSignatureForToken<IMDInternalImport, mdtMethodDef>( + methoddef, + &pOrigSig, // ppOrigSig + &cbOrigSig, // pcbOrigSig + ppvSigBlob, + pcbSigBlob, + m_pRawInternalImport); + } + + // return the name of a FieldDef + __checkReturn + STDMETHODIMP GetNameOfFieldDef( + mdFieldDef fd, // given memberdef + LPCSTR *pszName) + { + return m_pRawInternalImport->GetNameOfFieldDef(fd, pszName); + } + + // return the name of typeref + __checkReturn + STDMETHODIMP GetNameOfTypeRef( + mdTypeRef classref, // [IN] given typeref + LPCSTR *psznamespace, // [OUT] return typeref name + LPCSTR *pszname) // [OUT] return typeref namespace + { + mdToken resolutionScope; + return m_pWinMDAdapter->GetTypeRefProps(classref, psznamespace, pszname, &resolutionScope); + } + + // return the resolutionscope of typeref + __checkReturn + STDMETHODIMP GetResolutionScopeOfTypeRef( + mdTypeRef classref, // given classref + mdToken *ptkResolutionScope) + { + LPCSTR sznamespace; + LPCSTR szname; + return m_pWinMDAdapter->GetTypeRefProps(classref, &sznamespace, &szname, ptkResolutionScope); + } + + // Find the type token given the name. + __checkReturn + STDMETHODIMP FindTypeRefByName( + 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. + { + return m_pWinMDAdapter->FindTypeRef(szNamespace, szName, tkResolutionScope, ptk); + } + + // return the TypeDef properties + // returned void in v1.0/v1.1 + __checkReturn + STDMETHODIMP GetTypeDefProps( + mdTypeDef classdef, // given classdef + DWORD *pdwAttr, // return flags on class, tdPublic, tdAbstract + mdToken *ptkExtends) // [OUT] Put base class TypeDef/TypeRef here + { + HRESULT hr; + IfFailGo(m_pWinMDAdapter->GetTypeDefProps(classdef, NULL, NULL, pdwAttr, ptkExtends)); + ErrExit: + return hr; + } + + // return the item's guid + __checkReturn + STDMETHODIMP GetItemGuid( + mdToken tkObj, // [IN] given item. + CLSID *pGuid) // [out[ put guid here. + { + HRESULT hr; + IfFailGo(m_pWinMDAdapter->GetItemGuid(tkObj, pGuid)); + + if (hr == S_FALSE) + { + // if this is not a WinRT type, also look for System.Guid by falling back to the raw internal MD import + if (TypeFromToken(tkObj) == mdtTypeDef) + { + DWORD dwAttr; + IfFailGo(m_pWinMDAdapter->GetTypeDefProps(tkObj, NULL, NULL, &dwAttr, NULL)); + + if (!IsTdWindowsRuntime(dwAttr)) + { + IfFailGo(m_pRawInternalImport->GetItemGuid(tkObj, pGuid)); + } + else + { + // reset the return value to S_FALSE if the type is WinRT + hr = S_FALSE; + } + } + } + + ErrExit: + return hr; + } + + // Get enclosing class of the NestedClass. + __checkReturn + STDMETHODIMP GetNestedClassProps( // S_OK or error + mdTypeDef tkNestedClass, // [IN] NestedClass token. + mdTypeDef *ptkEnclosingClass) // [OUT] EnclosingClass token. + { + return m_pRawInternalImport->GetNestedClassProps(tkNestedClass, ptkEnclosingClass); + } + + // Get count of Nested classes given the enclosing class. + __checkReturn + STDMETHODIMP GetCountNestedClasses( // return count of Nested classes. + mdTypeDef tkEnclosingClass, // Enclosing class. + ULONG *pcNestedClassesCount) + { + return m_pRawInternalImport->GetCountNestedClasses(tkEnclosingClass, pcNestedClassesCount); + } + + // Return array of Nested classes given the enclosing class. + __checkReturn + STDMETHODIMP GetNestedClasses( // Return actual count. + mdTypeDef tkEnclosingClass, // [IN] Enclosing class. + mdTypeDef *rNestedClasses, // [OUT] Array of nested class tokens. + ULONG ulNestedClasses, // [IN] Size of array. + ULONG *pcNestedClasses) + { + return m_pRawInternalImport->GetNestedClasses(tkEnclosingClass, rNestedClasses, ulNestedClasses, pcNestedClasses); + } + + // return the ModuleRef properties + // returned void in v1.0/v1.1 + __checkReturn + STDMETHODIMP GetModuleRefProps( + mdModuleRef mur, // [IN] moduleref token + LPCSTR *pszName) // [OUT] buffer to fill with the moduleref name + { + return m_pRawInternalImport->GetModuleRefProps(mur, pszName); + } + + //***************************************** + // + // GetSig* functions + // + //***************************************** + __checkReturn + STDMETHODIMP GetSigOfMethodDef( + mdMethodDef methoddef, // [IN] given memberdef + ULONG *pcbSigBlob, // [OUT] count of bytes in the signature blob + PCCOR_SIGNATURE *ppSig) + { + return m_pWinMDAdapter->GetSignatureForToken<IMDInternalImport, mdtMethodDef>( + methoddef, + NULL, + NULL, + ppSig, + pcbSigBlob, + m_pRawInternalImport); + } + + __checkReturn + STDMETHODIMP GetSigOfFieldDef( + mdFieldDef fielddef, // [IN] given fielddef + ULONG *pcbSigBlob, // [OUT] count of bytes in the signature blob + PCCOR_SIGNATURE *ppSig) + { + return m_pWinMDAdapter->GetSignatureForToken<IMDInternalImport, mdtFieldDef>( + fielddef, + NULL, + NULL, + ppSig, + pcbSigBlob, + m_pRawInternalImport); + } + + __checkReturn + STDMETHODIMP GetSigFromToken( + mdToken tk, // FieldDef, MethodDef, Signature or TypeSpec token + ULONG * pcbSig, + PCCOR_SIGNATURE * ppSig) + { + if (TypeFromToken(tk) == mdtMethodDef) + { + return GetSigOfMethodDef(tk, pcbSig, ppSig); + } + else if (TypeFromToken(tk) == mdtFieldDef) + { + return GetSigOfFieldDef(tk, pcbSig, ppSig); + } + else if (TypeFromToken(tk) == mdtTypeSpec) + { + return GetTypeSpecFromToken(tk, ppSig, pcbSig); + } + // Note: mdtSignature is not part of public WinMD surface, so it does not need signature rewriting - just call the underlying "raw" implementation + return m_pRawInternalImport->GetSigFromToken(tk, pcbSig, ppSig); + } + + + + //***************************************** + // get method property + //***************************************** + __checkReturn + STDMETHODIMP GetMethodDefProps( + mdMethodDef md, // The method for which to get props. + DWORD *pdwFlags) + { + HRESULT hr; + IfFailGo(m_pRawInternalImport->GetMethodDefProps(md, pdwFlags)); + IfFailGo(m_pWinMDAdapter->ModifyMethodProps(md, pdwFlags, NULL, NULL, NULL)); + ErrExit: + return hr; + } + + //***************************************** + // return method implementation informaiton, like RVA and implflags + //***************************************** + // returned void in v1.0/v1.1 + __checkReturn + STDMETHODIMP GetMethodImplProps( + mdToken tk, // [IN] MethodDef + ULONG *pulCodeRVA, // [OUT] CodeRVA + DWORD *pdwImplFlags) // [OUT] Impl. Flags + { + HRESULT hr; + IfFailGo(m_pRawInternalImport->GetMethodImplProps(tk, pulCodeRVA, pdwImplFlags)); + IfFailGo(m_pWinMDAdapter->ModifyMethodProps(tk, NULL, pdwImplFlags, pulCodeRVA, NULL)); + ErrExit: + return hr; + } + + //***************************************** + // return method implementation informaiton, like RVA and implflags + //***************************************** + __checkReturn + STDMETHODIMP GetFieldRVA( + mdFieldDef fd, // [IN] fielddef + ULONG *pulCodeRVA) // [OUT] CodeRVA + { + return m_pRawInternalImport->GetFieldRVA(fd, pulCodeRVA); + } + + //***************************************** + // get field property + //***************************************** + __checkReturn + STDMETHODIMP GetFieldDefProps( + mdFieldDef fd, // [IN] given fielddef + DWORD *pdwFlags) // [OUT] return fdPublic, fdPrive, etc flags + { + HRESULT hr; + IfFailGo(m_pRawInternalImport->GetFieldDefProps(fd, pdwFlags)); + IfFailGo(m_pWinMDAdapter->ModifyFieldDefProps(fd, pdwFlags)); +ErrExit: + return hr; + } + + //***************************************************************************** + // return default value of a token(could be paramdef, fielddef, or property + //***************************************************************************** + __checkReturn + STDMETHODIMP GetDefaultValue( + mdToken tk, // [IN] given FieldDef, ParamDef, or Property + MDDefaultValue *pDefaultValue) // [OUT] default value to fill + { + return m_pRawInternalImport->GetDefaultValue(tk, pDefaultValue); + } + + + //***************************************** + // get dispid of a MethodDef or a FieldDef + //***************************************** + __checkReturn + STDMETHODIMP GetDispIdOfMemberDef( // return hresult + mdToken tk, // [IN] given methoddef or fielddef + ULONG *pDispid) // [OUT] Put the dispid here. + { + return m_pRawInternalImport->GetDispIdOfMemberDef(tk, pDispid); + } + + //***************************************** + // return TypeRef/TypeDef given an InterfaceImpl token + //***************************************** + __checkReturn + STDMETHODIMP GetTypeOfInterfaceImpl( // return the TypeRef/typedef token for the interfaceimpl + mdInterfaceImpl iiImpl, // given a interfaceimpl + mdToken *ptkType) + { + return m_pRawInternalImport->GetTypeOfInterfaceImpl(iiImpl, ptkType); + } + + //***************************************** + // look up function for TypeDef + //***************************************** + __checkReturn + STDMETHODIMP FindTypeDef( + LPCSTR szNamespace, // [IN] Namespace for the TypeDef. + LPCSTR szName, // [IN] Name of the TypeDef. + mdToken tkEnclosingClass, // [IN] TypeRef/TypeDef Token for the enclosing class. + mdTypeDef *ptypedef) // [IN] return typedef + { + return m_pWinMDAdapter->FindTypeDef(szNamespace, szName, tkEnclosingClass, ptypedef); + } + + //***************************************** + // return name and sig of a memberref + //***************************************** + __checkReturn + STDMETHODIMP GetNameAndSigOfMemberRef( // return name here + mdMemberRef memberref, // given memberref + PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to a blob value of CLR signature + ULONG *pcbSigBlob, // [OUT] count of bytes in the signature blob + LPCSTR *pszName) + { + HRESULT hr = S_OK; + PCCOR_SIGNATURE pOrigSig; + ULONG cbOrigSig; + + IfFailRet(m_pRawInternalImport->GetNameAndSigOfMemberRef(memberref, &pOrigSig, &cbOrigSig, pszName)); + IfFailRet(m_pWinMDAdapter->ModifyMemberProps(memberref, NULL, NULL, NULL, pszName)); + + return m_pWinMDAdapter->GetSignatureForToken<IMDInternalImport, mdtMemberRef>( + memberref, + &pOrigSig, // ppOrigSig + &cbOrigSig, // pcbOrigSig + ppvSigBlob, + pcbSigBlob, + m_pRawInternalImport); + } + + //***************************************************************************** + // Given memberref, return the parent. It can be TypeRef, ModuleRef, MethodDef + //***************************************************************************** + __checkReturn + STDMETHODIMP GetParentOfMemberRef( + mdMemberRef memberref, // given memberref + mdToken *ptkParent) // return the parent token + { + return m_pRawInternalImport->GetParentOfMemberRef(memberref, ptkParent); + } + + __checkReturn + STDMETHODIMP GetParamDefProps( + mdParamDef paramdef, // given a paramdef + USHORT *pusSequence, // [OUT] slot number for this parameter + DWORD *pdwAttr, // [OUT] flags + LPCSTR *pszName) // [OUT] return the name of the parameter + { + return m_pRawInternalImport->GetParamDefProps(paramdef, pusSequence, pdwAttr, pszName); + } + + __checkReturn + STDMETHODIMP GetPropertyInfoForMethodDef( // Result. + mdMethodDef md, // [IN] memberdef + mdProperty *ppd, // [OUT] put property token here + LPCSTR *pName, // [OUT] put pointer to name here + ULONG *pSemantic) // [OUT] put semantic here + { + return m_pRawInternalImport->GetPropertyInfoForMethodDef(md, ppd, pName, pSemantic); + } + + //***************************************** + // class layout/sequence information + //***************************************** + __checkReturn + STDMETHODIMP GetClassPackSize( // return error if class doesn't have packsize + mdTypeDef td, // [IN] give typedef + ULONG *pdwPackSize) // [OUT] 1, 2, 4, 8, or 16 + { + return m_pRawInternalImport->GetClassPackSize(td, pdwPackSize); + } + + __checkReturn + STDMETHODIMP GetClassTotalSize( // return error if class doesn't have total size info + mdTypeDef td, // [IN] give typedef + ULONG *pdwClassSize) // [OUT] return the total size of the class + { + return m_pRawInternalImport->GetClassTotalSize(td, pdwClassSize); + } + + __checkReturn + STDMETHODIMP GetClassLayoutInit( + mdTypeDef td, // [IN] give typedef + MD_CLASS_LAYOUT *pLayout) // [OUT] set up the status of query here + { + return m_pRawInternalImport->GetClassLayoutInit(td, pLayout); + } + + __checkReturn + STDMETHODIMP GetClassLayoutNext( + MD_CLASS_LAYOUT *pLayout, // [IN|OUT] set up the status of query here + mdFieldDef *pfd, // [OUT] return the fielddef + ULONG *pulOffset) // [OUT] return the offset/ulSequence associate with it + { + return m_pRawInternalImport->GetClassLayoutNext(pLayout, pfd, pulOffset); + } + + //***************************************** + // marshal information of a field + //***************************************** + __checkReturn + STDMETHODIMP GetFieldMarshal( // return error if no native type associate with the token + mdFieldDef fd, // [IN] given fielddef + PCCOR_SIGNATURE *pSigNativeType, // [OUT] the native type signature + ULONG *pcbNativeType) // [OUT] the count of bytes of *ppvNativeType + { + return m_pRawInternalImport->GetFieldMarshal(fd, pSigNativeType, pcbNativeType); + } + + + //***************************************** + // property APIs + //***************************************** + // find a property by name + __checkReturn + STDMETHODIMP FindProperty( + mdTypeDef td, // [IN] given a typdef + LPCSTR szPropName, // [IN] property name + mdProperty *pProp) // [OUT] return property token + { + return m_pRawInternalImport->FindProperty(td, szPropName, pProp); + } + + // returned void in v1.0/v1.1 + __checkReturn + STDMETHODIMP GetPropertyProps( + mdProperty prop, // [IN] property token + LPCSTR *szProperty, // [OUT] property name + DWORD *pdwPropFlags, // [OUT] property flags. + PCCOR_SIGNATURE *ppvSig, // [OUT] property type. pointing to meta data internal blob + ULONG *pcbSig) // [OUT] count of bytes in *ppvSig + { + HRESULT hr = S_OK; + PCCOR_SIGNATURE pOrigSig; + ULONG cbOrigSig; + + IfFailRet(m_pRawInternalImport->GetPropertyProps(prop, szProperty, pdwPropFlags, &pOrigSig, &cbOrigSig)); + + return m_pWinMDAdapter->GetSignatureForToken<IMDInternalImport, mdtProperty>( + prop, + &pOrigSig, // ppOrigSig + &cbOrigSig, // pcbOrigSig + ppvSig, + pcbSig, + m_pRawInternalImport); + } + + //********************************** + // Event APIs + //********************************** + __checkReturn + STDMETHODIMP FindEvent( + mdTypeDef td, // [IN] given a typdef + LPCSTR szEventName, // [IN] event name + mdEvent *pEvent) // [OUT] return event token + { + return m_pRawInternalImport->FindEvent(td, szEventName, pEvent); + } + + // returned void in v1.0/v1.1 + __checkReturn + STDMETHODIMP GetEventProps( + mdEvent ev, // [IN] event token + LPCSTR *pszEvent, // [OUT] Event name + DWORD *pdwEventFlags, // [OUT] Event flags. + mdToken *ptkEventType) // [OUT] EventType class + { + return m_pRawInternalImport->GetEventProps(ev, pszEvent, pdwEventFlags, ptkEventType); + } + + + //********************************** + // find a particular associate of a property or an event + //********************************** + __checkReturn + STDMETHODIMP FindAssociate( + mdToken evprop, // [IN] given a property or event token + DWORD associate, // [IN] given a associate semantics(setter, getter, testdefault, reset, AddOn, RemoveOn, Fire) + mdMethodDef *pmd) // [OUT] return method def token + { + return m_pRawInternalImport->FindAssociate(evprop, associate, pmd); + } + + // Note, void function in v1.0/v1.1 + __checkReturn + STDMETHODIMP EnumAssociateInit( + mdToken evprop, // [IN] given a property or an event token + HENUMInternal *phEnum) // [OUT] cursor to hold the query result + { + return m_pRawInternalImport->EnumAssociateInit(evprop, phEnum); + } + + // returned void in v1.0/v1.1 + __checkReturn + STDMETHODIMP GetAllAssociates( + HENUMInternal *phEnum, // [IN] query result form GetPropertyAssociateCounts + ASSOCIATE_RECORD *pAssociateRec, // [OUT] struct to fill for output + ULONG cAssociateRec) // [IN] size of the buffer + { + return m_pRawInternalImport->GetAllAssociates(phEnum, pAssociateRec, cAssociateRec); + } + + + //********************************** + // Get info about a PermissionSet. + //********************************** + // returned void in v1.0/v1.1 + __checkReturn + STDMETHODIMP GetPermissionSetProps( + mdPermission pm, // [IN] the permission token. + DWORD *pdwAction, // [OUT] CorDeclSecurity. + void const **ppvPermission, // [OUT] permission blob. + ULONG *pcbPermission) // [OUT] count of bytes of pvPermission. + { + return m_pRawInternalImport->GetPermissionSetProps(pm, pdwAction, ppvPermission, pcbPermission); + } + + //**************************************** + // Get the String given the String token. + // Returns a pointer to the string, or NULL in case of error. + //**************************************** + __checkReturn + STDMETHODIMP GetUserString( + mdString stk, // [IN] the string token. + ULONG *pchString, // [OUT] count of characters in the string. + BOOL *pbIs80Plus, // [OUT] specifies where there are extended characters >= 0x80. + LPCWSTR *pwszUserString) + { + return m_pRawInternalImport->GetUserString(stk, pchString, pbIs80Plus, pwszUserString); + } + + //***************************************************************************** + // p-invoke APIs. + //***************************************************************************** + __checkReturn + STDMETHODIMP GetPinvokeMap( + mdToken tk, // [IN] FieldDef, MethodDef. + DWORD *pdwMappingFlags, // [OUT] Flags used for mapping. + LPCSTR *pszImportName, // [OUT] Import name. + mdModuleRef *pmrImportDLL) // [OUT] ModuleRef token for the target DLL. + { + return m_pRawInternalImport->GetPinvokeMap(tk, pdwMappingFlags, pszImportName, pmrImportDLL); + } + + //***************************************************************************** + // helpers to convert a text signature to a com format + //***************************************************************************** + __checkReturn + STDMETHODIMP ConvertTextSigToComSig( // Return hresult. + BOOL fCreateTrIfNotFound, // [IN] create typeref if not found + LPCSTR pSignature, // [IN] class file format signature + CQuickBytes *pqbNewSig, // [OUT] place holder for CLR signature + ULONG *pcbCount) // [OUT] the result size of signature + { + return m_pRawInternalImport->ConvertTextSigToComSig(fCreateTrIfNotFound, pSignature, pqbNewSig, pcbCount); + } + + //***************************************************************************** + // Assembly MetaData APIs. + //***************************************************************************** + // returned void in v1.0/v1.1 + __checkReturn + STDMETHODIMP GetAssemblyProps( + mdAssembly mda, // [IN] The Assembly for which to get the properties. + const void **ppbPublicKey, // [OUT] Pointer to the public key. + ULONG *pcbPublicKey, // [OUT] Count of bytes in the public key. + ULONG *pulHashAlgId, // [OUT] Hash Algorithm. + LPCSTR *pszName, // [OUT] Buffer to fill with name. + AssemblyMetaDataInternal *pMetaData,// [OUT] Assembly MetaData. + DWORD *pdwAssemblyFlags) // [OUT] Flags. + { + return m_pRawInternalImport->GetAssemblyProps(mda, ppbPublicKey, pcbPublicKey, pulHashAlgId, pszName, pMetaData, pdwAssemblyFlags); + } + + // returned void in v1.0/v1.1 + __checkReturn + STDMETHODIMP GetAssemblyRefProps( + mdAssemblyRef mdar, // [IN] The AssemblyRef for which to get the properties. + const void **ppbPublicKeyOrToken, // [OUT] Pointer to the public key or token. + ULONG *pcbPublicKeyOrToken, // [OUT] Count of bytes in the public key or token. + LPCSTR *pszName, // [OUT] Buffer to fill with name. + AssemblyMetaDataInternal *pMetaData,// [OUT] Assembly MetaData. + const void **ppbHashValue, // [OUT] Hash blob. + ULONG *pcbHashValue, // [OUT] Count of bytes in the hash blob. + DWORD *pdwAssemblyRefFlags) // [OUT] Flags. + { + HRESULT hr; + mdAssemblyRef md = mdar; + if (RidFromToken(md) > m_pWinMDAdapter->GetRawAssemblyRefCount()) + { + // The extra framework assemblies we add references to should all have the + // same verion, key, culture, etc as those of mscorlib. + // So we retrieve the mscorlib properties and change the name. + md = m_pWinMDAdapter->GetAssemblyRefMscorlib(); + } + + IfFailRet(m_pRawInternalImport->GetAssemblyRefProps(md, ppbPublicKeyOrToken, pcbPublicKeyOrToken, pszName, pMetaData, ppbHashValue, pcbHashValue, pdwAssemblyRefFlags)); + + USHORT *pusMajorVersion = nullptr; + USHORT *pusMinorVersion = nullptr; + USHORT *pusBuildNumber = nullptr; + USHORT *pusRevisionNumber = nullptr; + + if (pMetaData != nullptr) + { + pusMajorVersion = &pMetaData->usMajorVersion; + pusMinorVersion = &pMetaData->usMinorVersion; + pusBuildNumber = &pMetaData->usBuildNumber; + pusRevisionNumber = &pMetaData->usRevisionNumber; + } + + m_pWinMDAdapter->ModifyAssemblyRefProps( + mdar, + ppbPublicKeyOrToken, + pcbPublicKeyOrToken, + pszName, + pusMajorVersion, + pusMinorVersion, + pusBuildNumber, + pusRevisionNumber, + ppbHashValue, + pcbHashValue); + + return hr; + } + + // returned void in v1.0/v1.1 + __checkReturn + STDMETHODIMP GetFileProps( + mdFile mdf, // [IN] The File for which to get the properties. + LPCSTR *pszName, // [OUT] Buffer to fill with name. + const void **ppbHashValue, // [OUT] Pointer to the Hash Value Blob. + ULONG *pcbHashValue, // [OUT] Count of bytes in the Hash Value Blob. + DWORD *pdwFileFlags) // [OUT] Flags. + { + return m_pRawInternalImport->GetFileProps(mdf, pszName, ppbHashValue, pcbHashValue, pdwFileFlags); + } + + // returned void in v1.0/v1.1 + __checkReturn + STDMETHODIMP GetExportedTypeProps( + mdExportedType mdct, // [IN] The ExportedType for which to get the properties. + LPCSTR *pszNamespace, // [OUT] Namespace. + LPCSTR *pszName, // [OUT] Name. + mdToken *ptkImplementation, // [OUT] mdFile or mdAssemblyRef that provides the ExportedType. + mdTypeDef *ptkTypeDef, // [OUT] TypeDef token within the file. + DWORD *pdwExportedTypeFlags) // [OUT] Flags. + { + HRESULT hr; + IfFailRet(m_pRawInternalImport->GetExportedTypeProps(mdct, pszNamespace, pszName, ptkImplementation, ptkTypeDef, pdwExportedTypeFlags)); + IfFailRet(m_pWinMDAdapter->ModifyExportedTypeName(mdct, pszNamespace, pszName)); + return hr; + } + + // returned void in v1.0/v1.1 + __checkReturn + STDMETHODIMP GetManifestResourceProps( + mdManifestResource mdmr, // [IN] The ManifestResource for which to get the properties. + LPCSTR *pszName, // [OUT] Buffer to fill with name. + mdToken *ptkImplementation, // [OUT] mdFile or mdAssemblyRef that provides the ExportedType. + DWORD *pdwOffset, // [OUT] Offset to the beginning of the resource within the file. + DWORD *pdwResourceFlags) // [OUT] Flags. + { + return m_pRawInternalImport->GetManifestResourceProps(mdmr, pszName, ptkImplementation, pdwOffset, pdwResourceFlags); + } + + __checkReturn + STDMETHODIMP FindExportedTypeByName( // S_OK or error + LPCSTR szNamespace, // [IN] Namespace of the ExportedType. + LPCSTR szName, // [IN] Name of the ExportedType. + mdExportedType tkEnclosingType, // [IN] ExportedType for the enclosing class. + mdExportedType *pmct) // [OUT] Put ExportedType token here. + { + return m_pWinMDAdapter->FindExportedType(szNamespace, szName, tkEnclosingType, pmct); + } + + __checkReturn + STDMETHODIMP FindManifestResourceByName( // S_OK or error + LPCSTR szName, // [IN] Name of the ManifestResource. + mdManifestResource *pmmr) // [OUT] Put ManifestResource token here. + { + return m_pRawInternalImport->FindManifestResourceByName(szName, pmmr); + } + + __checkReturn + STDMETHODIMP GetAssemblyFromScope( // S_OK or error + mdAssembly *ptkAssembly) // [OUT] Put token here. + { + return m_pRawInternalImport->GetAssemblyFromScope(ptkAssembly); + } + + __checkReturn + STDMETHODIMP GetCustomAttributeByName( // S_OK or error + mdToken tkObj, // [IN] Object with Custom Attribute. + LPCUTF8 szName, // [IN] Name of desired Custom Attribute. + const void **ppData, // [OUT] Put pointer to data here. + ULONG *pcbData) // [OUT] Put size of data here. + { + return m_pWinMDAdapter->GetCustomAttributeByName(tkObj, szName, NULL, ppData, pcbData); + } + + // Note: The return type of this method was void in v1 + __checkReturn + STDMETHODIMP GetTypeSpecFromToken( // S_OK or error. + mdTypeSpec typespec, // [IN] Signature token. + PCCOR_SIGNATURE *ppvSig, // [OUT] return pointer to token. + ULONG *pcbSig) // [OUT] return size of signature. + { + return m_pWinMDAdapter->GetSignatureForToken<IMDInternalImport, mdtTypeSpec>( + typespec, + NULL, // ppOrigSig + NULL, // pcbOrigSig + ppvSig, + pcbSig, + m_pRawInternalImport); + } + + __checkReturn + STDMETHODIMP SetUserContextData( // S_OK or E_NOTIMPL + IUnknown *pIUnk) // The user context. + { + return m_pRawInternalImport->SetUserContextData(pIUnk); + } + + __checkReturn + STDMETHODIMP_(BOOL) IsValidToken( // True or False. + mdToken tk) // [IN] Given token. + { + if (TypeFromToken(tk) == mdtAssemblyRef) + return m_pWinMDAdapter->IsValidAssemblyRefToken(tk); + + return m_pRawInternalImport->IsValidToken(tk); + } + + + __checkReturn + STDMETHODIMP TranslateSigWithScope( + IMDInternalImport* pAssemImport, // [IN] import assembly scope. + const void* pbHashValue, // [IN] hash value for the import assembly. + ULONG cbHashValue, // [IN] count of bytes in the hash value. + PCCOR_SIGNATURE pbSigBlob, // [IN] signature in the importing scope + ULONG cbSigBlob, // [IN] count of bytes of signature + IMetaDataAssemblyEmit* pAssemEmit, // [IN] assembly emit scope. + IMetaDataEmit* emit, // [IN] emit interface + CQuickBytes* pqkSigEmit, // [OUT] buffer to hold translated signature + ULONG* pcbSig) // [OUT] count of bytes in the translated signature + { + return TranslateSigHelper( + this, + pAssemImport, + pbHashValue, + cbHashValue, + pbSigBlob, + cbSigBlob, + pAssemEmit, + emit, + pqkSigEmit, + pcbSig); + } + + + STDMETHODIMP_(IMetaModelCommon*) GetMetaModelCommon() // Return MetaModelCommon interface. + { + return static_cast<IMetaModelCommon*>(this); + } + + STDMETHODIMP_(IUnknown *) GetCachedPublicInterface(BOOL fWithLock) // return the cached public interface + { + return m_pRawInternalImport->GetCachedPublicInterface(fWithLock); + } + __checkReturn + + STDMETHODIMP SetCachedPublicInterface(IUnknown *pUnk) // no return value + { + return m_pRawInternalImport->SetCachedPublicInterface(pUnk); + } + + STDMETHODIMP_(UTSemReadWrite*) GetReaderWriterLock() // return the reader writer lock + { + return m_pRawInternalImport->GetReaderWriterLock(); + } + + __checkReturn + STDMETHODIMP SetReaderWriterLock(UTSemReadWrite * pSem) + { + return m_pRawInternalImport->SetReaderWriterLock(pSem); + } + + STDMETHODIMP_(mdModule) GetModuleFromScope() // [OUT] Put mdModule token here. + { + return m_pRawInternalImport->GetModuleFromScope(); + } + + + //----------------------------------------------------------------- + // Additional custom methods + + // finding a particular method + __checkReturn + STDMETHODIMP FindMethodDefUsingCompare( + mdTypeDef classdef, // [IN] given typedef + LPCSTR szName, // [IN] member name + PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of CLR signature + ULONG cbSigBlob, // [IN] count of bytes in the signature blob + PSIGCOMPARE pSignatureCompare, // [IN] Routine to compare signatures + void* pSignatureArgs, // [IN] Additional info to supply the compare function + mdMethodDef *pmd) // [OUT] matching memberdef + { + if (pvSigBlob == NULL || cbSigBlob == 0 || pSignatureCompare == NULL) + { + // if signature matching is not needed, we can delegate to the underlying implementation + return m_pRawInternalImport->FindMethodDefUsingCompare(classdef, szName, pvSigBlob, cbSigBlob, pSignatureCompare, pSignatureArgs, pmd); + } + + // The following code emulates MDInternalRO::FindMethodDefUsingCompare. We cannot call the underlying + // implementation because we need to compare pvSigBlob to reinterpreted signatures. + _ASSERTE(szName && pmd); + + HRESULT hr = S_OK; + HENUMInternal hEnum; + + CQuickBytes qbSig; // holds non-varargs signature + + *pmd = mdMethodDefNil; + + // check to see if this is a vararg signature + PCCOR_SIGNATURE pvSigTemp = pvSigBlob; + if (isCallConv(CorSigUncompressCallingConv(pvSigTemp), IMAGE_CEE_CS_CALLCONV_VARARG)) + { + // Get the fixed part of VARARG signature + IfFailGo(_GetFixedSigOfVarArg(pvSigBlob, cbSigBlob, &qbSig, &cbSigBlob)); + pvSigBlob = (PCCOR_SIGNATURE) qbSig.Ptr(); + } + + // now iterate all methods in td and compare name and signature + IfFailGo(EnumInit(mdtMethodDef, classdef, &hEnum)); + + mdMethodDef md; + while(EnumNext(&hEnum, &md)) + { + PCCOR_SIGNATURE pvMethodSigBlob; + ULONG cbMethodSigBlob; + LPCSTR szMethodName; + + IfFailGo(GetNameAndSigOfMethodDef(md, &pvMethodSigBlob, &cbMethodSigBlob, &szMethodName)); + + if (strcmp(szName, szMethodName) == 0) + { + // we have a name match, check signature + if (pSignatureCompare(pvMethodSigBlob, cbMethodSigBlob, pvSigBlob, cbSigBlob, pSignatureArgs) == FALSE) + continue; + + // ignore PrivateScope methods + DWORD dwMethodAttr; + IfFailGo(GetMethodDefProps(md, &dwMethodAttr)); + + if (IsMdPrivateScope(dwMethodAttr)) + continue; + + // we found the method + *pmd = md; + goto ErrExit; + } + } + hr = CLDB_E_RECORD_NOTFOUND; + + ErrExit: + EnumClose(&hEnum); + return hr; + } + + // Additional v2 methods. + + //***************************************** + // return a field offset for a given field + //***************************************** + __checkReturn + STDMETHODIMP GetFieldOffset( + mdFieldDef fd, // [IN] fielddef + ULONG *pulOffset) // [OUT] FieldOffset + { + return m_pRawInternalImport->GetFieldOffset(fd, pulOffset); + } + + __checkReturn + STDMETHODIMP GetMethodSpecProps( + mdMethodSpec ms, // [IN] The method instantiation + mdToken *tkParent, // [OUT] MethodDef or MemberRef + PCCOR_SIGNATURE *ppvSigBlob, // [OUT] point to the blob value of meta data + ULONG *pcbSigBlob) // [OUT] actual size of signature blob + { + HRESULT hr = S_OK; + PCCOR_SIGNATURE pOrigSig; + ULONG cbOrigSig; + + IfFailRet(m_pRawInternalImport->GetMethodSpecProps(ms, tkParent, &pOrigSig, &cbOrigSig)); + + return m_pWinMDAdapter->GetSignatureForToken<IMDInternalImport, mdtMethodSpec>( + ms, + &pOrigSig, // ppOrigSig + &cbOrigSig, // pcbOrigSig + ppvSigBlob, + pcbSigBlob, + m_pRawInternalImport); + } + + __checkReturn + STDMETHODIMP GetTableInfoWithIndex( + ULONG index, // [IN] pass in the table index + void **pTable, // [OUT] pointer to table at index + void **pTableSize) // [OUT] size of table at index + { + // This abstraction breaker is apparently used only by SOS... at this time of writing. + return m_pRawInternalImport->GetTableInfoWithIndex(index, pTable, pTableSize); + } + + __checkReturn + STDMETHODIMP ApplyEditAndContinue( + void *pDeltaMD, // [IN] the delta metadata + ULONG cbDeltaMD, // [IN] length of pData + IMDInternalImport **ppv) // [OUT] the resulting metadata interface + { + WINMD_COMPAT_ASSERT("IMDInternalImport::ApplyEditAndContinue() not supported on .winmd files."); + return E_NOTIMPL; + } + + //********************************** + // Generics APIs + //********************************** + __checkReturn + STDMETHODIMP GetGenericParamProps( // S_OK or error. + mdGenericParam rd, // [IN] The type parameter + ULONG* pulSequence, // [OUT] Parameter sequence number + DWORD* pdwAttr, // [OUT] Type parameter flags (for future use) + mdToken *ptOwner, // [OUT] The owner (TypeDef or MethodDef) + DWORD *reserved, // [OUT] The kind (TypeDef/Ref/Spec, for future use) + LPCSTR *szName) // [OUT] The name + { + return m_pRawInternalImport->GetGenericParamProps(rd, pulSequence, pdwAttr, ptOwner, reserved, szName); + } + + __checkReturn + STDMETHODIMP GetGenericParamConstraintProps( // S_OK or error. + mdGenericParamConstraint rd, // [IN] The constraint token + mdGenericParam *ptGenericParam, // [OUT] GenericParam that is constrained + mdToken *ptkConstraintType) // [OUT] TypeDef/Ref/Spec constraint + { + return m_pRawInternalImport->GetGenericParamConstraintProps(rd, ptGenericParam, ptkConstraintType); + } + + //***************************************************************************** + // This function gets the "built for" version of a metadata scope. + // NOTE: if the scope has never been saved, it will not have a built-for + // version, and an empty string will be returned. + //***************************************************************************** + __checkReturn + STDMETHODIMP GetVersionString( // S_OK or error. + LPCSTR *pVer) // [OUT] Put version string here. + { + return m_pWinMDAdapter->GetVersionString(pVer); + } + + __checkReturn + STDMETHODIMP SafeAndSlowEnumCustomAttributeByNameInit(// return S_FALSE if record not found + mdToken tkParent, // [IN] token to scope the search + LPCSTR szName, // [IN] CustomAttribute's name to scope the search + HENUMInternal *phEnum) // [OUT] The enumerator + { + WinMDAdapter::ConvertWellKnownTypeNameFromClrToWinRT(&szName); + return m_pRawInternalImport->SafeAndSlowEnumCustomAttributeByNameInit(tkParent, szName, phEnum); + } + __checkReturn + STDMETHODIMP SafeAndSlowEnumCustomAttributeByNameNext(// return S_FALSE if record not found + mdToken tkParent, // [IN] token to scope the search + LPCSTR szName, // [IN] CustomAttribute's name to scope the search + HENUMInternal *phEnum, // [IN] The enumerator + mdCustomAttribute *mdAttribute) // [OUT] The custom attribute that was found + { + WinMDAdapter::ConvertWellKnownTypeNameFromClrToWinRT(&szName); + return m_pRawInternalImport->SafeAndSlowEnumCustomAttributeByNameNext(tkParent, szName, phEnum, mdAttribute); + } + + + __checkReturn + STDMETHODIMP GetTypeDefRefTokenInTypeSpec(// return S_FALSE if enclosing type does not have a token + mdTypeSpec tkTypeSpec, // [IN] TypeSpec token to look at + mdToken *tkEnclosedToken) // [OUT] The enclosed type token + { + return m_pRawInternalImport->GetTypeDefRefTokenInTypeSpec(tkTypeSpec, tkEnclosedToken); + } + + STDMETHODIMP_(DWORD) GetMetadataStreamVersion() //returns DWORD with major version of + // MD stream in senior word and minor version--in junior word + { + return m_pRawInternalImport->GetMetadataStreamVersion(); + } + + __checkReturn + STDMETHODIMP GetNameOfCustomAttribute(// S_OK or error + mdCustomAttribute mdAttribute, // [IN] The Custom Attribute + LPCUTF8 *pszNamespace, // [OUT] Namespace of Custom Attribute. + LPCUTF8 *pszName) // [OUT] Name of Custom Attribute. + { + HRESULT hr; + IfFailRet(m_pRawInternalImport->GetNameOfCustomAttribute(mdAttribute, pszNamespace, pszName)); + WinMDAdapter::ConvertWellKnownTypeNameFromWinRTToClr(pszNamespace, pszName); + return hr; + } + + STDMETHODIMP SetOptimizeAccessForSpeed(// S_OK or error + BOOL fOptSpeed) + { + return m_pRawInternalImport->SetOptimizeAccessForSpeed(fOptSpeed); + } + + STDMETHODIMP SetVerifiedByTrustedSource(// S_OK or error + BOOL fVerified) + { + return m_pRawInternalImport->SetVerifiedByTrustedSource(fVerified); + } + + STDMETHODIMP GetRvaOffsetData(// S_OK or error + DWORD *pFirstMethodRvaOffset, // [OUT] Offset (from start of metadata) to the first RVA field in MethodDef table. + DWORD *pMethodDefRecordSize, // [OUT] Size of each record in MethodDef table. + DWORD *pMethodDefCount, // [OUT] Number of records in MethodDef table. + DWORD *pFirstFieldRvaOffset, // [OUT] Offset (from start of metadata) to the first RVA field in FieldRVA table. + DWORD *pFieldRvaRecordSize, // [OUT] Size of each record in FieldRVA table. + DWORD *pFieldRvaCount) // [OUT] Number of records in FieldRVA table. + { + return m_pRawInternalImport->GetRvaOffsetData( + pFirstMethodRvaOffset, + pMethodDefRecordSize, + pMethodDefCount, + pFirstFieldRvaOffset, + pFieldRvaRecordSize, + pFieldRvaCount); + } + + + // ******************************************************************************** + // **************** Implementation of IMetaModelCommon methods ******************** + // ******************************************************************************** + + __checkReturn + HRESULT CommonGetScopeProps( + LPCUTF8 *pszName, + GUID *pMvid) + { + return m_pRawMetaModelCommon->CommonGetScopeProps(pszName, pMvid); + } + + __checkReturn + HRESULT CommonGetTypeRefProps( + mdTypeRef tr, + LPCUTF8 *pszNamespace, + LPCUTF8 *pszName, + mdToken *ptkResolution) + { + return m_pWinMDAdapter->GetTypeRefProps(tr, pszNamespace, pszName, ptkResolution); + } + + __checkReturn + HRESULT CommonGetTypeDefProps( + mdTypeDef td, + LPCUTF8 *pszNameSpace, + LPCUTF8 *pszName, + DWORD *pdwFlags, + mdToken *pdwExtends, + ULONG *pMethodList) + { + // We currently don't support retrieving the method list. + if (pMethodList) + return E_NOTIMPL; + + return m_pWinMDAdapter->GetTypeDefProps(td, pszNameSpace, pszName, pdwFlags, pdwExtends); + } + + __checkReturn + HRESULT CommonGetTypeSpecProps( + mdTypeSpec ts, + PCCOR_SIGNATURE *ppvSig, + ULONG *pcbSig) + { + return m_pWinMDAdapter->GetSignatureForToken<IMDInternalImport, mdtTypeSpec>( + ts, + NULL, // ppOrigSig + NULL, // pcbOrigSig + ppvSig, + pcbSig, + m_pRawInternalImport); + } + + __checkReturn + HRESULT CommonGetEnclosingClassOfTypeDef( + mdTypeDef td, + mdTypeDef *ptkEnclosingTypeDef) + { + return m_pRawMetaModelCommon->CommonGetEnclosingClassOfTypeDef(td, ptkEnclosingTypeDef); + } + + __checkReturn + HRESULT CommonGetAssemblyProps( + USHORT *pusMajorVersion, + USHORT *pusMinorVersion, + USHORT *pusBuildNumber, + USHORT *pusRevisionNumber, + DWORD *pdwFlags, + const void **ppbPublicKey, + ULONG *pcbPublicKey, + LPCUTF8 *pszName, + LPCUTF8 *pszLocale) + { + HRESULT hr; + AssemblyMetaDataInternal MetaData; + mdToken tkAssembly = TokenFromRid(1, mdtAssembly); + + IfFailRet(GetAssemblyProps( + tkAssembly, + ppbPublicKey, + pcbPublicKey, + NULL, + pszName, + &MetaData, + pdwFlags)); + + if (pusMajorVersion) + *pusMajorVersion = MetaData.usMajorVersion; + if (pusMinorVersion) + *pusMinorVersion = MetaData.usMinorVersion; + if (pusBuildNumber) + *pusBuildNumber = MetaData.usBuildNumber; + if (pusRevisionNumber) + *pusRevisionNumber = MetaData.usRevisionNumber; + if (pszLocale) + *pszLocale = MetaData.szLocale; + + return S_OK; + } + + __checkReturn + HRESULT CommonGetAssemblyRefProps( + mdAssemblyRef tkAssemRef, + USHORT *pusMajorVersion, + USHORT *pusMinorVersion, + USHORT *pusBuildNumber, + USHORT *pusRevisionNumber, + DWORD *pdwFlags, + const void **ppbPublicKeyOrToken, + ULONG *pcbPublicKeyOrToken, + LPCUTF8 *pszName, + LPCUTF8 *pszLocale, + const void **ppbHashValue, + ULONG *pcbHashValue) + { + HRESULT hr; + + AssemblyMetaDataInternal MetaData; + IfFailRet(GetAssemblyRefProps( + tkAssemRef, + ppbPublicKeyOrToken, + pcbPublicKeyOrToken, + pszName, + &MetaData, + ppbHashValue, + pcbHashValue, + pdwFlags)); + + if (pusMajorVersion) + *pusMajorVersion = MetaData.usMajorVersion; + if (pusMinorVersion) + *pusMinorVersion = MetaData.usMinorVersion; + if (pusBuildNumber) + *pusBuildNumber = MetaData.usBuildNumber; + if (pusRevisionNumber) + *pusRevisionNumber = MetaData.usRevisionNumber; + if (pszLocale) + *pszLocale = MetaData.szLocale; + + return S_OK; + } + + __checkReturn + HRESULT CommonGetModuleRefProps( + mdModuleRef tkModuleRef, + LPCUTF8 *pszName) + { + return m_pRawMetaModelCommon->CommonGetModuleRefProps(tkModuleRef, pszName); + } + + __checkReturn + HRESULT CommonFindExportedType( + LPCUTF8 szNamespace, + LPCUTF8 szName, + mdToken tkEnclosingType, + mdExportedType *ptkExportedType) + { + return m_pWinMDAdapter->FindExportedType(szNamespace, szName, tkEnclosingType, ptkExportedType); + } + + __checkReturn + HRESULT CommonGetExportedTypeProps( + mdToken tkExportedType, + LPCUTF8 *pszNamespace, + LPCUTF8 *pszName, + mdToken *ptkImpl) + { + return GetExportedTypeProps( + tkExportedType, + pszNamespace, + pszName, + ptkImpl, + NULL, + NULL); + } + + __checkReturn + HRESULT CommonGetCustomAttributeByNameEx( // 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. + { + return m_pWinMDAdapter->GetCustomAttributeByName(tkObj, szName, ptkCA, ppData, pcbData); + } + + __checkReturn + HRESULT FindParentOfMethodHelper(mdMethodDef md, mdTypeDef *ptd) + { + return m_pRawMetaModelCommon->FindParentOfMethodHelper(md, ptd); + } + + int CommonIsRo() + { + return m_pRawMetaModelCommon->CommonIsRo(); + } + + private: + //========================================================= + // Private instance data + //========================================================= + IMDCommon *m_pRawMDCommon; + IMetaModelCommon *m_pRawMetaModelCommon; + IMDInternalImport *m_pRawInternalImport; + WinMDAdapter *m_pWinMDAdapter; + LONG m_cRef; +}; // class WinMDInternalImportRO + + + + +//======================================================================================== +// Entrypoint called by GetMDInternalInterface() +//======================================================================================== +HRESULT CreateWinMDInternalImportRO(IMDCommon * pRawMDCommon, REFIID riid, /*[out]*/ void **ppWinMDInternalImport) +{ + HRESULT hr; + *ppWinMDInternalImport = NULL; + WinMDInternalImportRO *pNewImport = NULL; + IfFailGo(WinMDInternalImportRO::Create(pRawMDCommon, &pNewImport)); + IfFailGo(pNewImport->QueryInterface(riid, ppWinMDInternalImport)); + hr = S_OK; + + ErrExit: + if (pNewImport) + pNewImport->Release(); + return hr; + +} + +#endif // FEATURE_METADATA_INTERNAL_APIS + + + diff --git a/src/md/winmd/wks/.gitmirror b/src/md/winmd/wks/.gitmirror new file mode 100644 index 0000000000..f507630f94 --- /dev/null +++ b/src/md/winmd/wks/.gitmirror @@ -0,0 +1 @@ +Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror.
\ No newline at end of file diff --git a/src/md/winmd/wks/CMakeLists.txt b/src/md/winmd/wks/CMakeLists.txt new file mode 100644 index 0000000000..139b68b28c --- /dev/null +++ b/src/md/winmd/wks/CMakeLists.txt @@ -0,0 +1,4 @@ +include(../../md_wks.cmake) + +add_precompiled_header(stdafx.h ../stdafx.cpp MDWINMD_SOURCES) +add_library_clr(mdwinmd_wks ${MDWINMD_SOURCES})
\ No newline at end of file diff --git a/src/md/winmd/wks/MDWinMD_wks.nativeproj b/src/md/winmd/wks/MDWinMD_wks.nativeproj new file mode 100644 index 0000000000..cc0a6f2bc1 --- /dev/null +++ b/src/md/winmd/wks/MDWinMD_wks.nativeproj @@ -0,0 +1,19 @@ +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <!-- All features are set in file:..\..\MD.props --> + <MetadataFlavor>wks</MetadataFlavor> + </PropertyGroup> + + <!--Import the settings--> + <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\src\MD\WinMD\WinMD.settings.targets" /> + + <!--Leaf project Properties--> + <PropertyGroup> + <BuildCoreBinaries>true</BuildCoreBinaries> + <BuildSysBinaries>true</BuildSysBinaries> + <OutputName>MDWinMD_wks</OutputName> + </PropertyGroup> + + <!--Import the targets--> + <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" /> +</Project> |