2017-04-11 694 views
3

我在C#中的方法,這是我從.DLLC#出的IntPtr相當於在Java中

[DllImport("somedll.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern int find([MarshalAs(UnmanagedType.AnsiBStr, SizeConst = 64)] string atr, out IntPtr int); 

[DllImport("somedll.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern int getData(IntPtr int, int dataId, byte[] dataBuffer, ref int dataBufferSize); 

調用這個方法C#調用如下

static IntPtr number = IntPtr.Zero; 
static int res = 0; 
try{ 
    number = IntPtr.Zero; 
    res = find(null, out number); 
    if (number == IntPtr.Zero) 
       throw new ApplicationException("Something is wrong"); 
    uint dataBufferSize = 1024; 
    res = getData(number, 1, null, ref dataBufferSize); 
} 

我沒有發現什麼在Java中是相同的。

如果我不喜歡這樣寫道:

public int find(String atr, Pointer int); 

它說

java.lang.Error: Invalid memory access 
at com.sun.jna.Native.invokeInt(Native Method) 
at com.sun.jna.Function.invoke(Function.java:419) 
at com.sun.jna.Function.invoke(Function.java:354) 
at com.sun.jna.Library$Handler.invoke(Library.java:244) 

如果我不喜歡這樣寫道:

public int find(String atr, IntByReference int); 

什麼也沒有發生。

Java代碼

IntByReference iref = new IntByReference();      
res = find(null, iref);            
Pointer pointer = iref.getPointer();        
int dataBufferSize = 1024; 
byte[] dataBuffer = new byte[dataBufferSize]; 
res = getData(Pointer.nativeValue(pointer), 1, dataBuffer, dataBufferSize); 

find返回0,這意味着OK,但返回的getData 6,這意味着內存地址也不好。通過什麼也沒有發生我的意思是任何其他res比0.

+0

所以,也許你應該放棄C#的標籤,並添加JNI,JNA或標籤? –

+0

(我的意思是,你根本不需要添加任何標籤,如果你願意的話,甚至可以使用完全誤導性的標籤,但那些可能提供答案的人可能不會看到你的問題。) –

+1

可能的重複[如何做相當於Java基元的引用傳遞](http://stackoverflow.com/questions/5614562/how-to-do-the-equivalent-of-pass-by-reference-for -primitives-in-java) – kennytm

回答

0

IntByReference是一種可能的正確映射(取決於指針指向什麼);但是,您要查找的值是相應的Pointer內部的本機「同級」值。您可能需要改用PointerType。無論哪種方式,Invalid Memory Access都與嘗試訪問您尚未分配的Native端內存有關。一個普通的Pointer不分配任何內存本機端:通常你會使用new Memory()初始化一個指針並分配它指向的內存。 (如果你創建了ByReference類型中的一種,它分配適當的大小存在,這就是爲什麼錯誤消失。)

IntPtr是代表實際的內存地址,你必須從IntByReference提取的整數值或PointerType通過使用getPointer()獲取Pointer對象,然後將其傳遞到Pointer.nativeValue()以返回與您的IntPtr對應的(long)內存地址。

更新響應您的編輯代碼:

一些錯誤的映射可能會引發問題:

getData()簽名要求dataBufferSize是爲int的引用,所以你應該使用IntByReference爲那個變量。

您無法將純數組從Java傳遞到本機端。你需要爲它分配內存。例如:

Pointer dataBuffer = new Memory(dataBufferSize); 
// call getData(); 
byte[] foo = dataBuffer.getByteArray(0, dataBufferSize); 

其他更新:

看來,find()方法調用返回一個指針到你想要的內存地址,所以你從find()承擔由此產生的IntByReference和使用getValue()來傳遞整數getData()

您可能需要進一步處理產生的byte[]陣列。您尚未提供該API的文檔,但如果它返回dataBufferSize的不同值,則可能需要截斷您的字節數組以匹配。既然你命名你IntByReference傳遞給getData()iref,這將是:

byte[] dataByteArray = new byte[iref.getValue()]; 
System.arraycopy(dataBuffer, 0, dataByteArray, 0, iref.getValue()); 
String data = new String(dataByteArray, "UTF-8"); 

如果C字符串比ASCII編碼的不同,你可能需要使用不同的轉換。

+0

現在我有另一個問題,我怎麼能從dataBuffer獲取字符串? 'String str = new String(dataBuffer,「UTF8」);'產生奇怪的字符 – vuis

+0

我不知道你的數據是如何編碼的。它是ASCII碼嗎? UTF-8有一個連字符。 –

+0

C#字節數組和Java中的值不一樣。在C#中,我得到4個字節,但在Java中,我獲得了更多。 – vuis

0

它工作,如果我通過number.getValue()getData()。現在水庫爲0

完整代碼:

IntByReference number=new IntByReference(0);       
res = find(null, number);         
int dataBufferSize = 1024; 
IntByReference iref=new IntByReference(dataBufferSize); 
Pointer array = new Memory(dataBufferSize);       
res = getData(number.getValue(),1, array,iref);     
byte[] dataBuffer=array.getByteArray(0,dataBufferSize);