• 问题起因:制作一个内嵌了IE控件的软件时使用第三方类出现问题

    处理过程:

    QQ截图20140628065135

     

    一个IE控件窗口,在失去焦点或最小化后内容会消失,只剩窗口背景颜色。如下图。

    QQ截图20140628065308

    看到这个情况我首先想到了一个办法,用JS不停刷新页面。

    function myrefresh()
    {
    window.location = window.location;
    }
    setTimeout('myrefresh()',1000);
    

      但是如果这么写,在网络状况不是极佳的情况下,用户看到的网页就会闪烁。

    那么我们可以稍微修改代码:

    function myrefresh() 
    { 
            var a = document.body.innerHTML;
            document.body.innerHTML="";
            document.body.innerHTML = a;
    } 
    setTimeout('myrefresh()',1000); 
    

    将body的内容存入变量,然后再写入网页,这样整个页面的内容就会变动。

    但是实际测试后发现当窗口最小化之后,再次打开就无法正常显示了

    搜寻网络之后,得知可能是由于WM_ERASEBKGND使控件图像没有正常加载,那么我们Hook掉他:

    LRESULT CALLBACK IEProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        if (message == WM_ERASEBKGND)
            return 0;
    
        return CallWindowProc((WNDPROC)prevProc2, hWnd, message, wParam, lParam);
    }
    LRESULT CALLBACK CallProc(int nCode, WPARAM wParam, LPARAM lParam)
    {
        if (HC_ACTION == nCode)
        {
            PCWPSTRUCT pInfo = (PCWPSTRUCT)lParam;
            if (WM_CREATE == pInfo->message)
            {
                char className[101] = { 0 };
                GetClassNameA(pInfo->hwnd, className, 100);
                if (0 == strcmp(className, "Internet Explorer_Server"))
                {
                    prevProc2 = GetWindowLong(pInfo->hwnd, GWL_WNDPROC);
                    SetWindowLong(pInfo->hwnd, GWL_WNDPROC, (LONG)IEProc);
                }
            }
        }
        return CallNextHookEx(hHook, nCode, wParam, lParam);
    }
    //在主函数中添加
    hHook = SetWindowsHookEx(WH_CALLWNDPROC, CallProc, NULL, GetCurrentThreadId()); 
    

    编译运行后发现,重绘时,界面确实不闪了。。但是在窗口最小化或失去焦点后,一样显示全部空白,除非手动点击页面,那我们拦截掉所有窗口消息试试。

    LRESULT CALLBACK IEProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
             return 0;
    }
    

    再次启动软件,失去焦点后显示正常,只不过最小化问题还无法解决,那我们用Spy++抓抓看,在窗口失去焦点后,Internet Explorer_Server接到了哪些消息。 QQ截图20140628071414

    忽略掉WM_IME 输入法消息,窗口接受到了WM_KILLFOCUS WM_USER+145 WM_TIMER三个消息,把它Hook掉。

    经过测试,仍然没有作用,那只好“小聪明”一下了。

    在得到WM_KILLFOCUS事件之后,就立刻刷新页面使其重绘(普通重绘的函数不知为何不起作用),也可以调用JS进行不获取服务器信息的快速刷新,由于刷新事件在失去焦点时触发,通常都是用户点击了其他窗口或者将窗口最小化掉了,一般一瞬间不会显示出来,所以刷新瞬间的闪烁一般不会被用户看到,有心的话也可以自动将当前窗口截图然后显示窗口截图,隐藏掉IE控件之后刷新,刷新完成销毁截图并显示IE。

    if (message == WM_KILLFOCUS){
        XWeb_Refresh(hAppView);
        return 0;
    }