MFC对话框应用程序中谷歌CEF浏览器内核的使用

最近在做一个与浏览器相关的MFC项目,用户要求使用IE和谷歌双内核。对于IE内核可以直接使用MFC中的ACTIVEX控件,但是对于谷歌浏览器内核却并没有这么现成的控件可以使用。原来是想要自己编译WebKit做相关dll的,但是查阅相关资料后发现编译WebKit不是一个短期内能够完成的任务。后来无意间在网上找到了CEF。它是对WebKit的一个封装。想要了解详细信息可以直接在百度里面搜索相关资料。

网上关于CEF在MFC中的使用看起来很多,其实它们几乎都是一个版本。而且如果直接按照他们的做法去做会出现这样或那样的错误。在这众多版本的参考资料中:http://blog.csdn.net/yhangleo/article/details/8482603是最大众化的一个,几乎一半以上的版本都和这个一样,也不知道谁引用谁的,不过拜托在发表之前先自己测试通过。http://blog.csdn.net/xuezhe521/article/details/9067035有点想法,但是只是从表面上解决了一些问题,按照他的做法做会为后面的使用埋下隐患。现在隆重推荐最好的一篇http://it.nittis.ru/mfc-cef.html虽然上面全是外文,只有代码可以看懂,但是却是这几篇中最好的。

言归正传,开始编写。

1、下载CEF源代码。这里是第一个注意点。CEF分为cef1、cef2和cef3三个版本,其中cef1为单线程版本,cef2已经放弃开发,cef3为多线程版本。本教程适用于cef1,至于cef3没有测试过,不知道能不能使。

cef官方网站  cef下载地址(记得下载的cef1不是3!!!)

2、CEF编译。下载好CEF后,解压。解压后的图片如下

用VS打开.sln文件。界面如下

设置libcef_dll_wrapper为启动项分别生成debug和release两个版本的libcef_dll_wrapper.lib。在生成后VS会提示无法运行libcef_dll_wrapper.lib,不用理它,因为本来生成的就是lib文件怎么可能运行。运行生成后在生成目录下找到生成的debug和release版本的libcef_dll_wrapper.lib.注意生成路径为目录bulid,截图如下:(Debug版本同理)

此时,cef相关文件的生成工作已经完成。需要从程序中找出来以备后用的文件如下:

…\cef_binary_1.1364.1123_windows\include文件夹

…\cef_binary_1.1364.1123_windows\lib\Debug\ libcef_dll-wrapper.lib

…\cef_binary_1.1364.1123_windows\lib\Release\ libcef_dll-wrapper.lib(与上面同名用不同的文件夹分开放)

…\cef_binary_1.1364.1123_windows\Debug文件夹(要用的是除cefclient以外的所有文件)

...\cef_binary_1.1364.1123_windows\cef_binary_1.1364.1123_windows\lib\Release\libcef.lib

最终准备文件截图如下:

至此准备工作完成。

3、在MFC对话框项目中使用CEF

(1)、建立一个MFC对话框项目

(2)、环境配置

将准备的libcef.lib、libcef_dll_wrapper.lib(在debug时工程目录下放的是debug版本的,当release时替换为release的)、include文件夹一同复制到工程目录下。

①          接下来设置工程属性。这里需要强调一下,工程属性的设置必须在“所有配置”模式下进行,以保证debug和release的情况完全一致。这一点必须注意,其截图如下:

②    在项目上vc++目录->包含目录->编辑双击后输入:$(ProjectDir)\include

③同样项目右键->属性->配置属性->链接器->输入->附加依赖项->编辑

输入:libcef.lib换行再输入libcef_dll_wrapper.lib

(细心的朋友会发现,如果在这里分开设置release和debug的包含lib就不用来回替换libcef_dll_wrapper.lib了。这个想法是正确的,我只是为了描述方便,实际采用分开设置对调试来说更方便)

④      配置属性->预编译头->预编译头->不适用预编译头。截图如下

⑤  配置属性->c/c++->代码生成->运行库->多线程调试(/MTd)(realse下选择多线程MT)。截图如下:

⑥  配置属性->常规->MFC的使用->在静态库中使用MFC.截图如下:

(3)、添加cwebclient类

在菜单栏选择:项目->类向导->添加类->输入类名->完成。截图如下:

此处注意系统会自动把.h和cpp文件名的c去掉,建议加上防止混乱。

把CWebClient.h的内容改为如下(直接覆盖原来内容):注意此处与大多数的教程不同,大多数教程往往让把下列代码加入cpp中,这种做法是错误的。

[cpp] view plaincopy
  1. #pragma once
  2. #include <cef_client.h>
  3. class CWebClient
  4. <span style="white-space:pre">    </span>: public CefClient
  5. <span style="white-space:pre">    </span>, public CefLifeSpanHandler
  6. {
  7. protected:
  8. <span style="white-space:pre">    </span>CefRefPtr<CefBrowser> m_Browser;
  9. public:
  10. <span style="white-space:pre">    </span>CWebClient(void){};
  11. <span style="white-space:pre">    </span>virtual ~CWebClient(void){};
  12. <span style="white-space:pre">    </span>CefRefPtr<CefBrowser> GetBrowser() { return m_Browser; }
  13. <span style="white-space:pre">    </span>virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() OVERRIDE
  14. <span style="white-space:pre">    </span>{ return this; }
  15. <span style="white-space:pre">    </span>virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;
  16. <span style="white-space:pre">    </span>// 添加CEF的SP虚函数
  17. <span style="white-space:pre">    </span>IMPLEMENT_REFCOUNTING(CWebClient);
  18. <span style="white-space:pre">    </span>IMPLEMENT_LOCKING(CWebClient);
  19. };

在cpp中加入如下代码(覆盖),这段代码只有那篇外文的文章中才有,但是这是一个很关键的代码,就是因为没有这句代码所以我见到的所有中文文章都是不完全正确的。

[cpp] view plaincopy
  1. #include "stdafx.h"
  2. #include "CWebClient.h"
  3. void CWebClient::OnAfterCreated(CefRefPtr<CefBrowser> browser)
  4. {
  5. m_Browser = browser;
  6. }

有一篇文章通过将.h中的virtualvoid OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;改为irtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) {};通过这种方法来消除这句代码的错误,这种做法其实是错误的,它只是将本来要重写的虚函数仍保持为虚函数,这样在后面调用这个函数的时候就出错了。

而这段代码给出的就是这个虚函数的实体,从而从根源上解决了上面这个虚函数重写的问题。

(4)

在主窗体的.h文件中加入

#include <cef_client.h>

#include "CWebClient.h"

#include <cef_app.h>

在类的public成员中添加

CefRefPtr<CWebClient>  m_cWebClient;

(5)通过类向导为主窗体添加onsize()事件,如下图:

在onsize()函数体中写入如下代码

[cpp] view plaincopy
  1. void CMfcBrowserDlg::OnSize(UINT nType, int cx,int cy)
  2. {
  3. CDialogEx::OnSize(nType,cx,cy);
  4. //TODO: 在此处添加消息处理程序代码
  5. if(m_cWebClient.get())
  6. {
  7. CefRefPtr<CefBrowser>browser = m_cWebClient->GetBrowser();
  8. if(browser)
  9. {
  10. CefWindowHandle hwnd = browser->GetWindowHandle();
  11. ::MoveWindow(hwnd,100,100,800,800, true);
  12. }
  13. }
  14. }

其中movewindow中参数可自行更改,也可设置为动态更改(可以查阅movewindow相关资料)。

(6)给出创建浏览器的代码

