1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file.
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "cloud_print/service/win/installer.h"
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <winerror.h>
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/at_exit.h"
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/command_line.h"
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/file_util.h"
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/path_service.h"
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/win/scoped_com_initializer.h"
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/win/shortcut.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "cloud_print/common/win/cloud_print_utils.h"
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "cloud_print/common/win/install_utils.h"
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "cloud_print/resources.h"
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "cloud_print/service/service_constants.h"
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "cloud_print/service/service_switches.h"
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "cloud_print/service/win/service_controller.h"
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace {
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const wchar_t kConfigBinaryName[] = L"cloud_print_service_config.exe";
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)base::FilePath GetShortcutPath(int dir_key, bool with_subdir) {
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath path;
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!PathService::Get(dir_key, &path))
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return base::FilePath();
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  path = path.Append(cloud_print::LoadLocalString(IDS_FULL_PRODUCT_NAME));
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (with_subdir)
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    path = path.Append(cloud_print::LoadLocalString(IDS_FULL_PRODUCT_NAME));
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return path.InsertBeforeExtension(L".lnk");
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void CreateShortcut(int dir_key, bool with_subdir,
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    base::win::ShortcutOperation operation) {
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath path = GetShortcutPath(dir_key, with_subdir);
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (path.empty())
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  file_util::CreateDirectory(path.DirName());
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::win::ShortcutProperties properties;
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath exe_path;
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!PathService::Get(base::FILE_EXE, &exe_path))
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  exe_path = exe_path.DirName().Append(base::FilePath(kConfigBinaryName));
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  properties.set_target(exe_path);
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  properties.set_working_dir(exe_path.DirName());
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CreateOrUpdateShortcutLink(path, properties, operation);
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void CreateShortcuts(bool create_always) {
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::win::ScopedCOMInitializer co_init;
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::win::ShortcutOperation operation =
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      create_always ? base::win::SHORTCUT_CREATE_ALWAYS :
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      base::win::SHORTCUT_REPLACE_EXISTING;
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CreateShortcut(base::DIR_COMMON_START_MENU, true, operation);
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CreateShortcut(base::DIR_COMMON_DESKTOP, false, operation);
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void DeleteShortcut(int dir_key, bool with_subdir) {
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath path = GetShortcutPath(dir_key, with_subdir);
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (path.empty())
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (with_subdir)
677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    base::DeleteFile(path.DirName(), true);
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  else
697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    base::DeleteFile(path, false);
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void DeleteShortcuts() {
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DeleteShortcut(base::DIR_COMMON_START_MENU, true);
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DeleteShortcut(base::DIR_COMMON_DESKTOP, false);
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)HRESULT ProcessInstallerSwitches() {
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const CommandLine& command_line(*CommandLine::ForCurrentProcess());
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (command_line.HasSwitch(kInstallSwitch)) {
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::FilePath old_location =
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        cloud_print::GetInstallLocation(kGoogleUpdateId);
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    cloud_print::CreateUninstallKey(
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        kGoogleUpdateId, cloud_print::LoadLocalString(IDS_FULL_PRODUCT_NAME),
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        kUninstallSwitch);
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ServiceController controller;
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    HRESULT hr = controller.UpdateBinaryPath();
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (FAILED(hr))
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return hr;
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!old_location.empty() &&
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        cloud_print::IsProgramsFilesParent(old_location) &&
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        old_location != cloud_print::GetInstallLocation(kGoogleUpdateId)) {
987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      base::DeleteFile(old_location, true);
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    cloud_print::SetGoogleUpdateKeys(
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        kGoogleUpdateId, cloud_print::LoadLocalString(IDS_FULL_PRODUCT_NAME));
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    CreateShortcuts(old_location.empty());
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return S_OK;
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else if (command_line.HasSwitch(kUninstallSwitch)) {
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ServiceController controller;
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    HRESULT hr = controller.UninstallService();
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (FAILED(hr))
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return hr;
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DeleteShortcuts();
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    cloud_print::DeleteGoogleUpdateKeys(kGoogleUpdateId);
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    cloud_print::DeleteUninstallKey(kGoogleUpdateId);
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    cloud_print::DeleteProgramDir(kDeleteSwitch);
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return S_OK;
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else if (command_line.HasSwitch(kDeleteSwitch)) {
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::FilePath delete_path = command_line.GetSwitchValuePath(kDeleteSwitch);
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!delete_path.empty() &&
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        cloud_print::IsProgramsFilesParent(delete_path)) {
1237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      base::DeleteFile(delete_path, true);
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return S_OK;
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return S_FALSE;
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class CloudPrintServiceSetupModule
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : public ATL::CAtlExeModuleT<CloudPrintServiceSetupModule> {
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)CloudPrintServiceSetupModule _AtlModule;
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)int WINAPI WinMain(__in  HINSTANCE hInstance,
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   __in  HINSTANCE hPrevInstance,
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   __in  LPSTR lpCmdLine,
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                   __in  int nCmdShow) {
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::AtExitManager at_exit;
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CommandLine::Init(0, NULL);
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return ProcessInstallerSwitches();
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
145