因?yàn)轫?xiàng)目需要,需要將游戲手機(jī)助手中的朋友圈給移植到PC游戲中,而以前游戲中的內(nèi)嵌瀏覽器采用的是IE6內(nèi)核,滿足不了我們的需求,于是決定把Cef3內(nèi)嵌到游戲中,在完成正常工作之余,利用閑散時(shí)間不斷地查找各種資料,初步完成了項(xiàng)目需求,決定寫(xiě)一篇文章來(lái)記錄我碰到的各種坑。 一開(kāi)始我只是在網(wǎng)上找了一個(gè)最后支持XP系統(tǒng)的版本–2623版本,利用這個(gè)版本進(jìn)行開(kāi)發(fā),后來(lái)發(fā)現(xiàn)不支持MP3、MP4,是需要重新編譯一個(gè)支持MP3、MP4的版本的,在網(wǎng)上找一個(gè)已編譯好了的版本(在Windows下編譯Cef3.2623并加入mp3、mp4支持(附帶源碼包和最終DLL)),最后把一些dll、資源等替換下就行,并不需要更改工程代碼,非常感謝Redrain!附上鏈接:http://blog.csdn.net/zhuhongshu/article/details/54193842 一、首先來(lái)了解下Cef3CEF全稱Chromium Embedded Framework,是一個(gè)基于Google Chromium 的開(kāi)源項(xiàng)目。CEF的典型應(yīng)用場(chǎng)景包括: 嵌入一個(gè)兼容HTML5的瀏覽器控件到一個(gè)已經(jīng)存在的本地應(yīng)用。 · 創(chuàng)建一個(gè)輕量化的殼瀏覽器,用以托管主要用Web技術(shù)開(kāi)發(fā)的應(yīng)用。 · 有些應(yīng)用有獨(dú)立的繪制框架,使用CEF對(duì)Web內(nèi)容做離線渲染。 · 使用CEF做自動(dòng)化Web測(cè)試。 CEF3是基于Chomuim Content API多進(jìn)程構(gòu)架的下一代CEF,擁有下列優(yōu)勢(shì): · 改進(jìn)的性能和穩(wěn)定性(JavaScript和插件在一個(gè)獨(dú)立的進(jìn)程內(nèi)執(zhí)行)。 · 支持Retina顯示器。 · 支持WebGL和3D CSS的GPU加速。 · 類似WebRTC和語(yǔ)音輸入這樣的前衛(wèi)特性。 · 通過(guò)DevTools遠(yuǎn)程調(diào)試協(xié)議以及ChromeDriver2提供更好的自動(dòng)化UI測(cè)試。 · 更快獲得當(dāng)前以及未來(lái)的Web特性和標(biāo)準(zhǔn)的能力。 翻譯自https:///chromiumembedded/cef/wiki/GeneralUsage.md 看不懂英文的可以看這篇GeneralUsage翻譯文:https://github.com/fanfeilong/cefutil/blob/master/doc/CEF General Usage-zh-cn.md#important-concepts 二、二進(jìn)制文件及資源文件說(shuō)明
有些是根據(jù)情況可刪減的,cef可以繼續(xù)運(yùn)行,或缺失部分功能:
三、引入到工程中因?yàn)槭莾?nèi)嵌在我們自己的項(xiàng)目中,所以只需要給工程中引入cef3,將一些dll等資源文件加入到工程exe所在目錄下,在我們自己的第三方庫(kù)文件夾中加入了cef3文件夾,里面加入cef的include文件夾,和lib文件夾,lib文件夾里分別放入的是debug版本和release版本的libcef.lib文件和libcef_dll_wrapper.lib文件。
四、Cef基礎(chǔ)概念1、多進(jìn)程架構(gòu) #define REQUIRE_UI_THREAD() ASSERT(CefCurrentlyOn(TID_UI)); #define REQUIRE_IO_THREAD() ASSERT(CefCurrentlyOn(TID_IO)); #define REQUIRE_FILE_THREAD() ASSERT(CefCurrentlyOn(TID_FILE)); 3、字符串 std::string str = “Some UTF8 string”; // Equivalent ways of assigning |str| to |cef_str|. Conversion from UTF8 will occur if necessary. CefString cef_str(str); cef_str = str; cef_str.FromString(str); // Equivalent ways of assigning |cef_str| to |str|. Conversion to UTF8 will occur if necessary. str = cef_str; str = cef_str.ToString(); 和std::wstring的相互轉(zhuǎn)換: // Equivalent ways of assigning |str| to |cef_str|. Conversion from wide will occur if necessary. CefString cef_str(str); cef_str = str; cef_str.FromWString(str); // Equivalent ways of assigning |cef_str| to |str|. Conversion to wide will occur if necessary. str = cef_str; str = cef_str.ToWString(); 4、入口函數(shù) CefMainArgs main_args(hInstance); 5、單一執(zhí)行體 int main(int argc, char* argv[]) { // Structure for passing command-line arguments. // The definition of this structure is platform-specific. CefMainArgs main_args(argc, argv); // Optional implementation of the CefApp interface. CefRefPtr<SimpleApp> app(new SimpleApp); // Execute the sub-process logic, if any. This will either return immediately for the browser // process or block until the sub-process should exit. int exit_code = CefExecuteProcess(main_args, app.get()); if (exit_code >= 0) { // The sub-process terminated, exit now. return exit_code; } // Populate this structure to customize CEF behavior. CefSettings settings; // Initialize CEF in the main process. CefInitialize(main_args, settings, app.get()); // Run the CEF message loop. This will block until CefQuitMessageLoop() is called. CefRunMessageLoop(); // Shut down CEF. CefShutdown(); return 0; } 6、分離子進(jìn)程執(zhí)行體 主程序的入口函數(shù): // Program entry-point function. // 程序入口函數(shù) int main(int argc, char* argv[]) { // Structure for passing command-line arguments. // The definition of this structure is platform-specific. // 傳遞命令行參數(shù)的結(jié)構(gòu)體。 // 這個(gè)結(jié)構(gòu)體的定義與平臺(tái)相關(guān)。 CefMainArgs main_args(argc, argv); // Optional implementation of the CefApp interface. // 可選擇性地實(shí)現(xiàn)CefApp接口 CefRefPtr<SimpleApp> app(new SimpleApp); // Populate this structure to customize CEF behavior. // 填充這個(gè)結(jié)構(gòu)體,用于定制CEF的行為。 CefSettings settings; // Specify the path for the sub-process executable. // 指定子進(jìn)程的執(zhí)行路徑 CefString(&settings.browser_subprocess_path).FromASCII(“/path/to/subprocess”); // Initialize CEF in the main process. // 在主進(jìn)程中初始化CEF CefInitialize(main_args, settings, app.get()); // Run the CEF message loop. This will block until CefQuitMessageLoop() is called. // 執(zhí)行消息循環(huán),此時(shí)會(huì)堵塞,直到CefQuitMessageLoop()函數(shù)被調(diào)用。 CefRunMessageLoop(); // Shut down CEF. // 關(guān)閉CEF CefShutdown(); return 0; } 子進(jìn)程程序的入口函數(shù): // Program entry-point function. // 程序入口函數(shù) int main(int argc, char* argv[]) { // Structure for passing command-line arguments. // The definition of this structure is platform-specific. // 傳遞命令行參數(shù)的結(jié)構(gòu)體。 // 這個(gè)結(jié)構(gòu)體的定義與平臺(tái)相關(guān)。 CefMainArgs main_args(argc, argv); // Optional implementation of the CefApp interface. // 可選擇性地實(shí)現(xiàn)CefApp接口 CefRefPtr<SimpleApp> app(new SimpleApp); // Execute the sub-process logic. This will block until the sub-process should exit. // 執(zhí)行子進(jìn)程邏輯,此時(shí)會(huì)堵塞直到子進(jìn)程退出。 return CefExecuteProcess(main_args, app.get()); } 7、CefSettings 8、CefApp 9、CefClient 到這你差不多就知道cef3是怎么一回事了。我們可以上代碼了 五、上代碼先說(shuō)兩點(diǎn): // 初始化函數(shù): void GameAppation::InitializeCef() { // Enable High-DPI support on Windows 7 or newer. CefEnableHighDPISupport(); void* sandbox_info = NULL; #if defined(CEF_USE_SANDBOX) // Manage the life span of the sandbox information object. This is necessary // for sandbox support on Windows. See cef_sandbox_win.h for complete details. CefScopedSandboxInfo scoped_sandbox; sandbox_info = scoped_sandbox.sandbox_info(); #endif // Provide CEF with command-line arguments. CefMainArgs main_args(hInstance); // hInstance是游戲窗口的實(shí)例句柄(HINSTANCE) // Parse command-line arguments. CefRefPtr<CefCommandLine> command_line = CefCommandLine::CreateCommandLine(); command_line->InitFromString(::GetCommandLineW()); // Create a ClientApp of the correct type. CefRefPtr<CefApp> app; // The command-line flag won't be specified for the browser process. if (!command_line->HasSwitch("type")) { app = new SimpleApp(); } else { const std::string& processType = command_line->GetSwitchValue("type"); if (processType == "renderer") { app = new SimpleApp(); } else { // app = new SimpleOtherApp(); } } // CEF applications have multiple sub-processes (render, plugin, GPU, etc) // that share the same executable. This function checks the command-line and, // if this is a sub-process, executes the appropriate logic. int exit_code = CefExecuteProcess(main_args, NULL, sandbox_info); if (exit_code >= 0) { // The sub-process has completed so return here. return exit_code; } // Specify CEF global settings here. CefSettings settings; #if !defined(CEF_USE_SANDBOX) settings.no_sandbox = true; #endif // 在這設(shè)置用于啟動(dòng)子進(jìn)程單獨(dú)執(zhí)行器的路徑 WCHAR subProcessPath[260] = { 0 }; GetModuleFileNameW(hInstance, subProcessPath, 260); *(wcsrchr(subProcessPath, L'\\') + 1) = L'\0'; LPCWSTR SUB_PROCESS_NAME = L"zt2asHelp.exe"; wcsncat_s(subProcessPath, 260, SUB_PROCESS_NAME, wcslen(SUB_PROCESS_NAME)); cef_string_from_wide(subProcessPath, 260, &settings.browser_subprocess_path); // SimpleApp implements application-level callbacks for the browser process. // It will create the first browser instance in OnContextInitialized() after // CEF has initialized. //CefRefPtr<SimpleApp> app(new SimpleApp); // Initialize CEF. CefInitialize(main_args, settings, app.get(), sandbox_info); } // 關(guān)閉函數(shù) void GameAppation::UnInitializeCef() { CefShutdown(); } 將cefsimple工程中的simple_app.cc、simple_handle.cc、simle_handle_win.cc及simple_app.h、simple_handle.h添加進(jìn)游戲工程中。并添加兩個(gè)文件simple_v8_handler.cc、simple_v8_handler.h。在分離子進(jìn)程執(zhí)行體的工程里新加一個(gè)文件zt2asHelp.cpp,并將上面幾個(gè)文件添加進(jìn)工程。 simple_app.h // Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. #ifndef CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_ #define CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_ #include "include/cef_app.h" // Implement application-level callbacks for the browser process. class SimpleApp : public CefApp, public CefBrowserProcessHandler, public CefRenderProcessHandler { public: SimpleApp(); // CefApp methods: virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() OVERRIDE { return this; } virtual CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() OVERRIDE { return this; } virtual void OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) OVERRIDE; virtual void OnWebKitInitialized() OVERRIDE; // CefBrowserProcessHandler methods: virtual void OnContextInitialized() OVERRIDE; virtual bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefProcessId source_process, CefRefPtr<CefProcessMessage> message) OVERRIDE; private: CefRefPtr<SimpleV8JsHandler> m_MyJShander = nullptr; // Include the default reference counting implementation. IMPLEMENT_REFCOUNTING(SimpleApp); }; #endif // CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_ simple_app.cc // Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. #include "simple_app.h" #include "Simple_V8_JS_Handler.h" #include <tchar.h> #include <string> #include "simple_handler.h" #include "include/cef_browser.h" #include "include/cef_command_line.h" #include "include/wrapper/cef_helpers.h" SimpleApp::SimpleApp() { } void SimpleApp::OnContextInitialized() { // 這塊的內(nèi)容由游戲里去創(chuàng)建 } void SimpleApp::OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) { // The var type can accept all object or variable CefRefPtr<CefV8Value> window = context->GetGlobal(); if (!m_MyJShander) { m_MyJShander = new SimpleV8JsHandler(); } CefRefPtr<CefV8Value> strValue = CefV8Value::CreateString(""); window->SetValue("token", strValue, V8_PROPERTY_ATTRIBUTE_NONE); CefRefPtr<CefV8Value> strValue1 = CefV8Value::CreateUInt(0); window->SetValue("accid", strValue, V8_PROPERTY_ATTRIBUTE_NONE); CefRefPtr<CefV8Value> myFunc = CefV8Value::CreateFunction(_T("youjin"), m_MyJShander); window->SetValue(_T("youjin"), myFunc, V8_PROPERTY_ATTRIBUTE_NONE); CefRefPtr<CefV8Value> myFunc2 = CefV8Value::CreateFunction(_T("mimang"), m_MyJShander); window->SetValue(_T("mimang"), myFunc2, V8_PROPERTY_ATTRIBUTE_NONE); CefRefPtr<CefV8Value> myFunc3 = CefV8Value::CreateFunction(_T("dejin"), m_MyJShander); window->SetValue(_T("dejin"), myFunc3, V8_PROPERTY_ATTRIBUTE_NONE); CefRefPtr<CefV8Value> myFunc4 = CefV8Value::CreateFunction(_T("mubiao"), m_MyJShander); window->SetValue(_T("mubiao"), myFunc4, V8_PROPERTY_ATTRIBUTE_NONE); } void SimpleApp::OnWebKitInitialized() { std::string extensionCode = "var g_value=\"global value here\";" "var zt2as;" "if (!zt2as)" " zt2as = {};" "(function() {" " zt2as.youjin = function() {" " native function youjin();" " return youjin();" " };" "})();" "(function() {" " zt2as.mimang = function() {" " native function mimang();" " return mimang();" " };" "})();" "(function() {" " zt2as.dejin = function() {" " native function dejin();" " return dejin();" " };" "})();" "(function() {" " zt2as.mubiao = function() {" " native function mubiao();" " return mubiao();" " };" "})();"; // 聲明本地函數(shù) native function hehe();" 如果有參數(shù)列表需要寫(xiě)具體的類型,而不能寫(xiě)var類型!與本地聲明一直 // 調(diào)用本地函數(shù) return hehe();" // Create an instance of my CefV8Handler object. CefRefPtr<CefV8Handler> handler = new SimpleV8JsHandler(); // Register the extension. CefRegisterExtension("v8/mycode", extensionCode, handler); } bool SimpleApp::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefProcessId source_process, CefRefPtr<CefProcessMessage> message) { const std::string& messageName = message->GetName(); if (messageName == "func_back") { CefRefPtr<CefListValue> argList = message->GetArgumentList(); std::string token_ = argList->GetString(0); uint32_t accid_ = argList->GetInt(1); CefRefPtr<CefV8Value> strValue = CefV8Value::CreateString(token_); browser->GetMainFrame()->GetV8Context()->GetGlobal()->SetValue("token", strValue, V8_PROPERTY_ATTRIBUTE_NONE); CefRefPtr<CefV8Value> strValue1 = CefV8Value::CreateUInt(accid_); browser->GetMainFrame()->GetV8Context()->GetGlobal()->SetValue("accid", strValue1, V8_PROPERTY_ATTRIBUTE_NONE); return true; } return false; } simple_handle.h // Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. #ifndef CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_ #define CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_ #include "include/cef_client.h" #include <list> class SimpleHandler : public CefClient, public CefDisplayHandler, public CefLifeSpanHandler, public CefLoadHandler, public CefContextMenuHandler, public CefJSDialogHandler { public: SimpleHandler(); ~SimpleHandler(); enum MY_MENU { MENU_ID_USER_OPENLINK = MENU_ID_USER_FIRST + 200, MENU_ID_USER_SHOWDEVTOOLS, }; // Provide access to the single global instance of this object. static SimpleHandler* GetInstance(); // CefClient methods: virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() OVERRIDE { return this; } virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() OVERRIDE { return this; } virtual CefRefPtr<CefLoadHandler> GetLoadHandler() OVERRIDE { return this; } virtual CefRefPtr<CefContextMenuHandler> GetContextMenuHandler() OVERRIDE { return this; } virtual CefRefPtr<CefJSDialogHandler> GetJSDialogHandler() OVERRIDE { return this; } // CefDisplayHandler methods: virtual void OnTitleChange(CefRefPtr<CefBrowser> browser, const CefString& title) OVERRIDE; // CefLifeSpanHandler methods: virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE; virtual bool DoClose(CefRefPtr<CefBrowser> browser) OVERRIDE; virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE; // CefLoadHandler methods: virtual void OnLoadError(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, ErrorCode errorCode, const CefString& errorText, const CefString& failedUrl) OVERRIDE; virtual void OnBeforeContextMenu(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefContextMenuParams> params, CefRefPtr<CefMenuModel> model) OVERRIDE; virtual bool OnContextMenuCommand(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefContextMenuParams> params, int command_id, EventFlags event_flags) OVERRIDE; virtual bool OnJSDialog(CefRefPtr<CefBrowser> browser, const CefString& origin_url, const CefString& accept_lang, JSDialogType dialog_type, const CefString& message_text, const CefString& default_prompt_text, CefRefPtr<CefJSDialogCallback> callback, bool& suppress_message) OVERRIDE; // Request that all existing browser windows close. void CloseAllBrowsers(bool force_close); bool IsClosing() const { return is_closing_; } virtual bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefProcessId source_process, CefRefPtr<CefProcessMessage> message) OVERRIDE; void SetToken(std::string str) { token_ = str; } std::string GetToken() { return token_; } void SetAccid(uint32_t accid) { accid_ = accid; } uint32_t GetAccid() { return accid_; } CefRefPtr<CefBrowser> GetBrowser() { return browser_; } void ShowDevelopTools(CefRefPtr<CefBrowser> browser); HWND GetGameHwnd() { return gameHwnd; } void SetGameHwnd(HWND h) { gameHwnd = h; } private: // List of existing browser windows. Only accessed on the CEF UI thread. typedef std::list<CefRefPtr<CefBrowser> > BrowserList; BrowserList browser_list_; bool is_closing_; CefRefPtr<CefBrowser> browser_ = nullptr; std::string token_ = ""; uint32_t accid_ = 0; HWND gameHwnd = NULL; // Include the default reference counting implementation. IMPLEMENT_REFCOUNTING(SimpleHandler); }; #endif // CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_ simple_handle.cc // Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. #include "simple_handler.h" #include <sstream> #include <string> #include "include/base/cef_bind.h" #include "include/cef_app.h" #include "include/wrapper/cef_closure_task.h" #include "include/wrapper/cef_helpers.h" #include <fstream> #include <Windows.h> #include <tchar.h> namespace { SimpleHandler* g_instance = NULL; } // namespace SimpleHandler::SimpleHandler() : is_closing_(false) { DCHECK(!g_instance); g_instance = this; } SimpleHandler::~SimpleHandler() { g_instance = NULL; } // static SimpleHandler* SimpleHandler::GetInstance() { return g_instance; } void SimpleHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) { CEF_REQUIRE_UI_THREAD(); // Add to the list of existing browsers. browser_list_.push_back(browser); browser_ = browser; } bool SimpleHandler::DoClose(CefRefPtr<CefBrowser> browser) { CEF_REQUIRE_UI_THREAD(); // Closing the main window requires special handling. See the DoClose() // documentation in the CEF header for a detailed destription of this // process. if (browser_list_.size() == 1) { // Set a flag to indicate that the window close should be allowed. is_closing_ = true; } // Allow the close. For windowed browsers this will result in the OS close // event being sent. return false; } void SimpleHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) { CEF_REQUIRE_UI_THREAD(); // Remove from the list of existing browsers. BrowserList::iterator bit = browser_list_.begin(); for (; bit != browser_list_.end(); ++bit) { if ((*bit)->IsSame(browser)) { browser_list_.erase(bit); break; } } if (browser_list_.empty()) { // All browser windows have closed. Quit the application message loop. CefQuitMessageLoop(); } } void SimpleHandler::OnLoadError(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, ErrorCode errorCode, const CefString& errorText, const CefString& failedUrl) { CEF_REQUIRE_UI_THREAD(); // Don't display an error for downloaded files. if (errorCode == ERR_ABORTED) return; // Display a load error message. std::stringstream ss; ss << "<html><body bgcolor=\"white\">" "<h2>Failed to load URL " << std::string(failedUrl) << " with error " << std::string(errorText) << " (" << errorCode << ").</h2></body></html>"; frame->LoadString(ss.str(), failedUrl); } void SimpleHandler::CloseAllBrowsers(bool force_close) { if (!CefCurrentlyOn(TID_UI)) { // Execute on the UI thread. CefPostTask(TID_UI, base::Bind(&SimpleHandler::CloseAllBrowsers, this, force_close)); return; } if (browser_list_.empty()) return; BrowserList::const_iterator it = browser_list_.begin(); for (; it != browser_list_.end(); ++it) (*it)->GetHost()->CloseBrowser(force_close); } bool SimpleHandler::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefProcessId source_process, CefRefPtr<CefProcessMessage> message) { const std::string& messageName = message->GetName(); if (messageName == "msg_from_render") { CefRefPtr<CefListValue> argList = message->GetArgumentList(); CefRefPtr<CefProcessMessage> msg_back = CefProcessMessage::Create("func_back"); msg_back->GetArgumentList()->SetString(0, token_); msg_back->GetArgumentList()->SetInt(1, accid_); browser->SendProcessMessage(PID_RENDERER, msg_back); return true; } return false; } void SimpleHandler::OnBeforeContextMenu(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefContextMenuParams> params, CefRefPtr<CefMenuModel> model) { //model->Clear(); // 禁止菜單只需這一句 model->Remove(MENU_ID_PRINT); model->Remove(MENU_ID_VIEW_SOURCE); if ((params->GetTypeFlags() & (CM_TYPEFLAG_PAGE | CM_TYPEFLAG_FRAME)) != 0) { if (model->GetCount() > 0) { model->RemoveAt(2); model->Remove(MENU_ID_BACK); model->Remove(MENU_ID_FORWARD); model->AddItem(MENU_ID_USER_SHOWDEVTOOLS,"developerTools"); } } } bool SimpleHandler::OnContextMenuCommand(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefContextMenuParams> params, int command_id, EventFlags event_flags) { switch (command_id) { case MENU_ID_USER_SHOWDEVTOOLS: { ShowDevelopTools(browser); return true; } break; } return false; } void SimpleHandler::ShowDevelopTools(CefRefPtr<CefBrowser> browser) { CefWindowInfo windowinfo; CefBrowserSettings settings; windowinfo.SetAsPopup(NULL, "DevTools"); browser->GetHost()->ShowDevTools(windowinfo, this, settings, CefPoint()); } bool SimpleHandler::OnJSDialog(CefRefPtr<CefBrowser> browser, const CefString& origin_url, const CefString& accept_lang, JSDialogType dialog_type, const CefString& message_text, const CefString& default_prompt_text, CefRefPtr<CefJSDialogCallback> callback, bool& suppress_message) { CEF_REQUIRE_UI_THREAD(); std::wstring msg = message_text.ToWString(); if (dialog_type == JSDIALOGTYPE_ALERT) { ::MessageBoxW(gameHwnd, (LPCWSTR)msg.c_str(), L"提示", MB_OK | MB_TOPMOST); suppress_message = true; return false; } else if(dialog_type == JSDIALOGTYPE_CONFIRM) { int a = ::MessageBoxW(gameHwnd, (LPCWSTR)msg.c_str(), L"提示", MB_OKCANCEL | MB_TOPMOST); if (a == IDOK) { callback->Continue(true, ""); } else { callback->Continue(false, ""); } suppress_message = false; return true; } return false; } simple_v8_handler.h #pragma once #include <include/cef_v8.h> class SimpleV8JsHandler : public CefV8Handler { public: SimpleV8JsHandler(void); virtual ~SimpleV8JsHandler(void); public: virtual bool Execute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception) OVERRIDE; IMPLEMENT_REFCOUNTING(SimpleV8JsHandler); }; simple_v8_handler.cc #include "Simple_V8_JS_Handler.h" #include <tchar.h> SimpleV8JsHandler::SimpleV8JsHandler(void) { } SimpleV8JsHandler::~SimpleV8JsHandler(void) { } bool SimpleV8JsHandler::Execute(const CefString& func_name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception) { if (func_name == _T("youjin")) { if (arguments.size() == 0) { CefRefPtr<CefFrame> frame = CefV8Context::GetCurrentContext()->GetBrowser()->GetMainFrame(); retval = frame->GetV8Context()->GetGlobal()->GetValue("token"); } return true; } else if (func_name == _T("mimang")) { if (arguments.size() == 0) { CefRefPtr<CefFrame> frame = CefV8Context::GetCurrentContext()->GetBrowser()->GetMainFrame(); retval = frame->GetV8Context()->GetGlobal()->GetValue("accid"); } return true; } else if (func_name == _T("dejin")) { retval = CefV8Value::CreateString("To Hit My Stride"); return true; } else if (func_name == _T("mubiao")) { CefRefPtr<CefProcessMessage> msg = CefProcessMessage::Create("msg_from_render"); CefRefPtr<CefListValue> args = msg->GetArgumentList(); args->SetString(0, name); CefV8Context::GetCurrentContext()->GetBrowser()->SendProcessMessage(PID_BROWSER, msg); } return false; } zh2asHelp.cpp #include "include/cef_app.h" #include "include/internal/cef_win.h" #include <windows.h> #include "simple_app.h" #include "include/cef_base.h" int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { CefMainArgs main_args(hInstance); CefRefPtr<SimpleApp> app(new SimpleApp); return CefExecuteProcess(main_args, app.get(), NULL); } 至此,幾乎所有的核心代碼都準(zhǔn)備好了,除了在游戲里創(chuàng)建我們的瀏覽器。 六、坑因?yàn)槲覀働C游戲只創(chuàng)建一個(gè)windows窗口,游戲里面的dialog都是模擬出來(lái)的,并非windows窗口。要把cef直接顯示游戲里,并且是可以拖動(dòng)位置,我的做法是在游戲里面創(chuàng)建一個(gè)新的windows子窗口,同時(shí)在游戲里創(chuàng)建一個(gè)游戲窗口,把windows子窗口的位置綁定到新建的游戲窗口上,當(dāng)拖動(dòng)游戲窗口時(shí),同時(shí)也移動(dòng)windows子窗口,然后再把cef的瀏覽器內(nèi)容顯示在windows子窗口上。 七、還有很多坑像游戲里的焦點(diǎn)問(wèn)題,鍵盤(pán)事件問(wèn)題等等。 <!DOCTYPE HTML> <html> <head> <meta charset="utf-8" /> <script type="text/javascript" > function youjin() { alert(zt2as.getToken()); } function mimang() { alert(zt2as.getAccId()); } function dejin() { alert(zt2as.getDevice()); } function mubiao() { alert(zt2as.initData()); alert(zt2as.getAccId()); alert(zt2as.getToken()); } </script> </head> <body style="width:100%;height:100%;background-color:white;"> <p>回望2018 奔向2019</p> <div > <button onclick="youjin();">getToken</button> <button onclick="mimang();">getAccId</button> <button onclick="dejin();">getDevice</button> <button onclick="mubiao();">initData</button> </div> </body> </html> |
|