码迷,mamicode.com
首页 > 编程语言 > 详细

201506022 CEF嵌入MFC对话框程序

时间:2015-06-23 19:42:37      阅读:420      评论:0      收藏:0      [点我收藏+]

标签:

        最近在学习CEF,发现自己的编程能力实在太弱,看不懂应该怎么使用这个库,也不知道可以向谁请教,尽管官方说提供的cefclient示例程序已经很清楚了啊,但是我看不懂啊,自己一个人慢慢磨真的十分痛苦。最近结合网上的资料,学习了一些些吧,写下这篇日志,希望可以帮到后来的人(不过后来的人应该不会像我这么弱了的吧)。

        这是一个将CEF嵌入MFC对话框的程序,说来惭愧,到现在我都还不会怎么写一个好看的界面,只会在MFC上堆砌各种控件,唉。

        这篇日志主要参考了以下资料:

  • https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage.md(这里面的资料貌似也很完善,但我还没有看完,主要是里面很多语句不理解,感觉是在给编程已经上道的人写的,看得心塞)
  • http://mickeymickstechblog.blogspot.com/2014/08/how-to-use-webkit-cef-in-mfc-project.html
  • https://github.com/acristoffers/CEF3SimpleSample

        再说一件惭愧的事情,下面说的程序也只是结合了上面的资料堆砌而成,一些API为什么要这么用,我也不清楚(好希望有人可以带我装逼带我飞)。

 

    预备工作:在http://www.magpcss.net/cef_downloads/中下载Windows版本的CEF3库,本文下载的是cef_binary_3.2171.1979_windows32.7z

        下面正式开始。

1. 项目建立和配置

        首先建立一个MFC基于对话框程序。注意要选上“在静态库中使用MFC”。如果不慎没选,可以在“项目属性->配置属性->常规->MFC的使用”重新配置(这时可能还需要手动将“项目属性->配置属性->C/C++->代码生成->运行库”配置为“多线程调试(/MTd)”)。

        在项目文件夹的代码文件夹里(这里就是cefinmfcdialog/cefinmfcdialog中)建立一个CEF3文件夹,将项目要用到的和CEF3相关的头文件和库放在这个目录中。

 

        解压cef_binary_3.2171.1979_windows32.7z,进入到解压后的目录(这里假设解压到了cef_binary_3.2171.1979_windows32),打开cefclient2010.sln,将其中的项目libcef_dll_wrapperDebug生成方案(默认就是)编译生成一次。生成后,在目录里会多出来一个out目录,里面是生成的文件。

   

        下面将编译项目需要的CEF3头文件和库拷贝到我们的项目文件夹中。

  1. cef_binary_3.2171.1979_windows32/include文件夹拷贝到项目代码目录/CEF3中;

  2. cef_binary_3.2171.1979_windows32/out/Debug中的lib目录拷贝到项目代码目录/CEF3中;

  3. cef_binary_3.2171.1979_windows32/Debug/libcef.lib拷贝到项目代码目录/CEF3/lib中(按理说libcef.lib也是应该可以用官方提供的CEF3项目文件重新生成一个的,但我还没有找到方法,这里只好拷贝官方生成好的了)。

 

 

        将CEF3目录添加到项目的附加包含目录中,将CEF3/lib/Debug目录添加到项目的附加库目录中。附加依赖项中添加libcef.liblibcef_dll_wrapper.lib

