??xml version="1.0" encoding="utf-8" standalone="yes"?> 声明Q?/P>
本h最q也在看孙老师的视频,Z加强理解Q所以想一些读书笔记。但是在CSDN上一搜烦Q发现已l有朋友做了相关W记。根据面向对象的“扎쀝观点,Z解决力_力,所以我打算在他们的基础上添加、修攏V应该不涉及(qing)著作权什么的东东吧?Q?/P>
我在BLOG.CSDN.NET/LEWISLAU上搜索了?nbsp;Q有两位朋写了相关笔讎ͼ而且都是一L(fng)Q。不知道谁才是原作者,所以列Z位BLOG地址Q?/P>
http://blog.csdn.net/hhitjsj021 http://blog.csdn.net/d007879 以后我会(x)在前辈的基础上修攏V发文!呵呵Q承嘛Q?/P>
windowsE序设计是种事g驱动方式的程序设计,主要Z消息的。当用户需要完成某U功能时Q需要调用OS某种支持Q然后OS用L(fng)需要包装成消息Qƈ投入到消息队列中Q最后应用程序从消息队列中取走消息ƈq行响应?/P>
MSG Structure -------------------------------------------------------------------------------- The MSG structure contains message information from a thread's message queue. Syntax typedef struct { 句柄Q资源的标识Q操作系l通过句柄指到资源。常见的句柄有图标句柄(HICONQ,光标句柄QHCURSORQ,H口句柄QHWNDQ,应用E序句柄QHINSTANCEQ?BR> 使用VC~程除了良好的C基础外还需要掌握两斚wQ?BR>一Q消息本w。不同消息所代表的用h作和应用E序的状态?BR>二,对于某个特定的消息来_(d)要让OS执行某个特定的功能去响应消息?/P>
创徏一个完整的H口需要经q下面四个操作步骤:(x) Windows提供的窗口类Q?BR>typedef struct WNDCLASS { HICON可以由LoadIcon 赋|它有两个参数HINSTANCE和LPCTSTRQ通常W一个参Cؓ(f)I,只对W二个参数赋|卛_标的IDQ?BR>HCURSOR同HICON H口cL册:(x) BOOL GetMessage( 回调原理Q当应用E序受到l某个窗口的消息Ӟ应调用某一函数来处理这条消息。这一消息有操作系l自动完成?/P>
注:(x)函数名可以用以表C函C码的首地址Q函数指针)Q额外数据通常??/P>
题记Q前几天出去感受一下,感触颇深Q发觉自q的很逊。现在回到清静的校园Q自p得应该更加努力。社?x)真的不是我们想的那P工作也不像学?fn)一栯松。只希望各位朋友在走出校门,q向C会(x)的过E中Q一切顺利! 在成都待了一个星期,切的说只有六天。在q六天里面,我完完全全是一个打工的Q一个社?x)上的hQ一个程序员。听上去多牛BQ程序员啊,q个可是我梦寐以求的职业啊,可是事实上一切都不是我想的那栯煌。我q几天脑里反复现一句话Q程序员的的确是十分辛苦的职业?BR> 我所在的公司是一家游戏外挂公司,专门做游戏外挂。从C会(x)的角度来_(d)q种“勾搭”只能暗操作,如今却还明目张胆的“开张营业”,实搞笑Q从技术的角度来说Q游戏外挂,利用HOOK拦截数据包、解密、修攏V封包,h都是安全斚w的比较牛B的技术,在没有进q个公司之前Q我没有惌一q以内会(x)接触到这些底层的技术。所有说公司Ҏ(gu)来说Q有些失望、但是也有一些期望?BR> 以前在阻I家乡Q的一些小IT公司也玩儿过Q但是这ơ是独自在外Q什么问题都要自p冻I所有从各个斚w来说Q都是自q一些新的尝试。不q还好的是,q次我是和朋友一切去成都“实?fn)”。呵呵,不过我比他好的就是,他在?sh)信设计规划院实习(fn)三个月Q没有实?fn)工资,三个月{正;而我实习(fn)一个月实习(fn)工资一千,一个月后{正,Ҏ(gu)情况而定工资Q表现的好的话在3K左右Q听上去挺吸引h的,但是真的很篏Q?BR> 我们到成都只用了2个小时找了一处住房,合租Q?50一月,只有一张床和一个书桌(天啦Q成都的房h(hun)真TMD的吓MhQ。唯一比较ƣ慰的是我们住在川大外面Q步行到川大只要5分钟Q原先设想的是每天下班去川大教室M自习(fn)Q可是现实往往与设x很大的差距,每天回到家篏的简直书都不想看。(白天在公司至看6个小时以上的文Q对q那?5寸的CRTQ我直万分的不爽Q公叔R?0多h我一个用CRT昄器,我靠Q欺负我Q?Q)每晚和朋友在川大转?zhn)两圈回ȝ觉,q种生活Q让我回忆v两岁的时候家里还不景气的状态。汗Q?BR> a归正转,q是说工作的事儿Q每天我7Q?0起床Q解军_所有问题大U?Q?0到达车站Q搭?9路,利的话8Q?5作用能到N升桥Q公司所在地Q,唉,不禁汗颜Q每天要白白费大约90分钟旉搭RQ在成都人看来,q还近的(大城市的是比我们q些农民z盘Q?点左叛_辑օ司,不出意外的话只有我旁边的仁兄比我早到。(公司老大考虑技术部l常加班Q所以允许技术部的兄弟们9Q?0上班Q这个还够h性化。)q位仁兄待会(x)要重点介l,公司里面p他的最熟,特牛B。说到加班,我突然想hd司和技术部老大谈的时候,老大特别交代Q“如果你加班的话Q晚上可以打车回家。拿上小,W二天回公司报销。”我汗,原来q个公司加班p喝水一样随ѝ?BR> 我才到公司,我的工作是不停的看文档Q中文的、英文的都看。(我都怀疑我居然能看懂英文)老大l我的Q务很单,׃句话Q“利用HOOK抓取E序的数据包。”他q特别交代,“不需要你解密数据包,抓取可以”看上去降低了很大难度哦Q但是有两个证明q个我这个公怸是我现在的水q够接受的。第一个冯SIRQ他说这个东西对于我来说Q非帔R常具有挑战,希望我能创造奇qV(汗,奇迹Q)W二个是李SIRQ回学校后我l他讲述我的“作业”,他说Q哦Q这个东西和我师兄研I生的毕业设计很像。(我再一ơ汗颜)我承认自q喜欢有挑战的工作Q但是我q是很有自知之明Q确切的说我很自量力?BR> 我每天的工作是看文,看的我要疯,HOOK属于WINDOWS的核心技术,于操作pȝ底层Q用于拦截操作系l发出的消息。对于我来说决不是简单的事儿Q所以不敢懈怠,我每天就GOOGLE,MSDN上搜d于它的一切,中文的英文的都看Q要疯!看看我旁边的家伙Q现在就来说说他Q他是测试部的,他的工作是不停的耍各U各L(fng)游戏Q居然耍游戏真的能扑ֈ工作Q我直ؓ(f)我们学校的兄弟们感到ƣ慰Q,有的时候网速比较卡Q他没法耍游戏,只能委屈一下看说Q这L(fng)工作让我慕的不行。偶?dng)看C再不断的抄录房信息Q就问他是否要买ѝ他_(d)恩。我q闷了Q看上去q纪轻轻的就x子,公司耍游戏的难不成拿8K一个月Ql问刎ͼ“你工作几年了哦Q都有钱买房了?”“我工作了都五年了,我一个月1500Q一q存不到5000。靠自己的话都不知道什么时候才能买哦、。其实是我父母给钱。”终于发C个比我还强的Z。事后,我给我爸妈打?sh)话汇报我的q况Q闲聊到此事儿,只听?sh)话那边一片寂静,我爸耍句“你l我说这些,难不成你q要我们l你准备׃房子Q”(上帝作证Q我l对没那么想Q?BR> 每天吃午饭大U半时不面寚w可恶的CRTQ其余时间就逃不q浩劫,现在用到W记本是爽哦Q至不是CRT的。公叔R面基本上都要玩儿游戏Q还有h被盗q帐受(我们都是q地下生意的Q还被h安吃黑Q!Q我想Q写个木马对于我们公司的几个高手来说l对是小菜一,但是自己的帐可盗了q是没办法,说不定就是自q木马盗的自己的帐受?BR> 公司q有一个女E序员,佩服啊。今天也是三八妇奌Q向牛B的女E序员致敬! 孙鑫VC讲W记--WINDOWSE序内部q行原理
HWND hwnd; //指示一个窗口的句柄Q改消息和那个窗口相兌?BR> UINT message; //具体的消息,用无W号整Ş表示
WPARAM wParam; //关于消息的附加参?BR> LPARAM lParam; //同上
DWORD time; //32位整敎ͼ表示消息被投递出ȝ旉
POINT pt; //表示光标位置
} MSG, *PMSG;
例如Q当按下按键?x)发送出WM_CHAR消息 通过消息的附加参敎ͼ保存对应的ASCII码,卛_知道按下的是那个键?/P>
消息队列Q?BR>每个应用E序OS都ؓ(f)它徏立一个消息队列,消息队列是个先进先出的缓冲区Q其中每个元素都是一个消息,OS生成的每个消息按先后顺序放q消息队列中Q应用程序L取走当前消息队列中的W一条消息,应用E序取走消息后便知道用户的操作和E序的状态,然后对其处理x息响应,消息响应通过~码实现?/P>
WindowE序入口Q?BR>int WINAPI WinMain(
HINSTANCE hInstance, // 当前事例句柄?BR> HINSTANCE hPrevInstance, // 先前事例句柄?BR> LPSTR lpCmdLine, // 命o(h)行指?BR> int nCmdShow // Q窗口)昄的状?BR>);
说明QWinMain函数是WindowsE序入口点函敎ͼ由O(jin)S调用Q当OS启动应用E序的时候,winmain函数的参数由O(jin)S传递的?/P>
一Q设计一个窗口类Q如QWNDCLASS wndcls;
二,注册H口c; 如:(x)RegisterClass(&wndcls);
三,创徏H口Q?nbsp; 如:(x)CreateWindow(),CreateWindowEX();
四,昄?qing)更新窗口。如QShowWindow(),UpdateWindow();
说明Q创建窗口的时候一定要Z已经注册的窗口类.
UINT style; //H口的类?BR> WNDPROC lpfnWndProc; //H口q程函数指针Q回调函敎ͼ
int cbClsExtra; //H口c附加字节,cȝ口所׃n。通常0?BR> int cbWndExtra; //H口附加字节。通常设ؓ(f)0?BR> HANDLE hInstance; //当前应用E序事例句柄?BR> HICON hIcon; //图标句柄 LoadIcon();
HCURSOR hCursor; //光标句柄 LoadCursor();
HBRUSH hbrBackground; //d句柄 (HBRUSH)GetStockObject();
LPCTSTR lpszMenuName; //菜单名字
LPCTSTR lpszClassName; //cȝ名字
} WNDCLASSQ?PWNDCLASS;
H口cdstyleZ个变量,该变量每一位对应着一U特性。对应ؓ(f)1Ӟ有该U特性;对应?Ӟ无该U特性。ؓ(f)了方便记忆,用一些宏对应一些特征,通过取反Q~Q和怸Q?amp;Q可以取消一些特性?nbsp; 通常讄?CS_HREDRAW | CS_VREDRAW"表示垂直重绘和水q重l?/P>
HBRUSH 使用GetStockObject函数Q它可以用来获取W、画列字W、调试板的画列用时要用HBRUSH做一直强制{化。因为GetStockObjectq回值和HBRUSH不同?/P>
ATOM RegisterClass(
CONST WNDCLASS *lpWndClass // address of structure with class
// data
);
//注意Q是使用地址W?/P>
创徏H口Q?BR>HWND CreateWindow(
LPCTSTR lpClassName, //注册H口cdQ用引号
LPCTSTR lpWindowName, //H口标题Q用引号
DWORD dwStyle, //H口cdQ风|通常?WS_OVERLAPPEDWINDOW)
int x, // H口X坐标
int y, // H口X坐标
int nWidth, // 宽度
int nHeight, // 高度
HWND hWndParent, // 指向父窗口的句柄
HMENU hMenu, // 菜单句柄
HANDLE hInstance, // 当前实例的句柄,由WINMAIN传?BR> LPVOID lpParam // WM_CREATE附加参数传入指针
);
创徏H口的时候会(x)发送WM_CREATE消息
昄和更新窗口窗口:(x)
BOOL ShowWindow(
HWND hWnd, // handle to window
int nCmdShow // show state of window
);
BOOL UpdateWindow(
HWND hWnd // handle of window 送出WM_PAINT消息
);
消息循环
MSG msg;
while(GetMessage(&msg,...)) //从消息队列中取出一条消?BR>{
TranslateMessage(&msg); //q行消息Q如键盘消息Q{化。{化过E不?x)媄响原消息Q只?x)创建新的消息?BR> DispatchMessage(&msg); //分派消息到窗口的回调函数处理,QOS调用H口回调函数q行处理Q?BR>}
LPMSG lpMsg, // 消息l构体变?BR> HWND hWnd, // 句柄Q那个一个窗口?为NULL则ؓ(f)所有窗口句?BR> UINT wMsgFilterMin, // 最消息|?时返回所有消?BR> UINT wMsgFilterMax // 最大消息?BR>);
H口q程函数Q回调函敎ͼ原型Q?BR>LRESULT CALLBACK WindowProc( //q里W(xu)indowProc是个代号名字?BR> HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
说明Q两U函数调用约定(__stdcall ?__cdeclQ:(x)
#define CALLBACK __stdcall
//__stdcall 标准调用预定Q是PASCAL 调用U定Q象DELPHI使用的就是标准调用约?BR>#define WINAPIV __cdecl
// __cdecl 是C 语言形式的调用约定?BR>主要区别Q函数参C递顺??对堆栈的清除上?BR>问题Q除了那些可变参数的函数调用外,其余的一般都是__stdcallU定。但 C/C++~译默然的是__cdeclU定。所以如果在VC{环境中调用__stdcallU定的函敎ͼ必须要在函数声明的时加上 __stdcall 修饰W,以便对这个函数的调用是用__stdcallU定Q如使用DELPHI~写的DLL时候)?BR>QVC中可通过q途径修改Qproject|settings..|c/c++|...)
在窗口过E函C通过一lswitch语句来对消息q行处理Q?BR>如:(x)
LRESULT CALLBACK WindowProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
switch(uMsg)
{
case WM_PAINT:
...
break;
case ...
break;
case WM_CLOSE:
//DestroyWindow(hwnd);
//销毁窗口,q发送WM_DESTROY消息?BR> break;
case WM_DESTROY:
//PostQuitMessage(0);
//发送WM_QUIT消息到消息队列中Q请求终止?BR> //GetMessage()取到WM_QUIT消息后,q回0Q退出消息@ // 环,从而终止应用程序?BR> break;
default:
return DefWindowProc(hwnd,uMsg,wParam,lParam);
//用缺省的H口q程处理我们不感兴趣的消息(其它消息Q?BR> //q是必须的?BR> }//switch
return 0;
}//WindowProc
响应WM_DESTROYQ调用PostQuitMessage(int)l束q程。它?x)投递一个WM_QUIT消息Ҏ(gu)息队列中。当消息循环的GetMessage取到WM_QUIT消息Q则q回0Q程序结束?BR> 另外对于不感兴趣的消息要景象~省的处理,使用DefWindowProcQ)内ؓ(f)H口的参数?/P>
关于DC句柄获取Q?BR>a)使用BeginPaint(),EndPaint()寏V注意只能在响应WM_PAINT消息时用?BR>b)使用GetDc(),ReleaseDC()寏V注意他们不能在响应WM_PAINT中?BR>
每天下午六点Q其实那个时候我都可以离开了,但是技术部所有同僚加班(除了我,因ؓ(f)我是新来的,q做不了事儿。)所以我也不好走的太快,慢慢腾腾的磨到六点一Ld公司Q回家咯?BR> 上面所有行文,也许你还没感觉到辛苦Q因为有些细节的事儿再说_(d)(x)
我每天上班搭乘公车,大约一p?0分钟Q绝Ҏ(gu)无多。上班还好,人ƈ不多Q我大概描述下我下班的情况,我第一天下班等了两?9路后换成77路,l果多步行了四十分钟的样子,到家的时候都?0Q?0了,q没吃饭。后来我?9路,大概情况是,本来是前门透币上R的,我只能从后门上,上R后脓(chung)在R门,途中路过要下车的我还要从后门下来让别Z车。我靠,q下感觉到毛大爷真不对,啥子人多力量大,瞎扯Q?BR> 回到住的地方Q吃q饭的时间是最难打发的。以前在家熬夜,也不可能睡的太早Q大概每天就十一点的样子睡,期间的时间就不知道如何处理?Q一切在家时候就玩儿?sh)脑Q现在连个电(sh)视都看不刎ͼ感觉自己都与外界隔绝了一栗每天就到川大的散散步步Q然后回住的地方w在床上Q发几条短信Q打几个?sh)话Q便早早的睡厅R这个是让我_上最难以忍受的地斏V我靠,我是IT人哦Q信息时代哦Q!q到底是什么见鬼的生活Q我最受不了就是这一炏V不q还好,我是和朋友一起出来的Q晚上还可以闲聊几句Q不q想想以后要是一个h出门在外Q我估计自己早晚要疯?BR> 晚上Q书也不想看Q要是以后还是这个样子,我估计这辈子只能当一辈子的垃圄序员了?BR> 有的时候我惻IE序员的非常辛苦,自己选择q条道\对不寏V后来想了想Q努力做好每一件事儿,L一天我怿自己的能力得到锻g后,我相信态度军_一切?BR> 唉,现在回到学校了,真的很多感?zhn)Q大家还是一起努力吧Q?BR> 现在感觉做程序真的很累,而且付出和收入显然不是成正比的,现在有点上了D又无法回_(d)仔细x又有点相q求库克舚w那样传奇的h生,矛盾Q?/P>
之来龙去?BR> 题记Q前些日子一直想写这个东西,做了一个开头放在我的BLOG?但是名ؓ(f)<MFC框架E序WINMAIN函数分析>)Q到后来没有再了Q其实那只是冰山一?具体MFC是怎么q行的,q是没有交待清楚Q虽然自qBLOG很少有h光顾Q但是本着做事儿就要做到底的心态,l箋完成该文?BR> 说明Q?、本文作者在VS2003中跟t代码,此代码ؓ(f)VS2003中拷贝,使用MFC7?BR> 2、不同框架的MFCE序由所不同Q本文以单文ؓ(f)例?BR> 3、本文读者需要有一定的SDK的基Q不需要太多,臛_知道它的基本框架和来龙去脉即可!
4、文章只惌v到说明作用,所以代码会(x)有一些删除?BR> 学MFCQ竟然还不知道MFC的MAIN函数在什么地方?怎么q行的?实在不高明?BR> 看过候捷(JJHOU)老师的《深入浅出MFC》的Q对它一定很熟?zhn)。呵呵,本文是献l没有看q那本书Q但是又很希望学?fn)MFCE序设计的朋友的。(没有看过那本书的朋友q不赶快MQ)其实本文Q主要是寏V深入浅出MFC》第六章的一个ȝ和补充Ş了!Q本文有该书不同的地方,也有一些笔者自q见解Q)
a归正传?BR> 假如你用AppWizard一步一步NEXT下来Q然后在CLASSVIEW中去扑֯WINMAIN函数Q那么你只有失望。MFC最大的特点是什么?装QMFC的确装的太好了Q以至于很多惛_?fn)MFC的h都望而却步。闲话少_(d)q是l箋我们今天的话题,MAIN函数Q实话告诉你吧,即你搜索所有的MFC生成的文Ӟ都无法发现WINMAIN的字|那么它就q在什么地方呢Q?BR> 我相信你已经惛_QMAIN函数应该在主要的应用E序文g中。难道是“?zhn)定义的程序?cpp”这个文Ӟ不错是它。再Crtl+F一下,看有没有我们要找的WINMAIN函数Q看来你又要失望了,但是你注意有q样一句:(x)
/////////////////////////////////////////////////////////////////////////////
// The one and only CMyApp object
CMyApp theApp; //本h建立的工E名为My?BR>
是不是很特别Q再注意一下那句注释“The one and only CMyApp object”,每个应用E序有且只用一个CMyApp对象。我想你应该惛_了,W(xu)inMain函数每个E序也只能有一个,那么q个全局对象跟WinMain函数肯定有莫大的关系Q没错,怿你的直觉?BR> 特别注意Q深晓C++l节的h一定知道,全局对象优先于MAIN函数执行的道理。如果你不知道也没关p,那么我在q里告诉你:(x)“全局对象优先于MIAN函数执行Q且构徏于栈中,切记Q切讎ͼ?BR> 现在Q我们该深入WinMainq行机制了,切的说Q应该是MFC的机Ӟ
首先Q看看MFC的库文g把,它能l我们带来许多惊喜。(vc6的相应的目录是\Microsoft Visual Studio\VC98\MFC\SRCQVC7相应的目录是\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\src\mfcQ?BR> 现在我们׃q个全局下手Q开始今天的旅途?BR> CMyApp theApp;
此时Q系l会(x)执行CMyApp的父c(CWinAppQ构造函敎ͼ再执行CMyApp的构造函数。(先有老爹Q再有儿子!Q,此时׃(x)调用CWinApp的构造函数?BR>
CWinApp的构造函敎ͼ在VC提供的MFC代码中以“文中的一个字或词l”的方式查询关键字,此时打开APPCORE.CPPQ以下用相同搜索方式,不再复述。)扑ֈ以下内容Q?BR> CWinApp::CWinApp(LPCTSTR lpszAppName)
{
if (lpszAppName != NULL)
m_pszAppName = _tcsdup(lpszAppName);
else
m_pszAppName = NULL;
// initialize CWinThread state
AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
AFX_MODULE_THREAD_STATE* pThreadState = pModuleState->m_thread;
ASSERT(AfxGetThread() == NULL);
pThreadState->m_pCurrentWinThread = this;
ASSERT(AfxGetThread() == this);
m_hThread = ::GetCurrentThread();
m_nThreadID = ::GetCurrentThreadId();
// initialize CWinApp state
ASSERT(afxCurrentWinApp == NULL); // only one CWinApp object please
pModuleState->m_pCurrentWinApp = this;
ASSERT(AfxGetApp() == this);
... ...
}
OKQ就到这里就可以了,仔细看上面代码,它已l完成了应用E序U程额的启动Q它l予了我们程序的生命。现在请注意Q?BR> pThreadState->m_pCurrentWinThread = this;
pModuleState->m_pCurrentWinApp = this;
q两行代码其实都是做的一件事ѝ?BR> q段代码的意思是Q获得了CMyApp的全局对象的this指针?此时你肯定要疑问Qؓ(f)什么是CMyApp的指针?this目前是在CWinApp中啊Q?nbsp; Ҏ(gu)我的{案是,可是你是由CMyApp的对象引发的CWinApp的构造啊Q!)q个指针可非一般的人物Q稍后我们的很多工作都要靠它完成?BR> CWinApp之中的成员变量将因ؓ(f)theAppq个全局对象的诞生而获得配|和初始倹{?BR> 构造完父类Q现在构造子cR可是我们看刎ͼAppWizardl我们的子类里它什么也没做Q是的,q一切都听从你的安排Q?BR> CMyApp::CMyApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
接下来就是今天的主角儿了Q搜索关键字“WinMain”,出现很多文g。别急,因ؓ(f)现在我们应该先看看WinMain的声明。打开appmodul.cppQ?/P>
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
// call shared/exported WinMain
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
q里_tWinMain是ؓ(f)了支持UNICODE而命名的一个宏Q真正v作用的是AfxWinMainQ注意看看它的参敎ͼ是不是和SDK的WinMain函数一P
现在再搜索下AfxWinMainQ其实在winmain.cpp中:(x)
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
ASSERT(hPrevInstance == NULL);
int nReturnCode = -1;
CWinThread* pThread = AfxGetThread();
CWinApp* pApp = AfxGetApp();
// AFX internal initialization
if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
goto InitFailure;
// App global initializations (rare)
if (pApp != NULL && !pApp->InitApplication())
goto InitFailure;
// Perform specific initializations
if (!pThread->InitInstance())
{
if (pThread->m_pMainWnd != NULL)
{
TRACE(traceAppMsg, 0, "Warning: Destroying non-NULL m_pMainWnd\n");
pThread->m_pMainWnd->DestroyWindow();
}
nReturnCode = pThread->ExitInstance();
goto InitFailure;
}
nReturnCode = pThread->Run();
... ...
}
此段代码注意五个l节Q?BR> CWinApp* pApp = AfxGetApp();
意ؓ(f)获得对象指针Q其实就是刚才那个THIS。不记得了?指向CMyApp的那个!q值得注意的是QAfx意是全局的,随时你都可以调用它?AFX是MFC开发小l的开发代P意ؓ(f)Application Framework 传说X只是Z好看Q没实在意思?Q?
if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
AfxWinInit完成了线E的初始化和H框cȝ注册。具体参看appinit.cpp中的定义?BR> if (pApp != NULL && !pApp->InitApplication())
其实pApp和pThread是同一个指针,都是指向CMyApp的指针,q里因ؓ(f)CMyApp中没有定义InitApplicationQ实际上p用的CWinApp::InitApplicationQ)Q完成了MFC的内容管理?BR> if (!pThread->InitInstance())
因ؓ(f)CMyApp中改写了它,所以调用CMyApp中的Q其实它也是初始化工作。此时也完成了默认窗口类的定义。假如你熟?zhn)SDK~程的话Q一定不?x)忘记窗口类的设计、注册、创建、现实及(qing)更新的步骤,此时MFC以ؓ(f)你设计好了默认的H口cR?BR> 现在你不要疑问,InitApplication()和InitInstance()有何不同Q?BR> {案是,假如你执行一个程序,于是两个函数都会(x)被调用;当你在不关闭前一个程序的前提下,再执行一个程序,那么只执行后一个函数?BR> nReturnCode = pThread->Run();
q个一步骤在《深入浅出MFC》中被成为程序的zL源头Q在我看来它?yu)是你开车踩沚w的步骤。待?x)我们?x)具体阐述Q?BR>
在设计窗口类以后Q就应该是注册,MFC自动调用(跌{?AfxEndDeferRegisterClassQWINCORE.CPP中)Qؓ(f)你注册了五个H口c,分别是:(x)AfxWndQAfxCreateBarQAfxMDIFrameQAfxFrameOrViewQAfxOleControl以上H口cMFC自动{化成独立无二的类名,供其调用?BR> 在窗口的注册以后Q就应该是窗口的创徏工作Q此时会(x)调用CFrameWnd::Create(),该代码位于WINFRM.Cpp?BR>BOOL CFrameWnd::Create(LPCTSTR lpszClassName,
LPCTSTR lpszWindowName,
DWORD dwStyle,
const RECT& rect,
CWnd* pParentWnd,
LPCTSTR lpszMenuName,
DWORD dwExStyle,
CCreateContext* pContext)
{
HMENU hMenu = NULL;
if (lpszMenuName != NULL)
{
// load in a menu that will get destroyed when window gets destroyed
HINSTANCE hInst = AfxFindResourceHandle(lpszMenuName, RT_MENU);
if ((hMenu = ::LoadMenu(hInst, lpszMenuName)) == NULL)
{
TRACE(traceAppMsg, 0, "Warning: failed to load menu for CFrameWnd.\n");
PostNcDestroy(); // perhaps delete the C++ object
return FALSE;
}
}
m_strTitle = lpszWindowName; // save title for later
if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext))
{
TRACE(traceAppMsg, 0, "Warning: failed to create CFrameWnd.\n");
if (hMenu != NULL)
DestroyMenu(hMenu);
return FALSE;
}
return TRUE;
}
其中完成了窗口的创徏工作Q里面还涉及(qing)扩展风格的调用CreateExQ具体细节请参看MSDN?BR>
此时你不要问,我们的事儉K让MFC做完了?工业化生产出来的H口都是千篇一律啊Q我要有我自q风格Q?BR> 别急,MFCl用h供了一个修改窗口设计的Z(x)那就是:(x)PreCreateWindow(CREATESTRUCT& cs) 你在MSDN中查询一下CREATESTRUCTq个l构体,你会(x)发现它和我们的CreateWindow几乎是一模一Pq个是MFC留给你修改窗口的一个机?x)。在PreCreateWindowӞ?x)蟩到CWnd::PreCreateWindowQ里面有一个宏QAfxDeferRegisterClassQ它的作用是Q如果该H口cL有被注册Q那么就注册它;如果注册了,׃么也不管Q?BR> H口cȝ设计、注册、创建都已经完成Q现在只剩下更新和显CZ。这些工作都交由 CMyApp::InitInstance()完成Q?BR> m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
现在if (!pThread->InitInstance())的工作已l完成,按照MAIN函数的内容,接下来该QnReturnCode = pThread->Run()?BR> 此时应该调用CMyApp的Run()函数Q但是在CMyAppcMQ根本没有声明或定义q样一个函敎ͼҎ(gu)多态性的原来Q指针迁升,指向CWinApp::Run()Q其代码位于APPCORE.CPP中:(x)
int CWinApp::Run()
{
if (m_pMainWnd == NULL && AfxOleGetUserCtrl())
{
// Not launched /Embedding or /Automation, but has no main window!
TRACE(traceAppMsg, 0, "Warning: m_pMainWnd is NULL in CWinApp::Run - quitting application.\n");
AfxPostQuitMessage(0);
}
return CWinThread::Run();
}
最后你?x)发玎ͼ它由调用了一个CWinThread::Run()Q此时你q不到CWinThread::Run()的代码了Q至笔者没有找刎ͼ因ؓ(f)微Y只提供了部分MFC代码。)但是你可以在MSDN中找到CWinThread::Run()的描qͼ(x)
Run 控制U程的函数。包含消息܇。一般不重写?
再具体点是Q?BR> Run acquires and dispatches Windows messages until the application receives a WM_QUIT message. If the thread's message queue currently contains no messages, Run calls OnIdle to perform idle-time processing. Incoming messages go to the PreTranslateMessage member function for special processing and then to the Windows function TranslateMessage for standard keyboard translation. Finally, the DispatchMessage Windows function is called.
Run is rarely overridden, but you can override it to implement special behavior.
This member function is used only in user-interface threads.
原来它把消息循环包装了一下,在MFC中称为消息映(message mapQ的东西Q至于消息映的具体l节本h?x)另写文章说明?BR> OKQMFC不再秘Q掌握了它的来龙去脉Q再看其他的MFC书籍的时候,q道我该怎么做?Z么我要这样做QvC知其然又知其所以然的效果,q就是我所q求的技术境界?BR>