12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "win8/test/metro_registration_helper.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <shlobj.h>
890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <vector>
1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/command_line.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/path_service.h"
16bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/process/kill.h"
17bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/process/launch.h"
18bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/process/process.h"
197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/string16.h"
2090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/win/scoped_co_mem.h"
2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/win/scoped_comptr.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/win/scoped_handle.h"
2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "win8/test/open_with_dialog_controller.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "win8/test/test_registrar_constants.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kRegistrationTimeoutSeconds = 30;
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copied from util_constants.cc to avoid taking a dependency on installer_util.
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const wchar_t kChromeExe[] = L"chrome.exe";
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const wchar_t kRegistrar[] = L"test_registrar.exe";
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Registers chrome.exe as a potential Win8 default browser.  It will then show
3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// up in the default browser selection dialog as kDefaultTestExeName. Intended
3690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// to be used by a test binary in the build output directory and assumes the
3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// presence of test_registrar.exe, a viewer process, and all needed DLLs in the
3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// same directory as the calling module.
3990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool RegisterTestDefaultBrowser() {
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath dir;
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!PathService::Get(base::DIR_EXE, &dir))
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath chrome_exe(dir.Append(kChromeExe));
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath registrar(dir.Append(kRegistrar));
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!base::PathExists(chrome_exe) || !base::PathExists(registrar)) {
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Could not locate " << kChromeExe << " or " << kRegistrar;
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Perform the registration by invoking test_registrar.exe.
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CommandLine register_command(registrar);
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  register_command.AppendArg("/RegServer");
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::ScopedHandle register_handle;
57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (base::LaunchProcess(register_command.GetCommandLineString(),
58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                          base::LaunchOptions(),
59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                          &register_handle)) {
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int ret = 0;
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (base::WaitForExitCodeWithTimeout(
62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            register_handle.Get(), &ret,
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            base::TimeDelta::FromSeconds(kRegistrationTimeoutSeconds))) {
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (ret == 0) {
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return true;
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        LOG(ERROR) << "Win8 registration using "
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   << register_command.GetCommandLineString()
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   << " failed with error code " << ret;
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LOG(ERROR) << "Win8 registration using "
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 << register_command.GetCommandLineString() << " timed out.";
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PLOG(ERROR) << "Failed to launch Win8 registration utility using "
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              << register_command.GetCommandLineString();
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Returns true if the test viewer's progid is the default handler for
8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// |protocol|.
8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool IsTestDefaultForProtocol(const wchar_t* protocol) {
8590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::win::ScopedComPtr<IApplicationAssociationRegistration> registration;
8690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  HRESULT hr = registration.CreateInstance(
8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      CLSID_ApplicationAssociationRegistration, NULL, CLSCTX_INPROC);
8890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (FAILED(hr)) {
8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LOG(ERROR) << std::hex << hr;
9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return false;
9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::win::ScopedCoMem<wchar_t> current_app;
9490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  hr = registration->QueryCurrentDefault(protocol, AT_URLPROTOCOL,
9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                         AL_EFFECTIVE, &current_app);
9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (FAILED(hr)) {
9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LOG(ERROR) << std::hex << hr;
9890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return false;
9990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
10090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return !base::string16(win8::test::kDefaultTestProgId).compare(current_app);
10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
10390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
10490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace
10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
10690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace win8 {
10790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
10890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool MakeTestDefaultBrowserSynchronously() {
10990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  static const wchar_t kDefaultBrowserProtocol[] = L"http";
11090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!RegisterTestDefaultBrowser())
11290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return false;
11390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Make sure the registration changes have been acknowledged by the shell
11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // before querying for the current default.
11690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSH, NULL, NULL);
11790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // OpenWithDialogController will fail if the Test Runner is already default
11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // since it will not show up verbatim in the dialog (e.g., in EN-US, it will
12090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // be prefixed by "Keep using ").
12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (IsTestDefaultForProtocol(kDefaultBrowserProtocol))
12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return true;
12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::vector<base::string16> choices;
12590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  OpenWithDialogController controller;
12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  HRESULT hr = controller.RunSynchronously(
12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      NULL, kDefaultBrowserProtocol, win8::test::kDefaultTestExeName, &choices);
12890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  LOG_IF(ERROR, FAILED(hr)) << std::hex << hr;
12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(IsTestDefaultForProtocol(kDefaultBrowserProtocol));
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return SUCCEEDED(hr);
13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace win8
134