ウィンドウプロシージャをどうラップするか? – Life like a clown

そのvirtualなWndProcにだってメッセージクラッカーを使えるよ、むしろ使わない理由がないです。

1
2
3
4
5
6
7
8
9
10
11
12
13
virtual LRESULT WndProc(UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch (msg)
  {
    HANDLE_MSG(this->Handle(), WM_DESTROY, OnDestroy);
  }
  return DefWindowProc(this->Handle(), msg, wParam, lParam);
}
 
void OnDestroy(HWND)
{
  PostQuitMessage(0);
}

そもそも、HANDLE_MSGの中身は、関数呼出演算子に展開されるマクロなので、メンバ関数以外にもstd::bind, boost::bindやラムダ式(C++11)、Boost.Lambdaでもなんでもござれのはずです。まあ使う機会はないとは思いますけど。

ついでなので、ソースコード全体を下に載せます。この記事を作るにあたってささっと書いたので、綺麗ではないですけど。

std::map方式も良いのですが、ここではGWLP_USERDATAを使ってみました。WNDCLASSのcbWndExtraという手もありますね。

以下余談になりますが、WM_NCCREATEを使っているのは、WM_CREATEより前に呼ばれるという小さな理由です。ただ、WM_NCREATEより前に呼ばれるメッセージ(WM_GETMINMAXINFO)があるので完璧を追求するならこれでも駄目です。本格的なGUIライブラリを作るなら気に掛けたほうが良いかもしれません。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include <windows.h>
#include <windowsx.h>
#include <tchar.h>
 
class Window
{
public:
  Window() : hwnd() {}
 
  static bool InitInstance(HINSTANCE hinst)
  {
    WNDCLASS wc;
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hinst;
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = TEXT("Windows Class");
    wndClassAtom = RegisterClass(&wc);
    return wndClassAtom != 0;
  }
 
  bool Create(HINSTANCE hinst) // NT系のみならこの引数は不要。
  {
    return CreateWindow(
      reinterpret_cast<PCTSTR>(static_cast<ULONG_PTR>(wndClassAtom)),
      TEXT("Window"), WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
      NULL, NULL, hinst, this) != NULL;
  }
 
  HWND Handle() const {return hwnd;}
 
private:
 
  virtual LRESULT WndProc(UINT msg, WPARAM wParam, LPARAM lParam)
  {
    // ここではHandle()の参照にあえてthis->を付加しています。
    switch (msg)
    {
      HANDLE_MSG(this->Handle(), WM_DESTROY, OnDestroy);
    }
    return DefWindowProc(this->Handle(), msg, wParam, lParam);
  }
 
  void OnDestroy(HWND)
  {
    PostQuitMessage(0);
  }
 
  // ここから実装
 
  HWND hwnd;
 
  static ATOM wndClassAtom;
 
  static BOOL OnNCCreate(HWND hwnd, CREATESTRUCT const* pcs)
  {
    Window* pwnd = static_cast<Window*>(pcs->lpCreateParams);
    pwnd->hwnd = hwnd;
    SetWindowLongPtr(hwnd, GWLP_USERDATA, 
      reinterpret_cast<LONG_PTR>(pwnd));
    return TRUE;
  }
 
  static LRESULT CALLBACK WndProc(
    HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  {
    if (msg == WM_NCCREATE)
    {
      return OnNCCreate(hwnd,
        reinterpret_cast<CREATESTRUCT const*>(lParam));
    }
 
    Window* pwnd = reinterpret_cast<Window*>(
      GetWindowLongPtr(hwnd, GWLP_USERDATA));
    return pwnd->WndProc(msg, wParam, lParam);
  }
};
 
ATOM Window::wndClassAtom;
 
int WINAPI _tWinMain(
  HINSTANCE hinst, HINSTANCE, LPTSTR /*cmdLine*/, int cmdShow)
{
  if (!Window::InitInstance(hinst))
  {
    return -1;
  }
 
  Window wnd;
  if (!wnd.Create(hinst))
  {
    return -2;
  }
 
  ShowWindow(wnd.Handle(), cmdShow);
  UpdateWindow(wnd.Handle());
 
  MSG msg;
  for (;;)
  {
    int ret = GetMessage(&msg, NULL, 0, 0);
    if (ret == -1)
    {
      return -1;
    }
    else if (ret == 0)
    {
      return static_cast<int>(msg.wParam);
    }
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
}

スポンサード リンク

この記事のカテゴリ

  • ⇒ メッセージクラッカー with C++
  • ⇒ メッセージクラッカー with C++