Windows CE是微軟為嵌入式設備打造的操作系統,CE操作系統必須是可定制.
Windows CE搭建出來的物體就是平台,是適應某種有固定標准的嵌入式設備的操作系統子集,最著名的平台是Pocket PC。
可以自己開發平台,開發工具是微軟提供的Platform Builder,Platform Builder的版本號是和Windows CE的版本號一致的。
應用程序開發是針對特定平台的,我們在開發之前必須安裝目標平台的SDK,才能夠開發出適應目標平台的開發工具。
微軟提供給應用程序開發者的工具包括:Embedded Visual Tools 3.0,其中包括Embedded Visual C++ 3.0和Embedded Visual Basic 3.0;Embedded Visual C++ 4.0和Visual Studio.Net。
開發工具的版本號是與Windows CE的版本號對應的。
開發環境和模擬器之間是通過網絡連接協議進行通訊的,所以開發所用的計算機上必須有一個活動的網絡連接。如果沒有,可以安裝微軟的虛擬網卡。
EVC也是WinCE上的主流開發工具。EVC支持MFC類庫的子集,可以給開發者提供最強大的支持,也使Win32平台上的VC程序員可以很容易地遷移到WinCE平台上。但由於MFC類庫需要一個DLL,所以對某些存儲空間有限的嵌入式設備來說,這是個很大的負擔,所以SmartPhone就不支持MFC。
由於嵌入式設備支持的CPU種類很多,我們在選擇創建工程類型的同時,也要把該工程所支持的CPU類型選擇好。創建工程的過程和VC是一樣的。當然不同的平台支持的工程類型是不同的,比如Pocket PC 2003有支持MFC和API的兩種工程,而SmartPhone 2003則只有支持API的一種工程。
EVC中比VC環境中多了一行下拉菜單的選項,分別用來選擇:工程、SDK、CPU類型和輸出設備。以Pocket PC為例,在實際設備上調試應該選擇Win32(WCE ARMV4)Debug ,而在模擬器上則需要選擇Win32(WCE emulator)Debug。
Windows CE是基於Win32應用程序接口(API)的。
Windows CE的編程戒律,如"千萬不要給Unicode(國際標准組織10646標准)字符分配奇數內存地址"。
大約有百分之九十的問題或多或少地與Unicode有關。盡管Unicode編程不難,但是,當給單字節字符編寫代碼時,很容易出錯(我有過許多次錯誤)。
當用Microsoft VC++(5.0版)創建一個Windows CE程序時,你會發現,包含路徑(include)、庫路徑(library)、及可執行程序路徑被自動調整以匹配反應目標環境的選擇。因此,比如說為Windows CE模擬器建立應用程序時,你會發現,include路徑沒有指向Win32的包含文件(在VC目錄下),而是指向Windows CE包含文件(在WCE目錄下)。千萬別去修改。
由於Windows CE在Windows NT下運行,所以仿真器上運行的程序能夠調用任一Windows NT動態鏈接庫(DLL)中的函數,即使這個DLL不是模擬器的成員也一樣。顯然,這不是很好的事,因為相同的函數也許在手持PC(H/PC)或Windows CE設備上不可用,而你的軟件最終要能在這些設備上運行。
你不要采用那些在寫普通Win32或非Windows CE程序時使用的包含文件和庫文件。
幾乎所有Windows CE支持的Win32和運行時間庫函數都要求寬字符變量。Windows 95不支持Unicode,然而,為了使程序代碼具有可移植性,你要盡可能采用tchar.h中定義的TCHAR類型,不要直接使用wchar_t。
TCHAR是定義為wchar_t還是char,取決於預處理器的符號UNICODE是否定義。同樣,所有有關字符串處理函數的宏,如_tcsncpy宏,它是定義為Unicode函數wcsncpy還是定義為ANSI函數strncpy,取決於UNICODE是否定義。
在現存的Windows應用程序中,有些代碼也許暗示字符長為單字節。這在給字符串分配內存時經常用到,例如:
int myfunc(char *p)
{
char *pszFileName;
pszFileName = malloc(MAXFILELEN);
if(pszFileName)
strncpy(pszFileName, p, MAXFILELEN);
/*etc*/
在這段代碼中,分配的內存塊應該寫作(MAXFILELEN * sizeof(char)),但是大多數程序員喜歡將它簡化為MAXFILELEN,因為對於所有的平台來說sizeof(char)的值等於1。然而,當你用TCHARS代替多個字符時,很容易忘記這種固有的概念,於是將代碼編寫成下面的形式:
int myfunc(TCHAR *p)
{
TCHAR *pszFileName;
PszFileName = (TCHAR*)malloc(MAXFILELEN);
If (pszFileName)
tcsncpy(pszFileName, p, MAXFILELEN);
/*etc*/
這是不行的。它馬上會導致出錯。這裡的錯誤在於malloc函數中指定變量大小為bytes,然而_tcsncpy函數中使用的第三個變量卻指定為TCHARs而不是bytes。當UNICODE被定義時,一個TCHAR等於兩個字節數(bytes)。
上述代碼段應該改寫為:
int myfunc(TCHAR *p)
{
TCHAR *pszFileName;
PszFileName = (TCHAR*)malloc(MAXFILELEN * sizeof(TCHAR));
if(pszFileName)
tcsncpy(pszFileName, p, MAXFILELEN);
/*etc*/
不要將Unicode 字符串放入奇數內存地址
編輯器經常在這些問題上提醒你。你無法管理堆棧變量地址,並且編輯器會檢查確定這些地址與變量類型是否相匹配。同樣,運行時間庫必須保證從堆中分配的內存總是滿足一個Word邊界,所以你一般不必擔心那兩點。
在ANSI和Unicode字符串之間進行翻譯,可采用MultiByteToWideChar()和WideCharToMultifor(pA=strA, pW=strW, len=1; lenW; pA++, pW++, lenW--, len++)
{
*pW = (lenW = =1) ? 0 : (wchar_t)( *pA);
if( ! (*pW))
break;
}
return len;
}
int wtoa(wxhar_t *strW, char *strA, int lenA)
{
int len;
char *pA;
wchar_t *pW;
/*
Start with len=1,not len=0, as string length returned
Must include null terminator, as in WideCharToMultiByte()
*/
for(pA=strA, pW=strW, len=1; lenA; pa++, pW++, lenA--, len++)
{
pA = (len==1)? 0 : (char)(pW);
if(!(*pA))
break;
}
return len;
}
#endif /*_WIN32_WCE<101*/
這種適合於Windows CE 1.0的實現辦法比使用wsprintf()函數要容易,因為使用wsprintf()函數更難以限制目標指針所指向的字符串的長度。
選擇正確的字符串比較函數
如果你要分類Unicode標准字符串,你會有以下幾個函數可供選擇:
wcscmp(), wcsncmp(), wcsicmp(), 和wcsnicmp()
wcscoll(), wcsncoll(), wcsicoll(),和wcsnicoll()
CompareString() 第一類函數可用來對字符串進行比較,不參考當地(Locale)或外文字符。如果你永遠不想支持外文,或者你僅僅想測試一下兩個字符串的內容是否相同,這類函數非常好用。
第二類函數使用現有的當地設置(current locale settings)(系統設置,除非你在字符串比較函數之前調用了wsetlocale()函數)來比較兩個字符串。這些函數也能正確分類外文字符。如果當地的字符"C"("C" locale)被選定,這些函數與第一類函數就具有了相同的功能。
第三類函數是Win32函數CompareString()。這個函數類似於第二類函數,但是它允許你指定當地設置(the locale)作為一個參數,而不是使用現有的當地設置(current locale settings)。CompareString()函數允許你選擇性地指定兩個字符串的長度。你可以將第二個參數設置為NORM_IGNORECASE,從而使函數比較字符串時不比較大小寫。
通常,即使不將第二個參數設置為NORM_IGNORECASE,CompareString()函數也不用來區分大小寫。我們經常用wcsncoll()函數來區分大小寫,除非使用當地的字符"C"("C" locale)。所以,在我們的代碼中,不使用CompareString()函數來區分大小寫,而用wcsncoll()函數來區分大小寫
不要使用相對路徑
與Windows NT不一樣,Windows CE沒有當前目錄這個概念,因此,任何路徑只是相對於根目錄而言的。如果你的軟件給文件或目錄使用相對路徑,那麼你很可能把它們移到別的地方了。例如,路徑".\abc"在Windows CE中被當作"\abc"看待。
移走了對calloc()和 time()函數的調用
C運行庫中的calloc()函數不能使用,但是malloc()函數可以代替calloc()函數。並且不要忘記,calloc()函數初始化時分配的內存為零,而malloc()函數不一樣。同樣,time()函數也不能使用,但你可以使用Win32函數GetSystemTime()函數代替time()函數。
經過以上的警告後,你會高興地學習最後令你驚訝的兩點忠告。
不需要改變Win32 輸入/輸出(I/O)文件的調用
Win32的輸入輸出函數,Windows CE也支持。允許你象訪問Win32文件系統那樣訪問對象。CreateFile()函數在Windows CE中不能辯認標志FILE_FLAG_RANDOM_Access,但是這個標志僅用作可選的磁盤訪問,並且不影響函數調用的功能。
不要擔心字節的狀態
當我們把應用程序寫入Windows CE時,有了一個美好的發現,那就是Windows CE的數字數據類型的字節狀態與Intel結構的字節狀態一樣,在所有的處理器上,Windows CE均支持。
幾乎象所有的數據庫引擎一樣,Raima數據庫管理器在數據庫文件中以二進制形式保存數字數據。這就意味一個記錄無論何時寫入數據庫或從數據庫讀出,均被當作一系列的字節來處理,不管它域的內容。只要數據庫文件不要傳給別的任何系統,數字數據的字節狀態問題就解決了。如果數據庫文件被一個來自原始系統且帶有不同字節狀態的處理器訪問,數字數據將被誤解。
無論何時,當你在擁有不同處理器的機器上傳輸文件時,就會出現這個問題。在這個問題上,值得高興的是所有類型的處理器都使用相同的字節狀態。
在使用Windows CE時,這些忠告應該引起你足夠的重視,避免學習時走彎路。