VB Shell_NotifyIcon函数设计托盘程序问题

我想在程序缩小到托盘后,然后单击任务栏中的托盘后弹出菜单,我是用窗口程序设计的,通过窗口程序截取WM_RBUTTONUP消息后,用PopupMenuha这句完成,但实现不... 我想在程序缩小到托盘后,然后单击任务栏中的托盘后弹出菜单,我是用窗口程序设计的,通过窗口程序截取WM_RBUTTONUP消息后,用PopupMenu ha这句完成,但实现不了,一运行程序就发生错误自动关闭了.用窗口程序怎样该呢?请高手帮忙解答!
下面是我的代码:
模块代码:
Option Explicit

Type NOTIFYICONDATA
cbSize As Long
hwnd As Long
uID As Long
uFlags As Long
uCallbackMessage As Long
hIcon As Long
szTip As String * 64
End Type
Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
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
Declare Function Shell_NotifyIcon Lib "shell32.dll" Alias "Shell_NotifyIconA" (ByVal dwMessage As Long, lpData As NOTIFYICONDATA) As Long
Public Const WM_MOUSEMOVE = &H200
Public Const NIM_ADD = &H0
Public Const NIF_ICON = &H2
Public Const NIF_MESSAGE = &H1
Public Const NIF_TIP = &H4
Public Const GWL_WNDPROC = (-4)
Public Const WM_LBUTTONDOWN = &H201
Public Const NIM_DELETE = &H2
Public Const WM_RBUTTONUP = &H205
Public p As Long, id As NOTIFYICONDATA

程序代码:
Private Sub Command1_Click()
Dim r As Long
p = GetWindowLong(Form1.hwnd, GWL_WNDPROC)
r = SetWindowLong(Form1.hwnd, GWL_WNDPROC, AddressOf wn)
id.cbSize = Len(id)
id.hwnd = Me.hwnd
id.uID = 9999
id.uFlags = NIF_ICON + NIF_TIP + NIF_MESSAGE
id.uCallbackMessage = 9000
id.hIcon = Me.Icon
id.szTip = "haha" + Chr(0)
Call Shell_NotifyIcon(NIM_ADD, id)
End Sub

Private Sub Form_Unload(Cancel As Integer)
Dim r As Long
r = SetWindowLong(Form1.hwnd, GWL_WNDPROC, p)
Call Shell_NotifyIcon(NIM_DELETE, id)
End Sub

还有一种方法,到是能实现弹出菜单,但代码中有些语句我不明白,还请能够给解释下.
Private Sub Command1_Click()
Form1.Hide
Dim id As NOTIFYICONDATA
id.cbSize = Len(id)
id.hwnd = Me.hwnd
id.uID = 9999
id.uFlags = NIF_ICON + NIF_TIP + NIF_MESSAGE
id.uCallbackMessage = WM_MOUSEMOVE
id.hIcon = Me.Icon
id.szTip = "haha" + Chr(0)
Call Shell_NotifyIcon(NIM_ADD, id)
End Sub

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim mm As Long
mm = X / Screen.TwipsPerPixelX
Select Case mm
Case WM_LBUTTONDOWN
PopupMenu ha
End Select
End Sub

代码里为什么用X来判断消息的类型呢?我用Y就不行,请问应该怎样理解!
我的窗口程序拉下了一段代码,在模块里的代码补充:
Function wn(ByVal hwnd As Long, ByVal msg As Long, ByVal wparam As Long, ByVal iparam As Long) As Long
If msg = 9000 Then
Select Case iparam
Case WM_LBUTTONDOWN
Form1.Show
Case WM_RBUTTONUP
PopupMenu ha
End Select
End If
wn = CallWindowProc(p, hwnd, msg, wparam, iparam)
End Function
展开
 我来答
swx1995
2009-06-01 · TA获得超过2696个赞
知道大有可为答主
回答量:1477
采纳率:0%
帮助的人:2362万
展开全部
Private Sub Command1_Click()
Dim r As Long
p = GetWindowLong(Form1.hwnd, GWL_WNDPROC)
r = SetWindowLong(Form1.hwnd, GWL_WNDPROC, AddressOf wn)
id.cbSize = Len(id)
id.hwnd = Me.hwnd
id.uID = 9999
id.uFlags = NIF_ICON + NIF_TIP + NIF_MESSAGE
id.uCallbackMessage = 9000
id.hIcon = Me.Icon
id.szTip = "haha" + Chr(0)
Call Shell_NotifyIcon(NIM_ADD, id)
End Sub

主要在这段。
由于托盘图标点击以后我们要做事情(转移Windows的处理程序),因此我们要用SetWindowlong把自己过程传进去代替原有(什么都不干)的处理程序。
这其中Windows怎么知道你过程在哪里(怎么传东西给你)呢?你就要传指针(内存地址)。于是Addressof出现了,它是一个运算符 返回一个函数/过程的内存地址。

但是问题是……Addressof不能在窗体中用。因此你可以尝试把这一段写入模块中一个自己过程如:Sub NewTrayIcon(),然后窗体中Call NewTrayIcon即可。

X的问题:
X是鼠标横坐标 但是单位是Twip(默认15Twip=1Px)。后面你可以看到Screen.TwipsPerPixelX就是15.windows中单位一般都是像素,所以我们要转换。但是为什么用X来判断消息类别……这个也很奇异。这种写法MSDN肯定不推荐,不建议使用。只是投机取巧的办法。
AiPPT
2024-09-19 广告
随着AI技术的飞速发展,如今市面上涌现了许多实用易操作的AI生成工具1、简介:AiPPT: 这款AI工具智能理解用户输入的主题,提供“AI智能生成”和“导入本地大纲”的选项,生成的PPT内容丰富多样,可自由编辑和添加元素,图表类型包括柱状图... 点击进入详情页
本回答由AiPPT提供
katar1024
2009-06-02 · TA获得超过942个赞
知道小有建树答主
回答量:511
采纳率:0%
帮助的人:531万
展开全部
WM_MOUSEMOVE消息的wparam的前一半包含x坐标值,后一半包含y坐标值,当VB接收到WM_MOUSEMOVE消息以后会分离lparam的xy坐标信息,按照form的scalemode经过单位转换后触发mousemove事件
正因为VB在处理WM_MOUSEMOVE,可以分离lparam的两个部分,而托盘发送来的消息的鼠标动作包含在lparam的前半部分,我们设置托盘选择发送的是WM_MOUSEMOVE,并预备触发mousemove事件,VB自动把lparam分离并转换,所以事件中的x值实际上是已经经过单位转换过的鼠标消息,需要通过X / Screen.TwipsPerPixelX转换回来
所以后如果要单独处理lparam,不能用Select Case iparam
而应该用Select Case iparam and &Hffff

一般我接收消托盘息使用一个picturebox的hwnd,你可以把它隐藏,然后处理mousemove事件,使用form的hwnd会发生一些冲突情况,而且给调试带来困难

setwindowlong方法当然用也行,不过调试风险很大,使用form的hwnd风险还要再加一等,出错的原因好象在CallWindowProc那句写错了,应该写成
wn = CallWindowProc(byval p,byval hwnd,byval msg,byval wparam,byval iparam)
这个方法很危险,不建议使用,用picturebox安全而且省事

觉得好再加点分吧,谢谢
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
收起 1条折叠回答
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式