第2个Wiindows程序讲解
上次,我们一起写了一个Windows窗口程序,这个窗口程序虽然非常简单,但是,代码仍然很多,相信,一定会有很多初学者看见这些代码而感到头疼。不用怕,现在,我们就一起来分析一下这些代码,相信通过我们共同的努力,一定可以克服这些难题。
首先,我们要做的第一件事情就是包含windows.h头文件,这个不再解释了,因为,我们前面已经解释过。
之后,我们定义了一个WinMain函数和一个窗口处理函数MainWndProc。
相信,很多人读到窗口处理函数,就一定会发晕,不知道它是一个什么东东,如果大家想要明白窗口处理函数,就必须先明白Windows下的消息机制,现在,我先简要介绍一下什么是消息机制,如果想要深入研究的人,可以看看《Windows核心编程》,windows的消息机制是借由消息系统来完成的。
Windows的消息系统是由3个部分组成的:
1)消息队列:Windows为所有的应用程序都维护一个消息队列,应用程序必须从消息队列中获取消息,然后分派给某个窗口处理函数处理。
2)消息泵:通过这个消息泵,应用程序可以从消息队列中获取消息,然后,再把它分派给适当的窗口,最终由该窗口的窗口处理函数来处理它。
3)窗口处理函数:每个窗口都有一个窗口处理函数,它的任务就是处理发给该窗口的消息,处理完消息后,它通常要返回一个值给Windows,告诉Windows该消息处理是否成功。
相信通过上面的了解,大家大概对消息机制会有一个整体的把握,下面,我将以一个键盘的按键消息为例,告诉大家这个消息是如何产生,流转,处理。
当我们按下键盘上的一个字符后,比如a,这个时候,键盘的硬件会检测到这个动作,然后通知系统,系统知道后,会为它产生一个消息:WM_CHAR,之后,系统会将这个消息发送到当前程序的消息队列,比如当前程序是记事本,那么这个时候,记事本程序的消息队列中会出现一个WM_CHAR消息,当记事本程序的消息泵从消息队列提取到这个字符的按键消息后,会调用当前窗口的处理函数来处理这个字符消息,当窗口处理函数处理WM_CHAR时,会在屏幕上显示这个字符,我们这里,这个字符是a,这就是整个消息处理的全过程。
好了,现在,我们言归正传,继续分析接下来的程序。WinMain程序,这个是所有Windows程序的入口点,它是必须要有的,上次,我们已经讲过,这里不再提及。
接下来,我们来一起看一下这个WinMain函数都做了什么?
为了帮助大家理解WinMain函数,我们这里先使用自然语言进行概括性的描述。
- int WINAPI WinMain(HINSTANCE hinstance,
- HINSTANCE hPrevInstance,
- LPSTR lpCmdLine,
- int nCmdShow)
- {
- 1、定义一个WNDCLASS或者WNDCLASSEX变量wcx;
- 2、设置WNDCLASSEX变量wcx;
- 3、利用wcx创建注册一个窗口类MainWClass,窗口类就好比一个模版,Windows系统会参考这个模版,为我们创建窗口;
- 4、用我们创建的窗口类MainWClass,创建一个窗口;
- 5、调用ShowWindow和UpdateWindow显示和更新窗口;
- 6、创建一个消息泵,这个消息泵的任务就是不断从消息队列中提取消息,并将消息传递给当前窗口的处理函数,
- 当消息泵接收到WM_QUIT退出消息后,消息泵就会退出;
- 7、程序返回。
- }
好了,现在,我们继续分析WinMain函数的内容:
1)定义一个WNDCLASS或者WNDCLASSEX变量wcx,这个目标是通过如下的代码来完成的:
- WNDCLASSEX wcx;
2)设置窗口类,具体实现是通过如下的代码:
- wcx.cbSize = sizeof(wcx); // 这个参数设置wcx的大小;
- wcx.style = CS_HREDRAW |CS_VREDRAW; // 告诉系统,当窗口大小改变时,重绘整个窗口;
- wcx.lpfnWndProc = MainWndProc; // 告诉系统,当前窗口类的消息处理函数是MainWndProc;
- wcx.cbClsExtra = 0; // 这个大家先不用管,设置为0就可以;
- wcx.cbWndExtra = 0; // 这个大家也先不用管,设置为0就可以;
- wcx.hInstance = hinstance; // 告诉系统当前这个窗口属于哪个程序,系统会根据这个参数,将该窗口的消息发送到这个程序的消息队列;
- wcx.hIcon = LoadIcon(NULL,IDI_APPLICATION); // 窗口图标:大家也先不用管,使用这个IDI_APPLICATION值,就可以;
- wcx.hCursor = LoadCursor(NULL,IDC_ARROW); //设置这个窗口的光标样式,大家也先不用管,设置为IDC_ARROW,就可以;
- wcx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // 设置当前窗口的背景颜色,这里是白色WHITE_BRUSH;
- wcx.lpszMenuName = NULL; //当前窗口的菜单,我们这个窗口没有菜单,所以,只需要设置为NULL,就可以;
- wcx.lpszClassName = "MainWClass"; // 告诉系统,我们这个窗口的类名;
- wcx.hIconSm = (HICON)LoadImage(hinstance, // 当前窗口的小图标,大家先这么写,先不用管具体什么意思,后面会介绍。
- MAKEINTRESOURCE(5),
- IMAGE_ICON,
- GetSystemMetrics(SM_CXSMICON),
- GetSystemMetrics(SM_CYSMICON),
- LR_DEFAULTCOLOR);
3)利用wcx创建注册一个窗口类MainWClass,具体通过如下的代码来完成:
- if (!RegisterClassEx(&wcx))
- {
- return 1;
- }
4)用我们创建的窗口类MainWClass,创建一个窗口,具体通过如下代码来完成:
- hwnd = CreateWindow(
- "MainWClass", // 窗口类名
- "我们的第二个程序", // 窗口标题
- WS_OVERLAPPEDWINDOW, // 窗口样式
- CW_USEDEFAULT, // 水平位置X:默认
- CW_USEDEFAULT, // 垂直位置Y:默认
- CW_USEDEFAULT, // 宽度:默认
- CW_USEDEFAULT, // 高度:默认
- (HWND)NULL, // 父窗口:无
- (HMENU)NULL, // 菜单:使用窗口类的菜单
- hinstance, // 应用程序实例句柄
- (LPVOID)NULL); // 窗口创建时数据:无
5)调用ShowWindow和UpdateWindow显示和更新窗口,具体通过如下代码来完成:
- ShowWindow(hwnd, nCmdShow);
- UpdateWindow(hwnd);
6)创建一个消息泵,具体通过如下的代码来完成:
- while ((fGotMessage = GetMessage(&msg, (HWND)NULL, 0, 0)) != 0 && fGotMessage != -1)
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
7)程序返回,具体通过如下的代码来完成:
- return msg.wParam; //这个msg通常是WM_QUIT,这个wParam是这个消息的退出码,通常由PostQuitMessage来设置,主要是通知系统,该程序是否正常退出。
相信,通过上面这段描述,大家一定对这个例子中的WinMain函数有了一个整体的把握,现在,我们趁热打铁,再一起分析一下我们这个窗口类的窗口处理函数。
现在,我先告诉大家窗口处理函数的格式,具体如下:
- LRESULT CALLBACK 窗口处理函数名(
- HWND hwnd,
- UINT uMsg,
- WPARAM wParam,
- LPARAM lParam
- )
大家只需要记住,窗口处理函数的格式必须这么写,只有函数名可以改变,其它的都不可以改变,这个是系统规定的,记住就可以,其中WPARAM和LPARAM是Windows消息中的两个参数,当窗口处理函数被调用的时候,hwnd代表了当前的窗口,uMsg代表了当前的消息,在Windows中,每个消息都用一个整数来表示。wParam和lParam是这个消息中的两个参数。
下面,我先给出消息处理函数的一般流程:
- LRESULT CALLBACK 窗口消息处理函数名(
- HWND hwnd,
- UINT uMsg,
- WPARAM wParam,
- LPARAM lParam
- )
- {
- switch (uMsg)
- {
- case 消息1:
- {
- 消息处理函数1;
- break;
- }
- case 消息2:
- {
- 消息处理函数2;
- break;
- }
- ...
- default:
- return DefWindowProc(hwnd, uMsg, wParam, lParam);
- }
- }
上面描述了消息处理函数的一般流程,我们按照这个一般流程来讲解一下我们的窗口处理函数,具体如下:
我们的窗口处理函数,只响应了一个消息WM_DESTROY,这个消息是在我们点击窗口的关闭按钮是产生的,当我们的消息泵接收到这个消息后,就会将它发给我们的窗口处理函数,然后,我们的窗口处理函数调用函数ExitThread,其中传递的是线程的退出码,线程正常退出,通常都设置为0,当执行完这个函数后,整个线程会结束运行,我们这里的线程只有一个,就是WinMian所在的线程,当这个线程退出后,整个程序就会结束运行。
对于其它的消息,我们都使用系统提供的默认消息处理函数来处理,这个函数的原型如下:
- LRESULT DefWindowProc(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam);
在这个函数中,hWnd就是当前窗口的句柄,Msg就是当前要处理的消息,wParam和lParam就是当前消息中的两个参数。
好了,今天讲了很多,相信,大家读完后,应该会对我们的第2个Windows程序有所理解,希望大家多实践,如果有暂时不明白的内容,可以先放下,因为主要的内容,我已经告诉你们了,次要的后边会根据需要讲解。
第2个Wiindows程序讲解的更多相关文章
- OpenGL学习-------visual studio 2010配置和第一个OpenGL程序讲解
OpenGL作为当前主流的图形API之一,它在一些场合具有比DirectX更优越的特性. 1.与C语言紧密结合. OpenGL命令最初就是用C语言函数来进行描述的,对于学习过C语言的人来讲,OpenG ...
- 第一个Windows程序讲解
上次,我们一起写了第一个Windows程序,虽然程序非常简单,但是它却可以帮助大家建立学好windows开发的信心. 今天,就让我帮助大家分析一下这个程序的内容.首先,我们的程序包含了一个头文件:wi ...
- fpga Verilog hdl 按键消抖 部分程序讲解
module debounce(clk_in,rst_in,key_in,key_pulse,key_state); input clk_in;//system clock input rst_in; ...
- C#可定制的数据库备份和恢复程序 (讲解流程)
可定制的数据库备份和恢复程序 tashanzhishi [原作] 关键字 数据库 备份 恢复 出处 在我们做数据库系统的程序时,经常需要为客户做一个数据库的备份和恢复程序,特别是对于一些非专业的数据库 ...
- C指针(3)——指向指针的指针(程序讲解)
int **q可以分成两部分,即int* 和 (*q),后面的 “q” 中的* 表示q是一个指针变量,前面的int*表示指针变量q只能存放int*型变量的地址.int** q表示为指针变量q只能存放i ...
- C指针(2)——指针在函数中的应用(程序讲解)
3-1.c指针用作函数参数 #include<stdio.h> typedef unsigned char uint8_t; //类型自定义,通过typedef语句重新把unsigned ...
- C指针(1)——指针在数组中的应用(程序讲解)
2-1.c数组指针的定义: #include <stdio.h> int main() { char str[]="China Beijing Fujian"; //定 ...
- php微信支付接口开发程序
php微信支付接口开发程序讲解 微信支付接口现在也慢慢的像支付宝一个可以利用api接口来实现第三方网站或应用进行支付了, 下文整理了一个php微信支付接口开发程序并且己测试,有兴趣的朋友可进入参考. ...
- iBrand 开源电商小程序 (Laravel API+ webpack + gulp + 原生小程序)
iBrand 社交电商产品正式进入开源过程中了,我们制定了详细的开源计划,目前已经发布了 V1 的版本,后续的版本也在陆续整理完善中. 各个版本功能明细如下图: 3 个版本计划在今年春节前全部完成,可 ...
随机推荐
- android控件上面实现提醒信息
android开发中,经常会用到显示一个提醒信息,比如个人中心,有新信息,购买商品后,在购物车控件,显示购物数量等.我们可以用,2个控件来实现,或者用层叠图. 还有一种简单方便的办法,使用别人的开源代 ...
- Qt深入:不能不知道的Type、Attribute和Flags
Qter高手与新手的区别在于:知道还是不知道 Qt不是开发语言,所以无所谓谁厉害.但使用他的Qter却有着差异,也许是面向对象语言本身的.或者实际经验上的.而对于Qt本身来说,高手与新手最显著的差异在 ...
- Linux磁盘管理:LVM逻辑卷基本概念及LVM的工作原理
一.传统的磁盘管理 其实在Linux操作系统中,我们的磁盘管理机制和windows上的差不多,绝大多数都是使用MBR(Master Boot Recorder)都是通过先对一个硬盘进行分区,然后再将该 ...
- 向量旋转 UPC 2217
这道题目是13山东省省赛的签到题,题目大意是给等边三角形的两个定点,让求逆时针旋转之后的第三个点的坐标,原来不会向量的旋转,在网上找了找,找到一篇挺好的,直接贴过来. 向量的旋转 实际做题中我们可能会 ...
- centos 6+安装山逗斯骚尅特(本文内容来自都比更具帝)
系统支持:CentOS 6+,Debian 7+,Ubuntu 12+ 内存要求:≥128M 关于本脚本 一键安装 Shadowsocks-Python, ShadowsocksR, Shadowso ...
- codevs 1242 布局(查分约束+SPFA)
/* 查分约束. 给出的约束既有>= 又有<= 这时统一化成一种 Sb-Sa>=x 建边 a到b 权值为x Sb-Sa<=y => Sa-Sb>=-y 建边 b到a ...
- 简单图片banner轮播
/**************[css]****************/ <style type="text/css"> *{margin:0px; ...
- 免写前缀JS包--prefixfree.min.js--插件
/** * StyleFix 1.0.3 & PrefixFree 1.0.7 * @author Lea Verou * MIT license */ (function(){functio ...
- 【转】Java学习之Iterator(迭代器)的一般用法 (转)
[转]Java学习之Iterator(迭代器)的一般用法 (转) 迭代器(Iterator) 迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构.迭 ...
- asp.net使用Mysql乱码处理
在asp.net与mysql数据库打交道的时候,由于配置的问题,会遇到自己写的方法在读取数据库中数据的时候,英文,数字可以正常通过,但是中文就无法通过,以登录为例(方法略),当输入英文用户名的时候可以 ...