CEF3研究(二)

  1. 应用程序结构

每个CEF3应用程序都有一个相同的结构:

  • 提供一个入口函数以初始化CEF和运行每个子进程逻辑和CEF消息处理
  • 提供一个CefApp子类处理某个进程的回调
  • 提供一个CefClinet子类处理某个浏览进程的回调
  • 调用CefBrowserHost::CreateBrowser()函数创建浏览进程实例并使用CefLifeSpanHandler来管理浏览生命周期

2. 入口函数

CEF3应用程序都是以多进程方式运行的。这些进程都可以使用相同的可执行文件和独立的可执行文件被分配在每个子进程上。每个可执行进程都有一个入口函数。
每个CEF3子进程运行时使用运行行来指定配置信息并通过CefMainArgs结构传递给CefExecuteProcess函数,CefMainArgs结构是跨平台的。
如:
 CefMainArgs main_args(argc, argv); 
 CefMainArgs main_args(hInstance);

3.单可执行体-单进程运行方式

当单可执行体时行时,入口函数CefExecuteProcess在不同进程类型之间需要区分。单可执行体结构只支持window和linux,不支持macos

4. 分离的子进程可执行体-多进程运行方式

当使用一个分离的子进程执行体时需要两个分离的进程和入口函数。

5. 消息循环集成

CEF可集成已经存在的应用程序消息循环来代替它自己的消息循环。有2种方式:

    1. 正常的调用CefDoMessageLoopWork() 函数来代替调用 CefRunMessageLoop()。每调用 CefDoMessageLoopWork()函数会对CEF消息循环执行单一集成。
      应该谨慎使用这种方法。调用的方法也经常会挨饿CEF消息循环凑并且浏览器性能产生影响。调用方法过于频繁地将影响CPU使用率。
    2. 设置 CefSettings.multi_threaded_message_loop = true(仅Windows平台),这会引起CEF从主应用程序线程以单个线程运行浏览器的UI线程。这不会引起 CefDoMessageLoopWork()和 CefRunMessageLoop()的调用。. CefInitialize() 和CefShutdown() 应该在应用程序的主线程调用。 需要自己提供机制与应用程序主线程通信。

6. CefSettings

CefSettings结构允许Cef配置应用程序类型。以下列出通用的成员:

  • single_process 设置为true将为浏览器和渲染使用单进程。也可配置使用单个进程的命令行开关。
  • browser_subprocess_path 子进程的单个执行体路径,
  • multi_threaded_message_loop为true表示浏览器进程的消息循环以单线程运行。
  • command_line_args_idsabled为true表示禁用使用标准的CEF和Chrominum命令行参数的浏览器进程配置的特性。
  • cache_path缓存数据保存在磁盘上,如果为空,内存缓存会被某些特性使用,临时磁盘缓存会被其他地方使用。如果不为空,如HTML5本地存储数据库会跨域。
  • locale locale字符串会传递给blink,默认为en-US
  • log_file为debuglog文件路径
  • log_severity日志等级
  • resources_dir_path资料的目录路径。即cef.pak或devtools_resources.pak文件的保存路径
  • locales_dir_path
  • locales_dir_path locales的保存路径
  • remote_debugging_port远程调试端口。范围在1024~65535

7.CefBrowser和CefFrame

CefBrowser和CefFrame对象用于向浏览器发送命令和接受回调函数的状态信息。每个CerBrowser对象有一个主CefFrame对象描述主窗口。有零个和多个描述子窗口。例如:一个浏览器加载两个窗口会有三个CefFrame对象,一个是顶层窗口,两个子窗口。

在主窗口中加载一个URL:
browser->GetMainFrame()->LoadURL(some_url);

调用浏览的返回按钮:
browser->GoBack();

获取主窗口的HTML内容

class Visitor : public CefStringVisitor {

public: Visitor() {}

virtual void Visit(const CefString& string) OVERRIDE { // Do something with |string|... }

IMPLEMENT_REFCOUNTING(Visitor);

};

browser->GetMainFrame()->GetSource(new Visitor());

CefBrowser和CefFrame对象分别存在浏览进程和渲染进程中。在浏览进程中可通过CefBrowser::GetHoset()函数控制主机行为,如获取窗口句柄:

CefWindowHandle window_handle = browser->GetHost()->GetWindowHandle();

8.CefApp

CefApp接口提供特殊进程回调的访问。重要的回调包括:
OnBeforeCommandLineProcessing 以编程的方式设置命令行
OnRegisterCustomSchemes 提供一个机会自定义主题
GetBrowserProcessHandler 指定浏览进程及包括 OnContextInitialized() 特定功能的处理者
GetRenderProcessHandler 渲染进程的处理者,包括JavaScript关联的回调和进程消息

9.CefClient

CefClient接口提供了浏览器实例的特定回调。一个CefClient实例可以被多个浏览器共享。重要的回调包括:
浏览器生命周期,上下文菜单,对话框,显示通知,拖拽事件,焦点事件,键盘事件的处理者
OnProcessMessageReceived 从渲染进程中发来的IPC消息的接受。

10.浏览器生命周期

Browser Life Space 以调用 CefBrowserHost::CreateBrowser()或CefBrowserHost::CreateBrowserSync()函数开始。 方便执行逻辑,包括CefBrowserProcessHandler::OnContextInitialized()或像WM_CREATE消息处理的调用。

CefLifeSpaceHandler类提供了管理浏览器生命周期的回调。

