日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

Windows Mobile和Wince(Windows Embedded CE)的字符集问题

發布時間:2025/4/16 windows 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Windows Mobile和Wince(Windows Embedded CE)的字符集问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

背景

開發過Windows Mobile和Wince(Windows Embedded CE)的開發者,特別是Native C++開發者,或多或少都遇到過ANSI字符集和Unicode字符集的轉換問題。本文試圖把Windows Mobile和Wince(Windows Embedded CE)開發的字符集問題講明白,其實這個題目有點ambitious和aggressive,就當成標題黨吧。

?

簡介

本文試圖通過一篇文章講清楚Windows Mobile和Wince(Windows Embedded CE) Native C++開發中字符集的轉換問題。從字符集的概念入手,講述Wince支持的所有字符串類型,以及各種類型的轉換方法,最后給出使用建議。

?

什么是字符集

字符集(Character Set)是映射關系,其定義了字符和編碼的關系。這里編碼通常來說是1和0的bit。當前流行的計算機系統任何數據存儲最終都表達為1和0。而這些1和0在不同字符集下映射成不同含義的字符。

計算機發明和使用初期,存儲設備都十分的昂貴,科學家們想盡辦法來節省成本,因此開始的是,最常見的字符集是單字節字符集(Signle-byte),所謂單字節字符集就是使用一個byte來代表一個字符,單字符集的典型是ASCII (American Standard Code for Information Interchange),你看這不是國籍標準,僅僅是美國標準,壓根就沒有考慮咱們感受,咱們從甲骨文開始發展漢字,美國人看到就A~Z幾個字母。

這個ASCII 表,學過C語言的人都學過,以前考試也用到,需要背下來的。

ANSI(American National Standards Institute) 是在ASCII 7bit 編碼標準 (ASA X3.4-1963)的基礎上,加入了歐洲字母發展出來的一個標準。

但是單字節字符集有個最要命的缺點是一個byte只要8個bit,也就是最多表示256 (28)個可見和不可見的字符。 對于英語國家可能是夠用的,但是對于說中文的國家,漢字是沒辦法通過256個字符表達的。因此慢慢出來國際標準的字符集Unicode。

?

Wince與Unicode

對于剛剛接觸Windows Mobile和Wince(Windows Embedded CE) Native C++開發的人來說,會有這樣的想法:Windows Mobile和Wince僅僅支持Unicode,不支持ANSI的。TinyXML是使用ANSI string的,但是Wince使用Unicode,那么TinyXML不能使用在Wince和Windows Mobile中。等等…… 其實這些想法有些錯誤,Wince是一個Unicode系統,沒錯,這表示Wince里面所有字符串處理代碼都是基于Unicode編碼,但是不表示Wince不支持ANSI。我們同樣可以繼續在Wince中使用ANSI,例如使用std::string, char[]等。

但是為什么會有這些誤區呢,先看一下下面的編譯錯誤。

error C2664:?'wprintf'?: cannot convert parameter 1 from?'const char [21]'?to?'const wchar_t *'

?

error C2664:?'DeleteFileW'?: cannot convert parameter 1 from?'const char [21]'?to?'LPCWSTR'

我敢保證剛剛接觸Windows Mobile和Wince(Windows Embedded CE) Native C++開發的人10個有9個甚至10個都碰到過上述問題。在調用Win32 API的時候,使用MFC,WTL的接口的時候都會碰到這樣的問題,因為我們習慣使用char*,std::string,但是恰恰Win32 API,MFC和WTL的函數入口中的字符串為Unicode,因此發生上述的編譯錯誤。不知道為什么大家碰到這個錯誤后會形成一個錯誤的想法:Wince只是支持Unicode,不支持ANSI了。其實Wince還是支持ANSI的,我們定義單字符的char數組,甚至可以通過C Runtime在Console中打印出ANSI string。

char?ansiStr[] =?"I am ANSI string";
printf(ansiStr);

?

Wince支持的字符串

既然Wince支持ANSI和Unicode,那什么時候用ANSI,什么時候用Unicode,下面我從在Wince開發中常常用到字符串講起,然后講述字符串的轉換以及使用建議。

char*

char*和char[]沒有本質的區別,都是指向內存的指針。ANSI版本的Win32的API中的字符串都是使用char*。 由于Win32的API是語言無關的,因此這些參數其實傳遞的是一段應該存放字符串的內存的指針。(很拗口,但是確實這樣,呵呵)。在ANSI環境下使用純粹C開發,程序是離不開char*的。

?

wchar_t *

