mirror of https://github.com/BOINC/boinc.git
989 lines
24 KiB
C++
989 lines
24 KiB
C++
// Berkeley Open Infrastructure for Network Computing
|
|
// http://boinc.berkeley.edu
|
|
// Copyright (C) 2005 University of California
|
|
//
|
|
// This is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU Lesser General Public
|
|
// License as published by the Free Software Foundation;
|
|
// either version 2.1 of the License, or (at your option) any later version.
|
|
//
|
|
// This software is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
// See the GNU Lesser General Public License for more details.
|
|
//
|
|
// To view the GNU Lesser General Public License visit
|
|
// http://www.gnu.org/copyleft/lesser.html
|
|
// or write to the Free Software Foundation, Inc.,
|
|
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include "boinccas.h"
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: BOINCCABase::BOINCCABase
|
|
//
|
|
// Description: Initialize the Custom Action infrastructure.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
BOINCCABase::BOINCCABase(
|
|
MSIHANDLE hMSIHandle,
|
|
const tstring strActionName,
|
|
const tstring strProgressTitle
|
|
)
|
|
{
|
|
|
|
// Store the parameters for later use
|
|
m_hMSIHandle = hMSIHandle;
|
|
m_strActionName = strActionName;
|
|
m_strProgressTitle = strProgressTitle;
|
|
|
|
// Initialize all other values to zero or null
|
|
m_phActionStartRec = NULL;
|
|
m_phActionDataRec = NULL;
|
|
m_phProgressRec = NULL;
|
|
m_phLogInfoRec = NULL;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: BOINCCABase::~BOINCCABase
|
|
//
|
|
// Description: Cleanup up allocation resources.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
BOINCCABase::~BOINCCABase()
|
|
{
|
|
|
|
if (m_phActionStartRec)
|
|
{
|
|
MsiCloseHandle(m_phActionStartRec);
|
|
m_phActionStartRec = NULL;
|
|
}
|
|
|
|
if (m_phActionDataRec)
|
|
{
|
|
MsiCloseHandle(m_phActionDataRec);
|
|
m_phActionDataRec = NULL;
|
|
}
|
|
|
|
if (m_phProgressRec)
|
|
{
|
|
MsiCloseHandle(m_phProgressRec);
|
|
m_phProgressRec = NULL;
|
|
}
|
|
|
|
if (m_phLogInfoRec)
|
|
{
|
|
MsiCloseHandle(m_phLogInfoRec);
|
|
m_phLogInfoRec = NULL;
|
|
}
|
|
|
|
m_strActionName.clear();
|
|
m_strProgressTitle.clear();
|
|
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: Execute
|
|
//
|
|
// Description:
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
UINT BOINCCABase::Execute()
|
|
{
|
|
UINT uiReturnValue = 0;
|
|
|
|
OnInitialize();
|
|
|
|
if ( TRUE == MsiGetMode( m_hMSIHandle, MSIRUNMODE_SCHEDULED ) )
|
|
{
|
|
uiReturnValue = OnInstall();
|
|
}
|
|
else if ( TRUE == MsiGetMode( m_hMSIHandle, MSIRUNMODE_COMMIT ) )
|
|
{
|
|
uiReturnValue = OnCommit();
|
|
}
|
|
else if ( TRUE == MsiGetMode( m_hMSIHandle, MSIRUNMODE_ROLLBACK ) )
|
|
{
|
|
uiReturnValue = OnRollback();
|
|
}
|
|
else
|
|
{
|
|
uiReturnValue = OnExecution();
|
|
}
|
|
|
|
OnCleanup();
|
|
|
|
return uiReturnValue;
|
|
}
|
|
|
|
|
|
static BOOL IsVersionNewer(const tstring v1, const tstring v2) {
|
|
int v1_maj=0, v1_min=0, v1_rel=0;
|
|
int v2_maj=0, v2_min=0, v2_rel=0;
|
|
|
|
_stscanf(v1.c_str(), _T("%d.%d.%d"), &v1_maj, &v1_min, &v1_rel);
|
|
_stscanf(v2.c_str(), _T("%d.%d.%d"), &v2_maj, &v2_min, &v2_rel);
|
|
|
|
if (v1_maj > v2_maj) return TRUE;
|
|
if (v1_maj < v2_maj) return FALSE;
|
|
if (v1_min > v2_min) return TRUE;
|
|
if (v1_min < v2_min) return FALSE;
|
|
if (v1_rel > v2_rel) return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: SetUpgradeParameters
|
|
//
|
|
// Description:
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
UINT BOINCCABase::SetUpgradeParameters()
|
|
{
|
|
tstring strCurrentProductVersion;
|
|
UINT uiReturnValue = 0;
|
|
|
|
uiReturnValue = GetProperty( _T("ProductVersion"), strCurrentProductVersion );
|
|
if ( uiReturnValue ) return uiReturnValue;
|
|
|
|
uiReturnValue = SetRegistryValue( _T("UpgradingTo"), strCurrentProductVersion );
|
|
if ( uiReturnValue ) return uiReturnValue;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: IsUpgrading
|
|
//
|
|
// Description:
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
BOOL BOINCCABase::IsUpgrading()
|
|
{
|
|
tstring strCurrentProductVersion;
|
|
tstring strRegistryProductVersion;
|
|
UINT uiReturnValue = 0;
|
|
|
|
uiReturnValue = GetProperty( _T("ProductVersion"), strCurrentProductVersion );
|
|
if ( uiReturnValue ) return FALSE;
|
|
|
|
uiReturnValue = GetRegistryValue( _T("UpgradingTo"), strRegistryProductVersion );
|
|
if ( uiReturnValue ) return FALSE;
|
|
|
|
return IsVersionNewer(strRegistryProductVersion, strCurrentProductVersion);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: OnInitialize
|
|
//
|
|
// Description:
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
UINT BOINCCABase::OnInitialize()
|
|
{
|
|
UINT uiReturnValue = 0;
|
|
|
|
m_phActionStartRec = MsiCreateRecord(3);
|
|
assert(NULL != m_phActionStartRec);
|
|
|
|
MsiRecordSetString(m_phActionStartRec, 1, m_strActionName.c_str());
|
|
MsiRecordSetString(m_phActionStartRec, 2, m_strProgressTitle.c_str());
|
|
MsiRecordSetString(m_phActionStartRec, 3, _T("[1]"));
|
|
uiReturnValue = MsiProcessMessage(m_hMSIHandle, INSTALLMESSAGE_ACTIONSTART, m_phActionStartRec);
|
|
if ((uiReturnValue == IDCANCEL))
|
|
return ERROR_INSTALL_USEREXIT;
|
|
|
|
// Give the UI a chance to refresh.
|
|
Sleep(0);
|
|
|
|
m_phActionDataRec = MsiCreateRecord(3);
|
|
assert(NULL != m_phActionDataRec);
|
|
|
|
|
|
m_phProgressRec = MsiCreateRecord(3);
|
|
assert(NULL != m_phProgressRec);
|
|
|
|
MsiRecordSetInteger(m_phProgressRec, 1, 1);
|
|
MsiRecordSetInteger(m_phProgressRec, 2, 1);
|
|
MsiRecordSetInteger(m_phProgressRec, 3, 0);
|
|
uiReturnValue = MsiProcessMessage(m_hMSIHandle, INSTALLMESSAGE_PROGRESS, m_phProgressRec);
|
|
if ((uiReturnValue == IDCANCEL))
|
|
return ERROR_INSTALL_USEREXIT;
|
|
|
|
|
|
m_phLogInfoRec = MsiCreateRecord(3);
|
|
assert(NULL != m_phLogInfoRec);
|
|
|
|
MsiRecordSetString (m_phLogInfoRec, 0, _T("Custom Message : Action Name: [1] Description: [2] Error Code: [3] "));
|
|
MsiRecordSetString (m_phLogInfoRec, 1, m_strActionName.c_str());
|
|
|
|
|
|
LogMessage(
|
|
INSTALLMESSAGE_INFO,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
_T("Starting Custom Action")
|
|
);
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: OnCleanup
|
|
//
|
|
// Description:
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
UINT BOINCCABase::OnCleanup()
|
|
{
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: OnInstall
|
|
//
|
|
// Description:
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
UINT BOINCCABase::OnInstall()
|
|
{
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: OnRollback
|
|
//
|
|
// Description:
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
UINT BOINCCABase::OnRollback()
|
|
{
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: OnCommit
|
|
//
|
|
// Description:
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
UINT BOINCCABase::OnCommit()
|
|
{
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: OnExecution
|
|
//
|
|
// Description:
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
UINT BOINCCABase::OnExecution()
|
|
{
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: GetRegistryValue
|
|
//
|
|
// Description:
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
UINT BOINCCABase::GetRegistryValue(
|
|
const tstring strName,
|
|
tstring& strValue,
|
|
bool bDisplayValue
|
|
)
|
|
{
|
|
LONG lReturnValue;
|
|
HKEY hkSetupHive;
|
|
DWORD dwSize = 0;
|
|
LPTSTR lpszRegistryValue = NULL;
|
|
tstring strMessage;
|
|
|
|
lReturnValue = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
_T("SOFTWARE\\Space Sciences Laboratory, U.C. Berkeley\\BOINC Setup"),
|
|
0,
|
|
KEY_READ,
|
|
&hkSetupHive
|
|
);
|
|
if (lReturnValue != ERROR_SUCCESS) return ERROR_INSTALL_FAILURE;
|
|
|
|
// How large does our buffer need to be?
|
|
RegQueryValueEx(
|
|
hkSetupHive,
|
|
strName.c_str(),
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&dwSize
|
|
);
|
|
|
|
// Allocate the buffer space.
|
|
lpszRegistryValue = (LPTSTR) malloc(dwSize);
|
|
(*lpszRegistryValue) = NULL;
|
|
|
|
// Now get the data
|
|
lReturnValue = RegQueryValueEx(
|
|
hkSetupHive,
|
|
strName.c_str(),
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)lpszRegistryValue,
|
|
&dwSize
|
|
);
|
|
|
|
// Send up the returned value.
|
|
if (lReturnValue == ERROR_SUCCESS) strValue = lpszRegistryValue;
|
|
|
|
// Cleanup
|
|
RegCloseKey(hkSetupHive);
|
|
free(lpszRegistryValue);
|
|
|
|
// One last check to make sure everything is on the up and up.
|
|
if (lReturnValue != ERROR_SUCCESS) return ERROR_INSTALL_FAILURE;
|
|
|
|
|
|
strMessage = _T("Successfully retrieved registry value '") + strName;
|
|
strMessage += _T("' with a value of '");
|
|
if (bDisplayValue)
|
|
strMessage += strValue;
|
|
else
|
|
strMessage += _T("<Value Hidden>");
|
|
strMessage += _T("'");
|
|
|
|
LogMessage(
|
|
INSTALLMESSAGE_INFO,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
strMessage.c_str()
|
|
);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: SetRegistryValue
|
|
//
|
|
// Description:
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
UINT BOINCCABase::SetRegistryValue(
|
|
const tstring strName,
|
|
const tstring strValue,
|
|
bool bDisplayValue
|
|
)
|
|
{
|
|
LONG lReturnValue;
|
|
HKEY hkSetupHive;
|
|
tstring strMessage;
|
|
|
|
lReturnValue = RegCreateKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
_T("SOFTWARE\\Space Sciences Laboratory, U.C. Berkeley\\BOINC Setup"),
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_READ | KEY_WRITE,
|
|
NULL,
|
|
&hkSetupHive,
|
|
NULL
|
|
);
|
|
if (lReturnValue != ERROR_SUCCESS) return ERROR_INSTALL_FAILURE;
|
|
|
|
lReturnValue = RegSetValueEx(
|
|
hkSetupHive,
|
|
strName.c_str(),
|
|
0,
|
|
REG_SZ,
|
|
(CONST BYTE *)strValue.c_str(),
|
|
(DWORD)(strValue.size()*sizeof(TCHAR))
|
|
);
|
|
|
|
RegCloseKey(hkSetupHive);
|
|
if (lReturnValue != ERROR_SUCCESS) return ERROR_INSTALL_FAILURE;
|
|
|
|
strMessage = _T("Successfully set registry value '") + strName;
|
|
strMessage += _T("' to a value of '");
|
|
if (bDisplayValue)
|
|
strMessage += strValue;
|
|
else
|
|
strMessage += _T("<Value Hidden>");
|
|
strMessage += _T("'");
|
|
|
|
LogMessage(
|
|
INSTALLMESSAGE_INFO,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
strMessage.c_str()
|
|
);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: GetProperty
|
|
//
|
|
// Description:
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
UINT BOINCCABase::GetProperty(
|
|
const tstring strPropertyName,
|
|
tstring& strPropertyValue,
|
|
bool bDisplayValue
|
|
)
|
|
{
|
|
LPTSTR lpszBuffer = NULL;
|
|
DWORD dwCharacterCount = 0;
|
|
tstring strMessage;
|
|
UINT uiReturnValue = 0;
|
|
|
|
uiReturnValue = MsiGetProperty(m_hMSIHandle, strPropertyName.c_str(), _T(""), &dwCharacterCount);
|
|
switch(uiReturnValue)
|
|
{
|
|
case ERROR_INVALID_HANDLE:
|
|
case ERROR_INVALID_PARAMETER:
|
|
strMessage = _T("Failed to get '") + strPropertyName;
|
|
strMessage += _T("'");
|
|
|
|
LogMessage(
|
|
INSTALLMESSAGE_INFO,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
strMessage.c_str()
|
|
);
|
|
return ERROR_INSTALL_FAILURE;
|
|
break;
|
|
}
|
|
|
|
// Allocate memory for the property value return buffer
|
|
lpszBuffer = (LPTSTR) malloc( ((++dwCharacterCount)*sizeof(LPTSTR)) );
|
|
uiReturnValue = MsiGetProperty(m_hMSIHandle, strPropertyName.c_str(), lpszBuffer, &dwCharacterCount);
|
|
switch(uiReturnValue)
|
|
{
|
|
case ERROR_INVALID_HANDLE:
|
|
case ERROR_INVALID_PARAMETER:
|
|
strMessage = _T("Failed to get '") + strPropertyName;
|
|
strMessage += _T("' after allocating the buffer");
|
|
|
|
LogMessage(
|
|
INSTALLMESSAGE_INFO,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
strMessage.c_str()
|
|
);
|
|
if ( lpszBuffer ) free( lpszBuffer );
|
|
return ERROR_INSTALL_FAILURE;
|
|
break;
|
|
}
|
|
|
|
strPropertyValue = lpszBuffer;
|
|
free( lpszBuffer );
|
|
|
|
strMessage = _T("Successfully retrieved '") + strPropertyName;
|
|
strMessage += _T("' with a value of '");
|
|
if (bDisplayValue)
|
|
strMessage += strPropertyValue;
|
|
else
|
|
strMessage += _T("<Value Hidden>");
|
|
strMessage += _T("'");
|
|
|
|
LogMessage(
|
|
INSTALLMESSAGE_INFO,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
strMessage.c_str()
|
|
);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: SetProperty
|
|
//
|
|
// Description:
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
UINT BOINCCABase::SetProperty(
|
|
const tstring strPropertyName,
|
|
const tstring strPropertyValue,
|
|
bool bDisplayValue
|
|
)
|
|
{
|
|
tstring strMessage;
|
|
UINT uiReturnValue = 0;
|
|
|
|
uiReturnValue = MsiSetProperty(
|
|
m_hMSIHandle,
|
|
strPropertyName.c_str(),
|
|
strPropertyValue.c_str()
|
|
);
|
|
switch(uiReturnValue)
|
|
{
|
|
case ERROR_FUNCTION_FAILED:
|
|
case ERROR_INVALID_HANDLE:
|
|
case ERROR_INVALID_PARAMETER:
|
|
strMessage = _T("Failed to set '") + strPropertyName;
|
|
strMessage += _T("' to a value of '");
|
|
if (bDisplayValue)
|
|
strMessage += strPropertyValue;
|
|
else
|
|
strMessage += _T("<Value Hidden>");
|
|
strMessage += _T("'");
|
|
|
|
LogMessage(
|
|
INSTALLMESSAGE_INFO,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
strMessage.c_str()
|
|
);
|
|
return ERROR_INSTALL_FAILURE;
|
|
break;
|
|
}
|
|
|
|
strMessage = _T("Successfully set '") + strPropertyName;
|
|
strMessage += _T("' to a value of '");
|
|
if (bDisplayValue)
|
|
strMessage += strPropertyValue;
|
|
else
|
|
strMessage += _T("<Value Hidden>");
|
|
strMessage += _T("'");
|
|
|
|
LogMessage(
|
|
INSTALLMESSAGE_INFO,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
strMessage.c_str()
|
|
);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: GetComponentKeyFilename
|
|
//
|
|
// Description:
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
UINT BOINCCABase::GetComponentKeyFilename(
|
|
const tstring strComponentName,
|
|
tstring& strComponentKeyFilename
|
|
)
|
|
{
|
|
UINT uiReturnValue = 0;
|
|
tstring strMessage;
|
|
tstring strQuery;
|
|
TCHAR szBuffer[256];
|
|
DWORD dwBufferSize = sizeof(szBuffer);
|
|
MSIHANDLE hDatabase;
|
|
MSIHANDLE hView;
|
|
MSIHANDLE hRecComponentName;
|
|
MSIHANDLE hRec;
|
|
|
|
|
|
// Get the handle to the MSI package we are executing for.
|
|
hDatabase = MsiGetActiveDatabase(m_hMSIHandle);
|
|
if (!hDatabase) return ERROR_INSTALL_FAILURE;
|
|
|
|
// Construct the query that is going to give us the result we need.
|
|
strQuery = _T("SELECT `KeyPath` FROM `Component` WHERE `Component`= ?");
|
|
|
|
// Create the view
|
|
uiReturnValue = MsiDatabaseOpenView(hDatabase, strQuery.c_str(), &hView);
|
|
switch(uiReturnValue)
|
|
{
|
|
case ERROR_BAD_QUERY_SYNTAX:
|
|
MsiCloseHandle(hDatabase);
|
|
|
|
LogMessage(
|
|
INSTALLMESSAGE_INFO,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
_T("MsiDatabaseOpenView reports an invalid query was issued")
|
|
);
|
|
|
|
return ERROR_INSTALL_FAILURE;
|
|
break;
|
|
case ERROR_INVALID_HANDLE:
|
|
MsiCloseHandle(hDatabase);
|
|
|
|
LogMessage(
|
|
INSTALLMESSAGE_INFO,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
_T("MsiDatabaseOpenView reports an invalid handle was used")
|
|
);
|
|
|
|
return ERROR_INSTALL_FAILURE;
|
|
break;
|
|
}
|
|
|
|
// Create query parameter
|
|
hRecComponentName = MsiCreateRecord(1);
|
|
uiReturnValue = MsiRecordSetString(hRecComponentName, 1, strComponentName.c_str());
|
|
switch(uiReturnValue)
|
|
{
|
|
case ERROR_INVALID_HANDLE:
|
|
MsiCloseHandle(hRecComponentName);
|
|
MsiCloseHandle(hDatabase);
|
|
|
|
LogMessage(
|
|
INSTALLMESSAGE_INFO,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
_T("MsiRecordSetString reports an invalid handle was used")
|
|
);
|
|
|
|
return ERROR_INSTALL_FAILURE;
|
|
break;
|
|
case ERROR_INVALID_PARAMETER:
|
|
MsiCloseHandle(hRecComponentName);
|
|
MsiCloseHandle(hDatabase);
|
|
|
|
LogMessage(
|
|
INSTALLMESSAGE_INFO,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
_T("MsiRecordSetString reports an invalid parameter was used")
|
|
);
|
|
|
|
return ERROR_INSTALL_FAILURE;
|
|
break;
|
|
}
|
|
|
|
|
|
// Execute the query
|
|
uiReturnValue = MsiViewExecute(hView, hRecComponentName);
|
|
switch(uiReturnValue)
|
|
{
|
|
case ERROR_FUNCTION_FAILED:
|
|
MsiViewClose(hView);
|
|
MsiCloseHandle(hDatabase);
|
|
|
|
LogMessage(
|
|
INSTALLMESSAGE_INFO,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
_T("MsiViewExecute failed to execute the view")
|
|
);
|
|
|
|
return ERROR_INSTALL_FAILURE;
|
|
break;
|
|
case ERROR_INVALID_HANDLE:
|
|
MsiViewClose(hView);
|
|
MsiCloseHandle(hDatabase);
|
|
|
|
LogMessage(
|
|
INSTALLMESSAGE_INFO,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
_T("MsiViewExecute reports an invalid handle was used")
|
|
);
|
|
|
|
return ERROR_INSTALL_FAILURE;
|
|
break;
|
|
}
|
|
|
|
// Only one row should be returned by the resultset, so there is no need
|
|
// to execute MsiViewFetch more than once.
|
|
uiReturnValue = MsiViewFetch(hView, &hRec);
|
|
switch(uiReturnValue)
|
|
{
|
|
case ERROR_FUNCTION_FAILED:
|
|
MsiViewClose(hView);
|
|
MsiCloseHandle(hDatabase);
|
|
|
|
LogMessage(
|
|
INSTALLMESSAGE_INFO,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
_T("MsiViewFetch: An error occurred during fetching")
|
|
);
|
|
|
|
return ERROR_INSTALL_FAILURE;
|
|
break;
|
|
case ERROR_INVALID_HANDLE:
|
|
MsiViewClose(hView);
|
|
MsiCloseHandle(hDatabase);
|
|
|
|
LogMessage(
|
|
INSTALLMESSAGE_INFO,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
_T("MsiViewFetch reports an invalid handle was used")
|
|
);
|
|
|
|
return ERROR_INSTALL_FAILURE;
|
|
break;
|
|
case ERROR_INVALID_HANDLE_STATE:
|
|
MsiViewClose(hView);
|
|
MsiCloseHandle(hDatabase);
|
|
|
|
LogMessage(
|
|
INSTALLMESSAGE_INFO,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
_T("MsiViewFetch reports the handle was in an invalid state")
|
|
);
|
|
|
|
return ERROR_INSTALL_FAILURE;
|
|
break;
|
|
}
|
|
|
|
// Okay, now it is time to parse the string that was returned.
|
|
uiReturnValue = MsiRecordGetString(hRec, 1, (LPTSTR)&szBuffer, &dwBufferSize);
|
|
switch(uiReturnValue)
|
|
{
|
|
case ERROR_INVALID_HANDLE:
|
|
MsiCloseHandle(hRec);
|
|
MsiViewClose(hView);
|
|
MsiCloseHandle(hDatabase);
|
|
|
|
LogMessage(
|
|
INSTALLMESSAGE_INFO,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
_T("MsiRecordGetString reports an invalid handle was used")
|
|
);
|
|
|
|
return ERROR_INSTALL_FAILURE;
|
|
break;
|
|
case ERROR_INVALID_PARAMETER:
|
|
MsiCloseHandle(hRec);
|
|
MsiViewClose(hView);
|
|
MsiCloseHandle(hDatabase);
|
|
|
|
LogMessage(
|
|
INSTALLMESSAGE_INFO,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
_T("MsiRecordGetString reports an invalid parameter was used")
|
|
);
|
|
|
|
return ERROR_INSTALL_FAILURE;
|
|
break;
|
|
}
|
|
|
|
// Save the string
|
|
strComponentKeyFilename = szBuffer;
|
|
|
|
strMessage = _T("The key filename for component '");
|
|
strMessage += strComponentName;
|
|
strMessage += _T("' is '");
|
|
strMessage += strComponentKeyFilename;
|
|
strMessage += _T("'");
|
|
|
|
LogMessage(
|
|
INSTALLMESSAGE_INFO,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
strMessage.c_str()
|
|
);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: DisplayMessage
|
|
//
|
|
// Description:
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
UINT BOINCCABase::DisplayMessage(
|
|
const UINT uiPushButtonStyle, // push button sstyle to use in message box
|
|
const UINT uiIconStyle, // icon style to use in message box
|
|
const tstring strMessage // message
|
|
)
|
|
{
|
|
UINT uiReturnValue = 0;
|
|
|
|
uiReturnValue = ::MessageBox(
|
|
NULL,
|
|
strMessage.c_str(),
|
|
_T("Installer Message"),
|
|
uiPushButtonStyle | uiIconStyle | MB_SETFOREGROUND | MB_SERVICE_NOTIFICATION
|
|
);
|
|
|
|
return uiReturnValue;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: LogProgress
|
|
//
|
|
// Description:
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
UINT BOINCCABase::LogProgress(
|
|
const tstring strProgress
|
|
)
|
|
{
|
|
UINT uiReturnValue = 0;
|
|
|
|
MsiRecordSetString(m_phActionDataRec, 2, strProgress.c_str());
|
|
|
|
// returns IDOK if successful
|
|
uiReturnValue = MsiProcessMessage( m_hMSIHandle, INSTALLMESSAGE_ACTIONDATA, m_phActionDataRec );
|
|
if ((uiReturnValue == IDCANCEL))
|
|
return ERROR_INSTALL_USEREXIT;
|
|
|
|
// Give the UI a chance to refresh.
|
|
Sleep(0);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: LogMessage
|
|
//
|
|
// Description: This function writes to the MSI log file and displays
|
|
// the SetupError dialog box as appropriate.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
UINT BOINCCABase::LogMessage(
|
|
const UINT uiInstallMessageType, // message type to send to Windows Installer
|
|
const UINT uiPushButtonStyle, // push button sstyle to use in message box
|
|
const UINT uiIconStyle, // icon style to use in message box
|
|
const UINT uiErrorNumber, // number of error in Error table
|
|
const UINT uiErrorCode, // the return value from an api
|
|
const tstring strMessage // message
|
|
)
|
|
{
|
|
UINT uiReturnValue = 0;
|
|
|
|
switch(uiInstallMessageType)
|
|
{
|
|
|
|
// Send informational message to the log file
|
|
case INSTALLMESSAGE_INFO:
|
|
|
|
MsiRecordSetString (m_phLogInfoRec, 2, strMessage.c_str());
|
|
MsiRecordSetInteger(m_phLogInfoRec, 3, uiErrorCode);
|
|
|
|
// returns IDOK if successful
|
|
uiReturnValue = MsiProcessMessage(
|
|
m_hMSIHandle,
|
|
INSTALLMESSAGE(uiInstallMessageType),
|
|
m_phLogInfoRec
|
|
);
|
|
break;
|
|
|
|
// Display a dialog and send error message to log file
|
|
case INSTALLMESSAGE_ERROR:
|
|
case INSTALLMESSAGE_WARNING:
|
|
case INSTALLMESSAGE_USER:
|
|
|
|
PMSIHANDLE phLogErrorRec = MsiCreateRecord(2);
|
|
|
|
MsiRecordSetString (phLogErrorRec, 0, _T("[1]"));
|
|
MsiRecordSetString (phLogErrorRec, 1, strMessage.c_str());
|
|
|
|
// Return value to indicate which button is
|
|
// pushed on message box
|
|
uiReturnValue = MsiProcessMessage(
|
|
m_hMSIHandle,
|
|
INSTALLMESSAGE(uiInstallMessageType|uiPushButtonStyle|uiIconStyle),
|
|
phLogErrorRec
|
|
);
|
|
break;
|
|
|
|
}
|
|
return uiReturnValue;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: RebootWhenFinished
|
|
//
|
|
// Description: Reboot computer when setup completes installation.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
UINT BOINCCABase::RebootWhenFinished()
|
|
{
|
|
SetProperty(_T("RETURN_REBOOTREQUESTED"), _T("1"));
|
|
return MsiSetMode(m_hMSIHandle, MSIRUNMODE_REBOOTATEND, TRUE);
|
|
}
|
|
|