Windows程序设计,体系第四篇

By admin in 美高梅手机版4858 on 2019年1月17日

  刚起初上学Windows程序设计,磕磕碰碰,先做个小笔记缓缓神经,重如果将MessageBox这多少个Windows
API函数的。

第一回顾下C语言在决定台下通过标准输入输出函数输出”Hello,world!”的次第,
代码如下

美高梅手机版4858 1

目录

  MessageBox函数是众多少人刚先导学习Windows程序设计仍然是Windows
API遭逢的第一个放置函数,这多少个函数使用的章程是:

#include <stdio.h>

int main()
{
    printf( "Hello,world!\n" ) ;
    return 0 ;
}

上一篇我们学习了Windows编程的文书及字体输出,在以上几篇的实例中也应运而生了有的饱含“TEXT”的Windows宏定义,有意中人留言想通晓一些ANSI和Unicode编程方面的内容,本章就来打听和读书有些Windows下关于ANSI和Unicode方面的编程基础。

2.1       Windows数据类型.. 1

  MessageBox(NULL, TEXT(“弹出框内容”),
TEXT(“标题”), MB_OK);

下一场先天上了第一趟VC++课后,学会了Windows版Hello,world!,代码如下:

总括机最早在美利坚联邦合众国落地,所以最起首都是以阿尔巴尼(Barney)亚语为作为交互语言,由于只有26个假名,用一个字节(范围-128
~
127)表示,这多少个限制丰硕表示26个因为字符和一些常用的控制字符,这个就是ASCII编码。因而最早的各个程序设计语言以及采纳的字符串都用字节数组表示,也真的满意了编程的各样急需。可是随着总结机的普及,范围上逐级超过了乌克兰(Crane)语应用的国度,这样一来,字符编码就成了问题,因为众多国家的言语字符数目根本不可以用一个字节来代表,比如大家国家的闽南语,常用的就有四千两个,假使再加上有些不常用的字符,更是远远不止这一个,因而一个字节的字符串编码就不行了,那么自然则然就涌出了五个字节甚至跟多字节的编码情势了。

2.1.1       Windows数据类型示例.. 1

  初次之外,它还有多少个姐妹:

#include<windows.h>

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow )
{
    MessageBox( NULL, TEXT("Hello,world!"), TEXT("MessageBox"), 0 );

    return 0;
}

除外主导的ASCII编码外,近日常用的字符编码有MBCS、BG2312、GBK、UTF-8、UTF-16、
UTF-32、BIG5、Base64、Unicode等等,其实Unicode就是行使UTF-16编码。现在的富有系统都帮忙多字节编码,Windows98从前的对Unicode辅助不佳,很多内核函数都亟待将字符串转换之后才能处理,从Windows
NT系统后几乎都利用了Unicode编码重新系统基本,非Unicode的编码会经过转换之后在传唱内核处理。

2.1.2       Windows 数据类型与正规C 数据类型的关系.. 5

  MessageBoxA(NULL, “弹出框内容”,
“标题”, MB_OK);   // TEXT可有可无

在VC6.0环境下,新建WIN32
Application,选中C++Sources文件,添加cpp文件后,敲出如上代码,编译,运行,出现下边窗口:

在C语言诞生的时候,同样还未曾遇上多字节字符串问题,当然也尚未Unicode等这么些编码,标准的C语言库函数处理字符串时都是ASCII编码,由此用标C函数处理多字节字符编码就存在问题,所以不同体系都在内部开展这种字符编码的拍卖。那么问题来了,既然标C不补助Unicode,我们又何以编程使用Unicode呢?我们如何指定程序中的字符串拔取ASCII依然Unicode或者二种同时出现在一个顺序里面呢?
更好的事态,我们什么编写程序,依照自己的急需编译ASCII和Unicode(以下称宽字符)版本?本文我们就来谈谈那么些问题。在微软公司提供的C/C++编译器中提供了一个wchar_t的变量类型,那几个项目实际上是因此typedef定义的一个无符号16位整型数。大家应用那些来定义宽字符版本的字符和字符串,而日常的ANSI仍然专业C语言的char来定义。

2.1.3       Windows 数据类型与Windows API 5

  MessageBoxW(NULL, L””, L””, MB_OK);  
                    // 这些L用来表示Unicode,不得以简单

美高梅手机版4858 2

  • 宽字符串的采取

2.1.4       Windows 中的数据结构.. 6

  其实之所以有这六个是因为微软特需知足Windows
98之后对汉字等此外语言编码的需要,这种需要通过Unicode实现,然而微软本意不是要我们利用Unicode来编程,而是经过采用“通用”形式,也就是MessageBox();函数,实现不同的编码紧要如故经过IDE集成开发条件下转移不同的编码模式。回到MessageBox();,明天可比胸口痛的是,怎么在MessageBox();中落实变量的打印呢?

本条对话框中, 有标题栏, 标题栏的内容是”HELLO”,
对话框的情节为”Hello,world!”, 还有一个”确定”按钮, 而且,
没有这么些黑框框窗口, 一切看起来都是那么美好,
来一起看看这段Windows版的Hello,world!吧美高梅手机版4858 ,!

下面我们比较一下ASCII和Unicode字符(串)的概念及常量的概念形式。

2.2       Windows API 的意义分类.. 7

  就像C语言中不时使用printf函数,这么些函数挺好玩的,应为函数输入的参数是未曾范围个数的,相当于是随机改变的。例如:

*关于windows.h头文件:
    在windows.h这些头文件中, 实际上已经包含了好多的任何连锁的头文件,
用书上的话说, windows.h是个要命紧要的盈盈文件,
其中蕴蓄的其它相比关键的头文件有:
    ■ WINDEF.H              基本数据类型定义
    ■ WINNT.H                补助Unicode的类型定义
    ■ WINBASE.H           内核函数
    ■ WINUSER.H           用户界面函数
    ■ WINGDI.H             图像设备接口函数
唯独我或者好奇windows.h到底包含了那么些头文件, 找到VC6的设置目录,
打开Include文件夹, 找到WINDOWS.H并开拓, 虽说看不太懂,
但找#include关键词依旧无压力的.
而外下面的5个还有:
    ■ WINRESRC.H      ■ EXCPT.H              ■ STDARG.H            ■
WINNLS.H            ■ WINCON.H
    ■ WINVER.H          ■ WINREG.H         ■ WINNETWK.H       ■
CDERR.H             ■ DDE.H
    ■ DDEML.H            ■ DLGS.H             ■ LZEXPAND.H         ■
MMSYSTEM.H       ■ NB30.H
    ■ RPC.H                 ■ SHELLAPI.H        ■ WINPERF.H           ■
WINSOCK2.H       ■ MSWSOCK.H
    ■ WINSOCK.H        ■ WINCRYPT.H       ■ COMMDLG.H         ■
WINSPOOL.H       ■ OLE.H
    ■ OLE2.H               ■ WINWLM.H          ■ WINSVC.H            ■
MCX.H                 ■ IMM.H

ASCII版本:

2.2.1       系统大旨服务.. 7

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 int main(){
 5
 6     int x=100, y=200, z=300;    
 7     
 8     printf("%d %d %d.\n", x, y, z);
 9     system("pause");
10     return 0;
11 }

*先后的入口
在Win32控制台程序(Win32 Console Application)中,
应用程序的输入为main()函数,
windows程序的次序入口和win32控制台程序的进口类似, 为WinMain()函数.
程序的入口函数在WINBASE.H作出了声称, 阐明如下:

Char c = ‘A’;
Char str[] = “hello, world”;

2.2.2       系统管理.. 9

 

int
WINAPI
WinMain(
    HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR lpCmdLine,
    int nShowCmd
    );

 

2.2.3       用户界面.. 9

  这几个printf函数不仅可以应用五个参数打印,仍能用来一直打印变量,不过MessageBox却不可能直接打印,那个引起自己的直接思考。我先想到的是确立一个缓冲区,利用这几个缓冲区取打印字符数量。当然打印的函数得使用sprintf了

