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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/file_associations_win.h"
6
7 #include <vector>
8
9 #include <shlobj.h>
10
11 #include "base/command_line.h"
12 #include "base/files/file_path.h"
13 #include "base/logging.h"
14 #include "base/strings/string16.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/win/registry.h"
18
19 namespace {
20
21 // Key relative to HKEY_CURRENT_USER that provides a user-writable alias for
22 // HKEY_CLASSES_ROOT.
23 const wchar_t kRegClassesRootAlias[] = L"Software\\Classes";
24 const wchar_t kRegDefaultIcon[] = L"\\DefaultIcon";
25 const wchar_t kRegShellOpen[] = L"\\shell\\open\\command";
26 const wchar_t kRegOpenWithProgids[] = L"\\OpenWithProgids";
27
28 // Writes a value to the Windows registry under HKEY_CURRENT_USER, creating the
29 // key if it does not already exist. If |value_name| is the empty string, writes
30 // to the default value for the given key. If |keep_existing| is true, will not
31 // overwrite an existing value. If an error occurs, logs an error and returns
32 // false.
33 bool WriteCurrentUserRegistryValue(const base::string16& key_name,
34 const base::string16& value_name,
35 const base::string16& value_data,
36 bool keep_existing) {
37 base::win::RegKey key;
38 if (key.Create(HKEY_CURRENT_USER, key_name.c_str(), KEY_ALL_ACCESS) !=
39 ERROR_SUCCESS) {
40 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
41 return false;
42 }
43 if (keep_existing && key.HasValue(NULL))
44 return true;
45 if (key.WriteValue(value_name.empty() ? NULL : value_name.c_str(),
46 value_data.c_str()) != ERROR_SUCCESS) {
47 LOG(ERROR) << "Could not write HKEY_CURRENT_USER\\" << key_name << "."
48 << (value_name.empty() ? L"(Default)" : value_name);
49 return false;
50 }
51 return true;
52 }
53
54 // Writes a value to the Windows registry, overwriting any existing data.
55 bool WriteCurrentUserRegistryValue(const base::string16& key_name,
56 const base::string16& value_name,
57 const base::string16& value_data) {
58 return WriteCurrentUserRegistryValue(key_name, value_name, value_data, false);
59 }
60
61 // Class helper for AddWindowsFileAssociations. Objects of this class live only
62 // during the AddWindowsFileAssociations operation.
63 class FileAssociator {
64 public:
65 FileAssociator(const base::string16& progid);
66
67 // Creates the registry key for the file association class. This is the key
68 // that supplies information about the class (such as its name and command
69 // line), and is referenced by all file extensions sharing the association.
70 bool RegisterClass(const base::string16& file_type_name,
71 const base::FilePath& icon_path,
72 const base::CommandLine& command_line);
73
74 // Deletes the registry key for the file association class.
75 bool DeleteClass();
76
77 // Adds a file extension as a supported type of this class. |ext| is the file
78 // extension (without a leading '.').
79 bool AssociateExtension(const base::string16& ext);
80
81 private:
82 // The class name for this association.
83 base::string16 progid_;
84 };
85
86 FileAssociator::FileAssociator(const base::string16& progid) : progid_(progid) {
87 }
88
89 bool FileAssociator::RegisterClass(const base::string16& file_type_name,
90 const base::FilePath& icon_path,
91 const base::CommandLine& command_line) {
92 // Open or create a key HKEY_CLASSES_ROOT\PROGID.
93 base::string16 class_key_name = kRegClassesRootAlias;
94 class_key_name += L"\\";
95 class_key_name += progid_;
96
97 // Set the file type's user-visible name.
98 if (!WriteCurrentUserRegistryValue(class_key_name, L"", file_type_name))
99 return false;
100
101 // Set the file type's icon.
102 if (!WriteCurrentUserRegistryValue(
103 class_key_name + kRegDefaultIcon, L"", icon_path.value() + L",0")) {
104 return false;
105 }
106
107 // Set the command line to execute for the "open" verb.
108 if (!WriteCurrentUserRegistryValue(class_key_name + kRegShellOpen,
109 L"",
110 command_line.GetCommandLineString())) {
111 return false;
112 }
113
114 return true;
115 }
116
117 bool FileAssociator::DeleteClass() {
118 // Delete the key HKEY_CLASSES_ROOT\PROGID.
119 base::win::RegKey key;
120 if (key.Open(HKEY_CURRENT_USER, kRegClassesRootAlias, KEY_ALL_ACCESS) !=
121 ERROR_SUCCESS) {
122 LOG(ERROR) << "Could not open HKEY_CURRENT_USER\\" << kRegClassesRootAlias;
123 return false;
124 }
125
126 if (key.DeleteKey(progid_.c_str()) != ERROR_SUCCESS) {
127 LOG(ERROR) << "Could not delete HKEY_CURRENT_USER\\" << kRegClassesRootAlias
128 << "\\" << progid_;
129 return false;
130 }
131
132 return true;
133 }
134
135 bool FileAssociator::AssociateExtension(const base::string16& ext) {
136 // Open or create a key HKEY_CLASSES_ROOT\.EXT.
137 base::string16 ext_key_name = kRegClassesRootAlias;
138 ext_key_name += L"\\.";
139 ext_key_name += ext;
140
141 // Under OpenWithProgids, create an empty value with this class's name.
142 if (!WriteCurrentUserRegistryValue(
143 ext_key_name + kRegOpenWithProgids, progid_, L"")) {
144 return false;
145 }
146
147 // If the extension key has no default value (the default class for this
148 // file type) is blank, register this application as the default handler.
149 // Otherwise, leave the existing default as-is.
150 return WriteCurrentUserRegistryValue(ext_key_name, L"", progid_, true);
151 }
152
153 } // namespace
154
155 bool AddWindowsFileAssociations(const std::string& progid,
156 const base::CommandLine& command_line,
157 const std::string& file_type_name,
158 const base::FilePath& icon_path,
159 const std::set<std::string>& file_extensions) {
160 FileAssociator associator(base::UTF8ToUTF16(progid));
161
162 // Create a class for this app.
163 if (!associator.RegisterClass(
164 base::UTF8ToUTF16(file_type_name), icon_path, command_line)) {
165 return false;
166 }
167
168 // Associate each extension that the app can handle with the class.
169 for (std::set<std::string>::const_iterator it = file_extensions.begin();
170 it != file_extensions.end();
171 ++it) {
172 if (!associator.AssociateExtension(base::UTF8ToUTF16(*it)))
173 return false;
174 }
175
176 // Success. Tell Windows Explorer to update its cache.
177 SHChangeNotify(
178 SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSHNOWAIT, NULL, NULL);
179 return true;
180 }
181
182 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
183 FileAssociator associator(base::UTF8ToUTF16(progid));
184
185 // Delete the class for this app.
186 associator.DeleteClass();
187
188 // Note: there is no need to remove the association from the extension to the
189 // class, as Windows will ignore it. See:
190 // http://msdn.microsoft.com/en-us/library/windows/desktop/cc144148.aspx
191
192 // Success. Tell Windows Explorer to update its cache.
193 SHChangeNotify(
194 SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSHNOWAIT, NULL, NULL);
195 return true;
196 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698