JNA 可以用于像 IMAPI 这样复杂的 Windows DLL
Can JNA be used for a complex Windows DLL like IMAPI
我已经设法让 COM4J 在 windows IMAPI(CD 写入)中使用一些功能。
但是我没能得到任何 return SAFEARRAYs 工作的调用,但是这个项目目前似乎没有活动...
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");
只是将 'imapi2' 放在对 Native.load() 的调用中也不起作用。
我猜我在做一些根本性的错误,但不清楚你是如何让 JNA 'see' 一个你想要接口的新 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
我已经在 中回答了这个问题,我最初将其标记为重复。但是,鉴于加载这个有困难,您的案例非常独特,我将尝试给出一个单独的答案。
COM 的一般情况是有一个 API 函数创建对象。您已将其映射为 createMsftDiscMaster2()
。请注意,您已在此处分配了资源,并且需要在完成后对其进行处理; API 文档应该告诉你如何做到这一点(可能通过从 IUnknown
调用 Release()
。)
您的下一步是映射 IDiscMaster2
COM class。我在这里看到两个映射,所以我不知道你想要哪一个。问题顶部的那个是不正确的,但稍后扩展 Dispatch 的那个是正确的开始方式,但我不清楚你在那之后去了哪里。 JNA中Dispatch
class的其余classshould look similar to the internals
在那个 class 中,您可以看到您将遵循的样板文件。请注意,对于前 3 个 COM 函数 QueryInterface
、AddRef
和 Release
,它扩展了 Unknown
其中 follows the same boilerplate 的偏移量 0、1 和 2。 COM 函数 GetTypeInfoCount
、GetTypeInfo
、GetIDsOfNames
和 Invoke
.
的 Dispatch 使用偏移量 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);
}
您需要在此处找到此 class 的实际头文件以确定函数在 Vtbl 中的显示顺序。看起来您试图用您的代码执行此操作,但偏移量 2 已在未知中分配,您可以使用的最低偏移量是 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()
格式。 (它们都是 return HRESULT
,您只需更改参数列表即可。)
我已经设法让 COM4J 在 windows IMAPI(CD 写入)中使用一些功能。
但是我没能得到任何 return SAFEARRAYs 工作的调用,但是这个项目目前似乎没有活动...
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");
只是将 'imapi2' 放在对 Native.load() 的调用中也不起作用。
我猜我在做一些根本性的错误,但不清楚你是如何让 JNA 'see' 一个你想要接口的新 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
我已经在
COM 的一般情况是有一个 API 函数创建对象。您已将其映射为 createMsftDiscMaster2()
。请注意,您已在此处分配了资源,并且需要在完成后对其进行处理; API 文档应该告诉你如何做到这一点(可能通过从 IUnknown
调用 Release()
。)
您的下一步是映射 IDiscMaster2
COM class。我在这里看到两个映射,所以我不知道你想要哪一个。问题顶部的那个是不正确的,但稍后扩展 Dispatch 的那个是正确的开始方式,但我不清楚你在那之后去了哪里。 JNA中Dispatch
class的其余classshould look similar to the internals
在那个 class 中,您可以看到您将遵循的样板文件。请注意,对于前 3 个 COM 函数 QueryInterface
、AddRef
和 Release
,它扩展了 Unknown
其中 follows the same boilerplate 的偏移量 0、1 和 2。 COM 函数 GetTypeInfoCount
、GetTypeInfo
、GetIDsOfNames
和 Invoke
.
所以在 DiskMaster2
的映射中,您将使用偏移量 7 进行拾取,并且您的映射将如下所示:
public HRESULT TheFunctionName(FOO foo, BAR bar) {
return (HRESULT) this._invokeNativeObject(7,
new Object[] { this.getPointer(), foo, bar },
HRESULT.class);
}
您需要在此处找到此 class 的实际头文件以确定函数在 Vtbl 中的显示顺序。看起来您试图用您的代码执行此操作,但偏移量 2 已在未知中分配,您可以使用的最低偏移量是 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()
格式。 (它们都是 return HRESULT
,您只需更改参数列表即可。)