MFC程序运行流程

->进入入口函数_tWinMain()

程序首先进入文件AppModul.cpp,找到_tWinMain()函数运行,调用其中的AfxWinMain()函数。

由于为了支持UNICODE,C运行库对WinMain其实区分了UNICODE版和ANSI版.对UNICODE版的程序,C运行库将调用wWinMain,而对于ANSI版的应用,则调用WinMain.

文件tchar.h定义:

...

#ifdef  _UNICODE

...

#define _tmain      wmain

#define _tWinMain   wWinMain

...



#else   /* ndef _UNICODE */

...

#define _tmain      main

#define _tWinMain   WinMain

...



MFC的代码设计时是自动支持UNICODE的,所以,MFC的WinMain在APPMODUL.CPP被定义为_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow),无论用户#define _UNICODE与否,MFC的WinMain都会被调用.

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

}

hInstance:表示该程序当前运行的实例句柄,它是一个数值。当程序在Windows下运行时,它唯一标识运行中的实例。

hPrevInstance:父窗口句柄。这个参数在Win32下已经不起作用了。

lpCmpLine:指定传递给应用程序的命令行参数。

nCmdShow:指定程序窗口如何显示,例如最大化、最小化、隐藏等。

 

->进入AfxWinMain()

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

	_In_ LPTSTR lpCmdLine, int nCmdShow)

{

	ASSERT(hPrevInstance == NULL);



	int nReturnCode = -1;

	CWinThread* pThread = AfxGetThread();//返回指向theApp的指针

	CWinApp* pApp = AfxGetApp();//返回指向theApp的指针



	// AFX internal initialization

	if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))//初始化应用程序内部环境,设置MFC

		goto InitFailure;



	// App global initializations (rare)

	if (pApp != NULL && !pApp->InitApplication())//初始化应用程序内部环境,设置MFC

		goto InitFailure;



	// Perform specific initializations

	if (!pThread->InitInstance())//完成应用程序相关工作:设计窗口类、注册窗口类、创建窗口类、显示窗口类、更新窗口类

	{

		if (pThread->m_pMainWnd != NULL)

		{

			TRACE(traceAppMsg, 0, "Warning: Destroying non-NULL m_pMainWnd\n");

			pThread->m_pMainWnd->DestroyWindow();

		}

		nReturnCode = pThread->ExitInstance();

		goto InitFailure;

	}

	nReturnCode = pThread->Run();//进入消息循环,处理系统消息。
//Run()调用PumpMessage函数,通过调用GetMessage、TranslateMessage、DispatchMessage等建立了消息循环并投递消息。



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;

}

->pThread->InitInstance()

这是个虚函数,pThread指向的是theApp,调用的是子类C***App类中的InitInstance函数。

KuaiPaiClient项目中的该函数为:

BOOL CKuaiPanClientApp::InitInstance()

{

	// InitCommonControlsEx() is required on Windows XP if an application

	// manifest specifies use of ComCtl32.dll version 6 or later to enable

	// visual styles.  Otherwise, any window creation will fail.

	INITCOMMONCONTROLSEX InitCtrls;

	InitCtrls.dwSize = sizeof(InitCtrls);

	// Set this to include all the common control classes you want to use

	// in your application.

	InitCtrls.dwICC = ICC_WIN95_CLASSES;

	InitCommonControlsEx(&InitCtrls);



	CWinAppEx::InitInstance();





	// Initialize OLE libraries

	if (!AfxOleInit())

	{

		AfxMessageBox(IDP_OLE_INIT_FAILED);

		return FALSE;

	}



	AfxEnableControlContainer();



	EnableTaskbarInteraction(FALSE);



	// AfxInitRichEdit2() is required to use RichEdit control	

	// AfxInitRichEdit2();



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

	// 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(4);  // Load standard INI file options (including MRU)

	InitContextMenuManager();



	InitKeyboardManager();



	InitTooltipManager();

	CMFCToolTipInfo ttParams;

	ttParams.m_bVislManagerTheme = TRUE;

	theApp.GetTooltipManager()->SetTooltipParams(AFX_TOOLTIP_TYPE_ALL,

		RUNTIME_CLASS(CMFCToolTipCtrl), &ttParams);



	// 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(CKuaiPanClientDoc),

		RUNTIME_CLASS(CMainFrame),       // main SDI frame window

		RUNTIME_CLASS(CKuaiPanClientView));

	if (!pDocTemplate)

		return FALSE;

	AddDocTemplate(pDocTemplate);//将Doc类、CMainFrame和CView三个类用文档模板关联到一起,装载到当前应用程序的全局对象theApp中。



	// Parse command line for standard shell commands, DDE, file open

	CCommandLineInfo cmdInfo;

	ParseCommandLine(cmdInfo);



	// Dispatch commands specified on the command line.  Will return FALSE if

	// app was launched with /RegServer, /Register, /Unregserver or /Unregister.

	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();//更新框架窗口

	// call DragAcceptFiles only if there's a suffix

	//  In an SDI app, this should occur after ProcessShellCommand

	return TRUE;

}
 
 

->ProcessShellCommand()调用了LoadFrame()注册并创建窗口

ProcessShellCommand()——>OnCmdMsg()——>AfxDispatchCmdMsg()——>pfn_Command()——>OnFileNew()——>OpenDocumentFile()——>CreateNewFrame()——>LoadFrame()
多次调用PreCreateWindow、CreateEx、AfxEndDeferRegisterClass 注册工具栏、状态栏等.
 
