C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[5]: WndProcの処理を止める方法


(過去ログ 117 を表示中)

[トピック内 15 記事 (1 - 15 表示)]  << 0 >>

■68841 / inTopicNo.1)   WndProcの処理を止める方法
  
□投稿者/ kota (1回)-(2013/11/21(Thu) 19:22:52)

分類:[.NET 全般] 

2013/11/21(Thu) 20:40:04 編集(投稿者)

WndProcを使って他のアプリケーションと通信していますが、
自分のアプリケーションの中で
private void waitTimer(int millSec)
{

DateTime start = DateTime.Now;
for (; ; )
{
TimeSpan duration = DateTime.Now - start;
if ((duration.Seconds * 1000 + duration.Milliseconds) > millSec)
{
break;
}
Application.DoEvents();
Thread.Sleep(10);
}
}

というコードを使ってWaitをしていますが、Application.DoEvents()が誤動作をします。
一時的に WndProcを無効にする方法はあるでしょうか?

引用返信 編集キー/
■68842 / inTopicNo.2)  Re[1]: WndProcの処理を止める方法
□投稿者/ Azulean (239回)-(2013/11/21(Thu) 22:23:50)
No68841 (kota さん) に返信
> Application.DoEvents()が誤動作をします。

誤動作とは何を指していますか?
理想とする動きに対して、今はそれと異なる動きをしているので「誤動作」と表現されているのでしょうけれども、正直、第三者にはそれが何かわからないのです。


> 一時的に WndProcを無効にする方法はあるでしょうか?

ウィンドウメッセージを処理したくないということでしょうか?
そうすると、画面が白くなったり、応答なしになったり、ユーザーが操作できなかったりしますが、本当にそれでよいのでしょうか。
引用返信 編集キー/
■68843 / inTopicNo.3)  Re[2]: WndProcの処理を止める方法
□投稿者/ kota (2回)-(2013/11/22(Fri) 09:39:20)
No68842 (Azulean さん) に返信

誤動作はその時により若干異なるのですが(メッセージの入り方により)、
時によってタイマーのループから抜けません。
Application.DoEvents()によりメッセージループの
呼び出しが無限ループになっているように見えます。

無効にしたいとはビルド時の [Conditional("Debug")]属性のように
メッセージのフックそのものを一時的に止めたいということです。
WndProc(ref Message m)関数をコードに入れない状態になることが
理想的です。


>画面が白くなったり、応答なしになったり、ユーザーが操作できなかったりしますが
それを防ぎたいので、Application.DoEvents()を入れています。

よろしくお願いします。

引用返信 編集キー/
■68844 / inTopicNo.4)  Re[3]: WndProcの処理を止める方法
□投稿者/ Hongliang (127回)-(2013/11/22(Fri) 11:34:27)
> WndProc(ref Message m)関数をコードに入れない状態になることが
> 理想的です。

> それを防ぎたいので、Application.DoEvents()を入れています。

矛盾してますよ。
DoEventsはWndProcの呼び出しとおよそ同義です。
WndProcが呼び出されなかったらDoEventsを呼び出す意味もありません。

旧VBではそういう手法が使われていたこともありますが(擬似マルチスレッドのためでしたっけ?)
今時ではUIスレッドで長時間の処理をしたりApplication.DoEventsを呼び出したりするのはおよそ禁じ手とされています。
タイマを使ったりスレッド処理を使ったりして、非同期で動作できるように構成してください。
引用返信 編集キー/
■68859 / inTopicNo.5)  Re[4]: WndProcの処理を止める方法
□投稿者/ よる (1回)-(2013/11/22(Fri) 21:52:55)
> WndProcを使って他のアプリケーションと通信していますが、
> Application.DoEvents()が誤動作をします

DoEvents内ではあらゆるメッセージが処理されているはずなので、
目的の動作が(具体的に何なのかわかりませんが)すっ飛んでいるんでしょう。多分…

APIを使って特定のウィンドウメッセージだけを処理し
画面の再描画のみを行う事もできますが、お勧めしないです。

参考:
時間がかかる処理での「応答なし」を回避するには?
http://www.atmarkit.co.jp/fdotnet/dotnettips/136doevents/doevents.html



※補足
> WndProcを使って他のアプリケーションと通信
実際にやりたい事と現在の実装方法を書いた方が、適切な回答をもらえると思いますよ(丸投げ)。


引用返信 編集キー/
■68860 / inTopicNo.6)  Re[1]: WndProcの処理を止める方法
□投稿者/ Jitta (95回)-(2013/11/22(Fri) 22:16:27)
Jitta さんの Web サイト
No68841 (kota さん) に返信

