使用SWIG,你如何将C ++ void func(Class& out)包装为C#类func()? [英] With SWIG, how do you wrap C++ void func(Class& out) as C# Class func()?

查看:298
本文介绍了使用SWIG,你如何将C ++ void func(Class& out)包装为C#类func()?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



假设一个C ++函数使用这种典型的返回风格类类型:

  void func(Class& out); 

使用SWIG,此函数应该包装在C#中,如下所示:

  Class func(); 

从我发现的,我可以使用一个typemap来完成这个。



假设 Class 实际上是 int ,我试过下面的我发现:

 %include< typemaps.i> 

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

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

很多例子(倾向于Python)表明这应该创建一个没有参数的函数输出但是,我使用以下命令行:


$

b $ b

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

输出以下Test.cs:

 命名空间test {

使用System;
using System.Runtime.InteropServices;

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

}

}

如何实现我想要的函数签名,如何将它传递给一个对象类型?

解决方案

我已经找到了一种方法,在C#中具体做这 ,虽然它应该可扩展到其他语言。



考虑这个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!零)? null:new MyClass(cPtr,$ owner);
return ret;
}

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

我已将 func2



第一个3 %typemap 改变C ++ wrapper函数的返回类型,C#interop方法和C#wrapper方法。



%typemap(in)删除了额外的输出参数,在其位置使用新对象的代码。



%typemap(argout)使用输出参数值作为



%typemap(csout)重写C#封装方法代码以利用返回



以下是证明它的工作原理类似于charm的示例输出:



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

  [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


$ b b

  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;
}

}

$ c>%typemap 需要被其他语言替换为其他语言使用,但是我发现没有语言无关的方式。



为了使这个工作轻松与多种类型和功能,可以定义一个宏。


(Unfortunately, SWIG's documentation is very difficult to parse and online examples seem rare. So I come here.)

Suppose a C++ function uses this typical return style for a class type:

void func(Class& out);

Using SWIG, this function should be wrapped in C# like this:

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:

%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.

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:

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.

Consider this SWIG interface, where I've added additional arguments for dramatic effect:

%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.

The first 3 %typemaps change the return type of the C++ wrapper function, C# interop method, and the C# wrapper method respectively.

The %typemap(in) removes the extraneous output parameter and adds code to use a new object in its place. This also, miraculously, leaves other arguments intact.

The %typemap(argout) uses the output parameter value as the newly created return value.

The %typemap(csout) rewrites the C# wrapper method code to utilize the return value of the interop method just like in the normal case.

Here are the example outputs proving it works like a charm:

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

[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

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 %typemaps 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.

To make this work easily with multiple types and functions, a macro could be defined.

这篇关于使用SWIG,你如何将C ++ void func(Class&amp; out)包装为C#类func()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