Starting a Windows Service Example
To start a service, a service control program opens a handle to an installed database and then specifies the handle in a call to the StartService() function. After starting the service, the program uses the members of the SERVICE_STATUS_PROCESS structure returned by the QueryServiceStatusEx() function to track the progress of the service. The DoStartSvc() function in the following code fragment example shows how to start a service. The szSvcName variable is a global variable that contains the name of the service to be started.
// Purpose: Starts the service if possible
// Parameters: None
// Return value: None
void __stdcall DoStartSvc(void)
{
SERVICE_STATUS_PROCESS ssStatus;
DWORD dwOldCheckPoint;
DWORD dwStartTickCount;
DWORD dwWaitTime;
DWORD dwBytesNeeded;
// Get a handle to the SCM database
schSCManager = OpenSCManager(
NULL, // local computer
NULL, // servicesActive database
SC_MANAGER_ALL_ACCESS); // full access rights
if (schSCManager == NULL)
{
wprintf(LOpenSCManager() failed, error %u\n, GetLastError());
return;
}
else
wprintf(LOpenSCManager() is OK!\n);
// Get a handle to the service
schService = OpenService(
schSCManager, // SCM database
szSvcName, // name of service
SERVICE_ALL_ACCESS); // full access
if (schService == NULL)
{
wprintf(LOpenService() failed, error %u\n, GetLastError());
CloseServiceHandle(schSCManager);
return;
}
else
wprintf(LOpenService() is working!\n);
// Check the status in case the service is not stopped
if (!QueryServiceStatusEx(
schService, // handle to service
SC_STATUS_PROCESS_INFO, // information level
(LPBYTE) &ssStatus, // address of structure
sizeof(SERVICE_STATUS_PROCESS), // size of structure
&dwBytesNeeded)) // size needed if buffer is too small
{
wprintf(LQueryServiceStatusEx() failed, error %u\n, GetLastError());
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return;
}
else
wprintf(LQueryServiceStatusEx() is fine!\n);
// Check if the service is already running. It would be possible
// to stop the service here, but for simplicity this example just returns
if(ssStatus.dwCurrentState != SERVICE_STOPPED && ssStatus.dwCurrentState != SERVICE_STOP_PENDING)
{
wprintf(LCannot start the service because it is already running!\n);
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return;
}
// Save the tick count and initial checkpoint
dwStartTickCount = GetTickCount();
dwOldCheckPoint = ssStatus.dwCheckPoint;
// Wait for the service to stop before attempting to start it
while (ssStatus.dwCurrentState == SERVICE_STOP_PENDING)
{
// Do not wait longer than the wait hint. A good interval is
// one-tenth of the wait hint but not less than 1 second
// and not more than 10 seconds
dwWaitTime = ssStatus.dwWaitHint / 10;
if(dwWaitTime < 1000)
dwWaitTime = 1000;
else if (dwWaitTime > 10000)
dwWaitTime = 10000;
Sleep(dwWaitTime);
// Check the status until the service is no longer stop pending
if (!QueryServiceStatusEx(
schService, // handle to service
SC_STATUS_PROCESS_INFO, // information level
(LPBYTE) &ssStatus, // address of structure
sizeof(SERVICE_STATUS_PROCESS), // size of structure
&dwBytesNeeded)) // size needed if buffer is too small
{
wprintf(LQueryServiceStatusEx() failed, error %u\n, GetLastError());
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return;
}
else
wprintf(LQueryServiceStatusEx() is pretty fine!\n);
if (ssStatus.dwCheckPoint > dwOldCheckPoint)
{
// Continue to wait and check
dwStartTickCount = GetTickCount();
dwOldCheckPoint = ssStatus.dwCheckPoint;
}
else
{
if(GetTickCount()-dwStartTickCount > ssStatus.dwWaitHint)
{
wprintf(LTimeout waiting for service to stop\n);
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return;
}
}
}
// Attempt to start the service
if (!StartService(
schService, // handle to service
0, // number of arguments
NULL)) // no arguments
{
wprintf(LStartService() failed, error %u\n, GetLastError());
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return;
}
else
wprintf(LService start pending...\n);
// Check the status until the service is no longer start pending.
if (!QueryServiceStatusEx(
schService, // handle to service
SC_STATUS_PROCESS_INFO, // info level
(LPBYTE) &ssStatus, // address of structure
sizeof(SERVICE_STATUS_PROCESS), // size of structure
&dwBytesNeeded)) // if buffer too small
{
wprintf(LQueryServiceStatusEx() failed, error %u\n, GetLastError());
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return;
}
else
wprintf(LQueryServiceStatusEx() is working!\n);
// Save the tick count and initial checkpoint.
dwStartTickCount = GetTickCount();
dwOldCheckPoint = ssStatus.dwCheckPoint;
while (ssStatus.dwCurrentState == SERVICE_START_PENDING)
{
// Do not wait longer than the wait hint. A good interval is
// one-tenth the wait hint, but no less than 1 second and no
// more than 10 seconds
dwWaitTime = ssStatus.dwWaitHint / 10;
if(dwWaitTime < 1000)
dwWaitTime = 1000;
else if (dwWaitTime > 10000)
dwWaitTime = 10000;
Sleep(dwWaitTime);
// Check the status again
if (!QueryServiceStatusEx(
schService, // handle to service
SC_STATUS_PROCESS_INFO, // info level
(LPBYTE) &ssStatus, // address of structure
sizeof(SERVICE_STATUS_PROCESS), // size of structure
&dwBytesNeeded)) // if buffer too small
{
wprintf(LQueryServiceStatusEx() failed, error %u\n, GetLastError());
break;
}
else
wprintf(LQueryServiceStatusEx() is pretty damn OK!\n);
if(ssStatus.dwCheckPoint > dwOldCheckPoint)
{
// Continue to wait and check.
dwStartTickCount = GetTickCount();
dwOldCheckPoint = ssStatus.dwCheckPoint;
}
else
{
if(GetTickCount()-dwStartTickCount > ssStatus.dwWaitHint)
{
// No progress made within the wait hint
break;
}
}
}
// Determine whether the service is running
if (ssStatus.dwCurrentState == SERVICE_RUNNING)
{
wprintf(LService was started successfully!\n);
}
else
{
wprintf(LService not started.\n);
wprintf(L Current State: %d\n, ssStatus.dwCurrentState);
wprintf(L Exit Code: %d\n, ssStatus.dwWin32ExitCode);
wprintf(L Check Point: %d\n, ssStatus.dwCheckPoint);
wprintf(L Wait Hint: %d\n, ssStatus.dwWaitHint);
}
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
}