cefsimple. How to add the window.cefQuery

Having problems with building or using CEF's C/C++ APIs? This forum is here to help. Please do not post bug reports or feature requests here.

cefsimple. How to add the window.cefQuery

Postby maxktutby » Tue Apr 14, 2020 10:38 am

I was having difficulty extending the cefsimple example to provide additional functionality (JavaScript window.cefQuery).
(windows x32, cef/chromium 73.0.3683.75, VS 21015)
As specified in cef_message_router.h
1. Updated simple_app.h
Code: Select all
...
#include "include/wrapper/cef_message_router.h" // Add cefQuery
...
class SimpleApp : public CefApp,
   public CefRenderProcessHandler, // Add cefQuery
   public CefBrowserProcessHandler {
...
  // Add cefQuery
  virtual void OnRenderProcessThreadCreated(CefRefPtr<CefListValue> extra_info) OVERRIDE {
     CefMessageRouterConfig config; // YES
     renderer_side_router_ = CefMessageRouterRendererSide::Create(config);
  }

  // CefApp methods:
  CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() OVERRIDE {
     return this;
  }
  // CefRenderProcessHandler methods:
  void OnWebKitInitialized() OVERRIDE {
     // Create the renderer-side router for query handling.
     //CefMessageRouterConfig config;
     //message_router_ = CefMessageRouterRendererSide::Create(config);
  }
  void OnContextCreated(CefRefPtr<CefBrowser> browser,
     CefRefPtr<CefFrame> frame,
     CefRefPtr<CefV8Context> context) OVERRIDE {
     renderer_side_router_->OnContextCreated(browser, frame, context); //+
  }
  void OnContextReleased(CefRefPtr<CefBrowser> browser,
     CefRefPtr<CefFrame> frame,
     CefRefPtr<CefV8Context> context) OVERRIDE {
     renderer_side_router_->OnContextReleased(browser, frame, context);  //+
  }
  bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
     CefProcessId source_process,
     CefRefPtr<CefProcessMessage> message) OVERRIDE {
     return renderer_side_router_->OnProcessMessageReceived(browser, source_process, message); //+
  }
...
 private:
  CefRefPtr<CefMessageRouterRendererSide> renderer_side_router_; // Add cefQuery
...
}

2. Updated simple_handler.h
Code: Select all
...
#include "include/wrapper/cef_message_router.h"  // Add cefQuery
...
// Add cefQuery
const char kPrompt[] = "SendCommand";
class TestHandler : public CefMessageRouterBrowserSide::Handler {
public:
   TestHandler() {}
   // Called due to cefQuery execution.
   virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
      CefRefPtr<CefFrame> frame,
      int64 query_id,
      const CefString& request,
      bool persistent,
      CefRefPtr<Callback> callback) OVERRIDE {
      // Parse |request| which takes the form "Prompt.[type]:[value]".
      LOG(ERROR) << "++++ OnQuery start";
      const std::string& request_str = request;
      if (request_str.find(kPrompt) != 0)
         return false;

      // Nothing is done with the response.
      callback->Success(CefString());
      return true;
   }
};
...
class SimpleHandler : public CefClient,
...
                      public CefLoadHandler {
 public:
...
  bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, // Add cefQuery
     CefProcessId source_process,
     CefRefPtr<CefProcessMessage> message) OVERRIDE;
  bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,  // Add cefQuery
     CefRefPtr<CefFrame> frame,
     CefRefPtr<CefRequest> request,
     bool user_gesture,
     bool is_redirect) OVERRIDE;
  void OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser,   // Add cefQuery
     TerminationStatus status) OVERRIDE;
...
 private:
    CefRefPtr<CefMessageRouterBrowserSide> browser_side_router_; // Add cefQuery
    scoped_ptr<CefMessageRouterBrowserSide::Handler> testHandler_; // Add cefQuery
...
}


3. Updated simple_handler.cc
Code: Select all
...
void SimpleHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
  CEF_REQUIRE_UI_THREAD();

  // Add cefQuery
  if (!browser_side_router_) { //+ YES
     // как в описании
     CefMessageRouterConfig config;
     config.js_query_function = "cefQuery";
     config.js_cancel_function = "cefQueryCancel";
     browser_side_router_ = CefMessageRouterBrowserSide::Create(config);
     //testHandler_ = new TestHandler();
     testHandler_.reset(new TestHandler());
     browser_side_router_->AddHandler(testHandler_.get(), true);
     }
    
  // Add to the list of existing browsers.
  browser_list_.push_back(browser);
}
...
bool SimpleHandler::OnProcessMessageReceived(   // Add cefQuery
   CefRefPtr<CefBrowser> browser,
   CefProcessId source_process,
   CefRefPtr<CefProcessMessage> message) {
   CEF_REQUIRE_UI_THREAD();
   browser_side_router_->OnProcessMessageReceived(browser, source_process, message); //+
   return false;
}

bool SimpleHandler::OnBeforeBrowse(CefRefPtr<CefBrowser> browser, // Add cefQuery
   CefRefPtr<CefFrame> frame,
   CefRefPtr<CefRequest> request,
   bool user_gesture,
   bool is_redirect) {
   CEF_REQUIRE_UI_THREAD();

   browser_side_router_->OnBeforeBrowse(browser, frame); //+ YES
   return false;
}

