CefExecuteProcess; Running Entire Application Multiple Times

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.

CefExecuteProcess; Running Entire Application Multiple Times

Postby KKlouzal » Sat Aug 27, 2022 8:30 pm

CefExecuteProcess() appears to be running my entire application multiple times? I believe I misunderstand it's usage.
https://bitbucket.org/chromiumembedded/ ... -processes
By default the main application executable will be spawned multiple times to represent separate processes. This is handled via command-line flags that are passed into the CefExecuteProcess function. If the main application executable is large, takes a long time to load, or is otherwise unsuitable for non-browser processes the host can use a separate executable for those other processes. This can be configured via the CefSettings.browser_subprocess_path variable. See the “Application Structure” section for more information.

My main application is definitely unsuitable for non-browser processes.

Now, I'm using offscreen rendering, and it appears as if I don't even need to call CefExecuteProcess?
Not calling it, has zero adverse effect on my program, CEF still functions the same as it would otherwise.
In fact, my application exits much quicker without calling it. Normally I would expect 30secods of hang after my application returned before the subprocesses would exit and then my application window would finally close.

Code: Select all
      void Initialize()
      {
         CEFAPP = new MyCefApp();
         CefMainArgs args(::GetModuleHandle(NULL));

         CefSettings settings;
         settings.windowless_rendering_enabled = 1;
         settings.multi_threaded_message_loop = 0;
         settings.no_sandbox = 1;

         bool result = CefInitialize(args, settings, CEFAPP, nullptr);
         if (!result)
         {
            printf("CEF Initialize Error\n");
         }

         renderHandler = new RenderHandler();

         CefBrowserSettings browserSettings;
         browserSettings.windowless_frame_rate = 30;

         CefWindowInfo window_info;
         window_info.parent_window = glfwGetWin32Window(WorldEngine::VulkanDriver::_Window);
         window_info.SetAsWindowless(glfwGetWin32Window(WorldEngine::VulkanDriver::_Window));

         browserClient = new BrowserClient(renderHandler);

         browser = CefBrowserHost::CreateBrowserSync(window_info, browserClient.get(), "about:blank", browserSettings, nullptr, nullptr);
         browser->GetMainFrame()->LoadURL("file:///./html/main.html");
      }


Still though, looking in task manager, it looks like my application executable is still being launched multiple times by each of the CEF subprocesses.
I think I need to make use of CefSettings.browser_subprocess_path

This document outlines what a subprocess executable should include: https://bitbucket.org/chromiumembedded/ ... executable
Unfortunately it seems a bit out of dated for the version of CEF I'm using (104). So here is what I came up with:
Code: Select all
#include <include\cef_client.h>
#include <include\cef_app.h>

class MyV8Handler : public CefV8Handler {
public:

   bool Execute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception)
   {
      if (name == "myfunc")
      {
         if (arguments.size() == 2)
         {
            std::string RemoteIP = arguments[0]->GetStringValue().ToString();
            unsigned int RemotePort = arguments[1]->GetUIntValue();
            printf("[SUBPROCESS] MYFUNC %s %u\n", RemoteIP.c_str(), RemotePort);

            CefRefPtr<CefProcessMessage> msg = CefProcessMessage::Create("My_Message");
            CefRefPtr<CefListValue> args = msg->GetArgumentList();
            args->SetString(0, arguments[0]->GetStringValue());
            args->SetInt(1, arguments[1]->GetIntValue());

            CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
            context->GetBrowser()->GetMainFrame()->SendProcessMessage(PID_BROWSER, msg);
            return true;
         }
      }

      // Function does not exist.
      return false;
   }

   // Provide the reference counting implementation for this class.
   IMPLEMENT_REFCOUNTING(MyV8Handler);
};

class MyApp : public CefApp, public CefRenderProcessHandler
{
public:

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

   CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler()
   {
      return this;
   }

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

   void OnWebKitInitialized()
   {
      std::string extensionCode =
         "var test;"
         "if (!test)"
         "test = {};"
         "(function() {"
         "test.myfunc = function(RemoteAddr, RemotePort) {"
         "native function myfunc(RemoteAddr, RemotePort);"
         "return myfunc(RemoteAddr, RemotePort);"
         "};"
         "})();";

      CefRefPtr<CefV8Handler> handler = new MyV8Handler();
      CefRegisterExtension("v8/test", extensionCode, handler);
   }

