Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

Receiving Device Event Notification in Windows Service(Detecting Hardware Insertion and/or Removal in Service)

3.70/5 (25 votes)
27 Nov 2006CPOL4 min read 6   7.6K  
Receiving Device Event Notification in Windows Service

Introduction

Receiving Device Event Notification is one of the tricky and interesting things while programming in windows. We may have done this in our MFC or SDK applications.

This articles intention is to give a generic idea of receiving Device Event Notification in a windows service. This article is intended for the audience who has already got some knowledge of writing Windows Services.

Windows Services

As we already know, a Windows service is basically a win32 program that is loaded by the Service Control Manager. They are loaded before the login screen of windows appears. The windows service can be manually started, or at bootup time of windows.

Service Skeleton

The _tmain - General Entry Point

This Service is created by using Service option of ATL Application wizard with Visual C++ 6.0 IDE.The generic entrypoint of this service is _tWinMain which takes care of Registering the service,Unregistering and Installing the service in the system. Apart from this it is doing an important job by calling StartServiceCtrlDispatcher function and inturn makes the SCM to call our ServiceMain Function. I just filled up the SERVICE_TABLE_ENTRY structure with the Service Name and called StartServiceCtrlDispatcher passing the SERVICE_TABLE_ENTRY structure as a parameter.

The ServiceMain function – Entry point of Our Service

The ServiceMain is the entry point function for our service. When the SCM starts our service it creates a new thread for executing our ServiceMain function. The first thing a ServiceMain does is to call RegisterServiceCtrlHandler to register a handler function. The service uses this handler function as it's Service control handler which receives control codes including codes to start, stop, pause and continue the service.

m_hServiceStatus = RegisterServiceCtrlHandlerEx(m_szServiceName, 
                  (LPHANDLER_FUNCTION_EX)_Handler,0);

Once we have registered our service control handler, we can update all our status with regard to our service in our _Handler routine. We can do this using the SetServiceStatus API call. We will need to do this several times during the course of our program and each time it involves filling up a SERVICE_STATUS structure.

Here one Important thing that needs to be noticed is the Second Parameter of the RegisterServiceCtrlHandlerEx which is Normally be typecasted with LPHANDLER_FUNCTION but here I did the same with LPHANDLER_FUNCTION_EX.

The main reason is to get the extended Information in our service control handler.The syntax of the HandlerEX Function looks like as follows,_Handler(DWORD dwOpcode,DWORD evtype, PVOID evdata, PVOID Context);

Here’s our key to receive the DEVICE_EVENT_NOTIFICATION comes into picture. The evtype and evdata or our keys concentration and will be discussed in the following session.

Apart from registering the Control Handler, we have to do another main thing in our Service Main function. This step will enable us to receive the DEVICE_EVENT_NOTIFICATION.

DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
ZeroMemory( &NotificationFilter, sizeof(NotificationFilter) ); 
NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); 
NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; 

m_hDevNotify = RegisterDeviceNotification(m_hServiceStatus, 
               &NotificationFilter, DEVICE_NOTIFY_SERVICE_HANDLE|
               DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);

DEV_BROADCAST_DEVICEINTERFACE is a Windows defined structure in which we can specify the Type of interface for which we want to receive notification. DBT_DEVTYP_DEVICEINTERFACE specifies our device is of Interface type(Ex:USB/CDROM Interface).

RegisterDeviceNotification is the function to register the our service to receive the DeviceNotificationEvent.We are passing our service handle to this function to specify the SCM to send the DeviceNotificationEvent to our service.Remember that, this handle we have got with our RegisterServiceCtrlHandlerEx function.

One more thing here to note is the flags that are passed to RegisterDeviceNotification.

  1. DEVICE_NOTIFY_SERVICE_HANDLE: This flag is to specify that we are calling this function from a service.
  2. DEVICE_NOTIFY_ALL_INTERFACE_CLASSES:This is to tell the SCM that we want to receive the notification independent of interfaces.

This function will return m_hDevNotify to us to proceed further.

The ServiceCtrlHandler function

This is our service's control handler function. All service control requests like starting a service, stopping a service etc. are handled by the control handler.

_Handler(DWORD dwOpcode,DWORD evtype, PVOID evdata, PVOID Context);

As I already told, here’s our key to receive the DEVICE_EVENT_NOTIFICATION comes into picture. The evtype and evdata or our keys areas of our consideration.

Basically we put a switch statement on the dwOpcode variable and we have case blocks for each control code that we intend to handle.

In the DEVICE_EVENT_NOTIFICATION will be received in our switch case SERVICE_CONTROL_DEVICEEVENT.In that we calling a function DeviceEventNotify() where in we are passing the evtype and evdata as a parameter for our use.

switch (dwOpcode)
{
    case SERVICE_CONTROL_STOP:
        UnregisterDeviceNotification(m_hDevNotify);
        SetServiceStatus(SERVICE_STOP_PENDING);
        PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
        break;
    case SERVICE_CONTROL_PAUSE:
        break;
    case SERVICE_CONTROL_CONTINUE:
        break;
    case SERVICE_CONTROL_INTERROGATE:
        break;
    case SERVICE_CONTROL_SHUTDOWN:
        break;
    case SERVICE_CONTROL_DEVICEEVENT:
        OutputDebugString("SERVICE_CONTROL_DEVICEEVENT");
        DeviceEventNotify(evtype, evdata);
        break;
    default:
        LogEvent(_T("Bad service request"));
}

Our whole aim of this article will not be finished if I forgot to explain our main function which is,

DeviceEventNotify(evtype, evdata);

The body of this function looks like as follows:

unsigned long __stdcall DeviceEventNotify(DWORD evtype, PVOID evdata)
{
    switch (evtype)
    {
        case DBT_DEVICEREMOVECOMPLETE:
        {
            _Module.LogEvent(TEXT("Device Removal"));
            OutputDebugString("Device Removal");
        }
        break;
        case DBT_DEVICEARRIVAL:
        {
            _Module.LogEvent(TEXT("Device Arrival"));
            OutputDebugString("Device Arrival");
        }
        break;
    }
    return 0;
}


evtype specifies the DEVICE_EVENT type weather it is DEVICE_ARRIVAL or REMOVAL.This may be Media Insertion/Removal in case of CD/DVD.

Using Evdata we can get details Like, for which Interface we are getting this Notification.

Sample output when Using DebugView is as follows,

Sample screenshot

Building the Sample Code

Building the sample code requires Visual C++ 6.0 or Visual Studio.NET 2003 compiler.If you build the code it will be automatically registered in the system.For using this application as service Goto command prompt and goto the executable location and type ,

Devservice -/Service

If you do this the application will be reconised as service and we can start the service in the usual manner

1.Either by typing net start DevService

2.Or goto Control Panel Services and Rightclick our service and then start.

Once we do this the DeviceEvent Notifications are received by the service.We can see the output using DbgView.exe.

License

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