Discussion:
Windowsからキー入力に突然制限を受けた理由が知りたい
(too old to reply)
unknown
2009-03-29 03:52:00 UTC
Permalink
Windows 95 4.00上でVC6++でキーボード入力を主にしたプログラムを作成しています。
プログラムはシングルウインドウ(Win32)です。デバッグバージョンで動作を確認し、
リリースバージョンで再確認しながらほぼ完成しました。キー入力は
LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)で

case WM_KEYDOWN:
// キー入力
key_sw = wParam;
として受け取り
これを
int kansuA(HWND hWnd,int key_sw);
{
kansuB(hWnd,key_sw);
省略

int kansuB(HWND hWnd,int key_sw)
{
kansuC(hWnd,key_sw);
省略

int kansuC(HWND hWnd,int key_sw)
{
kansuD(hWnd,key_sw);
省略
と順に呼び出し

最終の関数kansuD内でkey_swの処理を行います。
この処理が数日前に突然出来なくなりました。
最初のkey_swは処理できるのですが、2回目からのkey_swは全く無視されます。
最初はフリーズしたのかと思ったのですが、そうではなく、上部右端の_、×は正常に動作します。
_をクリックし再度表示させると3回目のkey_swが入力できます。これらは何も自身のプログラムの
表示に限らず、例えば「メモ帳」を開いたり休止したりしても同じで、3回目のkey_swが受け取られます。
これらはリリースバージュンだけに発現しています。デバッグバージョンではこれらは発現しません。
まるでWindowsのハンドルを一時的に奪われたような動きに見えます。
 念のため、Windows98SEとXPでリリースバージョンをテストして見ましたが、正常の動作しました。
プログラムのサイズはリリースバージョンで580KB、デバッグバージョンで1.16MBです。
スタックはデフォルト設定で1MBあるそうですから、十分に余裕があります。
 又、停止する前後のソースを詳細に調べましたが、文字列のオーバーフローは見当りませんでした。
システムの違いの性なのか、原因がはっきりしないと不安です。
何故こうしたことが発生するのか、理由が判れば有り難いです。よろしくお願い致します。


/*****************************
堺市南区原山台
上田 恭平
E_Mail ***@sannet.ne.jp
*****************************/
UETA, Shin-ichi
2009-03-29 07:46:27 UTC
Permalink
こんにちは、植田です。
Post by unknown
最初のkey_swは処理できるのですが、2回目からのkey_swは全く無視されます。
最初はフリーズしたのかと思ったのですが、そうではなく、上部右端の_、×は正常に動作します。
_をクリックし再度表示させると3回目のkey_swが入力できます。これらは何も自身のプログラムの
表示に限らず、例えば「メモ帳」を開いたり休止したりしても同じで、3回目のkey_swが受け取られます。
これらはリリースバージュンだけに発現しています。デバッグバージョンではこれらは発現しません。
まるでWindowsのハンドルを一時的に奪われたような動きに見えます。
kansuA~kansuDが何をしているのかを見極めないと確かなことは
言えませんが、まず考えられるのは、当該ウィンドウがフォーカスを
失っている可能性です。
kansuA~kansuDの処理によって、あるいはバックグラウンドで動い
ているプログラムによって、アクティブウィンドウが切り替わっている
のではないでしょうか?

ウィンドウがフォーカスを失うと、どんなにキーを押そうが、キー関係
のメッセージは他のウィンドウに流れてしまいます。
タイトルバーにあるボタンをクリックして回復するのは、その操作に
よって、フォーカスを取り戻しているからでしょう。

# タイトルバーの色に変化は見られませんか?

また、たとえば、アサーション(ASSERTマクロやVERIFYマクロなど)
が余計な処理を含んでいるとReleaseビルドとDebugビルドで動きが
異なってしまうこともありまし、意図的に #ifdef _DEBUG で括ってい
れば言わずもがな。

アプリケーションのバグ、実行環境、その両面からチェックしていく
必要があろうかと思います。

たとえば、フォーカスの横取り辺りはWin95とWin98以降でずいぶん
違います。Win98以降、フォーカスの横取りが難しくなったので、
そのおかげでWin98SEやWinXPで正常に動いているのかもしれ
ません(逆にそれが原因でうまく動かないこともありますが、どこに
視点を置くかで解釈は変わります)。

# この件はSetForegroundWindowの解説に詳しく書かれています。

いずれにせよ、これだけでの情報では推測の域を出ませんね(苦笑)
単純なバグだったり、ブレークポイントやトレースポイントの設定を
誤っていただけかもしれませんし...。
--
植田システム設計事務所
Ueta System Design Studio
http://www.usdesign.jp/
植田真一
mailto:***@usdesign.jp
unknown
2009-03-29 11:06:04 UTC
Permalink
植田さん、
早速回答を頂きありがとうございます。

まず、タイトルバーはブルーのまま、アクティブです。
#define は複雑な処理はしてはおりません。今回の場合は単純に
定義しているだけです。意図してバックグランドで動かしているプログラムは
見当りません。あるとすれば、日本語入力のMS-IME97かな。元々のプログラムは
日本語入力は別ソフトで処理しているので、トラブル前までは、日本語処理ルーチンは
リンクさせていませんでしたが、どうしても1ケ所使わざるを得ない部分があり、
追加してimm32libをリンクさせました。ただ、トラブルの発生しているモードでは
使用していません。
kansuA~Dの説明を補足します。
関数の段階は以下の通りです。問題の発生はkansuCの数字入力部分で起こっています。

kansuA
kansu1A 登録モード 
Kansu2A 点検モード
kansu3A 精算モード
kansu4A 管理モード 
     kansu3B ジャーナル監視モード
        kansuC 日付選択モード
exsumoji[30]に数字を順に格納していく
case 0x61:
exsumoji[excnt] = '1'; excnt++; // 変数は何れもグローバル変数
break;
case 0x62:
exsumoji[excnt] = '2'; excnt++;
break;
case 0x0d: // 数字入力の終了
 break;
               kansuD 表示制御ルーチン   
 kansu5A 支払モード

トラブルは1234と入力すると1は入力できるが、2、3,4が無視される。
この段階で一旦画面を格納したり、メモ帳を格納しりすると
5678と入力すると5は入力できるが6,7,8は無視される。

/**************************
堺市南区原山台
上田 恭平
E_Mail ***@sannet.ne.jp
***************************/
UETA, Shin-ichi
2009-03-29 13:09:21 UTC
Permalink
どうも、植田です。
Post by unknown
まず、タイトルバーはブルーのまま、アクティブです。
であれば、純粋にアプリケーションのバグと考えるべきでは?
何かしら環境に依存する要因があるはずです。
imm32のリンクが大きな変化として挙がっているのであれば、
IME絡みを重点的にチェックしてみては?

# 「トラブルの発生しているモードでは使用していない」のは
# 確かなのか、使用していなくても何か干渉しているのでは
# ないか、etc.

アサーションやトレースポイントをいくつか仕込み、環境に
よって処理の流れが違っていないか、何か意図しない条件
が入り込んでいないか等、地道に調べていくしかないと思い
ます。
Post by unknown
問題の発生はkansuCの数字入力部分で起こっています。
「問題の発生」が特定できているのであれば、それに至る
過程を遡って原因を突き止めるしかないでしょう。
何かしらのAPIの呼び出しが影響しているのであれば、その
APIの振る舞いがWindowsのバージョンによって異なるの
かもしれません。

キー入力のメッセージを捕捉できているのかどうか
→捕捉できていないのであればフォーカス絡みが疑わしい
 IMEにメッセージが流れているのかもしれない
捕捉できているのであればどこで処理が終わっているのか
→kansuCを呼び出さない条件はないのか?
 テンキー(VK_NUMPAD1:0x61 など) を他の用途にも
 使っていて、それが干渉している可能性は?
kansuC内でキー入力を無視してしまう条件はないのか
→kansuCが呼び出されているのであればその処理内容に
 何かしら問題があるはず
--
植田システム設計事務所
Ueta System Design Studio
http://www.usdesign.jp/
植田真一
mailto:***@usdesign.jp
unknown
2009-03-30 07:38:07 UTC
Permalink
植田さん、ありがとうございます。

まず、問題が発現しているのはリリースバージョンのみ、
且つXP、98SEではリリースバージョンでも問題なく動作しています。
プログラム上の問題なら、デバッグバージョンでも発生するはず。
ワンステップずつ動かして各変数の変異を確認しましたが、
おかしな点は見つかりませんでした。
前回で、exsumoji[excnt] = '1'; excnt++;
文字列をキー入力に合わせて取込んでいると書きましたね。
1key毎にexcntは+1されているので、
数字キー該当keyならカウンタexcntは+1されて行くはずです。
これをリリースバージョンで別個所に文字列とカウンタを表示させた所
停止してる場合は+1されていません。表示された場合だけ+1されます。
この事から、この関数段階ではキーが到達していないことが判ります。
 それでは途中でキーが断絶されて伝わらなかったかどうかですが
関数から関数への伝達は関数内変数へのコピーで対応されています。
 関数内変数(ローカル)の文字列がオーバーフローするようなケース
例えばmoji[15]で20バイト分のデータを書くと、5バイト分オーバー
しますが、この隣に先のコピーされていた変数があった時、消されて
しまいます。消されていると言うよりは別の数値が入ってしまうので
結果として到達していないことになります。大抵こうしたオーバーフローは
プログラムの暴走になります。
 テンキー取込関数は汎用で使っており、あちこちで使っています。
当然、使用開始時には必ず初期化として、文字列のヌル化、変数の0セット
を行っています。念の為、ここだけしか使わない変数に変更して見ましたが
結果は同じでした。
 ちょっと気になるのはテンキー取込関数wintenkey(... )内で
static RECT rtrt;と宣言していることです。範囲を指定して数字を画面に
表示させているのですが、static これが引っ掛からないでしょうか。
これまで問題なく使ってきたのですが。

 今の感じではプログラムのサイズで問題が発生しているのではないかと
疑念を持っています。過去にMSDOS版で(内容は忘れましたが)メモリー
限界のプログラムを作成したとき、弱ったことを覚えています。
その時は時間もありませんでしたので、強制的に発現しないようにした記憶が
あります。もう少し頑張ってみます。
T. Sugita
2009-04-01 13:11:59 UTC
Permalink
Windows 95 4.00$B>e$G#V#C#6!\!\$G%-!<%\!<%IF~NO$r<g$K$7$?(B
$B!!!A(B $BN,(B $B!A(B
$B$^$k$G(BWindows$B$N%O%s%I%k$r0l;~E*$KC%$o$l$?$h$&$JF0$-$K8+$($^$9!#(B
VC6 $B$KIUB0$7$F$$$k$+$o$+$i$J$$$N$G$9$,!"(BSpy++ $B$H$$$&(B
$B%D!<%k$,$b$7$"$k$h$&$G$7$?$i!"$=$A$i$G%-!<%\!<%I%a%C%;!<%8(B
$B$r$9$Y$F3NG'$7$F$_$F$O$I$&$G$7$g$&$+!)(B

# Visual Studio 6 $B$K$OIUB0$7$F$$$^$9$,!"(BVC $BC1BN$KIUB0(B
# $B$7$F$$$k$+$O$o$+$i$J$$$G$9!#(B

$B$b$7B8:_$9$k>l9g$O!"(B
[$B%9%Q%$(B]$B%a%K%e!<"*(B[$B%a%C%;!<%8(B]$B"*(B[$B$9$Y$F$N%&%#%s%I%&(B]$B$r%A%'%C%/(B
[$B%a%C%;!<%8(B]$B%?%V"*(B[$B$9$Y$F%/%j%"(B]$B"*(B[$B%-!<%\!<%I(B]$B$r%A%'%C%/(B
$B$H$7$F<B9T$9$k$H!"$I$N%O%s%I%k$G%-!<%\!<%I%a%C%;!<%8$r(B
$B<u$1<h$C$F$$$k$+3NG'$G$-$^$9!#(B
--
$B?yED(B
nws-***@bp.iij4u.or.jp
unknown
2009-04-03 10:18:30 UTC
Permalink
杉田さん、ありがとうございます。

SPYを使って調査したらどうかとのことですが、
早速使って見ました。リリースバージョンを起動した上で
SPYを起動し、問題の個所の部分を操作した所、
今度はスムーズに動けます。そこでSPYを終了し
改めて問題の個所を操作すると26と入力すると
6の時点でストップしました。これではデバッグバージョンなら
スムーズに動作するが、リリースバージョンなら駄目になることと
同じ結果になります。この事から、デバッグやSPYでは
何か特別な配慮を行っているのではないかと推測します。
どちらもデバッグ処理のため、Windows95のシステムを部分的に
拡張しているのではないかと推測します。その拡張こそがWindows98
からは標準装備になっていると考えれば、これまでの現象に
説明がつきます。
 さて、staticの件は変更しても現象は同じでしたので関係なしと考えます。
その他に気になるのは
DefWindowProc(hWnd,message,wParam,lParam)の事です。
キー入力を
case WM_KEYDOWN:
// キー入力
key_sw = wParam;
で受けて次々と関数を呼び出していますが、
戻しにDefWindowProc(hWnd,message,wParam,lParam)は要らないですよね。
そもそもDefWindowProc(hWnd,message,wParam,lParam)の働きがもうひとつ
良く判らないものでちょっと不安です。
T. Sugita
2009-04-07 15:15:58 UTC
Permalink
$B$I$A$i$b%G%P%C%0=hM}$N$?$a!"(BWindows$B#9#5$N%7%9%F%`$rItJ,E*$K(B
$B3HD%$7$F$$$k$N$G$O$J$$$+$H?dB,$7$^$9!#(B
$B%7%9%F%`$rItJ,E*$K3HD%$7$F$$$k$H$$$&$N$O!"$A$g$C$H9M$($E$i$$(B
$B5$$,$7$^$9!#(B
$B$?$7$+!"%G%P%C%0%P!<%8%g%s$H%j%j!<%9%P!<%8%g%s$G%j%s%/$5$l$k(B
$B%i%$%V%i%j$,0[$J$C$?$H;W$$$^$9$N$G!"$=$l$K$h$C$F5sF0$,0[$J$C(B
$B$F$$$k2DG=@-$O$"$k$H;W$$$^$9!#(B
($B2sHr$9$kJ}K!$O$o$+$j$^$;$s$,!&!&!&(B)
$B%-!<F~NO$r(B
// $B%-!<F~NO(B
key_sw = wParam;
$B$G<u$1$F<!!9$H4X?t$r8F$S=P$7$F$$$^$9$,!"(B
$BLa$7$K(BDefWindowProc(hWnd,message,wParam,lParam)$B$OMW$i$J$$$G$9$h$M!#(B
$BMW$j$^$;$s!#(B
$B%X%k%W$N(B WM_KEYDOWN $B$K$O(B F10 $B%-!<$,F~NO$5$l$?>l9g$K$D$$$F(B
$B=q$+$l$F$"$j$^$9$,!"$3$l$O$h$/$o$+$i$J$+$C$?$G$9!#(B


$BK\7o(B($B%j%j!<%9%P!<%8%g%s$G$N%-!<F~NO(B)$B$K$D$$$F!"(BWindows95
$B%^%7%s$r8+$D$1$F$-$F$A$g$C$H$d$C$F$_$?$N$G$9$,!"(B
$B%j%j!<%9%P!<%8%g%s$G$bLdBj$J$/%-!<F~NO$,=PMh$F$$$^$7$?!#(B

$B>I>uE*$K$O!"%U%)!<%+%9$r<:$C$?$H$-$K;w$?>I>u$G$9$N$G!"(B
$B$?$H$($P(B WM_LBOTTUNDOWN $BEy$G6/@)E*$K%U%)!<%+%9$r<hF@$9$k$H(B
$B$I$&$J$k$+;n$5$l$F$_$F$O$I$&$G$7$g$&$+!)(B

case WM_LBUTTONDOWN: SetFocus(hWnd); break;

$B$b$7:8%/%j%C%/$GF~NO$,0l;~E*$KLa$k$h$&$@$H!"$I$3$+JL$N(B
$B%O%s%I%k$K%U%)!<%+%9$,0\$C$F$$$k$H;W$o$l$k$N$G!"(B
GetFocus() $B$G%O%s%I%k$rD4$Y$k$H!"(BSpy++ $B$G$=$N%O%s%I%k$,(B
$B2?$+D4$Y$k$3$H$,$G$-$k$H;W$$$^$9!#(B
--
$B?yED(B
nws-***@bp.iij4u.or.jp
unknown
2009-04-08 04:31:01 UTC
Permalink
杉田さん、ありがとうございます。

さて、F10は、このプログラムでは使わないので無視しました。
最初の元受の関数内で
case WM_SYSKEYDOWN: // f10を無視するため
break;
としました。こうしないと、キーボードの入力に邪魔になるのでやむなく。

問題をもう一度整理します。
問題発生の記述個所はこの元受関数から、呼出した関数内から更に呼出した
関数内で発生しています。
//ウインドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
key_sw = wParam; キーコードを一つづつ取込む
↓   ↑
smmode_shori4(hWnd,key_sw);
↓   ↑
ejournal_check43(hWnd,key_sw);
↓   ↑
wintenkey(hWnd,key_sw,&su_cnt,keta,x,y,x2,y2); 問題発生
1キーコードを処理して直ぐに戻す
問題点は次のコードを受け取れないこと、しかしWindowsを刺激するような
操作(例えば、別Windowをアクティブとか、非アクティブとか、
自身のWindowをアクティブとか、非アクティブとする)と次の
1キーだけを受け取れること。

smmode_shori4(hWnd,key_sw)と並列に処理されている
rmmode_shori1(hWnd,key_sw)
xmmode_shori2(hWnd,key_sw)...は何の問題はなく、

ejournal_check43(hWnd,key_sw)と並列に処理されている
   42(hWnd,key_sw)
41(hWnd,key_sw)...は何の問題はなし
そこで第一に疑われるのは
wintenkey(hWnd,key_sw,&su_cnt,keta,x,y,x2,y2)の内部処理だが、
この関数は汎用で使われて来たもので、このプログラム内でも
多数使われている。いづれも問題を起こしたことは一度もない。
問題を起こしている関数と他の関数との唯一の違いは
コンパイル単位が異なると言うこと。
wintenkeyと他の関数が主コンパイル単位のソースだとすると
ejournal_check43(hWnd,key_sw)は別のコンパイル単位のソースになる点です。
変数や関数がリンク時にどのように格納されているか知りませんが、
Windowsのバージョンによって、プログラム駆動時に格納の仕方に違いが
あるのかも知れません。デバッグバージョンでは当然利用されるメモリーは
大規模に確保されるでしょう。リリースバージョンとの違いはその点では
ないでしょうか。とにかく、現時点では未だ原因不明です。

/****************************
堺市南区原山台
上田 恭平
E_Mail ***@sannet.ne.jp
****************************/
UETA, Shin-ichi
2009-04-08 07:32:11 UTC
Permalink
どうも、植田です。
Post by unknown
問題発生の記述個所はこの元受関数から、呼出した関数内から更に呼出した
関数内で発生しています。
疑わしいのであれば、その関数の呼び出しを抑制して、
メッセージがちゃんと流れてくるかどうかを確認しては?

Windowsを疑う前にやるべきことはまだあると思います。

余分なものをそぎ落としてできるだけ素のウィンドウプロ
シージャに近づけていき、それでもなお期待どおりに動か
ないのであればWindowsを疑う必要が出てくるかもしれ
ません。

# Win95とはいえ、キー絡みでこんな障害はあっただろうか...?
Post by unknown
問題を起こしている関数と他の関数との唯一の違いは
コンパイル単位が異なると言うこと。
違う条件でコンパイルしているならともかく、同じ条件で
コンパイルしているかぎり、これは無視していいはずです。
何か問題があればリンカが警告してくれるでしょう。

# これを疑いだすと大規模なアプリケーションの開発には
# 常に不安がつきまとうことになって現実的ではないです。

ただし、Cの場合、リンク時に関数のシグネチャを照合でき
ないので、関数の宣言(プロトタイプ)が定義と異なっている
と思わぬトラブルを引き起こすかもしれません。
念のために確認してみては?
Post by unknown
変数や関数がリンク時にどのように格納されているか知りませんが、
Windowsのバージョンによって、プログラム駆動時に格納の仕方に違いが
あるのかも知れません。デバッグバージョンでは当然利用されるメモリーは
大規模に確保されるでしょう。リリースバージョンとの違いはその点では
ないでしょうか。
杉田さんも仰っているように、Debugビルドだからといって
Windowsのシステム部分にまで入り込んで何かをしている
わけではありません。
デバッグの対象のアプリケーションも、デバッガも、どちらも
独立したプロセスであり、デバッガはデバッグ用のAPIを
介してアプリケーションを制御しています。

Spy++もまたユーザーモードのプロセスであり、メッセージを
フックするためのAPIを活用してログを取っているだけです。

もちろん、デバッガやSpy++が介入することでパフォーマンス
に影響することはありますが、アプリケーションのロジックその
ものを破綻させてしまうようなことはまずありません。

# タイミングに依存するコードは要注意ですけど(苦笑)

Debugビルドが大きくなってしまうのは、コードが最適化され
ていないとか、アサーションなどのチェックが数多く含まれる
とか、それなりに理由があります。

メモリマップに依存するとか、仮想メモリ空間を限界まで食い
つぶしているとか、そんな極端なアプリケーションは別にして、
コードが多少大きくなったところでそれが直ちに問題になる
ことは滅多にないと思います。

余談ですが ――
Post by unknown
そもそもDefWindowProc(hWnd,message,wParam,lParam)の働きがもうひとつ
良く判らないものでちょっと不安です。
DefWindowProcは、その名のとおり、既定のウィンドウ
プロシージャを提供するAPIです。
Windowsアプリケーションに共通する基本的な振る舞いは
DefWindowProcによって成立します。
既定の振る舞いを明示的にオーバーライドするつもりが
ないのであれば、DefWindowProcを呼び出すのが鉄則
です。
--
植田システム設計事務所
Ueta System Design Studio
http://www.usdesign.jp/
植田真一
mailto:***@usdesign.jp
Loading...