Использование библиотеки C ++ в C # winforms

Я пытаюсь использовать систему частиц SPARK в OpenTK.
Мой проект содержит заголовочные файлы в папках, всего два заголовочных файла, в которые входят только остальные, и папки также содержат исходные файлы.
До сих пор я пробовал несколько подходов, но у меня пока ничего не получалось, вот что я пробовал:

1. P / Invoke

Это написание некоторого кода в вашем C ++ проекте, который собрал dll, а затем с использованием DllImport атрибут в C # (который, очевидно, нуждается в using System.Runtime.InteropServices;). Я обнаружил сложный способ, что это не работает с классами, оно работает только для методов вне классов, поэтому этот подход был неэффективным.

2. Обертки классов

Это написание класса, который содержит указатель на исходный класс. Я обнаружил, что трудности на самом деле возникают из-за вызова неуправляемого кода (без автоматического управления памятью) из управляемого кода, поэтому необходимы классы-обертки, и поэтому вам нужно переопределить сигнатуры методов и позволить им вызывать оригинальные методы.

Конечно, у этого есть свои преимущества, например, более точное наименование классов и методов, но библиотека настолько велика, что вы можете увидеть, как это работает.

3. Использование автоматической обертки:

Это хороший подход, особенно с xInterop ++. Я был очень оптимистичен по этому поводу и думал, что это сработает, он говорит: «дайте мне файлы .h и dll, и я создам .NET dll для вас». Хорошо, но это дает ошибку; вкратце:

Вы должны убедиться, что файлы .h и dll соответствуют друг другу и что
Библиотека работает в проекте C ++.

Я пробовал несколько вещей, чтобы справиться с этой ошибкой:

  1. Знать, что содержит dll: это трудно, как я узнал от Google и с этого сайта, поэтому моя попытка не удалась.
  2. Помещение заголовочных файлов в новый проект и его сборка: получал ошибки, исправлял их, а затем собирал проект, и он работал хорошо. Я загрузил файл dll с файлами заголовков в xInterop. Затем он рассказал классам, которые были найдены, но затем заявил, что ничего не было найдено! Я искал и узнал, что компилятору нужно сказать, какие классы должны быть доступны для DLL, пометив каждый класс, который необходим, используя следующую инструкцию:_declspec(dllexport),
  3. Я использовал Find & Замените, чтобы исправить эту проблему, и попробуйте снова, и классы были показаны, поэтому я запустил xInterop и получил ту же ошибку.
  4. Он попросил убедиться, что DLL работает. Проверив, что файл работает, я запустил программу, и появились ошибки компоновщика.

Вот где я застрял, вот ошибки компоновщика, которые я получаю:

main.obj: ошибка LNK2019: неразрешенный внешний символ «void __cdecl
SPK :: swapParticles (класс SPK :: Частица &, класс СПК :: Частица &) «(? swapParticles @ SPK @@ ​​YAXAAVParticle @ 1 @ 0 @ Z) ссылка на функцию
«private: void __thiscall SPK :: Pool :: swapElements (класс SPK :: Particle &, класс СПК :: Частица
&) «(? swapElements @? $ Pool @ VParticle @ SPK @@@ SPK @@ ​​AAEXAAVParticle @ 2 @ 0 @ Z)
main.obj: ошибка LNK2001: неразрешенный внешний символ «unsigned int
SPK :: randomSeed «(? RandomSeed @ SPK @@ ​​3IA) main.obj: ошибка LNK2001:
неразрешенный внешний символ «unsigned long const SPK :: NO_ID» (? NO_ID @ SPK @@ ​​3KB) main.obj: ошибка LNK2001: неразрешенный внешний символ
«public: static float const * const SPK :: Transformable :: IDENTITY» (? IDENTITY @ Transformable @ SPK @@ ​​2QBMB)

Это код, который вызвал эти ошибки:

#include "Extensions/Emitters/SPK_RandomEmitter.h"
using namespace SPK;

int main()
{
RandomEmitter e;
e.changeFlow(6);
e.getFlow();
return 0;
}

Так что это моя проблема, прошу прощения за слишком много объяснений, но я провел трехдневный поиск, не найдя никакого решения.

PS:

библиотека очень большая, поэтому необходимо автоматическое решение.

8

Решение

Это очень, очень недружелюбная библиотека C ++, с которой приходится взаимодействовать. Скажи идею, что pinvoke может работать, классы C ++ требуют оболочек C ++ / CLI. Существует множество классов с множеством маленьких методов. Библиотека зависит от композиции для создания эффектов, поэтому любой подход, который пытается взаимодействовать с несколькими классами Бога, является мертвой авеню.

Самая значительная опасность заключается в том, что он сильно зависит от множественного наследования. Не поддерживается в .NET, это победит любой инструмент, который автоматически генерирует оболочки. Также обратите внимание, что он поддерживает только рендеринг OpenGL, а не очень популярный графический API в Windows.

Библиотека привлекательна и существует уже довольно давно, но пока никто не смог успешно перенести ее на .NET. Это неудивительно. В моем мнение, у тебя нет шансов. Только переписать может работать.

5

Другие решения

PInvoke — это способ сделать то, что вы ищете. Не имеет значения, есть ли у вас или нет код для этой DLL, если вы знаете сигнатуру функции.

Взгляните на эти статьи из MSDN и проекта кода, которые охватывают основы PInvoke:

  1. Учебник по вызову платформы
  2. P / Invoke Tutorial: Основы (часть 1)

Редактировать:
Существуют инструменты, которые могут генерировать подпись DllImport для вас. Я не пробовал ничего из этого сам. Посмотри:

  1. P / Invoke Signature Generator
  2. Самый простой способ генерировать код P / Invoke?
  3. Вот этот
  4. http://www.swig.org/

Надеюсь, это поможет.

4

Если ваш родной dll экспортирует некоторые классы, я настоятельно рекомендую создать еще один родной DLL-обертку для исходного. Он должен экспортировать несколько функций и никаких классов вообще.

Экспортированный функционал может быть что-то вроде:

my_lib_create_context( void ** const ppContext );
my_lib_delete_context( void * const pContext );
my_lib_do_something( void * const pContext, T param1, T param2 );

внутри my_lib_create_context() создать экземпляр вашего класса и передать указатель обратно через ppContext параметр.
внутри my_lib_do_something() бросить pContext к указателю вашего типа класса и использовать его.

Кроме того, при написании вашей обертки обратите внимание на соглашение о вызовах, потому что вам нужно будет передать эту информацию в мир .NET (я думаю, что stdcall является значением по умолчанию, если оно явно не определено).

РЕДАКТИРОВАТЬ:
Что касается этой части о том, как это сделать:
Создайте новое C ++ решение / проект, выберите тип DLL. Затем добавьте файл .def в этот проект. Добавьте к этому файлу это:

ЭКСПОРТ
my_lib_create_context @ 1
my_lib_delete_context @ 2
my_lib_do_something @ 3

Затем добавьте заголовочный файл, в который вы поместите сигнатуры функций, например:

typedef void * SomeContext;

extern "C"{
int __stdcall my_lib_create_context( /* [ out ] */ SomeContext * ppContext );
int __stdcall my_lib_delete_context( /* [ in ] */ SomeContext pContext );
// TO DO: ... you get it by now...
}

Реализуйте эти функции в файле .cpp. Как только вы закончите, создайте оболочку в C # для этой DLL и используйте ее.

1

Хм P / Invoke вызов GetProcessAdress .. поэтому проблема импорта ABI так себе ..

http://www.codeproject.com/Articles/18032/How-to-Marshal-a-C-Class
вот ваш ответ отдать должное этим парнем

1
По вопросам рекламы [email protected]