来源(null)

在VC5下灵活控制WIN98/95的托盘图标
 

 


实用技巧

在VC5 下 灵 活 控 制WIN98/95 的 托 盘 图 标

辽 宁 省 铁 岭 市 委 办 公 室
宋 立 波

---- WIN98/95 的 托 盘 图 标 是 指 任 务 栏 右 侧 的 显 示 器、 声 音 和 输 入 法 等 图 标。 通 过 托 盘 图 标 可 有 效 控 制 常 用 功 能, 使 用 户 实 时 观 察 应 用 程 序 的 工 作 状 态, 例 如 系 统 中 的 设 备 状 态、 系 统 时 钟、 计 划 任 务 以 及 中 文 输 入 法 程 序 等。 在 其 它 应 用 程 序 开 发 中 也 比 较 常 见, 如 调 制 解 调 器 通 讯 状 态、 后 台 打 印 任 务 的 执 行 状 态、 解 霸 五 中 的 VCD 自 动 侦 测 状 态、 屏 幕 抓 图 程 序 的 控 制 状 态 以 及 其 它 后 台 任 务 事 件 等, 托 盘 图 标 不 仅 可 以 使 应 用 程 序 具 有 很 高 的 专 业 水 准, 同 时 极 大 地 方 便 了 用 户 操 作, 避 免 了 通 过 任 务 栏 中 窗 口 最 小 化 标 题 切 换 任 务 的 繁 锁 操 作, 而 且 在 节 省 使 用 任 务 条 中 有 效 客 户 区 域 和 实 时 获 取 任 务 执 行 状 态 方 面, 是 任 务 栏 中 最 小 化 的 窗 口 标 题 条 所 无 法 取 代 的, 同 时 通 过 各 种 功 能 操 作 菜 单, 也 能 实 现 重 新 激 活 应 用 程 序 等 功 能。 所 以 这 里 有 必 要 介 绍 在VC5 下 灵 活 控 制 托 盘 图 标 的 方 法 与 技 巧。

---- 控 制 托 盘 图 标 需 要 深 入 了 解Shell_NotifyIcon() 和NOTIFYICONDATA 数 据 结 构。 两 者 在VC5 中 的 定 义 和 用 法 如 下:

---- 1、Shell_NotifyIcon 函 数 的 用 法

   WINSHELLAPI BOOL Shell_NotifyIcon(
   DWORD dwMessage,
   //处理的消息类型
   pNOTIFYICONDATA pnid)
   //指向NOTIFYICONDATA数据结构的指针

---- 参 数dwMessage 为 函 数 的 控 制 功 能 消 息, 可 以 是 以 下 标 识 符 之 一:

  NIM_ADD  在任务栏中增加一个托盘图标
  NIM_MODIFY 修改任务栏中的一个托盘图标
  NIM_DELETE 删除任务栏中的一个托盘图标

---- 参 数lpData 为 指 向 由NOTIFYICONDATA 定 义 的 数 据 结 构 的 地 址 指 针。

---- 2、 NOTIFYICONDATA 数 据 结 构 的 定 义

struct NOTIFYICONDATA{
    DWORD cbsize; //该数据结构的大小
    HWND hWnd;  //处理任务栏中托盘图标的窗口句柄
    UINT uID;  //自定义的任务栏中托盘图标的标识信息,
           //不同于资源中的标识,
           //注意不能与任务栏中其它托盘图标的ID相同
    UINT uFlags; //任务栏托盘图标功能控制位,
           //可以是以下值的组合(一般全包括):
       //NIF_MESSAGE表示发送控制消息
       //NIF_ICON  表示显示控制栏中的托盘图标
       //NIF_TIP  表示任务栏中的托盘图标有动态提示
    UINT uCallbackMessage;//自定义消息,任务栏托盘图标通
       //过它与用户程序交换信息,
       //处理这个消息的窗口由hWnd来决定
    HICON hIcon; //任务栏中托盘图标的控制句柄
    char szTip[64];//托盘图标的提示信息
}

---- 当 函 数Shell_NotifyIcon 出 现 错 误 时, 其 错 误 参 数 的 含 义 与uFlags 的 内 容 相 同。 在 控 制 任 务 栏 上 的 托 盘 图 标 时 应 注 意 以 下 几 点:

---- 其 一 是 当 自 定 义 任 务 栏 图 标 的 标 识 符 值 不 一 致 时, 不 能 正 确 对 任 务 栏 中 对 应 托 盘 图 标 进 行 修 改 和 删 除 等 操 作, 所 以 各 种 功 能 函 数 中 的uID 值 必 须 一 致 并 不 与 系 统 冲 突;

