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