MFC程序运行流程

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;

}

相关科技文章

“小牛”案正式发布退赔公告:退赔比例约为3.44%!
365bet体育在线导航

“小牛”案正式发布退赔公告:退赔比例约为3.44%!

⌚ 07-07 👁️ 8401
电视盒子看电视直播用什么软件好?2025电视盒子直播软件推荐
正规365彩票平台app下载

电视盒子看电视直播用什么软件好?2025电视盒子直播软件推荐

⌚ 06-29 👁️ 2806
宝宝树app怎么修改宝宝预产期 宝宝树修改宝宝预产期教程
正规365彩票平台app下载

宝宝树app怎么修改宝宝预产期 宝宝树修改宝宝预产期教程

⌚ 07-24 👁️ 3474
10年,淘宝是如何从无到有再到“无”的?
365bet体育在线导航

10年,淘宝是如何从无到有再到“无”的?

⌚ 07-16 👁️ 6414

合作伙伴