16e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 26e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 36e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// found in the LICENSE file. 46e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 56e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/chrome_select_file_dialog_factory_win.h" 66e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 76e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include <Windows.h> 86e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include <commdlg.h> 96e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/bind.h" 116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/bind_helpers.h" 126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/callback.h" 136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/location.h" 146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/logging.h" 156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/metrics/field_trial.h" 166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/strings/string16.h" 176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/synchronization/waitable_event.h" 186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/win/metro.h" 196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/common/chrome_utility_messages.h" 206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "content/public/browser/utility_process_host.h" 216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "content/public/browser/utility_process_host_client.h" 226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "ipc/ipc_message_macros.h" 236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "ui/base/win/open_file_name_win.h" 246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "ui/shell_dialogs/select_file_dialog_win.h" 256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)namespace { 276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool CallMetroOPENFILENAMEMethod(const char* method_name, OPENFILENAME* ofn) { 2903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) typedef BOOL (*MetroOPENFILENAMEMethod)(OPENFILENAME*); 3003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) MetroOPENFILENAMEMethod metro_method = NULL; 3103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) HMODULE metro_module = base::win::GetMetroModule(); 3203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 3303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (metro_module != NULL) { 3403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) metro_method = reinterpret_cast<MetroOPENFILENAMEMethod>( 3503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) ::GetProcAddress(metro_module, method_name)); 3603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 3703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 3803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (metro_method != NULL) 3903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return metro_method(ofn) == TRUE; 4003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 4103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) NOTREACHED(); 4203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 4303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return false; 4403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)} 4503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 4603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool ShouldIsolateShellOperations() { 4703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return base::FieldTrialList::FindFullName("IsolateShellOperations") == 4803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) "Enabled"; 4903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)} 5003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Receives the GetOpenFileName result from the utility process. 526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)class GetOpenFileNameClient : public content::UtilityProcessHostClient { 536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) public: 546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) GetOpenFileNameClient(); 556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Blocks until the GetOpenFileName result is received (including failure to 576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // launch or a crash of the utility process). 586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) void WaitForCompletion(); 596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Returns the selected directory. 616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const base::FilePath& directory() const { return directory_; } 626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Returns the list of selected filenames. Each should be interpreted as a 646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // child of directory(). 656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const std::vector<base::FilePath>& filenames() const { return filenames_; } 666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // UtilityProcessHostClient implementation 686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) virtual void OnProcessCrashed(int exit_code) OVERRIDE; 696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) virtual void OnProcessLaunchFailed() OVERRIDE; 706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; 716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) protected: 736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) virtual ~GetOpenFileNameClient(); 746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) private: 766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) void OnResult(const base::FilePath& directory, 776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const std::vector<base::FilePath>& filenames); 786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) void OnFailure(); 796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) base::FilePath directory_; 816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) std::vector<base::FilePath> filenames_; 826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) base::WaitableEvent event_; 836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(GetOpenFileNameClient); 856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}; 866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)GetOpenFileNameClient::GetOpenFileNameClient() : event_(true, false) { 886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void GetOpenFileNameClient::WaitForCompletion() { 916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) event_.Wait(); 926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void GetOpenFileNameClient::OnProcessCrashed(int exit_code) { 956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) event_.Signal(); 966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void GetOpenFileNameClient::OnProcessLaunchFailed() { 996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) event_.Signal(); 1006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool GetOpenFileNameClient::OnMessageReceived(const IPC::Message& message) { 1036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) bool handled = true; 1046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) IPC_BEGIN_MESSAGE_MAP(GetOpenFileNameClient, message) 1056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetOpenFileName_Failed, 1066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) OnFailure) 1076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetOpenFileName_Result, 1086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) OnResult) 1096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) IPC_MESSAGE_UNHANDLED(handled = false) 1106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) IPC_END_MESSAGE_MAP() 1116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return handled; 1126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)GetOpenFileNameClient::~GetOpenFileNameClient() {} 1156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void GetOpenFileNameClient::OnResult( 1176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const base::FilePath& directory, 1186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const std::vector<base::FilePath>& filenames) { 1196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) directory_ = directory; 1206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) filenames_ = filenames; 1216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) event_.Signal(); 1226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void GetOpenFileNameClient::OnFailure() { 1256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) event_.Signal(); 1266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Initiates IPC with a new utility process using |client|. Instructs the 1296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// utility process to call GetOpenFileName with |ofn|. |current_task_runner| 1306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// must be the currently executing task runner. 1316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void DoInvokeGetOpenFileName( 1326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) OPENFILENAME* ofn, 1336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) scoped_refptr<GetOpenFileNameClient> client, 1346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const scoped_refptr<base::SequencedTaskRunner>& current_task_runner) { 1356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) DCHECK(current_task_runner->RunsTasksOnCurrentThread()); 1366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) base::WeakPtr<content::UtilityProcessHost> utility_process_host( 1386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) content::UtilityProcessHost::Create(client, current_task_runner) 1396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ->AsWeakPtr()); 1406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) utility_process_host->DisableSandbox(); 1416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) utility_process_host->Send(new ChromeUtilityMsg_GetOpenFileName( 1426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ofn->hwndOwner, 14303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) ofn->Flags & ~OFN_ENABLEHOOK, // We can't send a hook function over IPC. 1446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ui::win::OpenFileName::GetFilters(ofn), 1456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) base::FilePath(ofn->lpstrInitialDir ? ofn->lpstrInitialDir 1466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) : base::string16()), 1476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) base::FilePath(ofn->lpstrFile))); 1486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Invokes GetOpenFileName in a utility process. Blocks until the result is 1516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// received. Uses |blocking_task_runner| for IPC. 1526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool GetOpenFileNameInUtilityProcess( 1536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner, 1546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) OPENFILENAME* ofn) { 1556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) scoped_refptr<GetOpenFileNameClient> client(new GetOpenFileNameClient); 1566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) blocking_task_runner->PostTask( 1576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) FROM_HERE, 1586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) base::Bind(&DoInvokeGetOpenFileName, 1596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) base::Unretained(ofn), client, blocking_task_runner)); 1606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) client->WaitForCompletion(); 1616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (!client->filenames().size()) 1636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return false; 1646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ui::win::OpenFileName::SetResult( 1666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) client->directory(), client->filenames(), ofn); 1676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return true; 1686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Implements GetOpenFileName for CreateWinSelectFileDialog by delegating either 1716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// to Metro or a utility process. 1726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool GetOpenFileNameImpl( 1736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner, 1746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) OPENFILENAME* ofn) { 17503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (base::win::IsMetroProcess()) 17603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return CallMetroOPENFILENAMEMethod("MetroGetOpenFileName", ofn); 1776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 17803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (ShouldIsolateShellOperations()) 1796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return GetOpenFileNameInUtilityProcess(blocking_task_runner, ofn); 1806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return ::GetOpenFileName(ofn) == TRUE; 1826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 18403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)class GetSaveFileNameClient : public content::UtilityProcessHostClient { 18503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) public: 18603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) GetSaveFileNameClient(); 18703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 18803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) // Blocks until the GetSaveFileName result is received (including failure to 18903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) // launch or a crash of the utility process). 19003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) void WaitForCompletion(); 19103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 19203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) // Returns the selected path. 19303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) const base::FilePath& path() const { return path_; } 19403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 19503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) // Returns the index of the user-selected filter. 19603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) int one_based_filter_index() const { return one_based_filter_index_; } 19703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 19803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) // UtilityProcessHostClient implementation 19903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) virtual void OnProcessCrashed(int exit_code) OVERRIDE; 20003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) virtual void OnProcessLaunchFailed() OVERRIDE; 20103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; 20203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 20303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) protected: 20403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) virtual ~GetSaveFileNameClient(); 20503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 20603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) private: 20703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) void OnResult(const base::FilePath& path, int one_based_filter_index); 20803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) void OnFailure(); 20903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 21003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) base::FilePath path_; 21103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) int one_based_filter_index_; 21203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) base::WaitableEvent event_; 21303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 21403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(GetSaveFileNameClient); 21503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}; 21603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 21703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)GetSaveFileNameClient::GetSaveFileNameClient() 21803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) : event_(true, false), one_based_filter_index_(0) { 21903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)} 22003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 22103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void GetSaveFileNameClient::WaitForCompletion() { 22203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) event_.Wait(); 22303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)} 22403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 22503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void GetSaveFileNameClient::OnProcessCrashed(int exit_code) { 22603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) event_.Signal(); 22703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)} 22803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 22903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void GetSaveFileNameClient::OnProcessLaunchFailed() { 23003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) event_.Signal(); 23103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)} 23203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 23303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool GetSaveFileNameClient::OnMessageReceived(const IPC::Message& message) { 23403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) bool handled = true; 23503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) IPC_BEGIN_MESSAGE_MAP(GetSaveFileNameClient, message) 23603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetSaveFileName_Failed, 23703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) OnFailure) 23803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetSaveFileName_Result, 23903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) OnResult) 24003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) IPC_MESSAGE_UNHANDLED(handled = false) 24103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) IPC_END_MESSAGE_MAP() 24203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return handled; 24303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)} 24403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 24503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)GetSaveFileNameClient::~GetSaveFileNameClient() {} 24603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 24703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void GetSaveFileNameClient::OnResult(const base::FilePath& path, 24803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) int one_based_filter_index) { 24903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) path_ = path; 25003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) one_based_filter_index_ = one_based_filter_index; 25103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) event_.Signal(); 25203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)} 25303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 25403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void GetSaveFileNameClient::OnFailure() { 25503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) event_.Signal(); 25603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)} 25703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 25803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Initiates IPC with a new utility process using |client|. Instructs the 25903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// utility process to call GetSaveFileName with |ofn|. |current_task_runner| 26003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// must be the currently executing task runner. 26103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void DoInvokeGetSaveFileName( 26203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) OPENFILENAME* ofn, 26303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) scoped_refptr<GetSaveFileNameClient> client, 26403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) const scoped_refptr<base::SequencedTaskRunner>& current_task_runner) { 26503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) DCHECK(current_task_runner->RunsTasksOnCurrentThread()); 26603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 26703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) base::WeakPtr<content::UtilityProcessHost> utility_process_host( 26803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) content::UtilityProcessHost::Create(client, current_task_runner) 26903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) ->AsWeakPtr()); 27003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) utility_process_host->DisableSandbox(); 27103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) ChromeUtilityMsg_GetSaveFileName_Params params; 27203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) params.owner = ofn->hwndOwner; 27303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) // We can't pass the hook function over IPC. 27403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) params.flags = ofn->Flags & ~OFN_ENABLEHOOK; 27503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) params.filters = ui::win::OpenFileName::GetFilters(ofn); 27603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) params.one_based_filter_index = ofn->nFilterIndex; 27703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) params.suggested_filename = base::FilePath(ofn->lpstrFile); 27803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) params.initial_directory = base::FilePath( 27903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) ofn->lpstrInitialDir ? ofn->lpstrInitialDir : base::string16()); 28003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) params.default_extension = 28103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) ofn->lpstrDefExt ? base::string16(ofn->lpstrDefExt) : base::string16(); 28203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 28303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) utility_process_host->Send(new ChromeUtilityMsg_GetSaveFileName(params)); 28403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)} 28503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 28603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Invokes GetSaveFileName in a utility process. Blocks until the result is 28703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// received. Uses |blocking_task_runner| for IPC. 28803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool GetSaveFileNameInUtilityProcess( 28903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner, 29003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) OPENFILENAME* ofn) { 29103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) scoped_refptr<GetSaveFileNameClient> client(new GetSaveFileNameClient); 29203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) blocking_task_runner->PostTask( 29303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) FROM_HERE, 29403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) base::Bind(&DoInvokeGetSaveFileName, 29503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) base::Unretained(ofn), client, blocking_task_runner)); 29603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) client->WaitForCompletion(); 29703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 29803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (client->path().empty()) 29903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return false; 30003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 30103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) base::wcslcpy(ofn->lpstrFile, client->path().value().c_str(), ofn->nMaxFile); 30203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) ofn->nFilterIndex = client->one_based_filter_index(); 30303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 30403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return true; 30503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)} 30603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 30703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Implements GetSaveFileName for CreateWinSelectFileDialog by delegating either 30803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// to Metro or a utility process. 30903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool GetSaveFileNameImpl( 31003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner, 31103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) OPENFILENAME* ofn) { 31203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (base::win::IsMetroProcess()) 31303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return CallMetroOPENFILENAMEMethod("MetroGetSaveFileName", ofn); 31403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 31503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (ShouldIsolateShellOperations()) 31603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return GetSaveFileNameInUtilityProcess(blocking_task_runner, ofn); 31703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 31803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return ::GetSaveFileName(ofn) == TRUE; 31903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)} 32003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 3216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} // namespace 3226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 3236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)ChromeSelectFileDialogFactory::ChromeSelectFileDialogFactory( 3246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner) 3256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) : blocking_task_runner_(blocking_task_runner) { 3266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 3276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 3286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)ChromeSelectFileDialogFactory::~ChromeSelectFileDialogFactory() {} 3296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 3306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)ui::SelectFileDialog* ChromeSelectFileDialogFactory::Create( 3316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ui::SelectFileDialog::Listener* listener, 3326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ui::SelectFilePolicy* policy) { 3336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return ui::CreateWinSelectFileDialog( 3346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) listener, 3356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) policy, 33603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) base::Bind(GetOpenFileNameImpl, blocking_task_runner_), 33703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) base::Bind(GetSaveFileNameImpl, blocking_task_runner_)); 3386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 339