Thread: Experiencing TIMER problems, strange!..

  1. #1
    Registered User
    Join Date
    Apr 2008
    Posts
    610

    Experiencing TIMER problems, strange!..

    I have three timers

    Code:
    #define IDT_TIMER1 101
    #define IDT_TIMER2 102
    #define IDT_TIMER3 103
    
    
    	case WM_CREATE:
    		{	  
    
    			SetTimer(hwnd, IDT_TIMER1, 500, NULL); 
    			SetTimer(hwnd, IDT_TIMER2, 500, NULL); 
    			SetTimer(hwnd, IDT_TIMER3, 500, NULL); 
    
    
            .............
            .............
            .............
    
    
            case WM_TIMER: 
    		{
    			test++;
    			switch (wParam) 
    			{ 
    
    			case IDT_TIMER1: 
    				{
    					test1++;
    					InvalidateRect(hwnd, NULL, FALSE);
    					return 0; 
    				}
    
    
    			case IDT_TIMER2: 
    				{
    					test2++;
    					InvalidateRect(hwnd, NULL, FALSE);
    					return 0; 
    
    				}
    
    			case IDT_TIMER3: 
    				{
    					test3++;
    					InvalidateRect(hwnd, NULL, FALSE);
    					return 0; 
    				}
    			}
    		}
    Within WM_PAINT, i displayed test, test1, test2, & test3 respectively....
    Code:
    		sprintf(text, "%d %d %d %d", test, test1, test2, test3);
    		TextOut(hdc, 10, 10, text, (int)_tcslen(text));
    To my surprise, the output is as follows

    Code:
    0 0 0 0
    3 1 1 1
    6 2 2 2
    9 3 3 3
    12 4 4 4
    ......
    ......
    // etc.
    This means all three timers are only executed for every third call of WM_TIMER

  2. #2
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Yes, since each timer generates it's own WM_TIMER event, I would expect exactly that. What did you expect to see?

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  3. #3
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    Makes sense to me. test is going to be incremented for each timer call. This means that test is going to be equal to the sum of all timer calls, ie. test1 + test2 + test3

  4. #4
    Registered User
    Join Date
    Apr 2008
    Posts
    610
    Quote Originally Posted by matsp View Post
    Yes, since each timer generates it's own WM_TIMER event, I would expect exactly that. What did you expect to see?

    --
    Mats
    Test1, Test2, Test3 must be incremented for every repaint, not after 3 times.... Besides, if case IDT_TIMER(n) is only called after every three calls of WM_TIMER, what is updating/repainting the window between 0-3 counts? Notice i only call InvalidateRect() inside these times. I'm really confused... I'm doing some calculations within these timers and that should happen every IDT_TIMER execution...

  5. #5
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    You're not paying attention to your own code. When Timer 1 is called, both test and test1 will be incremented. Then when Timer 2 is called, both test and test2 will be incremented. Then when Timer 3 is called, both test and test3 will be incremented.

    Final score:

    Code:
    test = 3
    test1 = 1
    test2 = 1
    test3 = 1
    Get it now?

  6. #6
    Registered User
    Join Date
    Apr 2008
    Posts
    610
    Quote Originally Posted by MacGyver View Post
    Makes sense to me. test is going to be incremented for each timer call. This means that test is going to be equal to the sum of all timer calls, ie. test1 + test2 + test3
    No! I disagree, test is not sum of the three... All this means to me is, test increments three times before test(1-3) get increment. But then the window output is not showing those increments (1-2) of test, since InvalidateRect() is only done within TIMERS... i'm i talking bull

  7. #7
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    test is incremented no matter what timer is called. Read the code you posted.

  8. #8
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    But you (probably) started all your timers on the same system tick (1ms or 10ms ticks in most systems), so you will have all three timers queued at the same time. The first one does an InvalidateRect() which will queue a WM_PAINT message - but this will not be the next thing in the queue, as you already have two more WM_TIMER events in the queue. It's an orderly queue here, and there's no special priority for messages of a certain kind. So the WM_PAINT will not be performed until after you have done all the timers.

    If you change your timer setup this way:
    Code:
    			SetTimer(hwnd, IDT_TIMER1, 500, NULL); 
                            Sleep(20);
    			SetTimer(hwnd, IDT_TIMER2, 500, NULL); 
                            Sleep(20);
    			SetTimer(hwnd, IDT_TIMER3, 500, NULL);
    then you will see the different timers at different times.

    You could also change your 500 values to for example 400, 500, 1000 [without the Sleep calls], and you would see that every other IDT_TIMER2 you also get a IDT_TIMER3. And occassionally, you would also match the IDT_TIMER1 with the IDT_TIMER2 and/or IDT_TIMER3 (every 5 IDT_TIMER1 will be issued at the same time as the IDT_TIMER3).

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  9. #9
    Registered User
    Join Date
    Apr 2008
    Posts
    610
    Quote Originally Posted by MacGyver View Post
    You're not paying attention to your own code. When Timer 1 is called, both test and test1 will be incremented. Then when Timer 2 is called, both test and test2 will be incremented. Then when Timer 3 is called, both test and test3 will be incremented.
    Make sense, infect suggests something i was not aware of.... That: TIMER1, TIMER2, TIMER3, are never executed in the same cycle or same repaint.... But then, why do they show increments on the screen at the same repaint... Let me confess here, i thought i knew how timers work...

    Quote Originally Posted by MacGyver View Post
    test is incremented no matter what timer is called. Read the code you posted.
    Yes i know that... Refer to my comment above
    Last edited by csonx_p; 06-25-2008 at 04:07 AM.

  10. #10
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quite clearly, wparam will never hold more than one specific value at any given time. So when it holds IDT_TIMER2 that is a distinct different timer event than IDT_TIMER1 and IDT_TIMER3. But since all of your timers are started at the same time, and have the same timing, they will be coming into your application in a burst.

    InvalidateRect() will send a WM_PAINT message to your application, which gets received by your application when it's got to that point in the queue - which would be when it's finished the other two WM_TIMER events. There may possibly also be 3 WM_PAINT message (although I don't know if that is the case or the OS optimizes a WM_PAINT message that covers the same area as previous one).

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  11. #11
    Registered User
    Join Date
    Apr 2008
    Posts
    610
    Quote Originally Posted by matsp View Post
    But you (probably) started all your timers on the same system tick (1ms or 10ms ticks in most systems), so you will have all three timers queued at the same time. The first one does an InvalidateRect() which will queue a WM_PAINT message - but this will not be the next thing in the queue, as you already have two more WM_TIMER events in the queue. It's an orderly queue here, and there's no special priority for messages of a certain kind. So the WM_PAINT will not be performed until after you have done all the timers.

    If you change your timer setup this way:
    Code:
    			SetTimer(hwnd, IDT_TIMER1, 500, NULL); 
                            Sleep(20);
    			SetTimer(hwnd, IDT_TIMER2, 500, NULL); 
                            Sleep(20);
    			SetTimer(hwnd, IDT_TIMER3, 500, NULL);
    then you will see the different timers at different times.

    You could also change your 500 values to for example 400, 500, 1000 [without the Sleep calls], and you would see that every other IDT_TIMER2 you also get a IDT_TIMER3. And occassionally, you would also match the IDT_TIMER1 with the IDT_TIMER2 and/or IDT_TIMER3 (every 5 IDT_TIMER1 will be issued at the same time as the IDT_TIMER3).

    --
    Mats
    Ok, maybe i should clarify my intentions...

    Code:
    case WM_TIMER: 
    		{
    			switch (wParam) 
    			{ 
    
    			case IDT_TIMER1: 
    				{
    					if(!reflected)
    					{		
    						rdrCntr++;
    						xradOffset+=5;
    						yradOffset+=5;
    					}
    					InvalidateRect(hwnd, NULL, FALSE);
    					return 0; 
    				}
    
    			case IDT_TIMER2: 
    				{
    					if(reflected)
    					{
    						rdrBncCntr++;
    						xBncOffset+=5;
    						yBncOffset+=5;
    					}
    					InvalidateRect(hwnd, NULL, FALSE);
    					return 0; 
    
    				}
    
    			case IDT_TIMER3: 
    				{
    					hBitmapRect.xyPos.x+=5;
    					InvalidateRect(hwnd, NULL, FALSE);
    					return 0; 
    				}
    			}
    		}
    In the code above i have three timers, and i have three objects to be animated on the screen using these timers. Within each timer, all i do is to increment a variable to change an object position. All these animations can happen at different speeds but the change should happen at every single repaint or call to InvalidateRect()... What am i doing wrong here?

  12. #12
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    So what is (or isn't) happening, and how is that different from what you expected?

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  13. #13
    Registered User
    Join Date
    Apr 2008
    Posts
    610
    Quote Originally Posted by matsp View Post
    So what is (or isn't) happening, and how is that different from what you expected?

    --
    Mats
    Well, it seems WM_PAINT executes regardless of the InvalidateRect() calls... Meaning, the variables changed within the TIMER's case statements are used in WM_PAINT without having been change at least every three times... This obviously produces wrong results....

  14. #14
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    InvalidateRect isn't the only time Windows sends a WM_PAINT message.
    InvalidateRect simply tells Windows to invalidate a part of a region and send a new message as necessary.
    So don't count on it.
    WM_PAINT is sent everytime a window needs repainting.
    This includes if you hide it behind a window and remove that window, or if you move the window outside screen, among them.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  15. #15
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by csonx_p View Post
    Well, it seems WM_PAINT executes regardless of the InvalidateRect() calls... Meaning, the variables changed within the TIMER's case statements are used in WM_PAINT without having been change at least every three times... This obviously produces wrong results....
    I'm not sure I understand what you mean. I think you mean that after the InvalidateRect() you want the system to actually draw the screen before it processes the next timer. The only way you can achieve that is that you offset the calls to SetTimer() so that there is sufficient amount of time between the WM_TIMER to post the WM_PAINT event before the next WM_TIMER is posted.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Timer in Win32
    By nicolas in forum Windows Programming
    Replies: 5
    Last Post: 07-04-2004, 07:21 AM
  2. Computer Problems
    By fac7 in forum Tech Board
    Replies: 13
    Last Post: 03-23-2004, 01:22 AM
  3. contest problems on my site
    By DavidP in forum Contests Board
    Replies: 4
    Last Post: 01-10-2004, 09:19 PM
  4. strange problems w/phoenix
    By dP munky in forum A Brief History of Cprogramming.com
    Replies: 8
    Last Post: 04-06-2003, 06:41 PM
  5. bcc32 compiling error (really strange!!)
    By jester in forum C++ Programming
    Replies: 14
    Last Post: 01-26-2002, 04:00 PM