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#include "common.h"
7#include "vars.hpp"
8#include "excep.h"
9#include "interoputil.h"
10#include "cachelinealloc.h"
11#include "comutilnative.h"
12#include "field.h"
13#include "guidfromname.h"
14#include "eeconfig.h"
15#include "mlinfo.h"
16#include "comdelegate.h"
17#include "appdomain.hpp"
18#include "prettyprintsig.h"
19#include "util.hpp"
20#include "interopconverter.h"
21#include "wrappers.h"
22#include "invokeutil.h"
23#include "mdaassistants.h"
24#include "comcallablewrapper.h"
25#include "../md/compiler/custattr.h"
26#include "siginfo.hpp"
27#include "eemessagebox.h"
28#include "finalizerthread.h"
29
30#ifdef FEATURE_COMINTEROP
31#include "cominterfacemarshaler.h"
32#include <roerrorapi.h>
33#endif
34
35#ifdef FEATURE_COMINTEROP_APARTMENT_SUPPORT
36#include "olecontexthelpers.h"
37#endif // FEATURE_COMINTEROP_APARTMENT_SUPPORT
38
39#ifdef FEATURE_COMINTEROP
40#include "dispex.h"
41#include "runtimecallablewrapper.h"
42#include "comtoclrcall.h"
43#include "clrtocomcall.h"
44#include "comcache.h"
45#include "commtmemberinfomap.h"
46#include "olevariant.h"
47#include "stdinterfaces.h"
48#include "notifyexternals.h"
49#include "typeparse.h"
50#include "..\md\winmd\inc\adapter.h"
51#include "winrttypenameconverter.h"
52#include "interoputil.inl"
53#include "typestring.h"
54
55#ifndef __ILanguageExceptionErrorInfo_INTERFACE_DEFINED__
56#define __ILanguageExceptionErrorInfo_INTERFACE_DEFINED__
57 EXTERN_C const IID IID_ILanguageExceptionErrorInfo;
58
59 MIDL_INTERFACE("04a2dbf3-df83-116c-0946-0812abf6e07d")
60 ILanguageExceptionErrorInfo : public IUnknown
61 {
62 public:
63 virtual HRESULT STDMETHODCALLTYPE GetLanguageException(
64 /* [out] */ __RPC__deref_out_opt IUnknown **languageException) = 0;
65
66 };
67#endif // !__ILanguageExceptionErrorInfo_INTERFACE_DEFINED__
68
69#define STANDARD_DISPID_PREFIX W("[DISPID")
70#define STANDARD_DISPID_PREFIX_LENGTH 7
71#define GET_ENUMERATOR_METHOD_NAME W("GetEnumerator")
72
73// Note: All of the methods below must appear in the order in which the interfaces are defined in IL.
74// WinRT -> CLR adapters
75static const BinderMethodID s_stubsIterableToEnumerable[] =
76{
77 METHOD__ITERABLE_TO_ENUMERABLE_ADAPTER__GET_ENUMERATOR_STUB
78};
79static const BinderMethodID s_stubsVectorToList[] =
80{
81 METHOD__VECTOR_TO_LIST_ADAPTER__INDEXER_GET,
82 METHOD__VECTOR_TO_LIST_ADAPTER__INDEXER_SET,
83 METHOD__VECTOR_TO_LIST_ADAPTER__INDEX_OF,
84 METHOD__VECTOR_TO_LIST_ADAPTER__INSERT,
85 METHOD__VECTOR_TO_LIST_ADAPTER__REMOVE_AT
86};
87static const BinderMethodID s_stubsVectorToCollection[] =
88{
89 METHOD__VECTOR_TO_COLLECTION_ADAPTER__COUNT,
90 METHOD__VECTOR_TO_COLLECTION_ADAPTER__IS_READ_ONLY,
91 METHOD__VECTOR_TO_COLLECTION_ADAPTER__ADD,
92 METHOD__VECTOR_TO_COLLECTION_ADAPTER__CLEAR,
93 METHOD__VECTOR_TO_COLLECTION_ADAPTER__CONTAINS,
94 METHOD__VECTOR_TO_COLLECTION_ADAPTER__COPY_TO,
95 METHOD__VECTOR_TO_COLLECTION_ADAPTER__REMOVE
96};
97static const BinderMethodID s_stubsMapToDictionary[] =
98{
99 METHOD__MAP_TO_DICTIONARY_ADAPTER__INDEXER_GET,
100 METHOD__MAP_TO_DICTIONARY_ADAPTER__INDEXER_SET,
101 METHOD__MAP_TO_DICTIONARY_ADAPTER__KEYS,
102 METHOD__MAP_TO_DICTIONARY_ADAPTER__VALUES,
103 METHOD__MAP_TO_DICTIONARY_ADAPTER__CONTAINS_KEY,
104 METHOD__MAP_TO_DICTIONARY_ADAPTER__ADD,
105 METHOD__MAP_TO_DICTIONARY_ADAPTER__REMOVE,
106 METHOD__MAP_TO_DICTIONARY_ADAPTER__TRY_GET_VALUE
107};
108static const BinderMethodID s_stubsMapToCollection[] =
109{
110 METHOD__MAP_TO_COLLECTION_ADAPTER__COUNT,
111 METHOD__MAP_TO_COLLECTION_ADAPTER__IS_READ_ONLY,
112 METHOD__MAP_TO_COLLECTION_ADAPTER__ADD,
113 METHOD__MAP_TO_COLLECTION_ADAPTER__CLEAR,
114 METHOD__MAP_TO_COLLECTION_ADAPTER__CONTAINS,
115 METHOD__MAP_TO_COLLECTION_ADAPTER__COPY_TO,
116 METHOD__MAP_TO_COLLECTION_ADAPTER__REMOVE
117};
118static const BinderMethodID s_stubsIVectorViewToIReadOnlyCollection[] =
119{
120 METHOD__IVECTORVIEW_TO_IREADONLYCOLLECTION_ADAPTER__COUNT,
121};
122static const BinderMethodID s_stubsIVectorViewToIReadOnlyList[] =
123{
124 METHOD__IVECTORVIEW_TO_IREADONLYLIST_ADAPTER__INDEXER_GET,
125};
126static const BinderMethodID s_stubsIMapViewToIReadOnlyCollection[] =
127{
128 METHOD__IMAPVIEW_TO_IREADONLYCOLLECTION_ADAPTER__COUNT,
129};
130static const BinderMethodID s_stubsIMapViewToIReadOnlyDictionary[] =
131{
132 METHOD__IMAPVIEW_TO_IREADONLYDICTIONARY_ADAPTER__CONTAINSKEY,
133 METHOD__IMAPVIEW_TO_IREADONLYDICTIONARY_ADAPTER__TRYGETVALUE,
134 METHOD__IMAPVIEW_TO_IREADONLYDICTIONARY_ADAPTER__INDEXER_GET,
135 METHOD__IMAPVIEW_TO_IREADONLYDICTIONARY_ADAPTER__KEYS,
136 METHOD__IMAPVIEW_TO_IREADONLYDICTIONARY_ADAPTER__VALUES
137};
138static const BinderMethodID s_stubsBindableIterableToEnumerable[] =
139{
140 METHOD__BINDABLEITERABLE_TO_ENUMERABLE_ADAPTER__GET_ENUMERATOR_STUB
141};
142static const BinderMethodID s_stubsBindableVectorToList[] =
143{
144 METHOD__BINDABLEVECTOR_TO_LIST_ADAPTER__INDEXER_GET,
145 METHOD__BINDABLEVECTOR_TO_LIST_ADAPTER__INDEXER_SET,
146 METHOD__BINDABLEVECTOR_TO_LIST_ADAPTER__ADD,
147 METHOD__BINDABLEVECTOR_TO_LIST_ADAPTER__CONTAINS,
148 METHOD__BINDABLEVECTOR_TO_LIST_ADAPTER__CLEAR,
149 METHOD__BINDABLEVECTOR_TO_LIST_ADAPTER__IS_READ_ONLY,
150 METHOD__BINDABLEVECTOR_TO_LIST_ADAPTER__IS_FIXED_SIZE,
151 METHOD__BINDABLEVECTOR_TO_LIST_ADAPTER__INDEX_OF,
152 METHOD__BINDABLEVECTOR_TO_LIST_ADAPTER__INSERT,
153 METHOD__BINDABLEVECTOR_TO_LIST_ADAPTER__REMOVE,
154 METHOD__BINDABLEVECTOR_TO_LIST_ADAPTER__REMOVE_AT
155};
156static const BinderMethodID s_stubsBindableVectorToCollection[] =
157{
158 METHOD__BINDABLEVECTOR_TO_COLLECTION_ADAPTER__COPY_TO,
159 METHOD__BINDABLEVECTOR_TO_COLLECTION_ADAPTER__COUNT,
160 METHOD__BINDABLEVECTOR_TO_COLLECTION_ADAPTER__SYNC_ROOT,
161 METHOD__BINDABLEVECTOR_TO_COLLECTION_ADAPTER__IS_SYNCHRONIZED
162};
163static const BinderMethodID s_stubsNotifyCollectionChangedToManaged[] =
164{
165 (BinderMethodID)0, // add_CollectionChanged
166 (BinderMethodID)1, // remove_CollectionChanged
167};
168static const BinderMethodID s_stubsNotifyPropertyChangedToManaged[] =
169{
170 (BinderMethodID)0, // add_PropertyChanged
171 (BinderMethodID)1, // remove_PropertyChanged
172};
173static const BinderMethodID s_stubsICommandToManaged[] =
174{
175 (BinderMethodID)0, // add_CanExecuteChanged
176 (BinderMethodID)1, // remove_CanExecuteChanged
177 (BinderMethodID)2, // CanExecute
178 (BinderMethodID)3, // Execute
179};
180
181static const BinderMethodID s_stubsClosableToDisposable[] =
182{
183 METHOD__ICLOSABLE_TO_IDISPOSABLE_ADAPTER__DISPOSE
184};
185
186// CLR -> WinRT adapters
187static const BinderMethodID s_stubsEnumerableToIterable[] =
188{
189 METHOD__ENUMERABLE_TO_ITERABLE_ADAPTER__FIRST_STUB
190};
191static const BinderMethodID s_stubsListToVector[] =
192{
193 METHOD__LIST_TO_VECTOR_ADAPTER__GET_AT,
194 METHOD__LIST_TO_VECTOR_ADAPTER__SIZE,
195 METHOD__LIST_TO_VECTOR_ADAPTER__GET_VIEW,
196 METHOD__LIST_TO_VECTOR_ADAPTER__INDEX_OF,
197 METHOD__LIST_TO_VECTOR_ADAPTER__SET_AT,
198 METHOD__LIST_TO_VECTOR_ADAPTER__INSERT_AT,
199 METHOD__LIST_TO_VECTOR_ADAPTER__REMOVE_AT,
200 METHOD__LIST_TO_VECTOR_ADAPTER__APPEND,
201 METHOD__LIST_TO_VECTOR_ADAPTER__REMOVE_AT_END,
202 METHOD__LIST_TO_VECTOR_ADAPTER__CLEAR,
203 METHOD__LIST_TO_VECTOR_ADAPTER__GET_MANY,
204 METHOD__LIST_TO_VECTOR_ADAPTER__REPLACE_ALL,
205};
206static const BinderMethodID s_stubsDictionaryToMap[] =
207{
208 METHOD__DICTIONARY_TO_MAP_ADAPTER__LOOKUP,
209 METHOD__DICTIONARY_TO_MAP_ADAPTER__SIZE,
210 METHOD__DICTIONARY_TO_MAP_ADAPTER__HAS_KEY,
211 METHOD__DICTIONARY_TO_MAP_ADAPTER__GET_VIEW,
212 METHOD__DICTIONARY_TO_MAP_ADAPTER__INSERT,
213 METHOD__DICTIONARY_TO_MAP_ADAPTER__REMOVE,
214 METHOD__DICTIONARY_TO_MAP_ADAPTER__CLEAR,
215};
216static const BinderMethodID s_stubsIReadOnlyListToIVectorView[] =
217{
218 METHOD__IREADONLYLIST_TO_IVECTORVIEW_ADAPTER__GETAT,
219 METHOD__IREADONLYLIST_TO_IVECTORVIEW_ADAPTER__SIZE,
220 METHOD__IREADONLYLIST_TO_IVECTORVIEW_ADAPTER__INDEXOF,
221 METHOD__IREADONLYLIST_TO_IVECTORVIEW_ADAPTER__GETMANY,
222};
223static const BinderMethodID s_stubsIReadOnlyDictionaryToIMapView[] =
224{
225 METHOD__IREADONLYDICTIONARY_TO_IMAPVIEW_ADAPTER__LOOKUP,
226 METHOD__IREADONLYDICTIONARY_TO_IMAPVIEW_ADAPTER__SIZE,
227 METHOD__IREADONLYDICTIONARY_TO_IMAPVIEW_ADAPTER__HASKEY,
228 METHOD__IREADONLYDICTIONARY_TO_IMAPVIEW_ADAPTER__SPLIT,
229};
230static const BinderMethodID s_stubsEnumerableToBindableIterable[] =
231{
232 METHOD__ENUMERABLE_TO_BINDABLEITERABLE_ADAPTER__FIRST_STUB
233};
234static const BinderMethodID s_stubsListToBindableVector[] =
235{
236 METHOD__LIST_TO_BINDABLEVECTOR_ADAPTER__GET_AT,
237 METHOD__LIST_TO_BINDABLEVECTOR_ADAPTER__SIZE,
238 METHOD__LIST_TO_BINDABLEVECTOR_ADAPTER__GET_VIEW,
239 METHOD__LIST_TO_BINDABLEVECTOR_ADAPTER__INDEX_OF,
240 METHOD__LIST_TO_BINDABLEVECTOR_ADAPTER__SET_AT,
241 METHOD__LIST_TO_BINDABLEVECTOR_ADAPTER__INSERT_AT,
242 METHOD__LIST_TO_BINDABLEVECTOR_ADAPTER__REMOVE_AT,
243 METHOD__LIST_TO_BINDABLEVECTOR_ADAPTER__APPEND,
244 METHOD__LIST_TO_BINDABLEVECTOR_ADAPTER__REMOVE_AT_END,
245 METHOD__LIST_TO_BINDABLEVECTOR_ADAPTER__CLEAR
246};
247static const BinderMethodID s_stubsNotifyCollectionChangedToWinRT[] =
248{
249 (BinderMethodID)0, // add_CollectionChanged
250 (BinderMethodID)1, // remove_CollectionChanged
251};
252static const BinderMethodID s_stubsNotifyPropertyChangedToWinRT[] =
253{
254 (BinderMethodID)0, // add_PropertyChanged
255 (BinderMethodID)1, // remove_PropertyChanged
256};
257static const BinderMethodID s_stubsICommandToWinRT[] =
258{
259 (BinderMethodID)0, // add_CanExecuteChanged
260 (BinderMethodID)1, // remove_CanExecuteChanged
261 (BinderMethodID)2, // CanExecute
262 (BinderMethodID)3, // Execute
263};
264
265
266static const LPCUTF8 s_stubNamesNotifyCollectionChanged[] =
267{
268 "add_CollectionChanged", // 0
269 "remove_CollectionChanged", // 1
270};
271
272static const LPCUTF8 s_stubNamesNotifyPropertyChanged[] =
273{
274 "add_PropertyChanged", // 0
275 "remove_PropertyChanged", // 1
276};
277
278static const LPCUTF8 s_stubNamesICommand[] =
279{
280 "add_CanExecuteChanged", // 0
281 "remove_CanExecuteChanged", // 1
282 "CanExecute", // 2
283 "Execute", // 3
284};
285
286static const BinderMethodID s_stubsDisposableToClosable[] =
287{
288 METHOD__IDISPOSABLE_TO_ICLOSABLE_ADAPTER__CLOSE
289};
290
291DEFINE_ASM_QUAL_TYPE_NAME(NCCWINRT_ASM_QUAL_TYPE_NAME, g_INotifyCollectionChanged_WinRTName, g_SystemRuntimeWindowsRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken);
292DEFINE_ASM_QUAL_TYPE_NAME(NCCMA_ASM_QUAL_TYPE_NAME, g_NotifyCollectionChangedToManagedAdapterName, g_SystemRuntimeWindowsRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken);
293DEFINE_ASM_QUAL_TYPE_NAME(NCCWA_ASM_QUAL_TYPE_NAME, g_NotifyCollectionChangedToWinRTAdapterName, g_SystemRuntimeWindowsRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken);
294DEFINE_ASM_QUAL_TYPE_NAME(NPCWINRT_ASM_QUAL_TYPE_NAME, g_INotifyPropertyChanged_WinRTName, g_SystemRuntimeWindowsRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken);
295DEFINE_ASM_QUAL_TYPE_NAME(NPCMA_ASM_QUAL_TYPE_NAME, g_NotifyPropertyChangedToManagedAdapterName, g_SystemRuntimeWindowsRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken);
296DEFINE_ASM_QUAL_TYPE_NAME(NPCWA_ASM_QUAL_TYPE_NAME, g_NotifyPropertyChangedToWinRTAdapterName, g_SystemRuntimeWindowsRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken);
297DEFINE_ASM_QUAL_TYPE_NAME(CMDWINRT_ASM_QUAL_TYPE_NAME, g_ICommand_WinRTName, g_SystemRuntimeWindowsRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken);
298DEFINE_ASM_QUAL_TYPE_NAME(CMDMA_ASM_QUAL_TYPE_NAME, g_ICommandToManagedAdapterName, g_SystemRuntimeWindowsRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken);
299DEFINE_ASM_QUAL_TYPE_NAME(CMDWA_ASM_QUAL_TYPE_NAME, g_ICommandToWinRTAdapterName, g_SystemRuntimeWindowsRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken);
300DEFINE_ASM_QUAL_TYPE_NAME(NCCEHWINRT_ASM_QUAL_TYPE_NAME, g_NotifyCollectionChangedEventHandler_WinRT, g_SystemRuntimeWindowsRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken);
301DEFINE_ASM_QUAL_TYPE_NAME(PCEHWINRT_ASM_QUAL_TYPE_NAME, g_PropertyChangedEventHandler_WinRT_Name, g_SystemRuntimeWindowsRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken);
302
303const WinRTInterfaceRedirector::NonMscorlibRedirectedInterfaceInfo WinRTInterfaceRedirector::s_rNonMscorlibInterfaceInfos[3] =
304{
305 {
306 NCCWINRT_ASM_QUAL_TYPE_NAME,
307 NCCMA_ASM_QUAL_TYPE_NAME,
308 NCCWA_ASM_QUAL_TYPE_NAME,
309 s_stubNamesNotifyCollectionChanged
310 },
311 {
312 NPCWINRT_ASM_QUAL_TYPE_NAME,
313 NPCMA_ASM_QUAL_TYPE_NAME,
314 NPCWA_ASM_QUAL_TYPE_NAME,
315 s_stubNamesNotifyPropertyChanged
316 },
317 {
318 CMDWINRT_ASM_QUAL_TYPE_NAME,
319 CMDMA_ASM_QUAL_TYPE_NAME,
320 CMDWA_ASM_QUAL_TYPE_NAME,
321 s_stubNamesICommand
322 },
323};
324
325#define SYSTEMDLL__INOTIFYCOLLECTIONCHANGED ((BinderClassID)(WinRTInterfaceRedirector::NON_MSCORLIB_MARKER | 0))
326#define SYSTEMDLL__INOTIFYPROPERTYCHANGED ((BinderClassID)(WinRTInterfaceRedirector::NON_MSCORLIB_MARKER | 1))
327#define SYSTEMDLL__ICOMMAND ((BinderClassID)(WinRTInterfaceRedirector::NON_MSCORLIB_MARKER | 2))
328
329const WinRTInterfaceRedirector::RedirectedInterfaceStubInfo WinRTInterfaceRedirector::s_rInterfaceStubInfos[2 * s_NumRedirectedInterfaces] =
330{
331 { CLASS__IITERABLE, _countof(s_stubsIterableToEnumerable), s_stubsIterableToEnumerable, _countof(s_stubsEnumerableToIterable), s_stubsEnumerableToIterable },
332 { CLASS__IVECTOR, _countof(s_stubsVectorToList), s_stubsVectorToList, _countof(s_stubsListToVector), s_stubsListToVector },
333 { CLASS__IMAP, _countof(s_stubsMapToDictionary), s_stubsMapToDictionary, _countof(s_stubsDictionaryToMap), s_stubsDictionaryToMap },
334 { CLASS__IVECTORVIEW, _countof(s_stubsIVectorViewToIReadOnlyList), s_stubsIVectorViewToIReadOnlyList, _countof(s_stubsIReadOnlyListToIVectorView), s_stubsIReadOnlyListToIVectorView },
335 { CLASS__IMAPVIEW, _countof(s_stubsIMapViewToIReadOnlyDictionary), s_stubsIMapViewToIReadOnlyDictionary, _countof(s_stubsIReadOnlyDictionaryToIMapView), s_stubsIReadOnlyDictionaryToIMapView },
336 { CLASS__IBINDABLEITERABLE, _countof(s_stubsBindableIterableToEnumerable), s_stubsBindableIterableToEnumerable, _countof(s_stubsEnumerableToBindableIterable), s_stubsEnumerableToBindableIterable },
337 { CLASS__IBINDABLEVECTOR, _countof(s_stubsBindableVectorToList), s_stubsBindableVectorToList, _countof(s_stubsListToBindableVector), s_stubsListToBindableVector },
338 { SYSTEMDLL__INOTIFYCOLLECTIONCHANGED, _countof(s_stubsNotifyCollectionChangedToManaged), s_stubsNotifyCollectionChangedToManaged, _countof(s_stubsNotifyCollectionChangedToWinRT), s_stubsNotifyCollectionChangedToWinRT },
339 { SYSTEMDLL__INOTIFYPROPERTYCHANGED, _countof(s_stubsNotifyPropertyChangedToManaged), s_stubsNotifyPropertyChangedToManaged, _countof(s_stubsNotifyPropertyChangedToWinRT), s_stubsNotifyPropertyChangedToWinRT },
340 { SYSTEMDLL__ICOMMAND, _countof(s_stubsICommandToManaged), s_stubsICommandToManaged, _countof(s_stubsICommandToWinRT), s_stubsICommandToWinRT },
341 { CLASS__ICLOSABLE, _countof(s_stubsClosableToDisposable), s_stubsClosableToDisposable, _countof(s_stubsClosableToDisposable), s_stubsDisposableToClosable },
342
343 // ICollection/ICollection<> stubs:
344 { (BinderClassID)0, 0, NULL, 0, NULL },
345 { CLASS__IVECTOR, _countof(s_stubsVectorToCollection), s_stubsVectorToCollection, 0, NULL },
346 { CLASS__IMAP, _countof(s_stubsMapToCollection), s_stubsMapToCollection, 0, NULL },
347 { CLASS__IVECTORVIEW, _countof(s_stubsIVectorViewToIReadOnlyCollection), s_stubsIVectorViewToIReadOnlyCollection, 0, NULL },
348 { CLASS__IMAPVIEW, _countof(s_stubsIMapViewToIReadOnlyCollection), s_stubsIMapViewToIReadOnlyCollection, 0, NULL },
349 { (BinderClassID)0, 0, NULL, 0, NULL },
350 { CLASS__IBINDABLEVECTOR, _countof(s_stubsBindableVectorToCollection), s_stubsBindableVectorToCollection, 0, NULL },
351 { (BinderClassID)0, 0, NULL, 0, NULL },
352 { (BinderClassID)0, 0, NULL, 0, NULL },
353 { (BinderClassID)0, 0, NULL, 0, NULL },
354 { (BinderClassID)0, 0, NULL, 0, NULL },
355};
356
357#ifdef _DEBUG
358 VOID IntializeInteropLogging();
359#endif
360
361struct ByrefArgumentInfo
362{
363 BOOL m_bByref;
364 VARIANT m_Val;
365};
366
367// Flag indicating if COM support has been initialized.
368BOOL g_fComStarted = FALSE;
369
370#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
371void AllocateComClassObject(ComClassFactory* pComClsFac, OBJECTREF* pComObj);
372#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
373
374#endif // FEATURE_COMINTEROP
375
376
377#ifndef CROSSGEN_COMPILE
378//------------------------------------------------------------------
379// setup error info for exception object
380//
381#ifdef FEATURE_COMINTEROP
382HRESULT SetupErrorInfo(OBJECTREF pThrownObject, ComCallMethodDesc *pCMD)
383{
384 CONTRACTL
385 {
386 NOTHROW;
387 GC_TRIGGERS;
388 MODE_COOPERATIVE;
389 PRECONDITION(CheckPointer(pCMD));
390 }
391 CONTRACTL_END;
392
393 return SetupErrorInfo(pThrownObject, pCMD->IsWinRTCall());
394}
395
396typedef BOOL (*pfnRoOriginateLanguageException)(HRESULT error,
397 HSTRING message,
398 IUnknown* languageException);
399typedef HRESULT (*pfnGetRestrictedErrorInfo)(IRestrictedErrorInfo ** ppRestrictedErrorInfo);
400typedef HRESULT (*pfnSetRestrictedErrorInfo)(IRestrictedErrorInfo * pRestrictedErrorInfo);
401
402pfnRoOriginateLanguageException g_pfnRoOriginateLanguageException = nullptr;
403pfnGetRestrictedErrorInfo g_pfnGetRestrictedErrorInfo = nullptr;
404pfnSetRestrictedErrorInfo g_pfnSetRestrictedErrorInfo = nullptr;
405
406Volatile<bool> g_bCheckedWinRTErrorDllPresent = false;
407
408//--------------------------------------------------------------------------------
409// Attempts to load WinRT error API functions from the appropriate system library,
410// and populates g_pfnRoOriginateLanguageException, g_pfnGetRestrictedErrorInfo,
411// and g_pfnSetRestrictedErrorInfo.
412//
413// This is shared logic for loading the WinRT error libraries that should not be
414// called directly.
415void LoadProcAddressForWinRTErrorAPIs_Internal()
416{
417 WRAPPER_NO_CONTRACT;
418
419 GCX_PREEMP();
420
421 if (!g_bCheckedWinRTErrorDllPresent)
422 {
423 HMODULE hModWinRTError11Dll = WszLoadLibraryEx(W("api-ms-win-core-winrt-error-l1-1-1.dll"), NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
424
425 // We never release the library since we can only do it at AppDomain shutdown and there is no good way to release it then.
426 if (hModWinRTError11Dll)
427 {
428 g_pfnRoOriginateLanguageException = (pfnRoOriginateLanguageException)GetProcAddress(hModWinRTError11Dll, "RoOriginateLanguageException");
429 g_pfnSetRestrictedErrorInfo = (pfnSetRestrictedErrorInfo)GetProcAddress(hModWinRTError11Dll, "SetRestrictedErrorInfo");
430 g_pfnGetRestrictedErrorInfo = (pfnGetRestrictedErrorInfo)GetProcAddress(hModWinRTError11Dll, "GetRestrictedErrorInfo");
431 }
432 else
433 {
434 // Downlevel versions of WinRT that do not have the language-projected exceptions will still have
435 // APIs for IRestrictedErrorInfo, so we should still try to load those.
436 HMODULE hModWinRTError10Dll = WszLoadLibraryEx(L"api-ms-win-core-winrt-error-l1-1-0.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
437
438 if (hModWinRTError10Dll)
439 {
440 g_pfnSetRestrictedErrorInfo = (pfnSetRestrictedErrorInfo)GetProcAddress(hModWinRTError10Dll, "SetRestrictedErrorInfo");
441 g_pfnGetRestrictedErrorInfo = (pfnGetRestrictedErrorInfo)GetProcAddress(hModWinRTError10Dll, "GetRestrictedErrorInfo");
442 }
443 }
444
445 g_bCheckedWinRTErrorDllPresent = true;
446 }
447}
448
449//--------------------------------------------------------------------------------
450// Attempts to load the IRestrictedErrorInfo APIs into the function pointers
451// g_pfnGetRestrictedErrorInfo and g_pfnSetRestrictedErrorInfo. This is used for
452// WinRT scenarios where we don't care about support for language-projected exception
453// support. Returns S_OK if both of these functions could be loaded, and E_FAIL
454// otherwise.
455HRESULT LoadProcAddressForRestrictedErrorInfoAPIs()
456{
457 WRAPPER_NO_CONTRACT;
458
459 LoadProcAddressForWinRTErrorAPIs_Internal();
460
461 if (g_pfnSetRestrictedErrorInfo != NULL && g_pfnGetRestrictedErrorInfo != NULL)
462 return S_OK;
463 else
464 return E_FAIL;
465}
466
467//--------------------------------------------------------------------------------
468// Attempts to load the RoOriginateLanguageException API for language-projected
469// exceptions into the function pointer g_pfnRoOriginateLanguageException. Returns
470// S_OK if this function could be loaded, and E_FAIL otherwise.
471HRESULT LoadProcAddressForRoOriginateLanguageExceptionAPI()
472{
473 WRAPPER_NO_CONTRACT;
474
475 LoadProcAddressForWinRTErrorAPIs_Internal();
476
477 if (g_pfnRoOriginateLanguageException != NULL)
478 return S_OK;
479 else
480 return E_FAIL;
481}
482
483//--------------------------------------------------------------------------------
484// GetRestrictedErrorInfo helper, enables and disables GC during call-outs
485HRESULT SafeGetRestrictedErrorInfo(IRestrictedErrorInfo **ppIRestrictedErrInfo)
486{
487 CONTRACTL
488 {
489 NOTHROW;
490 GC_TRIGGERS;
491 MODE_ANY;
492 PRECONDITION(CheckPointer(ppIRestrictedErrInfo));
493 }
494 CONTRACTL_END;
495
496 *ppIRestrictedErrInfo = NULL;
497 HRESULT hr = S_OK;
498
499 if(SUCCEEDED(LoadProcAddressForRestrictedErrorInfoAPIs()))
500 {
501 GCX_PREEMP();
502
503 EX_TRY
504 {
505 hr = (*g_pfnGetRestrictedErrorInfo)(ppIRestrictedErrInfo);
506 }
507 EX_CATCH
508 {
509 hr = E_OUTOFMEMORY;
510 }
511 EX_END_CATCH(SwallowAllExceptions);
512 }
513
514 return hr;
515}
516
517// This method checks whether the given IErrorInfo is actually a managed CLR object.
518BOOL IsManagedObject(IUnknown *pIUnknown)
519{
520 CONTRACTL
521 {
522 THROWS;
523 GC_TRIGGERS;
524 MODE_ANY;
525 INJECT_FAULT(COMPlusThrowOM());
526 PRECONDITION(CheckPointer(pIUnknown));
527 }
528 CONTRACTL_END;
529
530 //Check based on IUnknown slots, i.e. we'll see whether the IP maps to a CCW.
531 if (MapIUnknownToWrapper(pIUnknown) != NULL)
532 {
533 // We found an existing CCW hence this is a managed exception.
534 return TRUE;
535 }
536 return FALSE;
537}
538
539// This method returns the IErrorInfo associated with the IRestrictedErrorInfo.
540// Return Value - a. IErrorInfo which corresponds to a managed exception object, where *bHasNonCLRLanguageErrorObject = FALSE
541// b. IErrorInfo corresponding to a non-CLR exception object , where *bHasNonCLRLanguageErrorObject = TRUE
542// c. NULL in case the current hr value is different from the one associated with IRestrictedErrorInfo.
543IErrorInfo *GetCorrepondingErrorInfo_WinRT(HRESULT hr, IRestrictedErrorInfo *pResErrInfo, BOOL* bHasNonCLRLanguageErrorObject)
544{
545 CONTRACTL
546 {
547 THROWS;
548 GC_TRIGGERS;
549 MODE_ANY;
550 INJECT_FAULT(COMPlusThrowOM());
551 PRECONDITION(CheckPointer(pResErrInfo));
552 }
553 CONTRACTL_END;
554
555 *bHasNonCLRLanguageErrorObject = FALSE;
556 // This function must run in preemptive GC mode.
557 {
558 GCX_PREEMP();
559 HRESULT hrLocal = S_OK;
560
561 SafeComHolderPreemp<ILanguageExceptionErrorInfo> pLangException;
562
563 // 1. Check whether the given IRestrictedErrorInfo supports ILanguageExceptionErrorInfo
564 // 2. If so, retrieve the language specific IInspectable by calling GetLanguageException.
565 // 3. Check whether the IInspectable is CLR specific.
566 // 4. If so, return the IInspectable as it is also the IErrorInfo.
567 // 5. If not, check whether the HResult returned by the API is same as the one stored in IRestrictedErrorInfo.
568 // 6. If so simply QI for IErrorInfo
569 // 7. If QI succeeds return IErrorInfo else return NULL.
570
571 hrLocal = SafeQueryInterfacePreemp(pResErrInfo, IID_ILanguageExceptionErrorInfo, (IUnknown **) &pLangException);
572 LogInteropQI(pResErrInfo, IID_ILanguageExceptionErrorInfo, hr, "ILanguageExceptionErrorInfo");
573 if (SUCCEEDED(hrLocal))
574 {
575 IUnknown* pUnk;
576 if(pLangException != NULL && SUCCEEDED(pLangException->GetLanguageException((IUnknown**) &pUnk)) && pUnk != NULL)
577 {
578 if(IsManagedObject(pUnk))
579 {
580 // Since this represent a managed CCW, this is our exception object and will always be an IErrorInfo.
581 // Hence type casting to IErrorInfo is safe.
582 return (IErrorInfo*)pUnk;
583 }
584 else
585 {
586 // pUnk represents an exception object of a different language.
587 // We simply need to store that the exception object represents a non-CLR exception and can release the actual exception object.
588 SafeReleasePreemp(pUnk);
589 *bHasNonCLRLanguageErrorObject = TRUE;
590 }
591 }
592 }
593 if(SUCCEEDED(GetRestrictedErrorDetails(pResErrInfo, NULL, NULL, &hrLocal, NULL)))
594 {
595 if(hr == hrLocal)
596 {
597 IErrorInfo *pErrInfo = NULL ;
598 hrLocal = SafeQueryInterfacePreemp(pResErrInfo, IID_IErrorInfo, (IUnknown **) &pErrInfo);
599 LogInteropQI(pResErrInfo, IID_IErrorInfo, hrLocal, "IErrorInfo");
600 if(SUCCEEDED(hrLocal))
601 {
602 return pErrInfo;
603 }
604 }
605 }
606 }
607
608 return NULL;
609}
610
611HRESULT GetRestrictedErrorDetails(IRestrictedErrorInfo *pRestrictedErrorInfo, BSTR *perrorDescription, BSTR *pErrorRestrictedDescription, HRESULT *pHr, BSTR *pErrorCapabilitySid)
612{
613 CONTRACTL
614 {
615 NOTHROW;
616 GC_TRIGGERS;
617 MODE_ANY;
618 PRECONDITION(CheckPointer(pRestrictedErrorInfo));
619 }
620 CONTRACTL_END;
621
622 GCX_PREEMP();
623
624 BSTR errDesc;
625 BSTR errResDesc;
626 BSTR errCapSid;
627 HRESULT hrLocal;
628
629 if(SUCCEEDED(pRestrictedErrorInfo->GetErrorDetails(&errDesc, &hrLocal, &errResDesc, &errCapSid)))
630 {
631 if(perrorDescription)
632 *perrorDescription = errDesc;
633 else
634 ::SysFreeString(errDesc);
635
636 if(pErrorRestrictedDescription)
637 *pErrorRestrictedDescription = errResDesc;
638 else
639 ::SysFreeString(errResDesc);
640
641 if(pErrorCapabilitySid)
642 *pErrorCapabilitySid = errCapSid;
643 else
644 ::SysFreeString(errCapSid);
645 if(pHr)
646 *pHr = hrLocal;
647
648 return S_OK;
649 }
650
651 return E_FAIL;
652}
653
654// HRESULT for CLR created IErrorInfo pointers are accessible
655// from the enclosing simple wrapper
656// This is in-proc only.
657HRESULT GetHRFromCLRErrorInfo(IErrorInfo* pErr)
658{
659 CONTRACTL
660 {
661 THROWS;
662 GC_TRIGGERS;
663 MODE_COOPERATIVE;
664 PRECONDITION(CheckPointer(pErr));
665 PRECONDITION(IsInProcCCWTearOff(pErr));
666 PRECONDITION(IsSimpleTearOff(pErr));
667 }
668 CONTRACTL_END;
669
670 SimpleComCallWrapper* pSimpleWrap = SimpleComCallWrapper::GetWrapperFromIP(pErr);
671 return pSimpleWrap->IErrorInfo_hr();
672}
673#endif // FEATURE_COMINTEROP
674
675HRESULT SetupErrorInfo(OBJECTREF pThrownObject, BOOL bIsWinRTScenario /* = FALSE */)
676{
677 CONTRACTL
678 {
679 NOTHROW;
680 GC_TRIGGERS;
681 MODE_COOPERATIVE;
682 }
683 CONTRACTL_END;
684
685 HRESULT hr = E_FAIL;
686
687#ifdef FEATURE_COMINTEROP
688 Exception* pException = NULL;
689#endif
690
691 GCPROTECT_BEGIN(pThrownObject)
692 {
693 EX_TRY
694 {
695 // Calls to COM up ahead.
696 hr = EnsureComStartedNoThrow();
697 if (SUCCEEDED(hr) && pThrownObject != NULL)
698 {
699#ifdef _DEBUG
700 EX_TRY
701 {
702 StackSString message;
703 GetExceptionMessage(pThrownObject, message);
704
705 if (g_pConfig->ShouldExposeExceptionsInCOMToConsole())
706 {
707 PrintToStdOutW(W(".NET exception in COM\n"));
708 if (!message.IsEmpty())
709 PrintToStdOutW(message.GetUnicode());
710 else
711 PrintToStdOutW(W("No exception info available"));
712 }
713
714 if (g_pConfig->ShouldExposeExceptionsInCOMToMsgBox())
715 {
716 GCX_PREEMP();
717 if (!message.IsEmpty())
718 EEMessageBoxNonLocalizedDebugOnly((LPWSTR)message.GetUnicode(), W(".NET exception in COM"), MB_ICONSTOP | MB_OK);
719 else
720 EEMessageBoxNonLocalizedDebugOnly(W("No exception information available"), W(".NET exception in COM"),MB_ICONSTOP | MB_OK);
721 }
722 }
723 EX_CATCH
724 {
725 }
726 EX_END_CATCH (SwallowAllExceptions);
727#endif
728
729#ifdef FEATURE_COMINTEROP
730 IErrorInfo* pErr = NULL;
731 EX_TRY
732 {
733 // This handles a special case for a newer subset of WinRT scenarios, starting in Windows
734 // 8.1, where we have support for language-projected extensions. In this case, we can use
735 // the thrown object to set up a projected IErrorInfo that we'll send back to native code.
736 //
737 // In all other scenarios (including WinRT prior to Windows 8.1), we just use the legacy
738 // IErrorInfo COM APIs.
739 if (bIsWinRTScenario &&
740 SUCCEEDED(LoadProcAddressForRestrictedErrorInfoAPIs()) &&
741 SUCCEEDED(LoadProcAddressForRoOriginateLanguageExceptionAPI()))
742 {
743 // In case of WinRT we check whether we have an already existing uncaught language exception.
744 // If so we simply SetRestrictedErrorInfo on that ensuring that the other language can catch that exception
745 // and we do not RoOriginateError from our side.
746 IRestrictedErrorInfo *pRestrictedErrorInfo = GetRestrictedErrorInfoFromErrorObject(pThrownObject);
747 if(pRestrictedErrorInfo != NULL)
748 {
749 (*g_pfnSetRestrictedErrorInfo)(pRestrictedErrorInfo);
750 GetRestrictedErrorDetails(pRestrictedErrorInfo, NULL, NULL, &hr, NULL);
751 }
752 else
753 {
754 // If there is no existing language exception we save the errorInfo on the current thread by storing the following information
755 // 1. HResult
756 // 2. ErrorMsg
757 // 3. The managed exception object, which can be later retrieved if needed.
758
759 pErr = (IErrorInfo *)GetComIPFromObjectRef(&pThrownObject, IID_IErrorInfo);
760
761 StackSString message;
762 HRESULT errorHr;
763 HSTRING errorMsgString;
764
765 GetExceptionMessage(pThrownObject, message);
766 errorHr = GetHRFromThrowable(pThrownObject);
767
768 if(FAILED(WindowsCreateString(message.GetUnicode(), message.GetCount(), &errorMsgString)))
769 errorMsgString = NULL;
770
771 //
772 // WinRT change to convert ObjectDisposedException into RO_E_CLOSED
773 // if we are calling into a WinRT managed object
774 //
775 if (errorHr == COR_E_OBJECTDISPOSED)
776 errorHr = RO_E_CLOSED;
777
778 // Set the managed exception
779 {
780 GCX_PREEMP();
781 // This Windows API call will store the pErr as the LanguageException and
782 // construct an IRestrictedErrorInfo from the errorHr and errorMsgString
783 // which can then be later retrieved using GetRestrictedErrorInfo.
784 (*g_pfnRoOriginateLanguageException)(errorHr, errorMsgString, pErr);
785 }
786 }
787 }
788 else
789 {
790 // set the error info object for the exception that was thrown.
791 pErr = (IErrorInfo *)GetComIPFromObjectRef(&pThrownObject, IID_IErrorInfo);
792 {
793 GCX_PREEMP();
794 SetErrorInfo(0, pErr);
795 }
796 }
797
798 // Release the pErr in case it exists.
799 if (pErr)
800 {
801 hr = GetHRFromCLRErrorInfo(pErr);
802 ULONG cbRef = SafeRelease(pErr);
803 LogInteropRelease(pErr, cbRef, "IErrorInfo");
804 }
805 }
806 EX_CATCH
807 {
808 hr = GET_EXCEPTION()->GetHR();
809 }
810 EX_END_CATCH(SwallowAllExceptions);
811 //
812 // WinRT change to convert ObjectDisposedException into RO_E_CLOSED
813 // if we are calling into a WinRT managed object
814 //
815 if (hr == COR_E_OBJECTDISPOSED && bIsWinRTScenario)
816 hr = RO_E_CLOSED;
817#endif // FEATURE_COMINTEROP
818 }
819 }
820 EX_CATCH
821 {
822 if (SUCCEEDED(hr))
823 hr = E_FAIL;
824 }
825 EX_END_CATCH(SwallowAllExceptions);
826 }
827 GCPROTECT_END();
828 return hr;
829}
830
831//-------------------------------------------------------------------
832 // Used to populate ExceptionData with COM data
833//-------------------------------------------------------------------
834void FillExceptionData(
835 _Inout_ ExceptionData* pedata,
836 _In_ IErrorInfo* pErrInfo,
837 _In_opt_ IRestrictedErrorInfo* pRestrictedErrorInfo)
838{
839 CONTRACTL
840 {
841 NOTHROW;
842 GC_TRIGGERS;
843 MODE_ANY;
844 PRECONDITION(CheckPointer(pedata));
845 }
846 CONTRACTL_END;
847
848 if (pErrInfo != NULL)
849 {
850 Thread* pThread = GetThread();
851 if (pThread != NULL)
852 {
853 GCX_PREEMP();
854
855 pErrInfo->GetSource (&pedata->bstrSource);
856 pErrInfo->GetDescription (&pedata->bstrDescription);
857 pErrInfo->GetHelpFile (&pedata->bstrHelpFile);
858 pErrInfo->GetHelpContext (&pedata->dwHelpContext );
859 pErrInfo->GetGUID(&pedata->guid);
860
861#ifdef FEATURE_COMINTEROP
862 HRESULT hr = S_OK;
863 if(pRestrictedErrorInfo == NULL)
864 {
865 hr = SafeQueryInterfacePreemp(pErrInfo, IID_IRestrictedErrorInfo, (IUnknown **) &pRestrictedErrorInfo);
866 LogInteropQI(pErrInfo, IID_IRestrictedErrorInfo, hr, "IRestrictedErrorInfo");
867 }
868
869 if (SUCCEEDED(hr) && pRestrictedErrorInfo != NULL)
870 {
871 // Keep a AddRef-ed IRestrictedErrorInfo*
872 pedata->pRestrictedErrorInfo = pRestrictedErrorInfo;
873
874 // Retrieve restricted error information
875 BSTR bstrDescription = NULL;
876 HRESULT hrError;
877 if (SUCCEEDED(GetRestrictedErrorDetails(pRestrictedErrorInfo, &bstrDescription, &pedata->bstrRestrictedError, &hrError, &pedata->bstrCapabilitySid)))
878 {
879 if (bstrDescription != NULL)
880 {
881 ::SysFreeString(pedata->bstrDescription);
882 pedata->bstrDescription = bstrDescription;
883 }
884
885 _ASSERTE(hrError == pedata->hr);
886 }
887
888 // Retrieve reference string and ignore error
889 pRestrictedErrorInfo->GetReference(&pedata->bstrReference);
890 }
891#endif
892 ULONG cbRef = SafeRelease(pErrInfo); // release the IErrorInfo interface pointer
893 LogInteropRelease(pErrInfo, cbRef, "IErrorInfo");
894 }
895 }
896}
897#endif // CROSSGEN_COMPILE
898
899//---------------------------------------------------------------------------
900//returns true if pImport has DefaultDllImportSearchPathsAttribute
901//if true, also returns dllImportSearchPathFlag and searchAssemblyDirectory values.
902BOOL GetDefaultDllImportSearchPathsAttributeValue(IMDInternalImport *pImport, mdToken token, DWORD * pDllImportSearchPathFlag)
903{
904 CONTRACTL
905 {
906 THROWS;
907 GC_NOTRIGGER;
908 MODE_ANY;
909 PRECONDITION(CheckPointer(pImport));
910 }
911 CONTRACTL_END;
912
913 BYTE* pData = NULL;
914 LONG cData = 0;
915
916 HRESULT hr = pImport->GetCustomAttributeByName(token,
917 g_DefaultDllImportSearchPathsAttribute,
918 (const VOID **)(&pData),
919 (ULONG *)&cData);
920
921 IfFailThrow(hr);
922 if(cData == 0 )
923 {
924 return FALSE;
925 }
926
927 CustomAttributeParser ca(pData, cData);
928 CaArg args[1];
929 args[0].InitEnum(SERIALIZATION_TYPE_U4, (ULONG)0);
930
931 ParseKnownCaArgs(ca, args, lengthof(args));
932 *pDllImportSearchPathFlag = args[0].val.u4;
933 return TRUE;
934}
935
936
937//---------------------------------------------------------------------------
938// Returns the index of the LCID parameter if one exists and -1 otherwise.
939int GetLCIDParameterIndex(MethodDesc *pMD)
940{
941 CONTRACTL
942 {
943 NOTHROW;
944 GC_NOTRIGGER;
945 MODE_ANY;
946 PRECONDITION(CheckPointer(pMD));
947 }
948 CONTRACTL_END;
949
950 int iLCIDParam = -1;
951 HRESULT hr;
952 const BYTE * pVal;
953 ULONG cbVal;
954
955 if (!pMD->GetMethodTable()->IsProjectedFromWinRT()) // ignore LCIDConversionAttribute on WinRT methods
956 {
957 // Check to see if the method has the LCIDConversionAttribute.
958 hr = pMD->GetMDImport()->GetCustomAttributeByName(pMD->GetMemberDef(), INTEROP_LCIDCONVERSION_TYPE, (const void**)&pVal, &cbVal);
959 if (hr == S_OK)
960 {
961 CustomAttributeParser caLCID(pVal, cbVal);
962 CaArg args[1];
963 args[0].Init(SERIALIZATION_TYPE_I4, 0);
964 IfFailGo(ParseKnownCaArgs(caLCID, args, lengthof(args)));
965 iLCIDParam = args[0].val.i4;
966 }
967 }
968
969ErrExit:
970 return iLCIDParam;
971}
972
973#ifndef CROSSGEN_COMPILE
974//---------------------------------------------------------------------------
975// Transforms an LCID into a CultureInfo.
976void GetCultureInfoForLCID(LCID lcid, OBJECTREF *pCultureObj)
977{
978 CONTRACTL
979 {
980 THROWS;
981 GC_TRIGGERS;
982 MODE_COOPERATIVE;
983 INJECT_FAULT(COMPlusThrowOM());
984 PRECONDITION(CheckPointer(pCultureObj));
985 }
986 CONTRACTL_END;
987
988#ifdef FEATURE_USE_LCID
989 OBJECTREF CultureObj = NULL;
990 GCPROTECT_BEGIN(CultureObj)
991 {
992 // Allocate a CultureInfo with the specified LCID.
993 CultureObj = AllocateObject(MscorlibBinder::GetClass(CLASS__CULTURE_INFO));
994
995 MethodDescCallSite cultureInfoCtor(METHOD__CULTURE_INFO__INT_CTOR, &CultureObj);
996
997 // Call the CultureInfo(int culture) constructor.
998 ARG_SLOT pNewArgs[] = {
999 ObjToArgSlot(CultureObj),
1000 (ARG_SLOT)lcid
1001 };
1002 cultureInfoCtor.Call(pNewArgs);
1003
1004 // Set the returned culture object.
1005 *pCultureObj = CultureObj;
1006 }
1007 GCPROTECT_END();
1008#else
1009 COMPlusThrow(kNotSupportedException);
1010#endif
1011}
1012
1013#endif // CROSSGEN_COMPILE
1014
1015//---------------------------------------------------------------------------
1016// This method determines if a member is visible from COM.
1017BOOL IsMemberVisibleFromCom(MethodTable *pDeclaringMT, mdToken tk, mdMethodDef mdAssociate)
1018{
1019 CONTRACTL
1020 {
1021 NOTHROW;
1022 GC_NOTRIGGER;
1023 MODE_ANY;
1024 PRECONDITION(CheckPointer(pDeclaringMT));
1025 }
1026 CONTRACTL_END;
1027
1028 HRESULT hr;
1029 const BYTE * pVal;
1030 ULONG cbVal;
1031 DWORD dwFlags;
1032
1033 IMDInternalImport *pInternalImport = pDeclaringMT->GetMDImport();
1034
1035 // Check to see if the member is public.
1036 switch (TypeFromToken(tk))
1037 {
1038 case mdtFieldDef:
1039 _ASSERTE(IsNilToken(mdAssociate));
1040 if (FAILED(pInternalImport->GetFieldDefProps(tk, &dwFlags)))
1041 {
1042 return FALSE;
1043 }
1044 if (!IsFdPublic(dwFlags))
1045 return FALSE;
1046 break;
1047
1048 case mdtMethodDef:
1049 _ASSERTE(IsNilToken(mdAssociate));
1050 if (FAILED(pInternalImport->GetMethodDefProps(tk, &dwFlags)))
1051 {
1052 return FALSE;
1053 }
1054 if (!IsMdPublic(dwFlags))
1055 {
1056 return FALSE;
1057 }
1058 {
1059 // Generic Methods are not visible from COM
1060 MDEnumHolder hEnumTyPars(pInternalImport);
1061 if (FAILED(pInternalImport->EnumInit(mdtGenericParam, tk, &hEnumTyPars)))
1062 return FALSE;
1063
1064 if (pInternalImport->EnumGetCount(&hEnumTyPars) != 0)
1065 return FALSE;
1066 }
1067 break;
1068
1069 case mdtProperty:
1070 _ASSERTE(!IsNilToken(mdAssociate));
1071 if (FAILED(pInternalImport->GetMethodDefProps(mdAssociate, &dwFlags)))
1072 {
1073 return FALSE;
1074 }
1075 if (!IsMdPublic(dwFlags))
1076 return FALSE;
1077
1078 if (!pDeclaringMT->IsProjectedFromWinRT() && !pDeclaringMT->IsExportedToWinRT() && !pDeclaringMT->IsWinRTObjectType())
1079 {
1080 // Check to see if the associate has the ComVisible attribute set (non-WinRT members only).
1081 hr = pInternalImport->GetCustomAttributeByName(mdAssociate, INTEROP_COMVISIBLE_TYPE, (const void**)&pVal, &cbVal);
1082 if (hr == S_OK)
1083 {
1084 CustomAttributeParser cap(pVal, cbVal);
1085 if (FAILED(cap.SkipProlog()))
1086 return FALSE;
1087
1088 UINT8 u1;
1089 if (FAILED(cap.GetU1(&u1)))
1090 return FALSE;
1091
1092 return (BOOL)u1;
1093 }
1094 }
1095 break;
1096
1097 default:
1098 _ASSERTE(!"The type of the specified member is not handled by IsMemberVisibleFromCom");
1099 break;
1100 }
1101
1102 if (!pDeclaringMT->IsProjectedFromWinRT() && !pDeclaringMT->IsExportedToWinRT() && !pDeclaringMT->IsWinRTObjectType())
1103 {
1104 // Check to see if the member has the ComVisible attribute set (non-WinRT members only).
1105 hr = pInternalImport->GetCustomAttributeByName(tk, INTEROP_COMVISIBLE_TYPE, (const void**)&pVal, &cbVal);
1106 if (hr == S_OK)
1107 {
1108 CustomAttributeParser cap(pVal, cbVal);
1109 if (FAILED(cap.SkipProlog()))
1110 return FALSE;
1111
1112 UINT8 u1;
1113 if (FAILED(cap.GetU1(&u1)))
1114 return FALSE;
1115
1116 return (BOOL)u1;
1117 }
1118 }
1119
1120 // The member is visible.
1121 return TRUE;
1122}
1123
1124
1125ULONG GetStringizedMethodDef(MethodTable *pDeclaringMT, mdToken tkMb, CQuickArray<BYTE> &rDef, ULONG cbCur)
1126{
1127 CONTRACTL
1128 {
1129 THROWS;
1130 GC_NOTRIGGER;
1131 MODE_ANY;
1132 PRECONDITION(CheckPointer(pDeclaringMT));
1133 }
1134 CONTRACTL_END;
1135
1136 IMDInternalImport *pMDImport = pDeclaringMT->GetMDImport();
1137 CQuickBytes rSig;
1138 MDEnumHolder ePm(pMDImport); // For enumerating params.
1139 mdParamDef tkPm; // A param token.
1140 DWORD dwFlags; // Param flags.
1141 USHORT usSeq; // Sequence of a parameter.
1142 ULONG cPm; // Count of params.
1143 PCCOR_SIGNATURE pSig;
1144 ULONG cbSig;
1145
1146 // Don't count invisible members.
1147 if (!IsMemberVisibleFromCom(pDeclaringMT, tkMb, mdMethodDefNil))
1148 return cbCur;
1149
1150 // accumulate the signatures.
1151 IfFailThrow(pMDImport->GetSigOfMethodDef(tkMb, &cbSig, &pSig));
1152 IfFailThrow(::PrettyPrintSigInternalLegacy(pSig, cbSig, "", &rSig, pMDImport));
1153
1154 // Get the parameter flags.
1155 IfFailThrow(pMDImport->EnumInit(mdtParamDef, tkMb, &ePm));
1156 cPm = pMDImport->EnumGetCount(&ePm);
1157
1158 // Resize for sig and params. Just use 1 byte of param.
1159 rDef.ReSizeThrows(cbCur + rSig.Size() + cPm);
1160 memcpy(rDef.Ptr() + cbCur, rSig.Ptr(), rSig.Size());
1161 cbCur += (ULONG)(rSig.Size()-1);
1162
1163 // Enumerate through the params and get the flags.
1164 while (pMDImport->EnumNext(&ePm, &tkPm))
1165 {
1166 LPCSTR szParamName_Ignore;
1167 IfFailThrow(pMDImport->GetParamDefProps(tkPm, &usSeq, &dwFlags, &szParamName_Ignore));
1168 if (usSeq == 0) // Skip return type flags.
1169 continue;
1170 rDef[cbCur++] = (BYTE)dwFlags;
1171 }
1172
1173 // Return the number of bytes.
1174 return cbCur;
1175} // void GetStringizedMethodDef()
1176
1177
1178ULONG GetStringizedFieldDef(MethodTable *pDeclaringMT, mdToken tkMb, CQuickArray<BYTE> &rDef, ULONG cbCur)
1179{
1180 CONTRACTL
1181 {
1182 THROWS;
1183 GC_NOTRIGGER;
1184 MODE_ANY;
1185 PRECONDITION(CheckPointer(pDeclaringMT));
1186 }
1187 CONTRACTL_END;
1188
1189 CQuickBytes rSig;
1190 PCCOR_SIGNATURE pSig;
1191 ULONG cbSig;
1192
1193 // Don't count invisible members.
1194 if (!IsMemberVisibleFromCom(pDeclaringMT, tkMb, mdMethodDefNil))
1195 return cbCur;
1196
1197 IMDInternalImport *pMDImport = pDeclaringMT->GetMDImport();
1198
1199 // accumulate the signatures.
1200 IfFailThrow(pMDImport->GetSigOfFieldDef(tkMb, &cbSig, &pSig));
1201 IfFailThrow(::PrettyPrintSigInternalLegacy(pSig, cbSig, "", &rSig, pMDImport));
1202 rDef.ReSizeThrows(cbCur + rSig.Size());
1203 memcpy(rDef.Ptr() + cbCur, rSig.Ptr(), rSig.Size());
1204 cbCur += (ULONG)(rSig.Size()-1);
1205
1206 // Return the number of bytes.
1207 return cbCur;
1208} // void GetStringizedFieldDef()
1209
1210//--------------------------------------------------------------------------------
1211// This method generates a stringized version of an interface that contains the
1212// name of the interface along with the signature of all the methods.
1213SIZE_T GetStringizedItfDef(TypeHandle InterfaceType, CQuickArray<BYTE> &rDef)
1214{
1215 CONTRACTL
1216 {
1217 THROWS;
1218 GC_NOTRIGGER;
1219 MODE_ANY;
1220 }
1221 CONTRACTL_END;
1222
1223 MethodTable* pIntfMT = InterfaceType.GetMethodTable();
1224 PREFIX_ASSUME(pIntfMT != NULL);
1225
1226 IMDInternalImport* pMDImport = pIntfMT->GetMDImport();
1227 PREFIX_ASSUME(pMDImport != NULL);
1228
1229 LPCWSTR szName;
1230 ULONG cchName;
1231 MDEnumHolder eMb(pMDImport); // For enumerating methods and fields.
1232 mdToken tkMb; // A method or field token.
1233 SIZE_T cbCur;
1234
1235 // Make sure the specified type is an interface with a valid token.
1236 _ASSERTE(!IsNilToken(pIntfMT->GetCl()) && pIntfMT->IsInterface());
1237
1238 // Get the name of the class.
1239 DefineFullyQualifiedNameForClassW();
1240 szName = GetFullyQualifiedNameForClassNestedAwareW(pIntfMT);
1241
1242 cchName = (ULONG)wcslen(szName);
1243
1244 // Start with the interface name.
1245 cbCur = cchName * sizeof(WCHAR);
1246 rDef.ReSizeThrows(cbCur + sizeof(WCHAR));
1247 wcscpy_s(reinterpret_cast<LPWSTR>(rDef.Ptr()), rDef.Size()/sizeof(WCHAR), szName);
1248
1249 // Enumerate the methods...
1250 IfFailThrow(pMDImport->EnumInit(mdtMethodDef, pIntfMT->GetCl(), &eMb));
1251 while(pMDImport->EnumNext(&eMb, &tkMb))
1252 { // accumulate the signatures.
1253 cbCur = GetStringizedMethodDef(pIntfMT, tkMb, rDef, (ULONG)cbCur);
1254 }
1255 pMDImport->EnumClose(&eMb);
1256
1257 // Enumerate the fields...
1258 IfFailThrow(pMDImport->EnumInit(mdtFieldDef, pIntfMT->GetCl(), &eMb));
1259 while(pMDImport->EnumNext(&eMb, &tkMb))
1260 { // accumulate the signatures.
1261 cbCur = GetStringizedFieldDef(pIntfMT, tkMb, rDef, (ULONG)cbCur);
1262 }
1263
1264 // Return the number of bytes.
1265 return cbCur;
1266} // ULONG GetStringizedItfDef()
1267
1268//--------------------------------------------------------------------------------
1269// Helper to get the stringized form of typelib guid.
1270HRESULT GetStringizedTypeLibGuidForAssembly(Assembly *pAssembly, CQuickArray<BYTE> &rDef, ULONG cbCur, ULONG *pcbFetched)
1271{
1272 CONTRACTL
1273 {
1274 NOTHROW;
1275 GC_TRIGGERS;
1276 MODE_ANY;
1277 PRECONDITION(CheckPointer(pAssembly));
1278 PRECONDITION(CheckPointer(pcbFetched));
1279 }
1280 CONTRACTL_END;
1281
1282 HRESULT hr = S_OK; // A result.
1283 LPCUTF8 pszName = NULL; // Library name in UTF8.
1284 ULONG cbName; // Length of name, UTF8 characters.
1285 LPWSTR pName; // Pointer to library name.
1286 ULONG cchName; // Length of name, wide chars.
1287 LPWSTR pch=0; // Pointer into lib name.
1288 const void *pSN=NULL; // Pointer to public key.
1289 DWORD cbSN=0; // Size of public key.
1290 USHORT usMajorVersion; // The major version number.
1291 USHORT usMinorVersion; // The minor version number.
1292 USHORT usBuildNumber; // The build number.
1293 USHORT usRevisionNumber; // The revision number.
1294 const BYTE *pbData = NULL; // Pointer to a custom attribute data.
1295 ULONG cbData = 0; // Size of custom attribute data.
1296 static char szTypeLibKeyName[] = {"TypeLib"};
1297
1298 // Get the name, and determine its length.
1299 pszName = pAssembly->GetSimpleName();
1300 cbName=(ULONG)strlen(pszName);
1301 cchName = WszMultiByteToWideChar(CP_ACP,0, pszName,cbName+1, 0,0);
1302
1303 // See if there is a public key.
1304 EX_TRY
1305 {
1306 pSN = pAssembly->GetPublicKey(&cbSN);
1307 }
1308 EX_CATCH
1309 {
1310 IfFailGo(COR_E_BADIMAGEFORMAT);
1311 }
1312 EX_END_CATCH(RethrowTerminalExceptions)
1313
1314
1315#ifdef FEATURE_COMINTEROP
1316 if (pAssembly->IsWinMD())
1317 {
1318 // ignore classic COM interop CA on .winmd
1319 hr = S_FALSE;
1320 }
1321 else
1322 {
1323 // If the ComCompatibleVersionAttribute is set, then use the version
1324 // number in the attribute when generating the GUID.
1325 IfFailGo(pAssembly->GetManifestImport()->GetCustomAttributeByName(TokenFromRid(1, mdtAssembly), INTEROP_COMCOMPATIBLEVERSION_TYPE, (const void**)&pbData, &cbData));
1326 }
1327
1328 if (hr == S_OK && cbData >= (2 + 4 * sizeof(INT32)))
1329 {
1330 CustomAttributeParser cap(pbData, cbData);
1331 IfFailRet(cap.SkipProlog());
1332
1333 // Retrieve the major and minor version from the attribute.
1334 UINT32 u4;
1335
1336 IfFailRet(cap.GetU4(&u4));
1337 usMajorVersion = GET_VERSION_USHORT_FROM_INT(u4);
1338 IfFailRet(cap.GetU4(&u4));
1339 usMinorVersion = GET_VERSION_USHORT_FROM_INT(u4);
1340 IfFailRet(cap.GetU4(&u4));
1341 usBuildNumber = GET_VERSION_USHORT_FROM_INT(u4);
1342 IfFailRet(cap.GetU4(&u4));
1343 usRevisionNumber = GET_VERSION_USHORT_FROM_INT(u4);
1344 }
1345 else
1346#endif // FEATURE_COMINTEROP
1347 {
1348 pAssembly->GetVersion(&usMajorVersion, &usMinorVersion, &usBuildNumber, &usRevisionNumber);
1349 }
1350
1351 // Get the version information.
1352 struct versioninfo
1353 {
1354 USHORT usMajorVersion; // Major Version.
1355 USHORT usMinorVersion; // Minor Version.
1356 USHORT usBuildNumber; // Build Number.
1357 USHORT usRevisionNumber; // Revision Number.
1358 } ver;
1359
1360 // <REVISIT_TODO> An issue here is that usMajor is used twice and usMinor not at all.
1361 // We're not fixing that because everyone has a major version, so all the
1362 // generated guids would change, which is breaking. To compensate, if
1363 // the minor is non-zero, we add it separately, below.</REVISIT_TODO>
1364 ver.usMajorVersion = usMajorVersion;
1365 ver.usMinorVersion = usMajorVersion; // Don't fix this line!
1366 ver.usBuildNumber = usBuildNumber;
1367 ver.usRevisionNumber = usRevisionNumber;
1368
1369 // Resize the output buffer.
1370 IfFailGo(rDef.ReSizeNoThrow(cbCur + cchName*sizeof(WCHAR) + sizeof(szTypeLibKeyName)-1 + cbSN + sizeof(ver)+sizeof(USHORT)));
1371
1372 // Put it all together. Name first.
1373 WszMultiByteToWideChar(CP_ACP,0, pszName,cbName+1, (LPWSTR)(&rDef[cbCur]),cchName);
1374 pName = (LPWSTR)(&rDef[cbCur]);
1375 for (pch=pName; *pch; ++pch)
1376 if (*pch == '.' || *pch == ' ')
1377 *pch = '_';
1378 else
1379 if (iswupper(*pch))
1380 *pch = towlower(*pch);
1381 cbCur += (cchName-1)*sizeof(WCHAR);
1382 memcpy(&rDef[cbCur], szTypeLibKeyName, sizeof(szTypeLibKeyName)-1);
1383 cbCur += sizeof(szTypeLibKeyName)-1;
1384
1385 // Version.
1386 memcpy(&rDef[cbCur], &ver, sizeof(ver));
1387 cbCur += sizeof(ver);
1388
1389 // If minor version is non-zero, add it to the hash. It should have been in the ver struct,
1390 // but due to a bug, it was omitted there, and fixing it "right" would have been
1391 // breaking. So if it isn't zero, add it; if it is zero, don't add it. Any
1392 // possible value of minor thus generates a different guid, and a value of 0 still generates
1393 // the guid that the original, buggy, code generated.
1394 if (usMinorVersion != 0)
1395 {
1396 SET_UNALIGNED_16(&rDef[cbCur], usMinorVersion);
1397 cbCur += sizeof(USHORT);
1398 }
1399
1400 // Public key.
1401 memcpy(&rDef[cbCur], pSN, cbSN);
1402 cbCur += cbSN;
1403
1404 if (pcbFetched)
1405 *pcbFetched = cbCur;
1406
1407ErrExit:
1408 return hr;
1409}
1410
1411void SafeRelease_OnException(IUnknown* pUnk, RCW* pRCW
1412#ifdef MDA_SUPPORTED
1413 , MdaReportAvOnComRelease* pProbe
1414#endif // MDA_SUPPORTED
1415 )
1416{
1417 CONTRACTL
1418 {
1419 NOTHROW;
1420 MODE_ANY;
1421 SO_TOLERANT;
1422 }
1423 CONTRACTL_END;
1424
1425#ifndef CROSSGEN_COMPILE
1426 BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return;)
1427
1428#ifdef MDA_SUPPORTED
1429 // Report the exception that was thrown.
1430 if (pProbe)
1431 pProbe->ReportHandledException(pRCW);
1432#endif // MDA_SUPPORTED
1433
1434#ifdef FEATURE_COMINTEROP
1435 LogInterop(W("An exception occurred during release"));
1436 LogInteropLeak(pUnk);
1437#endif // FEATURE_COMINTEROP
1438
1439 END_SO_INTOLERANT_CODE;
1440#endif // CROSSGEN_COMPILE
1441}
1442
1443#include <optsmallperfcritical.h>
1444//--------------------------------------------------------------------------------
1445// Release helper, must be called in preemptive mode. Only use this variant if
1446// you already know you're in preemptive mode for other reasons.
1447ULONG SafeReleasePreemp(IUnknown * pUnk, RCW * pRCW)
1448{
1449 CONTRACTL {
1450 NOTHROW;
1451 GC_TRIGGERS;
1452 MODE_PREEMPTIVE;
1453 SO_TOLERANT;
1454 PRECONDITION(CheckPointer(pUnk, NULL_OK));
1455 } CONTRACTL_END;
1456
1457 if (pUnk == NULL)
1458 return 0;
1459
1460 ULONG res = 0;
1461 Thread * const pThread = GetThreadNULLOk();
1462
1463 // Message pump could happen, so arbitrary managed code could run.
1464 CONTRACT_VIOLATION(ThrowsViolation | FaultViolation);
1465
1466#ifdef MDA_SUPPORTED
1467 // Mode where we just let the fault occur.
1468 MdaReportAvOnComRelease* pProbe = MDA_GET_ASSISTANT_EX(ReportAvOnComRelease);
1469 if (pProbe && pProbe->AllowAV())
1470 {
1471 return pUnk->Release();
1472 }
1473#endif // MDA_SUPPORTED
1474
1475 bool fException = false;
1476
1477 SCAN_EHMARKER();
1478 PAL_CPP_TRY
1479 {
1480 SCAN_EHMARKER_TRY();
1481 // This is a holder to tell the contract system that we're catching all exceptions.
1482 CLR_TRY_MARKER();
1483
1484 // Its very possible that the punk has gone bad before we could release it. This is a common application
1485 // error. We may AV trying to call Release, and that AV will show up as an AV in mscorwks, so we'll take
1486 // down the Runtime. Mark that an AV is alright, and handled, in this scope using this holder.
1487 AVInRuntimeImplOkayHolder AVOkay(pThread);
1488
1489 res = pUnk->Release();
1490
1491 SCAN_EHMARKER_END_TRY();
1492 }
1493 PAL_CPP_CATCH_ALL
1494 {
1495 SCAN_EHMARKER_CATCH();
1496#if defined(STACK_GUARDS_DEBUG)
1497 // Catching and just swallowing an exception means we need to tell
1498 // the SO code that it should go back to normal operation, as it
1499 // currently thinks that the exception is still on the fly.
1500 pThread->GetCurrentStackGuard()->RestoreCurrentGuard();
1501#endif
1502 fException = true;
1503 SCAN_EHMARKER_END_CATCH();
1504 }
1505 PAL_CPP_ENDTRY;
1506
1507 if (fException)
1508 {
1509 SafeRelease_OnException(pUnk, pRCW
1510#ifdef MDA_SUPPORTED
1511 , pProbe
1512#endif // MDA_SUPPORTED
1513 );
1514 }
1515
1516 return res;
1517}
1518
1519//--------------------------------------------------------------------------------
1520// Release helper, enables and disables GC during call-outs
1521ULONG SafeRelease(IUnknown* pUnk, RCW* pRCW)
1522{
1523 CONTRACTL {
1524 NOTHROW;
1525 GC_TRIGGERS;
1526 MODE_ANY;
1527 SO_TOLERANT;
1528 PRECONDITION(CheckPointer(pUnk, NULL_OK));
1529 } CONTRACTL_END;
1530
1531 if (pUnk == NULL)
1532 return 0;
1533
1534 ULONG res = 0;
1535 Thread * const pThread = GetThreadNULLOk();
1536 GCX_PREEMP_NO_DTOR_HAVE_THREAD(pThread);
1537
1538 // Message pump could happen, so arbitrary managed code could run.
1539 CONTRACT_VIOLATION(ThrowsViolation | FaultViolation);
1540
1541#ifdef MDA_SUPPORTED
1542 // Mode where we just let the fault occur.
1543 MdaReportAvOnComRelease* pProbe = MDA_GET_ASSISTANT_EX(ReportAvOnComRelease);
1544 if (pProbe && pProbe->AllowAV())
1545 {
1546 return pUnk->Release();
1547 }
1548#endif // MDA_SUPPORTED
1549
1550 bool fException = false;
1551
1552 SCAN_EHMARKER();
1553 PAL_CPP_TRY
1554 {
1555 SCAN_EHMARKER_TRY();
1556 // This is a holder to tell the contract system that we're catching all exceptions.
1557 CLR_TRY_MARKER();
1558
1559 // Its very possible that the punk has gone bad before we could release it. This is a common application
1560 // error. We may AV trying to call Release, and that AV will show up as an AV in mscorwks, so we'll take
1561 // down the Runtime. Mark that an AV is alright, and handled, in this scope using this holder.
1562 AVInRuntimeImplOkayHolder AVOkay(pThread);
1563
1564 res = pUnk->Release();
1565
1566 SCAN_EHMARKER_END_TRY();
1567 }
1568 PAL_CPP_CATCH_ALL
1569 {
1570 SCAN_EHMARKER_CATCH();
1571#if defined(STACK_GUARDS_DEBUG)
1572 // Catching and just swallowing an exception means we need to tell
1573 // the SO code that it should go back to normal operation, as it
1574 // currently thinks that the exception is still on the fly.
1575 pThread->GetCurrentStackGuard()->RestoreCurrentGuard();
1576#endif
1577 fException = true;
1578 SCAN_EHMARKER_END_CATCH();
1579 }
1580 PAL_CPP_ENDTRY;
1581
1582 if (fException)
1583 {
1584 SafeRelease_OnException(pUnk, pRCW
1585#ifdef MDA_SUPPORTED
1586 , pProbe
1587#endif // MDA_SUPPORTED
1588 );
1589 }
1590
1591 GCX_PREEMP_NO_DTOR_END();
1592
1593 return res;
1594}
1595
1596#include <optdefault.h>
1597
1598//--------------------------------------------------------------------------------
1599// Determines if a COM object can be cast to the specified type.
1600BOOL CanCastComObject(OBJECTREF obj, MethodTable * pTargetMT)
1601{
1602 CONTRACTL
1603 {
1604 THROWS;
1605 GC_TRIGGERS;
1606 MODE_COOPERATIVE;
1607 }
1608 CONTRACTL_END;
1609
1610 if (!obj)
1611 return TRUE;
1612
1613 if (pTargetMT->IsInterface())
1614 {
1615 return Object::SupportsInterface(obj, pTargetMT);
1616 }
1617 else
1618 {
1619 return obj->GetMethodTable()->CanCastToClass(pTargetMT);
1620 }
1621}
1622
1623// Returns TRUE iff the argument represents the "__ComObject" type or
1624// any type derived from it (i.e. typelib-imported RCWs).
1625BOOL IsComWrapperClass(TypeHandle type)
1626{
1627 CONTRACTL
1628 {
1629 NOTHROW;
1630 GC_NOTRIGGER;
1631 MODE_ANY;
1632 }
1633 CONTRACTL_END;
1634
1635 MethodTable* pMT = type.GetMethodTable();
1636 if (pMT == NULL)
1637 return FALSE;
1638
1639 return pMT->IsComObjectType();
1640}
1641
1642// Returns TRUE iff the argument represents the "__ComObject" type.
1643BOOL IsComObjectClass(TypeHandle type)
1644{
1645 CONTRACTL
1646 {
1647 NOTHROW;
1648 GC_NOTRIGGER;
1649 MODE_ANY;
1650 SO_TOLERANT;
1651 }
1652 CONTRACTL_END;
1653
1654#ifdef FEATURE_COMINTEROP
1655 if (!type.IsTypeDesc())
1656 {
1657 MethodTable *pMT = type.AsMethodTable();
1658
1659 if (pMT->IsComObjectType())
1660 {
1661 // May be __ComObject or typed RCW. __ComObject must have already been loaded
1662 // if we see an MT marked like this so calling the *NoInit method is sufficient.
1663
1664 return pMT == g_pBaseCOMObject;
1665 }
1666 }
1667#endif
1668
1669 return FALSE;
1670}
1671
1672VOID
1673ReadBestFitCustomAttribute(MethodDesc* pMD, BOOL* BestFit, BOOL* ThrowOnUnmappableChar)
1674{
1675 CONTRACTL
1676 {
1677 NOTHROW;
1678 GC_NOTRIGGER;
1679 SO_TOLERANT;
1680 MODE_ANY;
1681 }
1682 CONTRACTL_END;
1683
1684 ReadBestFitCustomAttribute(pMD->GetMDImport(),
1685 pMD->GetMethodTable()->GetCl(),
1686 BestFit, ThrowOnUnmappableChar);
1687}
1688
1689VOID
1690ReadBestFitCustomAttribute(IMDInternalImport* pInternalImport, mdTypeDef cl, BOOL* BestFit, BOOL* ThrowOnUnmappableChar)
1691{
1692 // Set the attributes to their defaults, just to be safe.
1693 *BestFit = TRUE;
1694 *ThrowOnUnmappableChar = FALSE;
1695
1696 CONTRACTL
1697 {
1698 NOTHROW;
1699 GC_NOTRIGGER;
1700 MODE_ANY;
1701 SO_TOLERANT;
1702 PRECONDITION(CheckPointer(pInternalImport));
1703 }
1704 CONTRACTL_END;
1705
1706 HRESULT hr;
1707 BYTE* pData;
1708 ULONG cbCount;
1709
1710 // A well-formed BestFitMapping attribute will have at least 5 bytes
1711 // 1,2 for the prolog (should be 0x1, 0x0)
1712 // 3 for the BestFitMapping bool
1713 // 4,5 for the number of named parameters (will be 0 if ThrowOnUnmappableChar doesn't exist)
1714 // 6 - 29 for the description of ThrowOnUnmappableChar
1715 // 30 for the ThrowOnUnmappableChar bool
1716
1717 // Try the assembly first
1718 hr = pInternalImport->GetCustomAttributeByName(TokenFromRid(1, mdtAssembly), INTEROP_BESTFITMAPPING_TYPE, (const VOID**)(&pData), &cbCount);
1719 if ((hr == S_OK) && (pData) && (cbCount > 4) && (pData[0] == 1) && (pData[1] == 0))
1720 {
1721 _ASSERTE((cbCount == 5) || (cbCount == 30));
1722
1723 // index to 2 to skip prolog
1724 *BestFit = pData[2] != 0;
1725
1726 // If this parameter exists,
1727 if (cbCount == 30)
1728 // index to end of data to skip description of named argument
1729 *ThrowOnUnmappableChar = pData[29] != 0;
1730 }
1731
1732 // Now try the interface/class/struct
1733 if (IsNilToken(cl))
1734 return;
1735 hr = pInternalImport->GetCustomAttributeByName(cl, INTEROP_BESTFITMAPPING_TYPE, (const VOID**)(&pData), &cbCount);
1736 if ((hr == S_OK) && (pData) && (cbCount > 4) && (pData[0] == 1) && (pData[1] == 0))
1737 {
1738 _ASSERTE((cbCount == 5) || (cbCount == 30));
1739
1740 // index to 2 to skip prolog
1741 *BestFit = pData[2] != 0;
1742
1743 // If this parameter exists,
1744 if (cbCount == 30)
1745 // index to end of data to skip description of named argument
1746 *ThrowOnUnmappableChar = pData[29] != 0;
1747 }
1748}
1749
1750
1751int InternalWideToAnsi(__in_ecount(iNumWideChars) LPCWSTR szWideString, int iNumWideChars, __out_ecount_opt(cbAnsiBufferSize) LPSTR szAnsiString, int cbAnsiBufferSize, BOOL fBestFit, BOOL fThrowOnUnmappableChar)
1752{
1753 CONTRACTL
1754 {
1755 THROWS;
1756 GC_TRIGGERS;
1757 MODE_ANY;
1758 }
1759 CONTRACTL_END;
1760
1761
1762 if ((szWideString == 0) || (iNumWideChars == 0) || (szAnsiString == 0) || (cbAnsiBufferSize == 0))
1763 return 0;
1764
1765 DWORD flags = 0;
1766 int retval;
1767
1768 if (fBestFit == FALSE)
1769 flags = WC_NO_BEST_FIT_CHARS;
1770
1771 if (fThrowOnUnmappableChar)
1772 {
1773 BOOL DefaultCharUsed = FALSE;
1774 retval = WszWideCharToMultiByte(CP_ACP,
1775 flags,
1776 szWideString,
1777 iNumWideChars,
1778 szAnsiString,
1779 cbAnsiBufferSize,
1780 NULL,
1781 &DefaultCharUsed);
1782 DWORD lastError = GetLastError();
1783
1784 if (retval == 0)
1785 {
1786 INSTALL_UNWIND_AND_CONTINUE_HANDLER;
1787 COMPlusThrowHR(HRESULT_FROM_WIN32(lastError));
1788 UNINSTALL_UNWIND_AND_CONTINUE_HANDLER;
1789 }
1790
1791 if (DefaultCharUsed)
1792 {
1793 struct HelperThrow
1794 {
1795 static void Throw()
1796 {
1797 COMPlusThrow( kArgumentException, IDS_EE_MARSHAL_UNMAPPABLE_CHAR );
1798 }
1799 };
1800
1801 ENCLOSE_IN_EXCEPTION_HANDLER( HelperThrow::Throw );
1802 }
1803
1804 }
1805 else
1806 {
1807 retval = WszWideCharToMultiByte(CP_ACP,
1808 flags,
1809 szWideString,
1810 iNumWideChars,
1811 szAnsiString,
1812 cbAnsiBufferSize,
1813 NULL,
1814 NULL);
1815 DWORD lastError = GetLastError();
1816
1817 if (retval == 0)
1818 {
1819 INSTALL_UNWIND_AND_CONTINUE_HANDLER;
1820 COMPlusThrowHR(HRESULT_FROM_WIN32(lastError));
1821 UNINSTALL_UNWIND_AND_CONTINUE_HANDLER;
1822 }
1823 }
1824
1825 return retval;
1826}
1827
1828namespace
1829{
1830 HRESULT TryParseClassInterfaceAttribute(
1831 _In_ IMDInternalImport *import,
1832 _In_ mdToken tkObj,
1833 _Out_ CorClassIfaceAttr *val)
1834 {
1835 CONTRACTL
1836 {
1837 NOTHROW;
1838 GC_TRIGGERS;
1839 MODE_ANY;
1840 PRECONDITION(CheckPointer(import));
1841 PRECONDITION(CheckPointer(val));
1842 }
1843 CONTRACTL_END
1844
1845 const BYTE *pVal = nullptr;
1846 ULONG cbVal = 0;
1847 HRESULT hr = import->GetCustomAttributeByName(tkObj, INTEROP_CLASSINTERFACE_TYPE, (const void**)&pVal, &cbVal);
1848 if (hr != S_OK)
1849 {
1850 *val = clsIfNone;
1851 return S_FALSE;
1852 }
1853
1854 CustomAttributeParser cap(pVal, cbVal);
1855 if (FAILED(cap.ValidateProlog()))
1856 return COR_E_BADIMAGEFORMAT;
1857
1858 U1 u1;
1859 if (FAILED(cap.GetU1(&u1)))
1860 return COR_E_BADIMAGEFORMAT;
1861
1862 *val = (CorClassIfaceAttr)(u1);
1863 _ASSERTE(*val < clsIfLast);
1864
1865 return S_OK;
1866 }
1867}
1868
1869//---------------------------------------------------------
1870// Read the ClassInterfaceType custom attribute info from
1871// both assembly level and class level
1872//---------------------------------------------------------
1873CorClassIfaceAttr ReadClassInterfaceTypeCustomAttribute(TypeHandle type)
1874{
1875 CONTRACTL
1876 {
1877 THROWS;
1878 GC_TRIGGERS;
1879 MODE_ANY;
1880 PRECONDITION(!type.IsInterface());
1881 }
1882 CONTRACTL_END
1883
1884 // Ignore classic COM interop CA on WinRT types
1885 if (!type.GetMethodTable()->IsWinRTObjectType() && !type.GetMethodTable()->IsExportedToWinRT())
1886 {
1887 CorClassIfaceAttr attrValueMaybe;
1888
1889 // First look for the class interface attribute at the class level.
1890 HRESULT hr = TryParseClassInterfaceAttribute(type.GetMethodTable()->GetMDImport(), type.GetCl(), &attrValueMaybe);
1891 if (FAILED(hr))
1892 ThrowHR(hr, BFA_BAD_CLASS_INT_CA_FORMAT);
1893
1894 if (hr == S_FALSE)
1895 {
1896 // Check the class interface attribute at the assembly level.
1897 Assembly *pAssembly = type.GetAssembly();
1898 hr = TryParseClassInterfaceAttribute(pAssembly->GetManifestImport(), pAssembly->GetManifestToken(), &attrValueMaybe);
1899 if (FAILED(hr))
1900 ThrowHR(hr, BFA_BAD_CLASS_INT_CA_FORMAT);
1901 }
1902
1903 if (hr == S_OK)
1904 return attrValueMaybe;
1905 }
1906
1907 return DEFAULT_CLASS_INTERFACE_TYPE;
1908}
1909
1910//--------------------------------------------------------------------------------
1911// GetErrorInfo helper, enables and disables GC during call-outs
1912HRESULT SafeGetErrorInfo(IErrorInfo **ppIErrInfo)
1913{
1914 CONTRACTL
1915 {
1916 NOTHROW;
1917 GC_TRIGGERS;
1918 MODE_ANY;
1919 PRECONDITION(CheckPointer(ppIErrInfo));
1920 }
1921 CONTRACTL_END;
1922
1923 *ppIErrInfo = NULL;
1924
1925#ifdef FEATURE_COMINTEROP
1926 GCX_PREEMP();
1927
1928 HRESULT hr = S_OK;
1929 EX_TRY
1930 {
1931 hr = GetErrorInfo(0, ppIErrInfo);
1932 }
1933 EX_CATCH
1934 {
1935 hr = E_OUTOFMEMORY;
1936 }
1937 EX_END_CATCH(SwallowAllExceptions);
1938
1939 return hr;
1940#else // FEATURE_COMINTEROP
1941 // Indicate no error object
1942 return S_FALSE;
1943#endif
1944}
1945
1946
1947#include <optsmallperfcritical.h>
1948//--------------------------------------------------------------------------------
1949// QI helper, enables and disables GC during call-outs
1950HRESULT SafeQueryInterface(IUnknown* pUnk, REFIID riid, IUnknown** pResUnk)
1951{
1952 STATIC_CONTRACT_NOTHROW;
1953 STATIC_CONTRACT_GC_TRIGGERS;
1954 STATIC_CONTRACT_MODE_ANY;
1955 STATIC_CONTRACT_SO_TOLERANT;
1956 _ASSERTE(pUnk);
1957 _ASSERTE(pResUnk);
1958
1959 Thread * const pThread = GetThreadNULLOk();
1960
1961 *pResUnk = NULL;
1962 HRESULT hr = E_FAIL;
1963
1964 GCX_PREEMP_NO_DTOR_HAVE_THREAD(pThread);
1965
1966 BEGIN_CONTRACT_VIOLATION(ThrowsViolation); // message pump could happen, so arbitrary managed code could run
1967 BEGIN_SO_TOLERANT_CODE(pThread);
1968
1969 struct Param { HRESULT * const hr; IUnknown** const pUnk; REFIID riid; IUnknown*** const pResUnk; } param = { &hr, &pUnk, riid, &pResUnk };
1970#define PAL_TRY_ARG(argName) (*(pParam->argName))
1971#define PAL_TRY_REFARG(argName) (pParam->argName)
1972 PAL_TRY(Param * const, pParam, &param)
1973 {
1974 PAL_TRY_ARG(hr) = PAL_TRY_ARG(pUnk)->QueryInterface(PAL_TRY_REFARG(riid), (void**) PAL_TRY_ARG(pResUnk));
1975 }
1976 PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1977 {
1978#if defined(STACK_GUARDS_DEBUG)
1979 // Catching and just swallowing an exception means we need to tell
1980 // the SO code that it should go back to normal operation, as it
1981 // currently thinks that the exception is still on the fly.
1982 GetThread()->GetCurrentStackGuard()->RestoreCurrentGuard();
1983#endif
1984 }
1985 PAL_ENDTRY;
1986#undef PAL_TRY_ARG
1987#undef PAL_TRY_REFARG
1988
1989 END_SO_TOLERANT_CODE;
1990 END_CONTRACT_VIOLATION;
1991
1992 LOG((LF_INTEROP, LL_EVERYTHING, hr == S_OK ? "QI Succeeded\n" : "QI Failed\n"));
1993
1994 // Ensure if the QI returned ok that it actually set a pointer.
1995 if (hr == S_OK)
1996 {
1997 if (*pResUnk == NULL)
1998 hr = E_NOINTERFACE;
1999 }
2000
2001 GCX_PREEMP_NO_DTOR_END();
2002
2003 return hr;
2004}
2005
2006
2007//--------------------------------------------------------------------------------
2008// QI helper, must be called in preemptive mode. Faster than the MODE_ANY version
2009// because it doesn't need to toggle the mode. Use this version only if you already
2010// know that you're in preemptive mode for other reasons.
2011HRESULT SafeQueryInterfacePreemp(IUnknown* pUnk, REFIID riid, IUnknown** pResUnk)
2012{
2013 STATIC_CONTRACT_NOTHROW;
2014 STATIC_CONTRACT_GC_TRIGGERS;
2015 STATIC_CONTRACT_MODE_PREEMPTIVE;
2016 STATIC_CONTRACT_SO_TOLERANT;
2017 _ASSERTE(pUnk);
2018 _ASSERTE(pResUnk);
2019
2020 Thread * const pThread = GetThreadNULLOk();
2021
2022 *pResUnk = NULL;
2023 HRESULT hr = E_FAIL;
2024
2025 BEGIN_CONTRACT_VIOLATION(ThrowsViolation); // message pump could happen, so arbitrary managed code could run
2026 BEGIN_SO_TOLERANT_CODE(pThread);
2027
2028 struct Param { HRESULT * const hr; IUnknown** const pUnk; REFIID riid; IUnknown*** const pResUnk; } param = { &hr, &pUnk, riid, &pResUnk };
2029#define PAL_TRY_ARG(argName) (*(pParam->argName))
2030#define PAL_TRY_REFARG(argName) (pParam->argName)
2031 PAL_TRY(Param * const, pParam, &param)
2032 {
2033 PAL_TRY_ARG(hr) = PAL_TRY_ARG(pUnk)->QueryInterface(PAL_TRY_REFARG(riid), (void**) PAL_TRY_ARG(pResUnk));
2034 }
2035 PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2036 {
2037#if defined(STACK_GUARDS_DEBUG)
2038 // Catching and just swallowing an exception means we need to tell
2039 // the SO code that it should go back to normal operation, as it
2040 // currently thinks that the exception is still on the fly.
2041 GetThread()->GetCurrentStackGuard()->RestoreCurrentGuard();
2042#endif
2043 }
2044 PAL_ENDTRY;
2045#undef PAL_TRY_ARG
2046#undef PAL_TRY_REFARG
2047
2048 END_SO_TOLERANT_CODE;
2049 END_CONTRACT_VIOLATION;
2050
2051
2052 LOG((LF_INTEROP, LL_EVERYTHING, hr == S_OK ? "QI Succeeded\n" : "QI Failed\n"));
2053
2054 // Ensure if the QI returned ok that it actually set a pointer.
2055 if (hr == S_OK)
2056 {
2057 if (*pResUnk == NULL)
2058 hr = E_NOINTERFACE;
2059 }
2060
2061 return hr;
2062}
2063#include <optdefault.h>
2064
2065#ifdef FEATURE_COMINTEROP
2066
2067#ifndef CROSSGEN_COMPILE
2068
2069//--------------------------------------------------------------------------------
2070// Cleanup helpers
2071//--------------------------------------------------------------------------------
2072void MinorCleanupSyncBlockComData(InteropSyncBlockInfo* pInteropInfo)
2073{
2074 CONTRACTL
2075 {
2076 NOTHROW;
2077 GC_NOTRIGGER;
2078 MODE_ANY;
2079 PRECONDITION( GCHeapUtilities::IsGCInProgress() || ( (g_fEEShutDown & ShutDown_SyncBlock) && g_fProcessDetach ) );
2080 }
2081 CONTRACTL_END;
2082
2083 // No need to notify the thread that the RCW is in use here.
2084 // This is a privileged function called during GC or shutdown.
2085 RCW* pRCW = pInteropInfo->GetRawRCW();
2086 if (pRCW)
2087 pRCW->MinorCleanup();
2088}
2089
2090void CleanupSyncBlockComData(InteropSyncBlockInfo* pInteropInfo)
2091{
2092 CONTRACTL
2093 {
2094 THROWS;
2095 GC_TRIGGERS;
2096 MODE_ANY;
2097 }
2098 CONTRACTL_END;
2099
2100 if ((g_fEEShutDown & ShutDown_SyncBlock) && g_fProcessDetach )
2101 MinorCleanupSyncBlockComData(pInteropInfo);
2102
2103#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
2104 ComClassFactory* pComClassFactory = pInteropInfo->GetComClassFactory();
2105 if (pComClassFactory)
2106 {
2107 delete pComClassFactory;
2108 pInteropInfo->SetComClassFactory(NULL);
2109 }
2110#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
2111
2112 // No need to notify the thread that the RCW is in use here.
2113 // This is only called during finalization of a __ComObject so no one
2114 // else could have a reference to this object.
2115 RCW* pRCW = pInteropInfo->GetRawRCW();
2116 if (pRCW)
2117 {
2118 pInteropInfo->SetRawRCW(NULL);
2119 pRCW->Cleanup();
2120 }
2121
2122 ComCallWrapper* pCCW = pInteropInfo->GetCCW();
2123 if (pCCW)
2124 {
2125 pInteropInfo->SetCCW(NULL);
2126 pCCW->Cleanup();
2127 }
2128}
2129
2130void ReleaseRCWsInCachesNoThrow(LPVOID pCtxCookie)
2131{
2132 CONTRACTL
2133 {
2134 DISABLED(NOTHROW);
2135 GC_TRIGGERS;
2136 MODE_ANY;
2137 PRECONDITION(CheckPointer(pCtxCookie, NULL_OK));
2138 }
2139 CONTRACTL_END;
2140
2141 EX_TRY
2142 {
2143 ReleaseRCWsInCaches(pCtxCookie);
2144 }
2145 EX_CATCH
2146 {
2147 }
2148 EX_END_CATCH(SwallowAllExceptions);
2149}
2150
2151//--------------------------------------------------------------------------------
2152// Helper to release all of the RCWs in the specified context across all caches.
2153// If pCtxCookie is NULL, release all RCWs
2154void ReleaseRCWsInCaches(LPVOID pCtxCookie)
2155{
2156 CONTRACTL
2157 {
2158 THROWS;
2159 GC_TRIGGERS;
2160 MODE_ANY;
2161 PRECONDITION(CheckPointer(pCtxCookie, NULL_OK));
2162 }
2163 CONTRACTL_END;
2164
2165 // Go through all the app domains and for each one release all the
2166 // RCW's that live in the current context.
2167 AppDomainIterator i(TRUE);
2168 while (i.Next())
2169 i.GetDomain()->ReleaseRCWs(pCtxCookie);
2170
2171 if (!g_fEEShutDown)
2172 {
2173 GCX_COOP();
2174
2175 // If the finalizer thread has sync blocks to clean up or if it is in the process
2176 // of cleaning up the sync blocks, we need to wait for it to finish.
2177 if (FinalizerThread::GetFinalizerThread()->RequireSyncBlockCleanup() || SyncBlockCache::GetSyncBlockCache()->IsSyncBlockCleanupInProgress())
2178 FinalizerThread::FinalizerThreadWait();
2179
2180 // If more sync blocks were added while the finalizer thread was calling the finalizers
2181 // or while it was transitioning into a context to clean up the IP's, we need to wake
2182 // it up again to have it clean up the newly added sync blocks.
2183 if (FinalizerThread::GetFinalizerThread()->RequireSyncBlockCleanup() || SyncBlockCache::GetSyncBlockCache()->IsSyncBlockCleanupInProgress())
2184 FinalizerThread::FinalizerThreadWait();
2185 }
2186}
2187
2188//--------------------------------------------------------------------------------
2189// Marshalling Helpers
2190//--------------------------------------------------------------------------------
2191
2192
2193// Convert an IUnknown to CCW, returns NULL if the pUnk is not on
2194// a managed tear-off (OR) if the pUnk is to a managed tear-off that
2195// has been aggregated
2196ComCallWrapper* GetCCWFromIUnknown(IUnknown* pUnk, BOOL bEnableCustomization)
2197{
2198 CONTRACT (ComCallWrapper*)
2199 {
2200 NOTHROW;
2201 GC_TRIGGERS;
2202 MODE_ANY;
2203 PRECONDITION(CheckPointer(pUnk));
2204 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
2205 }
2206 CONTRACT_END;
2207
2208 ComCallWrapper* pWrap = MapIUnknownToWrapper(pUnk);
2209 if (pWrap != NULL)
2210 {
2211 // check if this wrapper is aggregated
2212 if (pWrap->GetOuter() != NULL)
2213 {
2214 pWrap = NULL;
2215 }
2216 }
2217
2218 RETURN pWrap;
2219}
2220
2221HRESULT LoadRegTypeLib(_In_ REFGUID guid,
2222 _In_ unsigned short wVerMajor,
2223 _In_ unsigned short wVerMinor,
2224 _Outptr_ ITypeLib **pptlib)
2225{
2226 CONTRACTL
2227 {
2228 NOTHROW;
2229 GC_TRIGGERS;
2230 MODE_ANY;
2231 }
2232 CONTRACTL_END;
2233
2234 *pptlib = NULL;
2235
2236 GCX_PREEMP();
2237
2238 BSTRHolder wzPath;
2239 HRESULT hr = S_OK;
2240
2241 EX_TRY
2242 {
2243 hr = QueryPathOfRegTypeLib(guid, wVerMajor, wVerMinor, LOCALE_USER_DEFAULT, &wzPath);
2244 if (SUCCEEDED(hr))
2245 {
2246#ifdef _WIN64
2247 REGKIND rk = (REGKIND)(REGKIND_NONE | LOAD_TLB_AS_64BIT);
2248#else
2249 REGKIND rk = (REGKIND)(REGKIND_NONE | LOAD_TLB_AS_32BIT);
2250#endif // _WIN64
2251 hr = LoadTypeLibEx(wzPath, rk, pptlib);
2252 }
2253 }
2254 EX_CATCH
2255 {
2256 hr = GET_EXCEPTION()->GetHR();
2257 }
2258 EX_END_CATCH(SwallowAllExceptions);
2259
2260 return hr;
2261}
2262
2263VOID EnsureComStarted(BOOL fCoInitCurrentThread)
2264{
2265 CONTRACTL
2266 {
2267 THROWS;
2268 GC_TRIGGERS;
2269 MODE_ANY;
2270 PRECONDITION(GetThread() || !fCoInitCurrentThread);
2271 PRECONDITION(g_fEEStarted);
2272 }
2273 CONTRACTL_END;
2274
2275 if (g_fComStarted == FALSE)
2276 {
2277 FinalizerThread::GetFinalizerThread()->SetRequiresCoInitialize();
2278
2279 // Attempt to set the thread's apartment model (to MTA by default). May not
2280 // succeed (if someone beat us to the punch). That doesn't matter (since
2281 // COM+ objects are now apartment agile), we only care that a CoInitializeEx
2282 // has been performed on this thread by us.
2283 if (fCoInitCurrentThread)
2284 GetThread()->SetApartment(Thread::AS_InMTA, FALSE);
2285
2286 // set the finalizer event
2287 FinalizerThread::EnableFinalization();
2288
2289 g_fComStarted = TRUE;
2290 }
2291}
2292
2293HRESULT EnsureComStartedNoThrow(BOOL fCoInitCurrentThread)
2294{
2295 CONTRACTL
2296 {
2297 NOTHROW;
2298 GC_TRIGGERS;
2299 MODE_ANY;
2300 SO_TOLERANT;
2301 PRECONDITION(g_fEEStarted);
2302 PRECONDITION(GetThread() != NULL); // Should always be inside BEGIN_EXTERNAL_ENTRYPOINT
2303 }
2304 CONTRACTL_END;
2305
2306 HRESULT hr = S_OK;
2307
2308 if (!g_fComStarted)
2309 {
2310 GCX_COOP();
2311 EX_TRY
2312 {
2313 BEGIN_SO_INTOLERANT_CODE(GetThread());
2314
2315 EnsureComStarted(fCoInitCurrentThread);
2316
2317 END_SO_INTOLERANT_CODE;
2318 }
2319 EX_CATCH_HRESULT(hr);
2320 }
2321
2322 return hr;
2323}
2324
2325//--------------------------------------------------------------------------------
2326// BOOL ExtendsComImport(MethodTable* pMT);
2327// check if the class is OR extends a COM Imported class
2328BOOL ExtendsComImport(MethodTable* pMT)
2329{
2330 CONTRACTL
2331 {
2332 NOTHROW;
2333 GC_NOTRIGGER;
2334 MODE_ANY;
2335 PRECONDITION(CheckPointer(pMT));
2336 }
2337 CONTRACTL_END;
2338
2339 while (pMT != NULL && !pMT->IsComImport())
2340 {
2341 pMT = pMT->GetParentMethodTable();
2342 }
2343 return pMT != NULL;
2344}
2345
2346#ifdef FEATURE_CLASSIC_COMINTEROP
2347//--------------------------------------------------------------------------------
2348// Gets the CLSID from the specified Prog ID.
2349
2350HRESULT GetCLSIDFromProgID(__in_z WCHAR *strProgId, GUID *pGuid)
2351{
2352 CONTRACTL
2353 {
2354 NOTHROW;
2355 GC_TRIGGERS;
2356 MODE_PREEMPTIVE;
2357 }
2358 CONTRACTL_END;
2359
2360 HRESULT hr = S_OK;
2361
2362#ifdef FEATURE_CORESYSTEM
2363 return CLSIDFromProgID(strProgId, pGuid);
2364#else
2365 return CLSIDFromProgIDEx(strProgId, pGuid);
2366#endif
2367}
2368#endif // FEATURE_CLASSIC_COMINTEROP
2369
2370#include <optsmallperfcritical.h>
2371//--------------------------------------------------------------------------------
2372// AddRef helper, enables and disables GC during call-outs
2373ULONG SafeAddRef(IUnknown* pUnk)
2374{
2375 CONTRACTL
2376 {
2377 NOTHROW;
2378 GC_TRIGGERS;
2379 MODE_ANY;
2380 SO_TOLERANT;
2381 }
2382 CONTRACTL_END;
2383
2384 ULONG res = ~0;
2385 if (pUnk == NULL)
2386 return res;
2387
2388 GCX_PREEMP_NO_DTOR();
2389
2390 // @TODO: Consider special-casing this when we know it's one of ours so
2391 // that we can avoid having to 'leave' and then 'enter'.
2392
2393 CONTRACT_VIOLATION(ThrowsViolation); // arbitrary managed code could run
2394
2395 res = pUnk->AddRef();
2396
2397 GCX_PREEMP_NO_DTOR_END();
2398
2399 return res;
2400}
2401
2402//--------------------------------------------------------------------------------
2403// AddRef helper, must be called in preemptive mode. Only use this variant if
2404// you already know you're in preemptive mode for other reasons.
2405ULONG SafeAddRefPreemp(IUnknown* pUnk)
2406{
2407 CONTRACTL
2408 {
2409 NOTHROW;
2410 GC_TRIGGERS;
2411 MODE_PREEMPTIVE;
2412 SO_TOLERANT;
2413 }
2414 CONTRACTL_END;
2415
2416 ULONG res = ~0;
2417 if (pUnk == NULL)
2418 return res;
2419
2420 // @TODO: Consider special-casing this when we know it's one of ours so
2421 // that we can avoid having to 'leave' and then 'enter'.
2422
2423 CONTRACT_VIOLATION(ThrowsViolation); // arbitrary managed code could run
2424
2425 res = pUnk->AddRef();
2426
2427 return res;
2428}
2429#include <optdefault.h>
2430
2431//--------------------------------------------------------------------------------
2432// Ole RPC seems to return an inconsistent SafeArray for arrays created with
2433// SafeArrayVector(VT_BSTR). OleAut's SafeArrayGetVartype() doesn't notice
2434// the inconsistency and returns a valid-seeming (but wrong vartype.)
2435// Our version is more discriminating. This should only be used for
2436// marshaling scenarios where we can assume unmanaged code permissions
2437// (and hence are already in a position of trusting unmanaged data.)
2438
2439HRESULT ClrSafeArrayGetVartype(_In_ SAFEARRAY *psa, _Out_ VARTYPE *pvt)
2440{
2441 CONTRACTL
2442 {
2443 NOTHROW;
2444 GC_NOTRIGGER;
2445 MODE_ANY;
2446 PRECONDITION(CheckPointer(psa));
2447 PRECONDITION(CheckPointer(pvt));
2448 }
2449 CONTRACTL_END;
2450
2451 if (pvt == NULL || psa == NULL)
2452 {
2453 // This is the HRESULT returned by OLEAUT if either of the args are null.
2454 return E_INVALIDARG;
2455 }
2456
2457 USHORT fFeatures = psa->fFeatures;
2458 USHORT hardwiredType = (fFeatures & (FADF_BSTR|FADF_UNKNOWN|FADF_DISPATCH|FADF_VARIANT));
2459
2460 if (hardwiredType == FADF_BSTR && psa->cbElements == sizeof(BSTR))
2461 {
2462 *pvt = VT_BSTR;
2463 return S_OK;
2464 }
2465 else if (hardwiredType == FADF_UNKNOWN && psa->cbElements == sizeof(IUnknown*))
2466 {
2467 *pvt = VT_UNKNOWN;
2468 return S_OK;
2469 }
2470 else if (hardwiredType == FADF_DISPATCH && psa->cbElements == sizeof(IDispatch*))
2471 {
2472 *pvt = VT_DISPATCH;
2473 return S_OK;
2474 }
2475 else if (hardwiredType == FADF_VARIANT && psa->cbElements == sizeof(VARIANT))
2476 {
2477 *pvt = VT_VARIANT;
2478 return S_OK;
2479 }
2480 else
2481 {
2482 _ASSERTE(GetModuleHandleA("oleaut32.dll") != NULL);
2483 // We have got a SAFEARRAY. Oleaut32.dll should have been loaded.
2484 CONTRACT_VIOLATION(ThrowsViolation);
2485 return ::SafeArrayGetVartype(psa, pvt);
2486 }
2487}
2488
2489//--------------------------------------------------------------------------------
2490// // safe VariantChangeType
2491// Release helper, enables and disables GC during call-outs
2492HRESULT SafeVariantChangeType(_Inout_ VARIANT* pVarRes, _In_ VARIANT* pVarSrc,
2493 unsigned short wFlags, VARTYPE vt)
2494{
2495 CONTRACTL
2496 {
2497 NOTHROW;
2498 GC_TRIGGERS;
2499 MODE_ANY;
2500 PRECONDITION(CheckPointer(pVarRes));
2501 PRECONDITION(CheckPointer(pVarSrc));
2502 }
2503 CONTRACTL_END;
2504
2505 HRESULT hr = S_OK;
2506 if (pVarRes)
2507 {
2508 GCX_PREEMP();
2509 EX_TRY
2510 {
2511 hr = VariantChangeType(pVarRes, pVarSrc, wFlags, vt);
2512 }
2513 EX_CATCH
2514 {
2515 hr = GET_EXCEPTION()->GetHR();
2516 }
2517 EX_END_CATCH(SwallowAllExceptions);
2518 }
2519
2520 return hr;
2521}
2522
2523//--------------------------------------------------------------------------------
2524HRESULT SafeVariantChangeTypeEx(_Inout_ VARIANT* pVarRes, _In_ VARIANT* pVarSrc,
2525 LCID lcid, unsigned short wFlags, VARTYPE vt)
2526{
2527 CONTRACTL
2528 {
2529 NOTHROW;
2530 GC_TRIGGERS;
2531 MODE_ANY;
2532 PRECONDITION(CheckPointer(pVarRes));
2533 PRECONDITION(CheckPointer(pVarSrc));
2534 }
2535 CONTRACTL_END;
2536
2537 GCX_PREEMP();
2538 _ASSERTE(GetModuleHandleA("oleaut32.dll") != NULL);
2539 CONTRACT_VIOLATION(ThrowsViolation);
2540
2541 HRESULT hr = VariantChangeTypeEx (pVarRes, pVarSrc,lcid,wFlags,vt);
2542
2543 return hr;
2544}
2545
2546//--------------------------------------------------------------------------------
2547void SafeVariantInit(VARIANT* pVar)
2548{
2549 CONTRACTL
2550 {
2551 NOTHROW;
2552 GC_TRIGGERS;
2553 MODE_ANY;
2554 PRECONDITION(CheckPointer(pVar));
2555 }
2556 CONTRACTL_END;
2557
2558 // From the oa sources
2559 V_VT(pVar) = VT_EMPTY;
2560}
2561
2562//--------------------------------------------------------------------------------
2563// void SafeReleaseStream(IStream *pStream)
2564void SafeReleaseStream(IStream *pStream)
2565{
2566 CONTRACTL
2567 {
2568 NOTHROW;
2569 GC_TRIGGERS;
2570 MODE_ANY;
2571 PRECONDITION(CheckPointer(pStream));
2572 }
2573 CONTRACTL_END;
2574
2575 GCX_PREEMP();
2576
2577 {
2578 HRESULT hr = CoReleaseMarshalData(pStream);
2579
2580#ifdef _DEBUG
2581 wchar_t logStr[200];
2582 swprintf_s(logStr, NumItems(logStr), W("Object gone: CoReleaseMarshalData returned %x, file %S, line %d\n"), hr, __FILE__, __LINE__);
2583 LogInterop(logStr);
2584 if (hr != S_OK)
2585 {
2586 // Reset the stream to the begining
2587 LARGE_INTEGER li;
2588 LISet32(li, 0);
2589 ULARGE_INTEGER li2;
2590 pStream->Seek(li, STREAM_SEEK_SET, &li2);
2591 hr = CoReleaseMarshalData(pStream);
2592 swprintf_s(logStr, NumItems(logStr), W("Object gone: CoReleaseMarshalData returned %x, file %S, line %d\n"), hr, __FILE__, __LINE__);
2593 LogInterop(logStr);
2594 }
2595#endif
2596 }
2597
2598 ULONG cbRef = SafeReleasePreemp(pStream);
2599 LogInteropRelease(pStream, cbRef, "Release marshal Stream");
2600}
2601
2602//---------------------------------------------------------------------------
2603// is the iid represent an IClassX for this class
2604BOOL IsIClassX(MethodTable *pMT, REFIID riid, ComMethodTable **ppComMT)
2605{
2606 CONTRACTL
2607 {
2608 THROWS;
2609 GC_TRIGGERS;
2610 MODE_ANY;
2611 PRECONDITION(CheckPointer(pMT));
2612 PRECONDITION(CheckPointer(ppComMT));
2613 }
2614 CONTRACTL_END;
2615
2616 // Walk up the hierarchy starting at the specified method table and compare
2617 // the IID's of the IClassX's against the specified IID.
2618 while (pMT != NULL)
2619 {
2620 ComCallWrapperTemplate *pTemplate = ComCallWrapperTemplate::GetTemplate(pMT);
2621 if (pTemplate->SupportsIClassX())
2622 {
2623 ComMethodTable *pComMT =
2624 ComCallWrapperTemplate::SetupComMethodTableForClass(pMT, FALSE);
2625 _ASSERTE(pComMT);
2626
2627 if (IsEqualIID(riid, pComMT->GetIID()))
2628 {
2629 *ppComMT = pComMT;
2630 return TRUE;
2631 }
2632 }
2633
2634 pMT = pMT->GetComPlusParentMethodTable();
2635 }
2636
2637 return FALSE;
2638}
2639
2640#endif //#ifndef CROSSGEN_COMPILE
2641
2642
2643//---------------------------------------------------------------------------
2644// Returns TRUE if we support IClassX (the auto-generated class interface)
2645// for the given class.
2646BOOL ClassSupportsIClassX(MethodTable *pMT)
2647{
2648 CONTRACTL
2649 {
2650 THROWS;
2651 GC_TRIGGERS;
2652 MODE_ANY;
2653 }
2654 CONTRACTL_END;
2655
2656 // WinRT delegates use IClassX
2657 if (pMT->IsWinRTDelegate())
2658 return TRUE;
2659
2660 if (pMT->IsWinRTObjectType() || pMT->IsExportedToWinRT())
2661 {
2662 // Other than that WinRT does not need IClassX so the goal is to return FALSE for
2663 // anything that is guaranteed to not be a legacy classic COM interop scenario
2664 return FALSE;
2665 }
2666
2667 // If the class is decorated with an explicit ClassInterfaceAttribute, we're going to say yes.
2668 if (S_OK == pMT->GetMDImport()->GetCustomAttributeByName(pMT->GetCl(), INTEROP_CLASSINTERFACE_TYPE, NULL, NULL))
2669 return TRUE;
2670
2671 MethodTable::InterfaceMapIterator it = pMT->IterateInterfaceMap();
2672 while (it.Next())
2673 {
2674 MethodTable *pItfMT = it.GetInterfaceInfo()->GetApproxMethodTable(pMT->GetLoaderModule());
2675 if (pItfMT->IsProjectedFromWinRT())
2676 return FALSE;
2677 }
2678
2679 return TRUE;
2680}
2681
2682
2683#ifndef CROSSGEN_COMPILE
2684
2685#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
2686//---------------------------------------------------------------------------
2687// OBJECTREF AllocateComObject_ForManaged(MethodTable* pMT)
2688OBJECTREF AllocateComObject_ForManaged(MethodTable* pMT)
2689{
2690 CONTRACTL
2691 {
2692 THROWS;
2693 GC_TRIGGERS;
2694 MODE_COOPERATIVE;
2695 PRECONDITION(CheckPointer(pMT));
2696 PRECONDITION(pMT->IsComObjectType());
2697 PRECONDITION(!pMT->IsProjectedFromWinRT());
2698 }
2699 CONTRACTL_END;
2700
2701 // Calls to COM up ahead.
2702 HRESULT hr = S_OK;
2703 EnsureComStarted();
2704
2705 ComClassFactory *pComClsFac = (ComClassFactory *)GetComClassFactory(pMT);
2706 return pComClsFac->CreateInstance(pMT, TRUE);
2707}
2708#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
2709
2710#ifdef FEATURE_CLASSIC_COMINTEROP
2711
2712//---------------------------------------------------------------------------
2713// get/load type for a given clsid
2714MethodTable* GetTypeForCLSID(REFCLSID rclsid, BOOL* pfAssemblyInReg)
2715{
2716 CONTRACT (MethodTable*)
2717 {
2718 THROWS;
2719 GC_TRIGGERS;
2720 MODE_COOPERATIVE;
2721 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
2722 }
2723 CONTRACT_END;
2724
2725 AppDomain* pDomain = GetAppDomain();
2726 _ASSERTE(pDomain);
2727
2728 // check to see if we have this class cached
2729 MethodTable *pMT= pDomain->LookupClass(rclsid);
2730 if (pMT == NULL)
2731 {
2732 pMT = pDomain->LoadCOMClass(rclsid, FALSE, pfAssemblyInReg);
2733 if (pMT != NULL)
2734 pDomain->InsertClassForCLSID(pMT, TRUE);
2735 }
2736 RETURN pMT;
2737}
2738
2739
2740//---------------------------------------------------------------------------
2741// get/load a value class for a given guid
2742MethodTable* GetValueTypeForGUID(REFCLSID guid)
2743{
2744 CONTRACT (MethodTable*)
2745 {
2746 THROWS;
2747 GC_TRIGGERS;
2748 MODE_COOPERATIVE;
2749 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
2750 }
2751 CONTRACT_END;
2752
2753 AppDomain* pDomain = GetAppDomain();
2754 _ASSERTE(pDomain);
2755
2756 // Check to see if we have this value class cached
2757 MethodTable *pMT = pDomain->LookupClass(guid);
2758 if (pMT == NULL)
2759 pMT = pDomain->LoadCOMClass(guid, TRUE, NULL);
2760
2761 if (pMT)
2762 {
2763 // Make sure the class is a value class.
2764 if (!pMT->IsValueType())
2765 {
2766 DefineFullyQualifiedNameForClassW();
2767 COMPlusThrow(kArgumentException, IDS_EE_GUID_REPRESENTS_NON_VC,
2768 GetFullyQualifiedNameForClassNestedAwareW(pMT));
2769 }
2770
2771 // Insert the type in our map from CLSID to method table.
2772 pDomain->InsertClassForCLSID(pMT, TRUE);
2773 }
2774
2775 RETURN pMT;
2776}
2777
2778#endif // FEATURE_CLASSIC_COMINTEROP
2779
2780#endif //#ifndef CROSSGEN_COMPILE
2781
2782
2783//---------------------------------------------------------------------------
2784// This method returns the default interface for the class.
2785DefaultInterfaceType GetDefaultInterfaceForClassInternal(TypeHandle hndClass, TypeHandle *pHndDefClass)
2786{
2787 CONTRACTL
2788 {
2789 THROWS;
2790 GC_TRIGGERS;
2791 MODE_ANY;
2792 INJECT_FAULT(COMPlusThrowOM());
2793 PRECONDITION(!hndClass.IsNull());
2794 PRECONDITION(CheckPointer(pHndDefClass));
2795 PRECONDITION(!hndClass.GetMethodTable()->IsInterface());
2796 }
2797 CONTRACTL_END;
2798
2799 // Set ppDefComMT to NULL before we start.
2800 *pHndDefClass = TypeHandle();
2801
2802 HRESULT hr = S_FALSE;
2803 MethodTable* pClassMT = hndClass.GetMethodTable();
2804 const void* pvData;
2805 ULONG cbData;
2806 CorClassIfaceAttr ClassItfType;
2807 BOOL bComVisible;
2808
2809 PREFIX_ASSUME(pClassMT != NULL);
2810
2811 if (pClassMT->IsWinRTObjectType() || pClassMT->IsExportedToWinRT())
2812 {
2813 // there's no point executing the rest of the function for WinRT classes
2814 return DefaultInterfaceType_IUnknown;
2815 }
2816
2817 if (pClassMT->IsComImport())
2818 {
2819 ClassItfType = clsIfNone;
2820 bComVisible = TRUE;
2821 }
2822 else
2823 {
2824 ClassItfType = pClassMT->GetComClassInterfaceType();
2825 bComVisible = IsTypeVisibleFromCom(hndClass);
2826 }
2827
2828 // If the class is not COM visible, then its default interface is IUnknown.
2829 if (!bComVisible)
2830 return DefaultInterfaceType_IUnknown;
2831
2832 // Start by checking for the ComDefaultInterface attribute.
2833 hr = pClassMT->GetMDImport()->GetCustomAttributeByName(pClassMT->GetCl(), INTEROP_COMDEFAULTINTERFACE_TYPE, &pvData, &cbData);
2834 IfFailThrow(hr);
2835 if (hr == S_OK && cbData > 2)
2836 {
2837 TypeHandle DefItfType;
2838 AppDomain *pCurrDomain = SystemDomain::GetCurrentDomain();
2839
2840 CustomAttributeParser cap(pvData, cbData);
2841 IfFailThrow(cap.SkipProlog());
2842
2843 LPCUTF8 szStr;
2844 ULONG cbStr;
2845 IfFailThrow(cap.GetNonNullString(&szStr, &cbStr));
2846
2847 // Allocate a new buffer that will contain the name of the default COM interface.
2848 StackSString defItf(SString::Utf8, szStr, cbStr);
2849
2850 // Load the default COM interface specified in the CA.
2851 {
2852 GCX_COOP();
2853
2854 DefItfType = TypeName::GetTypeUsingCASearchRules(defItf.GetUnicode(), pClassMT->GetAssembly());
2855
2856 // If the type handle isn't a named type, then throw an exception using
2857 // the name of the type obtained from pCurrInterfaces.
2858 if (!DefItfType.GetMethodTable())
2859 {
2860 // This should only occur for TypeDesc's.
2861 StackSString ssClassName;
2862 DefineFullyQualifiedNameForClassW()
2863 COMPlusThrow(kTypeLoadException, IDS_EE_INVALIDCOMDEFITF,
2864 GetFullyQualifiedNameForClassW(pClassMT),
2865 defItf.GetUnicode());
2866 }
2867
2868 // Otherwise, if the type is not an interface thrown an exception using the actual
2869 // name of the type.
2870 if (!DefItfType.IsInterface())
2871 {
2872 StackSString ssClassName;
2873 StackSString ssInvalidItfName;
2874 pClassMT->_GetFullyQualifiedNameForClass(ssClassName);
2875 DefItfType.GetMethodTable()->_GetFullyQualifiedNameForClass(ssInvalidItfName);
2876 COMPlusThrow(kTypeLoadException, IDS_EE_INVALIDCOMDEFITF,
2877 ssClassName.GetUnicode(), ssInvalidItfName.GetUnicode());
2878 }
2879
2880 // Make sure the class implements the interface.
2881 if (!pClassMT->CanCastToNonVariantInterface(DefItfType.GetMethodTable()))
2882 {
2883 StackSString ssClassName;
2884 StackSString ssInvalidItfName;
2885 pClassMT->_GetFullyQualifiedNameForClass(ssClassName);
2886 DefItfType.GetMethodTable()->_GetFullyQualifiedNameForClass(ssInvalidItfName);
2887 COMPlusThrow(kTypeLoadException, IDS_EE_COMDEFITFNOTSUPPORTED,
2888 ssClassName.GetUnicode(), ssInvalidItfName.GetUnicode());
2889 }
2890 }
2891
2892 // The default interface is valid so return it.
2893 *pHndDefClass = DefItfType;
2894 return DefaultInterfaceType_Explicit;
2895 }
2896
2897 // If the class's interface type is AutoDispatch or AutoDual then return either the
2898 // IClassX for the current class or IDispatch.
2899 if (ClassItfType != clsIfNone)
2900 {
2901 *pHndDefClass = hndClass;
2902 return ClassItfType == clsIfAutoDisp ? DefaultInterfaceType_AutoDispatch : DefaultInterfaceType_AutoDual;
2903 }
2904
2905 // The class interface is set to NONE for this level of the hierarchy. So we need to check
2906 // to see if this class implements an interface.
2907
2908 // Search for the first COM visible implemented interface. We start with the most
2909 // derived class and work our way up the hierarchy.
2910 for (MethodTable *pParentMT = pClassMT->GetParentMethodTable(); pParentMT; pParentMT = pParentMT->GetParentMethodTable())
2911 {
2912 MethodTable::InterfaceMapIterator it = pClassMT->IterateInterfaceMap();
2913 while (it.Next())
2914 {
2915 MethodTable *pItfMT = it.GetInterfaceInfo()->GetApproxMethodTable(pClassMT->GetLoaderModule());
2916
2917 // Skip generic interfaces. Classic COM interop does not support these and we don't
2918 // use the result of this function in WinRT scenarios. WinRT parameter marshaling
2919 // doesn't come here at all because the default interface is always specified using
2920 // the DefaultAttribute. Field marshaling does come here but WinRT does not support
2921 // fields of reference types other than string.
2922 if (!pItfMT->HasInstantiation())
2923 {
2924 // If the interface is visible from COM and not implemented by our parent,
2925 // then use it as the default.
2926 if (IsTypeVisibleFromCom(TypeHandle(pItfMT)) && !pParentMT->ImplementsInterface(pItfMT))
2927 {
2928 *pHndDefClass = TypeHandle(pItfMT);
2929 return DefaultInterfaceType_Explicit;
2930 }
2931 }
2932 }
2933 }
2934
2935 // If the class is a COM import with no interfaces, then its default interface will
2936 // be IUnknown.
2937 if (pClassMT->IsComImport())
2938 return DefaultInterfaceType_IUnknown;
2939
2940 // If we have a managed parent class then return its default interface.
2941 MethodTable *pParentClass = pClassMT->GetComPlusParentMethodTable();
2942 if (pParentClass)
2943 return GetDefaultInterfaceForClassWrapper(TypeHandle(pParentClass), pHndDefClass);
2944
2945 // Check to see if the class is an extensible RCW.
2946 if (pClassMT->IsComObjectType())
2947 return DefaultInterfaceType_BaseComClass;
2948
2949 // The class has no interfaces and is marked as ClassInterfaceType.None.
2950 return DefaultInterfaceType_IUnknown;
2951}
2952
2953
2954DefaultInterfaceType GetDefaultInterfaceForClassWrapper(TypeHandle hndClass, TypeHandle *pHndDefClass)
2955{
2956 CONTRACTL
2957 {
2958 THROWS;
2959 GC_TRIGGERS;
2960 MODE_ANY;
2961 PRECONDITION(!hndClass.IsNull());
2962 }
2963 CONTRACTL_END;
2964
2965#ifndef CROSSGEN_COMPILE
2966 if (!hndClass.IsTypeDesc())
2967 {
2968 ComCallWrapperTemplate *pTemplate = hndClass.AsMethodTable()->GetComCallWrapperTemplate();
2969 if (pTemplate != NULL)
2970 {
2971 // if CCW template is available, use its cache
2972 MethodTable *pDefaultItf;
2973 DefaultInterfaceType itfType = pTemplate->GetDefaultInterface(&pDefaultItf);
2974
2975 *pHndDefClass = TypeHandle(pDefaultItf);
2976 return itfType;
2977 }
2978 }
2979#endif // CROSSGEN_COMPILE
2980
2981 return GetDefaultInterfaceForClassInternal(hndClass, pHndDefClass);
2982}
2983
2984
2985#ifndef CROSSGEN_COMPILE
2986
2987HRESULT TryGetDefaultInterfaceForClass(TypeHandle hndClass, TypeHandle *pHndDefClass, DefaultInterfaceType *pDefItfType)
2988{
2989 CONTRACTL
2990 {
2991 NOTHROW;
2992 GC_TRIGGERS;
2993 MODE_ANY;
2994 PRECONDITION(!hndClass.IsNull());
2995 PRECONDITION(CheckPointer(pHndDefClass));
2996 PRECONDITION(CheckPointer(pDefItfType));
2997 }
2998 CONTRACTL_END;
2999
3000 GCX_COOP();
3001
3002 HRESULT hr = S_OK;
3003 OBJECTREF pThrowable = NULL;
3004
3005 GCPROTECT_BEGIN(pThrowable)
3006 {
3007 EX_TRY
3008 {
3009 *pDefItfType = GetDefaultInterfaceForClassWrapper(hndClass, pHndDefClass);
3010 }
3011 EX_CATCH
3012 {
3013 pThrowable = GET_THROWABLE();
3014 }
3015 EX_END_CATCH(SwallowAllExceptions);
3016
3017 if (pThrowable != NULL)
3018 hr = SetupErrorInfo(pThrowable);
3019 }
3020 GCPROTECT_END();
3021 return hr;
3022}
3023
3024// Returns the default interface for a class if it's an explicit interface or the AutoDual
3025// class interface. Sets *pbDispatch otherwise. This is the logic used by array marshaling
3026// in code:OleVariant::MarshalInterfaceArrayComToOleHelper.
3027MethodTable *GetDefaultInterfaceMTForClass(MethodTable *pMT, BOOL *pbDispatch)
3028{
3029 CONTRACTL
3030 {
3031 THROWS;
3032 GC_TRIGGERS;
3033 MODE_ANY;
3034 PRECONDITION(CheckPointer(pMT));
3035 PRECONDITION(!pMT->IsInterface());
3036 PRECONDITION(CheckPointer(pbDispatch));
3037 }
3038 CONTRACTL_END;
3039
3040 TypeHandle hndDefItfClass;
3041 DefaultInterfaceType DefItfType = GetDefaultInterfaceForClassWrapper(TypeHandle(pMT), &hndDefItfClass);
3042
3043 switch (DefItfType)
3044 {
3045 case DefaultInterfaceType_Explicit:
3046 case DefaultInterfaceType_AutoDual:
3047 {
3048 return hndDefItfClass.GetMethodTable();
3049 }
3050
3051 case DefaultInterfaceType_IUnknown:
3052 case DefaultInterfaceType_BaseComClass:
3053 {
3054 *pbDispatch = FALSE;
3055 return NULL;
3056 }
3057
3058 case DefaultInterfaceType_AutoDispatch:
3059 {
3060 *pbDispatch = TRUE;
3061 return NULL;
3062 }
3063
3064 default:
3065 {
3066 _ASSERTE(!"Invalid default interface type!");
3067 return NULL;
3068 }
3069 }
3070}
3071
3072//---------------------------------------------------------------------------
3073// This method retrieves the list of source interfaces for a given class.
3074void GetComSourceInterfacesForClass(MethodTable *pMT, CQuickArray<MethodTable *> &rItfList)
3075{
3076 CONTRACTL
3077 {
3078 THROWS;
3079 GC_TRIGGERS;
3080 MODE_ANY;
3081 INJECT_FAULT(COMPlusThrowOM());
3082 PRECONDITION(CheckPointer(pMT));
3083 }
3084 CONTRACTL_END;
3085
3086 HRESULT hr = S_OK;
3087 const void* pvData;
3088 ULONG cbData;
3089 CQuickArray<CHAR> qbCurrInterfaces;
3090
3091 GCX_COOP();
3092
3093 // Reset the size of the interface list to 0.
3094 rItfList.Shrink(0);
3095
3096 if (pMT->IsWinRTObjectType() || pMT->IsExportedToWinRT())
3097 {
3098 // classic COM eventing is not supported in WinRT
3099 return;
3100 }
3101
3102 // Starting at the specified class MT retrieve the COM source interfaces
3103 // of all the striped of the hierarchy.
3104 for (; pMT != NULL; pMT = pMT->GetParentMethodTable())
3105 {
3106 // See if there is any [source] interface at this level of the hierarchy.
3107 hr = pMT->GetMDImport()->GetCustomAttributeByName(pMT->GetCl(), INTEROP_COMSOURCEINTERFACES_TYPE, &pvData, &cbData);
3108 IfFailThrow(hr);
3109 if (hr == S_OK && cbData > 2)
3110 {
3111 AppDomain *pCurrDomain = SystemDomain::GetCurrentDomain();
3112
3113 CustomAttributeParser cap(pvData, cbData);
3114 IfFailThrow(cap.SkipProlog());
3115
3116 while (cap.BytesLeft() != 0)
3117 {
3118 // Uncompress the current string of source interfaces.
3119 BYTE const *pbStr;
3120 ULONG cbStr;
3121 IfFailThrow(cap.GetData(&pbStr, &cbStr));
3122
3123 // Allocate a new buffer that will contain the current list of source interfaces.
3124 qbCurrInterfaces.ReSizeThrows(cbStr + 1);
3125 LPUTF8 strCurrInterfaces = qbCurrInterfaces.Ptr();
3126 memcpyNoGCRefs(strCurrInterfaces, pbStr, cbStr);
3127 strCurrInterfaces[cbStr] = 0;
3128 LPUTF8 pCurrInterfaces = strCurrInterfaces;
3129 LPUTF8 pCurrInterfacesEnd = pCurrInterfaces + cbStr + 1;
3130
3131 while (pCurrInterfaces < pCurrInterfacesEnd && *pCurrInterfaces != 0)
3132 {
3133 // Load the COM source interface specified in the CA.
3134 TypeHandle ItfType;
3135 ItfType = TypeName::GetTypeUsingCASearchRules(pCurrInterfaces, pMT->GetAssembly());
3136
3137 // If the type handle isn't a named type, then throw an exception using
3138 // the name of the type obtained from pCurrInterfaces.
3139 if (!ItfType.GetMethodTable())
3140 {
3141 // This should only occur for TypeDesc's.
3142 StackSString ssInvalidItfName(SString::Utf8, pCurrInterfaces);
3143 DefineFullyQualifiedNameForClassW()
3144 COMPlusThrow(kTypeLoadException, IDS_EE_INVALIDCOMSOURCEITF,
3145 GetFullyQualifiedNameForClassW(pMT),
3146 ssInvalidItfName.GetUnicode());
3147 }
3148
3149 // Otherwise, if the type is not an interface thrown an exception using the actual
3150 // name of the type.
3151 if (!ItfType.IsInterface())
3152 {
3153 StackSString ssClassName;
3154 StackSString ssInvalidItfName;
3155 pMT->_GetFullyQualifiedNameForClass(ssClassName);
3156 ItfType.GetMethodTable()->_GetFullyQualifiedNameForClass(ssInvalidItfName);
3157 COMPlusThrow(kTypeLoadException, IDS_EE_INVALIDCOMSOURCEITF,
3158 ssClassName.GetUnicode(), ssInvalidItfName.GetUnicode());
3159 }
3160
3161 // Ensure the source interface is not generic.
3162 if (ItfType.HasInstantiation())
3163 {
3164 StackSString ssClassName;
3165 StackSString ssInvalidItfName;
3166 pMT->_GetFullyQualifiedNameForClass(ssClassName);
3167 ItfType.GetMethodTable()->_GetFullyQualifiedNameForClass(ssInvalidItfName);
3168 COMPlusThrow(kTypeLoadException, IDS_EE_INVALIDCOMSOURCEITF,
3169 ssClassName.GetUnicode(), ssInvalidItfName.GetUnicode());
3170 }
3171
3172
3173 // Retrieve the IID of the COM source interface.
3174 IID ItfIID;
3175 ItfType.GetMethodTable()->GetGuid(&ItfIID, TRUE);
3176
3177 // Go through the list of source interfaces and check to see if the new one is a duplicate.
3178 // It can be a duplicate either if it is the same interface or if it has the same IID.
3179 BOOL bItfInList = FALSE;
3180 for (UINT i = 0; i < rItfList.Size(); i++)
3181 {
3182 if (rItfList[i] == ItfType.GetMethodTable())
3183 {
3184 bItfInList = TRUE;
3185 break;
3186 }
3187
3188 IID ItfIID2;
3189 rItfList[i]->GetGuid(&ItfIID2, TRUE);
3190 if (IsEqualIID(ItfIID, ItfIID2))
3191 {
3192 bItfInList = TRUE;
3193 break;
3194 }
3195 }
3196
3197 // If the COM source interface is not in the list then add it.
3198 if (!bItfInList)
3199 {
3200 size_t OldSize = rItfList.Size();
3201 rItfList.ReSizeThrows(OldSize + 1);
3202 rItfList[OldSize] = ItfType.GetMethodTable();
3203 }
3204
3205 // Process the next COM source interfaces in the CA.
3206 pCurrInterfaces += strlen(pCurrInterfaces) + 1;
3207 }
3208 }
3209 }
3210 }
3211}
3212
3213
3214//--------------------------------------------------------------------------------
3215// These methods convert a native IEnumVARIANT to a managed IEnumerator.
3216OBJECTREF ConvertEnumVariantToMngEnum(IEnumVARIANT *pNativeEnum)
3217{
3218 CONTRACTL
3219 {
3220 THROWS;
3221 GC_TRIGGERS;
3222 MODE_COOPERATIVE;
3223 }
3224 CONTRACTL_END;
3225
3226 OBJECTREF MngEnum = NULL;
3227 OBJECTREF EnumeratorToEnumVariantMarshaler = NULL;
3228 GCPROTECT_BEGIN(EnumeratorToEnumVariantMarshaler)
3229 {
3230 // Retrieve the custom marshaler and the MD to use to convert the IEnumVARIANT.
3231 StdMngIEnumerator *pStdMngIEnumInfo = SystemDomain::GetCurrentDomain()->GetMngStdInterfacesInfo()->GetStdMngIEnumerator();
3232 MethodDesc *pEnumNativeToManagedMD = pStdMngIEnumInfo->GetCustomMarshalerMD(CustomMarshalerMethods_MarshalNativeToManaged);
3233 EnumeratorToEnumVariantMarshaler = pStdMngIEnumInfo->GetCustomMarshaler();
3234 MethodDescCallSite enumNativeToManaged(pEnumNativeToManagedMD, &EnumeratorToEnumVariantMarshaler);
3235
3236 // Prepare the arguments that will be passed to MarshalNativeToManaged.
3237 ARG_SLOT MarshalNativeToManagedArgs[] = {
3238 ObjToArgSlot(EnumeratorToEnumVariantMarshaler),
3239 (ARG_SLOT)pNativeEnum
3240 };
3241
3242 // Retrieve the managed view for the current native interface pointer.
3243 MngEnum = enumNativeToManaged.Call_RetOBJECTREF(MarshalNativeToManagedArgs);
3244 }
3245 GCPROTECT_END();
3246
3247 return MngEnum;
3248}
3249
3250//--------------------------------------------------------------------------------
3251// This method converts an OLE_COLOR to a System.Color.
3252void ConvertOleColorToSystemColor(OLE_COLOR SrcOleColor, SYSTEMCOLOR *pDestSysColor)
3253{
3254 CONTRACTL
3255 {
3256 THROWS;
3257 GC_TRIGGERS;
3258 MODE_COOPERATIVE;
3259 }
3260 CONTRACTL_END;
3261
3262 // Retrieve the method desc to use for the current AD.
3263 MethodDesc *pOleColorToSystemColorMD =
3264 GetAppDomain()->GetMarshalingData()->GetOleColorMarshalingInfo()->GetOleColorToSystemColorMD();
3265
3266 MethodDescCallSite oleColorToSystemColor(pOleColorToSystemColorMD);
3267
3268 _ASSERTE(pOleColorToSystemColorMD->HasRetBuffArg());
3269
3270 ARG_SLOT Args[] =
3271 {
3272 PtrToArgSlot(pDestSysColor),
3273 PtrToArgSlot(SrcOleColor)
3274 };
3275
3276 oleColorToSystemColor.Call(Args);
3277}
3278
3279//--------------------------------------------------------------------------------
3280// This method converts a System.Color to an OLE_COLOR.
3281OLE_COLOR ConvertSystemColorToOleColor(OBJECTREF *pSrcObj)
3282{
3283 CONTRACTL
3284 {
3285 THROWS;
3286 GC_TRIGGERS;
3287 MODE_COOPERATIVE;
3288 }
3289 CONTRACTL_END;
3290
3291 // Retrieve the method desc to use for the current AD.
3292 MethodDesc *pSystemColorToOleColorMD =
3293 GetAppDomain()->GetMarshalingData()->GetOleColorMarshalingInfo()->GetSystemColorToOleColorMD();
3294 MethodDescCallSite systemColorToOleColor(pSystemColorToOleColorMD);
3295
3296 // Set up the args and call the method.
3297 SYSTEMCOLOR *pSrcSysColor = (SYSTEMCOLOR *)(*pSrcObj)->UnBox();
3298 return systemColorToOleColor.CallWithValueTypes_RetOleColor((const ARG_SLOT *)&pSrcSysColor);
3299}
3300
3301//--------------------------------------------------------------------------------
3302// This method generates a stringized version of a class interface that contains
3303// the signatures of all the methods and fields.
3304ULONG GetStringizedClassItfDef(TypeHandle InterfaceType, CQuickArray<BYTE> &rDef)
3305{
3306 CONTRACTL
3307 {
3308 THROWS;
3309 GC_TRIGGERS;
3310 MODE_ANY;
3311 INJECT_FAULT(COMPlusThrowOM());
3312 PRECONDITION(!InterfaceType.IsNull());
3313 }
3314 CONTRACTL_END;
3315
3316 LPCWSTR szName;
3317 ULONG cchName;
3318 MethodTable* pIntfMT = InterfaceType.GetMethodTable();
3319 PREFIX_ASSUME(pIntfMT != NULL);
3320
3321 MethodTable* pDeclaringMT = NULL;
3322 DWORD nSlots; // Slots on the pseudo interface.
3323 mdToken tkMb; // A method or field token.
3324 ULONG cbCur;
3325 HRESULT hr = S_OK;
3326 ULONG i;
3327
3328 // Should be an actual class.
3329 _ASSERTE(!pIntfMT->IsInterface());
3330
3331 // See what sort of IClassX this class gets.
3332 TypeHandle thDefItf;
3333 BOOL bGenerateMethods = FALSE;
3334 DefaultInterfaceType DefItfType = GetDefaultInterfaceForClassWrapper(TypeHandle(pIntfMT), &thDefItf);
3335
3336 // The results apply to this class if the thDefItf is this class itself, not a parent class.
3337 // A side effect is that [ComVisible(false)] types' guids are generated without members.
3338 if (thDefItf.GetMethodTable() == pIntfMT && DefItfType == DefaultInterfaceType_AutoDual)
3339 bGenerateMethods = TRUE;
3340
3341 // Get the name of the class.
3342 DefineFullyQualifiedNameForClassW();
3343 szName = GetFullyQualifiedNameForClassNestedAwareW(pIntfMT);
3344 cchName = (ULONG)wcslen(szName);
3345
3346 // Start with the interface name.
3347 cbCur = cchName * sizeof(WCHAR);
3348 rDef.ReSizeThrows(cbCur + sizeof(WCHAR));
3349 wcscpy_s(reinterpret_cast<LPWSTR>(rDef.Ptr()), rDef.Size()/sizeof(WCHAR), szName);
3350
3351 if (bGenerateMethods)
3352 {
3353 ComMTMemberInfoMap MemberMap(pIntfMT); // The map of members.
3354
3355 // Retrieve the method properties.
3356 MemberMap.Init(sizeof(void*));
3357
3358 CQuickArray<ComMTMethodProps> &rProps = MemberMap.GetMethods();
3359 nSlots = (DWORD)rProps.Size();
3360
3361 // Now add the methods to the TypeInfo.
3362 for (i=0; i<nSlots; ++i)
3363 {
3364 ComMTMethodProps *pProps = &rProps[i];
3365 if (pProps->bMemberVisible)
3366 {
3367 if (pProps->semantic < FieldSemanticOffset)
3368 {
3369 pDeclaringMT = pProps->pMeth->GetMethodTable();
3370 tkMb = pProps->pMeth->GetMemberDef();
3371 cbCur = GetStringizedMethodDef(pDeclaringMT, tkMb, rDef, cbCur);
3372 }
3373 else
3374 {
3375 ComCallMethodDesc *pFieldMeth; // A MethodDesc for a field call.
3376 FieldDesc *pField; // A FieldDesc.
3377 pFieldMeth = reinterpret_cast<ComCallMethodDesc*>(pProps->pMeth);
3378 pField = pFieldMeth->GetFieldDesc();
3379 pDeclaringMT = pField->GetApproxEnclosingMethodTable();
3380 tkMb = pField->GetMemberDef();
3381 cbCur = GetStringizedFieldDef(pDeclaringMT, tkMb, rDef, cbCur);
3382 }
3383 }
3384 }
3385 }
3386
3387 // Return the number of bytes.
3388 return cbCur;
3389} // ULONG GetStringizedClassItfDef()
3390
3391//--------------------------------------------------------------------------------
3392// Helper to get the GUID of a class interface.
3393void GenerateClassItfGuid(TypeHandle InterfaceType, GUID *pGuid)
3394{
3395 CONTRACTL
3396 {
3397 THROWS;
3398 GC_TRIGGERS;
3399 MODE_ANY;
3400 INJECT_FAULT(COMPlusThrowOM());
3401 PRECONDITION(!InterfaceType.IsNull());
3402 PRECONDITION(CheckPointer(pGuid));
3403 }
3404 CONTRACTL_END;
3405
3406 LPWSTR szName; // Name to turn to a guid.
3407 ULONG cchName; // Length of the name (possibly after decoration).
3408 CQuickArray<BYTE> rName; // Buffer to accumulate signatures.
3409 ULONG cbCur; // Current offset.
3410 HRESULT hr = S_OK; // A result.
3411
3412 cbCur = GetStringizedClassItfDef(InterfaceType, rName);
3413
3414 // Pad up to a whole WCHAR.
3415 if (cbCur % sizeof(WCHAR))
3416 {
3417 int cbDelta = sizeof(WCHAR) - (cbCur % sizeof(WCHAR));
3418 rName.ReSizeThrows(cbCur + cbDelta);
3419 memset(rName.Ptr() + cbCur, 0, cbDelta);
3420 cbCur += cbDelta;
3421 }
3422
3423 // Point to the new buffer.
3424 cchName = cbCur / sizeof(WCHAR);
3425 szName = reinterpret_cast<LPWSTR>(rName.Ptr());
3426
3427 // Generate guid from name.
3428 CorGuidFromNameW(pGuid, szName, cchName);
3429} // void GenerateClassItfGuid()
3430
3431HRESULT TryGenerateClassItfGuid(TypeHandle InterfaceType, GUID *pGuid)
3432{
3433 CONTRACTL
3434 {
3435 NOTHROW;
3436 GC_TRIGGERS;
3437 MODE_ANY;
3438 PRECONDITION(!InterfaceType.IsNull());
3439 PRECONDITION(CheckPointer(pGuid));
3440 }
3441 CONTRACTL_END;
3442
3443 GCX_COOP();
3444
3445 HRESULT hr = S_OK;
3446 OBJECTREF pThrowable = NULL;
3447
3448 GCPROTECT_BEGIN(pThrowable)
3449 {
3450 EX_TRY
3451 {
3452 GenerateClassItfGuid(InterfaceType, pGuid);
3453 }
3454 EX_CATCH
3455 {
3456 pThrowable = GET_THROWABLE();
3457 }
3458 EX_END_CATCH (SwallowAllExceptions);
3459
3460 if (pThrowable != NULL)
3461 hr = SetupErrorInfo(pThrowable);
3462 }
3463 GCPROTECT_END();
3464
3465 return hr;
3466}
3467
3468//--------------------------------------------------------------------------------
3469// Helper to get the GUID of the typelib that is created from an assembly.
3470HRESULT GetTypeLibGuidForAssembly(Assembly *pAssembly, GUID *pGuid)
3471{
3472 CONTRACTL
3473 {
3474 NOTHROW;
3475 GC_TRIGGERS;
3476 MODE_ANY;
3477 PRECONDITION(CheckPointer(pAssembly));
3478 PRECONDITION(CheckPointer(pGuid));
3479 }
3480 CONTRACTL_END;
3481
3482 HRESULT hr = S_OK;
3483 CQuickArray<BYTE> rName; // String for guid.
3484 ULONG cbData; // Size of the string in bytes.
3485
3486 // Get GUID from Assembly, else from Manifest Module, else Generate from name.
3487 hr = pAssembly->GetManifestImport()->GetItemGuid(TokenFromRid(1, mdtAssembly), pGuid);
3488
3489 if (*pGuid == GUID_NULL)
3490 {
3491 // Get the string.
3492 IfFailGo(GetStringizedTypeLibGuidForAssembly(pAssembly, rName, 0, &cbData));
3493
3494 // Pad to a whole WCHAR.
3495 if (cbData % sizeof(WCHAR))
3496 {
3497 IfFailGo(rName.ReSizeNoThrow(cbData + sizeof(WCHAR)-(cbData%sizeof(WCHAR))));
3498 while (cbData % sizeof(WCHAR))
3499 rName[cbData++] = 0;
3500 }
3501
3502 // Turn into guid
3503 CorGuidFromNameW(pGuid, (LPWSTR)rName.Ptr(), cbData/sizeof(WCHAR));
3504}
3505
3506ErrExit:
3507 return hr;
3508} // HRESULT GetTypeLibGuidForAssembly()
3509
3510//--------------------------------------------------------------------------------
3511// Helper to get the version of the typelib that is created from an assembly.
3512HRESULT GetTypeLibVersionForAssembly(
3513 _In_ Assembly *pAssembly,
3514 _Out_ USHORT *pMajorVersion,
3515 _Out_ USHORT *pMinorVersion)
3516{
3517 CONTRACTL
3518 {
3519 NOTHROW;
3520 GC_TRIGGERS;
3521 MODE_ANY;
3522 PRECONDITION(CheckPointer(pAssembly));
3523 PRECONDITION(CheckPointer(pMajorVersion));
3524 PRECONDITION(CheckPointer(pMinorVersion));
3525 }
3526 CONTRACTL_END;
3527
3528 HRESULT hr;
3529 const BYTE *pbData = nullptr;
3530 ULONG cbData = 0;
3531
3532 if (!pAssembly->IsWinMD())
3533 {
3534 // Check to see if the TypeLibVersionAttribute is set.
3535 IfFailRet(pAssembly->GetManifestImport()->GetCustomAttributeByName(TokenFromRid(1, mdtAssembly), INTEROP_TYPELIBVERSION_TYPE, (const void**)&pbData, &cbData));
3536 }
3537
3538 // For attribute contents, see https://docs.microsoft.com/dotnet/api/system.runtime.interopservices.typelibversionattribute
3539 if (cbData >= (2 + 2 * sizeof(UINT32)))
3540 {
3541 CustomAttributeParser cap(pbData, cbData);
3542 IfFailRet(cap.SkipProlog());
3543
3544 // Retrieve the major and minor version from the attribute.
3545 UINT32 u4;
3546 IfFailRet(cap.GetU4(&u4));
3547 *pMajorVersion = GET_VERSION_USHORT_FROM_INT(u4);
3548 IfFailRet(cap.GetU4(&u4));
3549 *pMinorVersion = GET_VERSION_USHORT_FROM_INT(u4);
3550 }
3551 else
3552 {
3553 // Use the assembly's major and minor version number.
3554 IfFailRet(pAssembly->GetVersion(pMajorVersion, pMinorVersion, nullptr, nullptr));
3555 }
3556
3557 // Some system don't handle a typelib with a version of 0.0.
3558 // When that happens, change it to 1.0.
3559 if (*pMajorVersion == 0 && *pMinorVersion == 0)
3560 *pMajorVersion = 1;
3561
3562 return S_OK;
3563} // HRESULT TypeLibExporter::GetTypeLibVersionFromAssembly()
3564
3565#endif //CROSSGEN_COMPILE
3566
3567
3568//---------------------------------------------------------------------------
3569// This method determines if a member is visible from COM.
3570BOOL IsMethodVisibleFromCom(MethodDesc *pMD)
3571{
3572 CONTRACTL
3573 {
3574 THROWS;
3575 GC_NOTRIGGER;
3576 MODE_ANY;
3577 PRECONDITION(CheckPointer(pMD));
3578 }
3579 CONTRACTL_END;
3580
3581 HRESULT hr = S_OK;
3582 mdProperty pd;
3583 LPCUTF8 pPropName;
3584 ULONG uSemantic;
3585 mdMethodDef md = pMD->GetMemberDef();
3586
3587 // See if there is property information for this member.
3588 hr = pMD->GetModule()->GetPropertyInfoForMethodDef(md, &pd, &pPropName, &uSemantic);
3589 IfFailThrow(hr);
3590
3591 if (hr == S_OK)
3592 {
3593 return IsMemberVisibleFromCom(pMD->GetMethodTable(), pd, md);
3594 }
3595 else
3596 {
3597 return IsMemberVisibleFromCom(pMD->GetMethodTable(), md, mdTokenNil);
3598 }
3599}
3600
3601//---------------------------------------------------------------------------
3602// This method determines if a type is visible from COM or not based on
3603// its visibility. This version of the method works with a type handle.
3604// This version will ignore a type's generic attributes.
3605//
3606// This API should *never* be called directly!!!
3607static BOOL SpecialIsGenericTypeVisibleFromCom(TypeHandle hndType)
3608{
3609 CONTRACTL
3610 {
3611 NOTHROW;
3612 GC_NOTRIGGER;
3613 MODE_ANY;
3614 PRECONDITION(!hndType.IsNull());
3615 }
3616 CONTRACTL_END;
3617
3618 DWORD dwFlags;
3619 mdTypeDef tdEnclosingType;
3620 HRESULT hr;
3621 const BYTE * pVal;
3622 ULONG cbVal;
3623 MethodTable * pMT = hndType.GetMethodTable();
3624 _ASSERTE(pMT);
3625
3626 mdTypeDef mdType = pMT->GetCl();
3627 IMDInternalImport * pInternalImport = pMT->GetMDImport();
3628 Assembly * pAssembly = pMT->GetAssembly();
3629
3630 // If the type is a COM imported interface then it is visible from COM.
3631 if (pMT->IsInterface() && pMT->IsComImport())
3632 return TRUE;
3633
3634 // If the type is imported from WinRT (has the tdWindowsRuntime flag set), then it is visible from COM.
3635 if (pMT->IsProjectedFromWinRT())
3636 return TRUE;
3637
3638 // If the type is an array, then it is not visible from COM.
3639 if (pMT->IsArray())
3640 return FALSE;
3641
3642 // Retrieve the flags for the current type.
3643 tdEnclosingType = mdType;
3644 if (FAILED(pInternalImport->GetTypeDefProps(tdEnclosingType, &dwFlags, 0)))
3645 {
3646 return FALSE;
3647 }
3648
3649 // Handle nested types.
3650 while (IsTdNestedPublic(dwFlags))
3651 {
3652 hr = pInternalImport->GetNestedClassProps(tdEnclosingType, &tdEnclosingType);
3653 if (FAILED(hr))
3654 {
3655 return FALSE;
3656 }
3657
3658 // Retrieve the flags for the enclosing type.
3659 if (FAILED(pInternalImport->GetTypeDefProps(tdEnclosingType, &dwFlags, 0)))
3660 {
3661 return FALSE;
3662 }
3663 }
3664
3665 // If the outermost type is not visible then the specified type is not visible.
3666 if (!IsTdPublic(dwFlags))
3667 return FALSE;
3668
3669 // Check to see if the type has the ComVisible attribute set.
3670 hr = pInternalImport->GetCustomAttributeByName(mdType, INTEROP_COMVISIBLE_TYPE, (const void**)&pVal, &cbVal);
3671 if (hr == S_OK)
3672 {
3673 CustomAttributeParser cap(pVal, cbVal);
3674 if (FAILED(cap.SkipProlog()))
3675 return FALSE;
3676
3677 UINT8 u1;
3678 if (FAILED(cap.GetU1(&u1)))
3679 return FALSE;
3680
3681 return (BOOL)u1;
3682 }
3683
3684 // Check to see if the assembly has the ComVisible attribute set.
3685 hr = pAssembly->GetManifestImport()->GetCustomAttributeByName(pAssembly->GetManifestToken(), INTEROP_COMVISIBLE_TYPE, (const void**)&pVal, &cbVal);
3686 if (hr == S_OK)
3687 {
3688 CustomAttributeParser cap(pVal, cbVal);
3689 if (FAILED(cap.SkipProlog()))
3690 return FALSE;
3691
3692 UINT8 u1;
3693 if (FAILED(cap.GetU1(&u1)))
3694 return FALSE;
3695
3696 return (BOOL)u1;
3697 }
3698
3699 // The type is visible.
3700 return TRUE;
3701}
3702
3703//---------------------------------------------------------------------------
3704// This method determines if a type is visible from COM or not based on
3705// its visibility. This version of the method works with a type handle.
3706BOOL IsTypeVisibleFromCom(TypeHandle hndType)
3707{
3708 CONTRACTL
3709 {
3710 NOTHROW;
3711 GC_NOTRIGGER;
3712 MODE_ANY;
3713 PRECONDITION(!hndType.IsNull());
3714 }
3715 CONTRACTL_END;
3716
3717 if (!hndType.SupportsGenericInterop(TypeHandle::Interop_NativeToManaged))
3718 {
3719 // If the type is a generic type, then it is not visible from COM.
3720 if (hndType.HasInstantiation() || hndType.IsGenericVariable())
3721 return FALSE;
3722 }
3723
3724 return SpecialIsGenericTypeVisibleFromCom(hndType);
3725}
3726
3727//---------------------------------------------------------------------------
3728// Determines if a method is likely to be used for forward COM/WinRT interop.
3729BOOL MethodNeedsForwardComStub(MethodDesc *pMD, DataImage *pImage)
3730{
3731 CONTRACTL
3732 {
3733 THROWS;
3734 GC_TRIGGERS;
3735 MODE_ANY;
3736 }
3737 CONTRACTL_END;
3738
3739 MethodTable *pMT = pMD->GetMethodTable();
3740
3741 if (pMT->HasInstantiation() && !pMT->SupportsGenericInterop(TypeHandle::Interop_ManagedToNative))
3742 {
3743 // method is declared on an unsupported generic type -> stub not needed
3744 return FALSE;
3745 }
3746
3747 if (pMT->IsProjectedFromWinRT() && pMT->IsComImport() && pMD->IsPrivate())
3748 {
3749 // private WinRT method -> stub not needed
3750 return FALSE;
3751 }
3752
3753 if (pMT->IsWinRTObjectType())
3754 {
3755 // WinRT runtime class -> stub needed
3756 return TRUE;
3757 }
3758
3759 if (pMT->IsWinRTRedirectedInterface(TypeHandle::Interop_ManagedToNative))
3760 {
3761 if (!pMT->HasInstantiation())
3762 {
3763 // non-generic redirected interface -> stub needed
3764 return TRUE;
3765 }
3766
3767 // Generating stubs for generic redirected interfaces into all assemblies would grow NetFX native images
3768 // by several per cent. See BCL\System\Internal.cs if you need to add specific instantiations in mscorlib.
3769 DWORD assemblyFlags = pImage->GetModule()->GetAssembly()->GetFlags();
3770 if (IsAfContentType_WindowsRuntime(assemblyFlags))
3771 {
3772 // generic redirected interface while NGENing a .winmd -> stub needed
3773 return TRUE;
3774 }
3775 }
3776
3777 GUID guid;
3778 pMT->GetGuid(&guid, FALSE);
3779
3780 if (guid != GUID_NULL)
3781 {
3782 // explicit GUID defined in metadata -> stub needed
3783 return TRUE;
3784 }
3785
3786 return FALSE;
3787}
3788
3789#ifdef FEATURE_PREJIT
3790//---------------------------------------------------------------------------
3791// Determines if a method is visible from COM in a way that requires a marshaling
3792// stub, i.e. it allows early binding.
3793BOOL MethodNeedsReverseComStub(MethodDesc *pMD)
3794{
3795 CONTRACTL
3796 {
3797 THROWS;
3798 GC_TRIGGERS;
3799 MODE_ANY;
3800 PRECONDITION(CheckPointer(pMD));
3801 }
3802 CONTRACTL_END;
3803
3804 BOOL fIsAllowedCtorOrStatic = FALSE;
3805 MethodTable *pMT = pMD->GetMethodTable();
3806
3807 if (pMT->IsInterface())
3808 {
3809 if (!pMT->IsComImport() && !IsTypeVisibleFromCom(TypeHandle(pMT)))
3810 return FALSE;
3811
3812 if (pMT->HasInstantiation() && !pMT->SupportsGenericInterop(TypeHandle::Interop_NativeToManaged))
3813 return FALSE;
3814
3815 // declaring interface must be InterfaceIsIUnknown or InterfaceIsDual
3816 if (pMT->GetComInterfaceType() == ifDispatch)
3817 return FALSE;
3818
3819 Assembly * pAssembly = pMT->GetAssembly();
3820 if (pAssembly->IsWinMD() && !pAssembly->IsManagedWinMD())
3821 {
3822 //
3823 // Internal interfaces defined in native winmds can only ever be implemented by native components.
3824 // Managed classes won't be able to implement the internal interfaces, and so the reverse COM stubs
3825 // are not needed for them.
3826 //
3827 if (IsTdNotPublic(pMT->GetClass()->GetProtection()))
3828 {
3829 //
3830 // However, we do need CCWs for internal interfaces that define protected members of inheritable classes
3831 // (for example, Windows.UI.Xaml.Application implements both IApplication, which we don't need
3832 // a CCW for and IApplicationOverrides, which we do need).
3833 //
3834 if (!pMT->GetWriteableData()->IsOverridingInterface())
3835 {
3836 return FALSE;
3837 }
3838 }
3839 }
3840 }
3841 else
3842 {
3843 if (!IsTypeVisibleFromCom(TypeHandle(pMT)))
3844 return FALSE;
3845
3846 if (pMT->IsDelegate())
3847 {
3848 // the 'Invoke' method of a WinRT delegate needs stub
3849 return ((pMT->IsProjectedFromWinRT() || WinRTTypeNameConverter::IsRedirectedType(pMT)) &&
3850 pMD->HasSameMethodDefAs(COMDelegate::FindDelegateInvokeMethod(pMT)));
3851 }
3852
3853 if (pMT->IsExportedToWinRT() && (pMD->IsCtor() || pMD->IsStatic()))
3854 {
3855 fIsAllowedCtorOrStatic = TRUE;
3856 }
3857 else
3858 {
3859 // declaring class must be AutoDual
3860 if (pMT->GetComClassInterfaceType() != clsIfAutoDual)
3861 return FALSE;
3862 }
3863 }
3864
3865 // static methods and ctors are not exposed to COM except for WinRT
3866 if (!fIsAllowedCtorOrStatic && (pMD->IsCtor() || pMD->IsStatic()))
3867 return FALSE;
3868
3869 // NGen can't compile stubs for var arg methods
3870 if (pMD->IsVarArg())
3871 return FALSE;
3872
3873 return IsMethodVisibleFromCom(pMD);
3874}
3875#endif // FEATURE_PREJIT
3876
3877
3878#ifndef CROSSGEN_COMPILE
3879
3880//--------------------------------------------------------------------------------
3881// Validate that the given target is valid for the specified type.
3882BOOL IsComTargetValidForType(REFLECTCLASSBASEREF* pRefClassObj, OBJECTREF* pTarget)
3883{
3884 CONTRACTL
3885 {
3886 THROWS;
3887 GC_TRIGGERS;
3888 MODE_COOPERATIVE;
3889 PRECONDITION(CheckPointer(pRefClassObj));
3890 PRECONDITION(CheckPointer(pTarget));
3891 }
3892 CONTRACTL_END;
3893
3894 MethodTable* pInvokedMT = (*pRefClassObj)->GetType().GetMethodTable();
3895
3896 MethodTable* pTargetMT = (*pTarget)->GetMethodTable();
3897 _ASSERTE(pTargetMT);
3898 PREFIX_ASSUME(pInvokedMT != NULL);
3899
3900 // If the target class and the invoke class are identical then the invoke is valid.
3901 if (pTargetMT == pInvokedMT)
3902 return TRUE;
3903
3904 // We always allow calling InvokeMember on a __ComObject type regardless of the type
3905 // of the target object.
3906 if (IsComObjectClass((*pRefClassObj)->GetType()))
3907 return TRUE;
3908
3909 // If the class that is being invoked on is an interface then check to see if the
3910 // target class supports that interface.
3911 if (pInvokedMT->IsInterface())
3912 return Object::SupportsInterface(*pTarget, pInvokedMT);
3913
3914 // Check to see if the target class inherits from the invoked class.
3915 while (pTargetMT)
3916 {
3917 pTargetMT = pTargetMT->GetParentMethodTable();
3918 if (pTargetMT == pInvokedMT)
3919 {
3920 // The target class inherits from the invoked class.
3921 return TRUE;
3922 }
3923 }
3924
3925 // There is no valid relationship between the invoked and the target classes.
3926 return FALSE;
3927}
3928
3929DISPID ExtractStandardDispId(__in_z LPWSTR strStdDispIdMemberName)
3930{
3931 CONTRACTL
3932 {
3933 THROWS;
3934 GC_NOTRIGGER;
3935 MODE_ANY;
3936 }
3937 CONTRACTL_END;
3938
3939 // Find the first character after the = in the standard DISPID member name.
3940 LPWSTR strDispId = wcsstr(&strStdDispIdMemberName[STANDARD_DISPID_PREFIX_LENGTH], W("=")) + 1;
3941 if (!strDispId)
3942 COMPlusThrow(kArgumentException, IDS_EE_INVALID_STD_DISPID_NAME);
3943
3944 // Validate that the last character of the standard member name is a ].
3945 LPWSTR strClosingBracket = wcsstr(strDispId, W("]"));
3946 if (!strClosingBracket || (strClosingBracket[1] != 0))
3947 COMPlusThrow(kArgumentException, IDS_EE_INVALID_STD_DISPID_NAME);
3948
3949 // Extract the number from the standard DISPID member name.
3950 return _wtoi(strDispId);
3951}
3952
3953static HRESULT InvokeExHelper(
3954 IDispatchEx * pDispEx,
3955 DISPID MemberID,
3956 LCID lcid,
3957 WORD flags,
3958 DISPPARAMS * pDispParams,
3959 VARIANT* pVarResult,
3960 EXCEPINFO * pExcepInfo,
3961 IServiceProvider *pspCaller)
3962{
3963 STATIC_CONTRACT_THROWS;
3964 STATIC_CONTRACT_GC_TRIGGERS;
3965 STATIC_CONTRACT_MODE_ANY;
3966 STATIC_CONTRACT_SO_INTOLERANT;
3967
3968 _ASSERTE(pDispEx != NULL);
3969
3970 struct Param : CallOutFilterParam {
3971 HRESULT hr;
3972 IDispatchEx * pDispEx;
3973 DISPID MemberID;
3974 LCID lcid;
3975 WORD flags;
3976 DISPPARAMS * pDispParams;
3977 VARIANT* pVarResult;
3978 EXCEPINFO * pExcepInfo;
3979 IServiceProvider * pspCaller;
3980 }; Param param;
3981
3982 param.OneShot = TRUE; // Inherited from CallOutFilterParam
3983 param.hr = S_OK;
3984 param.pDispEx = pDispEx;
3985 param.MemberID = MemberID;
3986 param.lcid = lcid;
3987 param.flags = flags;
3988 param.pDispParams = pDispParams;
3989 param.pVarResult = pVarResult;
3990 param.pExcepInfo = pExcepInfo;
3991 param.pspCaller = pspCaller;
3992
3993 PAL_TRY(Param *, pParam, &param)
3994 {
3995 BEGIN_SO_TOLERANT_CODE(GetThread());
3996
3997 pParam->hr = pParam->pDispEx->InvokeEx(pParam->MemberID,
3998 pParam->lcid,
3999 pParam->flags,
4000 pParam->pDispParams,
4001 pParam->pVarResult,
4002 pParam->pExcepInfo,
4003 pParam->pspCaller);
4004
4005 END_SO_TOLERANT_CODE;
4006 }
4007 PAL_EXCEPT_FILTER(CallOutFilter)
4008 {
4009 _ASSERTE(!"CallOutFilter returned EXECUTE_HANDLER.");
4010 }
4011 PAL_ENDTRY;
4012
4013 return param.hr;
4014}
4015
4016static HRESULT InvokeHelper(
4017 IDispatch * pDisp,
4018 DISPID MemberID,
4019 REFIID riid,
4020 LCID lcid,
4021 WORD flags,
4022 DISPPARAMS * pDispParams,
4023 VARIANT* pVarResult,
4024 EXCEPINFO * pExcepInfo,
4025 UINT *piArgErr)
4026{
4027 STATIC_CONTRACT_THROWS;
4028 STATIC_CONTRACT_GC_TRIGGERS;
4029 STATIC_CONTRACT_MODE_ANY;
4030 STATIC_CONTRACT_SO_INTOLERANT;
4031
4032 _ASSERTE(pDisp != NULL);
4033
4034 struct Param : CallOutFilterParam {
4035 HRESULT hr;
4036 IDispatch * pDisp;
4037 DISPID MemberID;
4038 REFIID riid;
4039 LCID lcid;
4040 WORD flags;
4041 DISPPARAMS * pDispParams;
4042 VARIANT * pVarResult;
4043 EXCEPINFO * pExcepInfo;
4044 UINT * piArgErr;
4045
4046 Param(REFIID _riid) : riid(_riid) {}
4047 }; Param param(riid);
4048
4049 param.OneShot = TRUE; // Inherited from CallOutFilterParam
4050 param.hr = S_OK;
4051 param.pDisp = pDisp;
4052 param.MemberID = MemberID;
4053 //param.riid = riid;
4054 param.lcid = lcid;
4055 param.flags = flags;
4056 param.pDispParams = pDispParams;
4057 param.pVarResult = pVarResult;
4058 param.pExcepInfo = pExcepInfo;
4059 param.piArgErr = piArgErr;
4060
4061 PAL_TRY(Param *, pParam, &param)
4062 {
4063 BEGIN_SO_TOLERANT_CODE(GetThread());
4064
4065 pParam->hr = pParam->pDisp->Invoke(pParam->MemberID,
4066 pParam->riid,
4067 pParam->lcid,
4068 pParam->flags,
4069 pParam->pDispParams,
4070 pParam->pVarResult,
4071 pParam->pExcepInfo,
4072 pParam->piArgErr);
4073
4074 END_SO_TOLERANT_CODE;
4075 }
4076 PAL_EXCEPT_FILTER(CallOutFilter)
4077 {
4078 _ASSERTE(!"CallOutFilter returned EXECUTE_HANDLER.");
4079 }
4080 PAL_ENDTRY;
4081
4082 return param.hr;
4083}
4084
4085
4086void DispInvokeConvertObjectToVariant(OBJECTREF *pSrcObj, VARIANT *pDestVar, ByrefArgumentInfo *pByrefArgInfo)
4087{
4088 CONTRACTL
4089 {
4090 THROWS;
4091 GC_TRIGGERS;
4092 MODE_COOPERATIVE;
4093 PRECONDITION(CheckPointer(pSrcObj));
4094 PRECONDITION(IsProtectedByGCFrame (pSrcObj));
4095 PRECONDITION(CheckPointer(pDestVar));
4096 PRECONDITION(CheckPointer(pByrefArgInfo));
4097 }
4098 CONTRACTL_END;
4099
4100 if (pByrefArgInfo->m_bByref)
4101 {
4102 if (*pSrcObj == NULL)
4103 {
4104 V_VT(pDestVar) = VT_VARIANT | VT_BYREF;
4105 pDestVar->pvarVal = &pByrefArgInfo->m_Val;
4106 }
4107 else if (MscorlibBinder::IsClass((*pSrcObj)->GetMethodTable(), CLASS__VARIANT_WRAPPER))
4108 {
4109 OBJECTREF WrappedObj = (*((VARIANTWRAPPEROBJECTREF*)pSrcObj))->GetWrappedObject();
4110 GCPROTECT_BEGIN(WrappedObj)
4111 {
4112 OleVariant::MarshalOleVariantForObject(&WrappedObj, &pByrefArgInfo->m_Val);
4113 V_VT(pDestVar) = VT_VARIANT | VT_BYREF;
4114 pDestVar->pvarVal = &pByrefArgInfo->m_Val;
4115 }
4116 GCPROTECT_END();
4117 }
4118 else
4119 {
4120 OleVariant::MarshalOleVariantForObject(pSrcObj, &pByrefArgInfo->m_Val);
4121 OleVariant::CreateByrefVariantForVariant(&pByrefArgInfo->m_Val, pDestVar);
4122 }
4123 }
4124 else
4125 {
4126 OleVariant::MarshalOleVariantForObject(pSrcObj, pDestVar);
4127 }
4128}
4129
4130static void DoIUInvokeDispMethod(IDispatchEx* pDispEx, IDispatch* pDisp, DISPID MemberID, LCID lcid,
4131 WORD flags, DISPPARAMS* pDispParams, VARIANT* pVarResult)
4132{
4133 CONTRACTL
4134 {
4135 THROWS;
4136 GC_TRIGGERS;
4137 MODE_ANY;
4138 }
4139 CONTRACTL_END;
4140
4141 UINT iArgErr;
4142 EXCEPINFO ExcepInfo;
4143 HRESULT hr;
4144
4145 memset(&ExcepInfo, 0, sizeof(EXCEPINFO));
4146
4147#ifdef MDA_SUPPORTED
4148 MDA_TRIGGER_ASSISTANT(GcManagedToUnmanaged, TriggerGC());
4149#endif
4150
4151 GCX_COOP();
4152 OBJECTREF pThrowable = NULL;
4153 GCPROTECT_BEGIN(pThrowable);
4154 {
4155 // Call the method
4156 EX_TRY
4157 {
4158 {
4159 // We are about to make call's to COM so switch to preemptive GC.
4160 GCX_PREEMP();
4161
4162 if (pDispEx)
4163 {
4164 hr = InvokeExHelper(pDispEx, MemberID, lcid, flags, pDispParams,
4165 pVarResult, &ExcepInfo, NULL);
4166 }
4167 else
4168 {
4169 hr = InvokeHelper( pDisp, MemberID, IID_NULL, lcid, flags,
4170 pDispParams, pVarResult, &ExcepInfo, &iArgErr);
4171 }
4172 }
4173
4174#ifdef MDA_SUPPORTED
4175 EX_TRY
4176 {
4177 MDA_TRIGGER_ASSISTANT(GcUnmanagedToManaged, TriggerGC());
4178 }
4179 EX_CATCH
4180 {
4181 }
4182 EX_END_CATCH(RethrowTerminalExceptions);
4183#endif
4184
4185 // If the invoke call failed then throw an exception based on the EXCEPINFO.
4186 if (FAILED(hr))
4187 {
4188 if (hr == DISP_E_EXCEPTION)
4189 {
4190 // This method will free the BSTR's in the EXCEPINFO.
4191 COMPlusThrowHR(&ExcepInfo);
4192 }
4193 else
4194 {
4195 COMPlusThrowHR(hr);
4196 }
4197 }
4198 }
4199 EX_CATCH
4200 {
4201 // If we get here we need to throw an TargetInvocationException
4202 pThrowable = GET_THROWABLE();
4203 _ASSERTE(pThrowable != NULL);
4204 }
4205 EX_END_CATCH(RethrowTerminalExceptions);
4206
4207 if (pThrowable != NULL)
4208 {
4209 COMPlusThrow(InvokeUtil::CreateTargetExcept(&pThrowable));
4210 }
4211 }
4212 GCPROTECT_END();
4213}
4214
4215
4216FORCEINLINE void DispParamHolderRelease(VARIANT* value)
4217{
4218 CONTRACTL
4219 {
4220 THROWS;
4221 GC_TRIGGERS;
4222 MODE_ANY;
4223 }
4224 CONTRACTL_END;
4225
4226 if (value)
4227 {
4228 if (V_VT(value) & VT_BYREF)
4229 {
4230 VariantHolder TmpVar;
4231 OleVariant::ExtractContentsFromByrefVariant(value, &TmpVar);
4232 }
4233
4234 SafeVariantClear(value);
4235 }
4236}
4237
4238class DispParamHolder : public Wrapper<VARIANT*, DispParamHolderDoNothing, DispParamHolderRelease, NULL>
4239{
4240public:
4241 DispParamHolder(VARIANT* p = NULL)
4242 : Wrapper<VARIANT*, DispParamHolderDoNothing, DispParamHolderRelease, NULL>(p)
4243 {
4244 WRAPPER_NO_CONTRACT;
4245 }
4246
4247 FORCEINLINE void operator=(VARIANT* p)
4248 {
4249 WRAPPER_NO_CONTRACT;
4250 Wrapper<VARIANT*, DispParamHolderDoNothing, DispParamHolderRelease, NULL>::operator=(p);
4251 }
4252};
4253
4254
4255
4256//--------------------------------------------------------------------------------
4257// InvokeDispMethod will convert a set of managed objects and call IDispatch. The
4258// result will be returned as a CLR Variant pointed to by pRetVal.
4259void IUInvokeDispMethod(
4260 REFLECTCLASSBASEREF* pRefClassObj,
4261 OBJECTREF* pTarget,
4262 OBJECTREF* pName,
4263 DISPID *pMemberID,
4264 OBJECTREF* pArgs,
4265 OBJECTREF* pByrefModifiers,
4266 OBJECTREF* pNamedArgs,
4267 OBJECTREF* pRetVal,
4268 LCID lcid,
4269 WORD flags,
4270 BOOL bIgnoreReturn,
4271 BOOL bIgnoreCase)
4272{
4273 CONTRACTL
4274 {
4275 THROWS;
4276 GC_TRIGGERS;
4277 MODE_COOPERATIVE;
4278 PRECONDITION(CheckPointer(pTarget));
4279 }
4280 CONTRACTL_END;
4281
4282 HRESULT hr;
4283 UINT i;
4284 UINT iSrcArg;
4285 UINT iDestArg;
4286 VARIANT VarResult;
4287 UINT cArgs = 0;
4288 UINT cNamedArgs = 0;
4289 DISPPARAMS DispParams = {0};
4290 DISPID* aDispID = NULL;
4291 DISPID MemberID = 0;
4292 ByrefArgumentInfo* aByrefArgInfos = NULL;
4293 BOOL bSomeArgsAreByref = FALSE;
4294 SafeComHolder<IDispatch> pDisp = NULL;
4295 SafeComHolder<IDispatchEx> pDispEx = NULL;
4296 VariantPtrHolder pVarResult = NULL;
4297 NewArrayHolder<DispParamHolder> params = NULL;
4298
4299 //
4300 // Function initialization.
4301 //
4302
4303 SafeVariantInit(&VarResult);
4304
4305
4306 // InteropUtil.h does not know about anything other than OBJECTREF so
4307 // convert the OBJECTREF's to their real type.
4308
4309 STRINGREF* pStrName = (STRINGREF*) pName;
4310 PTRARRAYREF* pArrArgs = (PTRARRAYREF*) pArgs;
4311 PTRARRAYREF* pArrByrefModifiers = (PTRARRAYREF*) pByrefModifiers;
4312 PTRARRAYREF* pArrNamedArgs = (PTRARRAYREF*) pNamedArgs;
4313 MethodTable* pInvokedMT = (*pRefClassObj)->GetType().GetMethodTable();
4314 PREFIX_ASSUME(pInvokedMT != NULL);
4315
4316 // Retrieve the total count of arguments.
4317 if (*pArrArgs != NULL)
4318 cArgs = (*pArrArgs)->GetNumComponents();
4319
4320 // Retrieve the count of named arguments.
4321 if (*pArrNamedArgs != NULL)
4322 cNamedArgs = (*pArrNamedArgs)->GetNumComponents();
4323
4324 // Validate that the target is valid for the specified type.
4325 if (!IsComTargetValidForType(pRefClassObj, pTarget))
4326 COMPlusThrow(kTargetException, W("RFLCT.Targ_ITargMismatch"));
4327
4328 // If the invoked type is an interface, make sure it is IDispatch based.
4329 if (pInvokedMT->IsInterface())
4330 {
4331 CorIfaceAttr ifaceType = pInvokedMT->GetComInterfaceType();
4332 if (!IsDispatchBasedItf(ifaceType))
4333 COMPlusThrow(kTargetInvocationException, IDS_EE_INTERFACE_NOT_DISPATCH_BASED);
4334 }
4335
4336 // Validate that the target is a COM object.
4337 _ASSERTE((*pTarget)->GetMethodTable()->IsComObjectType());
4338
4339 //
4340 // Initialize the DISPPARAMS structure.
4341 //
4342 if (cArgs > 0)
4343 {
4344 UINT cPositionalArgs = cArgs - cNamedArgs;
4345
4346 DispParams.cArgs = cArgs;
4347 DispParams.rgvarg = (VARIANTARG *)_alloca(cArgs * sizeof(VARIANTARG));
4348 params = new DispParamHolder[cArgs];
4349
4350 // Initialize all the variants.
4351 GCX_PREEMP();
4352 for (i = 0; i < cArgs; i++)
4353 {
4354 SafeVariantInit(&DispParams.rgvarg[i]);
4355 params[i] = &DispParams.rgvarg[i];
4356 }
4357 }
4358
4359
4360 //
4361 // Retrieve the IDispatch interface that will be invoked on.
4362 //
4363
4364 if (pInvokedMT->IsInterface())
4365 {
4366 // The invoked type is a dispatch or dual interface so we will make the
4367 // invocation on it.
4368 pDisp = (IDispatch *)ComObject::GetComIPFromRCWThrowing(pTarget, pInvokedMT);
4369 }
4370 else
4371 {
4372 // A class was passed in so we will make the invocation on the default
4373 // IDispatch for the COM component.
4374
4375 RCWHolder pRCW(GetThread());
4376 RCWPROTECT_BEGIN(pRCW, *pTarget);
4377
4378 // Retrieve the IDispath pointer from the wrapper.
4379 pDisp = (IDispatch*)pRCW->GetIDispatch();
4380 if (!pDisp)
4381 COMPlusThrow(kTargetInvocationException, IDS_EE_NO_IDISPATCH_ON_TARGET);
4382
4383 // If we aren't ignoring case, then we need to try and QI for IDispatchEx to
4384 // be able to use IDispatchEx::GetDispID() which has a flag to control case
4385 // sentisitivity.
4386 if (!bIgnoreCase && cNamedArgs == 0)
4387 {
4388 RCW_VTABLEPTR(pRCW);
4389 hr = SafeQueryInterface(pDisp, IID_IDispatchEx, (IUnknown**)&pDispEx);
4390 if (FAILED(hr))
4391 pDispEx = NULL;
4392 }
4393
4394 RCWPROTECT_END(pRCW);
4395 }
4396 _ASSERTE((IUnknown*)pDisp != NULL);
4397
4398
4399 //
4400 // Prepare the DISPID's that will be passed to invoke.
4401 //
4402
4403 if (pMemberID && (*pMemberID != DISPID_UNKNOWN) && (cNamedArgs == 0))
4404 {
4405 // The caller specified a member ID and we don't have any named arguments so
4406 // we can simply use the member ID the caller specified.
4407 MemberID = *pMemberID;
4408 }
4409 else
4410 {
4411 int strNameLength = (*pStrName)->GetStringLength();
4412
4413 // Check if we are invoking on the default member.
4414 if (strNameLength == 0)
4415 {
4416 // Set the DISPID to 0 (default member).
4417 MemberID = 0;
4418
4419 _ASSERTE(cNamedArgs == 0);
4420 if (cNamedArgs != 0)
4421 COMPlusThrow(kNotSupportedException,W("NotSupported_IDispInvokeDefaultMemberWithNamedArgs"));
4422 }
4423 else
4424 {
4425 //
4426 // Create an array of strings that will be passed to GetIDsOfNames().
4427 //
4428
4429 UINT cNamesToConvert = cNamedArgs + 1;
4430 LPWSTR strTmpName = NULL;
4431
4432 // Allocate the array of strings to convert, the array of pinned handles and the
4433 // array of converted DISPID's.
4434 size_t allocSize = cNamesToConvert * sizeof(LPWSTR);
4435 if (allocSize < cNamesToConvert)
4436 COMPlusThrowArgumentOutOfRange(W("namedParameters"), W("ArgumentOutOfRange_Capacity"));
4437 LPWSTR *aNamesToConvert = (LPWSTR *)_alloca(allocSize);
4438
4439 allocSize = cNamesToConvert * sizeof(DISPID);
4440 if (allocSize < cNamesToConvert)
4441 COMPlusThrowArgumentOutOfRange(W("namedParameters"), W("ArgumentOutOfRange_Capacity"));
4442 aDispID = (DISPID *)_alloca(allocSize);
4443
4444 // The first name to convert is the name of the method itself.
4445 aNamesToConvert[0] = (*pStrName)->GetBuffer();
4446
4447 // Check to see if the name is for a standard DISPID.
4448 if (SString::_wcsnicmp(aNamesToConvert[0], STANDARD_DISPID_PREFIX, STANDARD_DISPID_PREFIX_LENGTH) == 0)
4449 {
4450 // The name is for a standard DISPID so extract it from the name.
4451 MemberID = ExtractStandardDispId(aNamesToConvert[0]);
4452
4453 // Make sure there are no named arguments to convert.
4454 if (cNamedArgs > 0)
4455 {
4456 STRINGREF *pNamedArgsData = (STRINGREF *)(*pArrNamedArgs)->GetDataPtr();
4457
4458 for (i = 0; i < cNamedArgs; i++)
4459 {
4460 // The first name to convert is the name of the method itself.
4461 strTmpName = pNamedArgsData[i]->GetBuffer();
4462
4463 // Check to see if the name is for a standard DISPID.
4464 if (SString::_wcsnicmp(strTmpName, STANDARD_DISPID_PREFIX, STANDARD_DISPID_PREFIX_LENGTH) != 0)
4465 COMPlusThrow(kArgumentException, IDS_EE_NON_STD_NAME_WITH_STD_DISPID);
4466
4467 // The name is for a standard DISPID so extract it from the name.
4468 aDispID[i + 1] = ExtractStandardDispId(strTmpName);
4469 }
4470 }
4471 }
4472 else
4473 {
4474 BOOL fGotIt = FALSE;
4475 BOOL fIsNonGenericComObject = pInvokedMT->IsInterface() || (pInvokedMT != g_pBaseCOMObject && pInvokedMT->IsComObjectType());
4476 BOOL fUseCache = fIsNonGenericComObject && !(IUnknown*)pDispEx && strNameLength <= ReflectionMaxCachedNameLength && cNamedArgs == 0;
4477 DispIDCacheElement vDispIDElement;
4478
4479 // If the object is not a generic COM object and the member meets the criteria to be
4480 // in the cache then look up the DISPID in the cache.
4481 if (fUseCache)
4482 {
4483 vDispIDElement.pMT = pInvokedMT;
4484 vDispIDElement.strNameLength = strNameLength;
4485 vDispIDElement.lcid = lcid;
4486 wcscpy_s(vDispIDElement.strName, COUNTOF(vDispIDElement.strName), aNamesToConvert[0]);
4487
4488 // Only look up if the cache has already been created.
4489 DispIDCache* pDispIDCache = GetAppDomain()->GetRefDispIDCache();
4490 fGotIt = pDispIDCache->GetFromCache (&vDispIDElement, MemberID);
4491 }
4492
4493 if (!fGotIt)
4494 {
4495 NewArrayHolder<PinningHandleHolder> ahndPinnedObjs = new PinningHandleHolder[cNamesToConvert];
4496 ahndPinnedObjs[0] = GetAppDomain()->CreatePinningHandle((OBJECTREF)*pStrName);
4497
4498 // Copy the named arguments into the array of names to convert.
4499 if (cNamedArgs > 0)
4500 {
4501 STRINGREF *pNamedArgsData = (STRINGREF *)(*pArrNamedArgs)->GetDataPtr();
4502
4503 for (i = 0; i < cNamedArgs; i++)
4504 {
4505 // Pin the string object and retrieve a pointer to its data.
4506 ahndPinnedObjs[i + 1] = GetAppDomain()->CreatePinningHandle((OBJECTREF)pNamedArgsData[i]);
4507 aNamesToConvert[i + 1] = pNamedArgsData[i]->GetBuffer();
4508 }
4509 }
4510
4511 //
4512 // Call GetIDsOfNames to convert the names to DISPID's
4513 //
4514
4515 {
4516 // We are about to make call's to COM so switch to preemptive GC.
4517 GCX_PREEMP();
4518
4519 if ((IUnknown*)pDispEx)
4520 {
4521 // We should only get here if we are doing a case sensitive lookup and
4522 // we don't have any named arguments.
4523 _ASSERTE(cNamedArgs == 0);
4524 _ASSERTE(!bIgnoreCase);
4525
4526 // We managed to retrieve an IDispatchEx IP so we will use it to
4527 // retrieve the DISPID.
4528 BSTRHolder bstrTmpName = SysAllocString(aNamesToConvert[0]);
4529 if (!bstrTmpName)
4530 COMPlusThrowOM();
4531
4532 hr = pDispEx->GetDispID(bstrTmpName, fdexNameCaseSensitive, aDispID);
4533 }
4534 else
4535 {
4536 // Call GetIdsOfNames() to retrieve the DISPID's of the method and of the arguments.
4537 hr = pDisp->GetIDsOfNames(
4538 IID_NULL,
4539 aNamesToConvert,
4540 cNamesToConvert,
4541 lcid,
4542 aDispID
4543 );
4544 }
4545 }
4546
4547 if (FAILED(hr))
4548 {
4549 // Check to see if the user wants to invoke the new enum member.
4550 if (cNamesToConvert == 1 && SString::_wcsicmp(aNamesToConvert[0], GET_ENUMERATOR_METHOD_NAME) == 0)
4551 {
4552 // Invoke the new enum member.
4553 MemberID = DISPID_NEWENUM;
4554 }
4555 else
4556 {
4557 // The name is unknown.
4558 COMPlusThrowHR(hr);
4559 }
4560 }
4561 else
4562 {
4563 // The member ID is the first elements of the array we got back from GetIdsOfNames.
4564 MemberID = aDispID[0];
4565 }
4566
4567 // If the object is not a generic COM object and the member meets the criteria to be
4568 // in the cache then insert the member in the cache.
4569 if (fUseCache)
4570 {
4571 DispIDCache *pDispIDCache = GetAppDomain()->GetRefDispIDCache();
4572 pDispIDCache->AddToCache (&vDispIDElement, MemberID);
4573 }
4574 }
4575 }
4576 }
4577
4578 // Store the member ID if the caller passed in a place to store it.
4579 if (pMemberID)
4580 *pMemberID = MemberID;
4581 }
4582
4583
4584 //
4585 // Fill in the DISPPARAMS structure.
4586 //
4587
4588 if (cArgs > 0)
4589 {
4590 // Allocate the byref argument information.
4591 aByrefArgInfos = (ByrefArgumentInfo*)_alloca(cArgs * sizeof(ByrefArgumentInfo));
4592 memset(aByrefArgInfos, 0, cArgs * sizeof(ByrefArgumentInfo));
4593
4594 // Set the byref bit on the arguments that have the byref modifier.
4595 if (*pArrByrefModifiers != NULL)
4596 {
4597 BYTE *aByrefModifiers = (BYTE*)(*pArrByrefModifiers)->GetDataPtr();
4598 for (i = 0; i < cArgs; i++)
4599 {
4600 if (aByrefModifiers[i])
4601 {
4602 aByrefArgInfos[i].m_bByref = TRUE;
4603 bSomeArgsAreByref = TRUE;
4604 }
4605 }
4606 }
4607
4608 // We need to protect the temporary object that will be used to convert from
4609 // the managed objects to OLE variants.
4610 OBJECTREF TmpObj = NULL;
4611 GCPROTECT_BEGIN(TmpObj)
4612 {
4613 if (!(flags & (DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF)))
4614 {
4615 // For anything other than a put or a putref we just use the specified
4616 // named arguments.
4617 DispParams.cNamedArgs = cNamedArgs;
4618 DispParams.rgdispidNamedArgs = (cNamedArgs == 0) ? NULL : &aDispID[1];
4619
4620 // Convert the named arguments from COM+ to OLE. These arguments are in the same order
4621 // on both sides.
4622 for (i = 0; i < cNamedArgs; i++)
4623 {
4624 iSrcArg = i;
4625 iDestArg = i;
4626 TmpObj = ((OBJECTREF*)(*pArrArgs)->GetDataPtr())[iSrcArg];
4627 DispInvokeConvertObjectToVariant(&TmpObj, &DispParams.rgvarg[iDestArg], &aByrefArgInfos[iSrcArg]);
4628 }
4629
4630 // Convert the unnamed arguments. These need to be presented in reverse order to IDispatch::Invoke().
4631 for (iSrcArg = cNamedArgs, iDestArg = cArgs - 1; iSrcArg < cArgs; iSrcArg++, iDestArg--)
4632 {
4633 TmpObj = ((OBJECTREF*)(*pArrArgs)->GetDataPtr())[iSrcArg];
4634 DispInvokeConvertObjectToVariant(&TmpObj, &DispParams.rgvarg[iDestArg], &aByrefArgInfos[iSrcArg]);
4635 }
4636 }
4637 else
4638 {
4639 // If we are doing a property put then we need to set the DISPID of the
4640 // argument to DISP_PROPERTYPUT if there is at least one argument.
4641 DispParams.cNamedArgs = cNamedArgs + 1;
4642 DispParams.rgdispidNamedArgs = (DISPID*)_alloca((cNamedArgs + 1) * sizeof(DISPID));
4643
4644 // Fill in the array of named arguments.
4645 DispParams.rgdispidNamedArgs[0] = DISPID_PROPERTYPUT;
4646 for (i = 1; i < cNamedArgs; i++)
4647 DispParams.rgdispidNamedArgs[i] = aDispID[i];
4648
4649 // The last argument from reflection becomes the first argument that must be passed to IDispatch.
4650 iSrcArg = cArgs - 1;
4651 iDestArg = 0;
4652 TmpObj = ((OBJECTREF*)(*pArrArgs)->GetDataPtr())[iSrcArg];
4653 DispInvokeConvertObjectToVariant(&TmpObj, &DispParams.rgvarg[iDestArg], &aByrefArgInfos[iSrcArg]);
4654
4655 // Convert the named arguments from COM+ to OLE. These arguments are in the same order
4656 // on both sides.
4657 for (i = 0; i < cNamedArgs; i++)
4658 {
4659 iSrcArg = i;
4660 iDestArg = i + 1;
4661 TmpObj = ((OBJECTREF*)(*pArrArgs)->GetDataPtr())[iSrcArg];
4662 DispInvokeConvertObjectToVariant(&TmpObj, &DispParams.rgvarg[iDestArg], &aByrefArgInfos[iSrcArg]);
4663 }
4664
4665 // Convert the unnamed arguments. These need to be presented in reverse order to IDispatch::Invoke().
4666 for (iSrcArg = cNamedArgs, iDestArg = cArgs - 1; iSrcArg < cArgs - 1; iSrcArg++, iDestArg--)
4667 {
4668 TmpObj = ((OBJECTREF*)(*pArrArgs)->GetDataPtr())[iSrcArg];
4669 DispInvokeConvertObjectToVariant(&TmpObj, &DispParams.rgvarg[iDestArg], &aByrefArgInfos[iSrcArg]);
4670 }
4671 }
4672 }
4673 GCPROTECT_END();
4674 }
4675 else
4676 {
4677 // There are no arguments.
4678 DispParams.cArgs = cArgs;
4679 DispParams.cNamedArgs = 0;
4680 DispParams.rgdispidNamedArgs = NULL;
4681 DispParams.rgvarg = NULL;
4682 }
4683
4684 // If we're calling on DISPID=-4, then pass both METHOD and PROPERTYGET
4685 if (MemberID == DISPID_NEWENUM)
4686 {
4687 _ASSERTE((flags & DISPATCH_METHOD) && "Expected DISPATCH_METHOD to be set.");
4688 flags |= DISPATCH_METHOD | DISPATCH_PROPERTYGET;
4689 }
4690
4691 //
4692 // Call invoke on the target's IDispatch.
4693 //
4694
4695 if (!bIgnoreReturn)
4696 pVarResult = &VarResult;
4697
4698 DoIUInvokeDispMethod(pDispEx, pDisp, MemberID, lcid, flags, &DispParams, pVarResult);
4699
4700
4701 //
4702 // Return value handling and cleanup.
4703 //
4704
4705 // Back propagate any byref args.
4706 if (bSomeArgsAreByref)
4707 {
4708 OBJECTREF TmpObj = NULL;
4709 GCPROTECT_BEGIN(TmpObj)
4710 {
4711 for (i = 0; i < cArgs; i++)
4712 {
4713 if (aByrefArgInfos[i].m_bByref)
4714 {
4715 // Convert the variant back to an object.
4716 OleVariant::MarshalObjectForOleVariant(&aByrefArgInfos[i].m_Val, &TmpObj);
4717 (*pArrArgs)->SetAt(i, TmpObj);
4718 }
4719 }
4720 }
4721 GCPROTECT_END();
4722 }
4723
4724 if (!bIgnoreReturn)
4725 {
4726 if (MemberID == DISPID_NEWENUM)
4727 {
4728 //
4729 // Use a custom marshaler to convert the IEnumVARIANT to an IEnumerator.
4730 //
4731
4732 // Start by making sure that the variant we got back contains an IP.
4733 if ((VarResult.vt != VT_UNKNOWN) || !VarResult.punkVal)
4734 COMPlusThrow(kInvalidCastException, IDS_EE_INVOKE_NEW_ENUM_INVALID_RETURN);
4735
4736 // Have the custom marshaler do the conversion.
4737 *pRetVal = ConvertEnumVariantToMngEnum((IEnumVARIANT *)VarResult.punkVal);
4738 }
4739 else
4740 {
4741 // Convert the return variant to a COR variant.
4742 OleVariant::MarshalObjectForOleVariant(&VarResult, pRetVal);
4743 }
4744 }
4745}
4746
4747#if defined(FEATURE_COMINTEROP_UNMANAGED_ACTIVATION) && defined(FEATURE_CLASSIC_COMINTEROP)
4748
4749void GetComClassHelper(
4750 _Out_ OBJECTREF *pRef,
4751 _In_ EEClassFactoryInfoHashTable *pClassFactHash,
4752 _In_ ClassFactoryInfo *pClassFactInfo,
4753 _In_opt_ WCHAR *wszProgID)
4754{
4755 CONTRACTL
4756 {
4757 THROWS;
4758 GC_TRIGGERS;
4759 MODE_ANY;
4760 INJECT_FAULT(ThrowOutOfMemory());
4761 PRECONDITION(CheckPointer(pRef));
4762 PRECONDITION(CheckPointer(pClassFactHash));
4763 PRECONDITION(CheckPointer(pClassFactInfo));
4764 PRECONDITION(CheckPointer(wszProgID, NULL_OK));
4765 }
4766 CONTRACTL_END;
4767
4768 OBJECTHANDLE hRef;
4769 AppDomain *pDomain = GetAppDomain();
4770
4771 CrstHolder ch(pDomain->GetRefClassFactCrst());
4772
4773 // Check again.
4774 if (pClassFactHash->GetValue(pClassFactInfo, (HashDatum *)&hRef))
4775 {
4776 *pRef = ObjectFromHandle(hRef);
4777 }
4778 else
4779 {
4780 //
4781 // There is no managed class for this CLSID
4782 // so we will create a ComClassFactory to
4783 // represent it.
4784 //
4785
4786 NewHolder<ComClassFactory> pComClsFac = ComClassFactoryCreator::Create(pClassFactInfo->m_clsid);
4787 pComClsFac->SetManagedVersion();
4788
4789 NewArrayHolder<WCHAR> wszRefProgID = NULL;
4790 if (wszProgID)
4791 {
4792 size_t len = wcslen(wszProgID)+1;
4793 wszRefProgID = new WCHAR[len];
4794 wcscpy_s(wszRefProgID, len, wszProgID);
4795 }
4796
4797 NewArrayHolder<WCHAR> wszRefServer = NULL;
4798 if (pClassFactInfo->m_strServerName)
4799 {
4800 size_t len = wcslen(pClassFactInfo->m_strServerName)+1;
4801 wszRefServer = new WCHAR[len];
4802 wcscpy_s(wszRefServer, len, pClassFactInfo->m_strServerName);
4803 }
4804
4805 pComClsFac->Init(wszRefProgID, wszRefServer, NULL);
4806 AllocateComClassObject(pComClsFac, pRef);
4807
4808 // Insert to hash.
4809 hRef = pDomain->CreateHandle(*pRef);
4810 pClassFactHash->InsertValue(pClassFactInfo, (LPVOID)hRef);
4811
4812 // Make sure the hash code is working.
4813 _ASSERTE (pClassFactHash->GetValue(pClassFactInfo, (HashDatum *)&hRef));
4814
4815 wszRefProgID.SuppressRelease();
4816 wszRefServer.SuppressRelease();
4817 pComClsFac.SuppressRelease();
4818 }
4819}
4820
4821//-------------------------------------------------------------
4822// returns a ComClass reflect class that wraps the IClassFactory
4823void GetComClassFromProgID(STRINGREF srefProgID, STRINGREF srefServer, OBJECTREF *pRef)
4824{
4825 CONTRACTL
4826 {
4827 THROWS;
4828 GC_TRIGGERS;
4829 MODE_COOPERATIVE;
4830 INJECT_FAULT(COMPlusThrowOM());
4831 PRECONDITION(srefProgID != NULL);
4832 PRECONDITION(pRef != NULL);
4833 }
4834 CONTRACTL_END;
4835
4836 NewArrayHolder<WCHAR> wszProgID;
4837 NewArrayHolder<WCHAR> wszServer;
4838 HRESULT hr = S_OK;
4839 MethodTable* pMT = NULL;
4840 CLSID clsid = {0};
4841 BOOL bServerIsLocal = (srefServer == NULL);
4842
4843 //
4844 // Allocate strings for the ProgID and the server.
4845 //
4846
4847 int len = srefProgID->GetStringLength();
4848
4849 wszProgID = new WCHAR[len+1];
4850
4851 if (len)
4852 memcpy(wszProgID, srefProgID->GetBuffer(), (len*2));
4853 wszProgID[len] = W('\0');
4854
4855 if (srefServer != NULL)
4856 {
4857 len = srefServer->GetStringLength();
4858
4859 wszServer = new WCHAR[len+1];
4860
4861 if (len)
4862 memcpy(wszServer, srefServer->GetBuffer(), (len*2));
4863 wszServer[len] = W('\0');
4864 }
4865
4866
4867 //
4868 // Call GetCLSIDFromProgID() to convert the ProgID to a CLSID.
4869 //
4870
4871 EnsureComStarted();
4872
4873 {
4874 GCX_PREEMP();
4875 hr = GetCLSIDFromProgID(wszProgID, &clsid);
4876 }
4877
4878 if (FAILED(hr))
4879 COMPlusThrowHR(hr);
4880
4881 //
4882 // If no server name has been specified, see if we can find the well known
4883 // managed class for this CLSID.
4884 //
4885
4886 if (bServerIsLocal)
4887 {
4888 BOOL fAssemblyInReg = FALSE;
4889 // @TODO(DM): Do we really need to be this forgiving ? We should
4890 // look into letting the type load exceptions percolate
4891 // up to the user instead of swallowing them and using __ComObject.
4892 EX_TRY
4893 {
4894 pMT = GetTypeForCLSID(clsid, &fAssemblyInReg);
4895 }
4896 EX_CATCH
4897 {
4898 }
4899 EX_END_CATCH(RethrowTerminalExceptions)
4900 }
4901
4902 if (pMT != NULL)
4903 {
4904 //
4905 // There is a managed class for this ProgID.
4906 //
4907
4908 *pRef = pMT->GetManagedClassObject();
4909 }
4910 else
4911 {
4912 // Check if we have in the hash.
4913 OBJECTHANDLE hRef;
4914 ClassFactoryInfo ClassFactInfo;
4915 ClassFactInfo.m_clsid = clsid;
4916 ClassFactInfo.m_strServerName = wszServer;
4917 EEClassFactoryInfoHashTable *pClassFactHash = GetAppDomain()->GetClassFactHash();
4918
4919 if (pClassFactHash->GetValue(&ClassFactInfo, (HashDatum *)&hRef))
4920 {
4921 *pRef = ObjectFromHandle(hRef);
4922 }
4923 else
4924 {
4925 GetComClassHelper(pRef, pClassFactHash, &ClassFactInfo, wszProgID);
4926 }
4927 }
4928
4929 // If we made it this far *pRef better be set.
4930 _ASSERTE(*pRef != NULL);
4931}
4932
4933//-------------------------------------------------------------
4934// returns a ComClass reflect class that wraps the IClassFactory
4935void GetComClassFromCLSID(REFCLSID clsid, STRINGREF srefServer, OBJECTREF *pRef)
4936{
4937 CONTRACTL
4938 {
4939 THROWS;
4940 GC_TRIGGERS;
4941 MODE_COOPERATIVE;
4942 INJECT_FAULT(COMPlusThrowOM());
4943 PRECONDITION(pRef != NULL);
4944 }
4945 CONTRACTL_END;
4946
4947 NewArrayHolder<WCHAR> wszServer;
4948 HRESULT hr = S_OK;
4949 MethodTable* pMT = NULL;
4950 BOOL bServerIsLocal = (srefServer == NULL);
4951
4952 //
4953 // Allocate strings for the server.
4954 //
4955
4956 if (srefServer != NULL)
4957 {
4958 int len = srefServer->GetStringLength();
4959
4960 wszServer = new WCHAR[len+1];
4961
4962 if (len)
4963 memcpy(wszServer, srefServer->GetBuffer(), (len*2));
4964
4965 wszServer[len] = W('\0');
4966 }
4967
4968
4969 //
4970 // If no server name has been specified, see if we can find the well known
4971 // managed class for this CLSID.
4972 //
4973
4974 if (bServerIsLocal)
4975 {
4976 // @TODO(DM): Do we really need to be this forgiving ? We should
4977 // look into letting the type load exceptions percolate
4978 // up to the user instead of swallowing them and using __ComObject.
4979 EX_TRY
4980 {
4981 pMT = GetTypeForCLSID(clsid);
4982 }
4983 EX_CATCH
4984 {
4985 }
4986 EX_END_CATCH(RethrowTerminalExceptions)
4987 }
4988
4989 if (pMT != NULL)
4990 {
4991 //
4992 // There is a managed class for this CLSID.
4993 //
4994
4995 *pRef = pMT->GetManagedClassObject();
4996 }
4997 else
4998 {
4999 // Check if we have in the hash.
5000 OBJECTHANDLE hRef;
5001 ClassFactoryInfo ClassFactInfo;
5002 ClassFactInfo.m_clsid = clsid;
5003 ClassFactInfo.m_strServerName = wszServer;
5004 EEClassFactoryInfoHashTable *pClassFactHash = GetAppDomain()->GetClassFactHash();
5005
5006 if (pClassFactHash->GetValue(&ClassFactInfo, (HashDatum*) &hRef))
5007 {
5008 *pRef = ObjectFromHandle(hRef);
5009 }
5010 else
5011 {
5012 GetComClassHelper(pRef, pClassFactHash, &ClassFactInfo, NULL);
5013 }
5014 }
5015
5016 // If we made it this far *pRef better be set.
5017 _ASSERTE(*pRef != NULL);
5018}
5019
5020#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION && FEATURE_CLASSIC_COMINTEROP
5021
5022#endif //#ifndef CROSSGEN_COMPILE
5023
5024
5025#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
5026//-------------------------------------------------------------
5027// check if a ComClassFactory has been setup for this class
5028// if not set one up
5029ClassFactoryBase *GetComClassFactory(MethodTable* pClassMT)
5030{
5031 CONTRACT (ClassFactoryBase*)
5032 {
5033 THROWS;
5034 GC_TRIGGERS;
5035 MODE_ANY;
5036 INJECT_FAULT(ThrowOutOfMemory());
5037 PRECONDITION(CheckPointer(pClassMT));
5038 PRECONDITION(pClassMT->IsComObjectType() || pClassMT->IsExportedToWinRT());
5039 POSTCONDITION(CheckPointer(RETVAL));
5040 }
5041 CONTRACT_END;
5042
5043 if (!pClassMT->IsExportedToWinRT())
5044 {
5045 // Work our way up the hierachy until we find the first COM import type.
5046 while (!pClassMT->IsComImport())
5047 {
5048 pClassMT = pClassMT->GetParentMethodTable();
5049 _ASSERTE(pClassMT != NULL);
5050 _ASSERTE(pClassMT->IsComObjectType());
5051 }
5052 }
5053
5054 // check if com data has been setup for this class
5055 ClassFactoryBase *pClsFac = pClassMT->GetComClassFactory();
5056
5057 if (pClsFac == NULL)
5058 {
5059 //
5060 // Collectible types do not support WinRT interop
5061 //
5062 if (pClassMT->Collectible() && (pClassMT->IsExportedToWinRT() || pClassMT->IsProjectedFromWinRT()))
5063 {
5064 COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleWinRT"));
5065 }
5066
5067 NewHolder<ClassFactoryBase> pNewFactory;
5068
5069 if (pClassMT->IsExportedToWinRT())
5070 {
5071 WinRTManagedClassFactory *pWinRTMngClsFac = new WinRTManagedClassFactory(pClassMT);
5072 pNewFactory = pWinRTMngClsFac;
5073
5074 pWinRTMngClsFac->Init();
5075 }
5076 else if (pClassMT->IsProjectedFromWinRT())
5077 {
5078 WinRTClassFactory *pWinRTClsFac = new WinRTClassFactory(pClassMT);
5079 pNewFactory = pWinRTClsFac;
5080
5081 pWinRTClsFac->Init();
5082 }
5083 else
5084 {
5085 GUID guid;
5086 pClassMT->GetGuid(&guid, TRUE);
5087
5088 ComClassFactory *pComClsFac = ComClassFactoryCreator::Create(guid);
5089
5090 pNewFactory = pComClsFac;
5091
5092 pComClsFac->Init(NULL, NULL, pClassMT);
5093 }
5094
5095 // store the class factory in EE Class
5096 if (!pClassMT->SetComClassFactory(pNewFactory))
5097 {
5098 // another thread beat us to it
5099 pNewFactory = pClassMT->GetComClassFactory();
5100 }
5101
5102 pClsFac = pNewFactory.Extract();
5103 }
5104
5105 RETURN pClsFac;
5106}
5107#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
5108
5109
5110//-------------------------------------------------------------------
5111// void InitializeComInterop()
5112// Called from EEStartup, to initialize com Interop specific data
5113// structures.
5114//-------------------------------------------------------------------
5115void InitializeComInterop()
5116{
5117 CONTRACTL
5118 {
5119 THROWS;
5120 GC_TRIGGERS;
5121 MODE_ANY;
5122 }
5123 CONTRACTL_END;
5124
5125 InitializeSListHead(&RCW::s_RCWStandbyList);
5126 ComCall::Init();
5127#ifdef _TARGET_X86_
5128 ComPlusCall::Init();
5129#endif
5130#ifndef CROSSGEN_COMPILE
5131 CtxEntryCache::Init();
5132 ComCallWrapperTemplate::Init();
5133#ifdef _DEBUG
5134 IntializeInteropLogging();
5135#endif //_DEBUG
5136#endif //CROSSGEN_COMPILE
5137}
5138
5139// Try to load a WinRT type.
5140TypeHandle GetWinRTType(SString* ssTypeName, BOOL bThrowIfNotFound)
5141{
5142 CONTRACT (TypeHandle)
5143 {
5144 MODE_ANY;
5145 THROWS;
5146 GC_TRIGGERS;
5147 }
5148 CONTRACT_END;
5149
5150 TypeHandle typeHandle;
5151
5152 SString ssAssemblyName(SString::Utf8Literal, "WindowsRuntimeAssemblyName, ContentType=WindowsRuntime");
5153 DomainAssembly *pAssembly = LoadDomainAssembly(&ssAssemblyName, NULL,
5154 NULL,
5155 bThrowIfNotFound, ssTypeName);
5156 if (pAssembly != NULL)
5157 {
5158 typeHandle = TypeName::GetTypeFromAssembly(*ssTypeName, pAssembly->GetAssembly(), bThrowIfNotFound);
5159 }
5160
5161 RETURN typeHandle;
5162}
5163
5164// Makes a IRoSimpleMetaDataBuilder callback for a runtime class.
5165// static
5166HRESULT WinRTGuidGenerator::MetaDataLocator::LocateTypeWithDefaultInterface(MethodTable *pMT, LPCWSTR pszName, IRoSimpleMetaDataBuilder &metaDataDestination)
5167{
5168 CONTRACTL
5169 {
5170 THROWS;
5171 GC_TRIGGERS;
5172 MODE_ANY;
5173 PRECONDITION(CheckPointer(pMT));
5174 PRECONDITION(!pMT->IsInterface());
5175 PRECONDITION(CheckPointer(pszName));
5176 }
5177 CONTRACTL_END;
5178
5179 MethodTable *pDefItfMT = pMT->GetDefaultWinRTInterface();
5180 if (pDefItfMT == NULL)
5181 {
5182 StackSString ss;
5183 TypeString::AppendType(ss, TypeHandle(pMT));
5184 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, IDS_EE_WINRT_IID_NODEFAULTINTERFACE, ss.GetUnicode());
5185 }
5186
5187 DefineFullyQualifiedNameForClassW();
5188
5189 GUID iid;
5190 pDefItfMT->GetGuid(&iid, FALSE);
5191
5192 if (pDefItfMT->HasInstantiation())
5193 {
5194 SArray<BYTE> namesBuf;
5195 PCWSTR *pNamePointers;
5196 COUNT_T cNames;
5197 PopulateNames(pDefItfMT, namesBuf, pNamePointers, cNames);
5198
5199 // runtime class with generic default interface
5200 return metaDataDestination.SetRuntimeClassParameterizedDefault(
5201 pszName,
5202 cNames,
5203 pNamePointers);
5204 }
5205 else
5206 {
5207 LPCWSTR pszDefItfName = GetFullyQualifiedNameForClassW_WinRT(pDefItfMT);
5208
5209 // runtime class with non-generic default interface
5210 return metaDataDestination.SetRuntimeClassSimpleDefault(
5211 pszName,
5212 pszDefItfName,
5213 &iid);
5214 }
5215}
5216
5217// Makes a IRoSimpleMetaDataBuilder callback for a structure.
5218// static
5219HRESULT WinRTGuidGenerator::MetaDataLocator::LocateStructure(MethodTable *pMT, LPCWSTR pszName, IRoSimpleMetaDataBuilder &metaDataDestination)
5220{
5221 CONTRACTL
5222 {
5223 THROWS;
5224 GC_TRIGGERS;
5225 MODE_ANY;
5226 PRECONDITION(CheckPointer(pMT));
5227 PRECONDITION(CheckPointer(pszName));
5228 }
5229 CONTRACTL_END;
5230
5231 SArray<BYTE> namesBuf;
5232 COUNT_T cNames = 0;
5233
5234 ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
5235 for (FieldDesc *pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
5236 {
5237 TypeHandle th = pFD->GetApproxFieldTypeHandleThrowing();
5238 if (th.IsTypeDesc())
5239 {
5240 // WinRT structures should not have TypeDesc fields
5241 IfFailThrowBF(E_FAIL, BFA_BAD_SIGNATURE, pMT->GetModule());
5242 }
5243
5244 PopulateNamesAppendTypeName(th.AsMethodTable(), namesBuf, cNames);
5245 }
5246
5247 PCWSTR *pNamePointers;
5248 PopulateNamesAppendNamePointers(pMT, namesBuf, pNamePointers, cNames);
5249
5250 return metaDataDestination.SetStruct(
5251 pszName,
5252 cNames,
5253 pNamePointers);
5254}
5255
5256
5257//
5258// Tables of information about the redirected types used to setup GUID marshaling
5259//
5260
5261struct RedirectedEnumInfo
5262{
5263 LPCWSTR wszBackingField;
5264};
5265
5266#define DEFINE_PROJECTED_TYPE(szWinRTNS, szWinRTName, szClrNS, szClrName, nClrAsmIdx, nContractAsmIdx, nWinRTIndex, nClrIndex, nWinMDTypeKind) \
5267 { nullptr },
5268#define DEFINE_PROJECTED_ENUM(szWinRTNamespace, szWinRTName, szClrNamespace, szClrName, nClrAssemblyIndex, nContractAsmIdx, WinRTRedirectedTypeIndex, ClrRedirectedTypeIndex, szBackingFieldSize) \
5269 { L ## szBackingFieldSize },
5270
5271static const RedirectedEnumInfo g_redirectedEnumInfo[WinMDAdapter::RedirectedTypeIndex_Count] =
5272{
5273#include "winrtprojectedtypes.h"
5274};
5275
5276#undef DEFINE_PROJECTED_TYPE
5277#undef DEFINE_PROJECTED_ENUM
5278
5279struct RedirectedPInterfaceInfo
5280{
5281 DWORD cGenericParameters;
5282 const GUID IID;
5283};
5284
5285#define DEFINE_PROJECTED_TYPE(szWinRTNS, szWinRTName, szClrNS, szClrName, nClrAsmIdx, nContractAsmIdx, nWinRTIndex, nClrIndex, nWinMDTypeKind) \
5286 { 0, { 0 } },
5287#define DEFINE_PROJECTED_INTERFACE(szWinRTNamespace, szWinRTName, szClrNamespace, szClrName, nClrAssemblyIndex, nContractAsmIdx, WinRTRedirectedTypeIndex, ClrRedirectedTypeIndex, PIID) \
5288 { 0, PIID },
5289#define DEFINE_PROJECTED_PINTERFACE(szWinRTNamespace, szWinRTName, szClrNamespace, szClrName, nClrAssemblyIndex, nContractAsmIdx, WinRTRedirectedTypeIndex, ClrRedirectedTypeIndex, GenericTypeParameterCount, PIID) \
5290 { GenericTypeParameterCount, PIID },
5291
5292static const RedirectedPInterfaceInfo g_redirectedPInterfaceInfo[] =
5293{
5294#include "winrtprojectedtypes.h"
5295};
5296
5297#undef DEFINE_PROJECTED_TYPE
5298#undef DEFINE_PROJECTED_INTERFACE
5299#undef DEFINE_PROJECTED_PINTERFACE
5300
5301struct RedirectedPDelegateInfo
5302{
5303 const DWORD cGenericParameters;
5304 const GUID IID;
5305};
5306
5307#define DEFINE_PROJECTED_TYPE(szWinRTNS, szWinRTName, szClrNS, szClrName, nClrAsmIdx, nContractAsmIdx, nWinRTIndex, nClrIndex, nWinMDTypeKind) \
5308 { 0, { 0 } },
5309#define DEFINE_PROJECTED_DELEGATE(szWinRTNamespace, szWinRTName, szClrNamespace, szClrName, nClrAssemblyIndex, nContractAsmIdx, WinRTRedirectedTypeIndex, ClrRedirectedTypeIndex, PIID) \
5310 { 0, PIID },
5311#define DEFINE_PROJECTED_PDELEGATE(szWinRTNamespace, szWinRTName, szClrNamespace, szClrName, nClrAssemblyIndex, nContractAsmIdx, WinRTRedirectedTypeIndex, ClrRedirectedTypeIndex, GenericTypeParameterCount, PIID) \
5312 { GenericTypeParameterCount, PIID },
5313
5314static const RedirectedPDelegateInfo g_redirectedPDelegateInfo[] =
5315{
5316#include "winrtprojectedtypes.h"
5317};
5318
5319#undef DEFINE_PROJECTED_TYPE
5320#undef DEFINE_PROJECTED_DELEGATE
5321#undef DEFINE_PROJECTED_PDELEGATE
5322
5323struct RedirectedRuntimeclassInfo
5324{
5325 LPCWSTR wszDefaultIntefaceName;
5326 const GUID IID;
5327};
5328
5329#define DEFINE_PROJECTED_TYPE(szWinRTNS, szWinRTName, szClrNS, szClrName, nClrAsmIdx, nContractAsmIdx, nWinRTIndex, nClrIndex, nWinMDTypeKind) \
5330 { nullptr, { 0 } },
5331#define DEFINE_PROJECTED_RUNTIMECLASS(szWinRTNamespace, szWinRTName, szClrNamespace, szClrName, nClrAssemblyIndex, nContractAsmIdx, WinRTRedirectedTypeIndex, ClrRedirectedTypeIndex, szDefaultInterfaceName, DefaultInterfaceIID) \
5332 { L ## szDefaultInterfaceName, DefaultInterfaceIID },
5333
5334static RedirectedRuntimeclassInfo const g_redirectedRuntimeclassInfo[] =
5335{
5336#include "winrtprojectedtypes.h"
5337};
5338
5339#undef DEFINE_PROJECTED_TYPE
5340#undef DEFINE_PROJECTED_RUNTIMECLASS
5341
5342struct RedirectedStructInfo
5343{
5344 const DWORD cFields;
5345 const LPCWSTR *pwzFields;
5346};
5347
5348#define DEFINE_PROJECTED_TYPE(szWinRTNS, szWinRTName, szClrNS, szClrName, nClrAsmIdx, nContractAsmIdx, nWinRTIndex, nClrIndex, nWinMDTypeKind)
5349#define DEFINE_PROJECTED_STRUCT(szWinRTNamespace, szWinRTName, szClrNamespace, szClrName, nClrAssemblyIndex, nContractAsmIdx, WinRTRedirectedTypeIndex, ClrRedirectedTypeIndex, FieldSizes) \
5350static const LPCWSTR g_ ## WinRTRedirectedTypeIndex ## _Fields[] = { FieldSizes };
5351#define DEFINE_PROJECTED_JUPITER_STRUCT(szWinRTNamespace, szWinRTName, szClrNamespace, szClrName, nClrAssemblyIndex, nContractAsmIdx, WinRTRedirectedTypeIndex, ClrRedirectedTypeIndex, FieldSizes) \
5352static const LPCWSTR g_ ## WinRTRedirectedTypeIndex ## _Fields[] = { FieldSizes };
5353#include "winrtprojectedtypes.h"
5354#undef DEFINE_PROJECTED_TYPE
5355#undef DEFINE_PROJECTED_STRUCT
5356#undef DEFINE_PROJECTED_JUPITER_STRUCT
5357
5358#define DEFINE_PROJECTED_TYPE(szWinRTNS, szWinRTName, szClrNS, szClrName, nClrAsmIdx, nContractAsmIdx, nWinRTIndex, nClrIndex, nWinMDTypeKind) \
5359 { 0, nullptr },
5360#define DEFINE_PROJECTED_STRUCT(szWinRTNamespace, szWinRTName, szClrNamespace, szClrName, nClrAssemblyIndex, nContractAsmIdx, WinRTRedirectedTypeIndex, ClrRedirectedTypeIndex, FieldSizes) \
5361 { COUNTOF(g_ ## WinRTRedirectedTypeIndex ## _Fields), g_ ## WinRTRedirectedTypeIndex ## _Fields },
5362#define DEFINE_PROJECTED_JUPITER_STRUCT(szWinRTNamespace, szWinRTName, szClrNamespace, szClrName, nClrAssemblyIndex, nContractAsmIdx, WinRTRedirectedTypeIndex, ClrRedirectedTypeIndex, FieldSizes) \
5363 { COUNTOF(g_ ## WinRTRedirectedTypeIndex ## _Fields), g_ ## WinRTRedirectedTypeIndex ## _Fields },
5364
5365static const RedirectedStructInfo g_redirectedStructInfo[WinMDAdapter::RedirectedTypeIndex_Count] =
5366{
5367#include "winrtprojectedtypes.h"
5368};
5369
5370#undef DEFINE_PROJECTED_TYPE
5371#undef DEFINE_PROJECTED_STRUCT
5372#undef DEFINE_PROJECTED_JUPITER_STRUCT
5373
5374// Makes a IRoSimpleMetaDataBuilder callback for a redirected type or returns S_FALSE.
5375// static
5376HRESULT WinRTGuidGenerator::MetaDataLocator::LocateRedirectedType(
5377 MethodTable * pMT,
5378 IRoSimpleMetaDataBuilder & metaDataDestination)
5379{
5380 CONTRACTL
5381 {
5382 THROWS;
5383 GC_TRIGGERS;
5384 MODE_ANY;
5385 PRECONDITION(CheckPointer(pMT));
5386 }
5387 CONTRACTL_END;
5388
5389 WinMDAdapter::RedirectedTypeIndex nRedirectedTypeIndex;
5390 if (!WinRTTypeNameConverter::ResolveRedirectedType(pMT, &nRedirectedTypeIndex))
5391 {
5392 // this is not a redirected type
5393 return S_FALSE;
5394 }
5395
5396 WinMDAdapter::WinMDTypeKind typeKind;
5397 WinMDAdapter::GetRedirectedTypeInfo(nRedirectedTypeIndex, nullptr, nullptr, nullptr, nullptr, nullptr, &typeKind);
5398 switch (typeKind)
5399 {
5400 case WinMDAdapter::WinMDTypeKind_Attribute:
5401 {
5402 // not a runtime class -> throw
5403 StackSString ss;
5404 TypeString::AppendType(ss, TypeHandle(pMT));
5405 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, IDS_EE_WINRT_IID_NODEFAULTINTERFACE, ss.GetUnicode());
5406 }
5407
5408 case WinMDAdapter::WinMDTypeKind_Enum:
5409 return metaDataDestination.SetEnum(WinMDAdapter::GetRedirectedTypeFullWinRTName(nRedirectedTypeIndex),
5410 g_redirectedEnumInfo[nRedirectedTypeIndex].wszBackingField);
5411
5412 case WinMDAdapter::WinMDTypeKind_Delegate:
5413 return metaDataDestination.SetDelegate(g_redirectedPDelegateInfo[nRedirectedTypeIndex].IID);
5414
5415 case WinMDAdapter::WinMDTypeKind_PDelegate:
5416 return metaDataDestination.SetParameterizedDelegate(g_redirectedPDelegateInfo[nRedirectedTypeIndex].IID,
5417 g_redirectedPDelegateInfo[nRedirectedTypeIndex].cGenericParameters);
5418
5419 case WinMDAdapter::WinMDTypeKind_Interface:
5420 return metaDataDestination.SetWinRtInterface(g_redirectedPInterfaceInfo[nRedirectedTypeIndex].IID);
5421
5422 case WinMDAdapter::WinMDTypeKind_PInterface:
5423 return metaDataDestination.SetParameterizedInterface(g_redirectedPInterfaceInfo[nRedirectedTypeIndex].IID,
5424 g_redirectedPInterfaceInfo[nRedirectedTypeIndex].cGenericParameters);
5425
5426 case WinMDAdapter::WinMDTypeKind_Runtimeclass:
5427 return metaDataDestination.SetRuntimeClassSimpleDefault(WinMDAdapter::GetRedirectedTypeFullWinRTName(nRedirectedTypeIndex),
5428 g_redirectedRuntimeclassInfo[nRedirectedTypeIndex].wszDefaultIntefaceName,
5429 &g_redirectedRuntimeclassInfo[nRedirectedTypeIndex].IID);
5430
5431 case WinMDAdapter::WinMDTypeKind_Struct:
5432 return metaDataDestination.SetStruct(WinMDAdapter::GetRedirectedTypeFullWinRTName(nRedirectedTypeIndex),
5433 g_redirectedStructInfo[nRedirectedTypeIndex].cFields,
5434 g_redirectedStructInfo[nRedirectedTypeIndex].pwzFields);
5435
5436 default:
5437 UNREACHABLE();
5438 }
5439}
5440
5441HRESULT STDMETHODCALLTYPE WinRTGuidGenerator::MetaDataLocator::Locate(PCWSTR nameElement, IRoSimpleMetaDataBuilder &metaDataDestination) const
5442{
5443 CONTRACTL
5444 {
5445 THROWS;
5446 GC_TRIGGERS;
5447 MODE_ANY;
5448 PRECONDITION(CheckPointer(nameElement));
5449 }
5450 CONTRACTL_END;
5451
5452 // All names that we feed to RoGetParameterizedTypeInstanceIID begin with 'T'
5453 // which is followed by the MethodTable address printed as a pointer (in hex).
5454 MethodTable *pMT;
5455 if (swscanf_s(nameElement, W("T%p"), (LPVOID *)&pMT) != 1)
5456 {
5457 // Except that it could be a field from a redirected structure
5458 if (wcscmp(nameElement, W("Windows.Foundation.TimeSpan")) == 0)
5459 {
5460 LPCWSTR pwszFields[] = { W("Int64") };
5461 return metaDataDestination.SetStruct(nameElement, COUNTOF(pwszFields), pwszFields);
5462 }
5463 else if (wcscmp(nameElement, W("Windows.UI.Xaml.DurationType")) == 0)
5464 {
5465 return metaDataDestination.SetEnum(nameElement, W("Int32"));
5466 }
5467 else if (wcscmp(nameElement, W("Windows.UI.Xaml.GridUnitType")) == 0)
5468 {
5469 return metaDataDestination.SetEnum(nameElement, W("Int32"));
5470 }
5471 else if (wcscmp(nameElement, W("Windows.UI.Xaml.Interop.TypeKind")) == 0)
5472 {
5473 return metaDataDestination.SetEnum(nameElement, W("Int32"));
5474 }
5475 else if (wcscmp(nameElement, W("Windows.UI.Xaml.Media.Animation.RepeatBehaviorType")) == 0)
5476 {
5477 return metaDataDestination.SetEnum(nameElement, W("Int32"));
5478 }
5479 else if (wcscmp(nameElement, W("Windows.Foundation.Numerics.Vector3")) == 0)
5480 {
5481 LPCWSTR pwszFields[] = { W("Single"), W("Single"), W("Single") };
5482 return metaDataDestination.SetStruct(nameElement, COUNTOF(pwszFields), pwszFields);
5483 }
5484
5485 return E_FAIL;
5486 }
5487
5488 // do a check for a redirected type first
5489 HRESULT hr = LocateRedirectedType(pMT, metaDataDestination);
5490 if (hr == S_OK || FAILED(hr))
5491 {
5492 // already handled by LocateRedirectedType
5493 return hr;
5494 }
5495
5496 GUID iid;
5497 DefineFullyQualifiedNameForClassW();
5498
5499 if (pMT->IsValueType())
5500 {
5501 if (pMT->IsEnum())
5502 {
5503 // enum
5504 StackSString ssBaseType;
5505 VERIFY(WinRTTypeNameConverter::AppendWinRTNameForPrimitiveType(MscorlibBinder::GetElementType(pMT->GetInternalCorElementType()), ssBaseType));
5506
5507 return metaDataDestination.SetEnum(
5508 GetFullyQualifiedNameForClassW_WinRT(pMT),
5509 ssBaseType.GetUnicode());
5510 }
5511 else
5512 {
5513 // struct
5514 return LocateStructure(
5515 pMT,
5516 GetFullyQualifiedNameForClassW_WinRT(pMT),
5517 metaDataDestination);
5518 }
5519 }
5520 else
5521 {
5522 if (pMT->IsInterface())
5523 {
5524 pMT->GetGuid(&iid, FALSE);
5525 if (pMT->HasInstantiation())
5526 {
5527 // generic interface
5528 return metaDataDestination.SetParameterizedInterface(
5529 iid,
5530 pMT->GetNumGenericArgs());
5531 }
5532 else
5533 {
5534 // non-generic interface
5535 return metaDataDestination.SetWinRtInterface(iid);
5536 }
5537 }
5538 else
5539 {
5540 if (pMT->IsDelegate())
5541 {
5542 pMT->GetGuid(&iid, FALSE);
5543 if (pMT->HasInstantiation())
5544 {
5545 // generic delegate
5546 return metaDataDestination.SetParameterizedDelegate(
5547 iid,
5548 pMT->GetNumGenericArgs());
5549 }
5550 else
5551 {
5552 // non-generic delegate
5553 return metaDataDestination.SetDelegate(iid);
5554 }
5555 }
5556 else
5557 {
5558 // runtime class
5559 return LocateTypeWithDefaultInterface(
5560 pMT,
5561 GetFullyQualifiedNameForClassW_WinRT(pMT),
5562 metaDataDestination);
5563 }
5564 }
5565 }
5566}
5567
5568
5569void WinRTGuidGenerator::PopulateNames(MethodTable *pMT, SArray<BYTE> &namesBuf, PCWSTR* &pszNames, COUNT_T &cNames)
5570{
5571 CONTRACTL
5572 {
5573 THROWS;
5574 GC_TRIGGERS;
5575 MODE_ANY;
5576 PRECONDITION(CheckPointer(pMT));
5577 }
5578 CONTRACTL_END;
5579
5580 cNames = 0;
5581
5582 // Fill namesBuf with a pile of strings.
5583 PopulateNamesAppendTypeName(pMT, namesBuf, cNames);
5584 PopulateNamesAppendNamePointers(pMT, namesBuf, pszNames, cNames);
5585}
5586
5587void WinRTGuidGenerator::PopulateNamesAppendNamePointers(MethodTable *pMT, SArray<BYTE> &namesBuf, PCWSTR* &pszNames, COUNT_T cNames)
5588{
5589 CONTRACTL
5590 {
5591 THROWS;
5592 GC_TRIGGERS;
5593 MODE_ANY;
5594 PRECONDITION(CheckPointer(pMT));
5595 }
5596 CONTRACTL_END;
5597
5598 // Get pointers to internal strings
5599 COUNT_T cbNamesOld = (COUNT_T)ALIGN_UP(namesBuf.GetCount(), sizeof(PWSTR)); // End of strings is not necessarily pointer aligned, align so that the follow on pointers are aligned.
5600 COUNT_T cbNamePointers = cNames * sizeof(PWSTR); // How much space do we need for the pointers to the names?
5601 COUNT_T cbNamesNew = cbNamesOld + cbNamePointers; // Total space.
5602
5603 BYTE *pBuffer = namesBuf.OpenRawBuffer(cbNamesNew);
5604
5605 // Scan through strings, and build list of pointers to them. This assumes that the strings are seperated by a single null character
5606 PWSTR pszName = (PWSTR)pBuffer;
5607 pszNames = (PCWSTR*)(pBuffer + cbNamesOld);
5608 for (COUNT_T i = 0; i < cNames; i++)
5609 {
5610 pszNames[i] = pszName;
5611 pszName += wcslen(pszName) + 1;
5612 }
5613
5614 namesBuf.CloseRawBuffer(cbNamesNew);
5615}
5616
5617void WinRTGuidGenerator::PopulateNamesAppendTypeName(MethodTable *pMT, SArray<BYTE> &namesBuf, COUNT_T &cNames)
5618{
5619 CONTRACTL
5620 {
5621 THROWS;
5622 GC_TRIGGERS;
5623 MODE_ANY;
5624 PRECONDITION(CheckPointer(pMT));
5625 }
5626 CONTRACTL_END;
5627
5628 SmallStackSString name;
5629
5630#ifdef _DEBUG
5631 pMT->CheckLoadLevel(CLASS_LOAD_EXACTPARENTS);
5632#endif // _DEBUG
5633
5634 if (!WinRTTypeNameConverter::AppendWinRTNameForPrimitiveType(pMT, name))
5635 {
5636 if (pMT->HasInstantiation())
5637 {
5638 // get the typical instantiation
5639 TypeHandle typicalInst = ClassLoader::LoadTypeDefThrowing(pMT->GetModule(),
5640 pMT->GetCl(),
5641 ClassLoader::ThrowIfNotFound,
5642 ClassLoader::PermitUninstDefOrRef
5643 , tdNoTypes
5644 , CLASS_LOAD_EXACTPARENTS
5645 );
5646
5647 name.Printf(W("T%p"), typicalInst.AsPtr());
5648 }
5649 else
5650 {
5651 name.Printf(W("T%p"), (void *)pMT);
5652 }
5653 }
5654
5655 COUNT_T cbNamesOld = namesBuf.GetCount();
5656 COUNT_T cbNewName = (COUNT_T)(name.GetCount() + 1) * 2;
5657 COUNT_T cbNamesNew = cbNamesOld + cbNewName;
5658 memcpy(namesBuf.OpenRawBuffer(cbNamesNew) + cbNamesOld, name.GetUnicode(), cbNewName);
5659 namesBuf.CloseRawBuffer(cbNamesNew);
5660 cNames++;
5661
5662 if (pMT->HasInstantiation())
5663 {
5664 Instantiation inst = pMT->GetInstantiation();
5665 for (DWORD i = 0; i < inst.GetNumArgs(); i++)
5666 {
5667 PopulateNamesAppendTypeName(inst[i].GetMethodTable(), namesBuf, cNames);
5668 }
5669 }
5670}
5671
5672// We need to be able to compute IIDs of generic interfaces for WinRT interop even on Win7 when we NGEN.
5673// Otherwise Framework assemblies that contain projected WinRT types would end up with different native
5674// images depending on the OS they were compiled on.
5675namespace ParamInstanceAPI_StaticallyLinked
5676{
5677 // make sure that paraminstanceapi.h can be dropped in without extensive modifications
5678 namespace std
5679 {
5680 static const NoThrow nothrow = ::nothrow;
5681 }
5682
5683#pragma warning(push)
5684#pragma warning (disable: 4640)
5685 #include "paraminstanceapi.h"
5686#pragma warning(pop)
5687}
5688
5689// Although the IRoMetaDataLocator and IRoSimpleMetaDataBuilder interfaces may currently be structurally
5690// equivalent, use proper wrappers instead of dirty casts. This will trigger compile errors if the two
5691// implementations diverge from each other in the future.
5692class MetaDataLocatorWrapper : public ParamInstanceAPI_StaticallyLinked::IRoMetaDataLocator
5693{
5694 class SimpleMetaDataBuilderWrapper : public ::IRoSimpleMetaDataBuilder
5695 {
5696 ParamInstanceAPI_StaticallyLinked::IRoSimpleMetaDataBuilder &m_destination;
5697
5698 public:
5699 SimpleMetaDataBuilderWrapper(ParamInstanceAPI_StaticallyLinked::IRoSimpleMetaDataBuilder &destination)
5700 : m_destination(destination)
5701 { }
5702
5703 STDMETHOD(SetWinRtInterface)(GUID iid)
5704 { WRAPPER_NO_CONTRACT; return m_destination.SetWinRtInterface(iid); }
5705
5706 STDMETHOD(SetDelegate)(GUID iid)
5707 { WRAPPER_NO_CONTRACT; return m_destination.SetDelegate(iid); }
5708
5709 STDMETHOD(SetInterfaceGroupSimpleDefault)(PCWSTR name, PCWSTR defaultInterfaceName, const GUID *defaultInterfaceIID)
5710 { WRAPPER_NO_CONTRACT; return m_destination.SetInterfaceGroupSimpleDefault(name, defaultInterfaceName, defaultInterfaceIID); }
5711
5712 STDMETHOD(SetInterfaceGroupParameterizedDefault)(PCWSTR name, UINT32 elementCount, PCWSTR *defaultInterfaceNameElements)
5713 { WRAPPER_NO_CONTRACT; return m_destination.SetInterfaceGroupParameterizedDefault(name, elementCount, defaultInterfaceNameElements); }
5714
5715 STDMETHOD(SetRuntimeClassSimpleDefault)(PCWSTR name, PCWSTR defaultInterfaceName, const GUID *defaultInterfaceIID)
5716 { WRAPPER_NO_CONTRACT; return m_destination.SetRuntimeClassSimpleDefault(name, defaultInterfaceName, defaultInterfaceIID); }
5717
5718 STDMETHOD(SetRuntimeClassParameterizedDefault)(PCWSTR name, UINT32 elementCount, const PCWSTR *defaultInterfaceNameElements)
5719 { WRAPPER_NO_CONTRACT; return m_destination.SetRuntimeClassParameterizedDefault(name, elementCount, const_cast<PCWSTR *>(defaultInterfaceNameElements)); }
5720
5721 STDMETHOD(SetStruct)(PCWSTR name, UINT32 numFields, const PCWSTR *fieldTypeNames)
5722 { WRAPPER_NO_CONTRACT; return m_destination.SetStruct(name, numFields, const_cast<PCWSTR *>(fieldTypeNames)); }
5723
5724 STDMETHOD(SetEnum)(PCWSTR name, PCWSTR baseType)
5725 { WRAPPER_NO_CONTRACT; return m_destination.SetEnum(name, baseType); }
5726
5727 STDMETHOD(SetParameterizedInterface)(GUID piid, UINT32 numArgs)
5728 { WRAPPER_NO_CONTRACT; return m_destination.SetParameterizedInterface(piid, numArgs); }
5729
5730 STDMETHOD(SetParameterizedDelegate)(GUID piid, UINT32 numArgs)
5731 { WRAPPER_NO_CONTRACT; return m_destination.SetParameterizedDelegate(piid, numArgs); }
5732 };
5733
5734 ::IRoMetaDataLocator &m_locator;
5735
5736public:
5737 MetaDataLocatorWrapper(::IRoMetaDataLocator &locator)
5738 : m_locator(locator)
5739 { }
5740
5741 STDMETHOD(Locate)(PCWSTR nameElement, ParamInstanceAPI_StaticallyLinked::IRoSimpleMetaDataBuilder &destination) const
5742 {
5743 CONTRACTL
5744 {
5745 THROWS;
5746 GC_TRIGGERS;
5747 MODE_ANY;
5748 }
5749 CONTRACTL_END;
5750
5751 SimpleMetaDataBuilderWrapper destinationWrapper(destination);
5752 return m_locator.Locate(nameElement, destinationWrapper);
5753 }
5754};
5755
5756
5757//--------------------------------------------------------------------------
5758// pGuid is filled with the constructed IID by the function.
5759// static
5760void WinRTGuidGenerator::ComputeGuidForGenericType(MethodTable *pMT, GUID *pGuid)
5761{
5762 CONTRACTL
5763 {
5764 THROWS;
5765 GC_TRIGGERS;
5766 MODE_ANY;
5767 PRECONDITION(pMT->SupportsGenericInterop(TypeHandle::Interop_NativeToManaged));
5768 }
5769 CONTRACTL_END;
5770
5771 // throw a nice exception if the instantiation is not WinRT-legal
5772 if (!pMT->IsLegalNonArrayWinRTType())
5773 {
5774 StackSString ss;
5775 TypeString::AppendType(ss, TypeHandle(pMT));
5776 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, IDS_EE_WINRT_IID_ILLEGALTYPE, ss.GetUnicode());
5777 }
5778
5779 // create an array of name elements describing the type
5780 SArray<BYTE> namesBuf;
5781 PCWSTR *pNamePointers;
5782 COUNT_T cNames;
5783 PopulateNames(pMT, namesBuf, pNamePointers, cNames);
5784
5785 // pass the array to the REX API
5786 MetaDataLocator metadataLocator;
5787#ifndef CROSSGEN_COMPILE
5788 if (WinRTSupported())
5789 {
5790 IfFailThrow(RoGetParameterizedTypeInstanceIID(
5791 cNames,
5792 pNamePointers,
5793 metadataLocator,
5794 pGuid,
5795 NULL));
5796
5797#ifdef _DEBUG
5798 // assert that the two implementations computed the same Guid
5799 GUID pGuidForAssert;
5800
5801 MetaDataLocatorWrapper metadataLocatorWrapper(metadataLocator);
5802 IfFailThrow(ParamInstanceAPI_StaticallyLinked::RoGetParameterizedTypeInstanceIID(
5803 cNames,
5804 pNamePointers,
5805 metadataLocatorWrapper,
5806 &pGuidForAssert,
5807 NULL));
5808
5809 _ASSERTE_MSG(*pGuid == pGuidForAssert, "Guid computed by Win8 API does not match the one computed by statically linked RoGetParameterizedTypeInstanceIID");
5810#endif // _DEBUG
5811 }
5812 else
5813#endif //#ifndef CROSSGEN_COMPILE
5814 {
5815 // we should not be calling this on downlevel outside of NGEN
5816 _ASSERTE(GetAppDomain()->IsCompilationDomain());
5817
5818 MetaDataLocatorWrapper metadataLocatorWrapper(metadataLocator);
5819 IfFailThrow(ParamInstanceAPI_StaticallyLinked::RoGetParameterizedTypeInstanceIID(
5820 cNames,
5821 pNamePointers,
5822 metadataLocatorWrapper,
5823 pGuid,
5824 NULL));
5825 }
5826}
5827
5828// Returns MethodTable (typical instantiation) of the mscorlib copy of the specified redirected WinRT interface.
5829MethodTable *WinRTInterfaceRedirector::GetWinRTTypeForRedirectedInterfaceIndex(WinMDAdapter::RedirectedTypeIndex index)
5830{
5831 CONTRACT(MethodTable *)
5832 {
5833 THROWS;
5834 GC_TRIGGERS;
5835 MODE_ANY;
5836 POSTCONDITION(CheckPointer(RETVAL));
5837 }
5838 CONTRACT_END;
5839
5840 BinderClassID id = s_rInterfaceStubInfos[GetStubInfoIndex(index)].m_WinRTInterface;
5841
5842 if ((id & NON_MSCORLIB_MARKER) == 0)
5843 {
5844 // the redirected interface lives in mscorlib
5845 RETURN MscorlibBinder::GetClass(id);
5846 }
5847 else
5848 {
5849 // the redirected interface lives in some other Framework assembly
5850 const NonMscorlibRedirectedInterfaceInfo *pInfo = &s_rNonMscorlibInterfaceInfos[id & ~NON_MSCORLIB_MARKER];
5851 SString assemblyQualifiedTypeName(SString::Utf8, pInfo->m_szWinRTInterfaceAssemblyQualifiedTypeName);
5852
5853 RETURN TypeName::GetTypeFromAsmQualifiedName(assemblyQualifiedTypeName.GetUnicode()).GetMethodTable();
5854 }
5855}
5856
5857//
5858MethodDesc *WinRTInterfaceRedirector::LoadMethodFromRedirectedAssembly(LPCUTF8 szAssemblyQualifiedTypeName, LPCUTF8 szMethodName)
5859{
5860 CONTRACTL
5861 {
5862 THROWS;
5863 GC_TRIGGERS;
5864 MODE_ANY;
5865 }
5866 CONTRACTL_END;
5867
5868 SString assemblyQualifiedTypeName(SString::Utf8, szAssemblyQualifiedTypeName);
5869
5870 MethodTable *pMT = TypeName::GetTypeFromAsmQualifiedName(assemblyQualifiedTypeName.GetUnicode()).GetMethodTable();
5871 return MemberLoader::FindMethodByName(pMT, szMethodName);
5872}
5873
5874#ifdef _DEBUG
5875void WinRTInterfaceRedirector::VerifyRedirectedInterfaceStubs()
5876{
5877 CONTRACTL
5878 {
5879 THROWS;
5880 GC_TRIGGERS;
5881 MODE_ANY;
5882 }
5883 CONTRACTL_END;
5884
5885 // Verify signatures of all stub methods by calling GetStubMethodForRedirectedInterface with all valid
5886 // combination of arguments.
5887 for (int i = 0; i < WinMDAdapter::RedirectedTypeIndex_Count; i++)
5888 {
5889 if (i == WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_IEnumerable ||
5890 i == WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_IList ||
5891 i == WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_IDictionary ||
5892 i == WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_IReadOnlyList ||
5893 i == WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_IReadOnlyDictionary ||
5894 i == WinMDAdapter::RedirectedTypeIndex_System_IDisposable)
5895 {
5896 int stubInfoIndex = GetStubInfoIndex((WinMDAdapter::RedirectedTypeIndex)i);
5897
5898 // WinRT -> CLR
5899 for (int slot = 0; slot < s_rInterfaceStubInfos[stubInfoIndex].m_iCLRMethodCount; slot++)
5900 {
5901 GetStubMethodForRedirectedInterface((WinMDAdapter::RedirectedTypeIndex)i, slot, TypeHandle::Interop_ManagedToNative, FALSE);
5902 }
5903 if (i == WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_IList ||
5904 i == WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_IDictionary)
5905 {
5906 // WinRT -> CLR ICollection
5907 for (int slot = 0; slot < s_rInterfaceStubInfos[stubInfoIndex + s_NumRedirectedInterfaces].m_iCLRMethodCount; slot++)
5908 {
5909 GetStubMethodForRedirectedInterface((WinMDAdapter::RedirectedTypeIndex)i, slot, TypeHandle::Interop_ManagedToNative, TRUE);
5910 }
5911 }
5912
5913 // CLR -> WinRT
5914 for (int slot = 0; slot < s_rInterfaceStubInfos[stubInfoIndex].m_iWinRTMethodCount; slot++)
5915 {
5916 GetStubMethodForRedirectedInterface((WinMDAdapter::RedirectedTypeIndex)i, slot, TypeHandle::Interop_NativeToManaged, FALSE);
5917 }
5918 }
5919 }
5920}
5921#endif // _DEBUG
5922
5923// Returns a MethodDesc to be used as an interop stub for the given redirected interface/slot/direction.
5924MethodDesc *WinRTInterfaceRedirector::GetStubMethodForRedirectedInterface(WinMDAdapter::RedirectedTypeIndex interfaceIndex,
5925 int slot,
5926 TypeHandle::InteropKind interopKind,
5927 BOOL fICollectionStub,
5928 Instantiation methodInst /*= Instantiation()*/)
5929{
5930 CONTRACTL
5931 {
5932 THROWS;
5933 GC_TRIGGERS;
5934 MODE_ANY;
5935 PRECONDITION(!(fICollectionStub && interopKind == TypeHandle::Interop_NativeToManaged));
5936 }
5937 CONTRACTL_END;
5938
5939 int stubInfoIndex = GetStubInfoIndex(interfaceIndex);
5940 _ASSERTE(stubInfoIndex < s_NumRedirectedInterfaces);
5941 _ASSERTE(stubInfoIndex < _countof(s_rInterfaceStubInfos));
5942
5943 const RedirectedInterfaceStubInfo *pStubInfo;
5944 pStubInfo = &s_rInterfaceStubInfos[fICollectionStub ? stubInfoIndex + s_NumRedirectedInterfaces : stubInfoIndex];
5945
5946 BinderMethodID method;
5947 if (interopKind == TypeHandle::Interop_NativeToManaged)
5948 {
5949 _ASSERTE(slot < pStubInfo->m_iWinRTMethodCount);
5950 method = pStubInfo->m_rWinRTStubMethods[slot];
5951 }
5952 else
5953 {
5954 _ASSERTE(slot < pStubInfo->m_iCLRMethodCount);
5955 method = pStubInfo->m_rCLRStubMethods[slot];
5956 }
5957
5958 MethodDesc *pMD;
5959 if ((pStubInfo->m_WinRTInterface & NON_MSCORLIB_MARKER) == 0)
5960 {
5961 if (!methodInst.IsEmpty() &&
5962 (method == METHOD__ITERABLE_TO_ENUMERABLE_ADAPTER__GET_ENUMERATOR_STUB ||
5963 method == METHOD__IVECTORVIEW_TO_IREADONLYLIST_ADAPTER__INDEXER_GET))
5964 {
5965 if (GetStructureBaseType(methodInst) != BaseType_None)
5966 {
5967 // This instantiation has ambiguous run-time behavior because it can be assigned by co-variance
5968 // from another instantiation in which the type argument is not an interface pointer in the WinRT
5969 // world. We have to use a special stub for these which performs a run-time check to see how to
5970 // marshal the argument.
5971
5972 method = (method == METHOD__ITERABLE_TO_ENUMERABLE_ADAPTER__GET_ENUMERATOR_STUB) ?
5973 METHOD__ITERABLE_TO_ENUMERABLE_ADAPTER__GET_ENUMERATOR_VARIANCE_STUB :
5974 METHOD__IVECTORVIEW_TO_IREADONLYLIST_ADAPTER__INDEXER_GET_VARIANCE;
5975 }
5976 }
5977
5978 pMD = MscorlibBinder::GetMethod(method);
5979 }
5980 else
5981 {
5982 // the stub method does not live in mscorlib
5983 const NonMscorlibRedirectedInterfaceInfo *pInfo = &s_rNonMscorlibInterfaceInfos[pStubInfo->m_WinRTInterface & ~NON_MSCORLIB_MARKER];
5984
5985 pMD = LoadMethodFromRedirectedAssembly(
5986 (interopKind == TypeHandle::Interop_NativeToManaged) ? pInfo->m_szWinRTStubClassAssemblyQualifiedTypeName : pInfo->m_szCLRStubClassAssemblyQualifiedTypeName,
5987 pInfo->m_rszMethodNames[method]);
5988 }
5989
5990#ifdef _DEBUG
5991 // Verify that the signature of the stub method matches the corresponding interface method.
5992 MethodTable *pItfMT = NULL;
5993 Instantiation inst = pMD->GetMethodInstantiation();
5994
5995 if (interopKind == TypeHandle::Interop_NativeToManaged)
5996 {
5997 // we are interested in the WinRT interface method
5998 pItfMT = GetWinRTTypeForRedirectedInterfaceIndex(interfaceIndex);
5999 }
6000 else
6001 {
6002 // we are interested in the CLR interface method
6003 if (fICollectionStub)
6004 {
6005 if (pMD->HasMethodInstantiation())
6006 {
6007 if (interfaceIndex == WinMDAdapter::RedirectedTypeIndex_Windows_Foundation_Collections_IVectorView ||
6008 interfaceIndex == WinMDAdapter::RedirectedTypeIndex_Windows_Foundation_Collections_IMapView)
6009 pItfMT = MscorlibBinder::GetExistingClass(CLASS__IREADONLYCOLLECTIONGENERIC);
6010 else
6011 pItfMT = MscorlibBinder::GetExistingClass(CLASS__ICOLLECTIONGENERIC);
6012
6013 if (interfaceIndex == WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_IDictionary ||
6014 interfaceIndex == WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_IReadOnlyDictionary)
6015 {
6016 TypeHandle thKvPair = TypeHandle(MscorlibBinder::GetClass(CLASS__KEYVALUEPAIRGENERIC)).Instantiate(inst);
6017 inst = Instantiation(&thKvPair, 1);
6018 }
6019 }
6020 else
6021 {
6022 pItfMT = MscorlibBinder::GetExistingClass(CLASS__ICOLLECTION);
6023 }
6024 }
6025 else
6026 {
6027 pItfMT = GetAppDomain()->GetRedirectedType(interfaceIndex);
6028 }
6029 }
6030
6031 // get signature of the stub method
6032 PCCOR_SIGNATURE pSig1;
6033 DWORD cSig1;
6034
6035 pMD->GetSig(&pSig1, &cSig1);
6036 SigTypeContext typeContext1;
6037 SigTypeContext::InitTypeContext(Instantiation(), pMD->GetMethodInstantiation(), &typeContext1);
6038 MetaSig sig1(pSig1, cSig1, pMD->GetModule(), &typeContext1);
6039
6040 // get signature of the interface method
6041 PCCOR_SIGNATURE pSig2;
6042 DWORD cSig2;
6043
6044 MethodDesc *pItfMD = pItfMT->GetMethodDescForSlot(slot);
6045 pItfMD->GetSig(&pSig2, &cSig2);
6046 SigTypeContext typeContext2;
6047 SigTypeContext::InitTypeContext(inst, Instantiation(), &typeContext2);
6048 MetaSig sig2(pSig2, cSig2, pItfMD->GetModule(), &typeContext2);
6049
6050 _ASSERTE_MSG(MetaSig::CompareMethodSigs(sig1, sig2, FALSE), "Stub method signature does not match the corresponding interface method.");
6051#endif // _DEBUG
6052
6053 if (!methodInst.IsEmpty())
6054 {
6055 _ASSERTE(pMD->HasMethodInstantiation());
6056 _ASSERTE(pMD->GetNumGenericMethodArgs() == methodInst.GetNumArgs());
6057
6058 pMD = MethodDesc::FindOrCreateAssociatedMethodDesc(
6059 pMD,
6060 pMD->GetMethodTable(),
6061 FALSE, // forceBoxedEntryPoint
6062 methodInst, // methodInst
6063 FALSE, // allowInstParam
6064 TRUE); // forceRemotableMethod
6065 }
6066
6067 return pMD;
6068}
6069
6070// static
6071MethodDesc *WinRTInterfaceRedirector::GetStubMethodForRedirectedInterfaceMethod(MethodDesc *pMD, TypeHandle::InteropKind interopKind)
6072{
6073 CONTRACTL
6074 {
6075 THROWS;
6076 GC_TRIGGERS;
6077 MODE_ANY;
6078 }
6079 CONTRACTL_END;
6080
6081 MethodTable *pMT = pMD->GetMethodTable();
6082
6083 //
6084 // If we are calling into a class method instead of interface method,
6085 // convert it to first implemented interface method (we are always calling into the first
6086 // one - see code:ComPlusCall::PopulateComPlusCallMethodDesc for more details)
6087 //
6088 if (!pMT->IsInterface())
6089 {
6090 pMD = pMD->GetInterfaceMD();
6091 pMT = pMD->GetMethodTable();
6092 }
6093
6094 bool fICollectionStub = false;
6095 if (interopKind == TypeHandle::Interop_ManagedToNative)
6096 {
6097 MethodTable *pResolvedMT = RCW::ResolveICollectionInterface(pMT, TRUE /* fPreferIDictionary */, NULL);
6098 if (pResolvedMT != NULL)
6099 {
6100 fICollectionStub = true;
6101 pMT = pResolvedMT;
6102 }
6103 }
6104
6105 WinMDAdapter::RedirectedTypeIndex index;
6106 if (WinRTInterfaceRedirector::ResolveRedirectedInterface(pMT, &index))
6107 {
6108 // make sure we return an exact MD that takes no extra instantiating arguments
6109 return WinRTInterfaceRedirector::GetStubMethodForRedirectedInterface(
6110 index,
6111 pMD->GetSlot(),
6112 interopKind,
6113 fICollectionStub,
6114 pMT->GetInstantiation());
6115 }
6116
6117 return NULL;
6118}
6119
6120// static
6121MethodTable *WinRTDelegateRedirector::GetWinRTTypeForRedirectedDelegateIndex(WinMDAdapter::RedirectedTypeIndex index)
6122{
6123 CONTRACTL
6124 {
6125 THROWS;
6126 GC_TRIGGERS;
6127 MODE_ANY;
6128 }
6129 CONTRACTL_END;
6130
6131 switch (index)
6132 {
6133 case WinMDAdapter::RedirectedTypeIndex_System_EventHandlerGeneric:
6134 return MscorlibBinder::GetClass(CLASS__WINDOWS_FOUNDATION_EVENTHANDLER);
6135
6136 case WinMDAdapter::RedirectedTypeIndex_System_Collections_Specialized_NotifyCollectionChangedEventHandler:
6137 {
6138 SString assemblyQualifiedTypeName(SString::Utf8, NCCEHWINRT_ASM_QUAL_TYPE_NAME);
6139 return TypeName::GetTypeFromAsmQualifiedName(assemblyQualifiedTypeName.GetUnicode()).GetMethodTable();
6140 }
6141
6142 case WinMDAdapter::RedirectedTypeIndex_System_ComponentModel_PropertyChangedEventHandler:
6143 {
6144 SString assemblyQualifiedTypeName(SString::Utf8, PCEHWINRT_ASM_QUAL_TYPE_NAME);
6145 return TypeName::GetTypeFromAsmQualifiedName(assemblyQualifiedTypeName.GetUnicode()).GetMethodTable();
6146 }
6147
6148 default:
6149 UNREACHABLE();
6150 }
6151}
6152
6153#ifndef CROSSGEN_COMPILE
6154
6155#ifdef _DEBUG
6156//-------------------------------------------------------------------
6157// LOGGING APIS
6158//-------------------------------------------------------------------
6159
6160static int g_TraceCount = 0;
6161static IUnknown* g_pTraceIUnknown = 0;
6162
6163VOID IntializeInteropLogging()
6164{
6165 WRAPPER_NO_CONTRACT;
6166
6167 g_pTraceIUnknown = g_pConfig->GetTraceIUnknown();
6168 g_TraceCount = g_pConfig->GetTraceWrapper();
6169}
6170
6171VOID LogInterop(__in_z LPCSTR szMsg)
6172{
6173 LIMITED_METHOD_CONTRACT;
6174 LOG( (LF_INTEROP, LL_INFO10, "%s\n",szMsg) );
6175}
6176
6177VOID LogInterop(__in_z LPCWSTR wszMsg)
6178{
6179 LIMITED_METHOD_CONTRACT;
6180 LOG( (LF_INTEROP, LL_INFO10, "%S\n", wszMsg) );
6181}
6182
6183//-------------------------------------------------------------------
6184// VOID LogRCWCreate(RCW* pWrap, IUnknown* pUnk)
6185// log wrapper create
6186//-------------------------------------------------------------------
6187VOID LogRCWCreate(RCW* pWrap, IUnknown* pUnk)
6188{
6189 if (!LoggingOn(LF_INTEROP, LL_ALWAYS))
6190 return;
6191
6192 CONTRACTL
6193 {
6194 NOTHROW;
6195 GC_NOTRIGGER;
6196 MODE_ANY;
6197 }
6198 CONTRACTL_END;
6199
6200 static int count = 0;
6201 LPVOID pCurrCtx = GetCurrentCtxCookie();
6202
6203 // pre-increment the count, so it can never be zero
6204 count++;
6205
6206 if (count == g_TraceCount)
6207 {
6208 g_pTraceIUnknown = pUnk;
6209 }
6210
6211 if (g_pTraceIUnknown == 0 || g_pTraceIUnknown == pUnk)
6212 {
6213 LOG( (LF_INTEROP,
6214 LL_INFO10,
6215 "Create RCW: Wrapper %p #%d IUnknown:%p Context %p\n",
6216 pWrap, count,
6217 pUnk,
6218 pCurrCtx) );
6219 }
6220}
6221
6222//-------------------------------------------------------------------
6223// VOID LogRCWMinorCleanup(RCW* pWrap)
6224// log wrapper minor cleanup
6225//-------------------------------------------------------------------
6226VOID LogRCWMinorCleanup(RCW* pWrap)
6227{
6228 if (!LoggingOn(LF_INTEROP, LL_ALWAYS))
6229 return;
6230
6231 CONTRACTL
6232 {
6233 NOTHROW;
6234 GC_NOTRIGGER;
6235 MODE_ANY;
6236 PRECONDITION(CheckPointer(pWrap));
6237 }
6238 CONTRACTL_END;
6239
6240 static int dest_count = 0;
6241 dest_count++;
6242
6243 IUnknown *pUnk = pWrap->GetRawIUnknown_NoAddRef_NoThrow();
6244
6245 if (g_pTraceIUnknown == 0 || g_pTraceIUnknown == pUnk)
6246 {
6247 LPVOID pCurrCtx = GetCurrentCtxCookie();
6248 LOG( (LF_INTEROP,
6249 LL_INFO10,
6250 "Minor Cleanup RCW: Wrapper %p #%d IUnknown %p Context: %p\n",
6251 pWrap, dest_count,
6252 pUnk,
6253 pCurrCtx) );
6254 }
6255}
6256
6257//-------------------------------------------------------------------
6258// VOID LogRCWDestroy(RCW* pWrap, IUnknown* pUnk)
6259// log wrapper destroy
6260//-------------------------------------------------------------------
6261VOID LogRCWDestroy(RCW* pWrap)
6262{
6263 if (!LoggingOn(LF_INTEROP, LL_ALWAYS))
6264 return;
6265
6266 CONTRACTL
6267 {
6268 NOTHROW;
6269 GC_NOTRIGGER;
6270 MODE_ANY;
6271 PRECONDITION(CheckPointer(pWrap));
6272 }
6273 CONTRACTL_END;
6274
6275 static int dest_count = 0;
6276 dest_count++;
6277
6278 IUnknown *pUnk = pWrap->GetRawIUnknown_NoAddRef_NoThrow();
6279
6280 if (g_pTraceIUnknown == 0 || g_pTraceIUnknown == pUnk)
6281 {
6282 LPVOID pCurrCtx = GetCurrentCtxCookie();
6283 STRESS_LOG4(
6284 LF_INTEROP,
6285 LL_INFO10,
6286 "Destroy RCW: Wrapper %p #%d IUnknown %p Context: %p\n",
6287 pWrap, dest_count,
6288 pUnk,
6289 pCurrCtx);
6290 }
6291}
6292
6293//-------------------------------------------------------------------
6294// VOID LogInteropLeak(IUnkEntry * pEntry)
6295//-------------------------------------------------------------------
6296VOID LogInteropLeak(IUnkEntry * pEntry)
6297{
6298 if (!LoggingOn(LF_INTEROP, LL_ALWAYS))
6299 return;
6300
6301 CONTRACTL
6302 {
6303 NOTHROW;
6304 GC_NOTRIGGER;
6305 MODE_ANY;
6306 PRECONDITION(CheckPointer(pEntry));
6307 }
6308 CONTRACTL_END;
6309
6310 IUnknown *pUnk = pEntry->GetRawIUnknown_NoAddRef_NoThrow();
6311
6312 if (g_pTraceIUnknown == 0 || g_pTraceIUnknown == pUnk)
6313 {
6314 LOG( (LF_INTEROP,
6315 LL_INFO10,
6316 "IUnkEntry Leak: %p Context: %p\n",
6317 pUnk,
6318 pEntry->GetCtxCookie()) );
6319 }
6320}
6321
6322//-------------------------------------------------------------------
6323// VOID LogInteropLeak(IUnknown* pItf)
6324//-------------------------------------------------------------------
6325VOID LogInteropLeak(IUnknown* pItf)
6326{
6327 if (!LoggingOn(LF_INTEROP, LL_ALWAYS))
6328 return;
6329
6330 CONTRACTL
6331 {
6332 NOTHROW;
6333 GC_NOTRIGGER;
6334 MODE_ANY;
6335 }
6336 CONTRACTL_END;
6337
6338 LPVOID pCurrCtx = NULL;
6339
6340 if (g_pTraceIUnknown == 0 || g_pTraceIUnknown == pItf)
6341 {
6342 pCurrCtx = GetCurrentCtxCookie();
6343 LOG((LF_INTEROP,
6344 LL_EVERYTHING,
6345 "Leak: Itf = %p, CurrCtx = %p\n",
6346 pItf, pCurrCtx));
6347 }
6348}
6349
6350//-------------------------------------------------------------------
6351// VOID LogInteropQI(IUnknown* pItf, REFIID iid, HRESULT hr, LPCSTR szMsg)
6352//-------------------------------------------------------------------
6353VOID LogInteropQI(IUnknown* pItf, REFIID iid, HRESULT hrArg, __in_z LPCSTR szMsg)
6354{
6355 if (!LoggingOn(LF_INTEROP, LL_ALWAYS))
6356 return;
6357
6358 CONTRACTL
6359 {
6360 NOTHROW;
6361 GC_TRIGGERS;
6362 MODE_ANY;
6363 PRECONDITION(CheckPointer(pItf));
6364 }
6365 CONTRACTL_END;
6366
6367 LPVOID pCurrCtx = NULL;
6368 HRESULT hr = S_OK;
6369 SafeComHolder<IUnknown> pUnk = NULL;
6370 int cch = 0;
6371 WCHAR wszIID[64];
6372
6373 hr = SafeQueryInterface(pItf, IID_IUnknown, &pUnk);
6374
6375 if (g_pTraceIUnknown == 0 || g_pTraceIUnknown == pUnk)
6376 {
6377 pCurrCtx = GetCurrentCtxCookie();
6378
6379 cch = StringFromGUID2(iid, wszIID, sizeof(wszIID) / sizeof(WCHAR));
6380 _ASSERTE(cch > 0);
6381
6382 if (SUCCEEDED(hrArg))
6383 {
6384 LOG((LF_INTEROP,
6385 LL_EVERYTHING,
6386 "Succeeded QI: Unk = %p, Itf = %p, CurrCtx = %p, IID = %S, Msg: %s\n",
6387 (IUnknown*)pUnk, pItf, pCurrCtx, wszIID, szMsg));
6388 }
6389 else
6390 {
6391 LOG((LF_INTEROP,
6392 LL_EVERYTHING,
6393 "Failed QI: Unk = %p, Itf = %p, CurrCtx = %p, IID = %S, HR = %p, Msg: %s\n",
6394 (IUnknown*)pUnk, pItf, pCurrCtx, wszIID, hrArg, szMsg));
6395 }
6396 }
6397}
6398
6399//-------------------------------------------------------------------
6400// VOID LogInteropAddRef(IUnknown* pItf, ULONG cbRef, LPCSTR szMsg)
6401//-------------------------------------------------------------------
6402VOID LogInteropAddRef(IUnknown* pItf, ULONG cbRef, __in_z LPCSTR szMsg)
6403{
6404 if (!LoggingOn(LF_INTEROP, LL_ALWAYS))
6405 return;
6406
6407 CONTRACTL
6408 {
6409 NOTHROW;
6410 GC_TRIGGERS;
6411 MODE_ANY;
6412 PRECONDITION(CheckPointer(pItf));
6413 SO_TOLERANT;
6414 }
6415 CONTRACTL_END;
6416
6417 LPVOID pCurrCtx = NULL;
6418 HRESULT hr = S_OK;
6419 SafeComHolder<IUnknown> pUnk = NULL;
6420
6421 hr = SafeQueryInterface(pItf, IID_IUnknown, &pUnk);
6422
6423 if (g_pTraceIUnknown == 0 || g_pTraceIUnknown == pUnk)
6424 {
6425 pCurrCtx = GetCurrentCtxCookie();
6426 LOG((LF_INTEROP,
6427 LL_EVERYTHING,
6428 "AddRef: Unk = %p, Itf = %p, CurrCtx = %p, RefCount = %d, Msg: %s\n",
6429 (IUnknown*)pUnk, pItf, pCurrCtx, cbRef, szMsg));
6430 }
6431}
6432
6433//-------------------------------------------------------------------
6434// VOID LogInteropRelease(IUnknown* pItf, ULONG cbRef, LPCSTR szMsg)
6435//-------------------------------------------------------------------
6436VOID LogInteropRelease(IUnknown* pItf, ULONG cbRef, __in_z LPCSTR szMsg)
6437{
6438 if (!LoggingOn(LF_INTEROP, LL_ALWAYS))
6439 return;
6440
6441 CONTRACTL
6442 {
6443 NOTHROW;
6444 GC_NOTRIGGER;
6445 MODE_ANY;
6446 PRECONDITION(CheckPointer(pItf, NULL_OK));
6447 SO_TOLERANT;
6448 }
6449 CONTRACTL_END;
6450
6451 LPVOID pCurrCtx = NULL;
6452
6453 if (g_pTraceIUnknown == 0 || g_pTraceIUnknown == pItf)
6454 {
6455 pCurrCtx = GetCurrentCtxCookie();
6456 LOG((LF_INTEROP,
6457 LL_EVERYTHING,
6458 "Release: Itf = %p, CurrCtx = %p, RefCount = %d, Msg: %s\n",
6459 pItf, pCurrCtx, cbRef, szMsg));
6460 }
6461}
6462
6463#endif // _DEBUG
6464
6465IUnknown* MarshalObjectToInterface(OBJECTREF* ppObject, MethodTable* pItfMT, MethodTable* pClassMT, DWORD dwFlags)
6466{
6467 CONTRACTL
6468 {
6469 THROWS;
6470 MODE_COOPERATIVE;
6471 GC_TRIGGERS;
6472 }
6473 CONTRACTL_END;
6474
6475 // When an interface method table is specified, fDispIntf must be consistent with the
6476 // interface type.
6477 BOOL bDispatch = (dwFlags & ItfMarshalInfo::ITF_MARSHAL_DISP_ITF);
6478 BOOL bInspectable = (dwFlags & ItfMarshalInfo::ITF_MARSHAL_INSP_ITF);
6479 BOOL bUseBasicItf = (dwFlags & ItfMarshalInfo::ITF_MARSHAL_USE_BASIC_ITF);
6480
6481 _ASSERTE(!pItfMT || (!pItfMT->IsInterface() && bDispatch) ||
6482 (!!bDispatch == IsDispatchBasedItf(pItfMT->GetComInterfaceType())) ||
6483 (!!bInspectable == (pItfMT->GetComInterfaceType() == ifInspectable) || pItfMT->IsWinRTRedirectedInterface(TypeHandle::Interop_ManagedToNative)));
6484
6485 if (pItfMT)
6486 {
6487 return GetComIPFromObjectRef(ppObject, pItfMT);
6488 }
6489 else if (!bUseBasicItf)
6490 {
6491 return GetComIPFromObjectRef(ppObject, pClassMT);
6492 }
6493 else
6494 {
6495 ComIpType ReqIpType = bDispatch ? ComIpType_Dispatch : (bInspectable ? ComIpType_Inspectable : ComIpType_Unknown);
6496 return GetComIPFromObjectRef(ppObject, ReqIpType, NULL);
6497 }
6498}
6499
6500void UnmarshalObjectFromInterface(OBJECTREF *ppObjectDest, IUnknown **ppUnkSrc, MethodTable *pItfMT, MethodTable *pClassMT, DWORD dwFlags)
6501{
6502 CONTRACTL
6503 {
6504 THROWS;
6505 MODE_COOPERATIVE;
6506 GC_TRIGGERS;
6507 PRECONDITION(IsProtectedByGCFrame(ppObjectDest));
6508 }
6509 CONTRACTL_END;
6510
6511 _ASSERTE(!pClassMT || !pClassMT->IsInterface());
6512
6513 bool fIsInterface = (pItfMT != NULL && pItfMT->IsInterface());
6514
6515 DWORD dwObjFromComIPFlags = ObjFromComIP::FromItfMarshalInfoFlags(dwFlags);
6516 GetObjectRefFromComIP(
6517 ppObjectDest, // Object
6518 ppUnkSrc, // Interface pointer
6519 pClassMT, // Class type
6520 fIsInterface ? pItfMT : NULL, // Interface type - used to cache the incoming interface pointer
6521 dwObjFromComIPFlags // Flags
6522 );
6523
6524 // Make sure the interface is supported.
6525 _ASSERTE(!pItfMT || pItfMT->IsInterface() || pItfMT->GetComClassInterfaceType() != clsIfNone);
6526
6527 if (fIsInterface)
6528 {
6529 if ((dwFlags & ItfMarshalInfo::ITF_MARSHAL_WINRT_SCENARIO) == 0)
6530 {
6531 // We only verify that the object supports the interface for non-WinRT scenarios because we
6532 // believe that the likelihood of improperly constructed programs is significantly lower
6533 // with WinRT and the Object::SupportsInterface check is very expensive.
6534 if (!Object::SupportsInterface(*ppObjectDest, pItfMT))
6535 {
6536 COMPlusThrowInvalidCastException(ppObjectDest, TypeHandle(pItfMT));
6537 }
6538 }
6539 }
6540}
6541
6542#ifdef FEATURE_CLASSIC_COMINTEROP
6543
6544//--------------------------------------------------------------------------------
6545// Check if the pUnk implements IProvideClassInfo and try to figure
6546// out the class from there
6547MethodTable* GetClassFromIProvideClassInfo(IUnknown* pUnk)
6548{
6549 CONTRACT (MethodTable*)
6550 {
6551 THROWS;
6552 GC_TRIGGERS;
6553 MODE_ANY;
6554 PRECONDITION(CheckPointer(pUnk));
6555 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
6556 }
6557 CONTRACT_END;
6558
6559 MethodTable* pClassMT = NULL;
6560 SafeComHolder<ITypeInfo> pTypeInfo = NULL;
6561 SafeComHolder<IProvideClassInfo> pclsInfo = NULL;
6562
6563 // Use IProvideClassInfo to detect the appropriate class to use for wrapping
6564 HRESULT hr = SafeQueryInterface(pUnk, IID_IProvideClassInfo, (IUnknown **)&pclsInfo);
6565 LogInteropQI(pUnk, IID_IProvideClassInfo, hr, "GetClassFromIProvideClassInfo: QIing for IProvideClassinfo");
6566 if (hr == S_OK && pclsInfo)
6567 {
6568 hr = E_FAIL;
6569
6570 // Make sure the class info is not our own
6571 if (!IsSimpleTearOff(pclsInfo))
6572 {
6573 GCX_PREEMP();
6574
6575 hr = pclsInfo->GetClassInfo(&pTypeInfo);
6576 }
6577
6578 // If we succeded in retrieving the type information then keep going.
6579 TYPEATTRHolder ptattr(pTypeInfo);
6580 if (hr == S_OK && pTypeInfo)
6581 {
6582 {
6583 GCX_PREEMP();
6584 hr = pTypeInfo->GetTypeAttr(&ptattr);
6585 }
6586
6587 // If we succeeded in retrieving the attributes and they represent
6588 // a CoClass, then look up the class from the CLSID.
6589 if (hr == S_OK && ptattr->typekind == TKIND_COCLASS)
6590 {
6591 GCX_ASSERT_COOP();
6592 pClassMT = GetTypeForCLSID(ptattr->guid);
6593 }
6594 }
6595 }
6596
6597 RETURN pClassMT;
6598}
6599
6600#endif // FEATURE_CLASSIC_COMINTEROP
6601
6602
6603enum IInspectableQueryResults {
6604 IInspectableQueryResults_SupportsIReference = 0x1,
6605 IInspectableQueryResults_SupportsIReferenceArray = 0x2,
6606};
6607
6608//--------------------------------------------------------------------------------
6609// Try to get the class from IInspectable. If *pfSupportsIInspectable is true, pUnk
6610// is assumed to be an IInspectable-derived interface. Otherwise, this function will
6611// QI for IInspectable and set *pfSupportsIInspectable accordingly.
6612
6613TypeHandle GetClassFromIInspectable(IUnknown* pUnk, bool *pfSupportsIInspectable, bool *pfSupportsIReference, bool *pfSupportsIReferenceArray)
6614{
6615 CONTRACT (TypeHandle)
6616 {
6617 THROWS;
6618 GC_TRIGGERS;
6619 MODE_ANY;
6620 PRECONDITION(CheckPointer(pUnk));
6621 PRECONDITION(CheckPointer(pfSupportsIInspectable));
6622 PRECONDITION(CheckPointer(pfSupportsIReference));
6623 PRECONDITION(CheckPointer(pfSupportsIReferenceArray));
6624 }
6625 CONTRACT_END;
6626
6627 *pfSupportsIReference = false;
6628 *pfSupportsIReferenceArray = false;
6629
6630 HRESULT hr = S_OK;
6631
6632 SafeComHolder<IInspectable> pInsp = NULL;
6633 if (*pfSupportsIInspectable)
6634 {
6635 // we know that pUnk is an IInspectable
6636 pInsp = static_cast<IInspectable *>(pUnk);
6637 pInsp.SuppressRelease();
6638 }
6639 else
6640 {
6641 hr = SafeQueryInterface(pUnk, IID_IInspectable, (IUnknown **)&pInsp);
6642 LogInteropQI(pUnk, IID_IInspectable, hr, "GetClassFromIInspectable: QIing for IInspectable");
6643
6644 if (SUCCEEDED(hr))
6645 {
6646 *pfSupportsIInspectable = true;
6647 }
6648 else
6649 {
6650 RETURN TypeHandle();
6651 }
6652 }
6653
6654 WinRtString winrtClassName;
6655 {
6656 GCX_PREEMP();
6657 if (FAILED(pInsp->GetRuntimeClassName(winrtClassName.Address())))
6658 {
6659 RETURN TypeHandle();
6660 }
6661 }
6662
6663 // Early return if the class name is NULL
6664 if (winrtClassName == NULL)
6665 RETURN TypeHandle();
6666
6667 // we have a class name
6668 UINT32 cchClassName;
6669 LPCWSTR pwszClassName = winrtClassName.GetRawBuffer(&cchClassName);
6670 SString ssClassName(SString::Literal, pwszClassName, cchClassName);
6671
6672
6673 // Check a cache to see if this has already been looked up.
6674 AppDomain *pDomain = GetAppDomain();
6675 UINT vCacheVersion = 0;
6676 BYTE bFlags;
6677 TypeHandle classTypeHandle = pDomain->LookupTypeByName(ssClassName, &vCacheVersion, &bFlags);
6678
6679 if (!classTypeHandle.IsNull())
6680 {
6681 *pfSupportsIReference = ((bFlags & IInspectableQueryResults_SupportsIReference) != 0);
6682 *pfSupportsIReferenceArray = ((bFlags & IInspectableQueryResults_SupportsIReferenceArray) != 0);
6683 }
6684 else
6685 {
6686 // use a copy of the original class name in case we peel off IReference/IReferenceArray below
6687 StackSString ssTmpClassName;
6688
6689 // Check whether this is a value type, String, or T[] "boxed" in a IReference<T> or IReferenceArray<T>.
6690 if (ssClassName.BeginsWith(W("Windows.Foundation.IReference`1<")) && ssClassName.EndsWith(W(">")))
6691 {
6692 ssTmpClassName.Set(ssClassName);
6693 ssTmpClassName.Delete(ssTmpClassName.Begin(), _countof(W("Windows.Foundation.IReference`1<")) - 1);
6694 ssTmpClassName.Delete(ssTmpClassName.End() - 1, 1);
6695 *pfSupportsIReference = true;
6696 }
6697 else if (ssClassName.BeginsWith(W("Windows.Foundation.IReferenceArray`1<")) && ssClassName.EndsWith(W(">")))
6698 {
6699 ssTmpClassName.Set(ssClassName);
6700 ssTmpClassName.Delete(ssTmpClassName.Begin(), _countof(W("Windows.Foundation.IReferenceArray`1<")) - 1);
6701 ssTmpClassName.Delete(ssTmpClassName.End() - 1, 1);
6702 *pfSupportsIReferenceArray = true;
6703 }
6704
6705 EX_TRY
6706 {
6707 LPCWSTR pszWinRTTypeName = (ssTmpClassName.IsEmpty() ? ssClassName : ssTmpClassName);
6708 classTypeHandle = WinRTTypeNameConverter::GetManagedTypeFromWinRTTypeName(pszWinRTTypeName, /*pbIsPrimitive = */ NULL);
6709 }
6710 EX_CATCH
6711 {
6712 }
6713 EX_END_CATCH(RethrowTerminalExceptions)
6714
6715 if (!classTypeHandle.IsNull())
6716 {
6717 // cache the (positive) result
6718 BYTE bFlags = 0;
6719 if (*pfSupportsIReference)
6720 bFlags |= IInspectableQueryResults_SupportsIReference;
6721 if (*pfSupportsIReferenceArray)
6722 bFlags |= IInspectableQueryResults_SupportsIReferenceArray;
6723 pDomain->CacheTypeByName(ssClassName, vCacheVersion, classTypeHandle, bFlags);
6724 }
6725 }
6726
6727 RETURN classTypeHandle;
6728}
6729
6730
6731ABI::Windows::Foundation::IUriRuntimeClass *CreateWinRTUri(LPCWSTR wszUri, INT32 cchUri)
6732{
6733 STANDARD_VM_CONTRACT;
6734
6735 UriMarshalingInfo* marshalingInfo = GetAppDomain()->GetMarshalingData()->GetUriMarshalingInfo();
6736
6737 // Get the cached factory from the UriMarshalingInfo object of the current appdomain
6738 ABI::Windows::Foundation::IUriRuntimeClassFactory* pFactory = marshalingInfo->GetUriFactory();
6739
6740 SafeComHolder<ABI::Windows::Foundation::IUriRuntimeClass> pIUriRC;
6741 HRESULT hrCreate = pFactory->CreateUri(WinRtStringRef(wszUri, cchUri), &pIUriRC);
6742 if (FAILED(hrCreate))
6743 {
6744 if (hrCreate == E_INVALIDARG)
6745 {
6746 COMPlusThrow(kArgumentException, IDS_EE_INVALIDARG_WINRT_INVALIDURI);
6747 }
6748 else
6749 {
6750 ThrowHR(hrCreate);
6751 }
6752 }
6753
6754 return pIUriRC.Extract();
6755}
6756
6757static void DECLSPEC_NORETURN ThrowTypeLoadExceptionWithInner(MethodTable *pClassMT, LPCWSTR pwzName, HRESULT hr, unsigned resID)
6758{
6759 CONTRACTL
6760 {
6761 THROWS;
6762 DISABLED(GC_NOTRIGGER); // Must sanitize first pass handling to enable this
6763 MODE_ANY;
6764 }
6765 CONTRACTL_END;
6766
6767 StackSString simpleName(SString::Utf8, pClassMT->GetAssembly()->GetSimpleName());
6768
6769 EEMessageException ex(hr);
6770 EX_THROW_WITH_INNER(EETypeLoadException, (pwzName, simpleName.GetUnicode(), nullptr, resID), &ex);
6771}
6772
6773//
6774// Creates activation factory and wraps it with a RCW
6775//
6776void GetNativeWinRTFactoryObject(MethodTable *pMT, Thread *pThread, MethodTable *pFactoryIntfMT, BOOL bNeedUniqueRCW, ICOMInterfaceMarshalerCallback *pCallback, OBJECTREF *prefFactory)
6777{
6778 CONTRACTL
6779 {
6780 THROWS;
6781 MODE_COOPERATIVE;
6782 GC_TRIGGERS;
6783 PRECONDITION(CheckPointer(pMT));
6784 PRECONDITION(CheckPointer(pThread));
6785 PRECONDITION(CheckPointer(pFactoryIntfMT, NULL_OK));
6786 PRECONDITION(CheckPointer(pCallback, NULL_OK));
6787 }
6788 CONTRACTL_END;
6789
6790 if (!WinRTSupported())
6791 {
6792 COMPlusThrow(kPlatformNotSupportedException, W("PlatformNotSupported_WinRT"));
6793 }
6794
6795 HSTRING hName = GetComClassFactory(pMT)->AsWinRTClassFactory()->GetClassName();
6796
6797 HRESULT hr;
6798 SafeComHolder<IInspectable> pFactory;
6799 {
6800 GCX_PREEMP();
6801 hr = clr::winrt::GetActivationFactory<IInspectable>(hName, &pFactory);
6802 }
6803
6804 // There are a few particular failures that we'd like to map a specific exception type to
6805 // - the factory interface is for a WinRT type which is not registered => TypeLoadException
6806 // - the factory interface is not a factory for the WinRT type => ArgumentException
6807 if (hr == REGDB_E_CLASSNOTREG)
6808 {
6809 ThrowTypeLoadExceptionWithInner(pMT, WindowsGetStringRawBuffer(hName, nullptr), hr, IDS_EE_WINRT_TYPE_NOT_REGISTERED);
6810 }
6811 else if (hr == E_NOINTERFACE)
6812 {
6813 LPCWSTR wzTN = WindowsGetStringRawBuffer(hName, nullptr);
6814 if (pFactoryIntfMT)
6815 {
6816 InlineSString<DEFAULT_NONSTACK_CLASSNAME_SIZE> ssFactoryName;
6817 pFactoryIntfMT->_GetFullyQualifiedNameForClass(ssFactoryName);
6818 EEMessageException ex(hr);
6819 EX_THROW_WITH_INNER(EEMessageException, (kArgumentException, IDS_EE_WINRT_NOT_FACTORY_FOR_TYPE, ssFactoryName.GetUnicode(), wzTN), &ex);
6820 }
6821 else
6822 {
6823 EEMessageException ex(hr);
6824 EX_THROW_WITH_INNER(EEMessageException, (kArgumentException, IDS_EE_WINRT_INVALID_FACTORY_FOR_TYPE, wzTN), &ex);
6825 }
6826 }
6827 else
6828 {
6829 IfFailThrow(hr);
6830 }
6831
6832 DWORD flags =
6833 RCW::CF_SupportsIInspectable | // Returns a WinRT RCW
6834 RCW::CF_DontResolveClass; // Don't care about the exact type
6835
6836#ifdef FEATURE_WINDOWSPHONE
6837 flags |= RCW::CF_DetectDCOMProxy; // Attempt to detect that the factory is a DCOM proxy in order to suppress caching
6838#endif // FEATURE_WINDOWSPHONE
6839
6840 if (bNeedUniqueRCW)
6841 flags |= RCW::CF_NeedUniqueObject; // Returns a unique RCW
6842
6843 COMInterfaceMarshaler marshaler;
6844 marshaler.Init(
6845 pFactory,
6846 g_pBaseCOMObject, // Always System.__ComObject
6847 pThread,
6848 flags
6849 );
6850
6851 if (pCallback)
6852 marshaler.SetCallback(pCallback);
6853
6854 // Find an existing RCW or create a new RCW
6855 *prefFactory = marshaler.FindOrCreateObjectRef(pFactory);
6856
6857 return;
6858}
6859
6860#endif //#ifndef CROSSGEN_COMPILE
6861
6862
6863#endif // FEATURE_COMINTEROP
6864