Click here to Skip to main content
15,879,613 members
Articles / Programming Languages / C#
Article

Win 32 API Timers for .NET

Rate me:
Please Sign up or sign in to vote.
3.29/5 (6 votes)
1 Dec 20035 min read 100.1K   2.2K   24   10
This article describes how to work with timers provided by win32 API

Introduction

Not long time ago, I was programming an application for Windows that every certain time had to execute a task; in the development of the project everything went with normality but arrived the day to prove the program in the definitive machines where it had to remain working, and we observed that once in a while timers stopped working. We did thousand verifications always reaching the same result, sometimes, timers provided by the Framework don't tick, no events fired. It was then when we began to look for a solution to replace these timers and the solution that seemed better to me was the one to replace them by timers of the API of Windows. We looked on the Internet in case somebody had had the same idea that I had, without success, and therefore put hands to the work.

Background

The Win32 API has some system calls to make it possible, the first is SetTimer, used to init a timer and the second is KillTimer, used to kill or stop a timer. Here is a description of these system calls.

SetTimer

The SetTimer function creates a timer with the specified time-out value.

UINT_PTR SetTimer( 
  HWND hWnd, // handle to window 
  UINT_PTR nIDEvent, // timer identifier 
  UINT uElapse, // time-out value 
  TIMERPROC lpTimerFunc // timer procedure 
); 

Parameters

hWnd

[in] Handle to the window to be associated with the timer. This window must be owned by the calling thread. If this parameter is NULL, no window is associated with the timer and the nIDEvent parameter is ignored.

nIDEvent

[in] Specifies a nonzero timer identifier. If the hWnd parameter is NULL, this parameter is ignored.

If the hWnd parameter is not NULL and the window specified by hWnd already has a timer with the value nIDEvent, then the existing timer is replaced by the new timer. When SetTimer replaces a timer, the timer is reset. Therefore, a message will be sent after the current time-out value elapses, but the previously set time-out value is ignored.

uElapse

[in] Specifies the time-out value, in milliseconds.

lpTimerFunc

[in] Pointer to the function to be notified when the time-out value elapses. For more information about the function, see TimerProc.

If lpTimerFunc is NULL, the system posts a WM_TIMER message to the application queue. The hwnd member of the message's MSG structure contains the value of the hWnd parameter.

Return Values

If the function succeeds and the hWnd parameter is NULL, the return value is an integer identifying the new timer. An application can pass this value to the KillTimer function to destroy the timer.

If the function succeeds and the hWnd parameter is not NULL, then the return value is a nonzero integer. An application can pass the value of the nIDTimer parameter to the KillTimer function to destroy the timer.

If the function fails to create a timer, the return value is zero. To get extended error information, call GetLastError.

Remarks

An application can process WM_TIMER messages by including a WM_TIMER case statement in the window procedure or by specifying a TimerProc callback function when creating the timer. When you specify a TimerProc callback function, the default window procedure calls the callback function when it processes WM_TIMER. Therefore, you need to dispatch messages in the calling thread, even when you use TimerProc instead of processing WM_TIMER.

The wParam parameter of the WM_TIMER message contains the value of the nIDEvent parameter.

The timer identifier, nIDEvent, is specific to the associated windows. Another window can have its own timer which has the same identifier as a timer owned by another window. The timers are distinct.

KillTimer

The KillTimer function destroys the specified timer.

C#
BOOL KillTimer(
  HWND hWnd, // handle to window
  UINT_PTR uIDEvent // timer identifier
);

Parameters

hWnd

[in] Handle to the window associated with the specified timer. This value must be the same as the hWnd value passed to the SetTimer function that created the timer.

uIDEvent

[in] Specifies the timer to be destroyed. If the window handle passed to SetTimer is valid, this parameter must be the same as the uIDEvent value passed to SetTimer. If the application calls SetTimer with hWnd set to NULL, this parameter must be the timer identifier returned by SetTimer.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The KillTimer function does not remove WM_TIMER messages already posted to the message queue.

TimerProc

The TimerProc function is an application-defined callback function that processes WM_TIMER messages. The TIMERPROC type defines a pointer to this callback function. TimerProc is a placeholder for the application-defined function name.

C#
VOID CALLBACK TimerProc(
  HWND hwnd, // handle to window
  UINT uMsg, // WM_TIMER message
  UINT_PTR idEvent, // timer identifier
  DWORD dwTime // current system time
);

Parameters

hwnd

[in] Handle to the window associated with the timer.

uMsg

[in] Specifies the WM_TIMER message.

idEventnt

[in] Specifies the timer's identifier.

dwTime

[in] Specifies the number of milliseconds that have elapsed since the system was started. This is the value returned by the GetTickCount function.

Return Values

This function does not return a value.

Using the code

Common system calls :-

C#
public const int WM_TIMER = 0x113;
// Constant to identify System.Windows.Forms.Message 
// in WndProc is a timer Message
// Init Timer
[DllImport("user32")]
private static extern int SetTimer(IntPtr hwnd, int nIDEvent, 
    int uElapse, TimerProc CB); 
// Kill Timer
[DllImport("user32")]
private static extern int KillTimer(IntPtr hwnd, int nIDEvent);

CallBack Timers

We needed an appropriate function callback to the call of API and a procedure to which to do callback, also we must keep the identifier from timer for being able to kill it in the future.