个中由表明可以见见, WinMain函数的重返值被定义为int型;
WINAPI为WinMain函数的调用规则, 在WINDEF.H对”WINAPI”作出了之类宏定义:

宽字符版本:

2.2.4       图像和多媒体.. 15

  

#define WINAPI __stdcall

wchar_t wch = L’A’;
wchar_t wstr[] = L“hello, world”;

2.2.5       网络.. 15

 1 int main(){
 2     
 3     int a = 12;
 4     char szBuffer[100];             // 使用一个字符数组来做缓冲区
 5 
 6     sprintf(szBuffer, "helloworld %d.\n", a);
 7     _snprintf(szBuffer, 100, "helloworld %d.\n", a);
 8         // 使用_snprintf函数比较安全,因为可以输入限定字符的个数  
 9 
10     printf("%s.\n", szBuffer);
11     puts(szBuffer);                            // 可以使用printf中的%s将szBuffer打印出来,或者用puts直接输出
12     //printf("helloworld.\n");
13 
14     system("pause");
15     return 0;
16 }

表达, WinMain函数的调用规则为”__stdcall”方式,
对于”__stdcall”调用规则, 现在临时先不去探索, 知道有这么回事就行,
未来会详细摸底到的, 现在如若深究”__stdcall”就离开了这篇博文的主题。

 

2.2.6       其他职能.. 15

 

 

微软的编译器通过这么些大写字母“L”开端来鉴别前面的字符串将编译为一个Unicode的字符或字符串,注意这里的L前面不可以有空格

2.3       Windows API核心DLL. 16

  这个缓冲区的主意假使用在MessageBox函数里面,就可以兑现打印变量的法门,比如以下代码:

*WinMain函数的参数:
1>. WinMain的率先个参数 HINSTANCE hInstance,
用书上的讲演为”实例句柄”, 由于第一次接触C语言Windows程序设计,
对那些句柄的定义也不是很了然, 去完善了下,
句柄的演讲为”一个句柄是指利用的一个唯一的平头值,即一个四字节长的数值,来注明应用程序中的不同目的和同类对象中的不同的实例,诸如,一个窗口,按钮,图标,滚动条,输出设备,控件或者文件等。”——引用自百度百科->句柄。

看上面的实例:

2.3.1       Kerne132.dll 16

#include <windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){
    int a = 12;

    TCHAR szBuffer[100];                  // 通用版本
    _stprintf(szBuffer, TEXT("hello 通用 %d"), a);
    MessageBox(NULL, szBuffer, TEXT("通用"), MB_OK  | MB_ICONINFORMATION);

    return 0;
}

作者是这样对句柄举行精通的, 在一个应用程序中,
平时成立了成百上千的窗口、按钮、标签, 或者接纳了一个文件等,
在程序的此外地点, 只要可以收获这多少个被称为句柄的东西,
就可以找到该控件或者窗口在内存中的地方,
从而对其展开操作。感觉有点像带参数的main函数,
只是这里的主函数参数为一个句柄。

#include <windows.h>
#include <stdio.h>

int main(void)
{
    char c = 'A';
    char str[] = "hello, ANSI";

    wchar_t wch = L'A';
    wchar_t wstr[] = L"hello, Unicode";

    printf("1 --> %c\n", c);
    printf("2 --> %s\n", str);

    printf("3 --> %c\n", wch);
    printf("4 --> %s\n", wstr);

    printf("5 --> %C\n", c);
    printf("6 --> %S\n", wstr);

    wprintf(L"7 --> %c\n", wch);
    wprintf(L"8 --> %s\n\n", wstr);

    system("pause");
    return 0;
}

Windows程序设计,体系第四篇。2.3.2       User32.dll 16

 

2>. WinMain函数的第二个参数, 同样是个实例句柄,
但书上又进而解释说在32位的Windows程序设计中,
WinMain函数的实例句柄概念已不再动用,
由此WinMain的第二个参数日常总是NULL。

 

2.3.3       Gdi32.dll 16

  不过每一遍都写个缓冲区来存放在,并且一不下心忘记行使_snprintf函数,这就GG了,很可能爆发缓冲区溢出的安危。因而,这里运用printf原先函数设计的法则,我们也来规划一个MessageBoxPrintf();函数,用这一个函数来实现格式化输出的功效,要兑现这个函数,首先得参考printf();函数的实现原理。

笔者的理念: 感觉立刻快要晕了, 疑问一:
“由此WinMain的第二个参数通常总是NULL”,
那么首先个呢?WinMain的第一个参数会不会也可以是NULL呢? 疑问二:
WinMain函数的参数从何而来?是操作系统么?带着疑问继续向下看。

以此小程序的出口如下:

2.3.4       标准C函数.. 17

int my_printf(const char * szFormat, ...){

    int iReturn;
    va_list pArgs;

    va_start(pArgs, szFormat);
    iReturn = vprintf(szFormat, pArgs);
    va_end(pArgs);

    return iReturn;
}


int main(){

    int x=100, y=200, z=300;

    printf("hello %d, %d, %d.\n", x, y, z);        
    my_printf("test_my_printf,哈哈%d %d.\n", x, y);

    system("pause");
    return 0;
}

3>. WinMain的第三个参数是用来运转程序的命令行, PSTR:
用来针对一个字符串的指针类型, szCmdLine, sz:表示以0结尾的字符串;
目标是透过命令行模式运行程序并向主函数中流传参数,
应该就像给main函数传入参数一样;

美高梅手机版4858 3

2.3.5       其他Dll 17

 

4>. WinMain的第五个参数是一个int型参数,
用来指明程序(窗口)最初如何被呈现, 例如最小化?最大化?全屏?
笔者的见地: 应该很有用, 通常见一些嬉戏一启动就是全屏的,
可是其一参数也是顾虑系统传给程序的么?因为从平日运作Windows程序时都是直接双击,
并没有通过命令行给它传到参数,
在编程时应当对先后启动时的显示模式有坦白才对,
这样系统再运行时再把那一个交代的参数传入给程序告诉程序启动时应该怎么突显.

可以见到:

2.4       Unicode和多字节.. 17

  …表示的意味是传播的参数是可变参数个数的,va_start(pArgs,
szFormat);表示指向szFormat之后的一个参数,那些函数的浩大事物本身现在也还没精晓过来,之后再来补充,然而现在仿效这个函数我们得以自己写个MessageBoxPrintf();函数,具体代码如下:

*WinMain函数函数体的MessageBox函数:
MessageBox(), 名如其”人”, 不用猜也驾驭这几个就是显示一个对话框的函数,
打开API文档,MSDN Library通过索引找到MessageBox函数, 发现其宣称如下:

  1. 用printf可以输出ANSI的字符和字符串(废话)
  2. 用wprintf可以输出Unicode字符和字符串
  3. printf可以用小写的字母C、S,即“%C”“%S”来输出宽字符和字符串
  4. 能够看出第3和第4用printf可以输出宽字符,但宽字符串仅仅输出了字符串的第一个字符,实际上这多少个就是题材了,无法这样输出,第3的字符A实际上完全是天意好,因为Unicode是双字节,所以宽字符”A”实际在是十六进制的“00
    41”,而Windows系统是一个小端系统,所以在内存中的排版为“41 00
    ……”,所以率先个刚好输出A。而第4只好出口一个“h”,也是因为这多少个缘故。字符串wstr在内存的存在格局如下如:

2.4.1       W版本和A版本的API 21

