MFC终究是避不开的,那就慢慢来学习吧
看网上都推荐《深入浅出MFC》。结果发现并没有很容易的入门。我个人还是推荐《MFCWindows 应用程序设计》。任哲
一、预备知识
代码运行机理探究:
我们运行程序时,程序是怎么运作的呢。这一点分析清楚,有助于我们理解窗口运行机制。我们编写完代码后,点击编译,把所有文件都连接起来,形成一个可以被操作系统执行的文件。但操作系统怎么来执行我们的程序呢?它是通过调用系统调用来执行。正如我们在操作系统上所知道的,操作系统会提供我们用户接口。通过这个接口来调用我们的程序,由于语言的特性,调用我们的程序后,要有一个主函数。我们平常编写的console程序,入口是main。即控制台通过main函数进入执行我们的代码。而Windows程序则不同,它的入口函数是winmain。直观来说:Windows程序的架构是这样的:
Windows程序代码---------(winmain)-----------Windows操作平台-------------------硬件系统
而console程序的架构是:
console application 程序代码-------(main)----------MSDOS-------------Windows操作平台-----------硬件系统。(其中,MSDOS实质是一个运行平台,在Windows操作系统之上,与Windows程序相比,增加了一个中间层。提供了一个可视化界面。MSDOS不仅可以调用库函数,也可以调用Windows的API。)
Windows程序的特点:
Windows程序除了入口为winmain的主函数,还有一个消息处理函数,两者并不是调用关系,这两个函数都是系统调用的。主函数主要进行的操作是:1.创建程序图形窗口界面。2.进入一个叫做消息循环的循环中,并在这个循环中等待用户事件的产生。当收到事件后,主函数把事件的消息传到系统。系统再次调用Windows程序的消息处理函数。循环这种操作,直到事件是一个终止程序运行的事件。
Windows API的特点:
为了支持应用程序的设计和运行,Windows在系统函数中,向用户开放了一些可以由应用程序调用的函数(API)。实质上,这些API函数是一种软中断。因此称为系统调用。我们在操作系统中,也简要的学过:用户只有通过中断才能进入操作系统。
Windows API主要分为三大类型:
1.窗口管理函数:窗口的创建,移动,修改。
2.图形设备函数:实现图形的绘制及操作,图形设备接口(GDI)
3.系统服务函数:与操作系统有关的功能。
Windows开发工具:SDK,实际上就是利用Windows API。
Windows的特殊数据类型:
1.用typedef 起的别名。
2.特殊的数据类型:
1.句柄。是一个结构体。用来隐藏内部的信息。句柄实质上是结构类型变量指针的再封装。避免用户直接操作指针操作的危险。虽然与指针形式相同,但不能像指针那样参与运算。
HINSTACE句柄:应用程序实例句柄。在用户眼里程序可能就是静态的代码,操作系统中,程序是动态的过程。程序利用HINSTACE这种结构来管理这种动态行为。这个变量就代表了正在运行的一个程序。
2.WNDCLASS。结构体。这个结构体是Windows程序创建窗口的参数。其声明如下:
typedef struct _WNDCLASS { UNIT style;//指定窗口风格,通常选择style=0 WNDPROC lpfnWndproc;//函数指针,指向消息处理函数 int cbClsExTra; int cbWndExTra; HANDLE hInstance;//多窗口时,这个是和主窗口相同的。 HICON hIcon;//用户使用的图标。 HCURSOR hCursor;//窗口所使用的光标。 HBRUSH hbrBackground;//窗口背景颜色 LPCTSTR lpseMenuName;//窗口的菜单 LPCTSTR lpszClassName;//窗口的类名 }WNDCLASS;
3.Windows函数的调用。
主要是宏定义的理解。像WINAPI CALLBACK 等。这些属于修饰符,用来说明调用的顺序。程序被系统调用时,总要传一些参数,这些修饰符就是来说明传递参数的顺序的,因为使用堆栈来进行存储的,所以对参数顺序肯定是有要求的。比如你的main函数是应该先传递左边的参数,还是括号右边的。比较常用的就是_stdcall和_cdecl。_cdecl是默认vc++调用方式。但是,在winAPI中,都遵循_stdcall.所以在编写Windows程序时,也要声明这种修饰符。声明调用方式。WINAPI 和CALLBACK这些都是经过宏定义之后别名。其实质是_stdcall.
窗口的创建:
步骤是先定制窗口,在注册窗口,然后是创建,最后是显示在屏幕上。
代码结构是:
//1.定制窗口,利用结构体赋值来声明。 WNDCLASS wc; wc.style=0; ... //2.窗口的注册 BOOL RegisterClass (WNDCLASS & wc); //3.窗口的创建 //利用CreateWindow()来创建,用很多参数。 HWND hwnd; hwnd=CreateWindow("class name","title","style",x,y,w,h,fatherhandle,hMenu,hInstance,NULL) //4.窗口的显示 BOOL ShowWindow( HWND hwnd, int nCmdshow //窗口的显示方式 ); BOOL UpdateWindow(HWND hwnd);
事件、消息循环和窗口函数。
用户所提出的一个服务就是一个事件。这些事件的信息在Windows程序中构造了一个结构体用来存储这些消息。MSG。其结构是:
typedef struct tagMsg { HWND hwnd;//产生消息的窗口句柄,即事件的地点 UNIT messeage;//窗口消息的标识码,用宏定义来标识的。 WPARAM wparam;//事件的附加消息 LPARAM lparam;//事件的附加消息 DWORD time;//产生的时间 POINT pt;//发送消息时,光标所在的位置。 }MSG;
系统消息的标识码一般以VM_开头。
消息队列和消息循环:
MSG msg; while(GetMessage(&msg,NULL,NULL,NULL)){ TranslateMessage(&msg);//将键盘码消息转换为字符消息 DispatchMessage(&msg);//把消息派送给系统 }
消息派送给系统后,系统根据消息的hwnd找到窗口,然后根据窗口的lpfwinproc来找到消息处理函数,所以说消息处理函数是由系统调用的。消息处理完成后,会返回循环函数继续等待。多个消息时,会有一个消息队列进行缓存。也有不经过消息队列直接送达窗口的。
windows程序的结构:
一个入口为winmain的主函数(包括窗口的创建,以及消息的循环)
int WINAPI WinMain(HINSTANCE hInstance, hINSTANCE PreInstance, LPSTR lpCmdbine, int nCmdshow){ //窗口的创建 //消息循环 };
另一个是窗口函数(消息处理函数。)
LRESULT CALLBACK WndProc(HWND hwnd, UNIT messeage, WPARAM wparam, LPARAM lparam){ //消息处理函数 }
学到现在应该形成这样一个概念: