長い処理中のキー入力、マウス入力をクリアしたい

[戻る]
JILL 2010/11/19(金) 11:37:03
WindowsCE5.0/eMbeddedVC++4.0SP4/SDK(MFC未使用)にて開発

お世話になります。
長い処理中のキー入力、マウス入力を処理が終わる際にクリアしたいと思い
"処理中"表示のモーダルダイアログを用いて次のように処理しています。

frm_OnRunningMes(m_hwnd, TEXT("処理中") );    // 文字列 表示開始処理
nagaisyori();        // 時間のかかる処理 実際はループ処理で通信処理
frm_OffRunningMes();    // 文字列表示ダイアログ破棄 & キー入力クリア処理

しかし、処理中に入力したキー入力が有効になってしまいます。
何がいけないのでしょうか?
長い処理を別スレッドとしない方法で考えたくお願いします。
ここで、長い処理とはループ内の通信処理ですが、ループ内でキー入力クリア
(以下に示すcnt_ClrInputMes)を実行してみましたが、やはりうまくいきませんでした。
以下は、ほぼ実際のソースです(一部省略)

HWND hwnd_Running;
// 任意のメッセージ(m_lpText)を表示にするモーダルウィンドウ表示開始
void frm_OnRunningMes(HWND m_hwnd, LPCTSTR m_lpText)
{
    LPTSTR    cmdStr;

    cmdStr = (LPTSTR)m_lpText;
    CreateDialogParam(g_hInst,MAKEINTRESOURCE(IDD_RUNNING),m_hwnd,
            (DLGPROC)RunningProc,(LPARAM)&cmdStr);
}

// 任意のメッセージを表示にするウィンドウ表示終了
void frm_OffRunningMes(void)
{
    if( hwnd_Running != NULL ){
        cnt_ClrInputMes();        // キー・マウスメッセージ削除
        DestroyWindow(hwnd_Running);
        hwnd_Running = NULL;
    }
}

void    cnt_ClrInputMes(void)
{
    MSG    myMsg;

    while (PeekMessage(&myMsg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, 
PM_REMOVE)){    // マウス系メッセージを削除
        Sleep(200);    // WindowsCEでは Sleepが必要なのかと思い 一
応入れてみました。
    }
    while (PeekMessage(&myMsg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)){
    // キー系メッセージを削除
        Sleep(200);    // WindowsCEでは Sleepが必要なのかと思い 一
応入れてみました。
    }
}

