Книга: Writing Windows WDM Device Drivers

Plug and Play Notification

Plug and Play Notification

Plug and Play Notification informs Win32 programs and device drivers of device change events that interest them, such as device arrival and removal. They can also refuse requests to remove a device. PnP Notification uses a device interface GUID or a file handle to identify which devices are of interest.

Win32 applications and device drivers register to receive PnP notifications so that they can cope if a device is about to be removed, or if they want to use a device that has just been added. For example, if a program is in the middle of a long transfer, it could refuse permission for a device to be removed. In addition, device drivers can be informed of all devices that expose the required device interface.

Win32 PnP Notification

A Win32 program calls RegisterDeviceNotification to register that it wants to receive PnP Notification device change messages. You must pass either a window handle or (in W2000 only) a service status handle. The NotificationFilter parameter points a structure that says what type of events you want to receive.

To receive events about devices with a particular device interface, pass a DEV_BROADCAST_DEVICEINTERFACE structure pointer to RegisterDeviceNotification. Set the dbcc_classguid field to the device interface GUID of interest. Set the dbcc_size and dbcc_devicetype fields appropriately.

I have not tried it, but passing a DEV_BROADCAST_HANDLE structure pointer should let you receive events from one open file handle, including custom events.

Do not forget to call UnregisterDeviceNotification when you do not wish to receive any further PnP Notification events.

Device Change Message

Each PnP Notification event is sent to a Win32 program as a WM_DEVICECHANGE message. In MFC applications, this appears in an OnDeviceChange handler.

Table 9.4 lists the main event types returned in wParam. lParam may point to an appropriate structure. For device interface change events, it is a DEV_BROADCAST_DEVICEINTERFACE structure whose dbcc_name field contains the device filename.

For a WM_DEVICECHANGE message that asks permission to remove a device, the handler must return TRUE to agree or BROADCAST_QUERY_DENY[23] to deny the requests. Returning FALSE seems to have the same effect as returning TRUE.

Table 9.4 WM_DEVICECHANGE event types

DBT_CONFIGCHANGECANCELED A request to change the current configuration (dock or undock) has been cancelled
DBT_CONFIGCHANGED The current configuration has changed, due to a dock or undock
DBT_CUSTOMEVENT A custom event has occurred
DBT_DEVICEARRIVAL A device has been inserted and is now available
DBT_DEVICEQUERYREMOVE Permission is requested to remove a device. Any application candeny this request and cancel the removal
DBT_DEVICEQUERYREMOVEFAILED A request to remove a device has been cancelled
DBT_DEVICEREMOVEPENDING A device is about to be removed. Cannot be denied
DBT_DEVICEREMOVECOMPLETE A device has been removed
DBT_DEVICETYPESPECIFIC A device-specific event has occurred
DBT_QUERYCHANGECONFIG Permission is requested to change the current configuration (dock or undock)
DBT_DEVNODES_CHANGED Device tree has changed
DBT_USERDEFINED The meaning of this message is user-defined

Wdm2Notify application

Wdm2Notify is a Win32 MFC dialog application that displays any device change events for the Wdm2 device interface. It can be found in the Wdm2Notify directory of the book software. I had a little difficulty setting up the project so that it would compile and link correctly. As I was using VC++ 5, some of the header files and libraries were out of date. I therefore had to change the project settings to use the Platform SDK include directories first, before the Visual C++ directories. My Platform SDK was installed at D:MSSDK, so you may need to change the project settings if you want to recompile Wdm2Notify. I also had to link to the version of user32.lib in the Platform SDK. If you are running a later version of Visual Studio, you may be able to undo these project changes.

Some of the device change structures are defined in dbt.h, so I included this header file in the Wdm2Notify main MFC header, stdafx.h. I also had to include the following line in the stdafx.h to ensure that the correct functions were declared.

#define WINVER 0x0500

Listing 9.14 shows the main Wdm2Notify PnP Notification routines in file Wdm2Notif.yDlg.cpp. RegisterDeviceNotification is called in the dialog OnInitDialog routine and unregistered in DestroyWindow. Device change messages are handled in OnDeviceChange. The rest of the source code for Wdm2Notify can be found on the book software disk.

Listing 9.14 Wdm2Notify device change routines

