• ベストアンサー

CALLBACK 内の DefWindowProc の場所

こんにちは、最近 無料版Borland C++Compiler 5.5 を使って WIN32 API の勉強をしています 気にしなければ別に問題ないのですが、どうしても気になって気持ち悪いので、質問させて下さい 参考書や Web でコード例を見ていると、CALLBACK 内の DefWindowProc関数 を switch の default にする例 と switch の default を書かずに CALLBACK の return にする例があります 好みの問題なのでしょうか? switch は、 default を入れた方が正式と思いますが、default に DefWindowProc を記述すると コードが長くなるにつれ DefWindowProc が switch 内でちょこちょこ必要になってきます 私は、switch の default があった方が良いかなと思い DefWindowProc を default に記述していますが、コードが短くなるなら CALLBACK の return に DefWindowProc を記述しようと思っています どちらが良いのでしょうか? 暇な時でかまいませんので、ご教授下さい 宜しくお願い致します ※DefWindowProc の 記述場所を CALLBACK の return にする LRESULT CALLBACK WindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) {   switch(uMsg){     case WM_DESTROY:     PostQuitMessage(0);     break;   }   /*基本的なメッセージの処理*/   return DefWindowProc(hWnd, uMsg, wParam, lParam); } ※DefWindowProc の 記述場所を switch の default にする LRESULT CALLBACK WindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) {   switch(uMsg){     case WM_DESTROY:     PostQuitMessage(0);     break;   default:     /*基本的なメッセージの処理*/     return DefWindowProc(hWnd, uMsg, wParam, lParam);   }   return 0; }

質問者が選んだベストアンサー

  • ベストアンサー
  • anmochi
  • ベストアンサー率65% (1332/2045)
回答No.2

 私個人は前者の方が良い(default無し)と思う。  そもそもswitchにdefaultを入れるのが正式という考えがよく分からん。defaultはif構文で言えばelseにあたる。if構文にelseに当たる処理が無ければいちいち書いたりしないように、switch文でもdefaultにあたる処理が無ければ書かない方が正式なのではないかな。どうしても正式なら、前者のプログラムでdefaultブロックを書いた上で処理を空白にしておけば良い。  さて、前者と後者でプログラムの意味を考えると、WindowProcがリターンする値の意味は当然メッセージによって変わってくるので、なんでもかんでも0を返せば良いという訳ではない。そういう意味で後者のプログラムでWM_DESTROYメッセージのハンドル後に0を返しているのは意味が分かってやっているなら問題ないが、これは安全な方法とは言えないだろう。  仮に、WindowsがWindowProcからメッセージに対する不正なリターン値を受け取ったらエラーを表示するような仕組みになっていた場合、前者のプログラムは安全性(Windowsにリターンする値がWindowsが定義した値になるため)を、後者のプログラムは完全性(エラーというかリターン値の不正をきちんとエラーとして処理させる)を取った形式と言える。また、Microsoftはパラノイアと言っても良いくらいAPIの互換性に気を使っているが、WM_DESTORYを処理した後でWindowsに返すべき値がWindows 95とWindows Vistaでは違うというパターンもおこりうるだろう。その場合も0固定で返すよりもDefWindowProcを返す方が良いと言える。  リターン値が特別になるのなら個別に返すべきだ。仮に、PostQuitMessage()に失敗したら-1を返さなきゃいけない仕様になっていたとしたら、 LRESULT CALLBACK WindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) {   switch(uMsg){     case WM_DESTROY:     if(PostQuitMessage(0) == ERR_FAILER){       return -1;     }     break;   }   return DefWindowProc(hWnd, uMsg, wParam, lParam); } として、CASE WM_DESTORY内で独自に-1を返してやれば良いだけだ。

breeze2000
質問者

お礼

