Skip to main content

pacenotes_installer\ui/
folder_picker.rs

1const BIF_RETURNONLYFSDIRS: u32 = 0x0000_0001;
2const BIF_NEWDIALOGSTYLE: u32 = 0x0000_0040;
3const MAX_PATH: usize = 260;
4
5/// The folder the user picked, or `None` on cancel.
6pub unsafe fn browse_for_folder(
7    owner: windows_sys::Win32::Foundation::HWND,
8    prompt: &str,
9) -> Option<String> {
10    let title = crate::i18n::to_wide(prompt);
11    let mut browse_info: windows_sys::Win32::UI::Shell::BROWSEINFOW = core::mem::zeroed();
12    browse_info.hwndOwner = owner;
13    browse_info.lpszTitle = title.as_ptr();
14    browse_info.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
15
16    let item_list = windows_sys::Win32::UI::Shell::SHBrowseForFolderW(&browse_info);
17    if item_list.is_null() {
18        return None;
19    }
20    let mut buffer = [0u16; MAX_PATH];
21    let found = windows_sys::Win32::UI::Shell::SHGetPathFromIDListW(item_list, buffer.as_mut_ptr());
22    windows_sys::Win32::System::Com::CoTaskMemFree(item_list as *const core::ffi::c_void);
23    if found == 0 {
24        return None;
25    }
26    let length = buffer
27        .iter()
28        .position(|&unit| unit == 0)
29        .unwrap_or(buffer.len());
30    Some(String::from_utf16_lossy(&buffer[..length]))
31}