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

时间:2010-01-18 10:05:03

标签: c# serial-port bluetooth

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

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

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

我怎样才能在c#中做到这一点? (非常感谢安装蓝牙堆栈的解决方案。)

提前致谢。

6 个答案:

答案 0 :(得分:9)

请参阅我在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作为其更简单)。

这些都是微软蓝牙堆栈特有的。我还没有研究过其他堆栈在这方面的表现。经过简单检查后,Widcomm的串口出现在SerialPort.GetPortNames中,但不出现在WMI查询中......

答案 1 :(得分:4)

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

答案 2 :(得分: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;
}

答案 3 :(得分:1)

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

我刚发现一个与你不完全相同的问题,但为我工作..有了这个,你可以找到你的哪个COM端口来自蓝牙设备: StackOverflow - Determine if serial port is normal COM or SPP

我希望它有所帮助。如果您发现如何做您想做的事,请告诉我。感谢。

答案 4 :(得分:0)

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

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

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

答案 5 :(得分: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;
    }