JNA:通过jdk-11 64位调用dll的COM方法时无效的内存访问



我使用JNA(5.9.0)访问COM库gbda_aut.dll以连接到OPC服务器。当我使用64位版本的dll时,出现这个问题。

我已经通过代码生成器TlbCodeGenerator创建了类。因此,我有一个接口OPCItems与以下方法:

/**
* Adds an OPCItem object to the collection
*
* <p>id(0x6002000b)</p>
* <p>vtableId(18)</p>
* @param ItemID [in] {@code String}
* @param ClientHandle [in] {@code Integer}
*/
@ComMethod(name = "AddItem", dispId = 0x6002000b)
OPCItem AddItem(String ItemID, int ClientHandle);

在OLE/COM对象查看器中此dll的相同方法:

[id(0x6002000b), helpstring("Adds an OPCItem object to the collection")]
HRESULT AddItem(
[in] BSTR ItemID, 
[in] long ClientHandle, 
[out, retval] OPCItem** ppItem);
我的测试代码:
Ole32.INSTANCE.CoInitializeEx(Pointer.NULL, Ole32.COINIT_MULTITHREADED);
ObjectFactory factory = new ObjectFactory();
OPCServer opcServer = factory.createObject(OPCServer.class);
opcServer.Connect("Matrikon.OPC.Simulation", null);
OPCGroups opcGroups = opcServer.getOPCGroups();
OPCGroup opcGroup = opcGroups.Add("TestGroup");
OPCItems opcItems = opcGroup.getOPCItems();
OPCItem opcItem = opcItems.AddItem("TestGroup.DoubleTag", 1); // invalid memory access via JDK 11 x64 + Windows 10
System.out.println(opcItem.getValue()); // works with Windows before 10 or jdk 8
opcServer.Disconnect();

连接正常,其他方法工作正常。错误发生在方法AddItem中,异常为:

Exception in thread "main" java.lang.Error: Invalid memory access
at com.sun.jna.Native.invokeInt(Native Method)
at com.sun.jna.Function.invoke(Function.java:426)
at com.sun.jna.Function.invoke(Function.java:361)
at com.sun.jna.Function.invoke(Function.java:315)
at com.sun.jna.Function.invoke(Function.java:306)
at com.sun.jna.platform.win32.COM.COMInvoker._invokeNativeObject(COMInvoker.java:48)
at com.sun.jna.platform.win32.COM.Dispatch.Invoke(Dispatch.java:145)
at com.sun.jna.platform.win32.COM.util.ProxyObject.oleMethod(ProxyObject.java:726)
at com.sun.jna.platform.win32.COM.util.ProxyObject.invokeMethod(ProxyObject.java:450)
at com.sun.jna.platform.win32.COM.util.ProxyObject.invoke(ProxyObject.java:256)
at com.sun.proxy.$Proxy12.AddItem(Unknown Source)
at test.OpcTest.main(OpcTest.java:20)

我在不同版本的JDK和Windows上测试了它,得到了以下结果:

Java 8 x32Java 8 x64Java 11x32Java 11x64异常Java 16x64异常

要映射的函数有三个参数:

HRESULT AddItem(
[in] BSTR ItemID, 
[in] long ClientHandle, 
[out, retval] OPCItem** ppItem);

但是你的实现只有两个:

OPCItem AddItem(String ItemID, int ClientHandle);

在代码库的某个地方有一个实现,它将两个参数的Java方法映射到三个参数的本机函数:

  • 确保函数中的ppItemPointerByReference类型
  • 确保返回的OPCItem对象是从ppItem.getValue()实例化的

确保正确使用32位或64位版本的dll。long参数类型可能是32位或64位。而在Windows上,LONG总是32位的,小写的long可能表示你的dll中的可变宽度类型,你可以尝试NativeLong作为映射中ClientHandle的类型。

相关内容

最新更新