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?
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.
> 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?
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);
}
#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.
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