From 197240bcd94c8fec0200350aaf5a836e96934a0e Mon Sep 17 00:00:00 2001 From: Simon Rozman Date: Mon, 17 Mar 2014 13:06:12 +0000 Subject: [PATCH] Shranjevanje skript sem preselil v skupno funkcijo MSICA::SaveSequence(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Popravil sem napako pri preverjanju statusa, zaradi katere smo tudi v primeru napak med evaluacijo razporejenih opravil vseeno zapisali namestitvena skripta in vrnili uspešen rezultat. Dodal sem funkcijo MsiRecordGetStream() za branje binarnih podatkov iz tabel MSI. Usposobil sem nameščanje certifikatov. --- MSICACert/MSICACert.cpp | 164 ++++++++++++++++------------------------ MSICALib/MSICALib.cpp | 62 +++++++++++++++ MSICALib/MSICALib.h | 20 ++++- MSICATS/MSICATS.cpp | 57 +------------- 4 files changed, 150 insertions(+), 153 deletions(-) diff --git a/MSICACert/MSICACert.cpp b/MSICACert/MSICACert.cpp index 8bd316d..42ef48a 100644 --- a/MSICACert/MSICACert.cpp +++ b/MSICACert/MSICACert.cpp @@ -5,7 +5,7 @@ // Local constants //////////////////////////////////////////////////////////////////////////// -#define MSICACERT_TASK_TICK_SIZE (16*1024) +#define MSICACERT_CERT_TICK_SIZE (16*1024) //////////////////////////////////////////////////////////////////////////// @@ -27,8 +27,9 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpRes UINT MSICACERT_API EvaluateSequence(MSIHANDLE hInstall) { + //::MessageBox(NULL, _T(__FUNCTION__), _T("MSICACert"), MB_OK); + UINT uiResult; - HRESULT hr; BOOL bIsCoInitialized = SUCCEEDED(::CoInitialize(NULL)); MSICA::COpList olExecute; BOOL bRollbackEnabled; @@ -47,34 +48,37 @@ UINT MSICACERT_API EvaluateSequence(MSIHANDLE hInstall) // Open MSI database. hDatabase = ::MsiGetActiveDatabase(hInstall); if (hDatabase) { - // Check if ScheduledTask table exists. If it doesn't exist, there's nothing to do. - MSICONDITION condition = ::MsiDatabaseIsTablePersistent(hDatabase, _T("ScheduledTask")); + // Check if Certificate table exists. If it doesn't exist, there's nothing to do. + MSICONDITION condition = ::MsiDatabaseIsTablePersistent(hDatabase, _T("Certificate")); if (condition == MSICONDITION_FALSE || condition == MSICONDITION_TRUE) { - PMSIHANDLE hViewST; + PMSIHANDLE hViewCert; - // Prepare a query to get a list/view of tasks. - uiResult = ::MsiDatabaseOpenView(hDatabase, _T("SELECT Task,DisplayName,Application,Parameters,Directory_,Flags,Priority,User,Password,Author,Description,IdleMin,IdleDeadline,MaxRuntime,Condition,Component_ FROM ScheduledTask"), &hViewST); + // Prepare a query to get a list/view of certificates. + uiResult = ::MsiDatabaseOpenView(hDatabase, _T("SELECT Binary_,Store,Flags,Encoding,Condition,Component_ FROM Certificate"), &hViewCert); if (uiResult == ERROR_SUCCESS) { // Execute query! - uiResult = ::MsiViewExecute(hViewST, NULL); + uiResult = ::MsiViewExecute(hViewCert, NULL); if (uiResult == ERROR_SUCCESS) { //ATL::CAtlString sComponent; - ATL::CAtlStringW sDisplayName; + ATL::CAtlStringW sStore; + int iFlags, iEncoding; + ATL::CAtlArray binCert; for (;;) { PMSIHANDLE hRecord; INSTALLSTATE iInstalled, iAction; + PMSIHANDLE hViewBinary; // Fetch one record from the view. - uiResult = ::MsiViewFetch(hViewST, &hRecord); + uiResult = ::MsiViewFetch(hViewCert, &hRecord); if (uiResult == ERROR_NO_MORE_ITEMS) { uiResult = ERROR_SUCCESS; break; } else if (uiResult != ERROR_SUCCESS) break; - // Read and evaluate task's condition. - uiResult = ::MsiRecordGetString(hRecord, 15, sValue); + // Read and evaluate certificate's condition. + uiResult = ::MsiRecordGetString(hRecord, 5, sValue); if (uiResult != ERROR_SUCCESS) break; condition = ::MsiEvaluateCondition(hInstall, sValue); if (condition == MSICONDITION_FALSE) @@ -84,106 +88,68 @@ UINT MSICACERT_API EvaluateSequence(MSIHANDLE hInstall) break; } - // Read task's Component ID. - uiResult = ::MsiRecordGetString(hRecord, 16, sValue); + // Perform another query to get certificate's binary data. + uiResult = ::MsiDatabaseOpenView(hDatabase, _T("SELECT Data FROM Binary WHERE Name=?"), &hViewBinary); + if (uiResult != ERROR_SUCCESS) break; + + // Execute query! + uiResult = ::MsiViewExecute(hViewBinary, hRecord); + if (uiResult == ERROR_SUCCESS) { + PMSIHANDLE hRecord; + + // Fetch one record from the view. + uiResult = ::MsiViewFetch(hViewBinary, &hRecord); + if (uiResult == ERROR_SUCCESS) + uiResult = ::MsiRecordGetStream(hRecord, 1, binCert); + ::MsiViewClose(hViewBinary); + if (uiResult != ERROR_SUCCESS) break; + } else + break; + + // Read certificate's store. + uiResult = ::MsiRecordGetString(hRecord, 2, sStore); + if (uiResult != ERROR_SUCCESS) break; + + // Read certificate's flags. + iFlags = ::MsiRecordGetInteger(hRecord, 3); + if (iFlags == MSI_NULL_INTEGER) { + uiResult = ERROR_INVALID_FIELD; + break; + } + + // Read certificate's encoding. + iEncoding = ::MsiRecordGetInteger(hRecord, 4); + if (iEncoding == MSI_NULL_INTEGER) { + uiResult = ERROR_INVALID_FIELD; + break; + } + + // Read certificate's Component ID. + uiResult = ::MsiRecordGetString(hRecord, 6, sValue); if (uiResult != ERROR_SUCCESS) break; // Get the component state. uiResult = ::MsiGetComponentState(hInstall, sValue, &iInstalled, &iAction); if (uiResult != ERROR_SUCCESS) break; - // Get task's DisplayName. - uiResult = ::MsiRecordFormatStringW(hInstall, hRecord, 2, sDisplayName); - if (iAction >= INSTALLSTATE_LOCAL) { - // Component is or should be installed. Create the task. - PMSIHANDLE hViewTT; - MSICA::COpTaskCreate *opCreateTask = new MSICA::COpTaskCreate(sDisplayName, MSICACERT_TASK_TICK_SIZE); - - // Populate the operation with task's data. - uiResult = opCreateTask->SetFromRecord(hInstall, hRecord); - if (uiResult != ERROR_SUCCESS) break; - - // Perform another query to get task's triggers. - uiResult = ::MsiDatabaseOpenView(hDatabase, _T("SELECT Trigger,BeginDate,EndDate,StartTime,StartTimeRand,MinutesDuration,MinutesInterval,Flags,Type,DaysInterval,WeeksInterval,DaysOfTheWeek,DaysOfMonth,WeekOfMonth,MonthsOfYear FROM TaskTrigger WHERE Task_=?"), &hViewTT); - if (uiResult != ERROR_SUCCESS) break; - - // Execute query! - uiResult = ::MsiViewExecute(hViewTT, hRecord); - if (uiResult == ERROR_SUCCESS) { - // Populate trigger list. - uiResult = opCreateTask->SetTriggersFromView(hViewTT); - ::MsiViewClose(hViewTT); - if (uiResult != ERROR_SUCCESS) break; - } else - break; - - olExecute.AddTail(opCreateTask); + // Component is or should be installed. Install the certificate. + olExecute.AddTail(new MSICA::COpCertInstall(binCert.GetData(), binCert.GetCount(), sStore, iEncoding, iFlags, MSICACERT_CERT_TICK_SIZE)); } else if (iAction >= INSTALLSTATE_REMOVED) { - // Component is installed, but should be degraded to advertised/removed. Delete the task. - olExecute.AddTail(new MSICA::COpTaskDelete(sDisplayName, MSICACERT_TASK_TICK_SIZE)); + // Component is installed, but should be degraded to advertised/removed. Delete the certificate. + olExecute.AddTail(new MSICA::COpCertRemove(binCert.GetData(), binCert.GetCount(), sStore, iEncoding, iFlags, MSICACERT_CERT_TICK_SIZE)); } - // The amount of tick space to add for each task to progress indicator. + // The amount of tick space to add for each certificate to progress indicator. ::MsiRecordSetInteger(hRecordProg, 1, 3 ); - ::MsiRecordSetInteger(hRecordProg, 2, MSICACERT_TASK_TICK_SIZE); + ::MsiRecordSetInteger(hRecordProg, 2, MSICACERT_CERT_TICK_SIZE); if (::MsiProcessMessage(hInstall, INSTALLMESSAGE_PROGRESS, hRecordProg) == IDCANCEL) { uiResult = ERROR_INSTALL_USEREXIT; break; } } - ::MsiViewClose(hViewST); + ::MsiViewClose(hViewCert); - if (SUCCEEDED(uiResult)) { - ATL::CAtlString sSequenceFilename; - ATL::CAtlFile fSequence; - - // 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, _T("InstallCertificates"), 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, _T("RollbackCertificates"), sSequenceFilename2); - if (uiResult == ERROR_SUCCESS) { - sSequenceFilename2.Format(_T("%.*ls-cm%ls"), pszExtension - (LPCTSTR)sSequenceFilename, (LPCTSTR)sSequenceFilename, pszExtension); - uiResult = ::MsiSetProperty(hInstall, _T("CommitCertificates"), sSequenceFilename2); - if (uiResult != ERROR_SUCCESS) { - ::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_PROPERTY_SET); - ::MsiRecordSetString (hRecordProg, 2, _T("CommitCertificates")); - ::MsiRecordSetInteger(hRecordProg, 3, uiResult ); - ::MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecordProg); - } - } else { - ::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_PROPERTY_SET ); - ::MsiRecordSetString (hRecordProg, 2, _T("RollbackCertificates")); - ::MsiRecordSetInteger(hRecordProg, 3, uiResult ); - ::MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecordProg); - } - } else { - ::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_PROPERTY_SET ); - ::MsiRecordSetString (hRecordProg, 2, _T("InstallCertificates")); - ::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); - } + if (uiResult == ERROR_SUCCESS) { + // Save the sequences. + uiResult = MSICA::SaveSequence(hInstall, _T("InstallCertificates"), _T("CommitCertificates"), _T("RollbackCertificates"), olExecute); } else if (uiResult != ERROR_INSTALL_USEREXIT) { ::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_OPLIST_CREATE); ::MsiRecordSetInteger(hRecordProg, 2, uiResult ); @@ -212,5 +178,7 @@ UINT MSICACERT_API EvaluateSequence(MSIHANDLE hInstall) UINT MSICACERT_API ExecuteSequence(MSIHANDLE hInstall) { + //::MessageBox(NULL, _T(__FUNCTION__), _T("MSICACert"), MB_OK); + return MSICA::ExecuteSequence(hInstall); } diff --git a/MSICALib/MSICALib.cpp b/MSICALib/MSICALib.cpp index b3ac7be..56b338c 100644 --- a/MSICALib/MSICALib.cpp +++ b/MSICALib/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/MSICALib.h b/MSICALib/MSICALib.h index 8c201d2..5de0491 100644 --- a/MSICALib/MSICALib.h +++ b/MSICALib/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; diff --git a/MSICATS/MSICATS.cpp b/MSICATS/MSICATS.cpp index ea08602..707a878 100644 --- a/MSICATS/MSICATS.cpp +++ b/MSICATS/MSICATS.cpp @@ -28,7 +28,6 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpRes UINT MSICATS_API EvaluateSequence(MSIHANDLE hInstall) { UINT uiResult; - HRESULT hr; BOOL bIsCoInitialized = SUCCEEDED(::CoInitialize(NULL)); MSICA::COpList olExecute; BOOL bRollbackEnabled; @@ -131,59 +130,9 @@ UINT MSICATS_API EvaluateSequence(MSIHANDLE hInstall) } ::MsiViewClose(hViewST); - if (SUCCEEDED(uiResult)) { - 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. - // 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, _T("InstallScheduledTasks"), 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, _T("RollbackScheduledTasks"), sSequenceFilename2); - if (uiResult == ERROR_SUCCESS) { - sSequenceFilename2.Format(_T("%.*ls-cm%ls"), pszExtension - (LPCTSTR)sSequenceFilename, (LPCTSTR)sSequenceFilename, pszExtension); - uiResult = ::MsiSetProperty(hInstall, _T("CommitScheduledTasks"), sSequenceFilename2); - if (uiResult != ERROR_SUCCESS) { - ::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_PROPERTY_SET); - ::MsiRecordSetString (hRecordProg, 2, _T("CommitScheduledTasks")); - ::MsiRecordSetInteger(hRecordProg, 3, uiResult ); - ::MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecordProg); - } - } else { - ::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_PROPERTY_SET ); - ::MsiRecordSetString (hRecordProg, 2, _T("RollbackScheduledTasks")); - ::MsiRecordSetInteger(hRecordProg, 3, uiResult ); - ::MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecordProg); - } - } else { - ::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_PROPERTY_SET ); - ::MsiRecordSetString (hRecordProg, 2, _T("InstallScheduledTasks")); - ::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); - } + if (uiResult == ERROR_SUCCESS) { + // Save the sequences. + uiResult = MSICA::SaveSequence(hInstall, _T("InstallScheduledTasks"), _T("CommitScheduledTasks"), _T("RollbackScheduledTasks"), olExecute); } else if (uiResult != ERROR_INSTALL_USEREXIT) { ::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_OPLIST_CREATE); ::MsiRecordSetInteger(hRecordProg, 2, uiResult );