How to Implement ATL/wtl/MFC message ing

Source: Internet
Author: User

When we compile the wtl program, we are familiar with the following message ing:

Begin_msg_map (cmaindlg)
Message_handler (wm_initdialog, oninitdialog)
Command_id_handler (id_catalog, onsetcatalog)
End_msg_map ()

When writing an MFC program, the message ing is as follows:

Begin_message_map (cupdatedlg, cdialog)
On_wm_paint ()
On_wm_timer ()
End_message_map ()

Then we write the corresponding message function, which will be called when the program runs.

For our junior programmers, we may seldom pay attention to the implementation methods of these macros. Instead, we only focus on using these macros and know what these macros can do.

Not to mention their implementations for the moment, we are surprised to see this implementation method.

Close your eyes and ask yourself: what will I do if I implement a program framework with the same functions?

Most people will first think of a structure switch () {case ...}, good, just like when our brother and sister wrote the Win 32 program, there was a function that everyone was very familiar:

Lresult callback wndproc (hwnd, uint message, wparam, lparam)
{

Switch (Message)
{
Case wm_paint:

Paint_fun (...);

Break;

Case wm_mousemove:

Mousemove_fun (...);

Break;

Case wm_mouseleave:

Mouseleave_fun (...);

Break;

....

Default:

Break;

}

If derivation and inheritance are involved, you may naturally think of a class like this to support polymorphism:

Class cownwnd

{

Virtual lresult paint_fun (...){...}

Virtual lresult mousemove_fun (...){...}

....

Lresult callback wndproc (hwnd, uint message, wparam, lparam)
{

Switch (Message)
{
Case wm_paint:

Paint_fun (...);

Break;

Case wm_mousemove:

Mousemove_fun (...);

Break;

Case wm_mouseleave:

Mouseleave_fun (...);

Break;

....

Default:

Break;

}

};

Then, you only need to derive the corresponding virtual function in the derived class.

Well, yes, it can meet the requirements. But when we look at the wtl/mfc program, we find that they use macros to skillfully implement this method.

You can view the source code of wtl:

We found that all the window classes inherit the cmessagemap class, and what did this class do? The source code of this class is as follows:

Class atl_no_vtable cmessagemap
{
Public:
Virtual bool processwindowmessage (hwnd, uint umsg, wparam, lparam,
Lresult & lresult, DWORD dwmsgmapid) = 0;
};

Oh, it only provides a pure virtual function. Let's continue to look at it and we will find this important macro:

# Define begin_msg_map (theclass )/
Public :/
Bool processwindowmessage (hwnd, uint umsg, wparam, lparam, lresult & lresult, DWORD dwmsgmapid = 0 )/
{/
Bool bhandled = true ;/
(Hwnd );/
(Umsg );/
(Wparam );/
(Lparam );/
(Lresult );/
(Bhandled );/
Switch (dwmsgmapid )/
{/
Case 0:

# Define alt_msg_map (msgmapid )/
Break ;/
Case msgmapid:

# Define message_handler (MSG, func )/
If (umsg = MSG )/
{/
Bhandled = true ;/
Lresult = func (umsg, wparam, lparam, bhandled );/
If (bhandled )/
Return true ;/
}

# Define message_range_handler (msgfirst, msglast, func )/
If (umsg> = msgfirst & umsg <= msglast )/
{/
Bhandled = true ;/
Lresult = func (umsg, wparam, lparam, bhandled );/
If (bhandled )/
Return true ;/
}

# Define command_handler (ID, code, func )/
If (umsg = wm_command & id = loword (wparam) & code = hiword (wparam ))/
{/
Bhandled = true ;/
Lresult = func (hiword (wparam), loword (wparam), (hwnd) lparam, bhandled );/
If (bhandled )/
Return true ;/
}

# Define command_id_handler (ID, func )/
If (umsg = wm_command & id = loword (wparam ))/
{/
Bhandled = true ;/
Lresult = func (hiword (wparam), loword (wparam), (hwnd) lparam, bhandled );/
If (bhandled )/
Return true ;/
}

# Define command_code_handler (Code, func )/
If (umsg = wm_command & code = hiword (wparam ))/
{/
Bhandled = true ;/
Lresult = func (hiword (wparam), loword (wparam), (hwnd) lparam, bhandled );/
If (bhandled )/
Return true ;/
}

# Define command_range_handler (idfirst, idlast, func )/
If (umsg = wm_command & loword (wparam)> = idfirst & loword (wparam) <= idlast )/
{/
Bhandled = true ;/
Lresult = func (hiword (wparam), loword (wparam), (hwnd) lparam, bhandled );/
If (bhandled )/
Return true ;/
}

# Define command_range_code_handler (idfirst, idlast, code, func )/
If (umsg = wm_command & code = hiword (wparam) & loword (wparam)> = idfirst & loword (wparam) <= idlast )/
{/
Bhandled = true ;/
Lresult = func (hiword (wparam), loword (wparam), (hwnd) lparam, bhandled );/
If (bhandled )/
Return true ;/
}

# Define policy_handler (ID, CD, func )/
If (umsg = wm_policy & id = (lpnmhdr) lparam)-> idfrom & Cd = (lpnmhdr) lparam)-> code )/
{/
Bhandled = true ;/
Lresult = func (INT) wparam, (lpnmhdr) lparam, bhandled );/
If (bhandled )/
Return true ;/
}

# Define policy_id_handler (ID, func )/
If (umsg = wm_policy & id = (lpnmhdr) lparam)-> idfrom )/
{/
Bhandled = true ;/
Lresult = func (INT) wparam, (lpnmhdr) lparam, bhandled );/
If (bhandled )/
Return true ;/
}

