C# out IntPtr 在 Java 中等效

vui*_*uis 5 java pointers jna intptr

我在 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);
Run Code Online (Sandbox Code Playgroud)

在 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);
}
Run Code Online (Sandbox Code Playgroud)

我没有找到 Java 中的等价物。

如果我这样做:

public int find(String atr, Pointer int);
Run Code Online (Sandbox Code Playgroud)

它说

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)
Run Code Online (Sandbox Code Playgroud)

如果我这样做:

 public int find(String atr, IntByReference int);
Run Code Online (Sandbox Code Playgroud)

没发生什么事。

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);
Run Code Online (Sandbox Code Playgroud)

find 返回 0,表示 OK,而 getData 返回 6,表示内存地址不好。没有任何反应是指除 0 以外的任何其他资源。

Dan*_*dis 0

IntByReference是可能的正确映射(取决于指针指向的内容);但是,您要查找的值是相应Pointer. 您可能想改用PointerType。无论哪种方式,这Invalid Memory Access都与尝试访问尚未分配的本机端内存有关。plainPointer不会在本机端分配任何内存:通常您会使用 anew Memory()来初始化指针并分配它指向的内存。(如果您创建其中一种ByReference类型,它会在那里分配适当的大小,这就是该错误消失的原因。)

AnIntPtr是一个代表实际内存地址的整数值,您必须使用IntByReferenceor来提取该地址以获取对象,然后将其传递给以返回与您的.PointerTypegetPointer()PointerPointer.nativeValue()longIntPtr

更新以响应您编辑的代码:

一些可能导致问题的错误映射:

for 的签名getData()需要dataBufferSize是对 int 的引用,因此您应该使用IntByReferencefor 该变量。

您无法将普通数组从 Java 传递到本机端。您需要为其分配内存。例如:

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

附加更新:

看起来该方法调用返回一个指向您想要的内存地址的指针,因此您获取find()结果并使用该整数将该整数传递给。IntByReferencefind()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");
Run Code Online (Sandbox Code Playgroud)

如果 C 字符串的编码方式与 ASCII 不同,您可能需要使用不同的转换。