OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 // | 4 // |
5 // This file defines functions that integrate Chrome in Windows shell. These | 5 // This file defines functions that integrate Chrome in Windows shell. These |
6 // functions can be used by Chrome as well as Chrome installer. All of the | 6 // functions can be used by Chrome as well as Chrome installer. All of the |
7 // work is done by the local functions defined in anonymous namespace in | 7 // work is done by the local functions defined in anonymous namespace in |
8 // this class. | 8 // this class. |
9 | 9 |
10 #include "chrome/installer/util/shell_util.h" | 10 #include "chrome/installer/util/shell_util.h" |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
184 // class. | 184 // class. |
185 class RegistryEntry { | 185 class RegistryEntry { |
186 public: | 186 public: |
187 // A bit-field enum of places to look for this key in the Windows registry. | 187 // A bit-field enum of places to look for this key in the Windows registry. |
188 enum LookForIn { | 188 enum LookForIn { |
189 LOOK_IN_HKCU = 1 << 0, | 189 LOOK_IN_HKCU = 1 << 0, |
190 LOOK_IN_HKLM = 1 << 1, | 190 LOOK_IN_HKLM = 1 << 1, |
191 LOOK_IN_HKCU_THEN_HKLM = LOOK_IN_HKCU | LOOK_IN_HKLM, | 191 LOOK_IN_HKCU_THEN_HKLM = LOOK_IN_HKCU | LOOK_IN_HKLM, |
192 }; | 192 }; |
193 | 193 |
194 // Details about a Windows application, to be entered into the registry for | |
195 // the purpose of file associations. | |
196 struct ApplicationInfo { | |
197 ApplicationInfo() | |
198 : set_delegate_execute(false), | |
199 file_type_icon_index(0), | |
200 application_icon_index(0) {} | |
201 | |
202 // The unique internal name Windows will use for file associations with this | |
203 // application. | |
204 base::string16 prog_id; | |
205 // The friendly name, and the path of the icon that will be used for files | |
206 // of these types when associated with this application by default. (They | |
207 // are NOT the name/icon that will represent the application under the Open | |
208 // With menu.) | |
209 base::string16 file_type_name; | |
210 // TODO(mgiuca): |file_type_icon_path| should be a base::FilePath. | |
gab
2014/09/12 13:32:37
Agreed as that makes types more explicit, what pre
Matt Giuca
2014/09/15 03:49:46
Yes, I want to avoid touching heaps of other code
| |
211 base::string16 file_type_icon_path; | |
212 int file_type_icon_index; | |
213 // The command to execute when opening a file via this association. It | |
214 // should contain "%1" to pass the filename as an argument. | |
215 // TODO(mgiuca): |command_line| should be a base::CommandLine. | |
216 base::string16 command_line; | |
217 // The unique internal name used by Windows 8 for this application. Distinct | |
218 // from |prog_id|. May be empty. | |
219 base::string16 app_id; | |
220 | |
221 // User-visible details about this application. Any of these may be empty. | |
222 base::string16 application_name; | |
223 // TODO(mgiuca): |application_icon_path| should be a base::FilePath. | |
224 base::string16 application_icon_path; | |
225 int application_icon_index; | |
226 base::string16 application_description; | |
227 base::string16 publisher_name; | |
gab
2014/09/12 13:32:37
This is the core info, I'd say put this block firs
Matt Giuca
2014/09/15 03:49:46
What do you mean by "core info"? All of this is op
| |
228 | |
229 // Whether the application will have a DelegateExecute key. This should only | |
230 // be used by Windows 8 Metro web browsers (i.e. Chrome itself). All other | |
231 // fields in this section are ignored if this is false. | |
232 bool set_delegate_execute; | |
233 // A GUID for this application. | |
234 base::string16 delegate_guid; | |
235 // The command to execute when opening this application via the Metro UI. | |
236 base::string16 delegate_command; | |
237 }; | |
238 | |
194 // Returns the Windows browser client registration key for Chrome. For | 239 // Returns the Windows browser client registration key for Chrome. For |
195 // example: "Software\Clients\StartMenuInternet\Chromium[.user]". Strictly | 240 // example: "Software\Clients\StartMenuInternet\Chromium[.user]". Strictly |
196 // speaking, we should use the name of the executable (e.g., "chrome.exe"), | 241 // speaking, we should use the name of the executable (e.g., "chrome.exe"), |
197 // but that ship has sailed. The cost of switching now is re-prompting users | 242 // but that ship has sailed. The cost of switching now is re-prompting users |
198 // to make Chrome their default browser, which isn't polite. |suffix| is the | 243 // to make Chrome their default browser, which isn't polite. |suffix| is the |
199 // user-specific registration suffix; see GetUserSpecificDefaultBrowserSuffix | 244 // user-specific registration suffix; see GetUserSpecificDefaultBrowserSuffix |
200 // in shell_util.h for details. | 245 // in shell_util.h for details. |
201 static base::string16 GetBrowserClientKey(BrowserDistribution* dist, | 246 static base::string16 GetBrowserClientKey(BrowserDistribution* dist, |
202 const base::string16& suffix) { | 247 const base::string16& suffix) { |
203 DCHECK(suffix.empty() || suffix[0] == L'.'); | 248 DCHECK(suffix.empty() || suffix[0] == L'.'); |
204 return base::string16(ShellUtil::kRegStartMenuInternet) | 249 return base::string16(ShellUtil::kRegStartMenuInternet) |
205 .append(1, L'\\') | 250 .append(1, L'\\') |
206 .append(dist->GetBaseAppName()) | 251 .append(dist->GetBaseAppName()) |
207 .append(suffix); | 252 .append(suffix); |
208 } | 253 } |
209 | 254 |
210 // Returns the Windows Default Programs capabilities key for Chrome. For | 255 // Returns the Windows Default Programs capabilities key for Chrome. For |
211 // example: | 256 // example: |
212 // "Software\Clients\StartMenuInternet\Chromium[.user]\Capabilities". | 257 // "Software\Clients\StartMenuInternet\Chromium[.user]\Capabilities". |
213 static base::string16 GetCapabilitiesKey(BrowserDistribution* dist, | 258 static base::string16 GetCapabilitiesKey(BrowserDistribution* dist, |
214 const base::string16& suffix) { | 259 const base::string16& suffix) { |
215 return GetBrowserClientKey(dist, suffix).append(L"\\Capabilities"); | 260 return GetBrowserClientKey(dist, suffix).append(L"\\Capabilities"); |
216 } | 261 } |
217 | 262 |
218 // This method returns a list of all the registry entries that | 263 // This method returns a list of all the registry entries that |
219 // are needed to register this installation's ProgId and AppId. | 264 // are needed to register this installation's ProgId and AppId. |
220 // These entries need to be registered in HKLM prior to Win8. | 265 // These entries need to be registered in HKLM prior to Win8. |
221 static void GetProgIdEntries(BrowserDistribution* dist, | 266 static void GetChromeProgIdEntries(BrowserDistribution* dist, |
222 const base::string16& chrome_exe, | 267 const base::string16& chrome_exe, |
223 const base::string16& suffix, | 268 const base::string16& suffix, |
224 ScopedVector<RegistryEntry>* entries) { | 269 ScopedVector<RegistryEntry>* entries) { |
225 base::string16 icon_path( | 270 ApplicationInfo app_info; |
226 ShellUtil::FormatIconLocation( | 271 app_info.prog_id = GetBrowserProgId(suffix); |
227 chrome_exe, | 272 app_info.file_type_name = dist->GetBrowserProgIdDesc(); |
228 dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME))); | 273 app_info.file_type_icon_path = chrome_exe; |
229 base::string16 open_cmd(ShellUtil::GetChromeShellOpenCmd(chrome_exe)); | 274 app_info.file_type_icon_index = |
230 base::string16 delegate_command( | 275 dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME); |
231 ShellUtil::GetChromeDelegateCommand(chrome_exe)); | 276 app_info.command_line = ShellUtil::GetChromeShellOpenCmd(chrome_exe); |
232 // For user-level installs: entries for the app id and DelegateExecute verb | 277 // For user-level installs: entries for the app id will be in HKCU; thus we |
233 // handler will be in HKCU; thus we do not need a suffix on those entries. | 278 // do not need a suffix on those entries. |
234 base::string16 app_id( | 279 app_info.app_id = ShellUtil::GetBrowserModelId( |
235 ShellUtil::GetBrowserModelId( | 280 dist, InstallUtil::IsPerUserInstall(chrome_exe.c_str())); |
236 dist, InstallUtil::IsPerUserInstall(chrome_exe.c_str()))); | |
237 base::string16 delegate_guid; | |
238 bool set_delegate_execute = | |
239 IsChromeMetroSupported() && | |
240 dist->GetCommandExecuteImplClsid(&delegate_guid); | |
241 | 281 |
242 // DelegateExecute ProgId. Needed for Chrome Metro in Windows 8. | 282 // DelegateExecute ProgId. Needed for Chrome Metro in Windows 8. |
243 if (set_delegate_execute) { | 283 app_info.delegate_command = ShellUtil::GetChromeDelegateCommand(chrome_exe); |
284 app_info.set_delegate_execute = | |
285 IsChromeMetroSupported() && | |
286 dist->GetCommandExecuteImplClsid(&app_info.delegate_guid); | |
287 | |
288 // The Chrome app icon path is the same as its file type path. | |
289 app_info.application_name = dist->GetDisplayName(); | |
290 app_info.application_icon_path = app_info.file_type_icon_path; | |
291 app_info.application_icon_index = app_info.file_type_icon_index; | |
292 app_info.application_description = dist->GetAppDescription(); | |
293 app_info.publisher_name = dist->GetPublisherName(); | |
gab
2014/09/12 13:32:36
As mentioned above, put this information first (an
Matt Giuca
2014/09/15 03:49:46
See comment above.
OK I've done the latter sugges
| |
294 | |
295 GetProgIdEntries(app_info, entries); | |
296 } | |
297 | |
298 // Gets the registry entries to register an application in the Windows | |
299 // registry. |app_info| provides all of the information needed. | |
300 static void GetProgIdEntries(const ApplicationInfo& app_info, | |
301 ScopedVector<RegistryEntry>* entries) { | |
302 if (app_info.set_delegate_execute) { | |
244 base::string16 model_id_shell(ShellUtil::kRegClasses); | 303 base::string16 model_id_shell(ShellUtil::kRegClasses); |
245 model_id_shell.push_back(base::FilePath::kSeparators[0]); | 304 model_id_shell.push_back(base::FilePath::kSeparators[0]); |
246 model_id_shell.append(app_id); | 305 model_id_shell.append(app_info.app_id); |
247 model_id_shell.append(ShellUtil::kRegExePath); | 306 model_id_shell.append(ShellUtil::kRegExePath); |
248 model_id_shell.append(ShellUtil::kRegShellPath); | 307 model_id_shell.append(ShellUtil::kRegShellPath); |
249 | 308 |
250 // <root hkey>\Software\Classes\<app_id>\.exe\shell @=open | 309 // <root hkey>\Software\Classes\<app_id>\.exe\shell @=open |
251 entries->push_back(new RegistryEntry(model_id_shell, | 310 entries->push_back(new RegistryEntry(model_id_shell, |
252 ShellUtil::kRegVerbOpen)); | 311 ShellUtil::kRegVerbOpen)); |
253 | 312 |
254 // Each of Chrome's shortcuts has an appid; which, as of Windows 8, is | 313 // Each shortcut has an appid; which, as of Windows 8, is registered to |
255 // registered to handle some verbs. This registration has the side-effect | 314 // handle some verbs. This registration has the side-effect that these |
256 // that these verbs now show up in the shortcut's context menu. We | 315 // verbs now show up in the shortcut's context menu. We mitigate this |
257 // mitigate this side-effect by making the context menu entries | 316 // side-effect by making the context menu entries user readable/localized |
258 // user readable/localized strings. See relevant MSDN article: | 317 // strings. See relevant MSDN article: |
259 // http://msdn.microsoft.com/en-US/library/windows/desktop/cc144171.aspx | 318 // http://msdn.microsoft.com/en-US/library/windows/desktop/cc144171.aspx |
260 const struct { | 319 const struct { |
261 const wchar_t* verb; | 320 const wchar_t* verb; |
262 int name_id; | 321 int name_id; |
263 } verbs[] = { | 322 } verbs[] = { |
264 { ShellUtil::kRegVerbOpen, -1 }, | 323 { ShellUtil::kRegVerbOpen, -1 }, |
265 { ShellUtil::kRegVerbOpenNewWindow, IDS_SHORTCUT_NEW_WINDOW_BASE }, | 324 { ShellUtil::kRegVerbOpenNewWindow, IDS_SHORTCUT_NEW_WINDOW_BASE }, |
266 }; | 325 }; |
267 for (size_t i = 0; i < arraysize(verbs); ++i) { | 326 for (size_t i = 0; i < arraysize(verbs); ++i) { |
268 base::string16 sub_path(model_id_shell); | 327 base::string16 sub_path(model_id_shell); |
269 sub_path.push_back(base::FilePath::kSeparators[0]); | 328 sub_path.push_back(base::FilePath::kSeparators[0]); |
270 sub_path.append(verbs[i].verb); | 329 sub_path.append(verbs[i].verb); |
271 | 330 |
272 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb> | 331 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb> |
273 if (verbs[i].name_id != -1) { | 332 if (verbs[i].name_id != -1) { |
274 // TODO(grt): http://crbug.com/75152 Write a reference to a localized | 333 // TODO(grt): http://crbug.com/75152 Write a reference to a localized |
275 // resource. | 334 // resource. |
276 base::string16 verb_name( | 335 base::string16 verb_name( |
277 installer::GetLocalizedString(verbs[i].name_id)); | 336 installer::GetLocalizedString(verbs[i].name_id)); |
278 entries->push_back(new RegistryEntry(sub_path, verb_name.c_str())); | 337 entries->push_back(new RegistryEntry(sub_path, verb_name.c_str())); |
279 } | 338 } |
280 entries->push_back(new RegistryEntry( | 339 entries->push_back(new RegistryEntry( |
281 sub_path, L"CommandId", L"Browser.Launch")); | 340 sub_path, L"CommandId", L"Browser.Launch")); |
282 | 341 |
283 sub_path.push_back(base::FilePath::kSeparators[0]); | 342 sub_path.push_back(base::FilePath::kSeparators[0]); |
284 sub_path.append(ShellUtil::kRegCommand); | 343 sub_path.append(ShellUtil::kRegCommand); |
285 | 344 |
286 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>\command | 345 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>\command |
287 entries->push_back(new RegistryEntry(sub_path, delegate_command)); | 346 entries->push_back( |
347 new RegistryEntry(sub_path, app_info.delegate_command)); | |
288 entries->push_back(new RegistryEntry( | 348 entries->push_back(new RegistryEntry( |
289 sub_path, ShellUtil::kRegDelegateExecute, delegate_guid)); | 349 sub_path, ShellUtil::kRegDelegateExecute, app_info.delegate_guid)); |
290 } | 350 } |
291 } | 351 } |
292 | 352 |
293 // File association ProgId | 353 // File association ProgId |
294 base::string16 chrome_html_prog_id(ShellUtil::kRegClasses); | 354 base::string16 prog_id_path(ShellUtil::kRegClasses); |
295 chrome_html_prog_id.push_back(base::FilePath::kSeparators[0]); | 355 prog_id_path.push_back(base::FilePath::kSeparators[0]); |
296 chrome_html_prog_id.append(GetBrowserProgId(suffix)); | 356 prog_id_path.append(app_info.prog_id); |
357 entries->push_back( | |
358 new RegistryEntry(prog_id_path, app_info.file_type_name)); | |
297 entries->push_back(new RegistryEntry( | 359 entries->push_back(new RegistryEntry( |
298 chrome_html_prog_id, dist->GetBrowserProgIdDesc())); | 360 prog_id_path + ShellUtil::kRegDefaultIcon, |
361 ShellUtil::FormatIconLocation(app_info.file_type_icon_path, | |
362 app_info.file_type_icon_index))); | |
299 entries->push_back(new RegistryEntry( | 363 entries->push_back(new RegistryEntry( |
300 chrome_html_prog_id + ShellUtil::kRegDefaultIcon, icon_path)); | 364 prog_id_path + ShellUtil::kRegShellOpen, app_info.command_line)); |
301 entries->push_back(new RegistryEntry( | 365 if (app_info.set_delegate_execute) { |
302 chrome_html_prog_id + ShellUtil::kRegShellOpen, open_cmd)); | 366 entries->push_back( |
303 if (set_delegate_execute) { | 367 new RegistryEntry(prog_id_path + ShellUtil::kRegShellOpen, |
304 entries->push_back(new RegistryEntry( | 368 ShellUtil::kRegDelegateExecute, |
305 chrome_html_prog_id + ShellUtil::kRegShellOpen, | 369 app_info.delegate_guid)); |
306 ShellUtil::kRegDelegateExecute, delegate_guid)); | |
307 } | 370 } |
308 | 371 |
309 // The following entries are required as of Windows 8, but do not | 372 // The following entries are required as of Windows 8, but do not |
310 // depend on the DelegateExecute verb handler being set. | 373 // depend on the DelegateExecute verb handler being set. |
311 if (base::win::GetVersion() >= base::win::VERSION_WIN8) { | 374 if (base::win::GetVersion() >= base::win::VERSION_WIN8) { |
312 entries->push_back(new RegistryEntry( | 375 if (!app_info.app_id.empty()) { |
313 chrome_html_prog_id, ShellUtil::kRegAppUserModelId, app_id)); | 376 entries->push_back(new RegistryEntry( |
377 prog_id_path, ShellUtil::kRegAppUserModelId, app_info.app_id)); | |
378 } | |
314 | 379 |
315 // Add \Software\Classes\ChromeHTML\Application entries | 380 // Add \Software\Classes\<prog_id>\Application entries |
316 base::string16 chrome_application(chrome_html_prog_id + | 381 base::string16 application_path(prog_id_path + |
317 ShellUtil::kRegApplication); | 382 ShellUtil::kRegApplication); |
318 entries->push_back(new RegistryEntry( | 383 if (!app_info.app_id.empty()) { |
319 chrome_application, ShellUtil::kRegAppUserModelId, app_id)); | 384 entries->push_back(new RegistryEntry( |
320 entries->push_back(new RegistryEntry( | 385 application_path, ShellUtil::kRegAppUserModelId, app_info.app_id)); |
321 chrome_application, ShellUtil::kRegApplicationIcon, icon_path)); | 386 } |
387 if (!app_info.application_icon_path.empty()) { | |
388 entries->push_back(new RegistryEntry( | |
389 application_path, | |
390 ShellUtil::kRegApplicationIcon, | |
391 ShellUtil::FormatIconLocation(app_info.application_icon_path, | |
392 app_info.application_icon_index))); | |
393 } | |
322 // TODO(grt): http://crbug.com/75152 Write a reference to a localized | 394 // TODO(grt): http://crbug.com/75152 Write a reference to a localized |
gab
2014/09/12 13:32:36
This TODO now belongs in the Chrome specific metho
Matt Giuca
2014/09/15 03:49:46
Done.
| |
323 // resource for name, description, and company. | 395 // resource for name, description, and company. |
324 entries->push_back(new RegistryEntry( | 396 if (!app_info.application_name.empty()) { |
325 chrome_application, ShellUtil::kRegApplicationName, | 397 entries->push_back(new RegistryEntry(application_path, |
326 dist->GetDisplayName())); | 398 ShellUtil::kRegApplicationName, |
327 entries->push_back(new RegistryEntry( | 399 app_info.application_name)); |
328 chrome_application, ShellUtil::kRegApplicationDescription, | 400 } |
329 dist->GetAppDescription())); | 401 if (!app_info.application_description.empty()) { |
330 entries->push_back(new RegistryEntry( | 402 entries->push_back( |
331 chrome_application, ShellUtil::kRegApplicationCompany, | 403 new RegistryEntry(application_path, |
332 dist->GetPublisherName())); | 404 ShellUtil::kRegApplicationDescription, |
405 app_info.application_description)); | |
406 } | |
407 if (!app_info.publisher_name.empty()) { | |
408 entries->push_back(new RegistryEntry(application_path, | |
409 ShellUtil::kRegApplicationCompany, | |
410 app_info.publisher_name)); | |
411 } | |
gab
2014/09/12 13:32:36
Does it really hurt to set those if they're empty?
Matt Giuca
2014/09/15 03:49:46
I don't know, but I could imagine Windows treating
| |
333 } | 412 } |
334 } | 413 } |
335 | 414 |
336 // This method returns a list of the registry entries needed to declare a | 415 // This method returns a list of the registry entries needed to declare a |
337 // capability of handling a protocol on Windows. | 416 // capability of handling a protocol on Windows. |
338 static void GetProtocolCapabilityEntries( | 417 static void GetProtocolCapabilityEntries( |
339 BrowserDistribution* dist, | 418 BrowserDistribution* dist, |
340 const base::string16& suffix, | 419 const base::string16& suffix, |
341 const base::string16& protocol, | 420 const base::string16& protocol, |
342 ScopedVector<RegistryEntry>* entries) { | 421 ScopedVector<RegistryEntry>* entries) { |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
426 } | 505 } |
427 | 506 |
428 // This method returns a list of the registry entries required for this | 507 // This method returns a list of the registry entries required for this |
429 // installation to be registered in the Windows shell. | 508 // installation to be registered in the Windows shell. |
430 // In particular: | 509 // In particular: |
431 // - App Paths | 510 // - App Paths |
432 // http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121 | 511 // http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121 |
433 // - File Associations | 512 // - File Associations |
434 // http://msdn.microsoft.com/en-us/library/bb166549 | 513 // http://msdn.microsoft.com/en-us/library/bb166549 |
435 // These entries need to be registered in HKLM prior to Win8. | 514 // These entries need to be registered in HKLM prior to Win8. |
436 static void GetAppRegistrationEntries(const base::string16& chrome_exe, | 515 static void GetChromeAppRegistrationEntries( |
437 const base::string16& suffix, | 516 const base::string16& chrome_exe, |
438 ScopedVector<RegistryEntry>* entries) { | 517 const base::string16& suffix, |
518 ScopedVector<RegistryEntry>* entries) { | |
439 const base::FilePath chrome_path(chrome_exe); | 519 const base::FilePath chrome_path(chrome_exe); |
440 base::string16 app_path_key(ShellUtil::kAppPathsRegistryKey); | 520 base::string16 app_path_key(ShellUtil::kAppPathsRegistryKey); |
441 app_path_key.push_back(base::FilePath::kSeparators[0]); | 521 app_path_key.push_back(base::FilePath::kSeparators[0]); |
442 app_path_key.append(chrome_path.BaseName().value()); | 522 app_path_key.append(chrome_path.BaseName().value()); |
443 entries->push_back(new RegistryEntry(app_path_key, chrome_exe)); | 523 entries->push_back(new RegistryEntry(app_path_key, chrome_exe)); |
444 entries->push_back(new RegistryEntry(app_path_key, | 524 entries->push_back(new RegistryEntry(app_path_key, |
445 ShellUtil::kAppPathsRegistryPathName, chrome_path.DirName().value())); | 525 ShellUtil::kAppPathsRegistryPathName, chrome_path.DirName().value())); |
446 | 526 |
447 const base::string16 html_prog_id(GetBrowserProgId(suffix)); | 527 const base::string16 html_prog_id(GetBrowserProgId(suffix)); |
448 for (int i = 0; ShellUtil::kPotentialFileAssociations[i] != NULL; i++) { | 528 for (int i = 0; ShellUtil::kPotentialFileAssociations[i] != NULL; i++) { |
449 base::string16 key(ShellUtil::kRegClasses); | 529 GetAppExtRegistrationEntries( |
450 key.push_back(base::FilePath::kSeparators[0]); | 530 html_prog_id, ShellUtil::kPotentialFileAssociations[i], entries); |
451 key.append(ShellUtil::kPotentialFileAssociations[i]); | |
452 key.push_back(base::FilePath::kSeparators[0]); | |
453 key.append(ShellUtil::kRegOpenWithProgids); | |
454 entries->push_back( | |
455 new RegistryEntry(key, html_prog_id, base::string16())); | |
456 } | 531 } |
457 } | 532 } |
458 | 533 |
534 // Gets the registry entries to register an application as a handler for a | |
535 // particular file extension. |prog_id| is the unique internal name Windows | |
536 // uses for the application. |ext| is the file extension, which must begin | |
537 // with a '.'. | |
538 static void GetAppExtRegistrationEntries( | |
539 const base::string16& prog_id, | |
540 const base::string16& ext, | |
541 ScopedVector<RegistryEntry>* entries) { | |
542 // In HKEY_CLASSES_ROOT\EXT\OpenWithProgids, create an empty value with this | |
543 // class's name. | |
gab
2014/09/12 13:32:37
s/name/prog_id
Matt Giuca
2014/09/15 03:49:46
Done.
| |
544 base::string16 key_name(ShellUtil::kRegClasses); | |
545 key_name.push_back(base::FilePath::kSeparators[0]); | |
546 key_name.append(ext); | |
547 key_name.push_back(base::FilePath::kSeparators[0]); | |
548 key_name.append(ShellUtil::kRegOpenWithProgids); | |
549 entries->push_back(new RegistryEntry(key_name, prog_id, base::string16())); | |
550 } | |
551 | |
552 // Gets the registry entries to register an application as the default handler | |
553 // for a particular file extension. |prog_id| is the unique internal name | |
554 // Windows uses for the application. |ext| is the file extension, which must | |
555 // begin with a '.'. If |overwrite_existing|, always sets the default handler; | |
556 // otherwise only sets if there is no existing default. | |
557 static void GetAppDefaultRegistrationEntries( | |
gab
2014/09/12 13:32:36
Note in the method name that these are XP style de
Matt Giuca
2014/09/15 03:49:45
They certainly work in Windows 7 (haven't tested i
gab
2014/09/18 01:16:15
You're right that IApplicationAssociationRegistrat
Matt Giuca
2014/09/30 10:21:12
Where on that page ([1]) does it say it doesn't wo
gab
2014/10/01 14:31:11
Browsers are special indeed in that being default
Matt Giuca
2014/10/02 09:36:33
I have completed my investigation on Windows 8, an
| |
558 const base::string16& prog_id, | |
559 const base::string16& ext, | |
560 bool overwrite_existing, | |
561 ScopedVector<RegistryEntry>* entries) { | |
562 // Set the default value of HKEY_CLASSES_ROOT\EXT to this class's name. | |
563 base::string16 key_name(ShellUtil::kRegClasses); | |
564 key_name.push_back(base::FilePath::kSeparators[0]); | |
565 key_name.append(ext); | |
566 scoped_ptr<RegistryEntry> default_association( | |
567 new RegistryEntry(key_name, prog_id)); | |
568 if (overwrite_existing || | |
569 !default_association->KeyExistsInRegistry(RegistryEntry::LOOK_IN_HKCU)) | |
570 entries->push_back(default_association.release()); | |
gab
2014/09/12 13:32:36
nit: {} since conditional is multiline
Matt Giuca
2014/09/15 03:49:45
Done.
| |
571 } | |
572 | |
459 // This method returns a list of all the user level registry entries that | 573 // This method returns a list of all the user level registry entries that |
460 // are needed to make Chromium the default handler for a protocol on XP. | 574 // are needed to make Chromium the default handler for a protocol on XP. |
461 static void GetXPStyleUserProtocolEntries( | 575 static void GetXPStyleUserProtocolEntries( |
462 const base::string16& protocol, | 576 const base::string16& protocol, |
463 const base::string16& chrome_icon, | 577 const base::string16& chrome_icon, |
464 const base::string16& chrome_open, | 578 const base::string16& chrome_open, |
465 ScopedVector<RegistryEntry>* entries) { | 579 ScopedVector<RegistryEntry>* entries) { |
466 // Protocols associations. | 580 // Protocols associations. |
467 base::string16 url_key(ShellUtil::kRegClasses); | 581 base::string16 url_key(ShellUtil::kRegClasses); |
468 url_key.push_back(base::FilePath::kSeparators[0]); | 582 url_key.push_back(base::FilePath::kSeparators[0]); |
(...skipping 28 matching lines...) Expand all Loading... | |
497 // we register them anyways as some legacy apps are hardcoded to lookup those | 611 // we register them anyways as some legacy apps are hardcoded to lookup those |
498 // values. | 612 // values. |
499 static void GetXPStyleDefaultBrowserUserEntries( | 613 static void GetXPStyleDefaultBrowserUserEntries( |
500 BrowserDistribution* dist, | 614 BrowserDistribution* dist, |
501 const base::string16& chrome_exe, | 615 const base::string16& chrome_exe, |
502 const base::string16& suffix, | 616 const base::string16& suffix, |
503 ScopedVector<RegistryEntry>* entries) { | 617 ScopedVector<RegistryEntry>* entries) { |
504 // File extension associations. | 618 // File extension associations. |
505 base::string16 html_prog_id(GetBrowserProgId(suffix)); | 619 base::string16 html_prog_id(GetBrowserProgId(suffix)); |
506 for (int i = 0; ShellUtil::kDefaultFileAssociations[i] != NULL; i++) { | 620 for (int i = 0; ShellUtil::kDefaultFileAssociations[i] != NULL; i++) { |
507 base::string16 ext_key(ShellUtil::kRegClasses); | 621 GetAppDefaultRegistrationEntries( |
508 ext_key.push_back(base::FilePath::kSeparators[0]); | 622 html_prog_id, ShellUtil::kDefaultFileAssociations[i], true, entries); |
509 ext_key.append(ShellUtil::kDefaultFileAssociations[i]); | |
510 entries->push_back(new RegistryEntry(ext_key, html_prog_id)); | |
511 } | 623 } |
512 | 624 |
513 // Protocols associations. | 625 // Protocols associations. |
514 base::string16 chrome_open = ShellUtil::GetChromeShellOpenCmd(chrome_exe); | 626 base::string16 chrome_open = ShellUtil::GetChromeShellOpenCmd(chrome_exe); |
515 base::string16 chrome_icon = | 627 base::string16 chrome_icon = |
516 ShellUtil::FormatIconLocation( | 628 ShellUtil::FormatIconLocation( |
517 chrome_exe, | 629 chrome_exe, |
518 dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME)); | 630 dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME)); |
519 for (int i = 0; ShellUtil::kBrowserProtocolAssociations[i] != NULL; i++) { | 631 for (int i = 0; ShellUtil::kBrowserProtocolAssociations[i] != NULL; i++) { |
520 GetXPStyleUserProtocolEntries(ShellUtil::kBrowserProtocolAssociations[i], | 632 GetXPStyleUserProtocolEntries(ShellUtil::kBrowserProtocolAssociations[i], |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
556 DCHECK(look_for_in); | 668 DCHECK(look_for_in); |
557 | 669 |
558 RegistryStatus status = DOES_NOT_EXIST; | 670 RegistryStatus status = DOES_NOT_EXIST; |
559 if (look_for_in & LOOK_IN_HKCU) | 671 if (look_for_in & LOOK_IN_HKCU) |
560 status = StatusInRegistryUnderRoot(HKEY_CURRENT_USER); | 672 status = StatusInRegistryUnderRoot(HKEY_CURRENT_USER); |
561 if (status == DOES_NOT_EXIST && (look_for_in & LOOK_IN_HKLM)) | 673 if (status == DOES_NOT_EXIST && (look_for_in & LOOK_IN_HKLM)) |
562 status = StatusInRegistryUnderRoot(HKEY_LOCAL_MACHINE); | 674 status = StatusInRegistryUnderRoot(HKEY_LOCAL_MACHINE); |
563 return status == SAME_VALUE; | 675 return status == SAME_VALUE; |
564 } | 676 } |
565 | 677 |
678 // Checks if the current registry entry exists in \|key_path_|\|name_|, | |
679 // regardless of value. Same lookup rules as ExistsInRegistry. | |
680 // Unlike ExistsInRegistry, this returns true if some other value is present | |
681 // with the same key. | |
682 bool KeyExistsInRegistry(uint32 look_for_in) const { | |
gab
2014/09/12 13:32:37
Seems your only caller of this cares only about HK
Matt Giuca
2014/09/15 03:49:46
I think for the latter reason that it's best to ke
| |
683 DCHECK(look_for_in); | |
684 | |
685 RegistryStatus status = DOES_NOT_EXIST; | |
686 if (look_for_in & LOOK_IN_HKCU) | |
687 status = StatusInRegistryUnderRoot(HKEY_CURRENT_USER); | |
688 if (status == DOES_NOT_EXIST && (look_for_in & LOOK_IN_HKLM)) | |
689 status = StatusInRegistryUnderRoot(HKEY_LOCAL_MACHINE); | |
690 return status != DOES_NOT_EXIST; | |
691 } | |
692 | |
566 private: | 693 private: |
567 // States this RegistryKey can be in compared to the registry. | 694 // States this RegistryKey can be in compared to the registry. |
568 enum RegistryStatus { | 695 enum RegistryStatus { |
569 // |name_| does not exist in the registry | 696 // |name_| does not exist in the registry |
570 DOES_NOT_EXIST, | 697 DOES_NOT_EXIST, |
571 // |name_| exists, but its value != |value_| | 698 // |name_| exists, but its value != |value_| |
572 DIFFERENT_VALUE, | 699 DIFFERENT_VALUE, |
573 // |name_| exists and its value is |value_| | 700 // |name_| exists and its value is |value_| |
574 SAME_VALUE, | 701 SAME_VALUE, |
575 }; | 702 }; |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
669 // under a single registry root. Not doing so caused http://crbug.com/144910 for | 796 // under a single registry root. Not doing so caused http://crbug.com/144910 for |
670 // users who first-installed Chrome in that revision range (those users are | 797 // users who first-installed Chrome in that revision range (those users are |
671 // still impacted by http://crbug.com/144910). This method will keep returning | 798 // still impacted by http://crbug.com/144910). This method will keep returning |
672 // true for affected users (i.e. who have all the registrations, but over both | 799 // true for affected users (i.e. who have all the registrations, but over both |
673 // registry roots). | 800 // registry roots). |
674 bool IsChromeRegistered(BrowserDistribution* dist, | 801 bool IsChromeRegistered(BrowserDistribution* dist, |
675 const base::string16& chrome_exe, | 802 const base::string16& chrome_exe, |
676 const base::string16& suffix, | 803 const base::string16& suffix, |
677 uint32 look_for_in) { | 804 uint32 look_for_in) { |
678 ScopedVector<RegistryEntry> entries; | 805 ScopedVector<RegistryEntry> entries; |
679 RegistryEntry::GetProgIdEntries(dist, chrome_exe, suffix, &entries); | 806 RegistryEntry::GetChromeProgIdEntries(dist, chrome_exe, suffix, &entries); |
680 RegistryEntry::GetShellIntegrationEntries(dist, chrome_exe, suffix, &entries); | 807 RegistryEntry::GetShellIntegrationEntries(dist, chrome_exe, suffix, &entries); |
681 RegistryEntry::GetAppRegistrationEntries(chrome_exe, suffix, &entries); | 808 RegistryEntry::GetChromeAppRegistrationEntries(chrome_exe, suffix, &entries); |
682 return AreEntriesRegistered(entries, look_for_in); | 809 return AreEntriesRegistered(entries, look_for_in); |
683 } | 810 } |
684 | 811 |
685 // This method checks if Chrome is already registered on the local machine | 812 // This method checks if Chrome is already registered on the local machine |
686 // for the requested protocol. It just checks the one value required for this. | 813 // for the requested protocol. It just checks the one value required for this. |
687 // See RegistryEntry::ExistsInRegistry for the behavior of |look_for_in|. | 814 // See RegistryEntry::ExistsInRegistry for the behavior of |look_for_in|. |
688 bool IsChromeRegisteredForProtocol(BrowserDistribution* dist, | 815 bool IsChromeRegisteredForProtocol(BrowserDistribution* dist, |
689 const base::string16& suffix, | 816 const base::string16& suffix, |
690 const base::string16& protocol, | 817 const base::string16& protocol, |
691 uint32 look_for_in) { | 818 uint32 look_for_in) { |
(...skipping 1364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2056 // Check if chrome is already registered with this suffix. | 2183 // Check if chrome is already registered with this suffix. |
2057 if (IsChromeRegistered(dist, chrome_exe, suffix, look_for_in)) | 2184 if (IsChromeRegistered(dist, chrome_exe, suffix, look_for_in)) |
2058 return true; | 2185 return true; |
2059 | 2186 |
2060 bool result = true; | 2187 bool result = true; |
2061 if (root == HKEY_CURRENT_USER || IsUserAnAdmin()) { | 2188 if (root == HKEY_CURRENT_USER || IsUserAnAdmin()) { |
2062 // Do the full registration if we can do it at user-level or if the user is | 2189 // Do the full registration if we can do it at user-level or if the user is |
2063 // an admin. | 2190 // an admin. |
2064 ScopedVector<RegistryEntry> progid_and_appreg_entries; | 2191 ScopedVector<RegistryEntry> progid_and_appreg_entries; |
2065 ScopedVector<RegistryEntry> shell_entries; | 2192 ScopedVector<RegistryEntry> shell_entries; |
2066 RegistryEntry::GetProgIdEntries(dist, chrome_exe, suffix, | 2193 RegistryEntry::GetChromeProgIdEntries( |
2067 &progid_and_appreg_entries); | 2194 dist, chrome_exe, suffix, &progid_and_appreg_entries); |
2068 RegistryEntry::GetAppRegistrationEntries(chrome_exe, suffix, | 2195 RegistryEntry::GetChromeAppRegistrationEntries( |
2069 &progid_and_appreg_entries); | 2196 chrome_exe, suffix, &progid_and_appreg_entries); |
2070 RegistryEntry::GetShellIntegrationEntries( | 2197 RegistryEntry::GetShellIntegrationEntries( |
2071 dist, chrome_exe, suffix, &shell_entries); | 2198 dist, chrome_exe, suffix, &shell_entries); |
2072 result = (AddRegistryEntries(root, progid_and_appreg_entries) && | 2199 result = (AddRegistryEntries(root, progid_and_appreg_entries) && |
2073 AddRegistryEntries(root, shell_entries)); | 2200 AddRegistryEntries(root, shell_entries)); |
2074 } else if (elevate_if_not_admin && | 2201 } else if (elevate_if_not_admin && |
2075 base::win::GetVersion() >= base::win::VERSION_VISTA && | 2202 base::win::GetVersion() >= base::win::VERSION_VISTA && |
2076 ElevateAndRegisterChrome(dist, chrome_exe, suffix, base::string16())) { | 2203 ElevateAndRegisterChrome(dist, chrome_exe, suffix, base::string16())) { |
2077 // If the user is not an admin and OS is between Vista and Windows 7 | 2204 // If the user is not an admin and OS is between Vista and Windows 7 |
2078 // inclusively, try to elevate and register. This is only intended for | 2205 // inclusively, try to elevate and register. This is only intended for |
2079 // user-level installs as system-level installs should always be run with | 2206 // user-level installs as system-level installs should always be run with |
2080 // admin rights. | 2207 // admin rights. |
2081 result = true; | 2208 result = true; |
2082 } else { | 2209 } else { |
2083 // If we got to this point then all we can do is create ProgId and basic app | 2210 // If we got to this point then all we can do is create ProgId and basic app |
2084 // registrations under HKCU. | 2211 // registrations under HKCU. |
2085 ScopedVector<RegistryEntry> entries; | 2212 ScopedVector<RegistryEntry> entries; |
2086 RegistryEntry::GetProgIdEntries( | 2213 RegistryEntry::GetChromeProgIdEntries( |
2087 dist, chrome_exe, base::string16(), &entries); | 2214 dist, chrome_exe, base::string16(), &entries); |
2088 // Prefer to use |suffix|; unless Chrome's ProgIds are already registered | 2215 // Prefer to use |suffix|; unless Chrome's ProgIds are already registered |
2089 // with no suffix (as per the old registration style): in which case some | 2216 // with no suffix (as per the old registration style): in which case some |
2090 // other registry entries could refer to them and since we were not able to | 2217 // other registry entries could refer to them and since we were not able to |
2091 // set our HKLM entries above, we are better off not altering these here. | 2218 // set our HKLM entries above, we are better off not altering these here. |
2092 if (!AreEntriesRegistered(entries, RegistryEntry::LOOK_IN_HKCU)) { | 2219 if (!AreEntriesRegistered(entries, RegistryEntry::LOOK_IN_HKCU)) { |
2093 if (!suffix.empty()) { | 2220 if (!suffix.empty()) { |
2094 entries.clear(); | 2221 entries.clear(); |
2095 RegistryEntry::GetProgIdEntries(dist, chrome_exe, suffix, &entries); | 2222 RegistryEntry::GetChromeProgIdEntries( |
2096 RegistryEntry::GetAppRegistrationEntries(chrome_exe, suffix, &entries); | 2223 dist, chrome_exe, suffix, &entries); |
2224 RegistryEntry::GetChromeAppRegistrationEntries( | |
2225 chrome_exe, suffix, &entries); | |
2097 } | 2226 } |
2098 result = AddRegistryEntries(HKEY_CURRENT_USER, entries); | 2227 result = AddRegistryEntries(HKEY_CURRENT_USER, entries); |
2099 } else { | 2228 } else { |
2100 // The ProgId is registered unsuffixed in HKCU, also register the app with | 2229 // The ProgId is registered unsuffixed in HKCU, also register the app with |
2101 // Windows in HKCU (this was not done in the old registration style and | 2230 // Windows in HKCU (this was not done in the old registration style and |
2102 // thus needs to be done after the above check for the unsuffixed | 2231 // thus needs to be done after the above check for the unsuffixed |
2103 // registration). | 2232 // registration). |
2104 entries.clear(); | 2233 entries.clear(); |
2105 RegistryEntry::GetAppRegistrationEntries(chrome_exe, base::string16(), | 2234 RegistryEntry::GetChromeAppRegistrationEntries( |
2106 &entries); | 2235 chrome_exe, base::string16(), &entries); |
2107 result = AddRegistryEntries(HKEY_CURRENT_USER, entries); | 2236 result = AddRegistryEntries(HKEY_CURRENT_USER, entries); |
2108 } | 2237 } |
2109 } | 2238 } |
2110 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); | 2239 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); |
2111 return result; | 2240 return result; |
2112 } | 2241 } |
2113 | 2242 |
2114 bool ShellUtil::RegisterChromeForProtocol(BrowserDistribution* dist, | 2243 bool ShellUtil::RegisterChromeForProtocol(BrowserDistribution* dist, |
2115 const base::string16& chrome_exe, | 2244 const base::string16& chrome_exe, |
2116 const base::string16& unique_suffix, | 2245 const base::string16& unique_suffix, |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2285 // are any left...). | 2414 // are any left...). |
2286 if (free_bits >= 8 && next_byte_index < size) { | 2415 if (free_bits >= 8 && next_byte_index < size) { |
2287 free_bits -= 8; | 2416 free_bits -= 8; |
2288 bit_stream += bytes[next_byte_index++] << free_bits; | 2417 bit_stream += bytes[next_byte_index++] << free_bits; |
2289 } | 2418 } |
2290 } | 2419 } |
2291 | 2420 |
2292 DCHECK_EQ(ret.length(), encoded_length); | 2421 DCHECK_EQ(ret.length(), encoded_length); |
2293 return ret; | 2422 return ret; |
2294 } | 2423 } |
2424 | |
2425 // static | |
2426 bool ShellUtil::AddFileAssociations( | |
2427 const base::string16& progid, | |
2428 const base::CommandLine& command_line, | |
2429 const base::string16& file_type_name, | |
2430 const base::FilePath& icon_path, | |
2431 const std::set<base::string16>& file_extensions) { | |
2432 ScopedVector<RegistryEntry> entries; | |
2433 | |
2434 // Create a class for this app. | |
2435 RegistryEntry::ApplicationInfo app_info; | |
2436 app_info.prog_id = progid; | |
2437 app_info.file_type_name = file_type_name; | |
2438 app_info.file_type_icon_path = icon_path.value(); | |
2439 app_info.file_type_icon_index = 0; | |
2440 app_info.command_line = command_line.GetCommandLineString(); | |
2441 RegistryEntry::GetProgIdEntries(app_info, &entries); | |
2442 | |
2443 // Associate each extension that the app can handle with the class. Set this | |
2444 // app as the default handler if and only if there is no existing default. | |
2445 for (std::set<base::string16>::const_iterator it = file_extensions.begin(); | |
2446 it != file_extensions.end(); | |
2447 ++it) { | |
2448 base::string16 ext(1, L'.'); | |
gab
2014/09/12 13:32:36
Add this check above.
DCHECK(!it->empty() && (*it
Matt Giuca
2014/09/15 03:49:46
Done.
| |
2449 ext.append(*it); | |
2450 RegistryEntry::GetAppExtRegistrationEntries(progid, ext, &entries); | |
2451 RegistryEntry::GetAppDefaultRegistrationEntries( | |
2452 progid, ext, false, &entries); | |
2453 } | |
2454 | |
2455 return AddRegistryEntries(HKEY_CURRENT_USER, entries); | |
2456 } | |
2457 | |
2458 // static | |
2459 bool ShellUtil::DeleteFileAssociations(const base::string16& progid) { | |
2460 // Delete the key HKEY_CLASSES_ROOT\PROGID. | |
2461 base::string16 key_path(ShellUtil::kRegClasses); | |
2462 key_path.push_back(base::FilePath::kSeparators[0]); | |
2463 key_path.append(progid); | |
2464 return InstallUtil::DeleteRegistryKey( | |
2465 HKEY_CURRENT_USER, key_path, WorkItem::kWow64Default); | |
2466 | |
2467 // Note: there is no need to remove the association from the extension to the | |
2468 // class, as Windows will ignore it. See: | |
2469 // http://msdn.microsoft.com/en-us/library/windows/desktop/cc144148.aspx | |
gab
2014/09/12 13:32:37
Right but you should still delete the OpenWith reg
Matt Giuca
2014/09/15 03:49:46
While that document doesn't say *not* to remove th
gab
2014/09/18 01:16:15
The documentation *does* explicitly say that these
Matt Giuca
2014/09/30 10:21:12
But remember I will be calling this code far more
gab
2014/10/01 14:31:11
Ok fair enough, but I still think we should remove
Matt Giuca
2014/10/02 09:36:33
Acknowledged.
| |
2470 } | |
OLD | NEW |