Windows mobile/WinCE RAPI教程(二)

 

6.自定义RAPI函数

无论RAPI接口支持多少函数,总会出现一些应用程序需要的但RAPI接口没有提供的函数。RAPI为PC提供一种方法去调用 Windows CE上的用户定义的函数。

你可以使用两种方法来调用用户定义的函数。一种是“阻塞模式”,另一种是“流模式”

下面这段是它的英文介绍。

You can invoke a user-defined RAPI function in one of two ways. The first way is called block mode. In block mode, you make a call to the RAPI remote invocation function, the function makes the call to a specified function in a specified DLL, the DLL function does its thing and returns, and the RAPI function then returns to the calling PC program with the output. The second method is called stream mode. In this mode, the RAPI call to the function returns immediately, but a connection is maintained between the calling PC application and the Windows CE DLL–based function. This method allows information to be fed back to the PC on an ongoing basis.

6.1 使用RAPI调用自定义函数。

CeRapiInvoke将允许我们调用远程设备中的任何API函数!不过不是直接调用,仍然需要对远程API进行一些“包装”。

CeRapiInvoke的原型如下:

STDAPI_( HRESULT ) CeRapiInvoke(
    LPCWSTR pDllPath,                      // 包含API的Dll文件完整路径
    LPCWSTR pFunctionName,         // 要调用的函数名
    DWORD cbInput,                           // 函数输入缓冲区大小
    BYTE * pInput,                               // 函数输入缓冲区指针
    DWORD * pcbOutput,                  // 函数输出缓冲区大小
    BYTE ** ppOutput,                       // 函数输出缓冲区指针
    IRAPIStream ** ppIRAPIStream,  // 指定使用阻塞模式或流模式
    DWORD dwReserved);                // 保留

下面这段英文是它的详细介绍

The first parameter to CeRapiInvoke is the name of the DLL on the Windows CE device that contains the function you want to call. The name must be in Unicode but can include a path. If no path is specified, the DLL is assumed to be in the /windows directory on the device. The second parameter is the name of the function to be called. The function name must be in Unicode and is case specific.

The next two parameters, cbInput and pInput, should be set to the buffer containing the data and the size of that data to be sent to the Windows CE–based function. The input buffer should be allocated in the local heap of the application. When you call CeRapiInvoke, this buffer will be freed by the function. The pcbOutput and ppOutput parameters are both pointers—the first a pointer to a DWORD that receives the size of the data returned and the second a pointer to a PBYTE variable that receives the pointer to the buffer containing the data returned by the Windows CE function. The buffer returned by CeRapiInvoke is allocated by the function in your local heap. You're responsible for freeing this buffer.

6.2 编写RAPI服务器函数(CE端的DLL中的函数)

你不能调用Windows CE DLL 中的所有函数。函数结构必须符合下面的函数原型

STDAPI INT FuncName (DWORD cbInput, BYTE *pInput, DWORD *pcbOutput,

                     BYTE **ppOutput, IRAPIStream *pIRAPIStream);

这些参数与CeRapiInvoke非常匹配。

6.3 阻塞模式的例子代码

CE端的DLL程序。

RapiServ.c

//===================================================================

#include <windows.h>                 // For all that Windows stuff

   

// The following ensures that the function will be exported from the DLL

// and that any C++ compilers used won't mangle the name.

#ifdef __cplusplus

extern "C" {

#endif

__declspec (dllexport) INT RAPIGetDiskSize (DWORD, BYTE *, DWORD *,

                                            BYTE **, PVOID);

#ifdef __cplusplus

}

#endif

//===================================================================

// DllMain - DLL initialization entry point

BOOL WINAPI DllMain (HANDLE hinstDLL, DWORD dwReason,

                     LPVOID lpvReserved) {

    return TRUE;

}

//===================================================================

// RAPIGetDiskSize - Returns the disk size and free space.  Called from

// PC application using RAPI.

//

