[Function Discovery is available for use in the following versions of Windows: Windows Server 2012, Windows 8, Windows Server 2008 R2, Windows 7, Windows Server 2008, and Windows Vista. It may be altered or unavailable in subsequent versions.]
The Plug and Play (PnP) provider is a synchronous local provider that enumerates PnP resources and responds to function instance queries for PnP devices. The PnP provider can enumerate physical PnP devices connected to the computer, virtual PnP devices, and interfaces corresponding to physical or virtual PnP devices. Any resource that is discoverable by the SetupDI API can be discovered by the PnP provider. For more information about the SetupDI API, see Device Installation Functions.
The PnP provider supports collection queries and instance queries. That means the provider supports both the IFunctionInstanceCollectionQuery::Execute and IFunctionInstanceQuery::Execute methods. Because the PnP provider is synchronous, an Execute method usually returns S_OK for a successful query. An Execute method returns E_PENDING only when a notification-only query is executed. A notification-only query is a query with the PROVIDERPNP_QUERYCONSTRAINT_NOTIFICATIONSONLY constraint applied. If a notification-only query is performed, then memory is not allocated to the IFunctionInstanceCollection pointer returned by the IFunctionInstanceCollectionQuery::Execute method and function instances are not returned.
The function instance(s) returned by a query represent the devnode corresponding to a physical device. Many devnodes implement interfaces that communicate with the device. The interfaces, in turn, implement interface nodes. These interface nodes are not normally included in the query results, even when the PROVIDERPNP_QUERYCONSTRAINT_INTERFACECLASS constraint is applied to the query. If function instance(s) corresponding to the interface node(s) must be implemented on a devnode, IFunctionInstance::QueryService must be called on a returned devnode function instance. When calling QueryService, set the guidService parameter to
SID_PnpProvider and set the riid parameter to
A query constraint can be added by calling IFunctionInstanceCollectionQuery::AddQueryConstraint on an IFunctionInstanceCollectionQuery object before executing the query.
The following table shows the query constraints supported by the PnP provider. The table also shows the value to pass to the pszConstraintValue parameter of the AddQueryConstraint method.
|Constraint Name||Constraint Value||Remarks|
|PROVIDERPNP_QUERYCONSTRAINT_INTERFACECLASS||The GUID of the interface, for example,
||When this constraint is specified, the query returns only devnode function instances that have corresponding interface node function instances that match the specified GUID.
Many PROVIDERPNP_QUERYCONSTRAINT_INTERFACECLASS constraints can be applied to a query. When many constraints are specified, the query returns only devnode function instances that have multiple matching interface node function instances.
|PROVIDERPNP_QUERYCONSTRAINT_NOTIFICATIONSONLY||FD_CONSTRAINTVALUE_TRUE||When this constraint is specified, an Execute method returns E_PENDING and any query results are returned to the IFunctionDiscoveryNotification interface passed to the IFunctionDiscovery::CreateInstanceCollectionQuery or the IFunctionDiscovery::CreateInstanceQuery method. A non-NULL?IFunctionDiscoveryNotification pointer must be passed to the query creation methods.
The PROVIDERPNP_QUERYCONSTRAINT_NOTIFICATIONSONLY and PROVIDERPNP_QUERYCONSTRAINT_NOTPRESENT constraints cannot be used simultaneously.
|PROVIDERPNP_QUERYCONSTRAINT_NOTPRESENT||FD_CONSTRAINTVALUE_TRUE||When this constraint is specified, the PnP provider returns both present and not present function instances.
|FD_QUERYCONSTRAINT_PROVIDERINSTANCEID||The provider instance identifier, as returned by IFunctionInstance::GetProviderInstanceID.||When this constraint is specified, the query returns the function instance matching the provider instance identifier. The function instance must be present on the system.
Applying this query constraint is equivalent to calling IFunctionDiscovery::GetInstance.
The FD_QUERYCONSTRAINT_SUBCATEGORY and the FD_QUERYCONSTRAINT_VISIBILITY constraints are not supported by the PnP Provider.
If a non-NULL IFunctionDiscoveryNotification pointer is passed to the query creation method (either CreateInstanceCollectionQuery or CreateInstanceQuery), then the PnP provider will listen for WM_DEVICECHANGE messages and send QUA_ADD and QUA_REMOVE notifications to the interface as appropriate. An implementation of the IFunctionDiscoveryNotification::OnUpdate method should handle these two notifications.
The QUA_ADD notification corresponds to the DBT_DEVICEARRIVAL device event. When QUA_ADD is sent, a device was added to the system, or a device's presence changed from not present to present. The QUA_REMOVE notification corresponds to the DBT_DEVICEREMOVECOMPLETE device event. When QUA_REMOVE is sent, a device was removed from the system, or a device's presence was changed from present to not present. A device's properties may not be accessible after a QUA_REMOVE event. The QUA_CHANGE notification is not used.
The PnP provider implements writeable provider-side property stores. That means that there is no property store attached to a function instance enumerated by the PnP provider. Instead, property reads and writes are passed directly to the PnP provider and changes are committed immediately.
The IFunctionInstance::OpenPropertyStore method can be used to access the property keys (PKEYs) associated with the PnP function instance. The methods of the IPropertyStore interface can be used to get and set PKEYs associated with the function instance. It is not necessary to call IPropertyStore::Commit after setting a PKEY value, as changes are committed immediately, but it is good programming practice to call the method in any case.
When an IPropertyStore method is called to get or set a PKEY, the PnP provider persists the data using the SetupDI API.
The PnP Provider can get or set many types of PKEYs. The following table shows the list of PKEY types supported by the PnP provider. The table also shows the DEVPROPTYPE type corresponding to each PROPVARIANT type.
|PROPVARIANT Type||DEVPROPTYPE Type|
|VT_ARRAY | VT_UI1||DEVPROP_TYPEMOD_ARRAY | DEVPROP_TYPE_BYTE|
|VT_VECTOR | VT_LPWSTR||DEVPROP_TYPEMOD_LIST | DEVPROP_TYPE_STRING|
When getting or setting a PKEY using the Function Discovery API, use the PROPVARIANT type. When getting or setting a DEVPKEY using the SetupDI API, use the DEVPROPTYPE type.
For more information about PnP property types, see DEVPROPTYPE.
Required and Optional PKEYs
The PnP provider supports an extensible property store. That means any PKEY of a supported PKEY type can be added to the property store associated with a PnP device.
The following list shows the required PKEYs for PnP function instances. For more information about these PKEYs, see General PKEYs.
The PKEY_Device_Interface key can only be retrieved from PnP interface function instances. To obtain an interface function instance from a device function instance, call QueryService on a device function instance returned by the PnP provider.
The PnP provider supports all PnP device properties (DEVPKEYs). These properties are defined in the Devpkey.h header file included in the Windows Driver Kit (WDK). For more information about the device properties and PKEYs defined by PnP, see System-Defined Device Properties.
PKEYs defined in FunctionDiscoveryKeys.h and DEVPKEYs defined in Devpkey.h can be used interchangeably. Whenever possible, use the property key defined in FunctionDiscoveryKeys.h. If a key is not defined in FunctionDiscoveryKeys.h, cast the DEVPKEY type (DEVPROPKEY) to a PKEY type (PROPERTYKEY) and use the exposed IPropertyStore methods to get and set the key values.