// 自己做一个格式化的messageboxprintf对话框
int CDECL MessageBoxPrintf(TCHAR * szCaption, TCHAR * szFormat, ...){

    TCHAR szBuffer[1024];
    va_list pArglist;

    va_start(pArglist, szFormat);
    _vsnprintf(szBuffer, sizeof(szBuffer)/sizeof(TCHAR), szFormat, pArglist);
    va_end(pArglist);

    return MessageBox(NULL, szBuffer, szCaption, MB_OK | MB_ICONINFORMATION);
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){

    int x=100, y=200, z=300;
    int cxScreen, cyScreen;

    cxScreen = GetSystemMetrics(SM_CXSCREEN);
    cyScreen = GetSystemMetrics(SM_CYSCREEN);

    // MessageBoxW(NULL, L"helloworld", L"biaoti", MB_OK);
    // MessageBoxA(NULL, TEXT("helloworld"), TEXT("biaoti"), MB_OK);
    MessageBoxPrintf(TEXT("我的标题"), TEXT("hello %d %d %d"), x, y, z);    // 把这个函数做好后,直接就可以输出
    MessageBoxPrintf(TEXT("我的屏幕大小"), TEXT("我的屏幕宽度是:%d.\n高度是:%d.\n"), cxScreen, cyScreen);


    return 0;
}

int MessageBox(
  HWND hWnd,          // handle of owner window, 窗口的一个句柄
  LPCTSTR lpText,     // address of text in message box,
一个文书(字符串)的指针
  LPCTSTR lpCaption,  // address of title of message box,
标题字符串的指针
  UINT uType          // style of message box, 对话框的品格
);

美高梅手机版4858 4

2.4.2       Unicode与ASGII的转换.. 22

  相当于自己计划出来一个好像printf的小工具,因为微软真正没有计划MessageBox中举行格式化输出的函数。

在上边示例中对MessageBox函数的调用如下:

首个字符是“h”,它的宽字符在内存排布(小端系统)为”68 00
…”,依照C语言规则,字符串以空字符0x00为了却符,因而采取printf和%s来输出时,系统并不知道这一个h是一个宽字符,而是以此向后直接到空字符,这里刚好第二个就冲击了,因而只可以输出一个“h”。

2.4.3       对Windows程序设计规范的提议.. 22

MessageBox( NULL, TEXT(“Hello,world!”), TEXT(“MessageBox”), 0 );

一致,scanf函数也是如此:

2.5       小结.. 23

首先个参数窗口的句柄的实参为NULL, 意思为不属于另外窗口.
其次个参数为对话框的情节, 第六个参数为对话框的题目,
可是这多少个参数都采用了一个TEXT()的函数,
书上讲使用TEXT()的目标是将这多少个字符串打包到TEXT宏代码里面,
笔者尝试了不要这个TEXT()函数而直接像这么:

scanf(“%s”, str); //那个是C语言的健康用法

 

MessageBox( NULL, “Hello,world!”, “MessageBox”, 0 );
在VC6.0不会报错,在VS2010下会报错,那几个TEXT其实是为着匡助不同字符编码的预编译设置,假使定义了UNICODE宏,则TEXT(“”str“”)展开为宽字符串L“str”,反之则举行为“str”。这多少个题材本身查了成百上千材料,详细都记在记录本中。

scanf(“%s”, wstr); //这些是足以干活的,不过接到结果是ANSI格式的字符串

 

美高梅手机版4858 5

scanf(“%S”, wstr); //这一个可以正确接受宽字符格式的字符串

 

美高梅手机版4858 6

wscanf(L”%s”, wstr); //这么些是正统的收纳宽字符格式字符串

2.1    Windows数据类型

Windows API 使用了广大 Windows 自己定义的数据类型。读者也许较为娴熟 C
语言或 C++语言的数据类型。要熟谙应用 Windows API 必须要熟习 Windows
数据类型。这一个数据类型是Windows 特有的。在 SDK 的相关头文件中有定义。

在很多的Windows 数据类型中,最常用的有
DWORD、HANDLE、LPTSTR、WORD、BYTE、CHAR 等。在 Windows 系统中,DWORD
用于表示无符号整型的数量,意为 double word,32位。

在相似处境下 BYTE 是 8 位的,而 WORD 是 16 位,DWORD 就是 32 位的。

Windows 系统的应用程序中还有所一个故意的数据类型-HANDLE,通常 HANDLE
类型的变量用于唯一标识一个“对象”,如窗口、控件、文件等,Windows
平西安存在很多这样的目的,对象是先后操作的目的。HANDLE 也是一个 32
位的数据类型。

第五个参数为对话框的作风, 一些以MB_千帆竞发的有些常量的构成,
可以利用OR(|)运算举办重组, 这么些常量定义在WINUSER.H中, 例如常用的有:

如上的printf和scanf用%S来处理宽字符的章程是微软增加的,不肯定其他编译系统也能这样处理。

2.1.1    Windows数据类型示例

实例2-1施用了两种为主的 Windows 数据类型,演示 Windows
数据类型在程序中的使用模式。

  1. 实例2-1 常用Windows数据类型演示(DWORD/LPSTR/CHAR/INT)

本实例定义了多少个常用常量的 Windows 数据类型,包括 DWORD,LPSTR 和
CHAR,并演示了什么行使它们举行了复制、比较大小等操作。

/* ************************************
*《精通 Windows API》 
* 示例代码
* windata.c
* 2.1.1  常用的 Windows 数据类型
**************************************/
/* 头文件  */
#include <windows.h>
#include <stdio.h>
/* ************************************
* 功能  Windows 数据类型演示
**************************************/
int WINAPI WinMain( 
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
)
{
//定义字符串
LPSTR szString = "Windows data type, string.";
//定义字符数组
CHAR lpString[120];//要大于 szString 的长度
//定义 DWORD 类型的数据
DWORD dwMax = 0xFFFFFFFF;
DWORD dwOne = 0x1;
//定义 INT 类型的数据
INT iMax = 0xFFFFFFFF;
INT iOne = 0x1;
//显示字符串
MessageBox(NULL,szString,"LPSTR",MB_OK);
//复制内存,将字符串复制到数组中(包括 NULL 结束符)
CopyMemory(lpString, szString,lstrlen(szString)+1);
//显示复制的字符串
MessageBox(NULL,lpString,"CHAR[]",MB_OK);
//比较 DWORD 并显示结果
if(dwMax>dwOne)
{
MessageBox(NULL,"DWORD 类型的数据 OxFFFFFFFF > 0x1","DWORD",MB_OK);
} 
//比较 INT 并显示结果
if(iMax<iOne)
{
MessageBox(NULL,"INT 类型的数据 OxFFFFFFFF < 0x1","INT",MB_OK);
}
return 0;
}

 

 

在这一个程序中,使用了 4 种 Windows 数据类型,分别是 LPSTR、CHAR、DWORD 和
INT。

LPSTR 类型的数据是字符串,也就是字符指针,CHAR 是字符,DWORD 是 32
位的无符号整数,INT 是 32 位有标志整数。程序运行后会弹出 4
个对话框。这表达 dw马克斯>dwOne 是起家的。i马克斯<iOne 也是白手起家的。dw马克斯(Max)与 i马克斯 的数值是相同的,dwOne 与 iOne
的数值也是相同的。可是正如结实不同,是因为两者的数据类型不平等。

 

  1. 查阅Windows数据类型的概念

在 Visual Studio
中得以查看数据类型的定义。在数据类型的档次名(比如“DWORD”)上单击右键,选拔“转到定义”,如图
2-1 所示。

 美高梅手机版4858 7

图2-1

可以从 SDK 的头文件中观察各项目标类型定义。

“INT”的概念如下:

 typedef int                 INT;

 

“DWORD”的定义如下:

 typedef unsigned long       DWORD;

 

“CHAR”的定义如下:

 typedef char CHAR;

 

    从中可以发现,这个 Windows 数据类型都是从标准 C
的数据类型经过类型重定义而来。INT 数据类型是有记号整型,DWORD
数据类型是无符号整型。 这就认证了干吗在实例 2-1 中 INT 数据类型的变量
i马克斯 实际是“-1”,而 DWORD 类型的变量 dw马克斯实际是“4294967295”,所以会合世如上的可比结实。

  1. 最常见的Windows数据类型

