Click here to Skip to main content
15,893,161 members
Articles / Programming Languages / C++

About Windows Services

Rate me:
Please Sign up or sign in to vote.
4.72/5 (20 votes)
15 Nov 2001CPOL4 min read 138.8K   2.1K   68  
A discussion on Windows services with examples
#include <windows.h>
#include <stdio.h>
#include "resource.h"
#include "services.h"

#define BUFF_LEN	256

TCHAR g_szSelectedComputer[BUFF_LEN];
int g_iLen = BUFF_LEN;
QUERY_SERVICE_CONFIG* g_psc = NULL;

// main program
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
				   int nCmdShow) {

	DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG), NULL, DialogProc);
	return 0;
}

// Dialog procedure
BOOL CALLBACK DialogProc(HWND p_hWnd, UINT p_uMsg, WPARAM p_wParam, LPARAM p_lParam) {

	HICON hIcon = NULL;
	static HWND hWndList = NULL;
	int iWidth = 120;

	switch (p_uMsg) {

	case WM_INITDIALOG:
		// Load Icon
		hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MAIN));
		SendMessage(p_hWnd, WM_SETICON, TRUE, (LPARAM)hIcon);

		// initilize common control
		InitCommonControls();

		hWndList = GetDlgItem(p_hWnd, IDC_LIST_SERVICES);

		InsertColumn(hWndList, DISPLAY_NAME_COL, TEXT("Display Name"), iWidth);
		InsertColumn(hWndList, SERVICE_NAME_COL, TEXT("Service Name"), iWidth);
		InsertColumn(hWndList, TYPE_COL, TEXT("Type"), iWidth);
		InsertColumn(hWndList, STATE_COL, TEXT("Current State"), iWidth);
		InsertColumn(hWndList, CONTROL_COL, TEXT("Controls Accepted"), iWidth);

		// Set extended style of List control full row select
		SendMessage(hWndList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, (LPARAM) LVS_EX_FULLROWSELECT);
		break;

	case WM_COMMAND:
		switch(LOWORD(p_wParam)) {
		
		// Exit from the program
		case IDC_BTN_EXIT:
			PostQuitMessage(0);
			break;

		case IDC_BTN_UPDATE:
			GetWindowServices(hWndList);
			break;

		case IDC_BTN_COMPUTER:
			 if (DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG_COMPUTER), NULL, DialogProcComputer)
				 == IDOK) {
			 
				SetWindowText(GetDlgItem(p_hWnd, IDC_STATICCOMPUTER), g_szSelectedComputer);
			 }
			break;
		}

		case WM_NOTIFY:
			switch (p_wParam) {

			case IDC_LIST_SERVICES:
				if (((NMHDR*)p_lParam)->code == NM_DBLCLK) {

					TCHAR szService[BUFF_LEN];
					int iPos = SendMessage(hWndList, LVM_GETNEXTITEM, 
						-1, LVIS_SELECTED);
					LVITEM lvItem;
					ZeroMemory(&lvItem, sizeof(LVITEM));

					// get the text of second column
					lvItem.iSubItem = 1;
					lvItem.pszText = szService;
					lvItem.cchTextMax = g_iLen;
					SendMessage(hWndList, LVM_GETITEMTEXT, (WPARAM)iPos, (LPARAM)&lvItem);

					SC_HANDLE hSCM = OpenSCManager(g_szSelectedComputer, NULL, SC_MANAGER_ALL_ACCESS);
					SC_HANDLE hService = OpenService(hSCM, szService, SERVICE_ALL_ACCESS);

					QUERY_SERVICE_CONFIG sc;
					DWORD dwBytesNeeded = 0;

					// Try to get information about the query
					BOOL bRetVal = QueryServiceConfig(hService, &sc, sizeof(QUERY_SERVICE_CONFIG),
						&dwBytesNeeded);

					if (!bRetVal) {
						DWORD retVal = GetLastError();

						// buffer size is small. 
						// Required size is in dwBytesNeeded
						if (ERROR_INSUFFICIENT_BUFFER == retVal) {

							DWORD dwBytes = sizeof(QUERY_SERVICE_CONFIG) + dwBytesNeeded;
							g_psc = new QUERY_SERVICE_CONFIG[dwBytesNeeded];

							bRetVal = QueryServiceConfig(hService, g_psc, dwBytes, &dwBytesNeeded);

							if (!bRetVal) {

								ErrorDescription(GetLastError());

								delete [] g_psc;
								g_psc = NULL;
								break;
							}
				
							DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG_SERVICE), NULL, DialogProcService);

							delete [] g_psc;
							g_psc = NULL;
						}
					}

					CloseServiceHandle(hService);
					CloseServiceHandle(hSCM);
				}
			}
			break;
	}

	return FALSE;
}

