(
注:名字定义不准确,请按感觉看我写的东东,由于写得含糊,不会误导谁,高手不用骂,只需要用平和的语气指出我说错在哪就可以了;
另: 我的习惯把函数说成方法
要有C++的知识才能看懂
如果想看到下列描述,从学习书本上打开一个最简单的HELLO WORLD实例, 用F11键单步调,就可以看到下面我的描述的执行过程
)
一个消息是一个结构的实例对象,是什么样的结构可以在帮助里面找到,这里暂时不关心.很多个消息排成队,成了消息队列.任何一个WINDWOS进程(即一个可执行文件)有一个主线程,和可能有的多个工作线程以及多个用户线程(一个用户线程直观地看,就是一个窗口);主线程或者用户线程里面有一个RUN()方法,里面有一个死循环,这个死循环不停地去查上述的那个消息队列中是否有消息.如果有,就PEEK这个消息(PEEK意思是把这个消息拿过来,准备处理它)PEEK完后,这个死循环如果觉得这个消息没有什么疑意义,它就PUMP(处理)这个消息PUMP的过程:
1. 先GET这个消息.(GET与PEEK相比是这样的,PEEK得到消息后,没有从上述的消息队列中把消息删除,但是GET得到消息后,把这个消息从队列中删除了.)2. GET这个消息之后,先试着用快速处理的方法看是否可以把这个消息搞定(用PreTranslateMessage()方法来快速处理),如果搞不定------3. 把消息中的快捷键解释成普通的字各符;4. 把消息分发:就是去找相应的回调函数来响应(比如用户定义的ON_LEFT_DOWN,ON_KEY_DOWN之类的东西)<什么是回调函数? 大家最好发贴问一下, 或者看下述: 回调函数是一些函数, 这些函数在主线程或者应用线程建立一个窗口的时候, 每个函数把指向自己的一个指针在这个窗口中注册, 这个窗口是归WINDOWS管理的,我们暂时把管理这个窗口的那些WINDOWS函数称为管理员. 当一个消息被传给WINDOWS的管理员的时候, 这个管理员到上述指针列表里面去找合适的响应函数的指针,某个指针被找到后,该指针去调用所指向的函数,该函数用传来的消息作为参数,称为回调>**********************************************谢谢观看,请顶一下,确保高手可以随时看到并进来指教,要UP哦

解决方案 »

  1.   

    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。
      

  2.   

    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,则按键状态表不会被修改。
      

  3.   

    请问如何将消息传入系统队列?
     比如将WM_DEVICECHANGE传给windows  强制使其刷新,这种方法行得通吗?
      

  4.   

    按照会思考的草的说法,似乎是每个窗口有一个自己的消息队列,这个消息队列是其它软件发来的.
    所有的窗口共用一个系统队列,这个系统队列的消息是由硬件传递来的.对不对?????见下:
    2.对于消息的处理,Windows中其实有两个队列用于此目的,它们分别是系统队列和消息队列。每个要处理消息的窗口都有自己的一个消息队列。在系统队列中的事件仅仅是硬件事件的记录,GetMessage/PeekMessage会从这些事件中创建消息,并确定哪一个窗体将接收这个消息。
    3.鼠标单击事件的过程:
      

  5.   

    1.每个GUI线程都有一个消息队列。
    2.消息的产生:
      鼠标单击->鼠标驱动截获->生成消息放入系统队列->GetMessage/PeekMessage扫描系统队列->获取当前任务应该处理的消息->放入线程消息队列。