表2.1 常用的基本Windows数据类型

类型

描述

BOOL

布尔型变量(值只能是True或False)

BYTE

字节类型(8位)

CHAR

8比特字节(ANSI)

CONST

常量,相当于标准C中的”const”关键字

DWORD

32字节无符号整型数据

DWORD32

32字节无符号整型数据

DWORD64

64字节无符号整型数据

FLOAT

浮点数据类型

HANDLE

对象的句柄,最基本的句柄类型

HICON

图标的句柄

HINSTANCE

程序实例的句柄

HKEY

注册表键的句柄

HMODULE

模块的句柄

HWND

窗口的句柄

INT

32位符号整型数据类型

INT_PTR

指向INT类型数据的指针类型

INT32

32位符号整型

INT64

64位符号整型

LONG

32位符号整型,相当于C语言的标准数据类型long

LONGLONG

64位符号整型

LONG32

32位符号整型

LONG64

64位符号整型

LPARAM

消息的L参数

WPARAM

消息的W参数

LPCSTR

Windows(ANSI)字符串常量

LPCTSTR

根据环境配置,如果定义了UNICODE宏,则是LPCWSTR类型,否则是LPCSTR类型

LPCWSTR

UNICODE字符串常量

LPDWORD

指向DWORD类型数据的指针

LPSTR

Windows(ANSIC)字符串常量

LPTSTR

根据环境配置,如果定义了UNICODE宏,则是LPTSTR类型,否则是LPSTR类型

LPWSTR

UNICODE字符串常量

SHORT

无符号短整型(16位)

SIZE_T

表示内存大小,以字节为单位,其最大值是CPU最大寻址范围

TCHAR

如果定义了UNICOD,则为WCHAR,否则为CHAR

UCHAR

无符号CHAR

UINT

无符号INT

ULONG

无符号LONG

VOID

无类型,相当于标准C语言的void

WCHAR

16位Unicode字符

WINAPI

Windows API的函数调用方式,常见于SDK头文件中对API函数的声明中,相当于__stdcall(更严格讲,不是数据类型,而是函数调用约定)

WORD

16位无符号整型数据

  1. Windows数据类型名称命名的原理

Windows 数据类型的命名都很有规律。

主导数据类型包括 BYTE、CHAR、WORD、SHORT、DOWRD、INT 等。

指针类型的吩咐模式相似是在其针对性的数据类型前加“LP”或“P”,比如对准
DWORD的指针类型为“LPDWORD”和“PDWORD”。

各样句柄类型的下令形式一般都是在目的名前加“H”。Windows
系统中有好多目的,所有代表一个目的的数据类型都是句柄,每一种对象都对应着一种句柄类型,比如与位图(
BITMAP)对应的句柄类型为“HBITMAP”,与菜单(MENU)对应的句柄类型为“HMENU”,与窗口(WINDOW)对应的句柄类型为“HWND”。无符号类型一般是以“U”初始,比如“INT”是符号类型,“UINT”是无符号类型,“LONG”是符号类型“ULONG”是无符号类型等。

1>.对话框按钮类型:

  • Unicode字符串辅助函数

2.1.2    Windows 数据类型与规范C 数据类型的涉及

翻看 Windows 数据类型的概念可以观察,所有的 Windows 数据类型都是由 C
数据类型经过类型重定义拿到的。如 DWORD 实质上就是 unsigned long
数据类型,32 位的无符号整型:

typedef unsigned long       DWORD;

 

实则 VC 编译器是一个完好的 C 编译器,另外并不曾过多的扩充。Windows
数据类型也不是 VC 的内建类型,而从规范 C 类型重定义拿到。

    #define MB_OK                       0x00000000L           
//仅有一个”确定”按钮
    #define MB_OKCANCEL                 0x00000001L           
//”确定” + “取消”
    #define MB_ABORTRETRYIGNORE         0x00000002L           
//”终止” + “重试” + “忽略”
    #define MB_YESNOCANCEL              0x00000003L            //”是”

从地方大家看看,微软的编译器对宽字符及宽字符串常量用一个大写的“L”作为前缀来高手编译,前面的字符串作为Unicode版本而不是ANSI版本。此外printf和scanf也有对于的宽字符版本函数wprintf和wscanf来拍卖,从MSDN大家精通,所有关于字符/字符串都有四个本子,比如_wfopen、_getws、wcslen、wcscpy、wcscat等就是正经C函数fopen、gets、strlen、strcpy、strcat的宽字符版本。除了这个标C的宽字符函数外,Windows的API同样有ANSI和Unicode版本,比如创制窗体和空中的CreateWindowA、CreateProcessA等就是ANSI版本,而相应的CreateWindowW、CreateProcessW就是Unicode版本,他们处理的字符串类型都必须是wchar_t的字符串。

2.1.3    Windows 数据类型与Windows API

Windows API 函数的参数、重回值或部分至关首要的常量使用的数据类型都是 Windows
数据类型。如:

int MessageBox(
HWND hWnd,
LPCTSTR lpText,
LPCTSTR lpCaption, 
UINT uType
);

 

MessageBox 函数的再次来到值是 int 型的,是业内 C
数据类型,不过拥有的参数都拔取了Windows 数据类型。如 HWND 是一种 W
indows 数据类型,用于表示窗口的句柄;LPCTSTR 也是Windows
数据类型,表示字符串常量;UINT 也是 Windows 数据类型,为无符号整型。

  • “否” + “取消”
        #define MB_YESNO                    0x00000004L            //”是”
  • “否”
        #define MB_RETRYCANCEL              0x00000005L           
    //”重试” + “取消”

在一个主次里面,我们得以采用ANSI版本的函数来拍卖相应的字符串,同时也足以应用Unicode版本的函数来拍卖wchar_t的字符串,正如下面的实例一样,但必须呼应,否则可能出现编译错误,更麻烦的是有可能编译通过但是结果却不是我们想要的,如下面的第4一条出口。

2.1.4    Windows 中的数据结构

Windows 中涵盖很多种数据结构类型,在不同品种的 API
中会使用到不同的数据结构,由于数据结构的数据众多,将在继续章节具体的实例中介绍实现每一种意义所采纳的数据结构。数据结构平日会作为一些
API 的参数输入。

typedef struct _WIN32_FILE_ATTRIBUTE_DATA{
DWORD    dwFileAttributes;
FILETIME  ftCreationTime;
FILETIME  ftLastAccessTime;
FILETIME  ftLastWriteTime;
DWORD    nFileSizeHigh;
DWORD    nFileSizeLow;
} WIN32_FILE_ATTRIBUTE_DATA,*LPWIN32_FILE_ATTRIBUTE_DATA;

 

相当于:

typedef struct _WIN32_FILE_ATTRIBUTE_DATA{
DWORD    dwFileAttributes;
FILETIME  ftCreationTime;
FILETIME  ftLastAccessTime;
FILETIME  ftLastWriteTime;
DWORD    nFileSizeHigh;
DWORD    nFileSizeLow;
};
typedef _WIN32_FILE_ATTRIBUTE_DATA WIN32_FILE_ATTRIBUTE_DATA;
typedef _WIN32_FILE_ATTRIBUTE_DATA *LPWIN32_FILE_ATTRIBUTE_DATA;

 

Windows SDK 中,结构体也有温馨的命名规范。一般情况下,Windows
系统中应用全大写来命名结构体、共用体,并应用“_”来分隔单词,在结构名加“LP”或“P”表示针对数据结构的指针。

 

自然假设不是需要,最好不用在程序里面一会儿应用ANSI,一会采纳Unicode,这样对大顺的移植性兼容性很差,也不便宜多语种和国际化。强烈提议使用Unicode版本来编写程序,那些是一个大趋势,假诺你要把PC平台的Windows程序移植到微软的嵌入式平台Win
CE上的话,就非得是Unicode。微软为了简化和通用性,在Win
CE平台上只扶助Unicode。而且动用Unicode编码时运行效用更高,因为后天的Windows操作系统内核全体都是用Unicode版本,假若上面传出一个ANSI的,它必须先转换成Unicode字符串,再扩散内部的函数处理。

