druid_win_shell/
dialog.rs

1// Copyright 2018 The xi-editor Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! File open/save dialogs.
16
17#![allow(non_upper_case_globals)]
18
19use winapi::Interface;
20use winapi::shared::minwindef::*;
21use winapi::shared::ntdef::LPWSTR;
22use winapi::shared::windef::*;
23use winapi::shared::wtypesbase::*;
24use winapi::um::combaseapi::*;
25use winapi::um::shobjidl::*;
26use winapi::um::shobjidl_core::*;
27use wio::com::ComPtr;
28
29use std::ptr::null_mut;
30use std::ffi::OsString;
31use util::{as_result, Error, FromWide};
32
33/// Type of file dialog.
34pub enum FileDialogType {
35    /// File open dialog.
36    Open,
37    /// File save dialog.
38    Save,
39}
40
41/// Options for file dialog.
42///
43/// See documentation for
44/// [_FILEOPENDIALOGOPTIONS](https://docs.microsoft.com/en-us/windows/desktop/api/shobjidl_core/ne-shobjidl_core-_fileopendialogoptions)
45/// for more information on the winapi implementation.
46#[derive(Default)]
47pub struct FileDialogOptions(DWORD);
48
49impl FileDialogOptions {
50    /// Include system and hidden items.
51    ///
52    /// Maps to `FOS_FORCESHOWHIDDEN` in winapi.
53    pub fn set_show_hidden(&mut self) {
54        self.0 |= FOS_FORCESHOWHIDDEN;
55    }
56
57    // TODO: more options as needed
58}
59
60// TODO: remove these when they get added to winapi
61DEFINE_GUID!{CLSID_FileOpenDialog,
62    0xDC1C5A9C, 0xE88A, 0x4DDE, 0xA5, 0xA1, 0x60, 0xF8, 0x2A, 0x20, 0xAE, 0xF7}
63DEFINE_GUID!{CLSID_FileSaveDialog,
64    0xC0B4E2F3, 0xBA21, 0x4773, 0x8D, 0xBA, 0x33, 0x5E, 0xC9, 0x46, 0xEB, 0x8B}
65
66pub(crate) unsafe fn get_file_dialog_path(hwnd_owner: HWND, ty: FileDialogType,
67    options: FileDialogOptions) -> Result<OsString, Error>
68{
69    let mut pfd: *mut IFileDialog = null_mut();
70    let (class, id) = match ty {
71        FileDialogType::Open => (&CLSID_FileOpenDialog, IFileOpenDialog::uuidof()),
72        FileDialogType::Save => (&CLSID_FileSaveDialog, IFileSaveDialog::uuidof()),
73    };
74    as_result(CoCreateInstance(class,
75            null_mut(),
76            CLSCTX_INPROC_SERVER,
77            &id,
78            &mut pfd as *mut *mut IFileDialog as *mut LPVOID
79            ))?;
80    let file_dialog = ComPtr::from_raw(pfd);
81    as_result(file_dialog.SetOptions(options.0))?;
82    as_result(file_dialog.Show(hwnd_owner))?;
83    let mut result_ptr: *mut IShellItem = null_mut();
84    as_result(file_dialog.GetResult(&mut result_ptr))?;
85    let shell_item = ComPtr::from_raw(result_ptr);
86    let mut display_name: LPWSTR = null_mut();
87    as_result(shell_item.GetDisplayName(SIGDN_FILESYSPATH, &mut display_name))?;
88    let filename = display_name.to_os_string();
89    CoTaskMemFree(display_name as LPVOID);
90
91    Ok(filename)
92}