use windows::{
core::{w, Interface},
Win32::{
System::{
Com::{
CoCreateInstance, CoInitializeEx, CoUninitialize, IDispatch, IServiceProvider,
CLSCTX_SERVER, COINIT_APARTMENTTHREADED,
},
SystemServices::SFGAO_FILESYSTEM,
Variant::{VARIANT, VT_I4},
},
UI::{
Shell::{
IShellBrowser, IShellItemArray, IShellWindows, ShellWindows,
SIGDN_DESKTOPABSOLUTEPARSING, SIGDN_FILESYSPATH, SVGIO_SELECTION,
},
WindowsAndMessaging,
},
},
};
pub fn get_explorer_selected_file() -> Vec<String> {
unsafe {
let mut file_list = Vec::new();
let hr = CoInitializeEx(None, COINIT_APARTMENTTHREADED);
if hr.is_err() {
println!("Failed to initialize COM: {:?}", hr);
return file_list;
}
let hwnd_gfw = WindowsAndMessaging::GetForegroundWindow();
let shell_windows: IShellWindows =
match CoCreateInstance(&ShellWindows, None, CLSCTX_SERVER) {
Ok(windows) => windows,
Err(e) => {
println!("Failed to create ShellWindows instance: {:?}", e);
return file_list;
}
};
let result_hwnd = match WindowsAndMessaging::FindWindowExW(
Some(hwnd_gfw),
None,
w!("ShellTabWindowClass"),
None,
) {
Ok(hwnd) => hwnd,
Err(e) => {
println!("Failed to find ShellTabWindowClass window: {:?}", e);
return file_list;
}
};
let count = shell_windows.Count().unwrap_or_default();
for i in 0..count {
let mut variant = VARIANT::default();
let inner = &mut *variant.Anonymous.Anonymous;
inner.vt = VT_I4;
inner.Anonymous.lVal = i;
let window: IDispatch = match shell_windows.Item(&variant) {
Ok(w) => w,
Err(e) => {
println!("Failed to get window item: {:?}", e);
continue;
}
};
let mut service_provider: Option<IServiceProvider> = None;
let hr = window.query(
&IServiceProvider::IID,
&mut service_provider as *mut _ as *mut _,
);
if hr.is_err() {
println!("Failed to query service provider: {:?}", hr);
continue;
}
let service_provider = match service_provider {
Some(sp) => sp,
None => continue,
};
let shell_browser =
match service_provider.QueryService::<IShellBrowser>(&IShellBrowser::IID) {
Ok(sb) => sb,
Err(e) => {
println!("Failed to query shell browser: {:?}", e);
continue;
}
};
let phwnd = match shell_browser.GetWindow() {
Ok(hw) => hw,
Err(e) => {
println!("Failed to get window handle: {:?}", e);
continue;
}
};
if hwnd_gfw.0 != phwnd.0 && result_hwnd.0 != phwnd.0 {
continue;
}
let shell_view = match shell_browser.QueryActiveShellView() {
Ok(sv) => sv,
Err(e) => {
println!("Failed to query active shell view: {:?}", e);
continue;
}
};
let shell_items = match shell_view.GetItemObject::<IShellItemArray>(SVGIO_SELECTION) {
Ok(si) => si,
Err(e) => {
println!("Failed to get shell items: {:?}", e);
continue;
}
};
let count = shell_items.GetCount().unwrap_or_default();
for i in 0..count {
let shell_item = match shell_items.GetItemAt(i) {
Ok(item) => item,
Err(e) => {
println!("Failed to get shell item at {}: {:?}", i, e);
continue;
}
};
if let Ok(attrs) = shell_item.GetAttributes(SFGAO_FILESYSTEM) {
if attrs.0 == 0 {
continue;
}
}
if let Ok(display_name) = shell_item.GetDisplayName(SIGDN_FILESYSPATH) {
if let Ok(name) = display_name.to_string() {
file_list.push(name);
continue;
}
}
if let Ok(display_name) = shell_item.GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING) {
if let Ok(name) = display_name.to_string() {
file_list.push(name);
}
}
}
break;
}
CoUninitialize();
file_list
}
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(0, 0);
}
}