2013-09-30 33 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