当前位置:文档之家› MFC内部运行来龙去脉追踪

MFC内部运行来龙去脉追踪

MFC内部运行来龙去脉追踪
MFC内部运行来龙去脉追踪

MFC内部运行来龙去脉追踪

1.全局对象theApp先于WinMain函数构造,而theApp是一个派生类的对象,故先调用基类CWinApp的构造函数,再调用派生类对象的构造函数。

CWinApp的构造函数定义于APPCORE.CPP文件中

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);

// in non-running state until WinMain

m_hInstance = NULL;

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_nSafetyPoolSize = 512; // default size

}

CWinApp构造函数主要完成this指针的赋值,将全局对象theApp的this指针赋值给全局唯一实例。该构造函数有一参数,我们在默认调用的时候却没有指定参数,其实这是因为有默认值,

追踪AFXWIN.h头文件查看CWinApp类的定义可知。

class CWinApp : public CWinThread

{

DECLARE_DYNAMIC(CWinApp)

public:

// Constructor

CWinApp(LPCTSTR lpszAppName = NULL); // app name defaults to EXE name

......

接着调用我们自己派生类的构造函数,我们可以做一些数据成员的初始化操作。CHelloMFCApp::CHelloMFCApp()

{

// TODO: add construction code here,

// Place all significant initialization in InitInstance

}

2.全局对象之后即是WinMain函数的调用,在MFC中对WinMain进行了封装。所以在文件中查找WinMain是找不到的。可以在源文件的class CAboutDlg : public CDialo g这一行加上断点,

F5运行,程序停在了

extern "C" int WINAPI

_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPTSTR lpCmdLine, int nCmdShow)

{

// call shared/exported WinMain

return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);

}

代码处,而同时可以看到该代码位于APPMODUL.cpp中。说明程序运行时加载了该函数,有点像我们的WinMain函数。go to definition可以看到#define _tWinMain WinM ain,_tWinMain正是我们的WinMain。

而为什么是_tWinMain而不是WinMain执行,这主要是MFC做了手脚,在MFC开始运行时就运行_tWinMain函数。其中又调用了AfxWinMain函数。在MFC源代码中查找一下AfxWinMain,在WINMAIN.cpp中可以找到AfxWinMain的实现:

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;

}

稍加整理,可看到AfxWinMain主要做些什么事:

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)

{

int nReturnCode = -1;

CWinApp* pApp = AfxGetApp();

AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow);

pApp->InitApplication();

pApp->InitInstance();

nReturnCode = pApp->Run();

AfxWinTerm();

return nReturnCode;

}

在APPINIT.cpp中查看AfxWinInit的实现如下:

BOOL AFXAPI AfxWinInit(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)

{

ASSERT(hPrevInstance == NULL);

// handle critical errors and avoid Windows message boxes

SetErrorMode(SetErrorMode(0) |

SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);

// set resource handles

AFX_MODULE_STATE* pModuleState = AfxGetModuleState();

pModuleState->m_hCurrentInstanceHandle = hInstance;

pModuleState->m_hCurrentResourceHandle = hInstance;

// fill in the initial state for the application

CWinApp* pApp = AfxGetApp();

if (pApp != NULL)

{

// Windows specific initialization (not done if no CWinApp)

pApp->m_hInstance = hInstance;

pApp->m_hPrevInstance = hPrevInstance;

pApp->m_lpCmdLine = lpCmdLine;

pApp->m_nCmdShow = nCmdShow;

pApp->SetCurrentHandles();

}

// initialize thread specific data (for main thread)

if (!afxContextIsDLL)

AfxInitThread();

return TRUE;

}

void AFXAPI AfxInitThread()

{

if (!afxContextIsDLL)

{

// set message filter proc

_AFX_THREAD_STATE* pThreadState = AfxGetThreadState();

ASSERT(pThreadState->m_hHookOldMsgFilter == NULL);

pThreadState->m_hHookOldMsgFilter = ::SetWindowsHookEx(WH_MSGFIL TER,

_AfxMsgFilterHook, NULL, ::GetCurrentThreadId());

#ifndef _AFX_NO_CTL3D_SUPPORT

// intialize CTL3D for this thread

_AFX_CTL3D_STATE* pCtl3dState = _afxCtl3dState;

if (pCtl3dState->m_pfnAutoSubclass != NULL)

(*pCtl3dState->m_pfnAutoSubclass)(AfxGetInstanceHandle());

// allocate thread local _AFX_CTL3D_THREAD just for automatic terminati on

_AFX_CTL3D_THREAD* pTemp = _afxCtl3dThread;

pTemp; // avoid unused warning

#endif

}

}