C#
private delegate void TimerProc(IntPtr hWnd, uint nMsg, 
    int nIDEvent, int dwTime); 
private TimerProc Cb = new TimerProc(this.OnTickTimer); 
private int ID_CB_Timer = 0; // Callback timer identifier

// Start Callback 
// Save timer identifier 
this.ID_CB_Timer = SetTimer(IntPtr.Zero, 0, 
    (int)this.numericUpDown2.Value, Cb); 

// Send to form info about timer 
this.statusBar1.Text = "CalBack " + this.ID_CB_Timer.ToString(); 
this.label7.Text = this.ID_CB_Timer.ToString(); 
// Stop timer 
Int rs = KillTimer(IntPtr.Zero,this.ID_CB_Timer); 

If we obtain a Non-zero value when stop timer, an error occurred, we can obtain info about error calling GetLastError() system call.

When the tick occurs, she only add '1' to a counter of ticks and displays the number of ticks in form.

C#
// On Tick Timer 
// Received Ticks via callback 
private void OnTickTimer(IntPtr hWnd, uint nMsg, int nIDEvent, 
  int dwTime) 
{ 
  // Count ticks 
  this.Cnt_CB_Timer+=1; 
  this.label5.Text = this.Cnt_CB_Timer.ToString(); 
}

TimerProc Timers

We don't need a callback, ticks are received on TimerProc Form's function.

C#
private int ID_WN_Timer; // Timer's identifier
// Start Timer WndProc 
// Save the timer id in ID_WN_Timer 
this.ID_WN_Timer = SetTimer(this.Handle,5000,
  (int)this.numericUpDown2.Value,null); 
// Send the info about the new timer to the form 
this.statusBar1.Text = "WndProc " + this.ID_WN_Timer.ToString(); 
this.label8.Text = this.ID_WN_Timer.ToString();
// Stop WndProc 
this.Cnt_WN_Timer = 0; 
this.label6.Text = "0"; 
int rs = 0; 
rs = KillTimer(this.Handle,this.ID_WN_Timer); 
if (rs == 0) 
{ 
  // Error killing timer 
  this.statusBar1.Text = "Error Kill Timer WndProc " + 
    rs.ToString() + " Timer id [" + this.ID_WN_Timer.ToString() + ']'; 
  // Here we could search with GetLastError what is the 
  // cause the timer does not stop ticking 
} 
else 
{ 
this.statusBar1.Text = "Kill Timer WndProc " + rs.ToString(); 
} 

If we obtain a Non-zero value when stop timer, an error occurred, we can obtain info about error calling GetLastError() system call.

When the tick occurs, she only add '1' to a counter of ticks and displays the number of ticks in form.

C#
// On Tick Timer
protected override void WndProc( ref System.Windows.Forms.Message m ) 
{ 
  try 
  { 
  #region Switch system messages 
    switch (m.Msg) 
    { 
      case (int)WM_TIMER: 
      { 
        this.Cnt_WN_Timer+=1; 
        this.label6.Text = this.Cnt_WN_Timer.ToString(); 
        break; 
      } 
    default: 
      {     
        base.WndProc(ref m); 
        break;   
      } 
    }   
  #endregion 
  }   
  catch (Exception ex) 
  { 
    this.statusBar1.Text = ex.Message; 
  } 
} 

Conclusion

Ok, that’s all, I expect on this, my first article submitted to Codeproject it will help to someone. Thanks to all for the dozens of articles that I’ve read here. I'll never edit again any HTML page with Visual Studio - there is intelligent life on it!

Points of Interest

Refer Microsoft MSDN for related topics.

History

  • 1.0 Initial Release

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Spain Spain
I'm a System engineer which is programming in C# actually.

Comments and Discussions

 
Generalreal time timers Pin
Milos-Soucek16-Oct-06 6:55
Milos-Soucek16-Oct-06 6:55 
GeneralWinService Pin
octamxHot21-Jun-05 13:54
octamxHot21-Jun-05 13:54 
GeneralSomething I don't understand.... Pin
sagmam27-Dec-04 8:02
sagmam27-Dec-04 8:02 
GeneralBe careful with GetLastError Pin
Richard Poole15-Sep-04 1:31
Richard Poole15-Sep-04 1:31 
GeneralHELP! convert string to Intptr using ASP.Net ERROR Pin
gin_blossoms5-Jan-04 22:19
gin_blossoms5-Jan-04 22:19 
Questionwhat does "Form.Handle" do? Pin
gin_blossoms29-Dec-03 23:53
gin_blossoms29-Dec-03 23:53 
AnswerRe: what does "Form.Handle" do? Pin
jan larsen30-Dec-03 0:44
jan larsen30-Dec-03 0:44 
GeneralRe: what does "Form.Handle" do? Pin
gin_blossoms30-Dec-03 7:05
gin_blossoms30-Dec-03 7:05 
GeneralRe: what does "Form.Handle" do? Pin
jan larsen4-Jan-04 20:54
jan larsen4-Jan-04 20:54 
GeneralRe: what does "Form.Handle" do? Pin
jan larsen5-Jan-04 20:58
jan larsen5-Jan-04 20:58 
By the way, if you want to use the timer service from a non window application you can set the handle to NULL (0) and provide the callback function as described in parameter 4.

"After all it's just text at the end of the day. - Colin Davies

"For example, when a VB programmer comes to my house, they may say 'does your pool need cleaning, sir ?' " - Christian Graus

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.