public static void managedAdd(IntPtr p, ManagedObject mo)
        {
            Debug.Assert(p != IntPtr.Zero);

            lock ( syncRoot )
            {
                Debug.Assert(!managed.ContainsKey(p));
                managed.Add(p, new WeakReference <ManagedObject>(mo));
            }
        }
        /// <summary>Create a factory which supports two-way marshaling.</summary>
        static Func <object, bool, IntPtr> createTwoWayFactory <I>(Guid iid) where I : class
        {
            // The builder gets captured by the lambda.
            // This is what we want, the constructor takes noticeable time, the code outside the lambda runs once per interface type, the code inside lambda runs once per object instance.
            InterfaceBuilder builder = new InterfaceBuilder(typeof(I));

            return((object obj, bool addRef) =>
            {
                if (null == obj)
                {
                    // Marshalling null
                    return IntPtr.Zero;
                }
                Debug.Assert(obj is I);

                if (obj is RuntimeClass 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;
            });
        }
示例#3
0
        /// <summary>Create a factory which only supports objects implemented in .NET. Will throw an exception when given a COM object which is not implemented in C#.</summary>
        static Func <IntPtr, object> createOneWayToNativeFactory(Type tInterface)
        {
            string directionNotSupportedError = $"The COM interface { tInterface.FullName } doesn't support native to managed marshaling direction";

            return(( IntPtr pNative ) =>
            {
                if (pNative == IntPtr.Zero)
                {
                    return null;
                }
                ManagedObject mo = Cache.Managed.lookup(pNative);
                if (null != mo)
                {
                    return mo.managed;
                }
                throw new NotSupportedException(directionNotSupportedError);
            });
        }
        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);
            }
        }
 public static void add(I obj, ManagedObject wrapper)
 {
     table.Add(obj, wrapper);
 }