标签:
最近在学习CEF,发现自己的编程能力实在太弱,看不懂应该怎么使用这个库,也不知道可以向谁请教,尽管官方说提供的cefclient示例程序已经很清楚了啊,但是我看不懂啊,自己一个人慢慢磨真的十分痛苦。最近结合网上的资料,学习了一些些吧,写下这篇日志,希望可以帮到后来的人(不过后来的人应该不会像我这么弱了的吧)。
这是一个将CEF嵌入MFC对话框的程序,说来惭愧,到现在我都还不会怎么写一个好看的界面,只会在MFC上堆砌各种控件,唉。
这篇日志主要参考了以下资料:
再说一件惭愧的事情,下面说的程序也只是结合了上面的资料堆砌而成,一些API为什么要这么用,我也不清楚(好希望有人可以带我装逼带我飞)。
预备工作:在http://www.magpcss.net/cef_downloads/中下载Windows版本的CEF3库,本文下载的是cef_binary_3.2171.1979_windows32.7z。
下面正式开始。
首先建立一个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_wrapper以Debug生成方案(默认就是)编译生成一次。生成后,在目录里会多出来一个out目录,里面是生成的文件。
下面将编译项目需要的CEF3头文件和库拷贝到我们的项目文件夹中。
将cef_binary_3.2171.1979_windows32/include文件夹拷贝到项目代码目录/CEF3中;
将cef_binary_3.2171.1979_windows32/out/Debug中的lib目录拷贝到项目代码目录/CEF3中;
将cef_binary_3.2171.1979_windows32/Debug/libcef.lib拷贝到项目代码目录/CEF3/lib中(按理说libcef.lib也是应该可以用官方提供的CEF3项目文件重新生成一个的,但我还没有找到方法,这里只好拷贝官方生成好的了)。
将CEF3目录添加到项目的附加包含目录中,将CEF3/lib/Debug目录添加到项目的附加库目录中。附加依赖项中添加libcef.lib和libcef_dll_wrapper.lib。
根据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) );*/ }
在cefinmfcdialogDlg.cpp中包含头文件ClientApp.h和ClientHandler.h。
在类CcefinmfcdialogDlg的CcefinmfcdialogDlg::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的设置时Windows的CEF3库中特有的,设置后会使CEF新建一个线程执行消息循环。std:string site变量用于指定程序运行时要打开的网页。
给类CcefinmfcdialogDlg添加ON_DESTORY消息的处理函数,在处理函数中添加如下代码:
CefShutdown();
之后执行生成,应该可以无错生成程序的。
再次进入cef_binary_3.2171.1979_windows32目录,将Resources目录下的所有内容(不清楚有什么用)以及Debug目录下的libcef.dll和pdf.dll(是的,不知道为什么也要这个dll,从名字看这个dll应该和pdf文件浏览相关吧,如果不拷贝过去,程序会浏览不了网页,而且也会在程序所在文件夹中创建一个叫pdf.dll的目录)拷贝到项目目录的Debug文件夹中(就是程序生成所在的文件夹)。之后可以调试和运行了:
在VS中调试程序的话,会在关闭程序后,会连续提示好几个中断,原因还不明白。
当然还有对CEF还不熟悉啊,心塞。
标签:
原文地址:http://www.cnblogs.com/wlreg/p/4595248.html