2. 创建新的类

   

    根据https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage.md#markdown-header-application-structure的描述,CEF3的程序的一般结构包括以下部分:

  • 初始化CEF,并且运行子进程可执行逻辑(sub-process executable logic,不知道具体是什么鬼,大概就是自己做一个子进程来自己管理消息循环的意思?)或者CEF消息循环;

  • 提供一个CefApp的实现用来处理进程相关的回调(什么鬼!);

  • 提供一个CefClient的实现用来处理浏览器实例相关的回调(什么鬼!);

  • 调用CefBrowserHost::CreateBrowser()来创建浏览器实例,以及使用CefLifeSpanHandler管理浏览器的生命周期(什么鬼!)。

   

    下面是创建新的类,代码都是照搬https://github.com/acristoffers/CEF3SimpleSample中的了。基本上我找不到文档指导怎么继承CEF3的类来创建自己要求的类的,自己又找不到方法,唉。

    创建一个类ClientV8ExtensionHandler,继承类CefV8Handler

    ClientV8ExtensionHandler.h

    /************************************************************************************************ 
    *   Copyright (c) 2013 Álan Crístoffer 
    * 
    *   Permission is hereby granted, free of charge, to any person obtaining a copy 
    *   of this software and associated documentation files (the "Software"), to deal 
    *   in the Software without restriction, including without limitation the rights 
    *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
    *   of the Software, and to permit persons to whom the Software is furnished to do so, 
    *   subject to the following conditions: 
    * 
    *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
    *   INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
    *   PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
    *   FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
    *   OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
    *   DEALINGS IN THE SOFTWARE. 
    ************************************************************************************************/  
      
    #ifndef __CEF3SimpleSample__ClientV8ExtensionHandler__  
    #define __CEF3SimpleSample__ClientV8ExtensionHandler__  
      
    #include "include/cef_app.h"  
      
    struct ClientV8ExtensionHandler : public CefV8Handler {  
        ClientV8ExtensionHandler(CefRefPtr<CefApp> app);  
      
        bool Execute(const CefString &name, CefRefPtr<CefV8Value> object, const CefV8ValueList &arguments, CefRefPtr<CefV8Value> &retval, CefString &exception) OVERRIDE;  
      
    private:  
        CefRefPtr<CefApp> app;  
      
        IMPLEMENT_REFCOUNTING(ClientV8ExtensionHandler);  
    };  
      
    #endif /* defined(__CEF3SimpleSample__ClientV8ExtensionHandler__) */  

     ClientV8ExtensionHandler.cpp:

    /************************************************************************************************ 
    *   Copyright (c) 2013 Álan Crístoffer 
    * 
    *   Permission is hereby granted, free of charge, to any person obtaining a copy 
    *   of this software and associated documentation files (the "Software"), to deal 
    *   in the Software without restriction, including without limitation the rights 
    *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
    *   of the Software, and to permit persons to whom the Software is furnished to do so, 
    *   subject to the following conditions: 
    * 
    *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
    *   INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
    *   PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
    *   FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
    *   OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
    *   DEALINGS IN THE SOFTWARE. 
    ************************************************************************************************/  
    #include "stdafx.h"  
    #include "ClientV8ExtensionHandler.h"  
      
    ClientV8ExtensionHandler::ClientV8ExtensionHandler(CefRefPtr<CefApp> app)  
    {  
        this->app = app;  
    }  
      
    bool ClientV8ExtensionHandler::Execute(const CefString &name, CefRefPtr<CefV8Value> object, const CefV8ValueList &arguments, CefRefPtr<CefV8Value> &retval, CefString &exception)  
    {  
        if ( name == "ChangeTextInJS" ) {  
            if ( (arguments.size() == 1) && arguments[0]->IsString() ) {  
                CefString           text   = arguments[0]->GetStringValue();  
                CefRefPtr<CefFrame> frame  = CefV8Context::GetCurrentContext()->GetBrowser()->GetMainFrame();  
                std::string         jscall = "ChangeText(‘";  
                jscall += text;  
                jscall += "‘);";  
                frame->ExecuteJavaScript(jscall, frame->GetURL(), 0);  
                /* 
                 * If you want your method to return a value, just use retval, like this: 
                 * retval = CefV8Value::CreateString("Hello World!"); 
                 * you can use any CefV8Value, what means you can return arrays, objects or whatever you can create with CefV8Value::Create* methods 
                 */  
                return true;  
            }  
        }  
      
        return false;  
    }  

    创建类ClientHandler,继承类CefClient和类CefLifeSpanHandler。这里有几个方法是父类中的抽象方法,必须在实现类中给出实现。

    ClientHandler.h

    /************************************************************************************************ 
    *   Copyright (c) 2013 Álan Crístoffer 
    * 
    *   Permission is hereby granted, free of charge, to any person obtaining a copy 
    *   of this software and associated documentation files (the "Software"), to deal 
    *   in the Software without restriction, including without limitation the rights 
    *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
    *   of the Software, and to permit persons to whom the Software is furnished to do so, 
    *   subject to the following conditions: 
    * 
    *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
    *   INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
    *   PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
    *   FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
    *   OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
    *   DEALINGS IN THE SOFTWARE. 
    ************************************************************************************************/  
      
    #ifndef __CEFSimpleSample__ClientHandler__  
    #define __CEFSimpleSample__ClientHandler__  
      
    #include "include/cef_render_process_handler.h"  
    #include "include/cef_client.h"  
    #include "include/cef_v8.h"  
    #include "include/cef_browser.h"  
      
    class ClientHandler : public CefClient, public CefLifeSpanHandler {  
    public:  
        ClientHandler();  
      
        CefRefPtr<CefBrowser> GetBrowser()  
        {  
            return m_Browser;  
        }  
      
        CefWindowHandle GetBrowserHwnd()  
        {  
            return m_BrowserHwnd;  
        }  
      
        // CefClient methods  
        virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() OVERRIDE  
        {  
            return this;  
        }  
      
        // Virutal on CefLifeSpanHandler  
        virtual bool DoClose(CefRefPtr<CefBrowser> browser) OVERRIDE;  
        virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;  
        virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE;  
      
    protected:  
        // The child browser window  
        CefRefPtr<CefBrowser> m_Browser;  
      
        // The child browser window handle  
        CefWindowHandle m_BrowserHwnd;  
      
        // /  
        // Macro that provides a reference counting implementation for classes extending  
        // CefBase.  
        // /  
        IMPLEMENT_REFCOUNTING(ClientHandler);  
    };  
      
    #endif /* defined(__CEFSimpleSample__ClientHandler__) */  

 

    ClientHandler.cpp

 

    /************************************************************************************************ 
    *   Copyright (c) 2013 Álan Crístoffer 
    * 
    *   Permission is hereby granted, free of charge, to any person obtaining a copy 
    *   of this software and associated documentation files (the "Software"), to deal 
    *   in the Software without restriction, including without limitation the rights 
    *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
    *   of the Software, and to permit persons to whom the Software is furnished to do so, 
    *   subject to the following conditions: 
    * 
    *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
    *   INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
    *   PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
    *   FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
    *   OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
    *   DEALINGS IN THE SOFTWARE. 
    ************************************************************************************************/  
    #include "stdafx.h"  
    #include "ClientHandler.h"  
      
    #include "include/cef_app.h"  
    #include "include/cef_base.h"  
    #include "include/cef_client.h"  
    #include "include/cef_command_line.h"  
    #include "include/cef_frame.h"  
    #include "include/cef_runnable.h"  
    #include "include/cef_web_plugin.h"  
      
    ClientHandler::ClientHandler()  
    {  
    }  
      
    bool ClientHandler::DoClose(CefRefPtr<CefBrowser> browser)  
    {  
        return false;  
    }  
      
    void ClientHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser)  
    {  
        if ( !m_Browser.get() ) {  
            // We need to keep the main child window, but not popup windows  
            m_Browser     = browser;  
            m_BrowserHwnd = browser->GetHost()->GetWindowHandle();  
        }  
    }  
      
    void ClientHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser)  
    {  
        if ( m_BrowserHwnd == browser->GetHost()->GetWindowHandle() ) {  
            // Free the browser pointer so that the browser can be destroyed  
            m_Browser = NULL;  
        }  
    }  

 

    创建类ClientApp,继承类CefApp

    ClientApp.h

 

    /************************************************************************************************  
    *   Copyright (c) 2013 Álan Crístoffer  
    *  
    *   Permission is hereby granted, free of charge, to any person obtaining a copy  
    *   of this software and associated documentation files (the "Software"), to deal  
    *   in the Software without restriction, including without limitation the rights  
    *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies  
    *   of the Software, and to permit persons to whom the Software is furnished to do so,  
    *   subject to the following conditions:  
    *  
    *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,  
    *   INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR  
    *   PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE  
    *   FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR  
    *   OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER  
    *   DEALINGS IN THE SOFTWARE.  
    ************************************************************************************************/  
      
    #ifndef __CEF3SimpleSample__ClientHandler__  
    #define __CEF3SimpleSample__ClientHandler__  
      
    #include "include/cef_app.h"  
    #include "include/cef_client.h"  
      
    class ClientApp : public CefApp, public CefRenderProcessHandler {  
    public:  
        ClientApp();  
      
        CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() OVERRIDE  
        {  
            return this;  
        }  
      
        void OnWebKitInitialized() OVERRIDE;  
      
        IMPLEMENT_REFCOUNTING(ClientApp);  
    };  
      
    #endif /* defined(__CEF3SimpleSample__ClientHandler__) */  

 

    ClientApp.cpp

    /************************************************************************************************ 
    *   Copyright (c) 2013 Álan Crístoffer 
    * 
    *   Permission is hereby granted, free of charge, to any person obtaining a copy 
    *   of this software and associated documentation files (the "Software"), to deal 
    *   in the Software without restriction, including without limitation the rights 
    *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
    *   of the Software, and to permit persons to whom the Software is furnished to do so, 
    *   subject to the following conditions: 
    * 
    *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
    *   INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
    *   PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
    *   FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
    *   OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
    *   DEALINGS IN THE SOFTWARE. 
    ************************************************************************************************/  
    #include "stdafx.h"  
    #include "ClientApp.h"  
      
    #include "ClientHandler.h"  
    #include "ClientV8ExtensionHandler.h"  
      
    ClientApp::ClientApp()  
    {  
    }  
      
    void ClientApp::OnWebKitInitialized()  
    {  
        /*std::string app_code = 
            "var app;" 
            "if (!app)" 
            "    app = {};" 
            "(function() {" 
            "    app.ChangeTextInJS = function(text) {" 
            "        native function ChangeTextInJS();" 
            "        return ChangeTextInJS(text);" 
            "    };" 
            "})();;"; 
     
        CefRegisterExtension( "v8/app", app_code, new ClientV8ExtensionHandler(this) );*/  
    }  

