对消息机制仍然存在的几点迷惑,希望大家进来谈谈

ydyd 2003-09-29 05:42:32
1.是不是函数名前加CALLBACK(__stdcall)就是回调函数,怎么c的语法书上没有看到呢?函数名和返回类型间还可以加东西?

2.GetMessgae()函数是不是搜索所有的系统消息队列和程序消息队列?还是每个程序都有自己的消息队列,并在自己的内存区?

3.当鼠标通过单击激活一个窗口时,这个消息是怎么处理的,谁处理的?是不是点下去时操作系统就标明了此消息所属的窗口?

4.程序与程序间是怎么发送和处理消息的?一个时刻只有一个线程获得cpu啊。

暂时这么多,希望大家来指点或提出自己的疑问。
...全文
43 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
ydyd 2003-09-30
  • 打赏
  • 举报
回复
to codewarrior

“如果那个将会处理这个消息的任务在休眠之中,会被唤醒。这个新近被唤醒的任务不会在此刻立即运行,只会标记为准备运行,然后插入就绪队列中等待系统调度。如果消息前往了其它任务,并且在系统队列中没有要处理的事件被发现,“系统队列扫描”会代码返回到GetMessage/PeekMessage主代码。”

我看了,但是我学的太浅,有些不懂。消息发给你处理这个消息的任务后还会前往其他任务吗?

我来谈谈我对鼠标单击的看法和不解的地方:
比如我开了两个IE窗口,IE1,IE2,我现在浏览的是IE2,现在我用鼠标点击IE1

1.如你所说,系统从头至尾的扫描细统中的每一个窗体(包括子窗体),直到找到一个包含这个鼠标坐标点的窗体,并且这个窗体没有任何同样包含这个坐标点的子窗体。
那么这条消息的窗口句柄是不是就是这个被找到的窗体的句柄?任务栏是非客户区吗?是的话我点击IE1的任务栏图标,它怎么映射到IE1的窗口呢?

2.IE1窗口被激活,开始处理自己的消息。


以前就会照着书上的例子用mfc,感觉什么都没学到,现在重学,觉得如果能控制所有的消息才能控制windows系统和自己的程序

谢谢codewarrior(会思考的草)的指点,可能我问的问题古怪的近乎愚蠢。
会思考的草 2003-09-30
  • 打赏
  • 举报
回复
系统队列的消息是由驱动程序产生的。
qitiandasheng 2003-09-30
  • 打赏
  • 举报
回复
to: 94120144(错过了就没有呢)
那个hwnd是消息所在线程窗口的句柄,关键是你要搞清楚你的应用程序有几个线程,照你所述,如果一个窗口中点击,激活另一个窗口,这个时候所发的消息肯定是属于第一个线程,自然就会扔出来WM_CREAT,程序中代码响应就是了。
gully 2003-09-30
  • 打赏
  • 举报
回复
请问如何将消息传入系统队列?
比如将WM_DEVICECHANGE传给windows 强制使其刷新,这种方法行得通吗?
gully 2003-09-30
  • 打赏
  • 举报
回复
请问如何将消息传入系统队列?
比如将WM_DEVICECHANGE传给windows 强制使其刷新,这种方法行得通吗?
wy5622 2003-09-30
  • 打赏
  • 举报
回复
up
zhang865 2003-09-30
  • 打赏
  • 举报
回复
郁闷,玩了两年编程了,对消息机制还是不明白,学习
会思考的草 2003-09-30
  • 打赏
  • 举报
回复
补充ruihuahan(飞不起来的笨鸟):
只有GUI线程才有消息队列。对Windows来说,所有的线程都是一样的,但MFC把线程分为GUI线程和Worker线程,Worker线程是没有消息队列的,一旦一个Worker线程有了消息队列,它就成为GUI线程。
zgh266 2003-09-30
  • 打赏
  • 举报
回复
mark
94120144 2003-09-30
  • 打赏
  • 举报
