Windows编程.docx
- 文档编号:25985580
- 上传时间:2023-06-17
- 格式:DOCX
- 页数:106
- 大小:656.79KB
Windows编程.docx
《Windows编程.docx》由会员分享,可在线阅读,更多相关《Windows编程.docx(106页珍藏版)》请在冰豆网上搜索。
Windows编程
Windows编程
学习C语言很久了,是不是一直在跟黑乎乎的屏幕打交道,像QQ、360、VC6.0这样的软件都是带界面的,怎么做到的呢?
前面我们讲的”黑屏“叫控制台应用程序(Win32ConsoleApplication),也称DOS程序(或MS-DOS程序)。
DOS是早期的命令式操作系统,很难做出漂亮的界面,除了开发人员,”黑屏“对普通用户很不友好。
带界面的程序叫Windows应用程序(Win32Application)。
Windows是一款现代操作系统,带有丰富的交互界面,使用简单,无需记忆繁杂的命令。
使用C语言可以开发出Windows应用程序,也就是带界面的程序,只是绝大部分C语言教程没有讲,它们只讲了基本语法,让很多初学者认为学C语言没用,什么都做不出来。
其实不是这样的,C语言只是一种工具,需要与Windows系统结合,借助Windows提供的函数才能开发出漂亮的程序。
这套教程,将以简单明了的方式教你使用C语言来编写带界面的Windows应用程序。
WindowsAPI编程、Windows编程、WindowsSDK编程是一个概念,阅读完教程第一节你就会明白。
WindowsAPI的概念
在C语言中,使用fopen()函数可以打开一个文件,感觉非常简单。
文件保存在硬盘上,要经过复杂的处理才能显示,这些细节对我们来说是透明的,由操作系统完成。
也就是说,我们调用fopen()函数来通知操作系统,让操作系统打开一个文件。
那么,我们如何告诉操作系统打开文件呢?
看似简单的操作到底层都非常复杂,打开文件首先要扫描硬盘,找到文件的位置,然后从文件中读取一部分数据,将数据放进I/O缓冲区,放进内存;这些数据都是0、1序列,还要对照ASCII表或Unicode表”翻译“成字符,再在显示器上显示出来。
这个过程如果要让程序员来完成,那简直是噩梦!
怎么办呢?
Windows想了一个很好的办法,它预先把这些复杂的操作写在一个函数里面,编译成动态链接库(DLL),随Windows一起发布,程序员只需要简单地调用这些函数就可以完成复杂的工作,让编程变得简单有趣。
这些封装好的函数,叫做API(ApplicationProgrammingInterface),即应用程序编程接口。
API函数以C语言的形式向外暴露,可以通过C语言直接调用。
除了函数,Windows还预先定义了很多数据类型(使用C语言的typedef关键字定义)。
广义上来说,这些数据类型也是API的一部分。
API屏蔽了很多细节,大大简化了程序员的工作,这就是操作系统的威力,不但让普通用户使用方便,也让程序员如释重负。
在Windows上运行的程序(包括MS-DOS程序),本质上都是通过调用WindowsAPI来完成功能的,包括QQ、360、VC6.0等,别看这些团队牛,也不可能从底层做起,那简直不可想象。
C语言也一样,也是调用WindowsAPI,fopen()函数就是通过调用CreateFile()函数实现的。
CreateFile()是WindowsAPI中的一个函数,可以用来打开或创建文件。
通常所说的SDK编程就是直接调用API函数进行编程。
SDK是SoftwareDevelopmentKit的缩写,即软件开发工具包。
WindowsAPI函数成千上万,详细了解每一个函数的用法是不可能的,也是完全没有必要的。
只需知道哪些功能由哪些API函数提供就行了,等使用它们时再去查阅帮助文件。
带界面的程序的专业称呼是GUI程序。
GUI是GraphicalUserInterface的简写,即图形用户界面。
本教程将教你使用WindowsAPI来编写GUI程序,编程语言为C语言。
第一个真正的Windows程序
编写Windows程序,首先要包含windows.h头文件。
windows.h还包含了其他一些Windows头文件,例如:
∙windef.h:
基本类型定义
∙winbase.h:
内核函数
∙wingdi.h:
用户接口函数
∙winuser.h:
图形设备接口函数
这些头文件定义了Windows的所有数据类型、函数原型、数据结构和符号常量,也就是说,所有的WindowsAPI都在这些头文件中声明。
在C语言中,程序都是“黑屏”的,称为控制台程序(ConsoleApplication)。
这套教程要讲的是带界面的Windows程序(WindowsApplication),也称为GUI程序(GUIApplication)。
控制台程序以main()为入口函数,Windows程序以 WinMain()为入口函数,动态链接库(DLL)以 DllMain()为入口函数(请查看 动态链接库DLL教程),不同的入口函数决定了不同类型的程序。
WinMain()函数的原型为:
1.intWINAPIWinMain(
2.HINSTANCEhInstance,//当前窗口句柄
3.HINSTANCEhPrevInstance,//前一个窗口句柄,Win32下为NULL(Win16留下的废物,目前已弃用)
4.LPSTRlpCmdLine,//命令行参数
5.intnCmdShow//窗口显示方式
6.);
先不要急于理解这些参数的含义,我先给大家写一个简单的不带黑屏的、真正的Windows程序:
1.#include
2.
3.intWINAPIWinMain(
4.HINSTANCEhInstance,
5.HINSTANCEhPrevInstance,
6.LPSTRlpCmdLine,
7.intnCmdShow
8.){
9.//调用API函数MessageBox
10.intnSelect=MessageBox(NULL,TEXT("你好,欢迎来到C语言中文网!
"),TEXT("Welcome"),MB_OKCANCEL);
11.if(nSelect==IDOK){
12.MessageBox(NULL,TEXT("你点击了“确定”按钮"),TEXT("提示"),MB_OK);
13.}else{
14.MessageBox(NULL,TEXT("你点击了“取消”按钮"),TEXT("提示"),MB_OK);
15.}
16.
17.return0;
18.}
编译并运行,会弹出一个对话框,如下所示:
点击“确定”或“取消”按钮,又会弹出一个新的提示框。
大家可以亲自运行一下,会有真实的体验。
原来没有main()函数,没有#include
MessageBox()函数是众多API中的一个,用于弹出一个指定风格的对话框,其原型为:
intWINAPIMessageBox(HWNDhWnd,LPCTSTRlpText,LPCTSTRlpCaption,UINTuType);
WINAPI为宏定义#define WINAPI __stdcall,表示函数调用方式,暂时可以不理会,不影响代码编写,只需要知道MessageBox()返回值为int,表示按下的按钮。
有兴趣的读者可以查看:
__stdcall,__cdecl,__pascal,__fastcall的区别
参数说明:
∙hWnd:
该消息框的父窗口句柄,如果此参数为NULL,则该消息框没有拥有父窗口。
大家不用急于理解这个参数,后续会详细讲解。
∙lpText:
消息框的内容。
LPCTSTR是自定义数据类型,等价于constchar*。
∙lpCaption:
消息框的标题。
∙uType:
对话框的按钮样式和图标。
uType支持的按钮样式:
按钮
含义
MB_OK
默认值,有一个“确认”按钮在里面
MB_YESNO
有“是”和“否”两个按钮在里面
MB_ABORTRETRYIGNORE
有“中止”,“重试”和“跳过”三个按钮在里面
MB_YESNOCANCEL
有“是”,“否”和“取消”三个按钮在里面
MB_RETRYCANCEL
有“重试”和“取消”两个按钮在里面
MB_OKCANCEL
有“确定”和“取消”两个按钮在里面
这些按钮都是宏定义:
1.#defineMB_OK0x00000000L
2.#defineMB_OKCANCEL0x00000001L
3.#defineMB_ABORTRETRYIGNORE0x00000002L
4.#defineMB_YESNOCANCEL0x00000003L
5.#defineMB_YESNO0x00000004L
6.#defineMB_RETRYCANCEL0x00000005L
你也可以尝试用数字来表示按钮,例如:
MessageBox(NULL,TEXT("你好,欢迎来到C语言中文网!
"),TEXT("Welcome"),1);
也会生成与上面相同的对话框。
除了按钮,uType还支持图标(图标对用户有提醒作用):
图标
含义
MB_ICONEXCLAMATION
一个惊叹号出现在消息框:
MB_ICONWARNING
一个惊叹号出现在消息框(同上)
MB_ICONINFORMATION
一个圆圈中小写字母i组成的图标出现在消息框:
MB_ICONASTERISK
一个圆圈中小写字母i组成的图标出现在消息框(同上)
MB_ICONQUESTION
一个问题标记图标出现在消息框:
MB_ICONSTOP
一个停止消息图标出现在消息框:
MB_ICONERROR
一个停止消息图标出现在消息框(同上)
MB_ICONHAND
一个停止消息图标出现在消息框(同上)
这些图标也都是宏定义:
1.#defineMB_ICONHAND0x00000010L
2.#defineMB_ICONQUESTION0x00000020L
3.#defineMB_ICONEXCLAMATION0x00000030L
4.#defineMB_ICONASTERISK0x00000040L
如果希望同时定义按钮和图标的样式,可以使用或运算|,例如:
1.MessageBox(
2.NULL,
3.TEXT("你好,欢迎来到C语言中文网!
"),
4.TEXT("Welcome"),
5.MB_OKCANCEL|MB_ICONINFORMATION
6.);
会弹出如下的对话框:
与上面的对话框相比,多出了一个图标,同时还能听到提示音(Win7有,XP和Win8读者可以亲自测试)。
大家有没有发现,按钮都是用十六进制的第1位(二进制前4位)来表示,图标都是使用十六进制第2位(二进制第5~8位)来表示,进行或运算,每个位都不会改变,如下图所示:
Windows通过检测第1位的值来确定按钮的样式,检测第2位的值来确定图标样式。
再看来一下MessageBox()的返回值。
MessageBox()返回被按下的按钮,以数字表示,这些数字都被定义成了宏,如下所示:
返回值
含义
IDOK
用户按下了“确认”按钮
IDCANCEL
用户按下了“取消”按钮
IDABORT
用户按下了“中止”按钮
IDRETRY
用户按下了“重试”按钮
IDIGNORE
用户按下了“忽略”按钮
IDYES
用户按下了“是”按钮
IDNO
用户按下了“否”按钮
对应的宏定义为:
1.#defineIDOK1
2.#defineIDCANCEL2
3.#defineIDABORT3
4.#defineIDRETRY4
5.#defineIDIGNORE5
6.#defineIDYES6
7.#defineIDNO7
Windows数据类型
Windows使用typedef或#define定了很多新的数据类型,前面几节中我们已经领略到了。
它们虽然多,但是都有规律可循,很多都是对C/C++中数据类型的简单加工,而且很容易“见名知意”。
要想学习Windows编程,必须要了解常用的数据类型。
如果你对C语言或者C++的数据类型比较熟悉的话,那么对于一些基础的内容这个过程就是慢慢熟悉的过程。
这些数据类型在windows.h头文件中定义:
1.typedefintINT;/*整形*/
2.typedefunsignedintUINT;/*无符号整形*/
3.typedefunsignedint*PUINT;/*无符号整形指针*/
4.typedefintBOOL;/*布尔类型*/
5.typedefunsignedcharBYTE;/*字节*/
6.typedefunsignedshortWORD;/*WORD(无符号短整型)*/
7.typedefunsignedlongDWORD;/*DOUBLEWORD(无符号长整形)*/
8.typedeffloatFLOAT;/*浮点型*/
9.typedefFLOAT*PFLOAT;/*指向float类型指针*/
10.typedefBOOLnear*PBOOL;/*指向布尔类型指针*/
11.typedefBOOLfar*LPBOOL;
12.typedefBYTEnear*PBYTE;/*指向字节类型指针*/
13.typedefBYTEfar*LPBYTE;
14.typedefintnear*PINT;/*整形指针*/
15.typedefintfar*LPINT;
16.typedefWORDnear*PWORD;/*指向WORD类型的指针*/
17.typedefWORDfar*LPWORD;
18.typedeflongfar*LPLONG;/*指向长整形的指针*/
19.typedefDWORDnear*PDWORD;/*指向DWORD类型的指针*/
20.typedefDWORDfar*LPDWORD;
21.typedefvoidfar*LPVOID;/*指向void类型的指针*/
22.typedefCONSTvoidfar*LPCVOID;/*指向void类型的常指针*/
简单说下,大部分类型都没有什么离奇的地方,可能很多读者会对那个far和near觉得有疑问,实际上F12查看定义会发现他们就定义上方:
1.#definefar
2.#definenear
看到这里你是否还是有疑问?
其实,这个far和near只是用来标识变量的新旧的(预处理阶段far和near会被替换成空字符串)。
例如 PINT 和 LPINT 实际上都是 int*,只不过一个是老式写法,一个是新式写法,这都是为了兼容问题。
简单的看下这些数据类型,就可以总结出:
但凡是以“P”开头的都是指针(pointer)类型("LP"是老式写法)。
撇开这些不谈,那么实际上这些WindowsAPI常用的一些数据结构跟我们原本所学的C/C++变量差别就是一个 typedef 而已,基础好的熟悉一下就行了。
不过,也不要想得这么简单,Windows编程还有一些比较复杂的类型比如HWND、HANDLE等。
在碰到不熟悉的类型时请熟练的使用“右键转到定义”或者F12。
大家不用太过害怕这些复杂的类型名称,Windows数据类型并不是内建的数据类型类型,而都是从C类型重定义得到的。
Windows数据类型名命名的规律
∙无符号类型:
一般是以“U”开头,比如“INT”对应的“UINT”。
∙指针类型:
其指向的数据类型前加“LP”或“P”,比如指向DWORD的指针类型为“LPDWORD”和“PDWORD”。
∙句柄类型:
以“H”开头。
比如,HWND是window(WND简写)也就是窗口的句柄,菜单(MENU)类型对应的句柄类型为“HMENU”等等。
宽字符与Unicode
在C语言中,我们使用char来定义字符,占用一个字节,最多只能表示128个字符,也就是ASCII码中的字符。
计算机起源于美国,char可以表示所有的英文字符,在以英语为母语的国家完全没有问题。
但是世界上存在很多不同的语言,例如汉语、汉语、日语等有成千上万个字符,需要用多个字节来表示,称之为宽字符(WideCharacter)。
Unicode是宽字符编码的一种,已经被现代计算机指定为默认的编码方式,Windows2000以后的操作系统,包括Windows2000、XP、Vista、Win7、Win8、Win10、WindowsPhone、WindowsServer等(它们统称为WindowsNT)都从底层支持Unicode,存取效率比char要高。
更多内容请查看:
ASCII编码与Unicode编码
C语言中的宽字符
在C语言中,使用wchar.h头文件中的wchar_t来定义宽字符,例如:
wchar_tch='A';
wchar_t被定义为typedefunsignedshortwchar_t,和一个无符号整型一样,占用两个字节。
如果定义宽字符串,需要加前缀L,例如:
wchar_t*str=L"C语言中文网";
L是必须要加的,并且与字符串之间不能有空格,只有这样编译器才知道每个字符占用两个字节。
宽字符示例:
1.#include
2.#include
3.intmain(){
4.charch='A';
5.wchar_twch='A';
6.charstr[]="C语言中文网";
7.wchar_twstr[]=L"C语言中文网";
8.printf("ch=%d,wch=%d,str=%d,wstr=%d\n",sizeof(ch),sizeof(wch),sizeof(str),sizeof(wstr));
9.return0;
10.}
运行结果:
ch=1,wch=2,str=12,wstr=14
wstr之所以比str多两个字节是因为:
字符'C'占用两个字节,字符串结束标志'\0'也占用两个字节。
宽字符串的长度
计算ASCII字符串长度使用strlen函数,计算宽字符串长度使用wcslen函数:
1.#include
2.#include
3.#include
4.intmain(){
5.charstr[]="C语言中文网";
6.wchar_twstr[]=L"C语言中文网";
7.printf("strlen(str)=%d,wcslen(wstr)=%d\n",strlen(str),wcslen(wstr));
8.return0;
9.}
运行结果:
strlen(str)=11,wcslen(wstr)=6
strlen的运行结果显然不正确,因为它把一个字节作为一个字符计算,而wcslen把两个字节作为一个字符计算。
注意:
wcslen在string.h和wchar.h头文件中均有说明。
维护一个版本的源代码
在WindowsNT以前的操作系统中,甚至包括Windows98,对宽字符的支持都不是很好,所以大多情况下使用ASCII编码。
WindowsNT推出以后,已经从底层支持了Unicode,所以在WindowsNT上的程序大多使用Unicode。
如果你希望程序能够在各种版本的Windows操作系统中运行,那么就需要维护两个版本的源代码,ASCII版和Unicode版。
ASCII字符和Unicode字符的定义、使用都不一样,要想在一个版本的源代码中做兼容处理会非常困难,要做大量的工作,对程序员来说简直是噩梦。
不过,Windows又为我们做了一件好事,已经处理了兼容性问题。
它是怎么做到的呢?
例如对于字符串,ASCII中使用char来定义,而Unicode中使用wchar_t来定义,并且需要添加前缀L。
那么在windows.h头文件中(或者是它包含的其他头文件)就这样来处理:
1.#ifdefUNICODE
2.typedefwchar_tTCHAR;
3.#defineTEXT(quote)L##quote
4.#else
5.typedefcharTCHAR
6.#defineTEXT(quote)quote
7.#endif
我们在源码中可以这样来使用:
TCHARstr[]=TEXT("C语言中文网");
如果是Unicode版,也就是定义了UNICODE宏,那么上面的语句等价于:
wchar_tstr[]=L"C语言中文网";
如果是ASCII,也就是没有定义UNICODE宏,那么等价于:
charstr[]="C语言中文网";
在Windows中,随处可见这样的处理。
虽然现代操作系统都已经支持Unicode,无需再考虑与ASCII的兼容性问题,但是依然要为这些历史问题付出代价。
总结:
由于各种各样的原因,我们优先使用Windows定义的数据类型、宏、结构体等,这样编写的程序兼容性较好,不用考虑ASCII和Unicode的问题。
但这也带来了一个挑战,就是要熟悉Window定义的数据类型、宏、结构体等。
与windows编程有关的重要概念
窗口
窗口的概念很容易理解,就是我们使用软件时看到的界面。
Windows的核心就是窗口,它是Windows一统PC操作系统市场的杀手锏,如下图所示:
图1:
记事本程序
我们使用的软件都有自己的窗口,比如 QQ、计算器、记事本等。
这些窗口可以包含输入框、下拉菜单、单选按钮、多选按钮、文本区域等各种各样的控件(Controls),有的甚至还有动画!
窗口、控件、图像、音频视频等都称为资源(Resource),在程序中都可以使用、创建、添加、修改等。
句柄
在Windows编程中,不同窗口、控件、图像等都对应一个唯一的数字(初学者可以理解为ID),称为句柄(Handle)。
通过句柄,程序可以获取对应资源的各种信息,也可以使用、修改、删除该资源。
你可以将句柄理解为学号,你不需要记住学生的姓名、住址、成绩等各种信息,当你需要了解这名学生时,只要去教务处,将学号(句柄)告诉那里的工作人员(Windows),他就能够帮你找到这个学生。
句柄屏蔽了很多细节,程
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Windows 编程