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.