Re[16]: .Net Core Вызов виртуальных методов нативных объекто
От: pilgrim_ Россия  
Дата: 18.11.16 14:00
Оценка: 15 (1)
_>>Здравствуйте, Serginio1, Вы писали:

S>>>Попробовал с VMT

S>>>Определил методы

_>>Вот ты неуемный ты бы для начала проверил, работает ли COM-интероп на linux — ведь это же твоя цель?

_>>И если работает — тему можно закрывать, COM-интеропа тебе хватит за глаза.
_>>Или ты заради любви к искусству?

S> И то и другое. Да ине нужны мне методы IUknown. Я итак передаю нужныю ссылку, а подсчет ссылок если мне нужно организую сам.


S> Для приведения к интерфейсу при вызове одного метода идет куча QueryInterface Addref,Release

S>http://rsdn.org/forum/dotnet/6611240.1
Автор: pilgrim_
Дата: 15.11.16


Ну ежели упорный, вот смотри примерный вариант ручного маршалинга, а затем сравни его с автоматическим
Автор: pilgrim_
Дата: 15.11.16
(не забывая про разные C++ ABI)

  C++ native не-COM интерфейс
#include <stdio.h>
#include <cassert>


class ICallbackNotCom
{
public:
    virtual bool __stdcall release() = 0;
    virtual bool __stdcall execute() = 0;
    virtual bool __stdcall dispatch(ICallbackNotCom* other) = 0;
};

static void trace(const char* message)
{
    fprintf(stderr, "%s\n", message);
    //std::cout << message << std::endl;
}

class UnmanagedCallbackNotCom : public ICallbackNotCom
{
    static constexpr const char* Signature = "INTEROP";

    ICallbackNotCom* _other;
    const char* _sig;

private:
    void CheckSignature() const
    {
        assert(_sig == Signature);
    }

public:
    UnmanagedCallbackNotCom(ICallbackNotCom* other) : _other(other)
    {
        trace("ctor UnmanagedCallbackNotCom");
        _sig = Signature;
    }

    ~UnmanagedCallbackNotCom()
    {
        CheckSignature();
        trace("dtor UnmanagedCallbackNotCom");
    }


    //ICallbackNotCom

    bool __stdcall release() override
    {
        CheckSignature();
        trace("UnmanagedCallbackNotCom.release");
        delete this;
        return true;
    }

    bool __stdcall execute() override
    {
        CheckSignature();
        trace("UnmanagedCallbackNotCom.execute");
        _other->execute();
        return true;
    }

    bool __stdcall dispatch(ICallbackNotCom* other) override
    {
        CheckSignature();
        trace("UnmanagedCallbackNotCom.dispatch");
        if (other == nullptr) return false;

        _other->dispatch(other);

        return true;
    }
};

