windows-rs: IMMDevice.Activate fails with IAudioSessionManager2
Hello, thank you for this amazing library,
I get an error while retrieving back a pointer that should be filled by the IMMDevice::Activate function.
Exception 0xc0000005 encountered at address 0x7ff64e1d65e7: Access violation reading location 0xffffffffffffffff
(exit code: 0xc0000005, STATUS_ACCESS_VIOLATION)
I have got this error on Windows 10 with the following configuration:
- cargo 1.53.0 (4369396ce 2021-04-27)
- rustc 1.53.0 (53cb7b09b 2021-06-17)
- toolchain: stable-x86_64-pc-windows-msvc
Here is a minimal (non!)working example. Code is commented to highlight the problem.
Cargo.toml
[package]
name = "my-package"
version = "0.1.0"
authors = ["spineki"]
edition = "2018"
[dependencies.windows]
version = "0.28.0"
features = [
"Win32_Foundation",
"Win32_Media_Audio",
"Win32_Media_Multimedia",
"Win32_System_Com",
"Win32_System_Com_StructuredStorage",
]
Code:
use windows::Win32::{
Media::Audio::{
eCapture, eMultimedia, IAudioSessionManager2, IMMDeviceEnumerator, MMDeviceEnumerator,
},
System::Com::{
CoCreateInstance, CoInitializeEx, CoUninitialize, CLSCTX_ALL, CLSCTX_INPROC_SERVER,
COINIT_APARTMENTTHREADED,
},
};
use windows::core::{Interface, GUID};
fn main() {
unsafe {
CoInitializeEx(std::ptr::null(), COINIT_APARTMENTTHREADED).expect("CoInitializeEx Failed");
// Getting the device enumerator: works
let imm_device_enumerator: IMMDeviceEnumerator =
CoCreateInstance(&MMDeviceEnumerator, None, CLSCTX_INPROC_SERVER)
.expect("CoCreateInstance Failed");
// Getting the IMMDevice of the defaultAudioEndpoint: works
let endpoint = imm_device_enumerator
.GetDefaultAudioEndpoint(eCapture, eMultimedia)
.expect("GetDefaultAudioEnpoint Failed");
// preparing a pointer that will store the address of the created IAudioSessionManager2
let mut pinterface: *mut std::ffi::c_void = std::ptr::null_mut();
// Activating: the target Interface is IAudioSessionManager2: No error!
endpoint
.Activate(
&IAudioSessionManager2::IID,
CLSCTX_ALL.0,
std::ptr::null_mut(),
&mut pinterface as *mut _,
)
.expect("Activate Failed");
// -> Reaching this point, so Activate did not failed
// Casting back to IAudioSessionManager2: works
let audio_session_enumerator_ref = (pinterface as *mut IAudioSessionManager2)
.as_ref()
.expect("Pointer to ref failed");
// -------------------- HERE IS THE PROBLEM--------------------
// The call to GetSessionEnumerator fails.
let audio_session_enumerator = audio_session_enumerator_ref
.GetSessionEnumerator()
.expect("GetSessionEnumerator Failed");
CoUninitialize();
}
}
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 26 (12 by maintainers)
_COM_Outptr_
parameters must set the output value to null if they return failure. This is alluded to in the documentation where it says:In sal.h it says:
These DXC functions are returning pointers to interfaces that follow COM semantics, and so
_COM_Outptr_
can be used here. The definitions in sal.h are also useful to try and figure out what these annotations mean:_COM_Outptr_
must be passed in as a non-null value, and if the function succeeds it will be set to a value and if it fails it will be set to null._COM_Outptr_opt_
may be null. If it is non-null then it behaves as for_COM_Outptr_
.The maybenull versions are as above, but the function is allowed to succeed and set the parameter to null.
I suggest you ask on the dxc repo about when they’re next planning to update the SDK with the latest DXC changes.
Generally, COM out params will return ownership of a ref-counted object. You should prefer to do something like this:
Now the
pinterface
will own the resulting interface pointer (if any). It is regrettable that theGUID*, void**
pair aren’t at the back of the parameter list. In such cases, the method is much easier to call because the Windows crate will take care of the binding automatically. I may ask the win32 metadata folks about making this easier.Ideed. Thank you so much @MarijnS95 !
For future readers that didn’t find an example online like me before,
here is what it looks like
Before
After
Works like a charm, I can call for example
Agree, thought of that too when I was building the DIA sample that has a NoRegCoCreate workflow. Am also concerned about false positives, we’d have to take a closer look.
e.g.
@MarijnS95 yes, the metadata is missing the attribute as well, but it is also affected by the fact that the
GUID
parameter isn’t the second-to-last, as is conventional.