如何使用C#获取Windows「设备和打印机」中的设备名称
获取Windows「设备和打印机」中的非打印机设备名称
嘿,别着急,我完全理解你的困扰!要获取Windows「设备和打印机」里的那些非打印机设备名称(比如你的ATH-CKR35BT蓝牙耳机、ERGO M575鼠标这类),其实得找对Windows用来管理这些设备的逻辑——它们大多属于**设备容器(Device Container)**或者特定的外设接口类,我给你两种靠谱的方法:
方法1:通过WMI直接查询设备容器(最简便)
Windows的「设备和打印机」里显示的每个设备图标,本质对应一个设备容器(Device Container),WMI的Win32_DeviceContainer类直接提供了这些容器的名称,这是最直接的方式。
C#示例代码
using System; using System.Collections.Generic; using System.Management; public class DeviceContainerHelper { public static List<string> GetDeviceAndPrintersNames() { List<string> deviceNames = new List<string>(); // 查询所有设备容器,Name属性就是「设备和打印机」里显示的名称 string wmiQuery = "SELECT Name FROM Win32_DeviceContainer"; using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(wmiQuery)) { foreach (ManagementObject container in searcher.Get()) { string deviceName = container["Name"]?.ToString().Trim(); if (!string.IsNullOrEmpty(deviceName) && !deviceNames.Contains(deviceName)) { deviceNames.Add(deviceName); } } } return deviceNames; } }
说明
Win32_DeviceContainer的Name属性就是你在「设备和打印机」里看到的设备名称,比如“Xperia Z5”、“ERGO M575”- 如果你想要过滤掉打印机(因为你已经会获取打印机了),可以在查询里加条件:
WHERE NOT Name LIKE '%Printer%'(根据实际情况调整关键词) - 注意:需要以管理员权限运行程序,否则可能无法访问部分设备信息
方法2:使用Setup API枚举外设接口(更精准)
如果WMI的方法返回的结果不够精准,你可以用Windows原生的Setup API来枚举特定类的外设(比如蓝牙设备、HID输入设备、便携设备),然后获取它们的友好名称。
C#示例代码(P/Invoke调用Setup API)
using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; public class DeviceInterfaceHelper { // 「设备和打印机」中常见的外设类GUID private static readonly Guid GUID_DEVINTERFACE_HID = new Guid("{4D1E55B2-F16F-11CF-88CB-001111000030}"); // 鼠标、键盘等HID设备 private static readonly Guid GUID_BLUETOOTH_DEVICE = new Guid("{00001101-0000-1000-8000-00805F9B34FB}"); // 蓝牙设备 private static readonly Guid GUID_DEVINTERFACE_PORTABLE_DEVICE = new Guid("{6AC27878-A6FA-4155-BA85-F98F491D4F33}"); // 便携设备(如手机) // Setup API所需的结构体 [StructLayout(LayoutKind.Sequential)] private struct SP_DEVICE_INTERFACE_DATA { public int cbSize; public Guid InterfaceClassGuid; public int Flags; public IntPtr Reserved; } [StructLayout(LayoutKind.Sequential)] private struct SP_DEVINFO_DATA { public int cbSize; public Guid ClassGuid; public int DevInst; public IntPtr Reserved; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct SP_DEVICE_INTERFACE_DETAIL_DATA { public int cbSize; [MarshalAs(UnmanagedType.LPWStr)] public string DevicePath; } // P/Invoke函数声明 [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)] private static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, string Enumerator, IntPtr hwndParent, uint Flags); [DllImport("setupapi.dll", SetLastError = true)] private static extern bool SetupDiEnumDeviceInterfaces(IntPtr hDevInfo, IntPtr devInfo, ref Guid interfaceClassGuid, uint memberIndex, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData); [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)] private static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr hDevInfo, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData, IntPtr deviceInterfaceDetailData, uint deviceInterfaceDetailDataSize, out uint requiredSize, ref SP_DEVINFO_DATA deviceInfoData); [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)] private static extern bool SetupDiGetDeviceRegistryProperty(IntPtr hDevInfo, ref SP_DEVINFO_DATA deviceInfoData, uint property, out uint propertyRegDataType, StringBuilder propertyBuffer, uint propertyBufferSize, out uint requiredSize); // 常量定义 private const uint DIGCF_PRESENT = 0x00000002; private const uint DIGCF_DEVICEINTERFACE = 0x00000010; private const uint SPDRP_FRIENDLYNAME = 0x0000000C; // 设备友好名称 public static List<string> GetPeripheralDeviceNames() { List<string> deviceNames = new List<string>(); List<Guid> targetClasses = new List<Guid> { GUID_DEVINTERFACE_HID, GUID_BLUETOOTH_DEVICE, GUID_DEVINTERFACE_PORTABLE_DEVICE }; foreach (Guid classGuid in targetClasses) { // 获取当前存在的设备接口集合 IntPtr hDevInfo = SetupDiGetClassDevs(ref classGuid, null, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (hDevInfo == IntPtr.Zero) continue; SP_DEVICE_INTERFACE_DATA interfaceData = new SP_DEVICE_INTERFACE_DATA(); interfaceData.cbSize = Marshal.SizeOf(interfaceData); SP_DEVINFO_DATA devInfoData = new SP_DEVINFO_DATA(); devInfoData.cbSize = Marshal.SizeOf(devInfoData); uint index = 0; while (SetupDiEnumDeviceInterfaces(hDevInfo, IntPtr.Zero, ref classGuid, index, ref interfaceData)) { // 获取设备接口详情的缓冲区大小 uint requiredSize = 0; SetupDiGetDeviceInterfaceDetail(hDevInfo, ref interfaceData, IntPtr.Zero, 0, out requiredSize, ref devInfoData); // 分配缓冲区并获取详情 IntPtr detailPtr = Marshal.AllocHGlobal((int)requiredSize); Marshal.WriteInt32(detailPtr, IntPtr.Size == 8 ? 8 : 4); // 适配32/64位系统 if (SetupDiGetDeviceInterfaceDetail(hDevInfo, ref interfaceData, detailPtr, requiredSize, out requiredSize, ref devInfoData)) { // 获取设备友好名称 StringBuilder friendlyName = new StringBuilder(256); uint propType; uint nameSize = 0; if (SetupDiGetDeviceRegistryProperty(hDevInfo, ref devInfoData, SPDRP_FRIENDLYNAME, out propType, friendlyName, (uint)friendlyName.Capacity, out nameSize)) { string name = friendlyName.ToString().Trim(); if (!string.IsNullOrEmpty(name) && !deviceNames.Contains(name)) { deviceNames.Add(name); } } } Marshal.FreeHGlobal(detailPtr); index++; } Marshal.FreeHGlobal(hDevInfo); } return deviceNames; } }
说明
- 这段代码枚举了三类常见的外设:HID输入设备、蓝牙设备、便携设备,覆盖了「设备和打印机」里的大部分非打印机设备
SPDRP_FRIENDLYNAME属性就是设备在界面上显示的名称- 同样需要管理员权限运行,确保能访问所有设备信息
补充提示
- 如果你用的是C++,逻辑和上面的Setup API方法一致,直接调用原生的Setup API函数即可
- 两种方法都可以去重,避免重复的设备名称(比如同一个设备可能有多个接口,但显示同一个名称)
内容的提问来源于stack exchange,提问作者Shiranui
相关产品推荐
相关产品推荐

