| 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. |
| 4 | |
| 5 | /*============================================================ |
| 6 | ** |
| 7 | ** Header: AssemblyNative.cpp |
| 8 | ** |
| 9 | ** Purpose: Implements AssemblyNative (loader domain) architecture |
| 10 | ** |
| 11 | ** |
| 12 | |
| 13 | |
| 14 | ** |
| 15 | ===========================================================*/ |
| 16 | |
| 17 | #include "common.h" |
| 18 | |
| 19 | #include <shlwapi.h> |
| 20 | #include <stdlib.h> |
| 21 | #include "assemblynative.hpp" |
| 22 | #include "dllimport.h" |
| 23 | #include "field.h" |
| 24 | #include "assemblyname.hpp" |
| 25 | #include "eeconfig.h" |
| 26 | #include "strongname.h" |
| 27 | #include "interoputil.h" |
| 28 | #include "frames.h" |
| 29 | #include "typeparse.h" |
| 30 | #include "stackprobe.h" |
| 31 | |
| 32 | #include "appdomainnative.hpp" |
| 33 | #include "../binder/inc/clrprivbindercoreclr.h" |
| 34 | |
| 35 | |
| 36 | |
| 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) |
| 44 | { |
| 45 | FCALL_CONTRACT; |
| 46 | |
| 47 | struct _gc |
| 48 | { |
| 49 | ASSEMBLYNAMEREF assemblyName; |
| 50 | STRINGREF codeBase; |
| 51 | ASSEMBLYREF requestingAssembly; |
| 52 | ASSEMBLYREF rv; |
| 53 | } gc; |
| 54 | |
| 55 | gc.assemblyName = (ASSEMBLYNAMEREF) assemblyNameUNSAFE; |
| 56 | gc.codeBase = (STRINGREF) codeBaseUNSAFE; |
| 57 | gc.requestingAssembly = (ASSEMBLYREF) requestingAssemblyUNSAFE; |
| 58 | gc.rv = NULL; |
| 59 | |
| 60 | HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); |
| 61 | |
| 62 | if (gc.assemblyName == NULL) |
| 63 | COMPlusThrow(kArgumentNullException, W("ArgumentNull_AssemblyName" )); |
| 64 | |
| 65 | Thread * pThread = GetThread(); |
| 66 | CheckPointHolder cph(pThread->m_MarshalAlloc.GetCheckpoint()); //hold checkpoint for autorelease |
| 67 | |
| 68 | DomainAssembly * pParentAssembly = NULL; |
| 69 | Assembly * pRefAssembly = NULL; |
| 70 | |
| 71 | if(gc.assemblyName->GetSimpleName() == NULL) |
| 72 | { |
| 73 | if (gc.codeBase == NULL) |
| 74 | COMPlusThrow(kArgumentException, W("Format_StringZeroLength" )); |
| 75 | } |
| 76 | else |
| 77 | { |
| 78 | // Compute parent assembly |
| 79 | if (gc.requestingAssembly == NULL) |
| 80 | { |
| 81 | pRefAssembly = SystemDomain::GetCallersAssembly(stackMark); |
| 82 | } |
| 83 | else |
| 84 | { |
| 85 | pRefAssembly = gc.requestingAssembly->GetAssembly(); |
| 86 | } |
| 87 | |
| 88 | // Shared or collectible assemblies should not be used for the parent in the |
| 89 | // late-bound case. |
| 90 | if (pRefAssembly && (!pRefAssembly->IsCollectible())) |
| 91 | { |
| 92 | pParentAssembly= pRefAssembly->GetDomainAssembly(); |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | // Initialize spec |
| 97 | AssemblySpec spec; |
| 98 | spec.InitializeSpec(&(pThread->m_MarshalAlloc), |
| 99 | &gc.assemblyName, |
| 100 | FALSE); |
| 101 | |
| 102 | if (!spec.HasUniqueIdentity()) |
| 103 | { // Insuficient assembly name for binding (e.g. ContentType=WindowsRuntime cannot bind by assembly name) |
| 104 | EEFileLoadException::Throw(&spec, COR_E_NOTSUPPORTED); |
| 105 | } |
| 106 | |
| 107 | if (pPrivHostBinder != NULL) |
| 108 | { |
| 109 | pParentAssembly = NULL; |
| 110 | spec.SetHostBinder(pPrivHostBinder); |
| 111 | } |
| 112 | |
| 113 | if (gc.codeBase != NULL) |
| 114 | spec.SetCodeBase(&(pThread->m_MarshalAlloc), &gc.codeBase); |
| 115 | |
| 116 | if (pParentAssembly != NULL) |
| 117 | spec.SetParentAssembly(pParentAssembly); |
| 118 | |
| 119 | // Have we been passed the reference to the binder against which this load should be triggered? |
| 120 | // If so, then use it to set the fallback load context binder. |
| 121 | if (ptrLoadContextBinder != NULL) |
| 122 | { |
| 123 | spec.SetFallbackLoadContextBinderForRequestingAssembly(reinterpret_cast<ICLRPrivBinder *>(ptrLoadContextBinder)); |
| 124 | spec.SetPreferFallbackLoadContextBinder(); |
| 125 | } |
| 126 | else if (pRefAssembly != NULL) |
| 127 | { |
| 128 | // If the requesting assembly has Fallback LoadContext binder available, |
| 129 | // then set it up in the AssemblySpec. |
| 130 | PEFile *pRefAssemblyManifestFile = pRefAssembly->GetManifestFile(); |
| 131 | spec.SetFallbackLoadContextBinderForRequestingAssembly(pRefAssemblyManifestFile->GetFallbackLoadContextBinder()); |
| 132 | } |
| 133 | |
| 134 | Assembly *pAssembly; |
| 135 | |
| 136 | { |
| 137 | GCX_PREEMP(); |
| 138 | pAssembly = spec.LoadAssembly(FILE_LOADED, fThrowOnFileNotFound); |
| 139 | } |
| 140 | |
| 141 | if (pAssembly != NULL) |
| 142 | gc.rv = (ASSEMBLYREF) pAssembly->GetExposedObject(); |
| 143 | |
| 144 | HELPER_METHOD_FRAME_END(); |
| 145 | |
| 146 | return OBJECTREFToObject(gc.rv); |
| 147 | } |
| 148 | FCIMPLEND |
| 149 | |
| 150 | /* static */ |
| 151 | Assembly* AssemblyNative::LoadFromPEImage(ICLRPrivBinder* pBinderContext, PEImage *pILImage, PEImage *pNIImage) |
| 152 | { |
| 153 | CONTRACT(Assembly*) |
| 154 | { |
| 155 | STANDARD_VM_CHECK; |
| 156 | PRECONDITION(CheckPointer(pBinderContext)); |
| 157 | POSTCONDITION(CheckPointer(RETVAL)); |
| 158 | } |
| 159 | CONTRACT_END; |
| 160 | |
| 161 | Assembly *pLoadedAssembly = NULL; |
| 162 | |
| 163 | ReleaseHolder<ICLRPrivAssembly> pAssembly; |
| 164 | |
| 165 | // Get the correct PEImage to work with. |
| 166 | BOOL fIsNativeImage = TRUE; |
| 167 | PEImage *pImage = pNIImage; |
| 168 | if (pNIImage == NULL) |
| 169 | { |
| 170 | // Since we do not have a NI image, we are working with IL assembly |
| 171 | pImage = pILImage; |
| 172 | fIsNativeImage = FALSE; |
| 173 | } |
| 174 | _ASSERTE(pImage != NULL); |
| 175 | |
| 176 | BOOL fHadLoadFailure = FALSE; |
| 177 | |
| 178 | // Force the image to be loaded and mapped so that subsequent loads do not |
| 179 | // map a duplicate copy. |
| 180 | if (pImage->IsFile()) |
| 181 | { |
| 182 | pImage->Load(); |
| 183 | } |
| 184 | else |
| 185 | { |
| 186 | pImage->LoadNoFile(); |
| 187 | } |
| 188 | |
| 189 | DWORD dwMessageID = IDS_EE_FILELOAD_ERROR_GENERIC; |
| 190 | |
| 191 | // Set the caller's assembly to be mscorlib |
| 192 | DomainAssembly *pCallersAssembly = SystemDomain::System()->SystemAssembly()->GetDomainAssembly(); |
| 193 | PEAssembly *pParentAssembly = pCallersAssembly->GetFile(); |
| 194 | |
| 195 | // Initialize the AssemblySpec |
| 196 | AssemblySpec spec; |
| 197 | spec.InitializeSpec(TokenFromRid(1, mdtAssembly), pImage->GetMDImport(), pCallersAssembly); |
| 198 | spec.SetBindingContext(pBinderContext); |
| 199 | |
| 200 | HRESULT hr = S_OK; |
| 201 | PTR_AppDomain pCurDomain = GetAppDomain(); |
| 202 | CLRPrivBinderCoreCLR *pTPABinder = pCurDomain->GetTPABinderContext(); |
| 203 | if (!AreSameBinderInstance(pTPABinder, pBinderContext)) |
| 204 | { |
| 205 | // We are working with custom Assembly Load Context so bind the assembly using it. |
| 206 | CLRPrivBinderAssemblyLoadContext *pBinder = reinterpret_cast<CLRPrivBinderAssemblyLoadContext *>(pBinderContext); |
| 207 | hr = pBinder->BindUsingPEImage(pImage, fIsNativeImage, &pAssembly); |
| 208 | } |
| 209 | else |
| 210 | { |
| 211 | // Bind the assembly using TPA binder |
| 212 | hr = pTPABinder->BindUsingPEImage(pImage, fIsNativeImage, &pAssembly); |
| 213 | } |
| 214 | |
| 215 | if (hr != S_OK) |
| 216 | { |
| 217 | // Give a more specific message for the case when we found the assembly with the same name already loaded. |
| 218 | if (hr == COR_E_FILELOAD) |
| 219 | { |
| 220 | dwMessageID = IDS_HOST_ASSEMBLY_RESOLVER_ASSEMBLY_ALREADY_LOADED_IN_CONTEXT; |
| 221 | } |
| 222 | |
| 223 | StackSString name; |
| 224 | spec.GetFileOrDisplayName(0, name); |
| 225 | COMPlusThrowHR(COR_E_FILELOAD, dwMessageID, name); |
| 226 | } |
| 227 | |
| 228 | BINDER_SPACE::Assembly* assem; |
| 229 | assem = BINDER_SPACE::GetAssemblyFromPrivAssemblyFast(pAssembly); |
| 230 | |
| 231 | PEAssemblyHolder pPEAssembly(PEAssembly::Open(pParentAssembly, assem->GetPEImage(), assem->GetNativePEImage(), pAssembly)); |
| 232 | |
| 233 | DomainAssembly *pDomainAssembly = pCurDomain->LoadDomainAssembly(&spec, pPEAssembly, FILE_LOADED); |
| 234 | RETURN pDomainAssembly->GetAssembly(); |
| 235 | } |
| 236 | |
| 237 | /* static */ |
| 238 | void QCALLTYPE AssemblyNative::LoadFromPath(INT_PTR ptrNativeAssemblyLoadContext, LPCWSTR pwzILPath, LPCWSTR pwzNIPath, QCall::ObjectHandleOnStack retLoadedAssembly) |
| 239 | { |
| 240 | QCALL_CONTRACT; |
| 241 | |
| 242 | BEGIN_QCALL; |
| 243 | |
| 244 | PTR_AppDomain pCurDomain = GetAppDomain(); |
| 245 | |
| 246 | // Get the binder context in which the assembly will be loaded. |
| 247 | ICLRPrivBinder *pBinderContext = reinterpret_cast<ICLRPrivBinder*>(ptrNativeAssemblyLoadContext); |
| 248 | _ASSERTE(pBinderContext != NULL); |
| 249 | |
| 250 | // Form the PEImage for the ILAssembly. Incase of an exception, the holders will ensure |
| 251 | // the release of the image. |
| 252 | PEImageHolder pILImage, pNIImage; |
| 253 | |
| 254 | if (pwzILPath != NULL) |
| 255 | { |
| 256 | pILImage = PEImage::OpenImage(pwzILPath); |
| 257 | |
| 258 | // Need to verify that this is a valid CLR assembly. |
| 259 | if (!pILImage->CheckILFormat()) |
| 260 | ThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_IL); |
| 261 | } |
| 262 | |
| 263 | // Form the PEImage for the NI assembly, if specified |
| 264 | if (pwzNIPath != NULL) |
| 265 | { |
| 266 | pNIImage = PEImage::OpenImage(pwzNIPath, MDInternalImport_TrustedNativeImage); |
| 267 | |
| 268 | if (pNIImage->HasReadyToRunHeader()) |
| 269 | { |
| 270 | // ReadyToRun images are treated as IL images by the rest of the system |
| 271 | if (!pNIImage->CheckILFormat()) |
| 272 | ThrowHR(COR_E_BADIMAGEFORMAT); |
| 273 | |
| 274 | pILImage = pNIImage.Extract(); |
| 275 | pNIImage = NULL; |
| 276 | } |
| 277 | else |
| 278 | { |
| 279 | if (!pNIImage->CheckNativeFormat()) |
| 280 | ThrowHR(COR_E_BADIMAGEFORMAT); |
| 281 | } |
| 282 | } |
| 283 | |
| 284 | Assembly *pLoadedAssembly = AssemblyNative::LoadFromPEImage(pBinderContext, pILImage, pNIImage); |
| 285 | |
| 286 | { |
| 287 | GCX_COOP(); |
| 288 | retLoadedAssembly.Set(pLoadedAssembly->GetExposedObject()); |
| 289 | } |
| 290 | |
| 291 | LOG((LF_CLASSLOADER, |
| 292 | LL_INFO100, |
| 293 | "\tLoaded assembly from a file\n" )); |
| 294 | |
| 295 | END_QCALL; |
| 296 | } |
| 297 | |
| 298 | // static |
| 299 | INT_PTR QCALLTYPE AssemblyNative::InternalLoadUnmanagedDllFromPath(LPCWSTR unmanagedLibraryPath) |
| 300 | { |
| 301 | QCALL_CONTRACT; |
| 302 | |
| 303 | NATIVE_LIBRARY_HANDLE moduleHandle = nullptr; |
| 304 | |
| 305 | BEGIN_QCALL; |
| 306 | |
| 307 | moduleHandle = NDirect::LoadLibraryFromPath(unmanagedLibraryPath, true); |
| 308 | |
| 309 | END_QCALL; |
| 310 | |
| 311 | return reinterpret_cast<INT_PTR>(moduleHandle); |
| 312 | } |
| 313 | |
| 314 | /*static */ |
| 315 | void QCALLTYPE AssemblyNative::LoadFromStream(INT_PTR ptrNativeAssemblyLoadContext, INT_PTR ptrAssemblyArray, |
| 316 | INT32 cbAssemblyArrayLength, INT_PTR ptrSymbolArray, INT32 cbSymbolArrayLength, |
| 317 | QCall::ObjectHandleOnStack retLoadedAssembly) |
| 318 | { |
| 319 | QCALL_CONTRACT; |
| 320 | |
| 321 | BEGIN_QCALL; |
| 322 | |
| 323 | // Ensure that the invariants are in place |
| 324 | _ASSERTE(ptrNativeAssemblyLoadContext != NULL); |
| 325 | _ASSERTE((ptrAssemblyArray != NULL) && (cbAssemblyArrayLength > 0)); |
| 326 | _ASSERTE((ptrSymbolArray == NULL) || (cbSymbolArrayLength > 0)); |
| 327 | |
| 328 | // We must have a flat image stashed away since we need a private |
| 329 | // copy of the data which we can verify before doing the mapping. |
| 330 | PVOID pAssemblyArray = reinterpret_cast<PVOID>(ptrAssemblyArray); |
| 331 | |
| 332 | PEImageHolder pILImage(PEImage::LoadFlat(pAssemblyArray, (COUNT_T)cbAssemblyArrayLength)); |
| 333 | |
| 334 | // Need to verify that this is a valid CLR assembly. |
| 335 | if (!pILImage->CheckILFormat()) |
| 336 | ThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_IL); |
| 337 | |
| 338 | // Get the binder context in which the assembly will be loaded |
| 339 | ICLRPrivBinder *pBinderContext = reinterpret_cast<ICLRPrivBinder*>(ptrNativeAssemblyLoadContext); |
| 340 | |
| 341 | // Pass the stream based assembly as IL and NI in an attempt to bind and load it |
| 342 | Assembly* pLoadedAssembly = AssemblyNative::LoadFromPEImage(pBinderContext, pILImage, NULL); |
| 343 | { |
| 344 | GCX_COOP(); |
| 345 | retLoadedAssembly.Set(pLoadedAssembly->GetExposedObject()); |
| 346 | } |
| 347 | |
| 348 | LOG((LF_CLASSLOADER, |
| 349 | LL_INFO100, |
| 350 | "\tLoaded assembly from a file\n" )); |
| 351 | |
| 352 | // In order to assign the PDB image (if present), |
| 353 | // the resulting assembly's image needs to be exactly the one |
| 354 | // we created above. We need pointer comparison instead of pe image equivalence |
| 355 | // to avoid mixed binaries/PDB pairs of other images. |
| 356 | // This applies to both Desktop CLR and CoreCLR, with or without fusion. |
| 357 | BOOL fIsSameAssembly = (pLoadedAssembly->GetManifestFile()->GetILimage() == pILImage); |
| 358 | |
| 359 | // Setting the PDB info is only applicable for our original assembly. |
| 360 | // This applies to both Desktop CLR and CoreCLR, with or without fusion. |
| 361 | if (fIsSameAssembly) |
| 362 | { |
| 363 | #ifdef DEBUGGING_SUPPORTED |
| 364 | // If we were given symbols, save a copy of them. |
| 365 | if (ptrSymbolArray != NULL) |
| 366 | { |
| 367 | PBYTE pSymbolArray = reinterpret_cast<PBYTE>(ptrSymbolArray); |
| 368 | pLoadedAssembly->GetManifestModule()->SetSymbolBytes(pSymbolArray, (DWORD)cbSymbolArrayLength); |
| 369 | } |
| 370 | #endif // DEBUGGING_SUPPORTED |
| 371 | } |
| 372 | |
| 373 | END_QCALL; |
| 374 | } |
| 375 | |
| 376 | void QCALLTYPE AssemblyNative::GetLocation(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack retString) |
| 377 | { |
| 378 | QCALL_CONTRACT; |
| 379 | |
| 380 | BEGIN_QCALL; |
| 381 | |
| 382 | { |
| 383 | retString.Set(pAssembly->GetFile()->GetPath()); |
| 384 | } |
| 385 | |
| 386 | END_QCALL; |
| 387 | } |
| 388 | |
| 389 | void QCALLTYPE AssemblyNative::GetType(QCall::AssemblyHandle pAssembly, LPCWSTR wszName, BOOL bThrowOnError, BOOL bIgnoreCase, QCall::ObjectHandleOnStack retType, QCall::ObjectHandleOnStack keepAlive) |
| 390 | { |
| 391 | CONTRACTL |
| 392 | { |
| 393 | QCALL_CHECK; |
| 394 | PRECONDITION(CheckPointer(wszName)); |
| 395 | } |
| 396 | CONTRACTL_END; |
| 397 | |
| 398 | TypeHandle retTypeHandle; |
| 399 | |
| 400 | BEGIN_QCALL; |
| 401 | |
| 402 | if (!wszName) |
| 403 | COMPlusThrowArgumentNull(W("name" ), W("ArgumentNull_String" )); |
| 404 | |
| 405 | BOOL prohibitAsmQualifiedName = TRUE; |
| 406 | |
| 407 | // Load the class from this assembly (fail if it is in a different one). |
| 408 | retTypeHandle = TypeName::GetTypeManaged(wszName, pAssembly, bThrowOnError, bIgnoreCase, prohibitAsmQualifiedName, NULL, FALSE, (OBJECTREF*)keepAlive.m_ppObject); |
| 409 | |
| 410 | if (!retTypeHandle.IsNull()) |
| 411 | { |
| 412 | GCX_COOP(); |
| 413 | retType.Set(retTypeHandle.GetManagedClassObject()); |
| 414 | } |
| 415 | |
| 416 | END_QCALL; |
| 417 | |
| 418 | return; |
| 419 | } |
| 420 | |
| 421 | void QCALLTYPE AssemblyNative::GetForwardedType(QCall::AssemblyHandle pAssembly, mdToken mdtExternalType, QCall::ObjectHandleOnStack retType) |
| 422 | { |
| 423 | CONTRACTL |
| 424 | { |
| 425 | QCALL_CHECK; |
| 426 | } |
| 427 | CONTRACTL_END; |
| 428 | |
| 429 | BEGIN_QCALL; |
| 430 | |
| 431 | LPCSTR pszNameSpace; |
| 432 | LPCSTR pszClassName; |
| 433 | mdToken mdImpl; |
| 434 | |
| 435 | Assembly * pAsm = pAssembly->GetAssembly(); |
| 436 | Module *pManifestModule = pAsm->GetManifestModule(); |
| 437 | IfFailThrow(pManifestModule->GetMDImport()->GetExportedTypeProps(mdtExternalType, &pszNameSpace, &pszClassName, &mdImpl, NULL, NULL)); |
| 438 | if (TypeFromToken(mdImpl) == mdtAssemblyRef) |
| 439 | { |
| 440 | NameHandle typeName(pszNameSpace, pszClassName); |
| 441 | typeName.SetTypeToken(pManifestModule, mdtExternalType); |
| 442 | TypeHandle typeHnd = pAsm->GetLoader()->LoadTypeHandleThrowIfFailed(&typeName); |
| 443 | { |
| 444 | GCX_COOP(); |
| 445 | retType.Set(typeHnd.GetManagedClassObject()); |
| 446 | } |
| 447 | } |
| 448 | |
| 449 | END_QCALL; |
| 450 | |
| 451 | return; |
| 452 | } |
| 453 | |
| 454 | FCIMPL1(FC_BOOL_RET, AssemblyNative::IsDynamic, AssemblyBaseObject* pAssemblyUNSAFE) |
| 455 | { |
| 456 | FCALL_CONTRACT; |
| 457 | |
| 458 | ASSEMBLYREF refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE); |
| 459 | |
| 460 | if (refAssembly == NULL) |
| 461 | FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle" )); |
| 462 | |
| 463 | FC_RETURN_BOOL(refAssembly->GetDomainAssembly()->GetFile()->IsDynamic()); |
| 464 | } |
| 465 | FCIMPLEND |
| 466 | |
| 467 | void QCALLTYPE AssemblyNative::GetVersion(QCall::AssemblyHandle pAssembly, INT32* pMajorVersion, INT32* pMinorVersion, INT32*pBuildNumber, INT32* pRevisionNumber) |
| 468 | { |
| 469 | QCALL_CONTRACT; |
| 470 | |
| 471 | BEGIN_QCALL; |
| 472 | |
| 473 | UINT16 major=0xffff, minor=0xffff, build=0xffff, revision=0xffff; |
| 474 | |
| 475 | pAssembly->GetFile()->GetVersion(&major, &minor, &build, &revision); |
| 476 | |
| 477 | *pMajorVersion = major; |
| 478 | *pMinorVersion = minor; |
| 479 | *pBuildNumber = build; |
| 480 | *pRevisionNumber = revision; |
| 481 | |
| 482 | END_QCALL; |
| 483 | } |
| 484 | |
| 485 | void QCALLTYPE AssemblyNative::GetPublicKey(QCall::AssemblyHandle pAssembly, QCall::ObjectHandleOnStack retPublicKey) |
| 486 | { |
| 487 | QCALL_CONTRACT; |
| 488 | |
| 489 | BEGIN_QCALL; |
| 490 | |
| 491 | DWORD cbPublicKey = 0; |
| 492 | const void *pbPublicKey = pAssembly->GetFile()->GetPublicKey(&cbPublicKey); |
| 493 | retPublicKey.SetByteArray((BYTE *)pbPublicKey, cbPublicKey); |
| 494 | |
| 495 | END_QCALL; |
| 496 | } |
| 497 | |
| 498 | void QCALLTYPE AssemblyNative::GetSimpleName(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack retSimpleName) |
| 499 | { |
| 500 | QCALL_CONTRACT; |
| 501 | |
| 502 | BEGIN_QCALL; |
| 503 | retSimpleName.Set(pAssembly->GetSimpleName()); |
| 504 | END_QCALL; |
| 505 | } |
| 506 | |
| 507 | void QCALLTYPE AssemblyNative::GetLocale(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack retString) |
| 508 | { |
| 509 | QCALL_CONTRACT; |
| 510 | |
| 511 | BEGIN_QCALL; |
| 512 | |
| 513 | LPCUTF8 pLocale = pAssembly->GetFile()->GetLocale(); |
| 514 | if(pLocale) |
| 515 | { |
| 516 | retString.Set(pLocale); |
| 517 | } |
| 518 | |
| 519 | END_QCALL; |
| 520 | } |
| 521 | |
| 522 | void QCALLTYPE AssemblyNative::GetCodeBase(QCall::AssemblyHandle pAssembly, BOOL fCopiedName, QCall::StringHandleOnStack retString) |
| 523 | { |
| 524 | QCALL_CONTRACT; |
| 525 | |
| 526 | BEGIN_QCALL; |
| 527 | |
| 528 | StackSString codebase; |
| 529 | |
| 530 | { |
| 531 | pAssembly->GetFile()->GetCodeBase(codebase); |
| 532 | } |
| 533 | |
| 534 | retString.Set(codebase); |
| 535 | |
| 536 | END_QCALL; |
| 537 | } |
| 538 | |
| 539 | INT32 QCALLTYPE AssemblyNative::GetHashAlgorithm(QCall::AssemblyHandle pAssembly) |
| 540 | { |
| 541 | QCALL_CONTRACT; |
| 542 | |
| 543 | INT32 retVal=0; |
| 544 | BEGIN_QCALL; |
| 545 | retVal = pAssembly->GetFile()->GetHashAlgId(); |
| 546 | END_QCALL; |
| 547 | return retVal; |
| 548 | } |
| 549 | |
| 550 | INT32 QCALLTYPE AssemblyNative::GetFlags(QCall::AssemblyHandle pAssembly) |
| 551 | { |
| 552 | QCALL_CONTRACT; |
| 553 | |
| 554 | INT32 retVal=0; |
| 555 | BEGIN_QCALL; |
| 556 | retVal = pAssembly->GetFile()->GetFlags(); |
| 557 | END_QCALL; |
| 558 | return retVal; |
| 559 | } |
| 560 | |
| 561 | BYTE * QCALLTYPE AssemblyNative::GetResource(QCall::AssemblyHandle pAssembly, LPCWSTR wszName, DWORD * length) |
| 562 | { |
| 563 | QCALL_CONTRACT; |
| 564 | |
| 565 | PBYTE pbInMemoryResource = NULL; |
| 566 | |
| 567 | BEGIN_QCALL; |
| 568 | |
| 569 | if (wszName == NULL) |
| 570 | COMPlusThrow(kArgumentNullException, W("ArgumentNull_String" )); |
| 571 | |
| 572 | // Get the name in UTF8 |
| 573 | SString name(SString::Literal, wszName); |
| 574 | |
| 575 | StackScratchBuffer scratch; |
| 576 | LPCUTF8 pNameUTF8 = name.GetUTF8(scratch); |
| 577 | |
| 578 | if (*pNameUTF8 == '\0') |
| 579 | COMPlusThrow(kArgumentException, W("Format_StringZeroLength" )); |
| 580 | |
| 581 | pAssembly->GetResource(pNameUTF8, length, |
| 582 | &pbInMemoryResource, NULL, NULL, |
| 583 | NULL, FALSE); |
| 584 | |
| 585 | END_QCALL; |
| 586 | |
| 587 | // Can return null if resource file is zero-length |
| 588 | return pbInMemoryResource; |
| 589 | } |
| 590 | |
| 591 | INT32 QCALLTYPE AssemblyNative::GetManifestResourceInfo(QCall::AssemblyHandle pAssembly, LPCWSTR wszName, QCall::ObjectHandleOnStack retAssembly, QCall::StringHandleOnStack retFileName) |
| 592 | { |
| 593 | QCALL_CONTRACT; |
| 594 | |
| 595 | INT32 rv = -1; |
| 596 | |
| 597 | BEGIN_QCALL; |
| 598 | |
| 599 | if (wszName == NULL) |
| 600 | COMPlusThrow(kArgumentNullException, W("ArgumentNull_String" )); |
| 601 | |
| 602 | // Get the name in UTF8 |
| 603 | SString name(SString::Literal, wszName); |
| 604 | |
| 605 | StackScratchBuffer scratch; |
| 606 | LPCUTF8 pNameUTF8 = name.GetUTF8(scratch); |
| 607 | |
| 608 | if (*pNameUTF8 == '\0') |
| 609 | COMPlusThrow(kArgumentException, W("Format_StringZeroLength" )); |
| 610 | |
| 611 | DomainAssembly * pReferencedAssembly = NULL; |
| 612 | LPCSTR pFileName = NULL; |
| 613 | DWORD dwLocation = 0; |
| 614 | |
| 615 | if (pAssembly->GetResource(pNameUTF8, NULL, NULL, &pReferencedAssembly, &pFileName, |
| 616 | &dwLocation, FALSE)) |
| 617 | { |
| 618 | if (pFileName) |
| 619 | retFileName.Set(pFileName); |
| 620 | |
| 621 | GCX_COOP(); |
| 622 | |
| 623 | if (pReferencedAssembly) |
| 624 | retAssembly.Set(pReferencedAssembly->GetExposedAssemblyObject()); |
| 625 | |
| 626 | rv = dwLocation; |
| 627 | } |
| 628 | |
| 629 | END_QCALL; |
| 630 | |
| 631 | return rv; |
| 632 | } |
| 633 | |
| 634 | void QCALLTYPE AssemblyNative::GetModules(QCall::AssemblyHandle pAssembly, BOOL fLoadIfNotFound, BOOL fGetResourceModules, QCall::ObjectHandleOnStack retModules) |
| 635 | { |
| 636 | QCALL_CONTRACT; |
| 637 | |
| 638 | BEGIN_QCALL; |
| 639 | |
| 640 | HENUMInternalHolder phEnum(pAssembly->GetMDImport()); |
| 641 | phEnum.EnumInit(mdtFile, mdTokenNil); |
| 642 | |
| 643 | InlineSArray<DomainFile *, 8> modules; |
| 644 | |
| 645 | modules.Append(pAssembly); |
| 646 | |
| 647 | mdFile mdFile; |
| 648 | while (pAssembly->GetMDImport()->EnumNext(&phEnum, &mdFile)) |
| 649 | { |
| 650 | DomainFile *pModule = pAssembly->GetModule()->LoadModule(GetAppDomain(), mdFile, fGetResourceModules, !fLoadIfNotFound); |
| 651 | |
| 652 | if (pModule) { |
| 653 | modules.Append(pModule); |
| 654 | } |
| 655 | } |
| 656 | |
| 657 | { |
| 658 | GCX_COOP(); |
| 659 | |
| 660 | PTRARRAYREF orModules = NULL; |
| 661 | |
| 662 | GCPROTECT_BEGIN(orModules); |
| 663 | |
| 664 | // Return the modules |
| 665 | orModules = (PTRARRAYREF)AllocateObjectArray(modules.GetCount(), MscorlibBinder::GetClass(CLASS__MODULE)); |
| 666 | |
| 667 | for(COUNT_T i = 0; i < modules.GetCount(); i++) |
| 668 | { |
| 669 | DomainFile * pModule = modules[i]; |
| 670 | |
| 671 | OBJECTREF o = pModule->GetExposedModuleObject(); |
| 672 | orModules->SetAt(i, o); |
| 673 | } |
| 674 | |
| 675 | retModules.Set(orModules); |
| 676 | |
| 677 | GCPROTECT_END(); |
| 678 | } |
| 679 | |
| 680 | END_QCALL; |
| 681 | } |
| 682 | |
| 683 | BOOL QCALLTYPE AssemblyNative::GetNeutralResourcesLanguageAttribute(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack cultureName, INT16& outFallbackLocation) |
| 684 | { |
| 685 | CONTRACTL { |
| 686 | QCALL_CHECK; |
| 687 | } CONTRACTL_END; |
| 688 | |
| 689 | BOOL retVal = FALSE; |
| 690 | BEGIN_QCALL; |
| 691 | |
| 692 | _ASSERTE(pAssembly); |
| 693 | Assembly * pAsm = pAssembly->GetAssembly(); |
| 694 | _ASSERTE(pAsm); |
| 695 | Module * pModule = pAsm->GetManifestModule(); |
| 696 | _ASSERTE(pModule); |
| 697 | |
| 698 | LPCUTF8 pszCultureName = NULL; |
| 699 | ULONG cultureNameLength = 0; |
| 700 | INT16 fallbackLocation = 0; |
| 701 | |
| 702 | // find the attribute if it exists |
| 703 | if (pModule->GetNeutralResourcesLanguage(&pszCultureName, &cultureNameLength, &fallbackLocation, FALSE)) { |
| 704 | StackSString culture(SString::Utf8, pszCultureName, cultureNameLength); |
| 705 | cultureName.Set(culture); |
| 706 | outFallbackLocation = fallbackLocation; |
| 707 | retVal = TRUE; |
| 708 | } |
| 709 | |
| 710 | END_QCALL; |
| 711 | |
| 712 | return retVal; |
| 713 | } |
| 714 | |
| 715 | BOOL QCALLTYPE AssemblyNative::GetIsCollectible(QCall::AssemblyHandle pAssembly) |
| 716 | { |
| 717 | QCALL_CONTRACT; |
| 718 | |
| 719 | BOOL retVal = FALSE; |
| 720 | |
| 721 | BEGIN_QCALL; |
| 722 | |
| 723 | retVal = pAssembly->IsCollectible(); |
| 724 | |
| 725 | END_QCALL; |
| 726 | |
| 727 | return retVal; |
| 728 | } |
| 729 | |
| 730 | void QCALLTYPE AssemblyNative::GetModule(QCall::AssemblyHandle pAssembly, LPCWSTR wszFileName, QCall::ObjectHandleOnStack retModule) |
| 731 | { |
| 732 | QCALL_CONTRACT; |
| 733 | |
| 734 | BEGIN_QCALL; |
| 735 | |
| 736 | Module * pModule = NULL; |
| 737 | |
| 738 | CQuickBytes qbLC; |
| 739 | |
| 740 | if (wszFileName == NULL) |
| 741 | COMPlusThrow(kArgumentNullException, W("ArgumentNull_FileName" )); |
| 742 | if (wszFileName[0] == W('\0')) |
| 743 | COMPlusThrow(kArgumentException, W("Argument_EmptyFileName" )); |
| 744 | |
| 745 | |
| 746 | MAKE_UTF8PTR_FROMWIDE(szModuleName, wszFileName); |
| 747 | |
| 748 | |
| 749 | LPCUTF8 pModuleName = NULL; |
| 750 | |
| 751 | if SUCCEEDED(pAssembly->GetDomainAssembly()->GetModule()->GetScopeName(&pModuleName)) |
| 752 | { |
| 753 | if (::SString::_stricmp(pModuleName, szModuleName) == 0) |
| 754 | pModule = pAssembly->GetDomainAssembly()->GetModule(); |
| 755 | } |
| 756 | |
| 757 | |
| 758 | if (pModule != NULL) |
| 759 | { |
| 760 | GCX_COOP(); |
| 761 | retModule.Set(pModule->GetExposedObject()); |
| 762 | } |
| 763 | |
| 764 | END_QCALL; |
| 765 | |
| 766 | return; |
| 767 | } |
| 768 | |
| 769 | void QCALLTYPE AssemblyNative::GetExportedTypes(QCall::AssemblyHandle pAssembly, QCall::ObjectHandleOnStack retTypes) |
| 770 | { |
| 771 | QCALL_CONTRACT; |
| 772 | |
| 773 | BEGIN_QCALL; |
| 774 | |
| 775 | InlineSArray<TypeHandle, 20> types; |
| 776 | |
| 777 | Assembly * pAsm = pAssembly->GetAssembly(); |
| 778 | |
| 779 | IMDInternalImport *pImport = pAsm->GetManifestImport(); |
| 780 | |
| 781 | { |
| 782 | HENUMTypeDefInternalHolder phTDEnum(pImport); |
| 783 | phTDEnum.EnumTypeDefInit(); |
| 784 | |
| 785 | mdTypeDef mdTD; |
| 786 | while(pImport->EnumNext(&phTDEnum, &mdTD)) |
| 787 | { |
| 788 | DWORD dwFlags; |
| 789 | IfFailThrow(pImport->GetTypeDefProps( |
| 790 | mdTD, |
| 791 | &dwFlags, |
| 792 | NULL)); |
| 793 | |
| 794 | // nested type |
| 795 | mdTypeDef mdEncloser = mdTD; |
| 796 | while (SUCCEEDED(pImport->GetNestedClassProps(mdEncloser, &mdEncloser)) && |
| 797 | IsTdNestedPublic(dwFlags)) |
| 798 | { |
| 799 | IfFailThrow(pImport->GetTypeDefProps( |
| 800 | mdEncloser, |
| 801 | &dwFlags, |
| 802 | NULL)); |
| 803 | } |
| 804 | |
| 805 | if (IsTdPublic(dwFlags)) |
| 806 | { |
| 807 | TypeHandle typeHnd = ClassLoader::LoadTypeDefThrowing(pAsm->GetManifestModule(), mdTD, |
| 808 | ClassLoader::ThrowIfNotFound, |
| 809 | ClassLoader::PermitUninstDefOrRef); |
| 810 | types.Append(typeHnd); |
| 811 | } |
| 812 | } |
| 813 | } |
| 814 | |
| 815 | { |
| 816 | HENUMInternalHolder phCTEnum(pImport); |
| 817 | phCTEnum.EnumInit(mdtExportedType, mdTokenNil); |
| 818 | |
| 819 | // Now get the ExportedTypes that don't have TD's in the manifest file |
| 820 | mdExportedType mdCT; |
| 821 | while(pImport->EnumNext(&phCTEnum, &mdCT)) |
| 822 | { |
| 823 | mdToken mdImpl; |
| 824 | LPCSTR pszNameSpace; |
| 825 | LPCSTR pszClassName; |
| 826 | DWORD dwFlags; |
| 827 | |
| 828 | IfFailThrow(pImport->GetExportedTypeProps( |
| 829 | mdCT, |
| 830 | &pszNameSpace, |
| 831 | &pszClassName, |
| 832 | &mdImpl, |
| 833 | NULL, //binding |
| 834 | &dwFlags)); |
| 835 | |
| 836 | // nested type |
| 837 | while ((TypeFromToken(mdImpl) == mdtExportedType) && |
| 838 | (mdImpl != mdExportedTypeNil) && |
| 839 | IsTdNestedPublic(dwFlags)) |
| 840 | { |
| 841 | IfFailThrow(pImport->GetExportedTypeProps( |
| 842 | mdImpl, |
| 843 | NULL, //namespace |
| 844 | NULL, //name |
| 845 | &mdImpl, |
| 846 | NULL, //binding |
| 847 | &dwFlags)); |
| 848 | } |
| 849 | |
| 850 | if ((TypeFromToken(mdImpl) == mdtFile) && |
| 851 | (mdImpl != mdFileNil) && |
| 852 | IsTdPublic(dwFlags)) |
| 853 | { |
| 854 | NameHandle typeName(pszNameSpace, pszClassName); |
| 855 | typeName.SetTypeToken(pAsm->GetManifestModule(), mdCT); |
| 856 | TypeHandle typeHnd = pAsm->GetLoader()->LoadTypeHandleThrowIfFailed(&typeName); |
| 857 | |
| 858 | types.Append(typeHnd); |
| 859 | } |
| 860 | } |
| 861 | } |
| 862 | |
| 863 | { |
| 864 | GCX_COOP(); |
| 865 | |
| 866 | PTRARRAYREF orTypes = NULL; |
| 867 | |
| 868 | GCPROTECT_BEGIN(orTypes); |
| 869 | |
| 870 | // Return the types |
| 871 | orTypes = (PTRARRAYREF)AllocateObjectArray(types.GetCount(), MscorlibBinder::GetClass(CLASS__TYPE)); |
| 872 | |
| 873 | for(COUNT_T i = 0; i < types.GetCount(); i++) |
| 874 | { |
| 875 | TypeHandle typeHnd = types[i]; |
| 876 | |
| 877 | OBJECTREF o = typeHnd.GetManagedClassObject(); |
| 878 | orTypes->SetAt(i, o); |
| 879 | } |
| 880 | |
| 881 | retTypes.Set(orTypes); |
| 882 | |
| 883 | GCPROTECT_END(); |
| 884 | } |
| 885 | |
| 886 | END_QCALL; |
| 887 | } |
| 888 | |
| 889 | void QCALLTYPE AssemblyNative::GetForwardedTypes(QCall::AssemblyHandle pAssembly, QCall::ObjectHandleOnStack retTypes) |
| 890 | { |
| 891 | QCALL_CONTRACT; |
| 892 | |
| 893 | BEGIN_QCALL; |
| 894 | |
| 895 | InlineSArray<TypeHandle, 8> types; |
| 896 | |
| 897 | Assembly * pAsm = pAssembly->GetAssembly(); |
| 898 | |
| 899 | IMDInternalImport *pImport = pAsm->GetManifestImport(); |
| 900 | |
| 901 | // enumerate the ExportedTypes table |
| 902 | { |
| 903 | HENUMInternalHolder phCTEnum(pImport); |
| 904 | phCTEnum.EnumInit(mdtExportedType, mdTokenNil); |
| 905 | |
| 906 | // Now get the ExportedTypes that don't have TD's in the manifest file |
| 907 | mdExportedType mdCT; |
| 908 | while(pImport->EnumNext(&phCTEnum, &mdCT)) |
| 909 | { |
| 910 | mdToken mdImpl; |
| 911 | LPCSTR pszNameSpace; |
| 912 | LPCSTR pszClassName; |
| 913 | DWORD dwFlags; |
| 914 | |
| 915 | IfFailThrow(pImport->GetExportedTypeProps(mdCT, |
| 916 | &pszNameSpace, |
| 917 | &pszClassName, |
| 918 | &mdImpl, |
| 919 | NULL, //binding |
| 920 | &dwFlags)); |
| 921 | |
| 922 | if ((TypeFromToken(mdImpl) == mdtAssemblyRef) && (mdImpl != mdAssemblyRefNil)) |
| 923 | { |
| 924 | NameHandle typeName(pszNameSpace, pszClassName); |
| 925 | typeName.SetTypeToken(pAsm->GetManifestModule(), mdCT); |
| 926 | TypeHandle typeHnd = pAsm->GetLoader()->LoadTypeHandleThrowIfFailed(&typeName); |
| 927 | |
| 928 | types.Append(typeHnd); |
| 929 | } |
| 930 | } |
| 931 | } |
| 932 | |
| 933 | // Populate retTypes |
| 934 | { |
| 935 | GCX_COOP(); |
| 936 | |
| 937 | PTRARRAYREF orTypes = NULL; |
| 938 | |
| 939 | GCPROTECT_BEGIN(orTypes); |
| 940 | |
| 941 | // Return the types |
| 942 | orTypes = (PTRARRAYREF)AllocateObjectArray(types.GetCount(), MscorlibBinder::GetClass(CLASS__TYPE)); |
| 943 | |
| 944 | for(COUNT_T i = 0; i < types.GetCount(); i++) |
| 945 | { |
| 946 | TypeHandle typeHnd = types[i]; |
| 947 | |
| 948 | OBJECTREF o = typeHnd.GetManagedClassObject(); |
| 949 | orTypes->SetAt(i, o); |
| 950 | } |
| 951 | |
| 952 | retTypes.Set(orTypes); |
| 953 | |
| 954 | GCPROTECT_END(); |
| 955 | } |
| 956 | |
| 957 | END_QCALL; |
| 958 | } |
| 959 | |
| 960 | FCIMPL1(Object*, AssemblyNative::GetManifestResourceNames, AssemblyBaseObject * pAssemblyUNSAFE) |
| 961 | { |
| 962 | FCALL_CONTRACT; |
| 963 | |
| 964 | ASSEMBLYREF refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE); |
| 965 | |
| 966 | if (refAssembly == NULL) |
| 967 | FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle" )); |
| 968 | |
| 969 | DomainAssembly *pAssembly = refAssembly->GetDomainAssembly(); |
| 970 | PTRARRAYREF rv = NULL; |
| 971 | |
| 972 | HELPER_METHOD_FRAME_BEGIN_RET_2(rv, refAssembly); |
| 973 | |
| 974 | IMDInternalImport *pImport = pAssembly->GetMDImport(); |
| 975 | |
| 976 | HENUMInternalHolder phEnum(pImport); |
| 977 | DWORD dwCount; |
| 978 | |
| 979 | phEnum.EnumInit(mdtManifestResource, mdTokenNil); |
| 980 | dwCount = pImport->EnumGetCount(&phEnum); |
| 981 | |
| 982 | PTRARRAYREF ItemArray = (PTRARRAYREF) AllocateObjectArray(dwCount, g_pStringClass); |
| 983 | |
| 984 | mdManifestResource mdResource; |
| 985 | |
| 986 | GCPROTECT_BEGIN(ItemArray); |
| 987 | for(DWORD i = 0; i < dwCount; i++) { |
| 988 | pImport->EnumNext(&phEnum, &mdResource); |
| 989 | LPCSTR pszName = NULL; |
| 990 | |
| 991 | IfFailThrow(pImport->GetManifestResourceProps( |
| 992 | mdResource, |
| 993 | &pszName, // name |
| 994 | NULL, // linkref |
| 995 | NULL, // offset |
| 996 | NULL)); //flags |
| 997 | |
| 998 | OBJECTREF o = (OBJECTREF) StringObject::NewString(pszName); |
| 999 | ItemArray->SetAt(i, o); |
| 1000 | } |
| 1001 | |
| 1002 | rv = ItemArray; |
| 1003 | GCPROTECT_END(); |
| 1004 | |
| 1005 | HELPER_METHOD_FRAME_END(); |
| 1006 | |
| 1007 | return OBJECTREFToObject(rv); |
| 1008 | } |
| 1009 | FCIMPLEND |
| 1010 | |
| 1011 | FCIMPL1(Object*, AssemblyNative::GetReferencedAssemblies, AssemblyBaseObject * pAssemblyUNSAFE) |
| 1012 | { |
| 1013 | FCALL_CONTRACT; |
| 1014 | |
| 1015 | struct _gc { |
| 1016 | PTRARRAYREF ItemArray; |
| 1017 | ASSEMBLYNAMEREF pObj; |
| 1018 | ASSEMBLYREF refAssembly; |
| 1019 | } gc; |
| 1020 | ZeroMemory(&gc, sizeof(gc)); |
| 1021 | |
| 1022 | gc.refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE); |
| 1023 | |
| 1024 | if (gc.refAssembly == NULL) |
| 1025 | FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle" )); |
| 1026 | |
| 1027 | DomainAssembly *pAssembly = gc.refAssembly->GetDomainAssembly(); |
| 1028 | |
| 1029 | HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); |
| 1030 | |
| 1031 | IMDInternalImport *pImport = pAssembly->GetAssembly()->GetManifestImport(); |
| 1032 | |
| 1033 | MethodTable* pAsmNameClass = MscorlibBinder::GetClass(CLASS__ASSEMBLY_NAME); |
| 1034 | |
| 1035 | HENUMInternalHolder phEnum(pImport); |
| 1036 | DWORD dwCount = 0; |
| 1037 | |
| 1038 | phEnum.EnumInit(mdtAssemblyRef, mdTokenNil); |
| 1039 | |
| 1040 | dwCount = pImport->EnumGetCount(&phEnum); |
| 1041 | |
| 1042 | mdAssemblyRef mdAssemblyRef; |
| 1043 | |
| 1044 | gc.ItemArray = (PTRARRAYREF) AllocateObjectArray(dwCount, pAsmNameClass); |
| 1045 | |
| 1046 | for(DWORD i = 0; i < dwCount; i++) |
| 1047 | { |
| 1048 | pImport->EnumNext(&phEnum, &mdAssemblyRef); |
| 1049 | |
| 1050 | AssemblySpec spec; |
| 1051 | spec.InitializeSpec(mdAssemblyRef, pImport); |
| 1052 | |
| 1053 | gc.pObj = (ASSEMBLYNAMEREF) AllocateObject(pAsmNameClass); |
| 1054 | spec.AssemblyNameInit(&gc.pObj,NULL); |
| 1055 | |
| 1056 | gc.ItemArray->SetAt(i, (OBJECTREF) gc.pObj); |
| 1057 | } |
| 1058 | |
| 1059 | HELPER_METHOD_FRAME_END(); |
| 1060 | |
| 1061 | return OBJECTREFToObject(gc.ItemArray); |
| 1062 | } |
| 1063 | FCIMPLEND |
| 1064 | |
| 1065 | void QCALLTYPE AssemblyNative::GetEntryPoint(QCall::AssemblyHandle pAssembly, QCall::ObjectHandleOnStack retMethod) |
| 1066 | { |
| 1067 | QCALL_CONTRACT; |
| 1068 | |
| 1069 | MethodDesc* pMeth = NULL; |
| 1070 | |
| 1071 | BEGIN_QCALL; |
| 1072 | |
| 1073 | pMeth = pAssembly->GetAssembly()->GetEntryPoint(); |
| 1074 | if (pMeth != NULL) |
| 1075 | { |
| 1076 | GCX_COOP(); |
| 1077 | retMethod.Set(pMeth->GetStubMethodInfo()); |
| 1078 | } |
| 1079 | |
| 1080 | END_QCALL; |
| 1081 | |
| 1082 | return; |
| 1083 | } |
| 1084 | |
| 1085 | //--------------------------------------------------------------------------------------- |
| 1086 | // |
| 1087 | // Release QCALL for System.SafePEFileHandle |
| 1088 | // |
| 1089 | // |
| 1090 | |
| 1091 | void QCALLTYPE AssemblyNative::GetFullName(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack retString) |
| 1092 | { |
| 1093 | QCALL_CONTRACT; |
| 1094 | |
| 1095 | BEGIN_QCALL; |
| 1096 | |
| 1097 | StackSString name; |
| 1098 | pAssembly->GetFile()->GetDisplayName(name); |
| 1099 | retString.Set(name); |
| 1100 | |
| 1101 | END_QCALL; |
| 1102 | } |
| 1103 | |
| 1104 | void QCALLTYPE AssemblyNative::GetExecutingAssembly(QCall::StackCrawlMarkHandle stackMark, QCall::ObjectHandleOnStack retAssembly) |
| 1105 | { |
| 1106 | QCALL_CONTRACT; |
| 1107 | |
| 1108 | DomainAssembly * pExecutingAssembly = NULL; |
| 1109 | |
| 1110 | BEGIN_QCALL; |
| 1111 | |
| 1112 | Assembly* pAssembly = SystemDomain::GetCallersAssembly(stackMark); |
| 1113 | if(pAssembly) |
| 1114 | { |
| 1115 | pExecutingAssembly = pAssembly->GetDomainAssembly(); |
| 1116 | GCX_COOP(); |
| 1117 | retAssembly.Set(pExecutingAssembly->GetExposedAssemblyObject()); |
| 1118 | } |
| 1119 | |
| 1120 | END_QCALL; |
| 1121 | return; |
| 1122 | } |
| 1123 | |
| 1124 | void QCALLTYPE AssemblyNative::GetEntryAssembly(QCall::ObjectHandleOnStack retAssembly) |
| 1125 | { |
| 1126 | QCALL_CONTRACT; |
| 1127 | |
| 1128 | BEGIN_QCALL; |
| 1129 | |
| 1130 | DomainAssembly * pRootAssembly = NULL; |
| 1131 | Assembly * pAssembly = GetAppDomain()->m_pRootAssembly; |
| 1132 | |
| 1133 | if (pAssembly) |
| 1134 | { |
| 1135 | pRootAssembly = pAssembly->GetDomainAssembly(); |
| 1136 | GCX_COOP(); |
| 1137 | retAssembly.Set(pRootAssembly->GetExposedAssemblyObject()); |
| 1138 | } |
| 1139 | |
| 1140 | END_QCALL; |
| 1141 | |
| 1142 | return; |
| 1143 | } |
| 1144 | |
| 1145 | // return the in memory assembly module for reflection emit. This only works for dynamic assembly. |
| 1146 | FCIMPL1(ReflectModuleBaseObject *, AssemblyNative::GetInMemoryAssemblyModule, AssemblyBaseObject* pAssemblyUNSAFE) |
| 1147 | { |
| 1148 | FCALL_CONTRACT; |
| 1149 | |
| 1150 | |
| 1151 | ASSEMBLYREF refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE); |
| 1152 | |
| 1153 | if (refAssembly == NULL) |
| 1154 | FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle" )); |
| 1155 | |
| 1156 | DomainAssembly *pAssembly = refAssembly->GetDomainAssembly(); |
| 1157 | |
| 1158 | FC_RETURN_MODULE_OBJECT(pAssembly->GetCurrentModule(), refAssembly); |
| 1159 | } |
| 1160 | FCIMPLEND |
| 1161 | |
| 1162 | void QCALLTYPE AssemblyNative::GetImageRuntimeVersion(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack retString) |
| 1163 | { |
| 1164 | QCALL_CONTRACT; |
| 1165 | |
| 1166 | BEGIN_QCALL; |
| 1167 | |
| 1168 | // Retrieve the PEFile from the assembly. |
| 1169 | PEFile* pPEFile = pAssembly->GetFile(); |
| 1170 | PREFIX_ASSUME(pPEFile!=NULL); |
| 1171 | |
| 1172 | LPCSTR pszVersion = NULL; |
| 1173 | IfFailThrow(pPEFile->GetMDImport()->GetVersionString(&pszVersion)); |
| 1174 | |
| 1175 | SString version(SString::Utf8, pszVersion); |
| 1176 | |
| 1177 | // Allocate a managed string that contains the version and return it. |
| 1178 | retString.Set(version); |
| 1179 | |
| 1180 | END_QCALL; |
| 1181 | } |
| 1182 | |
| 1183 | /*static*/ |
| 1184 | |
| 1185 | INT_PTR QCALLTYPE AssemblyNative::InitializeAssemblyLoadContext(INT_PTR ptrManagedAssemblyLoadContext, BOOL fRepresentsTPALoadContext, BOOL fIsCollectible) |
| 1186 | { |
| 1187 | QCALL_CONTRACT; |
| 1188 | |
| 1189 | INT_PTR ptrNativeAssemblyLoadContext = NULL; |
| 1190 | |
| 1191 | BEGIN_QCALL; |
| 1192 | |
| 1193 | // We do not need to take a lock since this method is invoked from the ctor of AssemblyLoadContext managed type and |
| 1194 | // only one thread is ever executing a ctor for a given instance. |
| 1195 | // |
| 1196 | |
| 1197 | // Initialize the assembly binder instance in the VM |
| 1198 | PTR_AppDomain pCurDomain = AppDomain::GetCurrentDomain(); |
| 1199 | CLRPrivBinderCoreCLR *pTPABinderContext = pCurDomain->GetTPABinderContext(); |
| 1200 | if (!fRepresentsTPALoadContext) |
| 1201 | { |
| 1202 | // Initialize a custom Assembly Load Context |
| 1203 | CLRPrivBinderAssemblyLoadContext *pBindContext = NULL; |
| 1204 | |
| 1205 | AssemblyLoaderAllocator* loaderAllocator = NULL; |
| 1206 | OBJECTHANDLE loaderAllocatorHandle = NULL; |
| 1207 | |
| 1208 | if (fIsCollectible) |
| 1209 | { |
| 1210 | // Create a new AssemblyLoaderAllocator for an AssemblyLoadContext |
| 1211 | loaderAllocator = new AssemblyLoaderAllocator(); |
| 1212 | loaderAllocator->SetCollectible(); |
| 1213 | |
| 1214 | GCX_COOP(); |
| 1215 | LOADERALLOCATORREF pManagedLoaderAllocator = NULL; |
| 1216 | GCPROTECT_BEGIN(pManagedLoaderAllocator); |
| 1217 | { |
| 1218 | GCX_PREEMP(); |
| 1219 | // Some of the initialization functions are not virtual. Call through the derived class |
| 1220 | // to prevent calling the base class version. |
| 1221 | loaderAllocator->Init(pCurDomain); |
| 1222 | loaderAllocator->InitVirtualCallStubManager(pCurDomain); |
| 1223 | |
| 1224 | // Setup the managed proxy now, but do not actually transfer ownership to it. |
| 1225 | // Once everything is setup and nothing can fail anymore, the ownership will be |
| 1226 | // atomically transfered by call to LoaderAllocator::ActivateManagedTracking(). |
| 1227 | loaderAllocator->SetupManagedTracking(&pManagedLoaderAllocator); |
| 1228 | } |
| 1229 | |
| 1230 | // Create a strong handle to the LoaderAllocator |
| 1231 | loaderAllocatorHandle = pCurDomain->CreateHandle(pManagedLoaderAllocator); |
| 1232 | |
| 1233 | GCPROTECT_END(); |
| 1234 | |
| 1235 | loaderAllocator->ActivateManagedTracking(); |
| 1236 | } |
| 1237 | |
| 1238 | IfFailThrow(CLRPrivBinderAssemblyLoadContext::SetupContext(pCurDomain->GetId().m_dwId, pTPABinderContext, loaderAllocator, loaderAllocatorHandle, ptrManagedAssemblyLoadContext, &pBindContext)); |
| 1239 | ptrNativeAssemblyLoadContext = reinterpret_cast<INT_PTR>(pBindContext); |
| 1240 | } |
| 1241 | else |
| 1242 | { |
| 1243 | // We are initializing the managed instance of Assembly Load Context that would represent the TPA binder. |
| 1244 | // First, confirm we do not have an existing managed ALC attached to the TPA binder. |
| 1245 | INT_PTR ptrTPAAssemblyLoadContext = pTPABinderContext->GetManagedAssemblyLoadContext(); |
| 1246 | if ((ptrTPAAssemblyLoadContext != NULL) && (ptrTPAAssemblyLoadContext != ptrManagedAssemblyLoadContext)) |
| 1247 | { |
| 1248 | COMPlusThrow(kInvalidOperationException, IDS_HOST_ASSEMBLY_RESOLVER_INCOMPATIBLE_TPA_BINDING_CONTEXT); |
| 1249 | } |
| 1250 | |
| 1251 | // Attach the managed TPA binding context with the native one. |
| 1252 | pTPABinderContext->SetManagedAssemblyLoadContext(ptrManagedAssemblyLoadContext); |
| 1253 | ptrNativeAssemblyLoadContext = reinterpret_cast<INT_PTR>(pTPABinderContext); |
| 1254 | } |
| 1255 | |
| 1256 | END_QCALL; |
| 1257 | |
| 1258 | return ptrNativeAssemblyLoadContext; |
| 1259 | } |
| 1260 | |
| 1261 | /*static*/ |
| 1262 | void QCALLTYPE AssemblyNative::PrepareForAssemblyLoadContextRelease(INT_PTR ptrNativeAssemblyLoadContext, INT_PTR ptrManagedStrongAssemblyLoadContext) |
| 1263 | { |
| 1264 | QCALL_CONTRACT; |
| 1265 | |
| 1266 | BOOL fDestroyed = FALSE; |
| 1267 | |
| 1268 | BEGIN_QCALL; |
| 1269 | |
| 1270 | |
| 1271 | { |
| 1272 | GCX_COOP(); |
| 1273 | reinterpret_cast<CLRPrivBinderAssemblyLoadContext *>(ptrNativeAssemblyLoadContext)->PrepareForLoadContextRelease(ptrManagedStrongAssemblyLoadContext); |
| 1274 | } |
| 1275 | |
| 1276 | END_QCALL; |
| 1277 | } |
| 1278 | |
| 1279 | /*static*/ |
| 1280 | INT_PTR QCALLTYPE AssemblyNative::GetLoadContextForAssembly(QCall::AssemblyHandle pAssembly) |
| 1281 | { |
| 1282 | QCALL_CONTRACT; |
| 1283 | |
| 1284 | INT_PTR ptrManagedAssemblyLoadContext = NULL; |
| 1285 | |
| 1286 | BEGIN_QCALL; |
| 1287 | |
| 1288 | // Get the PEAssembly for the RuntimeAssembly |
| 1289 | PEFile *pPEFile = pAssembly->GetFile(); |
| 1290 | PTR_PEAssembly pPEAssembly = pPEFile->AsAssembly(); |
| 1291 | _ASSERTE(pAssembly != NULL); |
| 1292 | |
| 1293 | // Platform assemblies are semantically bound against the "Default" binder. |
| 1294 | // The reference to the same will be returned when this QCall returns. |
| 1295 | |
| 1296 | // Get the binding context for the assembly. |
| 1297 | // |
| 1298 | ICLRPrivBinder *pOpaqueBinder = nullptr; |
| 1299 | AppDomain *pCurDomain = AppDomain::GetCurrentDomain(); |
| 1300 | CLRPrivBinderCoreCLR *pTPABinder = pCurDomain->GetTPABinderContext(); |
| 1301 | |
| 1302 | // GetBindingContext returns a ICLRPrivAssembly which can be used to get access to the |
| 1303 | // actual ICLRPrivBinder instance in which the assembly was loaded. |
| 1304 | PTR_ICLRPrivBinder pBindingContext = pPEAssembly->GetBindingContext(); |
| 1305 | UINT_PTR assemblyBinderID = 0; |
| 1306 | IfFailThrow(pBindingContext->GetBinderID(&assemblyBinderID)); |
| 1307 | |
| 1308 | // If the assembly was bound using the TPA binder, |
| 1309 | // then we will return the reference to "Default" binder from the managed implementation when this QCall returns. |
| 1310 | // |
| 1311 | // See earlier comment about "Default" binder for additional context. |
| 1312 | pOpaqueBinder = reinterpret_cast<ICLRPrivBinder *>(assemblyBinderID); |
| 1313 | |
| 1314 | // We should have a load context binder at this point. |
| 1315 | _ASSERTE(pOpaqueBinder != nullptr); |
| 1316 | |
| 1317 | if (!AreSameBinderInstance(pTPABinder, pOpaqueBinder)) |
| 1318 | { |
| 1319 | // Only CLRPrivBinderAssemblyLoadContext instance contains the reference to its |
| 1320 | // corresponding managed instance. |
| 1321 | CLRPrivBinderAssemblyLoadContext *pBinder = (CLRPrivBinderAssemblyLoadContext *)(pOpaqueBinder); |
| 1322 | |
| 1323 | // Fetch the managed binder reference from the native binder instance |
| 1324 | ptrManagedAssemblyLoadContext = pBinder->GetManagedAssemblyLoadContext(); |
| 1325 | _ASSERTE(ptrManagedAssemblyLoadContext != NULL); |
| 1326 | } |
| 1327 | |
| 1328 | END_QCALL; |
| 1329 | |
| 1330 | return ptrManagedAssemblyLoadContext; |
| 1331 | } |
| 1332 | |
| 1333 | // static |
| 1334 | BOOL QCALLTYPE AssemblyNative::InternalTryGetRawMetadata( |
| 1335 | QCall::AssemblyHandle assembly, |
| 1336 | UINT8 **blobRef, |
| 1337 | INT32 *lengthRef) |
| 1338 | { |
| 1339 | QCALL_CONTRACT; |
| 1340 | |
| 1341 | PTR_CVOID metadata = nullptr; |
| 1342 | |
| 1343 | BEGIN_QCALL; |
| 1344 | |
| 1345 | _ASSERTE(assembly != nullptr); |
| 1346 | _ASSERTE(blobRef != nullptr); |
| 1347 | _ASSERTE(lengthRef != nullptr); |
| 1348 | |
| 1349 | static_assert_no_msg(sizeof(*lengthRef) == sizeof(COUNT_T)); |
| 1350 | metadata = assembly->GetFile()->GetLoadedMetadata(reinterpret_cast<COUNT_T *>(lengthRef)); |
| 1351 | *blobRef = reinterpret_cast<UINT8 *>(const_cast<PTR_VOID>(metadata)); |
| 1352 | _ASSERTE(*lengthRef >= 0); |
| 1353 | |
| 1354 | END_QCALL; |
| 1355 | |
| 1356 | return metadata != nullptr; |
| 1357 | } |
| 1358 | |