【问题标题】:Create C++/CLI Wrapper for native C++ code为原生 C++ 代码创建 C++/CLI Wrapper
【发布时间】:2014-04-29 08:29:56
【问题描述】:

我目前需要为本地 C++ 库 (TetGen) 编写 C++/CLI 包装器,以便以后在 C# 项目中使用。我已经阅读了很多关于如何做到这一点的文章,但对我的链接器错误感到茫然。正如他在Blog 中所说的那样,一个名为“Sam Agten”的小伙子也试图做到这一点,这使我看到了关于 C++ 互操作的系列文章(Part 1Part 2Part 3Part 4Part 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) 并且使用了no CLR-Support。从预处理器定义中,我假设 lib 是针对 x86 系统的:“WIN32”。一切都保留在标准值上。如果我右键单击 => 构建,它将成功构建一个名为“SimpleAdd.lib”的库。

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

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

// 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 开关。在我的 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 Token (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::scalar 删除析构函数'(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

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

【问题讨论】:

    标签: c++-cli static-libraries native wrapper tetgen


    【解决方案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 没有被声明并且你在那里导入该类)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多