use windows::Win32::Foundation::HWND;
use windows::Win32::UI::Shell::CMINVOKECOMMANDINFOEX;
use windows::Win32::UI::WindowsAndMessaging::SW_SHOWNORMAL;
use windows::core::PCSTR;
use crate::error::{Error, Result};
use crate::menu_items::InvokeParams;
const CMIC_MASK_UNICODE: u32 = 0x00004000;
pub(crate) fn invoke_command(
ctx_menu: &windows::Win32::UI::Shell::IContextMenu,
command_offset: u32,
hwnd: HWND,
params: Option<InvokeParams>,
) -> Result<()> {
let show_cmd = params
.as_ref()
.and_then(|p| p.show_cmd)
.unwrap_or(SW_SHOWNORMAL.0);
let directory_wide: Option<Vec<u16>> = params
.as_ref()
.and_then(|p| p.directory.as_ref())
.map(|d| d.encode_utf16().chain(std::iter::once(0)).collect());
let verb = command_offset as usize;
let verb_w = command_offset as usize;
let mut info = CMINVOKECOMMANDINFOEX {
cbSize: std::mem::size_of::<CMINVOKECOMMANDINFOEX>() as u32,
fMask: CMIC_MASK_UNICODE,
hwnd,
lpVerb: PCSTR(verb as *const u8),
lpVerbW: windows::core::PCWSTR(verb_w as *const u16),
nShow: show_cmd,
..Default::default()
};
if let Some(ref dir) = directory_wide {
info.lpDirectoryW = windows::core::PCWSTR(dir.as_ptr());
}
unsafe {
ctx_menu
.InvokeCommand(std::ptr::addr_of!(info) as *const _)
.map_err(Error::InvokeCommand)?;
}
Ok(())
}
pub(crate) fn invoke_command_by_verb(
ctx_menu: &windows::Win32::UI::Shell::IContextMenu,
verb: &str,
hwnd: HWND,
) -> Result<()> {
let verb_ansi: Vec<u8> = verb.bytes().chain(std::iter::once(0)).collect();
let verb_wide: Vec<u16> = verb.encode_utf16().chain(std::iter::once(0)).collect();
let info = CMINVOKECOMMANDINFOEX {
cbSize: std::mem::size_of::<CMINVOKECOMMANDINFOEX>() as u32,
fMask: CMIC_MASK_UNICODE,
hwnd,
lpVerb: PCSTR(verb_ansi.as_ptr()),
lpVerbW: windows::core::PCWSTR(verb_wide.as_ptr()),
nShow: SW_SHOWNORMAL.0,
..Default::default()
};
unsafe {
ctx_menu
.InvokeCommand(std::ptr::addr_of!(info) as *const _)
.map_err(Error::InvokeCommand)?;
}
Ok(())
}