VC中单文档框架删除菜单的调试经历
来源:互联网 发布:淘宝上刷心悦的原理 编辑:程序博客网 时间:2024/06/10 05:20
我的技术博客已搬家至: http://www.kai-zhou.com, 其他博客已停止更新,欢迎访问查看文章的最新版本.
最近想在VC中单文档框架中删除菜单,状态栏,工具栏 。状态栏,工具栏在CMainFrame::OnCreate中就可以注释调,但是怎么样将菜单删掉呢?百度了一下,不太好找到。只好依靠现有知识,自己找到办法了。通过跟踪调试MFC的源代码居然让我找到了办法。
首先,我们先想办法达到在单文档界面中不显示菜单的效果。
通过现有知识,我们知道MFC是在CMainFrame::OnCreate中生成状态栏,工具栏的。代码如下:
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("未能创建工具栏");
return -1; // 未能创建
}
if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
TRACE0("未能创建状态栏");
return -1; // 未能创建
}
// TODO: 如果不需要工具栏可停靠,则删除这三行
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
return 0;
}
所以如果不想要状态栏,工具栏,直接在CMainFrame::OnCreate中将相关代码注释调就行了。那么,菜单相关的代码在哪呢?遍历一遍CMainFrame类,没找到。根据代码相关性,既然状态栏,工具栏是在 CMainFrame::OnCreate中生成的,那么菜单估计也是在这个函数里面生成的。
首先在 if (CFrameWnd::OnCreate(lpCreateStruct) == -1) 处下断点,进入函数内部,代码如下:
{
ENSURE_ARG(lpcs != NULL);
CCreateContext* pContext = (CCreateContext*)lpcs->lpCreateParams;
return OnCreateHelper(lpcs, pContext);
}
继续进入OnCreateHelper函数,代码如下:
{
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.");
return -1;
}
// post message for initial message string
PostMessage(WM_SETMESSAGESTRING, AFX_IDS_IDLEMESSAGE);
// make sure the child windows have been properly sized
RecalcLayout();
return 0; // create ok
}
下一步进入OnCreateClient,代码如下:
{
// 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;
}
{
ASSERT(m_hWnd != NULL);
ASSERT(::IsWindow(m_hWnd));
ENSURE_ARG(pContext != NULL);
ENSURE_ARG(pContext->m_pNewViewClass != NULL);
// 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.",
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.");
return NULL; // can't continue without a view
}
if (pView->GetExStyle() & WS_EX_CLIENTEDGE)
{
// remove the 3d style from the frame, since the view is
// providing it.
// make sure to recalc the non-client area
ModifyStyleEx(WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED);
}
return pView;
}
LPCTSTR lpszWindowName, DWORD dwStyle,
const RECT& rect,
CWnd* pParentWnd, UINT nID,
CCreateContext* pContext)
{
// can't use for desktop or pop-up windows (use CreateEx instead)
ASSERT(pParentWnd != NULL);
ASSERT((dwStyle & WS_POPUP) == 0);
return CreateEx(0, lpszClassName, lpszWindowName,
dwStyle | WS_CHILD,
rect.left, rect.top,
rect.right - rect.left, rect.bottom - rect.top,
pParentWnd->GetSafeHwnd(), (HMENU)(UINT_PTR)nID, (LPVOID)pContext);
}
进入CreateEx,代码如下:
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))
{
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",
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;
}
注意 cs.hMenu = nIDorHMenu; 这段代码明显是与菜单有关的代码,那么找到了框架是如何生成菜单的,将菜单加入到框架中的,我们又如何在框架中将菜单删除呢?菜单的赋值是赋给CREATESTRUCT结构,所以猜测CREATESTRUCT结构可以控制菜单。返回到CMainFrame中,我们可以看到CMainFrame::OnCreate()的参数是LPCREATESTRUCT,所以先修改CMainFrame::OnCreate()如下:
{
lpCreateStruct->hMenu = NULL;
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
return 0;l
}
编译,运行。还有菜单。 再回到CMainFrame中,发现PreCreateWindow也有CREATESTRUCT结构,修改代码如下:
{
cs.hMenu = NULL;
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: 在此处通过修改
// CREATESTRUCT cs 来修改窗口类或样式
return TRUE;
}
编译运行,成功了。菜单没了。
第二步,既然菜单没用了,那么我们可不可以把wizard自动生成的菜单删除调呢?说干就干,删除菜单IDR_MAINFRAME,编译运行,什么“建立空文档失败”,程序直接退出。继续跟踪,调试吧。
首先估计是在CMainFrame中出的问题,在CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)中下断点,编译运行,结果没进入断点,程序就出错了,那在App类的InitInstance()中下断点吧。跟踪,发现是在
return FALSE;
if (!AfxGetApp()->OnCmdMsg(ID_FILE_NEW, 0, NULL, NULL))
OnFileNew();
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, ATL_RT_MENU);
if ((hMenu = ::LoadMenu(hInst, lpszMenuName)) == NULL)
{
TRACE(traceAppMsg, 0, "Warning: failed to load menu for CFrameWnd.");
PostNcDestroy(); // perhaps delete the C++ object
return FALSE;
}
}
m_strTitle = lpszWindowName; // 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.");
if (hMenu != NULL)
DestroyMenu(hMenu);
return FALSE;
}
return TRUE;
}
在LoadMenu的时候出错了,所以执行PostNcDestroy()函数了。找到了错误所在,怎么修改代码呢?
仔细阅读,发现Create()函数是在CFrameWnd类中,而CMainFrame类的父类就是CFrameWnd类,再一查,发现了CFrameWnd::Create()是虚函数,所以只要我们在CMainFrame中实现Create(),并将其中加载菜单的相关代码去掉应该就可以了,修改代码如下:
LPCTSTR lpszWindowName,
DWORD dwStyle /*= WS_OVERLAPPEDWINDOW*/,
const RECT& rect/* = rectDefault*/,
CWnd* pParentWnd /*= NULL*/, // != NULL for popups
LPCTSTR lpszMenuName/* = NULL*/,
DWORD dwExStyle/* = 0*/,
CCreateContext* pContext/* = NULL*/)
{
HMENU hMenu = NULL;
if (lpszMenuName != NULL)
{
}
m_strTitle = lpszWindowName; // 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.");
if (hMenu != NULL)
DestroyMenu(hMenu);
return FALSE;
}
}
编译,运行,成功了。
以前写代码总是查上网,翻书,看帮助查资料,现在才发现源代码也是很好的资料。上网,翻阅书籍查资料固然不错,但是那是学习别人已有的知识,自己解决问题的能力没什么大的提高。通过研究源代码,我们可以在没有任何书籍,文档的情况下解决问题。这是我第一次深入跟踪到MFC源代码内部进行调试,希望对像我一样的初学者有帮助。
- VC中单文档框架删除菜单的调试经历
- VC中单文档框架删除菜单的调试经历
- 转载::VC中单文档框架删除菜单的调试经历
- vc单文档中使某个菜单不可选
- mfc 单文档程序删除菜单的方式。
- VC单文档点击菜单弹出对话框
- vc++单文档动态创建菜单
- VC基于单文档opengl框架
- vc 在单文档中拖动图片的方法
- VC中实现单文档切换多视图的方法
- 调试中解决问题的经历
- 删除MFC自建的单文档工程的菜单和工具栏
- 删除MFC自建的单文档工程的菜单和工具栏
- 删除MFC自建的单文档工程的菜单和工具栏
- 删除MFC自建的单文档工程的菜单和工具栏
- VC去掉单文档中的菜单,工具栏,状态栏
- VC++6.0去掉单文档中的菜单,工具栏,状态栏
- VC++6.0去掉单文档中的菜单,工具栏,状态栏
- C++必知的几个知识点
- easyjweb-0.7.0版本发布
- Spring MVC的流程图,欢迎指正
- prototype学习
- 关于J2EE程序员的武器探讨
- VC中单文档框架删除菜单的调试经历
- 玩玩Spring之hibernate+ webwork+ spring添删改查示例
- 其实真的很开心
- Oracle中几个关于日期方面的SQL实例
- 值得关注技术网站汇总,以及技术(自学用)
- 面向Java开发人员的Ajax: 构建动态的Java应用程序
- 关于嵌入式系统方向
- 最新postfix的main.cf配置参考
- 面向Java开发人员的Ajax:Ajax的Java对象序列化