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

16

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

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

因此,我希望我的应用程序向用户展示已配对蓝牙设备的列表(它们的“友好名称”列表),然后自动查找所选设备的COM端口号。

如何在C#中实现此功能? (独立于安装的蓝牙堆栈的解决方案将不胜感激)。

提前致谢。

6个回答

9
请参考我在Widcomm蓝牙:如何打开虚拟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”的设备,然后解析出地址。
如果需要创建一个新的蓝牙虚拟串口,请使用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 Bluetooth堆栈的。我还没有研究其他堆栈在这方面的行为。经过简要检查,Widcomm的串行端口出现在SerialPort.GetPortNames中,但未出现在WMI查询中...

如果我能找到配对的蓝牙设备的友好名称,我就可以将它们与相应的COM端口号匹配。那样的话,我就会满意了 :) - Łukasz Bownik
1
你如何知道哪个COM口是输入,哪个是输出(而不必等待错误尝试!) - Tomer W
我有一个配对的BLE设备。为什么我的列表是空的? - shashwat

5

首先,创建一个管理对象搜索器来搜索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”参数中,这正是我需要的。 - Starwave

2
我通过修改注册表键值成功获取了蓝牙名称和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;
}

1

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

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

希望它能在某种程度上帮助你。如果你找到了想要的方法,请告诉我。谢谢。


0

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

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

如果不使用库,您将需要 P/Invoke Win32 的 BluetoothGetDeviceInfo。


好的 - 但是BluetoothGetDeviceInfo需要一个无线电句柄,而BluetoothFindFirstRadio仅适用于Microsoft堆栈 :(。我需要堆栈独立性。 就我所看到的,32feet.NET的稳定版本仅支持Microsoft堆栈 :( - Łukasz Bownik
我们支持MSFT和Widcomm;从2.4版本开始支持Widcomm。今天发布了2.5版本,非常稳定。只是因为我的胆怯,2.4被称为beta版,但它的质量很好。:-,)在大多数情况下,当MSFT API要求无线电句柄时,您可以传递NULL--我们将NULL传递给该函数。顺便说一下,上面的WMI查询仅显示MSFT端口,我目前没有看到任何Widcomm端口--但SerialPort.GetPortNames()确实包括一个Widcomm端口的名称... - alanjmcf

0
    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;
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接