duilib + cef簡單瀏覽器的demo
阿新 • • 發佈:2019-02-08
參考連線:
https://bitbucket.org/chromiumembedded/cef/wiki/Home
自己寫的demo地址:
http://download.csdn.net/detail/shuaixingrumo/9556308
關於編譯duilib的庫和cef庫的步驟不詳細說了, 網上有很多這樣的文章
首先我們要先新增倆個類:
一個是SimpleApp, 用來初始化cef context環境的類, 一個是 SimpleHandler類, 和cef互動主要靠它
simple_handler.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: SimpleHandler(); ~SimpleHandler(); // 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; } // 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; // Request that all existing browser windows close. // void CloseAllBrowsers(bool force_close); bool IsClosing() const { return is_closing_; } CefRefPtr<CefBrowser> GetBrowser(){return m_browser;} private: // List of existing browser windows. Only accessed on the CEF UI thread. /* typedef std::list<CefRefPtr<CefBrowser> > BrowserList; BrowserList browser_list_;*/ CefRefPtr<CefBrowser> m_browser; bool is_closing_; // Include the default reference counting implementation. IMPLEMENT_REFCOUNTING(SimpleHandler); }; #endif // CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_
simple_handler.cpp:
// 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" namespace { SimpleHandler* g_instance = NULL; } // namespace SimpleHandler::SimpleHandler() : is_closing_(false), m_browser(NULL) { 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);*/ m_browser = browser; } bool SimpleHandler::DoClose(CefRefPtr<CefBrowser> browser) { CEF_REQUIRE_UI_THREAD(); if(m_browser) 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(); if(m_browser->IsSame(browser)) m_browser = NULL; } 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); }
SimpleHandler類繼承了CefLifeSpanHandler, 用於管理CefBrowser的生存週期
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" class SimpleApp : public CefApp, public CefBrowserProcessHandler { public: SimpleApp(); // CefApp methods: virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() OVERRIDE { return this; } // CefBrowserProcessHandler methods: virtual void OnContextInitialized() OVERRIDE; private: // Include the default reference counting implementation. IMPLEMENT_REFCOUNTING(SimpleApp); }; #endif // CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_
simple_app.cpp:
// 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 <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() {
}
注意 simple_app的標頭檔案要放在前面, 否則會出現編譯錯誤
添加了這倆個類之後, 我們接下來要做的是初始化cef, 在main函式中新增如下程式碼:
void* sandbox_info = NULL;
CefMainArgs main_args(hInstance);
CefRefPtr<SimpleApp> app(new SimpleApp);
CefSettings settings;
settings.no_sandbox = true;
settings.multi_threaded_message_loop = true;
CefInitialize(main_args, settings, app.get(), sandbox_info);
這裡需要注意的是, CefSettings物件, 我們設定了multi_threaded_message_loop=true, 這樣設定的目的是,使cef 的browser ui執行緒和我們程式的執行緒分離, 我們可以使用duilib的訊息迴圈函式CPaintManagerUI::MessageLoop(), 而不必呼叫cef的CefRunMessageLoop()。
接下來新增我們的duilib程式碼:
CPaintManagerUI::SetInstance(hInstance);
CMainWnd wnd;
wnd.Create(NULL, L"", UI_WNDSTYLE_FRAME | WS_THICKFRAME, WS_EX_ACCEPTFILES);
wnd.ShowWindow();
wnd.CenterWindow();
CPaintManagerUI::MessageLoop();
CefShutdown();
退出訊息迴圈一定要呼叫CefShutdown()來關閉cef
在duilib的視窗類的initWindow()中新增如下程式碼來嵌入cef視窗:
CefWindowInfo info;
info.SetAsChild(m_hWnd, rt);
CefBrowserSettings settings;
CefBrowserHost::CreateBrowser(info, m_handler.get(), L"http://www.baidu.com", settings, NULL);
rt是一個RECT物件, 表示你放置cef視窗的區域
這樣, 把cef3嵌入到duilib視窗中的工作就基本完成了, 下面就可以設計我們自己需要的功能了:
例如新增一個URL輸入視窗, 並跳轉到對應的頁面, 我們可以新增如下程式碼:
std::wstring strUrl = m_pURL->GetText();
m_handler->GetBrowser()->GetMainFrame()->LoadURL(strUrl);
m_handler是一個SimpleHandler物件, m_pURL是一個duilib的編輯框物件
後退到前一個頁面:
m_handler->GetBrowser()->GoBack();
調整視窗大小:
HWND hwnd = ::FindWindowEx(m_hWnd, NULL, L"CefBrowserWindow", NULL);
::MoveWindow(hwnd, 3, 100, LOWORD(lParam)-6, HIWORD(lParam)-103, TRUE);
載入拖拽的本地html檔案:
WCHAR wcFile[MAX_PATH] = {0};
UINT count = DragQueryFile((HDROP)wParam, 0xFFFFFFFF, NULL, 0);
if(count)
{
DragQueryFile((HDROP)wParam, 0, wcFile, MAX_PATH);
wstring str = wcFile;
m_handler->GetBrowser()->GetMainFrame()->LoadURL(str);
m_pURL->SetText(wcFile);
}
接一下來, 我們會講解如何在cef中實現 js 和 c++的互動操作。
注:demo程式碼中, 需要在OnFinalMessage中處理下退出邏輯:
例如改為如下程式碼:
while(m_handler->GetBrowser())
{
Sleep(10);
}
::PostQuitMessage(0);
先判斷下, cef是否關閉了, 再退出訊息迴圈, 以防退出時候崩潰