Hello, user mode? Plug and Play calling

You can use Plug and Play notifications for simple one-way communication from a kernel-mode driver to a user-mode application. To do this, call IoReportTargetDeviceChangeAsynchronous with a TARGET_DEVICE_CUSTOM_NOTIFICATION structure that describes the event. This routine signals the Plug and Play manager that the event has occurred on a device.

The system defines several types of Plug and Play events that signal changes to a device interface, hardware profile, or target device. These are sent automatically, without any action on the part of the driver. A driver can define custom events, which don't necessarily have to relate to hardware. All that's needed is to publish a GUID for the event and populate the TARGET_DEVICE_CUSTOM_NOTIFICATION structure with the GUID and other information about the event.

Any number of user-mode applications can register for PnP notifications from your driver, by calling RegisterDeviceNotification and passing a DEV_BROADCAST_HANDLE notification filter that includes the handle to the device. (A kernel-mode driver registers for system-defined Plug and Play events by calling IoRegisterPlugPlayNotification to register a callback routine for a particular event category.)

When the event occurs, the system notifies all registered user-mode applications through the standard Windows messaging mechanism: Each registered application receives a WM_DEVICECHANGE message with a WPARAM of DBT_CUSTOMEVENT and an LPARAM that points to a structure containing event-specific data.

Plug and Play notifications are not guaranteed to work if the system is low on memory. IoReportTargetDeviceChangeAsynchronous allocates memory immediately on being called. If the allocation fails, the notification is never sent. In user mode, the system must allocate memory for the LPARAM for the message; if that fails, the notification is never received.

Also, notifications are transitory and there is no stored history. Assuming memory allocations succeed, an application receives only notifications that were sent after it registered to receive them. Notifications that were sent before the application registered are no longer available.

Finally, because Plug and Play notifications are one-way communication, you'll need to use a different mechanism if your driver must synchronize with a user-mode application. Shared events and driver-defined IOCTLs are two ways of accomplishing this. See the Event sample in the Windows DDK for sample code that illustrates these techniques.

What should you do?

To use Plug and Play notifications to communicate with a user-mode application:

  • If you're defining a custom event, use guidgen or uuidgen to create a global unique identifier (GUID) for the event, and publish the GUID in a header file for use by components that require notification.

  • In your kernel-mode driver, call IoReportTargetDeviceChangeAsynchronous when the event occurs, passing a TARGET_DEVICE_CUSTOM_NOTIFICATION structure that contains the GUID and other event information.

    To use IoReportTargetDeviceChangeAsynchronous, include Ntddk.h and link with both Wdm.lib and Ntoskrnl.lib.

  • In your user-mode application, obtain a handle to the device and register for notification by calling RegisterDeviceNotification, passing a DEV_BROADCAST_HANDLE notification filter that includes the handle to the device and the GUID for the event.

  • In your user-mode application, handle the WM_DEVICECHANGE message with a WPARAM of DBT_CUSTOMEVENT.

Code Examples

Example 1: Broadcast Notification of an Event. The following code sample shows how a kernel-mode driver would use IoReportTargetDeviceChangeAsynchronous to broadcast notification of an event-in this case, GUID_SOME_PNP_EVENT, which consists of the message "Hello."

typedef struct _EVENT_INFO {

    ULONG Count;

    WCHAR Message[32];

} EVENT_INFO;



    UCHAR buffer[sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION) +

                 sizeof(EVENT_INFO)];

    PTARGET_DEVICE_CUSTOM_NOTIFICATION pNotify;

    UNALIGNED EVENT_INFO * pInfo;



    RtlZeroMemory(buffer, sizeof(buffer));

    pNotify = (PTARGET_DEVICE_CUSTOM_NOTIFICATION) buffer;



    RtlCopyMemory(&pNotify->Event, &GUID_SOME_PNP_EVENT, sizeof(GUID));



    pNotify->NameBufferOffset = -1;

    pNotify->Version = 1;

    pNotify->Size = sizeof(*pNotify) - sizeof(pNotify->CustomDataBuffer) +

                    sizeof(*pInfo);



    pInfo = (EVENT_INFO UNALIGNED *) &pNotify->CustomDataBuffer[0];



     pInfo->Count = pdx->Count;



    status = RtlStringCchCopyW(pInfo->Message,

      sizeof(pInfo->Message)/sizeof(pInfo->Message[0]), L"Hello!");



    if (NT_SUCCESS(status)) {

        IoReportTargetDeviceChangeAsynchronous(pdx->Pdo, pNotify, NULL, NULL);

    }

Example 2: Register for Notification. The following code sample shows how a user-mode application would register for notification of changes in device interfaces for an interface class GUID.

BOOL DoRegisterDeviceInterface( 

    GUID InterfaceClassGuid, 

    HDEVNOTIFY *hDevNotify 

)

{

    DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;

    DWORD Err;

    ZeroMemory( &NotificationFilter, sizeof(NotificationFilter) );

    NotificationFilter.dbcc_size = 

        sizeof(DEV_BROADCAST_DEVICEINTERFACE);

    NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;

    NotificationFilter.dbcc_classguid = InterfaceClassGuid;



    *hDevNotify = RegisterDeviceNotification( hWnd, 

        &NotificationFilter,

        DEVICE_NOTIFY_WINDOW_HANDLE

    );



    if(!*hDevNotify) 

    {

        Err = GetLastError();

        printf( "RegisterDeviceNotification failed: %lx.\n", Err);

        return FALSE;

    }



    return TRUE;

}

Example 3: Handle a Custom Event. The following code sample shows how a user-mode application would handle the WM_DEVICECHANGE message for a custom event. See the Notify sample in the Windows DDK for more code that demonstrates how to register for and handle Plug and Play notifications.

case WM_DEVICECHANGE:

    OnDeviceChange(Wparam, (_DEV_BROADCAST_HEADER *) Lparam);

    break;



void

OnDeviceChange(

    ULONG EventCode,

    _DEV_BROADCAST_HEADER *Hdr

    )

{

    PDEV_BROADCAST_HANDLE pHdrHandle;

    pHdrHandle = (PDEV_BROADCAST_HANDLE) Hdr;

    if (EventCode == DBT_CUSTOMEVENT) {

        if (memcmp(&pHdrHandle->dbch_eventguid,

                   &GUID_PNPEVENT_EVENT,

                   sizeof(GUID)) == 0) {

            PEVENT_INFO pEventInfo = (PEVENT_INFO) pHdrHandle->dbch_data;



            ...

        }

        else { // handle other event guids here }

    }

    else { // handle other EventCodes here }

}

For more information:

User-Mode Interactions: Guidelines for Kernel-Mode Drivers

Windows Driver Kit (WDK):

Using PnP Notification

Defining and Exporting New GUIDs

IoReportTargetDeviceChangeAsynchronous

TARGET_DEVICE_CUSTOM_NOTIFICATION

Event sample - %winddk%\src\general\event\

Notify sample - %winddk%\src\general\toaster\exe\notify\

Platform SDK:

RegisterDeviceNotification

WM_DEVICECHANGE

 

 

Send comments about this topic to Microsoft