#![cfg(windows)]
use anyhow::{anyhow, Result};
use windows::core::{w, GUID, VARIANT};
use windows::Win32::Globalization::LOCALE_USER_DEFAULT;
use windows::Win32::System::Com::{
CoCreateInstance, CoInitializeEx, CoUninitialize, IDispatch, CLSCTX_LOCAL_SERVER,
COINIT_APARTMENTTHREADED, DISPATCH_METHOD, DISPPARAMS,
};
use windows::Win32::UI::WindowsAndMessaging::{
BringWindowToTop, EnumWindows, GetWindowTextLengthW, GetWindowTextW, IsWindowVisible,
SetForegroundWindow, ShowWindow, SW_SHOW,
};
use windows::Win32::Foundation::{BOOL, HWND, LPARAM};
const CLSID_IDMAN: GUID = GUID::from_values(
0xECF21EAB,
0x3AA8,
0x4355,
[0x82, 0xBE, 0xF7, 0x77, 0x99, 0x00, 0x01, 0xDD],
);
#[derive(Debug, thiserror::Error)]
pub enum IdmError {
#[error("It seem IDM (Internet Download Manager) not installed, please install first !")]
NotFound,
}
fn variant_str(v: Option<&str>) -> VARIANT {
match v {
Some(s) => VARIANT::from(s),
None => VARIANT::default(),
}
}
pub struct SendLinkArgs<'a> {
pub link: &'a str,
pub referrer: Option<&'a str>,
pub cookie: Option<&'a str>,
pub post_data: Option<&'a str>,
pub user: Option<&'a str>,
pub password: Option<&'a str>,
pub path_to_save: Option<&'a str>,
pub output: Option<&'a str>,
pub lflag: i32,
pub user_agent: Option<&'a str>,
}
pub fn send_link_to_idm(args: &SendLinkArgs) -> Result<()> {
unsafe {
let _ = CoInitializeEx(None, COINIT_APARTMENTTHREADED);
let disp: IDispatch = CoCreateInstance(&CLSID_IDMAN, None, CLSCTX_LOCAL_SERVER)
.map_err(|_| anyhow!(IdmError::NotFound))?;
let name = w!("SendLinkToIDM2");
let mut dispid: i32 = 0;
let names = [name];
disp.GetIDsOfNames(
&GUID::zeroed(),
names.as_ptr(),
1,
LOCALE_USER_DEFAULT,
&mut dispid,
)?;
let reserved1 = variant_str(args.user_agent);
let reserved2 = VARIANT::default();
let mut com_args: Vec<VARIANT> = vec![
reserved2,
reserved1,
VARIANT::from(args.lflag),
variant_str(args.output),
variant_str(args.path_to_save),
variant_str(args.password),
variant_str(args.user),
variant_str(args.post_data),
variant_str(args.cookie),
variant_str(args.referrer),
VARIANT::from(args.link),
];
let dp = DISPPARAMS {
rgvarg: com_args.as_mut_ptr(),
rgdispidNamedArgs: std::ptr::null_mut(),
cArgs: com_args.len() as u32,
cNamedArgs: 0,
};
let mut result = VARIANT::default();
disp.Invoke(
dispid,
&GUID::zeroed(),
LOCALE_USER_DEFAULT,
DISPATCH_METHOD,
&dp,
Some(&mut result),
None,
None,
)?;
CoUninitialize();
}
Ok(())
}
pub fn bring_to_top() {
unsafe {
static mut FOUND: Option<HWND> = None;
FOUND = None;
unsafe extern "system" fn enum_proc(hwnd: HWND, _lparam: LPARAM) -> BOOL {
if IsWindowVisible(hwnd).as_bool() {
let len = GetWindowTextLengthW(hwnd);
if len > 0 {
let mut buf = vec![0u16; (len + 1) as usize];
let read = GetWindowTextW(hwnd, &mut buf);
if read > 0 {
let title = String::from_utf16_lossy(&buf[..read as usize]);
if title.to_lowercase().contains("internet download manager") {
FOUND = Some(hwnd);
return BOOL(0); }
}
}
}
BOOL(1)
}
let _ = EnumWindows(Some(enum_proc), LPARAM(0));
if let Some(hwnd) = FOUND {
let _ = ShowWindow(hwnd, SW_SHOW);
let _ = SetForegroundWindow(hwnd);
let _ = BringWindowToTop(hwnd);
}
}
}