使用RAPI库操作移动设备——C#语言描述 (转贴)














引言
SMARTPHONE SDK API 库
管理设备中的目录文件
取系统信息
远程操作电话和短信功能

    Windows Mobile日益成熟,开发者队伍也越来越壮大。作为一个10年的计算机热爱者和程序员,我也经受不住新技术的诱惑,倒腾起Mobile这个玩具。Mobile和Windows的血缘关系决定了它在Windows程序员中的受欢迎程度,在网络上随便搜索一下,关于Mobile应用、开发的文章数不胜数。可是对于计划开发一款全能的Desktop<=>Device同步管理程序的我来说,却发现资源少得可怜——仅仅在MSDN和两个国外的Developer网站上发现了一点资料。现在我仍然在搜索学习中,在这里把我迄今掌握的一点心得写出来,希望能起到抛砖引玉的功效。另请各位高手指正。


    Mobile的开发资源很繁杂,很多人常常弄不清究竟要安装哪些工具才能搭建出合适的开发环境。但是我相信Microsoft SMARTPHONE 2003 SDK和Microsoft POCKETPC 2003 SDK是所有的人都知道的,它们分别为SmartPhone和PocketPC提供了必不可少的支持。兄弟我至今没有做出什么成绩,囊中羞涩,好容易攒了台SmartPhone,今天就已Microsoft SMARTPHONE 2003 SDK为例吧。


    SMARTPHONE SDK包含了大量的API,列表如下(选自SDK文档,本人翻译):





































































Smartphone API Description
ActiveSync 创建移动应用程序安装和配置,同步服务模块,过滤器和协助访问ActiveSync服务的应用。
Bluetooth API 创建支持蓝牙设备的Mobile应用程序,比如耳机,打印机和其他移动设备。
CE Messaging (CEMAPI) 创建messaging applications
Configuration Service Providers 创建可配置各种CSPs(Configuration Service Providers)的应用
Connection Manager 创建可自动管理移动设备网络连接的应用
Control API 在你的移动应用程序中使用Smartphone控件
Device Management API 创建可远程访问移动设备配置管理的应用程序
Game API (GAPI) 创建高性能的实时游戏
Home Screen API 创建用户界面插件
HTML Control 创建可显示HTML文本和嵌入图片,解析XML和绑定URL到别名的应用程序
MIDI 创建可播放MIDI文件的应用程序
Object Exchange (OBEX) 创建对象交换应用,允许移动设备自由的通过无线交换数据
Pocket Outlook Object Model (POOM) API 创建可操作收件箱部件(联系人,日历和任务)的移动应用程序
Projects Control 创建可以和Projects Control交互的应用
Remote API (RAPI) 创建可以同步或控制移动设备的桌面应用程序
Speech Recognizer 为应用程序增加语音识别功能(比如语音拨号)
Telephony 创建支持电话和短信的应用程序
User Interface 管理输入面板,增加用户界面元素到你的移动应用程序
Vibrate API 为你的移动应用程序增加震动特性
Voice Recorder Control 创建移动数字录音程序
Windows User Interface Controls 创建将移动扩展合并到标准Microsoft® Windows® CE用户界面控件的应用

    要创建Desktop<=>Device的桌面同步管理程序,主要就依靠SDK API中的Remote API(RAPI)。RAPI 库由一组函数组成,这些函数可用于通过桌面应用程序管理设备,包括设备的目录文件、设备的注册表和系统信息。废话不多说,我们先来看看如何管理设备中的目录文件


    RAPI提供了一组文件管理的方法(不完全列表,详见SDK文档。选自SDK文档,本人翻译):
















































