社区
ATL
帖子详情
.......................CWinApp::OnFileOpen()........................
luyangcplusplus
2008-08-01 11:16:18
各位大侠好,小弟做了一个文档/视图结构的ActiveX控件,
在响应工具栏的“打开”按钮的时候,调用CWinApp::OnFileOpen()出错。
不知道是什么原因,请各位大侠帮忙。
...全文
89
4
打赏
收藏
.......................CWinApp::OnFileOpen()........................
各位大侠好,小弟做了一个文档/视图结构的ActiveX控件, 在响应工具栏的“打开”按钮的时候,调用CWinApp::OnFileOpen()出错。 不知道是什么原因,请各位大侠帮忙。
复制链接
扫一扫
分享
转发到动态
举报
写回复
配置赞助广告
用AI写文章
4 条
回复
切换为时间正序
请发表友善的回复…
发表回复
打赏红包
kuangsun
2010-07-07
打赏
举报
回复
不懂,顶一个!!!!!!!!
yawer
2008-08-01
打赏
举报
回复
到你的doc的 BOOL OnOpenDocument(LPCTSTR lpszPathName);函数去看看。
ouyh12345
2008-08-01
打赏
举报
回复
为什么是CWinApp类?
luyangcplusplus
2008-08-01
打赏
举报
回复
谢谢yawer
我在“打开”的响应函数里写了一段测试代码,如下:
void CMNDrawApp::OnFileOpen()
{
if(m_pDocManager==NULL)
{
AfxMessageBox("yes");
return;
}
ASSERT(m_pDocManager != NULL);
m_pDocManager->OnFileOpen();
}
然后单击“打开”,就会弹出“yes”对话框。
证明m_pDocManager为NULL,不知是什么原因。
请问大侠,为什么m_pDocManager会为NULL呢?
MFC-MDI.zip_MDI_MFC MDI_On
File
Open
深入了解MFC中的文挡/视结构,文档/视结构有关的各种类之间的关系,了解C
win
App
::On
File
New、C
win
App
::On
File
Open
和
Win
dow/New的程序流程,
深入了解MFC中的文挡视结构
深入了解MFC中的文挡视结构。1、了解文档/视结构,2、了解与文档/视结构有关的各种类之间的关系。3、了解C
win
App
::On
File
New、C
win
App
::On
File
Open
和
Win
dow/New的程序流程等等。
MFC的程序框架剖析
什么是句柄? 句柄,是整个
Win
dows编程的基础。一个句柄是指使用的一个唯一的整数值,即一个4字节(64位程序中为8字节)长的数值,来标识应用程序中的不同对象和同类对象中的不同的实例,诸如,一个窗口,按钮,图标,滚动条,输出设备,控件或者文件等。应用程序能够通过句柄访问相应的对象的信息,但是句柄不是一个指针,程序不能利用句柄来直接阅读文件中的信息。如果句柄不用在I/O文件中,它是毫无用处的。 句柄是
Win
dows用来标志应用程序中建立的或是使用的唯一整数,
Win
dows使用了大量的句柄来标志很多对象。 一、MFC
App
Wizard 1、MFC(Microsoft Foundation Class,微软基础类库)是微软为了简化程序员的开发工作所开发的一套C++ 类的集合,是一套面向对象的函数库,以类的方式提供给用户使用 2、MFC
App
Wizard是一个辅助我们生成源代码的向导工具,它可以帮助我们自动生成基于MFC框架的源代码 二、基于MFC的程序框架剖析 1、MFC程序的ClassView标签页(图) 2、继承关系 (1)CMainFrame继承于CFrameWnd (2)CTest
App
继承于C
Win
App
(3)CTestDoc继承于CDocument (4)CTestView继承于CView 注:CFrameWnd和CView都继承于CWnd 3、CWnd类是MFC中一个非常重要的类,它封装了与窗口相关的操作 4、MFC类的简化组织结构图(图) 5、MFC程序也有一个
Win
Main函数,程序是在编译时,由链接器将它链接到程序中 6、MFC程序具有一个CTest
App
类的全局对象the
App
,在MFC程序运行时,程序执行的顺序为:the
App
全局对象定义 处->CTest
App
构造函数->
Win
Main函数 7、对于普通的VC++控制台程序,无论全局变量还是全局对象,程序运行时,在加载main函数之前,就已经为它们 分配了内存空间。对于一个全局对象来说,此时就会调用该对象的构造函数,构造该对象,并进行初始化操作 8、实例句柄与全局对象 (1)对于
Win
32 SDK程序,应用程序的实例是由实例句柄(
Win
Main函数的hInstance参数)来标识的 (2)对于MFC程序,应用程序的实例是由全局对象(每一个MFC程序有且仅有一个从应用程序类C
Win
App
派生的类, 如CTest
App
,它实例化the
App
全局对象)来标识的 9、基类构造函数中this指针的指向问题 在构造子类对象时,会自动调用父类的构造函数,此时在父类的构造函数中的this指针所指向的是子类对象地址 10、Afx
Win
Main函数 MFC程序的
Win
Main函数是通过调用Afx
Win
Main函数来完成它的功能的 注:Afx前缀的函数代表应用程序框架(
App
lication Framework)函数,它们可以在程序的任何地方被调用 11、CTest
App
::InitInstance函数 在Afx
Win
Main函数中,通过调用InitInstance函数来完成MFC内部管理方面的工作 12、AfxEndDeferRegisterClass函数 MFC提供了一些默认的标准窗口类,我们只需要选择所需的窗口类就行。然后,调用AfxEndDeferRegisterClass 函数来注册窗口类 13、CMainFrame::PreCreate
Win
dow函数 MFC程序具有两个窗口(框架窗口和视类窗口),在框架窗口产生之前会调用PreCreate
Win
dow函数 14、CWnd::CreateEx函数 在MFC程序中,窗口的创建是由CreateEx函数实现的 15、CWnd::Create
Win
dowEx函数 主要作用是当修改了CreateEx函数的CREATESTRUCT参数时,Create
Win
dowEx函数会根据参数发生的相应变化来创 建一个符合我们要求的窗口 注:MFC中后缀名为Ex的函数都是扩展函数 16、CMainFrame::Show
Win
dow函数和CMainFrame::Update
Win
dow函数 用于显示应用程序框架窗口和更新这个窗口 17、C
Win
Thread::Run函数和C
Win
Thread::PumpMessage函数 用于完成消息循环 18、Def
Win
dowProc函数 默认的窗口过程,但MFC程序对消息的处理实际上是通过消息映射机制来完成的 19、MFC程序的运行过程 (1)首先利用全局应用程序对象the
App
启动应用程序 (2)调用全局应用程序对象的构造函数,从而就会调用其基类C
Win
App
的构造函数,以完成应用程序的一些初始化 (3)进入
Win
Main函数 (4)进入消息循环 20、MFC程序的主要过程 the
App
-> CTest
App
::CTest
App
构造函数-> C
Win
App
::C
Win
App
构造函数-> _t
Win
Main(
Win
Main函数的宏)-> Afx
Win
Main函数-> CTest
App
::InitInstance函数-> AfxEndDeferRegisterClass函数-> CMainFrame::PreCreate
Win
dow函数-> CFrameWnd::PreCreate
Win
dow函数-> AfxDeferRegisterClass(AfxEndDeferRegisterClass函数的宏)-> CFrameWnd::Create函数-> CWnd::CreateEx函数-> CMainFrame::PreCreate
Win
dow函数-> CWnd::CreateEx函数-> CMainFrame::Show
Win
dow函数-> CMainFrame::Update
Win
dow函数-> C
Win
Thread::Run函数-> C
Win
Thread::PumpMessage函数 21、框架窗口(整个应用程序外框所包括的部分)是视类窗口(框架窗口中空白的地方)的一个父窗口 22、MFC提供了一个文档/视类的结构,文档是指CDocument类,视类是指CView类。前者用于数据的存储和加载, 后者用于数据的显示和修改 23、框架对象、文档对象和视类对象是通过一个单文档模板指针来有机地组织在一起,并利用AddDocTemplate函数 把这个单文档模板添加到文档模板中,从而把这三个类组织成为一个整体 24、MFC程序的CAboutDlg类继承于CDialog类,用于为用户提供一些与程序相关的帮助信息 三、窗口类、窗口类对象与窗口 1、以“::”开始的函数是一个全局函数,表示调用的是Platform SDK的函数 2、如果我们关闭了一个窗口,这个窗口就销毁了,那么该窗口对应的C++窗口类对象销毁了吗? (1)当一个窗口销毁时,它会调用CWnd::Destroy
Win
dow函数,该函数销毁窗口后,将CWnd::m_hWnd设为NULL (2)窗口的生命周期和C++窗口类对象的声明周期不是一致的。当一个窗口销毁时,与C++窗口类对象没有关系,它 们之间的纽带仅仅在于这个C++窗口类内部的成员变量m_hWnd,该变量保存了与这个C++窗口类对象相关的哪个窗口 的句柄 (3)但是,当C++窗口类对象销毁时,与之相关的窗口也将销毁,因为它们之间的纽带m_hWnd已经断了 3、示例---在窗口中显示按钮 (1)CButton按钮类继承于CWnd (2)对于一个CButton对象,在定义之后就可以使用了;但是,如果要显示这个按钮的话,还需调用 CButton::Create函数,把按钮窗口与CButton对象关联起来 (3)MFC程序的窗口创建时都会产生WM_CREATE消息,该消息通过OnCreate函数来捕获。对于框架窗口来说,MFC直 接把OnCreate函数提供到了CMainFrame中;而在视类窗口中没有提供该函数,如需使用,要用户自行添加 (4)通常对MFC程序的操作,都是在CTestView视类窗口中进行的 (5)在窗口创建之后,要显示该窗口可以通过调用Show
Win
dow函数或指定窗口风格为WS_VISIBLE来实现 (6)实现过程 A:在CTestView类中,添加CButton类型的私有成员m_btn B:在CTestView类中,添加WM_CREATE消息的OnCreate处理函数 C:在CTestView类中,通过GetParent函数可以获得CMainFrame框架窗口对象的指针 D:实现一(在视类窗口中通过Show
Win
dow函数显示按钮) int CTestView::OnCreate(LPCREATESTRUCT lpCreateStruct) { ... m_btn.Create("按钮",WS_CHILD|BS_DEFPUSHBUTTON,CRect(0,0,100,100),this,123); m_btn.Show
Win
dow(SW_SHOWNORMAL); return 0: } E:实现二(在视类窗口中通过WS_VISIBLE风格显示窗口) int CTestView::OnCreate(LPCREATESTRUCT lpCreateStruct) { ... m_btn.Create("按钮",WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON,CRect(0,0,100,100),this,123); return 0: } F:实现三(在框架窗口中显示按钮) int CTestView::OnCreate(LPCREATESTRUCT lpCreateStruct) { ... m_btn.Create("按钮",WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON,CRect(0,0,100,100),GetParent(),123); return 0: } 即便是基于MFC的应用程序,建立窗口类也是会遵循如下的过程: 设计窗口类->注册窗口类->生成窗口->显示窗口->更新窗口->消息循环->消息路由到窗口过程函数处理。下面就剖析一下在MFC中是如何完成上述过程的。 (1)每个应用程序都有且仅有一个应用类的全局变量the
App
,全局变量先于
Win
Main函数进行处理。 (2)
Win
Main函数体在
APP
MODUL.CPP文件中,定义如下: extern "C" int
WIN
API _t
Win
Main(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { // call shared/exported
Win
Main return Afx
Win
Main(hInstance, hPrevInstance, lpCmdLine, nCmdShow); } 其中#define _t
Win
Main
Win
Main (3)Afx
Win
Main函数体在
WIN
MAIN.CPP文件中,里面有如下两句话: C
Win
Thread* pThread = AfxGetThread(); C
Win
App
* p
App
= AfxGet
App
(); 其实这里得到的这两个指针都是指向全局的对象the
App
的; 接下来有函数调用pThread->InitInstance(),根据多态性,会调用CXXX
App
类中的InitInstance()函数。该函数很重要,在对该函数的调用中就会完成:设计窗口类->注册窗口类->生成窗口->显示窗口->更新窗口。 接下来,该函数中会继续调用pThread->Run(),这就完成了:消息循环->消息路由到窗口过程函数处理。 (4)进入CXXX
App
::InitInstance()函数体中,对于单文档应用程序,调用ProcessShellCommand(cmdInfo),通过调用该函数就会完成:设计窗口类->注册窗口类->生成窗口。 再接下来就会调用m_pMainWnd->Show
Win
dow(SW_SHOW);m_pMainWnd->Update
Win
dow();这就完成了:显示窗口->更新窗口。 (5)在函数C
Win
App
::ProcessShellCommand(CCommandLineInfo& rCmdInfo)中会进入到如下的case分支:case CCommandLineInfo::
File
New: if (!AfxGet
App
()->OnCmdMsg(ID_
FILE
_NEW, 0, NULL, NULL)) (6)进入函数CCmdTarget::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo),调用_AfxDispatchCmdMsg(this, nID, nCode, lpEntry->pfn, pExtra, lpEntry->nSig, pHandlerInfo); (7)进入函数AFXAPI _AfxDispatchCmdMsg(CCmdTarget* pTarget, UINT nID, int nCode, AFX_PMSG pfn, void* pExtra, UINT nSig, AFX_CMDHANDLERINFO* pHandlerInfo),调用 case AfxSig_vv: // normal command or control notification ASSERT(CN_COMMAND == 0); // CN_COMMAND same as BN_CLICKED ASSERT(pExtra == NULL); (pTarget->*mmf.pfn_COMMAND)(); (8)进入C
Win
App
::On
File
New(),调用m_pDocManager->On
File
New();这个函数很特殊,它本身是个消息响应函数,当我们点击ID为ID_
FILE
_NEW的菜单时,会产生一个命令消息,由于命令消息可以被CCmdTarget类及其派生类来捕获,而C
Win
App
是从CCmdTarget派生出来的,因此可以捕获这个消息。当应用程序创建完成并成功显示后,当我们点击文件菜单下的新建菜单项时,就会首先进入这个函数,然后再依次执行下去,最后就会执行到pDocument->OnNewDocument()中,往往我们会对这个函数不解,不知道它为什么会响应ID_
FILE
_NEW的命令消息,至此真相大白了。顺便说一句,为什么程序在刚启动的时候,我们并没有点击菜单项,为什么会自动的产生这个消息呢?这是因为在CXXXX
App
::InitInstance()函数中有“CCommandLineInfo cmdInfo;”这个类的构造函数是这样的:CCommandLineInfo::CCommandLineInfo() { m_bShowSplash = TRUE; m_bRunEmbedded = FALSE; m_bRunAutomated = FALSE; m_nShellCommand =
File
New; },因此就会在第(5)步骤的时候进入到“case CCommandLineInfo::
File
New:”这个分支中,就相当于产生了这样一个
File
New的消息。同理对于ID为ID_
FILE
_
OPEN
(在C
Win
App
::On
File
Open
()中响应)、ID_
FILE
_SAVE(在CDocument::On
File
Save()中响应)等等在MFC向导为我们生成的单文档类中找不到消息响应的入口时,其实都是在基类C
Win
App
或者CDocument类中进行了响应。对于CXXXXDoc::Serialize(CArchive& ar)函数也是通过ID_
FILE
_SAVE和ID_
FILE
_
OPEN
产生命令消息后就行响应从而才调用该函数的。 (9)进入CDocManager::On
File
New(),CDocManager类有一个成员变量是CPtrList m_templateList;该变量保存了一个文档模版链表指针,在CDocManager::On
File
New()函数体中会调用CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetHead();得到链表中的头,也就是第一个文档模版,后面就会用得到的这个指针去调用pTemplate->
Open
Document
File
(NULL);紧接着就会有一个判断,用来确定该链表中是否只有一项,如果链表中保存了多个文档模版,则会弹出一个对话框,来让我们选择到底是使用哪一套文档模版来构建应用程序,相信大家也都见到过这种情况吧。对了,还有一点要说明的是:pTemplate是一个CDocTemplate的指针,但接下来程序为什么会进入到CSingleDocTemplate::
Open
Document
File
的函数体内呢,这是因为CDocTemplate类中的
Open
Document
File
函数被定义为纯虚函数,而CSingleDocTemplate类又是从CDocTemplate类派生出来的,并且实现了该函数,因此就会进入到子类的函数体中了。 (10)进入CDocument* CSingleDocTemplate::
Open
Document
File
(LPCTSTR lpszPathName, BOOL bMakeVisible),先调用CreateNewDocument()创建文档类,再调用pFrame = CreateNewFrame(pDocument, NULL);创建框架类和视图类,从这里也可以看出MFC体系结构中文档、框架、视图“三位一体”的模式,在这一个函数中同时创建三个类;再会调用pDocument->OnNewDocument();因此就会进入到子类的文档类中的pDocument->OnNewDocument()中了。 (11)进入CFrameWnd* CDocTemplate::CreateNewFrame(CDocument* pDoc, CFrameWnd* pOther),调用if (!pFrame->LoadFrame(m_nIDResource, WS_OVERL
APP
ED
WIN
DOW | FWS_ADDTOTITLE, // default frame styles NULL, &context)) (12)进入BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd* pParentWnd, CCreateContext* pContext),调用VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG)); (13)进入BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister),该函数内部就完成了:设计窗口类->注册窗口类。MFC通过给我们提供好一些已经订制好的窗口类,我们不需要自己再设计窗口类,只需要到那些订制好的窗口类“仓库”中寻找一种适合我们需要的窗口类就可以了,然后通过AfxRegisterClass函数注册窗口类。还需要说明的是,再后续的跟踪过程中,我们会发现还会进入到AfxEndDeferRegisterClass函数中进行设计和注册窗口类,这主要是因为单文档应用程序比较特殊,它提前通过这样的一种途径进行了窗口类的设计和注册步骤,其实是应该在BOOL CMainFrame::PreCreate
Win
dow(CREATESTRUCT& cs)函数的调用中完成窗口类的设计和注册的,这一点我们要清楚,也就是说设计和注册窗口类的正宗发源地应该是PreCreate
Win
dow(CREATESTRUCT& cs)。此外,我们还会注意到在该函数体的前部分有一语句为“wndcls.lpfnWndProc = Def
Win
dowProc;”因此所有窗口类的窗口过程函数都是Def
Win
dowProc,这一点在后面的跟踪中可以看到,每次生成窗口之后都会调用几次Def
Win
dowProc函数。也就是说MFC都是让我们采用默认的窗口过程函数,这并不是说我们因此就不能使用自己的窗口过程函数实现个性化的消息处理了,MFC采用了一种基于消息映射的机制完成了消息个性化处理。 (14)回到BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd* pParentWnd, CCreateContext* pContext)中,调用LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource); (15)进入LPCTSTR CFrameWnd::GetIconWndClass(DWORD dwDefaultStyle, UINT nIDResource),调用PreCreate
Win
dow(cs); (16)进入BOOL CMainFrame::PreCreate
Win
dow(CREATESTRUCT& cs),调用CFrameWnd::PreCreate
Win
dow(cs) (17)进入BOOL CFrameWnd::PreCreate
Win
dow(CREATESTRUCT& cs),调用VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));又一次设计和注册窗口类 (18)回到BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd* pParentWnd, CCreateContext* pContext)中,调用if (!Create(lpszClass, lpszTitle, dwDefaultStyle, rectDefault, pParentWnd, MAKEINTRESOURCE(nIDResource), 0L, pContext)) (19)进入BOOL CFrameWnd::Create(LPCTSTR lpszClassName, LPCTSTR lpsz
Win
dowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, LPCTSTR lpszMenuName, DWORD dwExStyle, CCreateContext* pContext),调用if (!CreateEx(dwExStyle, lpszClassName, lpsz
Win
dowName, dwStyle, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext)) (20)BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpsz
Win
dowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam),调用if (!PreCreate
Win
dow(cs)) ,接下来调用HWND hWnd = ::Create
Win
dowEx(cs.dwExStyle, cs.lpszClass, cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy, cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);好了,终于让我们找到生成窗口的地方了——函数::Create
Win
dowEx! (21)进入int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct),调用if (CFrameWnd::OnCreate(lpCreateStruct) == -1) (22)进入int CFrameWnd::OnCreate(LPCREATESTRUCT lpcs),调用return OnCreateHelper(lpcs, pContext); (23)进入int CFrameWnd::OnCreateHelper(LPCREATESTRUCT lpcs, CCreateContext* pContext),调用if (CWnd::OnCreate(lpcs) == -1) (24)进入_AFX
WIN
_INLINE int CWnd::OnCreate(LPCREATESTRUCT),调用return (int)Default(); (25)进入LRESULT CWnd::Default(),调用return Def
Win
dowProc(pThreadState->m_lastSentMsg.message, pThreadState->m_lastSentMsg.wParam, pThreadState->m_lastSentMsg.lParam); (26)进入LRESULT CWnd::Def
Win
dowProc(UINT nMsg, WPARAM wParam, LPARAM lParam),调用return ::Call
Win
dowProc(m_pfnSuper, m_hWnd, nMsg, wParam, lParam); (27)回到int CFrameWnd::OnCreateHelper(LPCREATESTRUCT lpcs, CCreateContext* pContext),调用if (!OnCreateClient(lpcs, pContext)) (28)进入BOOL CFrameWnd::OnCreateClient(LPCREATESTRUCT, CCreateContext* pContext),调用if (CreateView(pContext, AFX_IDW_PANE_FIRST) == NULL) (29)进入CWnd* CFrameWnd::CreateView(CCreateContext* pContext, UINT nID),调用if (!pView->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, CRect(0,0,0,0), this, nID, pContext)) (30)进入BOOL CWnd::Create(LPCTSTR lpszClassName, LPCTSTR lpsz
Win
dowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext),调用return CreateEx(0, lpszClassName, lpsz
Win
dowName, dwStyle | WS_CHILD, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, pParentWnd->GetSafeHwnd(), (HMENU)nID, (LPVOID)pContext); (31)进入BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpsz
Win
dowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam),重复生成框架类CMainFrame的过程来生成CXXXView,因为它也是一个窗口类,因此也需要进行那一系列过程才能最终显示更新出来。 调用的顺序是这个样子的:PreCreate
Win
dow(cs)->BOOL CXXXView::PreCreate
Win
dow(CREATESTRUCT& cs)->CView::PreCreate
Win
dow(cs)->VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));->::Create
Win
dowEx(...)->CWnd::Def
Win
dowProc->::Call
Win
dowProc(...)->...->CXXXView::OnCreate->CView::OnCreate->CWnd::OnCreate->... 写到这里,基本上就清楚了,中间的省略号表示的部分大多数都是在与窗口过程函数有关的,因为在生成窗口的时候需要响应一些消息,因此需要调用一些窗口过程函数,每次在调用::Create
Win
dowEx(...)函数后都会调用一些窗口过程函数,然后再去调用该窗口类对应的OnCreate函数,其实在调用OnCreate函数之前调用Create
Win
dowEx只是生成了一个窗口,至于这个窗口里面要放置些什么东西,以及该如何装饰该窗口,则就需要由OnCreate来完成了,往往我们都会在OnCreate函数的后面(这样做是为了不影响窗口本身应该布置的格局)添加一些代码,创建我们自己的东西,比如我们通常会在CMainFrame类的OnCreate函数后面放置一些Create代码,来创建我们自己的可停靠的工具栏或者按钮之类的东西,当然我们也可以在CXXXView类的OnCreate函数的后面添加一些代码,来创建我们需要的东西,比如按钮之类的东西。在完成了从设计、注册到生成窗口的过程之后,往往还需要显示更新,有些时候,我们不必要每次都显示的调用CWnd的Show
Win
dow和Update
Win
dow两个函数,我们可以在创建的时候,给窗口风格中添加WS_VISIBLE即可,因此有些时候会跟踪不到Show
Win
dow和Update
Win
dow两个函数这两个函数,因为窗口在创建的时候就可见了。 总的来说,先初始化应用类,然后注册生成框架类,然后再注册生成视图类,然后注册生成视图类OnCreate函数后面用户添加的、用Create来准备创建的窗口,然后再注册生成框架类的OnCreate函数后面需要生成的m_wndToolBar、m_wndStatusBar以及我们自己添加的要创建的窗口类,最后在回到应用类的初始化的函数体中,调用框架类的显示和更新函数,然后再进入由框架类定义的窗口的消息循环中。 消息循环的过程是这个样子的: (1)调用int AFXAPI Afx
Win
Main(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)函数中的pThread->Run() (2)进入int C
Win
App
::Run(),调用return C
Win
Thread::Run(); (3)进入int C
Win
Thread::Run(),调用if (!PumpMessage()) (4)进入BOOL C
Win
Thread::PumpMessage(),调用if (!::GetMessage(&m_msgCur, NULL, NULL, NULL)) (5)回到BOOL C
Win
Thread::PumpMessage(),调用::TranslateMessage(&m_msgCur);::DispatchMessage(&m_msgCur); (6)回到int C
Win
Thread::Run(),调用while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE)); (7)再重复(4)-(6)的步骤 下面给出int C
Win
Thread::Run()中消息循环的部分代码: 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)); 这段代码其实本质上与我们基于
Win
32 SDK手写的代码: //消息循环 MSG msg; while(GetMessage(&msg,NULL,0,0)) { //简单的说,函数TranslateMessage就是把WM_KEYDOWN和WM_KEYUP翻译成WM_CHAR消息,没有该函数就不能产生WM_CHAR消息。 TranslateMessage(&msg); ::DispatchMessage(&msg); } 是一致的。 1,寻找
Win
Main人口: 在安装目录下找到MFC文件夹下的SRC文件夹,SRC下是MFC源代码。 路径:MFC|SRC|
APP
MODUL.CPP: _t
Win
Main(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { // call shared/exported
Win
Main return Afx
Win
Main(hInstance, hPrevInstance, lpCmdLine, nCmdShow); } 注意:(#define _t
Win
Main
Win
Main) 2,对于全局对象或全局变量来说,在程序运行即
WIN
MAIN函数加载的时候,已经为全局对象或全局变量分配了内存和赋初值。 所以:CTE
App
the
App
;->CTE
App
::CTE
App
(){}->_t
Win
Main(){} 说明:每一个MFC程序,有且只有一个从
Win
App
类派生的类(应用程序类),也只有一个从应用程序类所事例化的对象,表示应用程序本身。在
WIN
32程序当中,表示应用程序是通过
WIN
MAIN入口函数来表示的(通过一个应用程序的一个事例号这一个标识来表示的)。在基于MFC应用程序中,是通过产生一个应用程序对象,用它来唯一的表示了应用程序。 3,通过构造应用程序对象过程中调用基类C
Win
App
的构造函数,在C
Win
App
的构造函数中对程序包括运行时一些初始化工作完成了。 C
Win
App
构造函数:MFC|SRC|
APP
CORE.CPP C
Win
App
::C
Win
App
(LPCTSTR lpsz
App
Name){...}//带参数,而CTE
App
构造函数没有显式向父类传参,难道C
Win
App
()有默认参数?见下: (在C
Win
App
类定义中, C
Win
App
(LPCTSTR lpsz
App
Name = NULL); ) 注意:C
Win
App
()函数中: pThreadState->m_pCurrent
Win
Thread = this; pModuleState->m_pCurrent
Win
App
= this (this指向的是派生类CTE
App
对象,即the
App
) 调试:C
Win
App
::C
Win
App
();->CTE
App
the
App
;(->CTE
App
::CTE
App
())->C
Win
App
::C
Win
App
()->CTE
App
::CTE
App
()->_t
Win
Main(){} 4,_t
Win
Main函数中通过调用Afx
Win
Main()函数来完成它要完成的功能。(Afx*前缀代表这是应用程序框架函数,是一些全局函数,应用程序框架是一套辅助生成应用程序的框架模型,把一些类做一些有机的集成,我们可根据这些类函数来设计自己的应用程序)。 Afx
Win
Main()函数路径:MFC|SRC|
WIN
MAIN.CPP: 在Afx
Win
Main()函数中: C
Win
App
* p
App
= AfxGet
App
(); 说明:p
App
存储的是指向
Win
App
派生类对象(the
App
)的指针。 //_AFX
WIN
_INLINE C
Win
App
* AFXAPI AfxGet
App
() // { return afxCurrent
Win
App
; } 调用pThread->InitInstance() 说明:pThread也指向the
App
,由于基类中virtual BOOL Init
App
lication()定义为虚函数,所以调用pThread->InitInstance()时候,调用的是派生类CTE
App
的InitInstance()函数。 nReturnCode = pThread->Run(); 说明:pThread->Run()完成了消息循环。 5,注册窗口类:AfxEndDeferRegisterClass(); AfxEndDeferRegisterClass()函数所在文件:MFC|SRC|
APP
CORE.CPP BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister){...} 说明:设计窗口类:在MFC中事先设计好了几种缺省的窗口类,根据不同的应用程序的选择,调用AfxEndDeferRegisterClass()函数注册所选择的窗口类。 调试:C
Win
App
::C
Win
App
();->CTE
App
the
App
;(->CTE
App
::CTE
App
())->C
Win
App
::C
Win
App
()->CTE
App
::CTE
App
()->_t
Win
Main(){}//进入程序 ->Afx
Win
Main();->p
App
->Init
App
lication();->pThread->InitInstance()//父类InitInstance虚函数;->CTE
App
::InitInstance()//子类实现函数;->AfxEndDeferRegisterClass(LONG fToRegister)//注册所选择的窗口类(出于文档管理,注册提前,正常的应在PreCreate
Win
dow中进行注册)//之后进入创建窗口阶段(以下再不做调试) 6,PreCreate
Win
dow()://主要是注册窗口类 BOOL CMainFrame::PreCreate
Win
dow(CREATESTRUCT& cs) { if( !CFrameWnd::PreCreate
Win
dow(cs) ) return FALSE; return TRUE; } 说明: CFrameWnd::PreCreate
Win
dow()函数所在文件:MFC|SRC|
WIN
FRM.CPP BOOL CFrameWnd::PreCreate
Win
dow(CREATESTRUCT& cs) { if (cs.lpszClass == NULL) { VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG)); //判断AFX_WNDFRAMEORVIEW_REG型号窗口类是否注册,如果没有注册则注册 cs.lpszClass = _afxWndFrameOrView; // COLOR_
WIN
DOW background //把注册后的窗口类名赋给cs.lpszClass } if ((cs.style & FWS_ADDTOTITLE) && afxData.b
Win
4) cs.style |= FWS_PREFIXTITLE; if (afxData.b
Win
4) cs.dwExStyle |= WS_EX_CLIENTEDGE; return TRUE; } 其中: virtual BOOL PreCreate
Win
dow(CREATESTRUCT& cs);//PreCreate
Win
dow()是个虚函数,如果子类有则调用子类的。 #define VERIFY(f) ASSERT(f) #define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass) define AFX_WNDFRAMEORVIEW_REG 0x00008 const TCHAR _afxWndFrameOrView[] = AFX_WNDFRAMEORVIEW;//
WIN
CORE.CPP文件中,定义为全局数组。 //#define AFX_WNDFRAMEORVIEW AFX_WNDCLASS("FrameOrView") 7,创建窗口: Create()函数路径:MFC|SRC|
WIN
FRM.CPP: CFrameWnd::Create(...){ ... CreateEx(...);//从父类继承来的,调用CWnd::CreateEx(). ... } CWnd::CreateEx()函数路径:MFC|SRC|
WIN
CORE.CPP BOOL CWnd::CreateEx(...){ ... if (!PreCreate
Win
dow(cs))//虚函数,如果子类有调用子类的。 { PostNcDestroy(); return FALSE; } ... HWND hWnd = ::Create
Win
dowEx(cs.dwExStyle, cs.lpszClass, cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy, cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams); ... } 说明:Create
Win
dowEx()函数与CREATESTRUCT结构体参数的对应关系,使我们在创建窗口之前通过可PreCreate
Win
dow(cs)修改cs结构体成员来修改所要的窗口外观。PreCreate
Win
dow(cs))//是虚函数,如果子类有调用子类的。 HWND Create
Win
dowEx( DWORD dwExStyle, LPCTSTR lpClassName, LPCTSTR lp
Win
dowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam ); typedef struct tagCREATESTRUCT { // cs LPVOID lpCreateParams; HINSTANCE hInstance; HMENU hMenu; HWND hwndParent; int cy; int cx; int y; int x; LONG style; LPCTSTR lpszName; LPCTSTR lpszClass; DWORD dwExStyle; } CREATESTRUCT; 8,显示和更新窗口: CTE
App
类,TE
App
.cpp中 m_pMainWnd->Show
Win
dow(SW_SHOW);//显示窗口,m_pMainWnd指向框架窗口 m_pMainWnd->Update
Win
dow();//更新窗口 说明: class CTE
App
: public C
Win
App
{...} class C
Win
App
: public C
Win
Thread{...} class C
Win
Thread : public CCmdTarget { ... public: CWnd* m_pMainWnd; ... ... } 9,消息循环: int AFXAPI Afx
Win
Main() { ... // Perform specific initializations if (!pThread->InitInstance()){...} //完成窗口初始化工作,完成窗口的注册,完成窗口的创建,显示和更新。 nReturnCode = pThread->Run(); //继承基类Run()方法,调用C
Win
Thread::Run()来完成消息循环 ... } //////////////////////////////////////////////////////////////// C
Win
Thread::Run()方法路径:MFC|SRC|THRDCORE.CPP int C
Win
Thread::Run() { ... // phase2: pump messages while available do//消息循环 { // pump message, but quit on WM_QUIT if (!PumpMessage())//取消息并处理 return ExitInstance(); ... } while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE)); ... } 说明: BOOL PeekMessage(,,,,)函数说明 The PeekMessage function checks a thread message queue for a message and places the message (if any) in the specified structure. If a message is available, the return value is nonzero. If no messages are available, the return value is zero. ///////////////////////////////////////////////////////////// BOOL C
Win
Thread::PumpMessage() { ... if (!::GetMessage(&m_msgCur, NULL, NULL, NULL))//取消息 {...} ... // process this message if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur)) { ::TranslateMessage(&m_msgCur);//进行消息(如键盘消息)转换 ::DispatchMessage(&m_msgCur);//分派消息到窗口的回调函数处理(实际上分派的消息经过消息映射,交由消息响应函数进行处理。) } return TRUE; } 9,文档与视结构: 可以认为View类窗口是CMainFram类窗口的子窗口。 DOCument类是文档类。 DOC-VIEW结构将数据本身与它的显示分离开。 文档类:数据的存储,加载 视类:数据的显示,修改 10,文档类,视类,框架类的有机结合: 在CTE
App
类CTE
App
::InitInstance()函数中通过文档模板将文档类,视类,框架类的有机组织一起。 ... CSingleDocTemplate* pDocTemplate; pDocTemplate = new CSingleDocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CTEDoc), RUNTIME_CLASS(CMainFrame), // main SDI frame
win
dow RUNTIME_CLASS(CTEView)); AddDocTemplate(pDocTemplate);//增加到模板
大地测量中的大地正解
贝塞尔 正解 大地测量 // 大地测量学.cpp : Defines the class behaviors for the
app
lication. // #include "stdafx.h" #include "大地测量学.h" #include "MainFrm.h" #include "大地测量学Doc.h" #include "大地测量学View.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_
FILE
static char THIS_
FILE
[] = __
FILE
__; #endif ////////////////
毕业设计五子棋源代码
// FiveChess.cpp : Defines the class behaviors for the
app
lication. // #include "stdafx.h" #include "FiveChess.h" #include "MainFrm.h" #include "FiveChessDoc.h" #include "FiveChessView.h" #include "afxsock.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_
FILE
static char THIS_
FILE
[] = __
FILE
__; #endif //////////////////////////////////////////////////////////////////////////// // CFiveChess
App
BEGIN_MESSAGE_MAP(CFiveChess
App
, C
Win
App
) //{{AFX_MSG_MAP(CFiveChess
App
) ON_COMMAND(ID_
APP
_ABOUT, On
App
About) // NOTE - the ClassWizard will add and remove m
app
ing macros here. // DO NOT EDIT what you see in these blocks of generated code! //}}AFX_MSG_MAP // Standard
file
based document commands ON_COMMAND(ID_
FILE
_NEW, C
Win
App
::On
File
New) ON_COMMAND(ID_
FILE
_
OPEN
, C
Win
App
::On
File
Open
) // Standard print setup command ON_COMMAND(ID_
FILE
_PRINT_SETUP, C
Win
App
::On
File
PrintSetup) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CFiveChess
App
construction CFiveChess
App
::CFiveChess
App
() { // TODO: add construction code here, // Place all significant initialization in InitInstance } ///////////////////////////////////////////////////////////////////////////// // The one and only CFiveChess
App
object CFiveChess
App
the
App
; ///////////////////////////////////////////////////////////////////////////// // CFiveChess
App
initialization BOOL CFiveChess
App
::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 follo
win
g // 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
app
ropriate // such as the name of your company or organization. SetRegistryKey(_T("Local
App
Wizard-Generated
App
lications")); LoadStdPro
file
Settings(); // Load standard INI
file
options (including MRU) // Register the
app
lication's document templates. Document templates // serve as the connection between documents, frame
win
dows and views. CSingleDocTemplate* pDocTemplate; pDocTemplate = new CSingleDocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CFiveChessDoc), RUNTIME_CLASS(CMainFrame), // main SDI frame
win
dow RUNTIME_CLASS(CFiveChessView)); AddDocTemplate(pDocTemplate); // 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 one and only
win
dow has been initialized, so show and update it. m_pMainWnd->Show
Win
dow(SW_SHOW); m_pMainWnd->Update
Win
dow(); return TRUE; } ///////////////////////////////////////////////////////////////////////////// // CAboutDlg dialog used for
App
About class CAboutDlg : public CDialog { public: CAboutDlg(); // Dialog Data //{{AFX_DATA(CAboutDlg) enum { IDD = IDD_ABOUTBOX }; //}}AFX_DATA // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CAboutDlg) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: //{{AFX_MSG(CAboutDlg) // No message handlers //}}AFX_MSG DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { //{{AFX_DATA_INIT(CAboutDlg) //}}AFX_DATA_INIT } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CAboutDlg) //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) //{{AFX_MSG_MAP(CAboutDlg) // No message handlers //}}AFX_MSG_MAP END_MESSAGE_MAP() //
App
command to run the dialog void CFiveChess
App
::On
App
About() { CAboutDlg aboutDlg; aboutDlg.DoModal(); } ///////////////////////////////////////////////////////////////////////////// // CFiveChess
App
message handlers
ATL
3,245
社区成员
48,539
社区内容
发帖
与我相关
我的任务
ATL
ATL,Active Template Library活动(动态)模板库,是一种微软程序库,支持利用C++语言编写ASP代码以及其它ActiveX程序。
复制链接
扫一扫
分享
社区描述
ATL,Active Template Library活动(动态)模板库,是一种微软程序库,支持利用C++语言编写ASP代码以及其它ActiveX程序。
社区管理员
加入社区
获取链接或二维码
近7日
近30日
至今
加载中
查看更多榜单
社区公告
暂无公告
试试用AI创作助手写篇文章吧
+ 用AI写文章