前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >把cef3集成到MFC中的一些坑

把cef3集成到MFC中的一些坑

作者头像
xiny120
发布2019-06-11 11:17:17
6.4K0
发布2019-06-11 11:17:17
举报
文章被收录于专栏:毛毛v5毛毛v5

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.03.13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档