PeekMessage与GetMessage 原型篇

BOOL PeekMessage( 
    LPMSG lpMsg,
    HWND hWnd,
    UINT wMsgFilterMin,
    UINT wMsgFilterMax,
    UINT wRemoveMsg
);

当消息队列中存在消息时, PeekMessage就返回TRUE, 最后一个参数可以为:

PM_REMOVE
PM_NOREMOVE

表示是否在接收到消息的时候从消息队列中删除它们。
与GetMessage的不同:
PeekMessage只要有消息的时候, 这相依返回TRUE, 即使消息是WM_QUIT, 没有消息的时候, 它不会等待,
而是立即返回,并返回FALSE。而GetMessage则是从消息队列中取出消息并删除它们, 当消息队列是空的时候,它会一直等待,直到队列中存在消息, 当收到WM_QUIT消息时, 它返回FALSE, 这是GetMessage惟一返回FALSE的情况, 其它都会返回TRUE, 代表一直等待或处理消息。
请记住:不管是PeekMessage还是GetMessage, 它们都不会删除WM_PAINT消息, 绝不会!!!从队列中删除WM_PAINT消息的情况是当显示区域重新变得有效的时候, 用ValidateRect和ValidateRgn或者BeginPaint和EndPaint来完成, 记住!!!!

哈哈, 不妨运行下面的程序, 你就会明白了:

