zoukankan      html  css  js  c++  java
  • renderer进程中的JS给CEF的browserC++进程发送消息

    1.1  renderer进程中的JS给CEF的browserC++进程发送消息

    1.1.1         流程原理介绍

    renderer进程中暴露一个query函数和cancel函数,在renderer进程运行的JavaScript代码调用window.cefQuery,cefQueryCancel函数将消息发给browser进程的c++代码处理消息,.cefQuery,cefQueryCancel是在C++代码中的CefMessageRouterConfig对象中注册的,如果你希望注册不同名字的函数,需要在CefMessageRouterConfig对象中设置,如果你要 设置两套注册函数,router也要两套。rendder进程和browser进程之间是通两端的消息路由传递消息的,render进程消息路由CefMessageRouterRendererSide,browser进程消息路由CefMessageRouterBrowserSide。在renderer进程的OnProcessMessageRecieved, OnContextCreated OnContextReleased函数中通过router对象调用CefMessageRouterRendererSide中同名的函数(OnContextCreated注册JavaScript的函数;OnContextReleased取消与上下文相关的正在进行中的query,调用OnQueryCanceled会被调用;OnProcessMessageRecieved消被router正确处理返回true),消息路由会将从renderer进程发送给browser进程中的CefMessageRouterBrowserSide路由。renderer进程支持一般的JavaScript回调函数注册和执行,browser进程中的路由router可以对消息采用一个或者多个不同逻辑的处理实例来处理。前端JavaScript调用window.cefQuery函数,renderder通过消息路由将消息发给browser进程,browser进程的一个或者多个queryhander就会接收到消息,每个handler可以选择处理或者忽略消息。如果处理了消息,如果响应有效,需要执行回调函数Callback::Success,如果出错,需要调用Callback::Failure。这两个函数会同步调用renderer进程中JavaScript的回调函数onSuccess和onFailure,返回执行结果。如果query没有被borwser进程的hander处理,则会自动取消,JavaScript的onFaillure回调函数会被执行,错误码-1;qurry可以是持续的或者非持续的

    (1)如果是持续的,需要在browser进程中定义map<int64,CefRefPtr<callback>>保存持续的请求queryid和callback对象,在onquery函数中保存进入map,当JavaScript调用window.CefQueryCancel函数,或者C++代码中使用了CallFailure函数,或者上下文context销毁时,需要将query在C++的OnQueryCancel回调函数中从map中删除。

    (2)如果query是非持续的,注册会在JavaScript的回调函数执行后自动清除。不用保存到map主要实现在CEF的cef_message_router.h文件中。

    1.1.2         query请模式

    (1)   一次请求模式,使用非持续query,handle执行请求,返回响应, query销毁。

    (2)   广播模式。使用持久性query注册为一个广播接受者,handler一直追踪所有的注册回调,并执行他们来发送广播消息。

    (3)   订阅模式。使用持续性query注册为JavaScript的订阅接受者,handler在第一次请求时初始化订阅feed,将响应发送给所有的订阅者。没有一个注册的JavaScript接收者时,handle会取消订阅feed。

    render进程中一般只要一个router就可以了,如果需要注册不同的JavaScript函数名字,需要多个router。当browser进程需要多个hadler来处理不同的消息,这样做是非常有用的。

    1.1.3         消息通讯具体开发步骤

    (1)         在renderer进程的rendererApp类的构造函数中创建CefMessageRouterRendererSide对象。

    CefMessageRouterConfig config;

    m_messagerouter=CefMessageRouterRendererSide.Create(config);

    (2)         在renderer进程的OnProcessMessageRecieved, OnContextReleased OnContextCreated函数中通过router对象调用CefMessageRouterRendererSide中同名的函数,消息就会发送给browser进程中的CefMessageRouterBrowserSide路由。

    void RendererApp::OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context)

    {

           m_messageRouter->OnContextCreated(browser, frame, context);

    }

    void RendererApp::OnContextReleased(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context)

    {

           m_messageRouter->OnContextReleased(browser, frame, context);

    }

    bool RendererApp::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefProcessId source_process, CefRefPtr<CefProcessMessage> message)

    {

           return m_messageRouter->OnProcessMessageReceived(

                  browser, source_process, message);

    }

    (3)         定义处理类QueryHand,继承类 CefMessageRouterBrowserSide ::Handler类,实现OnQuery函数。

    #pragma once

    #include <map>

    #include "include/wrapper/cef_message_router.h"

    #include "FrameCommunication/CefInterfaceCallback.h"

     

    class CefQueryHandler : public CefBaseRefCounted

                           , public CefMessageRouterBrowserSide::Handler

    {

    protected:

        virtual bool OnQuery(CefRefPtr<CefBrowser> browser,

            CefRefPtr<CefFrame> frame,

            int64 query_id,

            const CefString& request,

            bool persistent,

            CefRefPtr<Callback> callback);

     

        virtual void OnQueryCanceled(CefRefPtr<CefBrowser> browser,

            CefRefPtr<CefFrame> frame,

            int64 query_id);

     

        void complete(int64 query_id, int error_code, const CefString response);

    private:

        std::map<int64, CefRefPtr<Callback>> m_pendings;

        IMPLEMENT_REFCOUNTING(CefQueryHandler);

    };

     

    (4)在browser进程中clienthand类中创建对象CefMessageRouterConfig

    CefMessageRouterConfig用来定义js调用的函数名称,下面给出的是默认函数名称。

    CefMessageRouterConfig config;

    //    config.js_query_function = "cefQuery";

    //    config.js_cancel_function = "cefQueryCancel";

    (5)在browser进程中根据配置创建CefMessageRouterBrowserSide对象管理QueryHand。创建QueryHand对象,并添加到CefMessageRouterBrowserSide。clienthandler的OnBeforeClose、OnBeforeBrowse、OnProcessMessageReceived函数中执行CefMessageRouterBrowserSide对象中对应名称的函数(在OnBeforeClose、OnBeforeBrowse中调用,这样做的目的是网页刷新或者关闭时,所有正在进行中的query会取消掉,OnQueryCanceled函数会被调用,取消所有正在进行的query。在OnProcessMessageReceived中调用,则是消息如果被router正确处理,则返回true,否则返回false)。定义CefMessageRouterBrowserSide对象用来管理QueryHand对象。

    m_queryHand=new QueryHand();

    m_browser_side_router= CefMessageRouterBrowserSide::Create(config);

    m_browser_side_router ->AddHandler(my_handler.);

    bool ClientHandler::OnBeforeBrowse(CefRefPtr<CefBrowser> browser,

        CefRefPtr<CefFrame> frame,

        CefRefPtr<CefRequest> request,

        bool user_gesture,

        bool is_redirect) {

        m_messageRouter->OnBeforeBrowse(browser, frame);

    }

    bool ClientHandler::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefProcessId source_process, CefRefPtr<CefProcessMessage> message)

    {

        if (m_messageRouter->OnProcessMessageReceived(browser, source_process,

            message)) {

            return true;

        }

    (6)JavaScript调用cefQuery函数

    <html>

    <head>

    <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>

    <script>

    $(document).ready(function(){

      $(document).dblclick(function(){

        //alert("get doubleclicked");

           if(window==top.window){//判断是否是嵌入

                  window.cefQuery({发给CEF消息

              request: "message-content",

              persistent: false,

              onSuccess: function(response) { alert(response); },

              onFailure: function(code, msg) { alert(code + " - " + msg); }

            });

           }

          

      });

    });

    </script>

    </head>

    <body>

    </body>

    </html>

    (7)onquery函数接收消息,处理消息,执行回调将queryid和回调对象保存到map,OnQueryCanceled函数中从map中找到对应的queryid,调用callback对象的onfailure函数,然后从map中清除。

    void MyHandler::OnQuery(int64 query_id,

                                CefRefPtr<CefBrowser> browser,

                               CefRefPtr<CefFrame> frame,

                                const CefString& request,

                               bool persistent,

                               CefRefPtr<Callback> callback) {

    // 处理消息request

    if (persistent)

           {

                  bRet = m_pendings.insert(std::make_pair(query_id, callback)).second;

           }

           else

           {

                  callback->Success("success");

                  bRet = true;

           }

    }

    void CefQueryHandler::OnQueryCanceled(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, int64 query_id)

    {

           auto it = m_pendings.find(query_id);

           if (it != m_pendings.end())

           {

                  it->second->Failure(-1,"canceled");

                  m_pendings.erase(it);

           }

    }

    Cef消息路由类定义如下:

    // Copyright (c) 2014 Marshall A. Greenblatt. All rights reserved.
    //
    // Redistribution and use in source and binary forms, with or without
    // modification, are permitted provided that the following conditions are
    // met:
    //
    //    * Redistributions of source code must retain the above copyright
    // notice, this list of conditions and the following disclaimer.
    //    * Redistributions in binary form must reproduce the above
    // copyright notice, this list of conditions and the following disclaimer
    // in the documentation and/or other materials provided with the
    // distribution.
    //    * Neither the name of Google Inc. nor the name Chromium Embedded
    // Framework nor the names of its contributors may be used to endorse
    // or promote products derived from this software without specific prior
    // written permission.
    //
    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    //
    // ---------------------------------------------------------------------------
    //
    // The contents of this file are only available to applications that link
    // against the libcef_dll_wrapper target.
    //
    
    #ifndef CEF_INCLUDE_WRAPPER_CEF_MESSAGE_ROUTER_H_
    #define CEF_INCLUDE_WRAPPER_CEF_MESSAGE_ROUTER_H_
    #pragma once
    
    #include "include/base/cef_ref_counted.h"
    #include "include/cef_base.h"
    #include "include/cef_browser.h"
    #include "include/cef_process_message.h"
    #include "include/cef_v8.h"
    
    // The below classes implement support for routing aynchronous messages between
    // JavaScript running in the renderer process and C++ running in the browser
    // process. An application interacts with the router by passing it data from
    // standard CEF C++ callbacks (OnBeforeBrowse, OnProcessMessageRecieved,
    // OnContextCreated, etc). The renderer-side router supports generic JavaScript
    // callback registration and execution while the browser-side router supports
    // application-specific logic via one or more application-provided Handler
    // instances.
    //
    // The renderer-side router implementation exposes a query function and a cancel
    // function via the JavaScript 'window' object:
    //
    //    // Create and send a new query.
    //    var request_id = window.cefQuery({
    //        request: 'my_request',
    //        persistent: false,
    //        onSuccess: function(response) {},
    //        onFailure: function(error_code, error_message) {}
    //    });
    //
    //    // Optionally cancel the query.
    //    window.cefQueryCancel(request_id);
    //
    // When |window.cefQuery| is executed the request is sent asynchronously to one
    // or more C++ Handler objects registered in the browser process. Each C++
    // Handler can choose to either handle or ignore the query in the
    // Handler::OnQuery callback. If a Handler chooses to handle the query then it
    // should execute Callback::Success when a response is available or
    // Callback::Failure if an error occurs. This will result in asynchronous
    // execution of the associated JavaScript callback in the renderer process. Any
    // queries unhandled by C++ code in the browser process will be automatically
    // canceled and the associated JavaScript onFailure callback will be executed
    // with an error code of -1.
    //
    // Queries can be either persistent or non-persistent. If the query is
    // persistent than the callbacks will remain registered until one of the
    // following conditions are met:
    //
    // A. The query is canceled in JavaScript using the |window.cefQueryCancel|
    //    function.
    // B. The query is canceled in C++ code using the Callback::Failure function.
    // C. The context associated with the query is released due to browser
    //    destruction, navigation or renderer process termination.
    //
    // If the query is non-persistent then the registration will be removed after
    // the JavaScript callback is executed a single time. If a query is canceled for
    // a reason other than Callback::Failure being executed then the associated
    // Handler's OnQueryCanceled method will be called.
    //
    // Some possible usage patterns include:
    //
    // One-time Request. Use a non-persistent query to send a JavaScript request.
    //    The Handler evaluates the request and returns the response. The query is
    //    then discarded.
    //
    // Broadcast. Use a persistent query to register as a JavaScript broadcast
    //    receiver. The Handler keeps track of all registered Callbacks and executes
    //    them sequentially to deliver the broadcast message.
    //
    // Subscription. Use a persistent query to register as a JavaScript subscription
    //    receiver. The Handler initiates the subscription feed on the first request
    //    and delivers responses to all registered subscribers as they become
    //    available. The Handler cancels the subscription feed when there are no
    //    longer any registered JavaScript receivers.
    //
    // Message routing occurs on a per-browser and per-context basis. Consequently,
    // additional application logic can be applied by restricting which browser or
    // context instances are passed into the router. If you choose to use this
    // approach do so cautiously. In order for the router to function correctly any
    // browser or context instance passed into a single router callback must then
    // be passed into all router callbacks.
    //
    // There is generally no need to have multiple renderer-side routers unless you
    // wish to have multiple bindings with different JavaScript function names. It
    // can be useful to have multiple browser-side routers with different client-
    // provided Handler instances when implementing different behaviors on a per-
    // browser basis.
    //
    // This implementation places no formatting restrictions on payload content.
    // An application may choose to exchange anything from simple formatted
    // strings to serialized XML or JSON data.
    //
    //
    // EXAMPLE USAGE
    //
    // 1. Define the router configuration. You can optionally specify settings
    //    like the JavaScript function names. The configuration must be the same in
    //    both the browser and renderer processes. If using multiple routers in the
    //    same application make sure to specify unique function names for each
    //    router configuration.
    //
    //    // Example config object showing the default values.
    //    CefMessageRouterConfig config;
    //    config.js_query_function = "cefQuery";
    //    config.js_cancel_function = "cefQueryCancel";
    //
    // 2. Create an instance of CefMessageRouterBrowserSide in the browser process.
    //    You might choose to make it a member of your CefClient implementation,
    //    for example.
    //
    //    browser_side_router_ = CefMessageRouterBrowserSide::Create(config);
    //
    // 3. Register one or more Handlers. The Handler instances must either outlive
    //    the router or be removed from the router before they're deleted.
    //
    //    browser_side_router_->AddHandler(my_handler);
    //
    // 4. Call all required CefMessageRouterBrowserSide methods from other callbacks
    //    in your CefClient implementation (OnBeforeClose, etc). See the
    //    CefMessageRouterBrowserSide class documentation for the complete list of
    //    methods.
    //
    // 5. Create an instance of CefMessageRouterRendererSide in the renderer
    // process.
    //    You might choose to make it a member of your CefApp implementation, for
    //    example.
    //
    //    renderer_side_router_ = CefMessageRouterRendererSide::Create(config);
    //
    // 6. Call all required CefMessageRouterRendererSide methods from other
    //    callbacks in your CefRenderProcessHandler implementation
    //    (OnContextCreated, etc). See the CefMessageRouterRendererSide class
    //    documentation for the complete list of methods.
    //
    // 7. Execute the query function from JavaScript code.
    //
    //    window.cefQuery({request: 'my_request',
    //                     persistent: false,
    //                     onSuccess: function(response) { print(response); },
    //                     onFailure: function(error_code, error_message) {} });
    //
    // 8. Handle the query in your Handler::OnQuery implementation and execute the
    //    appropriate callback either immediately or asynchronously.
    //
    //    void MyHandler::OnQuery(int64 query_id,
    //                            CefRefPtr<CefBrowser> browser,
    //                            CefRefPtr<CefFrame> frame,
    //                            const CefString& request,
    //                            bool persistent,
    //                            CefRefPtr<Callback> callback) {
    //      if (request == "my_request") {
    //        callback->Continue("my_response");
    //        return true;
    //      }
    //      return false;  // Not handled.
    //    }
    //
    // 9. Notice that the onSuccess callback is executed in JavaScript.
    
    ///
    // Used to configure the query router. The same values must be passed to both
    // CefMessageRouterBrowserSide and CefMessageRouterRendererSide. If using
    // multiple router pairs make sure to choose values that do not conflict.
    ///
    struct CefMessageRouterConfig {
      CefMessageRouterConfig();
    
      // Name of the JavaScript function that will be added to the 'window' object
      // for sending a query. The default value is "cefQuery".
      CefString js_query_function;
    
      // Name of the JavaScript function that will be added to the 'window' object
      // for canceling a pending query. The default value is "cefQueryCancel".
      CefString js_cancel_function;
    };
    
    ///
    // Implements the browser side of query routing. The methods of this class may
    // be called on any browser process thread unless otherwise indicated.
    ///
    class CefMessageRouterBrowserSide
        : public base::RefCountedThreadSafe<CefMessageRouterBrowserSide> {
     public:
      ///
      // Callback associated with a single pending asynchronous query. Execute the
      // Success or Failure method to send an asynchronous response to the
      // associated JavaScript handler. It is a runtime error to destroy a Callback
      // object associated with an uncanceled query without first executing one of
      // the callback methods. The methods of this class may be called on any
      // browser process thread.
      ///
      class Callback : public CefBaseRefCounted {
       public:
        ///
        // Notify the associated JavaScript onSuccess callback that the query has
        // completed successfully with the specified |response|.
        ///
        virtual void Success(const CefString& response) = 0;
    
        ///
        // Notify the associated JavaScript onFailure callback that the query has
        // failed with the specified |error_code| and |error_message|.
        ///
        virtual void Failure(int error_code, const CefString& error_message) = 0;
      };
    
      ///
      // Implement this interface to handle queries. All methods will be executed on
      // the browser process UI thread.
      ///
      class Handler {
       public:
        typedef CefMessageRouterBrowserSide::Callback Callback;
    
        ///
        // Executed when a new query is received. |query_id| uniquely identifies the
        // query for the life span of the router. Return true to handle the query
        // or false to propagate the query to other registered handlers, if any. If
        // no handlers return true from this method then the query will be
        // automatically canceled with an error code of -1 delivered to the
        // JavaScript onFailure callback. If this method returns true then a
        // Callback method must be executed either in this method or asynchronously
        // to complete the query.
        ///
        virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
                             CefRefPtr<CefFrame> frame,
                             int64 query_id,
                             const CefString& request,
                             bool persistent,
                             CefRefPtr<Callback> callback) {
          return false;
        }
    
        ///
        // Executed when a query has been canceled either explicitly using the
        // JavaScript cancel function or implicitly due to browser destruction,
        // navigation or renderer process termination. It will only be called for
        // the single handler that returned true from OnQuery for the same
        // |query_id|. No references to the associated Callback object should be
        // kept after this method is called, nor should any Callback methods be
        // executed.
        ///
        virtual void OnQueryCanceled(CefRefPtr<CefBrowser> browser,
                                     CefRefPtr<CefFrame> frame,
                                     int64 query_id) {}
    
        virtual ~Handler() {}
      };
    
      ///
      // Create a new router with the specified configuration.
      ///
      static CefRefPtr<CefMessageRouterBrowserSide> Create(
          const CefMessageRouterConfig& config);
    
      ///
      // Add a new query handler. If |first| is true it will be added as the first
      // handler, otherwise it will be added as the last handler. Returns true if
      // the handler is added successfully or false if the handler has already been
      // added. Must be called on the browser process UI thread. The Handler object
      // must either outlive the router or be removed before deletion.
      ///
      virtual bool AddHandler(Handler* handler, bool first) = 0;
    
      ///
      // Remove an existing query handler. Any pending queries associated with the
      // handler will be canceled. Handler::OnQueryCanceled will be called and the
      // associated JavaScript onFailure callback will be executed with an error
      // code of -1. Returns true if the handler is removed successfully or false
      // if the handler is not found. Must be called on the browser process UI
      // thread.
      ///
      virtual bool RemoveHandler(Handler* handler) = 0;
    
      ///
      // Cancel all pending queries associated with either |browser| or |handler|.
      // If both |browser| and |handler| are NULL all pending queries will be
      // canceled. Handler::OnQueryCanceled will be called and the associated
      // JavaScript onFailure callback will be executed in all cases with an error
      // code of -1.
      ///
      virtual void CancelPending(CefRefPtr<CefBrowser> browser,
                                 Handler* handler) = 0;
    
      ///
      // Returns the number of queries currently pending for the specified |browser|
      // and/or |handler|. Either or both values may be empty. Must be called on the
      // browser process UI thread.
      ///
      virtual int GetPendingCount(CefRefPtr<CefBrowser> browser,
                                  Handler* handler) = 0;
    
      // The below methods should be called from other CEF handlers. They must be
      // called exactly as documented for the router to function correctly.
    
      ///
      // Call from CefLifeSpanHandler::OnBeforeClose. Any pending queries associated
      // with |browser| will be canceled and Handler::OnQueryCanceled will be
      // called. No JavaScript callbacks will be executed since this indicates
      // destruction of the browser.
      ///
      virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) = 0;
    
      ///
      // Call from CefRequestHandler::OnRenderProcessTerminated. Any pending queries
      // associated with |browser| will be canceled and Handler::OnQueryCanceled
      // will be called. No JavaScript callbacks will be executed since this
      // indicates destruction of the context.
      ///
      virtual void OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser) = 0;
    
      ///
      // Call from CefRequestHandler::OnBeforeBrowse only if the navigation is
      // allowed to proceed. If |frame| is the main frame then any pending queries
      // associated with |browser| will be canceled and Handler::OnQueryCanceled
      // will be called. No JavaScript callbacks will be executed since this
      // indicates destruction of the context.
      ///
      virtual void OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
                                  CefRefPtr<CefFrame> frame) = 0;
    
      ///
      // Call from CefClient::OnProcessMessageReceived. Returns true if the message
      // is handled by this router or false otherwise.
      ///
      virtual bool OnProcessMessageReceived(
          CefRefPtr<CefBrowser> browser,
          CefProcessId source_process,
          CefRefPtr<CefProcessMessage> message) = 0;
    
     protected:
      // Protect against accidental deletion of this object.
      friend class base::RefCountedThreadSafe<CefMessageRouterBrowserSide>;
      virtual ~CefMessageRouterBrowserSide() {}
    };
    
    ///
    // Implements the renderer side of query routing. The methods of this class must
    // be called on the render process main thread.
    ///
    class CefMessageRouterRendererSide
        : public base::RefCountedThreadSafe<CefMessageRouterRendererSide> {
     public:
      ///
      // Create a new router with the specified configuration.
      ///
      static CefRefPtr<CefMessageRouterRendererSide> Create(
          const CefMessageRouterConfig& config);
    
      ///
      // Returns the number of queries currently pending for the specified |browser|
      // and/or |context|. Either or both values may be empty.
      ///
      virtual int GetPendingCount(CefRefPtr<CefBrowser> browser,
                                  CefRefPtr<CefV8Context> context) = 0;
    
      // The below methods should be called from other CEF handlers. They must be
      // called exactly as documented for the router to function correctly.
    
      ///
      // Call from CefRenderProcessHandler::OnContextCreated. Registers the
      // JavaScripts functions with the new context.
      ///
      virtual void OnContextCreated(CefRefPtr<CefBrowser> browser,
                                    CefRefPtr<CefFrame> frame,
                                    CefRefPtr<CefV8Context> context) = 0;
    
      ///
      // Call from CefRenderProcessHandler::OnContextReleased. Any pending queries
      // associated with the released context will be canceled and
      // Handler::OnQueryCanceled will be called in the browser process.
      ///
      virtual void OnContextReleased(CefRefPtr<CefBrowser> browser,
                                     CefRefPtr<CefFrame> frame,
                                     CefRefPtr<CefV8Context> context) = 0;
    
      ///
      // Call from CefRenderProcessHandler::OnProcessMessageReceived. Returns true
      // if the message is handled by this router or false otherwise.
      ///
      virtual bool OnProcessMessageReceived(
          CefRefPtr<CefBrowser> browser,
          CefProcessId source_process,
          CefRefPtr<CefProcessMessage> message) = 0;
    
     protected:
      // Protect against accidental deletion of this object.
      friend class base::RefCountedThreadSafe<CefMessageRouterRendererSide>;
      virtual ~CefMessageRouterRendererSide() {}
    };
    
    #endif  // CEF_INCLUDE_WRAPPER_CEF_MESSAGE_ROUTER_H_
    

      

    自己开发了一个股票智能分析软件,功能很强大,需要的点击下面的链接获取:

    https://www.cnblogs.com/bclshuai/p/11380657.html

    自己开发了一个股票智能分析软件,功能很强大,需要的点击下面的链接获取: https://www.cnblogs.com/bclshuai/p/11380657.html
  • 相关阅读:
    最富有客户的资产总量
    无重叠区间
    工作流分析推荐
    sharepoint外包和定制开发公司分析比较及推荐
    sharepoint开发企业信息门户系统分析及公司推荐
    北京sharepoint开发公司比较推荐
    国内市场主流专业的sharepoint开发公司分析比较及推荐
    北京工作流软件公司分析比较和推荐
    国内市场主流专业的工作流(bpm)软件分析、比较及推荐
    Hibernate的多对多实例
  • 原文地址:https://www.cnblogs.com/bclshuai/p/12796490.html
Copyright © 2011-2022 走看看