Option ExplicitPrivate Sub Command1_Click()
    sDo Me.hwnd
    With nfIconData
       .hwnd = Me.hwnd
       .uID = 0
       .uFlags = NIF_ICON Or NIF_MESSAGE Or NIF_TIP
       .uCallbackMessage = WM_RBUTTONUP
       .hIcon = Me.Icon.Handle
       .szTip = "毛芽村" & vbNullChar
       .cbSize = Len(nfIconData)
    End With
    Shell_NotifyIcon NIM_ADD, nfIconData
End SubPrivate Sub Form_Unload(Cancel As Integer)
    sStep Me.hwnd
    Shell_NotifyIcon NIM_DELETE, nfIconData
End Sub模块:
Option ExplicitPublic Declare Function SetForegroundWindow Lib "user32" (ByVal hwnd As Long) As Long
Declare Function Shell_NotifyIcon Lib "shell32.dll" Alias "Shell_NotifyIconA" (ByVal dwMessage As Long, lpData As NOTIFYICONDATA) 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 SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As LongPublic Const WM_RBUTTONDOWN = &H204
Public Const WM_RBUTTONUP = &H205
Public Const WM_ACTIVATEAPP = &H1C
Public Const NIF_ICON = &H2
Public Const NIF_MESSAGE = &H1
Public Const NIF_TIP = &H4
Public Const NIM_ADD = &H0
Public Const NIM_DELETE = &H2
Public Const MAX_TOOLTIP As Integer = 64
Public Const GWL_WNDPROC = (-4)Type NOTIFYICONDATA
   cbSize As Long
   hwnd As Long
   uID As Long
   uFlags As Long
   uCallbackMessage As Long
   hIcon As Long
   szTip As String * MAX_TOOLTIP
