java - 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 对其进行了测试,得到了以下结果:
赢 7 | 赢2008服务器 | 赢得 10 | 赢2012服务器 | |
---|---|---|---|---|
Java 8 x32 | 好的 | 好的 | 好的 | 好的 |
Java 8 x64 | 好的 | 好的 | 好的 | 好的 |
Java 11 x32 | 好的 | 好的 | 好的 | 好的 |
Java 11 x64 | 好的 | 好的 | 例外 | 例外 |
Java 16 x64 | 好的 | 好的 | 例外 | 例外 |
我猜错误发生在本机 dll 代码中,但我不清楚为什么在旧版本的 Java 或 Windows 上一切正常。我无权访问 dll 代码,也无法更改它。
是否可以正确调用该方法,从而在 JDK 11 64bit + Windows 10/2012 中不会出现错误?
我会很感激任何帮助。
解决方案
您正在映射的函数具有三个参数:
HRESULT AddItem(
[in] BSTR ItemID,
[in] long ClientHandle,
[out, retval] OPCItem** ppItem);
但是您的实现只有两个:
OPCItem AddItem(String ItemID, int ClientHandle);
在您的代码库中的某处是一个实现,它将您的双参数 Java 方法映射到三参数本机函数:
- 确保
ppItem
该函数是一种PointerByReference
类型 - 确保返回
OPCItem
对象是从实例化的ppItem.getValue()
确保您正确使用 32 位或 64 位版本的 dll。参数类型可能long
是 32 位或 64 位。在 Windows 上,LONG
始终为 32 位,小写long
可能表示您的 dll 中的可变宽度类型,您可以尝试映射中NativeLong
的类型。ClientHandle
推荐阅读
- python - 朱莉娅初始化数组未知大小
- scala - 找不到类型 EnvT
- swift - 为什么静态属性不能在 Swift 中显式使用 self?
- r - 使用两个记录分隔符读取 ASCII、固定长度字段/记录
- python - 在 EXCEL(.xlsx) 中的数据框 python 00:00:00 中删除
- asp.net-core-webapi - 带有 Identity Server 4 自定义密码验证的 Net Core 3.1 API
- python - 有没有办法创建一个值映射到索引/行对的 Pandas 数据框?
- c# - ECDiffieHellmanCng 安全吗?
- java - 无法从 mapStruct 自动装配 Mapper
- javascript - 如何在 Open Weather Map 上进行在线天气预报?