windows-nt/Source/XPSP1/NT/printscan/fax/config/dll/service.c
2020-09-26 16:20:57 +08:00

367 lines
8.3 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
service.c
Abstract:
Functions for restarting fax and spooler services
Environment:
Windows NT fax configuration DLL
Revision History:
05/28/96 -davidx-
Created it.
mm/dd/yy -author-
description
--*/
#include "faxcpl.h"
//
// Name of fax and spooler services
//
#define FAX_SERVICE_NAME TEXT("Fax")
#define SPOOLER_SERVICE_NAME TEXT("Spooler")
//
// Information about list of dependent services which we stopped
//
typedef struct {
PVOID pNext;
TCHAR serviceName[1];
} DEPENDENT_SERVICE_LIST, *PDEPENDENT_SERVICE_LIST;
BOOL
MyStartService(
LPTSTR pServerName,
LPTSTR pServiceName
)
/*++
Routine Description:
Start the specified service on the specified server and
wait for the service to be in the running state
Arguments:
pServerName - Specifies the name of the server computer, NULL for local machine
pServiceName - Specifies the name of the service to be started
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
SC_HANDLE hSvcMgr = NULL;
SC_HANDLE hService = NULL;
SERVICE_STATUS serviceStatus;
BOOL success = FALSE;
Verbose(("Starting service '%ws' ...\n", pServiceName));
//
// Find the specified service and start executing it
//
if ((hSvcMgr = OpenSCManager(pServerName, NULL, SC_MANAGER_ALL_ACCESS)) &&
(hService = OpenService(hSvcMgr, pServiceName, SERVICE_ALL_ACCESS)) &&
(StartService(hService, 0, NULL) || GetLastError() == ERROR_SERVICE_ALREADY_RUNNING) &&
QueryServiceStatus(hService, &serviceStatus))
{
while (serviceStatus.dwCurrentState != SERVICE_RUNNING) {
DWORD checkPoint = serviceStatus.dwCheckPoint;
Verbose(("Waiting for service '%ws' to run: state = %d\n",
pServiceName,
serviceStatus.dwCurrentState));
Sleep(serviceStatus.dwWaitHint);
if (!QueryServiceStatus(hService, &serviceStatus) ||
checkPoint == serviceStatus.dwCheckPoint)
{
break;
}
}
success = (serviceStatus.dwCurrentState == SERVICE_RUNNING);
}
//
// Cleanup before returning to the caller
//
if (! success)
Error(("Failed to start service '%ws': %d\n", pServiceName, GetLastError()));
if (hService)
CloseServiceHandle(hService);
if (hSvcMgr)
CloseServiceHandle(hSvcMgr);
return success;
}
BOOL
MyStopService(
LPTSTR pServerName,
LPTSTR pServiceName,
PDEPENDENT_SERVICE_LIST *ppDependentList
)
/*++
Routine Description:
Stop the specified service (as well as any services that depend on it)
on the specified server and wait for the service to be in a non-running state
Arguments:
pServerName - Specifies the name of the server computer, NULL for local machine
pServiceName - Specifies the name of the service to be stopped
ppDependentList - Remember the list of dependent services which we stopped
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
SC_HANDLE hSvcMgr;
SC_HANDLE hService;
BOOL success = FALSE;
Verbose(("Stopping service '%ws' ...\n", pServiceName));
if ((hSvcMgr = OpenSCManager(pServerName, NULL, SC_MANAGER_ALL_ACCESS)) &&
(hService = OpenService(hSvcMgr, pServiceName, SERVICE_ALL_ACCESS)))
{
LPENUM_SERVICE_STATUS pEnumStatus = NULL;
DWORD cb, count, index;
SERVICE_STATUS serviceStatus;
//
// Find all active services which depend on the current service
// and call ourselves recursively to stop those services first
//
success = TRUE;
if (! EnumDependentServices(hService, SERVICE_ACTIVE, NULL, 0, &cb, &count)) {
if (GetLastError() == ERROR_MORE_DATA &&
(pEnumStatus = (LPENUM_SERVICE_STATUS) MemAlloc(cb)) &&
EnumDependentServices(hService, SERVICE_ACTIVE, pEnumStatus, cb, &cb, &count))
{
for (index=0; success && index < count; index++) {
success = MyStopService(pServerName,
pEnumStatus[index].lpServiceName,
ppDependentList);
}
}
MemFree(pEnumStatus);
}
//
// Stop the current service and wait for it to die
//
if (success) {
ControlService(hService, SERVICE_CONTROL_STOP, &serviceStatus);
if (success = QueryServiceStatus(hService, &serviceStatus)) {
while (serviceStatus.dwCurrentState != SERVICE_STOPPED) {
DWORD checkPoint = serviceStatus.dwCheckPoint;
Verbose(("Waiting for service '%ws' to stop: state = %d\n",
pServiceName,
serviceStatus.dwCurrentState));
Sleep(serviceStatus.dwWaitHint);
if (!QueryServiceStatus(hService, &serviceStatus) ||
checkPoint == serviceStatus.dwCheckPoint)
{
break;
}
}
success = (serviceStatus.dwCurrentState == SERVICE_STOPPED);
}
}
}
//
// If the service has been successfully stopped, remember its name
// so that we can restart it later.
//
if (success) {
PDEPENDENT_SERVICE_LIST p;
if (p = MemAlloc(offsetof(DEPENDENT_SERVICE_LIST, serviceName) +
SizeOfString(pServiceName)))
{
_tcscpy(p->serviceName, pServiceName);
p->pNext = *ppDependentList;
*ppDependentList = p;
}
success = (p != NULL);
}
//
// Cleanup before returning to the caller
//
if (! success)
Error(("Failed to stop service '%ws': %d\n", pServiceName, GetLastError()));
if (hService)
CloseServiceHandle(hService);
if (hSvcMgr)
CloseServiceHandle(hSvcMgr);
return success;
}
BOOL
StartFaxService(
LPTSTR pServerName
)
/*++
Routine Description:
Start the fax service and
Arguments:
pServerName - Specifies the name of the server computer, NULL for local machine
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
BOOL success = FALSE;
//
// Start the fax service and wait for it to be in the running state
//
if (MyStartService(pServerName, FAX_SERVICE_NAME)) {
HANDLE hFaxServerEvent;
//
// Wait for the fax service to complete its initialization
//
if (hFaxServerEvent = OpenEvent(SYNCHRONIZE, FALSE, TEXT("FaxServerEvent"))) {
WaitForSingleObject(hFaxServerEvent, INFINITE);
CloseHandle(hFaxServerEvent);
success = TRUE;
} else
Error(("Couldn't open a handle to the fax service event: %d\n", GetLastError()));
}
return success;
}
BOOL
RestartFaxAndSpoolerServices(
LPTSTR pServerName
)
/*++
Routine Description:
Restart fax and spooler services after fax configuration settings are changed
Arguments:
pServerName - Specifies the name of the server computer, NULL for local machine
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
PDEPENDENT_SERVICE_LIST p, pDependents = NULL;
BOOL result;
//
// Fax service must be stopped after the spooler service
// because it's a dependent service of the spooler.
//
// Start the fax and spooler services in the opposite order,
// i.e., first start the fax service and then the spooler service.
//
result = MyStopService(pServerName, SPOOLER_SERVICE_NAME, &pDependents) &&
MyStopService(pServerName, FAX_SERVICE_NAME, &pDependents) &&
StartFaxService(pServerName);
//
// Start other services which we have stopped above
//
while (pDependents) {
if (result)
result = MyStartService(pServerName, pDependents->serviceName);
p = pDependents;
pDependents = p->pNext;
MemFree(p);
}
return result;
}