3. 初始化和运行CEF

    在cefinmfcdialogDlg.cpp中包含头文件ClientApp.hClientHandler.h

    在类CcefinmfcdialogDlgCcefinmfcdialogDlg::OnInitDialog()方法中添加如下代码:

 

           CefMainArgs main_args(theApp.m_hInstance);  
      
    CefRefPtr<ClientApp> app(new ClientApp);  
      
    int exit_code = CefExecuteProcess(main_args, app.get(), NULL);  
    if (exit_code >= 0){  
        exit(exit_code);  
    }  
      
    RECT rect;  
    GetDlgItem(IDC_BROWSER)->GetClientRect(&rect);  
      
    CefSettings settings;  
    CefSettingsTraits::init(&settings);  
    settings.multi_threaded_message_loop = true;  
    CefInitialize(main_args, settings, app.get(), NULL);  
      
    CefWindowInfo info;  
    CefBrowserSettings b_settings;  
    CefRefPtr<CefClient> client(new ClientHandler);  
      
    std::string site = "https://docs.python.org/2/c-api/";  
      
    info.SetAsChild(GetDlgItem(IDC_BROWSER)->GetSafeHwnd(), rect);  
    CefBrowserHost::CreateBrowser(info, client.get(), site, b_settings, NULL);  

 