[cpp] view plaincopy
  1. CefRefPtr<CWebClient>client(new CWebClient());
  2. m_cWebClient= client;
  3. CefSettings cSettings;
  4. CefSettingsTraits::init(&cSettings);
  5. cSettings.multi_threaded_message_loop= true;
  6. CefRefPtr<CefApp>spApp;
  7. CefInitialize(cSettings, spApp);
  8. CefWindowInfo info;
  9. RECT rect;
  10. GetClientRect(&rect);
  11. RECT rectnew=rect;
  12. rectnew.top=rect.top+70;
  13. rectnew.bottom=rect.bottom;
  14. rectnew.left=rect.left;
  15. rectnew.right=rect.right;
  16. info.SetAsChild(GetSafeHwnd(),rectnew);
  17. CefBrowserSettings browserSettings;
  18. CefBrowser::CreateBrowser(info, static_cast<CefRefPtr<CefClient> >(client),
  19. <span style="white-space:pre">        </span>"http://www.baidu.com",browserSettings);
[cpp] view plaincopy
  1. </pre><p></p><p>所有查到的资料中都将浏览器的创建过程写在主窗体的oncreate()中。这样本身并没有什么不妥,可以在窗体被创建的初始就创建出浏览器。但是我想说的是,浏览器的创建可以在任何时候。只要在你需要的时候使用如下代码段即可。</p><p>至于oncreate事件的添加与onsize()相同。</p><p>(7)浏览器被创建出来后,可以使用类成员m_cwebclient实现对浏览器的控制。这里要要说一下。如果你前面说的第一种文章的描述进行操作,你在调试的时候会在virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser)OVERRIDE;报错。如果你按照第二种文章的说法,将virtual voidOnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;中的OVERRIDE改为{},那么好吧问题暂时得到解决,你也可以在窗体中创建出来浏览器控件,一切看似很和谐。但是当你想在软件运行过程中导航网址时,即采用m_cWebClient->GetBrowser()->GetMainFrame()->LoadURL(url);将会报错,报错的原因是virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser){};为虚函数没有函数实体。因此,最正确的方式就是文章3中提到的在cpp中加入该函数的实体。</p><p>下面给出一些浏览器被创建后再程序中可以使用的一些操作:</p><p>导航网址(网址从文本框获得)</p><p></p><pre name="code" class="cpp">CString str;
  2. GetDlgItem(IDC_EDIT1)->GetWindowText(str);
  3. const CefString url(str);
  4. m_cWebClient->GetBrowser()->GetMainFrame()->LoadURL(url);

浏览器隐藏与显示

[cpp] view plaincopy
  1. ::ShowWindow(m_cWebClient->GetBrowser()->GetWindowHandle(),SW_HIDE);
  2. ::ShowWindow(m_cWebClient->GetBrowser()->GetWindowHandle(),SW_SHOW);

至于刷新、上一步、下一步等操作大同小异就不赘述了。

(8)代码的编写已经完成。如果你已正确地在debug模式下在工程下放入debug版的libcef_dll_wrapper.lib或在release模式下载工程下放入realse版的libcef_dll_wrapper.lib,那么运行时会报错缺少libcef.dll.此时恭喜你,你已经距离成功只差一步之遥了。如果你是在debug模式下,那么将你准备好的debug文件夹下的处理cefclient.exe的其它文件全部拷贝到工程debug文件夹下。如果你在release模式下,同样将debug文件夹下的这些文件拷贝到release文件夹下。此时运行,你会兴奋地发现,运行成功!截图如下:

Release文件夹

本来应该加载谷歌的但是谷歌最近被封了,一致登不上只好加载百度了

