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, 但是为什么会有这些误区呢,先看一下下面的编译错误。 error C2664: 'wprintf' : cannot convert parameter 1 from 'const char [21]' to 'const 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 char ansiStr[] = "I am ANSI string"; 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 在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版本的。 CStringCString最初在MFC里面封装,ATL和WTL分别封装了CString,这三个不同封装的CString具有语义兼容性,也就是他们提供的接口是相同的。使用CString的好处是可以同时兼容ANSI和Unicode,如下例子: CString str = "Independent String"; 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 以此CString使用字符串类型根据预编译选项来自动决定。 std::stringSTL里面的string,封装的是单字节字符,由于其跨平台的特性,我编写的代码中大量使用std::string,其实准确来说我大量使用STL。例如我一般使用std::string来操作TinyXML。抛开Wince平台不说,使用std::string基本上没有缺点,可以跨任何支持标准C++的平台。可是在Wince和Windows Mobile下做开发,情况有点不一样,因为std::string封装的是单字节字符,所以如果需要调用Win32的API,使用MFC,ATL和WTL的功能时都需要转型,这姑且算是一个缺点吧,但是熟悉了转换以后,使用std::string一点问题都没有。 std::wstringSTL里面的string的Unicode版本,和std::string一样,使用了unicode字符进行封装。其实std::wstring我用的不多,用std::string已经够了。 如何转换Wince支持的字符串既然Windows Mobile和Wince(Windows Embedded CE)支持上述的字符串,那么我们开发的时候会碰到这些字符串直接相互转换的问题,下面通过例子演示如何转换。 转换过程我推荐使用ATL的宏,关于ATL的宏可以参考 ATL 这些宏的命名规范为 CSourceType2[C]DestinationType[EX]
A表示ANSI string,W表示Unicode string,T表示通用string,根据预编译来决定类型。OLE和W一样,我从来不用OLE。 例如CT2CA就是通用string转成ANSI string。 转换到char*void ConvertToCharArray() 例子中用到了ATL CString,如果新建的是Win32项目需要加入ATL支持,方法可以参考: 在Windows 上面讲过ATL CString和WTL以及MFC CString语义相同,因此本文所有CString的代码在MFC下同样有效。 转换到wchar_t*void ConvertToWCharArray() 这里使用了微软推荐的CComBSTR(),而不是CA2W()。 转换到CStringvoid ConvertToCString() 转换到std::stringvoid ConvertToStlString() 转换到std::wstringvoid ConvertToStlWstring() 纯C Runtime库转换有时候使用Win32进行纯C的开发,例如进行今日插件的开发,不使用ATL,WTL,MFC以及STL的情况下,也会有转换char*和wchar_t*的需求,但是不能使用ATL的宏,下面演示如何使用C Runtime库来转换。 void ConvertToWCharArrayUsingCRuntime() 使用建议上面讲述了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 情况2封装DLL或者通用静态库提供给第三方使用,例如TinyXML, CppUnitLite这样的类库,他们内部都在char*基础上实现字符串处理类,这样库就不依赖于ATL,WTL,MFC和STL了。 关于TinyXML, CppUnitLite可以参考: Windows Wince和Windows Windows 情况3封装DLL给.NET Compact Framework使用,接口函数只能使用char*和wchar_t*,不能使用CString和std::string。 关于DLL的封装,可以参考: Windows Windows 情况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 三.程序需要跨平台时使用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)的字符集问题的更多相关文章
- (转) 关于Windows CE和Windows Mobile
转发自http://www.cnblogs.com/chump/articles/1281955.aspx 一.Windows CE Windows CE是微软的嵌入式操作系统主要的一种,面世于199 ...
- Windows Mobile 6开发环境搭建
Windows Mobile 6开发环境搭建 本文主要介绍在已有的Visual Studio 2005和Microsoft SQL Server2008环境基础上,如何搭建Windows Mobile ...
- 使用Visual Studio 2008创建你的第一个Windows Mobile程序介绍
使用Visual Studio 2008创建你的第一个Windows Mobile程序介绍 Windows MobileMobileWindowsMicrosoftWinForm 介绍 Microso ...
- Windows Embedded CE 6.0开发环境的搭建
最近开始在学习嵌入式,在这里首先得安装Windows Embedded CE 6.0,其中遇到了很多问题,电脑的系统以及相关配置都会在安装过程中受到影响,因此笔者就安装中的问题以及环境搭建来介绍一下. ...
- (转) Windows Mobile和Windows CE的区别
转发自 http://blog.sina.com.cn/s/blog_6250bbe60100tsf3.html WinCE Windows CE 是一个可定制的操作系统: Windows Mobil ...
- Windows Embedded CE 6.0开发环境的搭建(2)
最近开始在学习嵌入式,在这里首先得安装Windows Embedded CE 6.0,其中遇到了很多问题,电脑的系统以及相关配置都会在安装过程中受到影响,因此笔者就安装中的问题以及环境搭建来介绍一下. ...
- Windows Embedded CE 6.0 下载地址和序列号
Windows Embedded CE 6.0 下载地址和序列号 安装起来特麻烦 程序下载地址 http://download.microsoft.com/download/a/0/9/a09e587 ...
- Win10系统windows mobile设备中心无法连接WinCE采集器
1.开始-->运行,输入services.msc回车 2.在打开的服务界面中,找到“基于Windows Mobile 2003的连接设备” 3.右击属性,修改成自动 4.点击登陆选项卡,选择本地 ...
- [WinCE] [Win10] Win10 Creator 升级后 Windows Mobile Device Center 不能打开
运行 services.msc 找到 Windows Mobile 2003-based device connectivity服务,右键属性,Log On选项卡选择 Local System acc ...
随机推荐
- C实战:强大的程序调试工具GDB
C实战:强大的程序调试工具GDB 1.基本调试 这里只列举最最常用的GDB命令. 1.1 启动GDB gdb program:准备调试程序.也可以直接进入gdb,再通过file命令加载. 1.2 添加 ...
- 【SSH系列】Hibernate映射 -- 一对多关联映射
映射原理 一对多关联映射和多对一关联映射的映射原理是一样一样的,所以说嘛,知识都是相通的,一通百通,为什么说一对多关联映射和多对一关联映射是一样的呢?因为她们都是在多的一端加入一个 ...
- Unable to ignore resources
摘要:分享牛,分享牛系列, Unable to ignore resources Attempted to beginRule: 异常信息处理. 出现Unable to ignore resource ...
- springMVC源码分析--AbstractUrlHandlerMapping(三)
上一篇博客springMVC源码分析--AbstractHandlerMapping(二)中我们介绍了AbstractHandlerMapping了,接下来我们介绍其子类AbstractUrlHand ...
- ROS(indigo) 安装和使用更新版本的Gazebo----3,4,5,6,7 附:中国机器人大赛中型组仿真比赛说明
ROS(indigo) 安装和使用更新版本的Gazebo,本文以7为例. Gazebo7支持更多新的功能,如果使用下面命令安装ROS(indigo): ~$ sudo apt-get install ...
- JVM概述
JVM是什么 JVM全称是Java Virtual Machine(java虚拟机).它之所以被称之为是"虚拟"的,就是因为它仅仅是由一个规范来定义的抽象计算机.我们平时经常使用的 ...
- Spark技术内幕:Sort Based Shuffle实现解析
在Spark 1.2.0中,Spark Core的一个重要的升级就是将默认的Hash Based Shuffle换成了Sort Based Shuffle,即spark.shuffle.manager ...
- Dynamics CRM2013 从外部系统取到CRM系统的用户头像
CRM从2013开始引入了entityimage的概念,具体这个字段怎么设置的,图像是怎么上传的这里就不谈了.说实在的这玩意在项目中没啥用,所以也没去关注,直到最近遇到了个难题,要在外部系统去获取这个 ...
- 06 获取Activity的栈管理器
代码 <span style="font-size:18px;">package com.fmy.day8_29task.util; import java.util. ...
- antlr v4 使用指南连载1——简介
antlr v4简介 antlr是一个强大语言解析工具,可以用于处理结构化文本.二进制文件.说白了,其实可以这么认为,antlr是一个更强大的正则表达式工具.它可以完成更多正则表达式无法 ...