Best way to execute JS code upon closing?

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.

Best way to execute JS code upon closing?

Postby robinm2 » Wed Jul 10, 2024 9:01 am

The following bit of code used to work reliably in version 86.0.20 (I'm currently trying to upgrade to 126.2.0) :

Code: Select all
// tests/cefclient/browser/root_window_win.cc
bool RootWindowWin::OnClose() {
        CefRefPtr<CefFrame> frame = GetBrowser()->GetMainFrame();
        std::stringstream ss;
        ss << "myFunction();";
        frame->ExecuteJavaScript(ss.str(), frame->GetURL(), 0);
....
}


myFunction is doing some Ajax to record traffic data such as time spent on some page.
In the new CEF version, the function isn't always called.
Is there a known way to have some javascript executed reliably upon closing the browser?

Thanks,
robinm2
Techie
 
Posts: 39
Joined: Mon Feb 08, 2021 12:14 pm

Re: Best way to execute JS code upon closing?

Postby magreenblatt » Wed Jul 10, 2024 10:20 am

This is generally done from the JavaScript side. See https://developer.chrome.com/docs/web-p ... oad_events for recommendations.
magreenblatt
Site Admin
 
Posts: 12966
Joined: Fri May 29, 2009 6:57 pm

Re: Best way to execute JS code upon closing?

Postby robinm2 » Wed Jul 10, 2024 12:17 pm

Cool. Wasn't aware of those alternatives to unload. I'm testing pagehide at the moment, seems to work fine.
robinm2
Techie
 
Posts: 39
Joined: Mon Feb 08, 2021 12:14 pm

Re: Best way to execute JS code upon closing?

Postby robinm2 » Thu Jul 11, 2024 12:39 pm

Well, I don't understand, in today's tests the event is not fired when closing the window (it is, however, when I change the URL)
Guess the changes I've made since yesterday broke the apparent reliability? Back to square one anyway.
I'm planning to use libcurl to do the job on the CEF side, I just need the JS app to provide the URL to use.
robinm2
Techie
 
Posts: 39
Joined: Mon Feb 08, 2021 12:14 pm

Re: Best way to execute JS code upon closing?

Postby robinm2 » Thu Nov 14, 2024 4:31 pm

If anyone is interested, I ended up not using curl because in certain cases we need to do more than just post to an URL.
The way I managed to reliably call a JS function upon closing is by doing the following modifications:

browser/root_window_win.cc
Code: Select all
// in RootWindowWin::CreateRootWindow
  CHECK(hwnd_);

  browser_window_->GetClientHandler()->SetRootWindowHWND(hwnd_); // sets the custom member root_window_hwnd_ in ClientHandler

...

// in RootWindowWin::RootWndProc
case WM_CLOSE:
        browser = self->GetBrowser();
        if (browser == NULL) {
            return 0;
        }
        if (browser->GetIdentifier() == 1) { // Root window (blank and hidden) : do as usual
            if (self->OnClose()) {
                return 0;  // Cancel the close.
            }
        }
        else { // id > 1 so it's an App window
            if (wParam == 0) { // Origin = user action
                frame = self->GetBrowser()->GetMainFrame();
                frame->ExecuteJavaScript("closeApp();", frame->GetURL(), 0);
                return 0; // Cancel the close
            }
            else if (self->OnClose()) { // Origin = AllowClose
                return 0;  // Cancel the close.
            }
        }
        break;


browser/client_handler.cc
Code: Select all
// in ClientHandler::OnProcessMessageReceived
  else if (message_name == "AllowClose") {
      SendMessage(root_window_hwnd_, WM_CLOSE, 1, NULL);
      return true;
  }


I define the custom JS function "AllowClose"':
shared/renderer/client_app_renderer.cc
Code: Select all
// V8Handler
bool MyV8Handler::Execute(const CefString& name,
    CefRefPtr<CefV8Value> object,
    const CefV8ValueList& arguments,
    CefRefPtr<CefV8Value>& retval,
    CefString& exception) {
    if (name == "AllowClose") {
        CefRefPtr<CefProcessMessage> message = CefProcessMessage::Create("AllowClose");
        CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
        context->GetFrame()->SendProcessMessage(PID_BROWSER, message);
        retval = CefV8Value::CreateBool(true);
        return true;
    }

    // Function does not exist.
    return false;
}

...

// In ClientAppRenderer::OnContextCreated
  object->SetValue("AllowClose",
      CefV8Value::CreateFunction("AllowClose", handler),
      V8_PROPERTY_ATTRIBUTE_NONE);


Finally, in the JS app:
Code: Select all
let closing = false;
function closeApp() {
  if (!closing) {
    closing = true;
    // do stuff
    post(...).then(AllowClose).catch(AllowClose);
  }
}
robinm2
Techie
 
Posts: 39
Joined: Mon Feb 08, 2021 12:14 pm


Return to Support Forum

Who is online

Users browsing this forum: No registered users and 102 guests