本人小菜,最近正在学习MFC,看有讲到windows消息机制,里面讲到:WinMain()里面会有一个循环从操作系统的消息队列中获取消息,然后在调用DispatchMessage(&msg)告知操作系统调用回调函数WndProc()处理消息;此处有一个比较幼稚的疑问,
为什么在消息发生时,操作系统不直接调用窗口的回调函数WndProc(),而要在应用程序WinMain()中获取消息->再告知操作系统调用回调函数?为什么不设计成这样:当消息或者事件发生时,操作系统直接调用某个窗口的回调函数,将消息作为参数传递给该回调函数处理呢?为什要WinMain()先用GetMessage()获取消息,再用DispatchMessage(&msg)通知操作系统调用自己的窗口函数呢?这样一来控制权岂不是由窗口发起,递交给操作系统,再递交给窗口(回调函数),绕了一圈?请高手详细解释一下,感谢!MFCwindows消息机制getmessage()

解决方案 »

  1.   


    修改窗口函数?你是说WndProc()?
    可以改啊我想问的意思是窗口函数还是自己写,自己修改都行,但是由操作系统直接调用,不必由应用程序使用DispatchMessage()通知操作系统调用窗口函数;
      

  2.   

    网上看到一些解释,如下:“==================================================
    其实问题的关键在于DispatchMessage到底干了什么 
    如果只是去调用相应的窗口,那自己写个switch不就可以了。DispatchMessage与switch不同之处在于DispatchMessage会先调用windows,进入管态(大概是range 0),然后再由windows调用窗口的函数。 为什么这么麻烦? 因为这样windows就可以知道你的程序运行到什么情况了, windows来调用你的窗口,这样你的窗口返回的时候windows就知道你已经处理过一个消息了,如果没有新的消息进入消息队列windows就不再会给你的进程分配时间片如果是你自己写switch的话,windows就不可能这样灵活的分配时间资源利用率就会降低;那么还要消息循环干什么,windows直接把消息发给窗口不就可以了吗?因为你要在消息循环里把KEY_DOWN和KEY_UP组合成WM_CHAR,还可以直接屏蔽掉许多对你来说无用的消息,加快速度。
    ==================================================”难道就是因为这些?没有其他原因么?求解释!!!
      

  3.   

    直接调用就是SendMessage类似处理的,但是还有异步的方式PostMessage
      

  4.   

    不是系统调用的WNDPROC,系统只负责通知和调试,不参与回调
      

  5.   

    如果系统调用所有WNDPROC那其中一个过程有长时间耗时运算岂不是整个系统都无法响应?while (GetMessage(&msg, NULL, 0, 0))
    {
        TraslateMessage(&msg);
        DispatchMessage(&msg);
    }WNDPROC ...典型的消息泵,系统参与工作的就只有GetMessage 这句,从系统那取到消息。然后DispatchMessage再分发消息到同一线程的各WNDPROC,真正是由DispatchMessage回调WndProc的。所以DispatchMessage在哪个线程,就相当于谁执行了WndProc。
      

  6.   

    LZ的问题乍看起来容易让人产生误解,仔细看过之后,明白了LZ的问题。
    我认为:Windows设计消息管理机制时,希望用面向对象的思想对消息进行封装(不是用面向对象的C++语法进行封装),使用的是不支持面向对象表达的C语言WIN16/WIN32 API接口。封装后的对开发者提出的强制要求就是:窗口类、窗口回调WNDPROC、消息循环GetMessage()处理Send的消息、消息派遣DispatchMessage()处理Post的消息。大家都按照这个标准来开发Windows程序。我想这也就是9楼说的一种设计思想。
      

  7.   

    while (GetMessage(&msg, NULL, 0, 0)) { 
        TraslateMessage(&msg);     
        DispatchMessage(&msg); 

    这段代码保证了窗口过程,在用户程序的主线程里运行,这样对系统窗口过程的调用,才能保证在用户程序的地址空间和时间片里运行,如果系统自己调用窗口过程;
    那么
    1)用户程序,就没有办法控制程序的运行了。
    2)程序占用了系统的时间片了。
    3)用户地址空间和系统地址空间,没有办法分割了。
    4)系统没有办法管理,用户程序的运行了。
     GetMessage这个动作保证了,用户程序的消息不会堆积下来。
     TraslateMessage(&msg);     
     DispatchMessage(&msg); 
    保证用户程序,能够正确处理窗口的消息。
    有了这样一个消息循环,窗口程序就能不断的处理消息,保证用户程序的正确运行了。 
      

  8.   


    我不理解你说的SendMessage/PostMessage是在什么场景下应用的?
    你是说GetMessage/PeekMessage么?
    能否详细讲解一下?
      

  9.   


    ==================================================
    DispatchMessage函数功能:该函数分发一个消息给窗口程序。通常消息从GetMessage函数获得。消息被分发到回调函数(过程函数),作用是消息传递给操作系统,然后操作系统去调用我们的回调函数,也就是说我们在窗体的过程函数中处理消息
    ==================================================这是度娘的原话,WinMain用DispatchMessage函数将消息传递给系统,操作系统调用回调函数!
    你说不是系统调用WNDPROC?这我就迷糊了?还望详细解释!
      

  10.   


    没懂!我觉得你说的“发送消息和执行消息的两部分(两个函数或线程或窗口进程等等)彼此互相不需要知道对方是什么,这就是消息机制最大的优点”,这个我没有疑问,WinMain与WndProc是分开的,但是为什么消息发生时操作系统不直接调用WndProc?
      

  11.   


    针对你说的几点:
    1)用户程序,就没有办法控制程序的运行了。——这个是说的WinMain中需要过滤一些消息这个控制动作?
    2)程序占用了系统的时间片了。——那DispatchMessage函数将消息传递给系统,系统再去调用回调函数,这个动作不会占用系统的时间片段么?有什么区别?
    3)这个更2)是一个道理吧?
    4)这个也是由上面点造成的,暂且不谈把。综合起来看,你的观点就是,如果系统直接调用WndProc,则WndProc运行在系统的地址空间;而由WinMain调用DispatchMessage函数通知系统调用WndProc,则WndProc运行在WinMain的地址空间;可以这么理解么?但是为什么最后都是系统负责调用WndProc,到底有什么区别呢?
      

  12.   


    HOOK我就知道简单的挂钩原理,你的意思是说hook到消息后可以做一些处理、修改、过滤等等?有两点疑问,为什么要让应用程序能够hook到消息?这样有什么好处?这个有点扯远了。另外一个,WinMain与WndProc是同一个程序里,WinMain中能做的过滤、处理、修改等等,都可以放在WndProc中,感觉没必要在WinMain里获取消息,过滤、修改后再传给系统,让系统调用回调WndProc?
    还望版主细讲!
      

  13.   


    我讲的也是由操作系统调用WndProc,没有与回调这个概念相悖吧?你强调回调什么意思呢?请细讲!
      

  14.   

    DispatchMessage 这个函数的调用点在用户空间,所谓的系统调用,实际上是DispatchMessage这个函数在调用,只是DispatchMessage函数会进入系统内核,然后查找WndProc找到后返回用户地址空间和用户线程调用WndProc,这样就在用户地址空间,调用了WndProc,在用户线程的时间片里运行WndProc了。
    操作系统,只是为用户程序提供服务的,用户程序,才是真正完成工作的程序。操作系统,主要做以下工作。
    1)管理用户程序。
    2)为用户程序提供服务。具体执行的任务,实际上都是用户程序提供的。
    像画图,NotePad这样的程序,实际上,是操作系统附带提供的,用户程序。
    真正的系统内核,并不包含这些程序。
    Cmd,explorer 则处于二者之间,是操作系统的外壳程序,实际上,用户程序也可以实现类似的功能。比如unix的,linux的各种shell。Windows 系统,各种驱动程序,处于系统内核位置,GDI,USER,Kenerl 三大模块,是系统的核心模块。
    各种API,都可能有机会进入系统内核,从而唤醒内核调度程序。DispatchMessage是处理消息的核心API之一。如果应用程序不调用,这些API,没有办法在核心和用户状态之间转换。
    系统直接调用的话,那就处于内核的地址空间,而不是用户的地址空间了。同样,也不处于用户的时间片了,用户线程,无法运行,这样系统程序到处跑,用户程序饿死,这个系统是无法正常使用的。系统是用来管理,维护用户程序,并为用户程序提供服务的,不能全速运行。系统程序,应该占用尽量少的时间,从而让用户程序,可以流畅的运行。
      

  15.   

    Windows 回调程序的概念是,应用程序调用API,API 调用回调函数。这就是回调函数的含义。具体实现,就是注册或者传入一个函数指针。这个函数由用户程序实现。注册或者传入的是用户实现的那个函数的地址。函数格式---函数参数的个数和类型,返回值的类型,函数调用约定---由系统指定,而不是,用户随意定义。WndProc 由RegisterClass, RegisterClassEx等 函数注册,DispatchMessage等函数最终调用这就是 Windows 消息循环存在的理由。