在MFC原代码中有如下代码:AFX_STATIC BOOL AFXAPI _AfxDispatchCmdMsg(CCmdTarget* pTarget, UINT nID, int nCode,
AFX_PMSG pfn, void* pExtra, UINT nSig, AFX_CMDHANDLERINFO* pHandlerInfo)
// return TRUE to stop routing
{
ASSERT_VALID(pTarget);
UNUSED(nCode);   // unused in release builds union MessageMapFunctions mmf;
mmf.pfn = pfn;
BOOL bResult = TRUE; // default is ok if (pHandlerInfo != NULL)
{
// just fill in the information, don't do it
pHandlerInfo->pTarget = pTarget;
pHandlerInfo->pmf = mmf.pfn;
return TRUE;
} switch (nSig)
{
case AfxSig_vv:
// normal command or control notification
ASSERT(CN_COMMAND == 0);        // CN_COMMAND same as BN_CLICKED
ASSERT(pExtra == NULL);
(pTarget->*mmf.pfn_COMMAND)();  // ******注意这行*****
break;
为什么执行到*****这行 之后 程序跳到 CWinApp::OnFileNew()了呢? (pTarget->*mmf.pfn_COMMAND)()跟 CWinApp::OnFileNew() 有什么关系呢?请高手指点。

解决方案 »

  1.   

    http://www.china-askpro.com/msg45/qa29.shtml
      

  2.   

    pTarget->*mmf.pfn_COMMAND)();  就是函数OnFileNew()的函数指针
      

  3.   

    跟  http://www.china-askpro.com/msg45/qa29.shtml
     关系不大
      

  4.   

    “pTarget->*mmf.pfn_COMMAND)();  就是函数OnFileNew()的函数指针” 什么意思 ?何以见得?请 checkyvc6(已所不欲,勿施于人) ( ) 兄:再解释的详细点。谢谢!
      

  5.   

    在OnCmdMsg里面已经找到对应消息的消息处理函数然后通过
    return _AfxDispatchCmdMsg(this, nID, nCode,
    lpEntry->pfn, pExtra, lpEntry->nSig, pHandlerInfo);
    来调用消息处理函数
    lpEntry->pfn就是类中用宏关联的处理函数指针.
    在AfxDispatchCmdMsg里面 mmf.pfn = pfn;
    这一句就是将函数OnFileNew的地址赋值为mmf.pfn由于mmf是个联合体,因此pfn 和pfn_COMMAND的值是一样的
    通过下面的语句来调用OnFileNew()
    (pTarget->*mmf.pfn_COMMAND)();  
    至于为什么要这样调用,主要市考虑函数的堆栈的处理要和OnFileNew一致
    pTarget指向App对象
      

  6.   

    pTarget->*mmf.pfn_COMMAND():
    mmf是个联合union,它的成员mmf.pfn_COMMAND()是个指针,指向实际的WM_COMMAND的处理函数,处理函数是CcmdTarget或其派生类的成员函数,因此必须要用这种稍显怪异的方法进行函数指针所指函数的调用.MFC中WM_COMMAND消息的处理过程(以SDI为例):
        消息首先到发送消息的窗口的OnCommand,这是虚函数,所以直接调用发送消息的窗口所属类的实现,这里是CFrameWnd::OnCommand(WPARAM wParam, LPARAM lParam);[WinFrm.cpp] 这个函数中,如果消息是在线帮助请求,则发送一个WM_COMMANDHELP消息,并以ID_DEFAULT_HELP为wParam参数发送WM_COMMAND消息,同时返回;否则调用CWnd的实现CWnd::OnCommand()[WinCore.cpp].
    CWnd::OnCommand()中,首先检查是不是控件发出的消息if (hWndCtrl == NULL),如果是,它使用ReflectLastMsg(hWndCtrl)将消息直接发给控件并返回.否则,确认消息是菜单或加速键,首先检查对应的界面元素是否被禁用,没有的话将消息传给虚函数OnCmdMsg(),这里将调用CFrame::OnCmdMsg[WinFrm.cpp].
    Cframe::OnCmdMsg将消息按下面路由进行传送:活动视图,主窗口,应用程序.其中消息到活动视图中时,如用户的视图类没有重载此虚函数,则调用转到CView::OnCmdMsg()[ViewCore.cpp].在这里,它将消息转它的基类处理(CcmdTarget::OnCmdMsg[CmdTarg.cpp]),如基类不处理,将会转交它所属文档类去处理,文档类不处理时,后继路由上的主窗口或应用程序才有机会处理.
    CcmdTarget::OnCmdMsg遍历消息映射表查找消息处理函数,找不到返回FALSE进行后继处理,找到则调用指定义的处理函数:_ AfxDispatchCmdMsg.该函数前的static仅表示该全局函数在该文件内可见,其它文件不得调用.其参数nSig是个函数签名,pfn时处理函数的指针,二者都来自消息映射表入口,它将根据签名的不同执行不同的操作(因为它们的对应处理函数的返回值或参数有所区别,需要进行参数生成并将pfn转换成合适类型的函数指针进行的调用),如一般菜单命令的签名是AfxSig_xx.
    注意到_ AfxDispatchCmdMsg开头的那句 union MessageMapFunctions mmf; mmf.pfn = pfn;没有?这个联合用于将pfn根据签名的不同转换成不同的类型:
    //AfxImpl.cpp
    union MessageMapFunctions
    {
    AFX_PMSG pfn;   // generic member function pointer void (AFX_MSG_CALL CCmdTarget::*pfn_COMMAND)();
    BOOL (AFX_MSG_CALL CCmdTarget::*pfn_bCOMMAND)();
    void (AFX_MSG_CALL CCmdTarget::*pfn_COMMAND_RANGE)(UINT);
    BOOL (AFX_MSG_CALL CCmdTarget::*pfn_COMMAND_EX)(UINT);
    ……//后面列出了所有可能的消息处理函数的原型,详见源码
    } ;
    void (AFX_MSG_CALL CCmdTarget::*pfn_COMMAND)();代表一个指向CcmdTarget类的成员函数的指针,返回值及参数都为空,其它原型同理.因为这是个联合,不管用哪个成员来进行函数调用,实际都是用pfn这个指针----它已经在上面初使化为消息表入口中提供的特定处理函数的指针了.注意它是指向CCmdTarget类的成员函数的指针,按C++函数指针的规则,使用语法如:pTarget->*mmf.pfn_COMMAND()//这里pTarget须是个CcmdTarget或其派生类的对象.
    因此,有了函数签名后,对消息处理函数的调用就使用mmf中对应的函数原形以实现参数与返回值的匹配.
    当上面列出的所有消息路由都没处理消息时,由CWnd::DefWindowProc()处理.
    上面所有东西由一个称为函数签名的东西维系的.它定义于消息入口中:
    //AfxWin.h
    struct AFX_MSGMAP_ENTRY
    {
    UINT nMessage;   // windows message
    UINT nCode;      // control code or WM_NOTIFY code
    UINT nID;        // control ID (or 0 for windows messages)
    UINT nLastID;    // used for entries specifying a range of control id's
    UINT nSig;       // signature type (action) or pointer to message #
    AFX_PMSG pfn;    // routine to call (or special value)
    };
    中间的nSig就是函数签名.
    //AfxMsg_.h中定义了已知的函数签名,这是个enum:
    enum AfxSig
    {
    AfxSig_end = 0,     // [s end of message map] AfxSig_bD,      // BOOL (CDC*)
    AfxSig_bb,      // BOOL (BOOL)
    AfxSig_bWww,    // BOOL (CWnd*, UINT, UINT)
    ……//未完,详见源码.
    } ;
    消息映射宏的实现其实就是定义了个静态的消息入口表,入口表是个AFX_MSGMAP_ENTRY一维数组,每个元素对应于一条消息映射宏.但不限于此,DECLARE_MESSAGE_MAP()还定义了基类消息入口表的指针以实现向基类传递消息.
    AfxMsg_.h中的注释说明了消息入口表项的格式(共9种):
    // Entries in a message map (a 'AFX_MSGMAP_ENTRY') table can be of 9 formats
    //
    // 1) control notification message (i.e. in response to WM_COMMAND)
    //      WM_COMMAND, nNotifyCode, nControlID, nControlID, signature type, parameterless member function
    //      (eg: WM_COMMAND, LBN_SELCHANGE, IDC_LISTBOX, AfxSig_vv, ... )
    // 2) control notification message range (i.e. in response to WM_COMMAND)
    //      WM_COMMAND, nNotifyCode, nControlIDFirst, nControlIDLast, signature type, parameterless member function
    //      (eg: WM_COMMAND, LBN_SELCHANGE, IDC_LISTBOX1, IDC_LISTBOX5, AfxSig_vw, ... )
    // 3) WM_NOTIFY notification
    //      WM_NOTIFY, nNotifyCode, nControlID, nControlID, signature type, ...)
    // 3) Update Command UI
    //      -1, 0, nControlID, 0, signature Unknown, parameterless member function
    // 4) Update Command UI Range
    //      -1, 0, nControlIDFirst, nControlIDLast, signature Unknown, parameterless member function
    // 5) menu/accelerator notification message (i.e. special case of first format)
    //      WM_COMMAND, 0, nID, 0, signature type, parameterless member function
    //      (eg: WM_COMMAND, 0, IDM_FILESAVE, 0, AfxSig_vv, ... )
    // 6) menu/accelerator notification message range
    //      WM_COMMAND, 0, nIDFirst, nIDLast, signature type, parameterless member function
    //      (eg: WM_COMMAND, 0, IDM_FILE_MRU1, IDM_FILE_MRU4, AfxSig_vw, ... )
    // 7) constant windows message
    //      nMessage, 0, 0, 0, signature type, member function
    //      (eg: WM_PAINT, 0, ...)
    // 8) variable windows message (using RegisterWindowMessage)
    //      0xC000, 0, 0, 0, &nMessage, special member function
    //
    // The end of the message map is ed with a special value
    //      0, 0, AfxSig_end, 0
    /////////////////////////////////////////////////////////////////////////////
      

  7.   

    就是这样的:pTarget->*mmf.pfn_COMMAND)();  就是函数OnFileNew()的函数指针
      

  8.   

    指向成员函数的指针的在ISO/IEC14882标准的8.3.3节有详细的说明.