2010-03-19 110 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 **但痛飲不支持直接指向指針編組,這也避免了拷貝,以及因此可以認爲更好的性能