INT RAPIGetDiskSize (DWORD cbInput, BYTE *pInput, DWORD *pcbOutput,

                     BYTE **ppOutput, PVOID reserved) {

    PDWORD pdwLocal;

    LPTSTR pPtr;

    DWORD i;

    int rc = 0;

    ULARGE_INTEGER lnFree, lnTotal;

   

    *pcbOutput = 0;            // Zero output bytes for now.

if (!pInput) return –1;    // Make sure there is an input buffer.

    // 判断是否已零结束的字符串

    pPtr = (LPTSTR)pInput;

    for (i = 0; i < cbInput / 2; i++)

        if (!*pPtr++)

            break;

    // 如果是非零结束或字符串长度等于零返回-2

if ((i >= cbInput / 2) || (i == 0)) 

{

        LocalFree (pInput);

        return -2;

    }

   

    // 调用GetDiskFreeSpaceEx函数

    if (GetDiskFreeSpaceEx ((LPTSTR)pInput, NULL, &lnTotal, &lnFree)) {

   

        // Allocate memory for the return buffer.

        pdwLocal = (PDWORD) LocalAlloc (LPTR, 2 * sizeof (DWORD));

        if (pdwLocal) {

            // Copy data from function to output buffer.

            pdwLocal[0] = lnTotal.LowPart;

            pdwLocal[1] = lnFree.LowPart;

            // Specify size and buffer.

            *pcbOutput = 2 * sizeof (DWORD);

            *ppOutput = (PBYTE)pdwLocal;

        } else

            rc = GetLastError();

    } else

        rc = GetLastError();

    // The function is responsible for freeing the input buffer.

    LocalFree (pInput);

    return rc;

}

__declspec (dllexport) INT RAPIGetDiskSize

告诉链接程序已导出的山数,这样 外部模块就可以直接调用这个函数。

  RAPIGetDiskSize的输入缓冲区被用来将目录名称传递到DLL,而输出缓冲区将返回传递的目录的总的磁盘空间和自由空间。输入和输出缓冲区的格式完全由你决定,然而,输入缓冲区应使用 LocalAlloc来分配,这样RAPI库可以在它使用完后释放它。

   

   在PC端,调用堵塞模式RAPI服务器函数应像下面这样。

//-----------------------------------------------------------------------

// MyCeGetDiskFreeSpaceEx - Homegrown implementation of a RAPI

// GetDiskFreeSpace function

//

BOOL MyCeGetDiskFreeSpaceEx (LPWSTR pszDir, PDWORD pdwTotal,

                             PDWORD pdwFree) {

    HRESULT hr;

    DWORD dwIn, dwOut;

    LPBYTE pInput;

    LPWSTR pPtr;

    PDWORD pOut;

    BOOL bRC = FALSE;

   

    // Get length of Unicode string.

    for (dwIn = 2, pPtr = pszDir; *pPtr++; dwIn+=2);

    // Allocate buffer for input.

    pInput = LocalAlloc (LPTR, dwIn);

    if (!pInput)

        return FALSE;

    // Copy directory name into input buffer.

    memcpy (pInput, pszDir, dwIn);

   

    // Call function on Windows CE device.

    hr = CeRapiInvoke (L"RapiServ", L"RAPIGetDiskSize", dwIn,

                       pInput, &dwOut, (PBYTE *)&pOut, NULL, 0);

   

    // If successful, return total and free values.

    if (hr == 0) {

        *pdwTotal = pOut[0];

        *pdwFree = pOut[1];

        bRC = TRUE;

    }

    LocalFree (pOut);

    return bRC;

}

这个函数封装拉对CeRapiInvoke的调用,这样该调用看起来就像另一个Windows CE RAPI调用。当函数返回时,由返回代码指出调用的 成功或失败。CeRapiInvoke将释放传递给它的输入缓冲区。然后从输入缓冲区复制这些数据,并且那个缓冲区将用LocalFree()来释放。

6.4 流模式

流模式RAPI调用与阻塞模式不同,在流模式中,初始化RAPI调用将创建PC应用程序与Windows CE设备上的服务器程序之间的链接。当在流模式中调用CeRapiInvoke时,这个函数将立即返回。你此时使用IRAPIStream接口来与服务器DLL通信。你可以使用一个指针访问这个接口,该指针由CeRapiInvoke调用在由ppIRAPIStream指向的变量中返回。

Following is a call to CeRapiInvoke that establishes a stream connection and then writes and reads back 10 bytes from the remote server DLL.

DWORD dwIn, dwOut, cbBytes;

IRAPIStream *pIRAPIStream;

BYTE bBuff[BUFF_SIZE];

PBYTE pOut;

HRESULT hr;

   

// RAPI call

hr = CeRapiInvoke (L"ServDLL", L"RAPIRmtFunc", dwIn, bBuff,

                   &dwOut, &pOut, &pIRAPIStream, 0);

if (hr == S_OK) 

{

    // Write 10 bytes.

    pIRAPIStream->Write (bBuff, 10, &cbBytes);

    // Read data from server.

    pIRAPIStream->Read (bBuff, 10, &cbBytes);

}

pIRAPIStream->Release ();

When establishing a stream connection, you can still use the input buffer to pass initial data down to the remote server. From then on, you should use the Read and Write methods of IRAPIStream to communicate with the server. When you're finished with the IRAPIStream interface, you must call Release to release the interface.

你可能感兴趣的:(windows,api,服务器,null,dll,byte)