diff options
Diffstat (limited to 'src/vm/winrthelpers.cpp')
-rw-r--r-- | src/vm/winrthelpers.cpp | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/src/vm/winrthelpers.cpp b/src/vm/winrthelpers.cpp new file mode 100644 index 0000000000..63ab357482 --- /dev/null +++ b/src/vm/winrthelpers.cpp @@ -0,0 +1,164 @@ +// 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. +// +// winrthelpers.inl +// + +// +// Helpers to fetch the first WinRT Type def from metadata import +// +// ====================================================================================== + +#include "common.h" + +// -------------------------------------------------------------------------------------- +// Return the first public WinRT type's namespace and typename - the names have the lifetime of the MetaData scope. +// +//static +HRESULT GetFirstWinRTTypeDef( + IMDInternalImport * pMDInternalImport, + LPCSTR * pszNameSpace, // Tight to the lifetime of pssFakeNameSpaceAllocationBuffer when the WinMD file is empty + LPCSTR * pszTypeName, + LPCWSTR wszAssemblyPath, // Used for creating fake binding type name in case the WinMD file is empty + SString * pssFakeNameSpaceAllocationBuffer) // Used as allocation buffer for fake namespace +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END; + + _ASSERTE((wszAssemblyPath == NULL) || (pssFakeNameSpaceAllocationBuffer != NULL)); + + static const char const_szWinRTPrefix[] = "<WinRT>"; + + HRESULT hr = S_OK; + HENUMInternalHolder hEnum(pMDInternalImport); + mdToken tk; + + hEnum.EnumTypeDefInit(); + + while (pMDInternalImport->EnumTypeDefNext(&hEnum, &tk)) + { + DWORD dwAttr; + IfFailRet(pMDInternalImport->GetTypeDefProps(tk, &dwAttr, NULL)); + if (IsTdPublic(dwAttr) && IsTdWindowsRuntime(dwAttr)) + { + IfFailRet(pMDInternalImport->GetNameOfTypeDef(tk, pszTypeName, pszNameSpace)); + return hr; + } + } + + // We didn't find any public Windows runtime types. In the case of 1st party WinMDs, this means + // it's not exporting anything so we really cannot bind to it. + // For WinMDs built with WinMDExp, it's because the adapter has promoted the CLR implementation to + // public (no WindowsRuntime flag, though), and made the WinRT copy private. + // So there should exist a public type (not nested, not an interface), which has a corresponding + // private type with the same name prepended with <WinRT> that is marked as windows runtime + // This isn't very efficient O(n^2) but we expect all public types in WinMDs to have WinRT visible + // versions too so it should early out in the first iteration in almost all cases. + HENUMInternalHolder hEnum2(pMDInternalImport); + hEnum2.EnumTypeDefInit(); + + while (pMDInternalImport->EnumTypeDefNext(&hEnum2, &tk)) + { + DWORD dwAttr; + IfFailRet(pMDInternalImport->GetTypeDefProps(tk, &dwAttr, NULL)); + if (IsTdPublic(dwAttr) && !IsTdInterface(dwAttr)) + { + // Look for a matching private windows runtime type + mdToken tkPrivate; + HENUMInternalHolder hSubEnum(pMDInternalImport); + + LPCSTR szNameSpace = NULL; + LPCSTR szName = NULL; + IfFailRet(pMDInternalImport->GetNameOfTypeDef(tk, &szName, &szNameSpace)); + + hSubEnum.EnumTypeDefInit(); + + while (pMDInternalImport->EnumTypeDefNext(&hSubEnum, &tkPrivate)) + { + DWORD dwSubAttr; + IfFailRet(pMDInternalImport->GetTypeDefProps(tkPrivate, &dwSubAttr, NULL)); + if (IsTdNotPublic(dwSubAttr) && IsTdWindowsRuntime(dwSubAttr)) + { + LPCSTR szSubNameSpace = NULL; + LPCSTR szSubName = NULL; + IfFailRet(pMDInternalImport->GetNameOfTypeDef(tkPrivate, &szSubName, &szSubNameSpace)); + if (!strncmp(szSubName, const_szWinRTPrefix, strlen(const_szWinRTPrefix))) + { + szSubName += strlen(const_szWinRTPrefix); + // Skip over the <WinRT> prefix. Now pointing at type name + if (!strcmp(szSubNameSpace, szNameSpace) && + !strcmp(szSubName, szName)) + { + *pszNameSpace = szNameSpace; + *pszTypeName = szName; + return S_OK; + } + } + } + } + } + } + // The .winmd file is empty - i.e. there is no type we can bind to + + if ((wszAssemblyPath != NULL) && (*wszAssemblyPath != 0)) + { // Create fake name for WinMD binding purposes (used when .winmd file is loaded by file path - ngen, NativeBinder, etc.) + // We will use WinMD file name as namespace and use fake hardcoded type name + SString ssAssemblyPath(wszAssemblyPath); + SString ssAssemblyName; + SplitPath(ssAssemblyPath, + NULL, // drive + NULL, // dir + &ssAssemblyName, // name + NULL); // ext + if (!ssAssemblyName.IsEmpty()) + { + *pszTypeName = "FakeTypeNameForCLRBinding"; + ssAssemblyName.ConvertToUTF8(*pssFakeNameSpaceAllocationBuffer); + *pszNameSpace = pssFakeNameSpaceAllocationBuffer->GetUTF8NoConvert(); + return S_OK; + } + } + + return CLR_E_BIND_TYPE_NOT_FOUND; +} // GetFirstWinRTTypeDef + +// -------------------------------------------------------------------------------------- +//static +HRESULT +GetBindableWinRTName( + IMDInternalImport * pMDInternalImport, + IAssemblyName * pIAssemblyName) +{ + STANDARD_VM_CONTRACT; + + HRESULT hr = S_OK; + + LPCSTR szNameSpace; + LPCSTR szTypeName; + + // Note: This function is used only by native binder which does not support empty WinMDs - see code:CEECompileInfo::LoadAssemblyByPath + // Therefore we do not have to use file name to create fake type name + IfFailRet(GetFirstWinRTTypeDef(pMDInternalImport, &szNameSpace, &szTypeName, NULL, NULL)); + + DWORD dwSize = MAX_PATH_FNAME; + WCHAR wzAsmName[MAX_PATH_FNAME]; + + dwSize = MAX_PATH_FNAME * sizeof(WCHAR); + IfFailRet(pIAssemblyName->GetProperty(ASM_NAME_NAME, wzAsmName, &dwSize)); + + StackSString sNamespaceAndType(wzAsmName); + sNamespaceAndType.Append(W("!")); + sNamespaceAndType.AppendUTF8(szNameSpace); + sNamespaceAndType.Append(W(".")); + sNamespaceAndType.AppendUTF8(szTypeName); + + pIAssemblyName->SetProperty(ASM_NAME_NAME, sNamespaceAndType.GetUnicode(), (lstrlenW(sNamespaceAndType.GetUnicode()) + 1) * sizeof(WCHAR)); + + return hr; +} |