CEF Integration with the Juce Framework

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.

CEF Integration with the Juce Framework

Postby synth » Wed Dec 13, 2017 1:35 pm

Hi,

I am attempting to integrate CEF with my Juce application(https://juce.com/).

The full code is here: https://github.com/abhijitnandy2011/Juc ... ster/glcef

I am trying this in Visual Studio 2015 with the 64 bit version of the CEF framework (cef_binary_3.3202.1683.gb095524_windows64)

My aim is to use the CEF offline rendering feature to render into a texture in OpenGL mode similar to what https://github.com/gotnospirit/cef3-sdl2 does with the SDL framework. But before that I just want to get CEF running with the Juce message loop.

Currently I have just written a simple function to create a browser(https://github.com/abhijitnandy2011/Juc ... f.cpp#L187) and then start a while loop that repeatedly calls CefDoMessageLoopWork() (https://github.com/abhijitnandy2011/Juc ... in.cpp#L36)
I have implemented a custom render handler derived from CefRenderHandler and a custom BrowserClient deriving from CefClient, CefLifeSpanHandler, CefLoadHandler. This is all similar to https://github.com/gotnospirit/cef3-sdl2 which does work.

I request window less operation, so I am not expecting any window to be created by CEF or any GPU related code to run.

Yet I get a crash with this trace after about 10 seconds of running the application:

Code: Select all
>   libcef.dll!logging::LogMessage::~LogMessage() Line 791   C++
    libcef.dll!logging::Win32ErrorLogMessage::~Win32ErrorLogMessage() Line 912   C++
    libcef.dll!base::GetTerminationStatus(void * handle, int * exit_code) Line 59   C++
    libcef.dll!content::BrowserChildProcessHostImpl::GetTerminationStatus(bool known_dead, int * exit_code) Line 325   C++
    libcef.dll!content::GpuProcessHost::~GpuProcessHost() Line 528   C++
    [External Code]   
    libcef.dll!content::GpuProcessHost::Get(content::GpuProcessHost::GpuProcessKind kind, bool force_create) Line 411   C++
    libcef.dll!content::BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO() Line 106   C++
    libcef.dll!content::BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO(const IPC::ChannelHandle & channel_handle, const gpu::GPUInfo & gpu_info, content::GpuProcessHost::EstablishChannelStatus status) Line 133   C++
    libcef.dll!base::internal::Invoker<base::internal::BindState<void (__cdecl content::BrowserGpuChannelHostFactory::EstablishRequest::*)(IPC::ChannelHandle const & __ptr64,gpu::GPUInfo const & __ptr64,enum content::GpuProcessHost::EstablishChannelStatus) __ptr64,scoped_refptr<content::BrowserGpuChannelHostFactory::EstablishRequest> >,void __cdecl(IPC::ChannelHandle const & __ptr64,gpu::GPUInfo const & __ptr64,enum content::GpuProcessHost::EstablishChannelStatus)>::RunImpl<void (__cdecl content::BrowserGpuChannelHostFactory::EstablishRequest::*const & __ptr64)(IPC::ChannelHandle const & __ptr64,gpu::GPUInfo const & __ptr64,enum content::GpuProcessHost::EstablishChannelStatus) __ptr64,std::tuple<scoped_refptr<content::BrowserGpuChannelHostFactory::EstablishRequest> > const & __ptr64,0>(void(content::BrowserGpuChannelHostFactory::EstablishRequest::*)(const IPC::ChannelHandle &, const gpu::GPUInfo &, content::GpuProcessHost::EstablishChannelStatus) & functor, const std::tuple<scoped_refptr<content::BrowserGpuChannelHostFactory::EstablishRequest> > & bound, std::integer_sequence<unsigned __int64,0> __formal, const IPC::ChannelHandle & <unbound_args_0>, const gpu::GPUInfo & <unbound_args_1>, content::GpuProcessHost::EstablishChannelStatus && <unbound_args_2>) Line 353   C++
    libcef.dll!base::internal::Invoker<base::internal::BindState<void (__cdecl content::BrowserGpuChannelHostFactory::EstablishRequest::*)(IPC::ChannelHandle const & __ptr64,gpu::GPUInfo const & __ptr64,enum content::GpuProcessHost::EstablishChannelStatus) __ptr64,scoped_refptr<content::BrowserGpuChannelHostFactory::EstablishRequest> >,void __cdecl(IPC::ChannelHandle const & __ptr64,gpu::GPUInfo const & __ptr64,enum content::GpuProcessHost::EstablishChannelStatus)>::Run(base::internal::BindStateBase * base, const IPC::ChannelHandle & <unbound_args_0>, const gpu::GPUInfo & <unbound_args_1>, content::GpuProcessHost::EstablishChannelStatus && <unbound_args_2>) Line 334   C++
    libcef.dll!content::GpuProcessHost::SendOutstandingReplies() Line 1080   C++
    libcef.dll!content::GpuProcessHost::OnProcessCrashed(int exit_code) Line 835   C++
    libcef.dll!content::BrowserChildProcessHostImpl::OnChildDisconnected() Line 409   C++
    libcef.dll!IPC::ChannelMojo::OnPipeError() Line 383   C++
    libcef.dll!IPC::internal::MessagePipeReader::OnPipeError(unsigned int error) Line 125   C++
    libcef.dll!base::internal::Invoker<base::internal::BindState<void (__cdecl IPC::internal::MessagePipeReader::*)(unsigned int) __ptr64,base::internal::UnretainedWrapper<IPC::internal::MessagePipeReader>,unsigned int>,void __cdecl(void)>::RunImpl<void (__cdecl IPC::internal::MessagePipeReader::*const & __ptr64)(unsigned int) __ptr64,std::tuple<base::internal::UnretainedWrapper<IPC::internal::MessagePipeReader>,unsigned int> const & __ptr64,0,1>(void(IPC::internal::MessagePipeReader::*)(unsigned int) & functor, const std::tuple<base::internal::UnretainedWrapper<IPC::internal::MessagePipeReader>,unsigned int> & bound, std::integer_sequence<unsigned __int64,0,1> __formal) Line 353   C++
    libcef.dll!mojo::InterfaceEndpointClient::NotifyError(const base::Optional<mojo::DisconnectReason> & reason) Line 320   C++
    libcef.dll!IPC::`anonymous namespace'::ChannelAssociatedGroupController::NotifyEndpointOfError(IPC::`anonymous-namespace'::ChannelAssociatedGroupController::Endpoint * endpoint, bool force_async) Line 648   C++
    libcef.dll!IPC::`anonymous namespace'::ChannelAssociatedGroupController::OnPipeError() Line 630   C++
    libcef.dll!base::internal::Invoker<base::internal::BindState<void (__cdecl IPC::`anonymous namespace'::ChannelAssociatedGroupController::*)(void) __ptr64,base::internal::UnretainedWrapper<IPC::`anonymous namespace'::ChannelAssociatedGroupController> >,void __cdecl(void)>::RunImpl<void (__cdecl IPC::`anonymous namespace'::ChannelAssociatedGroupController::*const & __ptr64)(void) __ptr64,std::tuple<base::internal::UnretainedWrapper<IPC::`anonymous namespace'::ChannelAssociatedGroupController> > const & __ptr64,0>(void(IPC::`anonymous-namespace'::ChannelAssociatedGroupController::*)() & functor, const std::tuple<base::internal::UnretainedWrapper<IPC::`anonymous namespace'::ChannelAssociatedGroupController> > & bound, std::integer_sequence<unsigned __int64,0> __formal) Line 353   C++
    libcef.dll!mojo::Connector::HandleError(bool force_pipe_reset, bool force_async_handler) Line 534   C++
    libcef.dll!mojo::Connector::OnHandleReadyInternal(unsigned int result) Line 371   C++
    libcef.dll!base::internal::Invoker<base::internal::BindState<void (__cdecl mojo::Connector::*)(unsigned int) __ptr64,base::internal::UnretainedWrapper<mojo::Connector> >,void __cdecl(unsigned int)>::RunImpl<void (__cdecl mojo::Connector::*const & __ptr64)(unsigned int) __ptr64,std::tuple<base::internal::UnretainedWrapper<mojo::Connector> > const & __ptr64,0>(void(mojo::Connector::*)(unsigned int) & functor, const std::tuple<base::internal::UnretainedWrapper<mojo::Connector> > & bound, std::integer_sequence<unsigned __int64,0> __formal, unsigned int && <unbound_args_0>) Line 353   C++
    libcef.dll!base::MemoryPressureListener::Notify(base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) Line 83   C++
    libcef.dll!base::internal::Invoker<base::internal::BindState<void (__cdecl*)(base::RepeatingCallback<void __cdecl(unsigned int)> const & __ptr64,unsigned int,mojo::HandleSignalsState const & __ptr64),base::RepeatingCallback<void __cdecl(unsigned int)> >,void __cdecl(unsigned int,mojo::HandleSignalsState const & __ptr64)>::RunImpl<void (__cdecl*const & __ptr64)(base::RepeatingCallback<void __cdecl(unsigned int)> const & __ptr64,unsigned int,mojo::HandleSignalsState const & __ptr64),std::tuple<base::RepeatingCallback<void __cdecl(unsigned int)> > const & __ptr64,0>(void(*)(const base::RepeatingCallback<void __cdecl(unsigned int)> &, unsigned int, const mojo::HandleSignalsState &) & functor, const std::tuple<base::RepeatingCallback<void __cdecl(unsigned int)> > & bound, std::integer_sequence<unsigned __int64,0> __formal, unsigned int && <unbound_args_0>, const mojo::HandleSignalsState & <unbound_args_1>) Line 353   C++
    libcef.dll!base::internal::Invoker<base::internal::BindState<void (__cdecl*)(base::RepeatingCallback<void __cdecl(unsigned int)> const & __ptr64,unsigned int,mojo::HandleSignalsState const & __ptr64),base::RepeatingCallback<void __cdecl(unsigned int)> >,void __cdecl(unsigned int,mojo::HandleSignalsState const & __ptr64)>::Run(base::internal::BindStateBase * base, unsigned int && <unbound_args_0>, const mojo::HandleSignalsState & <unbound_args_1>) Line 334   C++
    libcef.dll!mojo::SimpleWatcher::OnHandleReady(int watch_id, unsigned int result, const mojo::HandleSignalsState & state) Line 277   C++
    libcef.dll!mojo::SimpleWatcher::Context::Notify(unsigned int result, MojoHandleSignalsState signals_state, unsigned int flags) Line 108   C++
    libcef.dll!mojo::SimpleWatcher::Context::CallNotify(unsigned __int64 context_value, unsigned int result, MojoHandleSignalsState signals_state, unsigned int flags) Line 61   C++
    libcef.dll!mojo::edk::WatcherDispatcher::InvokeWatchCallback(unsigned __int64 context, unsigned int result, const mojo::HandleSignalsState & state, unsigned int flags) Line 95   C++
    libcef.dll!mojo::edk::Watch::InvokeCallback(unsigned int result, const mojo::HandleSignalsState & state, unsigned int flags) Line 79   C++
    libcef.dll!mojo::edk::RequestContext::~RequestContext() Line 67   C++
    libcef.dll!mojo::edk::NodeChannel::OnChannelError(mojo::edk::Channel::Error error) Line 794   C++
    libcef.dll!mojo::edk::Channel::OnError(mojo::edk::Channel::Error error) Line 734   C++
    libcef.dll!mojo::edk::`anonymous namespace'::ChannelWin::OnIOCompleted(base::MessagePumpForIO::IOContext * context, unsigned long bytes_transfered, unsigned long error) Line 234   C++
    libcef.dll!base::MessagePumpForIO::WaitForIOCompletion(unsigned long timeout, base::MessagePumpForIO::IOHandler * filter) Line 542   C++
    libcef.dll!base::MessagePumpForIO::DoRunLoop() Line 483   C++
    libcef.dll!base::MessagePumpWin::Run(base::MessagePump::Delegate * delegate) Line 58   C++
    libcef.dll!base::RunLoop::Run() Line 124   C++
    libcef.dll!content::BrowserThreadImpl::IOThreadRun(base::RunLoop * run_loop) Line 279   C++
    libcef.dll!content::BrowserThreadImpl::Run(base::RunLoop * run_loop) Line 313   C++
    libcef.dll!base::Thread::ThreadMain() Line 341   C++
    libcef.dll!base::`anonymous namespace'::ThreadFunc(void * params) Line 89   C++
synth
Newbie
 
Posts: 7
Joined: Wed Dec 13, 2017 1:19 pm

Re: CEF Integration with the Juce Framework

Postby magreenblatt » Wed Dec 13, 2017 2:51 pm

You can use CefSettings.multi_threaded_message_loop on Windows. See https://bitbucket.org/chromiumembedded/ ... ntegration
magreenblatt
Site Admin
 
Posts: 12382
Joined: Fri May 29, 2009 6:57 pm

Re: CEF Integration with the Juce Framework

Postby synth » Thu Dec 14, 2017 11:06 am

With

Code: Select all
settings.multi_threaded_message_loop = true;


I get a crash:
Code: Select all
[1214/212121.464:FATAL:browser_host_impl.cc(253)] Check failed: false. called on invalid thread
[1214/212233.595:FATAL:browser_host_impl.cc(253)] Check failed: false. called on invalid thread
[1214/212233.639:FATAL:scoped_com_initializer.h(52)] Check failed: ((HRESULT)0x80010106L) != hr_ (-2147417850 vs. -2147417850)Invalid COM thread model change
[1214/212548.810:FATAL:browser_host_impl.cc(253)] Check failed: false. called on invalid thread
[1214/212548.877:FATAL:scoped_com_initializer.h(52)] Check failed: ((HRESULT)0x80010106L) != hr_ (-2147417850 vs. -2147417850)Invalid COM thread model change


Trace:
Code: Select all
    libcef.dll!logging::LogMessage::~LogMessage() Line 791   C++
    libcef.dll!CefBrowserHost::CreateBrowserSync(const CefWindowInfo & windowInfo, scoped_refptr<CefClient> client, const CefStringBase<CefStringTraitsUTF16> & url, const CefStructBase<CefBrowserSettingsTraits> & settings, scoped_refptr<CefRequestContext> request_context) Line 241   C++
    libcef.dll!cef_browser_host_create_browser_sync(const _cef_window_info_t * windowInfo, _cef_client_t * client, const _cef_string_utf16_t * url, const _cef_browser_settings_t * settings, _cef_request_context_t * request_context) Line 94   C++
>   glcef.exe!CefBrowserHost::CreateBrowserSync(const CefWindowInfo & windowInfo, scoped_refptr<CefClient> client, const CefStringBase<CefStringTraitsUTF16> & url, const CefStructBase<CefBrowserSettingsTraits> & settings, scoped_refptr<CefRequestContext> request_context) Line 60   C++
    glcef.exe!startCEF(HWND__ * hWnd) Line 261   C++
    glcef.exe!glcefApplication::initialise(const juce::String & commandLine) Line 39   C++
    glcef.exe!juce::JUCEApplicationBase::initialiseApp() Line 298   C++
    glcef.exe!juce::JUCEApplication::initialiseApp() Line 93   C++
    glcef.exe!juce::JUCEApplicationBase::main() Line 257   C++
    glcef.exe!WinMain(HINSTANCE__ * __formal, HINSTANCE__ * __formal, char * __formal, int __formal) Line 109   C++
    glcef.exe!invoke_main() Line 99   C++
    glcef.exe!__scrt_common_main_seh() Line 253   C++
    glcef.exe!__scrt_common_main() Line 296   C++
    glcef.exe!WinMainCRTStartup() Line 17   C++
    kernel32.dll!00000000774859cd()   Unknown
    ntdll.dll!00000000775ba561()   Unknown


What seems to work is:
Code: Select all
settings.single_process = true;


I see that this requires calling CefDoMessageLoopWork() regularly for the paint messages.

Also, settings.single_process seems to be windows only. Are there any features like audio, video or WebGL which wont run in this single_process mode?

Code: Select all
[1214/213044.488:ERROR:url_request_context_getter_impl.cc(129)] Cannot use V8 Proxy resolver in single process mode.
OnAfterCreated
GetViewRect()
GetViewRect()
[1214/213044.617:INFO:dxva_video_decode_accelerator_win.cc(1188)] mf.dll is required for hardware video decoding
[1214/213044.617:INFO:media_foundation_video_encode_accelerator_win.cc(335)] Windows versions earlier than 8 are not supported.
GetViewRect()
GetViewRect()
GetViewRect()
GetViewRect()
GetViewRect()
[1214/213044.668:WARNING:histograms.cc(40)] Started multiple compositor clients (Browser, Renderer) in one process. Some metrics will be disabled.
The thread 0x2be8 has exited with code 0 (0x0).
GetViewRect()
GetViewRect()
OnPaint()
GetViewRect()
GetViewRect()
OnPaint()
OnPaint()
...
synth
Newbie
 
Posts: 7
Joined: Wed Dec 13, 2017 1:19 pm

Re: CEF Integration with the Juce Framework

Postby magreenblatt » Thu Dec 14, 2017 1:05 pm

Use CreateBrowser instead of CreateBrowserSync. Also don't use single-process mode.
magreenblatt
Site Admin
 
Posts: 12382
Joined: Fri May 29, 2009 6:57 pm

Re: CEF Integration with the Juce Framework

Postby synth » Thu Dec 14, 2017 2:31 pm

With CefBrowserHost::CreateBrowser() I hit an assertion:
Code: Select all
[1215/005543.366:FATAL:kill_win.cc(48)] GetExitCodeProcess() failed: The handle is invalid. (0x6)
cefgl.exe has triggered a breakpoint.


Here is the complete code. I think I am creating the CefRequestContext correctly but I am not sure:
Code: Select all

// Separate impl as int32 type conflicts between juce and cef

#include <include/cef_app.h>
#include <include/cef_client.h>
#include <include/cef_render_handler.h>

#include <include/cef_life_span_handler.h>
#include <include/cef_load_handler.h>
#include <include/wrapper/cef_helpers.h>

uint32 gBuffer[800*600*4];

class RenderHandler : public CefRenderHandler
{
    int m_count;
public:

    RenderHandler()
        : m_count(0)
    {}

    // CefRenderHandler interface
    bool GetViewRect(CefRefPtr<CefBrowser> browser, CefRect &rect)
    {
        rect = CefRect(0, 0, 800, 600);
        return true;
    }
    void OnPaint(CefRefPtr<CefBrowser> browser, PaintElementType type, const RectList &dirtyRects, const void *buffer, int width, int height)
    {
        memcpy(gBuffer, buffer, width*height*4);
        m_count = m_count + 1;
    }

    IMPLEMENT_REFCOUNTING(RenderHandler);
};

// for manual render handler
class BrowserClient :
    public CefClient,
    public CefLifeSpanHandler,
    public CefLoadHandler
{
public:
    BrowserClient(CefRefPtr<CefRenderHandler> ptr) :
        handler(ptr)
    {
    }

    virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler()
    {
        return this;
    }

    virtual CefRefPtr<CefLoadHandler> GetLoadHandler()
    {
        return this;
    }

    virtual CefRefPtr<CefRenderHandler> GetRenderHandler()
    {
        return handler;
    }

    // CefLifeSpanHandler methods.
    void OnAfterCreated(CefRefPtr<CefBrowser> browser)
    {
        // Must be executed on the UI thread.
       // CEF_REQUIRE_UI_THREAD();

        browser_id = browser->GetIdentifier();
    }

    bool DoClose(CefRefPtr<CefBrowser> browser)
    {
        // Must be executed on the UI thread.
        //CEF_REQUIRE_UI_THREAD();

        // Closing the main window requires special handling. See the DoClose()
        // documentation in the CEF header for a detailed description of this
        // process.
        if (browser->GetIdentifier() == browser_id)
        {
            // Set a flag to indicate that the window close should be allowed.
            closing = true;
        }

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

    void OnBeforeClose(CefRefPtr<CefBrowser> browser)
    {
    }

    void OnLoadEnd(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, int httpStatusCode)
    {
        //std::cout << "OnLoadEnd(" << httpStatusCode << ")" << std::endl;
        loaded = true;
    }

    bool OnLoadError(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefLoadHandler::ErrorCode errorCode, const CefString & failedUrl, CefString & errorText)
    {
        //std::cout << "OnLoadError()" << std::endl;
        loaded = true;
    }

    void OnLoadingStateChange(CefRefPtr<CefBrowser> browser, bool isLoading, bool canGoBack, bool canGoForward)
    {
        //std::cout << "OnLoadingStateChange()" << std::endl;
    }

    void OnLoadStart(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame)
    {
       // std::cout << "OnLoadStart()" << std::endl;
    }

    bool closeAllowed() const
    {
        return closing;
    }

    bool isLoaded() const
    {
        return loaded;
    }

private:
    int browser_id;
    bool closing = false;
    bool loaded = false;
    CefRefPtr<CefRenderHandler> handler;

    IMPLEMENT_REFCOUNTING(BrowserClient);
};

RenderHandler* renderHandler;

// create browser-window
CefRefPtr<CefBrowser> browser;
CefRefPtr<BrowserClient> browserClient;

CefMainArgs args;
CefSettings settings;

class MyRequestContextHandler :public CefRequestContextHandler
{
public:
    MyRequestContextHandler(){
        m_cookieMgr = CefCookieManager::CreateManager("D:/CefCookie", FALSE, nullptr);
    };
    ~MyRequestContextHandler(){};
    CefRefPtr<CefCookieManager> GetCookieManager() override {
        return m_cookieMgr;
    }
private:
    CefRefPtr<CefCookieManager> m_cookieMgr;

    // Include the default reference counting implementation.
    IMPLEMENT_REFCOUNTING(MyRequestContextHandler);
};

CefRefPtr<CefRequestContext> rc;
CefRequestContextSettings reqsettings;

bool startCEF(HWND hWnd)
{

    {
        int result = CefExecuteProcess(args, nullptr, nullptr);
        // checkout CefApp, derive it and set it as second parameter, for more control on
        // command args and resources.
        if (result >= 0) // child proccess has endend, so exit.
        {
            return result;
        }
        else if (result == -1)
        {
            // we are here in the father proccess.
        }
    }

   
    settings.multi_threaded_message_loop = true;
    bool result = CefInitialize(args, settings, nullptr, nullptr);
    // CefInitialize creates a sub-proccess and executes the same executeable, as calling CefInitialize, if not set different in settings.browser_subprocess_path
    // if you create an extra program just for the childproccess you only have to call CefExecuteProcess(...) in it.
    if (!result)
    {
        // handle error
        return -1;
    }
   
    renderHandler = new RenderHandler();
    bool ret = false;
    {
        CefWindowInfo window_info;
        CefBrowserSettings browserSettings;

        // browserSettings.windowless_frame_rate = 60; // 30 is default
        window_info.SetAsWindowless(hWnd); // false means no transparency (site background colour)

        browserClient = new BrowserClient(renderHandler);

        rc = CefRequestContext::CreateContext(reqsettings, new MyRequestContextHandler());
        ret = CefBrowserHost::CreateBrowser(window_info, browserClient.get(), "http://www.google.com", browserSettings, rc);

        // inject user-input by calling - non-trivial for non-windows - checkout the cefclient source and the platform specific cpp, like cefclient_osr_widget_gtk.cpp for linux
        // browser->GetHost()->SendKeyEvent(...);
        // browser->GetHost()->SendMouseMoveEvent(...);
        // browser->GetHost()->SendMouseClickEvent(...);
        // browser->GetHost()->SendMouseWheelEvent(...);
    }
   
    /*{
        browser = nullptr;
        browserClient = nullptr;
        CefShutdown();

       /* renderScene->destroyAllMovableObjects();
        delete renderScene;
        delete renderSystem;
        delete renderHandler;*/
    //}

    return true;

}



I get a call in GetViewRect but after about 5 seconds it hits the assert.
synth
Newbie
 
Posts: 7
Joined: Wed Dec 13, 2017 1:19 pm

Re: CEF Integration with the Juce Framework

Postby magreenblatt » Thu Dec 14, 2017 2:53 pm

Where are you calling startCEF from? CefExecuteProcess should be executed from the main() function before anything else.
magreenblatt
Site Admin
 
Posts: 12382
Joined: Fri May 29, 2009 6:57 pm

Re: CEF Integration with the Juce Framework

Postby synth » Thu Dec 14, 2017 3:44 pm

Thanks so much! That solved it.

I changed the last part of the code to:
Code: Select all
juce::JUCEApplicationBase* juce_CreateApplication() { return new glcefApplication(); }

extern "C" int __stdcall WinMain(struct HINSTANCE__*, struct HINSTANCE__*, char*, int)
{
   startCEF(NULL);

   juce::JUCEApplicationBase::createInstance = &juce_CreateApplication;
   return juce::JUCEApplicationBase::main();
}


This seems to be the main function generated by various Juce macros for Windows. Manually expanding them and putting in the startCEF() before Juce initialization solved the issue.
synth
Newbie
 
Posts: 7
Joined: Wed Dec 13, 2017 1:19 pm


Return to Support Forum

Who is online

Users browsing this forum: No registered users and 34 guests