Leaked source code of windows server 2003
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.

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