// insert column in the list control
int InsertColumn(HWND p_hWnd, int p_iCol, LPCTSTR p_lpszHeading, int p_iWidth) {

	LVCOLUMN column;

	column.mask = LVCF_TEXT | LVCF_FMT | LVCF_WIDTH;
	column.fmt = LVCFMT_LEFT;
	column.cx = p_iWidth;
	column.pszText = (LPTSTR)p_lpszHeading;
	column.iSubItem = -1;
	column.iImage = -1;
	column.iOrder = 0;
	
	return (int) SendMessage(p_hWnd, LVM_INSERTCOLUMN, p_iCol, (LPARAM)&column);
}

// insert rows in the list control
int InsertItem(HWND p_hWnd, int p_iRow, LPCTSTR p_lpszText) {

	LVITEM lvItem;

	lvItem.mask = LVIF_TEXT;
	lvItem.iItem = p_iRow;
	lvItem.iSubItem = 0;
	lvItem.state = 0;
	lvItem.stateMask = 0;
	lvItem.pszText = (LPTSTR)p_lpszText;	
	lvItem.iImage = 0;
	lvItem.lParam = 0;
	lvItem.iIndent = 0;

	return (int) SendMessage(p_hWnd, LVM_INSERTITEM, 0, (LPARAM)&lvItem);
}

// insert the item in the other columns of the list control
int InsertSubItem(HWND p_hWnd, int p_iRow, LPCTSTR p_lpszText, int p_iSubItem) {

	LVITEM lvItem;

	lvItem.iSubItem = p_iSubItem;
	lvItem.pszText = (LPTSTR)p_lpszText;

	return (int) SendMessage(p_hWnd, LVM_SETITEMTEXT, p_iRow, (LPARAM)&lvItem);
}

// get all the services of the window
BOOL GetWindowServices(HWND p_hWnd) {

	// first delete all item
	SendMessage(p_hWnd, LVM_DELETEALLITEMS, 0, 0);

	// open service manager
	SC_HANDLE hHandle = OpenSCManager(g_szSelectedComputer, NULL, SC_MANAGER_ENUMERATE_SERVICE);

	if (!hHandle) {
	
		ErrorDescription(GetLastError());
		return FALSE;
	}

	ENUM_SERVICE_STATUS service;

	DWORD dwBytesNeeded = 0;
	DWORD dwServicesReturned = 0;
	DWORD dwResumedHandle = 0;

	// Query services
	BOOL retVal = EnumServicesStatus(hHandle, SERVICE_WIN32 | SERVICE_DRIVER, SERVICE_STATE_ALL, 
		&service, sizeof(ENUM_SERVICE_STATUS), &dwBytesNeeded, &dwServicesReturned,
		&dwResumedHandle);

	if (!retVal) {
	
		// Need big buffer
		if (ERROR_MORE_DATA == GetLastError()) {
		
			// Set the buffer
			DWORD dwBytes = sizeof(ENUM_SERVICE_STATUS) + dwBytesNeeded;
			ENUM_SERVICE_STATUS* pServices = NULL;
			pServices = new ENUM_SERVICE_STATUS [dwBytes];

			// Now query again for services
			EnumServicesStatus(hHandle, SERVICE_WIN32 | SERVICE_DRIVER, SERVICE_STATE_ALL, 
				pServices, dwBytes, &dwBytesNeeded, &dwServicesReturned, &dwResumedHandle);

			// now traverse each service to get information
			for (unsigned iIndex = 0; iIndex < dwServicesReturned; iIndex++) {
			
				InsertItem(p_hWnd, iIndex, (pServices + iIndex)->lpDisplayName);
				InsertSubItem(p_hWnd, iIndex, (pServices + iIndex)->lpServiceName, SERVICE_NAME_COL);

				// get type of the service
				GetTypeOfService(p_hWnd, (pServices + iIndex)->ServiceStatus.dwServiceType, iIndex);

				// get current status of the services
				GetCurrentStatus(p_hWnd, (pServices + iIndex)->ServiceStatus.dwCurrentState, iIndex);

				// check the control code which service can accept
				GetControlCode(p_hWnd, (pServices + iIndex)->ServiceStatus.dwControlsAccepted, iIndex);
			}

			delete [] pServices;
			pServices = NULL;
		}
		else
			return FALSE;
	}

	CloseServiceHandle(hHandle);

	return TRUE;
}
	