   IMPLEMENT_REFCOUNTING(MyApp);
};


// Program entry-point function.
int main(int argc, char* argv[]) {
    // Initialize the macOS sandbox for this helper process.
    //CefScopedSandboxContext sandbox_context;
    //if (!sandbox_context.Initialize(argc, argv))
    //    return 1;

    //// Load the CEF framework library at runtime instead of linking directly
    //// as required by the macOS sandbox implementation.
    //CefScopedLibraryLoader library_loader;
  /*  if (!library_loader.LoadInHelper())
        return 1;*/

    // Structure for passing command-line arguments.
    // The definition of this structure is platform-specific.
   CefMainArgs main_args;

    // Implementation of the CefApp interface.
    CefRefPtr<MyApp> app(new MyApp);

    // Execute the sub-process logic. This will block until the sub-process should exit.
    return CefExecuteProcess(main_args, app.get(), NULL);
}


Interestingly enough, I am lead to define my CefApp and V8Handler here inside the subprocess executable.
I essentially copied and pasted the functions from my original application.
Then commented them out inside my main application.
Everything appears to be running properly.

So is there any reason to define CefApp inside my main executable and include it here in CefInitialize?
bool result = CefInitialize(args, settings, nullptr, nullptr);

Here is what my initialization function looks like now:
Code: Select all
      void Initialize()
      {
         CefMainArgs args(::GetModuleHandle(NULL));

         CefSettings settings;
         settings.windowless_rendering_enabled = 1;
         settings.multi_threaded_message_loop = 0;
         settings.no_sandbox = 1;
         //
         wchar_t szPath[MAX_PATH];
         GetModuleFileNameW(NULL, szPath, MAX_PATH);
         auto P = std::filesystem::path{ szPath }.parent_path();
         printf("PATH: %s\n", P.generic_string().c_str());
         CefString(&settings.browser_subprocess_path) = P.generic_string() + "/CEFBrowserSubprocess.exe";

         bool result = CefInitialize(args, settings, nullptr, nullptr);
         if (!result)
         {
            printf("CEF Initialize Error\n");
         }

         renderHandler = new RenderHandler();

         CefBrowserSettings browserSettings;
         browserSettings.windowless_frame_rate = 30;

         CefWindowInfo window_info;
         window_info.parent_window = glfwGetWin32Window(WorldEngine::VulkanDriver::_Window);
         window_info.SetAsWindowless(glfwGetWin32Window(WorldEngine::VulkanDriver::_Window));

         browserClient = new BrowserClient(renderHandler);

         browser = CefBrowserHost::CreateBrowserSync(window_info, browserClient.get(), "about:blank", browserSettings, nullptr, nullptr);
         browser->GetMainFrame()->LoadURL("file:///./html/main.html");
      }


So, being that the docs are a little out of date, I guess I'm just looking for confirmation that I'm doing everything correctly so far, and if I've missed any steps..?
KKlouzal
Newbie
 
Posts: 9
Joined: Fri Nov 08, 2019 5:30 am

Re: CefExecuteProcess; Running Entire Application Multiple T

Postby magreenblatt » Sat Aug 27, 2022 9:35 pm

being that the docs are a little out of date

In what way are the docs out of date?

So is there any reason to define CefApp inside my main executable and include it here in CefInitialize?

Various CefApp methods are used in various processes. Refer to the source code (method) documentation.
magreenblatt
Site Admin
 
Posts: 12408
Joined: Fri May 29, 2009 6:57 pm

Re: CefExecuteProcess; Running Entire Application Multiple T

Postby KKlouzal » Sat Aug 27, 2022 9:49 pm

I very well could be mistaken in their 'outofdateness' but it seemed like in a few places, code presented in some of the docs were not 'cut and paste' a few things needed tweaked to get things to compile.
Again, I could be mistaken.

For example,
Code: Select all
CefMainArgs main_args(argc, argv);

Is not valid. Unless I was missing an include, it needed changed to:
Code: Select all
CefMainArgs main_args;

There were other little things in places that made me feel like I was either missing an include somewhere or it was documented from an older chromium.

I appreciate your assistance though :)
KKlouzal
Newbie
 
Posts: 9
Joined: Fri Nov 08, 2019 5:30 am


Return to Support Forum

Who is online

Users browsing this forum: No registered users and 64 guests