Cef功能开发经验总结_第1页
Cef功能开发经验总结_第2页
Cef功能开发经验总结_第3页
Cef功能开发经验总结_第4页
Cef功能开发经验总结_第5页
已阅读5页,还剩20页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

本文格式为Word版,下载可任意编辑——Cef功能开发经验总结Cef功能开发经验总结

Cef功能开发经验总结2023-04-1412:542072人阅读评论(0)珍藏

举报分类:Windows(110)C/C++(105)

javascript/vbs/lua/python(39)http/ftp/IE/Chrome/Firefox(43)网络(66)WTL/MFC(3)目录(?)[+]

转载请说明原出处,感谢~~:

/zhuhongshu/article/details/70159672

这是我开发Cef功能时对踩过的坑,进行的总结,话说Cef坑真的不少。好在踩完后用起来还是挺爽的。最终的代码可以下载网易云信PCDemo点我跳转

资料准备

这是我集成过程中查到的一些资料,包括了Cef开发的各方面资料

在调试Cef时需要Cef的pdb和源码:

Cef及pdb文件下载地址,其中的CefClient包含了Cef绝大多数功能的例如:/Cef及对应Chromiun源码下载地址:

/cefbuilds/index.htmlCef与JS交互:

/foruok/article/details/50573612Cef与JS交互二:

http://./guolixiucai/p/4943748.htmlCef官方文档中文翻译版,包含了Cef导读(这个导读是很重要的资料)和一些经验文档,很有用:/fanfeilong/cefutil

Cef基本结构

CefApp接口

CefApp接口提供了不同进程的可定制回调函数,每一个进程对应一个CefApp接口。CefBrowserProcessHandler对应浏览器进程的回调,CefRenderProcessHandler对应渲染进程的回调。我们应当继承CefApp、

CefBrowserProcessHandler、CefRenderProcessHandler

接口。假使完全使用多进程模式,可以分别在浏览器进程和渲染进程里分开继承接口

CefApp::OnBeforeCommandLineProcessing方法里可以附加传入给Cef的命令行参数,这里可以附加好多控制参数

CefRenderProcessHandler::OnWebKitInitialized方法可以在渲染进程初始化时用来注册js扩展代码,实现C++与JS交互

CefRenderProcessHandler::OnFocusedNodeChanged方法可以检测当前获取到焦点html元素,获取到一些元素信息可以通过进程通信发送给浏览器进程来辅助做进一步的判断

CefRenderProcessHandler::OnProcessMessageReceived方法用于接收浏览器进程发来的消息,在做C++与JS交互时会用到

CefClient接口

每一个CefBrowser对象会对应一个CefClient接口,用于处

理浏览器页面的各种回调信息,包括了Browser的生命周期,右键菜单,对话框,状态通知显示,下载事件,拖曳事件,焦点事件,键盘事件,离屏渲染事件。随着Cef版本的更新这些接口也会扩展和更新,多数对Cef进行行为控制的方法都集中在这些接口,假使对Cef有新的功能需求,一般都可以先翻翻这些接口中有没有提供相关功能

CefClient::OnProcessMessageReceived方法用于接收渲染进程发到的消息,在做C++与JS交互时会用到

CefSettings结构体

CefSettings结构体定义了Cef的全局配置信息,譬如指定单进程模式、指定渲染子进程路径、设置localstorage路径、设置日志等级、Cef资源文件路径。其中对于项目最重要的字段是single_process、multi_threaded_message_loop、windowless_rendering_enabled,分别用于指定单进程模式、多线程渲染模式、离屏渲染模式。

兼容现有的消息循环

假使是UI线程消息循环构架较简单的项目,可以直接调用

CefRunMessageLoop来使用Cef自带的消息循环,它会阻塞线程直到调用了CefQuitMessageLoop函数,

CefRunMessageLoop是兼容传统的Win32消息循环的。

不过NIM项目底层是使用谷歌base库的多线程构架,所以没法直接使用CefRunMessageLoop。(PS:实际上Cef的底层消息循环也是谷歌的base库)

要让NIM的消息循环兼容Cef消息循环,有两种方法。

第一种方法

第一种方法是使用CefDoMessageLoopWork函数代替CefRunMessageLoop来完全消息消息循环。

