TrayIcon.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  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::SetTipTitle(LPCTSTR lpTipTitle)
  136. {
  137. UINT msg;
  138. m_nid.uFlags = 0;
  139. if (m_nid.hIcon == NULL)
  140. return TRUE; // already deleted
  141. msg = NIM_MODIFY;
  142. StringCchCopy(m_nid.szInfo, sizeof(m_nid.szInfo), _lpTip);
  143. if ( lpTipTitle != NULL)
  144. {
  145. StringCchCopy(m_nid.szInfoTitle, sizeof(m_nid.szInfoTitle), lpTipTitle);
  146. m_nid.uFlags |= NIF_INFO|NIIF_INFO;
  147. m_nid.uTimeout = 1000;
  148. }
  149. else
  150. {
  151. m_nid.uFlags |= NIF_INFO;
  152. }
  153. // Use callback if any
  154. if (m_nid.uCallbackMessage && m_nid.hWnd)
  155. m_nid.uFlags |= NIF_MESSAGE;
  156. return Shell_NotifyIcon(msg, &m_nid);
  157. }
  158. //BOOL ITrayIcon::SetInfo(LPCSTR lpInof, LPCSTR lpInfoTitle)
  159. BOOL ITrayIcon::SetInfo(LPCTSTR lpInof, LPCTSTR lpInfoTitle)
  160. {
  161. UINT msg;
  162. m_nid.uFlags = 0;
  163. if (m_nid.hIcon == NULL)
  164. return TRUE; // already deleted
  165. msg = NIM_MODIFY;
  166. //strncpy(m_nid.szInfo, lpInof, sizeof(m_nid.szInfo));
  167. StringCchCopy(m_nid.szInfo, sizeof(m_nid.szInfo),lpInof);
  168. if ( lpInfoTitle != NULL)
  169. {
  170. StringCchCopy(m_nid.szInfoTitle, sizeof(m_nid.szInfoTitle), lpInfoTitle);
  171. m_nid.uFlags |= NIF_INFO|NIIF_INFO;
  172. m_nid.uTimeout = 1000;
  173. }
  174. else
  175. {
  176. m_nid.uFlags |= NIF_INFO;
  177. }
  178. // Use callback if any
  179. if (m_nid.uCallbackMessage && m_nid.hWnd)
  180. m_nid.uFlags |= NIF_MESSAGE;
  181. return Shell_NotifyIcon(msg, &m_nid);
  182. }
  183. /////////////////
  184. // Default event handler handles right-menu and doubleclick.
  185. // Call this function from your own notification handler.
  186. //
  187. LRESULT ITrayIcon::OnTrayNotification(WPARAM wID, LPARAM lEvent)
  188. {
  189. if (wID!=m_nid.uID || (lEvent!=WM_RBUTTONUP && lEvent!=WM_LBUTTONDBLCLK))
  190. return 0;
  191. // If there's a resource menu with the same ID as the icon, use it as
  192. // the right-button popup menu. CTrayIcon will interprets the first
  193. // item in the menu as the default command for WM_LBUTTONDBLCLK
  194. //
  195. #if 0
  196. CMenu menu;
  197. if (!menu.LoadMenu(m_nid.uID))
  198. return 0;
  199. CMenu* pSubMenu = menu.GetSubMenu(0);
  200. if (!pSubMenu)
  201. return 0;
  202. if (lEvent==WM_RBUTTONUP)
  203. {
  204. // Make first menu item the default (bold font)
  205. ::SetMenuDefaultItem(pSubMenu->m_hMenu, 0, TRUE);
  206. // Display the menu at the current mouse location. There's a "bug"
  207. // (Microsoft calls it a feature) in Windows 95 that requires calling
  208. // SetForegroundWindow. To find out more, search for Q135788 in MSDN.
  209. //
  210. CPoint mouse;
  211. GetCursorPos(&mouse);
  212. ::SetForegroundWindow(m_nid.hWnd);
  213. ::TrackPopupMenu(pSubMenu->m_hMenu, 0, mouse.x, mouse.y, 0,
  214. m_nid.hWnd, NULL);
  215. } else // double click: execute first menu item
  216. ::SendMessage(m_nid.hWnd, WM_COMMAND, pSubMenu->GetMenuItemID(0), 0);
  217. #endif
  218. return 1; // handled
  219. }
  220. // ------------------------------- [5/30/2013 Z.t]
  221. BOOL ITrayIcon::IsWow64()
  222. {
  223. BOOL bIsWow64 = FALSE;
  224. LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(_T("kernel32")),"IsWow64Process");
  225. if (NULL != fnIsWow64Process)
  226. {
  227. if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
  228. {
  229. // handle error
  230. }
  231. }
  232. return bIsWow64;
  233. }
  234. /************************************************************************/
  235. /*
  236. 函数:GetTrayRect,获取托盘图标区域;(有待完善,添加各种错误判断)
  237. 参数:None;
  238. 返回:返回指定托盘图标的区域;
  239. 注意:函数的功能有些太复杂,暂时没办法使用更简单的方法获取图标区域;
  240. */
  241. /************************************************************************/
  242. void ITrayIcon::GetTrayRect(RECT &rc)
  243. {
  244. HWND hWnd,hWndPaper;
  245. long ret;
  246. LPVOID lngAddress;
  247. // long lngTextAdr; //,lngHwndAdr,lngHwnd,lngButtonID;
  248. TCHAR strBuff[1024]={0};
  249. TBBUTTON btnData={0};
  250. hWnd = FindWindow(_T("Shell_TrayWnd"), NULL); // 获取任务栏句柄 [5/31/2013 Z.t]
  251. hWnd = FindWindowEx(hWnd, 0, _T("TrayNotifyWnd"), NULL); // 获取托盘区域句柄 [5/31/2013 Z.t]
  252. hWndPaper = FindWindowEx(hWnd, 0, _T("SysPager"), NULL); // 获取系统页句柄 [5/31/2013 Z.t]
  253. if(!hWndPaper)
  254. hWnd = FindWindowEx(hWnd, 0, _T("ToolbarWindow32"), NULL);
  255. else
  256. hWnd = FindWindowEx(hWndPaper, 0, _T("ToolbarWindow32"), NULL);
  257. DWORD dwProcessId = 0;
  258. GetWindowThreadProcessId(hWnd, &dwProcessId);//LOG4C_NO_FILENUM((LOG_NOTICE,"进程ID%d",dwProcessId));进程其实就是explorer.exe
  259. HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS|PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE,0,dwProcessId);
  260. if ( hProcess == NULL )
  261. {
  262. //LOG4C_NO_FILENUM((LOG_NOTICE,"hProcess == NULL--"));
  263. return ;
  264. }
  265. lngAddress = VirtualAllocEx(hProcess,0, 0x4096, MEM_COMMIT, PAGE_READWRITE);
  266. if( lngAddress == NULL)
  267. {
  268. //LOG4C_NO_FILENUM((LOG_NOTICE,"lngAddress == NULL--"));
  269. return;
  270. }
  271. DWORD lTextAdr = 0;
  272. BYTE buff[1024] = {0};
  273. CString strFilePath;
  274. CString strTile;
  275. HWND hMainWnd = NULL;
  276. int nDataOffset = sizeof(TBBUTTON) - sizeof(INT_PTR) - sizeof(DWORD_PTR);
  277. int nStrOffset = 18;
  278. if ( IsWow64() )
  279. {
  280. nDataOffset+=4;
  281. nStrOffset+=6;
  282. }
  283. // 获取托盘区域的所有图标数量 [5/31/2013 Z.t]
  284. int ibtnCount = SendMessage(hWnd, TB_BUTTONCOUNT, 0, 0);
  285. LPVOID lngRect = VirtualAllocEx(hProcess,0,sizeof(RECT), MEM_COMMIT, PAGE_READWRITE);
  286. CRect rect;
  287. for(int i=0 ;i< ibtnCount;i++)
  288. {
  289. int j = i;
  290. ret = SendMessage(hWnd,TB_GETBUTTON,j, (LPARAM)(lngAddress));
  291. // 读文本地址;
  292. ret = ReadProcessMemory(hProcess, LPVOID(long(lngAddress) + nDataOffset),&lTextAdr,4,0);
  293. if(lTextAdr != -1)
  294. {
  295. // 读文本;
  296. ret = ReadProcessMemory(hProcess, LPVOID(lTextAdr),buff,1024,0);
  297. hMainWnd = (HWND)(*((DWORD*)buff));
  298. strFilePath = (WCHAR *)buff + nStrOffset; // 获取托盘图标进程路径 [5/31/2013 Z.t]
  299. strTile = (WCHAR *)buff + nStrOffset + MAX_PATH; // 获取托盘图标tip标题 [5/31/2013 Z.t]
  300. //_tprintf(_T("%s %s\n"),strTile,strFilePath);
  301. if (strTile.Compare(m_nid.szTip) == 0)
  302. {
  303. ::SendMessage(hWnd,TB_GETITEMRECT,(WPARAM)j,(LPARAM)lngRect);
  304. ReadProcessMemory(hProcess,lngRect,&rc, sizeof(rc),0); // 获取托盘图标区域;
  305. CWnd::FromHandle(hWnd)->ClientToScreen(&rc);
  306. }
  307. }
  308. }
  309. VirtualFreeEx( hProcess, lngAddress, 0x4096, MEM_DECOMMIT);
  310. VirtualFreeEx( hProcess, lngAddress, 0, MEM_RELEASE);
  311. VirtualFreeEx( hProcess, lngRect, sizeof(RECT), MEM_DECOMMIT);
  312. VirtualFreeEx( hProcess, lngRect, 0, MEM_RELEASE);
  313. CloseHandle(hProcess);
  314. }
  315. int ITrayIcon::OpendThread()
  316. {
  317. //LOG4C_NO_FILENUM((LOG_NOTICE,"创建TrayIcon"));
  318. m_hThreadCtrl = CreateEvent(NULL,TRUE,FALSE,NULL); // 无信号事件;
  319. if ( m_hThreadCtrl == NULL )
  320. {
  321. //LOG4C_NO_FILENUM((LOG_NOTICE,"创建TrayIcon事件失败"));
  322. return -1;
  323. }
  324. m_hThreadObj = CreateThread(NULL,0,FlashingThread,this,CREATE_SUSPENDED,&m_dwThreadID);
  325. if ( m_hThreadObj == NULL )
  326. {
  327. //LOG4C_NO_FILENUM((LOG_NOTICE,"创建TrayIcon线程失败"));
  328. return -1;
  329. }
  330. bSuspending = true;
  331. return 0;
  332. }
  333. void ITrayIcon::TerminalThread()
  334. {
  335. if ( m_hThreadCtrl )
  336. {
  337. SetEvent( m_hThreadCtrl );
  338. }
  339. if (WaitForSingleObject(m_hThreadCtrl,INFINITE) != WAIT_TIMEOUT)
  340. {
  341. CloseHandle(m_hThreadObj);
  342. m_hThreadObj = NULL;
  343. }
  344. CloseHandle( m_hThreadCtrl );
  345. m_hThreadCtrl = NULL;
  346. bSuspending = false;
  347. }
  348. BOOL ITrayIcon::StartFlashing()
  349. {
  350. if ( !bSuspending ) return FALSE;
  351. if(::ResumeThread(m_hThreadObj) == 0xFFFFFFFF)
  352. return FALSE;
  353. bSuspending = false;
  354. SetInfo(_T("环境监控系统产生新警报,请及时处理!"),_T("警报提示"));
  355. return TRUE;
  356. }
  357. BOOL ITrayIcon::StopFlashing()
  358. {
  359. if ( bSuspending ) return FALSE;
  360. if(::SuspendThread(m_hThreadObj) == 0xFFFFFFFF)
  361. return FALSE;
  362. bSuspending = true;
  363. SetIcon(_utIcon[0]);
  364. return TRUE;
  365. }
  366. /************************************************************************/
  367. /*
  368. 线程函数:闪烁线程;
  369. */
  370. /************************************************************************/
  371. DWORD WINAPI ITrayIcon::FlashingThread(LPVOID lpVoid)
  372. {
  373. ITrayIcon *pTrayIcon = (ITrayIcon*)lpVoid;
  374. CPoint pt;
  375. CRect IconRect;
  376. bool bChange = FALSE;
  377. do
  378. {
  379. if ( bChange)
  380. {
  381. pTrayIcon->SetIcon(pTrayIcon->_utIcon[1]);
  382. bChange = FALSE;
  383. }
  384. else
  385. {
  386. pTrayIcon->SetIcon(pTrayIcon->_utIcon[2]);
  387. bChange = TRUE;
  388. }
  389. if( pTrayIcon->bShowMinibox )
  390. {
  391. GetCursorPos(&pt);
  392. pTrayIcon->GetTrayRect(IconRect);
  393. if ( IconRect.PtInRect( pt) )
  394. ::PostMessage(pTrayIcon->m_nid.hWnd,MYWM_SHOWMINBOX,1,0);
  395. else
  396. ::PostMessage(pTrayIcon->m_nid.hWnd,MYWM_SHOWMINBOX,0,0);
  397. }
  398. }while (WaitForSingleObject(pTrayIcon->m_hThreadCtrl,300) == WAIT_TIMEOUT);
  399. return 0;
  400. }