SUMMARY
Desktop applications call the
CeRapiInitEx function to initialize Remote API (RAPI) before the applications
make any RAPI calls to communicate with Pocket PC or Microsoft Smartphone
devices.
CeRapiInitEx can be called asynchronously by passing in a valid pointer to the
RAPIINIT structure, and the caller can determine how long it wants to wait
before RAPI is initialized by using the
WaitForSingleObject function.
In
Microsoft ActiveSync 3.7 and earlier, RAPI was designed to be initialized
on
threads with message pumps. RAPI was not designed to be initialized
asychronously on
worker threads in client applications. Microsoft does not recommend that
you use unofficial workarounds to make RAPI initialize asychronously on worker
threads in client applications.
The
RAPI thread model was changed in ActiveSync 3.7.1 so that it can be freely
initialized on either message pump threads (UI threads) or on simple worker
threads. Therefore, if you use
CeRapiInitEx correctly, no workaround is necessary and you will be able to
initialize RAPI in any context. As a side effect, unofficial workarounds will
not work. This article includes samples for how to correctly use
CeRapiInitEx to initialize RAPI asynchronously.
Note To initialize RAPI synchronously, make a blocking call by using
the
CeRapiInit function. The behavior change in ActiveSync 3.7.1 does not affect
applications that call
CeRapiInit to initialize RAPI synchronously.
back to the topMORE INFORMATION
Example of Incorrect Workaround Code
This sample code demonstrates a typical unofficial workaround that
worked in ActiveSync 3.7 or earlier. It is an inefficient solution because it
calls the
CeRapiInitEx and
CeRapiUninit functions many times. This code does not work in ActiveSync 3.7.1
or later because the thread model inside RAPI was changed.
RAPIINIT ri;
BOOL bCancel;
DWORD dwWait;
while (!bCancel)
{
// This is incorrect because it repeatedly calls CeRapiInitEx.
CeRapiInitEx(&ri);
// This is incorrect because in ActiveSync 3.7.1, the event may not be signaled before CeRapiInitEx
//returns if a device is already connected.
dwWait = WaitForSingleObject(ri.heRapiInit, 0);
if (dwWait == WAIT_OBJECT_0)
{
// Succeeded.
goto Succeeded;
}
else if (dwWait == WAIT_TIMEOUT)
{
// This is incorrect because it repeatedly calls CeRapiUninit.
CeRapiUninit();
Continue;
}
else
{
// Failed.
CeRapiUninit();
goto failed;
}
}
back to the topExamples
The following code examples demonstrate how to initialize RAPI
asynchronously. These examples are not the only method of initializing RAPI
asynchronously, but they demonstrate the general principle: Call
CeRapiInitEx one time, then wait for the RAPI event to initialize based on
your requirements. You may use a timeout value, a timer, or other event
mechanisms to wait for initialization to finish.
Note The samples are based on ActiveSync 3.7.1. If you want to make
sure your application works fine with both ActiveSync 3.7.1 and earlier version
of ActiveSync, you must initialize RAPI on a thread with a message pump. For
more information, see Example 2.
Example 1To initialize RAPI asynchronously in a simple
worker thread, use the following code. In the code, the CeRapiUninit function
is called to uninitialize RAPI if the
WaitForSingleObject function returns a
value that is other than
WAIT_OBJECT_0. This behavior is most likely caused by
a timeout event (in this example, the timeout is 30 seconds).
#define ONE_SECOND 1000
RAPIINIT ri = {sizeof(RAPIINIT), 0, 0};
HRESULT hr = E_FAIL;
DWORD dwWaitRet = 0;
DWORD dwTimeout = 30 * ONE_SECOND; // Wait for 30 seconds. You can specify a different value here.
// Call CeRapiInitEx one time.
hr = CeRapiInitEx(&ri);
if (FAILED(hr))
{
goto failed;
}
// Wait for the RAPI event until timeout.
// Use the WaitForSingleObject function for the worker thread.
// Use the WaitForMultipleObjects function if you are also waiting for other events.
dwWaitRet = WaitForSingleObject(ri.heRapiInit, dwTimeout);
if (dwWaitRet == WAIT_OBJECT_0)
{
// If the RAPI init is returned, check the result.
if (SUCCEEDED(ri.hrRapiInit))
{
// Succeeded.
goto succeeded;
}
else
{
goto failed;
}
}
else
{
// Timeout or failed.
goto failed;
}
succeeded:
// Now you can make RAPI calls.
failed:
// Uninitialize RAPI if you ever called CeRapiInitEx.
if (SUCCEEDED(hr))
{
CeRapiUninit();
}
Example 2To initialize RAPI asynchronously in a UI thread (a
thread with a message pump), abort when timeout
To initialize RAPI asynchronously in a UI thread, use the following code. In the code, the
CeRapiUninit function
is called to uninitialize RAPI if the
MsgWaitForMultipleObjects function returns a
value that is other than
WAIT_OBJECT_0. This behavior is most likely caused by
a timeout (in this example, the timeout is 30 seconds) or if any message is in the queue.
#define ONE_SECOND 1000
RAPIINIT ri = {sizeof(RAPIINIT), 0, 0};
HRESULT hr = E_FAIL;
DWORD dwWaitRet = 0;
DWORD dwTimeout = 30 * ONE_SECOND; // Wait for 30 seconds, or specify your own value here.
DWORD dwEndTime;
DWORD dwCurrentTime;
// Call CeRapiInitEx one time.
ri.cbSize = sizeof(ri);
hr = CeRapiInitEx(&ri);
if (FAILED(hr))
{
goto failed;
}
// Calculate the time that you want to wait until.
dwCurrentTime = GetTickCount();
dwEndTime = dwCurrentTime + dwTimeout;
// Now wait for the RAPI event until timeout.
while (dwEndTime > dwCurrentTime)
{
//
// Wait for the RAPI event until timeout. Use the MsgWaitForMultipleObjects function for the
// UI thread because otherwise the thread will be blocked for message processing.
//
dwWaitRet = MsgWaitForMultipleObjects(1, &ri.heRapiInit, FALSE, dwEndTime - dwCurrentTime,QS_ALLINPUT);
if (dwWaitRet == WAIT_OBJECT_0)
{
// RAPI init returned, check result
if (SUCCEEDED(ri.hrRapiInit))
{
// Succeeded.
goto succeeded;
}
else
{
goto failed;
}
}
else if (dwWaitRet == WAIT_OBJECT_0 + 1)
{
// Process the messages.
BOOL bQuit = FALSE;
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
bQuit = (msg.message == WM_QUIT);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (bQuit)
{
goto failed;
}
// Update the timer.
dwCurrentTime = GetTickCount();
// Loop back, and thencontinue to wait.
continue;
}
else
{
// Timed out or failed.
goto failed;
}
}
succeeded:
// Now you can make RAPI calls.
failed:
// Uninitialize RAPI if CeRapiInitEx was called.
if (SUCCEEDED(hr))
{
CeRapiUninit();
}
back to the top