我真的不知道如何表达这个问题(抱歉)。但基本上(使用 JNA 和 Windows API)我试图通过在我的 MMDeviceEnumerator 实例(?)上调用 GetDefaultAudioEndpoint 来获取 mmDevice 接口的实例(?)。问题是对 GetDefaultAudioEndpoint 的调用返回了我认为是空指针
null@0x2bd70eebeb0
。我认为这会导致稍后调用它在运行时产生此错误:
Calling MMDeviceEnumerator.create()
response: 0
Got MMDeviceEnumerator
Pointer: native@0x2bd70f68590
Pointer.getPointer(): native@0x2bd70f68590
Calling mmEnumerator.GetDefaultAudioEndpoint(args)
response: 1
Got mmDevice
Pointer: null@0x2bd70eebeb0
Pointer.getValue(): null
Pointer.getPointer(): allocated@0x2bd70eebeb0 (8 bytes)
null
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "com.sun.jna.Pointer.getPointer(long)" because "vptr" is null
at com.sun.jna.platform.win32.COM.COMInvoker._invokeNativeObject(COMInvoker.java:46)
at spicey.IAudioEndpointVolume.Activate(App.java:76)
at spicey.App.main(App.java:58)
对 GetDefaultAudioEndpoint 的调用还会返回 S_FALSE 或 1 的 HRESULT(如果有帮助的话)。 无论如何,这是完整的程序。我也很乐意提供任何额外信息。预先感谢!
public final class App extends Unknown {
public static final CLSID CLSID_IMMDeviceEnumerator = new CLSID("bcde0395-e52f-467c-8e3d-c4579291692e");
public static final GUID IID_IMMDeviceEnumerator = new GUID("a95664d2-9614-4f35-a746-de8db63617e6");
public static final GUID IID_IAudioEndpointVolume = new GUID("5CDF2C82-841E-4546-9722-0CF74078229A");
public static final GUID IID_IAudioStreamVolume = new GUID("93014887-242D-4068-8A15-CF5E93B90FE3");
public static void main(String[] args) {
Ole32.INSTANCE.CoInitializeEx(null, 0); // 0 is multi threaded
System.out.println("Calling MMDeviceEnumerator.create()");
MMDeviceEnumerator mmEnumerator = MMDeviceEnumerator.create();
System.out.println("Got MMDeviceEnumerator");
System.out.println("Pointer: " + mmEnumerator.getPointer());
System.out.println("Pointer.getPointer(): " + mmEnumerator.getPointer());
System.out.println();
PointerByReference ppEndpoint = new PointerByReference();
System.out.println("Calling mmEnumerator.GetDefaultAudioEndpoint(args)");
mmEnumerator.GetDefaultAudioEndpoint(0, 0, ppEndpoint);
System.out.println("Got mmDevice");
System.out.println("Pointer: " + ppEndpoint);
System.out.println("Pointer.getValue(): " + ppEndpoint.getValue());
System.out.println("Pointer.getPointer(): " + ppEndpoint.getPointer());
System.out.println();
IAudioEndpointVolume iEndpoint = IAudioEndpointVolume.create(ppEndpoint.getPointer());
PointerByReference ppInterface = new PointerByReference();
iEndpoint.Activate(IID_IAudioEndpointVolume, WTypes.CLSCTX_ALL, ppInterface.getPointer());
}
}
class IAudioEndpointVolume extends Unknown {
public IAudioEndpointVolume(Pointer p) {
super(p);
}
public static IAudioEndpointVolume create(Pointer p) {
return new IAudioEndpointVolume(p);
}
public void Activate(GUID iid, int dwClsCtx, Pointer ppInterface) {
HRESULT res = (HRESULT) _invokeNativeObject(1, new Object[] { getPointer(), iid, dwClsCtx, null, ppInterface },
HRESULT.class);
COMUtils.checkRC(res);
}
}
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 static interface Ole32 extends Library {
Ole32 INSTANCE = (Ole32) Native.load("Ole32",
Ole32.class);
HRESULT CoCreateInstance(GUID rclsid, Pointer pUnkOuter, int dwClsContext, GUID riid, PointerByReference ppv);
}
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);
System.out.println("response: " + hres);
if (COMUtils.FAILED(hres)) {
return null;
}
return new MMDeviceEnumerator(pEnumerator.getValue());
}
// functionz
public void GetDefaultAudioEndpoint(int dataFlow, int role, PointerByReference ppEndpoint) {
HRESULT res = (HRESULT) _invokeNativeObject(2,
new Object[] { getPointer(), dataFlow, role, ppEndpoint }, HRESULT.class);
COMUtils.checkRC(res);
System.out.println("response: " + res);
}
}
我也尝试直接查看 COMInvoker 类,但没有成功
public abstract class COMInvoker extends PointerType {
protected int _invokeNativeInt(int vtableId, Object[] args) {
Pointer vptr = this.getPointer().getPointer(0);
// we take the vtable id and multiply with the pointer size (4 bytes on
// 32bit OS)
Function func = Function.getFunction(vptr.getPointer(vtableId
* Native.POINTER_SIZE));
return func.invokeInt(args);
}
protected Object _invokeNativeObject(int vtableId, Object[] args, Class<?> returnType) {
Pointer vptr = this.getPointer().getPointer(0);
// we take the vtable id and multiply with the pointer size (4 bytes on
// 32bit OS)
Function func = Function.getFunction(vptr.getPointer(vtableId
* Native.POINTER_SIZE));
return func.invoke(returnType, args);
}
protected void _invokeNativeVoid(int vtableId, Object[] args) {
Pointer vptr = this.getPointer().getPointer(0);
// we take the vtable id and multiply with the pointer size (4 bytes on
// 32bit OS)
Function func = Function.getFunction(vptr.getPointer(vtableId
* Native.POINTER_SIZE));
func.invokeVoid(args);
}
}
Nvm我解决了。上面的代码有一些问题,但主要的一个是表id全部关闭,因为我忘记考虑到IMMDeviceEnumerator接口从IUnknown接口继承了3个方法,所以你必须为每个表id添加3争论。