如果连这个问题你都能回答,那我只能说,我服了你! 你是我遇到过的最高的手!!!

CYQ_96 2001-07-26 04:36:13
像CDialog这些类,不论生成多少个实例对象,都可以分别向每个对象发送消息。

可我也从CWnd派生下的一个类,当我在它的构造函数中用CreatWindow创建窗口时,却发现窗口过程必须是个全局函数,至少也要是个静态成员函数。大家都知道,窗口过程中间应该有消息循环,当收到消息时,它负责处理。那假设我同时使用了这个类的N个实例a1,a2----an,发送个这个类的每个实例的消息都是发到窗口过程中的,但是这个窗口过程是个全局函数,它怎能知道哪个消息是给哪个实例对象的呢?

可是很明显,像CDialog这些类,不论生成多少个实例对象,每个对象都能正确收到发给它的消息,那CDialog类的窗口过程是如何实现的呢?简直不可能!!!

回答人多的话,我会逐渐加分,包您满意!
...全文
250 28 打赏 收藏 转发到动态 举报
写回复
用AI写文章
28 条回复
切换为时间正序
请发表友善的回复…
发表回复
azuo_lee 2001-07-27
  • 打赏
  • 举报
回复
azuo.lee@163.net
horris 2001-07-27
  • 打赏
  • 举报
回复
horris@163.net
CYQ_96 2001-07-27
  • 打赏
  • 举报
回复
其实大家讲的,几年前我几乎全在书上都看过,只是没能形成统一连续的观点。
特别是近两年都是在Delphi,VB环境下编程,对这些细节渐渐淡忘了,现在各位的帮助下正逐渐恢复状态,再一次感谢大家!

另:如能得到各位的Email地址,以后多多交流那就不胜荣幸了。
CYQ_96 2001-07-27
  • 打赏
  • 举报
回复
: horris(僧推月下门) : azuo_lee() 
现在终于知道,VC栏里谁是真正乐于助人的高手了,希望能和你们交个朋友。

我的Email:CYQ_96@etang.com
greensleeve 2001-07-27
  • 打赏
  • 举报
回复
hao
Tnny 2001-07-27
  • 打赏
  • 举报
回复
搞那么吓人的标题干嘛。

小儿科的问题,自己多看看书不就明白了吗?

kao!
Tnny 2001-07-27
  • 打赏
  • 举报
回复
kao,
horris 2001-07-27
  • 打赏
  • 举报
回复
有点错,重写一遍:

MFC和ATL实现的窗口回调过程的流程:
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)。
horris 2001-07-27
  • 打赏
  • 举报
回复
MFC和ATL实现的窗口回调过程的流程:
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)

sandro 2001-07-26
  • 打赏
  • 举报
回复
你要是用SDK做过程序的话,就应该知道,窗口过程的第一参数是窗口句柄,MFC中不管是将其封装成CWnd,还是CDialog,都可以从此参数中知道是哪一个实例,不仅仅是this指针的问题。
xiaosaner 2001-07-26
  • 打赏
  • 举报
回复
长见识
gbstar2021 2001-07-26
  • 打赏
  • 举报
回复
看看 mfc 的消息映射,每个消息对应的处理函数是一个类的成员函数(自然带有 this 指针)
至于怎样使全局的窗口过程调用类的成员函数,侯捷的深入浅出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 指向你的对象的成员函数(消息处理函数)

具体的太麻烦了,去看看《深入浅出 ...》 吧
azuo_lee 2001-07-26
  • 打赏
  • 举报
回复
你只是在对话框中添加了一个a类型的变量a1显然不行——就像我上面说的,此时的a1还只是一个C++的对象,而没有与任何实际的Windows窗口相关联,它自然响应不了任何消息——因为Windows消息是发给Windows窗口的,而决不是发给C++对象的!!!
你必须在发消息之前,用某种办法使C++对象与窗口关联。这里最好的办法就是调用a的方法Create来创建一个窗口。你加上Create以后再试试,就应该没有问题了。
CYQ_96 2001-07-26
  • 打赏
  • 举报
回复
To: azuo_lee() 
最后一种方法我喜欢,可是试过了,好象不行,所以我才想写窗口过程。

不过既然高手说可以,那肯定是我的方法错了,下面是我的详细做法,讲大侠指正!

先从CWnd派生一个新类a,在Class View中单击右键选择Add Windows Message Handle,选择增加WM_TIMER消息处理代码,内容为显示一个MessageBox。

然后测试能不能响应,方法如下:在一个对话框类中加一个数据成员a1类型为a,再加一个按钮,按下按钮时调a1.PostMessage(WM_TIMER,0,0);结果是编译通过,运行出错!!!好可怜啊,不知哪里做的不对???
azuo_lee 2001-07-26
  • 打赏
  • 举报
回复
你的大概意思就是要在窗口过程中处理每个窗口实例各不相同的相关数据。关于这个问题,解决的方案其实有很多:
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程序框架的支持,就寸步难行了。
CYQ_96 2001-07-26
  • 打赏
  • 举报
回复
To horris(僧推月下门) and everyone:
可能是我打字太慢了,等我刚打完下面这段话竟然已有10多位朋友回答了,不知下面的问题是否已被解决,先发了再说,大家别怪我没长眼,别人的回复都不看。

"把消息应发到的类的实例的指针(this)作为一个参数传给这个全局函数",这也是我想到的唯一解决办法,不过消息传递一样只有两个参数,this指针就用掉一个有点可惜。现在别人叫我做一个类,而且由于种种原因,摆明了要我从CWnd派生,摆明了要我创建一个窗口,摆明了要求发一个自定义的消息让我的类处理它,摆明了该消息有两个参数要传递。它显然希望用PostMessage(WM_OURMESSAGE,p1,p2)的方式向我发这个消息。我总不能跟它说,不行,你这个消息只能带一个参数过来,因为我需要一个参数传递this指针!

当然逼急了我也只好这么说,马急了还咬人呢,不过不到万不得已我还不想这么说。

况且我觉得如果我生成一个CDialog类的实例d1,想向它发消息时好象不用d1.PostMessage(WM_OURMESSAGE,&d1,p2);当然这我还没有试过,没有调查就没有发言权,等我先去试一下先。
但话又说回来,如果的确如此,那就要请各位大哥再开动聪明的大脑,想想它是怎样实现的了。
CYQ_96 2001-07-26
  • 打赏
  • 举报
回复
cyq_96你是不是有时间,看一下信箱。快点!!!
bighead 2001-07-26
  • 打赏
  • 举报
回复
to: horris(僧推月下门) 
我看atl用的只不过是一个庞大的switch罢了。
to:: WhiteWaterBlueSky(疯狂数码) 
azuo_lee() is right,一个线程只有一个消息泵

几乎每一个窗口都要用到defwindowproc(?),当然是根据参数里的HWND判断目的窗口了。

CYQ_96 2001-07-26
  • 打赏
  • 举报
回复
看一下信箱(lf)sina的
horris 2001-07-26
  • 打赏
  • 举报
回复
to: cloudshadow1(云影) :但是静态成员函数的this指针必须是显式声明的参数,编译器不为静态成员函数生成隐含的this参数。
加载更多回复(8)

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