summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Robinson <arobins@microsoft.com>2018-12-07 14:31:24 -0800
committerGitHub <noreply@github.com>2018-12-07 14:31:24 -0800
commit139bdfd2b9378a7370e8d771811c330488d29ea2 (patch)
treee145b95746dbdb28a9d44b2384a0bbd58c745adf
parentd52df656f0a4c3dc6591698575cd598ea6d5272a (diff)
downloadcoreclr-139bdfd2b9378a7370e8d771811c330488d29ea2.tar.gz
coreclr-139bdfd2b9378a7370e8d771811c330488d29ea2.tar.bz2
coreclr-139bdfd2b9378a7370e8d771811c330488d29ea2.zip
Add support for loading registered TLBs (#21430)
* Add support for loading registered TLBs
-rw-r--r--src/inc/corerror.xml6
-rw-r--r--src/pal/prebuilt/corerror/mscorurt.rc1
-rw-r--r--src/pal/prebuilt/inc/corerror.h1
-rw-r--r--src/vm/assembly.cpp51
-rw-r--r--src/vm/assembly.hpp12
-rw-r--r--src/vm/interoputil.cpp42
-rw-r--r--src/vm/interoputil.h14
-rw-r--r--src/vm/marshalnative.cpp2
-rw-r--r--src/vm/olevariant.cpp8
-rw-r--r--src/vm/stdinterfaces.cpp97
-rw-r--r--src/vm/stdinterfaces.h2
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);
//-------------------------------------------------------------------------------------