Win32窗口机制和消息机制整体流程

时间:2021-10-08 05:35:46
[摘要] 本节课通过一张图,详细的介绍了Windows的窗口机制和消息机制整体流程,让你一目了然。 Windows系统,是窗口作为基础的系统,以消息机制作为运转机制的系统。我们学习Windows编程(Win32编程)也就必须先掌握这两个根本机制即窗口机制和消息机制。

    Windows系统,是窗口作为基础的系统,以消息机制作为运转机制的系统。我们学习Windows编程(Win32编程)也就必须先掌握这两个根本机制即窗口机制和消息机制。
    本节课结合一张Win32程序内部运作机制的整体流程图,来讲述整体的流程。

Win32窗口机制和消息机制整体流程

    我们本节课就是把这张图讲清楚。
    我们在WinMain函数中写这个代码,也就是入口函数写这个代码。在上一节课《Windows零基础入门:2.6 Win32第一个程序和计时文字闪烁》有完整代码。我们的代码要完成的功能就是创建一个窗口,然后完成计时和闪烁的功能。
    Windows中窗口如何创建出来,可不是一个CreateWindow函数就简单创建出来的。它经历了很多。我们应该深入学习,而不只是用一个函数,去记这个函数那些参数。这样学习是没用的,会让你始终不知所以然,总是摸不透。我们C++技术网推出的这个课程,会深入浅出的带你领略这般精彩。我相信,当你学完这些深入的背景知识后,即使你不用记住这些背景知识,有个印象,就足以让你在日后使用这些函数时胸有成竹,而不是云里雾里。我们的课程要让你知道,是什么,怎么用,更重要的是为什么!!
    Windows编程中,窗口机制部分和消息机制,是最为根本的两个技术点。我们这里就来整体上都串通来介绍,让你一开始就知道是怎么一回事。
    以上那张图,请仔细看几遍,然后对照下面的介绍来理解。这个图,没有太多的标注,需要文章来解释,一开始看不懂是正常的。
    我们以代码为主线来讲解。我们的代码,就是WinMain中的代码,这些代码创建了一个窗口,同时有一些功能。这些代码在入口函数中。我们启动一个程序,系统就建立一个进程。我们的exe没有运行的时候,就是一个文件而已。运行起来,系统给他在内存分配一些空间,这些内存就是进程的内存空间。这个进程就是在内存中执行的程序了。我们就把进程理解为我们的程序。而进程只是提供一个程序执行需要的内存空间以及相关的资源场所。这些内存空间和资源场所都是提供给进程的线程来使用的。
    打个比方,进程就像我们的家,线程就像家里的成员。代码是在线程中执行的,因为线程的东西才会跑到CPU里,进程就是一个场所,不会动的。而每一个进程至少有一个线程,就是主线程了。那么我们的WinMain函数就是在主线程里了。在上图中,就显示为主线程代码。途中只是一部分,实际上,窗口过程也在主线程中,我们这个程序就是一个线程的程序。这些进程线程的理论知识,请学习操作系统课程的进程部分。
    我们程序有了这个主线程,就可以执行代码了。
    1.注册窗口类,执行RegisterClass。必须要注册窗口类,我们才能创建我们自己的窗口。实际上,窗口类有三种:系统窗口类、应用程序全局窗口类和应用程序局部窗口类
    系统窗口类中一部分是系统内部使用的,而另一部分是可以供系统所有进程使用的,这些窗口类就是基本的控件窗口类。后面会详细介绍。
    应用程序全局窗口类,就是注册窗口类时以CS_GLOBALCLASS标志注册的窗口类,这个窗口类在这个进程中,所有模块都可以使用。模块一般是dll模块。我们知道的程序的皮肤库,很多都是以这种形式实现的,dll中注册的应用程序全局窗口类,我们程序就可以直接使用这些漂亮的皮肤库提供的控件了。
    应用程序局部窗口类则是没有CS_GLOBALCLASS标志注册的窗口类,这个窗口类只在模块范围内使用。我们的EXE如果加载了其他的dll模块,此时EXE的主线程注册的应用程序局部窗口类对于dll来说,是看不见的,也就不能使用这个局部窗口类来创建窗口。
    如果你对dll这些不懂,也不要紧,只要知道它就是被加载到进程中的一个部件而已。就像你把冰箱放在了你的房子一样。冰箱只能看到它冰箱内的东西和房子全局的东西。
    RegisterClass函数在图中的三个箭头分支,表示他可以注册应用程序全局和局部的窗口类,系统窗口类由系统来处理,不要我们来创建和销毁。注册窗口类其实就是在对应的窗口类表填写一个窗口类的信息而已,供创建窗口时查找使用。
    2.创建窗口,执行CreateWindow。这个函数就是根据指定的窗口类来创建一个窗口。你可以指定为系统窗口类来创建标准的控件,比如按钮控件,此时就不需要执行注册,因为系统会自动帮我们注册。只有我们要根据我们自己定制的窗口类创建窗口时,才需要先注册窗口类。不管是创建标准控件还是你定制的窗口类,都是要去窗口类表查找对应的窗口类信息的。执行的顺序就是:应用程序局部窗口类 -> 应用程序全局窗口类 -> 系统窗口类。也就是说,创建窗口就需要去按照这个顺序查找你指定的窗口类名称,找到就不再往后查找,否则就一直往后,如果最后都找不到,那么创建窗口就会失败。这个就是图中标注了1,2,3箭头的意思。
    3-4.显示窗口。创建好窗口后,就要显示它。执行的是ShowWindow和UpdateWindow函数。这个就是将窗口显示出来。
    以上就是窗口的创建过程。窗口显示后,我们要操作窗口,这就是消息机制完成的。
    5.获取消息。一个窗口对应一个窗口的消息队列,队列里的消息都是窗口的,窗口都要处理这些消息的。处理了这些消息,就实现了交互,实现了功能。在主线程函数中,GetMessage函数循环不断地从消息队列不断的获取消息,如果获取到的消息是WM_QUIT,循环就停止,也就意味着程序结束了。如果消息队列中没有消息了,系统会将这个程序挂起来,直到有消息了,才唤醒它来处理消息。
    6.获取了消息之后,要对消息进行处理,有些消息是原始消息,直接无法处理,需要转换一下。
    7.转换成正确格式的消息后,就要把消息发给合适的地方来处理了。分发了这个消息之后,就进入下一轮的获取消息,不断循环。分发的路线就是先根据消息里的窗口句柄,找到窗口,然后去查找这个窗口由哪个窗口类创建,找到窗口类后,就找到这个窗口类指定的窗口过程函数,这样这个消息就分发给这个窗口过程了。5-7三步构成的循环就是我们听说的消息循环了。
    而窗口过程中,就是通过switch来分类处理消息,完成一些功能的。Win32程序的功能,都在这个窗口过程中完成。
    那么最后一个问题,窗口消息如何来的?
    我们窗口显示之后,我们的单击窗口、拖动窗口等,系统都会捕捉到我们的光标在窗口上面有动作,系统就识别出来了,然后就处理成标准的消息,投递到这个窗口的消息队列中。还有一种就是窗口过程处理消息的过程中,为了完成一个复杂的功能,要做一系列的基本动作,只要有一个动作功能,就要产生一个新的消息,这个消息也会投递到窗口消息队列中。其他的进程也可以向我们的窗口发送消息,进而实现进程间的通信。
    以上就是整个窗口窗口机制和消息机制的一个整体过程。更详细的讲解,请继续学习后面的课程内容,这里只是一个大概的流程结果,重在整体的流程逻辑,一些细节,可能有所忽略,也是让整体流程更加的清晰。