Discussion:
WM_KEYDOWNを受け取ることができません。
(too old to reply)
unknown
2009-07-09 09:01:01 UTC
Permalink
前に一度質問したと思いますが、依然として解決に至っていませんので
再度質問したいと思います。
VC++6でWinAPIでプログラムを作成していますが、WM_KEYDOWNの処理を
するために、WPARAM wParamをint key_swで受け取り、関数から関数へと
コピーで渡して最終的な場所にある関数で条件処理しています。
リリースバージョンで作成したプログラムでは最初の1バイトは受け取りますが、
次からは無視されます。そこでSPYを駆動させたところ問題なく処理がされます。ところが、一旦SPYを終了させると途端に受け取りを無視されます。
最初からデバッグバージョンで作ると正常に操作できます。
プログラムでmallocを使っていますが、このサイズを変更すると、トラブルの出現
内容が変わってきます。これまで色々とやってはいますがお手上げ状態です。
よくある、文字列のサイズオーバーを疑いましたが該当個所には見当たりません。mallocで確保しているメモリーサイズは520K~700K程度です。ただ
プログラム本体はdllを使っていませんので700Kもあります。
unknown
2009-07-10 05:00:00 UTC
Permalink
上田です。
その後新しいことが判りました。
リリースバージョンでも、内蔵メモリーが190Mなら発現し、255Mなら発現しないことが判りました。最初はWindowsのバージョンの相違かと思いましたがそうではないよう
です。つまり、余裕のあまり無いメモリーの場合だけ発現していたようです。
UETA, Shin-ichi
2009-07-10 09:58:41 UTC
Permalink
こんにちは、植田です。
Post by unknown
リリースバージョンでも、内蔵メモリーが190Mなら発現し、255Mなら発現しないことが判りました。
Windowsアプリケーションは仮想メモリで動いているので、
物理メモリの多寡が直ちに不具合につながる可能性は低い
のでは?

# スワップファイルを使っていないならともかく...。

同じ環境でも、Debugビルドを実行したり、Spy++を稼動させ
たりした場合は発症しないようですが、むしろこれらの条件の
方がメモリの消費が激しいかと思います。

プログラム自体の大きさも、ヒープから切り出しているメモリ
ブロックの大きさも、深刻に考えるほどのものではないです。
もしメモリが不足しているなら、mallocが失敗したり、あるいは
APIがエラーを返したり、なにかしらの兆候があるはずです。
頻繁にmallocを呼び出しているならメモリリークやフラグメン
テーションを疑うべきかと。

# とはいえ、メモリ不足は、WM_KEYDOWNが取れなくなる
# 不具合の直接的な原因ではなさそうな気が...。
# 再現可能なコードを示さないかぎり、ここで質問しても推測
# 以上の回答は得られないと思いますよ。
--
植田システム設計事務所
Ueta System Design Studio
http://www.usdesign.jp/
植田真一
mailto:***@usdesign.jp
unknown
2009-07-11 02:56:02 UTC
Permalink
上田です。
返信ありがとうございます。
Post by UETA, Shin-ichi
同じ環境でも、Debugビルドを実行したり、Spy++を稼動させ
たりした場合は発症しないようですが、むしろこれらの条件の
方がメモリの消費が激しいかと思います。
私もそう考えています。だから?なんです。
Post by UETA, Shin-ichi
プログラム自体の大きさも、ヒープから切り出しているメモリ
ブロックの大きさも、深刻に考えるほどのものではないです。
もしメモリが不足しているなら、mallocが失敗したり、あるいは
APIがエラーを返したり、なにかしらの兆候があるはずです。
頻繁にmallocを呼び出しているならメモリリークやフラグメン
テーションを疑うべきかと。
mallocはプログラムのスタートのところで最初に1回だけ行い
終了時点でfreeを行っています。
Post by UETA, Shin-ichi
# とはいえ、メモリ不足は、WM_KEYDOWNが取れなくなる
# 不具合の直接的な原因ではなさそうな気が...。
# 再現可能なコードを示さないかぎり、ここで質問しても推測
# 以上の回答は得られないと思いますよ。
私も計算上はメモリー不足に陥るはずはないと考えています。
ただ、現実に停止していることを考えれば、搭載メモリのサイズに
よって影響を受けていることだけは確実だと考えています。
 これは推測ですが、Windowsの内部統制がサイズによって
差が出ていると考えます。
Post by UETA, Shin-ichi
# 再現可能なコードを示さないかぎり
ソースを示すことは量が膨大ですのでここで記載することは不可能
です。申し訳けありません。やれるとしたら、関係関数だけとなりますが
それでもかなりの量になります。
UETA, Shin-ichi
2009-07-11 05:30:01 UTC
Permalink
どうも、植田です。
Post by unknown
私も計算上はメモリー不足に陥るはずはないと考えています。
ただ、現実に停止していることを考えれば、搭載メモリのサイズに
よって影響を受けていることだけは確実だと考えています。
それをきっかけとして最終的にWM_KEYDOWNが取れないという
症状に至っているのかもしれませんが、いずれにしても、Windows
を疑う前に、まずはアプリケーションに問題がないかどうか地道に
障害箇所を絞り込んでいくしかないでしょう。
具体的な症状を見ないことには断定はできませんけど、アプリケー
ションのバグじゃない? ― という印象は拭えません。
Post by unknown
 これは推測ですが、Windowsの内部統制がサイズによって
