Windows Services Programming 19

 

 

 

 

 

Linking the DLL File

 

Next, link the resource file to generate the DLL.

 

Linking the DLL File

 

After completing the previous tasks, the following screenshot shows the generated files seen through Windows explorer.

 

The generated files seen through Windows explorer after the compile and linking steps

 

Adding the C++ Source File

 

Next, add the source file for our first project and give it a suitable name.

 

A Complete Windows Service Working Program Example:  Adding new C++ source file for C++ source code to the existing C++ project

 

Add the following source code.

 

// link with Kernel32.lib and Advapi32.lib

#include <windows.h>

#include <strsafe.h>

// The file winservice.h is generated when building the resource-only DLL, winservice.dll

#include "../winservice.h"

 

// #pragma comment(lib, "advapi32.lib")

 

// Change the service name accordingly

#define SVCNAME L"MyWinServiceName"

 

SERVICE_STATUS          gSvcStatus;

SERVICE_STATUS_HANDLE   gSvcStatusHandle;

HANDLE                  ghSvcStopEvent = NULL;

 

VOID SvcInstall(void);

VOID WINAPI SvcCtrlHandler( DWORD );

VOID WINAPI SvcMain( DWORD, LPTSTR * );

VOID ReportSvcStatus( DWORD, DWORD, DWORD );

VOID SvcInit( DWORD, LPTSTR * );

VOID SvcReportEvent( LPTSTR );

 

// Purpose: Entry point for the process

// Parameters: None

// Return value: None

void wmain(int argc, WCHAR *argv[])

{

    // If command-line parameter is "install", install the service.

    // Otherwise, the service is probably being started by the SCM

      if(argc != 2)

      {

            wprintf(L"Usage: %s install\n",argv[0]);

            wprintf(L" Otherwise, service probably being started by SCM...\n");

      }

 

    if( lstrcmpi( argv[1], L"install") == 0 )

    {

        wprintf(L"Installing the service....\n");

        SvcInstall();

        return;

    }

 

    // TO_DO: Add any additional services for the process to this table.

    SERVICE_TABLE_ENTRY DispatchTable[] =

    {

        { SVCNAME, (LPSERVICE_MAIN_FUNCTION) SvcMain },

        { NULL, NULL }

    };

 

    // This call returns when the service has stopped.

    // The process should simply terminate when the call returns

    if (!StartServiceCtrlDispatcher(DispatchTable))

    {

            SvcReportEvent(L"StartServiceCtrlDispatcher()...");

    }

}

 

// Purpose: Installs a service in the SCM database

// Parameters: None

// Return value: None

VOID SvcInstall()

{

    SC_HANDLE schSCManager;

    SC_HANDLE schService;

    WCHAR szPath[MAX_PATH];

 

    if( !GetModuleFileName( NULL, szPath, MAX_PATH ) )

    {

        wprintf(L"Cannot install %s service, error %d\n", SVCNAME, GetLastError());

        return;

    }

 

    // 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(L"OpenSCManager() failed, error %d\n", GetLastError());

        return;

    }

      else

            wprintf(L"OpenSCManager() is OK!\n");

 

    // Create the service

    schService = CreateService(

        schSCManager,              // SCM database

        SVCNAME,                   // name of service

        SVCNAME,                   // 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

        szPath,                    // path to service's binary

        NULL,                      // no load ordering group

        NULL,                      // no tag identifier

        NULL,                      // no dependencies

        NULL,                      // LocalSystem account

        NULL);                     // no password

 

    if (schService == NULL)

    {

        wprintf(L"CreateService() failed error %d\n", GetLastError());

        CloseServiceHandle(schSCManager);

        return;

    }

    else

            wprintf(L"Service %s installed successfully\n", SVCNAME);

 

    CloseServiceHandle(schService);

    CloseServiceHandle(schSCManager);

}

 

// Purpose: Entry point for the service

// Parameters:

//   dwArgc - Number of arguments in the lpszArgv array

//   lpszArgv - Array of strings. The first string is the name of

//     the service and subsequent strings are passed by the process

//     that called the StartService function to start the service.

// Return value: None.

VOID WINAPI SvcMain( DWORD dwArgc, LPTSTR *lpszArgv )

{

    // Register the handler function for the service

    gSvcStatusHandle = RegisterServiceCtrlHandler(SVCNAME,SvcCtrlHandler);

 

    if(!gSvcStatusHandle )

    {

        SvcReportEvent(L"RegisterServiceCtrlHandler()");

        return;

    }

 

    // These SERVICE_STATUS members remain as set here

    gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;

    gSvcStatus.dwServiceSpecificExitCode = 0;   

 

    // Report initial status to the SCM

    ReportSvcStatus( SERVICE_START_PENDING, NO_ERROR, 3000 );

 

    // Perform service-specific initialization and work

    SvcInit( dwArgc, lpszArgv );

}

 

