Re[3]: .Net Core Вызов виртуальных методов нативных объектов
От: α Российская Империя  
Дата: 14.11.16 08:01
Оценка:
Здравствуйте, Serginio1, Вы писали:

α>>В мсдн пишут что в принципе можно, но саму структуру классов с++ надо заранее проектировать под интеграцию с .net. Для остальных случаев рекомендуют оборачивать общение с классами с++ в с-api


S> Мне как раз и нужно вызывать нативные методы из .Net


Всё равно все сводится к соответствующей подготовке кода на С++ к interop/pinvoke. А это либо как уже тут сказали — COM, либо обертка в виде С-plain-API, либо вот такие фокусы — https://blogs.msdn.microsoft.com/vcblog/2008/12/08/inheriting-from-a-native-c-class-in-c/
Re[7]: .Net Core Вызов виртуальных методов нативных объектов
От: Lexey Россия  
Дата: 14.11.16 10:31
Оценка:
Здравствуйте, Serginio1, Вы писали:

S> Так суть COM это VMT. А она по сути кроссплатформенна.


С каких это пор реализации VMT стали кроссплатформенными?
Re[8]: .Net Core Вызов виртуальных методов нативных объектов
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 14.11.16 11:00
Оценка:
Здравствуйте, Lexey, Вы писали:

L>Здравствуйте, Serginio1, Вы писали:


S>> Так суть COM это VMT. А она по сути кроссплатформенна.


L>С каких это пор реализации VMT стали кроссплатформенными?

http://rsdn.org/forum/dotnet/6608772.1
Автор: Serginio1
Дата: 13.11.16


Реально работает на линукс
и солнце б утром не вставало, когда бы не было меня
Re[4]: .Net Core Вызов виртуальных методов нативных объектов
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 14.11.16 11:43
Оценка:
Здравствуйте, α, Вы писали:

α>Здравствуйте, Serginio1, Вы писали:


α>>>В мсдн пишут что в принципе можно, но саму структуру классов с++ надо заранее проектировать под интеграцию с .net. Для остальных случаев рекомендуют оборачивать общение с классами с++ в с-api


S>> Мне как раз и нужно вызывать нативные методы из .Net


α>Всё равно все сводится к соответствующей подготовке кода на С++ к interop/pinvoke. А это либо как уже тут сказали — COM, либо обертка в виде С-plain-API, либо вот такие фокусы — https://blogs.msdn.microsoft.com/vcblog/2008/12/08/inheriting-from-a-native-c-class-in-c/




Это видел. Решил поэксперементировать.

В .Net определил интерфейс


[ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
   public interface ICallback
    {
        void execute();
    }


и сделал статический метод

public static void CallInterface(ICallback cb)
        {
            cb.execute();

        }


В С++ определил класс
class ICallback :public IUnknown
    {
    public:
        
        virtual HRESULT __stdcall execute();


        // Унаследовано через IUnknown
        virtual HRESULT __stdcall QueryInterface(REFIID riid, void ** ppvObject) override;

        virtual ULONG __stdcall AddRef(void) override;

        virtual ULONG __stdcall Release(void) override;

    };


и реализацию

    HRESULT ICallback::execute()
    {
        
        wprintf_s(L" %s\n", L"ICallback from.Net");
        return NOERROR;
    }

    HRESULT ICallback::QueryInterface(REFIID riid, void ** ppvObject)
    {
        if (!ppvObject)
            return E_INVALIDARG;
        *ppvObject = NULL;
    //    if (riid == IID_IUnknown)
    //    {
            // Increment the reference count and return the pointer.
            *ppvObject = (LPVOID)this;
            return NOERROR;
  //        }
        return E_NOINTERFACE;
    }


    ULONG ICallback::AddRef(void)
    {
        return 1;
    }

    ULONG ICallback::Release(void)
    {
        return 0;
    }


Описание вызывемого метода из .Net Core

typedef void(STDMETHODCALLTYPE *ManagedRunCallback)(ICallback*);


Получаю ссылку на метод и вызываю
if (!CreateDelegate(domainId, L"CallInterface", (INT_PTR*)&pRunCallback)) return false;

        ICallback* cb = new ICallback();
        pRunCallback(cb);


Так вот перед вызовом execute сначала запрашиваеется QueryInterface с двумя riid IUnknown и IProvideClassInfo

Если не дать IProvideClassInfo то начинает запрашивать Idispatch и еще какие то интерфейсы.

И метод не вызывается.

Если же вернуть IProvideClassInfo сылку на this то метод вызывается и в консоли виден текст, но завершается ошибкой доступа памяти
и солнце б утром не вставало, когда бы не было меня
Re[5]: .Net Core Вызов виртуальных методов нативных объектов
От: α Российская Империя  
Дата: 14.11.16 11:58
Оценка:
Здравствуйте, Serginio1, Вы писали:

S> В С++ определил класс

S>class ICallback : public IUnknown

А упорядочить методы тут разве не надо? Т.е. сперва методы IUnknown, потом твой execute(). Что-то я уже подзабыл
PS А, это ж класс, а не интерфейс. Перепутал
Отредактировано 14.11.2016 12:00 α . Предыдущая версия .
Re[6]: .Net Core Вызов виртуальных методов нативных объектов
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 14.11.16 12:18
Оценка:
Здравствуйте, α, Вы писали:

α>Здравствуйте, Serginio1, Вы писали:


S>> В С++ определил класс

S>>class ICallback : public IUnknown

α>А упорядочить методы тут разве не надо? Т.е. сперва методы IUnknown, потом твой execute(). Что-то я уже подзабыл

α>PS А, это ж класс, а не интерфейс. Перепутал

так упорядочено по наследованию. IUnknown

вообще структура.

Переделал на
struct ICallback : IUnknown
    {
    public:
        
        


        // Унаследовано через IUnknown
        virtual HRESULT __stdcall QueryInterface(REFIID riid, void ** ppvObject) override;

        virtual ULONG __stdcall AddRef(void) override;

        virtual ULONG __stdcall Release(void) override;

        virtual HRESULT __stdcall execute();

    };


Эффект тот же.

Вызвано исключение по адресу 0x52684880 (coreclr.dll) в TestNetObjectToNative.exe: 0xC0000005: нарушение прав доступа при чтении по адресу 0x963E0B26.


Подозреваю из-за IProvideClassInfo.

Я на С++ пишу раз в год.
и солнце б утром не вставало, когда бы не было меня
Re[7]: .Net Core Вызов виртуальных методов нативных объектов
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 15.11.16 07:37
Оценка:
Здравствуйте, Serginio1, Вы писали:

Переделал

[ComImport, Guid("F2DAEB5F-228F-47AA-93B2-E81D46194FA8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
   public interface ICallback
    {
        void execute(int value);
    }


и вызоа

 public static void CallInterface(ICallback cb)
        {
            cb.execute(555);

        }

И на С++

HRESULT __stdcall ICallback::execute(int value)
    {
        
        wprintf_s(L"ICallback from.Net %d\n", value);
        return NOERROR;
    }


В итоге value отлично от 555
Значит вызывается единственный метод IProvideClassInfo GetClassInfo

Попробую проверку на GUID/ Но смотрел вроде нет его.
и солнце б утром не вставало, когда бы не было меня
Re[5]: .Net Core Вызов виртуальных методов нативных объектов
От: pilgrim_ Россия  
Дата: 15.11.16 19:00
Оценка: 15 (1)
Здравствуйте, Serginio1, Вы писали:

S>В .Net определил интерфейс



S>
S>[ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
S>   public interface ICallback
S>    {
S>        void execute();
S>    }
S>


Нужно явно задать id интерфейса (IID — GuidAttribute)..

S> и реализацию

S>
S>    HRESULT ICallback::QueryInterface(REFIID riid, void ** ppvObject)
S>    {
S>        if (!ppvObject)
S>            return E_INVALIDARG;
S>        *ppvObject = NULL;
S>    //    if (riid == IID_IUnknown)
S>    //    {
S>            // Increment the reference count and return the pointer.
S>            *ppvObject = (LPVOID)this; //тут кастовать нужно к требуемому интерфейсу
S>            return NOERROR;
S>  //        }
S>        return E_NOINTERFACE;
S>    }

S>


См. выделенное
-ты должен проверять поддерживаемые тобой интерфейсы (как минимум IUnknown)
-и возвращать правильную ссылку на них (с пом. приведения — чтобы получить правильное смещение на vtable)

S> Так вот перед вызовом execute сначала запрашиваеется QueryInterface с двумя riid IUnknown и IProvideClassInfo

S>Если не дать IProvideClassInfo то начинает запрашивать Idispatch и еще какие то интерфейсы.

Ты должен правильно реагировать на эти запросы — реализуешь — возвращай, нет — досвидания, в твоем случае как минимум 2 интерфейса ты поддерживаешь — IUnknown и твой ICallback

Рабочий пример (хост — .net приложение, в случае хостинга как у тебя из нативного приложения результат должен быть такой же)

  нативный код (dll)
#include <windows.h>
#include <iostream>


//COM sample

class ICallback : public IUnknown
{
public:
    virtual HRESULT __stdcall execute() = 0;
    virtual HRESULT __stdcall dispatch(ICallback* other) = 0;
};


extern "C"  __declspec(dllexport) ICallback* __stdcall UnmanagedWrapCallback(ICallback* cb);

// {FFB46654-083E-486A-94B8-E28B5C01561D}
static const GUID IID_ICallback =
{ 0xffb46654, 0x83e, 0x486a,{ 0x94, 0xb8, 0xe2, 0x8b, 0x5c, 0x1, 0x56, 0x1d } };


class UnmanagedCallback : public ICallback
{
    ULONG _refCount;
    ICallback* _other;
public:
    UnmanagedCallback(ICallback* other) : _refCount(1), _other(other)
    {
        std::cout << "ctor UnmanagedCallback" << std::endl;
        _other->AddRef();
    }

    ~UnmanagedCallback()
    {
        std::cout << "dtor UnmanagedCallback" << std::endl;
        _other->Release();
    }

    //IUnknown
    HRESULT __stdcall QueryInterface(REFIID riid, void ** ppvObject) override
    {
        OLECHAR* strGuid;
        StringFromCLSID(riid, &strGuid);
        std::wcout << L"UnmanagedCallback.QueryInterface. Requested IID: " << strGuid << std::endl;
        CoTaskMemFree(strGuid);
            
        if (ppvObject == nullptr) return E_INVALIDARG;

        if (riid == IID_IUnknown)
        {
            *ppvObject = static_cast<IUnknown*>(this);
            AddRef();
            return S_OK;
        }
        else if (riid == IID_ICallback)
        {
            *ppvObject = static_cast<ICallback*>(this);
            AddRef();
            return S_OK;
        }

        *ppvObject = nullptr;

        return E_NOINTERFACE;
    }

    ULONG __stdcall AddRef(void) override
    {
        std::cout << "UnmanagedCallback.AddRef" << std::endl;
        auto cnt = ++_refCount;
        return cnt;
    }

    ULONG __stdcall Release(void) override
    {
        std::cout << "UnmanagedCallback.Release" << std::endl;
        auto cnt = --_refCount;
        if (cnt == 0)
        {
            delete this;
        }
        return cnt;
    }

    //ICallback

    HRESULT __stdcall execute() override
    {
        std::cout << "UnmanagedCallback.execute" << std::endl;
        _other->execute();
        return S_OK;
    }

    HRESULT __stdcall dispatch(ICallback* other) override
    {
        std::cout << "UnmanagedCallback.dispatch" << std::endl;
        if (other == nullptr) return E_INVALIDARG;

        _other->dispatch(other);

        return S_OK;
    }
};


extern "C" __declspec(dllexport) ICallback* __stdcall UnmanagedWrapCallback(ICallback* other)
{
    auto ucb = new UnmanagedCallback(other);
    return ucb;
}


  ComCallback.cs — .net консольное приложение
    class Program
    {
        #region COM interop

        [ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        [Guid("FFB46654-083E-486A-94B8-E28B5C01561D")]
        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();
            }
        }

        [DllImport("Win32Project1.dll", CallingConvention = CallingConvention.StdCall)]
        private static extern ICallback UnmanagedWrapCallback(ICallback cb);

        #endregion COM interop


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

            TestComCallback();
        }

        static void TestComCallback()
        {
            var mcb = new ManagedCallback();
            mcb.Execute();

            WrapUnmanaged(mcb);
        }

        static void WrapUnmanaged(ICallback cb)
        {
            var ucb = UnmanagedWrapCallback(cb);

            try
            {
                ucb.Execute();
                ucb.Dispatch(cb);
            }
            finally
            {
                Marshal.ReleaseComObject(ucb);
            }
        }
    }



Проверил на .NET Core dotnet-dev-win-x86.1.0.0-preview2-003131 — все работает как и в "большом" .NET, значит как минимум для windows поддержка COM-interop реализованна.

  выхлоп
Project ComInterop (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.
Press Enter key to continue...
ManagedCallback.Execute
ctor UnmanagedCallback
UnmanagedCallback.QueryInterface. Requested IID: {00000000-0000-0000-C000-000000000046}
UnmanagedCallback.AddRef
UnmanagedCallback.QueryInterface. Requested IID: {B196B283-BAB4-101A-B69C-00AA00341D07}
UnmanagedCallback.AddRef
UnmanagedCallback.QueryInterface. Requested IID: {ECC8691B-C1DB-4DC0-855E-65F6C551AF49}
UnmanagedCallback.QueryInterface. Requested IID: {94EA2B94-E9CC-49E0-C0FF-EE64CA8F5B90}
UnmanagedCallback.QueryInterface. Requested IID: {00000003-0000-0000-C000-000000000046}
UnmanagedCallback.QueryInterface. Requested IID: {00000144-0000-0000-C000-000000000046}
UnmanagedCallback.Release
UnmanagedCallback.QueryInterface. Requested IID: {FFB46654-083E-486A-94B8-E28B5C01561D}
UnmanagedCallback.AddRef
UnmanagedCallback.AddRef
UnmanagedCallback.Release
UnmanagedCallback.Release
UnmanagedCallback.execute
ManagedCallback.Execute
UnmanagedCallback.dispatch
ManagedCallback.Dispatch
ManagedCallback.Execute
UnmanagedCallback.Release
UnmanagedCallback.Release
dtor UnmanagedCallback
Re[6]: .Net Core Вызов виртуальных методов нативных объектов
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 16.11.16 08:15
Оценка:
Здравствуйте, pilgrim_, Вы писали:
Огромнейшее спасибо!


Проблема была в прямом использовании ICallback

Но вот куча

[ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [Guid("FFB46654-083E-486A-94B8-E28B5C01561D")]
    public interface ICallback
    {
        void execute(int value);
    }



То есть вместо

public static void CallInterface(ICallback cb)
        {
            cb.execute();

        }



Нужно использовать


      public static void CallInterface(IntPtr cb)
        {

            var cb2 = Marshal.GetObjectForIUnknown(cb)  as ICallback;

            cb2?.execute(555);

        }


Но вот на 1 вызов куча QueryInterface, AddRef и Release это конечно
и солнце б утром не вставало, когда бы не было меня
Re: .Net Core Вызов виртуальных методов нативных объектов
От: ajanov  
Дата: 16.11.16 08:19
Оценка:
Здравствуйте, Serginio1, Вы писали:


S> Возможно ли вызвать виртуальные методы С++ классов из .Net Core.


S> Да и как там в .Net Core C++/CLI ?


Компилятор C++/CLI берет все заботы на себя
Re[2]: .Net Core Вызов виртуальных методов нативных объектов
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 16.11.16 08:27
Оценка:
Здравствуйте, ajanov, Вы писали:

A>Здравствуйте, Serginio1, Вы писали:



S>> Возможно ли вызвать виртуальные методы С++ классов из .Net Core.


S>> Да и как там в .Net Core C++/CLI ?


A>Компилятор C++/CLI берет все заботы на себя


А какие опции под .Net Core? Просто я в С++ новичок
и солнце б утром не вставало, когда бы не было меня
Re[3]: .Net Core Вызов виртуальных методов нативных объектов
От: ajanov  
Дата: 16.11.16 08:57
Оценка:
Здравствуйте, Serginio1, Вы писали:

S>Здравствуйте, ajanov, Вы писали:


A>>Здравствуйте, Serginio1, Вы писали:



S>>> Возможно ли вызвать виртуальные методы С++ классов из .Net Core.


S>>> Да и как там в .Net Core C++/CLI ?


A>>Компилятор C++/CLI берет все заботы на себя


S> А какие опции под .Net Core? Просто я в С++ новичок


Не заметил, что про .Net Core речь идет Прошу прощения. Боюсь, что и про C++/CLI наврал
Re[4]: .Net Core Вызов виртуальных методов нативных объектов
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 16.11.16 09:53
Оценка:
Здравствуйте, ajanov, Вы писали:

S>> А какие опции под .Net Core? Просто я в С++ новичок


A>Не заметил, что про .Net Core речь идет Прошу прощения. Боюсь, что и про C++/CLI наврал

Да нет на C++/CLI это легко
https://blogs.msdn.microsoft.com/junfeng/2006/05/20/sample-mixing-unmanaged-c-ccli-and-c-code/
http://stackoverflow.com/questions/15598445/is-it-possible-to-run-unmanaged-c-normally-from-a-managed-c-cli-project
и солнце б утром не вставало, когда бы не было меня
Отредактировано 16.11.2016 9:57 Serginio1 . Предыдущая версия .
Re[5]: .Net Core Вызов виртуальных методов нативных объектов
От: ajanov  
Дата: 16.11.16 10:10
Оценка: 10 (1)
Здравствуйте, Serginio1, Вы писали:

S>Здравствуйте, ajanov, Вы писали:


S>>> А какие опции под .Net Core? Просто я в С++ новичок


A>>Не заметил, что про .Net Core речь идет Прошу прощения. Боюсь, что и про C++/CLI наврал

S> Да нет на C++/CLI это легко
S>https://blogs.msdn.microsoft.com/junfeng/2006/05/20/sample-mixing-unmanaged-c-ccli-and-c-code/
S>http://stackoverflow.com/questions/15598445/is-it-possible-to-run-unmanaged-c-normally-from-a-managed-c-cli-project

Если все как в .Net Framework — то вперед, даже существующие библиотеки не нужно адаптировать, чтобы их использовать в .Net. В C++ проекте настройку General->Common Language Runtime support нужно установить в Common Language Runtime Support (/clr). Полезный раздел о поддержке .Net в C++: https://msdn.microsoft.com/en-us/library/68td296t(v=vs.140).aspx
Re[6]: .Net Core Вызов виртуальных методов нативных объектов
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 16.11.16 10:21
Оценка:
Здравствуйте, ajanov, Вы писали:


A>Если все как в .Net Framework — то вперед, даже существующие библиотеки не нужно адаптировать, чтобы их использовать в .Net. В C++ проекте настройку General->Common Language Runtime support нужно установить в Common Language Runtime Support (/clr). Полезный раздел о поддержке .Net в C++: https://msdn.microsoft.com/en-us/library/68td296t(v=vs.140).aspx


Спасибо! К сожалению у них нет никакого плана для поддержки C ++ / CLI с .NET Core
http://stackoverflow.com/questions/39140014/c-cli-support-in-net-core
и солнце б утром не вставало, когда бы не было меня
Re[7]: .Net Core Вызов виртуальных методов нативных объектов
От: ajanov  
Дата: 16.11.16 12:23
Оценка: +1
Здравствуйте, Serginio1, Вы писали:

S>Здравствуйте, ajanov, Вы писали:



A>>Если все как в .Net Framework — то вперед, даже существующие библиотеки не нужно адаптировать, чтобы их использовать в .Net. В C++ проекте настройку General->Common Language Runtime support нужно установить в Common Language Runtime Support (/clr). Полезный раздел о поддержке .Net в C++: https://msdn.microsoft.com/en-us/library/68td296t(v=vs.140).aspx


S> Спасибо! К сожалению у них нет никакого плана для поддержки C ++ / CLI с .NET Core

S>http://stackoverflow.com/questions/39140014/c-cli-support-in-net-core

Десиплюсплюсизация от Майкрософт
Re[8]: .Net Core Вызов виртуальных методов нативных объектов
От: fddima  
Дата: 16.11.16 12:54
Оценка: 5 (1) +1
Здравствуйте, ajanov, Вы писали:

A>Десиплюсплюсизация от Майкрософт

У C++/CLI столько тараканов, что лучше иметь нормальный ABI (C-like API), чем писать костыли. А для библиотек которые header/template based всё равно только топор поможет. Топором в этом случае я имею ввиду вынос части своей логики в C++ который и сможет быть и скомпилирован эффективно, и вызван (ну и работа будет делаться с минимумом пересечений managed-native границ). Микс же и прозрачные "трамплины" скорости не добавят, в поддержке сложнее, доп знания о диалекте и энвайронменте опять же нужны.
Ну на вскидку — прийдется хорошенько попрыгать прежде чем нативный колбэк будет вызывать код в правильном апп домене, в то время как в интеропе со стороны шарпа (через делегаты и GetFunctionPointer) это достанется бесплатно. Понятно, что всё тоже можно замутить в C++/CLI, но легче из шарпа работать с любыми типами. Лиж бы описания структур были, а потом указатель и вперёд. Но это как раз об ABI.
Re[9]: .Net Core Вызов виртуальных методов нативных объектов
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 16.11.16 13:04
Оценка:
Здравствуйте, fddima, Вы писали:

F> Ну на вскидку — прийдется хорошенько попрыгать прежде чем нативный колбэк будет вызывать код в правильном апп домене, в то время как в интеропе со стороны шарпа (через делегаты и GetFunctionPointer) это достанется бесплатно. Понятно, что всё тоже можно замутить в C++/CLI, но легче из шарпа работать с любыми типами. Лиж бы описания структур были, а потом указатель и вперёд. Но это как раз об ABI.

А можно поподробнее про ABI. Нашел только http://stackoverflow.com/questions/3784389/difference-between-api-and-abi
и солнце б утром не вставало, когда бы не было меня
Re[10]: .Net Core Вызов виртуальных методов нативных объекто
От: fddima  
Дата: 16.11.16 23:06
Оценка:
Здравствуйте, Serginio1, Вы писали:

S> А можно поподробнее про ABI. Нашел только http://stackoverflow.com/questions/3784389/difference-between-api-and-abi

Так там же ж вполне понятно написано. Под ABI понимается любое стабильное соглашение о том как программы взаимодействуют на бинарном уровне. COM в частности — это универсальный такой контракт (интерфейс). Они могут быть и специализированными. Все в итоге выливается в набор экспортируемых вызовов из динамической библиотеки, описания структур и желательно механизм валидации определения версий.
Понятно что для реализации этого нам необходимо предоставить C-like интерфейс, а в дотнете просто юзать PInvoke, при этом мы опускаем остальные детали т.к. обе среды остальное делают за нас (соглашение вызовов, упаковка/выравниевание структур и т.п.).

В том же CEF, например, для того что бы создать объект (реализуемый на стороне C#), я заполняю таблицу с адресами методов которые реализуют конкретные функции, что-то вроде VMT, но на каждый объект своя таблица. А при потреблении объектов — беру адрес функции, делегат и вперед вызывать. Т.е. тонны экспортов из dll нет.

Это и есть "наше" соглашение, используемое для:
1. построения этого самого слоя ABI, т.е. способ которым библиотека экспортирует свой функционал в виде динамической библиотеки (полностью автоматически).
2. построения клиента (C++) для библиотеки (т.е. API внешне выставляется такой же как и "внутри", но на самом деле там самый настоящий интероп с маршаллингом, например, с передачей строк по значению, ну и по ссылке когда надо) (полностью автоматически).
3. построения биндингов для (C#, Go, Python с той или иной степенью автоматизации), но не вокруг этой клиентской C++ обертки, а вокруг этого самого ABI. При этом, разумеется, выпуск патчей не ломает совместимость, хотя такой халявы как в дотнете с символическим связыванием — увы нет — метаданных то нет. Есть один идентификатор (хэш) — если не совпадает — значит другая версия ABI и работать с ней нельзя.

Механизм в целом тот ещё, но по факту довольно удобен, даж Servo к себе на вооружение взяли. Но это ж для демонстрации.

PS: Я возможно не верно понял, чего ты там не понял, или куда ещё подробнее?

UPD2: У WebKit2 на мой взгляд вменяемый интерфейс в этом плане, но правда не без своих таракашек, как и везде.

UPD3: Один из ответов на SO гласит:

ABI: Application Binary Interface

This is how the compiler builds an application.
It defines things (but is not limited to):

— How parameters are passed to functions (registers/stack).
— Who cleans parameters from the stack (caller/callee).
— Where the return value is placed for return.
— How exceptions propagate.


Конечно же это не так (это далеко не всё). Описанное — это соглашение вызова функции (call convention). Соглашение по исключениям... хм, а они есть / могут быть? Да даже C/C++ библиотеки имеют ABI, тот же libc которому следует компилятор (и может таргетиться на разные версии), дабы обеспечить максимальную совместимость. Ну т.е. на уровне того, чего именно финальный экзешник потребляет (в терминах импортов ну и связанных вещей, стуктуры, соглашение вызова и т.п.).

API же — это скорее то, что предоставляет библиотека, и как мы её потребляем в той или иной среде. API например может содержать 2 метода, однако на уровне ABI это будет один метод с параметром.
Отредактировано 16.11.2016 23:39 Mystic Artifact . Предыдущая версия . Еще …
Отредактировано 16.11.2016 23:38 Mystic Artifact . Предыдущая версия .
Отредактировано 16.11.2016 23:30 Mystic Artifact . Предыдущая версия .
Re[11]: .Net Core Вызов виртуальных методов нативных объекто
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 17.11.16 07:07
Оценка:
Здравствуйте, fddima, Вы писали:
Меня вот что интересует.

Передавать статические функции или ThisCall трудоемко.
Проще общаться с нативом в разные стороны через абстрактные классы

Повторюсь http://rsdn.org/Forum/NewMsg.aspx?mid=6608772&amp;edit=1
Автор: Serginio1
Дата: 13.11.16


Так суть интерфейса это VMT. А классы с виртуальными методами кроссплатформенны.
В 1С это прекрасно работает

class IInitDoneBase
{
public:
    virtual ~IInitDoneBase() {}
    /// Initializes component
    /**
     *  @param disp - 1C:Enterpise interface
     *  @return the result of
     */
    virtual bool ADDIN_API Init(void* disp) = 0;
    /// Sets the memory manager
    /*
     * @param mem - pointer to memory manager interface.
     *  @return the result of
     */
    virtual bool ADDIN_API setMemManager(void* mem) = 0;

    /// Returns component version
    /**
     *  @return - component version (2000 - version 2)
     */
    virtual long ADDIN_API GetInfo() = 0;

    /// Uninitializes component
    /**
     *  Component here should release all consumed resources.
     */
    virtual void ADDIN_API Done() = 0;

};
///////////////////////////////////////////////////////////////////////////
/**
 *  The given interface defines methods that are intented to be used by the Platform
 */
/// Interface describing extension of language.



где

#ifndef  ADDIN_API
#ifndef __linux__
#define ADDIN_API __stdcall
#else
//#define ADDIN_API __attribute__ ((__stdcall__))
#define ADDIN_API
#endif //__linux__
#endif //ADDIN_API



Этот вариант кроссплатформен.

Вот хотелось бы и такой вариант и на .Net описать.
Тот же наследник IUnknown это тот же виртуальный класс


class ICallback :public IUnknown
    {
    public:
        
        virtual HRESULT __stdcall execute();


        // Унаследовано через IUnknown
        virtual HRESULT __stdcall QueryInterface(REFIID riid, void ** ppvObject) override;

        virtual ULONG __stdcall AddRef(void) override;

        virtual ULONG __stdcall Release(void) override;

    };


Но при что бы получить ссылку на интерфейс, вызывается куча QueryInterface, AddRef и Release

То есть хотелось бы иметь контракт на уровне абстрактых классов без проверки как это и происходит при

Marshal.GetDelegateForFunctionPointer

с

[UnmanagedFunctionPointer(CallingConvention.ThisCall)]

или
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
и солнце б утром не вставало, когда бы не было меня
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.