| Index: chrome/installer/util/shell_util.cc
|
| diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc
|
| index 1d30439806614453966c6d8f8bf36b5162f30e39..6dad7c77409ce0dd6369b367a26d335aed9a2d0a 100644
|
| --- a/chrome/installer/util/shell_util.cc
|
| +++ b/chrome/installer/util/shell_util.cc
|
| @@ -24,6 +24,7 @@
|
| #include "base/utf_string_conversions.h"
|
| #include "base/values.h"
|
| #include "base/win/registry.h"
|
| +#include "base/win/scoped_comptr.h"
|
| #include "base/win/windows_version.h"
|
| #include "chrome/common/chrome_constants.h"
|
| #include "chrome/common/chrome_switches.h"
|
| @@ -70,6 +71,27 @@ class RegistryEntry {
|
| return true;
|
| }
|
|
|
| + // This method returns a list of the system level registry entries
|
| + // needed to declare a capability of handling a protocol.
|
| + static bool GetProtocolCapabilityEntries(BrowserDistribution* dist,
|
| + const std::wstring& chrome_exe,
|
| + const std::wstring& suffix,
|
| + const std::wstring& protocol,
|
| + std::list<RegistryEntry*>* entries) {
|
| + std::wstring app_name = dist->GetApplicationName() + suffix;
|
| + std::wstring start_menu_entry(ShellUtil::kRegStartMenuInternet);
|
| + start_menu_entry.append(L"\\" + app_name);
|
| +
|
| + std::wstring capabilities(start_menu_entry + L"\\Capabilities");
|
| +
|
| + std::wstring html_prog_id(ShellUtil::kChromeHTMLProgId);
|
| + html_prog_id.append(suffix);
|
| + entries->push_front(new RegistryEntry(capabilities + L"\\URLAssociations",
|
| + protocol, html_prog_id));
|
| + return true;
|
| +}
|
| +
|
| +
|
| // This method returns a list of all the system level registry entries that
|
| // are needed to register Chromium on the machine.
|
| static bool GetSystemEntries(BrowserDistribution* dist,
|
| @@ -119,10 +141,11 @@ class RegistryEntry {
|
| capabilities + L"\\FileAssociations",
|
| ShellUtil::kFileAssociations[i], html_prog_id));
|
| }
|
| - for (int i = 0; ShellUtil::kProtocolAssociations[i] != NULL; i++) {
|
| + for (int i = 0; ShellUtil::kPotentialProtocolAssociations[i] != NULL;
|
| + i++) {
|
| entries->push_front(new RegistryEntry(
|
| capabilities + L"\\URLAssociations",
|
| - ShellUtil::kProtocolAssociations[i], html_prog_id));
|
| + ShellUtil::kPotentialProtocolAssociations[i], html_prog_id));
|
| }
|
|
|
| FilePath chrome_path(chrome_exe);
|
| @@ -137,6 +160,44 @@ class RegistryEntry {
|
| }
|
|
|
| // This method returns a list of all the user level registry entries that
|
| + // are needed to make Chromium the default handler for a protocol.
|
| + static bool GetUserProtocolEntries(BrowserDistribution* dist,
|
| + const std::wstring& chrome_exe,
|
| + const std::wstring& suffix,
|
| + const std::wstring& protocol,
|
| + const std::wstring& chrome_icon,
|
| + const std::wstring& chrome_open,
|
| + std::list<RegistryEntry*>* entries) {
|
| + // Protocols associations.
|
| + std::wstring url_key(ShellUtil::kRegClasses);
|
| + file_util::AppendToPath(&url_key, protocol);
|
| +
|
| + // This registry value tells Windows that this 'class' is a URL scheme
|
| + // so IE, explorer and other apps will route it to our handler.
|
| + // <root hkey>\Software\Classes\<protocol>\URL Protocol
|
| + entries->push_front(new RegistryEntry(url_key,
|
| + ShellUtil::kRegUrlProtocol, L""));
|
| +
|
| + // <root hkey>\Software\Classes\<protocol>\DefaultIcon
|
| + std::wstring icon_key = url_key + ShellUtil::kRegDefaultIcon;
|
| + entries->push_front(new RegistryEntry(icon_key, chrome_icon));
|
| +
|
| + // <root hkey>\Software\Classes\<protocol>\shell\open\command
|
| + std::wstring shell_key = url_key + ShellUtil::kRegShellOpen;
|
| + entries->push_front(new RegistryEntry(shell_key, chrome_open));
|
| +
|
| + // <root hkey>\Software\Classes\<protocol>\shell\open\ddeexec
|
| + std::wstring dde_key = url_key + L"\\shell\\open\\ddeexec";
|
| + entries->push_front(new RegistryEntry(dde_key, L""));
|
| +
|
| + // <root hkey>\Software\Classes\<protocol>\shell\@
|
| + std::wstring protocol_shell_key = url_key + ShellUtil::kRegShellPath;
|
| + entries->push_front(new RegistryEntry(protocol_shell_key, L"open"));
|
| +
|
| + return true;
|
| + }
|
| +
|
| + // This method returns a list of all the user level registry entries that
|
| // are needed to make Chromium default browser.
|
| static bool GetUserEntries(BrowserDistribution* dist,
|
| const std::wstring& chrome_exe,
|
| @@ -154,25 +215,10 @@ class RegistryEntry {
|
| // Protocols associations.
|
| std::wstring chrome_open = ShellUtil::GetChromeShellOpenCmd(chrome_exe);
|
| std::wstring chrome_icon = ShellUtil::GetChromeIcon(dist, chrome_exe);
|
| - for (int i = 0; ShellUtil::kProtocolAssociations[i] != NULL; i++) {
|
| - std::wstring url_key(ShellUtil::kRegClasses);
|
| - file_util::AppendToPath(&url_key, ShellUtil::kProtocolAssociations[i]);
|
| -
|
| - // <root hkey>\Software\Classes\<protocol>\DefaultIcon
|
| - std::wstring icon_key = url_key + ShellUtil::kRegDefaultIcon;
|
| - entries->push_front(new RegistryEntry(icon_key, chrome_icon));
|
| -
|
| - // <root hkey>\Software\Classes\<protocol>\shell\open\command
|
| - std::wstring shell_key = url_key + ShellUtil::kRegShellOpen;
|
| - entries->push_front(new RegistryEntry(shell_key, chrome_open));
|
| -
|
| - // <root hkey>\Software\Classes\<protocol>\shell\open\ddeexec
|
| - std::wstring dde_key = url_key + L"\\shell\\open\\ddeexec";
|
| - entries->push_front(new RegistryEntry(dde_key, L""));
|
| -
|
| - // <root hkey>\Software\Classes\<protocol>\shell\@
|
| - std::wstring protocol_shell_key = url_key + ShellUtil::kRegShellPath;
|
| - entries->push_front(new RegistryEntry(protocol_shell_key, L"open"));
|
| + for (int i = 0; ShellUtil::kBrowserProtocolAssociations[i] != NULL; i++) {
|
| + GetUserProtocolEntries(dist, chrome_exe, suffix,
|
| + ShellUtil::kBrowserProtocolAssociations[i],
|
| + chrome_icon, chrome_open, entries);
|
| }
|
|
|
| // start->Internet shortcut.
|
| @@ -297,13 +343,36 @@ bool IsChromeRegistered(BrowserDistribution* dist,
|
| return registered;
|
| }
|
|
|
| +// This method checks if Chrome is already registered on the local machine
|
| +// for the requested protocol. It just checks the one value required for this.
|
| +bool IsChromeRegisteredForProtocol(BrowserDistribution* dist,
|
| + const std::wstring& chrome_exe,
|
| + const std::wstring& suffix,
|
| + const std::wstring& protocol) {
|
| + bool registered = true;
|
| + std::list<RegistryEntry*> entries;
|
| + STLElementDeleter<std::list<RegistryEntry*>> entries_deleter(&entries);
|
| + RegistryEntry::GetProtocolCapabilityEntries(dist, chrome_exe, suffix,
|
| + protocol, &entries);
|
| + for (std::list<RegistryEntry*>::const_iterator itr = entries.begin();
|
| + itr != entries.end() && registered; ++itr) {
|
| + // We do not need registered = registered && ... since the loop condition
|
| + // is set to exit early.
|
| + registered = (*itr)->ExistsInHKLM();
|
| + }
|
| + return registered;
|
| +}
|
| +
|
| // This method registers Chrome on Vista by launching an elevated setup.exe.
|
| // That will show the user the standard Vista elevation prompt. If the user
|
| // accepts it the new process will make the necessary changes and return SUCCESS
|
| // that we capture and return.
|
| +// If protocol is non-empty we will also register Chrome as being capable of
|
| +// handling the protocol.
|
| bool ElevateAndRegisterChrome(BrowserDistribution* dist,
|
| const std::wstring& chrome_exe,
|
| - const std::wstring& suffix) {
|
| + const std::wstring& suffix,
|
| + const std::wstring& protocol) {
|
| FilePath exe_path =
|
| FilePath::FromWStringHack(chrome_exe).DirName()
|
| .Append(installer::kSetupExe);
|
| @@ -331,6 +400,11 @@ bool ElevateAndRegisterChrome(BrowserDistribution* dist,
|
| cmd.AppendSwitch(installer::switches::kChromeFrame);
|
| }
|
|
|
| + if (!protocol.empty()) {
|
| + cmd.AppendSwitchNative(
|
| + installer::switches::kRegisterURLProtocol, protocol);
|
| + }
|
| +
|
| DWORD ret_val = 0;
|
| InstallUtil::ExecuteExeAsAdmin(cmd, &ret_val);
|
| if (ret_val == 0)
|
| @@ -396,7 +470,6 @@ bool AnotherUserHasDefaultBrowser(BrowserDistribution* dist,
|
|
|
| } // namespace
|
|
|
| -
|
| const wchar_t* ShellUtil::kRegDefaultIcon = L"\\DefaultIcon";
|
| const wchar_t* ShellUtil::kRegShellPath = L"\\shell";
|
| const wchar_t* ShellUtil::kRegShellOpen = L"\\shell\\open\\command";
|
| @@ -422,8 +495,10 @@ const wchar_t* ShellUtil::kChromeHTMLProgIdDesc = L"Chromium HTML Document";
|
|
|
| const wchar_t* ShellUtil::kFileAssociations[] = {L".htm", L".html", L".shtml",
|
| L".xht", L".xhtml", NULL};
|
| -const wchar_t* ShellUtil::kProtocolAssociations[] = {L"ftp", L"http", L"https",
|
| - NULL};
|
| +const wchar_t* ShellUtil::kBrowserProtocolAssociations[] = {L"ftp", L"http",
|
| + L"https", NULL};
|
| +const wchar_t* ShellUtil::kPotentialProtocolAssociations[] = {L"ftp", L"http",
|
| + L"https", L"mailto", L"webcal", NULL};
|
| const wchar_t* ShellUtil::kRegUrlProtocol = L"URL Protocol";
|
|
|
| bool ShellUtil::AdminNeededForRegistryCleanup(BrowserDistribution* dist,
|
| @@ -636,22 +711,32 @@ bool ShellUtil::MakeChromeDefault(BrowserDistribution* dist,
|
| // browser.
|
| if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
|
| VLOG(1) << "Registering Chrome as default browser on Vista.";
|
| - IApplicationAssociationRegistration* pAAR;
|
| - HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
|
| - NULL, CLSCTX_INPROC, __uuidof(IApplicationAssociationRegistration),
|
| - (void**)&pAAR);
|
| + base::win::ScopedComPtr<IApplicationAssociationRegistration> pAAR;
|
| + HRESULT hr = pAAR.CreateInstance(CLSID_ApplicationAssociationRegistration,
|
| + NULL, CLSCTX_INPROC);
|
| if (SUCCEEDED(hr)) {
|
| std::wstring app_name = dist->GetApplicationName();
|
| std::wstring suffix;
|
| if (ShellUtil::GetUserSpecificDefaultBrowserSuffix(dist, &suffix))
|
| app_name += suffix;
|
|
|
| - hr = pAAR->SetAppAsDefaultAll(app_name.c_str());
|
| - pAAR->Release();
|
| + for (int i = 0;
|
| + SUCCEEDED(hr) && ShellUtil::kBrowserProtocolAssociations[i] != NULL;
|
| + i++) {
|
| + hr = pAAR->SetAppAsDefault(app_name.c_str(),
|
| + ShellUtil::kBrowserProtocolAssociations[i], AT_URLPROTOCOL);
|
| + }
|
| +
|
| + for (int i = 0;
|
| + SUCCEEDED(hr) && ShellUtil::kFileAssociations[i] != NULL; i++) {
|
| + hr = pAAR->SetAppAsDefault(app_name.c_str(),
|
| + ShellUtil::kFileAssociations[i], AT_FILEEXTENSION);
|
| + }
|
| }
|
| if (!SUCCEEDED(hr)) {
|
| ret = false;
|
| - LOG(ERROR) << "Could not make Chrome default browser.";
|
| + LOG(ERROR) << "Could not make Chrome default browser (Vista): HRESULT="
|
| + << hr << ".";
|
| }
|
| }
|
|
|
| @@ -668,13 +753,17 @@ bool ShellUtil::MakeChromeDefault(BrowserDistribution* dist,
|
| RegistryEntry::GetUserEntries(dist, chrome_exe, suffix, &entries);
|
| // Change the default browser for current user.
|
| if ((shell_change & ShellUtil::CURRENT_USER) &&
|
| - !AddRegistryEntries(HKEY_CURRENT_USER, entries))
|
| - ret = false;
|
| + !AddRegistryEntries(HKEY_CURRENT_USER, entries)) {
|
| + ret = false;
|
| + LOG(ERROR) << "Could not make Chrome default browser (XP/current user).";
|
| + }
|
|
|
| // Chrome as default browser at system level.
|
| if ((shell_change & ShellUtil::SYSTEM_LEVEL) &&
|
| - !AddRegistryEntries(HKEY_LOCAL_MACHINE, entries))
|
| + !AddRegistryEntries(HKEY_LOCAL_MACHINE, entries)) {
|
| ret = false;
|
| + LOG(ERROR) << "Could not make Chrome default browser (XP/system level).";
|
| + }
|
|
|
| // Send Windows notification event so that it can update icons for
|
| // file associations.
|
| @@ -682,6 +771,61 @@ bool ShellUtil::MakeChromeDefault(BrowserDistribution* dist,
|
| return ret;
|
| }
|
|
|
| +bool ShellUtil::MakeChromeDefaultProtocolClient(BrowserDistribution* dist,
|
| + const std::wstring& chrome_exe,
|
| + const std::wstring& protocol) {
|
| + if (!dist->CanSetAsDefault())
|
| + return false;
|
| +
|
| + ShellUtil::RegisterChromeForProtocol(dist, chrome_exe, L"", protocol, true);
|
| +
|
| + bool ret = true;
|
| + // First use the new "recommended" way on Vista to make Chrome default
|
| + // protocol handler.
|
| + if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
|
| + VLOG(1) << "Registering Chrome as default handler for " << protocol
|
| + << " on Vista.";
|
| + base::win::ScopedComPtr<IApplicationAssociationRegistration> pAAR;
|
| + HRESULT hr = pAAR.CreateInstance(CLSID_ApplicationAssociationRegistration,
|
| + NULL, CLSCTX_INPROC);
|
| + if (SUCCEEDED(hr)) {
|
| + std::wstring app_name = dist->GetApplicationName();
|
| + std::wstring suffix;
|
| + if (ShellUtil::GetUserSpecificDefaultBrowserSuffix(dist, &suffix))
|
| + app_name += suffix;
|
| +
|
| + hr = pAAR->SetAppAsDefault(app_name.c_str(), protocol.c_str(),
|
| + AT_URLPROTOCOL);
|
| + }
|
| + if (!SUCCEEDED(hr)) {
|
| + ret = false;
|
| + LOG(ERROR) << "Could not make Chrome default protocol client (Vista):"
|
| + << " HRESULT=" << hr << ".";
|
| + }
|
| + }
|
| +
|
| + // Now use the old way to associate Chrome with the desired protocol. This
|
| + // should not be required on Vista but since some applications still read
|
| + // Software\Classes\http key directly, we have to do this on Vista also.
|
| +
|
| + std::list<RegistryEntry*> entries;
|
| + STLElementDeleter<std::list<RegistryEntry*>> entries_deleter(&entries);
|
| + std::wstring suffix;
|
| + if (!GetUserSpecificDefaultBrowserSuffix(dist, &suffix))
|
| + suffix = L"";
|
| + std::wstring chrome_open = ShellUtil::GetChromeShellOpenCmd(chrome_exe);
|
| + std::wstring chrome_icon = ShellUtil::GetChromeIcon(dist, chrome_exe);
|
| + RegistryEntry::GetUserProtocolEntries(dist, chrome_exe, suffix, protocol,
|
| + chrome_icon, chrome_open, &entries);
|
| + // Change the default protocol handler for current user.
|
| + if (!AddRegistryEntries(HKEY_CURRENT_USER, entries)) {
|
| + ret = false;
|
| + LOG(ERROR) << "Could not make Chrome default protocol client (XP).";
|
| + }
|
| +
|
| + return ret;
|
| +}
|
| +
|
| bool ShellUtil::RegisterChromeBrowser(BrowserDistribution* dist,
|
| const std::wstring& chrome_exe,
|
| const std::wstring& unique_suffix,
|
| @@ -716,7 +860,7 @@ bool ShellUtil::RegisterChromeBrowser(BrowserDistribution* dist,
|
| // If user is not an admin and OS is Vista, try to elevate and register.
|
| if (elevate_if_not_admin &&
|
| base::win::GetVersion() >= base::win::VERSION_VISTA &&
|
| - ElevateAndRegisterChrome(dist, chrome_exe, suffix))
|
| + ElevateAndRegisterChrome(dist, chrome_exe, suffix, L""))
|
| return true;
|
|
|
| // If we got to this point then all we can do is create ProgIds under HKCU
|
| @@ -727,6 +871,55 @@ bool ShellUtil::RegisterChromeBrowser(BrowserDistribution* dist,
|
| return AddRegistryEntries(HKEY_CURRENT_USER, entries);
|
| }
|
|
|
| +bool ShellUtil::RegisterChromeForProtocol(BrowserDistribution* dist,
|
| + const std::wstring& chrome_exe,
|
| + const std::wstring& unique_suffix,
|
| + const std::wstring& protocol,
|
| + bool elevate_if_not_admin) {
|
| + if (!dist->CanSetAsDefault())
|
| + return false;
|
| +
|
| + // Figure out we need to append a suffix to the registry entries to
|
| + // make them unique.
|
| + std::wstring suffix;
|
| + if (!unique_suffix.empty()) {
|
| + suffix = unique_suffix;
|
| + } else if (InstallUtil::IsPerUserInstall(chrome_exe.c_str()) &&
|
| + !GetUserSpecificDefaultBrowserSuffix(dist, &suffix) &&
|
| + !AnotherUserHasDefaultBrowser(dist, chrome_exe)) {
|
| + suffix = L"";
|
| + }
|
| +
|
| + // Check if Chromium is already registered with this suffix.
|
| + if (IsChromeRegisteredForProtocol(dist, chrome_exe, suffix, protocol))
|
| + return true;
|
| +
|
| + if (IsUserAnAdmin()) {
|
| + // We can do this operation directly.
|
| + // If we're not registered at all, try to register. If that fails
|
| + // we should give up.
|
| + if (!IsChromeRegistered(dist, chrome_exe, suffix) &&
|
| + !RegisterChromeBrowser(dist, chrome_exe, suffix, false)) {
|
| + return false;
|
| + }
|
| +
|
| + // Write in the capabillity for the protocol.
|
| + std::list<RegistryEntry*> entries;
|
| + STLElementDeleter<std::list<RegistryEntry*>> entries_deleter(&entries);
|
| + RegistryEntry::GetProtocolCapabilityEntries(dist, chrome_exe, suffix,
|
| + protocol, &entries);
|
| + return AddRegistryEntries(HKEY_LOCAL_MACHINE, entries);
|
| + } else if (elevate_if_not_admin &&
|
| + base::win::GetVersion() >= base::win::VERSION_VISTA) {
|
| + // Elevate to do the whole job
|
| + return ElevateAndRegisterChrome(dist, chrome_exe, suffix, protocol);
|
| + } else {
|
| + // we need admin rights to register our capability. If we don't
|
| + // have them and can't elevate, give up.
|
| + return false;
|
| + }
|
| +}
|
| +
|
| bool ShellUtil::RemoveChromeDesktopShortcut(BrowserDistribution* dist,
|
| int shell_change, bool alternate) {
|
| std::wstring shortcut_name;
|
|
|