From 6c75955bec93f8a68a44a313bed51b0384e14d2a Mon Sep 17 00:00:00 2001 From: Simon Rozman Date: Thu, 13 Mar 2014 10:57:11 +0000 Subject: [PATCH] EvaluateScheduledTasks() => EvaluateSequence() InstallScheduledTasks() => ExecuteSequence() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dodal sem še projekt za MSICACert.dll, ki je trenutno še čista kopija MSICATS.dll. --- MSICALib.cpp | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++ MSICALib.h | 7 +++ 2 files changed, 130 insertions(+) diff --git a/MSICALib.cpp b/MSICALib.cpp index 94e4326..b3ac7be 100644 --- a/MSICALib.cpp +++ b/MSICALib.cpp @@ -181,4 +181,127 @@ CSession::~CSession() m_olCommit.Free(); } + +//////////////////////////////////////////////////////////////////////////// +// Helper functions +//////////////////////////////////////////////////////////////////////////// + +UINT ExecuteSequence(MSIHANDLE hInstall) +{ + UINT uiResult; + HRESULT hr; + BOOL bIsCoInitialized = SUCCEEDED(::CoInitialize(NULL)); + ATL::CAtlString sSequenceFilename; + + uiResult = ::MsiGetProperty(hInstall, _T("CustomActionData"), sSequenceFilename); + if (uiResult == ERROR_SUCCESS) { + MSICA::COpList lstOperations; + BOOL bIsCleanup = ::MsiGetMode(hInstall, MSIRUNMODE_COMMIT) || ::MsiGetMode(hInstall, MSIRUNMODE_ROLLBACK); + + // Load operation sequence. + hr = lstOperations.LoadFromFile(sSequenceFilename); + if (SUCCEEDED(hr)) { + MSICA::CSession session; + + session.m_hInstall = hInstall; + + // In case of commit/rollback, continue sequence on error, to do as much cleanup as possible. + session.m_bContinueOnError = bIsCleanup; + + // Execute the operations. + hr = lstOperations.Execute(&session); + if (!bIsCleanup) { + // Save cleanup scripts of delayed action regardless of action's execution status. + // Rollback action MUST be scheduled in InstallExecuteSequence before this action! Otherwise cleanup won't be performed in case this action execution failed. + LPCTSTR pszExtension = ::PathFindExtension(sSequenceFilename); + ATL::CAtlString sSequenceFilenameCM, sSequenceFilenameRB; + HRESULT hr; + + 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 commit, delete rollback file. After rollback, delete commit file. + session.m_olCommit.AddTail(new MSICA::COpFileDelete( +#ifdef _UNICODE + sSequenceFilenameRB +#else + ATL::CAtlStringW(sSequenceFilenameRB) +#endif + )); + session.m_olRollback.AddTail(new MSICA::COpFileDelete( +#ifdef _UNICODE + sSequenceFilenameCM +#else + ATL::CAtlStringW(sSequenceFilenameCM) +#endif + )); + + // Save commit file first. + hr = session.m_olCommit.SaveToFile(sSequenceFilenameCM); + if (SUCCEEDED(hr)) { + // Save rollback file next. + hr = session.m_olRollback.SaveToFile(sSequenceFilenameRB); + if (SUCCEEDED(hr)) { + uiResult = ERROR_SUCCESS; + } else { + // Saving rollback file failed. + PMSIHANDLE hRecordProg = ::MsiCreateRecord(3); + uiResult = ERROR_INSTALL_SCRIPT_WRITE; + ::MsiRecordSetInteger(hRecordProg, 1, uiResult ); + ::MsiRecordSetString (hRecordProg, 2, sSequenceFilenameRB); + ::MsiRecordSetInteger(hRecordProg, 3, hr ); + ::MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecordProg); + } + } else { + // Saving commit file failed. + PMSIHANDLE hRecordProg = ::MsiCreateRecord(3); + uiResult = ERROR_INSTALL_SCRIPT_WRITE; + ::MsiRecordSetInteger(hRecordProg, 1, uiResult ); + ::MsiRecordSetString (hRecordProg, 2, sSequenceFilenameCM); + ::MsiRecordSetInteger(hRecordProg, 3, hr ); + ::MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecordProg); + } + + if (uiResult != ERROR_SUCCESS) { + // The commit and/or rollback scripts were not written to file successfully. Perform the cleanup immediately. + session.m_bContinueOnError = TRUE; + session.m_bRollbackEnabled = FALSE; + session.m_olRollback.Execute(&session); + ::DeleteFile(sSequenceFilenameRB); + } + } else { + // No cleanup after cleanup support. + uiResult = ERROR_SUCCESS; + } + + if (FAILED(hr)) { + // Execution of the action failed. + uiResult = HRESULT_CODE(hr); + } + + ::DeleteFile(sSequenceFilename); + } else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) && bIsCleanup) { + // Sequence file not found and this is rollback/commit action. Either of the following scenarios are possible: + // - The delayed action failed to save the rollback/commit file. The delayed action performed cleanup itself. No further action is required. + // - Somebody removed the rollback/commit file between delayed action and rollback/commit action. No further action is possible. + uiResult = ERROR_SUCCESS; + } else { + // Sequence loading failed. Probably, LOCAL SYSTEM doesn't have read access to user's temp directory. + PMSIHANDLE hRecordProg = ::MsiCreateRecord(3); + uiResult = ERROR_INSTALL_SCRIPT_READ; + ::MsiRecordSetInteger(hRecordProg, 1, uiResult ); + ::MsiRecordSetString (hRecordProg, 2, sSequenceFilename); + ::MsiRecordSetInteger(hRecordProg, 3, hr ); + ::MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecordProg); + } + + lstOperations.Free(); + } else { + // Couldn't get CustomActionData property. uiResult has the error code. + } + + if (bIsCoInitialized) ::CoUninitialize(); + return uiResult; +} + } // namespace MSICA diff --git a/MSICALib.h b/MSICALib.h index be87731..8c201d2 100644 --- a/MSICALib.h +++ b/MSICALib.h @@ -516,6 +516,13 @@ public: COpList m_olCommit; // Commit operation list }; + +//////////////////////////////////////////////////////////////////////////// +// Helper functions +//////////////////////////////////////////////////////////////////////////// + +UINT ExecuteSequence(MSIHANDLE hInstall); + } // namespace MSICA