VC2010 中 MFC 的改进导致 XTP 停靠窗体无法显示的解决方法
XTP( xtreme ToolKit Pro )界面库是基于 MFC 扩展的优秀的界面库,公司的项目一直在使用,但是最近尝试使用 VS2010 编辑工程时发现,停靠窗口居然消失了,跟踪消息发现停靠窗口通知消息 XTPWM_DOCKINGPANE_NOTIFY 中的 XTP_DPN_SHOWWINDOW ( wParam ) 居然在主窗口中收不到了,这个消息可是将自定义的窗口关联到停靠窗口容器的入口啊,为什么如此呢?
经过跟踪发现:CXTPDockingPaneManager 在注册到主窗口时没有指定子窗口 ID , 而在 MFC 2010 中,请看下列代码实现:
// for child windows
BOOL CWnd::PreCreateWindow(CREATESTRUCT& cs)
{
if (cs.lpszClass == NULL)
{
// make sure the default window class is registered
VERIFY(AfxDeferRegisterClass(AFX_WND_REG));
// no WNDCLASS provided - use child window default
ASSERT(cs.style & WS_CHILD);
cs.lpszClass = _afxWnd;
}
if ((cs.hMenu == NULL) && (cs.style & WS_CHILD))
{
cs.hMenu = (HMENU)(UINT_PTR)this;
}
return TRUE;
}
如果不指定 ID ,那么 MFC 将会把 this 指针转化为 ID 存放到 HMENU 中,所以通过 spy++ 可以看到停靠窗口是创建了的,但是 ID 非常大,这样就导致了停靠窗口的消息无法正常进行处理从而导致停靠窗口显示不出来的问题,最简单的解决办法就是为停靠窗口的管理器指定一个 ID,如下所示:
m_paneManager.InstallDockingPanes( this );
m_paneManager.SetDlgCtrlID( AFX_IDW_PANE_FIRST + 1 );
这样就正常了,当然,如果你不想所有的工程都修改一遍,那么只有两种办法了:
1、升级 XTP 库到 13.3 以上版本,例如现在最新的版本 13.4.1
2、修改 XTP 库中创建 CXTPDockingPaneManager的代码,在创建时指定一个 ID
最后附带提供 VS2008 中 MFC 的代码以作比较:
// for child windows
BOOL CWnd::PreCreateWindow(CREATESTRUCT& cs)
{
if (cs.lpszClass == NULL)
{
// make sure the default window class is registered
VERIFY(AfxDeferRegisterClass(AFX_WND_REG));
// no WNDCLASS provided - use child window default
ASSERT(cs.style & WS_CHILD);
cs.lpszClass = _afxWnd;
}
return TRUE;
}