简介本文向大家介绍一个C++实战项目:基于Duilib的CEF3中C++与JS函数互相调用示例,主要涉及开发技术点为DuiLib界面开发、谷歌浏览器CEF插件开发、C++与JavaScript的相互调用,具有一定的C++实战价值,感兴趣的朋友可以参考一下。
CEF是一个基于Google Chromium的简单的框架。 它主要是作为一个内嵌浏览器嵌入到客户端应用程序中。
本文示例源码工程中已集成编译好的CEF源码,有需要的可在文末下载。
先来张效果图:
首先在工程项目的入口函数中初始化CEF,其中CDuiCefApp类为继承 CefApp的类,详见源码。
void* sandbox_info = NULL;
CefMainArgs main_args(AfxGetInstanceHandle());
CefRefPtr<CDuiCefApp>app(new CDuiCefApp);
CefSettings settings;
settings.no_sandbox = true;
settings.background_color = CefColorSetARGB(255,255, 255, 255);
settings.multi_threaded_message_loop = true; // 使用主消息循环
CefInitialize(main_args, settings, app.get(), sandbox_info);
然后我们创建一个类为CMainWnd的Duilib窗口,然后在初始化窗口中加载CEF,其中CDuiMsgHandler类为继承CCefClient的类,详见源码。
if (msg.sType == _T("windowinit"))
{
CefWindowInfo windows_info;
RECT rc;
::GetClientRect(GetHWND(), &rc);
rc.top = rc.top + 108;
windows_info.SetAsChild(GetHWND(), rc);
m_handler = new CDuiMsgHandler();
CefBrowserSettings browser_settings;
browser_settings.default_encoding.str = _T("GB2312");
browser_settings.default_encoding.length = wcslen(_T("GB2312"));
//std::string url = "https://www.baidu.com/";
CString strHtmlPath = CCommon::GetModuleFilePath() + _T("");
strHtmlPath.Format(_T("%shtml\\test.html"), CCommon::GetModuleFilePath());
strHtmlPath.Replace(_T("\\"),_T("/"));
std::string url = (LPCSTR)(CStringA)(strHtmlPath);
CefBrowserHost::CreateBrowser(windows_info, m_handler, "file:///" + url, browser_settings, NULL,NULL);
}
test.html文件为自写的测试文件,内容如下:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8" />
<title>基于Duilib的CEF3中C++与JS函数互相调用示例</title>
</head>
<body style="margin-left: 30px;">
<p style="font-weight: bold;">Js调用C++函数</p>
<div>
<p><button onclick="OnJsCallCppTest1();">Js调用C++函数(参数为空)</button></p>
<p><button onclick="OnJsCallCppTest2();">Js调用C++函数(参数带整型)</button></p>
<p><button onclick="OnJsCallCppTest3();">Js调用C++函数(参数带字符串)</button></p>
</div>
</body>
<script type="text/javascript">
// C++调用JS
function CallJavaScript(value) {
alert('C++调用JS: ' + value)
}
// Js调用C++
function OnJsCallCppTest1() {
window.g_JsCallCppTest1();
}
function OnJsCallCppTest2() {
window.g_JsCallCppTest2(10, 20);
}
function OnJsCallCppTest3() {
window.g_JsCallCppTest3('C++实战网(www.cppszw.com)');
}
</script>
</html>
C++调用Js函数, 使用CefBrowser的GetMainFrame()获取browser的mainframe,再调用他的ExecuteJavaScript方法来调用页面的js函数, 此种方法比较简单:
// JS函数调用
m_handler->GetBrowser()->GetMainFrame()->ExecuteJavaScript(_T("CallJavaScript('C++实战网(www.cppszw.com)')"), m_handler->GetBrowser()->GetMainFrame()->GetURL(), 0);
想要C++和Js交互,我们只需要实现以下接口:
#pragma once
#include "../stdafx.h"
#include "include/cef_app.h"
class CDuiCefApp :
public CefApp,
public CefBrowserProcessHandler,
public CefRenderProcessHandler,
public CefV8Handler
{
public:
CDuiCefApp();
virtual ~CDuiCefApp(void) override;
// CefApp methods
virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() override;
// 通过返回值获取render线程,必须重写
virtual CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() override;
// 上下文对象创建后,进入这个函数
virtual void OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) override;
virtual void OnContextInitialized() override;
/**
* 执行JS函数
*
* @param funcName 函数名称
* @param object 调用对象
* @param retval 返回值
* @param exception 异常信息
*
**/
virtual bool Execute(const CefString& funcName,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception) override;
// 发送消息到主窗口
bool SendMsgToMainWnd(CefString strMsg);
private:
HWND m_hWndMain;
// Include the default reference counting implementation
IMPLEMENT_REFCOUNTING(CDuiCefApp);
};
然后我们在CDuiCefApp::OnContextCreated()函数中绑定自定义的Js中对应的C++函数即可:
void CDuiCefApp::OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context)
{
// The var type can accept all object or variable
CefRefPtr<CefV8Value> window = context->GetGlobal();
m_hWndMain = ::FindWindow(NULL, TEXT("DuilibCefDemo"));
// 绑定函数
CefRefPtr<CefV8Handler> pJsHandler = this;
CefRefPtr<CefV8Value> JsCallCppTest1 = CefV8Value::CreateFunction("JsCallCppTest1", pJsHandler);
CefRefPtr<CefV8Value> JsCallCppTest2 = CefV8Value::CreateFunction("JsCallCppTest2", pJsHandler);
CefRefPtr<CefV8Value> JsCallCppTest3 = CefV8Value::CreateFunction("JsCallCppTest3", pJsHandler);
// 特别注意:C++函数名不能与Js函数名挂接相同
window->SetValue("g_JsCallCppTest1", JsCallCppTest1, V8_PROPERTY_ATTRIBUTE_NONE);
window->SetValue("g_JsCallCppTest2", JsCallCppTest2, V8_PROPERTY_ATTRIBUTE_NONE);
window->SetValue("g_JsCallCppTest3", JsCallCppTest3, V8_PROPERTY_ATTRIBUTE_NONE);
}
这里需要特别注意的是:C++函数名不能与Js函数名挂接相同,如示例中C++函数名为JsCallCppTest1,则Js函数绑定的时候设为g_JsCallCppTest1,否则Js调用将会不成功。
最后,我们在CDuiCefApp::Execute()函数中编写对应函数的响应代码即可:
// 执行JS函数
bool CDuiCefApp::Execute(const CefString& funcName,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception)
{
// Js调用C++函数
if (funcName == "JsCallCppTest1")
{
SendMsgToMainWnd(L"Js调用C++函数:JsCallCppTest1(参数为空)");
return true;
}
else if (funcName == "JsCallCppTest2")
{
if (arguments.size() == 2)
{
CString sTemp = _T("");
sTemp.Format(_T("Js调用C++函数:JsCallCppTest2(%d,%d)"), arguments[0]->GetIntValue(), arguments[1]->GetIntValue());
SendMsgToMainWnd(sTemp.GetBuffer());
return true;
}
}
else if (funcName == "JsCallCppTest3")
{
if (arguments.size() == 1)
{
SendMsgToMainWnd(arguments[0]->GetStringValue());
return true;
}
}
return false;
}
点击Js调用C++函数(参数带字符串)中,可看到效果如下:
OpenMP是一种用于共享内存并行系统的多线程程序设计方案,本文向大家介绍C++并行计算之OpenMP快速入门,感兴趣的朋友可以参考一下。
一般好的软件程序是不应该占用太多CPU时间和内存空间的,一般在自己的学习过程中,我们常常忽略这一点,虽然功能实现没有问题,但是程序占用太多CPU时间,这在实际开发中是不允许的,一个好的程序员也应该注意这个问题。本文就CPU使用率问题做一些简单介绍,为开发稳定健壮的程序提供参考。
本文向大家介绍一个C++实战项目:C++实现MD5、DES加密,主要涉及MD5加密、DES加解密算法,具有一定的C++实战价值,感兴趣的朋友可以参考一下。
本文向大家介绍一个C++实战项目:C++11实现多线程下载操作类,很多时候我们需要同时在网络上下载文件,那么就需要一个类来管理多线程下载,提高下载速度,具有一定的C++实战价值,感兴趣的朋友可以参考一下。
本文向大家介绍一个C++实战项目:C++制作一个简单的程序依赖DLL打包工具,有时候我们需要对某个程序进行打包,却不知道该程序依赖哪些动态库,这个工具可实现程序的一键打包功能,具有一定的C++实战价值,感兴趣的朋友可以参考一下。
本文向大家介绍一个C++实战项目:C++程序崩溃生成Dump文件。在程序运行时候崩溃是头疼的时,本实战项目可在程序运行崩溃时在程序目录下生成Dump文件,具有一定的C++实战价值,感兴趣的朋友可以参考一下。