| Index: chrome/browser/chrome_select_file_dialog_factory_win.cc
|
| diff --git a/chrome/browser/chrome_select_file_dialog_factory_win.cc b/chrome/browser/chrome_select_file_dialog_factory_win.cc
|
| index 3522358795274aba4e5e54c501e09ecd1e3c7c50..c24a491a6a3f6c201001e724b55614c1fc0c437b 100644
|
| --- a/chrome/browser/chrome_select_file_dialog_factory_win.cc
|
| +++ b/chrome/browser/chrome_select_file_dialog_factory_win.cc
|
| @@ -25,6 +25,29 @@
|
|
|
| namespace {
|
|
|
| +bool CallMetroOPENFILENAMEMethod(const char* method_name, OPENFILENAME* ofn) {
|
| + typedef BOOL (*MetroOPENFILENAMEMethod)(OPENFILENAME*);
|
| + MetroOPENFILENAMEMethod metro_method = NULL;
|
| + HMODULE metro_module = base::win::GetMetroModule();
|
| +
|
| + if (metro_module != NULL) {
|
| + metro_method = reinterpret_cast<MetroOPENFILENAMEMethod>(
|
| + ::GetProcAddress(metro_module, method_name));
|
| + }
|
| +
|
| + if (metro_method != NULL)
|
| + return metro_method(ofn) == TRUE;
|
| +
|
| + NOTREACHED();
|
| +
|
| + return false;
|
| +}
|
| +
|
| +bool ShouldIsolateShellOperations() {
|
| + return base::FieldTrialList::FindFullName("IsolateShellOperations") ==
|
| + "Enabled";
|
| +}
|
| +
|
| // Receives the GetOpenFileName result from the utility process.
|
| class GetOpenFileNameClient : public content::UtilityProcessHostClient {
|
| public:
|
| @@ -117,7 +140,7 @@ void DoInvokeGetOpenFileName(
|
| utility_process_host->DisableSandbox();
|
| utility_process_host->Send(new ChromeUtilityMsg_GetOpenFileName(
|
| ofn->hwndOwner,
|
| - ofn->Flags,
|
| + ofn->Flags & ~OFN_ENABLEHOOK, // We can't send a hook function over IPC.
|
| ui::win::OpenFileName::GetFilters(ofn),
|
| base::FilePath(ofn->lpstrInitialDir ? ofn->lpstrInitialDir
|
| : base::string16()),
|
| @@ -149,28 +172,152 @@ bool GetOpenFileNameInUtilityProcess(
|
| bool GetOpenFileNameImpl(
|
| const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
|
| OPENFILENAME* ofn) {
|
| - HMODULE metro_module = base::win::GetMetroModule();
|
| - if (metro_module != NULL) {
|
| - typedef BOOL (*MetroGetOpenFileName)(OPENFILENAME*);
|
| - MetroGetOpenFileName metro_get_open_file_name =
|
| - reinterpret_cast<MetroGetOpenFileName>(
|
| - ::GetProcAddress(metro_module, "MetroGetOpenFileName"));
|
| - if (metro_get_open_file_name == NULL) {
|
| - NOTREACHED();
|
| - return false;
|
| - }
|
| -
|
| - return metro_get_open_file_name(ofn) == TRUE;
|
| - }
|
| + if (base::win::IsMetroProcess())
|
| + return CallMetroOPENFILENAMEMethod("MetroGetOpenFileName", ofn);
|
|
|
| - if (base::FieldTrialList::FindFullName("IsolateShellOperations") ==
|
| - "Enabled") {
|
| + if (ShouldIsolateShellOperations())
|
| return GetOpenFileNameInUtilityProcess(blocking_task_runner, ofn);
|
| - }
|
|
|
| return ::GetOpenFileName(ofn) == TRUE;
|
| }
|
|
|
| +class GetSaveFileNameClient : public content::UtilityProcessHostClient {
|
| + public:
|
| + GetSaveFileNameClient();
|
| +
|
| + // Blocks until the GetSaveFileName result is received (including failure to
|
| + // launch or a crash of the utility process).
|
| + void WaitForCompletion();
|
| +
|
| + // Returns the selected path.
|
| + const base::FilePath& path() const { return path_; }
|
| +
|
| + // Returns the index of the user-selected filter.
|
| + int one_based_filter_index() const { return one_based_filter_index_; }
|
| +
|
| + // UtilityProcessHostClient implementation
|
| + virtual void OnProcessCrashed(int exit_code) OVERRIDE;
|
| + virtual void OnProcessLaunchFailed() OVERRIDE;
|
| + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
|
| +
|
| + protected:
|
| + virtual ~GetSaveFileNameClient();
|
| +
|
| + private:
|
| + void OnResult(const base::FilePath& path, int one_based_filter_index);
|
| + void OnFailure();
|
| +
|
| + base::FilePath path_;
|
| + int one_based_filter_index_;
|
| + base::WaitableEvent event_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(GetSaveFileNameClient);
|
| +};
|
| +
|
| +GetSaveFileNameClient::GetSaveFileNameClient()
|
| + : event_(true, false), one_based_filter_index_(0) {
|
| +}
|
| +
|
| +void GetSaveFileNameClient::WaitForCompletion() {
|
| + event_.Wait();
|
| +}
|
| +
|
| +void GetSaveFileNameClient::OnProcessCrashed(int exit_code) {
|
| + event_.Signal();
|
| +}
|
| +
|
| +void GetSaveFileNameClient::OnProcessLaunchFailed() {
|
| + event_.Signal();
|
| +}
|
| +
|
| +bool GetSaveFileNameClient::OnMessageReceived(const IPC::Message& message) {
|
| + bool handled = true;
|
| + IPC_BEGIN_MESSAGE_MAP(GetSaveFileNameClient, message)
|
| + IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetSaveFileName_Failed,
|
| + OnFailure)
|
| + IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetSaveFileName_Result,
|
| + OnResult)
|
| + IPC_MESSAGE_UNHANDLED(handled = false)
|
| + IPC_END_MESSAGE_MAP()
|
| + return handled;
|
| +}
|
| +
|
| +GetSaveFileNameClient::~GetSaveFileNameClient() {}
|
| +
|
| +void GetSaveFileNameClient::OnResult(const base::FilePath& path,
|
| + int one_based_filter_index) {
|
| + path_ = path;
|
| + one_based_filter_index_ = one_based_filter_index;
|
| + event_.Signal();
|
| +}
|
| +
|
| +void GetSaveFileNameClient::OnFailure() {
|
| + event_.Signal();
|
| +}
|
| +
|
| +// Initiates IPC with a new utility process using |client|. Instructs the
|
| +// utility process to call GetSaveFileName with |ofn|. |current_task_runner|
|
| +// must be the currently executing task runner.
|
| +void DoInvokeGetSaveFileName(
|
| + OPENFILENAME* ofn,
|
| + scoped_refptr<GetSaveFileNameClient> client,
|
| + const scoped_refptr<base::SequencedTaskRunner>& current_task_runner) {
|
| + DCHECK(current_task_runner->RunsTasksOnCurrentThread());
|
| +
|
| + base::WeakPtr<content::UtilityProcessHost> utility_process_host(
|
| + content::UtilityProcessHost::Create(client, current_task_runner)
|
| + ->AsWeakPtr());
|
| + utility_process_host->DisableSandbox();
|
| + ChromeUtilityMsg_GetSaveFileName_Params params;
|
| + params.owner = ofn->hwndOwner;
|
| + // We can't pass the hook function over IPC.
|
| + params.flags = ofn->Flags & ~OFN_ENABLEHOOK;
|
| + params.filters = ui::win::OpenFileName::GetFilters(ofn);
|
| + params.one_based_filter_index = ofn->nFilterIndex;
|
| + params.suggested_filename = base::FilePath(ofn->lpstrFile);
|
| + params.initial_directory = base::FilePath(
|
| + ofn->lpstrInitialDir ? ofn->lpstrInitialDir : base::string16());
|
| + params.default_extension =
|
| + ofn->lpstrDefExt ? base::string16(ofn->lpstrDefExt) : base::string16();
|
| +
|
| + utility_process_host->Send(new ChromeUtilityMsg_GetSaveFileName(params));
|
| +}
|
| +
|
| +// Invokes GetSaveFileName in a utility process. Blocks until the result is
|
| +// received. Uses |blocking_task_runner| for IPC.
|
| +bool GetSaveFileNameInUtilityProcess(
|
| + const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
|
| + OPENFILENAME* ofn) {
|
| + scoped_refptr<GetSaveFileNameClient> client(new GetSaveFileNameClient);
|
| + blocking_task_runner->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&DoInvokeGetSaveFileName,
|
| + base::Unretained(ofn), client, blocking_task_runner));
|
| + client->WaitForCompletion();
|
| +
|
| + if (client->path().empty())
|
| + return false;
|
| +
|
| + base::wcslcpy(ofn->lpstrFile, client->path().value().c_str(), ofn->nMaxFile);
|
| + ofn->nFilterIndex = client->one_based_filter_index();
|
| +
|
| + return true;
|
| +}
|
| +
|
| +// Implements GetSaveFileName for CreateWinSelectFileDialog by delegating either
|
| +// to Metro or a utility process.
|
| +bool GetSaveFileNameImpl(
|
| + const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner,
|
| + OPENFILENAME* ofn) {
|
| + if (base::win::IsMetroProcess())
|
| + return CallMetroOPENFILENAMEMethod("MetroGetSaveFileName", ofn);
|
| +
|
| + if (ShouldIsolateShellOperations())
|
| + return GetSaveFileNameInUtilityProcess(blocking_task_runner, ofn);
|
| +
|
| + return ::GetSaveFileName(ofn) == TRUE;
|
| +}
|
| +
|
| } // namespace
|
|
|
| ChromeSelectFileDialogFactory::ChromeSelectFileDialogFactory(
|
| @@ -186,5 +333,6 @@ ui::SelectFileDialog* ChromeSelectFileDialogFactory::Create(
|
| return ui::CreateWinSelectFileDialog(
|
| listener,
|
| policy,
|
| - base::Bind(GetOpenFileNameImpl, blocking_task_runner_));
|
| + base::Bind(GetOpenFileNameImpl, blocking_task_runner_),
|
| + base::Bind(GetSaveFileNameImpl, blocking_task_runner_));
|
| }
|
|
|