VBでいう DoEvents をAPI等々で実現したい。。。

ActiveBasicでのプログラミングでわからないこと、困ったことなどがあったら、ここで質問してみましょう(質問を行う場合は、過去ログやWeb上であらかじめ問題を整理するようにしましょう☆)。
返信する
メッセージ
作成者
けんどん

VBでいう DoEvents をAPI等々で実現したい。。。

#1 投稿記事 by けんどん »

はじめまして。けんどん と申します。

みなさんのお知恵を拝借したく、トピックを新規投稿いたしました。

内容としては、ABでVB言語の'DoEvents'関数はないことは認識していますが、
この関数をAPIにて実装できないものかと考えています。

私もそうですが、使えたら良いのに・・・という人が以外と多いのではないでしょうか?

一時期、Sleep関数などを代替案に考えたのですが、結果的にイマイチでした。

自分なりに色々と調べて努力してみましたが、見当が付かずに困っています。
よろしければ、ヒントだけでもいただけないでしょうか?
やはり実現不可でしょうか?

最終的に完成したモジュールをみなさんに公開したいと思っています。
てふろん

Re: VBでいう DoEvents をAPI等々で実現したい。。。

#2 投稿記事 by てふろん »

こんにちは、てふろんです。

DoEvent がどんな物か分からなかったんですが、
ググッてみるとどうやらメッセージを処理させるようで。

コード: 全て選択


Function DoEvent( ByRef ExitCode As Long ) As Long

Dim wndMsg As MSG
Dim Result As Long

While( PeekMessage( wndMsg, NULL, 0, 0, PM_NOREMOVE ) )
Result = GetMessage( wndMsg, NULL, 0, 0 )
If 0 = Result Or -1 == Result Then
ExitCode = wndMsg.wParam
DoEvent = FALSE
Exit Function
End If
TranslateMessage( wndMsg )
DispatchMessage( wndMsg )
Wend

DoEvent = TRUE

End Function
テストしないまま即興で書いたのでなんとも言えませんが、
必要な所で上記プロシージャを呼び出せば
メッセージがある時だけメッセージを処理してくれると思います。
てふろん

Re: VBでいう DoEvents をAPI等々で実現したい。。。

#3 投稿記事 by てふろん »

こんにちは、再びてふろんです。

> If 0 = Result Or -1 == Result Then
ついつい、Cの癖が...

> If 0 = Result Or -1 = Result Then
と読み替えてください。
失礼致しました。
イグトランス
記事: 899
登録日時: 2005年5月31日(火) 17:59
お住まい: 東京都
連絡する:

Re: VBでいう DoEvents をAPI等々で実現したい。。。

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

> While( PeekMessage( wndMsg, NULL, 0, 0, PM_NOREMOVE ) )
> Result = GetMessage( wndMsg, NULL, 0, 0 )
単にWhile PeekMessage(wndMsg, NULL, 0, 0, PM_REMOVE)でいいと思いますよ。
そのときはその代わりに次のIfを次のようにする必要があります。
If wndMsg.message = WM_QUIT Then

まあWM_QUITが来たらそのままExitProcessを呼んでも良いと思いますが。
NoWest
記事: 264
登録日時: 2005年5月31日(火) 10:52
お住まい: 高知
連絡する:

Re: VBでいう DoEvents をAPI等々で実現したい。。。

#5 投稿記事 by NoWest »

> > While( PeekMessage( wndMsg, NULL, 0, 0, PM_NOREMOVE ) )
> > Result = GetMessage( wndMsg, NULL, 0, 0 )
> 単にWhile PeekMessage(wndMsg, NULL, 0, 0, PM_REMOVE)でいいと思いますよ。
> そのときはその代わりに次のIfを次のようにする必要があります。
> If wndMsg.message = WM_QUIT Then
>
> まあWM_QUITが来たらそのままExitProcessを呼んでも良いと思いますが。

そもそもDoEvents関数はC++のようにマルチスレッドが扱えなかった頃のVBの苦肉の策といった代物です。
DoEvents関数を呼び出す時点でパフォーマンスが低下するので、本来使用は極力避けるべきものだと私は思っていますが、人によって便利といえば便利なんでしょうね。

P.S.1 私は出来る限りイベントプロシージャがCPUを占有することがないようにプロシージャ内のプログラムは短くしたりFor文を避けるようにしています。

P.S.2 メッセージイベント実行中に別のメッセージを動かすというのは
グローバル変数が絡んでくると誤動作の原因になりそうな気もしますね


てふろん様とイグラトス様のご意見を参考にすると以下のようになります。

コード: 全て選択

Function DoEvents() As Long
	Dim msg As MSG
	While PeekMessage(msg,NULL,0,0,PM_REMOVE)=TRUE
		Select Case msg.message
			Case WM_QUIT
				ExitProcess(0)
			Case Else
				TranslateMessage(msg)
				DispatchMessage(msg)
		End Select
		Sleep(0)/*←不要かもね(別のスレッドに迷惑かけないように。。。)*/
	Wend
End Function
古いVBではDoEvents関数の戻り値はコントロールの数になっているようですが最近のVBでは常に0が返るようです。
マティ
記事: 161
登録日時: 2005年8月23日(火) 00:15
お住まい: 沖縄県
連絡する:

#6 投稿記事 by マティ »

Winは基本的にメッセージ駆動(擬似的なマルチスレッド)なので、各アプリケーションは一定時間以内に処理をシステムに返す必要があります。
(アプリケーションは基本的にプロセス管理です。また、WinAPIを呼び出すことにより、処理をシステムに戻せたはずです)

そうしないと、他のアプリケーション動作に影響を与えます。

NoWestさんも書いているように、DoEventsはVBでマルチスレッドが扱えなかった頃に、処理をシステムに強制的に戻す為の関数です。
その副作用としてDoEventsを呼び出した再に別メッセージの処理が始まってしまい、整合性を取るのに苦労する場合があります。
(スレッドの処理時間は、システムが管理しますので、ユーザで処理時間を意識する必要は無かったと思います。)

ActiveBasicにはマルチスレッドをサポートする関数があるので、
メッセージを処理する関数から、DoEventsを必要とする処理を呼び出す場合は、マルチスレッド対応に変更する事をお勧めします。

コード: 全て選択


CreateThread(ByVal 0,0,AddressOf(SubName),0,0,VarPtr(ThreadID))	'マルチスレッド実行


Sub SubName
	DoEeventsの必要な処理
	ExitThread(0)
End Sub
各命令の詳細はヘルプをご覧下さい。
イグトランス
記事: 899
登録日時: 2005年5月31日(火) 17:59
お住まい: 東京都
連絡する:

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

そうは言ってもマルチスレッドよりシングルスレッドとDoEventsのほうが簡単です。
(ウィンドウプロシージャへの再入さえ気をつければ)
ちょっとしたツール程度には良いではないでしょうか。

もちろん本格的に作り込むのならマルチスレッドのほうがよっぽど便利なのは間違いありません。
返信する