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

爷,独闯天下 提交于 2019-12-12 16:20:07

问题


(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?


回答1:


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.



来源:https://stackoverflow.com/questions/28633504/with-swig-how-do-you-wrap-c-void-funcclass-out-as-c-sharp-class-func

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!