MFC在处理消息时,把消息应发到的类的实例的指针(this)作为一个参数传给这个全局函数。这样此函数就可以区别处理多个实例。窗口过程是全局函数,是因为在所有的此类的窗口实例存在时,都要求此函数有效,如果是类的成员函数,当实例销毁时,就不能访问此函数了。
解决方案 »
- 【问题】在VC.net对项目打包
- CoolPopupMenu类的小问题
- 关于dat格式的文件读取
- listCtrl问题,急需解决,请各位高手帮忙!
- 请问在剪贴板操作中,如何才能将自定义结构中的指针正确复制呢?
- 对话框资源和类误删除,编译报错,怎么补救?
- 怎样把一个整型数据用AfxMessageBox()显示给用户?整型数据可不可能为NULL型?如是NULL型,怎样判断?
- SOS!!数据丢失,救救我的程序!!!up者,有分!
- 急问:基于TCP的socket传输媒体流数据问题的解决
- 如何在windows2000下获得GDI资源的占用率?
- 如何知道在CListCtrl中选中了哪个CheckBox了呢?大送分。。。!!
- 可能是最难的问题了,我问了好久都没有人回答。 分求解300
编译器在进行原码的编绎时为每一个类的成员函数加上THIS指什,当然窗口过程也不例外,
这正是为什么只有一个版本的成员函可以处理不同的对象的原因(This的值不一样)!!!!!!!!
我看atl用的只不过是一个庞大的switch罢了。
to:: WhiteWaterBlueSky(疯狂数码)
azuo_lee() is right,一个线程只有一个消息泵几乎每一个窗口都要用到defwindowproc(?),当然是根据参数里的HWND判断目的窗口了。
可能是我打字太慢了,等我刚打完下面这段话竟然已有10多位朋友回答了,不知下面的问题是否已被解决,先发了再说,大家别怪我没长眼,别人的回复都不看。"把消息应发到的类的实例的指针(this)作为一个参数传给这个全局函数",这也是我想到的唯一解决办法,不过消息传递一样只有两个参数,this指针就用掉一个有点可惜。现在别人叫我做一个类,而且由于种种原因,摆明了要我从CWnd派生,摆明了要我创建一个窗口,摆明了要求发一个自定义的消息让我的类处理它,摆明了该消息有两个参数要传递。它显然希望用PostMessage(WM_OURMESSAGE,p1,p2)的方式向我发这个消息。我总不能跟它说,不行,你这个消息只能带一个参数过来,因为我需要一个参数传递this指针!当然逼急了我也只好这么说,马急了还咬人呢,不过不到万不得已我还不想这么说。况且我觉得如果我生成一个CDialog类的实例d1,想向它发消息时好象不用d1.PostMessage(WM_OURMESSAGE,&d1,p2);当然这我还没有试过,没有调查就没有发言权,等我先去试一下先。
但话又说回来,如果的确如此,那就要请各位大哥再开动聪明的大脑,想想它是怎样实现的了。
1。使用WndExtra字节。这在你注册窗口类时指定。窗口过程中可以根据HWND和GetWindowLong取得相应的数据,但这种方法不很方便;
2。使用Window Properties。这与第一种方法类似,比它稍稍方便一些,还是不怎么好用;
3。使用结构体存储数据,然后把其指针作为message的参数发给窗口过程。这是Windows中普遍使用的方法之一。不存在你说的“不行,你这个消息只能带一个参数过来”这种问题,因为这一个参数实际可以是几乎无限多的参数;
4。利用MFC的封装,将每个窗口特定的数据作为窗口类的成员变量,然后传递this指针,窗口过程通过this指针访问特定数据。这其实是第3种方法的变通,或叫做第3种方法的MFC实现。同理,这个this指针实际代表的参数个数理论上几乎是无限,因此不必为其占用了一个message参数而耿耿于怀;
5。根本就不要直接写什么窗口过程,而是直接在CWnd的派生类中处理你关心的消息。应用程序框架负责在接到消息时调用指定的message handler。这是最方便、简洁的办法,也是MFC推荐的做法——这些message handler都是非静态成员函数,存取成员变量更是得心应手。
还有一点要注意的是,上面说的前两种方法虽然不方便,但可以实现跨进程的通信,也就是说,你用这种方法可以实现全局窗口类的窗口过程;后两种方法虽然好用,但由于进程间地址空间的独立,通过传递指针访问其他进程的数据是不行的,因此,这种方法只能是在一个进程内部使用(当然,也可以通过DLL注入的方法实现变通的“伪进程间”通信)。至于最后一种方法,自不必说,好用是非常的好用,但一旦脱离了MFC程序框架的支持,就寸步难行了。
最后一种方法我喜欢,可是试过了,好象不行,所以我才想写窗口过程。不过既然高手说可以,那肯定是我的方法错了,下面是我的详细做法,讲大侠指正!先从CWnd派生一个新类a,在Class View中单击右键选择Add Windows Message Handle,选择增加WM_TIMER消息处理代码,内容为显示一个MessageBox。然后测试能不能响应,方法如下:在一个对话框类中加一个数据成员a1类型为a,再加一个按钮,按下按钮时调a1.PostMessage(WM_TIMER,0,0);结果是编译通过,运行出错!!!好可怜啊,不知哪里做的不对???
你必须在发消息之前,用某种办法使C++对象与窗口关联。这里最好的办法就是调用a的方法Create来创建一个窗口。你加上Create以后再试试,就应该没有问题了。
至于怎样使全局的窗口过程调用类的成员函数,侯捷的深入浅出mfc....讲的再清楚不过了DECLARE_MESSAGE_MAP() 声明了一个消息处理的大表(静态的)
static const AFX_MSGMAP_ENTRY _messageEntries[];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)
};在消息映射表中会为每一个消息的处理填充这样一个结构,pfn 指向你的对象的成员函数(消息处理函数)具体的太麻烦了,去看看《深入浅出 ...》 吧
1.Windows消息(HWND,msg,wparam,lparam) -> 2.由HWND找到它对应的CWnd(对ATL是CWindowImpl)给pThis -> 3.调CWnd的静态成员函数CWnd::WndProc(可能是这个名字啊),这个函数的参数是:(pThis,msg,wparam,lparam) -> 4.WndProc解析msg,wparam,lparam,调用消息影射中定义的消息响应函数。消息影射的宏实际上就是在WndProc中引入一大堆case语句。to bighead(累了) :
我想我们讨论的是第二步,如何由HWND找到CWnd.MFC在每个CWnd实例产生时,都填写一个CMap类型的相关表,填入CWnd类实例的指针和HWND。第二步就是由HWND查表得到CWnd类实例的指针。应当说查CMap表是相当快的,且与表的元素多少没太大关系,但是当表的元素多时很显然占用的空间比较多。我看过一本书《ATL Internals》,里面介绍ATL处理这个问题比较有技巧,几乎没用额外的空间,你有兴趣可以看ATL的源码。to CYQ_96()只是路过而已():
我明白你是要干什么了,其实很简单,用不着自已编窗口过程,有现成的消息影射:
ON_MESSAGE( <message>, <memberFxn> )
其响应函数原型:
afx_msg LRESULT memberFxn(WPARAM, LPARAM);
你只要从CWnd派生,然后手工在头文件和实现文件中添加这个消息影射和响应函数,好象ClassWizard不支持ON_MESSAGE,具体步骤:
在头文件的
DECLARE_MESSAGE_MAP()
前加入
afx_msg LRESULT OnYourmsg(WPARAM, LPARAM);
在实现文件的
END_MESSAGE_MAP()
前加入
ON_MESSAGE( your msg id, OnYourmsg )
最后,在实现文件中加入OnYourmsg成员函数的函数体。
如果是自定义的消息,不是标准Windows消息,则要把ON_MESSAGE换成ON_REGISTERED_MESSAGE(your msg id, OnYourmsg)。如何你没有消息ID,只有消息的文字名称则要在实现文件中加入一个全局变量:
const UINT mymsg = RegisterWindowMessage( "WM_YOURMSG" );
而宏换成:
ON_REGISTERED_MESSAGE(your msg id, OnYourmsg)
1.Windows消息(HWND,msg,wparam,lparam) -> 2.由HWND找到它对应的CWnd(对ATL是CWindowImpl)给pThis -> 3.调CWnd的静态成员函数CWnd::WndProc(可能是这个名字啊),这个函数的参数是:(pThis,msg,wparam,lparam) -> 4.WndProc解析msg,wparam,lparam,调用pThis的消息影射中定义的消息响应函数。消息影射的宏实际上就是在WndProc中引入一大堆case语句。to bighead(累了) :
我想我们讨论的是第二步,如何由HWND找到CWnd.MFC在每个CWnd实例产生时,都填写一个CMap类型的相关表,填入CWnd类实例的指针和HWND。第二步就是由HWND查表得到CWnd类实例的指针。应当说查CMap表是相当快的,且与表的元素多少没太大关系,但是当表的元素多时很显然占用的空间比较多。我看过一本书《ATL Internals》,里面介绍ATL处理这个问题比较有技巧,几乎没用额外的空间,你有兴趣可以看ATL的源码。to CYQ_96()只是路过而已():
我明白你是要干什么了,其实很简单,用不着自已编窗口过程,有现成的消息影射:
ON_MESSAGE( <message>, <memberFxn> )
其响应函数原型:
afx_msg LRESULT memberFxn(WPARAM, LPARAM);
你只要从CWnd派生,然后手工在头文件和实现文件中添加这个消息影射和响应函数,好象ClassWizard不支持ON_MESSAGE,具体步骤:
1.在头文件的
DECLARE_MESSAGE_MAP()
前加入
afx_msg LRESULT OnYourmsg(WPARAM, LPARAM);
2.在实现文件的
END_MESSAGE_MAP()
前加入
ON_MESSAGE( your msg id, OnYourmsg )
3.最后,在实现文件中加入OnYourmsg成员函数的函数体。
如果没有自定义的消息的ID,只有消息的文字名称,则要在实现文件中加入一个全局变量:
const UINT mymsgid = RegisterWindowMessage( "WM_YOURMSG" );把ON_MESSAGE换成ON_REGISTERED_MESSAGE(mymsgid, OnYourmsg)。
现在终于知道,VC栏里谁是真正乐于助人的高手了,希望能和你们交个朋友。我的Email:[email protected]
特别是近两年都是在Delphi,VB环境下编程,对这些细节渐渐淡忘了,现在各位的帮助下正逐渐恢复状态,再一次感谢大家!另:如能得到各位的Email地址,以后多多交流那就不胜荣幸了。