Talking to a Windows Mobile device (RAPI 2)

November 1, 2008

Remote API (RAPI) library enables desktop application to perform actions on a Windows CE or a Windows Mobile device. Action can be one of the general purpose ones such as manipulating files on the devices, configuring registry on the device etc. Besides an application can do custom actions on the device by copying a special dll on the device and then calling custom functions implemented in that dll.

RAPI2 is available since Windows CE 5.01. An earlier version, just known as RAPI, is there since Windows CE 1.0. Going forward, its recommended to use RAPI2.

Desktop side functionality is provided by RAPI.dll which is installed when Microsoft ActiveSync is installed on the computer. So before calling any RAPI functions, desktop application should check if RAPI.dll is present on the system. RAPI.dll should not be bundled with the application as you might overwrite the latest version on a user’s computer.

To use RAPI in your native program, your must have basic knowledge of COM (Component Object Model). RAPI consists of the following interfaces which you need to acquire programmatically.

IRAPIDesktop : The connection point container for all devices.

IRAPIDevice : Represents a connected remote device.

IRAPIEnumDevices : Enumerates over all connected devices.

IRAPISession : Provides methods that replace the Remote API (RAPI) functions.

IRAPISink : Implemented by client application to receive connection events.

Sample Code

Access and usage of these interfaces is demonstrated in the code below. CDeviceManager class implements connecting/disconnecting the desktop to a Windows Mobile/CE device. You can use CDeviceManager class in your code to support connect/disconnect functionality and then use IRAPISession to call other functions as desired.

// CDeviceManager.h

#include <Rapi2.h>

#pragma once

class CDeviceManager
{
IRAPIDesktop*        m_pIRapiDesktop;
IRAPIEnumDevices*    m_pIRapiEnumDevices;
IRAPIDevice*        m_pIRapiDevice;
IRAPISession*        m_pIRapiSession;

public:
CDeviceManager(void);
~CDeviceManager(void);
int Connect(void);
bool IsConnected(void);
int Disconnect(void);
int Init(void);
int Deinit(void);
};

// CDeviceManager.cpp

#include “StdAfx.h”
#include “DeviceManager.h”

#define RELEASE_INTERFACE(p)    if (p) {    \
p->Release();    \
p = NULL;    \
}    \

CDeviceManager::CDeviceManager(void)
{
m_pIRapiDesktop = NULL;
m_pIRapiEnumDevices = NULL;
m_pIRapiDevice = NULL;
m_pIRapiSession = NULL;
}

CDeviceManager::~CDeviceManager(void)
{
Deinit();
}

int CDeviceManager::Init(void)
{
HRESULT hr = S_OK;

if (m_pIRapiDesktop == NULL)
{
// Initialize COM.
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);

// Create an instance of the IRAPIDesktop interface.
hr = CoCreateInstance(CLSID_RAPI, NULL, CLSCTX_INPROC_SERVER, IID_IRAPIDesktop, (void**)&m_pIRapiDesktop);

if (m_pIRapiDesktop == NULL)
return ERR_INIT_FAILED;
}

return 0;
}

int CDeviceManager::Deinit(void)
{
RELEASE_INTERFACE(m_pIRapiDesktop);
CoUninitialize();
return 0;
}

int CDeviceManager::Connect(void)
{
int        iRetVal = ERR_SUCCESS;
HRESULT hr = S_OK;

ASSERT(m_pIRapiDesktop);

RELEASE_INTERFACE(m_pIRapiEnumDevices);
RELEASE_INTERFACE(m_pIRapiDevice);
RELEASE_INTERFACE(m_pIRapiSession);

// Call EnumDevices to obtain an enumeration of connected devices.
if (SUCCEEDED(hr) && m_pIRapiDesktop)
{
hr = m_pIRapiDesktop->EnumDevices(&m_pIRapiEnumDevices );
}

if (m_pIRapiEnumDevices == NULL)
{
iRetVal = ERR_DEVICE_ENUM_FAILED;
goto cleanup;
}

// Call Next to get an interface to the device.
if (SUCCEEDED(hr) && m_pIRapiEnumDevices)
{
hr = m_pIRapiEnumDevices->Next(&m_pIRapiDevice);
}

if (m_pIRapiDevice == NULL)
{
iRetVal = ERR_NODEVICE_CONNECTED;
goto cleanup;
}

// Call CreateSession to establish a session with the connected device.
if (SUCCEEDED(hr) && m_pIRapiDevice)
{
hr=m_pIRapiDevice->CreateSession(&m_pIRapiSession);
}

if (m_pIRapiSession == NULL)
{
iRetVal = ERR_CONNECTION_FAILED;
goto cleanup;
}

if (SUCCEEDED(hr) && m_pIRapiSession)
{
// Call CeRapiInit before you call any other IRAPISession methods.
hr = m_pIRapiSession->CeRapiInit();
if (FAILED(hr))
{
hr = m_pIRapiSession->CeRapiGetError();
iRetVal = ERR_CONNECTION_FAILED;
goto cleanup;
}
}

goto success;
cleanup:
RELEASE_INTERFACE(m_pIRapiEnumDevices);
RELEASE_INTERFACE(m_pIRapiDevice);
RELEASE_INTERFACE(m_pIRapiSession);

success:
return iRetVal;
}

bool CDeviceManager::IsConnected(void)
{
if (m_pIRapiDevice)
{
RAPI_DEVICESTATUS Stat;
m_pIRapiDevice->GetConnectStat(&Stat);
if (Stat == RAPI_DEVICE_CONNECTED)
return true;
}

return false;
}

int CDeviceManager::Disconnect(void)
{
if (m_pIRapiSession)
{
m_pIRapiSession->CeRapiUninit();
RELEASE_INTERFACE(m_pIRapiSession);
}

RELEASE_INTERFACE(m_pIRapiEnumDevices);
RELEASE_INTERFACE(m_pIRapiDevice);

return 0;
}

// Error.h

#define        ERR_SUCCESS                0

// Device Manager errors
#define        ERR_DEVICECONN_START    ERR_SUCCESS+1
#define        ERR_INIT_FAILED            ERR_DEVICECONN_START
#define        ERR_DEVICE_ENUM_FAILED    ERR_DEVICECONN_START+1
#define        ERR_NODEVICE_CONNECTED    ERR_DEVICECONN_START+2
#define        ERR_CONNECTION_FAILED    ERR_DEVICECONN_START+3

Advertisements