The blog has been migrated to: http://kulv.sinaapp.com /.
Kingsoft guard open source code-message mechanism analysis (I)
Address: http://download.csdn.net/source/3301518
Today, Kingsoft's open-source code is simplified for learning. Thanks to Kingsoft's open-source spirit, it's the easiest to get it directly. See the window. The key code is as follows, put all the code in the attachment. There is no detailed description of the tired Inheritance Mechanism in the analysis. In the function declaration, I will use the Son: public base: func () method. today, I mainly want to learn about its message mechanism and routing. I have never learned ATL, so I am wrong. I hope you can give me some advice ···
Thank you ···
//////////////////////////////////////// /// // <Br/> // main. CPP <br/> int winapi _ twinmain (hinstance, hinstance/* hprevinstance */, lptstr lpstr1_line, int ncmdshow) {<br/> If (failed (_ module. init (hinstance) <br/> return-1; <br/>: coinitializeex (null, coinit_apartmentthreaded); </P> <p> _ module. run (); <br/> _ module. uninit (); </P> <p>: couninitialize (); <Br/> return 0; <br/>}</P> <p> hresult kappmodule: Init (hinstance) {<br/> hresult HRET = _ super: Init (null, hinstance); <br/> If (failed (HRET) <br/> return HRET; <br/> return HRET; <br/>}< br/> hresult kappmodule: Run () {<br/> _ inituiresource (); // load various resources, from XML <br/> If (m_hmodrichedit2 = NULL) <br/> m_hmodrichedit2 =: loadlibrary (_ T ("RICHED20.DLL ")); <br/> // displayed dialog box <br/> ckulvdlg Wdlg; <br/> return wdlg. domodal (); <br/>}</P> <p> void kappmodule: _ inituiresource () {// load various resources from XML <br/> bkfontpool:: setdefaultfont (_ T (""),-12); <br/> bkskin: loadskins (idr_skin_def); <br/> bkstyle: loadstyles (idr_style_def ); <br/> bkstring: load (idr_string_def); <br/>}</P> <p> // DLG. h <br/> # pragma once <br/> class ckulvdlg <br/>: Public cbkdialogimpl <ckulvdlg> <br/>{< br/> public: <br/> ckulvdlg () <br />: Cbkdialogimpl <ckulvdlg> (idr_warming_dlg) {// idr_warming_dlg: 107, "res // warning_dlg.xml") <br/>}< br/> ~ Ckulvdlg (); <br/> protected: <br/> booloninitdialog (cwindow/* wndfocus */, lparam/* linitparam */); <br/> voidonbtnclose (); <br/> voidonbtnclicktext (); <br/> Public: <br/> bk_policy_map (idc_richview_win) <br/> bk_policy_id_command (100, onbtnclose) <br/> timeout (101, onbtnclicktext) <br/> bk_policy_map_end () </P> <p> begin_msg_map_ex (ckulvdlg) <br/> msg_bk_policy (idc_richview_win) <br/> chain_msg_m AP (cbkdialogimpl <ckulvdlg>) <br/> msg_wm_initdialog (oninitdialog) <br/> end_msg_map () </P> <p >}; <br/> // DLG. CPP <br/> # include "stdafx. H "<br/> # include" DLG. H "</P> <p> ckulvdlg ::~ Ckulvdlg () {<br/>}</P> <p> bool ckulvdlg: oninitdialog (cwindow/* wndfocus */, lparam/* linitparam */) {<br/> return true; <br/>}</P> <p> void ckulvdlg: onbtnclose () {<br/>__ super :: enddialog (idok); <br/>}</P> <p> void ckulvdlg: onbtnclicktext () {<br/> dontshowwindow (); <br/> cstring STR = cstring (_ file _); <br/> Str. format (text ("% s: % d"), str. getbuffer (), _ line _); <br/> MessageBox (STR); <br/>}< br/>
//////////////////////////////////////// /////////////////////////////////////////
/* Let's look at the macro replacement of the following message mechanism. It's easy to see that its cool image is the macro of MFC! At first, I still got an error */
Bk_policy_map (idc_richview_win) <br/> bk_policy_id_command (100, onbtnclose) <br/> bk_policy_id_command (101, onbtnclicktext) <br/> bk_policy_map_end ()
/* If the macro declaration is replaced, the following message allocation mechanism is added in the class, that is, the comparison is made based on the control IDs, and then the corresponding control's processing function is called, this function is specified during macro Shen Ming.
*/
Lresult ckulvdlg: onbknotify_1000 (lpnmhdr pnmh) {<br/> uint_ptr ucode = pnmh-> code; <br/> If (bknm_command = ucode & 100 = (lpbknmcommand) pnmh)-> uitemid) <br/>{< br/> onbtnclose (); <br/> return true; <br/>}< br/> If (bknm_command = ucode & 101 = (lpbknmcommand) pnmh)-> uitemid) <br/>{< br/> onbtnclicktext (); <br/> return true; <br/>}< br/> setmsghandled (false ); <br/> return false; <br/>}
//////////////////////////////////////// /// // <Br/> /// // <br/>/* in the dialog box, see the following macro Shen Ming to see what it is. */<br/> sort (ckulvdlg) <br/> msg_bk_1_y (idc_richview_win) <br/> chain_msg_map (cbkdialogimpl <ckulvdlg>) <br/> msg_wm_initdialog (oninitdialog) <br/> end_msg_map () </P> <p>/* is replaced with the following code: */<br/> // begin_msg_map_ex (ckulvdlg) <br/> Public: <br/> bool m_bmsghandled; <br/ >/* "Handled" management for Cracked handlers */<br/> bool ismsghandled () const {<br/> return m_bmsghandled; <br/>}< br/> void setmsghandled (bool bhandled) {<br/> m_bmsghandled = bhandled; // set the message processing status <br/>}< br/> bool processwindowmessage (hwnd, uint umsg, wparam, lparam, <br/> lresult & lresult, DWORD dwmsgmapid = 0) <br/> {// All message processing in this dialog box <br/> bool boldmsghandled = m_bmsghandled; <Br/> bool Bret = _ processwindowmessage (hwnd, umsg, wparam, lparam, lresult, <br/> dwmsgmapid); <br/> m_bmsghandled = boldmsghandled; <br/> return Bret; <br/>}< br/> bool _ processwindowmessage (hwnd, uint umsg, wparam, lparam <br/>, lresult & lresult, DWORD dwmsgmapid) <br/> {// The following figure shows the long message length. Compared with the complex MFC, <br/> bool bhandled = true; <br/> hwnd; <br/> umsg; <br/> wparam; <br/> lparam; <br/> lresu Lt; <br/> bhandled; <br/> switch (dwmsgmapid) <br/>{< br/> case 0: <br/> // msg_bk_policy (idc_richview_win) <br/> If (umsg = wm_policy & 1000 = (lpnmhdr) lparam)-> idfrom) <br/> {// step 1, if the message is advertised by the control, the message processing function is: <br/> // onbknotify_1000. Don't forget, as we mentioned above, there is also the control message ing <br/> // In fact, It is found one by one based on the ID. <Br/> setmsghandled (true); <br/> lresult = onbknotify_1000 (lpnmhdr) lparam); <br/> If (ismsghandled () <br/> return true; <br/>}< br/> // chain_msg_map (cbkdialogimpl <ckulvdlg>) <br/> If (cbkdialogimpl <ckulvdlg>: processwindowmessage (hwnd, umsg, wparam, lparam <br/>, lresult) <br/> return true; </P> <p> // process the parent class, I don't understand why do we have to deal with the parent class so early? Oh, it's okay. <br/> // msg_wm_initdialog (oninitdialog) <br/> If (umsg = wm_initdialog) <br/> {// In fact, the parent class does not process the wm_initdialog message, so it must have been uploaded here for custom initialization <br/> setmsghandled (true ); <br/> lresult = (lresult) oninitdialog (hwnd) wparam, lparam); <br/> If (ismsghandled () <br/> return true; <br/>}< br/> // msg_wm_initdialog (oninitdialog) <br/> break; <br/> default: // the user ID is incorrect, print the error message in the output window for debugging <br/> atltrace (ATL: atltraceindexing wing, 0, _ T ("Invalid Message map ID (% I)/n "), <br/> dwmsgmapid); <br/> atlassert (false); <br/> break; <br/>}// message "The Long March officially ended" <br/> return false; <br/>}
/* The message allocation method is cleared. Where is the driver? Right. Start from the source. The following functions are generally called in winmain, which is the main function. Others are initialization or something */
Hresult kappmodule: Run () <br/>{< br/> _ inituiresource (); // initialize various UI libraries or something, next, let's take a closer look at <br/> // how the Jinshan interface library is implemented in XML, but it should basically encapsulate various Win32 APIs <br/> If (m_hmodrichedit2 = NULL) <br/> m_hmodrichedit2 =: loadlibrary (_ T ("richedw.dll"); </P> <p> ckulvdlg wdlg; <br/> return wdlg. domodal (); <br/> // starting from here, our custom subclass generally does not redefine this function. To the parent class, see the following: </P> <p >}< br/> // cbkdialogimpl: Public c0000wimpl <t, tbase, twintraits> </P> <p> Uint_ptr cbkdialogimpl: domodal (hwnd hwndparent = NULL, lprect rect = NULL) <br/> {<br/> //... the words are omitted here. <br/> // the create function loads XML resources and sets the window or something, next, let's look at this part, focus on... <br/> hwnd = create (hwndparent, rect ); <br/> //... words omitted here <br/> _ modalmessageloop (); /// · See the following <br/> // · omitted here · words <br/> destroywindow (); <br/> return m_uretcode; <br/>}</P> <p> void cbkdialogimpl: _ modalmessageloop () <br/>{< br/> bool Bret; <br/> msg MSG; <br/> for (;) <br/> {// This cycle is long until wm_quit and break are received. <br/> If (:: peekmessage (& MSG, null, 0, 0, pm_noremove) <br/> {// What is the difference between peekmessage and getmessage? Yes, the latter is pervasive <br/> If (wm_quit = MSG. message) <br/> break; <br/>}< br/> // · <br/>: translatemessage (& MSG); <br/> :: dispatchmessage (& MSG); <br/>}< br/>}
/* This... infinite loop gets the message, which has already reached the API layer of the operating system. Which function is the specific dispatchmessage sent to for distribution ?? Yes, a masterpiece said, create, registerwindow, there must be a message-driven function, we have to tell the operating system, and it is a callback function, by the way, why is a callback function required? Can we call it directly in dispathmessage? · En, Hou Jie said that the operating system wants to have some control.
Next proceed */
/* Let's talk about it first. I haven't seen ATL and wtl, so I don't know which parts belong to the database. Now let's go to the root ···
After message tracking, it is found that each time the dispatchmessage is sent, the next User-Defined Function called is:
C:/program files/Microsoft Visual Studio 9.0/VC/atlmfc/include/atlwin. h:
Lresult callback cwindowimplbaset <tbase, twintraits>: windowproc (hwnd, uint umsg, wparam, lparam )*/
Template <class tbase, class twintraits> <br/> lresult callback cwindowimplbaset <tbase, twintraits> <br/>: startwindowproc (hwnd, uint umsg, wparam, lparam) <br/> {<br/> cwindowimplbaset <tbase, twintraits> * pthis = (cwindowimplbaset <tbase, twintraits> *) _ atlwinmodule. extractcreatewnddata (); <br/> // · <br/> pthis-> m_hwnd = hwnd; <br/> pthis-> m_thunk.init (pthis-> getwindowproc (), pthis); <br/> wndproc pproc = pthis-> callback (); <br/> wndproc poldproc = (wndproc): setwindowlongptr (hwnd, gwlp_wndproc, (long_ptr) pproc); <br/> // · <br/> return pproc (hwnd, umsg, wparam, lparam ); <br/>}< br/> virtual wndproc template <class tbase, class twintraits> <br/> lresult callback cwindowimplbaset <tbase, twintraits> <br/>: getwindowproc () {<br/> return windowproc; <br/>}
/* In fact, startwindowproc calls windowproc.
C:/program files/Microsoft Visual Studio 9.0/VC/atlmfc/include/atlwin. h:
Lresult callback cwindowimplbaset <tbase, twintraits>: windowproc (hwnd, uint umsg, wparam, lparam)
Windowproc, right. We are very familiar with this function name !!
Right, we can see that startwindowproc must be the callback function we are looking for. The callback will not tell us. Haha, its statement is static:
Static lresult callback startwindowproc (hwnd, uint umsg, wparam, lparam );
Paste the following code:
*/
Template <class tbase, class twintraits> <br/> lresult callback cwindowimplbaset <tbase, twintraits >:: windowproc (hwnd, uint umsg, wparam, lparam) <br/> {<br/>/* forcibly converts a window handle to a base class pointer. Why? First, should this window handle be the first address of the window class? <Br/> This is the implementation method of the window system. Many handles are actually virtual addresses */<br/> cwindowimplbaset <tbase, twintraits> * pthis = (cwindowimplbaset <tbase, twintraits> *) hwnd; <br/> // · a few lines are omitted here <br/>/* Note that processwindowmessage is a virtual function, <br/> SO · actually called is our custom window class !! Therefore, the message routing goes to our ckulvdlg. <br/> the macro expansion mentioned above. However, I have to mention that the message will be moved step by step from ckulvdlg to the base class <br/> as long as the message is not processed, if it is really lucky, it has not been processed yet, then return... */<br/> bool Bret = pthis-> processwindowmessage (pthis-> m_hwnd, umsg, wparam, lparam, lres, 0 ); <br/> // · <br/> If (! Bret) <br/> {// if the message has not been processed, enter defwindowproc. If it is not wm_ncdestroy <br/> If (umsg! = Wm_ncdestroy) <br/> lres = pthis-> defwindowproc (umsg, wparam, lparam ); <br/> else <br/> {// The following preparation exits <br/> // unsubclass, if needed <br/> long_ptr pfnwndproc = :: getwindowlongptr (pthis-> m_hwnd, gwlp_wndproc); <br/> lres = pthis-> defwindowproc (umsg, wparam, lparam); <br/> If (pthis-> m_pfnsuperwindowproc! =: Defwindowproc &: getwindowlongptr (pthis-> m_hwnd, gwlp_wndproc) = pfnwndproc) <br/>: setwindowlongptr (pthis-> m_hwnd, callback, (long_ptr) pthis-> m_pfnsuperwindowproc); <br/> // mark window as destryed <br/> // the above comment is not written by me, the ATL designer accidentally wrote destroyed wrong. Haha · <br/> pthis-> m_dwstate | = winstate_destroyed; <br/>}< br/> // · <br/> return lres; <br/>}< br/>/* It is worth noting that processwindowmessage is a virtual function. <B R/>? Virtual is not written in the macro definition, but the base class is enough. <br/> the base class cbkwindow contains the following macro definition, which is indeed a virtual function. */<Br/> class cbkwindow bkwin_begin_msg_map (): Public cbkobject <br/> # define bkwin_begin_msg_map ()/<br/> protected: /<br/> virtual bool processwindowmessage (/<br/> hwnd, uint umsg, wparam,/<br/> lparam, lresult & lresult) /<br/> {
/* The Reader basically understands the message ing route. But it always feels awkward. Why is the message processing function startwindowproc ??? Who told windows? How do I know the operating system ?? Let's continue: If you remember correctly, we mentioned domodal as follows:
Hwnd = create (hwndparent, rect );
//... Omitted here. I intentionally omitted many words ···
Let's add the following code.
*/
See http://blog.csdn.net/hw_henry2008/archive/2011/05/22/6438183.aspx below