2

I'm tring to create a javascript object to pass it to a function-callback like following:

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.
        }
    }
}

But CefV8Value::CreateObject(NULL) always returns null result. I guess that happens because the code is run in a custom thread, for some tasks have to be performed in a special thread.

Am I right? And how to switch to cef thread to work with V8 engine and syncronise with it?

Am I wrong? And why V8 creates a null object?

Updated

I have added UI thread switching. After that I always have "Access violation reading location" exception in cef_v8value_create_object like in the Hzmy's quiestion.

Community
  • 1
  • 1
JohanTG
  • 1,304
  • 1
  • 13
  • 19
  • it would suprise me if V8 were threadsafe (well, a single instance) or even thread-aware. Have you tried just adding locking? – sehe Sep 30 '13 at 07:26
  • locking doesn't help because v8 just creates a null object :( – JohanTG Sep 30 '13 at 07:29

2 Answers2

3

In short: you must access to V8 only from valid thread.

You probably miss How to use V8 JavaScript integration in client applications wiki page.

With CEF3 WebKit and JS execution run in a separate renderer process. The main thread in a renderer process is identified as TID_RENDERER and all V8 execution must take place on this thread. JS APIs that communicate between the browser and renderer processes should be designed using asynchronous callbacks. See http://www.chromium.org/developers/design-documents/extensions/how-the-extension-system-works/api-pattern-design-doc for an example.

Eugen
  • 500
  • 6
  • 13
Dmitry Azaraev
  • 1,075
  • 6
  • 8
  • Exactly! And I have implemented the callback function. But I cannot call it. Of couse I read the article and I didn't find how to switch to necessary thread? – JohanTG Sep 30 '13 at 08:49
  • If you need post some job on specific thread - you can use CEF tasks for this. Look on CefPostTask method. But i'm not sure that you are clear describe your requirements. Also did not forget about V8 contexts. – Dmitry Azaraev Sep 30 '13 at 12:04
  • Yeah! And then I have the same result as [Chromium embedded framework: Creating an object fails when using "ExecuteFunctionWithContext"](http://stackoverflow.com/questions/9880217/chromium-embedded-framework-creating-an-object-fails-when-using-executefunctio): "Access violation reading location" in cef_v8value_create_object. – JohanTG Oct 01 '13 at 04:31
  • As i'm say - you must not forget about V8 contexts. Sorry, in general you question and self answer still not clear for follow readers. – Dmitry Azaraev Oct 01 '13 at 08:57
  • Thx, I'll take into account) – JohanTG Oct 02 '13 at 05:47
1

The chromiumembedded documentation contains following:

So you should switch on the right contect before your actions with javascript model. If V8 is not currently inside a context, or if you need to retrieve and store a reference to a context, you can use one of two available CefV8Context static methods. GetCurrentContext() returns the context for the frame that is currently executing JS. GetEnteredContext() returns the context for the frame where JS execution began. For example, if a function in frame1 calls a function in frame2 then the current context will be frame2 and the entered context will be frame1.

Arrays, objects and functions may only be created, modified and, in the case of functions, executed, if V8 is inside a context. If V8 is not inside a context then the application needs to enter a context by calling Enter() and exit the context by calling Exit(). The Enter() and Exit() methods should only be used:

  1. When creating a V8 object, function or array outside of an existing context. For example, when creating a JS object in response to a native menu callback.

  2. When creating a V8 object, function or array in a context other than the current context. For example, if a call originating from frame1 needs to modify the context of frame2.

So that's why I couldn't create an object but was able to create js strings. Also you could see the general usage example.

And the following code solves the problem:

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

    callbackCtxt->Exit();
}
Eugen
  • 500
  • 6
  • 13
JohanTG
  • 1,304
  • 1
  • 13
  • 19