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); } }
/// <summary>Create a factory which supports two-way marshaling.</summary> static Func <IntPtr, object> createTwoWayFactory(Type tInterface) { Func <IntPtr, object> newProxy = Proxy.build(tInterface); return(( IntPtr pNative ) => { if (pNative == IntPtr.Zero) { return null; } RuntimeClass rc = Cache.Native.lookup(pNative, tInterface); if (null != rc) { return rc; } ManagedObject mo = Cache.Managed.lookup(pNative); if (null != mo) { return mo.managed; } return newProxy(pNative); }); }
public static void nativeAdd(IntPtr p, RuntimeClass rc) { Debug.Assert(p != IntPtr.Zero); lock ( syncRoot ) { Debug.Assert(!native.ContainsKey(p)); native.Add(p, new WeakReference <RuntimeClass>(rc)); } }
static Func <object, bool, IntPtr> getFactory <I>() where I : class { Type tInterface = typeof(I); Func <object, bool, IntPtr> result; lock ( syncRoot ) { if (cache.TryGetValue(tInterface, out result)) { return(result); } Guid iid = ReflectionUtils.checkInterface(tInterface); // The builder gets captured by the lambda. // This is what we want, the constructor takes noticeable time, the code outside lambda runs once per interface type, the code inside lambda runs once per object instance. InterfaceBuilder builder = new InterfaceBuilder(tInterface); result = (object obj, bool addRef) => { if (null == obj) { // Marshalling null return(IntPtr.Zero); } Debug.Assert(obj is I); RuntimeClass rc = obj as RuntimeClass; if (null != rc) { // That .NET object is not actually managed, it's a wrapper around C++ implemented COM interface. if (rc.iid == iid) { // It wraps around the same interface if (addRef) { rc.addRef(); } return(rc.nativePointer); } // It wraps around different interface. Call QueryInterface on the native object. return(rc.queryInterface(iid, addRef)); } // It could be the same managed object is reused across native calls. If that's the case, the cache already contains the native pointer. I managed = (I)obj; IntPtr?wrapped = WrappersCache <I> .lookup(managed); if (wrapped.HasValue) { return(wrapped.Value); } Delegate[] delegates = builder.compile(managed); ManagedObject wrapper = new ManagedObject(managed, iid, delegates); WrappersCache <I> .add(managed, wrapper); if (addRef) { wrapper.callAddRef(); } return(wrapper.address); }; cache.Add(tInterface, result); return(result); } }