如何在 C# 中找出蓝牙设备的 COM 端口号?

Posted

技术标签:

【中文标题】如何在 C# 中找出蓝牙设备的 COM 端口号?【英文标题】:How can I find out a COM port number of a bluetooth device in c#? 【发布时间】:2010-01-18 10:05:02 【问题描述】:

我的公司开发了一种使用虚拟 COM 端口通过蓝牙与 PC 通信的设备。

现在我们需要用户先将设备与 PC(MS Windows 操作系统)配对,然后手动将其 com 端口号输入到我们的应用程序中(我敢打赌 95% 的用户会在此任务中失败)。

所以我希望我的应用程序向用户显示配对的蓝牙设备列表(他们的“友好名称”列表),然后我想自动找出所选设备的 COM 端口号。

如何在 C# 中做到这一点? (赞赏独立于已安装蓝牙堆栈的解决方案)。

提前致谢。

【问题讨论】:

【参考方案1】:

请参阅我在Widcomm bluetooth : how to open the virtual COM 的回答以了解我对许可证的理解:使用二进制版本可免费用于商业用途。而且,我也是图书馆的维护者。

所以,一个简短的题外话。我不是虚拟 COM 端口的忠实粉丝。使用直接“套接字”连接似乎总是容易得多,而不是尝试设置 COM 端口,并尝试找到它的创建名称(见下文!),然后必须打开一个 SerialPort 才能使用它,然后如果连接丢失,一个人不知道并且只需要继续重试......有了这个库,创建和使用直接的蓝牙连接就容易多了!

但是,您目前可能需要解决当前任务的方法。 :-) 所以,使用 WMI 查找当前的 COM 端口,看看它们中的任何一个是否适用于您的设备。例如在 PowerShell 中:

C:\> Get-WmiObject -query "select DeviceID,PNPDeviceID from Win32_SerialPort"
...
...
DeviceID         : COM66
PNPDeviceID      : BTHENUM\00001101-0000-1000-8000-00805F9B34FB\7&1D80ECD3&0&00803A686519_C00000003

在那个大长字符串中,可以看到目标设备的地址:00803A686519。可以使用 .NET 中的 WMI,运行该查询,过滤带有“BTHENUM”的查询,然后解析出地址。

如果您确实需要创建新的蓝牙虚拟 COM 端口,请使用 32feet.NET 的 BluetoothDeviceInfo.SetServiceState(BluetoothService.SerialPort) API。请参阅用户指南中的“蓝牙串行端口”部分,例如http://www.alanjmcf.me.uk/comms/bluetooth/32feet.NET%20--%20User%20Guide.html,以及发布中的类文档。

不幸的是,我们调用的本机 Win32 API 并没有告诉它创建的 COM 端口的名称! :-( 所以在调用之前和之后运行 WMI 查询以查看出现了什么新名称(或使用 System.IO.Ports.SerialPort.GetPortNames 更简单)。

这都是 Microsoft 蓝牙堆栈特有的。我还没有调查其他堆栈在这方面的行为。经过简短的检查,Widcomm 的串行端口出现在 SerialPort.GetPortNames 但不在 WMI 查询中...

【讨论】:

我可以找到配对蓝牙设备的友好名称,我可以将它们与这些 com 端口号匹配。那我就满足了:) 你怎么知道哪个 COM 是输入,哪个是输出(无需等待错误尝试!) 我有一个配对的 BLE 设备。为什么我的列表是空的?【参考方案2】:

首先,创建一个管理对象搜索器来搜索 WMI 数据库:

ManagementObjectSearcher serialSearcher =
                new ManagementObjectSearcher("root\\CIMV2",
                "SELECT * FROM Win32_SerialPort");

接下来,使用 LINQ 将所有串行端口放入一个查询中:

var query = from ManagementObject s in serialSearcher.Get()
            select new  Name = s["Name"], DeviceID = s["DeviceID"], PNPDeviceID = s["PNPDeviceID"] ; // DeviceID -- > PNPDeviceID

您现在可以打印所有 COM 端口及其友好名称,甚至可以过滤它们的 PNPDeviceID 以查找蓝牙设备地址。这是一个例子:

foreach (var port in query)

    Console.WriteLine("0 - 1", port.DeviceID, port.Name);
    var pnpDeviceId = port.PNPDeviceID.ToString();

    if(pnpDeviceId.Contains("BTHENUM"))
    
        var bluetoothDeviceAddress = pnpDeviceId.Split('&')[4].Split('_')[0];
        if (bluetoothDeviceAddress.Length == 12 && bluetoothDeviceAddress != "000000000000")
        
            Console.WriteLine(" - Address: 0", bluetoothDeviceAddress);
        
    

【讨论】:

谢谢,不知道Mac地址在PNPDeviceId参数里面,正是我需要的。【参考方案3】:

我设法通过修改注册表项来获取蓝牙名称和 COM 端口

获取蓝牙信息的伪代码如下:

枚举 PNP 中所有可用的 COM 端口 获取设备classGuid 从classGuid中搜索蓝牙地址 当蓝牙地址已知时,可以从这个注册表SYSTEM\CurrentControlSet\Services\BTHPORT\Parameters\Devices获取蓝牙名称

代码如下,只要调用GetBluetoothPort(),它会返回一个蓝牙设备列表,你可以通过将COM端口号传递给SerialPort类来连接它们

public static string[] GetBluetoothPort()

    Regex regexPortName = new Regex(@"(COM\d+)");

    List<string> portList = new List<string>();

    ManagementObjectSearcher searchSerial = new ManagementObjectSearcher("SELECT * FROM Win32_PnPEntity");

    foreach (ManagementObject obj in searchSerial.Get()) 
        string name = obj["Name"] as string;
        string classGuid = obj["ClassGuid"] as string;
        string deviceID = obj["DeviceID"] as string;

        if (classGuid != null && deviceID != null) 
            if (String.Equals(classGuid, "4d36e978-e325-11ce-bfc1-08002be10318", StringComparison.InvariantCulture)) 
                string[] tokens = deviceID.Split('&');

                if (tokens.Length >= 4) 
                    string[] addressToken = tokens[4].Split('_');
                    string bluetoothAddress = addressToken[0];

                    Match m = regexPortName.Match(name);
                    string comPortNumber = "";
                    if (m.Success) 
                        comPortNumber = m.Groups[1].ToString();
                    

                    if (Convert.ToUInt64(bluetoothAddress, 16) > 0) 
                        string bluetoothName = GetBluetoothRegistryName(bluetoothAddress);
                        portList.Add(String.Format("0 1 (2)", bluetoothName, bluetoothAddress, comPortNumber));
                    
                
                                
        
    

    return portList.ToArray();


private static string GetBluetoothRegistryName(string address)

    string deviceName = "";

    string registryPath = @"SYSTEM\CurrentControlSet\Services\BTHPORT\Parameters\Devices";
    string devicePath = String.Format(@"0\1", registryPath, address);

    using (RegistryKey key = Registry.LocalMachine.OpenSubKey(devicePath)) 
        if (key != null) 
            Object o = key.GetValue("Name");

            byte[] raw = o as byte[];

            if (raw != null) 
                deviceName = Encoding.ASCII.GetString(raw);
            
        
    

    return deviceName;

【讨论】:

【参考方案4】:

也许这不是你要找的,也许你已经找到了答案……

我刚刚发现了一个与您的问题不完全一样但对我有用的问题。通过这个问题,您可以找出您的哪个 COM 端口来自蓝牙设备: *** - Determine if serial port is normal COM or SPP

我希望它会有所帮助。如果你知道如何做你想做的事,请告诉我。谢谢。

【讨论】:

【参考方案5】:

因此,要使用 32feet.NET 获取有关远程设备的信息,包括其名称,请执行以下操作:

BluetoothAddress addr = ... ...
BluetoothDeviceInfo info = new BluetoothDeviceInfo(addr);
string name = info.DeviceName;

如果不使用该库,则必须 P/Invoke Win32 的 BluetoothGetDeviceInfo。

【讨论】:

好的-但是BluetoothGetDeviceInfo需要一个无线电句柄和BluetoothFindFirstRadio仅适用于Microsoft堆栈:(。我需要堆栈独立性。据我所知,32feet.NET的stabel版本支持olny Microsoft堆栈:(跨度> 我们同时支持 MSFT 和 Widcomm; Widcomm 从 2.4 版开始。 2.5今天发布并且稳定。只是因为我胆小,2.4才叫beta,质量不错。 :-,) 在 MSFT API 要求无线电句柄的大多数情况下,您可以传递 NULL —— 我们将 NULL 传递给该函数。顺便说一句,上面的 WMI 查询仅显示 MSFT 端口,我目前看不到任何 Widcomm 端口——但 SerialPort.GetPortNames() 确实包含 Widcomm 端口的名称...【参考方案6】:
    private static string FindSerialPortForRFIDReaderCore()
    
        string serialPort = "";

        List<string> ports = new List<string>();

        System.Management.ManagementObjectSearcher Searcher = new System.Management.ManagementObjectSearcher("Select * from WIN32_SerialPort");

        foreach (System.Management.ManagementObject Port in Searcher.Get())
        
            if (Port["PNPDeviceID"].ToString().ToUpper().Contains("MacAddress")) 
                ports.Add(Port["DeviceID"].ToString());
        

        if (ports.Count > 1) // There are more than one Serial Ports created for the bluetooth device.
            serialPort = ports.OrderByDescending(p => p).FirstOrDefault();
        else if(ports.Count == 1)
            serialPort = ports[0];


        return serialPort;
    

【讨论】:

以上是关于如何在 C# 中找出蓝牙设备的 COM 端口号?的主要内容,如果未能解决你的问题,请参考以下文章

C#:蓝牙串口读数据和写数据

C#如何将COM端口更改为指定的端口

如何使用Android蓝牙开发

如何使用Android蓝牙开发

如何使用 C# 在 WinForm 中手动绑定到蓝牙低功耗设备?

获取串口映射的COM端口号