美文网首页
C++ webbrowser实现IE 问题汇总

C++ webbrowser实现IE 问题汇总

作者: 爱写诗的程序员zxp | 来源:发表于2020-08-20 15:44 被阅读0次

1、向界面中注入脚本

HRESULT hr;
IHTMLDocument2 *doc = nullptr;
QAxObject *document = WebBrowser->querySubObject("Document");
document->queryInterface(QUuid(IID_IHTMLDocument2), (void**)&doc);
IHTMLWindow2* win2 = nullptr;
hr = doc->get_parentWindow(&win2);
if (SUCCEEDED(hr)) {
      QString invokeJs0 = QString("sss");
      QString invokeJs = invokeJs0;
      BSTR s1 =  SysAllocString((OLECHAR*)invokeJs.unicode());
      BSTR s2 = SysAllocString(L"JavaScript");
      VARIANT ret;
      win2->execScript(s1, s2, &ret);
      SysFreeString(s2);
      SysFreeString(s1);
}

2、通过绑定窗体钩子,拦截脚本错误弹窗提示及安全警告等弹窗
3、webbrowser下焦点问题
2、3代码如下:

Widget* globle_Widget = nullptr;
std::map<DWORD, HHOOK> hktable; //线程和HHOOK的关联表
struct extra_wndproc_t
{
    WNDPROC wndproc;
    bool has_close_sent;
    bool is_show;

    extra_wndproc_t() : wndproc(0), has_close_sent(false), is_show(true) {}
    //关键作用是初始化has_close_sent。至于什么用后面一看便知。
};
std::map<HWND, extra_wndproc_t> subcls_table;    //窗口和WNDPROC的关联表
LRESULT CALLBACK _m_trident_wdproc(HWND wd, UINT msg, WPARAM wpar, LPARAM lpar)
{
    WNDPROC wndproc = subcls_table[wd].wndproc; //获取旧的回调函数地址
    switch (msg) {
        case WM_SHOWWINDOW:
        {
            if (globle_Widget && !globle_Widget->m_alertError) {
                HWND hwnd;
                if ((hwnd = ::FindWindow(nullptr, (LPCWSTR)L"安全警报")) != 0 && hwnd == wd) {
                    HWND btn = ::FindWindowEx(hwnd, 0, nullptr, (LPCWSTR)L"是(&Y)");
                    if (btn != 0) {
                        ::SendMessage(btn, BM_CLICK, 0, 0);
                    }
                    else {
                        ::PostMessage(hwnd, WM_CLOSE, 0, 0);
                    }
                    subcls_table[wd].has_close_sent = true;
                }
                else if ((hwnd = ::FindWindow(nullptr, (LPCWSTR)L"安全警告")) != 0 && hwnd == wd) {
                    HWND btn = ::FindWindowEx(hwnd, 0, nullptr, (LPCWSTR)L"是(&Y)");
                    if (btn != 0) {
                        ::SendMessage(btn, BM_CLICK, 0, 0);
                    }
                    else {
                        ::PostMessage(hwnd, WM_CLOSE, 0, 0);
                    }
                    subcls_table[wd].has_close_sent = true;
                }
    //            else if ((hwnd = ::FindWindow(nullptr, (LPCWSTR)L"Visual Studio Just-In-Time Debugger")) != 0) {
    //                ::PostMessage(hwnd, WM_CLOSE, 0, 0);
    //                subcls_table[wd].has_close_sent = true;
    //            }

                if (subcls_table[wd].has_close_sent) {
                    ::SetWindowPos(wd, 0, -10000, -10000, 0, 0, SWP_NOZORDER);
                    return 0;
                }
            }
            return ::CallWindowProcW(wndproc, wd, msg, wpar, lpar);
        }
        case WM_SETTEXT:
        {
            if (globle_Widget && !globle_Widget->m_alertError) {
                if (lpar) {
                    if (false == subcls_table[wd].has_close_sent) {
                        std::wstring title(reinterpret_cast<TCHAR*>(lpar));
                        if (title == QStringLiteral("脚本错误").toStdWString() || title == QStringLiteral("Internet Explorer 脚本错误").toStdWString()) {
                            ::PostMessage(wd, WM_CLOSE, 0, 0);
                            subcls_table[wd].has_close_sent = true;
                        }
                        else if (title == QStringLiteral("安全警报").toStdWString() || title == QStringLiteral("安全警告").toStdWString()) {
                            HWND btn = ::FindWindowEx(wd, 0, nullptr, (LPCWSTR)L"是(&Y)");
                            if (btn != 0) {
                                ::SendMessage(btn, BM_CLICK, 0, 0);
                            }
                            else {
                                ::PostMessage(wd, WM_CLOSE, 0, 0);
                            }
                            subcls_table[wd].has_close_sent = true;
                        }
                        return 0;
                    }
                }
            }
            return ::CallWindowProcW(wndproc, wd, msg, wpar, lpar);
        }
        case WM_SETFOCUS:    //解决问题3,发送消息给当前嵌入到的父窗体。
        {
            if (globle_Widget) {
                globle_Widget->sendMsgToParent(IEProMsgType::setIEFouce, "");
            }
            return ::CallWindowProcW(wndproc, wd, msg, wpar, lpar);
        }
        case WM_DESTROY:
        {
            ::SetWindowLongW(wd, GWL_WNDPROC, (LONG)wndproc); //还原子类化过程。
            subcls_table.erase(wd);
            return 0;
        }
        default:
        {
            return ::CallWindowProcW(wndproc, wd, msg, wpar, lpar);
        }
    }
}

