Win32APIからCEFを使用するコードを書きたかったので前に書いたものを整頓した。
実行には.exeファイルと同じ場所
cef_binary_138.0.15+gd0f1f64+chromium-138.0.7204.50_windows64\Resources\
の内容(localesフォルダなど)をコピーする。
#include "MyCEFControl.hpp" #include <Windows.h> #include <windowsx.h>
void OnPaint(HWND hwnd, HDC hdc) { MyHandler* handler = (MyHandler*)GetWindowLongPtr(hwnd, GWLP_USERDATA); if (handler) { CefRefPtr<CefRenderHandler> baseRenderHandler = handler->GetRenderHandler(); MyRenderHandler* renderHandler = static_cast<MyRenderHandler*>(baseRenderHandler.get()); RGBAImage img = renderHandler->m_browserImage; if (img.buffer.size() > 0) { // ビットマップ情報の設定 BITMAPINFO bmi; ZeroMemory(&bmi, sizeof(BITMAPINFO)); bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = img.width; bmi.bmiHeader.biHeight = -img.height; // 上下反転 bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 24; // RGB24ビット bmi.bmiHeader.biCompression = BI_RGB; // 画像データを描画 SetDIBitsToDevice( hdc, 0, 0, // 描画位置 img.width, img.height, // 描画サイズ 0, 0, // ソースの開始位置 0, img.height, // ソースの開始ラインとライン数 img.buffer.data(), // ピクセルデータ &bmi, DIB_RGB_COLORS // カラーテーブルの使用方法 ); } } }
void OnMouseMove(HWND hwnd, int x, int y) { MyHandler* handler = (MyHandler*)GetWindowLongPtr(hwnd, GWLP_USERDATA); if (handler) { CefMouseEvent mouse_event; mouse_event.x = x; mouse_event.y = y; mouse_event.modifiers = 0; handler->GetBrowser()->GetHost()->SendMouseMoveEvent(mouse_event, false); InvalidateRect(hwnd, NULL, FALSE); } }
void OnLButtonDown(HWND hwnd, int x, int y) { MyHandler* handler = (MyHandler*)GetWindowLongPtr(hwnd, GWLP_USERDATA); if (handler) { CefMouseEvent mouse_event; mouse_event.x = x; mouse_event.y = y; mouse_event.modifiers = 0; handler->GetBrowser()->GetHost()->SendMouseClickEvent(mouse_event, cef_mouse_button_type_t::MBT_LEFT, false, 1); InvalidateRect(hwnd, NULL, FALSE); } }
void OnLButtonUp(HWND hwnd, int x, int y) { MyHandler* handler = (MyHandler*)GetWindowLongPtr(hwnd, GWLP_USERDATA); if (handler) { CefMouseEvent mouse_event; mouse_event.x = x; mouse_event.y = y; mouse_event.modifiers = 0; handler->GetBrowser()->GetHost()->SendMouseClickEvent(mouse_event, cef_mouse_button_type_t::MBT_LEFT, true, 1); InvalidateRect(hwnd, NULL, FALSE); } }
void OnClose(HWND hwnd) { MyHandler* handler = (MyHandler*)GetWindowLongPtr(hwnd, GWLP_USERDATA); if (handler) { handler->CloseAllBrowsers(true); } }
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { MyHandler* handler = nullptr; LPCREATESTRUCT pcs; PAINTSTRUCT ps; HDC hdc; switch (msg) { case WM_CLOSE: OnClose(hwnd); DestroyWindow(hwnd); return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); OnPaint(hwnd, hdc); EndPaint(hwnd, &ps); return 0; case WM_CREATE: return 0; case WM_DESTROY: //CefQuitMessageLoop(); PostQuitMessage(0); return 0; case WM_MOUSEMOVE: OnMouseMove(hwnd, GET_X_LPARAM(lp), GET_Y_LPARAM(lp)); return 0; case WM_LBUTTONDOWN: OnLButtonDown(hwnd, GET_X_LPARAM(lp), GET_Y_LPARAM(lp)); return 0; case WM_LBUTTONUP: OnLButtonUp(hwnd, GET_X_LPARAM(lp), GET_Y_LPARAM(lp)); return 0; } return DefWindowProc(hwnd, msg, wp, lp); }
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { HWND hwnd; MSG msg; WNDCLASS winc; winc.style = CS_HREDRAW | CS_VREDRAW; winc.lpfnWndProc = WndProc; winc.cbClsExtra = winc.cbWndExtra = 0; winc.hInstance = hInstance; winc.hIcon = LoadIcon(NULL, IDI_APPLICATION); winc.hCursor = LoadCursor(NULL, IDC_ARROW); winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); winc.lpszMenuName = NULL; winc.lpszClassName = TEXT("SZL-WND"); if (!RegisterClass(&winc)) return -1; ///////////////////////////////////////////////////////////////////////// CefRefPtr<MyHandler> g_handler = MyInitCEF(hInstance); if (!g_handler) { return -1; } ///////////////////////////////////////////////////////////////////////// hwnd = CreateWindow( TEXT("SZL-WND"), TEXT("CEF test"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 500, 500, NULL, NULL, hInstance, nullptr ); if (hwnd == NULL) return -1; ///////////////////////////////////////////////////////////////////////// SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)(g_handler.get())); ///////////////////////////////////////////////////////////////////////// MyRenderSetting(hwnd,g_handler); ///////////////////////////////////////////////////////////////////////// // メッセージループ CefRunMessageLoop(); // CEFのシャットダウン CefShutdown(); return 0; }
#pragma once #include <include/cef_app.h> struct RGBAImage { int width; int height; std::vector<unsigned char> buffer; // RGBAの生データ }; RGBAImage FromRGBA(const unsigned char* rgba_buffer, int width, int height); class MyRenderHandler : public CefRenderHandler { public: HWND m_pCanvasWindow = nullptr; RGBAImage m_browserImage; // GetViewRect() をoverrideする // 必須:ビューポートのサイズを返す void GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) override; // 必須:レンダリング結果がここに来る void OnPaint(CefRefPtr<CefBrowser> browser, PaintElementType type, const RectList& dirtyRects, const void* buffer, int width, int height) override; // サイズを外から設定 void SetSize(int w, int h); private: IMPLEMENT_REFCOUNTING(MyRenderHandler); }; class MyHandler : public CefClient, public CefLifeSpanHandler { CefRefPtr<CefRenderHandler> renderHandler_; public: MyHandler(CefRefPtr<CefRenderHandler> renderHandler) : renderHandler_(renderHandler) { } CefRefPtr<CefRenderHandler> GetRenderHandler() override; CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override; void OnAfterCreated(CefRefPtr<CefBrowser> browser) override; void OnBeforeClose(CefRefPtr<CefBrowser> browser) override; void CloseAllBrowsers(bool force_close); CefRefPtr<CefBrowser> GetBrowser(); IMPLEMENT_REFCOUNTING(MyHandler); private: CefRefPtr<CefBrowser> m_Browser; }; CefRefPtr<MyHandler> MyInitCEF(HINSTANCE hInstance); void MyRenderSetting(HWND window, CefRefPtr<MyHandler> ghandler);
#include "MyCEFControl.hpp" void MyRenderHandler::GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect){ // ビューポートのサイズを返す rect = CefRect(0, 0, m_browserImage.width, m_browserImage.height); } // 必須:レンダリング結果がここに来る void MyRenderHandler::OnPaint(CefRefPtr<CefBrowser> browser, PaintElementType type, const RectList& dirtyRects, const void* buffer, int width, int height) { // ※ buffer は 32bit BGRA フォーマット m_browserImage = FromRGBA(static_cast<const unsigned char*>(buffer), width, height); InvalidateRect(m_pCanvasWindow, NULL, FALSE); } // サイズを外から設定 void MyRenderHandler::SetSize(int w, int h) { m_browserImage.buffer.resize(w * h * 4); m_browserImage.width = w; m_browserImage.height = h; } //============================================================= CefRefPtr<CefRenderHandler> MyHandler::GetRenderHandler() { return renderHandler_; } CefRefPtr<CefLifeSpanHandler> MyHandler::GetLifeSpanHandler() { return this; } void MyHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) { m_Browser = browser; } void MyHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) { m_Browser = nullptr; CefQuitMessageLoop(); } void MyHandler::CloseAllBrowsers(bool force_close) { if (m_Browser) { m_Browser->GetHost()->CloseBrowser(force_close); } } CefRefPtr<CefBrowser> MyHandler::GetBrowser() { return m_Browser; } //============================================================= RGBAImage FromRGBA(const unsigned char* rgba_buffer, int width, int height) { // wxImage用にRGBを抜き出す // 既存の生配列からstd::vectorへの変換例 std::vector<unsigned char> rgb_data(rgba_buffer, rgba_buffer + width * height * 3); for (int i = 0; i < width * height; ++i) { rgb_data[i * 3 + 0] = rgba_buffer[i * 4 + 0]; rgb_data[i * 3 + 1] = rgba_buffer[i * 4 + 1]; rgb_data[i * 3 + 2] = rgba_buffer[i * 4 + 2]; } RGBAImage img; img.width = width; img.height = height; img.buffer = std::move(rgb_data); return img; } CefRefPtr<MyHandler> MyInitCEF(HINSTANCE hInstance) { CefMainArgs main_args(hInstance); int exit_code = CefExecuteProcess(main_args, nullptr, nullptr); if (exit_code >= 0) return nullptr; // CEFの設定 CefSettings settings; settings.no_sandbox = true; // マルチスレッドメッセージループを無効にする // オフスクリーンレンダリングでは false必須 settings.multi_threaded_message_loop = false; CefInitialize(main_args, settings, nullptr, nullptr); ///////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// CefRefPtr<MyRenderHandler> renderHandler = new MyRenderHandler(); CefRefPtr<MyHandler> g_handler = CefRefPtr<MyHandler>(new MyHandler(renderHandler)); return g_handler; } void MyRenderSetting(HWND window, CefRefPtr<MyHandler> ghandler) { // MyRenderHandlerを取得 CefRefPtr<CefRenderHandler> baseRenderHandler = ghandler->GetRenderHandler(); CefRefPtr<MyRenderHandler> renderHandler = static_cast<MyRenderHandler*>(baseRenderHandler.get()); renderHandler->m_pCanvasWindow = window; renderHandler->SetSize(400, 400); // ビューポートのサイズを設定 CefBrowserSettings browser_settings; CefWindowInfo window_info; CefRect cefRect( 0, 0, 800, 600); // オフスクリーンレンダリング window_info.SetAsWindowless(nullptr); CefBrowserHost::CreateBrowser( window_info, ghandler, "https://www.google.com", browser_settings, nullptr, nullptr); }