static object ComInterfaceToObjectInternal_NoManagedUnboxing( IntPtr pComItf, McgTypeInfo interfaceTypeInfo, McgClassInfo classInfoInSignature, CreateComObjectFlags flags) { if (pComItf == default(IntPtr)) { return(null); } // // Is this a CCW? // ComCallableObject ccw; if (ComCallableObject.TryGetCCW(pComItf, out ccw)) { return(ccw.TargetObject); } // // This pointer is not a CCW, but we need to do one additional check here for aggregation // In case the COM pointer is a interface implementation from native, but the outer object is a // managed object // IntPtr pComIdentityIUnknown = McgMarshal.ComQueryInterfaceNoThrow(pComItf, ref Interop.COM.IID_IUnknown); if (pComIdentityIUnknown == default(IntPtr)) { throw new InvalidCastException(); } try { // // Check whether the identity COM pointer to see if it is a aggregating CCW // if (ComCallableObject.TryGetCCW(pComIdentityIUnknown, out ccw)) { return(ccw.TargetObject); } // // Nope, not a CCW - let's go down our RCW creation code path // return(ComInterfaceToComObjectInternal( pComItf, pComIdentityIUnknown, interfaceTypeInfo, classInfoInSignature, ContextCookie.Default, flags )); } finally { McgMarshal.ComRelease(pComIdentityIUnknown); } }
public static IntPtr /* IUnknown* */ GetComInterfaceForObject(Object o, Type t) { if (o == null) { throw new ArgumentNullException("o"); } if (t == null) { throw new ArgumentNullException("type"); } RuntimeTypeHandle interfaceTypeHandle = t.TypeHandle; McgTypeInfo secondTypeInfo; McgTypeInfo mcgTypeInfo = McgModuleManager.GetTypeInfoFromTypeHandle(interfaceTypeHandle, out secondTypeInfo); if (mcgTypeInfo.IsNull) { #if CORECLR return(default(IntPtr)); #else throw new MissingInteropDataException(SR.ComTypeMarshalling_MissingInteropData, t); #endif } return(McgMarshal.ObjectToComInterface(o, mcgTypeInfo)); }
/// <summary> /// Converts a COM interface pointer to a managed object /// This either gets back a existing CCW, or a existing RCW, or create a new RCW /// </summary> internal static object ComInterfaceToObjectInternal( IntPtr pComItf, McgTypeInfo interfaceTypeInfo, McgClassInfo classInfoInSignature, CreateComObjectFlags flags) { bool needUnboxing = (flags & CreateComObjectFlags.SkipTypeResolutionAndUnboxing) == 0; object ret = ComInterfaceToObjectInternal_NoManagedUnboxing(pComItf, interfaceTypeInfo, classInfoInSignature, flags); if (ret != null && needUnboxing) { return(UnboxManagedWrapperIfBoxed(ret)); } return(ret); }
/// <summary> /// Returns the existing RCW or create a new RCW from the COM interface pointer /// NOTE: Don't use this overload if you already have the identity IUnknown /// </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 ComInterfaceToComObject( IntPtr pComItf, McgTypeInfo interfaceTypeInfo, McgClassInfo classInfoInSigature, ContextCookie expectedContext, CreateComObjectFlags flags ) { Debug.Assert(expectedContext.IsDefault || expectedContext.IsCurrent); // // Get identity IUnknown for lookup // IntPtr pComIdentityIUnknown = McgMarshal.ComQueryInterfaceNoThrow(pComItf, ref Interop.COM.IID_IUnknown); if (pComIdentityIUnknown == default(IntPtr)) { throw new InvalidCastException(); } try { object obj = ComInterfaceToComObjectInternal( pComItf, pComIdentityIUnknown, interfaceTypeInfo, classInfoInSigature, expectedContext, flags ); return(obj); } finally { McgMarshal.ComRelease(pComIdentityIUnknown); } }
internal static unsafe IntPtr ManagedObjectToComInterface(Object obj, McgTypeInfo itfTypeInfo) { Guid itfGuid = itfTypeInfo.ItfGuid; return ManagedObjectToComInterfaceInternal(obj, ref itfGuid, itfTypeInfo); }
private static unsafe IntPtr ManagedObjectToComInterfaceInternal(Object obj, ref Guid iid, McgTypeInfo itfTypeInfo) { if (obj == null) { return default(IntPtr); } // // Look up ComCallableObject from the cache // If couldn't find one, create a new one // ComCallableObject ccw = null; try { // // Either return existing one or create a new one // In either case, the returned CCW is addref-ed to avoid race condition // IntPtr dummy; ccw = CCWLookupMap.GetOrCreateCCW(obj, McgTypeInfo.Null, out dummy); Debug.Assert(ccw != null); return ccw.GetComInterfaceForIID(ref iid, itfTypeInfo); } finally { // // Free the extra ref count added by GetOrCreateCCW (to protect the CCW from being collected) // if (ccw != null) ccw.Release(); } }
static object ComInterfaceToObjectInternal_NoManagedUnboxing( IntPtr pComItf, McgTypeInfo interfaceTypeInfo, McgClassInfo classInfoInSignature, CreateComObjectFlags flags) { if (pComItf == default(IntPtr)) return null; // // Is this a CCW? // ComCallableObject ccw; if (ComCallableObject.TryGetCCW(pComItf, out ccw)) { return ccw.TargetObject; } // // This pointer is not a CCW, but we need to do one additional check here for aggregation // In case the COM pointer is a interface implementation from native, but the outer object is a // managed object // IntPtr pComIdentityIUnknown = McgMarshal.ComQueryInterfaceNoThrow(pComItf, ref Interop.COM.IID_IUnknown); if (pComIdentityIUnknown == default(IntPtr)) throw new InvalidCastException(); try { // // Check whether the identity COM pointer to see if it is a aggregating CCW // if (ComCallableObject.TryGetCCW(pComIdentityIUnknown, out ccw)) { return ccw.TargetObject; } // // Nope, not a CCW - let's go down our RCW creation code path // return ComInterfaceToComObjectInternal( pComItf, pComIdentityIUnknown, interfaceTypeInfo, classInfoInSignature, ContextCookie.Default, flags ); } finally { McgMarshal.ComRelease(pComIdentityIUnknown); } }
internal unsafe static IntPtr ObjectToComInterfaceInternal(Object obj, McgTypeInfo typeInfo) { if (obj == null) return default(IntPtr); #if ENABLE_WINRT // // Try boxing if this is a WinRT object // if (typeInfo == McgModuleManager.IInspectable) { object unboxed = McgModuleManager.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 = McgModuleManager.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(typeInfo, /* 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 // Guid itfGuid = typeInfo.ItfGuid; return ManagedObjectToComInterfaceInternal(obj, ref itfGuid, typeInfo); }
/// <summary> /// Returns the existing RCW or create a new RCW from the COM interface pointer /// NOTE: This does not do any unboxing at all. /// </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> private static object ComInterfaceToComObjectInternal_NoCache( IntPtr pComItf, IntPtr pComIdentityIUnknown, McgTypeInfo interfaceTypeInfo, McgClassInfo classInfoInSignature, ContextCookie expectedContext, CreateComObjectFlags flags, out string className ) { className = null; // // Lookup RCW in global RCW cache based on the identity IUnknown // __ComObject comObject = ComObjectCache.Lookup(pComIdentityIUnknown); if (comObject != null) { bool useThisComObject = true; if (!expectedContext.IsDefault) { // // Make sure the returned RCW matches the context we specify (if any) // if (!comObject.IsFreeThreaded && !comObject.ContextCookie.Equals(expectedContext)) { // // This is a mismatch. // We only care about context for WinRT factory RCWs (which is the only place we are // passing in the context right now). // When we get back a WinRT factory RCW created in a different context. This means the // factory is a singleton, and the returned IActivationFactory could be either one of // the following: // 1) A raw pointer, and it acts like a free threaded object // 2) A proxy that is used across different contexts. It might maintain a list of contexts // that it is marshaled to, and will fail to be called if it is not marshaled to this // context yet. // // In this case, it is unsafe to use this RCW in this context and we should proceed // to create a duplicated one instead. It might make sense to have a context-sensitive // RCW cache but I don't think this case will be common enough to justify it // // @TODO: Check for DCOM proxy as well useThisComObject = false; } } if (useThisComObject) { // // We found one - AddRef and return // comObject.AddRef(); return comObject; } } string winrtClassName = null; bool isSealed = false; if (!classInfoInSignature.IsNull) { isSealed = classInfoInSignature.IsSealed; } // // Only look at runtime class name if the class type in signature is not sealed // NOTE: In the case of System.Uri, we are not pass the class type, only the interface // if (!isSealed && (flags & CreateComObjectFlags.SkipTypeResolutionAndUnboxing) == 0) { IntPtr pInspectable; bool needRelease = false; if (interfaceTypeInfo.IsIInspectable) { // // Use the interface pointer as IInspectable as we know it is indeed a WinRT interface that // derives from IInspectable // pInspectable = pComItf; } else if ((flags & CreateComObjectFlags.IsWinRTObject) != 0) { // // Otherwise, if someone tells us that this is a WinRT object, but we don't have a // IInspectable interface at hand, we'll QI for it // pInspectable = McgMarshal.ComQueryInterfaceNoThrow(pComItf, ref Interop.COM.IID_IInspectable); needRelease = true; } else { pInspectable = default(IntPtr); } try { if (pInspectable != default(IntPtr)) { className = McgComHelpers.GetRuntimeClassName(pInspectable); winrtClassName = className; } } finally { if (needRelease && pInspectable != default(IntPtr)) { McgMarshal.ComRelease(pInspectable); pInspectable = default(IntPtr); } } } // // 1. Prefer using the class returned from GetRuntimeClassName // 2. Otherwise use the class (if there) in the signature // 3. Out of options - create __ComObject // McgClassInfo classInfoToCreateRCW = McgClassInfo.Null; McgTypeInfo interfaceInfo = McgTypeInfo.Null; if (!String.IsNullOrEmpty(className)) { if (!McgModuleManager.TryGetClassInfoFromName(className, out classInfoToCreateRCW)) { // // If we can't find the class name in our map, try interface as well // Such as IVector<Int32> // This apparently won't work if we haven't seen the interface type in MCG // McgModuleManager.TryGetInterfaceTypeInfoFromName(className, out interfaceInfo); } } if (classInfoToCreateRCW.IsNull) classInfoToCreateRCW = classInfoInSignature; // Use identity IUnknown to create the new RCW // @TODO: Transfer the ownership of ref count to the RCW if (classInfoToCreateRCW.IsNull) { // // Create a weakly typed RCW because we have no information about this particular RCW // @TODO - what if this RCW is not seen by MCG but actually exists in WinMD and therefore we // are missing GCPressure and ComMarshallingType information for this object? // comObject = new __ComObject(pComIdentityIUnknown, McgClassInfo.Null); } else { // // Create a strongly typed RCW based on McgClassInfo // comObject = CreateComObjectInternal(classInfoToCreateRCW, pComIdentityIUnknown); // Use identity IUnknown to create the new RCW } #if DEBUG // // Remember the runtime class name for debugging purpose // This way you can tell what the class name is, even when we failed to create a strongly typed // RCW for it // comObject.m_runtimeClassName = className; #endif // // Make sure we QI for that interface // if (!interfaceInfo.IsNull) { comObject.QueryInterface_NoAddRef_Internal(interfaceInfo, /* cacheOnly= */ false, /* throwOnQueryInterfaceFailure= */ false); } return comObject; }
/// <summary> /// Converts a COM interface pointer to a managed object /// This either gets back a existing CCW, or a existing RCW, or create a new RCW /// </summary> internal static object ComInterfaceToObjectInternal( IntPtr pComItf, McgTypeInfo interfaceTypeInfo, McgClassInfo classInfoInSignature, CreateComObjectFlags flags) { bool needUnboxing = (flags & CreateComObjectFlags.SkipTypeResolutionAndUnboxing) == 0; object ret = ComInterfaceToObjectInternal_NoManagedUnboxing(pComItf, interfaceTypeInfo, classInfoInSignature, flags); if (ret != null && needUnboxing) { return UnboxManagedWrapperIfBoxed(ret); } return ret; }
/// <summary> /// Returns the existing RCW or create a new RCW from the COM interface pointer /// NOTE: Don't use this overload if you already have the identity IUnknown /// </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 ComInterfaceToComObject( IntPtr pComItf, McgTypeInfo interfaceTypeInfo, McgClassInfo classInfoInSigature, ContextCookie expectedContext, CreateComObjectFlags flags ) { Debug.Assert(expectedContext.IsDefault || expectedContext.IsCurrent); // // Get identity IUnknown for lookup // IntPtr pComIdentityIUnknown = McgMarshal.ComQueryInterfaceNoThrow(pComItf, ref Interop.COM.IID_IUnknown); if (pComIdentityIUnknown == default(IntPtr)) throw new InvalidCastException(); try { object obj = ComInterfaceToComObjectInternal( pComItf, pComIdentityIUnknown, interfaceTypeInfo, classInfoInSigature, expectedContext, flags ); return obj; } finally { McgMarshal.ComRelease(pComIdentityIUnknown); } }
/// <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, McgTypeInfo interfaceTypeInfo, McgClassInfo classInfoInSignature, ContextCookie expectedContext, CreateComObjectFlags flags ) { string className; object obj = ComInterfaceToComObjectInternal_NoCache( pComItf, pComIdentityIUnknown, interfaceTypeInfo, classInfoInSignature, 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 && classInfoInSignature.IsNull && (interfaceTypeInfo == McgModuleManager.IUnknown || interfaceTypeInfo == McgModuleManager.IInspectable); 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 = McgModuleManager.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(interfaceTypeInfo, 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; }
/// <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, McgTypeInfo interfaceTypeInfo, McgClassInfo classInfoInSignature, ContextCookie expectedContext, CreateComObjectFlags flags ) { string className; object obj = ComInterfaceToComObjectInternal_NoCache( pComItf, pComIdentityIUnknown, interfaceTypeInfo, classInfoInSignature, 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 && classInfoInSignature.IsNull && (interfaceTypeInfo == McgModuleManager.IUnknown || interfaceTypeInfo == McgModuleManager.IInspectable); 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 = McgModuleManager.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(interfaceTypeInfo, 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); }
private static unsafe IntPtr ManagedObjectToComInterfaceInternal(Object obj, ref Guid iid, McgTypeInfo itfTypeInfo) { if (obj == null) { return(default(IntPtr)); } // // Look up ComCallableObject from the cache // If couldn't find one, create a new one // ComCallableObject ccw = null; try { // // Either return existing one or create a new one // In either case, the returned CCW is addref-ed to avoid race condition // IntPtr dummy; ccw = CCWLookupMap.GetOrCreateCCW(obj, McgTypeInfo.Null, out dummy); Debug.Assert(ccw != null); return(ccw.GetComInterfaceForIID(ref iid, itfTypeInfo)); } finally { // // Free the extra ref count added by GetOrCreateCCW (to protect the CCW from being collected) // if (ccw != null) { ccw.Release(); } } }
internal static unsafe IntPtr ManagedObjectToComInterface(Object obj, McgTypeInfo itfTypeInfo) { Guid itfGuid = itfTypeInfo.ItfGuid; return(ManagedObjectToComInterfaceInternal(obj, ref itfGuid, itfTypeInfo)); }
internal unsafe static IntPtr ObjectToComInterfaceInternal(Object obj, McgTypeInfo typeInfo) { if (obj == null) { return(default(IntPtr)); } #if ENABLE_WINRT // // Try boxing if this is a WinRT object // if (typeInfo == McgModuleManager.IInspectable) { object unboxed = McgModuleManager.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 = McgModuleManager.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(typeInfo, /* 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 // Guid itfGuid = typeInfo.ItfGuid; return(ManagedObjectToComInterfaceInternal(obj, ref itfGuid, typeInfo)); }
/// <summary> /// Returns the existing RCW or create a new RCW from the COM interface pointer /// NOTE: This does not do any unboxing at all. /// </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> private static object ComInterfaceToComObjectInternal_NoCache( IntPtr pComItf, IntPtr pComIdentityIUnknown, McgTypeInfo interfaceTypeInfo, McgClassInfo classInfoInSignature, ContextCookie expectedContext, CreateComObjectFlags flags, out string className ) { className = null; // // Lookup RCW in global RCW cache based on the identity IUnknown // __ComObject comObject = ComObjectCache.Lookup(pComIdentityIUnknown); if (comObject != null) { bool useThisComObject = true; if (!expectedContext.IsDefault) { // // Make sure the returned RCW matches the context we specify (if any) // if (!comObject.IsFreeThreaded && !comObject.ContextCookie.Equals(expectedContext)) { // // This is a mismatch. // We only care about context for WinRT factory RCWs (which is the only place we are // passing in the context right now). // When we get back a WinRT factory RCW created in a different context. This means the // factory is a singleton, and the returned IActivationFactory could be either one of // the following: // 1) A raw pointer, and it acts like a free threaded object // 2) A proxy that is used across different contexts. It might maintain a list of contexts // that it is marshaled to, and will fail to be called if it is not marshaled to this // context yet. // // In this case, it is unsafe to use this RCW in this context and we should proceed // to create a duplicated one instead. It might make sense to have a context-sensitive // RCW cache but I don't think this case will be common enough to justify it // // @TODO: Check for DCOM proxy as well useThisComObject = false; } } if (useThisComObject) { // // We found one - AddRef and return // comObject.AddRef(); return(comObject); } } string winrtClassName = null; bool isSealed = false; if (!classInfoInSignature.IsNull) { isSealed = classInfoInSignature.IsSealed; } // // Only look at runtime class name if the class type in signature is not sealed // NOTE: In the case of System.Uri, we are not pass the class type, only the interface // if (!isSealed && (flags & CreateComObjectFlags.SkipTypeResolutionAndUnboxing) == 0) { IntPtr pInspectable; bool needRelease = false; if (interfaceTypeInfo.IsIInspectable) { // // Use the interface pointer as IInspectable as we know it is indeed a WinRT interface that // derives from IInspectable // pInspectable = pComItf; } else if ((flags & CreateComObjectFlags.IsWinRTObject) != 0) { // // Otherwise, if someone tells us that this is a WinRT object, but we don't have a // IInspectable interface at hand, we'll QI for it // pInspectable = McgMarshal.ComQueryInterfaceNoThrow(pComItf, ref Interop.COM.IID_IInspectable); needRelease = true; } else { pInspectable = default(IntPtr); } try { if (pInspectable != default(IntPtr)) { className = McgComHelpers.GetRuntimeClassName(pInspectable); winrtClassName = className; } } finally { if (needRelease && pInspectable != default(IntPtr)) { McgMarshal.ComRelease(pInspectable); pInspectable = default(IntPtr); } } } // // 1. Prefer using the class returned from GetRuntimeClassName // 2. Otherwise use the class (if there) in the signature // 3. Out of options - create __ComObject // McgClassInfo classInfoToCreateRCW = McgClassInfo.Null; McgTypeInfo interfaceInfo = McgTypeInfo.Null; if (!String.IsNullOrEmpty(className)) { if (!McgModuleManager.TryGetClassInfoFromName(className, out classInfoToCreateRCW)) { // // If we can't find the class name in our map, try interface as well // Such as IVector<Int32> // This apparently won't work if we haven't seen the interface type in MCG // McgModuleManager.TryGetInterfaceTypeInfoFromName(className, out interfaceInfo); } } if (classInfoToCreateRCW.IsNull) { classInfoToCreateRCW = classInfoInSignature; } // Use identity IUnknown to create the new RCW // @TODO: Transfer the ownership of ref count to the RCW if (classInfoToCreateRCW.IsNull) { // // Create a weakly typed RCW because we have no information about this particular RCW // @TODO - what if this RCW is not seen by MCG but actually exists in WinMD and therefore we // are missing GCPressure and ComMarshallingType information for this object? // comObject = new __ComObject(pComIdentityIUnknown, McgClassInfo.Null); } else { // // Create a strongly typed RCW based on McgClassInfo // comObject = CreateComObjectInternal(classInfoToCreateRCW, pComIdentityIUnknown); // Use identity IUnknown to create the new RCW } #if DEBUG // // Remember the runtime class name for debugging purpose // This way you can tell what the class name is, even when we failed to create a strongly typed // RCW for it // comObject.m_runtimeClassName = className; #endif // // Make sure we QI for that interface // if (!interfaceInfo.IsNull) { comObject.QueryInterface_NoAddRef_Internal(interfaceInfo, /* cacheOnly= */ false, /* throwOnQueryInterfaceFailure= */ false); } return(comObject); }