@@ -55,6 +55,24 @@ namespace CefSharp
5555 return this ;
5656 };
5757
58+ ref struct CefBrowserWrapperUpdater
59+ {
60+ CefBrowserWrapper^ _capture;
61+ CefAppUnmanagedWrapper& _wrapper;
62+ CefBrowserWrapperUpdater (CefBrowserWrapper^ capture, CefAppUnmanagedWrapper& wrapper) :
63+ _capture (capture),
64+ _wrapper (wrapper) {
65+ }
66+
67+ public:
68+ CefBrowserWrapper^ update(int key, CefBrowserWrapper^ oldValue)
69+ {
70+ _wrapper._onBrowserDestroyed ->Invoke (oldValue);
71+ delete oldValue;
72+ return _capture;
73+ }
74+ };
75+
5876 // CefRenderProcessHandler
5977 void CefAppUnmanagedWrapper::OnBrowserCreated (CefRefPtr<CefBrowser> browser, CefRefPtr<CefDictionaryValue> extraInfo)
6078 {
@@ -63,7 +81,14 @@ namespace CefSharp
6381
6482 // Multiple CefBrowserWrappers created when opening popups
6583 auto browserId = browser->GetIdentifier ();
66- _browserWrappers->TryAdd (browserId, wrapper);
84+
85+ // In some cases CEF recreates the browser with identical id instead of making a new one
86+ // If this happens it will call OnBrowserCreated a second time before calling OnBrowserDestroyed for the first browser
87+ // We need to check if the browser wrapper with given id already exists and if it does destroy it before adding the new one
88+ // https://github.com/chromiumembedded/cef/blob/ffa86e361d9c210136b539953663526add56191e/include/cef_render_process_handler.h#L67
89+ auto updater = gcnew CefBrowserWrapperUpdater (wrapper, *this );
90+ auto updateFunc = gcnew Func<int , CefBrowserWrapper^, CefBrowserWrapper^>(updater, &CefBrowserWrapperUpdater::update);
91+ _browserWrappers->AddOrUpdate (browserId, wrapper, updateFunc);
6792
6893 static gcroot<Func<int , JavascriptBindingSettings^>^> factory =
6994 gcnew Func<int , JavascriptBindingSettings^>(CefAppUnmanagedWrapper::JavascriptBindingSettingsFactory);
@@ -136,11 +161,20 @@ namespace CefSharp
136161
137162 void CefAppUnmanagedWrapper::OnBrowserDestroyed (CefRefPtr<CefBrowser> browser)
138163 {
139- CefBrowserWrapper^ wrapper;
140- if (_browserWrappers->TryRemove (browser->GetIdentifier (), wrapper))
141- {
142- _onBrowserDestroyed->Invoke (wrapper);
143- delete wrapper;
164+ int browserId = browser->GetIdentifier ();
165+ CefBrowserWrapper^ currentValue;
166+ if (_browserWrappers->TryGetValue (browserId, currentValue)) {
167+ // Check if another wrapper hasn't already taken our place
168+ if (currentValue->IsSameBrowser (browser)) {
169+ CefBrowserWrapper^ wrapper;
170+ // This is technically a race condition since the entry for browser id might have changed between TryGetValue
171+ // and TryRemove. No clear way to fix this with ConcurrentDictionary
172+ if (_browserWrappers->TryRemove (browserId, wrapper))
173+ {
174+ _onBrowserDestroyed->Invoke (wrapper);
175+ delete wrapper;
176+ }
177+ }
144178 }
145179
146180 // Don't remove javascript settings because cef is unreliable in calling OnBrowserCreated/OnBrowserDestroyed consistently:
0 commit comments