看来我找到了一种方法来做到这一点具体来说在 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 != IntPtr.Zero) ? null : new MyClass(cPtr, $owner);
return ret;
}
class MyClass{};
void func(MyClass& pOut, int x);
MyClass* func2(int x);
我已经包括了func2
也有正确的签名。
前 3 个%typemap
分别更改 C++ 包装函数、C# 互操作方法和 C# 包装方法的返回类型。
The %typemap(in)
删除无关的输出参数并添加代码以在其位置使用新对象。这也奇迹般地让其他论点完好无损。
The %typemap(argout)
使用输出参数值作为新创建的返回值。
The %typemap(csout)
重写 C# 包装器方法代码以利用互操作方法的返回值,就像正常情况一样。
以下是证明它具有魅力的输出示例:
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;
}
测试PINVOKE.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;
}
}
C# 特定的%typemap
需要用其他特定语言的替换来与其他语言一起使用,但可惜我没有找到与语言无关的方法来做到这一点。
为了使此操作能够轻松地使用多种类型和函数,可以定义一个宏。