Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在C中查找有关通过USB连接的所有串行设备的信息#_C#_.net_Serial Port_Wmi - Fatal编程技术网

C# 在C中查找有关通过USB连接的所有串行设备的信息#

C# 在C中查找有关通过USB连接的所有串行设备的信息#,c#,.net,serial-port,wmi,C#,.net,Serial Port,Wmi,我的项目需要在连接到USB时检测特定设备。唯一可以识别此设备的方法是通过其说明/设备名称,而不是com端口。我发现执行正确功能的方法是使用WMI查询并检查name属性: ManagementObjectSearcher searcher = new ManagementObjectSearcher("Select * from WIN32_SerialPort"); foreach (ManagementObject port in searcher.Get())

我的项目需要在连接到USB时检测特定设备。唯一可以识别此设备的方法是通过其说明/设备名称,而不是com端口。我发现执行正确功能的方法是使用WMI查询并检查name属性:

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();
我在某处和其他地方读过许多文章,但都找不到令人满意的解决办法。有人能澄清为什么WIN32_SerialPort查询找不到我的其他设备吗?出于某种原因,它不被视为win32串行端口吗?
还有,有人能告诉我这个问题的解决方法吗?

我想我知道你在做什么,看看使用WMICodeCreator(链接到WMICodeCreator)生成的代码 从这篇文章

如何列出所有串行端口: 硬件供应商可以使用几种。正确编写的COM端口驱动程序应使用
端口(COM和LPT端口)
-类(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
}
请参阅-类的详细说明。您应该拥有识别设备所需的一切

为了确定端口号,我检查name属性并提取它。到目前为止,这一切都很好,但我不知道端口号是否保证包含在名称中。到目前为止,我还没有找到任何串行端口设备,名称中没有包含端口号

上述查询查找每个串行端口设备,无论它是蓝牙SPP、FTDI芯片、主板上的端口、扩展卡还是由某个调制解调器驱动程序(即Globetrotter GTM66xxW)生成的虚拟串行端口

要确定连接类型(蓝牙、usb等),您可以检查deviceid(查看deviceid的第一部分)。在这里,您还可以提取bt mac地址(注意:deviceid至少在Windows 7和Windows XP上看起来不同)

关于某些设备未与Win32_SerialPort一起列出的原因:
我怀疑这取决于驱动程序的实现,因为我有一些usb设备列出了它们的端口,而有些没有。

看到您想按“名称”搜索,我认为您需要遍历所有连接的设备并查询它们以获得产品名称

下面是迭代WinUSB设备的代码:

公共异步任务GetConnectedDeviceDefinitions(uint?vendorId,uint?productId)
{
返回等待任务。运行(()=>
{
var deviceDefinitions=新集合();
var spDeviceInterfaceData=新的spDeviceInterfaceData();
var spDeviceInfoData=新的spDeviceInfoData();
var spDeviceInterfaceDetailData=新的spDeviceInterfaceDetailData();
spDeviceInterfaceData.CbSize=(uint)Marshal.SizeOf(spDeviceInterfaceData);
spDeviceInfoData.CbSize=(uint)Marshal.SizeOf(spDeviceInfoData);
var guidString=ClassGuid.ToString();
var copyOfClassGuid=新Guid(guidString);
变量i=apicall.SetupDiGetClassDevs(参考copyOfClassGuid、IntPtr.Zero、IntPtr.Zero、apicall.DigcfDeviceinterface | apicall.DigcfPresent);
如果(IntPtr.Size==8)
{
spDeviceInterfaceDetailData.CbSize=8;
}
其他的
{
spDeviceInterfaceDetailData.CbSize=4+Marshal.SystemDefaultCharSize;
}
var x=-1;
while(true)
{
x++;
var issucess=APICalls.setupDienumDeviceInterface(i,IntPtr.Zero,ref copyOfClassGuid,(uint)x,ref spDeviceInterfaceData);
如果(!isSuccess)
{
var errorCode=Marshal.GetLastWin32Error();
if(errorCode==APICalls.ERROR\u无\u更多\u项)
{
打破
}
抛出新异常($“无法枚举设备。错误代码:{errorCode}”);
}
isSuccess=APICalls.SetupDiGetDeviceInterfaceDetail(i,参考spDeviceInterfaceData,参考spDeviceInterfaceDetailData,256,out,参考SPDeviceInfo数据);
WindowsDeviceBase.HandleError(isSuccess,“无法获取设备接口详细信息”);
//请注意,这是有点讨厌,但我们可以过滤视频和Pid的方式,我认为。。。
var vendorHex=vendorId?.ToString(“X”).ToLower().PadLeft(4,'0');
var productIdHex=productId?.ToString(“X”).ToLower().PadLeft(4,'0');
如果(vendorId.HasValue&!spDeviceInterfaceDetailData.DevicePath.ToLower().Contains(vendorHex))继续;
如果(productId.HasValue&&!spDeviceInterfaceDetailData.DevicePath.ToLower().Contains(productIdHex))继续;
var deviceDefinition=GetDeviceDefinition(spDeviceInterfaceDetailData.DevicePath);
添加(deviceDefinition);
}
Apicall.SetupDiDestroyDeviceInfo列表(i);
返回设备定义;
});
}
对于这些设备中的每一个,您都可以按如下方式查询设备:

var issucess=WinUsbApiCalls.WinUsb\u初始化(\u设备句柄,out var def
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
}
  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;
        });
    }
        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);
}