Below is a high precision timer that uses the QueryPerformance API's. I tried to structure it just like a normal timer would be so that it makes it easier to use.
My might you want to use this timer over normal timer? Well, in my case I needed a game loop that will be consistently executed. With the normal timer, any intervals around 15 - 20 milliseconds are no longer accurate and for a game loop you want an interval of 16.6 milliseconds(60 FPS).
Here is the code:
I'd like to thank Jacob Roman for introducing me to the QueryPerformance API's.Code:Option Strict On Option Explicit On <System.ComponentModel.DefaultEvent("Tick")> _ Public Class PrecisionTimer Inherits System.ComponentModel.Component Private frequency As Long Private waitThread As Threading.Thread #Region "Api" Private Declare Function QueryPerformanceCounter Lib "kernel32" (ByRef lpPerformanceCount As Long) As Integer Private Declare Function QueryPerformanceFrequency Lib "kernel32" (ByRef lpFrequency As Long) As Integer #End Region #Region "Events" Public Event Tick(ByVal sender As Object, ByVal e As EventArgs) #End Region #Region "Methods" Private Sub CheckCompatibility() Dim test As Long If Not CBool(QueryPerformanceCounter(test)) Then Throw New Exception("High-resolution counter is not supported for this computer.") End If End Sub Public Sub Start() Me.Enabled = True waitThread = New Threading.Thread(AddressOf Wait) waitThread.IsBackground = True waitThread.Start() End Sub Public Sub [Stop]() Me.Enabled = False End Sub Private Sub Wait() Dim counter1, counter2 As Long QueryPerformanceCounter(counter1) If Me.LowerCpuUsage Then Do QueryPerformanceCounter(counter2) Threading.Thread.Sleep(2) Loop Until (counter2 - counter1) / (frequency / 1000) >= Me.Interval Else Do QueryPerformanceCounter(counter2) Loop Until (counter2 - counter1) / (frequency / 1000) >= Me.Interval End If Console.WriteLine((counter2 - counter1) / (frequency / 1000)) RaiseEvent Tick(Me, EventArgs.Empty) If Me.AutoReset Then Me.Enabled = False ElseIf Me.Enabled Then waitThread = New Threading.Thread(AddressOf Wait) waitThread.Start() End If End Sub #End Region #Region "New Constructor" Sub New() Call CheckCompatibility() QueryPerformanceFrequency(frequency) Me.Interval = 100 End Sub Sub New(ByVal interval As Double) Call CheckCompatibility() QueryPerformanceFrequency(frequency) Me.Interval = interval End Sub #End Region #Region "Properties" Public Property AutoReset As Boolean Private pEnabled As Boolean Public Property Enabled() As Boolean Get Return pEnabled End Get Set(ByVal value As Boolean) If pEnabled <> value Then pEnabled = value If pEnabled Then RaiseEvent Tick(Me, EventArgs.Empty) End If End Set End Property Public Property Interval As Double Public Property LowerCpuUsage As Boolean #End Region End Class




Reply With Quote