完全用 VB 6.0 自身功能实现对 Windows 消息的拦截!

原创 2001年08月03日 18:33:00

众所周知,VB 的功能没有 VC++、Delphi 这样的全功能开发平台强大,但她也足以完成我们绝大部分的工作,只要你开动脑筋,敢想敢干,我们可以让 VB 发挥最大的效能,做出许多令人惊叹的软件。开发高难度软件,并不只是 VC++ 和 Delphi 的专利!

过去普遍认为 VB 无法自定义拦截 Windows 的消息,只能靠 VB 本身提供的几个有限的事件来编程,这有很大的局限性。缺少消息捕获,同时又被认为不支持回调函数机制(主要是因为 VB 没有指针,更谈不上函数指针),这造成了 VB 编程的很大局限性。事实上,VB 可以采用别的办法变相地实现这一机制。从 VB 5.0 开始就提供了 AddressOf 操作符,利用这个操作符可以获取 VB 自定义函数的地址。有了函数地址就可以采用回调函数的机制了。当然,VB 仍然无法实现 VB 函数之间的地址传递,她只支持 VB 函数到 DLL 的函数抵制传递。但是,这已经足够了。下面这个程序,就是采用了这一方法,程序中只有一个主窗体,通过设置属性,使得主窗体没有边框,没有标题栏,不能改变大小,不能通过标题栏托动。但是通过拦截 Windows 消息可以使得鼠标处在窗体中的任意位置都可以托动它,就像按住标题栏托动一样。这个程序没有用到任何附加的控件,全部采用 VB 代码完成。注意,请增加一个公共模块,以便声明一些函数和常数。以下代码在 VB 6.0 中通过。

' ===================================
' 这是公共模块的代码
Attribute VB_Name = "Module1"
Option Explicit

Public Const WM_NCHITTEST = &H84
Public Const VK_LBUTTON = &H1
Public Const HTCAPTION = 2
Public Const HTCLIENT = 1


Public Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

Public Const GWL_WNDPROC = -4
Global lpPrevWndProc As Long
Global gHW As Long

' 这里是关键,我自定义了一个窗口函数(回调函数),以替代 VB 窗体自己的默认窗口函数。' 窗口函数是干什么的?它就是负责处理 Windows 发送给它的消息,并加以过滤,筛选出它感兴趣' 的消息,映射成为事件供我们使用。VB 中每个窗口都有一个默认的窗口函数,我们是看不到的。' 有很多消息都被 VB 的默认窗口函数过滤掉了。了解 C/C++/Delphi 程序设计的朋友应该知道这些。

