CREATESTRUCT.lpCreateParamsは以前も使ったけど、ウィンドウをC++クラス"CWindow"(名前はなんでもいいけど)として定義し、ウィンドウハンドルとこのCWindowオブジェクトポインタが1対1に対応した形になるようにするために使うのが真骨頂かと思う。
CREATESTRUCTA (winuser.h) - Win32 apps | Microsoft Docs
Window.hで、
CWindowオブジェクトはウィンドウハンドルm_hWndを持つ。
staticのm_mapWindowMapも重要。
ウィンドウ作成メンバ関数Create。
そして、個々のオブジェクトごとにウィンドウメッセージ処理するDynamicWindowProc。
Window.cppは、
CWindow::Createの中のCreateWindowの最後の引数にthisを渡してる。
つまりCWindowオブジェクト自身のポインタが、CREATESTRUCT.lpCreateParamsに格納されることになる。
ParentWindow.hは、
CParentWindowは、CWindowの派生で、CChildWindowのポインタm_pChildWindowを持っていて、あとはDynamicWindowProcのオーバーライド。
ParentWindow.cppで、
子ウィンドウを作成し、ポインタはm_pChildWindowに格納。
ChildWindow.hは、
こちらのCChildWindowもCWindow派生。
ChildWindow.cppは、
こちらは特に中で子ウィンドウなどを作成はしない。
最後にCREATESTRUCT.cppで、
親ウィンドウCParentWindowの作成。
そして、CChildWindowもCParentWindowもウィンドウクラス"CREATESTRUCT"を指定しているので、WindowProcがウィンドウプロシージャになり、最初はここにウィンドウメッセージ処理が来る。
WM_CREATEで、lpCreateStruct->lpCreateParamsにオブジェクトポインタが入ってるので、ウィンドウハンドルをキー、ポインタを値としてCWindow::m_mapWindowMapに登録する。
WM_CREATEでない場合は、ハンドルを指定して、ポインタを取り出す。
ポインタが無ければDefWindowProcだが、ポインタがあればそのポインタが指すオブジェクトのDynamicWindowProcに処理を任せることになる。
こういう形で、最初のウィンドウプロシージャを統一しながらも、それぞれのウィンドウごとに具体的な処理をするウィンドウプロシージャを分けている。
最初に親ウィンドウを作る部分。
最初はこっちに来る。
WM_CREATEが来た時はこっちに。
そのあとはそれぞれのDynamicWindowProcの方に。
まずは親ウィンドウなのでこっち。
今度は子ウィンドウのWM_CREATEかな。
個々のDynamicWindowProcに。
今度は子ウィンドウのココに来る。
WM_CREATE以外の個別の処理。
ここにきて、
ここにくる。
ブレークポイントを無効にすると、
こんな感じでウィンドウが表示される。
閉じると、
親ウィンドウのココに来る。
_tWinMainの終盤でメッセージループ抜けたらCParentWindowオブジェクトを破棄しているが、そのデストラクタで子ウィンドウCChildWindowオブジェクトも破棄してる。
Sample/winapi/CREATESTRUCT/lpCreateParams/src/CREATESTRUCT at master · bg1bgst333/Sample · GitHub