window.cefQuery is not a function

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.

window.cefQuery is not a function

Postby BorjaPascual » Mon Jan 30, 2023 11:33 am

Greetings,

I am afraid I'm a CEF newbie here. I'm sure this has been asked a few times, but I'm having a hard time finding a solution. I have been modifying the cefsimple project so that it accepts a custom handler, pointing to local files (which works like charm), as well as messaging between C++ and JS. This last part is where I am having some trouble. I'm getting the dreaded "window.cefQuery is not a function" and, no matter how much I compare my code and the one in the message_router project, I cannot find where I'm failing.

Here is my client:

Code: Select all
void PlatformTitleChange(CefRefPtr<CefBrowser> browser,
                         const CefString& title) {
  CefWindowHandle hwnd = browser->GetHost()->GetWindowHandle();
  SetWindowText(hwnd, std::wstring(title).c_str());
}

// Handle messages in the browser process.
class MessageHandler : public CefMessageRouterBrowserSide::Handler {
 public:
  explicit MessageHandler() {}

  // Called due to cefQuery execution in message_router.html.
  bool OnQuery(CefRefPtr<CefBrowser> browser,
               CefRefPtr<CefFrame> frame,
               int64 query_id,
               const CefString& request,
               bool persistent,
               CefRefPtr<Callback> callback) override {
    const std::string& message_name = request;
    if (message_name.find("testMessage") == 0) {
      // Return
      callback->Success("This is a response message from CEF");
      return true;
    }

    return false;
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(MessageHandler);
};

namespace minimal {

Client::Client() {}

void Client::OnTitleChange(CefRefPtr<CefBrowser> browser,
                           const CefString& title) {
  CEF_REQUIRE_UI_THREAD();

#if defined(OS_WIN) || defined(OS_LINUX)
  // The Views framework is currently only supported on Windows and Linux.
  CefRefPtr<CefBrowserView> browser_view =
      CefBrowserView::GetForBrowser(browser);
  if (browser_view) {
    // Set the title of the window using the Views framework.
    CefRefPtr<CefWindow> window = browser_view->GetWindow();
    if (window)
      window->SetTitle(title);
  } else
#endif
  {
    // Set the title of the window using platform APIs.
    PlatformTitleChange(browser, title);
  }
}

bool Client::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
                                      CefRefPtr<CefFrame> frame,
                                      CefProcessId source_process,
                                      CefRefPtr<CefProcessMessage> message) {
  CEF_REQUIRE_UI_THREAD();

  return message_router_->OnProcessMessageReceived(browser, frame,
                                                   source_process, message);
}

void Client::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
  CEF_REQUIRE_UI_THREAD();

  if (!message_router_) {
    // Create the browser-side router for query handling.
    CefMessageRouterConfig config;
    config.js_query_function = "cefQuery";
    config.js_cancel_function = "cefQueryCancel";
    message_router_ = CefMessageRouterBrowserSide::Create(config);

    // Register handlers with the router.
    message_handler_.reset(new MessageHandler());
    message_router_->AddHandler(message_handler_.get(), false);
  }

  browser_ct_++;

  // Add to the list of existing browsers.
  ClientManager::GetInstance()->OnAfterCreated(browser);
}

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

  message_router_->OnBeforeBrowse(browser, frame);
  return false;
}

bool Client::DoClose(CefRefPtr<CefBrowser> browser) {
  CEF_REQUIRE_UI_THREAD();

  // Closing the main window requires special handling. See the DoClose()
  // documentation in the CEF header for a detailed destription of this
  // process.
  ClientManager::GetInstance()->DoClose(browser);

  // Allow the close. For windowed browsers this will result in the OS close
  // event being sent.
  return false;
}

void Client::OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser,
                                       TerminationStatus status) {
  CEF_REQUIRE_UI_THREAD();

  message_router_->OnRenderProcessTerminated(browser);
}

CefRefPtr<CefResourceRequestHandler> Client::GetResourceRequestHandler(
    CefRefPtr<CefBrowser> browser,
    CefRefPtr<CefFrame> frame,
    CefRefPtr<CefRequest> request,
    bool is_navigation,
    bool is_download,
    const CefString& request_initiator,
    bool& disable_default_handling) {
  CEF_REQUIRE_IO_THREAD();
  return this;
}

void Client::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
 
  if (--browser_ct_ == 0) {
    // Free the router when the last browser is closed.
    message_router_->RemoveHandler(message_handler_.get());
    message_handler_.reset();
    message_router_ = nullptr;
  }
  // Remove from the list of existing browsers.
  ClientManager::GetInstance()->OnBeforeClose(browser);
}

}


What may I be doing wrong? Thank you very much in advance.
BorjaPascual
Techie
 
Posts: 27
Joined: Mon Jan 30, 2023 11:25 am

Re: window.cefQuery is not a function

Postby magreenblatt » Mon Jan 30, 2023 11:41 am

