把cef3集成到MFC中的一些坑

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom阅读 2,615评论 0 3
  • Lua 5.1 参考手册 by Roberto Ierusalimschy, Luiz Henrique de F...
    苏黎九歌阅读 13,517评论 0 38
  • 别说话没用
    还需要记得阅读 110评论 0 0
  • 草籽被埋在土下/它什么都不知道/黑漆漆的土壤/是它最初的家 草籽被埋在土下/它什么都知道/黑漆漆的土壤/无法阻碍它...
    草籽阅读 329评论 0 6
  • 突然之间变得很安静比以往安静的自己更安静一些 每当自己安静下来时就想和自己说说话 于我而言写文字是和自己最好的沟通...
    爱笑的芦微阅读 182评论 0 0