End TypePublic nfIconData As NOTIFYICONDATA
Public winProc As LongPublic Function sProc(ByVal sWnd As Long, ByVal sMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    If sMsg = WM_RBUTTONUP And lParam = WM_RBUTTONDOWN Then
        SetForegroundWindow sWnd
        PopupMenu Form1.mnu_Pop
        sProc = True
        Exit Function
    End If
    sProc = CallWindowProc(winProc, sWnd, sMsg, wParam, lParam)
End Function'调用的setwindowlong函数不能在swnd的原窗体内
Public Function sDo(ByVal sWnd As Long)
    winProc = SetWindowLong(sWnd, GWL_WNDPROC, AddressOf sProc)
End FunctionPublic Function sStep(ByVal sWnd As Long)
    SetWindowLong sWnd, GWL_WNDPROC, winProc
End Function出错!各位帮看看是怎么回事???

解决方案 »

  1.   

    没看你的为什么出错,但如下是肯定没问题的!使用添加系统托盘的API函数!
    '申明
    Private 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 TypePrivate Const NIM_ADD = &H0
    Private Const NIM_MODIFY = &H1
    Private Const NIM_DELETE = &H2
    Private Const NIF_MESSAGE = &H1
    Private Const NIF_ICON = &H2
    Private Const NIF_TIP = &H4Private Const WM_LBUTTONDBLCLK = &H203
    Private Const WM_LBUTTONDOWN = &H201
    Private Const WM_RBUTTONUP = &H205Private Declare Function Shell_NotifyIcon Lib "shell32" Alias "Shell_NotifyIconA" (ByVal dwMessage As Long, pnid As NOTIFYICONDATA) As BooleanDim ty_NO As NOTIFYICONDATA
    '窗口操作
    Private Sub Form_Load()
        ty_NO.cbSize = Len(ty_NO)
        ty_NO.hwnd = frmCon.hwnd
        ty_NO.uId = 1&
        ty_NO.uFlags = NIF_ICON Or NIF_TIP Or NIF_MESSAGE
        ty_NO.ucallbackMessage = WM_LBUTTONDOWN
        ty_NO.hIcon = Me.Icon
        ty_NO.szTip = "数据更新...." & Chr$(0)
        Shell_NotifyIcon NIM_ADD, ty_NOEnd Sub
    Private Sub Form_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)
        Msg = x / Screen.TwipsPerPixelX
        If Msg = WM_LBUTTONDBLCLK Then
            'Left button double click
            mnuPop_Click 0
        ElseIf Msg = WM_RBUTTONUP Then
            'Right button click
            PopupMenu mnuPopup
            
        End IfEnd SubPrivate Sub Form_Unload(Cancel As Integer)
        'remove the icon
        TrayI.cbSize = Len(TrayI)
        TrayI.hwnd = Form1.hwnd
        TrayI.uId = 1&
        Shell_NotifyIcon NIM_DELETE, TrayI
        End
    End Sub
      

  2.   

    http://expert.csdn.net/Expert/FAQ/FAQ_Index.asp?id=197
      

  3.   

    没有把hook去掉,所以把ide关了
      

  4.   

    对,那是因为hook把消息发给IDE了,调试的时候父窗口是IDE
      

  5.   

    Agree! Try to run it after it is translated to executive file.
      

  6.   

    我的:
    Private Sub Form_Unload(Cancel As Integer)
        sStep Me.hwnd
        Shell_NotifyIcon NIM_DELETE, nfIconData
    End Sub
    不是把HOOK去掉了吗?
    小弟我第一次接触这类东西,还请大家多多指点开导,多谢!
      

  7.   

    Declare Function Shell_NotifyIcon Lib "shell32.dll" Alias "Shell_NotifyIconA" (ByVal dwMessage As Long, lpData As NOTIFYICONDATA) As Long   其中各参数的意义如下表: 参数: 意义 
    dwMessage 为消息设置值,它可以是以下的几个常数值:0、1、2
    NIM_ADD = 0     加入图标到系统状态栏中
    NIM_MODIFY = 1    修改系统状态栏中的图标
    NIM_DELETE = 2    删除系统状态栏中的图标 
     
    LpData 用以传入NOTIFYICONDATA数据结构变量,其结构如下所示:
    Type NOTIFYICONDATA
      cbSize As Long        需填入NOTIFYICONDATA数据结构的长度
      HWnd As Long         设置成窗口的句柄 
      Uid As Long         为图标所设置的ID值
      UFlags As Long        设置uCallbackMessage,hIcon,szTip是否有效
      UCallbackMessage As Long   消息编号
      HIcon As Long         显示在状态栏上的图标
      SzTip As String * 64     提示信息
    End Type
     
    返回值 Long,非零表示成功,零表示失败   在使用这个API函数之前我们应该先定义结构类型NOTIFYICONDATA:
       Public 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 
      然后定义一个NOTIFYICONDATA的变量TheData来记录设置托盘图标的数据
       Private TheData As NOTIFYICONDATA  这时我们就可以使用这个函数来设置系统托盘图标了,具体方法如下:
       1、添加图标
       With TheData 
        .Uid = 0
        .HWnd = frm.HWnd           'frm.HWnd是程序主窗体的句柄
        .cbSize = Len(TheData)
        .HIcon = frm.Icon.Handle       'frm.Icon.Handle指向主窗体的图标
        .UFlags = NIF_ICON
        .UCallbackMessage = TRAY_CALLBACK '作用是允许返回消息,在下一节中会有详细解释。
        .UFlags = .UFlags Or NIF_MESSAGE
        .cbSize = Len(TheData)
       End With
       Shell_NotifyIcon NIM_ADD, TheData    '根据前面定义NIM_ADD,设置为“添加模式”,然后添加   2、删去图标
       With TheData
        .UFlags = 0
       End With 
       Shell_NotifyIcon NIM_DELETE, TheData  '根据前面定义NIM_DELETE,设置为“删除模式”    3、更改图标
       With TheData 
        .HIcon = pic.Handle          'pic是图片狂PictureBox,存放图标文件
        .UFlags = NIF_ICON
       End With 
       Shell_NotifyIcon NIM_MODIFY, TheData  '根据前面定义NIM_MODIFY,设置为“更改模式”   4、为图标添加浮动提示信息
       With TheData 
        .SzTip = tip & vbNullChar       'tip是字符串string,存储提示信息
        .UFlags = NIF_TIP           '指明要对浮动提示进行设置 
       End With 
       Shell_NotifyIcon NIM_MODIFY, TheData  '根据前面定义NIM_MODIFY,设置为“修改模式”   通过以上几段代码我们就能根据自己需要添加、删除、更改系统托盘图标,并能添加系统图标上的浮动提示信息。但这时的托盘图标是孤立的,我们并不能利用它来控制应用程序的行为,怎么办呢?别急,接着下节的内容会继续这个例子的介绍,并给你答案的。如果你下载(源程序下载)并运行这个例程序,你会发现如果我们在托盘图标上点击鼠标右键,则会弹出一个右键菜单(如右图)。如果点击相应的菜单项,程序主窗体会随之变化,这样就可以控制程序的行为。而如果当主窗体处于最小化状态时,我们在托盘图标上点击左键,窗体会恢复到原来的大小。其实实现上述的功能都要依赖于WINDOWS操作系统的消息机制,要完全弄懂这个机制挺不容易的,但是我们可以按下述文字来理解它。  把WINDOWS操作系统看作人的大脑,它接收、处理、并发送各种各样的信息给我们的各个器官(当然是比喻各个应用程序了),也就是说它是消息的中枢。而每个应用程序(甚至每一个按钮、标签、窗体等等统称为窗口)在运行时都会被分配一个窗口过程WINDOWPROC,由这个窗口过程来接收和处理操作系统发来的消息(实际上存在一个消息队列),通常情况下这个窗口过程是由操作系统指定的,它会自动的响应并处理一些WINDOWS消息(如窗体移动、最大化、最小化、错误信息等)。好,到这我们先停一下,提出一个疑问,这些消息能否由我们自己写程序来处理呢?答案是肯定的,不过还得借助API函数的威力了,怎么用?我们还是先看看这些API函数的定义和参数吧。   程序中用到了SendMessage、CallWindowProc、SetWindowLong等API函数,其中SendMessage函数的作用是将一条消息发给某个窗口;CallWindowProc函数用来发送消息到一个窗口过程;而使用SetWindowLong函数来为窗口结构中为指定的窗口设置属性。使用API函数之前必须先在程序中声明如下:
       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 SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal HWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long 
       Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal HWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long   其中各参数的意义如下表: CallWindowProc函数
    参数: 意义 
    lpPrevWndFunc Long,原来的窗口过程地址
     
    HWnd Long,窗口句柄
     
    Msg Long,发送的消息 
    wParam Long,消息类型,参考wParam参数表 
    lParam Long,依据wParam参数的不同而不同 
    返回值 Long,依据发送的消息不同而变化 
    SetWindowLong函数 参数: 意义 
    hwnd Long,欲为其取得信息的窗口的句柄
     
    nIndex Long,请参考GetWindowLong函数的nIndex参数的说明
     
    dwNewLong Long,由nIndex指定的窗口信息的新值 
    返回值 Long,指定数据的前一个值 
    SendMessage函数 参数: 意义 
    hwnd Long,要接收消息的那个窗口的句柄
     
    wMsg Long,消息的标识符
     
    wParam Long,具体取决于消息 
    lParam Any,具体取决于消息 
    返回值 Long,由具体的消息决定   我们要自己写程序来处理消息,必须先更改窗口的属性,从原来由默认的窗口过程来处理消息变成由我们自己写的消息处理过程来处理消息。方法是使用SetWindowLong函数来取得默认窗口过程的地址,然后转向为我们自己写的窗口过程的地址,具体的实现方法如下代码:
       'GWL_WNDPROC获得该窗口的窗口过程的地址,AddressOf是取址函数,NewWindowProc是我们写的过程
       OldWindowProc = SetWindowLong(frm.HWnd, GWL_WNDPROC, AddressOf NewWindowProc)  然后在NewWindowProc函数中写入如下代码,需要注意的是下面代码中红色的TRAY_CALLBACK是由托盘区图标传来的消息,要让托盘图标传回消息,必须在添加托盘图标时指定(参见上节内容):
       Public Function NewWindowProc(ByVal HWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long 
       '如果用户点击了托盘中的图标,则进行判断是点击了左键还是右键
       If Msg = TRAY_CALLBACK Then 
         '如果点击了左键 
         If lParam = WM_LBUTTONUP Then
           '而这时窗体的状态是最小化时 
           If TheForm.WindowState = vbMinimized Then _ 
            '恢复到最小化前的窗体状态 
              TheForm.WindowState = TheForm.LastState 
              TheForm.SetFocus
              Exit Function
           End If 
         End If 
         '如果点击了右键 
         If lParam = WM_RBUTTONUP Then 
           '则弹出右键菜单 
           TheForm.PopupMenu TheMenu 
           Exit Function 
         End If 
       End If 
       '如果是其他类型的消息则传递给原有默认的窗口函数
       NewWindowProc = CallWindowProc(OldWindowProc, HWnd, Msg, wParam, lParam) 
       End Function   这样我们就取得并处理了来自托盘图标的消息,现在的问题是在鼠标右键菜单弹出后,怎么控制程序主窗体的状态,这时我们需要用到SendMessage函数来向主窗体发送最大化、最小化、关闭、移动等消息,具体的代码实现如下,其中HWnd是主窗体的句柄,WM_SYSCOMMAND表示发送的是系统控制类的消息,SC_MOVE、SC_SIZE、SC_RESTORE便是要发送的消息了:
       '托盘图标右键菜单上的“移动”项被点击时
       Private Sub mnuTrayMove_Click() 
         SendMessage HWnd, WM_SYSCOMMAND, SC_MOVE, 0& 
       End Sub 
       '托盘图标右键菜单上的“恢复”项被点击时 
       Private Sub mnuTrayRestore_Click() 
         SendMessage HWnd, WM_SYSCOMMAND, SC_RESTORE, 0& 
       End Sub 
       '托盘图标右键菜单上的“退出”项被点击时 
       Private Sub mnuTraySize_Click() 
         SendMessage HWnd, WM_SYSCOMMAND, SC_SIZE, 0& 
       End Sub