LRESULT CALLBACK _m_cbtproc(int nCode, WPARAM wParam, LPARAM lParam)
{
    switch (nCode) {
        case HCBT_CREATEWND:
        {
            HWND hwnd = reinterpret_cast<HWND>(wParam);
            WNDPROC prev = (WNDPROC)::SetWindowLongW(hwnd, GWL_WNDPROC, (LONG)_m_trident_wdproc);
            subcls_table[hwnd].wndproc = prev;
            break;
        }
    }

    return ::CallNextHookEx(hktable[::GetCurrentThreadId()], nCode, wParam, lParam);
}
//on_WebBrowser_BeforeNavigate下添加代码:
void Widget::on_WebBrowser_BeforeNavigate(const QString &URL, int Flags, const QString &TargetFrameName, QVariant &PostData, const QString &Headers, bool &Cancel) {
    HWND appwnd = (HWND)this->winId();
    DWORD tid = ::GetWindowThreadProcessId(appwnd, 0);

    if (hktable.count(tid) == 0) //表示该线程没有被HOOK
    {
        HHOOK cbt = ::SetWindowsHookEx(WH_CBT, &_m_cbtproc, NULL, tid);    //设置钩子,用来拦截窗口的创建
        hktable[tid] = cbt;
    }
}

4、window.close时tab页签关闭,仍然会出现确认关闭弹窗。
解决思路:网页注入脚本替换掉当前的window.close方法,注入脚本是当前自己编写浏览器js与C++交互的方法,从而调用C++方法的关闭tab页签。
5、父子窗体绑定方法

    Widget* child = new Widget(3, m_args);
    child->setChildWindow(true);
    QAxObject* pare = child->WebBrowser->querySubObject("Application()");
    child->WebBrowser->setProperty("RegisterAsBrowser", true);
    if(pare == nullptr) {
        return;
    }
    *ppDisp = (IDispatch *)pare->asVariant().value<IDispatch *>();

    child->setGeometry(0, 0, this->width(), this->height());
    child->setParent(this);

6、右键弹窗
解决方法:重载IDocHostUIHandler类

#include <MsHTML.h>
STDMETHODIMP TDocHostUIHandlerImpl::ShowContextMenu(DWORD dwID, POINT *ppt, IUnknown *pcmdtReserved, IDispatch *pdispReserved)
{
    IOleWindow* pWnd = NULL;
    HRESULT hr;
    hr = pcmdtReserved->QueryInterface(IID_IOleWindow, (void**) &pWnd);
    if (SUCCEEDED(hr))
    {
        HWND hwnd;
        if (SUCCEEDED(pWnd->GetWindow(&hwnd)))
        {
            if (g_hPubMenu) {
                ::DestroyMenu(g_hPubMenu);
                g_hPubMenu = nullptr;
            }

            g_hPubMenu = ::CreatePopupMenu();

//            HINSTANCE hinstSHDOCLC = LoadLibrary(TEXT("shdoclc.dll"));   // 加载该DLL即可得到IE右键菜单
//            if (hinstSHDOCLC == NULL) {
//                return S_FALSE;
//            }
//            HMENU hMenu = ::LoadMenu(hinstSHDOCLC, MAKEINTRESOURCE(24641));
//            g_hPubMenu = ::GetSubMenu(hMenu, dwID);

            if (dwID == 0) {
                ::AppendMenu(g_hPubMenu, MF_STRING, 2282, L"后退");
                
            }
            else if (dwID == 1) {
                ::AppendMenu(g_hPubMenu, MF_STRING, 2137, L"在新标签页打开");
            }
            else if (dwID == 2) {
            }
            else if (dwID == 5) {
            }
            long myRetVal = ::TrackPopupMenu(g_hPubMenu,
                                             TPM_RIGHTBUTTON | TPM_LEFTALIGN | TPM_RETURNCMD,
                                             ppt->x, ppt->y, NULL, hwnd, NULL);

            ::SendMessage(hwnd, WM_COMMAND, myRetVal, NULL);
        }
        pWnd->Release();
    }
    return S_OK;
}

7、网页与C++交互

太长。不想写。需要请评论告之。

相关文章

网友评论

      本文标题:C++ webbrowser实现IE 问题汇总

      本文链接:https://www.haomeiwen.com/subject/jturjktx.html