Home | History | Annotate | Download | only in test
      1 // Copyright (c) 2013 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 #include "win8/test/metro_registration_helper.h"
      6 
      7 #include <shlobj.h>
      8 
      9 #include <vector>
     10 
     11 #include "base/command_line.h"
     12 #include "base/file_util.h"
     13 #include "base/files/file_path.h"
     14 #include "base/logging.h"
     15 #include "base/path_service.h"
     16 #include "base/process/kill.h"
     17 #include "base/process/launch.h"
     18 #include "base/process/process.h"
     19 #include "base/strings/string16.h"
     20 #include "base/win/scoped_co_mem.h"
     21 #include "base/win/scoped_comptr.h"
     22 #include "base/win/scoped_handle.h"
     23 #include "win8/test/open_with_dialog_controller.h"
     24 #include "win8/test/test_registrar_constants.h"
     25 
     26 namespace {
     27 
     28 const int kRegistrationTimeoutSeconds = 30;
     29 
     30 // Copied from util_constants.cc to avoid taking a dependency on installer_util.
     31 const wchar_t kChromeExe[] = L"chrome.exe";
     32 const wchar_t kRegistrar[] = L"test_registrar.exe";
     33 
     34 // Registers chrome.exe as a potential Win8 default browser.  It will then show
     35 // up in the default browser selection dialog as kDefaultTestExeName. Intended
     36 // to be used by a test binary in the build output directory and assumes the
     37 // presence of test_registrar.exe, a viewer process, and all needed DLLs in the
     38 // same directory as the calling module.
     39 bool RegisterTestDefaultBrowser() {
     40   base::FilePath dir;
     41   if (!PathService::Get(base::DIR_EXE, &dir))
     42     return false;
     43 
     44   base::FilePath chrome_exe(dir.Append(kChromeExe));
     45   base::FilePath registrar(dir.Append(kRegistrar));
     46 
     47   if (!base::PathExists(chrome_exe) || !base::PathExists(registrar)) {
     48     LOG(ERROR) << "Could not locate " << kChromeExe << " or " << kRegistrar;
     49     return false;
     50   }
     51 
     52   // Perform the registration by invoking test_registrar.exe.
     53   CommandLine register_command(registrar);
     54   register_command.AppendArg("/RegServer");
     55 
     56   base::win::ScopedHandle register_handle;
     57   if (base::LaunchProcess(register_command.GetCommandLineString(),
     58                           base::LaunchOptions(),
     59                           &register_handle)) {
     60     int ret = 0;
     61     if (base::WaitForExitCodeWithTimeout(
     62             register_handle.Get(), &ret,
     63             base::TimeDelta::FromSeconds(kRegistrationTimeoutSeconds))) {
     64       if (ret == 0) {
     65         return true;
     66       } else {
     67         LOG(ERROR) << "Win8 registration using "
     68                    << register_command.GetCommandLineString()
     69                    << " failed with error code " << ret;
     70       }
     71     } else {
     72       LOG(ERROR) << "Win8 registration using "
     73                  << register_command.GetCommandLineString() << " timed out.";
     74     }
     75   }
     76 
     77   PLOG(ERROR) << "Failed to launch Win8 registration utility using "
     78               << register_command.GetCommandLineString();
     79   return false;
     80 }
     81 
     82 // Returns true if the test viewer's progid is the default handler for
     83 // |protocol|.
     84 bool IsTestDefaultForProtocol(const wchar_t* protocol) {
     85   base::win::ScopedComPtr<IApplicationAssociationRegistration> registration;
     86   HRESULT hr = registration.CreateInstance(
     87       CLSID_ApplicationAssociationRegistration, NULL, CLSCTX_INPROC);
     88   if (FAILED(hr)) {
     89     LOG(ERROR) << std::hex << hr;
     90     return false;
     91   }
     92 
     93   base::win::ScopedCoMem<wchar_t> current_app;
     94   hr = registration->QueryCurrentDefault(protocol, AT_URLPROTOCOL,
     95                                          AL_EFFECTIVE, &current_app);
     96   if (FAILED(hr)) {
     97     LOG(ERROR) << std::hex << hr;
     98     return false;
     99   }
    100 
    101   return !base::string16(win8::test::kDefaultTestProgId).compare(current_app);
    102 }
    103 
    104 }  // namespace
    105 
    106 namespace win8 {
    107 
    108 bool MakeTestDefaultBrowserSynchronously() {
    109   static const wchar_t kDefaultBrowserProtocol[] = L"http";
    110 
    111   if (!RegisterTestDefaultBrowser())
    112     return false;
    113 
    114   // Make sure the registration changes have been acknowledged by the shell
    115   // before querying for the current default.
    116   SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSH, NULL, NULL);
    117 
    118   // OpenWithDialogController will fail if the Test Runner is already default
    119   // since it will not show up verbatim in the dialog (e.g., in EN-US, it will
    120   // be prefixed by "Keep using ").
    121   if (IsTestDefaultForProtocol(kDefaultBrowserProtocol))
    122     return true;
    123 
    124   std::vector<base::string16> choices;
    125   OpenWithDialogController controller;
    126   HRESULT hr = controller.RunSynchronously(
    127       NULL, kDefaultBrowserProtocol, win8::test::kDefaultTestExeName, &choices);
    128   LOG_IF(ERROR, FAILED(hr)) << std::hex << hr;
    129   DCHECK(IsTestDefaultForProtocol(kDefaultBrowserProtocol));
    130   return SUCCEEDED(hr);
    131 }
    132 
    133 }  // namespace win8
    134