| Index: src/engine/Main.cpp | 
| diff --git a/src/engine/Main.cpp b/src/engine/Main.cpp | 
| index e4f653bdf26376534bbebd0158897072b826cf75..9108f1b668a46843b20bb97676119368bcb84d7f 100644 | 
| --- a/src/engine/Main.cpp | 
| +++ b/src/engine/Main.cpp | 
| @@ -15,6 +15,10 @@ | 
| * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. | 
| */ | 
| +#pragma comment(linker,"\"/manifestdependency:type='win32' \ | 
| + name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \ | 
| + processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") | 
| + | 
| #include <AdblockPlus.h> | 
| #include <functional> | 
| #include <vector> | 
| @@ -31,9 +35,14 @@ | 
| #include "AdblockPlus.h" | 
| #include "Debug.h" | 
| #include "Updater.h" | 
| +#include "NotificationWindow.h" | 
| namespace | 
| { | 
| + class MyModule : public ATL::CAtlExeModuleT<MyModule> { | 
| + public: | 
| + } _AtlModule; | 
| + | 
| std::auto_ptr<AdblockPlus::FilterEngine> filterEngine; | 
| std::auto_ptr<Updater> updater; | 
| int activeConnections = 0; | 
| @@ -428,7 +437,6 @@ namespace | 
| updater->Update(params[0]->AsString()); | 
| } | 
| -} | 
| std::auto_ptr<AdblockPlus::FilterEngine> CreateFilterEngine(const std::wstring& locale) | 
| { | 
| @@ -457,7 +465,138 @@ std::auto_ptr<AdblockPlus::FilterEngine> CreateFilterEngine(const std::wstring& | 
| return filterEngine; | 
| } | 
| -int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) | 
| +class ScopedTimer | 
| +{ | 
| +public: | 
| + explicit ScopedTimer(HWND hwnd, UINT_PTR timerId, UINT elapse, TIMERPROC timerProc) | 
| + : m_hwnd(hwnd), m_timerId(timerId) | 
| + { | 
| + m_timerId = SetTimer(m_hwnd, m_timerId, elapse, timerProc); | 
| + } | 
| + ~ScopedTimer() | 
| + { | 
| + Close(); | 
| + } | 
| + | 
| + UINT_PTR GetID() | 
| + { | 
| + return m_timerId; | 
| + } | 
| + | 
| + operator bool() const | 
| + { | 
| + return m_timerId != 0; | 
| + } | 
| + | 
| + void Close() | 
| + { | 
| + if (m_timerId) | 
| + { | 
| + KillTimer(m_hwnd, m_timerId); | 
| + m_timerId = 0; | 
| + } | 
| + } | 
| +private: | 
| + ScopedTimer(const ScopedTimer&); | 
| + ScopedTimer& operator=(const ScopedTimer&); | 
| +private: | 
| + HWND m_hwnd; | 
| + UINT_PTR m_timerId; | 
| +}; | 
| + | 
| +struct ScopedAtlAxInitializer | 
| +{ | 
| + ScopedAtlAxInitializer() | 
| + { | 
| + ATL::AtlAxWinInit(); | 
| + } | 
| + ~ScopedAtlAxInitializer() | 
| + { | 
| + ATL::AtlAxWinTerm(); | 
| + } | 
| +}; | 
| + | 
| +void ApplicationMessageLoop(HINSTANCE hInstance) | 
| +{ | 
| + const std::wstring className = L"ABPEngineMessageWindow"; | 
| + WNDCLASS wc; | 
| + wc.style = 0; | 
| + wc.lpfnWndProc = DefWindowProcW; | 
| + wc.cbClsExtra = 0; | 
| + wc.cbWndExtra = 0; | 
| + wc.hInstance = hInstance; | 
| + wc.hIcon = nullptr; | 
| + wc.hCursor = nullptr; | 
| + wc.hbrBackground = nullptr; | 
| + wc.lpszMenuName = nullptr; | 
| + wc.lpszClassName = className.c_str(); | 
| + ATOM atom = RegisterClass(&wc); | 
| + if (!atom) | 
| + { | 
| + DebugLastError("Cannot register class for message only window"); | 
| + return; | 
| + } | 
| + HWND msgHWnd = CreateWindowW(className.c_str(), | 
| + nullptr, // window name | 
| + 0, // style | 
| + 0, 0, 0, 0, // geometry (x, y, w, h) | 
| + HWND_MESSAGE, // parent | 
| + nullptr, // menu handle | 
| + hInstance, | 
| + 0); // windows creation data. | 
| + if (!msgHWnd) | 
| + { | 
| + DebugLastError("Cannot create message only window"); | 
| + return; | 
| + } | 
| + MSG msg = {}; | 
| + ScopedTimer notificationTimer(msgHWnd, /*timer ID*/1, 3000/*msec*/, nullptr); | 
| + std::unique_ptr<NotificationWindow> notificationWindow; | 
| + while (GetMessage(&msg, /*hwnd*/nullptr, /*msgFilterMin*/0, /*msgFilterMax*/0)) | 
| + { | 
| + if (msg.hwnd == msgHWnd) | 
| + { | 
| + if (msg.message == WM_TIMER) | 
| + { | 
| + if (msg.wParam == notificationTimer.GetID()) | 
| + { | 
| + notificationTimer.Close(); | 
| + auto notification = filterEngine->GetNextNotificationToShow(); | 
| + if (notification) | 
| + { | 
| + notificationWindow.reset(new NotificationWindow(*notification, GetExeDir() + L"html\\templates\\")); | 
| + notificationWindow->destroyed = [¬ificationWindow] | 
| + { | 
| + notificationWindow.reset(); | 
| + }; | 
| + notificationWindow->linkClicked = [](const std::wstring& url) | 
| + { | 
| + ATL::CComPtr<IWebBrowser2> webBrowser; | 
| + if (SUCCEEDED(webBrowser.CoCreateInstance(__uuidof(InternetExplorer))) && webBrowser) | 
| + { | 
| + ATL::CComVariant emptyVariant; | 
| + webBrowser->Navigate(ATL::CComBSTR(url.c_str()), &emptyVariant, &emptyVariant, &emptyVariant, &emptyVariant); | 
| + webBrowser->put_Visible(VARIANT_TRUE); | 
| + } | 
| + }; | 
| + notificationWindow->Create(/*parent window*/nullptr); | 
| + if (notificationWindow->operator HWND() != nullptr) | 
| + { | 
| + notificationWindow->ShowWindow(SW_SHOWNOACTIVATE); | 
| + notificationWindow->UpdateWindow(); | 
| + } | 
| + } | 
| + } | 
| + } | 
| + } | 
| + TranslateMessage(&msg); | 
| + DispatchMessage(&msg); | 
| + } | 
| +} | 
| + | 
| +} // namespace { | 
| + | 
| +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int) | 
| { | 
| AutoHandle mutex(CreateMutexW(0, false, L"AdblockPlusEngine")); | 
| if (!mutex) | 
| @@ -480,32 +619,43 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) | 
| filterEngine = CreateFilterEngine(locale); | 
| updater.reset(new Updater(filterEngine->GetJsEngine())); | 
| - for (;;) | 
| + std::thread communicationThread([] | 
| { | 
| - try | 
| + for (;;) | 
| { | 
| - auto pipe = std::make_shared<Communication::Pipe>(Communication::pipeName, Communication::Pipe::MODE_CREATE); | 
| - | 
| - // TODO: we should wait for the finishing of the thread before exiting from this function. | 
| - // It works now in most cases because the browser waits for the response in the pipe, and the | 
| - // thread has time to finish while this response is being processed and the browser is | 
| - // disposing all its stuff. | 
| - std::thread([pipe]() | 
| + try | 
| { | 
| - ClientThread(pipe.get()); | 
| - }).detach(); | 
| - } | 
| - catch(const std::system_error& ex) | 
| - { | 
| - DebugException(ex); | 
| - return 1; | 
| - } | 
| - catch (const std::runtime_error& e) | 
| - { | 
| - DebugException(e); | 
| - return 1; | 
| + auto pipe = std::make_shared<Communication::Pipe>(Communication::pipeName, Communication::Pipe::MODE_CREATE); | 
| + | 
| + // TODO: we should wait for the finishing of the thread before exiting from this function. | 
| + // It works now in most cases because the browser waits for the response in the pipe, and the | 
| + // thread has time to finish while this response is being processed and the browser is | 
| + // disposing all its stuff. | 
| + std::thread([pipe]() | 
| + { | 
| + ClientThread(pipe.get()); | 
| + }).detach(); | 
| + } | 
| + catch(const std::system_error& ex) | 
| + { | 
| + DebugException(ex); | 
| + return 1; | 
| + } | 
| + catch (const std::runtime_error& e) | 
| + { | 
| + DebugException(e); | 
| + return 1; | 
| + } | 
| } | 
| + }); | 
| + | 
| + ScopedAtlAxInitializer atlAxInit; | 
| + ApplicationMessageLoop(hInstance); | 
| + if (communicationThread.joinable()) | 
| + { | 
| + communicationThread.join(); | 
| } | 
| + | 
| return 0; | 
| } |