Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(38)

Unified Diff: chrome/browser/file_associations_win.cc

Issue 487693002: ShellUtil: Add generic methods to add/delete Windows file associations. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/file_associations_win.cc
diff --git a/chrome/browser/file_associations_win.cc b/chrome/browser/file_associations_win.cc
new file mode 100644
index 0000000000000000000000000000000000000000..d2a6f4574b4fa7c7e3f9b9718c966110a95ab31c
--- /dev/null
+++ b/chrome/browser/file_associations_win.cc
@@ -0,0 +1,196 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/file_associations_win.h"
+
+#include <vector>
+
+#include <shlobj.h>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/registry.h"
+
+namespace {
+
+// Key relative to HKEY_CURRENT_USER that provides a user-writable alias for
+// HKEY_CLASSES_ROOT.
+const wchar_t kRegClassesRootAlias[] = L"Software\\Classes";
+const wchar_t kRegDefaultIcon[] = L"\\DefaultIcon";
+const wchar_t kRegShellOpen[] = L"\\shell\\open\\command";
+const wchar_t kRegOpenWithProgids[] = L"\\OpenWithProgids";
+
+// Writes a value to the Windows registry under HKEY_CURRENT_USER, creating the
+// key if it does not already exist. If |value_name| is the empty string, writes
+// to the default value for the given key. If |keep_existing| is true, will not
+// overwrite an existing value. If an error occurs, logs an error and returns
+// false.
+bool WriteCurrentUserRegistryValue(const base::string16& key_name,
+ const base::string16& value_name,
+ const base::string16& value_data,
+ bool keep_existing) {
+ base::win::RegKey key;
+ if (key.Create(HKEY_CURRENT_USER, key_name.c_str(), KEY_ALL_ACCESS) !=
+ ERROR_SUCCESS) {
+ LOG(ERROR) << "Could not create HKEY_CURRENT_USER\\" << key_name;
jackhou1 2014/08/19 08:16:54 I think in general logging that will not be seen i
Matt Giuca 2014/08/19 08:24:48 Hmm OK. Well the problem is that these errors are
+ return false;
+ }
+ if (keep_existing && key.HasValue(NULL))
+ return true;
+ if (key.WriteValue(value_name.empty() ? NULL : value_name.c_str(),
+ value_data.c_str()) != ERROR_SUCCESS) {
+ LOG(ERROR) << "Could not write HKEY_CURRENT_USER\\" << key_name << "."
+ << (value_name.empty() ? L"(Default)" : value_name);
+ return false;
+ }
+ return true;
+}
+
+// Writes a value to the Windows registry, overwriting any existing data.
+bool WriteCurrentUserRegistryValue(const base::string16& key_name,
+ const base::string16& value_name,
+ const base::string16& value_data) {
+ return WriteCurrentUserRegistryValue(key_name, value_name, value_data, false);
+}
+
+// Class helper for AddWindowsFileAssociations. Objects of this class live only
+// during the AddWindowsFileAssociations operation.
+class FileAssociator {
+ public:
+ FileAssociator(const base::string16& progid);
+
+ // Creates the registry key for the file association class. This is the key
+ // that supplies information about the class (such as its name and command
+ // line), and is referenced by all file extensions sharing the association.
+ bool RegisterClass(const base::string16& file_type_name,
+ const base::FilePath& icon_path,
+ const base::CommandLine& command_line);
+
+ // Deletes the registry key for the file association class.
+ bool DeleteClass();
+
+ // Adds a file extension as a supported type of this class. |ext| is the file
+ // extension (without a leading '.').
+ bool AssociateExtension(const base::string16& ext);
+
+ private:
+ // The class name for this association.
+ base::string16 progid_;
+};
+
+FileAssociator::FileAssociator(const base::string16& progid) : progid_(progid) {
+}
+
+bool FileAssociator::RegisterClass(const base::string16& file_type_name,
+ const base::FilePath& icon_path,
+ const base::CommandLine& command_line) {
+ // Open or create a key HKEY_CLASSES_ROOT\PROGID.
+ base::string16 class_key_name = kRegClassesRootAlias;
+ class_key_name += L"\\";
+ class_key_name += progid_;
+
+ // Set the file type's user-visible name.
+ if (!WriteCurrentUserRegistryValue(class_key_name, L"", file_type_name))
+ return false;
+
+ // Set the file type's icon.
+ if (!WriteCurrentUserRegistryValue(
+ class_key_name + kRegDefaultIcon, L"", icon_path.value() + L",0")) {
+ return false;
+ }
+
+ // Set the command line to execute for the "open" verb.
+ if (!WriteCurrentUserRegistryValue(class_key_name + kRegShellOpen,
+ L"",
+ command_line.GetCommandLineString())) {
+ return false;
+ }
+
+ return true;
+}
+
+bool FileAssociator::DeleteClass() {
+ // Delete the key HKEY_CLASSES_ROOT\PROGID.
+ base::win::RegKey key;
+ if (key.Open(HKEY_CURRENT_USER, kRegClassesRootAlias, KEY_ALL_ACCESS) !=
+ ERROR_SUCCESS) {
+ LOG(ERROR) << "Could not open HKEY_CURRENT_USER\\" << kRegClassesRootAlias;
+ return false;
+ }
+
+ if (key.DeleteKey(progid_.c_str()) != ERROR_SUCCESS) {
+ LOG(ERROR) << "Could not delete HKEY_CURRENT_USER\\" << kRegClassesRootAlias
+ << "\\" << progid_;
+ return false;
+ }
+
+ return true;
+}
+
+bool FileAssociator::AssociateExtension(const base::string16& ext) {
+ // Open or create a key HKEY_CLASSES_ROOT\.EXT.
+ base::string16 ext_key_name = kRegClassesRootAlias;
+ ext_key_name += L"\\.";
+ ext_key_name += ext;
+
+ // Under OpenWithProgids, create an empty value with this class's name.
+ if (!WriteCurrentUserRegistryValue(
+ ext_key_name + kRegOpenWithProgids, progid_, L"")) {
+ return false;
+ }
+
+ // If the extension key has no default value (the default class for this
+ // file type) is blank, register this application as the default handler.
+ // Otherwise, leave the existing default as-is.
+ return WriteCurrentUserRegistryValue(ext_key_name, L"", progid_, true);
+}
+
+} // namespace
+
+bool AddWindowsFileAssociations(const std::string& progid,
+ const base::CommandLine& command_line,
+ const std::string& file_type_name,
+ const base::FilePath& icon_path,
+ const std::set<std::string>& file_extensions) {
+ FileAssociator associator(base::UTF8ToUTF16(progid));
+
+ // Create a class for this app.
+ if (!associator.RegisterClass(
+ base::UTF8ToUTF16(file_type_name), icon_path, command_line)) {
+ return false;
+ }
+
+ // Associate each extension that the app can handle with the class.
+ for (std::set<std::string>::const_iterator it = file_extensions.begin();
+ it != file_extensions.end();
+ ++it) {
+ if (!associator.AssociateExtension(base::UTF8ToUTF16(*it)))
+ return false;
+ }
+
+ // Success. Tell Windows Explorer to update its cache.
+ SHChangeNotify(
+ SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSHNOWAIT, NULL, NULL);
+ return true;
+}
+
+bool DeleteWindowsFileAssociations(const std::string& progid) {
jackhou1 2014/08/19 08:16:54 Is there a way to delete the entries added by Asso
Matt Giuca 2014/08/19 08:24:48 We could, but it would mean either: a) Taking a li
jackhou1 2014/08/19 08:40:03 What if we add a value to the progid key that cont
Matt Giuca 2014/08/22 03:48:58 Yeah that sounds reasonable. But I'd like to do it
+ FileAssociator associator(base::UTF8ToUTF16(progid));
+
+ // Delete the class for this app.
+ associator.DeleteClass();
+
+ // Note: there is no need to remove the association from the extension to the
+ // class, as Windows will ignore it. See:
+ // http://msdn.microsoft.com/en-us/library/windows/desktop/cc144148.aspx
+
+ // Success. Tell Windows Explorer to update its cache.
+ SHChangeNotify(
+ SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSHNOWAIT, NULL, NULL);
+ return true;
+}

Powered by Google App Engine
This is Rietveld 408576698