Device Interface Notifications (Windows Embedded CE 6.0)

1/6/2010

Windows Embedded CE uses device interface notification to alert applications, services, and device drivers to the appearance and disappearance of device interfaces. It is the Windows Embedded CE equivalent to the Plug and Play event system on Windows-based desktop platforms.

The following table shows the notifications generated by Device Manager.

Notification Description

WM_DEVICECHANGE messages

Transmit with SendNotifyMessage.

Message queue messages

Register for message queue messages with RequestDeviceNotifications. Stop receiving device notifications by calling StopDeviceNotifications.

Message queue notifications include notifications that AdvertiseInterface explicitly advertises and notifications that the driver's IClass registry key value implicitly advertises. IClass GUIDs can have a name associated with them. For example, "{GUID}=GUID_friendly_name".

AdvertiseInterface tells Device Manager to notify all interested parties of the availability or the removal of a device interface. It does not load or unload drivers. Drivers that use AdvertiseInterface should also advertise when the interface goes away.

The filesys module implements the AdvertiseInterface, RequestDeviceNotifications, and StopDeviceNotifications functions. This allows them to be available earlier in the boot process, in particular to block drivers loaded by the filesys module.

The following list shows the ways you can expose device interfaces to applications and drivers through Device Manager:

  • You can define the interface in the IClass value of the registry key used to activate the device.
  • You can define the IClass value in the Active key by a device driver's Init function.
  • You can define the IClass value in the REGINI parameter to ActivateDeviceEx.
    Defining the value requires advance access to the instance information for the driver that is about to be loaded. It also requires that the driver make statements concerning that driver's ability to conform to some interface.
  • You can explicitly call AdvertiseInterface for the interfaces that your driver supports.

These approaches all cause Device Manager APIs to send notifications for all of the driver's defined interfaces after the driver is loaded and initialized, and then again after the driver is unloaded.

The following list shows the rules that ensure applications are compatible with Plug and Play notifications that use non-legacy names:

  • IClass GUIDs without associated names only generate WM_DEVICECHANGE messages if the device has a legacy name such as "COM1:".
  • IClass GUIDs without associated names use the device's legacy name if the legacy name exists.
    "COM1:" is an example of legacy name.
  • IClass GUIDs without associated names use the device's full name if no legacy name exists.
    "\$device\COM11" is an example of a full device name.
  • AdvertiseInterface interface names are transmitted unmodified.
  • IClass GUIDs with associated names are transmitted unmodified.

These rules ensure that WM_DEVICECHANGE recipients can process a non-legacy device name. If a message queue does not include sufficient space for a non-legacy device name, the attempt to transmit fails and the message queue consumer will not receive a message it cannot process.

Use RequestDeviceNotifications and StopDeviceNotifications to register and deregister for device interface notifications. When you are not interested in receiving notifications, call StopDeviceNotifications, and then close the message queue with CloseMsgQueue.

Message queues are operating system (OS) objects that are useful for device notifications. They implement first in, first out (FIFO) queues in shared memory space. An open handle to a message queue can block with WaitForSingleObject or WaitForMultipleObjects. Aside from the WaitForSingleObject and WaitForMultipleObject calls, you must manipulate message queues only with the message queue functions. For example, you cannot call CloseHandle on a message queue handle. For more information about the message queue functions, see Message Queue Point-to-Point Reference.

The following code example shows a simple use of CreateMsgQueue, RequestDeviceNotifications, WaitForSingleObject, and StopDeviceNotifications.

#include <windows.h>
#include <msgqueue.h>

#include <pnp.h>

typedef union {
  DEVDETAIL d;
  char pad[sizeof(DEVDETAIL)+MAX_DEVCLASS_NAMELEN];
} MYDEV;

void EnumerateDevices (HANDLE h)
{
  MYDEV detail;
  DWORD flags;
  DWORD size;

  SetLastError(0);

  while (ReadMsgQueue(h, &detail, sizeof(detail), &size, 1, &flags) == TRUE)
    printf("Device notification: %S %s, f=0x%x\n", detail.d.szName, detail.d.fAttached ? "appeared" : "was removed", flags);

  printf("Leaving Enumerate, error = %d\n", GetLastError());
}

main ()
{
  GUID guid = {0};    // or any known and relevant device interface GUID
  HANDLE hq, hn;
  MSGQUEUEOPTIONS msgopts;

  msgopts.dwFlags = MSGQUEUE_VARIABLESIZE | MSGQUEUE_MSGSIZE;
  msgopts.dwMaxMessages = 0; //?
  msgopts.cbMaxMessage = sizeof(MYDEV);
  msgopts.cbMaxMsgQueue = 0; //?
  msgopts.dwDesiredAccess = GENERIC_READ;
  msgopts.dwShareMode = 0;
  msgopts.dwCreationDisposition = CREATE_NEW;
  hq = CreateMsgQueue(NULL, &msgopts);

  printf("Created message queue, h = %08X\n", hq);
  if (hq == 0) return 0;

  hn = RequestDeviceNotifications(&guid, hq, TRUE);

  printf("Registered for notifications, h = %08X\n", hn);

  EnumerateDevices(hq);

  printf("Completed initial notification pass.\n");

  // do whatever
  while (WaitForSingleObject(hq, 80000) == WAIT_OBJECT_0)
    EnumerateDevices(hq);

  printf("Commencing final enumeration\n");
  EnumerateDevices(hq);
  printf("Done.\n");

  StopDeviceNotifications(hn);
  CloseMsgQueue(hq);

  return 0;
}

See Also

Reference

Device Interface Notifications Reference

Concepts

Device Interfaces
Loading Device Drivers
Bus Enumerator