  • OnAfterCreated() 在浏览器对象被创建后立即调用,主应用程序通常用这个函数保存浏览器对象的引用,如:

    void MyClient::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
      // Must be executed on the UI thread.
      REQUIRE_UI_THREAD();
      // Protect data members from access on multiple threads.
      AutoLock lock_scope(this);  // Deprecated -- see the “Threads” section.
    
      if (!m_Browser.get())   {
        // Keep a reference to the main browser.
        m_Browser = browser;
        m_BrowserId = browser->GetIdentifier();
      }
    
      // Keep track of how many browsers currently exist.
      m_BrowserCount++;
    }
  • CefBrowserHost::CloseBrowser() 销毁浏览进程 如:browser->GetHost()->CloseBrowser(false)
    如果浏览器是其他窗口的父窗口,那么这个关闭事件会引起父窗口的系统函数调用。那父窗口需要调用 CloseBrowser(false) 并等待第二个系统调用的关闭事件来指示浏览进程允许关闭。
    如果关闭通过Javascript事件或DoClose()回调函数处理,那第二个系统关闭事件就不会被发送。
    IsClosing()测试是否关闭,如果是第一次的系统关闭事件就返回false,每二次返回true; 
    第一个系统关闭事件是在窗口的WndProc函数中处理的
    case WM_CLOSE:
      if (g_handler.get() && !g_handler->IsClosing()) {
        CefRefPtr<CefBrowser> browser = g_handler->GetBrowser();
        if (browser.get()) {
          // Notify the browser window that we would like to close it. This will result in a call to
          // MyHandler::DoClose() if the JavaScript ‘onbeforeunload‘ event handler allows it.
          browser->GetHost()->CloseBrowser(false);
    
          // Cancel the close.
          return 0;
        }
      }
    
      // Allow the close.
      break;
    
    case WM_DESTROY:
      // Quitting CEF is handled in MyHandler::OnBeforeClose().
      return 0;
    }
  • DoClose() 设置m_blsClosing标识并设置第二次系统关闭事件为false
    bool MyClient::DoClose(CefRefPtr<CefBrowser> browser) {
      // Must be executed on the UI thread.
      REQUIRE_UI_THREAD();
      // Protect data members from access on multiple threads.
      AutoLock lock_scope(this);
    
      // Closing the main window requires special handling. See the DoClose()
      // documentation in the CEF header for a detailed description of this
      // process.
      if (m_BrowserId == browser->GetIdentifier()) {
        // Notify the browser that the parent window is about to close.
        browser->GetHost()->ParentWindowWillClose();
    
        // Set a flag to indicate that the window close should be allowed.
        m_bIsClosing = true;
      }
    
      // Allow the close. For windowed browsers this will result in the OS close
      // event being sent.
      return false;
    }
  • OnBeforeClose 在接受第二次OS关闭事件之前需要调用OnBeforeCloseb函数释放浏览器进程的引用。
时间: 2024-08-28 17:11:21

CEF3研究(二)的相关文章

C++的开源跨平台日志库glog学习研究(二)--宏的使用

上一篇从整个工程上简单分析了glog,请看C++的开源跨平台日志库glog学习研究(一),这一篇对glog的实现代码入手,比如在其源码中以宏的使用最为广泛,接下来就先对各种宏的使用做一简单分析. 1. 日志输出宏 这里我们以一条最简单的日至输出为例说明: LOG(WARNING) << "This is a warning message"; 这里LOG是一个宏,其定义如下(logging.h line 487): #define LOG(severity) COMPACT

(转载)Fiddler实战深入研究(二)

原文来源于:http://www.cnblogs.com/tugenhua0707/p/4637771.html,作者:涂根华 !个人觉得文章写的特别好,故收藏于此,感谢原作者的分享 Fiddler实战深入研究(二) 阅读目录 Fiddler不能捕获chrome的session的设置 理解数据包统计 请求重定向(AutoResponder) Composer选项卡 Filters选项卡断点调式 Fiddler 中的Stave插件 回到顶部 Fiddler不能捕获chrome的session的设置

