JNA 可以用于像 IMAPI 这样的复杂 Windows DLL
Posted
技术标签:
【中文标题】JNA 可以用于像 IMAPI 这样的复杂 Windows DLL【英文标题】:Can JNA be used for a complex Windows DLL like IMAPI 【发布时间】:2022-01-03 15:34:47 【问题描述】:我已经设法让 COM4J 使用 windows IMAPI 中的一些功能(CD 写入)。
但是,我未能让任何返回 SAFEARRAY 的调用正常工作,但该项目目前似乎没有处于活动状态......
DLL一般在C:\Windows\System32\imapi2.dll,使用它也需要使用C:\Windows\System32\imapi2fs.dll
四处寻找一个活跃的 JAVA-COM 桥接项目将我带到了 JNA。
简化 JAVA-COM 桥接项目的职责引起了我的兴趣....但是我遇到了第一个障碍,希望有人能提供帮助。
到目前为止,我已经采用了 Microsoft IMAPI 示例并编写了一个 Powershell 应用程序,从中我可以对 API 进行一系列调用。[CDInterface][1]
使用 IMAPI 需要做的第一件事是创建 IDiskMaster2 的实例,所以我已经通过 Imapi2 接口声明了它,就像这样
public interface Imapi2 extends Library
Imapi2 INSTANCE = (Imapi2)
Native.load("C:/Windows/System32/imapi2.dll" , Imapi2.class);
public static class IDiscMaster2 extends Structure
int getCount;
public int getCount()
return getCount;
IDiscMaster2 createMsftDiscMaster2();
然后在主代码中
Imapi2.IDiscMaster2 recorderList = Imapi2.INSTANCE.createMsftDiscMaster2();
System.out.println("Found " + recorderList.getCount() + " Recorders");
仅仅在 Native.load() 调用中加入 'imapi2' 也不起作用。
我猜我做错了什么,但不清楚如何让 JNA '看到'一个你想要接口的新 dll ..... 而且我有点害怕有什么东西此 API 与人们使用 JNA 与之交谈的其他 API 非常不同,因此可能不值得尝试!
public interface Imapi2 extends Library
Imapi2 INSTANCE = (Imapi2)
Native.load("C:/Windows/System32/imapi2.dll" , Imapi2.class);
public class IDiscMaster2 extends Dispatch
public static final CLSID CLSID_MsftDiscMaster2 = new CLSID("2735412F-7F64-5B0F-8F00-5D77AFBE261E");
public IDiscMaster2()
private IDiscMaster2(Pointer pvInstance)
super(pvInstance);
public static IDiscMaster2 create()
PointerByReference pbr = new PointerByReference();
WinNT.HRESULT hres = Ole32.INSTANCE.CoCreateInstance(CLSID_MsftDiscMaster2, null, WTypes.CLSCTX_ALL, null, pbr);
if (COMUtils.FAILED(hres))
System.out.println("ERROR: Failed to create instance");
return null;
return new IDiscMaster2(pbr.getValue());
public WinNT.HRESULT _getCount(Pointer count )
return (WinNT.HRESULT) _invokeNativeObject(2, new Object[]count, WinNT.HRESULT.class);
public long getCount()
try
long count = -1;
Pointer ptr = new Pointer(count);
WinNT.HRESULT result = _getCount(ptr);
COMUtils.checkRC(result);
return count;
catch ( Exception e )
System.out.println("Error : " + e.getMessage());
return -1;
然后 main 中的调用更改为
Imapi2 imapi2Lib = Imapi2.INSTANCE;
Imapi2.IDiscMaster2 recorderList = new Imapi2.IDiscMaster2();
System.out.println("Found " + recorderList.getCount() + " Recorders");
IntelliJ 显示未调用的方法,因此它看起来不像 create() 被调用。不确定这是因为我需要调用它,还是因为实现 IDispatch 而不是 IUnknown 的函数。 [1]:https://github.com/nosdod/CDInterface
【问题讨论】:
这能回答你的问题吗? Mapping a COM interface method in JNA 我认为这有助于我意识到 JNA 需要我比我拥有更多的 COM 内部知识! IDiscMaster2 实现了 IDisplatch,我猜它位于 IUnkown 之上的一层。 我认为,如果我能接到最基本的工作电话,那么您在链接中提供的信息将开始有意义。 一开始可能会让人不知所措,但有一个基本模式,在你完成几个之后就会变得很明显。有一些 WinAPI 调用获取指向 COM 对象的指针。然后映射 com 对象并在该指针的偏移量处调用其函数(0、1、2 等...)。它主要是那里的样板。 【参考方案1】:我已经在a similar question 中回答了这个问题,我最初将其标记为重复。但是,鉴于加载此问题的困难,您的案例非常独特,我将尝试给出单独的答案。
COM 的一般情况是有一个创建对象的 API 函数。您已将其映射为createMsftDiscMaster2()
。请注意,您已在此处分配了一个资源,并且需要在完成后将其处理掉; API 文档应该告诉你如何做到这一点(可能通过从IUnknown
调用Release()
。)
下一步是映射IDiscMaster2
COM 类。我在这里看到两个映射,所以我很困惑你想要哪一个。您问题顶部的那个是不正确的,但是稍后扩展 Dispatch 是正确的开始方式,但是我不清楚您在那之后去了哪里。 JNA 中 Dispatch
类的 should look similar to the internals 类的其余部分。
在该课程中,您可以看到您将遵循的样板。请注意,它扩展了Unknown
,其中follows the same boilerplate 用于前3 个COM 函数QueryInterface
、AddRef
和Release
的偏移量0、1 和2。对于 COM 函数 GetTypeInfoCount
、GetTypeInfo
、GetIDsOfNames
和 Invoke
,使用偏移量 3、4、5 和 6 进行调度。
因此,在您的 DiskMaster2
映射中,您将使用偏移量 7 拾取,您的映射将如下所示:
public HRESULT TheFunctionName(FOO foo, BAR bar)
return (HRESULT) this._invokeNativeObject(7,
new Object[] this.getPointer(), foo, bar ,
HRESULT.class);
您需要在此处找到此类的实际头文件,以确定函数在 Vtbl 中出现的顺序。看起来您尝试使用您的代码执行此操作,但偏移量 2 已在 Unknown 中分配,您可以使用的最低值是 7(并继续使用 8、9、10 for each function in this COM interface,在正确的顺序——你必须从 Vtbl 中确定。)
基于this header,您可以看到这些函数按顺序映射,并且您的偏移量应为:7:get__NewEnum、8:get_Item、9:get_Count 和10:get_IsSupportedEnvironment。使用这些标头函数映射作为开始,并将它们更改为上面的_invokeNativeObject()
格式。 (它们都返回HRESULT
,您只需更改参数列表。)
【讨论】:
非常感谢 Daniel 对我的包容……我最初对 imapi2.h 中的 C++ 感到困惑。这错过了继承的方法!一旦我专注于 C 代码,我就可以完全了解如何在 9 处找到 get_Count 的偏移量。 Native.load() 调用是否正确?带有完整路径。明天将重新充满信心地尝试您的建议! 我相信完整的路径应该可以工作。我也不明白为什么“imapi2”不起作用。您还可以使用-Djava.library.path="add-the-path-here;$env_var:PATH"
添加库路径(或在代码中设置属性)。或使用NativeLibrary.addSearchPath(String libraryName, String path)
。以上是关于JNA 可以用于像 IMAPI 这样的复杂 Windows DLL的主要内容,如果未能解决你的问题,请参考以下文章
JNA 访问 NTFS USN (win32)。如何从内存对象中获取数据?
JMeter - Webdriver 错误:java.lang.NoClassDefFoundError: com/sun/jna/platform/win32/Kernel32