anmochi 様 ご回答有難う御座います なるほど~、良く解りました 特に >なんでもかんでも 0 を返せば良いという訳ではない。 >ハンドル後に 0 を返しているのは意味が分かってやっているなら問題ない の所が、私のような初心者の場合は、意味が解ってない事もあると思いますので、CALLBACK の return に DefWindowProc を使った方が良いと思いえました 私の所持する参考書(複数)は、両方の書き方があったので、どちらが良いのか気持ち悪かったのですが、すっきりしました 有難う御座いました それと >switch は、 default を入れた方が正式と思いますが この書き方は良く無かったです、ごめんなさい switch の構文や if 文 など、全部(default や else) を使って完結させた方が、私の個人的な所で、正式っぽい様な感じがする の方が良い表現だったと思います ( あまり深く考えてませんでしたので、スルーでお願い致します )

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (1)

回答No.1

お疲れ様です。 ほぼ、好みの問題です。 例えばウィンドウの「×」ボタン押下などにより「WM_CLOSE」メッセージを受信した時に、ウィンドウを閉じないよう「DefWindowProc」を実行したくない場合などがあります。 そんな時、前者の書き方ではswitch-case内でreturn文を記載する必要があり、プログラムの流れが見にくくなる可能性があります。 後者では、DefWindowProcを各case文の中に含める必要があります。 どちらが良いとも言えないでしょう。

breeze2000
質問者

お礼

