我是靠谱客的博主 正直蛋挞,最近开发中收集的这篇文章主要介绍第一章,Windows程序内部运行机制,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

          一个应用程序窗口通常都包含标题栏、菜单栏、系统菜单、最小化框、最大化框、可调边框,还有滚动条。


           窗口可以分为客户区和非客户区。客户区是窗口的一部分,应用程序通常在客户区中显示文字或者绘制图片。标题栏、菜单栏、系统菜单、最小化框和最大化框、可调边框统称为窗口的非客户区,他们由windows系统来管理,而应用程序则主要管理客户区的外观和操作。
           窗口可以有一个父窗口,有父窗口的窗口称为子窗口。除了上图显示的窗口类型外,对话框和消息框也是一个窗口。在对话框上统称还包含很多子窗口,这些子窗口的形式按钮、单选按钮、复选框、组框、文本编辑框等。
            在Windows应用程序中,窗口是通过窗口句柄来标识的,我们要对某个窗口进行操作,首先要得到这个窗口的句柄。
           在Windows程序中,有各种各样的资源(窗口、图标、光标等),系统在创建这些资源时会为他们分配内存,并返回标识这些资源的标识号,即句柄。

           Windows程序设计是一种不同于传统的DOS方式的程序设计方法。它是一种事件驱动方式的程序设计模式,主要是基于消息的。比如,用户按下鼠标右键,此时,操作系统会感知这一事件,于是将这个事件包装成一个消息,投递到应用程序的消息队列中,然后应用程序从消息队列中取出消息,并进行响应。在这个处理过程中,操作系统也会给应用程序发送消息,所谓发送消息,实际上是操作系统调用程序中一个专门负责处理消息函数,这个函数称为窗口过程。(即系统从此程序的消息队列中取出消息,然后调用处理消息的回调函数进行消息的处理)。

           

             消息MSG的结构:

             typedef struct tagMSG{

                            HWND hwnd;                                hwnd表示消息所属的窗口,将消息发送到该窗口的消息队列当中。

                            UINT message;                            消息的标识符。WM_XXX宏。

                            WPARAM wParam;

                            LPARAM lParam;

                            DWORD  time;

                            POINT pt;

           } MSG;               

 消息队列:

          每一个Windows应用程序开始执行后,系统都会为该程序创建一个消息队列,这个消息队列用来存放该程序创建的窗口的消息。比如,按下鼠标左键的时候,将会产生一个WM_LEBUTTONDOWN消息,系统会将这个消息放到窗口所属的应用程序的消息队列中,等待应用程序的处理。  

          进队消息和不进队消息:Windows程序中的消息可以分为进队消息和不进队消息。进队消息将由系统放入到应用程序的消息队列中,然后由应用程序取出并发送。不进队消息在系统调用窗口过程时直接发送给窗口。不管是进队消息还是不进队消息,最终都由系统调用窗口过程函数对消息进行处理。

          操作系统会向应用程序的消息队列发送(投递消息),应用程序也会从消息队列中取出并发送消息。 操作系统向消息队列发送消息其实是最原始的事件,操作系统将事件包装成消息投递到消息队列,应用程序取出消息并发送消息,此时的消息已经是一个满足消息定义的消息,并由操作系统调用窗口过程函数。    

WinMain函数:

          WinMain函数时程序的入口函数,当WinMain函数结束或者返回时,应用程序结束。

          WinMain函数的原型:WinMain函数接收4个参数,这些参数都是在系统调用WinMain函数时,传递给应用程序的。

          int WINAPI WinMain(

                              HINSTANCE hInstance,  表示程序当前运行的实例的句柄,当程序在Windows下运行时,它标识一个运行中的实例。一个程序可以运行多个实例,每当运行一个实例,系统都会给该实例分配一个句柄值,并通过hInstance参数传递给WinMain函数。

                              HINSTANCE hPreInstance,    总是NULL,不起作用。

                              LPSTR   lpCmdLine;

                              int nCmdShow ,    指定程序的窗口如何显示,这个参数的值由该程序的调用者指定,应用程序通常不需要去理会这个参数的值。

            };  

窗口的创建:

            1,设计一个窗口类;     指定窗口的特征,由WNDCLASS结构体来定义的。

            2,注册窗口类;

            3,创建窗口;

            4,显示及更新窗口。

回调函数的实现机制:

             回调函数不是由函数的实现方直接调用,而是在特定的事件或条件下发生时,由另外一方调用的,用于对该事件或条件进行响应。

             1,定义一个回调函数;

             2,提供函数实现的一方在初始化的时候,将回调函数的函数指针注册给调用者。

             3,当特定的时间或条件发生的时候,调用者使用函数指针调用回调函数对事件进行处理。

