Creating a Connection to a Remote Device Using a Virtual COM Port
A version of this page is also available for
4/8/2010
You can create a connection between two Bluetooth devices by using the Windows Mobile COM Port emulator facility. The COM Port emulator is the top most layer of the Bluetooth Protocol Stack and provides access to RFCOMM based on a virtual COM port. It does not expose stack interfaces but provides an API layer for opening connections to remote Bluetooth devices.
The Windows Mobile implementation of Bluetooth allows you to create a piconet. As per the Bluetooth specification, a master device can connect with seven active slave devices. For more information about piconet, see the Bluetooth Core Specification at this Official Bluetooth Wireless Info Web site.
When this layer is present in the Bluetooth stack, a virtual server or client COM port can be created to accept incoming or create outgoing RFCOMM connections.
Note
Microsoft recommends that you use Winsock APIs to create connections. For more information, see Creating a Connection to a Remote Device Using Winsock.
Before you create a connection between two Bluetooth devices, you must have the following information:
- Address of the Bluetooth device to connect to, stored as a BT_ADDR type (for client ports).
- RFCOMM channel number (between 1 and 31).
- COM port number (between 0 and 9) to be assigned for Bluetooth operations.
The Comtest sample that ships with Windows Mobile, contains source code for creating a Bluetooth connection by using a COM port.
To create a virtual COM port
Configure the PORTEMUPortParams structure to specify attributes for the virtual COM port. This structure stores Bluetooth specific information, such as the channel and Bluetooth address information.
For a server port, set flocal and channel, as the following example shows.
PORTEMUPortParams pp; memset (&pp, 0, sizeof(pp)); pp.flocal = TRUE; pp.channel = channel & 0xff;
The preceding example configures a server port by setting flocal to TRUE. This enables a server COM port to accept incoming connections at the specified channel.
Note
To avoid conflicts, when you are selecting the server channel, it is recommended that you set channel to RFCOMM_CHANNEL_MULTIPLE (0xfe). This configures RFCOMM to use the next available channel.
For a client port, set the device, channel, and the uiportflags members of PORTEMUPortParams as the following example shows.
PORTEMUPortParams pp; memset (&pp, 0, sizeof(pp)); pp.device = ba; pp.channel = channel & 0xff;
In the preceding example, device is set to a BT_ADDR type that stores the remote device to initiate a remote connection over the RFCOMM layer.
If the server channel is not known then the client can specify the UUID of the server in the uuidService member. In this case, an SDP query is performed automatically to retrieve the target channel number used on the remote device based on the service UUID.
Register the device by calling the RegisterDevice function, as the following example shows.
HANDLE h = RegisterDevice (L"COM", index, L"btd.dll", (DWORD)&pp);
The preceding example specifies the port type as COM, port number, and the name of the device driver DLL, as parameters to RegisterDevice. Also, pass the address of PORTEMUPortParams structure, created in step 1, in the dwInfo parameter. RegisterDevice registers the Bluetooth Protocol stack with the virtual COM port.**
Create a null-terminated string to store the name of the COM port. You must include a colon after the port name, as the following example shows.
WCHAR szComPort[30]; wsprintf (szComPort, L"COM%d:", index);
Open the COM port by calling the CreateFile function.
HANDLE hCommPort = CreateFile (szComPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
To specify the port name, pass the string created in step 3, in the lpFileName parameter of CreateFile.
For client ports, the physical connection is created only when the device is open with read or write access by using CreateFile. The physical connection is terminated for both server and client ports when the first handle with read or write access is closed.
Up to four open handles can be outstanding for each virtual port created. Every handle maintains its own set of communication event masks. If a file is open with a 0 access mask, it can only be used for WaitCommEvent, but not with ReadFile and WriteFile APIs.
Once the COM port is created, it is a functional equivalent of a serial port. The same APIs can be used to access it.
To remove an existing virtual COM port
Call the CloseHandle function and pass the handle returned by CreateFile, as the following example code shows.
CloseHandle (hCommPort);
To deregister the device, call the DeregisterDevice function and pass the handle returned by RegisterDevice, as the following example code shows.
DeregisterDevice (h);
To use auto-bound channel in port emulation
Set the channel member of PORTEMUPortParams to RFCOMM_CHANNEL_MULTIPLE.
PORTEMUPortParams pp; memset (&pp, 0, sizeof(pp)); pp.channel = RFCOMM_CHANNEL_MULTIPLE;
Create the virtual COM port by using RegisterDevice and CreateFile.
Determine the assigned RFCOMM channel by using the IOCTL, IOCTL_BLUETOOTH_GET_RFCOMM_CHANNEL.
DWORD port = 0; DWORD dwSizeOut = 0; HANDLE hFile; if (!DeviceIoControl (hFile, IOCTL_BLUETOOTH_GET_RFCOMM_CHANNEL, NULL, 0, &port, sizeof(port), &dwSizeOut, NULL)) { // Perform error handling }
The following functions are supported:
- ClearCommError
- EscapeCommFunction
- GetCommMask
- GetCommModemStatus
- GetCommProperties
- GetCommState
- GetCommTimeouts
- SetCommMask
- SetCommState
- SetCommTimeouts
- WaitCommEvent