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