Chromium Code Reviews| OLD | NEW |
|---|---|
| (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" | |
|
robertshield
2014/08/25 02:45:22
I think these files should be called shell_file_as
| |
| 6 | |
| 7 #include <shlobj.h> | |
| 8 | |
| 9 #include <vector> | |
| 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"; | |
|
cpu_(ooo_6.6-7.5)
2014/08/22 22:03:33
I am going to say we have this kind of logic somew
Matt Giuca
2014/08/25 00:58:18
See comment at the top of file_associations_win.h
robertshield
2014/08/25 02:45:22
There is a fair amount of duplication here with th
| |
| 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; | |
| 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 explicit 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. | |
|
robertshield
2014/08/25 02:45:22
Add a comment that this only for WinXP support.
Matt Giuca
2014/08/25 03:15:42
I'm lost... this is the only place where I say "as
robertshield
2014/08/25 13:13:45
Ick, sorry, I confused this vs OpenWithList which
| |
| 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); | |
|
robertshield
2014/08/25 02:45:22
The CL makes no mention of when/how this will be c
| |
| 179 return true; | |
| 180 } | |
| 181 | |
| 182 bool DeleteWindowsFileAssociations(const std::string& progid) { | |
| 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 } | |
| OLD | NEW |