extern "C" __declspec(dllexport) ICallbackNotCom* __stdcall UnmanagedWrapCallbackNotCom(ICallbackNotCom* other)
{
    auto ucb = new UnmanagedCallbackNotCom(other);
    return ucb;
}



  C# .NET хост — ручной маршалинг интерфейсов в натив и обратно

    class Program
    {
        public interface ICallback
        {
            void Execute();

            void Dispatch(ICallback other);
        }

        public class ManagedCallback : ICallback
        {
            public void Execute()
            {
                Console.WriteLine($"{nameof(ManagedCallback)}.{nameof(Execute)}");
            }

            public void Dispatch(ICallback other)
            {
                Console.WriteLine($"{nameof(ManagedCallback)}.{nameof(Dispatch)}");
                other.Execute();
            }
        }

        [StructLayout(LayoutKind.Sequential)]
        public class NativeCallbackShim
        {
            [StructLayout(LayoutKind.Sequential)]
            public sealed class Vtbl
            {
                [UnmanagedFunctionPointer(CallingConvention.StdCall)]
                public delegate bool ReleaseHandler(IntPtr self);

                [UnmanagedFunctionPointer(CallingConvention.StdCall)]
                public delegate bool ExecuteHandler(IntPtr self);

                [UnmanagedFunctionPointer(CallingConvention.StdCall)]
                public delegate bool DispatchHandler(IntPtr self, IntPtr other);

                //GCC (Itanium ABI) specific
                //public IntPtr VTableEntry0;
                //public IntPtr VTableEntry1;

                public ReleaseHandler Release;
                public ExecuteHandler Execute;
                public DispatchHandler Dispatch;
            }

            protected IntPtr _vtblPtr;

            protected NativeCallbackShim()
            {
            }

            public NativeCallbackShim(IntPtr thisPtr)
            {
                var iface = Marshal.PtrToStructure<NativeCallbackShim>(thisPtr);
                _vtblPtr = iface._vtblPtr;
            }

            public static Vtbl GetVtbl(IntPtr thisPtr)
            {
                var iface = Marshal.PtrToStructure<NativeCallbackShim>(thisPtr);
                var vtbl = iface.GetVtbl();
                return vtbl;
            }

            public Vtbl GetVtbl() => Marshal.PtrToStructure<Vtbl>(_vtblPtr);
        }

        public sealed class NativeCallback : ICallback, IDisposable
        {
            private IntPtr _nativeCallbackPtr;
            private readonly NativeCallbackShim.Vtbl _vtbl;

            public NativeCallback(IntPtr callbackPtr)
            {
                _nativeCallbackPtr = callbackPtr;
                _vtbl = NativeCallbackShim.GetVtbl(callbackPtr);
            }

            public void Execute()
            {
                CheckDisposedState();
                _vtbl.Execute(_nativeCallbackPtr);
            }

            public void Dispatch(ICallback other)
            {
                CheckDisposedState();
                using (var shim = new Managed2NativeCallbackShim(other))
                {
                    _vtbl.Dispatch(_nativeCallbackPtr, shim.ToPointer());
                }
            }

            public void Dispose()
            {
                if (_nativeCallbackPtr != IntPtr.Zero)
                {
                    _vtbl.Release(_nativeCallbackPtr);
                    _nativeCallbackPtr = IntPtr.Zero;
                }
            }

            private void CheckDisposedState()
            {
                if (_nativeCallbackPtr == IntPtr.Zero)
                {
                    throw new ObjectDisposedException(nameof(NativeCallback));
                }
            }
        }

        [StructLayout(LayoutKind.Sequential)]
        public sealed class Managed2NativeCallbackShim : NativeCallbackShim, ICallback, IDisposable
        {
            [StructLayout(LayoutKind.Sequential)]
            private struct NativeInterfaceShim
            {
                public IntPtr vtblPtr;
            }

            private readonly Vtbl _vtbl; //note: keep reference to vtbl!
            private IntPtr _thisPtr;
            private readonly ICallback _callback;

            public Managed2NativeCallbackShim(ICallback cb)
            {
                _callback = cb;
                //note: keep reference to vtbl!
                _vtbl = new Vtbl
                {
                    Release = _ => true,
                    Execute = _ =>
                    {
                        Execute();
                        return true;
                    },
                    Dispatch = (_, other) =>
                    {
                        Dispatch(new NativeCallback(other));
                        return true;
                    }
                };

                var vtblSize = Marshal.SizeOf(_vtbl);
                _vtblPtr = Marshal.AllocHGlobal(vtblSize);
                Marshal.StructureToPtr(_vtbl, _vtblPtr, false);
            }

            public IntPtr ToPointer()
            {
                CheckDisposedState();
                if (_thisPtr == IntPtr.Zero)
                {
                    var shim = new NativeInterfaceShim { vtblPtr = _vtblPtr};
                    _thisPtr = Marshal.AllocHGlobal(Marshal.SizeOf(shim));
                    Marshal.StructureToPtr(shim, _thisPtr, false);
                }
                return _thisPtr;
            }

            public void Execute()
            {
                CheckDisposedState();
                _callback.Execute();
            }

            public void Dispatch(ICallback other)
            {
                CheckDisposedState();
                _callback.Dispatch(other);
            }

            public void Dispose()
            {
                if (_thisPtr != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(_thisPtr);
                    _thisPtr = IntPtr.Zero;
                }

                if (_vtblPtr != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(_vtblPtr);
                    _vtblPtr = IntPtr.Zero;
                }
            }

            private void CheckDisposedState()
            {
                if (_vtblPtr == IntPtr.Zero)
                {
                    throw new ObjectDisposedException(nameof(Managed2NativeCallbackShim));
                }
            }
        }

        [DllImport("Win32Project1.dll", CallingConvention = CallingConvention.StdCall)]
        static extern IntPtr UnmanagedWrapCallbackNotCom(IntPtr callback);


        static void Main()
        {
            Console.WriteLine("Press Enter key to continue...");
            //Console.ReadLine();

            TestNotComCallback();
        }


        static void TestNotComCallback()
        {
            var managedCallback = new ManagedCallback();
            var managedCallbackShim = new Managed2NativeCallbackShim(managedCallback);
            managedCallbackShim.Execute();

            var nativeCallbackPtr = UnmanagedWrapCallbackNotCom(managedCallbackShim.ToPointer());
            var nativeCallback = new NativeCallback(nativeCallbackPtr);

            try
            {
                nativeCallback.Execute();
                nativeCallback.Dispatch(managedCallbackShim);

                nativeCallback.Dispatch(nativeCallback);
            }
            finally
            {
                managedCallbackShim.Dispose();
                nativeCallback.Dispose();
            }

            GC.KeepAlive(managedCallbackShim);
        }

    }



  выхлоп
Project NotComInterop (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.
Press Enter key to continue...
ManagedCallback.Execute
ctor UnmanagedCallbackNotCom
UnmanagedCallbackNotCom.execute
ManagedCallback.Execute
UnmanagedCallbackNotCom.dispatch
ManagedCallback.Dispatch
ManagedCallback.Execute
UnmanagedCallbackNotCom.dispatch
ManagedCallback.Dispatch
UnmanagedCallbackNotCom.execute
ManagedCallback.Execute
UnmanagedCallbackNotCom.release
dtor UnmanagedCallbackNotCom
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.