use crate::{
DbgModelResult, WdResult, data::Variant, dbgmodel::*, dmerr,
impl_debug_interface, wd::dbgmodel::WdModelObject,
};
use std::rc::Rc;
use windows::Win32::System::Diagnostics::Debug::Extensions::{
IKeyStore, IModelMethod, IModelMethod_Impl, IModelObject,
};
use windows_core::{IUnknown, OutRef, Ref, imp::E_POINTER, implement};
pub trait ModelMethodHandler {
fn call(
&self,
context_object: Option<ModelObjectRef>,
arguments: &[ModelObjectRef],
) -> DbgModelResult<(ModelObject, Option<KeyStore>)>;
}
impl_debug_interface!(ModelMethod, ModelMethodRef, IModelMethod);
impl ModelMethodHandler for ModelMethod {
fn call(
&self,
context_object: Option<ModelObjectRef>,
arguments: &[ModelObjectRef],
) -> DbgModelResult<(ModelObject, Option<KeyStore>)> {
let args: Vec<Option<IModelObject>> =
arguments.iter().map(|x| Some(x.as_base())).collect();
let mut result = None;
let mut metadata = None;
unsafe {
dmerr!(
result,
self.0.Call(
context_object.as_ref().map(|x| x.as_raw()),
&args,
&mut result,
Some(&mut metadata)
)
);
}
Ok((result.unwrap().into(), metadata.map(Into::into)))
}
}
#[implement(IModelMethod)]
pub struct ModelMethodAdapter(Rc<dyn ModelMethodHandler>);
impl ModelMethodAdapter {
pub fn new(callbacks: Rc<dyn ModelMethodHandler>) -> Self {
Self(callbacks)
}
pub fn as_handler(&self) -> &dyn ModelMethodHandler { self.0.as_ref() }
pub fn into_object(
self,
manager: impl AsRef<DataModelManager>,
) -> WdResult<WdModelObject> {
let unknown: IUnknown = self.into();
let variant = Variant::from(unknown);
Ok(manager
.as_ref()
.create_intrinsic_object(WdModelObjectKind::Method, &variant)?
.into())
}
}
#[allow(non_snake_case)]
impl IModelMethod_Impl for ModelMethodAdapter_Impl {
#[allow(clippy::not_unsafe_ptr_arg_deref)]
fn Call(
&self,
pContextObject: Ref<IModelObject>,
argCount: u64,
ppArguments: *const Option<IModelObject>,
ppResult: OutRef<IModelObject>,
ppMetadata: OutRef<IKeyStore>,
) -> windows_core::Result<()> {
let argCount = argCount.try_into()?;
let args = if argCount == 0 {
&[]
} else {
if ppArguments.is_null() {
return Err(E_POINTER.into());
}
unsafe { std::slice::from_raw_parts(ppArguments, argCount) }
};
let args: Vec<ModelObjectRef<'_>> = args
.iter()
.map(|argument| {
argument
.as_ref()
.ok_or_else(|| windows_core::Error::from(E_POINTER))
.map(Into::into)
})
.collect::<windows_core::Result<_>>()?;
let context_object = pContextObject.as_ref().map(Into::into);
let (result, metadata) = self
.0
.call(context_object, &args)
.map_err(|e| e.as_hresult())?;
ppResult.write(Some(result.as_base()))?;
match ppMetadata.write(metadata.map(|x| x.as_base())) {
Ok(_) => Ok(()),
Err(e) if e.code() == E_POINTER => Ok(()),
Err(e) => Err(e),
}
}
}