把最小化图标放到任务栏右下角

目 前 有 不 少Win95 应 用 程 序 在 最 小 化 后, 代 表 该 程 序 的 小 图 标 就 会 隐 藏 在 屏 幕 的 右 下角( 即 任 务 栏 的 右 边), 如“ 金 山 词 霸”、“ 东 方 快 车” 等, 而 我 们 用Visual Basic 编 制 的程 序 在 最 小 化 后, 图 标 却 总 是 出 现 在 任 务 栏 的 中 央, 并 且 占 据 较 大 的 空 间。 如 何 让 我们 自 己 的 程 序 也 能 将 最 小 化 图 标 放 在 任 务 栏 的 右 边 呢 ? 我 们 可 以 通 过Windows API 函 数 调 用 来 实 现 该 功 能。 一、 如 何 添 加 和 隐 藏 图 标 ---- 在Windows 的 动 态 连 接 库Shell32.dll 中 有 一 个 名 为Shell_NotifyIconA 的Windows API 函 数, 其 功 能 是 对 任 务 栏 的 右 下 角 图 标 进 行 操 作, 包 括 添 加、 删 除 和 修改。Shell_NotifyIconA 函 数 的VB 声 明 格 式 如 下: ---- Declare Function Shell_NotifyIconA Lib "SHELL32" (ByVal dwMessage As Long, lpData As NOTIFYICONDATA) As IntegerShell_NotifyIconA 有 两 个 参 数DwMessage 和lpData。DwMessage 为 操 作 图 标 的 方 式, 可 能 的 取 值 和 含 义 如 下: ---- 0( 向 任 务 栏 添 加 图 标) ---- 1( 修 改 任 务 栏 中 的 图 标) ---- 2( 删 除 任 务 栏 中 的 图 标) ---- lpData 是 自 定 义 数 据 类 型NOTIFYICONDATA 的 数 据, 该 自 定 义 数 据 结 构 由 以 下 成 员 构 成: ---- 1. cbSize: 需 填 写NOTIFYICONDATA 数 据 结 构 的 长 度, 在 使 用 时 可 通 过VB 的 标 准 函数Len 来 计 算, 如nid 为NOTIFYICONDATA 类 型 的 变 量, 则cbSize 为Len(nid)。 ---- 2. hWnd: 最 小 化 窗 体 的 句 柄。 ---- 3. uID: 使 用 者 为 图 标 所 设 定 的 ID, 可 自 定。 ---- 4. uFlags: 用 来 设 定 后 面 三 个 成 员(uCallbackMessage、hIcon、szTip) 是 否 有 效, 等于 1 时 为uCallbackMessage 有 效, 将 来 使 用 者 在 图 标 上 按 下 鼠 标 键 时, Windows 会 发出 消 息 给 窗 体 程 序; 等 于 2 时 为hIcon 有 效, 表 示 要 显 示 图 标( 如 果 不 显 示 图 标, 用 户只 是 无 法 看 见 图 标, 但 仍 然 可 在 任 务 栏 的 图 标 应 该 出 现 的 位 置 上 操 作); 等 于 4 时为szTip 有 效, 当 用 户 将 鼠 标 指 针 放 在 图 标 上 时, 要 显 示 提 示 信 息, 否 则 不 显 示。 通 常将uFlags 设 定 成 7( 即 1 + 2 + 4), 表 示 全 部 有 效。 ---- 5. uCallbackMessage: 当 用 户 在 图 标 上 按 下 鼠 标 按 键 时,Windows 发 给 应 用 程 序 的 消 息 编 号。 ---- 6. hIcon: 图 标 句 柄。 ---- 7. szTip: 当 用 户 将 鼠 标 指 针 放 在 图 标 上 时 显 示 的 提 示 信 息。 ---- 在 调 用Shell_NotifyIconA 函 数 之 前, 必 须 将NOTIFYICONDATA 类 型 变 量 的 以 上 各 成 员 填 写 正 确 的 内 容。 ---- 该 函 数 如 果 调 用 成 功 则 返 回1, 否 则 返 回0。 ---- 了 解 了Shell_NotifyIconA 函 数 的 功 能 和 用 法 后, 我 们 可 以 很 容 易 地 将 图 标 添 加 在 任 务 栏 的 右 边, 或 者 从 任 务 栏 上 将 图 标 删 除。 ---- 如: 假 设 我 们 事 先 声 明 了 一 个NOTIFYICONDATA 型 的 变 量nid, 且 已 经 给 它 的 所 有 成 员赋 予 了 合 适 的 值, 那 么, 下 面 的 两 条 语 句 分 别 可 完 成 添 加 和 删 除 图 标 的 任 务: Shell_NotifyIconA( 0, nid)    ' 添加图标 Shell_NotifyIconA( 2, nid) ' 删除图标 二、 如 何 响 应 鼠 标 按 键 ---- 按 照 上 面 的 方 法, 我 们 可 以 将 最 小 化 后 的 图 标 放 在 任 务 栏 的 右 边, 那 么 当 我 们 在 该 图标 上 按 下 鼠 标 按 键 时 会 发 生 什 么 事 情 呢 ? 很 遗 憾, 什 么 也 没 有 发 生, 最 小 化 的 窗 体 不会 象 我 们 希 望 的 那 样 恢 复 正 常 显 示 状 态。 ---- 这 时 怎 么 回 事 呢 ? 很 简 单,前 面 我 们 只 是 将 图 标 添 加 到 了 任 务 栏 上, 而 并 没 有 对 鼠 标 事 件 做 任 何 的 工 作, 为 了 对鼠 标 按 键 作 出 响 应, 我 们 还 有 一 些 事 情 要 做。 ---- 前 面 已 经 说 过,如 果 将 将NOTIFYICONDATA 类 型 变 量 的 成 员uFlags 设 定 为1, 则 当 用 户 在 图 标 上 按 下 鼠标 按 键 时,Windows 会 将 编 号 为uCallbackMessage 的 消 息 发 送 到 应 用 程 序, 因 此, 为 了能 响 应 鼠 标 事 件, 我 们 必 须 在 程 序 中 对 该 消 息 进 行 处 理。 ---- 需 要注 意 的 是, 由 于Windows 自 身 的 消 息 处 理 机 制 的 限 制, 我 们 无 法 直 接 干 预Windows 的 自身 消 息 处 理 过 程, 所 以 只 有 采 用 一 种 类 似 于 从 前DOS 环 境 下 截 获 中 断 的“ 曲 线 救 国“ 的方 法 来 处 理 消 息, 过 程 是: ---- 在 窗 体 最 小 化 后, 立 即 读 取 该 窗 体 原 消 息 处 理 过 程 的 地 址 并 记 录 在 一 个 全 局 变 量 中, 方 法 是 调 用Windows API 函 数GetWindowLong, 其 声 明 如 下: ---- Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long 其 中hWnd 为 窗 体 句柄,nIndex 为 过 程 类 型, 这 里 为-4(Windows 默 认 过 程)。 ---- (2) 编 写 自 己 的 消 息 处 理 过 程, 注 意 参 数 的 数 量 和 类 型 必 须 按 照 下 面 的 格 式( 过 程 名 可 随 意): ---- Sub WndProcForIcon(ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) ---- (3) 将 自 己 的 消 息 处 理 过 程 设 置 为 默 认 的 消 息 处 理 程 序, 方 法 是 调 用Windows API 函 数SetWindowLong, 其 声 明 如 下: ---- Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long ---- 其 中hWnd 与nIndex 含 义 同 上,dwNewLong 为 自 定 义 过 程的 地 址, 可 使 用VB 的 求 地 址 运 算 符AddressOf 得 到, 如AddressOf WndProcForIcon 可得 到 自 定 义 过 程WndProcForIcon 的 地 址。 ---- (4) 当 鼠 标 事 件 发生 后, 自 己 的 消 息 处 理 过 程( 现 在 已 成 为 默 认 的 消 息 处 理 过 程) 首 先 进 行 处 理, 一 般 是根 据 按 键 将 窗 体 恢 复 或 弹 出 一 个PopUp 菜 单 供 用 户 选 择。 ---- (5) 让Windows 去 执 行 原 消 息 处 理 过 程( 该 过 程 的 地 址 由 全 局 变 量 保 存), 方 法 是 调 用Windows API 函 数CallWindowProc, 其 声 明 如 下: ---- Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long ---- 其 中lpPrevWndFunc 为 原 消 息 处 理 程 序 的 地 址, 其 它 参 数 与 自 定 义 消 息 处 理 过 程 中 的 参 数 相 对 应。 ---- 细 心 的 读 者 一 定 会 发 现, 如 果 在 上 述 第3 步 完 成 后, 没 有 进 行 第5 步, 即: 使用setWindowLong 改 变 了 原 先 消 息 处 理 程 序 的 地 址, 却 没 有 在 程 序 结 束 前 将 地 址 设 定回 来, 那 程 序 将 不 会 正 常 结 束, 往 往 会 造 成 死 机, 因 此, 程 序 中 一 定 要 小 心 处 理 这 个 问题。 ---- 另 外, 为 了 正 确 的 处 理 消 息, 还 有 一 个 问 题 需 要 解 决, 就 是如 何 识 别 消 息 是 否 是 由 图 标 发 出 的 ? 这 一 点 可 以 这 样 解 决: 利 用 一 个 全 局 变 量 记 录下NOTIFYICONDATA 型 变 量 的 成 员uCallbackMessage( 消 息 号) 的 值, 然 后 在 消 息 处 理程 序 中 检 查Windows 传 回 的 消 息 号(MsgNo) 是 否 与 其 一 致, 如 果 一 致, 则 说 明 消 息 的 确是 由 图 标 发 出 的, 应 该 进 行 处 理, 否 则 即 可 忽 略。 如 本 文 后 面 的 程 序 实 例 就 用 全 局 变量IconMsg 来 实 现 这 一 功 能( 具 体 请 参 照 程 序 代 码)。 三、 程 序 实 例 ---- 下 面, 我 们 通 过 一 个 简 单 的 实 例 来 实 现 上 述 方 法: ---- 1、 窗 体 布 局 ---- 新 建 一 个 工 程IconTest, 新 建 一 个 标 准 窗 体frmIconTest, 在 窗 体 上 放 置 三 个 命 令 按钮, 名 称(Name) 分 别 为cmdCreateIcon、cmdNormalMin 和cmdExit, 标 题(Caption) 分 别为“ 最 小 化 到 右 下 角”、“ 普 通 最 小 化” 和“ 退 出”。 ---- 2、 代 码 ---- 添 加 一 个 模 块modIconTest, 在 其 中 编 写 如 下 的 代 码: Option Explicit '定义常量 Public Const GWL_WNDPROC = (-4) Public Const WM_LBUTTONDOWN = &H201 Public Const NIM_ADD = 0 Public Const NIM_DELETE = 2 Public Const NIF_MESSAGE = 1 Public Const NIF_ICON = 2 Public Const NIF_TIP = 4 '定义全局变量 Public IconMsg As Long '消息编号 Public OldWinProc As Long '原消息处理程序的地址 '定义自定义数据类型 Public Type NOTIFYICONDATA cbSize As Long hWnd As Long uID As Long uFlags As Long uCallbackMessage As Long hIcon As Long szTip As String * 64 End Type 'Windows API函数声明 Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long Declare Function Shell_NotifyIconA Lib "SHELL32" (ByVal dwMessage As Long, lpData As NOTIFYICONDATA) As Integer '自定义消息处理程序 Sub MyProc(ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) '根据Msg判断,消息是否是图标发出的, 如果是,再进行处理 If Msg = IconMsg Then If lParam = WM_LBUTTONDOWN Then frmIconTest.Show '如果在图标上按 下了左键则显示窗体 End If End If '执行全程变量OldWinProc记录的原 消息处理程序的地址中的消息处理程序 CallWindowProc OldWinProc, hWnd, Msg, wParam, lParam End Sub 在frmIconTest的窗体模块中编写如下代码: Option Explicit Dim HadAdd As Boolean Dim nid As NOTIFYICONDATA Private Sub cmdEnd_Click() If HadAdd Then '如果曾向右下角添加过小图标 '则根据事先记录的OldWinProc 恢复原来的消息处理程序,并删除图标 SetWindowLong frmIconTest.hWnd, GWL_WNDPROC, OldWinProc Call Shell_NotifyIconA(NIM_DELETE, nid) '删除图标 End If Unload Me '卸载窗体 End Sub Private Sub cmdCreateIcon_Click() If Not HadAdd Then '如果没有产生过图标,则添加图标到右下角 With nid '以下填写nid变量的所有成员 .cbSize = Len(nid) '填写自定义数据类型的长度 .hWnd = frmIconTest.hWnd '填写窗体的句柄 .uID = 9999 '图标的Id,可随意 '允许显示图标、提示并产生消息 .uFlags = NIF_ICON + NIF_TIP + NIF_MESSAGE .hIcon = frmIconTest.Icon.Handle '图标句柄 .szTip = "单击鼠标左键恢复窗体!" '提示信息 .uCallbackMessage = 2 '图标的消息号 End With Shell_NotifyIconA NIM_ADD, nid '添加图标 IconMsg = nid.uCallbackMessage '用全局变量记录消息号, '读取frmIconTest正常的消息处理程序 的地址保存在全程变量OldWinProc中 OldWinProc = GetWindowLong(frmIconTest.hWnd, GWL_WNDPROC) '用自定义过程MyProc的地址 代替正常消息处理程序的地址 SetWindowLong frmIconTest.hWnd, GWL_WNDPROC, AddressOf MyProc frmIconTest.Hide '隐藏窗体 HadAdd = True '置“已经添加图标”标志 Else frmIconTest.Hide '如果已经有小图标了, 则直接隐藏窗体 End If End Sub Private Sub cmdNormalMin_Click() frmIconTest.WindowState = 1 '普通最小化窗体 End Sub Private Sub Form_Load() HadAdd = False '将“是否添加了图标的标志”置为False '下面为窗体装载图标,读者应当根据自己的VB目录而定 frmIconTest.Icon= oadPicture("c:/MyIcon/files10.ico") End Sub ---- 按 下F5, 执 行 本 程 序, 单 击“ 最 小 化 到 右 下 角” 按 钮, 窗 体 将 消 失, 同 时 任 务 栏 的 右 边 出现 代 表 窗 体 的 图 标( 如 图2), 在 该 图 标 上 单 击 鼠 标 左 键, 窗 体 恢 复 正 常。 再 单 击“ 普 通最 小 化 图 标” 按 钮, 你 会 看 到 窗 体 虽 然 也 消 失 了, 但 最 小 化 图 标 在 任 务 栏 的 中 间, 即 普通 位 置( 如 图3)。 ---- 本 程 序 用VB5 编 制, 在Pwin95 下 调 试 正 常。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值