2017-04-11 80 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);