Sending information from Chromium Embedded (Javascript) to a containing C++ application
Asked Answered
R

3

10

After checking out the Chromium Embedded Framework example I have a question. I need native interaction with the embedded part of my window. However, in the CEF example, all I saw was the c++ sending messages to the browser, not the other way around. I was wondering if there is any way to send a message from JavaScript from c++, like in the way of a function.

What I am looking for is something like this. I have a button in my webpage that when clicked. I would like to minimize the window. Is there any way to call some c++ from JavaScript in CEF?

Rhythmandblues answered 20/9, 2013 at 22:43 Comment(1)
Take a look at my comments in this post (already linked )...#18225761 . It maybe helpful to you...Lizzettelizzie
C
9

Easiest way: 1. In main process (UI process) - you can create own custom scheme handler (it can be bounded to http protocol too, and distinct handlers by domain). 2. From JS side, you can use XMLHttpRequest to call you scheme handler. It is standard mechanism to IPC between JS<>Main process.

Other way: Use V8 bindings, but in this case you will need make own IPC between renderer and main process. Or use built-in IPC, but note that it is sends messages only in async way.

Creamy answered 21/9, 2013 at 0:1 Comment(3)
Thanks! Do you know of any examples or tutorials on the built in IPC? I could find examples of IPC in chromium, but have no clue if that is how it works in CEF. I'm assuming that it supports CEF type 3, correct?Rhythmandblues
Okay, having looked into the options more, registering a custom scheme handlers looks like a good choice, however, like many things in CEF, I can't seem to find any examples. groups.google.com/forum/#!msg/cefglue/GmUdlO-qA-w/2Jcnxp75ynUJ is a good example, however it in in c# and uses several classes not available in c++. Is there any site or example that explains the process of registering and reading messagesRhythmandblues
I'm not sure that i'm correctly understand you. It is all about CEF3. Built-in IPC's are lives around CefBrowser.SendProcessMessage and you can handle them at CefClient.OnProcessMessageReceived and CefRenderProcessHandler.OnProcessMessageReceived. Both C++ and Xilium.CefGlue contains simple samples, just search usage.Creamy
D
14

If anyone needs an example, here's one way i did it:

  1. Determine the custom 'protocol' you wish to use here's an example as a macro string #define PROTO_MYAPPCOMMAND "myapp://"

  2. On your custom CefApp class (the one inheriting from CefApp), also inherit from CefRenderProcessHandler.

  3. implement the OnBeforeNavigation() function:

    //declare (i.e. in header) 
    virtual bool OnBeforeNavigation(CefRefPtr<CefBrowser> browser, 
        CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request, 
        NavigationType navigation_type, bool is_redirect)  OVERRIDE; 
    
    //implementation 
    bool CClientApp::OnBeforeNavigation(CefRefPtr<CefBrowser> browser, 
        CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request, 
        NavigationType navigation_type, bool is_redirect)
    {
        CefString cefval = request->GetURL(); 
        CString csval = cefval.c_str(); 
    
        if (csval.Find(PROTO_MYAPPCOMMAND, 0) == 0)
        {
            //process the command here 
    
            //this is a command and not really intended for navigation 
            return true; 
        }
    
        return false; //true cancels navigation, false allows it 
    }
    

Here's an example of adding an 'exit' app button:

in cpp

    #define STR_COMMANDAPPEXIT _T("command.appexit")
    bool CClientApp::OnBeforeNavigation(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request, NavigationType navigation_type, bool is_redirect)
    {
        CefString cefval = request->GetURL(); 
        CString csval = cefval.c_str(); 

        if (csval.Find(PROTO_MYAPPCOMMAND, 0) == 0)
        {
            CString command = url; 
            command.Replace(PROTO_MYAPPCOMMAND, _T("")); 

            if (command.Find(STR_COMMANDAPPEXIT, 0) == 0) 
            {
                ::PostMessage(hwnd, WM_CLOSE, NULL, NULL); 
            }

            //this is a command and not really intended for navigation 
            return true; 
        }

        return false; //true cancels navigation, false allows it 
    }

also created a js utility file for all the operations to simplify calling them

    var MYHOST = MYHOST || {};
    /// Exit the Application (host app) 
    MYHOST.ExitApp = function() {
        window.location = 'myapp://command.appexit';
    };

in the pages js (i.e. in a button/div click)

    <div class="exitbutton" onclick="MYHOST.ExitApp();">Exit</div>

If you need to pass in parameters, just append them in the url in the js and parse the string in the cpp, like this:

    MYHOST.DoSomething = function() {
        window.location = 'myapp://command.dosomething?param1=' + value1 + "&param2=" + value2 + "&param3=" + value3;
    };

note: i've simplified the code but please do add the validations etc

Hope this helps!

Dwyer answered 16/1, 2014 at 3:6 Comment(2)
Thanks! This is the best example I have seen on how to do this, though it's not through the typical url scheme handler.Rhythmandblues
But it will be synchronous, will freez your browser rendering till event processedSarto
H
13

A no serious way to do this, needing a single line of code :

Console.Log('. ...') with a leading ESC char in front of the string/data structure you need to send to the app. Just implement the 'OnConsoleMessage' and trigger accurate job according to the leading or not ESC char.

PS: I had to use this tricky solution in 2015 as a DCEF3 release was buggy for scheme handler use.

For serious job: register custom scheme handler is fine.

Hastate answered 21/7, 2014 at 1:45 Comment(2)
This is one of the 'hackiest' solutions I've ever seen on stackoverflow!Kiri
ahahahahah ahahahahahGerianne
C
9

Easiest way: 1. In main process (UI process) - you can create own custom scheme handler (it can be bounded to http protocol too, and distinct handlers by domain). 2. From JS side, you can use XMLHttpRequest to call you scheme handler. It is standard mechanism to IPC between JS<>Main process.

Other way: Use V8 bindings, but in this case you will need make own IPC between renderer and main process. Or use built-in IPC, but note that it is sends messages only in async way.

Creamy answered 21/9, 2013 at 0:1 Comment(3)
Thanks! Do you know of any examples or tutorials on the built in IPC? I could find examples of IPC in chromium, but have no clue if that is how it works in CEF. I'm assuming that it supports CEF type 3, correct?Rhythmandblues
Okay, having looked into the options more, registering a custom scheme handlers looks like a good choice, however, like many things in CEF, I can't seem to find any examples. groups.google.com/forum/#!msg/cefglue/GmUdlO-qA-w/2Jcnxp75ynUJ is a good example, however it in in c# and uses several classes not available in c++. Is there any site or example that explains the process of registering and reading messagesRhythmandblues
I'm not sure that i'm correctly understand you. It is all about CEF3. Built-in IPC's are lives around CefBrowser.SendProcessMessage and you can handle them at CefClient.OnProcessMessageReceived and CefRenderProcessHandler.OnProcessMessageReceived. Both C++ and Xilium.CefGlue contains simple samples, just search usage.Creamy

© 2022 - 2024 — McMap. All rights reserved.