MFC的Main函数跑哪去了
习惯的思维
⽤习惯了C的⼈要看⼀个程序时⾸先会想到到那个main函数在哪,然后再顺着往下看.因为main函数作为程序的⼊⼝点,整个程序都是从那开始执⾏的.当在C++中SDK(win32 API project)开发时也继承沿⽤C的思维,是有个main函数,不过现在的main函数改名字了,叫WinMain,当然有时还有变体,⽐如叫_tWinMain,反正名字中总会带个Main,让我们⼀看就知道.⽽在QT中就跟C⼀样,就⽼实的来个标准的main函数.
我们会发现C++中可以有⼀个单独的main函数,不⽤包含在哪个类中,另外还有不属于任何类的全局变量或全局函数这⾃然就不是纯粹的⾯向对象语⾔了.所以说C++⽀持多种编程范式嘛,可以是跟C完全⼀样的⾯向过程范式,或者再加些普通的类就是基于对象的范式了,如果再⽤到继承和多态就是⾯向对象了,⽽要是⽤到模板就是泛型范式了.⽽且这些范式可以互相混合⽤.⽽C#就是纯的⾯向对象,所以它⾥⾯虽然也有main 函数,但也是要放在⼀个类⾥⾯去,⾄于具体放哪个类⽆所谓,你随便放.⼀般默认是放Program这个类⾥.当然并不是说纯的⾯向对象就⽐混合的范式好,应该各有优缺点.
哎扯得有点远了,⾔归正传.
SDK中的流程
开发⼀个带界⾯的SDK程序⼤致流程是这样的.⾸先⾃然是要有个main函数做⼊⼝点.然后按下⾯的步骤来(为了讨论⽅便,只说⼤概流程,代码也是不完整的)
int _tWinain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
MSG msg;
InitApplicatio(HINSTANCE hInstance)  //第1步,注册窗体类,并在这⾥指定了窗体过程WndProc
InitInstance(HINSTANCE hInstance, int nCmdShow)  //第2步,创建窗体
while (GetMessage(&msg, NULL, 0, 0))    //第3步消息循环,分派消息
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;  //第4步,退出程序
}
BOOL InitApplicatio(HINSTANCE hInstance)
{
return RegisterClass(...);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
CreateWindow(...); //创建窗体
ShowWindow(...); //显⽰窗体
深入浅出mfcUpdateWindow(...); //送出WM_PAINT
return TRUE;
}
LRESULT CALLBACK WndProc(...){ }
在MFC中⽣成⼀个有界⾯的程序⼤体过程也⼀样,只不过封装起来了.那我们感兴趣的就是两个问题.
1.MFC中有没有main函数了,如果有它跑哪去了?
2.如果有main函数,它⾥⾯的那4步涉及到的具体操作是否也跟win32 API⼀样?
下⾯我们就来⼀⼀解答下
MFC封装背后流程
实际上候捷那本深⼊浅出MFC⾥⾯有讲的很清楚了.不过由于讲的太详细了,有⼏⼗页,看的容易晕,⽽且他举的例都是⽼版本的MFC类,在新版本中⼀些类的函数会有⼀点点变化.
我这⾥就只概括的讲下最简洁的流程.先假如有类CMyApp继承⾃CWinApp吧
1.针对第⼀个问题,MFC⾥是有⽤到main函数的
// export WinMain to force linkage to this module
extern int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine, int nCmdShow);
就是这⼀个函数,在MFC的源⽂件appmodul.cpp中能看到这些代码,那这个main怎么被MFC调⽤的呢,你看那注释,是linkage to this module,也就是被链接器去调⽤的.准确说是被C-Runtime DLL,C运⾏时动态链接库调⽤的.
调⽤main的顺序
我们知道在MFC中能从代码⾥看到的⼊⼝点是定义⼀个全局的继承于CWinApp的类.⽐如CMyApp theApp;这样定义下.在C++中全局变量是先于main被执⾏的,所以先初始化theApp后才接着调⽤main
2.针对第2个问题,main函数⾥具体的操作.
知道了有main函数,你⼼⾥可能有⼀丝安慰了.但还是有些觉得不安的是这main函数⾥的具体操作是否跟SDK中的⼀样,是不是也来那么⼏步,先注册窗⼝再创建窗⼝之类的.
答案是MFC调⽤的main函数⼤概流程差不多是那样,但实现细节很不⼀样.我们看下上⾯说的AfxWinMain⾥⾯的内容是啥吧.你可以在winmain.cpp中看到详细代码.
把这个main函数简化⼀下,做的操作⼤概是这样,
AfxWinMain(...)
{
//先通过⼀个全局函数获得CWinApp和CWinThread的指针,因为调⽤main之前已经初始化了这两个类.CMyApp初始化时也会初始化他的⽗类CWinApp,及⽗类的⽗类CWinThread
CWinThread* pThread = AfxGetThread();
CWinApp* pApp = AfxGetApp();
//这下⾯⼏个函数就差不多是完成前⾯讲的SDK中的所有步骤
pApp->InitApplication();
pThread->InitInstance();
pThread->Run();
AfxWinTerm(); //结束程序
}
反正结束程序我们就不⽤管了,重点关⼼前⾯的三步,注册窗⼝,创建窗⼝,还有消息分派.
前⾯的SDK程序中也恰好有函数InitApplication 注册窗⼝, InitInstance创建并显⽰窗⼝.⽽Run函数你猜想可能是分派消息的..其实⼤体思路还是没错,但实现细节还是有蛮多区别.
pApp->InitApplication();这函数实际上并没有注册窗⼝.注册窗⼝,创建显⽰窗⼝全是在pThread->InitInstance();这函数中完
成,InitInstance是个虚函数,⽽且我们在⾃⼰的代码中会重写它.所以最后调⽤的是我们⾃⼰写的那个InitInstance函数,这就是⾯向对象⾥多态的功能了啊.你指针最终指向对应的⼦类定义的函数.
BOOL CMyApp::InitInstance()
{
m_pMainWnd = new CMyFrameWnd; //这张操作会注册并创建窗⼝,m_pMainWnd就是返回的窗⼝句柄
m_pMainWnd->ShowWindow(m_nCmdShow); //显⽰窗⼝
m_pMainWnd->UpdateWindow();
}
pThread->Run();是分派消息,你可以在thrdcore.cpp中查看CWinThreed的run函数的源码,下⾯摘了⼀点点.
// acquire and dispatch messages until a WM_QUIT message is received.
for (;;)
{}
不过关于消息的处理MFC⽤到了消息映射机制,⽐如复杂.这⾥不讨论了,反正⼤概就把CMyFrameWnd当成是窗⼝过程就⾏了.
总结起来可以这样简单的说,MFC中有main函数,但是由系统去调⽤.然后main函数⾥⾯执⾏的操作差不多,只不过它是通过CWinApp和CWinThread的指针去调⽤⼀些相关的函数.⽽指针嘛由于调⽤了虚函数,所以⽤到了⾯向对象中的多态,于是转来转去的.然后最难的地⽅可能就是消息机制在这⾥更复杂⼀点了.不能简单的与SDK中做⼀对⼀的对⽐.

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。