在使用 IHTMLDocument2::put_onclick() 在 OnCreate() 中创建浏览器时,您可以在文档完成之前绑定到 onclick 事件:
#include <comutil.h>
ClickEvents<RootFrame> clickEvents;
_variant_t clickDispatch;
clickDispatch.vt = VT_DISPATCH;
clickDispatch.pdispVal = &clickEvents;
CComQIPtr<IDispatch> dispatch;
hr = webBrowser2->get_Document(&dispatch);
ASSERT_EXIT(SUCCEEDED(hr), "webBrowser->get_Document(&dispatch)");
CComQIPtr<IHTMLDocument2> htmlDocument2;
hr = dispatch->QueryInterface(IID_IHTMLDocument2, (void**) &htmlDocument2);
ASSERT_EXIT(SUCCEEDED(hr), "dispatch->QueryInterface(&htmlDocument2)");
htmlDocument2->put_onclick(clickDispatch);
ClickEvents
类实现IDispatch,只需要实现Invoke
方法,其余返回E_NOTIMPL:
HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
HRESULT hr;
CComQIPtr<IWebBrowser2> webBrowser2;
hr = rootFrame->GetDlgControl(rootFrame->rootview.GetDlgCtrlID(), IID_IWebBrowser2, (void**) &webBrowser2);
ASSERT_EXIT(SUCCEEDED(hr), "rootframe->GetDlgControl(IID_IWebBrowser2) failed");
CComQIPtr<IDispatch> dispatch;
hr = webBrowser2->get_Document(&dispatch);
ASSERT_EXIT(SUCCEEDED(hr), "webBrowser2->get_Document(&dispatch)");
CComQIPtr<IHTMLDocument2> htmlDocument2;
hr = dispatch->QueryInterface(IID_IHTMLDocument2, (void**) &htmlDocument2);
ASSERT_EXIT(SUCCEEDED(hr), "dispatch->QueryInterface(&htmlDocument2)");
CComQIPtr<IHTMLWindow2> htmlWindow2;
hr = htmlDocument2->get_parentWindow((IHTMLWindow2**) &htmlWindow2);
ASSERT_EXIT(SUCCEEDED(hr), "htmlDocument2->get_parentWindow(&htmlWindow2)");
CComQIPtr<IHTMLEventObj> htmlEvent;
hr = htmlWindow2->get_event(&htmlEvent);
ASSERT_EXIT(SUCCEEDED(hr), "htmlWindow2->get_event(&htmlEvent)");
CComQIPtr<IHTMLElement> htmlElement;
hr = htmlEvent->get_srcElement(&htmlElement);
ASSERT_EXIT(SUCCEEDED(hr), "htmlEvent->get_srcElement(&htmlElement)");
CComBSTR hrefAttr(L"href");
VARIANT attrValue;
VariantInit(&attrValue);
hr = htmlElement->getAttribute(hrefAttr, 0 | 2, &attrValue); // 0 = case insensitive, 2 = return BSTR
ASSERT_EXIT(SUCCEEDED(hr), "htmlElement->getAttribute()");
wchar_t href[2084]; // maximum url length in IE, http://support.microsoft.com/kb/208427
wcsncpy_s(href, _countof(href), attrValue.bstrVal, _TRUNCATE);
if (!rootFrame->IsURLAllowed(href)) {
VARIANT variant;
variant.vt = VT_BOOL;
variant.boolVal = VARIANT_FALSE;
htmlEvent->put_returnValue(variant);
ShellExecute(0, L"open", href, 0, 0, SW_SHOWNORMAL);
}
return S_OK;
}
正如您在查询一些界面后看到的那样,我终于有了被点击的元素,然后我调用在我的根框架中定义的 IsURLAllowed() 来检查是否允许在当前 webbrowser 窗口中打开 url 或者是否使用用户计算机上的默认浏览器打开它.
这会处理所有链接,即使它们是使用 javascript 附加到文档中的。
表单的“onsubmit”事件也应该这样做。
我也认为我有一个解决方案,用于 javascript 中的“window.location”重定向,我还没有测试过,但我很快就会测试它,然后我会更新这个答案。您可以结合使用“onunload”和“onbeforeunload”事件以及 DWebBrowserEvents2::BeforeNavigate2(),在调用 onunload/onbeforeunload 之后,您将知道用户正在离开当前页面,因此现在在 BeforeNavigate2() 中您可以取消它。您可以使用 IHTMLWindow2::put_onunload() 和 IHTMLWindow2::put_onbeforeunload() 附加卸载事件。
请参阅下面“onclick”的完整解决方案的来源。
在 BrowserFrame 中附加点击事件:
http://code.google.com/p/phpdesktop/source/browse/phpdesktop-msie/msie/browser_frame.h?r=709d00b991b5#125
在 ClickEvents(IDispatch) 中调用:
http://code.google.com/p/phpdesktop/source/browse/phpdesktop-msie/msie/click_events.h?r=a5b0b350c933#132