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#ifndef _H_INTEROP_UTIL
7#define _H_INTEROP_UTIL
8
9#include "debugmacros.h"
10#include "interopconverter.h"
11
12struct VariantData;
13
14// Out of memory helper.
15#define IfNullThrow(EXPR) \
16do {if ((EXPR) == 0) {ThrowOutOfMemory();} } while (0)
17
18
19// Helper to determine the version number from an int.
20#define GET_VERSION_USHORT_FROM_INT(x) ((x < 0) || (x > (INT)((USHORT)-1))) ? 0 : static_cast<USHORT>(x)
21
22#ifdef FEATURE_COMINTEROP
23#include "winrttypenameconverter.h"
24#include "roparameterizediid.h"
25#include "../md/winmd/inc/adapter.h"
26#include <windows.foundation.h>
27
28// The format string to use to format unknown members to be passed to
29// invoke member
30#define DISPID_NAME_FORMAT_STRING W("[DISPID=%i]")
31
32//---------------------------------------------------------------------------
33// This method returns the default interface for the class as well as the
34// type of default interface we are dealing with.
35enum DefaultInterfaceType
36{
37 DefaultInterfaceType_Explicit = 0,
38 DefaultInterfaceType_IUnknown = 1,
39 DefaultInterfaceType_AutoDual = 2,
40 DefaultInterfaceType_AutoDispatch = 3,
41 DefaultInterfaceType_BaseComClass = 4
42};
43
44// System.Drawing.Color struct definition.
45
46struct SYSTEMCOLOR
47{
48#ifdef _WIN64
49 STRINGREF name;
50 INT64 value;
51#else
52 INT64 value;
53 STRINGREF name;
54#endif
55 short knownColor;
56 short state;
57};
58
59struct ComMethodTable;
60struct IUnkEntry;
61interface IStream;
62class ComCallWrapper;
63class InteropSyncBlockInfo;
64
65#endif //FEATURE_COMINTEROP
66
67#if FEATURE_COMINTEROP
68#include <restrictederrorInfo.h>
69#endif
70#ifndef __IRestrictedErrorInfo_INTERFACE_DEFINED__
71DEFINE_GUID(IID_IRestrictedErrorInfo, 0x82BA7092,0x4C88,0x427D,0xA7,0xBC,0x16,0xDD,0x93,0xFE,0xB6,0x7E);
72MIDL_INTERFACE("82BA7092-4C88-427D-A7BC-16DD93FEB67E")
73IRestrictedErrorInfo : public IUnknown
74{
75public:
76};
77#endif // !__IRestrictedErrorInfo_INTERFACE_DEFINED__
78
79class FieldDesc;
80struct ExceptionData;
81
82//------------------------------------------------------------------
83 // setup error info for exception object
84//
85#ifdef FEATURE_COMINTEROP
86HRESULT SetupErrorInfo(OBJECTREF pThrownObject, ComCallMethodDesc *pCMD);
87HRESULT SafeGetRestrictedErrorInfo(IRestrictedErrorInfo **ppIErrInfo);
88BOOL IsManagedObject(IUnknown *pErrInfo);
89IErrorInfo *GetCorrepondingErrorInfo_WinRT(HRESULT hr, IRestrictedErrorInfo *pResErrInfo, BOOL* bHasLangRestrictedErrInfo);
90HRESULT GetRestrictedErrorDetails(IRestrictedErrorInfo *pRestrictedErrorInfo, BSTR *perrorDescription, BSTR *pErrorRestrictedDescription, HRESULT *hr, BSTR *pErrorCapabilitySid);
91
92#endif // FEATURE_COMINTEROP
93
94HRESULT SetupErrorInfo(OBJECTREF pThrownObject, BOOL bIsWinRTScenario = FALSE);
95
96//--------------------------------------------------------------------------------
97 // Release helper, enables and disables GC during call-outs
98ULONG SafeRelease(IUnknown* pUnk, RCW* pRCW = NULL);
99
100//--------------------------------------------------------------------------------
101// Release helper, must be called in preemptive mode. Only use this variant if
102// you already know you're in preemptive mode for other reasons.
103ULONG SafeReleasePreemp(IUnknown* pUnk, RCW* pRCW = NULL);
104
105//--------------------------------------------------------------------------------
106// Determines if a COM object can be cast to the specified type.
107BOOL CanCastComObject(OBJECTREF obj, MethodTable * pTargetMT);
108
109// includes Types which hold a "ComObject" class
110// and types which are imported through typelib
111BOOL IsComWrapperClass(TypeHandle type);
112
113// includes Type which hold a "__ComObject" class
114BOOL IsComObjectClass(TypeHandle type);
115
116//---------------------------------------------------------
117// Read the BestFit custom attribute info from
118// both assembly level and interface level
119//---------------------------------------------------------
120VOID ReadBestFitCustomAttribute(MethodDesc* pMD, BOOL* BestFit, BOOL* ThrowOnUnmappableChar);
121VOID ReadBestFitCustomAttribute(IMDInternalImport* pInternalImport, mdTypeDef cl, BOOL* BestFit, BOOL* ThrowOnUnmappableChar);
122int InternalWideToAnsi(__in_ecount(iNumWideChars) LPCWSTR szWideString, int iNumWideChars, __out_ecount_opt(cbAnsiBufferSize) LPSTR szAnsiString, int cbAnsiBufferSize, BOOL fBestFit, BOOL fThrowOnUnmappableChar);
123
124//---------------------------------------------------------
125// Read the ClassInterfaceType custom attribute info from
126// both assembly level and interface level
127//---------------------------------------------------------
128CorClassIfaceAttr ReadClassInterfaceTypeCustomAttribute(TypeHandle type);
129
130//-------------------------------------------------------------------
131 // Used to populate ExceptionData with COM data
132//-------------------------------------------------------------------
133void FillExceptionData(
134 _Inout_ ExceptionData* pedata,
135 _In_ IErrorInfo* pErrInfo,
136 _In_opt_ IRestrictedErrorInfo* pRestrictedErrorInfo);
137
138//---------------------------------------------------------------------------
139//returns true if pImport has DefaultDllImportSearchPathsAttribute
140//if true, also returns dllImportSearchPathFlag and searchAssemblyDirectory values.
141BOOL GetDefaultDllImportSearchPathsAttributeValue(IMDInternalImport *pImport, mdToken token, DWORD * pDlImportSearchPathFlag);
142
143//---------------------------------------------------------------------------
144// Returns the index of the LCID parameter if one exists and -1 otherwise.
145int GetLCIDParameterIndex(MethodDesc *pMD);
146
147//---------------------------------------------------------------------------
148// Transforms an LCID into a CultureInfo.
149void GetCultureInfoForLCID(LCID lcid, OBJECTREF *pCultureObj);
150
151//---------------------------------------------------------------------------
152// This method determines if a member is visible from COM.
153BOOL IsMemberVisibleFromCom(MethodTable *pDeclaringMT, mdToken tk, mdMethodDef mdAssociate);
154
155//--------------------------------------------------------------------------------
156// This method generates a stringized version of an interface that contains the
157// name of the interface along with the signature of all the methods.
158SIZE_T GetStringizedItfDef(TypeHandle InterfaceType, CQuickArray<BYTE> &rDef);
159
160//--------------------------------------------------------------------------------
161// Helper to get the stringized form of typelib guid.
162HRESULT GetStringizedTypeLibGuidForAssembly(Assembly *pAssembly, CQuickArray<BYTE> &rDef, ULONG cbCur, ULONG *pcbFetched);
163
164//--------------------------------------------------------------------------------
165// GetErrorInfo helper, enables and disables GC during call-outs
166HRESULT SafeGetErrorInfo(_Outptr_ IErrorInfo **ppIErrInfo);
167
168//--------------------------------------------------------------------------------
169// QI helper, enables and disables GC during call-outs
170HRESULT SafeQueryInterface(IUnknown* pUnk, REFIID riid, IUnknown** pResUnk);
171
172//--------------------------------------------------------------------------------
173// QI helper, must be called in preemptive mode. Faster than the MODE_ANY version
174// because it doesn't need to toggle the mode. Use this version only if you already
175// know that you're in preemptive mode for other reasons.
176HRESULT SafeQueryInterfacePreemp(IUnknown* pUnk, REFIID riid, IUnknown** pResUnk);
177
178#ifdef FEATURE_COMINTEROP
179
180// Convert an IUnknown to CCW, does not handle aggregation and ICustomQI.
181ComCallWrapper* MapIUnknownToWrapper(IUnknown* pUnk);
182
183// Convert an IUnknown to CCW, returns NULL if the pUnk is not on
184// a managed tear-off (OR) if the pUnk is to a managed tear-off that
185// has been aggregated
186ComCallWrapper* GetCCWFromIUnknown(IUnknown* pUnk, BOOL bEnableCustomization = TRUE);
187
188// A version of LoadRegTypeLib that loads based on bitness and platform support
189// and loads with LCID == LOCALE_USER_DEFAULT
190HRESULT LoadRegTypeLib(_In_ REFGUID guid,
191 _In_ unsigned short wVerMajor,
192 _In_ unsigned short wVerMinor,
193 _Outptr_ ITypeLib **pptlib);
194
195//--------------------------------------------------------------------------------
196// Called from EEStartup, to initialize com Interop specific data structures.
197void InitializeComInterop();
198
199//--------------------------------------------------------------------------------
200// Clean up Helpers
201//--------------------------------------------------------------------------------
202// called by syncblock, on the finalizer thread to do major cleanup
203void CleanupSyncBlockComData(InteropSyncBlockInfo* pInteropInfo);
204
205// called by syncblock, during GC, do only minimal work
206void MinorCleanupSyncBlockComData(InteropSyncBlockInfo* pInteropInfo);
207
208// Helper to release all of the RCWs in the specified context, across all caches.
209// If context is null, release all RCWs, otherwise release RCWs created in the
210// given context, including Jupiter RCWs
211void ReleaseRCWsInCaches(LPVOID pCtxCookie);
212
213// A wrapper that catches all exceptions - used in the OnThreadTerminate case.
214void ReleaseRCWsInCachesNoThrow(LPVOID pCtxCookie);
215
216
217//--------------------------------------------------------------------------------
218// AddRef helper, enables and disables GC during call-outs
219ULONG SafeAddRef(IUnknown* pUnk);
220//--------------------------------------------------------------------------------
221// AddRef helper, must be called in preemptive mode. Only use this variant if
222// you already know you're in preemptive mode for other reasons.
223ULONG SafeAddRefPreemp(IUnknown* pUnk);
224
225//--------------------------------------------------------------------------------
226// Release helper, enables and disables GC during call-outs
227HRESULT SafeVariantChangeType(_Inout_ VARIANT* pVarRes, _In_ VARIANT* pVarSrc,
228 unsigned short wFlags, VARTYPE vt);
229
230//--------------------------------------------------------------------------------
231// Release helper, enables and disables GC during call-outs
232HRESULT SafeVariantChangeTypeEx(_Inout_ VARIANT* pVarRes, _In_ VARIANT* pVarSrc,
233 LCID lcid, unsigned short wFlags, VARTYPE vt);
234
235//--------------------------------------------------------------------------------
236// Init helper, enables and disables GC during call-outs
237void SafeVariantInit(VARIANT* pVar);
238
239//--------------------------------------------------------------------------------
240// Releases the data in the stream and then releases the stream itself.
241void SafeReleaseStream(IStream *pStream);
242
243//--------------------------------------------------------------------------------
244// Ole RPC seems to return an inconsistent SafeArray for arrays created with
245// SafeArrayVector(VT_BSTR). OleAut's SafeArrayGetVartype() doesn't notice
246// the inconsistency and returns a valid-seeming (but wrong vartype.)
247// Our version is more discriminating. This should only be used for
248// marshaling scenarios where we can assume unmanaged code permissions
249// (and hence are already in a position of trusting unmanaged data.)
250HRESULT ClrSafeArrayGetVartype(_In_ SAFEARRAY *psa, _Out_ VARTYPE *pvt);
251
252//Helpers
253
254//
255// Macros that defines how to recognize tear off
256//
257#define TEAR_OFF_SLOT 1
258#define TEAR_OFF_STANDARD Unknown_AddRef
259#define TEAR_OFF_SIMPLE_INNER Unknown_AddRefInner
260#define TEAR_OFF_SIMPLE Unknown_AddRefSpecial
261
262BOOL ComInterfaceSlotIs(IUnknown* pUnk, int slot, LPVOID pvFunction);
263
264// Is the tear-off a CLR created tear-off
265BOOL IsInProcCCWTearOff(IUnknown* pUnk);
266
267// is the tear-off represent one of the standard interfaces such as IProvideClassInfo, IErrorInfo etc.
268BOOL IsSimpleTearOff(IUnknown* pUnk);
269
270// Is the tear-off represent the inner unknown or the original unknown for the object
271BOOL IsInnerUnknown(IUnknown* pUnk);
272
273// Is this one of our "standard" ComCallWrappers
274BOOL IsStandardTearOff(IUnknown* pUnk);
275
276//---------------------------------------------------------------------------
277 // is the iid represent an IClassX for this class
278BOOL IsIClassX(MethodTable *pMT, REFIID riid, ComMethodTable **ppComMT);
279
280// Returns TRUE if we support IClassX for the given class.
281BOOL ClassSupportsIClassX(MethodTable *pMT);
282
283#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
284//---------------------------------------------------------------------------
285 // Calls COM class factory and instantiates a new RCW.
286OBJECTREF AllocateComObject_ForManaged(MethodTable* pMT);
287#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
288
289//---------------------------------------------------------------------------
290 // get/load data for a given clsid
291MethodTable* GetTypeForCLSID(REFCLSID rclsid, BOOL* pfAssemblyInReg = NULL);
292
293
294//---------------------------------------------------------------------------
295 // get/load a value class for a given guid
296#ifdef FEATURE_CLASSIC_COMINTEROP
297MethodTable* GetValueTypeForGUID(REFCLSID guid);
298#endif
299
300DefaultInterfaceType GetDefaultInterfaceForClassInternal(TypeHandle hndClass, TypeHandle *pHndDefClass);
301DefaultInterfaceType GetDefaultInterfaceForClassWrapper(TypeHandle hndClass, TypeHandle *pHndDefClass);
302
303HRESULT TryGetDefaultInterfaceForClass(TypeHandle hndClass, TypeHandle *pHndDefClass, DefaultInterfaceType *pDefItfType);
304
305MethodTable *GetDefaultInterfaceMTForClass(MethodTable *pMT, BOOL *pbDispatch);
306
307//---------------------------------------------------------------------------
308// This method retrieves the list of source interfaces for a given class.
309void GetComSourceInterfacesForClass(MethodTable *pClassMT, CQuickArray<MethodTable *> &rItfList);
310
311//--------------------------------------------------------------------------------
312// This methods converts an IEnumVARIANT to a managed IEnumerator.
313OBJECTREF ConvertEnumVariantToMngEnum(IEnumVARIANT *pNativeEnum);
314
315//--------------------------------------------------------------------------------
316// These methods convert an OLE_COLOR to a System.Color and vice versa.
317void ConvertOleColorToSystemColor(OLE_COLOR SrcOleColor, SYSTEMCOLOR *pDestSysColor);
318OLE_COLOR ConvertSystemColorToOleColor(SYSTEMCOLOR *pSrcSysColor);
319OLE_COLOR ConvertSystemColorToOleColor(OBJECTREF *pSrcObj);
320
321//--------------------------------------------------------------------------------
322// This method generates a stringized version of a class interface that contains
323// the signatures of all the methods and fields.
324ULONG GetStringizedClassItfDef(TypeHandle InterfaceType, CQuickArray<BYTE> &rDef);
325
326//--------------------------------------------------------------------------------
327// Helper to get the GUID of a class interface.
328void GenerateClassItfGuid(TypeHandle InterfaceType, GUID *pGuid);
329
330// Try/Catch wrapped version of the method.
331HRESULT TryGenerateClassItfGuid(TypeHandle InterfaceType, GUID *pGuid);
332
333//--------------------------------------------------------------------------------
334// Helper to get the GUID of the typelib that is created from an assembly.
335HRESULT GetTypeLibGuidForAssembly(Assembly *pAssembly, GUID *pGuid);
336
337//--------------------------------------------------------------------------------
338// Helper to get the version of the typelib that is created from an assembly.
339HRESULT GetTypeLibVersionForAssembly(
340 _In_ Assembly *pAssembly,
341 _Out_ USHORT *pMajorVersion,
342 _Out_ USHORT *pMinorVersion);
343
344//---------------------------------------------------------------------------
345// This method determines if a member is visible from COM.
346BOOL IsMethodVisibleFromCom(MethodDesc *pMD);
347
348//---------------------------------------------------------------------------
349// This method determines if a type is visible from COM or not based on
350// its visibility. This version of the method works with a type handle.
351BOOL IsTypeVisibleFromCom(TypeHandle hndType);
352
353//---------------------------------------------------------------------------
354// Determines if a method is likely to be used for forward COM/WinRT interop.
355BOOL MethodNeedsForwardComStub(MethodDesc *pMD, DataImage *pImage);
356
357//---------------------------------------------------------------------------
358// Determines if a method is visible from COM in a way that requires a marshaling stub.
359BOOL MethodNeedsReverseComStub(MethodDesc *pMD);
360
361//--------------------------------------------------------------------------------
362// InvokeDispMethod will convert a set of managed objects and call IDispatch. The
363// result will be returned as a COM+ Variant pointed to by pRetVal.
364void IUInvokeDispMethod(
365 REFLECTCLASSBASEREF* pRefClassObj,
366 OBJECTREF* pTarget,
367 OBJECTREF* pName,
368 DISPID *pMemberID,
369 OBJECTREF* pArgs,
370 OBJECTREF* pModifiers,
371 OBJECTREF* pNamedArgs,
372 OBJECTREF* pRetVal,
373 LCID lcid,
374 WORD flags,
375 BOOL bIgnoreReturn,
376 BOOL bIgnoreCase);
377
378#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
379// Class Factory helpers
380
381//--------------------------------------------------------------------------
382// GetComClassFromProgID used by reflection class to setup a Class based on ProgID
383void GetComClassFromProgID(STRINGREF srefProgID, STRINGREF srefServer, OBJECTREF* pRef);
384
385//--------------------------------------------------------------------------
386// GetComClassFromCLSID used by reflection class to setup a Class based on CLSID
387void GetComClassFromCLSID(REFCLSID clsid, STRINGREF srefServer, OBJECTREF* pRef);
388
389//-------------------------------------------------------------
390// check if a ComClassFactory/WinRTClassFactory has been setup for this class
391// if not set one up
392ClassFactoryBase *GetComClassFactory(MethodTable* pClassMT);
393#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
394
395
396// logging APIs
397
398#ifdef _DEBUG
399
400VOID LogInterop(__in_z LPCSTR szMsg);
401VOID LogInterop(__in_z LPCWSTR szMsg);
402
403VOID LogInteropLeak(IUnkEntry * pEntry);
404VOID LogInteropLeak(IUnknown* pItf);
405VOID LogInteropQI(IUnknown* pItf, REFIID riid, HRESULT hr, __in_z LPCSTR szMsg);
406VOID LogInteropAddRef(IUnknown* pItf, ULONG cbRef, __in_z LPCSTR szMsg);
407VOID LogInteropRelease(IUnknown* pItf, ULONG cbRef, __in_z LPCSTR szMsg);
408
409VOID LogRCWCreate(RCW* pWrap, IUnknown* pUnk);
410VOID LogRCWMinorCleanup(RCW* pWrap);
411VOID LogRCWDestroy(RCW* pWrap);
412
413#else
414
415#define LogInterop(x)
416#define LogInteropLeak(x)
417#define LogInteropQI(x, y, z, w)
418#define LogInteropAddRef(x, y, z)
419#define LogInteropRelease(x, y, z)
420#define LogRCWCreate(x, y)
421#define LogRCWMinorCleanup(x)
422#define LogRCWDestroy(x)
423
424#endif
425
426//--------------------------------------------------------------------------------
427// Ensure COM is started up.
428HRESULT EnsureComStartedNoThrow(BOOL fCoInitCurrentThread = TRUE);
429VOID EnsureComStarted(BOOL fCoInitCurrentThread = TRUE);
430
431//--------------------------------------------------------------------------------
432// check if the class is OR extends a COM Imported class
433BOOL ExtendsComImport(MethodTable* pMT);
434
435//--------------------------------------------------------------------------------
436// Gets the CLSID from the specified Prog ID.
437HRESULT GetCLSIDFromProgID(__in_z WCHAR *strProgId, GUID *pGuid);
438
439//--------------------------------------------------------------------------------
440// Check if the pUnk implements IProvideClassInfo and try to figure
441// out the class from there
442MethodTable* GetClassFromIProvideClassInfo(IUnknown* pUnk);
443
444//--------------------------------------------------------------------------------
445// Try to load a WinRT type.
446TypeHandle GetWinRTType(SString* ssTypeName, BOOL bThrowIfNotFound);
447
448//--------------------------------------------------------------------------------
449// Try to get the class from IInspectable.
450TypeHandle GetClassFromIInspectable(IUnknown* pUnk, bool *pfSupportsIInspectable, bool *pfSupportsIReference, bool *pfSupportsIReferenceArray);
451
452//--------------------------------------------------------------------------------
453// Build a WinRT URI for a given raw URI
454ABI::Windows::Foundation::IUriRuntimeClass *CreateWinRTUri(LPCWSTR wszUri, INT32 cchUri);
455
456// Generates GUIDs for parameterized WinRT types.
457class WinRTGuidGenerator
458{
459 class MetaDataLocator : public IRoMetaDataLocator
460 {
461 // IRoMetaDataLocator implementation:
462 STDMETHOD(Locate)(PCWSTR nameElement, IRoSimpleMetaDataBuilder &metaDataDestination) const;
463
464 // helper methods:
465 static HRESULT LocateTypeWithDefaultInterface(MethodTable *pMT, LPCWSTR pszName, IRoSimpleMetaDataBuilder &metaDataDestination);
466 static HRESULT LocateStructure(MethodTable *pMT, LPCWSTR pszName, IRoSimpleMetaDataBuilder &metaDataDestination);
467 static HRESULT LocateRedirectedType(MethodTable *pMT, IRoSimpleMetaDataBuilder &metaDataDestination);
468 };
469
470 static void PopulateNames(MethodTable *pMT, SArray<BYTE> &namesBuf, PCWSTR* &pszNames, COUNT_T &cNames);
471 static void PopulateNamesAppendNamePointers(MethodTable *pMT, SArray<BYTE> &namesBuf, PCWSTR* &pszNames, COUNT_T cNames);
472 static void PopulateNamesAppendTypeName(MethodTable *pMT, SArray<BYTE> &namesBuf, COUNT_T &cNames);
473public:
474 //--------------------------------------------------------------------------
475 // pGuid is filled with the constructed IID by the function.
476 static void ComputeGuidForGenericType(MethodTable *pMT, GUID *pGuid);
477}; // class WinRTGuidGenerator
478
479IUnknown* MarshalObjectToInterface(OBJECTREF* ppObject, MethodTable* pItfMT, MethodTable* pClassMT, DWORD dwFlags);
480void UnmarshalObjectFromInterface(OBJECTREF *ppObjectDest, IUnknown **ppUnkSrc, MethodTable *pItfMT, MethodTable *pClassMT, DWORD dwFlags);
481
482#define DEFINE_ASM_QUAL_TYPE_NAME(varname, typename, asmname, version, publickeytoken) static const char varname##[] = { typename##", "##asmname##", Culture=neutral, PublicKeyToken="##publickeytoken##", Version="##version };
483
484class ICOMInterfaceMarshalerCallback;
485void GetNativeWinRTFactoryObject(MethodTable *pMT, Thread *pThread, MethodTable *pFactoryIntfMT, BOOL bNeedUniqueRCW, ICOMInterfaceMarshalerCallback *pCallback, OBJECTREF *prefFactory);
486
487#else // FEATURE_COMINTEROP
488inline HRESULT EnsureComStartedNoThrow()
489{
490 LIMITED_METHOD_CONTRACT;
491
492 return S_OK;
493}
494
495inline VOID EnsureComStarted()
496{
497 LIMITED_METHOD_CONTRACT;
498}
499
500#define LogInteropRelease(x, y, z)
501
502#endif // FEATURE_COMINTEROP
503
504#endif // _H_INTEROP_UTIL
505