| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 // chrome_tab.cc : Implementation of DLL Exports. | |
| 6 | |
| 7 // Need to include this before the ATL headers below. | |
| 8 #include "chrome_frame/chrome_tab.h" | |
| 9 | |
| 10 #include <atlsecurity.h> | |
| 11 #include <objbase.h> | |
| 12 | |
| 13 #include "base/at_exit.h" | |
| 14 #include "base/basictypes.h" | |
| 15 #include "base/command_line.h" | |
| 16 #include "base/file_util.h" | |
| 17 #include "base/file_version_info.h" | |
| 18 #include "base/i18n/icu_util.h" | |
| 19 #include "base/logging.h" | |
| 20 #include "base/logging_win.h" | |
| 21 #include "base/path_service.h" | |
| 22 #include "base/process/launch.h" | |
| 23 #include "base/strings/string16.h" | |
| 24 #include "base/strings/string_number_conversions.h" | |
| 25 #include "base/strings/string_piece.h" | |
| 26 #include "base/strings/string_util.h" | |
| 27 #include "base/strings/sys_string_conversions.h" | |
| 28 #include "base/strings/utf_string_conversions.h" | |
| 29 #include "base/win/registry.h" | |
| 30 #include "base/win/windows_version.h" | |
| 31 #include "chrome/common/chrome_constants.h" | |
| 32 #include "chrome/common/chrome_switches.h" | |
| 33 #include "chrome/installer/util/google_update_settings.h" | |
| 34 #include "chrome_frame/bho.h" | |
| 35 #include "chrome_frame/chrome_active_document.h" | |
| 36 #include "chrome_frame/chrome_frame_activex.h" | |
| 37 #include "chrome_frame/chrome_frame_automation.h" | |
| 38 #include "chrome_frame/chrome_frame_reporting.h" | |
| 39 #include "chrome_frame/chrome_launcher_utils.h" | |
| 40 #include "chrome_frame/chrome_protocol.h" | |
| 41 #include "chrome_frame/dll_redirector.h" | |
| 42 #include "chrome_frame/exception_barrier.h" | |
| 43 #include "chrome_frame/pin_module.h" | |
| 44 #include "chrome_frame/resource.h" | |
| 45 #include "chrome_frame/utils.h" | |
| 46 #include "components/variations/entropy_provider.h" | |
| 47 #include "grit/chrome_frame_resources.h" | |
| 48 #include "url/url_util.h" | |
| 49 | |
| 50 #if _ATL_VER >= 0x0C00 | |
| 51 // This was removed between the VS2010 version and the VS2013 version, and | |
| 52 // the unsuffixed version was repurposed to mean 'S'. | |
| 53 #define UpdateRegistryFromResourceS UpdateRegistryFromResource | |
| 54 #endif | |
| 55 | |
| 56 using base::win::RegKey; | |
| 57 | |
| 58 namespace { | |
| 59 | |
| 60 const wchar_t kInternetSettings[] = | |
| 61 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"; | |
| 62 | |
| 63 const wchar_t kProtocolHandlers[] = | |
| 64 L"Software\\Classes\\Protocols\\Handler"; | |
| 65 | |
| 66 const wchar_t kRunOnce[] = | |
| 67 L"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce"; | |
| 68 | |
| 69 const wchar_t kRunKeyName[] = L"ChromeFrameHelper"; | |
| 70 | |
| 71 const wchar_t kChromeFrameHelperExe[] = L"chrome_frame_helper.exe"; | |
| 72 const wchar_t kChromeFrameHelperStartupArg[] = L"--startup"; | |
| 73 | |
| 74 // Window class and window names. | |
| 75 // TODO(robertshield): These and other constants need to be refactored into | |
| 76 // a common chrome_frame_constants.h|cc and built into a separate lib | |
| 77 // (either chrome_frame_utils or make another one). | |
| 78 const wchar_t kChromeFrameHelperWindowClassName[] = | |
| 79 L"ChromeFrameHelperWindowClass"; | |
| 80 const wchar_t kChromeFrameHelperWindowName[] = | |
| 81 L"ChromeFrameHelperWindowName"; | |
| 82 | |
| 83 // {0562BFC3-2550-45b4-BD8E-A310583D3A6F} | |
| 84 const GUID kChromeFrameProvider = | |
| 85 { 0x562bfc3, 0x2550, 0x45b4, | |
| 86 { 0xbd, 0x8e, 0xa3, 0x10, 0x58, 0x3d, 0x3a, 0x6f } }; | |
| 87 | |
| 88 const wchar_t kPostPlatformUAKey[] = | |
| 89 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\" | |
| 90 L"User Agent\\Post Platform"; | |
| 91 const wchar_t kChromeFramePrefix[] = L"chromeframe/"; | |
| 92 | |
| 93 // See comments in DllGetClassObject. | |
| 94 LPFNGETCLASSOBJECT g_dll_get_class_object_redir_ptr = NULL; | |
| 95 | |
| 96 // This function has the side effect of initializing an unprotected | |
| 97 // vector pointer inside GoogleUrl. If this is called during DLL loading, | |
| 98 // it has the effect of avoiding an initialization race on that pointer. | |
| 99 // TODO(siggi): fix GoogleUrl. | |
| 100 void InitGoogleUrl() { | |
| 101 static const char kDummyUrl[] = "http://www.google.com"; | |
| 102 | |
| 103 url_util::IsStandard(kDummyUrl, | |
| 104 url_parse::MakeRange(0, arraysize(kDummyUrl))); | |
| 105 } | |
| 106 | |
| 107 class ChromeTabModule : public CAtlDllModuleT<ChromeTabModule> { | |
| 108 public: | |
| 109 typedef CAtlDllModuleT<ChromeTabModule> ParentClass; | |
| 110 | |
| 111 ChromeTabModule() : do_system_registration_(true), | |
| 112 crash_reporting_(NULL), | |
| 113 icu_initialized_(false) {} | |
| 114 | |
| 115 DECLARE_LIBID(LIBID_ChromeTabLib) | |
| 116 DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CHROMETAB, | |
| 117 "{FD9B1B31-F4D8-436A-8F4F-D3C2E36733D3}") | |
| 118 | |
| 119 // Override to add our SYSTIME binary value to registry scripts. | |
| 120 // See chrome_frame_activex.rgs for usage. | |
| 121 virtual HRESULT AddCommonRGSReplacements(IRegistrarBase* registrar) throw() { | |
| 122 HRESULT hr = ParentClass::AddCommonRGSReplacements(registrar); | |
| 123 | |
| 124 if (SUCCEEDED(hr)) { | |
| 125 SYSTEMTIME local_time; | |
| 126 ::GetSystemTime(&local_time); | |
| 127 std::string hex(base::HexEncode(&local_time, sizeof(local_time))); | |
| 128 base::StringPiece sp_hex(hex); | |
| 129 hr = registrar->AddReplacement(L"SYSTIME", | |
| 130 base::SysNativeMBToWide(sp_hex).c_str()); | |
| 131 DCHECK(SUCCEEDED(hr)); | |
| 132 } | |
| 133 | |
| 134 if (SUCCEEDED(hr)) { | |
| 135 base::FilePath app_path = | |
| 136 chrome_launcher::GetChromeExecutablePath().DirName(); | |
| 137 hr = registrar->AddReplacement(L"CHROME_APPPATH", | |
| 138 app_path.value().c_str()); | |
| 139 DCHECK(SUCCEEDED(hr)); | |
| 140 } | |
| 141 | |
| 142 if (SUCCEEDED(hr)) { | |
| 143 hr = registrar->AddReplacement(L"CHROME_APPNAME", | |
| 144 chrome::kBrowserProcessExecutableName); | |
| 145 DCHECK(SUCCEEDED(hr)); | |
| 146 | |
| 147 // Fill in VERSION from the VERSIONINFO stored in the DLL's resources. | |
| 148 scoped_ptr<FileVersionInfo> module_version_info( | |
| 149 FileVersionInfo::CreateFileVersionInfoForCurrentModule()); | |
| 150 DCHECK(module_version_info != NULL); | |
| 151 std::wstring file_version(module_version_info->file_version()); | |
| 152 hr = registrar->AddReplacement(L"VERSION", file_version.c_str()); | |
| 153 DCHECK(SUCCEEDED(hr)); | |
| 154 } | |
| 155 | |
| 156 if (SUCCEEDED(hr)) { | |
| 157 // Add the directory of chrome_launcher.exe. This will be the same | |
| 158 // as the directory for the current DLL. | |
| 159 std::wstring module_dir; | |
| 160 base::FilePath module_path; | |
| 161 if (PathService::Get(base::FILE_MODULE, &module_path)) { | |
| 162 module_dir = module_path.DirName().value(); | |
| 163 } else { | |
| 164 NOTREACHED(); | |
| 165 } | |
| 166 hr = registrar->AddReplacement(L"CHROME_LAUNCHER_APPPATH", | |
| 167 module_dir.c_str()); | |
| 168 DCHECK(SUCCEEDED(hr)); | |
| 169 } | |
| 170 | |
| 171 if (SUCCEEDED(hr)) { | |
| 172 // Add the filename of chrome_launcher.exe | |
| 173 hr = registrar->AddReplacement(L"CHROME_LAUNCHER_APPNAME", | |
| 174 chrome_launcher::kLauncherExeBaseName); | |
| 175 DCHECK(SUCCEEDED(hr)); | |
| 176 } | |
| 177 | |
| 178 if (SUCCEEDED(hr)) { | |
| 179 // Add the registry hive to use. | |
| 180 // Note: This is ugly as hell. I'd rather use the pMapEntries parameter | |
| 181 // to CAtlModule::UpdateRegistryFromResource, unfortunately we have a | |
| 182 // few components that are registered by calling their | |
| 183 // static T::UpdateRegistry() methods directly, which doesn't allow | |
| 184 // pMapEntries to be passed through :-( | |
| 185 if (do_system_registration_) { | |
| 186 hr = registrar->AddReplacement(L"HIVE", L"HKLM"); | |
| 187 } else { | |
| 188 hr = registrar->AddReplacement(L"HIVE", L"HKCU"); | |
| 189 } | |
| 190 DCHECK(SUCCEEDED(hr)); | |
| 191 } | |
| 192 | |
| 193 if (SUCCEEDED(hr)) { | |
| 194 // Add the Chrome Frame CLSID. | |
| 195 wchar_t cf_clsid[64]; | |
| 196 StringFromGUID2(CLSID_ChromeFrame, &cf_clsid[0], arraysize(cf_clsid)); | |
| 197 hr = registrar->AddReplacement(L"CHROME_FRAME_CLSID", &cf_clsid[0]); | |
| 198 } | |
| 199 | |
| 200 return hr; | |
| 201 } | |
| 202 | |
| 203 // The module is "locked" when an object takes a reference on it. The first | |
| 204 // time it is locked, take a reference on crash reporting to bind its lifetime | |
| 205 // to the module and initialize ICU. | |
| 206 virtual LONG Lock() throw() { | |
| 207 LONG result = ParentClass::Lock(); | |
| 208 if (result == 1) { | |
| 209 DCHECK_EQ(crash_reporting_, | |
| 210 static_cast<chrome_frame::ScopedCrashReporting*>(NULL)); | |
| 211 crash_reporting_ = new chrome_frame::ScopedCrashReporting(); | |
| 212 | |
| 213 // Initialize ICU if this is the first time the module has been locked. | |
| 214 if (!icu_initialized_) { | |
| 215 icu_initialized_ = true; | |
| 216 // Best-effort since something is better than nothing here. | |
| 217 ignore_result(base::i18n::InitializeICU()); | |
| 218 } | |
| 219 } | |
| 220 return result; | |
| 221 } | |
| 222 | |
| 223 // The module is "unlocked" when an object that had a reference on it is | |
| 224 // destroyed. The last time it is unlocked, release the reference on crash | |
| 225 // reporting. | |
| 226 virtual LONG Unlock() throw() { | |
| 227 LONG result = ParentClass::Unlock(); | |
| 228 if (!result) { | |
| 229 DCHECK_NE(crash_reporting_, | |
| 230 static_cast<chrome_frame::ScopedCrashReporting*>(NULL)); | |
| 231 delete crash_reporting_; | |
| 232 crash_reporting_ = NULL; | |
| 233 } | |
| 234 return result; | |
| 235 } | |
| 236 | |
| 237 // See comments in AddCommonRGSReplacements | |
| 238 bool do_system_registration_; | |
| 239 | |
| 240 private: | |
| 241 // A scoper created when the module is initially locked and destroyed when it | |
| 242 // is finally unlocked. This is not a scoped_ptr since that could cause | |
| 243 // reporting to shut down at exit, which would lead to problems with the | |
| 244 // loader lock. | |
| 245 chrome_frame::ScopedCrashReporting* crash_reporting_; | |
| 246 | |
| 247 // Initially false, this is flipped to true to indicate that ICU has been | |
| 248 // initialized for the module. | |
| 249 bool icu_initialized_; | |
| 250 }; | |
| 251 | |
| 252 ChromeTabModule _AtlModule; | |
| 253 | |
| 254 base::AtExitManager* g_exit_manager = NULL; | |
| 255 | |
| 256 HRESULT RefreshElevationPolicy() { | |
| 257 const wchar_t kIEFrameDll[] = L"ieframe.dll"; | |
| 258 const char kIERefreshPolicy[] = "IERefreshElevationPolicy"; | |
| 259 HRESULT hr = E_NOTIMPL; | |
| 260 | |
| 261 // Stick an SEH in the chain to prevent the VEH from picking up on first | |
| 262 // chance exceptions caused by loading ieframe.dll. Use the vanilla | |
| 263 // ExceptionBarrier to report any exceptions that do make their way to us | |
| 264 // though. | |
| 265 ExceptionBarrier barrier; | |
| 266 | |
| 267 HMODULE ieframe_module = LoadLibrary(kIEFrameDll); | |
| 268 if (ieframe_module) { | |
| 269 typedef HRESULT (__stdcall *IERefreshPolicy)(); | |
| 270 IERefreshPolicy ie_refresh_policy = reinterpret_cast<IERefreshPolicy>( | |
| 271 GetProcAddress(ieframe_module, kIERefreshPolicy)); | |
| 272 | |
| 273 if (ie_refresh_policy) { | |
| 274 hr = ie_refresh_policy(); | |
| 275 } else { | |
| 276 hr = HRESULT_FROM_WIN32(GetLastError()); | |
| 277 } | |
| 278 | |
| 279 FreeLibrary(ieframe_module); | |
| 280 } else { | |
| 281 hr = HRESULT_FROM_WIN32(GetLastError()); | |
| 282 } | |
| 283 | |
| 284 return hr; | |
| 285 } | |
| 286 | |
| 287 // Experimental boot prefetch optimization for Chrome Frame | |
| 288 // | |
| 289 // If chrome is warmed up during a single reboot, it gets paged | |
| 290 // in for subsequent reboots and the cold startup times essentially | |
| 291 // look like warm times thereafter! The 'warm up' is done by | |
| 292 // setting up a 'RunOnce' key during DLLRegisterServer of | |
| 293 // npchrome_frame.dll. | |
| 294 // | |
| 295 // This works because chrome prefetch becomes part of boot | |
| 296 // prefetch file ntosboot-b00dfaad.pf and paged in on subsequent | |
| 297 // reboots. As long as the sytem does not undergo significant | |
| 298 // memory pressure those pages remain in memory and we get pretty | |
| 299 // amazing startup times, down to about 300 ms from 1200 ms | |
| 300 // | |
| 301 // The downside is: | |
| 302 // - Whether chrome frame is used or not, there's a read penalty | |
| 303 // (1200-300 =) 900 ms for every boot. | |
| 304 // - Heavy system memory usage after reboot will nullify the benefits | |
| 305 // but the user will still pay the cost. | |
| 306 // - Overall the time saved will always be less than total time spent | |
| 307 // paging in chrome | |
| 308 // - We are not sure when the chrome 'warm up' will age out from the | |
| 309 // boot prefetch file. | |
| 310 // | |
| 311 // The idea here is to try this out on chrome frame dev channel | |
| 312 // and see if it produces a significant drift in startup numbers. | |
| 313 HRESULT SetupRunOnce() { | |
| 314 HRESULT result = E_FAIL; | |
| 315 | |
| 316 base::string16 channel_name; | |
| 317 if (base::win::GetVersion() < base::win::VERSION_VISTA && | |
| 318 GoogleUpdateSettings::GetChromeChannelAndModifiers(true, &channel_name)) { | |
| 319 std::transform(channel_name.begin(), channel_name.end(), | |
| 320 channel_name.begin(), tolower); | |
| 321 // Use this only for the dev channel. | |
| 322 if (channel_name.find(L"dev") != base::string16::npos) { | |
| 323 HKEY hive = HKEY_CURRENT_USER; | |
| 324 if (IsSystemProcess()) { | |
| 325 // For system installs, our updates will be running as SYSTEM which | |
| 326 // makes writing to a RunOnce key under HKCU not so terribly useful. | |
| 327 hive = HKEY_LOCAL_MACHINE; | |
| 328 } | |
| 329 | |
| 330 RegKey run_once; | |
| 331 LONG ret = run_once.Create(hive, kRunOnce, KEY_READ | KEY_WRITE); | |
| 332 if (ret == ERROR_SUCCESS) { | |
| 333 CommandLine run_once_cmd(chrome_launcher::GetChromeExecutablePath()); | |
| 334 run_once_cmd.AppendSwitchASCII(switches::kAutomationClientChannelID, | |
| 335 "0"); | |
| 336 run_once_cmd.AppendSwitch(switches::kChromeFrame); | |
| 337 ret = run_once.WriteValue(L"A", | |
| 338 run_once_cmd.GetCommandLineString().c_str()); | |
| 339 } | |
| 340 result = HRESULT_FROM_WIN32(ret); | |
| 341 } else { | |
| 342 result = S_FALSE; | |
| 343 } | |
| 344 } else { | |
| 345 // We're on a non-XP version of Windows or on a stable channel. Nothing | |
| 346 // needs doing. | |
| 347 result = S_FALSE; | |
| 348 } | |
| 349 | |
| 350 return result; | |
| 351 } | |
| 352 | |
| 353 // Helper method called for user-level installs where we don't have admin | |
| 354 // permissions. Starts up the long running process and registers it to get it | |
| 355 // started at next boot. | |
| 356 HRESULT SetupUserLevelHelper() { | |
| 357 HRESULT hr = S_OK; | |
| 358 | |
| 359 // Remove existing run-at-startup entry. | |
| 360 base::win::RemoveCommandFromAutoRun(HKEY_CURRENT_USER, kRunKeyName); | |
| 361 | |
| 362 // Build the chrome_frame_helper command line. | |
| 363 base::FilePath module_path; | |
| 364 base::FilePath helper_path; | |
| 365 if (PathService::Get(base::FILE_MODULE, &module_path)) { | |
| 366 module_path = module_path.DirName(); | |
| 367 helper_path = module_path.Append(kChromeFrameHelperExe); | |
| 368 if (!base::PathExists(helper_path)) { | |
| 369 // If we can't find the helper in the current directory, try looking | |
| 370 // one up (this is the layout in the build output folder). | |
| 371 module_path = module_path.DirName(); | |
| 372 helper_path = module_path.Append(kChromeFrameHelperExe); | |
| 373 DCHECK(base::PathExists(helper_path)) << | |
| 374 "Could not find chrome_frame_helper.exe."; | |
| 375 } | |
| 376 | |
| 377 // Find window handle of existing instance. | |
| 378 HWND old_window = FindWindow(kChromeFrameHelperWindowClassName, | |
| 379 kChromeFrameHelperWindowName); | |
| 380 | |
| 381 if (base::PathExists(helper_path)) { | |
| 382 std::wstring helper_path_cmd(L"\""); | |
| 383 helper_path_cmd += helper_path.value(); | |
| 384 helper_path_cmd += L"\" "; | |
| 385 helper_path_cmd += kChromeFrameHelperStartupArg; | |
| 386 | |
| 387 // Add new run-at-startup entry. | |
| 388 if (!base::win::AddCommandToAutoRun(HKEY_CURRENT_USER, kRunKeyName, | |
| 389 helper_path_cmd)) { | |
| 390 hr = E_FAIL; | |
| 391 LOG(ERROR) << "Could not add helper process to auto run key."; | |
| 392 } | |
| 393 | |
| 394 // Start new instance. | |
| 395 base::LaunchOptions options; | |
| 396 options.start_hidden = true; | |
| 397 bool launched = base::LaunchProcess(helper_path.value(), options, NULL); | |
| 398 if (!launched) { | |
| 399 hr = E_FAIL; | |
| 400 PLOG(DFATAL) << "Could not launch helper process."; | |
| 401 } | |
| 402 | |
| 403 // Kill old instance using window handle. | |
| 404 if (IsWindow(old_window)) { | |
| 405 BOOL result = PostMessage(old_window, WM_CLOSE, 0, 0); | |
| 406 if (!result) { | |
| 407 PLOG(ERROR) << "Failed to post close message to old helper process: "; | |
| 408 } | |
| 409 } | |
| 410 } else { | |
| 411 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); | |
| 412 } | |
| 413 } else { | |
| 414 hr = E_UNEXPECTED; | |
| 415 NOTREACHED(); | |
| 416 } | |
| 417 | |
| 418 return hr; | |
| 419 } | |
| 420 | |
| 421 // To delete the user agent, set value to NULL. | |
| 422 // The is_system parameter indicates whether this is a per machine or a per | |
| 423 // user installation. | |
| 424 HRESULT SetChromeFrameUA(bool is_system, const wchar_t* value) { | |
| 425 HRESULT hr = E_FAIL; | |
| 426 HKEY parent_hive = is_system ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; | |
| 427 | |
| 428 RegKey ua_key; | |
| 429 LONG reg_result = ua_key.Create(parent_hive, kPostPlatformUAKey, | |
| 430 KEY_READ | KEY_WRITE); | |
| 431 if (reg_result == ERROR_SUCCESS) { | |
| 432 // Make sure that we unregister ChromeFrame UA strings registered previously | |
| 433 wchar_t value_name[MAX_PATH + 1] = {}; | |
| 434 wchar_t value_data[MAX_PATH + 1] = {}; | |
| 435 | |
| 436 DWORD value_index = 0; | |
| 437 while (value_index < ua_key.GetValueCount()) { | |
| 438 DWORD name_size = arraysize(value_name); | |
| 439 DWORD value_size = arraysize(value_data); | |
| 440 DWORD type = 0; | |
| 441 LRESULT ret = ::RegEnumValue(ua_key.Handle(), value_index, value_name, | |
| 442 &name_size, NULL, &type, | |
| 443 reinterpret_cast<BYTE*>(value_data), | |
| 444 &value_size); | |
| 445 if (ret == ERROR_SUCCESS) { | |
| 446 if (StartsWith(value_name, kChromeFramePrefix, false)) { | |
| 447 ua_key.DeleteValue(value_name); | |
| 448 } else { | |
| 449 ++value_index; | |
| 450 } | |
| 451 } else { | |
| 452 break; | |
| 453 } | |
| 454 } | |
| 455 | |
| 456 std::wstring chrome_frame_ua_value_name = kChromeFramePrefix; | |
| 457 chrome_frame_ua_value_name += GetCurrentModuleVersion(); | |
| 458 if (value) { | |
| 459 ua_key.WriteValue(chrome_frame_ua_value_name.c_str(), value); | |
| 460 } | |
| 461 hr = S_OK; | |
| 462 } else { | |
| 463 DLOG(ERROR) << __FUNCTION__ << ": " << kPostPlatformUAKey | |
| 464 << ", error code = " << reg_result; | |
| 465 hr = HRESULT_FROM_WIN32(reg_result); | |
| 466 } | |
| 467 return hr; | |
| 468 } | |
| 469 | |
| 470 class SecurityDescBackup { | |
| 471 public: | |
| 472 explicit SecurityDescBackup(const std::wstring& backup_key) | |
| 473 : backup_key_name_(backup_key) {} | |
| 474 ~SecurityDescBackup() {} | |
| 475 | |
| 476 // Save given security descriptor to the backup key. | |
| 477 bool SaveSecurity(const CSecurityDesc& sd) { | |
| 478 CString str; | |
| 479 if (!sd.ToString(&str)) | |
| 480 return false; | |
| 481 | |
| 482 RegKey backup_key(HKEY_LOCAL_MACHINE, backup_key_name_.c_str(), | |
| 483 KEY_READ | KEY_WRITE); | |
| 484 if (backup_key.Valid()) { | |
| 485 return backup_key.WriteValue(NULL, str.GetString()) == ERROR_SUCCESS; | |
| 486 } | |
| 487 | |
| 488 return false; | |
| 489 } | |
| 490 | |
| 491 // Restore security descriptor from backup key to given key name. | |
| 492 bool RestoreSecurity(const wchar_t* key_name) { | |
| 493 std::wstring sddl; | |
| 494 if (!ReadBackupKey(&sddl)) | |
| 495 return false; | |
| 496 | |
| 497 // Create security descriptor from string. | |
| 498 CSecurityDesc sd; | |
| 499 if (!sd.FromString(sddl.c_str())) | |
| 500 return false; | |
| 501 | |
| 502 bool result = true; | |
| 503 // Restore DACL and Owner of the key from saved security descriptor. | |
| 504 CDacl dacl; | |
| 505 CSid owner; | |
| 506 sd.GetDacl(&dacl); | |
| 507 sd.GetOwner(&owner); | |
| 508 | |
| 509 DWORD error = ::SetNamedSecurityInfo(const_cast<wchar_t*>(key_name), | |
| 510 SE_REGISTRY_KEY, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, | |
| 511 const_cast<SID*>(owner.GetPSID()), NULL, | |
| 512 const_cast<ACL*>(dacl.GetPACL()), NULL); | |
| 513 | |
| 514 DeleteBackupKey(); | |
| 515 return (error == ERROR_SUCCESS); | |
| 516 } | |
| 517 | |
| 518 private: | |
| 519 // Read SDDL string from backup key | |
| 520 bool ReadBackupKey(std::wstring* sddl) { | |
| 521 RegKey backup_key(HKEY_LOCAL_MACHINE, backup_key_name_.c_str(), KEY_READ); | |
| 522 if (!backup_key.Valid()) | |
| 523 return false; | |
| 524 | |
| 525 DWORD len = 0; | |
| 526 DWORD reg_type = REG_NONE; | |
| 527 if (backup_key.ReadValue(NULL, NULL, &len, ®_type) != ERROR_SUCCESS) | |
| 528 return false; | |
| 529 DCHECK_EQ(0u, len % sizeof(wchar_t)); | |
| 530 | |
| 531 if ((len == 0) || (reg_type != REG_SZ)) | |
| 532 return false; | |
| 533 | |
| 534 size_t wchar_count = 1 + len / sizeof(wchar_t); | |
| 535 if (backup_key.ReadValue(NULL, WriteInto(sddl, wchar_count), &len, | |
| 536 ®_type) != ERROR_SUCCESS) { | |
| 537 return false; | |
| 538 } | |
| 539 | |
| 540 return true; | |
| 541 } | |
| 542 | |
| 543 void DeleteBackupKey() { | |
| 544 ::RegDeleteKey(HKEY_LOCAL_MACHINE, backup_key_name_.c_str()); | |
| 545 } | |
| 546 | |
| 547 std::wstring backup_key_name_; | |
| 548 }; | |
| 549 | |
| 550 struct TokenWithPrivileges { | |
| 551 TokenWithPrivileges() { | |
| 552 token_.GetEffectiveToken(TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY); | |
| 553 token_.GetUser(&user_); | |
| 554 } | |
| 555 | |
| 556 ~TokenWithPrivileges() { | |
| 557 token_.EnableDisablePrivileges(take_ownership_); | |
| 558 token_.EnableDisablePrivileges(restore_); | |
| 559 } | |
| 560 | |
| 561 bool EnablePrivileges() { | |
| 562 if (take_ownership_.GetCount() == 0) | |
| 563 if (!token_.EnablePrivilege(L"SeTakeOwnershipPrivilege", | |
| 564 &take_ownership_)) | |
| 565 return false; | |
| 566 | |
| 567 if (restore_.GetCount() == 0) | |
| 568 if (!token_.EnablePrivilege(L"SeRestorePrivilege", &restore_)) | |
| 569 return false; | |
| 570 | |
| 571 return true; | |
| 572 } | |
| 573 | |
| 574 const CSid& GetUser() const { | |
| 575 return user_; | |
| 576 } | |
| 577 | |
| 578 private: | |
| 579 CAccessToken token_; | |
| 580 CTokenPrivileges take_ownership_; | |
| 581 CTokenPrivileges restore_; | |
| 582 CSid user_; | |
| 583 }; | |
| 584 | |
| 585 const wchar_t* const kMimeHandlerKeyValues[] = { | |
| 586 L"ChromeTab.ChromeActiveDocument", | |
| 587 L"ChromeTab.ChromeActiveDocument.1", | |
| 588 }; | |
| 589 | |
| 590 // Returns true if the values are present or absent in |root_key|'s Secure Mime | |
| 591 // Handlers key based on |for_installed|. Returns false if the values are not as | |
| 592 // expected or if an error occurred. | |
| 593 bool MimeHandlerKeyIsConfigured(bool for_install, HKEY root_key) { | |
| 594 base::string16 key_name(kInternetSettings); | |
| 595 key_name.append(L"\\Secure Mime Handlers"); | |
| 596 RegKey key(root_key, key_name.c_str(), KEY_QUERY_VALUE); | |
| 597 if (!key.Valid()) | |
| 598 return false; | |
| 599 | |
| 600 for (size_t i = 0; i < arraysize(kMimeHandlerKeyValues); ++i) { | |
| 601 DWORD value = 0; | |
| 602 LONG result = key.ReadValueDW(kMimeHandlerKeyValues[i], &value); | |
| 603 if (for_install) { | |
| 604 if (result != ERROR_SUCCESS || value != 1) | |
| 605 return false; | |
| 606 } else { | |
| 607 if (result != ERROR_FILE_NOT_FOUND) | |
| 608 return false; | |
| 609 } | |
| 610 } | |
| 611 return true; | |
| 612 } | |
| 613 | |
| 614 HRESULT SetOrDeleteMimeHandlerKey(bool set, HKEY root_key) { | |
| 615 base::string16 key_name(kInternetSettings); | |
| 616 key_name.append(L"\\Secure Mime Handlers"); | |
| 617 RegKey key(root_key, key_name.c_str(), KEY_SET_VALUE); | |
| 618 if (!key.Valid()) | |
| 619 return false; | |
| 620 | |
| 621 HRESULT result = S_OK; | |
| 622 for (size_t i = 0; i < arraysize(kMimeHandlerKeyValues); ++i) { | |
| 623 LONG intermediate = set ? | |
| 624 key.WriteValue(kMimeHandlerKeyValues[i], 1) : | |
| 625 key.DeleteValue(kMimeHandlerKeyValues[i]); | |
| 626 if (intermediate != ERROR_SUCCESS && result == S_OK) | |
| 627 result = HRESULT_FROM_WIN32(intermediate); | |
| 628 } | |
| 629 return result; | |
| 630 } | |
| 631 | |
| 632 void OnPinModule() { | |
| 633 // Pin crash reporting by leaking a reference. | |
| 634 ignore_result(new chrome_frame::ScopedCrashReporting()); | |
| 635 } | |
| 636 | |
| 637 // Chrome Frame registration functions. | |
| 638 //----------------------------------------------------------------------------- | |
| 639 HRESULT RegisterSecuredMimeHandler(bool enable, bool is_system) { | |
| 640 if (MimeHandlerKeyIsConfigured(enable, HKEY_LOCAL_MACHINE)) | |
| 641 return S_OK; | |
| 642 if (!is_system) | |
| 643 return SetOrDeleteMimeHandlerKey(enable, HKEY_CURRENT_USER); | |
| 644 if (base::win::GetVersion() < base::win::VERSION_VISTA) | |
| 645 return SetOrDeleteMimeHandlerKey(enable, HKEY_LOCAL_MACHINE); | |
| 646 | |
| 647 std::wstring mime_key = kInternetSettings; | |
| 648 mime_key.append(L"\\Secure Mime Handlers"); | |
| 649 std::wstring backup_key = kInternetSettings; | |
| 650 backup_key.append(L"\\__backup_SMH__"); | |
| 651 std::wstring object_name = L"MACHINE\\"; | |
| 652 object_name.append(mime_key); | |
| 653 | |
| 654 TokenWithPrivileges token_; | |
| 655 if (!token_.EnablePrivileges()) | |
| 656 return E_ACCESSDENIED; | |
| 657 | |
| 658 // If there is a backup key - something bad happened; try to restore | |
| 659 // security on "Secure Mime Handlers" from the backup. | |
| 660 SecurityDescBackup backup(backup_key); | |
| 661 backup.RestoreSecurity(object_name.c_str()); | |
| 662 | |
| 663 // Read old security descriptor of the Mime key first. | |
| 664 CSecurityDesc sd; | |
| 665 if (!AtlGetSecurityDescriptor(object_name.c_str(), SE_REGISTRY_KEY, &sd)) { | |
| 666 return E_FAIL; | |
| 667 } | |
| 668 | |
| 669 backup.SaveSecurity(sd); | |
| 670 HRESULT hr = E_FAIL; | |
| 671 // set new owner | |
| 672 if (AtlSetOwnerSid(object_name.c_str(), SE_REGISTRY_KEY, token_.GetUser())) { | |
| 673 // set new dacl | |
| 674 CDacl new_dacl; | |
| 675 sd.GetDacl(&new_dacl); | |
| 676 new_dacl.AddAllowedAce(token_.GetUser(), GENERIC_WRITE | GENERIC_READ); | |
| 677 if (AtlSetDacl(object_name.c_str(), SE_REGISTRY_KEY, new_dacl)) { | |
| 678 hr = SetOrDeleteMimeHandlerKey(enable, HKEY_LOCAL_MACHINE); | |
| 679 } | |
| 680 } | |
| 681 | |
| 682 backup.RestoreSecurity(object_name.c_str()); | |
| 683 return hr; | |
| 684 } | |
| 685 | |
| 686 HRESULT RegisterActiveDoc(bool reg, bool is_system) { | |
| 687 // We have to call the static T::UpdateRegistry function instead of | |
| 688 // _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_ACTIVEDOC, reg) | |
| 689 // because there is specific OLEMISC replacement. | |
| 690 return ChromeActiveDocument::UpdateRegistry(reg); | |
| 691 } | |
| 692 | |
| 693 HRESULT RegisterActiveX(bool reg, bool is_system) { | |
| 694 // We have to call the static T::UpdateRegistry function instead of | |
| 695 // _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_ACTIVEX, reg) | |
| 696 // because there is specific OLEMISC replacement. | |
| 697 return ChromeFrameActivex::UpdateRegistry(reg); | |
| 698 } | |
| 699 | |
| 700 HRESULT RegisterElevationPolicy(bool reg, bool is_system) { | |
| 701 HRESULT hr = S_OK; | |
| 702 if (base::win::GetVersion() >= base::win::VERSION_VISTA) { | |
| 703 // Register the elevation policy. This must succeed for Chrome Frame to | |
| 704 // be able launch Chrome when running in low-integrity IE. | |
| 705 hr = _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_ELEVATION, reg); | |
| 706 if (SUCCEEDED(hr)) { | |
| 707 // Ignore failures since old versions of IE 7 (e.g., 7.0.6000.16386, which | |
| 708 // shipped with Vista RTM) do not export IERefreshElevationPolicy. | |
| 709 RefreshElevationPolicy(); | |
| 710 } | |
| 711 } | |
| 712 return hr; | |
| 713 } | |
| 714 | |
| 715 HRESULT RegisterProtocol(bool reg, bool is_system) { | |
| 716 return _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEPROTOCOL, reg); | |
| 717 } | |
| 718 | |
| 719 HRESULT RegisterBhoClsid(bool reg, bool is_system) { | |
| 720 return Bho::UpdateRegistry(reg); | |
| 721 } | |
| 722 | |
| 723 HRESULT RegisterBhoIE(bool reg, bool is_system) { | |
| 724 if (is_system) { | |
| 725 return _AtlModule.UpdateRegistryFromResourceS(IDR_REGISTER_BHO, reg); | |
| 726 } else { | |
| 727 if (reg) { | |
| 728 // Setup the long running process: | |
| 729 return SetupUserLevelHelper(); | |
| 730 } else { | |
| 731 // Unschedule the user-level helper. Note that we don't kill it here | |
| 732 // so that during updates we don't have a time window with no running | |
| 733 // helper. Uninstalls and updates will explicitly kill the helper from | |
| 734 // within the installer. Unregister existing run-at-startup entry. | |
| 735 return base::win::RemoveCommandFromAutoRun(HKEY_CURRENT_USER, | |
| 736 kRunKeyName) ? S_OK : E_FAIL; | |
| 737 } | |
| 738 } | |
| 739 } | |
| 740 | |
| 741 HRESULT RegisterTypeLib(bool reg, bool is_system) { | |
| 742 if (reg && !is_system) { | |
| 743 // Enables the RegisterTypeLib Function function to override default | |
| 744 // registry mappings under Windows Vista Service Pack 1 (SP1), | |
| 745 // Windows Server 2008, and later operating system versions | |
| 746 typedef void (WINAPI* OaEnablePerUserTypeLibReg)(void); | |
| 747 OaEnablePerUserTypeLibReg per_user_typelib_func = | |
| 748 reinterpret_cast<OaEnablePerUserTypeLibReg>( | |
| 749 GetProcAddress(GetModuleHandle(L"oleaut32.dll"), | |
| 750 "OaEnablePerUserTLibRegistration")); | |
| 751 if (per_user_typelib_func) { | |
| 752 (*per_user_typelib_func)(); | |
| 753 } | |
| 754 } | |
| 755 return reg ? | |
| 756 UtilRegisterTypeLib(_AtlComModule.m_hInstTypeLib, | |
| 757 NULL, !is_system) : | |
| 758 UtilUnRegisterTypeLib(_AtlComModule.m_hInstTypeLib, | |
| 759 NULL, !is_system); | |
| 760 } | |
| 761 | |
| 762 HRESULT RegisterLegacyNPAPICleanup(bool reg, bool is_system) { | |
| 763 if (!reg) { | |
| 764 _AtlModule.UpdateRegistryFromResourceS(IDR_CHROMEFRAME_NPAPI, reg); | |
| 765 UtilRemovePersistentNPAPIMarker(); | |
| 766 } | |
| 767 // Ignore failures. | |
| 768 return S_OK; | |
| 769 } | |
| 770 | |
| 771 HRESULT RegisterAppId(bool reg, bool is_system) { | |
| 772 return _AtlModule.UpdateRegistryAppId(reg); | |
| 773 } | |
| 774 | |
| 775 HRESULT RegisterUserAgent(bool reg, bool is_system) { | |
| 776 if (reg) { | |
| 777 return SetChromeFrameUA(is_system, L"1"); | |
| 778 } else { | |
| 779 return SetChromeFrameUA(is_system, NULL); | |
| 780 } | |
| 781 } | |
| 782 | |
| 783 enum RegistrationStepId { | |
| 784 kStepSecuredMimeHandler = 0, | |
| 785 kStepActiveDoc = 1, | |
| 786 kStepActiveX = 2, | |
| 787 kStepElevationPolicy = 3, | |
| 788 kStepProtocol = 4, | |
| 789 kStepBhoClsid = 5, | |
| 790 kStepBhoRegistration = 6, | |
| 791 kStepRegisterTypeLib = 7, | |
| 792 kStepNpapiCleanup = 8, | |
| 793 kStepAppId = 9, | |
| 794 kStepUserAgent = 10, | |
| 795 kStepEnd = 11 | |
| 796 }; | |
| 797 | |
| 798 enum RegistrationFlags { | |
| 799 ACTIVEX = 0x0001, | |
| 800 ACTIVEDOC = 0x0002, | |
| 801 GCF_PROTOCOL = 0x0004, | |
| 802 BHO_CLSID = 0x0008, | |
| 803 BHO_REGISTRATION = 0x0010, | |
| 804 TYPELIB = 0x0020, | |
| 805 | |
| 806 ALL = 0xFFFF | |
| 807 }; | |
| 808 | |
| 809 // Mux the failure step into the hresult. We take only the first four bits | |
| 810 // and stick those into the top four bits of the facility code. We also set the | |
| 811 // Customer bit to be polite. Graphically, we write our error code to the | |
| 812 // bits marked with ^: | |
| 813 // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 | |
| 814 // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 | |
| 815 // +---+-+-+-----------------------+-------------------------------+ | |
| 816 // |Sev|C|R| Facility | Code | | |
| 817 // +---+-+-+-----------------------+-------------------------------+ | |
| 818 // ^ ^ ^ ^ ^ | |
| 819 // See http://msdn.microsoft.com/en-us/library/cc231198(PROT.10).aspx for | |
| 820 // more details on HRESULTS. | |
| 821 // | |
| 822 // The resulting error can be extracted by: | |
| 823 // error_code = (fiddled_hr & 0x07800000) >> 23 | |
| 824 HRESULT MuxErrorIntoHRESULT(HRESULT hr, int error_code) { | |
| 825 DCHECK_GE(error_code, 0); | |
| 826 DCHECK_LT(error_code, kStepEnd); | |
| 827 COMPILE_ASSERT(kStepEnd <= 0xF, update_error_muxing_too_many_steps); | |
| 828 | |
| 829 // Check that our four desired bits are clear. | |
| 830 // 0xF87FFFFF == 11111000011111111111111111111111 | |
| 831 DCHECK_EQ(static_cast<HRESULT>(hr & 0xF87FFFFF), hr); | |
| 832 | |
| 833 HRESULT fiddled_hr = ((error_code & 0xF) << 23) | hr; | |
| 834 fiddled_hr |= 1 << 29; // Set the customer bit. | |
| 835 | |
| 836 return fiddled_hr; | |
| 837 } | |
| 838 | |
| 839 HRESULT CustomRegistration(uint16 reg_flags, bool reg, bool is_system) { | |
| 840 if (reg && (reg_flags & (ACTIVEDOC | ACTIVEX))) | |
| 841 reg_flags |= (TYPELIB | GCF_PROTOCOL); | |
| 842 | |
| 843 // Set the flag that gets checked in AddCommonRGSReplacements before doing | |
| 844 // registration work. | |
| 845 _AtlModule.do_system_registration_ = is_system; | |
| 846 | |
| 847 typedef HRESULT (*RegistrationFn)(bool reg, bool is_system); | |
| 848 struct RegistrationStep { | |
| 849 RegistrationStepId id; | |
| 850 uint16 condition; | |
| 851 RegistrationFn func; | |
| 852 }; | |
| 853 static const RegistrationStep registration_steps[] = { | |
| 854 { kStepSecuredMimeHandler, ACTIVEDOC, &RegisterSecuredMimeHandler }, | |
| 855 { kStepActiveDoc, ACTIVEDOC, &RegisterActiveDoc }, | |
| 856 { kStepActiveX, ACTIVEX, &RegisterActiveX }, | |
| 857 { kStepElevationPolicy, (ACTIVEDOC | ACTIVEX), &RegisterElevationPolicy }, | |
| 858 { kStepProtocol, GCF_PROTOCOL, &RegisterProtocol }, | |
| 859 { kStepBhoClsid, BHO_CLSID, &RegisterBhoClsid }, | |
| 860 { kStepBhoRegistration, BHO_REGISTRATION, &RegisterBhoIE }, | |
| 861 { kStepRegisterTypeLib, TYPELIB, &RegisterTypeLib }, | |
| 862 { kStepNpapiCleanup, ALL, &RegisterLegacyNPAPICleanup }, | |
| 863 { kStepAppId, ALL, &RegisterAppId }, | |
| 864 { kStepUserAgent, ALL, &RegisterUserAgent } | |
| 865 }; | |
| 866 | |
| 867 HRESULT hr = S_OK; | |
| 868 | |
| 869 bool rollback = false; | |
| 870 int failure_step = 0; | |
| 871 HRESULT step_hr = S_OK; | |
| 872 for (int step = 0; step < arraysize(registration_steps); ++step) { | |
| 873 if ((reg_flags & registration_steps[step].condition) != 0) { | |
| 874 step_hr = registration_steps[step].func(reg, is_system); | |
| 875 if (FAILED(step_hr)) { | |
| 876 // Store only the first failing HRESULT with the step value muxed in. | |
| 877 if (hr == S_OK) { | |
| 878 hr = MuxErrorIntoHRESULT(step_hr, step); | |
| 879 } | |
| 880 | |
| 881 // On registration if a step fails, we abort and rollback. | |
| 882 if (reg) { | |
| 883 rollback = true; | |
| 884 failure_step = step; | |
| 885 break; | |
| 886 } | |
| 887 } | |
| 888 } | |
| 889 } | |
| 890 | |
| 891 if (rollback) { | |
| 892 DCHECK(reg); | |
| 893 // Rollback the failing action and all preceding ones. | |
| 894 for (int step = failure_step; step >= 0; --step) { | |
| 895 registration_steps[step].func(!reg, is_system); | |
| 896 } | |
| 897 } | |
| 898 | |
| 899 return hr; | |
| 900 } | |
| 901 | |
| 902 } // namespace | |
| 903 | |
| 904 // DLL Entry Point | |
| 905 extern "C" BOOL WINAPI DllMain(HINSTANCE instance, | |
| 906 DWORD reason, | |
| 907 LPVOID reserved) { | |
| 908 UNREFERENCED_PARAMETER(instance); | |
| 909 if (reason == DLL_PROCESS_ATTACH) { | |
| 910 #if _ATL_VER < 0x0C00 && !defined(NDEBUG) | |
| 911 // Silence traces from the ATL registrar to reduce the log noise. | |
| 912 ATL::CTrace::s_trace.ChangeCategory(atlTraceRegistrar, 0, | |
| 913 ATLTRACESTATUS_DISABLED); | |
| 914 #endif | |
| 915 InitGoogleUrl(); | |
| 916 | |
| 917 g_exit_manager = new base::AtExitManager(); | |
| 918 CommandLine::Init(0, NULL); | |
| 919 logging::LoggingSettings settings; | |
| 920 settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; | |
| 921 logging::InitLogging(settings); | |
| 922 | |
| 923 // Log the same items as Chrome. | |
| 924 logging::SetLogItems(true, // enable_process_id | |
| 925 true, // enable_thread_id | |
| 926 false, // enable_timestamp | |
| 927 true); // enable_tickcount | |
| 928 | |
| 929 DllRedirector* dll_redirector = DllRedirector::GetInstance(); | |
| 930 DCHECK(dll_redirector); | |
| 931 | |
| 932 if (!dll_redirector->RegisterAsFirstCFModule()) { | |
| 933 // Someone else was here first, try and get a pointer to their | |
| 934 // DllGetClassObject export: | |
| 935 g_dll_get_class_object_redir_ptr = | |
| 936 dll_redirector->GetDllGetClassObjectPtr(); | |
| 937 DCHECK(g_dll_get_class_object_redir_ptr != NULL) | |
| 938 << "Found CF module with no DllGetClassObject export."; | |
| 939 } | |
| 940 | |
| 941 // Enable trace control and transport through event tracing for Windows. | |
| 942 logging::LogEventProvider::Initialize(kChromeFrameProvider); | |
| 943 | |
| 944 // Set a callback so that crash reporting can be pinned when the module is | |
| 945 // pinned. | |
| 946 chrome_frame::SetPinModuleCallback(&OnPinModule); | |
| 947 } else if (reason == DLL_PROCESS_DETACH) { | |
| 948 DllRedirector* dll_redirector = DllRedirector::GetInstance(); | |
| 949 DCHECK(dll_redirector); | |
| 950 dll_redirector->UnregisterAsFirstCFModule(); | |
| 951 | |
| 952 g_patch_helper.UnpatchIfNeeded(); | |
| 953 | |
| 954 delete g_exit_manager; | |
| 955 g_exit_manager = NULL; | |
| 956 } | |
| 957 return _AtlModule.DllMain(reason, reserved); | |
| 958 } | |
| 959 | |
| 960 // Used to determine whether the DLL can be unloaded by OLE | |
| 961 STDAPI DllCanUnloadNow() { | |
| 962 return _AtlModule.DllCanUnloadNow(); | |
| 963 } | |
| 964 | |
| 965 // Returns a class factory to create an object of the requested type | |
| 966 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) { | |
| 967 chrome_frame::ScopedCrashReporting crash_reporting; | |
| 968 | |
| 969 // IE 11+ are unsupported. | |
| 970 if (GetIEVersion() > IE_10) { | |
| 971 return CLASS_E_CLASSNOTAVAILABLE; | |
| 972 } | |
| 973 | |
| 974 // If we found another module present when we were loaded, then delegate to | |
| 975 // that: | |
| 976 if (g_dll_get_class_object_redir_ptr) { | |
| 977 return g_dll_get_class_object_redir_ptr(rclsid, riid, ppv); | |
| 978 } | |
| 979 | |
| 980 // Enable sniffing and switching only if asked for BHO | |
| 981 // (we use BHO to get loaded in IE). | |
| 982 if (rclsid == CLSID_ChromeFrameBHO) { | |
| 983 g_patch_helper.InitializeAndPatchProtocolsIfNeeded(); | |
| 984 } | |
| 985 | |
| 986 return _AtlModule.DllGetClassObject(rclsid, riid, ppv); | |
| 987 } | |
| 988 | |
| 989 // DllRegisterServer - Adds entries to the system registry | |
| 990 STDAPI DllRegisterServer() { | |
| 991 chrome_frame::ScopedCrashReporting crash_reporting; | |
| 992 uint16 flags = ACTIVEX | ACTIVEDOC | TYPELIB | GCF_PROTOCOL | | |
| 993 BHO_CLSID | BHO_REGISTRATION; | |
| 994 | |
| 995 HRESULT hr = CustomRegistration(flags, true, true); | |
| 996 if (SUCCEEDED(hr)) { | |
| 997 SetupRunOnce(); | |
| 998 } | |
| 999 | |
| 1000 return hr; | |
| 1001 } | |
| 1002 | |
| 1003 // DllUnregisterServer - Removes entries from the system registry | |
| 1004 STDAPI DllUnregisterServer() { | |
| 1005 chrome_frame::ScopedCrashReporting crash_reporting; | |
| 1006 HRESULT hr = CustomRegistration(ALL, false, true); | |
| 1007 return hr; | |
| 1008 } | |
| 1009 | |
| 1010 // DllRegisterUserServer - Adds entries to the HKCU hive in the registry. | |
| 1011 STDAPI DllRegisterUserServer() { | |
| 1012 chrome_frame::ScopedCrashReporting crash_reporting; | |
| 1013 UINT flags = ACTIVEX | ACTIVEDOC | TYPELIB | GCF_PROTOCOL | | |
| 1014 BHO_CLSID | BHO_REGISTRATION; | |
| 1015 | |
| 1016 HRESULT hr = CustomRegistration(flags, TRUE, false); | |
| 1017 if (SUCCEEDED(hr)) { | |
| 1018 SetupRunOnce(); | |
| 1019 } | |
| 1020 | |
| 1021 return hr; | |
| 1022 } | |
| 1023 | |
| 1024 // DllUnregisterUserServer - Removes entries from the HKCU hive in the registry. | |
| 1025 STDAPI DllUnregisterUserServer() { | |
| 1026 chrome_frame::ScopedCrashReporting crash_reporting; | |
| 1027 HRESULT hr = CustomRegistration(ALL, FALSE, false); | |
| 1028 return hr; | |
| 1029 } | |
| 1030 | |
| 1031 // Object entries go here instead of with each object, so that we can move | |
| 1032 // the objects to a lib. Also reduces magic. | |
| 1033 OBJECT_ENTRY_AUTO(CLSID_ChromeFrameBHO, Bho) | |
| 1034 OBJECT_ENTRY_AUTO(__uuidof(ChromeActiveDocument), ChromeActiveDocument) | |
| 1035 OBJECT_ENTRY_AUTO(__uuidof(ChromeFrame), ChromeFrameActivex) | |
| 1036 OBJECT_ENTRY_AUTO(__uuidof(ChromeProtocol), ChromeProtocol) | |
| OLD | NEW |