読者です 読者をやめる 読者になる 読者になる

ウィンドウのクラス化(WindowsAPI)

「ウィンドウをただ表示する」からかなりハードルが上がって、Win32だとクラスを自作しないといけないので、ウィンドウをクラス化してみる・・・。
MFC風な設計をベースに、いろいろ試行錯誤してなんとかクラスに押し込めている・・・。

まず、WinMain.cppに_tWinMain関数の定義を書く・・・。

CApplicationはアプリケーションクラス、MFCだとCWinAppにあたる・・・。
その派生クラスのCMainApplicationのオブジェクトを作成し、ポインタをpAppに格納・・・。
pApp->InitInstanceで最初の処理・・・というか、ウィンドウの作成と表示をしている・・・。
失敗したら、pApp->ExitInstanceで終了処理をするし、成功すれば、pApp->Runでメッセージループに入る・・・。

Application.hを見ると、InitInstanceだけ純粋仮想関数にしているので、派生クラスのMainApplicationで実際の処理を書かないといけない・・・。

それ以外の部分は、Application.cppにある・・・。

RunのメッセージループはPeekMessageでメッセージが来ていたらディスパッチするし、来ていなかったらOnIdleでアイドル処理・・・。
最後に終了処理ExitInstanceもしてる・・・。

メンバにはウィンドウクラスCWindowのポインタm_pWindowもあった・・・。
CWindowは、

こんな感じで、結構いろいろある・・・。

ウィンドウハンドルと、CWindowオブジェクトポインタを紐づけるためのマップm_mapWindowMapをstaticで用意していて、ここですべてのウィンドウの管理をしている・・・。

CWindowオブジェクト自体はウィンドウハンドルm_hWndと、このウィンドウを生成した場所であるアプリケーションオブジェクトのポインタm_pAppを持つ・・・。
(m_pAppを持つのは、m_pAppの情報を使いたい場合があるため・・・。)

RegisterClassはstaticにした・・・。
そして、メッセージループからディスパッチして、メッセージが届く先はStaticWindowProc・・・。
ここで、どのCWindowオブジェクトのどのハンドラ関数に処理を振り分けるかを決めている・・・。

とりあえずOnCreateとOnDestroyを宣言・・・。
これらも純粋仮想関数なので派生クラスMainWindowでオーバーライドする・・・。

RegisterClassではウィンドウクラス名は"CWindow"固定にして、ウィンドウプロシージャもCWindow::StaticWindowProcにしている・・・。
それ以外も既定のものをつかうように指定している・・・。

StaticWindowProcは、

lpCreateStruct->lpCreateParamsをCWindowオブジェクトポインタpWindowにキャストして、プロシージャに渡されたhwndとpWindowのセットでm_mapWindowMapに登録している・・・。
これは、

ウィンドウをCreateで作成するとき、CreateWindowの最後の引数にthisを指定してそのオブジェクトのポインタを渡している・・・。
それがWM_CREATEのときにlpCreateStruct->lpCreateParamsとして渡されるので、このように紐づけられる・・・。

WM_CREATEの時以外は、

m_mapWindowMapからhwndをヒントにCWindowオブジェクトポインタを探す・・・。

みつからない場合はDefWindowProcに任せ、みつかった場合はそのpWindow->DynamicWindowProcに任せる・・・。

pWindow->DynamicWindowProcでは、

WM_CREATEなら、そのウィンドウオブジェクトのOnCreateに、WM_DESTROYならOnDestroyに任せる・・・。

OnCreateとOnDestroyのオーバーライドは、MainWindow.cppに・・・。

このように、OnCreateなら"return 0"でウィンドウ作成成功、OnDestroyなら"PostQuitMessage(0)"でメッセージループ終了と単純なモノ・・・。

さて、このウィンドウ作成処理の呼び元、CMainApplication::InitInstanceは、

RegisterClassで"CWindow"登録したら、CMainWindowウィンドウオブジェクトを作成・・・。
ウィンドウサイズをrcにセットしたら、m_pWindow->Createで生成して、m_pWindow->ShowWindowで表示という流れ・・・。
CMainApplicationは、このInitInstanceのオーバーライドのみである・・・。

これで実行すると、

f:id:BG1:20160517114234p:plain

と普通にウィンドウが表示される・・・。
ただ、ウィンドウが表示されてるように見えるが、実際にはウィンドウオブジェクトごとに管理されている・・・。

とはいえ、まだいろいろ改善の余地はありそう・・・。
とりあえずはこの辺で・・・。

Test/WinMain.cpp at master · bg1bgst333/Test · GitHub
Test/Application.h at master · bg1bgst333/Test · GitHub
Test/Application.cpp at master · bg1bgst333/Test · GitHub
Test/Window.h at master · bg1bgst333/Test · GitHub
Test/Window.cpp at master · bg1bgst333/Test · GitHub
Test/MainApplication.h at master · bg1bgst333/Test · GitHub
Test/MainApplication.cpp at master · bg1bgst333/Test · GitHub
Test/MainWindow.h at master · bg1bgst333/Test · GitHub
Test/MainWindow.cpp at master · bg1bgst333/Test · GitHub