`
`http://etutorials.org/Programming/Pocket+pc+network+programming/Ch...
`
`Home (/) / Programming (/Programming/)
`/ Pocket pc network programming (/Programming/Pocket+pc+network+programming/)
`
`21
`
`The Remote API (RAPI) provides a set
`of helper functions that enable a
`desktop-based application to execute
`code on a connected Pocket PC device.
`Once a function has returned, the
`results are sent back to the PC. In
`essence, RAPI is a type of one-way
`Remote Procedure Call (RPC)?the
`client (your desktop application) makes
`a request to the server (a connected
`Pocket PC device) to execute some
`functionality, and returns the results to
`it.
`
`RAPI was originally designed as a way
`to manage a Pocket PC device from the
`desktop. It includes functions that enable an application to query the file system, registry, and
`device databases, as well as get information about the Pocket PC's system configuration. You
`can even create your own functions, which can be run over the RAPI APIs.
`
`You will quickly notice that most of the functions in RAPI look similar to the functions in the
`standard Pocket PC and Windows 32 API. In fact, they typically have the same definition and
`number of parameters, as well as the same return values, as a standard desktop function call.
`The only difference is that they all are prefixed with the letters Ce. For example, the RAPI
`function CeFindFirstFile() is the same as the desktop FindFirstFile() API, except
`that it will enumerate the files on a connected Pocket PC device, rather than those on the
`desktop. This being the case, I will not provide a detailed description of each function available
`via the RAPI API.
`
`Because RAPI is run on the desktop, you must ensure that the computer running your
`application has the latest version of ActiveSync installed on it. This will ensure that rapi.dll
`(which is required for your application to work) is present on the desktop, as you may not
`distribute rapi.dll on your own. You can call RAPI from console applications, window
`applications, and even a .NET assembly.
`In order to use the Remote API within your applications, you need to include the rapi.h
`header file in your project, as well as link with the rapi.lib library (note that because this is a
`desktop library, it is located in the .\wce300\Pocket PC 2002\support
`
`1 of 22
`
`11/21/2016 8:17 PM
`
`Rosetta-2029
`
`0001
`
`
`
`Remote API (RAPI) :: Chapter 9. Desktop Synchronization :: Pocket pc ...
`
`http://etutorials.org/Programming/Pocket+pc+network+programming/Ch...
`
`\ActiveSync\lib directory in the folder where you have installed Embedded Visual C++).
`Using RAPI
`Before you can use any of the RAPI functions, you must first initialize Windows CE's remote
`services and establish a communications link with a connected device by calling either the
`CeRapiInit() or CeRapiInitEx() functions.
`The simplest way to start RAPI is by calling the synchronous (i.e., blocking) function
`CeRapiInit(), which is defined as follows:
`
`HRESULT CeRapiInit();
`
`Once the function is called, it will immediately attempt to establish a connection to a Pocket PC
`device, and will not return control to your application until either a connection has been made or
`the function fails. CeRapiInit() will return E_SUCCESS if a successful connection can be
`made and RAPI has initialized without a problem; otherwise, you will be returned E_FAIL. If
`RAPI has already been initialized, you will receive CERAPI_E_ALREADYINITIALIZED as the
`return value.
`The following short code sample shows you how to use the CeRapiInit() function:
`
`HRESULT hr = S_OK;
`hr = CeRapiInit();
`
`if(FAILED(hr)) {
` if(hr == CERAPI_E_ALREADYINITIALIZED)
` OutputDebugString(TEXT("RAPI has already been
` initalized"));
` return FALSE;
`}
`
`Although using the CeRapiInitEx() function is a bit more involved, you will find that it
`provides you with a greater amount of control because it is asynchronous (the function will
`return to you immediately). This means, of course, that you will have to periodically check the
`RAPI event handle you are returned in order to find out when it has become signaled.
`The CeRapiInitEx() function is defined as follows:
`
`HRESULT CeRapiInitEx(RAPIINIT *pRapiInit);
`
`The only parameter that the function takes is a pointer to a RAPIINIT structure, which contains
`information about the RAPI event handle and its status. The structure is defined as follows:
`
`typedef struct _RAPIINIT {
` DWORD cbSize;
` HANDLE heRapiInit;
` HRESULT hrRapiInit;
`} RAPIINIT;
`
`The first field, cbSize, should be set before calling CeRapiInitEx() with the size of the
`RAPIINIT structure. This is followed by heRapiInit, which will be filled in with the event
`handle that you can use to check on the status of your RAPI connection. The last field,
`
`2 of 22
`
`11/21/2016 8:17 PM
`
`Rosetta-2029
`
`0002
`
`
`
`Remote API (RAPI) :: Chapter 9. Desktop Synchronization :: Pocket pc ...
`
`http://etutorials.org/Programming/Pocket+pc+network+programming/Ch...
`
`hrRapiInit, will be filled in with the return code from CeRapiInitEx() once heRapiInit
`becomes signaled.
`The following code snippet shows how you can use the CeRapiInitEx() function to initialize
`your RAPI connection by using the WaitForSingleObject() function to monitor the RAPI
`event handle:
`
`HRESULT hr = S_OK;
`RAPIINIT rapiInit;
`
`memset(&rapiInit, 0, sizeof(RAPIINIT));
`rapiInit.cbSize = sizeof(RAPIINIT);
`
`hr = CeRapiInitEx(&rapiInit);
`if(FAILED(hr)) {
` if(hr == CERAPI_E_ALREADYINITIALIZED)
` OutputDebugString(TEXT("RAPI has already been
` initalized"));
` return FALSE;
`
`} /
`
`/ Wait for RAPI to be signaled
`DWORD dwResult = 0;
`dwResult = WaitForSingleObject(rapiInit.heRapiInit, 5000);
`if(dwResult == WAIT_TIMEOUT || dwResult == WAIT_ABANDONED) {
` // RAPI has failed or timed out. Proceed with cleanup
` CeRapiUninit();
` return FALSE;
`
`} i
`
`f(dwResult == WAIT_OBJECT_0 && SUCCEEDED(rapiInit.hrRapiInit)) {
` // RAPI has succeeded.
` OutputDebugString(TEXT("RAPI Initialized."));
`
` // Do something here
`}
`
`When working with applications that use RAPI, it is important to remember that you are relying
`on a network connection between the desktop and a device. When a function fails, an error can
`occur in either the RAPI layer or the function itself. You can determine where the error has
`actually occurred by calling into the CeRapiGetError() function, which is defined as follows:
`
`HRESULT CeRapiGetError(void);
`
`The function takes no parameters, and will return a value other than 0 if RAPI itself was
`responsible for the function failing. If CeRapiGetError() returns 0, however, you know that
`the error occurred in the actual remote function, and you can use the CeGetLastError()
`function to determine the error code, as shown in the following example:
`
`3 of 22
`
`11/21/2016 8:17 PM
`
`Rosetta-2029
`
`0003
`
`
`
`Remote API (RAPI) :: Chapter 9. Desktop Synchronization :: Pocket pc ...
`
`http://etutorials.org/Programming/Pocket+pc+network+programming/Ch...
`
`DWORD dwError = CeRapiGetError();
`
`if(dwError == 0) {
` // The error did not occur in RAPI, find out what the
` // remote function returned
` dwError = CeGetLastError();
`}
`
`A few functions (CeFindAllDatabases(), CeFindAllFiles(), and
`CeReadRecordProps()) will allocate memory on the desktop when they are called. In order to
`properly free this memory, you can use the following function:
`
`HRESULT CeRapiFreeBuffer(LPVOID);
`
`The only parameter you need to pass in is a pointer to the buffer that was allocated. If the
`function succeeds, then you will be returned a value of S_OK.
`When you have finished using RAPI, you must also make sure that you properly shut down the
`remote connection services. To do so, you can simply use the following function:
`
`HRESULT CeRapiUninit();
`
`The function takes no parameters, and will return a value of E_FAIL if RAPI has not been
`previously initialized.
`File System RAPI Functions
`Table 9.2 lists the Remote API functions for working with the Pocket PC file system.
`
`Table 9.2. RAPI File System Functions
`
`Remote File System Functions
`
`4 of 22
`
`11/21/2016 8:17 PM
`
`Rosetta-2029
`
`0004
`
`
`
`Remote API (RAPI) :: Chapter 9. Desktop Synchronization :: Pocket pc ...
`
`http://etutorials.org/Programming/Pocket+pc+network+programming/Ch...
`
`Remote File System Functions
`
`[View full width]
`
`BOOL CeCloseHandle(HANDLE);
`BOOL CeCopyFile(LPCWSTR, LPCWSTR, BOOL);
`BOOL CeCreateDirectory(LPCWSTR,
`LPSECURITY_ATTRIBUTES);
`BOOL CeDeleteFile(LPCWSTR);
`BOOL CeFindAllFiles(LPCWSTR, DWORD, LPDWORD,
` LPLPCE_FIND_DATA);
`BOOL CeFindClose(HANDLE);
`BOOL CeFindNextFile(HANDLE, LPCE_FIND_DATA);
`BOOL CeGetFileSize(HANDLE, LPDWORD);
`BOOL CeGetFileTime(HANDLE, LPFILETIME, LPFILETIME,
` LPFILETIME);
`BOOL CeMoveFile(LPCWSTR, LPCWSTR);
`BOOL CeReadFile(HANDLE, LPVOID, DWORD, LPDWORD,
` LPOVERLAPPED);
`BOOL CeRemoveDirectory(LPCWSTR);
`BOOL CeSetEndOfFile(HANDLE);
`BOOL CeSetFileAttributes(LPCWSTR, DWORD);
`BOOL CeSetFileTime(HANDLE, LPFILETIME, LPFILETIME,
` LPFILETIME);
`BOOL CeWriteFile(HANDLE, LPCVOID, DWORD, LPDWORD,
` LPOVERLAPPED);
`DWORD CeGetFileAttributes(LPCWSTR);
`DWORD CeSetFilePointer(HANDLE, LONG, PLONG,
`DWORD);
`HANDLE CeCreateFile(LPCWSTR, DWORD, DWORD,
` LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);
`HANDLE CeFindFirstFile(LPCWSTR, LPCE_FIND_DATA);
`
`The following example shows how you can use the Remote API's CeFindAllFiles() (as well
`as CeRapiFreeBuffer()) function on the desktop to easily retrieve a list of the wave files that
`are located on the device:
`
`5 of 22
`
`11/21/2016 8:17 PM
`
`Rosetta-2029
`
`0005
`
`
`
`Remote API (RAPI) :: Chapter 9. Desktop Synchronization :: Pocket pc ...
`
`http://etutorials.org/Programming/Pocket+pc+network+programming/Ch...
`
`LPVOID lpvFindData = NULL;
`DWORD dwFileCount = 0;
`
`// Get a list of the WAV files in the \Windows folder
`if(CeFindAllFiles(TEXT("\\Windows\\*.wav"),
` FAF_NO_HIDDEN_SYS_ROMMODULES|FAF_NAME, &dwFileCount,
` (LPLPCE_FIND_DATA)&lpvFindData) == FALSE) {
`
` DWORD dwError = CeRapiGetError();
` TCHAR tchError[128] = TEXT("\0");
`
` if(dwError == 0)
` dwError = CeGetLastError();
`
` wsprintf(tchError, TEXT("Error: %d"), dwError);
` OutputDebugString(tchError);
` return FALSE;
`
`} /
`
`/ Walk through the files
`LPCE_FIND_DATA pFindData = (LPCE_FIND_DATA)lpvFindData;
`
`for(DWORD dwCount = 0; dwCount<dwFileCount; dwCount++) {
` TCHAR tchFile[MAX_PATH+1] = TEXT("\0");
`
` wsprintf(tchFile, TEXT("Remote File:%s\r\n"),
` pFindData[dwCount].cFileName);
` OutputDebugString(tchFile);
`
`} /
`
`/ Clean up the buffer
`if(lpvFindData)
` CeRapiFreeBuffer(lpvFindData);
`
`Registry RAPI Functions
`Table 9.3 lists the Remote API functions that are available for manipulating the Pocket PC
`registry from the desktop host.
`
`Table 9.3. RAPI Registry Functions
`
`Remote Registry Functions
`
`6 of 22
`
`11/21/2016 8:17 PM
`
`Rosetta-2029
`
`0006
`
`
`
`Remote API (RAPI) :: Chapter 9. Desktop Synchronization :: Pocket pc ...
`
`http://etutorials.org/Programming/Pocket+pc+network+programming/Ch...
`
`Remote Registry Functions
`
`[View full width]
`
`LONG CeRegCloseKey(HKEY);
`LONG CeRegCreateKeyEx(HKEY, LPCWSTR, DWORD,
`LPWSTR, DWORD,
` REGSAM, LPSECURITY_ATTRIBUTES, PHKEY, LPDWORD);
`LONG CeRegDeleteKey(HKEY, LPCWSTR);
`LONG CeRegDeleteValue(HKEY, LPCWSTR);
`LONG CeRegEnumKeyEx(HKEY, DWORD, LPWSTR, LPDWORD,
`LPDWORD,
` LPWSTR, LPDWORD, PFILETIME);
`LONG CeRegEnumValue(HKEY, DWORD, LPWSTR, LPDWORD,
`LPDWORD,
` LPDWORD, LPBYTE, LPDWORD);
`LONG CeRegOpenKeyEx(HKEY, LPCWSTR, DWORD, REGSAM,
`PHKEY);
`LONG CeRegQueryInfoKey(HKEY, LPWSTR, LPDWORD,
`LPDWORD,
` LPDWORD, LPDWORD, LPDWORD, LPDWORD, LPDWORD,
`LPDWORD,
` LPDWORD, PFILETIME);
`LONG CeRegQueryValueEx(HKEY, LPCWSTR, LPDWORD,
`LPDWORD,
` LPBYTE, LPDWORD);
`LONG CeRegSetValueEx(HKEY, LPCWSTR, DWORD, DWORD,
`LPBYTE,
` DWORD);
`
`Database RAPI Functions
`Table 9.4 lists the Remote API functions for working with Pocket PC databases.
`
`Table 9.4. RAPI Database Functions
`
`Remote Database Functions
`
`7 of 22
`
`11/21/2016 8:17 PM
`
`Rosetta-2029
`
`0007
`
`
`
`Remote API (RAPI) :: Chapter 9. Desktop Synchronization :: Pocket pc ...
`
`http://etutorials.org/Programming/Pocket+pc+network+programming/Ch...
`
`Remote Database Functions
`
`[View full width]
`
`BOOL CeDeleteDatabase(CEOID);
`BOOL CeDeleteDatabaseEx(PCEGUID, CEOID);
`BOOL CeDeleteRecord(HANDLE, CEOID);
`BOOL CeEnumDBVolumes(PCEGUID, LPWSTR, DWORD);
`BOOL CeFindAllDatabases(DWORD, WORD, LPWORD,
` LPLPCEDB_FIND_DATA);
`BOOL CeFlushDBVol(PCEGUID);
`BOOL CeMountDBVol(PCEGUID, LPWSTR, DWORD);
`BOOL CeOidGetInfo(CEOID, CEOIDINFO*);
`BOOL CeOidGetInfoEx(PCEGUID, CEOID, CEOIDINFO*);
`BOOL CeSetDatabaseInfo(CEOID, CEDBASEINFO*);
`BOOL CeSetDatabaseInfoEx(PCEGUID, CEOID,
`CEDBASEINFO*);
`BOOL CeUnmountDBVol(PCEGUID);
`CEOID CeCreateDatabase(LPWSTR, DWORD, WORD,
`SORTORDERSPEC*);
`CEOID CeFindNextDatabase(HANDLE);
`CEOID CeCreateDatabaseEx(PCEGUID, CEDBASEINFO*);
`CEOID CeFindNextDatabaseEx(HANDLE, PCEGUID);
`CEOID CeReadRecordProps(HANDLE, DWORD, LPWORD,
`CEPROPID*,
` LPBYTE*, LPDWORD);
`CEOID CeReadRecordPropsEx(HANDLE, DWORD, LPWORD,
`CEPROPID*,
` LPBYTE*, LPDWORD, HANDLE);
`CEOID CeSeekDatabase(HANDLE, DWORD, DWORD,
`LPDWORD);
`CEOID CeWriteRecordProps(HANDLE, CEOID, WORD,
`CEPROPVAL*);
`CEOID CeWriteRecordProps(HANDLE, CEOID, WORD,
`CEPROPVAL*);
`HANDLE CeFindFirstDatabase(DWORD);
`HANDLE CeFindFirstDatabaseEx(PCEGUID, DWORD);
`HANDLE CeOpenDatabase(PCEOID, LPWSTR, CEPROPID,
`DWORD, HWND);
`HANDLE CeOpenDatabaseEx(PCEGUID, PCEOID, LPWSTR,
`CEPROPID,
` DWORD, CENOTIFYREQUEST *);
`
`System Configuration and Information RAPI Functions
`Table 9.5 lists the Remote API functions for retrieving Pocket PC configuration and system
`information.
`
`Table 9.5. RAPI System Information Functions
`
`Remote System Configuration and Information Functions
`
`8 of 22
`
`11/21/2016 8:17 PM
`
`Rosetta-2029
`
`0008
`
`
`
`Remote API (RAPI) :: Chapter 9. Desktop Synchronization :: Pocket pc ...
`
`http://etutorials.org/Programming/Pocket+pc+network+programming/Ch...
`
`Remote System Configuration and Information Functions
`
`[View full width]
`
`BOOL CeCheckPassword(LPWSTR);
`BOOL CeCreateProcess(LPCWSTR, LPCWSTR,
`LPSECURITY_ATTRIBUTES,
` LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID,
`LPWSTR,
` LPSTARTUPINFO, LPPROCESS_INFORMATION);
`BOOL CeGetStoreInformation(LPSTORE_INFORMATION);
`BOOL CeGetSystemPowerStatusEx(
`PSYSTEM_POWER_STATUS_EX, BOOL);
`BOOL CeGetVersionEx(LPCEOSVERSIONINFO);
`DWORD CeGetLastError(void);
`int CeGetDesktopDeviceCaps(int);
`int CeGetSystemMetrics(int);
`VOID CeGetSystemInfo(LPSYSTEM_INFO);
`VOID CeGlobalMemoryStatus(LPMEMORYSTATUS);
`
`Shell RAPI Functions
`Table 9.6 lists the Remote API shell management functions.
`
`Table 9.6. RAPI Shell Management Functions
`
`Remote Shell Functions
`
`BOOL CeSHGetShortcutTarget(LPWSTR, LPWSTR, int);
`DWORD CeGetSpecialFolderPath(int, DWORD, LPWSTR);
`DWORD CeGetTempPath(DWORD, LPWSTR);
`DWORD CeSHCreateShortcut(LPWSTR, LPWSTR);
`
`Window RAPI Functions
`Table 9.7 lists the Remote API window management functions.
`
`Table 9.7. RAPI Window Management Functions
`
`Remote Window Functions
`
`HWND CeGetWindow(HWND, UINT);
`int CeGetClassName(HWND, LPWSTR, int);
`int CeGetWindowText(HWND, LPWSTR, int);
`LONG CeGetWindowLong(HWND, int);
`
`Creating Your Own RAPI Functions
`While the Remote API provides a wide breadth of functions that cover most of the basic
`information you need about your Pocket PC device, there are certainly going to be times when
`
`9 of 22
`
`11/21/2016 8:17 PM
`
`Rosetta-2029
`
`0009
`
`
`
`Remote API (RAPI) :: Chapter 9. Desktop Synchronization :: Pocket pc ...
`
`http://etutorials.org/Programming/Pocket+pc+network+programming/Ch...
`
`you will need to communicate with your device in a way that isn't supported by the supplied
`functions. Fortunately, RAPI also provides you with an API that gives you the capability to create
`and execute your own functions on the Pocket PC.
`
`You can use two different methods to call your own RAPI functions:
`
`1.
`Block mode. When you call a remote function through RAPI in block (or synchronous)
`mode, your desktop application will not be returned control until the function has
`completed. RAPI will send the command to the device, load the specified DLL into
`memory, call the function you want to execute, and return any data through RAPI when it
`is finished.
`
`2.
`Stream mode. When calling a remote function in stream (or asynchronous) mode, your
`application is returned control immediately after making the call. You then need to use an
`IRAPIStream COM interface (based on IStream) to send data back and forth between
`the desktop and the remote device. Using stream mode typically provides faster
`communications with a remote device than block mode.
`Both block mode and stream mode use the same function, CeRapiInvoke(), to execute your
`own user-defined function, and is defined as follows:
`
`HRESULT CeRapiInvoke(LPCWSTR pDllPath, LPCWSTR
` pFunctionName, DWORD cbInput, BYTE *pInput, DWORD *pcbOutput,
` BYTE **ppOutput, IRAPIStream **ppIRAPIStream, DWORD dwReserved);
`
`The first parameter, pDllPath, should point to a null-terminated string that contains the full
`name and path of the DLL (in Unicode) on the Pocket PC that contains the function you are
`calling. The next parameter, pFunctionName, is the name of the function that you want RAPI
`to execute.
`
`The next two parameters are used to set up the data you are going to send to the remote
`function. The cbInput parameter should specify the number of bytes that are located in the
`data buffer, which is specified by the pointer to which you set the pInput parameter. Be aware
`that the buffer you pass in the pInput parameter will be freed by the function you are calling
`into, so you should make sure that you allocate it by using the LocalAlloc() function.
`The pcbOutput and ppOutput parameters are used to receive data from the remote function.
`The pcbOutput parameter is a pointer to a DWORD value that will be filled in with the number of
`bytes that are contained in the data buffer to which ppOutput points. Because the remote
`function (and RAPI) has allocated memory on the desktop for the returned data buffer, you need
`to remember to call the LocalFree() function to free the memory that is being used by the
`ppOutput buffer when you are finished using it.
`The ppIRAPIStream parameter will determine whether you are using stream mode or block
`mode to call the remote function. To call your function using block mode, you can simply set this
`to NULL. To use stream mode, you need to set this parameter to a pointer of an IRAPIStream
`interface.
`
`The last parameter is reserved, and should be set to 0.
`
`Although you can name your remote function anything you like, you have to make sure that it
`
`10 of 22
`
`11/21/2016 8:17 PM
`
`Rosetta-2029
`
`0010
`
`
`
`Remote API (RAPI) :: Chapter 9. Desktop Synchronization :: Pocket pc ...
`
`http://etutorials.org/Programming/Pocket+pc+network+programming/Ch...
`
`matches the following prototype:
`
`STDAPI RAPIFunctionName(DWORD cbInput, BYTE *pInput, DWORD
` *pcbOutput, BYTE **ppOutput, IRAPIStream *pIRAPIStream);
`
`The first two parameters, cbInput and pInput, specify the size and data buffer parameters,
`respectively, that are passed from the desktop call to CeRapiInvoke(). Because RAPI has
`automatically allocated data for pInput, your function needs to call LocalFree() on the
`buffer that is being passed in so that memory can be properly managed.
`The next two parameters, pcbOutput and ppOutput, are used to allocate a buffer, set the
`size of it, and return data to the desktop. The desktop application calling your remote function is
`responsible for freeing any data you allocate for the output buffer.
`The last parameter, pIRAPIStream, will point to an IRAPIStream object that RAPI has
`allocated if you are communicating with your desktop counterpart in stream mode.
`Now that you know how to call your own remote functions using CeRapiInvoke(), let's take a
`look at what's actually involved with writing a remote function that returns information from the
`Subscriber Identity Module (SIM) phonebook on a Pocket PC Phone Edition device (see
`Chapter 8 for more information about using the SIM Manager APIs).
`Using Block Mode
`Calling your own functions using RAPI's block mode interface is extremely straightforward. All
`you need to do is create a DLL for the Pocket PC device that contains the functions you need
`(following the prototype shown above). A desktop application can then use CeRapiInvoke()
`to call your function (be sure to pass in NULL for the ppIRAPIStream parameter). Essentially,
`this operates in the same fashion as all of the standard RAPI function calls.
`
`Let's take a look at how you can create a RAPI function to read a specific phonebook entry by
`using the SimReadPhonebookEntry() function on a Pocket PC Phone Edition device.
`The code for the DLL that you will be putting on your Pocket PC Phone Edition device would
`look like the following:
`
`11 of 22
`
`11/21/2016 8:17 PM
`
`Rosetta-2029
`
`0011
`
`
`
`Remote API (RAPI) :: Chapter 9. Desktop Synchronization :: Pocket pc ...
`
`http://etutorials.org/Programming/Pocket+pc+network+programming/Ch...
`
`#include <windows.h>
`#include <Simmgr.h>
`
`// Exported function prototypes
`#ifdef __cplusplus
`extern "C" {
`#endif
`__declspec(dllexport) INT MyCeGetPhonebookEntry(DWORD,
` BYTE *, DWORD *, BYTE **, PVOID);
`#ifdef __cplusplus
`
`}#
`
`endif
`
`// Standard DLL entry point
`BOOL WINAPI DllMain(HANDLE hinstDLL, DWORD dwReason,
` LPVOID lpvReserved)
`
`{
`
` return TRUE;
`
`} /
`
`/ Remote Block Function
`int MyCeGetPhonebookEntry(DWORD cbInput, BYTE *pInput,
` DWORD *pcbOutput, BYTE **ppOutput, PVOID *pVoid)
`
`{
`
` // Check to see if we have an input buffer
` if(!pInput || sizeof(cbInput)>4)
` return ‐1;
`
` // Get the phone entry that was requested
` DWORD dwEntry = 0;
` memcpy(&dwEntry, pInput, cbInput);
`
` // Free up the buffer that was passed in
` LocalFree(pInput);
`
`// Initialize the SIM
`HRESULT hr = S_OK;
`HSIM hSim = NULL;
`
`if(FAILED(SimInitialize(0, NULL, 0, &hSim)))
` return ‐1;
`
`// Get the data from the SIM
`SIMPHONEBOOKENTRY simEntry;
`
`memset(&simEntry, 0, sizeof(SIMPHONEBOOKENTRY));
`simEntry.cbSize = sizeof(SIMPHONEBOOKENTRY);
`
`hr = SimReadPhonebookEntry(hSim, SIM_PBSTORAGE_SIM,
` dwEntry, &simEntry);
`
`SimDeinitialize(hSim);
`
`12 of 22
`
`11/21/2016 8:17 PM
`
`Rosetta-2029
`
`0012
`
`
`
`Remote API (RAPI) :: Chapter 9. Desktop Synchronization :: Pocket pc ...
`
`http://etutorials.org/Programming/Pocket+pc+network+programming/Ch...
`
`// If the read failed, just exit
`if(FAILED(hr))
` return ‐1;
`
`// Allocate the return buffer
`DWORD dwBufferLength =
` (MAX_LENGTH_PHONEBOOKENTRYTEXT+MAX_LENGTH_ADDRESS+1);
`TCHAR tchBuffer[MAX_LENGTH_PHONEBOOKENTRYTEXT+MAX_
` LENGTH_ADDRESS+1];
`BYTE *pOutputBuffer = NULL;
`
`pOutputBuffer = (BYTE*)LocalAlloc(LPTR, dwBufferLength);
`
`if(!pOutputBuffer)
` return ‐1;
`
`// Copy the name and phone to the buffer
`wsprintf(tchBuffer, TEXT("%s %s"), simEntry.lpszText,
` simEntry.lpszAddress);
`
`// Convert it to non‐unicode
`wcstombs((char *)pOutputBuffer, tchBuffer,
` dwBufferLength);
`
`// Set up for the return
`*ppOutput = (BYTE *)pOutputBuffer;
` *pcbOutput = dwBufferLength;
` return 1;
`}
`
`Your code on the desktop for calling the remote function, MyCeGetPhonebookEntry(), in
`block mode is as follows:
`
`13 of 22
`
`11/21/2016 8:17 PM
`
`Rosetta-2029
`
`0013
`
`
`
`Remote API (RAPI) :: Chapter 9. Desktop Synchronization :: Pocket pc ...
`
`http://etutorials.org/Programming/Pocket+pc+network+programming/Ch...
`
`#include <windows.h>
`#include <stdio.h>
`#include <tchar.h>
`#include <rapi.h>
`
`// Entry point for a console app on the desktop
`int wmain()
`
`{
`
` HRESULT hr = S_OK;
`
` // Initalize RAPI
` hr = CeRapiInit();
` if(FAILED(hr)) {
` printf("Could not initialize RAPI\r\n");
` return ‐1;
` }
`
` // Set up stuff to send over
` DWORD dwSIMEntry = 1;
` DWORD dwSize = sizeof(dwSIMEntry);
` DWORD dwOutputSize = 0;
` BYTE *pOutput = NULL;
` BYTE *pInput = NULL;
`
` pInput = (BYTE *)LocalAlloc(LPTR, dwSize);
` memcpy(pInput, &dwSIMEntry, dwSize);
`
` // Call into the Remote API function
` hr = CeRapiInvoke(TEXT("myrapice"),
` TEXT("MyCeGetPhonebookEntry"), dwSize,
` pInput, &dwOutputSize, &pOutput, NULL, 0);
`
` if(FAILED(hr)) {
` printf("Could not get SIM information!\r\n");
` CeRapiUninit();
` return ‐1;
` }
`
` if(pOutput) {
` printf((char *)pOutput);
` LocalFree(pOutput);
` }
`
` CeRapiUninit();
` return 0;
`}
`
`In order to call this function in block mode from the desktop, you need to first allocate a buffer
`that will be used to pass information to the remote function. In this case, you want to pass in an
`argument that indicates which entry number from the SIM phonebook you are interested in.
`Once you have allocated a DWORD, you set it with the entry number you would like, and call the
`
`14 of 22
`
`11/21/2016 8:17 PM
`
`Rosetta-2029
`
`0014
`
`
`
`Remote API (RAPI) :: Chapter 9. Desktop Synchronization :: Pocket pc ...
`
`http://etutorials.org/Programming/Pocket+pc+network+programming/Ch...
`
`CeRapiInvoke() function. When the call returns, the output buffer will be filled in with a
`null-terminated string that contains the name and phone number of the entry. You must
`remember to call LocalFree() on the returned buffer in order to properly free the allocated
`memory.
`Using Stream Mode
`Although using the Remote API's stream mode to communicate with a device might seem a bit
`more complicated because it uses a COM object to send and receive data, using it is actually
`fairly straightforward, and the benefits outweigh the additional code. Not only will you have
`control returned to your application immediately after calling CeRapiInvoke(), using stream
`mode also enables you to more precisely control the flow of data between the desktop and a
`device.
`To use stream mode, all you need to do is call the CeRapiInvoke() function and pass in a
`pointer to an IRAPIStream object that has been initialized and set to NULL for the
`ppIRAPIStream parameter, as shown in the following example:
`
`IRAPIStream *pIRAPIStream = NULL;
`DWORD dwOutputSize = 0;
`BYTE *pOutput = NULL;
`
`// Initalize the RAPI Stream interface
`CoInitialize(NULL);
`
`// Call into the Remote API function
`hr = CeRapiInvoke(TEXT("myrapice"), TEXT("MyCeSimDir"),
` 0, NULL, &dwOutputSize, &pOutput, &pIRAPIStream, 0);
`
`As you can see, what makes using stream mode easy is that RAPI itself implements the
`IRAPIStream object?you only need to talk to the object to send and receive data.
`The IRAPIStream interface is based on the standard IStream, which generically supports
`sending and receiving data from other stream objects. Only two additional methods have been
`added to the IRAPIStream interface, and they enable you to get and set timeout values for
`your communications stream. They are defined as follows:
`
`HRESULT SetRapiStat(RAPISTREAMFLAG Flag, DWORD dwValue);
`HRESULT GetRapiStat(RAPISTREAMFLAG Flag, DWORD *pdwValue);
`
`For both setting and getting the timeout value, the first parameter must be set to
`STREAM_TIMEOUT_READ. If you are setting the timeout value, you should set dwValue to the
`amount of time you want to elapse before the communications stream times out. If you are
`getting the value, then you need to pass in only a pointer to a DWORD variable that will receive
`the set timeout.
`When calling a remote function using stream mode, you can still use CeRapiInvoke() to pass
`in some initial data using its cbInput and pInput parameters. However, once the initial call
`has been made, it is recommended that you use the stream object's Read() and Write()
`methods to pass data back and forth.
`
`Let's take a look at what would be involved if you wanted to use RAPI's stream mode to get a
`directory of phonebook entries from the SIM card on a Pocket PC Phone Edition device.
`
`15 of 22
`
`11/21/2016 8:17 PM
`
`Rosetta-2029
`
`0015
`
`
`
`Remote API (RAPI) :: Chapter 9. Desktop Synchronization :: Pocket pc ...
`
`http://etutorials.org/Programming/Pocket+pc+network+programming/Ch...
`
`The code for the DLL that contains the MyCeSimDir() command you will be putting on your
`Pocket PC Phone Edition device would look like the following:
`
`16 of 22
`
`11/21/2016 8:17 PM
`
`Rosetta-2029
`
`0016
`
`
`
`Remote API (RAPI) :: Chapter 9. Desktop Synchronization :: Pocket pc ...
`
`http://etutorials.org/Programming/Pocket+pc+network+programming/Ch...
`
`#include <windows.h>
`#include <Simmgr.h>
`#include <rapi.h>
`
`#ifdef __cplusplus
`extern "C" {
`#endif
`
`__declspec(dllexport) INT MyCeSimDir(DWORD, BYTE *, DWORD *,
` BYTE **, IRAPIStream *);
`#ifdef __cplusplus
`
`}#
`
`endif
`
`BOOL WINAPI DllMain(HANDLE hinstDLL, DWORD dwReason,
` LPVOID lpvReserved)
`
`{
`
` return TRUE;
`
`} i
`
`nt MyCeSimDir(DWORD cbInput, BYTE *pInput,
` DWORD *pcbOutput, BYTE **ppOutput, IRAPIStream *pIRAPIStream)
`
`{
`
` // This sample will return all entries, so ignore the
` // buffer that was passed in
` if(pInput)
` LocalFree(pInput);
`
` // Make sure that the IRAPIStream is valid
` if(!pIRAPIStream)
` return ‐1;
`
` // Initialize the SIM
` HRESULT hr = S_OK;
` HSIM hSim = NULL;
`
` if(FAILED(SimInitialize(0, NULL, 0, &hSim)))
` return ‐1;
`
` // Get the total number of entries
` DWORD dwUsed = 0, dwTotal = 0;
`
` hr = SimGetPhonebookStatus(hSim, SIM_PBSTORAGE_SIM,
` &dwUsed, &dwTotal);
`
` if(FAILED(hr)) {
` SimDeinitialize(hSim);
` return ‐1;
` }
`
` // Make sure there's something to return
` if(dwUsed == 0) {
` SimDeinitialize(hSim);
`
`17 of 22
`
`11/21/2016 8:17 PM
`
`Rosetta-2029
`
`0017
`
`
`
`Remote API (RAPI) :: Chapter 9. Desktop Synchronization :: Pocket pc ...
`
`http://etutorials.org/Programming/Pocket+pc+network+programming/Ch...
`
` return ‐1;
` }
`
` // Get each entry
` // We'll pass them back as a Name [Phonenumber] string.
` SIMPHONEBOOKENTRY simEntry;
` TCHAR tchEntry[MAX_LENGTH_PHONEBOOKENTRYTEXT+
` MAX_LENGTH_ADDRESS+1];
` DWORD dwLength = 0, dwBytesWritten = 0;
`
` for(DWORD dwEntry = 0; dwEntry<dwUsed; dwEntry++) {
` memset(&simEntry, 0, sizeof(SIMPHONEBOOKENTRY));
` simEntry.cbSize = sizeof(SIMPHONEBOOKENTRY);
`
` hr = SimReadPhonebookEntry(hSim, SIM_PBSTORAGE_SIM,
` dwEntry, &simEntry);
` if(FAILED(hr))
` break;
`
` // Build the string
` memset(tchEntry, 0,
` MAX_LENGTH_PHONEBOOKENTRYTEXT+MAX_LENGTH_ADDRESS+1);
` wsprintf(tchEntry, TEXT("%s [%s]"), simEntry.lpszText,
` simEntry.lpszAddress);
`
` // Write it to the stream
` // First, send the length
` dwLength = (lstrlen(tchEntry)+1)*sizeof(TCHAR);
` hr = pIRAPIStream‐>Write(&dwLength, sizeof(dwLength),
` &dwBytesWritten);
`
` // Next, send the buffer
` hr = pIRAPIStream‐>Write(tchEntry, dwLength,
` &dwBytesWritten);
` if(FAILED(hr))
` break;
`
`} /
`
`/ Clean up
`SimDeinitialize(hSim);
`
` // Send that there's "No more data"
` DWORD dwFinished = 0xFFFFFFFF;
` hr = pIRAPIStream‐>Write(&dwFinished, sizeof(dwFinished),
` &dwBytesWritten);
`
` // Release the stream interface
` pIRAPIStream‐>Release();
` return 0;
`}
`
`On the desktop side, you can create a simple console application that will call into your remote
`function using stream mode to output the contents of the SIM phonebook:
`
`18 of 22
`
`11/21/2016 8:17 PM
`
`Rosetta-2029
`
`0018
`
`
`
`Remote API (RAPI) :: Chapter 9. Desktop Synchronization :: Pocket pc ...
`
`http://etutorials.org/Programming/Pocket+pc+network+programming/Ch...
`
`#include <windows.h>
`#include <stdio.h>
`#include <tchar.h>
`#include <rapi.h>
`
`#define BUFFER_SIZE 1024
`
`// Entry point for a console app on the desktop
`int wmain()
`
`{
`
` HRESULT hr = S_OK;
`
` // Initalize RAPI
` hr = CeRapiInit();
` if(FAILED(hr)) {
` printf("Could not initialize RAPI\r\n");
` return ‐1;
` }
`
` // Set up stuff to send over
` IRAPIStream *pIRAPIStream = NULL;
` DWORD dwOutputSize = 0;
` BYTE *pOutput = NULL;
`
` // Initalize the RAPI Stream interface
` CoInitialize(NULL);
`
` // Call into the Remote API function
` hr = CeRapiInvoke(TEXT("myrapice"), TEXT("MyCeSimDir"),
` 0, NULL, &dwOutputSize, &pOutput, &pIRAPIStream, 0);
`
` if(FAILED(hr)) {
` DWORD dwError = CeRapiGetError();
` if(dwError == 0)
` dwError = CeGetLastError();
`
` printf("Could not get SIM information! Error: %u\r\n",
` dwError);
` CeRapiUninit();
` return ‐1;
` }
`
` // Read from the remote stream
` TCHAR tchEntry[BUFFER_SIZE+1];
` DWORD dwSize = BUFFER_SIZE;
` DWORD dwBytesRead = 0;
` DWORD dwLength = 0;
`
` do {
` // Get the length. If it is 0xFFFFFFFF, we're done.
` hr = pIRAPIStream‐>Read(&dwLength, sizeof(dwLength),
` &dwBytesRead);
`
`19 of 22
`
`11/21/2016 8:17 PM
`
`Rosetta-2029
`
`0019
`
`
`
`Remote API (RAPI) :: Chapter 9. Desktop Synchronization :: Pocket pc ...
`
`http://etutorials.org/Programming/Pocket+pc+network+programming/Ch...
`
` if(FAILED(hr) || dwLength == 0xFFFFFFFF)
` break;
`
` // Ok, read the buffer
` hr = pIRAPIStream‐>Read(tchE