关于系统响应函数OnSysCommand及托盘Shell_NotifyIcon()等

来源:互联网 发布:相宜本草 面膜 知乎 编辑:程序博客网 时间:2024/06/18 04:46

void CTestDlg::OnSysCommand(UINT nID, LPARAM lParam)

这个函数响应系统控制菜单的命令.(即左上角图标处)。

OnSysCommand:The framework calls this member function when the user selects a command from the Control menu, or when the user selects the Maximize or the Minimize button.

另外:

DoDataExchange:当UpdateData时候

OnInitDialog:对话框类已经构造,但是对话框还没有显示出来的时候

OnQueryDragIcon:The framework calls this member function by a minimized (iconic) window that does not have an icon defined for its class. The system makes this call to obtain the cursor to display while the user drags the minimized window.
-----------------------------------

http://down.dl.net.cn/Article.Asp?id=389  托盘编程全接触


所谓的“托盘”,在Windows系统界面中,指的就是下面任务条右侧,有系统时间等等的标志的那一部分。在程序最小化或挂起时,但有不希望占据任务栏的时候,就可以把程序放到托盘区。其实,托盘区的编程很简单,下面简要阐述一下子喽^_^

  二、托盘编程相关函数

  其实呢,把程序放到托盘上的本质就是先在托盘区绘制一个图标,然后把程序隐藏不见,再对托盘的图标进行消息处理,就可以了。

  绘制图标以及确定图标所传送消息的函数只有一个,那就是——————

WINSHELLAPI BOOL WINAPI Shell_NotifyIcon(
DWORD dwMessage,
PNOTIFYICONDATA pnid
); 

  这个函数呢,负责向系统传递消息,以添加、修改或删除托盘区的图标。她的返回值呢,是个布尔类型的。就是说,如果返回0,那就是成仁啦,非0才成功。

  参数dwMessage 是表示这个函数的应用功能是哪一方面,是添加、删除,还是修改图标。如果是添加,则它的值为NIM_ADD;删除则是NIM_DELETE;而修改是NIM_MODIFY。参数pnid就是具体的和程序在托盘区的图标有关系的结构了。它的定义如下:

typedef struct _NOTIFYICONDATA {
DWORD cbSize;
HWND hWnd;
UINT uID;
UINT uFlags;
UINT uCallbackMessage;
HICON hIcon;
char szTip[64];
} NOTIFYICONDATA, *PNOTIFYICONDATA; 

  下面就对该结构各个参数进行刨析:

  cbSize : 结构的长度,用“位”来做单位。一般在程序中,我们用(DWORD)sizeof(NOTIFYICONDATA) 给它赋值。

  HWnd : 一个句柄,如果对托盘中的图标进行操作,相应的消息就传给这个句柄所代表的窗口。自然了,大多数情况下是this->m_hWnd喽。

  uID : 在工程中定义的图标ID

  uFlags : 这个成员标志着其他哪些成员的数据是有效的,分别为NIF_ICON, NIF_MESSAGE, NIF_TIP,分别代表着数据有效的成员是hIcon, uCallbackMessage, szTip。当然,三个值可以用“|”联系到一起。下面分别对涉及到的成员进行阐述

  hIcon : 要增加,删除或修改的图标句柄。如果只知道个uID, 一般可能会用函数LoadIcon来得到句柄。例如LoadIcon ( AfxGetInstanceHandle() ,MAKEINTRESOURCE (IDR_MAINFRAME) )。

  uCallbackMessage : 这在对托盘区的操作中,是比较重要的数据成员。这是个消息标志,当用鼠标对托盘区相应图标进行操作的时候,就会传递消息给Hwnd所代表的窗口。所以说,在uFlags中,一般都得标志它有效。这里一般都是自定义的消息。

  szTip : 鼠标移动到托盘图标上时的提示文字。

  三、托盘编程例子

  有关托盘编程的基础知识呢,也就上面这些了。下面呢,我们就进入具体的实战演练阶段,举几个托盘编程的例子瞧瞧,加深理解。

  1、将程序最小化到系统托盘区的函数toTray()。

void CTimeWakeDlg::toTray()
{
NOTIFYICONDATA nid;
nid.cbSize=(DWORD)sizeof(NOTIFYICONDATA);
nid.hWnd=this->m_hWnd;
nid.uID=IDR_MAINFRAME;
nid.uFlags=NIF_ICON|NIF_MESSAGE|NIF_TIP ;
nid.uCallbackMessage=WM_SHOWTASK;//自定义的消息名称
nid.hIcon=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_MAINFRAME));
strcpy(nid.szTip,"计划任务提醒");//信息提示条为“计划任务提醒”
Shell_NotifyIcon(NIM_ADD,&nid);//在托盘区添加图标
ShowWindow(SW_HIDE);//隐藏主窗口

  这是个很简单的函数,里面首先给NOTIFYICONDATA赋值,然后调用shell_NotifyIcon, 头一个参数是NIM_ADD,表示添加。然后用函数ShowWindow 隐藏主窗口,这样,就实现了将程序最小化到系统托盘区的任务了。

  2、程序已经最小化到托盘区了,但是呢,对托盘图标的操作如何进行呢?这就体现了结构NOTIFYICONDATA的成员uCallbackMessage 的作用了。它所提供的作用就是,当用户用鼠标点击托盘区的图标的时候(无论是左键还是右键),会向hWnd所代表的窗口传送消息,如果是上例,消息的名称就是WM_SHOWTASK。根据VC的消息机制,对自定义消息增加消息响应函数。

  在头文件的//{{AFX_MSG和//}}AFX_MSG之间声明消息响应函数:

  afx_msg LRESULT onShowTask(WPARAM wParam,LPARAM lParam);

  然后在CPP文件中添加消息映射。在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP 之间加入: ON_MESSAGE(WM_SHOWTASK,onShowTask)将消息和消息响应函数映射起来。

  然后就是在CPP文件中加入函数onShowTask的实现了:

