您好,欢迎访问三七文档
浅析Windows窗体运行机制众所周知,上校放下了使用已久的VB6,开始搞对象了。而摆在上校偶面前的第一道坎就是如何用C++写WindowsGUI程序。为啥非要写WinGUI的程序呢?……那你为啥非要老是看PLMM呢……咱搞对象,就找要个PL点的是不?GUI总比CUI舒服,是吧。所以我们今天呢,就一起来探讨探讨,PLMM(WindowsGUI窗体)是怎么“美容”出来的。(美容--!上校偶要辩解,偶喜欢原生态的PLMM……)ps:部分较多的资料信息我将放在附录中,供大家参考pps:以下如非特殊说明,Windows程序/窗体指拥有GUI的程序/窗体1.概述从盘古开天辟地至今(MS有点夸张了--!),用C++写Windows程序就一直是个比较大的麻烦,一般来说,要用C++实现GUI,有如下几个方法:一:直接使用SDK一笔一笔给他画出来,然后自己实现内部消息联通。(这也正是我们今天要讲的主题)二:使用MFC/OWL等应用程序框架进行开发。(MS目前多是使用此种方法。而且上校也打算日后写一篇关于MFC窗体运行机制的文章--!)三:使用GTK进行开发。GTK可以跨平台,你写的东西在Linux/Windows下都能运行。不过在Win下需要安装运行库。ps:上校个人对GTK不是很了解,或许他可以归为第二种。或许……总之详情还是去Google/Wiki吧。pps:Wiki英文已经被GOV解禁了我们今天要研究的,就是如何用C++/SDK创建窗体,并剖析它的运行机制。2.总括Windows位于硬件和应用程序之间,事件驱动的环境决定应用程序需要大量代码来接受和处理事件。每当有某个程序所感兴趣的事情发生时,Windows都会通知应用程序,应用程序再根据消息做出反应。一般来说,应用程序窗体运行顺序总是以如下的顺序运行的调用WinMain入口函数→注册窗口类→窗口实例化→建立消息循环→处理消息为了便于理解,我先写出完整的代码,然后再逐步的根据代码和窗体运行顺序进行分析。/****************************************************Project:Win32App**File:Main.cpp**Edition:NULL**Coder:KingsamChen[MDSAGroup]**LastModify:2008-5-31**************************************************/#includewindows.h#includetchar.h//用于Unicode程序的头文件LRESULTCALLBACKWndproc(HWNDhwnd,UINTuMsg,WPARAMwParam,LPARAMlParam);intWINAPIWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,LPSTRlpCmdLine,intnCmdShow){WNDCLASSEXws;//定义结构注意:这里用的是WNDCLASSEXws.cbSize=sizeof(WNDCLASSEX);//返回结构大小这个选项是Ex结构中新增的ws.hbrBackground=(HBRUSH)COLOR_BACKGROUND;//背景颜色ws.hCursor=LoadCursor(NULL,IDC_ARROW);//鼠标指针样式ws.hIcon=LoadIcon(NULL,IDI_APPLICATION);//图标样式ws.hIconSm=LoadIcon(NULL,IDI_APPLICATION);//小图标同样是Ex新增的ws.hInstance=hInstance;//当前实例句柄ws.lpfnWndProc=Wndproc;//回调函数指针ws.lpszClassName=MyWindows;//窗口类名ws.lpszMenuName=NULL;//菜单名ws.style=CS_DBLCLKS;//接受双击窗体消息//CS_HREDRAW|CS_VREDRAW;ws.cbClsExtra=0;//无额外类存储ws.cbWndExtra=0;//无额外窗体存储if(!RegisterClassEx(&ws))//Ex的结构必须要Ex的注册函数{return0;//注册失败直接返回0}HWNDhWnd;hWnd=CreateWindowEx(0,//扩展样式MyWindows,//类名,就是注册时的类名ForExample,//标题栏文字WS_OVERLAPPEDWINDOW,//样式各属性均用默认值CW_USEDEFAULT,//窗体X值CW_USEDEFAULT,//窗体Y值CW_USEDEFAULT,//窗体宽度CW_USEDEFAULT,//窗体高度NULL,//父窗口句柄NULL,//功能菜单句柄hInstance,//应用程序实例句柄NULL//建立参数);if(!hWnd){return0;//失败返回}ShowWindow(hWnd,SW_SHOWNORMAL);//显示窗体UpdateWindow(hWnd);//更新窗体MSGmsg;//消息主循环while(GetMessage(&msg,NULL,0,0)){TranslateMessage(&msg);DispatchMessage(&msg);}return(int)msg.wParam;}//回调处理函数LRESULTCALLBACKWndproc(HWNDhwnd,UINTuMsg,WPARAMwParam,LPARAMlParam){switch(uMsg){caseWM_DESTROY:PostQuitMessage(0);break;caseWM_LBUTTONDBLCLK:MessageBox(NULL,Um...KingsamChenisaFucker,Fuker,MB_OK);break;default:returnDefWindowProc(hwnd,uMsg,wParam,lParam);break;}return0;}这里的注释比较少,而且很不全。这并不奇怪,因为要研究的东西太多,如果都放在代码里面个人感觉讲不清楚,打算一部分一部分的分离出来讲,所以索性注释少写一些。大家可以把这段代码敲进自己的电脑,然后编译,就会发现出现一个窗口,双击窗口就会弹出一个消息框。这么多代码仅仅实现了这些功能,怎么样,怕了吧?先别晕,幕后的东西准比你现在看到的要BT的多。所以啊,用C++写GUI就和陪PLMM逛街一样,是要付出代价滴--!那么现在,我们就一起来研究下,为什么一个窗体需要这么些代码~3.入口函数我们先来看看入口函数:intWINAPIWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,LPSTRlpCmdLine,intnCmdShow)上面的那行代码就是Windows程序的入口函数。就像C/C++程序都有一个main()函数一样,一个Windows程序都必须有一个WinMain()函数,它是程序的入口点,应用程序就是通过它从Windows获得运行所必要的信息。EveryWindows-basedapplicationmusthaveWinMainasitsentrypointfunction.WinMainperformsanumberoftasks,includingregisteringthewindowclassforthemainwindowandcreatingthemainwindow.WinMainregistersthemainwindowclassbycallingtheRegisterClassfunction,anditcreatesthemainwindowbycallingtheCreateWindowExfunction.FromMSDN根据上面MSDN对WinMain的描述,我们可以知道,WinMain会注册窗口类作为主窗体,创建并显示窗体。不仅如此,WinMain还会启动消息泵,进入消息循环。3.1入口函数名一般来说,可以作为Windows窗体的入口函数有2个:intWINAPIWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,LPSTRpszCmdLine,intnCmdShow);intWINAPTwWinMain(HINSTANCEhInstanc,HINSTANCEhPrevInstance,LPWSTRpszCmdLine,intnCmdShow);wWinMain用于Unicode字符的程序,WinMain则用于ANSI字符的程序。(不过MSWin2k之后的OS都是建立在Unicode之上,那么……)如果你用VC.NET作为IDE,你可能会发现_tWinMain这样的函数名,事实上,如果你对其进行跟踪,你就会在tchar.h文件里发现类似下面的代码#ifdefUNICODE#define_tWinMainwWinMain#else#define_tWinMainWinMain#endif也就是说,编译器会自动根据OS使用的字符对_tWinMain进行替换。而且MSM$更推荐在VC.NET里使用_tWinMain作为函数名。不过如果要使用_tWinMain,必须添加tchar.h这个头文件3.2调用虽然WinMain是Windows程序的入口函数,但是操作系统实际上并不调用你编写的入口函数。它调用的是C/C++运行时启动函数。该函数负责对C/C++运行时库进行初始化,这样,就可以调用malloc和free之类的函数。它还能够确保已经声明的任何全局对象和静态C++对象能够在代码执行以前正确地创建。下面是入口函数及其对应启动函数的参照表应用程序类型入口函数启动函数需要ANSI字符和字符串的GUI应用程序WinMainWinMainCRTStartup需要Unicode字符和字符串的GUI应用程序wWinMainwWinMainCRTStartup3.2.1调用约定在入口函数返回类型int的后面,大家能看到WINAPI这个东西。WINAPI是一种数据类型(WindowsDataTypes),它用于系统函数的调用约定(Callingconventionforsystemfunctions)详情参考附录事实上,WINAPI是一个宏(macro),如果你稍加跟踪,就会在几个.h文件中发现类似的代码#defineWINAPI__stdcall#defineWINAPICDECL#defineCDECL_cdecl也就是说,WINAPI实际指向的是__stdcall和_cdecl。至于这两个东东,我们待会再讲。如果你细心的话,可能会发现有些时候,WINAPI成了APIENTRY、PASCAL、FARPASCAL等关键字,而这些除了APIENTRY是新加入的之外,其他的都是被废除的旧的函数调用约定的宏。下面是MSDN对此的描述。The__pascal,__fortran,and__syscallcallingconventionsarenolongersupported.Youcanemulatetheirfunctionalitybyusingoneofthesupportedcallingconventionsandappropriatelinkeroptions.WINDOWS.HnowsupportstheWINAPImacro,whichtranslatestotheappropriatecallingconventionforthetarget.UseWINAPIwhereyoupreviouslyusedPASCALor__far__pascal.FromMSDN由此可见,M$推荐使用WINAPI来代替已经被废除的调用约定。不过为了保持兼容,你还是能在很多.h文件里看到WINAPI定义旧的调用约定,你甚至可能对
本文标题:The Analysis Of Windows Running Principle
链接地址:https://www.777doc.com/doc-3402372 .html