2.2    Windows API 的意义分类

Windows API
所能实现的效率包括过多上边,在进展应用程序的付出时,开发人士可能会选取到文件、进程、内存、权限、系统消息等系统的中坚服务和序列管理类的
API,可能会用到图形用户界面、控件等函数和对象,可能需要在界面上绘制图像处理多媒体消息等,还包括举行网络通信支出等。

2>.对话框中的图标类型:  

  • 与此同时帮忙三种编码

2.2.1    系统基本服务

系统主题服务是 Windows API
最主旨的始末,是最常使用到的程序接口。系统中央服务API 包括以下多少个方面。

  1. 文件系统

对文件的基本操作包括文件的创立、打开、读写、关闭、删除,文件属性的安装与收获,目录操作,以及磁盘分卷的操作,还包括镜像文件、加密文件系统等。

  1. 内存管理

着重是内在的分红、共享、释放等内容,包括虚拟内存管理、分页机制、堆管理等。

  1. 经过、线程和模块

概括经过主程序(
exe)、模块、动态链接库(dll)的编辑;线程的基本概念,线程创制、遍历、同步等操作;进程与权力;线程与纤程等内容。

  1. 设备 I/O、驱动程序控制

包括设备对象等基本概念。加载与卸载驱动程序,控制驱动程序,与驱动程序通信等。

  1. 调节与错误处理

席卷怎么样开发调试器,程序运行错误的处理,日志的记录、Windows
可执行文件的结构等。

  1. Windows 系统信息

席卷注册表的操作,如打开注册表,读取、写入键值,成立、删除键;还包括系统中央音信的拿到和装置,如系统目录、系统版本、总结机名等。

  1. 过程间通信

概括选取共享文件举办过程间通信的模式,使用信息举行过程间通信的法子,使用邮槽、管道等展开过程间通信的办法,使用网络共享举办过程间通信的点子。

  1. 定时器与音讯机制

音信机制是 Windows 系统中很重点的一种机制。几乎拥有的 Windows
应用程序都在与音讯打交道,而 Windows
的音信机制又是依靠于定时器的。所以通晓 Windows 信息机制是上学Windows
应用程序开发的关键内容。

  1. 其他

Windows
的体系中央服务还包括性能监视、电源管理、索引与数据存储等,也将在本书中兼有关联。

  1. 实例 2-2 将系统目录消息写入 systemroot.txt

本实例使用了 Windows 系统中央服务中的部分
API,实现将系统目录路径写入文件中。在此间不对实现原理做过多的诠释,只是使读者对
Windows 系统服务 API 有起首的询问。

/* ************************************
*《精通 Windows API》 
* 示例代码
* basic.c
* 2.2 Windows API 的功能分类
**************************************/
/* 头文件  */
#include <windows.h>
/* ************************************
* 功能  获取系统目录信息,并存储到文件中
**************************************/
int main(int argc, TCHAR argv[])
{
//文件句柄
HANDLE hFile;
DWORD dwWritten;
//字符数组,用于存储系统目录
TCHAR szSystemDir[MAX_PATH];
//获取系统目录
GetSystemDirectory(szSystemDir,MAX_PATH);
//创建文件 systemroot.txt
hFile = CreateFile("systemroot.txt",
GENERIC_WRITE,
0,NULL,CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
//判断文件是否创建成功
if(hFile != INVALID_HANDLE_VALUE)
{
//将系统目录系统信息写入文件
if(!WriteFile(hFile,szSystemDir,lstrlen(szSystemDir),&dwWritten,NULL))
{
return GetLastError();
}
}
//关闭文件,返回。
CloseHandle(hFile);
return 0;
}

 

运转程序,在先后所在的目录会生成文书“systemroot.txt”,文件内容为系统目录。

#define MB_ICONHAND                 0x00000010L           
//一个红X的失实/截至图标
#define MB_ICONQUESTION             0x00000020L           
//一个问号的领会图标
#define MB_ICONEXCLAMATION          0x00000030L           
//一个肉色惊叹号的告诫图标
#define MB_ICONASTERISK             0x00000040L           
//一个带有i的音信指示图标

当然可以状态是假如编写统一的应用程序,在编译时想编译成ANSI就编译成ANSI版本,想编译成Unicode版本就编译成Unicode版本是最好的,这样我们写出来的主次不管是移植性仍旧通用性都最好,其实那么些微软早就想开了。

2.2.2    系统管理

系统管理是 Windows 系统中很首要的内容。Windows 系统提供了以下地点的 API
供应用程序开发人员使用,包括:管理控制台接口、程序安装、系统恢复生机、任务调度、Windows
运程管理。

并且, 在这一个图标中部分仍可以够用其他名目代替,
这么些别名在WINUSER.H的概念如下:

微软本着业内C函数构造了一套平台相关的字符串处理宏定义,所谓平台相关就是说这些宏是微软温馨定义的,只是在Windows平台下使用,不是标准里面的东西。这么些概念在不同的景色下会变成不同的本子。即便定义了“_UNICODE”那些宏定义,Windows将在拍卖C/C++函数是拔取Unicode版本,否则就是ANSI版本。下面我们以strlen那个函数来看一下Windows是怎么定义的:

2.2.3    用户界面

用户界面开发是 Windows 应用程序开发的第一内容。Windows
用户界面重要不外乎六个部分,Windows Shell 和 Windows 图形用户界面。Windows
图形用户界面包括窗口对象的相干内容,界面资源,控件、用户数据交流(粘贴板等)和用户输入的处理。

  1. 窗口化

包括一些主导数据概念和目标:窗口类、消息对列、窗口过程(消息处理函数)、窗口属性等。
紧要包括的 API
有窗口类注册的函数、窗口建立与关闭函数、窗口属性修改函数等。

  1. 资源

资源是 Windows
应用程序中很要紧的一项内容,在可执行文件中,专门有用于存储资源的节。
这里所说的资源是界面资源,包括图标、菜单、字符串、版本音信、对话框、动态光标、插入号(Carets)等。资源的拍卖涉及许多
API 函数。

  1. 用户输入处理

席卷对话框、键盘加速器(急迅键)、键盘输入、鼠标输入、原始数据输入等。这么些概念是先后通过用户界面与用户展开交互的基本概念。

  1. 数据交换

席卷 Atom
表(包括了好多字符串和标识符)、粘贴板、数据复制、动态数据交接等基本概念,是用户和应用程序通过用户界面举办数据互换的机要载体。

  1. Windows 图形界面通用控件

Windows 系统提供了不少于 30 种的控件供应用程序接纳,其中最常用的二种包括
Edit控件(文本框)、Button 控件(按钮)、ListView 控件(列表)、ToolTip
控件(指示框)、ComboBox 控件(下拉采纳框)、Tree-View
控件(树)、Rich-Edit 控件(多效益文本框)、Tab 控件(分页)、Process
控件(进度条)等。

  1. Windows Shell

Windows 桌面浏览器(explorer.exe)的效率强大,Windows Shell
应用程序可以使用WindowsShell
桌面的程序接口达到管理序列、定制图标和默认程序、扩充桌面功用等目的。

  1. 实例 2-3 窗口创立以及信息处理 basic.c

    / **《精通 Windows API》

    • 演示代码
    • window.cpp
    • 2.2 Windows API 的效劳分类
      **/
      / 预处理 /
      / 头文件 /
      #include
      / 全局变量 /
      HINSTANCE hinst;
      / 函数扬言 /
      int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int);
      LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
      /* **
    • 职能 突显一个窗口
      **/
      int WINAPI WinMain(HINSTANCE hinstance,
      HINSTANCE hPrevInstance,
      LPSTR lpCmdLine,
      int nCmdShow)
      {
      WNDCLASSEX wcx; // 窗口类
      HWND hwnd; // 窗口句柄
      MSG msg; // 音信BOOL fGotMessage; // 是否中标博得音讯hinst = hinstance; // 应用程序实例句柄,保存为全局变量
      // 填充窗口类的数据结构
      wcx.cbSize = sizeof(wcx); // 结构体的大小
      wcx.style = CS_HREDRAW |
      CS_VREDRAW; // 样式:大小改变时重绘界面
      wcx.lpfnWndProc = MainWndProc; // 窗口信息处理函数
      wcx.cbClsExtra = 0; // 不应用类内存
      wcx.cbWndExtra = 0; // 不利用窗口内存
      wcx.hInstance = hinstance; // 所属的应用程序实例句柄
      wcx.hIcon = LoadIcon(NULL,
      IDI_APPLICATION); // 图标:默认
      wcx.hCursor = LoadCursor(NULL,
      IDC_ARROW); // 光标:默认
      wcx.hbrBackground = (HBRUSH)GetStockObject(
      WHITE_BRUSH); // 背景:白色
      wcx.lpszMenuName = NULL; // 菜单:不采用wcx.lpszClassName = “MainWClass”; // 窗口类名
      wcx.hIconSm = (HICON)LoadImage(hinstance, // 小图标
      MAKEINTRESOURCE(5),
      IMAGE_ICON,
      GetSystemMetrics(SM_CXSMICON),
      GetSystemMetrics(SM_CYSMICON),
      LR_DEFAULTCOLOR);
      // 注册窗口类
      if(!RegisterClassEx(&wcx))
      {
      return 1;
      }
      // 成立窗口
      hwnd = CreateWindow(
      “MainWClass”, // 窗口名
      “CH 2-3”, // 窗口标题
      WS_OVERLAPPEDWINDOW, // 窗口样式
      CW_USEDEFAULT, // 水平地点 X:默认
      CW_USEDEFAULT, // 垂直地点 Y:默认
      CW_USEDEFAULT, // 宽度:默认
      CW_USEDEFAULT, // 低度:默认
      (HWND) NULL, // 父窗口:无
      (HMENU) NULL, // 菜单:使用窗口类的菜谱
      hinstance, // 应用程序实例句柄
      (LPVOID) NULL); // 窗口创造时数据:无
      if (!hwnd)
      {
      return 1;
      }
      // 展现窗口
      ShowWindow(hwnd, nCmdShow);
      UpdateWindow(hwnd);
      // 消息循环
      while (
      (fGotMessage = GetMessage(&msg, (HWND) NULL, 0, 0)) != 0
      && fGotMessage != -1)
      {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
      }
      return msg.wParam;
      }
      /* **
    • MainWndProc
    • 功能 窗口音信处理函数,
      对所有的信息都利用默认处理函数
      **/
      LRESULT CALLBACK MainWndProc(HWND hwnd,
      UINT uMsg,
      WPARAM wParam,
      LPARAM lParam
      )
      {
      switch (uMsg)
      {
      case WM_DESTROY:
      ExitThread(0);
      return 0;
      default:
      return DefWindowProc(hwnd, uMsg, wParam, lParam);
      }
      }

 

