summaryrefslogtreecommitdiff
path: root/src/vm/assemblynative.cpp
diff options
context:
space:
mode:
authorJiyoung Yun <jy910.yun@samsung.com>2016-11-23 19:09:09 +0900
committerJiyoung Yun <jy910.yun@samsung.com>2016-11-23 19:09:09 +0900
commit4b4aad7217d3292650e77eec2cf4c198ea9c3b4b (patch)
tree98110734c91668dfdbb126fcc0e15ddbd93738ca /src/vm/assemblynative.cpp
parentfa45f57ed55137c75ac870356a1b8f76c84b229c (diff)
downloadcoreclr-4b4aad7217d3292650e77eec2cf4c198ea9c3b4b.tar.gz
coreclr-4b4aad7217d3292650e77eec2cf4c198ea9c3b4b.tar.bz2
coreclr-4b4aad7217d3292650e77eec2cf4c198ea9c3b4b.zip
Imported Upstream version 1.1.0upstream/1.1.0
Diffstat (limited to 'src/vm/assemblynative.cpp')
-rw-r--r--src/vm/assemblynative.cpp2635
1 files changed, 2635 insertions, 0 deletions
diff --git a/src/vm/assemblynative.cpp b/src/vm/assemblynative.cpp
new file mode 100644
index 0000000000..90c58fc59c
--- /dev/null
+++ b/src/vm/assemblynative.cpp
@@ -0,0 +1,2635 @@
+// 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.
+
+/*============================================================
+**
+** Header: AssemblyNative.cpp
+**
+** Purpose: Implements AssemblyNative (loader domain) architecture
+**
+**
+
+
+**
+===========================================================*/
+
+#include "common.h"
+
+#include <shlwapi.h>
+#include <stdlib.h>
+#ifdef FEATURE_FUSION
+#include "actasm.h"
+#include "appctx.h"
+#include "asm.h"
+#endif
+#include "assemblynative.hpp"
+#include "dllimport.h"
+#include "field.h"
+#include "assemblyname.hpp"
+#include "eeconfig.h"
+#include "security.h"
+#include "strongname.h"
+#include "interoputil.h"
+#include "frames.h"
+#include "typeparse.h"
+#ifdef FEATURE_REMOTING
+#include "appdomainhelper.h"
+#endif
+#include "stackprobe.h"
+#ifdef FEATURE_FUSION
+#include "dbglog.h"
+#include "bindinglog.hpp"
+#include "policy.h"
+#endif
+
+#ifdef FEATURE_CORECLR
+#include "appdomainnative.hpp"
+#include "../binder/inc/clrprivbindercoreclr.h"
+#endif // FEATURE_CORECLR
+
+#ifndef FEATURE_CORECLR
+#include "assemblynativeresource.h"
+#endif // !FEATURE_CORECLR
+
+#if !defined(FEATURE_CORECLR)
+#include "clrprivbinderloadfile.h"
+#endif
+
+
+#ifdef FEATURE_FUSION
+//----------------------------------------------------------------------------------------------------
+// Allows managed code in mscorlib to find out whether an assembly name corresponds to mscorlib,
+// a .NET Framework assembly found in the unification list (see fxretarget.h), or a portable assembly (see portabilityPolicy.cpp)
+// See Fusion::Util::IsAnyFrameworkAssembly for more details.
+// The NGEN task uses this function (via System.Reflection.RuntimeAssembly.IsFrameworkAssembly)
+FCIMPL1(FC_BOOL_RET, AssemblyNative::IsFrameworkAssembly, AssemblyNameBaseObject* refAssemblyNameUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ struct _gc
+ {
+ ASSEMBLYNAMEREF assemblyName;
+ } gc;
+ gc.assemblyName = (ASSEMBLYNAMEREF) refAssemblyNameUNSAFE;
+
+ BOOL bIsFxAssembly = FALSE;
+
+ HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
+ AssemblySpec spec;
+
+ Thread *pThread = GetThread();
+ CheckPointHolder cph(pThread->m_MarshalAlloc.GetCheckpoint()); //hold checkpoint for autorelease
+
+ spec.InitializeSpec(&(pThread->m_MarshalAlloc),
+ &gc.assemblyName,
+ FALSE, /*fIsStringized*/
+ FALSE /*fForIntrospection*/
+ );
+ ReleaseHolder<IAssemblyName> pIAssemblyName;
+ IfFailThrow(spec.CreateFusionName(&pIAssemblyName,FALSE));
+
+ bIsFxAssembly = (IfFailThrow(Fusion::Util::IsAnyFrameworkAssembly(pIAssemblyName)) == S_OK);
+ HELPER_METHOD_FRAME_END();
+
+ FC_RETURN_BOOL(bIsFxAssembly);
+}
+FCIMPLEND
+#endif // FEATURE_FUSION
+
+#ifdef FEATURE_FUSION
+//----------------------------------------------------------------------------------------------------
+FCIMPL1(FC_BOOL_RET, AssemblyNative::IsNewPortableAssembly, AssemblyNameBaseObject* refAssemblyNameUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ struct _gc
+ {
+ ASSEMBLYNAMEREF assemblyName;
+ } gc;
+ gc.assemblyName = (ASSEMBLYNAMEREF) refAssemblyNameUNSAFE;
+
+ BOOL fIsPortable = FALSE;
+
+ HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
+
+ AssemblySpec spec;
+
+ Thread *pThread = GetThread();
+ CheckPointHolder cph(pThread->m_MarshalAlloc.GetCheckpoint()); //hold checkpoint for autorelease
+
+ {
+ GCX_COOP();
+ spec.InitializeSpec(&(pThread->m_MarshalAlloc),
+ &gc.assemblyName,
+ FALSE, /*fIsStringized*/
+ FALSE /*fForIntrospection*/);
+ }
+
+ ReleaseHolder<IAssemblyName> pIAssemblyName;
+ IfFailThrow(spec.CreateFusionName(&pIAssemblyName,FALSE));
+
+ fIsPortable = (IfFailThrow(Fusion::Util::IsNewPortableAssembly(pIAssemblyName)) == S_OK);
+ HELPER_METHOD_FRAME_END();
+
+ FC_RETURN_BOOL(fIsPortable);
+}
+FCIMPLEND
+#endif // FEATURE_FUSION
+
+FCIMPL10(Object*, AssemblyNative::Load, AssemblyNameBaseObject* assemblyNameUNSAFE,
+ StringObject* codeBaseUNSAFE,
+ Object* securityUNSAFE,
+ AssemblyBaseObject* requestingAssemblyUNSAFE,
+ StackCrawlMark* stackMark,
+ ICLRPrivBinder * pPrivHostBinder,
+ CLR_BOOL fThrowOnFileNotFound,
+ CLR_BOOL fForIntrospection,
+ CLR_BOOL fSuppressSecurityChecks,
+ INT_PTR ptrLoadContextBinder)
+{
+ FCALL_CONTRACT;
+
+ struct _gc
+ {
+ ASSEMBLYNAMEREF assemblyName;
+ STRINGREF codeBase;
+ ASSEMBLYREF requestingAssembly;
+ OBJECTREF security;
+ ASSEMBLYREF rv;
+ } gc;
+
+ gc.assemblyName = (ASSEMBLYNAMEREF) assemblyNameUNSAFE;
+ gc.codeBase = (STRINGREF) codeBaseUNSAFE;
+ gc.requestingAssembly = (ASSEMBLYREF) requestingAssemblyUNSAFE;
+ gc.security = (OBJECTREF) securityUNSAFE;
+ gc.rv = NULL;
+
+ HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
+
+ if (gc.assemblyName == NULL)
+ COMPlusThrow(kArgumentNullException, W("ArgumentNull_AssemblyName"));
+
+ if (fForIntrospection)
+ {
+ if (!GetThread()->GetDomain()->IsVerificationDomain())
+ GetThread()->GetDomain()->SetIllegalVerificationDomain();
+ }
+
+ Thread * pThread = GetThread();
+ CheckPointHolder cph(pThread->m_MarshalAlloc.GetCheckpoint()); //hold checkpoint for autorelease
+
+ DomainAssembly * pParentAssembly = NULL;
+ Assembly * pRefAssembly = NULL;
+
+ if(gc.assemblyName->GetSimpleName() == NULL)
+ {
+ if (gc.codeBase == NULL)
+ COMPlusThrow(kArgumentException, W("Format_StringZeroLength"));
+ if ((!fForIntrospection) && CorHost2::IsLoadFromBlocked())
+ COMPlusThrow(kFileLoadException, FUSION_E_LOADFROM_BLOCKED);
+ }
+ else if (!fForIntrospection)
+ {
+ // name specified, if immersive ignore the codebase
+ if (GetThread()->GetDomain()->HasLoadContextHostBinder())
+ gc.codeBase = NULL;
+
+ // Compute parent assembly
+ if (gc.requestingAssembly == NULL)
+ {
+ pRefAssembly = SystemDomain::GetCallersAssembly(stackMark);
+
+ // Cross-appdomain callers aren't allowed as the parent
+ if (pRefAssembly &&
+ (pRefAssembly->GetDomain() != pThread->GetDomain()))
+ {
+ pRefAssembly = NULL;
+ }
+ }
+ else
+ pRefAssembly = gc.requestingAssembly->GetAssembly();
+
+ // Shared or collectible assemblies should not be used for the parent in the
+ // late-bound case.
+ if (pRefAssembly && (!pRefAssembly->IsDomainNeutral()) && (!pRefAssembly->IsCollectible()))
+ {
+ pParentAssembly= pRefAssembly->GetDomainAssembly();
+ }
+
+ }
+
+ // Initialize spec
+ AssemblySpec spec;
+ spec.InitializeSpec(&(pThread->m_MarshalAlloc),
+ &gc.assemblyName,
+ FALSE,
+ fForIntrospection);
+
+ if (!spec.HasUniqueIdentity())
+ { // Insuficient assembly name for binding (e.g. ContentType=WindowsRuntime cannot bind by assembly name)
+ EEFileLoadException::Throw(&spec, COR_E_NOTSUPPORTED);
+ }
+
+ if (pPrivHostBinder != NULL)
+ {
+ pParentAssembly = NULL;
+ spec.SetHostBinder(pPrivHostBinder);
+ }
+
+ if (gc.codeBase != NULL)
+ spec.SetCodeBase(&(pThread->m_MarshalAlloc), &gc.codeBase);
+
+ if (pParentAssembly != NULL)
+ spec.SetParentAssembly(pParentAssembly);
+
+#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
+ // Have we been passed the reference to the binder against which this load should be triggered?
+ // If so, then use it to set the fallback load context binder.
+ if (ptrLoadContextBinder != NULL)
+ {
+ spec.SetFallbackLoadContextBinderForRequestingAssembly(reinterpret_cast<ICLRPrivBinder *>(ptrLoadContextBinder));
+ spec.SetPreferFallbackLoadContextBinder();
+ }
+ else if (pRefAssembly != NULL)
+ {
+ // If the requesting assembly has Fallback LoadContext binder available,
+ // then set it up in the AssemblySpec.
+ PEFile *pRefAssemblyManifestFile = pRefAssembly->GetManifestFile();
+ spec.SetFallbackLoadContextBinderForRequestingAssembly(pRefAssemblyManifestFile->GetFallbackLoadContextBinder());
+ }
+#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
+
+ AssemblyLoadSecurity loadSecurity;
+ loadSecurity.m_pAdditionalEvidence = &gc.security;
+ loadSecurity.m_fCheckLoadFromRemoteSource = !!(gc.codeBase != NULL);
+ loadSecurity.m_fSuppressSecurityChecks = !!fSuppressSecurityChecks;
+
+ // If we're in an APPX domain, then all loads from the application will find themselves within the APPX package
+ // graph or from a trusted location. However, assemblies within the package may have been marked by Windows as
+ // not being from the MyComputer zone, which can trip the LoadFromRemoteSources check. Since we do not need to
+ // defend against accidental loads from HTTP for APPX applications, we simply suppress the remote load check.
+ if (AppX::IsAppXProcess())
+ {
+ loadSecurity.m_fCheckLoadFromRemoteSource = false;
+ }
+
+ Assembly *pAssembly;
+
+ {
+ GCX_PREEMP();
+ pAssembly = spec.LoadAssembly(FILE_LOADED, &loadSecurity, fThrowOnFileNotFound, FALSE /*fRaisePrebindEvents*/, stackMark);
+ }
+
+ if (pAssembly != NULL)
+ gc.rv = (ASSEMBLYREF) pAssembly->GetExposedObject();
+
+ HELPER_METHOD_FRAME_END();
+
+ return OBJECTREFToObject(gc.rv);
+}
+FCIMPLEND
+
+Assembly* AssemblyNative::LoadFromBuffer(BOOL fForIntrospection, const BYTE* pAssemblyData, UINT64 uAssemblyLength, const BYTE* pPDBData, UINT64 uPDBLength, StackCrawlMark* stackMark, Object * securityUNSAFE, SecurityContextSource securityContextSource)
+{
+ CONTRACTL
+ {
+ GC_TRIGGERS;
+ THROWS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ Assembly *pAssembly;
+
+ struct _gc {
+ OBJECTREF orefSecurity;
+ OBJECTREF granted;
+ OBJECTREF denied;
+ } gc;
+
+ ZeroMemory(&gc, sizeof(gc));
+
+ GCPROTECT_BEGIN(gc);
+
+ gc.orefSecurity = (OBJECTREF) securityUNSAFE;
+
+ if((!fForIntrospection) && CorHost2::IsLoadFromBlocked())
+ COMPlusThrow(kFileLoadException, FUSION_E_LOADFROM_BLOCKED);
+
+ if (pAssemblyData == NULL)
+ COMPlusThrow(kArgumentNullException, W("ArgumentNull_Array"));
+
+#ifndef FEATURE_CORECLR
+ // Event Tracing for Windows is used to log data for performance and functional testing purposes.
+ // The events in this function are used to help measure the performance of assembly loading as a whole when loading from a buffer.
+ FireEtwLoaderPhaseStart(GetAppDomain() ? GetAppDomain()->GetId().m_dwId : ETWAppDomainIdNotAvailable, ETWLoadContextNotAvailable, ETWFieldUnused, ETWLoaderDynamicLoad, NULL, NULL, GetClrInstanceId());
+#endif // FEATURE_CORECLR
+
+ if (fForIntrospection) {
+ if (!GetThread()->GetDomain()->IsVerificationDomain())
+ GetThread()->GetDomain()->SetIllegalVerificationDomain();
+ }
+
+ // Get caller's assembly so we can extract their codebase and propagate it
+ // into the new assembly (which obviously doesn't have one of its own).
+
+ AppDomain *pCallersDomain = NULL;
+ MethodDesc* pCallerMD = SystemDomain::GetCallersMethod (stackMark, &pCallersDomain);
+ Assembly *pCallersAssembly = (pCallerMD ? pCallerMD->GetAssembly() : NULL);
+ BOOL fPropagateIdentity = ((!fForIntrospection) && (gc.orefSecurity == NULL));
+
+ // Callers assembly can be null if caller is interop
+ // @todo: we really don't want to call this assembly "mscorlib" to anyone who asks
+ // for its code base. But the required effect here is that it recieves full trust
+ // as far as its codebase goes so this should be OK. We really need to allow a
+ // "no code base" condition to avoid confusion
+ if (pCallersAssembly == NULL) {
+ pCallersAssembly = SystemDomain::System()->SystemAssembly();
+ } else {
+#ifdef FEATURE_CAS_POLICY
+ // If no evidence was provided to the Assembly.Load(byte[]) call,
+ // we want to inherit the evidence from the security context source
+ if (fPropagateIdentity) {
+ ISecurityDescriptor *pSecDesc = NULL;
+ if (securityContextSource == kCurrentAppDomain) {
+ pSecDesc = pCallersDomain->GetSecurityDescriptor();
+ }
+ else {
+ _ASSERTE(securityContextSource == kCurrentAssembly);
+ pSecDesc = pCallersAssembly->GetSecurityDescriptor(pCallersDomain);
+ }
+
+ ENTER_DOMAIN_PTR(pSecDesc->GetDomain(),ADV_RUNNINGIN)
+ {
+ gc.orefSecurity = pSecDesc->GetEvidence();
+ }
+ END_DOMAIN_TRANSITION;
+
+ // Caller may be in another appdomain context, in which case we'll
+ // need to marshal/unmarshal the evidence across.
+#ifdef FEATURE_REMOTING // should not happenwithout remoting
+ if (pCallersDomain != GetAppDomain())
+ gc.orefSecurity = AppDomainHelper::CrossContextCopyFrom(pCallersDomain->GetId(), &gc.orefSecurity);
+#else
+ _ASSERTE(pCallersDomain == GetAppDomain());
+#endif
+ }
+#endif // FEATURE_CAS_POLICY
+ }
+
+ if ((COUNT_T)uAssemblyLength !=uAssemblyLength) // overflow
+ ThrowOutOfMemory();
+
+ PEAssemblyHolder pFile;
+
+ {
+ GCX_PREEMP();
+
+ CLRPrivBinderLoadFile* pBinderToUse = NULL;
+
+#if !defined(FEATURE_CORECLR)
+ if (GetAppDomain()->HasLoadContextHostBinder())
+ {
+ pBinderToUse = CLRPrivBinderLoadFile::GetOrCreateBinder();
+ }
+#endif // !FEATURE_CORECLR
+
+ pFile = PEAssembly::OpenMemory(pCallersAssembly->GetManifestFile(),
+ pAssemblyData, (COUNT_T)uAssemblyLength,
+ fForIntrospection,
+ pBinderToUse);
+ }
+
+ fPropagateIdentity = (fPropagateIdentity && pCallersDomain && pCallersAssembly);
+
+ AssemblyLoadSecurity loadSecurity;
+ loadSecurity.m_pEvidence = &gc.orefSecurity;
+ if (fPropagateIdentity)
+ {
+ DWORD dwSpecialFlags = 0;
+
+#ifdef FEATURE_CAS_POLICY
+ if (securityContextSource == kCurrentAssembly)
+ {
+ IAssemblySecurityDescriptor *pCallersSecDesc = pCallersAssembly->GetSecurityDescriptor(pCallersDomain);
+ gc.granted = pCallersSecDesc->GetGrantedPermissionSet( &(gc.denied));
+ dwSpecialFlags = pCallersSecDesc->GetSpecialFlags();
+
+ // If we're going to inherit the grant set of an anonymously hosted dynamic method, it will be
+ // full trust/transparent. In that case, we should demand full trust.
+ if(pCallersAssembly != NULL && pCallersDomain != NULL && pCallersAssembly->GetDomainAssembly(pCallersDomain) == pCallersDomain->GetAnonymouslyHostedDynamicMethodsAssembly())
+ {
+ loadSecurity.m_fPropagatingAnonymouslyHostedDynamicMethodGrant = true;
+ }
+ }
+ else
+#endif // FEATURE_CAS_POLICY
+ {
+ IApplicationSecurityDescriptor *pDomainSecDesc = pCallersDomain->GetSecurityDescriptor();
+
+#ifdef FEATURE_CAS_POLICY
+ // We only want to propigate the identity of homogenous domains, since heterogenous domains tend
+ // to be fully trusted even if they are housing partially trusted code - which could lead to an
+ // elevation of privilege if we allow the grant set to be pushed to assemblies partially trusted
+ // code is loading.
+ if (!pDomainSecDesc->IsHomogeneous())
+ {
+ COMPlusThrow(kNotSupportedException, W("NotSupported_SecurityContextSourceAppDomainInHeterogenous"));
+ }
+#endif // FEATURE_CAS_POLICY
+
+
+ gc.granted = pDomainSecDesc->GetGrantedPermissionSet();
+ dwSpecialFlags = pDomainSecDesc->GetSpecialFlags();
+ }
+
+#ifdef FEATURE_REMOTING
+ // Caller may be in another appdomain context, in which case we'll need to marshal/unmarshal the grant
+ // and deny sets across.
+ if (pCallersDomain != GetAppDomain())
+ {
+ gc.granted = AppDomainHelper::CrossContextCopyFrom(pCallersDomain->GetId(), &(gc.granted));
+ if (gc.denied != NULL)
+ {
+ gc.denied = AppDomainHelper::CrossContextCopyFrom(pCallersDomain->GetId(), &(gc.denied));
+ }
+ }
+#endif // FEATURE_REMOTING
+
+ // Instead of resolving policy, the loader should use an inherited grant set
+ loadSecurity.m_pGrantSet = &gc.granted;
+ loadSecurity.m_pRefusedSet = &gc.denied;
+ loadSecurity.m_dwSpecialFlags = dwSpecialFlags;
+
+ // if the caller is from another appdomain we wil not be able to get the ssembly's security descriptor
+ // but that is ok, since getting a pointer to our AppDomain required full trust
+ if (!pCallersDomain->GetSecurityDescriptor()->IsFullyTrusted() ||
+ ( pCallersAssembly->FindDomainAssembly(::GetAppDomain()) != NULL && !pCallersAssembly->GetSecurityDescriptor()->IsFullyTrusted()) )
+ pFile->VerifyStrongName();
+ }
+ pAssembly = GetPostPolicyAssembly(pFile, fForIntrospection, &loadSecurity, TRUE);
+
+ // perform necessary Transparency checks for this Load(byte[]) call (based on the calling method).
+ if (pCallerMD)
+ {
+ Security::PerformTransparencyChecksForLoadByteArray(pCallerMD, pAssembly->GetSecurityDescriptor());
+ }
+
+ // In order to assign the PDB image (if present),
+ // the resulting assembly's image needs to be exactly the one
+ // we created above. We need pointer comparison instead of pe image equivalence
+ // to avoid mixed binaries/PDB pairs of other images.
+ // This applies to both Desktop CLR and CoreCLR, with or without fusion.
+ BOOL fIsSameAssembly = (pAssembly->GetManifestFile()->GetILimage() == pFile->GetILimage());
+
+#ifdef FEATURE_REFLECTION_ONLY_LOAD
+ if (fForIntrospection)
+ {
+ IAssemblyName * pIAssemblyName = pAssembly->GetFusionAssemblyName();
+
+ AppDomain::AssemblyIterator i = GetAppDomain()->IterateAssembliesEx(
+ (AssemblyIterationFlags)(kIncludeLoaded | kIncludeIntrospection));
+ CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
+
+ while (i.Next(pDomainAssembly.This()))
+ {
+ Assembly * pCachedAssembly = pDomainAssembly->GetAssembly();
+ IAssemblyName * pCachedAssemblyName = pCachedAssembly->GetFusionAssemblyName();
+ if ((pAssembly != pCachedAssembly) && (S_OK == pCachedAssemblyName->IsEqual(pIAssemblyName, ASM_CMPF_IL_ALL)))
+ {
+ COMPlusThrow(kFileLoadException, IDS_EE_REFLECTIONONLY_LOADFROM, W("")); //@todo: need to fill in assemblyname
+ }
+ }
+ }
+#endif // FEATURE_REFLECTION_ONLY_LOAD
+
+#ifndef FEATURE_CORECLR
+ FireEtwLoaderPhaseEnd(GetAppDomain() ? GetAppDomain()->GetId().m_dwId : ETWAppDomainIdNotAvailable, ETWLoadContextNotAvailable, ETWFieldUnused, ETWLoaderDynamicLoad, NULL, NULL, GetClrInstanceId());
+#endif // FEATURE_CORECLR
+ LOG((LF_CLASSLOADER,
+ LL_INFO100,
+ "\tLoaded in-memory module\n"));
+
+ // Setting the PDB info is only applicable for our original assembly.
+ // This applies to both Desktop CLR and CoreCLR, with or without fusion.
+ if (fIsSameAssembly)
+ {
+#ifdef DEBUGGING_SUPPORTED
+ // If we were given symbols, save a copy of them.
+ // the debugger, load them now).
+ if (pPDBData != NULL)
+ {
+ GCX_PREEMP();
+ if ((DWORD)uPDBLength != uPDBLength) // overflow
+ ThrowOutOfMemory();
+ pAssembly->GetManifestModule()->SetSymbolBytes(pPDBData, (DWORD)uPDBLength);
+ }
+#endif // DEBUGGING_SUPPORTED
+ }
+
+ GCPROTECT_END();
+
+ return pAssembly;
+}
+
+FCIMPL6(Object*, AssemblyNative::LoadImage, U1Array* PEByteArrayUNSAFE,
+ U1Array* SymByteArrayUNSAFE, Object* securityUNSAFE,
+ StackCrawlMark* stackMark, CLR_BOOL fForIntrospection, SecurityContextSource securityContextSource)
+{
+ FCALL_CONTRACT;
+
+ struct _gc
+ {
+ U1ARRAYREF PEByteArray;
+ U1ARRAYREF SymByteArray;
+ OBJECTREF security;
+ OBJECTREF Throwable;
+ OBJECTREF refRetVal;
+ } gc;
+
+ gc.PEByteArray = (U1ARRAYREF) PEByteArrayUNSAFE;
+ gc.SymByteArray = (U1ARRAYREF) SymByteArrayUNSAFE;
+ gc.security = (OBJECTREF) securityUNSAFE;
+ gc.Throwable = NULL;
+ gc.refRetVal = NULL;
+
+ HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
+
+
+ if (gc.PEByteArray == NULL)
+ COMPlusThrow(kArgumentNullException, W("ArgumentNull_Array"));
+
+ NewArrayHolder<BYTE> pbSyms;
+ DWORD cbSyms = 0;
+
+#ifdef DEBUGGING_SUPPORTED
+ // If we were given symbols, save a copy of them.
+ // the debugger, load them now).
+ if (gc.SymByteArray != NULL)
+ {
+ Security::CopyByteArrayToEncoding(&gc.SymByteArray,
+ &pbSyms, &cbSyms);
+
+ }
+#endif // DEBUGGING_SUPPORTED
+
+ Assembly* pAssembly = NULL;
+ // Pin byte array for loading
+ {
+ Wrapper<OBJECTHANDLE, DoNothing, DestroyPinningHandle> handle(
+ GetAppDomain()->CreatePinningHandle(gc.PEByteArray));
+
+ const BYTE *pbImage = gc.PEByteArray->GetDirectConstPointerToNonObjectElements();
+ DWORD cbImage = gc.PEByteArray->GetNumComponents();
+ pAssembly = LoadFromBuffer(fForIntrospection, pbImage, cbImage, pbSyms, cbSyms, stackMark, OBJECTREFToObject(gc.security), securityContextSource);
+ }
+
+#ifdef FEATURE_FUSION
+ if (!fForIntrospection && IsLoggingNeeded())
+ {
+ BinderLogging::BindingLog::LogLoadByteArray(GetAppDomain()->GetFusionContext(), pAssembly);
+ }
+#endif
+
+ if (pAssembly != NULL)
+ gc.refRetVal = pAssembly->GetExposedObject();
+
+ HELPER_METHOD_FRAME_END();
+
+ return OBJECTREFToObject(gc.refRetVal);
+}
+FCIMPLEND
+
+FCIMPL2(Object*, AssemblyNative::LoadFile, StringObject* pathUNSAFE, Object* securityUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ struct _gc {
+ OBJECTREF refRetVal;
+ OBJECTREF refSecurity;
+ STRINGREF strPath;
+ } gc;
+
+ gc.refRetVal = NULL;
+ gc.refSecurity = ObjectToOBJECTREF(securityUNSAFE);
+ gc.strPath = ObjectToSTRINGREF(pathUNSAFE);
+
+ HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
+
+ if(CorHost2::IsLoadFromBlocked())
+ COMPlusThrow(kFileLoadException, FUSION_E_LOADFROM_BLOCKED);
+
+ if (pathUNSAFE == NULL)
+ COMPlusThrow(kArgumentNullException, W("ArgumentNull_Path"));
+
+ StackSString path;
+ gc.strPath->GetSString(path);
+
+#ifdef FEATURE_FUSION // use BindResult for abstraction
+ // Event Tracing for Windows is used to log data for performance and functional testing purposes.
+ // The events in this function are used to help measure the performance of assembly loading as a whole when loading directly from a file,
+ // of binding to an assembly, as well as of lookup scenarios such as from a host store.
+ FireEtwLoaderPhaseStart(ETWAppDomainIdNotAvailable, ETWLoadContextNotAvailable, ETWFieldUnused, ETWLoaderDynamicLoad, path, NULL, GetClrInstanceId());
+ SafeComHolder<IAssembly> pFusionAssembly;
+ SafeComHolder<IBindResult> pNativeFusionAssembly;
+ SafeComHolder<IFusionBindLog> pFusionLog;
+
+ PEAssemblyHolder pFile;
+ FireEtwBindingPhaseStart(GetAppDomain() ? GetAppDomain()->GetId().m_dwId : ETWAppDomainIdNotAvailable, ETWLoadContextNotAvailable, ETWFieldUnused, ETWLoaderLoadTypeNotAvailable, path, NULL, GetClrInstanceId());
+
+ if(GetAppDomain()->HasLoadContextHostBinder())
+ {
+ GCX_PREEMP();
+ CLRPrivBinderLoadFile* pLFBinder = CLRPrivBinderLoadFile::GetOrCreateBinder();
+ ReleaseHolder<PEImage> pImage(PEImage::OpenImage(path));
+ ReleaseHolder<ICLRPrivAssembly> pAsm;
+ ReleaseHolder<IAssemblyName> pAssemblyName;
+ IfFailThrow(pLFBinder->BindAssemblyExplicit(pImage, &pAssemblyName, &pAsm));
+ IfFailThrow(GetAppDomain()->BindHostedPrivAssembly(nullptr, pAsm, pAssemblyName, &pFile));
+ _ASSERTE(pFile);
+ }
+ else
+ {
+ GCX_PREEMP();
+ IfFailThrow(ExplicitBind(path, GetAppDomain()->GetFusionContext(),
+ EXPLICITBIND_FLAGS_NON_BINDABLE,
+ NULL, &pFusionAssembly, &pNativeFusionAssembly, &pFusionLog));
+ pFile.Assign(PEAssembly::Open(pFusionAssembly, pNativeFusionAssembly, pFusionLog, FALSE, FALSE));
+ }
+
+ FireEtwBindingLookupAndProbingPhaseEnd(GetAppDomain() ? GetAppDomain()->GetId().m_dwId : ETWAppDomainIdNotAvailable, ETWLoadContextNotAvailable, ETWFieldUnused, ETWLoaderLoadTypeNotAvailable, path, NULL, GetClrInstanceId());
+
+ FireEtwBindingPhaseEnd(GetAppDomain() ? GetAppDomain()->GetId().m_dwId : ETWAppDomainIdNotAvailable, ETWLoadContextNotAvailable, ETWFieldUnused, ETWLoaderLoadTypeNotAvailable, path, NULL, GetClrInstanceId());
+
+ AssemblyLoadSecurity loadSecurity;
+ loadSecurity.m_pAdditionalEvidence = &gc.refSecurity;
+ loadSecurity.m_fCheckLoadFromRemoteSource = true;
+
+ // If we're in an APPX domain, then all loads from the application will find themselves within the APPX package
+ // graph or from a trusted location. However, assemblies within the package may have been marked by Windows as
+ // not being from the MyComputer zone, which can trip the LoadFromRemoteSources check. Since we do not need to
+ // defend against accidental loads from HTTP for APPX applications, we simply suppress the remote load check.
+ if (AppX::IsAppXProcess())
+ {
+ loadSecurity.m_fCheckLoadFromRemoteSource = false;
+ }
+
+ Assembly *pAssembly = GetPostPolicyAssembly(pFile, FALSE, &loadSecurity);
+
+ FireEtwLoaderPhaseEnd(ETWAppDomainIdNotAvailable, ETWLoadContextNotAvailable, ETWFieldUnused, ETWLoaderDynamicLoad, path, NULL, GetClrInstanceId());
+
+ if (IsLoggingNeeded())
+ {
+ BinderLogging::BindingLog::LogLoadFile(GetAppDomain()->GetFusionContext(), path, pAssembly);
+ }
+
+#else // FEATURE_FUSION
+ Assembly *pAssembly = AssemblySpec::LoadAssembly(path);
+#endif // FEATURE_FUSION
+
+ LOG((LF_CLASSLOADER,
+ LL_INFO100,
+ "\tLoaded assembly from a file\n"));
+
+
+ if (pAssembly != NULL)
+ gc.refRetVal = (ASSEMBLYREF) pAssembly->GetExposedObject();
+
+ HELPER_METHOD_FRAME_END();
+
+ return OBJECTREFToObject(gc.refRetVal);
+}
+FCIMPLEND
+
+#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
+
+/* static */
+Assembly* AssemblyNative::LoadFromPEImage(ICLRPrivBinder* pBinderContext, PEImage *pILImage, PEImage *pNIImage)
+{
+ CONTRACT(Assembly*)
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(CheckPointer(pBinderContext));
+ POSTCONDITION(CheckPointer(RETVAL));
+ }
+ CONTRACT_END;
+
+ Assembly *pLoadedAssembly = NULL;
+
+ ReleaseHolder<ICLRPrivAssembly> pAssembly;
+
+ // Get the correct PEImage to work with.
+ BOOL fIsNativeImage = TRUE;
+ PEImage *pImage = pNIImage;
+ if (pNIImage == NULL)
+ {
+ // Since we do not have a NI image, we are working with IL assembly
+ pImage = pILImage;
+ fIsNativeImage = FALSE;
+ }
+ _ASSERTE(pImage != NULL);
+
+ BOOL fHadLoadFailure = FALSE;
+
+ // Force the image to be loaded and mapped so that subsequent loads do not
+ // map a duplicate copy.
+ if (pImage->IsFile())
+ {
+ pImage->Load();
+ }
+ else
+ {
+ pImage->LoadNoFile();
+ }
+
+ DWORD dwMessageID = IDS_EE_FILELOAD_ERROR_GENERIC;
+
+ // Set the caller's assembly to be mscorlib
+ DomainAssembly *pCallersAssembly = SystemDomain::System()->SystemAssembly()->GetDomainAssembly();
+ PEAssembly *pParentAssembly = pCallersAssembly->GetFile();
+
+ // Initialize the AssemblySpec
+ AssemblySpec spec;
+ spec.InitializeSpec(TokenFromRid(1, mdtAssembly), pImage->GetMDImport(), pCallersAssembly);
+ spec.SetBindingContext(pBinderContext);
+
+ HRESULT hr = S_OK;
+ PTR_AppDomain pCurDomain = GetAppDomain();
+ CLRPrivBinderCoreCLR *pTPABinder = pCurDomain->GetTPABinderContext();
+ if (!AreSameBinderInstance(pTPABinder, pBinderContext))
+ {
+ // We are working with custom Assembly Load Context so bind the assembly using it.
+ CLRPrivBinderAssemblyLoadContext *pBinder = reinterpret_cast<CLRPrivBinderAssemblyLoadContext *>(pBinderContext);
+ hr = pBinder->BindUsingPEImage(pImage, fIsNativeImage, &pAssembly);
+ }
+ else
+ {
+ // Bind the assembly using TPA binder
+ hr = pTPABinder->BindUsingPEImage(pImage, fIsNativeImage, &pAssembly);
+ }
+
+ if (hr != S_OK)
+ {
+ // Give a more specific message for the case when we found the assembly with the same name already loaded.
+ if (hr == COR_E_FILELOAD)
+ {
+ dwMessageID = IDS_HOST_ASSEMBLY_RESOLVER_ASSEMBLY_ALREADY_LOADED_IN_CONTEXT;
+ }
+
+ StackSString name;
+ spec.GetFileOrDisplayName(0, name);
+ COMPlusThrowHR(COR_E_FILELOAD, dwMessageID, name);
+ }
+
+ PEAssemblyHolder pPEAssembly(PEAssembly::Open(pParentAssembly, pILImage, pNIImage, pAssembly, FALSE));
+
+ GCX_COOP();
+
+ IApplicationSecurityDescriptor *pDomainSecDesc = pCurDomain->GetSecurityDescriptor();
+
+ OBJECTREF refGrantedPermissionSet = NULL;
+ AssemblyLoadSecurity loadSecurity;
+ DomainAssembly *pDomainAssembly = NULL;
+
+ // Setup the AssemblyLoadSecurity to perform the assembly load
+ GCPROTECT_BEGIN(refGrantedPermissionSet);
+
+ loadSecurity.m_dwSpecialFlags = pDomainSecDesc->GetSpecialFlags();
+ refGrantedPermissionSet = pDomainSecDesc->GetGrantedPermissionSet();
+ loadSecurity.m_pGrantSet = &refGrantedPermissionSet;
+
+ pDomainAssembly = pCurDomain->LoadDomainAssembly(&spec, pPEAssembly, FILE_LOADED, &loadSecurity);
+ pLoadedAssembly = pDomainAssembly->GetAssembly();
+
+ GCPROTECT_END();
+
+ RETURN pLoadedAssembly;
+}
+
+
+/* static */
+void QCALLTYPE AssemblyNative::LoadFromPath(INT_PTR ptrNativeAssemblyLoadContext, LPCWSTR pwzILPath, LPCWSTR pwzNIPath, QCall::ObjectHandleOnStack retLoadedAssembly)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ PTR_AppDomain pCurDomain = GetAppDomain();
+
+ // Get the binder context in which the assembly will be loaded.
+ ICLRPrivBinder *pBinderContext = reinterpret_cast<ICLRPrivBinder*>(ptrNativeAssemblyLoadContext);
+ _ASSERTE(pBinderContext != NULL);
+
+ // Form the PEImage for the ILAssembly. Incase of an exception, the holders will ensure
+ // the release of the image.
+ PEImageHolder pILImage, pNIImage;
+
+ if (pwzILPath != NULL)
+ {
+ pILImage = PEImage::OpenImage(pwzILPath);
+
+ // Need to verify that this is a valid CLR assembly.
+ if (!pILImage->CheckILFormat())
+ ThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_IL);
+ }
+
+ // Form the PEImage for the NI assembly, if specified
+ if (pwzNIPath != NULL)
+ {
+ pNIImage = PEImage::OpenImage(pwzNIPath, MDInternalImport_TrustedNativeImage);
+
+ if (pNIImage->HasReadyToRunHeader())
+ {
+ // ReadyToRun images are treated as IL images by the rest of the system
+ if (!pNIImage->CheckILFormat())
+ ThrowHR(COR_E_BADIMAGEFORMAT);
+
+ pILImage = pNIImage.Extract();
+ pNIImage = NULL;
+ }
+ else
+ {
+ if (!pNIImage->CheckNativeFormat())
+ ThrowHR(COR_E_BADIMAGEFORMAT);
+ }
+ }
+
+ Assembly *pLoadedAssembly = AssemblyNative::LoadFromPEImage(pBinderContext, pILImage, pNIImage);
+
+ {
+ GCX_COOP();
+ retLoadedAssembly.Set(pLoadedAssembly->GetExposedObject());
+ }
+
+ LOG((LF_CLASSLOADER,
+ LL_INFO100,
+ "\tLoaded assembly from a file\n"));
+
+ END_QCALL;
+}
+
+// static
+INT_PTR QCALLTYPE AssemblyNative::InternalLoadUnmanagedDllFromPath(LPCWSTR unmanagedLibraryPath)
+{
+ QCALL_CONTRACT;
+
+ HMODULE moduleHandle = nullptr;
+
+ BEGIN_QCALL;
+
+ moduleHandle = NDirect::LoadLibraryFromPath(unmanagedLibraryPath);
+
+ END_QCALL;
+
+ return reinterpret_cast<INT_PTR>(moduleHandle);
+}
+
+/*static */
+void QCALLTYPE AssemblyNative::LoadFromStream(INT_PTR ptrNativeAssemblyLoadContext, INT_PTR ptrAssemblyArray,
+ INT32 cbAssemblyArrayLength, INT_PTR ptrSymbolArray, INT32 cbSymbolArrayLength,
+ QCall::ObjectHandleOnStack retLoadedAssembly)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ // Ensure that the invariants are in place
+ _ASSERTE(ptrNativeAssemblyLoadContext != NULL);
+ _ASSERTE((ptrAssemblyArray != NULL) && (cbAssemblyArrayLength > 0));
+ _ASSERTE((ptrSymbolArray == NULL) || (cbSymbolArrayLength > 0));
+
+ // We must have a flat image stashed away since we need a private
+ // copy of the data which we can verify before doing the mapping.
+ PVOID pAssemblyArray = reinterpret_cast<PVOID>(ptrAssemblyArray);
+
+ PEImageHolder pILImage(PEImage::LoadFlat(pAssemblyArray, (COUNT_T)cbAssemblyArrayLength));
+
+ // Need to verify that this is a valid CLR assembly.
+ if (!pILImage->CheckILFormat())
+ ThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_IL);
+
+ // Get the binder context in which the assembly will be loaded
+ ICLRPrivBinder *pBinderContext = reinterpret_cast<ICLRPrivBinder*>(ptrNativeAssemblyLoadContext);
+
+ // Pass the stream based assembly as IL and NI in an attempt to bind and load it
+ Assembly* pLoadedAssembly = AssemblyNative::LoadFromPEImage(pBinderContext, pILImage, NULL);
+ {
+ GCX_COOP();
+ retLoadedAssembly.Set(pLoadedAssembly->GetExposedObject());
+ }
+
+ LOG((LF_CLASSLOADER,
+ LL_INFO100,
+ "\tLoaded assembly from a file\n"));
+
+ // In order to assign the PDB image (if present),
+ // the resulting assembly's image needs to be exactly the one
+ // we created above. We need pointer comparison instead of pe image equivalence
+ // to avoid mixed binaries/PDB pairs of other images.
+ // This applies to both Desktop CLR and CoreCLR, with or without fusion.
+ BOOL fIsSameAssembly = (pLoadedAssembly->GetManifestFile()->GetILimage() == pILImage);
+
+ // Setting the PDB info is only applicable for our original assembly.
+ // This applies to both Desktop CLR and CoreCLR, with or without fusion.
+ if (fIsSameAssembly)
+ {
+#ifdef DEBUGGING_SUPPORTED
+ // If we were given symbols, save a copy of them.
+ if (ptrSymbolArray != NULL)
+ {
+ PBYTE pSymbolArray = reinterpret_cast<PBYTE>(ptrSymbolArray);
+ pLoadedAssembly->GetManifestModule()->SetSymbolBytes(pSymbolArray, (DWORD)cbSymbolArrayLength);
+ }
+#endif // DEBUGGING_SUPPORTED
+ }
+
+ END_QCALL;
+}
+
+#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
+
+/* static */
+Assembly* AssemblyNative::GetPostPolicyAssembly(PEAssembly *pFile,
+ BOOL fForIntrospection,
+ AssemblyLoadSecurity *pLoadSecurity,
+ BOOL fIsLoadByteArray /* = FALSE */)
+{
+ CONTRACT(Assembly*)
+ {
+ MODE_ANY;
+ THROWS;
+ GC_TRIGGERS;
+ PRECONDITION(CheckPointer(pFile));
+ PRECONDITION(CheckPointer(pLoadSecurity));
+ POSTCONDITION(CheckPointer(RETVAL));
+ }
+ CONTRACT_END;
+
+ GCX_PREEMP();
+
+#ifdef FEATURE_FUSION
+ if (!fForIntrospection && !GetAppDomain()->HasLoadContextHostBinder()) {
+ DWORD dwSize = 0;
+ // if strongly named and not an exempt
+ BOOL bOptionallyRetargetable;
+
+ IfFailThrow(IsOptionallyRetargetableAssembly(pFile->GetFusionAssemblyName(), &bOptionallyRetargetable));
+ if ( !bOptionallyRetargetable && pFile->GetFusionAssemblyName()->GetProperty(ASM_NAME_PUBLIC_KEY_TOKEN, NULL, &dwSize) == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) {
+
+ SafeComHolder<IAssemblyName> pPostPolicyName(NULL);
+ HRESULT hr = PreBindAssembly(GetAppDomain()->GetFusionContext(),
+ pFile->GetFusionAssemblyName(),
+ NULL, // pAsmParent
+ &pPostPolicyName,
+ NULL); // pvReserved
+ if (FAILED(hr)) {
+ if (hr == FUSION_E_REF_DEF_MISMATCH) {
+ // Policy redirects to another version
+ AssemblySpec spec;
+ spec.InitializeSpec(pPostPolicyName, FALSE);
+ RETURN spec.LoadAssembly(FILE_LOADED, pLoadSecurity);
+ }
+ else
+ ThrowHR(hr);
+ }
+ else {
+ ReleaseHolder<IAssembly> pAsm;
+
+ SafeComHolder<IAssemblyCache> pIAsmCache (NULL);
+ IfFailThrow(CreateAssemblyCache(&pIAsmCache, 0));
+
+ DWORD dwFlags = ASM_DISPLAYF_FULL;
+
+ if (pFile->IsMarkedAsNoPlatform()) { // No Platform implies that the assembly is not tied to a specific machine architecture, which means we need to do full GAC probing.
+ hr = CreateAssemblyFromCacheLookup(GetAppDomain()->GetFusionContext(), pFile->GetFusionAssemblyName(), TRUE, &pAsm, NULL);
+ }
+ else {
+ SString sourceDisplay;
+ FusionBind::GetAssemblyNameDisplayName(pFile->GetFusionAssemblyName(), sourceDisplay, dwFlags);
+ hr = pIAsmCache->QueryAssemblyInfo(0, sourceDisplay, NULL);
+ }
+
+ if (SUCCEEDED(hr)) {
+ // It's in the GAC
+ AssemblySpec spec;
+ spec.InitializeSpec(pFile->GetFusionAssemblyName(), FALSE);
+ RETURN spec.LoadAssembly(FILE_LOADED, pLoadSecurity);
+ }
+ else if (hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
+ ThrowHR(hr);
+ }
+ }
+ }
+#else // FEATURE_FUSION
+ if (fIsLoadByteArray)
+ {
+ PEImage *pPEImage = pFile->GetILimage();
+ HRESULT hr = S_OK;
+ PTR_AppDomain pCurDomain = GetAppDomain();
+ CLRPrivBinderCoreCLR *pTPABinder = pCurDomain->GetTPABinderContext();
+
+ _ASSERTE(pCurDomain->GetFusionContext() == pTPABinder);
+ hr = pTPABinder->PreBindByteArray(pPEImage, fForIntrospection);
+ if (hr == S_OK)
+ {
+ AssemblySpec spec;
+ spec.InitializeSpec(pFile);
+
+ // Set the binder associated with the AssemblySpec
+ spec.SetBindingContext(pTPABinder);
+ RETURN spec.LoadAssembly(FILE_LOADED, pLoadSecurity);
+ }
+ else
+ {
+ _ASSERTE(hr != S_FALSE);
+ ThrowHR(hr);
+ }
+ }
+#endif // FEATURE_FUSION
+
+ RETURN GetAppDomain()->LoadAssembly(NULL, pFile, FILE_LOADED, pLoadSecurity);
+}
+
+#ifdef FEATURE_MULTIMODULE_ASSEMBLIES
+void QCALLTYPE AssemblyNative::LoadModule(QCall::AssemblyHandle pAssembly,
+ LPCWSTR wszModuleName,
+ LPCBYTE pRawModule, INT32 cbModule,
+ LPCBYTE pRawSymbolStore, INT32 cbSymbolStore,
+ QCall::ObjectHandleOnStack retModule)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ Module * pModule = NULL;
+
+ if(CorHost2::IsLoadFromBlocked())
+ COMPlusThrow(kFileLoadException, FUSION_E_LOADFROM_BLOCKED);
+
+ if (wszModuleName == NULL)
+ COMPlusThrow(kArgumentNullException, W("ArgumentNull_FileName"));
+
+ if (pRawModule == NULL)
+ COMPlusThrow(kArgumentNullException, W("ArgumentNull_Array"));
+
+ if (*wszModuleName == '\0')
+ COMPlusThrow(kArgumentException, W("Argument_EmptyFileName"));
+
+ CQuickBytes qbLC;
+
+ MAKE_UTF8PTR_FROMWIDE(pName, wszModuleName);
+ LPCSTR psModuleName = pName;
+
+ // Need to perform case insensitive lookup.
+ {
+ UTF8_TO_LOWER_CASE(psModuleName, qbLC);
+ psModuleName = (LPUTF8) qbLC.Ptr();
+ }
+
+ HashDatum datum;
+ mdFile kFile = NULL;
+ // m_pAllowedFiles only grows - entries are never deleted from it. So we do not take
+ // a lock around GetValue. If the code is modified such that we delete entries from m_pAllowedFiles,
+ // reconsider whether we should take the m_crstAllowedFiles lock here (see the uses of kFile below).
+ if (pAssembly->GetAssembly()->m_pAllowedFiles->GetValue(psModuleName, &datum))
+ kFile = (mdFile)(size_t)datum;
+
+ // If the name doesn't match one of the File def names, don't load this module.
+ // If this name matches the manifest file (datum was NULL), don't load either.
+ if (!kFile)
+ COMPlusThrow(kArgumentException, W("Arg_InvalidFileName"));
+
+
+ PEModuleHolder pFile(PEModule::OpenMemory(pAssembly->GetFile(), kFile,
+ pRawModule, cbModule));
+
+ DomainModule *pDomainModule = GetAppDomain()->LoadDomainModule(pAssembly->GetDomainAssembly(),
+ pFile, FILE_LOADED);
+ pModule = pDomainModule->GetModule();
+
+ if (!pFile->Equals(pModule->GetFile()))
+ COMPlusThrow(kArgumentException, W("Argument_ModuleAlreadyLoaded"));
+
+ LOG((LF_CLASSLOADER,
+ LL_INFO100,
+ "\tLoaded in-memory module\n"));
+
+#ifdef DEBUGGING_SUPPORTED
+ if (!pModule->IsResource())
+ {
+ // If we were given symbols, hold onto a copy
+ if (pRawSymbolStore != NULL)
+ {
+ pModule->SetSymbolBytes(pRawSymbolStore, cbSymbolStore);
+ }
+ }
+#endif // DEBUGGING_SUPPORTED
+
+ if (pModule != NULL)
+ {
+ GCX_COOP();
+ retModule.Set(pModule->GetExposedObject());
+ }
+
+ END_QCALL;
+
+ return;
+}
+#endif // FEATURE_MULTIMODULE_ASSEMBLIES
+
+void QCALLTYPE AssemblyNative::GetLocation(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack retString)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+#ifndef FEATURE_CORECLR
+ // workaround - lie about where mscorlib is. Mscorlib is now loaded out of the GAC,
+ // but some apps query its location to find the system directory. (Notably system.web)
+ if (pAssembly->IsSystem())
+ {
+ retString.Set(SystemDomain::System()->BaseLibrary());
+ }
+ else
+#endif // !FEATURE_CORECLR
+ {
+ retString.Set(pAssembly->GetFile()->GetPath());
+ }
+
+ END_QCALL;
+}
+
+FCIMPL1(FC_BOOL_RET, AssemblyNative::IsReflectionOnly, AssemblyBaseObject *pAssemblyUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ ASSEMBLYREF refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE);
+
+ if (refAssembly == NULL)
+ FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
+
+ FC_RETURN_BOOL(refAssembly->GetDomainAssembly()->IsIntrospectionOnly());
+}
+FCIMPLEND
+
+void QCALLTYPE AssemblyNative::GetType(QCall::AssemblyHandle pAssembly, LPCWSTR wszName, BOOL bThrowOnError, BOOL bIgnoreCase, QCall::ObjectHandleOnStack retType, QCall::ObjectHandleOnStack keepAlive)
+{
+ CONTRACTL
+ {
+ QCALL_CHECK;
+ PRECONDITION(CheckPointer(wszName));
+ }
+ CONTRACTL_END;
+
+ TypeHandle retTypeHandle;
+
+ BEGIN_QCALL;
+
+ if (!wszName)
+ COMPlusThrowArgumentNull(W("name"), W("ArgumentNull_String"));
+
+ BOOL prohibitAsmQualifiedName = TRUE;
+
+ // Load the class from this assembly (fail if it is in a different one).
+ retTypeHandle = TypeName::GetTypeManaged(wszName, pAssembly, bThrowOnError, bIgnoreCase, pAssembly->IsIntrospectionOnly(), prohibitAsmQualifiedName, NULL, FALSE, (OBJECTREF*)keepAlive.m_ppObject);
+
+ if (!retTypeHandle.IsNull())
+ {
+ GCX_COOP();
+ retType.Set(retTypeHandle.GetManagedClassObject());
+ }
+
+ END_QCALL;
+
+ return;
+}
+
+FCIMPL1(FC_BOOL_RET, AssemblyNative::IsDynamic, AssemblyBaseObject* pAssemblyUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ ASSEMBLYREF refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE);
+
+ if (refAssembly == NULL)
+ FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
+
+ FC_RETURN_BOOL(refAssembly->GetDomainAssembly()->GetFile()->IsDynamic());
+}
+FCIMPLEND
+
+void QCALLTYPE AssemblyNative::GetVersion(QCall::AssemblyHandle pAssembly, INT32* pMajorVersion, INT32* pMinorVersion, INT32*pBuildNumber, INT32* pRevisionNumber)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ UINT16 major=0xffff, minor=0xffff, build=0xffff, revision=0xffff;
+
+ pAssembly->GetFile()->GetVersion(&major, &minor, &build, &revision);
+
+ *pMajorVersion = major;
+ *pMinorVersion = minor;
+ *pBuildNumber = build;
+ *pRevisionNumber = revision;
+
+ END_QCALL;
+}
+
+void QCALLTYPE AssemblyNative::GetPublicKey(QCall::AssemblyHandle pAssembly, QCall::ObjectHandleOnStack retPublicKey)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ DWORD cbPublicKey = 0;
+ const void *pbPublicKey = pAssembly->GetFile()->GetPublicKey(&cbPublicKey);
+ retPublicKey.SetByteArray((BYTE *)pbPublicKey, cbPublicKey);
+
+ END_QCALL;
+}
+
+#if !FEATURE_CORECLR
+
+BYTE QCALLTYPE AssemblyNative::GetSecurityRuleSet(QCall::AssemblyHandle pAssembly)
+{
+ QCALL_CONTRACT;
+
+ SecurityRuleSet ruleSet = SecurityRuleSet_Default;
+
+ BEGIN_QCALL;
+
+ ModuleSecurityDescriptor *pMSD = ModuleSecurityDescriptor::GetModuleSecurityDescriptor(pAssembly->GetAssembly());
+ ruleSet = pMSD->GetSecurityRuleSet();
+
+ END_QCALL;
+
+ return static_cast<BYTE>(ruleSet);
+}
+
+#endif // !FEATURE_CORECLR
+
+void QCALLTYPE AssemblyNative::GetSimpleName(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack retSimpleName)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+ retSimpleName.Set(pAssembly->GetSimpleName());
+ END_QCALL;
+}
+
+void QCALLTYPE AssemblyNative::GetLocale(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack retString)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ LPCUTF8 pLocale = pAssembly->GetFile()->GetLocale();
+ if(pLocale)
+ {
+ retString.Set(pLocale);
+ }
+
+ END_QCALL;
+}
+
+void QCALLTYPE AssemblyNative::GetCodeBase(QCall::AssemblyHandle pAssembly, BOOL fCopiedName, QCall::StringHandleOnStack retString)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ StackSString codebase;
+
+#ifndef FEATURE_CORECLR
+ if (pAssembly->IsSystem()) {
+ // workaround: lie about the location of mscorlib. Some callers assume it is in the install dir.
+ codebase.Set(SystemDomain::System()->BaseLibrary());
+ PEAssembly::PathToUrl(codebase);
+ }
+ else
+#endif // !FEATURE_CORECLR
+ {
+ pAssembly->GetFile()->GetCodeBase(codebase);
+ }
+
+ retString.Set(codebase);
+
+ END_QCALL;
+}
+
+INT32 QCALLTYPE AssemblyNative::GetHashAlgorithm(QCall::AssemblyHandle pAssembly)
+{
+ QCALL_CONTRACT;
+
+ INT32 retVal=0;
+ BEGIN_QCALL;
+ retVal = pAssembly->GetFile()->GetHashAlgId();
+ END_QCALL;
+ return retVal;
+}
+
+INT32 QCALLTYPE AssemblyNative::GetFlags(QCall::AssemblyHandle pAssembly)
+{
+ QCALL_CONTRACT;
+
+ INT32 retVal=0;
+ BEGIN_QCALL;
+ retVal = pAssembly->GetFile()->GetFlags();
+ END_QCALL;
+ return retVal;
+}
+
+BYTE * QCALLTYPE AssemblyNative::GetResource(QCall::AssemblyHandle pAssembly, LPCWSTR wszName, UINT64 * length, QCall::StackCrawlMarkHandle stackMark, BOOL skipSecurityCheck)
+{
+ QCALL_CONTRACT;
+
+ PBYTE pbInMemoryResource = NULL;
+
+ BEGIN_QCALL;
+
+ if (wszName == NULL)
+ COMPlusThrow(kArgumentNullException, W("ArgumentNull_String"));
+
+ // Get the name in UTF8
+ SString name(SString::Literal, wszName);
+
+ StackScratchBuffer scratch;
+ LPCUTF8 pNameUTF8 = name.GetUTF8(scratch);
+
+ if (*pNameUTF8 == '\0')
+ COMPlusThrow(kArgumentException, W("Format_StringZeroLength"));
+
+ DWORD cbResource;
+ if (pAssembly->GetResource(pNameUTF8, &cbResource,
+ &pbInMemoryResource, NULL, NULL,
+ NULL, stackMark, skipSecurityCheck, FALSE))
+ {
+ *length = cbResource;
+ }
+
+ END_QCALL;
+
+ // Can return null if resource file is zero-length
+ return pbInMemoryResource;
+}
+
+#ifndef FEATURE_CORECLR
+
+BOOL QCALLTYPE AssemblyNative::UseRelativeBindForSatellites()
+{
+ QCALL_CONTRACT;
+
+ BOOL retVal = TRUE;
+
+ BEGIN_QCALL;
+ retVal = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_RelativeBindForResources);
+ END_QCALL;
+
+ return retVal;
+
+}
+#endif // !FEATURE_CORECLR
+
+INT32 QCALLTYPE AssemblyNative::GetManifestResourceInfo(QCall::AssemblyHandle pAssembly, LPCWSTR wszName, QCall::ObjectHandleOnStack retAssembly, QCall::StringHandleOnStack retFileName, QCall::StackCrawlMarkHandle stackMark)
+{
+ QCALL_CONTRACT;
+
+ INT32 rv = -1;
+
+ BEGIN_QCALL;
+
+ if (wszName == NULL)
+ COMPlusThrow(kArgumentNullException, W("ArgumentNull_String"));
+
+ // Get the name in UTF8
+ SString name(SString::Literal, wszName);
+
+ StackScratchBuffer scratch;
+ LPCUTF8 pNameUTF8 = name.GetUTF8(scratch);
+
+ if (*pNameUTF8 == '\0')
+ COMPlusThrow(kArgumentException, W("Format_StringZeroLength"));
+
+ DomainAssembly * pReferencedAssembly = NULL;
+ LPCSTR pFileName = NULL;
+ DWORD dwLocation = 0;
+
+ if (pAssembly->GetResource(pNameUTF8, NULL, NULL, &pReferencedAssembly, &pFileName,
+ &dwLocation, stackMark, FALSE, FALSE))
+ {
+ if (pFileName)
+ retFileName.Set(pFileName);
+
+ GCX_COOP();
+
+ if (pReferencedAssembly)
+ retAssembly.Set(pReferencedAssembly->GetExposedAssemblyObject());
+
+ rv = dwLocation;
+ }
+
+ END_QCALL;
+
+ return rv;
+}
+
+void QCALLTYPE AssemblyNative::GetModules(QCall::AssemblyHandle pAssembly, BOOL fLoadIfNotFound, BOOL fGetResourceModules, QCall::ObjectHandleOnStack retModules)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ HENUMInternalHolder phEnum(pAssembly->GetMDImport());
+ phEnum.EnumInit(mdtFile, mdTokenNil);
+
+ InlineSArray<DomainFile *, 8> modules;
+
+ modules.Append(pAssembly);
+
+ ReflectionModule *pOnDiskManifest = NULL;
+ if (pAssembly->GetAssembly()->NeedsToHideManifestForEmit())
+ pOnDiskManifest = pAssembly->GetAssembly()->GetOnDiskManifestModule();
+
+ mdFile mdFile;
+ while (pAssembly->GetMDImport()->EnumNext(&phEnum, &mdFile))
+ {
+ DomainFile *pModule = pAssembly->GetModule()->LoadModule(GetAppDomain(), mdFile, fGetResourceModules, !fLoadIfNotFound);
+
+ if (pModule && pModule->GetModule() != pOnDiskManifest) {
+ modules.Append(pModule);
+ }
+ }
+
+ {
+ GCX_COOP();
+
+ PTRARRAYREF orModules = NULL;
+
+ GCPROTECT_BEGIN(orModules);
+
+ // Return the modules
+ orModules = (PTRARRAYREF)AllocateObjectArray(modules.GetCount(), MscorlibBinder::GetClass(CLASS__MODULE));
+
+ for(COUNT_T i = 0; i < modules.GetCount(); i++)
+ {
+ DomainFile * pModule = modules[i];
+
+ OBJECTREF o = pModule->GetExposedModuleObject();
+ orModules->SetAt(i, o);
+ }
+
+ retModules.Set(orModules);
+
+ GCPROTECT_END();
+ }
+
+ END_QCALL;
+}
+
+BOOL QCALLTYPE AssemblyNative::GetNeutralResourcesLanguageAttribute(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack cultureName, INT16& outFallbackLocation)
+{
+ CONTRACTL {
+ QCALL_CHECK;
+ } CONTRACTL_END;
+
+ BOOL retVal = FALSE;
+ BEGIN_QCALL;
+
+ _ASSERTE(pAssembly);
+ Assembly * pAsm = pAssembly->GetAssembly();
+ _ASSERTE(pAsm);
+ Module * pModule = pAsm->GetManifestModule();
+ _ASSERTE(pModule);
+
+ LPCUTF8 pszCultureName = NULL;
+ ULONG cultureNameLength = 0;
+ INT16 fallbackLocation = 0;
+
+ // find the attribute if it exists
+ if (pModule->GetNeutralResourcesLanguage(&pszCultureName, &cultureNameLength, &fallbackLocation, FALSE)) {
+ StackSString culture(SString::Utf8, pszCultureName, cultureNameLength);
+ cultureName.Set(culture);
+ outFallbackLocation = fallbackLocation;
+ retVal = TRUE;
+ }
+
+ END_QCALL;
+
+ return retVal;
+}
+
+void QCALLTYPE AssemblyNative::GetModule(QCall::AssemblyHandle pAssembly, LPCWSTR wszFileName, QCall::ObjectHandleOnStack retModule)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ Module * pModule = NULL;
+
+ CQuickBytes qbLC;
+
+ if (wszFileName == NULL)
+ COMPlusThrow(kArgumentNullException, W("ArgumentNull_FileName"));
+ if (wszFileName[0] == W('\0'))
+ COMPlusThrow(kArgumentException, W("Argument_EmptyFileName"));
+
+
+ MAKE_UTF8PTR_FROMWIDE(szModuleName, wszFileName);
+
+#ifdef FEATURE_MULTIMODULE_ASSEMBLIES
+ // Need to perform case insensitive lookup.
+ {
+ UTF8_TO_LOWER_CASE(szModuleName, qbLC);
+ szModuleName = (LPUTF8) qbLC.Ptr();
+ }
+
+ HashDatum datum = NULL;
+
+ // m_pAllowedFiles only grows - entries are never deleted from it. So we do not take
+ // a lock around GetValue. If the code is modified such that we delete entries from m_pAllowedFiles,
+ // reconsider whether we should take the m_crstAllowedFiles lock here (see the uses of datum below).
+ if (pAssembly->GetAssembly()->m_pAllowedFiles->GetValue(szModuleName, &datum))
+ {
+ if (datum)
+ {
+ // internal module
+ mdFile tokFile = (mdFile)(UINT_PTR)datum;
+
+ pModule = pAssembly->GetModule()->LoadModule(GetAppDomain(), tokFile)->GetModule();
+ }
+ else
+ { // manifest module
+ pModule = pAssembly->GetDomainAssembly()->GetModule();
+ }
+ }
+#else
+
+ LPCUTF8 pModuleName = NULL;
+
+ if SUCCEEDED(pAssembly->GetDomainAssembly()->GetModule()->GetScopeName(&pModuleName))
+ {
+ if (::SString::_stricmp(pModuleName, szModuleName) == 0)
+ pModule = pAssembly->GetDomainAssembly()->GetModule();
+ }
+
+#endif
+
+ if (pModule != NULL)
+ {
+ GCX_COOP();
+ retModule.Set(pModule->GetExposedObject());
+ }
+
+ END_QCALL;
+
+ return;
+}
+
+void QCALLTYPE AssemblyNative::GetExportedTypes(QCall::AssemblyHandle pAssembly, QCall::ObjectHandleOnStack retTypes)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ InlineSArray<TypeHandle, 20> types;
+
+ Assembly * pAsm = pAssembly->GetAssembly();
+
+ IMDInternalImport *pImport = pAsm->GetManifestImport();
+
+ {
+ HENUMTypeDefInternalHolder phTDEnum(pImport);
+ phTDEnum.EnumTypeDefInit();
+
+ mdTypeDef mdTD;
+ while(pImport->EnumNext(&phTDEnum, &mdTD))
+ {
+ DWORD dwFlags;
+ IfFailThrow(pImport->GetTypeDefProps(
+ mdTD,
+ &dwFlags,
+ NULL));
+
+ // nested type
+ mdTypeDef mdEncloser = mdTD;
+ while (SUCCEEDED(pImport->GetNestedClassProps(mdEncloser, &mdEncloser)) &&
+ IsTdNestedPublic(dwFlags))
+ {
+ IfFailThrow(pImport->GetTypeDefProps(
+ mdEncloser,
+ &dwFlags,
+ NULL));
+ }
+
+ if (IsTdPublic(dwFlags))
+ {
+ TypeHandle typeHnd = ClassLoader::LoadTypeDefThrowing(pAsm->GetManifestModule(), mdTD,
+ ClassLoader::ThrowIfNotFound,
+ ClassLoader::PermitUninstDefOrRef);
+ types.Append(typeHnd);
+ }
+ }
+ }
+
+ {
+ HENUMInternalHolder phCTEnum(pImport);
+ phCTEnum.EnumInit(mdtExportedType, mdTokenNil);
+
+ // Now get the ExportedTypes that don't have TD's in the manifest file
+ mdExportedType mdCT;
+ while(pImport->EnumNext(&phCTEnum, &mdCT))
+ {
+ mdToken mdImpl;
+ LPCSTR pszNameSpace;
+ LPCSTR pszClassName;
+ DWORD dwFlags;
+
+ IfFailThrow(pImport->GetExportedTypeProps(
+ mdCT,
+ &pszNameSpace,
+ &pszClassName,
+ &mdImpl,
+ NULL, //binding
+ &dwFlags));
+
+ // nested type
+ while ((TypeFromToken(mdImpl) == mdtExportedType) &&
+ (mdImpl != mdExportedTypeNil) &&
+ IsTdNestedPublic(dwFlags))
+ {
+ IfFailThrow(pImport->GetExportedTypeProps(
+ mdImpl,
+ NULL, //namespace
+ NULL, //name
+ &mdImpl,
+ NULL, //binding
+ &dwFlags));
+ }
+
+ if ((TypeFromToken(mdImpl) == mdtFile) &&
+ (mdImpl != mdFileNil) &&
+ IsTdPublic(dwFlags))
+ {
+ NameHandle typeName(pszNameSpace, pszClassName);
+ typeName.SetTypeToken(pAsm->GetManifestModule(), mdCT);
+ TypeHandle typeHnd = pAsm->GetLoader()->LoadTypeHandleThrowIfFailed(&typeName);
+
+ types.Append(typeHnd);
+ }
+ }
+ }
+
+ {
+ GCX_COOP();
+
+ PTRARRAYREF orTypes = NULL;
+
+ GCPROTECT_BEGIN(orTypes);
+
+ // Return the types
+ orTypes = (PTRARRAYREF)AllocateObjectArray(types.GetCount(), MscorlibBinder::GetClass(CLASS__TYPE));
+
+ for(COUNT_T i = 0; i < types.GetCount(); i++)
+ {
+ TypeHandle typeHnd = types[i];
+
+ OBJECTREF o = typeHnd.GetManagedClassObject();
+ orTypes->SetAt(i, o);
+ }
+
+ retTypes.Set(orTypes);
+
+ GCPROTECT_END();
+ }
+
+ END_QCALL;
+}
+
+void QCALLTYPE AssemblyNative::GetForwardedTypes(QCall::AssemblyHandle pAssembly, QCall::ObjectHandleOnStack retTypes)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ InlineSArray<TypeHandle, 8> types;
+
+ Assembly * pAsm = pAssembly->GetAssembly();
+
+ IMDInternalImport *pImport = pAsm->GetManifestImport();
+
+ // enumerate the ExportedTypes table
+ {
+ HENUMInternalHolder phCTEnum(pImport);
+ phCTEnum.EnumInit(mdtExportedType, mdTokenNil);
+
+ // Now get the ExportedTypes that don't have TD's in the manifest file
+ mdExportedType mdCT;
+ while(pImport->EnumNext(&phCTEnum, &mdCT))
+ {
+ mdToken mdImpl;
+ LPCSTR pszNameSpace;
+ LPCSTR pszClassName;
+ DWORD dwFlags;
+
+ IfFailThrow(pImport->GetExportedTypeProps(mdCT,
+ &pszNameSpace,
+ &pszClassName,
+ &mdImpl,
+ NULL, //binding
+ &dwFlags));
+
+ if ((TypeFromToken(mdImpl) == mdtAssemblyRef) && (mdImpl != mdAssemblyRefNil))
+ {
+ NameHandle typeName(pszNameSpace, pszClassName);
+ typeName.SetTypeToken(pAsm->GetManifestModule(), mdCT);
+ TypeHandle typeHnd = pAsm->GetLoader()->LoadTypeHandleThrowIfFailed(&typeName);
+
+ types.Append(typeHnd);
+ }
+ }
+ }
+
+ // Populate retTypes
+ {
+ GCX_COOP();
+
+ PTRARRAYREF orTypes = NULL;
+
+ GCPROTECT_BEGIN(orTypes);
+
+ // Return the types
+ orTypes = (PTRARRAYREF)AllocateObjectArray(types.GetCount(), MscorlibBinder::GetClass(CLASS__TYPE));
+
+ for(COUNT_T i = 0; i < types.GetCount(); i++)
+ {
+ TypeHandle typeHnd = types[i];
+
+ OBJECTREF o = typeHnd.GetManagedClassObject();
+ orTypes->SetAt(i, o);
+ }
+
+ retTypes.Set(orTypes);
+
+ GCPROTECT_END();
+ }
+
+ END_QCALL;
+}
+
+FCIMPL1(Object*, AssemblyNative::GetManifestResourceNames, AssemblyBaseObject * pAssemblyUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ ASSEMBLYREF refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE);
+
+ if (refAssembly == NULL)
+ FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
+
+ DomainAssembly *pAssembly = refAssembly->GetDomainAssembly();
+ PTRARRAYREF rv = NULL;
+
+ HELPER_METHOD_FRAME_BEGIN_RET_2(rv, refAssembly);
+
+ IMDInternalImport *pImport = pAssembly->GetMDImport();
+
+ HENUMInternalHolder phEnum(pImport);
+ DWORD dwCount;
+
+ phEnum.EnumInit(mdtManifestResource, mdTokenNil);
+ dwCount = pImport->EnumGetCount(&phEnum);
+
+ PTRARRAYREF ItemArray = (PTRARRAYREF) AllocateObjectArray(dwCount, g_pStringClass);
+
+ mdManifestResource mdResource;
+
+ GCPROTECT_BEGIN(ItemArray);
+ for(DWORD i = 0; i < dwCount; i++) {
+ pImport->EnumNext(&phEnum, &mdResource);
+ LPCSTR pszName = NULL;
+
+ IfFailThrow(pImport->GetManifestResourceProps(
+ mdResource,
+ &pszName, // name
+ NULL, // linkref
+ NULL, // offset
+ NULL)); //flags
+
+ OBJECTREF o = (OBJECTREF) StringObject::NewString(pszName);
+ ItemArray->SetAt(i, o);
+ }
+
+ rv = ItemArray;
+ GCPROTECT_END();
+
+ HELPER_METHOD_FRAME_END();
+
+ return OBJECTREFToObject(rv);
+}
+FCIMPLEND
+
+FCIMPL1(Object*, AssemblyNative::GetReferencedAssemblies, AssemblyBaseObject * pAssemblyUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ struct _gc {
+ PTRARRAYREF ItemArray;
+ ASSEMBLYNAMEREF pObj;
+ ASSEMBLYREF refAssembly;
+ } gc;
+ ZeroMemory(&gc, sizeof(gc));
+
+ gc.refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE);
+
+ if (gc.refAssembly == NULL)
+ FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
+
+ DomainAssembly *pAssembly = gc.refAssembly->GetDomainAssembly();
+
+ HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
+
+ IMDInternalImport *pImport = pAssembly->GetAssembly()->GetManifestImport();
+
+ MethodTable* pAsmNameClass = MscorlibBinder::GetClass(CLASS__ASSEMBLY_NAME);
+
+ HENUMInternalHolder phEnum(pImport);
+ DWORD dwCount = 0;
+
+ phEnum.EnumInit(mdtAssemblyRef, mdTokenNil);
+
+ dwCount = pImport->EnumGetCount(&phEnum);
+
+ mdAssemblyRef mdAssemblyRef;
+
+ gc.ItemArray = (PTRARRAYREF) AllocateObjectArray(dwCount, pAsmNameClass);
+
+ for(DWORD i = 0; i < dwCount; i++)
+ {
+ pImport->EnumNext(&phEnum, &mdAssemblyRef);
+
+ AssemblySpec spec;
+ spec.InitializeSpec(mdAssemblyRef, pImport);
+
+ gc.pObj = (ASSEMBLYNAMEREF) AllocateObject(pAsmNameClass);
+ spec.AssemblyNameInit(&gc.pObj,NULL);
+
+ gc.ItemArray->SetAt(i, (OBJECTREF) gc.pObj);
+ }
+
+ HELPER_METHOD_FRAME_END();
+
+ return OBJECTREFToObject(gc.ItemArray);
+}
+FCIMPLEND
+
+void QCALLTYPE AssemblyNative::GetEntryPoint(QCall::AssemblyHandle pAssembly, QCall::ObjectHandleOnStack retMethod)
+{
+ QCALL_CONTRACT;
+
+ MethodDesc* pMeth = NULL;
+
+ BEGIN_QCALL;
+
+ pMeth = pAssembly->GetAssembly()->GetEntryPoint();
+ if (pMeth != NULL)
+ {
+ GCX_COOP();
+ retMethod.Set(pMeth->GetStubMethodInfo());
+ }
+
+ END_QCALL;
+
+ return;
+}
+
+#ifndef FEATURE_CORECLR
+// prepare saving manifest to disk
+void QCALLTYPE AssemblyNative::PrepareForSavingManifestToDisk(QCall::AssemblyHandle pAssembly, QCall::ModuleHandle pAssemblyModule)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ pAssembly->GetAssembly()->PrepareSavingManifest((ReflectionModule *)(Module *)pAssemblyModule);
+
+ END_QCALL;
+}
+
+#endif
+
+#ifndef FEATURE_CORECLR
+// add a file name to the file list of this assembly. On disk only.
+mdFile QCALLTYPE AssemblyNative::AddFile(QCall::AssemblyHandle pAssembly, LPCWSTR wszFileName)
+{
+ QCALL_CONTRACT;
+
+ mdFile retVal = 0;
+
+ BEGIN_QCALL;
+
+ retVal = pAssembly->GetAssembly()->AddFile(wszFileName);
+
+ END_QCALL;
+
+ return retVal;
+}
+#endif //FEATURE_CORECLR
+
+#ifndef FEATURE_CORECLR
+// set the hash value on a file.
+void QCALLTYPE AssemblyNative::SetFileHashValue(QCall::AssemblyHandle pAssembly, INT32 tkFile, LPCWSTR wszFullFileName)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ pAssembly->GetAssembly()->SetFileHashValue(tkFile, wszFullFileName);
+
+ END_QCALL;
+}
+#endif //FEATURE_CORECLR
+
+#ifndef FEATURE_CORECLR
+// Add a Type name to the ExportedType table in the on-disk assembly manifest.
+mdExportedType QCALLTYPE AssemblyNative::AddExportedTypeOnDisk(QCall::AssemblyHandle pAssembly, LPCWSTR wszCOMTypeName, INT32 tkImpl, INT32 tkTypeDef, INT32 flags)
+{
+ QCALL_CONTRACT;
+
+ mdExportedType retVal = 0;
+
+ BEGIN_QCALL;
+
+ retVal = pAssembly->GetAssembly()->AddExportedTypeOnDisk(wszCOMTypeName, tkImpl, tkTypeDef, (CorTypeAttr)flags);
+
+ END_QCALL;
+
+ return retVal;
+}
+
+// Add a Type name to the ExportedType table in the in-memory assembly manifest.
+mdExportedType QCALLTYPE AssemblyNative::AddExportedTypeInMemory(QCall::AssemblyHandle pAssembly, LPCWSTR wszCOMTypeName, INT32 tkImpl, INT32 tkTypeDef, INT32 flags)
+{
+ QCALL_CONTRACT;
+
+ mdExportedType retVal = 0;
+
+ BEGIN_QCALL;
+
+ retVal = pAssembly->GetAssembly()->AddExportedTypeInMemory(wszCOMTypeName, tkImpl, tkTypeDef, (CorTypeAttr)flags);
+
+ END_QCALL;
+
+ return retVal;
+}
+#endif //FEATURE_CORECLR
+
+#ifndef FEATURE_CORECLR
+// add a Stand alone resource to ManifestResource table
+void QCALLTYPE AssemblyNative::AddStandAloneResource(QCall::AssemblyHandle pAssembly, LPCWSTR wszName, LPCWSTR wszFileName, LPCWSTR wszFullFileName, INT32 iAttribute)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ pAssembly->GetAssembly()->AddStandAloneResource(
+ wszName,
+ NULL,
+ NULL,
+ wszFileName,
+ wszFullFileName,
+ iAttribute);
+
+ END_QCALL;
+}
+#endif //FEATURE_CORECLR
+
+#ifndef FEATURE_CORECLR
+// Save security permission requests.
+void QCALLTYPE AssemblyNative::AddDeclarativeSecurity(QCall::AssemblyHandle pAssembly, INT32 action, PVOID blob, INT32 length)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ pAssembly->GetAssembly()->AddDeclarativeSecurity(action, blob, length);
+
+ END_QCALL;
+}
+#endif //FEATURE_CORECLR
+
+//---------------------------------------------------------------------------------------
+//
+// Get the raw bytes making up this assembly
+//
+// Arguments:
+// pAssembly - Assembly to get the data of
+// retRawBytes - [out] raw bytes of the assembly
+//
+
+// static
+void QCALLTYPE AssemblyNative::GetRawBytes(QCall::AssemblyHandle pAssembly,
+ QCall::ObjectHandleOnStack retRawBytes)
+{
+ QCALL_CONTRACT;
+ BEGIN_QCALL;
+
+ PEFile *pPEFile = pAssembly->GetFile();
+ if (pPEFile != NULL)
+ {
+ PEImage *pPEImage = pPEFile->GetILimage();
+
+ if (pPEImage != NULL)
+ {
+ SBuffer dataBuffer;
+ pPEImage->GetImageBits(PEImageLayout::LAYOUT_FLAT, dataBuffer);
+
+ if (dataBuffer.GetSize() > 0)
+ {
+ retRawBytes.SetByteArray(dataBuffer, dataBuffer.GetSize());
+ }
+ }
+ }
+
+ END_QCALL;
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Release QCALL for System.SafePEFileHandle
+//
+//
+
+// static
+void QCALLTYPE AssemblyNative::ReleaseSafePEFileHandle(PEFile *pPEFile)
+{
+ CONTRACTL
+ {
+ QCALL_CHECK;
+ PRECONDITION(CheckPointer(pPEFile));
+ }
+ CONTRACTL_END;
+
+ BEGIN_QCALL;
+
+ pPEFile->Release();
+
+ END_QCALL;
+}
+
+// save the manifest to disk!
+extern void ManagedBitnessFlagsToUnmanagedBitnessFlags(
+ INT32 portableExecutableKind, INT32 imageFileMachine,
+ DWORD* pPeFlags, DWORD* pCorhFlags);
+
+#ifndef FEATURE_CORECLR
+void QCALLTYPE AssemblyNative::SaveManifestToDisk(QCall::AssemblyHandle pAssembly,
+ LPCWSTR wszManifestFileName,
+ INT32 entrypoint,
+ INT32 fileKind,
+ INT32 portableExecutableKind,
+ INT32 imageFileMachine)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ DWORD peFlags = 0, corhFlags = 0;
+ ManagedBitnessFlagsToUnmanagedBitnessFlags(portableExecutableKind, imageFileMachine, &peFlags, &corhFlags);
+
+ pAssembly->GetAssembly()->SaveManifestToDisk(wszManifestFileName, entrypoint, fileKind, corhFlags, peFlags);
+
+ END_QCALL;
+}
+#endif // !FEATURE_CORECLR
+
+void QCALLTYPE AssemblyNative::GetFullName(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack retString)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ StackSString name;
+ pAssembly->GetFile()->GetDisplayName(name);
+ retString.Set(name);
+
+ END_QCALL;
+}
+
+void QCALLTYPE AssemblyNative::GetExecutingAssembly(QCall::StackCrawlMarkHandle stackMark, QCall::ObjectHandleOnStack retAssembly)
+{
+ QCALL_CONTRACT;
+
+ DomainAssembly * pExecutingAssembly = NULL;
+
+ BEGIN_QCALL;
+
+ Assembly* pAssembly = SystemDomain::GetCallersAssembly(stackMark);
+ if(pAssembly)
+ {
+ pExecutingAssembly = pAssembly->GetDomainAssembly();
+ GCX_COOP();
+ retAssembly.Set(pExecutingAssembly->GetExposedAssemblyObject());
+ }
+
+ END_QCALL;
+ return;
+}
+
+void QCALLTYPE AssemblyNative::GetEntryAssembly(QCall::ObjectHandleOnStack retAssembly)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ DomainAssembly * pRootAssembly = NULL;
+ Assembly * pAssembly = GetAppDomain()->m_pRootAssembly;
+
+ if (pAssembly)
+ {
+ pRootAssembly = pAssembly->GetDomainAssembly();
+ GCX_COOP();
+ retAssembly.Set(pRootAssembly->GetExposedAssemblyObject());
+ }
+
+ END_QCALL;
+
+ return;
+}
+
+
+void QCALLTYPE AssemblyNative::GetGrantSet(QCall::AssemblyHandle pAssembly, QCall::ObjectHandleOnStack retGranted, QCall::ObjectHandleOnStack retDenied)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ IAssemblySecurityDescriptor *pSecDesc = pAssembly->GetSecurityDescriptor();
+
+ {
+ GCX_COOP();
+
+ pSecDesc->Resolve();
+
+ OBJECTREF granted, denied;
+
+ granted = pSecDesc->GetGrantedPermissionSet(&denied);
+
+ retGranted.Set(granted);
+ retDenied.Set(denied);
+ }
+
+ END_QCALL;
+}
+
+//
+// QCalls to determine if everything introduced by the assembly is either security critical or safe critical
+//
+
+// static
+BOOL QCALLTYPE AssemblyNative::IsAllSecurityCritical(QCall::AssemblyHandle pAssembly)
+{
+ QCALL_CONTRACT;
+
+ BOOL fIsCritical = FALSE;
+
+ BEGIN_QCALL;
+
+ fIsCritical = pAssembly->GetSecurityDescriptor()->IsAllCritical();
+
+ END_QCALL;
+
+ return fIsCritical;
+}
+
+// static
+BOOL QCALLTYPE AssemblyNative::IsAllSecuritySafeCritical(QCall::AssemblyHandle pAssembly)
+{
+ QCALL_CONTRACT;
+
+ BOOL fIsSafeCritical = FALSE;
+
+ BEGIN_QCALL;
+
+ fIsSafeCritical = pAssembly->GetSecurityDescriptor()->IsAllSafeCritical();
+
+ END_QCALL;
+
+ return fIsSafeCritical;
+}
+
+// static
+BOOL QCALLTYPE AssemblyNative::IsAllPublicAreaSecuritySafeCritical(QCall::AssemblyHandle pAssembly)
+{
+ QCALL_CONTRACT;
+
+ BOOL fIsAllPublicAreaSafeCritical = FALSE;
+
+ BEGIN_QCALL;
+
+ fIsAllPublicAreaSafeCritical = pAssembly->GetSecurityDescriptor()->IsAllPublicAreaSafeCritical();
+
+ END_QCALL;
+
+ return fIsAllPublicAreaSafeCritical;
+}
+
+// static
+BOOL QCALLTYPE AssemblyNative::IsAllSecurityTransparent(QCall::AssemblyHandle pAssembly)
+{
+ QCALL_CONTRACT;
+
+ BOOL fIsTransparent = FALSE;
+
+ BEGIN_QCALL;
+
+ fIsTransparent = pAssembly->GetSecurityDescriptor()->IsAllTransparent();
+
+ END_QCALL;
+
+ return fIsTransparent;
+}
+
+// return the on disk assembly module for reflection emit. This only works for dynamic assembly.
+FCIMPL1(ReflectModuleBaseObject *, AssemblyNative::GetOnDiskAssemblyModule, AssemblyBaseObject* pAssemblyUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ ASSEMBLYREF refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE);
+
+ if (refAssembly == NULL)
+ FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
+
+ DomainAssembly *pAssembly = refAssembly->GetDomainAssembly();
+
+ FC_RETURN_MODULE_OBJECT(pAssembly->GetCurrentAssembly()->GetOnDiskManifestModule(), refAssembly);
+}
+FCIMPLEND
+
+// return the in memory assembly module for reflection emit. This only works for dynamic assembly.
+FCIMPL1(ReflectModuleBaseObject *, AssemblyNative::GetInMemoryAssemblyModule, AssemblyBaseObject* pAssemblyUNSAFE)
+{
+ FCALL_CONTRACT;
+
+
+ ASSEMBLYREF refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE);
+
+ if (refAssembly == NULL)
+ FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
+
+ DomainAssembly *pAssembly = refAssembly->GetDomainAssembly();
+
+ FC_RETURN_MODULE_OBJECT(pAssembly->GetCurrentModule(), refAssembly);
+}
+FCIMPLEND
+
+
+#ifndef FEATURE_CORECLR
+// Create a stand-alone resource file for version resource.
+void QCALLTYPE AssemblyNative::CreateVersionInfoResource(LPCWSTR pwzFilename,
+ LPCWSTR pwzTitle,
+ LPCWSTR pwzIconFilename,
+ LPCWSTR pwzDescription,
+ LPCWSTR pwzCopyright,
+ LPCWSTR pwzTrademark,
+ LPCWSTR pwzCompany,
+ LPCWSTR pwzProduct,
+ LPCWSTR pwzProductVersion,
+ LPCWSTR pwzFileVersion,
+ INT32 lcid,
+ BOOL fIsDll,
+ QCall::StringHandleOnStack retFileName)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ Win32Res res; // Resource helper object.
+ const void *pvData=0; // Pointer to the resource.
+ ULONG cbData; // Size of the resource data.
+ ULONG cbWritten;
+ PathString szFile; // File name for resource file.
+ PathString szPath; // Path name for resource file.
+ HandleHolder hFile;
+
+ res.SetInfo(pwzFilename,
+ pwzTitle,
+ pwzIconFilename,
+ pwzDescription,
+ pwzCopyright,
+ pwzTrademark,
+ pwzCompany,
+ pwzProduct,
+ pwzProductVersion,
+ pwzFileVersion,
+ lcid,
+ fIsDll);
+
+ res.MakeResFile(&pvData, &cbData);
+
+ //<TODO>Change the COMPlusThrowWin32's to exceptions with
+ // messages including the path/file name</TODO>
+
+ // Persist to a file.
+ if (!WszGetTempPath(szPath))
+ COMPlusThrowWin32();
+ if (!WszGetTempFileName(szPath.GetUnicode(), W("RES"), 0, szFile))
+ COMPlusThrowWin32();
+
+ hFile = WszCreateFile(szFile, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ COMPlusThrowWin32();
+
+ if (!WriteFile(hFile, pvData, cbData, &cbWritten, NULL))
+ COMPlusThrowWin32();
+
+ retFileName.Set(szFile);
+
+ END_QCALL;
+}
+#endif // !FEATURE_CORECLR
+
+#ifndef FEATURE_CORECLR
+FCIMPL1(FC_BOOL_RET, AssemblyNative::IsGlobalAssemblyCache, AssemblyBaseObject* pAssemblyUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ ASSEMBLYREF refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE);
+
+ if (refAssembly == NULL)
+ FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
+
+ DomainAssembly *pAssembly = refAssembly->GetDomainAssembly();
+
+ FC_RETURN_BOOL(pAssembly->GetFile()->IsSourceGAC());
+}
+FCIMPLEND
+#endif // !FEATURE_CORECLR
+
+void QCALLTYPE AssemblyNative::GetImageRuntimeVersion(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack retString)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ // Retrieve the PEFile from the assembly.
+ PEFile* pPEFile = pAssembly->GetFile();
+ PREFIX_ASSUME(pPEFile!=NULL);
+
+ LPCSTR pszVersion = NULL;
+ IfFailThrow(pPEFile->GetMDImport()->GetVersionString(&pszVersion));
+
+ SString version(SString::Utf8, pszVersion);
+ #ifndef FEATURE_CORECLR
+ AdjustImageRuntimeVersion(&version);
+#endif // FEATURE_CORECLR
+
+ // Allocate a managed string that contains the version and return it.
+ retString.Set(version);
+
+ END_QCALL;
+}
+
+#ifdef FEATURE_FUSION
+INT64 QCALLTYPE AssemblyNative::GetHostContext(QCall::AssemblyHandle pAssembly)
+{
+ QCALL_CONTRACT;
+
+ UINT64 Context = 0;
+
+ BEGIN_QCALL;
+
+ IHostAssembly *pIHostAssembly = pAssembly->GetFile()->GetIHostAssembly();
+ if (pIHostAssembly != NULL)
+ {
+ IfFailThrow(pIHostAssembly->GetAssemblyContext(&Context));
+ }
+
+ END_QCALL;
+
+ return Context;
+}
+#endif // FEATURE_FUSION
+
+#ifdef FEATURE_CAS_POLICY
+BOOL QCALLTYPE AssemblyNative::IsStrongNameVerified(QCall::AssemblyHandle pAssembly)
+{
+ QCALL_CONTRACT;
+
+ BOOL fStrongNameVerified = FALSE;
+
+ BEGIN_QCALL;
+
+ PEFile *pPEFile = pAssembly->GetFile();
+ fStrongNameVerified = pPEFile->IsStrongNameVerified();
+
+ END_QCALL;
+
+ return fStrongNameVerified;
+}
+#endif // FEATURE_CAS_POLICY
+
+#ifdef FEATURE_APPX
+/*static*/
+BOOL QCALLTYPE AssemblyNative::IsDesignerBindingContext(QCall::AssemblyHandle pAssembly)
+{
+ QCALL_CONTRACT;
+
+ BOOL fRet = FALSE;
+
+ BEGIN_QCALL;
+
+ PEFile *pPEFile = pAssembly->GetFile();
+ fRet = pPEFile->IsDesignerBindingContext();
+
+ END_QCALL;
+
+ return fRet;
+}
+#endif // FEATURE_APPX
+
+#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
+/*static*/
+INT_PTR QCALLTYPE AssemblyNative::InitializeAssemblyLoadContext(INT_PTR ptrManagedAssemblyLoadContext, BOOL fRepresentsTPALoadContext)
+{
+ QCALL_CONTRACT;
+
+ INT_PTR ptrNativeAssemblyLoadContext = NULL;
+
+ BEGIN_QCALL;
+
+ // We do not need to take a lock since this method is invoked from the ctor of AssemblyLoadContext managed type and
+ // only one thread is ever executing a ctor for a given instance.
+ //
+
+ // Initialize the assembly binder instance in the VM
+ PTR_AppDomain pCurDomain = AppDomain::GetCurrentDomain();
+ CLRPrivBinderCoreCLR *pTPABinderContext = pCurDomain->GetTPABinderContext();
+ if (!fRepresentsTPALoadContext)
+ {
+ // Initialize a custom Assembly Load Context
+ CLRPrivBinderAssemblyLoadContext *pBindContext = NULL;
+ IfFailThrow(CLRPrivBinderAssemblyLoadContext::SetupContext(pCurDomain->GetId().m_dwId, pTPABinderContext, ptrManagedAssemblyLoadContext, &pBindContext));
+ ptrNativeAssemblyLoadContext = reinterpret_cast<INT_PTR>(pBindContext);
+ }
+ else
+ {
+ // We are initializing the managed instance of Assembly Load Context that would represent the TPA binder.
+ // First, confirm we do not have an existing managed ALC attached to the TPA binder.
+ INT_PTR ptrTPAAssemblyLoadContext = pTPABinderContext->GetManagedAssemblyLoadContext();
+ if ((ptrTPAAssemblyLoadContext != NULL) && (ptrTPAAssemblyLoadContext != ptrManagedAssemblyLoadContext))
+ {
+ COMPlusThrow(kInvalidOperationException, IDS_HOST_ASSEMBLY_RESOLVER_INCOMPATIBLE_TPA_BINDING_CONTEXT);
+ }
+
+ // Attach the managed TPA binding context with the native one.
+ pTPABinderContext->SetManagedAssemblyLoadContext(ptrManagedAssemblyLoadContext);
+ ptrNativeAssemblyLoadContext = reinterpret_cast<INT_PTR>(pTPABinderContext);
+ }
+
+ END_QCALL;
+
+ return ptrNativeAssemblyLoadContext;
+}
+
+/*static*/
+BOOL QCALLTYPE AssemblyNative::OverrideDefaultAssemblyLoadContextForCurrentDomain(INT_PTR ptrNativeAssemblyLoadContext)
+{
+ QCALL_CONTRACT;
+
+ BOOL fOverrodeDefaultLoadContext = FALSE;
+
+ BEGIN_QCALL;
+
+ AppDomain *pCurDomain = AppDomain::GetCurrentDomain();
+
+ if (pCurDomain->LockBindingModel())
+ {
+ // Only one thread will ever enter here - it will be the ones that actually locked the binding model
+ //
+ // AssemblyLoadContext should have a binder associated with it
+ IUnknown *pOverrideBinder = reinterpret_cast<IUnknown *>(ptrNativeAssemblyLoadContext);
+ _ASSERTE(pOverrideBinder != NULL);
+
+ // Get reference to the current default context binder
+
+ IUnknown * pCurrentDefaultContextBinder = pCurDomain->GetFusionContext();
+
+ // The default context binder can never be null since the runtime always sets one up
+ _ASSERTE(pCurrentDefaultContextBinder != NULL);
+
+ // The default context should also be the same as TPABinder context
+ _ASSERTE(pCurrentDefaultContextBinder == pCurDomain->GetTPABinderContext());
+
+ // Override the default context binder in the VM
+ pCurDomain->OverrideDefaultContextBinder(pOverrideBinder);
+
+ fOverrodeDefaultLoadContext = TRUE;
+ }
+
+ END_QCALL;
+
+ return fOverrodeDefaultLoadContext;
+}
+
+BOOL QCALLTYPE AssemblyNative::CanUseAppPathAssemblyLoadContextInCurrentDomain()
+{
+ QCALL_CONTRACT;
+
+ BOOL fCanUseAppPathAssemblyLoadContext = FALSE;
+
+ BEGIN_QCALL;
+
+ AppDomain *pCurDomain = AppDomain::GetCurrentDomain();
+
+ pCurDomain->LockBindingModel();
+
+ fCanUseAppPathAssemblyLoadContext = !pCurDomain->IsHostAssemblyResolverInUse();
+
+ END_QCALL;
+
+ return fCanUseAppPathAssemblyLoadContext;
+}
+
+/*static*/
+INT_PTR QCALLTYPE AssemblyNative::GetLoadContextForAssembly(QCall::AssemblyHandle pAssembly)
+{
+ QCALL_CONTRACT;
+
+ INT_PTR ptrManagedAssemblyLoadContext = NULL;
+
+ BEGIN_QCALL;
+
+ // Get the PEAssembly for the RuntimeAssembly
+ PEFile *pPEFile = pAssembly->GetFile();
+ PTR_PEAssembly pPEAssembly = pPEFile->AsAssembly();
+ _ASSERTE(pAssembly != NULL);
+
+ // Platform assemblies are semantically bound against the "Default" binder which could be the TPA Binder or
+ // the overridden binder. In either case, the reference to the same will be returned when this QCall returns.
+ if (!pPEAssembly->IsProfileAssembly())
+ {
+ // Get the binding context for the assembly.
+ //
+ ICLRPrivBinder *pOpaqueBinder = nullptr;
+ AppDomain *pCurDomain = AppDomain::GetCurrentDomain();
+ CLRPrivBinderCoreCLR *pTPABinder = pCurDomain->GetTPABinderContext();
+
+
+ // GetBindingContext returns a ICLRPrivAssembly which can be used to get access to the
+ // actual ICLRPrivBinder instance in which the assembly was loaded.
+ PTR_ICLRPrivBinder pBindingContext = pPEAssembly->GetBindingContext();
+ UINT_PTR assemblyBinderID = 0;
+ IfFailThrow(pBindingContext->GetBinderID(&assemblyBinderID));
+
+ // If the assembly was bound using the TPA binder,
+ // then we will return the reference to "Default" binder from the managed implementation when this QCall returns.
+ //
+ // See earlier comment about "Default" binder for additional context.
+ pOpaqueBinder = reinterpret_cast<ICLRPrivBinder *>(assemblyBinderID);
+
+ // We should have a load context binder at this point.
+ _ASSERTE(pOpaqueBinder != nullptr);
+
+ if (!AreSameBinderInstance(pTPABinder, pOpaqueBinder))
+ {
+ // Only CLRPrivBinderAssemblyLoadContext instance contains the reference to its
+ // corresponding managed instance.
+ CLRPrivBinderAssemblyLoadContext *pBinder = (CLRPrivBinderAssemblyLoadContext *)(pOpaqueBinder);
+
+ // Fetch the managed binder reference from the native binder instance
+ ptrManagedAssemblyLoadContext = pBinder->GetManagedAssemblyLoadContext();
+ _ASSERTE(ptrManagedAssemblyLoadContext != NULL);
+ }
+ }
+
+ END_QCALL;
+
+ return ptrManagedAssemblyLoadContext;
+}
+#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
+
+// static
+BOOL QCALLTYPE AssemblyNative::InternalTryGetRawMetadata(
+ QCall::AssemblyHandle assembly,
+ UINT8 **blobRef,
+ INT32 *lengthRef)
+{
+ QCALL_CONTRACT;
+
+ PTR_CVOID metadata = nullptr;
+
+ BEGIN_QCALL;
+
+ _ASSERTE(assembly != nullptr);
+ _ASSERTE(blobRef != nullptr);
+ _ASSERTE(lengthRef != nullptr);
+
+ static_assert_no_msg(sizeof(*lengthRef) == sizeof(COUNT_T));
+ metadata = assembly->GetFile()->GetLoadedMetadata(reinterpret_cast<COUNT_T *>(lengthRef));
+ *blobRef = reinterpret_cast<UINT8 *>(const_cast<PTR_VOID>(metadata));
+ _ASSERTE(*lengthRef >= 0);
+
+ END_QCALL;
+
+ return metadata != nullptr;
+}