ItrayIcon.cpp 11 KB

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