TrayIcon.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. #include "stdafx.h"
  2. #include "trayicon.h"
  3. #include <strsafe.h>
  4. #include <afxpriv.h> // for AfxLoadString
  5. IMPLEMENT_DYNAMIC(ITrayIcon, CCmdTarget)
  6. typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
  7. ITrayIcon::ITrayIcon(UINT uID)
  8. {
  9. // Initialize NOTIFYICONDATA
  10. memset(&m_nid, 0 , sizeof(m_nid));
  11. m_nid.cbSize = sizeof(m_nid);
  12. m_nid.uID = uID; // never changes after construction
  13. OpendThread();
  14. bShowMinibox = FALSE;
  15. //m_pWnd = AfxGetMainWnd();
  16. // Use resource string as tip if there is one
  17. AfxLoadString(uID, m_nid.szTip, sizeof(m_nid.szTip));
  18. }
  19. ITrayIcon::~ITrayIcon()
  20. {
  21. SetIcon(0); // remove icon from system tray
  22. TerminalThread();
  23. }
  24. //////////////////
  25. // Set notification window. It must created already.
  26. //
  27. void ITrayIcon::SetNotificationWnd(CWnd* pNotifyWnd, UINT uCbMsg)
  28. {
  29. // If the following assert fails, you're probably
  30. // calling me before you created your window. Oops.
  31. ASSERT(pNotifyWnd==NULL || ::IsWindow(pNotifyWnd->GetSafeHwnd()));
  32. m_nid.hWnd = pNotifyWnd->GetSafeHwnd();
  33. ASSERT(uCbMsg==0 || uCbMsg>=WM_USER);
  34. m_nid.uCallbackMessage = uCbMsg;
  35. }
  36. //////////////////
  37. // This is the main variant for setting the icon.
  38. // Sets both the icon and tooltip from resource ID
  39. // To remove the icon, call SetIcon(0)
  40. //
  41. BOOL ITrayIcon::SetIcon(UINT uID)
  42. {
  43. HICON hicon=NULL;
  44. if (uID)
  45. hicon = AfxGetApp()->LoadIcon(uID);
  46. UINT msg;
  47. m_nid.uFlags = 0;
  48. // Set the icon
  49. if (hicon)
  50. {
  51. // Add or replace icon in system tray
  52. msg = m_nid.hIcon ? NIM_MODIFY : NIM_ADD;
  53. m_nid.hIcon = hicon;
  54. m_nid.uFlags |= NIF_ICON;
  55. }
  56. else
  57. { // remove icon from tray
  58. if (m_nid.hIcon==NULL)
  59. return TRUE; // already deleted
  60. msg = NIM_DELETE;
  61. }
  62. // Use callback if any
  63. if (m_nid.uCallbackMessage && m_nid.hWnd)
  64. m_nid.uFlags |= NIF_MESSAGE;
  65. // Do it
  66. BOOL bRet = Shell_NotifyIcon(msg, &m_nid);
  67. if (msg==NIM_DELETE || !bRet)
  68. m_nid.hIcon = NULL; // failed
  69. return bRet;
  70. }
  71. BOOL ITrayIcon::SetIcon(UINT uID, LPCTSTR lpTip)
  72. {
  73. HICON hicon=NULL;
  74. if (uID)
  75. {
  76. AfxLoadString(uID, m_nid.szTip, sizeof(m_nid.szTip));
  77. hicon = AfxGetApp()->LoadIcon(uID);
  78. }
  79. return SetIcon(hicon, lpTip ? lpTip:NULL);
  80. }
  81. //////////////////
  82. // Common SetIcon for all overloads.
  83. //
  84. BOOL ITrayIcon::SetIcon(HICON hicon, LPCTSTR lpTip)
  85. {
  86. UINT msg;
  87. m_nid.uFlags = 0;
  88. // Set the icon
  89. if (hicon)
  90. {
  91. // Add or replace icon in system tray
  92. msg = m_nid.hIcon ? NIM_MODIFY : NIM_ADD;
  93. m_nid.hIcon = hicon;
  94. m_nid.uFlags |= NIF_ICON;
  95. }
  96. else
  97. { // remove icon from tray
  98. if (m_nid.hIcon==NULL)
  99. return TRUE; // already deleted
  100. msg = NIM_DELETE;
  101. }
  102. // Use the tip, if any
  103. if (lpTip)
  104. //strncpy(m_nid.szTip, lpTip, sizeof(m_nid.szTip));
  105. StringCchCopy(m_nid.szTip, sizeof(m_nid.szTip),lpTip);
  106. if (m_nid.szTip[0])
  107. m_nid.uFlags |= NIF_TIP;
  108. // Use callback if any
  109. if (m_nid.uCallbackMessage && m_nid.hWnd)
  110. m_nid.uFlags |= NIF_MESSAGE;
  111. // Do it
  112. BOOL bRet = Shell_NotifyIcon(msg, &m_nid);
  113. if (msg==NIM_DELETE || !bRet)
  114. m_nid.hIcon = NULL; // failed
  115. return bRet;
  116. }
  117. BOOL ITrayIcon::SetTip(LPCTSTR lpTip)
  118. {
  119. UINT msg;
  120. m_nid.uFlags = 0;
  121. if (m_nid.hIcon == NULL)
  122. return TRUE; // already deleted
  123. msg = NIM_MODIFY;
  124. // Use the tip, if any
  125. //if (lpTip)
  126. //strncpy(m_nid.szTip, lpTip, sizeof(m_nid.szTip));
  127. StringCchCopy(m_nid.szTip, sizeof(m_nid.szTip), lpTip);
  128. if (m_nid.szTip[0])
  129. m_nid.uFlags |= NIF_TIP;
  130. // Use callback if any
  131. if (m_nid.uCallbackMessage && m_nid.hWnd)
  132. m_nid.uFlags |= NIF_MESSAGE;
  133. return Shell_NotifyIcon(msg, &m_nid);
  134. }
  135. //BOOL ITrayIcon::SetInfo(LPCSTR lpInof, LPCSTR lpInfoTitle)
  136. BOOL ITrayIcon::SetInfo(LPCTSTR lpInof, LPCTSTR lpInfoTitle)
  137. {
  138. UINT msg;
  139. m_nid.uFlags = 0;
  140. if (m_nid.hIcon == NULL)
  141. return TRUE; // already deleted
  142. msg = NIM_MODIFY;
  143. //strncpy(m_nid.szInfo, lpInof, sizeof(m_nid.szInfo));
  144. StringCchCopy(m_nid.szInfo, sizeof(m_nid.szInfo),lpInof);
  145. if ( lpInfoTitle != NULL)
  146. {
  147. StringCchCopy(m_nid.szInfoTitle, sizeof(m_nid.szInfoTitle), lpInfoTitle);
  148. m_nid.uFlags |= NIF_INFO|NIIF_INFO;
  149. m_nid.uTimeout = 1000;
  150. }
  151. else
  152. {
  153. m_nid.uFlags |= NIF_INFO;
  154. }
  155. // Use callback if any
  156. if (m_nid.uCallbackMessage && m_nid.hWnd)
  157. m_nid.uFlags |= NIF_MESSAGE;
  158. return Shell_NotifyIcon(msg, &m_nid);
  159. }
  160. /////////////////
  161. // Default event handler handles right-menu and doubleclick.
  162. // Call this function from your own notification handler.
  163. //
  164. LRESULT ITrayIcon::OnTrayNotification(WPARAM wID, LPARAM lEvent)
  165. {
  166. if (wID!=m_nid.uID || (lEvent!=WM_RBUTTONUP && lEvent!=WM_LBUTTONDBLCLK))
  167. return 0;
  168. // If there's a resource menu with the same ID as the icon, use it as
  169. // the right-button popup menu. CTrayIcon will interprets the first
  170. // item in the menu as the default command for WM_LBUTTONDBLCLK
  171. //
  172. #if 0
  173. CMenu menu;
  174. if (!menu.LoadMenu(m_nid.uID))
  175. return 0;
  176. CMenu* pSubMenu = menu.GetSubMenu(0);
  177. if (!pSubMenu)
  178. return 0;
  179. if (lEvent==WM_RBUTTONUP)
  180. {
  181. // Make first menu item the default (bold font)
  182. ::SetMenuDefaultItem(pSubMenu->m_hMenu, 0, TRUE);
  183. // Display the menu at the current mouse location. There's a "bug"
  184. // (Microsoft calls it a feature) in Windows 95 that requires calling
  185. // SetForegroundWindow. To find out more, search for Q135788 in MSDN.
  186. //
  187. CPoint mouse;
  188. GetCursorPos(&mouse);
  189. ::SetForegroundWindow(m_nid.hWnd);
  190. ::TrackPopupMenu(pSubMenu->m_hMenu, 0, mouse.x, mouse.y, 0,
  191. m_nid.hWnd, NULL);
  192. } else // double click: execute first menu item
  193. ::SendMessage(m_nid.hWnd, WM_COMMAND, pSubMenu->GetMenuItemID(0), 0);
  194. #endif
  195. return 1; // handled
  196. }
  197. // ------------------------------- [5/30/2013 Z.t]
  198. BOOL ITrayIcon::IsWow64()
  199. {
  200. BOOL bIsWow64 = FALSE;
  201. LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(_T("kernel32")),"IsWow64Process");
  202. if (NULL != fnIsWow64Process)
  203. {
  204. if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
  205. {
  206. // handle error
  207. }
  208. }
  209. return bIsWow64;
  210. }
  211. /************************************************************************/
  212. /*
  213. 函数:GetTrayRect,获取托盘图标区域;(有待完善,添加各种错误判断)
  214. 参数:None;
  215. 返回:返回指定托盘图标的区域;
  216. 注意:函数的功能有些太复杂,暂时没办法使用更简单的方法获取图标区域;
  217. */
  218. /************************************************************************/
  219. void ITrayIcon::GetTrayRect(RECT &rc)
  220. {
  221. HWND hWnd,hWndPaper;
  222. long ret;
  223. LPVOID lngAddress;
  224. // long lngTextAdr; //,lngHwndAdr,lngHwnd,lngButtonID;
  225. TCHAR strBuff[1024]={0};
  226. TBBUTTON btnData={0};
  227. hWnd = FindWindow(_T("Shell_TrayWnd"), NULL); // 获取任务栏句柄 [5/31/2013 Z.t]
  228. hWnd = FindWindowEx(hWnd, 0, _T("TrayNotifyWnd"), NULL); // 获取托盘区域句柄 [5/31/2013 Z.t]
  229. hWndPaper = FindWindowEx(hWnd, 0, _T("SysPager"), NULL); // 获取系统页句柄 [5/31/2013 Z.t]
  230. if(!hWndPaper)
  231. hWnd = FindWindowEx(hWnd, 0, _T("ToolbarWindow32"), NULL);
  232. else
  233. hWnd = FindWindowEx(hWndPaper, 0, _T("ToolbarWindow32"), NULL);
  234. DWORD dwProcessId = 0;
  235. GetWindowThreadProcessId(hWnd, &dwProcessId);//LOG4C_NO_FILENUM((LOG_NOTICE,"进程ID%d",dwProcessId));进程其实就是explorer.exe
  236. HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS|PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE,0,dwProcessId);
  237. if ( hProcess == NULL )
  238. {
  239. //LOG4C_NO_FILENUM((LOG_NOTICE,"hProcess == NULL--"));
  240. return ;
  241. }
  242. lngAddress = VirtualAllocEx(hProcess,0, 0x4096, MEM_COMMIT, PAGE_READWRITE);
  243. if( lngAddress == NULL)
  244. {
  245. //LOG4C_NO_FILENUM((LOG_NOTICE,"lngAddress == NULL--"));
  246. return;
  247. }
  248. DWORD lTextAdr = 0;
  249. BYTE buff[1024] = {0};
  250. CString strFilePath;
  251. CString strTile;
  252. HWND hMainWnd = NULL;
  253. int nDataOffset = sizeof(TBBUTTON) - sizeof(INT_PTR) - sizeof(DWORD_PTR);
  254. int nStrOffset = 18;
  255. if ( IsWow64() )
  256. {
  257. nDataOffset+=4;
  258. nStrOffset+=6;
  259. }
  260. // 获取托盘区域的所有图标数量 [5/31/2013 Z.t]
  261. int ibtnCount = SendMessage(hWnd, TB_BUTTONCOUNT, 0, 0);
  262. LPVOID lngRect = VirtualAllocEx(hProcess,0,sizeof(RECT), MEM_COMMIT, PAGE_READWRITE);
  263. CRect rect;
  264. for(int i=0 ;i< ibtnCount;i++)
  265. {
  266. int j = i;
  267. ret = SendMessage(hWnd,TB_GETBUTTON,j, (LPARAM)(lngAddress));
  268. // 读文本地址;
  269. ret = ReadProcessMemory(hProcess, LPVOID(long(lngAddress) + nDataOffset),&lTextAdr,4,0);
  270. if(lTextAdr != -1)
  271. {
  272. // 读文本;
  273. ret = ReadProcessMemory(hProcess, LPVOID(lTextAdr),buff,1024,0);
  274. hMainWnd = (HWND)(*((DWORD*)buff));
  275. strFilePath = (WCHAR *)buff + nStrOffset; // 获取托盘图标进程路径 [5/31/2013 Z.t]
  276. strTile = (WCHAR *)buff + nStrOffset + MAX_PATH; // 获取托盘图标tip标题 [5/31/2013 Z.t]
  277. //_tprintf(_T("%s %s\n"),strTile,strFilePath);
  278. if (strTile.Compare(m_nid.szTip) == 0)
  279. {
  280. ::SendMessage(hWnd,TB_GETITEMRECT,(WPARAM)j,(LPARAM)lngRect);
  281. ReadProcessMemory(hProcess,lngRect,&rc, sizeof(rc),0); // 获取托盘图标区域;
  282. CWnd::FromHandle(hWnd)->ClientToScreen(&rc);
  283. }
  284. }
  285. }
  286. VirtualFreeEx( hProcess, lngAddress, 0x4096, MEM_DECOMMIT);
  287. VirtualFreeEx( hProcess, lngAddress, 0, MEM_RELEASE);
  288. VirtualFreeEx( hProcess, lngRect, sizeof(RECT), MEM_DECOMMIT);
  289. VirtualFreeEx( hProcess, lngRect, 0, MEM_RELEASE);
  290. CloseHandle(hProcess);
  291. }
  292. int ITrayIcon::OpendThread()
  293. {
  294. //LOG4C_NO_FILENUM((LOG_NOTICE,"创建TrayIcon"));
  295. m_hThreadCtrl = CreateEvent(NULL,TRUE,FALSE,NULL); // 无信号事件;
  296. if ( m_hThreadCtrl == NULL )
  297. {
  298. //LOG4C_NO_FILENUM((LOG_NOTICE,"创建TrayIcon事件失败"));
  299. return -1;
  300. }
  301. m_hThreadObj = CreateThread(NULL,0,FlashingThread,this,CREATE_SUSPENDED,&m_dwThreadID);
  302. if ( m_hThreadObj == NULL )
  303. {
  304. //LOG4C_NO_FILENUM((LOG_NOTICE,"创建TrayIcon线程失败"));
  305. return -1;
  306. }
  307. bSuspending = true;
  308. return 0;
  309. }
  310. void ITrayIcon::TerminalThread()
  311. {
  312. if ( m_hThreadCtrl )
  313. {
  314. SetEvent( m_hThreadCtrl );
  315. }
  316. if (WaitForSingleObject(m_hThreadCtrl,INFINITE) != WAIT_TIMEOUT)
  317. {
  318. CloseHandle(m_hThreadObj);
  319. m_hThreadObj = NULL;
  320. }
  321. CloseHandle( m_hThreadCtrl );
  322. m_hThreadCtrl = NULL;
  323. bSuspending = false;
  324. }
  325. BOOL ITrayIcon::StartFlashing()
  326. {
  327. if ( !bSuspending ) return FALSE;
  328. if(::ResumeThread(m_hThreadObj) == 0xFFFFFFFF)
  329. return FALSE;
  330. bSuspending = false;
  331. SetInfo(_T("环境监控系统产生新警报,请及时处理!"),_T("警报提示"));
  332. return TRUE;
  333. }
  334. BOOL ITrayIcon::StopFlashing()
  335. {
  336. if ( bSuspending ) return FALSE;
  337. if(::SuspendThread(m_hThreadObj) == 0xFFFFFFFF)
  338. return FALSE;
  339. bSuspending = true;
  340. SetIcon(_utIcon[0]);
  341. return TRUE;
  342. }
  343. /************************************************************************/
  344. /*
  345. 线程函数:闪烁线程;
  346. */
  347. /************************************************************************/
  348. DWORD WINAPI ITrayIcon::FlashingThread(LPVOID lpVoid)
  349. {
  350. ITrayIcon *pTrayIcon = (ITrayIcon*)lpVoid;
  351. CPoint pt;
  352. CRect IconRect;
  353. bool bChange = FALSE;
  354. do
  355. {
  356. if ( bChange)
  357. {
  358. pTrayIcon->SetIcon(pTrayIcon->_utIcon[1]);
  359. bChange = FALSE;
  360. }
  361. else
  362. {
  363. pTrayIcon->SetIcon(pTrayIcon->_utIcon[2]);
  364. bChange = TRUE;
  365. }
  366. if( pTrayIcon->bShowMinibox )
  367. {
  368. GetCursorPos(&pt);
  369. pTrayIcon->GetTrayRect(IconRect);
  370. if ( IconRect.PtInRect( pt) )
  371. ::PostMessage(pTrayIcon->m_nid.hWnd,MYWM_SHOWMINBOX,1,0);
  372. else
  373. ::PostMessage(pTrayIcon->m_nid.hWnd,MYWM_SHOWMINBOX,0,0);
  374. }
  375. }while (WaitForSingleObject(pTrayIcon->m_hThreadCtrl,300) == WAIT_TIMEOUT);
  376. return 0;
  377. }