Thread: Wm_timer

  1. #1
    Registered User
    Join Date
    Dec 2007
    Posts
    930

    Wm_timer

    I would like to call DrawPolygon (hwnd, hdc) in ID_TIMER2 but i dont know how.
    I get uninitialized local variable 'hdc' error.

    Code:
    #include <windows.h>
    #include <winuser.h>
    
    #define ID_TIMER1    1
    #define ID_TIMER2    2
    
    
    LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
    
    void DrawRectangle (HWND) ;
    void DrawEllipse (HWND,HDC) ;
    void DrawPolygon (HWND hwnd,HDC hdc) ;
    int cxClient, cyClient ;
    
    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                        PSTR szCmdLine, int iCmdShow)
    {
         static TCHAR szAppName[] = TEXT ("Screensaver") ;
         HWND         hwnd ;
         MSG          msg ;
         WNDCLASS     wndclass ;
         
         wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
         wndclass.lpfnWndProc   = WndProc ;
         wndclass.cbClsExtra    = 0 ;
         wndclass.cbWndExtra    = 0 ;
         wndclass.hInstance     = hInstance ;
         wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
         wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
         wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
         wndclass.lpszMenuName  = NULL ;
         wndclass.lpszClassName = szAppName ;
         
         if (!RegisterClass (&wndclass))
         {
              MessageBox (NULL, TEXT ("Program requires Windows NT!"), 
                          szAppName, MB_ICONERROR) ;
              return 0 ;
         }
         
         hwnd = CreateWindow (szAppName, TEXT ("Beeper1 Timer Demo"),
                              WS_OVERLAPPEDWINDOW,
                              CW_USEDEFAULT, CW_USEDEFAULT,
                              CW_USEDEFAULT, CW_USEDEFAULT,
                              NULL, NULL, hInstance, NULL) ;
              
         ShowWindow (hwnd, iCmdShow) ;
         UpdateWindow (hwnd) ;
              
         while (GetMessage (&msg, NULL, 0, 0))
         {
              TranslateMessage (&msg) ;
              DispatchMessage (&msg) ;
         }
         return msg.wParam ;
    }
    
    LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
         HBRUSH      hBrush ;
         static BOOL fFlipFlop = FALSE ;
         HDC         hdc ;
         PAINTSTRUCT ps ;
         RECT        rc ;
         
         
         switch (message)
         {
         case WM_SIZE:
              cxClient = LOWORD (lParam) ;
              cyClient = HIWORD (lParam) ;
              return 0 ;
         
         case WM_CREATE:
              SetTimer (hwnd, ID_TIMER1, 2000, NULL) ;
              SetTimer (hwnd, ID_TIMER2, 1000, NULL) ;
              return 0 ;
    
         case WM_TIMER :
              switch (wParam)
              {
              case ID_TIMER1:
                      fFlipFlop = !fFlipFlop ;
                        InvalidateRect (hwnd, NULL, FALSE) ;
                       break ;
              case ID_TIMER2:  
                      DrawPolygon (hwnd, hdc);
                      break ;
               }
               return 0 ;
    
         case WM_PAINT :
              hdc = BeginPaint (hwnd, &ps) ;
              
              GetClientRect (hwnd, &rc) ;
              hBrush = CreateSolidBrush (RGB(0,0,0)) ;
              FillRect (hdc, &rc, hBrush) ;
              DrawPolygon (hwnd, hdc);
              fFlipFlop ? DrawRectangle (hwnd) : DrawEllipse (hwnd,hdc) ;
            
              EndPaint (hwnd, &ps) ;
              DeleteObject (hBrush) ;
              return 0 ;
              
         case WM_DESTROY :
              KillTimer (hwnd, 1) ;
              KillTimer (hwnd, 2) ;
              PostQuitMessage (0) ;
              return 0 ;
         }
         return DefWindowProc (hwnd, message, wParam, lParam) ;
    }
    
    void DrawRectangle (HWND hwnd)
    {
         HBRUSH hBrush ;
         HDC    hdc ;
         RECT   rect ;
         
         if (cxClient == 0 || cyClient == 0)
              return ;
         
         SetRect (&rect, rand () % cxClient, rand () % cyClient, rand () % cxClient, rand () % cyClient) ;
         
         hBrush = CreateSolidBrush ( RGB (rand () % 256, rand () % 256, rand () % 256)) ;
         hdc = GetDC (hwnd) ;
         
         FillRect (hdc, &rect, hBrush) ;
         ReleaseDC (hwnd, hdc) ;
         DeleteObject (hBrush) ;
    }     
    
    void DrawEllipse (HWND hwnd,HDC hdc) 
    {
         HBRUSH hbr = CreateSolidBrush (RGB (rand () % 256, rand () % 256, rand () % 256)) ;
         HBRUSH hOld = (HBRUSH) SelectObject (hdc,hbr);
         Ellipse (hdc, rand () % cxClient, rand () % cyClient, rand () % cxClient, rand () % cyClient) ;
         SelectObject (hdc,hOld) ;
         DeleteObject (hbr) ;
    }
    void DrawPolygon (HWND hwnd, HDC hdc)
    {
         static    POINT points[7] = {{20, 50},{180, 50},{180, 20},{230, 70},
                                  {180, 120},{180, 90},{20, 90}};
        
         HBRUSH hbr = CreateSolidBrush (RGB (rand () % 256, rand () % 256, rand () % 256)) ;
         HBRUSH hOld = (HBRUSH) SelectObject (hdc,hbr);
         
         Polygon(hdc, points, 7);
         
         SelectObject (hdc,hOld) ;
         DeleteObject (hbr) ;
    }
    Using Windows 10 with Code Blocks and MingW.

  2. #2
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    You probably don't want to draw the polygon in the WM_TIMER code itself, but in the WM_PAINT that comes from a InvalidateRect call. Alternatively, you could use a double buffering technique to draw the data off-screen, and then just use the VM_PAINT to copy your off-screen data onto the screen.

    The compiler is indeed correct, hdc is in this case not initilalized - you declare it at the top of the function, and the only time it is assigned is in WM_PAINT, when you do BeginPaint. Remember that local variables "disappear" when you leave the function, and are created anew when the function is called next time. WndProc is called when a message is received by your application - it is not "there all the time".

    --
    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
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    Declare hdc as static.

    Code:
    LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
         HBRUSH      hBrush ;
         static BOOL fFlipFlop = FALSE ;
         static HDC         hdc ;
         PAINTSTRUCT ps ;
         RECT        rc ;

  4. #4
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    Things to consider....

    Timer events fire every time period, not once. So you have one timer every second and another firing every 2 secs. (or very similar times)

    EndPaint() cleans up the HDC from BeginPaint. It may not be valid to draw to it later. Look at GetDC(NULL) and ReleaseDC.

    You are not clearing the background (FillRect() or similar)

    I would set the drawing flags in the timer and call for a paint (which would choose the correct shape to draw).
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  5. #5
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by BobS0327 View Post
    Declare hdc as static.

    Code:
    LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
         HBRUSH      hBrush ;
         static BOOL fFlipFlop = FALSE ;
         static HDC         hdc ;
         PAINTSTRUCT ps ;
         RECT        rc ;
    But if you call EndPaint(hdc), the hdc will still not be valid next time around. Nor will it be valid BEFORE the first WM_PAINT [assuming no other changes to the previously posted code].

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

  6. #6
    Registered User
    Join Date
    Dec 2007
    Posts
    930
    Thanks for the help everybody!

    I would set the drawing flags in the timer and call for a paint (which would choose the correct shape to draw).
    I dont know how to do it so i'm trying to look into the double buffering technique instead.

    I found this tutorial already http://www.codeproject.com/KB/cpp/DoubleBuffering.aspx

    PS How could this be possible that the program compiles with 0 error 0 warning but won't execute.
    VC++ 2008
    Last edited by Ducky; 09-06-2008 at 01:28 AM.
    Using Windows 10 with Code Blocks and MingW.

  7. #7
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by Ducky View Post
    PS How could this be possible that the program compiles with 0 error 0 warning but won't execute.
    VC++ 2008
    Well, there are plenty of examples of code that compiles well but doesn't do what you wanted - unfortunately, the compiler can't know what you want the code to achieve - if you really want to write to random addresses in memory, divide by zero or some such, then that is your choice. The compiler will give errors for things that it KNOWS is impossible to achieve, but that is not a complete list of all that can go wrong.

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

  8. #8
    Registered User
    Join Date
    Dec 2007
    Posts
    930
    Makes sense, thanks Matsp!

    I will try to understand the code.
    Using Windows 10 with Code Blocks and MingW.

  9. #9
    Registered User
    Join Date
    Dec 2007
    Posts
    930
    Well what i see in this program is that he calls functions in WM_TIMER and not in WM_PAINT. And you told me above not to call drawing function in WM_TIMER.

    He also put a TODO in WM_PAINT, so maybe i should put some code there?

    Code:
    case WM_TIMER:
    		{
    		  //controls growth of the ellipse
    		  if (growth > 50 || growth < 0)
    			  addition *= -1;
    		  growth += addition;
    
    		 if(double_buffer == true)
    			Draw_With_Buffering();
    		 else
                            Draw_Without_Buffering(hWnd);
    		}
            break;
    
    	case WM_PAINT:
    		hdc = BeginPaint(hWnd, &ps);
    		// TODO: F&#252;gen Sie hier den Zeichnungscode hinzu...
    		EndPaint(hWnd, &ps);
    		break;
    http://www.turboupload.com/files/get...ource-code.zip
    Last edited by Ducky; 09-06-2008 at 06:12 AM.
    Using Windows 10 with Code Blocks and MingW.

  10. #10
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    Quote Originally Posted by Ducky View Post
    Thanks for the help everybody!


    I dont know how to do it so i'm trying to look into the double buffering technique instead.

    I found this tutorial already http://www.codeproject.com/KB/cpp/DoubleBuffering.aspx

    PS How could this be possible that the program compiles with 0 error 0 warning but won't execute.
    VC++ 2008
    The project is missing a resource file which is causing the above issue. I recreated the resource file based upon my interpretation of the author's code. The author's code along with the resource file is at this link. The download has a comp.bat batch file that I used to compile the project with a MS compiler.

  11. #11
    Registered User
    Join Date
    Dec 2007
    Posts
    930
    Thanks a million Bob, im very grateful for this.

    I managed to compile it with VC++ 6.0 but not with VC++ 2008 free version.
    It must have some limitations resource files i guess.

    Now i can play around with the program. Its much easier to learn that way for me.
    Using Windows 10 with Code Blocks and MingW.

  12. #12
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    The thing to know is that you have to do things in a slightly roundabout way. When you get your WM_TIMER messaege you don't just paint. Instead you ask the system to tell you to paint, via InvalidateRect for example.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  13. #13
    Registered User
    Join Date
    Dec 2007
    Posts
    930
    I would like to make this http://www.turboupload.com/files/get...dbuffering.zip (same as above) double buffering program to be displayed in full screen.

    I guess i should call GetClientRect (hWnd, &rect) ;.
    But the program is first being loaded in the buffer you dont have a client area.

    So i thought about to put GetClientRect (hWnd, &rect) ; in the
    void Bitmap_Operations::Copy_to_Screen(int which) function.

    But its not working either.
    Using Windows 10 with Code Blocks and MingW.

  14. #14
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    Quote Originally Posted by Ducky View Post
    I would like to make this http://www.turboupload.com/files/get...dbuffering.zip (same as above) double buffering program to be displayed in full screen.

    I guess i should call GetClientRect (hWnd, &rect) ;.
    But the program is first being loaded in the buffer you dont have a client area.

    So i thought about to put GetClientRect (hWnd, &rect) ; in the
    void Bitmap_Operations::Copy_to_Screen(int which) function.

    But its not working either.
    Unfortunately, this would require a update to the author's code because he calls Initialize_Buffers in WM_CREATE which stores the windows RECT coordinates. So, even if you maximized the client window, the double buffering would only take place in the original window RECT coordinates. Thus, when you resized or maximized the client window, you'll also have to somehow reinitialize the RECT coordinates in dc_rect to the new client window RECT coordinates. A starting point would be to add another function to the class called ReInitialize_Buffers which would update dc_rect to the new client RECT coordinates.

    EDIT: I've updated the code to handle resizing, mazimizing of the window. I don't want to do all your work for you. So, you'll have to figure out how to adjust the buffering to keep the ellipse totally in the client window. The new link
    Last edited by BobS0327; 09-19-2008 at 07:22 PM.

  15. #15
    Registered User
    Join Date
    Dec 2007
    Posts
    930
    Thank you Bob, highly appreciated.

    I put myself to it...
    Using Windows 10 with Code Blocks and MingW.

Popular pages Recent additions subscribe to a feed