返回

Visual Studio 2019构建CEF样例:踏出高效开发的第一步

前端




前言

CEF(Chromium Embedded Framework)是一个开源框架,将Chromium嵌入其他应用程序,使其能够展现网页内容。在上一节中,我们已经完成了CEF的配置与编译工作。现在,让我们在Visual Studio 2019中创建一个空白的C++Windows Desktop Application项目,并逐步进行CEF样例编写。

创建空白C++ Windows Desktop Application项目

  1. 打开Visual Studio 2019
  2. 点击“新建”->“项目”
  3. 选择“Visual C++”->“桌面”->“Windows桌面应用程序”
  4. 输入项目名称,选择项目位置,点击“创建”

添加CEF库

  1. 在解决方案资源管理器中,右键单击项目名称,选择“添加”->“现有项”
  2. 导航到CEF库的目录,选择“include”和“lib”文件夹,点击“添加”

配置项目属性

  1. 在解决方案资源管理器中,右键单击项目名称,选择“属性”
  2. 在“配置属性”->“常规”中,将“字符集”设置为“使用Unicode字符集”
  3. 在“配置属性”->“链接器”->“常规”中,将“子系统”设置为“控制台”
  4. 在“配置属性”->“链接器”->“输入”中,添加CEF库的库文件路径,如“C:\path\to\cef\lib\x64\cef.lib”
  5. 在“配置属性”->“链接器”->“附加依赖项”中,添加CEF库的依赖项,如“libcef_dll_wrapper.lib;libcef.lib;libcrypto.lib;libicudate.lib;libicuuc.lib;libbrotlidec.lib;libbrotlienc.lib;libssl.lib”

创建主窗口类

  1. 在解决方案资源管理器中,右键单击项目名称,选择“添加”->“新建项”
  2. 选择“代码”->“C++文件(.cpp)”
  3. 输入文件名,如“MainWindow.cpp”,点击“添加”
  4. 在MainWindow.cpp中添加如下代码:
#include <windows.h>
#include <commctrl.h>

class MainWindow : public HWND
{
public:
    MainWindow();
    ~MainWindow();

    BOOL Create(HINSTANCE hInstance, int nCmdShow);
    void Destroy();

private:
    HINSTANCE m_hInstance;
    HWND m_hWnd;
};

MainWindow::MainWindow()
{
    m_hInstance = nullptr;
    m_hWnd = nullptr;
}

MainWindow::~MainWindow()
{
    Destroy();
}

BOOL MainWindow::Create(HINSTANCE hInstance, int nCmdShow)
{
    m_hInstance = hInstance;

    WNDCLASSEXW wc = { 0 };
    wc.cbSize = sizeof(wc);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
    wc.lpszClassName = L"MainWindow";
    RegisterClassExW(&wc);

    m_hWnd = CreateWindowExW(0, L"MainWindow", L"CEF Example", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, nullptr, nullptr, hInstance, this);
    if (m_hWnd == nullptr)
    {
        return FALSE;
    }

    ShowWindow(m_hWnd, nCmdShow);
    UpdateWindow(m_hWnd);

    return TRUE;
}

void MainWindow::Destroy()
{
    if (m_hWnd != nullptr)
    {
        DestroyWindow(m_hWnd);
        m_hWnd = nullptr;
    }

    UnregisterClassW(L"MainWindow", m_hInstance);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    MainWindow* pThis = (MainWindow*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);

    switch (message)
    {
    case WM_CREATE:
        {
            CREATESTRUCTW* pCreateStruct = (CREATESTRUCTW*)lParam;
            SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)pCreateStruct->lpCreateParams);
        }
        break;
    case WM_DESTROY:
        {
            PostQuitMessage(0);
        }
        break;
    default:
        return DefWindowProcW(hWnd, message, wParam, lParam);
    }

    return 0;
}

int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
    MainWindow window;
    if (!window.Create(hInstance, nCmdShow))
    {
        return -1;
    }

    MSG msg;
    while (GetMessageW(&msg, nullptr, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessageW(&msg);
    }

    return (int)msg.wParam;
}

添加CEF控件

  1. 在解决方案资源管理器中,右键单击项目名称,选择“添加”->“新建项”
  2. 选择“CEF”->“CEF控件”
  3. 输入文件名,如“CEFControl.cpp”,点击“添加”
  4. 在CEFControl.cpp中添加如下代码:
#include "CEFControl.h"

#include <windows.h>
#include <commctrl.h>

#include <string>
#include <vector>

#include <include/cef_base.h>
#include <include/cef_app.h>
#include <include/cef_browser.h>
#include <include/cef_client.h>
#include <include/cef_command_line.h>
#include <include/cef_frame.h>
#include <include/cef_runnable.h>
#include <include/cef_string.h>
#include <include/cef_version.h>

class CEFControl : public HWND
{
public:
    CEFControl();
    ~CEFControl();

    BOOL Create(HINSTANCE hInstance, HWND hParentWnd);
    void Destroy();

    void LoadURL(const std::string& url);

private:
    HINSTANCE m_hInstance;
    HWND m_hWnd;
    HWND m_hParentWnd;

    CefRefPtr<CefBrowser> m_browser;
};

CEFControl::CEFControl()
{
    m_hInstance = nullptr;
    m_hWnd = nullptr;
    m_hParentWnd = nullptr;

    m_browser = nullptr;
}

CEFControl::~CEFControl()
{
    Destroy();
}

BOOL CEFControl::Create(HINSTANCE hInstance, HWND hParentWnd)
{
    m_hInstance = hInstance;
    m_hParentWnd = hParentWnd;

    CefMainArgs mainArgs(hInstance);

    CefRefPtr<CefCommandLine> commandLine = CefCommandLine::CreateCommandLine();
    commandLine->InitFromString(mainArgs.command_line_args_utf8());

    CefSettings settings;
    settings.single_process = true;
    settings.no_sandbox = true;
    settings.windowless_frame_rate = 30;

    CefInitialize(mainArgs, settings, commandLine.get());

    RECT rect;
    GetClientRect(m_hParentWnd, &rect);

    CefWindowInfo windowInfo;
    windowInfo.SetAsChild(m_hParentWnd, rect);

    CefRefPtr<CefClient> client(new CefClient());
    m_browser = CefBrowserHost::CreateBrowser(windowInfo, client.get(), "https://www.google.com");

    m_hWnd = m_browser->GetHost()->GetWindowHandle();

    return TRUE;
}

void CEFControl::Destroy()
{
    if (m_browser != nullptr)
    {
        m_browser->Get