Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(75)

Side by Side Diff: enterprise/installer/custom_actions/show_error_action.cc

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2011 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 // ========================================================================
15 //
16 // Author: grt
17 //
18 // A Windows Installer custom action that displays and logs an app installer's
19 // InstallResultUIString via MsiProcessMessage. The app's guid must be provided
20 // by the MSI wrapper by way of the CustomActionData property.
21
22 #include <windows.h>
23 #include <msi.h>
24 #include <msiquery.h>
25 #include <objbase.h>
26 #include <stdlib.h>
27
28 #include <algorithm>
29 #include <limits>
30 #include <string>
31
32 #define SOFTWARE_GOOGLE_UPDATE L"Software\\Google\\Update"
33 #define SOFTWARE_GOOGLE_UPDATE_CLIENTSTATE \
34 SOFTWARE_GOOGLE_UPDATE L"\\ClientState"
35
36 namespace {
37
38 const int kGuidStringLength = 38; // 128/4 + 4 dashes + 2 braces.
39 const DWORD kInstallerResultFailedCustomError = 1;
40 const wchar_t kPropertyCustomActionData[] = L"CustomActionData";
41 const wchar_t kRegKeyClientState[] = SOFTWARE_GOOGLE_UPDATE_CLIENTSTATE;
42 const wchar_t kRegKeyGoogleUpdate[] = SOFTWARE_GOOGLE_UPDATE;
43 const wchar_t kRegValueLastInstallerResult[] = L"LastInstallerResult";
44 const wchar_t kRegValueLastInstallerResultUIString[] =
45 L"LastInstallerResultUIString";
46
47 // Gets the value of the property named |property_name|, putting it in
48 // |property_value|. The anticipated length of the value can be provided in
49 // |expected_length| to reduce overhead. Returns true if a (possibly empty)
50 // value is read, or false on error.
51 bool GetProperty(MSIHANDLE install,
52 const wchar_t* property_name,
53 int expected_length,
54 std::wstring* property_value) {
55 DWORD value_len = static_cast<DWORD>(std::max(0, expected_length));
56 UINT result = ERROR_SUCCESS;
57 do {
58 // Make space to hold the string terminator.
59 property_value->resize(++value_len);
60 result = MsiGetProperty(install, property_name, &(*property_value)[0],
61 &value_len);
62 } while (result == ERROR_MORE_DATA &&
63 value_len <= std::numeric_limits<DWORD>::max() - 1);
64
65 if (result == ERROR_SUCCESS)
66 property_value->resize(value_len);
67 else
68 property_value->clear();
69
70 return result == ERROR_SUCCESS;
71 }
72
73 // The type of a function that returns true if |c| is a valid char in a GUID.
74 typedef bool (*IsGuidCharFn)(wchar_t c);
75
76 // A function template that returns true if |c| equals some constant |C|.
77 template<wchar_t C>
78 bool IsChar(wchar_t c) {
79 return c == C;
80 }
81
82 // Returns true if |c| is a valid hex character.
83 bool IsHexDigit(wchar_t c) {
84 return ((c >= L'0' && c <= '9') ||
85 (c >= L'a' && c <= 'f') ||
86 (c >= L'A' && c <= 'F'));
87 }
88
89 // Returns true if |guid| is a well-formed GUID.
90 bool IsGuid(const std::wstring& guid) {
91 static const IsGuidCharFn kGuidCharValidators[] = {
92 IsChar<L'{'>,
93 IsHexDigit,
94 IsHexDigit,
95 IsHexDigit,
96 IsHexDigit,
97 IsHexDigit,
98 IsHexDigit,
99 IsHexDigit,
100 IsHexDigit,
101 IsChar<L'-'>,
102 IsHexDigit,
103 IsHexDigit,
104 IsHexDigit,
105 IsHexDigit,
106 IsChar<L'-'>,
107 IsHexDigit,
108 IsHexDigit,
109 IsHexDigit,
110 IsHexDigit,
111 IsChar<L'-'>,
112 IsHexDigit,
113 IsHexDigit,
114 IsHexDigit,
115 IsHexDigit,
116 IsChar<L'-'>,
117 IsHexDigit,
118 IsHexDigit,
119 IsHexDigit,
120 IsHexDigit,
121 IsHexDigit,
122 IsHexDigit,
123 IsHexDigit,
124 IsHexDigit,
125 IsHexDigit,
126 IsHexDigit,
127 IsHexDigit,
128 IsHexDigit,
129 IsChar<L'}'>,
130 };
131
132 if (guid.size() != _countof(kGuidCharValidators))
133 return false;
134
135 for (size_t i = 0, end = guid.size(); i < end; ++i) {
136 if (!kGuidCharValidators[i](guid[i]))
137 return false;
138 }
139
140 return true;
141 }
142
143 // Gets the app guid for the product being installed. Returns false if a value
144 // that doesn't look like a GUID is read.
145 bool GetProductGuid(MSIHANDLE install, std::wstring* guid) {
146 return GetProperty(install, kPropertyCustomActionData, kGuidStringLength,
147 guid) &&
148 IsGuid(*guid);
149 }
150
151 // Populates |key_name| with the full name of |app_guid|'s ClientState registry
152 // key.
153 void GetAppClientStateKey(const std::wstring& app_guid,
154 std::wstring* key_name) {
155 const size_t base_len = _countof(kRegKeyClientState) - 1;
156 key_name->reserve(base_len + 1 + app_guid.size());
157 key_name->assign(kRegKeyClientState, base_len);
158 key_name->append(1, L'\\');
159 key_name->append(app_guid);
160 }
161
162 // Reads the string value named |value_name| in registry key |key| into
163 // |result_string|. Returns ERROR_NOT_SUPPORTED if the value exists but is not
164 // of type REG_SZ.
165 LONG ReadRegistryStringValue(HKEY key, const wchar_t* value_name,
166 std::wstring* result_string) {
167 LONG result;
168 DWORD type;
169 DWORD byte_length;
170
171 // Use all of the provided buffer.
172 result_string->resize(result_string->capacity());
173
174 // Figure out how much we can hold there, being careful about overflow.
175 byte_length = static_cast<DWORD>(std::min(
176 result_string->size(),
177 static_cast<size_t>(
178 std::numeric_limits<DWORD>::max() / sizeof(wchar_t))));
179 byte_length *= sizeof(wchar_t);
180
181 do {
182 // Read into the provided buffer.
183 BYTE* buffer = reinterpret_cast<BYTE*>(
184 result_string->empty() ? NULL : &(*result_string)[0]);
185 result = RegQueryValueEx(key, value_name, NULL, &type, buffer,
186 &byte_length);
187 if (result == ERROR_SUCCESS) {
188 const size_t chars_read = byte_length / sizeof(wchar_t);
189 if (type != REG_SZ) {
190 // The value wasn't a string.
191 result = ERROR_NOT_SUPPORTED;
192 } else if (byte_length == 0) {
193 // The string was empty.
194 result_string->clear();
195 } else if ((*result_string)[chars_read - 1] != L'\0') {
196 // The string was not terminated. Let std::basic_string do so.
197 result_string->resize(chars_read);
198 } else {
199 // The string was terminated. Trim off the terminator.
200 result_string->resize(chars_read - 1);
201 }
202 } else if (result == ERROR_MORE_DATA) {
203 // Increase the buffer and try again.
204 result_string->resize(byte_length / sizeof(wchar_t));
205 }
206 } while (result == ERROR_MORE_DATA);
207
208 return result;
209 }
210
211 // Reads the DWORD value named |value_name| in registry key |key| into |value|.
212 // Returns ERROR_NOT_SUPPORTED if the value exists but is not of type REG_DWORD.
213 LONG ReadRegistryDwordValue(HKEY key, const wchar_t* value_name, DWORD* value) {
214 LONG result;
215 DWORD type;
216 DWORD byte_length = sizeof(*value);
217
218 result = RegQueryValueEx(key, value_name, NULL, &type,
219 reinterpret_cast<BYTE*>(value), &byte_length);
220 if (result == ERROR_SUCCESS && type != REG_DWORD) {
221 // The value wasn't a DWORD.
222 result = ERROR_NOT_SUPPORTED;
223 }
224
225 return result;
226 }
227
228 // Checks to see if the app installer failed with a custom error and provided a
229 // UI string. If so, returns true and populates |result_string| with the UI
230 // string. Otherwise, returns false.
231 bool GetLastInstallerResultUIString(const std::wstring& app_guid,
232 std::wstring* result_string) {
233 std::wstring client_state_name;
234 HKEY key = NULL;
235
236 GetAppClientStateKey(app_guid, &client_state_name);
237
238 // First try looking in the app's ClientState key. Failing that, fall back to
239 // Google Update's own SOFTWARE\Google\Update key, into which GoogleUpdate.exe
240 // copies the app's value (see AppManager::ClearInstallerResultApiValues).
241 LONG result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, client_state_name.c_str(),
242 NULL, KEY_QUERY_VALUE, &key);
243 if (result != ERROR_SUCCESS) {
244 result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, kRegKeyGoogleUpdate, NULL,
245 KEY_QUERY_VALUE, &key);
246 }
247
248 if (result == ERROR_SUCCESS) {
249 // Is LastInstallerResult == INSTALLER_RESULT_FAILED_CUSTOM_ERROR?
250 DWORD last_installer_error = 0;
251 result = ReadRegistryDwordValue(key, kRegValueLastInstallerResult,
252 &last_installer_error);
253 if (result == ERROR_SUCCESS &&
254 last_installer_error == kInstallerResultFailedCustomError) {
255 result = ReadRegistryStringValue(
256 key, kRegValueLastInstallerResultUIString, result_string);
257 }
258
259 RegCloseKey(key);
260 }
261
262 return result == ERROR_SUCCESS;
263 }
264
265 } // namespace
266
267 // A DLL custom action entrypoint that performs the work described at the top
268 // of this file.
269 extern "C" UINT __stdcall ShowInstallerResultUIString(MSIHANDLE install) {
270 std::wstring app_guid;
271 std::wstring result_string;
272
273 if (GetProductGuid(install, &app_guid) &&
274 GetLastInstallerResultUIString(app_guid, &result_string) &&
275 !result_string.empty()) {
276 PMSIHANDLE record = MsiCreateRecord(0);
277 if (record != 0UL) {
278 UINT result = MsiRecordSetString(record, 0, result_string.c_str());
279 if (result == ERROR_SUCCESS)
280 MsiProcessMessage(install, INSTALLMESSAGE_ERROR, record);
281 }
282 }
283
284 return ERROR_SUCCESS;
285 }
OLDNEW
« no previous file with comments | « enterprise/installer/custom_actions/build.scons ('k') | enterprise/installer/custom_actions/show_error_action.def » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698