use log::trace;
use std::ptr;
use winapi::{
shared::{guiddef::GUID, minwindef::LPVOID, winerror::NOERROR, wtypesbase::CLSCTX},
um::{combaseapi::CoCreateInstance, oaidl::LPDISPATCH, unknwnbase::LPUNKNOWN},
};
use super::guids::{IID_IDISPATCH, IID_IUNKNOWN};
use super::{dispatch::DispatchInterface, Error};
pub struct UnknownInterface {
unknown: LPUNKNOWN,
released: bool,
}
impl UnknownInterface {
pub fn new(class_id: GUID, class_context: CLSCTX) -> Result<UnknownInterface, Error> {
let mut unknown: LPVOID = ptr::null_mut();
let result = unsafe {
CoCreateInstance(
&class_id,
ptr::null_mut(),
class_context,
&IID_IUNKNOWN,
&mut unknown,
)
};
if result != NOERROR {
Err(result.into())
} else {
Ok(UnknownInterface {
unknown: unknown as LPUNKNOWN,
released: false,
})
}
}
pub fn get_dispatch_interface(&self) -> Result<DispatchInterface, Error> {
let mut dispatch: LPVOID = ptr::null_mut();
let result = unsafe {
if let Some(r) = self.unknown.as_ref() {
r.QueryInterface(&IID_IDISPATCH, &mut dispatch)
} else {
return Err(Error::NullUnknownPointer);
}
};
if result != NOERROR {
Err(result.into())
} else {
Ok(DispatchInterface::new(dispatch as LPDISPATCH))
}
}
fn release(&mut self) {
if self.released {
return;
}
unsafe {
if let Some(r) = self.unknown.as_ref() {
r.Release();
self.released = true;
self.unknown = ptr::null_mut();
}
}
}
}
impl Drop for UnknownInterface {
fn drop(&mut self) {
trace!("dropping unknown interface");
self.release();
}
}