【问题标题】:C# out IntPtr equivalent in JavaC# out IntPtr 在 Java 中等效
【发布时间】:2017-09-06 10:08:22
【问题描述】:

我有一个从 .dll 调用的 C# 方法

[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 表示内存地址不好。什么都没发生,我的意思是除 0 以外的任何其他 res。

【问题讨论】:

  • 那么,也许您应该删除 C# 标签并添加 JNI 或 JNA 标签?
  • (我的意思是,您根本不必添加任何标签,如果您愿意,您甚至可以使用完全误导性的标签,但是可能能够提供答案的人可能会没有看到你的问题。)
  • @kennytm 这不是这个问题的有效副本
  • IntPtr 在 32 位系统上是 32 位,在 64 位系统上是 64 位,您可能正在寻找 NativeLongByReference 代替(尽管我不确定它在 Windows 上的行为)。

标签: java pointers jna intptr


【解决方案1】:

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

IntPtr 是一个表示实际内存地址的整数值,您必须从IntByReferencePointerType 中提取该地址,方法是使用getPointer() 获取Pointer 对象,然后将其传递给@ 987654333@返回你的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 返回不同的值,您可能需要截断字节数组以匹配。由于您将传递给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 不同,您可能需要使用不同的转换。

【讨论】:

  • 现在我还有一个问题,如何从dataBuffer中获取字符串? String str=new String(dataBuffer,"UTF8"); 产生奇怪的字符
  • 我不知道你的数据是如何编码的。是ASCII吗? UTF-8 有一个连字符。
  • C#字节数组和Java中的值不一样。在 C# 中我得到 4 个字节,但在 Java 中我得到更多。
  • Pointer memory = new Memory(dataBufferSize.getValue()); byte[] buffer = memory.getByteArray(0, dataBufferSize.getValue()); String bufferContent = new String(buffer,"UTF-8"); bufferContent 在调用 getData() 之前已包含一些字符。 res = getData(number.getValue(),1, array,iref); byte[] dataBufferAfter=array.getByteArray(0,dataBufferSize);String bufferContentAfter= new String(dataBufferAfter,"UTF-8"); bufferContent 和 bufferContentAfter 是一样的
  • 评论里的代码真的很难看懂。由于这超出了原始问题的范围,您可能会考虑一个新问题。一般的调试步骤是将字节数组值输出为整数,看看你是否能找出编码的字符串。 C 使用以 null 结尾的字符串,而 Java 忽略您使用的 new String() 代码中的零。你可以trim(),如果后面都是零,但最好的办法是找到字符串长度(我假设iref.getValue()告诉你这个)并截断数组并用它创建字符串。
【解决方案2】:

如果我将 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); 

【讨论】:

    猜你喜欢
    • 2023-03-26
    • 2023-04-06
    • 2018-07-22
    • 2013-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-24
    • 1970-01-01
    相关资源
    最近更新 更多