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

Unified Diff: src/plugin/PluginClass.h

Issue 29332848: Issue #3432 - Manage COM events with a resource class
Patch Set: rebase Created Jan. 5, 2016, 4:21 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | src/plugin/PluginClass.cpp » ('j') | src/plugin/PluginClass.cpp » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/plugin/PluginClass.h
===================================================================
--- a/src/plugin/PluginClass.h
+++ b/src/plugin/PluginClass.h
@@ -41,6 +41,102 @@
class CPluginMimeFilterClient;
+/**
+ * Resource class for COM events.
+ * If an instance exists, there's an active connection behind it.
+ *
+ * \tparam Sink
+ * subclass of ATL::IDispEventImpl.
+ * \tparam Source
+ * Type of event source. Implements IConnectionPoint
+ */
+template<class Sink, class Source>
+class AtlEventRegistration
sergei 2016/01/06 08:41:58 I doubt that we need two classes here, AtlEventReg
Eric 2016/01/07 16:24:48 It's not overengineering. You actually want two cl
sergei 2016/02/04 13:45:50 Answered in the message.
Eric 2016/02/04 17:00:27 Perhaps you are unclear about PImpl. PImpl = Poin
sergei 2016/02/04 19:41:57 I don't want to debate here, but it's not PIMPL, I
Eric 2016/02/04 20:13:25 I don't want to debate here either, so I'll forgo
+{
+ CComPtr<Sink> consumer;
+ CComPtr<Source> producer;
+public:
+ /**
+ * \throw std::runtime_error
+ * If connection is not established
+ *
+ * \par Precondition
+ * - consumer is not nullptr (not checked)
+ * - producer is not nullptr (not checked)
+ */
+ AtlEventRegistration(Sink* consumer, Source* producer)
+ : consumer(consumer), producer(producer)
+ {
+ auto hr = consumer->DispEventAdvise(producer);
+ if (FAILED(hr))
+ {
+ DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_SET_SITE, PLUGIN_ERROR_SET_SITE_ADVICE, "AtlEventRegistrationImpl::<constructor> - Advise");
+ throw std::runtime_error("DispEventAdvise() failed");
sergei 2016/01/06 08:41:57 I would prefer to make private constructor and hav
Eric 2016/01/07 16:24:48 I consider this suggestion an inferior design. See
sergei 2016/02/04 13:45:49 I consider the current impl as overengineering and
Eric 2016/02/04 17:00:27 Yes, I know. You said that already.
sergei 2016/02/04 19:41:57 I have not said whether I like exceptions or not,
Eric 2016/02/04 20:13:25 You'll have to tell me what "logic" you're talking
+ }
+ }
+
+ ~AtlEventRegistration() // noexcept
+ {
+ try
+ {
+ // Smart pointer members ensure that this statement does not fail because of life span
+ auto hr = consumer->DispEventUnadvise(producer);
+ if (FAILED(hr))
+ {
+ DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_SET_SITE, PLUGIN_ERROR_SET_SITE_UNADVISE, "AtlEventRegistrationImpl::<destructor> - Unadvise");
+ }
+ }
+ catch (...)
+ {
+ // Suppress exceptions
+ }
+ }
+};
+
+/**
+ * Resource holder for COM events.
+ *
+ * Manages the life time of an 'AtlEventRegistration' instance.
+ * Allows events to be started and stopped at some time other than construction/destruction.
+ *
+ * \tparam Sink
+ * subclass of ATL::IDispEventImpl.
+ * \tparam Source
+ * Type of event source. Implements IConnectionPoint
+ */
+template<class Sink, class Source>
+class AtlEventRegistrationHolder
+{
+ typedef AtlEventRegistration<Sink, Source> ImplType;
+ std::unique_ptr<ImplType> impl;
+
+public:
+ AtlEventRegistrationHolder()
+ : impl(nullptr)
sergei 2016/01/06 08:41:58 This line as well as the empty constructor and des
Eric 2016/01/07 16:24:48 Done.
+ {}
+
+ ~AtlEventRegistrationHolder() // = default;
+ {}
+
+ bool Start(Sink* consumer, Source* producer) // noexcept
+ {
+ try
+ {
+ impl = new ImplType(consumer, producer);
+ }
+ catch (...)
+ {
+ impl = nullptr;
sergei 2016/01/06 08:41:58 This line is not needed.
Eric 2016/01/07 16:24:48 It is. Start() has the semantics of stopping whate
sergei 2016/02/04 13:45:50 Actually expecting that Start can be called severa
+ return false;
+ }
+ return true;
+ }
+
+ Stop() // noexcept
+ {
+ impl = nullptr;
sergei 2016/01/06 08:41:58 it's correct, but I find it better to use impl.res
Eric 2016/01/07 16:24:48 Done.
+ }
+};
class ATL_NO_VTABLE CPluginClass :
public ATL::CComObjectRootEx<ATL::CComMultiThreadModel>,
@@ -73,7 +169,6 @@
SINK_ENTRY_EX(1, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, OnDocumentComplete)
SINK_ENTRY_EX(1, DIID_DWebBrowserEvents2, DISPID_WINDOWSTATECHANGED, OnWindowStateChanged)
SINK_ENTRY_EX(1, DIID_DWebBrowserEvents2, DISPID_COMMANDSTATECHANGE, OnCommandStateChange)
- SINK_ENTRY_EX(1, DIID_DWebBrowserEvents2, DISPID_ONQUIT, OnOnQuit)
END_SINK_MAP()
CPluginClass();
@@ -132,9 +227,7 @@
void STDMETHODCALLTYPE OnDocumentComplete(IDispatch* frameBrowserDisp, VARIANT* /*urlOrPidl*/);
void STDMETHODCALLTYPE OnWindowStateChanged(unsigned long flags, unsigned long validFlagsMask);
void STDMETHODCALLTYPE OnCommandStateChange(long command, VARIANT_BOOL enable);
- void STDMETHODCALLTYPE OnOnQuit();
- void Unadvise();
-
+
void ShowStatusBar();
bool IsStatusBarEnabled();
@@ -144,6 +237,12 @@
* It's values are set and reset solely in SetSite().
*/
CComPtr<IWebBrowser2> m_webBrowser2;
+ /**
+ * Event manager for events coming from our site object.
sergei 2016/01/06 08:41:58 Why do we need this comment?
Eric 2016/01/07 16:24:48 Because we have multiple sources of events. We ha
sergei 2016/02/04 13:45:49 I mean, it's clear from line `AtlEventRegistration
Eric 2016/02/04 17:00:27 It's a Doxygen comment.
+ */
+ AtlEventRegistrationHolder<CPluginClass, IWebBrowser2> browserEvents;
+ bool detachedInitializationFailed;
sergei 2016/01/06 08:41:58 The member naming is not consistent with other mem
sergei 2016/01/06 08:41:58 Since it's accessed from different threads, there
Eric 2016/01/07 16:24:48 You're raising a valid issue, certainly, but I've
Eric 2016/01/07 16:24:48 Right. It's not there because "m_" prefixes are ag
+
HWND m_hBrowserWnd;
HWND m_hTabWnd;
HWND m_hStatusBarWnd;
@@ -157,7 +256,6 @@
NotificationMessage notificationMessage;
- bool m_isAdvised;
bool m_isInitializedOk;
// Atom pane class
« no previous file with comments | « no previous file | src/plugin/PluginClass.cpp » ('j') | src/plugin/PluginClass.cpp » ('J')

Powered by Google App Engine
This is Rietveld