14歳の自分に衝撃の事実を告げてください

C言語でAPIのプログラミングを行っている者です。
ソースはこちらとなります。
http://onegaisimasune.web.fc2.com/main6.txt
mux2.vはこちらです。
http://onegaisimasune.web.fc2.com/main5.txt

そこで、二つ程今のとこバグがあり、
1つ目は何度かウィンドウ上で左クリックしていると、
23回目くらいの所でウィンドウ上の文字が消えてしまう、
と言う問題と、

2つめはウィンドウを画面の外に追い出すと
ウィンドウ上の文字が消えてしまうというものです。

どこが問題なのか、ご指摘願います。
どうか宜しくお願い致します。

A 回答 (5件)

私が書くとこんな感じでしょうか。

(行数稼ぐ為に括弧とかの対応が少し見辛いかもしれませんが。。)
全角スペースでインデントつけてます。
#include <windows.h>
#define WS_WINDOWMODE (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX)
const char * ApplicationClassName = "WindowsApplication";
const char * WindowTitleName = "WindowTitle";
BOOL bActive = FALSE;
BOOL OnIdle( VOID );
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
 switch( message ) {
 case WM_CREATE:
  bActive = TRUE;
  break;
 case WM_CLOSE:
  DestroyWindow( hWnd );
  break;
 case WM_DESTROY:
  PostQuitMessage( 0 );
  break;
 case WM_ACTIVATE:
  if ( LOWORD( wParam ) == WA_INACTIVE ){
   bActive = FALSE;
  } else {
   bActive = TRUE;
  }
  break;
  default:
  return DefWindowProc( hWnd, message, wParam, lParam );
 }
 return 0L;
}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
 HWND hWnd;
 WNDCLASS wc;
 ZeroMemory(&wc, sizeof(WNDCLASS));
 wc.style = CS_HREDRAW | CS_VREDRAW;
 wc.lpfnWndProc = (WndProc);
 wc.cbClsExtra = 0;
 wc.cbWndExtra = 0;
 wc.hInstance = hInstance;
 wc.hIcon = NULL;
 wc.hCursor = LoadCursor( hInstance, MAKEINTRESOURCE(IDC_ARROW));
 wc.hbrBackground = (HBRUSH)(COLOR_INACTIVECAPTIONTEXT);
 wc.lpszMenuName = NULL;
 wc.lpszClassName = ApplicationClassName;
 if(!RegisterClass(&wc)){
  MessageBox(NULL,"ウィンドウクラスの登録に失敗しました。",NULL,MB_OK);
  return 0;
 }
 hWnd = CreateWindowEx( NULL, wc.lpszClassName, WindowTitleName, WS_WINDOWMODE,
  0, 0, 320, 240, NULL, NULL, wc.hInstance, NULL );
 if ( hWnd == NULL )
 {
  MessageBox(NULL,"ウィンドウの作成に失敗しました。",NULL,MB_OK);
  return 1;
 }

 ShowWindow( hWnd, SW_SHOW );
 MSG Msg;
 do{
  if( PeekMessage( &Msg, NULL, 0, 0, PM_REMOVE)){
   TranslateMessage(&Msg);
   DispatchMessage(&Msg);
  }else if ( bActive != FALSE ){
   if (!OnIdle()){ break; }
  }else{
   WaitMessage();
  }
 }while( Msg.message != WM_QUIT );
 return Msg.wParam;
}
BOOL OnIdle( VOID )
{
 if(GetAsyncKeyState( VK_ESCAPE ) & 0x0001){
  return FALSE;
 }
 return TRUE;
}
殆どのメッセージは戻り値が0なので、戻り値0のものは
breakさせていますが、メッセージに応じて必要な戻り値が
ある場合はそのメッセージの処理後にreturnを入れる感じです。
後は、処理をプロシージャなどに書かず、OnCreateとか適当に
造って処理を分離すると見やすくなると思います

この回答への補足

回答どうもありがとうございます。
これは何のプログラムなのでしょうか?
実行してみましたが、黒いウィンドウが現れるだけでしたが。。

補足日時:2007/11/02 15:51
    • good
    • 0

>これは何のプログラムなのでしょうか?


WinMain雛型、スケルトンプログラムと呼ばれるものです。
(ウィンドウを表示するだけのものです)
質問者さんのコードはかなりごちゃごちゃに成りつつあります。

一度、不要な変数、おかしいインデント、不要な関数呼び出し、
などの整理をした上でトレースしていかなければ、バグを特定出来ません。

