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++交互
太长。不想写。需要请评论告之。
网友评论