Excel是如何实现让子窗口显示在任务栏上的?

matrix_lhx 2009-12-04 09:31:41
Excel在打开多个文件的时候,每一个MDIChildWnd都会有一个对应的任务栏按钮。刚开始我以为是SDI形式的程序,但是Excel上都有重新排列的选项,这样就可以让多个MDIChildWnd在同一个MainFrame中显示出来了。
这个问题困扰我很久,而且我也Google过多次但是都不能找到一个答案。
根据MSDN的说明:一个子窗口是不可能在任务栏上显示一个按钮的,但是为什么Excel就能做到这点呢?
在搜索的过程中我也想到了几种方案:

方案1:网上有一个例子MSDI,但是它的效果仅仅类似于MTI的效果,并不能把多个子窗口显示在同一个MainFrame中。

方案2:利用ITaskbarList。这个COM接口很是怪异,因为在一个程序中我只能用AddTab增加一个任务按钮,然后无论再怎么调用AddTab都不能多增加一个了。而且,我的试验机器的操作系统是Vista的,在Vista上面的表现就更怪异了。调用AddTab是完全没有任何反应的,只能调用ActivateTab才能将一个任务按钮显示出来。

方案3:利用Shell Hook,原理就是通过截获HSHELL_XXX来获取窗口建立、激活和销毁的消息,这主要是为了能防止一个窗口在任务栏上显示按钮的。但问题是,即使我拦截了这些消息MainFrame的任务按钮还是显示出来的。而ShellProc中完全获取不到子窗口创建和销毁的消息。

方案4:利用SendMessage想任务栏发送消息或者直接获取到任务栏(ToolBarWindow32)的句柄把它转换成指针直接增加一个按钮,但是前者会报告内存不能读的消息然后Explorer进程挂掉,而后者更甚直接把Explorer弄挂掉然后把我任务栏上的图标大小都改变了完全无法恢复。

方案5:利用SetParent或SetWindowLong方法设置子窗口的父窗口指针为空,这样子窗口就不算是一个子窗口了,然后也能在任务栏上显示出任务按钮来了。但是问题是,如果一个子窗口的父亲指针被设为空,整个程序基本都无法运行了,尤其是在MDI程序中基本上已启动就挂掉了。而且我也用Spy++检查过,Excel中的子窗口是有父亲指针的,不是一个独立的窗口。

经过反复的实验这几种方案都不能达到Excel的效果,当然关于Hook方面的东西我不大熟悉,也不敢下断言Hook这种方法一定不行。
所以今天想问问各位大虾,Excel到底是通过什么方法做到这点的?
...全文
1779 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
matrix_lhx 2009-12-07
  • 打赏
  • 举报
回复
帖子已结,感谢cnzdgs的解答,还有各位帮顶的人。
关于模拟Excel窗口的问题,我仍然在做试验,希望能达到Excel的效果。
matrix_lhx 2009-12-07
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 cnzdgs 的回复:]
可以这样考虑看看:
隐藏窗口最小化时将主窗口最小化,主窗口最小化时把所有隐藏窗口都最小化;隐藏窗口恢复时将主窗口恢复,主窗口恢复时将活动文档对应的隐藏窗口恢复。执行最小化和恢复前检查窗口的当前状态,避免重复操作(例如窗口已是最小化状态就不要再执行最小化操作了)。
隐藏窗口被激活时发消息给主窗口,主窗口收到消息后激活自己并切换文档;主窗口被激活时激活活动文档对应的隐藏窗口。(这里也可以试试用SetWindowPos设置窗口的Z-Order)
结帖时才能给分,不急。
[/Quote]

主窗口最小化是将所有隐藏窗口都最小化这个我试过了,但是在隐藏窗口比较多也就是说打开多个文档时,主窗口的最小化会等十分长的时间,因为系统需要把所有隐藏窗口都最小化。
恩,说一种我的解决方法。将隐藏窗口的式样设置为WS_EX_NOACTIVATE,这可以让主窗口最小化时的激活效果不转移给隐藏窗口。
对于模拟Excel的窗口显示形式已经有点儿成果了。其中cnzdgs提到的方法有些是很有效的。但是对比Excel的效果真是差很多。
看来想知道微软是怎么做的还需要继续研究啊。
周末休息,不能上网,也就没有结贴,今天就把帖结了。

顺便提一句,说“多文档框架 都可以将子窗口显示在任务栏上”这种话的你们是忽悠我呢,还是真有这么会事儿啊!!
syxhpx 2009-12-05
  • 打赏
  • 举报
回复
顶一下
wsc1509 2009-12-05
  • 打赏
  • 举报
回复
多文档框架 都可以将子窗口显示在任务栏上

用MFC  
yuanzh 2009-12-05
  • 打赏
  • 举报
回复
mark
cnzdgs 2009-12-05
  • 打赏
  • 举报
回复
可以这样考虑看看:
隐藏窗口最小化时将主窗口最小化,主窗口最小化时把所有隐藏窗口都最小化;隐藏窗口恢复时将主窗口恢复,主窗口恢复时将活动文档对应的隐藏窗口恢复。执行最小化和恢复前检查窗口的当前状态,避免重复操作(例如窗口已是最小化状态就不要再执行最小化操作了)。
隐藏窗口被激活时发消息给主窗口,主窗口收到消息后激活自己并切换文档;主窗口被激活时激活活动文档对应的隐藏窗口。(这里也可以试试用SetWindowPos设置窗口的Z-Order)