プロシージャなどの戻り値や、関数の構造はある程度参考に出来ると
思います。また、各メッセージの処理をWndProcの中で書かずに、
関数にしてから、そのメッセージが来たらWndProcから
呼び出すことで、WndProcの肥大化をある程度なくせると思います。
とりあえず、先にバグをつぶすより、コードをクリーンにしてください。そうすれば自ずとおかしい所が、見えてくる場合もあります。

この回答への補足

そうですね、不要箇所をまず消してみます。
アドバイスどうもありがとうございます。

補足日時:2007/11/02 21:16
    • good
    • 0

そうですね。

NO.2さんのおっしゃる通りです。


case WM_LBUTTONDOWNとcase WM_PAINTが直通していたので、
とりあえずそれを直したく説明していました。

1.最初に描画リソース処理の手直し
2.他のメッセージ処理や、WndProc内の変数定義。(ループ内で使いまわすフォントハンドル等はstaicで定義)
3.更新タイミングの調整。現状はLBUTTONDOWN内で背景描画なしのInalidateRectで、ループを抜けた後の更新になります。

の順で話の確認するつもりでした。


自分で手を入れた流れを勢いで書いたので勘違いしてますね。
×・WM_LBUTTON~の1167行付近の return;もbreak; に変える。(WM_CREATE以外は最後にDefWindowProc()を通すようにする)
○・WM_LBUTTON~の1167行付近の return;もbreak; に変える。(switchの最後にdefault: return(DefWindowProc());を書いて、最終行はreturn 0;にする)

サブクラス化等で用意した処理があるわけではないですし、今のDefWndProcが最後に書かれており、
switchにdefaultがないので、全てreturn 0;で問題ないですね。(戻り値はキー処理等ないので0でいいと思います。)


よろしければWin32SDKのWinMain雛型を貼って指摘して頂けるとありがたいです。
    • good
    • 0

1点気になったことを。


No1さんが
>WM_CREATE以外は最後にDefWindowProc()を通すようにする
と書かれていますが、デフォルトのプロシージャに委託するのは、
メッセージを処理しなかった場合のみです。
通常、メッセージを処理した場合、ウィンドウプロシージャは
処理したメッセージに応じて戻り値を返さなければなりません。
    • good
    • 0

mux2.vについては前の質問の

http://onegaisimasune.web.fc2.com/verilog/mux2.txt
使用しました。
main6.cについて、こちらでも20回ほどクリックしたらで同様の症状が再現しました。


とりあえずざっと見た部分

・case WM_XX~ は最後 break; で終える。今WM_LBUTTON~とWM_PAINT はそのまま繋がって実行されています。
・WM_PAINT もbreak;で終える
・WM_LBUTTON~の1167行付近の return;もbreak; に変える。(WM_CREATE以外は最後にDefWindowProc()を通すようにする)
・hdc と hDCが2種類混在使用してありhDCは値が取得されてない(多分NULL)


*描画ロジックの基本的な組み方 --------------------------------------------------------
// 1.描画オブジェクトの生成
hpen = CreatePen(PS_SOLID , 0 , RGB(100 , 0 , 50));

// 2.描画オブジェクトの選択(このとき従前のオブジェクトを保管する)
hOldbr = (HBRUSH)SelectObject(hdc , CreateHatchBrush(HS_DIAGCROSS , 0xFF));
hOldpen = (HPEN)SelectObject( hdc, hPen );

// 3.出力処理
TextOut(hdc , 30, 300, "hello", sizeof("hello")); // なんらかの出力処理

// 4.描画オブジェクトを戻す(保管してあったもの)
SelectObject( hdc, hOldpen );
SelectObject( hdc, hOldbr );

// 5.Createした描画オブジェクトは消去
DeleteObject(hpen);

※1と5についてはロジックの一番外側でのみ行いキープしていてもよい
--------------------------------------------------------------------------------------


描画が不安定になるのは、描画オブジェクトの生成消去等うまく処理されてないからと思われます。
リソースが不安定になってます。
WM_PAINT内の繰り返し存在する描画部分は、上記のルールに合わせるようにして下さい。

この回答への補足

申し訳ございません、
http://onegaisimasune.web.fc2.com/verilog/mux2.txt
で合っています。
質問文のURLは間違いです。

回答ありがとうございます。
ご指摘の点を修正してまた改めて補足させていただきます。
ありがとうございます。

補足日時:2007/10/31 17:52
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!