C Board  

Go Back   C Board > Platform Specific Boards > Windows Programming

Reply
 
LinkBack Thread Tools Display Modes
Old 09-04-2008, 02:20 AM   #1
Registered User
 
Join Date: Dec 2007
Location: France
Posts: 430
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 Code::Blocks,MingW with Windows.
Ducky is offline   Reply With Quote
Old 09-04-2008, 02:30 AM   #2
Kernel hacker
 
Join Date: Jul 2007
Location: Farncombe, Surrey, England
Posts: 15,686
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.
matsp is offline   Reply With Quote
Old 09-04-2008, 06:36 PM   #3
Registered User
 
Join Date: Mar 2005
Location: Mountaintop, Pa
Posts: 1,059
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 ;
BobS0327 is offline   Reply With Quote
Old 09-04-2008, 09:06 PM   #4
train spotter
 
Join Date: Aug 2001
Location: near a computer
Posts: 3,448
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
novacain is offline   Reply With Quote
Old 09-05-2008, 02:10 AM   #5
Kernel hacker
 
Join Date: Jul 2007
Location: Farncombe, Surrey, England
Posts: 15,686
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.
matsp is offline   Reply With Quote
Old 09-06-2008, 12:48 AM   #6
Registered User
 
Join Date: Dec 2007
Location: France
Posts: 430
Thanks for the help everybody!

Quote:
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
__________________
Using Code::Blocks,MingW with Windows.

Last edited by Ducky; 09-06-2008 at 01:28 AM.
Ducky is offline   Reply With Quote
Old 09-06-2008, 03:07 AM   #7
Kernel hacker
 
Join Date: Jul 2007
Location: Farncombe, Surrey, England
Posts: 15,686
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.
matsp is offline   Reply With Quote
Old 09-06-2008, 05:12 AM   #8
Registered User
 
Join Date: Dec 2007
Location: France
Posts: 430
Makes sense, thanks Matsp!

I will try to understand the code.
__________________
Using Code::Blocks,MingW with Windows.
Ducky is offline   Reply With Quote
Old 09-06-2008, 06:07 AM   #9
Registered User
 
Join Date: Dec 2007
Location: France
Posts: 430
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ügen Sie hier den Zeichnungscode hinzu...
		EndPaint(hWnd, &ps);
		break;
http://www.turboupload.com/files/get...ource-code.zip
__________________
Using Code::Blocks,MingW with Windows.

Last edited by Ducky; 09-06-2008 at 06:12 AM.
Ducky is offline   Reply With Quote
Old 09-06-2008, 12:35 PM   #10
Registered User
 
Join Date: Mar 2005
Location: Mountaintop, Pa
Posts: 1,059
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.
BobS0327 is offline   Reply With Quote
Old 09-06-2008, 01:23 PM   #11
Registered User
 
Join Date: Dec 2007
Location: France
Posts: 430
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 Code::Blocks,MingW with Windows.
Ducky is offline   Reply With Quote
Old 09-06-2008, 03:12 PM   #12
Algorithm Dissector
 
iMalc's Avatar
 
Join Date: Dec 2005
Location: New Zealand
Posts: 2,727
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
iMalc is offline   Reply With Quote
Old 09-18-2008, 07:21 AM   #13
Registered User
 
Join Date: Dec 2007
Location: France
Posts: 430
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 Code::Blocks,MingW with Windows.
Ducky is offline   Reply With Quote
Old 09-19-2008, 06:31 PM   #14
Registered User
 
Join Date: Mar 2005
Location: Mountaintop, Pa
Posts: 1,059
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.
BobS0327 is offline   Reply With Quote
Old 09-20-2008, 01:48 AM   #15
Registered User
 
Join Date: Dec 2007
Location: France
Posts: 430
Thank you Bob, highly appreciated.

I put myself to it...
__________________
Using Code::Blocks,MingW with Windows.
Ducky is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Forum Jump


All times are GMT -6. The time now is 09:13 AM.


Powered by vBulletin® Version 3.8.1
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.3.2

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22