// get type of the service
void GetTypeOfService(HWND p_hWnd, DWORD p_dwType, int p_iIndex) {

	switch (p_dwType) {
	
	case SERVICE_WIN32_OWN_PROCESS:
		InsertSubItem(p_hWnd, p_iIndex, TEXT("Run its own process"), TYPE_COL);
		break;

	case SERVICE_WIN32_SHARE_PROCESS:
		InsertSubItem(p_hWnd, p_iIndex, TEXT("Share a process with other application"), TYPE_COL);
		break;

	case SERVICE_KERNEL_DRIVER:
		InsertSubItem(p_hWnd, p_iIndex, TEXT("Device driver"), TYPE_COL);
		break;

	case SERVICE_FILE_SYSTEM_DRIVER:
		InsertSubItem(p_hWnd, p_iIndex, TEXT("File system driver"), TYPE_COL);
		break;

	case SERVICE_INTERACTIVE_PROCESS:
		InsertSubItem(p_hWnd, p_iIndex, TEXT("Service can interactive with desktop"), TYPE_COL);
		break;
	}
}

// get current status of the services
void GetCurrentStatus(HWND p_hWnd, DWORD p_dwType, int p_iIndex) {

	switch (p_dwType) {
	
	case SERVICE_STOPPED:
		InsertSubItem(p_hWnd, p_iIndex, TEXT("Not running"), STATE_COL);
		break;

	case SERVICE_START_PENDING:
		InsertSubItem(p_hWnd, p_iIndex, TEXT("Starting"), STATE_COL);
		break;

	case SERVICE_STOP_PENDING:
		InsertSubItem(p_hWnd, p_iIndex, TEXT("Stopping"), STATE_COL);
		break;

	case SERVICE_RUNNING:
		InsertSubItem(p_hWnd, p_iIndex, TEXT("Running"), STATE_COL);
		break;

	case SERVICE_CONTINUE_PENDING:
		InsertSubItem(p_hWnd, p_iIndex, TEXT("Continue is pending"), STATE_COL);
		break;

	case SERVICE_PAUSE_PENDING:
		InsertSubItem(p_hWnd, p_iIndex, TEXT("Pause is pending"), STATE_COL);
		break;

	case SERVICE_PAUSED:
		InsertSubItem(p_hWnd, p_iIndex, TEXT("Paused"), STATE_COL);
		break;
	}
}