LRESULT CTimeWakeDlg::onShowTask(WPARAM wParam,LPARAM lParam)
//wParam接收的是图标的ID,而lParam接收的是鼠标的行为
{
if(wParam!=IDR_MAINFRAME)
return 1;
switch(lParam)
{
case WM_RBUTTONUP://右键起来时弹出快捷菜单,这里只有一个“关闭”
{

LPPOINT lpoint=new tagPOINT;
::GetCursorPos(lpoint);//得到鼠标位置
CMenu menu;
menu.CreatePopupMenu();//声明一个弹出式菜单
//增加菜单项“关闭”,点击则发送消息WM_DESTROY给主窗口(已
//隐藏),将程序结束。
menu.AppendMenu(MF_STRING,WM_DESTROY,"关闭");
//确定弹出式菜单的位置
menu.TrackPopupMenu(TPM_LEFTALIGN,lpoint->x,lpoint->y,this);
//资源回收
HMENU hmenu=menu.Detach();
menu.DestroyMenu();
delete lpoint;
}
break;
case WM_LBUTTONDBLCLK://双击左键的处理
{
this->ShowWindow(SW_SHOW);//简单的显示主窗口完事儿
}
break;
}
return 0;
}

------------------------------------

http://www.daima.com.cn/Info/38/Info6881/

1。对不同的消息,MFC用不同的宏实现消息映射
  2。消息映射表处理这个类所定义的消息映射和这个类不处理而定义的消息而传递给其父类处理的消息映射
  3。在BEGIN_...和END_...之间的宏为这个消息映射表必须处理的消息产生登录入口
  4。宏分类:
    1、标准WINDOWS消息都由宏ON_WM_XXX处理,其中XXX为标准消息名
    2、宏ON_REGISTERED_MESSAGE用于处理用户自己登记注册的WINDOWS窗口消息。
    这个宏接受NEAR类型的无符号整型变量,这个变量就是已经登记注册的WINDOWS消息标识。
该消息标识可由RegisterWindowMessage函数调用而得到系统唯一的全局消息。
 例如:afx_msg LRESULT OnFind(WPARAM wParam,LPARAM lParam); 
static UINT NEAR WM_FIND=RegisterWindowMessage("COMMONDLG_FIND"); //用此函数登记的消息范围是0XC000~0XFFFF
 ( 注: WM_FIND必须说明为NEAR类型 )
 BEGIN_MESSAGE_MAP(...)
 ...
 ON_REGISTERED_MESSAGE(WM_FIND,OnFind)
 ...
 END_MESSAGE_MAP
 3、用户自定义的WINDOWS消息可以用宏ON_MESSAGE包含在消息映射中
 #define WM_MYMESSAGE WM_USER+100 
 ON_MESSAGE(WM_MYMESSAGE,OnMymessage)
 可以通过: CWnd * pwnd=...; pwnd->SendMessage(WM_MYMESSAGE);来实现

4、命令消息的处理是使用宏ON_COMMAND,命令消息包括菜单命令和菜单加速键命令,格式为ON_COMMAND(ID,MEMBERFUNCTION)
 ON_COMMAND接受命令标识,实际的命令处理函数不带任何参数,处理完后也不返回任何类型值
 5、命令更新的消息与ON_COMMAND的处理的机制的方法相同,
 不同的使用宏ON_UPDATE_COMMAND_UI来代替宏ON_COMMAND的使用。
 格式为:ON_UPDATE_COMMAND_UI(ID,MEMBERFUNCTION).
 此成员处理函数带一个参数CCmdUI * cmdUI,但不返回任何值.
 6、ON_COMMAND_EX不仅包含所有ON_COMMAND功能,而且提供了宏的功 能超集.
  扩展后的命令处理成员函数仅仅带有一个参数,一个包含命令标识符的无符号整型数,
 函数要求返回一个布尔型值,如果返回为正,则表示消息已经处理,
 为假,表示这个命令消息还要传给其他命令处理函数进一步处理 。
 7、更高级的消息宏还有ON_COMMAND_RANGE、ON_COMMAND_RANGE_EX,
 这两个宏允许用一个命令处理器处理属于一定范围的命令消息。
 CLASSWIZARD 仅仅识别ON_COMMAND、ON_UPDATE_COMMAND_UI宏
 8、对于一个窗口的子控制送往这个窗口的通知消息来说,
 这个通知消息在消息映射表之中有一个额外的信息:子控制的标识。
 仅当在消息映射表中的消息处理函数满足两个条件时,它才被调用。
 (a). 子控制的通知消息代码,即LPARAM的高字节; (b).子控制的标识
 (即WPARAM)与消息映射表中的子控制标识相同
 9、用户自定义的消息通知码可以用宏ON_CONTROL在消息映射表中,
 定义用户自己的消息通知码处理函数.定义格式为:
 ON_CONTROL(WNOTIFICATIONCODE,ID,MEMBERFUNCTION)
 10、可以采用宏ON_CONTROL_RANGE处理一定范围内的子控制通知消息码