LPWSTR, PWSTR等宏定義其實都是wchar_t*的定義, 最常見的LPCWSTR是const wchar_t*的宏定義。wchar_t表示16位Unicode字符。wchar_t*和wchar_t[]用來定義Unicode字符串。在Unicode版本下,所有Win32的API的字符串都由char*變成了wchar_t*了。

這個可以看一下頭文件的預編譯。例如以winbase.h的DeleteFile API為例。

WINBASEAPI
BOOL
WINAPI
DeleteFileA(
LPCSTR lpFileName
);
WINBASEAPI
BOOL
WINAPI
DeleteFileW(
LPCWSTR lpFileName
);
#ifdef?UNICODE
#define?DeleteFile DeleteFileW
#else
#define DeleteFile DeleteFileA
#endif?// !UNICODE

在ANSI版本DeleteFile為DeleteFileA,參數的字符串定義為LPCSTR,也就是const char*,而Unicode版本的DeleteFile為DeleteFileW,參數字符串定義變成了LPCWSTR,也就是const wchar_t*。

?

決定DeleteFile到底是DeleteFileA或者DeleteFileW是由預編譯宏 UNICODE 來決定的。

這個宏可以在項目屬性里面配置,如下圖:

?

當選擇Use Unicode Character Set時候,預編譯會增加宏UNICODE和_UNICODE。

但是需要注意的是,如果目標平臺為Windows Mobile或者Wince,不管是否選擇Use Unicode Character Set,UNICODE和_UNICODE的預編譯都會加上,也就是說Wince下所有Win32 API都是Unicode版本的。

?

CString

CString最初在MFC里面封裝,ATL和WTL分別封裝了CString,這三個不同封裝的CString具有語義兼容性,也就是他們提供的接口是相同的。使用CString的好處是可以同時兼容ANSI和Unicode,如下例子:

CString str =?"Independent String";
m_wndPic.SetWindowText(str);

m_wndPic是一個CStatic控件,上面的代碼不管在ANSI或者在Unicode都能使用,無需更改。

?

下面以ATL CString為例子講述CString是如何同時支持支持ANSI或者Unicode的。

typedef?CAtlString CString;typedef?CStringT< TCHAR, StrTraitATL< TCHAR > > CAtlString;

CString存儲字符串的類型由TCHAR來決定的,而TCHAR又是由UNICODE預編譯來決定,見下面的宏定義。

#ifdef?UNICODE?// r_winnt
typedef?WCHAR TCHAR, *PTCHAR;
#else?/* UNICODE */ // r_winnt
typedef char TCHAR, *PTCHAR;
#endif /* UNICODE */?

以此CString使用字符串類型根據預編譯選項來自動決定。

?

std::string

STL里面的string,封裝的是單字節字符,由于其跨平臺的特性,我編寫的代碼中大量使用std::string,其實準確來說我大量使用STL。例如我一般使用std::string來操作TinyXML。拋開Wince平臺不說,使用std::string基本上沒有缺點,可以跨任何支持標準C++的平臺。可是在Wince和Windows Mobile下做開發,情況有點不一樣,因為std::string封裝的是單字節字符,所以如果需要調用Win32的API,使用MFC,ATL和WTL的功能時都需要轉型,這姑且算是一個缺點吧,但是熟悉了轉換以后,使用std::string一點問題都沒有。

?

std::wstring

STL里面的string的Unicode版本,和std::string一樣,使用了unicode字符進行封裝。其實std::wstring我用的不多,用std::string已經夠了。

?

如何轉換Wince支持的字符串

既然Windows Mobile和Wince(Windows Embedded CE)支持上述的字符串,那么我們開發的時候會碰到這些字符串直接相互轉換的問題,下面通過例子演示如何轉換。

?

轉換過程我推薦使用ATL的宏,關于ATL的宏可以參考??ATL and MFC String Conversion Macros

這些宏的命名規范為

CSourceType2[C]DestinationType[EX]

SourceType/DestinationType

Description

A

ANSI character string.

W

Unicode character string.

T

Generic character string (equivalent to W when _UNICODE is defined, equivalent to A otherwise).

OLE

OLE character string (equivalent to W).

?

A表示ANSI string,W表示Unicode string,T表示通用string,根據預編譯來決定類型。OLE和W一樣,我從來不用OLE。

例如CT2CA就是通用string轉成ANSI string。

?

轉換到char*

