第一步,在CMainFrame中定义NOTIFYICONDATA结构m_notify。
第二步,在OnCreate中添加下面的代码。代码的解释参见注释。
1 | m_notify.cbSize = sizeof(NOTIFYICONDATA);//结构体大小 |
需要注意的是,m_notify.uFlags必须设置正确,如果不正确,那么有些功能是不会有效的,还有m_notify.cbSize也是必须设置的。
第三步,在MainFrame.h中添加宏定义#define WM_USER_NOTIFYICON (WM_USER + 100),再定义对应的消息处理函数,afx_msg LRESULT OnNotifyMsg(WPARAM wparam, LPARAM lparam);注意该函数的格式。这是普通的消息处理函数,消息的参数必须带全。再在源文件中的BEGIN_MESSAGE_MAP和END_MESSAGE_MAP()之间添加消息映射ON_MESSAGE(WM_USER_NOTIFYICON, OnNotifyMsg)。
第四步,实现OnNotifyMsg。我的OnNotifyMsg实现如下:
1 | // CMainFrame 消息处理程序 |
值得注意的是menu.AppendMenu(MF_STRING, WM_USER_EXIT, “关闭”);,我用了自定义的消息WM_USER_EXIT而不是WM_DESTROY。刚开始我参照别人的代码,使用WM_DESTROY,结果弹出菜单一直是灰色的。我换成WM_CLOSE也是一样的效果。没办法,我就试了下自定义消息。刚开始我采样的是普通类型的消息映射处理该菜单消息,菜单也是灰色的。直到最后我用ON_COMMAND映射菜单消息,菜单才能够点击。
第四步,在MainFrame.h中添加宏定义#define WM_USER_EXIT (WM_USER + 101),再定义对应的消息处理函数,aafx_msg void OnExit();注意该函数的格式,与第三步不同,因为这是命令消息。再在源文件中的BEGIN_MESSAGE_MAP和END_MESSAGE_MAP()之间添加消息映射ON_COMMAND(WM_USER_EXIT, OnExit)。第四步是使弹出菜单能够点击的关键。我在OnExit直接调用DestroyWindow退出程序。
第五步,重载WM_CLOSE,在其中调用ShowWindow(SW_HIDE);。这样点击关闭按钮则进入托盘状态,而点击最小化按钮在任务栏上有程序的图标。
第六步,重载WM_DESTROY,程序退出时候删除托盘。对应代码如下:
1 | void CMainFrame::OnDestroy() |
至此,实现了一个SDI框架下,完整的托盘程序。
我写这篇文章的目的是为了说明ON_MESSAGE和ON_COMMAND的区别。ON_COMMAND对应的普通的windows消息,ON_COMMAND则对应的是菜单和按钮之类的命令消息,需要区别对待。也就是处理不同类型的消息,需要使用不同类型的消息处理函数。如果消息处理函数类型不正确,有可能出现问题。比如,弹出菜单一直是灰色。