My Training Period: xx hours. Before you begin, read someinstruction here.
The programming abilities:
Note: For Multithreaded program examples, you have to set your project toMultithread project type.
Starting a Service
To start a service, the following example opens a handle to an installed database and then specifies the handle in a call to the StartService() function. It can be used to start either a service or a driver service, but this example assumes that a service is being started. After starting the service, the program uses the members of theSERVICE_STATUS structure returned by the QueryServiceStatus() function to track the progress of the service. The function requires a handle to a service control manager database. For more information, see Opening an SCManager Database example.
// ForWinXp #define _WIN32_WINNT 0x0501 #include <windows.h> #include <stdio.h>
BOOL StartSampleService(SC_HANDLE);
int main() { SC_HANDLE schSCManager; // Open a handle to the SC Manager database... schSCManager = OpenSCManager( NULL, // local machine NULL, // SERVICES_ACTIVE_DATABASE database is opened by default SC_MANAGER_ALL_ACCESS); // full access rights
if (NULL == schSCManager) printf("OpenSCManager() failed, error: %d.\n", GetLastError()); else printf("OpenSCManager() looks OK.\n"); // Call the StartSampleService()... StartSampleService(schSCManager); return 0; } |
BOOL StartSampleService(SC_HANDLE schSCManager)
{
SC_HANDLE schService;
SERVICE_STATUS ssStatus;
DWORD dwOldCheckPoint;
DWORD dwStartTickCount;
DWORD dwWaitTime;
// You can try to accept the service name through the command line...
// To test this program, make sure the dhcp client is installed and
// in the stop state...
LPCTSTR lpszServiceName = "dhcp";
schService = OpenService(
schSCManager, // SCM database
lpszServiceName, // service name
SERVICE_ALL_ACCESS);
if (schService == NULL)
{
printf("OpenService() failed, error: %d.\n", GetLastError());
return 0;
}
else
printf("OpenService() looks OK.\n");
// Proceed to other task...
if (!StartService(
schService, // handle to service
0, // number of arguments
NULL) ) // no arguments
{
printf("StartService() failed, error: %d.\n", GetLastError());
return 0;
}
else
printf("StartService(), service start pending.\n");
// Check the status until the service is no longer start pending.
if (!QueryServiceStatus(
schService, // handle to service
&ssStatus)) // address of status information structure
{
printf("StartService(), service still start pending.\n");
return 0;
}
else
printf("StartService(), service no longer start pending.\n");
// Save the tick count and initial checkpoint.
dwStartTickCount = GetTickCount();
dwOldCheckPoint = ssStatus.dwCheckPoint;
while (ssStatus.dwCurrentState == SERVICE_START_PENDING)
{
// Just some info...
printf("Wait Hint: %d\n", ssStatus.dwWaitHint);
// 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;
elseif (dwWaitTime > 10000)
dwWaitTime = 10000;
Sleep(dwWaitTime);
// Check the status again...
if (!QueryServiceStatus(
schService, // handle to service
&ssStatus)) // address of structure
break;
if (ssStatus.dwCheckPoint > dwOldCheckPoint)
{
// The service is making progress...
printf("Service starting in progress...\n");
dwStartTickCount = GetTickCount();
dwOldCheckPoint = ssStatus.dwCheckPoint;
}
else
{
if ((GetTickCount()-dwStartTickCount) > ssStatus.dwWaitHint)
{
// No progress made within the wait hint
printf("Well, starting the service looks no progress...\n");
break;
}
}
}
if (CloseServiceHandle(schService) == 0)
printf("CloseServiceHandle() failed, error: %d.\n", GetLastError());
else
printf("CloseServiceHandle() looks OK.\n");
if (ssStatus.dwCurrentState == SERVICE_RUNNING)
{
printf("StartService(), %s service successfully started.\n", lpszServiceName);
return 1;
}
else
{
printf("\nService %s not started.\n", lpszServiceName);
printf(" Current State: %d\n", ssStatus.dwCurrentState);
printf(" Exit Code: %d\n", ssStatus.dwWin32ExitCode);
printf(" Service Specific Exit Code: %d\n", ssStatus.dwServiceSpecificExitCode);
printf(" Check Point: %d\n", ssStatus.dwCheckPoint);
printf(" Wait Hint: %d\n", ssStatus.dwWaitHint);
return 0;
}
}

Then, run the program example.

Verify again through Service Control panel (also can be verified through Task Manager)

This example tests to see which operating system is being used, then checks to see if the Task Scheduler service is running. It starts the service if it is not already running.
// For WinXp
#define _WIN32_WINNT 0x0501
#include <Windows.h>
#include <stdio.h>
#define SCHED_CLASS TEXT("SAGEWINDOWCLASS")
#define SCHED_TITLE TEXT("SYSTEM AGENT COM WINDOW")
#define SCHED_SERVICE_APP_NAME TEXT("mstask.exe")
#define SCHED_SERVICE_NAME TEXT("Schedule")
int main(int argc,char **argv)
{
OSVERSIONINFO osver;
osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
// Determine which version of OS you are running.
GetVersionEx(&osver);
if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
{
// If Windows 95, check to see if Windows 95 version of Task Scheduler is running.
HWND hwnd = FindWindow(SCHED_CLASS, SCHED_TITLE);
if (hwnd != NULL)
{
// It is already running.
printf("Task Scheduler is already running.\n");
return 0;
}
// Execute the task scheduler process.
STARTUPINFO sui;
PROCESS_INFORMATION pi;
ZeroMemory(&sui, sizeof(sui));
sui.cb = sizeof (STARTUPINFO);
TCHAR szApp[MAX_PATH];
LPTSTR pszPath;
DWORD dwRet = SearchPath(NULL,
SCHED_SERVICE_APP_NAME,
NULL,
MAX_PATH,
szApp,
&pszPath);
if (dwRet == 0)
{ return GetLastError(); }
else
printf("SearchPath() is OK.\n");
BOOL fRet = CreateProcess(szApp,
NULL,
NULL,
NULL,
FALSE,
CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
NULL,
NULL,
&sui,
&pi);
if (fRet == 0)
{
return GetLastError();
}
else
printf("CreateProcess() is OK.\n");
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return S_OK;
}
else
{
// If not Windows 95, check to see if Windows NT version of Task Scheduler is running.
SC_HANDLE hSC = NULL;
SC_HANDLE hSchSvc = NULL;
hSC = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
if (hSC == NULL)
{
return GetLastError();
}
else
printf("OpenSCManager() is OK.\n");
hSchSvc = OpenService(hSC, SCHED_SERVICE_NAME, SERVICE_START | SERVICE_QUERY_STATUS);
CloseServiceHandle(hSC);
if (hSchSvc == NULL)
{
return GetLastError();
}
else
printf("OpenService() is OK.\n");
SERVICE_STATUS SvcStatus;
if (QueryServiceStatus(hSchSvc, &SvcStatus) == FALSE)
{
CloseServiceHandle(hSchSvc);
return GetLastError();
}
else
printf("QueryServiceStatus() is OK.\n");
if (SvcStatus.dwCurrentState == SERVICE_RUNNING)
{
// The service is already running.
CloseServiceHandle(hSchSvc);
printf("Task Scheduler is already running.\n");
return 0;
}
if (StartService(hSchSvc, 0, NULL) == FALSE)
{
CloseServiceHandle(hSchSvc);
printf("Could not start Task Scheduler.\n");
return GetLastError();
}
CloseServiceHandle(hSchSvc);
printf("Task Scheduler has been started.\n");
return S_OK;
}
}
![]() |
A service can be stopped with the ControlService() function by sending a SERVICE_CONTROL_STOP request. If the SCM receives a SERVICE_CONTROL_STOP request for a service, it instructs the service to stop by forwarding the request to the service'sServiceMain function. However, if the SCM determines that other running services are dependent on the specified service, it will not forward the stop request. Instead, it returns ERROR_DEPENDENT_SERVICES_RUNNING. Therefore, to programmatically stop such a service, you must first enumerate and stop its dependent services.The following code implements a StopService() function, which optionally attempts to stop the specified service's dependent services.
// ForWinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
DWORD StopService(SC_HANDLE, SC_HANDLE, BOOL, DWORD);
void DisplayError(LPTSTR, DWORD);
// Entry point for the program. This function contains sample code
// demonstrating how to use the StopService function implemented
// above.
//
// Parameters:
// argc - the number of command-line arguments
// argv[] - an array of command-line arguments
// Using _tmain(), TCHAR - A WCHAR if UNICODE is defined, a CHAR otherwise.
void _tmain(int argc, TCHAR *argv[])
{
SC_HANDLE hSCM;
SC_HANDLE hService;
DWORD dwError;
// If no command line argument supplied...
if (argc < 2)
{
_tprintf(TEXT("usage: %s <ServiceName>\n"), argv[0]);
_tprintf(TEXT("Please try again.\n"));
return;
}
// Exception handling...
__try
{
// Open the SCM database
hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
if (!hSCM)
{
DisplayError(TEXT("OpenSCManager() failed.\n"), GetLastError());
__leave;
}
else
_tprintf(TEXT("OpenSCManager() looks OK.\n"));
// Open the specified service
hService = OpenService(hSCM, argv[1], SERVICE_STOP | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS);
if (!hService)
{
DisplayError(TEXT("OpenService() failed.\n"), GetLastError());
__leave;
}
else
_tprintf(TEXT("OpenService() looks OK.\n"));
// Try to stop the service, specifying a 40 second timeout
dwError = StopService(hSCM, hService, TRUE, 40000);
if (dwError == ERROR_SUCCESS)
_tprintf(TEXT("The %s service was successfully stopped.\n"), argv[1]);
else
DisplayError(TEXT("StopService(), stopping the service failed.\n"), dwError);
}
__finally
{
if (hService)
CloseServiceHandle(hService);
if (hSCM)
CloseServiceHandle(hSCM);
}
}
// This function attempts to stop a service. It allows the caller to
// specify whether dependent services should also be stopped. It also
// accepts a timeout value, to prevent a scenario in which a service
// shutdown hangs, then the application stopping the service hangs.
//
// Parameters:
// hSCM - Handle to the service control manager.
// hService - Handle to the service to be stopped.
// fStopDependencies - Indicates whether to stop dependent services.
// dwTimeout - maximum time (in milliseconds) to wait
//
// If the operation is successful, returns ERROR_SUCCESS. Otherwise, returns a system error code.
DWORD StopService(SC_HANDLE hSCM, SC_HANDLE hService, BOOL fStopDependencies, DWORD dwTimeout)
{
SERVICE_STATUS ss;
DWORD dwStartTime = GetTickCount();
// Make sure the service is not already stopped...
if (!QueryServiceStatus(hService, &ss))
return GetLastError();
else
_tprintf(TEXT("QueryServiceStatus(), querying the service status...\n"));
if (ss.dwCurrentState == SERVICE_STOPPED)
{
_tprintf(TEXT("Service already stopped.\n"));
return ERROR_SUCCESS;
}
// If a stop is pending, just wait for it..
_tprintf(TEXT("Checking the service pending status...\n"));
while (ss.dwCurrentState == SERVICE_STOP_PENDING)
{
Sleep(ss.dwWaitHint);
if (!QueryServiceStatus(hService, &ss))
return GetLastError();
if (ss.dwCurrentState == SERVICE_STOPPED)
return ERROR_SUCCESS;
if (GetTickCount() - dwStartTime > dwTimeout)
return ERROR_TIMEOUT;
}
// If the service is running, dependencies must be stopped first
if (fStopDependencies)
{
DWORD i;
DWORD dwBytesNeeded;
DWORD dwCount;
LPENUM_SERVICE_STATUS lpDependencies = NULL;
ENUM_SERVICE_STATUS ess;
SC_HANDLE hDepService;
// Pass a zero-length buffer to get the required buffer size
if ((EnumDependentServices(hService, SERVICE_ACTIVE, lpDependencies, 0, &dwBytesNeeded, &dwCount)) != 0)
{
_tprintf(TEXT("EnumDependentServices(), no dependencies lol!\n"));
// If the Enum call succeeds, then there are no dependent services so do nothing...
}
else
{
_tprintf(TEXT("EnumDependentServices(), there are dependencies lol!\n"));
if (GetLastError() != ERROR_MORE_DATA)
return GetLastError();// Unexpected error
// Allocate a buffer for the dependencies
lpDependencies = (LPENUM_SERVICE_STATUS) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBytesNeeded);
if (!lpDependencies)
return GetLastError();
__try {
// Enumerate the dependencies
if (!EnumDependentServices(hService, SERVICE_ACTIVE, lpDependencies, dwBytesNeeded, &dwBytesNeeded, &dwCount))
return GetLastError();
_tprintf(TEXT("The number of dependencies: %d.\n"), dwCount);
for (i = 0; i < dwCount; i++)
{
ess = *(lpDependencies + i);
_tprintf(TEXT("Dependencies #%d: %s.\n"), i, ess.lpServiceName);
// Open the service
hDepService = OpenService(hSCM, ess.lpServiceName, SERVICE_STOP | SERVICE_QUERY_STATUS);
if (!hDepService)
return GetLastError();
__try {
_tprintf(TEXT("Stopping dependency #%d.\n"), i);
// Send a stop code
if (!ControlService(hDepService, SERVICE_CONTROL_STOP, &ss))
return GetLastError();
// Wait for the service to stop
while (ss.dwCurrentState != SERVICE_STOPPED)
{
Sleep(10000);
//Sleep(ss.dwWaitHint);
if (!QueryServiceStatus(hDepService, &ss))
return GetLastError();
if (ss.dwCurrentState == SERVICE_STOPPED)
_tprintf(TEXT("the %s service was stopped...\n"), ess.lpServiceName);
// Dependency was stopped
break;
if (GetTickCount() - dwStartTime > dwTimeout)
return ERROR_TIMEOUT;
}
}
__finally
{
// Always release the service handle
if (CloseServiceHandle(hDepService) == 0)
_tprintf(TEXT("CloseServiceHandle() failed, error: %d.\n"), GetLastError());
else
_tprintf(TEXT("CloseServiceHandle() looks OK.\n"));
}
}
}
__finally
{
// Always free the enumeration buffer
if (HeapFree(GetProcessHeap(), 0, lpDependencies) == 0)
_tprintf(TEXT("HeapFree() failed, error: %d.\n"), GetLastError());
else
_tprintf(TEXT("HeapFree() looks OK.\n"));
}
}
}
// Assuming all dependencies already stopped, send a stop code to the main service
if (!ControlService(hService, SERVICE_CONTROL_STOP, &ss))
return GetLastError();
// Wait for the service to stop
while (ss.dwCurrentState != SERVICE_STOPPED)
{
Sleep(10000);
// Sleep(ss.dwWaitHint);
if (!QueryServiceStatus(hService, &ss))
return GetLastError();
if (ss.dwCurrentState == SERVICE_STOPPED)
// The main service was stopped...
break;
if (GetTickCount() - dwStartTime > dwTimeout)
return ERROR_TIMEOUT;
}
// Return success
return ERROR_SUCCESS;
}
// Helper function to display an error message
void DisplayError(LPTSTR szAPI, DWORD dwError)
{
LPTSTR lpBuffer = NULL;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpBuffer, 0, NULL);
_tprintf(TEXT("%s failed:\n"), szAPI);
_tprintf(TEXT(" error code = %u\n"), dwError);
_tprintf(TEXT(" message = %s\n"), lpBuffer);
if (LocalFree(lpBuffer) == NULL)
_tprintf(TEXT("LocalFree() looks OK.\n"));
else
_tprintf(TEXT("LocalFree() failed.\n"));
}
In this example we are going to stop IISADMIN service. This service has one dependency that is W3SVC as shown below. Make sure the services already started.

A sample program output is shown below.

Well, you can verify through Service Control panel or Task Manager whether both services were stopped. Tenouk has tried stopping other services on the Windows XP Pro and 2000 server that having many dependencies; the output varies with several error codes. It is left for you to debug :o)
Further reading and digging:
Structure, enum, union and typedef story can be foundC/C++ struct, enum, union & typedef.
For Multi-bytes, Unicode characters and Localization please refer to Locale, wide characters & Unicode (Story) and Windows users & groups programming tutorials (Implementation).
Windows data types areWindows data types.
Microsoft Visual C++, online MSDN.
ReactOS - Windows binary compatible OS - C/C++ source code repository, Doxygen.
Check the best selling C / C++ and Windows books at Amazon.com.