进行Windows Mobile 编程跟windows编程很类似。所以我们首先要知道windows操作系统应用程序是怎么相互作用的(感谢孙鑫老师,这里对windows的理解都是他在MFC编程的教程中讲解的)。(Mobile编程是所有嵌入式编程中最接近Window编程的)。

      应用程序可以通知操作系统执行某个具体的动作,如操作系统能够控制声卡发出声音,但它并不知道应该何时发出何种声音,需要应用程序告诉操作系统该发出什么样的声音。这个关系好比有个机器人能够完成行走的功能,但是,如果人们不告诉它往哪个方向上走,机器人是不会主动行走的。这里的机器人就是操作系统,人们就是应用程序。
      应用程序中要完成某个功能,都是以函数调用的形式实现的,同样,应用程序也是以函数调用的方式来通知操作系统执行相应的功能的。操作系统所能够完成的每一个特殊功能通常都有一个函数与其对应,也就是说,操作系统把它所能够完成的功能以函数的形式提供给应用程序使用,应用程序对这些函数的调用就叫做系统调用,这些函数的集合就是Windows操作系统提供给应用程序编程的接口(Application Programming Interface),简称Windows API。如CreateWindow就是一个API函数,应用程序中调用这个函数,操作系统就会按照该函数提供的参数信息产生一个相应的窗口。

     操作系统能够将输入设备的变化上传给应用程序。如用户在某个程序活动时按了一下键盘,操作系统马上能够感知到这一事件,并且能够知道用户按下的是哪一个键,操作系统并不决定对这一事件如何作出反应,而是将这一事件转交给应用程序,由应用程序决定如何对这一事件作出反应。好比有个蚊子叮了我们一口,我们的神经末梢(相当于操作系统)马上感知到这一事件,并传递给了我们的大脑(相当于应用程序),我们的大脑最终决定如何对这一事件作出反应,如将蚊子赶走,或是将蚊子拍死。对事件作出反应的过程就是消息响应。

     操作系统是怎样将感知到的事件传递给应用程序的呢?这是通过消息机制(Message)来实现的。操作系统将每个事件都包装成一个称为消息的结构体MSG来传递给应用程序。消息本是 Windows 的基本控制手段,乍看与函数调用无关,其实是一种变相的函数调用。发送消息的目的是通知收方运行一段预先准备好的代码,相当于调用一个函数。消息所附带的 WParam 和 LParam 相当于函数的参数,只不过比普通参数更通用一些。应用程序可以主动发送消息,更多情况下是坐等 Windows 发送消息。一旦消息进入所属消息队列,便检感兴趣的那些,跳转去执行相应的消息处理代码。
   
windows是用消息机制实现的:
1、当我们对窗口进行操作(如调整窗口大小,移动窗口位置),或是点击鼠标和键盘的时候就会产生各种各样的消息。
2、Window系统会将这些消息排入本线程的消息队列中(在操作系统中完成)。
3、只要该窗口消息队列中有消息,我们的GetMessage(&msg,NULL,0,0)就会从消息队列中摘取一个消息的信息,填入msg结构体变量中,如果不是WM_QUIT则返回非零值,就执行循环体。(注意:如果消息队列中没有任何消息可取时,则程序会停在GetMessage函数里,直到消息队列中有了消息,GetMessage函数才会取一个消息信息并返回。)
4、用TranslateMessage(&msg)对msg中的数据进行预处理(你先不必知道它具体做了什么,但不要忘记这个函数)。
5、然后是调用DespatchMessage(&msg),这个函数里会调用WinProc,并将msg中的数据通过WinProc的参数传递给WinProc。
6、退出DispatchMessage(&msg);函数后程序又执行下一个循环。即while(GetMessage(&msg, NULL, 0, 0)) 又取下一个消息,进行下一个消息的处理。
7、直到GetMessage “摘取”到了退出程序的消息WM_QUIT,返回零值,退出循环,结束程序。

     Windows消息机制理解,当windows操作系统,给窗口发送一个消息后,windows就不再管这个窗口的事情,它转向处理其它任务,而消息则被放入到窗口的消息队列里面,由窗口处理。举例:汽车厂家生产汽车好比应用程序创建窗口,用户使用汽车好比操作系统管理窗口,某种汽车在销售前就指定好了修理站(类似回调函数),当用户的汽车出现故障后(类似窗口收到消息),汽车用户(类似操作系统)自己直接找到修理站去修理,不用厂家(类似应用程序)亲自将车送到修理站去修理,但修理站还得由厂家事先建造好。

     进一步对理解消息

     真正的Windows实际没有“消息映射”的概念,它只有消息发送(Send)、投递(Post)、接收(Get、Peek)与分发(Dispatch)。这些操作的对象都是实实在在的Windows窗口。
     但是MFC有些不同,因为它用C++的类来封装Windows窗口,这样就必须额外的引入消息在C++类之间“流动”的机制,这被MFC称为消息映射(map,即将Windows消息映射给一个MFC类来处理)与消息流动(route,消息在C++类之间的流动)。  
举个例子来说,在Windows中,一个消息发送到了窗口,只有几条路可选:
     1、自己“吃掉”;
     2、重新交给父窗口处理;
     3、交给DefWindowProc处理。
