概述
一个应用程序窗口通常都包含标题栏、菜单栏、系统菜单、最小化框、最大化框、可调边框,还有滚动条。
窗口可以分为客户区和非客户区。客户区是窗口的一部分,应用程序通常在客户区中显示文字或者绘制图片。标题栏、菜单栏、系统菜单、最小化框和最大化框、可调边框统称为窗口的非客户区,他们由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程序内部运行机制所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复