目前我所知的,能防假死的浏览器有:Chrome,Maxthon,Theworld,搜狗.除了Chrome外,其余的都是IE内核,它们的实现方式都是一样的,页面窗口与主程序窗口分离,每个页面一个线程.事实上,除了Chrome能完美实现防假死,其余都有瑕疵.
瑕疵有3
- 点击主窗口的时候,发现页面失去了输入焦点
- 按alt+tab键切换窗口的时候,发现第一次不能成功,按两次才行
- 弹出的模态窗口并不模态,主窗口仍能动,其他页面也能动
造成这些瑕疵,还是因为页面窗口与主程序窗口分离,问题是为什么不能在同一个窗口呢?实验证明,放在同一个窗口,即使是不同进程,子窗口处于假死状态的话,主窗口也同样假死了.
这一周,我一直在尝试一个事情,子窗口假死的时候,主窗口能否不死,两个窗口是处于不同线程.
测试内容如下:有窗口A和窗口B,A是由主线程创建,然后创建一个线程,再这个线程上创建B,CreateWindow的hWndParent参数是A的hwnd.显然A,B都有各自的消息循环,但当B执行一个死循环的时候,A也死掉,没有反应了,但如果B的hWndParent是NULL的话,当B无响应时,A仍然能活动自如.于是猜测是当两个窗口处于父子关系时,它们的消息循环是否合并了?
但,后来翻遍了资料,都没有讲两个不同线程的子父窗口的消息循环是怎样的.
最后发现在B执行死循环操作的时候,如果添加PeekMessage函数,那么A是可以正常响应的.PeekMessage是什么?就是在消息队列中把消息提出来,可以把消息清除,也可以不清除(使用PM_REMOVE 或 PM_NOREMOVE)标记.但如果不清除,A仍然是不能响应.于是可以猜测,当这两个窗口处于父子关系的时候,主进程会先将它们的消息放在同一队列中,然后再分发给各自的线程,所以当B堵塞的时候,A就无法响应,只有将属于B的消息都清除掉,A的消息才能到达A.
确实是这样吗?找不到资料,不能确定.
如果猜测是正确的,那么就要想办法将B的消息从消息队列中清除掉,而这个操作只能在另一个线程中,但PeekMessage做的只是当前线程的,也没有别的函数可以做到.
看来,目前来说,实验结果是不成功.
其实也是,Maxthon,Theworld,搜狗都不是省油的灯,他们肯定也想过,不得已才采用这个"分离"的办法.但为何Chrome能做到?不要忘了,那可是google的孩子,另外Chrome采用的是开源的核心,在处理这个事情上更方便.
最后附上测试代码,很混乱,见谅.
// MyWin.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "resource.h"
#include <windows.h>
#define szClassMain "MainWClass"
#define szClassChild "ChildWClass"
// Global variable
HINSTANCE hinst;
HWND hParent;
HWND hChild,hChild2;
HANDLE hTh1;
DWORD hThID1;
HHOOK hMsgHook;
// Function prototypes.
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int);
InitApplication(HINSTANCE);
InitInstance(HINSTANCE, int);
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ChildWndProc(HWND, UINT, WPARAM, LPARAM);
BOOL WINAPI ThreadProc(HWND);
BOOL WINAPI ThreadProc2(HWND);
LRESULT CALLBACK GetMsgProc(int,WPARAM ,LPARAM );
// Application