使用SWIG,你如何将C ++ void func(Class& out)包装为C#类func()? [英] With SWIG, how do you wrap C++ void func(Class& out) as C# Class 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 %typemap
s 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 %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.
To make this work easily with multiple types and functions, a macro could be defined.
这篇关于使用SWIG,你如何将C ++ void func(Class& out)包装为C#类func()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!