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; |
} |