スポンサーリンク

Chromium Embedded Framework(2)ウィンドウに張り付ける

Win32apiのCreateWindowのhwndにChromeを張り付ける。

CefRunMessageLoop 版

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 版

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;
}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: