// synchronously send a string from Node to browser, then return string result from browser to Node Handle<Value> Window::SendSync(const Arguments& args) { HandleScope scope; NativeWindow *window = ObjectWrap::Unwrap<NativeWindow> (args.This()); if (window->GetBrowser()) { // find browser's v8 context CefRefPtr<CefV8Context> context = window->GetBrowser()->GetMainFrame()->GetV8Context(); // ensure it's usable and enter if (context.get() && context->Enter()) { // try to get "appjs.onmessage" function CefRefPtr<CefV8Value> appjsObject = context->GetGlobal()->GetValue("appjs"); CefRefPtr<CefV8Value> callback = appjsObject->GetValue("onmessage"); if (callback.get()) { // convert Node V8 string to Cef V8 string CefV8ValueList argsOut; argsOut.push_back(CefV8Value::CreateString(V8StringToChar(args[0]->ToString()))); // execute window.appjs fuction, passing in the string, // then convert the return value from a CefValue to a Node V8 string Handle<String> ret = CefStringToV8(callback->ExecuteFunction(appjsObject, argsOut)->GetStringValue()); // exit browser v8 context, return string result to Node caller context->Exit(); return scope.Close(ret); } } } // likely error condition return scope.Close(Undefined()); }
bool ClientApp::OnProcessMessageReceived( CefRefPtr<CefBrowser> browser, CefProcessId source_process, CefRefPtr<CefProcessMessage> message) { ASSERT(source_process == PID_BROWSER); bool handled = false; RenderDelegateSet::iterator it = render_delegates_.begin(); for (; it != render_delegates_.end() && !handled; ++it) { handled = (*it)->OnProcessMessageReceived(this, browser, source_process, message); } if (handled) return true; // Execute the registered JavaScript callback if any. if (!callback_map_.empty()) { CefString message_name = message->GetName(); CallbackMap::const_iterator it = callback_map_.find( std::make_pair(message_name.ToString(), browser->GetIdentifier())); if (it != callback_map_.end()) { // Keep a local reference to the objects. The callback may remove itself // from the callback map. CefRefPtr<CefV8Context> context = it->second.first; CefRefPtr<CefV8Value> callback = it->second.second; // Enter the context. context->Enter(); CefV8ValueList arguments; // First argument is the message name. arguments.push_back(CefV8Value::CreateString(message_name)); // Second argument is the list of message arguments. CefRefPtr<CefListValue> list = message->GetArgumentList(); CefRefPtr<CefV8Value> args = CefV8Value::CreateArray(static_cast<int>(list->GetSize())); SetList(list, args); arguments.push_back(args); // Execute the callback. CefRefPtr<CefV8Value> retval = callback->ExecuteFunction(NULL, arguments); if (retval.get()) { if (retval->IsBool()) handled = retval->GetBoolValue(); } // Exit the context. context->Exit(); } } return handled; }
bool FUnrealCEFSubProcessRemoteScripting::HandleExecuteJSFunctionMessage(CefRefPtr<CefListValue> MessageArguments) { FGuid Guid; // Message arguments are CallbackGuid, FunctionArguments, bIsError if (MessageArguments->GetSize() != 3 || MessageArguments->GetType(0) != VTYPE_STRING || MessageArguments->GetType(1) != VTYPE_LIST || MessageArguments->GetType(2) != VTYPE_BOOL) { // Wrong message argument types or count return false; } if (!FGuid::Parse(FString(MessageArguments->GetString(0).ToWString().c_str()), Guid)) { // Invalid GUID return false; } if (!CallbackRegistry.Contains(Guid)) { // Unknown callback id return false; } auto Callback = CallbackRegistry[Guid]; { ScopedV8Context ContextScope(Callback.Context); bool bIsErrorCallback = MessageArguments->GetBool(2); CefRefPtr<CefV8Value> Function = bIsErrorCallback?Callback.OnError:Callback.Function; if (!Function.get()) { // Either invalid entry or no error handler return false; } CefV8ValueList FunctionArguments; CefToV8Arglist(MessageArguments->GetList(1), FunctionArguments); CefRefPtr<CefV8Value> Retval = Function->ExecuteFunction(Callback.Object, FunctionArguments); if (!Retval.get()) { // Function call resulted in an error return false; } // Remove callback if it's a one-shot callback and successful. if (Callback.bOneShot) { CallbackRegistry.Remove(Guid); } return true; } }
bool ClientApp::OnProcessMessageReceived( CefRefPtr<CefBrowser> browser, CefProcessId source_process, CefRefPtr<CefProcessMessage> message) { ASSERT(source_process == PID_BROWSER); bool handled = false; // Execute delegate callbacks. RenderDelegateSet::iterator it = render_delegates_.begin(); for (; it != render_delegates_.end() && !handled; ++it) { handled = (*it)->OnProcessMessageReceived(this, browser, source_process, message); } if (!handled) { if (message->GetName() == "invokeCallback") { // This is called by the appshell extension handler to invoke the asynchronous // callback function CefRefPtr<CefListValue> messageArgs = message->GetArgumentList(); int32 callbackId = messageArgs->GetInt(0); CefRefPtr<CefV8Context> context = callback_map_[callbackId].first; CefRefPtr<CefV8Value> callbackFunction = callback_map_[callbackId].second; CefV8ValueList arguments; context->Enter(); // Sanity check to make sure the context is still attched to a browser. // Async callbacks could be initiated after a browser instance has been deleted, // which can lead to bad things. If the browser instance has been deleted, don't // invoke this callback. if (context->GetBrowser()) { for (size_t i = 1; i < messageArgs->GetSize(); i++) { arguments.push_back(ListValueToV8Value(messageArgs, i)); } callbackFunction->ExecuteFunction(NULL, arguments); } context->Exit(); callback_map_.erase(callbackId); } else if (message->GetName() == "executeCommand") { // This is called by the browser process to execute a command via JavaScript // // The first argument is the command name. This is required. // The second argument is a message id. This is optional. If set, a response // message will be sent back to the browser process. CefRefPtr<CefListValue> messageArgs = message->GetArgumentList(); CefString commandName = messageArgs->GetString(0); int messageId = messageArgs->GetSize() > 1 ? messageArgs->GetInt(1) : -1; bool handled = false; StContextScope ctx(browser->GetMainFrame()->GetV8Context()); CefRefPtr<CefV8Value> global = ctx.GetContext()->GetGlobal(); if (global->HasValue("brackets")) { CefRefPtr<CefV8Value> brackets = global->GetValue("brackets"); if (brackets->HasValue("shellAPI")) { CefRefPtr<CefV8Value> shellAPI = brackets->GetValue("shellAPI"); if (shellAPI->HasValue("executeCommand")) { CefRefPtr<CefV8Value> executeCommand = shellAPI->GetValue("executeCommand"); if (executeCommand->IsFunction()) { CefRefPtr<CefV8Value> retval; CefV8ValueList args; args.push_back(CefV8Value::CreateString(commandName)); retval = executeCommand->ExecuteFunction(global, args); if (retval) { handled = retval->GetBoolValue(); } } } } } // Return a message saying whether or not the command was handled if (messageId != -1) { CefRefPtr<CefProcessMessage> result = CefProcessMessage::Create("executeCommandCallback"); result->GetArgumentList()->SetInt(0, messageId); result->GetArgumentList()->SetBool(1, handled); browser->SendProcessMessage(PID_BROWSER, result); } } } return handled; }