繁体   English   中英

在C#winforms中使用C ++库

[英]Using a C++ library in C# winforms

我正在尝试在OpenTK中使用SPARK粒子系统。
我的项目包含文件夹中的头文件,只有两个头文件只包含其他文件,文件夹也包含源文件。
到目前为止,我已尝试了几种方法,但对我来说没有任何效果,这些都是我尝试过的:

1. P / Invoke

这是在你的C ++项目中编写一些代码,它们构建了dll,然后在C#中使用了DllImport属性(显然需要using System.Runtime.InteropServices; )。 我发现这种方法不适用于类很难,它只适用于类外的方法,因此这种方法无效。

2.包装类

这是编写一个包含指向原始类的指针的类。 我发现实际上困难来自于从托管代码调用非托管代码(没有自动内存管理),这就是为什么需要包装类,这就是为什么你必须重新定义方法的签名并让它们调用原始方法。

当然这有一些优点,比如以更好的方式命名类和方法,但是库很大,所以你可以看到它的努力。

3.使用自动包装机:

这是一种很好的方法,特别是对于xInterop ++。 我对此非常乐观,并认为它会起作用,它说“给我.h文件和dll,我将为你构建.NET dll”。 很好,但这样做会给出错误; 简单来说:

您必须确保.h文件和dll是一致的,并且该库在C ++项目中工作。

我已经尝试了几件事来处理这个错误:

  1. 知道dll包含什么:我从谷歌搜索和从这个网站学到的很难,所以我的尝试失败了。
  2. 将头文件放在一个新项目中并构建它:收到错误,修复它们,然后构建项目,它运行良好。 我将带有头文件的dll文件上传到xInterop。 然后它告诉已发现的类,但会说没有找到任何东西! 我搜索并了解到编译器必须通过使用以下语句标记所需的每个类来告知dll需要暴露哪些类: _declspec(dllexport)
  3. 我使用Find&Replace来修复这个东西并再次尝试并显示了类,所以我启动了xInterop并收到了同样的错误。
  4. 它要求确保dll正常工作。 验证文件有效后,我启动了程序并生成了链接器错误。

这是我被卡住的地方,这些是我得到的链接器错误:

main.obj:错误LNK2019:未解析的外部符号“void __cdecl SPK :: swapParticles(类SPK :: Particle&,类SPK :: Particle&)”(?swapParticles @ SPK @@ YAXAAVParticle @ 1 @ 0 @ Z)在函数“private:void __thiscall SPK :: Pool :: swapElements(class SPK :: Particle&,class 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:

图书馆非常大,所以自动解决方案是必须的。

这是一个非常非常不友好的C ++库,必须与之互操作。 抓住pinvoke可以工作的想法,C ++类需要C ++ / CLI包装器。 有很多类有许多小方法。 图书馆依赖于构图来产生效果,因此任何尝试与少数上帝类进行互操作的方法都是一条死路。

最重要的危害是它严重依赖于多重继承。 在.NET中不支持,这将打败任何自动生成包装器的工具。 另请注意,它仅支持OpenGL渲染,而不是Windows上非常流行的图形API。

该库很有吸引力,已经存在了很长一段时间,但是还没有人成功将它移植到.NET。 这并不奇怪。 在我看来 ,你没有机会。 只有重写才能奏效。

PInvoke是您正在寻找的方式。 如果您知道函数签名,那么如果您拥有或没有该DLL的代码,则无关紧要。

看看MSDN和代码项目中的这些文章,它们涵盖了PInvoke的基础知识:

  1. 平台调用教程
  2. P / Invoke教程:基础知识(第1部分)

编辑:有些工具可能会为您生成DllImport签名。 我自己没有尝试过这些。 看一看:

  1. P / Invoke签名生成器
  2. 生成P / Invoke代码的最简单方法是什么?
  3. 这个
  4. http://www.swig.org/

希望有所帮助。

如果您的本机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文件添加到该项目。 添加到该文件:

EXPORTS
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创建一个包装器并使用它。

嗯P / Invoke调用GetProcessAdress ..因此导入ABI问题是如此..

http://www.codeproject.com/Articles/18032/How-to-Marshal-aC-Class这里是你的答案给予那些家伙的信任

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM