程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> 匯編語言 >> 匯編教程:系統托盤中的快捷圖標

匯編教程:系統托盤中的快捷圖標

編輯:匯編語言

本課中,我們將學習如何把小圖標放到系統托盤中去以及如何創建和使用彈出式菜單。

理論:

系統托盤是指任務條中的一個方形區域,在該區域中可以放入一些小圖標,通常您可以在此處看到系統提供的最新時間。您自己當然也可以把快捷小圖標放到此處。下面是這麼做的步驟:

設置NOTIFYICONDATA型的結構體變量的成員變量的值:

cbSize 該結構體的大小。

hwnd 窗口的句柄。當鼠標滑過該小圖標時,該窗口將接收到相關的消息。

uID 小圖標的ID號。您可以取任意值,只是當您的應用程序有不止一個小圖標時,您要能夠區分出到底是那一個小圖標接收到了鼠標的消息,也即ID號必須唯一。

uFlags 指定該結構體變量的那些成員變量有效。

NIF_ICON 有效。

NIF_MESSAGE 有效。

NIF_TIP 有效。

uCallbackMessage 自定義的消息。當鼠標對小圖標動作時,WINDOWS外殼將把該消息發送到您的應用程序。該消息的值您可以自己定義。

hIcon 放入系統托盤中的圖標的句柄。

szTip 64字節的緩沖區,它用來放入提示字符串,當鼠標停留在小圖標上時,就會顯示該字符串。

調用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函數來顯示它。步驟如下:

調用CreatePopupMenu函數來創建菜單。該函數創建一個空的菜單。如果成功,將在eax中返回該菜單的句柄。

調用AppendMenu, InsertMenu 或 InsertMenuItem來向菜單中加入菜單項。

當您想在當前鼠標位置顯示該菜單時,調用GetCursorPosition函數來得到鼠標當前的屏幕位置,然後調用TrackPopupMenu來顯示菜單。當用戶從彈出式菜單中選擇了一個菜單項時,WINDOWS將發送WM_COMMAND消息給您應用程序的消息處理過程,這和通常的菜單選擇是一樣的。.

注意:當您使用系統托盤中的小圖標時有兩件比較討厭的事:

該菜單可能不會像通常那樣馬上消失掉。這是因為從彈出式接收消息的窗口必須是前景窗口。調用SetForegroundWindow函數就可以糾正該錯誤;

在調用了SetForegroundWindow函數後,您會發現第一次該彈出式菜單會正常彈出而且工作的很好。但是隨後,該菜單只是一彈出就立即消失。根據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號。這是一個用戶自定義的值,它用來唯一地代表菜單項。.

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是在代碼開始處定義的一個數值常量,您可以任意設定它的值。由於我們僅有一個圖標,所以這一點並不重要,如果要同時加入幾個系統圖標的話,那麼每個圖標都要有一個唯一的ID號。由於我們指定了一個圖標NIF_ICON,所以我們要在uFlags成員變量中指定所有的標志位,我們還指定了一個自定義的消息NIF_MESSAGE和幫助文本NIF_TIP。 WM_SHELLNOTIFY 被定義為WM_USER+5,只要是唯一的值,就無所謂是多少了,只要大於WM_USER。我們這裡用的是WINDOWS登錄時的圖標,當然您可以使用任意您想要用的圖標,您可以用LoadIcon函數從資源中裝載,該函數返回一個圖標的句柄。最後我們在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
.else
invoke DestroyWindow,hWnd
.endif


  當用戶選擇恢復主窗口時,我們調用Shell_NotifyIcon函數來刪除掉系統托盤中的圖標,這一次我們要指定NIM_DELETE消息。接下來我們把主窗口恢復到原始的狀態。如果用戶選擇了Exit菜單項,我們不但把圖標給刪除掉,也從整個的應用程序中退出。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved