WindowsプログラムのウインドウプロシージャからC++のウインドウクラスにアクセスする方法

WIN32でWindowsプログラム作ろうと思って検討した内容のメモ。

WIN32のプログラムって、ウインドウプロシージャ(WndProcなど)の関数をコールバック関数にして、普通はここに巨大なswitch文があってメッセージを振り分ける構造になっています。

また、C++ではWindowsのウインドウにクラス(C++のクラス)を対応させて、普通は作ります。

この時に、ウインドウプロシージャから、どうやってウインドウクラスのオブジェクトを見れるようにするか、というのでちょっと悩んでしまったので、オープンソースプラグラムでその辺の設計をどうしてるか調べてみました。

見てみたのは、Notepad++(http://sourceforge.net/projects/notepad-plus/)とFLTK(http://www.fltk.org/)。WindowsC++であまり規模が大きすぎないオープンソースということで参考にさせていただいきました。

GWL_USERDATAにオブジェクトポインタを関連付ける(Notepad++)

以下のようにする。Windowsプログラムではそこそこ一般的な方法みたい。

  • メインのCreateWindow関数のlpParamにthisを渡す
  • WM_NCCREATEメッセージで以下のようにポインタを取得し、GWLP_USERDATAに設定する
Notepad_plus_Window *pM30ide = (Notepad_plus_Window *)(((LPCREATESTRUCT)lParam)->lpCreateParams);
::SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pM30ide);
  • その後のメッセージ処理は、以下のようにメインウインドウのポインタを取得して行う
Notepad_plus_Window *pM30ide = (Notepad_plus_Window *)::GetWindowLongPtr(hwnd, GWL_USERDATA))->runProc(hwnd, Message, wParam, lParam);

もしかしたらWM_NCCREATEじゃなくWM_CREATEでもポインタは取れるかも(未確認)。

グローバルにデータを置かないですむという利点があると思う。

複数ウインドウオブジェクトをハンドルに関連付けて管理 (FLTK)

ちゃんと読めてないから、間違っているかもしれないけど、複数のウインドウをリストで管理しているデータ構造があり、ウインドウハンドルを引数にしてウインドウプロシージャの頭でウインドウクラスを取得してるっぽい。データ自体はグローバルにおいてるように見える。

複数のウインドウを考慮された設計かな?

また、2つの方法を合わせたやり方もある気がする。。。