* 本文章只是对KyleMong写的《HOW TO :将程序嵌入任务栏中》做一个总结和延伸。请先看完《HOW TO :将程序嵌入任务栏中》后再浏览本文。
首先,我们先来具体了解下XP任务栏的结构
1.整个任务栏的类名为Shell_TrayWnd
2.其下分为了三个区:开始按钮,中间任务栏和右下角任务栏:
1)开始按钮: 类名为BUTTON,标题为"开始",控件ID为0x130
2)中间任务栏:类名为ReBarWindow32,控件ID为0xA005,其下又有三个子窗口:
i.快速启动栏: 类名:ToolbarWindow32,Title:Quick Launch
ii.正在运行程序栏:类名:MSTaskSwWClass,Title:运行应用程序;再其下又有一个类名:ToolbarWindow32,Title:运行应用程序
iii.文字输入语言栏:类名:CiceroUIWndFrame,Title:TF_FloatingLangBar_WndTitle
3.右下角任务栏:类名:TrayNotifyWnd,其下有也有三个子窗口:
1)时间显示栏:类名:TrayClockWClass,Title:当前时间如19:00
2)主要显示栏:类名:SysPager,其下有个子窗口,就是我们最常见的最小化到右下角任务栏的地方:类名:ToolbarWindow32,Title:通知区域
3)一个button,类名:Button,控件ID为0x5DE
好了,有了类名我们就可以通过FindWindow和FindWindowEx来找到它们的句柄,接着就可以进行操作了。
接下来我们介绍几个API在VB中的运用
'第一个是FindWindow
Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String,ByVal lpWindowName As String) As Long
lpClassName '类名
指向一个以null结尾的、用来指定类名的字符串或一个可以确定类名字符串的原子。如果这个参数是一个原子,那么它必须是一个在调用此函数前已经通过GlobalAddAtom函数创建好的全局原子。这个原子(一个16bit的值),必须被放置在lpClassName的低位字节中,lpClassName的高位字节置零。
如果该参数为null时,将会寻找任何与lpWindowName参数匹配的窗口。
lpWindowName '窗体名
指向一个以null结尾的、用来指定窗口名(即窗口标题)的字符串。如果此参数为NULL,则匹配所有窗口名。
'第二个是FindWindowEx
Public Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long,ByVal hWnd2 As Long,ByVal lpsz1 As String,ByVal lpsz2 As String) As Long
函数功能:该函数获得一个窗口的句柄,该窗口的类名和窗口名与给定的字符串相匹配。这个函数查找子窗口,从排在给定的子窗口后面的下一个子窗口开始。在查找时不区分大小写。
hwndParent
要查找子窗口的父窗口句柄。
如果hwndParent为NULL,则函数以桌面窗口为父窗口,查找桌面窗口的所有子窗口。
Windows NT5.0 and later:如果hwndParent是HWND_MESSAGE,函数仅查找所有消息窗口。
hwndChildAfter
子窗口句柄。查找从在Z序中的下一个子窗口开始。子窗口必须为hwndParent窗口的直接子窗口而非后代窗口。如果HwndChildAfter为NULL,查找从hwndParent的第一个子窗口开始。如果hwndParent 和 hwndChildAfter同时为NULL,则函数查找所有的顶层窗口及消息窗口。
lpszClass
指向一个指定了类名的空结束字符串,或一个标识类名字符串的成员的指针。如果该参数为一个成员,则它必须为前次调用theGlobaIAddAtom函数产生的全局成员。该成员为16位,必须位于lpClassName的低16位,高位必须为0。
lpszWindow
指向一个指定了窗口名(窗口标题)的空结束字符串。如果该参数为 NULL,则为所有窗口全匹配。返回值:如果函数成功,返回值为具有指定类名和窗口名的窗口句柄。如果函数失败,返回值为NULL。
'第三个是GetWindowRect
Public Declare Function GetWindowRect Lib "user32" Alias "GetWindowRect" (ByVal hwnd As Long,lpRect As RECT) As Long
函数功能:该函数返回指定窗口的边框矩形的尺寸。该尺寸以相对于屏幕坐标左上角的屏幕坐标给出。
hWnd
窗口句柄。
lpRect
指向一个RECT结构的指针,该结构接收窗口的左上角和右下角的屏幕坐标。
定义:首先添加:Imports System.Runtime.InteropServices(在vb2010中,写入下面代码后会有一个红色的感叹号,点击它并选择第一个。或者把它复制到代码最上端)
<StructLayout(LayoutKind.Sequential,CharSet:=CharSet.Auto)> _ Private Structure RECT Public Left As Integer 'X,即左上角的横坐标 Public Top As Integer 'Y,即左上角的纵坐标 Public Right As Integer 'Width,宽 Public Bottom As Integer 'Height,高 End Structure
返回值:如果函数成功,返回值为非零:如果函数失败,返回值为零。若想获得更多错误信息,请调用GetLastError函数。
'第四个是SetParent
Private Declare Function SetParent Lib "user32" (ByVal hWndChild As Long,ByVal hWndNewParent As Long) As Long
参数:
hWndChild:子窗口句柄。
hWndNewParent:新的父窗口句柄。如果该参数是NULL,则桌面窗口就成为新的父窗口。在WindowsNT5.0中,如果参数为HWND_MESSAGE,则子窗口成为消息窗口。
返回值:如果函数成功,返回值为子窗口的原父窗口句柄;如果函数失败,返回值为NULL。若想获得多错误信息,请调用GetLastError函数。
'第五个是MoveWindow
Public Declare Function MoveWindow Lib "user32" Alias "MoveWindow" (ByVal hwnd As Long,ByVal x As Long,ByVal y As Long,ByVal nWidth As Long,ByVal nHeight As Long,ByVal bRepaint As Long) As Long
函数功能:改变指定窗口的位置和大小.对顶窗口来说,位置和大小取决于屏幕的左上角;对子窗口来说,位置和大小取决于父窗口客户区的左上角.对于Owned窗口,位置和大小取决于屏幕左上角.
参数
hWnd指定了窗口的句柄
x指定了CWnd的左边的新位置。
y指定了CWnd的顶部的新位置。
nWidth指定了CWnd的新宽度。
nHeight指定了CWnd的新高度。
bRepaint指定了是否要重画CWnd。如果为TRUE,则CWnd象通常那样在OnPaint消息处理函数中接收到一条WM_PAINT消息。如果这个参数为FALSE,则不会发生任何类型的重画操作。这应用于客户区、非客户区(包括标题条和滚动条)和由于CWnd移动而露出的父窗口的任何部分。当这个参数为FALSE的时候,应用程序必须明确地使CWnd和父窗口中必须重画的部分无效或重画。
'第六个是ShowWindow
Public Declare Function ShowWindow Lib "user32" Alias "ShowWindow" (ByVal hwnd As Long,ByVal nCmdShow As Long) As Long
参数:(一些常量具体的值请查询API浏览器)
hWnd:指窗口句柄。 SW_HIDE:隐藏窗口并激活其他窗口。 SW_MAXIMIZE:最大化指定的窗口。 SW_MINIMIZE:最小化指定的窗口并且激活在Z序中的下一个顶层窗口。 SW_RESTORE:激活并显示窗口。如果窗口最小化或最大化,则系统将窗口恢复到原来的尺寸和位置。在恢复最小化窗口时,应用程序应该指定这个标志。 SW_SHOW:在窗口原来的位置以原来的尺寸激活和显示窗口。 SW_SHOWDEFAULT:依据在STARTUPINFO结构中指定的SW_FLAG标志设定显示状态,STARTUPINFO 结构是由启动应用程序的程序传递给CreateProcess函数的。 SW_SHOWMAXIMIZED:激活窗口并将其最大化。 SW_SHOWMINIMIZED:激活窗口并将其最小化。 SW_SHOWMINNOACTIVATE:窗口最小化,激活窗口仍然维持激活状态。 SW_SHOWNA:以窗口原来的状态显示窗口。激活窗口仍然维持激活状态。 SW_SHOWNOACTIVATE:以窗口最近一次的大小和状态显示窗口。激活窗口仍然维持激活状态。SW_SHOWNORMAL:激活并显示一个窗口。如果窗口被最小化或最大化,系统将其恢复到原来的尺寸和大小。应用程序在第一次显示窗口的时候应该指定此标志。
好了,一些API就介绍到这,现在就是编写代码了,请新建一个模块,然后复制入以下代码
Imports System.Runtime.InteropServices Module SetMinForm '寻找窗口列表中第一个符合指定条件的顶级窗口 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 '设置指定窗口的显示状态 Private Declare Function ShowWindow Lib "user32" (ByVal hwnd As IntPtr,_ ByVal nCmdShow As Integer) As Integer Const SW_SHOW = 5 Const SW_HIDE = 0 <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 '声明全集变量,并暂存相关数据 Dim hTaskbar,hBar,HLang As Long Dim rcBar As RECT Dim rcTaskbar As RECT Dim rcLang As RECT Public BarOldRight As Integer Public HBarOldWidth,HBarNewWidth As Integer Function SetMinFormStyle(ByVal Con As Form) As Boolean On Error GoTo cw hTaskbar = FindWindow("Shell_TrayWnd",vbNullString) '寻找类名是Shell_TrayWnd的窗口Handle hBar = FindWindowEx(hTaskbar,"ReBarWindow32",vbNullString) '寻找中间任务栏的Handle HLang = FindWindowEx(hTaskbar,"TrayNotifyWnd",vbNullString) '寻找右下角任务栏的Handle GetWindowRect(HLang,rcLang) '获得右下角任务栏的RECT GetWindowRect(hBar,rcBar) '获得中间任务栏的RECT GetWindowRect(hTaskbar,rcTaskbar) '获得任务栏的RECT HBarOldWidth = rcBar.Right - rcBar.Left BarOldRight = rcBar.Right HBarNewWidth = HBarOldWidth - Con.Width MoveWindow(hBar,rcBar.Left,HBarNewWidth,rcBar.Bottom,True) '调整中间任务栏的宽度,为程序腾出位置 SetParent(Con.Handle,hTaskbar) '把程序窗口设置成任务栏的子窗口 MoveWindow(Con.Handle,HBarOldWidth - Con.Width,Con.Width,Con.Height,True) '调整程序的位置 ShowWindow(Con.Handle,SW_SHOW) '显示窗体,可要可不要 Return True Exit Function cw: Return False End Function Function UnSetMinFormStyle() As Boolean On Error GoTo cw MoveWindow(hBar,rcBar.Right - rcBar.Left,True) '恢复中间任务栏的宽度 Return True Exit Function cw: Return False End Function Sub UpDataConBarRect(ByVal Con As Form) '调整程序与任务栏各窗口的位置 Dim HTaskBarA,HBarA,HLangA As Long Dim RCHBarA As RECT Dim RCHLangA As RECT HTaskBarA = FindWindow("Shell_TrayWnd",vbNullString) '寻找类名是Shell_TrayWnd的窗口Handle HBarA = FindWindowEx(HTaskBarA,vbNullString) '寻找中间任务栏的Handle HLangA = FindWindowEx(HTaskBarA,vbNullString) '寻找右下角任务栏的Handle GetWindowRect(HLangA,RCHLangA) '获得右下角任务栏的RECT GetWindowRect(HBarA,RCHBarA) '获得中间任务栏的RECT If RCHLangA.Left <> Con.Left + Con.Width Then MoveWindow(Con.Handle,RCHLangA.Left - Con.Width,True) HBarNewWidth = Con.Left - rcBar.Left If RCHBarA.Right - RCHBarA.Left <> HBarNewWidth Then MoveWindow(hBar,True) ShowWindow(Con.Handle,SW_SHOW) End Sub End Module
然后在你的程序中写入下面代码并设置Formborderstyle为none,然后运行程序,嘿嘿,程序是不是嵌入了呢?注意程序的Width和Height不要太大哦!
Public Class Form1 Private Sub Form1_Click(ByVal sender As Object,ByVal e As System.EventArgs) Handles Me.Click Me.Close() End Sub Private Sub Form1_FormClosing(ByVal sender As Object,ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing UnSetMinFormStyle() End Sub Private Sub Form1_Load(ByVal sender As System.Object,ByVal e As System.EventArgs) Handles MyBase.Load SetMinFormStyle(Me) End Sub Private Sub Timer1_Tick(ByVal sender As System.Object,ByVal e As System.EventArgs) Handles Timer1.Tick UpDataConBarRect(Me) End Sub End Class