是否可以使用 JNA/JNI 访问本机 COM/DirectX API 方法?

Is it possible to use JNA/JNI to access native COM/DirectX API methods?

我正在尝试使用 JNA 调用本机 Windows 方法:

HRESULT WINAPI DirectSoundCreate(LPGUID lpGuid, LPDIRECTSOUND* ppDS, LPUNKNOWN pUnkOuter );

但我真的很难理解在 Java 方面我应该使用什么作为参数。使用 JNA,您应该创建 Java classes 匹配本机 C 结构,我已经成功地使用 WinAPI.

的其他部分完成了此操作

根据我(我认为)到目前为止的理解,LPDIRECTSOUND 是 "Long pointer to a DirectSound struct" 的类型定义,而 LPUNKNOWN 是 "Long pointer to an Unknown"?

的类型定义

我在 DSound.h 中找到了原生结构 IDirectSound 和 IUnknown。我应该使用这些吗?然而,我找不到关于这些结构包含什么的规范,所以当我尝试将它们镜像为空的 classes 扩展 Java 侧的结构时,我得到

IllegalArgumentException: Structure class se.abjorklund.win32.jna.dsound.IDirectSound has unknown or zero size (ensure all fields are public)

所以这显然行不通。我猜我在这里遗漏了一些基本的东西,也许它与我不理解的 COM/Direct API 有关,并且像 "go read up" 这样的答案很酷,只要因为我可以获得有关阅读内容的指示!

下面是我尝试使用 JNA 移植到 Java 的 C 程序的工作片段。

LPDIRECTSOUND directSound; if (directSoundCreate && SUCCEEDED(directSoundCreate(0, &directSound, 0)))

所以在 C 中,您只需传递一个指向 LPDIRECTSOUND 的指针。我想我需要制作一个 LPDIRECTSOUND class 扩展 Java 中的 JNA 结构 class?我是接近答案还是离答案还很远?

JNA 确实支持 COM,并且 com.sun.jna.platform.win32.COM 包中已经存在多个映射,包括 IUnknown 接口和相应的 Unknown class 实现它。

您可以实现一个 IDirectSound 接口(可选)或通过扩展 Unknown 直接实现 class。您将必须使用 _invokeNativeObject() (或 -Int 和 -Void 变体)映射您需要的函数。

我在 WbemCli.java class 中贡献了几个查询 WMI 所需的 COM classes,它们可以作为如何传递这些参数的示例。 (注意:我可能不应该在具体的 classes 上使用 I 接口前缀,但现在已经太晚了。)

函数参数是 vtableId,参数的对象数组,以及 return 类型的 class。要获取 vtableId,您必须计算头文件中 directSoundVtbl 结构中的方法(从 0 开始)。我没有权威 Dsound.h 文件的副本,但这里有 one possibility 用于该排序(例如,CreateSoundBuffer 的 ID 为 3)。从 Unknown 继承已经获得了 Vtbl 中的前 3 个函数(id 的 0、1 和 2)。

这是一个(完全未经测试的)示例,可帮助您入门。

public interface DSound {

    @FieldOrder ({ "dwSize", "dwFlags", ... })
    class DSBUFFERDESC extends Structure {
        public int dwSize;
        public int dwFlags;
        // continue conventional JNA Structure mapping here
        // may have to map nested structures
    }

    class DirectSoundBuffer extends Unknown {
        // methods invoking COM similar to below
    }

    class DirectSound extends Unknown {
        public DirectSound() {
        }

        public DirectSound(Pointer p) {
            super(p);
        }

        public HRESULT CreateSoundBuffer(DSBUFFERDESC lpcDSBufferDesc, DirectSoundBuffer lplpDirectSoundBuffer, Unknown pUnkOuter) {
            // CreateSoundBuffer is 4th method of directSoundVtbl in Dsound.h
            return (HRESULT) _invokeNativeObject(3,
                    new Object[] { getPointer(), lpcDSBufferDesc, lplpDirectSoundBuffer, pUnkOuter }, HRESULT.class);
        }

        // Map whatever functions you need, or all of them!
    }
}