实例中,首先注册了窗口类,然后创造了一个窗口,成立窗口时指定的窗口的性能和窗口音讯的处理函数。函数信息的处理函数大多调用系统默认函数来处理。如下:

D:\002>cl window.cpp user32.lib gdi32.lib
用于 80x86 的 Microsoft (R) 32 位 C/C++ 优化编译器 15.00.21022.08 版
版权所有(C) Microsoft Corporation。保留所有权利。
window.cpp
Microsoft (R) Incremental Linker Version 9.00.21022.08
Copyright (C) Microsoft Corporation. All rights reserved.
/out:window.exe
window.obj 
user32.lib
gdi32.lib

 

运行效果:

 美高梅手机版4858 8

#define MB_ICONWARNING              MB_ICONEXCLAMATION        
//警告
#define MB_ICONERROR                MB_ICONHAND               
//错误
#define MB_ICONINFORMATION          MB_ICONASTERISK           
//信息
#define MB_ICONSTOP                 MB_ICONHAND               
//停止

#ifdef _UNICODE
#define _tcslen    wcslen
#else
#define _tcslen    strlen
#endif

2.2.4    图像和多媒体

Windows 的图像引擎和多媒体编程有多种接口,包括最基本的
GDI、GDI+,以及更尖端的OpenGL、DirectX 等图像引擎编程接口。DirectX 和
OpenGL
在娱乐支付、动画制作等地点采用相比较广泛,使用它们进行应用程序开发需要特其余SDK。本书只讲解 GDI,对一般的应用程序开发,已经足足使用。

GDI
的基本概念包括图像(Image)、位图(Bitmaps)、笔(Pen)、画刷(Brush)、文本和字体(
Text and
Fonts)、线(Line)、区域(Regions)、形状(Shapes)等。其主导的效果是对呈现设备开展支配、获取和修改相关安排,在处理器屏幕上出示用户所需要呈现的情节。

 

 

2.2.5    网络

用户采取 Windows API 可以付出基于各类网络协议的应用程序,例如 TCP\UDP
Socket、HTTP、DHCP、RPC、QOS、蓝牙,以及写真、点对点文件传输、即插即用设备管理等。
还能举办网络管理,包括网络的骨干信息,使用 IP helper
获取网络部署和网络音信、举办网络监视等。
同时微软还提供了拓展网络安全编程的片段接口,重假如防火墙 Windows、防火墙
API,以及一些 Windows 自带的网络应用程序的接口,包括 IE、Outlook 等。


这里的_tcslen就是特别平台相关的求字符串的字符长度的宏定义,当然我们在运用的时候把她当做函数就行了,可以见到倘若定义了_UNICODE,那么_tcslen在编译时实际是链接的wcslen,否则链接strlen。现在大家打开VS上面的头文件“tchar.h”,就足以看出众多之下划线初始的宏定义,这一个都是阳台相关的通用字符串处理库函数:

2.2.6    其他职能

Windows API
能实现的职能还有众多,限于篇幅不可能一切介绍。有局部情节本书未涉及,不过Windows API 也提供了有关接口。

  1. 数量存储和走访、数据库

席卷微软的“动态数据存取组件”技术(MDAC,包含了 ADO、ODBC)、OLE
数据库、XML 标准、微软 XML、可扩充存在引擎等多地方内容。紧要是 Windows
系统内的数据库文件、Windows.系统对数据库的造访接口等技术。

2.音讯与合作

信息与合作大多是 Windows
系统自带的部分应用程序所提供的开支接口。其中最要紧的始末是“协作数据对象”(
CDO)。CDO 包括了多少种 Windows 数据传输典型应用,包括 Mssager
(MSN)、邮件 SMTP (Outlook)应用接口等。

3.Web 开发

IIS(Intemet Information
Server,互联网信息服务)等应用程序提供的开支接口,使用户可以一向在
Windows 平台上展开 Web 开发,开发的程序运行于 ns
框架下。“数据存在与走访”、“音信与协作”、“Web 开发”等都足以归为 COM
开发的限量内。COM 是 Windows
应用程序接口的一种,具有原则性的接口情势,大多是 Windows
系统中自带的应用程序所提供的开销接口的聚集。

美高梅手机版4858 9

2.3    Windows API核心DLL

在 Windows 的系统目录中,存在着诸多的动态链接库文件(DLL 文件)。这些 DLL
文件中 包括了 Windows API 函数可执行程序。DLL
将各函数“导出”,这样应用程序就足以找到 DLL中的函数地址,当应用程序调用
Windows API 时,程序会运作到 DLL 中。API
函数根本存在于几个要旨的动态连接库文件中。Keme132.dll 是最要紧的
DLL,Windows 系统最要害的系统服务 API 函数都存在于 Kerne132.dll
中。User32.dll 紧要包括图形用户界面中所使用到的片段函数接口。 GDI32.dll
中,紧要不外乎 Windows 图形引擎中的接口函数。

