今天我們來看看VB.NET怎樣將程序窗口嵌入到任務(wù)欄(Taskbar)中,下圖是我們實(shí)現(xiàn)的效果。
開始之前,小孟先簡單介紹一下任務(wù)欄的組成,在這里小孟只介紹與我們的程序有關(guān)的部分。整個(gè)任務(wù)欄是有一個(gè)大的窗口容器(該容器類名是Shell_TrayWnd)和一些窗口共同組成的,在這個(gè)類名是Shell_TrayWnd的容器中,有一個(gè)類名是ReBarWindow32的二級容器。這個(gè)二級容器中包含的窗口在Win7和WinXP中是不同的(小孟使用的Win7,不過在這個(gè)程序中Win7和WinXP的效果都是一樣的)。在WinXP中,包含一個(gè)類名是MSTaskSwWClass的窗口外,這個(gè)窗口就是來顯示任務(wù)欄按鈕的(就是顯示你打開了哪些窗口的那個(gè)區(qū)域,在這里小孟叫他最小化窗口),還包含快速啟動(dòng)欄(在左側(cè)以小圖標(biāo)顯示,單擊后會啟動(dòng)相應(yīng)程序的那個(gè)區(qū)域);在Win7中只有一個(gè)類名是MSTaskSwWClass的窗口,因?yàn)閃in7中沒有快速啟動(dòng)欄,雖然左側(cè)也有一個(gè)類似快速啟動(dòng)的區(qū)域,但那個(gè)并不是快速啟動(dòng),而是屬于最小化窗口的一部分。以上就是與我們程序有關(guān)的任務(wù)欄組成了,小孟這表達(dá)能力很有限,大家可能看不懂,so 小孟在下面貼了一張圖。
=====================================================================================
Win7:
紅色區(qū)域:類名是Shell_TrayWnd的容器 黃色區(qū)域:類名是ReBarWindow32的二級容器
綠色區(qū)域:類名是MSTaskSwWClass的窗口
WinXP:
紅色區(qū)域:紅色區(qū)域——類名是Shell_TrayWnd的容器 黃色區(qū)域:類名是ReBarWindow32的二級容器 綠色區(qū)域:快速啟動(dòng)區(qū)域 紫色窗口:類名是MSTaskSwWClass的窗口
=====================================================================================
任務(wù)欄組成我們介紹完了,下面我們說說大體的思路。首先,我們要最小化窗口的width縮短,來給我們的程序騰出地方;然后,將我們的程序設(shè)置成任務(wù)欄的子窗口,以便于嵌入任務(wù)欄;最后,調(diào)整程序的大小和在任務(wù)欄中的位置。
準(zhǔn)備工作做了這么多,下面正式開工。
新建一個(gè)【W(wǎng)indows窗體應(yīng)用程序】。將窗體BorderStyle屬性改成None來把窗體的邊框去掉。然后在窗體上添加一個(gè)文本框,如下圖所示:
下面開始寫代碼。
我們先把程序需要用到的API和structure來聲明一下(先在類外面加上ImportsSystem.Runtime.InteropServices):
-
- Private Declare Function FindWindow Lib "user32" _
- Alias "FindWindowA" (ByVal lpClassName As String, _
- ByVal lpWindowName As String) As Integer
-
-
- Private Declare Function FindWindowEx Lib "user32" _
- Alias "FindWindowExA" (ByVal hWnd1 As Integer, _
- ByVal hWnd2 As Integer, _
- ByVal lpsz1 As String, _
- ByVal lpsz2 As String) As Integer
-
-
- Private Declare Function SetParent Lib "user32" _
- Alias "SetParent" (ByVal hWndChild As Integer, _
- ByVal hWndNewParent As Integer) As Integer
-
-
- Private Declare Function MoveWindow Lib "user32" _
- Alias "MoveWindow" (ByVal hWnd As IntPtr, _
- ByVal x As Integer, _
- ByVal y As Integer, _
- ByVal nWidth As Integer, _
- ByVal nHeight As Integer, _
- ByVal bRepaint As Integer) As Integer
-
-
- Private Declare Function GetWindowRect Lib "user32" _
- Alias "GetWindowRect" (ByVal hWnd As IntPtr, _
- ByRef lpRect As RECT) As Integer
-
- <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
- Private Structure RECT
- Public Left As Integer
- Public Top As Integer
- Public Right As Integer
- Public Bottom As Integer
- End Structure
為了方便調(diào)試,我們先添加程序退出的代碼:
- Private Sub cmdTextBox_KeyPress(ByVal sender As Object, ByVal e As _
- System.Windows.Forms.KeyPressEventArgs) _
- Handles cmdTextBox.KeyPress
- If e.KeyChar = Chr(13) Then
- If UCase(cmdTextBox.Text) = "END" Then
- Me.Close()
- End If
- End If
- End Su
這樣,我們就可以通過在文本框里輸入“end”,然后按回車來退出程序了。
既然要改變最小化窗口的width,那么我們就先來找最小化窗口的Handle,先聲明一個(gè)全局變量,來儲存我們找到的最小化窗口的Handle:
接下來,我們查找最小化窗口的句柄(下面的代碼都在窗體的Load事件里):
- Dim hTaskbar, hBar As Long
- hTaskbar = FindWindow("Shell_TrayWnd", vbNullString)
- hBar = FindWindowEx(hTaskbar, 0, "ReBarWindow32", vbNullString)
- hMin = FindWindowEx(hBar, 0, "MSTaskSwWClass", vbNullString)
找到句柄后,我們來獲得二級容器的坐標(biāo)和最小化窗口的坐標(biāo):
- Dim rcBar As RECT
- GetWindowRect(hMin, rcMin)
- GetWindowRect(hBar, rcBar)
下面我們通過用MoveWindow函數(shù)來改變窗口的width:
- MoveWindow(hMin, 0, 0, rcMin.Right - rcMin.Left - Me.Width, _
- rcMin.Bottom - rcMin.Top, True)
已經(jīng)為任務(wù)欄騰出地方了,是時(shí)候把程序嵌入到任務(wù)欄里了:
- SetParent(Me.Handle, hBar)
調(diào)整程序窗口的大小和位置:
- Me.Height = cmdTextBox.Height
- Me.Width = cmdTextBox.Width
- MoveWindow(Me.Handle, rcMin.Right - rcMin.Left - Me.Width + 2, _
- (rcBar.Bottom - rcBar.Top - Me.Height) / 2, _
- Me.Width, Me.Height, True)
把程序窗口嵌入到任務(wù)欄里的任務(wù)已經(jīng)完成了,但我們還需要處理一下窗體的Closing事件,使程序關(guān)閉的時(shí)候,把最小化窗口的width恢復(fù)回去(下面這一行代碼放在窗體的Closing事件里):
- MoveWindow(hMin, 0, 0, rcMin.Right - rcMin.Left, rcMin.Bottom - rcMin.Top, True)
終于完成了,現(xiàn)在可以運(yùn)行看一下效果了,和文章一開始的效果一樣吧?
By Alexis·M(小孟)