| Index: src/plugin/PluginClass.cpp |
| =================================================================== |
| --- a/src/plugin/PluginClass.cpp |
| +++ b/src/plugin/PluginClass.cpp |
| @@ -15,1881 +15,1881 @@ |
| * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
| */ |
| -#include "PluginStdAfx.h" |
| - |
| -#include "PluginClass.h" |
| -#include "PluginSettings.h" |
| -#include "PluginSystem.h" |
| -#include "PluginFilter.h" |
| -#include "PluginMimeFilterClient.h" |
| -#include "PluginClient.h" |
| -#include "PluginClientFactory.h" |
| -#include "PluginMutex.h" |
| -#include "sddl.h" |
| -#include "PluginUtil.h" |
| -#include "PluginUserSettings.h" |
| -#include "../shared/Utils.h" |
| -#include "../shared/Dictionary.h" |
| -#include "../shared/IE_version.h" |
| -#include <thread> |
| -#include <array> |
| - |
| -#ifdef DEBUG_HIDE_EL |
| -DWORD profileTime = 0; |
| -#endif |
| - |
| -typedef HANDLE (WINAPI *OPENTHEMEDATA)(HWND, LPCWSTR); |
| -typedef HRESULT (WINAPI *DRAWTHEMEBACKGROUND)(HANDLE, HDC, INT, INT, LPRECT, LPRECT); |
| -typedef HRESULT (WINAPI *CLOSETHEMEDATA)(HANDLE); |
| - |
| -HICON CPluginClass::s_hIcons[ICON_MAX] = { NULL, NULL, NULL }; |
| -DWORD CPluginClass::s_hIconTypes[ICON_MAX] = { IDI_ICON_DISABLED, IDI_ICON_ENABLED, IDI_ICON_DEACTIVATED }; |
| -uint32_t iconHeight = 32; |
| -uint32_t iconWidth = 32; |
| - |
| -CPluginMimeFilterClient* CPluginClass::s_mimeFilter = NULL; |
| - |
| -CLOSETHEMEDATA pfnClose = NULL; |
| -DRAWTHEMEBACKGROUND pfnDrawThemeBackground = NULL; |
| -OPENTHEMEDATA pfnOpenThemeData = NULL; |
| - |
| -ATOM CPluginClass::s_atomPaneClass = NULL; |
| -HINSTANCE CPluginClass::s_hUxtheme = NULL; |
| -std::set<CPluginClass*> CPluginClass::s_instances; |
| -std::map<DWORD, CPluginClass*> CPluginClass::s_threadInstances; |
| - |
| -CComAutoCriticalSection CPluginClass::s_criticalSectionLocal; |
| -CComAutoCriticalSection CPluginClass::s_criticalSectionBrowser; |
| -CComAutoCriticalSection CPluginClass::s_criticalSectionWindow; |
| - |
| -CComQIPtr<IWebBrowser2> CPluginClass::s_asyncWebBrowser2; |
| - |
| -/* |
| - * Without namespace declaration, the identifier "Rectangle" is ambiguous |
| - * See http://msdn.microsoft.com/en-us/library/windows/desktop/dd162898(v=vs.85).aspx |
| - */ |
| -namespace AdblockPlus |
| -{ |
| - /** |
| - * Replacement for ATL type CRect. |
| - */ |
| - class Rectangle |
| - : public RECT |
| - { |
| - public: |
| - int Height() const |
| - { |
| - return bottom - top; |
| - } |
| - |
| - int Width() const |
| - { |
| - return right - left; |
| - } |
| - }; |
| -} |
| - |
| -CPluginClass::CPluginClass() |
| -{ |
| - //Use this line to debug memory leaks |
| - // _CrtDumpMemoryLeaks(); |
| - |
| - m_isAdviced = false; |
| - m_nConnectionID = 0; |
| - m_hTabWnd = NULL; |
| - m_hStatusBarWnd = NULL; |
| - m_hPaneWnd = NULL; |
| - m_nPaneWidth = 0; |
| - m_pWndProcStatus = NULL; |
| - m_hTheme = NULL; |
| - m_isInitializedOk = false; |
| - |
| - |
| - m_tab = new CPluginTab(this); |
| - |
| - Dictionary::Create(GetBrowserLanguage()); |
| -} |
| - |
| -CPluginClass::~CPluginClass() |
| -{ |
| - delete m_tab; |
| -} |
| - |
| - |
| -///////////////////////////////////////////////////////////////////////////// |
| -// Initialization |
| - |
| -HRESULT CPluginClass::FinalConstruct() |
| -{ |
| - return S_OK; |
| -} |
| - |
| -void CPluginClass::FinalRelease() |
| -{ |
| - s_criticalSectionBrowser.Lock(); |
| - { |
| - m_webBrowser2.Release(); |
| - } |
| - s_criticalSectionBrowser.Unlock(); |
| -} |
| - |
| - |
| -// This method tries to get a 'connection point' from the stored browser, which can be |
| -// used to attach or detach from the stream of browser events |
| -CComPtr<IConnectionPoint> CPluginClass::GetConnectionPoint() |
| -{ |
| - CComQIPtr<IConnectionPointContainer, &IID_IConnectionPointContainer> pContainer(GetBrowser()); |
| - if (!pContainer) |
| - { |
| - return NULL; |
| - } |
| - |
| - CComPtr<IConnectionPoint> pPoint; |
| - HRESULT hr = pContainer->FindConnectionPoint(DIID_DWebBrowserEvents2, &pPoint); |
| - if (FAILED(hr)) |
| - { |
| - DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_SET_SITE, PLUGIN_ERROR_SET_SITE_FIND_CONNECTION_POINT, "Class::GetConnectionPoint - FindConnectionPoint") |
| - return NULL; |
| - } |
| - |
| - return pPoint; |
| -} |
| - |
| -HWND CPluginClass::GetBrowserHWND() const |
| -{ |
| - SHANDLE_PTR hBrowserWndHandle = NULL; |
| - |
| - CComQIPtr<IWebBrowser2> browser = GetBrowser(); |
| - if (browser) |
| - { |
| - HRESULT hr = browser->get_HWND(&hBrowserWndHandle); |
| - if (FAILED(hr)) |
| - { |
| - DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_GET_BROWSER_WINDOW, "Class::GetBrowserHWND - failed") |
| - } |
| - } |
| - |
| - return (HWND)hBrowserWndHandle; |
| -} |
| - |
| - |
| -CComQIPtr<IWebBrowser2> CPluginClass::GetBrowser() const |
| -{ |
| - CComQIPtr<IWebBrowser2> browser; |
| - |
| - s_criticalSectionBrowser.Lock(); |
| - { |
| - browser = m_webBrowser2; |
| - } |
| - s_criticalSectionBrowser.Unlock(); |
| - |
| - return browser; |
| -} |
| - |
| - |
| -CComQIPtr<IWebBrowser2> CPluginClass::GetAsyncBrowser() |
| -{ |
| - CComQIPtr<IWebBrowser2> browser; |
| - |
| - s_criticalSectionLocal.Lock(); |
| - { |
| - browser = s_asyncWebBrowser2; |
| - } |
| - s_criticalSectionLocal.Unlock(); |
| - |
| - return browser; |
| -} |
| - |
| -std::wstring CPluginClass::GetBrowserUrl() const |
| -{ |
| - std::wstring url; |
| - CComQIPtr<IWebBrowser2> browser = GetBrowser(); |
| - if (browser) |
| - { |
| - CComBSTR bstrURL; |
| - if (SUCCEEDED(browser->get_LocationURL(&bstrURL)) && bstrURL) |
| - { |
| - url = std::wstring(bstrURL, SysStringLen(bstrURL)); |
| - UnescapeUrl(url); |
| - } |
| - } |
| - else |
| - { |
| - url = m_tab->GetDocumentUrl(); |
| - } |
| - return url; |
| -} |
| - |
| -DWORD WINAPI CPluginClass::StartInitObject(LPVOID thisPtr) |
| -{ |
| - if (thisPtr == NULL) |
| - return 0; |
| - if (!((CPluginClass*)thisPtr)->InitObject(true)) |
| - { |
| - ((CPluginClass*)thisPtr)->Unadvice(); |
| - } |
| - |
| - return 0; |
| -} |
| - |
| - |
| - |
| -// This gets called when a new browser window is created (which also triggers the |
| -// creation of this object). The pointer passed in should be to a IWebBrowser2 |
| -// interface that represents the browser for the window. |
| -// it is also called when a tab is closed, this unknownSite will be null |
| -// so we should handle that it is called this way several times during a session |
| -STDMETHODIMP CPluginClass::SetSite(IUnknown* unknownSite) |
| -{ |
| - CPluginSettings* settings = CPluginSettings::GetInstance(); |
| - |
| - MULTIPLE_VERSIONS_CHECK(); |
| - |
| - if (unknownSite) |
| - { |
| - |
| - DEBUG_GENERAL(L"================================================================================\nNEW TAB UI\n================================================================================") |
| - |
| - HRESULT hr = ::CoInitialize(NULL); |
| - if (FAILED(hr)) |
| - { |
| - DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_SET_SITE, PLUGIN_ERROR_SET_SITE_COINIT, "Class::SetSite - CoInitialize"); |
| - } |
| - |
| - s_criticalSectionBrowser.Lock(); |
| - { |
| - m_webBrowser2 = unknownSite; |
| - } |
| - s_criticalSectionBrowser.Unlock(); |
| - |
| - //register the mimefilter |
| - //and only mimefilter |
| - //on some few computers the mimefilter does not get properly registered when it is done on another thread |
| - |
| - s_criticalSectionLocal.Lock(); |
| - { |
| - // Always register on startup, then check if we need to unregister in a separate thread |
| - s_mimeFilter = CPluginClientFactory::GetMimeFilterClientInstance(); |
| - s_asyncWebBrowser2 = unknownSite; |
| - s_instances.insert(this); |
| - } |
| - s_criticalSectionLocal.Unlock(); |
| - |
| - try |
| - { |
| - // Check if loaded as BHO |
| - if (GetBrowser()) |
| - { |
| - DEBUG_GENERAL("Loaded as BHO"); |
| - CComPtr<IConnectionPoint> pPoint = GetConnectionPoint(); |
| - if (pPoint) |
| - { |
| - HRESULT hr = pPoint->Advise((IDispatch*)this, &m_nConnectionID); |
| - if (SUCCEEDED(hr)) |
| - { |
| - m_isAdviced = true; |
| - |
| - try |
| - { |
| - std::thread startInitObjectThread(StartInitObject, this); |
| - startInitObjectThread.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 create StartInitObject thread"); |
| - } |
| - } |
| - else |
| - { |
| - DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_SET_SITE, PLUGIN_ERROR_SET_SITE_ADVICE, "Class::SetSite - Advice"); |
| - } |
| - } |
| - } |
| - else // Check if loaded as toolbar handler |
| - { |
| - DEBUG_GENERAL("Loaded as toolbar handler"); |
| - CComPtr<IServiceProvider> pServiceProvider; |
| - |
| - HRESULT hr = unknownSite->QueryInterface(&pServiceProvider); |
| - if (SUCCEEDED(hr)) |
| - { |
| - if (pServiceProvider) |
| - { |
| - s_criticalSectionBrowser.Lock(); |
| - { |
| - HRESULT hr = pServiceProvider->QueryService(IID_IWebBrowserApp, &m_webBrowser2); |
| - if (SUCCEEDED(hr)) |
| - { |
| - if (m_webBrowser2) |
| - { |
| - InitObject(false); |
| - } |
| - } |
| - else |
| - { |
| - DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_SET_SITE, PLUGIN_ERROR_SET_SITE_QUERY_BROWSER, "Class::SetSite - QueryService (IID_IWebBrowserApp)"); |
| - } |
| - } |
| - s_criticalSectionBrowser.Unlock(); |
| - } |
| - } |
| - else |
| - { |
| - DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_SET_SITE, PLUGIN_ERROR_SET_SITE_QUERY_SERVICE_PROVIDER, "Class::SetSite - QueryInterface (service provider)"); |
| - } |
| - } |
| - } |
| - catch (const std::runtime_error& ex) |
| - { |
| - DEBUG_EXCEPTION(ex); |
| - Unadvice(); |
| - } |
| - } |
| - else |
| - { |
| - // Unadvice |
| - Unadvice(); |
| - |
| - // Destroy window |
| - if (m_pWndProcStatus) |
| - { |
| - ::SetWindowLongPtr(m_hStatusBarWnd, GWLP_WNDPROC, (LPARAM)(WNDPROC)m_pWndProcStatus); |
| - |
| - m_pWndProcStatus = NULL; |
| - } |
| - |
| - if (m_hPaneWnd) |
| - { |
| - DestroyWindow(m_hPaneWnd); |
| - m_hPaneWnd = NULL; |
| - } |
| - |
| - m_hTabWnd = NULL; |
| - m_hStatusBarWnd = NULL; |
| - |
| - // Remove instance from the list, shutdown threads |
| - HANDLE hMainThread = NULL; |
| - HANDLE hTabThread = NULL; |
| - |
| - s_criticalSectionLocal.Lock(); |
| - { |
| - s_instances.erase(this); |
| - |
| - std::map<DWORD,CPluginClass*>::iterator it = s_threadInstances.find(::GetCurrentThreadId()); |
| - if (it != s_threadInstances.end()) |
| - { |
| - s_threadInstances.erase(it); |
| - } |
| - if (s_instances.empty()) |
| - { |
| - // TODO: Explicitly releasing a resource when a container becomes empty looks like a job better suited for shared_ptr |
| - CPluginClientFactory::ReleaseMimeFilterClientInstance(); |
| - } |
| - } |
| - s_criticalSectionLocal.Unlock(); |
| - |
| - // Release browser interface |
| - s_criticalSectionBrowser.Lock(); |
| - { |
| - m_webBrowser2.Release(); |
| - } |
| - s_criticalSectionBrowser.Unlock(); |
| - |
| - DEBUG_GENERAL("================================================================================\nNEW TAB UI - END\n================================================================================") |
| - |
| - ::CoUninitialize(); |
| - } |
| - |
| - return IObjectWithSiteImpl<CPluginClass>::SetSite(unknownSite); |
| -} |
| - |
| -bool CPluginClass::IsStatusBarEnabled() |
| -{ |
| - DEBUG_GENERAL("IsStatusBarEnabled start"); |
| - HKEY pHkey; |
| - HKEY pHkeySub; |
| - RegOpenCurrentUser(KEY_QUERY_VALUE, &pHkey); |
| - DWORD truth = 1; |
| - DWORD truthSize = sizeof(truth); |
| - RegOpenKey(pHkey, L"Software\\Microsoft\\Internet Explorer\\Main", &pHkeySub); |
| - LONG res = RegQueryValueEx(pHkeySub, L"StatusBarWeb", NULL, NULL, (BYTE*)&truth, &truthSize); |
| - RegCloseKey(pHkey); |
| - if (res != ERROR_SUCCESS) |
| - { |
| - res = RegOpenKey(pHkey, L"Software\\Microsoft\\Internet Explorer\\MINIE", &pHkeySub); |
| - if (res == ERROR_SUCCESS) |
| - { |
| - LONG res = RegQueryValueEx(pHkeySub, L"ShowStatusBar", NULL, NULL, (BYTE*)&truth, &truthSize); |
| - if (res == ERROR_SUCCESS) |
| - { |
| - RegCloseKey(pHkey); |
| - } |
| - } |
| - } |
| - DEBUG_GENERAL("IsStatusBarEnabled end"); |
| - return truth == 1; |
| -} |
| - |
| -void CPluginClass::ShowStatusBar() |
| -{ |
| - DEBUG_GENERAL("ShowStatusBar start"); |
| - |
| - VARIANT_BOOL isVisible; |
| - |
| - |
| - CComQIPtr<IWebBrowser2> browser = GetAsyncBrowser(); |
| - if (browser) |
| - { |
| - HRESULT hr = S_OK; |
| - hr = browser->get_StatusBar(&isVisible); |
| - if (SUCCEEDED(hr)) |
| - { |
| - if (!isVisible) |
| - { |
| - SHANDLE_PTR pBrowserHWnd; |
| - browser->get_HWND((SHANDLE_PTR*)&pBrowserHWnd); |
| - Dictionary* dictionary = Dictionary::GetInstance(); |
| - |
| - HKEY pHkey; |
| - HKEY pHkeySub; |
| - LSTATUS regRes = 0; |
| - regRes = RegOpenCurrentUser(KEY_WRITE, &pHkey); |
| - |
| - // Do we have enough rights to enable a status bar? |
| - if (regRes != 0) |
| - { |
| - // We use the tab window here and in the next few calls, since the browser window may still not be available |
| - LRESULT res = MessageBox((HWND)m_hTabWnd, |
| - dictionary->Lookup("status-bar", "error-text").c_str(), |
| - dictionary->Lookup("status-bar", "error-title").c_str(), |
| - MB_OK); |
| - return; |
| - } |
| - // Ask if a user wants to enable a status bar automatically |
| - LRESULT res = MessageBox((HWND)m_hTabWnd, |
| - dictionary->Lookup("status-bar", "question").c_str(), |
| - dictionary->Lookup("status-bar", "title").c_str(), |
| - MB_YESNO); |
| - if (res == IDYES) |
| - { |
| - DWORD truth = 1; |
| - regRes = RegOpenKey(pHkey, L"Software\\Microsoft\\Internet Explorer\\MINIE", &pHkeySub); |
| - regRes = RegSetValueEx(pHkeySub, L"ShowStatusBar", 0, REG_DWORD, (BYTE*)&truth, sizeof(truth)); |
| - regRes = RegCloseKey(pHkeySub); |
| - regRes = RegOpenKey(pHkey, L"Software\\Microsoft\\Internet Explorer\\Main", &pHkeySub); |
| - regRes = RegSetValueEx(pHkeySub, L"StatusBarWeb", 0, REG_DWORD, (BYTE*)&truth, sizeof(truth)); |
| - regRes = RegCloseKey(pHkeySub); |
| - hr = browser->put_StatusBar(TRUE); |
| - if (FAILED(hr)) |
| - { |
| - DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_PUT_STATUSBAR, "Class::Enable statusbar"); |
| - } |
| - CreateStatusBarPane(); |
| - |
| - // We need to restart the tab now, to enable the status bar properly |
| - VARIANT vFlags; |
| - vFlags.vt = VT_I4; |
| - vFlags.intVal = navOpenInNewTab; |
| - |
| - CComBSTR curLoc; |
| - browser->get_LocationURL(&curLoc); |
| - HRESULT hr = browser->Navigate(curLoc, &vFlags, NULL, NULL, NULL); |
| - if (FAILED(hr)) |
| - { |
| - vFlags.intVal = navOpenInNewWindow; |
| - |
| - hr = browser->Navigate(CComBSTR(curLoc), &vFlags, NULL, NULL, NULL); |
| - if (FAILED(hr)) |
| - { |
| - DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_NAVIGATION, PLUGIN_ERROR_NAVIGATION, "Navigation::Failed") |
| - } |
| - } |
| - browser->Quit(); |
| - } |
| - } |
| - } |
| - else |
| - { |
| - DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_GET_STATUSBAR, "Class::Get statusbar state"); |
| - } |
| - } |
| - DEBUG_GENERAL("ShowStatusBar end"); |
| -} |
| - |
| -/* |
| - * #1163 This class is the implementation for method DISPID_BEFORENAVIGATE2 in CPluginClass::Invoke. |
| - * - It validates and convertes its own arguments, rather than unifying them in the Invoke body. |
| - * - It's declared void and not HRESULT, so DISPID_BEFORENAVIGATE2 can only return S_OK. |
| - */ |
| -void CPluginClass::BeforeNavigate2(DISPPARAMS* pDispParams) |
| -{ |
| - |
| - if (pDispParams->cArgs < 7) |
| - { |
| - return; |
| - } |
| - //Register a mime filter if it's not registered yet |
| - if (s_mimeFilter == NULL) |
| - { |
| - s_mimeFilter = CPluginClientFactory::GetMimeFilterClientInstance(); |
| - } |
| - |
| - // Get the IWebBrowser2 interface |
| - CComQIPtr<IWebBrowser2, &IID_IWebBrowser2> WebBrowser2Ptr; |
| - VARTYPE vt = pDispParams->rgvarg[6].vt; |
| - if (vt == VT_DISPATCH) |
| - { |
| - WebBrowser2Ptr = pDispParams->rgvarg[6].pdispVal; |
| - } |
| - else |
| - { |
| - // Wrong type, return. |
| - return; |
| - } |
| - |
| - // Get the URL |
| - std::wstring url; |
| - const auto& arg = pDispParams->rgvarg[5]; |
| - vt = arg.vt; |
| - if (vt == (VT_BYREF | VT_VARIANT) && arg.pvarVal->vt == VT_BSTR) |
| - { |
| - BSTR b = arg.pvarVal->bstrVal; |
| - if (b) { |
| - url = std::wstring(b, SysStringLen(b)); |
| - UnescapeUrl(url); |
| - } |
| - } |
| - else |
| - { |
| - // Wrong type, return. |
| - return; |
| - } |
| - |
| - // If webbrowser2 is equal to top level browser (as set in SetSite), we are navigating new page |
| - CPluginClient* client = CPluginClient::GetInstance(); |
| - CString urlLegacy = ToCString(url); |
| - if (urlLegacy.Find(L"javascript") == 0) |
| - { |
| - } |
| - else if (GetBrowser().IsEqualObject(WebBrowser2Ptr)) |
| - { |
| - m_tab->OnNavigate(url); |
| - |
| - DEBUG_GENERAL( |
| - L"================================================================================\n" |
| - L"Begin main navigation url:" + url + L"\n" |
| - L"================================================================================") |
| - |
| -#ifdef ENABLE_DEBUG_RESULT |
| - CPluginDebug::DebugResultDomain(url); |
| -#endif |
| - |
| - UpdateStatusBar(); |
| - } |
| - else |
| - { |
| - DEBUG_NAVI(L"Navi::Begin navigation url:" + url) |
| - m_tab->CacheFrame(url); |
| - } |
| -} |
| - |
| -/* |
| - * #1163 implements behavior for method DISPID_WINDOWSTATECHANGED in CPluginClass::Invoke |
| - * - should validate and convert arguments in Invoke, not here |
| - * - does not validate number of arguments before indexing into 'rgvarg' |
| - * - does not validate type of argument before using its value |
| - */ |
| -STDMETHODIMP CPluginClass::OnTabChanged(DISPPARAMS* pDispParams, WORD wFlags) |
| -{ |
| - DEBUG_GENERAL("Tab changed"); |
| - bool newtabshown = pDispParams->rgvarg[1].intVal==3; |
| - if (newtabshown) |
| - { |
| - std::map<DWORD,CPluginClass*>::const_iterator it = s_threadInstances.find(GetCurrentThreadId()); |
| - if (it == s_threadInstances.end()) |
| - { |
| - s_threadInstances[::GetCurrentThreadId()] = this; |
| - if (!m_isInitializedOk) |
| - { |
| - m_isInitializedOk = true; |
| - InitObject(true); |
| - UpdateStatusBar(); |
| - } |
| - } |
| - } |
| - notificationMessage.Hide(); |
| - DEBUG_GENERAL("Tab change end"); |
| - return S_OK; |
| -} |
| - |
| -// This gets called whenever there's a browser event |
| -// ENTRY POINT |
| -STDMETHODIMP CPluginClass::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pvarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) |
| -{ |
| - try |
| - { |
| - WCHAR tmp[256]; |
| - wsprintf(tmp, L"Invoke: %d\n", dispidMember); |
| - DEBUG_GENERAL(tmp); |
| - switch (dispidMember) |
| - { |
| - case DISPID_WINDOWSTATECHANGED: |
| - { |
| - // #1163 should validate and convert arguments here |
| - return OnTabChanged(pDispParams, wFlags); |
| - } |
| - |
| - case DISPID_HTMLDOCUMENTEVENTS2_ONBEFOREUPDATE: |
| - break; |
| - |
| - case DISPID_HTMLDOCUMENTEVENTS2_ONCLICK: |
| - break; |
| - |
| - case DISPID_EVMETH_ONLOAD: |
| - DEBUG_NAVI("Navi::OnLoad") |
| - break; |
| - |
| - case DISPID_EVMETH_ONCHANGE: |
| - break; |
| - |
| - case DISPID_EVMETH_ONMOUSEDOWN: |
| - break; |
| - |
| - case DISPID_EVMETH_ONMOUSEENTER: |
| - break; |
| - |
| - case DISPID_IHTMLIMGELEMENT_START: |
| - break; |
| - |
| - case STDDISPID_XOBJ_ERRORUPDATE: |
| - break; |
| - |
| - case STDDISPID_XOBJ_ONPROPERTYCHANGE: |
| - break; |
| - |
| - case DISPID_READYSTATECHANGE: |
| - DEBUG_NAVI("Navi::ReadyStateChange"); |
| - break; |
| - |
| - case DISPID_BEFORENAVIGATE: |
| - DEBUG_NAVI("Navi::BeforeNavigate"); |
| - break; |
| - |
| - case DISPID_COMMANDSTATECHANGE: |
| - if (m_hPaneWnd == NULL) |
| - { |
| - CreateStatusBarPane(); |
| - } |
| - else |
| - { |
| - if (AdblockPlus::IE::InstalledMajorVersion() > 6) |
| - { |
| - RECT rect; |
| - //Get the RECT for the leftmost pane (the status text pane) |
| - BOOL rectRes = ::SendMessage(m_hStatusBarWnd, SB_GETRECT, 0, (LPARAM)&rect); |
| - if (rectRes == TRUE) |
| - { |
| - MoveWindow(m_hPaneWnd, rect.right - m_nPaneWidth, 0, m_nPaneWidth, rect.bottom - rect.top, TRUE); |
| - } |
| - } |
| - } |
| - break; |
| - |
| - case DISPID_STATUSTEXTCHANGE: |
| - break; |
| - |
| - case DISPID_BEFORENAVIGATE2: |
| - { |
| - // #1163 should validate and convert parameters here |
| - BeforeNavigate2(pDispParams); |
| - } |
| - break; |
| - |
| - case DISPID_DOWNLOADBEGIN: |
| - { |
| - DEBUG_NAVI("Navi::Download Begin") |
| - } |
| - break; |
| - |
| - case DISPID_DOWNLOADCOMPLETE: |
| - { |
| - DEBUG_NAVI("Navi::Download Complete"); |
| - CComQIPtr<IWebBrowser2> browser = GetBrowser(); |
| - if (browser) |
| - { |
| - m_tab->OnDownloadComplete(browser); |
| - } |
| - } |
| - break; |
| - |
| - case DISPID_DOCUMENTCOMPLETE: |
| - { |
| - DEBUG_NAVI("Navi::Document Complete"); |
| - CComQIPtr<IWebBrowser2> browser = GetBrowser(); |
| - if (browser && pDispParams->cArgs >= 2 && pDispParams->rgvarg[1].vt == VT_DISPATCH) |
| - { |
| - CComQIPtr<IWebBrowser2> pBrowser = pDispParams->rgvarg[1].pdispVal; |
| - if (pBrowser) |
| - { |
| - CComBSTR bstrUrl; |
| - if (SUCCEEDED(pBrowser->get_LocationURL(&bstrUrl)) && bstrUrl && ::SysStringLen(bstrUrl) > 0) |
| - { |
| - std::wstring url = std::wstring(bstrUrl, SysStringLen(bstrUrl)); |
| - UnescapeUrl(url); |
| - m_tab->OnDocumentComplete(browser, url, browser.IsEqualObject(pBrowser)); |
| - } |
| - } |
| - } |
| - } |
| - break; |
| - |
| - case DISPID_ONQUIT: |
| - case DISPID_QUIT: |
| - { |
| - Unadvice(); |
| - } |
| - break; |
| - |
| - default: |
| - { |
| - CString did; |
| - did.Format(L"DispId:%u", dispidMember); |
| - |
| - DEBUG_NAVI(L"Navi::Default " + did) |
| - } |
| - /* |
| - * Ordinarily a method not dispatched should return DISP_E_MEMBERNOTFOUND. |
| - * As a conservative initial change, we leave it behaving as before, |
| - * which is to do nothing and return S_OK. |
| - */ |
| - // do nothing |
| - break; |
| - } |
| - } |
| - catch(...) |
| - { |
| - DEBUG_GENERAL( "Caught unknown exception in CPluginClass::Invoke" ); |
| - return E_FAIL; |
| - } |
| - return S_OK; |
| -} |
| - |
| -bool CPluginClass::InitObject(bool bBHO) |
| -{ |
| - DEBUG_GENERAL("InitObject"); |
| - CPluginSettings* settings = CPluginSettings::GetInstance(); |
| - |
| - if (!settings->GetPluginEnabled()) |
| - { |
| - s_mimeFilter->Unregister(); |
| - } |
| - |
| - // Load theme module |
| - s_criticalSectionLocal.Lock(); |
| - { |
| - if (!s_hUxtheme) |
| - { |
| - s_hUxtheme = ::GetModuleHandle(L"uxtheme.dll"); |
| - if (s_hUxtheme) |
| - { |
| - pfnClose = (CLOSETHEMEDATA)::GetProcAddress(s_hUxtheme, "CloseThemeData"); |
| - if (!pfnClose) |
| - { |
| - DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_GET_UXTHEME_CLOSE, "Class::InitObject - GetProcAddress(CloseThemeData)"); |
| - } |
| - |
| - pfnDrawThemeBackground = (DRAWTHEMEBACKGROUND)::GetProcAddress(s_hUxtheme, "DrawThemeBackground"); |
| - if (!pfnDrawThemeBackground) |
| - { |
| - DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_GET_UXTHEME_DRAW_BACKGROUND, "Class::InitObject - GetProcAddress(DrawThemeBackground)"); |
| - } |
| - |
| - pfnOpenThemeData = (OPENTHEMEDATA)::GetProcAddress(s_hUxtheme, "OpenThemeData"); |
| - if (!pfnOpenThemeData) |
| - { |
| - DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_GET_UXTHEME_OPEN, "Class::InitObject - GetProcAddress(pfnOpenThemeData)"); |
| - } |
| - } |
| - else |
| - { |
| - DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_GET_UXTHEME, "Class::InitObject - GetModuleHandle(uxtheme.dll)"); |
| - } |
| - } |
| - } |
| - s_criticalSectionLocal.Unlock(); |
| - |
| - // Register pane class |
| - if (!GetAtomPaneClass()) |
| - { |
| - WNDCLASSEX wcex; |
| - |
| - wcex.cbSize = sizeof(wcex); |
| - wcex.style = 0; |
| - wcex.lpfnWndProc = (WNDPROC)PaneWindowProc; |
| - wcex.cbClsExtra = 0; |
| - wcex.cbWndExtra = 0; |
| - wcex.hInstance = _Module.m_hInst; |
| - wcex.hIcon = NULL; |
| - wcex.hCursor = NULL; |
| - wcex.hbrBackground = NULL; |
| - wcex.lpszMenuName = NULL; |
| - wcex.lpszClassName = STATUSBAR_PANE_NAME; |
| - wcex.hIconSm = NULL; |
| - |
| - s_criticalSectionLocal.Lock(); |
| - { |
| - s_atomPaneClass = ::RegisterClassEx(&wcex); |
| - } |
| - s_criticalSectionLocal.Unlock(); |
| - |
| - if (!GetAtomPaneClass()) |
| - { |
| - DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_REGISTER_PANE_CLASS, "Class::InitObject - RegisterClassEx"); |
| - return false; |
| - } |
| - } |
| - |
| - int ieVersion = AdblockPlus::IE::InstalledMajorVersion(); |
| - // Create status pane |
| - if (bBHO && ieVersion > 6 && !CreateStatusBarPane()) |
| - { |
| - return false; |
| - } |
| - |
| - s_criticalSectionLocal.Lock(); |
| - int versionCompRes = CPluginClient::GetInstance()->CompareVersions(CPluginClient::GetInstance()->GetPref(L"currentVersion", L"0.0"), L"1.2"); |
| - |
| - bool isFirstRun = CPluginClient::GetInstance()->IsFirstRun(); |
| - CPluginClient::GetInstance()->SetPref(L"currentVersion", std::wstring(IEPLUGIN_VERSION)); |
| - // This is the first time ABP was installed |
| - // Or ABP was updated from the version that did not support Acceptable Ads (<1.2) |
| - if (isFirstRun || versionCompRes < 0) |
| - { |
| - if (!isFirstRun) |
| - { |
| - CPluginClient::GetInstance()->SetPref(L"displayUpdatePage", true); |
| - } |
| - |
| - // IE6 can't be accessed from another thread, execute in current thread |
| - if (ieVersion < 7) |
| - { |
| - FirstRunThread(); |
| - } |
| - else |
| - { |
| - CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)CPluginClass::FirstRunThread, NULL, NULL, NULL); |
| - } |
| - if (((m_hPaneWnd == NULL) || !IsStatusBarEnabled()) && isFirstRun) |
| - { |
| - ShowStatusBar(); |
| - } |
| - |
| - // Enable acceptable ads by default |
| - std::wstring aaUrl = CPluginClient::GetInstance()->GetPref(L"subscriptions_exceptionsurl", L""); |
| - CPluginClient::GetInstance()->AddSubscription(aaUrl); |
| - } |
| - s_criticalSectionLocal.Unlock(); |
| - return true; |
| -} |
| - |
| -bool CPluginClass::CreateStatusBarPane() |
| -{ |
| - CriticalSection::Lock lock(m_csStatusBar); |
| - |
| - CPluginClient* client = CPluginClient::GetInstance(); |
| - |
| - std::array<wchar_t, MAX_PATH> className; |
| - // Get browser window and url |
| - HWND hBrowserWnd = GetBrowserHWND(); |
| - if (!hBrowserWnd) |
| - { |
| - DEBUG_ERROR_LOG(0, PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_NO_STATUSBAR_BROWSER, "Class::CreateStatusBarPane - No status bar") |
| - return false; |
| - } |
| - |
| - // Looking for a TabWindowClass window in IE7 |
| - // the last one should be parent for statusbar |
| - HWND hWndStatusBar = NULL; |
| - |
| - HWND hTabWnd = ::GetWindow(hBrowserWnd, GW_CHILD); |
| - UINT amoundOfNewTabs = 0; |
| - HWND uniqueNewTab = NULL; |
| - while (hTabWnd) |
| - { |
| - className[0] = L'\0'; |
| - // GetClassNameW returns the number of characters without '\0' |
| - int classNameLength = GetClassNameW(hTabWnd, className.data(), className.size()); |
| - |
| - if (classNameLength && (wcscmp(className.data(), L"TabWindowClass") == 0 || wcscmp(className.data(), L"Frame Tab") == 0)) |
| - { |
| - // IE8 support |
| - HWND hTabWnd2 = hTabWnd; |
| - if (wcscmp(className.data(), L"Frame Tab") == 0) |
| - { |
| - hTabWnd2 = ::FindWindowEx(hTabWnd2, NULL, L"TabWindowClass", NULL); |
| - } |
| - |
| - if (hTabWnd2) |
| - { |
| - DWORD nProcessId; |
| - ::GetWindowThreadProcessId(hTabWnd2, &nProcessId); |
| - if (::GetCurrentProcessId() == nProcessId) |
| - { |
| - bool bExistingTab = false; |
| - |
| - s_criticalSectionLocal.Lock(); |
| - { |
| - for (auto instance : s_instances) |
| - { |
| - if (instance->m_hTabWnd == hTabWnd2) |
| - { |
| - bExistingTab = true; |
| - break; |
| - } |
| - } |
| - } |
| - s_criticalSectionLocal.Unlock(); |
| - |
| - if (!bExistingTab) |
| - { |
| - amoundOfNewTabs ++; |
| - uniqueNewTab = hTabWnd2; |
| - if (GetCurrentThreadId() == GetWindowThreadProcessId(hTabWnd2, NULL)) |
| - { |
| - hBrowserWnd = hTabWnd = hTabWnd2; |
| - break; |
| - } |
| - |
| - } |
| - } |
| - } |
| - } |
| - |
| - hTabWnd = ::GetWindow(hTabWnd, GW_HWNDNEXT); |
| - } |
| - |
| - HWND hWnd = ::GetWindow(hBrowserWnd, GW_CHILD); |
| - while (hWnd) |
| - { |
| - className[0] = L'\0'; |
| - int classNameLength = GetClassNameW(hWnd, className.data(), className.size()); |
| - |
| - if (classNameLength && wcscmp(className.data(), L"msctls_statusbar32") == 0) |
| - { |
| - hWndStatusBar = hWnd; |
| - break; |
| - } |
| - |
| - hWnd = ::GetWindow(hWnd, GW_HWNDNEXT); |
| - } |
| - |
| - if (!hWndStatusBar) |
| - { |
| - DEBUG_ERROR_LOG(0, PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_NO_STATUSBAR_WIN, "Class::CreateStatusBarPane - No status bar") |
| - return true; |
| - } |
| - |
| - // Calculate pane height |
| - AdblockPlus::Rectangle rcStatusBar; |
| - ::GetClientRect(hWndStatusBar, &rcStatusBar); |
| - |
| - if (rcStatusBar.Height() > 0) |
| - { |
| - if (rcStatusBar.Height() < iconWidth) |
| - { |
| - iconWidth = 19; |
| - iconHeight = 19; |
| - } |
| - |
| -#ifdef _DEBUG |
| - m_nPaneWidth = 70; |
| -#else |
| - m_nPaneWidth = min(rcStatusBar.Height(), iconWidth); |
| -#endif |
| - } |
| - else |
| - { |
| -#ifdef _DEBUG |
| - m_nPaneWidth = 70; |
| -#else |
| - m_nPaneWidth = iconWidth; |
| -#endif |
| - } |
| - // Create pane window |
| - HWND hWndNewPane = ::CreateWindowEx( |
| - NULL, |
| - MAKEINTATOM(GetAtomPaneClass()), |
| - L"", |
| - WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, |
| - rcStatusBar.Width() - 500, 0, m_nPaneWidth, rcStatusBar.Height(), |
| - hWndStatusBar, |
| - (HMENU)3671, |
| - _Module.m_hInst, |
| - NULL); |
| - |
| - if (!hWndNewPane) |
| - { |
| - DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_CREATE_STATUSBAR_PANE, "Class::CreateStatusBarPane - CreateWindowEx") |
| - return false; |
| - } |
| - |
| - DEBUG_GENERAL("ABP window created"); |
| - m_hTabWnd = hTabWnd; |
| - m_hStatusBarWnd = hWndStatusBar; |
| - m_hPaneWnd = hWndNewPane; |
| - |
| - UpdateTheme(); |
| - |
| - // Subclass status bar |
| - m_pWndProcStatus = (WNDPROC)SetWindowLongPtr(hWndStatusBar, GWLP_WNDPROC, (LPARAM)(WNDPROC)NewStatusProc); |
| - |
| - // Adjust pane |
| - LRESULT nPartCount = ::SendMessage(m_hStatusBarWnd, SB_GETPARTS, 0, 0); |
| - |
| - if (nPartCount > 1) |
| - { |
| - INT *pData = new INT[nPartCount]; |
| - |
| - ::SendMessage(m_hStatusBarWnd, SB_GETPARTS, nPartCount, (LPARAM)pData); |
| - ::SendMessage(m_hStatusBarWnd, SB_SETPARTS, nPartCount, (LPARAM)pData); |
| - |
| - delete []pData; |
| - } |
| - |
| - HDC hdc = GetWindowDC(m_hStatusBarWnd); |
| - SendMessage(m_hStatusBarWnd, WM_PAINT, (WPARAM)hdc, 0); |
| - ReleaseDC(m_hStatusBarWnd, hdc); |
| - |
| - return true; |
| -} |
| - |
| -void CPluginClass::FirstRunThread() |
| -{ |
| - CoInitialize(NULL); |
| - VARIANT vFlags; |
| - vFlags.vt = VT_I4; |
| - vFlags.intVal = navOpenInNewTab; |
| - |
| - CComBSTR navigatePath = CComBSTR(FirstRunPageFileUrl().c_str()); |
| - |
| - HRESULT hr = GetAsyncBrowser()->Navigate(navigatePath, &vFlags, NULL, NULL, NULL); |
| - if (FAILED(hr)) |
| - { |
| - vFlags.intVal = navOpenInNewWindow; |
| - hr = GetAsyncBrowser()->Navigate(navigatePath, &vFlags, NULL, NULL, NULL); |
| - } |
| - |
| - if (FAILED(hr)) |
| - { |
| - DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_NAVIGATION, PLUGIN_ERROR_NAVIGATION_WELCOME, "Navigation::Welcome page failed") |
| - } |
| -} |
| -void CPluginClass::CloseTheme() |
| -{ |
| - if (m_hTheme) |
| - { |
| - if (pfnClose) |
| - { |
| - pfnClose(m_hTheme); |
| - } |
| - |
| - m_hTheme = NULL; |
| - } |
| -} |
| - |
| -void CPluginClass::UpdateTheme() |
| -{ |
| - CloseTheme(); |
| - |
| - if (pfnOpenThemeData) |
| - { |
| - m_hTheme = pfnOpenThemeData(m_hPaneWnd, L"STATUS"); |
| - if (!m_hTheme) |
| - { |
| - } |
| - } |
| -} |
| - |
| - |
| -CPluginClass* CPluginClass::FindInstance(HWND hStatusBarWnd) |
| -{ |
| - CPluginClass* result = nullptr; |
| - |
| - s_criticalSectionLocal.Lock(); |
| - { |
| - for (auto instance : s_instances) |
| - { |
| - if (instance->m_hStatusBarWnd == hStatusBarWnd) |
| - { |
| - result = instance; |
| - break; |
| - } |
| - } |
| - } |
| - s_criticalSectionLocal.Unlock(); |
| - |
| - return result; |
| -} |
| - |
| -CPluginTab* CPluginClass::GetTab() |
| -{ |
| - return m_tab; |
| -} |
| - |
| -CPluginTab* CPluginClass::GetTab(DWORD dwThreadId) |
| -{ |
| - CPluginTab* tab = NULL; |
| - |
| - s_criticalSectionLocal.Lock(); |
| - { |
| - std::map<DWORD,CPluginClass*>::const_iterator it = s_threadInstances.find(dwThreadId); |
| - if (it != s_threadInstances.end()) |
| - { |
| - tab = it->second->m_tab; |
| - } |
| - } |
| - s_criticalSectionLocal.Unlock(); |
| - |
| - return tab; |
| -} |
| - |
| - |
| -STDMETHODIMP CPluginClass::QueryStatus(const GUID* pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT* pCmdText) |
| -{ |
| - if (cCmds == 0) return E_INVALIDARG; |
| - if (prgCmds == 0) return E_POINTER; |
| - |
| - prgCmds[0].cmdf = OLECMDF_ENABLED; |
| - |
| - return S_OK; |
| -} |
| - |
| -HMENU CPluginClass::CreatePluginMenu(const std::wstring& url) |
| -{ |
| - DEBUG_GENERAL("CreatePluginMenu"); |
| - HINSTANCE hInstance = _AtlBaseModule.GetModuleInstance(); |
| - |
| - HMENU hMenu = ::LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MENU1)); |
| - |
| - HMENU hMenuTrackPopup = GetSubMenu(hMenu, 0); |
| - |
| - SetMenuBar(hMenuTrackPopup, url); |
| - |
| - return hMenuTrackPopup; |
| -} |
| - |
| -void CPluginClass::DisplayPluginMenu(HMENU hMenu, int nToolbarCmdID, POINT pt, UINT nMenuFlags) |
| -{ |
| - CPluginClient* client = CPluginClient::GetInstance(); |
| - |
| - // Create menu parent window |
| - HWND hMenuWnd = ::CreateWindowEx( |
| - NULL, |
| - MAKEINTATOM(GetAtomPaneClass()), |
| - L"", |
| - 0, |
| - 0,0,0,0, |
| - NULL, |
| - NULL, |
| - _Module.m_hInst, |
| - NULL); |
| - |
| - if (!hMenuWnd) |
| - { |
| - DestroyMenu(hMenu); |
| - return; |
| - } |
| - |
| - // Display menu |
| - nMenuFlags |= TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTBUTTON; |
| - |
| - int nCommand = ::TrackPopupMenu(hMenu, nMenuFlags, pt.x, pt.y, 0, hMenuWnd, 0); |
| - |
| - ::DestroyMenu(hMenu); |
| - ::DestroyWindow(hMenuWnd); |
| - |
| - switch (nCommand) |
| - { |
| - case ID_MENU_UPDATE: |
| - { |
| - CPluginClient* client = CPluginClient::GetInstance(); |
| - notificationMessage.SetParent(m_hPaneWnd); |
| - Dictionary* dictionary = Dictionary::GetInstance(); |
| - std::wstring checkingText = dictionary->Lookup("updater", "checking-for-updates-text"); |
| - std::wstring checkingTitle = dictionary->Lookup("updater", "checking-for-updates-title"); |
| - notificationMessage.Show(checkingText, checkingTitle, TTI_INFO); |
| - client->CheckForUpdates(m_hPaneWnd); |
| - } |
| - break; |
| - case ID_MENU_DISABLE: |
| - { |
| - CPluginSettings* settings = CPluginSettings::GetInstance(); |
| - |
| - settings->TogglePluginEnabled(); |
| - |
| - // Enable / disable mime filter |
| - s_criticalSectionLocal.Lock(); |
| - { |
| - if (settings->GetPluginEnabled()) |
| - { |
| - s_mimeFilter = CPluginClientFactory::GetMimeFilterClientInstance(); |
| - } |
| - else |
| - { |
| - s_mimeFilter = NULL; |
| - |
| - CPluginClientFactory::ReleaseMimeFilterClientInstance(); |
| - } |
| - } |
| - s_criticalSectionLocal.Unlock(); |
| - } |
| - break; |
| - case ID_MENU_SETTINGS: |
| - { |
| - CComQIPtr<IWebBrowser2> browser = GetAsyncBrowser(); |
| - if (browser) |
| - { |
| - VARIANT vFlags; |
| - vFlags.vt = VT_I4; |
| - vFlags.intVal = navOpenInNewTab; |
| - |
| - auto userSettingsFileUrl = UserSettingsFileUrl(); |
| - ATL::CComBSTR urlToNavigate(static_cast<int>(userSettingsFileUrl.length()), userSettingsFileUrl.c_str()); |
| - HRESULT hr = browser->Navigate(urlToNavigate, &vFlags, NULL, NULL, NULL); |
| - if (FAILED(hr)) |
| - { |
| - vFlags.intVal = navOpenInNewWindow; |
| - |
| - hr = browser->Navigate(urlToNavigate, &vFlags, NULL, NULL, NULL); |
| - if (FAILED(hr)) |
| - { |
| - DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_NAVIGATION, PLUGIN_ERROR_NAVIGATION_SETTINGS, "Navigation::Failed") |
| - } |
| - } |
| - } |
| - break; |
| - } |
| - case ID_MENU_DISABLE_ON_SITE: |
| - { |
| - CPluginSettings* settings = CPluginSettings::GetInstance(); |
| - std::wstring urlString = GetTab()->GetDocumentUrl(); |
| - if (client->IsWhitelistedUrl(urlString)) |
| - { |
| - settings->RemoveWhiteListedDomain(ToCString(client->GetHostFromUrl(urlString))); |
| - } |
| - else |
| - { |
| - settings->AddWhiteListedDomain(ToCString(client->GetHostFromUrl(urlString))); |
| - } |
| - GetBrowser()->Refresh(); |
| - } |
| - default: |
| - break; |
| - } |
| - |
| - // Invalidate and redraw the control |
| - UpdateStatusBar(); |
| -} |
| - |
| - |
| -bool CPluginClass::SetMenuBar(HMENU hMenu, const std::wstring& url) |
| -{ |
| - DEBUG_GENERAL("SetMenuBar"); |
| - |
| - std::wstring ctext; |
| - Dictionary* dictionary = Dictionary::GetInstance(); |
| - |
| - MENUITEMINFOW fmii = {}; |
| - fmii.cbSize = sizeof(fmii); |
| - |
| - MENUITEMINFOW miiSep = {}; |
| - miiSep.cbSize = sizeof(miiSep); |
| - miiSep.fMask = MIIM_TYPE | MIIM_FTYPE; |
| - miiSep.fType = MFT_SEPARATOR; |
| - |
| - CPluginClient* client = CPluginClient::GetInstance(); |
| - CPluginSettings* settings = CPluginSettings::GetInstance(); |
| - { |
| - ctext = dictionary->Lookup("menu", "menu-disable-on-site"); |
| - // Is domain in white list? |
| - ReplaceString(ctext, L"?1?", client->GetHostFromUrl(url)); |
| - if (client->IsWhitelistedUrl(GetTab()->GetDocumentUrl())) |
| - { |
| - fmii.fState = MFS_CHECKED | MFS_ENABLED; |
| - } |
| - else |
| - { |
| - fmii.fState = MFS_UNCHECKED | MFS_ENABLED; |
| - } |
| - fmii.fMask = MIIM_STRING | MIIM_STATE; |
| - fmii.dwTypeData = const_cast<LPWSTR>(ctext.c_str()); |
| - fmii.cch = static_cast<UINT>(ctext.size()); |
| - |
| - ::SetMenuItemInfoW(hMenu, ID_MENU_DISABLE_ON_SITE, FALSE, &fmii); |
| - } |
| - |
| - // Plugin update |
| - ctext = dictionary->Lookup("menu", "menu-update"); |
| - fmii.fMask = MIIM_STATE | MIIM_STRING; |
| - fmii.fState = client ? MFS_ENABLED : MFS_DISABLED; |
| - fmii.dwTypeData = const_cast<LPWSTR>(ctext.c_str()); |
| - fmii.cch = static_cast<UINT>(ctext.size()); |
| - ::SetMenuItemInfoW(hMenu, ID_MENU_UPDATE, FALSE, &fmii); |
| - |
| - |
| - // Plugin enable |
| - ctext = dictionary->Lookup("menu", "menu-disable"); |
| - if (settings->GetPluginEnabled()) |
| - { |
| - fmii.fState = MFS_UNCHECKED | MFS_ENABLED; |
| - } |
| - else |
| - { |
| - fmii.fState = MFS_CHECKED | MFS_ENABLED; |
| - } |
| - fmii.fMask = MIIM_STATE | MIIM_STRING; |
| - fmii.dwTypeData = const_cast<LPWSTR>(ctext.c_str()); |
| - fmii.cch = static_cast<UINT>(ctext.size()); |
| - ::SetMenuItemInfoW(hMenu, ID_MENU_DISABLE, FALSE, &fmii); |
| - |
| - // Settings |
| - ctext = dictionary->Lookup("menu", "menu-settings"); |
| - fmii.fMask = MIIM_STATE | MIIM_STRING; |
| - fmii.fState = MFS_ENABLED; |
| - fmii.dwTypeData = const_cast<LPWSTR>(ctext.c_str()); |
| - fmii.cch = static_cast<UINT>(ctext.size()); |
| - ::SetMenuItemInfoW(hMenu, ID_MENU_SETTINGS, FALSE, &fmii); |
| - |
| - return true; |
| -} |
| - |
| - |
| -STDMETHODIMP CPluginClass::Exec(const GUID*, DWORD nCmdID, DWORD, VARIANTARG*, VARIANTARG*) |
| -{ |
| - HWND hBrowserWnd = GetBrowserHWND(); |
| - if (!hBrowserWnd) |
| - { |
| - return E_FAIL; |
| - } |
| - |
| - // Create menu |
| - HMENU hMenu = CreatePluginMenu(m_tab->GetDocumentUrl()); |
| - if (!hMenu) |
| - { |
| - return E_FAIL; |
| - } |
| - |
| - // Check if button in toolbar was pressed |
| - int nIDCommand = -1; |
| - BOOL bRightAlign = FALSE; |
| - |
| - POINT pt; |
| - GetCursorPos(&pt); |
| - |
| - HWND hWndToolBar = ::WindowFromPoint(pt); |
| - |
| - DWORD nProcessId; |
| - ::GetWindowThreadProcessId(hWndToolBar, &nProcessId); |
| - |
| - if (hWndToolBar && ::GetCurrentProcessId() == nProcessId) |
| - { |
| - ::ScreenToClient(hWndToolBar, &pt); |
| - int nButton = (int)::SendMessage(hWndToolBar, TB_HITTEST, 0, (LPARAM)&pt); |
| - |
| - if (nButton > 0) |
| - { |
| - TBBUTTON pTBBtn = {}; |
| - |
| - if (SendMessage(hWndToolBar, TB_GETBUTTON, nButton, (LPARAM)&pTBBtn)) |
| - { |
| - RECT rcButton; |
| - nIDCommand = pTBBtn.idCommand; |
| - |
| - if (SendMessage(hWndToolBar, TB_GETRECT, nIDCommand, (LPARAM)&rcButton)) |
| - { |
| - pt.x = rcButton.left; |
| - pt.y = rcButton.bottom; |
| - ClientToScreen(hWndToolBar, &pt); |
| - |
| - RECT rcWorkArea; |
| - SystemParametersInfo(SPI_GETWORKAREA, 0, (LPVOID)&rcWorkArea, 0); |
| - if (rcWorkArea.right - pt.x < 150) |
| - { |
| - bRightAlign = TRUE; |
| - pt.x = rcButton.right; |
| - pt.y = rcButton.bottom; |
| - ClientToScreen(hWndToolBar, &pt); |
| - } |
| - } |
| - } |
| - } |
| - else |
| - { |
| - GetCursorPos(&pt); |
| - } |
| - } |
| - |
| - // Display menu |
| - UINT nFlags = 0; |
| - if (bRightAlign) |
| - { |
| - nFlags |= TPM_RIGHTALIGN; |
| - } |
| - else |
| - { |
| - nFlags |= TPM_LEFTALIGN; |
| - } |
| - |
| - DisplayPluginMenu(hMenu, nIDCommand, pt, nFlags); |
| - |
| - return S_OK; |
| -} |
| - |
| -///////////////////////////////////////////////////////////////////////////// |
| -// Window procedures |
| - |
| -LRESULT CALLBACK CPluginClass::NewStatusProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) |
| -{ |
| - // Find tab |
| - CPluginClass *pClass = FindInstance(hWnd); |
| - if (!pClass) |
| - { |
| - return DefWindowProc(hWnd, message, wParam, lParam); |
| - } |
| - |
| - // Process message |
| - switch (message) |
| - { |
| - case SB_SIMPLE: |
| - { |
| - ShowWindow(pClass->m_hPaneWnd, !wParam); |
| - break; |
| - } |
| - |
| - case WM_SYSCOLORCHANGE: |
| - { |
| - pClass->UpdateTheme(); |
| - break; |
| - } |
| - |
| - case SB_SETPARTS: |
| - { |
| - if (!lParam || !wParam || wParam > 30 || !IsWindow(pClass->m_hPaneWnd)) |
| - { |
| - return CallWindowProc(pClass->m_pWndProcStatus, hWnd, message, wParam, lParam); |
| - } |
| - |
| - WPARAM nParts = wParam; |
| - if (STATUSBAR_PANE_NUMBER >= nParts) |
| - { |
| - return CallWindowProc(pClass->m_pWndProcStatus, hWnd, message, wParam, lParam); |
| - } |
| - |
| - HLOCAL hLocal = LocalAlloc(LHND, sizeof(int) * (nParts+1)); |
| - LPINT lpParts = (LPINT)LocalLock(hLocal); |
| - memcpy(lpParts, (void*)lParam, wParam*sizeof(int)); |
| - |
| - for (unsigned i = 0; i < STATUSBAR_PANE_NUMBER; i++) |
| - { |
| - lpParts[i] -= pClass->m_nPaneWidth; |
| - } |
| - LRESULT hRet = CallWindowProc(pClass->m_pWndProcStatus, hWnd, message, wParam, (LPARAM)lpParts); |
| - |
| - AdblockPlus::Rectangle rcPane; |
| - ::SendMessage(hWnd, SB_GETRECT, STATUSBAR_PANE_NUMBER, (LPARAM)&rcPane); |
| - |
| - AdblockPlus::Rectangle rcClient; |
| - ::GetClientRect(hWnd, &rcClient); |
| - |
| - ::MoveWindow( |
| - pClass->m_hPaneWnd, |
| - lpParts[STATUSBAR_PANE_NUMBER] - pClass->m_nPaneWidth, |
| - 0, |
| - pClass->m_nPaneWidth, |
| - rcClient.Height(), |
| - TRUE); |
| - |
| - ::LocalFree(hLocal); |
| - |
| - |
| - return hRet; |
| - } |
| - |
| - default: |
| - break; |
| - } |
| - |
| - LRESULT result = CallWindowProc(pClass->m_pWndProcStatus, hWnd, message, wParam, lParam); |
| - |
| - |
| - return result; |
| - |
| -} |
| - |
| - |
| -HICON CPluginClass::GetStatusBarIcon(const std::wstring& url) |
| -{ |
| - // use the disable icon as defualt, if the client doesn't exists |
| - HICON hIcon = GetIcon(ICON_PLUGIN_DEACTIVATED); |
| - |
| - CPluginTab* tab = GetTab(::GetCurrentThreadId()); |
| - if (tab) |
| - { |
| - CPluginClient* client = CPluginClient::GetInstance(); |
| - if (CPluginSettings::GetInstance()->IsPluginEnabled()) |
| - { |
| - if (client->IsWhitelistedUrl(url)) |
| - { |
| - hIcon = GetIcon(ICON_PLUGIN_DISABLED); |
| - } |
| - else |
| - { |
| - CPluginSettings* settings = CPluginSettings::GetInstance(); |
| - hIcon = GetIcon(ICON_PLUGIN_ENABLED); |
| - } |
| - } |
| - } |
| - return hIcon; |
| -} |
| - |
| - |
| -LRESULT CALLBACK CPluginClass::PaneWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) |
| -{ |
| - // Find tab |
| - CPluginClass *pClass = FindInstance(GetParent(hWnd)); |
| - if (!pClass) |
| - { |
| - return ::DefWindowProc(hWnd, message, wParam, lParam); |
| - } |
| - |
| - // Process message |
| - switch (message) |
| - { |
| - |
| - case WM_SETCURSOR: |
| - { |
| - ::SetCursor(::LoadCursor(NULL, IDC_ARROW)); |
| - return TRUE; |
| - } |
| - case WM_PAINT: |
| - { |
| - PAINTSTRUCT ps; |
| - HDC hDC = ::BeginPaint(hWnd, &ps); |
| - |
| - AdblockPlus::Rectangle rcClient; |
| - ::GetClientRect(hWnd, &rcClient); |
| - |
| - int nDrawEdge = 0; |
| - |
| - // Old Windows background drawing |
| - if (pClass->m_hTheme == NULL) |
| - { |
| - ::FillRect(hDC, &rcClient, (HBRUSH)(COLOR_BTNFACE + 1)); |
| - ::DrawEdge(hDC, &rcClient, BDR_RAISEDINNER, BF_LEFT); |
| - |
| - nDrawEdge = 3; |
| - rcClient.left += 3; |
| - |
| - ::DrawEdge(hDC, &rcClient, BDR_SUNKENOUTER, BF_RECT); |
| - } |
| - // Themed background drawing |
| - else |
| - { |
| - // Draw background |
| - if (pfnDrawThemeBackground) |
| - { |
| - AdblockPlus::Rectangle rc = rcClient; |
| - rc.right -= 2; |
| - pfnDrawThemeBackground(pClass->m_hTheme, hDC, 0, 0, &rc, NULL); |
| - } |
| - |
| - // Copy separator picture to left side |
| - int nHeight = rcClient.Height(); |
| - int nWidth = rcClient.Width() - 2; |
| - |
| - for (int i = 0; i < 2; i++) |
| - { |
| - for (int j = 0; j < nHeight; j++) |
| - { |
| - COLORREF clr = ::GetPixel(hDC, i + nWidth, j); |
| - |
| - // Ignore black boxes (if source is obscured by other windows) |
| - if (clr != -1 && (GetRValue(clr) > 8 || GetGValue(clr) > 8 || GetBValue(clr) > 8)) |
| - { |
| - ::SetPixel(hDC, i, j, clr); |
| - } |
| - } |
| - } |
| - } |
| - |
| - // Draw icon |
| - if (CPluginClient::GetInstance()) |
| - { |
| - HICON hIcon = GetStatusBarIcon(pClass->GetTab()->GetDocumentUrl()); |
| - |
| - int offx = nDrawEdge; |
| - if (hIcon) |
| - { |
| - //Get the RECT for the leftmost pane (the status text pane) |
| - RECT rect; |
| - BOOL rectRes = ::SendMessage(pClass->m_hStatusBarWnd, SB_GETRECT, 0, (LPARAM)&rect); |
| - ::DrawIconEx(hDC, 0, rect.bottom - rect.top - iconHeight, hIcon, iconWidth, iconHeight, NULL, NULL, DI_NORMAL); |
| - offx += iconWidth; |
| - } |
| -#ifdef _DEBUG |
| - // Display version |
| - HFONT hFont = (HFONT)::SendMessage(pClass->m_hStatusBarWnd, WM_GETFONT, 0, 0); |
| - HGDIOBJ hOldFont = ::SelectObject(hDC,hFont); |
| - |
| - AdblockPlus::Rectangle rcText = rcClient; |
| - rcText.left += offx; |
| - ::SetBkMode(hDC, TRANSPARENT); |
| - ::DrawTextW(hDC, IEPLUGIN_VERSION, -1, &rcText, DT_WORD_ELLIPSIS|DT_LEFT|DT_SINGLELINE|DT_VCENTER); |
| - |
| - ::SelectObject(hDC, hOldFont); |
| -#endif // _DEBUG |
| - } |
| - |
| - // Done! |
| - EndPaint(hWnd, &ps); |
| - |
| - return 0; |
| - } |
| - |
| - case WM_LBUTTONUP: |
| - case WM_RBUTTONUP: |
| - { |
| - std::wstring url = pClass->GetBrowserUrl(); |
| - if (url != pClass->GetTab()->GetDocumentUrl()) |
| - { |
| - pClass->GetTab()->SetDocumentUrl(url); |
| - } |
| - |
| - // Create menu |
| - HMENU hMenu = pClass->CreatePluginMenu(url); |
| - if (!hMenu) |
| - { |
| - return 0; |
| - } |
| - |
| - // Display menu |
| - POINT pt; |
| - ::GetCursorPos(&pt); |
| - |
| - RECT rc; |
| - ::GetWindowRect(hWnd, &rc); |
| - |
| - if (rc.left >= 0 && rc.top >= 0) |
| - { |
| - pt.x = rc.left; |
| - pt.y = rc.top; |
| - } |
| - |
| - pClass->DisplayPluginMenu(hMenu, -1, pt, TPM_LEFTALIGN|TPM_BOTTOMALIGN); |
| - } |
| - break; |
| - case WM_DESTROY: |
| - break; |
| - case SC_CLOSE: |
| - break; |
| - |
| - case WM_UPDATEUISTATE: |
| - { |
| - CPluginTab* tab = GetTab(::GetCurrentThreadId()); |
| - if (tab) |
| - { |
| - tab->OnActivate(); |
| - RECT rect; |
| - GetWindowRect(pClass->m_hPaneWnd, &rect); |
| - pClass->notificationMessage.Move(rect.left + (rect.right - rect.left) / 2, rect.top + (rect.bottom - rect.top) / 2); |
| - } |
| - if (LOWORD(wParam) == UIS_CLEAR) |
| - { |
| - pClass->notificationMessage.Hide(); |
| - } |
| - } |
| - break; |
| - case WM_WINDOWPOSCHANGING: |
| - { |
| - RECT rect; |
| - GetWindowRect(pClass->m_hPaneWnd, &rect); |
| - if (pClass->notificationMessage.IsVisible()) |
| - { |
| - pClass->notificationMessage.Move(rect.left + (rect.right - rect.left) / 2, rect.top + (rect.bottom - rect.top) / 2); |
| - } |
| - } |
| - break; |
| - case WM_WINDOWPOSCHANGED: |
| - { |
| - WINDOWPOS* wndPos = reinterpret_cast<WINDOWPOS*>(lParam); |
| - if (wndPos->flags & SWP_HIDEWINDOW) |
| - { |
| - pClass->notificationMessage.Hide(); |
| - } |
| - } |
| - break; |
| - case WM_ALREADY_UP_TO_DATE: |
| - { |
| - Dictionary* dictionary = Dictionary::GetInstance(); |
| - std::wstring upToDateText = dictionary->Lookup("updater", "update-already-up-to-date-text"); |
| - std::wstring upToDateTitle = dictionary->Lookup("updater", "update-already-up-to-date-title"); |
| - pClass->notificationMessage.SetTextAndIcon(upToDateText, upToDateTitle, TTI_INFO); |
| - } |
| - break; |
| - case WM_UPDATE_CHECK_ERROR: |
| - { |
| - Dictionary* dictionary = Dictionary::GetInstance(); |
| - std::wstring errorText = dictionary->Lookup("updater", "update-error-text"); |
| - std::wstring errorTitle = dictionary->Lookup("updater", "update-error-title"); |
| - pClass->notificationMessage.SetTextAndIcon(errorText, errorText, TTI_ERROR); |
| - } |
| - break; |
| - case WM_DOWNLOADING_UPDATE: |
| - { |
| - Dictionary* dictionary = Dictionary::GetInstance(); |
| - std::wstring downloadingText = dictionary->Lookup("updater", "downloading-update-text"); |
| - std::wstring downloadingTitle = dictionary->Lookup("updater", "downloading-update-title"); |
| - pClass->notificationMessage.SetTextAndIcon(downloadingText, downloadingTitle, TTI_INFO); |
| - } |
| - break; |
| - } |
| - |
| - return DefWindowProc(hWnd, message, wParam, lParam); |
| -} |
| - |
| - |
| -void CPluginClass::UpdateStatusBar() |
| -{ |
| - DEBUG_GENERAL("*** Updating statusbar") |
| - if (m_hPaneWnd == NULL) |
| - { |
| - CreateStatusBarPane(); |
| - } |
| - if ((m_hPaneWnd != NULL) && !::InvalidateRect(m_hPaneWnd, NULL, FALSE)) |
| - { |
| - DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_INVALIDATE_STATUSBAR, "Class::Invalidate statusbar"); |
| - } |
| -} |
| - |
| - |
| -void CPluginClass::Unadvice() |
| -{ |
| - s_criticalSectionLocal.Lock(); |
| - { |
| - if (m_isAdviced) |
| - { |
| - CComPtr<IConnectionPoint> pPoint = GetConnectionPoint(); |
| - if (pPoint) |
| - { |
| - HRESULT hr = pPoint->Unadvise(m_nConnectionID); |
| - if (FAILED(hr)) |
| - { |
| - DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_SET_SITE, PLUGIN_ERROR_SET_SITE_UNADVICE, "Class::Unadvice - Unadvise"); |
| - } |
| - } |
| - |
| - m_isAdviced = false; |
| - } |
| - } |
| - s_criticalSectionLocal.Unlock(); |
| -} |
| - |
| -HICON CPluginClass::GetIcon(int type) |
| -{ |
| - HICON icon = NULL; |
| - |
| - s_criticalSectionLocal.Lock(); |
| - { |
| - if (!s_hIcons[type]) |
| - { |
| - std::wstring imageToLoad = L"#"; |
| - imageToLoad += std::to_wstring(s_hIconTypes[type]); |
| - s_hIcons[type] = (HICON)::LoadImage(_Module.m_hInst, imageToLoad.c_str(), IMAGE_ICON, iconWidth, iconHeight, LR_SHARED); |
| - if (!s_hIcons[type]) |
| - { |
| - DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_LOAD_ICON, "Class::GetIcon - LoadIcon"); |
| - } |
| - } |
| - |
| - icon = s_hIcons[type]; |
| - } |
| - s_criticalSectionLocal.Unlock(); |
| - |
| - return icon; |
| -} |
| - |
| -ATOM CPluginClass::GetAtomPaneClass() |
| -{ |
| - return s_atomPaneClass; |
| -} |
| - |
| -HWND CPluginClass::GetTabHWND() const |
| -{ |
| - std::array<wchar_t, MAX_PATH> className; |
| - // Get browser window and url |
| - HWND hBrowserWnd = GetBrowserHWND(); |
| - if (!hBrowserWnd) |
| - { |
| - DEBUG_ERROR_LOG(0, PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_NO_STATUSBAR_BROWSER, "Class::GetTabWindow - No tab window") |
| - s_criticalSectionWindow.Unlock(); |
| - |
| - return false; |
| - } |
| - |
| - // Looking for a TabWindowClass window in IE7 |
| - |
| - HWND hTabWnd = ::GetWindow(hBrowserWnd, GW_CHILD); |
| - while (hTabWnd) |
| - { |
| - className[0] = L'\0'; |
| - int classNameLength = GetClassNameW(hTabWnd, className.data(), className.size()); |
| - |
| - if (classNameLength && (wcscmp(className.data(), L"TabWindowClass") == 0 || wcscmp(className.data(), L"Frame Tab") == 0)) |
| - { |
| - // IE8 support |
| - HWND hTabWnd2 = hTabWnd; |
| - if (wcscmp(className.data(), L"Frame Tab") == 0) |
| - { |
| - hTabWnd2 = ::FindWindowEx(hTabWnd2, NULL, L"TabWindowClass", NULL); |
| - } |
| - |
| - if (hTabWnd2) |
| - { |
| - DWORD nProcessId; |
| - ::GetWindowThreadProcessId(hTabWnd2, &nProcessId); |
| - if (::GetCurrentProcessId() == nProcessId) |
| - { |
| - bool bExistingTab = false; |
| - s_criticalSectionLocal.Lock(); |
| - |
| - { |
| - for (auto instance : s_instances) |
| - { |
| - if (instance->m_hTabWnd == hTabWnd2) |
| - { |
| - bExistingTab = true; |
| - break; |
| - } |
| - } |
| - } |
| - |
| - if (!bExistingTab) |
| - { |
| - hBrowserWnd = hTabWnd2; |
| - hTabWnd = hTabWnd2; |
| - s_criticalSectionLocal.Unlock(); |
| - break; |
| - } |
| - s_criticalSectionLocal.Unlock(); |
| - |
| - } |
| - } |
| - } |
| - |
| - hTabWnd = ::GetWindow(hTabWnd, GW_HWNDNEXT); |
| - } |
| - |
| - return hTabWnd; |
| - |
| -} |
| +#include "PluginStdAfx.h" |
| + |
| +#include "PluginClass.h" |
| +#include "PluginSettings.h" |
| +#include "PluginSystem.h" |
| +#include "PluginFilter.h" |
| +#include "PluginMimeFilterClient.h" |
| +#include "PluginClient.h" |
| +#include "PluginClientFactory.h" |
| +#include "PluginMutex.h" |
| +#include "sddl.h" |
| +#include "PluginUtil.h" |
| +#include "PluginUserSettings.h" |
| +#include "../shared/Utils.h" |
| +#include "../shared/Dictionary.h" |
| +#include "../shared/IE_version.h" |
| +#include <thread> |
| +#include <array> |
| + |
| +#ifdef DEBUG_HIDE_EL |
| +DWORD profileTime = 0; |
| +#endif |
| + |
| +typedef HANDLE (WINAPI *OPENTHEMEDATA)(HWND, LPCWSTR); |
| +typedef HRESULT (WINAPI *DRAWTHEMEBACKGROUND)(HANDLE, HDC, INT, INT, LPRECT, LPRECT); |
| +typedef HRESULT (WINAPI *CLOSETHEMEDATA)(HANDLE); |
| + |
| +HICON CPluginClass::s_hIcons[ICON_MAX] = { NULL, NULL, NULL }; |
| +DWORD CPluginClass::s_hIconTypes[ICON_MAX] = { IDI_ICON_DISABLED, IDI_ICON_ENABLED, IDI_ICON_DEACTIVATED }; |
| +uint32_t iconHeight = 32; |
| +uint32_t iconWidth = 32; |
| + |
| +CPluginMimeFilterClient* CPluginClass::s_mimeFilter = NULL; |
| + |
| +CLOSETHEMEDATA pfnClose = NULL; |
| +DRAWTHEMEBACKGROUND pfnDrawThemeBackground = NULL; |
| +OPENTHEMEDATA pfnOpenThemeData = NULL; |
| + |
| +ATOM CPluginClass::s_atomPaneClass = NULL; |
| +HINSTANCE CPluginClass::s_hUxtheme = NULL; |
| +std::set<CPluginClass*> CPluginClass::s_instances; |
| +std::map<DWORD, CPluginClass*> CPluginClass::s_threadInstances; |
| + |
| +CComAutoCriticalSection CPluginClass::s_criticalSectionLocal; |
| +CComAutoCriticalSection CPluginClass::s_criticalSectionBrowser; |
| +CComAutoCriticalSection CPluginClass::s_criticalSectionWindow; |
| + |
| +CComQIPtr<IWebBrowser2> CPluginClass::s_asyncWebBrowser2; |
| + |
| +/* |
| + * Without namespace declaration, the identifier "Rectangle" is ambiguous |
| + * See http://msdn.microsoft.com/en-us/library/windows/desktop/dd162898(v=vs.85).aspx |
| + */ |
| +namespace AdblockPlus |
| +{ |
| + /** |
| + * Replacement for ATL type CRect. |
| + */ |
| + class Rectangle |
| + : public RECT |
| + { |
| + public: |
| + int Height() const |
| + { |
| + return bottom - top; |
| + } |
| + |
| + int Width() const |
| + { |
| + return right - left; |
| + } |
| + }; |
| +} |
| + |
| +CPluginClass::CPluginClass() |
| +{ |
| + //Use this line to debug memory leaks |
| + // _CrtDumpMemoryLeaks(); |
| + |
| + m_isAdviced = false; |
| + m_nConnectionID = 0; |
| + m_hTabWnd = NULL; |
| + m_hStatusBarWnd = NULL; |
| + m_hPaneWnd = NULL; |
| + m_nPaneWidth = 0; |
| + m_pWndProcStatus = NULL; |
| + m_hTheme = NULL; |
| + m_isInitializedOk = false; |
| + |
| + |
| + m_tab = new CPluginTab(this); |
| + |
| + Dictionary::Create(GetBrowserLanguage()); |
| +} |
| + |
| +CPluginClass::~CPluginClass() |
| +{ |
| + delete m_tab; |
| +} |
| + |
| + |
| +///////////////////////////////////////////////////////////////////////////// |
| +// Initialization |
| + |
| +HRESULT CPluginClass::FinalConstruct() |
| +{ |
| + return S_OK; |
| +} |
| + |
| +void CPluginClass::FinalRelease() |
| +{ |
| + s_criticalSectionBrowser.Lock(); |
| + { |
| + m_webBrowser2.Release(); |
| + } |
| + s_criticalSectionBrowser.Unlock(); |
| +} |
| + |
| + |
| +// This method tries to get a 'connection point' from the stored browser, which can be |
| +// used to attach or detach from the stream of browser events |
| +CComPtr<IConnectionPoint> CPluginClass::GetConnectionPoint() |
| +{ |
| + CComQIPtr<IConnectionPointContainer, &IID_IConnectionPointContainer> pContainer(GetBrowser()); |
| + if (!pContainer) |
| + { |
| + return NULL; |
| + } |
| + |
| + CComPtr<IConnectionPoint> pPoint; |
| + HRESULT hr = pContainer->FindConnectionPoint(DIID_DWebBrowserEvents2, &pPoint); |
| + if (FAILED(hr)) |
| + { |
| + DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_SET_SITE, PLUGIN_ERROR_SET_SITE_FIND_CONNECTION_POINT, "Class::GetConnectionPoint - FindConnectionPoint") |
| + return NULL; |
| + } |
| + |
| + return pPoint; |
| +} |
| + |
| +HWND CPluginClass::GetBrowserHWND() const |
| +{ |
| + SHANDLE_PTR hBrowserWndHandle = NULL; |
| + |
| + CComQIPtr<IWebBrowser2> browser = GetBrowser(); |
| + if (browser) |
| + { |
| + HRESULT hr = browser->get_HWND(&hBrowserWndHandle); |
| + if (FAILED(hr)) |
| + { |
| + DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_GET_BROWSER_WINDOW, "Class::GetBrowserHWND - failed") |
| + } |
| + } |
| + |
| + return (HWND)hBrowserWndHandle; |
| +} |
| + |
| + |
| +CComQIPtr<IWebBrowser2> CPluginClass::GetBrowser() const |
| +{ |
| + CComQIPtr<IWebBrowser2> browser; |
| + |
| + s_criticalSectionBrowser.Lock(); |
| + { |
| + browser = m_webBrowser2; |
| + } |
| + s_criticalSectionBrowser.Unlock(); |
| + |
| + return browser; |
| +} |
| + |
| + |
| +CComQIPtr<IWebBrowser2> CPluginClass::GetAsyncBrowser() |
| +{ |
| + CComQIPtr<IWebBrowser2> browser; |
| + |
| + s_criticalSectionLocal.Lock(); |
| + { |
| + browser = s_asyncWebBrowser2; |
| + } |
| + s_criticalSectionLocal.Unlock(); |
| + |
| + return browser; |
| +} |
| + |
| +std::wstring CPluginClass::GetBrowserUrl() const |
| +{ |
| + std::wstring url; |
| + CComQIPtr<IWebBrowser2> browser = GetBrowser(); |
| + if (browser) |
| + { |
| + CComBSTR bstrURL; |
| + if (SUCCEEDED(browser->get_LocationURL(&bstrURL)) && bstrURL) |
| + { |
| + url = std::wstring(bstrURL, SysStringLen(bstrURL)); |
| + UnescapeUrl(url); |
| + } |
| + } |
| + else |
| + { |
| + url = m_tab->GetDocumentUrl(); |
| + } |
| + return url; |
| +} |
| + |
| +DWORD WINAPI CPluginClass::StartInitObject(LPVOID thisPtr) |
| +{ |
| + if (thisPtr == NULL) |
| + return 0; |
| + if (!((CPluginClass*)thisPtr)->InitObject(true)) |
| + { |
| + ((CPluginClass*)thisPtr)->Unadvice(); |
| + } |
| + |
| + return 0; |
| +} |
| + |
| + |
| + |
| +// This gets called when a new browser window is created (which also triggers the |
| +// creation of this object). The pointer passed in should be to a IWebBrowser2 |
| +// interface that represents the browser for the window. |
| +// it is also called when a tab is closed, this unknownSite will be null |
| +// so we should handle that it is called this way several times during a session |
| +STDMETHODIMP CPluginClass::SetSite(IUnknown* unknownSite) |
| +{ |
| + CPluginSettings* settings = CPluginSettings::GetInstance(); |
| + |
| + MULTIPLE_VERSIONS_CHECK(); |
| + |
| + if (unknownSite) |
| + { |
| + |
| + DEBUG_GENERAL(L"================================================================================\nNEW TAB UI\n================================================================================") |
| + |
| + HRESULT hr = ::CoInitialize(NULL); |
| + if (FAILED(hr)) |
| + { |
| + DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_SET_SITE, PLUGIN_ERROR_SET_SITE_COINIT, "Class::SetSite - CoInitialize"); |
| + } |
| + |
| + s_criticalSectionBrowser.Lock(); |
| + { |
| + m_webBrowser2 = unknownSite; |
| + } |
| + s_criticalSectionBrowser.Unlock(); |
| + |
| + //register the mimefilter |
| + //and only mimefilter |
| + //on some few computers the mimefilter does not get properly registered when it is done on another thread |
| + |
| + s_criticalSectionLocal.Lock(); |
| + { |
| + // Always register on startup, then check if we need to unregister in a separate thread |
| + s_mimeFilter = CPluginClientFactory::GetMimeFilterClientInstance(); |
| + s_asyncWebBrowser2 = unknownSite; |
| + s_instances.insert(this); |
| + } |
| + s_criticalSectionLocal.Unlock(); |
| + |
| + try |
| + { |
| + // Check if loaded as BHO |
| + if (GetBrowser()) |
| + { |
| + DEBUG_GENERAL("Loaded as BHO"); |
| + CComPtr<IConnectionPoint> pPoint = GetConnectionPoint(); |
| + if (pPoint) |
| + { |
| + HRESULT hr = pPoint->Advise((IDispatch*)this, &m_nConnectionID); |
| + if (SUCCEEDED(hr)) |
| + { |
| + m_isAdviced = true; |
| + |
| + try |
| + { |
| + std::thread startInitObjectThread(StartInitObject, this); |
| + startInitObjectThread.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 create StartInitObject thread"); |
| + } |
| + } |
| + else |
| + { |
| + DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_SET_SITE, PLUGIN_ERROR_SET_SITE_ADVICE, "Class::SetSite - Advice"); |
| + } |
| + } |
| + } |
| + else // Check if loaded as toolbar handler |
| + { |
| + DEBUG_GENERAL("Loaded as toolbar handler"); |
| + CComPtr<IServiceProvider> pServiceProvider; |
| + |
| + HRESULT hr = unknownSite->QueryInterface(&pServiceProvider); |
| + if (SUCCEEDED(hr)) |
| + { |
| + if (pServiceProvider) |
| + { |
| + s_criticalSectionBrowser.Lock(); |
| + { |
| + HRESULT hr = pServiceProvider->QueryService(IID_IWebBrowserApp, &m_webBrowser2); |
| + if (SUCCEEDED(hr)) |
| + { |
| + if (m_webBrowser2) |
| + { |
| + InitObject(false); |
| + } |
| + } |
| + else |
| + { |
| + DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_SET_SITE, PLUGIN_ERROR_SET_SITE_QUERY_BROWSER, "Class::SetSite - QueryService (IID_IWebBrowserApp)"); |
| + } |
| + } |
| + s_criticalSectionBrowser.Unlock(); |
| + } |
| + } |
| + else |
| + { |
| + DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_SET_SITE, PLUGIN_ERROR_SET_SITE_QUERY_SERVICE_PROVIDER, "Class::SetSite - QueryInterface (service provider)"); |
| + } |
| + } |
| + } |
| + catch (const std::runtime_error& ex) |
| + { |
| + DEBUG_EXCEPTION(ex); |
| + Unadvice(); |
| + } |
| + } |
| + else |
| + { |
| + // Unadvice |
| + Unadvice(); |
| + |
| + // Destroy window |
| + if (m_pWndProcStatus) |
| + { |
| + ::SetWindowLongPtr(m_hStatusBarWnd, GWLP_WNDPROC, (LPARAM)(WNDPROC)m_pWndProcStatus); |
| + |
| + m_pWndProcStatus = NULL; |
| + } |
| + |
| + if (m_hPaneWnd) |
| + { |
| + DestroyWindow(m_hPaneWnd); |
| + m_hPaneWnd = NULL; |
| + } |
| + |
| + m_hTabWnd = NULL; |
| + m_hStatusBarWnd = NULL; |
| + |
| + // Remove instance from the list, shutdown threads |
| + HANDLE hMainThread = NULL; |
| + HANDLE hTabThread = NULL; |
| + |
| + s_criticalSectionLocal.Lock(); |
| + { |
| + s_instances.erase(this); |
| + |
| + std::map<DWORD,CPluginClass*>::iterator it = s_threadInstances.find(::GetCurrentThreadId()); |
| + if (it != s_threadInstances.end()) |
| + { |
| + s_threadInstances.erase(it); |
| + } |
| + if (s_instances.empty()) |
| + { |
| + // TODO: Explicitly releasing a resource when a container becomes empty looks like a job better suited for shared_ptr |
| + CPluginClientFactory::ReleaseMimeFilterClientInstance(); |
| + } |
| + } |
| + s_criticalSectionLocal.Unlock(); |
| + |
| + // Release browser interface |
| + s_criticalSectionBrowser.Lock(); |
| + { |
| + m_webBrowser2.Release(); |
| + } |
| + s_criticalSectionBrowser.Unlock(); |
| + |
| + DEBUG_GENERAL("================================================================================\nNEW TAB UI - END\n================================================================================") |
| + |
| + ::CoUninitialize(); |
| + } |
| + |
| + return IObjectWithSiteImpl<CPluginClass>::SetSite(unknownSite); |
| +} |
| + |
| +bool CPluginClass::IsStatusBarEnabled() |
| +{ |
| + DEBUG_GENERAL("IsStatusBarEnabled start"); |
| + HKEY pHkey; |
| + HKEY pHkeySub; |
| + RegOpenCurrentUser(KEY_QUERY_VALUE, &pHkey); |
| + DWORD truth = 1; |
| + DWORD truthSize = sizeof(truth); |
| + RegOpenKey(pHkey, L"Software\\Microsoft\\Internet Explorer\\Main", &pHkeySub); |
| + LONG res = RegQueryValueEx(pHkeySub, L"StatusBarWeb", NULL, NULL, (BYTE*)&truth, &truthSize); |
| + RegCloseKey(pHkey); |
| + if (res != ERROR_SUCCESS) |
| + { |
| + res = RegOpenKey(pHkey, L"Software\\Microsoft\\Internet Explorer\\MINIE", &pHkeySub); |
| + if (res == ERROR_SUCCESS) |
| + { |
| + LONG res = RegQueryValueEx(pHkeySub, L"ShowStatusBar", NULL, NULL, (BYTE*)&truth, &truthSize); |
| + if (res == ERROR_SUCCESS) |
| + { |
| + RegCloseKey(pHkey); |
| + } |
| + } |
| + } |
| + DEBUG_GENERAL("IsStatusBarEnabled end"); |
| + return truth == 1; |
| +} |
| + |
| +void CPluginClass::ShowStatusBar() |
| +{ |
| + DEBUG_GENERAL("ShowStatusBar start"); |
| + |
| + VARIANT_BOOL isVisible; |
| + |
| + |
| + CComQIPtr<IWebBrowser2> browser = GetAsyncBrowser(); |
| + if (browser) |
| + { |
| + HRESULT hr = S_OK; |
| + hr = browser->get_StatusBar(&isVisible); |
| + if (SUCCEEDED(hr)) |
| + { |
| + if (!isVisible) |
| + { |
| + SHANDLE_PTR pBrowserHWnd; |
| + browser->get_HWND((SHANDLE_PTR*)&pBrowserHWnd); |
| + Dictionary* dictionary = Dictionary::GetInstance(); |
| + |
| + HKEY pHkey; |
| + HKEY pHkeySub; |
| + LSTATUS regRes = 0; |
| + regRes = RegOpenCurrentUser(KEY_WRITE, &pHkey); |
| + |
| + // Do we have enough rights to enable a status bar? |
| + if (regRes != 0) |
| + { |
| + // We use the tab window here and in the next few calls, since the browser window may still not be available |
| + LRESULT res = MessageBox((HWND)m_hTabWnd, |
| + dictionary->Lookup("status-bar", "error-text").c_str(), |
| + dictionary->Lookup("status-bar", "error-title").c_str(), |
| + MB_OK); |
| + return; |
| + } |
| + // Ask if a user wants to enable a status bar automatically |
| + LRESULT res = MessageBox((HWND)m_hTabWnd, |
| + dictionary->Lookup("status-bar", "question").c_str(), |
| + dictionary->Lookup("status-bar", "title").c_str(), |
| + MB_YESNO); |
| + if (res == IDYES) |
| + { |
| + DWORD truth = 1; |
| + regRes = RegOpenKey(pHkey, L"Software\\Microsoft\\Internet Explorer\\MINIE", &pHkeySub); |
| + regRes = RegSetValueEx(pHkeySub, L"ShowStatusBar", 0, REG_DWORD, (BYTE*)&truth, sizeof(truth)); |
| + regRes = RegCloseKey(pHkeySub); |
| + regRes = RegOpenKey(pHkey, L"Software\\Microsoft\\Internet Explorer\\Main", &pHkeySub); |
| + regRes = RegSetValueEx(pHkeySub, L"StatusBarWeb", 0, REG_DWORD, (BYTE*)&truth, sizeof(truth)); |
| + regRes = RegCloseKey(pHkeySub); |
| + hr = browser->put_StatusBar(TRUE); |
| + if (FAILED(hr)) |
| + { |
| + DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_PUT_STATUSBAR, "Class::Enable statusbar"); |
| + } |
| + CreateStatusBarPane(); |
| + |
| + // We need to restart the tab now, to enable the status bar properly |
| + VARIANT vFlags; |
| + vFlags.vt = VT_I4; |
| + vFlags.intVal = navOpenInNewTab; |
| + |
| + CComBSTR curLoc; |
| + browser->get_LocationURL(&curLoc); |
| + HRESULT hr = browser->Navigate(curLoc, &vFlags, NULL, NULL, NULL); |
| + if (FAILED(hr)) |
| + { |
| + vFlags.intVal = navOpenInNewWindow; |
| + |
| + hr = browser->Navigate(CComBSTR(curLoc), &vFlags, NULL, NULL, NULL); |
| + if (FAILED(hr)) |
| + { |
| + DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_NAVIGATION, PLUGIN_ERROR_NAVIGATION, "Navigation::Failed") |
| + } |
| + } |
| + browser->Quit(); |
| + } |
| + } |
| + } |
| + else |
| + { |
| + DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_GET_STATUSBAR, "Class::Get statusbar state"); |
| + } |
| + } |
| + DEBUG_GENERAL("ShowStatusBar end"); |
| +} |
| + |
| +/* |
| + * #1163 This class is the implementation for method DISPID_BEFORENAVIGATE2 in CPluginClass::Invoke. |
| + * - It validates and convertes its own arguments, rather than unifying them in the Invoke body. |
| + * - It's declared void and not HRESULT, so DISPID_BEFORENAVIGATE2 can only return S_OK. |
| + */ |
| +void CPluginClass::BeforeNavigate2(DISPPARAMS* pDispParams) |
| +{ |
| + |
| + if (pDispParams->cArgs < 7) |
| + { |
| + return; |
| + } |
| + //Register a mime filter if it's not registered yet |
| + if (s_mimeFilter == NULL) |
| + { |
| + s_mimeFilter = CPluginClientFactory::GetMimeFilterClientInstance(); |
| + } |
| + |
| + // Get the IWebBrowser2 interface |
| + CComQIPtr<IWebBrowser2, &IID_IWebBrowser2> WebBrowser2Ptr; |
| + VARTYPE vt = pDispParams->rgvarg[6].vt; |
| + if (vt == VT_DISPATCH) |
| + { |
| + WebBrowser2Ptr = pDispParams->rgvarg[6].pdispVal; |
| + } |
| + else |
| + { |
| + // Wrong type, return. |
| + return; |
| + } |
| + |
| + // Get the URL |
| + std::wstring url; |
| + const auto& arg = pDispParams->rgvarg[5]; |
| + vt = arg.vt; |
| + if (vt == (VT_BYREF | VT_VARIANT) && arg.pvarVal->vt == VT_BSTR) |
| + { |
| + BSTR b = arg.pvarVal->bstrVal; |
| + if (b) { |
| + url = std::wstring(b, SysStringLen(b)); |
| + UnescapeUrl(url); |
| + } |
| + } |
| + else |
| + { |
| + // Wrong type, return. |
| + return; |
| + } |
| + |
| + // If webbrowser2 is equal to top level browser (as set in SetSite), we are navigating new page |
| + CPluginClient* client = CPluginClient::GetInstance(); |
| + CString urlLegacy = ToCString(url); |
| + if (urlLegacy.Find(L"javascript") == 0) |
| + { |
| + } |
| + else if (GetBrowser().IsEqualObject(WebBrowser2Ptr)) |
| + { |
| + m_tab->OnNavigate(url); |
| + |
| + DEBUG_GENERAL( |
| + L"================================================================================\n" |
| + L"Begin main navigation url:" + url + L"\n" |
| + L"================================================================================") |
| + |
| +#ifdef ENABLE_DEBUG_RESULT |
| + CPluginDebug::DebugResultDomain(url); |
| +#endif |
| + |
| + UpdateStatusBar(); |
| + } |
| + else |
| + { |
| + DEBUG_NAVI(L"Navi::Begin navigation url:" + url) |
| + m_tab->CacheFrame(url); |
| + } |
| +} |
| + |
| +/* |
| + * #1163 implements behavior for method DISPID_WINDOWSTATECHANGED in CPluginClass::Invoke |
| + * - should validate and convert arguments in Invoke, not here |
| + * - does not validate number of arguments before indexing into 'rgvarg' |
| + * - does not validate type of argument before using its value |
| + */ |
| +STDMETHODIMP CPluginClass::OnTabChanged(DISPPARAMS* pDispParams, WORD wFlags) |
| +{ |
| + DEBUG_GENERAL("Tab changed"); |
| + bool newtabshown = pDispParams->rgvarg[1].intVal==3; |
| + if (newtabshown) |
| + { |
| + std::map<DWORD,CPluginClass*>::const_iterator it = s_threadInstances.find(GetCurrentThreadId()); |
| + if (it == s_threadInstances.end()) |
| + { |
| + s_threadInstances[::GetCurrentThreadId()] = this; |
| + if (!m_isInitializedOk) |
| + { |
| + m_isInitializedOk = true; |
| + InitObject(true); |
| + UpdateStatusBar(); |
| + } |
| + } |
| + } |
| + notificationMessage.Hide(); |
| + DEBUG_GENERAL("Tab change end"); |
| + return S_OK; |
| +} |
| + |
| +// This gets called whenever there's a browser event |
| +// ENTRY POINT |
| +STDMETHODIMP CPluginClass::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pvarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) |
| +{ |
| + try |
| + { |
| + WCHAR tmp[256]; |
| + wsprintf(tmp, L"Invoke: %d\n", dispidMember); |
| + DEBUG_GENERAL(tmp); |
| + switch (dispidMember) |
| + { |
| + case DISPID_WINDOWSTATECHANGED: |
| + { |
| + // #1163 should validate and convert arguments here |
| + return OnTabChanged(pDispParams, wFlags); |
| + } |
| + |
| + case DISPID_HTMLDOCUMENTEVENTS2_ONBEFOREUPDATE: |
| + break; |
| + |
| + case DISPID_HTMLDOCUMENTEVENTS2_ONCLICK: |
| + break; |
| + |
| + case DISPID_EVMETH_ONLOAD: |
| + DEBUG_NAVI("Navi::OnLoad") |
| + break; |
| + |
| + case DISPID_EVMETH_ONCHANGE: |
| + break; |
| + |
| + case DISPID_EVMETH_ONMOUSEDOWN: |
| + break; |
| + |
| + case DISPID_EVMETH_ONMOUSEENTER: |
| + break; |
| + |
| + case DISPID_IHTMLIMGELEMENT_START: |
| + break; |
| + |
| + case STDDISPID_XOBJ_ERRORUPDATE: |
| + break; |
| + |
| + case STDDISPID_XOBJ_ONPROPERTYCHANGE: |
| + break; |
| + |
| + case DISPID_READYSTATECHANGE: |
| + DEBUG_NAVI("Navi::ReadyStateChange"); |
| + break; |
| + |
| + case DISPID_BEFORENAVIGATE: |
| + DEBUG_NAVI("Navi::BeforeNavigate"); |
| + break; |
| + |
| + case DISPID_COMMANDSTATECHANGE: |
| + if (m_hPaneWnd == NULL) |
| + { |
| + CreateStatusBarPane(); |
| + } |
| + else |
| + { |
| + if (AdblockPlus::IE::InstalledMajorVersion() > 6) |
| + { |
| + RECT rect; |
| + //Get the RECT for the leftmost pane (the status text pane) |
| + BOOL rectRes = ::SendMessage(m_hStatusBarWnd, SB_GETRECT, 0, (LPARAM)&rect); |
| + if (rectRes == TRUE) |
| + { |
| + MoveWindow(m_hPaneWnd, rect.right - m_nPaneWidth, 0, m_nPaneWidth, rect.bottom - rect.top, TRUE); |
| + } |
| + } |
| + } |
| + break; |
| + |
| + case DISPID_STATUSTEXTCHANGE: |
| + break; |
| + |
| + case DISPID_BEFORENAVIGATE2: |
| + { |
| + // #1163 should validate and convert parameters here |
| + BeforeNavigate2(pDispParams); |
| + } |
| + break; |
| + |
| + case DISPID_DOWNLOADBEGIN: |
| + { |
| + DEBUG_NAVI("Navi::Download Begin") |
| + } |
| + break; |
| + |
| + case DISPID_DOWNLOADCOMPLETE: |
| + { |
| + DEBUG_NAVI("Navi::Download Complete"); |
| + CComQIPtr<IWebBrowser2> browser = GetBrowser(); |
| + if (browser) |
| + { |
| + m_tab->OnDownloadComplete(browser); |
| + } |
| + } |
| + break; |
| + |
| + case DISPID_DOCUMENTCOMPLETE: |
| + { |
| + DEBUG_NAVI("Navi::Document Complete"); |
| + CComQIPtr<IWebBrowser2> browser = GetBrowser(); |
| + if (browser && pDispParams->cArgs >= 2 && pDispParams->rgvarg[1].vt == VT_DISPATCH) |
| + { |
| + CComQIPtr<IWebBrowser2> pBrowser = pDispParams->rgvarg[1].pdispVal; |
| + if (pBrowser) |
| + { |
| + CComBSTR bstrUrl; |
| + if (SUCCEEDED(pBrowser->get_LocationURL(&bstrUrl)) && bstrUrl && ::SysStringLen(bstrUrl) > 0) |
| + { |
| + std::wstring url = std::wstring(bstrUrl, SysStringLen(bstrUrl)); |
| + UnescapeUrl(url); |
| + m_tab->OnDocumentComplete(browser, url, browser.IsEqualObject(pBrowser)); |
| + } |
| + } |
| + } |
| + } |
| + break; |
| + |
| + case DISPID_ONQUIT: |
| + case DISPID_QUIT: |
| + { |
| + Unadvice(); |
| + } |
| + break; |
| + |
| + default: |
| + { |
| + CString did; |
| + did.Format(L"DispId:%u", dispidMember); |
| + |
| + DEBUG_NAVI(L"Navi::Default " + did) |
| + } |
| + /* |
| + * Ordinarily a method not dispatched should return DISP_E_MEMBERNOTFOUND. |
| + * As a conservative initial change, we leave it behaving as before, |
| + * which is to do nothing and return S_OK. |
| + */ |
| + // do nothing |
| + break; |
| + } |
| + } |
| + catch (...) |
| + { |
| + EntryPointExceptionDefault("CPluginClass::Invoke"); |
| + return E_FAIL; |
| + } |
| + return S_OK; |
| +} |
| + |
| +bool CPluginClass::InitObject(bool bBHO) |
| +{ |
| + DEBUG_GENERAL("InitObject"); |
| + CPluginSettings* settings = CPluginSettings::GetInstance(); |
| + |
| + if (!settings->GetPluginEnabled()) |
| + { |
| + s_mimeFilter->Unregister(); |
| + } |
| + |
| + // Load theme module |
| + s_criticalSectionLocal.Lock(); |
| + { |
| + if (!s_hUxtheme) |
| + { |
| + s_hUxtheme = ::GetModuleHandle(L"uxtheme.dll"); |
| + if (s_hUxtheme) |
| + { |
| + pfnClose = (CLOSETHEMEDATA)::GetProcAddress(s_hUxtheme, "CloseThemeData"); |
| + if (!pfnClose) |
| + { |
| + DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_GET_UXTHEME_CLOSE, "Class::InitObject - GetProcAddress(CloseThemeData)"); |
| + } |
| + |
| + pfnDrawThemeBackground = (DRAWTHEMEBACKGROUND)::GetProcAddress(s_hUxtheme, "DrawThemeBackground"); |
| + if (!pfnDrawThemeBackground) |
| + { |
| + DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_GET_UXTHEME_DRAW_BACKGROUND, "Class::InitObject - GetProcAddress(DrawThemeBackground)"); |
| + } |
| + |
| + pfnOpenThemeData = (OPENTHEMEDATA)::GetProcAddress(s_hUxtheme, "OpenThemeData"); |
| + if (!pfnOpenThemeData) |
| + { |
| + DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_GET_UXTHEME_OPEN, "Class::InitObject - GetProcAddress(pfnOpenThemeData)"); |
| + } |
| + } |
| + else |
| + { |
| + DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_GET_UXTHEME, "Class::InitObject - GetModuleHandle(uxtheme.dll)"); |
| + } |
| + } |
| + } |
| + s_criticalSectionLocal.Unlock(); |
| + |
| + // Register pane class |
| + if (!GetAtomPaneClass()) |
| + { |
| + WNDCLASSEX wcex; |
| + |
| + wcex.cbSize = sizeof(wcex); |
| + wcex.style = 0; |
| + wcex.lpfnWndProc = (WNDPROC)PaneWindowProc; |
| + wcex.cbClsExtra = 0; |
| + wcex.cbWndExtra = 0; |
| + wcex.hInstance = _Module.m_hInst; |
| + wcex.hIcon = NULL; |
| + wcex.hCursor = NULL; |
| + wcex.hbrBackground = NULL; |
| + wcex.lpszMenuName = NULL; |
| + wcex.lpszClassName = STATUSBAR_PANE_NAME; |
| + wcex.hIconSm = NULL; |
| + |
| + s_criticalSectionLocal.Lock(); |
| + { |
| + s_atomPaneClass = ::RegisterClassEx(&wcex); |
| + } |
| + s_criticalSectionLocal.Unlock(); |
| + |
| + if (!GetAtomPaneClass()) |
| + { |
| + DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_REGISTER_PANE_CLASS, "Class::InitObject - RegisterClassEx"); |
| + return false; |
| + } |
| + } |
| + |
| + int ieVersion = AdblockPlus::IE::InstalledMajorVersion(); |
| + // Create status pane |
| + if (bBHO && ieVersion > 6 && !CreateStatusBarPane()) |
| + { |
| + return false; |
| + } |
| + |
| + s_criticalSectionLocal.Lock(); |
| + int versionCompRes = CPluginClient::GetInstance()->CompareVersions(CPluginClient::GetInstance()->GetPref(L"currentVersion", L"0.0"), L"1.2"); |
| + |
| + bool isFirstRun = CPluginClient::GetInstance()->IsFirstRun(); |
| + CPluginClient::GetInstance()->SetPref(L"currentVersion", std::wstring(IEPLUGIN_VERSION)); |
| + // This is the first time ABP was installed |
| + // Or ABP was updated from the version that did not support Acceptable Ads (<1.2) |
| + if (isFirstRun || versionCompRes < 0) |
| + { |
| + if (!isFirstRun) |
| + { |
| + CPluginClient::GetInstance()->SetPref(L"displayUpdatePage", true); |
| + } |
| + |
| + // IE6 can't be accessed from another thread, execute in current thread |
| + if (ieVersion < 7) |
| + { |
| + FirstRunThread(); |
| + } |
| + else |
| + { |
| + CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)CPluginClass::FirstRunThread, NULL, NULL, NULL); |
| + } |
| + if (((m_hPaneWnd == NULL) || !IsStatusBarEnabled()) && isFirstRun) |
| + { |
| + ShowStatusBar(); |
| + } |
| + |
| + // Enable acceptable ads by default |
| + std::wstring aaUrl = CPluginClient::GetInstance()->GetPref(L"subscriptions_exceptionsurl", L""); |
| + CPluginClient::GetInstance()->AddSubscription(aaUrl); |
| + } |
| + s_criticalSectionLocal.Unlock(); |
| + return true; |
| +} |
| + |
| +bool CPluginClass::CreateStatusBarPane() |
| +{ |
| + CriticalSection::Lock lock(m_csStatusBar); |
| + |
| + CPluginClient* client = CPluginClient::GetInstance(); |
| + |
| + std::array<wchar_t, MAX_PATH> className; |
| + // Get browser window and url |
| + HWND hBrowserWnd = GetBrowserHWND(); |
| + if (!hBrowserWnd) |
| + { |
| + DEBUG_ERROR_LOG(0, PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_NO_STATUSBAR_BROWSER, "Class::CreateStatusBarPane - No status bar") |
| + return false; |
| + } |
| + |
| + // Looking for a TabWindowClass window in IE7 |
| + // the last one should be parent for statusbar |
| + HWND hWndStatusBar = NULL; |
| + |
| + HWND hTabWnd = ::GetWindow(hBrowserWnd, GW_CHILD); |
| + UINT amoundOfNewTabs = 0; |
| + HWND uniqueNewTab = NULL; |
| + while (hTabWnd) |
| + { |
| + className[0] = L'\0'; |
| + // GetClassNameW returns the number of characters without '\0' |
| + int classNameLength = GetClassNameW(hTabWnd, className.data(), className.size()); |
| + |
| + if (classNameLength && (wcscmp(className.data(), L"TabWindowClass") == 0 || wcscmp(className.data(), L"Frame Tab") == 0)) |
| + { |
| + // IE8 support |
| + HWND hTabWnd2 = hTabWnd; |
| + if (wcscmp(className.data(), L"Frame Tab") == 0) |
| + { |
| + hTabWnd2 = ::FindWindowEx(hTabWnd2, NULL, L"TabWindowClass", NULL); |
| + } |
| + |
| + if (hTabWnd2) |
| + { |
| + DWORD nProcessId; |
| + ::GetWindowThreadProcessId(hTabWnd2, &nProcessId); |
| + if (::GetCurrentProcessId() == nProcessId) |
| + { |
| + bool bExistingTab = false; |
| + |
| + s_criticalSectionLocal.Lock(); |
| + { |
| + for (auto instance : s_instances) |
| + { |
| + if (instance->m_hTabWnd == hTabWnd2) |
| + { |
| + bExistingTab = true; |
| + break; |
| + } |
| + } |
| + } |
| + s_criticalSectionLocal.Unlock(); |
| + |
| + if (!bExistingTab) |
| + { |
| + amoundOfNewTabs ++; |
| + uniqueNewTab = hTabWnd2; |
| + if (GetCurrentThreadId() == GetWindowThreadProcessId(hTabWnd2, NULL)) |
| + { |
| + hBrowserWnd = hTabWnd = hTabWnd2; |
| + break; |
| + } |
| + |
| + } |
| + } |
| + } |
| + } |
| + |
| + hTabWnd = ::GetWindow(hTabWnd, GW_HWNDNEXT); |
| + } |
| + |
| + HWND hWnd = ::GetWindow(hBrowserWnd, GW_CHILD); |
| + while (hWnd) |
| + { |
| + className[0] = L'\0'; |
| + int classNameLength = GetClassNameW(hWnd, className.data(), className.size()); |
| + |
| + if (classNameLength && wcscmp(className.data(), L"msctls_statusbar32") == 0) |
| + { |
| + hWndStatusBar = hWnd; |
| + break; |
| + } |
| + |
| + hWnd = ::GetWindow(hWnd, GW_HWNDNEXT); |
| + } |
| + |
| + if (!hWndStatusBar) |
| + { |
| + DEBUG_ERROR_LOG(0, PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_NO_STATUSBAR_WIN, "Class::CreateStatusBarPane - No status bar") |
| + return true; |
| + } |
| + |
| + // Calculate pane height |
| + AdblockPlus::Rectangle rcStatusBar; |
| + ::GetClientRect(hWndStatusBar, &rcStatusBar); |
| + |
| + if (rcStatusBar.Height() > 0) |
| + { |
| + if (rcStatusBar.Height() < iconWidth) |
| + { |
| + iconWidth = 19; |
| + iconHeight = 19; |
| + } |
| + |
| +#ifdef _DEBUG |
| + m_nPaneWidth = 70; |
| +#else |
| + m_nPaneWidth = min(rcStatusBar.Height(), iconWidth); |
| +#endif |
| + } |
| + else |
| + { |
| +#ifdef _DEBUG |
| + m_nPaneWidth = 70; |
| +#else |
| + m_nPaneWidth = iconWidth; |
| +#endif |
| + } |
| + // Create pane window |
| + HWND hWndNewPane = ::CreateWindowEx( |
| + NULL, |
| + MAKEINTATOM(GetAtomPaneClass()), |
| + L"", |
| + WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, |
| + rcStatusBar.Width() - 500, 0, m_nPaneWidth, rcStatusBar.Height(), |
| + hWndStatusBar, |
| + (HMENU)3671, |
| + _Module.m_hInst, |
| + NULL); |
| + |
| + if (!hWndNewPane) |
| + { |
| + DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_CREATE_STATUSBAR_PANE, "Class::CreateStatusBarPane - CreateWindowEx") |
| + return false; |
| + } |
| + |
| + DEBUG_GENERAL("ABP window created"); |
| + m_hTabWnd = hTabWnd; |
| + m_hStatusBarWnd = hWndStatusBar; |
| + m_hPaneWnd = hWndNewPane; |
| + |
| + UpdateTheme(); |
| + |
| + // Subclass status bar |
| + m_pWndProcStatus = (WNDPROC)SetWindowLongPtr(hWndStatusBar, GWLP_WNDPROC, (LPARAM)(WNDPROC)NewStatusProc); |
| + |
| + // Adjust pane |
| + LRESULT nPartCount = ::SendMessage(m_hStatusBarWnd, SB_GETPARTS, 0, 0); |
| + |
| + if (nPartCount > 1) |
| + { |
| + INT *pData = new INT[nPartCount]; |
| + |
| + ::SendMessage(m_hStatusBarWnd, SB_GETPARTS, nPartCount, (LPARAM)pData); |
| + ::SendMessage(m_hStatusBarWnd, SB_SETPARTS, nPartCount, (LPARAM)pData); |
| + |
| + delete []pData; |
| + } |
| + |
| + HDC hdc = GetWindowDC(m_hStatusBarWnd); |
| + SendMessage(m_hStatusBarWnd, WM_PAINT, (WPARAM)hdc, 0); |
| + ReleaseDC(m_hStatusBarWnd, hdc); |
| + |
| + return true; |
| +} |
| + |
| +void CPluginClass::FirstRunThread() |
| +{ |
| + CoInitialize(NULL); |
| + VARIANT vFlags; |
| + vFlags.vt = VT_I4; |
| + vFlags.intVal = navOpenInNewTab; |
| + |
| + CComBSTR navigatePath = CComBSTR(FirstRunPageFileUrl().c_str()); |
| + |
| + HRESULT hr = GetAsyncBrowser()->Navigate(navigatePath, &vFlags, NULL, NULL, NULL); |
| + if (FAILED(hr)) |
| + { |
| + vFlags.intVal = navOpenInNewWindow; |
| + hr = GetAsyncBrowser()->Navigate(navigatePath, &vFlags, NULL, NULL, NULL); |
| + } |
| + |
| + if (FAILED(hr)) |
| + { |
| + DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_NAVIGATION, PLUGIN_ERROR_NAVIGATION_WELCOME, "Navigation::Welcome page failed") |
| + } |
| +} |
| +void CPluginClass::CloseTheme() |
| +{ |
| + if (m_hTheme) |
| + { |
| + if (pfnClose) |
| + { |
| + pfnClose(m_hTheme); |
| + } |
| + |
| + m_hTheme = NULL; |
| + } |
| +} |
| + |
| +void CPluginClass::UpdateTheme() |
| +{ |
| + CloseTheme(); |
| + |
| + if (pfnOpenThemeData) |
| + { |
| + m_hTheme = pfnOpenThemeData(m_hPaneWnd, L"STATUS"); |
| + if (!m_hTheme) |
| + { |
| + } |
| + } |
| +} |
| + |
| + |
| +CPluginClass* CPluginClass::FindInstance(HWND hStatusBarWnd) |
| +{ |
| + CPluginClass* result = nullptr; |
| + |
| + s_criticalSectionLocal.Lock(); |
| + { |
| + for (auto instance : s_instances) |
| + { |
| + if (instance->m_hStatusBarWnd == hStatusBarWnd) |
| + { |
| + result = instance; |
| + break; |
| + } |
| + } |
| + } |
| + s_criticalSectionLocal.Unlock(); |
| + |
| + return result; |
| +} |
| + |
| +CPluginTab* CPluginClass::GetTab() |
| +{ |
| + return m_tab; |
| +} |
| + |
| +CPluginTab* CPluginClass::GetTab(DWORD dwThreadId) |
| +{ |
| + CPluginTab* tab = NULL; |
| + |
| + s_criticalSectionLocal.Lock(); |
| + { |
| + std::map<DWORD,CPluginClass*>::const_iterator it = s_threadInstances.find(dwThreadId); |
| + if (it != s_threadInstances.end()) |
| + { |
| + tab = it->second->m_tab; |
| + } |
| + } |
| + s_criticalSectionLocal.Unlock(); |
| + |
| + return tab; |
| +} |
| + |
| + |
| +STDMETHODIMP CPluginClass::QueryStatus(const GUID* pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT* pCmdText) |
| +{ |
| + if (cCmds == 0) return E_INVALIDARG; |
| + if (prgCmds == 0) return E_POINTER; |
| + |
| + prgCmds[0].cmdf = OLECMDF_ENABLED; |
| + |
| + return S_OK; |
| +} |
| + |
| +HMENU CPluginClass::CreatePluginMenu(const std::wstring& url) |
| +{ |
| + DEBUG_GENERAL("CreatePluginMenu"); |
| + HINSTANCE hInstance = _AtlBaseModule.GetModuleInstance(); |
| + |
| + HMENU hMenu = ::LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MENU1)); |
| + |
| + HMENU hMenuTrackPopup = GetSubMenu(hMenu, 0); |
| + |
| + SetMenuBar(hMenuTrackPopup, url); |
| + |
| + return hMenuTrackPopup; |
| +} |
| + |
| +void CPluginClass::DisplayPluginMenu(HMENU hMenu, int nToolbarCmdID, POINT pt, UINT nMenuFlags) |
| +{ |
| + CPluginClient* client = CPluginClient::GetInstance(); |
| + |
| + // Create menu parent window |
| + HWND hMenuWnd = ::CreateWindowEx( |
| + NULL, |
| + MAKEINTATOM(GetAtomPaneClass()), |
| + L"", |
| + 0, |
| + 0,0,0,0, |
| + NULL, |
| + NULL, |
| + _Module.m_hInst, |
| + NULL); |
| + |
| + if (!hMenuWnd) |
| + { |
| + DestroyMenu(hMenu); |
| + return; |
| + } |
| + |
| + // Display menu |
| + nMenuFlags |= TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTBUTTON; |
| + |
| + int nCommand = ::TrackPopupMenu(hMenu, nMenuFlags, pt.x, pt.y, 0, hMenuWnd, 0); |
| + |
| + ::DestroyMenu(hMenu); |
| + ::DestroyWindow(hMenuWnd); |
| + |
| + switch (nCommand) |
| + { |
| + case ID_MENU_UPDATE: |
| + { |
| + CPluginClient* client = CPluginClient::GetInstance(); |
| + notificationMessage.SetParent(m_hPaneWnd); |
| + Dictionary* dictionary = Dictionary::GetInstance(); |
| + std::wstring checkingText = dictionary->Lookup("updater", "checking-for-updates-text"); |
| + std::wstring checkingTitle = dictionary->Lookup("updater", "checking-for-updates-title"); |
| + notificationMessage.Show(checkingText, checkingTitle, TTI_INFO); |
| + client->CheckForUpdates(m_hPaneWnd); |
| + } |
| + break; |
| + case ID_MENU_DISABLE: |
| + { |
| + CPluginSettings* settings = CPluginSettings::GetInstance(); |
| + |
| + settings->TogglePluginEnabled(); |
| + |
| + // Enable / disable mime filter |
| + s_criticalSectionLocal.Lock(); |
| + { |
| + if (settings->GetPluginEnabled()) |
| + { |
| + s_mimeFilter = CPluginClientFactory::GetMimeFilterClientInstance(); |
| + } |
| + else |
| + { |
| + s_mimeFilter = NULL; |
| + |
| + CPluginClientFactory::ReleaseMimeFilterClientInstance(); |
| + } |
| + } |
| + s_criticalSectionLocal.Unlock(); |
| + } |
| + break; |
| + case ID_MENU_SETTINGS: |
| + { |
| + CComQIPtr<IWebBrowser2> browser = GetAsyncBrowser(); |
| + if (browser) |
| + { |
| + VARIANT vFlags; |
| + vFlags.vt = VT_I4; |
| + vFlags.intVal = navOpenInNewTab; |
| + |
| + auto userSettingsFileUrl = UserSettingsFileUrl(); |
| + ATL::CComBSTR urlToNavigate(static_cast<int>(userSettingsFileUrl.length()), userSettingsFileUrl.c_str()); |
| + HRESULT hr = browser->Navigate(urlToNavigate, &vFlags, NULL, NULL, NULL); |
| + if (FAILED(hr)) |
| + { |
| + vFlags.intVal = navOpenInNewWindow; |
| + |
| + hr = browser->Navigate(urlToNavigate, &vFlags, NULL, NULL, NULL); |
| + if (FAILED(hr)) |
| + { |
| + DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_NAVIGATION, PLUGIN_ERROR_NAVIGATION_SETTINGS, "Navigation::Failed") |
| + } |
| + } |
| + } |
| + break; |
| + } |
| + case ID_MENU_DISABLE_ON_SITE: |
| + { |
| + CPluginSettings* settings = CPluginSettings::GetInstance(); |
| + std::wstring urlString = GetTab()->GetDocumentUrl(); |
| + if (client->IsWhitelistedUrl(urlString)) |
| + { |
| + settings->RemoveWhiteListedDomain(ToCString(client->GetHostFromUrl(urlString))); |
| + } |
| + else |
| + { |
| + settings->AddWhiteListedDomain(ToCString(client->GetHostFromUrl(urlString))); |
| + } |
| + GetBrowser()->Refresh(); |
| + } |
| + default: |
| + break; |
| + } |
| + |
| + // Invalidate and redraw the control |
| + UpdateStatusBar(); |
| +} |
| + |
| + |
| +bool CPluginClass::SetMenuBar(HMENU hMenu, const std::wstring& url) |
| +{ |
| + DEBUG_GENERAL("SetMenuBar"); |
| + |
| + std::wstring ctext; |
| + Dictionary* dictionary = Dictionary::GetInstance(); |
| + |
| + MENUITEMINFOW fmii = {}; |
| + fmii.cbSize = sizeof(fmii); |
| + |
| + MENUITEMINFOW miiSep = {}; |
| + miiSep.cbSize = sizeof(miiSep); |
| + miiSep.fMask = MIIM_TYPE | MIIM_FTYPE; |
| + miiSep.fType = MFT_SEPARATOR; |
| + |
| + CPluginClient* client = CPluginClient::GetInstance(); |
| + CPluginSettings* settings = CPluginSettings::GetInstance(); |
| + { |
| + ctext = dictionary->Lookup("menu", "menu-disable-on-site"); |
| + // Is domain in white list? |
| + ReplaceString(ctext, L"?1?", client->GetHostFromUrl(url)); |
| + if (client->IsWhitelistedUrl(GetTab()->GetDocumentUrl())) |
| + { |
| + fmii.fState = MFS_CHECKED | MFS_ENABLED; |
| + } |
| + else |
| + { |
| + fmii.fState = MFS_UNCHECKED | MFS_ENABLED; |
| + } |
| + fmii.fMask = MIIM_STRING | MIIM_STATE; |
| + fmii.dwTypeData = const_cast<LPWSTR>(ctext.c_str()); |
| + fmii.cch = static_cast<UINT>(ctext.size()); |
| + |
| + ::SetMenuItemInfoW(hMenu, ID_MENU_DISABLE_ON_SITE, FALSE, &fmii); |
| + } |
| + |
| + // Plugin update |
| + ctext = dictionary->Lookup("menu", "menu-update"); |
| + fmii.fMask = MIIM_STATE | MIIM_STRING; |
| + fmii.fState = client ? MFS_ENABLED : MFS_DISABLED; |
| + fmii.dwTypeData = const_cast<LPWSTR>(ctext.c_str()); |
| + fmii.cch = static_cast<UINT>(ctext.size()); |
| + ::SetMenuItemInfoW(hMenu, ID_MENU_UPDATE, FALSE, &fmii); |
| + |
| + |
| + // Plugin enable |
| + ctext = dictionary->Lookup("menu", "menu-disable"); |
| + if (settings->GetPluginEnabled()) |
| + { |
| + fmii.fState = MFS_UNCHECKED | MFS_ENABLED; |
| + } |
| + else |
| + { |
| + fmii.fState = MFS_CHECKED | MFS_ENABLED; |
| + } |
| + fmii.fMask = MIIM_STATE | MIIM_STRING; |
| + fmii.dwTypeData = const_cast<LPWSTR>(ctext.c_str()); |
| + fmii.cch = static_cast<UINT>(ctext.size()); |
| + ::SetMenuItemInfoW(hMenu, ID_MENU_DISABLE, FALSE, &fmii); |
| + |
| + // Settings |
| + ctext = dictionary->Lookup("menu", "menu-settings"); |
| + fmii.fMask = MIIM_STATE | MIIM_STRING; |
| + fmii.fState = MFS_ENABLED; |
| + fmii.dwTypeData = const_cast<LPWSTR>(ctext.c_str()); |
| + fmii.cch = static_cast<UINT>(ctext.size()); |
| + ::SetMenuItemInfoW(hMenu, ID_MENU_SETTINGS, FALSE, &fmii); |
| + |
| + return true; |
| +} |
| + |
| + |
| +STDMETHODIMP CPluginClass::Exec(const GUID*, DWORD nCmdID, DWORD, VARIANTARG*, VARIANTARG*) |
| +{ |
| + HWND hBrowserWnd = GetBrowserHWND(); |
| + if (!hBrowserWnd) |
| + { |
| + return E_FAIL; |
| + } |
| + |
| + // Create menu |
| + HMENU hMenu = CreatePluginMenu(m_tab->GetDocumentUrl()); |
| + if (!hMenu) |
| + { |
| + return E_FAIL; |
| + } |
| + |
| + // Check if button in toolbar was pressed |
| + int nIDCommand = -1; |
| + BOOL bRightAlign = FALSE; |
| + |
| + POINT pt; |
| + GetCursorPos(&pt); |
| + |
| + HWND hWndToolBar = ::WindowFromPoint(pt); |
| + |
| + DWORD nProcessId; |
| + ::GetWindowThreadProcessId(hWndToolBar, &nProcessId); |
| + |
| + if (hWndToolBar && ::GetCurrentProcessId() == nProcessId) |
| + { |
| + ::ScreenToClient(hWndToolBar, &pt); |
| + int nButton = (int)::SendMessage(hWndToolBar, TB_HITTEST, 0, (LPARAM)&pt); |
| + |
| + if (nButton > 0) |
| + { |
| + TBBUTTON pTBBtn = {}; |
| + |
| + if (SendMessage(hWndToolBar, TB_GETBUTTON, nButton, (LPARAM)&pTBBtn)) |
| + { |
| + RECT rcButton; |
| + nIDCommand = pTBBtn.idCommand; |
| + |
| + if (SendMessage(hWndToolBar, TB_GETRECT, nIDCommand, (LPARAM)&rcButton)) |
| + { |
| + pt.x = rcButton.left; |
| + pt.y = rcButton.bottom; |
| + ClientToScreen(hWndToolBar, &pt); |
| + |
| + RECT rcWorkArea; |
| + SystemParametersInfo(SPI_GETWORKAREA, 0, (LPVOID)&rcWorkArea, 0); |
| + if (rcWorkArea.right - pt.x < 150) |
| + { |
| + bRightAlign = TRUE; |
| + pt.x = rcButton.right; |
| + pt.y = rcButton.bottom; |
| + ClientToScreen(hWndToolBar, &pt); |
| + } |
| + } |
| + } |
| + } |
| + else |
| + { |
| + GetCursorPos(&pt); |
| + } |
| + } |
| + |
| + // Display menu |
| + UINT nFlags = 0; |
| + if (bRightAlign) |
| + { |
| + nFlags |= TPM_RIGHTALIGN; |
| + } |
| + else |
| + { |
| + nFlags |= TPM_LEFTALIGN; |
| + } |
| + |
| + DisplayPluginMenu(hMenu, nIDCommand, pt, nFlags); |
| + |
| + return S_OK; |
| +} |
| + |
| +///////////////////////////////////////////////////////////////////////////// |
| +// Window procedures |
| + |
| +LRESULT CALLBACK CPluginClass::NewStatusProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) |
| +{ |
| + // Find tab |
| + CPluginClass *pClass = FindInstance(hWnd); |
| + if (!pClass) |
| + { |
| + return DefWindowProc(hWnd, message, wParam, lParam); |
| + } |
| + |
| + // Process message |
| + switch (message) |
| + { |
| + case SB_SIMPLE: |
| + { |
| + ShowWindow(pClass->m_hPaneWnd, !wParam); |
| + break; |
| + } |
| + |
| + case WM_SYSCOLORCHANGE: |
| + { |
| + pClass->UpdateTheme(); |
| + break; |
| + } |
| + |
| + case SB_SETPARTS: |
| + { |
| + if (!lParam || !wParam || wParam > 30 || !IsWindow(pClass->m_hPaneWnd)) |
| + { |
| + return CallWindowProc(pClass->m_pWndProcStatus, hWnd, message, wParam, lParam); |
| + } |
| + |
| + WPARAM nParts = wParam; |
| + if (STATUSBAR_PANE_NUMBER >= nParts) |
| + { |
| + return CallWindowProc(pClass->m_pWndProcStatus, hWnd, message, wParam, lParam); |
| + } |
| + |
| + HLOCAL hLocal = LocalAlloc(LHND, sizeof(int) * (nParts+1)); |
| + LPINT lpParts = (LPINT)LocalLock(hLocal); |
| + memcpy(lpParts, (void*)lParam, wParam*sizeof(int)); |
| + |
| + for (unsigned i = 0; i < STATUSBAR_PANE_NUMBER; i++) |
| + { |
| + lpParts[i] -= pClass->m_nPaneWidth; |
| + } |
| + LRESULT hRet = CallWindowProc(pClass->m_pWndProcStatus, hWnd, message, wParam, (LPARAM)lpParts); |
| + |
| + AdblockPlus::Rectangle rcPane; |
| + ::SendMessage(hWnd, SB_GETRECT, STATUSBAR_PANE_NUMBER, (LPARAM)&rcPane); |
| + |
| + AdblockPlus::Rectangle rcClient; |
| + ::GetClientRect(hWnd, &rcClient); |
| + |
| + ::MoveWindow( |
| + pClass->m_hPaneWnd, |
| + lpParts[STATUSBAR_PANE_NUMBER] - pClass->m_nPaneWidth, |
| + 0, |
| + pClass->m_nPaneWidth, |
| + rcClient.Height(), |
| + TRUE); |
| + |
| + ::LocalFree(hLocal); |
| + |
| + |
| + return hRet; |
| + } |
| + |
| + default: |
| + break; |
| + } |
| + |
| + LRESULT result = CallWindowProc(pClass->m_pWndProcStatus, hWnd, message, wParam, lParam); |
| + |
| + |
| + return result; |
| + |
| +} |
| + |
| + |
| +HICON CPluginClass::GetStatusBarIcon(const std::wstring& url) |
| +{ |
| + // use the disable icon as defualt, if the client doesn't exists |
| + HICON hIcon = GetIcon(ICON_PLUGIN_DEACTIVATED); |
| + |
| + CPluginTab* tab = GetTab(::GetCurrentThreadId()); |
| + if (tab) |
| + { |
| + CPluginClient* client = CPluginClient::GetInstance(); |
| + if (CPluginSettings::GetInstance()->IsPluginEnabled()) |
| + { |
| + if (client->IsWhitelistedUrl(url)) |
| + { |
| + hIcon = GetIcon(ICON_PLUGIN_DISABLED); |
| + } |
| + else |
| + { |
| + CPluginSettings* settings = CPluginSettings::GetInstance(); |
| + hIcon = GetIcon(ICON_PLUGIN_ENABLED); |
| + } |
| + } |
| + } |
| + return hIcon; |
| +} |
| + |
| + |
| +LRESULT CALLBACK CPluginClass::PaneWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) |
| +{ |
| + // Find tab |
| + CPluginClass *pClass = FindInstance(GetParent(hWnd)); |
| + if (!pClass) |
| + { |
| + return ::DefWindowProc(hWnd, message, wParam, lParam); |
| + } |
| + |
| + // Process message |
| + switch (message) |
| + { |
| + |
| + case WM_SETCURSOR: |
| + { |
| + ::SetCursor(::LoadCursor(NULL, IDC_ARROW)); |
| + return TRUE; |
| + } |
| + case WM_PAINT: |
| + { |
| + PAINTSTRUCT ps; |
| + HDC hDC = ::BeginPaint(hWnd, &ps); |
| + |
| + AdblockPlus::Rectangle rcClient; |
| + ::GetClientRect(hWnd, &rcClient); |
| + |
| + int nDrawEdge = 0; |
| + |
| + // Old Windows background drawing |
| + if (pClass->m_hTheme == NULL) |
| + { |
| + ::FillRect(hDC, &rcClient, (HBRUSH)(COLOR_BTNFACE + 1)); |
| + ::DrawEdge(hDC, &rcClient, BDR_RAISEDINNER, BF_LEFT); |
| + |
| + nDrawEdge = 3; |
| + rcClient.left += 3; |
| + |
| + ::DrawEdge(hDC, &rcClient, BDR_SUNKENOUTER, BF_RECT); |
| + } |
| + // Themed background drawing |
| + else |
| + { |
| + // Draw background |
| + if (pfnDrawThemeBackground) |
| + { |
| + AdblockPlus::Rectangle rc = rcClient; |
| + rc.right -= 2; |
| + pfnDrawThemeBackground(pClass->m_hTheme, hDC, 0, 0, &rc, NULL); |
| + } |
| + |
| + // Copy separator picture to left side |
| + int nHeight = rcClient.Height(); |
| + int nWidth = rcClient.Width() - 2; |
| + |
| + for (int i = 0; i < 2; i++) |
| + { |
| + for (int j = 0; j < nHeight; j++) |
| + { |
| + COLORREF clr = ::GetPixel(hDC, i + nWidth, j); |
| + |
| + // Ignore black boxes (if source is obscured by other windows) |
| + if (clr != -1 && (GetRValue(clr) > 8 || GetGValue(clr) > 8 || GetBValue(clr) > 8)) |
| + { |
| + ::SetPixel(hDC, i, j, clr); |
| + } |
| + } |
| + } |
| + } |
| + |
| + // Draw icon |
| + if (CPluginClient::GetInstance()) |
| + { |
| + HICON hIcon = GetStatusBarIcon(pClass->GetTab()->GetDocumentUrl()); |
| + |
| + int offx = nDrawEdge; |
| + if (hIcon) |
| + { |
| + //Get the RECT for the leftmost pane (the status text pane) |
| + RECT rect; |
| + BOOL rectRes = ::SendMessage(pClass->m_hStatusBarWnd, SB_GETRECT, 0, (LPARAM)&rect); |
| + ::DrawIconEx(hDC, 0, rect.bottom - rect.top - iconHeight, hIcon, iconWidth, iconHeight, NULL, NULL, DI_NORMAL); |
| + offx += iconWidth; |
| + } |
| +#ifdef _DEBUG |
| + // Display version |
| + HFONT hFont = (HFONT)::SendMessage(pClass->m_hStatusBarWnd, WM_GETFONT, 0, 0); |
| + HGDIOBJ hOldFont = ::SelectObject(hDC,hFont); |
| + |
| + AdblockPlus::Rectangle rcText = rcClient; |
| + rcText.left += offx; |
| + ::SetBkMode(hDC, TRANSPARENT); |
| + ::DrawTextW(hDC, IEPLUGIN_VERSION, -1, &rcText, DT_WORD_ELLIPSIS|DT_LEFT|DT_SINGLELINE|DT_VCENTER); |
| + |
| + ::SelectObject(hDC, hOldFont); |
| +#endif // _DEBUG |
| + } |
| + |
| + // Done! |
| + EndPaint(hWnd, &ps); |
| + |
| + return 0; |
| + } |
| + |
| + case WM_LBUTTONUP: |
| + case WM_RBUTTONUP: |
| + { |
| + std::wstring url = pClass->GetBrowserUrl(); |
| + if (url != pClass->GetTab()->GetDocumentUrl()) |
| + { |
| + pClass->GetTab()->SetDocumentUrl(url); |
| + } |
| + |
| + // Create menu |
| + HMENU hMenu = pClass->CreatePluginMenu(url); |
| + if (!hMenu) |
| + { |
| + return 0; |
| + } |
| + |
| + // Display menu |
| + POINT pt; |
| + ::GetCursorPos(&pt); |
| + |
| + RECT rc; |
| + ::GetWindowRect(hWnd, &rc); |
| + |
| + if (rc.left >= 0 && rc.top >= 0) |
| + { |
| + pt.x = rc.left; |
| + pt.y = rc.top; |
| + } |
| + |
| + pClass->DisplayPluginMenu(hMenu, -1, pt, TPM_LEFTALIGN|TPM_BOTTOMALIGN); |
| + } |
| + break; |
| + case WM_DESTROY: |
| + break; |
| + case SC_CLOSE: |
| + break; |
| + |
| + case WM_UPDATEUISTATE: |
| + { |
| + CPluginTab* tab = GetTab(::GetCurrentThreadId()); |
| + if (tab) |
| + { |
| + tab->OnActivate(); |
| + RECT rect; |
| + GetWindowRect(pClass->m_hPaneWnd, &rect); |
| + pClass->notificationMessage.Move(rect.left + (rect.right - rect.left) / 2, rect.top + (rect.bottom - rect.top) / 2); |
| + } |
| + if (LOWORD(wParam) == UIS_CLEAR) |
| + { |
| + pClass->notificationMessage.Hide(); |
| + } |
| + } |
| + break; |
| + case WM_WINDOWPOSCHANGING: |
| + { |
| + RECT rect; |
| + GetWindowRect(pClass->m_hPaneWnd, &rect); |
| + if (pClass->notificationMessage.IsVisible()) |
| + { |
| + pClass->notificationMessage.Move(rect.left + (rect.right - rect.left) / 2, rect.top + (rect.bottom - rect.top) / 2); |
| + } |
| + } |
| + break; |
| + case WM_WINDOWPOSCHANGED: |
| + { |
| + WINDOWPOS* wndPos = reinterpret_cast<WINDOWPOS*>(lParam); |
| + if (wndPos->flags & SWP_HIDEWINDOW) |
| + { |
| + pClass->notificationMessage.Hide(); |
| + } |
| + } |
| + break; |
| + case WM_ALREADY_UP_TO_DATE: |
| + { |
| + Dictionary* dictionary = Dictionary::GetInstance(); |
| + std::wstring upToDateText = dictionary->Lookup("updater", "update-already-up-to-date-text"); |
| + std::wstring upToDateTitle = dictionary->Lookup("updater", "update-already-up-to-date-title"); |
| + pClass->notificationMessage.SetTextAndIcon(upToDateText, upToDateTitle, TTI_INFO); |
| + } |
| + break; |
| + case WM_UPDATE_CHECK_ERROR: |
| + { |
| + Dictionary* dictionary = Dictionary::GetInstance(); |
| + std::wstring errorText = dictionary->Lookup("updater", "update-error-text"); |
| + std::wstring errorTitle = dictionary->Lookup("updater", "update-error-title"); |
| + pClass->notificationMessage.SetTextAndIcon(errorText, errorText, TTI_ERROR); |
| + } |
| + break; |
| + case WM_DOWNLOADING_UPDATE: |
| + { |
| + Dictionary* dictionary = Dictionary::GetInstance(); |
| + std::wstring downloadingText = dictionary->Lookup("updater", "downloading-update-text"); |
| + std::wstring downloadingTitle = dictionary->Lookup("updater", "downloading-update-title"); |
| + pClass->notificationMessage.SetTextAndIcon(downloadingText, downloadingTitle, TTI_INFO); |
| + } |
| + break; |
| + } |
| + |
| + return DefWindowProc(hWnd, message, wParam, lParam); |
| +} |
| + |
| + |
| +void CPluginClass::UpdateStatusBar() |
| +{ |
| + DEBUG_GENERAL("*** Updating statusbar") |
| + if (m_hPaneWnd == NULL) |
| + { |
| + CreateStatusBarPane(); |
| + } |
| + if ((m_hPaneWnd != NULL) && !::InvalidateRect(m_hPaneWnd, NULL, FALSE)) |
| + { |
| + DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_INVALIDATE_STATUSBAR, "Class::Invalidate statusbar"); |
| + } |
| +} |
| + |
| + |
| +void CPluginClass::Unadvice() |
| +{ |
| + s_criticalSectionLocal.Lock(); |
| + { |
| + if (m_isAdviced) |
| + { |
| + CComPtr<IConnectionPoint> pPoint = GetConnectionPoint(); |
| + if (pPoint) |
| + { |
| + HRESULT hr = pPoint->Unadvise(m_nConnectionID); |
| + if (FAILED(hr)) |
| + { |
| + DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_SET_SITE, PLUGIN_ERROR_SET_SITE_UNADVICE, "Class::Unadvice - Unadvise"); |
| + } |
| + } |
| + |
| + m_isAdviced = false; |
| + } |
| + } |
| + s_criticalSectionLocal.Unlock(); |
| +} |
| + |
| +HICON CPluginClass::GetIcon(int type) |
| +{ |
| + HICON icon = NULL; |
| + |
| + s_criticalSectionLocal.Lock(); |
| + { |
| + if (!s_hIcons[type]) |
| + { |
| + std::wstring imageToLoad = L"#"; |
| + imageToLoad += std::to_wstring(s_hIconTypes[type]); |
| + s_hIcons[type] = (HICON)::LoadImage(_Module.m_hInst, imageToLoad.c_str(), IMAGE_ICON, iconWidth, iconHeight, LR_SHARED); |
| + if (!s_hIcons[type]) |
| + { |
| + DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_LOAD_ICON, "Class::GetIcon - LoadIcon"); |
| + } |
| + } |
| + |
| + icon = s_hIcons[type]; |
| + } |
| + s_criticalSectionLocal.Unlock(); |
| + |
| + return icon; |
| +} |
| + |
| +ATOM CPluginClass::GetAtomPaneClass() |
| +{ |
| + return s_atomPaneClass; |
| +} |
| + |
| +HWND CPluginClass::GetTabHWND() const |
| +{ |
| + std::array<wchar_t, MAX_PATH> className; |
| + // Get browser window and url |
| + HWND hBrowserWnd = GetBrowserHWND(); |
| + if (!hBrowserWnd) |
| + { |
| + DEBUG_ERROR_LOG(0, PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_NO_STATUSBAR_BROWSER, "Class::GetTabWindow - No tab window") |
| + s_criticalSectionWindow.Unlock(); |
| + |
| + return false; |
| + } |
| + |
| + // Looking for a TabWindowClass window in IE7 |
| + |
| + HWND hTabWnd = ::GetWindow(hBrowserWnd, GW_CHILD); |
| + while (hTabWnd) |
| + { |
| + className[0] = L'\0'; |
| + int classNameLength = GetClassNameW(hTabWnd, className.data(), className.size()); |
| + |
| + if (classNameLength && (wcscmp(className.data(), L"TabWindowClass") == 0 || wcscmp(className.data(), L"Frame Tab") == 0)) |
| + { |
| + // IE8 support |
| + HWND hTabWnd2 = hTabWnd; |
| + if (wcscmp(className.data(), L"Frame Tab") == 0) |
| + { |
| + hTabWnd2 = ::FindWindowEx(hTabWnd2, NULL, L"TabWindowClass", NULL); |
| + } |
| + |
| + if (hTabWnd2) |
| + { |
| + DWORD nProcessId; |
| + ::GetWindowThreadProcessId(hTabWnd2, &nProcessId); |
| + if (::GetCurrentProcessId() == nProcessId) |
| + { |
| + bool bExistingTab = false; |
| + s_criticalSectionLocal.Lock(); |
| + |
| + { |
| + for (auto instance : s_instances) |
| + { |
| + if (instance->m_hTabWnd == hTabWnd2) |
| + { |
| + bExistingTab = true; |
| + break; |
| + } |
| + } |
| + } |
| + |
| + if (!bExistingTab) |
| + { |
| + hBrowserWnd = hTabWnd2; |
| + hTabWnd = hTabWnd2; |
| + s_criticalSectionLocal.Unlock(); |
| + break; |
| + } |
| + s_criticalSectionLocal.Unlock(); |
| + |
| + } |
| + } |
| + } |
| + |
| + hTabWnd = ::GetWindow(hTabWnd, GW_HWNDNEXT); |
| + } |
| + |
| + return hTabWnd; |
| + |
| +} |