| 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(); |
| + } |
| +} |