| Index: enterprise/installer/custom_actions/show_error_action.cc
|
| diff --git a/enterprise/installer/custom_actions/show_error_action.cc b/enterprise/installer/custom_actions/show_error_action.cc
|
| deleted file mode 100644
|
| index a44f0523d828aa37964f0ed00cfda51fc76502ce..0000000000000000000000000000000000000000
|
| --- a/enterprise/installer/custom_actions/show_error_action.cc
|
| +++ /dev/null
|
| @@ -1,285 +0,0 @@
|
| -// Copyright 2011 Google Inc.
|
| -//
|
| -// Licensed under the Apache License, Version 2.0 (the "License");
|
| -// you may not use this file except in compliance with the License.
|
| -// You may obtain a copy of the License at
|
| -//
|
| -// http://www.apache.org/licenses/LICENSE-2.0
|
| -//
|
| -// Unless required by applicable law or agreed to in writing, software
|
| -// distributed under the License is distributed on an "AS IS" BASIS,
|
| -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| -// See the License for the specific language governing permissions and
|
| -// limitations under the License.
|
| -// ========================================================================
|
| -//
|
| -// Author: grt
|
| -//
|
| -// A Windows Installer custom action that displays and logs an app installer's
|
| -// InstallResultUIString via MsiProcessMessage. The app's guid must be provided
|
| -// by the MSI wrapper by way of the CustomActionData property.
|
| -
|
| -#include <windows.h>
|
| -#include <msi.h>
|
| -#include <msiquery.h>
|
| -#include <objbase.h>
|
| -#include <stdlib.h>
|
| -
|
| -#include <algorithm>
|
| -#include <limits>
|
| -#include <string>
|
| -
|
| -#define SOFTWARE_GOOGLE_UPDATE L"Software\\Google\\Update"
|
| -#define SOFTWARE_GOOGLE_UPDATE_CLIENTSTATE \
|
| - SOFTWARE_GOOGLE_UPDATE L"\\ClientState"
|
| -
|
| -namespace {
|
| -
|
| -const int kGuidStringLength = 38; // 128/4 + 4 dashes + 2 braces.
|
| -const DWORD kInstallerResultFailedCustomError = 1;
|
| -const wchar_t kPropertyCustomActionData[] = L"CustomActionData";
|
| -const wchar_t kRegKeyClientState[] = SOFTWARE_GOOGLE_UPDATE_CLIENTSTATE;
|
| -const wchar_t kRegKeyGoogleUpdate[] = SOFTWARE_GOOGLE_UPDATE;
|
| -const wchar_t kRegValueLastInstallerResult[] = L"LastInstallerResult";
|
| -const wchar_t kRegValueLastInstallerResultUIString[] =
|
| - L"LastInstallerResultUIString";
|
| -
|
| -// Gets the value of the property named |property_name|, putting it in
|
| -// |property_value|. The anticipated length of the value can be provided in
|
| -// |expected_length| to reduce overhead. Returns true if a (possibly empty)
|
| -// value is read, or false on error.
|
| -bool GetProperty(MSIHANDLE install,
|
| - const wchar_t* property_name,
|
| - int expected_length,
|
| - std::wstring* property_value) {
|
| - DWORD value_len = static_cast<DWORD>(std::max(0, expected_length));
|
| - UINT result = ERROR_SUCCESS;
|
| - do {
|
| - // Make space to hold the string terminator.
|
| - property_value->resize(++value_len);
|
| - result = MsiGetProperty(install, property_name, &(*property_value)[0],
|
| - &value_len);
|
| - } while (result == ERROR_MORE_DATA &&
|
| - value_len <= std::numeric_limits<DWORD>::max() - 1);
|
| -
|
| - if (result == ERROR_SUCCESS)
|
| - property_value->resize(value_len);
|
| - else
|
| - property_value->clear();
|
| -
|
| - return result == ERROR_SUCCESS;
|
| -}
|
| -
|
| -// The type of a function that returns true if |c| is a valid char in a GUID.
|
| -typedef bool (*IsGuidCharFn)(wchar_t c);
|
| -
|
| -// A function template that returns true if |c| equals some constant |C|.
|
| -template<wchar_t C>
|
| -bool IsChar(wchar_t c) {
|
| - return c == C;
|
| -}
|
| -
|
| -// Returns true if |c| is a valid hex character.
|
| -bool IsHexDigit(wchar_t c) {
|
| - return ((c >= L'0' && c <= '9') ||
|
| - (c >= L'a' && c <= 'f') ||
|
| - (c >= L'A' && c <= 'F'));
|
| -}
|
| -
|
| -// Returns true if |guid| is a well-formed GUID.
|
| -bool IsGuid(const std::wstring& guid) {
|
| - static const IsGuidCharFn kGuidCharValidators[] = {
|
| - IsChar<L'{'>,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsChar<L'-'>,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsChar<L'-'>,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsChar<L'-'>,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsChar<L'-'>,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsHexDigit,
|
| - IsChar<L'}'>,
|
| - };
|
| -
|
| - if (guid.size() != _countof(kGuidCharValidators))
|
| - return false;
|
| -
|
| - for (size_t i = 0, end = guid.size(); i < end; ++i) {
|
| - if (!kGuidCharValidators[i](guid[i]))
|
| - return false;
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -// Gets the app guid for the product being installed. Returns false if a value
|
| -// that doesn't look like a GUID is read.
|
| -bool GetProductGuid(MSIHANDLE install, std::wstring* guid) {
|
| - return GetProperty(install, kPropertyCustomActionData, kGuidStringLength,
|
| - guid) &&
|
| - IsGuid(*guid);
|
| -}
|
| -
|
| -// Populates |key_name| with the full name of |app_guid|'s ClientState registry
|
| -// key.
|
| -void GetAppClientStateKey(const std::wstring& app_guid,
|
| - std::wstring* key_name) {
|
| - const size_t base_len = _countof(kRegKeyClientState) - 1;
|
| - key_name->reserve(base_len + 1 + app_guid.size());
|
| - key_name->assign(kRegKeyClientState, base_len);
|
| - key_name->append(1, L'\\');
|
| - key_name->append(app_guid);
|
| -}
|
| -
|
| -// Reads the string value named |value_name| in registry key |key| into
|
| -// |result_string|. Returns ERROR_NOT_SUPPORTED if the value exists but is not
|
| -// of type REG_SZ.
|
| -LONG ReadRegistryStringValue(HKEY key, const wchar_t* value_name,
|
| - std::wstring* result_string) {
|
| - LONG result;
|
| - DWORD type;
|
| - DWORD byte_length;
|
| -
|
| - // Use all of the provided buffer.
|
| - result_string->resize(result_string->capacity());
|
| -
|
| - // Figure out how much we can hold there, being careful about overflow.
|
| - byte_length = static_cast<DWORD>(std::min(
|
| - result_string->size(),
|
| - static_cast<size_t>(
|
| - std::numeric_limits<DWORD>::max() / sizeof(wchar_t))));
|
| - byte_length *= sizeof(wchar_t);
|
| -
|
| - do {
|
| - // Read into the provided buffer.
|
| - BYTE* buffer = reinterpret_cast<BYTE*>(
|
| - result_string->empty() ? NULL : &(*result_string)[0]);
|
| - result = RegQueryValueEx(key, value_name, NULL, &type, buffer,
|
| - &byte_length);
|
| - if (result == ERROR_SUCCESS) {
|
| - const size_t chars_read = byte_length / sizeof(wchar_t);
|
| - if (type != REG_SZ) {
|
| - // The value wasn't a string.
|
| - result = ERROR_NOT_SUPPORTED;
|
| - } else if (byte_length == 0) {
|
| - // The string was empty.
|
| - result_string->clear();
|
| - } else if ((*result_string)[chars_read - 1] != L'\0') {
|
| - // The string was not terminated. Let std::basic_string do so.
|
| - result_string->resize(chars_read);
|
| - } else {
|
| - // The string was terminated. Trim off the terminator.
|
| - result_string->resize(chars_read - 1);
|
| - }
|
| - } else if (result == ERROR_MORE_DATA) {
|
| - // Increase the buffer and try again.
|
| - result_string->resize(byte_length / sizeof(wchar_t));
|
| - }
|
| - } while (result == ERROR_MORE_DATA);
|
| -
|
| - return result;
|
| -}
|
| -
|
| -// Reads the DWORD value named |value_name| in registry key |key| into |value|.
|
| -// Returns ERROR_NOT_SUPPORTED if the value exists but is not of type REG_DWORD.
|
| -LONG ReadRegistryDwordValue(HKEY key, const wchar_t* value_name, DWORD* value) {
|
| - LONG result;
|
| - DWORD type;
|
| - DWORD byte_length = sizeof(*value);
|
| -
|
| - result = RegQueryValueEx(key, value_name, NULL, &type,
|
| - reinterpret_cast<BYTE*>(value), &byte_length);
|
| - if (result == ERROR_SUCCESS && type != REG_DWORD) {
|
| - // The value wasn't a DWORD.
|
| - result = ERROR_NOT_SUPPORTED;
|
| - }
|
| -
|
| - return result;
|
| -}
|
| -
|
| -// Checks to see if the app installer failed with a custom error and provided a
|
| -// UI string. If so, returns true and populates |result_string| with the UI
|
| -// string. Otherwise, returns false.
|
| -bool GetLastInstallerResultUIString(const std::wstring& app_guid,
|
| - std::wstring* result_string) {
|
| - std::wstring client_state_name;
|
| - HKEY key = NULL;
|
| -
|
| - GetAppClientStateKey(app_guid, &client_state_name);
|
| -
|
| - // First try looking in the app's ClientState key. Failing that, fall back to
|
| - // Google Update's own SOFTWARE\Google\Update key, into which GoogleUpdate.exe
|
| - // copies the app's value (see AppManager::ClearInstallerResultApiValues).
|
| - LONG result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, client_state_name.c_str(),
|
| - NULL, KEY_QUERY_VALUE, &key);
|
| - if (result != ERROR_SUCCESS) {
|
| - result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, kRegKeyGoogleUpdate, NULL,
|
| - KEY_QUERY_VALUE, &key);
|
| - }
|
| -
|
| - if (result == ERROR_SUCCESS) {
|
| - // Is LastInstallerResult == INSTALLER_RESULT_FAILED_CUSTOM_ERROR?
|
| - DWORD last_installer_error = 0;
|
| - result = ReadRegistryDwordValue(key, kRegValueLastInstallerResult,
|
| - &last_installer_error);
|
| - if (result == ERROR_SUCCESS &&
|
| - last_installer_error == kInstallerResultFailedCustomError) {
|
| - result = ReadRegistryStringValue(
|
| - key, kRegValueLastInstallerResultUIString, result_string);
|
| - }
|
| -
|
| - RegCloseKey(key);
|
| - }
|
| -
|
| - return result == ERROR_SUCCESS;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -// A DLL custom action entrypoint that performs the work described at the top
|
| -// of this file.
|
| -extern "C" UINT __stdcall ShowInstallerResultUIString(MSIHANDLE install) {
|
| - std::wstring app_guid;
|
| - std::wstring result_string;
|
| -
|
| - if (GetProductGuid(install, &app_guid) &&
|
| - GetLastInstallerResultUIString(app_guid, &result_string) &&
|
| - !result_string.empty()) {
|
| - PMSIHANDLE record = MsiCreateRecord(0);
|
| - if (record != 0UL) {
|
| - UINT result = MsiRecordSetString(record, 0, result_string.c_str());
|
| - if (result == ERROR_SUCCESS)
|
| - MsiProcessMessage(install, INSTALLMESSAGE_ERROR, record);
|
| - }
|
| - }
|
| -
|
| - return ERROR_SUCCESS;
|
| -}
|
|
|