1

我已经设法让 COM4J 使用 windows IMAPI(CD 写入)中的一些功能。

但是,我未能让任何返回 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 '看到'一个你想要接口的新 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

4

1 回答 1

0

我已经在一个类似的问题中回答了这个问题,我最初将其标记为副本。但是,鉴于加载此问题的困难,您的案例非常独特,我将尝试给出单独的答案。

COM 的一般情况是有一个创建对象的 API 函数。您已将其映射为createMsftDiscMaster2(). 请注意,您已在此处分配了一个资源,并且需要在完成后将其处理掉;API 文档应该告诉你如何做到这一点(可能通过调用Release()from IUnknown。)

下一步是映射IDiscMaster2COM 类。我在这里看到两个映射,所以我很困惑你想要哪一个。您问题顶部的那个是不正确的,但是稍后扩展 Dispatch 是正确的开始方式,但是我不清楚您在那之后去了哪里。类的其余部分应该与DispatchJNA中类的内部类似。

在该课程中,您可以看到您将遵循的样板。请注意,它扩展Unknown了前 3 个 COM 函数、和的偏移量 0、1 和 2的相同样板。对于 COM 函数、、和. ,Dispatch 使用偏移量 3、4、5 和 6 拾取QueryInterfaceAddRefReleaseGetTypeInfoCountGetTypeInfoGetIDsOfNamesInvoke

因此,在您的映射中,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(并继续为该 COM 中的每个函数使用 8、9、10 interface,以正确的顺序 - 您必须从 Vtbl 中确定。)

根据此标头,您可以看到按顺序映射的这些函数,并且您的偏移量应为:7:get__NewEnum、8:get_Item、9:get_Count 和 10:get_IsSupportedEnvironment。使用这些标头函数映射作为开始并将它们更改为上述_invokeNativeObject()格式。(它们都 return HRESULT,您将只是更改参数列表。)

于 2021-11-26T19:02:18.703 回答