#![allow(missing_docs)]
extern crate alloc;
use alloc::sync::Arc;
use core::ffi::c_void;
use windows::Win32::System::Com::{IClassFactory, IClassFactory_Impl};
use windows_core::{implement, ComObject, IUnknown, Interface, Ref, BOOL, GUID, HRESULT};
use crate::aec::instance_com::AecApoInstanceCom;
use crate::aec::AnyAecApoInstance;
use crate::apo::ApoCategory;
use crate::clsid::Clsid;
use crate::error::HResult;
use crate::realtime::Refcount;
pub struct AecApoVTable {
pub clsid: Clsid,
pub name: &'static str,
pub copyright: &'static str,
pub category: ApoCategory,
pub create: fn() -> Arc<dyn AnyAecApoInstance>,
}
impl core::fmt::Debug for AecApoVTable {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("AecApoVTable")
.field("clsid", &self.clsid)
.field("name", &self.name)
.field("copyright", &self.copyright)
.field("category", &self.category)
.finish_non_exhaustive()
}
}
#[implement(IClassFactory)]
pub struct AecApoClassFactory {
server_lock: Refcount,
vtable: &'static AecApoVTable,
}
impl AecApoClassFactory {
#[must_use]
pub const fn new(vtable: &'static AecApoVTable) -> Self {
Self {
server_lock: Refcount::new(),
vtable,
}
}
#[inline]
#[must_use]
pub fn server_lock_count(&self) -> u32 {
self.server_lock.count()
}
#[inline]
#[must_use]
pub fn clsid(&self) -> Clsid {
self.vtable.clsid
}
}
impl IClassFactory_Impl for AecApoClassFactory_Impl {
#[allow(clippy::not_unsafe_ptr_arg_deref)]
fn CreateInstance(
&self,
punkouter: Ref<IUnknown>,
riid: *const GUID,
ppvobject: *mut *mut c_void,
) -> windows_core::Result<()> {
if ppvobject.is_null() {
return Err(windows_core::Error::new(
HRESULT::from(HResult::E_POINTER),
"ppvobject is null",
));
}
unsafe {
*ppvobject = core::ptr::null_mut();
}
if !punkouter.is_null() {
return Err(windows_core::Error::new(
HRESULT::from(HResult::CLASS_E_NOAGGREGATION),
"AecApoClassFactory does not support aggregation",
));
}
let inner = (self.vtable.create)();
let com_object = ComObject::new(AecApoInstanceCom::new(inner));
let unknown: IUnknown = com_object.into_interface();
unsafe { unknown.query(riid, ppvobject) }.ok()
}
fn LockServer(&self, flock: BOOL) -> windows_core::Result<()> {
if flock.as_bool() {
self.server_lock.add_ref();
} else {
self.server_lock.release();
}
Ok(())
}
}