/// <summary> /// Gets a list of interfaces implemented by <paramref name="type"/> that aren't inherited by any other shadowed interfaces. /// </summary> /// <param name="type">The type for which to get the list.</param> /// <returns>The interface list.</returns> private static List <Type> GetUninheritedShadowedInterfaces(Type type) { // Cache reflection on interface inheritance lock (typeToShadowTypes) { if (!typeToShadowTypes.TryGetValue(type, out List <Type> cachedInterfaces)) { var interfaces = type.GetTypeInfo().ImplementedInterfaces.ToList(); typeToShadowTypes.Add(type, interfaces); var interfacesToRemove = new List <Type>(); // First pass to identify most detailed interfaces foreach (var item in interfaces) { // Only process interfaces that are using shadow var shadowAttribute = ShadowAttribute.Get(item); if (shadowAttribute == null) { interfacesToRemove.Add(item); continue; } // Keep only final interfaces and not intermediate. var inheritList = item.GetTypeInfo().ImplementedInterfaces; foreach (var inheritInterface in inheritList) { interfacesToRemove.Add(inheritInterface); } } foreach (var toRemove in interfacesToRemove) { interfaces.Remove(toRemove); } return(interfaces); } return(cachedInterfaces); } }
internal void Initialize(ICallbackable callbackable) { callbackable.Shadow = this; var type = callbackable.GetType(); List <Type> slimInterfaces; // Cache reflection on COM interface inheritance lock (typeToShadowTypes) { if (!typeToShadowTypes.TryGetValue(type, out slimInterfaces)) { #if NET40 var interfaces = type.GetTypeInfo().GetInterfaces(); #else var interfaces = type.GetTypeInfo().ImplementedInterfaces; #endif slimInterfaces = new List <Type>(); slimInterfaces.AddRange(interfaces); typeToShadowTypes.Add(type, slimInterfaces); // First pass to identify most detailed interfaces foreach (var item in interfaces) { // Only process interfaces that are using shadow var shadowAttribute = ShadowAttribute.Get(item); if (shadowAttribute == null) { slimInterfaces.Remove(item); continue; } // Keep only final interfaces and not intermediate. #if NET40 var inheritList = item.GetTypeInfo().GetInterfaces(); #else var inheritList = item.GetTypeInfo().ImplementedInterfaces; #endif foreach (var inheritInterface in inheritList) { slimInterfaces.Remove(inheritInterface); } } } } CppObjectShadow iunknownShadow = null; // Second pass to instantiate shadow foreach (var item in slimInterfaces) { // Only process interfaces that are using shadow var shadowAttribute = ShadowAttribute.Get(item); // Initialize the shadow with the callback var shadow = (CppObjectShadow)Activator.CreateInstance(shadowAttribute.Type); shadow.Initialize(callbackable); // Take the first shadow as the main IUnknown if (iunknownShadow == null) { iunknownShadow = shadow; // Add IUnknown as a supported interface guidToShadow.Add(ComObjectShadow.IID_IUnknown, iunknownShadow); } guidToShadow.Add(Utilities.GetGuidFromType(item), shadow); // Associate also inherited interface to this shadow #if NET40 var inheritList = item.GetTypeInfo().GetInterfaces(); #else var inheritList = item.GetTypeInfo().ImplementedInterfaces; #endif foreach (var inheritInterface in inheritList) { var inheritShadowAttribute = ShadowAttribute.Get(inheritInterface); if (inheritShadowAttribute == null) { continue; } // Use same shadow as derived guidToShadow.Add(Utilities.GetGuidFromType(inheritInterface), shadow); } } // Precalculate the list of GUID without IUnknown and IInspectable // Used for WinRT int countGuids = 0; foreach (var guidKey in guidToShadow.Keys) { if (guidKey != Utilities.GetGuidFromType(typeof(IInspectable)) && guidKey != Utilities.GetGuidFromType(typeof(IUnknown))) { countGuids++; } } guidPtr = Marshal.AllocHGlobal(Utilities.SizeOf <Guid>() * countGuids); Guids = new IntPtr[countGuids]; int i = 0; unsafe { var pGuid = (Guid *)guidPtr; foreach (var guidKey in guidToShadow.Keys) { if (guidKey == Utilities.GetGuidFromType(typeof(IInspectable)) || guidKey == Utilities.GetGuidFromType(typeof(IUnknown))) { continue; } pGuid[i] = guidKey; // Store the pointer Guids[i] = new IntPtr(pGuid + i); i++; } } }
internal ShadowContainer(ICallbackable callbackable) { var type = callbackable.GetType(); var guidList = new List <Guid>(); // Associate all shadows with their interfaces. foreach (var item in GetUninheritedShadowedInterfaces(type)) { var shadowAttribute = ShadowAttribute.Get(item); // Initialize the shadow with the callback var shadow = (CppObjectShadow)Activator.CreateInstance(shadowAttribute.Type); shadow.Initialize(callbackable); guidToShadow.Add(item.GetTypeInfo().GUID, shadow); if (item.GetTypeInfo().GetCustomAttribute <ExcludeFromTypeListAttribute>() != null) { guidList.Add(item.GetTypeInfo().GUID); } // Associate also inherited interface to this shadow var inheritList = item.GetTypeInfo().ImplementedInterfaces; foreach (var inheritInterface in inheritList) { // If there isn't a Shadow attribute then this isn't a native interface. var inheritShadowAttribute = ShadowAttribute.Get(inheritInterface); if (inheritShadowAttribute == null) { continue; } // If we have the same GUID as an already added interface, // then there's already an accurate shadow for it, so we have nothing to do. if (guidToShadow.ContainsKey(inheritInterface.GetTypeInfo().GUID)) { continue; } // Use same shadow as derived guidToShadow.Add(inheritInterface.GetTypeInfo().GUID, shadow); if (inheritInterface.GetTypeInfo().GetCustomAttribute <ExcludeFromTypeListAttribute>() != null) { guidList.Add(inheritInterface.GetTypeInfo().GUID); } } } var guidCount = guidList.Count; Guids = new IntPtr[guidCount]; guidPtr = Marshal.AllocHGlobal(Unsafe.SizeOf <Guid>() * guidCount); unsafe { var i = 0; var pGuid = (Guid *)guidPtr; foreach (var guidKey in guidList) { pGuid[i] = guidKey; // Store the pointer Guids[i] = new IntPtr(pGuid + i); i++; } } }