自作timerを作成するには?


みよさん  2004-11-04 21:30:19  No: 86471

色々と調べた結果、
Timer関数は精度悪いみたいなので(≒18Hz程度?)
自作をしようと試みています。

が、QueryPerformanceCounterとQueryPerformanceFrequencyを
使うと精度が良いというところまでは調べたのですが、
この二つを使っても時間が算出できるだけで、
どのようにタイマー処理にもって行けばいいのか見当が付きません。
えーと、つまり、この二つを使って一定時間毎にある処理をしたいのです。
どのような記述がいいのでしょうか?
よろしく、お願いいたします。


ねろ  2004-11-05 02:32:54  No: 86472

マルチスレッド(フリースレッド)にしてLoopを回すとか。


友二  2004-11-05 05:48:10  No: 86473

timeSetEventとかは?


みよさん  2004-11-05 10:53:50  No: 86474

>ねろさん  >友二さん

申し訳ないのですが、もう少し詳しくお教え願えないでしょうか?


ねろ  2004-11-05 17:49:56  No: 86475

>申し訳ないのですが、もう少し詳しくお教え願えないでしょうか?
なんとなく頭が冴えなくて。(^^; 
    Declare Function QueryPerformanceCounter Lib "Kernel32" (ByRef X As Long) As Short
    Declare Function QueryPerformanceFrequency Lib "Kernel32" (ByRef X As Long) As Short
    Dim Ctr1, Ctr2, Freq, Interval, Count As Long
    Dim Timer1Thread As New System.Threading.Thread(AddressOf Timer1)    
    Private Sub Timer1()
        QueryPerformanceCounter(Ctr1)
        Do
            QueryPerformanceCounter(Ctr2)
            If (Ctr2 - Ctr1) / Freq >= Interval / 1000 Then
                QueryPerformanceCounter(Ctr1)
                '処理を書く
                Count += 1
                Me.Text = Count
            End If
        Loop
    End Sub
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Interval = 10 'タイマー  mSecで設定
        QueryPerformanceFrequency(Freq)
        Timer1Thread.Start()
    End Sub
もう少し何とかなりそうな気もするんだけど、とりあえず。
Threading.Threadに付いては自分で調べてね。


ねろ  2004-11-05 18:18:14  No: 86476

そうーだ!
If (Ctr2 - Ctr1) / Freq >= Interval / 1000 Then

If Math.Abs(Ctr2 - Ctr1) / Freq >= Interval / 1000 Then
にすれば「Do」の上の  QueryPerformanceCounter(Ctr1)は要らない。
Dim Ctr1, Ctr2はTimer1の中で宣言した方がいい。
少しすっきりしてきた。
マルチスレッドはVB5では出来ましたが、VB6では出来なくなりました。
VB.NETでは再び出来るようになりました、しかも簡単に。
Dim Timer1Thread As New System.Threading.Thread(AddressOf Timer1)    
の様に宣言すればタイマーコントロールの様に幾つでも使えます。
単にループを回すのとの違いは、テキストボックスなどを置いて入力
してみると解りますが、並列の処理が可能です。
ただし注意点は、VB6でコールバックを使われた方は経験があると思いますが、
プログラムのブレークが上手く利かない時があります。


みよさん  2004-11-05 19:14:20  No: 86477

>ねろさん
おー、ソースまでありがとうございます!!

マルチスレッドとかThreading.Threadについて勉強してみますね。
あ、でもVB6には無いのか…。
新たに.NET頑張るしかないかなぁ。

>並列の処理が可能です
というのは、つまり、例えば違うインターバルで2つのタイマー
を同時に動かせるゼィ!みたいな感じですかね?


ぴろあき  2004-11-05 20:41:53  No: 86478

友二さんの言うtimeSetEventはこんな感じ。
今後は、関数名まで教えてもらったら関数名で検索してみましょうね。
いくらでもサンプルが見つかるから。。。

<以下標準モジュール>
Public Declare Function timeBeginPeriod Lib "winmm.dll" (ByVal uPeriod As Long) As Long
Public Declare Function timeEndPeriod Lib "winmm.dll" (ByVal uPeriod As Long) As Long
Public Declare Function timeSetEvent Lib "winmm.dll" (ByVal uDelay As Long, ByVal uResolution As Long, ByVal lpFunction As Long, ByVal dwUser As Long, ByVal uFlags As Long) As Long
Public Declare Function timeKillEvent Lib "winmm.dll" (ByVal uID As Long) As Long
Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Public Declare Function timeGetTime Lib "winmm.dll" () As Long
Public TimerID As Long
Public Const TIME_PERIODIC = 1

Sub TimerProc(uTimerID As Long, uMsg As Long, dwUser As Long, dw1 As Long, dw2 As Long)
    Form1.Text1.Text = timeGetTime
    CallCount = CallCount + 1
End Sub
<以上標準モジュール>

<以下フォーム>
Private Sub Form_Load()
    Call timeBeginPeriod(20)
    TimerID = timeSetEvent(20, 3, AddressOf TimerProc, 1, TIME_PERIODIC)
End Sub

Private Sub Form_Unload(Cancel As Integer)
    Call timeKillEvent(TimerID)
    Call timeEndPeriod(20)
    Call Sleep(100)
End Sub
<以上フォーム>


ねろ  2004-11-05 20:59:52  No: 86479

QueryPerformanceCounterとQueryPerformanceFrequencyを使用してVB6でやると
「LARGE_INTEGER」の変換が入りますが、

Option Explicit
Private Type LARGE_INTEGER
    lowpart As Long     ' lower 32-bit value
    highpart As Long    ' higher 32-bit value
End Type
Dim Freq As LARGE_INTEGER
Dim Interval As Long, CountTime As Long
Private Declare Function QueryPerformanceCounter Lib "kernel32" _
(lpPerformanceCount As LARGE_INTEGER) As Long
Private Declare Function QueryPerformanceFrequency Lib "kernel32" _
(lpFrequency As LARGE_INTEGER) As Long

Private Sub Command1_Click()
    Interval = 10 'タイマー  mSecで設定
    QueryPerformanceFrequency Freq
    DoEvents
    Timer1
End Sub

Private Sub Timer1()
    Dim Ctr1 As LARGE_INTEGER, Ctr2 As LARGE_INTEGER
    Do
        QueryPerformanceCounter Ctr2
        If Abs(LItoDouble(Ctr2) - LItoDouble(Ctr1)) / LItoDouble(Freq) >= Interval / 1000 Then
            QueryPerformanceCounter Ctr1
            '処理を書く
            CountTime = CountTime + 1
            Me.Caption = CountTime
            DoEvents
        End If
    Loop
End Sub

Private Function LItoDouble(Val As LARGE_INTEGER) As Double
    Dim Low As Double, High As Double
    Low = Val.lowpart
    High = Val.highpart
    If Low < 0 Then Low = 4294967296# + Low + 1
    If High < 0 Then High = 4294967296# + High + 1
    LItoDouble = Low + High * 4294967296#
End Function

こんなかんじかな。


ねろ  2004-11-05 22:51:49  No: 86480

>友二さん
>ぴろあきさん 
ここに書きましたが
http://madia.world.coocan.jp/cgi-bin/VBBBS/wwwlng.cgi?print+200408/04080125.txt
こんな理由で
http://support.microsoft.com/kb/q198607/
multimedia timerを使うtimeSetEventは、VB6のネイティブコードコンパイルでは
落ちてしまい使えません。


ぴろあき  2004-11-05 23:03:39  No: 86481

>ねろさん
勉強になりました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加