2010-03-19 74 views
3

我有一些遗留代码,我想要移植到C#。我不能修改C++代码,我只需要处理我提供的内容。SWIG:C++到C#,指向指针编组的指针

所以,情况。我使用痛饮,我碰到这个功能来:

void MarshalMe(int iNum, FooClass** ioFooClassArray); 

如果我跑了SWIG这样,就不会知道如何处理数组做的,所以它会创建一个SWIGTYPE_p_pFooClass。很公平! 此C#代码看起来像

void MarshalMe(int iNum, SWIGTYPE_p_p_FooClass ioFooClassArray); // Not ideal! 

有一些技巧正确编组这种代码,所以我尝试了几个:

%typemap(ctype) FooClass** "FooClass**" 
%typemap(cstype) FooClass** "FooClass[]" 
%typemap(imtype, inattributes="[In, Out, MarshalAs(UnmanagedType.LPArray)]") FooClass** "FooClass[]" 
%typemap(csin) FooClass** "$csinput" 
%typemap(in)  FooClass** "$1 = $input;" 
%typemap(freearg) FooClass** "" 
%typemap(argout) FooClass** "" 

这有效地创建一个更好的签名:

void MarshalMe(int iNum, FooClass[] ioFooClassArray); // Looks good! Would it work? 

然而,当我尝试运行它,我得到以下错误:

{"Exception of type 'System.ExecutionEngineException' was thrown."} 

有关实际类型图的任何想法?

+0

这已经有一段时间,因为我感动C++所以请纠正我,如果我在这里是错误的,但不FooClass **暗示你处理二维对象? **指定尺寸的数量。 – 2010-03-19 18:50:02

回答

2

该异常告诉您该函数已损坏垃圾回收堆。它写过数组的末尾。如果它实际上是一个FooClass [],最大的问题,那么你就必须先创建数组:

FooClass[] array = new FooClass[666]; 
MarshalMe(42, array); 

即假设该函数将填补FooClass对象数组。数组的大小真的是这里很重要,你必须有一些想法你会回来多少元素。如果“iNum”是一个说明数组有多长的参数,那么这只能工作可靠。传递数组。长度。

它也可能意味着函数将创建数组本身并返回指向它的指针。如果是这样的话,你真的被搞砸了,你不能释放阵列的内存。

1

[痛饮]的Java:另一种方式来传递指针到指针

  1. 我有类似的问题与返回指针到指针作为输入参数的C函数(API)。我试图从JAVA调用C函数,我无法修改API。

的API.h头文件包含:

extern int ReadMessage(HEADER **hdr); 

原始C-呼叫看起来像:

HEADER *hdr; 
int status; 
status = ReadMessage(&hdr); 

API的功能是在指定的存储器位置的数据存储由指针指向。

  1. 我试着用SWIG创建适当的接口文件。 SWIG.i从API.h创建文件SWIGTYPE_p_p_header.java。问题是SWIGTYPE_p_p_header构造函数将swigCPtr初始化为0。

的Java调用看起来像:

SWIGTYPE_p_p_header hdr = new SWIGTYPE_p_p_header(); 
status = SWIG.ReadMessage(hdr); 

但是,当我从Java调用API的PTR总是0

  1. 我终于放弃了传递指针到指针作为输入参数。相反,我在SWIG.i中定义了另一个C函数来返回指针返回值。我认为这是一个Kludge ...但它工作!

你可以试试这个:

SWIG.i样子:

// return pointer-to-pointer 
%inline %{ 
    HEADER *ReadMessageHelper() { 
    HEADER *hdr; 
    int returnValue; 
    returnValue = ReadMessage(&hdr); 
    if (returnValue!= 1) hdr = NULL; 
    return hdr; 
}%} 
  1. 如Java不会采取创建的内存的所有权上面的内联函数可能泄漏内存通过ReadMessageHelper,因为HEADER实例在堆上创建。