窗口过程函数被调用的过程如下:

             1,在设计窗口类的时候,将窗口过程函数的地址赋值给lpfnWndProc成员变量;

             2,调用RegisterCLass(&wndclass)注册窗口类,那么系统就有了我们所编写的窗口过程函数的地址;

             3,当应用程序接收到某一窗口的消息时,调用DispatchMessage(&msg)将对消息回传给系统,系统则利用先前注册窗口类时得到的函数指针,调用窗口过程函数对消息进行处理。

             一个Windows程序可以包含多个窗口过程函数,一个窗口过程总是与某一个特定的窗口类相关联。(通过WNDCLASS结构体中的lpfnWndProc成员变量指定),基于该窗口类创建的窗口使用同一个窗口过程。(注意控件也是一个封装好的窗口,窗口都有窗口类,即也就会有窗口过程函数)

              LoadIcon()如果加载的是系统的标准图标,那么第一个参数必须为NULL。

             使用MAKEINTRESOURCE宏把资源ID标识符转换为需要的LPCSTR类型。

             在VC++中,对于自定义的菜单、图标、光标、对话框等资源,都保存在资源脚本(.rc)文件中,资源是通过标识符(ID)来标识的,同一个ID可以标识多个不同的资源,资源的ID实际上是一个整数。在resource.h中定义为一个宏。

              使用GetStockObject函数可以得到系统的库存画笔、画刷等的句柄。

             菜单并不是一个窗口。

             CreateWindow:产生窗口的过程是由操作系统完成的,如果在调用CreateWindow函数之前,没有用RegisterClass函数注册过响应名称的窗口类,操作系统将无法得知这一类型的窗口的相关信息,从而导致创建窗口失败。注意区分WNDCLASS中的style成员与CreateWindow函数的dwStyle参数,前者指定窗口类的样式,基于该窗口类创建的窗口都具有这些样式,后者指定某个具体的窗口的样式。参数hWndParent指定被创建窗口的父窗口句柄,窗口之间可以有父子关系,子窗口必须具有WS_CHILD样式,对父窗口的操作同时也会影响到子窗口。如果窗口创建成功,CreateWindow函数将返回系统为该窗口分配的句柄,否则返回NULL。

              ShowWindow显示窗口,之后紧接着调用UpdateWindow来刷新窗口,该函数通过发送WM_PAINT消息来刷新窗口,UpdateWindow将WM_PAINT消息直接发送给窗口过程函数进行处理,而没有放到消息队列中等待处理。

               调用GetMessage函数从消息队列中取出消息,MetMessage从线程的消息队列中取出消息信息保存在MSG结构体中。参数hWnd指定结构属于哪一个窗口的消息,通常我们将其置为NULL,用于接收属于该调用线程的所有窗口的消息。

             GetMessage函数除WM_QUIT外的消息均返回非零值。

            TranslateMessage函数用于将虚拟键消息转换为字符消息,字符消息被投递到调用线程的消息队列中,当下一次调用GetMessage函数时被取出。例如TranslateMessage这个函数将WM_KEYDOWN和WM_KEYUP消息的组合转换为一条WM_CHAR消息(该消息的wParam附加参数包含了字符的ASCII码),并将转换后的新消息投递到调用线程的消息队列中,注意:TranslateM函数并不会修改原有的消息,它只是产生新的消息,并将其投递到消息队列中。

             DispatchMessage函数分派到一个消息到窗口过程,由窗口过程函数对消息进行处理,DispatchMessage实际上是将消息回传给操作系统,由操作系统调用窗口过程函数对消息进行处理(响应)。

Windows应用程序的消息处理机制:

               1,操作系统接收到应用程序的窗口消息,将消息投递给该应用程序的消息队列中,

               2,应用程序在消息循环中调用GetMessage函数从消息队列中取出一条一条地消息,取出消息后,应用程序可以对消息进行一些预处理,例如,放弃对某些消息的响应,或者调用TranslateMessage产生新的消息。(可以使用PeekMessage代替GetMessage)。

               3,应用程序调用DispatchMessage,将消息回传给操作系统,消息是由MSG结构体对象来表示的,其中就包含了接收消息的窗口的句柄,因此DispatchMessage函数总能进行正确的传递。

               4,系统利用WNDCLASS结构体的lpfnWndProc成员保存的窗口过程函数的指针调用窗口过程,对消息进行处理。

              DC是一个包含设备(物理输出设备,如显示器,以及设备驱动程序)信息的结构体。在,Windows平台下,所有的图形操作都是利用DC来完成的。物理是显示,还是打印,都是直接在DC上操作,然后由DC映射到这些物理设备上。

              当窗口客户区的一部分或者全部变为无效时,系统会发送WM_PAINT消息,通知应用程序重新绘制窗口。当窗口从无到有,改变尺寸、最小化后再恢复,被其他窗口遮盖后再显示时,窗口的客户区都将变为无效,此时系统都会给应用程序发送WM_PAINT消息,通知应用程序重新绘制。

               当用户单击窗口上的关闭按钮时,系统将给应用程序发送一条WM_CLOSE消息,调用DestroyWindow消息并销毁窗口,在调用DestroyWindow销毁窗口后,发送一条WM_DESTROY消息,但此时窗口虽然销毁了,但应用程序并没有退出。对WM_CLOSE消息进行响应不是必须的,默认窗口过程在响应此消息时会调用DestroyWindow函数来响应这条消息。

               DestroyWindow函数在窗口销毁后,会发送给窗口过程一条WM_DESTROY消息,在此消息的响应代码中,应该调用PostMessage函数,PostMessage函数向应用程序的消息队列中投递一条WM_QUIT消息并返回。


最后

以上就是正直蛋挞为你收集整理的第一章,Windows程序内部运行机制的全部内容,希望文章能够帮你解决第一章,Windows程序内部运行机制所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(67)

评论列表共有 0 条评论

立即
投稿
返回
顶部