《Windows核心编程》第二讲 Unicode(2)成为符合ANSI和Unicode的应用程序

1. 需要注意的缓存大小问题

        因为Unicode是双字节表示一个字符,而ANSI为单字符字符串,因此在以往的程序中得到字符串的缓存大小只需要使用sizeof(szBuffer)函数即可。但对于TChar类型我们需要使用(sizeof(szBuffer)/sizeof(TCHAR),得到缓存的大小。另外,如果需要为字符串分配一个内存块,并且拥有该字符串中的字符数目,那么请记住要按字节来分配内存,即应该调用malloc(nCharacters*sizeof(TCHAR)),而不是调用malloc(nCharacters)。

2. Windws字符串函数

对Unicode字符串进行操作的函数

        这些函数是作为宏来实现的,这些宏既可以调用函数的Unicode版本,也可以调用函数的ANSI版本,这要根据编译源代码时是否已经定义了UNICODE而定。

        在这些函数中需要注意的是lstrcmp和lstrcmpi,他们的行为特性与等价的C标准库函数不同。C运行期函数strcmp、strcmpi、wcscmp、wcscmpi只是对字符串中的代码点的值进行比较,也就是说这些函数将忽略实际字符的含义,只是将第一个字符串中的每个字符的数值与第二个字符串中的字符的数值进行比较。而Windows函数中这两个比较函数时通过对Windows函数CompareString的调用实现的。

int CompareString(
    LCID lcid,
    DWORD fdwStyle,
    PCWSTR pString1,
    int cch1,
    PCWSTR pString2,
    int cch2);
        该函数对两个Unicode字符串进行比较。

        不仅如此还有一些其他函数没有为Unicode字符串的操作提供很好的支持。tolower和toupper函数无法正确地转换带有重音符号的字符。为了弥补 C运行期库中的这些不足,必须调用下面这些Windows函数,以便转换Unicode字符串的大小写字母。这些函数也可以正确地用于ANSI字符串。

PTSTR CharLower(PTSTR pszString);
PTSTR CharUpper(PTSTR pszString);

       同样函数CharLowerBuff和CharUpperBuff与上述两个函数有同样的功能,差别在于它们用于转换缓存中包含的字符(该缓存不必以0结尾)。

       Microsoft公司已经给C运行期的printf函数家族增加了一些特殊的域类型。其中有些域类型尚未被ANSI C采用。新类型使你能够很容易对ANSI和Unicode字符和字符串进行混合和匹配。如下所示:

char      szA[100];
WCHAR szW[100];

//Normal sprintf: ANSI
sprintf(szA,"%s","ANSI Str");

//convert Unicode string to ANSI
sprintf(szA,"%S",L"Unicode Str");

//normal swprintf: Unicode
sprintf(szW,L"%s",L"Unicode Str");

//converts ANSI string to Unicode
sprintf(szW,L"%S","ANSIStr");
        使用IsTextUnicode函数可以区分文本文件是包含ANSI字符还是Unicode字符。
DWORD IsTextUnicode(CONST PVOID pvBuffer, int cb, PINT pResult);
        由于文本文件的内容没有严格和明确的规则,因此很难确定该文件是包含ANSI字符还是Unicode字符。IsTextUnicode使用一系列统计方法和定性方法,以便猜测缓存的内容。由于这不是一种确切的科学方法,因此IsTextUnicode有可能返回不正确的结果。

3. 在Unicode于ANSI之间转换字符串

Windows函数MultiByteToWideChar用于将多字节字符串转换成宽字符串,函数参数如下:
int MultiByteToWideChar(
    UINT uCodePage,
    DWORD dwFlags,
    PCSTR pMultiByteStr,
    int cchMultiByte,
    PWSTR pWideCharStr,
    int cchWideChar);
        uCodePage参数用于标识一个与多字节字符串相关的代码页号。dwFlags参数用于设定另一个控件,它可以用重音符号之类的区分标记来影响字符。这些标志通常并不使用,在dwFlags参数中传递0。pMultiByteStr参数用于设定要转换的字符串,cchMultiByte参数用于指明该字符串的长度(按字节计算) 。如果为cchMultiByte参数传递-1,那么该函数用于确定源字符串的长度。

        因为没学过计算机系统原理,因此对代码页的概念不是很清楚,百度得到:代码页是字符集编码的别名,也有人称"内码表"。早期,代码页是IBM称呼电脑BIOS本身支持的字符集编码的名称。当时通用的操作系统都是命令行界面系统,这些操作系统直接使用BIOS供应的VGA功能来显示字符,操作系统的编码支持也就依靠BIOS的编码。现在这BIOS代码页被称为OEM代码页。图形操作系统解决了此问题,图形操作系统使用自己字符呈现引擎可以支持很多不同的字符集编码。

        由函数提供的信息,将多字节字符串转化成Unicode等价字符串可由以下几个步骤组成:

1)  调用MultiByteToWideChar函数,为pWideCharStr参数传递NULL,为cchWideChar参数传递0。
2)  分配足够的内存块,用于存放转换后的Unicode字符串。该内存块的大小由前面对MultiByteToWideChar的返回结果决定。3)  再次调用MultiByteToWideChar,这次将缓存的地址作为pWideCharStr参数来传递,并传递第一次调用MultiByteToWideChar时返回的缓存大小,作为cchWideChar参数。4) 使用转换后的字符串。
5) 释放Unicode字符串占用的内存块。

       相应的有将宽字符串转换为等价的多字节字符串的函数WideCharToMultiByte:

int MultiByteToWideChar(
    UINT uCodePage,
    DWORD dwFlags,    
    PWSTR pWideCharStr,
    int cchWideChar,
    PCSTR pMultiByteStr,    
    int cchMultiByte,    
    PCSTR pDefaultChar,    
    PBOOL pfUsedDefaultChar);

        跟多字节字符串转换为双字节字符串函数相比多了最后两个参数,其含义如下:如果宽字节字符不能被转换,该函数便使用pDeafualtChar参数指向的字符。如果该参数是NULL(这是大多数情况下的参数值) ,那么该函数使用系统的默认字符。该默认字符通常是个问号。这对于文件名来说是危险的,因为问号是个通配符。pDeafualtChar参数指向一个布尔变量,如果宽字符串中至少有一个字符不能转换成等价多字节字符,那么函数就将该变量置为TRUE。如果所有字符均被成功地转换,那么该函数就将该变量置为FALSE。当函数返回以便检查宽字节字符串是否被成功地转换后,可以测试该变量。同样,通常为该测试传递NULL。

       如果使用这两个函数,就可以很容易创建这些函数的Unicode版本和ANSI版本。如可以先实现Unicode版本,在ANSI中对现将字符串转换为Unicode字符串,然后调用Unicode版本函数,如果是字符串的处理函数,则需要将Unicode函数处理得到的字符串使用字符串转换函数重新得到ANSI版本。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值