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.
Opening an SCManager Database
Many operations require an open handle to an SCManager object. The following example demonstrates how to obtain the handle. Different operations on the SCM database require different levels of access, and you should only request the minimum access required. If SC_MANAGER_ALL_ACCESS is requested, the OpenSCManager() function fails if the calling process does not have Administrator privileges. The following example shows how to request full access to the ServicesActive database on the local machine.
// ForWinXp #define _WIN32_WINNT 0x0501 #include <windows.h> #include <stdio.h>
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");
return 0; } |

A service configuration program uses the CreateService() function to install a service in a SCM database. The following example shows how to install a service. The application-defined schSCManager handle must have SC_MANAGER_CREATE_SERVICE access to the SCManager object. For an example of how to do this, see the previous example.
// ForWinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
int main()
{
SC_HANDLE schSCManager, schService;
// The service executable location, just dummy here else make sure the executable is there :o)...
LPCTSTR lpszBinaryPathName = "%SystemRoot%\\system\\mytestservice.exe";
// Service display name...
LPCTSTR lpszDisplayName = "My_Sample_Service";
// Registry Subkey
LPCTSTR lpszServiceName = "MySampleSrv";
// 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");
// Create/install service...
schService = CreateService(
schSCManager, // SCManager database
lpszServiceName, // name of service
lpszDisplayName, // service name to display
SERVICE_ALL_ACCESS, // desired access
SERVICE_WIN32_OWN_PROCESS, // service type
SERVICE_DEMAND_START, // start type
SERVICE_ERROR_NORMAL, // error control type
lpszBinaryPathName, // service's binary
NULL, // no load ordering group
NULL, // no tag identifier
NULL, // no dependencies
NULL, // LocalSystem account
NULL); // no password
if (schService == NULL)
{
printf("CreateService() failed.\n");
return FALSE;
}
else
{
printf("CreateService() for %s looks OK.\n", lpszServiceName);
if (CloseServiceHandle(schService) == 0)
printf("CloseServiceHandle() failed, error: %d.\n", GetLastError());
else
printf("CloseServiceHandle() is OK.\n");
return 0;
}
}

Verify through the registry editor using regedt32.

