MFC/VC++ programmers generate their projects using App Wizard and are quite happy with that. Once in a while, you have a programmer who will ask you, what happened to
WinMain and he is normally satisfied with the answer given that
WinMain is hidden within the
MFC libraries. In this article I'll try and explain the life-cycle of a typical MFC program. Before I do that I'd like to introduce you to the smallest MFC program you can write that will show a window on screen, other than by using a MessageBox. How to start MFC window-programming
Smallest MFC window-programcpp code
//NWinApp.h
class CNWinApp : public CWinApp
{
public:
BOOL InitInstance();
};
cpp code
//NWinApp.cpp
#include <afxwin.h>
#include "NWinApp.h"
CNWinApp app;
BOOL CNWinApp::InitInstance()
{
CFrameWnd *pnframe=new CFrameWnd;
m_pMainWnd=pnframe;
pnframe->Create(0,"Buster");
pnframe->ShowWindow(SW_SHOW);
return TRUE;
}
So, what happened to good old WinMain?When you run your program the kernel first calls this function,
WinMainCRTStartup.
WinMainCRTStartup first initializes the CRT routines. Then it parses the command line and removes the filename portion and calls WinMain passing the parsed command line as lpszCommandLine. But then where is WinMain? It is defined in
appmodul.cpp which you can find in your
MFC\SRC directory. Here is how the function is implemented.
cpp code
extern "C" int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
// call shared/exported WinMain
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
As you will observe, WinMain simply calls
AfxWinMain.
AfxWinMain is defined in
winmain.cpp which you will find under your MFC\SRC directory. I'll list the function below exactly as it is defined.
cpp code
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)
{
TRACE0("Warning: Destroying non-NULL m_pMainWnd\n");
pThread->m_pMainWnd->DestroyWindow();
}
nReturnCode = pThread->ExitInstance();
goto InitFailure;
}
nReturnCode = pThread->Run();
InitFailure:
#ifdef _DEBUG
// Check for missing AfxLockTempMap calls
if (AfxGetModuleThreadState()->m_nTempMapLock != 0)
{
TRACE1("Warning: Temp map lock count non-zero (%ld).\n",
AfxGetModuleThreadState()->m_nTempMapLock);
}
AfxLockTempMaps();
AfxUnlockTempMaps(-1);
#endif
AfxWinTerm();
return nReturnCode;
}
As you can see the functions
AfxGetThread and AfxGetApp are used to get pointers to the CWinApp derived global object and the current thread. If you are surprised as to how the global CWinApp derived object already exists, relax, C++ programs will first create all global and static objects before execution begins. All that happens much before
AfxWinMain gets called. By the way, it must have been a slight shock to you to see a goto in there, eh?
Now there might be those of you who might be wondering where
AfxGetThread and
AfxGetApp got their information from. The answer is simple. Take a look at the CWinApp constructor in appcore.cpp. You'll find the following two lines.
cpp code
pThreadState->m_pCurrentWinThread = this;
and
cpp code
pModuleState->m_pCurrentWinApp = this;
pThreadState is a AFX_MODULE_THREAD_STATE* and pModuleState is a AFX_MODULE_STATE*.
Thus when we create our global CNWinApp object, it's constructor gets called and the AFX_MODULE_STATE structure is setup properly. Now AfxWinInit is called and this function initializes the MFC framework. Now there is a call to InitApplication [this is for backward compatibility with 16-bit applications]. Now it calls the InitInstance of the CWinApp derived object. And as you can see from our code listing above we have overridden InitInstance and created a CFrameWnd object there. I'll repeat the code snippet here so that you won't have to scroll upwards.
cpp code
BOOL CNWinApp::InitInstance()
{
CFrameWnd *pnframe=new CFrameWnd;
m_pMainWnd=pnframe;
pnframe->Create(0,"Buster");
pnframe->ShowWindow(SW_SHOW);
return TRUE;
}
I have created my
CFrameWnd object on the heap, otherwise the moment InitInstance exits, the window will get destroyed. I have also set m_pMainWnd to point to my CFrameWnd window. Once InitInstance returns [if it returns false an error is assumed, so we return true], CWinApp::Run is called. Within the Run function is implemented our default message loop. Run keeps getting and dispatching messages till it receives a WM_QUIT message. Once WM_QUIT is received Run returns and control returns to AfxWinMain which performs clean-up and lastly calls
AfxWinTerm which deletes all the global application structures that were created.
Well, that's it. Pretty amusing to think that all this while you were writing MFC applications and you never bothered to think about what was happening under the hood.
- Attachments
-
- SrcFirstProg.zip
- (2.5 KiB) Downloaded 758 times