MFC學(xué)習(xí)筆記(一)
Win32應(yīng)用程序有條明確的主線:
(1) 進(jìn)入WinMain函數(shù)
(2) 設(shè)計(jì)一個(gè)Window
(3) 注冊(cè)這個(gè)Window
(4) 建立這個(gè)Window
(5) 顯示和更新這個(gè)Window
(6) 進(jìn)入消息循環(huán)
好,我就先找WinMain函數(shù)吧。
我在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是一個(gè)宏,詳細(xì)為: #define _tWinMain WinMain
所以這個(gè)確實(shí)是我們要找的WinMain函數(shù)
從代碼中看出,WinMain將參數(shù)全部交給AfxWinMain,來(lái)處理。
好,我又找AfxWinMain這個(gè)函數(shù)。
我在winmain.cpp的19行找到了AfxWinMain函數(shù)。
代碼:
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine, int nCmdShow)
{
ASSERT(hPrevInstance == NULL); // ASSERT在程序運(yùn)行時(shí)它計(jì)算括號(hào)內(nèi)的表達(dá)式,如果表達(dá)式為FALSE (0),
// 程序?qū)?bào)告錯(cuò)誤,并終止執(zhí)行。如果表達(dá)式不為0,則繼續(xù)執(zhí)行后面的語(yǔ)句。
// ASSERT只有在Debug版本中才有效,如果編譯為Release版本則被忽略。
// assert()的功能類(lèi)似,它是ANSI C標(biāo)準(zhǔn)中規(guī)定的函數(shù),它與ASSERT的一個(gè)重要區(qū)別是可以用在Release版本中。
int nReturnCode = -1;
// AfxGetThread和 AfxGetApp 都是全局函數(shù)
CWinThread* pThread = AfxGetThread(); // 獲得正在執(zhí)行的線程,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已經(jīng)過(guò)時(shí),用InitInstance代替,完成MFC內(nèi)部管理方面的工作
goto InitFailure;
// Perform specific initializations
if (!pThread->InitInstance()) // 初始化Instance,在每個(gè) a copy of the program runs的時(shí)候,虛函數(shù)
{
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.返回一個(gè)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函數(shù)后,看了下MFC為我生成的類(lèi):
1. CTestApp 2. CTestView 3. CMainFrame 4. CTestDoc 5. CAboutDlg
查看CTestApp.cpp,發(fā)現(xiàn)了一個(gè)全局的CTestApp theApp,因?yàn)槿謱?duì)象必須在main函數(shù)之前產(chǎn)生并初始化,所以應(yīng)用程序調(diào)用的順序應(yīng)該是
CTestApp的構(gòu)造函數(shù) -> WinMain函數(shù)
又發(fā)現(xiàn)class CTestApp : public CWinApp,子類(lèi)的構(gòu)造函數(shù)在父類(lèi)的構(gòu)造函數(shù)調(diào)用之后調(diào)用,所以就搜索CWinApp吧。
在appcore.cpp的368行發(fā)現(xiàn)以下代碼:
CWinApp::CWinApp(LPCTSTR lpszAppName) // 此處的lpszAppName有個(gè)默認(rèn)參數(shù)NULL
{
if (lpszAppName != NULL)
m_pszAppName = _tcsdup(lpszAppName); // 為lpszAppName分配內(nèi)存
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; // 如果有子類(lèi)繼承了CWinApp, this就是子類(lèi)
ASSERT(AfxGetThread() == this);
m_hThread = ::GetCurrentThread();
m_nThreadID = ::GetCurrentThreadId();
// initialize CWinApp state
ASSERT(afxCurrentWinApp == NULL); // only one CWinApp object please
pModuleState->m_pCurrentWinApp = this; // 如果有子類(lèi)繼承了CWinApp, this就是子類(lèi)
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的構(gòu)造函數(shù)的調(diào)用。
在CTestApp的聲明中,它重寫(xiě)了InitInstance函數(shù),如下:
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; // 對(duì)命令查詢(xún)分析
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函數(shù),也找到了顯示和更新窗口的語(yǔ)句,但是從哪里開(kāi)始設(shè)計(jì)窗口,注冊(cè)窗口,建立窗口呢?
我又搜索了WNDCLASS,在wincore.cpp的4495行發(fā)現(xiàn)了與設(shè)計(jì)窗口時(shí)很像的函數(shù)BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)
發(fā)現(xiàn)MS已經(jīng)在里面為我注冊(cè)了一些窗口,我只要選擇自己想要的樣式就可以了。
那么如何建立一個(gè)窗口呢?我又搜索了CreateWindow,在wincore.cpp的675行中有個(gè)BOOL CWnd::CreateEx函數(shù)。
里面有調(diào)用CreateWindowEx。這個(gè)函數(shù)還調(diào)用了一個(gè)叫PreCreateWindow的函數(shù),這個(gè)函數(shù)主要是確定在建立窗口之前,確保要建立的窗口已經(jīng)注冊(cè)了。
好了,一切都準(zhǔn)備好了。最后就是進(jìn)入消息循環(huán)。
posted on 2009-03-03 01:24 wil 閱讀(1874) 評(píng)論(0) 編輯 收藏 引用

