我正在为一个基于MFC的遗留应用程序(TestApp)构建一个测试应用程序(TestApp)。我试图模拟鼠标点击MFC-应用程序之间使用消息传递。我能够成功地从MFC-app菜单中弹出对话框。然而,当我试图模拟鼠标点击MFC -app的视图时,它似乎不起作用。
我的主要问题是,在尝试使用SendMessage、PostMessage函数与派生的CView类通信时是否存在已知的限制?还请注意,我正在重用ON_COMMAND()处理程序来处理我的消息,因为目标是使用相同的处理程序,该处理程序通过单击菜单选项通过TestApp调用。更多关于我尝试过的内容和我正在犯的错误的详细信息:
企图1。
TestApp:
*向MFC的CMainFrame发送消息,要求它用所需的输入打开CView。
MFCApp:
CMainFrame:使用以下方法检索CView (CDesignView)派生类及其HWND句柄的ptr :使用的https://support.microsoft.com/en-us/kb/108587代码如下所示:
CMDIChildWnd * pChild = MDIGetActive();
if ( !pChild )
return -1;
CView *pView = pChild->GetActiveView();
if (!pView) {
MessageBox(_T("Could not get a handle to the design"), _T("Test2 Error"), MB_OK);
return -1;
}
// Fail if view is of wrong kind
if ( !pView->IsKindOf( RUNTIME_CLASS(CDesignView) ) ) {
MessageBox(_T("View obtained is not of type DesignView"), _T("Test2 Error"), MB_OK);
return -1;
}
CDesignView* designView = (CDesignView*)pView ;
HWND view_hWnd = designView->m_hWnd ;
if (!view_hWnd) {
MessageBox(_T("designView handle could not be obtained"), _T("Test2 Error"), MB_OK);
return -1;
}但是,当我将这些用于SendMessage时,它会失败:
designView->PostMessageW(ID_DESIGN_xxx,NULL,NULL);
从来不调用ID_DESIGN_xxx处理程序。处理程序在CDesignView消息映射中声明如下:
ON_COMMAND(ID_DESIGN_xxx,OnXXX)
(注意:我正在重复使用MFCApp已经用于CDesignView上与此函数对应的菜单选项的处理程序,因为目标是测试它)
设计视图->OnStarOrder();
然而,这并不是我想要的行为,因为它涉及公开太多的View处理程序,也违背了测试应用程序与实际使用模型密切相关的目的。
designView->PostMessageW(WM_CLOSE,NULL,NULL);
这在此检查中出现异常失败: IsKindOf( RUNTIME_CLASS(CView)断言失败)。
企图2
我还试图让TestApp将消息发送到MFCApp CDesignView,而不是自己的MainFrame,就像上面描述的那样。因此,我使用CDerivedView消息将上述代码中的TestApp句柄view_hWnd传递给了TestApp。然后TestApp执行一个::SendMessage(view_hWnd,WM_CLOSE,NULL,NULL)。同样的错误也发生了。这种方法试图排除CDesignView在SendMessage时不是活动窗口的可能性。在本例中,在允许CView发送消息之前,我手动单击MFCApp的TestApp。
这些似乎都不起作用。你能给出的任何建议都会有很大的帮助。提前感谢!
发布于 2018-06-04 20:29:14
关于您的主要问题“尝试使用SendMessage、PostMessage函数与派生的CView类通信是否存在已知的限制”,答案是否定的。函数SendMessage()和PostMessage()是标准的Win32 API函数,用于向定义了窗口句柄的任何窗口提供消息。
--关于MFC的一点背景
大多数包装窗口的MFC类都是从某个时候的CWnd派生出来的。CWnd类用于包装Windows窗口,Win32 API与窗口一起使用。很多使用窗口句柄的Win32 API函数都有一个类似的CWnd类方法。
如果您查看CView的声明,您可以看到它是从CWnd派生出来的,它将这两个函数的一个版本作为方法。但是,CWnd的方法与Win32 API版本有不同的接口,因为它们消除了作为第一个参数的窗口句柄。
CWnd类声明看起来像
LRESULT CWnd::SendMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0);
这个方法在CWnd类中的实现可能是这样的:
LRESULT CWnd::SendMessage(UINT message, WPARAM wParam, LPARAM lParam)
{
return ::SendMessage (m_hWnd, message, wParam, lParam);
}其中,m_hWnd在CWnd类中定义为HWND m_hWnd;,是CWnd类正在包装的窗口句柄。
什么是消息映射
在MFC窗口类文件中,例如从CView派生的类中,将有一组类似于以下内容的源行:
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消息映射。
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[] = \
{它创建一组函数以及一个数组来将各种消息映射条目存储到其中。
END_MESSAGE_MAP宏提供消息映射条目数组的末尾,如下所示:
#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,如下所示:
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消息列表中进行迭代,以查看是否匹配。
如果它找到了Windows和适当的wParam值的匹配,那么它将通过为匹配的消息映射条目提供接口规范的适当参数的函数指针调用该函数。
包含数组条目源的ON_COMMAND宏如下所示:
#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条目,ON_COMMAND消息必须指定WM_COMMAND消息标识符。
MFC运行时知道,它将调用没有参数的消息处理程序,因为签名类型是AfxSigCmd_v,它是枚举AfxSig中的一个值,用于通知MFC运行时消息处理程序接口的外观。
如果查看ON_COMMAND处理程序的接口规范,就会发现没有参数,因此当MFC运行时调用指定的函数指针时,它不会提供任何参数。
因此,要使用ClassView类的方法SendMessage()发送SendMessage()消息,触发需要使用的viewObject的ClassView对象变量的ON_COMMAND(ID_DESIGN_xxx , OnXXX)的消息映射条目:
viewObject->SendMessage(WM_COMMAND, ID_DESIGN_xxx, 0);或者您可以将Win32 API用于:
::SendMessage (viewObject->m_hWnd, WM_COMMAND, ID_DESIGN_xxx, 0);另一个例子: ON_NOTIFY_EX
另一个不同的消息映射宏是ON_NOTIFY_EX宏。看上去:
#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)) },并将在消息地图中显示为:
ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTipText)触发此消息映射项时将调用的函数有一个接口,如下所示:
BOOL CPCSampleView::OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult )要触发这一点,您需要发送如下消息:
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);如 Windows message所示:
wParam 发送消息的公共控件的标识符。不能保证此标识符是唯一的。应用程序应该使用NMHDR结构的hwndFrom或idFrom成员(作为lParam参数传递)来标识控件。 lParam 指向包含通知代码和其他信息的NMHDR结构的指针。对于某些通知消息,此参数指向以NMHDR结构为其第一个成员的较大结构。
还有一个ON_NOTIFY消息映射宏,它与ON_NOTIFY_EX宏具有不同类型的签名AfxSigNotify_v,消息处理程序具有与ON_NOTIFY_EX宏不同的接口。但是,两者都使用WM_NOTIFY窗口消息id。看上去:
#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)) },https://stackoverflow.com/questions/32603409
复制相似问题