123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443 |
- #include "stdafx.h"
- #include "trayicon.h"
- #include <strsafe.h>
- #include <afxpriv.h> // for AfxLoadString
- IMPLEMENT_DYNAMIC(ITrayIcon, CCmdTarget)
- typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
- ITrayIcon::ITrayIcon(UINT uID)
- {
- // Initialize NOTIFYICONDATA
- memset(&m_nid, 0 , sizeof(m_nid));
- m_nid.cbSize = sizeof(m_nid);
- m_nid.uID = uID; // never changes after construction
- OpendThread();
-
- bShowMinibox = FALSE;
- //m_pWnd = AfxGetMainWnd();
- // Use resource string as tip if there is one
- AfxLoadString(uID, m_nid.szTip, sizeof(m_nid.szTip));
- }
- ITrayIcon::~ITrayIcon()
- {
- SetIcon(0); // remove icon from system tray
- TerminalThread();
- }
- //////////////////
- // Set notification window. It must created already.
- //
- void ITrayIcon::SetNotificationWnd(CWnd* pNotifyWnd, UINT uCbMsg)
- {
- // If the following assert fails, you're probably
- // calling me before you created your window. Oops.
- ASSERT(pNotifyWnd==NULL || ::IsWindow(pNotifyWnd->GetSafeHwnd()));
- m_nid.hWnd = pNotifyWnd->GetSafeHwnd();
- ASSERT(uCbMsg==0 || uCbMsg>=WM_USER);
- m_nid.uCallbackMessage = uCbMsg;
- }
- //////////////////
- // This is the main variant for setting the icon.
- // Sets both the icon and tooltip from resource ID
- // To remove the icon, call SetIcon(0)
- //
- BOOL ITrayIcon::SetIcon(UINT uID)
- {
- HICON hicon=NULL;
- if (uID)
- hicon = AfxGetApp()->LoadIcon(uID);
- UINT msg;
- m_nid.uFlags = 0;
- // Set the icon
- if (hicon)
- {
- // Add or replace icon in system tray
- msg = m_nid.hIcon ? NIM_MODIFY : NIM_ADD;
- m_nid.hIcon = hicon;
- m_nid.uFlags |= NIF_ICON;
- }
- else
- { // remove icon from tray
- if (m_nid.hIcon==NULL)
- return TRUE; // already deleted
- msg = NIM_DELETE;
- }
- // Use callback if any
- if (m_nid.uCallbackMessage && m_nid.hWnd)
- m_nid.uFlags |= NIF_MESSAGE;
- // Do it
- BOOL bRet = Shell_NotifyIcon(msg, &m_nid);
- if (msg==NIM_DELETE || !bRet)
- m_nid.hIcon = NULL; // failed
- return bRet;
- }
- BOOL ITrayIcon::SetIcon(UINT uID, LPCTSTR lpTip)
- {
- HICON hicon=NULL;
- if (uID)
- {
- AfxLoadString(uID, m_nid.szTip, sizeof(m_nid.szTip));
- hicon = AfxGetApp()->LoadIcon(uID);
- }
- return SetIcon(hicon, lpTip ? lpTip:NULL);
- }
- //////////////////
- // Common SetIcon for all overloads.
- //
- BOOL ITrayIcon::SetIcon(HICON hicon, LPCTSTR lpTip)
- {
- UINT msg;
- m_nid.uFlags = 0;
- // Set the icon
- if (hicon)
- {
- // Add or replace icon in system tray
- msg = m_nid.hIcon ? NIM_MODIFY : NIM_ADD;
- m_nid.hIcon = hicon;
- m_nid.uFlags |= NIF_ICON;
- }
- else
- { // remove icon from tray
- if (m_nid.hIcon==NULL)
- return TRUE; // already deleted
- msg = NIM_DELETE;
- }
- // Use the tip, if any
- if (lpTip)
- //strncpy(m_nid.szTip, lpTip, sizeof(m_nid.szTip));
- StringCchCopy(m_nid.szTip, sizeof(m_nid.szTip),lpTip);
- if (m_nid.szTip[0])
- m_nid.uFlags |= NIF_TIP;
- // Use callback if any
- if (m_nid.uCallbackMessage && m_nid.hWnd)
- m_nid.uFlags |= NIF_MESSAGE;
- // Do it
- BOOL bRet = Shell_NotifyIcon(msg, &m_nid);
- if (msg==NIM_DELETE || !bRet)
- m_nid.hIcon = NULL; // failed
- return bRet;
- }
- BOOL ITrayIcon::SetTip(LPCTSTR lpTip)
- {
- UINT msg;
- m_nid.uFlags = 0;
- if (m_nid.hIcon == NULL)
- return TRUE; // already deleted
- msg = NIM_MODIFY;
- // Use the tip, if any
- //if (lpTip)
- //strncpy(m_nid.szTip, lpTip, sizeof(m_nid.szTip));
- StringCchCopy(m_nid.szTip, sizeof(m_nid.szTip), lpTip);
- if (m_nid.szTip[0])
- m_nid.uFlags |= NIF_TIP;
- // Use callback if any
- if (m_nid.uCallbackMessage && m_nid.hWnd)
- m_nid.uFlags |= NIF_MESSAGE;
- return Shell_NotifyIcon(msg, &m_nid);
- }
- //BOOL ITrayIcon::SetInfo(LPCSTR lpInof, LPCSTR lpInfoTitle)
- BOOL ITrayIcon::SetInfo(LPCTSTR lpInof, LPCTSTR lpInfoTitle)
- {
- UINT msg;
- m_nid.uFlags = 0;
- if (m_nid.hIcon == NULL)
- return TRUE; // already deleted
- msg = NIM_MODIFY;
- //strncpy(m_nid.szInfo, lpInof, sizeof(m_nid.szInfo));
- StringCchCopy(m_nid.szInfo, sizeof(m_nid.szInfo),lpInof);
- if ( lpInfoTitle != NULL)
- {
- StringCchCopy(m_nid.szInfoTitle, sizeof(m_nid.szInfoTitle), lpInfoTitle);
- m_nid.uFlags |= NIF_INFO|NIIF_INFO;
- m_nid.uTimeout = 1000;
- }
- else
- {
- m_nid.uFlags |= NIF_INFO;
- }
- // Use callback if any
- if (m_nid.uCallbackMessage && m_nid.hWnd)
- m_nid.uFlags |= NIF_MESSAGE;
- return Shell_NotifyIcon(msg, &m_nid);
- }
- /////////////////
- // Default event handler handles right-menu and doubleclick.
- // Call this function from your own notification handler.
- //
- LRESULT ITrayIcon::OnTrayNotification(WPARAM wID, LPARAM lEvent)
- {
- if (wID!=m_nid.uID || (lEvent!=WM_RBUTTONUP && lEvent!=WM_LBUTTONDBLCLK))
- return 0;
- // If there's a resource menu with the same ID as the icon, use it as
- // the right-button popup menu. CTrayIcon will interprets the first
- // item in the menu as the default command for WM_LBUTTONDBLCLK
- //
- #if 0
- CMenu menu;
- if (!menu.LoadMenu(m_nid.uID))
- return 0;
- CMenu* pSubMenu = menu.GetSubMenu(0);
- if (!pSubMenu)
- return 0;
- if (lEvent==WM_RBUTTONUP)
- {
- // Make first menu item the default (bold font)
- ::SetMenuDefaultItem(pSubMenu->m_hMenu, 0, TRUE);
- // Display the menu at the current mouse location. There's a "bug"
- // (Microsoft calls it a feature) in Windows 95 that requires calling
- // SetForegroundWindow. To find out more, search for Q135788 in MSDN.
- //
- CPoint mouse;
- GetCursorPos(&mouse);
- ::SetForegroundWindow(m_nid.hWnd);
- ::TrackPopupMenu(pSubMenu->m_hMenu, 0, mouse.x, mouse.y, 0,
- m_nid.hWnd, NULL);
- } else // double click: execute first menu item
- ::SendMessage(m_nid.hWnd, WM_COMMAND, pSubMenu->GetMenuItemID(0), 0);
- #endif
- return 1; // handled
- }
- // ------------------------------- [5/30/2013 Z.t]
- BOOL ITrayIcon::IsWow64()
- {
- BOOL bIsWow64 = FALSE;
- LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(_T("kernel32")),"IsWow64Process");
- if (NULL != fnIsWow64Process)
- {
- if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
- {
- // handle error
- }
- }
- return bIsWow64;
- }
- /************************************************************************/
- /*
- 函数:GetTrayRect,获取托盘图标区域;(有待完善,添加各种错误判断)
- 参数:None;
- 返回:返回指定托盘图标的区域;
- 注意:函数的功能有些太复杂,暂时没办法使用更简单的方法获取图标区域;
- */
- /************************************************************************/
- void ITrayIcon::GetTrayRect(RECT &rc)
- {
- HWND hWnd,hWndPaper;
- long ret;
-
- LPVOID lngAddress;
- // long lngTextAdr; //,lngHwndAdr,lngHwnd,lngButtonID;
- TCHAR strBuff[1024]={0};
- TBBUTTON btnData={0};
- hWnd = FindWindow(_T("Shell_TrayWnd"), NULL); // 获取任务栏句柄 [5/31/2013 Z.t]
- hWnd = FindWindowEx(hWnd, 0, _T("TrayNotifyWnd"), NULL); // 获取托盘区域句柄 [5/31/2013 Z.t]
- hWndPaper = FindWindowEx(hWnd, 0, _T("SysPager"), NULL); // 获取系统页句柄 [5/31/2013 Z.t]
- if(!hWndPaper)
- hWnd = FindWindowEx(hWnd, 0, _T("ToolbarWindow32"), NULL);
- else
- hWnd = FindWindowEx(hWndPaper, 0, _T("ToolbarWindow32"), NULL);
- DWORD dwProcessId = 0;
- GetWindowThreadProcessId(hWnd, &dwProcessId);//LOG4C_NO_FILENUM((LOG_NOTICE,"进程ID%d",dwProcessId));进程其实就是explorer.exe
- HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS|PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE,0,dwProcessId);
- if ( hProcess == NULL )
- {
- //LOG4C_NO_FILENUM((LOG_NOTICE,"hProcess == NULL--"));
- return ;
- }
-
- lngAddress = VirtualAllocEx(hProcess,0, 0x4096, MEM_COMMIT, PAGE_READWRITE);
- if( lngAddress == NULL)
- {
- //LOG4C_NO_FILENUM((LOG_NOTICE,"lngAddress == NULL--"));
- return;
- }
- DWORD lTextAdr = 0;
- BYTE buff[1024] = {0};
- CString strFilePath;
- CString strTile;
- HWND hMainWnd = NULL;
- int nDataOffset = sizeof(TBBUTTON) - sizeof(INT_PTR) - sizeof(DWORD_PTR);
- int nStrOffset = 18;
- if ( IsWow64() )
- {
- nDataOffset+=4;
- nStrOffset+=6;
- }
- // 获取托盘区域的所有图标数量 [5/31/2013 Z.t]
- int ibtnCount = SendMessage(hWnd, TB_BUTTONCOUNT, 0, 0);
- LPVOID lngRect = VirtualAllocEx(hProcess,0,sizeof(RECT), MEM_COMMIT, PAGE_READWRITE);
-
- CRect rect;
- for(int i=0 ;i< ibtnCount;i++)
- {
- int j = i;
- ret = SendMessage(hWnd,TB_GETBUTTON,j, (LPARAM)(lngAddress));
- // 读文本地址;
- ret = ReadProcessMemory(hProcess, LPVOID(long(lngAddress) + nDataOffset),&lTextAdr,4,0);
- if(lTextAdr != -1)
- {
- // 读文本;
- ret = ReadProcessMemory(hProcess, LPVOID(lTextAdr),buff,1024,0);
- hMainWnd = (HWND)(*((DWORD*)buff));
- strFilePath = (WCHAR *)buff + nStrOffset; // 获取托盘图标进程路径 [5/31/2013 Z.t]
- strTile = (WCHAR *)buff + nStrOffset + MAX_PATH; // 获取托盘图标tip标题 [5/31/2013 Z.t]
- //_tprintf(_T("%s %s\n"),strTile,strFilePath);
- if (strTile.Compare(m_nid.szTip) == 0)
- {
- ::SendMessage(hWnd,TB_GETITEMRECT,(WPARAM)j,(LPARAM)lngRect);
- ReadProcessMemory(hProcess,lngRect,&rc, sizeof(rc),0); // 获取托盘图标区域;
- CWnd::FromHandle(hWnd)->ClientToScreen(&rc);
- }
- }
- }
- VirtualFreeEx( hProcess, lngAddress, 0x4096, MEM_DECOMMIT);
- VirtualFreeEx( hProcess, lngAddress, 0, MEM_RELEASE);
- VirtualFreeEx( hProcess, lngRect, sizeof(RECT), MEM_DECOMMIT);
- VirtualFreeEx( hProcess, lngRect, 0, MEM_RELEASE);
- CloseHandle(hProcess);
- }
- int ITrayIcon::OpendThread()
- {
- //LOG4C_NO_FILENUM((LOG_NOTICE,"创建TrayIcon"));
- m_hThreadCtrl = CreateEvent(NULL,TRUE,FALSE,NULL); // 无信号事件;
- if ( m_hThreadCtrl == NULL )
- {
- //LOG4C_NO_FILENUM((LOG_NOTICE,"创建TrayIcon事件失败"));
- return -1;
- }
- m_hThreadObj = CreateThread(NULL,0,FlashingThread,this,CREATE_SUSPENDED,&m_dwThreadID);
- if ( m_hThreadObj == NULL )
- {
- //LOG4C_NO_FILENUM((LOG_NOTICE,"创建TrayIcon线程失败"));
- return -1;
- }
- bSuspending = true;
- return 0;
- }
- void ITrayIcon::TerminalThread()
- {
- if ( m_hThreadCtrl )
- {
- SetEvent( m_hThreadCtrl );
- }
- if (WaitForSingleObject(m_hThreadCtrl,INFINITE) != WAIT_TIMEOUT)
- {
- CloseHandle(m_hThreadObj);
- m_hThreadObj = NULL;
- }
- CloseHandle( m_hThreadCtrl );
- m_hThreadCtrl = NULL;
- bSuspending = false;
- }
- BOOL ITrayIcon::StartFlashing()
- {
- if ( !bSuspending ) return FALSE;
- if(::ResumeThread(m_hThreadObj) == 0xFFFFFFFF)
- return FALSE;
-
- bSuspending = false;
- SetInfo(_T("环境监控系统产生新警报,请及时处理!"),_T("警报提示"));
- return TRUE;
- }
- BOOL ITrayIcon::StopFlashing()
- {
- if ( bSuspending ) return FALSE;
- if(::SuspendThread(m_hThreadObj) == 0xFFFFFFFF)
- return FALSE;
-
- bSuspending = true;
- SetIcon(_utIcon[0]);
- return TRUE;
- }
- /************************************************************************/
- /*
- 线程函数:闪烁线程;
- */
- /************************************************************************/
- DWORD WINAPI ITrayIcon::FlashingThread(LPVOID lpVoid)
- {
- ITrayIcon *pTrayIcon = (ITrayIcon*)lpVoid;
- CPoint pt;
- CRect IconRect;
- bool bChange = FALSE;
- do
- {
- if ( bChange)
- {
- pTrayIcon->SetIcon(pTrayIcon->_utIcon[1]);
- bChange = FALSE;
- }
- else
- {
- pTrayIcon->SetIcon(pTrayIcon->_utIcon[2]);
- bChange = TRUE;
- }
- if( pTrayIcon->bShowMinibox )
- {
- GetCursorPos(&pt);
- pTrayIcon->GetTrayRect(IconRect);
- if ( IconRect.PtInRect( pt) )
- ::PostMessage(pTrayIcon->m_nid.hWnd,MYWM_SHOWMINBOX,1,0);
- else
- ::PostMessage(pTrayIcon->m_nid.hWnd,MYWM_SHOWMINBOX,0,0);
- }
- }while (WaitForSingleObject(pTrayIcon->m_hThreadCtrl,300) == WAIT_TIMEOUT);
- return 0;
- }
|