Win32apiのCreateWindowのhwndにChromeを張り付ける。
CefRunMessageLoopを使用すると、メッセージループにCEFのものを使う。
#include <windows.h> #include <iostream> #include <include/cef_app.h> #ifdef _DEBUG #pragma comment(lib, "D:\\cmmon\\cef_binary_138.0.15+gd0f1f64+chromium-138.0.7204.50_windows64\\Debug\\libcef.lib") #pragma comment(lib, "D:\\cmmon\\MD\\Debug\\libcef_dll_wrapper.lib") #else #pragma comment(lib, "D:\\cmmon\\cef_binary_138.0.15+gd0f1f64+chromium-138.0.7204.50_windows64\\Release\\libcef.lib") #pragma comment(lib, "D:\\cmmon\\MD\\Release\\libcef_dll_wrapper.lib") #endif
class MyHandler : public CefClient , public CefLifeSpanHandler { public: MyHandler() {} CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override { return this; } void OnAfterCreated(CefRefPtr<CefBrowser> browser) override { m_Browser = browser; } void OnBeforeClose(CefRefPtr<CefBrowser> browser) override { m_Browser = nullptr; } void CloseAllBrowsers(bool force_close) { if (m_Browser) { m_Browser->GetHost()->CloseBrowser(force_close); } } IMPLEMENT_REFCOUNTING(MyHandler); private: CefRefPtr<CefBrowser> m_Browser; };
class MyApp : public CefApp { IMPLEMENT_REFCOUNTING(MyApp); };
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { MyHandler* handler; LPCREATESTRUCT pcs; switch (msg) { case WM_CLOSE:
handler = (MyHandler*)GetWindowLongPtr(hwnd, GWLP_USERDATA); if (handler) { handler->CloseAllBrowsers(true); }
DestroyWindow(hwnd); return 0; case WM_CREATE:
pcs = (LPCREATESTRUCT)lp; handler = (MyHandler *)pcs->lpCreateParams; SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)(handler));
return 0; case WM_DESTROY:
CefQuitMessageLoop();
PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, msg, wp, lp); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { /////////////////////////////////////////////////////////////////////////
CefMainArgs main_args(hInstance); CefRefPtr<MyApp> app(new MyApp); // MyAppのインスタンス用のポインタ // サブプロセス処理 int exit_code = CefExecuteProcess(main_args, app, nullptr); if (exit_code >= 0) return exit_code; // CEFの設定 CefSettings settings; settings.no_sandbox = true; CefInitialize(main_args, settings, app, nullptr);
///////////////////////////////////////////////////////////////////////// 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 = CefRefPtr<MyHandler>(new MyHandler);
hwnd = CreateWindow( TEXT("SZL-WND"), TEXT("CEF test"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, g_handler.get() ); if (hwnd == NULL) return -1;
CefRefPtr<CefClient> client = g_handler; // 型は CefClient で渡す CefBrowserSettings browser_settings; CefWindowInfo window_info; RECT rect; GetClientRect(hwnd, &rect); // 親ウィンドウのクライアント領域 CefRect cefRect( rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); window_info.SetAsChild(hwnd, cefRect); CefBrowserHost::CreateBrowser( window_info, g_handler, "https://www.google.com", browser_settings, nullptr, nullptr); CefRunMessageLoop(); // メッセージループ // settings.multi_threaded_message_loop = true;の時はコメントアウトすること CefShutdown(); // CEF終了処理
return 0; }
CefRunMessageLoopを使わない場合、メッセージループは自分で書き、CEFのメッセージを処理するためにループ内で CefDoMessageLoopWork() を呼び出す。
また、CefDoMessageLoopWork内でPeekMessageを呼んでいる関係でWM_QUITを検知できなくなるので、GetMessageを使わずにMsgWaitForMultipleObjectsとPeekMessageでメッセージループを管理する。
// CefRunMessageLoop(); // メッセージループ // 注意 GetMessageは使わない // CefDoMessageLoopWorkは中でPeekMessageを使っている // PeekMessage は強制的にWM_QUITを取り出してしまうので、 // こちら側でGetMessageをつかうと先にWM_QUITを取り出されて // 終了を感知できなくなりループから抜け出せなくなる // **CefDoMessageLoopWorkは内部でタイマーイベントなどを多数キューに投げているので、 // **GetMessageがタイマーを補足し、次に入っていたWM_QUITはCefDoMessageLoopWorkが取り出すという // **現象が起こる // bool should_quit = false; while (!should_quit) { // MsgWaitForMultipleObjects = メッセージが来るまでスレッドをスリープ DWORD result = MsgWaitForMultipleObjects(0, NULL, FALSE, INFINITE, QS_ALLINPUT); // もし何かメッセージが来たら処理 if (result == WAIT_OBJECT_0) { while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) { should_quit = true; } else { TranslateMessage(&msg); DispatchMessage(&msg); } } } if (!should_quit) { CefDoMessageLoopWork(); } }
multi_threaded_message_loopをtrueに設定すると、CEFが専用スレッドで動く。この場合、CefRunMessageLoop(),CefShutdown()を使用してはいけない。
メッセージループは自プログラムのメッセージだけを処理する。
CefSettings settings; settings.no_sandbox = true; settings.multi_threaded_message_loop = true; // を指定して専用スレッドでCEFを動かす場合、 // CefRunMessageLoop()も CefDoMessageLoopWork() も CefShutdown() も使ってはいけない /* ... */ while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } // 使わない CefRunMessageLoop(); // settings.multi_threaded_message_loop = true;の時はコメントアウトすること // 使わない CefShutdown(); return 0;// msg.wParam; }