GetMessage/PeekMessage

I know how (GetMessage(&msg, NULL, 0, 0)) works,


But how does it differ from (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))

And whats the best one to use?
GetMessage will check the message queue for message, if there aren't any messages in the queue it will block. Blocking, in this case, would mean that GetMessage will wait for a valid message to pop up into the message queue.

PeekMessage will check the message queue and return the first message it finds. If there are no messages in the queue it will then return nothing.

GetMessage = wait for message
PeekMessage = return the first message, or return nothing if there are no messages

Now you can't use PeekMessage like you would GetMessage, here's a code example for both:

1
2
3
4
5
6
//GetMessage loop example.
while (GetMessage (&uMsg, NULL, 0, 0) > 0)
{
     TranslateMessage (&uMsg);
     DispatchMessage (&uMsg);
}


1
2
3
4
5
6
7
8
9
//PeekMessage loop example
while (WM_QUIT != uMsg.message)
{
     while (PeekMessage (&uMsg, NULL, 0, 0, PM_REMOVE) > 0) //Or use an if statement
     {
          TranslateMessage (&uMsg);
          DispatchMessage (&uMsg);
     }
}
Hmm im still a little confused, could you tell me which one is better than the other (im guessing they both have their own advantages in different situations).
Well the PeekMessage loop is generally used in video games, or applications that need to do things without the user sending a message, such as animation that isn't used when the user does something. (Example: When sprites walk around every five seconds, such as in RPGs)

1
2
3
4
5
6
7
8
9
10
//PeekMessage loop example
while (WM_QUIT != uMsg.message)
{
     while (PeekMessage (&uMsg, NULL, 0, 0, PM_REMOVE) > 0) //Or use an if statement
     {
          TranslateMessage (&uMsg);
          DispatchMessage (&uMsg);
     }
     //Here is were all the "animation that isn't used when the user does something" code will go.
}


GetMessage is generally used in applications that only do things when the user does something, such as click a button, type in an edit control, ect.
Last edited on
I thought it was something to do with that :D

So getmessage freezes the application until it receives a message

And peekmessage does not freeze the application and lets it process background stuff :)

Two more questions:

1. What is this doing because i have not come across WM_QUIT and .messageWM_QUIT != uMsg.message

2. peekmessage has one more parameter than getmessage which is "PM_REMOVE", what information is stored in this?
1.
WM_QUIT is the message that is sent to the message queue when we are exiting the application. This loop:

1
2
3
4
MSG uMsg;
while (WM_QUIT != uMsg.message)
{
}


Will keep us in the program until we exit the application. If we just have this:

1
2
3
4
5
while (PeekMessage (&uMsg, NULL, 0, 0, PM_REMOVE) > 0)
{
     TranslateMessage (&uMsg);
     DispatchMessage (&uMsg);
}


Then our application will close almost instantly because PeekMessage will return 0 when there's no messages, and there isn't always messages. So we add the outer while loop to keep us in the application.

"message" is a member of the MSG structure, it holds the current message.

2.
After GetMessage reads the message it will remove that message from the message queue. PeekMessage has another parameter to allow us to use messages another way (I'm not sure what ways, google will tell you) I'm guessing. PM_REMOVE will just tell PeekMessage to remove any messages it finds from the message queue, just like GetMessage does.
Last edited on
Thanks :)
You're welcome.
Well the PeekMessage loop is generally used in video games, or applications that need to do things without the user sending a message


Well, I would do it with GetMessage anyways. I just install a timer, my objects do not have to do anything unless the timer tells them it's time to perform some logic.
:)
In my program i have:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))

{
 
if (msg.message == WM_QUIT)
     {
      break;
     }

      TranslateMessage(&msg);
      DispatchMessage(&msg);
      
}


If this breaks, the function which will be called next is " GameEnd();"

If the program has already received WM_QUIT will the GameEnd() actually get called? Because when WM_QUIT is received isnt the program immediately closed?
Last edited on
Shouldn't this be:
1
2
3
4
5
6
7
8
9
10
11
12
13
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))

{
 
if (msg.message == WM_QUIT)
     {
      break;
     }

      TranslateMessage(&msg);
      DispatchMessage(&msg);
      
}
instead ?

