diff --git a/.gitattributes b/.gitattributes index 2801940..5d0fed6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,8 +3,6 @@ MSICALib/MSITSCA.cpp -text MSICALib/MSITSCA.h -text MSICALib/MSITSCA.vcxproj -text svneol=unset#text/xml MSICALib/MSITSCA.vcxproj.filters -text svneol=unset#text/xml -MSICALib/MSITSCAOp.cpp -text -MSICALib/MSITSCAOp.h -text MSICALib/StdAfx.cpp -text MSICALib/StdAfx.h -text MSICALib/msm/Makefile -text svneol=unset#text/plain%3B+charset%3DWindows-1250 diff --git a/MSICALib/MSITSCA.cpp b/MSICALib/MSITSCA.cpp index bafb10c..f786d83 100644 --- a/MSICALib/MSITSCA.cpp +++ b/MSICALib/MSITSCA.cpp @@ -46,12 +46,12 @@ UINT MSITSCA_API EvaluateScheduledTasks(MSIHANDLE hInstall) UINT uiResult; HRESULT hr; BOOL bIsCoInitialized = SUCCEEDED(::CoInitialize(NULL)); - CMSITSCAOpList olExecute; + AMSICA::COpList olExecute; BOOL bRollbackEnabled; PMSIHANDLE hDatabase, hRecordProg = ::MsiCreateRecord(3); - CString sValue; + ATL::CAtlString sValue; assert(hRecordProg); @@ -60,7 +60,7 @@ UINT MSITSCA_API EvaluateScheduledTasks(MSIHANDLE hInstall) bRollbackEnabled = uiResult == ERROR_SUCCESS ? _ttoi(sValue) || !sValue.IsEmpty() && _totlower(sValue.GetAt(0)) == _T('y') ? FALSE : TRUE : TRUE; - olExecute.AddTail(new CMSITSCAOpRollbackEnable(bRollbackEnabled)); + olExecute.AddTail(new AMSICA::COpRollbackEnable(bRollbackEnabled)); // Open MSI database. hDatabase = ::MsiGetActiveDatabase(hInstall); @@ -76,8 +76,8 @@ UINT MSITSCA_API EvaluateScheduledTasks(MSIHANDLE hInstall) // Execute query! uiResult = ::MsiViewExecute(hViewST, NULL); if (uiResult == ERROR_SUCCESS) { - //CString sComponent; - CStringW sDisplayName; + //ATL::CAtlString sComponent; + ATL::CAtlStringW sDisplayName; for (;;) { PMSIHANDLE hRecord; @@ -116,7 +116,7 @@ UINT MSITSCA_API EvaluateScheduledTasks(MSIHANDLE hInstall) if (iAction >= INSTALLSTATE_LOCAL) { // Component is or should be installed. Create the task. PMSIHANDLE hViewTT; - CMSITSCAOpTaskCreate *opCreateTask = new CMSITSCAOpTaskCreate(sDisplayName, MSITSCA_TASK_TICK_SIZE); + AMSICA::COpTaskCreate *opCreateTask = new AMSICA::COpTaskCreate(sDisplayName, MSITSCA_TASK_TICK_SIZE); assert(opCreateTask); // Populate the operation with task's data. @@ -140,7 +140,7 @@ UINT MSITSCA_API EvaluateScheduledTasks(MSIHANDLE hInstall) olExecute.AddTail(opCreateTask); } else if (iAction >= INSTALLSTATE_REMOVED) { // Component is installed, but should be degraded to advertised/removed. Delete the task. - olExecute.AddTail(new CMSITSCAOpTaskDelete(sDisplayName, MSITSCA_TASK_TICK_SIZE)); + olExecute.AddTail(new AMSICA::COpTaskDelete(sDisplayName, MSITSCA_TASK_TICK_SIZE)); } // The amount of tick space to add for each task to progress indicator. @@ -151,8 +151,8 @@ UINT MSITSCA_API EvaluateScheduledTasks(MSIHANDLE hInstall) verify(::MsiViewClose(hViewST) == ERROR_SUCCESS); if (SUCCEEDED(uiResult)) { - CString sSequenceFilename; - CAtlFile fSequence; + ATL::CAtlString sSequenceFilename; + ATL::CAtlFile fSequence; // Prepare our own sequence script file. // The InstallScheduledTasks is a deferred custom action, thus all this information will be unavailable to it. @@ -171,7 +171,7 @@ UINT MSITSCA_API EvaluateScheduledTasks(MSIHANDLE hInstall) uiResult = ::MsiSetProperty(hInstall, _T("InstallScheduledTasks"), sSequenceFilename); if (uiResult == ERROR_SUCCESS) { LPCTSTR pszExtension = ::PathFindExtension(sSequenceFilename); - CString sSequenceFilename2; + ATL::CAtlString sSequenceFilename2; sSequenceFilename2.Format(_T("%.*ls-rb%ls"), pszExtension - (LPCTSTR)sSequenceFilename, (LPCTSTR)sSequenceFilename, pszExtension); uiResult = ::MsiSetProperty(hInstall, _T("RollbackScheduledTasks"), sSequenceFilename2); @@ -235,16 +235,16 @@ UINT MSITSCA_API InstallScheduledTasks(MSIHANDLE hInstall) UINT uiResult; HRESULT hr; BOOL bIsCoInitialized = SUCCEEDED(::CoInitialize(NULL)); - CString sSequenceFilename; + ATL::CAtlString sSequenceFilename; uiResult = ::MsiGetProperty(hInstall, _T("CustomActionData"), sSequenceFilename); if (uiResult == ERROR_SUCCESS) { - CMSITSCAOpList lstOperations; + AMSICA::COpList lstOperations; // Load operation sequence. hr = lstOperations.LoadFromFile(sSequenceFilename); if (SUCCEEDED(hr)) { - CMSITSCASession session; + AMSICA::CSession session; BOOL bIsCleanup = ::MsiGetMode(hInstall, MSIRUNMODE_COMMIT) || ::MsiGetMode(hInstall, MSIRUNMODE_ROLLBACK); session.m_hInstall = hInstall; @@ -258,24 +258,24 @@ UINT MSITSCA_API InstallScheduledTasks(MSIHANDLE hInstall) if (!bIsCleanup && session.m_bRollbackEnabled) { // Save cleanup scripts. LPCTSTR pszExtension = ::PathFindExtension(sSequenceFilename); - CString sSequenceFilenameCM, sSequenceFilenameRB; + ATL::CAtlString sSequenceFilenameCM, sSequenceFilenameRB; sSequenceFilenameRB.Format(_T("%.*ls-rb%ls"), pszExtension - (LPCTSTR)sSequenceFilename, (LPCTSTR)sSequenceFilename, pszExtension); sSequenceFilenameCM.Format(_T("%.*ls-cm%ls"), pszExtension - (LPCTSTR)sSequenceFilename, (LPCTSTR)sSequenceFilename, pszExtension); // After end of commit, delete rollback file too. After end of rollback, delete commit file too. - session.m_olCommit.AddTail(new CMSITSCAOpFileDelete( + session.m_olCommit.AddTail(new AMSICA::COpFileDelete( #ifdef _UNICODE sSequenceFilenameRB #else - CStringW(sSequenceFilenameRB) + ATL::CAtlStringW(sSequenceFilenameRB) #endif )); - session.m_olRollback.AddTail(new CMSITSCAOpFileDelete( + session.m_olRollback.AddTail(new AMSICA::COpFileDelete( #ifdef _UNICODE sSequenceFilenameCM #else - CStringW(sSequenceFilenameCM) + ATL::CAtlStringW(sSequenceFilenameCM) #endif )); diff --git a/MSICALib/MSITSCA.h b/MSICALib/MSITSCA.h index 4ad39cd..80e8bfb 100644 --- a/MSICALib/MSITSCA.h +++ b/MSICALib/MSITSCA.h @@ -6,14 +6,14 @@ // Constants //////////////////////////////////////////////////////////////////////////// -#define MSITSCA_VERSION 0x01010000 +#define MSITSCA_VERSION 0x01010100 #define MSITSCA_VERSION_MAJ 1 #define MSITSCA_VERSION_MIN 1 -#define MSITSCA_VERSION_REV 0 +#define MSITSCA_VERSION_REV 1 -#define MSITSCA_VERSION_STR "1.1" -#define MSITSCA_VERSION_INST "1.1.0.0" +#define MSITSCA_VERSION_STR "1.1.1" +#define MSITSCA_VERSION_INST "1.1.1.0" #if !defined(RC_INVOKED) && !defined(MIDL_PASS) @@ -33,23 +33,6 @@ #define MSITSCA_API #endif -//////////////////////////////////////////////////////////////////// -// Error codes (last unused 2561L) -//////////////////////////////////////////////////////////////////// - -#define ERROR_INSTALL_SCHEDULED_TASKS_DATABASE_OPEN 2550L -#define ERROR_INSTALL_SCHEDULED_TASKS_OPLIST_CREATE 2551L -#define ERROR_INSTALL_SCHEDULED_TASKS_SCRIPT_WRITE 2552L -#define ERROR_INSTALL_SCHEDULED_TASKS_SCRIPT_READ 2560L -#define ERROR_INSTALL_SCHEDULED_TASKS_PROPERTY_SET 2553L -#define ERROR_INSTALL_DELETE_FAILED 2554L -#define ERROR_INSTALL_MOVE_FAILED 2555L -#define ERROR_INSTALL_TASK_CREATE_FAILED 2556L -#define ERROR_INSTALL_TASK_DELETE_FAILED 2557L -#define ERROR_INSTALL_TASK_ENABLE_FAILED 2558L -#define ERROR_INSTALL_TASK_COPY_FAILED 2559L - - //////////////////////////////////////////////////////////////////// // Exported functions //////////////////////////////////////////////////////////////////// @@ -65,375 +48,6 @@ extern "C" { } #endif - -//////////////////////////////////////////////////////////////////// -// Local includes -//////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include - - -//////////////////////////////////////////////////////////////////// -// 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 UINT MsiGetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder, CStringA &sValue) -{ - DWORD dwSize = 0; - UINT uiResult; - - // Query the final string length first. - uiResult = ::MsiGetTargetPathA(hInstall, szFolder, "", &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 = ::MsiGetTargetPathA(hInstall, szFolder, 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 MsiGetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder, CStringW &sValue) -{ - DWORD dwSize = 0; - UINT uiResult; - - // Query the final string length first. - uiResult = ::MsiGetTargetPathW(hInstall, szFolder, 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 = ::MsiGetTargetPathW(hInstall, szFolder, 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 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, const TASK_TRIGGER &ttData) -{ - return f.Write(&ttData, sizeof(TASK_TRIGGER)); -} - - -inline HRESULT operator >>(CAtlFile &f, TASK_TRIGGER &ttData) -{ - return f.Read(&ttData, sizeof(TASK_TRIGGER)); -} - #endif // !defined(RC_INVOKED) && !defined(MIDL_PASS) #endif // __MSITSCA_H__ diff --git a/MSICALib/MSITSCA.vcxproj b/MSICALib/MSITSCA.vcxproj index 90a8404..4f62751 100644 --- a/MSICALib/MSITSCA.vcxproj +++ b/MSICALib/MSITSCA.vcxproj @@ -162,6 +162,9 @@ res\en_GB.po + + ..\AMSICA\include;%(AdditionalIncludeDirectories) + @@ -174,6 +177,9 @@ res\en_GB.po + + ..\AMSICA\include;%(AdditionalIncludeDirectories) + @@ -186,6 +192,9 @@ res\en_GB.po + + ..\AMSICA\include;%(AdditionalIncludeDirectories) + @@ -198,6 +207,9 @@ res\en_GB.po + + ..\AMSICA\include;%(AdditionalIncludeDirectories) + @@ -210,6 +222,9 @@ res\en_GB.po + + ..\AMSICA\include;%(AdditionalIncludeDirectories) + @@ -222,6 +237,9 @@ res\en_GB.po + + ..\AMSICA\include;%(AdditionalIncludeDirectories) + @@ -234,6 +252,9 @@ res\en_GB.po + + ..\AMSICA\include;%(AdditionalIncludeDirectories) + @@ -246,10 +267,12 @@ res\en_GB.po + + ..\AMSICA\include;%(AdditionalIncludeDirectories) + - Create Create @@ -263,7 +286,6 @@ - @@ -275,6 +297,16 @@ + + + {8552ee55-177e-4f51-b51b-baf7d6462cde} + true + true + true + true + false + + diff --git a/MSICALib/MSITSCA.vcxproj.filters b/MSICALib/MSITSCA.vcxproj.filters index a03fa1e..e33848e 100644 --- a/MSICALib/MSITSCA.vcxproj.filters +++ b/MSICALib/MSITSCA.vcxproj.filters @@ -21,9 +21,6 @@ Source Files - - Source Files - @@ -32,9 +29,6 @@ Header Files - - Header Files - diff --git a/MSICALib/MSITSCAOp.cpp b/MSICALib/MSITSCAOp.cpp deleted file mode 100644 index cddc7b9..0000000 --- a/MSICALib/MSITSCAOp.cpp +++ /dev/null @@ -1,1297 +0,0 @@ -#include "StdAfx.h" - -#pragma comment(lib, "taskschd.lib") - - -//////////////////////////////////////////////////////////////////////////// -// CMSITSCAOp -//////////////////////////////////////////////////////////////////////////// - -CMSITSCAOp::CMSITSCAOp(int iTicks) : - m_iTicks(iTicks) -{ -} - - -//////////////////////////////////////////////////////////////////////////// -// CMSITSCAOpTypeSingleString -//////////////////////////////////////////////////////////////////////////// - -CMSITSCAOpTypeSingleString::CMSITSCAOpTypeSingleString(LPCWSTR pszValue, int iTicks) : - m_sValue(pszValue), - CMSITSCAOp(iTicks) -{ -} - - -//////////////////////////////////////////////////////////////////////////// -// CMSITSCAOpDoubleStringOperation -//////////////////////////////////////////////////////////////////////////// - -CMSITSCAOpTypeSrcDstString::CMSITSCAOpTypeSrcDstString(LPCWSTR pszValue1, LPCWSTR pszValue2, int iTicks) : - m_sValue1(pszValue1), - m_sValue2(pszValue2), - CMSITSCAOp(iTicks) -{ -} - - -//////////////////////////////////////////////////////////////////////////// -// CMSITSCAOpTypeBoolean -//////////////////////////////////////////////////////////////////////////// - -CMSITSCAOpTypeBoolean::CMSITSCAOpTypeBoolean(BOOL bValue, int iTicks) : - m_bValue(bValue), - CMSITSCAOp(iTicks) -{ -} - - -//////////////////////////////////////////////////////////////////////////// -// CMSITSCAOpRollbackEnable -//////////////////////////////////////////////////////////////////////////// - -CMSITSCAOpRollbackEnable::CMSITSCAOpRollbackEnable(BOOL bEnable, int iTicks) : - CMSITSCAOpTypeBoolean(bEnable, iTicks) -{ -} - - -HRESULT CMSITSCAOpRollbackEnable::Execute(CMSITSCASession *pSession) -{ - assert(pSession); - - pSession->m_bRollbackEnabled = m_bValue; - return S_OK; -} - - -//////////////////////////////////////////////////////////////////////////// -// CMSITSCAOpFileDelete -//////////////////////////////////////////////////////////////////////////// - -CMSITSCAOpFileDelete::CMSITSCAOpFileDelete(LPCWSTR pszFileName, int iTicks) : - CMSITSCAOpTypeSingleString(pszFileName, iTicks) -{ -} - - -HRESULT CMSITSCAOpFileDelete::Execute(CMSITSCASession *pSession) -{ - assert(pSession); - DWORD dwError; - - if (pSession->m_bRollbackEnabled) { - CStringW sBackupName; - UINT uiCount = 0; - - do { - // Rename the file to make a backup. - sBackupName.Format(L"%ls (orig %u)", (LPCWSTR)m_sValue, ++uiCount); - dwError = ::MoveFileW(m_sValue, sBackupName) ? ERROR_SUCCESS : ::GetLastError(); - } while (dwError == ERROR_ALREADY_EXISTS); - if (dwError == ERROR_SUCCESS) { - // Order rollback action to restore from backup copy. - pSession->m_olRollback.AddHead(new CMSITSCAOpFileMove(sBackupName, m_sValue)); - - // Order commit action to delete backup copy. - pSession->m_olCommit.AddTail(new CMSITSCAOpFileDelete(sBackupName)); - } - } else { - // Delete the file. - dwError = ::DeleteFileW(m_sValue) ? ERROR_SUCCESS : ::GetLastError(); - } - - if (dwError == ERROR_SUCCESS || dwError == ERROR_FILE_NOT_FOUND) - return S_OK; - else { - PMSIHANDLE hRecordProg = ::MsiCreateRecord(3); - verify(::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_DELETE_FAILED) == ERROR_SUCCESS); - verify(::MsiRecordSetStringW(hRecordProg, 2, m_sValue ) == ERROR_SUCCESS); - verify(::MsiRecordSetInteger(hRecordProg, 3, dwError ) == ERROR_SUCCESS); - ::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg); - return AtlHresultFromWin32(dwError); - } -} - - -//////////////////////////////////////////////////////////////////////////// -// CMSITSCAOpFileMove -//////////////////////////////////////////////////////////////////////////// - -CMSITSCAOpFileMove::CMSITSCAOpFileMove(LPCWSTR pszFileSrc, LPCWSTR pszFileDst, int iTicks) : - CMSITSCAOpTypeSrcDstString(pszFileSrc, pszFileDst, iTicks) -{ -} - - -HRESULT CMSITSCAOpFileMove::Execute(CMSITSCASession *pSession) -{ - assert(pSession); - DWORD dwError; - - // Move the file. - dwError = ::MoveFileW(m_sValue1, m_sValue2) ? ERROR_SUCCESS : ::GetLastError(); - if (dwError == ERROR_SUCCESS) { - if (pSession->m_bRollbackEnabled) { - // Order rollback action to move it back. - pSession->m_olRollback.AddHead(new CMSITSCAOpFileMove(m_sValue2, m_sValue1)); - } - - return S_OK; - } else { - PMSIHANDLE hRecordProg = ::MsiCreateRecord(4); - verify(::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_MOVE_FAILED) == ERROR_SUCCESS); - verify(::MsiRecordSetStringW(hRecordProg, 2, m_sValue1 ) == ERROR_SUCCESS); - verify(::MsiRecordSetStringW(hRecordProg, 3, m_sValue2 ) == ERROR_SUCCESS); - verify(::MsiRecordSetInteger(hRecordProg, 4, dwError ) == ERROR_SUCCESS); - ::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg); - return AtlHresultFromWin32(dwError); - } -} - - -//////////////////////////////////////////////////////////////////////////// -// CMSITSCAOpTaskCreate -//////////////////////////////////////////////////////////////////////////// - -CMSITSCAOpTaskCreate::CMSITSCAOpTaskCreate(LPCWSTR pszTaskName, int iTicks) : - m_dwFlags(0), - m_dwPriority(NORMAL_PRIORITY_CLASS), - m_wIdleMinutes(0), - m_wDeadlineMinutes(0), - m_dwMaxRuntimeMS(INFINITE), - CMSITSCAOpTypeSingleString(pszTaskName, iTicks) -{ -} - - -CMSITSCAOpTaskCreate::~CMSITSCAOpTaskCreate() -{ - // Clear the password in memory. - int iLength = m_sPassword.GetLength(); - ::SecureZeroMemory(m_sPassword.GetBuffer(iLength), sizeof(WCHAR) * iLength); - m_sPassword.ReleaseBuffer(0); -} - - -HRESULT CMSITSCAOpTaskCreate::Execute(CMSITSCASession *pSession) -{ - HRESULT hr; - PMSIHANDLE hRecordMsg = ::MsiCreateRecord(1); - CComPtr pService; - POSITION pos; - - // Display our custom message in the progress bar. - verify(::MsiRecordSetStringW(hRecordMsg, 1, m_sValue) == ERROR_SUCCESS); - if (MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ACTIONDATA, hRecordMsg) == IDCANCEL) - return AtlHresultFromWin32(ERROR_INSTALL_USEREXIT); - - { - // Delete existing task first. - // Since task deleting is a complicated job (when rollback/commit support is required), and we do have an operation just for that, we use it. - // Don't worry, CMSITSCAOpTaskDelete::Execute() returns S_OK if task doesn't exist. - CMSITSCAOpTaskDelete opDeleteTask(m_sValue); - hr = opDeleteTask.Execute(pSession); - if (FAILED(hr)) goto finish; - } - - hr = pService.CoCreateInstance(CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER); - if (SUCCEEDED(hr)) { - // Windows Vista or newer. - CComVariant vEmpty; - CComPtr pTaskDefinition; - CComPtr pTaskSettings; - CComPtr pPrincipal; - CComPtr pActionCollection; - CComPtr pAction; - CComPtr pIdleSettings; - CComPtr pExecAction; - CComPtr pRegististrationInfo; - CComPtr pTriggerCollection; - CComPtr pTaskFolder; - CComPtr pTask; - CStringW str; - UINT iTrigger; - TASK_LOGON_TYPE logonType; - CComBSTR bstrContext(L"Author"); - - // Connect to local task service. - hr = pService->Connect(vEmpty, vEmpty, vEmpty, vEmpty); - if (FAILED(hr)) goto finish; - - // Prepare the definition for a new task. - hr = pService->NewTask(0, &pTaskDefinition); - if (FAILED(hr)) goto finish; - - // Get the task's settings. - hr = pTaskDefinition->get_Settings(&pTaskSettings); - if (FAILED(hr)) goto finish; - - // Enable/disable task. - if (pSession->m_bRollbackEnabled && (m_dwFlags & TASK_FLAG_DISABLED) == 0) { - // The task is supposed to be enabled. - // However, we shall enable it at commit to prevent it from accidentally starting in the very installation phase. - pSession->m_olCommit.AddTail(new CMSITSCAOpTaskEnable(m_sValue, TRUE)); - m_dwFlags |= TASK_FLAG_DISABLED; - } - hr = pTaskSettings->put_Enabled(m_dwFlags & TASK_FLAG_DISABLED ? VARIANT_FALSE : VARIANT_TRUE); if (FAILED(hr)) goto finish; - - // Get task actions. - hr = pTaskDefinition->get_Actions(&pActionCollection); - if (FAILED(hr)) goto finish; - - // Add execute action. - hr = pActionCollection->Create(TASK_ACTION_EXEC, &pAction); - if (FAILED(hr)) goto finish; - hr = pAction.QueryInterface(&pExecAction); - if (FAILED(hr)) goto finish; - - // Configure the action. - hr = pExecAction->put_Path (CComBSTR(m_sApplicationName )); if (FAILED(hr)) goto finish; - hr = pExecAction->put_Arguments (CComBSTR(m_sParameters )); if (FAILED(hr)) goto finish; - hr = pExecAction->put_WorkingDirectory(CComBSTR(m_sWorkingDirectory)); if (FAILED(hr)) goto finish; - - // Set task description. - hr = pTaskDefinition->get_RegistrationInfo(&pRegististrationInfo); - if (FAILED(hr)) goto finish; - hr = pRegististrationInfo->put_Author(CComBSTR(m_sAuthor)); - if (FAILED(hr)) goto finish; - hr = pRegististrationInfo->put_Description(CComBSTR(m_sComment)); - if (FAILED(hr)) goto finish; - - // Configure task "flags". - if (m_dwFlags & TASK_FLAG_DELETE_WHEN_DONE) { - hr = pTaskSettings->put_DeleteExpiredTaskAfter(CComBSTR(L"PT24H")); - if (FAILED(hr)) goto finish; - } - hr = pTaskSettings->put_Hidden(m_dwFlags & TASK_FLAG_HIDDEN ? VARIANT_TRUE : VARIANT_FALSE); - if (FAILED(hr)) goto finish; - hr = pTaskSettings->put_WakeToRun(m_dwFlags & TASK_FLAG_SYSTEM_REQUIRED ? VARIANT_TRUE : VARIANT_FALSE); - if (FAILED(hr)) goto finish; - hr = pTaskSettings->put_DisallowStartIfOnBatteries(m_dwFlags & TASK_FLAG_DONT_START_IF_ON_BATTERIES ? VARIANT_TRUE : VARIANT_FALSE); - if (FAILED(hr)) goto finish; - hr = pTaskSettings->put_StopIfGoingOnBatteries(m_dwFlags & TASK_FLAG_KILL_IF_GOING_ON_BATTERIES ? VARIANT_TRUE : VARIANT_FALSE); - if (FAILED(hr)) goto finish; - - // Configure task priority. - hr = pTaskSettings->put_Priority( - m_dwPriority == REALTIME_PRIORITY_CLASS ? 0 : - m_dwPriority == HIGH_PRIORITY_CLASS ? 1 : - m_dwPriority == ABOVE_NORMAL_PRIORITY_CLASS ? 2 : - m_dwPriority == NORMAL_PRIORITY_CLASS ? 4 : - m_dwPriority == BELOW_NORMAL_PRIORITY_CLASS ? 7 : - m_dwPriority == IDLE_PRIORITY_CLASS ? 9 : 7); - if (FAILED(hr)) goto finish; - - // Get task principal. - hr = pTaskDefinition->get_Principal(&pPrincipal); - if (FAILED(hr)) goto finish; - - if (m_sAccountName.IsEmpty()) { - logonType = TASK_LOGON_SERVICE_ACCOUNT; - hr = pPrincipal->put_LogonType(logonType); if (FAILED(hr)) goto finish; - hr = pPrincipal->put_UserId(CComBSTR(L"S-1-5-18")); if (FAILED(hr)) goto finish; - hr = pPrincipal->put_RunLevel(TASK_RUNLEVEL_HIGHEST); if (FAILED(hr)) goto finish; - } else if (m_dwFlags & TASK_FLAG_RUN_ONLY_IF_LOGGED_ON) { - logonType = TASK_LOGON_INTERACTIVE_TOKEN; - hr = pPrincipal->put_LogonType(logonType); if (FAILED(hr)) goto finish; - hr = pPrincipal->put_RunLevel(TASK_RUNLEVEL_LUA); if (FAILED(hr)) goto finish; - } else { - logonType = TASK_LOGON_PASSWORD; - hr = pPrincipal->put_LogonType(logonType); if (FAILED(hr)) goto finish; - hr = pPrincipal->put_UserId(CComBSTR(m_sAccountName)); if (FAILED(hr)) goto finish; - hr = pPrincipal->put_RunLevel(TASK_RUNLEVEL_HIGHEST); if (FAILED(hr)) goto finish; - } - - // Connect principal and action collection. - hr = pPrincipal->put_Id(bstrContext); - if (FAILED(hr)) goto finish; - hr = pActionCollection->put_Context(bstrContext); - if (FAILED(hr)) goto finish; - - // Configure idle settings. - hr = pTaskSettings->put_RunOnlyIfIdle(m_dwFlags & TASK_FLAG_START_ONLY_IF_IDLE ? VARIANT_TRUE : VARIANT_FALSE); - if (FAILED(hr)) goto finish; - hr = pTaskSettings->get_IdleSettings(&pIdleSettings); - if (FAILED(hr)) goto finish; - str.Format(L"PT%uS", m_wIdleMinutes*60); - hr = pIdleSettings->put_IdleDuration(CComBSTR(str)); - if (FAILED(hr)) goto finish; - str.Format(L"PT%uS", m_wDeadlineMinutes*60); - hr = pIdleSettings->put_WaitTimeout(CComBSTR(str)); - if (FAILED(hr)) goto finish; - hr = pIdleSettings->put_RestartOnIdle(m_dwFlags & TASK_FLAG_RESTART_ON_IDLE_RESUME ? VARIANT_TRUE : VARIANT_FALSE); - if (FAILED(hr)) goto finish; - hr = pIdleSettings->put_StopOnIdleEnd(m_dwFlags & TASK_FLAG_KILL_ON_IDLE_END ? VARIANT_TRUE : VARIANT_FALSE); - if (FAILED(hr)) goto finish; - - // Configure task runtime limit. - str.Format(L"PT%uS", m_dwMaxRuntimeMS != INFINITE ? (m_dwMaxRuntimeMS + 500) / 1000 : 0); - hr = pTaskSettings->put_ExecutionTimeLimit(CComBSTR(str)); - if (FAILED(hr)) goto finish; - - // Get task trigger colection. - hr = pTaskDefinition->get_Triggers(&pTriggerCollection); - if (FAILED(hr)) goto finish; - - // Add triggers. - for (pos = m_lTriggers.GetHeadPosition(), iTrigger = 0; pos; iTrigger++) { - CComPtr pTrigger; - TASK_TRIGGER &ttData = m_lTriggers.GetNext(pos); - - switch (ttData.TriggerType) { - case TASK_TIME_TRIGGER_ONCE: { - CComPtr pTriggerTime; - hr = pTriggerCollection->Create(TASK_TRIGGER_TIME, &pTrigger); if (FAILED(hr)) goto finish; - hr = pTrigger.QueryInterface(&pTriggerTime); if (FAILED(hr)) goto finish; - str.Format(L"PT%uM", ttData.wRandomMinutesInterval); - hr = pTriggerTime->put_RandomDelay(CComBSTR(str)); if (FAILED(hr)) goto finish; - break; - } - - case TASK_TIME_TRIGGER_DAILY: { - CComPtr pTriggerDaily; - hr = pTriggerCollection->Create(TASK_TRIGGER_DAILY, &pTrigger); if (FAILED(hr)) goto finish; - hr = pTrigger.QueryInterface(&pTriggerDaily); if (FAILED(hr)) goto finish; - hr = pTriggerDaily->put_DaysInterval(ttData.Type.Daily.DaysInterval); if (FAILED(hr)) goto finish; - str.Format(L"PT%uM", ttData.wRandomMinutesInterval); - hr = pTriggerDaily->put_RandomDelay(CComBSTR(str)); if (FAILED(hr)) goto finish; - break; - } - - case TASK_TIME_TRIGGER_WEEKLY: { - CComPtr pTriggerWeekly; - hr = pTriggerCollection->Create(TASK_TRIGGER_WEEKLY, &pTrigger); if (FAILED(hr)) goto finish; - hr = pTrigger.QueryInterface(&pTriggerWeekly); if (FAILED(hr)) goto finish; - hr = pTriggerWeekly->put_WeeksInterval(ttData.Type.Weekly.WeeksInterval); if (FAILED(hr)) goto finish; - hr = pTriggerWeekly->put_DaysOfWeek(ttData.Type.Weekly.rgfDaysOfTheWeek); if (FAILED(hr)) goto finish; - str.Format(L"PT%uM", ttData.wRandomMinutesInterval); - hr = pTriggerWeekly->put_RandomDelay(CComBSTR(str)); if (FAILED(hr)) goto finish; - break; - } - - case TASK_TIME_TRIGGER_MONTHLYDATE: { - CComPtr pTriggerMonthly; - hr = pTriggerCollection->Create(TASK_TRIGGER_MONTHLY, &pTrigger); if (FAILED(hr)) goto finish; - hr = pTrigger.QueryInterface(&pTriggerMonthly); if (FAILED(hr)) goto finish; - hr = pTriggerMonthly->put_DaysOfMonth(ttData.Type.MonthlyDate.rgfDays); if (FAILED(hr)) goto finish; - hr = pTriggerMonthly->put_MonthsOfYear(ttData.Type.MonthlyDate.rgfMonths); if (FAILED(hr)) goto finish; - str.Format(L"PT%uM", ttData.wRandomMinutesInterval); - hr = pTriggerMonthly->put_RandomDelay(CComBSTR(str)); if (FAILED(hr)) goto finish; - break; - } - - case TASK_TIME_TRIGGER_MONTHLYDOW: { - CComPtr pTriggerMonthlyDOW; - hr = pTriggerCollection->Create(TASK_TRIGGER_MONTHLYDOW, &pTrigger); if (FAILED(hr)) goto finish; - hr = pTrigger.QueryInterface(&pTriggerMonthlyDOW); if (FAILED(hr)) goto finish; - hr = pTriggerMonthlyDOW->put_WeeksOfMonth( - ttData.Type.MonthlyDOW.wWhichWeek == TASK_FIRST_WEEK ? 0x01 : - ttData.Type.MonthlyDOW.wWhichWeek == TASK_SECOND_WEEK ? 0x02 : - ttData.Type.MonthlyDOW.wWhichWeek == TASK_THIRD_WEEK ? 0x04 : - ttData.Type.MonthlyDOW.wWhichWeek == TASK_FOURTH_WEEK ? 0x08 : - ttData.Type.MonthlyDOW.wWhichWeek == TASK_LAST_WEEK ? 0x10 : 0x00); if (FAILED(hr)) goto finish; - hr = pTriggerMonthlyDOW->put_DaysOfWeek(ttData.Type.MonthlyDOW.rgfDaysOfTheWeek); if (FAILED(hr)) goto finish; - hr = pTriggerMonthlyDOW->put_MonthsOfYear(ttData.Type.MonthlyDOW.rgfMonths); if (FAILED(hr)) goto finish; - str.Format(L"PT%uM", ttData.wRandomMinutesInterval); - hr = pTriggerMonthlyDOW->put_RandomDelay(CComBSTR(str)); if (FAILED(hr)) goto finish; - break; - } - - case TASK_EVENT_TRIGGER_ON_IDLE: { - hr = pTriggerCollection->Create(TASK_TRIGGER_IDLE, &pTrigger); if (FAILED(hr)) goto finish; - break; - } - - case TASK_EVENT_TRIGGER_AT_SYSTEMSTART: { - CComPtr pTriggerBoot; - hr = pTriggerCollection->Create(TASK_TRIGGER_BOOT, &pTrigger); if (FAILED(hr)) goto finish; - hr = pTrigger.QueryInterface(&pTriggerBoot); if (FAILED(hr)) goto finish; - str.Format(L"PT%uM", ttData.wRandomMinutesInterval); - hr = pTriggerBoot->put_Delay(CComBSTR(str)); if (FAILED(hr)) goto finish; - break; - } - - case TASK_EVENT_TRIGGER_AT_LOGON: { - CComPtr pTriggerLogon; - hr = pTriggerCollection->Create(TASK_TRIGGER_LOGON, &pTrigger); if (FAILED(hr)) goto finish; - hr = pTrigger.QueryInterface(&pTriggerLogon); if (FAILED(hr)) goto finish; - str.Format(L"PT%uM", ttData.wRandomMinutesInterval); - hr = pTriggerLogon->put_Delay(CComBSTR(str)); if (FAILED(hr)) goto finish; - break; - } - } - - // Set trigger ID. - str.Format(L"%u", iTrigger); - hr = pTrigger->put_Id(CComBSTR(str)); - if (FAILED(hr)) goto finish; - - // Set trigger start date. - str.Format(L"%04u-%02u-%02uT%02u:%02u:00", ttData.wBeginYear, ttData.wBeginMonth, ttData.wBeginDay, ttData.wStartHour, ttData.wStartMinute); - hr = pTrigger->put_StartBoundary(CComBSTR(str)); - if (FAILED(hr)) goto finish; - - if (ttData.rgFlags & TASK_TRIGGER_FLAG_HAS_END_DATE) { - // Set trigger end date. - str.Format(L"%04u-%02u-%02u", ttData.wEndYear, ttData.wEndMonth, ttData.wEndDay); - hr = pTrigger->put_EndBoundary(CComBSTR(str)); - if (FAILED(hr)) goto finish; - } - - // Set trigger repetition duration and interval. - if (ttData.MinutesDuration || ttData.MinutesInterval) { - CComPtr pRepetitionPattern; - - hr = pTrigger->get_Repetition(&pRepetitionPattern); - if (FAILED(hr)) goto finish; - str.Format(L"PT%uM", ttData.MinutesDuration); - hr = pRepetitionPattern->put_Duration(CComBSTR(str)); - if (FAILED(hr)) goto finish; - str.Format(L"PT%uM", ttData.MinutesInterval); - hr = pRepetitionPattern->put_Interval(CComBSTR(str)); - if (FAILED(hr)) goto finish; - hr = pRepetitionPattern->put_StopAtDurationEnd(ttData.rgFlags & TASK_TRIGGER_FLAG_KILL_AT_DURATION_END ? VARIANT_TRUE : VARIANT_FALSE); - if (FAILED(hr)) goto finish; - } - - // Enable/disable trigger. - hr = pTrigger->put_Enabled(ttData.rgFlags & TASK_TRIGGER_FLAG_DISABLED ? VARIANT_FALSE : VARIANT_TRUE); - if (FAILED(hr)) goto finish; - } - - // Get the task folder. - hr = pService->GetFolder(CComBSTR(L"\\"), &pTaskFolder); - if (FAILED(hr)) goto finish; - -#ifdef _DEBUG - CComBSTR xml; - hr = pTaskDefinition->get_XmlText(&xml); -#endif - - // Register the task. - hr = pTaskFolder->RegisterTaskDefinition( - CComBSTR(m_sValue), // path - pTaskDefinition, // pDefinition - TASK_CREATE, // flags - vEmpty, // userId - logonType != TASK_LOGON_SERVICE_ACCOUNT && !m_sPassword.IsEmpty() ? CComVariant(m_sPassword) : vEmpty, // password - logonType, // logonType - vEmpty, // sddl - &pTask); // ppTask - } else { - // Windows XP or older. - CComPtr pTaskScheduler; - CComPtr pTask; - - // Get task scheduler object. - hr = pTaskScheduler.CoCreateInstance(CLSID_CTaskScheduler, NULL, CLSCTX_ALL); - if (FAILED(hr)) goto finish; - - // Create the new task. - hr = pTaskScheduler->NewWorkItem(m_sValue, CLSID_CTask, IID_ITask, (IUnknown**)&pTask); - if (pSession->m_bRollbackEnabled) { - // Order rollback action to delete the task. ITask::NewWorkItem() might made a blank task already. - pSession->m_olRollback.AddHead(new CMSITSCAOpTaskDelete(m_sValue)); - } - if (FAILED(hr)) goto finish; - - // Set its properties. - hr = pTask->SetApplicationName (m_sApplicationName ); if (FAILED(hr)) goto finish; - hr = pTask->SetParameters (m_sParameters ); if (FAILED(hr)) goto finish; - hr = pTask->SetWorkingDirectory(m_sWorkingDirectory); if (FAILED(hr)) goto finish; - hr = pTask->SetComment (m_sComment ); if (FAILED(hr)) goto finish; - if (pSession->m_bRollbackEnabled && (m_dwFlags & TASK_FLAG_DISABLED) == 0) { - // The task is supposed to be enabled. - // However, we shall enable it at commit to prevent it from accidentally starting in the very installation phase. - pSession->m_olCommit.AddTail(new CMSITSCAOpTaskEnable(m_sValue, TRUE)); - m_dwFlags |= TASK_FLAG_DISABLED; - } - hr = pTask->SetFlags (m_dwFlags ); if (FAILED(hr)) goto finish; - hr = pTask->SetPriority (m_dwPriority ); if (FAILED(hr)) goto finish; - - // Set task credentials. - hr = m_sAccountName.IsEmpty() ? - pTask->SetAccountInformation(L"", NULL ) : - pTask->SetAccountInformation(m_sAccountName, m_sPassword); - if (FAILED(hr)) goto finish; - - hr = pTask->SetIdleWait (m_wIdleMinutes, m_wDeadlineMinutes); if (FAILED(hr)) goto finish; - hr = pTask->SetMaxRunTime(m_dwMaxRuntimeMS ); if (FAILED(hr)) goto finish; - - // Add triggers. - for (pos = m_lTriggers.GetHeadPosition(); pos;) { - WORD wTriggerIdx; - CComPtr pTrigger; - TASK_TRIGGER ttData = m_lTriggers.GetNext(pos); // Don't use reference! We don't want to modify original trigger data by adding random startup delay. - - hr = pTask->CreateTrigger(&wTriggerIdx, &pTrigger); - if (FAILED(hr)) goto finish; - - if (ttData.wRandomMinutesInterval) { - // Windows XP doesn't support random startup delay. However, we can add fixed "random" delay when creating the trigger. - WORD wStartTime = ttData.wStartHour * 60 + ttData.wStartMinute + (WORD)::MulDiv(rand(), ttData.wRandomMinutesInterval, RAND_MAX); - FILETIME ftValue; - SYSTEMTIME stValue; - ULONGLONG ullValue; - - // Convert MDY date to numerical date (SYSTEMTIME -> FILETIME -> ULONGLONG). - memset(&stValue, 0, sizeof(SYSTEMTIME)); - stValue.wYear = ttData.wBeginYear; - stValue.wMonth = ttData.wBeginMonth; - stValue.wDay = ttData.wBeginDay; - verify(::SystemTimeToFileTime(&stValue, &ftValue)); - ullValue = ((ULONGLONG)(ftValue.dwHighDateTime) << 32) | ftValue.dwLowDateTime; - - // Wrap days. - while (wStartTime >= 1440) { - ullValue += (ULONGLONG)864000000000; - wStartTime -= 1440; - } - - // Convert numerical date to DMY (ULONGLONG -> FILETIME -> SYSTEMTIME). - ftValue.dwHighDateTime = ullValue >> 32; - ftValue.dwLowDateTime = ullValue & 0xffffffff; - verify(::FileTimeToSystemTime(&ftValue, &stValue)); - - // Set new trigger date and time. - ttData.wBeginYear = stValue.wYear; - ttData.wBeginMonth = stValue.wMonth; - ttData.wBeginDay = stValue.wDay; - ttData.wStartHour = wStartTime / 60; - ttData.wStartMinute = wStartTime % 60; - } - - hr = pTrigger->SetTrigger(&ttData); - if (FAILED(hr)) goto finish; - } - - // Save the task. - CComQIPtr pTaskFile(pTask); - if (!pTaskFile) { hr = E_NOINTERFACE; goto finish; } - hr = pTaskFile->Save(NULL, TRUE); - } - -finish: - if (FAILED(hr)) { - PMSIHANDLE hRecordProg = ::MsiCreateRecord(3); - verify(::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_TASK_CREATE_FAILED) == ERROR_SUCCESS); - verify(::MsiRecordSetStringW(hRecordProg, 2, m_sValue ) == ERROR_SUCCESS); - verify(::MsiRecordSetInteger(hRecordProg, 3, hr ) == ERROR_SUCCESS); - ::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg); - } - return hr; -} - - -UINT CMSITSCAOpTaskCreate::SetFromRecord(MSIHANDLE hInstall, MSIHANDLE hRecord) -{ - UINT uiResult; - int iValue; - CStringW sFolder; - - uiResult = ::MsiRecordFormatStringW(hInstall, hRecord, 3, m_sApplicationName); - if (uiResult != ERROR_SUCCESS) return uiResult; - - uiResult = ::MsiRecordFormatStringW(hInstall, hRecord, 4, m_sParameters); - if (uiResult != ERROR_SUCCESS) return uiResult; - - uiResult = ::MsiRecordGetStringW(hRecord, 5, sFolder); - if (uiResult != ERROR_SUCCESS) return uiResult; - uiResult = ::MsiGetTargetPathW(hInstall, sFolder, m_sWorkingDirectory); - if (uiResult != ERROR_SUCCESS) return uiResult; - if (!m_sWorkingDirectory.IsEmpty() && m_sWorkingDirectory.GetAt(m_sWorkingDirectory.GetLength() - 1) == L'\\') { - // Trim trailing backslash. - m_sWorkingDirectory.Truncate(m_sWorkingDirectory.GetLength() - 1); - } - - uiResult = ::MsiRecordFormatStringW(hInstall, hRecord, 10, m_sAuthor); - if (uiResult != ERROR_SUCCESS) return uiResult; - - uiResult = ::MsiRecordFormatStringW(hInstall, hRecord, 11, m_sComment); - if (uiResult != ERROR_SUCCESS) return uiResult; - - m_dwFlags = ::MsiRecordGetInteger(hRecord, 6); - if (m_dwFlags == MSI_NULL_INTEGER) return ERROR_INVALID_FIELD; - - m_dwPriority = ::MsiRecordGetInteger(hRecord, 7); - if (m_dwPriority == MSI_NULL_INTEGER) return ERROR_INVALID_FIELD; - - uiResult = ::MsiRecordFormatStringW(hInstall, hRecord, 8, m_sAccountName); - if (uiResult != ERROR_SUCCESS) return uiResult; - - uiResult = ::MsiRecordFormatStringW(hInstall, hRecord, 9, m_sPassword); - if (uiResult != ERROR_SUCCESS) return uiResult; - - iValue = ::MsiRecordGetInteger(hRecord, 12); - m_wIdleMinutes = iValue != MSI_NULL_INTEGER ? (WORD)iValue : 0; - - iValue = ::MsiRecordGetInteger(hRecord, 13); - m_wDeadlineMinutes = iValue != MSI_NULL_INTEGER ? (WORD)iValue : 0; - - m_dwMaxRuntimeMS = ::MsiRecordGetInteger(hRecord, 14); - if (m_dwMaxRuntimeMS == MSI_NULL_INTEGER) return ERROR_INVALID_FIELD; - - return ERROR_SUCCESS; -} - - -UINT CMSITSCAOpTaskCreate::SetTriggersFromView(MSIHANDLE hView) -{ - for (;;) { - UINT uiResult; - PMSIHANDLE hRecord; - TASK_TRIGGER ttData; - ULONGLONG ullValue; - FILETIME ftValue; - SYSTEMTIME stValue; - int iValue; - - // Fetch one record from the view. - uiResult = ::MsiViewFetch(hView, &hRecord); - if (uiResult == ERROR_NO_MORE_ITEMS) return ERROR_SUCCESS; - else if (uiResult != ERROR_SUCCESS) return uiResult; - - ZeroMemory(&ttData, sizeof(TASK_TRIGGER)); - ttData.cbTriggerSize = sizeof(TASK_TRIGGER); - - // Get StartDate. - iValue = ::MsiRecordGetInteger(hRecord, 2); - if (iValue == MSI_NULL_INTEGER) return ERROR_INVALID_FIELD; - ullValue = ((ULONGLONG)iValue + 138426) * 864000000000; - ftValue.dwHighDateTime = ullValue >> 32; - ftValue.dwLowDateTime = ullValue & 0xffffffff; - if (!::FileTimeToSystemTime(&ftValue, &stValue)) - return ::GetLastError(); - ttData.wBeginYear = stValue.wYear; - ttData.wBeginMonth = stValue.wMonth; - ttData.wBeginDay = stValue.wDay; - - // Get EndDate. - iValue = ::MsiRecordGetInteger(hRecord, 3); - if (iValue != MSI_NULL_INTEGER) { - ullValue = ((ULONGLONG)iValue + 138426) * 864000000000; - ftValue.dwHighDateTime = ullValue >> 32; - ftValue.dwLowDateTime = ullValue & 0xffffffff; - if (!::FileTimeToSystemTime(&ftValue, &stValue)) - return ::GetLastError(); - ttData.wEndYear = stValue.wYear; - ttData.wEndMonth = stValue.wMonth; - ttData.wEndDay = stValue.wDay; - ttData.rgFlags |= TASK_TRIGGER_FLAG_HAS_END_DATE; - } - - // Get StartTime. - iValue = ::MsiRecordGetInteger(hRecord, 4); - if (iValue == MSI_NULL_INTEGER) return ERROR_INVALID_FIELD; - ttData.wStartHour = (WORD)(iValue / 60); - ttData.wStartMinute = (WORD)(iValue % 60); - - // Get StartTimeRand. - iValue = ::MsiRecordGetInteger(hRecord, 5); - ttData.wRandomMinutesInterval = iValue != MSI_NULL_INTEGER ? (WORD)iValue : 0; - - // Get MinutesDuration. - iValue = ::MsiRecordGetInteger(hRecord, 6); - ttData.MinutesDuration = iValue != MSI_NULL_INTEGER ? iValue : 0; - - // Get MinutesInterval. - iValue = ::MsiRecordGetInteger(hRecord, 7); - ttData.MinutesInterval = iValue != MSI_NULL_INTEGER ? iValue : 0; - - // Get Flags. - iValue = ::MsiRecordGetInteger(hRecord, 8); - if (iValue == MSI_NULL_INTEGER) return ERROR_INVALID_FIELD; - ttData.rgFlags |= iValue & ~TASK_TRIGGER_FLAG_HAS_END_DATE; - - // Get Type. - iValue = ::MsiRecordGetInteger(hRecord, 9); - if (iValue == MSI_NULL_INTEGER) return ERROR_INVALID_FIELD; - ttData.TriggerType = (TASK_TRIGGER_TYPE)iValue; - - switch (ttData.TriggerType) { - case TASK_TIME_TRIGGER_DAILY: - // Get DaysInterval. - iValue = ::MsiRecordGetInteger(hRecord, 10); - if (iValue == MSI_NULL_INTEGER) return ERROR_INVALID_FIELD; - ttData.Type.Daily.DaysInterval = (WORD)iValue; - break; - - case TASK_TIME_TRIGGER_WEEKLY: - // Get WeeksInterval. - iValue = ::MsiRecordGetInteger(hRecord, 11); - if (iValue == MSI_NULL_INTEGER) return ERROR_INVALID_FIELD; - ttData.Type.Weekly.WeeksInterval = (WORD)iValue; - - // Get DaysOfTheWeek. - iValue = ::MsiRecordGetInteger(hRecord, 12); - if (iValue == MSI_NULL_INTEGER) return ERROR_INVALID_FIELD; - ttData.Type.Weekly.rgfDaysOfTheWeek = (WORD)iValue; - break; - - case TASK_TIME_TRIGGER_MONTHLYDATE: - // Get DaysOfMonth. - iValue = ::MsiRecordGetInteger(hRecord, 13); - if (iValue == MSI_NULL_INTEGER) return ERROR_INVALID_FIELD; - ttData.Type.MonthlyDate.rgfDays = (WORD)iValue; - - // Get MonthsOfYear. - iValue = ::MsiRecordGetInteger(hRecord, 15); - if (iValue == MSI_NULL_INTEGER) return ERROR_INVALID_FIELD; - ttData.Type.MonthlyDate.rgfMonths = (WORD)iValue; - break; - - case TASK_TIME_TRIGGER_MONTHLYDOW: - // Get WeekOfMonth. - iValue = ::MsiRecordGetInteger(hRecord, 14); - if (iValue == MSI_NULL_INTEGER) return ERROR_INVALID_FIELD; - ttData.Type.MonthlyDOW.wWhichWeek = (WORD)iValue; - - // Get DaysOfTheWeek. - iValue = ::MsiRecordGetInteger(hRecord, 12); - if (iValue == MSI_NULL_INTEGER) return ERROR_INVALID_FIELD; - ttData.Type.MonthlyDOW.rgfDaysOfTheWeek = (WORD)iValue; - - // Get MonthsOfYear. - iValue = ::MsiRecordGetInteger(hRecord, 15); - if (iValue == MSI_NULL_INTEGER) return ERROR_INVALID_FIELD; - ttData.Type.MonthlyDOW.rgfMonths = (WORD)iValue; - break; - } - - m_lTriggers.AddTail(ttData); - } - - return ERROR_SUCCESS; -} - - -//////////////////////////////////////////////////////////////////////////// -// CMSITSCAOpTaskDelete -//////////////////////////////////////////////////////////////////////////// - -CMSITSCAOpTaskDelete::CMSITSCAOpTaskDelete(LPCWSTR pszTaskName, int iTicks) : - CMSITSCAOpTypeSingleString(pszTaskName, iTicks) -{ -} - - -HRESULT CMSITSCAOpTaskDelete::Execute(CMSITSCASession *pSession) -{ - assert(pSession); - HRESULT hr; - CComPtr pService; - - hr = pService.CoCreateInstance(CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER); - if (SUCCEEDED(hr)) { - // Windows Vista or newer. - CComVariant vEmpty; - CComPtr pTaskFolder; - - // Connect to local task service. - hr = pService->Connect(vEmpty, vEmpty, vEmpty, vEmpty); - if (FAILED(hr)) goto finish; - - // Get task folder. - hr = pService->GetFolder(CComBSTR(L"\\"), &pTaskFolder); - if (FAILED(hr)) goto finish; - - if (pSession->m_bRollbackEnabled) { - CComPtr pTask, pTaskOrig; - CComPtr pTaskDefinition; - CComPtr pPrincipal; - VARIANT_BOOL bEnabled; - TASK_LOGON_TYPE logonType; - CComBSTR sSSDL; - CComVariant vSSDL; - CStringW sDisplayNameOrig; - UINT uiCount = 0; - - // Get the source task. - hr = pTaskFolder->GetTask(CComBSTR(m_sValue), &pTask); - if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) { hr = S_OK; goto finish; } - else if (FAILED(hr)) goto finish; - - // Disable the task. - hr = pTask->get_Enabled(&bEnabled); - if (FAILED(hr)) goto finish; - if (bEnabled) { - // The task is enabled. - - // In case the task disabling fails halfway, try to re-enable it anyway on rollback. - pSession->m_olRollback.AddHead(new CMSITSCAOpTaskEnable(m_sValue, TRUE)); - - // Disable it. - hr = pTask->put_Enabled(VARIANT_FALSE); - if (FAILED(hr)) goto finish; - } - - // Get task's definition. - hr = pTask->get_Definition(&pTaskDefinition); - if (FAILED(hr)) goto finish; - - // Get task principal. - hr = pTaskDefinition->get_Principal(&pPrincipal); - if (FAILED(hr)) goto finish; - - // Get task logon type. - hr = pPrincipal->get_LogonType(&logonType); - if (FAILED(hr)) goto finish; - - // Get task security descriptor. - hr = pTask->GetSecurityDescriptor(DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION, &sSSDL); - if (hr == HRESULT_FROM_WIN32(ERROR_PRIVILEGE_NOT_HELD)) vSSDL.Clear(); - else if (FAILED(hr)) goto finish; - else { - V_VT (&vSSDL) = VT_BSTR; - V_BSTR(&vSSDL) = sSSDL.Detach(); - } - - // Register a backup copy of task. - do { - sDisplayNameOrig.Format(L"%ls (orig %u)", (LPCWSTR)m_sValue, ++uiCount); - hr = pTaskFolder->RegisterTaskDefinition( - CComBSTR(sDisplayNameOrig), // path - pTaskDefinition, // pDefinition - TASK_CREATE, // flags - vEmpty, // userId - vEmpty, // password - logonType, // logonType - vSSDL, // sddl - &pTaskOrig); // ppTask - } while (hr == HRESULT_FROM_WIN32(ERROR_FILE_EXISTS)); - // In case the backup copy creation failed halfway, try to delete its remains anyway on rollback. - pSession->m_olRollback.AddHead(new CMSITSCAOpTaskDelete(sDisplayNameOrig)); - if (FAILED(hr)) goto finish; - - // Order rollback action to restore from backup copy. - pSession->m_olRollback.AddHead(new CMSITSCAOpTaskCopy(sDisplayNameOrig, m_sValue)); - - // Delete it. - hr = pTaskFolder->DeleteTask(CComBSTR(m_sValue), 0); - if (FAILED(hr)) goto finish; - - // Order commit action to delete backup copy. - pSession->m_olCommit.AddTail(new CMSITSCAOpTaskDelete(sDisplayNameOrig)); - } else { - // Delete the task. - hr = pTaskFolder->DeleteTask(CComBSTR(m_sValue), 0); - if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) hr = S_OK; - } - } else { - // Windows XP or older. - CComPtr pTaskScheduler; - - // Get task scheduler object. - hr = pTaskScheduler.CoCreateInstance(CLSID_CTaskScheduler, NULL, CLSCTX_ALL); - if (FAILED(hr)) goto finish; - - if (pSession->m_bRollbackEnabled) { - CComPtr pTask; - DWORD dwFlags; - CStringW sDisplayNameOrig; - UINT uiCount = 0; - - // Load the task. - hr = pTaskScheduler->Activate(m_sValue, IID_ITask, (IUnknown**)&pTask); - if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) { hr = S_OK; goto finish; } - else if (FAILED(hr)) goto finish; - - // Disable the task. - hr = pTask->GetFlags(&dwFlags); - if (FAILED(hr)) goto finish; - if ((dwFlags & TASK_FLAG_DISABLED) == 0) { - // The task is enabled. - - // In case the task disabling fails halfway, try to re-enable it anyway on rollback. - pSession->m_olRollback.AddHead(new CMSITSCAOpTaskEnable(m_sValue, TRUE)); - - // Disable it. - dwFlags |= TASK_FLAG_DISABLED; - hr = pTask->SetFlags(dwFlags); - if (FAILED(hr)) goto finish; - } - - // Prepare a backup copy of task. - do { - sDisplayNameOrig.Format(L"%ls (orig %u)", (LPCWSTR)m_sValue, ++uiCount); - hr = pTaskScheduler->AddWorkItem(sDisplayNameOrig, pTask); - } while (hr == HRESULT_FROM_WIN32(ERROR_FILE_EXISTS)); - // In case the backup copy creation failed halfway, try to delete its remains anyway on rollback. - pSession->m_olRollback.AddHead(new CMSITSCAOpTaskDelete(sDisplayNameOrig)); - if (FAILED(hr)) goto finish; - - // Save the backup copy. - CComQIPtr pTaskFile(pTask); - if (!pTaskFile) { hr = E_NOINTERFACE; goto finish; } - hr = pTaskFile->Save(NULL, TRUE); - if (FAILED(hr)) goto finish; - - // Order rollback action to restore from backup copy. - pSession->m_olRollback.AddHead(new CMSITSCAOpTaskCopy(sDisplayNameOrig, m_sValue)); - - // Delete it. - hr = pTaskScheduler->Delete(m_sValue); - if (FAILED(hr)) goto finish; - - // Order commit action to delete backup copy. - pSession->m_olCommit.AddTail(new CMSITSCAOpTaskDelete(sDisplayNameOrig)); - } else { - // Delete the task. - hr = pTaskScheduler->Delete(m_sValue); - if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) hr = S_OK; - } - } - -finish: - if (FAILED(hr)) { - PMSIHANDLE hRecordProg = ::MsiCreateRecord(3); - verify(::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_TASK_DELETE_FAILED) == ERROR_SUCCESS); - verify(::MsiRecordSetStringW(hRecordProg, 2, m_sValue ) == ERROR_SUCCESS); - verify(::MsiRecordSetInteger(hRecordProg, 3, hr ) == ERROR_SUCCESS); - ::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg); - } - return hr; -} - - -//////////////////////////////////////////////////////////////////////////// -// CMSITSCAOpTaskEnable -//////////////////////////////////////////////////////////////////////////// - -CMSITSCAOpTaskEnable::CMSITSCAOpTaskEnable(LPCWSTR pszTaskName, BOOL bEnable, int iTicks) : - m_bEnable(bEnable), - CMSITSCAOpTypeSingleString(pszTaskName, iTicks) -{ -} - - -HRESULT CMSITSCAOpTaskEnable::Execute(CMSITSCASession *pSession) -{ - assert(pSession); - HRESULT hr; - CComPtr pService; - - hr = pService.CoCreateInstance(CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER); - if (SUCCEEDED(hr)) { - // Windows Vista or newer. - CComVariant vEmpty; - CComPtr pTaskFolder; - CComPtr pTask; - VARIANT_BOOL bEnabled; - - // Connect to local task service. - hr = pService->Connect(vEmpty, vEmpty, vEmpty, vEmpty); - if (FAILED(hr)) goto finish; - - // Get task folder. - hr = pService->GetFolder(CComBSTR(L"\\"), &pTaskFolder); - if (FAILED(hr)) goto finish; - - // Get task. - hr = pTaskFolder->GetTask(CComBSTR(m_sValue), &pTask); - if (FAILED(hr)) goto finish; - - // Get currently enabled state. - hr = pTask->get_Enabled(&bEnabled); - if (FAILED(hr)) goto finish; - - // Modify enable state. - if (m_bEnable) { - if (pSession->m_bRollbackEnabled && !bEnabled) { - // The task is disabled and supposed to be enabled. - // However, we shall enable it at commit to prevent it from accidentally starting in the very installation phase. - pSession->m_olCommit.AddTail(new CMSITSCAOpTaskEnable(m_sValue, TRUE)); - hr = S_OK; goto finish; - } else - bEnabled = VARIANT_TRUE; - } else { - if (pSession->m_bRollbackEnabled && bEnabled) { - // The task is enabled and we will disable it now. - // Order rollback to re-enable it. - pSession->m_olRollback.AddHead(new CMSITSCAOpTaskEnable(m_sValue, TRUE)); - } - bEnabled = VARIANT_FALSE; - } - - // Set enable/disable. - hr = pTask->put_Enabled(bEnabled); - if (FAILED(hr)) goto finish; - } else { - // Windows XP or older. - CComPtr pTaskScheduler; - CComPtr pTask; - DWORD dwFlags; - - // Get task scheduler object. - hr = pTaskScheduler.CoCreateInstance(CLSID_CTaskScheduler, NULL, CLSCTX_ALL); - if (FAILED(hr)) goto finish; - - // Load the task. - hr = pTaskScheduler->Activate(m_sValue, IID_ITask, (IUnknown**)&pTask); - if (FAILED(hr)) goto finish; - - // Get task's current flags. - hr = pTask->GetFlags(&dwFlags); - if (FAILED(hr)) goto finish; - - // Modify flags. - if (m_bEnable) { - if (pSession->m_bRollbackEnabled && (dwFlags & TASK_FLAG_DISABLED)) { - // The task is disabled and supposed to be enabled. - // However, we shall enable it at commit to prevent it from accidentally starting in the very installation phase. - pSession->m_olCommit.AddTail(new CMSITSCAOpTaskEnable(m_sValue, TRUE)); - hr = S_OK; goto finish; - } else - dwFlags &= ~TASK_FLAG_DISABLED; - } else { - if (pSession->m_bRollbackEnabled && !(dwFlags & TASK_FLAG_DISABLED)) { - // The task is enabled and we will disable it now. - // Order rollback to re-enable it. - pSession->m_olRollback.AddHead(new CMSITSCAOpTaskEnable(m_sValue, TRUE)); - } - dwFlags |= TASK_FLAG_DISABLED; - } - - // Set flags. - hr = pTask->SetFlags(dwFlags); - if (FAILED(hr)) goto finish; - - // Save the task. - CComQIPtr pTaskFile(pTask); - if (!pTaskFile) { hr = E_NOINTERFACE; goto finish; } - hr = pTaskFile->Save(NULL, TRUE); - if (FAILED(hr)) goto finish; - } - -finish: - if (FAILED(hr)) { - PMSIHANDLE hRecordProg = ::MsiCreateRecord(3); - verify(::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_TASK_ENABLE_FAILED) == ERROR_SUCCESS); - verify(::MsiRecordSetStringW(hRecordProg, 2, m_sValue ) == ERROR_SUCCESS); - verify(::MsiRecordSetInteger(hRecordProg, 3, hr ) == ERROR_SUCCESS); - ::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg); - } - return hr; -} - - -//////////////////////////////////////////////////////////////////////////// -// CMSITSCAOpTaskCopy -//////////////////////////////////////////////////////////////////////////// - -CMSITSCAOpTaskCopy::CMSITSCAOpTaskCopy(LPCWSTR pszTaskSrc, LPCWSTR pszTaskDst, int iTicks) : - CMSITSCAOpTypeSrcDstString(pszTaskSrc, pszTaskDst, iTicks) -{ -} - - -HRESULT CMSITSCAOpTaskCopy::Execute(CMSITSCASession *pSession) -{ - assert(pSession); - HRESULT hr; - CComPtr pService; - - hr = pService.CoCreateInstance(CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER); - if (SUCCEEDED(hr)) { - // Windows Vista or newer. - CComVariant vEmpty; - CComPtr pTaskFolder; - CComPtr pTask, pTaskOrig; - CComPtr pTaskDefinition; - CComPtr pPrincipal; - TASK_LOGON_TYPE logonType; - CComBSTR sSSDL; - - // Connect to local task service. - hr = pService->Connect(vEmpty, vEmpty, vEmpty, vEmpty); - if (FAILED(hr)) goto finish; - - // Get task folder. - hr = pService->GetFolder(CComBSTR(L"\\"), &pTaskFolder); - if (FAILED(hr)) goto finish; - - // Get the source task. - hr = pTaskFolder->GetTask(CComBSTR(m_sValue1), &pTask); - if (FAILED(hr)) goto finish; - - // Get task's definition. - hr = pTask->get_Definition(&pTaskDefinition); - if (FAILED(hr)) goto finish; - - // Get task principal. - hr = pTaskDefinition->get_Principal(&pPrincipal); - if (FAILED(hr)) goto finish; - - // Get task logon type. - hr = pPrincipal->get_LogonType(&logonType); - if (FAILED(hr)) goto finish; - - // Get task security descriptor. - hr = pTask->GetSecurityDescriptor(DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION, &sSSDL); - if (FAILED(hr)) goto finish; - - // Register a new task. - hr = pTaskFolder->RegisterTaskDefinition( - CComBSTR(m_sValue2), // path - pTaskDefinition, // pDefinition - TASK_CREATE, // flags - vEmpty, // userId - vEmpty, // password - logonType, // logonType - CComVariant(sSSDL), // sddl - &pTaskOrig); // ppTask - if (FAILED(hr)) goto finish; - } else { - // Windows XP or older. - CComPtr pTaskScheduler; - CComPtr pTask; - - // Get task scheduler object. - hr = pTaskScheduler.CoCreateInstance(CLSID_CTaskScheduler, NULL, CLSCTX_ALL); - if (FAILED(hr)) goto finish; - - // Load the source task. - hr = pTaskScheduler->Activate(m_sValue1, IID_ITask, (IUnknown**)&pTask); - if (FAILED(hr)) goto finish; - - // Add with different name. - hr = pTaskScheduler->AddWorkItem(m_sValue2, pTask); - if (pSession->m_bRollbackEnabled) { - // Order rollback action to delete the new copy. ITask::AddWorkItem() might made a blank task already. - pSession->m_olRollback.AddHead(new CMSITSCAOpTaskDelete(m_sValue2)); - } - if (FAILED(hr)) goto finish; - - // Save the task. - CComQIPtr pTaskFile(pTask); - if (!pTaskFile) { hr = E_NOINTERFACE; goto finish; } - hr = pTaskFile->Save(NULL, TRUE); - if (FAILED(hr)) goto finish; - } - -finish: - if (FAILED(hr)) { - PMSIHANDLE hRecordProg = ::MsiCreateRecord(4); - verify(::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_TASK_COPY_FAILED) == ERROR_SUCCESS); - verify(::MsiRecordSetStringW(hRecordProg, 2, m_sValue1 ) == ERROR_SUCCESS); - verify(::MsiRecordSetStringW(hRecordProg, 3, m_sValue2 ) == ERROR_SUCCESS); - verify(::MsiRecordSetInteger(hRecordProg, 4, hr ) == ERROR_SUCCESS); - ::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg); - } - return hr; -} - - -//////////////////////////////////////////////////////////////////////////// -// CMSITSCAOpList -//////////////////////////////////////////////////////////////////////////// - -CMSITSCAOpList::CMSITSCAOpList(int iTicks) : - CMSITSCAOp(iTicks), - CAtlList(sizeof(CMSITSCAOp*)) -{ -} - - -void CMSITSCAOpList::Free() -{ - POSITION pos; - - for (pos = GetHeadPosition(); pos;) { - CMSITSCAOp *pOp = GetNext(pos); - CMSITSCAOpList *pOpList = dynamic_cast(pOp); - - if (pOpList) { - // Recursivelly free sublists. - pOpList->Free(); - } - delete pOp; - } - - RemoveAll(); -} - - -HRESULT CMSITSCAOpList::LoadFromFile(LPCTSTR pszFileName) -{ - assert(pszFileName); - HRESULT hr; - CAtlFile fSequence; - - hr = fSequence.Create(pszFileName, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN); - if (FAILED(hr)) return hr; - - // Load operation sequence. - return fSequence >> *this; -} - - -HRESULT CMSITSCAOpList::SaveToFile(LPCTSTR pszFileName) const -{ - assert(pszFileName); - HRESULT hr; - CAtlFile fSequence; - - hr = fSequence.Create(pszFileName, GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN); - if (FAILED(hr)) return hr; - - // Save execute sequence to file. - hr = fSequence << *this; - fSequence.Close(); - - if (FAILED(hr)) ::DeleteFile(pszFileName); - return hr; -} - - -HRESULT CMSITSCAOpList::Execute(CMSITSCASession *pSession) -{ - assert(pSession); - POSITION pos; - HRESULT hr; - PMSIHANDLE hRecordProg = ::MsiCreateRecord(3); - - // Tell the installer to use explicit progress messages. - verify(::MsiRecordSetInteger(hRecordProg, 1, 1) == ERROR_SUCCESS); - verify(::MsiRecordSetInteger(hRecordProg, 2, 1) == ERROR_SUCCESS); - verify(::MsiRecordSetInteger(hRecordProg, 3, 0) == ERROR_SUCCESS); - ::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_PROGRESS, hRecordProg); - - // Prepare hRecordProg for progress messages. - verify(::MsiRecordSetInteger(hRecordProg, 1, 2) == ERROR_SUCCESS); - verify(::MsiRecordSetInteger(hRecordProg, 3, 0) == ERROR_SUCCESS); - - for (pos = GetHeadPosition(); pos;) { - CMSITSCAOp *pOp = GetNext(pos); - assert(pOp); - - hr = pOp->Execute(pSession); - if (!pSession->m_bContinueOnError && FAILED(hr)) { - // Operation failed. Its Execute() method should have sent error message to Installer. - // Therefore, just quit here. - return hr; - } - - verify(::MsiRecordSetInteger(hRecordProg, 2, pOp->m_iTicks) == ERROR_SUCCESS); - if (::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_PROGRESS, hRecordProg) == IDCANCEL) - return AtlHresultFromWin32(ERROR_INSTALL_USEREXIT); - } - - verify(::MsiRecordSetInteger(hRecordProg, 2, m_iTicks) == ERROR_SUCCESS); - ::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_PROGRESS, hRecordProg); - - return S_OK; -} - - -//////////////////////////////////////////////////////////////////////////// -// CMSITSCASession -//////////////////////////////////////////////////////////////////////////// - -CMSITSCASession::CMSITSCASession() : - m_bContinueOnError(FALSE), - m_bRollbackEnabled(FALSE) -{ -} diff --git a/MSICALib/MSITSCAOp.h b/MSICALib/MSITSCAOp.h deleted file mode 100644 index c103ef8..0000000 --- a/MSICALib/MSITSCAOp.h +++ /dev/null @@ -1,565 +0,0 @@ -#ifndef __MSITSCAOP_H__ -#define __MSITSCAOP_H__ - -#include "MSITSCA.h" -#include -#include -#include -#include -#include -#include -#include - -class CMSITSCASession; - - -//////////////////////////////////////////////////////////////////////////// -// CMSITSCAOp -//////////////////////////////////////////////////////////////////////////// - -class CMSITSCAOp -{ -public: - CMSITSCAOp(int iTicks = 0); - - virtual HRESULT Execute(CMSITSCASession *pSession) = 0; - - friend class CMSITSCAOpList; - friend inline HRESULT operator <<(CAtlFile &f, const CMSITSCAOp &op); - friend inline HRESULT operator >>(CAtlFile &f, CMSITSCAOp &op); - -protected: - int m_iTicks; // Number of ticks on a progress bar required for this action execution -}; - - -//////////////////////////////////////////////////////////////////////////// -// CMSITSCAOpTypeSingleString -//////////////////////////////////////////////////////////////////////////// - -class CMSITSCAOpTypeSingleString : public CMSITSCAOp -{ -public: - CMSITSCAOpTypeSingleString(LPCWSTR pszValue = L"", int iTicks = 0); - - friend inline HRESULT operator <<(CAtlFile &f, const CMSITSCAOpTypeSingleString &op); - friend inline HRESULT operator >>(CAtlFile &f, CMSITSCAOpTypeSingleString &op); - -protected: - CStringW m_sValue; -}; - - -//////////////////////////////////////////////////////////////////////////// -// CMSITSCAOpDoubleStringOperation -//////////////////////////////////////////////////////////////////////////// - -class CMSITSCAOpTypeSrcDstString : public CMSITSCAOp -{ -public: - CMSITSCAOpTypeSrcDstString(LPCWSTR pszValue1 = L"", LPCWSTR pszValue2 = L"", int iTicks = 0); - - friend inline HRESULT operator <<(CAtlFile &f, const CMSITSCAOpTypeSrcDstString &op); - friend inline HRESULT operator >>(CAtlFile &f, CMSITSCAOpTypeSrcDstString &op); - -protected: - CStringW m_sValue1; - CStringW m_sValue2; -}; - - -//////////////////////////////////////////////////////////////////////////// -// CMSITSCAOpTypeBoolean -//////////////////////////////////////////////////////////////////////////// - -class CMSITSCAOpTypeBoolean : public CMSITSCAOp -{ -public: - CMSITSCAOpTypeBoolean(BOOL bValue = TRUE, int iTicks = 0); - - friend inline HRESULT operator <<(CAtlFile &f, const CMSITSCAOpTypeBoolean &op); - friend inline HRESULT operator >>(CAtlFile &f, CMSITSCAOpTypeBoolean &op); - -protected: - BOOL m_bValue; -}; - - -//////////////////////////////////////////////////////////////////////////// -// CMSITSCAOpRollbackEnable -//////////////////////////////////////////////////////////////////////////// - -class CMSITSCAOpRollbackEnable : public CMSITSCAOpTypeBoolean -{ -public: - CMSITSCAOpRollbackEnable(BOOL bEnable = TRUE, int iTicks = 0); - virtual HRESULT Execute(CMSITSCASession *pSession); -}; - - -//////////////////////////////////////////////////////////////////////////// -// CMSITSCAOpFileDelete -//////////////////////////////////////////////////////////////////////////// - -class CMSITSCAOpFileDelete : public CMSITSCAOpTypeSingleString -{ -public: - CMSITSCAOpFileDelete(LPCWSTR pszFileName = L"", int iTicks = 0); - virtual HRESULT Execute(CMSITSCASession *pSession); -}; - - -//////////////////////////////////////////////////////////////////////////// -// CMSITSCAOpFileMove -//////////////////////////////////////////////////////////////////////////// - -class CMSITSCAOpFileMove : public CMSITSCAOpTypeSrcDstString -{ -public: - CMSITSCAOpFileMove(LPCWSTR pszFileSrc = L"", LPCWSTR pszFileDst = L"", int iTicks = 0); - virtual HRESULT Execute(CMSITSCASession *pSession); -}; - - -//////////////////////////////////////////////////////////////////////////// -// CMSITSCAOpTaskCreate -//////////////////////////////////////////////////////////////////////////// - -class CMSITSCAOpTaskCreate : public CMSITSCAOpTypeSingleString -{ -public: - CMSITSCAOpTaskCreate(LPCWSTR pszTaskName = L"", int iTicks = 0); - virtual ~CMSITSCAOpTaskCreate(); - virtual HRESULT Execute(CMSITSCASession *pSession); - - UINT SetFromRecord(MSIHANDLE hInstall, MSIHANDLE hRecord); - UINT SetTriggersFromView(MSIHANDLE hView); - - friend inline HRESULT operator <<(CAtlFile &f, const CMSITSCAOpTaskCreate &op); - friend inline HRESULT operator >>(CAtlFile &f, CMSITSCAOpTaskCreate &op); - -protected: - CStringW m_sApplicationName; - CStringW m_sParameters; - CStringW m_sWorkingDirectory; - CStringW m_sAuthor; - CStringW m_sComment; - DWORD m_dwFlags; - DWORD m_dwPriority; - CStringW m_sAccountName; - CStringW m_sPassword; - WORD m_wIdleMinutes; - WORD m_wDeadlineMinutes; - DWORD m_dwMaxRuntimeMS; - - CAtlList m_lTriggers; -}; - - -//////////////////////////////////////////////////////////////////////////// -// CMSITSCAOpTaskDelete -//////////////////////////////////////////////////////////////////////////// - -class CMSITSCAOpTaskDelete : public CMSITSCAOpTypeSingleString -{ -public: - CMSITSCAOpTaskDelete(LPCWSTR pszTaskName = L"", int iTicks = 0); - virtual HRESULT Execute(CMSITSCASession *pSession); -}; - - -//////////////////////////////////////////////////////////////////////////// -// CMSITSCAOpTaskEnable -//////////////////////////////////////////////////////////////////////////// - -class CMSITSCAOpTaskEnable : public CMSITSCAOpTypeSingleString -{ -public: - CMSITSCAOpTaskEnable(LPCWSTR pszTaskName = L"", BOOL bEnable = TRUE, int iTicks = 0); - virtual HRESULT Execute(CMSITSCASession *pSession); - - friend inline HRESULT operator <<(CAtlFile &f, const CMSITSCAOpTaskEnable &op); - friend inline HRESULT operator >>(CAtlFile &f, CMSITSCAOpTaskEnable &op); - -protected: - BOOL m_bEnable; -}; - - -//////////////////////////////////////////////////////////////////////////// -// CMSITSCAOpTaskCopy -//////////////////////////////////////////////////////////////////////////// - -class CMSITSCAOpTaskCopy : public CMSITSCAOpTypeSrcDstString -{ -public: - CMSITSCAOpTaskCopy(LPCWSTR pszTaskSrc = L"", LPCWSTR pszTaskDst = L"", int iTicks = 0); - virtual HRESULT Execute(CMSITSCASession *pSession); -}; - - -//////////////////////////////////////////////////////////////////////////// -// CMSITSCAOpList -//////////////////////////////////////////////////////////////////////////// - -class CMSITSCAOpList : public CMSITSCAOp, public CAtlList -{ -public: - CMSITSCAOpList(int iTicks = 0); - - void Free(); - HRESULT LoadFromFile(LPCTSTR pszFileName); - HRESULT SaveToFile(LPCTSTR pszFileName) const; - - virtual HRESULT Execute(CMSITSCASession *pSession); - - friend inline HRESULT operator <<(CAtlFile &f, const CMSITSCAOpList &op); - friend inline HRESULT operator >>(CAtlFile &f, CMSITSCAOpList &op); - -protected: - enum OPERATION { - OPERATION_ENABLE_ROLLBACK = 1, - OPERATION_DELETE_FILE, - OPERATION_MOVE_FILE, - OPERATION_CREATE_TASK, - OPERATION_DELETE_TASK, - OPERATION_ENABLE_TASK, - OPERATION_COPY_TASK, - OPERATION_SUBLIST - }; - -protected: - template inline static HRESULT Save(CAtlFile &f, const CMSITSCAOp *p); - template inline HRESULT LoadAndAddTail(CAtlFile &f); -}; - - -//////////////////////////////////////////////////////////////////////////// -// CMSITSCASession -//////////////////////////////////////////////////////////////////////////// - -class CMSITSCASession -{ -public: - CMSITSCASession(); - - MSIHANDLE m_hInstall; // Installer handle - BOOL m_bContinueOnError; // Continue execution on operation error? - BOOL m_bRollbackEnabled; // Is rollback enabled? - CMSITSCAOpList m_olRollback; // Rollback operation list - CMSITSCAOpList m_olCommit; // Commit operation list -}; - - -//////////////////////////////////////////////////////////////////////////// -// Inline operators -//////////////////////////////////////////////////////////////////////////// - -inline HRESULT operator <<(CAtlFile &f, const CMSITSCAOp &op) -{ - return f << op.m_iTicks; -} - - -inline HRESULT operator >>(CAtlFile &f, CMSITSCAOp &op) -{ - return f >> op.m_iTicks; -} - - -inline HRESULT operator <<(CAtlFile &f, const CMSITSCAOpTypeSingleString &op) -{ - HRESULT hr; - - hr = f << (const CMSITSCAOp &)op; - if (FAILED(hr)) return hr; - - return f << op.m_sValue; -} - - -inline HRESULT operator >>(CAtlFile &f, CMSITSCAOpTypeSingleString &op) -{ - HRESULT hr; - - hr = f >> (CMSITSCAOp &)op; - if (FAILED(hr)) return hr; - - return f >> op.m_sValue; -} - - -inline HRESULT operator <<(CAtlFile &f, const CMSITSCAOpTypeSrcDstString &op) -{ - HRESULT hr; - - hr = f << (const CMSITSCAOp &)op; - if (FAILED(hr)) return hr; - - hr = f << op.m_sValue1; - if (FAILED(hr)) return hr; - - return f << op.m_sValue2; -} - - -inline HRESULT operator >>(CAtlFile &f, CMSITSCAOpTypeSrcDstString &op) -{ - HRESULT hr; - - hr = f >> (CMSITSCAOp &)op; - if (FAILED(hr)) return hr; - - hr = f >> op.m_sValue1; - if (FAILED(hr)) return hr; - - return f >> op.m_sValue2; -} - - -inline HRESULT operator <<(CAtlFile &f, const CMSITSCAOpTypeBoolean &op) -{ - HRESULT hr; - - hr = f << (const CMSITSCAOp &)op; - if (FAILED(hr)) return hr; - - return f << (int)op.m_bValue; -} - - -inline HRESULT operator >>(CAtlFile &f, CMSITSCAOpTypeBoolean &op) -{ - int iValue; - HRESULT hr; - - hr = f >> (CMSITSCAOp &)op; - if (FAILED(hr)) return hr; - - hr = f >> iValue; - if (FAILED(hr)) return hr; - op.m_bValue = iValue ? TRUE : FALSE; - - return S_OK; -} - - -inline HRESULT operator <<(CAtlFile &f, const CMSITSCAOpTaskCreate &op) -{ - HRESULT hr; - POSITION pos; - - hr = f << (const CMSITSCAOpTypeSingleString&)op; if (FAILED(hr)) return hr; - hr = f << op.m_sApplicationName; if (FAILED(hr)) return hr; - hr = f << op.m_sParameters; if (FAILED(hr)) return hr; - hr = f << op.m_sWorkingDirectory; if (FAILED(hr)) return hr; - hr = f << op.m_sAuthor; if (FAILED(hr)) return hr; - hr = f << op.m_sComment; if (FAILED(hr)) return hr; - hr = f << (int)op.m_dwFlags; if (FAILED(hr)) return hr; - hr = f << (int)op.m_dwPriority; if (FAILED(hr)) return hr; - hr = f << op.m_sAccountName; if (FAILED(hr)) return hr; - hr = f << op.m_sPassword; if (FAILED(hr)) return hr; - hr = f << (int)MAKELONG(op.m_wDeadlineMinutes, op.m_wIdleMinutes); if (FAILED(hr)) return hr; - hr = f << (int)op.m_dwMaxRuntimeMS; if (FAILED(hr)) return hr; - hr = f << (int)op.m_lTriggers.GetCount(); if (FAILED(hr)) return hr; - for (pos = op.m_lTriggers.GetHeadPosition(); pos;) { - hr = f << op.m_lTriggers.GetNext(pos); - if (FAILED(hr)) return hr; - } - - return S_OK; -} - - -inline HRESULT operator >>(CAtlFile &f, CMSITSCAOpTaskCreate &op) -{ - HRESULT hr; - DWORD dwValue; - - hr = f >> (CMSITSCAOpTypeSingleString&)op; if (FAILED(hr)) return hr; - hr = f >> op.m_sApplicationName; if (FAILED(hr)) return hr; - hr = f >> op.m_sParameters; if (FAILED(hr)) return hr; - hr = f >> op.m_sWorkingDirectory; if (FAILED(hr)) return hr; - hr = f >> op.m_sAuthor; if (FAILED(hr)) return hr; - hr = f >> op.m_sComment; if (FAILED(hr)) return hr; - hr = f >> (int&)op.m_dwFlags; if (FAILED(hr)) return hr; - hr = f >> (int&)op.m_dwPriority; if (FAILED(hr)) return hr; - hr = f >> op.m_sAccountName; if (FAILED(hr)) return hr; - hr = f >> op.m_sPassword; if (FAILED(hr)) return hr; - hr = f >> (int&)dwValue; if (FAILED(hr)) return hr; op.m_wIdleMinutes = HIWORD(dwValue); op.m_wDeadlineMinutes = LOWORD(dwValue); - hr = f >> (int&)op.m_dwMaxRuntimeMS; if (FAILED(hr)) return hr; - hr = f >> (int&)dwValue; if (FAILED(hr)) return hr; - while (dwValue--) { - TASK_TRIGGER ttData; - hr = f >> ttData; - if (FAILED(hr)) return hr; - op.m_lTriggers.AddTail(ttData); - } - - return S_OK; -} - - -inline HRESULT operator <<(CAtlFile &f, const CMSITSCAOpTaskEnable &op) -{ - HRESULT hr; - - hr = f << (const CMSITSCAOpTypeSingleString&)op; - if (FAILED(hr)) return hr; - - return f << (int)op.m_bEnable; -} - - -inline HRESULT operator >>(CAtlFile &f, CMSITSCAOpTaskEnable &op) -{ - HRESULT hr; - int iTemp; - - hr = f >> (CMSITSCAOpTypeSingleString&)op; - if (FAILED(hr)) return hr; - - hr = f >> iTemp; - if (FAILED(hr)) return hr; - op.m_bEnable = iTemp ? TRUE : FALSE; - - return S_OK; -} - - -inline HRESULT operator <<(CAtlFile &f, const CMSITSCAOpList &list) -{ - POSITION pos; - HRESULT hr; - - hr = f << (const CMSITSCAOp &)list; - if (FAILED(hr)) return hr; - - hr = f << (int)list.GetCount(); - if (FAILED(hr)) return hr; - - for (pos = list.GetHeadPosition(); pos;) { - const CMSITSCAOp *pOp = list.GetNext(pos); - if (dynamic_cast(pOp)) - hr = list.Save(f, pOp); - else if (dynamic_cast(pOp)) - hr = list.Save(f, pOp); - else if (dynamic_cast(pOp)) - hr = list.Save(f, pOp); - else if (dynamic_cast(pOp)) - hr = list.Save(f, pOp); - else if (dynamic_cast(pOp)) - hr = list.Save(f, pOp); - else if (dynamic_cast(pOp)) - hr = list.Save(f, pOp); - else if (dynamic_cast(pOp)) - hr = list.Save(f, pOp); - else if (dynamic_cast(pOp)) - hr = list.Save(f, pOp); - else { - // Unsupported type of operation. - assert(0); - hr = E_UNEXPECTED; - } - - if (FAILED(hr)) return hr; - } - - return S_OK; -} - - -inline HRESULT operator >>(CAtlFile &f, CMSITSCAOpList &list) -{ - HRESULT hr; - DWORD dwCount; - - hr = f >> (CMSITSCAOp &)list; - if (FAILED(hr)) return hr; - - hr = f >> (int&)dwCount; - if (FAILED(hr)) return hr; - - while (dwCount--) { - int iTemp; - - hr = f >> iTemp; - if (FAILED(hr)) return hr; - - switch ((CMSITSCAOpList::OPERATION)iTemp) { - case CMSITSCAOpList::OPERATION_ENABLE_ROLLBACK: - hr = list.LoadAndAddTail(f); - break; - case CMSITSCAOpList::OPERATION_DELETE_FILE: - hr = list.LoadAndAddTail(f); - break; - case CMSITSCAOpList::OPERATION_MOVE_FILE: - hr = list.LoadAndAddTail(f); - break; - case CMSITSCAOpList::OPERATION_CREATE_TASK: - hr = list.LoadAndAddTail(f); - break; - case CMSITSCAOpList::OPERATION_DELETE_TASK: - hr = list.LoadAndAddTail(f); - break; - case CMSITSCAOpList::OPERATION_ENABLE_TASK: - hr = list.LoadAndAddTail(f); - break; - case CMSITSCAOpList::OPERATION_COPY_TASK: - hr = list.LoadAndAddTail(f); - break; - case CMSITSCAOpList::OPERATION_SUBLIST: - hr = list.LoadAndAddTail(f); - break; - default: - // Unsupported type of operation. - assert(0); - hr = E_UNEXPECTED; - } - - if (FAILED(hr)) return hr; - } - - return S_OK; -} - - -//////////////////////////////////////////////////////////////////////////// -// Inline methods -//////////////////////////////////////////////////////////////////////////// - -template inline static HRESULT CMSITSCAOpList::Save(CAtlFile &f, const CMSITSCAOp *p) -{ - assert(p); - HRESULT hr; - const T *pp = dynamic_cast(p); - if (!pp) return E_UNEXPECTED; - - hr = f << (int)ID; - if (FAILED(hr)) return hr; - - return f << *pp; -} - - -template inline HRESULT CMSITSCAOpList::LoadAndAddTail(CAtlFile &f) -{ - HRESULT hr; - - // Create element. - T *p = new T(); - if (!p) return E_OUTOFMEMORY; - - // Load element from file. - hr = f >> *p; - if (FAILED(hr)) { - delete p; - return hr; - } - - // Add element. - AddTail(p); - return S_OK; -} - -#endif // __MSITSCAOP_H__ diff --git a/MSICALib/StdAfx.h b/MSICALib/StdAfx.h index 134ef21..3dda2b7 100644 --- a/MSICALib/StdAfx.h +++ b/MSICALib/StdAfx.h @@ -23,27 +23,20 @@ #define MSITSCA_DLL // This is a DLL #endif #define _ATL_APARTMENT_THREADED -#define _ATL_NO_AUTOMATIC_NAMESPACE -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // Some CString constructors will be explicit #include #include #include -using namespace ATL; - #include "BuildNum.h" #include "MSITSCA.h" -#include "MSITSCAOp.h" + +#include "AMSICA.h" #include #include -#include -#include -#include #include -#include #include #ifdef NDEBUG diff --git a/MSICALib/msm/Makefile b/MSICALib/msm/Makefile index ce1b21f..5406b91 100644 --- a/MSICALib/msm/Makefile +++ b/MSICALib/msm/Makefile @@ -136,12 +136,6 @@ i2 L0 2551 Pri pripravi seznama razvrščenih opravil je prišlo do napake [2]. Obrnite se na svojo tehnično službo. 2552 Pri pisanju v datoteko seznama razporejenih opravil »[2]« je prišlo do napake [3]. Obrnite se na svojo tehnično službo. 2553 Pri nastavljanju parametra »[2]« je prišlo do napake [3]. Obrnite se na svojo tehnično službo. -2554 Pri brisanju datoteke »[2]« je prišlo do napake [3]. Obrnite se na svojo tehnično službo. -2555 Pri premikanju datoteke »[2]« v »[3]« je prišlo do napake [4]. Obrnite se na svojo tehnično službo. -2556 Pri ustvarjanju razporejenega opravila »[2]« je prišlo do napake [3]. Obrnite se na svojo tehnično službo. -2557 Pri brisanju razporejenega opravila »[2]« je prišlo do napake [3]. Obrnite se na svojo tehnično službo. -2558 Pri o(ne)mogočanju razporejenega opravila »[2]« je prišlo do napake [3]. Obrnite se na svojo tehnično službo. -2559 Pri kopiranju razporejenega opravila »[2]« v »[3]« je prišlo do napake [4]. Obrnite se na svojo tehnično službo. 2560 Pri branju iz datoteke seznama razporejenih opravil »[2]« je prišlo do napake [3]. Obrnite se na svojo tehnično službo. <\n" "Language-Team: Amebis, d. o. o., Kamnik \n" @@ -70,8 +70,7 @@ msgstr "SUBLANG_DEFAULT" msgid "Vse pravice pridrĹľane © Amebis, d. o. o., Kamnik, 2012" msgstr "Copyright © Amebis, d. o. o., Kamnik, 2012" -# !!! Lektorirati !!! -#: ..\msm/Sl.DebugU.Win32.Error-2.idtx:14 ..\msm/Sl.DebugU.x64.Error-2.idtx:14 +#: ..\msm/Sl.DebugU.Win32.Error-2.idtx:8 ..\msm/Sl.DebugU.x64.Error-2.idtx:8 msgid "" "Pri branju iz datoteke seznama razporejenih opravil »[2]« je prišlo do " "napake [3]. Obrnite se na svojo tehniÄŤno sluĹľbo." @@ -79,33 +78,6 @@ msgstr "" "Error [3] reading from \"[2]\" scheduled task list file. Please, contact " "your support personnel." -# !!! Lektorirati !!! -#: ..\msm/Sl.DebugU.Win32.Error-2.idtx:8 ..\msm/Sl.DebugU.x64.Error-2.idtx:8 -msgid "" -"Pri brisanju datoteke »[2]« je prišlo do napake [3]. Obrnite se na svojo " -"tehniÄŤno sluĹľbo." -msgstr "" -"Error [3] deleting \"[2]\" file. Please, contact your support personnel." - -# !!! Lektorirati !!! -#: ..\msm/Sl.DebugU.Win32.Error-2.idtx:11 ..\msm/Sl.DebugU.x64.Error-2.idtx:11 -msgid "" -"Pri brisanju razporejenega opravila »[2]« je prišlo do napake [3]. Obrnite " -"se na svojo tehniÄŤno sluĹľbo." -msgstr "" -"Error [3] deleting \"[2]\" scheduled task. Please, contact your support " -"personnel." - -# !!! Lektorirati !!! -#: ..\msm/Sl.DebugU.Win32.Error-2.idtx:13 ..\msm/Sl.DebugU.x64.Error-2.idtx:13 -msgid "" -"Pri kopiranju razporejenega opravila »[2]« v »[3]« je prišlo do napake [4]. " -"Obrnite se na svojo tehniÄŤno sluĹľbo." -msgstr "" -"Error [4] copying \"[2]\" scheduled task to \"[3]\". Please, contact your " -"support personnel." - -# !!! Lektorirati !!! #: ..\msm/Sl.DebugU.Win32.Error-2.idtx:7 ..\msm/Sl.DebugU.x64.Error-2.idtx:7 msgid "" "Pri nastavljanju parametra »[2]« je prišlo do napake [3]. Obrnite se na " @@ -113,16 +85,6 @@ msgid "" msgstr "" "Error [3] setting \"[2]\" parameter. Please, contact your support personnel." -# !!! Lektorirati !!! -#: ..\msm/Sl.DebugU.Win32.Error-2.idtx:12 ..\msm/Sl.DebugU.x64.Error-2.idtx:12 -msgid "" -"Pri o(ne)mogoÄŤanju razporejenega opravila »[2]« je prišlo do napake [3]. " -"Obrnite se na svojo tehniÄŤno sluĹľbo." -msgstr "" -"Error [3] enabling/disabling \"[2]\" scheduled task. Please, contact your " -"support personnel." - -# !!! Lektorirati !!! #: ..\msm/Sl.DebugU.Win32.Error-2.idtx:4 ..\msm/Sl.DebugU.x64.Error-2.idtx:4 msgid "" "Pri odpiranju namestitvenega paketa je prišlo do napake. Obrnite se na svojo " @@ -130,7 +92,6 @@ msgid "" msgstr "" "Error opening installation package. Please, contact your support personnel." -# !!! Lektorirati !!! #: ..\msm/Sl.DebugU.Win32.Error-2.idtx:6 ..\msm/Sl.DebugU.x64.Error-2.idtx:6 msgid "" "Pri pisanju v datoteko seznama razporejenih opravil »[2]« je prišlo do " @@ -139,16 +100,6 @@ msgstr "" "Error [3] writing to \"[2]\" scheduled task list file. Please, contact your " "support personnel." -# !!! Lektorirati !!! -#: ..\msm/Sl.DebugU.Win32.Error-2.idtx:9 ..\msm/Sl.DebugU.x64.Error-2.idtx:9 -msgid "" -"Pri premikanju datoteke »[2]« v »[3]« je prišlo do napake [4]. Obrnite se na " -"svojo tehniÄŤno sluĹľbo." -msgstr "" -"Error [4] moving \"[2]\" file to \"[3]\". Please, contact your support " -"personnel." - -# !!! Lektorirati !!! #: ..\msm/Sl.DebugU.Win32.Error-2.idtx:5 ..\msm/Sl.DebugU.x64.Error-2.idtx:5 msgid "" "Pri pripravi seznama razvrščenih opravil je prišlo do napake [2]. Obrnite se " @@ -157,22 +108,11 @@ msgstr "" "Error [2] creating scheduled task list. Please, contact your support " "personnel." -# !!! Lektorirati !!! -#: ..\msm/Sl.DebugU.Win32.Error-2.idtx:10 ..\msm/Sl.DebugU.x64.Error-2.idtx:10 -msgid "" -"Pri ustvarjanju razporejenega opravila »[2]« je prišlo do napake [3]. " -"Obrnite se na svojo tehniÄŤno sluĹľbo." -msgstr "" -"Error [3] creating \"[2]\" scheduled task. Please, contact your support " -"personnel." - -# !!! Lektorirati !!! #: ..\msm/Sl.DebugU.Win32.ActionText-2.idtx:4 #: ..\msm/Sl.DebugU.x64.ActionText-2.idtx:4 msgid "Razporejeno opravilo: [1]" msgstr "Scheduled task: [1]" -# !!! Lektorirati !!! #: ..\msm/Sl.DebugU.Win32.ActionText-2.idtx:4 #: ..\msm/Sl.DebugU.x64.ActionText-2.idtx:4 msgid "Registracija razporejenih opravil"