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.

667 lines
18 KiB

  1. #include "stdafx.h"
  2. #include <nt.h>
  3. #include <ntrtl.h>
  4. #include <nturtl.h>
  5. #include <wtsapi32.h>
  6. #include <faxreg.h>
  7. #include "systray.h"
  8. #ifndef FAX_SYS_TRAY_DLL
  9. #define FAX_SYS_TRAY_DLL TEXT("fxsst.dll") // Fax notification bar DLL (loaded by STObject.dll)
  10. #define IS_FAX_MSG_PROC "IsFaxMessage" // Fax message handler (used by GetProcAddress)
  11. typedef BOOL (*PIS_FAX_MSG_PROC)(PMSG); // IsFaxMessage type
  12. #define FAX_MONITOR_SHUTDOWN_PROC "FaxMonitorShutdown"// Fax monitor shutdown (used by GetProcAddress)
  13. typedef BOOL (*PFAX_MONITOR_SHUTDOWN_PROC)(); // FaxMonitorShutdown type
  14. #endif
  15. // Global instance handle of this application.
  16. HINSTANCE g_hInstance;
  17. DWORD g_uiShellHook; //shell hook window message
  18. // Global handle to VxDs
  19. HANDLE g_hPCCARD = INVALID_HANDLE_VALUE;
  20. static UINT g_uEnabledSvcs = 0;
  21. // Context sensitive help array used by the WinHelp engine.
  22. extern const DWORD g_ContextMenuHelpIDs[];
  23. UINT g_msg_winmm_devicechange = 0;
  24. DWORD g_msgTaskbarCreated;
  25. LRESULT CALLBACK SysTrayWndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam);
  26. HMODULE g_hFaxLib = NULL;
  27. PIS_FAX_MSG_PROC g_pIsFaxMessage = NULL;
  28. PFAX_MONITOR_SHUTDOWN_PROC g_pFaxMonitorShutdown = NULL;
  29. /*******************************************************************************
  30. *
  31. * DESCRIPTION:
  32. * Turns the specified service on or off depending upon the value in
  33. * fEnable and writes the new value to the registry.
  34. *
  35. * PARAMETERS:
  36. * (returns), Mask of all currently enabled services.
  37. *
  38. *******************************************************************************/
  39. UINT EnableService(UINT uNewSvcMask, BOOL fEnable)
  40. {
  41. HKEY hk;
  42. UINT CurSvcMask;
  43. DWORD cb;
  44. CurSvcMask = STSERVICE_ALL; // Enable all standard serivces
  45. if (RegCreateKey(HKEY_CURRENT_USER, REGSTR_PATH_SYSTRAY, &hk) == ERROR_SUCCESS)
  46. {
  47. cb = sizeof(CurSvcMask);
  48. RegQueryValueEx(hk, REGSTR_VAL_SYSTRAYSVCS, NULL, NULL, (LPSTR)&CurSvcMask, &cb);
  49. if (uNewSvcMask)
  50. {
  51. if (fEnable)
  52. {
  53. CurSvcMask |= uNewSvcMask;
  54. }
  55. else
  56. {
  57. CurSvcMask &= ~uNewSvcMask;
  58. }
  59. RegSetValueEx(hk, REGSTR_VAL_SYSTRAYSVCS, 0, REG_DWORD, (LPSTR)&CurSvcMask, sizeof(CurSvcMask));
  60. }
  61. RegCloseKey(hk);
  62. }
  63. return(CurSvcMask & STSERVICE_ALL);
  64. }
  65. //
  66. // Closes file handles IFF the global variable != INVALID_HANDLE_VALUE
  67. //
  68. void CloseIfOpen(LPHANDLE lph)
  69. {
  70. if (*lph != INVALID_HANDLE_VALUE)
  71. {
  72. CloseHandle(*lph);
  73. *lph = INVALID_HANDLE_VALUE;
  74. }
  75. }
  76. // From stobject.cpp
  77. void StartNetShell();
  78. void StopNetShell();
  79. // if lpCmdLine contains an integer value then we'll enable that service
  80. STDAPI_(int) SysTrayMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpszCmdLine, int nCmdShow)
  81. {
  82. HWND hExistWnd = FindWindow(SYSTRAY_CLASSNAME, NULL);
  83. UINT iEnableServ = StrToInt(lpszCmdLine);
  84. CoInitializeEx (NULL, COINIT_DISABLE_OLE1DDE | COINIT_APARTMENTTHREADED);
  85. g_hInstance = hInstance;
  86. g_uiShellHook = 0;
  87. g_msg_winmm_devicechange = RegisterWindowMessage(TEXT("winmm_devicechange"));
  88. if (hExistWnd)
  89. {
  90. // NOTE: Send an enable message even if the command line parameter
  91. // is 0 to force us to re-check for all enabled services.
  92. SendMessage(hExistWnd, STWM_ENABLESERVICE, iEnableServ, TRUE);
  93. }
  94. else
  95. {
  96. WNDCLASSEX wc;
  97. // Register a window class for the Battery Meter. This is done so that
  98. // the power control panel applet has the ability to detect us and turn us
  99. // off if we're running.
  100. wc.cbSize = sizeof(wc);
  101. wc.style = CS_GLOBALCLASS;
  102. wc.lpfnWndProc = SysTrayWndProc;
  103. wc.cbClsExtra = 0;
  104. wc.cbWndExtra = DLGWINDOWEXTRA;
  105. wc.hInstance = hInstance;
  106. wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_BATTERYPLUG));
  107. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  108. wc.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
  109. wc.lpszMenuName = NULL;
  110. wc.lpszClassName = SYSTRAY_CLASSNAME;
  111. wc.hIconSm = NULL;
  112. if (RegisterClassEx(&wc))
  113. {
  114. MSG Msg;
  115. // Create the Battery Meter and get this thing going!!!
  116. HWND hWnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_BATTERYMETER), NULL, NULL);
  117. g_msgTaskbarCreated = RegisterWindowMessage(L"TaskbarCreated");
  118. // Ensure we're always running the CSC "service" on Win2000.
  119. // CSC won't work without it.
  120. //
  121. //
  122. // Ensure we're always running the hotplug "service" on Win2000.
  123. //
  124. iEnableServ |= (STSERVICE_CSC | STSERVICE_HOTPLUG);
  125. // create the timer that will delay the startup of the fax code.
  126. SetTimer( hWnd, FAX_STARTUP_TIMER_ID, 20 * 1000, NULL );
  127. // create the timer that will delay the startup of the print tray code.
  128. SetTimer( hWnd, PRINT_STARTUP_TIMER_ID, 20 * 1000, NULL );
  129. //
  130. // This message will initialize all existing services if iEnableServ
  131. // is 0, so it's used to do the general initialization as well as to
  132. // enable a new service via the command line.
  133. //
  134. SendMessage(hWnd, STWM_ENABLESERVICE, iEnableServ, TRUE);
  135. // Whistler runs NETSHELL in the thread of the systray
  136. StartNetShell();
  137. while (GetMessage(&Msg, NULL, 0, 0))
  138. {
  139. if(g_pIsFaxMessage && g_pIsFaxMessage(&Msg))
  140. {
  141. continue;
  142. }
  143. if (!IsDialogMessage(hWnd, &Msg) &&
  144. !CSC_MsgProcess(&Msg))
  145. {
  146. TranslateMessage(&Msg);
  147. DispatchMessage(&Msg);
  148. }
  149. }
  150. // Whistler runs NETSHELL in the thread of the systray
  151. StopNetShell();
  152. }
  153. CloseIfOpen(&g_hPCCARD);
  154. }
  155. CoUninitialize();
  156. return 0;
  157. }
  158. /*******************************************************************************
  159. *
  160. * UpdateServices
  161. *
  162. * DESCRIPTION:
  163. * Enables or disables all services specified by the uEnabled mask.
  164. *
  165. * PARAMETERS:
  166. * (returns), TRUE if any service wants to remain resident.
  167. *
  168. *******************************************************************************/
  169. BOOL UpdateServices(HWND hWnd, UINT uEnabled)
  170. {
  171. BOOL bAnyEnabled = FALSE;
  172. g_uEnabledSvcs = uEnabled;
  173. bAnyEnabled |= CSC_CheckEnable(hWnd, uEnabled & STSERVICE_CSC);
  174. bAnyEnabled |= Power_CheckEnable(hWnd, uEnabled & STSERVICE_POWER);
  175. bAnyEnabled |= HotPlug_CheckEnable(hWnd, uEnabled & STSERVICE_HOTPLUG);
  176. bAnyEnabled |= Volume_CheckEnable(hWnd, uEnabled & STSERVICE_VOLUME);
  177. bAnyEnabled |= USBUI_CheckEnable(hWnd, uEnabled & STSERVICE_USBUI);
  178. //
  179. // now check accessibility features
  180. //
  181. bAnyEnabled |= StickyKeys_CheckEnable(hWnd);
  182. bAnyEnabled |= MouseKeys_CheckEnable(hWnd);
  183. bAnyEnabled |= FilterKeys_CheckEnable(hWnd);
  184. // register to listen for SHChangeNotify events, so if somebody prints a job
  185. // we start the print tray code before the kick off timer.
  186. Print_SHChangeNotify_Register(hWnd);
  187. return(bAnyEnabled);
  188. }
  189. /*******************************************************************************
  190. *
  191. * SysTrayWndProc
  192. *
  193. * DESCRIPTION:
  194. * Callback procedure for the BatteryMeter window.
  195. *
  196. * PARAMETERS:
  197. * hWnd, handle of BatteryMeter window.
  198. * Message,
  199. * wParam,
  200. * lParam,
  201. * (returns),
  202. *
  203. *******************************************************************************/
  204. LRESULT CALLBACK SysTrayWndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)
  205. {
  206. if (g_uiShellHook && Message == g_uiShellHook) // NT5: 406505 shellhook for MouseKeys
  207. {
  208. switch (wParam)
  209. {
  210. case HSHELL_ACCESSIBILITYSTATE:
  211. switch (lParam)
  212. {
  213. case ACCESS_STICKYKEYS:
  214. StickyKeys_CheckEnable(hWnd);
  215. break;
  216. case ACCESS_MOUSEKEYS:
  217. MouseKeys_CheckEnable(hWnd);
  218. break;
  219. // Since we only enable the shellhook when MouseKeys or StickKeys is on, we should only get that msg
  220. // case ACCESS_FILTERKEYS:
  221. // FilterKeys_CheckEnable(hWnd);
  222. // break;
  223. }
  224. }
  225. return 0;
  226. }
  227. if (Message == g_msg_winmm_devicechange)
  228. {
  229. if (g_uEnabledSvcs & STSERVICE_VOLUME)
  230. {
  231. Volume_WinMMDeviceChange(hWnd);
  232. }
  233. return 0;
  234. }
  235. switch (Message)
  236. {
  237. case WM_CREATE:
  238. WTSRegisterSessionNotification(hWnd, NOTIFY_FOR_THIS_SESSION);
  239. break;
  240. case WM_COMMAND:
  241. Power_OnCommand(hWnd, wParam, lParam);
  242. break;
  243. case STWM_NOTIFYPOWER:
  244. Power_Notify(hWnd, wParam, lParam);
  245. break;
  246. case STWM_NOTIFYUSBUI:
  247. USBUI_Notify(hWnd, wParam, lParam);
  248. break;
  249. case STWM_NOTIFYHOTPLUG:
  250. HotPlug_Notify(hWnd, wParam, lParam);
  251. break;
  252. case STWM_NOTIFYSTICKYKEYS:
  253. StickyKeys_Notify(hWnd, wParam, lParam);
  254. break;
  255. case STWM_NOTIFYMOUSEKEYS:
  256. MouseKeys_Notify(hWnd, wParam, lParam);
  257. break;
  258. case STWM_NOTIFYFILTERKEYS:
  259. FilterKeys_Notify(hWnd, wParam, lParam);
  260. break;
  261. case STWM_NOTIFYVOLUME:
  262. Volume_Notify(hWnd, wParam, lParam);
  263. break;
  264. case STWM_ENABLESERVICE:
  265. UpdateServices(hWnd, EnableService((UINT)wParam, (BOOL)lParam));
  266. break;
  267. case STWM_GETSTATE:
  268. return((BOOL)(g_uEnabledSvcs & (UINT)wParam));
  269. case MM_MIXM_CONTROL_CHANGE:
  270. Volume_ControlChange(hWnd, (HMIXER)wParam, (DWORD)lParam);
  271. break;
  272. case MM_MIXM_LINE_CHANGE:
  273. Volume_LineChange(hWnd, (HMIXER)wParam, (DWORD)lParam);
  274. break;
  275. case WM_ACTIVATE:
  276. if (Power_OnActivate(hWnd, wParam, lParam))
  277. {
  278. break;
  279. }
  280. return DefWindowProc(hWnd, Message, wParam, lParam);
  281. case WM_TIMER:
  282. switch (wParam)
  283. {
  284. case VOLUME_TIMER_ID:
  285. Volume_Timer(hWnd);
  286. break;
  287. case POWER_TIMER_ID:
  288. Power_Timer(hWnd);
  289. break;
  290. case HOTPLUG_TIMER_ID:
  291. HotPlug_Timer(hWnd);
  292. break;
  293. case USBUI_TIMER_ID:
  294. USBUI_Timer(hWnd);
  295. break;
  296. case HOTPLUG_DEVICECHANGE_TIMERID:
  297. HotPlug_DeviceChangeTimer(hWnd);
  298. break;
  299. case FAX_STARTUP_TIMER_ID:
  300. KillTimer(hWnd, FAX_STARTUP_TIMER_ID);
  301. if (NULL == g_hFaxLib)
  302. {
  303. g_hFaxLib = LoadLibrary(FAX_SYS_TRAY_DLL);
  304. g_pIsFaxMessage = NULL;
  305. g_pFaxMonitorShutdown = NULL;
  306. if(g_hFaxLib)
  307. {
  308. g_pIsFaxMessage = (PIS_FAX_MSG_PROC)GetProcAddress(g_hFaxLib, IS_FAX_MSG_PROC);
  309. g_pFaxMonitorShutdown = (PFAX_MONITOR_SHUTDOWN_PROC)GetProcAddress(g_hFaxLib, FAX_MONITOR_SHUTDOWN_PROC);
  310. }
  311. }
  312. break;
  313. case PRINT_STARTUP_TIMER_ID:
  314. KillTimer(hWnd, PRINT_STARTUP_TIMER_ID);
  315. Print_TrayInit();
  316. break;
  317. case FAX_SHUTDOWN_TIMER_ID:
  318. {
  319. if (g_hFaxLib)
  320. {
  321. if (g_pFaxMonitorShutdown)
  322. {
  323. g_pFaxMonitorShutdown();
  324. }
  325. FreeLibrary (g_hFaxLib);
  326. g_hFaxLib = NULL;
  327. g_pIsFaxMessage = NULL;
  328. g_pFaxMonitorShutdown = NULL;
  329. }
  330. }
  331. break;
  332. }
  333. break;
  334. //
  335. // Handle SC_CLOSE to hide the window without destroying it. This
  336. // happens when we display the window and the user "closes" it.
  337. // Don't pass SC_CLOSE to DefWindowProc since that causes a
  338. // WM_CLOSE which destroys the window.
  339. //
  340. // Note that CSysTray::DestroySysTrayWindow must send WM_CLOSE
  341. // to destroy the window. It can't use DestroyWindow since it's
  342. // typically on a different thread and DestroyWindow fails.
  343. //
  344. case WM_SYSCOMMAND:
  345. if (SC_CLOSE != (wParam & ~0xf))
  346. return DefWindowProc(hWnd, Message, wParam, lParam);
  347. ShowWindow(hWnd, SW_HIDE);
  348. break;
  349. case WM_POWERBROADCAST:
  350. Power_OnPowerBroadcast(hWnd, wParam, lParam);
  351. Volume_HandlePowerBroadcast(hWnd, wParam, lParam);
  352. break;
  353. case WM_DEVICECHANGE:
  354. Power_OnDeviceChange(hWnd, wParam, lParam);
  355. if (g_uEnabledSvcs & STSERVICE_VOLUME)
  356. {
  357. Volume_DeviceChange(hWnd, wParam, lParam);
  358. }
  359. HotPlug_DeviceChange(hWnd, wParam, lParam);
  360. break;
  361. case WM_ENDSESSION:
  362. if (g_uEnabledSvcs & STSERVICE_VOLUME)
  363. {
  364. Volume_Shutdown(hWnd);
  365. }
  366. break;
  367. case WM_WTSSESSION_CHANGE:
  368. HotPlug_SessionChange(hWnd, wParam, wParam);
  369. break;
  370. case WM_DESTROY:
  371. WTSUnRegisterSessionNotification(hWnd);
  372. UpdateServices(hWnd, 0); // Force all services off
  373. Volume_WmDestroy(hWnd);
  374. Power_WmDestroy(hWnd);
  375. HotPlug_WmDestroy(hWnd);
  376. Print_SHChangeNotify_Unregister();
  377. Print_TrayExit();
  378. if (g_hFaxLib)
  379. {
  380. if (g_pFaxMonitorShutdown)
  381. {
  382. g_pFaxMonitorShutdown();
  383. }
  384. FreeLibrary (g_hFaxLib);
  385. g_hFaxLib = NULL;
  386. g_pIsFaxMessage = NULL;
  387. g_pFaxMonitorShutdown = NULL;
  388. }
  389. PostQuitMessage(0);
  390. break;
  391. case WM_HELP:
  392. WinHelp(((LPHELPINFO)lParam)->hItemHandle, NULL, HELP_WM_HELP,
  393. (ULONG_PTR)(LPSTR)g_ContextMenuHelpIDs);
  394. break;
  395. case WM_CONTEXTMENU:
  396. WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU,
  397. (ULONG_PTR)(LPSTR) g_ContextMenuHelpIDs);
  398. break;
  399. case WM_SYSCOLORCHANGE:
  400. StickyKeys_CheckEnable(hWnd);
  401. FilterKeys_CheckEnable(hWnd);
  402. MouseKeys_CheckEnable(hWnd);
  403. break;
  404. case WM_SETTINGCHANGE:
  405. switch(wParam)
  406. {
  407. case SPI_SETSTICKYKEYS:
  408. StickyKeys_CheckEnable(hWnd);
  409. break;
  410. case SPI_SETFILTERKEYS:
  411. FilterKeys_CheckEnable(hWnd);
  412. break;
  413. case SPI_SETMOUSEKEYS:
  414. MouseKeys_CheckEnable(hWnd);
  415. break;
  416. }
  417. break;
  418. case WM_PRINT_NOTIFY:
  419. Print_Notify(hWnd, Message, wParam, lParam);
  420. break;
  421. default:
  422. //
  423. // if Taskbar Created notification renenable all shell notify icons.
  424. //
  425. if (Message == g_msgTaskbarCreated)
  426. {
  427. UpdateServices(hWnd, EnableService(0, TRUE));
  428. break;
  429. }
  430. return DefWindowProc(hWnd, Message, wParam, lParam);
  431. }
  432. return 0;
  433. }
  434. // Loads the specified string ID and executes it.
  435. void SysTray_RunProperties(UINT RunStringID)
  436. {
  437. LPTSTR pszRunCmd = LoadDynamicString(RunStringID);
  438. if (pszRunCmd)
  439. {
  440. ShellExecute(NULL, TEXT("open"), TEXT("RUNDLL32.EXE"), pszRunCmd, NULL, SW_SHOWNORMAL);
  441. DeleteDynamicString(pszRunCmd);
  442. }
  443. }
  444. /*******************************************************************************
  445. *
  446. * SysTray_NotifyIcon
  447. *
  448. * DESCRIPTION:
  449. *
  450. * PARAMETERS:
  451. * hWnd, handle of BatteryMeter window.
  452. * Message,
  453. * hIcon,
  454. * lpTip,
  455. *
  456. *******************************************************************************/
  457. VOID SysTray_NotifyIcon(HWND hWnd, UINT uCallbackMessage, DWORD Message, HICON hIcon, LPCTSTR lpTip)
  458. {
  459. NOTIFYICONDATA nid = {0};
  460. nid.cbSize = sizeof(nid);
  461. nid.uID = uCallbackMessage;
  462. nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
  463. nid.uCallbackMessage = uCallbackMessage;
  464. nid.hWnd = hWnd;
  465. nid.hIcon = hIcon;
  466. if (lpTip)
  467. {
  468. UINT cch = ARRAYSIZE(nid.szTip);
  469. lstrcpyn(nid.szTip, lpTip, cch);
  470. }
  471. else
  472. {
  473. nid.szTip[0] = 0;
  474. }
  475. Shell_NotifyIcon(Message, &nid);
  476. }
  477. /*******************************************************************************
  478. *
  479. * DESCRIPTION:
  480. * Wrapper for the FormatMessage function that loads a string from our
  481. * resource table into a dynamically allocated buffer, optionally filling
  482. * it with the variable arguments passed.
  483. *
  484. * BE CAREFUL in 16-bit code to pass 32-bit quantities for the variable
  485. * arguments.
  486. *
  487. * PARAMETERS:
  488. * StringID, resource identifier of the string to use.
  489. * (optional), parameters to use to format the string message.
  490. *
  491. *******************************************************************************/
  492. LPTSTR CDECL LoadDynamicString(UINT StringID, ...)
  493. {
  494. TCHAR Buffer[256];
  495. LPTSTR pStr=NULL;
  496. va_list Marker;
  497. // va_start is a macro...it breaks when you use it as an assign
  498. va_start(Marker, StringID);
  499. LoadString(g_hInstance, StringID, Buffer, ARRAYSIZE(Buffer));
  500. FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  501. (void *) (LPTSTR) Buffer, 0, 0, (LPTSTR) (LPTSTR *) &pStr, 0, &Marker);
  502. return pStr;
  503. }
  504. //*****************************************************************************
  505. //
  506. // GenericGetSet
  507. //
  508. // DESCRIPTION:
  509. // Reads or writes a registry key value. The key must already be open.
  510. // The key will be closed after the data is read/written.
  511. //
  512. // PARAMETERS:
  513. // hk - HKEY to open registry key to read/write
  514. // lpszOptVal - value name string pointer
  515. // lpData - pointer to data buffer to read/write
  516. // cbSize - size of data to read/write in bytes
  517. // bSet - FALSE if reading, TRUE if writing
  518. //
  519. // RETURNS:
  520. // TRUE if successful, FALSE if not.
  521. //
  522. // NOTE:
  523. // Assumes data is of type REG_BINARY or REG_DWORD when bSet = TRUE!
  524. //
  525. //*****************************************************************************
  526. BOOL GenericGetSet(HKEY hk, LPCTSTR lpszOptVal, void * lpData, ULONG cbSize, BOOL bSet)
  527. {
  528. DWORD rr;
  529. if (bSet)
  530. rr = RegSetValueEx(hk, lpszOptVal, 0, (cbSize == sizeof(DWORD)) ? REG_DWORD : REG_BINARY,
  531. lpData, cbSize);
  532. else
  533. rr = RegQueryValueEx(hk, lpszOptVal, NULL, NULL, lpData, &cbSize);
  534. RegCloseKey(hk);
  535. return rr == ERROR_SUCCESS;
  536. }
  537. VOID SetIconFocus(HWND hwnd, UINT uiIcon)
  538. {
  539. NOTIFYICONDATA nid = {0};
  540. nid.cbSize = sizeof(NOTIFYICONDATA);
  541. nid.hWnd = hwnd;
  542. nid.uID = uiIcon;
  543. Shell_NotifyIcon(NIM_SETFOCUS, &nid);
  544. }