OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/platform_util.h" | 5 #include "chrome/browser/platform_util.h" |
6 | 6 |
7 #include <commdlg.h> | 7 #include <commdlg.h> |
8 #include <dwmapi.h> | 8 #include <dwmapi.h> |
9 #include <shellapi.h> | 9 #include <shellapi.h> |
10 #include <shlobj.h> | 10 #include <shlobj.h> |
11 | 11 |
12 #include "base/bind.h" | 12 #include "base/bind.h" |
13 #include "base/bind_helpers.h" | 13 #include "base/bind_helpers.h" |
14 #include "base/files/file_path.h" | 14 #include "base/files/file_path.h" |
| 15 #include "base/files/file_util.h" |
15 #include "base/logging.h" | 16 #include "base/logging.h" |
16 #include "base/metrics/field_trial.h" | 17 #include "base/metrics/field_trial.h" |
17 #include "base/strings/string_util.h" | 18 #include "base/strings/string_util.h" |
18 #include "base/strings/utf_string_conversions.h" | 19 #include "base/strings/utf_string_conversions.h" |
19 #include "base/win/registry.h" | 20 #include "base/win/registry.h" |
20 #include "base/win/scoped_co_mem.h" | 21 #include "base/win/scoped_co_mem.h" |
21 #include "base/win/scoped_comptr.h" | 22 #include "base/win/scoped_comptr.h" |
22 #include "base/win/windows_version.h" | 23 #include "base/win/windows_version.h" |
23 #include "chrome/browser/lifetime/application_lifetime.h" | 24 #include "chrome/browser/lifetime/application_lifetime.h" |
| 25 #include "chrome/browser/platform_util_internal.h" |
24 #include "chrome/browser/ui/host_desktop.h" | 26 #include "chrome/browser/ui/host_desktop.h" |
25 #include "chrome/common/chrome_utility_messages.h" | 27 #include "chrome/common/chrome_utility_messages.h" |
26 #include "content/public/browser/browser_thread.h" | 28 #include "content/public/browser/browser_thread.h" |
27 #include "content/public/browser/utility_process_host.h" | 29 #include "content/public/browser/utility_process_host.h" |
28 #include "content/public/browser/utility_process_host_client.h" | 30 #include "content/public/browser/utility_process_host_client.h" |
29 #include "ui/base/win/shell.h" | 31 #include "ui/base/win/shell.h" |
30 #include "ui/gfx/native_widget_types.h" | 32 #include "ui/gfx/native_widget_types.h" |
31 #include "url/gurl.h" | 33 #include "url/gurl.h" |
32 | 34 |
33 using content::BrowserThread; | 35 using content::BrowserThread; |
34 | 36 |
| 37 namespace platform_util { |
| 38 |
35 namespace { | 39 namespace { |
36 | 40 |
| 41 // TODO(asanka): Move this to ui/base/win/shell.{h,cc} and invoke it from the |
| 42 // utility process. |
37 void ShowItemInFolderOnFileThread(const base::FilePath& full_path) { | 43 void ShowItemInFolderOnFileThread(const base::FilePath& full_path) { |
38 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 44 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
39 base::FilePath dir = full_path.DirName().AsEndingWithSeparator(); | 45 base::FilePath dir = full_path.DirName().AsEndingWithSeparator(); |
40 // ParseDisplayName will fail if the directory is "C:", it must be "C:\\". | 46 // ParseDisplayName will fail if the directory is "C:", it must be "C:\\". |
41 if (dir.empty()) | 47 if (dir.empty()) |
42 return; | 48 return; |
43 | 49 |
44 typedef HRESULT (WINAPI *SHOpenFolderAndSelectItemsFuncPtr)( | 50 typedef HRESULT (WINAPI *SHOpenFolderAndSelectItemsFuncPtr)( |
45 PCIDLIST_ABSOLUTE pidl_Folder, | 51 PCIDLIST_ABSOLUTE pidl_Folder, |
46 UINT cidl, | 52 UINT cidl, |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
95 hr = (*open_folder_and_select_itemsPtr)(dir_item, arraysize(highlight), | 101 hr = (*open_folder_and_select_itemsPtr)(dir_item, arraysize(highlight), |
96 highlight, NULL); | 102 highlight, NULL); |
97 | 103 |
98 if (FAILED(hr)) { | 104 if (FAILED(hr)) { |
99 // On some systems, the above call mysteriously fails with "file not | 105 // On some systems, the above call mysteriously fails with "file not |
100 // found" even though the file is there. In these cases, ShellExecute() | 106 // found" even though the file is there. In these cases, ShellExecute() |
101 // seems to work as a fallback (although it won't select the file). | 107 // seems to work as a fallback (although it won't select the file). |
102 if (hr == ERROR_FILE_NOT_FOUND) { | 108 if (hr == ERROR_FILE_NOT_FOUND) { |
103 ShellExecute(NULL, L"open", dir.value().c_str(), NULL, NULL, SW_SHOW); | 109 ShellExecute(NULL, L"open", dir.value().c_str(), NULL, NULL, SW_SHOW); |
104 } else { | 110 } else { |
105 LOG(WARNING) << " " << __FUNCTION__ | 111 LOG(WARNING) << " " << __FUNCTION__ << "(): Can't open full_path = \"" |
106 << "(): Can't open full_path = \"" | |
107 << full_path.value() << "\"" | 112 << full_path.value() << "\"" |
108 << " hr = " << logging::SystemErrorCodeToString(hr); | 113 << " hr = " << logging::SystemErrorCodeToString(hr); |
109 } | 114 } |
110 } | 115 } |
111 } | 116 } |
112 | 117 |
113 // Old ShellExecute crashes the process when the command for a given scheme | 118 // Old ShellExecute crashes the process when the command for a given scheme |
114 // is empty. This function tells if it is. | 119 // is empty. This function tells if it is. |
115 bool ValidateShellCommandForScheme(const std::string& scheme) { | 120 bool ValidateShellCommandForScheme(const std::string& scheme) { |
116 base::win::RegKey key; | 121 base::win::RegKey key; |
117 base::string16 registry_path = base::ASCIIToUTF16(scheme) + | 122 base::string16 registry_path = base::ASCIIToUTF16(scheme) + |
118 L"\\shell\\open\\command"; | 123 L"\\shell\\open\\command"; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
152 if (reinterpret_cast<ULONG_PTR>(ShellExecuteA(NULL, "open", | 157 if (reinterpret_cast<ULONG_PTR>(ShellExecuteA(NULL, "open", |
153 escaped_url.c_str(), NULL, NULL, | 158 escaped_url.c_str(), NULL, NULL, |
154 SW_SHOWNORMAL)) <= 32) { | 159 SW_SHOWNORMAL)) <= 32) { |
155 // We fail to execute the call. We could display a message to the user. | 160 // We fail to execute the call. We could display a message to the user. |
156 // TODO(nsylvain): we should also add a dialog to warn on errors. See | 161 // TODO(nsylvain): we should also add a dialog to warn on errors. See |
157 // bug 1136923. | 162 // bug 1136923. |
158 return; | 163 return; |
159 } | 164 } |
160 } | 165 } |
161 | 166 |
162 void OpenItemViaShellInUtilityProcess(const base::FilePath& full_path) { | 167 void OpenItemViaShellInUtilityProcess(const base::FilePath& full_path, |
| 168 OpenItemType type) { |
163 base::WeakPtr<content::UtilityProcessHost> utility_process_host( | 169 base::WeakPtr<content::UtilityProcessHost> utility_process_host( |
164 content::UtilityProcessHost::Create(NULL, NULL)->AsWeakPtr()); | 170 content::UtilityProcessHost::Create(NULL, NULL)->AsWeakPtr()); |
165 utility_process_host->DisableSandbox(); | 171 utility_process_host->DisableSandbox(); |
166 utility_process_host->Send(new ChromeUtilityMsg_OpenItemViaShell(full_path)); | 172 switch (type) { |
| 173 case OPEN_FILE: |
| 174 utility_process_host->Send( |
| 175 new ChromeUtilityMsg_OpenFileViaShell(full_path)); |
| 176 return; |
| 177 |
| 178 case OPEN_FOLDER: |
| 179 utility_process_host->Send( |
| 180 new ChromeUtilityMsg_OpenFolderViaShell(full_path)); |
| 181 return; |
| 182 } |
| 183 } |
| 184 |
| 185 void ActivateDesktopIfNecessary() { |
| 186 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 187 if (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH) |
| 188 chrome::ActivateDesktopHelper(chrome::ASH_KEEP_RUNNING); |
167 } | 189 } |
168 | 190 |
169 } // namespace | 191 } // namespace |
170 | 192 |
171 namespace platform_util { | |
172 | |
173 void ShowItemInFolder(Profile* profile, const base::FilePath& full_path) { | 193 void ShowItemInFolder(Profile* profile, const base::FilePath& full_path) { |
174 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 194 ActivateDesktopIfNecessary(); |
175 | |
176 if (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH) | |
177 chrome::ActivateDesktopHelper(chrome::ASH_KEEP_RUNNING); | |
178 | |
179 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | 195 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
180 base::Bind(&ShowItemInFolderOnFileThread, full_path)); | 196 base::Bind(&ShowItemInFolderOnFileThread, full_path)); |
181 } | 197 } |
182 | 198 |
183 void OpenItem(Profile* profile, const base::FilePath& full_path) { | 199 namespace internal { |
184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
185 | 200 |
186 if (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH) | 201 void PlatformOpenVerifiedItem(const base::FilePath& path, OpenItemType type) { |
187 chrome::ActivateDesktopHelper(chrome::ASH_KEEP_RUNNING); | 202 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 203 base::Bind(&ActivateDesktopIfNecessary)); |
188 | 204 |
189 if (base::FieldTrialList::FindFullName("IsolateShellOperations") == | 205 if (base::FieldTrialList::FindFullName("IsolateShellOperations") == |
190 "Enabled") { | 206 "Enabled") { |
191 BrowserThread::PostTask( | 207 BrowserThread::PostTask( |
192 BrowserThread::IO, | 208 BrowserThread::IO, FROM_HERE, |
193 FROM_HERE, | 209 base::Bind(&OpenItemViaShellInUtilityProcess, path, type)); |
194 base::Bind(&OpenItemViaShellInUtilityProcess, full_path)); | |
195 } else { | 210 } else { |
196 BrowserThread::PostTask( | 211 switch (type) { |
197 BrowserThread::FILE, | 212 case OPEN_FILE: |
198 FROM_HERE, | 213 ui::win::OpenFileViaShell(path); |
199 base::Bind(base::IgnoreResult(&ui::win::OpenItemViaShell), full_path)); | 214 break; |
| 215 |
| 216 case OPEN_FOLDER: |
| 217 ui::win::OpenFolderViaShell(path); |
| 218 break; |
| 219 } |
200 } | 220 } |
201 } | 221 } |
202 | 222 |
| 223 } // namespace internal |
| 224 |
203 void OpenExternal(Profile* profile, const GURL& url) { | 225 void OpenExternal(Profile* profile, const GURL& url) { |
204 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 226 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
205 | 227 |
206 if (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH && | 228 if (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH && |
207 !url.SchemeIsHTTPOrHTTPS()) | 229 !url.SchemeIsHTTPOrHTTPS()) |
208 chrome::ActivateDesktopHelper(chrome::ASH_KEEP_RUNNING); | 230 chrome::ActivateDesktopHelper(chrome::ASH_KEEP_RUNNING); |
209 | 231 |
210 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | 232 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
211 base::Bind(&OpenExternalOnFileThread, url)); | 233 base::Bind(&OpenExternalOnFileThread, url)); |
212 } | 234 } |
(...skipping 15 matching lines...) Expand all Loading... |
228 ::SetForegroundWindow(window); | 250 ::SetForegroundWindow(window); |
229 } | 251 } |
230 | 252 |
231 bool IsVisible(gfx::NativeView view) { | 253 bool IsVisible(gfx::NativeView view) { |
232 // MSVC complains if we don't include != 0. | 254 // MSVC complains if we don't include != 0. |
233 return ::IsWindowVisible(view) != 0; | 255 return ::IsWindowVisible(view) != 0; |
234 } | 256 } |
235 #endif | 257 #endif |
236 | 258 |
237 } // namespace platform_util | 259 } // namespace platform_util |
OLD | NEW |