In this section, I will create a blank C++Windows Desktop Application project using VS2019 under Windows, modify the configuration and code writing step by step, and introduce the process of using vs and the C++ project in the process. See the Github link at the end of this article for the source code.

The premise

You’ve already read Using CEF (1) — Getting started. You can read zhihu links, CNBlogs, Nuggets, or you know how to get the libcef library and the libcef_dll_wrapper static library.

Documents to prepare

Next, I will complete the code development work in Debug mode. The same is true for Release, but note that the target you select for Debug or Release needs to be exactly the same as the libcef library and libcef_dll_wrapper.

  • Now, you need the libcef library file, which comes from:

  • You need to use the libcef_dll_wrapper static library file, which comes from the static library you compiled:

  • You need the include file for libcef and wrapper, which comes from:

Next we create a folder named cef and place the above mentioned folders and files in it:

Cef │ libcef_dll_wrapper. Lib │ libcef_dll_wrapper. PDB │ ├─Debug │...... │ │ libEGL. DLL │ │ │ libEGL. DLL │ │ │...... │ libEGL │ │ ├ ─ ├ ─ sci-imp (├ ─ sci-imp, sci-imp, sci-imp, sci-imp, sci-imp, sci-imp, sci-imp, sci-imp, sci-imp, sci-imp, sci-imp, sci-imp, sci-imp, sci-imp, sci-imp, sci-imp, sci-imp, sci-imp, sci-imp, sci-imp, sci-imp, sci-imp, sci-imp │ cef_audio_handler. | h...Copy the code

With the basic files created, let’s start writing a simple CEF-based program.

Project creation

Create a Windows desktop application

Create a project named simple-cef

Once created, we remove all the template generated code and have a completely blank application project:

Depend on the add

Header file addition

As we all know, C/C++ header files play an important role in the compilation process as declarative definitions. When we introduced CEF to compile our project, we first needed headers in the correct location of the include to compile (narrow compilation, not including links). We first put the ceF folder in the project directory, that is, we add the CEF inlucde header and static library files to the project:

Then, in VS, we introduce CEF headers for our projects as follows:

Right-click the project — Properties — C/C++ — General — Additional Include Directories

PS: If you find there is no C/C++ classification, it is because you have not created any source files, official FAQ. So we create a main. CPP in the Source Files directory and continue with the above configuration.

PS: HERE I use $(ProjectDir), which is a VS macro variable that returns the project directory (that is, the directory where vCXproj is located) with a backslash \ at the end. The Evaluated value shown in the above Evaluated value can verify whether our configuration is correct. This correctly returns the CEF folder we placed in the project directory.

The cef/include header uses the corresponding “include/xxx.h” when included. That is, you need to find the include folder in the import directory to find the XXx. h header file. When we specify the CEF level, we can cause the compiler to properly handle the location of the include in the CEF header file.

**$(ProjectDir)cef/include/cef_broweser.h**

When the compiler found the # include precompiled command, will have to find in the file directory, namely the hope from the configuration of * * (ProjectDir) cef / ∗ ∗ and default directory lookup, the default project directory should be can’t find it, But can be in ∗ ∗ (ProjectDir) cef / * *, and the default directory lookup, the default project directory should be can’t find it, but it can in * * (ProjectDir) cef / ∗ ∗ and default directory lookup, the default project directory should be can’t find it, But files such as include/cef_base.h can be found in the ∗∗(ProjectDir)cef/ directory, as $(ProjectDir)cef/include/cef_base.h** is indeed the correct file path. Therefore, the above additional include folder only needs to be specified at the CEF level.

Library file addition

After adding the header file, we also need to add the link target, the static library of CEF. Add method:

Properties – Linker – Input – Additional Dependencies

Also use macro variables to specify the corresponding lib static libraries: libcef_dll_wrapper.lib, libcef.lib, cef_sandbox.lib.

By adding the library file above, we have completed the configuration of the two steps of compile (narrow, header file search) – link (library file link) **, and now it is time to take the next step and start our code writing road.

Code writing and specification

For the overall architecture of CEF and the concepts of CefApp and CefClient, please refer to the documentation in the repository or read the official documentation. Next, you’ll use cefSimple code to explain, adding some minor details as appropriate.

simple_app

simple_app.h

#ifndef SIMPLE_APP_H
#define SIMPLE_APP_H
#pragma once

#include "include/cef_app.h"

// Implement application-level callbacks for the browser process.
class SimpleApp : public CefApp, public CefBrowserProcessHandler {
public:
    SimpleApp(a);// CefApp methods:
    virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler(a)
        OVERRIDE {
        return this;
    }

    // CefBrowserProcessHandler methods:
    virtual void OnContextInitialized(a) OVERRIDE;

private:
    // Include the default reference counting implementation.
    IMPLEMENT_REFCOUNTING(SimpleApp);
};

#endif
Copy the code

If #include “include/cef_app.h” is not valid, first check that the above configuration is correct! The platform configured in the above project Properties is X64, please select the same platform in VS. And we won’t be able to use 32-bit in this Demo because the static library we downloaded is X64 bit.

simple_app.cpp

In the simple_APP implementation, three parts of the code implementation are mainly needed:

  • CefWindowDelegate
  • CefBrowserViewDelegate
  • SimpleApp
CefWindowDelegate and CefBrowserViewDelegate

Cef Forms Broker and Cef Browser View Broker, a set of graphical view frameworks provided by Cef. This set of graphical interfaces is now supported on Windows and Linux, so on Windows and Linux we can skip the native forms framework (such as WinForm on Windows and QT on Linux) and use the graphical view framework provided by CEF directly. The internal implementation of CEF’s graphical view framework is not yet known. You can think of them as forms and control objects that need to be implemented in SimpleApp, so they are also written in Simple_app.cpp. The relevant codes are as follows:

// SimpleBrowserViewDelegate
// Inherits CefBrowserViewDelegate, the CEF browser view delegate.
// This proxy is masked by CEF and only exposes the interface callbacks specified by the view control for implementation
class SimpleBrowserViewDelegate : public CefBrowserViewDelegate 
{
public: 
    SimpleBrowserViewDelegate() {}bool OnPopupBrowserViewCreated(CefRefPtr<CefBrowserView> browser_view,
                                   CefRefPtr<CefBrowserView> popup_browser_view,
                                   bool is_devtools) OVERRIDE
    {
        // Create a new top-level Window for the popup. It will show itself after
        // creation.
        CefWindow::CreateTopLevelWindow(
            new SimpleWindowDelegate(popup_browser_view));

        // We created the Window.
        return true;
    }

private:
    IMPLEMENT_REFCOUNTING(SimpleBrowserViewDelegate);
    DISALLOW_COPY_AND_ASSIGN(SimpleBrowserViewDelegate);
};
Copy the code
// SimpleWindowDelegate
// Inherits CefWindowDelegate, the CEF window delegate.
// This proxy is masked by CEF and exposes only the window for some interface callbacks to implement.
class SimpleWindowDelegate : public CefWindowDelegate
{
public: 
    explicit SimpleWindowDelegate(CefRefPtr<CefBrowserView> browser_view)
        : browser_view_(browser_view)
        {
        }
	// When the form is created
    void OnWindowCreated(CefRefPtr<CefWindow> window) OVERRIDE
    {
        // Add the browser view and show the window.
        window->AddChildView(browser_view_);
        window->Show(a);// Give keyboard focus to the browser view.
        browser_view_->RequestFocus(a); }// When the form is destroyed
    void OnWindowDestroyed(CefRefPtr<CefWindow> window) OVERRIDE
    {
        browser_view_ = nullptr;
    }
	// Whether the form can be closed
    bool CanClose(CefRefPtr<CefWindow> window) OVERRIDE
    {
        // Allow the window to close if the browser says it's OK.
        CefRefPtr<CefBrowser> browser = browser_view_->GetBrowser(a);if (browser)
            return browser->GetHost() - >TryCloseBrowser(a);return true;
    }
	// Get the best size for the form to display
    CefSize GetPreferredSize(CefRefPtr<CefView> view) OVERRIDE
    {
        return CefSize(800.600);
    }

private:
    CefRefPtr<CefBrowserView> browser_view_;

    IMPLEMENT_REFCOUNTING(SimpleWindowDelegate);
    DISALLOW_COPY_AND_ASSIGN(SimpleWindowDelegate);
};
Copy the code
SimpleApp
SimpleApp::SimpleApp() {}void SimpleApp::OnContextInitialized(a)
{
    CEF_REQUIRE_UI_THREAD(a); CefRefPtr<CefCommandLine> command_line = CefCommandLine::GetGlobalCommandLine(a);const bool enable_chrome_runtime =
        command_line->HasSwitch("enable-chrome-runtime");

#if defined(OS_WIN) || defined(OS_LINUX)
    // Create the browser using the Views framework if "--use-views" is specified
    // via the command-line. Otherwise, create the browser using the native
    // platform framework. The Views framework is currently only supported on
    // Windows and Linux.
    const bool use_views = command_line->HasSwitch("use-views");
#else
    const bool use_views = false;
#endif

    // SimpleHandler implements browser-level callbacks.
    CefRefPtr<SimpleClient> handler(new SimpleClient(use_views));

    // Specify CEF browser settings here.
    CefBrowserSettings browser_settings;

    std::string url;

    // Check if a "--url=" value was provided via the command-line. If so, use
    // that instead of the default URL.
    url = command_line->GetSwitchValue("url");
    if (url.empty())
        url = "https://www.cnblogs.com/w4ngzhen/";

    if(use_views && ! enable_chrome_runtime) {// Create the BrowserView.
        CefRefPtr<CefBrowserView> browser_view = CefBrowserView::CreateBrowserView(
            handler, url, browser_settings, nullptr.nullptr.new SimpleBrowserViewDelegate());

        // Create the Window. It will show itself after creation.
        CefWindow::CreateTopLevelWindow(new SimpleWindowDelegate(browser_view));
    }
    else
    {
        // Information used when creating the native window.
        CefWindowInfo window_info;

#if defined(OS_WIN)
        // On Windows we need to specify certain flags that will be passed to
        // CreateWindowEx().
        window_info.SetAsPopup(NULL."simple-cef by w4ngzhen");
#endif

        // Create the first browser window.
        CefBrowserHost::CreateBrowser(window_info, handler, url, browser_settings,
                                      nullptr.nullptr); }}Copy the code

simple_client

simple_client.h
#ifndef SIMPLE_CLIENT_H
#define SIMPLE_CLIENT_H

#include "include/cef_client.h"

#include <list>

class SimpleClient : public CefClient,
                     public CefDisplayHandler,
                     public CefLifeSpanHandler,
                     public CefLoadHandler
{
public:
	explicit SimpleClient(bool use_views);
	~SimpleClient(a);static SimpleClient* GetInstance(a);

	virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler(a) OVERRIDE
	{ return this; }

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

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

	// CefDisplayHandler implementation declaration:
	virtual void OnTitleChange(CefRefPtr<CefBrowser> browser,
	                           const CefString& title) OVERRIDE;
	// Ceflifespan:
	virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;
	virtual bool DoClose(CefRefPtr<CefBrowser> browser) OVERRIDE;
	virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE;
	// CefLoadHandler implementation declaration:
	virtual void OnLoadError(CefRefPtr<CefBrowser> browser,
	                         CefRefPtr<CefFrame> frame,
	                         ErrorCode errorCode,
	                         const CefString& errorText,
	                         const CefString& failedUrl) OVERRIDE;
	
	void CloseAllBrowsers(bool force_close); // Request that all existing browser forms be closed
	bool IsClosing(a) const { return is_closing_; }

private:
	// Platform-specific title modifications
    // When we don't have CEF's GUI view framework, we need platform-specific title modification implementations
    // For example, in Windows, we need to get the form handle and call Windows API to complete the modification of the form title
	void PlatformTitleChange(CefRefPtr<CefBrowser> browser,
	                         const CefString& title);
	const bool use_views_; // Whether CEF's GUI view framework is used
	// List of existing browser windows. Only accessed on the CEF UI thread.
	typedef std::list<CefRefPtr<CefBrowser>> BrowserList;
	BrowserList browser_list_;

	bool is_closing_;

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

#endif
Copy the code
Simple_client. CPP and simple_client_os_win. CPP

Here we provide two source code sources, the first is a common implementation for all platforms, and the second source code, as the name suggests, is related to a particular operating system platform, which is Windows.

First look at simple_client.cpp source code:

#include "simple_client.h"

#include <sstream>
#include <string>

#include "include/base/cef_bind.h"
#include "include/cef_app.h"
#include "include/cef_parser.h"
#include "include/views/cef_browser_view.h"
#include "include/views/cef_window.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_helpers.h"

namespace
{
    SimpleClient* g_instance = nullptr;

    // Returns a data: URI with the specified contents.
    std::string GetDataURI(const std::string& data, const std::string& mime_type)
    {
        return "data:" + mime_type + "; base64," +
            CefURIEncode(CefBase64Encode(data.data(), data.size()), false).ToString();
    }
} // namespace

SimpleClient::SimpleClient(bool use_views)
    : use_views_(use_views), is_closing_(false)
{
    DCHECK(! g_instance); g_instance =this;
}

SimpleClient::~SimpleClient()
{
    g_instance = nullptr;
}

// static
SimpleClient* SimpleClient::GetInstance(a)
{
    return g_instance;
}

void SimpleClient::OnTitleChange(CefRefPtr<CefBrowser> browser,
                                 const CefString& title)
{
    CEF_REQUIRE_UI_THREAD(a);if (use_views_)
    {
        // If CEF's GUI view frame is used, modifying the form's title is done by calling the VIEW frame's API
        CefRefPtr<CefBrowserView> browser_view =
            CefBrowserView::GetForBrowser(browser);
        if (browser_view)
        {
            CefRefPtr<CefWindow> window = browser_view->GetWindow(a);if (window)
                window->SetTitle(title); }}else
    {
        // Otherwise use the platform-specific form title modification API
        // See simple_client_OS_win.cpp for details
        PlatformTitleChange(browser, title); }}void SimpleClient::OnAfterCreated(CefRefPtr<CefBrowser> browser)
{
    CEF_REQUIRE_UI_THREAD(a);// Add to the list of existing browsers.
    browser_list_.push_back(browser);
}

bool SimpleClient::DoClose(CefRefPtr<CefBrowser> browser)
{
    CEF_REQUIRE_UI_THREAD(a);// Closing the main window requires special handling. See the DoClose()
    // documentation in the CEF header for a detailed destription of this
    // process.
    if (browser_list_.size() = =1)
    {
        // Set a flag to indicate that the window close should be allowed.
        is_closing_ = true;
    }

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

void SimpleClient::OnBeforeClose(CefRefPtr<CefBrowser> browser)
{
    CEF_REQUIRE_UI_THREAD(a);// Remove from the list of existing browsers.
    BrowserList::iterator bit = browser_list_.begin(a);for(; bit ! = browser_list_.end(a); ++bit) {if ((*bit)->IsSame(browser))
        {
            browser_list_.erase(bit);
            break; }}if (browser_list_.empty())
    {
        // All browser windows have closed. Quit the application message loop.
        CefQuitMessageLoop();
    }
}

void SimpleClient::OnLoadError(CefRefPtr<CefBrowser> browser,
                               CefRefPtr<CefFrame> frame,
                               ErrorCode errorCode,
                               const CefString& errorText,
                               const CefString& failedUrl)
{
    CEF_REQUIRE_UI_THREAD(a);// Don't display an error for downloaded files.
    if (errorCode == ERR_ABORTED)
        return;

    // Display a load error message using a data: URI.
    std::stringstream ss;
    ss << "<html><body bgcolor=\"white\">"
        "<h2>Failed to load URL "
        << std::string(failedUrl) << " with error " << std::string(errorText)
        << "(" << errorCode << ").</h2></body></html>";

    frame->LoadURL(GetDataURI(ss.str(), "text/html"));
}

void SimpleClient::CloseAllBrowsers(bool force_close)
{
    if (!CefCurrentlyOn(TID_UI))
    {
        // Execute on the UI thread.
        CefPostTask(TID_UI, base::Bind(&SimpleClient::CloseAllBrowsers, this,
                                       force_close));
        return;
    }

    if (browser_list_.empty())
        return;

    BrowserList::const_iterator it = browser_list_.begin(a);for(; it ! = browser_list_.end(a); ++it) (*it)->GetHost() - >CloseBrowser(force_close);
}
Copy the code

The code above is important part for function SimpleClient: : OnTitleChange implementation. In this implementation code, the use_views_ variable is used to determine whether to use the CEF view frame. There are two cases:

  • Using the CEF view framework: In this case, the title of the form is changed directly using the CEF view framework API;
  • No VIEW framework provided by CEF: In this case, we must be using either a native form framework or a third party framework (QT or GTK+), so we need to call the relevant native form API or a third party API to modify the form title.

The following code for simple_client_OS_win.cpp is due to the above situation. (PS: the above code does not implement the PlatformTitleChange declaration in the header file, just calls it.)

/ / simple_client_os_win. CPP code
#include "simple_client.h"

#include <windows.h>
#include <string>

#include "include/cef_browser.h"

void SimpleClient::PlatformTitleChange(CefRefPtr<CefBrowser> browser,
    const CefString& title) {
    // Use GetHost() to get the host object of the CEF browser object (here is the Native Windows form)
    // Get the corresponding window handle
    // Use #include 
      
        to complete the title modification
      
    CefWindowHandle hwnd = browser->GetHost() - >GetWindowHandle(a);if (hwnd)
        SetWindowText(hwnd, std::wstring(title).c_str());
}
Copy the code

This code is actually platform-specific, in this case the Windows platform.

  1. GetHost() to get the host object of the CEF browser object (in this case, the Native Windows form);
  2. Then get the corresponding window handle;
  3. Complete the title modification through the WindowsAPI obtained with #include

    .

The entry code main.cpp

After writing the above CEF application module, we finally write the entry code.

// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.

#include <windows.h>

#include "include/cef_command_line.h"
#include "include/cef_sandbox_win.h"
#include "simple_app.h"

// When generating projects with CMake the CEF_USE_SANDBOX value will be defined
// automatically if using the required compiler version. Pass -DUSE_SANDBOX=OFF
// to the CMake command-line to disable use of the sandbox.
// Uncomment this line to manually enable sandbox support.
// #define CEF_USE_SANDBOX 1

#if defined(CEF_USE_SANDBOX)
// The cef_sandbox.lib static library may not link successfully with all VS
// versions.
#pragma comment(lib, "cef_sandbox.lib")
#endif

// 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(a);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(a);#endif

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

    // CEF applications have multiple sub-processes (render, plugin, 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(a); command_line->InitFromString(: :GetCommandLineW());

    // 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);

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

    // Run the CEF message loop. This will block until CefQuitMessageLoop() is
    // called.
    CefRunMessageLoop(a);// Shut down CEF.
    CefShutdown(a);return 0;
}
Copy the code

Compile and run

After the above code is completed, our code structure is as follows:

We right-click the project and try to compile it using the Build directive. If nothing else, we should see something like this:

error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MTd_StaticDebug' doesn't match value 'MDd_DynamicDebug'
Copy the code

Runtime library not detected: MTd_StaticDebug cannot match MDd_DynamicDebug. What is MDd? Key words: MD, MDd, MT and MTd. You can refer to this article to learn more about the difference between VS runtime /MD and /MDd and /MT and /MTd. To put it simply, we compiled a flag for the libcef_dll_wrapper.lib library that is different from the flag for the program we are currently compiling: one is MTd and one is MDd. So where does this sign go? Properties — C/C++ — Code Generation — Runtime Library

In our Simple project, VS uses MDd by default when creating the project, so what about libcef_dll_wrapper.lib? MTd is used in the project directory where libcef_dll_wrapper.lib is compiled in the article using CEF (1) – Getting started. Here’s a look back at the runtime types used by the project:

Of course, specific circumstances also need to be judged. For example, Debug is different from Release, or MD(d) was actually compiled at the time. Here we modify the RuntimeLibrary of our Simple project to the corresponding MTd and compile again. Not surprisingly, you should see the following compiled success output:

Rebuild started...
1>------ Rebuild All started: Project: simple-cef, Configuration: Debug x64 ------
1>main.cpp
1>simple_app.cpp
1>simple_client.cpp
1>simple_client_os_win.cpp
1>Generating Code...
1>simple-cef.vcxproj -> D:\Projects\cef-projects\simple-cef\x64\Debug\simple-cef.exe
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========
Copy the code

So, we run the generated exe, not out of the accident will have a pop-up error.

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- simple cef. Exe - system error -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- because I couldn't find libcef. DLL, can't continue to execute code. A reinstallation program may resolve this problem. -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- sure -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --Copy the code

A check of the directory reveals that there is indeed only a single executable program, with no dependent libraries. At this point, we need to copy all dependent files to the running directory. The following parts need to be copied:

  • Resources

Copy all files and subfolders in the Resources folder to the run directory.

  • CEF relies on library files

Copy the components shown above to the run directory except for the two lib library files.

At this point, our compiled run directory is as follows:

We try to run the simple-cef again and it opens successfully, but again, as expected, we see a browser window with a white screen. You will first see the title, and then the corresponding blank:

Check failed: fallback_available == base::win::GetVersion() > Base ::win::Version::WIN8 (1 vs. 0)

After the blank screen is displayed, a debug. Log file is displayed in the running directory.

/ / debug. The log [0124/113454.346: INFO: content_main_runner_impl. Cc (976)] Chrome is running in full browser mode. [0124/113454.488: FATAL: dwrite_font_proxy_init_impl_win. Cc (91) "the Check failed: fallback_available == base::win::GetVersion() > base::win::Version::WIN8 (1 vs. 0) [0124/113454.545: FATAL: dwrite_font_proxy_init_impl_win. Cc (91) "the Check failed: fallback_available == base::win::GetVersion() > base::win::Version::WIN8 (1 vs. 0)Copy the code

Error: CEF base::win::GetVersion() > Base ::win::Version::WIN8. CEF Forum Check failed: fallback_available (magpcss.org) Simply put, the browser program cannot load the manifest file and thus cannot handle the version of the operating system.

The solution

  1. Create the manifest file and place it in the project root directory

Create a manifest file in the root directory of the project: simple-cef.manifest

<? The XML version = "1.0" encoding = "utf-8"? > <assembly XMLNS ="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> <application> <! --The ID below Indicates Application Support for Windows Windows 8.1 --> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> <! SupportedOS Id="{8e0f7a12-BFB3-4fe8-b9a5-48FD50a15a9A}"/> </application> </ Compatibility > </assembly>Copy the code
  1. Add the above manifest for your project

Open the project properties, go to the Manifest Tool — Input and Output — Additional Manifest Files, and select simple-Cef. Manifest in the root directory of the project.

After saving, we built the project again and ran our simple-Cef.exe, finally seeing the long-awaited page:

Written in the end

After many steps, we finally got a web page, but this does not mean that our journey to use CEF is over. On the contrary, through this Demo, we have been exposed to more things, including CefApp, CefClient class, CefBrowserProcessHandler, etc. What are these classes for? CefWindowDelegate, CefBrowserViewDelegate what are the concepts of forms GUI proxies provided by the CEF framework here? What is the cross-platform implementation strategy of CEF? The questions only increase, and I will continue to explore and summarize these questions.

The source code

w4ngzhen/simple-cef (github.com)

PS: In the modified source code, the above CEF-related libraries and include files are not included in the source library, because the static library is too large. Readers are invited to compile and add as specified.