11、对于复杂的WINDOWS控制通知消息,WINDOWS的公用控制利用了更加强大的WM_NOTIFY
 在CWnd类中,成员函数OnNotify用于处理子控制的通知消息,一般的没有必要重载此函数
 定义格式为ON_NOTIFY(WNOTIFICATIONCODE,ID,MEMBERFUNCTION)
 成员函数的定义格式:afx_msg void memberfunction(NMHDR *pNotifyStruct,LRESULT *result)
 pNotifyStruct 为指向通知消息结构的指针,result为指向返回结果的指针

--------------------------------------

综合例子:

#define WM_SHOW_TASK WM_USER+150 //这个是自定义的一消息,用来传递mouse点到拖盘区的信息

。。。

BEGIN_MESSAGE_MAP(CMynetsendDlg, CDialog)
 //{{AFX_MSG_MAP(CMynetsendDlg)
 ON_WM_SYSCOMMAND()
 ON_WM_PAINT()
 ON_WM_QUERYDRAGICON()
 ON_BN_CLICKED(IDC_BUTTON1, OnButton1)
 ON_MESSAGE(WM_SHOW_TASK,OnShowTask)
 ON_WM_SHOWWINDOW()
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()

。。。

 

void CMynetsendDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
 if ((nID & 0xFFF0) == IDM_ABOUTBOX)
 {
  CAboutDlg dlgAbout;
  dlgAbout.DoModal();
 }
 else
 {
  CDialog::OnSysCommand(nID, lParam);
 }
 
 if (nID==SC_MINIMIZE)
 {
 
 NOTIFYICONDATA nid;
 nid.cbSize=(DWORD)sizeof(NOTIFYICONDATA);
 nid.hWnd=this->m_hWnd;
 nid.uID=IDR_MAINFRAME;
 nid.uFlags=NIF_ICON|NIF_MESSAGE|NIF_TIP ;
 nid.uCallbackMessage=WM_SHOW_TASK;//自定义的在托盘区显示图标的消息
 nid.hIcon=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_MAINFRAME));
 strcpy(nid.szTip,"要发消息点我!");//信息提示条
 Shell_NotifyIcon(NIM_ADD,&nid);//在托盘区添加图标
 ShowWindow(SW_HIDE);//隐藏窗口

 }

}

LRESULT CMynetsendDlg::OnShowTask(WPARAM wParam,LPARAM lParam)
//wParam接收的是图标的ID,而lParam接收的是鼠标的行为
{
 if(wParam!=IDR_MAINFRAME) return 1;

 switch(lParam)
 {
 case WM_RBUTTONUP://右键起来时弹出快捷菜单
  {  
   LPPOINT lpoint=new tagPOINT;
   ::GetCursorPos(lpoint);//得到鼠标位置

   CMenu menu;
   int pMenuID = 0;

   VERIFY(menu.LoadMenu(IDR_MENU1));//得到菜单
   CMenu* pPopup = menu.GetSubMenu(pMenuID);//得到子菜单
   ASSERT(pPopup != NULL);
  
   DWORD Made = pPopup->TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_NONOTIFY|TPM_RETURNCMD,lpoint->x,lpoint->y,this,NULL);//使用子菜单
  
   switch(Made)
   {
   case  ID_MENUITEM32771: {DestroyWindow();} break;
   case  ID_MENUITEM32772: {ShowWindow(SW_SHOW);ShowWindow(SW_SHOWNORMAL);}  break; 
   case  ID_MENUITEM32773: {CAboutDlg dlgAbout;dlgAbout.DoModal();}  break; 
   }

   pPopup->DestroyMenu();
   HMENU hmenu=menu.Detach();//资源回收
   menu.DestroyMenu();
   delete lpoint;
  }

  break;
 case WM_LBUTTONDOWN://左键的处理
  {
 
   ShowWindow(SW_SHOW);  //简单的显示主窗口完事儿
   ShowWindow(SW_SHOWNORMAL); //可以避免原来的最小化
  }
  break;
 }
 return 0;
}

注:例子摘自vckbase http://www.vckbase.com/code/listcode.asp?mclsid=9&sclsid=905

一个WINDOWS消息发送工具