总结

 
一、关于托盘制作
1.     在对话框头文件中添加一个 NOTIFYICONDATA 类型的成员数据,用来设定托盘消息处理的方法,如下:
NOTIFYICONDATA m_nid;
添加一个名为 ToTray 的函数,用来初始化 m_nid 和托盘的一些信息,在对话框头文件中添加函数原型:
void ToTray(void);
   函数定义如下:
void CSkypeTVDlg::ToTray(void)
{
    m_nid.cbSize=sizeof(NOTIFYICONDATA);
    m_nid.hWnd= this->GetSafeHwnd() ;
    m_nid.uID=IDR_MAINFRAME;
    m_nid.uFlags= NIF_ICON|NIF_MESSAGE|NIF_TIP;
    m_nid.uCallbackMessage= WM_CLICKONTRAY ;// 自定义的消息名称
    m_nid.hIcon=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_MAINFRAME));
    strcpy(m_nid.szTip,"SkypeTV");// 信息提示条
    Shell_NotifyIcon(NIM_ADD,&m_nid);// 在托盘区添加图标
}
其中 WM_CLICKONTRAY 为自定义消息,用来响应托盘的鼠标事件,下面将有介绍。
最后, OnInitDialog 中加入语句: ToTray() ; 使对话框开启后就初始化为托盘状态。
2 .自定义消息 : 定义一个名为 WM_CLICKONTRAY 的消息,用来响应托盘的鼠标事件:
#define WM_CLICKONTRAY   WM_USER+100
   BEGIN_MESSAGE_MAP END_MESSAGE_MAP 宏之间添加消息映射:
ON_MESSAGE(WM_CLICKONTRAY,OnTray)
   实现自定义消息函数( OnTray 函数),在对话框头文件中添加函数原型:
LRESULT OnTray(WPARAM wParam, LPARAM lParam);
   NOTE: 关于自定义消息函数的格式,请参考自定义消息相关知识。
   最后,函数定义如下:
LRESULT CSkypeTVDlg::OnTray(WPARAM wParam, LPARAM lParam)
{
    if(wParam!=IDR_MAINFRAME)
        return 1;
    switch(lParam)
    {
    case WM_RBUTTONUP:
        // 右键起来时弹出快捷菜单
        {         
            CPoint pp(LOWORD(lParam),HIWORD(lParam));
            ShowMenu(pp);
            // 显示浮动菜单
        }
        break;
    case WM_LBUTTONUP:
        {
            …….
        }
        break;
    }
    return 0;
}
其中 ShowMenu 用来显示托盘菜单,具体代码如下:
void CSkypeTVDlg::ShowMenu(CPoint point)
{
    CMenu *pMenu = new CMenu;   
    if(pMenu)
    {
        if(pMenu->LoadMenu( IDR_MENU1 ))
        { 
            SetMenu(pMenu);
            CMenu *pSubMenu = pMenu->GetSubMenu(0);      
            if(m_bStartWithComputer)
                // 注意:菜单状态在此时(右键弹起时)就要确定好,而不是在单击 // 菜单项时确定,下面有详细说明。
                pSubMenu-> CheckMenuItem (ID_TRAY_STARTWITHCOMPUTER, MF_CHECKED | MF_BYCOMMAND);             
            CPoint pt;
            GetCursorPos(&pt);           
            ::SetForegroundWindow(m_nid.hWnd);     
            if(pSubMenu)
            {
                ::TrackPopupMenu(pSubMenu->m_hMenu, 0, pt.x, pt.y, 0,
                    m_nid.hWnd, NULL);
            }                     
            ::PostMessage(m_nid.hWnd, WM_NULL, 0, 0);
        }  
    }  
}
其中 IDR_MENU1 为菜单资源文件。
3.添加托盘菜单事件处理的响应函数,一般托盘都有一个“退出”菜单选项,其实现如下:
void CSkypeTVDlg::OnTrayExit()
{
    // TODO: Add your command handler code here
    DelIcon();
    DestroyWindow();
}
 
