2

我正在尝试创建一个 javascript 对象以将其传递给函数回调,如下所示:

void MyClass::ThreadTaskOnSuccess(CefRefPtr<CefV8Value> callback, CefRefPtr<CefV8Context> callbackCtxt)
{
    if (!CefCurrentlyOn(TID_UI))
    {
        // switch to UI thread
        CefPostTask(TID_UI, NewCefRunnableMethod(this, &NewDownloadObject::CreateTempDownloadOnSuccess, callback, callbackCtxt));
        return;
    }
    // String creation works perfect!
    // CefRefPtr<CefV8Value> executionResult = CefV8Value::CreateString("test");

    // "Access violation" will be thrown
    CefRefPtr<CefV8Value> executionResult = CefV8Value::CreateObject(NULL);

    executionResult->SetValue("size", CefV8Value::CreateInt(123), V8_PROPERTY_ATTRIBUTE_NONE);
    executionResult->SetValue("fileName", CefV8Value::CreateString("some name of file"), V8_PROPERTY_ATTRIBUTE_NONE);

    CefV8ValueList args;
    args.push_back(executionResult);
    CefRefPtr<CefV8Value> retval;
    CefRefPtr<CefV8Exception> exception;
    if (callback->ExecuteFunctionWithContext(callbackCtxt, callbackCtxt->GetGlobal(), args, retval, exception, false))
    {
        if (exception.get())
        {
            throw CFdmException(exception->GetMessage().c_str());
        }
        else
        {
            // Execution succeeded.
        }
    }
}

但是 CefV8Value::CreateObject(NULL) 总是返回空结果。我猜这是因为代码是在自定义线程中运行的,因为某些任务必须在特殊线程中执行。

我对吗?以及如何切换到cef线程与V8引擎一起工作并与之同步?

我错了吗?为什么 V8 会创建一个空对象?

更新

我添加了 UI 线程切换。之后,我总是在 cef_v8value_create_object 中出现“访问冲突读取位置”异常,就像在Hzmy 的 quiestion中一样。

4

2 回答 2

3

简而言之:您必须只能从有效线程访问 V8。

您可能会错过如何在客户端应用程序wiki 页面中使用 V8 JavaScript 集成。

使用 CEF3 WebKit 和 JS 执行在单独的渲染器进程中运行。渲染器进程中的主线程被标识为 TID_RENDERER,并且所有 V8 执行都必须在此线程上进行。在浏览器和渲染器进程之间进行通信的 JS API 应该使用异步回调来设计。有关示例,请参见http://www.chromium.org/developers/design-documents/extensions/how-the-extension-system-works/api-pattern-design-doc 。

于 2013-09-30T08:21:41.007 回答
1

chromiumembedded 文档包含以下内容:

因此,您应该在使用 javascript 模型进行操作之前打开正确的连接。如果 V8 当前不在上下文中,或者如果您需要检索和存储对上下文的引用,则可以使用两种可用的 CefV8Context 静态方法之一。GetCurrentContext() 返回当前正在执行 JS 的框架的上下文。GetEnteredContext() 返回开始执行 JS 的帧的上下文。例如,如果 frame1 中的函数调用 frame2 中的函数,则当前上下文将为 frame2,输入的上下文将为 frame1。

如果 V8 在上下文中,则只能创建、修改和执行数组、对象和函数(如果是函数)。如果 V8 不在上下文中,则应用程序需要通过调用 Enter() 进入上下文并通过调用 Exit() 退出上下文。Enter() 和 Exit() 方法只能用于:

  1. 在现有上下文之外创建 V8 对象、函数或数组时。例如,在创建 JS 对象以响应本机菜单回调时。

  2. 在当前上下文之外的上下文中创建 V8 对象、函数或数组时。例如,如果来自 frame1 的调用需要修改 frame2 的上下文。

这就是为什么我无法创建对象但能够创建 js 字符串的原因。您还可以看到一般用法示例

下面的代码解决了这个问题:

if (callbackCtxt.get() && callbackCtxt->Enter())
{
    CefRefPtr<CefV8Value> object = CefV8Value::CreateObject(NULL);
    // call ExecuteFunctionWithContext and perform other actions

    callbackCtxt->Exit();
}
于 2013-10-01T07:07:10.000 回答