差が出ていると考えます。
ちなみに障害が起きているWindowsのバージョンは?

WinNT系に比べればWin9x系はリソースに制約が多いのは確か
ですが、挙げられた数字を見るかぎりでは搭載メモリの大きさに
左右されるほどのレベルではなさそうですけど...。
メモリ不足の原因がヒープメモリでないなら、ハンドルの解放忘れ
とか、そっちのリークも疑わしくなります。

ほかにも開発環境にインストールしている他のアプリケーションが
干渉している可能性は?
もしWM_KEYDOWNがキューに入ってこない場合は外的要因の
方が大きくなります。

# アプリケーションが自らバックグラウンドに移動しないかぎり。
Post by unknown
ソースを示すことは量が膨大ですのでここで記載することは不可能
です。申し訳けありません。やれるとしたら、関係関数だけとなりますが
それでもかなりの量になります。
ソースコードの開示は、量的な問題はもちろん、著作権的にも
不都合があろうかと思います。見せられても困りますし(苦笑)
しかし、Windowsを疑うのであればそれを再現できる最低限の
コードを用意しないことには検証のしようがなく、上田さんと同じ
視点に立つことができません。もどかしいかぎりです。
そのためにはアプリケーションのエッセンスを抽出して、それでも
なお障害が起きる状態を作り出さなければなりません。

上田さんがどういう立場の方かは存じませんが、第三者にソース
コードを精査してもらった方がよろしいのでは?

# 個人的な経験ではこのような状況に陥ったときは十中八九アプリ
# ケーションのバグでしたし、Windowsが期待どおりに動かない場合
# でもAPIのリファレンスにその旨が書かれていたりします。
# 何度Windowsに濡れ衣を着せたことか(苦笑)
--
植田システム設計事務所
Ueta System Design Studio
http://www.usdesign.jp/
植田真一
mailto:***@usdesign.jp
unknown
2009-07-13 02:32:01 UTC
Permalink
上田です。
植田さん、返信ありがとうございます。
Post by UETA, Shin-ichi
具体的な症状を見ないことには断定はできませんけど、アプリケー
ションのバグじゃない? ― という印象は拭えません。
私も第一義的にはソース自体に原因があることを考えてはいます。
過去に一度だけ、現象は異なりますがリリースバージョンが駄目で
デバッグバージョンはOKの事例にぶち当たったことがあります。
この時は原因が判ったのは1年半後でした。それも偶然に見つけた
事例です。この時の原因は確か文字配列のサイズが20とすると
実際に書き込んだのが20だったのが原因だったと記憶しています。
文字列のサイズは最後にnullを必要とするから21取らなければ
ならなかったのにそれを見過ごしていたためだったと思います。
 この時はMSCでの話ではあるのですが、今回もこれを疑って
おおもとから順に問題発生個所まで手繰ってはいるのですが、
それらしい個所は見つかってはいません。
Post by UETA, Shin-ichi
ちなみに障害が起きているWindowsのバージョンは?
95、98、XPです。問題を起こしていないのも
98、XPです。
98は1台が250M、1台が190Mです。
250は正常に動作し、190は停止します。
XPについては客先のテスト機2台がだめで、当社所有のXPはOKです。
客先の機械はXPは当社所有の分より古い機械です。メモリーサイズは
不明ですが、当社分は500Mになります。
こうしたことから、メモリーサイズが影響していると考えた次第です。
Post by UETA, Shin-ichi
メモリ不足の原因がヒープメモリでないなら、ハンドルの解放忘れ
とか、そっちのリークも疑わしくなります。
ハンドルの解放は最重要です。プログラム終了時に1度だけ行っています。
それと、Windowsを最初に立ち上げた時点でもテストを行っていますが
結果は同じでした。
Post by UETA, Shin-ichi
ほかにも開発環境にインストールしている他のアプリケーションが
干渉している可能性は?
そこまでは調査していません。一応一覧表を作り比較はしてみます。
Post by UETA, Shin-ichi
もしWM_KEYDOWNがキューに入ってこない場合は外的要因の
方が大きくなります。
# アプリケーションが自らバックグラウンドに移動しないかぎり。
タイトルバーは常にブルーです。

 昨日、テスト中に奇妙なことが判りました。以前、Windowを一時的に閉じたり開けたりしたら1バイトだけ受け取れるとお話ししたことがありましたが、あれが
どうやら少し間違えていたようなのです。
 マウスを少し動かしたり、クリックしたりすると1バイトだけ受け取り、それ以上は
無視されるようです。本プログラムではマウスは利用していません。
例えば123と入力したければ
1、マウス、2、マウス、3、マウス、enterとすれば入力できますが、
1、2、3とすると最初の1だけになります。
 これがヒントにならないでしょうか。
UETA, Shin-ichi
2009-07-13 05:27:21 UTC
Permalink
どうも、植田です。

# かなり行き詰っているようですね(苦笑)
Post by unknown
 マウスを少し動かしたり、クリックしたりすると1バイトだけ受け取り、それ以上は
無視されるようです。本プログラムではマウスは利用していません。
例えば123と入力したければ
1、マウス、2、マウス、3、マウス、enterとすれば入力できますが、
1、2、3とすると最初の1だけになります。
可能性だけならいくらでも考えられますけど...。

