MFC_消息传递方法
- 格式:doc
- 大小:98.00 KB
- 文档页数:4
在MFC中实现子窗体向父窗体传递参数的几种方法简述典型问题举例窗体和子窗体均有一个Edit控件和一个按钮,点击父窗体按钮显示子窗体;点击子窗体按钮后,子窗体中Edit控件的值显示在在父窗体中的Edit控件中。
在MFC中实现子窗体向父窗体传递参数的几种方法简述1、在父窗体定义静态变量2、传窗体的指针给子窗体3、子窗体调用GetParent4、向父窗体sendMessage方法1,使用静态变量,如果有多个子对象和父对象存在时,处理比较麻烦。
方法2, 传指针给子窗体,子窗体需要另外保存这个指针,此方法可由方法3替代。
方法3, 比方法2优,但与方法2都与父窗体耦合较深。
方法4,推荐采用方法;采用这种方法,子窗体可以放到任何父窗体上,只要父窗体响应此消息即可。
示例源码通过子窗体调用GetParent向父窗体传递参数的示例GetParent()->SetDlgItemText(IDC_EDIT1,TCHAR *)通过向父窗体发送消息(sendMessage)来传递参数示例SendMessage的基本结构如下SendMessage(HWND hWnd, //消息传递的目标窗口或线程的句柄。
UINT Msg, //消息类别(这里可以是一些系统消息,也可以是自己定义,下文具体介绍,)WPARAM wParam, //参数1 (WPARAM 其实是与UINT是同种类型的,//在vc编译器中右键有个“转到WPARAM的定义”的选项可以查看。
LPARAM lParam); //参数2其中一些参数的说明如下://typedef unsigned int UINT;//typedef UINT WPARAM;//typedef LONG LPARAM;//typedef LONG LRESULT;可以用以下语句发送消息:::SendMessage(this->m_hWnd, WM_MY_DOSOME, (WPARAM) 0, (LPARAM) 0);这里我发送的消息是本窗体接收的,所以句柄用:this->m_hWnd。
[原]关于MFC中父窗口与子窗口子窗口与子窗口之间的信息传递及控制2013-6-25阅读5993评论1因为项目的需要,某子窗口B的设置变动,经常需要联动其他子窗口C,或者父窗口A控件的名称更新,数据更新等等问题。
再网上查了许久,不得解,特抛砖引玉,提供几种思路。
以下都以A为父窗口,A1为A中的Tab控件,B和C为子窗口被非模态创建于A1上,所以之间的关系为A|A1 A2 A3 (An为A上控件)|B C|C1 C2 C3 (Cn 为C上控件)一、发送消息1、自定义消息,网上很多/s/blog_4a1695ff0100ckgo.html自定义消息中,加入自己要更新的消息内容,如果控件颜色,文字等等。
2、在A类中定义C类的对象page2即可通过调用page2.SendMessage(WM_MYMSG, NULL, NULL); 实现。
二、如果在C中的控件要控制A2的数据显示。
GetParent()->GetParent()->SetDlgItemText(A2, "XXXXX"); 实现。
其中,第一个getparent()获得A1的窗口指针,第二个getparent()获得A的窗口指针。
三、通过二可以知道,其实每个控件都是一个子窗口,它可以包含其他子窗口,成为Parent.我们通过GetParent()或的A1的窗口指针之后,可以通过FindWindow()等其他方式获得C的窗口指针,然后进行如二中的操作。
四、刚发现的一种方式,比如主对话框中MainDlg.cpp 中,子类或者对话框中Page.cpp中使用主对话框的资源。
1、在MainDlg.cpp中传输自己的对象到Page.cpp中。
PageX.SetDlgPtr(this);2、在Page.cpp中成员函数:void SetDlgPtr(class MainDlg *p){ m_pDlg = p; } 成员变量: class MainDlg *m_pDlg;3、使用m_pDlg使用MainDlg中的函数控制控件的显示信息。
MFC自定义消息步骤MFC(Microsoft Foundation Classes)是Microsoft公司为Windows平台开发的C++类库,它封装了许多Windows API函数,简化了Windows应用程序的开发过程。
在MFC中,可以使用自定义消息来进行应用程序内部的消息传递。
自定义消息的步骤如下:1. 定义消息常量:首先,在需要使用自定义消息的地方(通常是对话框或视图类中),定义一个用于表示自定义消息的整型常量。
可以使用WM_USER作为基准值,如const UINT WM_MY_MESSAGE = WM_USER + 12. 注册消息:在应用程序启动时,通常在InitInstance函数中,使用CWinApp类的RegisterWindowMessage函数来注册自定义消息,该函数用于获取一个唯一的消息值,如:UINT myMessage = RegisterWindowMessage(LPCTSTR pString).3. 处理消息:在需要处理自定义消息的类中,重写消息处理函数(通常是OnWndMsg函数),根据自定义消息的值,对相应的消息进行处理。
如:BEGIN_MESSAGE_MAP(CMyDialog, CDialog)ON_WM_COPYDATA//...ON_REGISTERED_MESSAGE(myMessage, OnMyMessageHandler)END_MESSAGE_MAPLRESULT CMyDialog::OnMyMessageHandler(WPARAM wParam, LPARAM lParam)//处理自定义消息//...return 0;4. 发送消息:要发送自定义消息,可以使用CWnd类的PostMessage或SendMessage函数。
其中,PostMessage函数用于异步发送消息,而SendMessage函数用于同步发送消息。
(1) 异步发送消息(PostMessage):CWnd* pDestWnd = GetDlgItem(IDC_MY_CONTROL);pDestWnd->PostMessage(myMessage, wParam, lParam);(2) 同步发送消息(SendMessage):CWnd* pDestWnd = GetParent(;pDestWnd->SendMessage(myMessage, wParam, lParam);5.消息映射宏:在使用消息映射宏处理自定义消息时,需要使用ON_REGISTERED_MESSAGE宏,该宏会自动在消息映射表中添加对应的消息处理函数。
用MFC实现的飞信给好友发送短信接口声明:本文摘自/showtopic-25343.html,转载请注明出处这段时间,我在学习vc。
以前一直是在用C#和Java的,最近发现MFC还是有一定的用处的,所以就利用暑假这段时间来学习一下。
但是光看书没有用,几个月之前,我用C#实现了一个飞信发短信的接口。
所以这次,以学习MFC为目的,写了一个MFC版的飞信发短信接口。
开发工具用的是Visual studio 2005。
其中用到了MFC中的众多功能,如Socket、CString类的使用、Winnet、加密(hash)、ATl提供的正则表达式库和调用Dom解析xml等等。
最后,我将该接口做成了一个MFC dll,从而也学习了MFC dll的制作和使用。
编译的时候采用默认的Unicode编码。
另外,其中还涉及到编码的转换等等。
在处理字符串的时候基本都用CString,不知道这种习惯好不好。
接口中只提供一个CFetion类,其中提供3个函数,功能主要登陆、发送短信和登出,相当简单,一看就明白。
由于其中调用了Com,所以调用的时候需要进行Com的初始化工作。
下面是一个使用的例子:#include "Fetion.h"#pragma comment(lib, "MFCFetionSDK.lib")CoInitialize(NULL);CFetion fetion(_T("你的手机号"), _T("你的密码"));fetion.Login();fetion.SendSMSToPhone(_T("好友手机号"), _T("要发送的消息。
"));fetion.Logout();CoUninitialize();速度方面,我测试一下,还是相当快的,占的内存也非常的少。
关于飞信协议方面,还是采用MD5进行加密的,改成SHA1也相当简单。
用户自定义消息SendMessage的使用这里主要讲一下mfc中SendMessage的使用方法。
传递消息主要分4步:1.在类的定义中声明消息函数:afx_msg void AAA();2.在相应的cpp文件中的MESSAGE_MAP区域内添加ON_MESSAGE(MESSAGE_ID,AAA),其中参数1为要传递消息的ID,参数2为刚刚声明的函数名称,不用带括号。
3.实现消息函数:在cpp文件中添加LRESULT 类名::AAA(WPARAM wparam,LPARAM lparam){执行内容……return 0;}4.发送消息:在需要发送消息的地方添加下列语句:HWND hWnd = ::FindWindowEx( m_hWnd, NULL, NULL, WINDOW_TEXT ) ;FromHandle(hWnd)->SendMessage(MESSAGE_ID,a,b);其中,m_hWnd为接收消息的父窗口的句柄,WINDOW_TEXT为接收消息窗口的标题,得到的hWnd为接收消息窗口的句柄。
调用该窗口的SendMessage 函数,MESSAGE_ID为刚刚设定的消息ID,a和b是要传递的参数。
注:在这4个步骤中,前三个我在做的时候基本没什么障碍。
问题主要出现在第4步。
开始找到网上的例子给的都是FindWindow函数,怎么用都不好使。
后来看到有人说FindWindow是找操作系统下打开的窗口的句柄,找窗口中子窗口要用FindWindowEx函数。
我也尝试过用对话框的ID找到相应的句柄,像GetDlgItem(ID)函数一样,未果。
我使用的对话框都是没有标题栏的,所以也就没有窗口的标题,当然这并不会影响我设置标题。
只要在生成该窗口的区域内添加SetWindowText(“窗口标题”)就可以了。
也就是说窗口标题可以设置,但是不会显示。
最后一点在SendMessage()函数中,MFC默认传递的参数是WPARAM和LPARAM型(一个是UINT型,一个LONG型),如果要传递浮点类型,或者其它不是整数的类型,就可以用指针的形式传递(如果发送方只是申请一个变量并以地址的形式传递,然后接收方以指针的形式接收,如果在执行完SendMessage 之后原函数体立即结束了,我不知道在接收函数体接收和使用该变量的之间的一瞬间,该内存区域会不会被占用,我觉得还是有这种可能的。
何谓消息、消息处理函数、消息映射?消息简单的说就是指通过输入设备向程序发出指令要执行某个操作。
具体的某个操作是你的一系列代码。
称为消息处理函数。
在SDK中消息其实非常容易理解,当窗口建立后便会有一个函数(窗口处理函数)开始执行一个消息循环,我们还可以清楚的看到消息处理的脉络。
一个switch case语句就可以搞定,消息循环直到遇到WM_QUIT消息才会结束,其余的消息均被拦截后调用相应的处理函数。
但在封装了API的MFC中,消息似乎变的有些复杂了,我们看不到熟悉的switch case语句了,取而代之的是一个叫消息映射的东西。
为什么MFC 要引入消息映射机制,你可以想象一下,在现在的程序开发活动中,你的一个程序是否拥有多个窗体,主窗口就算只有一个,那菜单、工具条、控件这些都是子窗口,那我们需要写多少个switch case,并且还要为每个消息分配一个消息处理函数,这样做是多么的复杂呀。
因此MFC采用了一种新的机制。
利用一个数组,将窗口消息和相对应的消息处理函数进行映射,你可以理解成这是一个表。
这种机制就是消息映射。
这张表在窗口基类CWnd定义,派生类的消息映射表如果你没有动作它是空的,也就是说如果你不手工的增加消息处理函数,则当派生窗口接受一个消息时会执行父类的消息处理函数。
这样做显然是高效的。
MFC提供的消息结构同时MFC定义了下面的两个主要结构:AFX_MSGMAP_ENTRYstruct AFX_MSGMAP_ENTRY{UINT nMessage; // Windows消息的ID号UINT nCode; // 控制消息的通知UINT nID; // Windows控制消息的IDUINT nLastID; //表示是一个指定范围的消息被映射的范围UINT nSig; //表示消息的动作标识AFX_PMSG pfn; // 指向消息处理函数的指针};AFX_MSGMAPstruct AFX_MSGMAP{#ifdef _AFXDLLconst AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();#elseconst AFX_MSGMAP* pBaseMap;#endifconst AFX_MSGMAP_ENTRY* lpEntries;};///AFX_MSGMAP可以得到基类的消息映射入口地址和得到本身的消息映射入口地址。
消息映射的实现Windows消息概述Windows应用程序的输入由Windows系统以消息的形式发送给应用程序的窗口。
这些窗口通过窗口过程来接收和处理消息,然后把控制返还给Windows。
消息的分类队列消息和非队列消息从消息的发送途径上看,消息分两种:队列消息和非队列消息。
队列消息送到系统消息队列,然后到线程消息队列;非队列消息直接送给目的窗口过程。
这里,对消息队列阐述如下:Windows维护一个系统消息队列(System message queue),每个GUI线程有一个线程消息队列(Thread message queue)。
鼠标、键盘事件由鼠标或键盘驱动程序转换成输入消息并把消息放进系统消息队列,例如WM_MOUSEMOVE、WM_LBUTTONUP、WM_KEYDOWN、WM_CHAR等等。
Windows 每次从系统消息队列移走一个消息,确定它是送给哪个窗口的和这个窗口是由哪个线程创建的,然后,把它放进窗口创建线程的线程消息队列。
线程消息队列接收送给该线程所创建窗口的消息。
线程从消息队列取出消息,通过Windows把它送给适当的窗口过程来处理。
除了键盘、鼠标消息以外,队列消息还有WM_PAINT、WM_TIMER和WM_QUIT。
这些队列消息以外的绝大多数消息是非队列消息。
系统消息和应用程序消息从消息的来源来看,可以分为:系统定义的消息和应用程序定义的消息。
系统消息ID的范围是从0到WM_USER-1,或0X80000到0XBFFFF;应用程序消息从WM_USER(0X0400)到0X7FFF,或0XC000到0XFFFF;WM_USER到0X7FFF范围的消息由应用程序自己使用;0XC000到0XFFFF范围的消息用来和其他应用程序通信,为了ID的唯一性,使用::RegisterWindowMessage来得到该范围的消息ID。
消息结构和消息处理消息的结构为了从消息队列获取消息信息,需要使用MSG结构。
SendMessage函数功能:该函数将指定的消息发送到一个或多个窗口。
此函数为指定的窗口调用窗口程序,直到窗口程序处理完消息再返回。
而函数PostMessage不同,将一个消息寄送到一个线程的消息队列后立即返回。
函数原型 :LRESULT SendMessage(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM IParam);参数:hWnd:其窗口程序将接收消息的窗口的句柄。
如果此参数为HWND_BROADCAST,则消息将被发送到系统中所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口和弹出式窗口,但消息不被发送到子窗口。
wMsg用于区别其他消息的常量值,这些常量可以是Windows单元中预定义的常量,也可以是自定义的常量.wParam通常是一个与消息有关的常量值,也可能是窗口或控件的句柄lParam通常是一个指向内存中数据的指针。
由于WParm、lParam和Pointer 都是32位的,因此,它们之间可以相互转换返回值:返回值指定消息处理的结果,依赖于所发送的消息。
SendMessage用例1.系统消息(WM_)::SendMessage(this->m_hWnd,WM_CLOSE,0,0);SendMessage(hWnd,WM_KEYDOWN,VK_TAB,0x000f0001);SendMessage(hWnd,WM_CHAR,VK_TAB,0x000f0001);SendMessage(hWnd,WM_KEYUP,VK_TAB,0xc00f0001);SendMessage(hWnd,WM_KEYDOWN,VK_TAB,0x000f0001);SendMessage(hWnd,WM_CHAR,VK_TAB,0x000f0001);SendMessage(hWnd,WM_KEYUP,VK_TAB,0xc00f0001);SendMessage(hWnd,WM_KEYDOWN,VK_TAB,0x000f0001);SendMessage(hWnd,WM_CHAR,VK_TAB,0x000f0001);SendMessage(hWnd,WM_KEYUP,VK_TAB,0xc00f0001);SendMessage(hWnd,WM_KEYDOWN,VK_RETURN,0x001c0001); SendMessage(hWnd,WM_CHAR,VK_RETURN,0x001c0001);SendMessage HWND, WM_SHOWWINDOW, SW_HIDE, vbNull '隐藏窗体SendMessage HWND, WM_SHOWWINDOW, SW_NORMAL, vbNull '显示窗体SendMessage(HWND, WM_SYSCOMMAND, SC_CLOSE, ByVal 0&) '关闭SendMessage(HWND, WM_SYSCOMMAND, SC_MINIMIZE, ByVal 0&) '最小化SendMessage(HWND, WM_PASTE, 0, 0) '粘贴SendMessage(HWND, WM_COPY, 0, 0) '复制SendMessage(HWND, WM_UNDO, 0, 0) '撤消2.通告消息比如:给资源ID为IDC_BUTTON2的按钮,发送点击消息:SendMessage(WM_COMMAND,MAKELONG(IDC_BUTTON2,BN_CLICKED),(LPARAM)(GetDlgItem(IDC_BUTTON2)-> GetSafeHwnd()));或:::SendMessage(m_hWnd,WM_COMMAND,MAKELONG(IDC_BUTTON2,BN_CLICKED),(LPARAM)(GetDlgItem(IDC_BUTTON2)-> GetSafeHwnd()));例:给菜单ID为ID_GET的菜单项,发送消息::SendMessage(AfxGetMainWnd()->m_hWnd,WM_COMMAND,ID_GET,NULL);3.用户自定义消息SendMessge(WM_MYMSG,0,0);或:::SendMessge(::AfxGetMainWnd()->m_hWnd,WM_MYMSG,0,0);4.向其他应用程序发送消息也可以为其他应用程序发送消息,前提是找到窗体的句柄,如:与FindWindow()函数一起使用;如:CString str="360w.txt -记事本";//向窗口为str的记事本窗口发送WM_CLOSE消息CWnd *pWnd=CWnd::FindWindow(NULL,str);//获取目的窗口对象::SendMessage(*pWnd,WM_CLOSE,0,0);窗口标题的获取方法:1.使用VC++自带工具SPY++2.编程实现,可用EnumWindows函数实现;详见“枚举所有窗体,并向打开的窗体发送关闭消息”举例:HWND gameh=NULL;gameh=::FindWindow(NULL,"窗口标题");//参看游戏的标题.可以用vc6.0自带的Spy++工具查看CWnd* pWnd = CWnd::FromHandle(gameh);//在坐标为(x,y)的点,发送鼠标按下消息//注意,x,y是客户区的坐标::SendMessage(*pWnd,WM_LBUTTONDOWN,0,(y<<16)+x);//发送鼠标移动消息,鼠标移动到点(x,y)::SendMessage(*pWnd,WM_MOUSEMOVE,0,MAKELONG(x,y));//发送粘贴消息::SendMessage(dlg_hwnd,WM_PASTE,0,0);5. 发送自己注册的消息5.1 发送端:本示例先通过RegisterWindowMessage函数来注册一条消息,然后用Win32 API函数SendMessage()发送。
软件英才网软件行业驰名招聘网站命令传递(Command routing)消息如果是仅仅从派生类流向父类,那就非常简单了。
然而MFC用来处理消息的C++类,并不是单线发展的。
document/view也具有处理消息的能力。
因此,消息应该有横向流动的机会。
MFC对消息循环的规定为:1:若是一般的windows消息(WM_xx)则一定是由派生类流向基类。
2:如果是WM_COMMAND消息,就非常复杂了。
要区分接受者的类型:1:接受者若为Frame窗口:处理次序为:View-> Frame窗口本身->CWinApp类。
2:接受者若为View :处理次序为:View本身->Document;3:接受者若为Document:处理次序为:Document本身->Document template软件英才网软件行业驰名招聘网站因此,接下来我们的任务就是仿真以上的消息传递路线。
以下为需要添加的函数:全局函数AfxWndProc,它是整个消息循环的起始点,本来应该在CWinThread::Run中被调用,每调用一次就推送一个消息。
模拟windows的disPatch函数。
软件英才网软件行业驰名招聘网站LRESULT AfxWndPro(HWND hWnd,UINT nMsg,WPARAMwParam,LPARAM lParam,CWnd *pWnd) {cout<<"AfxWndProc()"<<endl;return AfxCallWndProc (pWnd,hWnd,nMsg,wParam,lParam); }LRESULT AfxCallWndProc(CWnd*pWnd,HWND hWnd,UINT nMsg,WPARAM wParam,LPARAM lParam)软件英才网软件行业驰名招聘网站{cout<<"AfxCallWndProc"<<endl;LRESULT lResult=pWnd->windowProc(nMsg,wParam,lParam);return lResult;}全局函数AfxCallWndProc用于调用接受消息的类的消息处理函数。
背景:新建了一个基于对话框的MFC程序,在主对话框中添加tabcontrol控件,又新建了两个Dialog(CDialog1和CDialog2),将它们设为tabcontrol控件的子对话框。
目的:两个子对话框之间传递消息,子对话框与主对话框传递消息。
方法:第一步: 定义消息.
在目标窗口类的头文件或者stdafx.h中添加:#define
WM_MY_MESSAGE (WM_USER+100); 推荐用户自定义消息至少是WM_USER+100,因为很多新控件也要使用WM_USER消息。
第二步: 在目标类头文件的AFX_MSG块中说明消息处理函数: afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
view plaincopy to clipboardprint?
1.class CDialog1:public CDialog
2.{
3....
4.// 一般消息映射函数
5.protected:
6.// {{AFX_MSG(CDialog)
7. virtual BOOL OnInitDialog();
8. afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
9. afx_msg void OnPaint();
10. afx_msg HCURSOR OnQueryDragIcon();
11.afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
12.//}}AFX_MSG
13.DECLARE_MESSAGE_MAP()
14.}
第三步:在目标类源文件cpp中,使用ON_MESSAGE宏指令将消息映射到消息处理函数中。
view plaincopy to clipboardprint?
1.BEGIN_MESSAGE_MAP(CDialog1, CDialog)
2. ON_WM_SYSCOMMAND()
3. ON_WM_PAINT()
4. ON_WM_QUERYDRAGICON()
5.ON_MESSAGE(WM_MY_MESSAGE, OnMyMessage)
6.//}}AFX_MSG_MAP
7.END_MESSAGE_MAP()
1.LPESULT CDialog1::OnMyMessage(WPARAM wParam, LPARAM lParam)
2.{
3.// TODO: 处理用户自定义消息
4.//MessageBox("消息传递完成!");
5.return 0;
6.}
第五步:发送消息时,在源地址类CDialog2的CPP文件中(如一个Button),调用函数PostMessage或SendMessa
ge发送消息。
PoseMessage(WM_MY_MESSAGE,O,O); SendMessage(WM_MY_MESSAGE,O,O);
此时需要注意::::
假如主对话框的类名:CSecondShimDlg,两个子对话框的类名CDialog1和CDialog2;
. 要实现两个子对话框之间进行通信(CDialog2向CDialog1发送消息,目标类即为CDialog1),则在CDialog2源文件中的发送函数应该这么写:
view plaincopy to clipboardprint?
1.CSecondShimDlg * m_Host = (CSecondShimDlg*)AfxGetMainWnd();
2.m_Host->m_Diag1.SendMessage(WM_MY_MESSAGE , wparam, lparam);//这里要注意是m_Diag1,它
是在主对话框类中定义的一个CDialog1对象,即目标对象。
1.CSecondShimDlg * m_Host = (CSecondShimDlg*)AfxGetMainWnd();
2.m_Host->SendMessage(WM_MY_MESSAGE , wparam, lparam);
view plaincopy to clipboardprint?
1.::SendMessage(this->GetParent()->GetParent()->m_hWnd, WM_MY_MESSAGE ,wparam, lparam)
;
2. // SendMessage函数的第一个参数是目标窗口的句柄。
之所以要用两个GetParent()因为Dialog2
的父对话框为TabControl,TabControl的父对话框为主对话框CSecondShimDlg。