智力题研究二

[IT思想类] 1. 有1000瓶水,其中有一瓶有毒,小白鼠只要尝一点带毒的水24小时后就会死亡,至少要多少只小白鼠才能在24小时时鉴别出那瓶水有毒?(中级) 2. 共有三类药,分别重1g,2g,3g,放到若干个瓶子中,现在能确定每个瓶子中只有其中一种药,且每瓶中的药片足够多,能只称一次就知道各个瓶子中都是盛的哪类药吗? 如果有4类药呢?5类呢?N类呢(N可数)?(高级) 如果是共有m个瓶子盛着n类药呢(m,n为正整数,药的质量各不相同但各种药的质量已知)?你能只称一次就知道每瓶的药是什么吗?

王爽-汇编语言-综合研究二-使用寄存器

(一) 研究概述 我们为什么必须使用变量?因为我们在编程时必须存储数据.那么如果可以使用别的方法存储数据,我们就可以不必因此目的而使用变量. 用什么方法来存储数据呢?在学习汇编语言是.我们把数据存储在寄存器和内存空间中.那么,在本次试验中,我们研究的是C语言中如何使用寄存器. (二) 研究过程 (1) 编写一个程序url.c 编译链接完成,用debug加载. -u查看如下: 这里的语句比较整齐有逻辑,像是某些功能的实现语句,但是往下-u,几次都看不到所写的语句. 这里,main函数的代码应该是在

CEF3研究(三)

一.Off-Screen Rendering 脱屏绘制 CEF的脱屏渲染并不创建源生的浏览器窗口,而是CEF提供主应用程序在无效区域和像素buffer里渲染,然后主应用程序通过鼠标.键盘和焦点事件通知CEF.脱屏渲染现在不支持图层混合加速图层混合加速.脱屏渲染要窗口浏览器一样接受相同的通知,包括生命周期通知等,为了使用脱屏渲染: 实现CefRenderHandler接口,所有方法是必需的,除非另有指示. 调用CefWindowInfo::SetAsOffScreen()函数和将CefWindow

CEF3研究(四)之javascript集成

一.介绍 谷歌浏览器和CEF使用V8JavaScript Engine作为内容的JavaScript实现.在浏览器中的每个窗口都有它自己在的JS上下文提供作用域和在窗口中安全的执行JS代码.CEF暴露大量JS功能集成在客户端应用程序.CEF3的Webkit和JS在单独的渲染进程中运行.在渲染进程的主线程中使用TID_RENDERER 作为唯一标识.所有V8的执行必须放置在这个线程中.与JS执行相关的回调函数被暴露是通过CefRenderProcessHandler接口实现.当一个新的渲染进程被初

Nginx源码研究二:NGINX的网络IO

NGINX作为服务端的应用程序,在客户端发出数据后,服务端在做着这样一些处理,数据先会经过网卡,网卡会和操作系统做交互,经过操作系统的协议栈处理,再和不同的应用程序交互. 在这里面涉及两个概念,一个是用户态,一个是内核态.应用程序通过系统调用函数进入内核空间,内核运行进行数据准备和数据拷贝等工作.对于NGINX来说,他是作为应用程序和操作系统交互,即是用户态和内核态的之间的交互,NGINX和内核交互方式有很多,例如open(),read() 等都是在和内核交互,而对于网络IO来说,我们知道lin

自动几何推理的研究(二) 线

现在研究线. 线对象被大量使用, 为此需要仔细分析. 线对象大致分两类: 线段(L_Segment), 直线(L_Line). 线段(L_Segment) 主要用于线段相等记录(Cong_Seg), 线段等比(Ratio_Seg)记录中, 也用于线段相等集合(CSegs). 线段对象本身不作为搜索数据. 直线(L_Line) 主要用于平行线(P_Line), 垂线(T_Line), 角(AngleS) 记录中. 实现中直线以路径(G_Path)为基类, 这样与圆(Circle)共用一个实现基类,

mysql高可用研究(二) 主从+MHA+Atlas

关于Atlas的详细介绍请访问:https://github.com/Qihoo360/Atlas/blob/master/README_ZH.md 为什么要使用Atlas?应用程序直连数据库不好吗?还要在前面加上一层代理,会不会降低应用的读写性能?会不会增加维护管理的成本?我想这是每个使用atlas之前的疑问. 1.为什么要使用Atlas? 我们使用atlas,主要使用它的读写分离和从库负载均衡功能.因为咱们这读业务远远多于写,故采用读写分离的架构再合适不过了.之前实现读写分离,一般都是通过应