且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

SendMessage/PostMessage 到派生的 CView 类不适用于 MFC 应用程序

更新时间:2022-04-27 15:21:55

关于您的主要问题在尝试使用 SendMessage、PostMessage 函数与 CView 的派生类进行通信时是否存在任何已知限制",答案是否定的.函数 SendMessage()PostMessage() 是标准的 Win32 API 函数,用于向定义了窗口句柄的任何窗口提供消息.

Concerning your main question of "whether there are any known limitations in trying to use SendMessage,PostMessage functions to communicate to a derived class of CView" the answer is no. The functions SendMessage() and PostMessage() are standard Win32 API functions for providing a message to any window whose window handle is defined.

MFC 的一些背景

大多数包装窗口的 MFC 类都是从某个点 CWnd 派生而来的.CWnd 类用于环绕 Windows 窗口和与窗口一起使用的 Win32 API.许多采用窗口句柄的 Win32 API 函数都有一个类似的 CWnd 类方法.

Most of the MFC classes that wrap a window are derived from at some point CWnd. The CWnd class is used to wrap around a Windows window and the Win32 API used with a window. So many of the Win32 API functions that take a window handle have an analogue CWnd class method.

如果您查看 CView 的声明,您会发现它是从 CWnd 派生而来的,它具有这两个函数的版本作为方法.然而,CWnd 的方法具有与 Win32 API 版本不同的接口,因为它们消除了窗口句柄作为第一个参数.

If you look at the declaration for CView you can see it is derived from CWnd which has a version of these two functions as methods. However the methods of CWnd have a different interface than the Win32 API version as they eliminate the window handle as the first argument.

CWnd 类声明看起来像

LRESULT CWnd::SendMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0);

这个方法在 CWnd 类中的实现大概是这样的:

The implementation of this method within the CWnd class is probably something along the lines of:

LRESULT CWnd::SendMessage(UINT message, WPARAM wParam, LPARAM lParam)
{
    return ::SendMessage (m_hWnd, message, wParam, lParam);
}

其中 m_hWndCWnd 类中定义为 HWND m_hWnd; 并且是 CWnd 的窗口句柄> 课程正在结束.

where m_hWnd is defined in the CWnd class as HWND m_hWnd; and is the window handle that the CWnd class is wrapping.

什么是消息映射

在 MFC 窗口类文件中,例如从 CView 派生的类,将有一组类似于以下内容的源代码行:

In an MFC window class file such as for a class derived from CView there will be a set of source lines similar to:

BEGIN_MESSAGE_MAP(CPCSampleApp, CWinApp)
    //{{AFX_MSG_MAP(CPCSampleApp)
    ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
    ON_COMMAND(ID_APP_EXIT, OnAppExit)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

它们是在包含文件中定义的一组预处理器宏,允许创建 MFC 消息映射.

which are a set of preprocessor macros defined in an include file that allow an MFC message map be to created.

BEGIN_MESSAGE_MAP 宏如下所示:

#define BEGIN_MESSAGE_MAP(theClass, baseClass) \
    PTM_WARNING_DISABLE \
    const AFX_MSGMAP* theClass::GetMessageMap() const \
        { return GetThisMessageMap(); } \
    const AFX_MSGMAP* PASCAL theClass::GetThisMessageMap() \
    { \
        typedef theClass ThisClass;                        \
        typedef baseClass TheBaseClass;                    \
        static const AFX_MSGMAP_ENTRY _messageEntries[] =  \
        {

它正在创建一组函数以及一个数组来存储各种消息映射条目.

which is creating a set of functions along with an array to store the various message map entries into.

END_MESSAGE_MAP 宏提供消息映射条目数组的结尾,如下所示:

The END_MESSAGE_MAP macro provides the end of the array of message map entries and looks like:

#define END_MESSAGE_MAP() \
        {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \
    }; \
        static const AFX_MSGMAP messageMap = \
        { &TheBaseClass::GetThisMessageMap, &_messageEntries[0] }; \
        return &messageMap; \
    }                                 \
    PTM_WARNING_RESTORE

实际的数组元素是一个struct AFX_MSGMAP_ENTRY,如下所示:

The actual array elements are of a struct AFX_MSGMAP_ENTRY which looks like this:

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_PTR nSig;       // signature type (action) or pointer to message #
    AFX_PMSG pfn;    // routine to call (or special value)
};

在 MFC 的底层是一系列查找函数,这些函数获取 Windows 消息,然后遍历消息映射数组中声明的 Windows 消息列表,以查看是否存在匹配项.

Under the hood of MFC is a series of lookup functions that take a Windows message and then iterates over the list of Windows messages declared in the message map array to see if there is a match.

如果它找到了 Windows 消息 ID 和相应的 wParam 值的匹配项,则它通过为匹配消息映射条目提供接口规范的正确参数的函数指针调用该函数.

If it finds a match of the Windows message id and the appropriate wParam value, then it calls the function through the function pointer provided with the proper arguments of the interface specification for the matching message map entry.

ON_COMMAND 宏,其中包含数组条目的源代码,如下所示:

The ON_COMMAND macro, which contains the source for an array entry looks like:

#define ON_COMMAND(id, memberFxn) \
    { WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)id, AfxSigCmd_v, \
        static_cast<AFX_PMSG> (memberFxn) },
        // ON_COMMAND(id, OnBar) is the same as
        //   ON_CONTROL(0, id, OnBar) or ON_BN_CLICKED(0, id, OnBar)

如果您查看 ON_COMMAND 的定义,Windows 消息标识符被硬编码为 WM_COMMAND,以便触发 ON_COMMAND 条目,Windows 消息必须指定 WM_COMMAND 消息标识符.

If you look at the definition of an ON_COMMAND the windows message identifier is hard coded to WM_COMMAND so in order to trigger the ON_COMMAND entry, a Windows message must specify the WM_COMMAND message identifier.

MFC 运行时知道它将不带参数调用消息处理程序,因为签名类型是 AfxSigCmd_v,枚举 AfxSig 中的一个值用于通知 MFC 运行时消息处理程序的接口是什么样的.

The MFC Run Time knows that it is to call the message handler with no arguments because the signature type is AfxSigCmd_v, a value in the enumeration AfxSig which is used to inform the MFC Run Time what the interface to the message handler looks like.

如果您查看 ON_COMMAND 处理程序的接口规范,则没有参数,因此当 MFC 运行时调用指定的函数指针时,它不提供任何参数.

If you look at the interface specification for an ON_COMMAND handler, there are no arguments so when the MFC run time calls the designated function pointer, it does not provide any arguments.

所以使用ClassView类的方法SendMessage()发送Windows消息触发ON_COMMAND(ID_DESIGN_xxx, OnXXX)viewObjectClassView 对象变量的/code> :

So to use the ClassView class' method SendMessage() to send a Windows message to trigger a message map entry of ON_COMMAND(ID_DESIGN_xxx , OnXXX) of a ClassView object variable of viewObject you would need to use:

viewObject->SendMessage(WM_COMMAND, ID_DESIGN_xxx, 0);

或者你可以使用 Win32 API:

or you could use the Win32 API with:

::SendMessage (viewObject->m_hWnd, WM_COMMAND, ID_DESIGN_xxx, 0);

另一个例子:ON_NOTIFY_EX

另一个不同的消息映射宏是ON_NOTIFY_EX 宏.它看起来像:

Another message map macro that is different is the ON_NOTIFY_EX macro. It looks like:

#define ON_NOTIFY_EX(wNotifyCode, id, memberFxn) \
    { WM_NOTIFY, (WORD)(int)wNotifyCode, (WORD)id, (WORD)id, AfxSigNotify_EX, \
        (AFX_PMSG) \
        (static_cast< BOOL (AFX_MSG_CALL CCmdTarget::*)(UINT, NMHDR*, LRESULT*) > \
        (memberFxn)) },

并将在消息映射中显示为:

and would appear in the message map as:

ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTipText)

触发此消息映射条目时将调用的函数具有如下所示的界面:

The function that will be called when this message map entry is triggered has an interface that looks like:

BOOL CPCSampleView::OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult )

要触发此操作,您需要发送一条消息,例如:

To trigger this you would need to send a message such as:

TOOLTIPTEXT  myToolTipInfo = {0};

//  fill in the necessary data fields to identify the tool tip properly
myToolTipInfo.hdr.idFrom = ID_CONNECT_LAN_ON;  // set the id for which tool text to fetch
myToolTipInfo.hdr.code = TTN_NEEDTEXT;   // set the notify code
// ... other fields as appropriate

viewObject->SendMessage(WM_NOTIFY, idcControlId, &myToolTipInfo);

作为 规范WM_NOTIFY Windows 消息是:

as the specification for a WM_NOTIFY Windows message is:

wParam

发送消息的公共控件的标识符.这标识符不保证是唯一的.应用程序应该使用NMHDR 结构的 hwndFrom 或 idFrom 成员(作为lParam 参数)来识别控件.

The identifier of the common control sending the message. This identifier is not guaranteed to be unique. An application should use the hwndFrom or idFrom member of the NMHDR structure (passed as the lParam parameter) to identify the control.

lParam

指向包含通知的 NMHDR 结构的指针代码和附加信息.对于某些通知消息,这参数指向具有 NMHDR 结构的更大结构,如它的第一个成员.

A pointer to an NMHDR structure that contains the notification code and additional information. For some notification messages, this parameter points to a larger structure that has the NMHDR structure as its first member.

还有一个 ON_NOTIFY 消息映射宏,它具有与 ON_NOTIFY_EX 宏和消息处理程序不同的签名类型,AfxSigNotify_v具有与用于 ON_NOTIFY_EX 宏的接口不同的接口.但是,两者都使用 WM_NOTIFY Windows 消息 ID.它看起来像:

There is also an ON_NOTIFY message map macro which has a different type of signature, AfxSigNotify_v, than the ON_NOTIFY_EX macro and the message handler has a different interface than what is used for the ON_NOTIFY_EX macro. However both use the WM_NOTIFY Windows message id. It looks like:

#define ON_NOTIFY(wNotifyCode, id, memberFxn) \
    { WM_NOTIFY, (WORD)(int)wNotifyCode, (WORD)id, (WORD)id, AfxSigNotify_v, \
        (AFX_PMSG) \
        (static_cast< void (AFX_MSG_CALL CCmdTarget::*)(NMHDR*, LRESULT*) > \
        (memberFxn)) },