hiro_knigh 様 ご回答有難う御座います >ほぼ、好みの問題です。 やっぱり好みなんですね 今読んでいる参考書が、switch 内の default に DefWindowProc を記述しています 前に読んでいた参考書が、CALLBACK の return に DefWindowProc を記述しています 前に読んでいた方が C がベースで、今読んでいる方が CPP がベースです 読んでいる参考書が新しい ( 出版に5年位の差が有ります ) ので、新しい方が良い記述方法なのかな、でも私のコードは DefWindowProc が増えてやだなぁ と思っていた所です これで、参考書の DefWindowProc の部分を置き換えて、すっきり 読んで行けます 有難う御座いました

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • 子ウインドウの作成と破棄について

    CALLBACK のみを書きました。 メインウインドウを破棄したら 子ウインドウも破棄したいのですが、 うまく出来ません。 どうすればよろしいでしょうか? よろしくお願いします。 #include<windows.h> #include"ChildWindow.h" char MainWindowClassName[]="mainwindow"; LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) { static HWND childWnd; switch(message) { case WM_ACTIVATEAPP: childWnd=Child_CreateWindow(hWnd,message,wParam,lParam); break; case WM_DESTROY: DestroyWindow(childWnd); PostQuitMessage(0); break; default: return DefWindowProc(hWnd,message,wParam,lParam); } } ///////////////////////////////////////////// #include<windows.h> char ChildWindowClassName[]="childwindow"; LRESULT CALLBACK ChildProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) { switch(message) { case WM_LBUTTONDOWN: MessageBox(NULL,"","",MB_OK); break; default: return DefWindowProc(hWnd,message,wParam,lParam); } } ATOM Child_RegistWindow(HINSTANCE hInstance){} HWND Child_InitInstance(HWND hParentWnd,HINSTANCE hInst,int CmdShow){} HWND Child_CreateWindow(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) { int CmdShow=1; Child_RegistWindow(NULL); HWND ChildWnd=Child_InitInstance(hWnd,NULL,CmdShow); MSG msg; while(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return ChildWnd; }

  • 別関数に渡す変数のポインタが難しい

    構造体初心者で、ポインタもよく分かっていません。 12, 8 と表示するつもりのソースだけど、実行結果は違っていました。 直してください。 ソースは長いけど、スケルトンに構造体とTextOutを付けたぐらいのものです。 #include <windows.h> struct MYOBJ { int a; int b; }; LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int) { MSG msg; WNDCLASS wc; 投稿できなかったからここを消しました。 wc.lpszClassName = "x"; if(RegisterClass(&wc) == 0)return 0; HWND hWnd = CreateWindow("x","",WS_OVERLAPPEDWINDOW|WS_VISIBLE,0,0,320,240,NULL,NULL,hInst,NULL); while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } void myfunc(struct MYOBJ *obj)//ここが違うかもしれません。 { obj->a += 2; obj->b -= 2; } LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { HDC hDC; PAINTSTRUCT ps; char buf[30]; switch(uMsg) { case WM_CREATE: struct MYOBJ myobj; myobj.a = 10; myobj.b = 10; myfunc(&myobj);//ここが違うかもしれません。 return 0; case WM_PAINT: hDC = BeginPaint(hWnd, &ps); wsprintf(buf, "%d, %d", myobj.a, myobj.b); TextOut(hDC, 0, 0, buf, strlen(buf)); EndPaint(hWnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; default: return DefWindowProc(hWnd, uMsg, wParam, lParam); } return 0; }

  •    ダイアログのクラス化で仮想関数を用いて派生クラスにしているんです

       ダイアログのクラス化で仮想関数を用いて派生クラスにしているんですが・・・ ダイアログを基本クラスで静的プロシージャと派生クラスでオーバーライドしてプロシージャを使いたい のですが、どうしても自身のポインタが取得できません。 以下にソースを載せておきます。  class CBaseWnd  {  public:    // ポインタの設定    void SetPointer( HWND hWnd );    // ウィンドウプロシージャの呼び出し    static LRESULT CALLBACK CallProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );    // ウィンドウプロシージャの実装    virtual LRESULT MainProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );  }; [クラスの実装]  //===== ポインタの設定 =====//  void CBaseWnd::SetPointer( HWND hWnd )  {    SetWindowLong( hWnd, GWL_USERDATA, (LONG)this );  }  //===== ウィンドウプロシージャの呼び出し =====//  LRESULT CALLBACK CBaseWnd::CallProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )  {    //_プロパティリストからthisポインタを取得 //ここでポインタを取得することができないでいます。値が0です。 //先にSetWindowlongをやっても値が0のままです。    CBaseWnd* thisPtr = (CBaseWnd*)GetWindowLong( hWnd, GWL_USERDATA );    //_thisポインタが取得できなかった場合...    if( ! thisPtr )    {      //_ウィンドウの作成時の場合... //ここでアクセス違反というエラーが起きる      if( message == WM_INITDIALOG )        thisPtr = (CBaseWnd*)((LPCREATESTRUCT)lParam)->lpCreateParams;      //_thisポインタが取得できた場合...      if( thisPtr )      {        //_プロパティリストにオブジェクトハンドル(thisポインタ)を設定する        thisPtr->SetPointer( hWnd );      }    }    //_thisポインタが取得できた場合...    if( thisPtr )    {      LRESULT lResult = thisPtr->MainProc( hWnd, message, wParam, lParam );      return lResult;    }    return DefWindowProc( hWnd, message, wParam, lParam );  }  //===== ウィンドウプロシージャの実装(継承可能) =====//  // ここでの記述はデフォルトの処理  //  LRESULT CBaseWnd::MainProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )  {    switch( message )    {      //_ウィンドウが破棄された場合      case WM_DESTROY:        PostQuitMessage(0);        return 0;        //_デフォルトの場合      default:        return DefWindowProc( hWnd, message, wParam, lParam );    }  } WM_INITDIALOGでダイアログの初期化中にポインタを取得しようとしますが、アクセス違反が起こり失敗します。 どなたか分かる方がいらっしゃったらご指摘お願いします。

  • WindowsSDKのCALLBACK内について

    猫でも分かるWindowsSDKを参考にして、とりあえずウィンドウプロシージャの関数内を下のようにしてプログラムを組んでみました。 //ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { switch (msg) { case WM_CREATE: break; case WM_TIMER: break; case WM_PAINT: break; case WM_COMMAND: break; case WM_CLOSE: SendMessage(hWnd, WM_DESTROY, wp, lp); break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0L; } しかし、これで何もないWindow表示をさせるとCPU使用率が80%くらいまで跳ね上がります。 調べてみたところcase WM_PAINT:を削ったらCPU使用率が下がりました。 普通にクライアント領域に文字を表示したり画像を表示したりするだけだったら、それほどCPU使用率が上がらないのに、上のようにあらかじめ用意しておいたらCPU使用率が跳ね上がるのは何故でしょうか。 まだ勉強したてでレベルの低い質問でしたらすみません。

  • WM_NCLBUTTONUPについて

    タイトルバー上でのマウスボタンのアップを検出したいので、 WM_NCLBUTTONUPメッセージを拾うために、単純に以下のようなコードを書きました。 が、このコードではうまくWM_NCLBUTTONUPメッセージを拾えません。 ウィンドウを最大化しているときは問題なくメッセージを拾えるのですが、 それ以外の時(縮小表示)はメッセージを拾えません。 ただ、WM_NCLBUTTONDOWNは正しく拾うことができました。 ウィンドウが縮小表示になっている時にWM_NCLBUTTONUPを取得する場合には何か特殊な処理が必要なんでしょうか? ご存知の方がいらっしゃったら、よろしくお願いします。 // ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_NCLBUTTONUP: MessageBox(hWnd, "UP", "LBUTTON", MB_OK); return 0; case WM_DESTROY: // ウインドウが破棄されたときの処理 PostQuitMessage(0); return 0; default: // デフォルトの処理 return DefWindowProc(hWnd, message, wParam, lParam); } }

  • なぜhButton1ボタンからのWM_COMMANDはフックできてクライアントエリアのWM_RBUTTONDOWNはフックできないのでしょうか?

    #define STRLBUTTON TEXT("マウス左ボタンが押されました from mainProc") #define STRRBUTTON TEXT("マウス右ボタンが押されました from my_HookProc") #define STRCOMMAND TEXT("ボタンが押されました") HWND hButton1; LRESULT CALLBACK my_HookProc(int nCode, WPARAM wParam, LPARAM lParam) { CWPRETSTRUCT *pcwpRetStruct = (CWPRETSTRUCT *)lParam; HDC hDC; if(nCode==HC_ACTION) { hDC = GetDC(pcwpRetStruct->hwnd); switch(pcwpRetStruct->message) { case WM_COMMAND: TextOut(hDC, 10, 10, STRCOMMAND, strlen(STRCOMMAND)); break; case WM_RBUTTONDOWN: TextOut(hDC, 10, 10, STRRBUTTON, strlen(STRRBUTTON)); break; } ReleaseDC(pcwpRetStruct->hwnd, hDC); } return CallNextHookEx(NULL, nCode, wParam, lParam); } LRESULT CALLBACK mainProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static HHOOK hHook; HDC hDC; switch(uMsg) { case WM_DESTROY: UnhookWindowsHookEx(hHook); PostQuitMessage(0); return 0; case WM_CREATE: hHook = SetWindowsHookEx(WH_CALLWNDPROCRET, my_HookProc, NULL, GetCurrentThreadId() ); if(!hHook) MessageBox(NULL, "hooking failed", NULL, MB_OK); hButton1 = CreateWindow( "BUTTON", "hButton1", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 10, 40, 100, 20, hWnd, NULL, ((LPCREATESTRUCT)lParam)->hInstance, NULL ); return 0; case WM_LBUTTONDOWN: hDC = GetDC(hWnd); TextOut(hDC, 10, 10, STRLBUTTON, strlen(STRLBUTTON)); ReleaseDC(hWnd, hDC); return 0; } return DefWindowProc(hWnd, uMsg, wParam, lParam); }

  • CTreeCtrlのCreate関数でエラーになります。

    Visual C++ .NET Win32 プロジェクト で、アプリケーションを作成しようと思っています。 #include<afxwin.h> #include<afxcmn.h> // マルチスレッド CTreeCtrl *m_TreeCtrl; LRESULT CALLBACK int WindowProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) { switch(message) { case WM_LBUTTONDOWN: m_TreeCtrl=new CTreeCtrl; m_TreeCtrl->Create(WS_VISIBLE | WS_TABSTOP | WS_CHILD | WS_BORDER | TVS_HASBUTTONS | TVS_LINESATROOT | TVS_HASLINES | TVS_DISABLEDRAGDROP, CRect(10, 10, 300, 100), CWnd::FromHandle(hWnd), 10000); break; case WM_CREATE: break; case WM_DESTROY: PostQuitMessage(0); break; case WM_PAINT: HDC hDC; PAINTSTRUCT Paint; hDC=BeginPaint(hWnd,&Paint); EndPaint(hWnd,&Paint); } return DefWindowProc(hWnd,message,wParam,lParam); } ・・・ と記述すると、エラーになります。 解決方法を教えてください。

  • C++ WIN32 ウィドウの表示

    プログラミング初心者です。 WIN32APIの勉強を始めたばかりの状態です。 本を見ながら、ウィンドウを表示させるだけのプログラムを書いてみたのですが、エラーになってしまいます。 #include <windows.h> //ウィンドウ・クラス名 #define MYWNDCLSNAME "MyWindowClass" LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) { WNDCLASS wndcls; HWND hWnd; MSG msg; //ウィンドウ・クラスを登録 ZeroMemory(&wndcls, sizeof(wndcls)); wndcls.lpfnWndProc = WndProc; wndcls.hInstance = hInst; wndcls.hIcon = LoadIcon(0, IDI_APPLICATION); wndcls.hCursor = LoadCursor(0, IDC_ARROW); wndcls.hbrBackground = (HBRUSH)COLOR_BACKGROUND; wndcls.lpszClassName = MYWNDCLSNAME; if(RegisterClass(&wndcls) == 0) return -1; //メイン・ウィンドウを作成 hWnd = CreateWindow(MYWNDCLSNAME, "My Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hInst, NULL); if(hWnd == 0) return -2; //ウィンドウの表示状態を指定する ShowWindow(hWnd,nCmdShow); UpdateWindow(hWnd); //メッセージループ while(GetMessage(&msg, 0, 0, 0)){ DispatchMessage(&msg); } //WM_QUITメッセージのwParamを終了コードにする return msg.wParam; } LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg){ case WM_DESTROY: PostQuitMessage(0); return 0; } //自分で処理しないメッセージはWindowsに任せる return DefWindowProc(hWnd, uMsg, wParam, lParam); } 本を読み直しても原因がよくわかりません。 どこがいけないのかご指摘いただけるとうれしいです。お願いします。 エラーの内容は error C2440: '=' : 'const char [14]' から 'LPCWSTR' に変換できません。 error C2664: 'CreateWindowExW' : 2 番目の引数を 'const char [14]' から 'LPCWSTR' に変換できません。 です。

  • MIDIをBGMとして使いたい

    ウインドウズでゲームを作ってみたいと思い立ち、1ヶ月ほど細々とプログラミングしている者です。環境はXPSP2、VC++6.0です。 このサイトの方たちには色々教えて頂いております。 今、BGMとしてMID(MIDI)ファイルを使いたいと思って色々やっているのですが、音を出すことが出来ません。 VCで作成したプロジェクトフォルダに、test.midというファイルを入れてあり、test.mid単独では音は鳴ります。 アプリケーションのクライアント領域上で右ボタンを押すと音が鳴ると思っていたのですが、メッセージボックスしか出ませんでした。 #include "windows.h" #include <mmsystem.h> #pragma comment(lib, "winmm.lib") LRESULT CALLBACK WindowProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch(uMsg) { case WM_CREATE: mciSendString("open test.mid type sequencer alias music",NULL,0,NULL); break; case WM_DESTROY: mciSendString("stop music",NULL,0,NULL); mciSendString("close music",NULL,0,NULL); PostQuitMessage(0); return 0; case WM_KEYUP: if(wParam==VK_RIGHT) { MessageBox(NULL,TEXT("MUSIC"),NULL,MB_OK); mciSendString("play music", NULL, 0, NULL);      } } return DefWindowProc(hWnd,uMsg,wParam,lParam); } WINMAINは別段変わったことはやっておりません。ご存知の方が居ましたら宜しくお願い致します。

  • プロトタイプが必要な場合

    WndProc関数の前にFunc関数を書いているから、WndProc関数の ソースがコンパイルされる時はFunc関数は既に読み込み済みで Func関数のプロトタイプは必要無いと思ったんだけど、必要なんですか? #include <windows.h> int Func(HWND); ←これは必要ですか? LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPInst, LPSTR lpstr, int n) {  … } int Func(HWND hWnd) {  … } LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {  static int i;  switch(uMsg){  case WM_CREATE:   i = Func(hWnd);   break;  … }

このQ&Aのポイント
  • ts8430を購入して本日届いたのですが、CDを焼くトレイが付属品として入っていませんでした。
  • 現在は付属品ではなくて別途購入するのでしょうか?
  • キヤノン製品についての質問です。
回答を見る

専門家に質問してみよう