MSDN ライブラリ>Windows 開発>C++ による Windows プログラミングの学習>モジュール 1. 初めての Windows プログラム>アプリケーション状態を管理する
https://msdn.microsoft.com/ja-jp/library/ff381400(v=vs.85).aspx
今回は1-3で触れたウィンドウプロシージャをメンバ関数にする話です。
まず、ウィンドウを表すクラスのコンストラクタで呼び出している
CreateWindowEx()の最後の引数lpParamにthisポインタ,作成中のオブジェクト自身を渡します。
渡されたオブジェクトはWM_NCCREATE,WM_CREATEメッセージのlParamに渡される
CREATESTRUCT型のオブジェクトのメlpCreateParamンバに代入されます。
WM_NCCREATEでこれを回収し、 SetWindowLongPtr()関数でウィンドウハンドルと関連付けます。
GetWindowLongPtr()関数でハンドルに関連付けられたオブジェクトを取得できるので、
ウィンドウプロシージャ内でメンバ関数を呼び出すことが出来ます。
WM_NCCREATE,WM_CREATEはCreateWindowEx()の終了前に呼び出されるので
ウィンドウハンドルをウィンドウを表すオブジェクトのメンバに保存する処理は、
これらのメッセージの処理内で行うようにします。
CreateWindowEx
https://msdn.microsoft.com/ja-jp/library/cc410714.aspx
SetWindowLongPtr()
https://msdn.microsoft.com/ja-jp/library/cc411204.aspx
GetWindowLongPtr()
https://msdn.microsoft.com/ja-jp/library/cc364762.aspx
class Form { public: static LRESULT CALLBACK WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); private: LRESULT WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam); HWND hwnd_; public: Form(); virtual ~Form(); bool Show(); };
Form::Form() { // ウィンドウ クラスを登録する const wchar_t CLASS_NAME[] = L"Form"; WNDCLASSEXW wc = {}; wc.cbSize = sizeof(WNDCLASSEXW); wc.lpfnWndProc = Form::WindowProc; wc.lpszClassName = CLASS_NAME; Application::Instance().RegisterWindowClass(wc); // ウィンドウを作成する CreateWindowEx( 0, // オプションのウィンドウ スタイル CLASS_NAME, // ウィンドウ クラス L"Title", // ウィンドウ テキスト WS_OVERLAPPEDWINDOW, // ウィンドウ スタイル // サイズと位置 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, // 親ウィンドウ NULL, // メニュー Application::Instance().getHandle(), // インスタンス ハンドル this // 追加のアプリケーション データ ); } /// static版ウィンドウプロシージャ LRESULT CALLBACK Form::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { // ウィンドウ作成時メッセージ if (uMsg == WM_NCCREATE) { // lParamからCREATESTRUCTを取り出す。 CREATESTRUCT *pCreate = reinterpret_cast<CREATESTRUCT*>(lParam); // CREATESTRUCTからウィンドウオブジェクトを取り出す。 Form* f = reinterpret_cast<Form*>(pCreate->lpCreateParams); // ウィンドウハンドルを保存 f->hwnd_ = hwnd; // ウィンドウオブジェクトとハンドルを関連付け SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(f)); } { // ウィンドウハンドルに関連付けられたウィンドウオブジェクトを取得する LONG_PTR ptr = GetWindowLongPtr(hwnd, GWLP_USERDATA); if (ptr != 0) { // 関連付けされていた場合 // メンバ関数版ウィンドウプロシージャを呼び出す。 Form *f = reinterpret_cast<Form*>(ptr); return f->WindowProc(uMsg, wParam, lParam); } else { //関連付けられていなければデフォルトの処理を実行 return DefWindowProc(hwnd, uMsg, wParam, lParam); } } } /// メンバ版ウィンドウプロシージャ LRESULT Form::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) { //とりあえずデフォルト処理 return DefWindowProc(hwnd_, uMsg, wParam, lParam); }
最後にこれらの処理をまとめて基底クラスへ移動します。
class Wnd { public: static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); protected: virtual LRESULT WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam); HWND hwnd_; public: Wnd(); virtual ~Wnd(); }; /// static版ウィンドウプロシージャ LRESULT CALLBACK Wnd::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { // ウィンドウ作成時メッセージ if (uMsg == WM_NCCREATE) { // lParamからCREATESTRUCTを取り出す。 CREATESTRUCT *pCreate = reinterpret_cast<CREATESTRUCT*>(lParam); // CREATESTRUCTからウィンドウオブジェクトを取り出す。 Wnd* f = reinterpret_cast<Wnd*>(pCreate->lpCreateParams); // ウィンドウハンドルを保存 f->hwnd_ = hwnd; // ウィンドウオブジェクトとハンドルを関連付け SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(f)); } { // ウィンドウハンドルに関連付けられたウィンドウオブジェクトを取得する LONG_PTR ptr = GetWindowLongPtr(hwnd, GWLP_USERDATA); if (ptr != 0) { // 関連付けされていた場合 // メンバ関数版ウィンドウプロシージャを呼び出す。 Wnd *f = reinterpret_cast<Wnd*>(ptr); return f->WindowProc(uMsg, wParam, lParam); } else { //関連付けられていなければデフォルトの処理を実行 return DefWindowProc(hwnd, uMsg, wParam, lParam); } } } /// メンバ版ウィンドウプロシージャ LRESULT Wnd::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) { //とりあえずデフォルト処理 return DefWindowProc(hwnd_, uMsg, wParam, lParam); } Wnd::Wnd(){} Wnd::~Wnd(){}
class Form:public Wnd { protected: LRESULT WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam); public: Form(); virtual ~Form(); bool Show(); }; Form::Form() { // ウィンドウ クラスを登録する const wchar_t CLASS_NAME[] = L"Form"; WNDCLASSEXW wc = {}; wc.cbSize = sizeof(WNDCLASSEXW); wc.lpfnWndProc = Wnd::WindowProc; wc.lpszClassName = CLASS_NAME; Application::Instance().RegisterWindowClass(wc); // ウィンドウを作成する //this->hwnd_ = CreateWindowEx( 0, // オプションのウィンドウ スタイル CLASS_NAME, // ウィンドウ クラス L"Title", // ウィンドウ テキスト WS_OVERLAPPEDWINDOW, // ウィンドウ スタイル // サイズと位置 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, // 親ウィンドウ NULL, // メニュー Application::Instance().getHandle(), // インスタンス ハンドル this // 追加のアプリケーション データ ); } Form::~Form(){} bool Form::Show() { BOOL b = ShowWindow(hwnd_, Application::Instance().getCmdShow()); return (b != 0); } /// メンバ版ウィンドウプロシージャ LRESULT Form::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) { return Wnd::WindowProc(uMsg, wParam, lParam); }