From ddde7488fa976b6a4a1cdfc546c22b58a3b2c669 Mon Sep 17 00:00:00 2001 From: Simon Rozman Date: Fri, 21 Mar 2014 13:35:01 +0000 Subject: [PATCH] =?UTF-8?q?Namestitev=20sem=20dopolnil=20=C5=A1e=20z=20mo?= =?UTF-8?q?=C5=BEnostjo=20zagona/zaustavitve=20poljubnega=20sistemskega=20?= =?UTF-8?q?servisa=20(v=20tej=20fazi=20brez=20odvisnih=20servisov).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MSICA/MSIBuild/Makefile | 5 ++-- MSICA/MSICA.cpp | 40 ++++++++++++++++++++----- MSICALib/MSICALib.h | 50 ++++++++++++++++++++++++++++--- MSICALib/OpSvc.cpp | 65 ++++++++++++++++++++++++++++++++++++----- 4 files changed, 139 insertions(+), 21 deletions(-) diff --git a/MSICA/MSIBuild/Makefile b/MSICA/MSIBuild/Makefile index 8bbaaca..865a4f7 100644 --- a/MSICA/MSIBuild/Makefile +++ b/MSICA/MSIBuild/Makefile @@ -40,6 +40,7 @@ ScheduledTask Component_ N Component 1 Identifier Component the task is part ServiceConfigure ServiceConfigure N Identifier Primary key, non-localized token. ServiceConfigure Name N Formatted Name of a service. /, \, comma and space are invalid ServiceConfigure StartType N DoubleInteger -1;0;1;2;3;4 Start type: -1=don't change, 0=boot, 1=system, 2=auto, 3=demand, 4=disabled +ServiceConfigure Control N Integer 0;2;3;4;5;7 Bitwise combination of: 0=no action, 1=wait to finish, 2=start, 4=stop ServiceConfigure Condition Y Condition Optional expression which skips the service configuration if evaluates to expFalse. If the expression syntax is invalid, the engine will terminate, returning iesBadActionData. ServiceConfigure Sequence Y Number that determines the sort order in which the configurations are to be executed. TaskTrigger Trigger N Identifier Primary key, non-localized token. @@ -198,8 +199,8 @@ All :: "$(LANG).$(PLAT).$(CFG).ServiceConfigure-1.idt" "$(LANG).$(PLAT).$(CFG).ServiceConfigure-1.idt" : "Makefile" "..\..\..\include\MSIBuildCfg.mak" -if exist $@ del /f /q $@ move /y << $@ > NUL -ServiceConfigure Name StartType Condition Sequence -s$(MSIBUILD_LENGTH_ID) l255 i4 S255 I2 +ServiceConfigure Name StartType Control Condition Sequence +s$(MSIBUILD_LENGTH_ID) l255 i4 i2 S255 I2 ServiceConfigure ServiceConfigure <= 0) { + if (iValue >= 0) { // Set service start type. - olExecute.AddTail(new MSICA::COpSvcSetStart(sValue, iStartType, MSICA_SVC_SET_START_TICK_SIZE)); + olExecute.AddTail(new MSICA::COpSvcSetStart(sValue, iValue, MSICA_SVC_SET_START_TICK_SIZE)); // The amount of tick space to add to progress indicator. ::MsiRecordSetInteger(hRecordProg, 1, 3 ); ::MsiRecordSetInteger(hRecordProg, 2, MSICA_SVC_SET_START_TICK_SIZE); if (::MsiProcessMessage(hInstall, INSTALLMESSAGE_PROGRESS, hRecordProg) == IDCANCEL) { uiResult = ERROR_INSTALL_USEREXIT; break; } } + + // Read service control. + iValue = ::MsiRecordGetInteger(hRecord, 3); + if (iValue == MSI_NULL_INTEGER) { + uiResult = ERROR_INVALID_FIELD; + break; + } + if ((iValue & 4) != 0) { + // Stop service. + olExecute.AddTail(new MSICA::COpSvcStop(sValue, (iValue & 1) ? TRUE : FALSE, MSICA_SVC_STOP_TICK_SIZE)); + + // The amount of tick space to add to progress indicator. + ::MsiRecordSetInteger(hRecordProg, 1, 3 ); + ::MsiRecordSetInteger(hRecordProg, 2, MSICA_SVC_STOP_TICK_SIZE); + if (::MsiProcessMessage(hInstall, INSTALLMESSAGE_PROGRESS, hRecordProg) == IDCANCEL) { uiResult = ERROR_INSTALL_USEREXIT; break; } + } else if ((iValue & 2) != 0) { + // Start service. + olExecute.AddTail(new MSICA::COpSvcStart(sValue, (iValue & 1) ? TRUE : FALSE, MSICA_SVC_START_TICK_SIZE)); + + // The amount of tick space to add to progress indicator. + ::MsiRecordSetInteger(hRecordProg, 1, 3 ); + ::MsiRecordSetInteger(hRecordProg, 2, MSICA_SVC_START_TICK_SIZE); + if (::MsiProcessMessage(hInstall, INSTALLMESSAGE_PROGRESS, hRecordProg) == IDCANCEL) { uiResult = ERROR_INSTALL_USEREXIT; break; } + } } ::MsiViewClose(hViewSC); diff --git a/MSICALib/MSICALib.h b/MSICALib/MSICALib.h index b8741a5..0679a8a 100644 --- a/MSICALib/MSICALib.h +++ b/MSICALib/MSICALib.h @@ -476,14 +476,33 @@ protected: }; +//////////////////////////////////////////////////////////////////////////// +// COpSvcControl +//////////////////////////////////////////////////////////////////////////// + +class COpSvcControl : public COpTypeSingleString +{ +public: + COpSvcControl(LPCWSTR pszService = L"", BOOL bWait = FALSE, int iTicks = 0); + + static DWORD WaitForState(CSession *pSession, SC_HANDLE hService, DWORD dwPendingState, DWORD dwFinalState); + + friend inline HRESULT operator <<(ATL::CAtlFile &f, const COpSvcControl &op); + friend inline HRESULT operator >>(ATL::CAtlFile &f, COpSvcControl &op); + +protected: + BOOL m_bWait; +}; + + //////////////////////////////////////////////////////////////////////////// // COpSvcStart //////////////////////////////////////////////////////////////////////////// -class COpSvcStart : public COpTypeSingleString +class COpSvcStart : public COpSvcControl { public: - COpSvcStart(LPCWSTR pszService = L"", int iTicks = 0); + COpSvcStart(LPCWSTR pszService = L"", BOOL bWait = FALSE, int iTicks = 0); virtual HRESULT Execute(CSession *pSession); }; @@ -492,10 +511,10 @@ public: // COpSvcStop //////////////////////////////////////////////////////////////////////////// -class COpSvcStop : public COpTypeSingleString +class COpSvcStop : public COpSvcControl { public: - COpSvcStop(LPCWSTR pszService = L"", int iTicks = 0); + COpSvcStop(LPCWSTR pszService = L"", BOOL bWait = FALSE, int iTicks = 0); virtual HRESULT Execute(CSession *pSession); }; @@ -1438,6 +1457,29 @@ inline HRESULT operator >>(ATL::CAtlFile &f, COpSvcSetStart &op) } +inline HRESULT operator <<(ATL::CAtlFile &f, const COpSvcControl &op) +{ + HRESULT hr; + + hr = f << (const COpTypeSingleString&)op; if (FAILED(hr)) return hr; + hr = f << (int)(op.m_bWait); if (FAILED(hr)) return hr; + + return S_OK; +} + + +inline HRESULT operator >>(ATL::CAtlFile &f, COpSvcControl &op) +{ + HRESULT hr; + int iValue; + + hr = f >> (COpTypeSingleString&)op; if (FAILED(hr)) return hr; + hr = f >> iValue; if (FAILED(hr)) return hr; op.m_bWait = iValue ? TRUE : FALSE; + + return S_OK; +} + + inline HRESULT operator <<(ATL::CAtlFile &f, const COpList &list) { POSITION pos; diff --git a/MSICALib/OpSvc.cpp b/MSICALib/OpSvc.cpp index ef4bf06..c5115b5 100644 --- a/MSICALib/OpSvc.cpp +++ b/MSICALib/OpSvc.cpp @@ -76,11 +76,60 @@ HRESULT COpSvcSetStart::Execute(CSession *pSession) } +//////////////////////////////////////////////////////////////////////////// +// COpSvcControl +//////////////////////////////////////////////////////////////////////////// + +COpSvcControl::COpSvcControl(LPCWSTR pszService, BOOL bWait, int iTicks) : + COpTypeSingleString(pszService, iTicks), + m_bWait(bWait) +{ +} + + +DWORD COpSvcControl::WaitForState(CSession *pSession, SC_HANDLE hService, DWORD dwPendingState, DWORD dwFinalState) +{ + PMSIHANDLE hRecordProg = ::MsiCreateRecord(3); + + // Prepare hRecordProg for progress messages. + ::MsiRecordSetInteger(hRecordProg, 1, 2); + ::MsiRecordSetInteger(hRecordProg, 3, 0); + + // Wait for the service to start. + for (;;) { + SERVICE_STATUS_PROCESS ssp; + DWORD dwSize; + + // Check service status. + if (::QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, sizeof(SERVICE_STATUS_PROCESS), &dwSize)) { + if (ssp.dwCurrentState == dwPendingState) { + // Service is pending. Wait some more ... + ::Sleep(ssp.dwWaitHint < 1000 ? ssp.dwWaitHint : 1000); + } else if (ssp.dwCurrentState == dwFinalState) { + // Service is in expected state. + return NO_ERROR; + } else { + // Service is in unexpected state. + return ERROR_ASSERTION_FAILURE; + } + } else { + // Service query failed. + return ::GetLastError(); + } + + // Check if user cancelled installation. + ::MsiRecordSetInteger(hRecordProg, 2, 0); + if (::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_PROGRESS, hRecordProg) == IDCANCEL) + return ERROR_INSTALL_USEREXIT; + } +} + + //////////////////////////////////////////////////////////////////////////// // COpSvcStart //////////////////////////////////////////////////////////////////////////// -COpSvcStart::COpSvcStart(LPCWSTR pszService, int iTicks) : COpTypeSingleString(pszService, iTicks) +COpSvcStart::COpSvcStart(LPCWSTR pszService, BOOL bWait, int iTicks) : COpSvcControl(pszService, bWait, iTicks) { } @@ -96,15 +145,15 @@ HRESULT COpSvcStart::Execute(CSession *pSession) SC_HANDLE hService; // Open the specified service. - hService = ::OpenServiceW(hSCM, m_sValue, SERVICE_START); + hService = ::OpenServiceW(hSCM, m_sValue, SERVICE_START | (m_bWait ? SERVICE_QUERY_STATUS : 0)); if (hService) { // Start the service. if (::StartService(hService, 0, NULL)) { - if (pSession->m_bRollbackEnabled) { + dwError = m_bWait ? WaitForState(pSession, hService, SERVICE_START_PENDING, SERVICE_RUNNING) : NO_ERROR; + if (dwError == NO_ERROR && pSession->m_bRollbackEnabled) { // Order rollback action to stop the service. pSession->m_olRollback.AddHead(new COpSvcStop(m_sValue)); } - dwError = NO_ERROR; } else { dwError = ::GetLastError(); if (dwError == ERROR_SERVICE_ALREADY_RUNNING) { @@ -134,7 +183,7 @@ HRESULT COpSvcStart::Execute(CSession *pSession) // COpSvcStop //////////////////////////////////////////////////////////////////////////// -COpSvcStop::COpSvcStop(LPCWSTR pszService, int iTicks) : COpTypeSingleString(pszService, iTicks) +COpSvcStop::COpSvcStop(LPCWSTR pszService, BOOL bWait, int iTicks) : COpSvcControl(pszService, bWait, iTicks) { } @@ -150,16 +199,16 @@ HRESULT COpSvcStop::Execute(CSession *pSession) SC_HANDLE hService; // Open the specified service. - hService = ::OpenServiceW(hSCM, m_sValue, SERVICE_STOP); + hService = ::OpenServiceW(hSCM, m_sValue, SERVICE_STOP | (m_bWait ? SERVICE_QUERY_STATUS : 0)); if (hService) { SERVICE_STATUS ss; // Stop the service. if (::ControlService(hService, SERVICE_CONTROL_STOP, &ss)) { - if (pSession->m_bRollbackEnabled) { + dwError = m_bWait ? WaitForState(pSession, hService, SERVICE_STOP_PENDING, SERVICE_STOPPED) : NO_ERROR; + if (dwError == NO_ERROR && pSession->m_bRollbackEnabled) { // Order rollback action to start the service. pSession->m_olRollback.AddHead(new COpSvcStart(m_sValue)); } - dwError = NO_ERROR; } else { dwError = ::GetLastError(); if (dwError == ERROR_SERVICE_NOT_ACTIVE) {