jna 构造函数_java - 使用JNA从结构内部的结构数组读取时进行无效的内存访问 - 堆栈内存溢出...

在将C#应用迁移至Java的过程中,遇到使用JNA调用DLL时,处理结构体数组导致的内存访问错误。C#中的结构体包含字符串和布尔值,Java端使用JNA映射时,尝试读取结构体数组,出现空字符串或内存访问错误。分析了不同结构体映射方式的影响,并展示了错误发生的具体堆栈。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我的任务是将C#应用程序迁移到Java应用程序。 C#应用程序使用几个DLL来完成其工作,并与外围设备进行通信。

DLL的标头在C#中看起来像这样

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]

public struct InnerStructure

{

/// COM port used by the device

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = PORT_SIZE)] //7

public string szPort;

/// Specifies whether the device is activated.

public bool fActivated;

/// Name of the device

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_NAME_SIZE)] //248

public string szName; //COM

}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]

public struct ParamStructure

{

/// COM port used by the devices

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]

public InnerStructure[] USB;

}

[DllImport("PCLService.dll", CallingConvention = CallingConvention.Cdecl)]

public static extern bool startPclService();

[DllImport("PCLService.dll", CallingConvention = CallingConvention.Cdecl)]

public static extern bool stopPclService();

[DllImport("PclUtilities.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]

public static extern int getUSBDevices(ref ParamStructure pStructure, ref int pdwSize, ref int pdwEntries);

我最初尝试使用JNI,但是我无法加载DLL(它们使用.NET,因此很难通过DependenciesWalker查找依赖项),因此我改用了JNA。

这是我的Java代码

public class DllDemo {

@Structure.FieldOrder({ "szPort", "fActivated", "szName" })

public static class InnerStructure extends Structure {

public PointerByReference szPort;

public IntByReference fActivated;

public PointerByReference szName;

public InnerStructure() {};

public InnerStructure(Pointer p) {

super(p);

read();

};

}

@Structure.FieldOrder({ "USB" })

public static class ParamStructure extends Structure implements Structure.ByReference {

// In the C# code, the array is size 10

public InnerStructure[] USB = (InnerStructure[])new InnerStructure().toArray(10);

public ParamStructure() {};

public ParamStructure(Pointer p) {

super(p);

read();

};

}

public interface MyService extends Library {

MyService INSTANCE = (MyService) Native.load("C:\\IRD\\Documentacion\\VisaNet\\App PCL Demo VisaNet - V2.11\\x32\\PCLService.dll", MyService.class);

boolean startPclService();

boolean stopPclService();

}

public interface MyUtilities extends Library {

MyUtilities INSTANCE = (MyUtilities) Native.load("C:\\IRD\\Documentacion\\VisaNet\\App PCL Demo VisaNet - V2.11\\x32\\PclUtilities", MyUtilities.class);

int getUSBDevices(ParamStructure paramStructure, IntByReference pdwSize, IntByReference pdwEntries);

}

public static void main(String args[]) {

System.out.println("start");

MyService.INSTANCE.startPclService();

ParamStructure paramStructure = new ParamStructure();

paramStructure.write();

//This value is copied straightforward from the original code as well

int size = (248 + 8 + 7) * 10;

IntByReference pdwSize = new IntByReference(size);

IntByReference pdwEntries = new IntByReference(0);

int Ret2 = MyUtilities.INSTANCE.getUSBDevices(paramStructure, pdwSize, pdwEntries);

System.out.println("Ret2 = " + Ret2 + ", pdwEntries = " + pdwEntries.getValue());

if (pdwEntries.getValue() > 0) {

for (int i = 0 ; i < pdwEntries.getValue() ; i++) {

InnerStructure inner = paramStructure.USB[i];

inner.read();

System.out.println(i + " => " + inner.toString());

System.out.println("toString 1 => " + inner.szPort.toString());

System.out.println("toString 2 => " + inner.szPort.getPointer().toString());

System.out.println(">" + inner.szPort.getPointer().getString(0, "utf8") + "

}

}

paramStructure.clear();

MyService.INSTANCE.stopPclService();

System.out.println("stop");

}

}

这就是输出。

start

Ret2 = 0, pdwEntries = 1

0 => DllDemo$InnerStructure(allocated@0x59b550 (12 bytes) (shared from auto-allocated@0x59b550 (120 bytes))) {

PointerByReference szPort@0x0=native@0x4f0043 (com.sun.jna.ptr.PointerByReference@4f0043)

IntByReference fActivated@0x4=native@0x35004d (com.sun.jna.ptr.IntByReference@35004d)

PointerByReference szName@0x8=null

}

toString 1 => native@0x4f0043 (com.sun.jna.ptr.PointerByReference@4f0043)

toString 2 => native@0x4f0043

Exception in thread "main" java.lang.Error: Invalid memory access

at com.sun.jna.Native.getStringBytes(Native Method)

at com.sun.jna.Native.getString(Native.java:2224)

at com.sun.jna.Pointer.getString(Pointer.java:681)

at com.ingenico.DllDemo.main(DllDemo.java:65)

Process finished with exit code 1

65行是这个

System.out.println(">" + inner.szPort.getPointer().getString(0, "utf8") + "

有时它不会给出错误,但是字符串为空。 我还不知道为什么会这样。

在两个类中以及行paramStructure.write()和inner.read()中是否存在构造函数都没有区别。

无论价值如何,这就是IntelliJ在调试器中的外观

我尝试过这样改变内部结构

public static class InnerStructure extends Structure implements Structure.ByReference {

public PointerByReference szPort;

public IntByReference fActivated;

public PointerByReference szName;

public InnerStructure() {};

public InnerStructure(Pointer p) { super(p); };

}

甚至像这样。

public static class InnerStructure extends Structure implements Structure.ByReference {

public String szPort;

public int fActivated;

public String szName;

public InnerStructure() {};

public InnerStructure(Pointer p) { super(p); };

}

在两种情况下,我都会

Exception in thread "main" java.lang.Error: Invalid memory access

at com.sun.jna.Native._getPointer(Native Method)

at com.sun.jna.Native.getPointer(Native.java:2211)

at com.sun.jna.Pointer.getPointer(Pointer.java:642)

at com.sun.jna.Pointer.getValue(Pointer.java:390)

at com.sun.jna.Structure.readField(Structure.java:732)

at com.sun.jna.Structure.read(Structure.java:591)

at com.sun.jna.Structure.autoRead(Structure.java:2141)

at com.sun.jna.Structure.conditionalAutoRead(Structure.java:561)

at com.sun.jna.Structure.updateStructureByReference(Structure.java:690)

at com.sun.jna.Pointer.readArray(Pointer.java:492)

at com.sun.jna.Pointer.getValue(Pointer.java:450)

at com.sun.jna.Structure.readField(Structure.java:732)

at com.sun.jna.Structure.read(Structure.java:591)

at com.sun.jna.Structure.autoRead(Structure.java:2141)

at com.sun.jna.Function.invoke(Function.java:381)

at com.sun.jna.Library$Handler.invoke(Library.java:265)

at com.sun.proxy.$Proxy3.getUSBDevices(Unknown Source)

at com.ingenico.DllDemo.main(DllDemo.java:49)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值