| 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_));
 | 
|  }
 | 
| 
 |