ページ 1 / 1
VBでいう DoEvents をAPI等々で実現したい。。。
Posted: 2005年11月01日(火) 08:17
by けんどん
はじめまして。けんどん と申します。
みなさんのお知恵を拝借したく、トピックを新規投稿いたしました。
内容としては、ABでVB言語の'DoEvents'関数はないことは認識していますが、
この関数をAPIにて実装できないものかと考えています。
私もそうですが、使えたら良いのに・・・という人が以外と多いのではないでしょうか?
一時期、Sleep関数などを代替案に考えたのですが、結果的にイマイチでした。
自分なりに色々と調べて努力してみましたが、見当が付かずに困っています。
よろしければ、ヒントだけでもいただけないでしょうか?
やはり実現不可でしょうか?
最終的に完成したモジュールをみなさんに公開したいと思っています。
Re: VBでいう DoEvents をAPI等々で実現したい。。。
Posted: 2005年11月01日(火) 14:36
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等々で実現したい。。。
Posted: 2005年11月01日(火) 14:40
by てふろん
こんにちは、再びてふろんです。
> If 0 = Result Or -1 == Result Then
ついつい、Cの癖が...
> If 0 = Result Or -1 = Result Then
と読み替えてください。
失礼致しました。
Re: VBでいう DoEvents をAPI等々で実現したい。。。
Posted: 2005年11月01日(火) 18:43
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を呼んでも良いと思いますが。
Re: VBでいう DoEvents をAPI等々で実現したい。。。
Posted: 2005年11月01日(火) 19:23
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が返るようです。
Posted: 2005年11月01日(火) 21:00
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
各命令の詳細はヘルプをご覧下さい。
Posted: 2005年11月01日(火) 23:40
by イグトランス
そうは言ってもマルチスレッドよりシングルスレッドとDoEventsのほうが簡単です。
(ウィンドウプロシージャへの再入さえ気をつければ)
ちょっとしたツール程度には良いではないでしょうか。
もちろん本格的に作り込むのならマルチスレッドのほうがよっぽど便利なのは間違いありません。