色々と調べた結果、
Timer関数は精度悪いみたいなので(≒18Hz程度?)
自作をしようと試みています。
が、QueryPerformanceCounterとQueryPerformanceFrequencyを
使うと精度が良いというところまでは調べたのですが、
この二つを使っても時間が算出できるだけで、
どのようにタイマー処理にもって行けばいいのか見当が付きません。
えーと、つまり、この二つを使って一定時間毎にある処理をしたいのです。
どのような記述がいいのでしょうか?
よろしく、お願いいたします。
マルチスレッド(フリースレッド)にしてLoopを回すとか。
timeSetEventとかは?
>ねろさん >友二さん
申し訳ないのですが、もう少し詳しくお教え願えないでしょうか?
>申し訳ないのですが、もう少し詳しくお教え願えないでしょうか?
なんとなく頭が冴えなくて。(^^;
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に付いては自分で調べてね。
そうーだ!
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でコールバックを使われた方は経験があると思いますが、
プログラムのブレークが上手く利かない時があります。
>ねろさん
おー、ソースまでありがとうございます!!
マルチスレッドとかThreading.Threadについて勉強してみますね。
あ、でもVB6には無いのか…。
新たに.NET頑張るしかないかなぁ。
>並列の処理が可能です
というのは、つまり、例えば違うインターバルで2つのタイマー
を同時に動かせるゼィ!みたいな感じですかね?
友二さんの言う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
<以上フォーム>
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
こんなかんじかな。
>友二さん
>ぴろあきさん
ここに書きましたが
http://madia.world.coocan.jp/cgi-bin/VBBBS/wwwlng.cgi?print+200408/04080125.txt
こんな理由で
http://support.microsoft.com/kb/q198607/
multimedia timerを使うtimeSetEventは、VB6のネイティブコードコンパイルでは
落ちてしまい使えません。
>ねろさん
勉強になりました。
ツイート | ![]() |