Click here to Skip to main content
Email Password   helpLost your password?

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.

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.

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 :-

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.

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.

// 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.

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.

// 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

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
Generalreal time timers
Milos-Soucek
7:55 16 Oct '06  
hallo all,

a "small" problem with timers - if You are using one, You cannot be sure, that You dont miss a rise of event.
FE: 50ms timer is running, event handler is logging time of its calling, and when You move a form, an hole in calls occurs.

How can one make timer more real time ?
I need an application, which will send a message through a serial port every 50ms, and there cannot be a delay between messages.

Does anyone know - how ??

Thank You.

OssO

GeneralWinService
octamxHot
14:54 21 Jun '05  
i´am using this code in Windows Service, but never execute OnTickTimer.

SetTimer return number >0 but never ticks the timer
GeneralSomething I don't understand....
sagmam
9:02 27 Dec '04  
It says in the article that the Win32 timers worked but other "timers" didn't. What timers DIDN'T work? Are we talking about System.Threading.Timer objects, or something else?

/=/=/=/= Sagmam =\=\=\=\
GeneralBe careful with GetLastError
Richard Poole
2:31 15 Sep '04  
Apparently, while invoking a native DLL function, the CLR may make other opearting system calls when marshalling parameters etc. which may invalidate the value returned by GetLastError.

According to Adam Nathan's CLR blog you should define your DLL import as (note the addition of SetLastError = true): -

[DllImport("user32", SetLastError = true)]
private static extern int KillTimer(IntPtr hwnd, int nIDEvent);
And use the managed method Marshal.GetLastWin32Error() to obtain the actual error code of the invoked DLL function.

Cheers,
Richard.
GeneralHELP! convert string to Intptr using ASP.Net ERROR
gin_blossoms
23:19 5 Jan '04  
I'm trying to convert string to Intptr using ASP.Net, this is the code...

string v = this.ID;

public static explicit operator IntPtr(int v);


But this error occurs...

User-defined conversion must convert to or from the enclosing type


What can I do? Help!!

Generalwhat does "Form.Handle" do?
gin_blossoms
0:53 30 Dec '03  
Can anyone tell me what does 'this.handle' do??
and what is the equivalent of ".handle" function if developing a web application?
it's only available in a windows application form..why is this so?
pls help!! asap!!

tnx in advanceConfused

GeneralRe: what does "Form.Handle" do?
jan larsen
1:44 30 Dec '03  
gin_blossoms wrote: Can anyone tell me what does 'this.handle' do??
Actually it is not doing anything Smile
'handle' is the chosen name for an id that is used by the Win32 API, it could be, like in the article, the id of a form (In Win32: window).
A Win32 handle is a 32 bit, at the moment anyway, integer. The API uses them for keeping track of resources like timers and windows.

If you are easily confused, then don't read this: A handle can be a simple integer that indexes into an array of pointers to memory chunks, or it could be a pointer to the memory chunk itself. Win32 programming is all about manipulating handles, because they are a layer of abstraction that makes it possible for Microsoft to change the underlying objects without breaking existing code.

gin_blossoms wrote: and what is the equivalent of ".handle" function if developing a web application?
As far as i know, nothing. Allthough you could say that because a handle is just an identifier for an object, then the equivalent could be the reference to a WebForm instance on the heap, but I guess I'm pushing you off the track telling you this Smile

"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

GeneralRe: what does "Form.Handle" do?
gin_blossoms
8:05 30 Dec '03  
".handle" is an IntPtr right?
does web appliactions support that?
what should i use in place of this when calling a function that asks also of a var in IntPtr vartype?
doesn't web applications/form have handles??

i also thought of another way, is it possible to launch a windows application just by clicking a button or link from a web form? it might wor..but i dnt know how.
i tried form1.show(), form1.activeform.show()...nothing happened!

can u help me? thanks a lot for replying!
GeneralRe: what does "Form.Handle" do?
jan larsen
21:54 4 Jan '04  
I haven't really dug very deep into the web framework in .NET, so I cant dismiss the probability of a workaround. But there aren't really any window instance required to run a web app, and my, admittedly very brief, search for any members looking vaguely like a window handle didn't turn successfull.
So based on my findings, or rather the lack of those, I would say that web pages doesn't have any access, directly or otherwise, to a window handle.

It shouldn't be impossible to launch a window from a webapp, but I doubt it would be possible using the .NET framework itself. I mean, to create windows using the Win32 API, you have to have an instance handle for the application, and I don't believe I have seen any reference to such a member in the classes I looked in.

"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

GeneralRe: what does "Form.Handle" do?
jan larsen
21:58 5 Jan '04  
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


Last Updated 2 Dec 2003 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010