用多个 C# .dll 包装多个 C++ .dll

Posted

技术标签:

【中文标题】用多个 C# .dll 包装多个 C++ .dll【英文标题】:Wrapping multiple C++ .dlls with multiple C# .dlls 【发布时间】:2017-01-19 14:41:30 【问题描述】:

我正在开发一个项目,用 C# 包装多 dll C++ SDK,试图用单独的 C# dll 包装每个原始 C++ dll。我遇到了一个问题,如果 C++ 库 A 中的一些常用符号在 C++ 库 B 和 C 中使用,则无法换行。由于这是 C++ 中非常常见的场景,显然我错过了一些琐碎的事情。花了几天时间后,我仍然不知所措,如果能帮助我继续前进,我将不胜感激。

以下简单示例重现了该问题: - 类 Point 应该在库 A 中定义 - 类 Triangle 应该在使用 A 的库 B 中定义 - Quadrange 类应该在使用 A 的库 C 中定义

"MyPoint.h"
class  MyPoint

public:

    MyPoint(double theX, double theY) : myX(theX), myY(theY) 

    double X() const  return myX; 
    double& X()  return myX; 

    double Y() const  return myY; 
    double& Y()  return myY; 

private:

    double myX;
    double myY;
;

"MyTriangle.h"
#include "MyPoint.h"

class MyTriangle

public:

    MyTriangle(const MyPoint& theP1, const MyPoint& theP2, const MyPoint& theP3) :
        myP1(theP1),
        myP2(theP2),
        myP3(theP3) 

    MyPoint P1() const  return myP1; 
    MyPoint& P1()  return myP1; 

    MyPoint P2() const  return myP2; 
    MyPoint& P2()  return myP2; 

    MyPoint P3() const  return myP3; 
    MyPoint& P3()  return myP3; 

private:

    MyPoint myP1;
    MyPoint myP2;
    MyPoint myP3;
;

"MyQuadrangle.h"
#include "MyPoint.h"

class MyQuadrangle

public:

    MyQuadrangle(const MyPoint& theP1, const MyPoint& theP2, const MyPoint& theP3, const MyPoint& theP4) :
        myP1(theP1),
        myP2(theP2),
        myP3(theP3),
        myP4(theP4) 

    MyPoint P1() const  return myP1; 
    MyPoint& P1()  return myP1; 

    MyPoint P2() const  return myP2; 
    MyPoint& P2()  return myP2; 

    MyPoint P3() const  return myP3; 
    MyPoint& P3()  return myP3; 

    MyPoint P4() const  return myP4; 
    MyPoint& P4()  return myP4; 

private:

    MyPoint myP1;
    MyPoint myP2;
    MyPoint myP3;
    MyPoint myP4;

;

三角形和四边形分别设置了三个点和四个点。 因此,两个类(MyTriangle 和 MyQuadrangle)都使用类 MyPoint。 所有三个类都是单独包装的。对于每个类都有自己的接口文件:

"MyPoint.i"
%module MyPointWrapper
%
#include "MyPoint.h"
%
%include <windows.i>
%include "MyPoint.h"

"MyTriangle.i"
%module MyTriangleWrapper
%
#include "MyTriangle.h"
%
%include "MyPoint.i"
%include "MyTriangle.h"

"MyQuadrangle.i"
%module MyQuadrangleWrapper
%
#include "MyQuadrangle.h"
%
%include "MyPoint.i"
%include "MyQuadrangle.h"

为每个文件编写了命令行界面: C:\swigwin-3.0.10\swigwin-3.0.10\swig -csharp -c++ -namespace geometry -outdir C:\Geometrics\MyPointNet\Generated MyPoint.i C:\swigwin-3.0.10\swigwin-3.0.10\swig -csharp -c++ -命名空间几何 -I"C:\Geometrics\MyPointcpp" -outdir C:\Geometrics\MyTriangleNet\Generated MyTriangle.i C:\swigwin-3.0.10\swigwin-3.0.10\swig -csharp -c++ -namespace geometry -I"C:\Geometrics\MyPointcpp" -outdir C:\Geometrics\MyQuadrangleNet\Generated MyQuadrangle.i

当我在 C# 中使用 MyPoint 类时:

using System;
using geometry;

namespace Example

        class Program
        
            static void Main(string[] args)
            
                MyPoint P = new MyPoint (3, 4, 5);
            
        

