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