используя класс, определенный в c ++ dll в коде c # - PullRequest
60 голосов
/ 24 ноября 2008

У меня есть dll, которая была написана на c ++, мне нужно использовать эту dll в моем коде c #. После поиска я обнаружил, что использование P / Invoke даст мне доступ к нужной мне функции, но эти функции определены в классе и используют нестатические закрытые переменные-члены. Поэтому мне нужно иметь возможность создать экземпляр этого класса, чтобы правильно использовать функции. Как я могу получить доступ к этому классу, чтобы я мог создать экземпляр? Я не смог найти способ сделать это.

Полагаю, я должен отметить, что dll c ++ - это не мой код.

Ответы [ 7 ]

80 голосов
/ 24 ноября 2008

Нет способа напрямую использовать класс C ++ в коде C #. Вы можете использовать PInvoke косвенным образом для доступа к вашему типу.

Основной шаблон заключается в том, что для каждой функции-члена в классе Foo создайте связанную функцию, не являющуюся членом, которая вызывает функцию-член.

class Foo {
public:
  int Bar();
};
extern "C" Foo* Foo_Create() { return new Foo(); }
extern "C" int Foo_Bar(Foo* pFoo) { return pFoo->Bar(); }
extern "C" void Foo_Delete(Foo* pFoo) { delete pFoo; }

Теперь нужно вызвать эти методы в код C #

[DllImport("Foo.dll")]
public static extern IntPtr Foo_Create();

[DllImport("Foo.dll")]
public static extern int Foo_Bar(IntPtr value);

[DllImport("Foo.dll")]
public static extern void Foo_Delete(IntPtr value);

Недостатком является то, что вам придется обходить неудобным IntPtr, но довольно просто создать класс-оболочку C # вокруг этого указателя для создания более удобной модели.

Даже если у вас нет этого кода, вы можете создать другую DLL, которая обернет исходную DLL и предоставит небольшой слой PInvoke.

16 голосов
/ 12 апреля 2016

Маршал С ++ Класс и использование PInvoke

Код C ++, ClassName.h

class __declspec(dllexport) CClassName
{
 public:
    CClassName();
    ~CClassName();
    void function();

};

Код C ++, ClassName.cpp

CClassName::CClassName()
{
}

CClassName::~CClassName()
{
}

void CClassName::function()
{
    std::cout << "Bla bla bla" << std::endl;

}

Код C ++, файл ClassNameCaller.h для функции вызывающего абонента

#include "ClassName.h"      

#ifdef __cplusplus
extern "C" {
#endif

extern __declspec(dllexport) CClassName* CreateClassName();

extern __declspec(dllexport) void DisposeClassName(CClassName* a_pObject);

extern __declspec(dllexport) void function(CClassName* a_pObject);


#ifdef __cplusplus
}
#endif

Код C ++, файл ClassNameCaller.cpp для функции вызывающей стороны

#include "ClassNameCaller.h"


CClassName* CreateClassName()
{
    return new CClassName();
}

void DisposeClassName(CClassName* a_pObject)
{
    if(a_pObject!= NULL)
    {
        delete a_pObject;
        a_pObject= NULL;
    }
}

void function(CClassName* a_pObject)
{
    if(a_pObject!= NULL)
    {
        a_pObject->function();
    }
}

C # код

[DllImport("ClassNameDll.dll")]
static public extern IntPtr CreateClassName();

[DllImport("ClassNameDll.dll")]
static public extern void DisposeClassName(IntPtr pClassNameObject);

[DllImport("ClassNameDll.dll")]
static public extern void CallFunction(IntPtr pClassNameObject);

//use the functions
IntPtr pClassName = CreateClassName();

CallFunction(pClassName);

DisposeClassName(pClassName);

pClassName = IntPtr.Zero; 
4 голосов
/ 24 ноября 2008

Здесь - это пример того, как вызывать метод класса C ++ из VB - для C # вам нужно переписать только пример программы на шаге 4.

3 голосов
/ 26 марта 2009

myfile.i

%module learnaboutswig

class A

{

public:

    void boringfunction(char *charstr);
};

скачать swig с сайта swig.org

swig -c ++ -csharp myfile.i

посмотрите на вывод, посмотрите, будет ли он работать на вас.

2 голосов
/ 25 ноября 2008

Я сделал это путем создания тонкой оболочки Managed C ++ вокруг моей неуправляемой C ++ DLL. Управляемая оболочка содержит прокси-классы, которые обертывают неуправляемый код, предоставляя интерфейс, необходимый для приложения .NET. Это немного двойная работа, но она позволяет работать в нормальных условиях. В некоторых случаях (например, ASP.NET) дела обстоят сложнее с зависимостями, но вы, вероятно, не столкнетесь с этим.

2 голосов
/ 24 ноября 2008

Я согласен с JaredPar. Создание экземпляров неуправляемых классов в управляемом коде не должно быть возможным.

Другое дело - если бы вы могли перекомпилировать DLL в управляемом C ++ или сделать из нее COM-компонент, это было бы намного проще /

2 голосов
/ 24 ноября 2008

Возможно, вам понадобится написать промежуточную DLL (возможно, на C ++), которая обрабатывает это для вас и предоставляет необходимый вам интерфейс. Ваша DLL будет отвечать за загрузку сторонней DLL, создание экземпляра этого объекта C ++ и предоставление его функций-членов по мере необходимости через любой API, который вы разрабатываете. Затем вы будете использовать P / Invoke, чтобы получить доступ к своему API и чисто манипулировать объектом.

Примечание. Для API вашей DLL старайтесь ограничивать типы данных примитивами (long, int, char * и т. Д.), Чтобы избежать проблем с границами модуля.

...