11.2.1 WinMain()函数(5)
GetMessage()函数的最后两个实参是两个整数,它们存储希望从队列中检索的消息ID的最小值和最大值,从而可以有选择性地检索消息。该范围通常是用符号常量指定的。例如,使用WM_ MOUSEFIRST和WM_MOUSELAST作为这两个实参将只选择鼠标消息。如果这两个实参像本例中这样都是0,那么将检索所有消息。
多任务
如果没有排队的消息,则GetMessage()函数不会把控制权返回到程序中。Windows允许将执行权传递给另一个应用程序,仅当队列中有消息时才能从调用GetMessage()函数获得返回值。
该机制是允许多个应用程序在旧版Windows下运行的基础,称作协作式多任务,因为该机制依赖于并发的应用程序不时放弃对处理器的控制权。在程序调用GetMessage()函数之后,如果没有需要程序处理的消息,则系统将执行另一个应用程序,而我们的程序仅当另一个应用程序释放处理器之后才能获得另一次执行操作的机会。释放处理器的原因可能是调用GetMessage()函数之后该程序的消息队列中没有消息,但这不是唯一的可能性。
在当前的Windows版本中,操作系统可以在一段时间之后中断某个应用程序,然后将控制权传递给另一个应用程序。该机制称作抢先式多任务,因为任何情况下都可以中断某个应用程序。但在抢先式多任务机制下,仍然必须像以前那样在WinMain()函数中使用GetMessage()函数编写消息循环的代码,并为在长时间运行的计算中不时将对处理器的控制权交还给Windows预先采取措施(通常是使用API函数PeekMessage()完成的)。如果不这样做,应用程序就可能无法响应出现的重画应用程序窗口的消息。产生该消息的原因可能与应用程序完全无关-- 例如,关闭相重叠的另一个应用程序的窗口。
GetMessage()函数概念性的工作过程如图11-3所示。
在while循环内,首先调用TranslateMessage()函数,请求Windows为与键盘有关的消息做一些转换工作。然后调用DispatchMessage()函数,使Windows分派该消息-- 换句话说,就是调用程序中的WindowProc()函数来处理该消息。在WindowProc()函数结束对消息的处理之前,DispatchMessage()函数不会返回。WM_QUIT消息意味着程序应该结束,因此该消息把FALSE返回给应用程序,使消息循环停止。

5. 完整的WinMain()函数
我们已经看过所有需要包含在WinMain()函数中的代码,因此现在可以将它们汇编成一个完整的函数:
- // Listing OFWIN_1
- int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
- LPSTR lpCmdLine, int nCmdShow)
- {
- WNDCLASSEX WindowClass; // Structure to hold our window's attributes
- static LPCTSTR szAppName = L"OFWin"; // Define window class name
- HWND hWnd; // Window handle
- MSG msg; // Windows message structure
- WindowClass.cbSize = sizeof(WNDCLASSEX); // Set structure size
- // Redraw the window if the size changes
- WindowClass.style = CS_HREDRAW | CS_VREDRAW;
- // Define the message handling function
- WindowClass.lpfnWndProc = WindowProc;
- WindowClass.cbClsExtra = 0; // No extra bytes after the window class
- WindowClass.cbWndExtra = 0; // structure or the window instance
- WindowClass.hInstance = hInstance; // Application instance handle
- // Set default application icon
- WindowClass.hIcon = LoadIcon(0, IDI_APPLICATION);
- // Set window cursor to be the standard arrow
- WindowClass.hCursor = LoadCursor(0, IDC_ARROW);
- // Set gray brush for background color
- WindowClass.hbrBackground = static_cast<HBRUSH>(GetStockObject(GRAY_BRUSH));
- WindowClass.lpszMenuName = 0; // No menu
- WindowClass.lpszClassName = szAppName; // Set class name
- WindowClass.hIconSm = 0; // Default small icon
- // Now register our window class
- RegisterClassEx(&WindowClass);
- // Now we can create the window
- hWnd = CreateWindow(
- szAppName, // the window class name
- L"A Basic Window the Hard Way", // The window title
- WS_OVERLAPPEDWINDOW, // Window style as overlapped
- CW_USEDEFAULT, // Default screen position of upper left
- CW_USEDEFAULT, // corner of our window as x,y...
- CW_USEDEFAULT, // Default window size
- CW_USEDEFAULT, // ....
- 0, // No parent window
- 0, // No menu
- hInstance, // Program Instance handle
- 0 // No window creation data
- );
- ShowWindow(hWnd, nCmdShow); // Display the window
- UpdateWindow(hWnd); // Cause window client area to be drawn
- // The message loop
- while(GetMessage(&msg, 0, 0, 0) == TRUE) // Get any messages
- {
- TranslateMessage(&msg); // Translate the message
- DispatchMessage(&msg); // Dispatch the message
- }
- return static_cast<int>(msg.wParam); // End, so return to Windows
- }