BOOL CWinApp::ProcessShellCommand(CCommandLineInfo& rCmdInfo)

{

	BOOL bResult = TRUE;

	switch (rCmdInfo.m_nShellCommand)

	{

	case CCommandLineInfo::RestartByRestartManager:

		// Re-register with the restart manager using the restart identifier from the command line

		RegisterWithRestartManager(SupportsApplicationRecovery(), rCmdInfo.m_strRestartIdentifier);



		// Call RestartIntance, which should reopen any previously opened document(s) and

		// optionally load the autosaved versions after querying the user about loading.

		if (RestartInstance())

			break;

		// If RestartInstance returns FALSE, then fall through to FileNew case, so

		// a new document is created--otherwise the main frame will not be created.



	case CCommandLineInfo::FileNew:

		if (!AfxGetApp()->OnCmdMsg(ID_FILE_NEW, 0, NULL, NULL))

			OnFileNew();

		if (m_pMainWnd == NULL)

			bResult = FALSE;

		break;



	// If we've been asked to open a file, call OpenDocumentFile()

	case CCommandLineInfo::FileOpen:

		if (!OpenDocumentFile(rCmdInfo.m_strFileName))

			bResult = FALSE;

		break;



	// If the user wanted to print, hide our main window and

	// fire a message to ourselves to start the printing

	case CCommandLineInfo::FilePrintTo:

	case CCommandLineInfo::FilePrint:

		m_nCmdShow = SW_HIDE;

		ASSERT(m_pCmdInfo == NULL);

		if(OpenDocumentFile(rCmdInfo.m_strFileName))

		{

			m_pCmdInfo = &rCmdInfo;

			ENSURE_VALID(m_pMainWnd);

			m_pMainWnd->SendMessage(WM_COMMAND, ID_FILE_PRINT_DIRECT);

			m_pCmdInfo = NULL;

		}

		bResult = FALSE;

		break;



	// If we're doing DDE print or print to, start up without a new document and hide ourselves

	case CCommandLineInfo::FileDDENoShow:

		m_pCmdInfo = (CCommandLineInfo*)(UINT_PTR)m_nCmdShow;

		m_nCmdShow = SW_HIDE;

		break;



	// If we're doing DDE open, start up without a new document, but don't hide ourselves -- this causes the

	// icon in the Windows 7 taskbar to start in the wrong position and slide into the right position.

	case CCommandLineInfo::FileDDE:

		break;



	// If we've been asked to register, exit without showing UI.

	// Registration was already done in InitInstance().

	case CCommandLineInfo::AppRegister:

		{

			Register();			

			bResult = FALSE;    // that's all we do



			// If nobody is using it already, we can use it.

			// We'll flag that we're unregistering and not save our state

			// on the way out. This new object gets deleted by the

			// app object destructor.



			if (m_pCmdInfo == NULL)

			{

				m_pCmdInfo = new CCommandLineInfo;

				m_pCmdInfo->m_nShellCommand = CCommandLineInfo::AppUnregister;

			}

			break;

		}



	// If we've been asked to unregister, unregister and then terminate

	case CCommandLineInfo::AppUnregister:

		{

			BOOL bUnregistered = Unregister();



			if (!rCmdInfo.m_bRunEmbedded)

			{

				if (bUnregistered)

					AfxMessageBox(AFX_IDP_UNREG_DONE);

				else

					AfxMessageBox(AFX_IDP_UNREG_FAILURE);

			}

			bResult = FALSE;    // that's all we do



			// If nobody is using it already, we can use it.

			// We'll flag that we're unregistering and not save our state

			// on the way out. This new object gets deleted by the

			// app object destructor.



			if (m_pCmdInfo == NULL)

			{

				m_pCmdInfo = new CCommandLineInfo;

				m_pCmdInfo->m_nShellCommand = CCommandLineInfo::AppUnregister;

			}

		}

		break;

	}

	return bResult;

}

->CreateEx()

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)

{

	ASSERT(lpszClassName == NULL || AfxIsValidString(lpszClassName) || 

		AfxIsValidAtom(lpszClassName));

	ENSURE_ARG(lpszWindowName == NULL || AfxIsValidString(lpszWindowName));

	

	// 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))//此处调用的PreCreateWindow,事实上调用的是C***App的成员函数,虚函数,可以在C***App中重写,这样可以在窗口被创建前通过结构体CREATESTRUCT更改窗口风格等

	{

		PostNcDestroy();

		return FALSE;

	}



	AfxHookWindowCreate(this);

	HWND hWnd = ::AfxCtxCreateWindowEx(cs.dwExStyle, cs.lpszClass,//开始创建窗口

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

			cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);



#ifdef _DEBUG

	if (hWnd == NULL)

	{

		TRACE(traceAppMsg, 0, "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;

}

->AfxEndDeferRegisterClass()

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 fRegisteredClasses 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_VREDRAW;

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

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

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

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

	}

	if (fToRegister & AFX_WNDCOMMCTL_LINK_REG)

	{

		init.dwICC = ICC_LINK_CLASS;

		fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_LINK_REG);

	}

	if (fToRegister & AFX_WNDCOMMCTL_PAGER_REG)

	{

		init.dwICC = ICC_PAGESCROLLER_CLASS;

		fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_PAGER_REG);

	}



	// save new state of registered controls

	pModuleState->m_fRegisteredClasses |= fRegisteredClasses;



	// special case for all common controls registered, turn on AFX_WNDCOMMCTLS_REG

	if ((pModuleState->m_fRegisteredClasses & AFX_WIN95CTLS_MASK) == AFX_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)