|< Windows Services Programming 3 | Main | Windows Services Programming 5 >| Site Index | Download |


 

 

MODULE EE1

WINDOWS SERVICES

Part 4: MORE PROGRAM EXAMPLES

 

 

What do we have in this Module?

  1. Opening an SCManager database program example.

  2. Installing a service program example.

  3. Deleting a service program example.

  4. Changing a service configuration program example.

  5. Querying a service's configuration program example.

 

My Training Period: xx hours. Before you begin, read some instruction here.

 

 

 

 

 

 

 

 

 

 

 

The programming abilities:

  • Able to collect and understand all the required information related to Windows Services.

  • Able to understand, build and run various Windows Service application programs.

Note: For Multithreaded program examples, you have to set your project to Multithread 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.

 

// For WinXp

#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;

}

 

Windows services: Opening SCManager database

 

Installing a Service

 

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.

 

// For WinXp

#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;

    }

}

 

Windows services: installing a service program example

 

Verify through the registry editor using regedt32.

 

Windows services: Registry verification of the service installation example

 

Use the following program example to delete the service; do not delete the key directly through the Registry editor

 

Deleting a Service

 

In the following example, a service configuration program uses the OpenService() function to get a handle with DELETE access to an installed service object. The program then uses the service object handle in the DeleteService() 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;

}

 

Windows services: Deleting a service program example

 

Changing a Service Configuration

 

In the following example, a service configuration program uses the ChangeServiceConfig() 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 the QueryServiceLockStatus() 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.

 

// For WinXp

#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;

}

 

Windows services: Changing a service configuration program example

 

Verify through the Registry editor.

 

Windows services: Writing service program main functionVerification of service deletion using Registry editor

 

Don’t forget to delete the installed service using our Deleting a Service program example.

 

Querying a Service's Configuration

 

In the following example, a service configuration program uses the OpenService() function to get a handle with SERVICE_QUERY_CONFIG access to an installed service object. Then the program uses the service object handle in the QueryServiceConfig() 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;

}

 

Windows services: Querying a service configuration program example

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Further reading and digging:

 

  1. Structure, enum, union and typedef story can be found C/C++ struct, enum, union & typedef.

  2. For Multibytes, Unicode characters and Localization please refer to Locale, wide characters & Unicode (Story) and Windows users & groups programming tutorials (Implementation).

  3. Windows data types are Windows data types.

  4. Microsoft Visual C++, online MSDN.

  5. Check the best selling C / C++ and Windows books at Amazon.com.

 

 

 

 

 

 

 

|< Windows Services Programming 3 | Main | Windows Services Programming 5 >| Site Index | Download |