OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 // NOTE: This code is a legacy utility API for partners to check whether | 5 // NOTE: This code is a legacy utility API for partners to check whether |
6 // Chrome can be installed and launched. Recent updates are being made | 6 // Chrome can be installed and launched. Recent updates are being made |
7 // to add new functionality. These updates use code from Chromium, the old | 7 // to add new functionality. These updates use code from Chromium, the old |
8 // coded against the win32 api directly. If you have an itch to shave a | 8 // coded against the win32 api directly. If you have an itch to shave a |
9 // yak, feel free to re-write the old code too. | 9 // yak, feel free to re-write the old code too. |
10 | 10 |
11 #include "chrome/installer/gcapi/gcapi.h" | 11 #include "chrome/installer/gcapi/gcapi.h" |
12 | 12 |
13 #include <atlbase.h> | |
14 #include <atlcom.h> | |
15 #include <sddl.h> | 13 #include <sddl.h> |
16 #define STRSAFE_NO_DEPRECATE | 14 #define STRSAFE_NO_DEPRECATE |
17 #include <strsafe.h> | 15 #include <strsafe.h> |
18 #include <tlhelp32.h> | 16 #include <tlhelp32.h> |
19 #include <windows.h> | 17 #include <windows.h> |
20 | 18 |
21 #include <cstdlib> | 19 #include <cstdlib> |
22 #include <limits> | 20 #include <limits> |
23 #include <string> | 21 #include <string> |
24 | 22 |
25 #include "base/basictypes.h" | 23 #include "base/basictypes.h" |
| 24 #include "base/file_path.h" |
| 25 #include "base/file_util.h" |
26 #include "base/string_number_conversions.h" | 26 #include "base/string_number_conversions.h" |
27 #include "base/time.h" | 27 #include "base/time.h" |
28 #include "base/win/registry.h" | 28 #include "base/win/registry.h" |
| 29 #include "base/win/scoped_com_initializer.h" |
| 30 #include "base/win/scoped_comptr.h" |
| 31 #include "base/win/scoped_handle.h" |
29 #include "chrome/installer/util/google_update_constants.h" | 32 #include "chrome/installer/util/google_update_constants.h" |
| 33 #include "chrome/installer/util/util_constants.h" |
30 | 34 |
31 #include "google_update_idl.h" // NOLINT | 35 #include "google_update_idl.h" // NOLINT |
32 | 36 |
| 37 using base::Time; |
| 38 using base::TimeDelta; |
| 39 using base::win::RegKey; |
| 40 using base::win::ScopedCOMInitializer; |
| 41 using base::win::ScopedComPtr; |
| 42 using base::win::ScopedHandle; |
| 43 |
33 namespace { | 44 namespace { |
34 | 45 |
35 const wchar_t kChromeRegClientsKey[] = | 46 const wchar_t kChromeRegClientsKey[] = |
36 L"Software\\Google\\Update\\Clients\\" | 47 L"Software\\Google\\Update\\Clients\\" |
37 L"{8A69D345-D564-463c-AFF1-A69D9E530F96}"; | 48 L"{8A69D345-D564-463c-AFF1-A69D9E530F96}"; |
38 const wchar_t kChromeRegClientStateKey[] = | 49 const wchar_t kChromeRegClientStateKey[] = |
39 L"Software\\Google\\Update\\ClientState\\" | 50 L"Software\\Google\\Update\\ClientState\\" |
40 L"{8A69D345-D564-463c-AFF1-A69D9E530F96}"; | 51 L"{8A69D345-D564-463c-AFF1-A69D9E530F96}"; |
41 const wchar_t kChromeRegClientStateMediumKey[] = | 52 const wchar_t kChromeRegClientStateMediumKey[] = |
42 L"Software\\Google\\Update\\ClientStateMedium\\" | 53 L"Software\\Google\\Update\\ClientStateMedium\\" |
43 L"{8A69D345-D564-463c-AFF1-A69D9E530F96}"; | 54 L"{8A69D345-D564-463c-AFF1-A69D9E530F96}"; |
44 | 55 |
45 const wchar_t kChromeRegLaunchCmd[] = L"InstallerSuccessLaunchCmdLine"; | 56 const wchar_t kChromeRegLaunchCmd[] = L"InstallerSuccessLaunchCmdLine"; |
46 const wchar_t kChromeRegLastLaunchCmd[] = L"LastInstallerSuccessLaunchCmdLine"; | 57 const wchar_t kChromeRegLastLaunchCmd[] = L"LastInstallerSuccessLaunchCmdLine"; |
47 const wchar_t kChromeRegVersion[] = L"pv"; | 58 const wchar_t kChromeRegVersion[] = L"pv"; |
48 const wchar_t kNoChromeOfferUntil[] = | 59 const wchar_t kNoChromeOfferUntil[] = |
49 L"SOFTWARE\\Google\\No Chrome Offer Until"; | 60 L"SOFTWARE\\Google\\No Chrome Offer Until"; |
50 | 61 |
| 62 const wchar_t kChromeWindowClass[] = L"Chrome_WidgetWin_0"; |
| 63 |
51 // Return the company name specified in the file version info resource. | 64 // Return the company name specified in the file version info resource. |
52 bool GetCompanyName(const wchar_t* filename, wchar_t* buffer, DWORD out_len) { | 65 bool GetCompanyName(const wchar_t* filename, wchar_t* buffer, DWORD out_len) { |
53 wchar_t file_version_info[8192]; | 66 wchar_t file_version_info[8192]; |
54 DWORD handle = 0; | 67 DWORD handle = 0; |
55 DWORD buffer_size = 0; | 68 DWORD buffer_size = 0; |
56 | 69 |
57 buffer_size = ::GetFileVersionInfoSize(filename, &handle); | 70 buffer_size = ::GetFileVersionInfoSize(filename, &handle); |
58 // Cannot stats the file or our buffer size is too small (very unlikely). | 71 // Cannot stats the file or our buffer size is too small (very unlikely). |
59 if (buffer_size == 0 || buffer_size > _countof(file_version_info)) | 72 if (buffer_size == 0 || buffer_size > _countof(file_version_info)) |
60 return false; | 73 return false; |
(...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
332 local_reasons |= GCCC_ERROR_ALREADYOFFERED; | 345 local_reasons |= GCCC_ERROR_ALREADYOFFERED; |
333 | 346 |
334 // Done. Copy/return results. | 347 // Done. Copy/return results. |
335 if (reasons != NULL) | 348 if (reasons != NULL) |
336 *reasons = local_reasons; | 349 *reasons = local_reasons; |
337 | 350 |
338 return (local_reasons == 0); | 351 return (local_reasons == 0); |
339 } | 352 } |
340 | 353 |
341 BOOL __stdcall LaunchGoogleChrome() { | 354 BOOL __stdcall LaunchGoogleChrome() { |
342 wchar_t launch_cmd[MAX_PATH]; | 355 // Check to make sure we have a valid Chrome installation. |
343 size_t size = _countof(launch_cmd); | 356 HKEY install_key = HKEY_LOCAL_MACHINE; |
344 if (!ReadValueFromRegistry(HKEY_LOCAL_MACHINE, kChromeRegClientStateKey, | 357 if (!IsChromeInstalled(install_key)) { |
345 kChromeRegLastLaunchCmd, launch_cmd, &size)) { | 358 install_key = HKEY_CURRENT_USER; |
346 size = _countof(launch_cmd); | 359 if (!IsChromeInstalled(install_key)) { |
347 if (!ReadValueFromRegistry(HKEY_LOCAL_MACHINE, kChromeRegClientStateKey, | |
348 kChromeRegLaunchCmd, launch_cmd, &size)) { | |
349 return false; | 360 return false; |
350 } | 361 } |
351 } | 362 } |
352 | 363 |
353 HRESULT hr = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); | 364 // Now grab the uninstall string from the appropriate ClientState key |
354 if (hr != S_OK) { | 365 // and use that as the base for a path to chrome.exe. |
355 if (hr == S_FALSE) | 366 FilePath chrome_exe_path; |
356 ::CoUninitialize(); | 367 RegKey client_state(install_key, kChromeRegClientStateKey, KEY_QUERY_VALUE); |
| 368 if (client_state.Valid()) { |
| 369 std::wstring uninstall_string; |
| 370 if (client_state.ReadValue(installer::kUninstallStringField, |
| 371 &uninstall_string) == ERROR_SUCCESS) { |
| 372 // The uninstall path contains the path to setup.exe which is two levels |
| 373 // down from chrome.exe. Move up two levels (plus one to drop the file |
| 374 // name) and look for chrome.exe from there. |
| 375 FilePath uninstall_path(uninstall_string); |
| 376 chrome_exe_path = uninstall_path.DirName() |
| 377 .DirName() |
| 378 .DirName() |
| 379 .Append(installer::kChromeExe); |
| 380 if (!file_util::PathExists(chrome_exe_path)) { |
| 381 // By way of mild future proofing, look up one to see if there's a |
| 382 // chrome.exe in the version directory |
| 383 chrome_exe_path = |
| 384 uninstall_path.DirName().DirName().Append(installer::kChromeExe); |
| 385 } |
| 386 } |
| 387 } |
| 388 |
| 389 if (!file_util::PathExists(chrome_exe_path)) { |
357 return false; | 390 return false; |
358 } | 391 } |
359 | 392 |
| 393 ScopedCOMInitializer com_initializer; |
360 if (::CoInitializeSecurity(NULL, -1, NULL, NULL, | 394 if (::CoInitializeSecurity(NULL, -1, NULL, NULL, |
361 RPC_C_AUTHN_LEVEL_PKT_PRIVACY, | 395 RPC_C_AUTHN_LEVEL_PKT_PRIVACY, |
362 RPC_C_IMP_LEVEL_IDENTIFY, NULL, | 396 RPC_C_IMP_LEVEL_IDENTIFY, NULL, |
363 EOAC_DYNAMIC_CLOAKING, NULL) != S_OK) { | 397 EOAC_DYNAMIC_CLOAKING, NULL) != S_OK) { |
364 ::CoUninitialize(); | |
365 return false; | 398 return false; |
366 } | 399 } |
367 | 400 |
368 bool impersonation_success = false; | 401 bool impersonation_success = false; |
369 if (IsRunningElevated()) { | 402 if (IsRunningElevated()) { |
370 wchar_t* curr_proc_sid; | 403 wchar_t* curr_proc_sid; |
371 if (!GetUserIdForProcess(GetCurrentProcessId(), &curr_proc_sid)) { | 404 if (!GetUserIdForProcess(GetCurrentProcessId(), &curr_proc_sid)) { |
372 ::CoUninitialize(); | |
373 return false; | 405 return false; |
374 } | 406 } |
375 | 407 |
376 DWORD pid = 0; | 408 DWORD pid = 0; |
377 ::GetWindowThreadProcessId(::GetShellWindow(), &pid); | 409 ::GetWindowThreadProcessId(::GetShellWindow(), &pid); |
378 if (pid <= 0) { | 410 if (pid <= 0) { |
379 ::LocalFree(curr_proc_sid); | 411 ::LocalFree(curr_proc_sid); |
380 ::CoUninitialize(); | |
381 return false; | 412 return false; |
382 } | 413 } |
383 | 414 |
384 wchar_t* exp_proc_sid; | 415 wchar_t* exp_proc_sid; |
385 if (GetUserIdForProcess(pid, &exp_proc_sid)) { | 416 if (GetUserIdForProcess(pid, &exp_proc_sid)) { |
386 if (_wcsicmp(curr_proc_sid, exp_proc_sid) == 0) { | 417 if (_wcsicmp(curr_proc_sid, exp_proc_sid) == 0) { |
387 HANDLE process_handle = ::OpenProcess( | 418 ScopedHandle process_handle( |
388 PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION, TRUE, pid); | 419 ::OpenProcess(PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION, |
389 if (process_handle != NULL) { | 420 TRUE, |
| 421 pid)); |
| 422 if (process_handle.IsValid()) { |
390 HANDLE process_token = NULL; | 423 HANDLE process_token = NULL; |
391 HANDLE user_token = NULL; | 424 HANDLE user_token = NULL; |
392 if (::OpenProcessToken(process_handle, TOKEN_DUPLICATE | TOKEN_QUERY, | 425 if (::OpenProcessToken(process_handle, TOKEN_DUPLICATE | TOKEN_QUERY, |
393 &process_token) && | 426 &process_token) && |
394 ::DuplicateTokenEx(process_token, | 427 ::DuplicateTokenEx(process_token, |
395 TOKEN_IMPERSONATE | TOKEN_QUERY | | 428 TOKEN_IMPERSONATE | TOKEN_QUERY | |
396 TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE, | 429 TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE, |
397 NULL, SecurityImpersonation, | 430 NULL, SecurityImpersonation, |
398 TokenPrimary, &user_token) && | 431 TokenPrimary, &user_token) && |
399 (::ImpersonateLoggedOnUser(user_token) != 0)) { | 432 (::ImpersonateLoggedOnUser(user_token) != 0)) { |
400 impersonation_success = true; | 433 impersonation_success = true; |
401 } | 434 } |
402 if (user_token) | 435 if (user_token) |
403 ::CloseHandle(user_token); | 436 ::CloseHandle(user_token); |
404 if (process_token) | 437 if (process_token) |
405 ::CloseHandle(process_token); | 438 ::CloseHandle(process_token); |
406 ::CloseHandle(process_handle); | |
407 } | 439 } |
408 } | 440 } |
409 ::LocalFree(exp_proc_sid); | 441 ::LocalFree(exp_proc_sid); |
410 } | 442 } |
411 | 443 |
412 ::LocalFree(curr_proc_sid); | 444 ::LocalFree(curr_proc_sid); |
413 if (!impersonation_success) { | 445 if (!impersonation_success) { |
414 ::CoUninitialize(); | |
415 return false; | 446 return false; |
416 } | 447 } |
417 } | 448 } |
418 | 449 |
419 bool ret = false; | 450 bool ret = false; |
420 CComPtr<IProcessLauncher> ipl; | 451 ScopedComPtr<IProcessLauncher> ipl; |
421 if (!FAILED(ipl.CoCreateInstance(__uuidof(ProcessLauncherClass), NULL, | 452 if (SUCCEEDED(ipl.CreateInstance(__uuidof(ProcessLauncherClass), |
| 453 NULL, |
422 CLSCTX_LOCAL_SERVER))) { | 454 CLSCTX_LOCAL_SERVER))) { |
423 if (!FAILED(ipl->LaunchCmdLine(launch_cmd))) | 455 if (SUCCEEDED(ipl->LaunchCmdLine(chrome_exe_path.value().c_str()))) |
424 ret = true; | 456 ret = true; |
425 ipl.Release(); | 457 ipl.Release(); |
426 } | 458 } |
427 | 459 |
428 if (impersonation_success) | 460 if (impersonation_success) |
429 ::RevertToSelf(); | 461 ::RevertToSelf(); |
430 ::CoUninitialize(); | |
431 return ret; | 462 return ret; |
432 } | 463 } |
433 | 464 |
434 BOOL __stdcall LaunchGoogleChromeWithDimensions(int x, | 465 BOOL __stdcall LaunchGoogleChromeWithDimensions(int x, |
435 int y, | 466 int y, |
436 int width, | 467 int width, |
437 int height) { | 468 int height, |
| 469 bool in_background) { |
438 if (!LaunchGoogleChrome()) | 470 if (!LaunchGoogleChrome()) |
439 return false; | 471 return false; |
440 | 472 |
441 HWND handle = NULL; | 473 HWND handle = NULL; |
442 int seconds_elapsed = 0; | 474 int seconds_elapsed = 0; |
443 | 475 |
444 // Chrome may have been launched, but the window may not have appeared | 476 // Chrome may have been launched, but the window may not have appeared |
445 // yet. Wait for it to appear for 10 seconds, but exit if it takes longer | 477 // yet. Wait for it to appear for 10 seconds, but exit if it takes longer |
446 // than that. | 478 // than that. |
447 while (!handle && seconds_elapsed < 10) { | 479 while (!handle && seconds_elapsed < 10) { |
448 handle = FindWindowEx(NULL, handle, L"Chrome_WindowImpl_0", NULL); | 480 handle = FindWindowEx(NULL, handle, kChromeWindowClass, NULL); |
449 if (!handle) { | 481 if (!handle) { |
450 Sleep(1000); | 482 Sleep(1000); |
451 seconds_elapsed++; | 483 seconds_elapsed++; |
452 } | 484 } |
453 } | 485 } |
454 | 486 |
455 if (!handle) | 487 if (!handle) |
456 return false; | 488 return false; |
457 | 489 |
458 // At this point, there are several top-level Chrome windows | 490 // At this point, there are several top-level Chrome windows |
459 // but we only want the window that has child windows. | 491 // but we only want the window that has child windows. |
460 | 492 |
461 // This loop iterates through all of the top-level Windows named | 493 // This loop iterates through all of the top-level Windows named |
462 // Chrome_WindowImpl_0, and looks for the first one with any children. | 494 // kChromeWindowClass, and looks for the first one with any children. |
463 while (handle && !FindWindowEx(handle, NULL, L"Chrome_WindowImpl_0", NULL)) { | 495 while (handle && !FindWindowEx(handle, NULL, kChromeWindowClass, NULL)) { |
464 // Get the next top-level Chrome window. | 496 // Get the next top-level Chrome window. |
465 handle = FindWindowEx(NULL, handle, L"Chrome_WindowImpl_0", NULL); | 497 handle = FindWindowEx(NULL, handle, kChromeWindowClass, NULL); |
466 } | 498 } |
467 | 499 |
| 500 HWND set_window_hwnd_insert_after = in_background ? HWND_BOTTOM : NULL; |
| 501 DWORD set_window_flags = in_background ? SWP_NOACTIVATE : SWP_NOZORDER; |
| 502 |
468 return (handle && | 503 return (handle && |
469 SetWindowPos(handle, 0, x, y, width, height, SWP_NOZORDER)); | 504 SetWindowPos(handle, set_window_hwnd_insert_after, x, y, |
| 505 width, height, set_window_flags)); |
470 } | 506 } |
471 | 507 |
472 int __stdcall GoogleChromeDaysSinceLastRun() { | 508 int __stdcall GoogleChromeDaysSinceLastRun() { |
473 using base::win::RegKey; | |
474 using base::Time; | |
475 using base::TimeDelta; | |
476 | |
477 int days_since_last_run = std::numeric_limits<int>::max(); | 509 int days_since_last_run = std::numeric_limits<int>::max(); |
478 | 510 |
479 struct { | 511 struct { |
480 HKEY hive; | 512 HKEY hive; |
481 const wchar_t* path; | 513 const wchar_t* path; |
482 } reg_data[] = { | 514 } reg_data[] = { |
483 { HKEY_LOCAL_MACHINE, kChromeRegClientStateMediumKey }, | 515 { HKEY_LOCAL_MACHINE, kChromeRegClientStateMediumKey }, |
484 { HKEY_CURRENT_USER, kChromeRegClientStateKey } | 516 { HKEY_CURRENT_USER, kChromeRegClientStateKey } |
485 }; | 517 }; |
486 | 518 |
(...skipping 20 matching lines...) Expand all Loading... |
507 } | 539 } |
508 } | 540 } |
509 } | 541 } |
510 | 542 |
511 if (days_since_last_run == std::numeric_limits<int>::max()) { | 543 if (days_since_last_run == std::numeric_limits<int>::max()) { |
512 days_since_last_run = -1; | 544 days_since_last_run = -1; |
513 } | 545 } |
514 | 546 |
515 return days_since_last_run; | 547 return days_since_last_run; |
516 } | 548 } |
OLD | NEW |