using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; namespace CPF.Windows.MicroCom { public static unsafe class MicroComRuntime { private static ConcurrentDictionary _vtables = new ConcurrentDictionary(); private static ConcurrentDictionary> _factories = new ConcurrentDictionary>(); private static ConcurrentDictionary _guids = new ConcurrentDictionary(); private static ConcurrentDictionary _guidsToTypes = new ConcurrentDictionary(); static MicroComRuntime() { Register(typeof(IUnknown), new Guid("00000000-0000-0000-C000-000000000046"), (ppv, owns) => new MicroComProxyBase(ppv, owns)); RegisterVTable(typeof(IUnknown), MicroComVtblBase.Vtable); } public static void RegisterVTable(Type t, IntPtr vtable) { _vtables[t] = vtable; } public static void Register(Type t, Guid guid, Func proxyFactory) { _factories[t] = proxyFactory; _guids[t] = guid; _guidsToTypes[guid] = t; } public static Guid GetGuidFor(Type type) => _guids[type]; public static T CreateProxyFor(void* pObject, bool ownsHandle) => (T)CreateProxyFor(typeof(T), new IntPtr(pObject), ownsHandle); public static T CreateProxyFor(IntPtr pObject, bool ownsHandle) => (T)CreateProxyFor(typeof(T), pObject, ownsHandle); public static object CreateProxyFor(Type type, IntPtr pObject, bool ownsHandle) => _factories[type](pObject, ownsHandle); public static IntPtr GetNativeIntPtr(this T obj, bool owned = false) where T : IUnknown => new IntPtr(GetNativePointer(obj, owned)); public static void* GetNativePointer(T obj, bool owned = false) where T : IUnknown { if (obj == null) return null; if (obj is MicroComProxyBase proxy) { if (owned) proxy.AddRef(); return (void*)proxy.NativePointer; } if (obj is IMicroComShadowContainer container) { //container.Shadow ??= new MicroComShadow(container); if (container.Shadow==null) { container.Shadow = new MicroComShadow(container); } void* ptr = null; var res = container.Shadow.GetOrCreateNativePointer(typeof(T), &ptr); if (res != 0) throw new COMException( "Unable to create native callable wrapper for type " + typeof(T) + " for instance of type " + obj.GetType(), res); if (owned) container.Shadow.AddRef((Ccw*)ptr); return ptr; } throw new ArgumentException("Unable to get a native pointer for " + obj); } public static object GetObjectFromCcw(IntPtr ccw) { var ptr = (Ccw*)ccw; var shadow = (MicroComShadow)GCHandle.FromIntPtr(ptr->GcShadowHandle).Target; return shadow.Target; } public static bool TryGetTypeForGuid(Guid guid, out Type t) => _guidsToTypes.TryGetValue(guid, out t); public static bool GetVtableFor(Type type, out IntPtr ptr) => _vtables.TryGetValue(type, out ptr); public static void UnhandledException(object target, Exception e) { if (target is IMicroComExceptionCallback cb) { try { cb.RaiseException(e); } catch { // We've tried } } } public static T CloneReference(this T iface) where T : IUnknown { var proxy = (MicroComProxyBase)(object)iface; var ownedPointer = GetNativePointer(iface, true); return CreateProxyFor(ownedPointer, true); } public static T QueryInterface(this IUnknown unknown) where T : IUnknown { var proxy = (MicroComProxyBase)unknown; return proxy.QueryInterface(); } public static void UnsafeAddRef(this IUnknown unknown) { ((MicroComProxyBase)unknown).AddRef(); } public static void UnsafeRelease(this IUnknown unknown) { ((MicroComProxyBase)unknown).Release(); } } }