当用户调用一个 API 时,系统会透过程序文件中的导入表结构找到需要调用的
API 函数位于哪个 DLL,确定函数的地方,以便应用程序可以成功调用 API
函数。

就此接纳这么些函数的时候要包含这多少个头文件。

2.3.1    Kerne132.dll

Keme132.dll 包括了系统中央服务中最核心的 API
函数,如文件系统、进程与线程、内存管理等。 Windows XPSP2
系统中,Keme132.d11 有 949
个导出函数,例如,CreateFileA、CreateProcessA、OpenThread、SetFile提姆(Tim)e
等。本书将在延续章节中通过实例介绍那一个 API的利用。

除此以外,假使定义了“UNCODE”这个宏,Windows的API也会动用Unicode版本,否则拔取ANSI版本。比如CreateWindow这些函数定义如下:

2.3.2    User32.dll

User32.dll 是 Windows
图形用户界面的要害补助。一些重点的图形用户界面函数由User32.dll
函数导出。Windows XP SP2 系统中,User32.dll 有 732
个导出函数,例如CreateWindowExW、RegisterClassA 等。

#ifdef UNICODE
#define CreateWindow  CreateWindowW
#else
#define CreateWindow  CreateWindowA
#endif // !UNICODE

2.3.3    Gdi32.dll

Gd132.dll 是 Windows GDI 应用程序设计接口,Gdi32.dll
导出了与此相关的好多函数,如 GetTextColor、LineTo、TextOutA 等。

 

2.3.4    标准C函数

规范 C 程序是一种标准,任何匡助 C 语言应用程序开发的系统都应当提供 C
语言库函数的 调用。在系统环境下利用正式 C
实行程序支付时,用户所接纳的库函数实际上是由操作系统提供的。正是由于各种主流操作系统都提供了一套标准
C 库所定义的函数接口,标准 C
函数库才会有这样大规模的逾越操作系统平台。所以 C
程序仍然借助于操作系统开发人士为其实现接口,而 C
库函数的兑现依然凭借于操作系统提供的调用接口,如正式 C 函数 fopen
函数在Windows 系统中的实现就凭借于 API CreateFile 函数(CreateFile
实现了文件的创办和开辟等操作)。

Windows 系统的 C 标准库函数接口首要存在于crtdll.dll 中。实际上,C
标准函数库必须由操作系统为其提供接口,否则使用专业 C
开发的次序不可能在一定的体系上运行。 Windows XP SP2 系统中,crtdll.dll 有
526 个导出函数,如 fopen、printf. strlen等。

于是其实CreateWindow是一个宏定义而已,可是这不影响我们把它当作函数来使用,同样其他包含字符串作为参数的Windows
API也一律做了概念。

2.3.5    其他Dll

自然,Windows 系统中的 DLL 文件远远不止那些,Windows
系统提供了卓殊充足而且效能强大的 API,上文已经介绍了 Windows API
所首要倚重的几个 DLL,其他的 DLL
库文件由于过度庞杂,就不一一介绍,将在此起彼伏的章节中享有涉及。读者只需要精晓调用
Windows API 的基本原理就能够了。

默认情状下,我们选择VS来确立工程,_UNICODE和UNICODE这多少个宏都是打开的,所以我们用携带创制的工程都是Unicode版本的,我们也得以从布局选项里面删除这多少个概念来编译ANSI版本的主次。

2.4    Unicode和多字节

Windows 既可以采纳 Unicode
字符集又可以选拔传统的字符集(如多字节编码)来促成对多种语言的支撑,以适应国际市场的要求。与传统的字符集编码比较,Unicode
是社会风气通用的字符编码标准,使用 16 位数据表示一个字符,一共可以代表 65535
种字符,可以概括现代总计机中所使用的装有字符,包括各类字母、文字、在出版业中采取的特殊符号等。
传统的字符集,如 Windows ASNI 字符集,使用 8 位数据或将紧邻的六个 8
位的数量整合在一齐表示卓殊的言语字符。Windows 系统接纳了 ASNI
字符的扩大模式,假设一个字节是负数,则将其继承的一个字节组合在同步表示一个字符。这种编码格局的字符集也号称“多字节”字符集。

在 Windows 系统中,Unicode 字符编码和多字节字符编码都足以拔取。

  1. 实例 2-4 Unicode 与多字节编码演示

    / **《精通 Windows API》

    • 演示代码
    • StringCode.c
    • 2.4 Unicode 和多字节
      **/
      / 预处理 /
      / 头文件 /
      #include
      /* **
    • 意义 Unicode 与多字节编码演示
      **/
      int WINAPI WinMain(
      HINSTANCE hInstance,
      HINSTANCE hPrevInstance,
      LPSTR lpCmdLine,
      int nCmdShow
      )
      {
      //定义 LPWSTR 类型的宽字符串
      LPWSTR szUnicode = L”This is a Unicode String;”;
      //定义 LPSTR 类型的窄字符串
      LPSTR szMutliByte = “This is not a Unicode String;”;
      //定义 LPTSTR 类型的自适就字符串
      LPTSTR szString = TEXT(“This string is Unicode or not depends on the option.”);
      //使用 W 版本的 API 函数,以宽字符串为参数。
      MessageBoxW(NULL,szUnicode,L”<字符编码 1>“,MB_OK);
      //使用 A 版本的 API 函数,以窄字符串为参数。
      MessageBoxA(NULL,szMutliByte,”<字符编码 2>“,MB_OK);
      //使用自适用的 API 函数,采取相适应的字符串类型为参数。
      MessageBox(NULL,szString,TEXT(“<字符编码 3>“),MB_OK);
      return 0;
      }

 

在本实例中,一共动用了 3
序列型的字符串变量,每系列型的字符串变量的起始化是见仁见智的,如表 2.2
所示。

表2.2 字符串与初叶化

类型

变量类型

初始化形式

Unicode

LPWSTR

L”string”

多字节

LPSTR

”string”

根据开发环境的设置自动适应

LPTSTR

TEXT(”string”)

本实例首先应用“多字节”情势开展编译。可以利用二进制编辑器来查阅编译得到的可执行文件,上例中定义的字符串分别存储为以下形式。使用二进制编辑器查看,可以从
exe可执行文件中找到如下新闻。读者可以相比 ASCII 编码表查看。

“This is a Unicode String;”使用 Unicode 情势的十六进制编码:

54 00 68 00 69 00 73 00 20 00 69 00 73 00 20 00 61 00 20 00 55 00 6e 00 69 00 63 00 6f 00 64 00 65 00 20 00 53 00 74 00 72 00 69 00 6e 00 67 00 3b 00

 

 美高梅手机版4858 10

“This is not a Unicode String;”使用 ASCII 模式的十六进制编码:

54 68 69 73 20 69 73 20 61 20 55 6e 69 63 6f 64 65 20 53 74 72 69 6e 67 3b

 

 美高梅手机版4858 11

“This string is Unicode or not depends on the option.”的ASCII
情势的十六进制编码:

54 68 69 73 20 73 74 72 69 6e 67 20 69 73 20 55 6e 69 63 6f 64 65 20 6f 72 20 6e 6f 74 20 64 65 70 65 6e 64 73 20 6f 6e 20 74 68 65 20 6f 70 74 69 6f 6e 2e

 

之后是“<字符编码 1>”和 Unicode 编码、“<字符编码
2>”和“<字符编码
3>”的多字节编码。对汉字字符,二种编码的不二法门是例外的,如“字符编码”多少个字,三种编码分别为:

Unicode编码

57 5b 26 7b 16 7f 01 78

 

 美高梅手机版4858 12

和多字节ASCII

d7 d6 b7 fb b1 e0 c2 eb

 

 美高梅手机版4858 13

读者可以分析设置使用 Unicode
字符集后编译完成的可执行文件与安装为多字节字符集后编译得到的可执行文件有什么不同。

 

  1. 在工程安排中采用编码格局

