連続的なメッセージの解消について

ActiveBasicでのプログラミングでわからないこと、困ったことなどがあったら、ここで質問してみましょう(質問を行う場合は、過去ログやWeb上であらかじめ問題を整理するようにしましょう☆)。
返信する
メッセージ
作成者
jacoby
記事: 106
登録日時: 2006年6月02日(金) 18:20

連続的なメッセージの解消について

#1 投稿記事 by jacoby »

一つのスレッドと、ウインドウ上に一つのメニュー「Test」を持つプログラムがあるとします。
ここでウインドウ上のメニュー「Test」をクリックすると
スレッド内の特定の処理を行わせたいとします。

メニュー「Test」クリック・イベントで

コード: 全て選択


'
'●Testメニュー・クリックイベント
'
Sub MainWnd_IDM_Test_MenuClick()

 PostThreadMessage(thread1_ID,MYTHREADMSG_TEST,0,0)

End Sub
スレッド1にPostThreadMassageにより"MYTHREADMSG_TEST"をポスト


これをスレッド1中の

コード: 全て選択


 ret=PeekMessage(myMsg,NULL,0,0,PM_REMOVE)
で拾い、

コード: 全て選択


 If myMsg.message=MYTHREADMSG_TEST Then
   Print "Got MYTHREADMSG_TEST"
   Sleep (3000)
 End If
として、If文の中でとりあえず仮の処理(3秒待つ)を行わせています。

 ここで問題なのが、その特定の「処理」がかなり時間の掛かるものだった
場合、メニュー「Test」をせわしなく連続的にクリックした時にメッセージキューの
中に信号メッセージであるMYTHREADMSG_TESTが一方的に溜まっていってしまい
それらのメッセージがすべて無くなるまで「処理」を実行し続けてしまいます。

 もちろんこのこと自体は正常な動作なのですが、仮に、スレッド1内の
PeekMassageでMYTHREADMSG_TESTを受け取ったとき、
メッセージキュー中に他にも同一のメッセージ(MYTHREADMSG_TEST)が
ポストされているなら、それらを全て削除する、というようなことが出来ればと
思っています。

 メッセージキュー中の、同一のメッセージのクリア、について良い方法があれば、
あるいはそれ以外でも、このような連続的なメッセージ・ポストの解消方法があれば
是非教えて下さい。
konisi
記事: 893
登録日時: 2005年7月25日(月) 13:27
お住まい: 埼玉県東松山市
連絡する:

#2 投稿記事 by konisi »

PeekMessage関数を使っているのですから、
補助用の変数を使用して、受け取れなくなるまで受け取り、
最後に取得した有効な物を使用してはどうでしょうか?
#小休止なし無限ループで使う時はGetMessageの方がいい気がします。

あるいは、別途受け取り専用のスレッドを作成し、
その中で専用のキューを用いて処理してもいいかもしれません。

イメージ
作業スレッド→(終了を意味するメッセージを発行)→受け取り用スレッド
↓↑(状態遷移)
受け取り用スレッド→(次のコマンド発行)→作業スレッド
↑(コマンド発行)
Main

又は、今回の場合はメニューを一時的にEnableMenuItem等で押せない状態にするのもいいかもしれません。
Website→http://web1.nazca.co.jp/himajinn13sei/top.html
ここ以外の場所では「暇人13世」というHNを主として使用。

に署名を書き換えて欲しいと言われたので暇だしやってみるテスト。
jacoby
記事: 106
登録日時: 2006年6月02日(金) 18:20

レスありがとうございます。

#3 投稿記事 by jacoby »

konisiさん、レスありがとうございます。
PeekMessage関数を使っているのですから、
補助用の変数を使用して、受け取れなくなるまで受け取り、
最後に取得した有効な物を使用してはどうでしょうか?
そうなんです。まさにキユーの中から「最後に取得した有効な物」を
取ることが出来ればそもそもクリアなどの必要も無く一番良いのですが、
その方法が分からず、
 ただ単にPeekMessageでは時間的に一番先にポストされたものから
順に取っていってしまうので、、

 もし宜しければその方法を教えていただけたら有り難いです。

(上の仮プロジェクトではPeekMessageである意味はあまり無いのですが
元々のプログラムでスレッド1のループでキー入力などを受け付ているので
GetMessageでなくPeekの方を使わせて貰いました。)
konisi
記事: 893
登録日時: 2005年7月25日(月) 13:27
お住まい: 埼玉県東松山市
連絡する:

