15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <iomanip>
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <winspool.h>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <setupapi.h>  // Must be included after windows.h
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/at_exit.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_util.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_version_info_win.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/scoped_temp_dir.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h"
17bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/process/process.h"
18bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/process/launch.h"
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string16.h"
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/registry.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_handle.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/windows_version.h"
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "cloud_print/common/win/cloud_print_utils.h"
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "cloud_print/common/win/install_utils.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "cloud_print/virtual_driver/win/virtual_driver_consts.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "cloud_print/virtual_driver/win/virtual_driver_helpers.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/virtual_driver_setup_resources.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <strsafe.h>  // Must be after base headers to avoid deprecation
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      // warnings.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace cloud_print {
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kNameValue[] = L"GCP Virtual Driver";
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const wchar_t kUninstallId[] = L"{74AA24E0-AC50-4B28-BA46-9CF05467C9B7}";
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kInstallerName[] = L"virtual_driver_setup.exe";
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kGcpUrl[] = L"http://www.google.com/cloudprint";
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const wchar_t kDataFileName[] = L"gcp_driver.gpd";
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const wchar_t kDriverName[] = L"MXDWDRV.DLL";
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const wchar_t kUiDriverName[] = L"UNIDRVUI.DLL";
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const wchar_t kHelpName[] = L"UNIDRV.HLP";
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const wchar_t* kDependencyList[] = {
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  kDriverName,
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  kHelpName,
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  kUiDriverName,
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  L"STDDTYPE.GDL",
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  L"STDNAMES.GPD",
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  L"STDSCHEM.GDL",
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  L"STDSCHMX.GDL",
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  L"UNIDRV.DLL",
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  L"UNIRES.DLL",
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  L"XPSSVCS.DLL",
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kDelete[] = "delete";
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kInstallSwitch[] = "install";
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kRegisterSwitch[] = "register";
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kUninstallSwitch[] = "uninstall";
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kUnregisterSwitch[] = "unregister";
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
65a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)base::FilePath GetSystemPath(const base::string16& binary) {
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath path;
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!PathService::Get(base::DIR_SYSTEM, &path)) {
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Unable to get system path.";
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return path;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return path.Append(binary);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
74a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)base::FilePath GetNativeSystemPath(const base::string16& binary) {
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!IsSystem64Bit())
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return GetSystemPath(binary);
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath path;
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Sysnative will bypass filesystem redirection and give us
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the location of the 64bit system32 from a 32 bit process.
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!PathService::Get(base::DIR_WINDOWS, &path)) {
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Unable to get windows path.";
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return path;
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return path.Append(L"sysnative").Append(binary);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SpoolerServiceCommand(const char* command) {
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath net_path = GetNativeSystemPath(L"net");
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (net_path.empty())
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CommandLine command_line(net_path);
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  command_line.AppendArg(command);
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  command_line.AppendArg("spooler");
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  command_line.AppendArg("/y");
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::LaunchOptions options;
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  options.wait = true;
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  options.start_hidden = true;
99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  VLOG(0) << command_line.GetCommandLineString();
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::LaunchProcess(command_line, options, NULL);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT RegisterPortMonitor(bool install, const base::FilePath& install_path) {
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(install || install_path.empty());
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath target_path = GetNativeSystemPath(GetPortMonitorDllName());
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (target_path.empty()) {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Unable to get port monitor target path.";
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (install) {
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath source_path =
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        install_path.Append(GetPortMonitorDllName());
1137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (!base::CopyFile(source_path, target_path)) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Unable copy port monitor dll from " <<
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          source_path.value() << " to " << target_path.value();
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return GetLastHResult();
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  } else if (!base::PathExists(target_path)) {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Already removed.  Just "succeed" silently.
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return S_OK;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath regsvr32_path = GetNativeSystemPath(L"regsvr32.exe");
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (regsvr32_path.empty()) {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Can't find regsvr32.exe.";
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandLine command_line(regsvr32_path);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  command_line.AppendArg("/s");
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!install) {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    command_line.AppendArg("/u");
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Use system32 path here because otherwise ::AddMonitor would fail.
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  command_line.AppendArgPath(GetSystemPath(GetPortMonitorDllName()));
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::LaunchOptions options;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  options.wait = true;
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::ScopedHandle regsvr32_handle;
142f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!base::LaunchProcess(command_line.GetCommandLineString(), options,
143f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                           &regsvr32_handle)) {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Unable to launch regsvr32.exe.";
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD exit_code = S_OK;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (install) {
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!GetExitCodeProcess(regsvr32_handle, &exit_code)) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Unable to get regsvr32.exe exit code.";
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return GetLastHResult();
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (exit_code != 0) {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Regsvr32.exe failed with " << exit_code;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return HRESULT_FROM_WIN32(exit_code);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (!base::DeleteFile(target_path, false)) {
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SpoolerServiceCommand("stop");
1617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      bool deleted = base::DeleteFile(target_path, false);
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SpoolerServiceCommand("start");
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if(!deleted) {
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        LOG(ERROR) << "Unable to delete " << target_path.value();
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return S_OK;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DWORDLONG GetVersionNumber() {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORDLONG retval = 0;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<FileVersionInfo> version_info(
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FileVersionInfo::CreateFileVersionInfoForCurrentModule());
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (version_info.get()) {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FileVersionInfoWin* version_info_win =
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        static_cast<FileVersionInfoWin*>(version_info.get());
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VS_FIXEDFILEINFO* fixed_file_info = version_info_win->fixed_file_info();
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    retval = fixed_file_info->dwFileVersionMS;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    retval <<= 32;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    retval |= fixed_file_info->dwFileVersionLS;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return retval;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)UINT CALLBACK CabinetCallback(PVOID data,
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              UINT notification,
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              UINT_PTR param1,
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              UINT_PTR param2) {
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const base::FilePath* temp_path(
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      reinterpret_cast<const base::FilePath*>(data));
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (notification == SPFILENOTIFY_FILEINCABINET) {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FILE_IN_CABINET_INFO* info =
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        reinterpret_cast<FILE_IN_CABINET_INFO*>(param1);
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < arraysize(kDependencyList); i++) {
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::FilePath base_name(info->NameInCabinet);
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base_name = base_name.BaseName();
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (base::FilePath::CompareEqualIgnoreCase(base_name.value().c_str(),
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                 kDependencyList[i])) {
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        StringCchCopy(info->FullTargetName, MAX_PATH,
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      temp_path->Append(kDependencyList[i]).value().c_str());
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return FILEOP_DOIT;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FILEOP_SKIP;
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NO_ERROR;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ReadyDriverDependencies(const base::FilePath& destination) {
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // GetCorePrinterDrivers and GetPrinterDriverPackagePath only exist on
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Vista and later. Winspool.drv must be delayloaded so these calls don't
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // create problems on XP.
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DWORD size = MAX_PATH;
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    wchar_t package_path[MAX_PATH] = {0};
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CORE_PRINTER_DRIVER driver;
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    GetCorePrinterDrivers(NULL, NULL, L"{D20EA372-DD35-4950-9ED8-A6335AFE79F5}",
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          1, &driver);
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    GetPrinterDriverPackagePath(NULL, NULL, NULL, driver.szPackageID,
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                package_path, MAX_PATH, &size);
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SetupIterateCabinet(package_path, 0, &CabinetCallback,
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        &base::FilePath(destination));
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Driver files are in the sp3 cab.
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath package_path;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PathService::Get(base::DIR_WINDOWS, &package_path);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    package_path = package_path.Append(L"Driver Cache\\i386\\sp3.cab");
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SetupIterateCabinet(package_path.value().c_str(), 0, &CabinetCallback,
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        &base::FilePath(destination));
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Copy the rest from the driver cache or system dir.
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath driver_cache_path;
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    PathService::Get(base::DIR_WINDOWS, &driver_cache_path);
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    driver_cache_path = driver_cache_path.Append(L"Driver Cache\\i386");
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < arraysize(kDependencyList); ++i) {
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::FilePath dst_path = destination.Append(kDependencyList[i]);
2407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if (!base::PathExists(dst_path)) {
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::FilePath src_path = driver_cache_path.Append(kDependencyList[i]);
2427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        if (!base::PathExists(src_path))
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          src_path = GetSystemPath(kDependencyList[i]);
2447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        base::CopyFile(src_path, dst_path);
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT InstallDriver(const base::FilePath& install_path) {
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ScopedTempDir temp_path;
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!temp_path.CreateUniqueTempDir())
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return HRESULT_FROM_WIN32(ERROR_CANNOT_MAKE);
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ReadyDriverDependencies(temp_path.path());
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
256a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  std::vector<base::string16> dependent_array;
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Add all files. AddPrinterDriverEx will removes unnecessary.
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < arraysize(kDependencyList); ++i) {
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath file_path = temp_path.path().Append(kDependencyList[i]);
2607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (base::PathExists(file_path))
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      dependent_array.push_back(file_path.value());
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LOG(WARNING) << "File is missing: " << file_path.BaseName().value();
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set up paths for the files we depend on.
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath data_file = install_path.Append(kDataFileName);
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath xps_path = temp_path.path().Append(kDriverName);
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath ui_path = temp_path.path().Append(kUiDriverName);
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath ui_help_path = temp_path.path().Append(kHelpName);
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!base::PathExists(xps_path)) {
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return HRESULT_FROM_WIN32(ERROR_BAD_DRIVER);
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DRIVER_INFO_6 driver_info = {0};
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Set up supported print system version.  Must be 3.
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  driver_info.cVersion = 3;
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // None of the print API structures likes constant strings even though they
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // don't modify the string.  const_casting is the cleanest option.
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  driver_info.pDataFile = const_cast<LPWSTR>(data_file.value().c_str());
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  driver_info.pHelpFile = const_cast<LPWSTR>(ui_help_path.value().c_str());
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  driver_info.pDriverPath = const_cast<LPWSTR>(xps_path.value().c_str());
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  driver_info.pConfigFile = const_cast<LPWSTR>(ui_path.value().c_str());
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
287a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 dependent_files(JoinString(dependent_array, L'\n'));
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dependent_files.push_back(L'\n');
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::replace(dependent_files.begin(), dependent_files.end(), L'\n', L'\0');
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  driver_info.pDependentFiles = &dependent_files[0];
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set up user visible strings.
293a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 manufacturer = LoadLocalString(IDS_GOOGLE);
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  driver_info.pszMfgName = const_cast<LPWSTR>(manufacturer.c_str());
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  driver_info.pszProvider = const_cast<LPWSTR>(manufacturer.c_str());
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  driver_info.pszOEMUrl = const_cast<LPWSTR>(kGcpUrl);
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  driver_info.dwlDriverVersion = GetVersionNumber();
298a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 driver_name = LoadLocalString(IDS_DRIVER_NAME);
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  driver_info.pName = const_cast<LPWSTR>(driver_name.c_str());
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!::AddPrinterDriverEx(NULL, 6, reinterpret_cast<BYTE*>(&driver_info),
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            APD_COPY_NEW_FILES | APD_COPY_FROM_DIRECTORY)) {
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Unable to add printer driver";
304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return GetLastHResult();
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return S_OK;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT UninstallDriver() {
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int tries = 3;
311a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 driver_name = LoadLocalString(IDS_DRIVER_NAME);
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!DeletePrinterDriverEx(NULL,
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                NULL,
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const_cast<LPWSTR>(driver_name.c_str()),
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                DPD_DELETE_UNUSED_FILES,
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                0) && tries > 0) {
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (GetLastError() == ERROR_UNKNOWN_PRINTER_DRIVER) {
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(WARNING) << "Print driver is already uninstalled.";
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return S_OK;
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // After deleting the printer it can take a few seconds before
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the driver is free for deletion.  Retry a few times before giving up.
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Attempt to delete printer driver failed.  Retrying.";
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tries--;
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Sleep(2000);
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (tries <= 0) {
328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    HRESULT result = GetLastHResult();
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Unable to delete printer driver.";
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return S_OK;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT InstallPrinter(void) {
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PRINTER_INFO_2 printer_info = {0};
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // None of the print API structures likes constant strings even though they
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // don't modify the string.  const_casting is the cleanest option.
340a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 driver_name = LoadLocalString(IDS_DRIVER_NAME);
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  printer_info.pDriverName = const_cast<LPWSTR>(driver_name.c_str());
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  printer_info.pPrinterName = const_cast<LPWSTR>(driver_name.c_str());
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  printer_info.pComment =  const_cast<LPWSTR>(driver_name.c_str());
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  printer_info.pLocation = const_cast<LPWSTR>(kGcpUrl);
345a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 port_name;
346c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  printer_info.pPortName = const_cast<LPWSTR>(kPortName);
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  printer_info.Attributes = PRINTER_ATTRIBUTE_DIRECT|PRINTER_ATTRIBUTE_LOCAL;
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  printer_info.pPrintProcessor = L"winprint";
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HANDLE handle = AddPrinter(NULL, 2, reinterpret_cast<BYTE*>(&printer_info));
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (handle == NULL) {
351c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    HRESULT result = GetLastHResult();
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Unable to add printer";
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClosePrinter(handle);
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return S_OK;
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT UninstallPrinter(void) {
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HANDLE handle = NULL;
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PRINTER_DEFAULTS printer_defaults = {0};
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  printer_defaults.DesiredAccess = PRINTER_ALL_ACCESS;
363a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 driver_name = LoadLocalString(IDS_DRIVER_NAME);
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!OpenPrinter(const_cast<LPWSTR>(driver_name.c_str()),
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   &handle,
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   &printer_defaults)) {
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we can't open the printer, it was probably already removed.
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Unable to open printer";
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return S_OK;
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!DeletePrinter(handle)) {
372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    HRESULT result = GetLastHResult();
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Unable to delete printer";
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ClosePrinter(handle);
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClosePrinter(handle);
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return S_OK;
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsOSSupported() {
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't support XP service pack 2 or older.
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::Version version = base::win::GetVersion();
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (version > base::win::VERSION_XP) ||
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ((version == base::win::VERSION_XP) &&
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       (base::win::OSInfo::GetInstance()->service_pack().major >= 3));
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT RegisterVirtualDriver(const base::FilePath& install_path) {
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT result = S_OK;
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(base::DirectoryExists(install_path));
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsOSSupported()) {
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Requires XP SP3 or later.";
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION);
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result = InstallDriver(install_path);
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(result)) {
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Unable to install driver.";
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return result;
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = RegisterPortMonitor(true, install_path);
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(result)) {
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Unable to register port monitor.";
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = InstallPrinter();
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(result) &&
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      result != HRESULT_FROM_WIN32(ERROR_PRINTER_ALREADY_EXISTS)) {
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Unable to install printer.";
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return S_OK;
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT TryUnregisterVirtualDriver() {
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT result = S_OK;
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = UninstallPrinter();
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(result)) {
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Unable to delete printer.";
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result = UninstallDriver();
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(result)) {
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Unable to remove driver.";
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The second argument is ignored if the first is false.
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result = RegisterPortMonitor(false, base::FilePath());
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(result)) {
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Unable to remove port monitor.";
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return S_OK;
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT UnregisterVirtualDriver() {
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HRESULT hr = S_FALSE;
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = 0; i < 2; ++i) {
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    hr = TryUnregisterVirtualDriver();
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (SUCCEEDED(hr)) {
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Restart spooler and try again.
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SpoolerServiceCommand("stop");
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SpoolerServiceCommand("start");
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return hr;
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT DoUninstall() {
455c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DeleteGoogleUpdateKeys(kGoogleUpdateProductId);
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HRESULT result = UnregisterVirtualDriver();
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(result))
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return result;
459c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DeleteUninstallKey(kUninstallId);
460c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DeleteProgramDir(kDelete);
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return S_OK;
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT DoUnregister() {
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return UnregisterVirtualDriver();
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT DoRegister(const base::FilePath& install_path) {
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HRESULT result = UnregisterVirtualDriver();
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(result))
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return result;
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return RegisterVirtualDriver(install_path);
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT DoDelete(const base::FilePath& install_path) {
4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (install_path.value().empty())
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return E_INVALIDARG;
4787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!base::DirectoryExists(install_path))
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return S_FALSE;
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Sleep(5000);  // Give parent some time to exit.
4817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return base::DeleteFile(install_path, true) ? S_OK : E_FAIL;
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT DoInstall(const base::FilePath& install_path) {
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HRESULT result = UnregisterVirtualDriver();
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(result)) {
4872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Unable to unregister.";
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return result;
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
490c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath old_install_path = GetInstallLocation(kUninstallId);
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!old_install_path.value().empty() &&
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      install_path != old_install_path) {
4937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (base::DirectoryExists(old_install_path))
4947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      base::DeleteFile(old_install_path, true);
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
496c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CreateUninstallKey(kUninstallId, LoadLocalString(IDS_DRIVER_NAME),
497c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     kUninstallSwitch);
4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result = RegisterVirtualDriver(install_path);
4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(result))
5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return result;
501c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SetGoogleUpdateKeys(kGoogleUpdateProductId, kNameValue);
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return result;
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT ExecuteCommands() {
5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath exe_path;
5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(PathService::Get(base::DIR_EXE, &exe_path)) ||
5107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      !base::DirectoryExists(exe_path)) {
5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (command_line.HasSwitch(kDelete)) {
5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return DoDelete(command_line.GetSwitchValuePath(kDelete));
5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (command_line.HasSwitch(kUninstallSwitch)) {
5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return DoUninstall();
5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (command_line.HasSwitch(kInstallSwitch)) {
5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return DoInstall(exe_path);
5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (command_line.HasSwitch(kUnregisterSwitch)) {
5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return DoUnregister();
5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (command_line.HasSwitch(kRegisterSwitch)) {
5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return DoRegister(exe_path);
5242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return E_INVALIDARG;
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
531c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace cloud_print
532c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int WINAPI WinMain(__in  HINSTANCE hInstance,
534c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   __in  HINSTANCE hPrevInstance,
535c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   __in  LPSTR lpCmdLine,
536c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   __in  int nCmdShow) {
537a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  using namespace cloud_print;
538a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AtExitManager at_exit_manager;
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandLine::Init(0, NULL);
5412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
542a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  HRESULT retval = ExecuteCommands();
543a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
544a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (retval == HRESULT_FROM_WIN32(ERROR_BAD_DRIVER)) {
545a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    SetGoogleUpdateError(kGoogleUpdateProductId,
546a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         LoadLocalString(IDS_ERROR_NO_XPS));
547a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else if (FAILED(retval)) {
548a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    SetGoogleUpdateError(kGoogleUpdateProductId, retval);
549a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
550a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
551a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(0) << GetErrorMessage(retval)
552a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          << " HRESULT=0x" << std::setbase(16) << retval;
5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Installer is silent by default as required by Google Update.
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (CommandLine::ForCurrentProcess()->HasSwitch("verbose")) {
556a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DisplayWindowsMessage(NULL, retval, LoadLocalString(IDS_DRIVER_NAME));
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return retval;
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
560