结帖时才能给分,不急。
matrix_lhx 2009-12-04
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 wwgddx 的回复:]
我觉得EXCEL那应该不算在任务栏上吧,只是在滚动条左边区域, 移动滚动条区域自己画就可以了, 一个文档对应多个视图.

这里有个很好的例子, 不知道你看了没有

http://www.vckbase.com/document/viewdoc/?id=526
[/Quote]

我说的效果和你给我的例子不一样。你说的只是Tab的实现,而我希望是子窗口在任务栏上显示出来。
wwgddx 2009-12-04
  • 打赏
  • 举报
回复
我觉得EXCEL那应该不算在任务栏上吧,只是在滚动条左边区域, 移动滚动条区域自己画就可以了, 一个文档对应多个视图.

这里有个很好的例子, 不知道你看了没有

http://www.vckbase.com/document/viewdoc/?id=526
matrix_lhx 2009-12-04
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 wfx_net 的回复:]
用单文档的向导创建应用程序,然后在创建多个CDocTemplate,这样很一个DocTemplate就会有一个单独的窗口。
[/Quote]
那如何让这些单独的窗口在同一个MainFrame中并列或重叠显示呢?
而且这些单独的窗口的描画区域是指在一个MainFrame中还是独立于MainFrame的另一个窗口?
wfx_net 2009-12-04
  • 打赏
  • 举报
回复
用单文档的向导创建应用程序,然后在创建多个CDocTemplate,这样很一个DocTemplate就会有一个单独的窗口。
VeiwoZouhui 2009-12-04
  • 打赏
  • 举报
回复
多文档框架 都可以将子窗口显示在任务栏上

你用MFC 创建一个多文档试试就明白了 
matrix_lhx 2009-12-04
  • 打赏
  • 举报
回复
哦,好久没来论坛了,需要结贴时才能放分吗?
matrix_lhx 2009-12-04
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 cnzdgs 的回复:]
子框架可以响应WM_SETFOCUS消息。
顶级窗口响应WM_SIZE消息控制主窗口的最大/最小化及恢复。
[/Quote]

的确如此但是仍然会有很多问题。我举个例子,如果有什么解决方法能告诉我的话我真感激不尽啊。
首先,是当主窗口最小化后该如何让其回复原状?我是在隐藏窗口的OnActivate函数中进行处理的,当隐藏窗口被激活,也就是说隐藏窗口的任务按钮被点击的时候对主窗口进行显示。但问题来了。在主窗口被最小化后,很多情况下系统会将隐藏窗口激活(因为这两个窗口之间常常转移激活状态,那么一个窗口最小话后一定会将激活状态转移到另外一个窗口)。那么此时需要防止刚刚最小化的主窗口有显示出来。其次,即使这个问题解决了,那么此时隐藏窗口被激活了。那么就需要点击两次隐藏窗口的任务按钮才能让主窗口再次显示出来(激活中->失去激活->激活->显示主窗口)。有什么方法能让,主窗口隐藏是不把激活状态转移个隐藏窗口呢?

说了这么多废话,先放分给你吧。
Dingnifei123 2009-12-04
  • 打赏
  • 举报
回复
学习~
cnzdgs 2009-12-04
  • 打赏
  • 举报
回复
子框架可以响应WM_SETFOCUS消息。
顶级窗口响应WM_SIZE消息控制主窗口的最大/最小化及恢复。
matrix_lhx 2009-12-04
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 cnzdgs 的回复:]
其实Excel是多个窗口,主窗口不在任务栏显示,每个文档对应一个顶级窗口。文档对应的顶级窗口只用于在任务栏显示,窗口可以设置的很小并显示在屏幕之外,通过消息与主窗口建立关联。
[/Quote]

你的说法和我现在正在做的方法是一样的。通过一个顶层窗口来模拟一个任务栏按钮,但问题是这种方法应该没有Excel显示的那么完美吧?我在模拟的过程中会产生很多的问题,比如如何同步隐藏的顶层窗口和文档之间的激活和焦点的获得?在最大化和最小化的情况下该如何通过顶层窗口的任务栏按钮来进行恢复?等等,这些问题都很难以解决。而且用最严重的问题是,在MFC的MDI结构中子窗口是无法得到激活或者得到焦点的这些信息的,这些信息都被主窗口所拦截。但是用Spy++查看Excel的话可以发现,子窗口可以获得这些消息。

题外话:等了这么长时间,也没见有什么实质性的回答。不过cnzdgs的想法倒和我现在模拟的做法不谋而合。如果还没有什么突破性的进展,分就给cnzdgs吧。谢谢回答。
xwsn007 2009-12-04
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 cnzdgs 的回复:]
其实Excel是多个窗口,主窗口不在任务栏显示,每个文档对应一个顶级窗口。文档对应的顶级窗口只用于在任务栏显示,窗口可以设置的很小并显示在屏幕之外,通过消息与主窗口建立关联。
[/Quote]

学习了,顶起来!!!
xwsn007 2009-12-04
  • 打赏
  • 举报
回复
mark 关注
cnzdgs 2009-12-04
  • 打赏
  • 举报
回复
其实Excel是多个窗口,主窗口不在任务栏显示,每个文档对应一个顶级窗口。文档对应的顶级窗口只用于在任务栏显示,窗口可以设置的很小并显示在屏幕之外,通过消息与主窗口建立关联。

15,979

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 界面
社区管理员
  • 界面
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