安装的法子是在Visual
Studio工程属性中甄选“配置属性”→“常规”→“字符集”选项中展开抉择。

近日函数的应用解决了,那么怎么着来定义字符以及字符串的变量类型已日常量,使得_UNICODE和UNICODE定义也能影响项目和常量呢?微软如出一辙运用了一层层的概念来缓解那一个题材。TCHAR是当做字符、字符串的变量类型,等价于char和wchar_t,假诺定义了UNICDOE,TCHAR实际上是wchar_t,否则就是char,这么些在winnt.h中能找到。

2.4.1    W版本和A版本的API

Windows 辅助 Unicode 和 ASCII 编码的字符。Windows 系统 API
凡是以字符串作为参数的无数怀有 W 和 A
五个版本以落实二种不同编码的字符处理。

下面以 MessageBox 为例介绍二种不同版本 API 函数的使用。在 User32.dll
中导出的函数实际上并未 MessageBox,唯有 MessageBoxA 和
MessageBoxW,这二者是同一个 API,实现了平等的效用。不同的是,MessageBoxA
以多字节字符串作为参数输入,MessateBoxW 以Unicode 字符串作为参数输入。

可以从 User32.dll 的导出函数看到多少个不等版本的 API 函数。在 Platform SDK
中,MessageBox 函数扬言所在的头文件中窥见如下概念(以下代码来自于
Microsoft Platform SDK):

WINUSERAPI
int
WINAPI
MessageBoxA(
__in_opt HWND hWnd,
__in_opt LPCSTR lpText,
__in_opt LPCSTR lpCaption,
__in UINT uType);
WINUSERAPI
int
WINAPI
MessageBoxW(
__in_opt HWND hWnd,
__in_opt LPCWSTR lpText,
__in_opt LPCWSTR lpCaption,
__in UINT uType);
#ifdef UNICODE
#define MessageBox MessageBoxW
#else 
#define MessageBox MessageBoxA
#endif // !UNICODE

 

可以见见,在程序开展编译和连续时,假设程序在 UNICODE 环境下,会使用
MessageBoxW,否则使用 MessageBoxA。

软件开发人员可以自行设定使用 Unicode
编码或都多字节编码文件,不影响程序的正常功用。

但一旦在编写程序时,使用的字符集与代码中应用的函数不雷同、定义的字符串变量不配合,将会引起编译错误或者运行程序显示乱码,甚至可能引起程序运行错误,这或多或少急需引起注意。

对字符串常量,VS定义了TEXT、__TEXT,在tchar.h中,还定义了_T等一些种方法,只要定义了UNICODE,则这多少个宏定义就是Unicode,否则即便ANSI版本。由此大家今后在编写程序时,应该充足用这么些宏来定义字符串类型变量,常量以及处理函数。下边是一个推荐的粗略实例:

2.4.2    Unicode与ASGII的转换

Windows 专门提供了若干个 API
来落实对字符编码的变换工作。ideCharToMultiByte、MultiByteToWideChar、UnicodeToBytes
函数可以形成这多少个工作。

WideCharToMultiByte 函数将 Unicode 字符串转换为多字节字符串,以适应 A
版本的API,MultiByteToWideChar 函数将多字节字符串转换为了 Unicode
字符串,以适应 W 版本的 API 的参数情势要求。

#include <windows.h>
#include <tchar.h>

int _tmain(void)
{
    TCHAR c = TEXT('A');
    TCHAR buf[16];
    TCHAR *str = TEXT("hello, world!");

    _tprintf(TEXT("1 --> %c\n"), c);
    _tprintf(TEXT("2 --> %s\n"), str);

    _tscanf(_T("%s"), buf);
    _tprintf(_T("%s\n"), buf);

    _tsystem(TEXT("pause"));

    return 0;
}

2.4.3    对Windows程序设计规范的建议

每个程序员都有友好的规范化编程习惯。代码的业内不是本书的要害,所以这边只交给一些微软平时使用代码规范,MSDN
的以身作则中,SDK 的头文件和例子中几乎都是行使的这种措施。

变量名:通常拔取所谓的“匈牙利命名法”,变量名由“类型缩写(小写)”+“变量描述(单词首字母大写)”构成,如字符串类型的变量可以命名为
szFileName,DWORD 类型的数量足以命名为 dwFileSize,指针类型可以命名为
lpBuffer,句柄类型的变量可以命名为 hLogFile 等。

函数名:各单词的首字母大写,如 EnumerateFilesInDrectory、ShowFileSize
等。

项目名:全大写,各单词以下划线分隔,如 WIN32_FILE_
ATTRIBUTE_DATA、DWORD、 HANDLE 等。

常量:同类型名的命名格局。

宏:多与项目名命名情势相同,有的也与函数名命名格局一样。
大括号与代码段:一般大括号独立占一行,大括号内的代码段缩进。假如代码段仅一行(如
if-else 后的说话),也提出使用大括号。

在调用或概念函数时,假使函数太长,可以分行写,将各种参数写一行。一般多于
3个参数的函数需要分行写,以漂亮和方便阅读为尺度。

在本书的以身作则中,都将尽量采取这些规范化的章程。

 

 

2.5    小结

PDF下载:

摘自:《了解Windows.API-函数、接口、编程实例》 人民邮电出版社

范文庆、周彬彬、安靖写作

 

在这一个实例中,所有可能用到字符串的函数都利用通用的函数,能正确的编译Unicode版本和ANSI版本。

  • Unicode和ANSI字符串转换

偶然我们兴许如故会面世不同编码之间的转移,那是我们可以使用Windows提供的API来完成。

MultiByteToWideChar函数和WideCharToMultiByte函数,这多少个函数可以在ANSI和Unicode字符串之间往来转换。他们的参数有广大相似之处,原型为:

int MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar);
int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar);

 

切切实实用法可以参照MSDN,网上也能找到大量的应用验证和实例,这里就不再叙述。

下边给一个实例来演示ANSI和Unicode之间的变换:

#include <windows.h>
#include <tchar.h>
#include <stdio.h>

int _tmain(void)
{
    int nwCh;
    char AnsiStr[] = "hello, world!";
    wchar_t wszBuf[20] = {0};

    //获得转换后产生多少Unicode字符,可以作为后面实际转换时传入容纳转换结果的Unicode字符数buffer大小
    nwCh = MultiByteToWideChar(CP_ACP, 0, AnsiStr, -1, NULL, 0);
    //转换并接收结果
    MultiByteToWideChar(CP_ACP, 0, AnsiStr, -1, wszBuf, nwCh);
    wprintf(L"nwCh = %d, %s\n", nwCh, wszBuf);

    int nCh;
    char AnsiBuf[20] = {0};
    //获得转换后产生多少ANSI字符,可以作为后面实际转换时传入容纳转换结果的ANSI字符数buffer大小
    nCh = WideCharToMultiByte(CP_ACP, 0, wszBuf, -1, NULL, 0, NULL, NULL);
    //转换并接收结果
    WideCharToMultiByte(CP_ACP, 0, wszBuf, -1, AnsiBuf, nCh, NULL, NULL);
    printf("nCh = %d, %s\n", nCh, AnsiBuf);

    _tsystem(TEXT("pause"));

    return 0;
}

请留心注释部分,该函数及可以变换,也能取得转后所需出口的积存字符个数空间的尺寸。运行后的输出结果:

美高梅手机版4858 14

到这里本文就终止了,下一篇将延续大家的Windows编程连串之旅。敬请关注!

 

关爱微信公众平台:程序员互动联盟(coder_online),你可以第一时间获取原创技术随笔,和(java/C/C++/Android/Windows/Linux)技术大牛做情人,在线交换编程经验,获取编程基础知识,解决编程问题。程序员互动联盟,开发人士自己的家。

美高梅手机版4858 15

转载请阐明出处,谢谢合作!

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有