Open stuntman11 opened 1 year ago
Hey, that's a confusing error! Getting Rust macros to produce meaningful errors is hard... Anyway, the trick is that the implement
macro is only for COM interfaces and IXAudio2VoiceCallback
is not a COM interface! A few Windows APIs rely on these Frankenstein interfaces that don't inherit from IUnknown
and thus have no way to express lifetime and discovery.
The good news is that I recently provided support for such interfaces: #2066
I applied the concepts from the example you provided in (#2066) to my XAudio2 problem and think it works. Now I use the interface
macro to declare my own type trait for the IXAudio2VoiceCallback
interface. But I have a follow-up question regarding the interface instantiation and to simplify the example I only show the OnBufferEnd
method.
struct XAudio2VoiceCallbacks;
#[interface]
unsafe trait XAudio2VoiceCallbackInterface {
unsafe fn OnBufferEnd(&self, pbuffercontext: *mut ::core::ffi::c_void);
}
impl XAudio2VoiceCallbackInterface_Impl for XAudio2VoiceCallbacks {
unsafe fn OnStreamEnd(&self) {}
}
The final goal is to call the CreateSourceVoice()
method which expects an Into<InParam<'a, IXAudio2VoiceCallback>>
for the callbacks argument. At first I thought there must be some kind of constructor or conversion method to convert my callbacks struct to the official callbacks struct but didn't find anything. So do I use mem::transmute()
to convert between the types?
let callback_instance = XAudio2VoiceCallbacks {};
let callback_interface = XAudio2VoiceCallbackInterface::new(&callback_instance);
let callback_windows = mem::transmute(callback_interface);
Thanks for your time! I am still in the process of learning the rust language and really appreciate the support.
No, since the IXAudio2VoiceCallback
interface is defined by the windows
crate, you need not use the interface
macro to define it again. That macro exists only for those interfaces that aren't already defined by the windows
crate.
So I don't know anything about the XAudio2 API but something like this should get you started:
[dependencies.windows]
version = "0.42"
features = [
"implement",
"Win32_Foundation",
"Win32_Media_Audio_XAudio2",
"Win32_System_Com",
"Win32_System_SystemInformation",
]
use windows::{
core::*, Win32::Media::Audio::XAudio2::*, Win32::System::Com::*,
Win32::System::SystemInformation::*,
};
struct Callback;
impl IXAudio2VoiceCallback_Impl for Callback {
fn OnVoiceProcessingPassStart(&self, _: u32) {
todo!()
}
fn OnVoiceProcessingPassEnd(&self) {
todo!()
}
fn OnStreamEnd(&self) {
println!("callback");
}
fn OnBufferStart(&self, _: *mut std::ffi::c_void) {
todo!()
}
fn OnBufferEnd(&self, _: *mut std::ffi::c_void) {
todo!()
}
fn OnLoopEnd(&self, _: *mut std::ffi::c_void) {
todo!()
}
fn OnVoiceError(&self, _: *mut std::ffi::c_void, _: HRESULT) {
todo!()
}
}
fn main() -> Result<()> {
unsafe {
CoInitializeEx(None, COINIT_MULTITHREADED)?;
let mut audio = None;
XAudio2CreateWithVersionInfo(&mut audio, 0, XAUDIO2_DEFAULT_PROCESSOR, NTDDI_VERSION)?;
if let Some(audio) = audio {
// Call the callback interface directly...
let callback = IXAudio2VoiceCallback::new(&Callback);
callback.OnStreamEnd();
// Pass the callback to another API...
let mut source = None;
audio.CreateSourceVoice(
&mut source,
std::ptr::null(),
0,
0.0,
&*callback,
None,
None,
)?;
}
Ok(())
}
}
Notice the weird &*
that is required for complicated reasons. I hope to get rid of that soon.
Anyway, I hope that helps.
Ohhhh wow the &*
does the trick. Would never have guessed that. Thanks!
Great, I'll keep this open to remind me to get rid of the need for that trick.
Hello, the last couple of days I tried to migrate my XAudio2 project from C++ to Rust and was simply unable to implement the IXAudio2VoiceCallback interface.
I am quite new to the rust language and even after hours of research do not understand why the implement macro doesn't work in my case. I don't think this is a general rust question because the macro is a specific functionality of the windows crate.
I want to call the function CreateSourceVoice on an XAudio2 instance:
To create an implementation for the IXAudio2VoiceCallback interface I use the implement macro:
The compiler error for the implement macro is:
The issue "How to get COM object as "base" Interface without move" shows a similar situation with the IAudioEndpointVolumeCallback interface but in their case it just works. It would be awesome if someone with more windows crate knowledge or more rust experience in generell could help me.