peekmessage和wm_paint的关系msdn说:The PeekMessage function does not remove WM_PAINT messages from the queue. WM_PAINT messages remain in the queue until they are processed. 
windows程序设计说,while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) ;
        
这行叙述从消息队列中删除WM_PAINT之外的所有消息。如果队列中有一个WM_PAINT消息,程序就会永远地陷在while循环中。)作者是否理解错了,为什么死循环? 如果是死循环。作者又提供了这样的一个例子:
  while (TRUE)
         
    {
         
            if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
         
            {
         
                   if (msg.message == WM_QUIT)
         
                     break ;
         
                   TranslateMessage (&msg) ;
         
                   DispatchMessage (&msg) ;
         
        }
         
            else
         
                   DrawRectangle (hwnd) ; //这里进行绘图操作
         
    }
         
    return msg.wParam ;}作者就不担心死循环???????? 他一方面说,会产生死循环,一方面她还用peekmessage我是在昏了

解决方案 »

  1.   

    1.peekmessage 不等待,立即返回
    2.PM_REMOVE 对 wm_paint 不起作用,返回 0.
      

  2.   

    收到WM_QUIT不就退出循环了嘛   这样设计只是为了在无任何消息的时候进行 DrawRectangle (hwnd) ;操作 否则什么消息都没有程序是挂起状态
      

  3.   


    我觉得作者的意图:wm_paint由系统默认处理第二:利用 空闲时候绘图。当发现消息对垒中有wm_paint的时候,由 系统默认处理
      

  4.   


    它所说的死循环,猜测是 认为的去处理wm_paint,但是处理的时候,并没有用beginpaint等函数去掉wm_paint!
      

  5.   

    本帖最后由 VisualEleven 于 2012-11-28 13:12:00 编辑
      

  6.   


    windows程序设计randrect.c 这个例子书上是 164页5.6.2节
      

  7.   

    我意思是这段代码在那个函数里? 如果是消息处理函数里 没有对WM_PAINT进行处理 那就不会重绘除非DrawRectangle有重绘动作
      

  8.   

    我觉得它所说的死循环是当PeekMessage返回0的时候,消息并没有被处理也没有被移除,然后不断循环
    while (TRUE)
    {
      if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
      {
        if (msg.message == WM_QUIT)
          break;
        if (msg.message == WM_PAINT)
           OutputDebugString("WM_PAINT: PeekMessage return TRUE");
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }
      else if (msg.message == WM_PAINT)
         OutputDebugString("WM_PAINT: PeekMessage return FALSE");
    }可以用这段代码测试一下,有时会出现不断输出"WM_PAINT: PeekMessage return FALSE"的情况
    而且也发现这段代码是比较占CPU的
      

  9.   


     while (TRUE)
            
        {
            
                if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
            
                {
            
                       if (msg.message == WM_QUIT)
            
                         break ;
            
                       TranslateMessage (&msg) ;
            
                       DispatchMessage (&msg) ;
            
            }
            
                else
            
                       DrawRectangle (hwnd) ;
            
        }
            
        return msg.wParam ;
            
    }
    void DrawRectangle (HWND hwnd)
            
    {
            
        HBRUSHhBrush ;
            
        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) ;
            
    }
      

  10.   


    什么叫重绘动作? 可否科普一下。我理解的重绘: 重新绘制,什么时候重新绘制, wm_paint等消息产生的时候绘制。何时产生,如:拖动,放大缩小,被遮盖!这些才是需要重绘。

    其他不算,比如:在wm_close里 填充背景。 这是刻意的, 仅仅是调用画图的代码,不能叫重绘
      

  11.   


    息并没有被处理也没有被移除,然后不断循环++
    作者提供的源码,其实是处理了,peekmessage并没有去除掉。但是由于defwindowproc 使无效区域成为有效,所以wm_paint就消失了
      

  12.   


    case WM_PAINT:
        return 0;怎么又不见了? 你的while (TRUE) 是在WndProc还是哪个里面的?
      

  13.   


    /*----------------------------------------------------------------------
            
      RANDRECT.C --   Displays Random Rectangles
            
                    (c) Charles Petzold, 1998
            
    -----------------------------------------------------------------------*/
    #include "stdafx.h"  
    #include <windows.h>
            
    #include <stdlib.h>// for the rand function
            LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
            
    void DrawRectangle (HWND) ;
            int cxClient, cyClient ;
            
    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
            
                       PSTR szCmdLine, int iCmdShow)
            
    {
            
        static TCHAR szAppName[] = TEXT ("RandRect") ;
            
        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 ("This program requires Windows NT!"),
            
                                        szAppName, MB_ICONERROR) ;
            
                return 0 ;
            
        }
            
       
            
        hwnd = CreateWindow (szAppName, TEXT ("Random Rectangles"),
            
                               WS_OVERLAPPEDWINDOW,
            
                               CW_USEDEFAULT, CW_USEDEFAULT,
            
                               CW_USEDEFAULT, CW_USEDEFAULT,
            
                               NULL, NULL, hInstance, NULL) ;
            
       
            
        ShowWindow (hwnd, iCmdShow) ;
            
        UpdateWindow (hwnd) ;
            
       
            
        while (TRUE)
            
        {
            
                if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
            
                {
            
                       if (msg.message == WM_QUIT)
            
                         break ;
            
                       TranslateMessage (&msg) ;
            
                       DispatchMessage (&msg) ;
            
            }
            
                else
            
                       DrawRectangle (hwnd) ;
            
        }
            
        return msg.wParam ;
            
    }
            LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
            
    {
            
        switch (iMsg)
            
        {
            
        case   WM_SIZE:
            
                cxClient = LOWORD (lParam) ;
            
                cyClient = HIWORD (lParam) ;
            
                return 0 ;
            
            
            
        case   WM_DESTROY:
            
                PostQuitMessage (0) ;
            
                return 0 ; //case wm_paitn是我添加的,我加的目的是,故意return 0; 这样的话,wm_paint就无法把无效区域变成有效区域,导致其一直在队列中,看
    是否会堵塞?? case WM_PAINT: return 0;
            
        }
            
        return DefWindowProc (hwnd, iMsg, 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) ;
            
    }
    注意wm_paint!!!,是我加的, 作者的源码是没有的
      

  14.   

    作者的愿意是 没有任何消息的话就DrawRectangle 你加了return 0; 那么永远没机会处理WM_PAINT消息 那界面不就不会再刷新了吗
      

  15.   


    MSDN说的null update region是指无效区域吧,那么PeekMessage就会移除WM_PAINT,并返回TRUE了;如果一直是无效区域,那么PeekMessage总是返回TRUE另外可能是PeekMessage不等待的缘故,CPU占用率还是比较高的
      

  16.   


    贴完整的:The PeekMessage function normally does not remove WM_PAINT messages from the queue. WM_PAINT messages remain in the queue until they are processed. However, if a WM_PAINT message has a NULL update region, PeekMessage does remove it from the queue.作者对wm_paitn的理解,早就有人指出有错误了,一个国外的网站上。根本不会死循环。msdn是这样解释的:The PeekMessage function normally does not remove WM_PAINT messages from the queue. WM_PAINT messages remain in the queue until they are processed. However, if a WM_PAINT message has a NULL update region, PeekMessage does remove it from the queue.一般不会删除,直到 XX来处理。 XX可以使程序员,也可以是os. 如何处理,没规定。那么指定了pm_remove,会不会一定删除,应该是不会的。一旦删除,是进入不了case wm_paint的.那么wm_paint是如何产生的,是有非null update region才产生, 否则不产生。这里msdn是有不少疑问。总之:不存在所谓死循环, windows程序设计这本书wm_paitn 的理解不对, 早就有人指出了
      

  17.   


    我好像说错了,wm_paint如果处理不正确(无效区域一直存在,无论getmessage,peekmesssage都不会去掉一直存在的该帖子讨论的是与peekmessage的关系, windows程序一书多虑了自己可以设置断点,