| Index: src/plugin/PluginClass.cpp |
| =================================================================== |
| --- a/src/plugin/PluginClass.cpp |
| +++ b/src/plugin/PluginClass.cpp |
| @@ -30,6 +30,7 @@ |
| #include "../shared/Dictionary.h" |
| #include "IeVersion.h" |
| #include "../shared/Version.h" |
| +#include "Instances.h" |
| #include <thread> |
| #include <array> |
| @@ -57,13 +58,43 @@ |
| ATOM CPluginClass::s_atomPaneClass = NULL; |
| HINSTANCE CPluginClass::s_hUxtheme = NULL; |
| std::set<CPluginClass*> CPluginClass::s_instances; |
| -std::map<DWORD, CPluginClass*> CPluginClass::s_threadInstances; |
| CComAutoCriticalSection CPluginClass::s_criticalSectionLocal; |
| CComAutoCriticalSection CPluginClass::s_criticalSectionWindow; |
| CComQIPtr<IWebBrowser2> CPluginClass::s_asyncWebBrowser2; |
| + |
|
sergei
2016/02/01 15:50:43
Why not to put it into anonymous namespace?
Eric
2016/02/03 17:17:05
OK.
|
| +/** |
| + * A synchronized map whose key is always the current thread ID. |
| + */ |
| +class CurrentThreadMap |
| + : public SyncMap<DWORD, CPluginClass*, nullptr> |
| +{ |
| + typedef SyncMap<DWORD, CPluginClass*, nullptr> Base; |
| + |
| +public: |
| + bool AddIfAbsent(CPluginClass* p) |
| + { |
| + return Base::AddIfAbsent(::GetCurrentThreadId(), p); |
| + } |
| + |
| + bool RemoveAndCheck() |
| + { |
| + return Base::RemoveAndCheck(::GetCurrentThreadId()); |
| + } |
| + |
| + CPluginClass* Locate() |
| + { |
| + return Base::Locate(::GetCurrentThreadId()); |
| + } |
| +}; |
| + |
| +/** |
| + * Map from thread ID's to CPluginClass instances |
| + */ |
| +CurrentThreadMap threadMap; |
|
sergei
2016/02/01 15:50:43
Off topic: Still a global variable. When will we s
Eric
2016/02/03 17:17:05
The map from threads to BHO instances is inherentl
|
| + |
| /* |
| * Without namespace declaration, the identifier "Rectangle" is ambiguous |
| * See http://msdn.microsoft.com/en-us/library/windows/desktop/dd162898(v=vs.85).aspx |
| @@ -103,10 +134,7 @@ |
| m_pWndProcStatus = NULL; |
| m_hTheme = NULL; |
| m_isInitializedOk = false; |
| - |
| - |
| m_tab = new CPluginTab(this); |
| - |
| Dictionary::Create(GetBrowserLanguage()); |
| } |
| @@ -215,6 +243,14 @@ |
| throw std::logic_error("CPluginClass::SetSite - Unable to convert site pointer to IWebBrowser2*"); |
| } |
| + /* |
| + * Add ourselves to the thread map. |
| + */ |
| + if (!threadMap.AddIfAbsent(this)) |
| + { |
| + throw std::logic_error("CPluginClass::SetSite - May not overwrite existing entry in thread map"); |
|
sergei
2016/02/01 15:50:43
That looks suspicious. It can happen that two inst
Eric
2016/02/03 17:17:05
Actually, that cannot happen.
|
| + } |
| + |
| //register the mimefilter |
| //and only mimefilter |
| //on some few computers the mimefilter does not get properly registered when it is done on another thread |
| @@ -281,15 +317,14 @@ |
| HANDLE hMainThread = NULL; |
| HANDLE hTabThread = NULL; |
| + if (!threadMap.RemoveAndCheck()) |
| + { |
| + throw std::logic_error("CPluginClass::SetSite - Missing entry in thread map"); |
| + } |
| + |
| s_criticalSectionLocal.Lock(); |
| { |
| s_instances.erase(this); |
| - |
| - std::map<DWORD,CPluginClass*>::iterator it = s_threadInstances.find(::GetCurrentThreadId()); |
| - if (it != s_threadInstances.end()) |
| - { |
| - s_threadInstances.erase(it); |
| - } |
| if (s_instances.empty()) |
| { |
| // TODO: Explicitly releasing a resource when a container becomes empty looks like a job better suited for shared_ptr |
| @@ -526,16 +561,11 @@ |
| && flags == (OLECMDIDF_WINDOWSTATE_USERVISIBLE | OLECMDIDF_WINDOWSTATE_ENABLED); |
| if (newtabshown) |
| { |
| - std::map<DWORD,CPluginClass*>::const_iterator it = s_threadInstances.find(GetCurrentThreadId()); |
| - if (it == s_threadInstances.end()) |
| + if (!m_isInitializedOk) |
| { |
| - s_threadInstances[::GetCurrentThreadId()] = this; |
|
sergei
2016/02/01 15:50:43
Pay attention that we are overriding the value of
Eric
2016/02/03 17:17:05
I don't know what you mean here.
|
| - if (!m_isInitializedOk) |
| - { |
| - m_isInitializedOk = true; |
| - InitObject(); |
| - UpdateStatusBar(); |
| - } |
| + m_isInitializedOk = true; |
| + InitObject(); |
| + UpdateStatusBar(); |
| } |
| } |
| notificationMessage.Hide(); |
| @@ -954,21 +984,10 @@ |
| return m_tab; |
| } |
| -CPluginTab* CPluginClass::GetTab(DWORD dwThreadId) |
| +CPluginTab* CPluginClass::GetTabCurrentThread() |
| { |
| - CPluginTab* tab = NULL; |
| - |
| - s_criticalSectionLocal.Lock(); |
| - { |
| - std::map<DWORD,CPluginClass*>::const_iterator it = s_threadInstances.find(dwThreadId); |
| - if (it != s_threadInstances.end()) |
| - { |
| - tab = it->second->m_tab; |
| - } |
| - } |
| - s_criticalSectionLocal.Unlock(); |
| - |
| - return tab; |
| + auto p = threadMap.Locate(); |
| + return p ? p->m_tab : nullptr; |
| } |
| @@ -1349,7 +1368,7 @@ |
| // use the disable icon as defualt, if the client doesn't exists |
| HICON hIcon = GetIcon(ICON_PLUGIN_DEACTIVATED); |
| - CPluginTab* tab = GetTab(::GetCurrentThreadId()); |
| + CPluginTab* tab = GetTabCurrentThread(); |
| if (tab) |
| { |
| CPluginClient* client = CPluginClient::GetInstance(); |
| @@ -1512,7 +1531,7 @@ |
| case WM_UPDATEUISTATE: |
| { |
| - CPluginTab* tab = GetTab(::GetCurrentThreadId()); |
| + CPluginTab* tab = GetTabCurrentThread(); |
| if (tab) |
| { |
| tab->OnActivate(); |