Merge pull request #14619 from briansull/emitter-cleanup
[platform/upstream/coreclr.git] / src / vm / clrprivbinderwinrt.cpp
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 // 
8 // Contains the types that implement code:ICLRPrivBinder and code:ICLRPrivAssembly for WinRT binding.
9 // 
10 //=============================================================================================
11
12 #include "common.h" // precompiled header
13
14 #include "clr/fs/file.h"
15 #include "clrprivbinderwinrt.h"
16 #include "clrprivbinderutil.h"
17
18 #ifndef DACCESS_COMPILE
19
20 //=====================================================================================================================
21 #include "sstring.h"
22 #ifdef FEATURE_APPX
23 #include "appxutil.h"
24 #endif
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"
33
34 #ifdef CROSSGEN_COMPILE
35 #include "crossgenroresolvenamespace.h"
36 #include "../binder/inc/fusionassemblyname.hpp"
37 #endif
38
39
40 using namespace CLRPrivBinderUtil;
41
42
43 //=====================================================================================================================
44 #define WINDOWS_NAMESPACE W("Windows")  
45 #define WINDOWS_NAMESPACE_PREFIX WINDOWS_NAMESPACE W(".")  
46
47 #define WINDOWS_NAMESPACEA "Windows"  
48 #define WINDOWS_NAMESPACE_PREFIXA WINDOWS_NAMESPACEA "."  
49
50 //=====================================================================================================================
51 static BOOL 
52 IsWindowsNamespace(const WCHAR * wszNamespace)
53 {
54     LIMITED_METHOD_CONTRACT;
55     
56     if (wcsncmp(wszNamespace, WINDOWS_NAMESPACE_PREFIX, (_countof(WINDOWS_NAMESPACE_PREFIX) - 1)) == 0)
57     {  
58         return TRUE;  
59     }  
60     else if (wcscmp(wszNamespace, WINDOWS_NAMESPACE) == 0)  
61     {  
62         return TRUE;
63     }  
64
65     return FALSE;
66 }
67
68
69 //=====================================================================================================================
70 BOOL 
71 IsWindowsNamespace(const char * wszNamespace)
72 {
73     LIMITED_METHOD_CONTRACT;
74     
75     if (strncmp(wszNamespace, WINDOWS_NAMESPACE_PREFIXA, (_countof(WINDOWS_NAMESPACE_PREFIXA) - 1)) == 0)
76     {  
77         return TRUE;  
78     }  
79     else if (strcmp(wszNamespace, WINDOWS_NAMESPACEA) == 0)
80     {  
81         return TRUE;
82     }  
83
84     return FALSE;
85 }
86
87
88 //=====================================================================================================================
89 DELAY_LOADED_FUNCTION(WinTypes, RoResolveNamespace);
90
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)
101 {
102     LIMITED_METHOD_CONTRACT;
103     HRESULT hr = S_OK;
104
105     decltype(RoResolveNamespace) * pFunc = nullptr;
106     IfFailRet(DelayLoad::WinTypes::RoResolveNamespace.GetValue(&pFunc));
107
108     return (*pFunc)(
109         name, windowsMetaDataDir, packageGraphDirsCount, packageGraphDirs, metaDataFilePathsCount,
110         metaDataFilePaths, subNamespacesCount, subNamespaces);
111 }
112
113 //=====================================================================================================================
114 CLRPrivBinderWinRT * CLRPrivBinderWinRT::s_pSingleton = nullptr;
115
116 //=====================================================================================================================
117 CLRPrivBinderWinRT::CLRPrivBinderWinRT(
118     ICLRPrivBinder *        pParentBinder, 
119     CLRPrivTypeCacheWinRT * pWinRtTypeCache, 
120     LPCWSTR *               rgwzAltPath, 
121     UINT                    cAltPaths, 
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)
129 {
130     STANDARD_VM_CONTRACT;
131     PRECONDITION(CheckPointer(pWinRtTypeCache));
132     
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
136     m_MapsLock.Init(
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);
143
144
145     // Copy altpaths
146     if (cAltPaths > 0)
147     {
148         m_rgAltPaths.Allocate(cAltPaths);
149
150         for (UINT iAltPath = 0; iAltPath < cAltPaths; iAltPath++)
151         {
152             IfFailThrow(WindowsCreateString(
153                 rgwzAltPath[iAltPath], 
154                 (UINT32)wcslen(rgwzAltPath[iAltPath]), 
155                 m_rgAltPaths.GetRawArray() + iAltPath));
156         }
157     }
158 #endif //CROSSGEN_COMPILE
159
160 }
161
162 //=====================================================================================================================
163 CLRPrivBinderWinRT::~CLRPrivBinderWinRT()
164 {
165     WRAPPER_NO_CONTRACT;
166
167     if (m_pTypeCache != nullptr)
168     {
169         m_pTypeCache->Release();
170     }
171 }
172
173 //=====================================================================================================================
174 CLRPrivBinderWinRT * 
175 CLRPrivBinderWinRT::GetOrCreateBinder(
176     CLRPrivTypeCacheWinRT * pWinRtTypeCache, 
177     NamespaceResolutionKind fNamespaceResolutionKind)
178 {
179     STANDARD_VM_CONTRACT;
180     HRESULT hr = S_OK;
181
182     if (s_pSingleton == nullptr)
183     {
184         ReleaseHolder<CLRPrivBinderWinRT> pBinder;
185         pBinder = clr::SafeAddRef(new CLRPrivBinderWinRT(
186             nullptr,    // pParentBinder
187             pWinRtTypeCache, 
188             nullptr,    // rgwzAltPath
189             0,          // cAltPaths
190             fNamespaceResolutionKind,
191             TRUE // fCanUseNativeImages
192             ));
193         
194         if (InterlockedCompareExchangeT<decltype(s_pSingleton)>(&s_pSingleton, pBinder, nullptr) == nullptr)
195         {
196             pBinder.SuppressRelease();
197         }
198     }
199     _ASSERTE(s_pSingleton->m_fNamespaceResolutionKind == fNamespaceResolutionKind);
200     
201     return clr::SafeAddRef(s_pSingleton);
202 }
203
204 //=====================================================================================================================
205 STDAPI
206 CreateAssemblyNameObjectFromMetaData(
207     LPASSEMBLYNAME    *ppAssemblyName,
208     LPCOLESTR          szAssemblyName,
209     ASSEMBLYMETADATA  *pamd,
210     LPVOID             pvReserved);
211
212 //=====================================================================================================================
213 HRESULT CLRPrivBinderWinRT::BindWinRTAssemblyByName(
214     IAssemblyName *         pAssemblyName,
215     CLRPrivAssemblyWinRT ** ppAssembly,
216     BOOL fPreBind)
217 {
218     STANDARD_VM_CONTRACT;
219     HRESULT hr = S_OK;
220     ReleaseHolder<CLRPrivAssemblyWinRT> pAssembly;
221     LPWSTR wszFullTypeName = nullptr;
222
223 #ifndef CROSSGEN_COMPILE
224     BINDER_SPACE::BINDER_LOG_ENTER(W("CLRPrivBinderWinRT_CoreCLR::BindWinRTAssemblyByName"));
225 #endif
226     VALIDATE_ARG_RET(pAssemblyName != nullptr);
227     VALIDATE_ARG_RET(ppAssembly != nullptr);
228     
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))
232     {
233         IfFailGo(CLR_E_BIND_UNRECOGNIZED_IDENTITY_FORMAT);
234     }
235     
236     // Note: WinRT type resolution is supported also on pre-Win8 with DesignerResolveEvent
237     if (!WinRTSupported() && (m_fNamespaceResolutionKind != NamespaceResolutionKind_DesignerResolveEvent))
238     {
239         IfFailGo(COR_E_PLATFORMNOTSUPPORTED);
240     }
241     
242     WCHAR wszAssemblySimpleName[_MAX_PATH];
243     {
244         DWORD cchAssemblySimpleName = _MAX_PATH;
245         IfFailGo(pAssemblyName->GetName(&cchAssemblySimpleName, wszAssemblySimpleName));
246     }
247     
248     wszFullTypeName = wcschr(wszAssemblySimpleName, W('!'));
249     
250     if (wszFullTypeName != nullptr)
251     {
252         _ASSERTE(wszAssemblySimpleName < wszFullTypeName);
253         if (!(wszAssemblySimpleName < wszFullTypeName))
254         {
255             IfFailGo(E_UNEXPECTED);
256         }
257
258         // Turns wszAssemblySimpleName into simple name, wszFullTypeName into type name.
259         *wszFullTypeName++ = W('\0');
260         
261         CLRPrivBinderUtil::WStringList * pFileNameList = nullptr;
262         BOOL fIsWindowsNamespace = FALSE;
263
264         {
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');
269
270             LPWSTR wszSimpleTypeName = wcsrchr(wszFullTypeName, W('.'));
271
272             // restore the generics backtick
273             if (pGenericBegin != nullptr)
274                 *pGenericBegin = W('`');
275
276             if (wszSimpleTypeName == nullptr)
277             {
278                 IfFailGo(CLR_E_BIND_UNRECOGNIZED_IDENTITY_FORMAT);
279             }
280             
281             // Turns wszFullTypeName into namespace name (without simple type name)
282             *wszSimpleTypeName = W('\0');
283             
284             IfFailGo(GetFileNameListForNamespace(wszFullTypeName, &pFileNameList));
285             
286             fIsWindowsNamespace = IsWindowsNamespace(wszFullTypeName);
287
288             // Turns wszFullTypeName back into full type name (was namespace name)
289             *wszSimpleTypeName = W('.');
290         }
291         
292         if (pFileNameList == nullptr)
293         {   // There are no file associated with the namespace
294             IfFailGo(CLR_E_BIND_TYPE_NOT_FOUND);
295         }
296         
297         CLRPrivBinderUtil::WStringListElem * pFileNameElem = pFileNameList->GetHead();
298         for (; pFileNameElem != nullptr; pFileNameElem = CLRPrivBinderUtil::WStringList::GetNext(pFileNameElem))
299         {
300             const WCHAR * wszFileName = pFileNameElem->GetValue();
301             pAssembly = FindAssemblyByFileName(wszFileName);
302             
303             WCHAR wszFileNameStripped[_MAX_PATH] = {0};
304             SplitPath(wszFileName, NULL, NULL, NULL, NULL, wszFileNameStripped, _MAX_PATH, NULL, NULL);
305
306             if (pAssembly == nullptr)
307             {
308                 NewHolder<CLRPrivResourcePathImpl> pResource(
309                     new CLRPrivResourcePathImpl(wszFileName));
310                 
311                 ReleaseHolder<IAssemblyName> pAssemblyDefName;
312
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
318                 // assembly def row.
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)));
324
325                 // 
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.
333                 // 
334                 IfFailGo(pAssemblyDefName->SetProperty(ASM_NAME_NAME, wszFileNameStripped, (lstrlenW(wszFileNameStripped) + 1) * sizeof(WCHAR)));
335
336                 NewHolder<CoreBindResult> pBindResult(new CoreBindResult());
337                 StackSString sAssemblyPath(pResource->GetPath());
338                 ReleaseHolder<BINDER_SPACE::Assembly> pBinderAssembly;
339
340                 IfFailGo(GetAssemblyAndTryFindNativeImage(sAssemblyPath, wszFileNameStripped, &pBinderAssembly));
341
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));
347                 
348                 // pNewAssembly holds references to these now
349                 pResource.SuppressRelease();
350                 pBindResult.SuppressRelease();
351                 
352                 // Add the assembly into cache (multi-thread aware)
353                 pAssembly = AddFileNameToAssemblyMapping(pResource->GetPath(), pNewAssembly);
354                 
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)
358                 {
359                     pNewAssembly.SuppressRelease();
360                 }
361                 
362             }
363
364             //
365             // Look to see if there's a native image available.
366             //
367             hr = pAssembly->EnsureAvailableImageTypes();
368
369             // Determine if this is the assembly we really want to find.
370             IfFailGo(hr = m_pTypeCache->ContainsType(pAssembly, wszFullTypeName));
371             if (hr == S_OK)
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);
375 #endif
376                 *ppAssembly = pAssembly.Extract();
377                 return (hr = S_OK);
378             }
379             _ASSERTE(hr == S_FALSE);
380         }
381     }
382
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;
385  ErrExit:
386
387     BINDER_SPACE::BINDER_LOG_LEAVE_HR(W("CLRPrivBinderWinRT_CoreCLR::BindWinRTAssemblyByName"), hr);
388     return hr;
389 } // CLRPrivBinderWinRT::BindWinRTAssemblyByName
390
391
392
393 //=====================================================================================================================
394 HRESULT CLRPrivBinderWinRT::BindWinRTAssemblyByName(
395     IAssemblyName *     pAssemblyName,
396     ICLRPrivAssembly ** ppPrivAssembly,
397     BOOL fPreBind)
398 {
399     STANDARD_VM_CONTRACT;
400     HRESULT hr = S_OK;
401
402     ReleaseHolder<CLRPrivAssemblyWinRT> pWinRTAssembly;
403     IfFailRet(BindWinRTAssemblyByName(pAssemblyName, &pWinRTAssembly, fPreBind));
404     IfFailRet(pWinRTAssembly->QueryInterface(__uuidof(ICLRPrivAssembly), (LPVOID *)ppPrivAssembly));
405
406     return hr;
407 }
408
409 //=====================================================================================================================
410 HRESULT CLRPrivBinderWinRT::BindWinRTAssemblyByName(
411     IAssemblyName * pAssemblyName,
412     IBindResult ** ppIBindResult,
413     BOOL fPreBind)
414 {
415     STANDARD_VM_CONTRACT;
416     HRESULT hr = S_OK;
417
418     VALIDATE_ARG_RET(pAssemblyName != nullptr);
419     VALIDATE_ARG_RET(ppIBindResult != nullptr);
420
421     ReleaseHolder<CLRPrivAssemblyWinRT> pWinRTAssembly;
422     IfFailRet(BindWinRTAssemblyByName(pAssemblyName, &pWinRTAssembly, fPreBind));
423     IfFailRet(pWinRTAssembly->GetIBindResult(ppIBindResult));
424
425     return hr;
426 }
427
428 //
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.
433 //
434 HRESULT CLRPrivBinderWinRT::GetAssemblyAndTryFindNativeImage(SString &sWinmdFilename, LPCWSTR pwzSimpleName, BINDER_SPACE::Assembly ** ppAssembly)
435 {
436     HRESULT hr = S_OK;
437
438     if (!m_pApplicationContext->IsTpaListProvided())
439         return COR_E_FILENOTFOUND;
440
441     BINDER_SPACE::SimpleNameToFileNameMap * tpaMap = m_pApplicationContext->GetTpaList();
442     const BINDER_SPACE::SimpleNameToFileNameMapEntry *pTpaEntry = tpaMap->LookupPtr(pwzSimpleName);
443     if (pTpaEntry != nullptr)
444     {
445         ReleaseHolder<BINDER_SPACE::Assembly> pAssembly;
446
447         if (pTpaEntry->m_wszNIFileName != nullptr)
448         {
449             SString fileName(pTpaEntry->m_wszNIFileName);
450
451             // A GetAssembly overload perhaps, or just another parameter to the existing method
452             hr = BINDER_SPACE::AssemblyBinder::GetAssembly(fileName,
453                                 FALSE, /* fInspectionOnly */
454                                 TRUE, /* fIsInGAC */
455                                 TRUE /* fExplicitBindToNativeImage */,
456                                 &pAssembly,
457                                 sWinmdFilename.GetUnicode()
458                                 );
459
460             // On file not found, simply fall back to app ni path probing
461             if (hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
462             {
463                 // Any other error is fatal
464                 IfFailRet(hr);
465
466                 *ppAssembly = pAssembly.Extract();
467                 return (hr = S_OK);
468             }
469         }
470     }
471
472     StringArrayList *pBindingPaths = m_pApplicationContext->GetAppNiPaths();
473     
474     // Loop through the binding paths looking for a matching assembly
475     for (DWORD i = 0; i < pBindingPaths->GetCount(); i++)
476     {
477         ReleaseHolder<BINDER_SPACE::Assembly> pAssembly;
478         LPCWSTR wszBindingPath = (*pBindingPaths)[i];
479         
480         SString simpleName(pwzSimpleName);
481         SString fileName(wszBindingPath);
482         BINDER_SPACE::CombinePath(fileName, simpleName, fileName);
483         fileName.Append(W(".ni.DLL"));
484         
485         hr = BINDER_SPACE::AssemblyBinder::GetAssembly(fileName,
486                         FALSE, /* fInspectionOnly */
487                         FALSE, /* fIsInGAC */
488                         TRUE /* fExplicitBindToNativeImage */,
489                         &pAssembly);
490         
491         // Since we're probing, file not founds are ok and we should just try another
492         // probing path
493         if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
494         {
495             continue;
496         }
497         
498         IfFailRet(hr);
499
500         *ppAssembly = pAssembly.Extract();
501         return (hr = S_OK);
502     }
503     
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 */,
509                             ppAssembly);
510
511     return hr;
512 }
513
514 //=====================================================================================================================
515 HRESULT CLRPrivBinderWinRT::SetApplicationContext(BINDER_SPACE::ApplicationContext *pApplicationContext, SString &appLocalWinMD)
516 {
517     STANDARD_VM_CONTRACT;
518
519     HRESULT hr = S_OK;
520     
521     _ASSERTE(pApplicationContext != nullptr);
522     m_pApplicationContext = pApplicationContext;
523
524     StringArrayList * pAppPaths = m_pApplicationContext->GetAppPaths();
525     
526 #ifndef CROSSGEN_COMPILE
527     DWORD cAppPaths = pAppPaths->GetCount();
528     m_rgAltPaths.Allocate(cAppPaths);
529     
530     for (DWORD i = 0; i < cAppPaths; i++)
531     {
532         IfFailRet(WindowsCreateString(
533                 pAppPaths->Get(i).GetUnicode(),
534                 (UINT32)(pAppPaths->Get(i).GetCount()),
535                 m_rgAltPaths.GetRawArray() + i));
536     }
537
538     if (!appLocalWinMD.IsEmpty())
539     {
540         m_appLocalWinMDPath = DuplicateStringThrowing(appLocalWinMD.GetUnicode());
541     }
542 #else
543     Crossgen::SetAppPaths(pAppPaths);
544 #endif
545     
546     return hr;
547 }
548
549 //=====================================================================================================================
550 // Implements interface method code:ICLRPrivBinder::BindAssemblyByName.
551 // 
552 HRESULT CLRPrivBinderWinRT::BindAssemblyByName(
553     IAssemblyName     * pAssemblyName,
554     ICLRPrivAssembly ** ppAssembly)
555 {
556     STANDARD_BIND_CONTRACT;
557     HRESULT hr = S_OK;
558
559     VALIDATE_ARG_RET((pAssemblyName != nullptr) && (ppAssembly != nullptr));
560     
561     EX_TRY
562     {
563         if (m_pParentBinder != nullptr)
564         {
565             // Delegate to parent binder.
566             hr = m_pParentBinder->BindAssemblyByName(pAssemblyName, ppAssembly);
567         }
568         else
569         {
570             hr = BindWinRTAssemblyByName(pAssemblyName, ppAssembly);
571         }
572     }
573     EX_CATCH_HRESULT(hr);
574
575     return hr;
576 }
577
578 //=====================================================================================================================
579 ReleaseHolder<CLRPrivAssemblyWinRT> 
580 CLRPrivBinderWinRT::FindAssemblyByFileName(
581     PCWSTR wszFileName)
582 {
583     LIMITED_METHOD_CONTRACT;
584     STATIC_CONTRACT_CAN_TAKE_LOCK;
585
586     ForbidSuspendThreadHolder suspend;
587     {
588         CrstHolder lock(&m_MapsLock);
589
590         const FileNameToAssemblyWinRTMapEntry * pEntry = m_FileNameToAssemblyMap.LookupPtr(wszFileName);
591         return (pEntry == nullptr) ? nullptr : clr::SafeAddRef(pEntry->m_pAssembly);
592     }
593 }
594
595 //=====================================================================================================================
596 // Add FileName -> CLRPrivAssemblyWinRT * mapping to the map (multi-thread safe).
597 // 
598 ReleaseHolder<CLRPrivAssemblyWinRT> 
599 CLRPrivBinderWinRT::AddFileNameToAssemblyMapping(
600     PCWSTR                 wszFileName, 
601     CLRPrivAssemblyWinRT * pAssembly)
602 {
603     STANDARD_VM_CONTRACT;
604     
605     _ASSERTE(pAssembly != nullptr);
606     
607     // We have to serialize all Add operations
608     CrstHolder lock(&m_MapsAddLock);
609     
610     // Wrapper for m_FileNameToAssemblyMap.Add that avoids call out into host
611     FileNameToAssemblyWinRTMap::AddPhases addCall;
612     
613     // 1. Preallocate one element
614     addCall.PreallocateForAdd(&m_FileNameToAssemblyMap);
615     {
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;
619         {
620             CrstHolder lock(&m_MapsLock);
621
622             const FileNameToAssemblyWinRTMapEntry * pEntry = m_FileNameToAssemblyMap.LookupPtr(wszFileName);
623             CLRPrivAssemblyWinRT * pResultAssembly = nullptr;
624             if (pEntry != nullptr)
625             {
626                 pResultAssembly = pEntry->m_pAssembly;
627                 
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();
630             }
631             else
632             {
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;
637                 addCall.Add(e);
638                 
639                 pResultAssembly = pAssembly;
640             }
641             return clr::SafeAddRef(pResultAssembly);
642         }
643     }
644     // 4. Cleanup the old memory (if any) - will be called by destructor of addCall
645     //addCall.DeleteOldTable();
646 }
647
648 //=====================================================================================================================
649 void 
650 CLRPrivBinderWinRT::RemoveFileNameToAssemblyMapping(
651     PCWSTR wszFileName)
652 {
653     LIMITED_METHOD_CONTRACT;
654     STATIC_CONTRACT_CAN_TAKE_LOCK;
655
656     ForbidSuspendThreadHolder suspend;
657     {
658         CrstHolder lock(&m_MapsLock);
659
660         m_FileNameToAssemblyMap.Remove(wszFileName);
661     }
662 }
663
664 //=====================================================================================================================
665 // Returns list of file names from code:m_NamespaceToFileNameListMap for the namespace
666 // 
667 HRESULT 
668 CLRPrivBinderWinRT::GetFileNameListForNamespace(
669     LPCWSTR                           wszNamespace, 
670     CLRPrivBinderUtil::WStringList ** ppFileNameList)
671 {
672     STANDARD_VM_CONTRACT;
673     STATIC_CONTRACT_CAN_TAKE_LOCK;
674
675     HRESULT hr = S_OK;
676     
677     CLRPrivBinderUtil::WStringList * pFileNameList = nullptr;
678     {
679         ForbidSuspendThreadHolder suspend;
680         {
681             CrstHolder lock(&m_MapsLock);
682
683             const NamespaceToFileNameListMapEntry * pEntry = m_NamespaceToFileNameListMap.LookupPtr(wszNamespace);
684             if (pEntry != nullptr)
685             {
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;
688             }
689         }
690     }
691     
692     if (pFileNameList != nullptr)
693     {
694         *ppFileNameList = pFileNameList;
695     }
696     else
697     {
698         CLRPrivBinderUtil::WStringListHolder hFileNameList;
699         LPCWSTR wszNamespaceRoResolve = wszNamespace;
700         
701 #ifndef CROSSGEN_COMPILE
702         if (m_fNamespaceResolutionKind == NamespaceResolutionKind_WindowsAPI)
703         {
704             CoTaskMemHSTRINGArrayHolder hFileNames;
705             
706             UINT32 cchNamespaceRoResolve;
707             IfFailRet(StringCchLength(wszNamespaceRoResolve, &cchNamespaceRoResolve));
708
709             CLRConfigStringHolder wszWinMDPathConfig;
710             LPWSTR wszWinMDPath = nullptr;
711             UINT32 cchWinMDPath = 0;
712
713             wszWinMDPath = m_appLocalWinMDPath;
714                 
715             if (wszWinMDPath != nullptr)
716             {
717                 IfFailRet(StringCchLength(wszWinMDPath, &cchWinMDPath));
718             }
719    
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
727                 &cFileNames, 
728                 &rgFileNames, 
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)
734             {
735                 if (!AppX::IsAppXProcess())
736                 {
737                     IfFailRet(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED));
738                 }
739             }
740
741
742             IfFailRet(hr);
743             if (hr != S_OK)
744             {   // Not expecting success codes other than S_OK.
745                 IfFailRet(E_UNEXPECTED);
746             }
747
748             hFileNames.Init(rgFileNames, cFileNames);
749         
750             for (DWORD i = 0; i < hFileNames.GetCount(); i++)
751             {
752                 UINT32  cchFileName = 0;
753                 LPCWSTR wszFileName = WindowsGetStringRawBuffer(
754                     hFileNames.GetAt(i), 
755                     &cchFileName);
756                 
757                 BOOL fSkipFilename = FALSE;
758                 if (!fSkipFilename)
759                     hFileNameList.InsertTail(wszFileName);
760             }
761         }
762         else
763         {
764             // This code is desktop specific. 
765             _ASSERTE(m_fNamespaceResolutionKind == NamespaceResolutionKind_DesignerResolveEvent);
766             
767             EX_TRY
768             {
769                 m_pTypeCache->RaiseDesignerNamespaceResolveEvent(wszNamespace, &hFileNameList);
770             }
771             EX_CATCH
772             {
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);
778                 }
779                 EX_RETHROW;
780             }
781             EX_END_CATCH_UNREACHABLE
782         }
783         
784 #else //CROSSGEN_COMPILE
785
786         DWORD     cFileNames = 0;
787         SString * rgFileNames = nullptr;
788
789         hr = Crossgen::CrossgenRoResolveNamespace(
790             wszNamespaceRoResolve,
791             &cFileNames, 
792             &rgFileNames); 
793
794         IfFailRet(hr);
795
796         if (cFileNames > 0)
797         {
798             _ASSERTE(cFileNames == 1); //only support mapping to one file in coregen
799             hFileNameList.InsertTail(rgFileNames->GetUnicode());
800             delete rgFileNames;
801         }
802         
803 #endif //CROSSGEN_COMPILE
804         
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();
810         }
811     }
812     
813     return hr;
814 } // CLRPrivBinderWinRT::GetFileNameListForNamespace
815
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.
820 // 
821 BOOL 
822 CLRPrivBinderWinRT::AddFileNameListForNamespace(
823     LPCWSTR                           wszNamespace, 
824     CLRPrivBinderUtil::WStringList *  pFileNameList, 
825     CLRPrivBinderUtil::WStringList ** ppFileNameList)
826 {
827     STANDARD_VM_CONTRACT;
828     
829     NewArrayHolder<WCHAR> wszEntryNamespace = DuplicateStringThrowing(wszNamespace);
830     
831     NamespaceToFileNameListMapEntry entry;
832     entry.m_wszNamespace = wszEntryNamespace.GetValue();
833     entry.m_pFileNameList = pFileNameList;
834     
835     // We have to serialize all Add operations
836     CrstHolder lock(&m_MapsAddLock);
837
838     // Wrapper for m_NamespaceToFileNameListMap.Add that avoids call out into host
839     NamespaceToFileNameListMap::AddPhases addCall;
840     
841     // Status if the element was added to the hash table or not
842     BOOL fAddedToCache = FALSE;
843     
844     // 1. Preallocate one element
845     addCall.PreallocateForAdd(&m_NamespaceToFileNameListMap);
846     {
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;
850         {
851             CrstHolder lock(&m_MapsLock);
852
853             const NamespaceToFileNameListMapEntry * pEntry = m_NamespaceToFileNameListMap.LookupPtr(wszNamespace);
854             if (pEntry == nullptr)
855             {
856                 // 3a. Add the element to the hash table (no call out into host)
857                 addCall.Add(entry);
858             
859                 // These values are now owned by the hash table element
860                 wszEntryNamespace.SuppressRelease();
861                 *ppFileNameList = pFileNameList;
862                 fAddedToCache = TRUE;
863             }
864             else
865             {   // Another thread beat us adding this entry to the hash table
866                 *ppFileNameList = pEntry->m_pFileNameList;
867                 
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);
871             }
872         }
873     }
874     // 4. Cleanup the old memory (if any), also called from the destructor of addCall
875     addCall.DeleteOldTable();
876     
877     return fAddedToCache;
878 } // CLRPrivBinderWinRT::AddFileNameListForNamespace
879
880 #endif //!DACCESS_COMPILE
881
882 //=====================================================================================================================
883 // Finds assembly with WinRT type if it is already loaded.
884 // 
885 PTR_Assembly 
886 CLRPrivBinderWinRT::FindAssemblyForTypeIfLoaded(
887     PTR_AppDomain pAppDomain, 
888     LPCUTF8       szNamespace, 
889     LPCUTF8       szClassName)
890 {
891     CONTRACTL
892     {
893         NOTHROW;
894         GC_NOTRIGGER;
895         FORBID_FAULT;
896         MODE_ANY;
897         SUPPORTS_DAC;
898     }
899     CONTRACTL_END
900     
901     WCHAR wszNamespace[MAX_CLASSNAME_LENGTH];
902     int cchNamespace = WszMultiByteToWideChar(CP_UTF8, 0, szNamespace, -1, wszNamespace, _countof(wszNamespace));
903     if (cchNamespace == 0)
904     {
905         return NULL;
906     }
907     
908     CLRPrivBinderUtil::WStringListElem * pFileNameElem= nullptr; 
909     const NamespaceToFileNameListMapEntry * pNamespaceEntry;
910     {
911         ForbidSuspendThreadHolder suspend;
912         {
913             CrstHolder lock(&m_MapsLock);
914
915             pNamespaceEntry = m_NamespaceToFileNameListMap.LookupPtr(wszNamespace);
916             if ((pNamespaceEntry == nullptr) || (pNamespaceEntry->m_pFileNameList == nullptr))
917             {
918                return NULL;
919             }
920
921             pFileNameElem = pNamespaceEntry->m_pFileNameList->GetHead();
922         }
923     }
924     
925     while (pFileNameElem != nullptr)
926     {
927         const WCHAR * wszFileName = pFileNameElem->GetValue();
928         PTR_CLRPrivAssemblyWinRT pPrivAssembly=NULL;
929         const FileNameToAssemblyWinRTMapEntry * pFileNameEntry;
930         {
931             ForbidSuspendThreadHolder suspend;
932             {
933                 CrstHolder lock(&m_MapsLock);
934                 
935                 pFileNameEntry = m_FileNameToAssemblyMap.LookupPtr(wszFileName);
936                 if (pFileNameEntry == nullptr || pFileNameEntry->m_pAssembly == nullptr)
937                 {
938                     return NULL;
939                 }
940
941                 pPrivAssembly = pFileNameEntry->m_pAssembly;
942             }
943         }
944
945         if (pPrivAssembly == NULL)
946         {
947             return NULL;
948         }
949         
950         _ASSERT(((void *)(CLRPrivAssemblyWinRT *)0x100) == 
951                 ((void *)(ICLRPrivAssembly *)(CLRPrivAssemblyWinRT *)0x100));
952         
953         PTR_Assembly pAssembly = NULL;
954         HRESULT hr = m_pTypeCache->ContainsTypeIfLoaded(
955             pAppDomain, 
956             dac_cast<PTR_ICLRPrivAssembly>(pPrivAssembly), 
957             szNamespace, 
958             szClassName, 
959             &pAssembly);
960         if (hr == S_OK)
961         {   // The type we are looking for has been found in this assembly
962             _ASSERTE(pAssembly != nullptr);
963             return pAssembly;
964         }
965         if (FAILED(hr))
966         {   // Assembly was not loaded
967             return NULL;
968         }
969         // Type was not found in the assembly
970         _ASSERTE(hr == S_FALSE);
971         
972         // Try next file name for this namespace
973         pFileNameElem = CLRPrivBinderUtil::WStringList::GetNext(pFileNameElem);
974     }
975     
976     return NULL;
977 } // CLRPrivBinderWinRT::FindAssemblyForTypeIfLoaded
978
979 #ifndef DACCESS_COMPILE
980
981
982 //=====================================================================================================================
983 CLRPrivAssemblyWinRT::CLRPrivAssemblyWinRT(
984     CLRPrivBinderWinRT *      pBinder, 
985     CLRPrivResourcePathImpl * pResourceIL, 
986     IBindResult *             pIBindResult,
987     BOOL                      fShareable)
988     : m_pBinder(nullptr),
989       m_pResourceIL(nullptr),
990       m_pIResourceNI(nullptr),
991       m_pIBindResult(nullptr),
992       m_fShareable(fShareable),
993       m_dwImageTypes(0)
994 {
995     STANDARD_VM_CONTRACT;
996     VALIDATE_ARG_THROW((pBinder != nullptr) && (pResourceIL != nullptr) && (pIBindResult != nullptr));
997
998     m_pBinder = clr::SafeAddRef(pBinder);
999     m_pResourceIL = clr::SafeAddRef(pResourceIL);
1000     m_pIBindResult = clr::SafeAddRef(pIBindResult);
1001 }
1002
1003 //=====================================================================================================================
1004 CLRPrivAssemblyWinRT::~CLRPrivAssemblyWinRT()
1005 {
1006     LIMITED_METHOD_CONTRACT;
1007     clr::SafeRelease(m_pIResourceNI);
1008 }
1009
1010 //=====================================================================================================================
1011 // Implements interface method code:IUnknown::Release.
1012 // Overridden to implement self-removal from assembly map code:CLRPrivBinderWinRT::m_FileNameToAssemblyMap.
1013 // 
1014 ULONG CLRPrivAssemblyWinRT::Release()
1015 {
1016     LIMITED_METHOD_CONTRACT;
1017     STATIC_CONTRACT_CAN_TAKE_LOCK;
1018     _ASSERTE(m_cRef > 0);
1019     
1020     ULONG cRef;
1021     
1022     {
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;
1029         {
1030             CrstHolder lock(&m_pBinder->m_MapsLock);
1031             cRef = InterlockedDecrement(&m_cRef);
1032             if (cRef == 0)
1033             {
1034                 m_pBinder->RemoveFileNameToAssemblyMapping(m_pResourceIL->GetPath());
1035             }
1036         }
1037     }
1038     
1039     // Note: We cannot deallocate memory in the ForbidSuspendThread region
1040     if (cRef == 0)
1041     {
1042         delete this;
1043     }
1044     
1045     return cRef;
1046 } // CLRPrivAssemblyWinRT::Release
1047
1048 //=====================================================================================================================
1049 // Implements interface method code:ICLRPrivAssembly::IsShareable.
1050 // 
1051 HRESULT CLRPrivAssemblyWinRT::IsShareable(
1052     BOOL * pbIsShareable)
1053 {
1054     LIMITED_METHOD_CONTRACT;
1055
1056     VALIDATE_ARG_RET(pbIsShareable != nullptr);
1057
1058     *pbIsShareable = m_fShareable;
1059     return S_OK;
1060 }
1061
1062 //=====================================================================================================================
1063 // Implements interface method code:ICLRPrivAssembly::GetAvailableImageTypes.
1064 // 
1065 HRESULT CLRPrivAssemblyWinRT::GetAvailableImageTypes(
1066     LPDWORD pdwImageTypes)
1067 {
1068     STANDARD_BIND_CONTRACT;
1069
1070     HRESULT hr = S_OK;
1071
1072     VALIDATE_ARG_RET(pdwImageTypes != nullptr);
1073
1074     EX_TRY
1075     {
1076         IfFailGo(EnsureAvailableImageTypes());
1077     
1078         *pdwImageTypes = m_dwImageTypes;
1079         hr = S_OK;
1080     ErrExit:
1081         ;
1082     }
1083     EX_CATCH_HRESULT(hr);
1084     
1085     return hr;
1086 }
1087
1088
1089 //=====================================================================================================================
1090 // Implements interface method code:ICLRPrivAssembly::GetImageResource.
1091 // 
1092 HRESULT CLRPrivAssemblyWinRT::GetImageResource(
1093     DWORD               dwImageType, 
1094     DWORD *             pdwImageType, 
1095     ICLRPrivResource ** ppIResource)
1096 {
1097     STANDARD_BIND_CONTRACT;
1098     HRESULT hr = S_OK;
1099     
1100     VALIDATE_ARG_RET((ppIResource != nullptr) && (m_pIBindResult != nullptr));
1101     
1102     EX_TRY
1103     {
1104         IfFailGo(EnsureAvailableImageTypes());
1105
1106         DWORD _dwImageType;
1107         if (pdwImageType == nullptr)
1108         {
1109             pdwImageType = &_dwImageType;
1110         }
1111         
1112         if ((dwImageType & ASSEMBLY_IMAGE_TYPE_NATIVE) == ASSEMBLY_IMAGE_TYPE_NATIVE)
1113         {
1114             if (m_pIResourceNI == nullptr)
1115             {
1116                 IfFailGo(CLR_E_BIND_IMAGE_UNAVAILABLE);
1117             }
1118
1119             *ppIResource = clr::SafeAddRef(m_pIResourceNI);
1120             *pdwImageType = ASSEMBLY_IMAGE_TYPE_NATIVE;
1121         }
1122         else if ((dwImageType & ASSEMBLY_IMAGE_TYPE_IL) == ASSEMBLY_IMAGE_TYPE_IL)
1123         {
1124             *ppIResource = clr::SafeAddRef(m_pResourceIL);
1125             *pdwImageType = ASSEMBLY_IMAGE_TYPE_IL;
1126         }
1127         else
1128         {
1129             hr = CLR_E_BIND_IMAGE_UNAVAILABLE;
1130         }
1131     ErrExit:
1132         ;
1133     }
1134     EX_CATCH_HRESULT(hr);
1135     
1136     return hr;
1137 }
1138
1139 //=====================================================================================================================
1140 // Implements interface method code:ICLRPrivBinder::VerifyBind.
1141 // 
1142 HRESULT CLRPrivBinderWinRT::VerifyBind(
1143     IAssemblyName *        pAssemblyName, 
1144     ICLRPrivAssembly *     pAssembly, 
1145     ICLRPrivAssemblyInfo * pAssemblyInfo)
1146 {
1147     STANDARD_BIND_CONTRACT;
1148     HRESULT hr = S_OK;
1149
1150     VALIDATE_ARG_RET(pAssemblyInfo != nullptr);
1151     
1152     UINT_PTR binderID;
1153     IfFailRet(pAssembly->GetBinderID(&binderID));
1154     if (binderID != reinterpret_cast<UINT_PTR>(this))
1155     {
1156         return pAssembly->VerifyBind(pAssemblyName, pAssembly, pAssemblyInfo);
1157     }
1158     
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.
1161     return S_OK;
1162 }
1163
1164 //=====================================================================================================================
1165 // Implements interface method code:ICLRPrivBinder::GetBinderID.
1166 // 
1167 HRESULT CLRPrivBinderWinRT::GetBinderID(
1168     UINT_PTR * pBinderId)
1169 {
1170     LIMITED_METHOD_CONTRACT;
1171
1172     *pBinderId = reinterpret_cast<UINT_PTR>(this);
1173     return S_OK;
1174 }
1175
1176 //=====================================================================================================================
1177 HRESULT CLRPrivBinderWinRT::FindWinRTAssemblyBySpec(
1178     LPVOID pvAppDomain,
1179     LPVOID pvAssemblySpec,
1180     HRESULT * pResult,
1181     ICLRPrivAssembly ** ppAssembly)
1182 {
1183     STATIC_CONTRACT_WRAPPER;
1184     return E_FAIL; 
1185 }
1186
1187
1188 //=====================================================================================================================
1189 HRESULT CLRPrivAssemblyWinRT::GetIBindResult(
1190     IBindResult ** ppIBindResult)
1191 {
1192     LIMITED_METHOD_CONTRACT;
1193     
1194     VALIDATE_ARG_RET(ppIBindResult != nullptr);
1195     VALIDATE_CONDITION((m_pIBindResult != nullptr), return E_UNEXPECTED);
1196     
1197     *ppIBindResult = clr::SafeAddRef(m_pIBindResult);
1198     
1199     return S_OK;
1200 }
1201
1202 //=====================================================================================================================
1203 HRESULT CLRPrivAssemblyWinRT::EnsureAvailableImageTypes()
1204 {
1205     STANDARD_VM_CONTRACT;
1206     HRESULT hr = S_OK;
1207
1208     DWORD dwImageTypesLocal = m_dwImageTypes;
1209
1210     // If image types has not yet been set, attempt to bind to native assembly
1211     if (dwImageTypesLocal == 0)
1212     {
1213         if (m_pIResourceNI == nullptr)
1214         {
1215             if (m_pIBindResult->HasNativeImage())
1216             {
1217                 SString sPath = m_pIBindResult->GetNativeImage()->GetPath();
1218                 m_pIResourceNI = new CLRPrivResourcePathImpl(sPath.GetUnicode());
1219                 m_pIResourceNI->AddRef();
1220             }
1221             IfFailGo(hr);
1222         }
1223
1224         DWORD dwImageTypes = 0;
1225
1226         if (m_pResourceIL != nullptr)
1227             dwImageTypes |= ASSEMBLY_IMAGE_TYPE_IL;
1228
1229         if (m_pIResourceNI != nullptr)
1230             dwImageTypes |= ASSEMBLY_IMAGE_TYPE_NATIVE;
1231
1232         m_dwImageTypes = dwImageTypes;
1233     }
1234 ErrExit:
1235
1236     return hr;
1237 }
1238
1239 //=====================================================================================================================
1240 //static
1241 HRESULT CLRPrivAssemblyWinRT::GetIBindResult(
1242     ICLRPrivAssembly * pPrivAssembly, 
1243     IBindResult **     ppIBindResult)
1244 {
1245     LIMITED_METHOD_CONTRACT;
1246     
1247     HRESULT hr;
1248     
1249     VALIDATE_ARG_RET(pPrivAssembly != nullptr);
1250     
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);
1255     
1256     return pPrivAssemblyWinRT->GetIBindResult(ppIBindResult);
1257 }
1258
1259 #endif //!DACCESS_COMPILE