简体   繁体   English

使用SWIG,如何将C ++ void func(Class&out)包装为C#Class func()?

[英]With SWIG, how do you wrap C++ void func(Class& out) as C# Class func()?

(Unfortunately, SWIG's documentation is very difficult to parse and online examples seem rare. So I come here.) (不幸的是,SWIG的文档很难解析,在线示例似乎很少见。所以我来到这里。)

Suppose a C++ function uses this typical return style for a class type: 假设C ++函数对类类型使用这种典型的返回样式:

void func(Class& out);

Using SWIG, this function should be wrapped in C# like this: 使用SWIG,这个函数应该用C#包装,如下所示:

Class func();

From what I've found, I can use a typemap to accomplish this. 从我发现的,我可以使用类型图来实现这一目标。

Pretending that Class is actually int , I've attempted the following based on examples I've found: 假设Class实际上是int ,我根据我发现的例子尝试了以下内容:

%include <typemaps.i>

%{
void func(int& pOut);
%}

%apply int &OUTPUT { int &pOut }
void func(int& pOut);

Many examples (leaning toward Python, though) suggest that this should create a function with no parameters that outputs an int . 许多例子(尽管倾向于Python)表明这应该创建一个没有参数输出int的函数。

However, I've used the following commandline: 但是,我使用了以下命令行:

swig.exe -namespace Test -o .\Test.cxx -c++ -module Test -csharp -outdir . test.i

This output the following Test.cs: 这输出以下Test.cs:

namespace Test {

using System;
using System.Runtime.InteropServices;

public class Test {
  public static void func(out int pOut) {
    TestPINVOKE.func(out pOut);
  }

}

}

How can I achieve the function signature I want, and how do I transfer this to an object type? 如何实现我想要的功能签名,以及如何将其传递给对象类型?

Looks like I've found a way to do this specifically in C#, although it should be extendable to other languages. 看起来我已经找到了一种在C#中专门执行此操作的方法,尽管它应该可以扩展到其他语言。

Consider this SWIG interface, where I've added additional arguments for dramatic effect: 考虑一下这个SWIG界面,我在其中添加了额外的参数以获得显着的效果:

%include <typemaps.i>

%{
class MyClass{};
void func(MyClass& pOut, int x);
MyClass* func2(int x);
%}

%typemap(ctype, out="void *") void func ""
%typemap(imtype, out="global::System.IntPtr") void func ""
%typemap(cstype, out="MyClass") void func ""
%typemap(in, numinputs=0, noblock=1) MyClass &pOut
{
    $1 = new MyClass();
}
%typemap(argout, noblock=1) MyClass &pOut
{
    $result = $1;
}
%typemap(csout, excode=SWIGEXCODE) void func
{
    IntPtr cPtr = $imcall;$excode
    MyClass ret = (cPtr != IntPtr.Zero) ? null : new MyClass(cPtr, $owner);
    return ret;
}

class MyClass{};
void func(MyClass& pOut, int x);
MyClass* func2(int x);

I've included func2 with the proper signature as well. 我也包含了func2以及正确的签名。

The first 3 %typemap s change the return type of the C++ wrapper function, C# interop method, and the C# wrapper method respectively. 前3 %typemap改变了C ++包装函数,C#interop方法和C#包装方法的返回类型。

The %typemap(in) removes the extraneous output parameter and adds code to use a new object in its place. %typemap(in)删除无关的输出参数,并添加代码以在其位置使用新对象。 This also, miraculously, leaves other arguments intact. 这也奇迹般地保留了其他论点。

The %typemap(argout) uses the output parameter value as the newly created return value. %typemap(argout)使用输出参数值作为新创建的返回值。

The %typemap(csout) rewrites the C# wrapper method code to utilize the return value of the interop method just like in the normal case. %typemap(csout)重写C#包装器方法代码以使用interop方法的返回值,就像在正常情况下一样。

Here are the example outputs proving it works like a charm: 以下示例输出证明它像魅力一样:

Test.cxx Test.cxx

SWIGEXPORT void * SWIGSTDCALL CSharp_func(int jarg2) {
  void * jresult ;
  MyClass *arg1 = 0 ;
  int arg2 ;

  arg1 = new MyClass();
  arg2 = (int)jarg2; 
  func(*arg1,arg2);
  jresult = arg1;
  return jresult;
}


SWIGEXPORT void * SWIGSTDCALL CSharp_func2(int jarg1) {
  void * jresult ;
  int arg1 ;
  MyClass *result = 0 ;

  arg1 = (int)jarg1; 
  result = (MyClass *)func2(arg1);
  jresult = (void *)result; 
  return jresult;
}

TestPINVOKE.cs TestPINVOKE.cs

[DllImport("Test", EntryPoint="CSharp_func")]
public static extern global::System.IntPtr func(int jarg2);

[DllImport("Test", EntryPoint="CSharp_func2")]
public static extern IntPtr func2(int jarg1);

Test.cs test.cs中

public class Test {
  public static MyClass func(int x) {
    IntPtr cPtr = TestPINVOKE.func(x);
    MyClass ret = (cPtr != IntPtr.Zero) ? null : new MyClass(cPtr, false);
    return ret;
}

  public static MyClass func2(int x) {
    IntPtr cPtr = TestPINVOKE.func2(x);
    MyClass ret = (cPtr == IntPtr.Zero) ? null : new MyClass(cPtr, false);
    return ret;
  }

}

The C#-specific %typemap s would need to be replaced with other language-specific ones to use with other languages, but alas I found no language-agnostic way to do it. C#特定的%typemap需要替换为其他语言特定的类型%typemap ,以便与其他语言一起使用,但是我发现没有与语言无关的方法。

To make this work easily with multiple types and functions, a macro could be defined. 为了使用多种类型和功能轻松完成这项工作,可以定义一个宏。

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

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