> private void waitTimer(int millSec)
> {
>
> DateTime start = DateTime.Now;
> for (; ; )
> {
> TimeSpan duration = DateTime.Now - start;
> if ((duration.Seconds * 1000 + duration.Milliseconds) > millSec)
> {
> break;
> }
> Application.DoEvents();
> Thread.Sleep(10);
> }
> }

 このコードが、「一定時間待つ」ということをしたいがためのコードであるなら、
タイマーで通知してもらう方が、ずっと少ないコードで管理も楽だと思います。
引用返信 編集キー/
■68864 / inTopicNo.7)  Re[2]: WndProcの処理を止める方法
□投稿者/ kota (3回)-(2013/11/22(Fri) 23:52:57)
No68860 (Jitta さん) に返信
> ■No68841 (kota さん) に返信
>
>> private void waitTimer(int millSec)
>> {
>>
>> DateTime start = DateTime.Now;
>> for (; ; )
>> {
>> TimeSpan duration = DateTime.Now - start;
>> if ((duration.Seconds * 1000 + duration.Milliseconds) > millSec)
>> {
>> break;
>> }
>> Application.DoEvents();
>> Thread.Sleep(10);
>> }
>> }
>
>  このコードが、「一定時間待つ」ということをしたいがためのコードであるなら、
> タイマーで通知してもらう方が、ずっと少ないコードで管理も楽だと思います。
引用返信 編集キー/
■68865 / inTopicNo.8)  Re[3]: WndProcの処理を止める方法
□投稿者/ kota (4回)-(2013/11/22(Fri) 23:54:41)
回答ありがとうございます。

工業用のPCにOSはXp(客指定)のOSでリアルタイムモニター
のような使い方をしています。
PCIのGPIB、96IN/48OUTのI/Oボード、A/Dボード、3軸のモーター
コントロールボード、RS−232Cのティーチングペンダント
計測用にマルチポイントシリアルRS-485が3本繋がっています。

GPIB、232C、I/O、A/Dボードはマルチスレッドタイマーで
読み込んで、メインスレッドにチェンジイベントをあげ、
RS-485は別ソフトがメッセージを投げてきます。

自作のタイマーを含めタイマーは200個ほど使っています。
計測器などは非同期でも構わないのですが、モーターコントロールは
同期が必要で、メインスレッドで処理しています。
モーターの動きを監視し目的の場所に移動するまで、メインスレッドは
ループで待ちます。

待っている間、測定器からのメッセージはSenndMessageで待たせます。
ただしI/OからのStopコマンドは受け付ける為に、Doeventで処理を
します。
この時、自分のWndProcのコールバックメソドに処理が入り込み、
抜け出さない(これは想像ですが)症状が起きます。
仕方なく現在は単にsleepを入れています。

そこで一時的にWndProcのコールバックを禁止する方法が無いものか
と質問しました。

現在システムは殆ど完成していますがI/Oの読み込みが少し遅いために、
コードを見直しています。

引用返信 編集キー/
■68866 / inTopicNo.9)  Re[4]: WndProcの処理を止める方法
□投稿者/ Azulean (240回)-(2013/11/23(Sat) 00:04:20)
2013/11/23(Sat) 00:06:18 編集(投稿者)

No68865 (kota さん) に返信
> 待っている間、測定器からのメッセージはSenndMessageで待たせます。
> ただしI/OからのStopコマンドは受け付ける為に、Doeventで処理を
> します。
> この時、自分のWndProcのコールバックメソドに処理が入り込み、
> 抜け出さない(これは想像ですが)症状が起きます。
> 仕方なく現在は単にsleepを入れています。

すでに指摘のあるとおり、DoEvents を呼んだ時点でメッセージは処理されるものです。
特定のメッセージだけ遅延させるという都合のいいものはないと考えた方がよいでしょう。
(GetMessage とかを自分で呼ぶなら別でしょうけれども)


> そこで一時的にWndProcのコールバックを禁止する方法が無いものか
> と質問しました。

ウィンドウメッセージベースでの通信となっていることと、それを待たせなければならない要求・設計の時点で、UI の操作性が損なわれる許容すべきことかと思います。
SendMessage で送られてくる処理を必ず待たせないといけないのであれば、DoEvents は使わないことです。そして、その結果として応答なしと出ることも許容しなければなりません。