AfxInitThread函数利用钩子函数将消息映射机制引入MFC的Message Map中,然后再回到默认的DefWindowProc。而AfxWinInit也主要做些初始化工作,完成一些初始细节配置。

之后是pApp->Application()调用了,由于派生类没有改写,故调用基类CWinApp::Ap plication(),回到APPCORE.CPP文件:

BOOL CWinApp::InitApplication()

{

if (CDocManager::pStaticDocManager != NULL)

{

if (m_pDocManager == NULL)

m_pDocManager = CDocManager::pStaticDocManager;

CDocManager::pStaticDocManager = NULL;

}

if (m_pDocManager != NULL)

m_pDocManager->AddDocTemplate(NULL);

else

CDocManager::bStaticInit = FALSE;

return TRUE;

}

可以看到主要做些内部管理。

然后是pApp->InitInstance()调用,派生类进行了改写,所以调用的是派生类的InitIns tance(),如下:

BOOL CHelloMFCApp::InitInstance()

{

AfxEnableControlContainer();

// 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.

#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 view s.

CMultiDocTemplate* pDocTemplate;

pDocTemplate = new CMultiDocTemplate(

IDR_HELLOMTYPE,

RUNTIME_CLASS(CHelloMFCDoc),

RUNTIME_CLASS(CChildFrame), // custom MDI child frame

RUNTIME_CLASS(CHelloMFCView));

AddDocTemplate(pDocTemplate);

// create main MDI Frame window

CMainFrame* pMainFrame = new CMainFrame;

if (!pMainFrame->LoadFrame(IDR_MAINFRAME))

return FALSE;

m_pMainWnd = pMainFrame;

// 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 main window has been initialized, so show and update it.

pMainFrame->ShowWindow(m_nCmdShow);

pMainFrame->UpdateWindow();

return TRUE;

}

在派生类的InitInstance函数中产生了一个CMainFrame窗口对象,故先调用基类CMD IFrameWnd的构造函数,CMDIFrameWnd的基类是CFrameWnd,故调用CFrame Wnd的构造函数,在WinFrm.cpp文件中

CFrameWnd::CFrameWnd()

{

ASSERT(m_hWnd == NULL);

m_nWindow = -1; // unknown window ID

m_bAutoMenuEnable = TRUE; // auto enable on by default

m_lpfnCloseProc = NULL;

m_hMenuDefault = NULL;

m_hAccelTable = NULL;

m_nIDHelp = 0;

m_nIDTracking = 0;

m_nIDLastMessage = 0;

m_pViewActive = NULL;

m_cModalStack = 0; // initialize modality support

m_phWndDisable = NULL;

m_pNotifyHook = NULL;

m_hMenuAlt = NULL;

m_nIdleFlags = 0; // no idle work at start

m_rectBorder.SetRectEmpty();

m_bHelpMode = HELP_INACTIVE; // not in Shift+F1 help mode

m_dwPromptContext = 0;

m_pNextFrameWnd = NULL; // not in list yet

m_bInRecalcLayout = FALSE;

m_pFloatingFrameClass = NULL;

m_nShowDelay = -1; // no delay pending

AddFrameWnd();

}

一直追踪到基类CWnd,CCmdTarget,CObject都没有发现产生窗口(Create)的操作,当然在产生窗口之前首先要注册窗口。其实Create的调用是在pMainFrame->LoadFra me(IDR_MAINFRAME)

中完成的。即CFrameWnd::LoadFrame()

BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd* pParentWnd, CCreateContext* pContext)

{

// only do this once

ASSERT_VALID_IDR(nIDResource);

ASSERT(m_nIDHelp == 0 || m_nIDHelp == nIDResource);

m_nIDHelp = nIDResource; // ID for help context (+HID_BASE_RESOUR CE)

CString strFullString;

if (strFullString.LoadString(nIDResource))

AfxExtractSubString(m_strTitle, strFullString, 0); // first sub-string

VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));

// attempt to create the window

LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource);

LPCTSTR lpszTitle = m_strTitle;

if (!Create(lpszClass, lpszTitle, dwDefaultStyle, rectDefault, pParentWnd, MAKEINTRESOURCE(nIDResource), 0L, pContext))

{

return FALSE; // will self destruct on failure normally

}

// save the default menu handle

ASSERT(m_hWnd != NULL);

m_hMenuDefault = ::GetMenu(m_hWnd);

// load accelerator resource

