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





Невозможно напрямую использовать класс 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.
Хотя в то время это был прекрасный ответ, возможно, лучше использовать C++ / CLI, чтобы избежать ручного создания прокси-функций - что-то, что может стать довольно утомительным довольно быстро.
Должны ли прокси-функции C++ быть окружены extern "C" { .... } или можно делать это только на C++?
@jaredpar где мне скопировать C++ dll? помимо C# exe? Я получаю System.EntryPointNotFoundException: 'Невозможно найти точку входа с именем' ... 'в DLL
Возможно, вам потребуется написать промежуточную DLL (возможно, на C++), которая сделает это за вас и предоставит нужный вам интерфейс. Ваша DLL будет отвечать за загрузку сторонней DLL, создание экземпляра этого объекта C++ и предоставление его функций-членов по мере необходимости через любой разрабатываемый вами API. Затем вы должны использовать P / Invoke, чтобы получить доступ к своему API и аккуратно манипулировать объектом.
Примечание. Для API вашей DLL постарайтесь ограничить типы данных примитивами (long, int, char * и т. д.), Чтобы предотвратить проблемы с границами модуля.
Я согласен с JaredPar. Создание экземпляров неуправляемых классов в управляемом коде должно быть невозможно.
Другое дело - если бы вы могли перекомпилировать DLL в управляемом C++ или сделать из нее COM-компонент, это было бы намного проще /
Здесь - это пример вызова метода класса C++ из VB - для C# вам нужно только переписать пример программы на шаге 4.
Я сделал это, создав тонкую управляемую оболочку C++ вокруг моей неуправляемой библиотеки DLL C++. Управляемая оболочка содержит классы-посредники, которые охватывают неуправляемый код, открывая интерфейс, необходимый для приложения .NET. Это немного двойная работа, но она позволяет довольно плавно работать в нормальных условиях. В некоторых случаях (например, в ASP.NET) все становится сложнее с зависимостями, но вы, вероятно, не столкнетесь с этим.
Код 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;
Разве в первом файле ClassName.h не должно быть «dllexport» вместо «dllimport»?
Да, он используется для экспорта этого класса в проект .Net, поэтому мы можем использовать класс CClassName.
Этот пример действительно очень помог, большое вам спасибо :-)
Привет. Не уверен, что это слишком поздно, но можете ли вы показать модификацию своего кода, в которой я могу передавать строки через функцию, изменять их, а затем возвращать их в код C#? Я пытался, но это не позволяет мне добавлять имена типов в функцию a_pObject-> (std :: string args1);
Примечание: если вы получаете «BadImageFormatException», возможно, вам придется изменить платформу. Я скомпилировал свой код C++ как x64, как обычно, но для проекта по умолчанию, который я создал для стороны C#, было установлено значение «Any CPU». Это не работает, но когда-то переключился на x64. Убедитесь, что соответствует.
Утверждение «Невозможно напрямую использовать класс C++ в коде C#» неверно. Статическая функция C++ работает так же, как функция в стиле C, и функции экземпляра могут быть объявлены как соглашение о вызовах ThisCall, добавив ThisObject, указывающий на сам экземпляр, в качестве первого аргумента. Для подробностей вы можете прочитать мой Блоги. Вы также можете попробовать наш инструмент (я автор)