C++コードだけで、なおかつATL::CAxWindowクラス(MSDNライブラリ)を使って、WebBrowserコントロールを使うプログラムを作ってみました。というのも、ATLでWebBrowserコントロールを使うコードとして、

  • ダイアログで作るもの
  • AtlAxWinInit関数とAtlAxWinウィンドウクラス(正確にはATLのバージョンによって少し異なる名称)を使うもの

しか見当たらなかったので、自分で書いてみることにしました。

ATL::CAxWindowは、ATL::CWindowから派生して、いくつかメンバー関数が増えたクラスです。その点では、WTL::CButtonやWTL::CEditなどと同様な存在です。ウィンドウクラスAtlAxWinのウィンドウを持ち、また、その中でActiveXコントロールを動かす機能を持っています。

そんなわけで、ATL/WTLを使って作るプログラムにおいて、ウィンドウ内にActiveXコントロールを載せようという場合、まずATL::CAxWindowを使ってみれば良いというわけです。

#define UNICODE
#define _UNIDODE
 
#define WINVER 0x0501
#define _ATL_XP_TARGETING
#define _ATL_NO_AUTOMATIC_NAMESPACE
#define _WTL_NO_AUTOMATIC_NAMESPACE
 
#include <cstdlib>
 
#include <windows.h>
 
#include <atlbase.h>
#include <atlwin.h>
#include <atltypes.h>
 
#include <atlapp.h>
#include <atlcrack.h>
 
class Module : public ATL::CAtlExeModuleT<Module>
{
};
 
Module module;
 
class TestWindow :
  public ATL::CWindowImpl<TestWindow>,
  public WTL::CMessageFilter
{
public:
  int Run(int cmdShow, _Inout_ WTL::CMessageLoop& msgLoop)
  {
    if (!Create(nullptr, ATL::CWindow::rcDefault,
      TEXT("Hello, world"), WS_OVERLAPPEDWINDOW))
    {
      return -1;
    }
 
    ShowWindow(cmdShow);
    UpdateWindow();
 
    msgLoop.AddMessageFilter(this);
    return msgLoop.Run();
  }
 
  BOOL PreTranslateMessage(_In_ MSG* pmsg) override
  {
    if (m_webBrowser.IsWindow()
      && m_webBrowser.SendMessage(
        WM_FORWARDMSG, 0, reinterpret_cast<LPARAM>(pmsg)))
    {
      return TRUE;
    }
    return IsDialogMessage(pmsg);
  }
 
  DECLARE_WND_CLASS(TEXT("Test Window Class"));
 
  BEGIN_MSG_MAP(TestWindow)
    MSG_WM_SIZE(OnSize)
    MSG_WM_SETFOCUS(OnSetFocus)
    MSG_WM_CREATE(OnCreate)
    MSG_WM_DESTROY(OnDestroy)
  END_MSG_MAP()
 
private:
  void OnSize(UINT, SIZE size)
  {
    m_webBrowser.ResizeClient(size.cx, size.cy);
  }
 
  void OnSetFocus(HWND)
  {
    m_webBrowser.SetFocus();
  }
 
  LRESULT OnCreate(const CREATESTRUCT*)
  {
    constexpr DWORD IDC_WEBBROWSER_CONTROL = 1;
    RECT empty{};
    m_webBrowser.Create(m_hWnd, empty, L"https://www.google.co.jp",
      WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP | WS_GROUP, 0,
      IDC_WEBBROWSER_CONTROL);
 
    return 0;
  }
 
  void OnDestroy()
  {
    PostQuitMessage(0);
  }
 
  ATL::CAxWindow m_webBrowser;
};
 
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int cmdShow)
{
  if (FAILED(OleInitialize(nullptr)))
  {
    std::quick_exit(-1);
  }
 
  WTL::CMessageLoop msgLoop;
  TestWindow wnd;
  std::quick_exit(wnd.Run(cmdShow, msgLoop));
}

WebBrowserコントロールのCLSIDなどを指定している箇所が全くありませんが、Createメンバー関数でURLを指定しているためです。なお、ProgIDやCLSIDを文字列で指定すれば、他のコントロールを作成できます。

なお、IWebBrowser2へのポインタを得るには、次のようにQueryControlメンバー関数を使用します。

ATL::CComPtr<IWebBrowser2> wb;
m_webBrowser.QueryControl(&wb);

PreTranslateMessage関数の実装が特徴的です。これはどうしても分からなかったので、ATL::CAxDialogImplの実装を参考にしました。2016年9月22日追記: 自分が最初に書いたコードが動かない原因が分かった(単純な誤りだった)ので、PreTranslateMessage関数の実装を単純なものに変えました。

以上、ATL::CAxWindowを使ってWebBrowserコントロールを使ってみるサンプルプログラムでした。これは最低限の実装なので、実際活用するにはここからいろいろ書き足していくことになると思います。

ところで、IEコントロールやIEコンポーネントという呼び方もよく見かけますし、私も使いますが、この記事ではWebBrowserコントロールに統一しました。ExDisp.idlでcoclass WebBrowser (CLSID_WebBrowser)と定義されていて、MSDNライブラリでもWebBrowser Controlと表記されているためです。


スポンサード リンク

この記事のカテゴリ

  • ⇒ ATL::CAxWindowでWebBrowserコントロールを使ってみる
  • ⇒ ATL::CAxWindowでWebBrowserコントロールを使ってみる
  • ⇒ ATL::CAxWindowでWebBrowserコントロールを使ってみる