Namestitev sem dopolnil še z možnostjo zagona/zaustavitve poljubnega sistemskega servisa (v tej fazi brez odvisnih servisov).
This commit is contained in:
parent
ed18da4ebb
commit
ddde7488fa
@ -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 ServiceConfigure N Identifier Primary key, non-localized token.
|
||||||
ServiceConfigure Name N Formatted Name of a service. /, \, comma and space are invalid
|
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 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 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.
|
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.
|
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"
|
"$(LANG).$(PLAT).$(CFG).ServiceConfigure-1.idt" : "Makefile" "..\..\..\include\MSIBuildCfg.mak"
|
||||||
-if exist $@ del /f /q $@
|
-if exist $@ del /f /q $@
|
||||||
move /y << $@ > NUL
|
move /y << $@ > NUL
|
||||||
ServiceConfigure Name StartType Condition Sequence
|
ServiceConfigure Name StartType Control Condition Sequence
|
||||||
s$(MSIBUILD_LENGTH_ID) l255 i4 S255 I2
|
s$(MSIBUILD_LENGTH_ID) l255 i4 i2 S255 I2
|
||||||
ServiceConfigure ServiceConfigure
|
ServiceConfigure ServiceConfigure
|
||||||
<<NOKEEP
|
<<NOKEEP
|
||||||
|
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#define MSICA_CERT_TICK_SIZE (4*1024)
|
#define MSICA_CERT_TICK_SIZE (4*1024)
|
||||||
#define MSICA_SVC_SET_START_TICK_SIZE (1*1024)
|
#define MSICA_SVC_SET_START_TICK_SIZE (1*1024)
|
||||||
|
#define MSICA_SVC_START_TICK_SIZE (1*1024)
|
||||||
|
#define MSICA_SVC_STOP_TICK_SIZE (1*1024)
|
||||||
#define MSICA_TASK_TICK_SIZE (16*1024)
|
#define MSICA_TASK_TICK_SIZE (16*1024)
|
||||||
|
|
||||||
|
|
||||||
@ -207,12 +209,12 @@ UINT MSICA_API ServiceConfigEval(MSIHANDLE hInstall)
|
|||||||
PMSIHANDLE hViewSC;
|
PMSIHANDLE hViewSC;
|
||||||
|
|
||||||
// Prepare a query to get a list/view of service configurations.
|
// Prepare a query to get a list/view of service configurations.
|
||||||
uiResult = ::MsiDatabaseOpenView(hDatabase, _T("SELECT Name,StartType,Condition FROM ServiceConfigure ORDER BY Sequence"), &hViewSC);
|
uiResult = ::MsiDatabaseOpenView(hDatabase, _T("SELECT Name,StartType,Control,Condition FROM ServiceConfigure ORDER BY Sequence"), &hViewSC);
|
||||||
if (uiResult == NO_ERROR) {
|
if (uiResult == NO_ERROR) {
|
||||||
// Execute query!
|
// Execute query!
|
||||||
uiResult = ::MsiViewExecute(hViewSC, NULL);
|
uiResult = ::MsiViewExecute(hViewSC, NULL);
|
||||||
if (uiResult == NO_ERROR) {
|
if (uiResult == NO_ERROR) {
|
||||||
int iStartType;
|
int iValue;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
PMSIHANDLE hRecord;
|
PMSIHANDLE hRecord;
|
||||||
@ -226,7 +228,7 @@ UINT MSICA_API ServiceConfigEval(MSIHANDLE hInstall)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
// Read and evaluate service configuration condition.
|
// Read and evaluate service configuration condition.
|
||||||
uiResult = ::MsiRecordGetString(hRecord, 3, sValue);
|
uiResult = ::MsiRecordGetString(hRecord, 4, sValue);
|
||||||
if (uiResult != NO_ERROR) break;
|
if (uiResult != NO_ERROR) break;
|
||||||
condition = ::MsiEvaluateCondition(hInstall, sValue);
|
condition = ::MsiEvaluateCondition(hInstall, sValue);
|
||||||
if (condition == MSICONDITION_FALSE)
|
if (condition == MSICONDITION_FALSE)
|
||||||
@ -241,20 +243,44 @@ UINT MSICA_API ServiceConfigEval(MSIHANDLE hInstall)
|
|||||||
if (uiResult != NO_ERROR) break;
|
if (uiResult != NO_ERROR) break;
|
||||||
|
|
||||||
// Read service start type.
|
// Read service start type.
|
||||||
iStartType = ::MsiRecordGetInteger(hRecord, 2);
|
iValue = ::MsiRecordGetInteger(hRecord, 2);
|
||||||
if (iStartType == MSI_NULL_INTEGER) {
|
if (iValue == MSI_NULL_INTEGER) {
|
||||||
uiResult = ERROR_INVALID_FIELD;
|
uiResult = ERROR_INVALID_FIELD;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (iStartType >= 0) {
|
if (iValue >= 0) {
|
||||||
// Set service start type.
|
// 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.
|
// The amount of tick space to add to progress indicator.
|
||||||
::MsiRecordSetInteger(hRecordProg, 1, 3 );
|
::MsiRecordSetInteger(hRecordProg, 1, 3 );
|
||||||
::MsiRecordSetInteger(hRecordProg, 2, MSICA_SVC_SET_START_TICK_SIZE);
|
::MsiRecordSetInteger(hRecordProg, 2, MSICA_SVC_SET_START_TICK_SIZE);
|
||||||
if (::MsiProcessMessage(hInstall, INSTALLMESSAGE_PROGRESS, hRecordProg) == IDCANCEL) { uiResult = ERROR_INSTALL_USEREXIT; break; }
|
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);
|
::MsiViewClose(hViewSC);
|
||||||
|
|
||||||
|
@ -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
|
// COpSvcStart
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class COpSvcStart : public COpTypeSingleString
|
class COpSvcStart : public COpSvcControl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
COpSvcStart(LPCWSTR pszService = L"", int iTicks = 0);
|
COpSvcStart(LPCWSTR pszService = L"", BOOL bWait = FALSE, int iTicks = 0);
|
||||||
virtual HRESULT Execute(CSession *pSession);
|
virtual HRESULT Execute(CSession *pSession);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -492,10 +511,10 @@ public:
|
|||||||
// COpSvcStop
|
// COpSvcStop
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class COpSvcStop : public COpTypeSingleString
|
class COpSvcStop : public COpSvcControl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
COpSvcStop(LPCWSTR pszService = L"", int iTicks = 0);
|
COpSvcStop(LPCWSTR pszService = L"", BOOL bWait = FALSE, int iTicks = 0);
|
||||||
virtual HRESULT Execute(CSession *pSession);
|
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)
|
inline HRESULT operator <<(ATL::CAtlFile &f, const COpList &list)
|
||||||
{
|
{
|
||||||
POSITION pos;
|
POSITION pos;
|
||||||
|
@ -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::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;
|
SC_HANDLE hService;
|
||||||
|
|
||||||
// Open the specified service.
|
// 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) {
|
if (hService) {
|
||||||
// Start the service.
|
// Start the service.
|
||||||
if (::StartService(hService, 0, NULL)) {
|
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.
|
// Order rollback action to stop the service.
|
||||||
pSession->m_olRollback.AddHead(new COpSvcStop(m_sValue));
|
pSession->m_olRollback.AddHead(new COpSvcStop(m_sValue));
|
||||||
}
|
}
|
||||||
dwError = NO_ERROR;
|
|
||||||
} else {
|
} else {
|
||||||
dwError = ::GetLastError();
|
dwError = ::GetLastError();
|
||||||
if (dwError == ERROR_SERVICE_ALREADY_RUNNING) {
|
if (dwError == ERROR_SERVICE_ALREADY_RUNNING) {
|
||||||
@ -134,7 +183,7 @@ HRESULT COpSvcStart::Execute(CSession *pSession)
|
|||||||
// COpSvcStop
|
// 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;
|
SC_HANDLE hService;
|
||||||
|
|
||||||
// Open the specified service.
|
// 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) {
|
if (hService) {
|
||||||
SERVICE_STATUS ss;
|
SERVICE_STATUS ss;
|
||||||
// Stop the service.
|
// Stop the service.
|
||||||
if (::ControlService(hService, SERVICE_CONTROL_STOP, &ss)) {
|
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.
|
// Order rollback action to start the service.
|
||||||
pSession->m_olRollback.AddHead(new COpSvcStart(m_sValue));
|
pSession->m_olRollback.AddHead(new COpSvcStart(m_sValue));
|
||||||
}
|
}
|
||||||
dwError = NO_ERROR;
|
|
||||||
} else {
|
} else {
|
||||||
dwError = ::GetLastError();
|
dwError = ::GetLastError();
|
||||||
if (dwError == ERROR_SERVICE_NOT_ACTIVE) {
|
if (dwError == ERROR_SERVICE_NOT_ACTIVE) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user