| Index: src/plugin/PluginClass.cpp | 
| =================================================================== | 
| --- a/src/plugin/PluginClass.cpp | 
| +++ b/src/plugin/PluginClass.cpp | 
| @@ -233,175 +233,149 @@ | 
| } | 
| - | 
| -// This gets called when a new browser window is created (which also triggers the | 
| -// creation of this object). The pointer passed in should be to a IWebBrowser2 | 
| -// interface that represents the browser for the window. | 
| -// it is also called when a tab is closed, this unknownSite will be null | 
| -// so we should handle that it is called this way several times during a session | 
| +/* | 
| + * IE calls this when it creates a new browser window or tab, immediately after it also | 
| + * creates the object. The argument 'unknownSite' in is the OLE "site" of the object, | 
| + * which is an IWebBrowser2 interface associated with the window/tab. | 
| + * | 
| + * IE also ordinarily calls this again when its window/tab is closed, in which case | 
| + * 'unknownSite' will be null. Extraordinarily, this is sometimes _not_ called when IE | 
| + * is shutting down. Thus 'SetSite(nullptr)' has some similarities with a destructor, | 
| + * but it is not a proper substitute for one. | 
| 
 
sergei
2015/03/09 10:23:50
I'm not sure that we need this comment except the
 
Eric
2015/03/09 13:31:29
I was just rewriting the comment, mostly, with the
 
Oleksandr
2015/03/10 08:38:26
I am pretty sure it _is_ called every time when IE
 
Oleksandr
2015/03/10 08:42:04
https://msdn.microsoft.com/en-us/library/bb250489(
 
 | 
| + */ | 
| STDMETHODIMP CPluginClass::SetSite(IUnknown* unknownSite) | 
| { | 
| - CPluginSettings* settings = CPluginSettings::GetInstance(); | 
| + try | 
| + { | 
| + if (unknownSite) | 
| + { | 
| - MULTIPLE_VERSIONS_CHECK(); | 
| + DEBUG_GENERAL(L"================================================================================\nNEW TAB UI\n================================================================================") | 
| - if (unknownSite) | 
| - { | 
| + HRESULT hr = ::CoInitialize(NULL); | 
| + if (FAILED(hr)) | 
| + { | 
| + DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_SET_SITE, PLUGIN_ERROR_SET_SITE_COINIT, "Class::SetSite - CoInitialize"); | 
| + } | 
| - DEBUG_GENERAL(L"================================================================================\nNEW TAB UI\n================================================================================") | 
| + s_criticalSectionBrowser.Lock(); | 
| + { | 
| + m_webBrowser2 = unknownSite; | 
| 
 
Eric
2015/03/06 15:58:04
Assigned to m_webBrowser2 here, declared as CComQI
 
sergei
2015/03/06 16:07:19
Here `AddRef` is called.
 
 | 
| + } | 
| + s_criticalSectionBrowser.Unlock(); | 
| - HRESULT hr = ::CoInitialize(NULL); | 
| - if (FAILED(hr)) | 
| - { | 
| - DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_SET_SITE, PLUGIN_ERROR_SET_SITE_COINIT, "Class::SetSite - CoInitialize"); | 
| - } | 
| + //register the mimefilter | 
| + //and only mimefilter | 
| + //on some few computers the mimefilter does not get properly registered when it is done on another thread | 
| - s_criticalSectionBrowser.Lock(); | 
| - { | 
| - m_webBrowser2 = unknownSite; | 
| - } | 
| - s_criticalSectionBrowser.Unlock(); | 
| + s_criticalSectionLocal.Lock(); | 
| + { | 
| + // Always register on startup, then check if we need to unregister in a separate thread | 
| + s_mimeFilter = CPluginClientFactory::GetMimeFilterClientInstance(); | 
| + s_asyncWebBrowser2 = unknownSite; | 
| + s_instances.insert(this); | 
| + } | 
| + s_criticalSectionLocal.Unlock(); | 
| - //register the mimefilter | 
| - //and only mimefilter | 
| - //on some few computers the mimefilter does not get properly registered when it is done on another thread | 
| + try | 
| + { | 
| + // Check if loaded as BHO | 
| + if (GetBrowser()) | 
| 
 
sergei
2015/03/09 10:23:50
We don't need this comment now.
 
Eric
2015/03/09 13:31:29
We don't need this particular comment, but we'll n
 
Eric
2015/03/17 10:41:07
Done.
 
 | 
| + { | 
| + DEBUG_GENERAL("Loaded as BHO"); | 
| + CComPtr<IConnectionPoint> pPoint = GetConnectionPoint(); | 
| + if (pPoint) | 
| + { | 
| + HRESULT hr = pPoint->Advise((IDispatch*)this, &m_nConnectionID); | 
| + if (SUCCEEDED(hr)) | 
| + { | 
| + m_isAdviced = true; | 
| - s_criticalSectionLocal.Lock(); | 
| - { | 
| - // Always register on startup, then check if we need to unregister in a separate thread | 
| - s_mimeFilter = CPluginClientFactory::GetMimeFilterClientInstance(); | 
| - s_asyncWebBrowser2 = unknownSite; | 
| - s_instances.insert(this); | 
| - } | 
| - s_criticalSectionLocal.Unlock(); | 
| - | 
| - try | 
| - { | 
| - // Check if loaded as BHO | 
| - if (GetBrowser()) | 
| - { | 
| - DEBUG_GENERAL("Loaded as BHO"); | 
| - CComPtr<IConnectionPoint> pPoint = GetConnectionPoint(); | 
| - if (pPoint) | 
| - { | 
| - HRESULT hr = pPoint->Advise((IDispatch*)this, &m_nConnectionID); | 
| - if (SUCCEEDED(hr)) | 
| - { | 
| - m_isAdviced = true; | 
| - | 
| - try | 
| + try | 
| + { | 
| + std::thread startInitObjectThread(StartInitObject, this); | 
| + startInitObjectThread.detach(); // TODO: but actually we should wait for the thread in the dtr. | 
| + } | 
| + catch (const std::system_error& ex) | 
| + { | 
| + DEBUG_SYSTEM_EXCEPTION(ex, PLUGIN_ERROR_THREAD, PLUGIN_ERROR_MAIN_THREAD_CREATE_PROCESS, | 
| + "Class::Thread - Failed to create StartInitObject thread"); | 
| + } | 
| + } | 
| + else | 
| { | 
| - std::thread startInitObjectThread(StartInitObject, this); | 
| - startInitObjectThread.detach(); // TODO: but actually we should wait for the thread in the dtr. | 
| + DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_SET_SITE, PLUGIN_ERROR_SET_SITE_ADVICE, "Class::SetSite - Advice"); | 
| } | 
| - catch (const std::system_error& ex) | 
| - { | 
| - DEBUG_SYSTEM_EXCEPTION(ex, PLUGIN_ERROR_THREAD, PLUGIN_ERROR_MAIN_THREAD_CREATE_PROCESS, | 
| - "Class::Thread - Failed to create StartInitObject thread"); | 
| - } | 
| - } | 
| - else | 
| - { | 
| - DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_SET_SITE, PLUGIN_ERROR_SET_SITE_ADVICE, "Class::SetSite - Advice"); | 
| } | 
| } | 
| } | 
| - else // Check if loaded as toolbar handler | 
| + catch (const std::runtime_error& ex) | 
| { | 
| - DEBUG_GENERAL("Loaded as toolbar handler"); | 
| - CComPtr<IServiceProvider> pServiceProvider; | 
| + DEBUG_EXCEPTION(ex); | 
| + Unadvice(); | 
| + } | 
| + } | 
| + else | 
| + { | 
| + // Unadvice | 
| + Unadvice(); | 
| - HRESULT hr = unknownSite->QueryInterface(&pServiceProvider); | 
| - if (SUCCEEDED(hr)) | 
| + // Destroy window | 
| + if (m_pWndProcStatus) | 
| + { | 
| + ::SetWindowLongPtr(m_hStatusBarWnd, GWLP_WNDPROC, (LPARAM)(WNDPROC)m_pWndProcStatus); | 
| + | 
| + m_pWndProcStatus = NULL; | 
| + } | 
| + | 
| + if (m_hPaneWnd) | 
| + { | 
| + DestroyWindow(m_hPaneWnd); | 
| + m_hPaneWnd = NULL; | 
| + } | 
| + | 
| + m_hTabWnd = NULL; | 
| + m_hStatusBarWnd = NULL; | 
| + | 
| + // Remove instance from the list, shutdown threads | 
| + HANDLE hMainThread = NULL; | 
| + HANDLE hTabThread = NULL; | 
| + | 
| + s_criticalSectionLocal.Lock(); | 
| + { | 
| + s_instances.erase(this); | 
| + | 
| + std::map<DWORD,CPluginClass*>::iterator it = s_threadInstances.find(::GetCurrentThreadId()); | 
| + if (it != s_threadInstances.end()) | 
| { | 
| - if (pServiceProvider) | 
| - { | 
| - s_criticalSectionBrowser.Lock(); | 
| - { | 
| - HRESULT hr = pServiceProvider->QueryService(IID_IWebBrowserApp, &m_webBrowser2); | 
| - if (SUCCEEDED(hr)) | 
| - { | 
| - if (m_webBrowser2) | 
| - { | 
| - InitObject(false); | 
| - } | 
| - } | 
| - else | 
| - { | 
| - DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_SET_SITE, PLUGIN_ERROR_SET_SITE_QUERY_BROWSER, "Class::SetSite - QueryService (IID_IWebBrowserApp)"); | 
| - } | 
| - } | 
| - s_criticalSectionBrowser.Unlock(); | 
| - } | 
| + s_threadInstances.erase(it); | 
| } | 
| - else | 
| + if (s_instances.empty()) | 
| { | 
| - DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_SET_SITE, PLUGIN_ERROR_SET_SITE_QUERY_SERVICE_PROVIDER, "Class::SetSite - QueryInterface (service provider)"); | 
| + // TODO: Explicitly releasing a resource when a container becomes empty looks like a job better suited for shared_ptr | 
| + CPluginClientFactory::ReleaseMimeFilterClientInstance(); | 
| } | 
| } | 
| - } | 
| - catch (const std::runtime_error& ex) | 
| - { | 
| - DEBUG_EXCEPTION(ex); | 
| - Unadvice(); | 
| - } | 
| - } | 
| - else | 
| - { | 
| - // Unadvice | 
| - Unadvice(); | 
| + s_criticalSectionLocal.Unlock(); | 
| - // Destroy window | 
| - if (m_pWndProcStatus) | 
| - { | 
| - ::SetWindowLongPtr(m_hStatusBarWnd, GWLP_WNDPROC, (LPARAM)(WNDPROC)m_pWndProcStatus); | 
| + // Release browser interface | 
| + s_criticalSectionBrowser.Lock(); | 
| + { | 
| + m_webBrowser2.Release(); | 
| 
 
Eric
2015/03/06 15:58:04
Explicit release here.
 
sergei
2015/03/06 16:07:19
So, since `AddRef` is called and `m_webBrowser2` i
 
Eric
2015/03/06 16:27:22
Calling 'Release' through 'CComPtr' apparently als
 
 | 
| + } | 
| + s_criticalSectionBrowser.Unlock(); | 
| - m_pWndProcStatus = NULL; | 
| + DEBUG_GENERAL("================================================================================\nNEW TAB UI - END\n================================================================================") | 
| + | 
| + ::CoUninitialize(); | 
| } | 
| - if (m_hPaneWnd) | 
| - { | 
| - DestroyWindow(m_hPaneWnd); | 
| - m_hPaneWnd = NULL; | 
| - } | 
| - | 
| - m_hTabWnd = NULL; | 
| - m_hStatusBarWnd = NULL; | 
| - | 
| - // Remove instance from the list, shutdown threads | 
| - HANDLE hMainThread = NULL; | 
| - HANDLE hTabThread = NULL; | 
| - | 
| - 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 | 
| - CPluginClientFactory::ReleaseMimeFilterClientInstance(); | 
| - } | 
| - } | 
| - s_criticalSectionLocal.Unlock(); | 
| - | 
| - // Release browser interface | 
| - s_criticalSectionBrowser.Lock(); | 
| - { | 
| - m_webBrowser2.Release(); | 
| - } | 
| - s_criticalSectionBrowser.Unlock(); | 
| - | 
| - DEBUG_GENERAL("================================================================================\nNEW TAB UI - END\n================================================================================") | 
| - | 
| - ::CoUninitialize(); | 
| + IObjectWithSiteImpl<CPluginClass>::SetSite(unknownSite); | 
| } | 
| - | 
| - return IObjectWithSiteImpl<CPluginClass>::SetSite(unknownSite); | 
| + catch (...) | 
| + { | 
| + } | 
| + return S_OK; | 
| } | 
| bool CPluginClass::IsStatusBarEnabled() |