It looks like you're missing the renderer side of the changes. The part in app_renderer_impl.cc.
magreenblatt
Site Admin
 
Posts: 12382
Joined: Fri May 29, 2009 6:57 pm

Re: window.cefQuery is not a function

Postby BorjaPascual » Mon Jan 30, 2023 3:34 pm

magreenblatt wrote:It looks like you're missing the renderer side of the changes. The part in app_renderer_impl.cc.


As a matter of fact, I implemented it, here's the code:

Code: Select all
class RendererApp : public CefApp, public CefRenderProcessHandler {
 public:
  RendererApp() {}

  // CefApp methods:
  CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() override {
    return this;
  }

  void OnRegisterCustomSchemes(CefRawPtr<CefSchemeRegistrar> registrar) {
    CefRegisterSchemeHandlerFactory("https", "test",
                                    new BackendSchemeHandlerFactory());
    // Register the custom scheme as standard and secure.
    // Must be the same implementation in all processes.
    registrar->AddCustomScheme("https", CEF_SCHEME_OPTION_STANDARD |
                                            CEF_SCHEME_OPTION_SECURE |
                                            CEF_SCHEME_OPTION_CORS_ENABLED |
                                            CEF_SCHEME_OPTION_FETCH_ENABLED);
  }

  // CefRenderProcessHandler methods:
  void OnWebKitInitialized() override {
    // Create the renderer-side router for query handling.
    CefMessageRouterConfig config;
    config.js_query_function = "cefQuery";
    config.js_cancel_function = "cefQueryCancel";
    message_router_ = CefMessageRouterRendererSide::Create(config);
  }

  void OnContextCreated(CefRefPtr<CefBrowser> browser,
                        CefRefPtr<CefFrame> frame,
                        CefRefPtr<CefV8Context> context) override {
    message_router_->OnContextCreated(browser, frame, context);
  }

  void OnContextReleased(CefRefPtr<CefBrowser> browser,
                         CefRefPtr<CefFrame> frame,
                         CefRefPtr<CefV8Context> context) override {
    message_router_->OnContextReleased(browser, frame, context);
  }

  bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
                                CefRefPtr<CefFrame> frame,
                                CefProcessId source_process,
                                CefRefPtr<CefProcessMessage> message) override {
    return message_router_->OnProcessMessageReceived(browser, frame,
                                                     source_process, message);
  }

 private:
  // Handles the renderer side of query routing.
  CefRefPtr<CefMessageRouterRendererSide> message_router_;

  IMPLEMENT_REFCOUNTING(RendererApp);
  DISALLOW_COPY_AND_ASSIGN(RendererApp);
};


I placed a breakpoint in the constructor and didn't fire, tho. Tried placing it in app_renderer_impl.cc and also didn't fire. My main is a literal copypaste of shared:

Code: Select all
// Entry point function for all processes.
int APIENTRY wWinMain(HINSTANCE hInstance,
                      HINSTANCE hPrevInstance,
                      LPTSTR lpCmdLine,
                      int nCmdShow) {
  UNREFERENCED_PARAMETER(hPrevInstance);
  UNREFERENCED_PARAMETER(lpCmdLine);

  // Enable High-DPI support on Windows 7 or newer.
  CefEnableHighDPISupport();

  void* sandbox_info = nullptr;

#if defined(CEF_USE_SANDBOX)
  // Manage the life span of the sandbox information object. This is necessary
  // for sandbox support on Windows. See cef_sandbox_win.h for complete details.
  CefScopedSandboxInfo scoped_sandbox;
  sandbox_info = scoped_sandbox.sandbox_info();
#endif

  // Provide CEF with command-line arguments.
  CefMainArgs main_args(hInstance);

  // CEF applications have multiple sub-processes (render, GPU, etc) that share
  // the same executable. This function checks the command-line and, if this is
  // a sub-process, executes the appropriate logic.
  int exit_code = CefExecuteProcess(main_args, nullptr, sandbox_info);
  if (exit_code >= 0) {
    // The sub-process has completed so return here.
    return exit_code;
  }

  // Parse command-line arguments for use in this method.
  CefRefPtr<CefCommandLine> command_line = CefCommandLine::CreateCommandLine();
  command_line->InitFromString(::GetCommandLineW());

  // Create the singleton manager instance.
  ClientManager manager;

  // Specify CEF global settings here.
  CefSettings settings;

  if (command_line->HasSwitch("enable-chrome-runtime")) {
    // Enable experimental Chrome runtime. See issue #2969 for details.
    settings.chrome_runtime = true;
  }

#if !defined(CEF_USE_SANDBOX)
  settings.no_sandbox = true;
#endif

  // SimpleApp implements application-level callbacks for the browser process.
  // It will create the first browser instance in OnContextInitialized() after
  // CEF has initialized.
  //CefRefPtr<SimpleApp> app(new SimpleApp);
  // Create a CefApp of the correct process type.
  CefRefPtr<CefApp> app;
  switch (GetProcessType(command_line)) {
    case PROCESS_TYPE_BROWSER:
      app = CreateBrowserProcessApp();
      break;
    case PROCESS_TYPE_RENDERER:
      app = CreateRendererProcessApp();
      break;
    case PROCESS_TYPE_OTHER:
      app = CreateOtherProcessApp();
      break;
  }

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

  // Run the CEF message loop. This will block until CefQuitMessageLoop() is
  // called.
  CefRunMessageLoop();

  // Shut down CEF.
  CefShutdown();

  return 0;
}


