0

我目前需要为本地 C++ 库 (TetGen) 编写 C++/CLI 包装器,以便以后在 C# 项目中使用。我已经阅读了很多关于如何做到这一点的文章,但对我的链接器错误感到茫然。一个叫做“Sam Agten”的小伙子也试图做到这一点,正如他在他的博客中所说的那样,这使我看到了一个关于 C++ 互操作的系列(第 1部分、第 2部分、第 3部分、第 4部分、第 5 部分),其中第 3 部分应该是解释如何做我完成的事情。

因为 Sam 想将 TetGen 与 Unity 集成,所以他最后不得不求助于 C-Style-Wrappers。现在,如果我没有完全弄错的话,我已经尝试在以前的相关项目中使用 C-Style-Wrappers。

因为我打包的 TetGen 必须在 Windows Server(我认为是 2008 年)上运行,所以我的第一个问题是: C++/CLI-Wrapper 将在服务器环境中工作吗?

我根据前面提到的第 3 部分开始编写一个非常简单的包装器,但失败得很惨。无论如何,我试图沿着思路创建一个简单的包装库,我想与你分享。我首先创建了一个 C# 项目,它最终应该使用我的包装库,并首先从 C++ 项目“SimpleAdd”的“Win32”子部分添加一个新项目。

//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 支持。从预处理器定义中,我假设 lib 是针对 x86 系统的:“WIN32”。一切都保留在标准值上。如果我右键单击 => 构建,它将成功构建一个名为“SimpleAdd.lib”的库。

我通过其他帖子指出的一件事:如果我在 DependencyWalker 中打开库,我会收到一条错误消息:“未找到 DOS 或 PE 签名。此文件不是有效的 32 位或 64 位 Windows 模块”,即有点令人沮丧。我必须做什么才能使 DependencyWalker 停止显示此错误,因为我认为这个 32/64 问题可能暗示解决方案。

无论如何,我有我的库,现在我想把它包起来。因此,我使用 C++ 分支的 CLR-ClassLibrary-template 在我的解决方案中创建了一个名为“AddWrapper”的新项目。

// 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++ 文件夹中,我添加了整个灵魂的调试目录的路径,因为这是编译引用的库的位置。在“附加依赖项”下的链接器设置中,我添加了名称:“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)" 版本。%path%\AddWrapper\AddWrapper.obj AddWrapper Fehler 4 错误 LNK2028: Nicht aufgel÷stes 令牌 (0A00000C) ""public: __thiscall SimpleAdd::~SimpleAdd(void)" (??1SimpleAdd@@$$FQAE@XZ)" , auf das in Funktion ""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。

现在,这些错误的原因可能是什么?是 lib 的平台迷惑性吗?我是否错过了指定其他内容?

4

1 回答 1

2

What do I have to to to make DependencyWalker stop showing this error

Do not compile to a lib file! It's not an executable and it's not a dynamic link library so it has not PE signature. You can build a static library and link it inside your C++/CLI assembly (if you wish so) or you can simply put all that code inside your C++/CLI assembly. Up to you.

what could be the cause of these errors?

You directly included header file, let me highlight your code:

class _declspec(dllexport) SimpleAdd

As you can see you're actually compiling with _declspec(dllexport), you're not telling the compiler to import such class from a library but that you're exporting it (and linker will complain because you declared that class but there is not any implementation). When you include a class it has to be declared with _declspec(dllimport).

class _declspec(dllimport) SimpleAdd

Usually this trick is done with preprocessor macros. Let me make a simplified example. In your SimpleAdd.h file you can declare:

#if defined(SIMPLEADD_LIB)
#define SIMPLEADD_EXPORTED _declspec(dllexport)
#else
#define SIMPLEADD_EXPORTED _declspec(dllimport)
#endif

Then change your code to

class SIMPLEADD_EXPORTED SimpleAdd

In your SimpleAdd project you define a macro (from Project settings) named SIMPLEADD_LIB. This will cause your library to be built with dllexport (because from library you export that class) but in your C++/CLI wrapper to be declared as dllimport (right because SIMPLEADD_LIB isn't declared and there you're importing that class).

于 2014-04-29T08:40:33.237 回答