| 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 } |
| 213 | 235 |
| 214 } // namespace platform_util | 236 } // namespace platform_util |
| OLD | NEW |