这篇文章主要了解单独的函数PeekMessage(),并谈一下与类似的GetMessage()函数有什么不同。GetMessage()也不是不好,只是没办法再游戏中取得持续卓越的效果所以考虑PeekMessage()函数代替前者。
The Structure of the GetMessage() Loop
上一篇文章中,使用GetMessage()函数创建了一个简单的窗口应用,同时结合另外两个函数创建处理系统发送消息的循环。但还有一些并未提及。
下面的关系图显示了事件循环的工作原理 ︰
![The Structure of a GetMessage() Loop](https://i-blog.csdnimg.cn/blog_migrate/8e64102aba8737dc034d75da90f9411a.gif)
The Structure of a GetMessage() Loop
循环结构
当创建窗口的时候,开始从GetMessage()函数中进入事件循环。Getmessage () 即处于等待消息状态,并在收到一个消息的时候将其发送到下一个函数中。系统程序的逻辑就是等待指令然后执行。然而这种逻辑并不适用于我们,当等待执行语句开始执行的时候,每秒需要创建30到60完全渲染的3D图像并且要毫无延迟的将这些图像传递到屏幕。如此我们遇到一个相当有趣的麻烦,因为系统无法以30/s的速度发送这些消息。
A New Function, PeekMessage()
解决这个问题的方式就是把 GetMessage()语句换为PeekMessage()。这个函数虽然执行同样的操作但是却有很重要的区别:它不需要等待就可以进行发送。PeekMessage()函数只看消息队列,检测消息队列是否有正在等待的任何消息,如果存在消息及发送到下一个函数,如果不存在则程序处理其他内容。
![The Structure of a PeekMessage() Loop](https://i-blog.csdnimg.cn/blog_migrate/be7af54fab7a421205de3f2082cfe0c5.gif)
The Structure of a PeekMessage() Loop
以下是 PeekMessage()的函数原型:
BOOL PeekMessage(LPMSG lpMsg,
HWND hWnd,
UINT wMsgFilterMin,
UINT wMsgFilterMax,
UINT wRemoveMsg);
前四个参数与GetMessage()的参数相同,然而第五个wRemoveMsg参数是此函数特有的。
这个函数的作用是消息是否留在消息队列中。其决定参数为PM_REMOVE 或者PM_NOREMOVE。
以下是使用 PeekMessage()修改过的主循环:
// enter the main loop:
// this struct holds Windows event messages
MSG msg = {0};
// Enter the infinite message loop
while(TRUE)
{
// Check to see if any messages are waiting in the queue
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// translate keystroke messages into the right format
TranslateMessage(&msg);
// send the message to the WindowProc function
DispatchMessage(&msg);
// check to see if it's time to quit
if(msg.message == WM_QUIT)
break;
}
else
{
// Run game code here
// ...
// ...
}
}
while(TRUE)
将创建一个无限循环直至退出游戏。
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
因为不再等待消息,只是使用 PeekMessage()检测消息是否存在。如果有消息 PeekMessage() 返回 TRUE,如果没有返回FALSE。所以如果存在消息,它运行 TranslateMessage() 和 DispatchMessage(),否则继续代码程序。
if(msg.message == WM_QUIT)
如果消息结果是 WM_QUIT,这意味着退出"无限"的循环并返回。如果推出程序Getmessage () 返回 '0',从而结束 while() 循环。
Running the New Loop
以下是新修改的代码:
// include the basic windows header file
#include <windows.h>
#include <windowsx.h>
// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam);
// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// the handle for the window, filled by a function
HWND hWnd;
// this struct holds information for the window class
WNDCLASSEX wc;
// clear out the window class for use
ZeroMemory(&wc, sizeof(WNDCLASSEX));
// fill in the struct with the needed information
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = L"WindowClass1";
// register the window class
RegisterClassEx(&wc);
// calculate the size of the client area
RECT wr = {0, 0, 500, 400}; // set the size, but not the position
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE); // adjust the size
// create the window and use the result as the handle
hWnd = CreateWindowEx(NULL,
L"WindowClass1", // name of the window class
L"Our First Windowed Program", // title of the window
WS_OVERLAPPEDWINDOW, // window style
300, // x-position of the window
300, // y-position of the window
wr.right - wr.left, // width of the window
wr.bottom - wr.top, // height of the window
NULL, // we have no parent window, NULL
NULL, // we aren't using menus, NULL
hInstance, // application handle
NULL); // used with multiple windows, NULL
// display the window on the screen
ShowWindow(hWnd, nCmdShow);
// enter the main loop:
// this struct holds Windows event messages
MSG msg = {0};
// Enter the infinite message loop
while(TRUE)
{
// Check to see if any messages are waiting in the queue
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// translate keystroke messages into the right format
TranslateMessage(&msg);
// send the message to the WindowProc function
DispatchMessage(&msg);
// check to see if it's time to quit
if(msg.message == WM_QUIT)
break;
}
else
{
// Run game code here
// ...
// ...
}
}
// return this part of the WM_QUIT message to Windows
return msg.wParam;
}
// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// sort through and find what code to run for the message given
switch(message)
{
// this message is read when the window is closed
case WM_DESTROY:
{
// close the application entirely
PostQuitMessage(0);
return 0;
} break;
}
// Handle any messages the switch statement didn't
return DefWindowProc (hWnd, message, wParam, lParam);
}
这一篇文章的内容并没有对之前的程序有明显的改变,因为只影响在改变窗口的时候。