我的任务是将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)