这里要执行CefExecuteProcess函数必须传递一个类CefMainArgs的实例,该实例在Windows中是使用主程序的句柄来初始化的。 CefSettings.multi_threaded_message_loop = true的设置时WindowsCEF3库中特有的,设置后会使CEF新建一个线程执行消息循环。std:string site变量用于指定程序运行时要打开的网页。

        给类CcefinmfcdialogDlg添加ON_DESTORY消息的处理函数,在处理函数中添加如下代码:

 

CefShutdown();  

 

之后执行生成,应该可以无错生成程序的。

4. 拷贝运行依赖的资源

        再次进入cef_binary_3.2171.1979_windows32目录,将Resources目录下的所有内容(不清楚有什么用)以及Debug目录下的libcef.dllpdf.dll(是的,不知道为什么也要这个dll,从名字看这个dll应该和pdf文件浏览相关吧,如果不拷贝过去,程序会浏览不了网页,而且也会在程序所在文件夹中创建一个叫pdf.dll的目录)拷贝到项目目录的Debug文件夹中(就是程序生成所在的文件夹)。之后可以调试和运行了:

 技术分享

5. 还存在的问题

        在VS中调试程序的话,会在关闭程序后,会连续提示好几个中断,原因还不明白。

技术分享

        当然还有对CEF还不熟悉啊,心塞。

201506022 CEF嵌入MFC对话框程序

标签:

原文地址:http://www.cnblogs.com/wlreg/p/4595248.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!