Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: src/engine/Main.cpp

Issue 6505394822184960: Issue 1109 - Support notifications (Closed)
Patch Set: rebase and address comments Created July 23, 2015, 2:13 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « installer/src/msi/adblockplusie.wxs ('k') | src/engine/NotificationWindow.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-2015 Eyeo GmbH 3 * Copyright (C) 2006-2015 Eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 #pragma comment(linker,"\"/manifestdependency:type='win32' \
19 name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
20 processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
21
18 #include <AdblockPlus.h> 22 #include <AdblockPlus.h>
19 #include <functional> 23 #include <functional>
20 #include <vector> 24 #include <vector>
25 #include <deque>
21 #include <thread> 26 #include <thread>
27 #include <mutex>
28 #include <condition_variable>
22 #include <Windows.h> 29 #include <Windows.h>
23 30
24 #include "../shared/AutoHandle.h" 31 #include "../shared/AutoHandle.h"
25 #include "../shared/Communication.h" 32 #include "../shared/Communication.h"
26 #include "../shared/Dictionary.h" 33 #include "../shared/Dictionary.h"
27 #include "../shared/Utils.h" 34 #include "../shared/Utils.h"
28 #include "../shared/Version.h" 35 #include "../shared/Version.h"
29 #include "../shared/CriticalSection.h" 36 #include "../shared/CriticalSection.h"
30 #include "IeVersion.h" 37 #include "IeVersion.h"
31 #include "AdblockPlus.h" 38 #include "AdblockPlus.h"
32 #include "Debug.h" 39 #include "Debug.h"
33 #include "Updater.h" 40 #include "Updater.h"
34 #include "Registry.h" 41 #include "Registry.h"
42 #include "NotificationWindow.h"
35 43
36 namespace 44 namespace
37 { 45 {
46 struct ScopedAtlAxInitializer
47 {
48 ScopedAtlAxInitializer()
49 {
50 ATL::AtlAxWinInit();
51 }
52 ~ScopedAtlAxInitializer()
53 {
54 ATL::AtlAxWinTerm();
55 }
56 };
57
58 class ABPAtlModule : public ATL::CAtlExeModuleT<ABPAtlModule> {
59 enum CustomMessages
60 {
61 TaskPosted = WM_USER + 1
Oleksandr 2015/07/29 10:47:16 Nit: TASK_POSTED. Our enums are almost always uppe
62 };
63 public:
64 ABPAtlModule() : m_msgHWnd(nullptr)
65 {
66 }
67 void Finalize();
68 HRESULT PreMessageLoop(int showCmd) throw();
69 void RunMessageLoop() throw();
70 static HRESULT InitializeCom() throw()
71 {
72 // The default implementation initializes multithreaded version but
73 // in this case hosted ActiveX does not properly work.
74 return CoInitialize(nullptr);
75 }
76 private:
77 void onNewNotification(const AdblockPlus::NotificationPtr& notification);
78 void dispatchTask(std::function<void()>&& task);
79 void processTasks();
80 private:
81 ScopedAtlAxInitializer m_scopedAtlAxInit;
82 HWND m_msgHWnd;
83 std::recursive_mutex m_tasksMutex;
84 std::deque<std::function<void()>> m_tasks;
85 std::unique_ptr<NotificationBorderWindow> m_notificationWindow;
86 } _AtlModule;
87
38 std::auto_ptr<AdblockPlus::FilterEngine> filterEngine; 88 std::auto_ptr<AdblockPlus::FilterEngine> filterEngine;
39 std::auto_ptr<Updater> updater; 89 std::auto_ptr<Updater> updater;
40 int activeConnections = 0; 90 int activeConnections = 0;
41 CriticalSection activeConnectionsLock; 91 CriticalSection activeConnectionsLock;
42 HWND callbackWindow; 92 HWND callbackWindow;
43 93
44 void WriteSubscriptions(Communication::OutputBuffer& response, 94 void WriteSubscriptions(Communication::OutputBuffer& response,
45 const std::vector<AdblockPlus::SubscriptionPtr>& subscriptions) 95 const std::vector<AdblockPlus::SubscriptionPtr>& subscriptions)
46 { 96 {
47 int32_t count = static_cast<int32_t>(subscriptions.size()); 97 int32_t count = static_cast<int32_t>(subscriptions.size());
(...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after
405 455
406 Debug("Client disconnected " + threadString); 456 Debug("Client disconnected " + threadString);
407 457
408 { 458 {
409 CriticalSection::Lock lock(activeConnectionsLock); 459 CriticalSection::Lock lock(activeConnectionsLock);
410 activeConnections--; 460 activeConnections--;
411 if (activeConnections < 1) 461 if (activeConnections < 1)
412 { 462 {
413 Debug("No connections left, shutting down the engine"); 463 Debug("No connections left, shutting down the engine");
414 activeConnections = 0; 464 activeConnections = 0;
465
466 // The following exit(0) calls the destructor of _AtlModule from the
467 // current thread which results in the disaster because there is a
468 // running message loop as well as there can be alive notification
469 // window which holds v8::Value as well as m_tasks can hold v8::Value
470 // but JS Engine is destroyed before _AtlModule. BTW, various free
471 // running threads like Timeout also cause the crash because the engine
472 // is already destroyed.
473 _AtlModule.Finalize();
415 exit(0); 474 exit(0);
416 } 475 }
417 } 476 }
418 477
419 } 478 }
420 479
421 void OnUpdateAvailable(AdblockPlus::JsValueList& params) 480 void OnUpdateAvailable(AdblockPlus::JsValueList& params)
422 { 481 {
423 if (params.size() < 1) 482 if (params.size() < 1)
424 { 483 {
(...skipping 10 matching lines...) Expand all
435 try 494 try
436 { 495 {
437 AdblockPlus::RegistryKey regKey(HKEY_CURRENT_USER, L"Software\\AdblockPlus "); 496 AdblockPlus::RegistryKey regKey(HKEY_CURRENT_USER, L"Software\\AdblockPlus ");
438 return regKey.value_wstring(preconfigName); 497 return regKey.value_wstring(preconfigName);
439 } 498 }
440 catch (const std::runtime_error&) 499 catch (const std::runtime_error&)
441 { 500 {
442 return L""; 501 return L"";
443 } 502 }
444 } 503 }
445 }
446 504
447 std::auto_ptr<AdblockPlus::FilterEngine> CreateFilterEngine(const std::wstring& locale) 505 std::auto_ptr<AdblockPlus::FilterEngine> CreateFilterEngine(const std::wstring& locale)
448 { 506 {
449 AdblockPlus::AppInfo appInfo; 507 AdblockPlus::AppInfo appInfo;
450 appInfo.version = ToUtf8String(IEPLUGIN_VERSION); 508 appInfo.version = ToUtf8String(IEPLUGIN_VERSION);
451 appInfo.name = "adblockplusie"; 509 appInfo.name = "adblockplusie";
452 #ifdef _WIN64 510 #ifdef _WIN64
453 appInfo.application = "msie64"; 511 appInfo.application = "msie64";
454 #else 512 #else
455 appInfo.application = "msie32"; 513 appInfo.application = "msie32";
(...skipping 13 matching lines...) Expand all
469 dynamic_cast<AdblockPlus::DefaultFileSystem*>(jsEngine->GetFileSystem().get()) ->SetBasePath(dataPath); 527 dynamic_cast<AdblockPlus::DefaultFileSystem*>(jsEngine->GetFileSystem().get()) ->SetBasePath(dataPath);
470 std::map<std::string, AdblockPlus::JsValuePtr> preconfig; 528 std::map<std::string, AdblockPlus::JsValuePtr> preconfig;
471 preconfig["disable_auto_updates"] = jsEngine->NewValue( 529 preconfig["disable_auto_updates"] = jsEngine->NewValue(
472 PreconfigurationValueFromRegistry(L"disable_auto_updates") == L"true"); 530 PreconfigurationValueFromRegistry(L"disable_auto_updates") == L"true");
473 preconfig["suppress_first_run_page"] = jsEngine->NewValue( 531 preconfig["suppress_first_run_page"] = jsEngine->NewValue(
474 PreconfigurationValueFromRegistry(L"suppress_first_run_page") == L"true"); 532 PreconfigurationValueFromRegistry(L"suppress_first_run_page") == L"true");
475 std::auto_ptr<AdblockPlus::FilterEngine> filterEngine(new AdblockPlus::FilterE ngine(jsEngine, preconfig)); 533 std::auto_ptr<AdblockPlus::FilterEngine> filterEngine(new AdblockPlus::FilterE ngine(jsEngine, preconfig));
476 return filterEngine; 534 return filterEngine;
477 } 535 }
478 536
479 int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) 537 void ABPAtlModule::Finalize()
538 {
539 std::condition_variable cv;
540 std::mutex cvMutex;
541 std::unique_lock<std::mutex> lock(cvMutex);
542 dispatchTask([&cvMutex, &cv, this]
543 {
544 if (m_notificationWindow)
545 {
546 m_notificationWindow->SendMessage(WM_CLOSE);
547 }
548 SendMessage(m_msgHWnd, WM_QUIT, 0, 0);
549 {
550 std::lock_guard<std::recursive_mutex> lock(m_tasksMutex);
551 m_tasks.clear();
552 }
553 std::unique_lock<std::mutex> lock(cvMutex);
554 cv.notify_one();
555 });
556 cv.wait(lock);
557 }
558
559 HRESULT ABPAtlModule::PreMessageLoop(int showCmd) throw()
560 {
561 const std::wstring className = L"ABPEngineMessageWindow";
562 WNDCLASS wc;
563 wc.style = 0;
564 wc.lpfnWndProc = DefWindowProcW;
565 wc.cbClsExtra = 0;
566 wc.cbWndExtra = 0;
567 wc.hInstance = ATL::_AtlBaseModule.GetModuleInstance();
568 wc.hIcon = nullptr;
569 wc.hCursor = nullptr;
570 wc.hbrBackground = nullptr;
571 wc.lpszMenuName = nullptr;
572 wc.lpszClassName = className.c_str();
573 ATOM atom = RegisterClass(&wc);
574 if (!atom)
575 {
576 DebugLastError("Cannot register class for message only window");
577 return E_FAIL;
578 }
579 m_msgHWnd = CreateWindowW(className.c_str(),
580 nullptr, // window name
581 0, // style
582 0, 0, 0, 0, // geometry (x, y, w, h)
583 HWND_MESSAGE, // parent
584 nullptr, // menu handle
585 wc.hInstance,
586 0); // windows creation data.
587 if (!m_msgHWnd)
588 {
589 DebugLastError("Cannot create message only window");
590 return E_FAIL;
591 }
592
593 filterEngine->SetShowNotificationCallback([this](const AdblockPlus::Notificati onPtr& notification)
594 {
595 if (!notification)
596 {
597 return;
598 }
599 dispatchTask([notification, this]
600 {
601 onNewNotification(notification);
602 });
603 });
604
605 HRESULT retValue = __super::PreMessageLoop(showCmd);
606 // __super::PreMessageLoop returns S_FALSE because there is nothing to
607 // register but S_OK is required to run message loop.
608 return FAILED(retValue) ? retValue : S_OK;
609 }
610
611 void ABPAtlModule::RunMessageLoop() throw()
612 {
613 MSG msg = {};
614 while (GetMessage(&msg, /*hwnd*/nullptr, /*msgFilterMin*/0, /*msgFilterMax*/0) )
615 {
616 if (msg.hwnd == m_msgHWnd && msg.message == CustomMessages::TaskPosted)
617 {
618 processTasks();
619 }
620 TranslateMessage(&msg);
621 DispatchMessage(&msg);
622 }
623 }
624
625 void ABPAtlModule::onNewNotification(const AdblockPlus::NotificationPtr& notific ation)
626 {
627 m_notificationWindow.reset(new NotificationBorderWindow(*notification, GetExeD ir() + L"html\\templates\\"));
628 m_notificationWindow->SetOnDestroyed([notification, this]
629 {
630 notification->MarkAsShown();
631 m_notificationWindow.reset();
632 });
633 m_notificationWindow->SetOnLinkClicked([](const std::wstring& url)
634 {
635 ATL::CComPtr<IWebBrowser2> webBrowser;
636 if (SUCCEEDED(webBrowser.CoCreateInstance(__uuidof(InternetExplorer))) && we bBrowser)
637 {
638 ATL::CComVariant emptyVariant;
639 webBrowser->Navigate(ATL::CComBSTR(url.c_str()), &emptyVariant, &emptyVari ant, &emptyVariant, &emptyVariant);
640 webBrowser->put_Visible(VARIANT_TRUE);
641 }
642 });
643 m_notificationWindow->Create(/*parent window*/nullptr);
644 if (m_notificationWindow->operator HWND() != nullptr)
645 {
646 m_notificationWindow->ShowWindow(SW_SHOWNOACTIVATE);
647 m_notificationWindow->UpdateWindow();
648 }
649 }
650
651 void ABPAtlModule::dispatchTask(std::function<void()>&& task)
Oleksandr 2015/07/29 10:47:16 Nit: How about "DispatchTask" instead? We usually
652 {
653 {
654 std::lock_guard<std::recursive_mutex> lock(m_tasksMutex);
655 m_tasks.emplace_back(std::move(task));
656 }
657 PostMessageW(m_msgHWnd, CustomMessages::TaskPosted, 0, 0);
658 }
659
660 void ABPAtlModule::processTasks()
Oleksandr 2015/07/29 10:47:16 Nit: ProcessTasks(). Upper case?
661 {
662 std::lock_guard<std::recursive_mutex> lock(m_tasksMutex);
663 while(!m_tasks.empty())
664 {
665 auto task = *m_tasks.begin();
666 m_tasks.pop_front();
667 if (task)
668 task();
669 }
670 }
671
672 } // namespace {
673
674 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int cmdShow)
480 { 675 {
481 AutoHandle mutex(CreateMutexW(0, false, L"AdblockPlusEngine")); 676 AutoHandle mutex(CreateMutexW(0, false, L"AdblockPlusEngine"));
482 if (!mutex) 677 if (!mutex)
483 { 678 {
484 DebugLastError("CreateMutex failed"); 679 DebugLastError("CreateMutex failed");
485 return 1; 680 return 1;
486 } 681 }
487 682
488 if (GetLastError() == ERROR_ALREADY_EXISTS) 683 if (GetLastError() == ERROR_ALREADY_EXISTS)
489 { 684 {
490 DebugLastError("Named pipe exists, another engine instance appears to be run ning"); 685 DebugLastError("Named pipe exists, another engine instance appears to be run ning");
491 return 1; 686 return 1;
492 } 687 }
493 688
494 int argc; 689 int argc;
495 LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc); 690 LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc);
496 std::wstring locale(argc >= 2 ? argv[1] : L""); 691 std::wstring locale(argc >= 2 ? argv[1] : L"");
497 LocalFree(argv); 692 LocalFree(argv);
498 Dictionary::Create(locale); 693 Dictionary::Create(locale);
499 filterEngine = CreateFilterEngine(locale); 694 filterEngine = CreateFilterEngine(locale);
500 updater.reset(new Updater(filterEngine->GetJsEngine())); 695 updater.reset(new Updater(filterEngine->GetJsEngine()));
501 696
502 for (;;) 697 std::thread communicationThread([]
503 { 698 {
504 try 699 for (;;)
505 { 700 {
506 auto pipe = std::make_shared<Communication::Pipe>(Communication::pipeName, Communication::Pipe::MODE_CREATE); 701 try
702 {
703 auto pipe = std::make_shared<Communication::Pipe>(Communication::pipeNam e, Communication::Pipe::MODE_CREATE);
704
705 // TODO: we should wait for the finishing of the thread before exiting f rom this function.
706 // It works now in most cases because the browser waits for the response in the pipe, and the
707 // thread has time to finish while this response is being processed and the browser is
708 // disposing all its stuff.
709 std::thread([pipe]()
710 {
711 ClientThread(pipe.get());
712 }).detach();
713 }
714 catch(const std::system_error& ex)
715 {
716 DebugException(ex);
717 return 1;
718 }
719 catch (const std::runtime_error& e)
720 {
721 DebugException(e);
722 return 1;
723 }
724 }
725 });
507 726
508 // TODO: we should wait for the finishing of the thread before exiting fro m this function. 727 int retValue = _AtlModule.WinMain(cmdShow);
509 // It works now in most cases because the browser waits for the response i n the pipe, and the 728 if (communicationThread.joinable())
510 // thread has time to finish while this response is being processed and th e browser is 729 {
511 // disposing all its stuff. 730 communicationThread.join();
512 std::thread([pipe]()
513 {
514 ClientThread(pipe.get());
515 }).detach();
516 }
517 catch(const std::system_error& ex)
518 {
519 DebugException(ex);
520 return 1;
521 }
522 catch (const std::runtime_error& e)
523 {
524 DebugException(e);
525 return 1;
526 }
527 } 731 }
528 732
529 return 0; 733 return retValue;
530 } 734 }
OLDNEW
« no previous file with comments | « installer/src/msi/adblockplusie.wxs ('k') | src/engine/NotificationWindow.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld