系统托盘中的快捷图标_我是仙剑NPC_新浪博客

先秀一下我的成果:

 

理论:

系统托盘是指任务条中的一个方形区域,在该区域中可以放入一些小图标,通常您可以在此处看到系统提供的{zx1}时间。您自己当然也可以把快捷小图标放到此处。下面是这么做的步骤:
  1. 设置NOTIFYICONDATA型的结构体变量的成员变量的值:
    • cbSize   该结构体的大小。
    • hwnd 窗口的句柄。当鼠标滑过该小图标时,该窗口将接收到相关的消息。
    • uID         小图标的ID号。您可以取任意值,只是当您的应用程序有不止一个小图标时,您要能够区分出到底是那一个小图标接收到了鼠标的消息,也即ID号必须{wy}。
    • uFlags    指定该结构体变量的那些成员变量有效。
      • NIF_ICON 有效。
      • NIF_MESSAGE 有效。
      • NIF_TIP 有效。
    • uCallbackMessage  自定义的消息。当鼠标对小图标动作时,WINDOWS外壳将把该消息发送到您的应用程序。该消息的值您可以自己定义。
    • hIcon      放入系统托盘中的图标的句柄。
    • szTip    64字节的缓冲区,它用来放入提示字符串,当鼠标停留在小图标上时,就会显示该字符串。
  2. 调用Shell_NotifyIcon函数。该函数在shell32.inc中定义,其原型如下:


                Shell_NotifyIcon PROTO dwMessage:DWORD ,pnid:DWORD

        dwMessage  是发送到WINDOWS外壳的消息:
               NIM_ADD 把小图标加到系统托盘区。
              NIM_DELETE 从系统托盘中删除小图标。
              NIM_MODIFY 修改小图标。
        pnid  是指向NOTIFYICONDATA型结构体变量的指针。
    如果您想要加入一个小图标就用NIM_ADD,删除时使用NIM_DELETE消息。

基本上的消息就是这些。但是大多数的情况下,您不会仅仅满足把一个小图标放到那里。您还必须要对鼠标事件作出适当的反应。您可以在NOTIFYICONDATA型的结构体变量的成员变量uCallbackMessage 中设置您要处理的消息,然后WINDOWS外壳将在发生这些事件时通知您的应用程序。随着消息传送的参数wParam和lParam的值如下:
  • wParam 小图标的ID号。它和您在NOTIFYICONDATA型结构体变量中的成员变量uID中设置的值一样。
  • lParam 低字包含鼠标消息。譬如,用户在小图标上按下了右键时,lParam中将包含WM_RBUTTONDOWN消息。
大多数的系统托盘中的小图标,在用户用鼠标右击时都会弹出一个菜单以方便用户选择。我们可先创建菜单,然后调用TrackPopupMenu函数来显示它。步骤如下:
  1. 调用CreatePopupMenu函数来创建菜单。该函数创建一个空的菜单。如果成功,将在eax中返回该菜单的句柄。
  2. 调用AppendMenu, InsertMenu 或 InsertMenuItem来向菜单中加入菜单项。
  3. 当您想在当前鼠标位置显示该菜单时,调用GetCursorPosition函数来得到鼠标当前的屏幕位置,然后调用TrackPopupMenu来显示菜单。当用户从弹出式菜单中选择了一个菜单项时,WINDOWS将发送WM_COMMAND消息给您应用程序的消息处理过程,这和通常的菜单选择是一样的。.
注意:当您使用系统托盘中的小图标时有两件比较讨厌的事:
  1. 该菜单可能不会像通常那样马上消失掉。这是因为从弹出式接收消息的窗口必须是前景窗口。调用SetForegroundWindow函数就可以纠正该错误;
  2. 在调用了SetForegroundWindow函数后,您会发现{dy}次该弹出式菜单会正常弹出而且工作的很好。但是随后,该菜单只是一弹出就立即消失。根据MSDN,这么做是故意的。为了使得弹出菜单保持住,必须要求下一个切换到的是程序的主窗口。您可以通过邮寄任何消息给该程序的窗口来强行进行任务切换。注意要使用PostMessage而不是SendMessage。

例子:

.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\shell32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\shell32.lib

WM_SHELLNOTIFY equ WM_USER+5
IDI_TRAY equ 0
IDM_RESTORE equ 1000
IDM_EXIT equ 1010
WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD

.data
ClassName  db "TrayIconWinClass",0
AppName    db "TrayIcon Demo",0
RestoreString db "&Restore",0
ExitString   db "E&xit Program",0

.data?
hInstance dd ?
note NOTIFYICONDATA <>
hPopupMenu dd ?

.code
start:
    invoke GetModuleHandle, NULL
    mov    hInstance,eax
    invoke WinMain, hInstance,NULL,NULL, SW_SHOWDEFAULT
    invoke ExitProcess,eax

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
    LOCAL wc:WNDCLASSEX
    LOCAL msg:MSG
    LOCAL hwnd:HWND
    mov   wc.cbSize,SIZEOF WNDCLASSEX
    mov   wc.style, CS_HREDRAW or CS_VREDRAW or CS_DBLCLKS
    mov   wc.lpfnWndProc, OFFSET WndProc
    mov   wc.cbClsExtra,NULL
    mov   wc.cbWndExtra,NULL
    push  hInst
    pop   wc.hInstance
    mov   wc.hbrBackground,COLOR_APPWORKSPACE
    mov   wc.lpszMenuName,NULL
    mov   wc.lpszClassName,OFFSET ClassName
    invoke LoadIcon,NULL,IDI_APPLICATION
    mov   wc.hIcon,eax
    mov   wc.hIconSm,eax
    invoke LoadCursor,NULL,IDC_ARROW
    mov   wc.hCursor,eax
    invoke RegisterClassEx, addr wc
    invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR AppName,\
WS_OVERLAPPED+WS_CAPTION+WS_SYSMENU+WS_MINIMIZEBOX+WS_MAXIMIZEBOX+WS_VISIBLE,CW_USEDEFAULT,\
           CW_USEDEFAULT,350,200,NULL,NULL,\
           hInst,NULL
    mov   hwnd,eax
    .while TRUE
        invoke GetMessage, ADDR msg,NULL,0,0
        .BREAK .IF (!eax)
        invoke TranslateMessage, ADDR msg
        invoke DispatchMessage, ADDR msg
    .endw
    mov eax,msg.wParam
    ret
WinMain endp

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    LOCAL pt:POINT
    .if uMsg==WM_CREATE
        invoke CreatePopupMenu
        mov hPopupMenu,eax
        invoke AppendMenu,hPopupMenu,MF_STRING,IDM_RESTORE,addr RestoreString
        invoke AppendMenu,hPopupMenu,MF_STRING,IDM_EXIT,addr ExitString
    .elseif uMsg==WM_DESTROY
        invoke DestroyMenu,hPopupMenu
        invoke PostQuitMessage,NULL
    .elseif uMsg==WM_SIZE
        .if wParam==SIZE_MINIMIZED
            mov note.cbSize,sizeof NOTIFYICONDATA
            push hWnd
            pop note.hwnd
            mov note.uID,IDI_TRAY
            mov note.uFlags,NIF_ICON+NIF_MESSAGE+NIF_TIP
            mov note.uCallbackMessage,WM_SHELLNOTIFY
            invoke LoadIcon,NULL,IDI_WINLOGO
            mov note.hIcon,eax
            invoke lstrcpy,addr note.szTip,addr AppName
            invoke ShowWindow,hWnd,SW_HIDE
            invoke Shell_NotifyIcon,NIM_ADD,addr note
        .endif
    .elseif uMsg==WM_COMMAND
        .if lParam==0
            invoke Shell_NotifyIcon,NIM_DELETE,addr note
            mov eax,wParam
            .if ax==IDM_RESTORE
                invoke ShowWindow,hWnd,SW_RESTORE
            .else
                invoke DestroyWindow,hWnd
            .endif
        .endif
    .elseif uMsg==WM_SHELLNOTIFY
        .if wParam==IDI_TRAY
            .if lParam==WM_RBUTTONDOWN
                invoke GetCursorPos,addr pt
                invoke SetForegroundWindow,hWnd
                invoke TrackPopupMenu,hPopupMenu,TPM_RIGHTALIGN,pt.x,pt.y,NULL,hWnd,NULL
                invoke PostMessage,hWnd,WM_NULL,0,0
            .elseif lParam==WM_LBUTTONDBLCLK
                invoke SendMessage,hWnd,WM_COMMAND,IDM_RESTORE,0
            .endif
        .endif
    .else
        invoke DefWindowProc,hWnd,uMsg,wParam,lParam
        ret
    .endif
    xor eax,eax
    ret
WndProc endp

end start
 

分析:

该程序将显示一个简单的窗口。当您按下最小化按钮时,该窗口将隐藏,然后放一个小图标到系统托盘中。当您双击小图标时,应用程序将恢复自己,并把小图标从系统托盘中删除。当您右击小图标时,会显示一个弹出式菜单。您可以在菜单中选择是恢复窗口还是退出应用程序。

   .if uMsg==WM_CREATE
        invoke CreatePopupMenu
        mov hPopupMenu,eax
        invoke AppendMenu,hPopupMenu,MF_STRING,IDM_RESTORE,addr RestoreString
        invoke AppendMenu,hPopupMenu,MF_STRING,IDM_EXIT,addr ExitString

当主窗口创建时,将会创建一个弹出式菜单,并且加入两个菜单项。 AppendMenu的语法如下:
 

AppendMenu PROTO hMenu:DWORD, uFlags:DWORD, uIDNewItem:DWORD, lpNewItem:DWORD
 
  • hMenu 是将要加入菜单项的菜单的句柄。
  • uFlags 告诉WINDOWS要加入的菜单项是位图、字符串或自画的项目以及是可用、不可用或灰色显示等。您可以从WIN32 API 指南中得到全部的标志位的信息。在我们的例子中使用标志位MF_STRING,它表示我们加入的菜单项是字符串。
  • uIDNewItem 是菜单项的ID号。这是一个用户自定义的值,它用来{wy}地代表菜单项。.
  • lpNewItem 用来指定菜单项的内容,具体代表什么取决于uFlags中指定的标志。我们前面指定了MF_STRING标志,所以此处代表一个字符串
主窗口创建完成后,用户就可以开始测试了。这时按下最小化键。
当一个窗口被最小化时将接收到WM_SIZE消息,其中wParam参数中的值为SIZE_MINIMIZED。

    .elseif uMsg==WM_SIZE
        .if wParam==SIZE_MINIMIZED
            mov note.cbSize,sizeof NOTIFYICONDATA
            push hWnd
            pop note.hwnd
            mov note.uID,IDI_TRAY
            mov note.uFlags,NIF_ICON+NIF_MESSAGE+NIF_TIP
            mov note.uCallbackMessage,WM_SHELLNOTIFY
            invoke LoadIcon,NULL,IDI_WINLOGO
            mov note.hIcon,eax
            invoke lstrcpy,addr note.szTip,addr AppName
            invoke ShowWindow,hWnd,SW_HIDE
            invoke Shell_NotifyIcon,NIM_ADD,addr note
        .endif

这时我们来给NOTIFYICONDATA型结构体变量赋值。IDI_TRAY是在代码开始处定义的一个数值常量,您可以任意设定它的值。由于我们仅有一个图标,所以这一点并不重要,如果要同时加入几个系统图标的话,那么每个图标都要有一个{wy}的ID号。由于我们指定了一个图标NIF_ICON,所以我们要在uFlags成员变量中指定所有的标志位,我们还指定了一个自定义的消息NIF_MESSAGE和帮助文本NIF_TIP。 WM_SHELLNOTIFY 被定义为WM_USER+5,只要是{wy}的值,就无所谓是多少了,只要大于WM_USER。我们这里用的是WINDOWS登录时的图标,当然您可以使用任意您想要用的图标,您可以用LoadIcon函数从资源中装载,该函数返回一个图标的句柄。{zh1}我们在szTip中放入当鼠标放在图标时显示的提示文本。为了达到“最小化然后只显示图标的效果”,我们在这时隐藏掉主窗口。
接下来,我们调用Shell_NotifyIcon函数并指定标志位NIM_ADD把图标加到系统托盘中去。

现在我们的主窗口隐藏了,图标显示在系统托盘中。如果您让鼠标从图标上滑过,将看到提示文本。如果您双击小图标,主窗口就会显示,图标将消失。

    .elseif uMsg==WM_SHELLNOTIFY
        .if wParam==IDI_TRAY
            .if lParam==WM_RBUTTONDOWN
                invoke GetCursorPos,addr pt
                invoke SetForegroundWindow,hWnd
                invoke TrackPopupMenu,hPopupMenu,TPM_RIGHTALIGN,pt.x,pt.y,NULL,hWnd,NULL
                invoke PostMessage,hWnd,WM_NULL,0,0
            .elseif lParam==WM_LBUTTONDBLCLK
                invoke SendMessage,hWnd,WM_COMMAND,IDM_RESTORE,0
            .endif
        .endif

当在系统托盘中的图标发生鼠标事件时,您的窗口将接收到WM_SHELLNOTIFY消息,该消息是在uCallbackMessage成员变量中指定的。在接收到该消息时,wParam中包含了图标的ID号,lParam中包含了鼠标动作的原始数据。在上面的代码中,我们首先检测是否是我们感兴趣的消息。如果是的话,我们在看看是什么消息。因为我们只对右击和双击事件感兴趣,所以我们仅仅处理WM_RBUTTONDOWN和WM_LBUTTONDBLCLK消息。
如果是WM_RBUTTONDOWN,我们调用GetCursorPos来得到鼠标光标所在的当前屏幕位置。注意我指的是屏幕位置,即,其坐标是相对于整个的屏幕的。譬如,如果屏幕的解析读640*480,那么它的右下角的坐标是x==639 ,y==479。如果您想要把屏幕位置转换成窗口的坐标,可以调用ScreenToClient函数
我们想要在当前的位置显示弹出式菜单,我们就调用TrackPopupMenu函数,该函数需要屏幕的坐标,由GetCursorPos函数返回的坐标就可以原封不动的拿过来用。
TrackPopupMenu的原型如下:
 

  • TrackPopupMenu PROTO hMenu:DWORD, uFlags:DWORD,  x:DWORD,  y:DWORD, nReserved:DWORD, hWnd:DWORD, prcRect:DWORD
     
  • hMenu 是弹出式菜单的句柄。
  • uFlags 功能的选择。像在哪里放置(相对于随后将指定的坐标)菜单,那一个鼠标按钮用来跟踪弹出式菜单。在我们的例子中,我们用TPM_RIGHTALIGN标志位来指定弹出式菜单放在坐标的左边。
  • x 和 y 指定放置菜单的屏幕坐标。
  • nReserved 必须为NULL。
  • hWnd 是将要接收消息的窗口的句柄。
  • prcRect 指定一个矩形区域。如果在该矩形区域外面按下鼠标的话,菜单将消失。一般我们把该值设为NULL,这样当用户只要在菜单外面按下鼠标,菜单立即消失。

 

当用户双击图标时,我们给我们自己的窗口发送WM_COMMAND消息,并指定消息为IDM_RESTORE,这样可以达到和在弹出式菜单中选择“Restore”菜单项同样的效果。为了能够接收到双击消息,主窗口必须要有的CS_DBLCLKS 风格。

            invoke Shell_NotifyIcon,NIM_DELETE,addr note
            mov eax,wParam
            .if ax==IDM_RESTORE
                invoke ShowWindow,hWnd,SW_RESTORE

         invoke SetForegroundWindow,hWnd;设为最前台窗口

             .else
                invoke DestroyWindow,hWnd
            .endif

当用户选择恢复主窗口时,我们调用Shell_NotifyIcon函数来删除掉系统托盘中的图标,这一次我们要指定NIM_DELETE消息。接下来我们把主窗口恢复到原始的状态。如果用户选择了Exit菜单项,我们不但把图标给删除掉,也从整个的应用程序中退出。

已投稿到:
郑重声明:资讯 【系统托盘中的快捷图标_我是仙剑NPC_新浪博客】由 发布,版权归原作者及其所在单位,其原创性以及文中陈述文字和内容未经(企业库qiyeku.com)证实,请读者仅作参考,并请自行核实相关内容。若本文有侵犯到您的版权, 请你提供相关证明及申请并与我们联系(qiyeku # qq.com)或【在线投诉】,我们审核后将会尽快处理。
—— 相关资讯 ——