Windows程序内部运行原理主讲人:孙鑫
http://www.sunxin.org
Windows应用程序,操作系统,计算机硬件之间的相互关系应用程序操作系统输入输出设备
③ ④
① ②
消息队列
http://www.sunxin.org
关于 API
向下的箭头③表示应用程序可以通知操作系统执行某个具体的动作,如操作系统能够控制声卡发出声音,
但它并不知道应该何时发出何种声音,需要应用程序告诉操作系统该发出什么样的声音。这个关系好比有个机器人能够完成行走的功能,但是,如果人们不告诉它往哪个方向上走,机器人是不会主动行走的。这里的机器人就是操作系统,人们就是应用程序。
http://www.sunxin.org
关于 API
那么,应用程序是如何通知操作系统执行某个功能的呢?
有过编程经验的读者都应该知道,在应用程序中要完成某个功能,都是以函数调用的形式实现的,同样,应用程序也是以函数调用的方式来通知操作系统执行相应的功能的。
操作系统所能够完成的每一个特殊功能通常都有一个函数与其对应,也就是说,操作系统把它所能够完成的功能以函数的形式提供给应用程序使用,应用程序对这些函数的调用就叫做系统调用,这些函数的集合就是 Windows操作系统提供给应用程序编程的接口 (Application Programming
Interface),简称 Windows API。如 CreateWindow就是一个 API
函数,应用程序中调用这个函数,操作系统就会按照该函数提供的参数信息产生一个相应的窗口。
http://www.sunxin.org
关于消息及消息队列向上的箭头④表示操作系统能够将输入设备的变化上传给应用程序。如用户在某个程序活动时按了一下键盘,操作系统马上能够感知到这一事件,并且能够知道用户按下的是哪一个键,操作系统并不决定对这一事件如何作出反应,而是将这一事件转交给应用程序,由应用程序决定如何对这一事件作出反应。好比有个蚊子叮了我们一口,我们的神经末梢
(相当于操作系统)马上感知到这一事件,并传递给了我们的大脑(相当于应用程序),我们的大脑最终决定如何对这一事件作出反应,如将蚊子赶走,或是将蚊子拍死。对事件作出反应的过程就是消息响应。
http://www.sunxin.org
关于消息及消息队列操作系统是怎样将感知到的事件传递给应用程序的呢?
这是通过消息机制 (Message)来实现的。操作系统将每个事件都包装成一个称为消息的结构体 MSG来传递给应用程序,参看 MSDN。
MSG结构定义如下:
typedef struct tagMSG {
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG;
http://www.sunxin.org
关于句柄
句柄( HANDLE),资源的标识。
操作系统要管理和操作这些资源,都是通过句柄来找到对应的资源。按资源的类型,
又可将句柄细分成图标句柄( HICON),
光标句柄( HCURSOR),窗口句柄
( HWND),应用程序实例句柄
( HINSTANCE)等等各种类型的句柄。操作系统给每一个窗口指定的一个唯一的标识号即窗口句柄。
http://www.sunxin.org
从变量的类型区分变量的用途
int x,y;
x=30;
y=30;
//x和 y既可以用来表示坐标点,也可以用来表示宽度和高度,还可以用来表示身高和体重。
typedef int WIDTH
typedef int HEIGHT
WIDTH x;
HEIGHT y;
//好处:我们从变量的类型上就可以知道 x和 y是用来表示宽度和高度。
http://www.sunxin.org
WinMain函数
Windows程序的入口函数
int WINAPI WinMain(
HINSTANCE hInstance,// handle to current instance
HINSTANCE hPrevInstance,// handle to previous instance
LPSTR lpCmdLine,// command line
int nCmdShow // show state
);
http://www.sunxin.org
窗口的创建创建一个完整的窗口需要经过下面四个操作步骤:
设计一个窗口类;
注册窗口类;
创建窗口;
显示及更新窗口。
http://www.sunxin.org
设计窗口类
typedef struct _WNDCLASS {
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HANDLE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
} WNDCLASS;
http://www.sunxin.org
窗口类的类型在我们的程序中经常要用到一类变量,这个变量里的每一位 (bit)
都对应某一种特性。当该变量的某位为 1时,表示有该位对应的那种特性,当该位为 0时,即没有该位所对应的特性。当变量中的某几位同时为 1时,就表示同时具有几种特性的组合。一个变量中的哪一位代表哪种意义,不容易记忆,所以我们经常根据特征的英文拼写的大写去定义一些宏,该宏所对应的数值中仅有与该特征相对应的那一位( bit)为 1,其余的 bit都为 0。我们使用 goto
definition就能发现 CS_VREDRAW=0x0001,
CS_HREDRAW=0x0002,CS_DBLCLKS =0x0008,
CS_NOCLOSE=0x0200。他们的共同点就是只有一位为 1,其余位都为 0。如果我们希望某一变量的数值既有 CS_VREDRAW特性,
又有 CS_HREDRAW特性,我们只需使用二进制 OR( |)操作符将他们进行或运算相组合,如 style=CS_VREDRAW | CS_HREDRAW
| CS_NOCLOSE。如果我们希望在某一变量原有的几个特征上去掉其中一个特征,用取反( ~)之后再进行与( &)运算,就能够实现,如在刚才的 style的基础上去掉 CS_NOCLOSE特征,可以用
style & ~CS_NOCLOSE实现。
http://www.sunxin.org
窗口过程函数第二个成员变量 lpfnWndProc指定了这一类型窗口的过程函数,也称回调函数。回调函数的原理是这样的,当应用程序收到给某一窗口的消息时(还记得前面讲过的消息通常与窗口相关的吗?),就应该调用某一函数来处理这条消息。这一调用过程不用应用程序自己来实施,
而由操作系统来完成,但是,回调函数本身的代码必须由应用程序自己完成。对于一条消息,操作系统到底调用应用程序中的哪个函数(回调函数)来处理呢?操作系统调用的就是接受消息的窗口所属的类型中的
lpfnWndProc成员指定的函数。每一种不同类型的窗口都有自己专用的回调函数,该函数就是通过 lpfnWndProc成员指定的。
http://www.sunxin.org
窗口过程函数举例:汽车厂家生产汽车好比应用程序创建窗口,
用户使用汽车好比操作系统管理窗口,某种汽车在销售前就指定好了修理站(类似回调函数),当用户的汽车出现故障后(类似窗口收到消息),汽车用户(类似操作系统)自己直接找到修理站去修理,
不用厂家(类似应用程序)亲自将车送到修理站去修理,但修理站还得由厂家事先建造好。
http://www.sunxin.org