С использованием класса, определенного в dll C++ в коде C#

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

Думаю, я должен отметить, что dll C++ - это не мой код.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
73
0
97 364
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Ответ принят как подходящий

Невозможно напрямую использовать класс 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++ в коде C#» неверно. Статическая функция C++ работает так же, как функция в стиле C, и функции экземпляра могут быть объявлены как соглашение о вызовах ThisCall, добавив ThisObject, указывающий на сам экземпляр, в качестве первого аргумента. Для подробностей вы можете прочитать мой Блоги. Вы также можете попробовать наш инструмент (я автор)

xInterop 11.04.2014 05:09

Хотя в то время это был прекрасный ответ, возможно, лучше использовать C++ / CLI, чтобы избежать ручного создания прокси-функций - что-то, что может стать довольно утомительным довольно быстро.

MickyD 15.02.2015 20:40

Должны ли прокси-функции C++ быть окружены extern "C" { .... } или можно делать это только на C++?

divB 01.04.2015 09:26

@jaredpar где мне скопировать C++ dll? помимо C# exe? Я получаю System.EntryPointNotFoundException: 'Невозможно найти точку входа с именем' ... 'в DLL

Hamed_gibago 24.07.2019 13:01

Возможно, вам потребуется написать промежуточную 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) все становится сложнее с зависимостями, но вы, вероятно, не столкнетесь с этим.

Marshal C++ Class и используйте 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; 

Разве в первом файле ClassName.h не должно быть «dllexport» вместо «dllimport»?

P.W. 07.03.2018 20:11

Да, он используется для экспорта этого класса в проект .Net, поэтому мы можем использовать класс CClassName.

Amir Touitou 08.03.2018 08:20

Этот пример действительно очень помог, большое вам спасибо :-)

Ashish Rana 28.03.2018 13:15

Привет. Не уверен, что это слишком поздно, но можете ли вы показать модификацию своего кода, в которой я могу передавать строки через функцию, изменять их, а затем возвращать их в код C#? Я пытался, но это не позволяет мне добавлять имена типов в функцию a_pObject-> (std :: string args1);

CausticLasagne 04.11.2018 23:29

Примечание: если вы получаете «BadImageFormatException», возможно, вам придется изменить платформу. Я скомпилировал свой код C++ как x64, как обычно, но для проекта по умолчанию, который я создал для стороны C#, было установлено значение «Any CPU». Это не работает, но когда-то переключился на x64. Убедитесь, что соответствует.

clocktown 29.08.2019 16:47

Другие вопросы по теме