Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(372)

Side by Side Diff: chrome/installer/gcapi/gcapi.cc

Issue 8776038: Fix up GCAPI's LaunchGoogleChrome() method. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/installer/gcapi/gcapi.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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::win::RegKey;
38 using base::win::ScopedCOMInitializer;
39 using base::win::ScopedComPtr;
40 using base::win::ScopedHandle;
41 using base::Time;
grt (UTC plus 2) 2011/12/05 15:14:22 what do you think about moving these above RegKey
robertshield 2011/12/05 18:18:00 I think that's a splendid idea.
42 using base::TimeDelta;
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\\"
(...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after
332 local_reasons |= GCCC_ERROR_ALREADYOFFERED; 343 local_reasons |= GCCC_ERROR_ALREADYOFFERED;
333 344
334 // Done. Copy/return results. 345 // Done. Copy/return results.
335 if (reasons != NULL) 346 if (reasons != NULL)
336 *reasons = local_reasons; 347 *reasons = local_reasons;
337 348
338 return (local_reasons == 0); 349 return (local_reasons == 0);
339 } 350 }
340 351
341 BOOL __stdcall LaunchGoogleChrome() { 352 BOOL __stdcall LaunchGoogleChrome() {
342 wchar_t launch_cmd[MAX_PATH]; 353 // Check to make sure we have a valid Chrome installation.
343 size_t size = _countof(launch_cmd); 354 HKEY install_key = HKEY_LOCAL_MACHINE;
344 if (!ReadValueFromRegistry(HKEY_LOCAL_MACHINE, kChromeRegClientStateKey, 355 if (!IsChromeInstalled(install_key)) {
345 kChromeRegLastLaunchCmd, launch_cmd, &size)) { 356 install_key = HKEY_CURRENT_USER;
346 size = _countof(launch_cmd); 357 if (!IsChromeInstalled(install_key)) {
Roger Tawa OOO till Jul 10th 2011/12/05 16:19:45 For my own info, why try HKLM before HKCU?
robertshield 2011/12/05 18:18:00 If both exist and the user-level one is launched,
347 if (!ReadValueFromRegistry(HKEY_LOCAL_MACHINE, kChromeRegClientStateKey,
348 kChromeRegLaunchCmd, launch_cmd, &size)) {
349 return false; 358 return false;
350 } 359 }
351 } 360 }
352 361
353 HRESULT hr = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 362 // Now grab the uninstall string from the appropriate ClientState key
354 if (hr != S_OK) { 363 // and use that as the base for a path to chrome.exe.
355 if (hr == S_FALSE) 364 FilePath chrome_exe_path;
356 ::CoUninitialize(); 365 RegKey client_state(install_key, kChromeRegClientStateKey, KEY_QUERY_VALUE);
357 return false; 366 if (client_state.Valid()) {
367 std::wstring uninstall_string;
368 if (client_state.ReadValue(installer::kUninstallStringField,
369 &uninstall_string) == ERROR_SUCCESS) {
370 // The uninstall path contains the path to setup.exe which is two levels
371 // down from chrome.exe. Move up two levels (plus one to drop the file
372 // name) and look for chrome.exe from there.
373 FilePath uninstall_path(uninstall_string);
374 chrome_exe_path = uninstall_path.DirName()
375 .DirName()
376 .DirName()
377 .Append(installer::kChromeExe);
378 if (!file_util::PathExists(chrome_exe_path)) {
379 // By way of mild future proofing, look up one to see if there's a
380 // chrome.exe in the version directory
381 chrome_exe_path =
382 uninstall_path.DirName().DirName().Append(installer::kChromeExe);
383 }
Roger Tawa OOO till Jul 10th 2011/12/05 16:19:45 You don't want to do another path exists check her
robertshield 2011/12/05 18:18:00 Good idea, done.
384 }
358 } 385 }
359 386
387 ScopedCOMInitializer com_initializer;
360 if (::CoInitializeSecurity(NULL, -1, NULL, NULL, 388 if (::CoInitializeSecurity(NULL, -1, NULL, NULL,
361 RPC_C_AUTHN_LEVEL_PKT_PRIVACY, 389 RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
362 RPC_C_IMP_LEVEL_IDENTIFY, NULL, 390 RPC_C_IMP_LEVEL_IDENTIFY, NULL,
363 EOAC_DYNAMIC_CLOAKING, NULL) != S_OK) { 391 EOAC_DYNAMIC_CLOAKING, NULL) != S_OK) {
364 ::CoUninitialize();
365 return false; 392 return false;
366 } 393 }
367 394
368 bool impersonation_success = false; 395 bool impersonation_success = false;
369 if (IsRunningElevated()) { 396 if (IsRunningElevated()) {
370 wchar_t* curr_proc_sid; 397 wchar_t* curr_proc_sid;
371 if (!GetUserIdForProcess(GetCurrentProcessId(), &curr_proc_sid)) { 398 if (!GetUserIdForProcess(GetCurrentProcessId(), &curr_proc_sid)) {
372 ::CoUninitialize();
373 return false; 399 return false;
374 } 400 }
375 401
376 DWORD pid = 0; 402 DWORD pid = 0;
377 ::GetWindowThreadProcessId(::GetShellWindow(), &pid); 403 ::GetWindowThreadProcessId(::GetShellWindow(), &pid);
378 if (pid <= 0) { 404 if (pid <= 0) {
379 ::LocalFree(curr_proc_sid); 405 ::LocalFree(curr_proc_sid);
380 ::CoUninitialize();
381 return false; 406 return false;
382 } 407 }
383 408
384 wchar_t* exp_proc_sid; 409 wchar_t* exp_proc_sid;
385 if (GetUserIdForProcess(pid, &exp_proc_sid)) { 410 if (GetUserIdForProcess(pid, &exp_proc_sid)) {
386 if (_wcsicmp(curr_proc_sid, exp_proc_sid) == 0) { 411 if (_wcsicmp(curr_proc_sid, exp_proc_sid) == 0) {
387 HANDLE process_handle = ::OpenProcess( 412 ScopedHandle process_handle(
388 PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION, TRUE, pid); 413 ::OpenProcess(PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION,
389 if (process_handle != NULL) { 414 TRUE,
415 pid));
416 if (process_handle.IsValid()) {
390 HANDLE process_token = NULL; 417 HANDLE process_token = NULL;
391 HANDLE user_token = NULL; 418 HANDLE user_token = NULL;
392 if (::OpenProcessToken(process_handle, TOKEN_DUPLICATE | TOKEN_QUERY, 419 if (::OpenProcessToken(process_handle, TOKEN_DUPLICATE | TOKEN_QUERY,
393 &process_token) && 420 &process_token) &&
394 ::DuplicateTokenEx(process_token, 421 ::DuplicateTokenEx(process_token,
395 TOKEN_IMPERSONATE | TOKEN_QUERY | 422 TOKEN_IMPERSONATE | TOKEN_QUERY |
396 TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE, 423 TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE,
397 NULL, SecurityImpersonation, 424 NULL, SecurityImpersonation,
398 TokenPrimary, &user_token) && 425 TokenPrimary, &user_token) &&
399 (::ImpersonateLoggedOnUser(user_token) != 0)) { 426 (::ImpersonateLoggedOnUser(user_token) != 0)) {
400 impersonation_success = true; 427 impersonation_success = true;
401 } 428 }
402 if (user_token) 429 if (user_token)
403 ::CloseHandle(user_token); 430 ::CloseHandle(user_token);
404 if (process_token) 431 if (process_token)
405 ::CloseHandle(process_token); 432 ::CloseHandle(process_token);
406 ::CloseHandle(process_handle);
407 } 433 }
408 } 434 }
409 ::LocalFree(exp_proc_sid); 435 ::LocalFree(exp_proc_sid);
410 } 436 }
411 437
412 ::LocalFree(curr_proc_sid); 438 ::LocalFree(curr_proc_sid);
413 if (!impersonation_success) { 439 if (!impersonation_success) {
414 ::CoUninitialize();
415 return false; 440 return false;
416 } 441 }
417 } 442 }
418 443
419 bool ret = false; 444 bool ret = false;
420 CComPtr<IProcessLauncher> ipl; 445 ScopedComPtr<IProcessLauncher> ipl;
421 if (!FAILED(ipl.CoCreateInstance(__uuidof(ProcessLauncherClass), NULL, 446 if (SUCCEEDED(ipl.CreateInstance(__uuidof(ProcessLauncherClass),
grt (UTC plus 2) 2011/12/05 15:14:22 what, !FAILED implies SUCCEEDED to you?
robertshield 2011/12/05 18:18:00 #define SUCCEEDED(hr) (((HRESULT)(hr)) >= 0) #defi
447 NULL,
422 CLSCTX_LOCAL_SERVER))) { 448 CLSCTX_LOCAL_SERVER))) {
423 if (!FAILED(ipl->LaunchCmdLine(launch_cmd))) 449 if (SUCCEEDED(ipl->LaunchCmdLine(chrome_exe_path.value().c_str())))
424 ret = true; 450 ret = true;
425 ipl.Release(); 451 ipl.Release();
426 } 452 }
427 453
428 if (impersonation_success) 454 if (impersonation_success)
429 ::RevertToSelf(); 455 ::RevertToSelf();
430 ::CoUninitialize();
431 return ret; 456 return ret;
432 } 457 }
433 458
434 BOOL __stdcall LaunchGoogleChromeWithDimensions(int x, 459 BOOL __stdcall LaunchGoogleChromeWithDimensions(int x,
435 int y, 460 int y,
436 int width, 461 int width,
437 int height) { 462 int height,
463 bool in_background) {
438 if (!LaunchGoogleChrome()) 464 if (!LaunchGoogleChrome())
439 return false; 465 return false;
440 466
441 HWND handle = NULL; 467 HWND handle = NULL;
442 int seconds_elapsed = 0; 468 int seconds_elapsed = 0;
443 469
444 // Chrome may have been launched, but the window may not have appeared 470 // 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 471 // yet. Wait for it to appear for 10 seconds, but exit if it takes longer
446 // than that. 472 // than that.
447 while (!handle && seconds_elapsed < 10) { 473 while (!handle && seconds_elapsed < 10) {
448 handle = FindWindowEx(NULL, handle, L"Chrome_WindowImpl_0", NULL); 474 handle = FindWindowEx(NULL, handle, L"Chrome_WidgetWin_0", NULL);
grt (UTC plus 2) 2011/12/05 15:14:22 how about making a kChromeWindowClass for this?
robertshield 2011/12/05 18:18:00 Done.
449 if (!handle) { 475 if (!handle) {
450 Sleep(1000); 476 Sleep(1000);
451 seconds_elapsed++; 477 seconds_elapsed++;
452 } 478 }
453 } 479 }
454 480
455 if (!handle) 481 if (!handle)
456 return false; 482 return false;
457 483
458 // At this point, there are several top-level Chrome windows 484 // At this point, there are several top-level Chrome windows
459 // but we only want the window that has child windows. 485 // but we only want the window that has child windows.
460 486
461 // This loop iterates through all of the top-level Windows named 487 // This loop iterates through all of the top-level Windows named
462 // Chrome_WindowImpl_0, and looks for the first one with any children. 488 // Chrome_WindowImpl_0, and looks for the first one with any children.
463 while (handle && !FindWindowEx(handle, NULL, L"Chrome_WindowImpl_0", NULL)) { 489 while (handle && !FindWindowEx(handle, NULL, L"Chrome_WidgetWin_0", NULL)) {
464 // Get the next top-level Chrome window. 490 // Get the next top-level Chrome window.
465 handle = FindWindowEx(NULL, handle, L"Chrome_WindowImpl_0", NULL); 491 handle = FindWindowEx(NULL, handle, L"Chrome_WidgetWin_0", NULL);
466 } 492 }
467 493
494 HWND set_window_hwnd_insert_after = in_background ? HWND_BOTTOM : NULL;
495 DWORD set_window_flags = in_background ? SWP_NOACTIVATE : SWP_NOZORDER;
496
468 return (handle && 497 return (handle &&
469 SetWindowPos(handle, 0, x, y, width, height, SWP_NOZORDER)); 498 SetWindowPos(handle, set_window_hwnd_insert_after, x, y,
499 width, height, set_window_flags));
470 } 500 }
471 501
472 int __stdcall GoogleChromeDaysSinceLastRun() { 502 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(); 503 int days_since_last_run = std::numeric_limits<int>::max();
478 504
479 struct { 505 struct {
480 HKEY hive; 506 HKEY hive;
481 const wchar_t* path; 507 const wchar_t* path;
482 } reg_data[] = { 508 } reg_data[] = {
483 { HKEY_LOCAL_MACHINE, kChromeRegClientStateMediumKey }, 509 { HKEY_LOCAL_MACHINE, kChromeRegClientStateMediumKey },
484 { HKEY_CURRENT_USER, kChromeRegClientStateKey } 510 { HKEY_CURRENT_USER, kChromeRegClientStateKey }
485 }; 511 };
486 512
(...skipping 20 matching lines...) Expand all
507 } 533 }
508 } 534 }
509 } 535 }
510 536
511 if (days_since_last_run == std::numeric_limits<int>::max()) { 537 if (days_since_last_run == std::numeric_limits<int>::max()) {
512 days_since_last_run = -1; 538 days_since_last_run = -1;
513 } 539 }
514 540
515 return days_since_last_run; 541 return days_since_last_run;
516 } 542 }
OLDNEW
« no previous file with comments | « chrome/installer/gcapi/gcapi.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698