.h
#pragma once
#include "include/cef_render_process_handler.h"
#include "include/cef_client.h"
#include "include/cef_v8.h"
#include "include/cef_browser.h"
class CCefClientHandler : public CefClient, public CefDisplayHandler, public CefLifeSpanHandler,
public CefLoadHandler, public CefRequestHandler, public CefContextMenuHandler
{
public:
CCefClientHandler();
~CCefClientHandler();
// CefClient methods:
virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() override;
virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override;
virtual CefRefPtr<CefLoadHandler> GetLoadHandler() override;
virtual CefRefPtr<CefRequestHandler> GetRequestHandler() override;
virtual CefRefPtr<CefContextMenuHandler> GetContextMenuHandler() override{
return this;
}
// ----------------CefDisplayHandler methods:-------------------
virtual void OnTitleChange(CefRefPtr<CefBrowser> browser, const CefString& title) override;
//---------------- CefLifeSpanHandler methods:----------------------------
virtual bool OnBeforePopup(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& target_url, const CefString& target_frame_name,
CefLifeSpanHandler::WindowOpenDisposition target_disposition, bool user_gesture, const CefPopupFeatures& popupFeatures, CefWindowInfo& windowInfo, CefRefPtr<CefClient>& client, CefBrowserSettings& settings, bool* no_javascript_access) override;
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 OnLoadStart(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame);
virtual void OnLoadEnd(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, int httpStatusCode) override;
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;
void CloseHostBrowser(CefRefPtr<CefBrowser>browser, bool force_close);
// Request that all existing browser windows close.
void CloseAllBrowsers(bool force_close);
bool IsClosing() const;
void ShowDevelopTools(CefRefPtr<CefBrowser> browser, const CefPoint& inspect_element_at);
void CloseDevelopTools(CefRefPtr<CefBrowser> browser);
public:
//CefRefPtr<CefBrowser> browser_;
HWND hWnd_; //接收消息的句柄
CefString strTitle_; //网址标题
// List of existing browser windows. Only accessed on the CEF UI thread.
typedef std::vector<CefRefPtr<CefBrowser> > BrowserList;
BrowserList browser_list_;
private:
bool is_closing_;
// Include the default reference counting implementation.
IMPLEMENT_REFCOUNTING(CCefClientHandler);
//由于CEF采用多线程架构,有必要使用锁和闭包来保证在多不同线程安全的传递数据。IMPLEMENT_LOCKING定义提供了Lock()和Unlock()方法以及AutoLock对象来保证不同代码块同步访问
IMPLEMENT_LOCKING(CCefClientHandler);
};
.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 "CCefClientHandler.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_web_plugin.h"
CCefClientHandler::CCefClientHandler() :hWnd_(NULL), is_closing_(false)
{
}
CCefClientHandler::~CCefClientHandler()
{
}
// CefClient methods:
CefRefPtr<CefDisplayHandler> CCefClientHandler::GetDisplayHandler()
{
return this;
}
CefRefPtr<CefLifeSpanHandler> CCefClientHandler::GetLifeSpanHandler()
{
return this;
}
CefRefPtr<CefLoadHandler> CCefClientHandler::GetLoadHandler()
{
return this;
}
CefRefPtr<CefRequestHandler> CCefClientHandler::GetRequestHandler()
{
return this;
}
// 缓存一个指向browser的引用
void CCefClientHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser)
{
int c = 3;
c++;
// Add to the list of existing browsers.
browser_list_.push_back(browser);
int nID = browser->GetIdentifier();
::PostMessage(hWnd_, UM_CEF_AFTERCREATED, nID, 0);
}
bool CCefClientHandler::DoClose(CefRefPtr<CefBrowser> browser)
{
int c = 3;
c++;
//TID_UI 线程是浏览器的主线程。
CEF_REQUIRE_UI_THREAD();
// AutoLock lock_scope(this);
lock_.Acquire();
// 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);
browser = NULL;
break;
}
}
lock_.Release();
if (browser_list_.size() == 0) {
// Set a flag to indicate that the window close should be allowed.
is_closing_ = true;
::PostMessage(hWnd_, UM_CEF_POSTQUITMESSAGE, 0, 0);
}
return false;
}
void CCefClientHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser)
{
int c = 3;
c++;
CEF_REQUIRE_UI_THREAD();
AutoLock lock_scope(this);
// lock_.Acquire();
BrowserList::iterator bit = browser_list_.begin();
for (; bit != browser_list_.end(); bit++)
{
if ((*bit)->IsSame(browser))
{
browser_list_.erase(bit);
browser = NULL;
break;
}
}
if (browser_list_.empty())
{
is_closing_ = true;
::PostMessage(hWnd_, UM_CEF_POSTQUITMESSAGE, 0, 0);
// All browser windows have closed. Quit the application message loop.
//CefQuitMessageLoop();
//PostQuitMessage(0l);
}
// lock_.Release();
}
void CCefClientHandler::OnLoadStart(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame)
{
int c = 3;
c++;
CEF_REQUIRE_UI_THREAD();
CefString* strTmpURL = new CefString(browser->GetMainFrame()->GetURL());
int nID = browser->GetIdentifier();
::PostMessage(hWnd_, UM_CEF_WEBLOADSTART, nID, (LPARAM)strTmpURL);
//return __super::OnLoadStart(browser, frame);
}
void CCefClientHandler::OnLoadEnd(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, int httpStatusCode)
{
int c = 3;
c++;
CEF_REQUIRE_UI_THREAD();
CefString* strTmpURL = new CefString(browser->GetMainFrame()->GetURL());
int nID = browser->GetIdentifier();
::PostMessage(hWnd_, UM_CEF_WEBLOADEND, nID, (LPARAM)strTmpURL);
}
void CCefClientHandler::OnLoadError(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, ErrorCode errorCode, const CefString& errorText, const CefString& failedUrl)
{
int c = 3;
c++;
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 CCefClientHandler::OnTitleChange(CefRefPtr<CefBrowser> browser, const CefString& title)
{
int c = 3;
c++;
CEF_REQUIRE_UI_THREAD();
// globally unique identifier for this browser
int nID = browser->GetIdentifier();
CefString* strTitle = new CefString(title);
::PostMessage(hWnd_, UM_CEF_WEBTITLECHANGE, nID, (LPARAM)strTitle);
}
bool CCefClientHandler::OnBeforePopup(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& target_url, const CefString& target_frame_name, CefLifeSpanHandler::WindowOpenDisposition target_disposition,
bool user_gesture, const CefPopupFeatures& popupFeatures, CefWindowInfo& windowInfo, CefRefPtr<CefClient>& client, CefBrowserSettings& settings, bool* no_javascript_access)
{
//消息处理后记得delete分配的字符串资源
CefString* strTargetURL = new CefString(target_url);
::PostMessage(hWnd_, UM_CEF_WEBLOADPOPUP, (WPARAM)0, (LPARAM)strTargetURL);
return true;
}
enum MyEnum
{
MENU_ID_USER_OPENLINK = MENU_ID_USER_FIRST + 200,
MENU_ID_USER_COPYLINK,
MENU_ID_USER_SHOWDEVTOOLS,
};
void CCefClientHandler::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_LINK)
{
model->Clear(); //清除所有菜单项
model->AddItem(MENU_ID_USER_OPENLINK, L"在新标签页中打开(&T)");//增加菜单项
model->AddSeparator(); //加分隔线
model->AddItem(MENU_ID_USER_COPYLINK, L"复制链接地址(&C)");//增加菜单项
//model->SetEnabled(MENU_ID_USER_OPENLINK, false); //禁用菜单项。
return;
}
if (flag & CM_TYPEFLAG_PAGE)
{//普通页面的右键消息
model->SetLabel(MENU_ID_BACK, L"后退");
model->SetLabel(MENU_ID_FORWARD, L"前进");
model->AddSeparator();
model->AddItem(MENU_ID_RELOAD, L"刷新");
model->AddItem(MENU_ID_RELOAD_NOCACHE, L"强制刷新");
model->AddItem(MENU_ID_STOPLOAD, L"停止加载");
model->AddSeparator();
model->SetLabel(MENU_ID_PRINT, L"打印");
model->SetLabel(MENU_ID_VIEW_SOURCE, L"查看源代码");
model->AddItem(MENU_ID_USER_SHOWDEVTOOLS, L"开发者工具"); //"&Show DevTools");
}
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 CCefClientHandler::OnContextMenuCommand(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefContextMenuParams> params, int command_id, EventFlags event_flags)
{
//CefString strLinkURL;
CefString strURLLink;
CefString* strTargetURL = nullptr;
HGLOBAL hglbCopy;
LPTSTR lptstrCopy;
int nBuffLength = 0;
switch (command_id)
{
case MENU_ID_USER_OPENLINK:
strTargetURL = new CefString(params->GetLinkUrl());
::PostMessage(hWnd_, UM_CEF_WEBLOADPOPUP, (WPARAM)0, (LPARAM)strTargetURL);
break;
case MENU_ID_USER_COPYLINK:
if (!OpenClipboard(frame->GetBrowser().get()->GetHost().get()->GetWindowHandle()))
{
return FALSE;
}
EmptyClipboard();
strURLLink = params->GetUnfilteredLinkUrl();
if (strURLLink.length() != 0)
{
nBuffLength = (strURLLink.length() + 1) * sizeof(TCHAR);
hglbCopy = GlobalAlloc(GMEM_MOVEABLE, nBuffLength);
if (hglbCopy == NULL)
{
CloseClipboard();
return FALSE;
}
// Lock the handle and copy the text to the buffer.
lptstrCopy = (LPTSTR)::GlobalLock(hglbCopy);
memset(lptstrCopy, '\0', nBuffLength);
memcpy(lptstrCopy, strURLLink.c_str(), nBuffLength - sizeof(TCHAR));
GlobalUnlock(hglbCopy); // 解除锁定剪贴板
// Place the handle on the clipboard.
//SetClipboardData(CF_TEXT, hglbCopy);
SetClipboardData(CF_UNICODETEXT, hglbCopy);// CF_UNICODETEXT为Unicode编码
}
CloseClipboard();
break;
case MENU_ID_USER_SHOWDEVTOOLS:
ShowDevelopTools(browser, CefPoint());
return true;
default:
break;
}
return false;
}
void CCefClientHandler::CloseHostBrowser(CefRefPtr<CefBrowser>browser, bool force_close)
{
if (!CefCurrentlyOn(TID_UI))
{
// Execute on the UI thread.
CefPostTask(TID_UI, base::Bind(&CCefClientHandler::CloseHostBrowser, this, browser, force_close));
return;
}
int nID = browser->GetIdentifier();
::PostMessage(hWnd_, UM_CEF_BROWSERCLOSE, nID, 0);
browser->GetHost()->CloseBrowser(force_close);
}
void CCefClientHandler::CloseAllBrowsers(bool force_close)
{
//if (!CefCurrentlyOn(TID_UI))
//{
// // Execute on the UI thread.
// CefPostTask(TID_UI, base::Bind(&CCefClientHandler::CloseAllBrowsers, this, force_close));
// return;
//}
lock_.Acquire();
if (browser_list_.empty()) {
return;
}
BrowserList::const_iterator it = browser_list_.begin();
for (; it != browser_list_.end(); ++it)
{
(*it)->GetHost()->CloseBrowser(force_close);
}
lock_.Release();
}
bool CCefClientHandler::IsClosing() const
{
return is_closing_;
}
void CCefClientHandler::ShowDevelopTools(CefRefPtr<CefBrowser> browser, const CefPoint& inspect_element_at) {
CefWindowInfo windowInfo; CefBrowserSettings settings;
#if defined(OS_WIN)
//windowInfo.SetAsPopup(browser->GetHost()->GetWindowHandle(), "DevTools");
RECT rc = { 0, 0, 800, 600 };
windowInfo.SetAsChild(hWnd_, rc);
#endif
browser->GetHost()->ShowDevTools(windowInfo, this, settings, inspect_element_at);
}
void CCefClientHandler::CloseDevelopTools(CefRefPtr<CefBrowser> browser)
{
browser->GetHost()->CloseDevTools();
}