一种从Java访问Windows MMDevice API的方法?

f8rj6qna  于 2023-01-24  发布在  Java
关注(0)|答案(2)|浏览(143)

我想使用Java应用程序中的MMDevice API。有哪些选项?
我尝试使用JNA。看起来我不能使用JNA类型库解析,因为没有此API(Is there a COM type library for Windows Core Audio)的类型。正如建议的那样,我需要提供自己的API声明。
因此,我还尝试了两个手动声明的JNA示例,但它们给予了“Interface not supported HRESULT=80004002”错误:

public class MMDeviceAPITest {
    public static void test1() {
        try {
            Ole32.INSTANCE.CoInitializeEx(Pointer.NULL, Ole32.COINIT_MULTITHREADED);
            var obj = new Test1.MMDeviceEnumerator();  // exception E_NOINTERFACE (HRESULT: 80004002)
            // ...
        } finally {
            Ole32.INSTANCE.CoUninitialize();
        }
    }
    public static void test2() {
        try {
            Ole32.INSTANCE.CoInitializeEx(Pointer.NULL, Ole32.COINIT_MULTITHREADED);
            var factory = new Factory();
            var obj = factory.createObject(Test2.MMDeviceEnumerator.class);  // exception E_NOINTERFACE (HRESULT: 80004002)
            var in = obj.queryInterface(Test2.IMMDeviceEnumerator.class);
            // ...
        } finally {
            Ole32.INSTANCE.CoUninitialize();
        }
    }
}

interface Test1 {
    class MMDeviceEnumerator extends COMLateBindingObject {
        public MMDeviceEnumerator() {
            super(new Guid.CLSID("bcde0395-e52f-467c-8e3d-c4579291692e"), true);
        }
    }
}

interface Test2 {
    @ComObject(clsId = "bcde0395-e52f-467c-8e3d-c4579291692e")
    interface MMDeviceEnumerator extends IUnknown {}  // doesn't extend IUnknown in C sources, probably it's the problem...
    @ComInterface(iid = "a95664d2-9614-4f35-a746-de8db63617e6")
    interface IMMDeviceEnumerator extends IUnknown {}
}

我能从Java访问这个API吗?我能为JNA创建工作声明吗?或者使用另一个框架?
我的最后一个想法是创建/找到一个封装所需COM调用的微型原生应用程序/库,这样我就可以轻松地调用此应用程序/库(通过子进程或简单的JNA声明)。

ss2ws0br

ss2ws0br1#

docs you linked显示了如何使用CoCreateInstance创建:

const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
hr = CoCreateInstance(
       CLSID_MMDeviceEnumerator, NULL,
       CLSCTX_ALL, IID_IMMDeviceEnumerator,
       (void**)&pEnumerator);

这会让你接近JNA

class MMDeviceEnumerator extends Unknown {
    public static final CLSID CLSID_MMDeviceEnumerator = new CLSID("bcde0395-e52f-467c-8e3d-c4579291692e");
    public static final GUID IID_IMMDeviceEnumerator = new GUID("a95664d2-9614-4f35-a746-de8db63617e6");

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

    public static MMDeviceEnumerator create() {
        PointerByReference pEnumerator = new PointerByReference();

        HRESULT hres = Ole32.INSTANCE.CoCreateInstance(
            CLSID_MMDeviceEnumerator, null,
            WTypes.CLSCTX_ALL, IID_IMMDeviceEnumerator,
            pEnumerator);
        if (COMUtils.FAILED(hres)) {
            return null;
        }

        return new MMDeviceEnumerator(pEnumerator.getValue());
    }

    // map functions as needed
}

我使用了JNA中IWbemContext的实现作为上面的模板。您可以参考该类来获得COM函数Map的示例。

6tdlim6h

6tdlim6h2#

出于某种原因,我不能建议修改丹尼尔Widdis的答案。答案对我很有效,非常感谢!只是想以示例的形式展示如何Map一个方法:

class MMDeviceEnumerator extends Unknown {
    public static final CLSID CLSID_MMDeviceEnumerator = new CLSID("bcde0395-e52f-467c-8e3d-c4579291692e");
    public static final GUID IID_IMMDeviceEnumerator = new GUID("a95664d2-9614-4f35-a746-de8db63617e6");

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

    public static MMDeviceEnumerator create() {
        PointerByReference pEnumerator = new PointerByReference();

        HRESULT hres = Ole32.INSTANCE.CoCreateInstance(
            CLSID_MMDeviceEnumerator, null,
            WTypes.CLSCTX_ALL, IID_IMMDeviceEnumerator, pEnumerator);
        if (COMUtils.FAILED(hres)) {
            return null;
        }

        return new MMDeviceEnumerator(pEnumerator.getValue());
    }

    public static final int EDataFlow_eRender = 0;
    public static final int EDataFlow_eCapture = 1;
    public static final int EDataFlow_eAll = 2;
    public static final int EDataFlow_enum_count = 3;

    public static final int DEVICE_STATE_ACTIVE = 0x1;
    public static final int DEVICE_STATE_DISABLED = 0x2;
    public static final int DEVICE_STATE_NOTPRESENT = 0x4;
    public static final int DEVICE_STATE_UNPLUGGED = 0x8;
    public static final int DEVICE_STATEMASK_ALL = 0xF;

    public void EnumAudioEndpoints(int dataFlow, int dwStateMask, PointerByReference ppDevices) {
        WinNT.HRESULT res = (WinNT.HRESULT) _invokeNativeObject(
            3,  // `EnumAudioEndpoints` is the 3rd method of `IMMDeviceEnumeratorVtbl` in `mmdeviceapi.h`
            new Object[] { getPointer(), dataFlow, new WinDef.DWORD(dwStateMask), ppDevices},
            WinNT.HRESULT.class
        );
        COMUtils.checkRC(res);
    }

    // map other functions as needed
}

相关问题