Предоставление C ++ API для C # - PullRequest
7 голосов
/ 09 апреля 2010

Итак, у меня есть C ++ API, содержащийся в * .dll, и я хочу использовать приложение C # для вызова методов в API.

До сих пор я создал проект C ++ / CLR, который включает в себяродной C ++ API и ему удалось создать «мостовой» класс, который выглядит примерно так:

// ManagedBridge.h
#include <CoreAPI.h>
using namespace __CORE_API;

namespace ManagedAPIWrapper
{
    public ref class Bridge
    {
        public:
            int             bridge_test(void);
            int             bridge_test2(api_struct* temp);
    }
}

.

// ManagedBridge.cpp
#include <ManagedBridge.h>

int Bridge::bridge_test(void)
{
    return test();
}

int Bridge::bridge_test2(api_struct* temp)
{
    return test2(temp);
}

У меня также есть приложение C #, которое имеет ссылкув C ++ / CLR "Bridge.dll", а затем использует методы, содержащиеся в.У меня есть ряд проблем с этим:

  1. Я не могу понять, как вызвать bridge_test2 в программе на C #, поскольку она не знает, что такое api_struct на самом деле.Я знаю, что мне нужно где-то маршалировать объект, но я делаю это в программе на C # или на мосту C ++ / CLR?
  2. Это похоже на очень скучный способ разоблачения всех методов в API, разве нет более простого способа, который я упускаю?(Это не использует P / Invoke!)

РЕДАКТИРОВАТЬ: Хорошо, теперь у меня есть основы работы благодаря ответам ниже, однако моя структура (назовите это"api_struct2" для этого примера) имеет как собственный enum, так и объединение в собственном коде C ++, например:

typedef struct
{
    enum_type1  eEnumExample;
    union
    {
            long        lData;
            int     iData;
            unsigned char   ucArray[128];
            char        *cString;
            void        *pvoid;
    } uData;
} api_struct2;

Я думаю, я понял, как заставить работать enum;Я повторно объявил об этом в управляемом коде и выполняю «native_enum test = static_cast (eEnumExample)», чтобы переключить управляемую версию на собственную.

Однако профсоюз поставил меня в тупик, я не совсем уверен, как на него напасть .. Идеи кого-нибудь?

Ответы [ 3 ]

3 голосов
/ 09 апреля 2010

Да, вы передаете неуправляемую структуру по ссылке. Это проблема для программы на C #, указатели совершенно несовместимы с сборкой мусора. Не считая того факта, что он, вероятно, также не имеет декларации для структуры.

Вы можете решить эту проблему, объявив управляемую версию структуры:

public value struct managed_api_struct {
  // Members...
};

Теперь вы можете объявить метод как

int bridge_test2(managed_api_struct temp);   // pass by value

или

int bridge_test2(managed_api_struct% temp);  // pass by reference

Выберите последнее, если структура имеет более 4 полей (~ 16 байт). Метод должен скопировать поочередно членов структуры в неуправляемую структуру api_struct и вызвать метод неуправляемого класса. Это, к сожалению, необходимо, поскольку структура памяти управляемой структуры непредсказуема.

Это все довольно механично, вы можете получить помощь от SWIG . Сам не использовал, не уверен, достаточно ли он умен, чтобы справиться с переданной структурой.

Совершенно другой подход заключается в том, чтобы сделать класс-оболочку более чистым, предоставив ему конструктор и / или свойства, которые позволяют вам создавать содержимое api_struct. Или вы можете объявить класс ref-оболочки для структуры, как в управляемом коде.

2 голосов
/ 12 апреля 2010

Юо пытается сделать это более сложным, чем оно есть на самом деле. То, что вы хотите, это две разные структуры. Один управляемый и один неуправляемый. Вы открываете управляемую версию извне (для своего приложения C #). Это будет все ".Net-иш" без концепций союзов или около того.

В вашем мосту вы получаете управляемую версию структуры, вручную создаете неуправляемую структуру и пишете код для перемещения ваших данных, поле за полем в неуправляемую структуру. Затем вызовите неуправляемый код и, наконец, переместите данные обратно в управляемую структуру.

Прекрасной особенностью C ++ / CLI является то, что управляемый код также может работать с неуправляемым кодом и данными (включая неуправляемые файлы .h).

2 голосов
/ 09 апреля 2010

поскольку он не знает, что такое api_struct на самом деле

Вам необходимо определить управляемую версию в сборке .NET, которая использует атрибуты (например, StructLayoutAttribute) для обеспечения правильного маршала.

Это похоже на очень скучный [...]

Другой подход заключается в создании оболочки COM (например, с использованием ATL) вокруг вашего API. Это может потребовать больше усилий, но по крайней мере вы избежите двойного кодирования определений структуры и функций, необходимых для P / Invoke.

Исправление : Вы создали проект C ++ / CLI: поэтому просто добавьте правильный '#pragma', чтобы сообщить компилятору, что это код .NET, а затем вывод Сборка проекта C # может просто ссылаться.

...