void CSkypeTVDlg::DelIcon(void)
{
    m_nid.cbSize=sizeof(NOTIFYICONDATA);
    m_nid.hWnd=this->m_hWnd;
    m_nid.uID=IDR_MAINFRAME;
    Shell_NotifyIcon(NIM_DELETE,&m_nid);
    CDialog::OnCancel();  
}
其中 OnTrayExit 是添加菜单事件处理时得到的消息映射函数,在菜单资源文件中右键点击“退出”菜单项,选择“ Add Event Handler…… ”选项,将自动生成相应的菜单消息函数。(其它菜单项操作相同)。
下面是另一个菜单项的消息映射函数,主要用来示范怎么样改变菜单的状态(是否 ”CHECK” ,例如:有的菜单项前面有个勾或点之类的,就已经 CHECK 了)。
void CSkypeTVDlg::OnTrayChangeMenuState()
{
    // TODO: Add your command handler code here
    HKEY hkey;
    DWORD dwValue = 0;
    TCHAR path[256]="HKEY_CURRENT_USER//Software
//VideoHome//SkypeTV";
 
    OpenRegKey(path,&hkey);
 
    if ( m_bMenuChecked == FALSE )
    {
        m_bMenuChecked = TRUE;
        dwValue = 1;
        RegSetValueEx(hkey,"MenuChecked",0,REG_DWORD,(const BYTE*)&dwValue,sizeof(DWORD));
    }
    else
    {
        m_bMenuChecked = FALSE;    
        RegSetValueEx(hkey,"MenuChecked",0,REG_DWORD,(const BYTE*)&dwValue,sizeof(DWORD));
    }
    RegCloseKey(hkey);
}
需要注意的是:点击托盘任一菜单项(其实所有弹出式菜单都一样)后,菜单将立即消失(退出),而菜单状态的初始化或改变应该在菜单显示或弹出时进行。因此 不能在此时(菜单项的消息映射函数中)调用 CheckMenuItem 来改变菜单项的状态 (如果此时在菜单项的消息映射函数中进行 CheckMenuItem 操作将不起作用),此时在菜单项的消息映射函数中必须记录(而不是改变)菜单项的状态,可以用一个 BOOL 型的变量(例如 bMenuChecked )来保存菜单项的状态,鼠标每点击一次就进行 FALSE TRUE 之间的转换(注意:在最后退出托盘程序时,必须将菜单项的状态保存到注册表或 INI 文件中,以便托盘程序下次启动时初始化菜单项状态)。而 菜单状态的初始化动作应该在右键单击托盘图标弹起后进行, 此时通过读取在菜单项消息映射函数中记录的菜单项状态来决定 CHECK MENU 还是不 CHECK MENU.( 例如 : bMenuChecked TRUE 时,就在相应的菜单项前面进行打勾操作( CHECK MENE , bMenuChecked FALSE 时,就将菜单项前面的勾取消掉 )
 
4.最后将对话框窗口最小化并隐藏。在 OnInitDialog中添加如下代码:
   PostMessage(WM_SYSCOMMAND,MAKEWPARAM(SC_MINIMIZE,0),0);
 并在 OnSysCommand 中添加下面的代码:
   if ((nID & 0xFFF0)==SC_MINIMIZE)
    {      
        ShowWindow(SW_HIDE);
}
  不要在OnInitDialog中直接调用 ShowWindow(SW_HIDE); 因为此时窗口还没有完全 Init
 
二、             关于与 Skype 的通信
BOOL CSkypeTVDlg::Init ()
{
    HWND hwnd = this->GetSafeHwnd();
  
    m_MsgID_SkypeAttach =
RegisterWindowMessage("SkypeControlAPIAttach") ;
    m_MsgID_SkypeDiscover = RegisterWindowMessage("SkypeControlAPIDiscover") ;
    if ( m_MsgID_SkypeAttach == 0 || m_MsgID_SkypeDiscover == 0 )    
    {
         return FALSE;
    }
      
    if(:: PostMessage(HWND_BROADCAST,m_MsgID_SkypeDiscover, (WPARAM)hwnd, 0) ==0)
      return FALSE;
   
   return TRUE;
}
其中 m_MsgID_SkypeAttach m_MsgID_SkypeDiscover CSkypeTVDlg 的成员变量,类型为 UINT
 
因为需要处理 Skype 发过来的消息,所以重载了 WindowProc (或 DefWindowProc ,在工程的 properties window 中选择 overrides ,再选择需要重载的函数):
LRESULT CSkypeTVDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
    // TODO: Add your specialized code here and/or call the base class
    if ( message == m_MsgID_SkypeAttach
        || message == m_MsgID_SkypeDiscover
        || message == WM_COPYDATA )
    {
        if ( TranslateMessage ( message, wParam, lParam ) )
            return TRUE;
    }
    return CDialog::WindowProc(message, wParam, lParam);
}
其中 TranslateMessage 定义如下:
BOOL CSkypeTVDlg::TranslateMessage ( UINT message, WPARAM wParam, LPARAM lParam )
{   
    if ( message == WM_COPYDATA )
    {
        if( m_hWnd_Skype == (HWND)wParam )
        {          
            PCOPYDATASTRUCT poCopyData = (PCOPYDATASTRUCT)lParam;
            // 解析返回的字符信息;
            ParseSkypeMsg (LPCTSTR(poCopyData->lpData));     
            return TRUE;
        }      
    }    
    if ( message == m_MsgID_SkypeAttach )
    {
         switch ( lParam )
         {
                case SKYPECONTROLAPI_ATTACH_SUCCESS:     
                      m_hWnd_Skype=(HWND)wParam;// 得到 skype 的句柄                 
                      break; 
                case SKYPECONTROLAPI_ATTACH_PENDING_AUTHORIZATION:
                      break;
                case SKYPECONTROLAPI_ATTACH_REFUSED:          
                      break;
                case SKYPECONTROLAPI_ATTACH_NOT_AVAILABLE:
                      break;
                case SKYPECONTROLAPI_ATTACH_API_AVAILABLE:             
                      break;
         }
    }
    return TRUE;  
}
其中 m_hWnd_Skype CSkypeTVDlg 的成员变量,类型为 HWND.
其中 ParseSkypeMsg 定义如下:
BOOL CSkypeTVDlg :: ParseSkypeMsg (LPCTSTR lpszMsg)
{
     if ( !lpszMsg || strlen(lpszMsg) < 1 )
         return FALSE;
     CStringArray StrAry;
     INT_PTR nStrNum = PartStringAndAddToStrAry ( (char*)lpszMsg, StrAry, " ,;/t" );
     if ( nStrNum < 1 ) return FALSE;
     int nCmdPos = 0;
     // Get the current chat's ID
     if ( StrAry.GetAt ( nCmdPos ) == "CHAT")
     {      
         ………………          
     }
     else if (StrAry.GetAt ( nCmdPos ) == "MESSAGE")
     {
          ………………
     }
     else if (StrAry.GetAt ( nCmdPos ) == "CALL")
     {
          ………………
     }
     StrAry.RemoveAll ();
     return TRUE;
}
其中 PartStringAndAddToStrAry 定义如下:
INT_PTR PartStringAndAddToStrAry ( char *pStr, CStringArray &StrAry, char *seps/*="/t/r/n"*/ )
{
     StrAry.RemoveAll();
     char *token;
     token = strtok( pStr, seps );
     while( token != NULL )
     {
         /* While there are tokens in "string" */
         StrAry.Add ( token );
         /* Get next token: */
         token = strtok( NULL, seps );
     }
     return StrAry.GetSize();
}
 
 
最后一个函数用来与 Skype 通信,向 Skype 发送消息:
BOOL CSkypeTVDlg::SendMsg ( LPCTSTR lpszMsg, ... )
{
     if ( !lpszMsg || strlen(lpszMsg) < 1 ) return FALSE;
    
     COPYDATASTRUCT CopyData = {0};
     char buf[1024] = {0};
    
     va_list va;
     va_start ( va, lpszMsg );
     _vsnprintf ( buf, sizeof(buf) - 1, (char*)lpszMsg, va);
     va_end(va);
 
     CopyData.dwData = 0;
     CopyData.lpData = (PVOID)buf;
     CopyData.cbData = strlen(buf)+1;
 
      HWND hwnd = this->GetSafeHwnd();
     if ( :: SendMessage ( m_hWnd_Skype, WM_COPYDATA, WPARAM(hwnd),
         LPARAM(&CopyData)) == 0 )
     {     
         return FALSE;
     }
     return TRUE;
}
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值