What may I be missing?
BorjaPascual
Techie
 
Posts: 27
Joined: Mon Jan 30, 2023 11:25 am

Re: window.cefQuery is not a function

Postby magreenblatt » Mon Jan 30, 2023 4:36 pm

Code: Select all
// Register the custom scheme as standard and secure.
    // Must be the same implementation in all processes.
    registrar->AddCustomScheme("https", CEF_SCHEME_OPTION_STANDARD |
                                            CEF_SCHEME_OPTION_SECURE |
                                            CEF_SCHEME_OPTION_CORS_ENABLED |
                                            CEF_SCHEME_OPTION_FETCH_ENABLED);

HTTPS is not a custom scheme, so you don't have to register it.

I placed a breakpoint in the constructor and didn't fire, tho. Tried placing it in app_renderer_impl.cc and also didn't fire.

The renderer process is a different process. You need to explicitly attach the debugger to it. Debug with Visual Studio and add "--wait-for-debugger-children=renderer" on the command-line. Debugging tips are available at https://www.chromium.org/developers/how ... n-windows/
magreenblatt
Site Admin
 
Posts: 12382
Joined: Fri May 29, 2009 6:57 pm

Re: window.cefQuery is not a function

Postby BorjaPascual » Tue Jan 31, 2023 1:57 am

magreenblatt wrote:HTTPS is not a custom scheme, so you don't have to register it.


I created a custom scheme for https so it loads local files. Tried with a custom protocol called "backend:" but, for some reason, it wasn't able to run JS.
BorjaPascual
Techie
 
Posts: 27
Joined: Mon Jan 30, 2023 11:25 am

Re: window.cefQuery is not a function

Postby BorjaPascual » Tue Jan 31, 2023 2:31 am

magreenblatt wrote:The renderer process is a different process. You need to explicitly attach the debugger to it. Debug with Visual Studio and add "--wait-for-debugger-children=renderer" on the command-line. Debugging tips are available at https://www.chromium.org/developers/how ... n-windows/


I have tried with
Code: Select all
command_line->AppendSwitch("wait-for-debugger-children=renderer");


but nothing appened still.
BorjaPascual
Techie
 
Posts: 27
Joined: Mon Jan 30, 2023 11:25 am

Re: window.cefQuery is not a function

Postby ndesktop » Tue Jan 31, 2023 6:06 am

You should call AppendSwitchWithValue("wait-for-debugger-children", "renderer"), not AppendSwitch.
AppendSwitch will interpret "wait-for-debugger-children=renderer" as a switch name and obviously will not be found.
ndesktop
Master
 
Posts: 750
Joined: Thu Dec 03, 2015 10:10 am

Re: window.cefQuery is not a function

Postby BorjaPascual » Tue Jan 31, 2023 6:42 am

ndesktop wrote:You should call AppendSwitchWithValue("wait-for-debugger-children", "renderer"), not AppendSwitch.
AppendSwitch will interpret "wait-for-debugger-children=renderer" as a switch name and obviously will not be found.


Thanks. I tried that too, but nothing. In the end, I have been able to do it via VS project properties. Either way, the main problem still is the whole "window.cefQuery is not a function" situation :(
BorjaPascual
Techie
 
Posts: 27
Joined: Mon Jan 30, 2023 11:25 am

Re: window.cefQuery is not a function

Postby BorjaPascual » Tue Jan 31, 2023 10:10 am

So here's another update:

I ran the "message_router" example with --renderer-process-limit=1 --renderer-startup-dialog --no-sandbox and hit some breakpoints in the renderer. Did the same in my project and no breakpoint was triggered. Could this mean my render handler is not being instantiated properly?
BorjaPascual
Techie
 
Posts: 27
Joined: Mon Jan 30, 2023 11:25 am

Re: window.cefQuery is not a function

Postby ndesktop » Tue Jan 31, 2023 1:02 pm

I think you should start from debugger with --wait-for-debugger-children=renderer directly on the arguments.
AppendSwitch(WithValue) probably occurs later when the renderer is already started.
ndesktop
Master
 
Posts: 750
Joined: Thu Dec 03, 2015 10:10 am

Next

Return to Support Forum

Who is online

Users browsing this forum: Google [Bot] and 23 guests