分享
 
 
 

Windows程序设计——笔记(4)

王朝system·作者佚名  2006-02-01
窄屏简体版  字體: |||超大  

2.3 宽字符和WINDOWS

Windows NT从底层支援Unicode。即Windows NT内部使用由16位字符组成的字串。Windows NT可执行为ASCII、Unicode或者ASCII和Unicode混合编写的程序。

只有很少的Windows 98函数调用支援宽字串(这些函数列在《Microsoft Knowledge Base article Q125671》中;它们包括MessageBox)。

2.3.1 Windows头文件类型

一个Windows程序包括头文件WINDOWS.H。该档案包括WINDEF.H。

在WINDEF.H中有许多在Windows中使用的基本型态定义,并包括WINNT.H。

WINNT.H处理基本的Unicode支援。WINNT.H的前面包含C的头文件CTYPE.H,这是C的众多头文件之一,包括wchar_t的定义。WINNT.H定义了新的数据类型,称作CHAR和WCHAR:

typedef char CHAR ;

typedef wchar_t WCHAR ; // wc

当您需要定义8位字符或者16位字符时,推荐您在Windows程序中使用的数据类型是CHAR和WCHAR。WCHAR定义後面的注释是匈牙利标记法的建议:一个基於WCHAR数据类型的变量可在前面附加上字母wc以说明一个宽字符。

WINNT.H头文件还定义了可用做8位字串指针的6种数据类型和4个可用做const 8位字串指针的数据类型。这里是头文件中一些实用的数据类型语句:

typedef CHAR * PCHAR, * LPCH, * PCH, * NPSTR, * LPSTR, * PSTR ;

typedef CONST CHAR * LPCCH, * PCCH, * LPCSTR, * PCSTR ;

字首N和L表示「near」和「long」,指的是16位Windows中两种大小不同的指针。在Win32中near和long指针没有区别。

同样,WINNT.H定义了6种可作为16位字串指针的数据类型和4种可作为const 16位字串指针的数据类型:

typedef WCHAR * PWCHAR, * LPWCH, * PWCH, * NWPSTR, * LPWSTR, * PWSTR ;

typedef CONST WCHAR * LPCWCH, * PCWCH, * LPCWSTR, * PCWSTR ;

至此,我们有了数据类型CHAR(一个8位的char)和WCHAR(一个16位的wchar_t),以及指向CHAR和WCHAR的指针。

与TCHAR.H一样,WINNT.H将TCHAR定义为一般的字符类型。如果定义了识别字UNICODE(没有下横线),则TCHAR和指向TCHAR的指针就分别定义为WCHAR和指向WCHAR的指针;如果没有定义识别字UNICODE,则TCHAR和指向TCHAR的指针就分别定义为char和指向char的指针:

#ifdef UNICODE

typedef WCHAR TCHAR, * PTCHAR ;

typedef LPWSTR LPTCH, PTCH, PTSTR, LPTSTR ;

typedef LPCWSTR LPCTSTR ;

#else

typedef char TCHAR, * PTCHAR ;

typedef LPSTR LPTCH, PTCH, PTSTR, LPTSTR ;

typedef LPCSTR LPCTSTR ;

#endif

如果已经在某个头文件或者其他头文件中定义了TCHAR数据类型,那么WINNT.H和WCHAR.H头文件都能防止其重复定义。不过,无论何时在程序中使用其他头文件时,都应在所有其他头文件之前包含WINDOWS.H。

WINNT.H头文件还定义了一个宏定义,该宏定义将L添加到字串的第一个引号前。如果定义了UNICODE识别字,则一个称作 __TEXT的宏定义定义如下:

#define __TEXT(quote) L##quote

如果没有定义识别字UNICODE,则像这样定义__TEXT宏定义:

#define __TEXT(quote) quote

此外, TEXT宏定义可这样定义:

#define TEXT(quote) __TEXT(quote)

这与TCHAR.H中定义_TEXT宏定义的方法一样,只是不必担心下横线。我将在本书中使用这个宏定义的TEXT版本。