---- 第 二 是 当 响 应 任 务 栏 中 托 盘 图 标 的 窗 口 无 效 时, 鼠 标 指 针 移 动 了 任 务 栏 中 的 托 盘 图 标 上 时, 托 盘 图 标 立 刻 自 动 消 失, 窗 口 指 针 正 确 获 取 方 法:

  CWnd* m_pCWnd=AfxGetMainWnd();// 取 得 窗 口 指 针
iData.hWnd=*m_pCWnd;     // 窗 口 句 柄

---- 第 三 是 当 应 用 程 序 被 关 闭 后, 系 统 并 不 马 上 删 除 任 务 栏 中 的 托 盘 图 标 , 即 托 盘 图 标 不 存 在 相 应 的 响 应 窗 口, 只 有 鼠 标 指 针 移 到 托 盘 图 标 上 时 才 删 除 对 应 空 闲 图 标, 所 以 程 序 最 好 能 对 关 闭 功 能 进 行 完 善 处 理;

---- 第 四 是 应 合 理 选 择 托 盘 图 标 自 定 义 消 息, 应 为WM_APP 或USER 以 后 的 数 值;

---- 第 五 是 要 使 应 用 程 序 响 应 托 盘 图 标 发 送 的 自 定 义 消 息, 必 须 增 加 窗 口 消 息 处 理 框 架 功 能 函 数DefWindowProc, 可 利 用 类 向 导 直 接 增 加, 并 完 善 其 功 能 实 现 对 自 定 义 消 息 及 鼠 标 操 作 类 型 的 判 断 处 理。

---- 第 六 是 当 设 置 托 盘 图 标 再 删 除 它 后, 设 置 和 修 改 托 盘 图 标 功 能 无 效, 除 非 重 新 运 行 一 次 应 用 程 序, 所 以 实 际 应 用 时 对 这 项 功 能 也 应 进 行 完 善。

---- 接 下 来 就 是 可 视 化 程 序 设 计, 其 步 骤 如 下:

---- 第 一 步 利 用“FILE- >NEW- >PROJECTS- >MFC AppWizard(EXE)" 建 立 名 为TICON 工 程, 在 建 立 过 程 中 选 择 基 于 对 话 框(Dialog based) 的 应 用 程 序 类 型;

---- 第 二 步 将 对 话 框 中 的 默 认 控 件 删 除, 并 将 所 有 对 话 框 属 性 中 的Lang uage 域 设 置 为Chinese(P.R.C.), 以 使 应 用 程 序 支 持 中 文;

---- 第 三 步 建 立 两 个 图 标IDI_ICON1 和IDI_ICON2, 用 来 表 示 图 标 的 设 置 和 修 改 两 种 状 态, 对 于 每 个 图 标 都 应 建 立32X32 和16X16 两 种, 保 证 程 序 需 要;

---- 第 四 步 在 对 话 框 窗 口 中 设 计 四 个 按 钮(Button)“ 设 置 图 标”、“ 修 改 图 标”、“ 删 除 图 标” 和“ 关 闭”, 其 对 应 标 识 分 别 如 下:

  按 钮 名 称        标 识 符 号
  设 置 图 标        IDC_ADD
  修 改 图 标        IDC_MODI
  删 除 图 标        IDC_DEL
关 闭           IDOK

---- 第 五 步 利 用 类 向 导ClassWizard 向 应 用 程 序 中 增 加 前 三 个 按 钮 对 应 的 功 能 函 数:ONADD()、ONMODI() 和ONDEL();

---- 第 六 步 在 应 用 程 序 中 增 加 如 下 代 码:

---- 首 先 在TIconDlg.h 中 增 加 如 下 定 义

