MFC hook for skin replacement

Source: Internet
Author: User

Dialog box for accessing MFCProgramThe idea at the beginning is simple: Write a base class for the dialog box, and then all the dialogs of the program are derived from the base class. In this way, I only need to modify the style of the dialog box in the base class, but the problem is that the style of the Windows General dialog box (file selection dialog box, color box, font box, message box) cannot be changed, instead, I thought of a way to embed these general dialogs into my dialog box, so that it may be okay, finally, the general dialog box is embedded into its own dialog box through view. This is a solution, but how does the system message box solve the problem? Instead, continue to Baidu Google and find a keyword hook, it turns out that the function of skin replacement can be implemented through hook. Baidu Google continues, but there is no detailed explanation about Hook skin replacement.ArticleFortunately, Baidu Google came to the source code and was surprised when it opened it. There were so many classes in it that there were countless functions, and the class inheritance feature was used to bypass it! Helpless, so I had to watch and practice it with my head! Enter the topic below:

Here I will talk about the skin replacement of the dialog box form. Let's talk about the principle first!

Install wh_callwndproc hook (setwindowshookex) in the application to capture the creation of each form, and then replace the form process function of the original form with the form process function written by yourself, we can customize the styles of all forms by ourselves.

CombinedCodeLet's talk about the specific process:

1. Check whether the listener has been created in the dialog box during wh_callwndproc processing.

 Tchar szclassname [max_path];