これが許せないであるとか、メッセージベースなのでパフォーマンスを上げられないとか、そういったことになると、完成間近であろうと抜本的な見直しが必要だと思います。
ウィンドウメッセージに頼った通信部分を見直せないかとか、ソフトを変えられないなら自作するとか。
引用返信 編集キー/
■68871 / inTopicNo.10)  Re[4]: WndProcの処理を止める方法
□投稿者/ しま (44回)-(2013/11/23(Sat) 09:39:38)
No68865 (kota さん) に返信
> 回答ありがとうございます。
>
> 工業用のPCにOSはXp(客指定)のOSでリアルタイムモニター
> のような使い方をしています。
> PCIのGPIB、96IN/48OUTのI/Oボード、A/Dボード、3軸のモーター
> コントロールボード、RS−232Cのティーチングペンダント
> 計測用にマルチポイントシリアルRS-485が3本繋がっています。
>
> GPIB、232C、I/O、A/Dボードはマルチスレッドタイマーで
> 読み込んで、メインスレッドにチェンジイベントをあげ、
> RS-485は別ソフトがメッセージを投げてきます。
>
> 自作のタイマーを含めタイマーは200個ほど使っています。
> 計測器などは非同期でも構わないのですが、モーターコントロールは
> 同期が必要で、メインスレッドで処理しています。
> モーターの動きを監視し目的の場所に移動するまで、メインスレッドは
> ループで待ちます。
>
> 待っている間、測定器からのメッセージはSenndMessageで待たせます。
> ただしI/OからのStopコマンドは受け付ける為に、Doeventで処理を
> します。
> この時、自分のWndProcのコールバックメソドに処理が入り込み、
> 抜け出さない(これは想像ですが)症状が起きます。
> 仕方なく現在は単にsleepを入れています。
>
> そこで一時的にWndProcのコールバックを禁止する方法が無いものか
> と質問しました。
>
> 現在システムは殆ど完成していますがI/Oの読み込みが少し遅いために、
> コードを見直しています。
>

画面の処理がない、若しくは画面の制御が分離できるのであれば
サービスとして動かすといいかもしれません
ただ、Windows はリアルタイムOSではないので 100mS 以内に応答するといったことは必ずしも
望めないことはご存知のことと思います
ですから、高速な応答が必要な場合はプロセスでもスレッドでも自分の処理が終わったらタイムスロットをOSに
返却(自分に割当たっているタイムスロットを独占しない)することが大切です

ところで、
> 自分のWndProcのコールバックメソドに処理が入り込み、抜け出さない

とありますが、 WndProc のコールバックとはなんのことでしょうか?
分類 .NET全般 とあったので貼り付けていたコードの記述言語は C# かと思っていましたが、 C/C++ なんですか?

開発環境、動作環境については書いてください。
引用返信 編集キー/
■68872 / inTopicNo.11)  Re[5]: WndProcの処理を止める方法
□投稿者/ kota (5回)-(2013/11/23(Sat) 10:19:47)
No68871 (しま さん) に返信
回答有難うございます。

言語はC#です。
コールバックと書いたのは
>>http://msdn.microsoft.com/ja-jp/library/ms229658(v=vs.90).aspx
の英語のコメントで
// This is a generic wndproc. It is the callback for all hooked
// windows
と書いてあったので使いましたが、正しくありませんでしょうか。

Windowsの応答に関しては制御ループ一巡の時間を測定して、
何とか使える範囲であることを確認しています。
遅いですが。

OSは書きました、ハードはPentium 4 2Gだと思います。
引用返信 編集キー/
■68873 / inTopicNo.12)  Re[6]: WndProcの処理を止める方法
□投稿者/ しま (45回)-(2013/11/23(Sat) 10:46:38)
No68872 (kota さん) に返信
> ■No68871 (しま さん) に返信
> 回答有難うございます。
>
> 言語はC#です。
> コールバックと書いたのは
> >>http://msdn.microsoft.com/ja-jp/library/ms229658(v=vs.90).aspx
> の英語のコメントで
> // This is a generic wndproc. It is the callback for all hooked
> // windows
> と書いてあったので使いましたが、正しくありませんでしょうか。

C# なのか C/C++ なのか文面だけではよくわからなかったからです。
決して言葉の使い方が正しいとか間違っているとかいうことではございません

> Windowsの応答に関しては制御ループ一巡の時間を測定して、
> 何とか使える範囲であることを確認しています。
> 遅いですが。
>
> OSは書きました、ハードはPentium 4 2Gだと思います。

>>開発環境、動作環境については書いてください。
言葉足らずでした。最初の投稿で書いて欲しかったという意味です

余計なことかもしれませんが、高速な動作が必要な場合はメモリーもプロセッサー(CPU)も早いほうがいいです
ソフトで解決できないことがハードウエアーを変えることで解決してしまうことがあります
引用返信 編集キー/
■68876 / inTopicNo.13)  Re[5]: WndProcの処理を止める方法
□投稿者/ よる (2回)-(2013/11/23(Sat) 13:13:36)
各種信号は別スレッドで拾ってからメインスレッドへ集約されていて、
メインスレッド=モーターコントロール用のスレッド=GUIスレッドという認識で良いでしょうか?

