Enumerate all devices windows

Enumerating devices (WPD)

The first task completed by most applications is the enumeration of the devices connected to the computer. This task, and the retrieval of device information (such as manufacturer, friendly name, and description), is supported by the IPortableDeviceManager interface.

The EnumerateAllDevices function in the DeviceEnumeration.cpp module contains code that demonstrates the retrieval of the count of connected devices and, once the count is retrieved, the retrieval of device-specific information for each connected device.

The EnumerateAllDevices function accomplishes four primary tasks:

  1. Creates the portable device manager object.
  2. Retrieves a count of connected devices.
  3. Retrieves device information (for the connected devices).
  4. Frees the memory used when retrieving the device information.

Each of these four tasks is described in more detail in the following sections.

The first step in the device enumeration process is the creation of a portable device manager object. This is done by calling the CoCreateInstance function and passing the class identifier (CLSID) for the object, specifying the context in which the code will run, specifying a reference identifier for the IPortableDeviceManager interface, and then supplying a pointer variable that receives the IPortableDeviceManager interface pointer.

Once you obtain an IPortableDeviceManager interface pointer, you can begin calling methods on this interface. The first method called in the EnumerateAllDevices function is IPortableDeviceManager::GetDevices. When this method is called with the first argument set to NULL, it returns the count of connected devices.

After you have retrieved the count of connected devices, you can use this value to retrieve device information for each connected device. This process begins by passing an array of string pointers as the first argument and a count of the number of elements that this array can hold as the second argument (this count should at least be equal to the number of available devices).

The strings returned by this method are the Plug and Play names of the connected devices. These names, in turn, are passed to other methods on the IPortableDeviceManager interface to retrieve device-specific information such as the friendly name, the manufacturer’s name, and the device description. (These names are also used to open a connection to the device when an application calls the IPortableDevice::Open method.)

Once you’ve retrieved the device information, you will need to free the memory associated with the strings pointed to by the array of string pointers. You will also need to delete this array.

Enumerate devices over a network

Important APIs

In addition to discovering locally connected devices, you can use the Windows.Devices.Enumeration APIs to enumerate devices over wireless and networked protocols.

Enumerating devices over networked or wireless protocols

Sometimes you need to enumerate devices that are not locally connected and can only be discovered over a wireless or networking protocols. In order to do so, the Windows.Devices.Enumeration APIs have three different kinds of device objects: the AssociationEndpoint (AEP), the AssociationEndpointContainer (AEP Container), and the AssociationEndpointService (AEP Service). As a group these are referred to as AEPs or AEP objects.

Some device APIs provide a selector string that you can use to enumerate through the available AEP objects. This could include both devices that are paired and are not paired with the system. Some of the devices might not require pairing. Those device APIs may attempt to pair the device if pairing it is necessary before interacting with it. Wi-Fi Direct is an example of APIs that follow this pattern. If those device APIs do not automatically pair the device, you can pair it using the DeviceInformationPairing object available from DeviceInformation.Pairing.

However, there may be cases where you want to manually discover devices on your own without using a pre-defined selector string. For example, you may just need to gather information about AEP devices without interacting with them or you may want to find more AEP objects than will be discovered with the pre-defined selector string. In this case, you will build your own selector string and use it following the instructions under Build a device selector.

When you build your own selector, it is strongly recommended that you limit your scope of enumeration to the protocols that you are interested in. For example, you don’t want to have the Wi-Fi radio search for Wi-Fi Direct devices if you are particularly interested in UPnP devices. Windows has defined an identity for each protocol that you can use to scope your enumeration. The following table lists the protocol types and identifiers.

Protocol or network device type Id
UPnP (including DIAL and DLNA)
Web services on devices (WSD)
Wi-Fi Direct
DNS service discovery (DNS-SD)
Point of service
Network printers (active directory printers)
Windows connect now (WNC)
WiGig docks
Wi-Fi provisioning for HP printers
Bluetooth
Bluetooth LE
Network Camera

AQS examples

Each AEP kind has a property you can use to constrain your enumeration to a specific protocol. Keep in mind you can use the OR operator in an AQS filter to combine multiple protocols. Here are some examples of AQS filter strings that show how to query for AEP devices.

This AQS queries for all UPnP AssociationEndpoint objects when the DeviceInformationKind is set to AsssociationEndpoint.

This AQS queries for all UPnP and WSD AssociationEndpoint objects when the DeviceInformationKind is set to AsssociationEndpoint.

This AQS queries for all UPnP AssociationEndpointService objects if the DeviceInformationKind is set to AsssociationEndpointService.