// Purpose: The service code

// Parameters:

//   dwArgc - Number of arguments in the lpszArgv array

//   lpszArgv - Array of strings. The first string is the name of

//     the service and subsequent strings are passed by the process

//     that called the StartService function to start the service.

// Return value: None

//

VOID SvcInit( DWORD dwArgc, LPTSTR *lpszArgv)

{

    // TO_DO: Declare and set any required variables.

    //   Be sure to periodically call ReportSvcStatus() with

    //   SERVICE_START_PENDING. If initialization fails, call

    //   ReportSvcStatus with SERVICE_STOPPED.

    // Create an event. The control handler function, SvcCtrlHandler(),

    // signals this event when it receives the stop control code

    ghSvcStopEvent = CreateEvent(

                         NULL,    // default security attributes

                         TRUE,    // manual reset event

                         FALSE,   // not signaled

                         NULL);   // no name

 

    if ( ghSvcStopEvent == NULL)

    {

        ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );

        return;

    }

 

    // Report running status when initialization is complete.

    ReportSvcStatus( SERVICE_RUNNING, NO_ERROR, 0 );

 

    // TO_DO: Perform work until service stops.

    while(1)

    {

        // Check whether to stop the service.

        WaitForSingleObject(ghSvcStopEvent, INFINITE);

        ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );

        return;

    }

}

 

// Purpose: Sets the current service status and reports it to the SCM.

// Parameters:

//   dwCurrentState - The current state (see SERVICE_STATUS)

//   dwWin32ExitCode - The system error code

//   dwWaitHint - Estimated time for pending operation, in milliseconds

// Return value: None

VOID ReportSvcStatus( DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)

{

    static DWORD dwCheckPoint = 1;

 

    // Fill in the SERVICE_STATUS structure

    gSvcStatus.dwCurrentState = dwCurrentState;

    gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;

    gSvcStatus.dwWaitHint = dwWaitHint;

 

    if (dwCurrentState == SERVICE_START_PENDING)

      {

        wprintf(L"The %s service is starting...\n", SVCNAME);

        gSvcStatus.dwControlsAccepted = 0;

      }

    else

      {

            wprintf(L"The %s service can be stopped...\n", SVCNAME);

            gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;

      }

 

    if ( (dwCurrentState == SERVICE_RUNNING) || (dwCurrentState == SERVICE_STOPPED) )

        gSvcStatus.dwCheckPoint = 0;

    else

            gSvcStatus.dwCheckPoint = dwCheckPoint++;

 

    // Report the status of the service to the SCM.

    SetServiceStatus(gSvcStatusHandle, &gSvcStatus);

}

 

// Purpose:

//   Called by SCM whenever a control code is sent to the service

//   using the ControlService function.

// Parameters: dwCtrl - control code

// Return value: None

VOID WINAPI SvcCtrlHandler(DWORD dwCtrl)

{

   // Handle the requested control code.

   switch(dwCtrl)

   { 

      case SERVICE_CONTROL_STOP:

         ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);

         // Signal the service to stop.

         SetEvent(ghSvcStopEvent);        

         return;

      case SERVICE_CONTROL_INTERROGATE:

         // Fall through to send current status.

         break;

      default:

         break;

   }

 

   ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0);

}

 

// Purpose: Logs messages to the event log

// Parameters: szFunction - name of function that failed

// Return value: None

// Remarks: The service must have an entry in the Application event log.

VOID SvcReportEvent(LPTSTR szFunction)

{

    HANDLE hEventSource;

    LPCTSTR lpszStrings[2];

    WCHAR Buffer[80];

 

    hEventSource = RegisterEventSource(NULL, SVCNAME);

 

    if( hEventSource != NULL )

    {

        StringCchPrintf(Buffer, 80, L"%s failed with %d", szFunction, GetLastError());

 

        lpszStrings[0] = SVCNAME;

        lpszStrings[1] = Buffer;

 

        ReportEvent(hEventSource,        // event log handle

                    EVENTLOG_ERROR_TYPE, // event type

                    0,                   // event category

                    SVC_ERROR,           // event identifier

                    NULL,                // no security identifier

                    2,                   // size of lpszStrings array

                    0,                   // no binary data

                    lpszStrings,         // array of strings

                    NULL);               // no binary data

 

        DeregisterEventSource(hEventSource);

    }

}

 

 

 

 

< Windows Services 18 | Win32 Programming | Windows Services Win32 Programming | Windows Services 20 >