void?ConvertToCharArray()
{
char?ansiStr[255] =?"ANSI string";
wchar_t?unicodeStr[255] = _T("Unicode string");?//use _T() convert const string to wchar_t string

CString cstr("ATL CString");

std::string stlStr("STL string");
std::wstring stlWStr(_T("STL wstring"));?//use _T() convert const string to wchar_t string

printf("All string convert to char*\n");
strcpy(ansiStr, CT2CA(unicodeStr));
printf("Convert from wchar_t*, %s\n", ansiStr);

strcpy(ansiStr, CT2CA(cstr));
printf("Convert from CString, %s\n", ansiStr);

strcpy(ansiStr, stlStr.c_str());
printf("Convert from std::string, %s\n", ansiStr);

strcpy(ansiStr, CT2CA(stlWStr.c_str()));
printf("Convert from std::wstring, %s\n", ansiStr);
}

例子中用到了ATL CString,如果新建的是Win32項目需要加入ATL支持,方法可以參考:?在Windows Mobile和Wince(Windows Embedded CE)下Win32項目加入ATL支持

上面講過ATL CString和WTL以及MFC CString語義相同,因此本文所有CString的代碼在MFC下同樣有效。

?

轉換到wchar_t*

void?ConvertToWCharArray()
{
char?ansiStr[255] =?"ANSI string";
wchar_t?unicodeStr[255] = _T("Unicode string");?//use _T() convert const string to wchar_t string

CString cstr("ATL CString");

std::string stlStr("STL string");
std::wstring stlWStr(_T("STL wstring"));?//use _T() convert const string to wchar_t string

printf("All string convert to wchar_t*\n");
wcscpy(unicodeStr, CComBSTR(ansiStr));
wprintf(_T("Convert from char*, %s\n"), unicodeStr);

wcscpy(unicodeStr, cstr);
wprintf(_T("Convert from CString, %s\n"), unicodeStr);

wcscpy(unicodeStr, CComBSTR(stlStr.c_str()));
wprintf(_T("Convert from std::string, %s\n"), unicodeStr);

wcscpy(unicodeStr, stlWStr.c_str());
wprintf(_T("Convert from std::wstring, %s\n"), unicodeStr);
}

這里使用了微軟推薦的CComBSTR(),而不是CA2W()。

轉換到CString

void?ConvertToCString()
{
char?ansiStr[255] =?"ANSI string";
wchar_t?unicodeStr[255] = _T("Unicode string");?//use _T() convert const string to wchar_t string

CString cstr("ATL CString");

std::string stlStr("STL string");
std::wstring stlWStr(_T("STL wstring"));?//use _T() convert const string to wchar_t string

printf("All string convert to CString\n");
cstr = ansiStr;
wprintf(_T("Convert from char*, %s\n"), cstr);

cstr = unicodeStr;
wprintf(_T("Convert from wchar_t*, %s\n"), cstr);

cstr = stlStr.c_str();
wprintf(_T("Convert from std::string, %s\n"), cstr);

cstr = stlWStr.c_str();
wprintf(_T("Convert from std::wstring, %s\n"), cstr);
}

?

轉換到std::string

void?ConvertToStlString()
{
char?ansiStr[255] =?"ANSI string";
wchar_t?unicodeStr[255] = _T("Unicode string");?//use _T() convert const string to wchar_t string

CString cstr("ATL CString");

std::string stlStr("STL string");
std::wstring stlWStr(_T("STL wstring"));?//use _T() convert const string to wchar_t string

printf("All string convert to STL string\n");
stlStr = ansiStr;
printf("Convert from char*, %s\n", stlStr.c_str());

stlStr = CT2CA(unicodeStr);
printf("Convert from wchar_t*, %s\n", stlStr.c_str());

stlStr = CT2CA(cstr);
printf("Convert from CString, %s\n", stlStr.c_str());

stlStr = CT2CA(stlWStr.c_str());
printf("Convert from std::wstring, %s\n", stlStr.c_str());
}

?

轉換到std::wstring

void?ConvertToStlWstring()
{
char?ansiStr[255] =?"ANSI string";
wchar_t?unicodeStr[255] = _T("Unicode string");?//use _T() convert const string to wchar_t string

CString cstr("ATL CString");

std::string stlStr("STL string");
std::wstring stlWStr(_T("STL wstring"));?//use _T() convert const string to wchar_t string

printf("All string convert to STL wstring\n");
stlWStr = CComBSTR(ansiStr);
wprintf(_T("Convert from char*, %s\n"), stlWStr.c_str());

stlWStr = unicodeStr;
wprintf(_T("Convert from wchar_t*, %s\n"), stlWStr.c_str());

stlWStr = cstr;
wprintf(_T("Convert from CString, %s\n"), stlWStr.c_str());

stlWStr = CComBSTR(stlStr.c_str());
wprintf(_T("Convert from std::string, %s\n"), stlWStr.c_str());
}