Function Description
CeCopyFile 复制文件
CeCreateDirectory 创建目录
CeCreateFile 创建,打开文件、管道、通讯资源、磁盘设备或者控制台。返回一个句柄用来访问对象。
CeDeleteFile 删除文件
CeFindAllFiles 从指定的Windows CE目录中获取所有文件和目录的信息,并且复制到一个包含CE_FIND_DATA结构的数组中
CeFindFirstFile 在目录中查找匹配给定文件名的一个文件
CeFindClose 关闭指定的查找句柄,CeFindFirstFileCeFindNextFile 函数用这个句柄查找文件
CeFindNextFile 从上一次访问的CeFindFirstFile继续查找文件
CeGetFileAttributes 返回指定文件或目录的属性
CeGetFileSize 获取指定文件的字节大小
CeGetFileTime 获取文件创建日期时间,最后访问日期时间和最后修改日期时间
CeMoveFile 移动(重命名)一个文件或者目录
CeReadFile 从文件指针处读取文件数据
CeWriteFile 从文件指针处写入文件数据

    首先要说明的是,任何RAPI操作都需要首先初始化与设备的连接:









Function Description
CeRapiInit (RAPI) 创建Windows CE remote application-programming interface (RAPI).






[C#.NET]
 
using System;
using System.Runtime.InteropServices;
public class RAPI
{
public void RapiInit()
{
int ret = CeRapiInit();

if( ret != 0)
{
// 连接失败,获取失败代码
int e = CeRapiGetError();

// 抛出异常
Marshal.ThrowExceptionForHR(ret);
}

// 连接成功
// To Do

}

[DllImport("rapi.dll", CharSet=CharSet.Unicode)]
internal static extern int CeRapiGetError();

[DllImport("rapi.dll", CharSet=CharSet.Unicode)]
internal static extern int CeRapiInit();
}
 

    连接建立后,就可以进行文件操作了。看一个将文件复制到设备的例子:







[C#.NET]
using System;
using System.Runtime.InteropServices;
using System.IO;
public class RAPI
{
private const uint GENERIC_WRITE = 0x40000000; // 设置读写权限
private const short CREATE_NEW = 1; // 创建新文件
private const short FILE_ATTRIBUTE_NORMAL = 0x80; // 设置文件属性
private const short INVALID_HANDLE_VALUE = -1; // 错误句柄

IntPtr remoteFile = IntPtr.Zero;
String LocalFileName = @"
c:\test.txt"; // 本地计算机文件名
String RemoteFileName = @"\My Documents\test.txt"; // 远程设备文件名
byte[] buffer = new byte[0x1000]; // 传输缓冲区定义为4k
FileStream localFile;

int bytesread = 0;
int byteswritten = 0;
int filepos = 0;

public RapiFile()
{
// 创建远程文件
remoteFile = CeCreateFile(RemoteFileName, GENERIC_WRITE, 0, 0, CREATE_NEW,
FILE_ATTRIBUTE_NORMAL, 0);

// 检查文件是否创建成功
if ((int)remoteFile == INVALID_HANDLE_VALUE)
{
throw new Exception("Could not create remote file");
}

// 打开本地文件
localFile = new FileStream(LocalFileName, FileMode.Open);

// 读取4K字节
bytesread = localFile.Read(buffer, filepos, buffer.Length);
while(bytesread > 0)
{
// 移动文件指针到已读取的位置
filepos += bytesread;

// 写缓冲区数据到远程设备文件
if(! Convert.ToBoolean(CeWriteFile(remoteFile, buffer, bytesread,
ref byteswritten, 0)))
{ // 检查是否成功,不成功关闭文件句柄,抛出异常
CeCloseHandle(remoteFile);
throw new Exception("Could not write to remote file");
}
try
{
// 重新填充本地缓冲区
bytesread = localFile.Read(buffer, 0, buffer.Length);
}
catch(Exception)
{
bytesread = 0;
}
}

// 关闭本地文件
localFile.Close();

// 关闭远程文件
CeCloseHandle(remoteFile);
}
	// 声明要引用的API
[DllImport("rapi.dll", CharSet=CharSet.Unicode)]
internal static extern int CeCloseHandle(IntPtr hObject);

[DllImport("rapi.dll", CharSet=CharSet.Unicode)]
internal static extern int CeWriteFile(IntPtr hFile, byte[] lpBuffer,
int nNumberOfbytesToWrite, ref int lpNumberOfbytesWritten, int lpOverlapped);

[DllImport("rapi.dll", CharSet=CharSet.Unicode, SetLastError=true)]
internal static extern IntPtr CeCreateFile(
string lpFileName,
uint dwDesiredAccess,
int dwShareMode,
int lpSecurityAttributes,
int dwCreationDisposition,
int dwFlagsAndAttributes,
int hTemplateFile);
}
 

    操作完毕后在合适的时候需要断开RAPI连接,使用如下函数(选自SDK文档,本人翻译):









Function Description
CeRapiUninit (RAPI) 销毁Windows CE remote application-programming interface (RAPI).






[C#.NET]
using System;
using System.Runtime.InteropServices;

public class RAPIUninit
{
public RAPIUninit()
{
CeRapiUninit();
}

// 声明要引用的API
[DllImport("rapi.dll", CharSet=CharSet.Unicode)]
internal static extern int CeRapiUninit();
}
 

    文件操作的函数有很多,基本思路都是一样的,在这里就不一一举例了。请注意文件句柄使用以后一定要释放。


    我们再看一个取系统信息的例子,RAPI提供了一些取系统信息的函数(选自SDK文档,本人翻译):
























Function Description
CeGetSystemInfo 返回当前系统信息
CeGetSystemMetrics 获取Windows元素的尺寸和系统设置
CeGetVersionEx 获取当前运行的操作系统版本的扩展信息
CeGetSystemPowerStatusEx 获取电池状态
CeGlobalMemoryStatus 获取系统物理内存和虚拟内存信息
CeGetStoreInformation 获取存储器信息并填入STORE_INFORMATION结构




[C#.net]
public class RAPI
{
SYSTEM_INFO si; // 系统信息
OSVERSIONINFO versionInfo; // 版本信息
SYSTEM_POWER_STATUS_EX PowerStatus; // 电源信息
MEMORYSTATUS ms; // 内存信息
String info;

public void systemInfo()
{
// 检索系统信息
try
{
CeGetSystemInfo(out si);
}
catch(Exception)
{
throw new Exception("Error retrieving system info.");
}

// 检索设备操作系统版本号。
bool b;
versionInfo.dwOSVersionInfoSize = Marshal.SizeOf(typeof(OSVERSIONINFO)); // 设置为结构大小

b = CeGetVersionEx(out versionInfo);
if(!b)
{
throw new Exception("Error retrieving version information.");
}

// 检索设备电源状态
try
{
CeGetSystemPowerStatusEx(out PowerStatus, true); // true 表示读取最新的电源信息,否则将从缓存中获得
}
catch(Exception)
{
throw new Exception("Error retrieving system power status.");
}

// 检索设备内存状态
CeGlobalMemoryStatus( out ms );

// 设置检索信息的格式。
info = "The connected device has an ";
switch (si.wProcessorArchitecture)
{
case ProcessorArchitecture.Intel:
info += "Intel processor.\n";
break;
case ProcessorArchitecture.MIPS:
info += "MIPS processor.\n";
break;
case ProcessorArchitecture.ARM:
info += "ARM processor.\n";
break;
default:
info = "unknown processor type.\n";
break;
}

info += "OS version: " + versionInfo.dwMajorVersion + "." + versionInfo.dwMinorVersion + "." +
versionInfo.dwBuildNumber + "\n";
if (PowerStatus.ACLineStatus == 1)
{
info += "On AC power:YES\n";
}
else
{
info += "On AC power:NO \n";
}
info += "Battery level: " + PowerStatus.BatteryLifePercent + "%\n";
info += "Total memory: " + String.Format("{0:###,###,###}",  ms.dwTotalPhys) +
"\n";

// 显示结果。
Console.WriteLine(info);
}

#region 声明API,详见SDK文档
[DllImport("rapi.dll", CharSet=CharSet.Unicode, SetLastError=true)]
internal static extern int CeGetSystemInfo(out SYSTEM_INFO pSI);

[DllImport("rapi.dll", CharSet=CharSet.Unicode, SetLastError=true)]
internal static extern bool CeGetVersionEx(out OSVERSIONINFO lpVersionInformation);

[DllImport("rapi.dll", CharSet=CharSet.Unicode, SetLastError=true)]
internal static extern bool CeGetSystemPowerStatusEx(out SYSTEM_POWER_STATUS_EX pStatus, bool fUpdate);

[DllImport("rapi.dll", CharSet=CharSet.Unicode, SetLastError=true)]
internal static extern void CeGlobalMemoryStatus(out MEMORYSTATUS msce);
#endregion

#region 声明结构
///
/// 处理器架构 (CeGetSystemInfo)
///
public enum ProcessorArchitecture : short
{
///
/// Intel
///
Intel = 0,

///
/// MIPS
///
MIPS = 1,

///
/// Alpha
///
Alpha = 2,

///
/// PowerPC
///
PPC = 3,

///
/// Hitachi SHx
///
SHX = 4,

///
/// ARM
///
ARM = 5,

///
/// IA64
///
IA64 = 6,

///
/// Alpha 64
///
Alpha64 = 7,

///
/// Unknown
///
Unknown = -1
}

///
/// 移动设备内存信息
///
[StructLayout(LayoutKind.Sequential)]
public struct MEMORYSTATUS
{
internal uint dwLength;
///
/// 当前内存占用 (%)
///
public int dwMemoryLoad;
///
/// 物理内存总量
///
public int dwTotalPhys;
///
/// 可用物理内存
///
public int dwAvailPhys;
///
/// 分页数
///
public int dwTotalPageFile;
///
/// 未分页
///
public int dwAvailPageFile;
///
/// 虚拟内存总量
///
public int dwTotalVirtual;
///
/// 可用虚拟内存
///
public int dwAvailVirtual;
}

///
/// 移动设备电源信息
///
public struct SYSTEM_POWER_STATUS_EX
{
///
/// 交流电状态
///
public byte ACLineStatus;
///
/// 电池充电状态。1 High,2 Low,4 Critical,8 Charging,128 No system battery,255 Unknown status
///
public byte BatteryFlag;
///
/// 电池电量剩余百分比
///
public byte BatteryLifePercent;
///
/// 保留字段,设置为0
///
internal byte Reserved1;
///
/// 电池电量剩余时间(秒)
///
public int BatteryLifeTime;
///
/// 电池充满电的总可用时间(秒)
///
public int BatteryFullLifeTime;
///
/// 保留字段,设置为0
///
internal byte Reserved2;
///
/// 后备电池状态
///
public byte BackupBatteryFlag;
///
/// 后备电池剩余电量百分比
///
public byte BackupBatteryLifePercent;
///
/// 保留字段,设置为0
///
internal byte Reserved3;
///
/// 后备电池电量剩余时间(秒)
///
public int BackupBatteryLifeTime;
///
/// 后备电池充满电的总可用时间(秒)
///
public int BackupBatteryFullLifeTime;
}

///
/// OSVERSIONINFO platform type
///
public enum PlatformType : int
{
///
/// Win32 on Windows CE.
///
VER_PLATFORM_WIN32_CE = 3
}

///
/// 操作系统版本信息
///
public struct OSVERSIONINFO
{
internal int dwOSVersionInfoSize;
///
/// 主版本信息
///
public int dwMajorVersion;
///
/// 副版本信息
///
public int dwMinorVersion;
///
/// 编译信息
///
public int dwBuildNumber;
///
/// 操作系统类型
///
public PlatformType dwPlatformId;
}

///
/// 处理器类型 (CeGetSystemInfo)
///
public enum ProcessorType : int
{
///
/// 386
///
PROCESSOR_INTEL_386 = 386,
///
/// 486
///
PROCESSOR_INTEL_486 = 486,
///
/// Pentium
///
PROCESSOR_INTEL_PENTIUM = 586,
///
/// P2
///
PROCESSOR_INTEL_PENTIUMII = 686,
///
/// IA 64
///
PROCESSOR_INTEL_IA64 = 2200,
///
/// MIPS 4000 series
///
PROCESSOR_MIPS_R4000        = 4000,
///
/// Alpha 21064
///
PROCESSOR_ALPHA_21064       = 21064,
///
/// PowerPC 403
///
PROCESSOR_PPC_403           = 403,
///
/// PowerPC 601
///
PROCESSOR_PPC_601           = 601,
///
/// PowerPC 603
///
PROCESSOR_PPC_603           = 603,
///
/// PowerPC 604
///
PROCESSOR_PPC_604           = 604,
///
/// PowerPC 620
///
PROCESSOR_PPC_620           = 620,
///
/// Hitachi SH3
///
PROCESSOR_HITACHI_SH3       = 10003,
///
/// Hitachi SH3E
///
PROCESSOR_HITACHI_SH3E      = 10004,
///
/// Hitachi SH4
///
PROCESSOR_HITACHI_SH4       = 10005,
///
/// Motorola 821
///
PROCESSOR_MOTOROLA_821      = 821,
///
/// Hitachi SH3
///
PROCESSOR_SHx_SH3           = 103,
///
/// Hitachi SH4
///
PROCESSOR_SHx_SH4           = 104,
///
/// Intel StrongARM
///
PROCESSOR_STRONGARM         = 2577,
///
/// ARM720
///
PROCESSOR_ARM720            = 1824,
///
/// ARM820
///
PROCESSOR_ARM820            = 2080,
///
/// ARM920
///
PROCESSOR_ARM920            = 2336,
///
/// ARM 7
///
PROCESSOR_ARM_7TDMI         = 70001
}

///
/// CeGetSystemInfo的数据结构
///
public struct SYSTEM_INFO
{
///
/// 处理器架构
///
public ProcessorArchitecture wProcessorArchitecture;
///
/// 保留
///
internal ushort wReserved;
///
/// Specifies the page size and the granularity of page protection and commitment.
///
public int dwPageSize;
///
/// 应用程序可访问内存地址的最小值
///(Pointer to the lowest memory address accessible to applications
/// and dynamic-link libraries (DLLs). )
///
public int lpMinimumApplicationAddress;
///
/// 应用程序可访问内存地址的最大值(Pointer to the highest memory address
/// accessible to applications and DLLs.)
///
public int lpMaximumApplicationAddress;
///
/// Specifies a mask representing the set of processors configured into
/// the system. Bit 0 is processor 0; bit 31 is processor 31.
///
public int dwActiveProcessorMask;
///
/// 处理器数量(Specifies the number of processors in the system.)
///
public int dwNumberOfProcessors;
///
/// 处理器类型(Specifies the type of processor in the system.)
///
public ProcessorType dwProcessorType;
///
/// Specifies the granularity with which virtual memory is allocated.
///
public int dwAllocationGranularity;
///
/// Specifies the system architecture-dependent processor level.
///
public short wProcessorLevel;
///
/// Specifies an architecture-dependent processor revision.
///
public short wProcessorRevision;
}
#endregion
}
 

    RAPI可以做的事情还有很多,比如取注册表信息,提供对 Microsoft ActiveSync 底层功能的访问,运行远程应用程序,文件列表等等。只要仔细阅读SDK文档,相信都不是难事。


    作为Mobile设备的桌面管理程序,备份通话记录,联机发送短信等功能是必不可少的。在我刚发现RAPI的时候,以为和前面的例子一样,有现成的函数可以使用。仔细研究以后才发现要复杂的多。相信这是很多朋友的希望实现的功能,所以班门弄斧,简述如下。


    RAPI并没有提供通话,SIM卡和短信方面的函数,它们分别包含在SmartPhone SDK的Phone API,SIM Manager和Short Message Service中。然而包含这些API的phone.dll,cellcore.dll和sms.dll都是储存在设备上的,在Windows上运行的程序是无法调用存储在远程设备上的动态连接库的。


    我们仍然需要RAPI。虽然它没有提供直接访问通话记录和短信方面的操作,但是它提供了一个特殊的函数:









Function Description
CeRapiInvoke 使用一种通用的机制执行远程程序

    CeRapiInvoke的原型如下:





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

    CeRapiInvoke将允许我们调用远程设备中的任何API函数!不过不是直接调用,仍然需要对远程API进行一些“包装”。由于时间关系,我将在不久的将来为大家献上关于CeRapiInvoke的详细说明。

posted on 2006-02-03 16:31  Ооo酷鱼  阅读(7707)  评论(1编辑  收藏  举报

导航