- ベストアンサー
WM_CREATE について
Windows API の勉強を始めた者です。 CreateWindow関数を使ったときに発行されるWM_CREATEについて質問させていただきます。 以下のようなプログラムを作りました。このプログラムはウインドウを作るプログラムなのですが、はじめにウインドウを作るかどうかをWindowProcの中で聞いています。 このプログラムでウインドウを作らないという選択肢をとった時が分かりません。 WindowProcでは return -1 をするのでウインドウは作られず、従ってhWndにはNULLが入ります。そして次の文で、 if (hWnd == NULL) { MessageBox(NULL,TEXT("CreateWindow failed"),NULL,MB_OK); return 0; } メッセージボックスが表示されてからプログラムが終了すると思ったのですが、実際にはメッセージボックスは表示されませんでした。 なぜでしょうか。return -1 をした時点で、ウインドウが作られないのでWM_DESTROYがウインドウプロシージャにSendされるのかと考えたのですが、そうなのでしょうか。 よろしくお願いします。 /* 作ったプログラム */ #include <windows.h> LRESULT CALLBACK WindowProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { int YESNO; switch(uMsg) { case WM_DESTROY: PostQuitMessage(0); return 0; case WM_CREATE: YESNO = MessageBox(NULL, TEXT("Create a new window?"), ((LPCREATESTRUCT)lParam)->lpszName, MB_YESNO); if (YESNO == IDYES) return 0; if (YESNO == IDNO) return -1; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow) { WNDCLASS wc; ATOM atom; MSG msg; HWND hWnd; wc.style = CS_HREDRAW| CS_VREDRAW; wc.lpfnWndProc = WindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = NULL; wc.hCursor = NULL; wc.hbrBackground = (HBRUSH)COLOR_BACKGROUND + 1; wc.lpszMenuName = NULL; wc.lpszClassName = TEXT("sample_window"); if ((atom = RegisterClass(&wc)) == 0) { MessageBox(NULL,TEXT("RegisterClass failed"),NULL,MB_OK); return 0; } hWnd = CreateWindow((LPCTSTR)atom, TEXT("Sampe window"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 400, 300, NULL, NULL, hInstance, NULL); if (hWnd == NULL) { MessageBox(NULL,TEXT("CreateWindow failed"),NULL,MB_OK); return 0; } while (GetMessage(&msg, NULL, 0, 0) > 0) { DispatchMessage(&msg); } return msg.wParam; }
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
こんばんは。御礼頂きました。 >>WM_CREATEメッセージが送られた後にWM_DESTROYが送られるのは、なぜなのでしょうか?return -1 をすることでウインドウが破棄されるのでDestroyWindow()関数が使われるためなのでしょうか。 に関してですが、流石に当方もWindows OSの実装者では無いので其処までは分かりません・・・。 ただ、想像する分には、そのサイトの一番下にも書いて有る様に、「GetMessage()に到達するまでの間に必要なコールバックはKiUserCallbackDispatcher()を介して行われる」と言うのですから、その中でWM_CREATEを呼び出して戻り値を確認し、エラー値が返された場合は即座にWM_DESTROYを呼び出しているのではないでしょうか。 此れならば、GetMessage()に到達していなくても、WM_DESTROY位は呼び出せる筈です。 単純な関数ポインタの呼び出し見たいな感覚で行われる物なのかもしれません。 >>もう一点に関して 取り敢えずPostQuitMessage()をコメントアウトしてWM_CREATEに失敗させると(メッセージループは無くても同じ)、MessageBox()が表示されました(Windows2000 sp4 VC++6.0で試しています)。 確かにPostQuitMessage()があると、MessageBox()が表示されなかったです(ただしサウンドだけは鳴った)。 今まで色々とWindows関連のサイトなどを見てきましたが、流石にココまでメスを入れていたものは見た事がありません。 海外から輸入されて来ているWindows関連の詳しい書籍であれば、こう言った詳細が書かれているかもしれません。
その他の回答 (3)
MessageBoxは呼ばれてますよ デバッガでステップ実行でもすれば(しなくてもですけど)ifに入ってメッセージボックスが出る音が出てます 戻り値もGetLastErrorもエラー無しな値しか返しませんし表示されない理由もわかりませんけど
お礼
回答をありがとうございます。 回答者様のおっしゃるとおり、メッセージボックスの音が出ていました。 これはつまり、メッセージボックスは表示はされていないが、 if (hWnd == NULL) のところのreturn 0; でプログラムが終了しているのですね。 なぜ表示されないかについてはいろいろ調べてみたいと思います。 回答をありがとうございました。
- machongola
- ベストアンサー率60% (434/720)
こんにちは。 WM_DESTROYの中にMessageBox()を置きます。 また、WM_CREATEはCreateWindow()APIの内部でメッセージループに先立って呼び出される物です。 http://keicode.com/windows/win01.php ですのでWM_CREATEで失敗させる分には while (GetMessage(&msg, NULL, 0, 0) > 0) { DispatchMessage(&msg); } が無くてもWM_DESTROYが呼び出されます。 WM_DESTROYの下にあるPostQuitMessage()が呼び出されて終了したため、MessageBox()が出なかったのだと思います。 また、WM_CREATEが呼び出される順番は、 (1)WM_GETMINMAXINFO (2)WM_NCCREATE (3)WM_NCCALCSIZE (4)WM_CREATE と言う事で、四番目に位置します。
お礼
回答をありがとうございます。 参考ページをありがとうございます。いろいろ細かいところまであり参考になります。 なお、気になった点があるのですが、どうなのでしょうか。 WM_CREATEメッセージが送られた後にWM_DESTROYが送られるのは、なぜなのでしょうか?return -1 をすることでウインドウが破棄されるのでDestroyWindow()関数が使われるためなのでしょうか。 もう一点は、WM_DESTROYメッセージが送られた後、PostQuitMessage()関数が呼びだされます。 これはWM_QUITをメッセージキューにポストします。WM_QUITはGetMessage()関数にメッセージループの終了を通知するもので対象がウインドウプロシージャではないと思うのですが、もしそうするとメッセージキューからWM_QUITメッセージを取り出すにはGetMessage()関数が必要で、このプログラムが終了するにはWM_QUITを取り出さなければなりません(もしくはreturn 0 に到達する)。しかし、それ以前にメッセージボックスを出す命令がありますから、やはりメッセージボックスが出ると思うのですが、どうでしょうか? よろしくお願いします。
- Nitar
- ベストアンサー率23% (5/21)
WindowProc はメッセージループに入ってから呼び出される物として記憶しています。つまりWM_CREATEが生じたときには既に while (GetMessage(&msg, NULL, 0, 0) > 0) { DispatchMessage(&msg); } の中にいるのではないかと。 WM_CREATEで判断している以上、メッセージボックスを出したいのであればWM_DESTROYの分岐で書くのが自然な気がします。
お礼
素早い回答をありがとうございます。 私の方では、CreateWindow()関数はメッセージループに入る前の段階でウインドウプロシージャにメッセージを送ると考えています。 このプログラムではメッセージループの前の段階でコメントボックスを出すように書かれているため、どうやらこのプログラムはメッセージループに入ることなく終了しているようなのです。どうもその辺りの動きが分かりません。 回答をありがとうございました。
お礼
回答をありがとうございます。 回答者様のおっしゃる通り、PostQuitMessage()をコメントアウトしてWM_CREATEを失敗させるとMessageBoxが表示されました。ということは確かにWM_DESTROYのケースが行われている訳ですが、PostQuitMessage()が存在する場合でもMessageBoxのサウンドだけなるということは、やはり if (hWnd == NULL) のところのreturn 0; でプログラムが終了しているようです。 なぜ表示されないかについては興味深いのでもう少し他の書籍で勉強してみたいと思います。 何度もの詳しい回答、参考ページの紹介など、いろいろ本当にありがとうございました。