消息用GetMessage读入后(注意这个消息可不是WM_QUIT消息),它首先要经过函数TranslateMessage()进行翻译,这个函数会转换成一些键盘消息,它检索匹配的WM_KEYDOWN和WM_KEYUP消息,并为窗口产生相应的ASCII字符消息(WM_CHAR),它包含指定键的ANSI字符.但对大多数消息来说它并不起什么作用,所以现在没有必要考虑它。
下一个函数调用DispatchMessage()要求Windows将消息传送给在MSG结构中为窗口所指定的窗口过程。我们在讲到登记窗口类时曾提到过,登记窗口类时,我们曾指定Windows把函数WindosProc作为咱们这个窗口的窗口过程(就是指处理这个消息的东东)。就是说,Windows会调用函数WindowsProc()来处理这个消息。在WindowProc()处理完消息后,代码又循环到开始去接收另一个消息,这样就完成了一个消息循环。
因此,从某种角度上来看,Windows应用程序是由一系列的消息处理代码来实现的。这和传统的过程式编程方法很不一样,编程者只能够预测用户所利用应用程序用户界面对象所进行的操作以及为这些操作编写处理代码,却不可以这些操作在什么时候发生或者是以什么顺序来发生,也就是说,我们不可能知道什么消息会在什么时候以什么顺序来临。那么windows是如何解决这个问题的呢?windows采用一种叫做回调函数(callback function)的特殊函数,这个函数由Windows直接调用。实际上每个窗口类都必须有一个回调函数。在Windows中消息循环和窗口类的回调函数已经都被封装起来,我们一般情况不会接触,如果我们想重新注册窗口过程函数WindowProc(就是这个回调函数),我们必须使用子类(Subclass)的技术。
(这部分说的可能比较多,而且都是开发Windows应用程序的基础部分(基础的东西虽然难度不大,但是非常重要)。但是因为对于部分VB程序员来说可能接触不多,因此说的多了点。)
子类(Subclass):
按照上文提到的因为对于正常的VB通常不能直接处理Windows系统的消息,但是我们可以通过子类的方法截获Windows消息并且自定义其处理方法(而如果想截获其他应用程序的消息就需要使用钩子(Hook)技术)。
应用程序可以用过SetWindowLong API 函数为具有窗口句柄(hWnd)的窗体、控件或其他对象安装新的消息处理(Message handler)过程函数WindowProc。这个新的WindowProc过程必须被定义在模块(.BAS)文件中。
Private Sub Form_Load()
OldWindowProc = SetWindowLong( _
hwnd, GWL_WNDPROC, _
AddressOf NewWindowProc)
End Sub
现在,如果窗体收到Windows消息,系统将调用新的WindowProc 过程(NewWindowProc),这个新的窗口过程函数将检查当前的消息行为是否被指定,如果没有指定具体的行为,将被传递给源窗口过程函数WindowProc,有源WindowProc进行默认的处理。这个过程是非常重要的,否则因为当前窗口可能会因为消息遗失,造成不能进行重绘、更新等其他窗口默认的标准行为。而且新的窗口过程必须返回源过程函数返回的结果。
下面用一个实际代码例子演示处理WM_SYSCOMMAND消息的过程:
WM_SYSCOMMAND: 当用户选择“窗口菜单”的一条命令是触发。
Public Function NewWindowProc( _
ByVal hwnd As Long, ByVal msg As Long, _
ByVal wParam As Long, lParam As WINDOWPO