1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 /*============================================================
7 ** Header: AssemblyNative.cpp
9 ** Purpose: Implements AssemblyNative (loader domain) architecture
15 ===========================================================*/
21 #include "assemblynative.hpp"
22 #include "dllimport.h"
24 #include "assemblyname.hpp"
26 #include "strongname.h"
27 #include "interoputil.h"
29 #include "typeparse.h"
30 #include "stackprobe.h"
32 #include "appdomainnative.hpp"
33 #include "../binder/inc/clrprivbindercoreclr.h"
37 FCIMPL7(Object*, AssemblyNative::Load, AssemblyNameBaseObject* assemblyNameUNSAFE,
38 StringObject* codeBaseUNSAFE,
39 AssemblyBaseObject* requestingAssemblyUNSAFE,
40 StackCrawlMark* stackMark,
41 ICLRPrivBinder * pPrivHostBinder,
42 CLR_BOOL fThrowOnFileNotFound,
43 INT_PTR ptrLoadContextBinder)
49 ASSEMBLYNAMEREF assemblyName;
51 ASSEMBLYREF requestingAssembly;
55 gc.assemblyName = (ASSEMBLYNAMEREF) assemblyNameUNSAFE;
56 gc.codeBase = (STRINGREF) codeBaseUNSAFE;
57 gc.requestingAssembly = (ASSEMBLYREF) requestingAssemblyUNSAFE;
60 HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
62 if (gc.assemblyName == NULL)
63 COMPlusThrow(kArgumentNullException, W("ArgumentNull_AssemblyName"));
65 Thread * pThread = GetThread();
66 CheckPointHolder cph(pThread->m_MarshalAlloc.GetCheckpoint()); //hold checkpoint for autorelease
68 DomainAssembly * pParentAssembly = NULL;
69 Assembly * pRefAssembly = NULL;
71 if(gc.assemblyName->GetSimpleName() == NULL)
73 if (gc.codeBase == NULL)
74 COMPlusThrow(kArgumentException, W("Format_StringZeroLength"));
78 // name specified, if immersive ignore the codebase
79 if (GetThread()->GetDomain()->HasLoadContextHostBinder())
82 // Compute parent assembly
83 if (gc.requestingAssembly == NULL)
85 pRefAssembly = SystemDomain::GetCallersAssembly(stackMark);
87 // Cross-appdomain callers aren't allowed as the parent
89 (pRefAssembly->GetDomain() != pThread->GetDomain()))
95 pRefAssembly = gc.requestingAssembly->GetAssembly();
97 // Shared or collectible assemblies should not be used for the parent in the
99 if (pRefAssembly && (!pRefAssembly->IsDomainNeutral()) && (!pRefAssembly->IsCollectible()))
101 pParentAssembly= pRefAssembly->GetDomainAssembly();
108 spec.InitializeSpec(&(pThread->m_MarshalAlloc),
113 if (!spec.HasUniqueIdentity())
114 { // Insuficient assembly name for binding (e.g. ContentType=WindowsRuntime cannot bind by assembly name)
115 EEFileLoadException::Throw(&spec, COR_E_NOTSUPPORTED);
118 if (pPrivHostBinder != NULL)
120 pParentAssembly = NULL;
121 spec.SetHostBinder(pPrivHostBinder);
124 if (gc.codeBase != NULL)
125 spec.SetCodeBase(&(pThread->m_MarshalAlloc), &gc.codeBase);
127 if (pParentAssembly != NULL)
128 spec.SetParentAssembly(pParentAssembly);
130 // Have we been passed the reference to the binder against which this load should be triggered?
131 // If so, then use it to set the fallback load context binder.
132 if (ptrLoadContextBinder != NULL)
134 spec.SetFallbackLoadContextBinderForRequestingAssembly(reinterpret_cast<ICLRPrivBinder *>(ptrLoadContextBinder));
135 spec.SetPreferFallbackLoadContextBinder();
137 else if (pRefAssembly != NULL)
139 // If the requesting assembly has Fallback LoadContext binder available,
140 // then set it up in the AssemblySpec.
141 PEFile *pRefAssemblyManifestFile = pRefAssembly->GetManifestFile();
142 spec.SetFallbackLoadContextBinderForRequestingAssembly(pRefAssemblyManifestFile->GetFallbackLoadContextBinder());
149 pAssembly = spec.LoadAssembly(FILE_LOADED, fThrowOnFileNotFound, FALSE /*fRaisePrebindEvents*/, stackMark);
152 if (pAssembly != NULL)
153 gc.rv = (ASSEMBLYREF) pAssembly->GetExposedObject();
155 HELPER_METHOD_FRAME_END();
157 return OBJECTREFToObject(gc.rv);
162 Assembly* AssemblyNative::LoadFromPEImage(ICLRPrivBinder* pBinderContext, PEImage *pILImage, PEImage *pNIImage)
167 PRECONDITION(CheckPointer(pBinderContext));
168 POSTCONDITION(CheckPointer(RETVAL));
172 Assembly *pLoadedAssembly = NULL;
174 ReleaseHolder<ICLRPrivAssembly> pAssembly;
176 // Get the correct PEImage to work with.
177 BOOL fIsNativeImage = TRUE;
178 PEImage *pImage = pNIImage;
179 if (pNIImage == NULL)
181 // Since we do not have a NI image, we are working with IL assembly
183 fIsNativeImage = FALSE;
185 _ASSERTE(pImage != NULL);
187 BOOL fHadLoadFailure = FALSE;
189 // Force the image to be loaded and mapped so that subsequent loads do not
190 // map a duplicate copy.
191 if (pImage->IsFile())
197 pImage->LoadNoFile();
200 DWORD dwMessageID = IDS_EE_FILELOAD_ERROR_GENERIC;
202 // Set the caller's assembly to be mscorlib
203 DomainAssembly *pCallersAssembly = SystemDomain::System()->SystemAssembly()->GetDomainAssembly();
204 PEAssembly *pParentAssembly = pCallersAssembly->GetFile();
206 // Initialize the AssemblySpec
208 spec.InitializeSpec(TokenFromRid(1, mdtAssembly), pImage->GetMDImport(), pCallersAssembly);
209 spec.SetBindingContext(pBinderContext);
212 PTR_AppDomain pCurDomain = GetAppDomain();
213 CLRPrivBinderCoreCLR *pTPABinder = pCurDomain->GetTPABinderContext();
214 if (!AreSameBinderInstance(pTPABinder, pBinderContext))
216 // We are working with custom Assembly Load Context so bind the assembly using it.
217 CLRPrivBinderAssemblyLoadContext *pBinder = reinterpret_cast<CLRPrivBinderAssemblyLoadContext *>(pBinderContext);
218 hr = pBinder->BindUsingPEImage(pImage, fIsNativeImage, &pAssembly);
222 // Bind the assembly using TPA binder
223 hr = pTPABinder->BindUsingPEImage(pImage, fIsNativeImage, &pAssembly);
228 // Give a more specific message for the case when we found the assembly with the same name already loaded.
229 if (hr == COR_E_FILELOAD)
231 dwMessageID = IDS_HOST_ASSEMBLY_RESOLVER_ASSEMBLY_ALREADY_LOADED_IN_CONTEXT;
235 spec.GetFileOrDisplayName(0, name);
236 COMPlusThrowHR(COR_E_FILELOAD, dwMessageID, name);
239 BINDER_SPACE::Assembly* assem;
240 assem = BINDER_SPACE::GetAssemblyFromPrivAssemblyFast(pAssembly);
242 PEAssemblyHolder pPEAssembly(PEAssembly::Open(pParentAssembly, assem->GetPEImage(), assem->GetNativePEImage(), pAssembly, FALSE));
244 DomainAssembly *pDomainAssembly = pCurDomain->LoadDomainAssembly(&spec, pPEAssembly, FILE_LOADED);
245 RETURN pDomainAssembly->GetAssembly();
249 void QCALLTYPE AssemblyNative::LoadFromPath(INT_PTR ptrNativeAssemblyLoadContext, LPCWSTR pwzILPath, LPCWSTR pwzNIPath, QCall::ObjectHandleOnStack retLoadedAssembly)
255 PTR_AppDomain pCurDomain = GetAppDomain();
257 // Get the binder context in which the assembly will be loaded.
258 ICLRPrivBinder *pBinderContext = reinterpret_cast<ICLRPrivBinder*>(ptrNativeAssemblyLoadContext);
259 _ASSERTE(pBinderContext != NULL);
261 // Form the PEImage for the ILAssembly. Incase of an exception, the holders will ensure
262 // the release of the image.
263 PEImageHolder pILImage, pNIImage;
265 if (pwzILPath != NULL)
267 pILImage = PEImage::OpenImage(pwzILPath);
269 // Need to verify that this is a valid CLR assembly.
270 if (!pILImage->CheckILFormat())
271 ThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_IL);
274 // Form the PEImage for the NI assembly, if specified
275 if (pwzNIPath != NULL)
277 pNIImage = PEImage::OpenImage(pwzNIPath, MDInternalImport_TrustedNativeImage);
279 if (pNIImage->HasReadyToRunHeader())
281 // ReadyToRun images are treated as IL images by the rest of the system
282 if (!pNIImage->CheckILFormat())
283 ThrowHR(COR_E_BADIMAGEFORMAT);
285 pILImage = pNIImage.Extract();
290 if (!pNIImage->CheckNativeFormat())
291 ThrowHR(COR_E_BADIMAGEFORMAT);
295 Assembly *pLoadedAssembly = AssemblyNative::LoadFromPEImage(pBinderContext, pILImage, pNIImage);
299 retLoadedAssembly.Set(pLoadedAssembly->GetExposedObject());
304 "\tLoaded assembly from a file\n"));
310 INT_PTR QCALLTYPE AssemblyNative::InternalLoadUnmanagedDllFromPath(LPCWSTR unmanagedLibraryPath)
314 HMODULE moduleHandle = nullptr;
318 moduleHandle = NDirect::LoadLibraryFromPath(unmanagedLibraryPath);
322 return reinterpret_cast<INT_PTR>(moduleHandle);
326 void QCALLTYPE AssemblyNative::LoadFromStream(INT_PTR ptrNativeAssemblyLoadContext, INT_PTR ptrAssemblyArray,
327 INT32 cbAssemblyArrayLength, INT_PTR ptrSymbolArray, INT32 cbSymbolArrayLength,
328 QCall::ObjectHandleOnStack retLoadedAssembly)
334 // Ensure that the invariants are in place
335 _ASSERTE(ptrNativeAssemblyLoadContext != NULL);
336 _ASSERTE((ptrAssemblyArray != NULL) && (cbAssemblyArrayLength > 0));
337 _ASSERTE((ptrSymbolArray == NULL) || (cbSymbolArrayLength > 0));
339 // We must have a flat image stashed away since we need a private
340 // copy of the data which we can verify before doing the mapping.
341 PVOID pAssemblyArray = reinterpret_cast<PVOID>(ptrAssemblyArray);
343 PEImageHolder pILImage(PEImage::LoadFlat(pAssemblyArray, (COUNT_T)cbAssemblyArrayLength));
345 // Need to verify that this is a valid CLR assembly.
346 if (!pILImage->CheckILFormat())
347 ThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_IL);
349 // Get the binder context in which the assembly will be loaded
350 ICLRPrivBinder *pBinderContext = reinterpret_cast<ICLRPrivBinder*>(ptrNativeAssemblyLoadContext);
352 // Pass the stream based assembly as IL and NI in an attempt to bind and load it
353 Assembly* pLoadedAssembly = AssemblyNative::LoadFromPEImage(pBinderContext, pILImage, NULL);
356 retLoadedAssembly.Set(pLoadedAssembly->GetExposedObject());
361 "\tLoaded assembly from a file\n"));
363 // In order to assign the PDB image (if present),
364 // the resulting assembly's image needs to be exactly the one
365 // we created above. We need pointer comparison instead of pe image equivalence
366 // to avoid mixed binaries/PDB pairs of other images.
367 // This applies to both Desktop CLR and CoreCLR, with or without fusion.
368 BOOL fIsSameAssembly = (pLoadedAssembly->GetManifestFile()->GetILimage() == pILImage);
370 // Setting the PDB info is only applicable for our original assembly.
371 // This applies to both Desktop CLR and CoreCLR, with or without fusion.
374 #ifdef DEBUGGING_SUPPORTED
375 // If we were given symbols, save a copy of them.
376 if (ptrSymbolArray != NULL)
378 PBYTE pSymbolArray = reinterpret_cast<PBYTE>(ptrSymbolArray);
379 pLoadedAssembly->GetManifestModule()->SetSymbolBytes(pSymbolArray, (DWORD)cbSymbolArrayLength);
381 #endif // DEBUGGING_SUPPORTED
387 void QCALLTYPE AssemblyNative::GetLocation(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack retString)
394 retString.Set(pAssembly->GetFile()->GetPath());
400 void QCALLTYPE AssemblyNative::GetType(QCall::AssemblyHandle pAssembly, LPCWSTR wszName, BOOL bThrowOnError, BOOL bIgnoreCase, QCall::ObjectHandleOnStack retType, QCall::ObjectHandleOnStack keepAlive)
405 PRECONDITION(CheckPointer(wszName));
409 TypeHandle retTypeHandle;
414 COMPlusThrowArgumentNull(W("name"), W("ArgumentNull_String"));
416 BOOL prohibitAsmQualifiedName = TRUE;
418 // Load the class from this assembly (fail if it is in a different one).
419 retTypeHandle = TypeName::GetTypeManaged(wszName, pAssembly, bThrowOnError, bIgnoreCase, pAssembly->IsIntrospectionOnly(), prohibitAsmQualifiedName, NULL, FALSE, (OBJECTREF*)keepAlive.m_ppObject);
421 if (!retTypeHandle.IsNull())
424 retType.Set(retTypeHandle.GetManagedClassObject());
432 void QCALLTYPE AssemblyNative::GetForwardedType(QCall::AssemblyHandle pAssembly, mdToken mdtExternalType, QCall::ObjectHandleOnStack retType)
447 Assembly * pAsm = pAssembly->GetAssembly();
448 Module *pManifestModule = pAsm->GetManifestModule();
449 IfFailThrow(pManifestModule->GetMDImport()->GetExportedTypeProps(mdtExternalType, &pszNameSpace, &pszClassName, &mdImpl, NULL, NULL));
450 if (TypeFromToken(mdImpl) == mdtAssemblyRef)
452 NameHandle typeName(pszNameSpace, pszClassName);
453 typeName.SetTypeToken(pManifestModule, mdtExternalType);
454 TypeHandle typeHnd = pAsm->GetLoader()->LoadTypeHandleThrowIfFailed(&typeName);
457 retType.Set(typeHnd.GetManagedClassObject());
466 FCIMPL1(FC_BOOL_RET, AssemblyNative::IsDynamic, AssemblyBaseObject* pAssemblyUNSAFE)
470 ASSEMBLYREF refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE);
472 if (refAssembly == NULL)
473 FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
475 FC_RETURN_BOOL(refAssembly->GetDomainAssembly()->GetFile()->IsDynamic());
479 void QCALLTYPE AssemblyNative::GetVersion(QCall::AssemblyHandle pAssembly, INT32* pMajorVersion, INT32* pMinorVersion, INT32*pBuildNumber, INT32* pRevisionNumber)
485 UINT16 major=0xffff, minor=0xffff, build=0xffff, revision=0xffff;
487 pAssembly->GetFile()->GetVersion(&major, &minor, &build, &revision);
489 *pMajorVersion = major;
490 *pMinorVersion = minor;
491 *pBuildNumber = build;
492 *pRevisionNumber = revision;
497 void QCALLTYPE AssemblyNative::GetPublicKey(QCall::AssemblyHandle pAssembly, QCall::ObjectHandleOnStack retPublicKey)
503 DWORD cbPublicKey = 0;
504 const void *pbPublicKey = pAssembly->GetFile()->GetPublicKey(&cbPublicKey);
505 retPublicKey.SetByteArray((BYTE *)pbPublicKey, cbPublicKey);
510 void QCALLTYPE AssemblyNative::GetSimpleName(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack retSimpleName)
515 retSimpleName.Set(pAssembly->GetSimpleName());
519 void QCALLTYPE AssemblyNative::GetLocale(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack retString)
525 LPCUTF8 pLocale = pAssembly->GetFile()->GetLocale();
528 retString.Set(pLocale);
534 void QCALLTYPE AssemblyNative::GetCodeBase(QCall::AssemblyHandle pAssembly, BOOL fCopiedName, QCall::StringHandleOnStack retString)
540 StackSString codebase;
543 pAssembly->GetFile()->GetCodeBase(codebase);
546 retString.Set(codebase);
551 INT32 QCALLTYPE AssemblyNative::GetHashAlgorithm(QCall::AssemblyHandle pAssembly)
557 retVal = pAssembly->GetFile()->GetHashAlgId();
562 INT32 QCALLTYPE AssemblyNative::GetFlags(QCall::AssemblyHandle pAssembly)
568 retVal = pAssembly->GetFile()->GetFlags();
573 BYTE * QCALLTYPE AssemblyNative::GetResource(QCall::AssemblyHandle pAssembly, LPCWSTR wszName, UINT64 * length, QCall::StackCrawlMarkHandle stackMark, BOOL skipSecurityCheck)
577 PBYTE pbInMemoryResource = NULL;
582 COMPlusThrow(kArgumentNullException, W("ArgumentNull_String"));
584 // Get the name in UTF8
585 SString name(SString::Literal, wszName);
587 StackScratchBuffer scratch;
588 LPCUTF8 pNameUTF8 = name.GetUTF8(scratch);
590 if (*pNameUTF8 == '\0')
591 COMPlusThrow(kArgumentException, W("Format_StringZeroLength"));
594 if (pAssembly->GetResource(pNameUTF8, &cbResource,
595 &pbInMemoryResource, NULL, NULL,
596 NULL, stackMark, skipSecurityCheck, FALSE))
598 *length = cbResource;
603 // Can return null if resource file is zero-length
604 return pbInMemoryResource;
607 INT32 QCALLTYPE AssemblyNative::GetManifestResourceInfo(QCall::AssemblyHandle pAssembly, LPCWSTR wszName, QCall::ObjectHandleOnStack retAssembly, QCall::StringHandleOnStack retFileName, QCall::StackCrawlMarkHandle stackMark)
616 COMPlusThrow(kArgumentNullException, W("ArgumentNull_String"));
618 // Get the name in UTF8
619 SString name(SString::Literal, wszName);
621 StackScratchBuffer scratch;
622 LPCUTF8 pNameUTF8 = name.GetUTF8(scratch);
624 if (*pNameUTF8 == '\0')
625 COMPlusThrow(kArgumentException, W("Format_StringZeroLength"));
627 DomainAssembly * pReferencedAssembly = NULL;
628 LPCSTR pFileName = NULL;
629 DWORD dwLocation = 0;
631 if (pAssembly->GetResource(pNameUTF8, NULL, NULL, &pReferencedAssembly, &pFileName,
632 &dwLocation, stackMark, FALSE, FALSE))
635 retFileName.Set(pFileName);
639 if (pReferencedAssembly)
640 retAssembly.Set(pReferencedAssembly->GetExposedAssemblyObject());
650 void QCALLTYPE AssemblyNative::GetModules(QCall::AssemblyHandle pAssembly, BOOL fLoadIfNotFound, BOOL fGetResourceModules, QCall::ObjectHandleOnStack retModules)
656 HENUMInternalHolder phEnum(pAssembly->GetMDImport());
657 phEnum.EnumInit(mdtFile, mdTokenNil);
659 InlineSArray<DomainFile *, 8> modules;
661 modules.Append(pAssembly);
663 ReflectionModule *pOnDiskManifest = NULL;
664 if (pAssembly->GetAssembly()->NeedsToHideManifestForEmit())
665 pOnDiskManifest = pAssembly->GetAssembly()->GetOnDiskManifestModule();
668 while (pAssembly->GetMDImport()->EnumNext(&phEnum, &mdFile))
670 DomainFile *pModule = pAssembly->GetModule()->LoadModule(GetAppDomain(), mdFile, fGetResourceModules, !fLoadIfNotFound);
672 if (pModule && pModule->GetModule() != pOnDiskManifest) {
673 modules.Append(pModule);
680 PTRARRAYREF orModules = NULL;
682 GCPROTECT_BEGIN(orModules);
684 // Return the modules
685 orModules = (PTRARRAYREF)AllocateObjectArray(modules.GetCount(), MscorlibBinder::GetClass(CLASS__MODULE));
687 for(COUNT_T i = 0; i < modules.GetCount(); i++)
689 DomainFile * pModule = modules[i];
691 OBJECTREF o = pModule->GetExposedModuleObject();
692 orModules->SetAt(i, o);
695 retModules.Set(orModules);
703 BOOL QCALLTYPE AssemblyNative::GetNeutralResourcesLanguageAttribute(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack cultureName, INT16& outFallbackLocation)
713 Assembly * pAsm = pAssembly->GetAssembly();
715 Module * pModule = pAsm->GetManifestModule();
718 LPCUTF8 pszCultureName = NULL;
719 ULONG cultureNameLength = 0;
720 INT16 fallbackLocation = 0;
722 // find the attribute if it exists
723 if (pModule->GetNeutralResourcesLanguage(&pszCultureName, &cultureNameLength, &fallbackLocation, FALSE)) {
724 StackSString culture(SString::Utf8, pszCultureName, cultureNameLength);
725 cultureName.Set(culture);
726 outFallbackLocation = fallbackLocation;
735 void QCALLTYPE AssemblyNative::GetModule(QCall::AssemblyHandle pAssembly, LPCWSTR wszFileName, QCall::ObjectHandleOnStack retModule)
741 Module * pModule = NULL;
745 if (wszFileName == NULL)
746 COMPlusThrow(kArgumentNullException, W("ArgumentNull_FileName"));
747 if (wszFileName[0] == W('\0'))
748 COMPlusThrow(kArgumentException, W("Argument_EmptyFileName"));
751 MAKE_UTF8PTR_FROMWIDE(szModuleName, wszFileName);
754 LPCUTF8 pModuleName = NULL;
756 if SUCCEEDED(pAssembly->GetDomainAssembly()->GetModule()->GetScopeName(&pModuleName))
758 if (::SString::_stricmp(pModuleName, szModuleName) == 0)
759 pModule = pAssembly->GetDomainAssembly()->GetModule();
766 retModule.Set(pModule->GetExposedObject());
774 void QCALLTYPE AssemblyNative::GetExportedTypes(QCall::AssemblyHandle pAssembly, QCall::ObjectHandleOnStack retTypes)
780 InlineSArray<TypeHandle, 20> types;
782 Assembly * pAsm = pAssembly->GetAssembly();
784 IMDInternalImport *pImport = pAsm->GetManifestImport();
787 HENUMTypeDefInternalHolder phTDEnum(pImport);
788 phTDEnum.EnumTypeDefInit();
791 while(pImport->EnumNext(&phTDEnum, &mdTD))
794 IfFailThrow(pImport->GetTypeDefProps(
800 mdTypeDef mdEncloser = mdTD;
801 while (SUCCEEDED(pImport->GetNestedClassProps(mdEncloser, &mdEncloser)) &&
802 IsTdNestedPublic(dwFlags))
804 IfFailThrow(pImport->GetTypeDefProps(
810 if (IsTdPublic(dwFlags))
812 TypeHandle typeHnd = ClassLoader::LoadTypeDefThrowing(pAsm->GetManifestModule(), mdTD,
813 ClassLoader::ThrowIfNotFound,
814 ClassLoader::PermitUninstDefOrRef);
815 types.Append(typeHnd);
821 HENUMInternalHolder phCTEnum(pImport);
822 phCTEnum.EnumInit(mdtExportedType, mdTokenNil);
824 // Now get the ExportedTypes that don't have TD's in the manifest file
826 while(pImport->EnumNext(&phCTEnum, &mdCT))
833 IfFailThrow(pImport->GetExportedTypeProps(
842 while ((TypeFromToken(mdImpl) == mdtExportedType) &&
843 (mdImpl != mdExportedTypeNil) &&
844 IsTdNestedPublic(dwFlags))
846 IfFailThrow(pImport->GetExportedTypeProps(
855 if ((TypeFromToken(mdImpl) == mdtFile) &&
856 (mdImpl != mdFileNil) &&
859 NameHandle typeName(pszNameSpace, pszClassName);
860 typeName.SetTypeToken(pAsm->GetManifestModule(), mdCT);
861 TypeHandle typeHnd = pAsm->GetLoader()->LoadTypeHandleThrowIfFailed(&typeName);
863 types.Append(typeHnd);
871 PTRARRAYREF orTypes = NULL;
873 GCPROTECT_BEGIN(orTypes);
876 orTypes = (PTRARRAYREF)AllocateObjectArray(types.GetCount(), MscorlibBinder::GetClass(CLASS__TYPE));
878 for(COUNT_T i = 0; i < types.GetCount(); i++)
880 TypeHandle typeHnd = types[i];
882 OBJECTREF o = typeHnd.GetManagedClassObject();
883 orTypes->SetAt(i, o);
886 retTypes.Set(orTypes);
894 void QCALLTYPE AssemblyNative::GetForwardedTypes(QCall::AssemblyHandle pAssembly, QCall::ObjectHandleOnStack retTypes)
900 InlineSArray<TypeHandle, 8> types;
902 Assembly * pAsm = pAssembly->GetAssembly();
904 IMDInternalImport *pImport = pAsm->GetManifestImport();
906 // enumerate the ExportedTypes table
908 HENUMInternalHolder phCTEnum(pImport);
909 phCTEnum.EnumInit(mdtExportedType, mdTokenNil);
911 // Now get the ExportedTypes that don't have TD's in the manifest file
913 while(pImport->EnumNext(&phCTEnum, &mdCT))
920 IfFailThrow(pImport->GetExportedTypeProps(mdCT,
927 if ((TypeFromToken(mdImpl) == mdtAssemblyRef) && (mdImpl != mdAssemblyRefNil))
929 NameHandle typeName(pszNameSpace, pszClassName);
930 typeName.SetTypeToken(pAsm->GetManifestModule(), mdCT);
931 TypeHandle typeHnd = pAsm->GetLoader()->LoadTypeHandleThrowIfFailed(&typeName);
933 types.Append(typeHnd);
942 PTRARRAYREF orTypes = NULL;
944 GCPROTECT_BEGIN(orTypes);
947 orTypes = (PTRARRAYREF)AllocateObjectArray(types.GetCount(), MscorlibBinder::GetClass(CLASS__TYPE));
949 for(COUNT_T i = 0; i < types.GetCount(); i++)
951 TypeHandle typeHnd = types[i];
953 OBJECTREF o = typeHnd.GetManagedClassObject();
954 orTypes->SetAt(i, o);
957 retTypes.Set(orTypes);
965 FCIMPL1(Object*, AssemblyNative::GetManifestResourceNames, AssemblyBaseObject * pAssemblyUNSAFE)
969 ASSEMBLYREF refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE);
971 if (refAssembly == NULL)
972 FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
974 DomainAssembly *pAssembly = refAssembly->GetDomainAssembly();
975 PTRARRAYREF rv = NULL;
977 HELPER_METHOD_FRAME_BEGIN_RET_2(rv, refAssembly);
979 IMDInternalImport *pImport = pAssembly->GetMDImport();
981 HENUMInternalHolder phEnum(pImport);
984 phEnum.EnumInit(mdtManifestResource, mdTokenNil);
985 dwCount = pImport->EnumGetCount(&phEnum);
987 PTRARRAYREF ItemArray = (PTRARRAYREF) AllocateObjectArray(dwCount, g_pStringClass);
989 mdManifestResource mdResource;
991 GCPROTECT_BEGIN(ItemArray);
992 for(DWORD i = 0; i < dwCount; i++) {
993 pImport->EnumNext(&phEnum, &mdResource);
994 LPCSTR pszName = NULL;
996 IfFailThrow(pImport->GetManifestResourceProps(
1003 OBJECTREF o = (OBJECTREF) StringObject::NewString(pszName);
1004 ItemArray->SetAt(i, o);
1010 HELPER_METHOD_FRAME_END();
1012 return OBJECTREFToObject(rv);
1016 FCIMPL1(Object*, AssemblyNative::GetReferencedAssemblies, AssemblyBaseObject * pAssemblyUNSAFE)
1021 PTRARRAYREF ItemArray;
1022 ASSEMBLYNAMEREF pObj;
1023 ASSEMBLYREF refAssembly;
1025 ZeroMemory(&gc, sizeof(gc));
1027 gc.refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE);
1029 if (gc.refAssembly == NULL)
1030 FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
1032 DomainAssembly *pAssembly = gc.refAssembly->GetDomainAssembly();
1034 HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
1036 IMDInternalImport *pImport = pAssembly->GetAssembly()->GetManifestImport();
1038 MethodTable* pAsmNameClass = MscorlibBinder::GetClass(CLASS__ASSEMBLY_NAME);
1040 HENUMInternalHolder phEnum(pImport);
1043 phEnum.EnumInit(mdtAssemblyRef, mdTokenNil);
1045 dwCount = pImport->EnumGetCount(&phEnum);
1047 mdAssemblyRef mdAssemblyRef;
1049 gc.ItemArray = (PTRARRAYREF) AllocateObjectArray(dwCount, pAsmNameClass);
1051 for(DWORD i = 0; i < dwCount; i++)
1053 pImport->EnumNext(&phEnum, &mdAssemblyRef);
1056 spec.InitializeSpec(mdAssemblyRef, pImport);
1058 gc.pObj = (ASSEMBLYNAMEREF) AllocateObject(pAsmNameClass);
1059 spec.AssemblyNameInit(&gc.pObj,NULL);
1061 gc.ItemArray->SetAt(i, (OBJECTREF) gc.pObj);
1064 HELPER_METHOD_FRAME_END();
1066 return OBJECTREFToObject(gc.ItemArray);
1070 void QCALLTYPE AssemblyNative::GetEntryPoint(QCall::AssemblyHandle pAssembly, QCall::ObjectHandleOnStack retMethod)
1074 MethodDesc* pMeth = NULL;
1078 pMeth = pAssembly->GetAssembly()->GetEntryPoint();
1082 retMethod.Set(pMeth->GetStubMethodInfo());
1090 //---------------------------------------------------------------------------------------
1092 // Get the raw bytes making up this assembly
1095 // pAssembly - Assembly to get the data of
1096 // retRawBytes - [out] raw bytes of the assembly
1100 void QCALLTYPE AssemblyNative::GetRawBytes(QCall::AssemblyHandle pAssembly,
1101 QCall::ObjectHandleOnStack retRawBytes)
1106 PEFile *pPEFile = pAssembly->GetFile();
1107 if (pPEFile != NULL)
1109 PEImage *pPEImage = pPEFile->GetILimage();
1111 if (pPEImage != NULL)
1114 pPEImage->GetImageBits(PEImageLayout::LAYOUT_FLAT, dataBuffer);
1116 if (dataBuffer.GetSize() > 0)
1118 retRawBytes.SetByteArray(dataBuffer, dataBuffer.GetSize());
1126 //---------------------------------------------------------------------------------------
1128 // Release QCALL for System.SafePEFileHandle
1133 void QCALLTYPE AssemblyNative::ReleaseSafePEFileHandle(PEFile *pPEFile)
1138 PRECONDITION(CheckPointer(pPEFile));
1149 // save the manifest to disk!
1150 extern void ManagedBitnessFlagsToUnmanagedBitnessFlags(
1151 INT32 portableExecutableKind, INT32 imageFileMachine,
1152 DWORD* pPeFlags, DWORD* pCorhFlags);
1154 void QCALLTYPE AssemblyNative::GetFullName(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack retString)
1161 pAssembly->GetFile()->GetDisplayName(name);
1162 retString.Set(name);
1167 void QCALLTYPE AssemblyNative::GetExecutingAssembly(QCall::StackCrawlMarkHandle stackMark, QCall::ObjectHandleOnStack retAssembly)
1171 DomainAssembly * pExecutingAssembly = NULL;
1175 Assembly* pAssembly = SystemDomain::GetCallersAssembly(stackMark);
1178 pExecutingAssembly = pAssembly->GetDomainAssembly();
1180 retAssembly.Set(pExecutingAssembly->GetExposedAssemblyObject());
1187 void QCALLTYPE AssemblyNative::GetEntryAssembly(QCall::ObjectHandleOnStack retAssembly)
1193 DomainAssembly * pRootAssembly = NULL;
1194 Assembly * pAssembly = GetAppDomain()->m_pRootAssembly;
1198 pRootAssembly = pAssembly->GetDomainAssembly();
1200 retAssembly.Set(pRootAssembly->GetExposedAssemblyObject());
1208 // return the on disk assembly module for reflection emit. This only works for dynamic assembly.
1209 FCIMPL1(ReflectModuleBaseObject *, AssemblyNative::GetOnDiskAssemblyModule, AssemblyBaseObject* pAssemblyUNSAFE)
1213 ASSEMBLYREF refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE);
1215 if (refAssembly == NULL)
1216 FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
1218 DomainAssembly *pAssembly = refAssembly->GetDomainAssembly();
1220 FC_RETURN_MODULE_OBJECT(pAssembly->GetCurrentAssembly()->GetOnDiskManifestModule(), refAssembly);
1224 // return the in memory assembly module for reflection emit. This only works for dynamic assembly.
1225 FCIMPL1(ReflectModuleBaseObject *, AssemblyNative::GetInMemoryAssemblyModule, AssemblyBaseObject* pAssemblyUNSAFE)
1230 ASSEMBLYREF refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE);
1232 if (refAssembly == NULL)
1233 FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
1235 DomainAssembly *pAssembly = refAssembly->GetDomainAssembly();
1237 FC_RETURN_MODULE_OBJECT(pAssembly->GetCurrentModule(), refAssembly);
1241 void QCALLTYPE AssemblyNative::GetImageRuntimeVersion(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack retString)
1247 // Retrieve the PEFile from the assembly.
1248 PEFile* pPEFile = pAssembly->GetFile();
1249 PREFIX_ASSUME(pPEFile!=NULL);
1251 LPCSTR pszVersion = NULL;
1252 IfFailThrow(pPEFile->GetMDImport()->GetVersionString(&pszVersion));
1254 SString version(SString::Utf8, pszVersion);
1256 // Allocate a managed string that contains the version and return it.
1257 retString.Set(version);
1266 BOOL QCALLTYPE AssemblyNative::IsDesignerBindingContext(QCall::AssemblyHandle pAssembly)
1274 PEFile *pPEFile = pAssembly->GetFile();
1275 fRet = pPEFile->IsDesignerBindingContext();
1281 #endif // FEATURE_APPX
1284 INT_PTR QCALLTYPE AssemblyNative::InitializeAssemblyLoadContext(INT_PTR ptrManagedAssemblyLoadContext, BOOL fRepresentsTPALoadContext)
1288 INT_PTR ptrNativeAssemblyLoadContext = NULL;
1292 // We do not need to take a lock since this method is invoked from the ctor of AssemblyLoadContext managed type and
1293 // only one thread is ever executing a ctor for a given instance.
1296 // Initialize the assembly binder instance in the VM
1297 PTR_AppDomain pCurDomain = AppDomain::GetCurrentDomain();
1298 CLRPrivBinderCoreCLR *pTPABinderContext = pCurDomain->GetTPABinderContext();
1299 if (!fRepresentsTPALoadContext)
1301 // Initialize a custom Assembly Load Context
1302 CLRPrivBinderAssemblyLoadContext *pBindContext = NULL;
1303 IfFailThrow(CLRPrivBinderAssemblyLoadContext::SetupContext(pCurDomain->GetId().m_dwId, pTPABinderContext, ptrManagedAssemblyLoadContext, &pBindContext));
1304 ptrNativeAssemblyLoadContext = reinterpret_cast<INT_PTR>(pBindContext);
1308 // We are initializing the managed instance of Assembly Load Context that would represent the TPA binder.
1309 // First, confirm we do not have an existing managed ALC attached to the TPA binder.
1310 INT_PTR ptrTPAAssemblyLoadContext = pTPABinderContext->GetManagedAssemblyLoadContext();
1311 if ((ptrTPAAssemblyLoadContext != NULL) && (ptrTPAAssemblyLoadContext != ptrManagedAssemblyLoadContext))
1313 COMPlusThrow(kInvalidOperationException, IDS_HOST_ASSEMBLY_RESOLVER_INCOMPATIBLE_TPA_BINDING_CONTEXT);
1316 // Attach the managed TPA binding context with the native one.
1317 pTPABinderContext->SetManagedAssemblyLoadContext(ptrManagedAssemblyLoadContext);
1318 ptrNativeAssemblyLoadContext = reinterpret_cast<INT_PTR>(pTPABinderContext);
1323 return ptrNativeAssemblyLoadContext;
1327 BOOL QCALLTYPE AssemblyNative::OverrideDefaultAssemblyLoadContextForCurrentDomain(INT_PTR ptrNativeAssemblyLoadContext)
1331 BOOL fOverrodeDefaultLoadContext = FALSE;
1335 AppDomain *pCurDomain = AppDomain::GetCurrentDomain();
1337 if (pCurDomain->LockBindingModel())
1339 // Only one thread will ever enter here - it will be the ones that actually locked the binding model
1341 // AssemblyLoadContext should have a binder associated with it
1342 IUnknown *pOverrideBinder = reinterpret_cast<IUnknown *>(ptrNativeAssemblyLoadContext);
1343 _ASSERTE(pOverrideBinder != NULL);
1345 // Get reference to the current default context binder
1347 IUnknown * pCurrentDefaultContextBinder = pCurDomain->GetFusionContext();
1349 // The default context binder can never be null since the runtime always sets one up
1350 _ASSERTE(pCurrentDefaultContextBinder != NULL);
1352 // The default context should also be the same as TPABinder context
1353 _ASSERTE(pCurrentDefaultContextBinder == pCurDomain->GetTPABinderContext());
1355 // Override the default context binder in the VM
1356 pCurDomain->OverrideDefaultContextBinder(pOverrideBinder);
1358 fOverrodeDefaultLoadContext = TRUE;
1363 return fOverrodeDefaultLoadContext;
1366 BOOL QCALLTYPE AssemblyNative::CanUseAppPathAssemblyLoadContextInCurrentDomain()
1370 BOOL fCanUseAppPathAssemblyLoadContext = FALSE;
1374 AppDomain *pCurDomain = AppDomain::GetCurrentDomain();
1376 pCurDomain->LockBindingModel();
1378 fCanUseAppPathAssemblyLoadContext = !pCurDomain->IsHostAssemblyResolverInUse();
1382 return fCanUseAppPathAssemblyLoadContext;
1386 INT_PTR QCALLTYPE AssemblyNative::GetLoadContextForAssembly(QCall::AssemblyHandle pAssembly)
1390 INT_PTR ptrManagedAssemblyLoadContext = NULL;
1394 // Get the PEAssembly for the RuntimeAssembly
1395 PEFile *pPEFile = pAssembly->GetFile();
1396 PTR_PEAssembly pPEAssembly = pPEFile->AsAssembly();
1397 _ASSERTE(pAssembly != NULL);
1399 // Platform assemblies are semantically bound against the "Default" binder which could be the TPA Binder or
1400 // the overridden binder. In either case, the reference to the same will be returned when this QCall returns.
1401 if (!pPEAssembly->IsProfileAssembly())
1403 // Get the binding context for the assembly.
1405 ICLRPrivBinder *pOpaqueBinder = nullptr;
1406 AppDomain *pCurDomain = AppDomain::GetCurrentDomain();
1407 CLRPrivBinderCoreCLR *pTPABinder = pCurDomain->GetTPABinderContext();
1410 // GetBindingContext returns a ICLRPrivAssembly which can be used to get access to the
1411 // actual ICLRPrivBinder instance in which the assembly was loaded.
1412 PTR_ICLRPrivBinder pBindingContext = pPEAssembly->GetBindingContext();
1413 UINT_PTR assemblyBinderID = 0;
1414 IfFailThrow(pBindingContext->GetBinderID(&assemblyBinderID));
1416 // If the assembly was bound using the TPA binder,
1417 // then we will return the reference to "Default" binder from the managed implementation when this QCall returns.
1419 // See earlier comment about "Default" binder for additional context.
1420 pOpaqueBinder = reinterpret_cast<ICLRPrivBinder *>(assemblyBinderID);
1422 // We should have a load context binder at this point.
1423 _ASSERTE(pOpaqueBinder != nullptr);
1425 if (!AreSameBinderInstance(pTPABinder, pOpaqueBinder))
1427 // Only CLRPrivBinderAssemblyLoadContext instance contains the reference to its
1428 // corresponding managed instance.
1429 CLRPrivBinderAssemblyLoadContext *pBinder = (CLRPrivBinderAssemblyLoadContext *)(pOpaqueBinder);
1431 // Fetch the managed binder reference from the native binder instance
1432 ptrManagedAssemblyLoadContext = pBinder->GetManagedAssemblyLoadContext();
1433 _ASSERTE(ptrManagedAssemblyLoadContext != NULL);
1439 return ptrManagedAssemblyLoadContext;
1443 BOOL QCALLTYPE AssemblyNative::InternalTryGetRawMetadata(
1444 QCall::AssemblyHandle assembly,
1450 PTR_CVOID metadata = nullptr;
1454 _ASSERTE(assembly != nullptr);
1455 _ASSERTE(blobRef != nullptr);
1456 _ASSERTE(lengthRef != nullptr);
1458 static_assert_no_msg(sizeof(*lengthRef) == sizeof(COUNT_T));
1459 metadata = assembly->GetFile()->GetLoadedMetadata(reinterpret_cast<COUNT_T *>(lengthRef));
1460 *blobRef = reinterpret_cast<UINT8 *>(const_cast<PTR_VOID>(metadata));
1461 _ASSERTE(*lengthRef >= 0);
1465 return metadata != nullptr;