| 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,45 @@ |
| 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; |
| +namespace |
| +{ |
| + /** |
| + * 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::RemoveIfPresent(::GetCurrentThreadId()); |
| + } |
| + |
| + CPluginClass* Locate() |
| + { |
| + return Base::Locate(::GetCurrentThreadId()); |
| + } |
| + }; |
| + |
| + /** |
| + * Map from thread ID's to CPluginClass instances |
| + */ |
| + CurrentThreadMap threadMap; |
| +} |
| + |
| /* |
| * Without namespace declaration, the identifier "Rectangle" is ambiguous |
| * See http://msdn.microsoft.com/en-us/library/windows/desktop/dd162898(v=vs.85).aspx |
| @@ -118,10 +151,7 @@ |
| m_pWndProcStatus = NULL; |
| m_hTheme = NULL; |
| m_isInitializedOk = false; |
| - |
| - |
| m_tab = new CPluginTab(); |
| - |
| Dictionary::Create(GetBrowserLanguage()); |
| } |
| @@ -246,6 +276,14 @@ |
| return ss.str(); |
| }()); |
| + /* |
| + * Add ourselves to the thread map. |
| + */ |
| + if (!threadMap.AddIfAbsent(this)) |
| + { |
| + throw std::logic_error("CPluginClass::SetSite - May not overwrite existing entry in thread map"); |
| + } |
| + |
| //register the mimefilter |
| //and only mimefilter |
| //on some few computers the mimefilter does not get properly registered when it is done on another thread |
| @@ -319,15 +357,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 |
| @@ -564,16 +601,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; |
| - if (!m_isInitializedOk) |
| - { |
| - m_isInitializedOk = true; |
| - InitObject(); |
| - UpdateStatusBar(); |
| - } |
| + m_isInitializedOk = true; |
| + InitObject(); |
| + UpdateStatusBar(); |
| } |
| } |
| notificationMessage.Hide(); |
| @@ -992,21 +1024,10 @@ |
| return m_tab; |
| } |
| -CPluginTab* CPluginClass::GetTab(DWORD dwThreadId) |
| +CPluginTab* CPluginClass::GetTabForCurrentThread() |
| { |
| - 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; |
| } |
| // Entry point |
| @@ -1417,7 +1438,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 = GetTabForCurrentThread(); |
| if (tab) |
| { |
| CPluginClient* client = CPluginClient::GetInstance(); |
| @@ -1581,7 +1602,7 @@ |
| case WM_UPDATEUISTATE: |
| { |
| - CPluginTab* tab = GetTab(::GetCurrentThreadId()); |
| + CPluginTab* tab = GetTabForCurrentThread(); |
| if (tab) |
| { |
| tab->OnActivate(); |