LoadAccelTable(MAKEINTRESOURCE(nIDResource));

if (pContext == NULL) // send initial update

SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE);

return TRUE;

}

可以看到在LoadFrame中主要做了2件事,第一,注册窗口。第二,创建窗口。先看Af xDeferRegisterClass(),它是一个全局函数,在文件AFXIMPL.H中可以看到

#define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass)

在WINCORE.CPP中可以追踪到AfxEndDeferRegisterClass(fClass)如下:

BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)

{

// mask off all classes that are already registered

AFX_MODULE_STATE* pModuleState = AfxGetModuleState();

fToRegister &= ~pModuleState->m_fRegisteredClasses;

if (fToRegister == 0)

return TRUE;

LONG fRegisteredClasses = 0;

// common initialization

WNDCLASS wndcls;

memset(&wndcls, 0, sizeof(WNDCLASS)); // start with NULL defaults

wndcls.lpfnWndProc = DefWindowProc;

wndcls.hInstance = AfxGetInstanceHandle();

wndcls.hCursor = afxData.hcurArrow;

INITCOMMONCONTROLSEX init;

init.dwSize = sizeof(init);

// work to register classes as specified by fToRegister, populate fRegistere dClasses as we go

if (fToRegister & AFX_WND_REG)

{

// Child windows - no brush, no icon, safest default class styles

wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;

wndcls.lpszClassName = _afxWnd;

if (AfxRegisterClass(&wndcls))

fRegisteredClasses |= AFX_WND_REG;

}

if (fToRegister & AFX_WNDOLECONTROL_REG)

{

// OLE Control windows - use parent DC for speed

wndcls.style |= CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VRE DRAW;

wndcls.lpszClassName = _afxWndOleControl;

if (AfxRegisterClass(&wndcls))

fRegisteredClasses |= AFX_WNDOLECONTROL_REG;

}

if (fToRegister & AFX_WNDCONTROLBAR_REG)

{

// Control bar windows

wndcls.style = 0; // control bars don't handle double click

wndcls.lpszClassName = _afxWndControlBar;

wndcls.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);

if (AfxRegisterClass(&wndcls))

fRegisteredClasses |= AFX_WNDCONTROLBAR_REG;

}

if (fToRegister & AFX_WNDMDIFRAME_REG)

{

// MDI Frame window (also used for splitter window)

wndcls.style = CS_DBLCLKS;

wndcls.hbrBackground = NULL;

if (_AfxRegisterWithIcon(&wndcls, _afxWndMDIFrame, AFX_IDI_STD_MDIF RAME))

fRegisteredClasses |= AFX_WNDMDIFRAME_REG;

}

if (fToRegister & AFX_WNDFRAMEORVIEW_REG)

{

// SDI Frame or MDI Child windows or views - normal colors

wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;

wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);

if (_AfxRegisterWithIcon(&wndcls, _afxWndFrameOrView, AFX_IDI_STD_FR AME))

fRegisteredClasses |= AFX_WNDFRAMEORVIEW_REG;

}

if (fToRegister & AFX_WNDCOMMCTLS_REG)

{

// this flag is compatible with the old InitCommonControls() API

init.dwICC = ICC_WIN95_CLASSES;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WIN95CTLS_MA

fToRegister &= ~AFX_WIN95CTLS_MASK;

}

if (fToRegister & AFX_WNDCOMMCTL_UPDOWN_REG)

{

init.dwICC = ICC_UPDOWN_CLASS;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_ UPDOWN_REG);

}

if (fToRegister & AFX_WNDCOMMCTL_TREEVIEW_REG)

{

init.dwICC = ICC_TREEVIEW_CLASSES;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_ TREEVIEW_REG);

}

if (fToRegister & AFX_WNDCOMMCTL_TAB_REG)

{

init.dwICC = ICC_TAB_CLASSES;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_ TAB_REG);

}

if (fToRegister & AFX_WNDCOMMCTL_PROGRESS_REG)

{

init.dwICC = ICC_PROGRESS_CLASS;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_ PROGRESS_REG);

}

if (fToRegister & AFX_WNDCOMMCTL_LISTVIEW_REG)

{

init.dwICC = ICC_LISTVIEW_CLASSES;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_ LISTVIEW_REG);

}

if (fToRegister & AFX_WNDCOMMCTL_HOTKEY_REG)

{

init.dwICC = ICC_HOTKEY_CLASS;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_ HOTKEY_REG);

}

if (fToRegister & AFX_WNDCOMMCTL_BAR_REG)

{

init.dwICC = ICC_BAR_CLASSES;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_ BAR_REG);

