Thread: What is causing WM_PAINT to be sent?

  1. #1
    Registered User
    Join Date
    Jun 2008
    Location
    Somewhere in Europe
    Posts
    99

    What is causing WM_PAINT to be sent?

    Hello,

    On my machine, running the following causes "Hello, Windows 98!" to be painted immediately, even with the call of UpdateWindow() in WinMain commented out. According to Charles Petzold in "Programming Windows", the first WM_PAINT message would normally be sent as a result of this call of UpdateWindow().

    My question is thus: if it is not UpdateWindow() that is causing WM_PAINT to be sent, what is causing it be sent? I presume Windows is at some point deciding that the client area is invalid and thus sending the WM_PAINT message. But when does that happen? During or immediately after execution of ShowWindow(), or at some later stage?

    Code:
    #include <windows.h>
    
    LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
    
    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                        PSTR szCmdLine, int iCmdShow)
    {
         static TCHAR szAppName[] = TEXT ("HelloWin") ;
         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))
         {
              return 0 ;
         }
    
          hwnd = CreateWindow (szAppName,
                      TEXT ("Application"),
                      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)
    {
         HDC         hdc ;
         PAINTSTRUCT ps ;
         RECT        rect ;
    
         switch (message)
         {
         case WM_PAINT:
              hdc = BeginPaint (hwnd, &ps) ;
    
              GetClientRect (hwnd, &rect) ;
    
              DrawText (hdc, TEXT ("Hello, Windows 98!"), -1, &rect,
                        DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
    
              EndPaint (hwnd, &ps) ;
              return 0 ;
    
         }
         return DefWindowProc (hwnd, message, wParam, lParam) ;
    }

  2. #2
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    It would be crazy if you had to deliberately call UpdateWindow() to get a paint event. The whole point of event based programming is that you do not trigger the events, the OS does it for you. If it worked that way, why have events at all?

    You get a WM_PAINT because you've created a window and placed it on the screen. Now that's it's on the screen, it needs to be painted. You get a WM_PAINT.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  3. #3
    'Allo, 'Allo, Allo
    Join Date
    Apr 2008
    Posts
    639
    In addition, WM_PAINT, WM_TIMER, and a few others are low-priority messages that aren't necessarily processed as they are generated. UpdateWindow is called to force the processing of a WM_PAINT message. It's usage in the above program is to ensure you see the text, otherwise there could potentially be a lag between the window appearing and the text being drawn.

  4. #4
    Registered User
    Join Date
    Jun 2008
    Location
    Somewhere in Europe
    Posts
    99
    So the UpdateWindow() in the example is redundant?

    And is it thus the ShowWindow() call that causes the WM_PAINT? If I understand Petzold correctly, he implies that ShowWindow() doesn't cause a WM_PAINT but just erases the client area, which is why it is followed by UpdateWindow() (the program is from his book).

    Sorry if these questions sound stupid but I am just starting out with Windows programming.

  5. #5
    Registered User
    Join Date
    Jun 2008
    Location
    Somewhere in Europe
    Posts
    99
    adeyblue, I didn't see your reply before posting mine. Anyhow, I would still be very interested to hear exactly what event it is that causes the WM_PAINT to be sent if there is no UpdateWindow() call. Is it the just the processing of ShowWindow()?

  6. #6
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    Quote Originally Posted by adeyblue View Post
    In addition, WM_PAINT, WM_TIMER, and a few others are low-priority messages that aren't necessarily processed as they are generated.
    WM_PAINT msgs are preprocessed in the OS queue (concatinated into one invalid area in the OS queue, IIRC in response to a Peek/GetMessage call).

    WM_TIMER msgs can be ignored if higher priority msgs are in the queue (8 msgs by default).

    Quote Originally Posted by adeyblue View Post
    UpdateWindow is called to force the processing of a WM_PAINT message.
    Not exactly.

    UpdateWindow() sends the WM_PAINT msg directly to the callback, bypassing the OS queue, for a faster response.

    However if there is no invalid area (ie set by a call to InvalidateRect()) the paint msg will be ignored.

    Quote Originally Posted by adeyblue View Post
    It's usage in the above program is to ensure you see the text, otherwise there could potentially be a lag between the window appearing and the text being drawn.
    Only if the PC is under extreme load or very slow. In either case the UpdateWindow() call will not improve this performance.
    Calling UpdateWindow() in this case is redundant. [Comment it out and see].

    When a window is created, but before it is shown, a WM_CREATE is sent.

    If the window was created with the WM_VISIBLE style (or ShowWindow() with a non zero flag is called) a series of non client and cleint paints are sent.

    Resizing also causes a paint msg (if the ShowWindow() contains a size change ie SW_SHOWMAXIMISED).

    Generating another paint, without invalidating any of the client area, will result in the paint msg being ignored.
    "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

  7. #7
    Registered User
    Join Date
    Jun 2008
    Location
    Somewhere in Europe
    Posts
    99
    If the window was created with the WM_VISIBLE style (or ShowWindow() with a non zero flag is called) a series of non client and cleint paints are sent.
    So if you set WS_VISIBLE you make both the ShowWindow() and UpdateWindow() calls redundant.

  8. #8
    Malum in se abachler's Avatar
    Join Date
    Apr 2007
    Posts
    3,195
    Usually you InvalidateRect() on the client area to get a WM_PAINT sent.

    Code:
    			InvalidateRect(hwnd , &rect , FALSE);
    			RedrawWindow(hwnd , NULL , NULL , RDW_INVALIDATE);
    that is the code I use to trigger a WM_PAINT in my current project. It's actually in my WM_TIMER case, as I want to redraw the client area 30 times per second. The WM_PAINT is typically waiting in the message queue by time wndproc returns. I have had a few cases where I had to use a critical section because the WM_PAINT would get processed before RedrawWindow() finished, that was back on NT 4.0 with a dual Pentium II system though, I've never had an issue on XP.
    Last edited by abachler; 10-08-2009 at 06:16 AM.

  9. #9
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    Quote Originally Posted by DL1 View Post
    So if you set WS_VISIBLE you make both the ShowWindow() and UpdateWindow() calls redundant.
    Yes.

    Unless you want to change the size with something like

    Code:
    CreateWindow(.....
    ShowWindow(hWnd, SW_MAXIMIZE);
    "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

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Pre-processor macros causing segfaults
    By nempo in forum C++ Programming
    Replies: 6
    Last Post: 02-10-2009, 02:35 AM
  2. strtok is causing segmentation fault
    By yougene in forum C Programming
    Replies: 11
    Last Post: 03-08-2008, 10:32 AM
  3. strlen causing my program to freeze
    By Beowolf in forum C Programming
    Replies: 2
    Last Post: 09-11-2007, 04:09 PM
  4. WM_CAPTION causing CreateWindowEx() to fail.
    By Necrofear in forum Windows Programming
    Replies: 8
    Last Post: 04-06-2007, 08:23 AM
  5. Class member using a global variable, causing problems.
    By RealityFusion in forum C++ Programming
    Replies: 1
    Last Post: 09-11-2005, 11:27 PM