Подтвердить что ты не робот

Используя класс, определенный в dll С++ в коде С#

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

Думаю, я должен отметить, что dll С++ не является моим кодом.

4b9b3361

Ответ 1

Невозможно напрямую использовать класс 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; }

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

[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, но довольно просто создать класс-оболочку С# вокруг этого указателя, чтобы создать более удобную модель.

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

Ответ 2

Маршал C++ Класс и использовать PInvoke

C++ Код, ClassName.h

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

};

C++ Code, 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();
    }
}

код С#

[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; 

Ответ 3

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

Ответ 4

myfile.i

%module learnaboutswig

class A

{

public:

    void boringfunction(char *charstr);
};

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

swig -С++ -csharp myfile.i

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

Ответ 5

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

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

Ответ 6

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

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

Ответ 7

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