为了了解MFC,必须先了解Win32。因为Win32程序的来龙去脉和消息动向等等这些重要的动作在MFC应用程序中被Application Framework 封装起来了,所以对于程序员来说,必须先弄清楚Win32才能很好的理解MFC。
上图所示是Win32应用程序与操作系统之间的关系。
详细的代码框架如下:
Generic.h文件中
BOOL InitApplication(HANDLE); //初始化程序
BOOL InitInstance(HANDLE, int); //初始化进程实例
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //窗口函数
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM); //关于
Genric.c文件中
#i nclude <windows.h> //每个Windows程序都要载入此头文件
#i nclude “resource.h” //内涵各个resource IDs
#i nclude <generic.h> //本程序的头文件
//……全局变量的声明
HINSTANCE _hInst;
HWND _hwnd;
Char _szAppName[] = “Generic”; // 程序名称
Char _szTitle[] = “Generic Sample Application” ;//窗口标题
/
//WinMain 程序进入点
/
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
UNREFERENCED_PARAMETER(lpCmdLine); //避免编译的时候警告
If(! hPrevInstance)
If (! InitApplication(hInstance))
Return (FALSE);
If(! InitInstance(hInstance, nCmdShow))
Return FALSE;
While(GetMessage(&msg, NULL, 0 , 0))
{
TranslateMessage(&msg); //转换键盘消息
DispatchMessage(&msg); //分派消息
}
return msg.wParam; //传回PostQuitMessage的参数
}
/
//InitApplication 注册窗口类
/
BOOL InitApplication(HINSTANCE hInstance)
{
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
…
wc.hInstance = hInstance;
wc.lpfnWndProc = (WNDPROC)WndProc; //窗口函数
wc.lpszClassName = _szAppName; //窗口类名称
return (RegisterClass(&wc));
}
/
//InitInstance 产生窗口
/
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
_hInst = hInstance; //存储为全局变量,方便使用
_hWnd = CreateWindow(
_szAppName, //窗口类名称
_szTitle, //窗口标题(caption)
…
);
if(! _hWnd)
return FALSE;
ShowWindow(_hWnd, nCmdShow); //显示窗口
UpdateWindow(_hWnd); //送出WM_PAINT
Return TRUE;
}
/
//WndProc 窗口函数
/
LPRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (wmId)
{
case IDM_ABOUT:
……break;
case IDM_EXIT:
……break;
default:
return (DefWindowProc(hWnd, message, wParam, lParam));
}
break;
case WM_DESTROY:
PostQuitMessage(0);
Break;
Default:
return (DefWindowProc(hWnd, message, wParam, lParam));
}
return 0;
}
其他函数省略。
基本上代码中的Win32程序和示意图是一致的。
(1)WinMain
其中WinMain函数是Windows 程序的进入点,在Win32中CALLBACK被定义为_stdcall,是一种函数调用习惯,关系到参数进入到堆栈的次序,以及处理堆栈的责任归属。WinMain的四个参数由操作系统传递进来。
(2)RegisterClass
一开始,Windows程序必须做些初始化工作,为的是产生应用程序的工作舞台——窗口。但在窗口产生之前,必须设定好窗口的属性(WNDCLASS对象),包括窗口的外貌(风格)和行为(窗口函数)等。RegisterClass是一个API函数,通过它就可以设定窗口的属性,这一步操作被称为注册窗口类。
(3)CreateWindow
在窗口属性设定好了以后,就可以用API函数CreateWindow创建窗口。注意,CreateWindow只产生窗口,并不显示窗口。
(4)ShowWindow和UpdateWindow
在创建了窗口以后,利用ShowWindow将它显示在屏幕上。又,我们希望线传送一个WM_PAINT给窗口,以驱动窗口的绘图操作,所以调用UpdateWindow。
(5)GetMessage
消息循环中的GetMessage是Windows3.x 非强制性多任务的关键。如果消息队列上没有属于程序自己的消息,他就把机会让给其他程序。通过程序之间彼此协调让步的方式达到多任务能力。应用程序需要靠消息推动,需要通过GetMessage抓消息。
(6)TranslateMessage和DispatchMessage
TranslateMessage是为了将键盘消息转化,DispatchMessage会将消息传给窗口函数去处理。在消息发生之际,操作系统已根据当时状态,为该消息标明所属窗口,而窗口所属的窗口类又已经明白标示了窗口函数,所以DispatchMessage自由脉络可寻。图中可以看出,DispatchMessage经过USER模块的协助,才能把消息交到窗口函数手中。
(7)窗口函数WndProc
窗口函数通常先判断消息的种类,以决定处理方式。由于它是被Windows系统所调用(我们并没有在应用程序的任何地方显式调用此函数,DispatchMessag在USER模块的协助下,将消息送到窗口函数,然后由操作系统调用窗口函数)的,所以这是一种call back函数,意思是指在应用程序中被Windows系统调用的函数。这些函数虽然是我们自己设计,但是永远不会也不该被我们自己程序来调用,而是为Windows系统准备的。之所以这样,原因是除了我们自己程序需要调用窗口函数,很多时候操作系统也要调用我们的窗口函数,窗口函数设计为CallBack形式,才能开放出一个接口给操作系统调用。
(8)DefWindowProc
这是Windows内部默认的消息处理函数。