MSICALib/MSITSCA.h

538 lines
16 KiB
C

#ifndef __MSITSCA_H__
#define __MSITSCA_H__
////////////////////////////////////////////////////////////////////////////
// Constants
////////////////////////////////////////////////////////////////////////////
#define MSITSCA_VERSION 0x01000000
#define MSITSCA_VERSION_MAJ 1
#define MSITSCA_VERSION_MIN 0
#define MSITSCA_VERSION_REV 0
#define MSITSCA_VERSION_STR "1.0"
#define MSITSCA_VERSION_INST "1.0.0.0"
////////////////////////////////////////////////////////////////////
// Resource IDs
////////////////////////////////////////////////////////////////////
#define IDR_MAINFRAME 1
#if !defined(RC_INVOKED) && !defined(MIDL_PASS)
#include <msi.h>
////////////////////////////////////////////////////////////////////
// Calling declaration
////////////////////////////////////////////////////////////////////
#if defined(MSITSCA_DLL)
#define MSITSCA_API __declspec(dllexport)
#elif defined(MSITSCA_DLLIMP)
#define MSITSCA_API __declspec(dllimport)
#else
#define MSITSCA_API
#endif
////////////////////////////////////////////////////////////////////
// Exported functions
////////////////////////////////////////////////////////////////////
#ifdef __cplusplus
extern "C" {
#endif
UINT MSITSCA_API EvaluateScheduledTasks(MSIHANDLE hInstall);
UINT MSITSCA_API InstallScheduledTasks(MSIHANDLE hInstall);
UINT MSITSCA_API FinalizeScheduledTasks(MSIHANDLE hInstall);
#ifdef __cplusplus
}
#endif
////////////////////////////////////////////////////////////////////
// Local includes
////////////////////////////////////////////////////////////////////
#include <atlfile.h>
#include <atlstr.h>
#include <assert.h>
#include <msiquery.h>
#include <mstask.h>
////////////////////////////////////////////////////////////////////
// Inline Functions
////////////////////////////////////////////////////////////////////
inline UINT MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, CStringA &sValue)
{
DWORD dwSize = 0;
UINT uiResult;
// Query the actual string length first.
uiResult = ::MsiGetPropertyA(hInstall, szName, "", &dwSize);
if (uiResult == ERROR_MORE_DATA) {
// Prepare the buffer to read the string data into and read it.
LPSTR szBuffer = sValue.GetBuffer(dwSize++);
if (!szBuffer) return ERROR_OUTOFMEMORY;
uiResult = ::MsiGetPropertyA(hInstall, szName, szBuffer, &dwSize);
sValue.ReleaseBuffer(uiResult == ERROR_SUCCESS ? dwSize : 0);
return uiResult;
} else if (uiResult == ERROR_SUCCESS) {
// The string in database is empty.
sValue.Empty();
return ERROR_SUCCESS;
} else {
// Return error code.
return uiResult;
}
}
inline UINT MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName, CStringW &sValue)
{
DWORD dwSize = 0;
UINT uiResult;
// Query the actual string length first.
uiResult = ::MsiGetPropertyW(hInstall, szName, L"", &dwSize);
if (uiResult == ERROR_MORE_DATA) {
// Prepare the buffer to read the string data into and read it.
LPWSTR szBuffer = sValue.GetBuffer(dwSize++);
if (!szBuffer) return ERROR_OUTOFMEMORY;
uiResult = ::MsiGetPropertyW(hInstall, szName, szBuffer, &dwSize);
sValue.ReleaseBuffer(uiResult == ERROR_SUCCESS ? dwSize : 0);
return uiResult;
} else if (uiResult == ERROR_SUCCESS) {
// The string in database is empty.
sValue.Empty();
return ERROR_SUCCESS;
} else {
// Return error code.
return uiResult;
}
}
inline UINT MsiRecordGetStringA(MSIHANDLE hRecord, unsigned int iField, CStringA &sValue)
{
DWORD dwSize = 0;
UINT uiResult;
// Query the actual string length first.
uiResult = ::MsiRecordGetStringA(hRecord, iField, "", &dwSize);
if (uiResult == ERROR_MORE_DATA) {
// Prepare the buffer to read the string data into and read it.
LPSTR szBuffer = sValue.GetBuffer(dwSize++);
if (!szBuffer) return ERROR_OUTOFMEMORY;
uiResult = ::MsiRecordGetStringA(hRecord, iField, szBuffer, &dwSize);
sValue.ReleaseBuffer(uiResult == ERROR_SUCCESS ? dwSize : 0);
return uiResult;
} else if (uiResult == ERROR_SUCCESS) {
// The string in database is empty.
sValue.Empty();
return ERROR_SUCCESS;
} else {
// Return error code.
return uiResult;
}
}
inline UINT MsiRecordGetStringW(MSIHANDLE hRecord, unsigned int iField, CStringW &sValue)
{
DWORD dwSize = 0;
UINT uiResult;
// Query the actual string length first.
uiResult = ::MsiRecordGetStringW(hRecord, iField, L"", &dwSize);
if (uiResult == ERROR_MORE_DATA) {
// Prepare the buffer to read the string data into and read it.
LPWSTR szBuffer = sValue.GetBuffer(dwSize++);
if (!szBuffer) return ERROR_OUTOFMEMORY;
uiResult = ::MsiRecordGetStringW(hRecord, iField, szBuffer, &dwSize);
sValue.ReleaseBuffer(uiResult == ERROR_SUCCESS ? dwSize : 0);
return uiResult;
} else if (uiResult == ERROR_SUCCESS) {
// The string in database is empty.
sValue.Empty();
return ERROR_SUCCESS;
} else {
// Return error code.
return uiResult;
}
}
inline UINT MsiFormatRecordA(MSIHANDLE hInstall, MSIHANDLE hRecord, CStringA &sValue)
{
DWORD dwSize = 0;
UINT uiResult;
// Query the final string length first.
uiResult = ::MsiFormatRecordA(hInstall, hRecord, "", &dwSize);
if (uiResult == ERROR_MORE_DATA) {
// Prepare the buffer to format the string data into and read it.
LPSTR szBuffer = sValue.GetBuffer(dwSize++);
if (!szBuffer) return ERROR_OUTOFMEMORY;
uiResult = ::MsiFormatRecordA(hInstall, hRecord, szBuffer, &dwSize);
sValue.ReleaseBuffer(uiResult == ERROR_SUCCESS ? dwSize : 0);
return uiResult;
} else if (uiResult == ERROR_SUCCESS) {
// The result is empty.
sValue.Empty();
return ERROR_SUCCESS;
} else {
// Return error code.
return uiResult;
}
}
inline UINT MsiFormatRecordW(MSIHANDLE hInstall, MSIHANDLE hRecord, CStringW &sValue)
{
DWORD dwSize = 0;
UINT uiResult;
// Query the final string length first.
uiResult = ::MsiFormatRecordW(hInstall, hRecord, L"", &dwSize);
if (uiResult == ERROR_MORE_DATA) {
// Prepare the buffer to format the string data into and read it.
LPWSTR szBuffer = sValue.GetBuffer(dwSize++);
if (!szBuffer) return ERROR_OUTOFMEMORY;
uiResult = ::MsiFormatRecordW(hInstall, hRecord, szBuffer, &dwSize);
sValue.ReleaseBuffer(uiResult == ERROR_SUCCESS ? dwSize : 0);
return uiResult;
} else if (uiResult == ERROR_SUCCESS) {
// The result is empty.
sValue.Empty();
return ERROR_SUCCESS;
} else {
// Return error code.
return uiResult;
}
}
inline UINT MsiRecordFormatStringA(MSIHANDLE hInstall, MSIHANDLE hRecord, unsigned int iField, CStringA &sValue)
{
UINT uiResult;
PMSIHANDLE hRecordEx;
// Read string to format.
uiResult = ::MsiRecordGetStringA(hRecord, iField, sValue);
if (uiResult != ERROR_SUCCESS) return uiResult;
// If the string is empty, there's nothing left to do.
if (sValue.IsEmpty()) return ERROR_SUCCESS;
// Create a record.
hRecordEx = ::MsiCreateRecord(1);
if (!hRecordEx) return ERROR_INVALID_HANDLE;
// Populate record with data.
uiResult = ::MsiRecordSetStringA(hRecordEx, 0, sValue);
if (uiResult != ERROR_SUCCESS) return uiResult;
// Do the formatting.
return ::MsiFormatRecordA(hInstall, hRecordEx, sValue);
}
inline UINT MsiRecordFormatStringW(MSIHANDLE hInstall, MSIHANDLE hRecord, unsigned int iField, CStringW &sValue)
{
UINT uiResult;
PMSIHANDLE hRecordEx;
// Read string to format.
uiResult = ::MsiRecordGetStringW(hRecord, iField, sValue);
if (uiResult != ERROR_SUCCESS) return uiResult;
// If the string is empty, there's nothing left to do.
if (sValue.IsEmpty()) return ERROR_SUCCESS;
// Create a record.
hRecordEx = ::MsiCreateRecord(1);
if (!hRecordEx) return ERROR_INVALID_HANDLE;
// Populate record with data.
uiResult = ::MsiRecordSetStringW(hRecordEx, 0, sValue);
if (uiResult != ERROR_SUCCESS) return uiResult;
// Do the formatting.
return ::MsiFormatRecordW(hInstall, hRecordEx, sValue);
}
#ifdef UNICODE
#define MsiRecordFormatString MsiRecordFormatStringW
#else
#define MsiRecordFormatString MsiRecordFormatStringA
#endif // !UNICODE
////////////////////////////////////////////////////////////////////
// Inline operators
////////////////////////////////////////////////////////////////////
inline HRESULT operator <<(CAtlFile &f, int i)
{
return f.Write(&i, sizeof(int));
}
inline HRESULT operator >>(CAtlFile &f, int &i)
{
return f.Read(&i, sizeof(int));
}
inline HRESULT operator <<(CAtlFile &f, const CStringA &str)
{
HRESULT hr;
int iLength = str.GetLength();
// Write string length (in characters) as 32-bit integer.
hr = f.Write(&iLength, sizeof(int));
if (FAILED(hr)) return hr;
// Write string data (without terminator).
return f.Write((LPCSTR)str, sizeof(CHAR) * iLength);
}
inline HRESULT operator >>(CAtlFile &f, CStringA &str)
{
HRESULT hr;
int iLength;
LPSTR buf;
// Read string length (in characters) as 32-bit integer.
hr = f.Read(&iLength, sizeof(int));
if (FAILED(hr)) return hr;
// Allocate the buffer.
buf = str.GetBuffer(iLength);
if (!buf) return E_OUTOFMEMORY;
// Read string data (without terminator).
hr = f.Read(buf, sizeof(CHAR) * iLength);
str.ReleaseBuffer(SUCCEEDED(hr) ? iLength : 0);
return hr;
}
inline HRESULT operator <<(CAtlFile &f, const CStringW &str)
{
HRESULT hr;
int iLength = str.GetLength();
// Write string length (in characters) as 32-bit integer.
hr = f.Write(&iLength, sizeof(int));
if (FAILED(hr)) return hr;
// Write string data (without terminator).
return f.Write((LPCWSTR)str, sizeof(WCHAR) * iLength);
}
inline HRESULT operator >>(CAtlFile &f, CStringW &str)
{
HRESULT hr;
int iLength;
LPWSTR buf;
// Read string length (in characters) as 32-bit integer.
hr = f.Read(&iLength, sizeof(int));
if (FAILED(hr)) return hr;
// Allocate the buffer.
buf = str.GetBuffer(iLength);
if (!buf) return E_OUTOFMEMORY;
// Read string data (without terminator).
hr = f.Read(buf, sizeof(WCHAR) * iLength);
str.ReleaseBuffer(SUCCEEDED(hr) ? iLength : 0);
return hr;
}
inline HRESULT operator >>(CAtlFile &f, ITask *pTask)
{
assert(pTask);
HRESULT hr;
CStringW sValue, sValue2;
int iValue, iValue2;
UINT nTriggers;
hr = f >> sValue;
if (FAILED(hr)) return hr;
hr = pTask->SetApplicationName(sValue);
if (FAILED(hr)) return hr;
hr = f >> sValue;
if (FAILED(hr)) return hr;
hr = pTask->SetParameters(sValue);
if (FAILED(hr)) return hr;
hr = f >> sValue;
if (FAILED(hr)) return hr;
hr = pTask->SetWorkingDirectory(sValue);
if (FAILED(hr)) return hr;
hr = f >> iValue;
if (FAILED(hr)) return hr;
hr = pTask->SetFlags(iValue);
if (FAILED(hr)) return hr;
hr = f >> iValue;
if (FAILED(hr)) return hr;
hr = pTask->SetPriority(iValue);
if (FAILED(hr)) return hr;
hr = f >> sValue;
if (FAILED(hr)) return hr;
hr = f >> sValue2;
if (FAILED(hr)) return hr;
hr = !sValue.IsEmpty() ? pTask->SetAccountInformation(sValue, sValue2.IsEmpty() ? NULL : sValue2) : S_OK;
{
// Clear the password in memory before proceeding.
int iLength = sValue2.GetLength();
LPWSTR pszValue2 = sValue2.GetBuffer(iLength);
::SecureZeroMemory(pszValue2, sizeof(WCHAR) * iLength);
sValue2.ReleaseBuffer(0);
}
if (FAILED(hr)) return hr;
hr = f >> sValue;
if (FAILED(hr)) return hr;
hr = pTask->SetComment(sValue);
if (FAILED(hr)) return hr;
hr = f >> iValue;
if (FAILED(hr)) return hr;
hr = f >> iValue2;
if (FAILED(hr)) return hr;
hr = pTask->SetIdleWait((WORD)iValue, (WORD)iValue2);
if (FAILED(hr)) return hr;
hr = f >> iValue;
if (FAILED(hr)) return hr;
hr = pTask->SetMaxRunTime(iValue);
if (FAILED(hr)) return hr;
// Read and add triggers.
hr = f >> (int&)nTriggers;
if (FAILED(hr)) return hr;
while (nTriggers--) {
CComPtr<ITaskTrigger> pTrigger;
TASK_TRIGGER ttData;
WORD wTriggerIdx;
ULONGLONG ullValue;
FILETIME ftValue;
SYSTEMTIME stValue;
int iDaysInterval, iWeeksInterval, iDaysOfTheWeek, iDaysOfMonth, iWeekOfMonth, iMonthsOfYear;
ZeroMemory(&ttData, sizeof(TASK_TRIGGER));
ttData.cbTriggerSize = sizeof(TASK_TRIGGER);
hr = pTask->CreateTrigger(&wTriggerIdx, &pTrigger);
if (FAILED(hr)) return hr;
hr = f >> iValue;
if (FAILED(hr)) return hr;
ullValue = ((ULONGLONG)iValue + 138426) * 864000000000;
ftValue.dwHighDateTime = ullValue >> 32;
ftValue.dwLowDateTime = ullValue & 0xffffffff;
if (!::FileTimeToSystemTime(&ftValue, &stValue))
return AtlHresultFromLastError();
ttData.wBeginYear = stValue.wYear;
ttData.wBeginMonth = stValue.wMonth;
ttData.wBeginDay = stValue.wDay;
hr = f >> iValue;
if (FAILED(hr)) return hr;
if (iValue != MSI_NULL_INTEGER) {
ullValue = ((ULONGLONG)iValue + 138426) * 864000000000;
ftValue.dwHighDateTime = ullValue >> 32;
ftValue.dwLowDateTime = ullValue & 0xffffffff;
if (!::FileTimeToSystemTime(&ftValue, &stValue))
return AtlHresultFromLastError();
ttData.wEndYear = stValue.wYear;
ttData.wEndMonth = stValue.wMonth;
ttData.wEndDay = stValue.wDay;
ttData.rgFlags |= TASK_TRIGGER_FLAG_HAS_END_DATE;
}
hr = f >> iValue;
if (FAILED(hr)) return hr;
ttData.wStartHour = (WORD)(iValue / 60);
ttData.wStartMinute = (WORD)(iValue % 60);
hr = f >> iValue;
if (FAILED(hr)) return hr;
ttData.MinutesDuration = iValue;
hr = f >> iValue;
if (FAILED(hr)) return hr;
ttData.MinutesInterval = iValue;
hr = f >> iValue;
if (FAILED(hr)) return hr;
ttData.rgFlags |= iValue & ~TASK_TRIGGER_FLAG_HAS_END_DATE;
hr = f >> iValue;
if (FAILED(hr)) return hr;
ttData.TriggerType = (TASK_TRIGGER_TYPE)iValue;
hr = f >> iDaysInterval;
if (FAILED(hr)) return hr;
hr = f >> iWeeksInterval;
if (FAILED(hr)) return hr;
hr = f >> iDaysOfTheWeek;
if (FAILED(hr)) return hr;
hr = f >> iDaysOfMonth;
if (FAILED(hr)) return hr;
hr = f >> iWeekOfMonth;
if (FAILED(hr)) return hr;
hr = f >> iMonthsOfYear;
if (FAILED(hr)) return hr;
switch (ttData.TriggerType) {
case TASK_TIME_TRIGGER_DAILY:
ttData.Type.Daily.DaysInterval = (WORD)iDaysInterval;
break;
case TASK_TIME_TRIGGER_WEEKLY:
ttData.Type.Weekly.WeeksInterval = (WORD)iWeeksInterval;
ttData.Type.Weekly.rgfDaysOfTheWeek = (WORD)iDaysOfTheWeek;
break;
case TASK_TIME_TRIGGER_MONTHLYDATE:
ttData.Type.MonthlyDate.rgfDays = iDaysOfMonth;
ttData.Type.MonthlyDate.rgfMonths = (WORD)iMonthsOfYear;
break;
case TASK_TIME_TRIGGER_MONTHLYDOW:
ttData.Type.MonthlyDOW.wWhichWeek = (WORD)iWeekOfMonth;
ttData.Type.MonthlyDOW.rgfDaysOfTheWeek = (WORD)iDaysOfTheWeek;
ttData.Type.MonthlyDOW.rgfMonths = (WORD)iMonthsOfYear;
break;
}
hr = pTrigger->SetTrigger(&ttData);
if (FAILED(hr)) return hr;
}
return S_OK;
}
#endif // !defined(RC_INVOKED) && !defined(MIDL_PASS)
#endif // __MSITSCA_H__