Как вызвать метод CefV8Context :: Eval () в процессе браузера?

Я хочу вызвать функцию CefV8Context :: Eval и получить возвращенное значение в потоке пользовательского интерфейса процесса браузера. Но Документы CEF3 C ++ API утверждают, что к дескрипторам V8 можно получить доступ только из потока, в котором они созданы. К допустимым потокам для создания дескриптора V8 относятся основной поток процесса рендеринга (TID_RENDERER) и потоки WebWorker. Означает ли это, что я должен использовать межпроцессное взаимодействие (CefProcessMessage) для вызова этого метода и получения возвращаемого значения? Если да, то как это сделать в синхронном режиме?

1

Решение

Короткий ответ: CefFrame::ExecuteJavaScript для простых запросов будет работать. Для более сложных вы должны отказаться от одного уровня синхронности или использовать пользовательский цикл сообщений.


Насколько я понимаю, вы хотите выполнить код Javascript как часть потока пользовательского интерфейса вашего собственного приложения. Есть две возможности:

  1. Это общий код JS, на самом деле он не имеет доступа к каким-либо переменным или функциям в вашем JS и поэтому не имеет контекст. Это означает, что Cef может просто раскрутить новый контекст V8 и выполнить ваш код — смотрите CefFrame::ExecuteJavaScript(), Цитировать примеры на Интеграционная ссылка JS CEF:

    CefRefPtr browser = …;
    CefRefPtr frame = browser-> GetMainFrame ();
    frame-> ExecuteJavaScript («alert (‘ExecuteJavaScript работает!’);»,
    frame-> GetURL (), 0);

  2. Это код JS с контекстом. В этом случае читайте дальше.

да — CEF разработан таким образом, что только RenderProcess имеет доступ к движку V8, вам придется использовать CefProcessMessage чтобы перейти к браузеру и выполнить оценку там. Похоже, вы уже знаете, как это сделать. Я свяжу свой ответ для тех, кто не знает и может наткнуться на это позже: Фоновый процесс на встроенной функции в Chromium Embedded Framework

CEFProcessMessage от процессов Browser до Render — это единственное место, где запрос должен быть синхронизирован.

Поэтому после того, как вы отправите свою логику в процесс рендеринга, вам нужно будет выполнить фактическое выполнение кода javascript. К счастью, это довольно просто — та же ссылка на интеграцию JS продолжает:

Собственный код может выполнять функции JS с помощью ExecuteFunction ()
и методы ExecuteFunctionWithContext ()

Лучшая часть — выполнение кажется синхронным (я говорю, кажется, так как я не могу найти конкретные документы по этому вопросу). Использование в примерах иллюстрирует это:

if (callback_func_->ExecuteFunctionWithContext(callback_context_, NULL, args, retval, exception, false)) {
if (exception.get()) {
// Execution threw an exception.
} else {
// Execution succeeded.
}
}

Вы заметите, что вторая строка предполагает, что первая закончила выполнение и что результаты указанного выполнения доступны для нее. Так, Вызов CefV8Value :: ExecuteFunction () по своей природе является синхронным.

Таким образом, вопрос сводится к — Как синхронно опубликовать CefProcessMessage из браузера в процесс рендерера?. К сожалению, сам класс не создан для этого. Более того, Вики-страница МПК явно запрещает это:

Некоторые сообщения должны быть синхронными с точки зрения средства визуализации.
В основном это происходит, когда нам звонят из WebKit
вернуть что-то, но это мы должны сделать в браузере. Примеры
сообщения такого типа проверяют орфографию и получают файлы cookie для
JavaScript. Синхронный IPC от браузера к рендереру запрещен
предотвратить блокировку пользовательского интерфейса на потенциально нестабильном рендерере.

Это такое большое дело? Ну, я действительно не знаю, так как я не сталкивался с этой необходимостью — для меня это нормально, поскольку цикл обработки сообщений в браузере будет продолжать вращаться в ожидании чего-либо, и ничего не получит, пока ваш рендерер не отправит сообщение процесса с результаты JS. Единственный способ, которым браузер заставляет что-то делать, — это когда происходит какое-то взаимодействие, а это невозможно, поскольку средство визуализации блокирует.

Если ты действительно определенно нужна синхронность, я бы порекомендовал вам использовать свой собственный MessageLoop, который вызывает CefDoMessageLoopWork() на каждой итерации. Таким образом, вы можете установить флаг, чтобы приостановить работу цикла, пока ваше сообщение не будет получено от средства визуализации. Обратите внимание, что CefDoMessageLoopWork() а также CefRunMessageLoop() являются взаимоисключающий и не могут работать друг с другом — вы либо сами управляете циклом, либо позволяете CEF сделать это за вас.

Это было долго и охватывает большую часть того, что вы, возможно, захотите сделать — надеюсь, это поможет!

8

Другие решения


По вопросам рекламы ammmcru@yandex.ru
Adblock
detector