出现一个错误,指出每个类都包含一种 MyPoint: 'MyPoint' 类型同时存在于 'MyTriangleNet, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' 和 'MyPointNet, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'

如何避免这种情况,但在 C# 中拥有三个功能齐全的类,条件是每个类都将单独包装?

【问题讨论】:

我回滚了这个问题 - 由于缺乏 C#/Windows 知识,您所做的编辑是我的测试/答案的错误,而不是您问题中的(非常好的)细节,最好把它写得更像百科全书条目而不是交互式调试会话。 【参考方案1】:

您几乎已经完成了,但是要简单地引用现有代码而不生成更多代码,您需要使用 %import "modulename.i" 而不是 %include,因此您的 .i 文件变为:

MyPoint.i:

%module MyPointWrapper
%
#include "MyPoint.h"
%
%include "MyPoint.h"

MyQuadrangle.i:

%module MyQuadrangleWrapper
%
#include "MyQuadrangle.h"
%
%import "MyPoint.i"
%include "MyQuadrangle.h"

MyTriangle.i:

%module MyTriangleWrapper
%
#include "MyTriangle.h"
%
%import "MyPoint.i"
%include "MyTriangle.h"

无论如何,我都不是 C# 专家,所以我希望您必须使用 %typemap(csimports) 或其他东西来确保,例如MyTriangle.cs 知道如何使用非限定名称来引用它所指的 MyPoint 类型,但至少当我在 Linux 上使用 Mono 测试它时,构建了一个似乎不需要的单个可执行文件:

#!/bin/bash
swig3.0 -csharp -c++ -namespace geometry -outdir MyPointNet MyPoint.i
swig3.0 -csharp -c++ -namespace geometry -outdir MyTriangleNet MyTriangle.i
swig3.0 -csharp -c++ -namespace geometry -outdir MyQuadrangleNet MyQuadrangle.i

g++ -Wall -Wextra -o libMyPointWrapper.so MyPoint_wrap.cxx -shared -fPIC
g++ -Wall -Wextra -o libMyQuadrangleWrapper.so MyQuadrangle_wrap.cxx -shared -fPIC
g++ -Wall -Wextra -o libMyTriangleWrapper.so MyTriangle_wrap.cxx -shared -fPIC

mcs run.cs */*.cs && ./run.exe

一旦我更改了您的示例用法以调用存在的 MyPoint (2-arg) 的构造函数,所有工作正常。我还在以下位置添加了对 MyTriangle 的快速测试:

MyTriangle T = new MyTriangle(P,P,P);

此外,要跨多个程序集进行这项工作,您还需要在a little more work, as outlined in the documentation, to change 中查看从internalpublic 的一些内部结构。您只需要在导入的模块中执行此操作,因此在此实例中 MyPoint.i 变为:

%module MyPointWrapper
SWIG_CSBODY_PROXY(public, public, SWIGTYPE)
SWIG_CSBODY_TYPEWRAPPER(public, public, public, SWIGTYPE)
%
#include "MyPoint.h"
%
%include "MyPoint.h"

请注意,文档提出了一些比仅仅公开它更好的解决方法。如果是我的生产代码,我会调查这些。

【讨论】:

非常感谢您提供提示。在我将 %module 添加到 Triangle.i 文件后,我遇到了从为 Triangle 生成的代码(与 Qudrangle 相同)中访问 MyPoint 类的方法的问题。对原始帖子进行了更详细的编辑。 @KKrill 如果您使用-Wall 运行SWIG,它会警告很多关于internal 是C# 中的保留字。我的猜测是与此有关。 实际上可能不是,似乎这是我以前没有经验的一些 C# 模块。会再挖一点。 知道了。即将进行一项编辑。事实证明,这正是我在使用 Mono 编译之前提到的问题,但文档中已经有了更简洁的解决方案。 非常感谢您的详细解答。它帮助我解决了我的问题!

以上是关于用多个 C# .dll 包装多个 C++ .dll的主要内容,如果未能解决你的问题,请参考以下文章

使用 C++ 包装器时如何访问 C# .dll 属性

从 C# 程序访问 C++ DLL 中的多个函数

c++ lib dll 的 C# 包装类

MFC dll 中的访问冲突(用 C++/CLI 包装)从 C# 程序开始

c#如何合并多个dll文件

非托管C++通过C++/CLI包装调用C# DLL