私、WTLでそんなに大きなアプリケーションを作ったことがないので、WTL::CAppModuleの必要性を感じたことがないんです。あと、基底クラスであるATL::CComModuleは、ATL 7より非推奨になっています。それも、なんとなく避けたい理由の1つです。

では、WTL::CMessageFilterやWTL::CIdleHandlerを使いたいときはどうするかというと、こうです。WinMain関数かどこかで定義したWTL::CMessageLoopのオブジェクトを直接使います。WTL::CAppModuleのAddMessageLoopとGetMessageLoopのメンバー関数を使わない、それだけのことです。

以下のサンプルプログラムでは、WTL::CMessageFilterだけしか登場しませんが、WTL::CIdleHandlerも同じ要領です。

#define UNICODE
#define _UNIDODE
 
#define WINVER 0x0600
#define _ATL_NO_AUTOMATIC_NAMESPACE
#define _WTL_NO_AUTOMATIC_NAMESPACE
 
#include <windows.h>
 
#include <atlbase.h>
#include <atlwin.h>
#include <atltypes.h>
 
#include <atlapp.h>
#include <atlcrack.h>
#include <atlctrls.h>
 
// https://msdn.microsoft.com/ja-jp/library/bb531404.aspx
#ifdef UNICODE
  #if defined _M_IX86
    #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
  #elif defined _M_IA64
    #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"")
  #elif defined _M_X64
    #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
  #else
    #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
  #endif
#endif
 
class TestWindow :
  public ATL::CWindowImpl<TestWindow>,
  public WTL::CMessageFilter
{
public:
  DECLARE_WND_CLASS(TEXT("Test Window Class"));
 
  bool Initialize(int cmdShow, _Inout_ WTL::CMessageLoop& msgLoop)
  {
    if (!Create(nullptr, CRect(0, 0, 200, 100),
      TEXT("Hello, world"), WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU))
    {
      return false;
    }
 
    ShowWindow(cmdShow);
    UpdateWindow();
 
    msgLoop.AddMessageFilter(this);
    return true;
  }
 
  BOOL PreTranslateMessage(_In_ MSG* msg) override
  {
    return IsDialogMessage(msg);
  }
 
  BEGIN_MSG_MAP(TestWindow)
    COMMAND_ID_HANDLER_EX(IDOK, OnOK)
    COMMAND_ID_HANDLER_EX(IDCANCEL, OnCancel)
    MSG_WM_CREATE(OnCreate)
    MSG_WM_DESTROY(OnDestroy)
  END_MSG_MAP()
 
private:
  void OnOK(UINT, int, HWND)
  {
    SendMessage(WM_CLOSE);
  }
 
  void OnCancel(UINT, int, HWND)
  {
    SendMessage(WM_CLOSE);
  }
 
  LRESULT OnCreate(const CREATESTRUCT*)
  {
    constexpr DWORD ButtonStyle =
      WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON;
    constexpr DWORD ButtonExStyle = WS_EX_NOPARENTNOTIFY;
    m_buttonOK.Create(
      *this, CRect(20, 20, 80, 50), L"OK",
      ButtonStyle, ButtonExStyle, IDOK);
    m_buttonCancel.Create(
      *this, CRect(100, 20, 160, 50), L"Cancel",
      ButtonStyle, ButtonExStyle, IDCANCEL);
 
    m_font = WTL::AtlCreateControlFont();
 
    m_buttonOK.SetFont(m_font);
    m_buttonCancel.SetFont(m_font);
 
    return 0;
  }
 
  void OnDestroy()
  {
    PostQuitMessage(0);
  }
 
  WTL::CFont m_font;
  WTL::CButton m_buttonOK;
  WTL::CButton m_buttonCancel;
};
 
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int cmdShow)
{
  if (!WTL::AtlInitCommonControls(ICC_STANDARD_CLASSES))
  {
    return -1;
  }
 
  WTL::CMessageLoop msgLoop;
  TestWindow wnd;
  if (!wnd.Initialize(cmdShow, msgLoop))
  {
    return -1;
  }
 
  return msgLoop.Run();
}

このコードは、Visual C++ 2015とWTL 9.1.5321 Finalでコンパイル・動作確認しました。

なお、ATL 7で導入されたATL::CAtlExeModuleTやATL::CAtlDllModuleTを活用しているプログラムに、あとからWTLを導入しようという場合、WTL::CAppModuleの入る隙がありません。そんなときも、この書き方が適用できます。

そんなわけで、邪道かもしれない、WTL::CAppModuleを使わないWTLプログラミングの話でした。ちなみに、昔書いた空のウィンドウを表示するだけのWindowsアプリケーション (WTL)でも、WTL::CAppModuleを使っていません。当時(それ以前)から、この書き方をずっとやっていたわけです。


スポンサード リンク

この記事のカテゴリ

  • ⇒ WTL::CAppModuleを使わない書き方