void SimpleHandler::OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser,  // Add cefQuery
   TerminationStatus status) {
   CEF_REQUIRE_UI_THREAD();

   browser_side_router_->OnRenderProcessTerminated(browser); //+
}
...

In debug mode, I can see that they are running
1. SimpleHandler::OnAfterCreated
2. SimpleHandler::OnBeforeBrowse
3. OnRenderProcessThreadCreated /*SimpleApp*/
When you call the JavaScript
Code: Select all
function sendMessage() {
  window.cefQuery({
    request: 'TestWeb: Test string',
    onSuccess: function(response) {
   console.log("++++ work cefQuery");
    },
    onFailure: function(error_code, error_message) {}
  });
}

I'm getting a message "Uncaught TypeError: window.cefQuery is not a function"
This does not call any other functions of the SimpleApp class containing renderer_side_router_ ->..., or of the SimpleHandler class containing browser_side_router_->... and the OnQuery function.

What am I wrong about?
Why window.cefQuery is missing for JavaScript?
maxktutby
Newbie
 
Posts: 5
Joined: Sun Dec 23, 2018 4:32 pm

Re: cefsimple. How to add the window.cefQuery

Postby magreenblatt » Tue Apr 14, 2020 11:57 am

Are you passing the CefApp instance to CefExecuteProcess? See also the example at https://bitbucket.org/chromiumembedded/ ... ge_router/
magreenblatt
Site Admin
 
Posts: 10919
Joined: Fri May 29, 2009 6:57 pm

Re: cefsimple. How to add the window.cefQuery

Postby maxktutby » Wed Apr 15, 2020 7:22 am

Thank you for your comment. I didn't change it cefsimple_win.cc, which uses a call sequence
Code: Select all
...
  int exit_code = CefExecuteProcess(main_args, NULL, sandbox_info);
  if (exit_code >= 0) {
    // The sub-process has completed so return here.
    return exit_code;
  }
...
  CefRefPtr<SimpleApp> app(new SimpleApp);

  // Initialize CEF.
  CefInitialize(main_args, settings, app.get(), sandbox_info);
...

I changed the code as follows
Code: Select all
...
  CefRefPtr<SimpleApp> app(new SimpleApp);

  int exit_code = CefExecuteProcess(main_args, app.get(), sandbox_info);
  if (exit_code >= 0) {
    // The sub-process has completed so return here.
    return exit_code;
  }

  // Initialize CEF.
  CefInitialize(main_args, settings, app.get(), sandbox_info);
...

but this did not help to get rid of the error "Uncaught TypeError: window.cefQuery is not a function"

I took your advice with the message_router example. To solve my problem, it was easier to rework this example.

I do not plan to continue the cefsimple theme with the addition of the window.cefQuery feature.

Thank you again for your help.
maxktutby
Newbie
 
Posts: 5
Joined: Sun Dec 23, 2018 4:32 pm

Re: cefsimple. How to add the window.cefQuery

Postby payalord » Wed Apr 15, 2020 7:44 pm

Why just not do it like this?
Code: Select all
// ClientApp.cpp
#include "ClientApp.h"

#include "ClientHandler.h"
#include "ClientV8ExtensionHandler.h"

ClientApp::ClientApp()
{
   
}

ClientApp::~ClientApp()
{
   
}

void ClientApp::OnWebKitInitialized()
{
    std::string app_code =
        "var app;"
        "if (!app)"
        "    app = {};"
        "(function() {"
        "    app.ChangeTextInJS = function(text) {"
        "        native function ChangeTextInJS();"
        "        return ChangeTextInJS(text);"
        "    };"
        "})();;";
    CefRegisterExtension( "v8/app", app_code, new ClientV8ExtensionHandler(this) );
}

Code: Select all
// ClientV8ExtensionHandler.cpp
#include "ClientV8ExtensionHandler.h"

ClientV8ExtensionHandler::ClientV8ExtensionHandler(CefRefPtr<CefApp> app)
{
    this->app = app;
}

bool ClientV8ExtensionHandler::Execute(const CefString &name, CefRefPtr<CefV8Value> object, const CefV8ValueList &arguments, CefRefPtr<CefV8Value> &retval, CefString &exception)
{
    if (name == "ChangeTextInJS") {
        if ( (arguments.size() == 1) && arguments[0]->IsString() ) {
            CefString           text   = arguments[0]->GetStringValue();
            CefRefPtr<CefFrame> frame  = CefV8Context::GetCurrentContext()->GetBrowser()->GetMainFrame();
            std::string         jscall = "ChangeText('";
            jscall += text;
            jscall += "');";
            frame->ExecuteJavaScript(jscall, frame->GetURL(), 0);
            /*
             * If you want your method to return a value, just use retval, like this:
             * retval = CefV8Value::CreateString("Hello World!");
             * you can use any CefV8Value, what means you can return arrays, objects or whatever you can create with CefV8Value::Create* methods
             */
            return true;
        }
    }

    return false;
}

So then you can easily call window.app.ChangeTextInJS or whatever function you want to add there, with no problems?
payalord
Techie
 
Posts: 21
Joined: Sun Jan 07, 2018 8:21 am


Return to Support Forum

Who is online

Users browsing this forum: No registered users and 11 guests