if (fToRegister & AFX_WNDCOMMCTL_ANIMATE_REG)

{

init.dwICC = ICC_ANIMATE_CLASS;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_ ANIMATE_REG);

}

if (fToRegister & AFX_WNDCOMMCTL_INTERNET_REG)

{

init.dwICC = ICC_INTERNET_CLASSES;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_ INTERNET_REG);

}

if (fToRegister & AFX_WNDCOMMCTL_COOL_REG)

{

init.dwICC = ICC_COOL_CLASSES;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_ COOL_REG);

}

if (fToRegister & AFX_WNDCOMMCTL_USEREX_REG)

{

init.dwICC = ICC_USEREX_CLASSES;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_ USEREX_REG);

}

if (fToRegister & AFX_WNDCOMMCTL_DATE_REG)

{

init.dwICC = ICC_DATE_CLASSES;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_ DATE_REG);

}

// save new state of registered controls

pModuleState->m_fRegisteredClasses |= fRegisteredClasses;

// special case for all common controls registered, turn on AFX_WNDCOM MCTLS_REG

if ((pModuleState->m_fRegisteredClasses & AFX_WIN95CTLS_MASK) == A FX_WIN95CTLS_MASK)

{

pModuleState->m_fRegisteredClasses |= AFX_WNDCOMMCTLS_REG;

fRegisteredClasses |= AFX_WNDCOMMCTLS_REG;

}

// must have registered at least as mamy classes as requested

return (fToRegister & fRegisteredClasses) == fToRegister;

}

至此可以看到MFC默认的注册了很多窗口类,而其中调用了AfxRegisterClass函数。而AfxRegisterClass函数实现如下:

BOOL AFXAPI AfxRegisterClass(WNDCLASS* lpWndClass)

{

WNDCLASS wndcls;

if (GetClassInfo(lpWndClass->hInstance, lpWndClass->lpszClassName,

&wndcls))

{

// class already registered

return TRUE;

}

if (!::RegisterClass(lpWndClass))

{

TRACE1("Can't register window class named %s\n",

lpWndClass->lpszClassName);

return FALSE;

}

if (afxContextIsDLL)

{

AfxLockGlobals(CRIT_REGCLASSLIST);

TRY

{

// class registered successfully, add to registered list

AFX_MODULE_STATE* pModuleState = AfxGetModuleState();

LPTSTR lpszUnregisterList = pModuleState->m_szUnregisterList;

// the buffer is of fixed size -- ensure that it does not overflow

ASSERT(lstrlen(lpszUnregisterList) + 1 +

lstrlen(lpWndClass->lpszClassName) + 1 <

_countof(pModuleState->m_szUnregisterList));

// append classname + newline to m_szUnregisterList

lstrcat(lpszUnregisterList, lpWndClass->lpszClassName);

TCHAR szTemp[2];

szTemp[0] = '\n';

szTemp[1] = '\0';

lstrcat(lpszUnregisterList, szTemp);

}

CATCH_ALL(e)

{

AfxUnlockGlobals(CRIT_REGCLASSLIST);

THROW_LAST();

// Note: DELETE_EXCEPTION not required.

}

END_CATCH_ALL

AfxUnlockGlobals(CRIT_REGCLASSLIST);

}

return TRUE;

}

可以看到最终调用Windows API函数实现窗口类的注册。

再次回到CFrameWnd::LoadFrame()函数,接下来就是产生窗口的操作了。LoadFram e中的Create调用依据多态性,应调用派生类的Create函数,由于派生类没有改写,此处调用CFrameWnd的Create函数。如下(在WINFRM.CPP中):

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)

{

TRACE0("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))

{

TRACE0("Warning: failed to create CFrameWnd.\n");

if (hMenu != NULL)

DestroyMenu(hMenu);

return FALSE;

}

return TRUE;

}

后者又调用了CreateEx函数,CWnd有CreateEx函数,而CFrameWnd函数并没有改写它,故调用CWnd类的CreateEx函数,在WINCORE.cpp中实现如下:

BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,

LPCTSTR lpszWindowName, DWORD dwStyle,

int x, int y, int nWidth, int nHeight,

HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)

{

// allow modification of several common create parameters

CREATESTRUCT cs;

cs.dwExStyle = dwExStyle;

cs.lpszClass = lpszClassName;

cs.lpszName = lpszWindowName;

cs.style = dwStyle;

cs.x = x;

cs.y = y;

cs.cx = nWidth;

cs.cy = nHeight;

cs.hwndParent = hWndParent;

cs.hMenu = nIDorHMenu;

cs.hInstance = AfxGetInstanceHandle();

cs.lpCreateParams = lpParam;

if (!PreCreateWindow(cs))

{

PostNcDestroy();

return FALSE;

}

AfxHookWindowCreate(this);

HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass,

cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,

cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);//Windows AP I完成窗口类的一些额外风格设置

