Сбой при выгрузке CEF

#c #chromium-embedded

#c #встроенный в chromium

Вопрос:

Мы хотим показать некоторые окна браузера из библиотеки dll MFC (Visual Studio 2015). К сожалению, как только мы выгружаем CEF, он вылетает. Мы нашли очень похожие вопросы, но так и не получили ответа.

Чтобы лучше рассмотреть проблему, мы переместили все содержимое CEF в другую dll (cefwrapper). Это основные шаги, которые мы в основном делаем:

 1.  LoadLibrary(cefwrapper.dll) 
2.  Inside cefwrapper.dll
    a.  CefString(amp;settings.browser_subprocess_path) = "cefsimple.exe"
    b.  CefInitialize(args, settings, this, NULL)
    c.  window_info.SetAsChild(hwnd, rect);
    d.  browser_ = CefBrowserHost::CreateBrowserSync(window_info, browser_client_.get(), url, browser_settings, request_context);
    e.  ::SetParent(browser_->GetHost()->GetWindowHandle(), NULL); // Prevent getting a CLOSE Message
    f.  CloseBrowser();
    g.  Waiting until OnBeforeClose was called for all browsers.
    h.  CefShutdown();
    i.  (all sub-processes (cefsimple.exe) are gone by now)
3.  FreeLibrary --> Crash
  

Стек вызовов

 libcef.dll!sandbox::BrokerServicesBase::~BrokerServicesBase() Line 135  C  
libcef.dll!sandbox::SingletonBase<sandbox::BrokerServicesBase>::OnExit() Line 63    C  
libcef.dll!_execute_onexit_table::__l2::<lambda>() Line 206 C  
libcef.dll!__crt_seh_guarded_call<int>::operator()<<lambda_7777bce6b2f8c936911f934f8298dc43>,int <lambda>(void) amp; __ptr64,<lambda_3883c3dff614d5e0c5f61bb1ac94921c> >(__acrt_lock_and_call::__l2::<lambda_7777bce6b2f8c936911f934f8298dc43> amp;amp; setup, _execute_onexit_table::__l2::int <lambda>(void) amp; action, __acrt_lock_and_call::__l2::<lambda_3883c3dff614d5e0c5f61bb1ac94921c> amp;amp; cleanup) Line 204  C  
libcef.dll!_execute_onexit_table(_onexit_table_t * table) Line 231  C  
libcef.dll!common_exit::__l2::<lambda>() Line 230   C  
libcef.dll!__crt_seh_guarded_call<void>::operator()<<lambda_d80eeec6fff315bfe5c115232f3240e3>,void <lambda>(void) amp; __ptr64,<lambda_2358e3775559c9db80273638284d5e45> >(__acrt_lock_and_call::__l2::<lambda_d80eeec6fff315bfe5c115232f3240e3> amp;amp; setup, common_exit::__l2::void <lambda>(void) amp; action, __acrt_lock_and_call::__l2::<lambda_2358e3775559c9db80273638284d5e45> amp;amp; cleanup) Line 224 C  
libcef.dll!common_exit(const int return_code, const _crt_exit_cleanup_mode cleanup_mode, const _crt_exit_return_mode return_mode) Line 278  C  
  

Отсутствие вызова FreeLibrary отложит проблему до момента завершения работы приложения.

Мы используем cef_binary_73.1.12 gee4b49f chromium-73.0.3683.75_windows64

В качестве альтернативы мы начали cefsimple.exe через CreateProcess и передал hwnd этому процессу. К сожалению, через некоторое время окно браузера зависает.

Комментарии:

1. Вы уверены, что в момент выгрузки / выхода нет живых объектов cef и нет ссылок на статические данные или функции из cef?

2. После вызова Shutdown() все еще выполняются некоторые потоки. Например, BrokerEvent libcef.dll !песочница::База брокерских услуг::TargetEventsThread, TaskSchedulerServiceThread libcef.dll !base::`анонимное пространство имен’::waitUntil, CacheThread_BlockFile libcef.dll !база::MessagePumpForIO::WaitForIOCompletion, …)

Ответ №1:

Никогда не вызывайте FreeLibrary CEF DLL.

В Chromium есть много глобальных объектов (одиночек, служебных потоков), которые должны быть активными до конца приложения. Это сделано для более быстрого завершения работы приложения: глобальные объекты и одиночные элементы не удаляются, потоки не завершаются, никто не беспокоится об этом при завершении процесса.

При вызове вы FreeLibrary повреждаете эту архитектуру. Потоки, запущенные из CEF, остаются активными, но память DLL освобождается. Таким образом, вы получаете сбой.

Чтобы исправить это, просто не выполняйте шаг 3.

Комментарии:

1. Спасибо за ваш вклад. Это разрушает мои надежды найти решение. Мы инициализируем CEF внутри dll. Эта dll может загружаться и выгружаться во время выполнения нашими клиентами. Как только dll выгружается, происходит сбой cef, независимо от того, выполняем мы шаг 3 или нет.

2. Не имеет значения, откуда вызывается CefInititialize. Кажется, некоторые ссылки на объекты CEF из вашего приложения все еще существуют после CefShutdown.