Use the following program example to delete the service; do not delete the key directly through the Registry editor
In the following example, a service configuration program uses theOpenService() function to get a handle with DELETE access to an installed service object. The program then uses the service object handle in theDeleteService() function to remove the service from the SCM database.
void DeleteSampleService()
{
schService = OpenService(
schSCManager, // SCManager database
"Sample_Srv", // name of service
DELETE); // only need DELETE access
if (schService == NULL)
MyErrorExit("OpenService()");
if (!DeleteService(schService))
MyErrorExit("DeleteService()");
else
printf("DeleteService() SUCCESS\n");
CloseServiceHandle(schService);
}
The following is a working program example.
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
int main()
{
SC_HANDLE schSCManager, schService;
// The service name...
LPCTSTR lpszServiceName = "MySampleSrv";
// 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");
schService = OpenService(
schSCManager, // SCManager database
lpszServiceName, // name of service
DELETE); // only need DELETE access
if (schService == NULL)
printf("OpenService() failed, error: %d.\n", GetLastError());
else
printf("OpenService() looks OK.\n");
if (!DeleteService(schService))
printf("DeleteService() failed, error: %d.\n", GetLastError());
else
printf("DeleteService(), %s is deleted.\n", lpszServiceName);
if (CloseServiceHandle(schService) == 0)
printf("CloseServiceHandle() failed, error: %d.\n", GetLastError());
else
printf("CloseServiceHandle() looks OK.\n");
return 0;
}
![]()
Changing a Service Configuration
In the following example, a service configuration program uses theChangeServiceConfig() and ChangeServiceConfig2() functions to change the configuration parameters of an installed service. The program first tries to lock the database, to prevent the SCM from starting a service while it is being reconfigured. If it successfully locks the database, the program opens a handle to the service object, modifies its configuration, unlocks the database, and then closes the service object handle. |
If the program does not successfully in lock the database, it uses theQueryServiceLockStatus() function to retrieve information about the lock. To test this program we re-run our previous program example in Installing a Service. Then run the following program example.
// ForWinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
// lpDescription - string description of the service fDisable - service start type
void ReconfigureMySampleService(BOOL, LPSTR);
int main()
{
BOOL fDisable = FALSE;
LPSTR lpDesc = "This is an added description for MySampleSrv";
// Call the function...
ReconfigureMySampleService(fDisable, lpDesc);
return 0;
}
void ReconfigureMySampleService(BOOL fDisable, LPSTR lpDesc)
{
LPCTSTR lpszServiceName = "MySampleSrv";
SC_HANDLE schSCManager, schService;
SC_LOCK sclLock;
LPQUERY_SERVICE_LOCK_STATUS lpqslsBuf;
SERVICE_DESCRIPTION sdBuf;
DWORD dwBytesNeeded, dwStartType;
// 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");
// Need to acquire database lock before reconfiguring.
sclLock = LockServiceDatabase(schSCManager);
// If the database cannot be locked, report the details.
if (sclLock == NULL)
{
// Exit if the database is not locked by another process.
if (GetLastError() != ERROR_SERVICE_DATABASE_LOCKED)
printf("LockServiceDatabase() failed, error: %d.\n", GetLastError());
else
printf("LockServiceDatabase() is OK.\n");
// Allocate a buffer to get details about the lock.
lpqslsBuf = (LPQUERY_SERVICE_LOCK_STATUS) LocalAlloc(
LPTR, sizeof(QUERY_SERVICE_LOCK_STATUS)+256);
if (lpqslsBuf == NULL)
printf("LocalAlloc() failed, error: %d.\n", GetLastError());
else
printf("LocalAlloc() is OK.\n");
// Get and print the lock status information.
if (!QueryServiceLockStatus(
schSCManager,
lpqslsBuf,
sizeof(QUERY_SERVICE_LOCK_STATUS)+256, &dwBytesNeeded))
printf("QueryServiceLockStatus() failed, error: %d.\n", GetLastError());
else
printf("QueryServiceLockStatus() looks OK.\n");
if (lpqslsBuf->fIsLocked)
printf("Locked by: %s, duration: %d seconds\n", lpqslsBuf->lpLockOwner, lpqslsBuf->dwLockDuration);
else
printf("No longer locked.\n");
LocalFree(lpqslsBuf);
printf("Could not lock the database.\n");
}
// The database is locked, so it is safe to make changes.
// Open a handle to the service.
schService = OpenService(
schSCManager, // SCManager database
lpszServiceName, // name of service
SERVICE_CHANGE_CONFIG); // need CHANGE access
if (schService == NULL)
printf("OpenService() failed, error: %d.\n", GetLastError());
else
printf("OpenService() looks OK.\n");
dwStartType = (fDisable) ? SERVICE_DISABLED : SERVICE_DEMAND_START;
// Make the changes.
if (! ChangeServiceConfig(
schService, // handle of service
SERVICE_NO_CHANGE, // service type: no change
dwStartType, // change service start type
SERVICE_NO_CHANGE, // error control: no change
NULL, // binary path: no change
NULL, // load order group: no change
NULL, // tag ID: no change
NULL, // dependencies: no change
NULL, // account name: no change
NULL, // password: no change
NULL)) // display name: no change
{
printf("ChangeServiceConfig() failed, error: %d.\n", GetLastError());
}
else
printf("ChangeServiceConfig() looks OK, service config changed.\n");
sdBuf.lpDescription = lpDesc;
if(!ChangeServiceConfig2(
schService, // handle to service
SERVICE_CONFIG_DESCRIPTION, // change: description
&sdBuf)) // value: new description
{
printf("ChangeServiceConfig2() failed, error: %d.\n", GetLastError());
}
else
printf("ChangeServiceConfig2() looks OK, service description changed.\n");
// Release the database lock.
if (UnlockServiceDatabase(sclLock) == 0)
printf("UnlockServiceDatabase() failed, error: %d.\n");
else
printf("UnlockServiceDatabase() looks oK.\n");
// Close the handle to the service.
if (CloseServiceHandle(schService) == 0)
printf("CloseServiceHandle() failed, error: %d.\n");
else
printf("CloseServiceHandle() looks OK.\n");
return;
}