#4 投稿記事 by konisi »

だいたいこんな感じですかね?

コード: 全て選択

Dim myMsg As MSG
Dim myMsg_ As MSG
Do
    If PeekMessage(myMsg_,NULL,0,0,PM_REMOVE)=FALSE then
        Exit Do'メッセージがうまく取得できなくなった
    End If
    'ここら辺でmyMsg_の情報を解析して、コピーする必要が無ければそのままcontinueしてもいいと思う。

    myMsg=myMsg_'本体に情報をコピー
Loop'抜けた時にmyMsgに最終情報が入っている。ただしキューは空になってしまう。
この手の奴はあまりやったことがないので正しいかどうか自信がないのですが。

追記:今思いついたのですが、同じような手法で作業終了時にキューを空にしてあげるというのもいいかもしれません。
Website→http://web1.nazca.co.jp/himajinn13sei/top.html
ここ以外の場所では「暇人13世」というHNを主として使用。

に署名を書き換えて欲しいと言われたので暇だしやってみるテスト。
jacoby
記事: 106
登録日時: 2006年6月02日(金) 18:20

レスありがとうございます。

#5 投稿記事 by jacoby »

'ここら辺でmyMsg_の情報を解析して、コピーする必要が無ければそのままcontinueしてもいいと思う。
僕の理解がいまいちあやふやで申し訳ないのですが
「myMsg_」はメッセージ構造体でこれは「メッセージ・キュー」では
無いですよね。つまりこの中にはポストされたメッセージ自体に関する
情報が入っている。
このメッセージが時間的にもっとも後にポストされたものかどうかを
知るには、「メッセージ・キュー」全体を見ることが
必要なのではないでしょうか。

「キューを空に」というのも出来たら良いのですが、どうやってキューに
アクセスしたらいいのか。。
Googleなどで少し調べたりもしているんですけども、それが悩んでいる所です。
jacoby
記事: 106
登録日時: 2006年6月02日(金) 18:20

Do~Loop?

#6 投稿記事 by jacoby »

書いて頂いたプログラムは「Do~Loop」でメッセージを取れるだけ取って
その結果メッセージキュー全体を取り出す、という理解で良いでしょうか?
だとしたら僕の上の
このメッセージが時間的にもっとも後にポストされたものかどうかを
知るには、「メッセージ・キュー」全体を見ることが
必要なのではないでしょうか。
というのは、これによって実現されていますね。浅い理解ですみません。

ただこの方法は、もしメッセージキュー中に他の別のメッセージがまぎれて
ポストされていた場合、最後のMYTHREADMSG_TESTの検出の為に
キューの取り出し先頭位置を繰り上げ続けてしまい、結果
本来のメッセージ取得ループおいて、その別のメッセージを取り逃がすことも
あるのではないかとも思いますが、、
 どうでしょうか?
イグトランス
記事: 899
登録日時: 2005年5月31日(火) 17:59
お住まい: 東京都
連絡する:

#7 投稿記事 by イグトランス »

それならPeekMessage(myMsg_, NULL, MYTHREADMSG_TEST, MYTHREADMSG_TEST, PM_REMOVE)とすればよいです。
PeekMessageとGetMessageは,3番目の引数から4番目の引数までの範囲のメッセージだけを対象にするという使い方ができます。
(普段よくやる両方に0を指定した場合は、全てのメッセージが対象になります)
jacoby
記事: 106
登録日時: 2006年6月02日(金) 18:20

レスありがとうございます。

#8 投稿記事 by jacoby »

それならPeekMessage(myMsg_, NULL, MYTHREADMSG_TEST, MYTHREADMSG_TEST, PM_REMOVE)とすればよいです。
PeekMessageとGetMessageは,3番目の引数から4番目の引数までの範囲のメッセージだけを対象にするという使い方ができます。
peekMessageのヘルプを見たとき、これらの設定は何の為にあるんだろうと
思っていたところです。
これに先のDo~Loopチェックを組み合わせればキューの中から
MYTHREADMSG_TESTだけを削除することが可能ですね。
ありがとうございます。

それからkonisiさんが指摘されていたように「処理」の実行中
メニュークリックを無効化ロックしてそもそもメッセージを溜めないようにすることも
安全な処置だなと思っています。

konisiさん、イグトランスさん、レスありがとうございました。
返信する