#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("rect demo");
    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 = GetStockObject(WHITE_BRUSH);
    wndclass.lpszMenuName = NULL;
    wndclass.lpszClassName = szAppName;
    
    if(!RegisterClass(&wndclass)) {
        MessageBox(NULL, TEXT("Register failure..."),
            szAppName, MB_ICONERROR);
        return 0;
    }
    
    hwnd = CreateWindow(szAppName,
        szAppName,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        NULL,
        NULL,
        hInstance,
        NULL);
    
    ShowWindow(hwnd, iCmdShow);
    UpdateWindow(hwnd);
    
    while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
        if(msg.message == WM_QUIT)
            break;
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd,
                         UINT message,
                         WPARAM wParam,
                         LPARAM lParam) {
    static int cxClient, cyClient;
    HDC hdc;
    PAINTSTRUCT ps;
    TCHAR buffer[5];
    static int i;
    RECT rect;

    switch(message) {
    case WM_SIZE:
        cxClient = LOWORD(lParam);
        cyClient = HIWORD(lParam);
        i = 0;
        return 0;

    case WM_PAINT:
        hdc = GetDC(hwnd);
        GetClientRect(hwnd, &rect);
        DrawText(hdc, buffer, wsprintf(buffer, "%5d",i++), &rect, 
            DT_SINGLELINE | DT_CENTER | DT_VCENTER);
        ReleaseDC(hwnd, hdc);
        return 0;

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

Peekmessage和Getmessage都是向系统的消息队列中取得消息,不过性质不同。 
  若第一次向消息队列中取不到消息,则程序的主线程会被OS(操作系统)挂起;等到OS重新调度到该线程时,而且消息队列仍然是空的时,两者的性质不同:  
  若使用Getmessage(),则程序的主线程会仍被OS挂起。  
  若是用Peekmessage(),则程序会取得OS控制权,运行一段时间。此函数多用于处理系统的空闲时间。 
getmessage   and   peekmessage   are     both   get   the   message   from   send_message   queue.  
getmessage   supports     同步机制。PEEKMESSAGE   SUPPORTS   异步机制。 

从原因上而言:GetMessage函数从消息队列中得到消息后并在队列中删除该消息  
              PeekMessage函数从消息队列中得到消息后并不在队列中删除该消息  
从结果上而言:GetMessage等待一个消息(就像_getch),直到拿到消息才返回
              PeekMessage不是这样(就像_kbhit),查询消息队列,有就取,即使没有也立即返回。  
    
为了实现windows的多任务,要用getmessage,因为当getmessage发现自己的消息队列里没有消息时,就会把控制权交还给系统,这样就可以让避免资源的浪费。

GetMessage函数每次调用是肯定会取回一个消息的,当消息队列为空的时候此进程会被挂起直到消息队列中有消息可取为止。  
PeekMessage函数不管消息队列中是否有消息都会立即返回,返回是可以从返回的值里判断是否取到了消息,准确地说此函数是询问了一下消息队列,至于取回消息后是否从消息队列中删除此消息,由参数可以指定。  
  Windows3.1时很多应用程序的消息队列是由GetMessage函数构成的,而Win32以后大多数的应用程序的消息队列是由 PeekMessage函数构成的,vc和bcb好像都是这样的,基于Win32的抢先式多任务处理机制,采用PeekMessage函数构成的消息循环也不会对系统造成什么威胁。

1.PeekMessage


函数功能:该函数为一个消息检查线程消息队列,并将该消息(如果存在)放于指定的结构。
函数原型:BOOL PeekMessage(LPMSG IpMsg,HWND hWnd,UINT wMSGfilterMin,UINT wMsgFilterMax,UINT wRemoveMsg);
参数:
    lpMsg:接收消息信息的MSG结构指针。
    hWnd:其消息被检查的窗口的句柄。
    wMsgFilterMin:指定被检查的消息范围里的第一个消息。
    wMsgFilterMax:指定被检查的消息范围里的最后一个消息。
    wRemoveMsg:确定消息如何被处理。此参数可取下列值之一:
    PM_NOREMOVE:PeekMessage处理后,消息不从队列里除掉。
    PM_REMOVE:PeekMessage处理后,消息从队列里除掉。
    可将PM_NOYIELD随意组合到PM_NOREMOVE或PM_REMOVE。此标志使系统不释放等待调用程序空闲的线程。
    缺省地,处理所有类型的消息。若只处理某些消息,指定一个或多个下列值:
    PM_QS_INPUT:Windows NT5.0和Windows 98:处理鼠标和键盘消息。
    PM_QS_PAINT:Windows NT 5.0和Windows 98:处理画图消息。
    PM_QS_POSTMESSAGE:Windows NT 5.0和Windows 98:处理所有被寄送的消息,包括计时器和热键。
    PM_QS_SENDMESSAGE:Windows NT 5.0和Windows 98:处理所有发送消息。
    返回值:如果消息可得到,返回非零值;如果没有消息可得到,返回值是零。
    备注:和函数GetMessage不一样的是,函数PeekMesssge在返回前不等待消息被放到队列里。
    PeekMesssge只得到那些与参数hWnd标识的窗口相联系的消息或被lsChild确定为其子窗口相联系的消息,并且该消息要在由参数wMsgFiterMin和wMsgFiherMax确定的范围内。如果hWnd为NULL,则PeekMessage接收属于当前调用线程的窗口的消息(PeekMessage不接收属于其他线程的窗口的消息)。如果hWnd为C1,PeekMessage只返回hWnd值为NULL的消息,该消息由函数PostThreadMessage寄送。如果wMsgFilterMin和wMsgFilterMax都为零,GetMessage返回所有可得的消息(即,无范围过滤)。
    常数WM_KEYFIRST和WMKEYLAST可作为过滤值取得所有键盘消息;常数WM_MOUSEFIRST和WM_MOUSELAST可用来接收所有的鼠标消息。
    PeekMessage通常不从队列里清除WM_PAINT消息。该消息将保留在队列里直到处理完毕。但如果WM_PAINT消息有一个空更新区,PeekMessage将从队列里清除WM_PAINT消息。


2.PeekMessage和GetMessage的区别
a.GetMessage将等到有合适的消息时才返回,而PeekMessage只是撇一下消息队列.
b.GetMessage会将消息从队列中删除,而PeekMessage可以设置最后一个参数wRemoveMsg来决定是否将消息保留在队列中.

你可能感兴趣的:(PeekMessage与GetMessage 原型篇)