MFC对话框应用程序中谷歌CEF浏览器内核的使用相关推荐

  1. 在Delphi程序中应用IE浏览器控件

    ---- 大概大家还记得Delphi的范例程序中的那个浏览器的例子吧.在那个例子中,利用控件THttp的属性和方法制作了一个浏览器.该例子用于理解THttp控件的使用方法,确实不错.但很少有人会用它作 ...

  2. MFC应用程序中嵌入一个谷歌cef浏览器

    声明:文章来自http://www.codeproject.com/Articles/1105945/Embedding-a-Chromium-browser-in-an-MFC-applicatio ...

  3. 在MFC,Win32程序中向控制台(Console)窗口输出调试信息

    在MFC程序中输出调试信息的方法有两种,一种是使用TRACE宏,可以向Output窗口输出调试信息:另一种是用MessageBox,弹出消息框来输出调试信息,但会影响程序的运行. 其实有一种方法可以更 ...

  4. mfc 对话框应用程序 如何利用按钮弹出另一对话框

    首先要新增加一个类,父类选CDialog,类名:CDCM2DLG 然后定义:CDCM2DLG  *CDcm2dlg; 初始化: CDcm2dlg = NULL; 调用: CDcm2dlg = new ...

  5. cefsharp设置cookie_使用CefSharp在.Net程序中嵌入Chrome浏览器(八)——Cookie

    CEF中的Cookie是通过CookieManager来管理的,可以用它来设置发送的Cookie. 发送Cookie 发送Cookie的一个基本示例如下: var cookieManager = _c ...

  6. CEF:MFC 对话框 Demo(VS2013)

    原文链接:https://blog.csdn.net/blackwoodcliff/article/details/74276848 随着 HTML5 的崛起和 IE 的淘汰,微软 Web Brows ...

  7. mfc 内嵌 本地html,MFC程序中内嵌网页,附示例工程

    最近在课程设计,因为小悠太懒了,是在不想用C++完成一些简单的文件上传下载操作,于是就想着将网页内嵌到程序中,上传下载神马的就直接使用网页Web来完成就好了,本示例中将演示在MFC程序中内嵌一个htm ...

  8. soildworks模型导入MFC对话框

    最近项目需要把solidworks创建的设备模型导入MFC对话框中显示,并且能鼠标控制移动.缩放. 软件平台包括 solidworks 2008 .3DS-Max 7.0 . vs 2008 sp1; ...

  9. 改变MFC对话框背景色、控件内的字体颜色和背景色

    原文转自http://www.rosoo.net/a/201408/17018.html C 设置 Dialog, Group Box, Static Text, Check Box, Edit Ct ...

最新文章

  1. [翻译] - Inside SQL Server 2000's Memory Management Facilities
  2. 苹果cms的php.ini,苹果cms安装及配置详细教程
  3. 灰鸽子木马的原理和清除方法
  4. Mysql中用SQL增加、删除字段,修改字段名、字段类型、注释,调整字段顺序总结...
  5. Oracle免客户端InstantClient安装使用
  6. 二维均匀分布的边缘密度函数_理解概率密度函数
  7. 【java面试题】equals()方法和==的比较区别?
  8. java基础-软件简述
  9. Codeforces Round #294 (Div. 2) -- A. A and B and Chess
  10. 四十多岁的男人还适合重新创业吗?
  11. C# Excel数据验重及Table数据验重
  12. 年化费率和年利率的区别
  13. C语言编程宏定义的优缺点,C语言重要知识点总结(二)--内存结构、函数调用过程(栈帧)、宏的优缺点以及##和#的使用...
  14. 刘强东给村民送500万年货;支付宝或上线黄金红包;Space X成功发射重型火箭丨价值早报
  15. matlab如何打开dcm_MATLAB结合Unreal Engine构建用以自动驾驶仿真测试的逼真驾驶场景...
  16. 抖音 -抖店开放平台 SDK 实现及项目工程
  17. 学习用的Django教程
  18. 2017 八大黑客攻击事件,这一年网络安全的世界血雨腥风
  19. Avue-crud使用各参数说明
  20. python高级 笔记 08 (TCP服务器增强 + 文件下载器 案例 综合应用)

热门文章

  1. Win10下如何在右键新建菜单使用Typora新建.md文件
  2. python网络爬虫学习_python网络爬虫学习笔记
  3. mysql数据库爆破_mysql数据库密码爆破
  4. wzoi 1~200
  5. 计算机不能进入桌面,win7系统电脑开机后无法进入桌面的解决方法
  6. 携程无线发布稳定高效的秘诀
  7. E+H浊度传感器CUS52D-AA1BA3
  8. pdf裁边app_PDF切边裁剪(paper for kindle)
  9. 视频号运营攻略大全,视频号从0到1运营变现教程丨国仁网络资讯
  10. CMemoryDC(是吕鑫写的版本)