This AQS queries AssociationEndpointContainer objects when the DeviceInformationKind is set to AssociationEndpointContainer, but only finds them by enumerating the UPnP protocol. Typically, it wouldn’t be useful to enumerate containers that only come from one protocol. However, this might be useful by limiting your filter to protocols where you know your device can be discovered.

Using the System Device Enumerator

The System Device Enumerator provides a uniform way to enumerate, by category, the filters registered on a user’s system. Moreover, it differentiates between individual hardware devices, even if the same filter supports them. This is particularly useful for devices that use the Windows Driver Model (WDM) and the KSProxy filter. For example, the user might have several WDM video capture devices, all supported by the same filter. The System Device Enumerator treats them as separate device instances.

The System Device Enumerator works by creating an enumerator for a specific category, such as audio capture or video compression. The category enumerator returns a unique moniker for each device in the category. The category enumerator automatically includes any relevant Plug and Play devices in the category. For a list of categories, see Filter Categories.

To use the System Device Enumerator, do the following:

  1. Create the system device enumerator by calling CoCreateInstance. The class identifier (CLSID) is CLSID_SystemDeviceEnum.
  2. Obtain a category enumerator by calling ICreateDevEnum::CreateClassEnumerator with the CLSID of the desired category. This method returns an IEnumMoniker interface pointer. If the category is empty (or does not exist), the method returns S_FALSE rather than an error code. If so, the returned IEnumMoniker pointer is NULL and dereferencing it will cause an exception. Therefore, explicitly test for S_OK when you call CreateClassEnumerator, instead of calling the usual SUCCEEDED macro.
  3. Use the IEnumMoniker::Next method to enumerate each moniker. This method returns an IMoniker interface pointer. When the Next method reaches the end of the enumeration, it also returns S_FALSE, so again check for S_OK.
  4. To retrieve the friendly name of the device (for example, to display in the user interface), call the IMoniker::BindToStorage method.
  5. To create and initialize the DirectShow filter that manages the device, call IMoniker::BindToObject on the moniker. Call IFilterGraph::AddFilter to add the filter to the graph.

The following diagram illustrates this process.

The following example shows how to enumerate the video compressors installed on the user’s system. For brevity, the example performs minimal error checking.

Device Monikers

For device monikers, you can pass the moniker to the IFilterGraph2::AddSourceFilterForMoniker method to create a capture filter for the device. For example code, see the documentation for that method.

The IMoniker::GetDisplayName method returns the display name of the moniker. Although the display name is readable, you would not typically display it to an end-user. Get the friendly name from the property bag instead, as described previously.

The IMoniker::ParseDisplayName method or the MkParseDisplayName function can be used to create a default device moniker for a given filter category. Use a display name with the form @device:*: , where category-clsid is the string representation of the category GUID. The default moniker is the first moniker returned by the device enumerator for that category.

Enumerate devices

Samples

The simplest way to enumerate all available devices is to take a snapshot with the FindAllAsync command (explained further in a section below).

To download a sample showing the more advanced usages of the Windows.Devices.Enumeration APIs, click here.

Enumeration APIs

The enumeration namespace enables you to find devices that are internally connected to the system, externally connected, or detectable over wireless or networking protocols. The APIs that you use to enumerate through the possible devices are the Windows.Devices.Enumeration namespace. Some reasons for using these APIs include the following.

  • Finding a device to connect to with your application.
  • Getting information about devices connected to or discoverable by the system.
  • Have an app receive notifications when devices are added, connect, disconnect, change online status, or change other properties.
  • Have an app receive background triggers when devices connect, disconnect, change online status, or change other properties.

These APIs can enumerate devices over any of the following protocols and buses, provided the individual device and the system running the app support that technology. This is not an exhaustive list, and other protocols may be supported by a specific device.

In many cases, you will not need to worry about using the enumeration APIs. This is because many APIs that use devices will automatically select the appropriate default device or provide a more streamlined enumeration API. For example, MediaElement will automatically use the default audio renderer device. As long as your app can use the default device, there is no need to use the enumeration APIs in your application. The enumeration APIs provide a general and flexible way for you to discover and connect to available devices. This topic provides information about enumerating devices and describes the four common ways to enumerate devices.

  • Using the DevicePicker UI
  • Enumerating a snapshot of devices currently discoverable by the system
  • Enumerating devices currently discoverable and watch for changes
  • Enumerating devices currently discoverable and watch for changes in a background task

DeviceInformation objects

Working with the enumeration APIs, you will frequently need to use DeviceInformation objects. These objects contain most of the available information about the device. The following table explains some of the DeviceInformation properties you will be interested in. For a complete list, see the reference page for DeviceInformation.

Property Comments
DeviceInformation.Id This is the unique identifier of the device and is provided as a string variable. In most cases, this is an opaque value you will just pass from one method to another to indicate the specific device you are interested in. You can also use this property and the DeviceInformation.Kind property after closing down your app and reopening it. This will ensure that you can recover and reuse the same DeviceInformation object.
DeviceInformation.Kind This indicates the kind of device object represented by the DeviceInformation object. This is not the device category or type of device. A single device can be represented by several different DeviceInformation objects of different kinds. The possible values for this property are listed in DeviceInformationKind as well as how they relate to one another.
DeviceInformation.Properties This property bag contains information that is requested for the DeviceInformation object. The most common properties are easily referenced as properties of the DeviceInformation object, such as with DeviceInformation.Name. For more information, see Device information properties.

DevicePicker UI

The DevicePicker is a control provided by Windows that creates a small UI that enables the user to select a device from a list. You can customize the DevicePicker window in a few ways.

  • You can control the devices that are displayed in the UI by adding a SupportedDeviceSelectors, a SupportedDeviceClasses, or both to the DevicePicker.Filter. In most cases, you only need to add one selector or class, but if you do need more than one you can add multiple. If you do add multiple selectors or classes, they are conjoined using an OR logic function.
  • You can specify the properties you want to retrieve for the devices. You can do this by adding properties to DevicePicker.RequestedProperties.
  • You can alter the appearance of the DevicePicker using Appearance.
  • You can specify the size and location of the DevicePicker when it is displayed.

While the DevicePicker is displayed, the contents of the UI will be automatically updated if devices are added, removed, or updated.

NoteВ В You cannot specify the DeviceInformationKind using the DevicePicker. If you want to have devices of a specific DeviceInformationKind, you will need to build a DeviceWatcher and provide your own UI.

Casting media content and DIAL also each provide their own pickers if you want to use them. They are CastingDevicePicker and DialDevicePicker, respectively.

Enumerate a snapshot of devices

In some scenarios, the DevicePicker will not be suitable for your needs and you need something more flexible. Perhaps you want to build your own UI or need to enumerate devices without displaying a UI to the user. In these situations, you could enumerate a snapshot of devices. This involves looking through the devices that are currently connected to or paired with the system. However, you need to be aware that this method only looks at a snapshot of devices that are available, so you will not be able to find devices that connect after you enumerate through the list. You also will not be notified if a device is updated or removed. Another potential downside to be aware of is that this method will hold back any results until the entire enumeration is completed. For this reason, you should not use this method when you are interested in AssociationEndpoint, AssociationEndpointContainer, or AssociationEndpointService objects since they are found over a network or wireless protocol. This can take up to 30 seconds to complete. In that scenario, you should use a DeviceWatcher object to enumerate through the possible devices.

To enumerate through a snapshot of devices, use the FindAllAsync method. This method waits until the entire enumeration process is complete and returns all the results as one DeviceInformationCollection object. This method is also overloaded to provide you with several options for filtering your results and limiting them to the devices that you are interested in. You can do this by providing a DeviceClass or passing in a device selector. The device selector is an AQS string that specifies the devices you want to enumerate. For more information, see Build a device selector.

An example of a device enumeration snapshot is provided below:

In addition to limiting the results, you can also specify the properties that you want to retrieve for the devices. If you do, the specified properties will be available in the property bag for each of the DeviceInformation objects returned in the collection. It is important to note that not all properties are available for all device kinds. To see what properties are available for which device kinds, see Device information properties.

Enumerate and watch devices

A more powerful and flexible method of enumerating devices is creating a DeviceWatcher. This option provides the most flexibility when you are enumerating devices. It allows you to enumerate devices that are currently present, and also receive notifications when devices that match your device selector are added, removed, or properties change. When you create a DeviceWatcher, you provide a device selector. For more information about device selectors, see Build a device selector. After creating the watcher, you will receive the following notifications for any device that matches your provided criteria.

  • Add notification when a new device is added.
  • Update notification when a property you are interested in is changed.
  • Remove notification when a device is no longer available or no longer matches your filter.

In most cases where you are using a DeviceWatcher, you are maintaining a list of devices and adding to it, removing items from it, or updating items as your watcher receives updates from the devices that you are watching. When you receive an update notification, the updated information will be available as a DeviceInformationUpdate object. In order to update your list of devices, first find the appropriate DeviceInformation that changed. Then call the Update method for that object, providing the DeviceInformationUpdate object. This is a convenience function that will automatically update your DeviceInformation object.

