Windows 8 设备枚举
探索 Windows.Devices.Enumeration.DeviceInformation 和 Windows.Devices.Enumeration.Pnp API。
引言
Windows 8 引入了一套新的 API 用于枚举设备。它们需要一些时间来适应。本文将描述它们如何协同工作,以及它们会产生什么样的输出。
为什么会使用这些 API?在我的情况下,我希望发现连接到计算机的所有 UPnP 设备,以便向它们播放音频。并且我希望用 Windows 应用商店的应用程序来编写,因此我必须使用相应的 Windows 8 API。
本文中的代码全部是 VB 语言,但用 C# 编写同样有效。
本文中的代码使用 WinRT API,并且只能在 Windows 8 上运行。您可以在应用商店应用中使用它们,或者通过遵循这些说明在桌面/控制台应用中使用它们。
您可以查询哪些信息
在 Windows.Devices.Enumeration
命名空间中有五个主要的查询方法您将要使用。
Await DeviceInformation.FindAllAsync()
Await Pnp.PnpObject.FindAllAsync(Pnp.PnpObjectType.DeviceContainer, ...)
Await Pnp.PnpObject.FindAllAsync(Pnp.PnpObjectType.Device, ...)
Await Pnp.PnpObject.FindAllAsync(Pnp.PnpObjectType.DeviceInterface, ...)
Await Pnp.PnpObject.FindAllAsync(Pnp.PnpObjectType.DeviceInterfaceClass, ...)
Await Pnp.PnpObject.CreateFromIdAsync(..., id, ...)
它们不能互换使用。每种方法检索关于不同类型实体(entity)的不同类型信息。让我们逐一查看,并附带示例输出。(注意:随附的 zip 文件还包含了我的系统中所有设备的完整转储,以备您进行交叉引用。)
每个 DeviceContainer
包含多个 Device
。每个 Device
包含多个 DeviceInterface
。DeviceContainer
是您知道某个设备是否已连接或已打开的级别。DeviceInterface
是您与设备交互的级别。
DeviceInformation.FindAllAsync - 此方法检索关于每个设备的初步信息,例如:
[DeviceInformation.FindAllAsync] - SA-NS300
System.ItemNameDisplay=SA-NS300
System.Devices.Icon=C:\Windows\System32\DDORes.dll,-2363
{51236583-0C4A-4FE8-B81F-166AEC13F510},123=C:\Windows\SYSTEM32\DDORes.dll,-3097
System.Devices.IsDefault=False
System.Devices.DeviceInstanceId=SWD\DAFUPnPProvider\uuid:5f9ec1b3-ed59-1900-4530-0007f521ebd6
System.Devices.InterfaceEnabled=True
Pnp.PnpObject.FindAllAsync(Pnp.PnpObjectType.DeviceContainer, ...) - 此方法检索有关即插即用(PnP)设备的信息,例如您插入 USB 或 Wi-Fi UPnP 设备。从技术上讲,您插入的每个设备都是一个“DeviceContainer
”,它包含一个或多个“Device
”(通常只有一个)。DeviceContainer
知道它是否已连接(通过其 System.Devices.Connected
属性)。以下是我从我的索尼 SA-NS300 Wi-Fi 扬声器获得的信息:
[PnpObject.FindAllAsync(DeviceContainer)] - SA-NS300
System.ItemNameDisplay=SA-NS300
System.Devices.IsDefault=False
System.Devices.Icon=C:\Windows\System32\DDORes.dll,-2363
System.Devices.FriendlyName=SA-NS300
System.Devices.Connected=True
System.Devices.Manufacturer=Sony Corporation
System.Devices.ModelName=Network Speaker
System.Devices.PresentationUrl=http://169.254.235.214/
System.Devices.DiscoveryMethod={UPnP}
System.Devices.Paired=True
PKEY_DeviceDisplay_IsShowInDisconnectedState=False
System.Devices.LocalMachine=False
PKEY_DeviceDisplay_IsMetadataSearchInProgress=False
PKEY_DeviceDisplay_IsNotInterestingForDisplay=False
PKEY_DeviceDisplay_IsDeviceUniquelyIdentifiable=True
PKEY_DeviceDisplay_AssociationArray={HardwareId\UMB#Sony_Corporation#SA-NS300#
urn:schemas-upnp-org:device:MediaRenderer:1,CompatibleId\UMB#
urn:schemas-upnp-org:device:MediaRenderer:1,CompatibleId\SWD#
GenericRaw,CompatibleId\SWD#Generic,InterfaceClass\{2A323D9D-EDF1-
430B-AB95-5860894493D4},InterfaceClass\{D0875FB4-2196-4C7A-A63D-E416ADDD60A1},
InterfaceClass\{8660E926-FF3D-580C-959E-8B8AF44D7CDE},InterfaceClass\{4C38E836-
6A2F-5949-9406-1788EA20D1D5},InterfaceClass\{07B357BA-B46A-5072-A024-68A038054D72},
InterfaceClass\{AE9EB9C4-8819-51D8-879D-9A42FFB89D4E},InterfaceClass\
{4B8C50DD-9515-5A28-BCFD-A9ED2D92F273},AllItems}
System.Devices.NotWorkingProperly=False
System.Devices.IsShared=False
System.Devices.IsNetworkConnected=True
PKEY_DeviceDisplay_RequiresPairingElevation=False
PKEY_DeviceDisplay_Category={Multimedia.DMR}
PKEY_DeviceDisplay_PrimaryCategory=Multimedia.DMR
PKEY_DeviceDisplay_AlwaysShowDeviceAsConnected=False
System.Devices.HardwareIds={UMB\Sony_Corporation/SA-NS300/urn:schemas-upnp-org:device:MediaRenderer:1}
PnP.PnpObject.FindAllAsync(Pnp.PnpObjectType.Device) - 此方法检索有关构成 DeviceContainer
的各个设备的更详细信息。我的索尼 SA-NS300 Wi-Fi 扬声器是一个 DeviceContainer
,仅包含一个 Device
。(您可以通过其“System.Devices.ContainerId
”属性将 Device
与其 DeviceContainer
相关联。)
[PnpObject.FindAllAsync(Device)] - SA-NS300
System.ItemNameDisplay=SA-NS300
System.Devices.DeviceInstanceId=SWD\DAFUPnPProvider\uuid:5f9ec1b3-ed59-1900-4530-0007f521ebd6
System.Devices.ContainerId=5f9ec1b3-ed59-1900-4530-0007f521ebd6
System.Devices.IpAddress={192.168.0.122}
System.Devices.FriendlyName=SA-NS300
PKEY_Device_DevNodeStatus=25190410
PKEY_Device_ProblemCode=0
System.Devices.Parent=SWD\MSDAS\{ce958e9a-424f-4c88-86f4-11314821e75a}
PKEY_PNPX_CompatibleTypes={Sony Corporation/SA-NS300,urn:schemas-upnp-org:device:MediaRenderer:1}
PKEY_Device_BusReportedDeviceDesc=Network Speaker
System.Devices.Present=True
System.Devices.DeviceHasProblem=False
PKEY_PNPX_GlobalIdentity=uuid:5f9ec1b3-ed59-1900-4530-0007f521ebd6
PKEY_PNPX_Types={urn:schemas-upnp-org:device:MediaRenderer:1}
PKEY_PNPX_XAddrs={192.168.0.122:3911}
PKEY_PNPX_ID=uuid:5f9ec1b3-ed59-1900-4530-0007f521ebd6
System.Devices.Manufacturer=Sony Corporation
PKEY_PNPX_ManufacturerUrl=http://www.sony.net/
System.Devices.ModelName=SA-NS300
System.Devices.PresentationUrl=http://192.168.0.122/
PKEY_PNPX_DeviceCategory={MediaDevices}
PKEY_PNPX_PhysicalAddress={0,7,245,33,235,214}
PKEY_PNPX_NetworkInterfaceLuid=19984723346456576
PKEY_PNPX_NetworkInterfaceGuid=8761549f-f8b6-439a-aed1-6d7920306768
PKEY_SSDP_DevLifeTime=1800
PKEY_SSDP_NetworkInterface={0,0,0,0,159,84,97,135,182,248,154,67,174,209,109,
121,32,48,103,104,0,7,245,33,235,214,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,2,0,0,0,192,168,0,122,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0}
System.Devices.DiscoveryMethod={UPnP}
System.Devices.IsNetworkConnected=True
PKEY_DeviceDisplay_Category={Multimedia.DMR}
PKEY_Device_FriendlyNameAttributes=2
PKEY_Device_ManufacturerAttributes=1
System.Devices.InLocalMachineContainer=False
System.Devices.HardwareIds={UMB\Sony_Corporation/SA-NS300/urn:schemas-upnp-org:device:MediaRenderer:1}
System.Devices.CompatibleIds={UMB\urn:schemas-upnp-org:device:MediaRenderer:1,SWD\GenericRaw,SWD\Generic}
PKEY_Device_Class=SoftwareDevice
PKEY_Device_ClassGuid=62f9c741-b25a-46ce-b54c-9bccce08b6f2
PKEY_Device_Driver={62f9c741-b25a-46ce-b54c-9bccce08b6f2}\0010
PKEY_Device_ConfigFlags=0
PKEY_Device_Manufacturer=Sony Corporation
PKEY_Device_FriendlyName=SA-NS300
PKEY_Device_LocationInfo=http://192.168.0.122:8080/description.xml
PKEY_Device_PDOName=\Device\0000005d
System.Devices.DeviceCapabilities=244
PKEY_Device_BusTypeGuid=06d10322-7de0-4cef-8e25-197d0e7442e2
PKEY_Device_LegacyBusType=15
PKEY_Device_BusNumber=0
PKEY_Device_EnumeratorName=SWD
PKEY_Device_PowerData={56,0,0,0,1,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,1,0,0,0,4,0,0,0,4,0,0,0,4,0,0,0,4,0,0,0,4,0,0,0,0,0,0,0}
PKEY_Device_RemovalPolicy=2
PKEY_Device_RemovalPolicyDefault=2
PKEY_Device_InstallState=0
PKEY_Device_BaseContainerId=5f9ec1b3-ed59-1900-4530-0007f521ebd6
PKEY_Device_DriverDate=6/20/2006 5:00:00 PM -07:00
PKEY_Device_DriverVersion=6.2.9200.16384
PKEY_Device_DriverDesc=Generic software device
PKEY_Device_DriverInfPath=c_swdevice.inf
PKEY_Device_DriverInfSection=SoftwareDevice
PKEY_Device_MatchingDeviceId=SWD\GenericRaw
PKEY_Device_DriverProvider=Microsoft
PKEY_Device_DriverRank=16723969
PKEY_Device_NoConnectSound=True
System.Devices.SafeRemovalRequired=False
PKEY_DrvPkg_VendorWebSite=http://www.sony.net/
Pnp.PnpObject.FindAllAsync(Pnp.PnpObjectType.DeviceInterface, ...) - 每个设备公开一个或多个“接口”。您通过这些接口来实际控制它。例如,我的索尼 SA-NS300 扬声器有两个接口:ConnectionManager
(获取其支持的协议信息)和 AVTransport
(实际告诉它播放音频)。
[[PnpObject.FindAllAsync(DeviceInterface)] - SA-NS300
System.ItemNameDisplay=SA-NS300
System.Devices.IsDefault=False
System.Devices.Icon=C:\Windows\System32\DDORes.dll,-2363
System.Devices.ServiceId=urn:upnp-org:serviceId:AVTransport
System.Devices.InterfaceClassGuid=4c38e836-6a2f-5949-9406-1788ea20d1d5
System.Devices.DeviceInstanceId=SWD\DAFUPnPProvider\uuid:5f9ec1b3-ed59-1900-4530-0007f521ebd6
System.Devices.ContainerId=5f9ec1b3-ed59-1900-4530-0007f521ebd6
System.Devices.InterfaceEnabled=True
System.Devices.ServiceAddress={http://192.168.0.122:8080/AVTransport/ctrl}
PKEY_PNPX_ServiceTypes={urn:schemas-upnp-org:service:AVTransport:1}
PKEY_PNPX_ServiceControlUrl=http://192.168.0.122:8080/AVTransport/ctrl
PKEY_PNPX_ServiceDescUrl=http://192.168.0.122:8080/AVTransport/desc.xml
PKEY_PNPX_ServiceEventSubUrl=http://192.168.0.122:8080/AVTransport/evt
[PnpObject.FindAllAsync(DeviceInterface)] - SA-NS300
System.ItemNameDisplay=SA-NS300
System.Devices.IsDefault=False
System.Devices.Icon=C:\Windows\System32\DDORes.dll,-2363
System.Devices.ServiceId=urn:upnp-org:serviceId:ConnectionManager
System.Devices.InterfaceClassGuid=ae9eb9c4-8819-51d8-879d-9a42ffb89d4e
System.Devices.DeviceInstanceId=SWD\DAFUPnPProvider\uuid:5f9ec1b3-ed59-1900-4530-0007f521ebd6
System.Devices.ContainerId=5f9ec1b3-ed59-1900-4530-0007f521ebd6
System.Devices.InterfaceEnabled=True
System.Devices.ServiceAddress={http://192.168.0.122:8080/ConnectionManager/ctrl}
PKEY_PNPX_ServiceTypes={urn:schemas-upnp-org:service:ConnectionManager:1}
PKEY_PNPX_ServiceControlUrl=http://192.168.0.122:8080/ConnectionManager/ctrl
PKEY_PNPX_ServiceDescUrl=http://192.168.0.122:8080/ConnectionManager/desc.xml
PKEY_PNPX_ServiceEventSubUrl=http://192.168.0.122:8080/ConnectionManager/evt
Pnp.PnpObject.FindAllAsync(Pnp.PnpObjectType.DeviceInterfaceClass, ...) - 您从此查询中几乎得不到任何信息。它只会告诉您硬件的基本类别,例如:
[PnpObject.FindAllAsync(DeviceInterfaceClass)] - Gyrometer
System.ItemNameDisplay=Gyrometer
[PnpObject.FindAllAsync(DeviceInterfaceClass)] - Orientation sensor
System.ItemNameDisplay=Orientation sensor
Pnp.PnpObject.CreateFromIdAsync(..., id, ...) - 如果您已经有了 DeviceContainerId
,那么您可以使用此方法直接获取其信息(而不是进行查询)。同样,如果您有 DeviceInstanceId
,那么您可以获取一个设备。
属性列表和 AQS 过滤器
这是一个使用其中一个查询 API 的完整示例:
Dim PKEY_PNPX_ServiceControlUrl = "{656A3BB3-ECC0-43FD-8477-4AE0404A96CD},16388"
Dim props = {"System.Devices.DeviceInstanceId", "System.Devices.ServiceId", PKEY_PNPX_ServiceControlUrl}
Dim aqsFilter = "System.Devices.ServiceId:=""urn:upnp-org:serviceId:" & _
"ConnectionManager"" AND System.Devices.DeviceInstanceId:=""" & id & """"
Dim ifaces = Await Pnp.PnpObject.FindAllAsync(Pnp.PnpObjectType.DeviceInterface, props, aqsFilter)
我们已经看到了第一个参数 Pnp.PnpObjectType.DeviceInterface
,它确定了我们正在查询的对象类型(因此它可能返回的属性类型)。
第二个参数 props
是一个 IEnumerable(Of String)
。在这里,您必须显式列出您想要检索的属性。它只会返回您请求的属性信息。在这种情况下,我已经请求了三个属性。许多属性都有易于记住的字符串名称,例如前两个。但其他属性则不然,您必须使用它们的“规范名称”(由全大写的 GUID 和一个整数组成)来调用它们。规范名称都定义在 Windows SDK 的头文件中。我已经在附带的源代码中将它们全部写成了 VB 格式。
第三个可选参数 aqsFilter
是限制获取哪些结果的简便方法。在这种情况下,我的过滤器如下所示:
System.Devices.ServiceId:="..." AND System.Devices.DeviceInstanceId:="..."
请注意,您可以使用布尔连词,如 AND、OR 和 NOT;您可以使用括号;使用 := 进行比较;将字符串参数放在引号中;并将布尔参数写在引号外,例如:System.Devices.InterfaceEnabled:=true
。
关注点
设备枚举 API 将返回大量的搜索结果。会有大量来自几个月前连接到您家庭 Wi-Fi 的设备的旧结果。您必须在 DeviceContainer
中查找其 System.Devices.Connected
属性,以查看它是否仍然连接。
Windows 8 具有“配对”的概念。在某些情况下,您需要进入 Windows 8 控制面板并添加设备。这将把设备“配对”到您的计算机。本文中的 API 只会枚举已配对到您计算机的设备。
接下来是什么?您要用所有枚举到的信息做什么?... 我还不知道!我认为这关键取决于硬件的类型!
免责声明:尽管我在微软工作,但本文纯粹是我作为业余项目独立完成的。它超出了我的专业领域。我只是在学习。我与设备枚举团队没有任何联系。