Function WindowProc(ByVal hw As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
  ' 我们也进行消息过滤,不过我们指拦截我们感兴趣的消息
  ' 其他消息我们懒得处理,交给 VB 默认的窗口函数去处理吧。
  Select Case uMsg
    Case WM_NCHITTEST  ' 拦截 WM_NCHITTEST 消息
      If GetAsyncKeyState(VK_LBUTTON) < 0 Then  ' 是否有鼠标左键在窗体客户区按下?
        ' 如果是,函数返回值被设置为 HTCAPTION,欺骗 Windows,让它以为鼠标是按在标题栏
        ' Windows 是通过窗口函数的返回值进行判断处理的
        WindowProc = HTCAPTION
        Exit Function
      Else
        ' 其他的我们不管,还是规规矩矩的该怎么样就怎么样
        WindowProc = HTCLIENT
        Exit Function
      End If
  End Select
  ' 这里又是关键,因为其他我们不关心的消息我们自己不处理,所以必须由 VB 的默认处理函数处理
  ' lpPrevWndProc 其实就是一个函数指针,它指向 VB 默认窗口函数
  WindowProc = CallWindowProc(lpPrevWndProc, hw, uMsg, wParam, lParam)
End Function

' ===================================
' 这是窗体的代码
VERSION 5.00
Begin VB.Form Form1
   BorderStyle     =   0  'None
   ClientHeight    =   3195
   ClientLeft      =   0
   ClientTop       =   0
   ClientWidth     =   4680
   LinkTopic       =   "Form1"
   MaxButton       =   0   'False
   MinButton       =   0   'False
   ScaleHeight     =   3195
   ScaleWidth      =   4680
   ShowInTaskbar   =   0   'False
   StartUpPosition =   3  '窗口缺省
   Begin VB.CommandButton Command1
      Caption         =   "Command1"
      Height          =   375
      Left            =   2160
      TabIndex        =   0
      Top             =   720
      Width           =   1575
   End
End
Attribute VB_Name = "Form1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False

Private Sub Command1_Click()
  Unload Me  ' 按下这个按钮就退出了
End Sub

Private Sub Form_Load()
  gHW = Me.hwnd  ' 保存窗体的句柄
  ' 下面是关键,完成两个工作:1、将我们自己的全局函数替换为新的窗体回调函数
  ' 2、保存原来的 VB 默认窗户口函数地址
  lpPrevWndProc = SetWindowLong(gHW, GWL_WNDPROC, AddressOf WindowProc)
End Sub

其实,一切就这么简单。有了这种办法,Windows 中需要回调函数的 API 函数我们都可以调用了,有很多的功能我们都可以用 VB 来实现了。注意,我们自定义的回调函数只能是模块中定义的全局函数!不能在窗体中定义。

写出来只是想抛砖引玉,其实有很多功能不需要到处去找控件的。我现在在研究用 VB 6 + DirectX 7/8 写游戏。游戏速度当然不可能达到 C++ 的程度,但是足够应付一些中小型的游戏题材了,比如 RPG 的。这又有很多值得写出来的了。虽然不是什么新鲜的话题,但是其中仍不乏许多的技巧和编程思想。希望对此有研究的朋友能够多多出来交流指点一二。

用VB编写键盘拦截程序[转]

我们知道,在一些程序中,有一些快捷方式(如:Shift键最小化、ESC键退出、Ctrl+S存盘、Alt+x退出等等)。以前有一些介绍使用Win32 API可以做到,但过于繁琐,其实VB本身已经给我们提...
  • benqmm
  • benqmm
  • 2005年12月18日 20:31
  • 1474

windows中使用钩子拦截消息

一、前 言 众所周知,Windows程式的运行是依靠发生的事件来驱动。换句话说,程式不断等待一个消息的发生,然后对这个消息的类型进行判断,再做适当的处理。处理完此次消息后又回到等待状态。从上面对...
  • zi_wu_xian
  • zi_wu_xian
  • 2013年04月25日 22:21
  • 3347

Hook 简单的实例--拦截鼠标和键盘消息(一)

Hook(钩子)就是对Windows系统的一些消息或是API函数进行拦截和监控的处理平台,让可以根据程序员的设置获取其感兴趣的信息。 这里主要是介绍一下Hook拦截鼠标消息和键盘消息。 下面是CALL...
  • u013147600
  • u013147600
  • 2015年05月06日 15:05
  • 4500

Java窗口如何接收并处理windows消息

简介 当前的java窗口若需要接收到window的消息,首先需要获取到当前窗口的句柄,然后通过窗口句柄得到其window消息回调函数,最后截获消息回调函数中有用的消息,并将无用的消息还给window...
  • XUXUEMING
  • XUXUEMING
  • 2016年09月05日 14:22
  • 3812

用VB6.0实现将窗体最小化到系统托盘区 两个方法均测试部分有效或完全有效

用VB6.0实现将窗体最小化到系统托盘区 两个方法均测试部分有效或完全有效 1、新建立一个VB6工程,将Form1的ShowInTaskBar属性设置为False 2、菜单:工程--添加模块 按“...
  • karl_han
  • karl_han
  • 2013年09月27日 11:50
  • 901

C#Accp6.0项目网络精灵个人增版,后面的功能没有完全实现

  • 2013年09月13日 01:42
  • 1.73MB
  • 下载

Mapx4+vb 6.0实现功能全面的例子

  • 2007年09月27日 16:00
  • 205KB
  • 下载

简单的ftp软件实现基本功能开发环境vb6.0

  • 2011年06月29日 09:12
  • 6KB
  • 下载

C#完全仿QQ源码(换肤色,系统消息,等完善功能)

  • 2010年02月11日 21:55
  • 10.36MB
  • 下载

VB6.0中提示:该部件的许可证信息没有找到,在设计环境中,没有合适的许可证使用该功能”的解决办法

用VB6.0中的某些控件时总是提示“该部件的许可证信息没有找到,在设计环境中,没有合适的许可证使用该功能”~!(主要是因为VB6.0精简版) 具体解决方法: 这里需要一个工具:vbcli.ex...
  • kencaber
  • kencaber
  • 2016年02月07日 11:36
  • 6044
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:完全用 VB 6.0 自身功能实现对 Windows 消息的拦截!
举报原因:
原因补充:

(最多只允许输入30个字)