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.
8 // Contains the types that implement code:ICLRPrivBinder and code:ICLRPrivAssembly for WinRT binding.
10 //=============================================================================================
12 #include "common.h" // precompiled header
14 #include "clr/fs/file.h"
15 #include "clrprivbinderwinrt.h"
16 #include "clrprivbinderutil.h"
18 #ifndef DACCESS_COMPILE
20 //=====================================================================================================================
25 #include <TypeResolution.h>
26 #include "delayloadhelpers.h"
27 #include "../binder/inc/applicationcontext.hpp"
28 #include "../binder/inc/assemblybinder.hpp"
29 #include "../binder/inc/assembly.hpp"
30 #include "../binder/inc/debuglog.hpp"
31 #include "../binder/inc/utils.hpp"
32 #include "../binder/inc/fusionassemblyname.hpp"
34 #ifdef CROSSGEN_COMPILE
35 #include "crossgenroresolvenamespace.h"
36 #include "../binder/inc/fusionassemblyname.hpp"
40 using namespace CLRPrivBinderUtil;
43 //=====================================================================================================================
44 #define WINDOWS_NAMESPACE W("Windows")
45 #define WINDOWS_NAMESPACE_PREFIX WINDOWS_NAMESPACE W(".")
47 #define WINDOWS_NAMESPACEA "Windows"
48 #define WINDOWS_NAMESPACE_PREFIXA WINDOWS_NAMESPACEA "."
50 //=====================================================================================================================
52 IsWindowsNamespace(const WCHAR * wszNamespace)
54 LIMITED_METHOD_CONTRACT;
56 if (wcsncmp(wszNamespace, WINDOWS_NAMESPACE_PREFIX, (_countof(WINDOWS_NAMESPACE_PREFIX) - 1)) == 0)
60 else if (wcscmp(wszNamespace, WINDOWS_NAMESPACE) == 0)
69 //=====================================================================================================================
71 IsWindowsNamespace(const char * wszNamespace)
73 LIMITED_METHOD_CONTRACT;
75 if (strncmp(wszNamespace, WINDOWS_NAMESPACE_PREFIXA, (_countof(WINDOWS_NAMESPACE_PREFIXA) - 1)) == 0)
79 else if (strcmp(wszNamespace, WINDOWS_NAMESPACEA) == 0)
88 //=====================================================================================================================
89 DELAY_LOADED_FUNCTION(WinTypes, RoResolveNamespace);
91 //=====================================================================================================================
92 HRESULT RoResolveNamespace(
93 _In_opt_ const HSTRING name,
94 _In_opt_ const HSTRING windowsMetaDataDir,
95 _In_ const DWORD packageGraphDirsCount,
96 _In_reads_opt_(packageGraphDirsCount) const HSTRING *packageGraphDirs,
97 _Out_opt_ DWORD *metaDataFilePathsCount,
98 _Outptr_opt_result_buffer_(*metaDataFilePathsCount) HSTRING **metaDataFilePaths,
99 _Out_opt_ DWORD *subNamespacesCount,
100 _Outptr_opt_result_buffer_(*subNamespacesCount) HSTRING **subNamespaces)
102 LIMITED_METHOD_CONTRACT;
105 decltype(RoResolveNamespace) * pFunc = nullptr;
106 IfFailRet(DelayLoad::WinTypes::RoResolveNamespace.GetValue(&pFunc));
109 name, windowsMetaDataDir, packageGraphDirsCount, packageGraphDirs, metaDataFilePathsCount,
110 metaDataFilePaths, subNamespacesCount, subNamespaces);
113 //=====================================================================================================================
114 CLRPrivBinderWinRT * CLRPrivBinderWinRT::s_pSingleton = nullptr;
116 //=====================================================================================================================
117 CLRPrivBinderWinRT::CLRPrivBinderWinRT(
118 ICLRPrivBinder * pParentBinder,
119 CLRPrivTypeCacheWinRT * pWinRtTypeCache,
120 LPCWSTR * rgwzAltPath,
122 NamespaceResolutionKind fNamespaceResolutionKind,
123 BOOL fCanUseNativeImages)
124 : m_pTypeCache(clr::SafeAddRef(pWinRtTypeCache))
125 , m_pParentBinder(pParentBinder) // Do not addref, lifetime directly tied to parent.
126 , m_fNamespaceResolutionKind(fNamespaceResolutionKind)
127 , m_pApplicationContext(nullptr)
128 , m_appLocalWinMDPath(nullptr)
130 STANDARD_VM_CONTRACT;
131 PRECONDITION(CheckPointer(pWinRtTypeCache));
133 #ifndef CROSSGEN_COMPILE
134 // - To prevent deadlock with GC thread, we cannot trigger GC while holding the lock
135 // - To prevent deadlock with profiler thread, we cannot allow thread suspension
137 CrstCLRPrivBinderMaps,
138 (CrstFlags)(CRST_REENTRANCY // Reentracy is needed for code:CLRPrivAssemblyWinRT::Release
139 | CRST_GC_NOTRIGGER_WHEN_TAKEN
140 | CRST_DEBUGGER_THREAD
141 INDEBUG(| CRST_DEBUG_ONLY_CHECK_FORBID_SUSPEND_THREAD)));
142 m_MapsAddLock.Init(CrstCLRPrivBinderMapsAdd);
148 m_rgAltPaths.Allocate(cAltPaths);
150 for (UINT iAltPath = 0; iAltPath < cAltPaths; iAltPath++)
152 IfFailThrow(WindowsCreateString(
153 rgwzAltPath[iAltPath],
154 (UINT32)wcslen(rgwzAltPath[iAltPath]),
155 m_rgAltPaths.GetRawArray() + iAltPath));
158 #endif //CROSSGEN_COMPILE
162 //=====================================================================================================================
163 CLRPrivBinderWinRT::~CLRPrivBinderWinRT()
167 if (m_pTypeCache != nullptr)
169 m_pTypeCache->Release();
173 //=====================================================================================================================
175 CLRPrivBinderWinRT::GetOrCreateBinder(
176 CLRPrivTypeCacheWinRT * pWinRtTypeCache,
177 NamespaceResolutionKind fNamespaceResolutionKind)
179 STANDARD_VM_CONTRACT;
182 if (s_pSingleton == nullptr)
184 ReleaseHolder<CLRPrivBinderWinRT> pBinder;
185 pBinder = clr::SafeAddRef(new CLRPrivBinderWinRT(
186 nullptr, // pParentBinder
188 nullptr, // rgwzAltPath
190 fNamespaceResolutionKind,
191 TRUE // fCanUseNativeImages
194 if (InterlockedCompareExchangeT<decltype(s_pSingleton)>(&s_pSingleton, pBinder, nullptr) == nullptr)
196 pBinder.SuppressRelease();
199 _ASSERTE(s_pSingleton->m_fNamespaceResolutionKind == fNamespaceResolutionKind);
201 return clr::SafeAddRef(s_pSingleton);
204 //=====================================================================================================================
206 CreateAssemblyNameObjectFromMetaData(
207 LPASSEMBLYNAME *ppAssemblyName,
208 LPCOLESTR szAssemblyName,
209 ASSEMBLYMETADATA *pamd,
212 //=====================================================================================================================
213 HRESULT CLRPrivBinderWinRT::BindWinRTAssemblyByName(
214 IAssemblyName * pAssemblyName,
215 CLRPrivAssemblyWinRT ** ppAssembly,
218 STANDARD_VM_CONTRACT;
220 ReleaseHolder<CLRPrivAssemblyWinRT> pAssembly;
221 LPWSTR wszFullTypeName = nullptr;
223 #ifndef CROSSGEN_COMPILE
224 BINDER_SPACE::BINDER_LOG_ENTER(W("CLRPrivBinderWinRT_CoreCLR::BindWinRTAssemblyByName"));
226 VALIDATE_ARG_RET(pAssemblyName != nullptr);
227 VALIDATE_ARG_RET(ppAssembly != nullptr);
229 DWORD dwContentType = AssemblyContentType_Default;
230 IfFailGo(hr = fusion::util::GetProperty(pAssemblyName, ASM_NAME_CONTENT_TYPE, &dwContentType));
231 if ((hr != S_OK) || (dwContentType != AssemblyContentType_WindowsRuntime))
233 IfFailGo(CLR_E_BIND_UNRECOGNIZED_IDENTITY_FORMAT);
236 // Note: WinRT type resolution is supported also on pre-Win8 with DesignerResolveEvent
237 if (!WinRTSupported() && (m_fNamespaceResolutionKind != NamespaceResolutionKind_DesignerResolveEvent))
239 IfFailGo(COR_E_PLATFORMNOTSUPPORTED);
242 WCHAR wszAssemblySimpleName[_MAX_PATH];
244 DWORD cchAssemblySimpleName = _MAX_PATH;
245 IfFailGo(pAssemblyName->GetName(&cchAssemblySimpleName, wszAssemblySimpleName));
248 wszFullTypeName = wcschr(wszAssemblySimpleName, W('!'));
250 if (wszFullTypeName != nullptr)
252 _ASSERTE(wszAssemblySimpleName < wszFullTypeName);
253 if (!(wszAssemblySimpleName < wszFullTypeName))
255 IfFailGo(E_UNEXPECTED);
258 // Turns wszAssemblySimpleName into simple name, wszFullTypeName into type name.
259 *wszFullTypeName++ = W('\0');
261 CLRPrivBinderUtil::WStringList * pFileNameList = nullptr;
262 BOOL fIsWindowsNamespace = FALSE;
265 // don't look past the first generics backtick (if any)
266 WCHAR *pGenericBegin = (WCHAR*)wcschr(wszFullTypeName, W('`'));
267 if (pGenericBegin != nullptr)
268 *pGenericBegin = W('\0');
270 LPWSTR wszSimpleTypeName = wcsrchr(wszFullTypeName, W('.'));
272 // restore the generics backtick
273 if (pGenericBegin != nullptr)
274 *pGenericBegin = W('`');
276 if (wszSimpleTypeName == nullptr)
278 IfFailGo(CLR_E_BIND_UNRECOGNIZED_IDENTITY_FORMAT);
281 // Turns wszFullTypeName into namespace name (without simple type name)
282 *wszSimpleTypeName = W('\0');
284 IfFailGo(GetFileNameListForNamespace(wszFullTypeName, &pFileNameList));
286 fIsWindowsNamespace = IsWindowsNamespace(wszFullTypeName);
288 // Turns wszFullTypeName back into full type name (was namespace name)
289 *wszSimpleTypeName = W('.');
292 if (pFileNameList == nullptr)
293 { // There are no file associated with the namespace
294 IfFailGo(CLR_E_BIND_TYPE_NOT_FOUND);
297 CLRPrivBinderUtil::WStringListElem * pFileNameElem = pFileNameList->GetHead();
298 for (; pFileNameElem != nullptr; pFileNameElem = CLRPrivBinderUtil::WStringList::GetNext(pFileNameElem))
300 const WCHAR * wszFileName = pFileNameElem->GetValue();
301 pAssembly = FindAssemblyByFileName(wszFileName);
303 WCHAR wszFileNameStripped[_MAX_PATH] = {0};
304 SplitPath(wszFileName, NULL, NULL, NULL, NULL, wszFileNameStripped, _MAX_PATH, NULL, NULL);
306 if (pAssembly == nullptr)
308 NewHolder<CLRPrivResourcePathImpl> pResource(
309 new CLRPrivResourcePathImpl(wszFileName));
311 ReleaseHolder<IAssemblyName> pAssemblyDefName;
313 // Instead of using the metadata of the assembly to get the AssemblyDef name, fake one up from the filename.
314 // This ties in with the PreBind binding behavior and ngen. This particular logic was implemented in order
315 // to provide best performance as actually reading the metadata was prohibitively slow. (Due to the cost of opening
316 // the assembly file.) We use a zeroed out ASSEMBLYMETADATA structure to create the assembly name object
317 // in order to ensure that every field of the assembly name is filled out as if this was created from a normal
319 // See comment on CLRPrivBinderWinRT::PreBind for further details about NGEN binding and WinMDs.
320 ASSEMBLYMETADATA asmd = { 0 };
321 IfFailGo(CreateAssemblyNameObjectFromMetaData(&pAssemblyDefName, wszFileNameStripped, &asmd, NULL));
322 DWORD dwAsmContentType = AssemblyContentType_WindowsRuntime;
323 IfFailGo(pAssemblyDefName->SetProperty(ASM_NAME_CONTENT_TYPE, (LPBYTE)&dwAsmContentType, sizeof(dwAsmContentType)));
326 // Creating the BindResult we will pass to the native binder to find native images.
327 // We strip off the type from the assembly name, leaving the simple assembly name.
328 // The native binder stores native images under subdirectories named after their
329 // simple name so we only want to pass the simple name portion of the name to it,
330 // which it uses along with the fingerprint matching in BindResult to find the
331 // native image for this WinRT assembly.
332 // The WinRT team has said that WinMDs will have the same simple name as the filename.
334 IfFailGo(pAssemblyDefName->SetProperty(ASM_NAME_NAME, wszFileNameStripped, (lstrlenW(wszFileNameStripped) + 1) * sizeof(WCHAR)));
336 NewHolder<CoreBindResult> pBindResult(new CoreBindResult());
337 StackSString sAssemblyPath(pResource->GetPath());
338 ReleaseHolder<BINDER_SPACE::Assembly> pBinderAssembly;
340 IfFailGo(GetAssemblyAndTryFindNativeImage(sAssemblyPath, wszFileNameStripped, &pBinderAssembly));
342 // We have set bInGac to TRUE here because the plan is full trust for WinRT. If this changes, we may need to check with
343 // AppDomain to verify trust based on the WinMD's path
344 pBindResult->Init(pBinderAssembly, TRUE);
345 NewHolder<CLRPrivAssemblyWinRT> pNewAssembly(
346 new CLRPrivAssemblyWinRT(this, pResource, pBindResult, fIsWindowsNamespace));
348 // pNewAssembly holds references to these now
349 pResource.SuppressRelease();
350 pBindResult.SuppressRelease();
352 // Add the assembly into cache (multi-thread aware)
353 pAssembly = AddFileNameToAssemblyMapping(pResource->GetPath(), pNewAssembly);
355 // We did not find an existing assembly in the cache and are using the newly created pNewAssembly.
356 // Stop it from being deleted when we go out of scope.
357 if (pAssembly == pNewAssembly)
359 pNewAssembly.SuppressRelease();
365 // Look to see if there's a native image available.
367 hr = pAssembly->EnsureAvailableImageTypes();
369 // Determine if this is the assembly we really want to find.
370 IfFailGo(hr = m_pTypeCache->ContainsType(pAssembly, wszFullTypeName));
372 { // The type we are looking for has been found in this assembly
373 #ifndef CROSSGEN_COMPILE
374 BINDER_SPACE::BINDER_LOG_LEAVE_HR(W("CLRPrivBinderWinRT_CoreCLR::BindWinRTAssemblyByName"), hr);
376 *ppAssembly = pAssembly.Extract();
379 _ASSERTE(hr == S_FALSE);
383 // The type has not been found in any of the files from the type's namespace
384 hr = CLR_E_BIND_TYPE_NOT_FOUND;
387 BINDER_SPACE::BINDER_LOG_LEAVE_HR(W("CLRPrivBinderWinRT_CoreCLR::BindWinRTAssemblyByName"), hr);
389 } // CLRPrivBinderWinRT::BindWinRTAssemblyByName
393 //=====================================================================================================================
394 HRESULT CLRPrivBinderWinRT::BindWinRTAssemblyByName(
395 IAssemblyName * pAssemblyName,
396 ICLRPrivAssembly ** ppPrivAssembly,
399 STANDARD_VM_CONTRACT;
402 ReleaseHolder<CLRPrivAssemblyWinRT> pWinRTAssembly;
403 IfFailRet(BindWinRTAssemblyByName(pAssemblyName, &pWinRTAssembly, fPreBind));
404 IfFailRet(pWinRTAssembly->QueryInterface(__uuidof(ICLRPrivAssembly), (LPVOID *)ppPrivAssembly));
409 //=====================================================================================================================
410 HRESULT CLRPrivBinderWinRT::BindWinRTAssemblyByName(
411 IAssemblyName * pAssemblyName,
412 IBindResult ** ppIBindResult,
415 STANDARD_VM_CONTRACT;
418 VALIDATE_ARG_RET(pAssemblyName != nullptr);
419 VALIDATE_ARG_RET(ppIBindResult != nullptr);
421 ReleaseHolder<CLRPrivAssemblyWinRT> pWinRTAssembly;
422 IfFailRet(BindWinRTAssemblyByName(pAssemblyName, &pWinRTAssembly, fPreBind));
423 IfFailRet(pWinRTAssembly->GetIBindResult(ppIBindResult));
429 // This method opens the assembly using the CoreCLR Binder, which has logic supporting opening either the IL or
430 // even just the native image without IL present.
431 // RoResolveNamespace has already told us the IL file to open. We try and find a native image to open instead
432 // by looking in the TPA list and the App_Ni_Paths.
434 HRESULT CLRPrivBinderWinRT::GetAssemblyAndTryFindNativeImage(SString &sWinmdFilename, LPCWSTR pwzSimpleName, BINDER_SPACE::Assembly ** ppAssembly)
438 if (!m_pApplicationContext->IsTpaListProvided())
439 return COR_E_FILENOTFOUND;
441 BINDER_SPACE::SimpleNameToFileNameMap * tpaMap = m_pApplicationContext->GetTpaList();
442 const BINDER_SPACE::SimpleNameToFileNameMapEntry *pTpaEntry = tpaMap->LookupPtr(pwzSimpleName);
443 if (pTpaEntry != nullptr)
445 ReleaseHolder<BINDER_SPACE::Assembly> pAssembly;
447 if (pTpaEntry->m_wszNIFileName != nullptr)
449 SString fileName(pTpaEntry->m_wszNIFileName);
451 // A GetAssembly overload perhaps, or just another parameter to the existing method
452 hr = BINDER_SPACE::AssemblyBinder::GetAssembly(fileName,
453 FALSE, /* fInspectionOnly */
455 TRUE /* fExplicitBindToNativeImage */,
457 sWinmdFilename.GetUnicode()
460 // On file not found, simply fall back to app ni path probing
461 if (hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
463 // Any other error is fatal
466 *ppAssembly = pAssembly.Extract();
472 StringArrayList *pBindingPaths = m_pApplicationContext->GetAppNiPaths();
474 // Loop through the binding paths looking for a matching assembly
475 for (DWORD i = 0; i < pBindingPaths->GetCount(); i++)
477 ReleaseHolder<BINDER_SPACE::Assembly> pAssembly;
478 LPCWSTR wszBindingPath = (*pBindingPaths)[i];
480 SString simpleName(pwzSimpleName);
481 SString fileName(wszBindingPath);
482 BINDER_SPACE::CombinePath(fileName, simpleName, fileName);
483 fileName.Append(W(".ni.DLL"));
485 hr = BINDER_SPACE::AssemblyBinder::GetAssembly(fileName,
486 FALSE, /* fInspectionOnly */
487 FALSE, /* fIsInGAC */
488 TRUE /* fExplicitBindToNativeImage */,
491 // Since we're probing, file not founds are ok and we should just try another
493 if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
500 *ppAssembly = pAssembly.Extract();
504 // We did not find a native image for this WinMD; open the WinMD file itself as the assembly to return.
505 hr = BINDER_SPACE::AssemblyBinder::GetAssembly(sWinmdFilename,
506 FALSE, /* fInspectionOnly */
507 FALSE, /* fIsInGAC */
508 FALSE /* fExplicitBindToNativeImage */,
514 //=====================================================================================================================
515 HRESULT CLRPrivBinderWinRT::SetApplicationContext(BINDER_SPACE::ApplicationContext *pApplicationContext, SString &appLocalWinMD)
517 STANDARD_VM_CONTRACT;
521 _ASSERTE(pApplicationContext != nullptr);
522 m_pApplicationContext = pApplicationContext;
524 StringArrayList * pAppPaths = m_pApplicationContext->GetAppPaths();
526 #ifndef CROSSGEN_COMPILE
527 DWORD cAppPaths = pAppPaths->GetCount();
528 m_rgAltPaths.Allocate(cAppPaths);
530 for (DWORD i = 0; i < cAppPaths; i++)
532 IfFailRet(WindowsCreateString(
533 pAppPaths->Get(i).GetUnicode(),
534 (UINT32)(pAppPaths->Get(i).GetCount()),
535 m_rgAltPaths.GetRawArray() + i));
538 if (!appLocalWinMD.IsEmpty())
540 m_appLocalWinMDPath = DuplicateStringThrowing(appLocalWinMD.GetUnicode());
543 Crossgen::SetAppPaths(pAppPaths);
549 //=====================================================================================================================
550 // Implements interface method code:ICLRPrivBinder::BindAssemblyByName.
552 HRESULT CLRPrivBinderWinRT::BindAssemblyByName(
553 IAssemblyName * pAssemblyName,
554 ICLRPrivAssembly ** ppAssembly)
556 STANDARD_BIND_CONTRACT;
559 VALIDATE_ARG_RET((pAssemblyName != nullptr) && (ppAssembly != nullptr));
563 if (m_pParentBinder != nullptr)
565 // Delegate to parent binder.
566 hr = m_pParentBinder->BindAssemblyByName(pAssemblyName, ppAssembly);
570 hr = BindWinRTAssemblyByName(pAssemblyName, ppAssembly);
573 EX_CATCH_HRESULT(hr);
578 //=====================================================================================================================
579 ReleaseHolder<CLRPrivAssemblyWinRT>
580 CLRPrivBinderWinRT::FindAssemblyByFileName(
583 LIMITED_METHOD_CONTRACT;
584 STATIC_CONTRACT_CAN_TAKE_LOCK;
586 ForbidSuspendThreadHolder suspend;
588 CrstHolder lock(&m_MapsLock);
590 const FileNameToAssemblyWinRTMapEntry * pEntry = m_FileNameToAssemblyMap.LookupPtr(wszFileName);
591 return (pEntry == nullptr) ? nullptr : clr::SafeAddRef(pEntry->m_pAssembly);
595 //=====================================================================================================================
596 // Add FileName -> CLRPrivAssemblyWinRT * mapping to the map (multi-thread safe).
598 ReleaseHolder<CLRPrivAssemblyWinRT>
599 CLRPrivBinderWinRT::AddFileNameToAssemblyMapping(
601 CLRPrivAssemblyWinRT * pAssembly)
603 STANDARD_VM_CONTRACT;
605 _ASSERTE(pAssembly != nullptr);
607 // We have to serialize all Add operations
608 CrstHolder lock(&m_MapsAddLock);
610 // Wrapper for m_FileNameToAssemblyMap.Add that avoids call out into host
611 FileNameToAssemblyWinRTMap::AddPhases addCall;
613 // 1. Preallocate one element
614 addCall.PreallocateForAdd(&m_FileNameToAssemblyMap);
616 // 2. Take the reader lock which can be taken during stack walking
617 // We cannot call out into host from ForbidSuspend region (i.e. no allocations/deallocations)
618 ForbidSuspendThreadHolder suspend;
620 CrstHolder lock(&m_MapsLock);
622 const FileNameToAssemblyWinRTMapEntry * pEntry = m_FileNameToAssemblyMap.LookupPtr(wszFileName);
623 CLRPrivAssemblyWinRT * pResultAssembly = nullptr;
624 if (pEntry != nullptr)
626 pResultAssembly = pEntry->m_pAssembly;
628 // 3a. Use the newly allocated table (if any) to avoid allocation in the next call (no call out into host)
629 addCall.AddNothing_PublishPreallocatedTable();
633 // 3b. Add the element to the hash table (no call out into host)
634 FileNameToAssemblyWinRTMapEntry e;
635 e.m_wszFileName = wszFileName;
636 e.m_pAssembly = pAssembly;
639 pResultAssembly = pAssembly;
641 return clr::SafeAddRef(pResultAssembly);
644 // 4. Cleanup the old memory (if any) - will be called by destructor of addCall
645 //addCall.DeleteOldTable();
648 //=====================================================================================================================
650 CLRPrivBinderWinRT::RemoveFileNameToAssemblyMapping(
653 LIMITED_METHOD_CONTRACT;
654 STATIC_CONTRACT_CAN_TAKE_LOCK;
656 ForbidSuspendThreadHolder suspend;
658 CrstHolder lock(&m_MapsLock);
660 m_FileNameToAssemblyMap.Remove(wszFileName);
664 //=====================================================================================================================
665 // Returns list of file names from code:m_NamespaceToFileNameListMap for the namespace
668 CLRPrivBinderWinRT::GetFileNameListForNamespace(
669 LPCWSTR wszNamespace,
670 CLRPrivBinderUtil::WStringList ** ppFileNameList)
672 STANDARD_VM_CONTRACT;
673 STATIC_CONTRACT_CAN_TAKE_LOCK;
677 CLRPrivBinderUtil::WStringList * pFileNameList = nullptr;
679 ForbidSuspendThreadHolder suspend;
681 CrstHolder lock(&m_MapsLock);
683 const NamespaceToFileNameListMapEntry * pEntry = m_NamespaceToFileNameListMap.LookupPtr(wszNamespace);
684 if (pEntry != nullptr)
686 // Entries from the map are never removed, so we do not have to protect the file name list with a lock
687 pFileNameList = pEntry->m_pFileNameList;
692 if (pFileNameList != nullptr)
694 *ppFileNameList = pFileNameList;
698 CLRPrivBinderUtil::WStringListHolder hFileNameList;
699 LPCWSTR wszNamespaceRoResolve = wszNamespace;
701 #ifndef CROSSGEN_COMPILE
702 if (m_fNamespaceResolutionKind == NamespaceResolutionKind_WindowsAPI)
704 CoTaskMemHSTRINGArrayHolder hFileNames;
706 UINT32 cchNamespaceRoResolve;
707 IfFailRet(StringCchLength(wszNamespaceRoResolve, &cchNamespaceRoResolve));
709 CLRConfigStringHolder wszWinMDPathConfig;
710 LPWSTR wszWinMDPath = nullptr;
711 UINT32 cchWinMDPath = 0;
713 wszWinMDPath = m_appLocalWinMDPath;
715 if (wszWinMDPath != nullptr)
717 IfFailRet(StringCchLength(wszWinMDPath, &cchWinMDPath));
720 DWORD cFileNames = 0;
721 HSTRING * rgFileNames = nullptr;
722 hr = RoResolveNamespace(
723 WinRtStringRef(wszNamespaceRoResolve, cchNamespaceRoResolve),
724 wszWinMDPath != nullptr ? (HSTRING)WinRtStringRef(wszWinMDPath, cchWinMDPath) : nullptr, // hsWindowsSdkPath
725 m_rgAltPaths.GetCount(), // cPackageGraph
726 m_rgAltPaths.GetRawArray(), // rgPackageGraph
729 nullptr, // pcDirectNamespaceChildren
730 nullptr); // rgDirectNamespaceChildren
731 // For CoreCLR, if the process is not AppX, deliver more appropriate error message
732 // when trying to bind to 3rd party WinMDs that is not confusing.
733 if (HRESULT_FROM_WIN32(APPMODEL_ERROR_NO_PACKAGE) == hr)
735 if (!AppX::IsAppXProcess())
737 IfFailRet(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED));
744 { // Not expecting success codes other than S_OK.
745 IfFailRet(E_UNEXPECTED);
748 hFileNames.Init(rgFileNames, cFileNames);
750 for (DWORD i = 0; i < hFileNames.GetCount(); i++)
752 UINT32 cchFileName = 0;
753 LPCWSTR wszFileName = WindowsGetStringRawBuffer(
757 BOOL fSkipFilename = FALSE;
759 hFileNameList.InsertTail(wszFileName);
764 // This code is desktop specific.
765 _ASSERTE(m_fNamespaceResolutionKind == NamespaceResolutionKind_DesignerResolveEvent);
769 m_pTypeCache->RaiseDesignerNamespaceResolveEvent(wszNamespace, &hFileNameList);
773 Exception * ex = GET_EXCEPTION();
774 if (!ex->IsTransient())
775 { // Exception was caused by user code
776 // Cache empty file name list for this namespace
777 (void)AddFileNameListForNamespace(wszNamespace, nullptr, ppFileNameList);
781 EX_END_CATCH_UNREACHABLE
784 #else //CROSSGEN_COMPILE
786 DWORD cFileNames = 0;
787 SString * rgFileNames = nullptr;
789 hr = Crossgen::CrossgenRoResolveNamespace(
790 wszNamespaceRoResolve,
798 _ASSERTE(cFileNames == 1); //only support mapping to one file in coregen
799 hFileNameList.InsertTail(rgFileNames->GetUnicode());
803 #endif //CROSSGEN_COMPILE
805 // Add the Namespace -> File name list entry into cache (even if the file name list is empty)
806 if (AddFileNameListForNamespace(wszNamespace, hFileNameList.GetValue(), ppFileNameList))
807 { // The file name list was added to the cache - do not delete it
808 _ASSERTE(*ppFileNameList == hFileNameList.GetValue());
809 (void)hFileNameList.Extract();
814 } // CLRPrivBinderWinRT::GetFileNameListForNamespace
816 //=====================================================================================================================
817 // Adds (thread-safe) list of file names to code:m_NamespaceToFileNameListMap for the namespace - returns the cached value.
818 // Returns TRUE, if pFileNameList was added to the cache and caller should NOT delete it.
819 // Returns FALSE, if pFileNameList was not added to the cache and caller should delete it.
822 CLRPrivBinderWinRT::AddFileNameListForNamespace(
823 LPCWSTR wszNamespace,
824 CLRPrivBinderUtil::WStringList * pFileNameList,
825 CLRPrivBinderUtil::WStringList ** ppFileNameList)
827 STANDARD_VM_CONTRACT;
829 NewArrayHolder<WCHAR> wszEntryNamespace = DuplicateStringThrowing(wszNamespace);
831 NamespaceToFileNameListMapEntry entry;
832 entry.m_wszNamespace = wszEntryNamespace.GetValue();
833 entry.m_pFileNameList = pFileNameList;
835 // We have to serialize all Add operations
836 CrstHolder lock(&m_MapsAddLock);
838 // Wrapper for m_NamespaceToFileNameListMap.Add that avoids call out into host
839 NamespaceToFileNameListMap::AddPhases addCall;
841 // Status if the element was added to the hash table or not
842 BOOL fAddedToCache = FALSE;
844 // 1. Preallocate one element
845 addCall.PreallocateForAdd(&m_NamespaceToFileNameListMap);
847 // 2. Take the reader lock which can be taken during stack walking
848 // We cannot call out into host from ForbidSuspend region (i.e. no allocations/deallocations)
849 ForbidSuspendThreadHolder suspend;
851 CrstHolder lock(&m_MapsLock);
853 const NamespaceToFileNameListMapEntry * pEntry = m_NamespaceToFileNameListMap.LookupPtr(wszNamespace);
854 if (pEntry == nullptr)
856 // 3a. Add the element to the hash table (no call out into host)
859 // These values are now owned by the hash table element
860 wszEntryNamespace.SuppressRelease();
861 *ppFileNameList = pFileNameList;
862 fAddedToCache = TRUE;
865 { // Another thread beat us adding this entry to the hash table
866 *ppFileNameList = pEntry->m_pFileNameList;
868 // 3b. Use the newly allocated table (if any) to avoid allocation in the next call (no call out into host)
869 addCall.AddNothing_PublishPreallocatedTable();
870 _ASSERTE(fAddedToCache == FALSE);
874 // 4. Cleanup the old memory (if any), also called from the destructor of addCall
875 addCall.DeleteOldTable();
877 return fAddedToCache;
878 } // CLRPrivBinderWinRT::AddFileNameListForNamespace
880 #endif //!DACCESS_COMPILE
882 //=====================================================================================================================
883 // Finds assembly with WinRT type if it is already loaded.
886 CLRPrivBinderWinRT::FindAssemblyForTypeIfLoaded(
887 PTR_AppDomain pAppDomain,
901 WCHAR wszNamespace[MAX_CLASSNAME_LENGTH];
902 int cchNamespace = WszMultiByteToWideChar(CP_UTF8, 0, szNamespace, -1, wszNamespace, _countof(wszNamespace));
903 if (cchNamespace == 0)
908 CLRPrivBinderUtil::WStringListElem * pFileNameElem= nullptr;
909 const NamespaceToFileNameListMapEntry * pNamespaceEntry;
911 ForbidSuspendThreadHolder suspend;
913 CrstHolder lock(&m_MapsLock);
915 pNamespaceEntry = m_NamespaceToFileNameListMap.LookupPtr(wszNamespace);
916 if ((pNamespaceEntry == nullptr) || (pNamespaceEntry->m_pFileNameList == nullptr))
921 pFileNameElem = pNamespaceEntry->m_pFileNameList->GetHead();
925 while (pFileNameElem != nullptr)
927 const WCHAR * wszFileName = pFileNameElem->GetValue();
928 PTR_CLRPrivAssemblyWinRT pPrivAssembly=NULL;
929 const FileNameToAssemblyWinRTMapEntry * pFileNameEntry;
931 ForbidSuspendThreadHolder suspend;
933 CrstHolder lock(&m_MapsLock);
935 pFileNameEntry = m_FileNameToAssemblyMap.LookupPtr(wszFileName);
936 if (pFileNameEntry == nullptr || pFileNameEntry->m_pAssembly == nullptr)
941 pPrivAssembly = pFileNameEntry->m_pAssembly;
945 if (pPrivAssembly == NULL)
950 _ASSERT(((void *)(CLRPrivAssemblyWinRT *)0x100) ==
951 ((void *)(ICLRPrivAssembly *)(CLRPrivAssemblyWinRT *)0x100));
953 PTR_Assembly pAssembly = NULL;
954 HRESULT hr = m_pTypeCache->ContainsTypeIfLoaded(
956 dac_cast<PTR_ICLRPrivAssembly>(pPrivAssembly),
961 { // The type we are looking for has been found in this assembly
962 _ASSERTE(pAssembly != nullptr);
966 { // Assembly was not loaded
969 // Type was not found in the assembly
970 _ASSERTE(hr == S_FALSE);
972 // Try next file name for this namespace
973 pFileNameElem = CLRPrivBinderUtil::WStringList::GetNext(pFileNameElem);
977 } // CLRPrivBinderWinRT::FindAssemblyForTypeIfLoaded
979 #ifndef DACCESS_COMPILE
982 //=====================================================================================================================
983 CLRPrivAssemblyWinRT::CLRPrivAssemblyWinRT(
984 CLRPrivBinderWinRT * pBinder,
985 CLRPrivResourcePathImpl * pResourceIL,
986 IBindResult * pIBindResult,
988 : m_pBinder(nullptr),
989 m_pResourceIL(nullptr),
990 m_pIResourceNI(nullptr),
991 m_pIBindResult(nullptr),
992 m_fShareable(fShareable),
995 STANDARD_VM_CONTRACT;
996 VALIDATE_ARG_THROW((pBinder != nullptr) && (pResourceIL != nullptr) && (pIBindResult != nullptr));
998 m_pBinder = clr::SafeAddRef(pBinder);
999 m_pResourceIL = clr::SafeAddRef(pResourceIL);
1000 m_pIBindResult = clr::SafeAddRef(pIBindResult);
1003 //=====================================================================================================================
1004 CLRPrivAssemblyWinRT::~CLRPrivAssemblyWinRT()
1006 LIMITED_METHOD_CONTRACT;
1007 clr::SafeRelease(m_pIResourceNI);
1010 //=====================================================================================================================
1011 // Implements interface method code:IUnknown::Release.
1012 // Overridden to implement self-removal from assembly map code:CLRPrivBinderWinRT::m_FileNameToAssemblyMap.
1014 ULONG CLRPrivAssemblyWinRT::Release()
1016 LIMITED_METHOD_CONTRACT;
1017 STATIC_CONTRACT_CAN_TAKE_LOCK;
1018 _ASSERTE(m_cRef > 0);
1023 // To achieve proper lifetime semantics, the name to assembly map elements' CLRPrivAssemblyWinRT
1024 // instances are not ref counted. We cannot allow discovery of the object via m_FileNameToAssemblyMap
1025 // when the ref count is 0 (to prevent another thread to AddRef and Release it back to 0 in parallel).
1026 // All uses of the map are guarded by the map lock, so we have to decrease the ref count under that
1027 // lock (to avoid the chance that 2 threads are running Release to ref count 0 at once).
1028 ForbidSuspendThreadHolder suspend;
1030 CrstHolder lock(&m_pBinder->m_MapsLock);
1031 cRef = InterlockedDecrement(&m_cRef);
1034 m_pBinder->RemoveFileNameToAssemblyMapping(m_pResourceIL->GetPath());
1039 // Note: We cannot deallocate memory in the ForbidSuspendThread region
1046 } // CLRPrivAssemblyWinRT::Release
1048 //=====================================================================================================================
1049 // Implements interface method code:ICLRPrivAssembly::IsShareable.
1051 HRESULT CLRPrivAssemblyWinRT::IsShareable(
1052 BOOL * pbIsShareable)
1054 LIMITED_METHOD_CONTRACT;
1056 VALIDATE_ARG_RET(pbIsShareable != nullptr);
1058 *pbIsShareable = m_fShareable;
1062 //=====================================================================================================================
1063 // Implements interface method code:ICLRPrivAssembly::GetAvailableImageTypes.
1065 HRESULT CLRPrivAssemblyWinRT::GetAvailableImageTypes(
1066 LPDWORD pdwImageTypes)
1068 STANDARD_BIND_CONTRACT;
1072 VALIDATE_ARG_RET(pdwImageTypes != nullptr);
1076 IfFailGo(EnsureAvailableImageTypes());
1078 *pdwImageTypes = m_dwImageTypes;
1083 EX_CATCH_HRESULT(hr);
1089 //=====================================================================================================================
1090 // Implements interface method code:ICLRPrivAssembly::GetImageResource.
1092 HRESULT CLRPrivAssemblyWinRT::GetImageResource(
1094 DWORD * pdwImageType,
1095 ICLRPrivResource ** ppIResource)
1097 STANDARD_BIND_CONTRACT;
1100 VALIDATE_ARG_RET((ppIResource != nullptr) && (m_pIBindResult != nullptr));
1104 IfFailGo(EnsureAvailableImageTypes());
1107 if (pdwImageType == nullptr)
1109 pdwImageType = &_dwImageType;
1112 if ((dwImageType & ASSEMBLY_IMAGE_TYPE_NATIVE) == ASSEMBLY_IMAGE_TYPE_NATIVE)
1114 if (m_pIResourceNI == nullptr)
1116 IfFailGo(CLR_E_BIND_IMAGE_UNAVAILABLE);
1119 *ppIResource = clr::SafeAddRef(m_pIResourceNI);
1120 *pdwImageType = ASSEMBLY_IMAGE_TYPE_NATIVE;
1122 else if ((dwImageType & ASSEMBLY_IMAGE_TYPE_IL) == ASSEMBLY_IMAGE_TYPE_IL)
1124 *ppIResource = clr::SafeAddRef(m_pResourceIL);
1125 *pdwImageType = ASSEMBLY_IMAGE_TYPE_IL;
1129 hr = CLR_E_BIND_IMAGE_UNAVAILABLE;
1134 EX_CATCH_HRESULT(hr);
1139 //=====================================================================================================================
1140 // Implements interface method code:ICLRPrivBinder::VerifyBind.
1142 HRESULT CLRPrivBinderWinRT::VerifyBind(
1143 IAssemblyName * pAssemblyName,
1144 ICLRPrivAssembly * pAssembly,
1145 ICLRPrivAssemblyInfo * pAssemblyInfo)
1147 STANDARD_BIND_CONTRACT;
1150 VALIDATE_ARG_RET(pAssemblyInfo != nullptr);
1153 IfFailRet(pAssembly->GetBinderID(&binderID));
1154 if (binderID != reinterpret_cast<UINT_PTR>(this))
1156 return pAssembly->VerifyBind(pAssemblyName, pAssembly, pAssemblyInfo);
1159 // Since WinRT types are bound by type name and not assembly name, assembly-level version validation
1160 // does not make sense here. Just return S_OK.
1164 //=====================================================================================================================
1165 // Implements interface method code:ICLRPrivBinder::GetBinderID.
1167 HRESULT CLRPrivBinderWinRT::GetBinderID(
1168 UINT_PTR * pBinderId)
1170 LIMITED_METHOD_CONTRACT;
1172 *pBinderId = reinterpret_cast<UINT_PTR>(this);
1176 //=====================================================================================================================
1177 HRESULT CLRPrivBinderWinRT::FindWinRTAssemblyBySpec(
1179 LPVOID pvAssemblySpec,
1181 ICLRPrivAssembly ** ppAssembly)
1183 STATIC_CONTRACT_WRAPPER;
1188 //=====================================================================================================================
1189 HRESULT CLRPrivAssemblyWinRT::GetIBindResult(
1190 IBindResult ** ppIBindResult)
1192 LIMITED_METHOD_CONTRACT;
1194 VALIDATE_ARG_RET(ppIBindResult != nullptr);
1195 VALIDATE_CONDITION((m_pIBindResult != nullptr), return E_UNEXPECTED);
1197 *ppIBindResult = clr::SafeAddRef(m_pIBindResult);
1202 //=====================================================================================================================
1203 HRESULT CLRPrivAssemblyWinRT::EnsureAvailableImageTypes()
1205 STANDARD_VM_CONTRACT;
1208 DWORD dwImageTypesLocal = m_dwImageTypes;
1210 // If image types has not yet been set, attempt to bind to native assembly
1211 if (dwImageTypesLocal == 0)
1213 if (m_pIResourceNI == nullptr)
1215 if (m_pIBindResult->HasNativeImage())
1217 SString sPath = m_pIBindResult->GetNativeImage()->GetPath();
1218 m_pIResourceNI = new CLRPrivResourcePathImpl(sPath.GetUnicode());
1219 m_pIResourceNI->AddRef();
1224 DWORD dwImageTypes = 0;
1226 if (m_pResourceIL != nullptr)
1227 dwImageTypes |= ASSEMBLY_IMAGE_TYPE_IL;
1229 if (m_pIResourceNI != nullptr)
1230 dwImageTypes |= ASSEMBLY_IMAGE_TYPE_NATIVE;
1232 m_dwImageTypes = dwImageTypes;
1239 //=====================================================================================================================
1241 HRESULT CLRPrivAssemblyWinRT::GetIBindResult(
1242 ICLRPrivAssembly * pPrivAssembly,
1243 IBindResult ** ppIBindResult)
1245 LIMITED_METHOD_CONTRACT;
1249 VALIDATE_ARG_RET(pPrivAssembly != nullptr);
1251 ReleaseHolder<ICLRPrivAssemblyID_WinRT> pAssemblyID;
1252 IfFailRet(pPrivAssembly->QueryInterface(__uuidof(ICLRPrivAssemblyID_WinRT), (LPVOID *)&pAssemblyID));
1253 // QI succeeded, we can cast up:
1254 CLRPrivAssemblyWinRT * pPrivAssemblyWinRT = static_cast<CLRPrivAssemblyWinRT *>(pPrivAssembly);
1256 return pPrivAssemblyWinRT->GetIBindResult(ppIBindResult);
1259 #endif //!DACCESS_COMPILE