内存泄漏的修复是将ReadMessageHelper定义为newobject,以便Java控制内存。

%newobject ReadMessageHelper(); 

JAVA call now would look like: 
    HEADER hdr; 
    hdr = SWIG.ReadMessageHelper(); 
  1. 如果你是幸运的,因为我是,你可能有另一个可用的API发布消息缓冲区。在这种情况下,你就不必做步骤4

  2. 威廉·富尔顿的SWIG大师,曾这样说上面的方法:

“我不看助手作为一种混合物发挥作用,更棘手的问题的最简单的解决方案。考虑ReadMessage()的等效纯100%Java代码。我不认为有类似的东西,因为Java类是通过引用传递的,并且不存在对引用的引用或指向Java中指针的指针。在C函数中,HEADER实例由ReadMessage创建并传回给调用者。如果不在HEADER周围提供一些包装类并将包装传递给ReadMessage函数,我不会看到如何在Java中执行相同的操作。在一天结束时,ReadMessage返回一个新创建的HEADER,返回新创建对象的Java方法是将其返回到返回值中,而不是通过参数。“

0

使用SWIG typemap传递pointer-to-指针:

这是另一种使用类型映射的方法。它的目标是Perl,而不是Java,但概念是相同的。我终于设法得到它的工作使用typemaps,没有辅助功能:

对于此功能:

typedef void * MyType; 
int getblock(int a, int b, MyType *block); 

我有2个typemaps:

%typemap(perl5, in, numinputs=0) void ** data(void * scrap) 
{ 
    $1 = &scrap; 
} 

%typemap(perl5, argout) void ** data 
{ 
    SV* tempsv = sv_newmortal(); 
    if (argvi >= items) EXTEND(sp,1); 
    SWIG_MakePtr(tempsv, (void *)*$1, $descriptor(void *), 0); 
    $result = tempsv; 
    argvi++; 
} 

和功能定义为:

int getblock(int a, int b, void ** data); 

在我的swig .i文件中。现在,这会在argout typemap中传回一个不透明指针,因为这对于这种特殊情况非常有用,但是,如果需要,您可以用指针中的数据替换SWIG_MakePtr行来实际执行某些操作。此外,当我想将指针传递到一个函数,我有一个类型映射,看起来像这样:

%typemap(perl5, in) void * data 
{ 
    if (!(SvROK($input)) croak("Not a reference...\n"); 

    if (SWIG_ConvertPtr($input, (void **) &$1, $1_descriptor, 0) == -1) 
     croak("Couldn't convert $1 to $1_descriptor\n"); 
} 

和函数的定义为:

int useblock(void * data); 

在我痛饮.i文件。

显然,这是所有perl,但应该直接映射到Java,就像typemap体系结构一样。希望它有帮助...

0

我设法解决这个使用Swig Managed Arrays and Pinning文档。

Given a function in C++

void myArrayCopy(int *sourceArray, int *targetArray, int nitems);

Declare the method as unsafe in C#

%csmethodmodifiers myArrayCopy "public unsafe";

Add the appropriate typemaps

%include "arrays_csharp.i" 
%apply int FIXED[] {int *sourceArray} 
%apply int FIXED[] {int *targetArray} 

As a result, we get the following method in the module class:

public unsafe static void myArrayCopy(int[] sourceArray, int[] targetArray, int nitems) 
{ 
    fixed (int *swig_ptrTo_sourceArray = sourceArray) 
    { 
     fixed (int *swig_ptrTo_targetArray = targetArray) 
     { 
      examplePINVOKE.myArrayCopy((IntPtr)swig_ptrTo_sourceArray,    

       (IntPtr)swig_ptrTo_targetArray, 
       nitems); 
     } 
    } 
} 

在实践中,这可能会有点不同与FooClass **但痛饮不支持直接指向指针编组,这也避免了拷贝,以及因此可以认为更好的性能