Win32应用程序有条明确的主线:
(1) 进入WinMain函数
(2) 设计一个Window
(3) 注册这个Window
(4) 建立这个Window
(5) 显示和更新这个Window
(6) 进入消息循环
好,我就先找WinMain函数吧。
我在C:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\src\mfc的appmodul.cpp的23行中找到了以下代码:
extern "C" int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine, int nCmdShow)
#pragma warning(suppress: 4985)
{
// call shared/exported WinMain
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
_tWinMain是一个宏,详细为: #define _tWinMain WinMain
所以这个确实是我们要找的WinMain函数
从代码中看出,WinMain将参数全部交给AfxWinMain,来处理。
好,我又找AfxWinMain这个函数。
我在winmain.cpp的19行找到了AfxWinMain函数。
代码:
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine, int nCmdShow)
{
ASSERT(hPrevInstance == NULL); // ASSERT在程序运行时它计算括号内的表达式,如果表达式为FALSE (0),
// 程序将报告错误,并终止执行。如果表达式不为0,则继续执行后面的语句。
// ASSERT只有在Debug版本中才有效,如果编译为Release版本则被忽略。
// assert()的功能类似,它是ANSI C标准中规定的函数,它与ASSERT的一个重要区别是可以用在Release版本中。
int nReturnCode = -1;
// AfxGetThread和 AfxGetApp 都是全局函数
CWinThread* pThread = AfxGetThread(); // 获得正在执行的线程,Must be called from within the desired thread.
CWinApp* pApp = AfxGetApp(); // 获得A pointer to the single CWinApp object for the application
// AFX internal initialization
// This function is called by the MFC-supplied WinMain function, as part of the CWinApp initialization of a GUI-based
// application, to initialize MFC.
if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
goto InitFailure;
// App global initializations (rare)
if (pApp != NULL && !pApp->InitApplication()) //InitApplication已经过时,用InitInstance代替,完成MFC内部管理方面的工作
goto InitFailure;
// Perform specific initializations
if (!pThread->InitInstance()) // 初始化Instance,在每个 a copy of the program runs的时候,虚函数
{
if (pThread->m_pMainWnd != NULL)
{
TRACE(traceAppMsg, 0, "Warning: Destroying non-NULL m_pMainWnd\n");
pThread->m_pMainWnd->DestroyWindow(); // m_pMainWnd holds a pointer to the application's main window.返回一个CWnd.
// cWnd Destroys the attached Windows window.
}
nReturnCode = pThread->ExitInstance(); // to exit this instance of the thread
goto InitFailure;
}
nReturnCode = pThread->Run();
InitFailure:
#ifdef _DEBUG
// Check for missing AfxLockTempMap calls
if (AfxGetModuleThreadState()->m_nTempMapLock != 0)
{
TRACE(traceAppMsg, 0, "Warning: Temp map lock count non-zero (%ld).\n",
AfxGetModuleThreadState()->m_nTempMapLock);
}
AfxLockTempMaps();
AfxUnlockTempMaps(-1);
#endif
AfxWinTerm();
return nReturnCode;
}
找到了WinMain函数后,看了下MFC为我生成的类:
1. CTestApp 2. CTestView 3. CMainFrame 4. CTestDoc 5. CAboutDlg
查看CTestApp.cpp,发现了一个全局的CTestApp theApp,因为全局对象必须在main函数之前产生并初始化,所以应用程序调用的顺序应该是
CTestApp的构造函数 -> WinMain函数
又发现class CTestApp : public CWinApp,子类的构造函数在父类的构造函数调用之后调用,所以就搜索CWinApp吧。
在appcore.cpp的368行发现以下代码:
CWinApp::CWinApp(LPCTSTR lpszAppName) // 此处的lpszAppName有个默认参数NULL
{
if (lpszAppName != NULL)
m_pszAppName = _tcsdup(lpszAppName); // 为lpszAppName分配内存
else
m_pszAppName = NULL;
// initialize CWinThread state
AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
ENSURE(pModuleState);
AFX_MODULE_THREAD_STATE* pThreadState = pModuleState->m_thread;
ENSURE(pThreadState);
ASSERT(AfxGetThread() == NULL);
pThreadState->m_pCurrentWinThread = this; // 如果有子类继承了CWinApp, 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; // 如果有子类继承了CWinApp, this就是子类
ASSERT(AfxGetApp() == this);
// in non-running state until WinMain
m_hInstance = NULL;
m_hLangResourceDLL = NULL;v
m_pszHelpFilePath = NULL;
m_pszProfileName = NULL;
m_pszRegistryKey = NULL;
m_pszExeName = NULL;
m_pRecentFileList = NULL;
m_pDocManager = NULL;
m_atomApp = m_atomSystemTopic = NULL;
m_lpCmdLine = NULL;
m_pCmdInfo = NULL;
// initialize wait cursor state
m_nWaitCursorCount = 0;
m_hcurWaitCursorRestore = NULL;
// initialize current printer state
m_hDevMode = NULL;
m_hDevNames = NULL;
m_nNumPreviewPages = 0; // not specified (defaults to 1)
// initialize DAO state
m_lpfnDaoTerm = NULL; // will be set if AfxDaoInit called
// other initialization
m_bHelpMode = FALSE;
m_eHelpType = afxWinHelp;
m_nSafetyPoolSize = 512; // default size
}
然后是CTestApp的构造函数的调用。
在CTestApp的声明中,它重写了InitInstance函数,如下:
BOOL CTestApp::InitInstance()
{
AfxEnableControlContainer(); //Call this function in your application object's InitInstance function
//to enable support for containment of ActiveX controls
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.
// In MFC 5.0, Enable3dControls and Enable3dControlsStatic are obsolete because their functionality is incorporated
// into Microsoft's 32-bit and 64-bit operating systems.
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
// Change the registry key under which our settings are stored.
// TODO: You should modify this string to be something appropriate
// such as the name of your company or organization.
SetRegistryKey(_T("Local AppWizard-Generated Applications"));
LoadStdProfileSettings(); // Load standard INI file options (including MRU)
// Register the application's document templates. Document templates
// serve as the connection between documents, frame windows and views.
CSingleDocTemplate* pDocTemplate; // 单文档程序的模板生成
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CTestDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CTestView));
AddDocTemplate(pDocTemplate);
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo; // 对命令查询分析
ParseCommandLine(cmdInfo);
// Dispatch commands specified on the command line
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// The one and only window has been initialized, so show and update it.
m_pMainWnd->ShowWindow(SW_SHOW); //显示和更新窗口
m_pMainWnd->UpdateWindow();
return TRUE;
}
有了WinMain函数,也找到了显示和更新窗口的语句,但是从哪里开始设计窗口,注册窗口,建立窗口呢?
我又搜索了WNDCLASS,在wincore.cpp的4495行发现了与设计窗口时很像的函数BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)
发现MS已经在里面为我注册了一些窗口,我只要选择自己想要的样式就可以了。
那么如何建立一个窗口呢?我又搜索了CreateWindow,在wincore.cpp的675行中有个BOOL CWnd::CreateEx函数。
里面有调用CreateWindowEx。这个函数还调用了一个叫PreCreateWindow的函数,这个函数主要是确定在建立窗口之前,确保要建立的窗口已经注册了。
好了,一切都准备好了。最后就是进入消息循环。