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