Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Bluetooth virtual serial ports

1,299 views
Skip to first unread message

JimmyBluetooth

unread,
Sep 29, 2005, 3:39:04 PM9/29/05
to
I'm writing a C++ application that communicates with a Bluetooth device, and
that device restricts me to using the serial port profile. Using the
Platform SDK Bluetooth APIs (defined in BluetoothAPIs.h) on Windows XP
Service Pack 2, my application is able to programmatically discover, pair
with, and connect to a Bluetooth device without any user intervention at all.
My problem lies in trying to determine which virtual serial port a given
Bluetooth device gets mapped to.

To connect to the serial port service on my Bluetooth device, my code makes
the following call:

GUID service = SerialPortServiceClass_UUID; // from bthdef.h
lastError = BluetoothSetServiceState( radioHandle, &bluetoothDeviceInfo,
&service, BLUETOOTH_SERVICE_ENABLE );

When that function is called, Windows automatically creates a virtual serial
port for my application to use for outgoing communication with my Bluetooth
device. Great! That saves me the hassle of calling RegisterDevice. There's
only one problem -- which virtual serial port just got created? (It's not
always COM7 or COM8.)

But the problem gets more complicated. Imagine that the user quits my
application, comes back a couple of hours later, and starts my application up
again. At this point, I can programmatically go through and find out that
Bluetooth device X has been connected before and has been authenticated
(paired). But which virtual serial port should I open to communicate with
device X? Obviously this information is stored somewhere, because it is
presented when I open Control Panel->Bluetooth Devices->COM Ports. But how
can my application access that information?

In short, the task is to start with a BLUETOOTH_DEVICE_INFO structure and
end up with a virtual serial port number. What functions do I need to call
to access that information?

Rhett Gong [MSFT]

unread,
Sep 30, 2005, 4:04:51 AM9/30/05
to
Hello,
Based on my understanding of your post, you would like a way to access the virtual serial ports by yourself. If you check "Appendix A: Windows Sockets Support for Virtual
Serial Port Functionality" topic of BlueTooth doc, you will find following line:
<quote>
The Microsoft? Windows? Bluetooth stack does not directly support virtual serial ports, nor expose a way for kernel mode drivers to be developed directly on top of
RFCOMM in kernel mode. Developers that want a virtual serial port solution must write their own application that accesses user-mode Winsock interfaces, then route data
and control messages back down to an independently created kernel-mode driver that exposes the named virtual serial port. No samples are provided for this potential
implementation, and implementation details beyond the relevant Winsock interfaces provided in this section are the discretion of the developer. In order to support
Winsock applications that access virtual serial functionality, the Bluetooth Winsock interface has a facility for allowing Windows Sockets clients to process the serial-
related messages of the RFCOMM protocol (the MSC, RPN, and RLS RFCOMM MUX messages) through a Windows Sockets IOCTL interface. These interfaces are
described in the following table.
</quotte>

More information can be found at: http://msdn.microsoft.com/library/en-
us/bluetooth/bluetooth/appendix_a_windows_sockets_support_for_virtual_serial_port_functionality.asp
Or topic "Appendix A: Windows Sockets Support for Virtual Serial Port Functionality" of MSDN

Thanks,
Rhett Gong [MSFT]
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
http://support.microsoft.com/default.aspx?scid=/servicedesks/msdn/nospam.asp&SD=msdn

This posting is provided "AS IS" with no warranties and confers no rights.

JimmyBluetooth

unread,
Sep 30, 2005, 3:04:03 PM9/30/05
to

JimmyBluetooth

unread,
Sep 30, 2005, 5:31:16 PM9/30/05
to
Thanks for your feedback, Rhett.

> Based on my understanding of your post, you would like a way to access the virtual serial ports by yourself.

I'm sorry I wasn't more clear in describing the problem. I do have a way to
read and write to a virtual serial port using a kernel-mode driver; in fact,
that is already working beautifully. Where I get hung up is that I don't
know how to identify which virtual serial port Windows created to talk with a
specific Bluetooth device. Perhaps a specific example will help clarify.

Using the SDK BluetoothAPI, I can easily list BT devices that are in range
of computer. With calls to BluetoothFindFirstDevice and
BluetoothFindNextDevice, I can get a list of which devices are in range.
Let's say one of the devices I find has the name "MyDevice" and the Bluetooth
address 01:23:45:67:89:AB. Then I can call BluetoothAuthenticateDevice to
establish the pairing relationship with MyDevice. Finally, I can call
BluetoothSetServiceState (as mentioned in my original post) to subscribe to
the serial port service on MyDevice. During the call to
BluetoothSetServiceState, Windows creates virtual serial ports for me to use
when talking to MyDevice -- we'll say it creates COM4 (outgoing) and COM5
(incoming).

Now I want to talk to MyDevice. I have another code module that allows me
to read and write to serial ports. But here's the problem: which serial port
should I tell that other module to read from and write to? As a human user
who watched all of the dialogs during the pairing process, I know that I need
to use COM4. But how can I determine that fact programmatically, without any
user intervention?

Right now I am using what I think is a very unreliable approach. My code
gets a list of existing serial ports before it calls
BluetoothSetServiceState, then a second list after that call, then compares
the two lists to see what changed.

There must be a more deterministic way to figure out which virtual serial
port(s) BluetoothSetServiceState created for me. But what is that way?

Elliot Leonard

unread,
Oct 3, 2005, 8:39:07 PM10/3/05
to
I had the same problem. Here is my solution. It is absolutely nuts that
Microsoft does not provide a better solution.

