系統托盤中的快捷圖示(轉)

heying1229發表於2007-07-28
系統托盤中的快捷圖示:

  本課中,我們將學習如何把小圖示放到系統托盤中去以及如何建立和使用彈出式選單。
理論:
系統托盤是指任務條中的一個方形區域,在該區域中可以放入一些小圖示,通常您可以在此處看到系統提供的最新時間。您自己當然也可以把快捷小圖示放到此處。下面是這麼做的步驟:
設定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 masm32includewindows.inc
include masm32includeuser32.inc
include masm32includekernel32.inc
include masm32includeshell32.inc
includelib masm32libuser32.lib
includelib masm32libkernel32.lib
includelib masm32libshell32.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選單項,我們不但把圖示給刪除掉,也從整個的應用程式中退出。

[@more@]

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10172717/viewspace-928739/,如需轉載,請註明出處,否則將追究法律責任。

相關文章