Index: ui/base/win/shell.cc |
diff --git a/ui/base/win/shell.cc b/ui/base/win/shell.cc |
index 9e47f8c94ac45f50bdeb8e5d0760135c87816198..2a5bd29798da5b9ec878477e1007f07a87eb5c08 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() ? nullptr : verb.c_str()); |
+ sei.lpFile = path.c_str(); |
+ sei.lpDirectory = |
+ (working_directory.empty() ? nullptr : working_directory.c_str()); |
+ sei.lpParameters = (args.empty() ? nullptr : 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) { |