Since a DeviceWatcher sends notifications as devices arrive and when they change, you should use this method of enumerating devices when you are interested in AssociationEndpoint, AssociationEndpointContainer, or AssociationEndpointService objects since they are enumerated over networking or wireless protocols.

To create a DeviceWatcher, use one of the CreateWatcher methods. These methods are overloaded to enable you to specify the devices that you are interested in. You can do this by providing a DeviceClass or passing in a device selector. The device selector is an AQS string that specifies the devices you want to enumerate. For more information, see Build a device selector. You can also specify the properties that you want to retrieve for the devices and are interested in. If you do, the specified properties will be available in the property bag for each of the DeviceInformation objects returned in the collection. It is important to note that not all properties are available for all device kinds. To see what properties are available for which device kinds, see Device information properties

Watch devices as a background task

Watching devices as a background task is very similar to creating a DeviceWatcher as described above. In fact, you will still need to create a normal DeviceWatcher object first as described in the previous section. Once you create it, you call GetBackgroundTrigger instead of DeviceWatcher.Start. When you call GetBackgroundTrigger, you must specify which of the notifications you are interested in: add, remove, or update. You cannot request update or remove without requesting add as well. Once you register the trigger, the DeviceWatcher will start running immediately in the background. From this point forward, whenever it receives a new notification for your application that matches your criteria, the background task will trigger and it will provide you the latest changes since it last triggered your application.

ImportantВ В The first time that a DeviceWatcherTrigger triggers your application will be when the watcher reaches the EnumerationCompleted state. This means it will contain all of the initial results. Any future times it triggers your application, it will only contain the add, update, and remove notifications that have occurred since the last trigger. This is slightly different from a foreground DeviceWatcher object because the initial results do not come in one at a time and are only delivered in a bundle after the EnumerationCompleted is reached.

Some wireless protocols behave differently if they are scanning in the background versus the foreground, or they may not support scanning in the background at all. There are three possibilities with relation to background scanning. The following table lists the possibilities and the effects this may have on your application. For example, Bluetooth and Wi-Fi Direct do not support background scans, so by extension, they do not support a DeviceWatcherTrigger.

Behavior Impact
Same behavior in background None
Only passive scans possible in background Device may take longer to discover while waiting for a passive scan to occur.
Background scans not supported No devices will be detectable by the DeviceWatcherTrigger, and no updates will be reported.

If your DeviceWatcherTrigger includes a protocol that does not support scanning in as a background task, your trigger will still work. However, you will not be able to get any updates or results over that protocol. The updates for other protocols or devices will still be detected normally.

Using DeviceInformationKind

In most scenarios, you will not need to worry about the DeviceInformationKind of a DeviceInformation object. This is because the device selector returned by the device API you’re using will often guarantee you are getting the correct kinds of device objects to use with their API. However, in some scenarios you will want to get the DeviceInformation for devices, but there is not a corresponding device API to provide a device selector. In these cases you will need to build your own selector. For example, Web Services on Devices does not have a dedicated API, but you can discover those devices and get information about them using the Windows.Devices.Enumeration APIs and then use them using the socket APIs.

If you are building your own device selector to enumerate through device objects, DeviceInformationKind will be important for you to understand. All of the possible kinds, as well as how they relate to one another, are described on the reference page for DeviceInformationKind. One of the most common uses of DeviceInformationKind is to specify what kind of devices you are searching for when submitting a query in conjunction with a device selector. By doing this, it makes sure that you only enumerate over devices that match the provided DeviceInformationKind. For example, you could find a DeviceInterface object and then run a query to get the information for the parent Device object. That parent object may contain additional information.

It is important to note that the properties available in the property bag for a DeviceInformation object will vary depending on the DeviceInformationKind of the device. Certain properties are only available with certain kinds. For more information about which properties are available for which kinds, see Device information properties. Hence, in the above example, searching for the parent Device will give you access to more information that was not available from the DeviceInterface device object. Because of this, when you create your AQS filter strings, it is important to ensure that the requested properties are available for the DeviceInformationKind objects you are enumerating. For more information about building a filter, see Build a device selector.

When enumerating AssociationEndpoint, AssociationEndpointContainer, or AssociationEndpointService objects, you are enumerating over a wireless or network protocol. In these situations, we recommend that you don’t use FindAllAsync and instead use CreateWatcher. This is because searching over a network often results in search operations that won’t timeout for 10 or more seconds before generating EnumerationCompleted. FindAllAsync doesn’t complete its operation until EnumerationCompleted is triggered. If you are using a DeviceWatcher, you’ll get results closer to real time regardless of when EnumerationCompleted is called.

Читайте также:  Startup sound changer для windows 10
Оцените статью