2013-09-30 375 views
2

我特林创建一个JavaScript对象将其传递给函数回调像以下:C++中的自定义线程创建CEF对象

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)始终返回null结果。我想这是因为代码是运行自定义线程,因为一些任务必须在特殊线程中执行。

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

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

更新

我加入UI线程切换。之后,我总是在cef_v8value_create_object中出现“Access violation reading location”异常,例如the Hzmy's quiestion

+0

会惊喜我,如果V8是线程安全的(当然,一个单一实例),或者甚至线程感知。你尝试过只是添加锁定? – sehe

+0

锁定并没有帮助,因为v8只是创建一个null对象:( – JohanTG

回答

1

的chromiumembedded文档包含以下内容:

所以,你应该与之前型号的JavaScript你的行动右侧contect切换。 如果V8当前不在上下文中,或者您需要检索并存储对上下文的引用,则可以使用两个可用的CefV8Context静态方法之一。 GetCurrentContext()返回当前正在执行JS的框架的上下文。 GetEnteredContext()返回JS执行开始帧的上下文。例如,如果frame1中的函数调用frame2中的函数,那么当前上下文将是frame2,输入的上下文将是frame1。

只有当V8位于上下文内时,才可以创建,修改数组,对象和函数,并且在函数的情况下执行。如果V8不在上下文中,则应用程序需要通过调用Enter()来输入上下文,并通过调用Exit()来退出上下文。只应使用Enter()和Exit()方法:

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

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

所以这就是为什么我不能创建一个对象,但能够创造JS字符串。 你也可以看到the general usage example

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

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

    callbackCtxt->Exit(); 
} 
+0

因此,您将任务发布到TID_RENDERER并进入上下文,对吧? – fddima

+0

我已经发布了任务到UI线程(TID_UI)。什么是TID_RENDERER? – JohanTG

+0

TID_UI是CEF1中V8的有效线程。 TID_RENDERER是CEF3中V8的有效线程,而渲染器通常是单独的进程, - 此进程根本没有TID_UI线程。 – fddima

3

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

您可能会错过How to use V8 JavaScript integration in client applications wiki页面。

随着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

+0

正是!我已经实现了回调函数,但是我不能调用它,因为我读了文章,并且没有找到如何切换到必要的线程? – JohanTG

+0

如果你需要在特定的线程上发布一些工作 - 你可以使用CEF任务来做这件事,看看CefPostTask的方法,但我不确定你是否清楚描述你的需求,也不会忘记V8的上下文 – fddima

+0

是啊!然后我得到了与[嵌入式框架:使用“ExecuteFunctionWithContext”时创建对象失败]相同的结果(http://stackoverflow.com/questions/9880217/chromium-embedded-framework-creating-an-object-fails- when-using-executefunctio):cef_v8value_create_object中的“访问冲突读取位置” – JohanTG