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

41,618

Solution 1

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

Solution 2

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

Solution 3

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

Solution 4

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.

Share:
41,618
JPN
Author by

JPN

mainly Java programer, a c# experience, Sematic Web technologies experience, a little HTML/CSS/JavaScript experience, GWT experience, a little Flex experience

Updated on July 09, 2022

Comments

  • JPN
    JPN almost 2 years

    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.

  • JPN
    JPN over 14 years
    I I could find out the friendly names of paired bluetooth devices I could match them with those com port numbers. Then I'd be satisfied :)
  • JPN
    JPN over 14 years
    ok - but BluetoothGetDeviceInfo needs a radio handle ang BluetoothFindFirstRadio works only with Microsoft stack :(. I need stack independency. As far as I see stabel version of 32feet.NET supports olny Microsoft stack :(
  • alanjmcf
    alanjmcf over 14 years
    We support both MSFT and Widcomm; Widcomm from version 2.4 onward. 2.5 was released today and is stable. Only by my timidity was 2.4 called beta, it was good quality. :-,) You can pass NULL in most cases where the MSFT API asks for a radio handle -- we pass NULL to that function. BTW the WMI query above shows the MSFT ports only, I don't see any Widcomm ports in it at the moment -- but SerialPort.GetPortNames() does include the name of a Widcomm port...
  • Tomer W
    Tomer W over 8 years
    How would you know which COM is the Input and which is the Output (without waiting on an error trying!)
  • shashwat
    shashwat almost 8 years
    I've a paired BLE device. Why my list is empty ?
  • Starwave
    Starwave over 3 years
    Thank you, didn't know Mac address was inside PNPDeviceId param, just what I needed.