在MFC中,如果一个类“接收”到了消息,它的路就比较多了:
     1、自己“吃掉”;
     2、发给父窗口的类处理;
     3、发给父类(注意与“父窗口的类”的不同)处理,如果父类不处理,继续向上派遣,直至最后无人处理,交给DefWindowProc;
     4、交给相关类处理(比如,CFrameWnd收到消息,会首先交给CView、CDocment处理)。
由于这其中的第4点机制,使得MFC的一些非CWnd派生类(即那些不具有Windows窗口的类),比如CDocment,也有机会处理部分消息,增大了编程的灵活性,但另一方面,这又给消息机制平添了许多复杂的路径,因此MFC决定用消息映射表和几个宏来完成这项“艰巨”的任务。在windows里所有的对象都是窗口。而MFC却不全是。

消息的分类:
      标准消息:除了WM_COMMAND之外的所有以WM_开头的消息,从CWmd派生的类都可以接受到这些消息。
     
命令消息:来自菜单、加速键、工具栏按钮的消息。这类消息都以WM_COMMAND呈现。在MFC中,通过ID来标识,在SDK中,通过wParam参数识别。从CCmdTarget派生的类,都可以接收到这类消息。
      通告消息:由控件产生的消息。例如,按钮单击,列表框的选择,为的是向其父窗口通知事件的发生。这类消息也是以WM_COMMAND形式呈现的。从CCmdTarget派生的类,都可以接收到这类消息。 

     消息其实都是编码,windows给各种操作都有一个唯一的编码。消息实际就是对窗口过程的一次调用。消息通传机制就是系统帮你发送数据调用函数。

     16位的系统中只有一个消息队列。而32位的系统中每一运行的程序都会有一个消息队列,所以系统可以在多个消息队列中转换而不必等待当前程序完成消息处理就可以得到控制权。这种多任务的系统叫做抢占式多任务系统。

       这里在讲一下回调函数,回调函数即使事先准备一段现成的代码,调用者可以随时跳转至此段代码的起始地址,执行完后再返回跳转时的后续地址。简单地说,回调(Callback)函数就是一个按规定原型实现的一个函数,让别人(操作系统、函数等)来调用。Windows 系统还包含着另一种更为广泛的回调机制,即消息机制。其实,应用程序之间也可以形成这种回调。假如进程 B 收到进程 A 发来的消息,启动了一段代码,其中又向进程 A 发送消息,这就形成了回调。

        例如通过使用 EnumFont ( myfunc) 就可以将所有额字体信息添加到一个列表框中。那么我们称 myfunc是一个回调函数,即让某个系统函数调用的函数。因此可以得出结论:
        1 回调函数是由开发者按照一定的原型进行定义的函数
        2 回调函数并不由开发者直接调用执行
        3 回调函数通常作为参数传递给系统API,由该API来调用。
        4 回调函数可能被系统API调用一次,也可能被循环调用多次。
比如 函数:

             int EnumFontFamilies(

                    HDC hdc,                    // handle to device control
                    LPCTSTR lpszFamily,  // pointer to family-name string
                    FONTENUMPROC lpEnumFontFamProc,  // pointer to callback function
                    LPARAM lParam        // pointer to application-supplied data
                   );
其中的   FONTENUMPROC lpEnumFontFamProc就是一个回调函数,该函数遵照格式int CALLBACK EnumFontFamProc( ENUMLOGFONT FAR *lpelf,  NEWTEXTMETRIC FAR *lpntm, int FontType,  LPARAM lParam )进行定义。

 

        回调函数主要用于一些比较费时的操作,响应不知道何时将会发生的事件(像窗口的MainProc,回调函数提供了一种异步的机制,相对于同步执行,提高了效率.前者的例子如WriteFileEx,ReadFileEx等,函数的最后一个参数是一个回调函数的指针,程序中调用WriteFileEx以后,就直接返回了,可以继续进行其他工作,系统在读写操作完成后通知程序作善后处理.

       后者的例子就是windows的事件机制回调函数的另一个用途,是用于一些枚举函数,如EnumDisplayModes等,每找到一种支持的显示模式,就通知回调函数,由回调函数具体处理,这是因为 EnumDisplayModes本身并不知道用户要如何处理.用户提供回调函数,定制系统的功能,这样,不同的用户提供不同的回调函数,可以使系统具有不同的功能.这就是所谓的plugin.使用回调函数实际上就是在调用某个函数(通常是API函数)时,将自己的一个函数(这个函数为回调函数)的地址作为参数传递给那个函数。而那个函数在需要的时候,利用传递的地址调用回调函数,这时你可以利用这个机会在回调函数中处理消息或完成一定的操作。至于如何定义回调函数,跟具体使用的API函数有关,一般在帮助中有说明回调函数的参数和返回值等。

        windows很好很强大。对于这些定义先有个概念,还需要在以后的应用中不断加深理解。

 

  个人感觉,MFC太过强大复杂,对于新手而言掌握起来极其困难。建议大家学习MFC之初先阅读侯捷先生的《深入浅出MFC》。


Posted on 2010-01-30 21:54  我不是牛人  阅读(275)  评论(0编辑  收藏  举报