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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2085179/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 23:23:59  来源:igfitidea点击:

How can I find out a COM port number of a bluetooth device in c#?

c#serial-portbluetooth

提问by ?ukasz Bownik

My company developed a device that communicates with a PC via Bluetooth using a virtual COM port.

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

Now we need a user to pair a device with a PC (MS Windows OS) first and then enter it's com port number manually into our application(I bet 95% of users will fail on this taks).

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

So I'd like my application to present a user with a list of paired bluetooth devices (a list of their "friendly names") and after that I'd like to find out the selecded device's COM port number automatically.

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

How can I do it in c#? (a solution independent of installed bluetooth stack is appreciated).

我怎样才能在 c# 中做到这一点?(独立于安装的蓝牙堆栈的解决方案值得赞赏)。

Thanks in advance.

提前致谢。

回答by alanjmcf

See my answer at Widcomm bluetooth : how to open the virtual COMfor my understanding of the licence: using the binary version is free for commercial use. And, also that I'm maintainer of the library.

请参阅我在Widcomm bluetooth 上的回答:如何打开虚拟 COM以了解许可证:使用二进制版本可免费用于商业用途。而且,我也是图书馆的维护者。

So a brief slight digression. I'm not a big fan of virtual COM ports. It always seems much easier to use a direct 'sockets' connection, rather than attempt to setup a COM port, and try to find what name it was created as (see below!), and then have to open a SerialPort to use it, and then if the connection is lost one doesn't know and have simply to keep retrying... With the library its so much easier to just to create and use that direct Bluetooth connection!

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

However you may want a solution to your current task at the moment. :-) So, use WMI to find the current COM ports in place and see if any of them are for your device. For example in PowerShell:

但是,您目前可能需要解决当前任务的方法。:-) 因此,请使用 WMI 查找当前的 COM 端口,并查看其中是否有任何适用于您的设备。例如在 PowerShell 中:

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

In that big long string one sees the address of the target device: 00803A686519. One can use WMI from .NET, run that query, filter the ones with "BTHENUM", and then parse out the address.

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

If you the do need to create a new Bluetooth virtual COM port, use 32feet.NET's BluetoothDeviceInfo.SetServiceState(BluetoothService.SerialPort) API. See the "Bluetooth Serial Ports" section in the User Guide e.g. at http://www.alanjmcf.me.uk/comms/bluetooth/32feet.NET%20--%20User%20Guide.html, and the class documentation in the release.

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

Unfortunately the native Win32 API we call does not tell what name of COM port it created! :-( So run the WMI query before and after the call to see what new name appeared (or use System.IO.Ports.SerialPort.GetPortNames as its simpler).

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

That's all specific to the Microsoft Bluetooth stack. I haven't investigated how other stacks behave in this regard. After a brief check Widcomm's serial ports appear in SerialPort.GetPortNames but not in the WMI query...

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

回答by alanjmcf

So, to get the information about a remote device including its name, using 32feet.NET do:

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

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

If not using the library you'll have to P/Invoke Win32's BluetoothGetDeviceInfo.

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

回答by Vic

Maybe it is not what you are looking for, and maybe you already found your answer...

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

I just found a question not exactly like yours but worked for me.. With this one you can find out which one of your COM Ports are from a Bluetooth device: StackOverflow - Determine if serial port is normal COM or SPP

我刚刚发现了一个与您不完全相同的问题,但对我有用.. 通过这个问题,您可以找出您的哪个 COM 端口来自蓝牙设备: StackOverflow - 确定串行端口是正常的 COM 还是 SPP

I hope it helps somehow. If you find out how to do what you wanted, please let me know. Thanks.

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

回答by Matt Williams

First, create a Management Object Searcher to search the WMI database:

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

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

Next, use LINQ to get all the serial ports into a query:

接下来,使用 LINQ 将所有串行端口获取到查询中:

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

You can now print all the COM ports, their friendly names and you can even filter through their PNPDeviceID's to find the bluetooth device address. Here's an example:

您现在可以打印所有 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);
        }
    }
}

回答by Tim

I manage to get the bluetooth name and the COM port by fiddling the registry key

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

The pseudo code to obtain the bluetooth information is below:

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

  • enumerate all the COM port available in the PNP
  • obtain the device classGuid
  • search the bluetooth address from the classGuid
  • when the bluetooth address is known, the bluetooth name can be obtained from the this registry SYSTEM\CurrentControlSet\Services\BTHPORT\Parameters\Devices
  • 枚举 PNP 中所有可用的 COM 端口
  • 获取设备类Guid
  • 从 classGuid 搜索蓝牙地址
  • 当蓝牙地址已知时,蓝牙名称可以从这个注册表中获取 SYSTEM\CurrentControlSet\Services\BTHPORT\Parameters\Devices

The code is below, just call the GetBluetoothPort(), it will return a list of bluetooth devices, and you could connect them by passing the COM port number to the SerialPort class

代码如下,只需调用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;
}

回答by CJ_

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