1 // Copyright (c) 2012 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 "chrome/installer/mini_installer/configuration.h"
7 #include <shellapi.h> // NOLINT
9 #include "chrome/installer/mini_installer/appid.h"
10 #include "chrome/installer/mini_installer/mini_installer_constants.h"
11 #include "chrome/installer/mini_installer/mini_installer_resource.h"
12 #include "chrome/installer/mini_installer/regkey.h"
14 namespace mini_installer
{
16 Configuration::Configuration() : args_(NULL
) {
20 Configuration::~Configuration() {
24 // When multi_install is true, we are potentially:
25 // 1. Performing a multi-install of some product(s) on a clean machine.
26 // Neither the product(s) nor the multi-installer will have a
27 // ClientState key in the registry, so there is no key to be modified.
28 // 2. Upgrading an existing multi-install. The multi-installer will have
29 // a ClientState key in the registry. Only it need be modified.
30 // 3. Migrating a single-install into a multi-install. The product will
31 // have a ClientState key in the registry. Only it need be modified.
32 // To handle all cases, we inspect the product's ClientState to see if it
33 // exists and its "ap" value does not contain "-multi". This is case 3,
34 // so we modify the product's ClientState. Otherwise, we check the
35 // multi-installer's ClientState and modify it if it exists.
36 // TODO(bcwhite): Write a unit test for this that uses registry virtualization.
37 void Configuration::SetChromeAppGuid() {
39 is_system_level_
? HKEY_LOCAL_MACHINE
: HKEY_CURRENT_USER
;
40 const wchar_t* app_guid
=
42 google_update::kChromeFrameAppGuid
:
43 is_side_by_side_
? google_update::kSxSAppGuid
44 : google_update::kAppGuid
;
46 // This is the value for single-install and case 3.
47 chrome_app_guid_
= app_guid
;
49 if (is_multi_install_
) {
51 LONG ret
= ERROR_SUCCESS
;
52 if (ReadClientStateRegistryValue(root_key
, app_guid
, &ret
, value
)) {
53 // The product has a client state key. See if it's a single-install.
54 if (ret
== ERROR_FILE_NOT_FOUND
||
55 (ret
== ERROR_SUCCESS
&&
56 !FindTagInStr(value
.get(), kMultiInstallTag
, NULL
))) {
57 // yes -- case 3: use the existing key.
61 // error, case 1, or case 2: modify the multi-installer's key.
62 chrome_app_guid_
= google_update::kMultiInstallAppGuid
;
66 bool Configuration::ReadClientStateRegistryValue(
67 const HKEY root_key
, const wchar_t* app_guid
,
68 LONG
* retval
, ValueString
& value
) {
70 if (!OpenClientStateKey(root_key
, app_guid
, KEY_QUERY_VALUE
, &key
))
72 *retval
= key
.ReadSZValue(kApRegistryValue
, value
.get(), value
.capacity());
76 const wchar_t* Configuration::program() const {
77 return args_
== NULL
|| argument_count_
< 1 ? NULL
: args_
[0];
80 void Configuration::Clear() {
85 chrome_app_guid_
= google_update::kAppGuid
;
87 operation_
= INSTALL_PRODUCT
;
90 has_chrome_frame_
= false;
91 is_multi_install_
= false;
92 is_system_level_
= false;
93 is_side_by_side_
= false;
94 previous_version_
= NULL
;
97 bool Configuration::Initialize(HMODULE module
) {
99 ReadResources(module
);
100 return ParseCommandLine(::GetCommandLine());
103 // |command_line| is shared with this instance in the sense that this
104 // instance may refer to it at will throughout its lifetime, yet it will
106 bool Configuration::ParseCommandLine(const wchar_t* command_line
) {
107 command_line_
= command_line
;
108 args_
= ::CommandLineToArgvW(command_line_
, &argument_count_
);
110 for (int i
= 1; i
< argument_count_
; ++i
) {
111 if (0 == ::lstrcmpi(args_
[i
], L
"--chrome-sxs"))
112 is_side_by_side_
= true;
113 else if (0 == ::lstrcmpi(args_
[i
], L
"--chrome"))
115 else if (0 == ::lstrcmpi(args_
[i
], L
"--chrome-frame"))
116 has_chrome_frame_
= true;
117 else if (0 == ::lstrcmpi(args_
[i
], L
"--multi-install"))
118 is_multi_install_
= true;
119 else if (0 == ::lstrcmpi(args_
[i
], L
"--system-level"))
120 is_system_level_
= true;
121 else if (0 == ::lstrcmpi(args_
[i
], L
"--cleanup"))
122 operation_
= CLEANUP
;
126 if (!is_multi_install_
) {
127 has_chrome_
= !has_chrome_frame_
;
131 return args_
!= NULL
;
134 void Configuration::ReadResources(HMODULE module
) {
135 HRSRC resource_info_block
=
136 FindResource(module
, MAKEINTRESOURCE(ID_PREVIOUS_VERSION
), RT_RCDATA
);
137 if (!resource_info_block
)
140 HGLOBAL data_handle
= LoadResource(module
, resource_info_block
);
144 // The data is a Unicode string, so it must be a multiple of two bytes.
145 DWORD version_size
= SizeofResource(module
, resource_info_block
);
146 if (!version_size
|| (version_size
& 0x01) != 0)
149 void* version_data
= LockResource(data_handle
);
153 const wchar_t* version_string
= reinterpret_cast<wchar_t*>(version_data
);
154 size_t version_len
= version_size
/ sizeof(wchar_t);
156 // The string must be terminated.
157 if (version_string
[version_len
- 1])
160 previous_version_
= version_string
;
163 } // namespace mini_installer