use windows::Win32::Foundation::{
DISP_E_BADPARAMCOUNT, DISP_E_MEMBERNOTFOUND, DISP_E_UNKNOWNINTERFACE, DISP_E_UNKNOWNNAME,
E_POINTER, TYPE_E_ELEMENTNOTFOUND,
};
use windows::Win32::System::Com::{
DISPATCH_FLAGS, DISPPARAMS, EXCEPINFO, IConnectionPoint, IConnectionPoint_Impl,
IConnectionPointContainer, IConnectionPointContainer_Impl, IDispatch, IDispatch_Impl,
IEnumConnectionPoints, IEnumConnections, ITypeInfo,
};
use windows::Win32::System::Ole::{CONNECT_E_CANNOTCONNECT, CONNECT_E_NOCONNECTION};
use windows::Win32::System::Variant::VARIANT;
use windows_core::{GUID, IUnknown, IUnknownImpl, Interface, PCWSTR, Ref};
use crate::control::DenisePanel_Impl;
use crate::dispatch::{self, Action};
use crate::typelib;
use crate::variant;
pub const DIID_DENISE_PANEL_EVENTS: GUID =
GUID::from_u128(0x5405_253D_6E92_42BA_916C_F483_4D09_9F69);
impl IDispatch_Impl for DenisePanel_Impl {
fn GetTypeInfoCount(&self) -> windows_core::Result<u32> {
Ok(u32::from(self.type_info().is_ok()))
}
fn GetTypeInfo(&self, index: u32, _lcid: u32) -> windows_core::Result<ITypeInfo> {
if index != 0 {
return Err(TYPE_E_ELEMENTNOTFOUND.into());
}
self.type_info()
}
fn GetIDsOfNames(
&self,
riid: *const GUID,
names: *const PCWSTR,
count: u32,
_lcid: u32,
out: *mut i32,
) -> windows_core::Result<()> {
if names.is_null() || out.is_null() {
return Err(E_POINTER.into());
}
reserved_iid(riid)?;
let count = count as usize;
let (names, out) = unsafe {
(
core::slice::from_raw_parts(names, count),
core::slice::from_raw_parts_mut(out, count),
)
};
let owned: Vec<String> = names
.iter()
.map(|name| unsafe { name.to_string() }.unwrap_or_default())
.collect();
let borrowed: Vec<&str> = owned.iter().map(String::as_str).collect();
if dispatch::resolve(&borrowed, out) {
Ok(())
} else {
Err(DISP_E_UNKNOWNNAME.into())
}
}
fn Invoke(
&self,
dispid: i32,
riid: *const GUID,
_lcid: u32,
flags: DISPATCH_FLAGS,
params: *const DISPPARAMS,
result: *mut VARIANT,
_exception: *mut EXCEPINFO,
_argument_error: *mut u32,
) -> windows_core::Result<()> {
reserved_iid(riid)?;
let member = dispatch::member_by_id(dispid).ok_or(DISP_E_MEMBERNOTFOUND)?;
let action = dispatch::action(member, flags.0).ok_or(DISP_E_MEMBERNOTFOUND)?;
match action {
Action::Get => {
match member.dispid {
dispatch::DISPID_TEXT => {
let text = self.model.borrow().text.clone();
unsafe { variant::write_string(result, &text) };
}
dispatch::DISPID_CAPTION => {
let caption = self.model.borrow().caption.clone();
unsafe { variant::write_string(result, &caption) };
}
dispatch::DISPID_ENABLED => {
let enabled = self.model.borrow().enabled;
unsafe { variant::write_bool(result, enabled) };
}
_ => return Err(DISP_E_MEMBERNOTFOUND.into()),
}
Ok(())
}
Action::Put => {
let argument =
unsafe { variant::sole_argument(params) }.ok_or(DISP_E_BADPARAMCOUNT)?;
match member.dispid {
dispatch::DISPID_TEXT => {
let text = unsafe { variant::to_string(argument) }?;
self.model.borrow_mut().text = text;
}
dispatch::DISPID_CAPTION => {
let caption = unsafe { variant::to_string(argument) }?;
self.model.borrow_mut().caption = caption;
}
dispatch::DISPID_ENABLED => {
let enabled = unsafe { variant::to_bool(argument) }?;
self.model.borrow_mut().enabled = enabled;
}
_ => return Err(DISP_E_MEMBERNOTFOUND.into()),
}
self.model.borrow_mut().touch();
self.sync();
Ok(())
}
Action::Call => match member.dispid {
dispatch::DISPID_REFRESH => {
{
let mut model = self.model.borrow_mut();
model.refresh = true;
model.touch();
}
self.sync();
Ok(())
}
_ => Err(DISP_E_MEMBERNOTFOUND.into()),
},
}
}
}
impl DenisePanel_Impl {
fn type_info(&self) -> windows_core::Result<ITypeInfo> {
if let Some(info) = self.state.borrow().type_info.clone() {
return Ok(info);
}
let info = typelib::panel_type_info(crate::server::library_path().as_deref())?;
self.state.borrow_mut().type_info = Some(info.clone());
Ok(info)
}
}
fn reserved_iid(riid: *const GUID) -> windows_core::Result<()> {
if riid.is_null() {
return Ok(());
}
if unsafe { *riid } == GUID::zeroed() {
Ok(())
} else {
Err(DISP_E_UNKNOWNINTERFACE.into())
}
}
impl IConnectionPointContainer_Impl for DenisePanel_Impl {
fn EnumConnectionPoints(&self) -> windows_core::Result<IEnumConnectionPoints> {
Err(windows::Win32::Foundation::E_NOTIMPL.into())
}
fn FindConnectionPoint(&self, riid: *const GUID) -> windows_core::Result<IConnectionPoint> {
if riid.is_null() {
return Err(E_POINTER.into());
}
if unsafe { *riid } != DIID_DENISE_PANEL_EVENTS {
return Err(CONNECT_E_NOCONNECTION.into());
}
Ok(self.to_interface())
}
}
impl IConnectionPoint_Impl for DenisePanel_Impl {
fn GetConnectionInterface(&self) -> windows_core::Result<GUID> {
Ok(DIID_DENISE_PANEL_EVENTS)
}
fn GetConnectionPointContainer(&self) -> windows_core::Result<IConnectionPointContainer> {
Ok(self.to_interface())
}
fn Advise(&self, sink: Ref<'_, IUnknown>) -> windows_core::Result<u32> {
let sink = sink.cloned().ok_or(E_POINTER)?;
let sink: IDispatch = sink.cast().map_err(|_| CONNECT_E_CANNOTCONNECT)?;
Ok(self.model.borrow_mut().advise(sink))
}
fn Unadvise(&self, cookie: u32) -> windows_core::Result<()> {
if self.model.borrow_mut().unadvise(cookie) {
Ok(())
} else {
Err(CONNECT_E_NOCONNECTION.into())
}
}
fn EnumConnections(&self) -> windows_core::Result<IEnumConnections> {
Err(windows::Win32::Foundation::E_NOTIMPL.into())
}
}