如下的WebBrowser控件的问题困扰了我很久,诚心向高手请教。具体问题:简单地将一个WebBroser控件放到一个Form上,然后用此WebBrowser控件浏览到一个视频网站如Youtube,
随便打开一个视频,点全屏,这时屏幕上会显示按ESC键退出全屏。但是当你按ESC键时,视频仍然保持全屏状态,
不会退出全屏。 目前可知的一个变通方法是按Ctrl+W或Alt+F4可以退出全屏。但是由于全屏时,屏幕上会提示按ESC键退出,而实际上按ESC键无法退出会给用户带来相当大的困惑。这个问题好象普遍存在于各种开发语言中,在wxPython或Java的SWT中绑定IE同样会出现这个问题。唯一的例外是VC++/MFC,在MFC中无论使用CHtmlView或是直接在CDialog上放ActiveX控件,均可以在Flash的全屏状态下
按ESC键正常退出。
我跟了一下MFC中的代码,好象关键部分是是CWnd的CreateControl函数中正确建立了OleControlContainer与OleControlSite
之间的联系,不过我对COM编程不是很熟,目前没找到具体哪里是关键,在C#中应该怎么做。C#中我试过了用Form实现IOleClientSite并注册到WebBrowser控件中,不过没有用。用Spy++看了一下Flash全屏的过程,实质上是重新建立了一个最上层的全屏窗口,按ESC键时,C#的程序中,
全屏窗口能正确接收到KeyDown与KeyUp消息,但未将消息回传给Form。相比之下,MFC程序中的全屏窗口将
KeyUp消息回传给了控件宿主的CWnd窗口。有没有哪位高手能解一下这个谜题啊,感谢万分。

解决方案 »

  1.   

    在CDialog上放ActiveX控件没有这个问题的话,就应该和IE的API没有关系了,而是ActiveX容器的实现问题。
    没有具体看Windows Forms的AxHost和COleControlContainer/Site对ActiveX容器接口的实现的区别,但是ActiveX容器这种复杂的COM编程用托管语言不容易写,你可以考虑一下显示WebBrowser这部分是不是改用非托管语言。
      

  2.   

    很简单的问题,ActiveX会截获消息不发给宿主窗体,可做个hook window或者键盘钩子之类,把消息传递过去即可,C#调些API应该可以实现。
      

  3.   

    这是因为WebBrowser实际上是调用的IE内核,所有使用IE内核的浏览器都会有这个问题.当你点全屏的时候,实际上并不是IE把视频给全屏了,而是调用的Adobe,而且你可以看到状态栏里会有这么一个程序.而正是这个程序把你的esc键给屏蔽了,当你按ALT+F4的时候其实是将adobe给关闭了,所以你感觉好像是有恢复到了原始状态.当然这只是默认情况,所以你需要进行一些处理,让你的esc键好用起来.
      最简单的办法就是做一个全局的键盘钩子捕获对ESC的点击,当捕获到esc的时候你可以发送ALT+F4.但是c#处理全局的键盘钩子比较复杂,如果你做过的话就比较简单,如果你没做过的话,建议你去网上找一找,答案应该很多.我几年前封装过一个全局钩子的程序,键盘鼠标的都有,不过放哪我忘了,如果你实在研究不明白的话,可以联系我,我帮你找一找.
      

  4.   

    先谢谢楼上各位的回复。To jiangsheng:
    我在WebBrowser中有很多定制部分想在C#中实现,如果WebBrowser和宿主窗体用非托管实现,托管与非托管间调用管理会弄得复杂繁琐;如果大量用非托管代码,我本来就用MFC实现了,好象也没有必要移植到C#中了。To r3000:
    对此简单的问题,我在贴中已提出了疑问,如果说ActiveX会截获消息不发给宿主窗体,MFC中在CDialog上建立的WebBrowser ActiveX控件为何能正常退出全屏?正是因为同样的ActiveX控件表现行为不一样才让人产生迷惑。To mwsz_666:
    我已经在贴中说了,在MFC中调用IE内核不会产生此问题,无论是CHtmlView还是在CDialog上的WebBrowser控件,工作都非常正常,全屏下按ESC键能正常退出。关于用键盘钩子的方法,我已经实现了,用 http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/8f573d2c-7ba5-480e-a25d-b2ce608d8b5f/ 贴中的代码对程序内的KeyUp事件挂钩。用 http://blog.csdn.net/jingzhongrong/archive/2010/03/16/5385951.aspx 中的代码判断Flash的全屏事件,
    然后只要在KeyUp的钩子函数中处理ESC键,用GetActiveWindow得到Flash的全屏窗口,再用SendMessage发送WM_CLOSE到Flash的全屏窗口可以解决此问题。不过我感觉这个解决办法绕了一大圈,有点笨拙,而且我不太相信MFC中也是用这种键盘钩子来解决问题的,关键问题是为什么在C#程序中,Flash的全屏明明收到了ESC按键,却不处理?而在MFC程序中,Flash的全屏收到了ESC按键后正确退出全屏,还将ESC按键回传给了宿主窗体?
      

  5.   

    Silverlight全屏程序也有同样的问题,估计和Windows Forms的处理有关。
      

  6.   

    楼主,我也碰到同样的问题,可以告诉一下怎么解决的吗。谢了。邮箱:[email protected]
      

  7.   

    这两天我又试了一下Qt提供的ActiveX控件支持,晕倒,完美支持Flash全屏的ESC键,不至于吧,第三方的库的都能将ActiveX Container实现得这么好,微软对自己的东西的支持反而不完美,有点无语…。
    鉴于Qt这个跨平台的库不大可能专门为了ActiveX实现Windows下键盘钩子啥的,这也从另一方面证明确实是Winform的ActiveX Host实现有问题,微软的开发测试人员从来不浏览视频网站的么,这么明显的Bug都会忽视…有谁知道哪里可以将此Bug报告给微软开发团队,以便在下个版本.NET中改正此问题么?To wbpmrck:
    我在回复里不是写得很清楚了吗
    1. 实现全局的键盘钩子,这样在Flash全屏状态下也能监视按键信息。
    2. 监视全屏事件,以判断Flash是否处于全屏状态。
    3. 当Flash处于全屏状态,且收到ESC键时,用GetActiveWindow得到当前活动窗口,也就是Flash全屏窗口的句柄,用API函数SendMessage发送WM_CLOSE到此窗口,可以正常关闭此窗口退回WebBrowser控件。关键的原代码就是我上面贴的两个链接,直接拷贝粘贴就行了,一些细节自己稍微改改,我这个没学过C#的人都能做,一般的C#程序员都能做吧。
      

  8.   

    Windows Forms项目组早就解散了,我不认为下个版本的.Net里WF有多少优先权。你可以去connect.microsoft.com/visualstudio提交一个bug让Visual Studio项目组在考虑工作项优先级别的时候也考虑这个问题。