# Define policy_code_handler (Cd, func )/
If (umsg = wm_policy & Cd = (lpnmhdr) lparam)-> code )/
{/
Bhandled = true ;/
Lresult = func (INT) wparam, (lpnmhdr) lparam, bhandled );/
If (bhandled )/
Return true ;/
}

# Define policy_range_handler (idfirst, idlast, func )/
If (umsg = wm_policy & (lpnmhdr) lparam)-> idfrom> = idfirst & (lpnmhdr) lparam)-> idfrom <= idlast )/
{/
Bhandled = true ;/
Lresult = func (INT) wparam, (lpnmhdr) lparam, bhandled );/
If (bhandled )/
Return true ;/
}

# Define policy_range_code_handler (idfirst, idlast, CD, func )/
If (umsg = wm_policy & Cd = (lpnmhdr) lparam)-> code & (lpnmhdr) lparam)-> idfrom> = idfirst & (lpnmhdr) lparam)-> idfrom <= idlast )/
{/
Bhandled = true ;/
Lresult = func (INT) wparam, (lpnmhdr) lparam, bhandled );/
If (bhandled )/
Return true ;/
}

# Define chain_msg_map (thechainclass )/
{/
If (thechainclass: processwindowmessage (hwnd, umsg, wparam, lparam, lresult ))/
Return true ;/
}

# Define chain_msg_map_member (thechainmember )/
{/
If (thechainmember. processwindowmessage (hwnd, umsg, wparam, lparam, lresult ))/
Return true ;/
}

# Define chain_msg_map_alt (thechainclass, msgmapid )/
{/
If (thechainclass: processwindowmessage (hwnd, umsg, wparam, lparam, lresult, msgmapid ))/
Return true ;/
}

# Define chain_msg_map_alt_member (thechainmember, msgmapid )/
{/
If (thechainmember. processwindowmessage (hwnd, umsg, wparam, lparam, lresult, msgmapid ))/
Return true ;/
}

# Define chain_msg_map_dynamic (dynachainid )/
{/
If (cdynamicchain: callchain (dynachainid, hwnd, umsg, wparam, lparam, lresult ))/
Return true ;/
}

# Define end_msg_map ()/
Break ;/
Default :/
Atltrace (ATL: atltracewindowing, 0, _ T ("Invalid Message map ID (% I)/n"), dwmsgmapid );/
Atlassert (false );/
Break ;/
}/
Return false ;/
}

This macro will provide a specific processwindowmessage function to override the pure virtual function.

If there is a class like this:

Class test: Public cmessagemap
{

// When you write down this macro, you have provided a specific processwindowmessage function.

Begin_msg_map (test)

// Add the corresponding message ing

End_msg_map ()

}

Oh, so let's simulate this implementation!

// Msg
# Define own_msg_1 0x1
# Define own_msg_2 0x2
# Define own_msg_3 0x3
// Cmd
# Define own_1__1 0x4
# Define own_1__2 0x5
# Define own_1__3 0x6

Class cownmessagemap //
{
Public:
Virtual int defawinwinproc (unsigned int umsg, char * wparam, char * lparam) = 0; // key pure virtual functions
Void _ run ()
{
Int I = 0;
Char STR [3] = {0 };
While (1) // simulate getmsg
{
_ Sleep (1000 );
Sprintf (STR, "% d", I );
Defaultwinproc (I, STR, STR );
I ++;
If (I> 10)
Break;
}
}
};

# Define begin_own_map (theclass )/
Int defawinwinproc (unsigned int umsg, char * wparam, char * lparam )/
{/

# Define msg_handler (MSG, function )/
If (umsg = MSG )/
{/
Return function (wparam, lparam );/
}/

# Define handler _handler (MSG, function )/
If (umsg = MSG )/
{/
Return function (umsg, wparam, lparam );/
}/

# Define end_own_map ()/
Return 1 ;/
}

Class cownwnd: Public cownmessagemap
{
Begin_own_map (cownwnd)
Msg_handler (own_msg_1, onmsg1)
Msg_handler (own_msg_3, onmsg3)
Resource_handler (own_0000_1, oncmd1)
Resource_handler (own_0000_2, oncmd)
Resource_handler (own_rj_3, oncmd)
End_own_map ()
Int onmsg1 (char * WP, char * LP)
{
Printf ("MSG/t ");
Printf (WP );
Printf ("/N ");
Return 1;
}
Int onmsg3 (char * WP, char * LP)
{
Printf ("MSG/t ");
Printf (WP );
Printf ("/N ");
Return 1;
}
Int oncmd1 (unsigned int ID, char * WP, char * LP)
{
Printf ("command ID: % x/T", ID );
Printf ("CMD/t ");
Printf (WP );
Printf ("/N ");
Return 1;
}
Int oncmd (unsigned int ID, char * WP, char * LP)
{
Printf ("command ID: % d/T", ID );
Printf ("CMD/t ");
Printf (WP );
Printf ("/N ");
Return 1;
}
};

Int _ tmain (INT argc, _ tchar * argv [])
{
Cownwnd WND;
WND. _ run ();
Getchar ();
Return 0;
}

Running result:

MSG 1

MSG 3

Command ID: 4 cmd 4

Command ID: 5 cmd 5

Command ID: 6 cmd 6

Macros are worth learning for C/C ++ programmers.

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.