GUI側/制御側のレスポンス双方に影響がありそうな気がします。
現状ではイベント(ウィンドウメッセージ)で各種制御をしているわけですから、DoEventの使用はかなり危険です。
GUI(メイン)スレッドと制御スレッドを分離し、制御側がイベントに依存しない様にする事が考えられます。

・各種信号について、別スレッドからメインスレッドにイベントを投げている箇所を見直す(イベントを使わない)。
→プログラム内で信号状態を保持する。(listで状態/コマンド履歴を持つときもありますが)
・モーターコントロールをメインスレッドとは別スレッドで行う。
・各種信号状態を上記モータコントロール用スレッドで使用する(スレッドセーフに扱う事)。


それと、SendMessageはPostMessageでは駄目ですか?
SendMessageでは転送先で処理が終わるまで転送元の処理がブロックされます。
処理完了を待っているのであれば、要求/要求処理完了のハンドシェイクを互いにPostMessageで行うとか。





引用返信 編集キー/
■68877 / inTopicNo.14)  Re[4]: WndProcの処理を止める方法
□投稿者/ Jitta (99回)-(2013/11/23(Sat) 13:15:52)
Jitta さんの Web サイト
No68865 (kota さん) に返信
> 工業用のPCにOSはXp(客指定)のOSでリアルタイムモニター
> のような使い方をしています。

 どれくらいの「リアル」を求めるかにも依りますが、Windows でリアルタイムを求めるのには、無理があります。
そのことは、納得済みなのでしょうか。たとえば、I/O 要求が重なると、簡単に遅延します。


> 自作のタイマーを含めタイマーは200個ほど使っています。
> 計測器などは非同期でも構わないのですが、モーターコントロールは
> 同期が必要で、メインスレッドで処理しています。
> モーターの動きを監視し目的の場所に移動するまで、メインスレッドは
> ループで待ちます。

 そもそも、モーターの制御を Windows OS でやろうというところが間違っているように思います。
いや、求める精度によるけど。


> 待っている間、測定器からのメッセージはSenndMessageで待たせます。
> ただしI/OからのStopコマンドは受け付ける為に、Doeventで処理を
> します。

 この理由で、メインスレッドでなければならないとは思えません。
メインスレッドというのは、起動したときのスレッドだというだけです。
スレッドの優先度を指定しないなら、どのスレッドでも優先度は同じです。

引用返信 編集キー/
■68885 / inTopicNo.15)  Re[5]: WndProcの処理を止める方法
□投稿者/ kota (6回)-(2013/11/23(Sat) 19:52:49)
すみません、質問の本題は、題名にあるように
WndProcを一時的に無効にする方法は有るか無いか
お聞きしたかったのです。
「無い」ということであれば、他の方法を考えます。
特にそれほど悩んでいるわけではなく、メッセージフックを
一時的に無効に出来るのであれば、そちらの方法も検討しようかな
と思った次第です。
回答者さんの回答はそんな方法はないので、Application.DoEvents()
を止めろという回答と理解しました。
納得です。

回答者さんの質問に答えているうちになぜか重い処理や、非力な
環境をどうにかしたいという方向に向かってしまいました。
多分私がいけなかったのでしょう。
申し訳ありませんでした、解決とさせていただきます。

以下質問にお答えします。
■(しま さん) に返信
>高速な動作が必要な場合はメモリーもプロセッサー(CPU)も
早いほうがいいですソフトで解決できないことがハードウエアーを
変えることで解決してしまうことがあります

全くその通りであると思います、私もXP上のプログラムなど
書きたくないのですが客指定のハードとOSです。(泣


■(よる さん) に返信
>どれくらいの「リアル」を求めるかにも依りますが、
Windows でリアルタイムを求めるのには、無理があります。
そのことは、納得済みなのでしょうか。たとえば、
I/O 要求が重なると、簡単に遅延します。

>そもそも、モーターの制御を Windows OS でやろうというところが
間違っているように思います。いや、求める精度によるけど。

I/Oはマルチスレッドタイマーでスキャンし、変化が有れば
メインスレッドにInvokeしています。
I/Oはビットイメージなので、ワード単位で8w読むだけなので、
状態が変化しても遅延はしませんが、メカニカルな押しボタンの
有効無効の判断に時間がかかります。

モーターは専用のモータードライバーが有って、PCからDLL経由で
速度、加速度、行先を指示しますが、PCの負担は大きくありません。
精度は専用ハードが0.1mm単位で制御します。

>この理由で、メインスレッドでなければならないとは思えません。
メインスレッドで同期をとるのはデバッグ環境に依存するところが
大きいのです。
VS2010によるマルチスレッドの開発環境は快適とは言えません。
私の使い方が悪いのかもしれませんが。


解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -