diff --git a/MSICALib.cpp b/MSICALib.cpp index b3ac7be..56b338c 100644 --- a/MSICALib.cpp +++ b/MSICALib.cpp @@ -186,6 +186,68 @@ CSession::~CSession() // Helper functions //////////////////////////////////////////////////////////////////////////// +UINT SaveSequence(MSIHANDLE hInstall, LPCTSTR szActionExecute, LPCTSTR szActionCommit, LPCTSTR szActionRollback, const COpList &olExecute) +{ + HRESULT hr; + UINT uiResult; + ATL::CAtlString sSequenceFilename; + ATL::CAtlFile fSequence; + PMSIHANDLE hRecordProg = ::MsiCreateRecord(3); + + // Prepare our own sequence script file. + // The InstallCertificates is a deferred custom action, thus all this information will be unavailable to it. + // Therefore save all required info to file now. + { + LPTSTR szBuffer = sSequenceFilename.GetBuffer(MAX_PATH); + ::GetTempPath(MAX_PATH, szBuffer); + ::GetTempFileName(szBuffer, _T("TS"), 0, szBuffer); + sSequenceFilename.ReleaseBuffer(); + } + // Save execute sequence to file. + hr = olExecute.SaveToFile(sSequenceFilename); + if (SUCCEEDED(hr)) { + // Store sequence script file names to properties for deferred custiom actions. + uiResult = ::MsiSetProperty(hInstall, szActionExecute, sSequenceFilename); + if (uiResult == ERROR_SUCCESS) { + LPCTSTR pszExtension = ::PathFindExtension(sSequenceFilename); + ATL::CAtlString sSequenceFilename2; + + sSequenceFilename2.Format(_T("%.*ls-rb%ls"), pszExtension - (LPCTSTR)sSequenceFilename, (LPCTSTR)sSequenceFilename, pszExtension); + uiResult = ::MsiSetProperty(hInstall, szActionRollback, sSequenceFilename2); + if (uiResult == ERROR_SUCCESS) { + sSequenceFilename2.Format(_T("%.*ls-cm%ls"), pszExtension - (LPCTSTR)sSequenceFilename, (LPCTSTR)sSequenceFilename, pszExtension); + uiResult = ::MsiSetProperty(hInstall, szActionCommit, sSequenceFilename2); + if (uiResult != ERROR_SUCCESS) { + ::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_PROPERTY_SET); + ::MsiRecordSetString (hRecordProg, 2, szActionCommit ); + ::MsiRecordSetInteger(hRecordProg, 3, uiResult ); + ::MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecordProg); + } + } else { + ::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_PROPERTY_SET); + ::MsiRecordSetString (hRecordProg, 2, szActionRollback ); + ::MsiRecordSetInteger(hRecordProg, 3, uiResult ); + ::MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecordProg); + } + } else { + ::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_PROPERTY_SET); + ::MsiRecordSetString (hRecordProg, 2, szActionExecute ); + ::MsiRecordSetInteger(hRecordProg, 3, uiResult ); + ::MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecordProg); + } + if (uiResult != ERROR_SUCCESS) ::DeleteFile(sSequenceFilename); + } else { + uiResult = ERROR_INSTALL_SCRIPT_WRITE; + ::MsiRecordSetInteger(hRecordProg, 1, uiResult ); + ::MsiRecordSetString (hRecordProg, 2, sSequenceFilename); + ::MsiRecordSetInteger(hRecordProg, 3, hr ); + ::MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecordProg); + } + + return uiResult; +} + + UINT ExecuteSequence(MSIHANDLE hInstall) { UINT uiResult; diff --git a/MSICALib.h b/MSICALib.h index 8c201d2..5de0491 100644 --- a/MSICALib.h +++ b/MSICALib.h @@ -521,6 +521,7 @@ public: // Helper functions //////////////////////////////////////////////////////////////////////////// +UINT SaveSequence(MSIHANDLE hInstall, LPCTSTR szActionExecute, LPCTSTR szActionCommit, LPCTSTR szActionRollback, const COpList &olExecute); UINT ExecuteSequence(MSIHANDLE hInstall); } // namespace MSICA @@ -537,7 +538,7 @@ UINT ExecuteSequence(MSIHANDLE hInstall); //////////////////////////////////////////////////////////////////// -// Inline Functions +// Inline helper functions //////////////////////////////////////////////////////////////////// inline UINT MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, ATL::CAtlStringA &sValue) @@ -640,6 +641,23 @@ inline UINT MsiRecordGetStringW(MSIHANDLE hRecord, unsigned int iField, ATL::CAt } +inline UINT MsiRecordGetStream(MSIHANDLE hRecord, unsigned int iField, ATL::CAtlArray &binData) +{ + DWORD dwSize = 0; + UINT uiResult; + + // Query the actual data length first. + uiResult = ::MsiRecordReadStream(hRecord, iField, NULL, &dwSize); + if (uiResult == ERROR_SUCCESS) { + if (!binData.SetCount(dwSize)) return ERROR_OUTOFMEMORY; + return ::MsiRecordReadStream(hRecord, iField, (char*)binData.GetData(), &dwSize); + } else { + // Return error code. + return uiResult; + } +} + + inline UINT MsiFormatRecordA(MSIHANDLE hInstall, MSIHANDLE hRecord, ATL::CAtlStringA &sValue) { DWORD dwSize = 0;