| Index: src/plugin/PluginTabBase.cpp |
| diff --git a/src/plugin/PluginTabBase.cpp b/src/plugin/PluginTabBase.cpp |
| index 3ac26f23bfca300ac710654ca2b406b6bd1be5c1..f17b140b1bf125c98fd95a9661c1f75d47819da6 100644 |
| --- a/src/plugin/PluginTabBase.cpp |
| +++ b/src/plugin/PluginTabBase.cpp |
| @@ -1,394 +1,440 @@ |
| -/* |
| - * This file is part of Adblock Plus <https://adblockplus.org/>, |
| - * Copyright (C) 2006-2015 Eyeo GmbH |
| - * |
| - * Adblock Plus is free software: you can redistribute it and/or modify |
| - * it under the terms of the GNU General Public License version 3 as |
| - * published by the Free Software Foundation. |
| - * |
| - * Adblock Plus is distributed in the hope that it will be useful, |
| - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| - * GNU General Public License for more details. |
| - * |
| - * You should have received a copy of the GNU General Public License |
| - * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
| - */ |
| - |
| -#include "PluginStdAfx.h" |
| -#include "AdblockPlusClient.h" |
| -#include "PluginClientBase.h" |
| -#include "PluginSettings.h" |
| -#include "AdblockPlusDomTraverser.h" |
| -#include "PluginTabBase.h" |
| -#include "IeVersion.h" |
| -#include <Mshtmhst.h> |
| - |
| -CPluginTabBase::CPluginTabBase(CPluginClass* plugin) |
| - : m_plugin(plugin) |
| - , m_isActivated(false) |
| - , m_continueThreadRunning(true) |
| -{ |
| - m_filter = std::auto_ptr<CPluginFilter>(new CPluginFilter()); |
| - m_filter->hideFiltersLoadedEvent = CreateEvent(NULL, true, false, NULL); |
| - |
| - CPluginClient* client = CPluginClient::GetInstance(); |
| - if (AdblockPlus::IE::InstalledMajorVersion() < 10) |
| - { |
| - m_isActivated = true; |
| - } |
| - |
| - try |
| - { |
| - m_thread = std::thread(&CPluginTabBase::ThreadProc, this); |
| - } |
| - catch (const std::system_error& ex) |
| - { |
| - DEBUG_SYSTEM_EXCEPTION(ex, PLUGIN_ERROR_THREAD, PLUGIN_ERROR_TAB_THREAD_CREATE_PROCESS, |
| - "Tab::Thread - Failed to create tab thread"); |
| - } |
| - m_traverser = new CPluginDomTraverser(static_cast<CPluginTab*>(this)); |
| -} |
| - |
| - |
| -CPluginTabBase::~CPluginTabBase() |
| -{ |
| - delete m_traverser; |
| - m_traverser = NULL; |
| - m_continueThreadRunning = false; |
| - if (m_thread.joinable()) { |
| - m_thread.join(); |
| - } |
| -} |
| - |
| -void CPluginTabBase::OnActivate() |
| -{ |
| - m_isActivated = true; |
| -} |
| - |
| - |
| -void CPluginTabBase::OnUpdate() |
| -{ |
| - m_isActivated = true; |
| -} |
| - |
| -namespace |
| -{ |
| - // Entry Point |
| - void FilterLoader(CPluginTabBase* tabBase) |
| - { |
| - try |
| - { |
| - tabBase->m_filter->LoadHideFilters(CPluginClient::GetInstance()->GetElementHidingSelectors(tabBase->GetDocumentDomain())); |
| - SetEvent(tabBase->m_filter->hideFiltersLoadedEvent); |
| - } |
| - catch (...) |
| - { |
| - // As a thread-main function, we truncate any C++ exception. |
| - } |
| - } |
| -} |
| - |
| -void CPluginTabBase::OnNavigate(const std::wstring& url) |
| -{ |
| - SetDocumentUrl(url); |
| - ClearFrameCache(GetDocumentDomain()); |
| - std::wstring domainString = GetDocumentDomain(); |
| - ResetEvent(m_filter->hideFiltersLoadedEvent); |
| - try |
| - { |
| - std::thread filterLoaderThread(&FilterLoader, this); |
| - filterLoaderThread.detach(); // TODO: but actually we should wait for the thread in the dtr. |
| - } |
| - catch (const std::system_error& ex) |
| - { |
| - DEBUG_SYSTEM_EXCEPTION(ex, PLUGIN_ERROR_THREAD, PLUGIN_ERROR_MAIN_THREAD_CREATE_PROCESS, |
| - "Class::Thread - Failed to start filter loader thread"); |
| - } |
| - m_traverser->ClearCache(); |
| -} |
| - |
| -namespace |
| -{ |
| - /** |
| - * Determine if the HTML file is one of ours. |
| - * The criterion is that it appear in the "html/templates" folder within our installation. |
| - * |
| - * Warning: This function may fail if the argument is not a "file://" URL. |
| - * This is occasionally the case in circumstances yet to be characterized. |
| - */ |
| - bool IsOurHtmlFile(const std::wstring& url) |
| - { |
| - // Declared static because the value is derived from an installation directory, which won't change during run-time. |
| - static auto dir = FileUrl(HtmlFolderPath()); |
| - |
| - DEBUG_GENERAL([&]() -> std::wstring { |
| - std::wstring log = L"InjectABP. Current URL: "; |
| - log += url; |
| - log += L", template directory URL: "; |
| - log += dir; |
| - return log; |
| - }()); |
| - |
| - /* |
| - * The length check here is defensive, in case the document URL is truncated for some reason. |
| - */ |
| - if (url.length() < 5) |
| - { |
| - // We can't match ".html" at the end of the URL if it's too short. |
| - return false; |
| - } |
| - auto urlCstr = url.c_str(); |
| - // Check the prefix to match our directory |
| - // Check the suffix to be an HTML file |
| - return (_wcsnicmp(urlCstr, dir.c_str(), dir.length()) == 0) && |
| - (_wcsnicmp(urlCstr + url.length() - 5, L".html", 5) == 0); |
| - } |
| -} |
| - |
| -void CPluginTabBase::InjectABP(IWebBrowser2* browser) |
| -{ |
| - CriticalSection::Lock lock(m_csInject); |
| - auto url = GetDocumentUrl(); |
| - if (!IsOurHtmlFile(url)) |
| - { |
| - DEBUG_GENERAL(L"InjectABP. Not injecting"); |
| - return; |
| - } |
| - DEBUG_GENERAL(L"InjectABP. Injecting"); |
| - CComPtr<IDispatch> pDocDispatch; |
| - browser->get_Document(&pDocDispatch); |
| - CComQIPtr<IHTMLDocument2> pDoc2 = pDocDispatch; |
| - if (!pDoc2) |
| - { |
| - DEBUG_ERROR_LOG(0, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT_INVOKE, "CPluginTabBase::InjectABP - Failed to QI document"); |
| - return; |
| - } |
| - CComPtr<IHTMLWindow2> pWnd2; |
| - pDoc2->get_parentWindow(&pWnd2); |
| - if (!pWnd2) |
| - { |
| - DEBUG_ERROR_LOG(0, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT_INVOKE, "CPluginTabBase::InjectABP - Failed to get parent window"); |
| - return; |
| - } |
| - CComQIPtr<IDispatchEx> pWndEx = pWnd2; |
| - if (!pWndEx) |
| - { |
| - DEBUG_ERROR_LOG(0, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT_INVOKE, "CPluginTabBase::InjectABP - Failed to QI dispatch"); |
| - return; |
| - } |
| - // Create "Settings" object in JavaScript. |
| - // A method call of "Settings" in JavaScript, transfered to "Invoke" of m_pluginUserSettings |
| - DISPID dispid; |
| - HRESULT hr = pWndEx->GetDispID(L"Settings", fdexNameEnsure, &dispid); |
| - if (FAILED(hr)) |
| - { |
| - DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT_INVOKE, "CPluginTabBase::InjectABP - Failed to get dispatch"); |
| - return; |
| - } |
| - CComVariant var((IDispatch*)&m_pluginUserSettings); |
| - |
| - DEBUG_GENERAL("Injecting"); |
| - |
| - DISPPARAMS params; |
| - params.cArgs = 1; |
| - params.cNamedArgs = 0; |
| - params.rgvarg = &var; |
| - params.rgdispidNamedArgs = 0; |
| - hr = pWndEx->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF, ¶ms, 0, 0, 0); |
| - DEBUG_GENERAL("Invoke"); |
| - if (FAILED(hr)) |
| - { |
| - DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT_INVOKE, "CPluginTabBase::InjectABP - Failed to create Settings in JavaScript"); |
| - } |
| -} |
| - |
| -void CPluginTabBase::OnDownloadComplete(IWebBrowser2* browser) |
| -{ |
| - CPluginClient* client = CPluginClient::GetInstance(); |
| - std::wstring url = GetDocumentUrl(); |
| - if (!client->IsWhitelistedUrl(url) && !client->IsElemhideWhitelistedOnDomain(url)) |
| - { |
| - m_traverser->TraverseDocument(browser, GetDocumentDomain(), GetDocumentUrl()); |
| - } |
| - InjectABP(browser); |
| -} |
| - |
| -void CPluginTabBase::OnDocumentComplete(IWebBrowser2* browser, const std::wstring& url, bool isDocumentBrowser) |
| -{ |
| - std::wstring documentUrl = GetDocumentUrl(); |
| - |
| - if (isDocumentBrowser) |
| - { |
| - if (url != documentUrl) |
| - { |
| - SetDocumentUrl(url); |
| - } |
| - InjectABP(browser); |
| - } |
| - CString urlLegacy = ToCString(url); |
| - if (urlLegacy.Left(6) != "res://") |
| - { |
| - // Get document |
| - CComPtr<IDispatch> pDocDispatch; |
| - HRESULT hr = browser->get_Document(&pDocDispatch); |
| - if (FAILED(hr) || !pDocDispatch) |
| - { |
| - return; |
| - } |
| - |
| - CComQIPtr<IHTMLDocument2> pDoc = pDocDispatch; |
| - if (!pDoc) |
| - { |
| - return; |
| - } |
| - CComPtr<IOleObject> pOleObj; |
| - |
| - pDocDispatch->QueryInterface(IID_IOleObject, (void**)&pOleObj); |
| - |
| - |
| - CComPtr<IOleClientSite> pClientSite; |
| - pOleObj->GetClientSite(&pClientSite); |
| - if (pClientSite != NULL) |
| - { |
| - CComPtr<IDocHostUIHandler> docHostUIHandler; |
| - pClientSite->QueryInterface(IID_IDocHostUIHandler, (void**)&docHostUIHandler); |
| - if (docHostUIHandler != NULL) |
| - { |
| - docHostUIHandler->UpdateUI(); |
| - } |
| - } |
| - } |
| -} |
| - |
| -std::wstring CPluginTabBase::GetDocumentDomain() |
| -{ |
| - std::wstring domain; |
| - |
| - m_criticalSection.Lock(); |
| - { |
| - domain = m_documentDomain; |
| - } |
| - m_criticalSection.Unlock(); |
| - |
| - return domain; |
| -} |
| - |
| -void CPluginTabBase::SetDocumentUrl(const std::wstring& url) |
| -{ |
| - m_criticalSection.Lock(); |
| - { |
| - m_documentUrl = url; |
| - m_documentDomain = CAdblockPlusClient::GetInstance()->GetHostFromUrl(url); |
| - } |
| - m_criticalSection.Unlock(); |
| -} |
| - |
| -std::wstring CPluginTabBase::GetDocumentUrl() |
| -{ |
| - std::wstring url; |
| - |
| - m_criticalSection.Lock(); |
| - { |
| - url = m_documentUrl; |
| - } |
| - m_criticalSection.Unlock(); |
| - |
| - return url; |
| -} |
| - |
| - |
| -// ============================================================================ |
| -// Frame caching |
| -// ============================================================================ |
| -bool CPluginTabBase::IsFrameCached(const std::wstring& url) |
| -{ |
| - bool isFrame; |
| - |
| - m_criticalSectionCache.Lock(); |
| - { |
| - isFrame = m_cacheFrames.find(url) != m_cacheFrames.end(); |
| - } |
| - m_criticalSectionCache.Unlock(); |
| - |
| - return isFrame; |
| -} |
| - |
| -void CPluginTabBase::CacheFrame(const std::wstring& url) |
| -{ |
| - m_criticalSectionCache.Lock(); |
| - { |
| - m_cacheFrames.insert(url); |
| - } |
| - m_criticalSectionCache.Unlock(); |
| -} |
| - |
| -void CPluginTabBase::ClearFrameCache(const std::wstring& domain) |
| -{ |
| - m_criticalSectionCache.Lock(); |
| - { |
| - if (domain.empty() || domain != m_cacheDomain) |
| - { |
| - m_cacheFrames.clear(); |
| - m_cacheDomain = domain; |
| - } |
| - } |
| - m_criticalSectionCache.Unlock(); |
| -} |
| - |
| -void CPluginTabBase::ThreadProc() |
| -{ |
| - // Force loading/creation of settings |
| - CPluginSettings::GetInstance()->SetWorkingThreadId(); |
| - |
| - std::string message = |
| - "================================================================================\n" |
| - "TAB THREAD process="; |
| - message += std::to_string(::GetCurrentProcessId()); |
| - message + " thread="; |
| - message += std::to_string(::GetCurrentThreadId()); |
| - message += |
| - "\n" |
| - "================================================================================"; |
| - DEBUG_GENERAL(message); |
| - |
| - // -------------------------------------------------------------------- |
| - // Tab loop |
| - // -------------------------------------------------------------------- |
| - |
| - DWORD loopCount = 0; |
| - DWORD tabLoopIteration = 1; |
| - |
| - while (this->m_continueThreadRunning) |
| - { |
| -#ifdef ENABLE_DEBUG_THREAD |
| - CStringA sTabLoopIteration; |
| - sTabLoopIteration.Format("%u", tabLoopIteration); |
| - |
| - DEBUG_THREAD("--------------------------------------------------------------------------------") |
| - DEBUG_THREAD("Loop iteration " + sTabLoopIteration); |
| - DEBUG_THREAD("--------------------------------------------------------------------------------") |
| -#endif |
| - this->m_isActivated = false; |
| - |
| - // -------------------------------------------------------------------- |
| - // End loop |
| - // -------------------------------------------------------------------- |
| - |
| - // Sleep loop |
| - while (this->m_continueThreadRunning && !this->m_isActivated && (++loopCount % (TIMER_THREAD_SLEEP_TAB_LOOP / 50)) != 0) |
| - { |
| - // Post async plugin error |
| - CPluginError pluginError; |
| - if (LogQueue::PopFirstPluginError(pluginError)) |
| - { |
| - LogQueue::LogPluginError(pluginError.GetErrorCode(), pluginError.GetErrorId(), pluginError.GetErrorSubid(), pluginError.GetErrorDescription(), true, pluginError.GetProcessId(), pluginError.GetThreadId()); |
| - } |
| - |
| - // Non-hanging sleep |
| - Sleep(50); |
| - } |
| - |
| - tabLoopIteration++; |
| - } |
| -} |
| +/* |
| + * This file is part of Adblock Plus <https://adblockplus.org/>, |
| + * Copyright (C) 2006-2015 Eyeo GmbH |
| + * |
| + * Adblock Plus is free software: you can redistribute it and/or modify |
| + * it under the terms of the GNU General Public License version 3 as |
| + * published by the Free Software Foundation. |
| + * |
| + * Adblock Plus is distributed in the hope that it will be useful, |
| + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + * GNU General Public License for more details. |
| + * |
| + * You should have received a copy of the GNU General Public License |
| + * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
| + */ |
| + |
| +#include "PluginStdAfx.h" |
| +#include "AdblockPlusClient.h" |
| +#include "PluginClientBase.h" |
| +#include "PluginSettings.h" |
| +#include "AdblockPlusDomTraverser.h" |
| +#include "PluginTabBase.h" |
| +#include "IeVersion.h" |
| +#include "../shared/Utils.h" |
| +#include <Mshtmhst.h> |
| + |
| +CPluginTabBase::CPluginTabBase(CPluginClass* plugin) |
| + : m_plugin(plugin) |
| + , m_isActivated(false) |
| + , m_continueThreadRunning(true) |
| +{ |
| + m_filter = std::auto_ptr<CPluginFilter>(new CPluginFilter()); |
| + m_filter->hideFiltersLoadedEvent = CreateEvent(NULL, true, false, NULL); |
| + |
| + CPluginClient* client = CPluginClient::GetInstance(); |
| + if (AdblockPlus::IE::InstalledMajorVersion() < 10) |
| + { |
| + m_isActivated = true; |
| + } |
| + |
| + try |
| + { |
| + m_thread = std::thread(&CPluginTabBase::ThreadProc, this); |
| + } |
| + catch (const std::system_error& ex) |
| + { |
| + DEBUG_SYSTEM_EXCEPTION(ex, PLUGIN_ERROR_THREAD, PLUGIN_ERROR_TAB_THREAD_CREATE_PROCESS, |
| + "Tab::Thread - Failed to create tab thread"); |
| + } |
| + m_traverser = new CPluginDomTraverser(static_cast<CPluginTab*>(this)); |
| +} |
| + |
| + |
| +CPluginTabBase::~CPluginTabBase() |
| +{ |
| + delete m_traverser; |
| + m_traverser = NULL; |
| + m_continueThreadRunning = false; |
| + if (m_thread.joinable()) { |
| + m_thread.join(); |
| + } |
| +} |
| + |
| +void CPluginTabBase::OnActivate() |
| +{ |
| + m_isActivated = true; |
| +} |
| + |
| + |
| +void CPluginTabBase::OnUpdate() |
| +{ |
| + m_isActivated = true; |
| +} |
| + |
| +namespace |
| +{ |
| + // Entry Point |
| + void FilterLoader(CPluginTabBase* tabBase) |
| + { |
| + try |
| + { |
| + tabBase->m_filter->LoadHideFilters(CPluginClient::GetInstance()->GetElementHidingSelectors(tabBase->GetDocumentDomain())); |
| + SetEvent(tabBase->m_filter->hideFiltersLoadedEvent); |
| + } |
| + catch (...) |
| + { |
| + // As a thread-main function, we truncate any C++ exception. |
| + } |
| + } |
| +} |
| + |
| +void CPluginTabBase::OnNavigate(const std::wstring& url) |
| +{ |
| + SetDocumentUrl(url); |
| + ClearFrameCache(GetDocumentDomain()); |
| + std::wstring domainString = GetDocumentDomain(); |
| + ResetEvent(m_filter->hideFiltersLoadedEvent); |
| + try |
| + { |
| + std::thread filterLoaderThread(&FilterLoader, this); |
| + filterLoaderThread.detach(); // TODO: but actually we should wait for the thread in the dtr. |
| + } |
| + catch (const std::system_error& ex) |
| + { |
| + DEBUG_SYSTEM_EXCEPTION(ex, PLUGIN_ERROR_THREAD, PLUGIN_ERROR_MAIN_THREAD_CREATE_PROCESS, |
| + "Class::Thread - Failed to start filter loader thread"); |
| + } |
| + m_traverser->ClearCache(); |
| +} |
| + |
| +namespace |
| +{ |
| + /** |
| + * Determine if the HTML file is one of ours. |
| + * The criterion is that it appear in the "html/templates" folder within our installation. |
| + * |
| + * Warning: This function may fail if the argument is not a "file://" URL. |
| + * This is occasionally the case in circumstances yet to be characterized. |
| + */ |
| + bool IsOurHtmlFile(const std::wstring& url) |
| + { |
| + // Declared static because the value is derived from an installation directory, which won't change during run-time. |
| + static auto dir = FileUrl(HtmlFolderPath()); |
| + |
| + DEBUG_GENERAL([&]() -> std::wstring { |
| + std::wstring log = L"InjectABP. Current URL: "; |
| + log += url; |
| + log += L", template directory URL: "; |
| + log += dir; |
| + return log; |
| + }()); |
| + |
| + /* |
| + * The length check here is defensive, in case the document URL is truncated for some reason. |
| + */ |
| + if (url.length() < 5) |
| + { |
| + // We can't match ".html" at the end of the URL if it's too short. |
| + return false; |
| + } |
| + auto urlCstr = url.c_str(); |
| + // Check the prefix to match our directory |
| + // Check the suffix to be an HTML file |
| + return (_wcsnicmp(urlCstr, dir.c_str(), dir.length()) == 0) && |
| + (_wcsnicmp(urlCstr + url.length() - 5, L".html", 5) == 0); |
| + } |
| +} |
| + |
| +void CPluginTabBase::InjectABP(IWebBrowser2* browser) |
| +{ |
| + CriticalSection::Lock lock(m_csInject); |
| + auto url = GetDocumentUrl(); |
| + if (!IsOurHtmlFile(url)) |
| + { |
| + DEBUG_GENERAL(L"InjectABP. Not injecting"); |
| + return; |
| + } |
| + DEBUG_GENERAL(L"InjectABP. Injecting"); |
| + CComPtr<IDispatch> pDocDispatch; |
| + browser->get_Document(&pDocDispatch); |
| + CComQIPtr<IHTMLDocument2> pDoc2 = pDocDispatch; |
| + if (!pDoc2) |
| + { |
| + DEBUG_ERROR_LOG(0, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT_INVOKE, "CPluginTabBase::InjectABP - Failed to QI document"); |
| + return; |
| + } |
| + CComPtr<IHTMLWindow2> pWnd2; |
| + pDoc2->get_parentWindow(&pWnd2); |
| + if (!pWnd2) |
| + { |
| + DEBUG_ERROR_LOG(0, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT_INVOKE, "CPluginTabBase::InjectABP - Failed to get parent window"); |
| + return; |
| + } |
| + CComQIPtr<IDispatchEx> pWndEx = pWnd2; |
| + if (!pWndEx) |
| + { |
| + DEBUG_ERROR_LOG(0, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT_INVOKE, "CPluginTabBase::InjectABP - Failed to QI dispatch"); |
| + return; |
| + } |
| + // Create "Settings" object in JavaScript. |
| + // A method call of "Settings" in JavaScript, transfered to "Invoke" of m_pluginUserSettings |
| + DISPID dispid; |
| + HRESULT hr = pWndEx->GetDispID(L"Settings", fdexNameEnsure, &dispid); |
| + if (FAILED(hr)) |
| + { |
| + DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT_INVOKE, "CPluginTabBase::InjectABP - Failed to get dispatch"); |
| + return; |
| + } |
| + CComVariant var((IDispatch*)&m_pluginUserSettings); |
| + |
| + DEBUG_GENERAL("Injecting"); |
| + |
| + DISPPARAMS params; |
| + params.cArgs = 1; |
| + params.cNamedArgs = 0; |
| + params.rgvarg = &var; |
| + params.rgdispidNamedArgs = 0; |
| + hr = pWndEx->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF, ¶ms, 0, 0, 0); |
| + DEBUG_GENERAL("Invoke"); |
| + if (FAILED(hr)) |
| + { |
| + DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT_INVOKE, "CPluginTabBase::InjectABP - Failed to create Settings in JavaScript"); |
| + } |
| +} |
| + |
| +namespace |
| +{ |
| + ATL::CComPtr<IWebBrowser2> GetParent(IWebBrowser2& browser) |
| + { |
| + ATL::CComPtr<IDispatch> parentDispatch; |
| + if (FAILED(browser.get_Parent(&parentDispatch)) || !parentDispatch) |
| + { |
| + return nullptr; |
| + } |
| + // The InternetExplorer application always returns a pointer to itself. |
|
Oleksandr
2015/10/28 10:12:12
Nit: I'd include a link here: https://msdn.microso
sergei
2015/10/28 10:33:28
Done.
|
| + if (parentDispatch.IsEqualObject(&browser)) |
| + { |
| + return nullptr; |
| + } |
| + ATL::CComQIPtr<IServiceProvider> parentDocumentServiceProvider = parentDispatch; |
| + if (!parentDocumentServiceProvider) |
| + { |
| + return nullptr; |
| + } |
| + ATL::CComPtr<IWebBrowserApp> webBrowserApp; |
| + if (FAILED(parentDocumentServiceProvider->QueryService(IID_IWebBrowserApp, &webBrowserApp)) || !webBrowserApp) |
| + { |
| + return nullptr; |
| + } |
| + return ATL::CComQIPtr<IWebBrowser2>(webBrowserApp); |
| + } |
| + |
| + bool IsFrameWhiteListed(ATL::CComPtr<IWebBrowser2> frame) |
| + { |
| + if (!frame) |
| + { |
| + return false; |
| + } |
| + auto url = GetLocationUrl(*frame); |
| + std::vector<std::string> frameHierarchy; |
| + while(frame = GetParent(*frame)) |
| + { |
| + frameHierarchy.push_back(ToUtf8String(GetLocationUrl(*frame))); |
| + } |
| + CPluginClient* client = CPluginClient::GetInstance(); |
| + return client->IsWhitelistedUrl(url, frameHierarchy) |
| + || client->IsElemhideWhitelistedOnDomain(url, frameHierarchy); |
| + } |
| +} |
| + |
| +void CPluginTabBase::OnDownloadComplete(IWebBrowser2* browser) |
| +{ |
| + CPluginClient* client = CPluginClient::GetInstance(); |
| + std::wstring url = GetDocumentUrl(); |
| + if (!client->IsWhitelistedUrl(url) && !client->IsElemhideWhitelistedOnDomain(url)) |
| + { |
| + m_traverser->TraverseDocument(browser, GetDocumentDomain(), GetDocumentUrl()); |
| + } |
| + InjectABP(browser); |
| +} |
| + |
| +void CPluginTabBase::OnDocumentComplete(IWebBrowser2* browser, const std::wstring& url, bool isDocumentBrowser) |
| +{ |
| + std::wstring documentUrl = GetDocumentUrl(); |
| + |
| + if (isDocumentBrowser) |
| + { |
| + if (url != documentUrl) |
| + { |
| + SetDocumentUrl(url); |
| + } |
| + InjectABP(browser); |
| + } |
| + CString urlLegacy = ToCString(url); |
| + if (urlLegacy.Left(6) != "res://") |
| + { |
| + // Get document |
| + CComPtr<IDispatch> pDocDispatch; |
| + HRESULT hr = browser->get_Document(&pDocDispatch); |
| + if (FAILED(hr) || !pDocDispatch) |
| + { |
| + return; |
| + } |
| + |
| + CComQIPtr<IHTMLDocument2> pDoc = pDocDispatch; |
| + if (!pDoc) |
| + { |
| + return; |
| + } |
| + CComPtr<IOleObject> pOleObj; |
| + |
| + pDocDispatch->QueryInterface(IID_IOleObject, (void**)&pOleObj); |
| + |
| + |
| + CComPtr<IOleClientSite> pClientSite; |
| + pOleObj->GetClientSite(&pClientSite); |
| + if (pClientSite != NULL) |
| + { |
| + CComPtr<IDocHostUIHandler> docHostUIHandler; |
| + pClientSite->QueryInterface(IID_IDocHostUIHandler, (void**)&docHostUIHandler); |
| + if (docHostUIHandler != NULL) |
| + { |
| + docHostUIHandler->UpdateUI(); |
| + } |
| + } |
| + } |
| +} |
| + |
| +std::wstring CPluginTabBase::GetDocumentDomain() |
| +{ |
| + std::wstring domain; |
| + |
| + m_criticalSection.Lock(); |
| + { |
| + domain = m_documentDomain; |
| + } |
| + m_criticalSection.Unlock(); |
| + |
| + return domain; |
| +} |
| + |
| +void CPluginTabBase::SetDocumentUrl(const std::wstring& url) |
| +{ |
| + m_criticalSection.Lock(); |
| + { |
| + m_documentUrl = url; |
| + m_documentDomain = CAdblockPlusClient::GetInstance()->GetHostFromUrl(url); |
| + } |
| + m_criticalSection.Unlock(); |
| +} |
| + |
| +std::wstring CPluginTabBase::GetDocumentUrl() |
| +{ |
| + std::wstring url; |
| + |
| + m_criticalSection.Lock(); |
| + { |
| + url = m_documentUrl; |
| + } |
| + m_criticalSection.Unlock(); |
| + |
| + return url; |
| +} |
| + |
| + |
| +// ============================================================================ |
| +// Frame caching |
| +// ============================================================================ |
| +bool CPluginTabBase::IsFrameCached(const std::wstring& url) |
| +{ |
| + bool isFrame; |
| + |
| + m_criticalSectionCache.Lock(); |
| + { |
| + isFrame = m_cacheFrames.find(url) != m_cacheFrames.end(); |
| + } |
| + m_criticalSectionCache.Unlock(); |
| + |
| + return isFrame; |
| +} |
| + |
| +void CPluginTabBase::CacheFrame(const std::wstring& url) |
| +{ |
| + m_criticalSectionCache.Lock(); |
| + { |
| + m_cacheFrames.insert(url); |
| + } |
| + m_criticalSectionCache.Unlock(); |
| +} |
| + |
| +void CPluginTabBase::ClearFrameCache(const std::wstring& domain) |
| +{ |
| + m_criticalSectionCache.Lock(); |
| + { |
| + if (domain.empty() || domain != m_cacheDomain) |
| + { |
| + m_cacheFrames.clear(); |
| + m_cacheDomain = domain; |
| + } |
| + } |
| + m_criticalSectionCache.Unlock(); |
| +} |
| + |
| +void CPluginTabBase::ThreadProc() |
| +{ |
| + // Force loading/creation of settings |
| + CPluginSettings::GetInstance()->SetWorkingThreadId(); |
| + |
| + std::string message = |
| + "================================================================================\n" |
| + "TAB THREAD process="; |
| + message += std::to_string(::GetCurrentProcessId()); |
| + message + " thread="; |
| + message += std::to_string(::GetCurrentThreadId()); |
| + message += |
| + "\n" |
| + "================================================================================"; |
| + DEBUG_GENERAL(message); |
| + |
| + // -------------------------------------------------------------------- |
| + // Tab loop |
| + // -------------------------------------------------------------------- |
| + |
| + DWORD loopCount = 0; |
| + DWORD tabLoopIteration = 1; |
| + |
| + while (this->m_continueThreadRunning) |
| + { |
| +#ifdef ENABLE_DEBUG_THREAD |
| + CStringA sTabLoopIteration; |
| + sTabLoopIteration.Format("%u", tabLoopIteration); |
| + |
| + DEBUG_THREAD("--------------------------------------------------------------------------------") |
| + DEBUG_THREAD("Loop iteration " + sTabLoopIteration); |
| + DEBUG_THREAD("--------------------------------------------------------------------------------") |
| +#endif |
| + this->m_isActivated = false; |
| + |
| + // -------------------------------------------------------------------- |
| + // End loop |
| + // -------------------------------------------------------------------- |
| + |
| + // Sleep loop |
| + while (this->m_continueThreadRunning && !this->m_isActivated && (++loopCount % (TIMER_THREAD_SLEEP_TAB_LOOP / 50)) != 0) |
| + { |
| + // Post async plugin error |
| + CPluginError pluginError; |
| + if (LogQueue::PopFirstPluginError(pluginError)) |
| + { |
| + LogQueue::LogPluginError(pluginError.GetErrorCode(), pluginError.GetErrorId(), pluginError.GetErrorSubid(), pluginError.GetErrorDescription(), true, pluginError.GetProcessId(), pluginError.GetThreadId()); |
| + } |
| + |
| + // Non-hanging sleep |
| + Sleep(50); |
| + } |
| + |
| + tabLoopIteration++; |
| + } |
| +} |