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