CefDoMessageLoopWork函数的作用是让Cef执行一次消息循环,这个函数不会阻塞线程,所以需要在我们现有的消息循环里的适当状况下主动去调用

CefDoMessageLoopWork函数,假使调用的太频繁会很消耗CPU,假使调用频率太低会导致Cef来不及处理内部消息,让Cef界面反映变慢,所以这个函数的调用时机很重要。

由于CefDoMessageLoopWork函数应当在原本的消息循环

中调用,而base库的UI线程消息循环是封装好的。这里首先说一下定制base库消息循环的方法。在WinMain入口函数里调用UI消息循环的代码如下:{

MainThreadthread;//创立主线程

thread.RunOnCurrentThreadWithLoop(nbase::MessageLoop::kUIMessageLoop);//执行主线程循环}

在RunOnCurrentThreadWithLoop方法的其次个参数里可以指定一个消息分派器指针dispatcher,dispatcher继承自nbase::Dispatcher。base库中的UI消息循环代码如下:PreProcessMessage(msg);

if(state_-dispatcher){

if(!state_-dispatcher-Dispatch(msg))state_-should_quit=true;}else

{

TranslateMessage(msg);DispatchMessage(msg);}

PostProcessMessage(msg);

假使我们指定了RunOnCurrentThreadWithLoop方法的其次个参数,就不会调用原本的消息循环了,所以可以在这个dispatcher里定制消息循环。我实现

CefMessageLoopDispatcher类并重写Dispatch接口。BOOLCefMessageLoopDispatcher::IsIdleMessage(constMSG*pMsg){

switch(pMsg-message){

caseWM_MOUSEMOVE:caseWM_NCMOUSEMOVE:caseWM_PAINT:returnFALSE;}

returnTRUE;}

boolCefMessageLoopDispatcher::Dispatch(constMSGmsg){

staticBOOLbDoIdle=TRUE;

TranslateMessage(msg);DispatchMessage(msg);

if(IsIdleMessage(msg)){

bDoIdle=TRUE;}

while(bDoIdle

!::PeekMessage(const_castMSG*(msg),NULL,0,0,PM_NOREMOVE)){

CefDoMessageLoopWork();

bDoIdle=FALSE;}

returntrue;}

在定制消息循环里,假使判断当前消息队列为空并且方才处理的消息不会指定的几个消息,就去调用CefDoMessageLoopWork函数。WM_PAINT、

WM_MOUSEMOVE等消息的处理比较繁杂,所以不在这里调用CefDoMessageLoopWork函数

这个方法基本可以使用,但是还存在一些问题,这里CefDoMessageLoopWork函数的调用机制还不够好,Cef界面不够顺畅,而且由于Cef与项目base库的冲突,导致在程序终止时有些问题。这个方法有待优化

其次种方法

CefSettings结构体的multi_threaded_message_loop(多线程消息循环)为false时,可以调用CefRunMessageLoop或

者CefDoMessageLoopWork函数来触发Cef消息循环,这时浏览器进程的UI线程就是调用CefRunMessageLoop或者CefDoMessageLoopWork函数的线程。假使CefSettings结构体的multi_threaded_message_loop为true时。浏览器进程的UI线程是另外的线程。设置

multi_threaded_message_loop为true则使用多线程消息循环。

通过对比CefDemo的多线程消息循环代码,可以确定在NIM项目中直接开启多线程消息循环,不需要修改现有消息循环代码就可以正常使用Cef了。不过需要注意的是,使用多线程消息循环后某些函数就无法使用了,譬如

CreateBrowserSync,这种函数要求必需在Cef的UI线程调用。

另外,在好多版本的Cef里,假使开启了多线程消息循环,会导致程序在终止时触发中断,这属于Cef的bug,不过在release版本的Cef中没有问题。应当在项目中使用这个方法。不过使用了多线程消息循环后,好多Cef对象触发的回调函数,都是在Cef的UI线程而不是我们的UI线程,所以这时操作我们的UI线程就比较麻烦,要注意一些多线程问题,尽量把操作转发到我们的UI线程,不转发的话必需确

定所操作的代码不会影响我们的UI线程,切记!

CefClient接口介绍

CefLifeSpanHandler

CefBrowser对象的生命周期事件的回调接口。

OnAfterCreated:当调用CreateBrowser函数创立浏览器对象后会立马触发这个回调,在这里可以保存浏览器对象的指针DoClose:当调用CloseBrowser函数后触发这个回调OnBeforeClose:当浏览器对象即将销毁时会触发这个回调,在这里一定要释放所有对CefBrowser对象的引用,否则会导致程序无法退出。切记这个坑。OnBeforePopup:当单击了网页中会弹出新窗口的链接时,会触发这个回调。我们的项目里应当阻止新窗口的弹出,而在原控件中跳转链接

CefRenderHandler

要使用离屏渲染功能,就必需要实现这个接口类。由于项目中使用的duilib库,目前使用分层窗体机制实现异形窗体效果,不支持显示子窗口只能自绘控件,所以没法使用比较简单的子窗口的形式显示Cef浏览器对象。只能使用离屏渲染

方法,离屏渲染的数据会通过CefRenderHandler接口回调。

首先必需要开启CefSettings结构体的windowless_rendering_enabled字段

GetRootScreenRect:浏览器对象创立后触发的回调,返回最外层窗体在屏幕中的位置GetViewRect:在浏览器对象初始化后,或者浏览器大小改变时,触发这个回调来获取浏览器对象的位置。由于浏览器对象会平铺满整个控件,所以这里返回控件的位置。其中返回的左上位置要确凿,否则Cef在处理一些坐标信息时会出错GetScreenPoint:在这里把传入的坐标值,由客户区坐标转换为屏幕坐标OnCursorChange:当需要修改鼠标光标时触发这个回调OnPaint:当浏览器对象有新的渲染数据后,会触发这个回调,包含了脏区和渲染数据。应当保存这些数据,然后在适当的时候贴到目标窗体上OnPopupShow:当浏览器中要弹出内部对话框时(譬如弹出一个下拉菜单),触发这个回调,通知要显示或者隐蔽弹出框OnPopupSize:当浏览器中要弹出内部对话框时,触发这个回调,通知弹出框的位置和大小

离屏渲染的实现

离屏渲染的效率不如真窗口渲染,假使不是必需要离屏渲染

的状况,还是用真窗口比较好。CefControl控件实现了duilib嵌入Cef浏览器对象。

在控件初始化触发Init函数时,调用CreateBrowser函数创立CefBrowser对象,这会触发

CefRenderHandler::GetViewRect回调,在这个回调里返回控件的位置。随后网页第一次渲染时触发CefRenderHandler::OnPaint回调。

绘制渲染数据的流程

当网页渲染数据改变、或者我们主动调用了CefBrowser对象的Invalidate方法时,会触发CefRenderHandler::OnPaint回调。我写了一个内存位图缓冲类MemoryDC来保存Cef传来的渲染数据,在CefControl控件中dc_cef_成员变量负责保存渲染数据。在CefRenderHandler::OnPaint回调里,根据渲染数据初始化dc_cef_,然后根据脏区把渲染数据拷贝到dc_cef_中。数据拷贝完之后,调用CefControl控件的Invalidate方法通知窗体重绘控件在CefControl控件的Paint方法里,把dc_cef_的位图数据拷贝到duilib传入的HDC中

CefControl对事件的处理

修改CefBrowser尺寸

在离屏渲染模式下,无法直接修改CefBrowser对象的尺寸。CefControl控件重写SetPos函数,在这里调用CefBrowser对象的WasResized接口通知CefBrowser对象需要改变尺寸,之后GetViewRect接口会被触发,这时仍旧是返回CefControl控件的位置就可以了。之后OnPaint接口会被自动触发,依照前一节的流程进行一次渲染数据的刷新

设置CefBrowser隐蔽(显示)

CefControl控件重写SetVisible函数和SetInternVisible函数,在这里调用CefBrowser对象的WasHidden接口通知CefBrowser对象隐蔽或显示

对系统消息的处理

在控件初始化触发Init函数时,调用窗体类的

AddMessageFilter函数把自己注册到窗体的消息过滤队列里。CefControl控件继承IUIMessageFilter接口类并重写MessageHandler函数。当系统消息进入窗体后会依次调用消息过滤队列指针来过滤消息。在MessageHandler函数里处理我们感兴趣的消息,其他消息并不过滤处理各种鼠标类消息时,判断假使鼠标不在控件范围内则不处理相关消息。获取当前鼠标的坐标,由于CefBrowser的坐标值是以自身

左上角作为原点的,所以获取的鼠标坐标要减去CefControl控件的左上角坐标值。其中处理ButtonDown、ButtonUp、MouseMove消息时,不会中断消息继续传递给窗体,这里需要让duilib窗体类处理SetCapture、ReleaseCapture等函数处理键盘消息时,判断当前控件是否获取焦点,只处理有焦点的状况WM_SETCURSOR消息处理,在

MessageHandler函数拦截WM_SETCURSOR消息,直接调用窗体类的默认消息处理函数,不让duilib处理这个消息。CefRenderHandler::OnCursorChange接口会修改鼠标光标并修改窗体的默认光标样式,而duilib处理

WM_SETCURSOR消息时会另外修改光标,所以需要拦截

渲染Popup弹出框

浏览器中,弹出框的渲染数据是需要自己额外处理的。如下拉菜单等弹出框,否则浏览器中不会显示出弹出框当需要显示弹出框时,CefRenderHandler::OnPopupSize接口会传入弹出框的位置和尺寸等数据,在这里把数据保存到rect_popup_成员变量之后会触发

CefRenderHandler::OnPaint回调,并且渲染类型会被指定为弹出框类型PET_POPUP。这时把弹出框的渲染数据保存到MemoryDC类型的dc_cef_popup_成员变量中数据拷贝完之后,调用CefControl控件的Invalidate方法通知窗体重

绘控件在CefControl控件的Paint方法里,把dc_cef_popup_的位图数据依照rect_popup_的信息拷贝到duilib传入的HDC中当弹出框消失时,触发

CefRenderHandler::OnPopupShow接口,这里重置rect_popup_的信息,并且通知CefBrowser刷新页面

多进程渲染

Cef3支持多进程和单进程渲染,但是单进程渲染不够稳定,只应当在Debug模式下作为调试目的使用。在Cef3.1916等好几个版本中,调试状态下使用单进程模式,当程序初始化或者退出时,会触发中断。但是在多进程模式下没有问题。官方也明确说明不推荐使用单进程模式

CefManager类实现了Cef3的初始化和销毁功能。初始化函数Initialize里调用的CefExecuteProcess函数会检测当前的进程类型,假使是浏览器进程则函数会直接返回,在其他进程的话这个函数会阻塞直接进程销毁。

ClientApp类继承CefBrowserProcessHandler和

CefRenderProcessHandler,可以同时处理浏览器进程和渲染进程的消息。原本多进程模式中,浏览器进程和渲染进程

可以同用一个程序。但是由于我们的主程序的代码比较繁杂,假使让主程序多开进程的话,会占用较多的内存和CPU,同时触发不必要的问题。所以专门另写了一个cef_render项目来作为渲染子进程

cef_render项目代码比较简单,主要代码都是继承CefRenderProcessHandler接口的

CefRenderProcessHandler类。考虑到代码周全,以后可以在cef_render项目补充一些崩溃Dump处理等代码。务必要保证主程序的CefRenderProcessHandler接口实现代码与cef_render程序的CefRenderProcessHandler接口实现代一致。否则单进程和多进程模式下会出现不同的处理结果

在浏览器进程启动时,通过附加参数可以指定渲染子进程的路径

command_line-AppendSwitchWithValue(\process-path\

C++与JS交互

C++调用JS

在browser进程和render进程都可以直接执行JS代码,直接调用CefFrame对象的ExecuteJavaScript方法就可以

JS调用C++

网页中的一些JS回调和对网页的JS扩展,都必需在渲染进程操作。让JS调用C++的方法有三个,

http://./guolixiucai/p/4943748.html里面介绍了两种,/fanfeilong/cefutil里面是更繁杂更强的第三种。

我们项目里,只需要给JS开放一个函数接口,而且接口并不繁杂,所以直接采用JS扩展的方法注册JS回调函数就可以。

在CefRenderProcessHandler::OnWebKitInitialized接口里,注册JS扩展代码

std::stringextensionCode=\

\CefTestWebFunction=function(param){\\nativefunctionCefTestWebFunction(param);\

\returnCefTestWebFunction(param);\\};\\

CefRefPtrCefV8Handlerhandler=newCefJSHandler();

CefRegisterExtension(\handler);

CefRegisterExtension函数会执行扩展代码。网上例子都是创立一个全局对象,然后把JS函数和变量绑定到这个对象上。这里直接申明一个FunExternal的全局函数。当JS代码中调用FunExternal函数时,会根据native关键字后的函数名,去通知C++代码调用对应的native函数

CefJSHandler类继承CefV8Handler接口并实现Execute方法,在CefRegisterExtension传入CefJSHandle指针,当JS代码需要调用native函数时会,会主动触发CefJSHandler::Execute方法

boolCefJSHandler::Execute(constCefStringname,CefRefPtrCefV8Valueobject,const

CefV8ValueListarguments,

CefRefPtrCefV8Valueretval,CefStringexception){

if(name==\arguments.size()==1){

for(autoit:arguments){

if(it-IsString()){CefStringparam=it-GetStringValue();CefRefPtrCefBrowserbrowser=CefV8Context::GetCurrentContext()-GetBrowser();CefRefPtrCefProcessMessagemessage=

CefProcessMessage::Create(kJsCallbackMessage);

message-GetArgumentList()-SetString(0,name);

message-GetArgumentList()-SetString(1,param);

browser-SendProcessMessage(PID_BROWSER,message);retval=CefV8Value::CreateBool(true);}}

returntrue;}

//Functiondoesnotexist.returnfalse;}

在这里可以获取到JS要调用的函数名,以及传入的参数等信息。获取到这些信息后,把他们包装为

CefProcessMessage结构,通过IPC把信息发送到Browser进程进行异步处理。调用SendProcessMessage方法把信息发送到Browser进程

浏览器进程的CefClient::OnProcessMessageReceived方法接收到Render进程发来的消息。Browser进程处理消息后,可以通过C++调用JS的方法去通知Web端消息处理结果

进程终止的流程在

/fanfeilong/cefutil/blob/master/doc/CEF_Close.md里有完整的Cef终止流程分析和处理代码,不过由于我们的项目不单单只有Cef组件,而且使用场景和CefDemo中的不一样,所以采用了不同的关闭流程

CefControl控件的销毁流程

在CefControl控件的析构函数里调用CloseBrowser(true)方法通知浏览器对象要关闭BrowserHandler::DoClose接口被触发,这里不需要做额外处理,直接返回就可以之后BrowserHandler::OnBeforeClose接口被触发,在这里一定要释放所有对CefBrowser对象的引用,否则会导致程序无法退出。

进程退出流程

用户单击右下角托盘的退出菜单项触发到

LoginCallback::DoLogout函数,在这里会调用到代码nim_comp::

WindowsManager::GetInstance()-DestroyAllWindows();,这里销毁所有的窗体,所有控件被销毁,自然就会触发所有CefControl控件的销毁流程,所有浏览器对象被关闭LoginCallback::DoLogout函数里之后会调用到UILogoutCallback函数,这里原本会调用

PostQuitMessage(0)函数终止消息循环,但是我们应当等待所有浏览器对象关闭后在终止消息循环,否则会发生错误。而CefBrowser的关闭是异步的,所以无法保证调用UILogoutCallback函数时所有CefBrowser被关闭我在CefManager类实现PostQuitMessage函数,在这里等待所有CefBrowser关闭后再终止消息循环程序正常终止

CefManager::PostQuitMessage函数里判断当前浏览器对象的数量来决定是否退出消息循环,假使还有浏览器对象没有关闭就等待500毫秒后再检测:

voidCefManager::PostQuitMessage(intnExitCode){

if(browser_count_==0)

{

Post2UI([nExitCode](){

::PostQuitMessage(nExitCode);});}else{

autocb=[nExitCode](){

CefManager::GetInstance()-PostQuitMessage(nExitCode);};

nbase::ThreadManager::PostDelayedTask(kThreadUI,cb,nbase::TimeDelta::FromMilliseconds(500));}}

把Cef组件集成到云信NIM项目

把tool_kits\\cef目录中写好的Cef模块组件拷贝到自己项目的对应目录,并且添加到解决方案中。其中cef_render项目是Cef渲染子进程,是一个独立的exe;libcef_dll_wrapper项目是Cef导出的C语言接口的C++包装类;cef_module项目是核心封装代码,把cef功能封装为可以在nimdemo中直接使用的类,其中包含了对cef功能进行管理的CefManager和CefControl、CefNativeControl两个控件等。把nim_win_demo\\gui\\cef目录的源文件拷贝都自己项目的某个目录,这里面CefControl、CefNativeControl两个控件的测试窗口代码,可有可无进入libs目录,解压cef_sandbox.rar压缩包并把cef_sandbox.lib、

cef_sandbox_d.lib文件放到libs目录;进入libs\\x64目录,解压cef_sandbox.rar压缩包并把cef_sandbox.lib、cef_sandbox_d.lib文件放到libs\\x64目录。这里面是编译cef组件时,为cef模块增加sandbox功能的静态库。bin\\cef目录是cef模块依靠的cef相关dll。主程序初始化时会从bin\\cef目录加载cef所需dll配置nim_demo项目属性,在链接器\\输入\\延迟加载的DLL中参与

libcef.dll;libEGL.dll;libGLESv2.dll(由于我们把cef所需的dll都放到bin\\cef目录了,这样不会导致目录混乱,但是为了顺利加载cefdll,需要延迟加载;假使不想用延迟加载,就把

bin\\cef目录的dll都直接放到bin目录)

WinMain函数中第一句参与(用于延迟加载cefdll,假使不延迟加载,则不需要这句)nim_ui::

InitManager::GetInstance()-AddCefDllToPath();在开始云信组件初始化之前参与如下代码用于初始化cef功能(一定要在云信组件初始化之前)

if(!nim_cef::CefManager::GetInstance()-Initialize(true)return0;

在开始UI线程消息循环之后参与如下代码用于清理cef功能nim_ui::InitManager::GetInstance()-CleanupUiKit();

找到原项目中调用::PostQuitMessage函数的地方,修改为nim_cef::

CefManager::GetInstance()-PostQuitMessage(0);其他配置假使有疑问可以参见CefNimDemo的配置

让Cef支持Flash、mp3、mp4

现在附带的nimdemo中使用的cef相关dll是专门下载了

cef源码增加mp3、mp4功能后重新编译的(在Windows下编译Cef3.2623并参与mp3、mp4支持(附带源码包和最终DLL))。所以假使使用我提供的dll,可以直接支持mp3、mp4播放(官方直接下载的cef不支持)。假使对cef功能有其他需求的话请自行下载编译cef并替换demo中的dll

demo中附带的dll都是release版本,没有附带debug版本

cef_module项目中已经默认支持flash播放,

bin\\cef\\PepperFlash目录中附带了支持flash播放所需的dll,假使不需要flash功能,可以删除这个目录

cef_module项目中提供了两个控件来展示cef浏览器,分别为CefControl、CefNativeControl,CefControl用于离屏渲染模式,CefNativeControl用于真窗口模式,根据需求来选择使用这两个控件的一个。离屏渲染模式的话控件自己控制浏览器的渲染,所以可以与nimduilib结合的更完美,支持透明异形窗体;真窗口模式由于Cef需要依托一个子窗口,由Cef自己渲染,所以无法支持透明异形窗体。对于绝大多数需求,使用离屏渲染模式的CefControl更好,由于与duilib结合更完美。但是假使网页的内容刷新十分频繁(特别是用

于播放Flash时),应当使用真窗口模式,否则Flash播放导致的频繁绘制操作会让程序的CPU占用率飙升!

我们的代码默认是开启离屏渲染模式的,假使有播放Flash的需求或者其他浏览器画面频繁的需求时,应当关闭离屏渲染模式而使用真窗口模式,关于方法时Winmain函数中初始化cef功能时参数传入false,nim_cef::

CefManager::GetInstance()-Initialize(false)。另外我们的duilib窗口默认是使用支持透明异形的分层窗口,是不支持子窗口的,所以假使使用cef的真窗口模式,那么应当关闭duilib窗口的分层窗口样式,关闭方法是创立窗口的Window::Create函数的第五个参数isLayeredWindow设置为false。demo中CefForm、CefNativeForm这两个窗体类分别用于演示离屏渲染模式(对应CefControl控件)和真窗口模式(对应CefNativeControl控件)的功能。这两个窗口的创立代码在MainForm::OnClicked中有演示代码

禁用Cef模块功能

cef_module项目中预处理宏中增加了两个控件Cef模块功能的宏SUPPORT_CEF、SUPPORT_CEF_FLASH。SUPPORT_CEF宏控制是否启用cef功能,

SUPPORT_CEF

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论