// check the control code which service can accept
void GetControlCode(HWND p_hWnd, DWORD p_dwType, int p_iIndex) {

	switch (p_dwType) {
	
	case SERVICE_ACCEPT_STOP:
		InsertSubItem(p_hWnd, p_iIndex, TEXT("Can Stop"), CONTROL_COL);
		break;

	case SERVICE_ACCEPT_PAUSE_CONTINUE:
		InsertSubItem(p_hWnd, p_iIndex, TEXT("Can Pause and continue"), CONTROL_COL);
		break;

	case SERVICE_ACCEPT_SHUTDOWN:
		InsertSubItem(p_hWnd, p_iIndex, TEXT("Notified when shutdown"), CONTROL_COL);
		break;

	// win 2000 and above
	case SERVICE_ACCEPT_PARAMCHANGE:
		InsertSubItem(p_hWnd, p_iIndex, TEXT("Reread startup paramater"), CONTROL_COL);
		break;

	// win 2000 and above
	case SERVICE_ACCEPT_NETBINDCHANGE:
		InsertSubItem(p_hWnd, p_iIndex, TEXT("Can change network binding"), CONTROL_COL);
		break;
	}
}

// dialog procedure for computer dialog
BOOL CALLBACK DialogProcComputer(HWND p_hWnd, UINT p_uMsg, WPARAM p_wParam, LPARAM p_lParam) {

	HICON hIcon = NULL;
	static HWND hWndList = NULL;
	int iWidth = 85;
	int iPos = 0;

	switch (p_uMsg) {
	
	case WM_INITDIALOG:
		// Load Icon
		hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MAIN));
		SendMessage(p_hWnd, WM_SETICON, TRUE, (LPARAM)hIcon);

		hWndList = GetDlgItem(p_hWnd, IDC_LIST_COMPUTER);

		InsertColumn(hWndList, PLATEFORM_COLUMN, TEXT("Plateform"), iWidth);
		InsertColumn(hWndList, NAME_COLUMN, TEXT("Name"), iWidth);
		InsertColumn(hWndList, VERSION_COLUMN, TEXT("Version"), iWidth);
		InsertColumn(hWndList, TYPE_COLUMN, TEXT("Type"), iWidth);
		InsertColumn(hWndList, COMMENT_COLUMN, TEXT("Comment"), iWidth);

		// Set extended style of List control full row select
		SendMessage(hWndList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, (LPARAM) LVS_EX_FULLROWSELECT);
		GetComputerInfo(hWndList);

		break;

	case WM_COMMAND:
		switch(LOWORD(p_wParam)) {
		
		case IDOK:
			iPos = SendMessage(hWndList, LVM_GETNEXTITEM, -1, LVIS_SELECTED);
			LVITEM lvItem;
			ZeroMemory(&lvItem, sizeof(LVITEM));

			// get the text of second column
			lvItem.iSubItem = 1;
			lvItem.pszText = g_szSelectedComputer;
			lvItem.cchTextMax = g_iLen;
			SendMessage(hWndList, LVM_GETITEMTEXT, (WPARAM)iPos, (LPARAM)&lvItem);

			EndDialog(p_hWnd, IDOK);
			break;

		case IDCANCEL:
			strcpy(g_szSelectedComputer, TEXT(""));
			EndDialog(p_hWnd, IDCANCEL);
			break;
		}

	case WM_NOTIFY:
		switch (p_wParam) {
		
		case IDC_LIST_COMPUTER:
			if (((NMHDR*)p_lParam)->code == NM_DBLCLK) {

				SendMessage(p_hWnd, WM_COMMAND, IDOK, NULL);
			}
			break;
		}

		break;
	}

	return FALSE;
}

