把cef3集成到MFC中的一些坑

作者: 毛毛v5 | 来源:发表于2019-03-13 15:11 被阅读0次

    cef3变化太大了。要注意版本。笔者所用版本为:cef_binary_3.3626.1895.g7001d56_windows32 版本。在将cef3集成到MFC时,遇到了一些问题。google了很多文档,都是针对几个月之前的版本,由于api变化太多,某些坑不能解决。现在做一下记录,防止下次再掉坑里。

    cef3官方代码每隔几天都编译发布一次,版本更新太快,api接口变化大,所以这里保存一个版本,可以对本文档的稳定行有好处。

    cef_binary_3.3626.1895.g7001d56_windows32 版本 百度网盘

    链接: https://pan.baidu.com/s/1mZQlgbWRQH72-YJw5tHFFA 提取码: 1z3z 

    cef3下载下来解压,之后用CMake生成vs2017工程文件。CMake步骤如下:

    1.指定cef3解压之后目录

    2.指定vs工程生成目录

    3.点击configure按钮。configure好了之后还要点一下configure

    4.点击Generate按钮生成vs工程。

    5.点击Open Project 打开vs工程。

    点击菜单“生成” 生成libcef_wrapper包装库。libcef_dll_wrapper.lib

    笔者的cef目录是:H:\DEVTOOLS\project\git\common\cef_binary_3.3626.1895.g7001d56_windows32

    这个目录在自己的工程中要用到,要记清楚。另外在tests\cefsimple目录还有两个manifest文件:cefsimple.exe.manifest 和 compatibility.manifest 。这两个文件也要copy到要集成cef3的工程中。

    1,把cef工程的tests/cefsimple文件夹中的如上图红框中的 simple_app.h , simple_handler.h , simple_app.cc , simple_handler.cc , simple_handler_win.cc 这几个文件copy到自己工程的目录并加入工程。

    2,将 simple_app.cc中的 void SimpleApp::OnContextInitialized()  修改成如下:

    void SimpleApp::OnContextInitialized() {

    CEF_REQUIRE_UI_THREAD();

    return; // 直接return 需要其他创建浏览器界面的代码,因为我们要在其他地方自己控制窗口创建。

    }

    3,自己工程的CWinApp.h文件修改如下:

    #pragma once

    #ifndef __AFXWIN_H__

    #error "在包含此文件之前包含“stdafx.h”以生成 PCH 文件"

    #endif

    #include "resource.h" // 主符号

    #include "simple_app.h"

    #include "simple_handler.h"

    // CLiveWin32App:

    // 有关此类的实现,请参阅 LiveWin32.cpp

    //

    class CLiveWin32App : public CWinApp

    {

    public:

    CLiveWin32App();

    // 重写

    public:

    virtual BOOL InitInstance();

    CefRefPtr<SimpleApp> app;

    CefRefPtr<SimpleHandler> handler;

    CefMainArgs main_args;

    // 实现

    DECLARE_MESSAGE_MAP()

    virtual int ExitInstance();

    };

    extern CLiveWin32App theApp;

    CWinApp.cpp文件修改如下:

    InitInstance() 中让cef3自己用CefExecuteProcess启动自己的render和browser进程。这个一定要在自己的程序的所有逻辑前面,因为CefExecuteProcess之前的所有代码都是cef3的render和browser的多进程里面的代码。CefExecuteProcess 之后再写自己的代码,比如创建窗口什么的。

    ExitInstance()中关闭cef3。CefShutdown();

    #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

    #ifdef _DEBUG

    #define new DEBUG_NEW

    #endif

    // CLiveWin32App 初始化

    BOOL CLiveWin32App::InitInstance()

    {

    // 如果一个运行在 Windows XP 上的应用程序清单指定要

    // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式,

    //则需要 InitCommonControlsEx()。  否则,将无法创建窗口。

    INITCOMMONCONTROLSEX InitCtrls;

    InitCtrls.dwSize = sizeof(InitCtrls);

    // 将它设置为包括所有要在应用程序中使用的

    // 公共控件类。

    InitCtrls.dwICC = ICC_WIN95_CLASSES;

    InitCommonControlsEx(&InitCtrls);

    // Enable High-DPI support on Windows 7 or newer.

    // 这里是启动cef3的render进程和browser进程等,cef3是多进程模式,

    CefEnableHighDPISupport();

    void* sandbox_info = NULL;

    app = (new SimpleApp);

    handler = (new SimpleHandler(false));

    main_args = CefMainArgs(this->m_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, app.get(), sandbox_info);

    if (exit_code >= 0) {

    // The sub-process has completed so return here.

    return exit_code;

    }

    CWinApp::InitInstance();

    AfxEnableControlContainer();

    CShellManager *pShellManager = new CShellManager;

    CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));

    SetRegistryKey(_T("应用程序向导生成的本地应用程序"));

    CLiveWin32Dlg dlg;

    m_pMainWnd = &dlg;

    INT_PTR nResponse = dlg.DoModal();

    if (nResponse == IDOK)

    {

    // TODO:  在此放置处理何时用

    //  “确定”来关闭对话框的代码

    }

    else if (nResponse == IDCANCEL)

    {

    // TODO:  在此放置处理何时用

    //  “取消”来关闭对话框的代码

    }

    else if (nResponse == -1)

    {

    TRACE(traceAppMsg, 0, "警告: 对话框创建失败,应用程序将意外终止。\n");

    TRACE(traceAppMsg, 0, "警告: 如果您在对话框上使用 MFC 控件,则无法 #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS。\n");

    }

    // 删除上面创建的 shell 管理器。

    if (pShellManager != NULL)

    {

    delete pShellManager;

    }

    // 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序,

    //  而不是启动应用程序的消息泵。

    return FALSE;

    }

    int CLiveWin32App::ExitInstance()

    {

    // TODO: 在此添加专用代码和/或调用基类

    CefShutdown();

    return CWinApp::ExitInstance();

    }

    到这里cef3就成功启动了多进程模式。然后我们要初始化cef库。在CLiveWin32Dlg.cpp文件中的CLiveWin32Dlg::OnInitDialog()里面初始化并创建窗口。这里特别注意的时 settings.multi_threaded_message_loop = true; 一定要设置成true,这样cef3就可以利用windows的消息循环,不然cef3没有办法处理消息,界面就出不来,我就掉这个坑里面了。开始没有设置,结果对话框里面的浏览器界面死活不出来。调试了半天,才想到这个问题。因为cef3的两个实例都是用的 CefRunMessageLoop(); 来阻塞处理消息的。。。,另外一定要 SetAsChild ,这样创建的窗口就能是一个子窗口了。

    // CLiveWin32Dlg 消息处理程序

    BOOL CLiveWin32Dlg::OnInitDialog()

    {

    CDialogEx::OnInitDialog();

    // 将“关于...”菜单项添加到系统菜单中。

    // IDM_ABOUTBOX 必须在系统命令范围内。

    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);

    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);

    if (pSysMenu != NULL)

    {

    BOOL bNameValid;

    CString strAboutMenu;

    bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);

    ASSERT(bNameValid);

    if (!strAboutMenu.IsEmpty())

    {

    pSysMenu->AppendMenu(MF_SEPARATOR);

    pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);

    }

    }

    SetIcon(m_hIcon, TRUE); // 设置大图标

    SetIcon(m_hIcon, FALSE); // 设置小图标

    //* ShowWindow(SW_MINIMIZE);

    // TODO:  在此添加额外的初始化代码

    // Specify CEF global settings here.

    CefSettings settings;

    settings.log_severity = cef_log_severity_t::LOGSEVERITY_VERBOSE;

    settings.multi_threaded_message_loop = 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.

    //CefMainArgs main_args(theApp.m_hInstance);

    theApp.app.get()->hWnd = GetSafeHwnd();

    // Initialize CEF.

    CefInitialize(theApp.main_args, settings, theApp.app.get(), NULL);

    // 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 = "http://www.qq.com";

    CefWindowInfo window_info;

    #if defined(OS_WIN)

    // On Windows we need to specify certain flags that will be passed to

    // CreateWindowEx().

    RECT rc;

    rc.left = 0;

    rc.top = 0;

    rc.bottom = 500;

    rc.right = 500;

    window_info.SetAsChild(m_hWnd, rc);

    //window_info.SetAsPopup(NULL, "cefsimple");

    #endif

    // Create the first browser window.

    CefBrowserHost::CreateBrowser(window_info, theApp.handler, url, browser_settings,

    NULL);

    return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE

    }

    到这里代码部分就搞定了,开始编译。我去。找不到文件头?找不到库文件。。好吧。设置如下:

    工程属性里面,包含文件路径,库文件路径,都要设置到刚刚解压的目录。加入你理得清相对路径,就用上图一样的相对路径。或者用绝对路径就简单点。然后如下图,加入附加库。liebcef和libcef_wrapper

    开始编译,编译成功!运行!哎哎哎为啥还是白屏?????因为还有manifest文件没加。如下图:test/cefsimple目录copy过来的cefsimple.exe.manifest文件。

    然后再生成事件,选项中生成之后加入:

    以上大红框的内容为(exe路径,manifest路径改成你自己的):

    setlocal

    mt.exe -nologo -manifest "$(ProjectDir)cefsimple.exe.manifest" "$(ProjectDir)compatibility.manifest" -outputresource:"$(ProjectDir)out\Win32\Debug\LiveWin32.exe";#1

    if %errorlevel% neq 0 goto :cmEnd

    :cmEnd

    endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone

    :cmErrorLevel

    exit /b %1

    :cmDone

    if %errorlevel% neq 0 goto :VCEnd

    然后编译。再运行,咋还是崩溃啊。。。因为cef3有好多依赖文件你要copy过来。。

    上图这些文件都要从cefsimple生成的目录copy到你的exe的目录。。。

    OK完工。福利来了,漂亮小姐姐来啦

    全部代码在全球最大同性交友网站上面,改的别人的一个开源代码,打算里面加入cef3用h5做界面。

    https://github.com/xiny120/anyRTC-RTMP-OpenSource

    相关文章

      网友评论

        本文标题:把cef3集成到MFC中的一些坑

        本文链接:https://www.haomeiwen.com/subject/qwwapqtx.html