目录
一、编译CEF3里的lib:
1.下载CEF3
http://opensource.spotify.com/cefbuilds/index.html
2.下载CMake,运行CMake_GUI.exe
3.CMake设置CEF3的Sources文件夹路径,与新new build路径后,点击“Configure”
4.选择编译平台,无后缀表示32位,ARM,Win64表示各自平台,这里我们选择VS2017位编译
5.等待Configuring Done结束,点“Generate”按钮
注意路径中不能有'\',只能有'/',否则会提示“Invalid escape sequence \o”错误
6.使用VS打开cef工程
二、开始在MFC中使用Cef3(多进程和单进程讲解):
1.新建一个MFC基础窗口程序
2.把Cef3 SDK里的文件整理出来,并放进自己工程文件夹里,整理出来的效果如图
3.配置工程属性
4.添加文件到工程
5.在MFC中正式写代码前还要做一件事,就是要先学习如何在纯Win32中使用CEF3!
a.打开cef目录里的test/cefsimple
b.学习cefsimple示例工程
c.理解Cef3的多进程与单进程之间的关系
6.开始写Cef3的初始化代码
7.开始写创建Cef3窗口控件的代码
8.增加 多进程Release与单进程Debug之间的切换代码
成功运行!
三、难点及疑问解答
Q:为什么cefsimple Win32可以运行,直接复制到MFC中却运行不起来?
A:如果需要在MFC环境中运行,还需要在CEF3初始化的参数加上
Q:为什么调用CefShutdown会崩溃?
A:多进程模式下调用CefShutdown就是OK的,app也能够正常析构,而单进程模式调用CefShutdown会直接崩溃!
Q:为什么SimpleHandler这个类没有办法获取CefBrowser句柄?
A:自己增加两个函数就很方便啦
一、编译CEF3里的lib:
1.下载CEF3
http://opensource.spotify.com/cefbuilds/index.html
2.下载CMake,运行CMake_GUI.exe
3.CMake设置CEF3的Sources文件夹路径,与新new build路径后,点击“Configure”
4.选择编译平台,无后缀表示32位,ARM,Win64表示各自平台,这里我们选择VS2017位编译
5.等待Configuring Done结束,点“Generate”按钮
注意路径中不能有'\',只能有'/',否则会提示“Invalid escape sequence \o”错误
6.使用VS打开cef工程
二、开始在MFC中使用Cef3(多进程和单进程讲解):
1.新建一个MFC基础窗口程序
2.把Cef3 SDK里的文件整理出来,并放进自己工程文件夹里,整理出来的效果如图
bin->x86->Debug来源于:
D:\cef_binary_3.3626.1891.g52be333_windows32\Debug
bin->x86->Release来源于:
D:\cef_binary_3.3626.1891.g52be333_windows32\Release
include来源于:
D:\cef_binary_3.3626.1891.g52be333_windows32\include
lib->x86->Debug来源于:
D:\cef_binary_3.3626.1891.g52be333_windows32\Debug 里的lib后缀文件
lib->x86->Release来源于:
D:\cef_binary_3.3626.1891.g52be333_windows32\Release 里的lib后缀文件
Resources来源于:
D:\cef_binary_3.3626.1891.g52be333_windows32\Resources
其他来源于:
D:\cef_binary_3.3626.1891.g52be333_windows32\tests\cefsimple
3.配置工程属性
-
xcopy /e /r /y
"$(ProjectDir)CEF3\bin\x86\Debug"
"$(OutDir)"
-
xcopy /e /r /y
"$(ProjectDir)CEF3\Resources"
"$(OutDir)"
-
xcopy /e /r /y
"$(ProjectDir)CEF3\bin\x86\Release"
"$(OutDir)"
-
xcopy /e /r /y
"$(ProjectDir)CEF3\Resources"
"$(OutDir)"
4.添加文件到工程
5.在MFC中正式写代码前还要做一件事,就是要先学习如何在纯Win32中使用CEF3!
a.打开cef目录里的test/cefsimple
b.学习cefsimple示例工程
(里面每个文件都要认真看一遍,不然后面MFC的示例 你很难看懂原理)
文件说明:
cefsimple_win.cc:Win32主程序的main入口演示
simple_handler.cc:Chrome浏览器控件的回调函数演示
simple_handler.h
simple_app.cc:初始化Chrome浏览器控件演示
simple_app.h
c.理解Cef3的多进程与单进程之间的关系
在Debug模式中要使用单进程,只有Release模式中才使用多进程。
因为CEF3多进程的时候Browser、Rendder等进程是独立分开的,在一些函数上打断点是打不进去的,无法调试!而单进程话就可以正常调试。好,明白了 就开始写代码
6.开始写Cef3的初始化代码
(1).在程序入口InitInstance的最头部加上这段代码
-
#pragma region 使用CEF3控件_仅支持32位编译环境
-
-
#include "CEF3/simple_app.h"
-
-
#include <include/cef_browser.h>
-
#include <include/cef_command_line.h>
-
#include <include/views/cef_browser_view.h>
-
#include <include/views/cef_window.h>
-
#include <include/wrapper/cef_helpers.h>
-
-
#include "simple_handler.h"
-
-
-
#pragma comment(lib,"CEF3/lib/x86/Debug/libcef.lib")
-
#pragma comment(lib,"CEF3/lib/x86/Debug/libcef_dll_wrapper.lib")
-
-
-
#pragma comment(lib,"CEF3/lib/x86/Release/libcef.lib")
-
#pragma comment(lib,"CEF3/lib/x86/Release/libcef_dll_wrapper.lib")
-
-
-
-
-
-
CefEnableHighDPISupport();
-
void* sandbox_info =
NULL;
-
CefMainArgs main_args(AfxGetApp()->m_hInstance);
-
-
-
-
settings.no_sandbox =
true;
-
settings.multi_threaded_message_loop =
true;
-
-
-
-
settings.log_severity = LOGSEVERITY_DISABLE;
//禁用debug.log日志
-
-
-
CefRefPtr<SimpleApp> app(new SimpleApp);
-
CefInitialize(main_args, settings, app.get(), sandbox_info);
-
-
#ifndef _DEBUG //只有Release模式才启用多进程模式
-
// 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,
NULL, sandbox_info);
-
-
//The sub - process has completed so return here.
-
-
-
-
-
(2).在程序入口InitInstance的最底部加上这段代码
-
-
7.开始写创建Cef3窗口控件的代码
(1).在OnInitDialog加上这段代码
-
-
-
GetClientRect(&rt);
//获取自己窗口的大小
-
-
CefWindowInfo window_info;
-
window_info.SetAsChild(GetSafeHwnd(), rt);
// cefsimple中的是用SetAsPopup,这里嵌入控件要用SetAsChild
-
m_CefHandler =
new SimpleHandler(
false);
-
std::
string url =
"http://www.baidu.com";
-
//std::wstring wurl = s2ws(url); //如果网址要有中文则需要用宽字节
-
CefBrowserSettings browser_settings;
-
CefBrowserHost::CreateBrowser(window_info, m_CefHandler, CefString(url), browser_settings,
-
(2).在窗口的Dlg私有成员变量增加这句代码
CefRefPtr<SimpleHandler> m_CefHandler;
8.增加 多进程Release与单进程Debug之间的切换代码
需要在simple_app.cc、simple_app.h中添加
-
-
void SimpleApp::OnBeforeCommandLineProcessing(const CefString& process_type,
-
CefRefPtr<CefCommandLine> command_line)
-
-
-
#ifdef _DEBUG //只在Debug模式使用单进程
-
command_line->AppendSwitch(
"single-process");
-
-
-
-
-
void SimpleApp::OnContextInitialized()
-
-
-
-
-
// CefBrowserProcessHandler methods:
-
virtual void OnBeforeCommandLineProcessing(
-
const CefString& process_type,
-
CefRefPtr<CefCommandLine> command_line) OVERRIDE;
-
-
-
// CefBrowserProcessHandler methods:
-
virtual void OnContextInitialized() OVERRIDE;
成功运行!
三、难点及疑问解答
Q:为什么cefsimple Win32可以运行,直接复制到MFC中却运行不起来?
A:如果需要在MFC环境中运行,还需要在CEF3初始化的参数加上
CefSettings.multi_threaded_message_loop = true;
否则是运行不起来的!
原因在于Win32中的示例是调用CefRunMessageLoop()来处理CEF3的消息,
而MFC中已经有一个消息循环了,所以告诉CEF3让它自己处理消息循环。
CEF能整合现有的应用程序的消息循环替代自己的消息循环
有两种做法
1.定期调用CefDoMessageLoopWork() 替代调用CefRunMessageLoop()
每次调用CefDoMessageLoopWork() 将会执行一次CEF消息循环的迭代,小心使用这种方法。调用这个方法频率太少,将会饿死CEF消息循环并且消极的影响浏览器的性能。调用这种方法太频繁将会消极的影响CPU的使用
2.设置
CefSettings.multi_threaded_message_loop = true(仅限windows下使用),
这将导致CEF运行在浏览器UI线程,该UI线程是从主应用程序分离出来的线程。这种方法既不需要调用CefDoMessageLoopWork() 也不需要调用 CefRunMessageLoop() 。
CefInitialize() 和CefShutdown()这两个函数仍然需要在主应用程序调用。你需要提供你自己的机制和主应用程序线程交流。在cefclient_win.cpp查看消息的使用示例.你可以在windows下使用命令行 “–multi-threaded-message-loop”测试cefclient模式。
Q:为什么调用CefShutdown会崩溃?
A:多进程模式下调用CefShutdown就是OK的,app也能够正常析构,而单进程模式调用CefShutdown会直接崩溃!
Q:为什么SimpleHandler这个类没有办法获取CefBrowser句柄?
A:自己增加两个函数就很方便啦
-
-
-
// 返回第一个浏览器控件CefBrowser指针(自定义函数)
-
CefRefPtr<CefBrowser> GetCefBrowser(int nIndex);
-
-
int GetCefBrowserCount();
-
-
// 返回第一个浏览器控件CefBrowser指针(自定义函数)
-
CefRefPtr<CefBrowser> SimpleHandler::GetCefBrowser(int nIndex)
-
-
if (browser_list_.empty())
-
-
-
-
BrowserList::iterator bit = browser_list_.begin();
-
for (
int i =
0; i < nIndex ; i++)
-
-
-
-
-
-
-
-
int SimpleHandler::GetCefBrowserCount()
-
-
-
BrowserList::iterator bit = browser_list_.begin();
-
for (; bit != browser_list_.end(); ++bit)
-
-
-
-
-