#ifdef _DEBUG

if (hWnd == NULL)

{

TRACE1("Warning: Window creation failed: GetLastError returns 0x%8.8X\ n",

GetLastError());

}

#endif

if (!AfxUnhookWindowCreate())

PostNcDestroy(); // cleanup if CreateWindowEx fails too soon

if (hWnd == NULL)

return FALSE;

ASSERT(hWnd == m_hWnd); // should have been set in send msg hook return TRUE;

}

该函数先是调用PreCreateWindow函数,依据多态性,先调用派生类,接着是CMDIFr ameWnd,然后是CFrameWnd的PreCreateWindow函数

在WINFRM.CPP中如下:

BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs)

{

if (cs.lpszClass == NULL)

{

VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));

cs.lpszClass = _afxWndFrameOrView; // COLOR_WINDOW background }

if ((cs.style & FWS_ADDTOTITLE) && afxData.bWin4)

cs.style |= FWS_PREFIXTITLE;

if (afxData.bWin4)

cs.dwExStyle |= WS_EX_CLIENTEDGE;

return TRUE;

}

沿着AfxDeferRegisterClass追踪下去,和上面的相同,都为MFC注册窗口类。

追踪完毕,回到开始的InitInstance函数中,接下来就是ShowWindow、UpdateWind ow了。UpdateWindow会发出WM_PAINT消息。

再回到AfxWinMain()函数就是调用pApp->Run()函数了。因为派生类没有改写所以调用CWinApp::Run()函数,在APPCORE.CPP中实现如下:

int CWinApp::Run()

{

if (m_pMainWnd == NULL && AfxOleGetUserCtrl())

{

// Not launched /Embedding or /Automation, but has no main window! TRACE0("Warning: m_pMainWnd is NULL in CWinApp::Run - quitting appli cation.\n");

AfxPostQuitMessage(0);

}

return CWinThread::Run();

}

而CWinThread::Run实现如下,在文件THRDCORE.CPP中:

int CWinThread::Run()

{

ASSERT_VALID(this);

// for tracking the idle time state

BOOL bIdle = TRUE;

LONG lIdleCount = 0;

// acquire and dispatch messages until a WM_QUIT message is received. for (;;)

{

// phase1: check to see if we can do idle work

while (bIdle &&

!::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))

{

// call OnIdle while in bIdle state

if (!OnIdle(lIdleCount++))

bIdle = FALSE; // assume "no idle" state

}

// phase2: pump messages while available

do

{

// pump message, but quit on WM_QUIT

if (!PumpMessage())

return ExitInstance();

// reset "no idle" state after pumping "normal" message

if (IsIdleMessage(&m_msgCur))

{

bIdle = TRUE;

lIdleCount = 0;

}

} while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE)); }

ASSERT(FALSE); // not reachable

}

而CWinThread::PumpMessage实现如下:

BOOL CWinThread::PumpMessage()

{

ASSERT_VALID(this);

if (!::GetMessage(&m_msgCur, NULL, NULL, NULL))

{

#ifdef _DEBUG

if (afxTraceFlags & traceAppMsg)

TRACE0("CWinThread::PumpMessage - Received WM_QUIT.\n");

m_nDisablePumpCount++; // application must die

// Note: prevents calling message loop things in 'ExitInstance'

// will never be decremented

#endif

return FALSE;

}

#ifdef _DEBUG

if (m_nDisablePumpCount != 0)

{

TRACE0("Error: CWinThread::PumpMessage called when not permitted.\n ");

ASSERT(FALSE);

}

#endif

#ifdef _DEBUG

if (afxTraceFlags & traceAppMsg)

_AfxTraceMsg(_T("PumpMessage"), &m_msgCur);

#endif

// process this message

if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_ms

gCur))

{

::TranslateMessage(&m_msgCur);

::DispatchMessage(&m_msgCur);

}

return TRUE;

}

可以看到都是调用底层Windows API实现。程序退出时回到AfxWinInit最后调用AfxW

inTerm终止程序。

而消息映射的实现是利用钩子函数在AfxWndProc中实现的,最后没有处理的消息都用DefWindowP roc函数处理

相关主题
文本预览
相关文档 最新文档