And you can skip the second if, because PeekMessage returns 0 anyways when the message is WM_QUIT. And no, WM_QUIT doesn't automatically quit your program, it tells you that you should quit the program.
hanst99, that loop wouldn't work, here's some code of a program that uses that type of loop and it instantly closes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <windows.h>

/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/*  Make the class name into a global variable  */
char szClassName[ ] = "CodeBlocksWindowsApp";

int WINAPI WinMain (HINSTANCE hThisInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpszArgument,
                     int nCmdShow)
{
    HWND hwnd;               /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default colour as the background of the window */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;

    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
           0,                   /* Extended possibilites for variation */
           szClassName,         /* Classname */
           "Code::Blocks Template Windows App",       /* Title Text */
           WS_OVERLAPPEDWINDOW, /* default window */
           CW_USEDEFAULT,       /* Windows decides the position */
           CW_USEDEFAULT,       /* where the window ends up on the screen */
           544,                 /* The programs width */
           375,                 /* and height in pixels */
           HWND_DESKTOP,        /* The window is a child-window to desktop */
           NULL,                /* No menu */
           hThisInstance,       /* Program Instance handler */
           NULL                 /* No Window Creation data */
           );

    /* Make the window visible on the screen */
    ShowWindow (hwnd, nCmdShow);

    while (PeekMessage (&messages, NULL, 0, 0, PM_REMOVE))
    {
    	if (WM_QUIT == messages.message) break;
    	TranslateMessage (&messages);
    	DispatchMessage (&messages);
    }

    /* The program return-value is 0 - The value that PostQuitMessage() gave */
    return messages.wParam;
}


/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}
Unless you're using a different compiler, other than GNU GCC, that uses Win32 slightly different?

If the program has already received WM_QUIT will the GameEnd() actually get called? Because when WM_QUIT is received isnt the program immediately closed?


Sorry if I made it seem like WM_QUIT = program exits instantly. I meant to say is more like what hanst99 said:
And no, WM_QUIT doesn't automatically quit your program, it tells you that you should quit the program.
Last edited on
The loop is not working because I meant to write GetMessage instead of PeekMessage. If you do that it works just fine, and you can skip one if. And if a compiler behaved differently with the same API it would be buggy.
msdn wrote:
If the function retrieves a message other than WM_QUIT, the return value is nonzero.

If the function retrieves the WM_QUIT message, the return value is zero.

If there is an error, the return value is -1. For example, the function fails if hWnd is an invalid window handle or lpMsg is an invalid pointer. To get extended error information, call GetLastError.
Last edited on
closed account (z05DSL3A)
GetMessage() is used for the message loop
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    MSG msg;
    BOOL bRet;
    //...
    while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
    { 
        if (bRet == -1)
        {
            // handle the error and possibly exit
        }
        else
        {
            TranslateMessage(&msg); 
            DispatchMessage(&msg); 
        }
    } 
 
    // Return the exit code to the system. 
 
    return msg.wParam; 


PeekMessage() is use to examine a message queue during a lengthy operation.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
while (!fDone) // lengthy operation
{ 
    // doing long loopy stuff
    //
    while (PeekMessage(&msg, hwnd,  0, 0, PM_REMOVE)) 
    { 
        switch(msg.message) 
        {  
            case WM_KEYDOWN: 
                {
                    //
                    // Check for ESC key 
                    // clean up and quit.
                    fDone = TRUE; 
                }
        } 
    } 
} 
hanst99 wrote:
The loop is not working because I meant to write GetMessage instead of PeekMessage. If you do that it works just fine, and you can skip one if. And if a compiler behaved differently with the same API it would be buggy.


Ah, that explains it. =]
Last edited on
For this:

1
2
3
4
5
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))

{
}
else


The function after this else statement would be carried out if PeekMessage returned a FALSE value wouldnt it. Does PeekMessage return a FALSE value if no messages are available?
TpOreily wrote:
For this:

1
2
3
4
5
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))

{
}
else




The function after this else statement would be carried out if PeekMessage returned a FALSE value wouldnt it. Does PeekMessage return a FALSE value if no messages are available?


The else statement can only be used after an if or else if statement, not a while loop. If you wanted to execute something after that while loop you would just put it directed after it, so just deleted the if statement.

And PeekMessage will return 0 if there's no messages in the queue so you will need to have an outer while loop that runs while WM_QUIT is not equal to uMsg.message.
Topic archived. No new replies allowed.