| // Copyright 2014 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/win/chrome_select_file_dialog_factory.h" |
| |
| #include <utility> |
| #include <vector> |
| |
| #include "base/feature_list.h" |
| #include "base/functional/bind.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/win/win_util.h" |
| #include "chrome/browser/win/util_win_service.h" |
| #include "chrome/services/util_win/public/mojom/util_win.mojom.h" |
| #include "mojo/public/cpp/bindings/remote.h" |
| #include "mojo/public/cpp/bindings/sync_call_restrictions.h" |
| #include "ui/shell_dialogs/execute_select_file_win.h" |
| #include "ui/shell_dialogs/select_file_dialog_win.h" |
| #include "ui/shell_dialogs/select_file_policy.h" |
| |
| // Helper class to execute a select file operation on a utility process. It |
| // hides the complexity of managing the lifetime of the connection to the |
| // UtilWin service. |
| class UtilWinHelper { |
| public: |
| UtilWinHelper(const UtilWinHelper&) = delete; |
| UtilWinHelper& operator=(const UtilWinHelper&) = delete; |
| |
| // Executes the select file operation and returns the result via |
| // |on_select_file_executed_callback|. |
| static void ExecuteSelectFile( |
| ui::SelectFileDialog::Type type, |
| const std::u16string& title, |
| const base::FilePath& default_path, |
| const std::vector<ui::FileFilterSpec>& filter, |
| int file_type_index, |
| const std::wstring& default_extension, |
| HWND owner, |
| ui::OnSelectFileExecutedCallback on_select_file_executed_callback); |
| |
| private: |
| UtilWinHelper( |
| ui::SelectFileDialog::Type type, |
| const std::u16string& title, |
| const base::FilePath& default_path, |
| const std::vector<ui::FileFilterSpec>& filter, |
| int file_type_index, |
| const std::wstring& default_extension, |
| HWND owner, |
| ui::OnSelectFileExecutedCallback on_select_file_executed_callback); |
| |
| // Connection error handler for the interface pipe. |
| void OnConnectionError(); |
| |
| // Forwards the result of the file operation to the |
| // |on_select_file_executed_callback_|. |
| void OnSelectFileExecuted(const std::vector<base::FilePath>& paths, |
| int index); |
| |
| // The pointer to the UtilWin interface. This must be kept alive while waiting |
| // for the response. |
| mojo::Remote<chrome::mojom::UtilWin> remote_util_win_; |
| |
| // The callback that is invoked when the file operation is finished. |
| ui::OnSelectFileExecutedCallback on_select_file_executed_callback_; |
| |
| SEQUENCE_CHECKER(sequence_checker_); |
| }; |
| |
| // static |
| void UtilWinHelper::ExecuteSelectFile( |
| ui::SelectFileDialog::Type type, |
| const std::u16string& title, |
| const base::FilePath& default_path, |
| const std::vector<ui::FileFilterSpec>& filter, |
| int file_type_index, |
| const std::wstring& default_extension, |
| HWND owner, |
| ui::OnSelectFileExecutedCallback on_select_file_executed_callback) { |
| // Self-deleting when the select file operation completes. |
| new UtilWinHelper(type, title, default_path, filter, file_type_index, |
| default_extension, owner, |
| std::move(on_select_file_executed_callback)); |
| } |
| |
| UtilWinHelper::UtilWinHelper( |
| ui::SelectFileDialog::Type type, |
| const std::u16string& title, |
| const base::FilePath& default_path, |
| const std::vector<ui::FileFilterSpec>& filter, |
| int file_type_index, |
| const std::wstring& default_extension, |
| HWND owner, |
| ui::OnSelectFileExecutedCallback on_select_file_executed_callback) |
| : on_select_file_executed_callback_( |
| std::move(on_select_file_executed_callback)) { |
| remote_util_win_ = LaunchUtilWinServiceInstance(); |
| |
| // |remote_util_win_| owns the callbacks and is guaranteed to be destroyed |
| // before |this|, therefore making base::Unretained() safe to use. |
| remote_util_win_.set_disconnect_handler(base::BindOnce( |
| &UtilWinHelper::OnConnectionError, base::Unretained(this))); |
| |
| remote_util_win_->CallExecuteSelectFile( |
| type, base::win::HandleToUint32(owner), title, default_path, filter, |
| file_type_index, base::WideToUTF16(default_extension), |
| base::BindOnce(&UtilWinHelper::OnSelectFileExecuted, |
| base::Unretained(this))); |
| } |
| |
| void UtilWinHelper::OnConnectionError() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| std::move(on_select_file_executed_callback_).Run({}, 0); |
| |
| delete this; |
| } |
| |
| void UtilWinHelper::OnSelectFileExecuted( |
| const std::vector<base::FilePath>& paths, |
| int index) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| |
| std::move(on_select_file_executed_callback_).Run(paths, index); |
| delete this; |
| } |
| |
| void ExecuteSelectFileImpl( |
| ui::SelectFileDialog::Type type, |
| const std::u16string& title, |
| const base::FilePath& default_path, |
| const std::vector<ui::FileFilterSpec>& filter, |
| int file_type_index, |
| const std::wstring& default_extension, |
| HWND owner, |
| ui::OnSelectFileExecutedCallback on_select_file_executed_callback) { |
| UtilWinHelper::ExecuteSelectFile(type, title, default_path, filter, |
| file_type_index, default_extension, owner, |
| std::move(on_select_file_executed_callback)); |
| } |
| |
| ChromeSelectFileDialogFactory::ChromeSelectFileDialogFactory() = default; |
| |
| ChromeSelectFileDialogFactory::~ChromeSelectFileDialogFactory() = default; |
| |
| ui::SelectFileDialog* ChromeSelectFileDialogFactory::Create( |
| ui::SelectFileDialog::Listener* listener, |
| std::unique_ptr<ui::SelectFilePolicy> policy) { |
| return ui::CreateWinSelectFileDialog( |
| listener, std::move(policy), base::BindRepeating(&ExecuteSelectFileImpl)); |
| } |