Note that cppstring is just std::wstring - you can easily change this to
something more to your taste.
Our code is a Unicode build, so we use the following macro.
#define GSTD_S(x) L##x


int WinFindCOMPortMappedToBluetoothDevice(
const BLUETOOTH_ADDRESS &btAddr,
cppstring *pCOMPortString)
{
int status = 0;
DWORD reqGuids = 16;
GUID guids[16];
HDEVINFO devs = INVALID_HANDLE_VALUE;
unsigned int ii;
bool bPortFound = false;
DWORD devIndex;
SP_DEVINFO_DATA devInfo;
devInfo.cbSize = sizeof(devInfo);
TCHAR tmpstring[60];
TCHAR hardware_id_string[300];
DWORD propertyType;
SP_DEVINFO_LIST_DETAIL_DATA devInfoListDetail;
devInfoListDetail.cbSize = sizeof(devInfoListDetail);

//Create search string that we are looking for from bluetooth address.
wsprintf(tmpstring, GSTD_S("%02x%02x%02x%02x%02x%02x"),
btAddr.rgBytes[5], btAddr.rgBytes[4], btAddr.rgBytes[3],
btAddr.rgBytes[2], btAddr.rgBytes[1], btAddr.rgBytes[0]);
CString searchString = tmpstring;
searchString.MakeUpper();
CString hwParsingString;

if (SetupDiClassGuidsFromNameEx(GSTD_S("ports"), guids, reqGuids,
&reqGuids, NULL, NULL))
{
for (ii = 0; (ii < reqGuids) && (!bPortFound); ii++)
{
devs =
SetupDiGetClassDevsEx(&guids[ii],NULL,NULL,DIGCF_PRESENT,NULL,NULL,NULL);
if (devs != INVALID_HANDLE_VALUE)
{
BOOL bSuccess = SetupDiGetDeviceInfoListDetail(devs, &devInfoListDetail);
if (bSuccess)
{
devIndex = 0;
while (SetupDiEnumDeviceInfo(devs,devIndex,&devInfo) && (!bPortFound))
{
status = CM_Get_Device_ID_Ex(devInfo.DevInst, hardware_id_string, 300,
0, devInfoListDetail.RemoteMachineHandle);
if (CR_SUCCESS == status)
{
hwParsingString = hardware_id_string;
if (hwParsingString.Find(searchString) >= 0)
{
bSuccess = SetupDiGetDeviceRegistryProperty(devs, &devInfo,
SPDRP_FRIENDLYNAME, &propertyType,
(PBYTE) hardware_id_string, sizeof(hardware_id_string), NULL);
if (bSuccess)
{
hwParsingString = hardware_id_string;
int firstIndex = hwParsingString.Find(GSTD_S("(COM"));
if (firstIndex >= 0)
{
firstIndex++;
int lastIndex = hwParsingString.Find(GSTD_S(")"), firstIndex);
if (lastIndex > firstIndex)
{
*pCOMPortString = hwParsingString.Mid(firstIndex, lastIndex -
firstIndex);
bPortFound = true;
}
}
}
}
}

devIndex++;
}
}

SetupDiDestroyDeviceInfoList(devs);
}
}
}

return (bPortFound ? 0 : -1);
}


Elliot Leonard

unread,
Oct 4, 2005, 1:45:01 PM10/4/05
to
The sample code that I posted earlier for
WinFindCOMPortMappedToBluetoothDevice() can crash if the number of ports
installed is large. Safer code would go something like:

#define MAX_NUM_PORT_GUIDS 32
GUID guids[MAX_NUM_PORT_GUIDS];
DWORD reqGuids;
if (SetupDiClassGuidsFromNameEx("ports", guids, MAX_NUM_PORT_GUIDS,
&reqGuids, NULL, NULL))
{
if (reqGuids > MAX_NUM_PORT_GUIDS)
reqGuids = MAX_NUM_PORT_GUIDS;


for (ii = 0; (ii < reqGuids) && (!bPortFound); ii++)
{
}
}

The best solution would call SetupDiClassGuidsFromNameEx() twice and
allocate a big enough guids buffer based on the value of reqGuids returned
from the first call.

Rhett Gong [MSFT]

unread,
Oct 6, 2005, 2:01:57 AM10/6/05
to
Hello Jimmy,
I searched our SDK, but seems there is no interface to achieve the goal. Currently, I am contacting our BlueTooth SDK team to see if they could shed a light on this issue.

In addition, I saw Elliot Leonard shared his solution with DDK interface --- SetupDiClassGuidsFromNameEx. Could you check his reply and let me know if it meets your
need please?

Rhett Gong [MSFT]

unread,
Oct 10, 2005, 1:41:46 AM10/10/05
to
Hello Jimmy,
I have discussed this issue with out BlueTooth guys. Currently, there is not a programmatic way to get the name of the com port associated with a remote Bluetooth device.
Since your application is calling BluetoothAuthenticateDevice() and BluetoothSetServiceState(), you should as well use RFCOM socket to connect directly with the SPP on
the device side. We suggest you just use RFCOM to connect to the device without hoping through the COM port.

Christian Aguilar

unread,
Nov 22, 2005, 11:49:44 AM11/22/05
to
Hi Jimmy,

I found this post and it helped me a lot with my program. I was trying to
create virtual serial ports, and then became disapointed with the bluetooth
API.

BluetoothSetServiceState in fact creates the outgoing COM port. Since I do
not have the DDK and I am not planning to buy it, I am reading directly from
the registry: HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM with the same
aproach: What was there before the call and after the call.

Now, in your post you said you were able to create also an incoming COM port?
!?! Could you please explain me how did you do that?

Thanks,
Christian

0 new messages