Chromium Code Reviews| Index: ui/base/win/shell.cc |
| diff --git a/ui/base/win/shell.cc b/ui/base/win/shell.cc |
| index 9e47f8c94ac45f50bdeb8e5d0760135c87816198..12fe88d00faf7e2df7abc93ad165a82d96d70d48 100644 |
| --- a/ui/base/win/shell.cc |
| +++ b/ui/base/win/shell.cc |
| @@ -11,9 +11,11 @@ |
| #include "base/command_line.h" |
| #include "base/debug/alias.h" |
| +#include "base/files/file.h" |
| #include "base/files/file_path.h" |
| #include "base/native_library.h" |
| #include "base/strings/string_util.h" |
| +#include "base/threading/thread_restrictions.h" |
| #include "base/win/metro.h" |
| #include "base/win/scoped_comptr.h" |
| #include "base/win/win_util.h" |
| @@ -25,15 +27,39 @@ namespace win { |
| namespace { |
| -// Show the Windows "Open With" dialog box to ask the user to pick an app to |
| -// open the file with. |
| -bool OpenItemWithExternalApp(const base::string16& full_path) { |
| - SHELLEXECUTEINFO sei = { sizeof(sei) }; |
| - sei.fMask = SEE_MASK_FLAG_DDEWAIT; |
| +// Default ShellExecuteEx flags used with the "openas" verb. |
| +// |
| +// SEE_MASK_NOASYNC is specified so that ShellExecuteEx can be invoked from a |
| +// thread whose message loop may not wait around long enough for the |
| +// asynchronous tasks initiated by ShellExecuteEx to complete. Using this flag |
| +// causes ShellExecuteEx() to block until these tasks complete. |
| +const DWORD kDefaultOpenAsFlags = SEE_MASK_NOASYNC; |
| + |
| +// Default ShellExecuteEx flags used with the "explore", "open" or default verb. |
| +// |
| +// See kDefaultOpenFlags for description SEE_MASK_NOASYNC flag. |
| +// SEE_MASK_FLAG_NO_UI is used to suppress any error message boxes that might be |
| +// displayed if there is an error in opening the file. Failure in invoking the |
| +// "open" actions result in invocation of the "saveas" verb, making the error |
| +// dialog superfluous. |
| +const DWORD kDefaultOpenFlags = SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI; |
| + |
| +// Invokes ShellExecuteExW() with the given parameters. |
| +DWORD InvokeShellExecute(const base::string16 path, |
| + const base::string16 working_directory, |
| + const base::string16 args, |
| + const base::string16 verb, |
| + DWORD mask) { |
| + base::ThreadRestrictions::AssertIOAllowed(); |
| + SHELLEXECUTEINFO sei = {sizeof(sei)}; |
| + sei.fMask = mask; |
| sei.nShow = SW_SHOWNORMAL; |
| - sei.lpVerb = L"openas"; |
| - sei.lpFile = full_path.c_str(); |
| - return (TRUE == ::ShellExecuteExW(&sei)); |
| + sei.lpVerb = (verb.empty() ? NULL : verb.c_str()); |
|
sky
2015/03/06 18:21:33
nullptr evey where?
asanka
2015/03/06 21:09:40
Done.
|
| + sei.lpFile = path.c_str(); |
| + sei.lpDirectory = |
| + (working_directory.empty() ? NULL : working_directory.c_str()); |
| + sei.lpParameters = (args.empty() ? NULL : args.c_str()); |
| + return ::ShellExecuteExW(&sei) ? ERROR_SUCCESS : ::GetLastError(); |
| } |
| } // namespace |
| @@ -42,24 +68,32 @@ bool OpenAnyViaShell(const base::string16& full_path, |
| const base::string16& directory, |
| const base::string16& args, |
| DWORD mask) { |
| - SHELLEXECUTEINFO sei = { sizeof(sei) }; |
| - sei.fMask = mask; |
| - sei.nShow = SW_SHOWNORMAL; |
| - sei.lpFile = full_path.c_str(); |
| - sei.lpDirectory = directory.c_str(); |
| - if (!args.empty()) |
| - sei.lpParameters = args.c_str(); |
| - |
| - if (::ShellExecuteExW(&sei)) |
| + DWORD open_result = |
| + InvokeShellExecute(full_path, directory, args, base::string16(), mask); |
| + if (open_result == ERROR_SUCCESS) |
| return true; |
| - if (::GetLastError() == ERROR_NO_ASSOCIATION) |
| - return OpenItemWithExternalApp(full_path); |
| + // Show the Windows "Open With" dialog box to ask the user to pick an app to |
| + // open the file with. Note that we are not forwarding |args| for the "openas" |
| + // call since the target application is nolonger known at this point. |
| + if (open_result == ERROR_NO_ASSOCIATION) |
| + return InvokeShellExecute(full_path, directory, base::string16(), L"openas", |
| + kDefaultOpenAsFlags) == ERROR_SUCCESS; |
| return false; |
| } |
| -bool OpenItemViaShell(const base::FilePath& full_path) { |
| +bool OpenFileViaShell(const base::FilePath& full_path) { |
| return OpenAnyViaShell(full_path.value(), full_path.DirName().value(), |
| - base::string16(), 0); |
| + base::string16(), kDefaultOpenFlags); |
| +} |
| + |
| +bool OpenFolderViaShell(const base::FilePath& full_path) { |
| + // The "explore" verb causes the folder at |full_path| to be displayed in a |
| + // file browser. This will fail if |full_path| is not a directory. The |
| + // resulting error does not cause UI due to the SEE_MASK_FLAG_NO_UI flag in |
| + // kDefaultOpenFlags. |
| + return InvokeShellExecute(full_path.value(), full_path.value(), |
| + base::string16(), L"explore", |
| + kDefaultOpenFlags) == ERROR_SUCCESS; |
| } |
| bool PreventWindowFromPinning(HWND hwnd) { |