My company developed a device that communicates with a PC via Bluetooth using a virtual COM port.
我的公司开发了一种通过蓝牙与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 OS)配对,然后手动输入它的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.
因此,我希望我的应用程序可以向用户提供一组配对的蓝牙设备列表(它们的“友好名称”列表),然后我将自动找到selecded设备的COM端口号。
How can I do it in c#? (a solution independent of installed bluetooth stack is appreciated).
我怎么用c#来做呢?(一个独立于安装的蓝牙栈的解决方案被欣赏)。
Thanks in advance.
提前谢谢。
6 个解决方案
#1
8
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.
在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端口,并试图找到什么名字是创建(见下文),然后需要打开串口使用它,然后如果连接是失去了一个不知道,只是保持重试…有了图书馆,就更容易创建和使用直接的蓝牙连接!
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}\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.
在那个大的长串中,你可以看到目标设备的地址: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端口,请使用32英尺。净的BluetoothDeviceInfo.SetServiceState(BluetoothService.SerialPort)API。请参阅用户指南中的“蓝牙串行端口”部分,如http://www.alanjmcf.s.uk/comms/bluetooth/32feet.net%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...
这都是针对微软的蓝牙栈。我还没有研究其他栈在这方面的表现。在一个简短的检查之后,Widcomm的串行端口出现在SerialPort中。GetPortNames而不是WMI查询中…
#2
3
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的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);
}
}
}
#3
1
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: * - Determine if serial port is normal COM or SPP
我刚发现一个问题,跟你的不太一样,但对我很有效。通过这个,您可以发现您的COM端口来自于蓝牙设备:*——确定串行端口是普通的COM还是SPP。
I hope it helps somehow. If you find out how to do what you wanted, please let me know. Thanks.
我希望它能有所帮助。如果你知道如何做你想做的事,请告诉我。谢谢。
#4
1
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
- 枚举PNP中可用的所有COM端口。
- obtain the device classGuid
- 获取设备classGuid
- search the bluetooth address from the classGuid
- 从classGuid搜索蓝牙地址。
- when the bluetooth address is known, the bluetooth name can be obtained from the this registry
SYSTEM\CurrentControlSet\Services\BTHPORT\Parameters\Devices
- 当蓝牙地址被知道时,蓝牙名称可以从这个注册表系统\CurrentControlSet\ \ \ \ \ \ \ \ \ \ \设备。
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;
}
#5
0
So, to get the information about a remote device including its name, using 32feet.NET do:
所以,要获取一个远程设备的信息,包括它的名字,使用32英尺。净做:
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/调用Win32的BluetoothGetDeviceInfo。
#6
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;
}
#1
8
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.
在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端口,并试图找到什么名字是创建(见下文),然后需要打开串口使用它,然后如果连接是失去了一个不知道,只是保持重试…有了图书馆,就更容易创建和使用直接的蓝牙连接!
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}\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.
在那个大的长串中,你可以看到目标设备的地址: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端口,请使用32英尺。净的BluetoothDeviceInfo.SetServiceState(BluetoothService.SerialPort)API。请参阅用户指南中的“蓝牙串行端口”部分,如http://www.alanjmcf.s.uk/comms/bluetooth/32feet.net%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...
这都是针对微软的蓝牙栈。我还没有研究其他栈在这方面的表现。在一个简短的检查之后,Widcomm的串行端口出现在SerialPort中。GetPortNames而不是WMI查询中…
#2
3
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的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);
}
}
}
#3
1
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: * - Determine if serial port is normal COM or SPP
我刚发现一个问题,跟你的不太一样,但对我很有效。通过这个,您可以发现您的COM端口来自于蓝牙设备:*——确定串行端口是普通的COM还是SPP。
I hope it helps somehow. If you find out how to do what you wanted, please let me know. Thanks.
我希望它能有所帮助。如果你知道如何做你想做的事,请告诉我。谢谢。
#4
1
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
- 枚举PNP中可用的所有COM端口。
- obtain the device classGuid
- 获取设备classGuid
- search the bluetooth address from the classGuid
- 从classGuid搜索蓝牙地址。
- when the bluetooth address is known, the bluetooth name can be obtained from the this registry
SYSTEM\CurrentControlSet\Services\BTHPORT\Parameters\Devices
- 当蓝牙地址被知道时,蓝牙名称可以从这个注册表系统\CurrentControlSet\ \ \ \ \ \ \ \ \ \ \设备。
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;
}
#5
0
So, to get the information about a remote device including its name, using 32feet.NET do:
所以,要获取一个远程设备的信息,包括它的名字,使用32英尺。净做:
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/调用Win32的BluetoothGetDeviceInfo。
#6
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;
}