这些定义可使您在同一程序中混合使用ASCII和Unicode字串,或者编写一个可被ASCII或Unicode编译的程序。如果您希望明确定义8位字符变量和字串,请使用CHAR、PCHAR(或者其他),以及带引号的字串。为明确地使用16位字符变量和字串,请使用WCHAR、PWCHAR,并将L添加到引号前面。对於是8位还是16位取决於UNICODE识别字的定义的变量或字串,要使用TCHAR、PTCHAR和TEXT宏定义。

2.3.2 Windows函数调用

从Windows 1.0到Windows 3.1的16位Windows中,MessageBox函数位於动态连结程序库USER.EXE。在Windows 3.1软件开发套件的WINDOWS.H中,MessageBox函数定义如下:

int WINAPI MessageBox (HWND, LPCSTR, LPCSTR, UINT) ;

注意,函数的第二个、第三个参数是指向常数字串的指针。

32位的Windows(即所有版本的Windows NT,以及Windows 95和Windows 98)除了含有与16位相容的USER.EXE以外,还含有一个称为USER32.DLL的动态连结程序库,该动态连结程序库含有32位使用者介面函数的进入点,包括32位的MessageBox。

这就是Windows支援Unicode的关键:在USER32.DLL中,没有32位MessageBox函数的进入点。实际上,有两个进入点,一个名为MessageBoxA(ASCII版),另一个名为MessageBoxW(宽字符版)。用字串作参数的每个Win32函数都在作业系统中有两个进入点!

下面是MessageBoxA在WINUSER.H中定义的方法。这与MessageBox早期的定义很相似:

WINUSERAPI int WINAPI MessageBoxA ( HWND hWnd, LPCSTR lpText,

LPCSTR lpCaption, UINT uType) ;

下面是MessageBoxW:

WINUSERAPI int WINAPI MessageBoxW (HWND hWnd, LPCWSTR lpText,

LPCWSTR lpCaption, UINT uType) ;

注意,MessageBoxW函数的第二个和第三个参数是指向宽字符的指针。

根据是否定义了UNICODE,MessageBox将与MessageBoxA或MessageBoxW一样。

#ifdef UNICODE

#define MessageBox MessageBoxW

#else

#define MessageBox MessageBoxA

#endif

这样,如果定义了UNICODE识别字,那么程序中所有的MessageBox函数调用实际上就是MessageBoxW函数;否则,就是MessageBoxA函数。

2.3.3 Windows的字串函数

下面是Windows定义的一组字串函数,这些函数用来计算字串长度、复制字串、连接字串和比较字串:

ILength = lstrlen (pString) ;

pString = lstrcpy (pString1, pString2) ;

pString = lstrcpyn (pString1, pString2, iCount) ;

pString = lstrcat (pString1, pString2) ;

iComp = lstrcmp (pString1, pString2) ;

iComp = lstrcmpi (pString1, pString2) ;

这些函数与C程序库中对应的函数功能相同。如果定义了UNICODE识别字,那么这些函数将接受宽字串,否则只接受常规字串。宽字串版的lstrlenW函数可在Windows 98中执行。

2.3.4 在Windows中使用printf

如果您从未使用过sprintf (我第一次开始写Windows程序时也没用过此函数),这里有一个简短的执行实例,printf函数说明如下:

int printf (const char * szFormat, ...) ;

第一个参数是一个格式字串,後面是与格式字串中的代码相对应的不同类型多个参数。

sprintf函数定义如下:

int sprintf (char * szBuffer, const char * szFormat, ...) ;

第一个参数是字符缓冲区;後面是一个格式字串。Sprintf不是将格式化结果标准输出,而是将其存入szBuffer。该函数返回该字串的长度。

在文字模式程序设计中,

printf ("The sum of %i and %i is %i", 5, 3, 5+3) ;

的功能相同於

char szBuffer [100] ;

sprintf (szBuffer, "The sum of %i and %i is %i", 5, 3, 5+3) ;

puts (szBuffer) ;

在Windows中,使用MessageBox显示结果优於puts。

使用sprintf时,有一个问题,即定义的字串缓冲区必须足够大以存放结果。Microsoft专用函数_snprintf解决了这一问题,此函数引进了另一个参数,表示以字符计算的缓冲区大小。

vsprintf是sprintf的一个变形,它只有三个参数。vsprintf用於执行有多个参数的自订函数,类似printf格式。vsprintf的前两个参数与sprintf相同:一个用於保存结果的字符缓冲区和一个格式字串。第三个参数是指向格式化参数阵列的指针。实际上,该指针指向在堆栈中供函数调用的变量。va_list、va_start和va_end宏定义(在STDARG.H中定义)帮助我们处理堆栈指针。

使用vsprintf函数,sprintf函数可以这样编写:

int sprintf (char * szBuffer, const char * szFormat, ...)

{

int iReturn ;

va_list pArgs ;

va_start (pArgs, szFormat) ;

iReturn = vsprintf (szBuffer, szFormat, pArgs) ;

va_end (pArgs) ;

return iReturn ;

}

va_start宏定义将pArg设置为指向一个堆栈变量,该变量位址在堆栈参数szFormat的上面。

由於许多Windows早期程序使用了sprintf和vsprintf,最终导致Microsoft向Windows API中增添了两个相似的函数。Windows的wsprintf和wvsprintf函数在功能上与sprintf和vsprintf相同,但它们不能处理浮点格式。

当然,随著宽字符的发表,sprintf类型的函数增加许多,使得函数名称变得极为混乱。表2-1列出了Microsoft的C执行时期程序库和Windows支援的所有sprintf函数。

表2-1

ASCII

宽字符

常规

参数的变量个数

标准版

sprintf

swprintf

_stprintf

最大长度版

_snprintf

_snwprintf

_sntprintf

Windows版

wsprintfA

wsprintfW

wsprintf

参数阵列的指针

标准版

vsprintf

vswprintf

_vstprintf

最大长度版

_vsnprintf

_vsnwprintf

_vsntprintf

Windows版

wvsprintfA

wvsprintfW

wvsprintf

在宽字符版的sprintf函数中,将字串缓冲区定义为宽字串。在宽字符版的所有这些函数中,格式字串必须是宽字串。不过,您必须确保传递给这些函数的其他字串也必须由宽字符组成。

2.3.5 格式化讯息方块

程序2-1所示的SCRNSIZE程序展示了如何实现MessageBoxPrintf函数,该函数有许多参数并能像printf那样编排它们的格式。

程序2-1 SCRNSIZE

SCRNSIZE.C

/*---------------------------------------------------------------------------

SCRNSIZE.C -- Displays screen size in a message box

(c) Charles Petzold, 1998

----------------------------------------------------------------------------*/

#include <windows.h>

#include <tchar.h>

#include <stdio.h>

int CDECL MessageBoxPrintf (TCHAR * szCaption, TCHAR * szFormat, ...)

{

TCHAR szBuffer [1024] ;

va_list pArgList ;

// The va_start macro (defined in STDARG.H) is usually equivalent to:

// pArgList = (char *) &szFormat + sizeof (szFormat) ;

va_start (pArgList, szFormat) ;

// The last argument to wvsprintf points to the arguments

_vsntprintf ( szBuffer, sizeof (szBuffer) / sizeof (TCHAR),

szFormat, pArgList) ;

// The va_end macro just zeroes out pArgList for no good reason

va_end (pArgList) ;

return MessageBox (NULL, szBuffer, szCaption, 0) ;

}

int WINAPI WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance,

PSTR szCmdLine, int iCmdShow)

{

int cxScreen, cyScreen ;

cxScreen = GetSystemMetrics (SM_CXSCREEN) ;

cyScreen = GetSystemMetrics (SM_CYSCREEN) ;

MessageBoxPrintf ( TEXT ("ScrnSize"),

TEXT ("The screen is %i pixels wide by %i pixels high."),

cxScreen, cyScreen) ;

return 0 ;

}

经由从GetSystemMetrics函数得到的信息,该程序以像素为单位显示了视讯显示的宽度和高度。GetSystemMetrics是一个能用来获得Windows中不同物件的尺寸信息的函数。

2.3.6 本书与国际化

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有