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