Создать C++/CLI Wrapper для собственного кода C++
В настоящее время мне нужно написать оболочку C++/CLI для нативной библиотеки C++ (TetGen) для последующего использования в проекте C#. Я прочитал довольно много статей о том, как это сделать, но затрудняюсь с ошибками компоновщика. Парень под названием "Сэм Агтен" тоже пытался достичь этого, как он заявляет в своем блоге, который привел меня к серии о взаимодействии C++ ( часть 1, часть 2, часть 3, часть 4, часть 5), где предполагается, что часть 3 объяснить, как делать то, что я делаю.
Поскольку Сэм хотел интегрировать TetGen с Unity, ему, наконец, пришлось прибегнуть к C-Style-Wrappers. Теперь, если я не совсем ошибаюсь, я попытался использовать C-Style-Wrappers в предыдущем связанном проекте.
Поскольку мой упакованный TetGen должен работать на Windows Server (я думаю, что это мой 2008 год), мой первый вопрос: будет ли C++/CLI-Wrapper работать в серверной среде?
Я начал писать очень простую обертку в соответствии с вышеупомянутой частью 3, которая с треском провалилась. Во всяком случае, я попытался создать простую библиотеку-оболочку по образцу, которой я хочу поделиться с вами. Я начал с создания C#-проекта, который в конечном итоге должен использовать мою обернутую библиотеку, и сначала добавил новый проект из раздела "Win32" C++- проекты "SimpleAdd".
//SimpleAdd.h
class _declspec(dllexport) SimpleAdd
{
public:
SimpleAdd();
~SimpleAdd();
int Add(int a,int b);
};
//SimpleAdd.cpp
#include "SimpleAdd.h"
int SimpleAdd::Add(int a, int b)
{
return a+b;
}
В настройках проекта я убедился, что он скомпилирован в статическую библиотеку (*.lib), и поддержка CLR не использовалась. Из определения препроцессора я предполагаю, что библиотека предназначена для систем x86: "WIN32". Все осталось в значительной степени на стандартных значениях. Если я щелкну правой кнопкой мыши => build, он успешно создаст библиотеку с именем "SimpleAdd.lib".
Одна вещь, на которую мне указывали в других статьях: если я открываю библиотеку в DependencyWalker, я получаю сообщение об ошибке: "Не найдена подпись DOS или PE. Этот файл не является допустимым 32-разрядным или 64-разрядным модулем Windows", вид разочарования. Что мне нужно сделать, чтобы DependencyWalker прекратил показывать эту ошибку, так как я думаю, что эта проблема 32/64 может указывать на решение.
Во всяком случае, у меня есть моя библиотека, теперь я хочу ее завершить. Поэтому я создал новый проект в своем решении под названием "AddWrapper", используя CLR-ClassLibrary-шаблон ветви C++.
// AddWrapper.h
#pragma once
#include "..\SimpleAdd\SimpleAdd.h"
using namespace System;
namespace AddWrapper {
public ref class ManagedSimpleAdd
{
private:
SimpleAdd *sa;
public:
ManagedSimpleAdd();
~ManagedSimpleAdd();
int Add(int a, int b);
};
}
//AddWrapper.cpp
#include "AddWrapper.h"
using namespace AddWrapper;
ManagedSimpleAdd::ManagedSimpleAdd() : sa(new SimpleAdd())
{
}
ManagedSimpleAdd::~ManagedSimpleAdd(){delete sa;}
int ManagedSimpleAdd::Add(int a, int b)
{
return sa->Add(a,b);
}
Поскольку оба C++-проекта находятся в отдельных папках на одном иерархическом уровне, я указал относительный путь к файлу заголовка. В настройках проекта у меня теперь есть стандартная конфигурация .dll и / clr -switch. В моих папках VC++ я добавил путь к каталогу Debug всей моей души, потому что именно здесь компилируется ссылочная библиотека. В моих настройках компоновщика в разделе "Дополнительные зависимости" я добавил имя: "SimpleAdd.lib".
Однако, когда я хочу создать свою оболочку, возникает проблема, а точнее 5 из них:
Ошибка Fehler 3 LNK2028: Nicht aufgel÷stes Token (0A00000B) ""public: __thiscall SimpleAdd::SimpleAdd(void)" (??0SimpleAdd@@$$FQAE@XZ)", auf das in Funktion ""public: __clrcall AddWrapper::ManagedSimpleAdd::ManagedSimpleAdd(void)" (??0ManagedSimpleAdd@AddWrapper@@$$FQ$AAM@XZ)" verwiesen wird. %path%\AddWrapper\AddWrapper.obj Ошибка AddWrapper Fehler 4 LNK2028: Nicht aufgel÷stes Token (0A00000C) ""public: __thiscall SimpleAdd::~SimpleAdd(void)" (??1SimpleAdd@@$$FQAE@XZ)", auf das in Funk ""public: void * __thiscall SimpleAdd::
scalar deleting destructor'(unsigned int)" (??_GSimpleAdd@@$$FQAEPAXI@Z)" verwiesen wird. %path%\AddWrapper\AddWrapper.obj AddWrapper Fehler 5 error LNK2019: Verweis auf nicht aufgel÷stes externes Symbol ""public: __thiscall SimpleAdd::SimpleAdd(void)" (??0SimpleAdd@@$$FQAE@XZ)" in Funktion ""public: __clrcall AddWrapper::ManagedSimpleAdd::ManagedSimpleAdd(void)" (??0ManagedSimpleAdd@AddWrapper@@$$FQ$AAM@XZ)". %path%\AddWrapper\AddWrapper.obj AddWrapper Fehler 6 error LNK2019: Verweis auf nicht aufgel÷stes externes Symbol ""public: __thiscall SimpleAdd::~SimpleAdd(void)" (??1SimpleAdd@@$$FQAE@XZ)" in Funktion ""public: void * __thiscall SimpleAdd::
скалярное удаление деструктора '(unsigned int)" (??_GSimpleAdd@@$$FQAEPAXI@Z)". %path%\AddWrapper\AddWrapper.obj Ошибка AddWrapper Fehler 7 LNK1120: 4 nicht aufgel÷ste Externe %path%\Debug\AddWrapper.dll 1 1 AddWrapper
Теперь, что может быть причиной этих ошибок? Является ли это платформой-обманчивостью библиотеки? Я пропустил, чтобы указать что-то еще?
1 ответ
Что мне нужно сделать, чтобы DependencyWalker перестал показывать эту ошибку
Не компилируйте в файл lib! Это не исполняемый файл и не библиотека динамических ссылок, поэтому она не имеет подписи PE. Вы можете создать статическую библиотеку и связать ее внутри вашей сборки C++/CLI (если вы этого хотите) или просто поместить весь этот код в свою сборку C++/CLI. Вам решать.
что может быть причиной этих ошибок?
Вы напрямую включили заголовочный файл, позвольте мне выделить ваш код:
class _declspec(dllexport) SimpleAdd
Как вы можете видеть, вы на самом деле компилируете с _declspec(dllexport)
вы не говорите компилятору импортировать такой класс из библиотеки, но экспортируете его (и компоновщик будет жаловаться, потому что вы объявили этот класс, но реализации нет). Когда вы включаете класс, он должен быть объявлен с _declspec(dllimport)
,
class _declspec(dllimport) SimpleAdd
Обычно этот трюк делается с макросами препроцессора. Позвольте мне привести упрощенный пример. В вашем SimpleAdd.h
файл, который вы можете объявить:
#if defined(SIMPLEADD_LIB)
#define SIMPLEADD_EXPORTED _declspec(dllexport)
#else
#define SIMPLEADD_EXPORTED _declspec(dllimport)
#endif
Затем измените свой код на
class SIMPLEADD_EXPORTED SimpleAdd
В вашем SimpleAdd
проект вы определяете макрос (из настроек проекта) с именем SIMPLEADD_LIB
, Это приведет к тому, что ваша библиотека будет построена с dllexport
(потому что из библиотеки вы экспортируете этот класс), но в вашей оболочке C++/CLI, которая будет объявлена как dllimport
(правильно, потому что SIMPLEADD_LIB
не объявлено, и вы импортируете этот класс).