//メッセージ表示 ダイアログボックスプロシージャ
//スタティックコントロール IDC_MESSAGE をもつダイアログ
LRESULT CALLBACK RunningProc(HWND m_hwnd, UINT m_iMsg, WPARAM m_wParam, LPARAM 
m_lParam)
{
    LPTSTR        lpText;
    
    switch(m_iMsg) {
    case WM_INITDIALOG :
        lpText        = *((LPTSTR*)m_lParam);
        if(lpText) {
            SetDlgItemText(m_hwnd, IDC_MESSAGE, lpText);
        }
        break;

    case WM_ACTIVATE:
        if (WA_INACTIVE == LOWORD(m_wParam)){
            hwnd_Running = NULL;
        }else{
            hwnd_Running = m_hwnd;
        }
        return FALSE;
        break;
    // 以下省略
}
長くなり申しわけありませんが、よろしくお願いいたします。

2010/11/19(金) 22:44:36
適当書いてますので信用しないで下さいね。
長い処理の方で画面更新のためにPeekMessage使ってるとか?

>while (PeekMessage(&myMsg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE));
>while (PeekMessage(&myMsg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
メッセージクリアで上記は出来たと思うんだけど。
環境あるので、月曜になりますけど試してみます。

JILL 2010/11/20(土) 13:19:25
のさま、お世話になります。

>while (PeekMessage(&myMsg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE));
>while (PeekMessage(&myMsg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
いろんなサイトで調べたので、上記を実行してみたところだめだったので
一応Sleep入れてみたんですけど。やっぱりだめだったのです。

gak 2010/11/24(水) 18:14:52
Windows CE で PeekMessage でキー入力クリアしようとしたけどダメだった、という事例
があった。
http://blog.skychildren.jp/article/40587539.html
これが正しいのかどうかは検証していないけど、Windows CE 系ではこの方法は使えない
のかもね。

> frm_OnRunningMes(m_hwnd, TEXT("処理中") );    // 文字列 表示開始処理
> nagaisyori();        // 時間のかかる処理 実際はループ処理で通信処理
> frm_OffRunningMes();    // 文字列表示ダイアログ破棄 & キー入力クリア処理
この処理の頭に EnableWindow(m_hwnd, FALSE) 、末に EnableWindow(m_hwnd, TRUE) と
してはどうだろう?
無効ウィンドウはマウス入力とキー入力を受け取らない仕様だし。

ITO 2010/11/25(木) 14:02:33
 ウインドウの表示の変更等の様に見かけリアルタイムに処理しないといけない場合、
PeekMessage等でチェックするのはどうかと思います。
 1.フラグを用意して、nagaisyori()の処理の開始と終了のフラグをたてる。
 2.実際に操作を行なうウインドウでタイマー等で絶えず監視する。
にないとモーダルウインドウ上の処理とnagaisyori()の処理が合わなくなってしまう
可能性があると思います。

 あと、キー入力の有効/無効等の処理はデバッグをよくしないとまずいですね。
他のAPIのウインドウの下に隠れたときだけキー入力が有効になっていたなんてことはあ
りませんでしょうか?

JILL 2010/11/26(金) 08:49:57
gakさま、ありがとうございます。
>この処理の頭に EnableWindow(m_hwnd, FALSE) 、末に EnableWindow(m_hwnd, TRUE) と
>してはどうだろう?
試しました、がキー入力は無効にはなりませんでした。(悲)
 実は、下記を参考にしてDoEventsでの回避も試みたのですが、うまくできませんでし
た。
http://www.softist.com/programming/doevents/doevents.htm

ITOさま、ありがとうございます。
フラグも私なりに試しているのですが。。。実はシステム全体で特別なキー入力を
制御するためにキー入力をフックしています。上記のキーバッファクリアができなかった
ので、このフック処理の中でフラグがオンならキー入力を無効にする処理にしたのです
が、
完全に無効にはなりませんでした。
最初のキー入力は取り消すことができたけど、2文字目以降のキー入力が無効にならなく
て。。。
例:nagaisyori()処理中に'7','8','9'と3文字キー入力、
  nagaisyori()終了直後に2文字分の無効なキー入力を知らせる警告音が鳴る。
1.PeekMessageでバッファクリア→失敗
2.キーボードフック処理中にフラグ監視してキー無効→失敗
3.DoEvents風にして、キー制御に渡す→うまくできない
の状況です。3については、やりかたがまずかったのかもしれませんので再考します。

ITO 2010/11/26(金) 10:06:36
> フラグも私なりに試しているのですが。。。実はシステム全体で特別なキー入力を
> 制御するためにキー入力をフックしています。
  完全に無効にはなりませんでした。
  ----------- 省略
> 完全に無効にはなりませんでした。
> 最初のキー入力は取り消すことができたけど、2文字目以降のキー入力が無効になら
> なくて。。。
なるほど、それは難しそうですね。
「特殊なキー入力」となるとデバイスドライバー等がからんでないでしょうか?
WindowsCEのデバイスドライバーは特殊なので、その場合はドライバー開発者に
問い合わせた方がいいですね。

> 実は、下記を参考にしてDoEventsでの回避も試みたのですが、うまくできませんでし
> た。
DoEventsは.NET Frameworkの関数ですね。
全体として、.NET Frameworkを使用しているのですか?
もしそうでないのなら、SetEvent / WaitForSingleObject等を使用した方がいいです
ね。

ITO 2010/11/26(金) 11:11:54
修正です。
>もしそうでないのなら、SetEvent / WaitForSingleObject等を使用した方がいいです
>ね。
僕個人としては、イベント同期をすすめたいのですが、
DoEventsに対応するのは、ユーザイベント登録みたいですね。
.NET Frameworkは使わないので失礼しました。

メッセージ処理は、約200mSのタイムロスがあります。
>一応Sleep入れてみたんですけど。やっぱりだめだったのです。
うーん、Sleepは難しいですね。
他に起動しているAPIによって時間が変わります。
仮にSleep入れるとなると200mS以上、できれば2倍、3倍、400/600mS位は必要だと
思います。
特にWindowsCEだと組み込んでいるCPUによって変わるので難しいと思います。

JILL 2010/11/26(金) 14:19:05
ITOさま、ありがとうございます。
Sleepを200→2000まで少しずつ増やしながら試しましたが、2000にしてもダメでした。

ところが、いろいろ試しているうちに、全然、意図して行ったわけではありませんが、
プログラムを2重起動して実行した場合は冒頭に記載した処理でキー入力をクリアするこ
とができました。
(Sleepの値を200でもSleepを実施しなくても)
このことは何を意味しているのでしょうか?
2重起動は本来の運用では許可しませんし、当然2重起動することが解決ではないと
思うのですが、この結果から解決の糸口がみつかりません。
なにかお知恵をお持ちの方がいらっしゃいましたら、お願いします。

ITO 2010/11/27(土) 16:24:39
> このことは何を意味しているのでしょうか?
うん?
 ウインドウがアクティブにならないうちに、キー入力を無効にする処理
 を行なってしまう。
ってことはないですか?
2回目は、アクティブになっているので処理が有効なのかな?

>この結果から解決の糸口がみつかりません。

うーん、
 同じ内容で別名のプロジェクトのコピーを作る。
 コピー版のソースを削っていってどこが原因か調べる。
ぐらいしか思いつきませんね。

  

PATIO 2010/11/29(月) 16:44:21
同じスレッド内で待つ処理もキーイベントも
一緒に処理しようと言う時点でかなり無理があると思いますが、
待つ処理の所為でメッセージループが止まった状態ですからねぇ。

ITOさんが書いておられるように
ウインドウがアクティブになりきる前に処理が動いてしまっているのでは
と言う気がします。
いっその事、マルチスレッド化してしまった方がすっきりしそうですけれど、
何か制約があるんですかねぇ。
通信の待ち合わせならマルチスレッド化しても弊害は少なそうですけれど。
裏でバンバン動いて表が止まるなんて事はなさそうですし。
そうでもないのかなぁ。
組み込み系は実装次第でいろいろ違いが出るから
実装絡みの制限だったりするといかんともしがたいですけど。

JILL 2010/11/29(月) 20:25:14
ITOさま、PATIOさまありがとうございます。
あきらめかけていましたが、解決しました。
【変更前】
冒頭で示すfrm_OffRunningMes(下記B)内で
「○○中」表示用のモーダレスダイアログを破棄する際に
キー入力系のメッセージを削除するcnt_ClrInputMesを実行していました。

frm_OnRunningMes(m_hwnd, TEXT("処理中") ); //@
nagaisyori();        // A
frm_OffRunningMes();    // B
frm_MsgBox();  // C
【変更後】
実はBの後に処理結果を表示するメッセージボックス(っぽいもの)を実行していまして、
このCの処理でダイアログをクリエイトする直前にcnt_ClrInputMesを実行しました。
ただし、当初指定していたPeekMessage前のSleep()の値は200→300に変えています。
そうしたら、キー入力メッセージは削除されました。
Sleepの時間を短くするとやっぱりだめなので、メッセージが到着(?)するまでに時間がか
かるのでしょうか?(WindowsCEだから???)
原因は不明ですが、解決とさせていただきます。
みなさま、お騒がせいたしました。

JILL 2010/11/29(月) 20:25:40
[[解決]]
解決をチェックし忘れました。

古いスレッドには追加発言できません。