本頁內容
● | 引言 |
● | 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 | 關閉指定的查找句柄,CeFindFirstFile和CeFindNextFile 函數用這個句柄查找文件 |
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 |
??? 文件操作的函數有很多,基本思路都是一樣的,在這里就不一一舉例了。請注意文件句柄使用以后一定要釋放。
??? 我們再看一個取系統信息的例子,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的詳細說明。
?