一个简单的系统托盘图标的实现

很久没有弄这个了,差点了,见朋友的博客有个Delphi版的,于是自己也想弄一个VC的出来!
要实现系统托盘图标,关键在于一个系统函数和一个数据结构。
函数就是Shell_NotifyIcon,原型如下:
BOOL Shell_NotifyIcon(DWORD dwMessage,NOTIFYICONDATA  lpdata);

而数据结构就是NOTIFYICONDATA了,呵呵,具体如下:


typedef struct _NOTIFYICONDATA {
    DWORD cbSize;
    HWND hWnd;
    UINT uID;
    UINT uFlags;
    UINT uCallbackMessage;
    HICON hIcon;
    TCHAR szTip[64];
    DWORD dwState;
    DWORD dwStateMask;
    TCHAR szInfo[256];
    union {
        UINT uTimeout;
        UINT uVersion;
    };
    TCHAR szInfoTitle[64];
    DWORD dwInfoFlags;
    GUID guidItem;
    HICON hBalloonIcon;
} NOTIFYICONDATA, *PNOTIFYICONDATA;

具体的解释,大家还是查查MSDN吧,这里不多说了!主要用到的几个是:
1、由于Shell_NotifyIcon是定义在shellapi.h里的,所以程序里需要包含上。
2、Shell_NotifyIcon的第一个参数取值:
  A)、NIM_ADD    //这个就是添加一个系统托盘图标了
  B)、NIM_DELETE    //这个是在退出时删除系统托盘图标了

3、对Shell_NotifyIcon的第2个参数,也即NOTIFYICONDATA结构的设置了:
  A)、先定义一个全局的变量:NOTIFYICONDATA nid
  B)、然后在适当的位置对其进行初始化:

对于对话框程序,一般在WM_INITDIALOG里消息初始,不过我这里是用CreateDialog来创建对话框的,所以在主程序WinMain里初始化:


  nid.cbSize=sizeof(NOTIFYICONDATA);  //初始化结构的大小
  nid.hWnd=g_hWnd;      //指定接收托盘消息的句柄
  nid.uID=IDI_TRAY;      //指定托盘图标的ID,呵呵
  nid.uFlags=NIF_ICON | NIF_MESSAGE | NIF_TIP;      //设定结构里有效的位置
      //NIF_ICON:  指定hIcon是有效的,(这里设定自定义系统托盘图标必须的)
      //NIF_MESSAGE:  指定uCallbackMessage是有效的,用于程序接收来自托盘图标的消息,需要自定义一个消息
      //NIF_TIP:  指定szTip是有效的,功能是当鼠标移动到图标上时,显示提示信息
  nid.uCallbackMessage=WM_IAWENTRAY;        //自定义的消息,
      //#define WM_IAWENTRAY  WM_USER+5
  nid.hIcon=LoadIcon(g_hInst,MAKEINTRESOURCE(IDI_TRAY));    //设置图标的句柄
  strcpy(nid.szTip,"测试系统托盘图标,呵呵\r\n点击打开主界面");  //设置提示信息

完成了上面的设置,现在就是开始调用了!
这里示例,是设定系统最小化按钮为隐藏到系统托盘,退出时则删除系统托盘!
如:


    case WM_DESTROY:
      Shell_NotifyIcon(NIM_DELETE,&nid);
      return TRUE;
    case WM_SYSCOMMAND:
      switch(wParam)
      {
        case SC_CLOSE:
          DestroyWindow(hDlg);
          PostQuitMessage(0);
          return TRUE;
        case SC_MINIMIZE:
          ShowWindow(g_hWnd,SW_HIDE);
          Shell_NotifyIcon(NIM_ADD,&nid);
          return TRUE;
      }

这里只所以没有在SC_CLOSE消息里直接删除托盘图标,而是因为在WM_DESTROY里处理会更好!
如果是在SC_CLOSE里直接处理,则会出现程序退出时,图标还在,只有当鼠标移过图标时则会完全不见!
大家可以测试一下,^&^……

而程序要接收来自系统托盘的消息,则是通过我们上面的定义的消息:


    case WM_IAWENTRAY:
      if(wParam==IDI_TRAY){
        if(lParam==WM_LBUTTONDOWN){
          ShowWindow(hDlg,SW_SHOWNORMAL);
          return TRUE;
        }  
      }
      return FALSE;

其中消息的wParam参数为指定的图标ID,lParam参数为事件类型,示例里只接收了WM_LBUTTONDOWN事件,即鼠标左键点击事件!

完整的的代码示例如下:


#include
#include
#include"resource.h"

#define WM_IAWENTRAY  WM_USER+5

HINSTANCE g_hInst;
HWND g_hWnd;
NOTIFYICONDATA nid;
INT_PTR CALLBACK MainDlgProc(HWND,UINT,WPARAM,LPARAM);

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE,LPSTR lpCmdLine,int nShowCmd)
{
  g_hInst=hInstance;
  g_hWnd=CreateDialog(hInstance,MAKEINTRESOURCE(IDD_DIALOG1),NULL,MainDlgProc);
  ShowWindow(g_hWnd,nShowCmd);
  
  nid.cbSize=sizeof(NOTIFYICONDATA);
  nid.hWnd=g_hWnd;
  nid.uID=IDI_TRAY;
  nid.uFlags=NIF_ICON | NIF_MESSAGE | NIF_TIP;    
  nid.uCallbackMessage=WM_IAWENTRAY;  
  nid.hIcon=LoadIcon(g_hInst,MAKEINTRESOURCE(IDI_TRAY));
  strcpy(nid.szTip,"测试系统托盘图标,呵呵\r\n点击打开主界面");  //

  MSG uMsg;
  while(GetMessage(&uMsg,NULL,0,0)){
    TranslateMessage(&uMsg);
    DispatchMessage(&uMsg);
  }

  return 0;
}

INT_PTR CALLBACK MainDlgProc(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
  switch(uMsg){
    case WM_INITDIALOG:
      {
      HICON hIcon=LoadIcon(g_hInst,MAKEINTRESOURCE(IDI_TRAY));
      SendMessage(hDlg,WM_SETICON,ICON_BIG,(LPARAM)hIcon);
      SendMessage(hDlg,WM_SETICON,ICON_SMALL,(LPARAM)hIcon);
      SetDlgItemText(hDlg,IDC_INFO,TEXT("Write By Iawen --2009.02.03"));
      return TRUE;
      }
    case WM_IAWENTRAY:
      if(wParam==IDI_TRAY){
        if(lParam==WM_LBUTTONDOWN){
          ShowWindow(hDlg,SW_SHOWNORMAL);
          return TRUE;
        }  
      }
      return FALSE;
    case WM_DESTROY:
      Shell_NotifyIcon(NIM_DELETE,&nid);
      return TRUE;
    case WM_SYSCOMMAND:
      switch(wParam)
      {
        case SC_CLOSE:
          DestroyWindow(hDlg);
          PostQuitMessage(0);
          return TRUE;
        case SC_MINIMIZE:
          ShowWindow(g_hWnd,SW_HIDE);
          Shell_NotifyIcon(NIM_ADD,&nid);
          return TRUE;
      }
  }
  return FALSE;
}

附件为完整的程序示例工程:
TrayIcon.rar

发表评论