// get the information about the computer
void GetComputerInfo(HWND p_hWnd) {

	NET_API_STATUS nStatus;
	LPSERVER_INFO_101 pBuff = NULL;
	DWORD dwEntriesRead = NULL;
	DWORD dwTotalEntries = NULL;
	DWORD dwResumeHandle = NULL;
	TCHAR buff[BUFF_LEN];
	DWORD dwPrefMaxLen = -1;

	// get information
	nStatus = NetServerEnum(NULL, 101, (LPBYTE*)&pBuff, MAX_PREFERRED_LENGTH, 
		&dwEntriesRead,	&dwTotalEntries, SV_TYPE_SERVER, NULL, &dwResumeHandle);

	if ((NERR_Success == nStatus) || (ERROR_MORE_DATA == nStatus)) {
	
		// first delete all item
		SendMessage(p_hWnd, LVM_DELETEALLITEMS, 0, 0);

		for (unsigned int iIndex = 0; iIndex < dwEntriesRead; iIndex++) {
		
			if ((pBuff+iIndex)->sv101_platform_id == PLATFORM_ID_DOS) {

				sprintf(buff, TEXT("%s"), TEXT("DOS"));
			}
			else if ((pBuff+iIndex)->sv101_platform_id == PLATFORM_ID_OS2) {

				sprintf(buff, TEXT("%s"), TEXT("OS/2 or Win9x"));
			}
			else if ((pBuff+iIndex)->sv101_platform_id == PLATFORM_ID_NT) {

				sprintf(buff, TEXT("%s"), TEXT("Win NT/2000"));
			}
			else if ((pBuff+iIndex)->sv101_platform_id == PLATFORM_ID_VMS) {

				sprintf(buff, TEXT("%s"), TEXT("VMS"));
			}

			InsertItem(p_hWnd, iIndex, buff);

			// Name
			// convert UNICODE to ANSI
			sprintf(buff, TEXT("%S"), (pBuff+iIndex)->sv101_name);
			InsertSubItem(p_hWnd, iIndex, buff, NAME_COLUMN);

			// version
			sprintf(buff, TEXT("%d.%d"), (pBuff+iIndex)->sv101_version_major, 
				(pBuff+iIndex)->sv101_version_minor);
			InsertSubItem(p_hWnd, iIndex, buff, VERSION_COLUMN);

			// type
			if ((pBuff+iIndex)->sv101_type & SV_TYPE_DOMAIN_CTRL) {
			
				sprintf(buff, TEXT("%s"), TEXT("PDC"));
			}
			else if ((pBuff+iIndex)->sv101_type & SV_TYPE_DOMAIN_BAKCTRL) {
			
				sprintf(buff, TEXT("%s"), TEXT("BDC"));
			}
			else if ((pBuff+iIndex)->sv101_type & SV_TYPE_WORKSTATION){ 
			
				sprintf(buff, TEXT("%s"), TEXT("WorkStation"));
			}

			InsertSubItem(p_hWnd, iIndex, buff, TYPE_COLUMN);

			// comment
			// convert UNICODE to ANSI
			sprintf(buff, TEXT("%S"), (pBuff+iIndex)->sv101_comment);
			InsertSubItem(p_hWnd, iIndex, buff, COMMENT_COLUMN);
		}
	}
	else {
	
		ErrorDescription(GetLastError());
	}

	if (pBuff != NULL) {
	
		NetApiBufferFree(pBuff);
	}
}

// get the description of the error
void ErrorDescription(DWORD p_dwError) {

	HLOCAL hLocal = NULL;

	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
		NULL, p_dwError, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),(LPTSTR)&hLocal, 
		0, NULL);

	MessageBox(NULL, (LPCTSTR)LocalLock(hLocal), TEXT("Error"), MB_OK | MB_ICONERROR);
	LocalFree(hLocal);
}

// call back function for service dialog
BOOL CALLBACK DialogProcService(HWND p_hWnd, UINT p_uMsg, WPARAM p_wParam, LPARAM p_lParam) {

	HWND hWndEdit = NULL;
	HICON hIcon = NULL;
	TCHAR szBuff[BUFF_LEN];

	switch(p_uMsg) {
	
	case WM_INITDIALOG:
		// Load Icon
		hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MAIN));
		SendMessage(p_hWnd, WM_SETICON, TRUE, (LPARAM)hIcon);

		// display information
		SetDlgItemText(p_hWnd, IDC_EDIT_PATH_NAME, g_psc->lpBinaryPathName);
		SetDlgItemText(p_hWnd, IDC_EDIT_DEPENDENCIES, g_psc->lpDependencies);
		SetDlgItemText(p_hWnd, IDC_EDIT_START_NAME, g_psc->lpServiceStartName);
		SetDlgItemText(p_hWnd, IDC_EDIT_DISPLAY_NAME, g_psc->lpDisplayName);
		SetDlgItemText(p_hWnd, IDC_EDIT_ORDER_GROUP, g_psc->lpLoadOrderGroup);

		SetServiceType(p_hWnd, g_psc->dwServiceType);
		SetStartType(p_hWnd, g_psc->dwStartType);
		SetErrorControl(p_hWnd, g_psc->dwErrorControl);

		sprintf(szBuff, TEXT("%d"), g_psc->dwTagId);
		SetDlgItemText(p_hWnd, IDC_EDIT_TAG_ID, szBuff);
		break;

	case WM_COMMAND:
		switch(LOWORD(p_wParam)) {
		
		case IDOK:
			EndDialog(p_hWnd, IDOK);
			break;
		}
	}

	return FALSE;
}

