Вопрос или проблема
Конечная цель:
- Открыть Проводник (несколько вкладок) в win11.
- Выбрать файл
- Нажать клавишу пробела, чтобы получить путь к выбранному файлу в вашей программе
Текущий прогресс:
Все выбранные пути к файлам получены.
Что я пробовал:
- С помощью
IShellWindows
Не удалось получить путь к файлу, который в данный момент выбран на вкладке Проводника.
fn get_select_file_path(hwnd: HWND) -> Option<String> {
// hwnd это дескриптор активного окна, полученный через WindowsAndMessaging::GetForegroundWindow();
unsafe {
// Инициализация библиотеки COM
let com = CoInitializeEx(None, COINIT_DISABLE_OLE1DDE);
if com.is_err() {
return None;
}
let hr: Result<IShellWindows, windows::core::Error> =
CoCreateInstance(&ShellWindows, None, CLSCTX_LOCAL_SERVER);
// let hr = CoCreateInstance(&ShellWindows, None, CLSCTX_INPROC_HANDLER);
if hr.is_err() {
println!("Ошибка создания IShellWindows");
CoUninitialize(); // Очистка COM
return None; // Ошибка создания IShellWindows
}
let shell_windows = hr.unwrap();
let mut target_path = None;
let count = shell_windows.Count().unwrap_or_default();
for i in 0..count {
let variant = VARIANT::from(i);
let window: IDispatch = shell_windows.Item(&variant).ok()?;
let web_browser: IWebBrowser2 = window.cast().ok()?;
// Проверка, соответствует ли окно текущему активному окну
let item_hwnd = web_browser.HWND().ok()?;
if item_hwnd.0 != hwnd.0 as isize {
continue;
}
let a = web_browser.LocationURL().ok()?;
println!("web_browser Путь: {:?}", a);
// Получение представления папки через IWebBrowser2 и выбор выбранных элементов
let document = web_browser.Document().ok()?;
let folder_view: IShellFolderViewDual3 = document.cast().ok()?;
let selected_items = folder_view.SelectedItems().ok()?;
let count = selected_items.Count().ok()?;
if count > 0 {
let item = selected_items.Item(&VARIANT::from(0)).ok()?;
let path = item.Path().ok()?;
target_path = Some(path.to_string());
break
}
}
// Очистка COM
CoUninitialize();
target_path
}
}
- С помощью
IUIAutomation
Я получаю имя файла, выбранного на текущей вкладке Проводника, но не могу получить его путь.
unsafe fn find_tab_items(ui_automation: &IUIAutomation, element: &IUIAutomationElement, file_name: &mut String) -> Result<(), WError> {
// Поиск дочерних элементов
let condition = ui_automation.CreatePropertyCondition(UIA_ControlTypePropertyId, &VARIANT::from(UIA_ListItemControlTypeId.0))?;
let list_element = element.FindAll(TreeScope_Descendants, &condition)?;
let count = list_element.Length()?;
for i in 0..count {
let item = list_element.GetElement(i)?;
// Попытка получить SelectionItemPattern
let selection_pattern: IUIAutomationSelectionItemPattern = item.GetCurrentPatternAs(UIA_SelectionItemPatternId)?;
// Проверка, выбран ли элемент
let is_selected = selection_pattern.CurrentIsSelected()?;
if is_selected.as_bool().eq(&true) {
// Получение имени файла или пути
let tmp_name = item.GetCurrentPropertyValue(UIA_NamePropertyId)?;
*file_name = tmp_name.to_string();
break
}
}
Ok(())
}
Ожидается:
- Получает путь к файлу, выбранному на текущей вкладке в Проводнике.
Ответ или решение
Для того чтобы получить путь к выбранному файлу в текущей вкладке проводника Windows с использованием языка программирования Rust, необходимо использовать несколько компонентов Windows API и COM (Component Object Model). Ниже приводится более подробный подход к решению этой задачи, основываясь на вашем текущем прогрессе и опыте работы с IShellWindows
и IUIAutomation
.
Предварительная настройка и инициализация COM
Прежде всего, убедитесь, что вы инициализируете COM-библиотеку перед тем, как вызывать методы из нее. Это можно сделать с помощью функции CoInitializeEx
. Ваша функция уже включает этот шаг, что хорошо.
Использование IShellWindows
Вы используете интерфейс IShellWindows
, чтобы получить доступ к открытым окнам проводника. Однако важно понимать, что IShellWindows
не дает прямого доступа к выбранному элементу. Вам нужно будет использовать IWebBrowser2
и затем получить доступ к текущему выбранному элементу через IWebBrowser2::Document
.
Основная логика, которую вы можете использовать, состоит в том, чтобы:
- Итерировать по всем открытым окнам проводника.
- Для каждого окна проверять, совпадает ли его дескриптор (
HWND
) с текущим активным окном. - Если совпадает, получать текущий документ из
IWebBrowser2
. - Затем получать доступ к выбранным элементам.
Пример кода
Вот пример функции для получения пути к выбранному файлу:
fn get_selected_file_path(hwnd: HWND) -> Option<String> {
unsafe {
// Инициализация COM
let com = CoInitializeEx(None, COINIT_DISABLE_OLE1DDE);
if com.is_err() {
return None;
}
// Получение экземпляра IShellWindows
let shell_windows: IShellWindows = match CoCreateInstance(&ShellWindows, None, CLSCTX_LOCAL_SERVER) {
Ok(instance) => instance,
Err(_) => {
CoUninitialize();
return None;
}
};
// Перебор всех открытых окон
let count = shell_windows.Count().unwrap_or_default();
for i in 0..count {
let window: IDispatch = shell_windows.Item(&VARIANT::from(i)).ok()?;
let web_browser: IWebBrowser2 = window.cast().ok()?;
let item_hwnd = web_browser.HWND().ok()?;
if item_hwnd.0 != hwnd.0 as isize {
continue;
}
// Получение документа и выбранных элементов
let document = web_browser.Document().ok()?;
let folder_view: IShellFolderViewDual3 = document.cast().ok()?;
let selected_items = folder_view.SelectedItems().ok()?;
let num_selected = selected_items.Count().unwrap_or_default();
if num_selected > 0 {
let selected_item = selected_items.Item(&VARIANT::from(0)).ok()?;
let path = selected_item.Path().ok()?;
CoUninitialize();
return Some(path.to_string());
}
}
// Завершение работы с COM
CoUninitialize();
None
}
}
Использование IUIAutomation
Если вы хотите использовать IUIAutomation
, чтобы найти имя выбранного файла, вы можете продолжить с этого подхода. Однако вам потребуется дополнительно оформить механизм для получения полного пути на основе имени файла. Это может включать в себя добавление логики для поиска родительской директории и комбинирования имени файла с путем к директории.
Завершение
Эти шаги предоставляют вам возможность получить путь к выбранному файлу в текущей вкладке Windows Explorer. Убедитесь, что у вас есть необходимые зависимости для работы с COM и что ваш проект настроен правильно для работы с Windows API.
Следуя этим рекомендациям, вы сможете успешно извлечь путь к выбранному файлу в проводнике. Если у вас возникнут дополнительные вопросы или проблемы, не стесняйтесь обращаться за помощью.