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);
     }
 }