Object Exchange (OBEX) Protocol Primer
What OBEX Stands For
According to its name, OBEX stands for OBject EXchange. It allows the devices to exchange standard objects such as files, business cards, and calendar infos. This is a vendor-independent protocol implemented on different OSes, such as Palm OS and Windows CE. The actual OBEX support on a particular mobile device depends on system configuration; in other words, vendors can decide what to put there, but at least the OBEX Push protocol is usually presented because it is supported by an Inbox application.
If you turn to the Windows Mobile area, you now can choose between IrDA and Bluetooth as underlying transports. OBEX does all the transport-specific work for you, so there is no need to worry about such things like BT devices being discovered and so forth. In addition, there are a number of COM interfaces to control OBEX as well as to perform device enumeration:
- IObex
- IObex2
- IObexDevice
- IHeaderCollection
- IObexSink
- IObexService
- IObexServiceConnection
- IInboxSink
- IHeaderEnum
- IPropertyBagEnum
- IDeviceEnum
- IObexCaps
Initialization
Your entry point to OBEX is the IObex and IObex2 interfaces. A common workflow, therefore, will be as follows:
- Initialize OBEX
- Find a connection point and command OBEX to send notifications on the remote device's arrival or departure
- Enumerate devices
- Handle OBEX events
- Perform all required transfers
- Shut down OBEX
The very first step is to make an initialization. You will assume that IObex2 is supported in your system:
int CObex::InitObex(HWND hWnd)
{
HRESULT hr;
CString sInfo;
CComPtr<IObex> pObex;
m_hWnd = hWnd;
hr = pObex.CoCreateInstance(__uuidof(Obex),NULL,
CLSCTX_INPROC_SERVER);
if(FAILED(hr))
{
sInfo.Format(_T("Failed to initialize Obex interface:
hr = 0x%X, err = 0x%Xn"),
hr, GetLastError());
::SendMessage(m_hWnd, WM_OBEX_INFO,0,(LPARAM)&sInfo);
return 0;
}
hr = pObex->QueryInterface(__uuidof(IObex2),(void**)&m_pObex);
if(FAILED(hr))
{
sInfo.Format(_T("Failed to initialize Obex interface:
hr = 0x%X, err = 0x%Xn"),
hr, GetLastError());
::SendMessage(m_hWnd, WM_OBEX_INFO,0,(LPARAM)&sInfo);
return 0;
}
pObex.Release();
if (!m_pObex)
return 0;
m_pObex->Initialize();
IObexCaps *pObexCaps = NULL;
hr = m_pObex->QueryInterface(IID_IObexCaps,
(LPVOID *)&pObexCaps);
if(SUCCEEDED(hr))
{
pObexCaps->SetCaps(SEND_DEVICE_UPDATES);
pObexCaps->Release();
}
CCriticalSection csLock;
csLock.Lock(INFINITE);
IObexSinkImpl *pSink = new IObexSinkImpl(hWnd);
if (!pSink)
{
csLock.Unlock();
return 0;
}
hr = m_pObex->QueryInterface(IID_IConnectionPointContainer,
(LPVOID *)&m_pContainer);
if (!SUCCEEDED(hr) || (m_pContainer == 0))
{
csLock.Unlock();
return 0;
}
hr = m_pContainer->FindConnectionPoint(IID_IObexSink,
&m_pConPoint);
if (!SUCCEEDED(hr) || (m_pConPoint == 0))
{
m_pContainer.Release();
csLock.Unlock();
return 0;
}
hr = m_pConPoint->Advise((IUnknown *)pSink, &m_dwCookie);
csLock.Unlock();
if (ERROR_SUCCESS != m_pObex->StartDeviceEnum())
return 0;
if(!SUCCEEDED(hr) || (pDeviceEnum == 0))
return 0;
return 1;
}
This code snippet illustrates the entire process: Create all required interfaces, look for connection point, and advise for sink object. Please note that, to receive callback notifications, you have to implement a simple COM-like class. In this sample, it is IObexSinkImpl. All it actually does is to implement the Notify method to pass events to the main application. After all objects are ready, you can start a device lookup. You can collect all devices in range either with a Notify callback or directly by a
CComPtr<IDeviceEnum> pDeviceEnum; hr = m_pObex->EnumDevices(&pDeviceEnum, GUID_NULL);
call. This function returns the IDeviceEnum interface, which allows you to surf through device enumeration. The last parameter defines a device type to request. You want all devices in range, so sending CLSID_NULL will do. If you want a specific device class, you can do it by sending the appropriate parameter here. The following table lists possible values:
| Value | Description |
|---|---|
| CLSID_BthTransport | A device that uses Bluetooth to communicate with other devices |
| CLSID_HeaderCollection | The header collection of a device |
| CLSID_IpTransport | A device that uses TCP/IP to communicate with other devices |
| CLSID_IrdaTransport | A device that uses IRdA to communicate with other devices |
| CLSID_Obex | An OBEX-class device |
| CLSID_PropertyBag | The property bag of a device |
Page 1 of 3