Int Count = Getclassname (hwnd, szclassname, Sizeof (Szclassname) / Sizeof (Szclassname [ 0 ]);
Cstringw strclassname = Szclassname;
If (Strclassname. comparenocase (_ T ( " #32770 " )) = 0 ) // "#32770" indicates the dialog box form
{
....
}

2. after a dialog box is created, you have to replace the window procedure function of the dialog box. Here, a base class cskinwnd is created, which is used as the base class for all windows (buttons, text boxes, dialog Box ...), we only discuss the dialog box here. Therefore, a class cskindlg is derived from this base class. The cskinwnd class provides the replacement processing function for the form process function and the registration of the skin replacement form (cmap, key: form handle, value: class that implements the form skin replacement function (for example, cskindlg). cskindlg mainly encapsulates the static functions of the self-created form process, and the processing functions for some messages in the form creation process.

3. The following describes the form process processing functions in the cskindlg class:

First, let's talk about some styles in the self-developed dialog box: mainly for non-customer areas re-painting: title bar icon, title bar text, title bar button, Title Bar background, and border. Since it is for non-customer re-painting, it is necessary to process the messages in the non-customer region. The following message is used here: wm_ncpaint, wm_ncactivate, wm_nclbuttondown, wm_nclbuttonup, wm_ncmousemove, wm_nccalcsize, from the abbreviation (NC indicates no client, huh, this is my own guess) you can see the meaning of these messages.

Wm_ncpaint, which processes the repainting of non-customer areas in this message. For the drawing of the maximize, minimize, and close buttons of non-customer areas, the dialog boxes may be different, some dialogs do not have the maximization and minimization buttons, so before drawing the buttons, determine whether the dialog box supports maximization and minimization (as for closing, the dialog box should be supported). This requires capturing the wm_create message, after obtaining the style created by the form in this message, the Code is as follows:

  case   wm_create: 
{< br> DWORD dwstyle = getwindowlongptr (hwnd, gwl_style);
If (dwstyle & ws_maximizebox) = ws_maximizebox) // maximize button
pskindlg -> m_bmaxbtn = true;
......

when it comes to the Message wm_create, there is another process in the message, that is, to modify the form style and remove the title bar that comes with the form (as to why to remove the built-in title bar, my understanding is to better control the formulation of the title bar, because the title bar effects of XP and win7 are different. To ensure stability, I still need to remove the built-in title bar and draw it by myself.)

  dwstyle  &=    ~   ws_caption;  ///   remove the default title bar   
setwindowlong (hwnd, gwl_style, dwstyle);
crect rcwnd;
getwindowrect (hwnd, rcwnd);
hrgn = createrectrgn ( 0 , 0 , rcwnd. width (), rcwnd. height ();
setjavaswrgn (hwnd, hrgn, true); /// trigger the wm_ncclacsize message

Analyze the code, go to the title bar, And why call setmediawrgn to reset the form area. After debugging, it is found that the execution of setmediawrgn triggers the wm_nccalcsize message. msdn, this message is triggered when the form needs to be re-calculated. In this program, the message is used to re-calculate the rect of the customer area to make a position to draw the title bar and border.

The parameters of this message are worth pondering. Here, I will briefly talk about the parameters of this program, mainly these two parameters:

 WparamWparam,// When this parameter is set to true, You need to specify which parts of the form are valid (I understand which parts are client partitions)
 LparamLparam// Nccalcsize_params struct. The rect rgrc [3] of this struct needs to be processed.

[Rgrc, rgrc [0] indicates the new coordinates after the form is moved or changed. rgrc [1] indicates the coordinates before the form is moved or the size is changed, rgrc [2] indicates the coordinates of the customer zone before the form is moved or the size is changed]

The Return Value of the message processing function wm_nccalcsize is also special. Here we use wvr_validrects, the rgrc [1] and rgrc [2] members respectively contain valid target region Rectangles and source region rectangles. Therefore, the size of the recalculated customer region is placed in rgrc [1, let's take a look at the message processing code.

 Bool cskindlg: onnccalcsize (bool bcalcvalidrects, nccalcsize_params  *  Lpncsp)
{
If (Bcalcvalidrects)
{
If (M_btitle) // Adjust the position of the title bar and the border
{
Lpncsp -> Rgrc [ 0 ]. Top + = Gettitleheight ();
Lpncsp -> Rgrc [ 0 ]. Left + = Getborderwidth ();
Lpncsp -> Rgrc [ 0 ]. Right -= Getborderwidth ();
Lpncsp -> Rgrc [ 0 ]. Bottom -= Getborderwidth ();
}

Lpncsp -> Rgrc [ 1 ] = Lpncsp -> Rgrc [ 0 ];
Return True;
}
Return False;
}

Here, we go back to wm_ncpaint and adjust the title bar and border position in the wm_nccalcsize message. We can draw the following picture. We recommend that you create a bitmap during the painting, this bitmap draws all the elements in the title bar, and then in the bitblt to the title bar area, the advantage is to prevent non-customer area refreshing, icons, titles, the buttons are constantly flashing (XP cannot detect it, but it is obvious in win7). As for the size of the border and title bar, the system is not used, but it is specified by itself, adjust it according to the actual situation.

Let's take a look at the message wm_nchittest. This message mainly determines where the mouse clicks the title bar. Its return value nhittest is very useful, for messages such as wm_ncmousemove, wm_ncmousedown, and wm_ncmouseup, you can determine which button you clicked Based on nhittest to process the response and implement its functions, it should be noted that because the title bar is drawn by ourselves, the re-drawing is maximized and minimized, and the location of the close button may not be the same as the default location of the system. Therefore, we captured the wm_nchittest message and determined it by ourselves. The Code is as follows:

 Crect rcwnd;
Getwindowrect (hwnd, & Rcwnd );

// Determines which button the mouse has been placed on
If (Gettwndrect (rcwnd, tbtncls). ptinrect (point )) // Close button
Return Htclose;
If (Gettwndrect (rcwnd, tbtnmin). ptinrect (point) && M_bminbtn)
Return Htminbutton;
If (Gettwndrect (rcwnd, tbtnmax). ptinrect (point) && M_bmaxbtn)
Return Htmaxbutton;
If (Gettwndrect (rcwnd, title). ptinrect (point) && M_btitle) // Whether the mouse is on the title bar
Return Htcaption;
Return Nhittest;

Note: gettwndrect (crect & rcwnd, int nwhich) is used to obtain the rect of the control on the title bar. tbtncls is the identifier, indicating to close the button.

The message is similar. Oh, yes, there is a wm_size message. Do you still remember that we have set the valid region of the form through setmediawrgn in the wm_create message, if we no longer process the form in wm_size, The Size Change of the form will be faulty. What should we do in wm_size? It's easy to get the current form area, once setmediawrgn is set, it is okay, because wm_nccalcsize has recalculated the size of the form before wm_size.

Now, the general process of the program has ended. I will upload another source code for the reference of the users who need it.

I would like to note that my reference source code was downloaded online and compiled by jia wei yunniu. I analyzed the source code and wrote a piece of code based on my understanding, my code mainly implements the dialog box skin replacement function, while Daniel's source code is relatively complete, and various controls are basically designed, that is, there are few notes, it's laborious !!!!!!!!! But I still want to thank Jia weiyun's predecessors. His source code has helped me a lot!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.