我的项目需要在连接到USB时检测特定设备。我可以识别此设备的唯一方法是通过其描述/设备名称,而不是com端口。我发现执行正确的功能是使用WMI查询并检查名称属性:
ManagementObjectSearcher searcher = new ManagementObjectSearcher("Select * from WIN32_SerialPort");
foreach (ManagementObject port in searcher.Get())
{
deviceName = (string)foundPort.GetPropertyValue("Name");
...
我最初通过连接手机对此进行了测试,查询按预期返回了COM3上找到的手机。然后,我连接了另一个设备(一个USB到串行转换器,它更像我需要这个项目的设备),查询根本找不到它。它只能找到手机。但是,此设备显示在设备管理器中的端口COM4上。为了让我更加讨厌,SerialPort类找到了两个设备,但它没有提供识别设备所需的信息:
string[] tempPorts = SerialPort.GetPortNames();
我已经在SO和其他地方阅读过很多线程,但找不到满意的解决方案。有人可以澄清为什么WIN32_SerialPort查询找不到我的其他设备?出于某种原因它不被认为是win32串口吗? 并且,有人可以指出我解决这个问题的方向吗?
答案 0 :(得分:22)
硬件供应商可以使用多个System-Defined Device Setup Classes。正确编写的COM-Ports
驱动程序应使用Ports (COM & LPT ports)
- 类(guid:4d36e978-e325-11ce-bfc1-08002be10318
)。该类也可能由设备管理器使用。
因此,您可以使用以下查询列出您在devicemanager中看到的每个串口:
ManagementObjectSearcher searcher = new ManagementObjectSearcher(
"root\\CIMV2",
"SELECT * FROM Win32_PnPEntity WHERE ClassGuid=\"{4d36e978-e325-11ce-bfc1-08002be10318}\""
);
foreach (ManagementObject queryObj in searcher.Get())
{
// do what you like with the Win32_PnpEntity
}
请参阅Win32_PnPEntity课程的详细说明。您应该拥有识别设备所需的一切。
为了确定端口号,我检查了name属性并将其解压缩。到目前为止,这种方法很好,但我不知道端口号是否保证包含在名称中。到目前为止,我还没有找到任何串口设备,但名称中没有包含端口号。
以上查询查找每个串口设备,无论是蓝牙SPP,FTDI芯片,主板上的端口,扩展卡还是某些调制解调器驱动程序生成的虚拟串口(即Globetrotter GTM66xxW)
要确定连接类型(蓝牙,USB等),您可以检查deviceid(查看deviceid的第一部分)。在那里你也可以提取bt-mac地址(注意:至少在Windows 7和Windows XP上,deviceid看起来不同)。
我怀疑这取决于驱动程序的实现,因为我有一些usb设备可以列出他们的端口,而有些设备不会。
答案 1 :(得分:5)
我想我知道你要做什么,看看使用WMICodeCreator制作的代码(链接到WMICodeCreator http://www.microsoft.com/en-us/download/details.aspx?id=8572) 来自这篇文章http://www.codeproject.com/Articles/32330/A-Useful-WMI-Tool-How-To-Find-USB-to-Serial-Adapto
//Below is code pasted from WMICodeCreator
try
{
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("root\\WMI",
"SELECT * FROM MSSerial_PortName");
foreach (ManagementObject queryObj in searcher.Get())
{
Console.WriteLine("-----------------------------------");
Console.WriteLine("MSSerial_PortName instance");
Console.WriteLine("-----------------------------------");
Console.WriteLine("InstanceName: {0}", queryObj["InstanceName"]);
Console.WriteLine("-----------------------------------");
Console.WriteLine("MSSerial_PortName instance");
Console.WriteLine("-----------------------------------");
Console.WriteLine("PortName: {0}", queryObj["PortName"]);
//If the serial port's instance name contains USB
//it must be a USB to serial device
if (queryObj["InstanceName"].ToString().Contains("USB"))
{
Console.WriteLine(queryObj["PortName"] + "
is a USB to SERIAL adapter/converter");
}
}
}
catch (ManagementException e)
{
MessageBox.Show("An error occurred while querying for WMI data: " + e.Message);
}
答案 2 :(得分:0)
看到您要按“名称”进行搜索,我认为您需要遍历所有连接的设备并查询它们以获得产品名称。
以下是通过WinUSB设备进行迭代的代码:
public async Task<IEnumerable<DeviceDefinition>> GetConnectedDeviceDefinitions(uint? vendorId, uint? productId)
{
return await Task.Run<IEnumerable<DeviceDefinition>>(() =>
{
var deviceDefinitions = new Collection<DeviceDefinition>();
var spDeviceInterfaceData = new SpDeviceInterfaceData();
var spDeviceInfoData = new SpDeviceInfoData();
var spDeviceInterfaceDetailData = new SpDeviceInterfaceDetailData();
spDeviceInterfaceData.CbSize = (uint)Marshal.SizeOf(spDeviceInterfaceData);
spDeviceInfoData.CbSize = (uint)Marshal.SizeOf(spDeviceInfoData);
var guidString = ClassGuid.ToString();
var copyOfClassGuid = new Guid(guidString);
var i = APICalls.SetupDiGetClassDevs(ref copyOfClassGuid, IntPtr.Zero, IntPtr.Zero, APICalls.DigcfDeviceinterface | APICalls.DigcfPresent);
if (IntPtr.Size == 8)
{
spDeviceInterfaceDetailData.CbSize = 8;
}
else
{
spDeviceInterfaceDetailData.CbSize = 4 + Marshal.SystemDefaultCharSize;
}
var x = -1;
while (true)
{
x++;
var isSuccess = APICalls.SetupDiEnumDeviceInterfaces(i, IntPtr.Zero, ref copyOfClassGuid, (uint)x, ref spDeviceInterfaceData);
if (!isSuccess)
{
var errorCode = Marshal.GetLastWin32Error();
if (errorCode == APICalls.ERROR_NO_MORE_ITEMS)
{
break;
}
throw new Exception($"Could not enumerate devices. Error code: {errorCode}");
}
isSuccess = APICalls.SetupDiGetDeviceInterfaceDetail(i, ref spDeviceInterfaceData, ref spDeviceInterfaceDetailData, 256, out _, ref spDeviceInfoData);
WindowsDeviceBase.HandleError(isSuccess, "Could not get device interface detail");
//Note this is a bit nasty but we can filter Vid and Pid this way I think...
var vendorHex = vendorId?.ToString("X").ToLower().PadLeft(4, '0');
var productIdHex = productId?.ToString("X").ToLower().PadLeft(4, '0');
if (vendorId.HasValue && !spDeviceInterfaceDetailData.DevicePath.ToLower().Contains(vendorHex)) continue;
if (productId.HasValue && !spDeviceInterfaceDetailData.DevicePath.ToLower().Contains(productIdHex)) continue;
var deviceDefinition = GetDeviceDefinition(spDeviceInterfaceDetailData.DevicePath);
deviceDefinitions.Add(deviceDefinition);
}
APICalls.SetupDiDestroyDeviceInfoList(i);
return deviceDefinitions;
});
}
对于这些设备中的每一个,您都可以这样查询设备:
https://github.com/MelbourneDeveloper/Device.Net/blob/master/src/Usb.Net/Windows/WindowsUsbDevice.cs
var isSuccess = WinUsbApiCalls.WinUsb_Initialize(_DeviceHandle, out var defaultInterfaceHandle);
HandleError(isSuccess, "Couldn't initialize device");
var bufferLength = (uint)Marshal.SizeOf(typeof(USB_DEVICE_DESCRIPTOR));
isSuccess = WinUsbApiCalls.WinUsb_GetDescriptor(defaultInterfaceHandle, WinUsbApiCalls.DEFAULT_DESCRIPTOR_TYPE, 0, EnglishLanguageID, out _UsbDeviceDescriptor, bufferLength, out var lengthTransferred);
HandleError(isSuccess, "Couldn't get device descriptor");
if (_UsbDeviceDescriptor.iProduct > 0)
{
//Get the product name
var buffer = new byte[256];
isSuccess = WinUsbApiCalls.WinUsb_GetDescriptor(defaultInterfaceHandle, WinUsbApiCalls.USB_STRING_DESCRIPTOR_TYPE, _UsbDeviceDescriptor.iProduct, 1033, buffer, (uint)buffer.Length, out var transfered);
HandleError(isSuccess, "Couldn't get product name");
Product = new string(Encoding.Unicode.GetChars(buffer, 2, (int)transfered));
Product = Product.Substring(0, Product.Length - 1);
}
public static partial class WinUsbApiCalls
{
public const uint DEVICE_SPEED = 1;
public const byte USB_ENDPOINT_DIRECTION_MASK = 0X80;
public const int WritePipeId = 0x80;
/// <summary>
/// Not sure where this constant is defined...
/// </summary>
public const int DEFAULT_DESCRIPTOR_TYPE = 0x01;
public const int USB_STRING_DESCRIPTOR_TYPE = 0x03;
[DllImport("winusb.dll", SetLastError = true)]
public static extern bool WinUsb_ControlTransfer(IntPtr InterfaceHandle, WINUSB_SETUP_PACKET SetupPacket, byte[] Buffer, uint BufferLength, ref uint LengthTransferred, IntPtr Overlapped);
[DllImport("winusb.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool WinUsb_GetAssociatedInterface(SafeFileHandle InterfaceHandle, byte AssociatedInterfaceIndex, out SafeFileHandle AssociatedInterfaceHandle);
[DllImport("winusb.dll", SetLastError = true)]
public static extern bool WinUsb_GetDescriptor(SafeFileHandle InterfaceHandle, byte DescriptorType, byte Index, ushort LanguageID, out USB_DEVICE_DESCRIPTOR deviceDesc, uint BufferLength, out uint LengthTransfered);
[DllImport("winusb.dll", SetLastError = true)]
public static extern bool WinUsb_GetDescriptor(SafeFileHandle InterfaceHandle, byte DescriptorType, byte Index, UInt16 LanguageID, byte[] Buffer, UInt32 BufferLength, out UInt32 LengthTransfered);
[DllImport("winusb.dll", SetLastError = true)]
public static extern bool WinUsb_Free(SafeFileHandle InterfaceHandle);
[DllImport("winusb.dll", SetLastError = true)]
public static extern bool WinUsb_Initialize(SafeFileHandle DeviceHandle, out SafeFileHandle InterfaceHandle);
[DllImport("winusb.dll", SetLastError = true)]
public static extern bool WinUsb_QueryDeviceInformation(IntPtr InterfaceHandle, uint InformationType, ref uint BufferLength, ref byte Buffer);
[DllImport("winusb.dll", SetLastError = true)]
public static extern bool WinUsb_QueryInterfaceSettings(SafeFileHandle InterfaceHandle, byte AlternateInterfaceNumber, out USB_INTERFACE_DESCRIPTOR UsbAltInterfaceDescriptor);
[DllImport("winusb.dll", SetLastError = true)]
public static extern bool WinUsb_QueryPipe(SafeFileHandle InterfaceHandle, byte AlternateInterfaceNumber, byte PipeIndex, out WINUSB_PIPE_INFORMATION PipeInformation);
[DllImport("winusb.dll", SetLastError = true)]
public static extern bool WinUsb_ReadPipe(SafeFileHandle InterfaceHandle, byte PipeID, byte[] Buffer, uint BufferLength, out uint LengthTransferred, IntPtr Overlapped);
[DllImport("winusb.dll", SetLastError = true)]
public static extern bool WinUsb_SetPipePolicy(IntPtr InterfaceHandle, byte PipeID, uint PolicyType, uint ValueLength, ref uint Value);
[DllImport("winusb.dll", SetLastError = true)]
public static extern bool WinUsb_WritePipe(SafeFileHandle InterfaceHandle, byte PipeID, byte[] Buffer, uint BufferLength, out uint LengthTransferred, IntPtr Overlapped);
}
答案 3 :(得分:0)
亚历克斯的回答确实帮助了我。但是我不得不根据我的机器调整查询...
我不得不查询“ root \ CIMV2”,但是我不得不从另一个表中选择所有行:“ SELECT * FROM Win32_SerialPort”。
对于任何想弄清楚如何使用WMI或管理对象搜索器的人,Microsoft的WMI Code Creator确实救了我。使用该应用程序,您可以查询WMI以获取其他信息,以便确定要在“管理对象搜索器”查询中添加的内容。
链接可能会在未来过期,但现在是2020年:
https://www.microsoft.com/en-us/download/details.aspx?id=8572