Windows Messages |
|
The computer is a machine that only follows instructions. It almost doesn't know anything. Because of this, the computer cannot predict what a user wants to do with the computer. In fact, a great deal of the responsibility is left to the programmer who must decide what can and cannot or should not be done on an application. To help the users with computer interaction, the operating system provides a series of objects called Windows controls. The programmer decides what objects are necessary for a given application. Each computer application is equipped with Windows controls that allow the user to interact with the computer. Because the computer cannot and would not predict what the user wants to do when using the computer, the operating system lets each object tell it when it needs something from Windows. To do this, a control sends a message to the operating system every time something is new. Because there can be so many messages a control can send and because many controls can send various messages, there is a formula each message or almost every one of them must follow, just like there are rules the post office wants you to follow in order to send a letter. A message to Windows must provide four pieces of information:
To manage the messages sent to Windows, they are communicated through a function pointer called a Windows procedure. The name of the function is not important but it must return a 32-bit integer, in fact a C/C++ long or Win32 LONG. Therefore, it is declared as LRESULT (LONG Result). Because this is a function pointer, it must be declared and defined as CALLBACK. The messages can be carried in a function defined as follows: LRESULT CALLBACK MessageProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); To process the messages, and because there can be so many of them, this function typically uses a switch control to list all necessary messages and process each one in turn. After processing a message, its case must return a value indicating that the message was successfully processed or not. No matter how many messages you processed, there will still be messages that you did not deal with. It could be because they were not sent even though they are part of the Windows controls used on an application. If you didn't process some messages, you should/must let the operating system know so it can take over. What happens is that the operating system is aware of all messages and it has a default behavior or processing for each one of them. Therefore, you should/must return a value for this to happen. The value returned can be placed in the default section of the switch condition and must simply be a DefWindowProc() function. Its syntax is: LRESULT DefWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); This function is returned to Windows, saying "There are messages I couldn't process. Do what you want with them". The operating system would simply apply a default processing to them. The values returned by the DefWindowProc() function should be the same passed to the procedure. The most basic message you can process is to make sure a user can close a window after using it. This can be done with a function called PostQuitMessage(). Its syntax is: VOID PostQuitMessage(int nExitCode) This function takes one argument which is the value of the LPARAM argument. To close a window, you can pass the argument as WM_QUIT. Based on this, a simple Windows procedure can be defined as follows: LRESULT CALLBACK WndProcedure(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { switch(Msg) { case WM_DESTROY: PostQuitMessage(WM_QUIT); break; default: return DefWindowProc(hWnd, Msg, wParam, lParam); } return 0; }
|
|
A basic program with one message can be written as follows: |
//--------------------------------------------------------------------------- #include <windows.h> //--------------------------------------------------------------------------- HWND hWnd; LPCTSTR ClsName = L"WndMsg"; LPCTSTR WindowCaption = L"Windows and Controls Messages"; LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); //--------------------------------------------------------------------------- INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG Msg; WNDCLASSEX WndClsEx; WndClsEx.cbSize = sizeof(WNDCLASSEX); WndClsEx.style = CS_HREDRAW | CS_VREDRAW; WndClsEx.lpfnWndProc = WndProc; WndClsEx.cbClsExtra = NULL; WndClsEx.cbWndExtra = NULL; WndClsEx.hInstance = hInstance; WndClsEx.hIcon = LoadIcon(NULL, IDI_APPLICATION); WndClsEx.hCursor = LoadCursor(NULL, IDC_ARROW); WndClsEx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); WndClsEx.lpszMenuName = NULL; WndClsEx.lpszClassName = ClsName; WndClsEx.hIconSm = LoadIcon(NULL, IDI_APPLICATION); RegisterClassEx(&WndClsEx); hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, ClsName, WindowCaption, WS_OVERLAPPEDWINDOW, 100, 120, 640, 480, NULL, NULL, hInstance, NULL); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); while( GetMessage(&Msg, NULL, 0, 0) ) { TranslateMessage(&Msg); DispatchMessage(&Msg); } return Msg.wParam; } //--------------------------------------------------------------------------- LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { switch(Msg) { case WM_DESTROY: PostQuitMessage(WM_QUIT); break; default: return DefWindowProc(hWnd, Msg, wParam, lParam); } return 0; } //---------------------------------------------------------------------------
Windows Messages |
Window Creation |
WM_CREATE: Once you have decided to create a message, you send a message to Windows. Actually, when you are creating a window, a message called WM_CREATE is sent to Windows. This is the favorite message you can use to perform any early processing that you want to make sure happens before most other things show up. For example, you can use this message to initialize anything in your application. Therefore, this message is the first sent to the operating system. Here is an example: |
//--------------------------------------------------------------------------- LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { switch(Msg) { case WM_CREATE: MessageBox(NULL, L"The window is being created", WindowCaption, MB_OK); break; case WM_DESTROY: PostQuitMessage(WM_QUIT); break; default: return DefWindowProc(hWnd, Msg, wParam, lParam); } return 0; } //---------------------------------------------------------------------------
Window Display |
WM_SHOWWINDOW: After a window has been created, it needs to be displayed, that is, the window needs to be shown. Also, if the window was previously hidden, you can decide to show it. On the other hand, if a window is displaying, you may want to hide it, for any reason you judge necessary. To take any of these actions, that is, to show or hide a window, you must send the WM_SHOWWINDOW message. The syntax of this message is: OnCreate(HWND hWnd, WM_SHOWWINDOW, WPARAM wParam, LPARAM lParam); hWnd is the window that sends the message. wParam is a Boolean value. If you want to display or show the hWnd window, set the wParam value to TRUE. If you want to hide the hWnd window, set this value to FALSE. lParam specifies the status of the window. |
//--------------------------------------------------------------------------- LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { switch(Msg) { case WM_CREATE: MessageBox(NULL, "The window is being created", WindowCaption, MB_OK); break; case WM_SHOWWINDOW: break; case WM_DESTROY: PostQuitMessage(WM_QUIT); break; default: return DefWindowProc(hWnd, Msg, wParam, lParam); } return 0; } //---------------------------------------------------------------------------
Window Activation |
WM_ACTIVATE: When two or more windows are running on the computer, only one can receive input from the user, that is, only one can actually be directly used at one particular time. Such a window has a title bar with the color identified in Control Panel as Active Window. The other window(s), if any, display(s) its/their title bar with a color called Inactive Window: To manage this setting, the windows are organized in a 3-dimensional coordinate system and they are incrementally positioned on the Z coordinate, which defines the (0, 0, 0) origin on the screen (actually on the top-left corner of your monitor) with Z coordinate coming from the screen towards you. In order to use a window other than the one that is active, you must activate it. To do this, you can send a message called WM_ACTIVATE. The syntax of this message is: OnActivate(HWND hWnd, WM_ACTIVATE, WPARAM wParam, LPARAM lParam); Actually, this message is sent to two objects: the window that is being activated and the one that is being deactivated. hWnd identifies a window involved in this message and is related to the wParam parameter. The wParam parameter specifies the action to take. It is a constant value that can be one of the following: |
Value | Description |
---|---|
WA_ACTIVE | Used to activate the window |
WA_INACTIVE | Used to deactivate the window without using the mouse, for example by pressing Alt+Tab |
WA_CLICKACTIVE | Used to activate the window using the mouse |
//--------------------------------------------------------------------------- LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { switch(Msg) { case WM_CREATE: MessageBox(NULL, L"The window is being created", WindowCaption, MB_OK); break; case WM_ACTIVATE: break; case WM_DESTROY: PostQuitMessage(WM_QUIT); break; default: return DefWindowProc(hWnd, Msg, wParam, lParam); } return 0; } //---------------------------------------------------------------------------
Window Painting |
WM_PAINT: Whenever Microsoft Windows is asked to display (whether it must unhide or activate) a window, it must use its location (measure from left and top) and size (width and height). It must give it the Active Window color and it must restore its other active colors. To do this, the operating system must paint the window. When doing this, a message called WM_PAINT is sent. The syntax of this message is: OnPaint(HWND hWnd, WM_PAINT, WPARAM wParam, LPARAM lParam); The only thing Windows needs to know is the window that needs to be painted or repainted, which is specified as the hWnd value. |
//--------------------------------------------------------------------------- LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { switch(Msg) { case WM_CREATE: MessageBox(NULL, L"The window is being created", WindowCaption, MB_OK); break; case WM_SHOWWINDOW: break; case WM_ACTIVATE: break; case WM_PAINT: break; case WM_DESTROY: PostQuitMessage(WM_QUIT); break; default: return DefWindowProc(hWnd, Msg, wParam, lParam); } return 0; } //---------------------------------------------------------------------------
Window Sizing |
WM_SIZE: When using an application, one of the actions a user may perform is to change its size. Whenever the size of a window has changed, the window receives the WM_SIZE message. Its syntax is: OnSize(HWND hWnd, WM_SIZE, WPARAM wParam, LPARAM lParam); hWnd is the window that was resized. wParam determines how the sizing action should be performed. It can be one of the following values |
Value | Description |
---|---|
SIZE_MAXHIDE | Sent to this window if it was maximized from being previously hidden |
SIZE_MAXIMIZED | Sent to this window if it was maximized |
SIZE_MAXSHOW | Sent if the window was restored |
SIZE_MINIMIZED | Sent if the window was minimized |
SIZE_RESTORED | Sent if the window was resized, but neither the SIZE_MINIMIZED nor SIZE_MAXIMIZED value applies |
lParam specifies the dimensions of the window (the width and the height
//--------------------------------------------------------------------------- LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { switch(Msg) { case WM_CREATE: break; case WM_SHOWWINDOW: break; case WM_ACTIVATE: break; case WM_PAINT: break; case WM_SIZE: break; case WM_DESTROY: PostQuitMessage(WM_QUIT); break; default: return DefWindowProc(hWnd, Msg, wParam, lParam); } return 0; } //---------------------------------------------------------------------------
WM_SIZING: This message is sent to a window that is being resized with the above WM_SIZE message. Its syntax is: OnSizing(HWND hWnd, WM_SIZING, WPARAM wParam, LPARAM lParam); hWnd is the window that is being resized. To resize a window, the user usually grabs one of the four corners or one of the four borders. The lParam parameter specifies what border or corner the user is moving. It can be one of the following values: |
Value | Border or Corner |
---|---|
WMSZ_BOTTOM | Bottom edge |
WMSZ_BOTTOMLEFT | Bottom-left corner |
WMSZ_BOTTOMRIGHT | Bottom-right corner |
WMSZ_LEFT | Left edge |
WMSZ_RIGHT | Right edge |
WMSZ_TOP | Top edge |
WMSZ_TOPLEFT | Top-left corner |
WMSZ_TOPRIGHT | Top-right corner |
lParam is actually the rectangular dimensions of the window that is being resized. It is a RECT object. |
Window Moving |
WM_MOVE: When a window has been moved, the operating system needs to update its location. Therefore, the window sends a message called WM_MOVE. Its syntax is: OnMove(HWND hWnd, WM_MOVE, WPARAM wParam, LPARAM lParam); hWnd is the window that needs to be moved. The wParam and lParam values are not used. WN_DESTROY: Once the window has been used and the user has closed it, the window must send a message to the operating system to destroy it and reclaim the memory space it was using. The message is called WN_DESTROY and its syntax is: OnDestroy(HWND hWnd, WN_DESTROY, WPARAM wParam, LPARAM lParam); hWnd is the window that needs to be destroyed. The wParam and lParam values are not used. |
Window Destruction |
WM_DESTROY: Once the window has been used and the user has closed it, the window must send a message to the operating system to destroy it. The message sent is called WN_DESTROY and its syntax is: OnDestroy(HWND hwnd, WM_DESTROY, WPARAM wParam, LPARAM lParam); hWWnd is the window that is being destroyed. The wParam and lParam values are not used. |
Anytime Messages |
Introduction |
The messages we have used so far belong to specific events generated at a particular time by a window. Sometimes in the middle of doing something, you may want to send a message regardless of what is going on. This is made possible by a function called SendMessage(). The syntax of the SendMessage() function is as follows:
LRESULT SendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
The hWnd argument is the object or control that is sending the message.
The Msg argument is the message to be sent.
The wParam and the lParam values depend on the message that is being sent.
Sending Messages |
The advantage of using the SendMessage() function is that, when sending this message, it would target the procedure that can perform the task and this function would return only after its message has been processed. Because this (member) function can sometimes universally be used, that is by any control or object, the application cannot predict the type of message that SendMessage() is carrying. Therefore, (the probable disadvantage is that) you must know the (name or identity of the) message you are sending and you must provide accurate accompanying items (like sending a letter with the right stamp; imagine you send a sexy letter to your grand-mother in Australia about her already dead grand grand-father who is celebrating his first job while he has just become 5 years old).
In order to send a message using the SendMessage() function, you must know what message you are sending and what that message needs in order to be complete. For example, to change the caption of a window at any time, you can use the WM_SETTEXT message. The syntax to use would be:
SendMessage(hWnd, WM_SETTEXT, wParam, lParam);
Obviously you would need to provide the text for the caption you are trying to change. This string is carried by the lParam argument as a null-terminated string. For this message, the wParam is ignored.
LPCTSTR strMsg = L"This message was sent"; SendMessage(hWnd, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)strMsg);
|
||
Previous | Copyright © 2003-2015, FunctionX | Next |
|