First of all, let's talk about what is subclass. In fact, subclass is very easy to understand. Like before, it's still starting from the win32 sdk method. Here we can also add something, I have seen some people in some groups saying that they can simply learn MFC, and there is no need to learn win32. Some people say that it is very simple, but it is not actually true, due to the hidden underlying layer of MFC and its complicated framework, it is very difficult for us to learn it many times. Moreover, many people follow the instructions in some programming books, but I don't know how it works. When I need to design my own program, I don't know how it works. Since I learned how to develop a windows desktop program, I found that, whether it is NET Framework, MFC, ATL, MFC ACTIVEX, or MFC automation, we need to really understand and learn it from win32, because they are at the bottom layer, only by knowing them can we flexibly apply the MFC. When encountering errors, we can analyze the program and find the problem. You may not use win32 to write it yourself, but it is very helpful for your understanding. Now, let's get down to the truth.
First, let's take a look at how the program processes various behaviors in the window process in win32, such as the user's operation message or the message generated by the system. Then, subclass is to insert a process before the message arrives at the window. It turns out that we only have one window process. All messages about this window are processed in this window process. However, before the message reaches this process, we can process the message and send it to the original window. In win32, The SetWindowLong function is used to set the window to be inserted. Function prototype:
Long winapi SetWindowLong (
_ In _ HWND hWnd,
_ In _ int nIndex,
_ In _ LONG dwNewLong
);
We know that during the win32 creation window (see "MFC-prelude" in this blog), the first step is to declare a WNDCLASS window class and then fill in the members, in this way, some properties of the window to be created are set, such as menus, cursors, and program icons. One of the members is the window setting process, we use the RegisterClass function to register this window class (you can also use other functions and some MFC functions, but the principle is the same). Then we can use this window class to create a window, the messages of the window created with this window class will arrive at the window procedure function set in the window class. A window is identified by a handle class. Therefore, the first parameter of SetWindowLong is a window handle, which indicates that it must be prior to the originally registered window process, to insert a window procedure function, the second parameter is an index value. This function is used to change the attributes of the window registration window class, such as the style and instance handle, the index value is used to describe the attributes to be modified. Here, you can modify the window pointing to this window, in this new window process, the most important one is to pass unprocessed messages to the original window process function, and the third parameter is the new value. After the message is successfully inserted, the new window is inserted first and then to the original window. As follows:
{
If (uMsg = WM_GETDLGCODE)
Return DLGC_WANTALLKEYS;
Return CallWindowProc (OrigProc, hwnd, uMsg, wParam, lParam );
}
The unprocessed messages are passed to the original window process.
So why do we need to subtype the window? In fact, we can do some preprocessing or intercept some messages before processing the original window process, so that we do not want to pass them to the original window process or some messages, it must be subclass-based before it can be processed. For example, the control on the dialog box must process standard window messages such as WM_LBUTTONDOWN and WM_SETCURSOR. If we do not use subclass-based processing, directly transmitted to the dialog box. After the dialog box is processed, we can only process notification messages of controls, such as click messages.
In MFC, the window process function is used with the switch/case statement to process messages. Instead, the window class and message ing function are used to process messages. The truth is the same. That is, they have different message processing methods. The message of MFC is described in the article "MFC -- message", which is also described in combination with win32. If you are interested, please refer to it. Below is an example to illustrate the subclass of MFC.
First, I create a dialog box-based program, and then put six edit boxes in the dialog box. The IDS are IDC_EDIT1 to IDC_EDIT6, and then two buttons are put. The IDS are IDC_BUTTON1 and idc_button2. For example:
For the edit box, sometimes we want to press enter after the input is complete to complete the input of an edit box, and automatically go to the next edit box, you do not need to move the input focus of the edit box with the mouse or tab key, but the response to the Enter key in the edit box is either a line break (multi-row style) or no response (single-row style ), now I set this to single-line Input. To implement the enter key, the focus is automatically moved to the next edit box. The following two buttons, for the buttons we draw on the dialog box, the default mouse pointer shape is the arrow pointer, now I want to achieve when you move the mouse to the "Hand Pointer" button, turns it into a hand pointer. To achieve this, we need to subtype the message to process the response.
As described above, the window class and message response used in MFC are used to process messages. Now I want to process the messages in the edit box and button before reaching the message processing in the dialog box, the edit box and button messages are processed because the control still has windows and standard window messages, such as WM_MOUSEMOVE and WM_LBUTTONDOWN. Therefore, we first add two MFC classes, CMyEdit and CMyButton, which inherit from CEdit and CButton, respectively, and then add them as follows:
In the main dialog box, the header file contains two header files:
# Include MyEdit. h
# Include MyButton. h
Declare the corresponding variables in the Main Dialog Box:
In OnInitDialog in the Main Dialog Box, set subclass:
In this way, all messages on the control will first go through the window we just added and then go to the dialog box. Now let's move the input focus of the edit box through the enter key.
When a window gets the focus, it receives the message WM_SETFOCUS. When a window loses the focus, it receives the WM_KILLFOCUS message. Therefore, when processing these two messages, set a Boolean value in the CMyEdit class to determine whether the window has a focus. When obtaining the focus, set it to TRUE, FALSE if the focus is lost. As follows:
Then, the system responds to the WM_KEYUP message to filter the press of the enter key. In addition, I set a custom message to send a message to the main dialog box, so that it can use the Boolean value in each edit box object to determine that the current edit box has a focus, then, use the SetFocus function to focus on the next edit box. As follows:
After receiving the enter pop-up message, send a custom message WM_SETCONTROLFOCUS to the Main Dialog Box and process the custom message as follows:
CheckFocus is a function that I declare and define to process the conversion of input focus. This completes such a function.
The following code converts a mouse pointer to a hand shape on a button. By default, the mouse pointer is the pointer type set when the window class is registered. Of course, this is not the case in the dialog box. The dialog box is a predefined window class. If you want to modify the shape of the mouse pointer without changing the window class attributes, including common windows, dialog boxes, controls, and other types of windows, you can process the WM_SETCURSOR message, if we do not process this message, the system will use the default mouse pointer. If we want to use our own pointer, we can set our own pointer in this message, after completion, we also need to set the return value to a non-zero value to inform the system that we have provided our own pointer, instead of providing the pointer for us. After knowing this principle, we can add a message to CMyButton to process the WM_SETCURSOR message and process it as follows:
In this way, the sub-type button is changed to a hand-shaped mouse pointer when the mouse is moved. The above example illustrates the application of subclass, but the most important thing is to understand the principle of subclass. In the future, we will know how to use subclass in the Process of program design, the subclass application here is just to illustrate its principles, and its application is totally more than that.
Note that the SubclassWindow function of CWnd is not bound to an MFC object before subclass is used, that is to say, an HWND has not been bound to an MFC object by using Attach. In addition, the UnsubclassWindow function can be used to remove the subclass of a window. For the MFC dialog box control, there is also a function that can also be easily subclass, SubclassDlgItem. The first parameter of this function is the Control ID, and the second parameter is the parent window object pointer. This effect is the same as that of SubclassWindow, but the parameters are different. To use SubclassWindow, you must obtain the control's window handle through GetDlgItem of win32. SubclassDlgItem is not required.
For more information, see msdn.