ん~、たとえば、メッセージポンプ/メッセージループに問題があるとか。

メッセージループの周辺で何か特殊な処理をしていませんか?

メッセージハンドラの問題ではなく、もっと根源的なところ、メッセージ
を取り出すところに何か原因があるのかもしれません。
滞りなくキューからメッセージを取り出して所定のウィンドウにディス
パッチしなければ、いくらメッセージハンドラが正しくてもうまく動かない
ですよね。

あるいはマウス入力(キー入力以外という括りでもよい)がキー入力の
処理に干渉しているとか。
アプリケーションでマウスを使っていようがいまいが、マウスをつないで
いるかぎり、マウス絡みのメッセージは入ってきますから。
--
植田システム設計事務所
Ueta System Design Studio
http://www.usdesign.jp/
植田真一
mailto:***@usdesign.jp
unknown
2009-07-13 08:04:02 UTC
Permalink
上田です。
返信ありがとうございます。
Post by UETA, Shin-ichi
# かなり行き詰っているようですね(苦笑)
えーかなり弱っています。
前回と同様暫く、デバッグバージョンで逃げるか、
あるいは、新規購入機ではOSはXPになるでしょうから、メモリーは
512Mを積んでもらうことで対応するかです。もっとも客先のトラブルを
起こしている機械のメモリーサイズを調査してからですが。
Post by UETA, Shin-ichi
ん~、たとえば、メッセージポンプ/メッセージループに問題があるとか。
メッセージループの周辺で何か特殊な処理をしていませんか?
別段特別なことをしてません。以下参照下さい。
//エントリポイント
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR
lpCmdLine,int nCmdShow)
{
.. 前略 ..
// ウインドウを表示
ShowWindow(hWnd,SW_SHOWMAXIMIZED); // 最大
UpdateWindow(hWnd);

SetActiveWindow(hWnd); // 自動立上げの時は設定が必要、通常は必要ない。
// メッセージループ
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// 戻値
return msg.wParam;
}
Post by UETA, Shin-ichi
あるいはマウス入力(キー入力以外という括りでもよい)がキー入力の
処理に干渉しているとか。
アプリケーションでマウスを使っていようがいまいが、マウスをつないで
いるかぎり、マウス絡みのメッセージは入ってきますから。
別段特別な処理はしていないつもりですが 以下参照下さい。
文中 exmode_sw、exsagyo_noはモード管理スイッチ、作業管理NOでグローバル変数です。
dft_shori_swはローカル変数ですが、関数の初めの部分で0にセットしています。
一気にreturnで戻るより一旦switch文の外に出た方が良いと判断したためです。
一時変数の領域を食いつぶす恐れが感じられたのであえて、手順を踏んだまでです。

//ウインドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
case WM_KEYDOWN:
// キー入力
key_sw = wParam;
if(exmode_sw > 0){ // 各項目処理
if(exmode_sw == 4){
// 管理操作
smmode_shori4(hWnd,key_sw);
break;
}
.. 中略 ..

case WM_PAINT:
switch(exmode_sw)
{
.. 中略 ..
case 4:
// 管理目次画面
switch(exsagyo_no)
{
.. 中略 ..
  case 3: // 電子ジャーナル点検
ejournal_43g(hWnd);
break;
..中略..
default:
// デフォルトの処理
dft_shori_sw = 1; //ディフォルト処理する
// return DefWindowProc(hWnd,message,wParam,lParam);
}
if(dsp_sw == 1){ InvalidateRect(hWnd,NULL,TRUE); } // 全面更新
if(dft_shori_sw == 1){
return DefWindowProc(hWnd,message,wParam,lParam);
} // メッセージ処理済みは 0を返す
return 0;
}
UETA, Shin-ichi
2009-07-13 11:32:50 UTC
Permalink
どうも、植田です。
Post by unknown
Post by UETA, Shin-ichi
メッセージループの周辺で何か特殊な処理をしていませんか?
別段特別なことをしてません。以下参照下さい。
ごく普通のメッセージループですね...。
Post by unknown
if(dsp_sw == 1){ InvalidateRect(hWnd,NULL,TRUE); } // 全面更新
dsp_swもグローバル変数でしょうか?

たとえば、2文字目以降の処理でdsp_swが1に設定されなくなって
いて画面が更新されていないとか...?
実は入力できているけど画面に反映されていない ― というありがち
な不具合も考えられますけど...。

# あるいは、dsp_swが1に設定されていたとしても、メッセージ
# ハンドラの多重呼び出しによってクリアされてしまうとか、etc.

とはいえ、これまでの調査ではWM_KEYDOWNそのものが来て
いないんですよね...?
ん~、仮に画面が更新されていないとしても、マウス操作でそれが
解消するのは説明がつかないし...。

何かがグローバル変数を壊している印象しかないんですけど...。
Post by unknown
一気にreturnで戻るより一旦switch文の外に出た方が良いと判断したためです。
コーディングスタイルの問題なのでいろいろな考え方はあろうかと
思いますけど、「メッセージ処理済みは0」かどうかはメッセージに
よって違いますし、それなりに意味のある値を返さなければならな
い場合もあるので、無理に出口を一本化しなくてもいいような気が
します。個人的には。

※意見には個人差があります(苦笑)
--
植田システム設計事務所
Ueta System Design Studio
http://www.usdesign.jp/
植田真一
mailto:***@usdesign.jp
unknown
2009-07-17 06:06:01 UTC
Permalink
植田さん、ありがとうございます。
Post by UETA, Shin-ichi
if(dsp_sw == 1){ InvalidateRect(hWnd,NULL,TRUE); } // 全面更新
dsp_swもグローバル変数でしょうか?
dsp_swはモードの作業画面を切り替えた時、再作画をするためです。
Post by UETA, Shin-ichi
実は入力できているけど画面に反映されていない ― というありがち
な不具合も考えられますけど...。
それは十分に考えました。そこで、キーコードを受け取る最初の関数で
グローバル変数を臨時に作り、表示させて見ましたが結果は同じでした。
Post by UETA, Shin-ichi
とはいえ、これまでの調査ではWM_KEYDOWNそのものが来て
いないんですよね...?
 ん~、仮に画面が更新されていないとしても、マウス操作でそれが
解消するのは説明がつかないし...。
そうなんです。マウスを動かしたり、クリックしたりすると
もちろん、操作中のWindowsの画面だけの話ですけど。画面外は影響ありません。
Post by UETA, Shin-ichi
何かがグローバル変数を壊している印象しかないんですけど...。
印象的にはそうなんです。ただ、マウスの件からメッセージそのものを
受け取っていないのではないかと考えています。
T. Sugita
2009-07-17 14:55:22 UTC
Permalink
$B2?$+$,%0%m!<%P%kJQ?t$r2u$7$F$$$k0u>]$7$+$J$$$s$G$9$1$I(B...$B!#(B
$B<u$1<h$C$F$$$J$$$N$G$O$J$$$+$H9M$($F$$$^$9!#(B
$BD4$Y$F$I$&$K$+$J$k$H$$$&OC$G$O$J$$$G$9$,!"(B
$BG0$N$?$a!"0J2<$N$h$&$K$7$F!"%a%C%;!<%8%k!<%W<+BN$r(B
$B3NG'$7$F$_$F$O$I$&$G$7$g$&$+!)(B

$B$b$7:F8=$7$J$/$J$C$F$7$^$&>l9g$O!"%?%$%H%k%P!<$G$O$J$/!"(B
$B%U%!%$%k$K=q$-=P$9Ey$N9)IW$,I,MW$+$b$7$l$^$;$s!#(B

while (GetMessage(&msg, NULL, 0, 0)) {
#if 1
{
static char msg_buf[128] = "";
static char key_buf[128] = "";
static int msg_cnt = 0;
static int key_cnt = 0;
msg_cnt++;
if (msg.message == WM_KEYDOWN) {
key_cnt++;
wsprintf(key_buf, "MsgCnt=%u Cnt=%u Key=%04X"
, msg_cnt, key_cnt, msg.wParam);
}
wsprintf(msg_buf, "MsgCnt=%u msg=%08X wParam=%04X (%s)"
, msg_cnt, msg.message, msg.wParam, key_buf);
SetWindowText(hWnd, msg_buf);
}
#endif
TranslateMessage(&msg);
DispatchMessage(&msg);
}

$B$b$7%k!<%W<+BN$,$^$o$C$F$$$J$$(B(GetMessage$B$GDd;_$7$F$$$k(B)$B$H$7$F$b!"(B
$B$=$N860x$r:n$C$F$$$k$N$O!"%W%m%0%i%`<+BN$N%P%0$G$O$J$$$+$H$$$&(B
$B0u>]$r<u$1$^$9!#(B
--
$B?yED(B
nws-***@bp.iij4u.or.jp
unknown
2009-07-20 06:47:01 UTC
Permalink
上田です。
提案ありがとうございます。
while内に条件コンパイルを付けたらとの提案ですが、
残念ながら、実行は無理ではないかと思います。
理由は問題の発生する個所に到達するまでプログラムを
進められないからです。
 本プログラムはキーボード上の指定したキーが指定した
時に指定した作業を行なっています。
簡潔に言いますと
1.モードキー(R、X、Z、P..)選択 <> Windowに制御を返す
2.作業番号選択 <> Windowに制御を返したりしながら、
3.指定年月選択 <> Windowに制御を返したりしながら、
4.頁参照
となる訳ですが、
この3の時に問題を起こしています。
この時点でマウスをちょっと動かすかクリックすると1メッセージだけ
受け取ることができます。例えば11月としたいとき
1、マウス、1、マウス、Enterとすれば動作します。
現時点では1を表示しただけて停止した状態になります。
(マウスが自由に操作できるのでフリーズ状態ではありません。)
それと問題はこの個所だけで、他の作業項目では一切発生していません。
同じような工程を他の部分では行なっているのに、何故この個所になると
発生するのか。通常に考えれば、ここまでのルート上どこかがおかしいから
問題が起こっているのだと考えるのが普通です。
 一時は頁参照のためのファイルオープンに問題があるのではないかと
チェックしましたが、該当個所が見つかりませんでした。それよりも
指定月入力途中ですから、この時点ではファイルをオープンしていません。
つまり関係ないと言うことになります。
Imo
2009-07-13 15:44:38 UTC
Permalink
省略されすぎていて、肝心のdsp_sw等の状態が判りません。
Post by unknown
上田です。
返信ありがとうございます。
Post by UETA, Shin-ichi
# かなり行き詰っているようですね(苦笑)
えーかなり弱っています。
前回と同様暫く、デバッグバージョンで逃げるか、
あるいは、新規購入機ではOSはXPになるでしょうから、メモリーは
512Mを積んでもらうことで対応するかです。もっとも客先のトラブルを
起こしている機械のメモリーサイズを調査してからですが。
Post by UETA, Shin-ichi
ん~、たとえば、メッセージポンプ/メッセージループに問題があるとか。
メッセージループの周辺で何か特殊な処理をしていませんか?
別段特別なことをしてません。以下参照下さい。
//エントリポイント
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR
lpCmdLine,int nCmdShow)
{
.. 前略 ..
// ウインドウを表示
ShowWindow(hWnd,SW_SHOWMAXIMIZED); // 最大
UpdateWindow(hWnd);
SetActiveWindow(hWnd); // 自動立上げの時は設定が必要、通常は必要ない。
// メッセージループ
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// 戻値
return msg.wParam;
}
Post by UETA, Shin-ichi
あるいはマウス入力(キー入力以外という括りでもよい)がキー入力の
処理に干渉しているとか。
アプリケーションでマウスを使っていようがいまいが、マウスをつないで
いるかぎり、マウス絡みのメッセージは入ってきますから。
別段特別な処理はしていないつもりですが 以下参照下さい。
文中 exmode_sw、exsagyo_noはモード管理スイッチ、作業管理NOでグローバル変数です。
dft_shori_swはローカル変数ですが、関数の初めの部分で0にセットしています。
一気にreturnで戻るより一旦switch文の外に出た方が良いと判断したためです。
一時変数の領域を食いつぶす恐れが感じられたのであえて、手順を踏んだまでです。
//ウインドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
// キー入力
key_sw = wParam;
if(exmode_sw > 0){ // 各項目処理
if(exmode_sw == 4){
// 管理操作
smmode_shori4(hWnd,key_sw);
break;
}
.. 中略 ..
switch(exmode_sw)
{
.. 中略 ..
// 管理目次画面
switch(exsagyo_no)
{
.. 中略 ..
  case 3: // 電子ジャーナル点検
ejournal_43g(hWnd);
break;
..中略..
// デフォルトの処理
dft_shori_sw = 1; //ディフォルト処理する
// return DefWindowProc(hWnd,message,wParam,lParam);
}
if(dsp_sw == 1){ InvalidateRect(hWnd,NULL,TRUE); } // 全面更新
if(dft_shori_sw == 1){
return DefWindowProc(hWnd,message,wParam,lParam);
} // メッセージ処理済みは 0を返す
return 0;
}
unknown
2009-07-17 06:07:01 UTC
Permalink
 省略されすぎていて、肝心のdsp_sw等の状態が判りません。
すみません。dsp_swが問題だと考えていなかったので省略しました。
// モード選択は以下の部分でbreakまで
switch(key_sw)
{
case 0x71: // 登録モード
exmode_sw = 1; dsp_sw = 1; ex_comment_step = 0; exhour_moto = 24;
sw = InvalidateRect(hWnd,NULL,TRUE); cdsp_dspclear();
break;
case 0x74: // 管理モード
exmode_sw = 4; dsp_sw = 1; ex_comment_step = 0; exej_yearmonth = 0;
sw = InvalidateRect(hWnd,NULL,TRUE); cdsp_waitmes();
break;
モードの切替の時だけです。
Imo
2009-07-23 01:59:05 UTC
Permalink
Post by unknown
dsp_sw等.....
だけを問題にしたつもりはないのですが、... 示されたソースだけでは、 やはり全体が見えないと解決しないのではないでしょうかと言うつもりでした。

私も、長くプログラムを作ってきましたが、 基本的には、デバッグアウトを出すのが一番手っ取り早いバグ解決の方法だと思います。
デバッグアウトを出す方法もいろいろあると思いますが、 ディスクトップウインドウを出力ウィンドウに見立てbitbltでスクロールし、textoutを行う方法なんかはわざわざウィンドウをオープンする必要もなく わりと簡単です。
Post by unknown
 省略されすぎていて、肝心のdsp_sw等の状態が判りません。
すみません。dsp_swが問題だと考えていなかったので省略しました。
// モード選択は以下の部分でbreakまで
switch(key_sw)
{
case 0x71: // 登録モード
exmode_sw = 1; dsp_sw = 1; ex_comment_step = 0; exhour_moto = 24;
sw = InvalidateRect(hWnd,NULL,TRUE); cdsp_dspclear();
break;
case 0x74: // 管理モード
exmode_sw = 4; dsp_sw = 1; ex_comment_step = 0; exej_yearmonth = 0;
sw = InvalidateRect(hWnd,NULL,TRUE); cdsp_waitmes();
break;
モードの切替の時だけです。
unknown
2009-07-28 05:37:01 UTC
Permalink
上田です。
色々と皆さんのご意見を伺いましたことをまずお礼申し上げます。
その後、毎日の様に問題の個所を調べましたが判りませんでした。
本日、改めてデバッグバージョンからリリースバージョンに移行する時に発生する問題を検討しました。
1.最初にヒープの問題がないかをチェックしましたが、
  異常は発見できませんでした。下記は問題の関数の上部部分です。
  heapstatusはテストした名残です。
2.次に警告レベルをレベル4に(通常はレベル3)上げて再ビルド
  したところ、警告が出たので一つ一つ個所を潰して行きました。
  そうして下記のレベル4で警告に従い、end_sw = 0;を追加した
  ところ停止状態がなくなりました。ex_comment_stepは関数内の
  制御用グローバル変数です。数値に従って関数内での作業を
  取り仕切っています。key_swはキーボードから取込んだキーコード
  になります。
3.違和感を感じるのは、この関数に最初に突入するのはex_comment_step == 0の時で
  switch(key_sw)ではend_sw = 1;もしくはend_sw = 0;で1か0に設定されているにも
  関わらず、何故先頭に追加が必要だったについてです。
  ともかく、取りあえずは解消したことをお知らせ致します。

// 問題の関数
int ejournal_check43(HWND hWnd,int key_sw)
{
int year,month,day,monthday,hour,minute,sec,su_cnt,end_sw,dsk_sw;
int keta,x,y,x2,y2,sw,sw2,len; // heapstatus;
long adress_st,adress_ed,nagasa,next_ad,st_adress,adress,lsrno;

end_sw = 0; // レベル4で警告が出たため、この行を追加
if(ex_comment_step == 0){
switch(key_sw)
{
case VK_DIVIDE: // クリアは中止
exsagyo_no = 0; // 設定目次に戻る 設定科目NO 選択されていないときは0
end_sw = 1;
InvalidateRgn(hWnd,NULL,TRUE);
break;
default: // 実行のとき
// 次に進める
ex_comment_step = 1; cls_exsumoji();su_cnt = 0; end_sw = 0; ex_sucnt3 = 0;
break;
}
}
if(end_sw > 0){ return(end_sw); } // レベル4で警告

// 指定日の入力
if(ex_comment_step == 1){

  以下省略
UETA, Shin-ichi
2009-07-28 06:31:01 UTC
Permalink
どうも、植田です。

# 解決したようでなによりです。
Post by unknown
3.違和感を感じるのは、この関数に最初に突入するのはex_comment_step == 0の時で
  switch(key_sw)ではend_sw = 1;もしくはend_sw = 0;で1か0に設定されているにも
  関わらず、何故先頭に追加が必要だったについてです。
最初はそれでよくても、ex_comment_step != 0 の条件で ejournal_check43
を呼び出したときはend_swが不定値になります。
スタック上のローカル変数を明示的に初期化していない場合、Debugビルド
であれば固定値(0xCC)で初期化されますが、Releaseビルドでは不定値の
ままです。
そのため、switch を抜けた後の if (end_sw > 0) で不定値を比較することに
なるので期待したようには動かなくなるはずです。
end_sw が偶然0よりも大きな値を持っていればそこで処理が終わります。
Debugビルドの場合は end_sw が 0xCC ... CC で初期化されているため
end_sw > 0 が成立しません。

面倒でもローカル変数は明示的に初期化するのが定石です。
--
植田システム設計事務所
Ueta System Design Studio
http://www.usdesign.jp/
植田真一
mailto:***@usdesign.jp
unknown
2009-07-28 07:22:11 UTC
Permalink
(この文章は1回目の投稿に失敗したので再送信したものです)
上田です。

色々と皆さんのご意見を伺いましたことをまずお礼申し上げます。
その後、毎日の様に問題の個所を調べましたが判りませんでした。

改めてデバッグバージョンからリリースバージョンに移行
する時に発生する問題を検討しました結果、
1.最初にヒープの問題がないかをチェックしましたが、
  異常は発見できませんでした。下記は問題の関数の上部部分です。
  heapstatusはテストした名残です。
2.次に警告レベルをレベル4に(通常はレベル3)上げて再ビルド
  したところ、警告が出たので一つ一つ個所を潰して行きました。
  そうして下記のレベル4で警告に従い、end_sw = 0;を追加した
  ところ停止状態がなくなりました。ex_comment_stepは関数内の
  制御用グローバル変数です。数値に従って関数内での作業を
  取り仕切っています。key_swはキーボードから取込んだキーコード
  になります。
3.違和感を感じるのは、この関数に最初に突入するのはex_comment_step == 0の時で
  switch(key_sw)ではend_sw = 1;もしくはend_sw = 0;で1か0に設定されているにも
  関わらず、何故先頭に追加が必要だったについてです。
  ともかく、取りあえずは解消したことをお知らせ致します。


int ejournal_check43(HWND hWnd,int key_sw)
{
int year,month,day,monthday,hour,minute,sec,su_cnt,end_sw,dsk_sw;
int keta,x,y,x2,y2,sw,sw2,len; // heapstatus;
long adress_st,adress_ed,nagasa,next_ad,st_adress,adress,lsrno;

end_sw = 0; // レベル4で警告が出たため、この行を追加
if(ex_comment_step == 0){
switch(key_sw)
{
case VK_DIVIDE: // クリアは中止
exsagyo_no = 0; // 設定目次に戻る 設定科目NO 選択されていないときは0
end_sw = 1;
InvalidateRgn(hWnd,NULL,TRUE);
break;
default: // 実行のとき
// 次に進める
ex_comment_step = 1; cls_exsumoji();su_cnt = 0; end_sw = 0; ex_sucnt3 = 0;
break;
}
}
if(end_sw > 0){ return(end_sw); } // レベル4で警告

// 指定日の入力
if(ex_comment_step == 1){
  以下省略

 取りあえず、プログラムの動作が正常に戻ったことをお知らせしたいと思いました。

/*******************
堺市南区原山台
上田 恭平
********************/
UETA, Shin-ichi
2009-07-28 08:32:01 UTC
Permalink
どうも、植田です。
Post by unknown
(この文章は1回目の投稿に失敗したので再送信したものです)
ニュースグループの方にはちゃんと投稿できているようですが、念のため、
こちらの投稿にもリプライしておきます。

―・―

# 解決したようでなによりです。
Post by unknown
3.違和感を感じるのは、この関数に最初に突入するのはex_comment_step == 0の時で
  switch(key_sw)ではend_sw = 1;もしくはend_sw = 0;で1か0に設定されているにも
  関わらず、何故先頭に追加が必要だったについてです。
最初はそれでよくても、ex_comment_step != 0 の条件で ejournal_check43
を呼び出したときはend_swが不定値になります。
スタック上のローカル変数を明示的に初期化していない場合、Debugビルド
であれば固定値(0xCC)で初期化されますが、Releaseビルドでは不定値の
ままです。
そのため、switch を抜けた後の if (end_sw > 0) で不定値を比較することに
なるので期待したようには動かなくなるはずです。
end_sw が偶然0よりも大きな値を持っていればそこで処理が終わります。
Debugビルドの場合は end_sw が 0xCC ... CC で初期化されているため
end_sw > 0 が成立しません。

面倒でもローカル変数は明示的に初期化するのが定石です。
--
植田システム設計事務所
Ueta System Design Studio
http://www.usdesign.jp/
植田真一
mailto:***@usdesign.jp
unknown
2009-07-29 04:46:00 UTC
Permalink
植田さん、色々とありがとうございました。
デバッグバージョンではローカル変数に0xccを書き込まれることを初めて知りました。
int では-858993460と言うことですね。
正規に学校で学んだのでなく、市場に出ている参考書を基に「必要な個所しか
勉強しない」スタイルで行ってきた弱点が現れたと反省しています。
でも、今更変更できない(時間がない)のでこのままのスタイルを続けるしか方法
はありません。
 改めてend_swを考えると、ご指摘の通り数値が不安定なために、ここでreturnして
しまった事が停止した状況になったと考えます。だとすれば、SPYを駆動しと時も
同じ様に、0xccとかが書き込まれてのかと言うことでしょうか。
又、何故マウスを1回動かしたり、クリックしたりしたら1キーのみ取り込まれてのかの
理由が釈然としません。
 それはともかく、皆様に再度お礼申し上げます。
UETA, Shin-ichi
2009-07-29 07:11:12 UTC
Permalink
どうも、植田です。

# 余談ではありますが ――
Post by unknown
 改めてend_swを考えると、ご指摘の通り数値が不安定なために、ここでreturnして
しまった事が停止した状況になったと考えます。だとすれば、SPYを駆動しと時も
同じ様に、0xccとかが書き込まれてのかと言うことでしょうか。
又、何故マウスを1回動かしたり、クリックしたりしたら1キーのみ取り込まれてのかの
理由が釈然としません。
ejournal_check43 が呼び出されたとき、その直前にスタックがどのよう
に使われたかによって end_sw の値が左右されることになります。
end_sw に割り当てられた領域がかつて負数を持っていたなら end_sw
も負数になりますし、正数を持っていたなら end_sw も正数になります。

Spy++を起動してトレースを開始すると対象プロセスにSpy++のフックが
インストールされるため、それだけでも条件が変わってきます。
マウスをクリックしたときもウィンドウプロシージャが呼び出されるので、
これまたスタックの状態を変える要因となります。
Windowsの内部処理でもスタックは使われるでしょうから、バージョンや
セキュリティアップデート、アンチウィルスソフトなど、ちょっとした条件の
違いで不具合が発症する可能性があります。

いずれにせよ初期化されていないローカル変数がどんな値になるかは
予測できないので、たとえうまく動いていたとしてもそれは奇跡的なこと
です。マウスを動かせば入力できるというのも偶然の産物です。
--
植田システム設計事務所
Ueta System Design Studio
http://www.usdesign.jp/
植田真一
mailto:***@usdesign.jp
unknown
2009-07-29 08:22:02 UTC
Permalink
上田です。

これまでは、ローカル変数については文字変数の初期化については徹底していました。
今回はint型であったのでショックでした。MSCでは大抵、初期化していない
int、long型はプログラムの初期の段階では0ですが、途中からとんでもない
数値になるので、ほとんど100%初期値未設定として引っ掛かかります。
ただMSDOSでは使用1回で済む関数がWindowsでは大抵は複数回連続して
使用することになります。そうすると、初期値の設定も毎回関数の最初の部分で
行わなくてはならなくなり、初期値設定に掛かる時間のロスを考えてしまいました。
それで、つい必要ないなら省略しようと言う心理的な考えになってしまったように
思います。出来るだけ高速処理できるようにする習慣がそうさせたのかも知れません
UETA, Shin-ichi
2009-07-31 06:40:45 UTC
Permalink
どうも、植田です。
Post by unknown
今回はint型であったのでショックでした。MSCでは大抵、初期化していない
int、long型はプログラムの初期の段階では0ですが、~
はて、MS-Cの細かい仕様はすでに忘れてしまいましたが、初期化していない
ローカル変数の値が不定であることにかわりはないかと...。
C/C++の言語仕様として0で初期化されるのが保証されているのは静的な
変数だけのはず...。
Post by unknown
ただMSDOSでは使用1回で済む関数がWindowsでは大抵は複数回連続して
使用することになります。
関数の呼び出しが1回だけかどうかは、MS-DOSであろうが、Windowsであろ
うが、プログラムの構造次第です。
むしろ繰り返し呼び出される関数の方が普通です。
Windowsのプログラミングモデルがイベントドリブンであり、イベントハンドラで
あるウィンドウプロシージャが繰り返し呼ばれるので、そんな印象を持っている
だけだと思います。
Post by unknown
そうすると、初期値の設定も毎回関数の最初の部分で
行わなくてはならなくなり、初期値設定に掛かる時間のロスを考えてしまいました。
何もしないよりは初期化にコストがかかるのは当然ですが、整数型の変数を
0で初期化する程度なら1~2ステップのマシン語で済むので、ほとんど無視
できるほどわずかなコストです。

# ましてや今やCPUのクロックはGHzの時代ですし(苦笑)

極限まで最適化しなければならないような関数ならともかく、多くの場合、
アルゴリズムを見直した方がよっぽど効果があります。
--
植田システム設計事務所
Ueta System Design Studio
http://www.usdesign.jp/
植田真一
mailto:***@usdesign.jp
ちゅ
2009-07-14 02:47:35 UTC
Permalink
$B$A$e(B $B$G$9!#(B

On Mon, 13 Jul 2009 01:04:02 -0700
Re: WM_KEYDOWN$B$r<u$1<h$k$3$H$,$G$-$^$;$s!#(B
$B2#$+$i$9$_$^$;$s!#(B
$B%G%P%C%/%P!<%8%g%s$GF0:n$7$F%j%j!<%9%P!<%8%g%s$GF0:n$,IT0BDj$J$s$G$9$h$M!#(B
$BJ8Cf!!(Bexmode_sw$B!"(Bexsagyo_no$B$O%b!<%I4IM}%9%$%C%A!":n6H4IM}#N#O$G%0%m!<%P%kJQ?t$G$9!#(B
$BK\Ev$K(BWM_KEYDOWN$B%a%C%;!<%8$,Mh$F$$$J$$$N$J$i(B WndProc() $B$NLa$jCM$d(B
DefWindowProc() $B$N8F$S=P$7$KLdBj$,M-$k$N$+$b$7$l$^$;$s$,!"(B
C++$B$N%=!<%9$J$i(B volatile $B%-!<%o!<%I$G(B
C$B$J$i(B __restrict $B%-!<%o!<%I(B $B$G(B exmode_sw$B!"(Bexsagyo_no $B$***@k8@;~$K;XDj$7$F$*$/$H(B
$B:GE,2=$G$N%H%i%V%k$r8:$i$9$3$H$,=PMh$^$9!#(B
$BFC$K!"%0%m!<%P%kJQ?t$G%a%C%;!<%8%k!<%WFb$G;HMQ$9$kJQ?t$OJ]81$N0Y$K$b(B
$B;d$O;HMQ$7$F$^$9!#5$5Y$a$G$9$,!D!#(B

$B;d$O%G%P%C%/%P!<%8%g%s$GF0:n$7$F%j%j!<%9%P!<%8%g%s$GF0:n$,IT0BDj$J;~$O(B
$BJQ?t$N=i4|2=K:$l$r=***@E*$K%A%'%C%/$7$F$^$9!#(B
$B%G%P%C%/%P!<%8%g%s$G$O#0$K=i4|2=$5$l$F$$$k$N$GFC$K!#(B
$B%3%s%Q%$%i!<$N%o!<%K%s%0$O=P$F$$$^$;$s$h$M!)(B
--
$B$A$e(B
unknown
2009-07-17 06:11:01 UTC
Permalink
デバックバージョンで動作してリリースバージョンで動作が不安定なんですよね。
文中 exmode_sw、exsagyo_noはモード管理スイッチ、作業管理NOでグローバル変数です。
 C++のソースなら volatile キーワードで
Cなら __restrict キーワード で exmode_sw、exsagyo_no の宣言時に指定しておくと
最適化でのトラブルを減らすことが出来ます。
特に、グローバル変数でメッセージループ内で使用する変数は保険の為にも
私は使用してます。気休めですが…。
でも、それでは「SPY」を駆動中(一旦駆動させて終了するまで)は問題なく
動作することの説明が付かないと思うのですが。
私はデバックバージョンで動作してリリースバージョンで動作が不安定な時は
変数の初期化忘れを重点的にチェックしてます。
デバックバージョンでは0に初期化されているので特に。
グローバル変数の場合は使う直前に必ず初期化(特定の数値等)をセットしています。
まあほとんどは0とヌルですが。面倒なので、初期化関数を作り、それを呼び出すやり方
ですが。なお、exmode_sw、exsagyo_no等の制御のための変数ではその場面毎にセット
例えば登録モードではexmode_sw = 1;管理モードではexmode_sw = 4;と変更してはいます。
この変数により、画面と処理の同期を取っています。まあ、マルチウインドウで言えば
登録ウインドウ、管理ウインドウと同じ役割ですね。
コンパイラーのワーニングは出ていませんよね?
もちろん出ていません。

で、メモリーを取りあえず増設することで対応しておこうかと考えています。
Loading...