Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

346 lines
9.5 KiB

  1. // File: taskbar.cpp
  2. #include "precomp.h"
  3. #include "taskbar.h"
  4. #include <iappldr.h>
  5. #include <tsecctrl.h>
  6. static HWND g_hwndHidden = NULL;
  7. const TCHAR g_cszHiddenWndClassName[] = _TEXT("MnmSrvcHiddenWindow");
  8. BOOL g_fTaskBarIconAdded = FALSE;
  9. BOOL g_fTimerRunning = FALSE;
  10. extern INmSysInfo2 * g_pNmSysInfo;
  11. extern int g_cPersonsInConf;
  12. // This routine starts a timer to periodically retry adding the taskbar icon.
  13. // This is necessary in case the taskbar is not showing at the time the
  14. // service is launched, or the taskbar is destroyed by a logoff-logon sequence.
  15. VOID StartTaskbarTimer(VOID)
  16. {
  17. if ( !g_fTimerRunning)
  18. {
  19. ASSERT(g_hwndHidden);
  20. SetTimer(g_hwndHidden, 0, 5000, NULL);
  21. g_fTimerRunning = TRUE;
  22. }
  23. }
  24. VOID KillTaskbarTimer(VOID)
  25. {
  26. if ( g_fTimerRunning )
  27. {
  28. KillTimer ( g_hwndHidden, 0 );
  29. g_fTimerRunning = FALSE;
  30. }
  31. }
  32. LRESULT CALLBACK HiddenWndProc( HWND hwnd, UINT uMsg,
  33. WPARAM wParam, LPARAM lParam)
  34. {
  35. switch(uMsg)
  36. {
  37. case WM_USERCHANGED:
  38. case WM_ENDSESSION:
  39. // A user is logging on or off... We don't know which but
  40. // since the desktop is changing we assume our taskbar icon
  41. // is toast. Start a timer to periodically try to add it back
  42. // until it succeeds.
  43. g_fTaskBarIconAdded = FALSE;
  44. StartTaskbarTimer();
  45. break;
  46. case WM_TASKBAR_NOTIFY:
  47. {
  48. if (WM_RBUTTONUP == lParam)
  49. {
  50. ::OnRightClickTaskbar();
  51. }
  52. break;
  53. }
  54. case WM_TIMER:
  55. AddTaskbarIcon();
  56. break;
  57. case WM_DESTROY:
  58. {
  59. // NULL the global variable:
  60. g_hwndHidden = NULL;
  61. return 0;
  62. }
  63. default:
  64. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  65. }
  66. return FALSE;
  67. }
  68. BOOL CmdActivate(VOID)
  69. {
  70. RegEntry Re( REMOTECONTROL_KEY, HKEY_LOCAL_MACHINE );
  71. Re.SetValue ( REMOTE_REG_ACTIVATESERVICE, (DWORD)1 );
  72. if (MNMServiceActivate())
  73. {
  74. ReportStatusToSCMgr( SERVICE_RUNNING, NO_ERROR, 0);
  75. return TRUE;
  76. }
  77. else
  78. {
  79. return FALSE;
  80. }
  81. }
  82. VOID CmdInActivate(VOID)
  83. {
  84. RegEntry Re( REMOTECONTROL_KEY, HKEY_LOCAL_MACHINE );
  85. Re.SetValue ( REMOTE_REG_ACTIVATESERVICE, (DWORD)0 );
  86. if (MNMServiceDeActivate())
  87. ReportStatusToSCMgr( SERVICE_PAUSED, NO_ERROR, 0);
  88. }
  89. VOID CmdSendFiles(VOID)
  90. {
  91. ASSERT(g_pNmSysInfo);
  92. if (g_pNmSysInfo)
  93. {
  94. g_pNmSysInfo->ProcessSecurityData(LOADFTAPPLET, 0, 0, NULL);
  95. }
  96. }
  97. VOID CmdShutdown(VOID)
  98. {
  99. if (STATE_ACTIVE == g_dwActiveState)
  100. {
  101. CmdInActivate();
  102. }
  103. MNMServiceStop();
  104. DestroyWindow(g_hwndHidden);
  105. }
  106. BOOL AddTaskbarIcon(VOID)
  107. {
  108. BOOL bRet = FALSE;
  109. if ( NULL == g_hwndHidden )
  110. {
  111. // Register hidden window class:
  112. WNDCLASS wcHidden =
  113. {
  114. 0L,
  115. HiddenWndProc,
  116. 0,
  117. 0,
  118. GetModuleHandle(NULL),
  119. NULL,
  120. NULL,
  121. NULL,
  122. NULL,
  123. g_cszHiddenWndClassName
  124. };
  125. if (!RegisterClass(&wcHidden))
  126. {
  127. ERROR_OUT(("Could not register hidden wnd classes"));
  128. return FALSE;
  129. }
  130. // Create a hidden window for event processing:
  131. g_hwndHidden = ::CreateWindow( g_cszHiddenWndClassName,
  132. _TEXT(""),
  133. WS_POPUP, // not visible!
  134. 0, 0, 0, 0,
  135. NULL,
  136. NULL,
  137. GetModuleHandle(NULL),
  138. NULL);
  139. }
  140. if (NULL == g_hwndHidden)
  141. {
  142. ERROR_OUT(("Could not create hidden windows"));
  143. return FALSE;
  144. }
  145. // Place a 16x16 icon in the taskbar notification area:
  146. NOTIFYICONDATA tnid;
  147. tnid.cbSize = sizeof(NOTIFYICONDATA);
  148. tnid.hWnd = g_hwndHidden;
  149. tnid.uID = ID_TASKBAR_ICON;
  150. tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
  151. tnid.uCallbackMessage = WM_TASKBAR_NOTIFY;
  152. tnid.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_SM_WORLD));
  153. ::LoadString(GetModuleHandle(NULL), IDS_MNMSRVC_TITLE,
  154. tnid.szTip, CCHMAX(tnid.szTip));
  155. // Attempt to add the icon. This may fail because there is no taskbar
  156. // (no user desktop shown). Warn if this is so... We will retry on
  157. // a periodic timer.
  158. if (FALSE == (bRet = Shell_NotifyIcon(NIM_ADD, &tnid)))
  159. {
  160. #ifdef DEBUG
  161. if ( !g_fTimerRunning )
  162. WARNING_OUT(("Could not add notify icon!"));
  163. #endif // DEBUG
  164. // Start the taskbar timer to periodically retry until this succeeds
  165. StartTaskbarTimer();
  166. }
  167. else
  168. {
  169. g_fTaskBarIconAdded = TRUE;
  170. KillTaskbarTimer(); // Kill timer if necessary
  171. }
  172. if (NULL != tnid.hIcon)
  173. {
  174. DestroyIcon(tnid.hIcon);
  175. }
  176. return bRet;
  177. }
  178. BOOL RemoveTaskbarIcon(VOID)
  179. {
  180. NOTIFYICONDATA tnid;
  181. BOOL ret;
  182. if ( !g_fTaskBarIconAdded || NULL == g_hwndHidden )
  183. {
  184. return FALSE;
  185. }
  186. tnid.cbSize = sizeof(NOTIFYICONDATA);
  187. tnid.hWnd = g_hwndHidden;
  188. tnid.uID = ID_TASKBAR_ICON;
  189. ret = Shell_NotifyIcon(NIM_DELETE, &tnid);
  190. g_fTaskBarIconAdded = FALSE;
  191. return ret;
  192. }
  193. BOOL OnRightClickTaskbar()
  194. {
  195. TRACE_OUT(("OnRightClickTaskbar called"));
  196. POINT ptClick;
  197. if (FALSE == ::GetCursorPos(&ptClick))
  198. {
  199. ptClick.x = ptClick.y = 0;
  200. }
  201. // Get the menu for the popup from the resource file.
  202. HMENU hMenu = ::LoadMenu(GetModuleHandle(NULL), MAKEINTRESOURCE(IDR_TASKBAR_POPUP));
  203. if (NULL == hMenu)
  204. {
  205. return FALSE;
  206. }
  207. // Get the first menu in it which we will use for the call to
  208. // TrackPopup(). This could also have been created on the fly using
  209. // CreatePopupMenu and then we could have used InsertMenu() or
  210. // AppendMenu.
  211. HMENU hMenuTrackPopup = ::GetSubMenu(hMenu, 0);
  212. RegEntry reLM( REMOTECONTROL_KEY, HKEY_LOCAL_MACHINE);
  213. BOOL fNoExit = reLM.GetNumber(REMOTE_REG_NOEXIT, DEFAULT_REMOTE_NOEXIT);
  214. ::EnableMenuItem(hMenuTrackPopup, IDM_TBPOPUP_STOP, fNoExit ? MF_GRAYED : MF_ENABLED);
  215. if (STATE_ACTIVE == g_dwActiveState)
  216. {
  217. ::EnableMenuItem(hMenuTrackPopup, IDM_TBPOPUP_INACTIVATE, fNoExit ? MF_GRAYED : MF_ENABLED);
  218. ::EnableMenuItem(hMenuTrackPopup, IDM_TBPOPUP_SENDFILES, (2 == g_cPersonsInConf) ? MF_ENABLED : MF_GRAYED);
  219. }
  220. else if (STATE_INACTIVE == g_dwActiveState)
  221. {
  222. HANDLE hInit = ::OpenEvent(EVENT_ALL_ACCESS, FALSE, _TEXT("CONF:Init"));
  223. ::EnableMenuItem(hMenuTrackPopup, IDM_TBPOPUP_ACTIVATE, hInit ?
  224. MF_GRAYED : MF_ENABLED);
  225. ::CloseHandle(hInit);
  226. }
  227. else
  228. {
  229. // Leave all menus grayed
  230. }
  231. // Draw and track the "floating" popup
  232. // According to the font view code, there is a bug in USER which causes
  233. // TrackPopupMenu to work incorrectly when the window doesn't have the
  234. // focus. The work-around is to temporarily create a hidden window and
  235. // make it the foreground and focus window.
  236. HWND hwndDummy = ::CreateWindow(_TEXT("STATIC"), NULL, 0,
  237. ptClick.x,
  238. ptClick.y,
  239. 1, 1, HWND_DESKTOP,
  240. NULL, GetModuleHandle(NULL), NULL);
  241. if (NULL != hwndDummy)
  242. {
  243. HWND hwndPrev = ::GetForegroundWindow(); // to restore
  244. TPMPARAMS tpmp;
  245. tpmp.cbSize = sizeof(tpmp);
  246. tpmp.rcExclude.right = 1 + (tpmp.rcExclude.left = ptClick.x);
  247. tpmp.rcExclude.bottom = 1 + (tpmp.rcExclude.top = ptClick.y);
  248. ::SetForegroundWindow(hwndDummy);
  249. ::SetFocus(hwndDummy);
  250. int iRet = ::TrackPopupMenuEx( hMenuTrackPopup,
  251. TPM_RETURNCMD | TPM_HORIZONTAL | TPM_RIGHTALIGN |
  252. TPM_RIGHTBUTTON | TPM_LEFTBUTTON,
  253. ptClick.x,
  254. ptClick.y,
  255. hwndDummy,
  256. &tpmp);
  257. // Restore the previous foreground window (before destroying hwndDummy).
  258. if (hwndPrev)
  259. {
  260. ::SetForegroundWindow(hwndPrev);
  261. }
  262. ::DestroyWindow(hwndDummy);
  263. switch (iRet)
  264. {
  265. case IDM_TBPOPUP_ACTIVATE:
  266. {
  267. CmdActivate();
  268. break;
  269. }
  270. case IDM_TBPOPUP_INACTIVATE:
  271. {
  272. CmdInActivate();
  273. break;
  274. }
  275. case IDM_TBPOPUP_SENDFILES:
  276. {
  277. CmdSendFiles();
  278. break;
  279. }
  280. case IDM_TBPOPUP_STOP:
  281. {
  282. CmdShutdown();
  283. break;
  284. }
  285. default:
  286. break;
  287. }
  288. }
  289. // We are finished with the menu now, so destroy it
  290. ::RemoveMenu(hMenu, 0, MF_BYPOSITION);
  291. ::DestroyMenu(hMenuTrackPopup);
  292. ::DestroyMenu(hMenu);
  293. return TRUE;
  294. }