diff options
author | Aaron Robinson <arobins@microsoft.com> | 2018-12-07 14:31:24 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-12-07 14:31:24 -0800 |
commit | 139bdfd2b9378a7370e8d771811c330488d29ea2 (patch) | |
tree | e145b95746dbdb28a9d44b2384a0bbd58c745adf /src | |
parent | d52df656f0a4c3dc6591698575cd598ea6d5272a (diff) | |
download | coreclr-139bdfd2b9378a7370e8d771811c330488d29ea2.tar.gz coreclr-139bdfd2b9378a7370e8d771811c330488d29ea2.tar.bz2 coreclr-139bdfd2b9378a7370e8d771811c330488d29ea2.zip |
Add support for loading registered TLBs (#21430)
* Add support for loading registered TLBs
Diffstat (limited to 'src')
-rw-r--r-- | src/inc/corerror.xml | 6 | ||||
-rw-r--r-- | src/pal/prebuilt/corerror/mscorurt.rc | 1 | ||||
-rw-r--r-- | src/pal/prebuilt/inc/corerror.h | 1 | ||||
-rw-r--r-- | src/vm/assembly.cpp | 51 | ||||
-rw-r--r-- | src/vm/assembly.hpp | 12 | ||||
-rw-r--r-- | src/vm/interoputil.cpp | 42 | ||||
-rw-r--r-- | src/vm/interoputil.h | 14 | ||||
-rw-r--r-- | src/vm/marshalnative.cpp | 2 | ||||
-rw-r--r-- | src/vm/olevariant.cpp | 8 | ||||
-rw-r--r-- | src/vm/stdinterfaces.cpp | 97 | ||||
-rw-r--r-- | src/vm/stdinterfaces.h | 2 |
11 files changed, 170 insertions, 66 deletions
diff --git a/src/inc/corerror.xml b/src/inc/corerror.xml index 713fce20fc..c98ac83e02 100644 --- a/src/inc/corerror.xml +++ b/src/inc/corerror.xml @@ -388,6 +388,12 @@ <Comment> A token of the wrong type passed to a metadata function. </Comment> </HRESULT> +<HRESULT NumericValue="0x80131165"> + <SymbolicName>TLBX_E_LIBNOTREGISTERED</SymbolicName> + <Message>"Typelib export: Type library is not registered."</Message> + <Comment> Typelib export: type library is not registered. </Comment> +</HRESULT> + <HRESULT NumericValue="0x8013118a"> <SymbolicName>META_E_BADMETADATA</SymbolicName> <Message>"Merge: Inconsistency in meta data import scope."</Message> diff --git a/src/pal/prebuilt/corerror/mscorurt.rc b/src/pal/prebuilt/corerror/mscorurt.rc index 35b26618a1..25a6870d79 100644 --- a/src/pal/prebuilt/corerror/mscorurt.rc +++ b/src/pal/prebuilt/corerror/mscorurt.rc @@ -51,6 +51,7 @@ BEGIN MSG_FOR_URT_HR(CLDB_E_RECORD_OUTOFORDER) "Record is emitted out of order." MSG_FOR_URT_HR(CLDB_E_TOO_BIG) "A blob or string was too big." MSG_FOR_URT_HR(META_E_INVALID_TOKEN_TYPE) "A token of the wrong type passed to a metadata function." + MSG_FOR_URT_HR(TLBX_E_LIBNOTREGISTERED) "Typelib export: Type library is not registered." MSG_FOR_URT_HR(META_E_BADMETADATA) "Merge: Inconsistency in meta data import scope." MSG_FOR_URT_HR(META_E_BAD_SIGNATURE) "Bad binary signature." MSG_FOR_URT_HR(META_E_BAD_INPUT_PARAMETER) "Bad input parameters." diff --git a/src/pal/prebuilt/inc/corerror.h b/src/pal/prebuilt/inc/corerror.h index 237cd40aa6..9ca564a8a8 100644 --- a/src/pal/prebuilt/inc/corerror.h +++ b/src/pal/prebuilt/inc/corerror.h @@ -78,6 +78,7 @@ #define CLDB_E_RECORD_OUTOFORDER EMAKEHR(0x1135) #define CLDB_E_TOO_BIG EMAKEHR(0x1154) #define META_E_INVALID_TOKEN_TYPE EMAKEHR(0x115f) +#define TLBX_E_LIBNOTREGISTERED EMAKEHR(0x1165) #define META_E_BADMETADATA EMAKEHR(0x118a) #define META_E_BAD_SIGNATURE EMAKEHR(0x1192) #define META_E_BAD_INPUT_PARAMETER EMAKEHR(0x1193) diff --git a/src/vm/assembly.cpp b/src/vm/assembly.cpp index 2f82a97c2e..5724c6643d 100644 --- a/src/vm/assembly.cpp +++ b/src/vm/assembly.cpp @@ -118,6 +118,7 @@ Assembly::Assembly(BaseDomain *pDomain, PEAssembly* pFile, DebuggerAssemblyContr m_pLoaderAllocator(NULL), m_isDisabledPrivateReflection(0), #ifdef FEATURE_COMINTEROP + m_pITypeLib(NULL), m_winMDStatus(WinMDStatus_Unknown), m_pManifestWinMDImport(NULL), #endif // FEATURE_COMINTEROP @@ -275,6 +276,11 @@ Assembly::~Assembly() { m_pManifestWinMDImport->Release(); } + + if (m_pITypeLib != nullptr && m_pITypeLib != Assembly::InvalidTypeLib) + { + m_pITypeLib->Release(); + } #endif // FEATURE_COMINTEROP } @@ -1983,6 +1989,51 @@ BOOL Assembly::IsInstrumentedHelper() } #endif // FEATURE_PREJIT + +#ifdef FEATURE_COMINTEROP + +ITypeLib * const Assembly::InvalidTypeLib = (ITypeLib *)-1; + +ITypeLib* Assembly::GetTypeLib() +{ + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + FORBID_FAULT; + } + CONTRACTL_END + + ITypeLib *pTlb = m_pITypeLib; + if (pTlb != nullptr && pTlb != Assembly::InvalidTypeLib) + pTlb->AddRef(); + + return pTlb; +} // ITypeLib* Assembly::GetTypeLib() + +bool Assembly::TrySetTypeLib(_In_ ITypeLib *pNew) +{ + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + FORBID_FAULT; + PRECONDITION(CheckPointer(pNew)); + } + CONTRACTL_END + + ITypeLib *pOld = InterlockedCompareExchangeT(&m_pITypeLib, pNew, nullptr); + if (pOld != nullptr) + return false; + + if (pNew != Assembly::InvalidTypeLib) + pNew->AddRef(); + + return true; +} // void Assembly::SetTypeLib() + +#endif // FEATURE_COMINTEROP + //*********************************************************** // Add an assembly to the assemblyref list. pAssemEmitter specifies where // the AssemblyRef is emitted to. diff --git a/src/vm/assembly.hpp b/src/vm/assembly.hpp index 24f2547bde..99f0fbfca7 100644 --- a/src/vm/assembly.hpp +++ b/src/vm/assembly.hpp @@ -455,6 +455,16 @@ public: BOOL IsInstrumentedHelper(); #endif // FEATURE_PREJIT +#ifdef FEATURE_COMINTEROP + static ITypeLib * const InvalidTypeLib; + + // Get any cached ITypeLib* for the assembly. + ITypeLib *GetTypeLib(); + + // Try to set the ITypeLib*, if one is not already cached. + bool TrySetTypeLib(_In_ ITypeLib *pTlb); +#endif // FEATURE_COMINTEROP + #ifndef DACCESS_COMPILE void DECLSPEC_NORETURN ThrowTypeLoadException(LPCUTF8 pszFullName, UINT resIDWhy); @@ -604,6 +614,8 @@ private: DWORD m_isDisabledPrivateReflection; #ifdef FEATURE_COMINTEROP + // If a TypeLib is ever required for this module, cache the pointer here. + ITypeLib *m_pITypeLib; InteropAttributeStatus m_InteropAttributeStatus; WinMDStatus m_winMDStatus; diff --git a/src/vm/interoputil.cpp b/src/vm/interoputil.cpp index 513813c4d8..6b4f14babe 100644 --- a/src/vm/interoputil.cpp +++ b/src/vm/interoputil.cpp @@ -2182,12 +2182,10 @@ ComCallWrapper* GetCCWFromIUnknown(IUnknown* pUnk, BOOL bEnableCustomization) RETURN pWrap; } - -HRESULT LoadRegTypeLibWithFlags(REFGUID guid, - unsigned short wVerMajor, - unsigned short wVerMinor, - int flags, - ITypeLib** pptlib) +HRESULT LoadRegTypeLib(_In_ REFGUID guid, + _In_ unsigned short wVerMajor, + _In_ unsigned short wVerMinor, + _Outptr_ ITypeLib **pptlib) { CONTRACTL { @@ -2207,6 +2205,15 @@ HRESULT LoadRegTypeLibWithFlags(REFGUID guid, EX_TRY { hr = QueryPathOfRegTypeLib(guid, wVerMajor, wVerMinor, LOCALE_USER_DEFAULT, &wzPath); + if (SUCCEEDED(hr)) + { +#ifdef _WIN64 + REGKIND rk = (REGKIND)(REGKIND_NONE | LOAD_TLB_AS_64BIT); +#else + REGKIND rk = (REGKIND)(REGKIND_NONE | LOAD_TLB_AS_32BIT); +#endif // _WIN64 + hr = LoadTypeLibEx(wzPath, rk, pptlib); + } } EX_CATCH { @@ -2214,32 +2221,9 @@ HRESULT LoadRegTypeLibWithFlags(REFGUID guid, } EX_END_CATCH(SwallowAllExceptions); - if (FAILED(hr)) - return hr; - - hr = LoadTypeLibExWithFlags(wzPath, flags, pptlib); - return hr; } - -HRESULT LoadTypeLibExWithFlags(LPCOLESTR szFile, - int flags, - ITypeLib** pptlib) -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - return E_FAIL; -} - - - // HRESULT for CLR created IErrorInfo pointers are accessible // from the enclosing simple wrapper // This is in-proc only. diff --git a/src/vm/interoputil.h b/src/vm/interoputil.h index 02c0a9b792..9c6dcb6a58 100644 --- a/src/vm/interoputil.h +++ b/src/vm/interoputil.h @@ -188,16 +188,10 @@ ComCallWrapper* GetCCWFromIUnknown(IUnknown* pUnk, BOOL bEnableCustomization = T // A version of LoadRegTypeLib that loads based on bitness and platform support // and loads with LCID == LOCALE_USER_DEFAULT -HRESULT LoadRegTypeLibWithFlags(REFGUID rguid, - unsigned short wVerMajor, - unsigned short wVerMinor, - int flags, - ITypeLib FAR* FAR* pptlib); - -// A version of LoadTypeLibEx that loads based on bitness and platform support. -HRESULT LoadTypeLibExWithFlags(LPCOLESTR szFile, - int flags, - ITypeLib** pptlib); +HRESULT LoadRegTypeLib(_In_ REFGUID guid, + _In_ unsigned short wVerMajor, + _In_ unsigned short wVerMinor, + _Outptr_ ITypeLib **pptlib); //------------------------------------------------------------------------------- // Given an IErrorInfo pointer created on a com exception obect diff --git a/src/vm/marshalnative.cpp b/src/vm/marshalnative.cpp index 75b6d3542c..cacc09ae3a 100644 --- a/src/vm/marshalnative.cpp +++ b/src/vm/marshalnative.cpp @@ -1056,7 +1056,7 @@ FCIMPL1(ITypeInfo*, MarshalNative::GetITypeInfoForType, ReflectClassBaseObject* _ASSERTE(pMT); // Retrieve the ITypeInfo for the class. - IfFailThrow(GetITypeInfoForEEClass(pMT, &pTI, true)); + IfFailThrow(GetITypeInfoForEEClass(pMT, &pTI, true /* bClassInfo */)); _ASSERTE(pTI != NULL); HELPER_METHOD_FRAME_END(); diff --git a/src/vm/olevariant.cpp b/src/vm/olevariant.cpp index b874fc4c9a..c1b047c586 100644 --- a/src/vm/olevariant.cpp +++ b/src/vm/olevariant.cpp @@ -4675,11 +4675,11 @@ void OleVariant::ConvertValueClassToVariant(OBJECTREF *pBoxedValueClass, VARIANT V_RECORDINFO(pRecHolder) = NULL; V_RECORD(pRecHolder) = NULL; - // Retrieve the ITypeInfo for the value class. - MethodTable *pValueClassMT = (*pBoxedValueClass)->GetMethodTable(); - IfFailThrow(GetITypeInfoForEEClass(pValueClassMT, &pTypeInfo, TRUE, TRUE, 0)); + // Retrieve the ITypeInfo for the value class. + MethodTable *pValueClassMT = (*pBoxedValueClass)->GetMethodTable(); + IfFailThrow(GetITypeInfoForEEClass(pValueClassMT, &pTypeInfo, true /* bClassInfo */)); - // Convert the ITypeInfo to an IRecordInfo. + // Convert the ITypeInfo to an IRecordInfo. hr = GetRecordInfoFromTypeInfo(pTypeInfo, &V_RECORDINFO(pRecHolder)); if (FAILED(hr)) { diff --git a/src/vm/stdinterfaces.cpp b/src/vm/stdinterfaces.cpp index b96681f76d..9e5b8bcda1 100644 --- a/src/vm/stdinterfaces.cpp +++ b/src/vm/stdinterfaces.cpp @@ -575,7 +575,7 @@ ClassInfo_GetClassInfo(IUnknown* pUnk, ITypeInfo** ppTI) } MethodTable* pClass = pWrap->GetMethodTable(); - IfFailThrow(GetITypeInfoForEEClass(pClass, ppTI, true/*bClassInfo*/)); + IfFailThrow(GetITypeInfoForEEClass(pClass, ppTI, true /* bClassInfo */)); } END_EXTERNAL_ENTRYPOINT; @@ -583,22 +583,87 @@ ClassInfo_GetClassInfo(IUnknown* pUnk, ITypeInfo** ppTI) } //------------------------------------------------------------------------------------------ -// Helper to get the ITypeInfo* for a type. -HRESULT GetITypeLibForEEClass(MethodTable *pClass, ITypeLib **ppTLB, int bAutoCreate, int flags) +// Helper to get the ITypeLib* for a Assembly. +HRESULT GetITypeLibForAssembly(_In_ Assembly *pAssembly, _Outptr_ ITypeLib **ppTlb) { CONTRACTL { NOTHROW; GC_TRIGGERS; MODE_PREEMPTIVE; + PRECONDITION(CheckPointer(pAssembly)); + PRECONDITION(CheckPointer(ppTlb)); } CONTRACTL_END; - return COR_E_NOTSUPPORTED; -} // HRESULT GetITypeLibForEEClass() + // If the module wasn't imported from COM, fail. In .NET Framework the runtime + // would generate a ITypeLib instance, but .NET Core doesn't support that. + if (!pAssembly->IsImportedFromTypeLib()) + return COR_E_NOTSUPPORTED; + HRESULT hr; + + // Check for cached copy. + ITypeLib *pTlb = pAssembly->GetTypeLib(); + if (pTlb != nullptr) + { + // If the cached value is the invalid sentinal, an attempt was already made but failed. + if (pTlb == Assembly::InvalidTypeLib) + return TLBX_E_LIBNOTREGISTERED; + + *ppTlb = pTlb; + return S_OK; + } + + // Retrieve the guid for the assembly. + GUID assemblyGuid; + IfFailRet(GetTypeLibGuidForAssembly(pAssembly, &assemblyGuid)); + + // Retrieve the major and minor version number. + USHORT wMajor; + USHORT wMinor; + IfFailRet(GetTypeLibVersionForAssembly(pAssembly, &wMajor, &wMinor)); + + // Attempt to load the exact TypeLib + hr = LoadRegTypeLib(assemblyGuid, wMajor, wMinor, &pTlb); + if (FAILED(hr)) + { + // Try just the Assembly version + IfFailRet(pAssembly->GetVersion(&wMajor, &wMinor, nullptr, nullptr)); + hr = LoadRegTypeLib(assemblyGuid, wMajor, wMinor, &pTlb); + if (FAILED(hr)) + { + // Try loading the highest registered version. + hr = LoadRegTypeLib(assemblyGuid, -1, -1, &pTlb); + if (FAILED(hr)) + pTlb = Assembly::InvalidTypeLib; + } + } + + bool setCache = pAssembly->TrySetTypeLib(pTlb); + if (!setCache) + { + // Release the TypeLib that isn't going to be used + if (pTlb != Assembly::InvalidTypeLib) + pTlb->Release(); -HRESULT GetITypeInfoForEEClass(MethodTable *pClass, ITypeInfo **ppTI, int bClassInfo/*=false*/, int bAutoCreate/*=true*/, int flags) + // This call lost the race to set the TypeLib so recusively call + // this function again to get the one that is set. + return GetITypeLibForAssembly(pAssembly, ppTlb); + } + + if (FAILED(hr)) + { + // Pass the HRESULT on if it is any error other than "TypeLib not registered". + return (hr == TYPE_E_LIBNOTREGISTERED) ? TLBX_E_LIBNOTREGISTERED : hr; + } + + *ppTlb = pTlb; + return S_OK; +} // HRESULT GetITypeLibForAssembly() + + +HRESULT GetITypeInfoForEEClass(MethodTable *pClass, ITypeInfo **ppTI, bool bClassInfo) { CONTRACTL { @@ -681,7 +746,7 @@ HRESULT GetITypeInfoForEEClass(MethodTable *pClass, ITypeInfo **ppTI, int bClass } // Retrieve the ITypeLib for the assembly containing the type. - IfFailGo(GetITypeLibForEEClass(pClass, &pITLB, bAutoCreate, flags)); + IfFailGo(GetITypeLibForAssembly(pClass->GetAssembly(), &pITLB)); // Get the GUID of the desired TypeRef. IfFailGo(TryGetGuid(pClass, &clsid, TRUE)); @@ -692,8 +757,8 @@ HRESULT GetITypeInfoForEEClass(MethodTable *pClass, ITypeInfo **ppTI, int bClass else if (pClass->IsComImport()) { // This is a COM imported class, with no IClassX. Get default interface. - IfFailGo(GetITypeLibForEEClass(pClass, &pITLB, bAutoCreate, flags)); - IfFailGo(TryGetGuid(pClass, &clsid, TRUE)); + IfFailGo(GetITypeLibForAssembly(pClass->GetAssembly(), &pITLB)); + IfFailGo(TryGetGuid(pClass, &clsid, TRUE)); IfFailGo(pITLB->GetTypeInfoOfGuid(clsid, &pTI)); IfFailGo(GetDefaultInterfaceForCoclass(pTI, &pTIDef)); @@ -717,7 +782,7 @@ HRESULT GetITypeInfoForEEClass(MethodTable *pClass, ITypeInfo **ppTI, int bClass { _ASSERTE(!hndDefItfClass.IsNull()); _ASSERTE(hndDefItfClass.IsInterface()); - hr = GetITypeInfoForEEClass(hndDefItfClass.GetMethodTable(), ppTI, FALSE, bAutoCreate, flags); + hr = GetITypeInfoForEEClass(hndDefItfClass.GetMethodTable(), ppTI, false /* bClassInfo */); break; } @@ -728,7 +793,7 @@ HRESULT GetITypeInfoForEEClass(MethodTable *pClass, ITypeInfo **ppTI, int bClass _ASSERTE(!hndDefItfClass.IsInterface()); // Retrieve the ITypeLib for the assembly containing the type. - IfFailGo(GetITypeLibForEEClass(hndDefItfClass.GetMethodTable(), &pITLB, bAutoCreate, flags)); + IfFailGo(GetITypeLibForAssembly(hndDefItfClass.GetMethodTable()->GetAssembly(), &pITLB)); // Get the GUID of the desired TypeRef. IfFailGo(TryGetGuid(hndDefItfClass.GetMethodTable(), &clsid, TRUE)); @@ -759,16 +824,6 @@ HRESULT GetITypeInfoForEEClass(MethodTable *pClass, ITypeInfo **ppTI, int bClass } } - if (bAutoCreate && SUCCEEDED(hr)) - { - EX_TRY - { - // Make sure that marshaling recognizes CLSIDs of types with autogenerated ITypeInfo. - GetAppDomain()->InsertClassForCLSID(pClass, TRUE); - } - EX_CATCH_HRESULT(hr) - } - ErrExit: if (*ppTI == NULL) { diff --git a/src/vm/stdinterfaces.h b/src/vm/stdinterfaces.h index fd274d4bfc..ab0e4b22bd 100644 --- a/src/vm/stdinterfaces.h +++ b/src/vm/stdinterfaces.h @@ -523,7 +523,7 @@ HRESULT TryGetGuid(MethodTable* pClass, GUID* pGUID, BOOL b); //------------------------------------------------------------------------------------------ // Helpers to get the ITypeInfo* for a type. -HRESULT GetITypeInfoForEEClass(MethodTable *pMT, ITypeInfo **ppTI, int bClassInfo=false, int bAutoCreate=true, int flags=0); +HRESULT GetITypeInfoForEEClass(MethodTable *pMT, ITypeInfo **ppTI, bool bClassInfo = false); HRESULT GetDefaultInterfaceForCoclass(ITypeInfo *pTI, ITypeInfo **ppTIDef); //------------------------------------------------------------------------------------- |