?

?

純C Runtime庫轉換

有時候使用Win32進行純C的開發,例如進行今日插件的開發,不使用ATL,WTL,MFC以及STL的情況下,也會有轉換char*和wchar_t*的需求,但是不能使用ATL的宏,下面演示如何使用C Runtime庫來轉換。

void?ConvertToWCharArrayUsingCRuntime()
{
char?ansiStr[255] =?"ANSI string";
wchar_t?unicodeStr[255] = _T("Unicode string");?//use _T() convert const string to wchar_t string

printf("Convert to char* from wchar_t* using C Runtime library.\n");
sprintf(ansiStr,?"%S", unicodeStr);
printf("Convert from wchar_t*, %s\n", ansiStr);
}

void?ConvertToCharArrayUsingCRuntime()
{
char?ansiStr[255] =?"ANSI string";
wchar_t?unicodeStr[255] = _T("Unicode string");?//use _T() convert const string to wchar_t string

printf("Convert to wchar_t* from char* using C Runtime library.\n");
swprintf(unicodeStr, _T("%S"), ansiStr);
wprintf(_T("Convert from char*, %s\n"), unicodeStr);
}

?


使用建議

上面講述了Windows Mobile和Wince(Windows Embedded CE)支持那么多字符串,那么我們到底如何選擇使用的字符串呢?其實這個沒有準則,我下面談一下我的經驗。這不是準則,所以只做參考之用。

一.盡量避免使用char*和wchar_t*

除了以下情況,不得不使用char*和wchar_t*時,大部分時候盡量避免使用char*和wchar_t*。

情況1

做今日組件開發,只是使用Win32,如果不依賴于ATL,WTL,MFC和STL,那么沒得選擇只能使用char*和wchar_t*。

關于今日組件的開發,可以參考:

關于在Windows Mobile下今日插件使用WTL的問題

?

情況2

封裝DLL或者通用靜態庫提供給第三方使用,例如TinyXML, CppUnitLite這樣的類庫,他們內部都在char*基礎上實現字符串處理類,這樣庫就不依賴于ATL,WTL,MFC和STL了。

關于TinyXML, CppUnitLite可以參考:

Windows Mobile和Wince下使用TinyXML進行Native C++的開發

Wince和Windows Mobile下native C++的單元測試

Windows Mobile下使用CppUnitLite輸出測試結果

?

情況3

封裝DLL給.NET Compact Framework使用,接口函數只能使用char*和wchar_t*,不能使用CString和std::string。

關于DLL的封裝,可以參考:

Windows Mobile和Wince(Windows Embedded CE)下如何封裝Native DLL提供給.NET Compact Framework進行調用

Windows Mobile和Wince(Windows Embedded CE)下封裝Native DLL進一步探討

?

情況4

可以使用char*和wchar_t*包括一些字符串常量,用于替換宏定義。

?

除了上述情況以外,應當盡量避免使用char*和wchar_t*,而是用CString,std::string等封裝好的字符串類。

?

二.程序需要同時支持PC和Window Mobile版本時使用CString

如果使用C++加上ATL,WTL或者MFC開發,程序需要同時支持Windows桌面版和Windows Mobile以及Wince,可以考慮使用CString。CString可以很好的兼容ANSI和Unicode版本。

例如我封裝的一個SQL Server Compact的數據庫訪問類,使用到CString,這個類可以支持PC和Windows Mobile。可以參考:

Windows Mobile下Native C++訪問SqlCe的封裝

?

三.程序需要跨平臺時使用std::string

程序不僅僅用于windows平臺,而且用于Linux,Unix,BSD等平臺,可以考慮使用std::string,我一般不使用std::wstring,覺得沒有這個必要,使用std::string在需要的時候轉換就可以了。但是如果追求更高的跨平臺性,那只能使用char*和wchar_t*了,連STL都不依賴。

?

我個人喜歡使用std::string,因為我大量使用STL。在設計的時候把界面和處理邏輯分開,處理邏輯內部統一使用std::string以及STL的容器。需要界面交互出來,或者調用Win32的時候進行字符串的轉換。

?

可以進一步參考的文章

http://www.tenouk.com/ModuleG.html

http://www.codeproject.com/KB/string/cppstringguide1.aspx


總結

以上是生活随笔為你收集整理的Windows Mobile和Wince(Windows Embedded CE)的字符集问题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。