windows消息处理(强烈推荐,收藏)
2012-08-22 17:30
387 查看
由于看了一下,比较好理解,暂时先放到这里,待有空再翻译。只是在每节后大致介绍一下讲的内容。
感觉写的比较全,无论从消息的原理还是从MFC操作上来说,值得一看,我也在此做个收藏。
(一)
说明:以下首先对消息进行介绍,然后在消息处理中,使用类向导创建消息循环,这个操作是在vc6.0(或者之下版本)操作的。
TheWindowsconceptisdifferent.Thewayyouprograminwindowsisbyrespondingtoevents.Theseeventsarecalledmessages.
Messagescansignalmanyevents,causedbytheuser,theoperatingsystem,oranotherprogram.Aneventcouldbecausedbyamousemove,akey-press,orbyyourwindowgettingresized.Thereare2kindsofmessages:awindowmessage,orathreadmessage.
SinceThreadsareanadvancedissue,I'llreferonlytowindowmessages.
afunctiondesignedtohelptheMessageLoopatprocessingthemessage.
TheMessageLoopwillendwhena
closebutton(theXsmallbuttonintheupperrightcornerofyourwindow),orpressedAlt+F4.WindowshasdefaultMessageHandlersforalmostallthemessages,givingyourwindowthedefaultwindowbehavior.Infact,allthestandardcontrolsaresimplywindows
withMessagehandlers.TakeaButtonforexample.Whenitgetsa
message,anditdrawsthepressed-button.Whenyouletgoofthemousebuttonitreceivesa
Windowsdefinesmanydifferentmessagetypes(whicharestoredasUINTs).Theyusuallybeginwiththeletters"WM"andanunderscore,asin
Thenamesofthemessageareusuallyagoodindicatorofwhattheyrepresent.
messagesandsoon.ThenamingconventioninMFCformessagehandlerfunctionsistotakeawaythe"WM_"andreplaceitwith"On",sothemessagehandlerfor
Amessagecomeswith2parametersthatgiveyoumoreinformationabouttheevent.Eachparameterisa32-bitvalue:lParamandwParam.Forexample:
inoneparamter,andintheothersomeflagsindicatingthestateoftheALT,Shift,CTRLandmousebuttons.
AMessagemayalsoreturnavaluewhichallowsyoutosenddatabacktothethesendingprogram.Forexample,the
youtoreturnaBooleanvalue.Ifyourapplicationcanterminateconveniently,itshouldreturnTRUE;otherwise,itshouldreturnFALSE.Othermessagesuchasthe
toreturnan
Note:IntherestofthetutorialIwillfocusonMFCforsimplicityreasons.AlltheinformationaboveappliestobothSDKprograms,andMFCprograms.
window.TheonlythingyouneedtodosoyoucanreceivemessagesistocreateMessageHandlers,andinformMFCofthem.So,howdoyoucreateaMessageHandler?OnceyouhaveanMFCC++classthatencapsulatesawindow,youcaneasilyuseClassWizardtocreate
MessageHandlers.
item(formessagescausedbytheuserinteractingwithamenu),theIDofacontrol(formessagescausedbytheuserinteractingwithacontrol),orthefirstoptiontohandlemessagesothermessages.ChoosethemessagefromtheMessageslist,
forexample,andClickonAddFunction.ClickOK,thenclickEditCode.ClassWizardwillwriteanewemptyfunction(
generatedshouldlooksimilartothis:
That'sit,nowyoucanhandlemessages.Ifyouwanttohandleamessageandthenletthedefaultmessagehandlerhandlethemessage,youshouldcallthebaseclassmemberfunctionthatcorrespondswiththemessage.Takethefollowing
MessageHandlerasanexample:
Ifyouwantwindowstogetashotatthemessage,youshouldcallthebaseclassmemberfunctionOnClose:
Youcouldusethisbehaviortoscreen-outevents.Forexample,aprogramthatpromptstheuserifheissurethathewantstoclosethewindow:
ac++windowclass.Thiscanberetrievedusingvariousfunctions,including
memberfunctionwhichallowsyoutosendmessagestoit'swindow.Forexample,Let’ssayyouhaveaCWndpointertotheCalculator,andyouwanttocloseit.Whatyoushoulddoissenda
functionandpassthetitleofthewindow,whichinourcaseis"Calculator".
(二)
MFCusesatechniquecalledMessageMaps.AMessageMapisatablethatassociatesmessageswithfunctions.Whenyoureceiveamessage,MFCwillgothroughyourMessageMapandsearchforacorrespondingMessageHandler.IhaveshowedinPart1howyouadd
aMessageHandlertotheMessageMapbyusingClassWizard,butwhatreallyhappenscode-wise?
MFCusesalargesetofrathercomplicatedmacrosthataddtheMessageMaptoyourclasses.WhenyouuseClassWizardtocreateaMessageHandler,itwillfirstaddthefunctiontoyourclass,andaddthecorrespondingmacrotoyourMessageMap.Forexample,
examinethefollowingClassWizardgenerated
Byaddinga
tellsMFCwheretheMessageMapbegins,andidentifiesyourclassandit'sbaseclass.ThereasonitneedsthebaseclassisbecauseMessageHandlersarepassedthroughc++inheritance,justlikeanyotherfunction.
obviously,tellsMFCwheretheMessageMapends.InbetweenthesetwomacrosiswhereyourdeclaretheMessageMapentryforyourMessageHandler.MFChasmanypredefinedmacros,whichassociatemessageswithyourmemberfunction.Takethethe
macroasanexample:Itassociatesthe
alwaysexpectsafunctioncalled
ItiseasytokeeptrackofMessageHandlersandthemessagestheyhandle
MFCscreensoutanyirrelevantandwillbreakuplParamandwParamtoparametersrelevanttothemessage.
Alsothereturnvalueissimplified,andtheMessageHandlerisprototypedaccordingtothemessage.Forexample:Ifthevalueshouldalwaysbezero,MFCsimplifiestheprocessandallowsyoutodeclarethefunctionasa
andMFCwillberesponsibleforreturning0.TofindthenameofthemessagehandlerthatcorrelateswithagivenMessageHandlermacroyoushouldlookitupintheMFCdocumentation.
TherearesomemessagesthatClassWizarddoesn'tsupport,butyoucanmanualyaddyourmessagehandlerbyaddingthefunctionandMessageMapmacroasdescribedabove.Ifyouaddmessage-mapentriesmanually,youmaynotbeabletoeditthemwithClassWizard
later.Ifyouaddthemoutsidethebracketingcomments
atall.NotethatbythesametokenClassWizardwillnottouchanyentriesyouaddoutsidethecomments,sofeelfreetoaddmessagesoutsidethecommentsifyoudonotwantthemtobemodified.MessagesthatarenotrecognizedbyClassWizard,suchasmessage-map
ranges,mustbeaddedoutsidethecomments.
allowsyoutohandleanymessagethatexists.TheprototypeofMessageHandlersthatuse
where
themessageitshouldhandle.Forexample:ThefollowingstatementMaps
messageandnottheuserofyourprogram.IhavestatedinPart1thatmessagesareidentifiedbynumbers,andthatWindowspredefinesstandardmessages.Thewayofusingpredefinedmessagesistosimplyuseanumber.Tomakesurethatyoudon'tconflictwith
thesystemdefinedmessagesyoushoulduseanumberintherangeof
Handlingauser-definedmessageisdonewiththe
isusedtohandlethesemessages.Thismacroacceptsanameofa
Therangeofuserdefinedmessagesusingthisapproachwillbeintherange0xC000to0xFFFF.Andyousenditusingtheregular
(三)
说明:这部分才是消息处理的底层部分,前面MFC只是在这部分之上包了一层,所以你在那层看不到消息处理的本质。
HandlingmessagesinSDKapplicationsisatotallydifferentprocessthanMFC.NoClassWizardormacrostohelpyou.No
aWindowClassthatdefinestheattributesofawindowsuchasthewindow'sicon,thewindow'sbackgroundandthewindow'sprocedure.TocreateaWindowclass,youcall
a
calledin
Usually,theMessageLoopisimplementedasabasic
The
parametersthatcomewiththemessage,thetimeatwhichthemessagewassent,andthepositionofthemousewhenthemessagewassent.
Thecallto
willnotreturnuntilthereis.Thereturnvaluefrom
itwillreturn
functiontranslatesvirtual-keymessagesintocharactermessages.Thecharactermessagesarepostedtothecallingthread'sMessageQueue,tobereadthenexttimethethreadcallsthe
function.Forexample,ifyougeta
messagetoyourMessageQueue.Thisisveryusefulbecausethe
for
ifitshouldbecapitalforyou.Thecallto
AWindowProcedureisafunctioncalledbytheMessageLoop.Wheneveramessageissenttoawindow,theMessageLooplooksatthewindow'sWindowClassandcallstheWindowProcedurepassingthemessage'sinformation.AWindowProcedureisprototypedas:
The
isthemessageidentifier,andthelast2parametersaretheparameterssentwiththemessage.
Typically,aWindowProcedureisimplementedasasetof
The
parameterandrunsthecorrespondingmessagehandler.The
toreturn
as
thetargetwindow.Thiscanberetrievedusingavarietyoffunctions,including
functionwhichallowsyoutosendmessagestoawindow.Forexample,let'ssayyouhaveahandletotheCalculator,andyouwanttocloseit.Whatyoushoulddoissenda
willnotifytheCalculatorthatitshouldclose.Youcanusethefollowingcode.InordertogetapointertoCalculator,Iusethe
inourcaseis"Calculator":
message.MSDNstatesthatthe
TheSDKhas2macrosdesignedforexactlythispurpose:
an
parameterinamessage?TheSDKhas2macrosforthissituationalso:
a32-bitvalue,thatisusableformessages.Forexample,thefollowingcodesendsa
withthe
usingoneofthe
DialogProcedureisprototypedas:
YoumighthavenoticedthattheDialogProcedurelooksverysimilartotheWindowProcedure,butitisn'tarealWindowProcedure.TheWindowProcedureforthedialogislocatedinsidewindows.ThatWindowProcedurecallsyourDialogProcedurewhenvarious
messagesaresenttoyourwindow.Becauseoftheabove,therearemessagesthatyouwillreceiveinaWindowProcedurethatyouwon'treceiveinaDialogProcedure.ThereareafewmajordifferencesbetweenaWindowProcedureandaDialogProcedure:
ADialogProcedurereturnsa
ADialogProceduredoesn'tneedtohandle
ADialogProceduredoesn'treceivea
AWindowProcedurecalls
themessageor
messageandnottheuserofyourprogram.IhavestatedinPart1thatmessagesareidentifiedbynumbers,andthatWindowspredefinesstandardmessages.Thewayofusinguser-definedmessagesistosimplyuseanumber.Tomakesurethatyoudon'tconflict
withthesystemdefinedmessages,youshoulduseanumberintherangeof
Youhandleauser-definedmessagejustlikeyouhandlearegularmessage:
regularmessages:
Theregisteredmessageidentifiersusingthisapproachwillbeintherangeof0xC000to0xFFFF.Andyousenditusingtheregular
(四)
这部分没研究,可以看看,原文:http://www.codeproject.com/Articles/600/Windows-Message-Handling-Part-4
windowprocedure.Iwilldevidethisarticleinto3:
screenoutcharactersfromaneditcontrol?".IwillshowthesolutiontothisfromanMFCapproachandfromanSDKapproach,whileItrytoexplainSubclassing.
TheneedforsubclassingcomesfromthefactthatthecodefortheWindowscontrolsiswithinWindows,meaningyoucannoteditthecode.Althoughyoucannoteditthecodeofthecontrolitself,youinterceptthemessagessenttoit,andhandlethemyour
self.Youdosobysubclassingthecontrol.SubclassinginvolvesreplacingtheMessageHandlersofthecontrol,andpassinganyunprocessedmessagetothecontrolsMessageHandler.
identifier.Likewise,youcancall
anymessageitgets.SubclassingistheWindowstermforreplacingtheWindowProcedureofawindowwithadifferentWindowProcedureandcallingtheoldWindowProcedurefordefault(superclass)functionality.Remember
insteadofcalling
that,wecansimplysubclasstheeditcontrol,andinterceptthe
likespacebarorbackspacewe'llpassthemessagetotheeditcontrol.Ifitisn'toneoftheabove,we'lljust"Swallow"themessage,blockingitfromreachingtheEditControl.
Thefirststeptosubclassingistoaddaglobal/static
ThesecondstepistocreateanewWindowProcedurefortheeditcontrol:
The
ControlPanel.
Moreinterestingisthe
Procedure.Acallto
ThethirdstepistoreplacetheWindowProcedurefortheeditcontrol,andtostoretheoldoneing_OldEdit.Forexample,ifyouwanttosubclassaneditcontrolthatresidesinadialog(hDlg)andhastheIDof
youwouldusethefollowingcode:
Thecontrolisnowsubclassed.Anymessagetotheeditcontrolwillfirstgothroughthe
Procedure.
clickon"AddClass",then"New".Forthebaseclass,choosetheMFCControlclassyouarederivingfrom,inourcase,
UsingMFCrelievesyoufromhavingtocalltheoldMessageHandlers,sinceMFCwilltakecareofitforyou.
ThesecondstepistoaddMessageHandlerstoyournewclass.Ifyouhandleamessageandyouwantthecontrol'smessagehandlertogetashotatit,youshouldcallthebaseclassmemberfunctionthecorrespondswiththemessage.thisisthesubclassed
handler:
Thethirdandfinalstageistoassociatethewindowwithaninstanceofournewclass.InadialogthisisdonesimplybyusingClassWizardtocreateacontrolmembervariableofyourclassinthewindow'sparent,andassociateitwiththe
control.
Inanon-dialogparentyoushouldaddamembervariableinstanceofyourcontroltoit,andcalloneofthetwo
takesthe
designedforattachingC++objectstodialogcontrolscreatedfromadialogtemplate.
Createyourowncontrols-theartofsubclassing".
example,aButtonwillsenda
thecontrolitself.InClassWizardthesemessagesappearwithan"="signbeforethem,indicatingtheyareReflectedMessages.Youhandlethemjustlikeanyothermessage.Themacrosforthesemessagesaresimilartotheregularmessages,buthave
addedtotheendofthemacro.Forexample,
感觉写的比较全,无论从消息的原理还是从MFC操作上来说,值得一看,我也在此做个收藏。
(一)
说明:以下首先对消息进行介绍,然后在消息处理中,使用类向导创建消息循环,这个操作是在vc6.0(或者之下版本)操作的。
Introduction
PerhapsoneofthemostimportantmeansofcommunicationinwindowsisMessages.Thetraditionalprogramstartsatyourmain()function,movesdownline-by-lineinyourcode,andeventuallyexits.
TheWindowsconceptisdifferent.Thewayyouprograminwindowsisbyrespondingtoevents.Theseeventsarecalledmessages.
Messagescansignalmanyevents,causedbytheuser,theoperatingsystem,oranotherprogram.Aneventcouldbecausedbyamousemove,akey-press,orbyyourwindowgettingresized.Thereare2kindsofmessages:awindowmessage,orathreadmessage.
SinceThreadsareanadvancedissue,I'llreferonlytowindowmessages.
WindowMessages:
Ingeneral,amessagemustbesenttoawindow.AllthemessagessenttoyouarestoredinaMessageQueue,aplaceinthememorywhichstoresmessagewhicharetransferredbetweenapplications.MessageLoop:
thewayyouretrievemessagesfromtheMessageQueueisbycreatingaMessageLoop.AMessageLoopisaloopthatchecksformessagesintheMessageQueue.onceamessageisreceived,theMessageLoopdispatchesthemessagebycallingaMessageHandler,afunctiondesignedtohelptheMessageLoopatprocessingthemessage.
TheMessageLoopwillendwhena
WM_QUITmessageisreceived,signalingtheapplicationtoend.ThismessagecouldbesentbecausetheuserselectedExitfromyourFilemenu,clickedonthe
closebutton(theXsmallbuttonintheupperrightcornerofyourwindow),orpressedAlt+F4.WindowshasdefaultMessageHandlersforalmostallthemessages,givingyourwindowthedefaultwindowbehavior.Infact,allthestandardcontrolsaresimplywindows
withMessagehandlers.TakeaButtonforexample.Whenitgetsa
WM_PAINTmessageitwilldrawthebutton.WhenyouLeft-clickthebutton,itgetsa
WM_LBUTTONDOWN
message,anditdrawsthepressed-button.Whenyouletgoofthemousebuttonitreceivesa
WM_LBUTTONUPmessage,andrespectivelydrawsthebutton.
Windowsdefinesmanydifferentmessagetypes(whicharestoredasUINTs).Theyusuallybeginwiththeletters"WM"andanunderscore,asin
WM_CHARand
WM_SIZE.
Thenamesofthemessageareusuallyagoodindicatorofwhattheyrepresent.
WM_SIZEforsizingmessages,
WM_CHARforcharacterentry
messagesandsoon.ThenamingconventioninMFCformessagehandlerfunctionsistotakeawaythe"WM_"andreplaceitwith"On",sothemessagehandlerfor
WM_SIZEisusuallycalled
OnSize.
Amessagecomeswith2parametersthatgiveyoumoreinformationabouttheevent.Eachparameterisa32-bitvalue:lParamandwParam.Forexample:
WM_MOUSEMOVEwillgiveyouthemousecoordinates
inoneparamter,andintheothersomeflagsindicatingthestateoftheALT,Shift,CTRLandmousebuttons.
AMessagemayalsoreturnavaluewhichallowsyoutosenddatabacktothethesendingprogram.Forexample,the
WM_QUERYENDSESSIONmessagesentbywindowsbeforethecomputerisshutdown,expects
youtoreturnaBooleanvalue.Ifyourapplicationcanterminateconveniently,itshouldreturnTRUE;otherwise,itshouldreturnFALSE.Othermessagesuchasthe
WM_CTLCOLORmessagesexpectyou
toreturnan
HBRUSH.
Note:IntherestofthetutorialIwillfocusonMFCforsimplicityreasons.AlltheinformationaboveappliestobothSDKprograms,andMFCprograms.
MessageHandlers:
Fortunately,MFCwillgiveallthecodeneededforthemessageloop,OneoftheCWinAppmemberfunctionscalledbyWinMain—Run—providesthemessageloopthatpumpsmessagestotheapplication's
window.TheonlythingyouneedtodosoyoucanreceivemessagesistocreateMessageHandlers,andinformMFCofthem.So,howdoyoucreateaMessageHandler?OnceyouhaveanMFCC++classthatencapsulatesawindow,youcaneasilyuseClassWizardtocreate
MessageHandlers.
UsingClassWizardtocreateMessageHandlers:
PressCtrl+WtostarttheClassWizard,orrightclicktheAddbuttonandselectClassWizardfromthecontextmenu.OpenClassWizard,selectMessageMapstab.InClassnameselectthenameofyourC++class.onObjectIDsselecteithertheIDofamenuitem(formessagescausedbytheuserinteractingwithamenu),theIDofacontrol(formessagescausedbytheuserinteractingwithacontrol),orthefirstoptiontohandlemessagesothermessages.ChoosethemessagefromtheMessageslist,
WM_SIZE
forexample,andClickonAddFunction.ClickOK,thenclickEditCode.ClassWizardwillwriteanewemptyfunction(
OnSizeforexample)withtheproperprototypeintheclassheader.Thecode
generatedshouldlooksimilartothis:
voidCAboutWindow::OnSize(UINTnType,intcx,intcy) { CDialog::OnSize(nType,cx,cy); //TODO:Addyourmessagehandlercodehere //Hereiswhereyoucanresizecontrolsinyourwindow,change //thesizeofabitmapinit,ordowhateveryoucanthinkof. }
That'sit,nowyoucanhandlemessages.Ifyouwanttohandleamessageandthenletthedefaultmessagehandlerhandlethemessage,youshouldcallthebaseclassmemberfunctionthatcorrespondswiththemessage.Takethefollowing
WM_CLOSE
MessageHandlerasanexample:
voidCAboutWindow::OnClose() { //TheUseroranotherprogramistryingtocloseourwindow... //Ifyoudon'taddcodetoclosethewindow,yourwindowwillneverclose }
Ifyouwantwindowstogetashotatthemessage,youshouldcallthebaseclassmemberfunctionOnClose:
voidCAboutWindow::OnClose() { MessageBox(_T("Closingthewindow!")) //CalltheBaseclassmemberfunction,whichwillclosethewindow. CWnd::OnClose() }
Youcouldusethisbehaviortoscreen-outevents.Forexample,aprogramthatpromptstheuserifheissurethathewantstoclosethewindow:
voidCAboutWindow::OnClose() { intRet=MessageBox(_T("Areyousureyouwanttoclosethewindow?"), _T("CloseWindow?"),MB_YESNO); if(Ret==IDYES){ //TheUserissure,closethewindowbycallingthebaseclass //member CWnd::OnClose() } else{ //Theuserpressedno,screenoutthemessagebynotcalling //thebaseclassmember //Donothing } }
SendingMessages:
Besidesreceivingmessages,youwilloftenfindyourselfsendingmessages.Youmightwanttosendmessagestocommunicatebetweentowindowsinyourprogram,ortocommunicatebetweendifferentprograms.Inordertosendamessageyouneedapointertoac++windowclass.Thiscanberetrievedusingvariousfunctions,including
CWnd::FindWindow,GetDlgItem(),GetParent(),andmore.The
CWndclasshasa
SendMessage()
memberfunctionwhichallowsyoutosendmessagestoit'swindow.Forexample,Let’ssayyouhaveaCWndpointertotheCalculator,andyouwanttocloseit.Whatyoushoulddoissenda
WM_CLOSEmessage,whichwillnotifytheCalculatorthatitshouldclose.Youcanusethefollowingcode.InordertogetapointertoCalculator,Iusethestatic
CWnd::FindWindow()
functionandpassthetitleofthewindow,whichinourcaseis"Calculator".
CWnd*pCalc; //Getapointertothe"Calculator"Window pCalc=CWnd::FindWindow(NULL,_T("Calculator)); if(pCalc==NULL){ //Couldn'tfindCalculator } else{ pCalc->SendMessage(WM_CLOSE); //Presto!TheCalculatorshouldclose. }
(二)
HowdoMFCmessagehandlerswork?
Wheneveryourwindowreceivesamessage,MFCwillcallamemberfunctionofyourclass.ButhowdoesMFCknowwhatfunctiontocall?MFCusesatechniquecalledMessageMaps.AMessageMapisatablethatassociatesmessageswithfunctions.Whenyoureceiveamessage,MFCwillgothroughyourMessageMapandsearchforacorrespondingMessageHandler.IhaveshowedinPart1howyouadd
aMessageHandlertotheMessageMapbyusingClassWizard,butwhatreallyhappenscode-wise?
MFCusesalargesetofrathercomplicatedmacrosthataddtheMessageMaptoyourclasses.WhenyouuseClassWizardtocreateaMessageHandler,itwillfirstaddthefunctiontoyourclass,andaddthecorrespondingmacrotoyourMessageMap.Forexample,
examinethefollowingClassWizardgenerated
WM_CLOSEhandler:
第一步:消息映射---MessageMap:locatedintheclassimplementation
BEGIN_MESSAGE_MAP(CAboutDlg,CDialog) //{{AFX_MSG_MAP(CAboutDlg) ON_WM_CLOSE() //}}AFX_MSG_MAP END_MESSAGE_MAP()
第二步:函数声明---FunctionDeclaration:locatedintheclassdeclaration.
protected: //{{AFX_MSG(CAboutDlg) afx_msgvoidOnClose(); //}}AFX_MSG DECLARE_MESSAGE_MAP()
第三步:函数执行---FunctionImplementation:locatedintheclassimplementation
voidCAboutDlg::OnClose() { //TODO:Addyourmessagehandlercodehereand/orcalldefault CDialog::OnClose(); }
Byaddinga
DECLARE_MESSAGE_MAPstatementtotheclassdeclaration,MFCaddstherequiredcodetodeclarethemessagemap.The
BEGIN_MESSAGE_MAP
tellsMFCwheretheMessageMapbegins,andidentifiesyourclassandit'sbaseclass.ThereasonitneedsthebaseclassisbecauseMessageHandlersarepassedthroughc++inheritance,justlikeanyotherfunction.
END_MESSAGE_MAP
obviously,tellsMFCwheretheMessageMapends.InbetweenthesetwomacrosiswhereyourdeclaretheMessageMapentryforyourMessageHandler.MFChasmanypredefinedmacros,whichassociatemessageswithyourmemberfunction.Takethethe
ON_WM_CLOSE
macroasanexample:Itassociatesthe
WM_CLOSEmessagewithyour
OnClose()memberfunction.Themacrotakesnoparameterssinceit
alwaysexpectsafunctioncalled
OnClose()whichisprototypedas
afx_msgvoidOnClose().Thismethodgivesyou2advantages:
ItiseasytokeeptrackofMessageHandlersandthemessagestheyhandle
MFCscreensoutanyirrelevantandwillbreakuplParamandwParamtoparametersrelevanttothemessage.
Alsothereturnvalueissimplified,andtheMessageHandlerisprototypedaccordingtothemessage.Forexample:Ifthevalueshouldalwaysbezero,MFCsimplifiestheprocessandallowsyoutodeclarethefunctionasa
void,
andMFCwillberesponsibleforreturning0.TofindthenameofthemessagehandlerthatcorrelateswithagivenMessageHandlermacroyoushouldlookitupintheMFCdocumentation.
TherearesomemessagesthatClassWizarddoesn'tsupport,butyoucanmanualyaddyourmessagehandlerbyaddingthefunctionandMessageMapmacroasdescribedabove.Ifyouaddmessage-mapentriesmanually,youmaynotbeabletoeditthemwithClassWizard
later.Ifyouaddthemoutsidethebracketingcomments
//{{AFX_MSG_MAP(classname)and
//}}AFX_MSG_MAP,ClassWizardcannoteditthem
atall.NotethatbythesametokenClassWizardwillnottouchanyentriesyouaddoutsidethecomments,sofeelfreetoaddmessagesoutsidethecommentsifyoudonotwantthemtobemodified.MessagesthatarenotrecognizedbyClassWizard,suchasmessage-map
ranges,mustbeaddedoutsidethecomments.
TheallmightyON_MESSAGE
SometimesyouwillfindyourselftryingtohandleamessagethatClassWizarddoesn'tsupport,anditdoesn'thaveaMessageMapmacro.MFChasagenericmacrojustforthiskindofsituationON_MESSAGE.
ON_MESSAGE
allowsyoutohandleanymessagethatexists.TheprototypeofMessageHandlersthatuse
ON_MESSAGEis
afx_msgLRESULTOnMessage(WPARAMwParam,LPARAMlParam);
where
OnMessageisthenameofyourhandlerfunction.The
ON_MESSAGEmacrotakes2parameters:Theaddressofthehandler,and
themessageitshouldhandle.Forexample:ThefollowingstatementMaps
WM_GETTEXTLENGTHto
OnGetTextLength():
ON_MESSAGE(WM_GETTEXTLENGTH,OnGetTextLength)
OnGetTextLengthisprototypedas
afx_msgLRESULTOnGetTextLength(WPARAMwParam,LPARAMlParam);
说明:以上部分还是接第一部分的类向导,通过ctrl+w快捷键进入,选择之后,vc6会自动把上文标注的三步骤放到相应的位置,下边自定义的消息(在类向导中没有的消息,自己定义的消息),则可以参考上文的三步骤,在和它们对应的位置添加,注意这个需要定义一个消息宏(下面红色标注),WM_APP现在应该为WM_USER,自定义消息只需要在WM_USER之上加上一个数字,因为一般WM_USER之前的消息,是系统消息(ctrl+w中看到的鼠标点击消息、键盘消息】重绘消息等)。
User-definedmessages
Sometimes,youwillneedtocommunicatebetween2windowsinyourapplicationorbetween2windowsfromdifferentapplications.AneasywaytodothisisbyusingUser-definedmessages.Thename"User-defined"canbeconfusingatfirst;youdefineaUser-definedmessageandnottheuserofyourprogram.IhavestatedinPart1thatmessagesareidentifiedbynumbers,andthatWindowspredefinesstandardmessages.Thewayofusingpredefinedmessagesistosimplyuseanumber.Tomakesurethatyoudon'tconflictwith
thesystemdefinedmessagesyoushoulduseanumberintherangeof
WM_APPthrough0xBFFF:
#defineWM_DELETEALLWM_APP+0x100
//...
pYourDialog->SendMessage(WM_DELETEALL,0,0);
Handlingauser-definedmessageisdonewiththe
ON_MESSAGEmacro:
#defineWM_DELETEALLWM_APP+0x100
//...
//MessageMapentry:
ON_MESSAGE(WM_DELETEALL,OnDeleteAll)
//OnDeleteAllisprototypedas
afx_msgLRESULTOnDeleteAll(WPARAMwParam,LPARAMlParam);
//Andisimplementedas
LRESULTOnDeleteAll(WPARAMwParam,LPARAMlParam){
//DoWhateveryouwant
returnsomevalue;
}
RegisteredWindowsMessages
TheRegisterWindowMessagefunctionisusedtodefineanewwindowmessagethatisguaranteedtobeuniquethroughoutthesystem.Themacro
ON_REGISTERED_MESSAGE
isusedtohandlethesemessages.Thismacroacceptsanameofa
UINTvariablethatcontainstheregisteredWindowsmessageID.Forexample:
classCMyWnd:publicCMyParentWndClass
{
public:
CMyWnd();
//{{AFX_MSG(CMyWnd)
afx_msgLRESULTOnFind(WPARAMwParam,LPARAMlParam);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
staticUINTWM_FIND=RegisterWindowMessage("YOURAPP_FIND_MSG");
BEGIN_MESSAGE_MAP(CMyWnd,CMyParentWndClass)
//{{AFX_MSG_MAP(CMyWnd)
ON_REGISTERED_MESSAGE(WM_FIND,OnFind)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
Therangeofuserdefinedmessagesusingthisapproachwillbeintherange0xC000to0xFFFF.Andyousenditusingtheregular
SendMessage()method:
staticUINTWM_FIND=RegisterWindowMessage("YOURAPP_FIND_MSG");
//...
pFindWindow->SendMessage(WM_FIND,lParam,wParam);
(三)
说明:这部分才是消息处理的底层部分,前面MFC只是在这部分之上包了一层,所以你在那层看不到消息处理的本质。
HandlingMessagesinSDKapplications
ThisarticleassumesyouarefamiliarwithcreatingawindowinanSDKprogram.TheDialogpartassumesyouarefamiliarwithcreatingmodalandmodelessdialoginaSDKprogram.HandlingmessagesinSDKapplicationsisatotallydifferentprocessthanMFC.NoClassWizardormacrostohelpyou.No
CWinApptoimplementtheMessageLoopforyou.It'salluptoyou.
WindowsClassesandWindowProcedures
Window"classes"intraditionalprogrammingforWindowsdefinethecharacteristicsofa"class"(notaC++class)fromwhichanynumberofwindowscanbecreated.Thiskindofclassisatemplateormodelforcreatingwindows.InWindows,everywindowhasaWindowClassthatdefinestheattributesofawindowsuchasthewindow'sicon,thewindow'sbackgroundandthewindow'sprocedure.TocreateaWindowclass,youcall
RegisterClassthataccepts
a
WNDCLASSstructuredefiningthepropertiesoftheWindowclass.Everywindowmusthaveawindowclass,sotypically,
RegisterClassis
calledin
WinMain.
Usually,theMessageLoopisimplementedasabasic
whileloop:
MSGmsg;
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
returnmsg.wParam;
The
MSGstructureisastructurethatholdsalltheinformationaboutthemessage:Thewindowitwassentto,themessageidentifier,the2
lParam/
wParam
parametersthatcomewiththemessage,thetimeatwhichthemessagewassent,andthepositionofthemousewhenthemessagewassent.
Thecallto
GetMessagetellswindowstoretrievethefirstmessageintheMessageQueue.IfthereisnomessageintheMessageQueue,
GetMessage
willnotreturnuntilthereis.Thereturnvaluefrom
GetMessagedependsonthemessageitretrieved:Ifitwasa
WM_QUITmessage
itwillreturn
FALSE,ifitwasn't,itwillreturn
TRUE.The
TranslateMessage
functiontranslatesvirtual-keymessagesintocharactermessages.Thecharactermessagesarepostedtothecallingthread'sMessageQueue,tobereadthenexttimethethreadcallsthe
GetMessage
function.Forexample,ifyougeta
WM_KEYDOWNmessage,
TranslateMessagewilladda
WM_CHAR
messagetoyourMessageQueue.Thisisveryusefulbecausethe
WM_KEYDOWNwillonlytellyouwhatkeyhasbeenpressed,notthecharacteritself.A
WM_KEYDOWN
for
VK_Acouldmean"a"or"A",dependingonthestateoftheCapsLockandShiftkey.
TranslateMessagewilldotheworkofchecking
ifitshouldbecapitalforyou.Thecallto
DispatchMessagewillcalltheWindowProcedureassociatedwiththewindowthatreceivedthemessage.That'stheSDKMessageLoopinanutshell.
AWindowProcedureisafunctioncalledbytheMessageLoop.Wheneveramessageissenttoawindow,theMessageLooplooksatthewindow'sWindowClassandcallstheWindowProcedurepassingthemessage'sinformation.AWindowProcedureisprototypedas:
LRESULTCALLBACKWindowProc(
HWNDhwnd,//handletowindow
UINTuMsg,//messageidentifier
WPARAMwParam,//firstmessageparameter
LPARAMlParam//secondmessageparameter
);
The
HWNDisthehandletothewindowthatreceivedthemessage.Thisparameterisimportantsinceyoumightcreatemorethanonewindowusingthesamewindowclass.
uMsg
isthemessageidentifier,andthelast2parametersaretheparameterssentwiththemessage.
Typically,aWindowProcedureisimplementedasasetof
switchstatements,andacalltothedefaultwindowprocedure:
LRESULTCALLBACKWndProc(HWNDhwnd,UINTuMsg,
WPARAMwParam,LPARAMlParam){
switch(uMsg)
{
caseWM_CREATE:
//Dosomeinitialization,Playasoundorwhateveryouwant
return0;
caseWM_PAINT:
//HandletheWM_PAINTmessage
return0;
caseWM_DESTROY:
PostQuitMessage(0);
return0;
}
returnDefWindowProc(hwnd,message,wParam,lParam);
}
The
switch-
caseblockinspectsthemessageidentifierpassedinthe
uMsg
parameterandrunsthecorrespondingmessagehandler.The
PostQuitMessagecallwillsenda
WM_QUITmessagetotheMessageLoop,causing
GetMessage()
toreturn
FALSE,andtheMessageLooptohalt.
DefWindowProc
AsIstatedinPart1,Windowsshouldhandleanymessageyoudon'thandle.ThecalltoDefWindowProc()givesWindowsashotatthemessage.Somemessagessuch
as
WM_PAINTand
WM_DESTROYmustbehandledinyourWindowProcedure,andnotin
DefWindowProc.
Puttingitalltogether:AllToGether.C(这个是核心的处理函数,入口函数)
#include<windows.h>
//DeclaretheWindowProcedure
LRESULTCALLBACKWndProc(HWND,UINT,WPARAM,LPARAM);
intWINAPIWinMain(
HINSTANCEhInstance,//handletocurrentinstance
HINSTANCEhPrevInstance,//handletopreviousinstance
LPSTRlpCmdLine,//pointertocommandline
intnCmdShow//showstateofwindow
){
staticTCHARlpszClassName[]=TEXT("AllTogether");
HWNDhwndMainWindow;
MSGmsg;
WNDCLASSwndclass;//窗口类,窗口显示的样式
//FillintheWindowclassdata
wndclass.cbClsExtra=0;
wndclass.cbWndExtra=0;
//Thedefaultwindowbackground
wndclass.hbrBackground=COLOR_WINDOW;
//Thesystem,IDC_ARROWcursor
wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
//ThesystemIDI_APPLICATIONicon
wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
wndclass.hInstance=hInstance;
wndclass.lpfnWndProc=WndProc;
//Thenameoftheclass,neededforCreateWindow
wndclass.lpszClassName=lpszClassName;
wndclass.lpszMenuName=NULL;
wndclass.style=CS_HREDRAW|CS_VREDRAW;
RegisterClass(&wndclass);//注册类,下面是创建窗体
hwndMainWindow=
CreateWindow(lpszClassName,//pointertoregisteredclassname
TEXT("LetsPutitalltogether"),//pointertowindowname
WS_OVERLAPPEDWINDOW,//windowstyle
CW_USEDEFAULT,CW_USEDEFAULT,//positionofwindow
CW_USEDEFAULT,CW_USEDEFAULT,//sizeofwindow
NULL,//handletoparentorownerwindow
NULL,//handletomenu
hInstance,//handletoapplicationinstance
NULL);//pointertowindow-creationdata
ShowWindow(hwnd,nCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&msg,NULL,0,0))//消息循环
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
returnmsg.wParam;
}
LRESULTCALLBACKWndProc(HWNDhwnd,UINTuMsg,
WPARAMwParam,LPARAMlParam){
switch(uMsg)
{
caseWM_CREATE:
//Dosomeinitialization,Playasoundorwhateveryouwant
return0;
caseWM_PAINT:
//HandletheWM_PAINTmessage
return0;
caseWM_DESTROY:
PostQuitMessage(0);
return0;
}
returnDefWindowProc(hwnd,message,wParam,lParam);
}
SendingMessages
Besidesreceivingmessages,youwilloftenfindyourselfsendingmessages.Youmightwanttosendmessagestocommunicatebetweentwowindowsinyourprogram,ortocommunicatebetweendifferentprograms.Inordertosendamessage,youneedahandletothetargetwindow.Thiscanberetrievedusingavarietyoffunctions,including
FindWindow(),
GetDlgItem(),
GetParent(),
EnumWindows()andmanymore.TheSDKhasa
SendMessage()
functionwhichallowsyoutosendmessagestoawindow.Forexample,let'ssayyouhaveahandletotheCalculator,andyouwanttocloseit.Whatyoushoulddoissenda
WM_CLOSEmessage,which
willnotifytheCalculatorthatitshouldclose.Youcanusethefollowingcode.InordertogetapointertoCalculator,Iusethe
FindWindow()functionandpassthetitleofthewindow,which
inourcaseis"Calculator":
HWNDhWndCalc;
//Getahandletothe"Calculator"Window
hWndCalc=FindWindow(NULL,TEXT("Calculator));
if(hWndCalc==NULL)
{
//Couldn'tfindCalculator
}
else
{
SendMessage(hWndCalc,WM_CLOSE,0,0);
//Presto!TheCalculatorshouldclose.
}
LOWORDandHIWORDmacros:SplituplParamandwParam
Often,oneormoreofthe32-bitlParamand
wParamparametersareactuallymadeoftwo16-bitparameters.Onecaseisthe
WM_MOUSEMOVE
message.MSDNstatesthatthe
lParamforthismessageisactually2values:theXpositionofthemouse,andtheYpositionofthemouse.Buthowdoyouretrievethevaluesfromthe
lParam?
TheSDKhas2macrosdesignedforexactlythispurpose:
LOWORD()and
HIWORD().The
LOWORDmacroretrievesthelow-orderwordfromthegiven32-bitvalue,andthe
HIWORD()macroretrievesthehigh-orderword.So,given
an
lParamof
WM_MOUSEMOVE,youcanretrievethecoordinatesusingthefollowingcode:
WORDxPos=LOWORD(lParam);//horizontalpositionofcursor
WORDyPos=HIWORD(lParam);//verticalpositionofcursor
MAKELPARAMandMAKEWPARAMmacros:concatenatetwo16-bitvalues
LOWORDand
HIWORDarefineifyouwanttosplituptheparameters,butwhatifyouwanttocreatea32-bitvalueforuseasan
lParamor
wParam
parameterinamessage?TheSDKhas2macrosforthissituationalso:
MAKELPARAMand
MAKEWPARAMbothcombinetwo16-bitvaluesinto
a32-bitvalue,thatisusableformessages.Forexample,thefollowingcodesendsa
WM_MOUSEMOVEmessagetoawindow(
HWNDhWndTarget)
withthe
fFlagsparameterasthe
wParam,andthex/ycoordinatesasthe
lParam:
SendMessage(hWndTarget,WM_MOUSEMOVE,fFlags,MAKELPARAM(x,y));
Dialogs
Handlingamessageinadialogisverysimilartohandlingamessageinanormalwindow.WindowshaveWindowProcedures,DialogshaveDialogProcedures.Onemajordifferenceisthatyoudon'tspecifyawindowclassforadialog.Whenyoucreateadialogusingoneofthe
CreateDialog...functionsorthe
DialogBox...functions,youpassaDialogProcedureasoneoftheparameters.A
DialogProcedureisprototypedas:
BOOLCALLBACKDialogProc(
HWNDhwndDlg,//handletodialogbox
UINTuMsg,//message
WPARAMwParam,//firstmessageparameter
LPARAMlParam//secondmessageparameter
);
YoumighthavenoticedthattheDialogProcedurelooksverysimilartotheWindowProcedure,butitisn'tarealWindowProcedure.TheWindowProcedureforthedialogislocatedinsidewindows.ThatWindowProcedurecallsyourDialogProcedurewhenvarious
messagesaresenttoyourwindow.Becauseoftheabove,therearemessagesthatyouwillreceiveinaWindowProcedurethatyouwon'treceiveinaDialogProcedure.ThereareafewmajordifferencesbetweenaWindowProcedureandaDialogProcedure:
ADialogProcedurereturnsa
BOOL,aWindowProcedurereturnsa
LRESULT.
ADialogProceduredoesn'tneedtohandle
WM_PAINTor
WM_DESTROY.
ADialogProceduredoesn'treceivea
WM_CREATEmessage,butrathera
WM_INITDIALOGmessage
AWindowProcedurecalls
DefWindowProc()formessagesitdoesnothandle.ADialogProcedureshouldreturn
TRUEifithandled
themessageor
FALSEifnotwithoneexception:ifyousettheinputfocustoacontrolin
WM_INITDIALOG,youshouldreturn
FALSE.
User-definedmessages
Sometimes,youwillneedtocommunicatebetween2windowsinyourapplicationorbetween2windowsfromdifferentapplications.AneasywaytodothisisbyusingUser-definedmessages.Thename"User-defined"canbeconfusingatfirst;youdefineaUser-definedmessageandnottheuserofyourprogram.IhavestatedinPart1thatmessagesareidentifiedbynumbers,andthatWindowspredefinesstandardmessages.Thewayofusinguser-definedmessagesistosimplyuseanumber.Tomakesurethatyoudon'tconflict
withthesystemdefinedmessages,youshoulduseanumberintherangeof
WM_APPthrough0xBFFF:
#defineWM_DELETEALLWM_APP+0x100
//...
SendMessage(hWndYourDialog,WM_DELETEALL,0,0);
Youhandleauser-definedmessagejustlikeyouhandlearegularmessage:
#defineWM_DELETEALLWM_APP+0x100
//WindowProcedure
LRESULTCALLBACKWndProc(HWNDhwnd,UINTuMsg,WPARAMwParam,LPARAMlParam)
{
switch(uMsg)
{
caseWM_DELETEALL:
//We'vegottheuser-definedmessage,letsDeleteAll
return0;
caseWM_CREATE:
//Dosomeinitialization,Playasoundorwhateveryouwant
return0;
caseWM_PAINT:
//HandletheWM_PAINTmessage
return0;
caseWM_DESTROY:
PostQuitMessage(0);
return0;
}
returnDefWindowProc(hwnd,message,wParam,lParam);
}
RegisteredWindowsMessages
TheRegisterWindowMessagefunctionisusedtodefineanewwindowmessagethatisguaranteedtobeuniquethroughoutthesystem.Likeuser-definedmessages,RegisteredMessagesarehandledlike
regularmessages:
staticUINTWM_FIND=RegisterWindowMessage(TEXT("YOURAPP_FIND_MSG");
//WindowProcedure
LRESULTCALLBACKWndProc(HWNDhwnd,UINTuMsg,WPARAMwParam,LPARAMlParam)
{
switch(uMsg)
{
caseWM_FIND:
//We'vegottheregisteredmessage,letsstartFinding.
return0;
caseWM_CREATE:
//Dosomeinitialization,Playasoundorwhateveryouwant
return0;
caseWM_PAINT:
//HandletheWM_PAINTmessage
return0;
caseWM_DESTROY:
PostQuitMessage(0);
return0;
}
returnDefWindowProc(hwnd,message,wParam,lParam);
}
Theregisteredmessageidentifiersusingthisapproachwillbeintherangeof0xC000to0xFFFF.Andyousenditusingtheregular
SendMessage()method:
staticUINTWM_FIND=RegisterWindowMessage(TEXT("YOURAPP_FIND_MSG"));
//...
SendMessage(hWndFindWindow,WM_FIND,lParam,wParam);
(四)
这部分没研究,可以看看,原文:
Introduction
Subclassingisatechniquethatallowsanapplicationtointerceptandprocessmessagessentorpostedtoaparticularwindowbeforethewindowhasachancetoprocessthem.ThisistypicallydonebyreplacingtheWindowProcedureforawindowwithapplication-definedwindowprocedure.Iwilldevidethisarticleinto3:
Whysubclass?
Sometimesyouwanttotakethefunctionalityofacontrolandmodifyitslightly.Oneexampleisreplacingthemenuinaneditcontrol,Anotherisaddingacontextmenuwhenyoupressonabutton.OneofthemostcommonquestionsIencounteris"HowdoIscreenoutcharactersfromaneditcontrol?".IwillshowthesolutiontothisfromanMFCapproachandfromanSDKapproach,whileItrytoexplainSubclassing.
TheneedforsubclassingcomesfromthefactthatthecodefortheWindowscontrolsiswithinWindows,meaningyoucannoteditthecode.Althoughyoucannoteditthecodeofthecontrolitself,youinterceptthemessagessenttoit,andhandlethemyour
self.Youdosobysubclassingthecontrol.SubclassinginvolvesreplacingtheMessageHandlersofthecontrol,andpassinganyunprocessedmessagetothecontrolsMessageHandler.
SDKSubclassing
AlthoughtheMessageProcedureforthecontrolislocatedwithinwindows,youcanretrieveapointertoitbyusingtheGetWindowLongfunctionwiththe
GWL_WNDPROC
identifier.Likewise,youcancall
SetWindowLongandspecifyanewWindowProcedureforthecontrol.ThisprocessiscalledSubclassing,andallowsyoutohookintoawindow/controlandintercept
anymessageitgets.SubclassingistheWindowstermforreplacingtheWindowProcedureofawindowwithadifferentWindowProcedureandcallingtheoldWindowProcedurefordefault(superclass)functionality.Remember
DefWindowProc()?
insteadofcalling
DefWindowProcfordefaultMessageHandlingyouusetheoldWindowProcedureasthedefaultMessageHandler.
ImplementingSDKSubclassing
So,letstrytosolvetheclassicquestion"HowdoIscreenoutcharactersfromaneditcontrol?",or"HowdoIcreatealetter-onlyeditcontrol?"Firstletsanalyzehowaneditcontrolworks:
Aneditcontrolisawindow.It'swindowprocedurelieswithinwindows.Amongotherthings,wheneveritgetsaWM_CHARmessageitaddsthecharactertothetextitcontains.Nowthatweknow
that,wecansimplysubclasstheeditcontrol,andinterceptthe
WM_CHARmessages.Wheneverthe
WM_CHARmessageisaletterorakey
likespacebarorbackspacewe'llpassthemessagetotheeditcontrol.Ifitisn'toneoftheabove,we'lljust"Swallow"themessage,blockingitfromreachingtheEditControl.
Thefirststeptosubclassingistoaddaglobal/static
WNDPROCvariablethatwillstoretheaddressoftheeditcontrol'sWindowProcedure.
WNDPROCg_OldEdit;
ThesecondstepistocreateanewWindowProcedurefortheeditcontrol:
LRESULTCALLBACKNewEditProc(HWNDhwnd,UINTmessage,
WPARAMwParam,LPARAMlParam)
{
TCHARchCharCode;
switch(message)
{
caseWM_CHAR:
chCharCode=(TCHAR)wParam;
if(chCharCode>0x20&&!IsCharAlpha(chCharCode))
return0;
break;
}
returnCallWindowProc(g_OldEdit,hwnd,message,wParam,lParam);
}
The
IsCharAlphafunctiondetermineswhetheracharacterisanalphabeticcharacter.Thisdeterminationisbasedonthesemanticsofthelanguageselectedbytheuserduringsetuporbyusing
ControlPanel.
Moreinterestingisthe
CallWindowProcfunction.The
CallWindowProcfunctionpassesmessageinformationtothespecifiedWindow
Procedure.Acallto
CallWindowProcwillallowyoutocalltheoldWindowProcedurewithanymessageyoureceive,thusprovidingdefaultmessagehandling
ThethirdstepistoreplacetheWindowProcedurefortheeditcontrol,andtostoretheoldoneing_OldEdit.Forexample,ifyouwanttosubclassaneditcontrolthatresidesinadialog(hDlg)andhastheIDof
IDC_EDIT1
youwouldusethefollowingcode:
hwndhWndEdit=GetDlgItem(hDlg,IDC_EDIT1);<BR>//ReplacetheWindowProcedureandStoretheOldWindowProcedure
g_OldEdit=(WNDPROC)SetWindowLong(hWndEdit,GWL_WNDPROC,(LONG)NewEditProc);
Thecontrolisnowsubclassed.Anymessagetotheeditcontrolwillfirstgothroughthe
NewEditProcWindowProcedure,whichwilldecideifthemessageshouldgototheeditcontrol'sWindow
Procedure.
MFCSubclassing
SubclassinginbothMFCandSDKprogramsisdonebyreplacingthemessagehandlersofacontrol.ItisrathereasytosubclassinaMFCprogram.Firstyouinherityourclassfromaclassthatencapsulatesthefunctionalityofathecontrol.InClassWizard,clickon"AddClass",then"New".Forthebaseclass,choosetheMFCControlclassyouarederivingfrom,inourcase,
CEdit.
UsingMFCrelievesyoufromhavingtocalltheoldMessageHandlers,sinceMFCwilltakecareofitforyou.
ThesecondstepistoaddMessageHandlerstoyournewclass.Ifyouhandleamessageandyouwantthecontrol'smessagehandlertogetashotatit,youshouldcallthebaseclassmemberfunctionthecorrespondswiththemessage.thisisthesubclassed
WM_CHAR
handler:
voidCLetterEdit::OnChar(UINTnChar,UINTnRepCnt,UINTnFlags)
{
if(nChar<=0x20||IsCharAlpha((TCHAR)nChar))<BR>{
//Callbaseclassmember,whichwillcall<BR>//thecontrol'smessagehandler
CEdit::OnChar(nChar,nRepCnt,nFlags);
//Ifnot,themessageisblocked<BR>}
}
Thethirdandfinalstageistoassociatethewindowwithaninstanceofournewclass.InadialogthisisdonesimplybyusingClassWizardtocreateacontrolmembervariableofyourclassinthewindow'sparent,andassociateitwiththe
control.
Inanon-dialogparentyoushouldaddamembervariableinstanceofyourcontroltoit,andcalloneofthetwo
CWndSubclassingfunctions:
CWnd::SubclassWindow.Bothroutinesattacha
orCWnd::SubclassDlgItem
CWndobjecttoanexistingWindows
HWND.
SubclassWindow
takesthe
HWNDdirectly,and
SubclassDlgItemisahelperthattakesacontrolIDandtheparentwindow(usuallyadialog).
SubclassDlgItemis
designedforattachingC++objectstodialogcontrolscreatedfromadialogtemplate.
FurtherReading
ForamoreindepthtreatmentofMFCsubclassingseeChrisMaunder'sarticle:"ReflectedMessages-MFC4.0+
Whenyousubclassacontrol,besideshandlingthemessageitreceives,inMFCyoucanalsohandlethenotificationsitsendstoit'sparentwindow.ThistechniqueiscalledMessageReflecting.Windowscontrolsoftensendnotificationstotheirparents,forexample,aButtonwillsenda
WM_COMMANDmessagetellingit'sparentithasbeenclicked.Usuallyitistheparent'sjobtohandlethesemessages,butMFCwillalsoallowyoutohandlethemin
thecontrolitself.InClassWizardthesemessagesappearwithan"="signbeforethem,indicatingtheyareReflectedMessages.Youhandlethemjustlikeanyothermessage.Themacrosforthesemessagesaresimilartotheregularmessages,buthave
_REFLECT
addedtotheendofthemacro.Forexample,
ON_NOTIFY()becomes
ON_NOTIFY_REFLECT().
相关文章推荐
- windows消息处理(强烈推荐,收藏)
- windows 消息处理过程说明
- Windows 键盘消息处理
- Windows消息队列 UI线程,窗口以及消息处理方式总结
- Windows消息对Edit控件的处理
- 关于捕获VCL没有处理的Windows消息
- Windows编程:计时器消息的处理、销毁计时器
- c# Windows消息处理过程探究
- Window API 关于控件的消息处理(SendMessage)(转) 收藏
- MFC/Windows_Windows/MFC对消息处理的顺序
- 网络编程(53)—— Windows下使用WSAAsyncSelect实现窗口处理socket消息
- Windows事件与消息处理
- Windows消息队列,UI线程,窗口以及消息处理方式总结
- 走进windows编程的世界-----消息处理函数(4)
- WINDOWS消息大全(收藏)
- 走进windows编程的世界-----消息处理函数(2)
- (收藏)MFC中的消息处理
- DELPHI中的消息处理机制(收藏)
- Win32 SDK基础(10)—— 几种常见的Windows消息处理
- Qt for windows消息循环、libqxt分析和wince快捷键处理