我使用MFC单文档创建工程,在cmainframe类中怎么没有 OnCreateClient这个函数呢

关于CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)//没响应?的搜索推荐 -MFC-TryCatch
>> 相关推荐
关于的搜索推荐
打断点也不行??????????????????????
你是怎么加的这个函数,如果是手工加的,你可能没有加消息映射了
/question/9316026.html 是否响应WM_CREATE消息
Nevercallthisfunction. 不要调用这个函数
/en-us/library/5t513e2c.aspx
这是个虚函数,怎么打断点不行了?你确定在debug模式下调试吗?
告诉我咋办就行了,看不懂你发的地址
引用3楼sha_jinhao的回复:
Nevercallthisfunction. 不要调用这个函数
/en-us/library/5t513e2c.aspx
咋回事啊!!!!!!!!!!
RebuildAll一下,确实你是Debug模式下运行?
在头文件中加入virtualBOOLOnCreateClient(LPCREATESTRUCTlpcs,CCreateContext*pContext);
你这问题没头没脑的 消息怎么添加的?
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/,CCreateContext* pContext)
------------
Never call this function.The default implementation o...
Tab对象//Obj.Create(50,250,this,007);
BOOL TabEx::Create(int sx,int sy,CWnd* pParent,UINT nID,CCreateContext* pContext){CString szClassName = AfxRegi...
本帖最后由 chyun7290 于
14:02:47 编辑
------------
是lpCreateStruct-&lpCreateParams为空,为什么会为空
------------
那个 View create ...
hi,用着vs2005还是和vs6.0差别很大,现在做一个SDI想重载CMainFrame的OnCreateClient却怎么都找不到,在属性里面找了,只找到了OnCreate的重写。不太清楚是我程序...
msdn里说当选中某个类后才可看到,我已经选了,还是没有。
------------
OnCreateClient是CFrameWnd类的虚函数,而CMainFrame类是CFrameWnd类是继承类.在类的头...
在CMainFrame的OnCreateClient添加如下代码,运行时菜单的“打印”与“打印预览”就会被禁用BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateCont...
要在视图类中添加一个CEdit控件,代码如下,没有产生效果,加断点发现,启动时没有进入OnCreate。但在另一个程序中是有效的,不知道为什么?int CFFTtestView::O...
当对话框插入在1位置时,运行时能够弹出显示。而插入在2位置时,运行时不会弹出显示。自己思考了半天,得出的结论是1位置以后的代码貌似都没有运行。这是为什么呢...
如题,m_pMainWnd 不就是指向CMainFrame类的吗??
------------
CWinThread::m_pMainWnd
Use this data member to store a pointer to your thread's main ...
EVC中我通过classwizard添加一个::OnCreate(LPCREATESTRUCT lpCreateStruct),为什么没执行到啊?如何让他能执行到呢?
------------
顶!期待中。。。。
现在想重绘部分主菜单区域,问题是在CMainFrame里面响应了一些诸如WM_NCPAINT的消息重绘后,菜单栏总会闪。应该是因为在某些事件后,菜单本身重绘了而我没有处理...
想在框架中响应鼠标左键单击操作,问问有没有办法可以实现,同时VIEW类也可以响应鼠标消息
------------
框架中响应鼠标左键单击操作,干啥?
------------
请教一个问题?我有一个多文档程序,在CMainFrame 里有一个TREE,我想加入TREE的双击节点消息,让FORMVIEW做出相应的响应。 //MainFrm.h
CTreeCtre...
我的步骤如下:打开资源视图,展开Menu,双击IDR_MAINFRAME,弹出菜单设计窗口。右击“保存“菜单,左击添加事件处理程序,弹出事件处理程序向导,消息类型选COMM...
本人从CToolBar中派生出一个类CMainToolBar,是用于创建一个新的工具栏,并创建了一个开始按钮,OnBegin()这个函数就是响应这个开始按钮,而本人想把OnBegin()这个消...MFC文档视图结构内幕 - flying-roc - 博客园
Powered by:
模板提供:
////////////////////////////////////////////////////////////////////////////////////&&&&&&&&&&&&&&&&&&&& /********* 文章系列:MFC技术内幕系列***********/&&&&&&&&&&&&&&&&&&&& /************MFC技术内幕系列之(二)***********/&&&&&&&&&&&&&&&&&&&& /****&&& 文章题目:MFC文档视图结构内幕&&&&&&& & *****/&&&&&&&&&&&&&&&&&&&& /*&&&&&&&&&&&&&&&&&&&&&&&&&& Copyright(c)2002 bigwhite&&&&&&&&&& & */&&&&&&&&&&&&&&&&&&&& /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& & All rights Reserved&&&&&&&&&&&& &&&&& */&&&&&&&&&&&&&&&&&&&& /*********关键字:MFC,文档视图结构************/&&&&&&&&&&&&&&&&&&&& /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &时间:&&&&&&&&&&&&&& &&& */&&&&&&&&&&&&&&&&&&&& /*&&&& 注释:本文所涉及的程序源代码均在Microsoft&& */&&&&&&&&&&&&&&&&&&&& /&&&&&&&&&&&&&Visual Studio.Net Enterprise Architect Edition&& /&&&&&&&&&&&&&&&&&&&& /*&&&&&&&&&&&&&&&&&& 开发工具包提供的源代码中&&&&&&&&&&& &&& */&&&&&&&&&&&&&&&&&&&&&//////////////////////////////////////////////////////////////////////////////////////////////////////////引言:侯捷老师的"深入浅出MFC"一书的第8章中有&"Document/View"是MFC的基石。&一说,可以看出文档视图结构在MFC Framework中的地位是多么的重要。本文将以一个标准MFC应用程序向导作成的MDI程序为例,来和大家一起详细挖掘文档视图结构的内幕。
正文:&&&&&&&&&&&&&&&&&&&&&& /////////////////////////////////////////////&&&&&&&&&&&&&&&&&&&&&& /*& 1.回顾"InitInstance函数"& */&&&&&&&&&&&&&&&&&&&&&& /////////////////////////////////////////////&& 在我的《MFC应用程序&生死因果&内幕》一文中,当谈到CMyWinApp::InitInstance()时,我只是粗略的讲了介绍了一下各个函数的功能,而忽略了很多细节,这里让我们在回顾一下CMyWinApp::InitInstance()函数,并将里面与文档视图结构有关的代码深入探讨一下:&& BOOL CMyApp::InitInstance()//只列出了与文档视图结构相关的源代码& {&//...
&//文档模板将用作文档、框架窗口和视图之间的连接&CMultiDocTemplate* pDocT&pDocTemplate = new CMultiDocTemplate(IDR_MyTYPE,&&RUNTIME_CLASS(CMyDoc),&&RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架&&RUNTIME_CLASS(CMyView));&AddDocTemplate(pDocTemplate);&// 创建主 MDI 框架窗口&CMainFrame* pMainFrame = new CMainF&if (!pMainFrame-&LoadFrame(IDR_MAINFRAME))&&return FALSE;&m_pMainWnd = pMainF&// 仅当具有后缀时才调用 DragAcceptFiles&//& 在 MDI 应用程序中,这应在设置 m_pMainWnd 之后立即发生&// 分析标准外壳命令、DDE、打开文件操作的命令行&CCommandLineInfo cmdI&ParseCommandLine(cmdInfo);&// 调度在命令行中指定的命令。如果&// 用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序,则返回 FALSE。&if (!ProcessShellCommand(cmdInfo))&&return FALSE;&// 主窗口已初始化,因此显示它并对其进行更新&pMainFrame-&ShowWindow(m_nCmdShow);&pMainFrame-&UpdateWindow();&return TRUE;&}
&&&&&&&&&&&&&&&&&&&&&& ////////////////////////////////////////////&&&&&&&&&&&&&&&&&&&&&& /*&&&& 2.初始化文档模板&&&&&& */&&&&&&&&&&&&&&&&&&&&&& ////////////////////////////////////////////分析以下代码:&&&&&&& CMultiDocTemplate* pDocT&pDocTemplate = new CMultiDocTemplate(IDR_MyTYPE,&&RUNTIME_CLASS(CMyDoc),&&RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架&&RUNTIME_CLASS(CMyView));&&& 应用程序首先实例化一个CMultiDocTemplate对象,此过程也是对CMultiDocTemplate类数据成员的初始化过程。按调用次序我列出了以下源代码:&&& 注释1: CDocTemplate构造函数定义在:..\Visual Studio.NET\vc7\atlmfc\src\mfc\doctempl.cpp&CDocTemplate::CDocTemplate(UINT nIDResource, CRuntimeClass* pDocClass,&&&&&&&&&& CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass)//部分源代码&{&ASSERT_VALID_IDR(nIDResource);&ASSERT(pDocClass == NULL ||&&pDocClass-&IsDerivedFrom(RUNTIME_CLASS(CDocument)));&ASSERT(pFrameClass == NULL ||&&pFrameClass-&IsDerivedFrom(RUNTIME_CLASS(CFrameWnd)));&ASSERT(pViewClass == NULL ||&&pViewClass-&IsDerivedFrom(RUNTIME_CLASS(CView)));
&m_nIDResource = nIDR&...//&&&&&&& m_pDocClass = pDocC&m_pFrameClass = pFrameC&m_pViewClass = pViewC&m_pOleFrameClass = NULL;&m_pOleViewClass = NULL;&&&&&&& ...//&}& 以上为CMultiDocTemplate类的基类CDocTemplate构造函数的部分源代码,该函数初始化了四个重要的成员m_nIDResource,m_pDocClass,m_pFrameClass和m_pViewClass。&& 注释2: CMultiDocTemplate构造函数定义在:..\Visual Studio.NET\vc7\atlmfc\src\mfc\docmulti.cpp&& CMultiDocTemplate::CMultiDocTemplate(UINT nIDResource, CRuntimeClass* pDocClass,&CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass)&&: CDocTemplate(nIDResource, pDocClass, pFrameClass, pViewClass)& {&ASSERT(m_docList.IsEmpty());
&m_hMenuShared = NULL;&m_hAccelTable = NULL;&m_nUntitledCount = 0;&& // start at 1
&// load resources in constructor if not statically allocated&if (!CDocManager::bStaticInit)&&LoadTemplate();& }&& 看完以上代码后,来回过头看一看InitInstance函数将什么参数值传给了CMultiDocTemplate的构造函数。原来是一些RUNTIME_CLASS宏。以下是RUNTIME_CLASS宏的定义:&& 注释3: 以下的宏定义在:..\Visual Studio.NET\vc7\atlmfc\include\afx.h中&& #define RUNTIME_CLASS(class_name) _RUNTIME_CLASS(class_name)&& #define _RUNTIME_CLASS(class_name) ((CRuntimeClass*)(&class_name::class##class_name))&& 这个地方是个难点,这将涉及到MFC的另一个重要技术---"执行期类型识别"。此项技术我将在MFC技术内幕系列之(三)---《MFC执行期类型识别与动态创建技术内幕》中详细讲解。回到眼前来,源代码中这样作是为了将CMyDoc,CChildFrame,CMyView各类中的static CRuntimeClass class##class_name地址赋予CMultiDocTemplate类的各CRuntimeClass*指针成员m_pDocClass,m_pFrameClass和m_pViewClass,这位以后的动态创建Document/Frame/View"三口组"打下了基础。&&&&&&&&&&&&&&&&&&&&&& ///////////////////////////////////////////&&&&&&&&&&&&&&&&&&&&&& /*&&&&&& 3.文档模板列队&&&&&& */&&&&&&&&&&&&&&&&&&&&&& ///////////////////////////////////////////&& 文档模板初始化结束后,InitInstance函数调用了CWinApp::AddDocTemplate(pDocTemplate)函数,其主要目的是将以初始化后的那个文档模板加入到文档模板链表中,并由CDocManager类对象进行管理。以下操作就是为了完成此工作。
注释1: 以下函数定义在:..\Visual Studio.NET\vc7\atlmfc\src\mfc\appui2.cppvoid CWinApp::AddDocTemplate(CDocTemplate* pTemplate)//将CMultiDocTemplate* pDocTemplate{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& //传给pTemplate&if (m_pDocManager == NULL)&&m_pDocManager = new CDocM&m_pDocManager-&AddDocTemplate(pTemplate);}注释2: 以下函数定义在:..\Visual Studio.NET\vc7\atlmfc\src\mfc\docmgr.cpp&CDocManager::CDocManager()&{& }//目前是一个空函数;
&void CDocManager::AddDocTemplate(CDocTemplate* pTemplate)//部分源代码&{&if (pTemplate == NULL)&{&&...//&}&else&{&&ASSERT_VALID(pTemplate);&&ASSERT(m_templateList.Find(pTemplate, NULL) == NULL);// must not be in list&&pTemplate-&LoadTemplate();&&m_templateList.AddTail(pTemplate);//CPtrList m_templateList is a member&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& //of CDocManager&}&}
&&&&&&&&&&&&&&&&&&&&&& ///////////////////////////////////////////////&&&&&&&&&&&&&&&&&&&&&& /*&&& 4.创建程序主框架窗口&&& */&&&&&&&&&&&&&&&&&&&&&& ///////////////////////////////////////////////&&& 应用程序实例化了一个CMainFrame类对象,并调用LoadFrame函数加载窗口资源创建主框架窗口。以下是创建主框架窗口的流程。&&& 创建窗口的主要代码是:pMainFrame-&LoadFrame(IDR_MAINFRAME);LoadFrame函数是MFC包装了窗口创建过程的函数,在后面动态创建Child窗口时,它还将披挂上阵(但稍有不同)。下面是它的源代码,让我们仔细分析一下:& 注释1: 以下函数定义在:..\Visual Studio.NET\vc7\atlmfc\src\mfc\winmdi.cpp&&&&& BOOL CMDIFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,&CWnd* pParentWnd, CCreateContext* pContext)&&&&&&&&&&&&{&if (!CFrameWnd::LoadFrame(nIDResource, dwDefaultStyle,&& pParentWnd, pContext))&&return FALSE;
&// save menu to use when no active MDI child window is present&ASSERT(m_hWnd != NULL);&m_hMenuDefault = ::GetMenu(m_hWnd);&if (m_hMenuDefault == NULL)&&TRACE(traceAppMsg, 0, "Warning: CMDIFrameWnd without a default menu.\n");&return TRUE;&}& CMDIFrameWnd::LoadFrame调用了其基类CFrameWnd的LoadFrame,并将参数原封不动的传给它。
& 注释2: 以下函数定义在:..\Visual Studio.NET\vc7\atlmfc\src\mfc\winfrm.cpp&BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,&CWnd* pParentWnd, CCreateContext* pContext)&&&&&&&&& //部分源代码&{&...//&CString strFullS&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);&CString strTitle = m_strT&if (!Create(lpszClass, strTitle, dwDefaultStyle, rectDefault,&& pParentWnd, MAKEINTRESOURCE(nIDResource), 0L, pContext))&{&&return FALSE;&& // will self destruct on failure normally&}
&...//&if (pContext == NULL)&& // send initial update&&SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE);
&return TRUE;&}&&&&&&&&&&&&&&&&&&&&&& //////////////////////////////////////////////////////&&&&&&&&&&&&&&&&&&&&&& /* 4.1注册应用程序主框架窗口类 */&&&&&&&&&&&&&&&&&&&&&& //////////////////////////////////////////////////////&& 在传统的Win32API编程中,创建窗口一般步骤是定义窗口类,注册窗口类,并调用::CreateWindow函数来创建。前面说过LoadFrame函数封装了MFC创建窗口的过程,那么也就是说LoadFrame函数将负责定义窗口类,注册窗口类等琐碎工作。下面我们就通过挖掘源代码来看看LoadFrame函数是如何完成这些工作的。&& LoadFrame首先调用AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG),&& 注释1: 以下宏定义在:..\Visual Studio.NET\vc7\atlmfc\src\mfc\afximpl.h&&&&&& #define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass)&&&&& 注释2: 以下函数定义在:..\Visual Studio.NET\vc7\atlmfc\src\mfc\wincore.cpp&&& BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)//部分源代码& {&// mask off all classes that are already registered&AFX_MODULE_STATE* pModuleState = AfxGetModuleState();&fToRegister &= ~pModuleState-&m_fRegisteredC&if (fToRegister == 0)&&return TRUE;
&LONG fRegisteredClasses = 0;
&// common initialization&WNDCLASS&memset(&wndcls, 0, sizeof(WNDCLASS));&& // start with NULL defaults&wndcls.lpfnWndProc = DefWindowP&wndcls.hInstance = AfxGetInstanceHandle();&wndcls.hCursor = afxData.hcurA
&INITCOMMONCONTROLSEX&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 = _afxW&&if (AfxRegisterClass(&wndcls))&&&fRegisteredClasses |= AFX_WND_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;&} &&&&&&&&&&&&&&&& ...//&// must have registered at least as mamy classes as requested&return (fToRegister & fRegisteredClasses) == fToR&& }&& MFC预定义了若干个&窗口类模板&,比如"AFX_WNDMDIFRAME_REG","AFX_WNDFRAMEORVIEW_REG"等,MFC在LoadFrame函数中调用AfxEndDeferRegisterClass函数为你的应用程序预注册了适当的窗口类。本例中预注册的窗口类为AFX_WNDFRAMEORVIEW_REG。(注意是预注册,如果你在后面更改了CREATESTRUCT结构的域成员,MFC还会根据你的更改重新为你的应用程序正式注册新的窗口类,稍候会有详细叙述)&&&&& 预注册完窗口类,MFC将判断你是否想更改窗口类的各参数。若你更改了,则MFC会重新注册新类;否则源预注册的窗口类就将成为正式的窗口类。下面我们来看看MFC的判断过程:此判断过程由GetIconWndClass开始& LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource);& 注释3: 以下函数定义在:..\Visual Studio.NET\vc7\atlmfc\src\mfc\winfrm.cpp&&& LPCTSTR CFrameWnd::GetIconWndClass(DWORD dwDefaultStyle, UINT nIDResource)//部分源代码&{&...//&HICON hIcon = ::LoadIcon(hInst, MAKEINTRESOURCE(nIDResource));&if (hIcon != NULL)&{&&CREATESTRUCT&&memset(&cs, 0, sizeof(CREATESTRUCT));&&cs.style = dwDefaultS&&PreCreateWindow(cs);&&&// will fill lpszClassName with default WNDCLASS name&&&// ignore instance handle from PreCreateWindow.
&&WNDCLASS&&if (cs.lpszClass != NULL &&&&&GetClassInfo(AfxGetInstanceHandle(), cs.lpszClass, &wndcls) &&&&&wndcls.hIcon != hIcon)&&{&&&// register a very similar WNDCLASS&&&return AfxRegisterWndClass(wndcls.style,&&&&wndcls.hCursor, wndcls.hbrBackground, hIcon);&&}&}&return NULL;&&&&&&& // just use the default}&& GetIconWndClass函数将调用CMainFrame::PreCreateWindow(CREATESTRUCT& cs)来看看应用程序是否修改了CREATESTRUCT结构的域成员。CMainFrame::PreCreateWindow调用&& CMDIFrameWnd::PreCreateWindow(CREATESTRUCT& cs),后者的代码如下:& BOOL CMDIFrameWnd::PreCreateWindow(CREATESTRUCT& cs)//in winmdi.cpp& {&if (cs.lpszClass == NULL)&{&&VERIFY(AfxDeferRegisterClass(AFX_WNDMDIFRAME_REG));&&cs.lpszClass = _afxWndMDIF&}&return TRUE;& }& MFC将为应用程序注册AFX_WNDMDIFRAME_REG预定义窗口类,并设置cs.lpszClass = _afxWndMDIFrame。在应用程序的代码中我更改了cs结构:& BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)&{&if( !CMDIFrameWnd::PreCreateWindow(cs) )&&return FALSE;&// TODO: 在此处通过修改 CREATESTRUCT cs 来修改窗口类或&// 样式&cs.dwExStyle=~WS_EX_CLIENTEDGE;&return TRUE;&}&&&&&&CMainFrame::PreCreateWindow返回后,GetIconWndClass函数调用GetClassInfo函数重新收集cs信息(此时的信息已是更改后的了),并调用AfxRegisterWndClass函数重新注册该窗口类(此窗口类为该应用程序的正式窗口类)。到此为止窗口类注册完毕,以后程序还会调用一次CMainFrame::PreCreateWindow,不过那此只是"过门不如"而已。&&&&&&&&&&&&&&&&&&&&&& /////////////////////////////////////////////////&&&&&&&&&&&&&&&&&&&&&& /*&&& 4.2主框架窗口创建开始&&& */&&&&&&&&&&&&&&&&&&&&&& /////////////////////////////////////////////////
& 开始进入创建框架窗口的实质阶段。看LoadFrame函数做了什么?原来它调用了Create函数。& 注释1: 以下函数定义在:..\Visual Studio.NET\vc7\atlmfc\src\mfc\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)&&{&&&TRACE(traceAppMsg, 0, "Warning: failed to load menu for CFrameWnd.\n");&&&PostNcDestroy();&&&&&&&&&&& // perhaps delete the C++ object&&&return FALSE;&&}&}
&m_strTitle = lpszWindowN&&& // 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))&{&&TRACE(traceAppMsg, 0, "Warning: failed to create CFrameWnd.\n");&&if (hMenu != NULL)&&&DestroyMenu(hMenu);&&return FALSE;&}
&return TRUE;& }
& 简单地说CFrameWnd::Create函数调用了基类的CWnd::CreateEx;& 注释2: 以下函数定义在:..\Visual Studio.NET\vc7\atlmfc\src\mfc\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.dwExStyle = dwExS&cs.lpszClass = lpszClassN&cs.lpszName = lpszWindowN&cs.style = dwS&cs.x =&cs.y =&cs.cx = nW&cs.cy = nH&cs.hwndParent = hWndP&cs.hMenu = nIDorHM&cs.hInstance = AfxGetInstanceHandle();&cs.lpCreateParams = lpP
&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);&&&&&&& ...//&&&&&&&&&&&&&&& return TRUE;&}
&BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)&{&if( !CMDIFrameWnd::PreCreateWindow(cs) )&&return FALSE;&// TODO: 在此处通过修改 CREATESTRUCT cs 来修改窗口类或&// 样式&&&&&&& cs.dwExStyle=~WS_EX_CLIENTEDGE;&return TRUE;&}
&BOOL CMDIFrameWnd::PreCreateWindow(CREATESTRUCT& cs)&{&if (cs.lpszClass == NULL)&{&&VERIFY(AfxDeferRegisterClass(AFX_WNDMDIFRAME_REG));&&cs.lpszClass = _afxWndMDIF&}&return TRUE;&}&& CWnd::CreateEx调用了CMainFrame::PreCreateWindow,但此次AfxDeferRegisterClass将不会被调用。也就是我上面所说的&过门不入&。
&&& CWnd::CreateEx函数还调用了AfxHookWindowCreate(this);后者是干什么的呢?其实它与消息映射和命令传递有关,我将在MFC技术内幕系列之(四)--《MFC消息映射与消息传递内幕》一文中详解。&&&&& CWnd::CreateEx调用Win32API ::CreateWindowEx函数(传统的Win32API程序员一定不陌生这个函数),就这样主框架窗口创建结束。
&&&&&&&&&&&&&&&&&&&&&& //////////////////////////////////////////////&&&&&&&&&&&&&&&&&&&&&& /*&&&& 5.标准外壳命令解析&&&&& */&&&&&&&&&&&&&&&&&&&&&& ///////////////////////////////////////////////&&& MFC向导制作的标准MDI应用程序启动时,应用程序会自动启动一个子窗口框架(实际上是一套文档模板),这是为何呢?下面我将详细讲解一下这个创建过程.&&& 其实这一过程也是在CMyWinApp::InitInstance()函数中完成的,看看下面代码:
&&&&&&& CCommandLineInfo cmdI&ParseCommandLine(cmdInfo);&&&&&&& if (!ProcessShellCommand(cmdInfo))&&return FALSE;&& 函数首先实例化一个CCommandLineInfo类对象cmdInfo,让我们看看CCommandLineInfo是个什么东东?&&&//in afxwin.h&class CCommandLineInfo : public CObject//部分源代码{&public:&// Sets default values&CCommandLineInfo();&&&&&&& ...//&BOOL m_bShowS&BOOL m_bRunE&BOOL m_bRunA&enum { FileNew, FileOpen, FilePrint, FilePrintTo, FileDDE, AppRegister,&&AppUnregister, FileNothing = -1 } m_nShellC
&// not valid for FileNew&CString m_strFileN
&// valid only for FilePrintTo&CString m_strPrinterN&CString m_strDriverN&CString m_strPortN
&~CCommandLineInfo();&&&&&&& // Implementation&&&&&&& ...//&};
&再让我们来看看它的构造函数的实现:
//in appcore.cpp&CCommandLineInfo::CCommandLineInfo()&{&m_bShowSplash = TRUE;&m_bRunEmbedded = FALSE;&m_bRunAutomated = FALSE;&m_nShellCommand = FileN&}&m_nShellCommand = FileN这一句对我们最重要;至于CWinApp::ParseCommandLine我想用MFC文档中的一句话来解释:&& Call this member function to parse the command line and send the parameters, one at a time, to CCommandLineInfo::ParseParam.&& 下面我们来看看外壳命令解析的主角:CWinApp::ProcessShellCommand//in appui2.cpp&//DDE and ShellExecute support
BOOL CWinApp::ProcessShellCommand(CCommandLineInfo& rCmdInfo)//部分源代码{&BOOL bResult = TRUE;&switch (rCmdInfo.m_nShellCommand)&{&case CCommandLineInfo::FileNew:&&if (!AfxGetApp()-&OnCmdMsg(ID_FILE_NEW, 0, NULL, NULL))&&&OnFileNew();&&if (m_pMainWnd == NULL)&&&bResult = FALSE;&&
&&// If we've been asked to open a file, call OpenDocumentFile()
&case CCommandLineInfo::FileOpen:&&if (!OpenDocumentFile(rCmdInfo.m_strFileName))&&&bResult = FALSE;&&&&&&&&& case CCommandLineInfo::FilePrintTo:&case CCommandLineInfo::FilePrint:&&...//&&&&&&& case CCommandLineInfo::FileDDE:&&...//&case CCommandLineInfo::AppRegister:&&...//&&&&&&& case CCommandLineInfo::AppUnregister:&&...//&&&&&&&& }&return bR}&& 挖掘源代码的确是了解MFC运行内幕的最好手段,大家一看源代码便知道如之何了。CCommandLineInfo构造函数中m_nShellCommand = FileN所以在ProcessShellCommand中对应的代码自然就一目了然了:CWinApp::OnFileNew()被调用了。
&&&&&&&&&&&&&&&&&&&&&& //////////////////////////////////////////////////&&&&&&&&&&&&&&&&&&&&&& /*&& 6.一套文档/视图即将诞生&& */&&&&&&&&&&&&&&&&&&&&&& //////////////////////////////////////////////////&&& 上文说CWinApp::OnFileNew()被调用了,那么就让我来看看其代码吧!&//in appdlg.cpp&void CWinApp::OnFileNew()&{&&& if (m_pDocManager != NULL)&m_pDocManager-&OnFileNew();&}& //in docmgr.cppvoid CDocManager::OnFileNew()//部分源代码{&...//&&&&&& CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetHead();&if (m_templateList.GetCount() & 1)&{&&// more than one document template to choose from&&// bring up dialog prompting user&&CNewTypeDlg dlg(&m_templateList);&&INT_PTR nID = dlg.DoModal();&&if (nID == IDOK)&&&pTemplate = dlg.m_pSelectedT&&else&&&&&&& // none - cancel operation&}
&ASSERT(pTemplate != NULL);&ASSERT_KINDOF(CDocTemplate, pTemplate);&&&&&&& pTemplate-&OpenDocumentFile(NULL);&&// if returns NULL, the user has already been alerted}&//in docmulti.cppCDocument* CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,&BOOL bMakeVisible)//部分源代码{&CDocument* pDocument = CreateNewDocument();&...//&&&&&&& BOOL bAutoDelete = pDocument-&m_bAutoD&pDocument-&m_bAutoDelete = FALSE;&& // don't destroy if something goes wrong&CFrameWnd* pFrame = CreateNewFrame(pDocument, NULL);&pDocument-&m_bAutoDelete = bAutoD&...//
&if (lpszPathName == NULL)&{&&// create a new document - with default document name&&SetDefaultTitle(pDocument);
&&// avoid creating temporary compound file when starting up invisible&&if (!bMakeVisible)&&&pDocument-&m_bEmbedded = TRUE;
&&if (!pDocument-&OnNewDocument())&&{&&&// user has be alerted to what failed in OnNewDocument&&&TRACE(traceAppMsg, 0, "CDocument::OnNewDocument returned FALSE.\n");&&&pFrame-&DestroyWindow();&&&return NULL;&&}
&&// it worked, now bump untitled count&&m_nUntitledCount++;&}&else&{&&// open an existing document&&CWaitC&&if (!pDocument-&OnOpenDocument(lpszPathName))&&{&&&// user has be alerted to what failed in OnOpenDocument&&&TRACE(traceAppMsg, 0, "CDocument::OnOpenDocument returned FALSE.\n");&&&pFrame-&DestroyWindow();&&&return NULL;&&}&&pDocument-&SetPathName(lpszPathName);&}
&InitialUpdateFrame(pFrame, pDocument, bMakeVisible);&return pD}&&&&&&&&&&&&&&&&&&&&&& //////////////////////////////////////////////&&&&&&&&&&&&&&&&&&&&&& /*&&&& 6.1.子文档动态生成&&&&& */&&&&&&&&&&&&&&&&&&&&&& //////////////////////////////////////////////&& CMultiDocTemplate::OpenDocumentFile调用了CreateNewDocument(),这就是子文档动态生成的主函数。& //in doctempl.cpp&CDocument* CDocTemplate::CreateNewDocument()//部分源代码&{&// default implementation constructs one from CRuntimeClass&...//&CDocument* pDocument = (CDocument*)m_pDocClass-&CreateObject();&...//&AddDocument(pDocument);//将动态生成的文档对象的指针加入到应用程序的文档列表中&return pD&}& CDocument* pDocument = (CDocument*)m_pDocClass-&CreateObject();这一句就是动态产生的核心,它借助于CRuntimeClass动态生成一个CDocument对象。其动态生成的奥秘我将在MFC技术内幕系列之(三)---《MFC执行期类型识别与动态创建技术内幕》一文中详解。
&&&&&&&&&&&&&&&&&&&&&& //////////////////////////////////////////////////&&&&&&&&&&&&&&&&&&&&&& /*&& 6.2.子窗口框架动态生成&&& */&&&&&&&&&&&&&&&&&&&&&& /////////////////////////////////////////////////& CMultiDocTemplate::OpenDocumentFile调用了CreateNewFrame,这就是子窗口框架动态生成的主函数。
&// Default frame creation&CFrameWnd* CDocTemplate::CreateNewFrame(CDocument* pDoc, CFrameWnd* pOther)//部分源代码&{&if (pDoc != NULL)&&ASSERT_VALID(pDoc);&// create a frame wired to the specified document
&ASSERT(m_nIDResource != 0); // must have a resource ID to load from&CCreateC&context.m_pCurrentFrame = pO&context.m_pCurrentDoc = pD&context.m_pNewViewClass = m_pViewC&context.m_pNewDocTemplate =&&&&&&& ...//&CFrameWnd* pFrame = (CFrameWnd*)m_pFrameClass-&CreateObject();&if (pFrame == NULL)&{&&TRACE(traceAppMsg, 0, "Warning: Dynamic create of frame %hs failed.\n",&&&m_pFrameClass-&m_lpszClassName);&&return NULL;&}&ASSERT_KINDOF(CFrameWnd, pFrame);&&&&&&& ...//&&// create new from resource&if (!pFrame-&LoadFrame(m_nIDResource,&&&WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE,&& // default frame styles&&&NULL, &context))&{&&TRACE(traceAppMsg, 0, "Warning: CDocTemplate couldn't create a frame.\n");&&// frame will be deleted in PostNcDestroy cleanup&&return NULL;&}
&// it worked !&return pF}&& CFrameWnd* pFrame = (CFrameWnd*)m_pFrameClass-&CreateObject();这一句就是动态产生的核心,它借助于CRuntimeClass动态生成一个CDocument对象。其动态生成的奥秘我将在MFC技术内幕系列之(三)---《MFC执行期类型识别与动态创建技术内幕》一文中详解。之后函数调用LoadFrame来创建子窗口。其过程与创建主框架窗口的过程大致相同,但也有一些不同的地方,下面我就将说说这点不同。
&&&&&&&&&&&&&&&&&&&&&& //////////////////////////////////////////////&&&&&&&&&&&&&&&&&&&&&& /*&&&& 6.3.子视图动态生成&&&&& */&&&&&&&&&&&&&&&&&&&&&& //////////////////////////////////////////////&& 瞪大眼睛仔细察看OpenDocumentFile的源代码,疑惑了,"怎么没有类似CView* pView =CreateNewView();的代码?","那么子视图是如何生成的呢"下面我就为你详细解释一下吧!其实子视图动态生成函数被放到另一个地方了。让我们详细来看看吧。&& 其实,关键还是在LoadFrame,但与创建主窗口框架的那个LoadFrame不同的是传进了一个不同的参数&context,你回过头看看主窗口框架的那个LoadFrame,调用它时使用了默认参数,而那个默认参数值为NULL,下面看看CCreateContext 结构。//in afxext.hstruct CCreateContext&& // Creation information structure&// All fields are optional and may be NULL{&// for creating new views&CRuntimeClass* m_pNewViewC // runtime class of view to create or NULL&CDocument* m_pCurrentD
&// for creating MDI children (CMDIChildWnd::LoadFrame)&CDocTemplate* m_pNewDocT
&// for sharing view/frame state from the original view/frame&CView* m_pLastV&CFrameWnd* m_pCurrentF// Implementation&CCreateContext();};& 而在CDocTemplate::CreateNewFrame中初始化了该结构如下:&&&&& CCreateC&context.m_pCurrentFrame = pO&context.m_pCurrentDoc = pD&context.m_pNewViewClass = m_pViewC&context.m_pNewDocTemplate =&&&&&& context.m_pNewViewClass = m_pViewC//关键的成员& 下面看看这个创建的具体过程:&&&&& LoadFrame(...,&context)--&CFrameWnd::Create(...,&context)--& CWnd::CreateEx(...,&context)--&::CreateWindowEx&&&& ::CreateWindowEx API函数将产生WM_CREATE消息,并将&context传递之,CMainFrame::OnCreate将响应消息,并引起一系列的函数调用,看下面://in mainfrm.cppint CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct){&if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)&&return -1;&...//&return 0;}// in winfrm.cppint CFrameWnd::OnCreate(LPCREATESTRUCT lpcs){&CCreateContext* pContext = (CCreateContext*)lpcs-&lpCreateP&return OnCreateHelper(lpcs, pContext);}// in winfrm.cppint CFrameWnd::OnCreateHelper(LPCREATESTRUCT lpcs, CCreateContext* pContext)//部分源代码{&if (CWnd::OnCreate(lpcs) == -1)&&return -1;
&// create special children first&if (!OnCreateClient(lpcs, pContext))&{&&TRACE(traceAppMsg, 0, "Failed to create client pane/view for frame.\n");&&return -1;&}
&...//&&&&&&& return 0;&& // create ok}// in winfrm.cppBOOL CFrameWnd::OnCreateClient(LPCREATESTRUCT, CCreateContext* pContext){&// default create client will create a view if asked for it&if (pContext != NULL && pContext-&m_pNewViewClass != NULL)&{&&if (CreateView(pContext, AFX_IDW_PANE_FIRST) == NULL)&&&return FALSE;&}&return TRUE;}// in winfrm.cppCWnd* CFrameWnd::CreateView(CCreateContext* pContext, UINT nID)//部分源代码{&...//
&// Note: can be a CWnd with PostNcDestroy self cleanup&CWnd* pView = (CWnd*)pContext-&m_pNewViewClass-&CreateObject();&if (pView == NULL)&{&&TRACE(traceAppMsg, 0, "Warning: Dynamic create of view type %hs failed.\n",&&&pContext-&m_pNewViewClass-&m_lpszClassName);&&return NULL;&}&ASSERT_KINDOF(CWnd, pView);
&// views are always created with a border!&if (!pView-&Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,&&CRect(0,0,0,0), this, nID, pContext))&{&&TRACE(traceAppMsg, 0, "Warning: could not create view for frame.\n");&&return NULL;&&&&&&& // can't continue without a view&}
&...//&return pV}& CWnd* pView = (CWnd*)pContext-&m_pNewViewClass-&CreateObject();核心函数终于出现了。子视图动态生成完毕。
&&&&&&&&&&&&&&&&&&&&&& /////////////////////////////////////////&&&&&&&&&&&&&&&&&&&&&& /*&&&&&&&& 7.收尾工作&&&&&&&&& */&&&&&&&&&&&&&&&&&&&&&& /////////////////////////////////////////&& 至此,一套完整的Document/ChildFrame/View结构生成,此&三口组&共属同一套文档模板,如果你要定义另一套不同的文档模档需再定义另一组不同&三口组&(ChildFrame可以使用相同的)。并调用AddDocTemplate将该文档模板加入到应用程序的文档模板列表。比如:
&&&&&& CMultiDocTemplate* pOtherDocT&pOtherDocTemplate = new CMultiDocTemplate(IDR_MyOtherTYPE,&&RUNTIME_CLASS(CMyOtherDoc),&&RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架&&RUNTIME_CLASS(CMyOtherView));&AddDocTemplate(pOtherDocTemplate);
&三口组&生成后程序调用ShowWindow,UpdateWindow将应用程序的主窗口展现在你眼前。
& 注释:当你在File菜单中选择new或在工具栏中单击&新建&时,应用程序将选择当前默认的文档模板并以它为基础动态生成 Document/ChildFrame/View&三口组&,其生成过程与我上述讲的一般不二。
阅读(...) 评论() &

我要回帖

更多关于 mfc tcp client 的文章

 

随机推荐