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) { m_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]); Cache.Native.add(ptr, this); }