summaryrefslogtreecommitdiffstats
path: root/win8/test/metro_registration_helper.cc
blob: 59b2235034c1dac80b2e43763665ad6551c3258f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "win8/test/metro_registration_helper.h"

#include <shlobj.h>

#include <vector>

#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/process/kill.h"
#include "base/process/launch.h"
#include "base/process/process.h"
#include "base/strings/string16.h"
#include "base/win/scoped_co_mem.h"
#include "base/win/scoped_comptr.h"
#include "base/win/scoped_handle.h"
#include "win8/test/open_with_dialog_controller.h"
#include "win8/test/test_registrar_constants.h"

namespace {

const int kRegistrationTimeoutSeconds = 30;

// Copied from util_constants.cc to avoid taking a dependency on installer_util.
const wchar_t kChromeExe[] = L"chrome.exe";
const wchar_t kRegistrar[] = L"test_registrar.exe";

// Registers chrome.exe as a potential Win8 default browser.  It will then show
// up in the default browser selection dialog as kDefaultTestExeName. Intended
// to be used by a test binary in the build output directory and assumes the
// presence of test_registrar.exe, a viewer process, and all needed DLLs in the
// same directory as the calling module.
bool RegisterTestDefaultBrowser() {
  base::FilePath dir;
  if (!PathService::Get(base::DIR_EXE, &dir))
    return false;

  base::FilePath chrome_exe(dir.Append(kChromeExe));
  base::FilePath registrar(dir.Append(kRegistrar));

  if (!base::PathExists(chrome_exe) || !base::PathExists(registrar)) {
    LOG(ERROR) << "Could not locate " << kChromeExe << " or " << kRegistrar;
    return false;
  }

  // Perform the registration by invoking test_registrar.exe.
  CommandLine register_command(registrar);
  register_command.AppendArg("/RegServer");

  base::Process register_process =
      base::LaunchProcess(register_command.GetCommandLineString(),
                          base::LaunchOptions());
  if (register_process.IsValid()) {
    int ret = 0;
    if (base::WaitForExitCodeWithTimeout(
            register_process.Handle(), &ret,
            base::TimeDelta::FromSeconds(kRegistrationTimeoutSeconds))) {
      if (ret == 0) {
        return true;
      } else {
        LOG(ERROR) << "Win8 registration using "
                   << register_command.GetCommandLineString()
                   << " failed with error code " << ret;
      }
    } else {
      LOG(ERROR) << "Win8 registration using "
                 << register_command.GetCommandLineString() << " timed out.";
    }
  }

  PLOG(ERROR) << "Failed to launch Win8 registration utility using "
              << register_command.GetCommandLineString();
  return false;
}

// Returns true if the test viewer's progid is the default handler for
// |protocol|.
bool IsTestDefaultForProtocol(const wchar_t* protocol) {
  base::win::ScopedComPtr<IApplicationAssociationRegistration> registration;
  HRESULT hr = registration.CreateInstance(
      CLSID_ApplicationAssociationRegistration, NULL, CLSCTX_INPROC);
  if (FAILED(hr)) {
    LOG(ERROR) << std::hex << hr;
    return false;
  }

  base::win::ScopedCoMem<wchar_t> current_app;
  hr = registration->QueryCurrentDefault(protocol, AT_URLPROTOCOL,
                                         AL_EFFECTIVE, &current_app);
  if (FAILED(hr)) {
    LOG(ERROR) << std::hex << hr;
    return false;
  }

  return !base::string16(win8::test::kDefaultTestProgId).compare(current_app);
}

}  // namespace

namespace win8 {

bool MakeTestDefaultBrowserSynchronously() {
  static const wchar_t kDefaultBrowserProtocol[] = L"http";

  if (!RegisterTestDefaultBrowser())
    return false;

  // Make sure the registration changes have been acknowledged by the shell
  // before querying for the current default.
  SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSH, NULL, NULL);

  // OpenWithDialogController will fail if the Test Runner is already default
  // since it will not show up verbatim in the dialog (e.g., in EN-US, it will
  // be prefixed by "Keep using ").
  if (IsTestDefaultForProtocol(kDefaultBrowserProtocol))
    return true;

  std::vector<base::string16> choices;
  OpenWithDialogController controller;
  HRESULT hr = controller.RunSynchronously(
      NULL, kDefaultBrowserProtocol, win8::test::kDefaultTestExeName, &choices);
  LOG_IF(ERROR, FAILED(hr)) << std::hex << hr;
  DCHECK(IsTestDefaultForProtocol(kDefaultBrowserProtocol));
  return SUCCEEDED(hr);
}

}  // namespace win8