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.
5 #include "win8/test/metro_registration_helper.h"
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"
28 const int kRegistrationTimeoutSeconds
= 30;
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";
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() {
41 if (!PathService::Get(base::DIR_EXE
, &dir
))
44 base::FilePath
chrome_exe(dir
.Append(kChromeExe
));
45 base::FilePath
registrar(dir
.Append(kRegistrar
));
47 if (!base::PathExists(chrome_exe
) || !base::PathExists(registrar
)) {
48 LOG(ERROR
) << "Could not locate " << kChromeExe
<< " or " << kRegistrar
;
52 // Perform the registration by invoking test_registrar.exe.
53 CommandLine
register_command(registrar
);
54 register_command
.AppendArg("/RegServer");
56 base::win::ScopedHandle register_handle
;
57 if (base::LaunchProcess(register_command
, base::LaunchOptions(),
58 register_handle
.Receive())) {
60 if (base::WaitForExitCodeWithTimeout(
61 register_handle
, &ret
,
62 base::TimeDelta::FromSeconds(kRegistrationTimeoutSeconds
))) {
66 LOG(ERROR
) << "Win8 registration using "
67 << register_command
.GetCommandLineString()
68 << " failed with error code " << ret
;
71 LOG(ERROR
) << "Win8 registration using "
72 << register_command
.GetCommandLineString() << " timed out.";
76 PLOG(ERROR
) << "Failed to launch Win8 registration utility using "
77 << register_command
.GetCommandLineString();
81 // Returns true if the test viewer's progid is the default handler for
83 bool IsTestDefaultForProtocol(const wchar_t* protocol
) {
84 base::win::ScopedComPtr
<IApplicationAssociationRegistration
> registration
;
85 HRESULT hr
= registration
.CreateInstance(
86 CLSID_ApplicationAssociationRegistration
, NULL
, CLSCTX_INPROC
);
88 LOG(ERROR
) << std::hex
<< hr
;
92 base::win::ScopedCoMem
<wchar_t> current_app
;
93 hr
= registration
->QueryCurrentDefault(protocol
, AT_URLPROTOCOL
,
94 AL_EFFECTIVE
, ¤t_app
);
96 LOG(ERROR
) << std::hex
<< hr
;
100 return string16(win8::test::kDefaultTestProgId
).compare(current_app
) == 0;
107 bool MakeTestDefaultBrowserSynchronously() {
108 static const wchar_t kDefaultBrowserProtocol
[] = L
"http";
110 if (!RegisterTestDefaultBrowser())
113 // Make sure the registration changes have been acknowledged by the shell
114 // before querying for the current default.
115 SHChangeNotify(SHCNE_ASSOCCHANGED
, SHCNF_IDLIST
| SHCNF_FLUSH
, NULL
, NULL
);
117 // OpenWithDialogController will fail if the Test Runner is already default
118 // since it will not show up verbatim in the dialog (e.g., in EN-US, it will
119 // be prefixed by "Keep using ").
120 if (IsTestDefaultForProtocol(kDefaultBrowserProtocol
))
123 std::vector
<base::string16
> choices
;
124 OpenWithDialogController controller
;
125 HRESULT hr
= controller
.RunSynchronously(
126 NULL
, kDefaultBrowserProtocol
, win8::test::kDefaultTestExeName
, &choices
);
127 LOG_IF(ERROR
, FAILED(hr
)) << std::hex
<< hr
;
128 DCHECK(IsTestDefaultForProtocol(kDefaultBrowserProtocol
));
129 return SUCCEEDED(hr
);