📄 m72.htm
字号:
<html>
<head>
<title>VB教程</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>
<p align="center"><script src="../../1.js"></script></a>
<body bgcolor="#ffffff" leftmargin="5" topmargin="1" marginheight="5" marginwidth="5">
<div align=center>
<table border=0 cellpadding=0 cellspacing=0 width=680 align="center">
<tbody>
<tr>
<td bgcolor=#000000 height=9>
<div align=center class=H1> <font color="#FFFFFF">用 Visual Basic编写托盘程序</font> </font> </font></div>
</td>
</tr>
<tr valign=top>
<td class=H1 height=76>
<p align="left"> <br>
</font></p>
<p> <span class="unnamed1">Windows 95、Windows 98、Windows
NT 等操作系统的界面上都增加了Shell层的技术,这就为广大编程人员开辟了界面编程的新途径。本文讲述的是如何用VB 5.0来编写托盘程序。
</span></font>
<p> 托盘程序主要解决两个问题:(1)创建、修改、删除托盘;(2)如何对托盘接收到的消息进行处理。这就要用到几个Win32
API。 </span></font>
<p> 首先,Shell_NotifyIcon是用于托盘的Shell
API。该API用到一个NOTIFYICONDATA结构,该结构包括:hIcon(托盘图标指针)、hwnd(接收托盘图标消息的窗口指针)、szTIP(提示字符串)、uCallbackMessage(标志应用程序的消息)、uFlag(对托盘图标操作的标志,包括添加、删除、修改)、Uid(由程序定义的图标识别符,因为有的程序有多个图标)、cbSize(该结构所占的字节数)。因为该API的用法在许多书刊中都有论述,故在此处不再多讲,具体用法可参见下文的注释。
</span></font>
<p> 其次,应该考虑怎样在VB中接收、处理托盘的消息。C++、Delphi等语言对消息循环的处理较简单,但在VB中处理消息循环时必须应用Win32的API,而且要采用窗口子类化技术,需要用到SetWindowLong、CallWindowProc这两个API。SetWindowLong
函数利用GWL_WNDPROC 索引来创建窗口类的子类(窗口类是用来创建窗口的),它使用AddressOf 关键字和回调函数(WindowProc)来截取消息并根据消息来执行相应的功能,如窗口的最大化、最小化、隐藏、退出等。CallWindowProc函数调用原窗口类缺省的指针,程序最后退出时可通过SetWindowLong来关闭子类,重新使原来的
Windows 过程成为回调函数。因为代码要调用VB 5.0的函数指针,所以必须将该代码放到标准的 .BAS 模块中,不可以将它放到类模块中,也不能将其附加到窗体上。在使用
AddressOf 关键字声明函数时,必须注意:VB 5.0仅支持从 Visual Basic 到 DLL 函数的指针,不支持“Basic
到 Basic”的函数指针。 </span></font>
<p> 本程序项目名为TRAY.vbp,它包括模块TRAY.bas和窗体TRAY.frm。
</span></font>
<p> 1、TRAY.bas源代码 </span></font>
<p> Type NOTIFYICONDATA
</span></font>
<p> cbSize As Long </span></font>
<p> hwnd As Long </span></font>
<p> uID As Long </span></font>
<p> uFlags As Long </span></font>
<p> uCallbackMessage As
Long </span></font>
<p> hIcon As Long </span></font>
<p> szTip As String * 64
</span></font>
<p> End Type </span></font>
<p> Public a As Long </span></font>
<p> '以下为 Shell_NotifyIcon将用到的常量
</span></font>
<p> Public Const NIF_ICON
= &H2 </span></font>
<p> Public Const NIF_MESSAGE
= &H1 </span></font>
<p> Public Const NIF_TIP
= &H4 </span></font>
<p> Public Const NIM_ADD
= &H0 </span></font>
<p> Public Const NIM_DELETE
= &H2 </span></font>
<p> Public Const NIM_MODIFY
= &H1 </span></font>
<p> 'Shell_NotifyIcon的函数声明
</span></font>
<p> Declare Function Shell_NotifyIcon
Lib "shell32.dll" Alias "Shell_NotifyIconA" _ </span></font>
<p> (ByVal dwMessage As
Long, lpData As NOTIFYICONDATA) As Long </span></font>
<p> '处理消息将用到的结构、常量、API声明
</span></font>
<p> Type POINTAPI </span></font>
<p> x As Long </span></font>
<p> y As Long </span></font>
<p> End Type </span></font>
<p> Type Msg </span></font>
<p> hwnd As Long </span></font>
<p> message As Long </span></font>
<p> wParam As Long </span></font>
<p> lParam As Long </span></font>
<p> time As Long </span></font>
<p> pt As POINTAPI </span></font>
<p> End Type </span></font>
<p> Public Const WM_USER
= &H400 </span></font>
<p> Public Const WM_RBUTTONDOWN
= &H204 </span></font>
<p> Public Const WM_LBUTTONDOWN
= &H201 </span></font>
<p> Public Const GWL_WNDPROC
= -4 </span></font>
<p> Public trayflag As Boolean
</span></font>
<p> Global lpPrevWndProc
As Long </span></font>
<p> Global gHW As Long </span></font>
<p> 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 </span></font>
<p> Declare Function SetWindowLong
Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex
As Long, ByVal dwNewLong As Long) As Long </span></font>
<p> '以下过程为消息循环处理 </span></font>
<p> Function WindowProc(ByVal
hw As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As
Long) As Long </span></font>
<p> If hw = Form1.hwnd And
uMsg = WM_USER+100 Then'检测到鼠标点动托盘图标 </span></font>
<p> Select Case lParam
</span></font>
<p> Case WM_RBUTTONDOWN
'鼠标右键按下 </span></font>
<p> Form1.PopupMenu Form1.traymnu
'弹出菜单 </span></font>
<p> Case WM_LBUTTONDOWN
'鼠标左键按下 </span></font>
<p> Form1.PopupMenu Form1.mnutray2
'弹出菜单 </span></font>
<p> Case Else </span></font>
<p> End Select </span></font>
<p> Else '调用缺省窗口指针 </span></font>
<p> WindowProc = CallWindowProc(lpPrevWndProc,
hw,uMsg, wParam, lParam) </span></font>
<p> End If </span></font>
<p> End Function </span></font>
<p> 2、TRAY.frm源代码 </span></font>
<p> Dim MyNot As NOTIFYICONDATA
'定义一个托盘结构 </span></font>
<p> Private Sub Command1_Click()
'鼠标按下删除按钮 </span></font>
<p> With MyNot </span></font>
<p> .hIcon = Form1.Icon
'托盘图标指针 </span></font>
<p> .hwnd = Form1.hwnd
'窗体指针 </span></font>
<p> .szTip = "" '弹出提示字符串
</span></font>
<p> .uCallbackMessage =
WM_USER+100 '对应程序定义的消息 </span></font>
<p> .uFlags = NIF_ICON
Or NIF_TIP Or NIF_MESSAGE '标志 </span></font>
<p> .uID = 1 '图标识别符 </span></font>
<p> .cbSize = Len(MyNot)
'计算该结构所占字节数 </span></font>
<p> End With </span></font>
<p> hh = Shell_NotifyIcon(NIM_DELETE,
MyNot) '删除该图标 </span></font>
<p> trayflag = False '图标删除后trayflag为假
</span></font>
<p> End Sub </span></font>
<p> Private Sub Command2_Click()
'按下创建按钮 </span></font>
<p> Dim hh As Long </span></font>
<p> With MyNot </span></font>
<p> .hIcon = Form1.Icon
</span></font>
<p> .hwnd = Form1.hwnd
</span></font>
<p> .szTip = "托盘图标" &
Chr(&H0) </span></font>
<p> .uCallbackMessage =
WM_USER+100 </span></font>
<p> .uFlags = NIF_ICON
Or NIF_TIP Or NIF_MESSAGE </span></font>
<p> .uID = 1 </span></font>
<p> .cbSize = Len(MyNot)
</span></font>
<p> End With </span></font>
<p> hh = Shell_NotifyIcon(NIM_ADD,
MyNot) '添加一个托盘图标 </span></font>
<p> trayflag = True '图标添加后trayflag为真
</span></font>
<p> End Sub </span></font>
<p> Private Sub Command3_Click()
'修改托盘图标 </span></font>
<p> Dim hh As Long </span></font>
<p> Set P = LoadPicture("c:\dos\bridge.ico")
'导入一个新图标 </span></font>
<p> With MyNot </span></font>
<p> .hIcon = P '将托盘图标改为新图标
</span></font>
<p> .hwnd = Form1.hwnd
</span></font>
<p> .szTip = "桥梁图标" &
Chr(&H0) '更改提示信息 </span></font>
<p> .uCallbackMessage =
WM_USER+100 </span></font>
<p> .uFlags = NIF_ICON
Or NIF_TIP Or NIF_MESSAGE </span></font>
<p> .uID = 1 </span></font>
<p> .cbSize = Len(MyNot)
</span></font>
<p> End With </span></font>
<p> hh = Shell_NotifyIcon(NIM_MODIFY,
MyNot) '修改托盘的某些特征 </span></font>
<p> End Sub </span></font>
<p> Private Sub Command4_Click()
'END按钮被按下 </span></font>
<p> Quit '调用退出函数Quit </span></font>
<p> End Sub </span></font>
<p> Private Sub Form_Load()
</span></font>
<p> gHW = Me.hwnd '取得本窗体指针
</span></font>
<p> '下一句调用钩子函数,将自制消息处理函数钩入Windows的消息循环
</span></font>
<p> hook </span></font>
<p> End Sub </span></font>
<p> Public Sub hook() </span></font>
<p> '利用AddressOf取得消息处理函数WindowProc的指针,并将其传给SetWindowLong
</span></font>
<p> 'lpPrevWndProc用来存储原窗口的指针
</span></font>
<p> lpPrevWndProc = SetWindowLong(gHW,
GWL_WNDPROC, AddressOfWindowProc) </span></font>
<p> End Sub </span></font>
<p> Public Sub Unhook()
</span></font>
<p> '本子程序用原窗口的指针替换WindowProc函数的指针,即关闭子类、退出消息循环
</span></font>
<p> Dim temp As Long </span></font>
<p> temp = SetWindowLong(gHW,
GWL_WNDPROC, lpPrevWndProc) </span></font>
<p> End Sub </span></font>
<p> Private Sub mnuhideForm_Click()
'点中弹出菜单的‘隐藏’功能 </span></font>
<p> Form1.Hide '将窗体隐藏 </span></font>
<p> End Sub </span></font>
<p> Private Sub mnumaxForm_Click()
'点中弹出菜单的‘最大化’功能 </span></font>
<p> formstatus (2) '窗体最大化
</span></font>
<p> End Sub </span></font>
<p> Private Sub mnuminForm_Click()
'点中弹出菜单的‘最小化’功能 </span></font>
<p> formstatus (1) '窗体最小化
</span></font>
<p> End Sub </span></font>
<p> Private Sub mnunorForm_Click()
'点中弹出菜单的‘正常’功能 </span></font>
<p> formstatus (0) '窗体还原到正常
</span></font>
<p> End Sub </span></font>
<p> Public Sub quit() '退出
</span></font>
<p> If trayflag = True
Then Command1_Click '托盘图标仍在,模拟按下‘删除’按钮 </span></font>
<p> Unhook '退出消息循环 </span></font>
<p> Unload Me '卸载窗体 </span></font>
<p> End Sub </span></font>
<p> Private Sub mnuQuit_Click()
'点中弹出菜单的‘退出’功能 </span></font>
<p> quit </span></font>
<p> End Sub </span></font>
<p> Public Sub formstatus(ByVal
wstates) '根据传递的参数变化窗体的状态 </span></font>
<p> Form1.WindowState =
wstates '设置窗体的状态 </span></font>
<p> Form1.Show '显示窗体 </span></font>
<p> End Sub </span></font>
<p> 对于Shell_NotifyIcon函数的介绍可参见Win32
API类的书籍。因为在VB中使用函数指针将大大降低程序的坚固性,所以在应用与其相关的函数及关键字时应多加小心。在工作的时候必须经常地保存和备份工作成果。也可以借用第三方的回调消息控件来实现消息循环,这样做会比较安全一些。有兴趣的读者还可以参阅以下网址:www.mywebpages.com/nagar(VB编程的各种技术及控件)、www.chez.com/scribe/vb_us.htm(在VB中用OpenGL、DirectX编程)、
www.apexsc.com/vb/index.html(VB编程之家)。希望与我进一步交流的朋友请e-mail至cuijb@163.net。
</span></font>
<p> (辽宁大连沙河口区凌北路11号 管理推进室
116023 崔佳宾) </span></font>
<p>
<p align=center> </p>
<p></p>
<p align="left">
</table>
</div>
<p align="center"><a href="../../pian/vb.htm">回首页</a>
<p align="center"><script src="../../2.js"></script></a>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -