Index: chrome/browser/web_applications/web_app_win.cc |
diff --git a/chrome/browser/web_applications/web_app_win.cc b/chrome/browser/web_applications/web_app_win.cc |
index 5701e5333ef80f94dde69d03af5b7db6c76558c1..a393a2039f488e60a05aeb0f78f22b4e19ace5fc 100644 |
--- a/chrome/browser/web_applications/web_app_win.cc |
+++ b/chrome/browser/web_applications/web_app_win.cc |
@@ -12,17 +12,22 @@ |
#include "base/logging.h" |
#include "base/md5.h" |
#include "base/path_service.h" |
+#include "base/strings/string16.h" |
#include "base/strings/string_piece.h" |
#include "base/strings/stringprintf.h" |
#include "base/strings/utf_string_conversions.h" |
#include "base/win/shortcut.h" |
#include "base/win/windows_version.h" |
+#include "chrome/browser/profiles/profile.h" |
#include "chrome/browser/web_applications/update_shortcut_worker_win.h" |
#include "chrome/common/chrome_switches.h" |
#include "chrome/installer/util/browser_distribution.h" |
+#include "chrome/installer/util/install_util.h" |
#include "chrome/installer/util/shell_util.h" |
#include "chrome/installer/util/util_constants.h" |
#include "content/public/browser/browser_thread.h" |
+#include "extensions/common/extension.h" |
+#include "net/base/mime_util.h" |
#include "ui/base/win/shell.h" |
#include "ui/gfx/icon_util.h" |
#include "ui/gfx/image/image.h" |
@@ -33,6 +38,9 @@ namespace { |
const base::FilePath::CharType kIconChecksumFileExt[] = |
FILE_PATH_LITERAL(".ico.md5"); |
+const base::FilePath::CharType kAppShimExe[] = |
+ FILE_PATH_LITERAL("app_shim.exe"); |
+ |
// Calculates checksum of an icon family using MD5. |
// The checksum is derived from all of the icons in the family. |
void GetImageCheckSum(const gfx::ImageFamily& image, base::MD5Digest* digest) { |
@@ -363,10 +371,7 @@ void OnShortcutInfoLoadedForSetRelaunchDetails( |
shortcut_info.extension_id, |
shortcut_info.url); |
base::FilePath icon_file = |
- web_app_path.Append(web_app::internals::GetSanitizedFileName( |
- shortcut_info.title)) |
- .ReplaceExtension(FILE_PATH_LITERAL(".ico")); |
- |
+ web_app::internals::GetIconFilePath(web_app_path, shortcut_info.title); |
content::BrowserThread::PostBlockingPoolTask( |
FROM_HERE, |
base::Bind(&CreateIconAndSetRelaunchDetails, |
@@ -376,6 +381,136 @@ void OnShortcutInfoLoadedForSetRelaunchDetails( |
hwnd)); |
} |
+// Creates an "app shim exe" by linking or copying the generic app shim exe. |
+// This is the binary that will be run when the user opens a file with this |
+// application. The name and icon of the binary will be used on the Open With |
+// menu. For this reason, we cannot simply launch chrome.exe. We give the app |
+// shim exe the same name as the application (with no ".exe" extension), so that |
+// the correct title will appear on the Open With menu. (Note: we also need a |
+// separate binary per app because Windows only allows a single association with |
+// each executable.) |
+// |path| is the full path of the shim binary to be created. |
+bool CreateAppShimBinary(const base::FilePath& path) { |
+ // TODO(mgiuca): Hard-link instead of copying, if on the same file system. |
+ base::FilePath chrome_binary_directory; |
+ if (!PathService::Get(base::DIR_EXE, &chrome_binary_directory)) { |
+ NOTREACHED(); |
+ return false; |
+ } |
+ |
+ base::FilePath generic_shim_path = |
+ chrome_binary_directory.Append(kAppShimExe); |
+ if (!base::CopyFile(generic_shim_path, path)) { |
+ LOG(ERROR) << "Could not copy app shim exe to " << path.value(); |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+ |
+// Gets the full command line for calling the shim binary. This will include a |
+// placeholder "%1" argument, which Windows will substitute with the filename |
+// chosen by the user. |
+base::CommandLine GetAppShimCommandLine(const base::FilePath& app_shim_path, |
+ const std::string& extension_id, |
+ const base::FilePath& profile_path) { |
+ // Get the command-line to pass to the shim (e.g., "chrome.exe --app-id=..."). |
+ CommandLine chrome_cmd_line = ShellIntegration::CommandLineArgsForLauncher( |
+ GURL(), extension_id, profile_path); |
+ chrome_cmd_line.AppendArg("%1"); |
+ |
+ // Get the command-line for calling the shim (e.g., |
+ // "app_shim [--chrome-sxs] -- --app-id=..."). |
+ CommandLine shim_cmd_line(app_shim_path); |
+ // If this is a canary build, launch the shim in canary mode. |
+ if (InstallUtil::IsChromeSxSProcess()) |
+ shim_cmd_line.AppendSwitch(installer::switches::kChromeSxS); |
+ // Ensure all subsequent switches are treated as args to the shim. |
+ shim_cmd_line.AppendArg("--"); |
+ for (const auto& arg : chrome_cmd_line.GetArgs()) |
+ shim_cmd_line.AppendArgNative(arg); |
+ |
+ return shim_cmd_line; |
+} |
+ |
+// Gets the set of file extensions associated with a particular file handler. |
+// Uses both the MIME types and extensions. |
+void GetHandlerFileExtensions(const extensions::FileHandlerInfo& handler, |
+ std::set<base::string16>* exts) { |
+ for (const auto& mime : handler.types) { |
+ std::vector<base::string16> mime_type_extensions; |
+ net::GetExtensionsForMimeType(mime, &mime_type_extensions); |
+ exts->insert(mime_type_extensions.begin(), mime_type_extensions.end()); |
+ } |
+ for (const auto& ext : handler.extensions) |
+ exts->insert(base::UTF8ToUTF16(ext)); |
+} |
+ |
+// Creates operating system file type associations for a given app. |
+// This is the platform specific implementation of the CreateFileAssociations |
+// function, and is executed on the FILE thread. |
+// Returns true on success, false on failure. |
+bool CreateFileAssociationsForApp( |
+ const std::string& extension_id, |
+ const base::string16& title, |
+ const base::FilePath& profile_path, |
+ const extensions::FileHandlersInfo& file_handlers_info) { |
+ base::FilePath web_app_path = |
+ web_app::GetWebAppDataDirectory(profile_path, extension_id, GURL()); |
+ base::FilePath file_name = web_app::internals::GetSanitizedFileName(title); |
+ |
+ // The progid is "chrome-APPID-HANDLERID". This is the internal name Windows |
+ // will use for file associations with this application. |
+ base::string16 progid_base = L"chrome-"; |
+ progid_base += base::UTF8ToUTF16(extension_id); |
+ |
+ // Create the app shim binary (see CreateAppShimBinary for rationale). Get the |
+ // command line for the shim. |
+ base::FilePath app_shim_path = web_app_path.Append(file_name); |
+ if (!CreateAppShimBinary(app_shim_path)) |
+ return false; |
+ |
+ CommandLine shim_cmd_line( |
+ GetAppShimCommandLine(app_shim_path, extension_id, profile_path)); |
+ |
+ // TODO(mgiuca): Get the file type name from the manifest, or generate a |
+ // default one. (If this is blank, Windows will generate one of the form |
+ // '<EXT> file'.) |
+ base::string16 file_type_name = L""; |
+ |
+ // TODO(mgiuca): Generate a new icon for this application's file associations |
+ // that looks like a page with the application icon inside. |
+ base::FilePath icon_file = |
+ web_app::internals::GetIconFilePath(web_app_path, title); |
+ |
+ // Create a separate file association (ProgId) for each handler. This allows |
+ // each handler to have its own filetype name and icon, and also a different |
+ // command line (so the app can see which handler was invoked). |
+ size_t num_successes = 0; |
+ for (const auto& handler : file_handlers_info) { |
+ base::string16 progid = progid_base + L"-" + base::UTF8ToUTF16(handler.id); |
+ |
+ std::set<base::string16> exts; |
+ GetHandlerFileExtensions(handler, &exts); |
+ |
+ if (ShellUtil::AddFileAssociations(progid, shim_cmd_line, file_type_name, |
+ icon_file, exts)) { |
+ ++num_successes; |
+ } |
+ } |
+ |
+ if (num_successes == 0) { |
+ // There were no successes; delete the shim. |
+ base::DeleteFile(app_shim_path, false); |
+ } else { |
+ // There were some successes; tell Windows Explorer to update its cache. |
+ SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSHNOWAIT, |
+ nullptr, nullptr); |
+ } |
+ |
+ return num_successes == file_handlers_info.size(); |
+} |
+ |
} // namespace |
namespace web_app { |
@@ -483,6 +618,12 @@ bool CreatePlatformShortcuts( |
return false; |
} |
+ if (switches::kEnableAppsFileAssociations) { |
Nico
2014/11/18 23:22:13
..\..\chrome\browser\web_applications\web_app_win.
|
+ CreateFileAssociationsForApp( |
+ shortcut_info.extension_id, shortcut_info.title, |
+ shortcut_info.profile_path, file_handlers_info); |
+ } |
+ |
return true; |
} |