// display the service type
void SetServiceType(HWND p_hWnd, DWORD p_dwType) {

	TCHAR szBuff[BUFF_LEN];

	// service type
	switch(p_dwType) {

	case SERVICE_WIN32_OWN_PROCESS:
		sprintf(szBuff, TEXT("%s"), TEXT("Runs in its own process"));
		break;

	case SERVICE_WIN32_SHARE_PROCESS:
		sprintf(szBuff, TEXT("%s"), TEXT("Service shares a process with other services"));
		break;

	case SERVICE_KERNEL_DRIVER:
		sprintf(szBuff, TEXT("%s"), TEXT("Service is device driver"));
		break;

	case SERVICE_FILE_SYSTEM_DRIVER:
		sprintf(szBuff, TEXT("%s"), TEXT("Service is file system driver"));
		break;

	case SERVICE_INTERACTIVE_PROCESS:
		sprintf(szBuff, TEXT("%s"), TEXT("Service can interact with desktop"));
		break;
	}

	SetDlgItemText(p_hWnd, IDC_EDIT_SERVICE_TYPE, szBuff);
}

// dispalay the start type
void SetStartType(HWND p_hWnd, DWORD p_dwType) {

	TCHAR szBuff[BUFF_LEN];

	// service type
	switch(p_dwType) {
	
	case SERVICE_BOOT_START:
		sprintf(szBuff, TEXT("%s"), TEXT("Start by System Loader"));
		break;

	case SERVICE_SYSTEM_START:
		sprintf(szBuff, TEXT("%s"), TEXT("Started by IoInitSystem function"));
		break;

	case SERVICE_AUTO_START:
		sprintf(szBuff, TEXT("%s"), TEXT("Started by Service Control Manager"));
		break;

	case SERVICE_DEMAND_START:
		sprintf(szBuff, TEXT("%s"), TEXT("Start by StartService function"));
		break;

	case SERVICE_DISABLED:
		sprintf(szBuff, TEXT("%s"), TEXT("No Longer be started"));
		break;
	}

	SetDlgItemText(p_hWnd, IDC_EDIT_START_TYPE, szBuff);
}

// set error control
void SetErrorControl(HWND p_hWnd, DWORD p_dwErrro) {

	TCHAR szBuff[BUFF_LEN];

	// service type
	switch(p_dwErrro) {
	
	case SERVICE_ERROR_IGNORE:
		sprintf(szBuff, TEXT("%s"), TEXT("Logs error but continue operation"));
		break;

	case SERVICE_ERROR_NORMAL:
		sprintf(szBuff, TEXT("%s"), TEXT("Logs error and display message box"));
		break;

	case SERVICE_ERROR_SEVERE:
		sprintf(szBuff, TEXT("%s"), TEXT("Logs error and restarted with Last Known Good Configuration"));
		break;

	case SERVICE_ERROR_CRITICAL:
		sprintf(szBuff, TEXT("%s"), TEXT("Log error if possible"));
		break;
	}

	SetDlgItemText(p_hWnd, IDC_EDIT_ERROR_CONTROL, szBuff);
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Team Leader American Institute for Research
United States United States
Working as a Team leader in American Institute for Research

Comments and Discussions