internal static unsafe IntPtr ObjectToComInterfaceInternal(Object obj, RuntimeTypeHandle typeHnd) { if (obj == null) { return(default(IntPtr)); } #if ENABLE_WINRT // // Try boxing if this is a WinRT object // if (typeHnd.Equals(InternalTypes.IInspectable)) { object unboxed = McgMarshal.BoxIfBoxable(obj); // // Marshal ReferenceImpl<T> to WinRT as IInspectable // if (unboxed != null) { obj = unboxed; } else { // // Anything that can be casted to object[] will be boxed as object[] // object[] objArray = obj as object[]; if (objArray != null) { unboxed = McgMarshal.BoxIfBoxable(obj, typeof(object[]).TypeHandle); if (unboxed != null) { obj = unboxed; } } } } #endif //ENABLE_WINRT // // If this is a RCW, and the RCW is not a base class (managed class deriving from RCW class), // QI on the RCW // __ComObject comObject = obj as __ComObject; if (comObject != null && !comObject.ExtendsComObject) { IntPtr pComPtr = comObject.QueryInterface_NoAddRef_Internal(typeHnd, /* cacheOnly= */ false, /* throwOnQueryInterfaceFailure= */ false); if (pComPtr == default(IntPtr)) { return(default(IntPtr)); } McgMarshal.ComAddRef(pComPtr); GC.KeepAlive(comObject); // make sure we don't collect the object before adding a refcount. return(pComPtr); } // // Otherwise, go down the CCW code path // return(ManagedObjectToComInterface(obj, typeHnd)); }
public static int AddRef(IntPtr pUnk) { return(McgMarshal.ComAddRef(pUnk)); }
/// <summary> /// Returns the existing RCW or create a new RCW from the COM interface pointer /// NOTE: This does unboxing unless CreateComObjectFlags.SkipTypeResolutionAndUnboxing is specified /// </summary> /// <param name="expectedContext"> /// The current context of this thread. If it is passed and is not Default, we'll check whether the /// returned RCW from cache matches this expected context. If it is not a match (from a different /// context, and is not free threaded), we'll go ahead ignoring the cached entry, and create a new /// RCW instead - which will always end up in the current context /// We'll skip the check if current == ContextCookie.Default. /// </param> internal static object ComInterfaceToComObjectInternal( IntPtr pComItf, IntPtr pComIdentityIUnknown, RuntimeTypeHandle interfaceType, RuntimeTypeHandle classTypeInSignature, ContextCookie expectedContext, CreateComObjectFlags flags ) { string className; object obj = ComInterfaceToComObjectInternal_NoCache( pComItf, pComIdentityIUnknown, interfaceType, classTypeInSignature, expectedContext, flags, out className ); // // The assumption here is that if the classInfoInSignature is null and interfaceTypeInfo // is either IUnknow and IInspectable we need to try unboxing. // bool doUnboxingCheck = (flags & CreateComObjectFlags.SkipTypeResolutionAndUnboxing) == 0 && obj != null && classTypeInSignature.IsNull() && (interfaceType.Equals(InternalTypes.IUnknown) || interfaceType.IsIInspectable()); if (doUnboxingCheck) { // // Try unboxing // Even though this might just be a IUnknown * from the signature, we still attempt to unbox // if it implements IInspectable // // @TODO - We might need to optimize this by pre-checking the names to see if they // potentially represents a boxed type, but for now let's keep it simple and I also don't // want to replicate the knowledge here // @TODO2- We probably should skip the creating the COM object in the first place. // // NOTE: the RCW here could be a cached one (for a brief time if GC doesn't kick in. as there // is nothing to hold the RCW alive for IReference<T> RCWs), so this could save us a RCW // creation cost potentially. Desktop CLR doesn't do this. But we also paying for unnecessary // cache management cost, and it is difficult to say which way is better without proper // measuring // object unboxedObj = McgMarshal.UnboxIfBoxed(obj, className); if (unboxedObj != null) { return(unboxedObj); } } // // In order for variance to work, we save the incoming interface pointer as specified in the // signature into the cache, so that we know this RCW does support this interface and variance // can take advantage of that later // NOTE: In some cases, native might pass a WinRT object as a 'compatible' interface, for example, // pass IVector<IFoo> as IVector<Object> because they are 'compatible', but QI for IVector<object> // won't succeed. In this case, we'll just believe it implements IVector<Object> as in the // signature while the underlying interface pointer is actually IVector<IFoo> // __ComObject comObject = obj as __ComObject; if (comObject != null) { McgMarshal.ComAddRef(pComItf); try { comObject.InsertIntoCache(interfaceType, ContextCookie.Current, ref pComItf, true); } finally { // // Only release when a exception is thrown or we didn't 'swallow' the ref count by // inserting it into the cache // McgMarshal.ComSafeRelease(pComItf); } } return(obj); }