static Func <IntPtr, object> getFactory(Type tInterface) { Func <IntPtr, object> factory = null; lock ( syncRoot ) { if (factories.TryGetValue(tInterface, out factory)) { return(factory); } Func <IntPtr, object> newProxy = Proxy.build(tInterface); factory = ( IntPtr pNative ) => { RuntimeClass rc = LiveObjectsCache.nativeLookup(pNative); if (null != rc) { return(rc); } ManagedObject mo = LiveObjectsCache.managedLookup(pNative); if (null != mo) { return(mo.managed); } return(newProxy(pNative)); }; factories.Add(tInterface, factory); return(factory); } }
public ManagedObject(object managed, Guid iid, Delegate[] delegates) { this.managed = managed; this.iid = iid; IntPtr[] nativeTable = new IntPtr[delegates.Length + 4]; gchNativeData = GCHandle.Alloc(nativeTable, GCHandleType.Pinned); LiveObjectsCache.managedAdd(address, this); // A COM pointer is an address of address: "this" points to vtable pointer, vtable pointer points to the first vtable entry, the rest of the entries follow. // We want binary compatibility, so nativeTable[ 0 ] contains address of nativeTable[ 1 ], and methods function pointers start at nativeTable[ 1 ]. nativeTable[0] = address + Marshal.SizeOf <IntPtr>(); // Build 3 first entries of the vtable, with IUnknown methods queryInterface = delegate(IntPtr pThis, ref Guid ii, out IntPtr result) { Debug.Assert(pThis == address); return(implQueryInterface(ref ii, out result)); }; nativeTable[1] = Marshal.GetFunctionPointerForDelegate(queryInterface); addRef = delegate(IntPtr pThis) { Debug.Assert(pThis == address); return(implAddRef()); }; nativeTable[2] = Marshal.GetFunctionPointerForDelegate(addRef); release = delegate(IntPtr pThis) { Debug.Assert(pThis == address); return(implRelease()); }; nativeTable[3] = Marshal.GetFunctionPointerForDelegate(release); // Custom methods entries of the vtable for (int i = 0; i < delegates.Length; i++) { nativeTable[i + 4] = Marshal.GetFunctionPointerForDelegate(delegates[i]); } ; }
/// <summary>Construct the wrapper.</summary> public RuntimeClass(IntPtr ptr, IntPtr[] vtbl, Guid iid) { nativePointer = ptr; this.iid = iid; QueryInterface = Marshal.GetDelegateForFunctionPointer <IUnknown.QueryInterface>(vtbl[0]); AddRef = Marshal.GetDelegateForFunctionPointer <IUnknown.AddRef>(vtbl[1]); Release = Marshal.GetDelegateForFunctionPointer <IUnknown.Release>(vtbl[2]); LiveObjectsCache.nativeAdd(ptr, this); }
/// <summary>Release native COM pointer. If it reaches 0, causes C++ to run `delete this`. Safe to be called multiple times, only the first one will work.</summary> public void releaseInterfacePointer() { if (!pointerReleased) { pointerReleased = true; if (nativePointer != IntPtr.Zero) { LiveObjectsCache.nativeDrop(nativePointer); Release(nativePointer); } } }
public IntPtr wrap(T managed, bool addRef) { lock ( syncRoot ) { object cached; IntPtr result; if (native.TryGetValue(managed, out cached)) { result = (IntPtr)cached; if (addRef) { LiveObjectsCache.addRef(result); } return(result); } result = factory(managed, addRef); native.Add(managed, result); return(result); } }