From 32ef7ddcb293b0166b4c97ab9c883822318e3e54 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 --- MSICALib.h | 50 +++++++++++++++++++++++++++++++++++++---- OpSvc.cpp | 65 +++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 103 insertions(+), 12 deletions(-) diff --git a/MSICALib.h b/MSICALib.h index b8741a5..0679a8a 100644 --- a/MSICALib.h +++ b/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/OpSvc.cpp b/OpSvc.cpp index ef4bf06..c5115b5 100644 --- a/OpSvc.cpp +++ b/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) {