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

发布于 2024-08-18 09:16:50 字数 260 浏览 2 评论 0原文

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

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

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

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

提前致谢。

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

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).

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.

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

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

萌︼了一个春 2024-08-25 09:16:50

请参阅我的答案 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”过滤查询,然后解析出地址。

如果您确实需要创建新的蓝牙虚拟 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 查询中之后,其他堆栈的行为如何...

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

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!

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:

C:\> Get-WmiObject -query "select DeviceID,PNPDeviceID from Win32_SerialPort"
...
...
DeviceID         : COM66
PNPDeviceID      : BTHENUM\{00001101-0000-1000-8000-00805F9B34FB}\7&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.

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.

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).

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...

会傲 2024-08-25 09:16:50

首先,创建一个管理对象搜索器来搜索 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);
        }
    }
}

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

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

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

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:

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);
        }
    }
}
羅雙樹 2024-08-25 09:16:50

我设法通过修改注册表项来获取蓝牙名称和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;
}

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

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

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

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;
}
最笨的告白 2024-08-25 09:16:50

也许这不是您正在寻找的,也许您已经找到了答案...

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

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

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

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

泼猴你往哪里跑 2024-08-25 09:16:50

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

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

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

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

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.

给我一枪 2024-08-25 09:16:50
    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;
    }
    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;
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文