|
https://blog.csdn.net/mfcing/article/details/43953433
浏览器代码已开源:欢迎收藏 https://github.com/JelinYao/MyChrome
CEF出来很久了,使用的也很广泛的,QQ里面很多地方都是嵌入的CEF浏览器(个人资料、微博、查找……),网上的资料也挺多的,大家可以搜搜看。
首先是下载CEF代码编译,通过里面的那两个例子你也可以依葫芦画瓢的。官方下载地址:http://cefbuilds.com/
这里推荐一个很详细的解说:http://www.cnblogs.com/think/arc ... /CEF-Introduce.html
重载CEF的各种“消息”处理类,当你需要自己处理或者自定义这些消息时,才需要重载它们,重载后一定要重写相应的虚函数返回this指针。估计内部是有这些个回调类对象指针,不返回this的话默认就是NULL了,就会执行内部默认的那套机制。
#pragma once
#include "include/cef_client.h"
#include <list>
#include <string>
using std::wstring;
class CCefHandler :
public CefClient,
public CefDisplayHandler,
public CefLifeSpanHandler,
public CefLoadHandler,
public CefRequestHandler,
public CefContextMenuHandler,
public CefDownloadHandler
{
public:
CCefHandler(const wstring& strUrl=L"");
virtual ~CCefHandler();
//自定义方法
CefRefPtr<CefBrowser> GetBrowser() { return m_pBrowser; }
CefRefPtr<CefFrame> GetMainFram() { return m_pBrowser.get()?m_pBrowser->GetMainFrame():NULL; }
HWND GetBrowserHostWnd() { return m_pBrowser.get()?m_pBrowser->GetHost()->GetWindowHandle():NULL; }
void SetHomePage(const wstring& strUrl) { m_strHomePage=strUrl; }
const wstring& GetHomePage()const { return m_strHomePage; }
wstring GetLoadingUrl();
void Navigate(const wstring& strUrl);
void CreateBrowser(HWND hParentWnd, const RECT& rect);
bool IsClosing() const { return m_bIsClose; }
//凡是继承了的处理功能都在这里返回this指针
virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() { return this; }
virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() { return this; }
virtual CefRefPtr<CefLoadHandler> GetLoadHandler() { return this; }
virtual CefRefPtr<CefContextMenuHandler> GetContextMenuHandler() { return this; }
virtual CefRefPtr<CefDownloadHandler> GetDownloadHandler() { return this; }
// CefDisplayHandler methods:
virtual void OnTitleChange(CefRefPtr<CefBrowser> browser, const CefString& title);
virtual void OnAddressChange(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& url);
virtual bool OnTooltip(CefRefPtr<CefBrowser> browser, CefString& text);
virtual void OnStatusMessage(CefRefPtr<CefBrowser> browser, const CefString& value);
// CefLifeSpanHandler methods:
virtual bool OnBeforePopup(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, \
const CefString& target_url, const CefString& target_frame_name, const CefPopupFeatures& popupFeatures, \
CefWindowInfo& windowInfo, CefRefPtr<CefClient>& client, CefBrowserSettings& settings, \
bool* no_javascript_access);
virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser);
virtual bool DoClose(CefRefPtr<CefBrowser> browser);
virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser);
// CefLoadHandler methods:
virtual void OnLoadStart(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame);
virtual void OnLoadEnd(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, int httpStatusCode);
virtual void OnLoadError(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, ErrorCode errorCode, const CefString& errorText, const CefString& failedUrl);
// Request that all existing browser windows close.
void CloseAllBrowsers(bool force_close);
//
virtual bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, \
CefRefPtr<CefRequest> request, bool is_redirect)
{
//return true;
return false;
}
virtual bool OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request) {
return false;
}
//菜单处理
virtual void OnBeforeContextMenu(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, \
CefRefPtr<CefContextMenuParams> params, CefRefPtr<CefMenuModel> model);
virtual bool OnContextMenuCommand(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, \
CefRefPtr<CefContextMenuParams> params, int command_id, EventFlags event_flags);
//下载处理
virtual void OnBeforeDownload( CefRefPtr<CefBrowser> browser, CefRefPtr<CefDownloadItem> download_item, \
const CefString& suggested_name, CefRefPtr<CefBeforeDownloadCallback> callback);
virtual void OnDownloadUpdated( CefRefPtr<CefBrowser> browser, CefRefPtr<CefDownloadItem> download_item, \
CefRefPtr<CefDownloadItemCallback> callback);
private:
typedef std::list<CefRefPtr<CefBrowser> > BrowserList;
BrowserList browser_list_;
CefRefPtr<CefBrowser> m_pBrowser;
bool m_bIsClose;
wstring m_strHomePage;
static int m_nBrowserCount;
// Include the default reference counting implementation.
IMPLEMENT_REFCOUNTING(CCefHandler);
IMPLEMENT_LOCKING(CCefHandler);
};
对应的实现代码:
#include "stdafx.h"
#include "CefHandler.h"
#include <sstream>
#include "util.h"
#include "../include/cef_app.h"
#include "../include/cef_runnable.h"
int CCefHandler::m_nBrowserCount = 0;
CCefHandler::CCefHandler( const wstring& strUrl/*=L""*/ )
: m_bIsClose(false)
, m_strHomePage(strUrl)
{
}
CCefHandler::~CCefHandler()
{
}
void CCefHandler::CloseAllBrowsers(bool force_close)
{
if (!CefCurrentlyOn(TID_UI))
{
// Execute on the UI thread.
CefPostTask(TID_UI, NewCefRunnableMethod(this, &CCefHandler::CloseAllBrowsers, 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);
}
wstring CCefHandler::GetLoadingUrl()
{
CefRefPtr<CefFrame> pMainFram=GetMainFram();
return pMainFram.get()?pMainFram->GetURL()"";
}
void CCefHandler::Navigate( const wstring& strUrl )
{
CefRefPtr<CefFrame> pMainFram=GetMainFram();
if ( pMainFram.get() )
pMainFram->LoadURL(strUrl.c_str());
}
void CCefHandler::CreateBrowser( HWND hParentWnd, const RECT& rect )
{
CefWindowInfo info;
CefBrowserSettings settings;
static wchar_t* pCharset = L"GB2312";
settings.default_encoding.str = pCharset;
settings.default_encoding.length = wcslen(pCharset);
info.SetAsChild(hParentWnd, rect);
CefBrowserHost::CreateBrowser(info, this, m_strHomePage.c_str(), settings, NULL);
}
//****************************************************
//菜单加载接口
void CCefHandler::OnBeforeContextMenu( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, \
CefRefPtr<CefContextMenuParams> params, CefRefPtr<CefMenuModel> model )
{
//在这里,我添加了自己想要的菜单
cef_context_menu_type_flags_t flag = params->GetTypeFlags();
if ( flag & CM_TYPEFLAG_PAGE )
{//普通页面的右键消息
model->SetLabel(MENU_ID_BACK, L"后退");
model->SetLabel(MENU_ID_FORWARD, L"前进");
model->SetLabel(MENU_ID_VIEW_SOURCE, L"查看源代码");
model->SetLabel(MENU_ID_PRINT, L"打印");
model->SetLabel(MENU_ID_RELOAD, L"刷新");
model->SetLabel(MENU_ID_RELOAD_NOCACHE, L"强制刷新");
model->SetLabel(MENU_ID_STOPLOAD, L"停止加载");
model->SetLabel(MENU_ID_REDO, L"重复");
}
if ( flag & CM_TYPEFLAG_EDITABLE)
{//编辑框的右键消息
model->SetLabel(MENU_ID_UNDO, L"撤销");
model->SetLabel(MENU_ID_REDO, L"重做");
model->SetLabel(MENU_ID_CUT, L"剪切");
model->SetLabel(MENU_ID_COPY, L"复制");
model->SetLabel(MENU_ID_PASTE, L"粘贴");
model->SetLabel(MENU_ID_DELETE, L"删除");
model->SetLabel(MENU_ID_SELECT_ALL, L"全选");
}
}
bool CCefHandler::OnContextMenuCommand( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, \
CefRefPtr<CefContextMenuParams> params, int command_id, EventFlags event_flags )
{
return false;
}
//****************************************************
//网页加载状态回调接口
void CCefHandler::OnLoadStart( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame )
{
}
void CCefHandler::OnLoadEnd( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, int httpStatusCode )
{
//CefRefPtr<CefV8Context> v8 = frame->GetV8Context();
}
void CCefHandler::OnLoadError(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, \
ErrorCode errorCode, const CefString& errorText, const CefString& failedUrl)
{
REQUIRE_UI_THREAD();
// Don't display an error for downloaded files.
if (errorCode == ERR_ABORTED)
return;
// Display a load error message.
std::wstringstream ss;
//std::wstring
ss << L"<html><body bgcolor=\"white\">"
L"<h2>Failed to load URL " << std::wstring(failedUrl) <<
L" with error " << std::wstring(errorText) << L" (" << errorCode <<
L").</h2></body></html>"<<'\0';
frame->LoadString(ss.str(), failedUrl);
}
//****************************************************
//状态改变回调接口
void CCefHandler::OnTitleChange( CefRefPtr<CefBrowser> browser, const CefString& title )
{
}
void CCefHandler::OnAddressChange( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& url )
{
}
bool CCefHandler::OnTooltip( CefRefPtr<CefBrowser> browser, CefString& text )
{
return false;
}
void CCefHandler::OnStatusMessage( CefRefPtr<CefBrowser> browser, const CefString& value )
{
}
//****************************************************
//网页生命周期回调接口
bool CCefHandler::OnBeforePopup( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, \
const CefString& target_url, const CefString& target_frame_name, const CefPopupFeatures& popupFeatures, \
CefWindowInfo& windowInfo, CefRefPtr<CefClient>& client, CefBrowserSettings& settings, \
bool* no_javascript_access )
{
//这里使用默认浏览器打开网页,避免CEF重新创建窗口
ShellExecute(NULL, L"open", target_url.c_str(), NULL, NULL, SW_SHOW);
//return false;//创建新窗口
return true; //禁止创建新的窗口
}
void CCefHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser)
{
REQUIRE_UI_THREAD();
// Add to the list of existing browsers.
browser_list_.push_back(browser);
AutoLock scopLock(this);
if ( ! m_pBrowser.get() )
m_pBrowser=browser;
m_nBrowserCount++;
}
bool CCefHandler:oClose(CefRefPtr<CefBrowser> browser)
{
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.
m_bIsClose = true;
}
// Allow the close. For windowed browsers this will result in the OS close
// event being sent.
return false;
}
void CCefHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser)
{
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 CCefHandler::OnBeforeDownload( CefRefPtr<CefBrowser> browser, CefRefPtr<CefDownloadItem> download_item, \
const CefString& suggested_name, CefRefPtr<CefBeforeDownloadCallback> callback )
{
int i=0;
}
void CCefHandler::OnDownloadUpdated( CefRefPtr<CefBrowser> browser, CefRefPtr<CefDownloadItem> download_item, \
CefRefPtr<CefDownloadItemCallback> callback )
{
//取消CEF内部下载文件,使用默认浏览器打开链接去下载,下载过程就不需要我们关心了,毕竟不是做浏览器
callback->Cancel();
CefString strUrl = download_item->GetURL();
ShellExecute(NULL, L"open", strUrl.c_str(), NULL, NULL, SW_SHOW);
int i = 0;
}
然后是实现CefApp类的重载,没有实际的处理功能,在此忽略。
使用时,创建一个win32项目,然后修改WinMain函数:
CefRefPtr<CCefHandler> g_handler;
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
// TODO: 在此放置代码。
CefMainArgs main_args(hInstance);
CefRefPtr<CCefAppEx> app(new CCefAppEx);
int exit_code = CefExecuteProcess(main_args, app.get());
if (exit_code >= 0) {
return exit_code;
}
CefSettings settings;
settings.single_process = true;
//settings.multi_threaded_message_loop = true;
CefInitialize(main_args, settings, app.get());
//if ( strCmd.size() == 0 )
HACCEL hAccelTable;
// 初始化全局字符串
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_CEFDEMO, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// 执行应用程序初始化:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_CEFDEMO));
CefRunMessageLoop();
CefShutdown();
return 0;
}
消息处理主要是创建、销毁CEF对象,窗口大小改变时通知CEF窗口等:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_CREATE:
{//http://blog.csdn.net/wongson/article/details/6210854
g_handler=new CCefHandler(L"www.qq.com");
RECT rect;
::GetClientRect(hWnd, &rect);
g_handler->CreateBrowser(hWnd, rect);
break;
}
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// 分析菜单选择:
switch (wmId)
{
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default: break;
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: 在此添加任意绘图代码...
EndPaint(hWnd, &ps);
break;
case WM_SIZE:
{
if ( wParam == SIZE_MINIMIZED
|| NULL == g_handler
|| NULL == g_handler->GetBrowserHostWnd() )
break;
HWND hBrowserWnd=g_handler->GetBrowserHostWnd();
RECT rect;
::GetClientRect(hWnd, &rect);
::MoveWindow(hBrowserWnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE);
break;
}
case WM_CLOSE:
{
if ( g_handler.get() && !g_handler->IsClosing() )
{
wstring strUrl=g_handler->GetLoadingUrl();
CefRefPtr<CefBrowser> pBrowser=g_handler->GetBrowser();
if ( pBrowser.get() )
pBrowser->GetHost()->CloseBrowser(true);
}
break;
}
default: break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
编译,运行程序,一个简单的网页就出来了,加载速度比IE那垃圾快多了,关键是不用理会兼容性问题了。
最后记得带上CEF的一大堆DLL,这个是必须的,如果网页需要播放视频,需要新建一个plugins文件夹,放入视频播放插件NPSWF32.dll。
需要链接的CEF动态链接库:
#ifdef _DEBUG
#pragma comment(lib, "..\\LibCef\\Debug\\libcef")
#pragma comment(lib, "..\\LibCef\\Debug\\libcef_dll_wrapper")
#else
#pragma comment(lib, "..\\LibCef\\Release\\libcef")
#pragma comment(lib, "..\\LibCef\\Release\\libcef_dll_wrapper")
#endif
libcef使用范例之4399网页小游戏,git源码:https://github.com/JelinYao/4399WebGames
使用libCef+Duilib开发属于自己的浏览器已开源:https://github.com/JelinYao/MyChrome
————————————————
版权声明:本文为CSDN博主「疯狂-的-蜗牛」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/mfcing/article/details/43953433
|
|