OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/chrome_select_file_dialog_factory_win.h" | |
6 | |
7 #include <Windows.h> | |
8 #include <commdlg.h> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/bind_helpers.h" | |
12 #include "base/callback.h" | |
13 #include "base/location.h" | |
14 #include "base/logging.h" | |
15 #include "base/metrics/field_trial.h" | |
16 #include "base/strings/string16.h" | |
17 #include "base/synchronization/waitable_event.h" | |
18 #include "base/win/metro.h" | |
19 #include "chrome/common/chrome_utility_messages.h" | |
20 #include "content/public/browser/utility_process_host.h" | |
21 #include "content/public/browser/utility_process_host_client.h" | |
22 #include "ipc/ipc_message_macros.h" | |
23 #include "ui/base/win/open_file_name_win.h" | |
24 #include "ui/shell_dialogs/select_file_dialog_win.h" | |
25 | |
26 namespace { | |
27 | |
28 // Receives the GetOpenFileName result from the utility process. | |
29 class GetOpenFileNameClient : public content::UtilityProcessHostClient { | |
30 public: | |
31 GetOpenFileNameClient(); | |
32 | |
33 // Blocks until the GetOpenFileName result is received (including failure to | |
34 // launch or a crash of the utility process). | |
35 void WaitForCompletion(); | |
36 | |
37 // Returns the selected directory. | |
38 const base::FilePath& directory() { return directory_; } | |
sky
2014/07/31 20:47:46
make const.
erikwright (departed)
2014/08/01 13:53:15
Done.
| |
39 | |
40 // Returns the list of selected filenames. Each should be interpreted as a | |
41 // child of directory(). | |
42 const std::vector<base::FilePath>& filenames() { return filenames_; } | |
sky
2014/07/31 20:47:46
make const
erikwright (departed)
2014/08/01 13:53:15
Done.
| |
43 | |
44 // UtilityProcessHostClient implementation | |
45 virtual void OnProcessCrashed(int exit_code) OVERRIDE; | |
46 virtual void OnProcessLaunchFailed() OVERRIDE; | |
47 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; | |
48 | |
49 protected: | |
50 virtual ~GetOpenFileNameClient(); | |
51 | |
52 private: | |
53 void OnResult(const base::FilePath& directory, | |
54 const std::vector<base::FilePath>& filenames); | |
55 void OnFailure(); | |
56 | |
57 base::FilePath directory_; | |
58 std::vector<base::FilePath> filenames_; | |
59 base::WaitableEvent event_; | |
60 | |
61 DISALLOW_COPY_AND_ASSIGN(GetOpenFileNameClient); | |
62 }; | |
63 | |
64 GetOpenFileNameClient::GetOpenFileNameClient() : event_(true, false) { | |
65 } | |
66 | |
67 GetOpenFileNameClient::~GetOpenFileNameClient() {} | |
sky
2014/07/31 20:47:46
declaration/definition order should match.
erikwright (departed)
2014/08/01 13:53:15
Done.
| |
68 | |
69 void GetOpenFileNameClient::WaitForCompletion() { | |
70 event_.Wait(); | |
71 } | |
72 | |
73 void GetOpenFileNameClient::OnProcessCrashed(int exit_code) { | |
74 event_.Signal(); | |
75 } | |
76 | |
77 void GetOpenFileNameClient::OnProcessLaunchFailed() { | |
78 event_.Signal(); | |
79 } | |
80 | |
81 bool GetOpenFileNameClient::OnMessageReceived(const IPC::Message& message) { | |
82 bool handled = true; | |
83 IPC_BEGIN_MESSAGE_MAP(GetOpenFileNameClient, message) | |
84 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetOpenFileName_Failed, | |
85 OnFailure) | |
86 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetOpenFileName_Result, | |
87 OnResult) | |
88 IPC_MESSAGE_UNHANDLED(handled = false) | |
89 IPC_END_MESSAGE_MAP() | |
90 return handled; | |
91 } | |
92 | |
93 void GetOpenFileNameClient::OnResult(const base::FilePath& directory, | |
94 const std::vector<base::FilePath> & | |
sky
2014/07/31 20:47:46
wrapping here is weird. & should be next to >
erikwright (departed)
2014/08/01 13:53:15
Done.
| |
95 filenames) { | |
96 directory_ = directory; | |
97 filenames_ = filenames; | |
98 event_.Signal(); | |
99 } | |
100 | |
101 void GetOpenFileNameClient::OnFailure() { | |
102 event_.Signal(); | |
103 } | |
104 | |
105 // Initiates IPC with a new utility process using |client|. Instructs the | |
106 // utility process to call GetOpenFileName with |ofn|. |current_task_runner| | |
107 // must be the currently executing task runner. | |
108 void DoInvokeGetOpenFileName( | |
109 OPENFILENAME* ofn, | |
110 scoped_refptr<GetOpenFileNameClient> client, | |
111 const scoped_refptr<base::SequencedTaskRunner>& current_task_runner) { | |
112 DCHECK(current_task_runner->RunsTasksOnCurrentThread()); | |
113 | |
114 base::WeakPtr<content::UtilityProcessHost> utility_process_host( | |
115 content::UtilityProcessHost::Create(client, current_task_runner) | |
116 ->AsWeakPtr()); | |
117 utility_process_host->DisableSandbox(); | |
118 utility_process_host->Send(new ChromeUtilityMsg_GetOpenFileName( | |
119 ofn->hwndOwner, | |
120 ofn->Flags, | |
121 ui::win::OpenFileName::GetFilters(ofn), | |
122 base::FilePath(ofn->lpstrInitialDir ? ofn->lpstrInitialDir : L""), | |
sky
2014/07/31 20:47:46
""->std::wstring or string16.
erikwright (departed)
2014/08/01 13:53:15
Done.
| |
123 base::FilePath(ofn->lpstrFile))); | |
124 } | |
125 | |
126 // Invokes GetOpenFileName in a utility process. Blocks until the result is | |
127 // received. Uses |blocking_task_runner| for IPC. | |
128 bool GetOpenFileNameInUtilityProcess( | |
129 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner, | |
130 OPENFILENAME* ofn) { | |
131 scoped_refptr<GetOpenFileNameClient> client(new GetOpenFileNameClient); | |
132 blocking_task_runner->PostTask( | |
133 FROM_HERE, | |
134 base::Bind(&DoInvokeGetOpenFileName, | |
135 base::Unretained(ofn), client, blocking_task_runner)); | |
136 client->WaitForCompletion(); | |
137 | |
138 if (!client->filenames().size()) | |
139 return false; | |
140 | |
141 ui::win::OpenFileName::SetResult( | |
142 client->directory(), client->filenames(), ofn); | |
143 return true; | |
144 } | |
145 | |
146 // Implements GetOpenFileName for CreateWinSelectFileDialog by delegating either | |
147 // to Metro or a utility process. | |
148 bool GetOpenFileNameImpl( | |
149 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner, | |
150 OPENFILENAME* ofn) { | |
151 HMODULE metro_module = base::win::GetMetroModule(); | |
152 if (metro_module != NULL) { | |
153 typedef BOOL (*MetroGetOpenFileName)(OPENFILENAME*); | |
154 MetroGetOpenFileName metro_get_open_file_name = | |
155 reinterpret_cast<MetroGetOpenFileName>( | |
156 ::GetProcAddress(metro_module, "MetroGetOpenFileName")); | |
157 if (metro_get_open_file_name == NULL) { | |
158 NOTREACHED(); | |
159 return false; | |
160 } | |
161 | |
162 return metro_get_open_file_name(ofn) == TRUE; | |
163 } else if (base::FieldTrialList::FindFullName("IsolateShellOperations") == | |
sky
2014/07/31 20:47:46
nit: no else after return here and 166.
erikwright (departed)
2014/08/01 13:53:15
Done.
| |
164 "Enabled") { | |
165 return GetOpenFileNameInUtilityProcess(blocking_task_runner, ofn); | |
166 } else { | |
167 return ::GetOpenFileName(ofn) == TRUE; | |
168 } | |
169 } | |
170 | |
171 } // namespace | |
172 | |
173 ChromeSelectFileDialogFactory::ChromeSelectFileDialogFactory( | |
174 const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner) | |
175 : blocking_task_runner_(blocking_task_runner) { | |
176 } | |
177 | |
178 ChromeSelectFileDialogFactory::~ChromeSelectFileDialogFactory() {} | |
179 | |
180 ui::SelectFileDialog* ChromeSelectFileDialogFactory::Create( | |
181 ui::SelectFileDialog::Listener* listener, | |
182 ui::SelectFilePolicy* policy) { | |
183 return ui::CreateWinSelectFileDialog( | |
184 listener, | |
185 policy, | |
186 base::Bind(GetOpenFileNameImpl, blocking_task_runner_)); | |
187 } | |
OLD | NEW |