注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Leo

笑:胸怀,傲:实力,才能笑傲江湖。

 
 
 

日志

 
 

C++学习——MFC  

2012-04-09 18:51:40|  分类: 大学留笔 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

03-简介MFC学习文档

一、单文档、多文档、对话框编程

2012年04月09日 - leo - Leo

 

Windows窗口设计的主线步骤:

1、进入WinMain函数;

2、设计窗口类;

3、注册窗口类;

4、产生窗口;

5、显示窗口;

6、更新窗口;

7、消息循环。消息路由到窗口中进行处理。

 二、MFC下的WinMain函数,入口函数。

在生成的代码中,是找不到WinMain函数的。当我们编译连接的时候,由连接器将WinMain连接到我们的编译器中。在安装目录,如:D:\PD:\Program Files\Microsoft Visual Studio\VC98\MFC\SRC,这个目录下就是MFC的源代码。下找到:APPMODUL.CPP

2012年04月09日 - leo - Leo

打开,可以看见一个WinMain函数。

_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPTSTR lpCmdLine, int nCmdShow)

{

    // call shared/exported WinMain

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

}

注意:四个参数,和前面说的一样。

三、看看WinMain和类,是怎么组织在一起的。

     

2012年04月09日 - leo - Leo

 

1、点击C....APP类,可以看见:class CLesson3App : public CWinApp 是由CWinApp继承下来的,是应有程序类。

2、点开CPP中的构造函数,加断点调试,会发现先执行到CLesson3App::CLesson3App()。在下面,可以看见,用CLesson3App theApp; 定义了一个全局变量,设置断点,调试云行,会先运行到这儿,再到构造函数,再到WinMain

3、全局变量和全局对象是在Main函数加载的时候,就已经为它分配了空间或可能赋值。所以会先运行CLesson3App theApp;

4、在生成的MFC代码中,有且仅有一个APPCWinApp派生出来的类。在定义全局变量之后,会调用构造函数,在调用子类构造函数的时候,会先够着父类CWinApp的构造函数。这样,就在构造CWinApp中初始化的工作就完成了。

 

四、看看设计窗口主线运行。

1、找到APPCORE.CPP文件

2012年04月09日 - leo - Leo

2CWinApp构造函数:做初始化的工作了。

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

}

3、初始化后,就该到WinMain函数了。

回到APPMODUL.CPP中:

_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPTSTR lpCmdLine, int nCmdShow)

{

// call shared/exported WinMain

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

}

收索AfxWinMain,在WINMAIN.CPP中:

2012年04月09日 - leo - Leo

 

函数:int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPTSTR lpCmdLine, int nCmdShow)

会调用:InitApplication 内部初始化管理。

InitInstance()  是虚函数,根据多态知道这儿调用的是派生类,就是我们生成的C....App类中的InitInstance()函数。

Run() 函数,消息处理了。

4、注册窗口类

2012年04月09日 - leo - Leo

设计窗口类中,MFC定义好了几种缺省的窗口类,只需要调用AfxEndDeferRegisterClass 这个函数去注册一下就可以了。

找到函数AfxEndDeferRegisterClass函数,

if (fToRegister & AFX_WND_REG)

if (fToRegister & AFX_WNDOLECONTROL_REG)

if (fToRegister & AFX_WNDCONTROLBAR_REG)

.................

if (fToRegister & AFX_WNDCOMMCTL_DATE_REG)

等等注册不同的窗口类。

BOOL AFXAPI AfxRegisterClass(WNDCLASS* lpWndClass) 这个是判断注册类的函数。

5、产生窗口

CMainFrame类中,产生窗口。

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)

{

if( !CFrameWnd::PreCreateWindow(cs) )

return FALSE;

这里调用了一个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;

}

产生窗口,在WINCORE.CPP中:CreateWindow函数,会找到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)

再看看在是谁调用了CreateEx,发现,是在WINFRM.CPP中被调用的。

BOOL CFrameWnd::Create(LPCTSTR lpszClassName,

LPCTSTR lpszWindowName,

DWORD dwStyle,

const RECT& rect,

CWnd* pParentWnd,

LPCTSTR lpszMenuName,

DWORD dwExStyle,

CCreateContext* pContext) 函数调用。

这个麻烦,再看看。

6、显示窗口和更新窗口

C....App中,BOOL CLesson3App::InitInstance()函数,最后有一个:

m_pMainWnd->ShowWindow(SW_SHOW);

m_pMainWnd->UpdateWindow();

来显示和更新窗口。

CWnd* m_pMainWnd; 指向框架窗口指针。

if (!ProcessShellCommand(cmdInfo))

return FALSE;

后,创建窗口就完成了,接着就是显示和更新了。

7、消息循环

收索:CWinThread::Run() ,在THRDCORE.CPP中。

BOOL CWinThread::InitInstance()

{

ASSERT_VALID(this);

return FALSE;   // by default don't enter run loop

}

// main running routine until thread exits

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

}

PumpMessage()中有:

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

{ ::TranslateMessage(&m_msgCur); ::DispatchMessage(&m_msgCur);

}

 

 

流程总结:

1、C.......App theApp;启动应有程序。

2、C.......App::C.......App();调用构造函数,产生对象,并先调用父类构造函数,完成初始化工作,保存子类的指针。

3、进入到_tWinMain函数。获得子类的指针,利用它来调用虚函数,就是子类的InitInstance() 函数了。

4、进入子类的InitInstance() 函数。完成应用程序的初始化工作,包括窗口类的注册,

5、进入注册:AfxEndDeferRegisterClass

6、 CFrameWnd::PreCreateWindow(CREATESTRUCT& cs)

7、 CWnd::CreateEx.........)函数;

8、CWinThread::Run(),进入消息循环。

 

 

 

 

MainFrameCViewCDoc类的关联:

BOOL C.....App::InitInstance() 中,有这样的代码:

CSingleDocTemplate* pDocTemplate;

pDocTemplate = new CSingleDocTemplate(

IDR_MAINFRAME,

RUNTIME_CLASS(CLesson3Doc),

RUNTIME_CLASS(CMainFrame),       // main SDI frame window

RUNTIME_CLASS(CLesson3View));

AddDocTemplate(pDocTemplate);

将这三个类,用函数增加到模版中,有机的组织在一起。

  评论这张
 
阅读(460)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017