C# out IntPtr 等效于 Java
C# out IntPtr equivalent in Java
我在 C# 中有一个从 .dll 调用的方法
[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 returns 0,表示OK,但是getData returns 6,表示内存地址不好。什么都没有发生,我的意思是除 0 之外的任何其他资源。
IntByReference
是可能的正确映射(取决于指针指向的内容);但是,您要查找的值是相应 Pointer
中的本机 "peer" 值。您可能想改用 PointerType
。无论哪种方式, Invalid Memory Access
都与尝试访问您尚未分配的本机端内存有关。一个普通的 Pointer
不分配任何本地内存:通常你会使用 new Memory()
来初始化一个指针并分配它指向的内存。 (如果您创建 ByReference
类型之一,它会在那里分配适当的大小,这就是错误消失的原因。)
一个 IntPtr
是一个整数值,表示实际内存地址,您必须使用 getPointer()
从 IntByReference
或 PointerType
中提取它以获得 Pointer
对象,然后将其传递给 Pointer.nativeValue()
到 return 对应于您的 IntPtr
.
的 (long
) 内存地址
已根据您编辑的代码更新:
一些可能导致问题的错误映射:
getData()
的签名要求 dataBufferSize
是对 int 的引用,因此您应该为该变量使用 IntByReference
。
您不能将普通数组从 Java 传递到本机端。您需要为其分配内存。例如:
Pointer dataBuffer = new Memory(dataBufferSize);
// call getData();
byte[] foo = dataBuffer.getByteArray(0, dataBufferSize);
补充更新:
看起来 find()
方法调用 return 是指向您想要的内存地址的指针,因此您从 find()
中获取结果 IntByReference
并使用 getValue()
将该整数传递给 getData()
.
您可能需要进一步处理生成的 byte[]
数组。您没有提供 API 的文档,但如果 return 是 dataBufferSize
的不同值,您可能需要截断字节数组以匹配。由于您将传递给 getData()
的 IntByReference
命名为 iref
,这将是:
byte[] dataByteArray = new byte[iref.getValue()];
System.arraycopy( dataBuffer, 0, dataByteArray, 0, iref.getValue());
String data = new String(dataByteArray, "UTF-8");
如果 C 字符串的编码不同于 ASCII,您可能需要使用不同的转换。
如果我将 number.getValue() 传递给 getData(),它会起作用。现在 res 为 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);
我在 C# 中有一个从 .dll 调用的方法
[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 returns 0,表示OK,但是getData returns 6,表示内存地址不好。什么都没有发生,我的意思是除 0 之外的任何其他资源。
IntByReference
是可能的正确映射(取决于指针指向的内容);但是,您要查找的值是相应 Pointer
中的本机 "peer" 值。您可能想改用 PointerType
。无论哪种方式, Invalid Memory Access
都与尝试访问您尚未分配的本机端内存有关。一个普通的 Pointer
不分配任何本地内存:通常你会使用 new Memory()
来初始化一个指针并分配它指向的内存。 (如果您创建 ByReference
类型之一,它会在那里分配适当的大小,这就是错误消失的原因。)
一个 IntPtr
是一个整数值,表示实际内存地址,您必须使用 getPointer()
从 IntByReference
或 PointerType
中提取它以获得 Pointer
对象,然后将其传递给 Pointer.nativeValue()
到 return 对应于您的 IntPtr
.
long
) 内存地址
已根据您编辑的代码更新:
一些可能导致问题的错误映射:
getData()
的签名要求 dataBufferSize
是对 int 的引用,因此您应该为该变量使用 IntByReference
。
您不能将普通数组从 Java 传递到本机端。您需要为其分配内存。例如:
Pointer dataBuffer = new Memory(dataBufferSize);
// call getData();
byte[] foo = dataBuffer.getByteArray(0, dataBufferSize);
补充更新:
看起来 find()
方法调用 return 是指向您想要的内存地址的指针,因此您从 find()
中获取结果 IntByReference
并使用 getValue()
将该整数传递给 getData()
.
您可能需要进一步处理生成的 byte[]
数组。您没有提供 API 的文档,但如果 return 是 dataBufferSize
的不同值,您可能需要截断字节数组以匹配。由于您将传递给 getData()
的 IntByReference
命名为 iref
,这将是:
byte[] dataByteArray = new byte[iref.getValue()];
System.arraycopy( dataBuffer, 0, dataByteArray, 0, iref.getValue());
String data = new String(dataByteArray, "UTF-8");
如果 C 字符串的编码不同于 ASCII,您可能需要使用不同的转换。
如果我将 number.getValue() 传递给 getData(),它会起作用。现在 res 为 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);