Index: src/plugin/WebBrowserEventsListener.cpp |
diff --git a/src/plugin/WebBrowserEventsListener.cpp b/src/plugin/WebBrowserEventsListener.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..56602d9c1ae63c1cec839ea5b94a05b057bb34dc |
--- /dev/null |
+++ b/src/plugin/WebBrowserEventsListener.cpp |
@@ -0,0 +1,129 @@ |
+#include "PluginStdAfx.h" |
+#include "WebBrowserEventsListener.h" |
+#include "PluginClientBase.h" // for UnescapeUrl |
+ |
+WebBrowserEventsListener::WebBrowserEventsListener() |
+ : m_isDocumentEvents2Connected(false) |
+ , m_state(State::FirstTimeLoading) |
+{ |
+} |
+ |
+WebBrowserEventsListener::~WebBrowserEventsListener() |
+{ |
+ if (!!m_onDestroy) |
+ { |
+ m_onDestroy(); |
+ } |
+} |
+ |
+HRESULT STDMETHODCALLTYPE WebBrowserEventsListener::OnDocumentComplete(IDispatch* dispFrameBrowser, VARIANT* /*variantUrl*/) |
+{ |
+ if (!dispFrameBrowser) |
+ { |
+ return E_POINTER; |
+ } |
+ |
+ // if it's a signal from another browser (sub-frame for-example) then ignore it. |
+ if (!m_browser.IsEqualObject(dispFrameBrowser)) |
+ { |
+ return S_OK; |
+ } |
+ |
+ if (!m_isDocumentEvents2Connected) |
+ { |
+ ATL::CComPtr<IDispatch> dispDocument; |
+ ATL::CComQIPtr<IHTMLDocument2> htmlDocument2; |
+ bool isHtmlDocument2 = SUCCEEDED(m_browser->get_Document(&dispDocument)) && (htmlDocument2 = dispDocument); |
+ isHtmlDocument2 && (m_isDocumentEvents2Connected = SUCCEEDED(HTMLDocumentEvents2Listener::DispEventAdvise(htmlDocument2))); |
+ } |
+ |
+ // We can get here when readyStateChanged("complete") is already received, |
+ // don't emit reloaded, because it's already emitted from OnReadyStateChange. |
+ if (m_state == State::FirstTimeLoading) |
+ { |
+ m_state = State::Loaded; |
+ emitReloaded(); |
+ } |
+ return S_OK; |
+} |
+ |
+void STDMETHODCALLTYPE WebBrowserEventsListener::OnReadyStateChange(IHTMLEventObj* /*pEvtObj*/) |
+{ |
+ auto documentReadyState = [this]()->std::wstring |
+ { |
+ std::wstring notAvailableReadyState; |
+ ATL::CComPtr<IDispatch> pDocDispatch; |
+ m_browser->get_Document(&pDocDispatch); |
+ ATL::CComQIPtr<IHTMLDocument2> htmlDocument2 = pDocDispatch; |
+ if (!htmlDocument2) |
+ { |
+ assert(false && "htmlDocument2 in OnReadyStateChange should not be nullptr"); |
+ return notAvailableReadyState; |
+ } |
+ ATL::CComBSTR readyState; |
+ if (FAILED(htmlDocument2->get_readyState(&readyState)) || !readyState) |
+ { |
+ assert(false && "cannot obtain document readyState in OnReadyStateChange"); |
+ return notAvailableReadyState; |
+ } |
+ return std::wstring(readyState, readyState.Length()); |
+ }(); |
+ if (documentReadyState == L"loading") |
+ { |
+ m_state = State::Loading; |
+ } |
+ else if (documentReadyState == L"interactive") |
+ { |
+ } |
+ else if (documentReadyState == L"complete") |
+ { |
+ if (m_state == State::Loading) |
+ { |
+ m_state = State::Loaded; |
+ emitReloaded(); |
+ } |
+ else if (m_state == State::Loaded) |
+ { |
+ // It happens but very rearely, most often it appears on gmail. |
+ // It seems IE prepares the 'browser' and then immediately says |
+ // "complete" with the new URL. However all cases are related to |
+ // some redirection technique and I could not reproduce it with local |
+ // server which redirects, so let's wait for the user response on another |
+ // web site when an advertisement is not blocked to better investigate |
+ // when it happens. |
+ } |
+ else |
+ { |
+ assert(false); |
+ } |
+ } |
+ else if (documentReadyState == L"uninitialized") |
+ { |
+ } |
+ else |
+ { |
+ assert(false); |
+ } |
+} |
+ |
+HRESULT WebBrowserEventsListener::Init(IWebBrowser2* webBrowser, const OnDestroy& onDestroy) |
+{ |
+ if (!(m_browser = webBrowser)) |
+ { |
+ return E_POINTER; |
+ } |
+ m_onDestroy = onDestroy; |
+ if (FAILED(WebBrowserEvents2Listener::DispEventAdvise(m_browser, &DIID_DWebBrowserEvents2))) |
+ { |
+ return E_FAIL; |
+ } |
+ return S_OK; |
+} |
+ |
+void WebBrowserEventsListener::emitReloaded() |
+{ |
+ if (reloaded) |
+ { |
+ reloaded(); |
+ } |
+} |