//在开始处增加通用功能函数定义
  BOOL SendIconMessage(DWORD dwMessage,
   UINT uID,HICON hIcon,PSTR pszTip);
  //……
  Protected:
   HICON m_hIcon1;//定义图标控制句柄
   HICON m_hIcon2;
  其次在TIconDlg.h和Ticon.h中增加如下代码
  //在TIcon.h开始处增加如下定义
  int iIndex=0;
  //在TIconDlg.h开始处增加如下定义
  #define MYWM_NOTIFYICON  (WM_APP+100)
  UINT Flag;
  ……//其它代码

  //完善类初始化函数
  BOOL CTIconDlg::OnInitDialog()
  {
    CDialog::OnInitDialog();
    ……//其它代码
    // TODO: Add extra initialization here
    iIndex=0;//清除代码标志
m_hIcon1 = AfxGetApp()- >
LoadIcon(IDI_ICON1);//调入图标
m_hIcon2 = AfxGetApp()- >
LoadIcon(IDI_ICON2);//调入图标
    return TRUE;
  }
  ……//其它代码

  //完善各功能函数
  void CTIconDlg::OnAdd()//设置任务栏图标功能函数
  {
    UINT Flag;
    Flag=NIM_ADD;
    if (iIndex==1) return;
    if (iIndex==2) Flag=NIM_MODIFY;
    SendIconMessage(Flag,120,m_hIcon1,"设置图标\0");
    //三者uID必须统一,指任务栏上的图标标识信息
    iIndex=1;
  }

  void CTIconDlg::OnDel() //删除任务栏图标功能函数
  {
    if (iIndex==0) return;
    SendIconMessage(NIM_DELETE,120,NULL,NULL);
    iIndex==0;
    CWnd* m_pCWnd=AfxGetMainWnd();//取得窗口指针
    DestroyWindow(*m_pCWnd);
  }

  void CTIconDlg::OnModi() //修改任务栏图标功能函数
  {
    Flag=NIM_MODIFY;
    if (iIndex==2) return;
    if (iIndex==0) Flag=NIM_ADD;
    SendIconMessage(Flag,120,m_hIcon2,"修改图标\0");
    iIndex=2;
  }

  BOOL SendIconMessage(DWORD dwMessage,UINT uID,
  HICON hIcon,PSTR pszTip)
  { //任务栏图标消息处理通用功能函数
    BOOL uRet;
    CWnd* m_pCWnd=AfxGetMainWnd();//取得窗口指针
    NOTIFYICONDATA iData;   //定义数据结构
    iData.cbSize=sizeof(NOTIFYICONDATA);//结构大小
    iData.hWnd=*m_pCWnd;    //窗口句柄
    iData.uID=uID;       //图标标识
iData.uFlags=NIF_MESSAGE|NIF_ICON|NIF_TIP;
//设置处理的消息类型
    iData.hIcon=hIcon;     //图标句柄
iData.uCallbackMessage=
MYWM_NOTIFYICON;//自定义消息名
if(lstrlen(pszTip) >0 && lstrlen(pszTip)<64) {//处理提示信息 lstrcpy(iData.szTip,pszTip);//处理动态提示信息 iData.szTip[63]="\0" ; } else { iData.szTip[0]="\0" ; } uRet="Shell_NotifyIcon(dwMessage,&iData);//发送消息" if (dwMessage="=NIM_DELETE){" DestroyWindow(*m_pCWnd);//关闭窗口 }else { ShowWindow(*m_pCWnd,SW_HIDE);//关闭窗口 } ShowWindow(*m_pCWnd,SW_HIDE);//关闭窗口 return uRet; } 

---- 第 七 步 为 了 使 任 务 栏 上 的 图 标 能 够 处 理 鼠 标 消 息, 应 利 用 类 向 导ClassWizard 增 加DefWindowProc 功 能, 以 实 现 对 自 定 义 消 息 的 处 理, 用 户 可 以 根 据 自 己 的 实 际 需 要 确 定 要 处 理 的 鼠 标 消 息 类 型 和 响 应 消 息 功 能 函 数, 本 文 只 实 现 了 重 新 激 活 对 话 框 窗 口 的 功 能。 代 码 如 下:

LRESULT CTIconDlg::DefWindowProc(UINT message, 
WPARAM wParam, LPARAM lParam)
  {//响应自定义类型消息功能函数
    if (message==MYWM_NOTIFYICON && lParam
    ==WM_LBUTTONDOWN){ //判断消息
     //AfxMessageBox("SSSSSSSSSSSSSSSS",IDOK,0);
     CWnd* m_pCWnd=AfxGetMainWnd();//取得窗口指针
     ShowWindow(SW_SHOW);     //显示窗口
     SetForegroundWindow();    //强制为活动窗口
    }
return CDialog::DefWindowProc
(message, wParam, lParam);
}

---- 第 八 步 当 对 话 框 应 用 程 序 关 闭 后, 程 序 并 不 对 任 务 栏 中 的 图 标 进 行 自 动 删 除 , 除 非 鼠 标 指 针 移 到 任 务 栏 的 图 标 上 时 系 统 才 自 动 删 除 已 经 关 闭 窗 口 所 对 应 的 图 标 , 这 时 应 在TICON.CPP 程 序 中 对 应 用 程 序 窗 口 关 闭 功 能 进 行 完 善。

BOOL CTIconApp::InitInstance()
  {
    AfxEnableControlContainer();
    ……//其它代码
    if (nResponse == IDOK){
     if(iIndex >0){删除任务栏图标
     SendIconMessage(NIM_DELETE,120,NULL,NULL);
     iIndex=0;
     }
    }
    else if (nResponse == IDCANCEL){
     if(iIndex >0){//删除任务栏图标
     SendIconMessage(NIM_DELETE,120,NULL,NULL);
     iIndex=0;
     }
  }

 

Link: http://www.asm32.net/article_details.aspx?id=81