回复
消息的结构如下:
typedef struct tagMSG { // msg
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG;
________________________________
问:在楼主提出的第三问中,
如果一个窗口中点击,激活另一个窗口,这个时候所发的消息中,上述结构中的 HWND hwnd;是指向源窗口的句柄还是新窗口的句柄

ruihuahan 2003-09-30
  • 打赏
  • 举报
回复
消息队列和堆栈一样都是线程相关的,每个线程都可以有自己的消息队列,每个线程的消息循环只从自己的消息队列中取得消息。
会思考的草 2003-09-30
  • 打赏
  • 举报
回复
“如果那个将会处理这个消息的任务在休眠之中,会被唤醒。这个新近被唤醒的任务不会在此刻立即运行,只会标记为准备运行,然后插入就绪队列中等待系统调度。如果消息前往了其它任务,并且在系统队列中没有要处理的事件被发现,“系统队列扫描”会代码返回到GetMessage/PeekMessage主代码。”
这段你有没有仔细看?????
会思考的草 2003-09-30
  • 打赏
  • 举报
回复
to ydyd
1.去掉CALLBACK肯定不行,这样编译的时候产生的代码是错误的,你还是需要从汇编级别理解它。
2.鼠标键盘等输入设备的事件,是由设备驱动程序转换成输入消息,并放入系统消息队列的。Windows每次从系统队列中取出一个消息,然后再判断它是送给哪个窗口的和这个窗口是有哪个线程创建的(至于如何判断该消息应该由哪个窗口处理,参见我前面的分析),然后把该消息放入对应窗口的线程的线程消息队列。
ydyd 2003-09-29
  • 打赏
  • 举报
回复
“1、只有当你把一个函数当作回调函数来用时,它才是回调函数,与CALLBACK标记无关
CALLBACK WINAPI这些东西主要是为了表明这个函数将怎么用”

如果去掉WndProc函数前的CALLBACK也行吗,在其他地方回调函数怎么用呢?

鼠标消息属于系统消息,当鼠标点击任务栏的另一个程序,则被点击的程序被唤醒成为当前运行的程序,这条鼠标消息是那个窗口的消息处理函数处理的呢,还是不明白。
sad_4978 2003-09-29
  • 打赏
  • 举报
回复
这些消息是由窗口过程函数处理的。
hotness28 2003-09-29
  • 打赏
  • 举报
回复
c语法书上不会有把,消息处理好象只有在window下才可以
建议看mfc的源代码,或者高级c++内容
grasshopperliu 2003-09-29
  • 打赏
  • 举报
回复
好文章!
学习ing
nonocast 2003-09-29
  • 打赏
  • 举报
回复
楼上的文章很不错
会思考的草 2003-09-29
  • 打赏
  • 举报
回复
2.对于消息的处理,Windows中其实有两个队列用于此目的,它们分别是系统队列和消息队列。每个要处理消息的窗口都有自己的一个消息队列。在系统队列中的事件仅仅是硬件事件的记录,GetMessage/PeekMessage会从这些事件中创建消息,并确定哪一个窗体将接收这个消息。
3.鼠标单击事件的过程:
首先,将计算该事件屏幕坐标的相应窗体。此计算(调用窗体点击测试)以桌面窗体开始,从头至尾的扫描细统中的每一个窗体(包括子窗体),直到找到一个包含这个鼠标坐标点的窗体,并且这个窗体没有任何同样包含这个坐标点的子窗体。
如果一个窗体使用SetCapture捕获鼠标,那么“系统队列扫描”代码将通过普通的点击测试,并将所有的鼠标消息返回到捕获的窗体。
如果这个被处理的事件是一个“鼠标键按下”事件(任何一个鼠标键),代码会检测这个事件是否会转化为双击事件。如果在两次鼠标键按下事件中,时间和距离的增量在允许的范围之中,该事件将会生成一个双击消息,否则它将生成一个标准的“按下”事件。所有的鼠标事件都将生成标准的鼠标消息,而双击测试只在鼠标事件指定的,包含CS_DBLCLKS类型的窗体中进行。
一个消息从鼠标事件中构造出来。
如果鼠标点击测试确定该事件发生在一个窗体的非客户区,如边框或标题栏,那么该构造出的消息映射到它相应的非客户区消息中。例如:一个WM_MOUSEMOVE事件会被映谢为WM_NCMOUSEMOVE消息。
与所有指定的消息过滤器进行对照,核查此消息,如果该消息不匹配过滤器,则重新从头开始“系统队列扫描”代码,查看队列中的下一个消息。
如果鼠标消息需要前往与当前任务不同的另一个任务的相关窗体,事件会被留在系统队列中,并且如果那个将会处理这个消息的任务在休眠之中,会被唤醒。这个新近被唤醒的任务不会在此刻立即运行,只会标记为准备运行,然后插入就绪队列中等待系统调度。如果消息前往了其它任务,并且在系统队列中没有要处理的事件被发现,“系统队列扫描”会代码返回到GetMessage/PeekMessage主代码。
如果安装了鼠标钩子,它将在此刻被调用。如果鼠标钩子返回了一个非零值,那么该鼠标事件被忽略,并从系统队列中被删除,然后重新从头开始“系统队列扫描”代码。如果钩子返回零,则继续处理。
如果消息是一个“鼠标键按下”消息,“系统队列扫描”则会在返回此消息之前,按照下面的方法激活窗体:沿着父链一直向上寻找该窗体的“最终顶层父窗体”,直到相遇,然后用SendMessage向该窗体的“最终顶层父窗体”发送一个WM_MOUSEACTIVATE消息。检查WM_MOUSEACTVATE的返回值,如果返回的值为空、MA_ACTIVATE或者MA_ACTIVATEANDEAT,ActivateWindow函数将被调用去激活那个“最终顶层父窗体”;如果返回的值是MA_NOACTIVATE或者MA_NOACTIVATEANDEAT,窗体则不被激活(注意:MA_ACTIVATEANDEAT和MA_NOACTIVATEANDEAT会导致“鼠标键按下”事件从系统队列中被删除,而不会生成一个鼠标按下消息);如果都不是以上的值,则一个WM_SETCURSOR消息被发送到窗体,充许窗体设置指针的轮廓。
如果鼠标钩子被调用,并且当前的鼠标事件从系统队列中被删除了,则检查“基于计算机训练”(CBT)的钩子。如果安装有有一个CBT钩子,将会携带HCBT_CLICKSKIPPED钩子码代调用它。
按键状态表包含了三个用于跟踪鼠标按键状态的入口。这些按键被分配予虚拟键代码(VK_LBUTTON,VK_RUTTON和VC_MBUTTON),它们和GetKeyState一起始用去确事实上鼠标键是弹起还是按下。在返回鼠标消息之前,“系统队列扫描”代码会(为弹起或按下消息)设置按键状态表并且从系统队列中删除消息。如果PeekMessage被调用时携带PM_NOREMOVE,则按键状态表不会被修改。
会思考的草 2003-09-29
  • 打赏
  • 举报
回复
1.确切讲,__stdcall不是ANSI C的关键字,它是Windows扩充的,(教材上讲的都是ANSI C,以DOS为平台的,所以你看不到这些奇怪的符号),这里面牵涉到一个调用规则和堆栈管理的问题。我们知道,在发生函数调用的时候,函数的参数会先压栈(别告诉我你不知道什么叫做“栈”——什么?你不知道?那还是回去拿本数据结构看看再来吧)。一直以来,存在两种压栈规则:PASCAL和C规则,C规则是,参数按照从右到左的顺序依次入栈,函数返回时,由调用者负责清理栈;PASCAL约定和C约定正好相反,它规定参数是从左向右传递,由被调用者恢复堆栈。这两种约定在Win16中都存在的,所以有时候还能看到PASCAL的修饰符。举个例子:
假如有函数:foo(int arg1,int arg2,int arg3),
用C规则的话就是:
push [arg1]
push [arg2]
push [arg3]
call foo
add esp, 3 * 4 ;调用者自己恢复堆栈指针
但是在Win32中的__stdcall和两者都不完全相同,它采用的是C的压栈顺序(即从右到左),但是由被调用者清理栈。这就有个好处,即,在编译的时候,被调用函数中无须生成清理栈的代码,所以编译产生的目标代码小一些。Win32只用__stdcall约定,它是Windows API函数中默认的调用约定,VB、VFP等也采用这个约定,但除了一个特例,即wsprintf。
但是C调用规则(__cdecl)还是相当有用的,譬如我们都知道,printf函数的参数是可变的,这个时候用__stdcall规则显然不可能,因为被调用的函数怎么能事先知道有多少个参数呢?所以这个时候采用C规则就方便得多。
除了__stdcall和__cdecl,还有几种规则:
__fastcall调用约定是“人”如其名,它的主要特点就是快,因为它是通过寄存器来传送参数的(实际上,它用ECX和EDX传送前两个双字(DWORD)或更小的参数,剩下的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的内存栈),在函数名修饰约定方面,它和前两者均不同。
__thiscall仅仅应用于“C++”成员函数。this指针存放于CX寄存器,参数从右到左压。thiscall不是关键词,因此不能被程序员指定。
说到现在,其实这些修饰符就是编译器开关,指定编译器如何产生代码,相当于汇编中的伪指令它们可以直接加在要输出的函数前,也可以在编译环境的Setting...\C/C++ \Code Generation项选择。当加在输出函数前的关键字与编译环境中的选择不同时,直接加在输出函数前的关键字有效。它们对应的命令行参数分别为/Gz、/Gd和/Gr。缺省状态为/Gd,即__cdecl。
加载更多回复(4)

16,467

社区成员

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

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

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