Verify through theRegistry editor.

Don’t forget to delete the installed service using our Deleting a Service program example.
In the following example, a service configuration program uses theOpenService() function to get a handle with SERVICE_QUERY_CONFIG access to an installed service object. Then the program uses the service object handle in theQueryServiceConfig() function to retrieve the current configuration of the service.
// For WinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
void GetSampleServiceConfig(void);
int main()
{
// Call the function...
printf("In main(), just some test...\n\n");
GetSampleServiceConfig();
return 0;
}
void GetSampleServiceConfig()
{
// This should be a Subkey name in
// HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services
// registry key. Here we test querying the winmgmt service...
// Try querying other service...
LPCTSTR lpszServiceName = "winmgmt";
SC_HANDLE schSCManager, schService;
LPQUERY_SERVICE_CONFIG lpqscBuf;
LPSERVICE_DESCRIPTION lpqscBuf2;
DWORD dwBytesNeeded;
// 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");
// Open a handle to the service.
schService = OpenService(
schSCManager, // SCManager database
lpszServiceName, // name of service
SERVICE_QUERY_CONFIG); // need QUERY access
if (schService == NULL)
printf("OpenService() failed, error: %d.\n", GetLastError());
else
printf("OpenService() looks OK.\n");
// Allocate a buffer for the configuration information.
lpqscBuf = (LPQUERY_SERVICE_CONFIG) LocalAlloc(LPTR, 4096);
if (lpqscBuf == NULL)
printf("LocalAlloc() for lpqscBuf failed, error: %d.\n", GetLastError());
else
printf("LocalAlloc() for lpqscBuf looks OK.\n");
lpqscBuf2 = (LPSERVICE_DESCRIPTION) LocalAlloc(LPTR, 4096);
if (lpqscBuf2 == NULL)
printf("LocalAlloc() for lpqscBuf2 failed, error: %d.\n", GetLastError());
else
printf("LocalAlloc() for lpqscBuf2 looks OK.\n");
// Get the configuration information.
if (!QueryServiceConfig(
schService,
lpqscBuf,
4096,
&dwBytesNeeded))
{
printf("QueryServiceConfig() failed, error: %d.\n", GetLastError());
}
else
printf("QueryServiceConfig() looks OK.\n");
// May fail and can be scrapped coz can use the following lpqscBuf2->lpDescription...
if (!QueryServiceConfig2(
schService,
SERVICE_CONFIG_DESCRIPTION,
(LPBYTE)lpqscBuf2,
4096,
&dwBytesNeeded))
{
printf("QueryServiceConfig2() failed, error: %d.\n", GetLastError());
}
else
printf("QueryServiceConfig2() failed, error: %d.\n", GetLastError());
// Print the configuration information...
printf("\n%s configuration: \n", lpszServiceName);
printf(" Type: 0x%x\n", lpqscBuf->dwServiceType);
printf(" Start Type: 0x%x\n", lpqscBuf->dwStartType);
printf(" Error Control: 0x%x\n", lpqscBuf->dwErrorControl);
printf(" Binary path: %s\n", lpqscBuf->lpBinaryPathName);
if (lpqscBuf->lpLoadOrderGroup != NULL)
printf(" Load order group: %s\n", lpqscBuf->lpLoadOrderGroup);
if (lpqscBuf->dwTagId != 0)
printf(" Tag ID: %d\n", lpqscBuf->dwTagId);
if (lpqscBuf->lpDependencies != NULL)
printf(" Dependencies: %s\n", lpqscBuf->lpDependencies);
if (lpqscBuf->lpServiceStartName != NULL)
printf(" Start Name: %s\n", lpqscBuf->lpServiceStartName);
if (lpqscBuf2->lpDescription != NULL)
printf(" Description: %s\n", lpqscBuf2->lpDescription);
if (LocalFree(lpqscBuf) == NULL)
printf("LocalFree() for lpqscBuf is OK.\n");
else
printf("LocalFree() for lpqscBuf failed.\n");
if (LocalFree(lpqscBuf2) == NULL)
printf("LocalFree() for lpqscBuf2 is OK.\n");
else
printf("LocalFree() for lpqscBuf2 failed.\n");
return;
}

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.