BOOL CWdm2NotifyDlg::OnInitDialog() {
 CDialog::OnlnitDialog();
 // …
 // Register for Wdm2 device interface changes
 DEV_BROADCAST_DEVICEINTERFACE dbch;
 dbch.dbcc_size = sizeof(dbch);
 dbch.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
 dbch.dbcc_classguid = WDM2_GUID;
 dbch.dbcc_name[0] = '';
 WdmNotificationHandle = RegisterDeviceNotification(GetSafeHwnd(), &dbch, DEVICE_NOTIFY_WINDOW_HANDLE);
 if (WdmNotificationHandle==NULL)
  GetDlgItem(IDC_STATUS)->SetWindowText("Cannot register for Wdm2 class device notification");
 return TRUE;
}
BOOL CWdm2NotifyDlg::DestroyWindow() {
 if (WdmNotificationHandle!=NULL) {
  UnregisterDeviceNotification(WdmNotificationHandle);
  WdmNotificationHandle = NULL;
 }
 return CDialog::DestroyWindow();
}
BOOL CWdm2NotifyDlg::OnDeviceChange(UINT nEventType, DWORD dwData) {
 CString Msg = "duh";
 switch (nEventType) {
 case DBT_CONFIGCHANGECANCELED:
  Msg.Format("DBT_CONFIGCHANGECANCELED");
  break;
 case DBT_CONFIGCHANGED:
  Msg.Format("DBT_CONFIGCHANGED");
  break;
 case DBT_CUSTOMEVENT:
  Msg.Format("DBT_CUSTOMEVENT");
  break;
 case DBT_DEVICEARRIVAL:
  Msg.Format("DBT_DEVICEARRIVAL");
  break;
 case DBT_DEVICEQUERYREMOVE:
  Msg.Format("DBT_DEVICEQUERYREMOVE");
  break;
 case DBT_DEVICEQUERYREMOVEFAILED:
  Msg.Format("DBT_DEVICEQUERYREMOVEFAILED");
  break;
 case DBT_DEVICEREMOVEPENDING:
  Msg.Format("DBT_DEVICEREMOVEPENDING");
  break;
 case DBT_DEVICEREMOVECOMPLETE:
  Msg.Format("DBT_DEVICEREMOVECOMPLETE");
  break;
 case DBT_DEVICETYPESPECIFIC:
  Msg.Format("DBT_DEVICETYPESPECIFIC");
  break;
 case DBT_QUERYCHANGECONFIG:
  Msg.Format("DBT_QUERYCHANGECONFIG");
  break;
 case DBT_DEVNODES_CHANGED:
  Msg.Format("DBT_DEVNODES_CHANGED");
  break;
 case DBT_USERDEFINED:
  Msg.Format("DBT_USERDEFINED");
  break;
 default:
  Msg.Format("Event type %d",nEventType);
 }
 PDEV_BROADCAST_DEVICEINTERfACE pdbch = (PDEV_BROADCAST_DEVICEINTERFACE)dwData;
 if (pdbch!=NULL && pdbch->dbcc_devicetype==DBT_DEVTYP_DEVICEINTERFACE) {
  CString Msg2;
  Msg2.Format("%s: %s",Msg,pdbch->dbcc_name);
  Msg = Msg2;
 }
 CListBox* EventList = (CListBox*)GetDlgItem(IOC_EVENT_LIST);
 EventList->AddString(Msg);
 return TRUE; // or BROADCAST_QUERY_DENY to deny a query remove
}

Running Wdm2Notify in Windows 98

Figure 9.2 shows some typical output in the Wdm2Notify window in Windows 98 as the Wdm2 driver is updated for an installed Wdm2 device. First the PnP Manager asks if it is OK for the existing Wdm2 device to be removed. Then it issues remove pending and remove complete messages. When the driver has been updated, the Wdm2 device is added again resulting in a device arrival message. Finally, a DBT_DEVNODES_CHANGED event indicates that the device tree has changed.

I am not sure why there are so many duplicate device change messages.

If Wdm2Notify returns BROADCAST_QUERY_DENY to the Query Remove message, the remove is correctly refused and a DBT_DEVICEQUERYREMOVEFAILED message is then issued.

Figure 9.2 Wdm2Notify output in Windows 98


Running Wdm2Notify in Windows 2000

The Beta 2 version of Windows 2000 produces output very different from Wdm2Notify. It issues only a DBT_DEVICEREMOVECOMPLETE message and then a DBT_DEVICEARRIVAL message. A Query Remove request is not issued and there are no repeat messages. I hope that the final version of W2000 will issue more PnP Notification device change messages to Win32 applications.

Device Driver PnP Notification

A driver uses PnP Notification to find devices with a particular device interface. A driver does this so that it can issue calls to the devices that it finds. It may wish to layer its own device on top of each found device. This technique is commonly used when finding Human Input Devices, and a full example of this is given in Chapter 23.

PnP Notification in device drivers works in a similar way to Win32 applications. Remember that this is one device driver asking for device change notifications about devices controlled by another driver.

The driver must call IoRegisterPlugPlayNotification to indicate which events it is interested in receiving, and eventually call IoUnregisterPlugPlayNotification when done. You must pass the name of a callback routine to IoRegisterPlugPlayNotification, along with a context pointer.

In device drivers, you can ask for three different categories of PnP Notification events. If you ask for EventCategoryDeviceInterfaceChange events your callback routine is passed a DEVICE_INTERFACE_CHANGE_NOTIFICATION structure that notifies you only of device removal and device arrival events, along with the appropriate symbolic link. Specify the relevant GUID in the EventCategoryData parameter of IoRegisterPlugPlayNotification. If you specify PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES for the EventCategoryFlags parameter, arrival events are also sent straightaway for any existing devices that have a matching device interface GUID.

If you register for EventCategoryHardwareProfileChange events, you receive query change, change complete, and change cancelled events.

Finally, if you ask for EventCategoryTargetDeviceChange events, you receive query remove, removal completes, and remove cancelled messages for one specific device. You must supply a pointer to the relevant file object as the EventCategoryData parameter of IoRegisterPlugPlayNotification. I assume that you can reject query remove requests.

Driver PnP Notification is particularly important for client drivers that use device interfaces exposed by the system class drivers. For example, kernel mode Human Input Device (HID) client drivers can use PnP Notification to identify all installed HID devices. See Chapter 23 for a full example of PnP Notification in device drivers.

As mentioned earlier, device stacks cannot be changed once they are built. PnP Notification lets you find existing devices and effectively layer on top of them.

Notification Request Driver Interactions

As might expect, Win32 programs and device drivers that register for PnP Notification events will effect the operation of a driver. Query remove requests are processed by PnP Notification applications and drivers before the main driver receives an IRP_MN_QUERY_REMOVE_DEVICE IRP. Cancel remove notification messages are sent to applications and other drivers after the main driver has processed its IRP_MN_CANCEL_REMOVE_DEVICE message. Remove pending messages are sent before a device is removed (or surprise removed) and a remove complete notification message is sent afterwards.

Оглавление книги


Генерация: 1.335. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз