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"); |
sergei
2015/03/06 13:51:12
I expected such methods to determine what should b
Eric
2015/03/06 17:29:59
For the generic version for arbitrary entry point
|
+ 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; |
+ |
+} |