2013-01-16 35 views
0

我知道這個問題的一部分在這裏被一些帖子所覆蓋,我已經看過他們並測試了一些,但沒有運氣。 我應該填充提供CBadgeData結構數組與結果此機方法簽名:JNA - 使用結構數組作爲byref參數

int elc_GetBadges(int nHandle, char* cErr, int* nRecCount, CBadgeData** arr) 

的CBadgeData結構實現如下:

package test.elcprog; 

import java.util.Arrays; 
import java.util.List; 
import com.sun.jna.Pointer; 
import com.sun.jna.Structure; 

public class CBadgeData extends Structure{ 

    public static class ByReference extends CBadgeData implements Structure.ByReference { } 

    public int nBadgeID, nTrigger, nExtraData; 
    public String cName; 

    public CBadgeData(Pointer pointer){ 
     super(pointer); 
    } 

    public CBadgeData(){ } 

    public String ToString() { 
     return nBadgeID + "," + nTrigger + "," + nExtraData + "," + cName; 
    } 

    @Override 
    protected List getFieldOrder() { 
     String[] s = new String[]{"nBadgeID","nTrigger","nExtraData","cName"}; 
     return Arrays.asList(s); 
    } 
} 

我最後一次嘗試手藝這一觀點,並調用方法如下所示:

CBadgeData.ByReference[] badges = new CBadgeData.ByReference[max_items]; 
new CBadgeData.ByReference().toArray(badges); 
int ret = inst.elc_GetBadges(handle, err, recCount, badges); 

它會因分段錯誤而失敗。

我的問題是什麼Java類型應該在這裏作爲CBadgeData**的調用elc_GetBadges調用的參數提供?

EDIT -1-

填充陣列自己(有或沒有終止空指針)沒有工作,引起進一步波段崩潰。然後我用指針[] ARG作爲technomage建議:

Pointer[] pointers = new Pointer[max_items]; 
for(int i=0; i<max_items; i++){ 
    pointers[i] = new CBadgeData.ByReference().getPointer(); 
} 
int ret = inst.elc_GetBadges(handle, err, recCount, pointers); 

這導致沒有錯誤,但似乎沒有使應該有任何更改返回結構包含在這種情況下,4項:

int bid = new CBadgeData(pointers[i]).nBadgeID; // this returns null for all items 

在結構上使用顯式的read()/ write()導致seg再次崩潰(在讀): 任何想法我還在這裏失蹤了什麼?


編輯-2-

有趣的是 - 直接使用Memory.get,調用本地方法後,得到正確的結果:

Memory m= (Memory)pointers[0]; 
System.out.println("1st int: "+m.getInt(0)); // this gets 24289 which is 5ee1 
System.out.println("2nd int: "+m.getInt(4)); // this gets 3 
System.out.println("3rd int: "+m.getInt(8)); // this gets 255 
System.out.println("String: "+m.getString(12)); // this gets "Badge[5EE1]" as supposed 

read()仍然崩潰。有什麼想法嗎?

+0

存儲器轉儲打印在可尋址的順序的字節。在intel(little-endian)上,最低有效字節首先出現,所以[e15e0000]表示值00005ee1。這被稱爲字節排序,並且絕對不是與對齊相同的事情。 – technomage

+0

請發佈本機和Java結構定義。 – technomage

+0

我明白了(從q中刪除)。 那麼在讀'Memory'時'read()'可能會有什麼問題直接正常工作? – Aditi

回答

1

我推斷CBadgeData **輸入旨在是指向CBadgeData的指針數組。

因此,Structure.ByReference標記是正確的。

Structure.toArray()可能是而不是適合在這裏,或者至少不必要(它在內存中分配連續的結構塊)。你可以用CBadgeData.ByReference實例填充你的數組。

也許你的被調用者期望在數組的末尾有一個NULL指針?我沒有看到被調用者的數組長度的另一個指標。

CBadgeData.ByReference[] badges = new CBadgeData.ByReference[max_items+1]; 
for (int i=0;i < badges.length-1;i++) { 
    badges[i] = new CBadgeData.ByReference(); 
} 
badges[badges.length-1] = null; 

很確定這是有效的。如果因任何原因有一個錯誤處理Structure.ByReference[],我知道Pointer[]是可靠的,並會做同樣的事情。

編輯

如果使用Pointer[]代替Structure.ByReference[](請郵寄到項目現場,如果Structure.ByReference[]不起作用的錯誤),你將不得不手動調用Structure.write/read前/你的本地函數調用之後,因爲JNA不會知道指針引用需要與本機內存同步的結構。但我敢打賭,在使用Structure.ByReference[]當你崩潰的原因是僅僅是JNA來電後自動調用Structure.read(),並引發你看到顯式調用時相同的錯誤。

如果你在讀段錯誤,這可能意味着你的結構域沒有正確對齊或定義,或(不太可能),你有無法正確讀取損壞的數據。要診斷此,設置jna.dump_memory=true,並呼籲Structure.write(),看是否結構的內容顯示爲你所期望的後打印出你的結構。如果可能的話,它也可以幫助在這裏發佈你的結構的本地和JNA表單。

+0

謝謝!請參閱我的「答案」,其中包含您的建議。 爲什麼我不能「回答」你的答案,但只有評論的全部細節? – Aditi

+0

一般而言,在您的原始問題上添加一個附錄是非常有意義的,明確地標記爲這樣。 – technomage

+0

這樣做 - 請參閱**編輯-2 - ** – Aditi