diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 01e4fdb..a48a9d4 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -35,6 +35,7 @@ windows = { version = "0.58.0", features = [ "Win32_System_Ole", "Win32_System_Registry", "Win32_Graphics_Gdi", + "Win32_UI_Accessibility", ] } infer = { version = "0.16.0", features = ["std"] } tauri-plugin-fs = "2" diff --git a/src-tauri/src/helper/win.rs b/src-tauri/src/helper/win.rs index f4ae199..77754c7 100644 --- a/src-tauri/src/helper/win.rs +++ b/src-tauri/src/helper/win.rs @@ -103,4 +103,11 @@ pub fn get_default_program_name(path: &str) -> Result { let name = String::from_utf16_lossy(&buffer[..size as usize - 1]); Ok(name) } +} + +pub fn get_window_text(hwnd: HWND) -> String { + let len = unsafe { WindowsAndMessaging::GetWindowTextLengthW(hwnd) + 1 }; + let mut buffer = vec![0u16; len as usize]; + let len = unsafe { WindowsAndMessaging::GetWindowTextW(hwnd, &mut buffer) }; + String::from_utf16_lossy(&buffer[0..len as usize]) } \ No newline at end of file diff --git a/src-tauri/src/preview.rs b/src-tauri/src/preview.rs index e9e2c50..00b92db 100644 --- a/src-tauri/src/preview.rs +++ b/src-tauri/src/preview.rs @@ -9,16 +9,18 @@ use windows::{ Foundation::{BOOL, HWND, LPARAM, LRESULT, WPARAM}, System::{ Com::{ - CoCreateInstance, CoInitializeEx, CoUninitialize, IDispatch, IServiceProvider, CLSCTX_LOCAL_SERVER, CLSCTX_SERVER, COINIT_APARTMENTTHREADED, COINIT_MULTITHREADED + CoCreateInstance, CoInitializeEx, CoUninitialize, IDispatch, IServiceProvider, CLSCTX_INPROC_SERVER, CLSCTX_LOCAL_SERVER, CLSCTX_SERVER, COINIT_APARTMENTTHREADED, COINIT_DISABLE_OLE1DDE, COINIT_MULTITHREADED }, SystemServices::SFGAO_FILESYSTEM, Variant, }, UI::{ - Controls, + Controls::{self, LVM_GETITEMCOUNT, LVM_GETNEXTITEM, LVM_GETSELECTEDCOUNT, LVNI_SELECTED}, Input::KeyboardAndMouse, Shell::{ - IShellBrowser, IShellItemArray, IShellView, IShellWindows, ShellWindows, SIGDN_DESKTOPABSOLUTEPARSING, SIGDN_FILESYSPATH, SVGIO_SELECTION, SWFO_NEEDDISPATCH + IFileDialog, IShellBrowser, IShellFolder, IShellItemArray, IShellView, IShellWindows, + ShellWindows, SIGDN_DESKTOPABSOLUTEPARSING, SIGDN_FILESYSPATH, SVGIO_SELECTION, + SWFO_NEEDDISPATCH, IFileSaveDialog, FileOpenDialog, IFileOpenDialog, FileSaveDialog }, WindowsAndMessaging }, @@ -187,94 +189,93 @@ impl Selected { fn get_select_file_from_dialog() -> Result { - let (tx, rx) = mpsc::channel(); + let mut target_path = String::new(); + let fw_hwnd = unsafe { + WindowsAndMessaging::GetForegroundWindow() + }; + println!("fw_hwnd: {:?}", fw_hwnd); - unsafe { - // 如何将shell_def_view 转为 IShellBrowser - thread::spawn(move || { - let mut target_path = String::new(); - let hwnd_gfw = WindowsAndMessaging::GetForegroundWindow(); - println!("hwnd_gfw: {:?}", hwnd_gfw); - // dump_window_hierarchy(hwnd_gfw); - - let _ = CoInitializeEx(None, COINIT_APARTMENTTHREADED); - - let mut def_view: Option = None; - let _ = WindowsAndMessaging::EnumChildWindows(hwnd_gfw, Some(Self::get_select_file_from_dialog_proc), LPARAM(&mut def_view as *mut _ as isize)); - - if def_view.is_none() { - tx.send(target_path).unwrap(); - return; - } - - let def_view = def_view.unwrap(); - println!("def_view: {:?}", def_view); - // let list_view_hwnd = WindowsAndMessaging::FindWindowExW(def_view, None, w!("DirectUIHWND"), None); - // if list_view_hwnd.is_err() { - // tx.send(target_path).unwrap(); - // return; - // } - // let list_view_hwnd = list_view_hwnd.unwrap(); - // println!("list_view_hwnd: {:?}", list_view_hwnd); - // let list_view_classname = win::get_window_class_name(list_view_hwnd); - // if !list_view_classname.contains("DirectUIHWND") { - // tx.send(target_path).unwrap(); - // return; - // } - - - let msg_id = WindowsAndMessaging::RegisterWindowMessageW(w!("ShellView_GetIShellBrowser")); - println!("msg_id: {:?}", msg_id); - - let mut view_dispatch: Option = None; - let tmp_q = WindowsAndMessaging::SendMessageW( - def_view, - msg_id, - WPARAM(0), - LPARAM(&mut view_dispatch as *mut _ as isize) - ); - println!("tmp_q: {:?}", tmp_q); - println!("view_dispatch: {:?}", view_dispatch); - - let mut unknown: Option = None; - let result = WindowsAndMessaging::SendMessageW( - def_view, - msg_id, - WPARAM(0x0), - LPARAM(&mut unknown as *mut _ as isize) - ); - - println!("result: {:?}", result); - println!("unknown: {:?}", unknown); - if unknown.is_none() { - tx.send(target_path).unwrap(); - return; - } - let unknown = unknown.unwrap(); - - let shell_view = unknown.cast::().ok(); - if let Some(shell_view) = shell_view { - target_path = Self::get_selected_file_path_from_shellview(shell_view); - println!("target_path: {:?}", target_path); - } - - CoUninitialize(); - tx.send(target_path).unwrap(); - }); + // 获取选中文件窗口的 Text + let seleced_file_hwnd = unsafe { + WindowsAndMessaging::FindWindowExW(fw_hwnd, None, w!("ComboBoxEx32"), None) + }; + println!("seleced_file_hwnd: {:?}", seleced_file_hwnd); + if seleced_file_hwnd.is_err() { + return Ok(target_path); } - let target_path = rx.recv().unwrap(); + let seleced_file_hwnd = seleced_file_hwnd.unwrap(); + let mut real_selected_file_hwnd: Option = None; + let _ = unsafe { + WindowsAndMessaging::EnumChildWindows(seleced_file_hwnd, Some(Self::get_select_file_from_dialog_proc), LPARAM(&mut real_selected_file_hwnd as *const _ as _)) + }; + println!("real_selected_file_hwnd: {:?}", real_selected_file_hwnd); + if real_selected_file_hwnd.is_none() { + return Ok(target_path); + } + let real_selected_file_hwnd = real_selected_file_hwnd.unwrap(); + let seleced_file_title = win::get_window_text(real_selected_file_hwnd); + println!("seleced_file_title: {:?}", seleced_file_title); + + // 获取搜索框的 Text + let mut breadcrumb_parent_hwnd: Option = None; + let _ = unsafe { + WindowsAndMessaging::EnumChildWindows(fw_hwnd, Some(Self::get_select_file_from_dialog_proc), LPARAM(&mut breadcrumb_parent_hwnd as *const _ as _)) + }; + if breadcrumb_parent_hwnd.is_none() { + return Ok(target_path); + } + let breadcrumb_parent_hwnd = breadcrumb_parent_hwnd.unwrap(); + let breadcrumb_hwnd = unsafe { + WindowsAndMessaging::FindWindowExW(breadcrumb_parent_hwnd, None, w!("ToolbarWindow32"), None) + }; + if breadcrumb_hwnd.is_err() { + return Ok(target_path); + } + let breadcrumb_hwnd = breadcrumb_hwnd.unwrap(); + let breadcrumb_title = win::get_window_text(breadcrumb_hwnd); + println!("breadcrumb_title: {:?}", breadcrumb_title); + + target_path = format!("{}\\{}", breadcrumb_title.replace("地址:", ""), seleced_file_title); + println!("target_path: {:?}", target_path); + Ok(target_path) } unsafe extern "system" fn get_select_file_from_dialog_proc(hwnd: HWND, lparam: LPARAM) -> BOOL { let list_view = lparam.0 as *mut Option; let class_name = win::get_window_class_name(hwnd); - if class_name.contains("DirectUIHWND") { + if class_name.contains("Breadcrumb Parent") | class_name.contains("Edit") | class_name.contains("SHELLDLL_DefView") { *list_view = Some(hwnd); return BOOL(0); } BOOL(1) } + unsafe fn get_shellview_from_hwnd(hwnd: HWND) -> Option { + // 定义 WM 消息 + const SFVM_GETSERVICEPROVIDER: u32 = WindowsAndMessaging::WM_USER + 7; + + let mut service_provider: Option = None; + WindowsAndMessaging::SendMessageW( + hwnd, + SFVM_GETSERVICEPROVIDER, + WPARAM(0), + LPARAM(&mut service_provider as *mut _ as isize) + ); + + println!("service_provider: {:?}", service_provider); + + if let Some(provider) = service_provider { + // 获取 IShellBrowser + if let Ok(browser) = provider.QueryService::(&IShellBrowser::IID) { + // 获取 IShellView + return browser.QueryActiveShellView().ok(); + } + } + + + None + } + unsafe fn get_selected_file_path_from_shellview(shell_view: IShellView) -> String { let mut target_path = String::new(); let shell_items = shell_view.GetItemObject::(SVGIO_SELECTION);