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.

9279 lines
265 KiB

  1. #include "cabinet.h"
  2. #include <wtsapi32.h> // for NOTIFY_FOR_THIS_SESSION
  3. #include <winsta.h> // for disconnect and reconnect messages from terminal server
  4. #include "mmsysp.h"
  5. #include "rcids.h"
  6. #include "dlg.h"
  7. #include <atlstuff.h>
  8. #include <shlapip.h>
  9. #include "trayclok.h"
  10. #include <help.h> // help ids
  11. #include <desktray.h>
  12. #include "util.h"
  13. #include "tray.h"
  14. #if defined(FE_IME)
  15. #include <immp.h>
  16. #endif
  17. #include <regstr.h>
  18. #include "bandsite.h"
  19. #include "startmnu.h"
  20. #include "uemapp.h"
  21. #include <uxthemep.h>
  22. #define NO_NOTIFYSUBCLASSWNDPROC
  23. #include "cwndproc.cpp"
  24. #include "desktop2.h"
  25. #include "mixer.h"
  26. #include "winbrand.h"
  27. #define DM_FOCUS 0 // focus
  28. #define DM_SHUTDOWN TF_TRAY // shutdown
  29. #define DM_UEMTRACE TF_TRAY // timer service, other UEM stuff
  30. #define DM_MISC 0 // miscellany
  31. const GUID CLSID_MSUTBDeskBand = {0x540d8a8b, 0x1c3f, 0x4e32, 0x81, 0x32, 0x53, 0x0f, 0x6a, 0x50, 0x20, 0x90};
  32. // From Desktop2\proglist.cpp
  33. HRESULT AddMenuItemsCacheTask(IShellTaskScheduler* pSystemScheduler, BOOL fKeepCacheWhenFinished);
  34. // import the WIN31 Compatibility HACKs from the shell32.dll
  35. STDAPI_(void) CheckWinIniForAssocs(void);
  36. // hooks to Shell32.dll
  37. STDAPI CheckDiskSpace();
  38. STDAPI CheckStagingArea();
  39. // startmnu.cpp
  40. void HandleFirstTime();
  41. HWND v_hwndDesktop = NULL;
  42. HWND v_hwndTray = NULL;
  43. HWND v_hwndStartPane = NULL;
  44. BOOL g_fDesktopRaised = FALSE;
  45. BOOL g_fInSizeMove = FALSE;
  46. UINT _uMsgEnableUserTrackedBalloonTips = 0;
  47. void ClearRecentDocumentsAndMRUStuff(BOOL fBroadcastChange);
  48. void DoTaskBarProperties(HWND hwnd, DWORD dwFlags);
  49. void ClassFactory_Start();
  50. void ClassFactory_Stop();
  51. //
  52. // Settings UI entry point types.
  53. //
  54. typedef void (WINAPI *PTRAYPROPSHEETCALLBACK)(DWORD nStartPage);
  55. typedef void (WINAPI *PSETTINGSUIENTRY)(PTRAYPROPSHEETCALLBACK);
  56. // Shell perf automation
  57. extern DWORD g_dwShellStartTime;
  58. extern DWORD g_dwShellStopTime;
  59. extern DWORD g_dwStopWatchMode;
  60. CTray c_tray;
  61. // from explorer\desktop2
  62. STDAPI DesktopV2_Create(
  63. IMenuPopup **ppmp, IMenuBand **ppmb, void **ppvStartPane);
  64. STDAPI DesktopV2_Build(void *pvStartPane);
  65. // dyna-res change for multi-config hot/warm-doc
  66. void HandleDisplayChange(int x, int y, BOOL fCritical);
  67. DWORD GetMinDisplayRes(void);
  68. // timer IDs
  69. #define IDT_AUTOHIDE 2
  70. #define IDT_AUTOUNHIDE 3
  71. #ifdef DELAYWININICHANGE
  72. #define IDT_DELAYWININICHANGE 5
  73. #endif
  74. #define IDT_DESKTOP 6
  75. #define IDT_PROGRAMS IDM_PROGRAMS
  76. #define IDT_RECENT IDM_RECENT
  77. #define IDT_REBUILDMENU 7
  78. #define IDT_HANDLEDELAYBOOTSTUFF 8
  79. #define IDT_REVERTPROGRAMS 9
  80. #define IDT_REVERTRECENT 10
  81. #define IDT_REVERTFAVORITES 11
  82. #define IDT_STARTMENU 12
  83. #define IDT_ENDUNHIDEONTRAYNOTIFY 13
  84. #define IDT_SERVICE0 14
  85. #define IDT_SERVICE1 15
  86. #define IDT_SERVICELAST IDT_SERVICE1
  87. #define IDT_SAVESETTINGS 17
  88. #define IDT_ENABLEUNDO 18
  89. #define IDT_STARTUPFAILED 19
  90. #define IDT_CHECKDISKSPACE 21
  91. #define IDT_STARTBUTTONBALLOON 22
  92. #define IDT_CHANGENOTIFY 23
  93. #define IDT_COFREEUNUSED 24
  94. #define IDT_DESKTOPCLEANUP 25
  95. #define FADEINDELAY 100
  96. #define BALLOONTIPDELAY 10000 // default balloon time copied from traynot.cpp
  97. // INSTRUMENTATION WARNING: If you change anything here, make sure to update instrument.c
  98. // we need to start at 500 because we're now sharing the hotkey handler
  99. // with shortcuts.. they use an index array so they need to be 0 based
  100. // NOTE, this constant is also in desktop.cpp, so that we can forward hotkeys from the desktop for
  101. // NOTE, app compatibility.
  102. #define GHID_FIRST 500
  103. enum
  104. {
  105. GHID_RUN = GHID_FIRST,
  106. GHID_MINIMIZEALL,
  107. GHID_UNMINIMIZEALL,
  108. GHID_HELP,
  109. GHID_EXPLORER,
  110. GHID_FINDFILES,
  111. GHID_FINDCOMPUTER,
  112. GHID_TASKTAB,
  113. GHID_TASKSHIFTTAB,
  114. GHID_SYSPROPERTIES,
  115. GHID_DESKTOP,
  116. GHID_TRAYNOTIFY,
  117. GHID_MAX
  118. };
  119. const DWORD GlobalKeylist[] =
  120. {
  121. MAKELONG(TEXT('R'), MOD_WIN),
  122. MAKELONG(TEXT('M'), MOD_WIN),
  123. MAKELONG(TEXT('M'), MOD_SHIFT|MOD_WIN),
  124. MAKELONG(VK_F1,MOD_WIN),
  125. MAKELONG(TEXT('E'),MOD_WIN),
  126. MAKELONG(TEXT('F'),MOD_WIN),
  127. MAKELONG(TEXT('F'), MOD_CONTROL|MOD_WIN),
  128. MAKELONG(VK_TAB, MOD_WIN),
  129. MAKELONG(VK_TAB, MOD_WIN|MOD_SHIFT),
  130. MAKELONG(VK_PAUSE,MOD_WIN),
  131. MAKELONG(TEXT('D'),MOD_WIN),
  132. MAKELONG(TEXT('B'),MOD_WIN),
  133. };
  134. CTray::CTray() : _fCanSizeMove(TRUE), _fIsLogoff(FALSE), _fIsDesktopConnected(TRUE), _fBandSiteInitialized(FALSE)
  135. {
  136. }
  137. void CTray::ClosePopupMenus()
  138. {
  139. if (_pmpStartMenu)
  140. _pmpStartMenu->OnSelect(MPOS_FULLCANCEL);
  141. if (_pmpStartPane)
  142. _pmpStartPane->OnSelect(MPOS_FULLCANCEL);
  143. }
  144. BOOL Tray_StartPanelEnabled()
  145. {
  146. SHELLSTATE ss = {0};
  147. SHGetSetSettings(&ss, SSF_STARTPANELON, FALSE);
  148. return ss.fStartPanelOn;
  149. }
  150. #ifdef FEATURE_STARTPAGE
  151. BOOL Tray_ShowStartPageEnabled()
  152. {
  153. #if 0
  154. SHELLSTATE ss = {0};
  155. SHGetSetSettings(&ss, SSF_SHOWSTARTPAGE, FALSE);
  156. return ss.fShowStartPage;
  157. #endif
  158. static BOOL s_fEnabled = -1;
  159. if (s_fEnabled == -1)
  160. {
  161. DWORD dwType = REG_DWORD;
  162. DWORD dwData;
  163. DWORD cbData = sizeof(DWORD);
  164. DWORD dwDefault = 0;
  165. // FaultID is a decoy so that hackers won't think of trying to enable this feature.
  166. LONG lRet = SHRegGetUSValue(REGSTR_PATH_EXPLORER, TEXT("FaultID"), &dwType, &dwData, &cbData, FALSE, &dwDefault, sizeof(dwDefault));
  167. if (lRet == ERROR_SUCCESS && dwData == 101) // Some random value not easily guessed
  168. s_fEnabled = TRUE;
  169. else
  170. s_fEnabled = FALSE;
  171. }
  172. return s_fEnabled;
  173. }
  174. #endif
  175. //
  176. // The StartButtonBalloonTip registry value can have one of these values:
  177. //
  178. // 0 (or nonexistent): User has never clicked the Start Button.
  179. // 1: User has clicked the Start Button on a pre-Whistler system.
  180. // 2: User has clicked the Start Button on a Whistler system.
  181. //
  182. // In case 0, we always want to show the balloon tip regardless of whether
  183. // the user is running Classic or Personal.
  184. //
  185. // In case 1, we want to show the balloon tip if the user is using the
  186. // Personal Start Menu, but not if using Classic (since he's already
  187. // seen the Classic Start Menu). In the Classic case, upgrade the counter
  188. // to 2 so the user won't be annoyed when they switch from Classic to
  189. // Personal.
  190. //
  191. // In case 2, we don't want to show the balloon tip at all since the
  192. // user has seen all we have to offer.
  193. //
  194. BOOL CTray::_ShouldWeShowTheStartButtonBalloon()
  195. {
  196. DWORD dwType;
  197. DWORD dwData = 0;
  198. DWORD cbSize = sizeof(DWORD);
  199. SHGetValue(HKEY_CURRENT_USER, REGSTR_EXPLORER_ADVANCED,
  200. TEXT("StartButtonBalloonTip"), &dwType, (BYTE*)&dwData, &cbSize);
  201. if (Tray_StartPanelEnabled())
  202. {
  203. // Personal Start Menu is enabled, so show the balloon if the
  204. // user has never logged on to a Whistler machine before.
  205. return dwData < 2;
  206. }
  207. else
  208. {
  209. // Classic Start Menu is enabled.
  210. switch (dwData)
  211. {
  212. case 0:
  213. // User has never seen the Start Menu before, not even the
  214. // classic one. So show the tip.
  215. return TRUE;
  216. case 1:
  217. // User has already seen the Classic Start Menu, so don't
  218. // prompt them again. Note that this means that they aren't
  219. // prompted when they turn on the Personal Start Menu, but
  220. // that's okay, because by the time they switch to Personal,
  221. // they clearly have demonstrated that they know how the
  222. // Start Button works and don't need a tip.
  223. _DontShowTheStartButtonBalloonAnyMore();
  224. return FALSE;
  225. default:
  226. // User has seen Whistler Start menu before, so don't show tip.
  227. return FALSE;
  228. }
  229. }
  230. }
  231. //
  232. // Set the value to 2 to indicate that the user has seen a Whistler
  233. // Start Menu (either Classic or Personal).
  234. //
  235. void CTray::_DontShowTheStartButtonBalloonAnyMore()
  236. {
  237. DWORD dwData = 2;
  238. SHSetValue(HKEY_CURRENT_USER, REGSTR_EXPLORER_ADVANCED,
  239. TEXT("StartButtonBalloonTip"), REG_DWORD, (BYTE*)&dwData, sizeof(dwData));
  240. }
  241. void CTray::_DestroyStartButtonBalloon()
  242. {
  243. if (_hwndStartBalloon)
  244. {
  245. DestroyWindow(_hwndStartBalloon);
  246. _hwndStartBalloon = NULL;
  247. }
  248. KillTimer(_hwnd, IDT_STARTBUTTONBALLOON);
  249. }
  250. void CTray::CreateStartButtonBalloon(UINT idsTitle, UINT idsMessage)
  251. {
  252. if (!_hwndStartBalloon)
  253. {
  254. _hwndStartBalloon = CreateWindow(TOOLTIPS_CLASS, NULL,
  255. WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP | TTS_BALLOON,
  256. CW_USEDEFAULT, CW_USEDEFAULT,
  257. CW_USEDEFAULT, CW_USEDEFAULT,
  258. _hwnd, NULL, hinstCabinet,
  259. NULL);
  260. if (_hwndStartBalloon)
  261. {
  262. // set the version so we can have non buggy mouse event forwarding
  263. SendMessage(_hwndStartBalloon, CCM_SETVERSION, COMCTL32_VERSION, 0);
  264. SendMessage(_hwndStartBalloon, TTM_SETMAXTIPWIDTH, 0, (LPARAM)300);
  265. // taskbar windows are themed under Taskbar subapp name
  266. SendMessage(_hwndStartBalloon, TTM_SETWINDOWTHEME, 0, (LPARAM)c_wzTaskbarTheme);
  267. // Tell the Start Menu that this is a special balloon tip
  268. SetProp(_hwndStartBalloon, PROP_DV2_BALLOONTIP, DV2_BALLOONTIP_STARTBUTTON);
  269. }
  270. }
  271. if (_hwndStartBalloon)
  272. {
  273. TCHAR szTip[MAX_PATH];
  274. szTip[0] = TEXT('\0');
  275. LoadString(hinstCabinet, idsMessage, szTip, ARRAYSIZE(szTip));
  276. if (szTip[0])
  277. {
  278. RECT rc;
  279. TOOLINFO ti = {0};
  280. ti.cbSize = sizeof(ti);
  281. ti.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_TRANSPARENT;
  282. ti.hwnd = _hwnd;
  283. ti.uId = (UINT_PTR)_hwndStart;
  284. //ti.lpszText = NULL;
  285. SendMessage(_hwndStartBalloon, TTM_ADDTOOL, 0, (LPARAM)(LPTOOLINFO)&ti);
  286. SendMessage(_hwndStartBalloon, TTM_TRACKACTIVATE, (WPARAM)FALSE, (LPARAM)0);
  287. ti.lpszText = szTip;
  288. SendMessage(_hwndStartBalloon, TTM_UPDATETIPTEXT, 0, (LPARAM)&ti);
  289. LoadString(hinstCabinet, idsTitle, szTip, ARRAYSIZE(szTip));
  290. if (szTip[0])
  291. {
  292. SendMessage(_hwndStartBalloon, TTM_SETTITLE, TTI_INFO, (LPARAM)szTip);
  293. }
  294. GetWindowRect(_hwndStart, &rc);
  295. SendMessage(_hwndStartBalloon, TTM_TRACKPOSITION, 0, MAKELONG((rc.left + rc.right)/2, rc.top));
  296. SetWindowZorder(_hwndStartBalloon, HWND_TOPMOST);
  297. SendMessage(_hwndStartBalloon, TTM_TRACKACTIVATE, (WPARAM)TRUE, (LPARAM)&ti);
  298. SetTimer(_hwnd, IDT_STARTBUTTONBALLOON, BALLOONTIPDELAY, NULL);
  299. }
  300. }
  301. }
  302. void CTray::_ShowStartButtonToolTip()
  303. {
  304. if (!_ShouldWeShowTheStartButtonBalloon() || SHRestricted(REST_NOSMBALLOONTIP))
  305. {
  306. PostMessage(_hwnd, TM_SHOWTRAYBALLOON, TRUE, 0);
  307. return;
  308. }
  309. if (Tray_StartPanelEnabled())
  310. {
  311. // In order to display the Start Menu, we need foreground activation
  312. // so keyboard focus will work properly.
  313. if (SetForegroundWindow(_hwnd))
  314. {
  315. LockSetForegroundWindow(LSFW_LOCK);
  316. _fForegroundLocked = TRUE;
  317. // Inform the tray that start button is auto-popping, so the tray
  318. // can hold off on showing balloons.
  319. PostMessage(_hwnd, TM_SHOWTRAYBALLOON, FALSE, 0);
  320. // This pushes the start button and causes the start menu to popup.
  321. SendMessage(GetDlgItem(_hwnd, IDC_START), BM_SETSTATE, TRUE, 0);
  322. // Once successfully done once, don't do it again.
  323. _DontShowTheStartButtonBalloonAnyMore();
  324. }
  325. }
  326. else
  327. {
  328. PostMessage(_hwnd, TM_SHOWTRAYBALLOON, TRUE, 0);
  329. CreateStartButtonBalloon(IDS_STARTMENUBALLOON_TITLE, IDS_STARTMENUBALLOON_TIP);
  330. }
  331. }
  332. BOOL CTray::_CreateClockWindow()
  333. {
  334. _hwndNotify = _trayNotify.TrayNotifyCreate(_hwnd, IDC_CLOCK, hinstCabinet);
  335. SendMessage(_hwndNotify, TNM_UPDATEVERTICAL, 0, !STUCK_HORIZONTAL(_uStuckPlace));
  336. return BOOLFROMPTR(_hwndNotify);
  337. }
  338. BOOL CTray::_InitTrayClass()
  339. {
  340. WNDCLASS wc = {0};
  341. wc.lpszClassName = TEXT(WNDCLASS_TRAYNOTIFY);
  342. wc.style = CS_DBLCLKS;
  343. wc.lpfnWndProc = s_WndProc;
  344. wc.hInstance = hinstCabinet;
  345. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  346. wc.hbrBackground = (HBRUSH)(COLOR_3DFACE+1);
  347. wc.cbWndExtra = sizeof(LONG_PTR);
  348. return RegisterClass(&wc);
  349. }
  350. HFONT CTray::_CreateStartFont(HWND hwndTray)
  351. {
  352. HFONT hfontStart = NULL;
  353. NONCLIENTMETRICS ncm;
  354. ncm.cbSize = sizeof(ncm);
  355. if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, FALSE))
  356. {
  357. WORD wLang = GetUserDefaultLangID();
  358. // Select normal weight font for chinese language.
  359. if (PRIMARYLANGID(wLang) == LANG_CHINESE &&
  360. ((SUBLANGID(wLang) == SUBLANG_CHINESE_TRADITIONAL) ||
  361. (SUBLANGID(wLang) == SUBLANG_CHINESE_SIMPLIFIED)))
  362. ncm.lfCaptionFont.lfWeight = FW_NORMAL;
  363. else
  364. ncm.lfCaptionFont.lfWeight = FW_BOLD;
  365. hfontStart = CreateFontIndirect(&ncm.lfCaptionFont);
  366. }
  367. return hfontStart;
  368. }
  369. // Set the stuck monitor for the tray window
  370. void CTray::_SetStuckMonitor()
  371. {
  372. // use STICK_LEFT because most of the multi-monitors systems are set up
  373. // side by side. use DEFAULTTONULL because we don't want to get the wrong one
  374. // use the center point to call again in case we failed the first time.
  375. _hmonStuck = MonitorFromRect(&_arStuckRects[STICK_LEFT],
  376. MONITOR_DEFAULTTONULL);
  377. if (!_hmonStuck)
  378. {
  379. POINT pt;
  380. pt.x = (_arStuckRects[STICK_LEFT].left + _arStuckRects[STICK_LEFT].right)/2;
  381. pt.y = (_arStuckRects[STICK_LEFT].top + _arStuckRects[STICK_LEFT].bottom)/2;
  382. _hmonStuck = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
  383. }
  384. _hmonOld = _hmonStuck;
  385. }
  386. DWORD _GetDefaultTVSDFlags()
  387. {
  388. DWORD dwFlags = TVSD_TOPMOST;
  389. // if we are on a remote hydra session and if there is no previous saved value,
  390. // do not display the clock.
  391. if (SHGetMachineInfo(GMI_TSCLIENT))
  392. {
  393. dwFlags |= TVSD_HIDECLOCK;
  394. }
  395. return dwFlags;
  396. }
  397. void CTray::_GetSaveStateAndInitRects()
  398. {
  399. TVSDCOMPAT tvsd;
  400. RECT rcDisplay;
  401. DWORD dwTrayFlags;
  402. UINT uStick;
  403. SIZE size;
  404. // first fill in the defaults
  405. SetRect(&rcDisplay, 0, 0, g_cxPrimaryDisplay, g_cyPrimaryDisplay);
  406. // size gets defaults
  407. size.cx = _sizeStart.cx + 2 * (g_cxDlgFrame + g_cxBorder);
  408. size.cy = _sizeStart.cy + 2 * (g_cyDlgFrame + g_cyBorder);
  409. // sStuckWidths gets minimum
  410. _sStuckWidths.cx = 2 * (g_cxDlgFrame + g_cxBorder);
  411. _sStuckWidths.cy = _sizeStart.cy + 2 * (g_cyDlgFrame + g_cyBorder);
  412. _uStuckPlace = STICK_BOTTOM;
  413. dwTrayFlags = _GetDefaultTVSDFlags();
  414. _uAutoHide = 0;
  415. // now try to load saved vaules
  416. // BUG : 231077
  417. // Since Tasbar properties don't roam from NT5 to NT4, (NT4 -> NT5 yes)
  418. // Allow roaming from NT4 to NT5 only for the first time the User logs
  419. // on to NT5, so that future changes to NT5 are not lost when the user
  420. // logs on to NT4 after customizing the taskbar properties on NT5.
  421. DWORD cbData1 = sizeof(tvsd);
  422. DWORD cbData2 = sizeof(tvsd);
  423. if (Reg_GetStruct(g_hkeyExplorer, TEXT("StuckRects2"), TEXT("Settings"),
  424. &tvsd, &cbData1)
  425. ||
  426. Reg_GetStruct(g_hkeyExplorer, TEXT("StuckRects"), TEXT("Settings"),
  427. &tvsd, &cbData2))
  428. {
  429. if (IS_CURRENT_TVSD(tvsd.t) && IsValidSTUCKPLACE(tvsd.t.uStuckPlace))
  430. {
  431. _GetDisplayRectFromRect(&rcDisplay, &tvsd.t.rcLastStuck,
  432. MONITOR_DEFAULTTONEAREST);
  433. size = tvsd.t.sStuckWidths;
  434. _uStuckPlace = tvsd.t.uStuckPlace;
  435. dwTrayFlags = tvsd.t.dwFlags;
  436. }
  437. else if (MAYBE_WIN95_TVSD(tvsd.w95) &&
  438. IsValidSTUCKPLACE(tvsd.w95.uStuckPlace))
  439. {
  440. _uStuckPlace = tvsd.w95.uStuckPlace;
  441. dwTrayFlags = tvsd.w95.dwFlags;
  442. if (tvsd.w95.uAutoHide & AH_ON)
  443. dwTrayFlags |= TVSD_AUTOHIDE;
  444. switch (_uStuckPlace)
  445. {
  446. case STICK_LEFT:
  447. size.cx = tvsd.w95.dxLeft;
  448. break;
  449. case STICK_RIGHT:
  450. size.cx = tvsd.w95.dxRight;
  451. break;
  452. case STICK_BOTTOM:
  453. size.cy = tvsd.w95.dyBottom;
  454. break;
  455. case STICK_TOP:
  456. size.cy = tvsd.w95.dyTop;
  457. break;
  458. }
  459. }
  460. }
  461. ASSERT(IsValidSTUCKPLACE(_uStuckPlace));
  462. //
  463. // use the size only if it is not bogus
  464. //
  465. if (_sStuckWidths.cx < size.cx)
  466. _sStuckWidths.cx = size.cx;
  467. if (_sStuckWidths.cy < size.cy)
  468. _sStuckWidths.cy = size.cy;
  469. //
  470. // set the tray flags
  471. //
  472. _fAlwaysOnTop = BOOLIFY(dwTrayFlags & TVSD_TOPMOST);
  473. _fSMSmallIcons = BOOLIFY(dwTrayFlags & TVSD_SMSMALLICONS);
  474. _fHideClock = SHRestricted(REST_HIDECLOCK) || BOOLIFY(dwTrayFlags & TVSD_HIDECLOCK);
  475. _uAutoHide = (dwTrayFlags & TVSD_AUTOHIDE) ? AH_ON | AH_HIDING : 0;
  476. _RefreshSettings();
  477. //
  478. // initialize stuck rects
  479. //
  480. for (uStick = STICK_LEFT; uStick <= STICK_BOTTOM; uStick++)
  481. _MakeStuckRect(&_arStuckRects[uStick], &rcDisplay, _sStuckWidths, uStick);
  482. _UpdateVertical(_uStuckPlace);
  483. // Determine which monitor the tray is on using its stuck rectangles
  484. _SetStuckMonitor();
  485. }
  486. IBandSite * BandSite_CreateView();
  487. HRESULT BandSite_SaveView(IUnknown *pbs);
  488. LRESULT BandSite_OnMarshallBS(WPARAM wParam, LPARAM lParam);
  489. void CTray::_SaveTrayStuff(void)
  490. {
  491. TVSD tvsd;
  492. tvsd.dwSize = sizeof(tvsd);
  493. tvsd.lSignature = TVSDSIG_CURRENT;
  494. // position
  495. CopyRect(&tvsd.rcLastStuck, &_arStuckRects[_uStuckPlace]);
  496. tvsd.sStuckWidths = _sStuckWidths;
  497. tvsd.uStuckPlace = _uStuckPlace;
  498. tvsd.dwFlags = 0;
  499. if (_fAlwaysOnTop) tvsd.dwFlags |= TVSD_TOPMOST;
  500. if (_fSMSmallIcons) tvsd.dwFlags |= TVSD_SMSMALLICONS;
  501. if (_fHideClock && !SHRestricted(REST_HIDECLOCK)) tvsd.dwFlags |= TVSD_HIDECLOCK;
  502. if (_uAutoHide & AH_ON) tvsd.dwFlags |= TVSD_AUTOHIDE;
  503. // Save in Stuck rects.
  504. Reg_SetStruct(g_hkeyExplorer, TEXT("StuckRects2"), TEXT("Settings"), &tvsd, sizeof(tvsd));
  505. BandSite_SaveView(_ptbs);
  506. return;
  507. }
  508. // align toolbar so that buttons are flush with client area
  509. // and make toolbar's buttons to be MENU style
  510. void CTray::_AlignStartButton()
  511. {
  512. HWND hwndStart = _hwndStart;
  513. if (hwndStart)
  514. {
  515. TCHAR szStart[50];
  516. LoadString(hinstCabinet, _hTheme ? IDS_START : IDS_STARTCLASSIC, szStart, ARRAYSIZE(szStart));
  517. SetWindowText(_hwndStart, szStart);
  518. RECT rcClient;
  519. if (!_sizeStart.cx)
  520. {
  521. Button_GetIdealSize(hwndStart, &_sizeStart);
  522. }
  523. GetClientRect(_hwnd, &rcClient);
  524. if (rcClient.right < _sizeStart.cx)
  525. {
  526. SetWindowText(_hwndStart, L"");
  527. }
  528. int cyStart = _sizeStart.cy;
  529. if (_hwndTasks)
  530. {
  531. if (_hTheme)
  532. {
  533. cyStart = max(cyStart, SendMessage(_hwndTasks, TBC_BUTTONHEIGHT, 0, 0));
  534. }
  535. else
  536. {
  537. cyStart = SendMessage(_hwndTasks, TBC_BUTTONHEIGHT, 0, 0);
  538. }
  539. }
  540. SetWindowPos(hwndStart, NULL, 0, 0, min(rcClient.right, _sizeStart.cx),
  541. cyStart, SWP_NOZORDER | SWP_NOACTIVATE);
  542. }
  543. }
  544. // Helper function for CDesktopHost so clicking twice on the Start Button
  545. // treats the second click as a dismiss rather than a redisplay.
  546. //
  547. // The crazy state machine goes like this:
  548. //
  549. // SBSM_NORMAL - normal state, nothing exciting
  550. //
  551. // When user opens Start Pane, we become
  552. //
  553. // SBSM_SPACTIVE - start pane is active
  554. //
  555. // If user clicks Start Button while SBSM_SPACTIVE, then we become
  556. //
  557. // SBSM_EATING - eat mouse clicks
  558. //
  559. // Until we receive a WM_MOUSEFIRST/WM_MOUSELAST message, and then
  560. // we return to SBSM_NORMAL.
  561. //
  562. // If user dismisses Start Pane, we go straight to SBSM_NORMAL.
  563. //
  564. //
  565. // We eat the mouse clicks so that the click that the user made
  566. // to "unclick" the start button doesn't cause it to get pushed down
  567. // again (and cause the Start Menu to reopen).
  568. //
  569. #define SBSM_NORMAL 0
  570. #define SBSM_SPACTIVE 1
  571. #define SBSM_EATING 2
  572. void Tray_UnlockStartPane()
  573. {
  574. // If we had locked out foreground window changes (first-boot),
  575. // then release the lock.
  576. if (c_tray._fForegroundLocked)
  577. {
  578. c_tray._fForegroundLocked = FALSE;
  579. LockSetForegroundWindow(LSFW_UNLOCK);
  580. }
  581. }
  582. void Tray_SetStartPaneActive(BOOL fActive)
  583. {
  584. if (fActive)
  585. { // Start Pane appearing
  586. c_tray._uStartButtonState = SBSM_SPACTIVE;
  587. }
  588. else if (c_tray._uStartButtonState != SBSM_EATING)
  589. { // Start Pane dismissing, not eating messages -> return to normal
  590. c_tray._uStartButtonState = SBSM_NORMAL;
  591. Tray_UnlockStartPane();
  592. }
  593. }
  594. // Allow us to do stuff on a "button-down".
  595. LRESULT WINAPI CTray::StartButtonSubclassWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  596. {
  597. return c_tray._StartButtonSubclassWndProc(hwnd, uMsg, wParam, lParam);
  598. }
  599. LRESULT CTray::_StartButtonSubclassWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  600. {
  601. LRESULT lRet;
  602. ASSERT(_pfnButtonProc)
  603. // Is the button going down?
  604. if (uMsg == BM_SETSTATE)
  605. {
  606. // Is it going Down?
  607. if (wParam)
  608. {
  609. // DebugMsg(DM_TRACE, "c.stswp: Set state %d", wParam);
  610. // Yes - proceed if it's currently up and it's allowed to be down
  611. if (!_uDown)
  612. {
  613. // Nope.
  614. INSTRUMENT_STATECHANGE(SHCNFI_STATE_START_DOWN);
  615. _uDown = 1;
  616. // If we are going down, then we do not want to popup again until the Start Menu is collapsed
  617. _fAllowUp = FALSE;
  618. SendMessage(_hwndTrayTips, TTM_ACTIVATE, FALSE, 0L);
  619. // Show the button down.
  620. lRet = CallWindowProc(_pfnButtonProc, hwnd, uMsg, wParam, lParam);
  621. // Notify the parent.
  622. SendMessage(GetParent(hwnd), WM_COMMAND, (WPARAM)LOWORD(GetDlgCtrlID(hwnd)), (LPARAM)hwnd);
  623. _tmOpen = GetTickCount();
  624. return lRet;
  625. }
  626. else
  627. {
  628. // Yep. Do nothing.
  629. // fDown = FALSE;
  630. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  631. }
  632. }
  633. else
  634. {
  635. // DebugMsg(DM_TRACE, "c.stswp: Set state %d", wParam);
  636. // Nope, buttons coming up.
  637. // Is it supposed to be down? Is it not allowed to be up?
  638. if (_uDown == 1 || !_fAllowUp)
  639. {
  640. INSTRUMENT_STATECHANGE(SHCNFI_STATE_START_UP);
  641. // Yep, do nothing.
  642. _uDown = 2;
  643. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  644. }
  645. else
  646. {
  647. SendMessage(_hwndTrayTips, TTM_ACTIVATE, TRUE, 0L);
  648. // Nope, Forward it on.
  649. _uDown = 0;
  650. return CallWindowProc(_pfnButtonProc, hwnd, uMsg, wParam, lParam);
  651. }
  652. }
  653. }
  654. else
  655. {
  656. if (_uStartButtonState == SBSM_EATING &&
  657. uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST)
  658. {
  659. _uStartButtonState = SBSM_NORMAL;
  660. // Explicitly dismiss the Start Panel because it might be
  661. // stuck in this limbo state where it is open but not the
  662. // foreground window (_ShowStartButtonToolTip does this)
  663. // so it doesn't know that it needs to go away.
  664. ClosePopupMenus();
  665. }
  666. switch (uMsg) {
  667. case WM_LBUTTONDOWN:
  668. // The button was clicked on, then we don't need no stink'n focus rect.
  669. SendMessage(GetParent(hwnd), WM_UPDATEUISTATE, MAKEWPARAM(UIS_SET,
  670. UISF_HIDEFOCUS), 0);
  671. goto ProcessCapture;
  672. break;
  673. case WM_KEYDOWN:
  674. // The user pressed enter or return or some other bogus key combination when
  675. // the start button had keyboard focus, so show the rect....
  676. SendMessage(GetParent(hwnd), WM_UPDATEUISTATE, MAKEWPARAM(UIS_CLEAR,
  677. UISF_HIDEFOCUS), 0);
  678. if (wParam == VK_RETURN)
  679. PostMessage(_hwnd, WM_COMMAND, IDC_KBSTART, 0);
  680. // We do not need the capture, because we do all of our button processing
  681. // on the button down. In fact taking capture for no good reason screws with
  682. // drag and drop into the menus. We're overriding user.
  683. ProcessCapture:
  684. lRet = CallWindowProc(_pfnButtonProc, hwnd, uMsg, wParam, lParam);
  685. SetCapture(NULL);
  686. return lRet;
  687. break;
  688. case WM_MOUSEMOVE:
  689. {
  690. MSG msg;
  691. msg.lParam = lParam;
  692. msg.wParam = wParam;
  693. msg.message = uMsg;
  694. msg.hwnd = hwnd;
  695. SendMessage(_hwndTrayTips, TTM_RELAYEVENT, 0, (LPARAM)(LPMSG)& msg);
  696. break;
  697. }
  698. case WM_MOUSEACTIVATE:
  699. if (_uStartButtonState != SBSM_NORMAL)
  700. {
  701. _uStartButtonState = SBSM_EATING;
  702. return MA_ACTIVATEANDEAT;
  703. }
  704. break;
  705. //
  706. // Debounce the Start Button. Usability shows that lots of people
  707. // double-click the Start Button, resulting in the menu opening
  708. // and then immediately closing...
  709. //
  710. case WM_NCHITTEST:
  711. if (GetTickCount() - _tmOpen < GetDoubleClickTime())
  712. {
  713. return HTNOWHERE;
  714. }
  715. break;
  716. case WM_NULL:
  717. break;
  718. }
  719. return CallWindowProc(_pfnButtonProc, hwnd, uMsg, wParam, lParam);
  720. }
  721. }
  722. EXTERN_C const WCHAR c_wzTaskbarTheme[] = L"Taskbar";
  723. EXTERN_C const WCHAR c_wzTaskbarVertTheme[] = L"TaskbarVert";
  724. // create the toolbar with the three buttons and align windows
  725. HWND CTray::_CreateStartButton()
  726. {
  727. DWORD dwStyle = 0;//BS_BITMAP;
  728. _uStartButtonBalloonTip = RegisterWindowMessage(TEXT("Welcome Finished"));
  729. _uLogoffUser = RegisterWindowMessage(TEXT("Logoff User"));
  730. // Register for MM device changes
  731. _uWinMM_DeviceChange = RegisterWindowMessage(WINMMDEVICECHANGEMSGSTRING);
  732. HWND hwnd = CreateWindowEx(0, WC_BUTTON, TEXT("Start"),
  733. WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS |
  734. BS_PUSHBUTTON | BS_LEFT | BS_VCENTER | dwStyle,
  735. 0, 0, 0, 0, _hwnd, (HMENU)IDC_START, hinstCabinet, NULL);
  736. if (hwnd)
  737. {
  738. // taskbar windows are themed under Taskbar subapp name
  739. SetWindowTheme(hwnd, L"Start", NULL);
  740. SendMessage(hwnd, CCM_DPISCALE, TRUE, 0);
  741. // Subclass it.
  742. _hwndStart = hwnd;
  743. _pfnButtonProc = SubclassWindow(hwnd, StartButtonSubclassWndProc);
  744. _StartButtonReset();
  745. }
  746. return hwnd;
  747. }
  748. void CTray::_GetWindowSizes(UINT uStuckPlace, PRECT prcClient, PRECT prcView, PRECT prcNotify)
  749. {
  750. prcView->top = 0;
  751. prcView->left = 0;
  752. prcView->bottom = prcClient->bottom;
  753. prcView->right = prcClient->right;
  754. if (STUCK_HORIZONTAL(uStuckPlace))
  755. {
  756. DWORD_PTR dwNotifySize = SendMessage(_hwndNotify, WM_CALCMINSIZE, prcClient->right / 2, prcClient->bottom);
  757. prcNotify->top = 0;
  758. prcNotify->left = prcClient->right - LOWORD(dwNotifySize);
  759. prcNotify->bottom = HIWORD(dwNotifySize);
  760. prcNotify->right = prcClient->right;
  761. prcView->left = _sizeStart.cx + g_cxFrame + 1;
  762. prcView->right = prcNotify->left;
  763. }
  764. else
  765. {
  766. DWORD_PTR dwNotifySize = SendMessage(_hwndNotify, WM_CALCMINSIZE, prcClient->right, prcClient->bottom / 2);
  767. prcNotify->top = prcClient->bottom - HIWORD(dwNotifySize);
  768. prcNotify->left = 0;
  769. prcNotify->bottom = prcClient->bottom;
  770. prcNotify->right = LOWORD(dwNotifySize);
  771. prcView->top = _sizeStart.cy + g_cyTabSpace;
  772. prcView->bottom = prcNotify->top;
  773. }
  774. }
  775. void CTray::_RestoreWindowPos()
  776. {
  777. WINDOWPLACEMENT wp;
  778. //first restore the stuck postitions
  779. _GetSaveStateAndInitRects();
  780. wp.length = sizeof(wp);
  781. wp.showCmd = SW_HIDE;
  782. _uMoveStuckPlace = (UINT)-1;
  783. _GetDockedRect(&wp.rcNormalPosition, FALSE);
  784. SendMessage(_hwndNotify, TNM_TRAYHIDE, 0, _fHideClock);
  785. SetWindowPlacement(_hwnd, &wp);
  786. }
  787. // Get the display (monitor) rectangle from the given arbitrary point
  788. HMONITOR CTray::_GetDisplayRectFromPoint(LPRECT prcDisplay, POINT pt, UINT uFlags)
  789. {
  790. RECT rcEmpty = {0};
  791. HMONITOR hmon = MonitorFromPoint(pt, uFlags);
  792. if (hmon && prcDisplay)
  793. GetMonitorRect(hmon, prcDisplay);
  794. else if (prcDisplay)
  795. *prcDisplay = rcEmpty;
  796. return hmon;
  797. }
  798. // Get the display (monitor) rectangle from the given arbitrary rectangle
  799. HMONITOR CTray::_GetDisplayRectFromRect(LPRECT prcDisplay, LPCRECT prcIn, UINT uFlags)
  800. {
  801. RECT rcEmpty = {0};
  802. HMONITOR hmon = MonitorFromRect(prcIn, uFlags);
  803. if (hmon && prcDisplay)
  804. GetMonitorRect(hmon, prcDisplay);
  805. else if (prcDisplay)
  806. *prcDisplay = rcEmpty;
  807. return hmon;
  808. }
  809. // Get the display (monitor) rectangle where the taskbar is currently on,
  810. // if that monitor is invalid, get the nearest one.
  811. void CTray::_GetStuckDisplayRect(UINT uStuckPlace, LPRECT prcDisplay)
  812. {
  813. ASSERT(prcDisplay);
  814. BOOL fValid = GetMonitorRect(_hmonStuck, prcDisplay);
  815. if (!fValid)
  816. _GetDisplayRectFromRect(prcDisplay, &_arStuckRects[uStuckPlace], MONITOR_DEFAULTTONEAREST);
  817. }
  818. void CTray::_AdjustRectForSizingBar(UINT uStuckPlace, LPRECT prc, int iIncrement)
  819. {
  820. if (iIncrement != 0)
  821. {
  822. switch (uStuckPlace)
  823. {
  824. case STICK_BOTTOM: prc->top -= iIncrement * _sizeSizingBar.cy; break;
  825. case STICK_TOP: prc->bottom += iIncrement * _sizeSizingBar.cy; break;
  826. case STICK_LEFT: prc->right += iIncrement * _sizeSizingBar.cx; break;
  827. case STICK_RIGHT: prc->left -= iIncrement * _sizeSizingBar.cx; break;
  828. }
  829. }
  830. else
  831. {
  832. if (IS_BIDI_LOCALIZED_SYSTEM())
  833. {
  834. switch (uStuckPlace)
  835. {
  836. case STICK_BOTTOM: prc->bottom = prc->top + _sizeSizingBar.cy; break;
  837. case STICK_TOP: prc->top = prc->bottom - _sizeSizingBar.cy; break;
  838. case STICK_LEFT: prc->right = prc->left + _sizeSizingBar.cx; break;
  839. case STICK_RIGHT: prc->left = prc->right - _sizeSizingBar.cx; break;
  840. }
  841. }
  842. else
  843. {
  844. switch (uStuckPlace)
  845. {
  846. case STICK_BOTTOM: prc->bottom = prc->top + _sizeSizingBar.cy; break;
  847. case STICK_TOP: prc->top = prc->bottom - _sizeSizingBar.cy; break;
  848. case STICK_LEFT: prc->left = prc->right - _sizeSizingBar.cx; break;
  849. case STICK_RIGHT: prc->right = prc->left + _sizeSizingBar.cx; break;
  850. }
  851. }
  852. }
  853. }
  854. // Snap a StuckRect to the edge of a containing rectangle
  855. // fClip determines whether to clip the rectangle if it's off the display or move it onto the screen
  856. void CTray::_MakeStuckRect(LPRECT prcStick, LPCRECT prcBound, SIZE size, UINT uStick)
  857. {
  858. CopyRect(prcStick, prcBound);
  859. if (_hTheme && (_fCanSizeMove || _fShowSizingBarAlways))
  860. {
  861. _AdjustRectForSizingBar(uStick, prcStick, 1);
  862. }
  863. if (!_hTheme)
  864. {
  865. InflateRect(prcStick, g_cxEdge, g_cyEdge);
  866. }
  867. if (size.cx < 0) size.cx *= -1;
  868. if (size.cy < 0) size.cy *= -1;
  869. switch (uStick)
  870. {
  871. case STICK_LEFT: prcStick->right = (prcStick->left + size.cx); break;
  872. case STICK_TOP: prcStick->bottom = (prcStick->top + size.cy); break;
  873. case STICK_RIGHT: prcStick->left = (prcStick->right - size.cx); break;
  874. case STICK_BOTTOM: prcStick->top = (prcStick->bottom - size.cy); break;
  875. }
  876. }
  877. // the screen size has changed, so the docked rectangles need to be
  878. // adjusted to the new screen.
  879. void CTray::_ResizeStuckRects(RECT *arStuckRects)
  880. {
  881. RECT rcDisplay;
  882. _GetStuckDisplayRect(_uStuckPlace, &rcDisplay);
  883. for (UINT uStick = STICK_LEFT; uStick <= STICK_BOTTOM; uStick++)
  884. {
  885. _MakeStuckRect(&arStuckRects[uStick], &rcDisplay, _sStuckWidths, uStick);
  886. }
  887. }
  888. //*** CTray::InvisibleUnhide -- temporary 'invisible' un-autohide
  889. // DESCRIPTION
  890. // various tray resize routines need the tray to be un-autohide'd for
  891. // stuff to be calculated correctly. so we un-autohide it (invisibly...)
  892. // here. note the WM_SETREDRAW to prevent flicker (nt5:182340).
  893. // note that this is kind of a hack -- ideally the tray code would do
  894. // stuff correctly even if hidden.
  895. //
  896. void CTray::InvisibleUnhide(BOOL fShowWindow)
  897. {
  898. if (fShowWindow == FALSE)
  899. {
  900. if (_cHided++ == 0)
  901. {
  902. SendMessage(_hwnd, WM_SETREDRAW, FALSE, 0);
  903. ShowWindow(_hwnd, SW_HIDE);
  904. Unhide();
  905. }
  906. }
  907. else
  908. {
  909. ASSERT(_cHided > 0); // must be push/pop
  910. if (--_cHided == 0)
  911. {
  912. _Hide();
  913. ShowWindow(_hwnd, SW_SHOWNA);
  914. SendMessage(_hwnd, WM_SETREDRAW, TRUE, 0);
  915. }
  916. }
  917. }
  918. void CTray::VerifySize(BOOL fWinIni, BOOL fRoundUp /* = FALSE */)
  919. {
  920. RECT rc;
  921. BOOL fHiding;
  922. fHiding = (_uAutoHide & AH_HIDING);
  923. if (fHiding)
  924. {
  925. // force it visible so various calculations will happen relative
  926. // to unhidden size/position.
  927. //
  928. // fixes (e.g.) ie5:154536, where dropping a large-icon ISFBand
  929. // onto hidden tray didn't do size negotiation.
  930. //
  931. InvisibleUnhide(FALSE);
  932. }
  933. rc = _arStuckRects[_uStuckPlace];
  934. _HandleSizing(0, NULL, _uStuckPlace);
  935. if (!EqualRect(&rc, &_arStuckRects[_uStuckPlace]))
  936. {
  937. if (fWinIni)
  938. {
  939. // if we're changing size or position, we need to be unhidden
  940. Unhide();
  941. SizeWindows();
  942. }
  943. rc = _arStuckRects[_uStuckPlace];
  944. if (EVAL((_uAutoHide & (AH_ON | AH_HIDING)) != (AH_ON | AH_HIDING)))
  945. {
  946. _fSelfSizing = TRUE;
  947. SetWindowPos(_hwnd, NULL,
  948. rc.left, rc.top,
  949. RECTWIDTH(rc),RECTHEIGHT(rc),
  950. SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS);
  951. _fSelfSizing = FALSE;
  952. }
  953. _StuckTrayChange();
  954. }
  955. if (fWinIni)
  956. SizeWindows();
  957. if (fHiding)
  958. {
  959. InvisibleUnhide(TRUE);
  960. }
  961. }
  962. HWND CTray::_GetClockWindow(void)
  963. {
  964. return (HWND)SendMessage(_hwndNotify, TNM_GETCLOCK, 0, 0L);
  965. }
  966. UINT _GetStartIDB()
  967. {
  968. UINT id;
  969. #ifdef _WIN64
  970. if (IsOS(OS_ANYSERVER))
  971. {
  972. id = IDB_WIN64ADVSERSTART;
  973. }
  974. else
  975. {
  976. id = IDB_WIN64PROSTART;
  977. }
  978. #else
  979. if (IsOS(OS_TERMINALCLIENT))
  980. {
  981. id = IDB_TERMINALSERVICESBKG;
  982. }
  983. else if (IsOS(OS_DATACENTER))
  984. {
  985. id = IDB_DCSERVERSTARTBKG;
  986. }
  987. else if (IsOS(OS_ADVSERVER))
  988. {
  989. id = IDB_ADVSERVERSTARTBKG;
  990. }
  991. else if (IsOS(OS_SERVER))
  992. {
  993. id = IDB_SERVERSTARTBKG;
  994. }
  995. else if (IsOS(OS_EMBEDDED))
  996. {
  997. id = IDB_EMBEDDED;
  998. }
  999. else if (IsOS(OS_PERSONAL))
  1000. {
  1001. id = IDB_PERSONALSTARTBKG;
  1002. }
  1003. else if (IsOS(OS_MEDIACENTER))
  1004. {
  1005. id = IDB_MEDIACENTER_STARTBKG;
  1006. }
  1007. else if (IsOS(OS_TABLETPC))
  1008. {
  1009. id = IDB_TABLETPC_STARTBKG;
  1010. }
  1011. else
  1012. {
  1013. id = IDB_PROFESSIONALSTARTBKG;
  1014. }
  1015. #endif // _WIN64
  1016. return id;
  1017. }
  1018. void CTray::_CreateTrayTips()
  1019. {
  1020. _hwndTrayTips = CreateWindowEx(WS_EX_TRANSPARENT, TOOLTIPS_CLASS, NULL,
  1021. WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
  1022. CW_USEDEFAULT, CW_USEDEFAULT,
  1023. CW_USEDEFAULT, CW_USEDEFAULT,
  1024. _hwnd, NULL, hinstCabinet,
  1025. NULL);
  1026. if (_hwndTrayTips)
  1027. {
  1028. // taskbar windows are themed under Taskbar subapp name
  1029. SendMessage(_hwndTrayTips, TTM_SETWINDOWTHEME, 0, (LPARAM)c_wzTaskbarTheme);
  1030. SetWindowZorder(_hwndTrayTips, HWND_TOPMOST);
  1031. TOOLINFO ti;
  1032. ti.cbSize = sizeof(ti);
  1033. ti.uFlags = TTF_IDISHWND | TTF_EXCLUDETOOLAREA;
  1034. ti.hwnd = _hwnd;
  1035. ti.uId = (UINT_PTR)_hwndStart;
  1036. ti.lpszText = (LPTSTR)MAKEINTRESOURCE(IDS_STARTBUTTONTIP);
  1037. ti.hinst = hinstCabinet;
  1038. SendMessage(_hwndTrayTips, TTM_ADDTOOL, 0, (LPARAM)(LPTOOLINFO)&ti);
  1039. HWND hwndClock = _GetClockWindow();
  1040. if (hwndClock)
  1041. {
  1042. ti.uFlags = TTF_EXCLUDETOOLAREA;
  1043. ti.uId = (UINT_PTR)hwndClock;
  1044. ti.lpszText = LPSTR_TEXTCALLBACK;
  1045. ti.rect.left = ti.rect.top = ti.rect.bottom = ti.rect.right = 0;
  1046. SendMessage(_hwndTrayTips, TTM_ADDTOOL, 0, (LPARAM)(LPTOOLINFO)&ti);
  1047. }
  1048. }
  1049. }
  1050. #define SHCNE_STAGINGAREANOTIFICATIONS (SHCNE_CREATE | SHCNE_MKDIR | SHCNE_UPDATEDIR | SHCNE_UPDATEITEM)
  1051. LRESULT CTray::_CreateWindows()
  1052. {
  1053. if (_CreateStartButton() && _CreateClockWindow())
  1054. {
  1055. //
  1056. // We need to set the tray position, before creating
  1057. // the view window, because it will call back our
  1058. // GetWindowRect member functions.
  1059. //
  1060. _RestoreWindowPos();
  1061. _CreateTrayTips();
  1062. SendMessage(_hwndNotify, TNM_HIDECLOCK, 0, _fHideClock);
  1063. _ptbs = BandSite_CreateView();
  1064. if (_ptbs)
  1065. {
  1066. IUnknown_GetWindow(_ptbs, &_hwndRebar);
  1067. SetWindowStyle(_hwndRebar, RBS_BANDBORDERS, FALSE);
  1068. // No need to check the disk space thing for non-privileged users, this reduces activity in the TS case
  1069. // and only admins can properly free disk space anyways.
  1070. if (IsUserAnAdmin() && !SHRestricted(REST_NOLOWDISKSPACECHECKS))
  1071. {
  1072. SetTimer(_hwnd, IDT_CHECKDISKSPACE, 60 * 1000, NULL); // 60 seconds poll
  1073. }
  1074. if (IsOS(OS_PERSONAL) || IsOS(OS_PROFESSIONAL))
  1075. {
  1076. SetTimer(_hwnd, IDT_DESKTOPCLEANUP, 24 * 60 * 60 * 1000, NULL); // 24 hour poll
  1077. }
  1078. if (!SHRestricted(REST_NOCDBURNING))
  1079. {
  1080. LPITEMIDLIST pidlStaging;
  1081. if (SUCCEEDED(SHGetFolderLocation(NULL, CSIDL_CDBURN_AREA | CSIDL_FLAG_CREATE, NULL, 0, &pidlStaging)))
  1082. {
  1083. SHChangeNotifyEntry fsne;
  1084. fsne.fRecursive = FALSE;
  1085. fsne.pidl = pidlStaging;
  1086. _uNotify = SHChangeNotifyRegister(_hwnd, SHCNRF_NewDelivery | SHCNRF_ShellLevel | SHCNRF_InterruptLevel,
  1087. SHCNE_STAGINGAREANOTIFICATIONS, TM_CHANGENOTIFY, 1, &fsne);
  1088. // start off by checking the first time.
  1089. _CheckStagingAreaOnTimer();
  1090. ILFree(pidlStaging);
  1091. }
  1092. }
  1093. return 1;
  1094. }
  1095. }
  1096. return -1;
  1097. }
  1098. LRESULT CTray::_InitStartButtonEtc()
  1099. {
  1100. UINT uID = _GetStartIDB();
  1101. // NOTE: This bitmap is used as a flag in CTaskBar::OnPosRectChangeDB to
  1102. // tell when we are done initializing, so we don't resize prematurely
  1103. #ifndef _WIN64
  1104. if (uID == IDB_MEDIACENTER_STARTBKG || uID == IDB_TABLETPC_STARTBKG) // SP1 Only!
  1105. {
  1106. HMODULE hmod = LoadLibraryEx(TEXT("winbrand.dll"), NULL, LOAD_LIBRARY_AS_DATAFILE);
  1107. if (hmod)
  1108. {
  1109. _hbmpStartBkg = LoadBitmap(hmod, MAKEINTRESOURCE(uID));
  1110. FreeLibrary(hmod);
  1111. }
  1112. else
  1113. {
  1114. _hbmpStartBkg = LoadBitmap(hinstCabinet, MAKEINTRESOURCE(IDB_PROFESSIONALSTARTBKG));
  1115. }
  1116. }
  1117. else
  1118. #endif
  1119. {
  1120. _hbmpStartBkg = LoadBitmap(hinstCabinet, MAKEINTRESOURCE(uID));
  1121. }
  1122. if (_hbmpStartBkg)
  1123. {
  1124. UpdateWindow(_hwnd);
  1125. _BuildStartMenu();
  1126. _RegisterDropTargets();
  1127. if (_CheckAssociations())
  1128. CheckWinIniForAssocs();
  1129. SendNotifyMessage(HWND_BROADCAST,
  1130. RegisterWindowMessage(TEXT("TaskbarCreated")), 0, 0);
  1131. return 1;
  1132. }
  1133. return -1;
  1134. }
  1135. void CTray::_AdjustMinimizedMetrics()
  1136. {
  1137. MINIMIZEDMETRICS mm;
  1138. mm.cbSize = sizeof(mm);
  1139. SystemParametersInfo(SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, FALSE);
  1140. mm.iArrange |= ARW_HIDE;
  1141. SystemParametersInfo(SPI_SETMINIMIZEDMETRICS, sizeof(mm), &mm, FALSE);
  1142. }
  1143. void CTray::_UpdateBandSiteStyle()
  1144. {
  1145. if (_ptbs)
  1146. {
  1147. BANDSITEINFO bsi;
  1148. bsi.dwMask = BSIM_STYLE;
  1149. _ptbs->GetBandSiteInfo(&bsi);
  1150. BOOL fCanMoveBands = _fCanSizeMove && !SHRestricted(REST_NOMOVINGBAND);
  1151. DWORD dwStyleNew;
  1152. if (fCanMoveBands)
  1153. {
  1154. dwStyleNew = (bsi.dwStyle & ~(BSIS_NOGRIPPER | BSIS_LOCKED)) | BSIS_AUTOGRIPPER
  1155. | BSIS_PREFERNOLINEBREAK;
  1156. }
  1157. else
  1158. {
  1159. dwStyleNew = (bsi.dwStyle & ~BSIS_AUTOGRIPPER) | BSIS_NOGRIPPER | BSIS_LOCKED
  1160. | BSIS_PREFERNOLINEBREAK;
  1161. }
  1162. // only bother with refresh if something's changed
  1163. if (bsi.dwStyle ^ dwStyleNew)
  1164. {
  1165. bsi.dwStyle = dwStyleNew;
  1166. _ptbs->SetBandSiteInfo(&bsi);
  1167. IUnknown_Exec(_ptbs, &CGID_DeskBand, DBID_BANDINFOCHANGED, 0, NULL, NULL);
  1168. }
  1169. }
  1170. }
  1171. BOOL _IsSizeMoveRestricted()
  1172. {
  1173. return SHRegGetBoolUSValue(REGSTR_POLICIES_EXPLORER, TEXT("LockTaskbar"), FALSE, FALSE);
  1174. }
  1175. BOOL _IsSizeMoveEnabled()
  1176. {
  1177. BOOL fCanSizeMove;
  1178. if (_IsSizeMoveRestricted())
  1179. {
  1180. fCanSizeMove = FALSE;
  1181. }
  1182. else
  1183. {
  1184. fCanSizeMove = SHRegGetBoolUSValue(REGSTR_EXPLORER_ADVANCED, TEXT("TaskbarSizeMove"), FALSE, TRUE);
  1185. }
  1186. return fCanSizeMove;
  1187. }
  1188. void CTray::_RefreshSettings()
  1189. {
  1190. BOOL fOldCanSizeMove = _fCanSizeMove;
  1191. _fCanSizeMove = _IsSizeMoveEnabled();
  1192. BOOL fOldShowSizingBarAlways = _fShowSizingBarAlways;
  1193. _fShowSizingBarAlways = (_uAutoHide & AH_ON) ? TRUE : FALSE;
  1194. if ((fOldCanSizeMove != _fCanSizeMove) || (_fShowSizingBarAlways != fOldShowSizingBarAlways))
  1195. {
  1196. BOOL fHiding = (_uAutoHide & AH_HIDING);
  1197. if (fHiding)
  1198. {
  1199. InvisibleUnhide(FALSE);
  1200. }
  1201. RECT rc;
  1202. GetWindowRect(_hwnd, &rc);
  1203. if (_hTheme && !_fShowSizingBarAlways)
  1204. {
  1205. if (_fCanSizeMove)
  1206. {
  1207. _AdjustRectForSizingBar(_uStuckPlace, &rc, 1);
  1208. }
  1209. else
  1210. {
  1211. _AdjustRectForSizingBar(_uStuckPlace, &rc, -1);
  1212. }
  1213. }
  1214. _ClipWindow(FALSE);
  1215. _fSelfSizing = TRUE;
  1216. SetWindowPos(_hwnd, NULL, rc.left, rc.top, RECTWIDTH(rc), RECTHEIGHT(rc), SWP_NOZORDER | SWP_FRAMECHANGED);
  1217. _fSelfSizing = FALSE;
  1218. _ClipWindow(TRUE);
  1219. _arStuckRects[_uStuckPlace] = rc;
  1220. _StuckTrayChange();
  1221. if (fHiding)
  1222. {
  1223. InvisibleUnhide(TRUE);
  1224. }
  1225. if (!_fCanSizeMove)
  1226. {
  1227. SetWindowPos(_hwnd, NULL, rc.left, rc.top, RECTWIDTH(rc), RECTHEIGHT(rc), SWP_NOZORDER);
  1228. }
  1229. }
  1230. }
  1231. LRESULT CTray::_OnCreateAsync()
  1232. {
  1233. LRESULT lres;
  1234. if (g_dwProfileCAP & 0x00000004)
  1235. {
  1236. StartCAP();
  1237. }
  1238. lres = _InitStartButtonEtc();
  1239. if (g_dwProfileCAP & 0x00000004)
  1240. {
  1241. StopCAP();
  1242. }
  1243. _hMainAccel = LoadAccelerators(hinstCabinet, MAKEINTRESOURCE(ACCEL_TRAY));
  1244. _RegisterGlobalHotkeys();
  1245. // We spin a thread that will process "Load=", "Run=", CU\Run, and CU\RunOnce
  1246. RunStartupApps();
  1247. // If there were any startup failures that occurred before we were
  1248. // ready to handle them, re-raise the failure now that we're ready.
  1249. if (_fEarlyStartupFailure)
  1250. LogFailedStartupApp();
  1251. // we run the tray thread that handles Ctrl-Esc with a high priority
  1252. // class so that it can respond even on a stressed system.
  1253. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
  1254. return lres;
  1255. }
  1256. LRESULT CTray::_OnCreate(HWND hwnd)
  1257. {
  1258. LRESULT lres = -1;
  1259. v_hwndTray = hwnd;
  1260. Mixer_SetCallbackWindow(hwnd);
  1261. SendMessage(_hwnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, 0), 0);
  1262. _AdjustMinimizedMetrics();
  1263. _hTheme = OpenThemeData(hwnd, c_wzTaskbarTheme);
  1264. _fShowSizingBarAlways = (_uAutoHide & AH_ON) ? TRUE : FALSE;
  1265. if (_hTheme)
  1266. {
  1267. GetThemeBool(_hTheme, 0, 0, TMT_ALWAYSSHOWSIZINGBAR, &_fShowSizingBarAlways);
  1268. }
  1269. SetWindowStyle(_hwnd, WS_BORDER | WS_THICKFRAME, !_hTheme);
  1270. // Force Refresh of frame
  1271. SetWindowPos(_hwnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE);
  1272. if (_HotkeyCreate())
  1273. {
  1274. lres = _CreateWindows();
  1275. }
  1276. return lres;
  1277. }
  1278. typedef struct tagFSEPDATA
  1279. {
  1280. LPRECT prc;
  1281. HMONITOR hmon;
  1282. CTray* ptray;
  1283. }
  1284. FSEPDATA, *PFSEPDATA;
  1285. BOOL WINAPI CTray::FullScreenEnumProc(HMONITOR hmon, HDC hdc, LPRECT prc, LPARAM dwData)
  1286. {
  1287. BOOL fFullScreen; // Is there a rude app on this monitor?
  1288. PFSEPDATA pd = (PFSEPDATA)dwData;
  1289. if (pd->hmon == hmon)
  1290. {
  1291. fFullScreen = TRUE;
  1292. }
  1293. else if (pd->prc)
  1294. {
  1295. RECT rc, rcMon;
  1296. GetMonitorRect(hmon, &rcMon);
  1297. IntersectRect(&rc, &rcMon, pd->prc);
  1298. fFullScreen = EqualRect(&rc, &rcMon);
  1299. }
  1300. else
  1301. {
  1302. fFullScreen = FALSE;
  1303. }
  1304. if (hmon == pd->ptray->_hmonStuck)
  1305. {
  1306. pd->ptray->_fStuckRudeApp = fFullScreen;
  1307. }
  1308. //
  1309. // Tell all the appbars on the same display to get out of the way too
  1310. //
  1311. pd->ptray->_AppBarNotifyAll(hmon, ABN_FULLSCREENAPP, NULL, fFullScreen);
  1312. return TRUE;
  1313. }
  1314. void CTray::HandleFullScreenApp(HWND hwnd)
  1315. {
  1316. //
  1317. // First check to see if something has actually changed
  1318. //
  1319. _hwndRude = hwnd;
  1320. //
  1321. // Enumerate all the monitors, see if the app is rude on each, adjust
  1322. // app bars and _fStuckRudeApp as necessary. (Some rude apps, such
  1323. // as the NT Logon Screen Saver, span multiple monitors.)
  1324. //
  1325. FSEPDATA d = {0};
  1326. RECT rc;
  1327. if (hwnd && GetWindowRect(hwnd, &rc))
  1328. {
  1329. d.prc = &rc;
  1330. d.hmon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONULL);
  1331. }
  1332. d.ptray = this;
  1333. EnumDisplayMonitors(NULL, NULL, FullScreenEnumProc, (LPARAM)&d);
  1334. //
  1335. // Now that we've set _fStuckRudeApp, update the tray's z-order position
  1336. //
  1337. _ResetZorder();
  1338. //
  1339. // stop the clock so we don't eat cycles and keep tons of code paged in
  1340. //
  1341. SendMessage(_hwndNotify, TNM_TRAYHIDE, 0, _fStuckRudeApp);
  1342. //
  1343. // Finally, let traynot know about whether the tray is hiding
  1344. //
  1345. SendMessage(_hwndNotify, TNM_RUDEAPP, _fStuckRudeApp, 0);
  1346. }
  1347. BOOL CTray::_IsTopmost()
  1348. {
  1349. return BOOLIFY(GetWindowLong(_hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST);
  1350. }
  1351. BOOL CTray::_IsPopupMenuVisible()
  1352. {
  1353. HWND hwnd;
  1354. return ((SUCCEEDED(IUnknown_GetWindow(_pmpStartMenu, &hwnd)) && IsWindowVisible(hwnd)) ||
  1355. (SUCCEEDED(IUnknown_GetWindow(_pmpStartPane, &hwnd)) && IsWindowVisible(hwnd)) ||
  1356. (SUCCEEDED(IUnknown_GetWindow(_pmpTasks, &hwnd)) && IsWindowVisible(hwnd)));
  1357. }
  1358. BOOL CTray::_IsActive()
  1359. {
  1360. //
  1361. // We say the tray is "active" iff:
  1362. //
  1363. // (a) the foreground window is the tray or a window owned by the tray, or
  1364. // (b) the start menu is showing
  1365. //
  1366. BOOL fActive = FALSE;
  1367. HWND hwnd = GetForegroundWindow();
  1368. if (hwnd != NULL &&
  1369. (hwnd == _hwnd || (GetWindowOwner(hwnd) == _hwnd)))
  1370. {
  1371. fActive = TRUE;
  1372. }
  1373. else if (_IsPopupMenuVisible())
  1374. {
  1375. fActive = TRUE;
  1376. }
  1377. return fActive;
  1378. }
  1379. void CTray::_ResetZorder()
  1380. {
  1381. HWND hwndZorder, hwndZorderCurrent;
  1382. if (g_fDesktopRaised || _fProcessingDesktopRaise || (_fAlwaysOnTop && !_fStuckRudeApp))
  1383. {
  1384. hwndZorder = HWND_TOPMOST;
  1385. }
  1386. else if (_IsActive())
  1387. {
  1388. hwndZorder = HWND_TOP;
  1389. }
  1390. else if (_fStuckRudeApp)
  1391. {
  1392. hwndZorder = HWND_BOTTOM;
  1393. }
  1394. else
  1395. {
  1396. hwndZorder = HWND_NOTOPMOST;
  1397. }
  1398. //
  1399. // We don't have to worry about the HWND_BOTTOM current case -- it's ok
  1400. // to keep moving ourselves down to the bottom when there's a rude app.
  1401. //
  1402. // Nor do we have to worry about the HWND_TOP current case -- it's ok
  1403. // to keep moving ourselves up to the top when we're active.
  1404. //
  1405. hwndZorderCurrent = _IsTopmost() ? HWND_TOPMOST : HWND_NOTOPMOST;
  1406. if (hwndZorder != hwndZorderCurrent)
  1407. {
  1408. // only do this if somehting has changed.
  1409. // this keeps us from popping up over menus as desktop async
  1410. // notifies us of it's state
  1411. SHForceWindowZorder(_hwnd, hwndZorder);
  1412. }
  1413. }
  1414. void CTray::_MessageLoop()
  1415. {
  1416. for (;;)
  1417. {
  1418. MSG msg;
  1419. if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  1420. {
  1421. if (msg.message == WM_QUIT)
  1422. {
  1423. if (_hwnd && IsWindow(_hwnd))
  1424. {
  1425. // Tell the tray to save everything off if we got here
  1426. // without it being destroyed.
  1427. SendMessage(_hwnd, WM_ENDSESSION, 1, 0);
  1428. }
  1429. return; // break all the way out of the main loop
  1430. }
  1431. if (_pmbTasks)
  1432. {
  1433. HRESULT hr = _pmbTasks->IsMenuMessage(&msg);
  1434. if (hr == E_FAIL)
  1435. {
  1436. if (_hwndTasks)
  1437. SendMessage(_hwndTasks, TBC_FREEPOPUPMENUS, 0, 0);
  1438. }
  1439. else if (hr == S_OK)
  1440. {
  1441. continue;
  1442. }
  1443. }
  1444. // Note that this needs to come before _pmbStartMenu since
  1445. // the start pane sometimes hosts the start menu and it needs
  1446. // to handle the start menu messages in that case.
  1447. if (_pmbStartPane &&
  1448. _pmbStartPane->IsMenuMessage(&msg) == S_OK)
  1449. {
  1450. continue;
  1451. }
  1452. if (_pmbStartMenu &&
  1453. _pmbStartMenu->IsMenuMessage(&msg) == S_OK)
  1454. {
  1455. continue;
  1456. }
  1457. if (_hMainAccel && TranslateAccelerator(_hwnd, _hMainAccel, &msg))
  1458. {
  1459. continue;
  1460. }
  1461. TranslateMessage(&msg);
  1462. DispatchMessage(&msg);
  1463. }
  1464. else
  1465. {
  1466. WaitMessage();
  1467. }
  1468. }
  1469. }
  1470. BOOL CTray::Init()
  1471. {
  1472. // use _COINIT to make sure COM is inited disabling the OLE1 support
  1473. return SHCreateThread(MainThreadProc, this, CTF_COINIT, SyncThreadProc) && (_hwnd != NULL);
  1474. }
  1475. int CTray::_GetPart(BOOL fSizingBar, UINT uStuckPlace)
  1476. {
  1477. if (fSizingBar)
  1478. {
  1479. switch (uStuckPlace)
  1480. {
  1481. case STICK_BOTTOM: return TBP_SIZINGBARBOTTOM;
  1482. case STICK_LEFT: return TBP_SIZINGBARLEFT;
  1483. case STICK_TOP: return TBP_SIZINGBARTOP;
  1484. case STICK_RIGHT: return TBP_SIZINGBARRIGHT;
  1485. }
  1486. }
  1487. else
  1488. {
  1489. switch (uStuckPlace)
  1490. {
  1491. case STICK_BOTTOM: return TBP_BACKGROUNDBOTTOM;
  1492. case STICK_LEFT: return TBP_BACKGROUNDLEFT;
  1493. case STICK_TOP: return TBP_BACKGROUNDTOP;
  1494. case STICK_RIGHT: return TBP_BACKGROUNDRIGHT;
  1495. }
  1496. }
  1497. return 0;
  1498. }
  1499. void CTray::_UpdateVertical(UINT uStuckPlace, BOOL fForce)
  1500. {
  1501. static UINT _uOldStuckPlace = STICK_MAX + 1;
  1502. if ((_uOldStuckPlace != uStuckPlace) || fForce)
  1503. {
  1504. _uOldStuckPlace = uStuckPlace;
  1505. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.t_uv tray is now %s"), STUCK_HORIZONTAL(uStuckPlace) ? TEXT("HORIZONTAL") : TEXT("VERTICAL"));
  1506. if (_ptbs)
  1507. {
  1508. // This following function will cause a WINDOWPOSCHANGING which will call DoneMoving
  1509. // DoneMoving will then go a screw up all of the window sizing
  1510. _fIgnoreDoneMoving = TRUE;
  1511. BandSite_SetMode(_ptbs, STUCK_HORIZONTAL(uStuckPlace) ? 0 : DBIF_VIEWMODE_VERTICAL);
  1512. BandSite_SetWindowTheme(_ptbs, (LPWSTR)(STUCK_HORIZONTAL(uStuckPlace) ? c_wzTaskbarTheme : c_wzTaskbarVertTheme));
  1513. _fIgnoreDoneMoving = FALSE;
  1514. }
  1515. SendMessage(_hwndNotify, TNM_UPDATEVERTICAL, 0, !STUCK_HORIZONTAL(uStuckPlace));
  1516. if (_hTheme)
  1517. {
  1518. HDC hdc = GetDC(_hwnd);
  1519. GetThemePartSize(_hTheme, hdc, _GetPart(TRUE, uStuckPlace), 0, NULL, TS_TRUE, &_sizeSizingBar);
  1520. ReleaseDC(_hwnd, hdc);
  1521. }
  1522. }
  1523. }
  1524. void CTray::_InitBandsite()
  1525. {
  1526. ASSERT(_hwnd);
  1527. // we initilize the contents after all the infrastructure is created and sized properly
  1528. // need to notify which side we're on.
  1529. // nt5:211881: set mode *before* load, o.w. Update->RBAutoSize messed up
  1530. _UpdateBandSiteStyle();
  1531. BandSite_Load();
  1532. // now that the mode is set, we need to force an update because we
  1533. // explicitly avoided the update during BandSite_Load
  1534. _UpdateVertical(_uStuckPlace, TRUE);
  1535. BandSite_Update(_ptbs);
  1536. BandSite_UIActivateDBC(_ptbs, DBC_SHOW);
  1537. BandSite_FindBand(_ptbs, CLSID_TaskBand, IID_PPV_ARG(IDeskBand, &_pdbTasks), NULL, NULL);
  1538. IUnknown_GetWindow(_pdbTasks, &_hwndTasks);
  1539. // Now that bandsite is ready, set the correct size
  1540. // BUG: 606284 was caused by the tray do _HandleSizing before the BandSite's band were ready to go
  1541. // they all had their default band size of 0,0 so the tray became 0 px height
  1542. _fBandSiteInitialized = TRUE;
  1543. VerifySize(FALSE, TRUE);
  1544. }
  1545. void CTray::_KickStartAutohide()
  1546. {
  1547. if (_uAutoHide & AH_ON)
  1548. {
  1549. // tray always starts out hidden on autohide
  1550. _uAutoHide = AH_ON | AH_HIDING;
  1551. // we and many apps rely upon us having calculated the size correctly
  1552. Unhide();
  1553. // register it
  1554. if (!_AppBarSetAutoHideBar2(_hwnd, TRUE, _uStuckPlace))
  1555. {
  1556. // don't bother putting up UI in this case
  1557. // if someone is there just silently convert to normal
  1558. // (the shell is booting who would be there anyway?)
  1559. _SetAutoHideState(FALSE);
  1560. }
  1561. }
  1562. }
  1563. void CTray::_InitNonzeroGlobals()
  1564. {
  1565. // initalize globals that need to be non-zero
  1566. if (GetSystemMetrics(SM_SLOWMACHINE))
  1567. {
  1568. _dtSlideHide = 0; // dont slide the tray out
  1569. _dtSlideShow = 0;
  1570. }
  1571. else
  1572. {
  1573. _dtSlideHide = 400;
  1574. _dtSlideShow = 200;
  1575. }
  1576. _RefreshSettings();
  1577. }
  1578. void CTray::_CreateTrayWindow()
  1579. {
  1580. _InitTrayClass();
  1581. _uMsgEnableUserTrackedBalloonTips = RegisterWindowMessage(ENABLE_BALLOONTIP_MESSAGE);
  1582. _fNoToolbarsOnTaskbarPolicyEnabled = (SHRestricted(REST_NOTOOLBARSONTASKBAR) != 0);
  1583. DWORD dwExStyle = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW;
  1584. // Don't fadein because layered windows suck
  1585. // If you create a layered window on a non-active desktop then the window goes black
  1586. dwExStyle |= IS_BIDI_LOCALIZED_SYSTEM() ? dwExStyleRTLMirrorWnd : 0L;
  1587. CreateWindowEx(dwExStyle, TEXT(WNDCLASS_TRAYNOTIFY), NULL,
  1588. WS_CLIPCHILDREN | WS_POPUP,
  1589. 0, 0, 0, 0, NULL, NULL, hinstCabinet, (void*)this);
  1590. }
  1591. DWORD WINAPI CTray::SyncThreadProc(void *pv)
  1592. {
  1593. CTray* ptray = (CTray*)pv;
  1594. return ptray->_SyncThreadProc();
  1595. }
  1596. DWORD CTray::_SyncThreadProc()
  1597. {
  1598. if (g_dwStopWatchMode)
  1599. StopWatch_StartTimed(SWID_STARTUP, TEXT("_SyncThreadProc"), SPMODE_SHELL | SPMODE_DEBUGOUT, GetPerfTime());
  1600. if (g_dwProfileCAP & 0x00000002)
  1601. StartCAP();
  1602. InitializeCriticalSection(&_csHotkey);
  1603. OleInitialize(NULL); // matched in MainThreadProc()
  1604. ClassFactory_Start();
  1605. _InitNonzeroGlobals();
  1606. _ssomgr.Init();
  1607. //
  1608. // Watch the registry key that tells us which app is the default
  1609. // web browser, so we can track it in
  1610. // HKLM\Software\Clients\StartMenuInternet. We have to track it
  1611. // ourselves because downlevel browsers won't know about it.
  1612. //
  1613. // We need to do this only if we have write access to the key.
  1614. // (If we don't have write access, then we can't change it,
  1615. // so there's no point watching for it to change...)
  1616. //
  1617. // Well, okay, even if we only have read access, we have to do
  1618. // it once in case it changed while we were logged off.
  1619. //
  1620. // The order of these operations is important...
  1621. //
  1622. // 1. Migrate browser settings.
  1623. // 2. Build default MFU. (Depends on browser settings.)
  1624. // 3. Create tray window. (Relies on value MFU.)
  1625. //
  1626. _hHTTPEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
  1627. if (_hHTTPEvent)
  1628. {
  1629. // Make one migration pass immediately so HandleFirstTime
  1630. // sees good information. This also kick-starts the
  1631. // registry change notification process if the current user
  1632. // has write permission.
  1633. _MigrateOldBrowserSettings();
  1634. if (RegisterWaitForSingleObject(&_hHTTPWait, _hHTTPEvent,
  1635. _MigrateOldBrowserSettingsCB, this,
  1636. INFINITE, WT_EXECUTEDEFAULT))
  1637. {
  1638. // Yay, everything is fine.
  1639. }
  1640. }
  1641. // Build the default MFU if necessary
  1642. HandleFirstTime();
  1643. _CreateTrayWindow();
  1644. if (_hwnd && _ptbs)
  1645. {
  1646. _ResetZorder(); // obey the "always on top" flag
  1647. _KickStartAutohide();
  1648. _InitBandsite();
  1649. _ClipWindow(TRUE); // make sure we clip the taskbar to the current monitor before showing it
  1650. // it looks really strange for the tray to pop up and rehide at logon
  1651. // if we are autohide don't activate the tray when we show it
  1652. // if we aren't autohide do what Win95 did (tray is active by default)
  1653. ShowWindow(_hwnd, (_uAutoHide & AH_HIDING) ? SW_SHOWNA : SW_SHOW);
  1654. UpdateWindow(_hwnd);
  1655. _StuckTrayChange();
  1656. // get the system background scheduler thread
  1657. IShellTaskScheduler* pScheduler;
  1658. if (SUCCEEDED(CoCreateInstance(CLSID_SharedTaskScheduler, NULL, CLSCTX_INPROC,
  1659. IID_PPV_ARG(IShellTaskScheduler, &pScheduler))))
  1660. {
  1661. AddMenuItemsCacheTask(pScheduler, Tray_StartPanelEnabled());
  1662. pScheduler->Release();
  1663. }
  1664. SetTimer(_hwnd, IDT_HANDLEDELAYBOOTSTUFF, 5 * 1000, NULL);
  1665. }
  1666. if (g_dwProfileCAP & 0x00020000)
  1667. StopCAP();
  1668. if (g_dwStopWatchMode)
  1669. StopWatch_StopTimed(SWID_STARTUP, TEXT("_SyncThreadProc"), SPMODE_SHELL | SPMODE_DEBUGOUT, GetPerfTime());
  1670. return FALSE;
  1671. }
  1672. // the rest of the thread proc that includes the message loop
  1673. DWORD WINAPI CTray::MainThreadProc(void *pv)
  1674. {
  1675. CTray* ptray = (CTray*)pv;
  1676. if (!ptray->_hwnd)
  1677. return FALSE;
  1678. ptray->_OnCreateAsync();
  1679. PERFSETMARK("ExplorerStartMenuReady");
  1680. ptray->_MessageLoop();
  1681. ClassFactory_Stop();
  1682. OleUninitialize(); // matched in _SyncThreadProc()
  1683. return FALSE;
  1684. }
  1685. #define DM_IANELHK 0
  1686. #define HKIF_NULL 0
  1687. #define HKIF_CACHED 1
  1688. #define HKIF_FREEPIDLS 2
  1689. typedef struct
  1690. {
  1691. LPITEMIDLIST pidlFolder;
  1692. LPITEMIDLIST pidlItem;
  1693. WORD wGHotkey;
  1694. WORD wFlags;
  1695. } HOTKEYITEM;
  1696. UINT CTray::_HotkeyGetFreeItemIndex(void)
  1697. {
  1698. int i, cItems;
  1699. HOTKEYITEM *phki;
  1700. ASSERT(IS_VALID_HANDLE(_hdsaHKI, DSA));
  1701. cItems = DSA_GetItemCount(_hdsaHKI);
  1702. for (i=0; i<cItems; i++)
  1703. {
  1704. phki = (HOTKEYITEM *)DSA_GetItemPtr(_hdsaHKI, i);
  1705. if (!phki->wGHotkey)
  1706. {
  1707. ASSERT(!phki->pidlFolder);
  1708. ASSERT(!phki->pidlItem);
  1709. break;
  1710. }
  1711. }
  1712. return i;
  1713. }
  1714. // Weird, Global hotkeys use different flags for modifiers than window hotkeys
  1715. // (and hotkeys returned by the hotkey control)
  1716. WORD _MapHotkeyToGlobalHotkey(WORD wHotkey)
  1717. {
  1718. UINT nMod = 0;
  1719. // Map the modifiers.
  1720. if (HIBYTE(wHotkey) & HOTKEYF_SHIFT)
  1721. nMod |= MOD_SHIFT;
  1722. if (HIBYTE(wHotkey) & HOTKEYF_CONTROL)
  1723. nMod |= MOD_CONTROL;
  1724. if (HIBYTE(wHotkey) & HOTKEYF_ALT)
  1725. nMod |= MOD_ALT;
  1726. UINT nVirtKey = LOBYTE(wHotkey);
  1727. return (WORD)((nMod*256) + nVirtKey);
  1728. }
  1729. // NB This takes a regular window hotkey not a global hotkey (it does
  1730. // the convertion for you).
  1731. int CTray::HotkeyAdd(WORD wHotkey, LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlItem, BOOL fClone)
  1732. {
  1733. if (wHotkey)
  1734. {
  1735. LPCITEMIDLIST pidl1, pidl2;
  1736. HOTKEYITEM hki;
  1737. EnterCriticalSection(&_csHotkey);
  1738. int i = _HotkeyGetFreeItemIndex();
  1739. ASSERT(IS_VALID_HANDLE(_hdsaHKI, DSA));
  1740. // DebugMsg(DM_IANELHK, "c.hl_a: Hotkey %x with id %d.", wHotkey, i);
  1741. if (fClone)
  1742. {
  1743. pidl1 = ILClone(pidlFolder);
  1744. pidl2 = ILClone(pidlItem);
  1745. hki.wFlags = HKIF_FREEPIDLS;
  1746. }
  1747. else
  1748. {
  1749. pidl1 = pidlFolder;
  1750. pidl2 = pidlItem;
  1751. hki.wFlags = HKIF_NULL;
  1752. }
  1753. hki.pidlFolder = (LPITEMIDLIST)pidl1;
  1754. hki.pidlItem = (LPITEMIDLIST)pidl2;
  1755. hki.wGHotkey = _MapHotkeyToGlobalHotkey(wHotkey);
  1756. DSA_SetItem(_hdsaHKI, i, &hki);
  1757. LeaveCriticalSection(&_csHotkey);
  1758. return i;
  1759. }
  1760. return -1;
  1761. }
  1762. // NB Cached hotkeys have their own pidls that need to be free but
  1763. // regular hotkeys just keep a pointer to pidls used by the startmenu and
  1764. // so don't.
  1765. int CTray::_HotkeyAddCached(WORD wGHotkey, LPITEMIDLIST pidl)
  1766. {
  1767. int i = -1;
  1768. if (wGHotkey)
  1769. {
  1770. LPITEMIDLIST pidlItem = ILClone(ILFindLastID(pidl));
  1771. ASSERT(IS_VALID_HANDLE(_hdsaHKI, DSA));
  1772. if (pidlItem)
  1773. {
  1774. if (ILRemoveLastID(pidl))
  1775. {
  1776. HOTKEYITEM hki;
  1777. EnterCriticalSection(&_csHotkey);
  1778. i = _HotkeyGetFreeItemIndex();
  1779. // DebugMsg(DM_IANELHK, "c.hl_ac: Hotkey %x with id %d.", wGHotkey, i);
  1780. hki.pidlFolder = pidl;
  1781. hki.pidlItem = pidlItem;
  1782. hki.wGHotkey = wGHotkey;
  1783. hki.wFlags = HKIF_CACHED | HKIF_FREEPIDLS;
  1784. DSA_SetItem(_hdsaHKI, i, &hki);
  1785. LeaveCriticalSection(&_csHotkey);
  1786. }
  1787. }
  1788. }
  1789. return i;
  1790. }
  1791. // NB Again, this takes window hotkey not a Global one.
  1792. // NB This doesn't delete cached hotkeys.
  1793. int CTray::_HotkeyRemove(WORD wHotkey)
  1794. {
  1795. int iRet = -1;
  1796. if (EVAL(_hdsaHKI))
  1797. {
  1798. int i, cItems;
  1799. HOTKEYITEM *phki;
  1800. WORD wGHotkey;
  1801. ASSERT(IS_VALID_HANDLE(_hdsaHKI, DSA));
  1802. // DebugMsg(DM_IANELHK, "c.hl_r: Remove hotkey for %x" , wHotkey);
  1803. // Unmap the modifiers.
  1804. wGHotkey = _MapHotkeyToGlobalHotkey(wHotkey);
  1805. EnterCriticalSection(&_csHotkey);
  1806. cItems = DSA_GetItemCount(_hdsaHKI);
  1807. for (i=0; i<cItems; i++)
  1808. {
  1809. phki = (HOTKEYITEM *)DSA_GetItemPtr(_hdsaHKI, i);
  1810. if (phki && !(phki->wFlags & HKIF_CACHED) && (phki->wGHotkey == wGHotkey))
  1811. {
  1812. // DebugMsg(DM_IANELHK, "c.hl_r: Invalidating %d", i);
  1813. if (phki->wFlags & HKIF_FREEPIDLS)
  1814. {
  1815. if (phki->pidlFolder)
  1816. ILFree(phki->pidlFolder);
  1817. if (phki->pidlItem)
  1818. ILFree(phki->pidlItem);
  1819. }
  1820. phki->wGHotkey = 0;
  1821. phki->pidlFolder = NULL;
  1822. phki->pidlItem = NULL;
  1823. phki->wFlags &= ~HKIF_FREEPIDLS;
  1824. iRet = i;
  1825. break;
  1826. }
  1827. }
  1828. LeaveCriticalSection(&_csHotkey);
  1829. }
  1830. return iRet;
  1831. }
  1832. // NB This takes a global hotkey.
  1833. int CTray::_HotkeyRemoveCached(WORD wGHotkey)
  1834. {
  1835. int iRet = -1;
  1836. int i, cItems;
  1837. HOTKEYITEM *phki;
  1838. ASSERT(IS_VALID_HANDLE(_hdsaHKI, DSA));
  1839. // DebugMsg(DM_IANELHK, "c.hl_rc: Remove hotkey for %x" , wGHotkey);
  1840. EnterCriticalSection(&_csHotkey);
  1841. cItems = DSA_GetItemCount(_hdsaHKI);
  1842. for (i=0; i<cItems; i++)
  1843. {
  1844. phki = (HOTKEYITEM *)DSA_GetItemPtr(_hdsaHKI, i);
  1845. if (phki && (phki->wFlags & HKIF_CACHED) && (phki->wGHotkey == wGHotkey))
  1846. {
  1847. // DebugMsg(DM_IANELHK, "c.hl_r: Invalidating %d", i);
  1848. if (phki->wFlags & HKIF_FREEPIDLS)
  1849. {
  1850. if (phki->pidlFolder)
  1851. ILFree(phki->pidlFolder);
  1852. if (phki->pidlItem)
  1853. ILFree(phki->pidlItem);
  1854. }
  1855. phki->pidlFolder = NULL;
  1856. phki->pidlItem = NULL;
  1857. phki->wGHotkey = 0;
  1858. phki->wFlags &= ~(HKIF_CACHED | HKIF_FREEPIDLS);
  1859. iRet = i;
  1860. break;
  1861. }
  1862. }
  1863. LeaveCriticalSection(&_csHotkey);
  1864. return iRet;
  1865. }
  1866. // NB Some (the ones not marked HKIF_FREEPIDLS) of the items in the list of hotkeys
  1867. // have pointers to idlists used by the filemenu so they are only valid for
  1868. // the lifetime of the filemenu.
  1869. BOOL CTray::_HotkeyCreate(void)
  1870. {
  1871. if (!_hdsaHKI)
  1872. {
  1873. // DebugMsg(DM_TRACE, "c.hkl_c: Creating global hotkey list.");
  1874. _hdsaHKI = DSA_Create(sizeof(HOTKEYITEM), 0);
  1875. }
  1876. if (_hdsaHKI)
  1877. return TRUE;
  1878. return FALSE;
  1879. }
  1880. void CTray::_BuildStartMenu()
  1881. {
  1882. HRESULT hr;
  1883. ClosePopupMenus();
  1884. //
  1885. // Avoid redundant rebuilds: Peek out any pending SBM_REBUILDMENU messages
  1886. // since the rebuild we're about to do will take care of it. Do this
  1887. // before destroying the Start Menu so we never yield while there isn't
  1888. // a Start Menu.
  1889. //
  1890. MSG msg;
  1891. while (PeekMessage(&msg, _hwnd, SBM_REBUILDMENU, SBM_REBUILDMENU, PM_REMOVE | PM_NOYIELD))
  1892. {
  1893. // Keep sucking them out
  1894. }
  1895. _DestroyStartMenu();
  1896. if (Tray_StartPanelEnabled())
  1897. {
  1898. hr = DesktopV2_Create(&_pmpStartPane, &_pmbStartPane, &_pvStartPane);
  1899. DesktopV2_Build(_pvStartPane);
  1900. }
  1901. else
  1902. {
  1903. hr = StartMenuHost_Create(&_pmpStartMenu, &_pmbStartMenu);
  1904. if (SUCCEEDED(hr))
  1905. {
  1906. IBanneredBar* pbb;
  1907. hr = _pmpStartMenu->QueryInterface(IID_PPV_ARG(IBanneredBar, &pbb));
  1908. if (SUCCEEDED(hr))
  1909. {
  1910. pbb->SetBitmap(_hbmpStartBkg);
  1911. if (_fSMSmallIcons)
  1912. pbb->SetIconSize(BMICON_SMALL);
  1913. else
  1914. pbb->SetIconSize(BMICON_LARGE);
  1915. pbb->Release();
  1916. }
  1917. }
  1918. }
  1919. if (FAILED(hr))
  1920. {
  1921. TraceMsg(TF_ERROR, "Could not create StartMenu");
  1922. }
  1923. }
  1924. void CTray::_DestroyStartMenu()
  1925. {
  1926. IUnknown_SetSite(_pmpStartMenu, NULL);
  1927. ATOMICRELEASET(_pmpStartMenu, IMenuPopup);
  1928. ATOMICRELEASET(_pmbStartMenu, IMenuBand);
  1929. IUnknown_SetSite(_pmpStartPane, NULL);
  1930. ATOMICRELEASET(_pmpStartPane, IMenuPopup);
  1931. ATOMICRELEASET(_pmbStartPane, IMenuBand);
  1932. ATOMICRELEASET(_pmpTasks, IMenuPopup);
  1933. ATOMICRELEASET(_pmbTasks, IMenuBand);
  1934. }
  1935. void CTray::ForceStartButtonUp()
  1936. {
  1937. MSG msg;
  1938. // don't do that check message pos because it gets screwy with
  1939. // keyboard cancel. and besides, we always want it cleared after
  1940. // track menu popup is done.
  1941. // do it twice to be sure it's up due to the _uDown cycling twice in
  1942. // the subclassing stuff
  1943. // pull off any button downs
  1944. PeekMessage(&msg, _hwndStart, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE);
  1945. SendMessage(_hwndStart, BM_SETSTATE, FALSE, 0);
  1946. SendMessage(_hwndStart, BM_SETSTATE, FALSE, 0);
  1947. if (_hwndTasks)
  1948. SendMessage(_hwndTasks, TBC_SETPREVFOCUS, 0, NULL);
  1949. PostMessage(_hwnd, TM_STARTMENUDISMISSED, 0, 0);
  1950. }
  1951. void Tray_OnStartMenuDismissed()
  1952. {
  1953. c_tray._bMainMenuInit = FALSE;
  1954. // Tell the Start Button that it's allowed to be in the up position now. This
  1955. // prevents the problem where the start menu is displayed but the button is
  1956. // in the up position... This happens when dialog boxes are displayed
  1957. c_tray._fAllowUp = TRUE;
  1958. // Now tell it to be in the up position
  1959. c_tray.ForceStartButtonUp();
  1960. PostMessage(v_hwndTray, TM_SHOWTRAYBALLOON, TRUE, 0);
  1961. }
  1962. #ifdef FEATURE_STARTPAGE
  1963. void Tray_OnStartPageDismissed()
  1964. {
  1965. if (g_fDesktopRaised)
  1966. c_tray._RaiseDesktop(!g_fDesktopRaised, TRUE);
  1967. Tray_OnStartMenuDismissed();
  1968. }
  1969. void Tray_MenuInvoke(int idCmd)
  1970. {
  1971. c_tray.ContextMenuInvoke(idCmd);
  1972. }
  1973. #endif
  1974. int CTray::_TrackMenu(HMENU hmenu)
  1975. {
  1976. TPMPARAMS tpm;
  1977. int iret;
  1978. tpm.cbSize = sizeof(tpm);
  1979. GetClientRect(_hwndStart, &tpm.rcExclude);
  1980. RECT rcClient;
  1981. GetClientRect(_hwnd, &rcClient);
  1982. tpm.rcExclude.bottom = min(tpm.rcExclude.bottom, rcClient.bottom);
  1983. MapWindowPoints(_hwndStart, NULL, (LPPOINT)&tpm.rcExclude, 2);
  1984. SendMessage(_hwndTrayTips, TTM_ACTIVATE, FALSE, 0L);
  1985. iret = TrackPopupMenuEx(hmenu, TPM_VERTICAL | TPM_BOTTOMALIGN | TPM_RETURNCMD,
  1986. tpm.rcExclude.left, tpm.rcExclude.bottom, _hwnd, &tpm);
  1987. SendMessage(_hwndTrayTips, TTM_ACTIVATE, TRUE, 0L);
  1988. return iret;
  1989. }
  1990. /*------------------------------------------------------------------
  1991. ** Respond to a button's pressing by bringing up the appropriate menu.
  1992. ** Clean up the button depression when the menu is dismissed.
  1993. **------------------------------------------------------------------*/
  1994. void CTray::_ToolbarMenu()
  1995. {
  1996. RECTL rcExclude;
  1997. POINTL ptPop;
  1998. DWORD dwFlags = MPPF_KEYBOARD; // Assume that we're popuping
  1999. // up because of the keyboard
  2000. // This is for the underlines on NT5
  2001. if (_hwndTasks)
  2002. SendMessage(_hwndTasks, TBC_FREEPOPUPMENUS, 0, 0);
  2003. if (_hwndStartBalloon)
  2004. {
  2005. _DontShowTheStartButtonBalloonAnyMore();
  2006. ShowWindow(_hwndStartBalloon, SW_HIDE);
  2007. _DestroyStartButtonBalloon();
  2008. }
  2009. SetActiveWindow(_hwnd);
  2010. _bMainMenuInit = TRUE;
  2011. // Exclude rect is the VISIBLE portion of the Start Button.
  2012. {
  2013. RECT rcParent;
  2014. GetClientRect(_hwndStart, (RECT *)&rcExclude);
  2015. MapWindowRect(_hwndStart, HWND_DESKTOP, &rcExclude);
  2016. GetClientRect(_hwnd, &rcParent);
  2017. MapWindowRect(_hwnd, HWND_DESKTOP, &rcParent);
  2018. IntersectRect((RECT*)&rcExclude, (RECT*)&rcExclude, &rcParent);
  2019. }
  2020. ptPop.x = rcExclude.left;
  2021. ptPop.y = rcExclude.top;
  2022. // Close any Context Menus
  2023. SendMessage(_hwnd, WM_CANCELMODE, 0, 0);
  2024. // Is the "Activate" button down (If the buttons are swapped, then it's the
  2025. // right button, otherwise the left button)
  2026. if (GetKeyState(GetSystemMetrics(SM_SWAPBUTTON)?VK_RBUTTON:VK_LBUTTON) < 0)
  2027. {
  2028. dwFlags = 0; // Then set to the default
  2029. }
  2030. #ifdef FEATURE_STARTPAGE
  2031. if(!(GetAsyncKeyState(VK_SHIFT) < 0) && Tray_ShowStartPageEnabled()) //If the start page is on, then just raise the desktop!
  2032. {
  2033. _hwndFocusBeforeRaise = GetForegroundWindow();
  2034. _RaiseDesktop(TRUE, TRUE);
  2035. Tray_SetStartPaneActive(TRUE);
  2036. }
  2037. else
  2038. #endif //FEATURE_STARTPAGE
  2039. {
  2040. IMenuPopup **ppmpToDisplay = &_pmpStartMenu;
  2041. if (_pmpStartPane)
  2042. {
  2043. ppmpToDisplay = &_pmpStartPane;
  2044. }
  2045. // Close race window: The user can click on the Start Button
  2046. // before we get a chance to rebuild the Start Menu in its new
  2047. // form. In such case, rebuild it now.
  2048. if (!*ppmpToDisplay)
  2049. {
  2050. TraceMsg(TF_WARNING, "e.tbm: Rebuilding Start Menu");
  2051. _BuildStartMenu();
  2052. }
  2053. if (*ppmpToDisplay && SUCCEEDED((*ppmpToDisplay)->Popup(&ptPop, &rcExclude, dwFlags)))
  2054. {
  2055. // All is well - the menu is up
  2056. TraceMsg(DM_MISC, "e.tbm: dwFlags=%x (0=mouse 1=key)", dwFlags);
  2057. }
  2058. else
  2059. {
  2060. TraceMsg(TF_WARNING, "e.tbm: %08x->Popup failed", *ppmpToDisplay);
  2061. // Start Menu failed to display -- reset the Start Button
  2062. // so the user can click it again to try again
  2063. Tray_OnStartMenuDismissed();
  2064. }
  2065. if (dwFlags == MPPF_KEYBOARD)
  2066. {
  2067. // Since the user has launched the start button by Ctrl-Esc, or some other worldly
  2068. // means, then turn the rect on.
  2069. SendMessage(_hwndStart, WM_UPDATEUISTATE, MAKEWPARAM(UIS_CLEAR,
  2070. UISF_HIDEFOCUS), 0);
  2071. }
  2072. }
  2073. }
  2074. HRESULT CTray::_AppBarSetState(UINT uFlags)
  2075. {
  2076. if (uFlags & ~(ABS_AUTOHIDE | ABS_ALWAYSONTOP))
  2077. {
  2078. return E_INVALIDARG;
  2079. }
  2080. else
  2081. {
  2082. _SetAutoHideState(uFlags & ABS_AUTOHIDE);
  2083. _UpdateAlwaysOnTop(uFlags & ABS_ALWAYSONTOP);
  2084. return S_OK;
  2085. }
  2086. }
  2087. //
  2088. // can't use SubtractRect sometimes because of inclusion limitations
  2089. //
  2090. void CTray::_AppBarSubtractRect(PAPPBAR pab, LPRECT lprc)
  2091. {
  2092. switch (pab->uEdge) {
  2093. case ABE_TOP:
  2094. if (pab->rc.bottom > lprc->top)
  2095. lprc->top = pab->rc.bottom;
  2096. break;
  2097. case ABE_LEFT:
  2098. if (pab->rc.right > lprc->left)
  2099. lprc->left = pab->rc.right;
  2100. break;
  2101. case ABE_BOTTOM:
  2102. if (pab->rc.top < lprc->bottom)
  2103. lprc->bottom = pab->rc.top;
  2104. break;
  2105. case ABE_RIGHT:
  2106. if (pab->rc.left < lprc->right)
  2107. lprc->right = pab->rc.left;
  2108. break;
  2109. }
  2110. }
  2111. void CTray::_AppBarSubtractRects(HMONITOR hmon, LPRECT lprc)
  2112. {
  2113. int i;
  2114. if (!_hdpaAppBars)
  2115. return;
  2116. i = DPA_GetPtrCount(_hdpaAppBars);
  2117. while (i--)
  2118. {
  2119. PAPPBAR pab = (PAPPBAR)DPA_GetPtr(_hdpaAppBars, i);
  2120. //
  2121. // autohide bars are not in our DPA or live on the edge
  2122. // don't subtract the appbar if it's on a different display
  2123. // don't subtract the appbar if we are in a locked desktop
  2124. //
  2125. // if (hmon == MonitorFromRect(&pab->rc, MONITOR_DEFAULTTONULL))
  2126. if (hmon == MonitorFromRect(&pab->rc, MONITOR_DEFAULTTONULL) && !_fIsDesktopLocked)
  2127. _AppBarSubtractRect(pab, lprc);
  2128. }
  2129. }
  2130. #define RWA_NOCHANGE 0
  2131. #define RWA_CHANGED 1
  2132. #define RWA_BOTTOMMOSTTRAY 2
  2133. // (dli) This is a hack put in because bottommost tray is wierd, once
  2134. // it becomes a toolbar, this code should go away.
  2135. // In the bottommost tray case, even though the work area has not changed,
  2136. // we should notify the desktop.
  2137. int CTray::_RecomputeWorkArea(HWND hwndCause, HMONITOR hmon, LPRECT prcWork)
  2138. {
  2139. int iRet = RWA_NOCHANGE;
  2140. MONITORINFO mi;
  2141. mi.cbSize = sizeof(mi);
  2142. if (_fIsLogoff)
  2143. {
  2144. if (GetMonitorInfo(hmon, &mi))
  2145. {
  2146. *prcWork = mi.rcMonitor;
  2147. iRet = RWA_CHANGED;
  2148. }
  2149. return iRet;
  2150. }
  2151. ASSERT(!_fIsLogoff);
  2152. //
  2153. // tell everybody that this window changed positions _on_this_monitor_
  2154. // note that this notify happens even if we don't change the work area
  2155. // since it may cause another app to change the work area...
  2156. //
  2157. PostMessage(_hwnd, TM_RELAYPOSCHANGED, (WPARAM)hwndCause, (LPARAM)hmon);
  2158. //
  2159. // get the current info for this monitor
  2160. // we subtract down from the display rectangle to build the work area
  2161. //
  2162. if (GetMonitorInfo(hmon, &mi))
  2163. {
  2164. //
  2165. // don't subtract the tray if it is autohide
  2166. // don't subtract the tray if it is not always on top
  2167. // don't subtract the tray if it's on a different display
  2168. // don't subtract the tray if it is on a different desktop
  2169. //
  2170. if (!(_uAutoHide & AH_ON) && _fAlwaysOnTop &&
  2171. (hmon == _hmonStuck) && !_fIsDesktopLocked)
  2172. {
  2173. SubtractRect(prcWork, &mi.rcMonitor,
  2174. &_arStuckRects[_uStuckPlace]);
  2175. }
  2176. else
  2177. *prcWork = mi.rcMonitor;
  2178. //
  2179. // now subtract off all the appbars on this display
  2180. //
  2181. _AppBarSubtractRects(hmon, prcWork);
  2182. //
  2183. // return whether we changed anything
  2184. //
  2185. if (!EqualRect(prcWork, &mi.rcWork))
  2186. iRet = RWA_CHANGED;
  2187. else if (!(_uAutoHide & AH_ON) && (!_fAlwaysOnTop) &&
  2188. (!IsRectEmpty(&_arStuckRects[_uStuckPlace])))
  2189. // NOTE: This is the bottommost case, it only applies for the tray.
  2190. // this should be taken out when bottommost tray becomes toolbar
  2191. iRet = RWA_BOTTOMMOSTTRAY;
  2192. }
  2193. else
  2194. {
  2195. iRet = RWA_NOCHANGE;
  2196. }
  2197. return iRet;
  2198. }
  2199. void RedrawDesktop(RECT *prcWork)
  2200. {
  2201. // This rect point should always be valid (dli)
  2202. RIP(prcWork);
  2203. if (v_hwndDesktop && g_fCleanBoot)
  2204. {
  2205. MapWindowRect(NULL, v_hwndDesktop, prcWork);
  2206. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.sac invalidating desktop rect {%d,%d,%d,%d}"), prcWork->left, prcWork->top, prcWork->right, prcWork->bottom);
  2207. RedrawWindow(v_hwndDesktop, prcWork, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN);
  2208. }
  2209. }
  2210. void CTray::_StuckAppChange(HWND hwndCause, LPCRECT prcOld, LPCRECT prcNew, BOOL bTray)
  2211. {
  2212. RECT rcWork1, rcWork2;
  2213. HMONITOR hmon1, hmon2 = 0;
  2214. int iChange = 0;
  2215. //
  2216. // PERF FEATURE:
  2217. // there are cases where we end up setting the work area multiple times
  2218. // we need to keep a static array of displays that have changed and a
  2219. // reenter count so we can avoid pain of sending notifies to the whole
  2220. // planet...
  2221. //
  2222. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.sac from_AppBar %08X"), hwndCause);
  2223. //
  2224. // see if the work area changed on the display containing prcOld
  2225. //
  2226. if (prcOld)
  2227. {
  2228. if (bTray)
  2229. hmon1 = _hmonOld;
  2230. else
  2231. hmon1 = MonitorFromRect(prcOld, MONITOR_DEFAULTTONEAREST);
  2232. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.sac old pos {%d,%d,%d,%d} on monitor %08X"), prcOld->left, prcOld->top, prcOld->right, prcOld->bottom, hmon1);
  2233. if (hmon1)
  2234. {
  2235. int iret = _RecomputeWorkArea(hwndCause, hmon1, &rcWork1);
  2236. if (iret == RWA_CHANGED)
  2237. iChange = 1;
  2238. if (iret == RWA_BOTTOMMOSTTRAY)
  2239. iChange = 4;
  2240. }
  2241. }
  2242. else
  2243. hmon1 = NULL;
  2244. //
  2245. // see if the work area changed on the display containing prcNew
  2246. //
  2247. if (prcNew)
  2248. {
  2249. hmon2 = MonitorFromRect(prcNew, MONITOR_DEFAULTTONULL);
  2250. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.sac new pos {%d,%d,%d,%d} on monitor %08X"), prcNew->left, prcNew->top, prcNew->right, prcNew->bottom, hmon2);
  2251. if (hmon2 && (hmon2 != hmon1))
  2252. {
  2253. int iret = _RecomputeWorkArea(hwndCause, hmon2, &rcWork2);
  2254. if (iret == RWA_CHANGED)
  2255. iChange |= 2;
  2256. else if (iret == RWA_BOTTOMMOSTTRAY && (!iChange))
  2257. iChange = 4;
  2258. }
  2259. }
  2260. //
  2261. // did the prcOld's display's work area change?
  2262. //
  2263. if (iChange & 1)
  2264. {
  2265. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.sac changing work area for monitor %08X"), hmon1);
  2266. // only send SENDWININICHANGE if the desktop has been created (otherwise
  2267. // we will hang the explorer because the main thread is currently blocked)
  2268. SystemParametersInfo(SPI_SETWORKAREA, TRUE, &rcWork1,
  2269. (iChange == 1 && v_hwndDesktop)? SPIF_SENDWININICHANGE : 0);
  2270. RedrawDesktop(&rcWork1);
  2271. }
  2272. //
  2273. // did the prcOld's display's work area change?
  2274. //
  2275. if (iChange & 2)
  2276. {
  2277. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.sac changing work area for monitor %08X"), hmon2);
  2278. // only send SENDWININICHANGE if the desktop has been created (otherwise
  2279. // we will hang the explorer because the main thread is currently blocked)
  2280. SystemParametersInfo(SPI_SETWORKAREA, TRUE, &rcWork2,
  2281. v_hwndDesktop ? SPIF_SENDWININICHANGE : 0);
  2282. RedrawDesktop(&rcWork2);
  2283. }
  2284. // only send if the desktop has been created...
  2285. // need to send if it's from the tray or any outside app that causes size change
  2286. // from the tray because autohideness will affect desktop size even if it's not always on top
  2287. if ((bTray || iChange == 4) && v_hwndDesktop)
  2288. SendMessage(v_hwndDesktop, WM_SIZE, 0, 0);
  2289. }
  2290. void CTray::_StuckTrayChange()
  2291. {
  2292. // We used to blow off the _StuckAppChange when the tray was in autohide
  2293. // mode, since moving or resizing an autohid tray doesn't change the
  2294. // work area. Now we go ahead with the _StuckAppChange in this case
  2295. // too. The reason is that we can get into a state where the work area
  2296. // size is incorrect, and we want the taskbar to always be self-repairing
  2297. // in this case (so that resizing or moving the taskbar will correct the
  2298. // work area size).
  2299. //
  2300. // pass a NULL window here since we don't want to hand out our window and
  2301. // the tray doesn't get these anyway (nobody cares as long as its not them)
  2302. //
  2303. _StuckAppChange(NULL, &_rcOldTray,
  2304. &_arStuckRects[_uStuckPlace], TRUE);
  2305. //
  2306. // save off the new tray position...
  2307. //
  2308. _rcOldTray = _arStuckRects[_uStuckPlace];
  2309. }
  2310. UINT CTray::_RecalcStuckPos(LPRECT prc)
  2311. {
  2312. RECT rcDummy;
  2313. POINT pt;
  2314. if (!prc)
  2315. {
  2316. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.t_rsp no rect supplied, using window rect"));
  2317. prc = &rcDummy;
  2318. GetWindowRect(_hwnd, prc);
  2319. }
  2320. // use the center of the original drag rect as a staring point
  2321. pt.x = prc->left + RECTWIDTH(*prc) / 2;
  2322. pt.y = prc->top + RECTHEIGHT(*prc) / 2;
  2323. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.t_rsp rect is {%d, %d, %d, %d} point is {%d, %d}"), prc->left, prc->top, prc->right, prc->bottom, pt.x, pt.y);
  2324. // reset this so the drag code won't give it preference
  2325. _uMoveStuckPlace = (UINT)-1;
  2326. // simulate a drag back to figure out where we originated from
  2327. // you may be tempted to remove this. before you do think about dragging
  2328. // the tray across monitors and then hitting ESC...
  2329. return _CalcDragPlace(pt);
  2330. }
  2331. /*------------------------------------------------------------------
  2332. ** the position is changing in response to a move operation.
  2333. **
  2334. ** if the docking status changed, we need to get a new size and
  2335. ** maybe a new frame style. change the WINDOWPOS to reflect
  2336. ** these changes accordingly.
  2337. **------------------------------------------------------------------*/
  2338. void CTray::_DoneMoving(LPWINDOWPOS lpwp)
  2339. {
  2340. RECT rc, *prc;
  2341. if ((_uMoveStuckPlace == (UINT)-1) || (_fIgnoreDoneMoving))
  2342. return;
  2343. if (_fSysSizing)
  2344. _fDeferedPosRectChange = TRUE;
  2345. rc.left = lpwp->x;
  2346. rc.top = lpwp->y;
  2347. rc.right = lpwp->x + lpwp->cx;
  2348. rc.bottom = lpwp->y + lpwp->cy;
  2349. prc = &_arStuckRects[_uMoveStuckPlace];
  2350. if (!EqualRect(prc, &rc))
  2351. {
  2352. _uMoveStuckPlace = _RecalcStuckPos(&rc);
  2353. prc = &_arStuckRects[_uMoveStuckPlace];
  2354. }
  2355. // Get the new hmonitor
  2356. _hmonStuck = MonitorFromRect(prc, MONITOR_DEFAULTTONEAREST);
  2357. lpwp->x = prc->left;
  2358. lpwp->y = prc->top;
  2359. lpwp->cx = RECTWIDTH(*prc);
  2360. lpwp->cy = RECTHEIGHT(*prc);
  2361. lpwp->flags &= ~(SWP_NOMOVE | SWP_NOSIZE);
  2362. // if we were autohiding, we need to update our appbar autohide rect
  2363. if (_uAutoHide & AH_ON)
  2364. {
  2365. // unregister us from the old side
  2366. _AppBarSetAutoHideBar2(_hwnd, FALSE, _uStuckPlace);
  2367. }
  2368. // All that work might've changed _uMoveStuckPlace (since there
  2369. // was a lot of message traffic), so check one more time.
  2370. // Somehow, NT Stress manages to get us in here with an invalid
  2371. // uMoveStuckPlace.
  2372. if (IsValidSTUCKPLACE(_uMoveStuckPlace))
  2373. {
  2374. // remember the new state
  2375. _uStuckPlace = _uMoveStuckPlace;
  2376. }
  2377. _uMoveStuckPlace = (UINT)-1;
  2378. _UpdateVertical(_uStuckPlace);
  2379. _HandleSizing(0, prc, _uStuckPlace);
  2380. if ((_uAutoHide & AH_ON) &&
  2381. !_AppBarSetAutoHideBar2(_hwnd, TRUE, _uStuckPlace))
  2382. {
  2383. _AutoHideCollision();
  2384. }
  2385. }
  2386. UINT CTray::_CalcDragPlace(POINT pt)
  2387. {
  2388. UINT uPlace = _uMoveStuckPlace;
  2389. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.t_cdp starting point is {%d, %d}"), pt.x, pt.y);
  2390. //
  2391. // if the mouse is currently over the tray position leave it alone
  2392. //
  2393. if ((uPlace == (UINT)-1) || !PtInRect(&_arStuckRects[uPlace], pt))
  2394. {
  2395. HMONITOR hmonDrag;
  2396. SIZE screen, error;
  2397. UINT uHorzEdge, uVertEdge;
  2398. RECT rcDisplay, *prcStick;
  2399. //
  2400. // which display is the mouse on?
  2401. //
  2402. hmonDrag = _GetDisplayRectFromPoint(&rcDisplay, pt,
  2403. MONITOR_DEFAULTTOPRIMARY);
  2404. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.t_cdp monitor is %08X"), hmonDrag);
  2405. //
  2406. // re-origin at zero to make calculations simpler
  2407. //
  2408. screen.cx = RECTWIDTH(rcDisplay);
  2409. screen.cy = RECTHEIGHT(rcDisplay);
  2410. pt.x -= rcDisplay.left;
  2411. pt.y -= rcDisplay.top;
  2412. //
  2413. // are we closer to the left or right side of this display?
  2414. //
  2415. if (pt.x < (screen.cx / 2))
  2416. {
  2417. uVertEdge = STICK_LEFT;
  2418. error.cx = pt.x;
  2419. }
  2420. else
  2421. {
  2422. uVertEdge = STICK_RIGHT;
  2423. error.cx = screen.cx - pt.x;
  2424. }
  2425. //
  2426. // are we closer to the top or bottom side of this display?
  2427. //
  2428. if (pt.y < (screen.cy / 2))
  2429. {
  2430. uHorzEdge = STICK_TOP;
  2431. error.cy = pt.y;
  2432. }
  2433. else
  2434. {
  2435. uHorzEdge = STICK_BOTTOM;
  2436. error.cy = screen.cy - pt.y;
  2437. }
  2438. //
  2439. // closer to a horizontal or vertical edge?
  2440. //
  2441. uPlace = ((error.cy * screen.cx) > (error.cx * screen.cy))?
  2442. uVertEdge : uHorzEdge;
  2443. // which StuckRect should we use?
  2444. prcStick = &_arStuckRects[uPlace];
  2445. //
  2446. // need to recalc stuck rect for new monitor?
  2447. //
  2448. if ((hmonDrag != _GetDisplayRectFromRect(NULL, prcStick,
  2449. MONITOR_DEFAULTTONULL)))
  2450. {
  2451. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.t_cdp re-snapping rect for new display"));
  2452. _MakeStuckRect(prcStick, &rcDisplay, _sStuckWidths, uPlace);
  2453. }
  2454. }
  2455. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.t_cdp edge is %d, rect is {%d, %d, %d, %d}"), uPlace, _arStuckRects[uPlace].left, _arStuckRects[uPlace].top, _arStuckRects[uPlace].right, _arStuckRects[uPlace].bottom);
  2456. ASSERT(IsValidSTUCKPLACE(uPlace));
  2457. return uPlace;
  2458. }
  2459. void CTray::_HandleMoving(WPARAM wParam, LPRECT lprc)
  2460. {
  2461. POINT ptCursor;
  2462. GetCursorPos(&ptCursor);
  2463. // If the cursor is not far from its starting point, then ignore it.
  2464. // A very common problem is the user clicks near the corner of the clock,
  2465. // twitches the mouse 5 pixels, and BLAM, their taskbar is now vertical
  2466. // and they don't know what they did or how to get it back.
  2467. if (g_fInSizeMove && PtInRect(&_rcSizeMoveIgnore, ptCursor))
  2468. {
  2469. // Ignore -- user is merely twitching
  2470. _uMoveStuckPlace = _uStuckPlace;
  2471. }
  2472. else
  2473. {
  2474. _uMoveStuckPlace = _CalcDragPlace(ptCursor);
  2475. }
  2476. *lprc = _arStuckRects[_uMoveStuckPlace];
  2477. _HandleSizing(wParam, lprc, _uMoveStuckPlace);
  2478. }
  2479. // store the tray size when dragging is finished
  2480. void CTray::_SnapshotStuckRectSize(UINT uPlace)
  2481. {
  2482. RECT rcDisplay, *prc = &_arStuckRects[uPlace];
  2483. //
  2484. // record the width of this stuck rect
  2485. //
  2486. if (STUCK_HORIZONTAL(uPlace))
  2487. _sStuckWidths.cy = RECTHEIGHT(*prc);
  2488. else
  2489. _sStuckWidths.cx = RECTWIDTH(*prc);
  2490. //
  2491. // we only present a horizontal or vertical size to the end user
  2492. // so update the StuckRect on the other side of the screen to match
  2493. //
  2494. _GetStuckDisplayRect(uPlace, &rcDisplay);
  2495. uPlace += 2;
  2496. uPlace %= 4;
  2497. prc = &_arStuckRects[uPlace];
  2498. _MakeStuckRect(prc, &rcDisplay, _sStuckWidths, uPlace);
  2499. }
  2500. // Size the icon area to fill as much of the tray window as it can.
  2501. void CTray::SizeWindows()
  2502. {
  2503. RECT rcView, rcNotify, rcClient;
  2504. int fHiding;
  2505. if (!_hwndRebar || !_hwnd || !_hwndNotify)
  2506. return;
  2507. fHiding = (_uAutoHide & AH_HIDING);
  2508. if (fHiding)
  2509. {
  2510. InvisibleUnhide(FALSE);
  2511. }
  2512. // remember our current size
  2513. _SnapshotStuckRectSize(_uStuckPlace);
  2514. GetClientRect(_hwnd, &rcClient);
  2515. _AlignStartButton();
  2516. _GetWindowSizes(_uStuckPlace, &rcClient, &rcView, &rcNotify);
  2517. InvalidateRect(_hwndStart, NULL, TRUE);
  2518. InvalidateRect(_hwnd, NULL, TRUE);
  2519. // position the view
  2520. SetWindowPos(_hwndRebar, NULL, rcView.left, rcView.top,
  2521. RECTWIDTH(rcView), RECTHEIGHT(rcView),
  2522. SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS);
  2523. UpdateWindow(_hwndRebar);
  2524. // And the clock
  2525. SetWindowPos(_hwndNotify, NULL, rcNotify.left, rcNotify.top,
  2526. RECTWIDTH(rcNotify), RECTHEIGHT(rcNotify),
  2527. SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS);
  2528. {
  2529. TOOLINFO ti;
  2530. HWND hwndClock = _GetClockWindow();
  2531. ti.cbSize = sizeof(ti);
  2532. ti.uFlags = 0;
  2533. ti.hwnd = _hwnd;
  2534. ti.lpszText = LPSTR_TEXTCALLBACK;
  2535. ti.uId = (UINT_PTR)hwndClock;
  2536. GetWindowRect(hwndClock, &ti.rect);
  2537. MapWindowPoints(HWND_DESKTOP, _hwnd, (LPPOINT)&ti.rect, 2);
  2538. SendMessage(_hwndTrayTips, TTM_NEWTOOLRECT, 0, (LPARAM)((LPTOOLINFO)&ti));
  2539. }
  2540. if (fHiding)
  2541. {
  2542. InvisibleUnhide(TRUE);
  2543. }
  2544. }
  2545. void CTray::_HandleSize()
  2546. {
  2547. //
  2548. // if somehow we got minimized go ahead and un-minimize
  2549. //
  2550. if (((GetWindowLong(_hwnd, GWL_STYLE)) & WS_MINIMIZE))
  2551. {
  2552. ASSERT(FALSE);
  2553. ShowWindow(_hwnd, SW_RESTORE);
  2554. }
  2555. //
  2556. // if we are in the move/size loop and are visible then
  2557. // re-snap the current stuck rect to the new window size
  2558. //
  2559. #ifdef DEBUG
  2560. if (_fSysSizing && (_uAutoHide & AH_HIDING)) {
  2561. TraceMsg(DM_TRACE, "fSysSize && hiding");
  2562. ASSERT(0);
  2563. }
  2564. #endif
  2565. if (_fSysSizing &&
  2566. ((_uAutoHide & (AH_ON | AH_HIDING)) != (AH_ON | AH_HIDING)))
  2567. {
  2568. _uStuckPlace = _RecalcStuckPos(NULL);
  2569. _UpdateVertical(_uStuckPlace);
  2570. }
  2571. //
  2572. // if we are in fulldrag or we are not in the middle of a move/size then
  2573. // we should resize all our child windows to reflect our new size
  2574. //
  2575. if (g_fDragFullWindows || !_fSysSizing)
  2576. SizeWindows();
  2577. //
  2578. // if we are just plain resized and we are visible we may need re-dock
  2579. //
  2580. if (!_fSysSizing && !_fSelfSizing && IsWindowVisible(_hwnd))
  2581. {
  2582. if (_uAutoHide & AH_ON)
  2583. {
  2584. UINT uPlace = _uStuckPlace;
  2585. HWND hwndOther =_AppBarGetAutoHideBar(uPlace);
  2586. //
  2587. // we sometimes defer checking for this until after a move
  2588. // so as to avoid interrupting a full-window-drag in progress
  2589. // if there is a different autohide window in our slot then whimper
  2590. //
  2591. if (hwndOther?
  2592. (hwndOther != _hwnd) :
  2593. !_AppBarSetAutoHideBar2(_hwnd, TRUE, uPlace))
  2594. {
  2595. _AutoHideCollision();
  2596. }
  2597. }
  2598. _StuckTrayChange();
  2599. //
  2600. // make sure we clip to tray to the current monitor (if necessary)
  2601. //
  2602. _ClipWindow(TRUE);
  2603. }
  2604. if (_hwndStartBalloon)
  2605. {
  2606. RECT rc;
  2607. GetWindowRect(_hwndStart, &rc);
  2608. SendMessage(_hwndStartBalloon, TTM_TRACKPOSITION, 0, MAKELONG((rc.left + rc.right)/2, rc.top));
  2609. SetWindowZorder(_hwndStartBalloon, HWND_TOPMOST);
  2610. }
  2611. }
  2612. BOOL _IsSliverHeight(int cy)
  2613. {
  2614. //
  2615. // Is this height clearly bigger than the pure-border height that you
  2616. // get when you resize the taskbar as small as it will go?
  2617. //
  2618. return (cy < (3 * (g_cyDlgFrame + g_cyBorder)));
  2619. }
  2620. BOOL CTray::_HandleSizing(WPARAM code, LPRECT lprc, UINT uStuckPlace)
  2621. {
  2622. BOOL fChangedSize = FALSE;
  2623. RECT rcDisplay;
  2624. SIZE sNewWidths;
  2625. RECT rcTemp;
  2626. BOOL fHiding;
  2627. if (!lprc)
  2628. {
  2629. rcTemp = _arStuckRects[uStuckPlace];
  2630. lprc = &rcTemp;
  2631. }
  2632. fHiding = (_uAutoHide & AH_HIDING);
  2633. if (fHiding)
  2634. {
  2635. InvisibleUnhide(FALSE);
  2636. }
  2637. //
  2638. // get the a bunch of relevant dimensions
  2639. //
  2640. // (dli) need to change this funciton or get rid of it
  2641. _GetDisplayRectFromRect(&rcDisplay, lprc, MONITOR_DEFAULTTONEAREST);
  2642. if (code)
  2643. {
  2644. // if code != 0, this is the user sizing.
  2645. // make sure they clip it to the screen.
  2646. RECT rcMax = rcDisplay;
  2647. if (!_hTheme)
  2648. {
  2649. InflateRect(&rcMax, g_cxEdge, g_cyEdge);
  2650. }
  2651. // don't do intersect rect because of sizing up from the bottom
  2652. // (when taskbar docked on bottom) confuses people
  2653. switch (uStuckPlace)
  2654. {
  2655. case STICK_LEFT:
  2656. lprc->left = rcMax.left;
  2657. break;
  2658. case STICK_TOP:
  2659. lprc->top = rcMax.top;
  2660. break;
  2661. case STICK_RIGHT:
  2662. lprc->right = rcMax.right;
  2663. break;
  2664. case STICK_BOTTOM:
  2665. lprc->top += (rcMax.bottom-lprc->bottom);
  2666. lprc->bottom = rcMax.bottom;
  2667. break;
  2668. }
  2669. }
  2670. //
  2671. // compute the new widths
  2672. // don't let either be more than half the screen
  2673. //
  2674. sNewWidths.cx = min(RECTWIDTH(*lprc), RECTWIDTH(rcDisplay) / 2);
  2675. sNewWidths.cy = min(RECTHEIGHT(*lprc), RECTHEIGHT(rcDisplay) / 2);
  2676. if (_hTheme && (_fCanSizeMove || _fShowSizingBarAlways))
  2677. {
  2678. sNewWidths.cy = max(_sizeSizingBar.cy, sNewWidths.cy);
  2679. }
  2680. //
  2681. // compute an initial size
  2682. //
  2683. _MakeStuckRect(lprc, &rcDisplay, sNewWidths, uStuckPlace);
  2684. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.t_hs starting rect is {%d, %d, %d, %d}"), lprc->left, lprc->top, lprc->right, lprc->bottom);
  2685. //
  2686. // negotiate the exact size with our children
  2687. //
  2688. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.t_hs tray is being calculated for %s"), STUCK_HORIZONTAL(uStuckPlace) ? TEXT("HORIZONTAL") : TEXT("VERTICAL"));
  2689. _UpdateVertical(uStuckPlace);
  2690. if (_ptbs && _fBandSiteInitialized)
  2691. {
  2692. IDeskBarClient* pdbc;
  2693. if (SUCCEEDED(_ptbs->QueryInterface(IID_PPV_ARG(IDeskBarClient, &pdbc))))
  2694. {
  2695. RECT rcClient = *lprc;
  2696. RECT rcOldClient = _arStuckRects[uStuckPlace];
  2697. // Go from a Window Rect to Client Rect
  2698. if (_hTheme && (_fCanSizeMove || _fShowSizingBarAlways))
  2699. {
  2700. _AdjustRectForSizingBar(uStuckPlace, &rcClient, -1);
  2701. _AdjustRectForSizingBar(uStuckPlace, &rcOldClient, -1);
  2702. }
  2703. else if (!_hTheme)
  2704. {
  2705. InflateRect(&rcClient, -g_cxFrame, -g_cyFrame);
  2706. InflateRect(&rcOldClient, -g_cxFrame, -g_cyFrame);
  2707. }
  2708. // Make rcClient start at 0,0, Rebar only used the right and bottom values of this rect
  2709. OffsetRect(&rcClient, -rcClient.left, -rcClient.top);
  2710. OffsetRect(&rcOldClient, -rcOldClient.left, -rcOldClient.top);
  2711. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.t_hs starting client rect is {%d, %d, %d, %d}"), rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
  2712. RECT rcNotify;
  2713. RECT rcView;
  2714. RECT rcOldView;
  2715. // Go from the taskbar's client rect to the rebar's client rect
  2716. _GetWindowSizes(uStuckPlace, &rcClient, &rcView, &rcNotify);
  2717. _GetWindowSizes(uStuckPlace, &rcOldClient, &rcOldView, &rcNotify);
  2718. // Make rcView start at 0,0, Rebar only used the right and bottom values of this rect
  2719. OffsetRect(&rcView, -rcView.left, -rcView.top);
  2720. OffsetRect(&rcOldView, -rcOldView.left, -rcOldView.top);
  2721. if (!_fCanSizeMove || (RECTHEIGHT(rcView) && RECTWIDTH(rcView)))
  2722. {
  2723. // This following function will cause a WINDOWPOSCHAGING which will call DoneMoving
  2724. // DoneMoving will then go a screw up all of the window sizing
  2725. _fIgnoreDoneMoving = TRUE;
  2726. pdbc->GetSize(DBC_GS_SIZEDOWN, &rcView);
  2727. _fIgnoreDoneMoving = FALSE;
  2728. }
  2729. // Go from a Client Rect to Window Rect
  2730. if (STUCK_HORIZONTAL(uStuckPlace))
  2731. {
  2732. rcClient.top = rcView.top;
  2733. rcClient.bottom = rcView.bottom;
  2734. }
  2735. else
  2736. {
  2737. rcClient.left = rcView.left;
  2738. rcClient.right = rcView.right;
  2739. }
  2740. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.t_hs ending client rect is {%d, %d, %d, %d}"), rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
  2741. if (_hTheme && (_fCanSizeMove || _fShowSizingBarAlways))
  2742. {
  2743. _AdjustRectForSizingBar(uStuckPlace, &rcClient, 1);
  2744. _AdjustRectForSizingBar(uStuckPlace, &rcOldClient, 1);
  2745. }
  2746. else if (!_hTheme)
  2747. {
  2748. InflateRect(&rcClient, g_cxFrame, g_cyFrame);
  2749. InflateRect(&rcOldClient, g_cxFrame, g_cyFrame);
  2750. }
  2751. // Prevent huge growth of taskbar, caused by bugs in the rebar sizing code
  2752. if (RECTHEIGHT(rcView) && RECTHEIGHT(rcOldView) && (RECTHEIGHT(rcClient) > (3 * RECTHEIGHT(rcOldClient))))
  2753. {
  2754. rcClient = rcOldClient;
  2755. }
  2756. if (STUCK_HORIZONTAL(uStuckPlace) && sNewWidths.cy != RECTHEIGHT(rcClient))
  2757. {
  2758. sNewWidths.cy = RECTHEIGHT(rcClient);
  2759. fChangedSize = TRUE;
  2760. }
  2761. if (!STUCK_HORIZONTAL(uStuckPlace) && sNewWidths.cx != RECTWIDTH(rcClient))
  2762. {
  2763. sNewWidths.cx = RECTWIDTH(rcClient);
  2764. fChangedSize = TRUE;
  2765. }
  2766. pdbc->Release();
  2767. }
  2768. }
  2769. //
  2770. // was there a change?
  2771. //
  2772. if (fChangedSize)
  2773. {
  2774. //
  2775. // yes, update the final rectangle
  2776. //
  2777. _MakeStuckRect(lprc, &rcDisplay, sNewWidths, uStuckPlace);
  2778. }
  2779. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.t_hs final rect is {%d, %d, %d, %d}"), lprc->left, lprc->top, lprc->right, lprc->bottom);
  2780. //
  2781. // store the new size in the appropriate StuckRect
  2782. //
  2783. _arStuckRects[uStuckPlace] = *lprc;
  2784. if (fHiding)
  2785. {
  2786. InvisibleUnhide(TRUE);
  2787. }
  2788. if (_hwndStartBalloon)
  2789. {
  2790. RECT rc;
  2791. GetWindowRect(_hwndStart, &rc);
  2792. SendMessage(_hwndStartBalloon, TTM_TRACKPOSITION, 0, MAKELONG((rc.left + rc.right)/2, rc.top));
  2793. SetWindowZorder(_hwndStartBalloon, HWND_TOPMOST);
  2794. }
  2795. return fChangedSize;
  2796. }
  2797. /*-------------------------------------------------------------------
  2798. ** the screen size changed, and we need to adjust some stuff, mostly
  2799. ** globals. if the tray was docked, it needs to be resized, too.
  2800. **
  2801. ** TRICKINESS: the handling of WM_WINDOWPOSCHANGING is used to
  2802. ** actually do all the real sizing work. this saves a bit of
  2803. ** extra code here.
  2804. **-------------------------------------------------------------------*/
  2805. BOOL WINAPI CTray::MonitorEnumProc(HMONITOR hMonitor, HDC hdc, LPRECT lprc, LPARAM lData)
  2806. {
  2807. CTray* ptray = (CTray*)lData;
  2808. RECT rcWork;
  2809. int iRet = ptray->_RecomputeWorkArea(NULL, hMonitor, &rcWork);
  2810. if (iRet == RWA_CHANGED)
  2811. {
  2812. // only send SENDWININICHANGE if the desktop has been created (otherwise
  2813. // we will hang the explorer because the main thread is currently blocked)
  2814. // PERF FEATURE: it will be nice to send WININICHANGE only once, but we can't
  2815. // because each time the rcWork is different, and there is no way to do it all
  2816. SystemParametersInfo(SPI_SETWORKAREA, TRUE, &rcWork, v_hwndDesktop ? SPIF_SENDWININICHANGE : 0);
  2817. RedrawDesktop(&rcWork);
  2818. }
  2819. return TRUE;
  2820. }
  2821. void CTray::_RecomputeAllWorkareas()
  2822. {
  2823. EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)this);
  2824. }
  2825. void CTray::_ScreenSizeChange(HWND hwnd)
  2826. {
  2827. // Set our new HMONITOR in case there is some change
  2828. {
  2829. MONITORINFO mi = {0};
  2830. mi.cbSize = sizeof(mi);
  2831. // Is our old HMONITOR still valid?
  2832. // NOTE: This test is used to tell whether somethings happened to the
  2833. // HMONITOR's or just the screen size changed
  2834. if (!GetMonitorInfo(_hmonStuck, &mi))
  2835. {
  2836. // No, this means the HMONITORS changed, our monitor might have gone away
  2837. _SetStuckMonitor();
  2838. _fIsLogoff = FALSE;
  2839. _RecomputeAllWorkareas();
  2840. }
  2841. }
  2842. // screen size changed, so we need to adjust globals
  2843. g_cxPrimaryDisplay = GetSystemMetrics(SM_CXSCREEN);
  2844. g_cyPrimaryDisplay = GetSystemMetrics(SM_CYSCREEN);
  2845. _ResizeStuckRects(_arStuckRects);
  2846. if (hwnd)
  2847. {
  2848. //
  2849. // set a bogus windowpos and actually repaint with the right
  2850. // shape/size in handling the WINDOWPOSCHANGING message
  2851. //
  2852. SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOACTIVATE);
  2853. }
  2854. SizeWindows();
  2855. RECT rc = _arStuckRects[_uStuckPlace];
  2856. _HandleSizing(0, &rc, _uStuckPlace);
  2857. // In the multi-monitor case, we need to turn on clipping for the dynamic
  2858. // monitor changes i.e. when the user add monitors or remove them from the
  2859. // control panel.
  2860. _ClipWindow(TRUE);
  2861. }
  2862. BOOL CTray::_UpdateAlwaysOnTop(BOOL fAlwaysOnTop)
  2863. {
  2864. BOOL fChanged = ((_fAlwaysOnTop == 0) != (fAlwaysOnTop == 0));
  2865. //
  2866. // The user clicked on the AlwaysOnTop menu item, we should now toggle
  2867. // the state and update the window accordingly...
  2868. //
  2869. _fAlwaysOnTop = fAlwaysOnTop;
  2870. _ResetZorder();
  2871. // Make sure the screen limits are update to the new state.
  2872. _StuckTrayChange();
  2873. return fChanged;
  2874. }
  2875. void CTray::_SaveTrayAndDesktop(void)
  2876. {
  2877. _SaveTray();
  2878. if (v_hwndDesktop)
  2879. SendMessage(v_hwndDesktop, DTM_SAVESTATE, 0, 0);
  2880. if (_hwndNotify)
  2881. SendMessage(_hwndNotify, TNM_SAVESTATE, 0, 0);
  2882. }
  2883. void CTray::_SlideStep(HWND hwnd, const RECT *prcMonitor, const RECT *prcOld, const RECT *prcNew)
  2884. {
  2885. SIZE sizeOld = {prcOld->right - prcOld->left, prcOld->bottom - prcOld->top};
  2886. SIZE sizeNew = {prcNew->right - prcNew->left, prcNew->bottom - prcNew->top};
  2887. BOOL fClipFirst = FALSE;
  2888. UINT flags;
  2889. DAD_ShowDragImage(FALSE); // Make sure this is off - client function must turn back on!!!
  2890. if (prcMonitor)
  2891. {
  2892. RECT rcClip, rcClipSafe, rcClipTest;
  2893. _CalcClipCoords(&rcClip, prcMonitor, prcNew);
  2894. rcClipTest = rcClip;
  2895. OffsetRect(&rcClipTest, prcOld->left, prcOld->top);
  2896. IntersectRect(&rcClipSafe, &rcClipTest, prcMonitor);
  2897. fClipFirst = EqualRect(&rcClipTest, &rcClipSafe);
  2898. if (fClipFirst)
  2899. _ClipInternal(&rcClip);
  2900. }
  2901. flags = SWP_NOZORDER|SWP_NOACTIVATE;
  2902. if ((sizeOld.cx == sizeNew.cx) && (sizeOld.cy == sizeNew.cy))
  2903. flags |= SWP_NOSIZE;
  2904. SetWindowPos(hwnd, NULL,
  2905. prcNew->left, prcNew->top, sizeNew.cx, sizeNew.cy, flags);
  2906. if (prcMonitor && !fClipFirst)
  2907. {
  2908. RECT rcClip;
  2909. _CalcClipCoords(&rcClip, prcMonitor, prcNew);
  2910. _ClipInternal(&rcClip);
  2911. }
  2912. }
  2913. void CTray::_SlideWindow(HWND hwnd, RECT *prc, BOOL fShow)
  2914. {
  2915. RECT rcLast;
  2916. RECT rcMonitor;
  2917. const RECT *prcMonitor;
  2918. DWORD dt;
  2919. BOOL fAnimate;
  2920. if (!IsWindowVisible(hwnd))
  2921. {
  2922. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.sw window is hidden, just moving"));
  2923. MoveWindow(_hwnd, prc->left, prc->top, RECTWIDTH(*prc), RECTHEIGHT(*prc), FALSE);
  2924. return;
  2925. }
  2926. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.sw -----------------BEGIN-----------------"));
  2927. if (GetSystemMetrics(SM_CMONITORS) > 1)
  2928. {
  2929. _GetStuckDisplayRect(_uStuckPlace, &rcMonitor);
  2930. prcMonitor = &rcMonitor;
  2931. }
  2932. else
  2933. prcMonitor = NULL;
  2934. GetWindowRect(hwnd, &rcLast);
  2935. dt = fShow? _dtSlideShow : _dtSlideHide;
  2936. // See if we can use animation effects.
  2937. SystemParametersInfo(SPI_GETMENUANIMATION, 0, &fAnimate, 0);
  2938. if (g_fDragFullWindows && fAnimate && (dt > 0))
  2939. {
  2940. RECT rcOld, rcNew, rcMove;
  2941. int dx, dy, priority;
  2942. DWORD t, t2, t0;
  2943. HANDLE me;
  2944. rcOld = rcLast;
  2945. rcNew = *prc;
  2946. dx = ((rcNew.left + rcNew.right) - (rcOld.left + rcOld.right)) / 2;
  2947. dy = ((rcNew.top + rcNew.bottom) - (rcOld.top + rcOld.bottom)) / 2;
  2948. ASSERT(dx == 0 || dy == 0);
  2949. me = GetCurrentThread();
  2950. priority = GetThreadPriority(me);
  2951. SetThreadPriority(me, THREAD_PRIORITY_HIGHEST);
  2952. t2 = t0 = GetTickCount();
  2953. rcMove = rcOld;
  2954. while ((t = GetTickCount()) - t0 < dt)
  2955. {
  2956. int dtdiff;
  2957. if (t != t2)
  2958. {
  2959. rcMove.right -= rcMove.left;
  2960. rcMove.left = rcOld.left + (dx) * (t - t0) / dt;
  2961. rcMove.right += rcMove.left;
  2962. rcMove.bottom -= rcMove.top;
  2963. rcMove.top = rcOld.top + (dy) * (t - t0) / dt;
  2964. rcMove.bottom += rcMove.top;
  2965. _SlideStep(hwnd, prcMonitor, &rcLast, &rcMove);
  2966. if (fShow)
  2967. UpdateWindow(hwnd);
  2968. rcLast = rcMove;
  2969. t2 = t;
  2970. }
  2971. // don't draw frames faster than user can see, e.g. 20ms
  2972. #define ONEFRAME 20
  2973. dtdiff = GetTickCount();
  2974. if ((dtdiff - t) < ONEFRAME)
  2975. Sleep(ONEFRAME - (dtdiff - t));
  2976. // try to give desktop a chance to update
  2977. // only do it on hide because desktop doesn't need to paint on taskbar show
  2978. if (!fShow)
  2979. {
  2980. DWORD_PTR lres;
  2981. SendMessageTimeout(v_hwndDesktop, DTM_UPDATENOW, 0, 0, SMTO_ABORTIFHUNG, 50, &lres);
  2982. }
  2983. }
  2984. SetThreadPriority(me, priority);
  2985. }
  2986. _SlideStep(hwnd, prcMonitor, &rcLast, prc);
  2987. if (fShow)
  2988. UpdateWindow(hwnd);
  2989. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.sw ------------------END------------------"));
  2990. }
  2991. void CTray::_UnhideNow()
  2992. {
  2993. if (_uModalMode == MM_SHUTDOWN)
  2994. return;
  2995. _fSelfSizing = TRUE;
  2996. DAD_ShowDragImage(FALSE); // unlock the drag sink if we are dragging.
  2997. _SlideWindow(_hwnd, &_arStuckRects[_uStuckPlace], _dtSlideShow);
  2998. DAD_ShowDragImage(TRUE); // restore the lock state.
  2999. _fSelfSizing = FALSE;
  3000. SendMessage(_hwndNotify, TNM_TRAYHIDE, 0, FALSE);
  3001. }
  3002. void CTray::_ComputeHiddenRect(LPRECT prc, UINT uStuck)
  3003. {
  3004. int dwh;
  3005. HMONITOR hMon;
  3006. RECT rcMon;
  3007. hMon = MonitorFromRect(prc, MONITOR_DEFAULTTONULL);
  3008. if (!hMon)
  3009. return;
  3010. GetMonitorRect(hMon, &rcMon);
  3011. if (STUCK_HORIZONTAL(uStuck))
  3012. dwh = prc->bottom - prc->top;
  3013. else
  3014. dwh = prc->right - prc->left;
  3015. switch (uStuck)
  3016. {
  3017. case STICK_LEFT:
  3018. prc->right = rcMon.left + (g_cxFrame / 2);
  3019. prc->left = prc->right - dwh;
  3020. break;
  3021. case STICK_RIGHT:
  3022. prc->left = rcMon.right - (g_cxFrame / 2);
  3023. prc->right = prc->left + dwh;
  3024. break;
  3025. case STICK_TOP:
  3026. prc->bottom = rcMon.top + (g_cyFrame / 2);
  3027. prc->top = prc->bottom - dwh;
  3028. break;
  3029. case STICK_BOTTOM:
  3030. prc->top = rcMon.bottom - (g_cyFrame / 2);
  3031. prc->bottom = prc->top + dwh;
  3032. break;
  3033. }
  3034. }
  3035. UINT CTray::_GetDockedRect(LPRECT prc, BOOL fMoving)
  3036. {
  3037. UINT uPos;
  3038. if (fMoving && (_uMoveStuckPlace != (UINT)-1))
  3039. uPos = _uMoveStuckPlace;
  3040. else
  3041. uPos = _uStuckPlace;
  3042. *prc = _arStuckRects[uPos];
  3043. if ((_uAutoHide & (AH_ON | AH_HIDING)) == (AH_ON | AH_HIDING))
  3044. {
  3045. _ComputeHiddenRect(prc, uPos);
  3046. }
  3047. return uPos;
  3048. }
  3049. void CTray::_CalcClipCoords(RECT *prcClip, const RECT *prcMonitor, const RECT *prcNew)
  3050. {
  3051. RECT rcMonitor;
  3052. RECT rcWindow;
  3053. if (!prcMonitor)
  3054. {
  3055. _GetStuckDisplayRect(_uStuckPlace, &rcMonitor);
  3056. prcMonitor = &rcMonitor;
  3057. }
  3058. if (!prcNew)
  3059. {
  3060. GetWindowRect(_hwnd, &rcWindow);
  3061. prcNew = &rcWindow;
  3062. }
  3063. IntersectRect(prcClip, prcMonitor, prcNew);
  3064. OffsetRect(prcClip, -prcNew->left, -prcNew->top);
  3065. }
  3066. void CTray::_ClipInternal(const RECT *prcClip)
  3067. {
  3068. HRGN hrgnClip;
  3069. // don't worry about clipping if there's only one monitor
  3070. if (GetSystemMetrics(SM_CMONITORS) <= 1)
  3071. prcClip = NULL;
  3072. if (prcClip)
  3073. {
  3074. _fMonitorClipped = TRUE;
  3075. hrgnClip = CreateRectRgnIndirect(prcClip);
  3076. }
  3077. else
  3078. {
  3079. // SetWindowRgn is expensive, skip ones that are NOPs
  3080. if (!_fMonitorClipped)
  3081. return;
  3082. _fMonitorClipped = FALSE;
  3083. hrgnClip = NULL;
  3084. }
  3085. SetWindowRgn(_hwnd, hrgnClip, TRUE);
  3086. }
  3087. void CTray::_ClipWindow(BOOL fClipState)
  3088. {
  3089. RECT rcClip;
  3090. RECT *prcClip;
  3091. if (_fSelfSizing || _fSysSizing)
  3092. {
  3093. TraceMsg(TF_WARNING, "_ClipWindow: _fSelfSizing %x, _fSysSizing %x", _fSelfSizing, _fSysSizing);
  3094. return;
  3095. }
  3096. if ((GetSystemMetrics(SM_CMONITORS) <= 1) || _hTheme)
  3097. fClipState = FALSE;
  3098. if (fClipState)
  3099. {
  3100. prcClip = &rcClip;
  3101. _CalcClipCoords(prcClip, NULL, NULL);
  3102. }
  3103. else
  3104. prcClip = NULL;
  3105. _ClipInternal(prcClip);
  3106. }
  3107. void CTray::_Hide()
  3108. {
  3109. RECT rcNew;
  3110. // if we're in shutdown or if we're on boot up
  3111. // don't hide
  3112. if (_uModalMode == MM_SHUTDOWN)
  3113. {
  3114. TraceMsg(TF_TRAY, "e.th: suppress hide (shutdown || Notify)");
  3115. return;
  3116. }
  3117. KillTimer(_hwnd, IDT_AUTOHIDE);
  3118. _fSelfSizing = TRUE;
  3119. //
  3120. // update the flags here to prevent race conditions
  3121. //
  3122. _uAutoHide = AH_ON | AH_HIDING;
  3123. _GetDockedRect(&rcNew, FALSE);
  3124. DAD_ShowDragImage(FALSE); // unlock the drag sink if we are dragging.
  3125. _SlideWindow(_hwnd, &rcNew, _dtSlideHide);
  3126. DAD_ShowDragImage(FALSE); // Another thread could have locked while we were gone
  3127. DAD_ShowDragImage(TRUE); // restore the lock state.
  3128. SendMessage(_hwndNotify, TNM_TRAYHIDE, 0, TRUE);
  3129. _fSelfSizing = FALSE;
  3130. }
  3131. void CTray::_AutoHideCollision()
  3132. {
  3133. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.t_ahc COLLISION! (posting UI request)"));
  3134. PostMessage(_hwnd, TM_WARNNOAUTOHIDE, ((_uAutoHide & AH_ON) != 0),
  3135. 0L);
  3136. }
  3137. LONG CTray::_SetAutoHideState(BOOL fAutoHide)
  3138. {
  3139. //
  3140. // make sure we have something to do
  3141. //
  3142. if ((fAutoHide != 0) == ((_uAutoHide & AH_ON) != 0))
  3143. {
  3144. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.sahs nothing to do"));
  3145. return MAKELONG(FALSE, TRUE);
  3146. }
  3147. //
  3148. // make sure we can do it
  3149. //
  3150. if (!_AppBarSetAutoHideBar2(_hwnd, fAutoHide, _uStuckPlace))
  3151. {
  3152. _AutoHideCollision();
  3153. return MAKELONG(FALSE, FALSE);
  3154. }
  3155. //
  3156. // do it
  3157. //
  3158. if (fAutoHide)
  3159. {
  3160. _uAutoHide = AH_ON;
  3161. _RefreshSettings();
  3162. _Hide();
  3163. #ifdef DEBUG
  3164. // _Hide updates the flags for us (sanity)
  3165. if (!(_uAutoHide & AH_ON))
  3166. {
  3167. TraceMsg(DM_WARNING, "e.sahs: !AH_ON"); // ok to fail on boot/shutdown
  3168. }
  3169. #endif
  3170. }
  3171. else
  3172. {
  3173. _uAutoHide = 0;
  3174. KillTimer(_hwnd, IDT_AUTOHIDE);
  3175. _UnhideNow();
  3176. _RefreshSettings();
  3177. }
  3178. //
  3179. // brag about it
  3180. //
  3181. _StuckTrayChange();
  3182. return MAKELONG(TRUE, TRUE);
  3183. }
  3184. void CTray::_HandleEnterMenuLoop()
  3185. {
  3186. // kill the timer when we're in the menu loop so that we don't
  3187. // pop done while browsing the menus.
  3188. if (_uAutoHide & AH_ON)
  3189. {
  3190. KillTimer(_hwnd, IDT_AUTOHIDE);
  3191. }
  3192. }
  3193. void CTray::_SetAutoHideTimer()
  3194. {
  3195. if (_uAutoHide & AH_ON)
  3196. {
  3197. SetTimer(_hwnd, IDT_AUTOHIDE, 500, NULL);
  3198. }
  3199. }
  3200. void CTray::_HandleExitMenuLoop()
  3201. {
  3202. // when we leave the menu stuff, start checking again.
  3203. _SetAutoHideTimer();
  3204. }
  3205. void CTray::Unhide()
  3206. {
  3207. // handle autohide
  3208. if ((_uAutoHide & AH_ON) &&
  3209. (_uAutoHide & AH_HIDING))
  3210. {
  3211. _UnhideNow();
  3212. _uAutoHide &= ~AH_HIDING;
  3213. _SetAutoHideTimer();
  3214. if (_fShouldResize)
  3215. {
  3216. ASSERT(0);
  3217. ASSERT(!(_uAutoHide & AH_HIDING));
  3218. SizeWindows();
  3219. _fShouldResize = FALSE;
  3220. }
  3221. }
  3222. }
  3223. void CTray::_SetUnhideTimer(LONG x, LONG y)
  3224. {
  3225. // handle autohide
  3226. if ((_uAutoHide & AH_ON) &&
  3227. (_uAutoHide & AH_HIDING))
  3228. {
  3229. LONG dx = x-_ptLastHittest.x;
  3230. LONG dy = y-_ptLastHittest.y;
  3231. LONG rr = dx*dx + dy*dy;
  3232. LONG dd = GetSystemMetrics(SM_CXDOUBLECLK) * GetSystemMetrics(SM_CYDOUBLECLK);
  3233. if (rr > dd)
  3234. {
  3235. SetTimer(_hwnd, IDT_AUTOUNHIDE, 50, NULL);
  3236. _ptLastHittest.x = x;
  3237. _ptLastHittest.y = y;
  3238. }
  3239. }
  3240. }
  3241. void CTray::_StartButtonReset()
  3242. {
  3243. // Get an idea about how big we need everyhting to be.
  3244. TCHAR szStart[50];
  3245. LoadString(hinstCabinet, _hTheme ? IDS_START : IDS_STARTCLASSIC, szStart, ARRAYSIZE(szStart));
  3246. SetWindowText(_hwndStart, szStart);
  3247. if (_hFontStart)
  3248. DeleteObject(_hFontStart);
  3249. _hFontStart = _CreateStartFont(_hwndStart);
  3250. int idbStart = IDB_START16;
  3251. HDC hdc = GetDC(NULL);
  3252. if (hdc)
  3253. {
  3254. int bpp = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES);
  3255. if (bpp > 8)
  3256. {
  3257. idbStart = _hTheme ? IDB_START : IDB_STARTCLASSIC;
  3258. }
  3259. ReleaseDC(NULL, hdc);
  3260. }
  3261. HBITMAP hbmFlag = (HBITMAP)LoadImage(hinstCabinet, MAKEINTRESOURCE(idbStart), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
  3262. if (hbmFlag)
  3263. {
  3264. BITMAP bm;
  3265. if (GetObject(hbmFlag, sizeof(BITMAP), &bm))
  3266. {
  3267. BUTTON_IMAGELIST biml = {0};
  3268. if (_himlStartFlag)
  3269. ImageList_Destroy(_himlStartFlag);
  3270. DWORD dwFlags = ILC_COLOR32;
  3271. HBITMAP hbmFlagMask = NULL;
  3272. if (idbStart == IDB_START16)
  3273. {
  3274. dwFlags = ILC_COLOR8 | ILC_MASK;
  3275. hbmFlagMask = (HBITMAP)LoadImage(hinstCabinet, MAKEINTRESOURCE(IDB_START16MASK), IMAGE_BITMAP, 0, 0, LR_MONOCHROME);
  3276. }
  3277. if (IS_WINDOW_RTL_MIRRORED(_hwndStart))
  3278. {
  3279. dwFlags |= ILC_MIRROR;
  3280. }
  3281. biml.himl = _himlStartFlag = ImageList_Create(bm.bmWidth, bm.bmHeight, dwFlags, 1, 1);
  3282. ImageList_Add(_himlStartFlag, hbmFlag, hbmFlagMask);
  3283. biml.uAlign = BUTTON_IMAGELIST_ALIGN_LEFT;
  3284. Button_SetImageList(_hwndStart, &biml);
  3285. }
  3286. DeleteObject(hbmFlag);
  3287. }
  3288. if (_hFontStart)
  3289. {
  3290. SendMessage(_hwndStart, WM_SETFONT, (WPARAM)_hFontStart, TRUE);
  3291. _sizeStart.cx = 0;
  3292. }
  3293. _AlignStartButton();
  3294. }
  3295. void CTray::_OnNewSystemSizes()
  3296. {
  3297. TraceMsg(TF_TRAY, "Handling win ini change.");
  3298. _StartButtonReset();
  3299. VerifySize(TRUE);
  3300. }
  3301. //*** CheckWindowPositions -- flag which windows actually changed
  3302. // ENTRY/EXIT
  3303. // _pPositions->hdsaWP[*]->fRestore modified
  3304. // NOTES
  3305. // in order to correctly implement 'Undo Minimize-all(Cascade/Tile)',
  3306. // we need to tell which windows were changed by the 'Do' operation.
  3307. // (nt5:183421: we used to restore *every* top-level window).
  3308. int WINAPI CTray::CheckWndPosEnumProc(void *pItem, void *pData)
  3309. {
  3310. HWNDANDPLACEMENT *pI2 = (HWNDANDPLACEMENT *)pItem;
  3311. WINDOWPLACEMENT wp;
  3312. wp.length = sizeof(wp);
  3313. pI2->fRestore = TRUE;
  3314. if (GetWindowPlacement(pI2->hwnd, &wp)) {
  3315. if (memcmp(&pI2->wp, &wp, sizeof(wp)) == 0)
  3316. pI2->fRestore = FALSE;
  3317. }
  3318. TraceMsg(TF_TRAY, "cwp: (hwnd=0x%x) fRestore=%d", pI2->hwnd, pI2->fRestore);
  3319. return 1; // 1:continue enum
  3320. }
  3321. void CTray::CheckWindowPositions()
  3322. {
  3323. ENTERCRITICAL; // i think this is needed...
  3324. if (_pPositions) {
  3325. if (_pPositions->hdsaWP) {
  3326. DSA_EnumCallback(_pPositions->hdsaWP, CheckWndPosEnumProc, NULL);
  3327. }
  3328. }
  3329. LEAVECRITICAL;
  3330. return;
  3331. }
  3332. BOOL BandSite_PermitAutoHide(IUnknown* punk)
  3333. {
  3334. OLECMD cmd = { DBID_PERMITAUTOHIDE, 0 };
  3335. if (SUCCEEDED(IUnknown_QueryStatus(punk, &IID_IDockingWindow, 1, &cmd, NULL)))
  3336. {
  3337. return !(cmd.cmdf & OLECMDF_SUPPORTED) || (cmd.cmdf & OLECMDF_ENABLED);
  3338. }
  3339. return TRUE;
  3340. }
  3341. void CTray::_HandleTimer(WPARAM wTimerID)
  3342. {
  3343. switch (wTimerID)
  3344. {
  3345. case IDT_CHECKDISKSPACE:
  3346. CheckDiskSpace();
  3347. break;
  3348. case IDT_DESKTOPCLEANUP:
  3349. _CheckDesktopCleanup();
  3350. break;
  3351. case IDT_CHANGENOTIFY:
  3352. // did somebody send another notify since we last handled one?
  3353. if (_fUseChangeNotifyTimer)
  3354. {
  3355. // yep.
  3356. // all we do is check the staging area.
  3357. CheckStagingArea();
  3358. // kill it off the next time.
  3359. _fUseChangeNotifyTimer = FALSE;
  3360. }
  3361. else
  3362. {
  3363. // nope.
  3364. KillTimer(_hwnd, IDT_CHANGENOTIFY);
  3365. _fChangeNotifyTimerRunning = FALSE;
  3366. }
  3367. break;
  3368. case IDT_HANDLEDELAYBOOTSTUFF:
  3369. KillTimer(_hwnd, IDT_HANDLEDELAYBOOTSTUFF);
  3370. PostMessage(_hwnd, TM_HANDLEDELAYBOOTSTUFF, 0, 0);
  3371. break;
  3372. case IDT_STARTMENU:
  3373. SetForegroundWindow(_hwnd);
  3374. KillTimer(_hwnd, wTimerID);
  3375. DAD_ShowDragImage(FALSE); // unlock the drag sink if we are dragging.
  3376. SendMessage(_hwndStart, BM_SETSTATE, TRUE, 0);
  3377. UpdateWindow(_hwndStart);
  3378. DAD_ShowDragImage(TRUE); // restore the lock state.
  3379. break;
  3380. case IDT_SAVESETTINGS:
  3381. KillTimer(_hwnd, IDT_SAVESETTINGS);
  3382. _SaveTray();
  3383. break;
  3384. case IDT_ENABLEUNDO:
  3385. KillTimer(_hwnd, IDT_ENABLEUNDO);
  3386. CheckWindowPositions();
  3387. _fUndoEnabled = TRUE;
  3388. break;
  3389. case IDT_AUTOHIDE:
  3390. if (!_fSysSizing && (_uAutoHide & AH_ON))
  3391. {
  3392. POINT pt;
  3393. RECT rc;
  3394. // Don't hide if we're already hiding, a balloon tip is showing, or
  3395. // (on NT5) if any apps are flashing.
  3396. //
  3397. if (!(_uAutoHide & AH_HIDING) && BandSite_PermitAutoHide(_ptbs) && !_fBalloonUp)
  3398. {
  3399. // Get the cursor position.
  3400. GetCursorPos(&pt);
  3401. // Get the tray rect and inflate it a bit.
  3402. rc = _arStuckRects[_uStuckPlace];
  3403. InflateRect(&rc, g_cxEdge * 4, g_cyEdge*4);
  3404. // Don't hide if cursor is within inflated tray rect.
  3405. if (!PtInRect(&rc, pt))
  3406. {
  3407. // Don't hide if the tray is active
  3408. if (!_IsActive() && _uStartButtonState != SBSM_SPACTIVE)
  3409. {
  3410. // Don't hide if the view has a system menu up.
  3411. if (!SendMessage(_hwndTasks, TBC_SYSMENUCOUNT, 0, 0L))
  3412. {
  3413. // Phew! We made it. Hide the tray.
  3414. _Hide();
  3415. }
  3416. }
  3417. }
  3418. }
  3419. }
  3420. break;
  3421. case IDT_AUTOUNHIDE:
  3422. if (!_fSysSizing && (_uAutoHide & AH_ON))
  3423. {
  3424. POINT pt;
  3425. RECT rc;
  3426. KillTimer(_hwnd, wTimerID);
  3427. _ptLastHittest.x = -0x0fff;
  3428. _ptLastHittest.y = -0x0fff;
  3429. GetWindowRect(_hwnd, &rc);
  3430. if (_uAutoHide & AH_HIDING)
  3431. {
  3432. GetCursorPos(&pt);
  3433. if (PtInRect(&rc, pt))
  3434. Unhide();
  3435. }
  3436. }
  3437. break;
  3438. case IDT_STARTBUTTONBALLOON:
  3439. _DestroyStartButtonBalloon();
  3440. break;
  3441. case IDT_COFREEUNUSED:
  3442. CoFreeUnusedLibraries();
  3443. KillTimer(_hwnd, IDT_COFREEUNUSED);
  3444. break;
  3445. }
  3446. }
  3447. void CTray::_CheckStagingAreaOnTimer()
  3448. {
  3449. if (_fChangeNotifyTimerRunning)
  3450. {
  3451. // we're already running the timer, so force a check the next time it comes up
  3452. _fUseChangeNotifyTimer = TRUE;
  3453. }
  3454. else
  3455. {
  3456. _fChangeNotifyTimerRunning = TRUE;
  3457. // check once immediately
  3458. CheckStagingArea();
  3459. // check again in half a minute, but only if notifies have been happening in the meantime.
  3460. SetTimer(_hwnd, IDT_CHANGENOTIFY, 30 * 1000, NULL);
  3461. }
  3462. }
  3463. void CTray::_HandleChangeNotify(WPARAM wParam, LPARAM lParam)
  3464. {
  3465. LPITEMIDLIST *ppidl;
  3466. LONG lEvent;
  3467. LPSHChangeNotificationLock pshcnl = SHChangeNotification_Lock((HANDLE)wParam, (DWORD)lParam, &ppidl, &lEvent);
  3468. if (pshcnl)
  3469. {
  3470. if (lEvent & SHCNE_STAGINGAREANOTIFICATIONS)
  3471. {
  3472. // something has changed within the staging area.
  3473. _CheckStagingAreaOnTimer();
  3474. }
  3475. SHChangeNotification_Unlock(pshcnl);
  3476. }
  3477. }
  3478. BOOL _ExecItemByPidls(HWND hwnd, LPITEMIDLIST pidlFolder, LPITEMIDLIST pidlItem)
  3479. {
  3480. BOOL fRes = FALSE;
  3481. if (pidlFolder && pidlItem)
  3482. {
  3483. IShellFolder *psf = BindToFolder(pidlFolder);
  3484. if (psf)
  3485. {
  3486. fRes = SUCCEEDED(SHInvokeDefaultCommand(hwnd, psf, pidlItem));
  3487. }
  3488. else
  3489. {
  3490. TCHAR szPath[MAX_PATH];
  3491. SHGetPathFromIDList(pidlFolder, szPath);
  3492. ShellMessageBox(hinstCabinet, hwnd, MAKEINTRESOURCE(IDS_CANTFINDSPECIALDIR),
  3493. NULL, MB_ICONEXCLAMATION, szPath);
  3494. }
  3495. }
  3496. return fRes;
  3497. }
  3498. void _DestroySavedWindowPositions(LPWINDOWPOSITIONS pPositions);
  3499. LRESULT CTray::_HandleDestroy()
  3500. {
  3501. MINIMIZEDMETRICS mm;
  3502. TraceMsg(DM_SHUTDOWN, "_HD: enter");
  3503. mm.cbSize = sizeof(mm);
  3504. SystemParametersInfo(SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, FALSE);
  3505. mm.iArrange &= ~ARW_HIDE;
  3506. SystemParametersInfo(SPI_SETMINIMIZEDMETRICS, sizeof(mm), &mm, FALSE);
  3507. _RevokeDropTargets();
  3508. _DestroyStartMenu();
  3509. Mixer_Shutdown();
  3510. // Tell the start menu to free all its cached darwin links
  3511. SHRegisterDarwinLink(NULL, NULL, TRUE);
  3512. _DestroySavedWindowPositions(_pPositions);
  3513. _pPositions = NULL;
  3514. if (_hTheme)
  3515. {
  3516. CloseThemeData(_hTheme);
  3517. _hTheme = NULL;
  3518. }
  3519. _UnregisterGlobalHotkeys();
  3520. if (_uNotify)
  3521. {
  3522. SHChangeNotifyDeregister(_uNotify);
  3523. _uNotify = 0;
  3524. }
  3525. ATOMICRELEASE(_ptbs);
  3526. ATOMICRELEASE(_pdbTasks);
  3527. _hwndTasks = NULL;
  3528. if (_hwndTrayTips)
  3529. {
  3530. DestroyWindow(_hwndTrayTips);
  3531. _hwndTrayTips = NULL;
  3532. }
  3533. _DestroyStartButtonBalloon();
  3534. // REVIEW
  3535. PostQuitMessage(0);
  3536. if (_hbmpStartBkg)
  3537. {
  3538. DeleteBitmap(_hbmpStartBkg);
  3539. }
  3540. if (_hFontStart)
  3541. {
  3542. DeleteObject(_hFontStart);
  3543. }
  3544. if (_himlStartFlag)
  3545. {
  3546. ImageList_Destroy(_himlStartFlag);
  3547. }
  3548. // clean up service objects
  3549. _ssomgr.Destroy();
  3550. if (_hShellReadyEvent)
  3551. {
  3552. ResetEvent(_hShellReadyEvent);
  3553. CloseHandle(_hShellReadyEvent);
  3554. _hShellReadyEvent = NULL;
  3555. }
  3556. if (_fHandledDelayBootStuff)
  3557. {
  3558. TBOOL(WinStationUnRegisterConsoleNotification(SERVERNAME_CURRENT, v_hwndTray));
  3559. }
  3560. DeleteCriticalSection(&_csHotkey);
  3561. // The order in which we shut down the HTTP key monitoring is important.
  3562. //
  3563. // We must close the key before closing the event handle because
  3564. // closing the key causes the event to be signalled and we don't
  3565. // want ADVAPI32 to try to signal an event after we closed its handle...
  3566. //
  3567. // To avoid a spurious trigger when the event fires, we unregister
  3568. // the wait before closing the key.
  3569. //
  3570. if (_hHTTPWait)
  3571. {
  3572. UnregisterWait(_hHTTPWait);
  3573. _hHTTPWait = NULL;
  3574. }
  3575. if (_hkHTTP)
  3576. {
  3577. RegCloseKey(_hkHTTP);
  3578. _hkHTTP = NULL;
  3579. }
  3580. if (_hHTTPEvent)
  3581. {
  3582. CloseHandle(_hHTTPEvent);
  3583. _hHTTPEvent = NULL;
  3584. }
  3585. // End of order-sensitive operations ----------------------------------
  3586. v_hwndTray = NULL;
  3587. _hwndStart = NULL;
  3588. TraceMsg(DM_SHUTDOWN, "_HD: leave");
  3589. return 0;
  3590. }
  3591. void CTray::_SetFocus(HWND hwnd)
  3592. {
  3593. IUnknown_UIActivateIO(_ptbs, FALSE, NULL);
  3594. SetFocus(hwnd);
  3595. }
  3596. #define TRIEDTOOMANYTIMES 100
  3597. void CTray::_ActAsSwitcher()
  3598. {
  3599. if (_uModalMode)
  3600. {
  3601. if (_uModalMode != MM_SHUTDOWN)
  3602. {
  3603. SwitchToThisWindow(GetLastActivePopup(_hwnd), TRUE);
  3604. }
  3605. MessageBeep(0);
  3606. }
  3607. else
  3608. {
  3609. HWND hwndForeground;
  3610. HWND hwndActive;
  3611. static int s_iRecurse = 0;
  3612. s_iRecurse++;
  3613. ASSERT(s_iRecurse < TRIEDTOOMANYTIMES);
  3614. TraceMsg(TF_TRAY, "s_iRecurse = %d", s_iRecurse);
  3615. hwndForeground = GetForegroundWindow();
  3616. hwndActive = GetActiveWindow();
  3617. BOOL fIsTrayActive = (hwndForeground == _hwnd) && (hwndActive == _hwnd);
  3618. if (v_hwndStartPane && hwndForeground == v_hwndStartPane && hwndActive == v_hwndStartPane)
  3619. {
  3620. fIsTrayActive = TRUE;
  3621. }
  3622. // only do the button once we're the foreground dude.
  3623. if (fIsTrayActive)
  3624. {
  3625. // This code path causes the start button to do something because
  3626. // of the keyboard. So reflect that with the focus rect.
  3627. SendMessage(_hwndStart, WM_UPDATEUISTATE, MAKEWPARAM(UIS_CLEAR,
  3628. UISF_HIDEFOCUS), 0);
  3629. if (SendMessage(_hwndStart, BM_GETSTATE, 0, 0) & BST_PUSHED)
  3630. {
  3631. ClosePopupMenus();
  3632. ForceStartButtonUp();
  3633. }
  3634. else
  3635. {
  3636. // This pushes the start button and causes the start menu to popup.
  3637. SendMessage(GetDlgItem(_hwnd, IDC_START), BM_SETSTATE, TRUE, 0);
  3638. }
  3639. s_iRecurse = 0;
  3640. }
  3641. else
  3642. {
  3643. // we don't want to loop endlessly trying to become
  3644. // foreground. With NT's new SetForegroundWindow rules, it would
  3645. // be pointless to try and hopefully we won't need to anyhow.
  3646. // Randomly, I picked a quarter as many times as the debug squirty would indicate
  3647. // as the number of times to try on NT.
  3648. // Hopefully that is enough on most machines.
  3649. if (s_iRecurse > (TRIEDTOOMANYTIMES / 4))
  3650. {
  3651. s_iRecurse = 0;
  3652. return;
  3653. }
  3654. // until then, try to come forward.
  3655. HandleFullScreenApp(NULL);
  3656. if (hwndForeground == v_hwndDesktop)
  3657. {
  3658. _SetFocus(_hwndStart);
  3659. if (GetFocus() != _hwndStart)
  3660. return;
  3661. }
  3662. SwitchToThisWindow(_hwnd, TRUE);
  3663. SetForegroundWindow(_hwnd);
  3664. Sleep(20); // give some time for other async activation messages to get posted
  3665. PostMessage(_hwnd, TM_ACTASTASKSW, 0, 0);
  3666. }
  3667. }
  3668. }
  3669. void CTray::_OnWinIniChange(HWND hwnd, WPARAM wParam, LPARAM lParam)
  3670. {
  3671. Cabinet_InitGlobalMetrics(wParam, (LPTSTR)lParam);
  3672. // Reset the programs menu.
  3673. // REVIEW IANEL - We should only need to listen to the SPI_SETNONCLIENT stuff
  3674. // but deskcpl doesn't send one.
  3675. if (wParam == SPI_SETNONCLIENTMETRICS || (!wParam && (!lParam || (lstrcmpi((LPTSTR)lParam, TEXT("WindowMetrics")) == 0))))
  3676. {
  3677. #ifdef DEBUG
  3678. if (wParam == SPI_SETNONCLIENTMETRICS)
  3679. TraceMsg(TF_TRAY, "c.t_owic: Non-client metrics (probably) changed.");
  3680. else
  3681. TraceMsg(TF_TRAY, "c.t_owic: Window metrics changed.");
  3682. #endif
  3683. _OnNewSystemSizes();
  3684. }
  3685. // Handle old extensions.
  3686. if (!lParam || (lParam && (lstrcmpi((LPTSTR)lParam, TEXT("Extensions")) == 0)))
  3687. {
  3688. TraceMsg(TF_TRAY, "t_owic: Extensions section change.");
  3689. CheckWinIniForAssocs();
  3690. }
  3691. if (lParam && (0 == lstrcmpi((LPCTSTR)lParam, TEXT("TraySettings"))))
  3692. {
  3693. _Command(FCIDM_REFRESH);
  3694. }
  3695. // Tell shell32 to refresh its cache
  3696. SHSettingsChanged(wParam, lParam);
  3697. }
  3698. HWND CTray::_HotkeyInUse(WORD wHK)
  3699. {
  3700. HWND hwnd;
  3701. DWORD_PTR lrHKInUse = 0;
  3702. int nMod;
  3703. WORD wHKNew;
  3704. #ifdef DEBUG
  3705. TCHAR sz[MAX_PATH];
  3706. #endif
  3707. // Map the modifiers back.
  3708. nMod = 0;
  3709. if (HIBYTE(wHK) & MOD_SHIFT)
  3710. nMod |= HOTKEYF_SHIFT;
  3711. if (HIBYTE(wHK) & MOD_CONTROL)
  3712. nMod |= HOTKEYF_CONTROL;
  3713. if (HIBYTE(wHK) & MOD_ALT)
  3714. nMod |= HOTKEYF_ALT;
  3715. wHKNew = (WORD)((nMod*256)+LOBYTE(wHK));
  3716. DebugMsg(DM_IANELHK, TEXT("c.hkl_hiu: Checking for %x"), wHKNew);
  3717. hwnd = GetWindow(GetDesktopWindow(), GW_CHILD);
  3718. while (hwnd)
  3719. {
  3720. SendMessageTimeout(hwnd, WM_GETHOTKEY, 0, 0, SMTO_ABORTIFHUNG| SMTO_BLOCK, 3000, &lrHKInUse);
  3721. if (wHKNew == (WORD)lrHKInUse)
  3722. {
  3723. #ifdef DEBUG
  3724. GetWindowText(hwnd, sz, ARRAYSIZE(sz));
  3725. DebugMsg(DM_IANELHK, TEXT("c.hkl_hiu: %s (%x) is using %x"), sz, hwnd, lrHKInUse);
  3726. #endif
  3727. return hwnd;
  3728. }
  3729. #ifdef DEBUG
  3730. else if (lrHKInUse)
  3731. {
  3732. GetWindowText(hwnd, sz, ARRAYSIZE(sz));
  3733. DebugMsg(DM_IANELHK, TEXT("c.hkl_hiu: %s (%x) is using %x"), sz, hwnd, lrHKInUse);
  3734. }
  3735. #endif
  3736. hwnd = GetWindow(hwnd, GW_HWNDNEXT);
  3737. }
  3738. return NULL;
  3739. }
  3740. void CTray::_HandleHotKey(int nID)
  3741. {
  3742. TraceMsg(TF_TRAY, "c.hkl_hh: Handling hotkey (%d).", nID);
  3743. // Find it in the list.
  3744. ASSERT(IS_VALID_HANDLE(_hdsaHKI, DSA));
  3745. EnterCriticalSection(&_csHotkey);
  3746. HOTKEYITEM *phki = (HOTKEYITEM *)DSA_GetItemPtr(_hdsaHKI, nID);
  3747. if (phki && phki->wGHotkey)
  3748. {
  3749. TraceMsg(TF_TRAY, "c.hkl_hh: Hotkey listed.");
  3750. // Are global hotkeys enabled?
  3751. if (!_fGlobalHotkeyDisable)
  3752. {
  3753. // Yep.
  3754. HWND hwnd = _HotkeyInUse(phki->wGHotkey);
  3755. // Make sure this hotkey isn't already in use by someone.
  3756. if (hwnd)
  3757. {
  3758. TraceMsg(TF_TRAY, "c.hkl_hh: Hotkey is already in use.");
  3759. // Activate it.
  3760. SwitchToThisWindow(GetLastActivePopup(hwnd), TRUE);
  3761. }
  3762. else
  3763. {
  3764. DECLAREWAITCURSOR;
  3765. // Exec the item.
  3766. SetWaitCursor();
  3767. TraceMsg(TF_TRAY, "c.hkl_hh: Hotkey is not in use, execing item.");
  3768. ASSERT(phki->pidlFolder && phki->pidlItem);
  3769. BOOL fRes = _ExecItemByPidls(_hwnd, phki->pidlFolder, phki->pidlItem);
  3770. ResetWaitCursor();
  3771. #ifdef DEBUG
  3772. if (!fRes)
  3773. {
  3774. DebugMsg(DM_ERROR, TEXT("c.hkl_hh: Can't exec command ."));
  3775. }
  3776. #endif
  3777. }
  3778. }
  3779. else
  3780. {
  3781. DebugMsg(DM_ERROR, TEXT("c.hkl_hh: Global hotkeys have been disabled."));
  3782. }
  3783. }
  3784. else
  3785. {
  3786. DebugMsg(DM_ERROR, TEXT("c.hkl_hh: Hotkey not listed."));
  3787. }
  3788. LeaveCriticalSection(&_csHotkey);
  3789. }
  3790. LRESULT CTray::_UnregisterHotkey(HWND hwnd, int i)
  3791. {
  3792. TraceMsg(TF_TRAY, "c.t_uh: Unregistering hotkey (%d).", i);
  3793. if (!UnregisterHotKey(hwnd, i))
  3794. {
  3795. DebugMsg(DM_ERROR, TEXT("c.t_rh: Unable to unregister hotkey %d."), i);
  3796. }
  3797. return TRUE;
  3798. }
  3799. // Add hotkey to the shell's list of global hotkeys.
  3800. LRESULT CTray::_ShortcutRegisterHotkey(HWND hwnd, WORD wHotkey, ATOM atom)
  3801. {
  3802. int i;
  3803. LPITEMIDLIST pidl;
  3804. TCHAR szPath[MAX_PATH];
  3805. ASSERT(atom);
  3806. if (GlobalGetAtomName(atom, szPath, MAX_PATH))
  3807. {
  3808. TraceMsg(TF_TRAY, "c.t_srh: Hotkey %d for %s", wHotkey, szPath);
  3809. pidl = ILCreateFromPath(szPath);
  3810. if (pidl)
  3811. {
  3812. i = _HotkeyAddCached(_MapHotkeyToGlobalHotkey(wHotkey), pidl);
  3813. if (i != -1)
  3814. {
  3815. _RegisterHotkey(_hwnd, i);
  3816. }
  3817. }
  3818. return TRUE;
  3819. }
  3820. else
  3821. {
  3822. return FALSE;
  3823. }
  3824. }
  3825. // Remove hotkey from shell's list.
  3826. LRESULT CTray::_ShortcutUnregisterHotkey(HWND hwnd, WORD wHotkey)
  3827. {
  3828. // DebugMsg(DM_TRACE, "c.t_suh: Hotkey %d", wHotkey);
  3829. int i = _HotkeyRemove(wHotkey);
  3830. if (i == -1)
  3831. i = _HotkeyRemoveCached(_MapHotkeyToGlobalHotkey(wHotkey));
  3832. if (i != -1)
  3833. _UnregisterHotkey(hwnd, i);
  3834. return TRUE;
  3835. }
  3836. LRESULT CTray::_RegisterHotkey(HWND hwnd, int i)
  3837. {
  3838. HOTKEYITEM *phki;
  3839. WORD wGHotkey = 0;
  3840. ASSERT(IS_VALID_HANDLE(_hdsaHKI, DSA));
  3841. TraceMsg(TF_TRAY, "c.t_rh: Registering hotkey (%d).", i);
  3842. EnterCriticalSection(&_csHotkey);
  3843. phki = (HOTKEYITEM *)DSA_GetItemPtr(_hdsaHKI, i);
  3844. ASSERT(phki);
  3845. if (phki)
  3846. {
  3847. wGHotkey = phki->wGHotkey;
  3848. }
  3849. LeaveCriticalSection(&_csHotkey);
  3850. if (wGHotkey)
  3851. {
  3852. // Is the hotkey available?
  3853. if (RegisterHotKey(hwnd, i, HIBYTE(wGHotkey), LOBYTE(wGHotkey)))
  3854. {
  3855. // Yes.
  3856. return TRUE;
  3857. }
  3858. else
  3859. {
  3860. // Delete any cached items that might be using this
  3861. // hotkey.
  3862. int iCached = _HotkeyRemoveCached(wGHotkey);
  3863. ASSERT(iCached != i);
  3864. if (iCached != -1)
  3865. {
  3866. // Free up the hotkey for us.
  3867. _UnregisterHotkey(hwnd, iCached);
  3868. // Yep, nuked the cached item. Try again.
  3869. if (RegisterHotKey(hwnd, i, HIBYTE(wGHotkey), LOBYTE(wGHotkey)))
  3870. {
  3871. return TRUE;
  3872. }
  3873. }
  3874. }
  3875. // Can't set hotkey for this item.
  3876. DebugMsg(DM_ERROR, TEXT("c.t_rh: Unable to register hotkey %d."), i);
  3877. // Null out this item.
  3878. phki->wGHotkey = 0;
  3879. phki->pidlFolder = NULL;
  3880. phki->pidlItem = NULL;
  3881. }
  3882. else
  3883. {
  3884. DebugMsg(DM_ERROR, TEXT("c.t_rh: Hotkey item is invalid."));
  3885. }
  3886. return FALSE;
  3887. }
  3888. #define GetABDHWnd(pabd) ((HWND)ULongToPtr((pabd)->dwWnd))
  3889. void CTray::_AppBarGetTaskBarPos(PTRAYAPPBARDATA ptabd)
  3890. {
  3891. APPBARDATA3264 *pabd;
  3892. pabd = (APPBARDATA3264*)SHLockShared(UlongToPtr(ptabd->hSharedABD), ptabd->dwProcId);
  3893. if (pabd)
  3894. {
  3895. pabd->rc = _arStuckRects[_uStuckPlace];
  3896. pabd->uEdge = _uStuckPlace; // compat: new to ie4
  3897. SHUnlockShared(pabd);
  3898. }
  3899. }
  3900. void CTray::_NukeAppBar(int i)
  3901. {
  3902. LocalFree(DPA_GetPtr(_hdpaAppBars, i));
  3903. DPA_DeletePtr(_hdpaAppBars, i);
  3904. }
  3905. void CTray::_AppBarRemove(PTRAYAPPBARDATA ptabd)
  3906. {
  3907. int i;
  3908. if (!_hdpaAppBars)
  3909. return;
  3910. i = DPA_GetPtrCount(_hdpaAppBars);
  3911. while (i--)
  3912. {
  3913. PAPPBAR pab = (PAPPBAR)DPA_GetPtr(_hdpaAppBars, i);
  3914. if (GetABDHWnd(&ptabd->abd) == pab->hwnd)
  3915. {
  3916. RECT rcNuke = pab->rc;
  3917. _NukeAppBar(i);
  3918. _StuckAppChange(GetABDHWnd(&ptabd->abd), &rcNuke, NULL, FALSE);
  3919. }
  3920. }
  3921. }
  3922. PAPPBAR CTray::_FindAppBar(HWND hwnd)
  3923. {
  3924. if (_hdpaAppBars)
  3925. {
  3926. int i = DPA_GetPtrCount(_hdpaAppBars);
  3927. while (i--)
  3928. {
  3929. PAPPBAR pab = (PAPPBAR)DPA_GetPtr(_hdpaAppBars, i);
  3930. if (hwnd == pab->hwnd)
  3931. return pab;
  3932. }
  3933. }
  3934. return NULL;
  3935. }
  3936. void CTray::_AppBarNotifyAll(HMONITOR hmon, UINT uMsg, HWND hwndExclude, LPARAM lParam)
  3937. {
  3938. if (!_hdpaAppBars)
  3939. return;
  3940. int i = DPA_GetPtrCount(_hdpaAppBars);
  3941. while (i--)
  3942. {
  3943. PAPPBAR pab = (PAPPBAR)DPA_GetPtr(_hdpaAppBars, i);
  3944. // We need to check pab here as an appbar can delete other
  3945. // appbars on the callback.
  3946. if (pab && (hwndExclude != pab->hwnd))
  3947. {
  3948. if (!IsWindow(pab->hwnd))
  3949. {
  3950. _NukeAppBar(i);
  3951. continue;
  3952. }
  3953. //
  3954. // if a monitor was specified only tell appbars on that display
  3955. //
  3956. if (hmon &&
  3957. (hmon != MonitorFromWindow(pab->hwnd, MONITOR_DEFAULTTONULL)))
  3958. {
  3959. continue;
  3960. }
  3961. PostMessage(pab->hwnd, pab->uCallbackMessage, uMsg, lParam);
  3962. }
  3963. }
  3964. }
  3965. BOOL CTray::_AppBarNew(PTRAYAPPBARDATA ptabd)
  3966. {
  3967. PAPPBAR pab;
  3968. if (!_hdpaAppBars)
  3969. {
  3970. _hdpaAppBars = DPA_Create(4);
  3971. if (!_hdpaAppBars)
  3972. return FALSE;
  3973. }
  3974. else if (_FindAppBar(GetABDHWnd(&ptabd->abd)))
  3975. {
  3976. // already have this hwnd
  3977. return FALSE;
  3978. }
  3979. pab = (PAPPBAR)LocalAlloc(LPTR, sizeof(APPBAR));
  3980. if (!pab)
  3981. return FALSE;
  3982. pab->hwnd = GetABDHWnd(&ptabd->abd);
  3983. pab->uCallbackMessage = ptabd->abd.uCallbackMessage;
  3984. pab->uEdge = (UINT)-1;
  3985. if (DPA_AppendPtr(_hdpaAppBars, pab) == -1)
  3986. {
  3987. // insertion failed
  3988. LocalFree(pab);
  3989. return FALSE;
  3990. }
  3991. return TRUE;
  3992. }
  3993. BOOL CTray::_AppBarOutsideOf(PAPPBAR pabReq, PAPPBAR pab)
  3994. {
  3995. if (pabReq->uEdge == pab->uEdge)
  3996. {
  3997. switch (pab->uEdge)
  3998. {
  3999. case ABE_RIGHT:
  4000. return (pab->rc.right >= pabReq->rc.right);
  4001. case ABE_BOTTOM:
  4002. return (pab->rc.bottom >= pabReq->rc.bottom);
  4003. case ABE_TOP:
  4004. return (pab->rc.top <= pabReq->rc.top);
  4005. case ABE_LEFT:
  4006. return (pab->rc.left <= pabReq->rc.left);
  4007. }
  4008. }
  4009. return FALSE;
  4010. }
  4011. void CTray::_AppBarQueryPos(PTRAYAPPBARDATA ptabd)
  4012. {
  4013. int i;
  4014. PAPPBAR pabReq = _FindAppBar(GetABDHWnd(&ptabd->abd));
  4015. if (pabReq)
  4016. {
  4017. APPBARDATA3264 *pabd;
  4018. pabd = (APPBARDATA3264*)SHLockShared(UlongToPtr(ptabd->hSharedABD), ptabd->dwProcId);
  4019. if (pabd)
  4020. {
  4021. HMONITOR hmon;
  4022. pabd->rc = ptabd->abd.rc;
  4023. //
  4024. // default to the primary display for this call because old appbars
  4025. // sometimes pass a huge rect and let us pare it down. if they do
  4026. // something like that they don't support multiple displays anyway
  4027. // so just put them on the primary display...
  4028. //
  4029. hmon = MonitorFromRect(&pabd->rc, MONITOR_DEFAULTTOPRIMARY);
  4030. //
  4031. // always subtract off the tray if it's on the same display
  4032. //
  4033. if (!_uAutoHide && (hmon == _hmonStuck))
  4034. {
  4035. APPBAR ab;
  4036. ab.uEdge = _GetDockedRect(&ab.rc, FALSE);
  4037. _AppBarSubtractRect(&ab, &pabd->rc);
  4038. }
  4039. i = DPA_GetPtrCount(_hdpaAppBars);
  4040. while (i--)
  4041. {
  4042. PAPPBAR pab = (PAPPBAR)DPA_GetPtr(_hdpaAppBars, i);
  4043. //
  4044. // give top and bottom preference
  4045. // ||
  4046. // if we're not changing edges,
  4047. // subtract anything currently on the outside of us
  4048. // ||
  4049. // if we are changing sides,
  4050. // subtract off everything on the new side.
  4051. //
  4052. // of course ignore appbars which are not on the same display...
  4053. //
  4054. if ((((pabReq->hwnd != pab->hwnd) &&
  4055. STUCK_HORIZONTAL(pab->uEdge) &&
  4056. !STUCK_HORIZONTAL(ptabd->abd.uEdge)) ||
  4057. ((pabReq->hwnd != pab->hwnd) &&
  4058. (pabReq->uEdge == ptabd->abd.uEdge) &&
  4059. _AppBarOutsideOf(pabReq, pab)) ||
  4060. ((pabReq->hwnd != pab->hwnd) &&
  4061. (pabReq->uEdge != ptabd->abd.uEdge) &&
  4062. (pab->uEdge == ptabd->abd.uEdge))) &&
  4063. (hmon == MonitorFromRect(&pab->rc, MONITOR_DEFAULTTONULL)))
  4064. {
  4065. _AppBarSubtractRect(pab, &pabd->rc);
  4066. }
  4067. }
  4068. SHUnlockShared(pabd);
  4069. }
  4070. }
  4071. }
  4072. void CTray::_AppBarSetPos(PTRAYAPPBARDATA ptabd)
  4073. {
  4074. PAPPBAR pab = _FindAppBar(GetABDHWnd(&ptabd->abd));
  4075. if (pab)
  4076. {
  4077. RECT rcOld;
  4078. APPBARDATA3264 *pabd;
  4079. BOOL fChanged = FALSE;
  4080. _AppBarQueryPos(ptabd);
  4081. pabd = (APPBARDATA3264*)SHLockShared(UlongToPtr(ptabd->hSharedABD), ptabd->dwProcId);
  4082. if (pabd)
  4083. {
  4084. if (!EqualRect(&pab->rc, &pabd->rc)) {
  4085. rcOld = pab->rc;
  4086. pab->rc = pabd->rc;
  4087. pab->uEdge = ptabd->abd.uEdge;
  4088. fChanged = TRUE;
  4089. }
  4090. SHUnlockShared(pabd);
  4091. }
  4092. if (fChanged)
  4093. _StuckAppChange(GetABDHWnd(&ptabd->abd), &rcOld, &pab->rc, FALSE);
  4094. }
  4095. }
  4096. //
  4097. // FEATURE: need to get rid of this array-based implementation to allow autohide
  4098. // appbars on secondary display (or a/h tray on 2nd with a/h appbar on primary)
  4099. // change it to an _AppBarFindAutoHideBar that keeps flags on the appbardata...
  4100. //
  4101. HWND CTray::_AppBarGetAutoHideBar(UINT uEdge)
  4102. {
  4103. if (uEdge >= ABE_MAX)
  4104. return FALSE;
  4105. else
  4106. {
  4107. HWND hwndAutoHide = _aHwndAutoHide[uEdge];
  4108. if (!IsWindow(hwndAutoHide))
  4109. {
  4110. _aHwndAutoHide[uEdge] = NULL;
  4111. }
  4112. return _aHwndAutoHide[uEdge];
  4113. }
  4114. }
  4115. BOOL CTray::_AppBarSetAutoHideBar2(HWND hwnd, BOOL fAutoHide, UINT uEdge)
  4116. {
  4117. HWND hwndAutoHide = _aHwndAutoHide[uEdge];
  4118. if (!IsWindow(hwndAutoHide))
  4119. {
  4120. _aHwndAutoHide[uEdge] = NULL;
  4121. }
  4122. if (fAutoHide)
  4123. {
  4124. // register
  4125. if (!_aHwndAutoHide[uEdge])
  4126. {
  4127. _aHwndAutoHide[uEdge] = hwnd;
  4128. }
  4129. return _aHwndAutoHide[uEdge] == hwnd;
  4130. }
  4131. else
  4132. {
  4133. // unregister
  4134. if (_aHwndAutoHide[uEdge] == hwnd)
  4135. {
  4136. _aHwndAutoHide[uEdge] = NULL;
  4137. }
  4138. return TRUE;
  4139. }
  4140. }
  4141. BOOL CTray::_AppBarSetAutoHideBar(PTRAYAPPBARDATA ptabd)
  4142. {
  4143. UINT uEdge = ptabd->abd.uEdge;
  4144. if (uEdge >= ABE_MAX)
  4145. return FALSE;
  4146. else {
  4147. return _AppBarSetAutoHideBar2(GetABDHWnd(&ptabd->abd), BOOLFROMPTR(ptabd->abd.lParam), uEdge);
  4148. }
  4149. }
  4150. void CTray::_AppBarActivationChange2(HWND hwnd, UINT uEdge)
  4151. {
  4152. //
  4153. // FEATURE: make this multi-monitor cool
  4154. //
  4155. HWND hwndAutoHide = _AppBarGetAutoHideBar(uEdge);
  4156. if (hwndAutoHide && (hwndAutoHide != hwnd))
  4157. {
  4158. //
  4159. // the _AppBar got this notification inside a SendMessage from USER
  4160. // and is now in a SendMessage to us. don't try to do a SetWindowPos
  4161. // right now...
  4162. //
  4163. PostMessage(_hwnd, TM_BRINGTOTOP, (WPARAM)hwndAutoHide, uEdge);
  4164. }
  4165. }
  4166. void CTray::_AppBarActivationChange(PTRAYAPPBARDATA ptabd)
  4167. {
  4168. PAPPBAR pab = _FindAppBar(GetABDHWnd(&ptabd->abd));
  4169. if (pab)
  4170. {
  4171. // if this is an autohide bar and they're claiming to be on an edge not the same as their autohide edge,
  4172. // we don't do any activation of other autohides
  4173. for (UINT i = 0; i < ABE_MAX; i++)
  4174. {
  4175. if (_aHwndAutoHide[i] == GetABDHWnd(&ptabd->abd) &&
  4176. i != pab->uEdge)
  4177. return;
  4178. }
  4179. _AppBarActivationChange2(GetABDHWnd(&ptabd->abd), pab->uEdge);
  4180. }
  4181. }
  4182. LRESULT CTray::_OnAppBarMessage(PCOPYDATASTRUCT pcds)
  4183. {
  4184. PTRAYAPPBARDATA ptabd = (PTRAYAPPBARDATA)pcds->lpData;
  4185. ASSERT(pcds->cbData == sizeof(TRAYAPPBARDATA));
  4186. ASSERT(ptabd->abd.cbSize == sizeof(APPBARDATA3264));
  4187. switch (ptabd->dwMessage) {
  4188. case ABM_NEW:
  4189. return _AppBarNew(ptabd);
  4190. case ABM_REMOVE:
  4191. _AppBarRemove(ptabd);
  4192. break;
  4193. case ABM_QUERYPOS:
  4194. _AppBarQueryPos(ptabd);
  4195. break;
  4196. case ABM_SETPOS:
  4197. _AppBarSetPos(ptabd);
  4198. break;
  4199. case ABM_GETSTATE:
  4200. return _desktray.AppBarGetState();
  4201. case ABM_SETSTATE:
  4202. _AppBarSetState((UINT)ptabd->abd.lParam);
  4203. break;
  4204. case ABM_GETTASKBARPOS:
  4205. _AppBarGetTaskBarPos(ptabd);
  4206. break;
  4207. case ABM_WINDOWPOSCHANGED:
  4208. case ABM_ACTIVATE:
  4209. _AppBarActivationChange(ptabd);
  4210. break;
  4211. case ABM_GETAUTOHIDEBAR:
  4212. return (LRESULT)_AppBarGetAutoHideBar(ptabd->abd.uEdge);
  4213. case ABM_SETAUTOHIDEBAR:
  4214. return _AppBarSetAutoHideBar(ptabd);
  4215. default:
  4216. return FALSE;
  4217. }
  4218. return TRUE;
  4219. }
  4220. // EA486701-7F92-11cf-9E05-444553540000
  4221. const GUID CLSID_HIJACKINPROC = {0xEA486701, 0x7F92, 0x11cf, 0x9E, 0x05, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00};
  4222. HRESULT CTray::_LoadInProc(PCOPYDATASTRUCT pcds)
  4223. {
  4224. ASSERT(pcds->cbData == sizeof(LOADINPROCDATA));
  4225. PLOADINPROCDATA plipd = (PLOADINPROCDATA)pcds->lpData;
  4226. // Hack to allow us to kill W95 shell extensions that do reall hacky things that
  4227. // we can not support. In this case Hijack pro
  4228. if (IsEqualIID(plipd->clsid, CLSID_HIJACKINPROC))
  4229. {
  4230. return E_FAIL;
  4231. }
  4232. return _ssomgr.EnableObject(&plipd->clsid, plipd->dwFlags);
  4233. }
  4234. // Allow the trays global hotkeys to be disabled for a while.
  4235. LRESULT CTray::_SetHotkeyEnable(HWND hwnd, BOOL fEnable)
  4236. {
  4237. _fGlobalHotkeyDisable = !fEnable;
  4238. return TRUE;
  4239. }
  4240. BOOL IsPosInHwnd(LPARAM lParam, HWND hwnd)
  4241. {
  4242. RECT r1;
  4243. POINT pt;
  4244. pt.x = GET_X_LPARAM(lParam);
  4245. pt.y = GET_Y_LPARAM(lParam);
  4246. GetWindowRect(hwnd, &r1);
  4247. return PtInRect(&r1, pt);
  4248. }
  4249. void CTray::_HandleWindowPosChanging(LPWINDOWPOS lpwp)
  4250. {
  4251. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.t_hwpc"));
  4252. if (_uMoveStuckPlace != (UINT)-1)
  4253. {
  4254. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.t_hwpc handling pending move"));
  4255. _DoneMoving(lpwp);
  4256. }
  4257. else if (_fSysSizing || !_fSelfSizing)
  4258. {
  4259. RECT rc;
  4260. if (_fSysSizing)
  4261. {
  4262. GetWindowRect(_hwnd, &rc);
  4263. if (!(lpwp->flags & SWP_NOMOVE))
  4264. {
  4265. rc.left = lpwp->x;
  4266. rc.top = lpwp->y;
  4267. }
  4268. if (!(lpwp->flags & SWP_NOSIZE))
  4269. {
  4270. rc.right = rc.left + lpwp->cx;
  4271. rc.bottom = rc.top + lpwp->cy;
  4272. }
  4273. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.t_hwpc sys sizing to rect {%d, %d, %d, %d}"), rc.left, rc.top, rc.right, rc.bottom);
  4274. _uStuckPlace = _RecalcStuckPos(&rc);
  4275. _UpdateVertical(_uStuckPlace);
  4276. }
  4277. _GetDockedRect(&rc, _fSysSizing);
  4278. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.t_hwpc using rect {%d, %d, %d, %d}"), rc.left, rc.top, rc.right, rc.bottom);
  4279. lpwp->x = rc.left;
  4280. lpwp->y = rc.top;
  4281. lpwp->cx = RECTWIDTH(rc);
  4282. lpwp->cy = RECTHEIGHT(rc);
  4283. lpwp->flags &= ~(SWP_NOMOVE | SWP_NOSIZE);
  4284. }
  4285. lpwp->flags |= SWP_FRAMECHANGED;
  4286. }
  4287. void CTray::_HandlePowerStatus(UINT uMsg, WPARAM wParam, LPARAM lParam)
  4288. {
  4289. BOOL fResetDisplay = FALSE;
  4290. //
  4291. // always reset the display when the machine wakes up from a
  4292. // suspend. NOTE: we don't need this for a standby suspend.
  4293. //
  4294. // a critical resume does not generate a WM_POWERBROADCAST
  4295. // to windows for some reason, but it does generate an old
  4296. // WM_POWER message.
  4297. //
  4298. switch (uMsg)
  4299. {
  4300. case WM_POWER:
  4301. fResetDisplay = (wParam == PWR_CRITICALRESUME);
  4302. break;
  4303. case WM_POWERBROADCAST:
  4304. switch (wParam)
  4305. {
  4306. case PBT_APMRESUMECRITICAL:
  4307. fResetDisplay = TRUE;
  4308. break;
  4309. }
  4310. break;
  4311. }
  4312. if (fResetDisplay)
  4313. ChangeDisplaySettings(NULL, CDS_RESET);
  4314. }
  4315. //////////////////////////////////////////////////////
  4316. //
  4317. // This function checks whether we need to run the cleaner
  4318. // We will not run if user is guest, user has forced us not to, or if the requisite
  4319. // number of days have not yet elapsed
  4320. //
  4321. // We execute a great deal of code to decide whether to run or not that logically should be
  4322. // in fldrclnr.dll, but we execute it here so that we don't have to load fldrclnr.dll unless
  4323. // we absolutely have to, since we execute this path on every logon of explorer.exe
  4324. //
  4325. #define REGSTR_PATH_CLEANUPWIZ REGSTR_PATH_EXPLORER TEXT("\\Desktop\\CleanupWiz")
  4326. #define REGSTR_OEM_PATH REGSTR_PATH_SETUP TEXT("\\OemStartMenuData")
  4327. #define REGSTR_VAL_TIME TEXT("Last used time")
  4328. #define REGSTR_VAL_DELTA_DAYS TEXT("Days between clean up")
  4329. #define REGSTR_VAL_DONTRUN TEXT("NoRun")
  4330. #define REGSTR_OEM_OPTIN TEXT("DoDesktopCleanup")
  4331. //
  4332. // iDays can be negative or positive, indicating time in the past or future
  4333. //
  4334. //
  4335. #define FTsPerDayOver1000 (10000*60*60*24) // we've got (1000 x 10,000) 100ns intervals per second
  4336. void CTray::_DesktopCleanup_GetFileTimeNDaysFromGivenTime(const FILETIME *pftGiven, FILETIME * pftReturn, int iDays)
  4337. {
  4338. __int64 i64 = *((__int64 *) pftGiven);
  4339. i64 += Int32x32To64(iDays*1000,FTsPerDayOver1000);
  4340. *pftReturn = *((FILETIME *) &i64);
  4341. }
  4342. //////////////////////////////////////////////////////
  4343. BOOL CTray::_DesktopCleanup_ShouldRun()
  4344. {
  4345. BOOL fRetVal = FALSE;
  4346. if (!IsOS(OS_ANYSERVER) &&
  4347. _fIsDesktopConnected &&
  4348. !SHTestTokenMembership(NULL, DOMAIN_ALIAS_RID_GUESTS) &&
  4349. !SHRestricted(REST_NODESKTOPCLEANUP))
  4350. {
  4351. fRetVal = TRUE;
  4352. FILETIME ftNow, ftLast;
  4353. SYSTEMTIME st;
  4354. GetLocalTime(&st);
  4355. SystemTimeToFileTime(&st, &ftNow);
  4356. DWORD cb = sizeof(ftLast);
  4357. DWORD dwData;
  4358. if (ERROR_SUCCESS != SHRegGetUSValue(REGSTR_PATH_CLEANUPWIZ, REGSTR_VAL_TIME,
  4359. NULL, &ftLast, &cb, FALSE, NULL, 0))
  4360. {
  4361. cb = sizeof(dwData);
  4362. if ((ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, REGSTR_OEM_PATH, REGSTR_OEM_OPTIN, NULL, &dwData, &cb)) &&
  4363. (dwData != 0))
  4364. {
  4365. // to get the timer to kick in 60 days from now, set last to be now
  4366. ftLast = ftNow;
  4367. }
  4368. else
  4369. {
  4370. // to get the timer to kick in 14 days from now, set last to be 46 days ago
  4371. _DesktopCleanup_GetFileTimeNDaysFromGivenTime(&ftNow, &ftLast, -60 + 14);
  4372. }
  4373. SHRegSetUSValue(REGSTR_PATH_CLEANUPWIZ, REGSTR_VAL_TIME, NULL, &ftLast, sizeof(ftLast), SHREGSET_FORCE_HKCU);
  4374. }
  4375. HUSKEY hkey = NULL;
  4376. if (ERROR_SUCCESS == SHRegOpenUSKey(REGSTR_PATH_CLEANUPWIZ, KEY_READ, NULL, &hkey, FALSE))
  4377. {
  4378. //
  4379. // if we're in normal mode and the DONT RUN flag is set, we return immediately
  4380. // (the user checked the "don't run automatically" box)
  4381. //
  4382. cb = sizeof (DWORD);
  4383. if ((ERROR_SUCCESS == SHRegQueryUSValue(hkey, REGSTR_VAL_DONTRUN, NULL, &dwData, &cb, FALSE, NULL, 0)) &&
  4384. (dwData != 0))
  4385. {
  4386. fRetVal = FALSE;
  4387. }
  4388. else
  4389. {
  4390. //
  4391. // we need to figure out if if we are within the (last run time + delta days)
  4392. // time period
  4393. //
  4394. int iDays = 60;
  4395. if (ERROR_SUCCESS == (SHRegGetUSValue(REGSTR_PATH_CLEANUPWIZ, REGSTR_VAL_DELTA_DAYS,
  4396. NULL, &dwData, &cb,FALSE, NULL, 0)))
  4397. {
  4398. iDays = dwData;
  4399. }
  4400. // if (iDays == 0), run every time!
  4401. if (iDays > 0)
  4402. {
  4403. FILETIME ftRange;
  4404. _DesktopCleanup_GetFileTimeNDaysFromGivenTime(&ftLast, &ftRange, iDays);
  4405. if (!(CompareFileTime(&ftNow, &ftRange) > 0))
  4406. {
  4407. fRetVal = FALSE;
  4408. }
  4409. }
  4410. }
  4411. SHRegCloseUSKey(hkey);
  4412. }
  4413. }
  4414. return fRetVal;
  4415. }
  4416. void CTray::_CheckDesktopCleanup()
  4417. {
  4418. if (_DesktopCleanup_ShouldRun())
  4419. {
  4420. PROCESS_INFORMATION pi = {0};
  4421. TCHAR szRunDll32[MAX_PATH];
  4422. GetSystemDirectory(szRunDll32, ARRAYSIZE(szRunDll32));
  4423. PathAppend(szRunDll32, TEXT("rundll32.exe"));
  4424. if (CreateProcessWithArgs(szRunDll32, TEXT("fldrclnr.dll,Wizard_RunDLL"), NULL, &pi))
  4425. {
  4426. CloseHandle(pi.hProcess);
  4427. CloseHandle(pi.hThread);
  4428. }
  4429. }
  4430. }
  4431. //////////////////////////////////////////////////////
  4432. //
  4433. // Try tacking a 1, 2, 3 or whatever on to a file or
  4434. // directory name until it is unique. When on a file,
  4435. // stick it before the extension.
  4436. //
  4437. void _MakeBetterUniqueName(LPTSTR pszPathName)
  4438. {
  4439. TCHAR szNewPath[MAX_PATH];
  4440. int i = 1;
  4441. if (PathIsDirectory(pszPathName))
  4442. {
  4443. do
  4444. {
  4445. wsprintf(szNewPath, TEXT("%s%d"), pszPathName, i++);
  4446. } while (-1 != GetFileAttributes(szNewPath));
  4447. lstrcpy(pszPathName, szNewPath);
  4448. }
  4449. else
  4450. {
  4451. TCHAR szExt[MAX_PATH];
  4452. LPTSTR pszExt;
  4453. pszExt = PathFindExtension(pszPathName);
  4454. if (pszExt)
  4455. {
  4456. lstrcpy(szExt, pszExt);
  4457. *pszExt = 0;
  4458. do
  4459. {
  4460. wsprintf(szNewPath, TEXT("%s%d%s"), pszPathName, i++,szExt);
  4461. } while (-1 != GetFileAttributes(szNewPath));
  4462. lstrcpy(pszPathName, szNewPath);
  4463. }
  4464. }
  4465. }
  4466. BOOL_PTR WINAPI CTray::RogueProgramFileDlgProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
  4467. {
  4468. TCHAR szBuffer[MAX_PATH*2];
  4469. TCHAR szBuffer2[MAX_PATH*2];
  4470. static TCHAR szBetterPath[MAX_PATH];
  4471. static TCHAR *pszPath = NULL;
  4472. switch (iMsg)
  4473. {
  4474. case WM_INITDIALOG:
  4475. pszPath = (TCHAR *)lParam;
  4476. lstrcpy(szBetterPath, pszPath);
  4477. _MakeBetterUniqueName(szBetterPath);
  4478. SendDlgItemMessage(hWnd, IDC_MSG, WM_GETTEXT, (WPARAM)(MAX_PATH*2), (LPARAM)szBuffer);
  4479. wsprintf(szBuffer2, szBuffer, pszPath, szBetterPath);
  4480. SendDlgItemMessage(hWnd, IDC_MSG, WM_SETTEXT, (WPARAM)0, (LPARAM)szBuffer2);
  4481. return TRUE;
  4482. case WM_COMMAND:
  4483. switch(LOWORD(wParam))
  4484. {
  4485. case IDC_RENAME:
  4486. //rename and fall through
  4487. if (pszPath)
  4488. {
  4489. MoveFile(pszPath, szBetterPath);
  4490. }
  4491. EndDialog(hWnd, IDC_RENAME);
  4492. return TRUE;
  4493. case IDIGNORE:
  4494. EndDialog(hWnd, IDIGNORE);
  4495. return TRUE;
  4496. }
  4497. break;
  4498. }
  4499. return FALSE;
  4500. }
  4501. //
  4502. // Check to see if there are any files or folders that could interfere
  4503. // with the fact that Program Files has a space in it.
  4504. //
  4505. // An example would be a directory called: "C:\Program" or a file called"C:\Program.exe".
  4506. //
  4507. // This can prevent apps that dont quote strings in the registry or call CreateProcess with
  4508. // unquoted strings from working properly since CreateProcess wont know what the real exe is.
  4509. //
  4510. void CTray::_CheckForRogueProgramFile()
  4511. {
  4512. TCHAR szProgramFilesPath[MAX_PATH];
  4513. TCHAR szProgramFilesShortName[MAX_PATH];
  4514. if (S_OK == SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, SHGFP_TYPE_CURRENT, szProgramFilesPath))
  4515. {
  4516. LPTSTR pszRoguePattern;
  4517. pszRoguePattern = StrChr(szProgramFilesPath, TEXT(' '));
  4518. if (pszRoguePattern)
  4519. {
  4520. HANDLE hFind;
  4521. WIN32_FIND_DATA wfd;
  4522. // Remember short name for folder name comparison below
  4523. *pszRoguePattern = TEXT('\0');
  4524. lstrcpy(szProgramFilesShortName, szProgramFilesPath);
  4525. // turn "C:\program files" into "C:\program.*"
  4526. lstrcpy(pszRoguePattern, TEXT(".*"));
  4527. pszRoguePattern = szProgramFilesPath;
  4528. hFind = FindFirstFile(pszRoguePattern, &wfd);
  4529. while (hFind != INVALID_HANDLE_VALUE)
  4530. {
  4531. int iRet = 0;
  4532. TCHAR szRogueFileName[MAX_PATH];
  4533. // we found a file (eg "c:\Program.txt")
  4534. lstrcpyn(szRogueFileName, pszRoguePattern, ARRAYSIZE(szRogueFileName));
  4535. PathRemoveFileSpec(szRogueFileName);
  4536. lstrcatn(szRogueFileName, wfd.cFileName, ARRAYSIZE(szRogueFileName));
  4537. // don't worry about folders unless they are called "Program"
  4538. if (!((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  4539. lstrcmpi(szProgramFilesShortName, szRogueFileName) != 0))
  4540. {
  4541. iRet = SHMessageBoxCheckEx(GetDesktopWindow(),
  4542. hinstCabinet,
  4543. MAKEINTRESOURCE(DLG_PROGRAMFILECONFLICT),
  4544. RogueProgramFileDlgProc,
  4545. (void *)szRogueFileName,
  4546. IDIGNORE,
  4547. TEXT("RogueProgramName"));
  4548. }
  4549. if ((iRet == IDIGNORE) || !FindNextFile(hFind, &wfd))
  4550. {
  4551. // user hit ignore or we are done, so don't keep going
  4552. break;
  4553. }
  4554. }
  4555. if (hFind != INVALID_HANDLE_VALUE)
  4556. {
  4557. FindClose(hFind);
  4558. }
  4559. }
  4560. }
  4561. }
  4562. void CTray::_OnWaitCursorNotify(LPNMHDR pnm)
  4563. {
  4564. _iWaitCount += (pnm->code == NM_STARTWAIT ? 1 :-1);
  4565. ASSERT(_iWaitCount >= 0);
  4566. // Don't let it go negative or we'll never get rid of it.
  4567. if (_iWaitCount < 0)
  4568. _iWaitCount = 0;
  4569. // what we really want is for user to simulate a mouse move/setcursor
  4570. SetCursor(LoadCursor(NULL, _iWaitCount ? IDC_APPSTARTING : IDC_ARROW));
  4571. }
  4572. void CTray::_HandlePrivateCommand(LPARAM lParam)
  4573. {
  4574. LPSTR psz = (LPSTR) lParam; // lParam always ansi.
  4575. if (!lstrcmpiA(psz, "ToggleDesktop"))
  4576. {
  4577. _RaiseDesktop(!g_fDesktopRaised, TRUE);
  4578. }
  4579. else if (!lstrcmpiA(psz, "Explorer"))
  4580. {
  4581. // Fast way to bring up explorer window on root of
  4582. // windows dir.
  4583. SHELLEXECUTEINFO shei = {0};
  4584. TCHAR szPath[MAX_PATH];
  4585. if (GetWindowsDirectory(szPath, ARRAYSIZE(szPath)) != 0)
  4586. {
  4587. PathStripToRoot(szPath);
  4588. shei.lpIDList = ILCreateFromPath(szPath);
  4589. if (shei.lpIDList)
  4590. {
  4591. shei.cbSize = sizeof(shei);
  4592. shei.fMask = SEE_MASK_IDLIST;
  4593. shei.nShow = SW_SHOWNORMAL;
  4594. shei.lpVerb = TEXT("explore");
  4595. ShellExecuteEx(&shei);
  4596. ILFree((LPITEMIDLIST)shei.lpIDList);
  4597. }
  4598. }
  4599. }
  4600. LocalFree(psz);
  4601. }
  4602. //***
  4603. //
  4604. void CTray::_OnFocusMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
  4605. {
  4606. BOOL fActivate = (BOOL) wParam;
  4607. switch (uMsg)
  4608. {
  4609. case TM_UIACTIVATEIO:
  4610. {
  4611. #ifdef DEBUG
  4612. {
  4613. int dtb = (int) lParam;
  4614. TraceMsg(DM_FOCUS, "tiois: TM_UIActIO fAct=%d dtb=%d", fActivate, dtb);
  4615. ASSERT(dtb == 1 || dtb == -1);
  4616. }
  4617. #endif
  4618. if (fActivate)
  4619. {
  4620. // Since we are tabbing into the tray, turn the focus rect on.
  4621. SendMessage(_hwnd, WM_UPDATEUISTATE, MAKEWPARAM(UIS_CLEAR,
  4622. UISF_HIDEFOCUS), 0);
  4623. SendMessage(v_hwndDesktop, DTM_ONFOCUSCHANGEIS, TRUE, (LPARAM) _hwnd);
  4624. SetForegroundWindow(_hwnd);
  4625. // fake an IUnknown_UIActivateIO(_ptbs, TRUE, &msg);
  4626. if (GetAsyncKeyState(VK_SHIFT) < 0)
  4627. {
  4628. _SetFocus(_hwndNotify);
  4629. }
  4630. else
  4631. {
  4632. _SetFocus(_hwndStart);
  4633. }
  4634. }
  4635. else
  4636. {
  4637. Ldeact:
  4638. IUnknown_UIActivateIO(_ptbs, FALSE, NULL);
  4639. SetForegroundWindow(v_hwndDesktop);
  4640. }
  4641. break;
  4642. }
  4643. case TM_ONFOCUSCHANGEIS:
  4644. {
  4645. HWND hwnd = (HWND) lParam;
  4646. TraceMsg(DM_FOCUS, "tiois: TM_OnFocChgIS hwnd=%x fAct=%d", hwnd, fActivate);
  4647. if (fActivate)
  4648. {
  4649. // someone else is activating, so we need to deactivate
  4650. goto Ldeact;
  4651. }
  4652. break;
  4653. }
  4654. default:
  4655. ASSERT(0);
  4656. break;
  4657. }
  4658. return;
  4659. }
  4660. #define TSVC_NTIMER (IDT_SERVICELAST - IDT_SERVICE0 + 1)
  4661. struct {
  4662. #ifdef DEBUG
  4663. UINT_PTR idtWin;
  4664. #endif
  4665. TIMERPROC pfnSvc;
  4666. } g_timerService[TSVC_NTIMER];
  4667. #define TSVC_IDToIndex(id) ((id) - IDT_SERVICE0)
  4668. #define TSVC_IndexToID(i) ((i) + IDT_SERVICE0)
  4669. int CTray::_OnTimerService(UINT uMsg, WPARAM wParam, LPARAM lParam)
  4670. {
  4671. int i;
  4672. UINT_PTR idt;
  4673. TIMERPROC pfn;
  4674. BOOL b;
  4675. switch (uMsg) {
  4676. case TM_SETTIMER:
  4677. TraceMsg(DM_UEMTRACE, "e.TM_SETTIMER: wP=0x%x lP=%x", wParam, lParam);
  4678. ASSERT(IS_VALID_CODE_PTR(lParam, TIMERPROC));
  4679. for (i = 0; i < TSVC_NTIMER; i++) {
  4680. if (g_timerService[i].pfnSvc == 0) {
  4681. g_timerService[i].pfnSvc = (TIMERPROC)lParam;
  4682. idt = SetTimer(_hwnd, TSVC_IndexToID(i), (UINT)wParam, 0);
  4683. if (idt == 0) {
  4684. TraceMsg(DM_UEMTRACE, "e.TM_SETTIMER: ST()=%d (!)", idt);
  4685. break;
  4686. }
  4687. ASSERT(idt == (UINT_PTR)TSVC_IndexToID(i));
  4688. DBEXEC(TRUE, (g_timerService[i].idtWin = idt));
  4689. TraceMsg(DM_UEMTRACE, "e.TM_SETTIMER: ret=0x%x", TSVC_IndexToID(i));
  4690. return TSVC_IndexToID(i); // idtWin
  4691. }
  4692. }
  4693. TraceMsg(DM_UEMTRACE, "e.TM_SETTIMER: ret=0 (!)");
  4694. return 0;
  4695. case TM_KILLTIMER: // lP=idtWin
  4696. TraceMsg(DM_UEMTRACE, "e.TM_KILLTIMER: wP=0x%x lP=%x", wParam, lParam);
  4697. if (EVAL(IDT_SERVICE0 <= lParam && lParam <= IDT_SERVICE0 + TSVC_NTIMER - 1)) {
  4698. i = (int)TSVC_IDToIndex(lParam);
  4699. if (g_timerService[i].pfnSvc) {
  4700. ASSERT(g_timerService[i].idtWin == (UINT)lParam);
  4701. b = KillTimer(_hwnd, lParam);
  4702. ASSERT(b);
  4703. g_timerService[i].pfnSvc = 0;
  4704. DBEXEC(TRUE, (g_timerService[i].idtWin = 0));
  4705. return TRUE;
  4706. }
  4707. }
  4708. return 0;
  4709. case WM_TIMER: // wP=idtWin lP=0
  4710. TraceMsg(DM_UEMTRACE, "e.TM_TIMER: wP=0x%x lP=%x", wParam, lParam);
  4711. if (EVAL(IDT_SERVICE0 <= wParam && wParam <= IDT_SERVICE0 + TSVC_NTIMER - 1)) {
  4712. i = (int)TSVC_IDToIndex(wParam);
  4713. pfn = g_timerService[i].pfnSvc;
  4714. if (EVAL(IS_VALID_CODE_PTR(pfn, TIMERPROC)))
  4715. (*pfn)(_hwnd, WM_TIMER, wParam, GetTickCount());
  4716. }
  4717. return 0;
  4718. }
  4719. ASSERT(0); /*NOTREACHED*/
  4720. return 0;
  4721. }
  4722. void CTray::RealityCheck()
  4723. {
  4724. //
  4725. // Make sure that the tray's actual z-order position agrees with what we think
  4726. // it is. We need to do this because there's a recurring bug where the tray
  4727. // gets bumped out of TOPMOST position. (Lots of things, like a tray-owned
  4728. // window moving itself to non-TOPMOST or a random app messing with the tray
  4729. // window position, can cause this.)
  4730. //
  4731. _ResetZorder();
  4732. }
  4733. #define DELAY_STARTUPTROUBLESHOOT (15 * 1000)
  4734. void CTray::LogFailedStartupApp()
  4735. {
  4736. if (_hwnd)
  4737. {
  4738. PostMessage(_hwnd, TM_HANDLESTARTUPFAILED, 0, 0);
  4739. }
  4740. else
  4741. {
  4742. _fEarlyStartupFailure = TRUE;
  4743. }
  4744. }
  4745. void WINAPI CTray::TroubleShootStartupCB(HWND hwnd, UINT uMsg, UINT_PTR idTimer, DWORD dwTime)
  4746. {
  4747. KillTimer(hwnd, idTimer);
  4748. if (!c_tray._fStartupTroubleshooterLaunched)
  4749. {
  4750. TCHAR szCmdLine[MAX_PATH];
  4751. DWORD cb;
  4752. c_tray._fStartupTroubleshooterLaunched = TRUE;
  4753. cb = sizeof(szCmdLine);
  4754. if (SHGetValue(HKEY_LOCAL_MACHINE, REGSTR_PATH_EXPLORER,
  4755. TEXT("StartupTroubleshoot"), NULL,
  4756. szCmdLine, &cb) == ERROR_SUCCESS)
  4757. {
  4758. ShellExecuteRegApp(szCmdLine, RRA_NOUI | RRA_DELETE);
  4759. }
  4760. }
  4761. }
  4762. void CTray::_OnHandleStartupFailed()
  4763. {
  4764. /*
  4765. * Don't launch the troubleshooter until we have gone
  4766. * DELAY_STARTUPTROUBLESHOOT milliseconds without a startup problem.
  4767. * This gives time for the system to settle down before starting to
  4768. * annoy the user all over again.
  4769. *
  4770. * (And, of course, don't launch it more than once.)
  4771. */
  4772. if (!_fStartupTroubleshooterLaunched)
  4773. {
  4774. SetTimer(_hwnd, IDT_STARTUPFAILED, DELAY_STARTUPTROUBLESHOOT, TroubleShootStartupCB);
  4775. }
  4776. }
  4777. void CTray::_HandleDelayBootStuff()
  4778. {
  4779. // This posted message is the last one processed by the primary
  4780. // thread (tray thread) when we boot. At this point we will
  4781. // want to load the shell services (which usually create threads)
  4782. // and resume both the background start menu thread and the fs_notfiy
  4783. // thread.
  4784. if (!_fHandledDelayBootStuff)
  4785. {
  4786. if (GetShellWindow() == NULL)
  4787. {
  4788. // The desktop browser hasn't finished navigating yet.
  4789. SetTimer(_hwnd, IDT_HANDLEDELAYBOOTSTUFF, 3 * 1000, NULL);
  4790. return;
  4791. }
  4792. _fHandledDelayBootStuff = TRUE;
  4793. if (g_dwStopWatchMode)
  4794. {
  4795. StopWatch_StartTimed(SWID_STARTUP, TEXT("_DelayedBootStuff"), SPMODE_SHELL | SPMODE_DEBUGOUT, GetPerfTime());
  4796. }
  4797. PostMessage(_hwnd, TM_SHELLSERVICEOBJECTS, 0, 0);
  4798. BandSite_HandleDelayBootStuff(_ptbs);
  4799. //check to see if there are any files or folders that could interfere
  4800. //with the fact that Program Files has a space in it. An example would
  4801. //be a folder called "C:\Program" or a file called "C:\Program.exe"
  4802. _CheckForRogueProgramFile();
  4803. // Create a named event and fire it so that the services can
  4804. // go to work, reducing contention during boot.
  4805. _hShellReadyEvent = CreateEvent(0, TRUE, TRUE, TEXT("ShellReadyEvent"));
  4806. if (_hShellReadyEvent)
  4807. {
  4808. // Set the event in case it was already created and our "create
  4809. // signaled" parameter to CreateEvent got ignored.
  4810. SetEvent(_hShellReadyEvent);
  4811. }
  4812. // Check whether we should launch Desktop Cleanup Wizard
  4813. _CheckDesktopCleanup();
  4814. TBOOL(WinStationRegisterConsoleNotification(SERVERNAME_CURRENT, _hwnd, NOTIFY_FOR_THIS_SESSION));
  4815. if (g_dwStopWatchMode)
  4816. {
  4817. StopWatch_StopTimed(SWID_STARTUP, TEXT("_DelayedBootStuff"), SPMODE_SHELL | SPMODE_DEBUGOUT, GetPerfTime());
  4818. }
  4819. }
  4820. }
  4821. LRESULT CTray::_OnDeviceChange(HWND hwnd, WPARAM wParam, LPARAM lParam)
  4822. {
  4823. switch (wParam)
  4824. {
  4825. case DBT_CONFIGCHANGED:
  4826. // We got an update. Refresh.
  4827. _RefreshStartMenu();
  4828. break;
  4829. case DBT_QUERYCHANGECONFIG:
  4830. //
  4831. // change to registry settings
  4832. //
  4833. ChangeDisplaySettings(NULL, 0);
  4834. break;
  4835. case DBT_MONITORCHANGE:
  4836. //
  4837. // handle monitor change
  4838. //
  4839. HandleDisplayChange(LOWORD(lParam), HIWORD(lParam), TRUE);
  4840. break;
  4841. case DBT_CONFIGCHANGECANCELED:
  4842. //
  4843. // if the config change was canceled go back
  4844. //
  4845. HandleDisplayChange(0, 0, FALSE);
  4846. break;
  4847. }
  4848. Mixer_DeviceChange(wParam, lParam);
  4849. return 0;
  4850. }
  4851. //
  4852. // The "resizable" edge of the taskbar is the edge adjacent to
  4853. // the desktop, i.e. opposite the stuck place.
  4854. //
  4855. // returns HTXXX if on a resizable edge, else HTBORDER
  4856. //
  4857. DWORD CTray::_PtOnResizableEdge(POINT pt, LPRECT prcClient)
  4858. {
  4859. RECT rc;
  4860. GetWindowRect(_hwnd, &rc);
  4861. DWORD dwHit = HTBORDER;
  4862. switch (_uStuckPlace)
  4863. {
  4864. case STICK_LEFT: rc.left = prcClient->right; dwHit = HTRIGHT; break;
  4865. case STICK_TOP: rc.top = prcClient->bottom; dwHit = HTBOTTOM; break;
  4866. case STICK_RIGHT: rc.right = prcClient->left; dwHit = HTLEFT; break;
  4867. case STICK_BOTTOM: rc.bottom = prcClient->top; dwHit = HTTOP; break;
  4868. }
  4869. return PtInRect(&rc, pt) ? dwHit : HTBORDER;
  4870. }
  4871. //
  4872. // _OnFactoryMessage
  4873. //
  4874. // The OPK "factory.exe" tool sends us this message to tell us that
  4875. // it has dorked some setting or other and we should refresh so the
  4876. // OEM can see the effect immediately and feel confident that it
  4877. // actually worked. This is not technically necessary but it cuts
  4878. // down on OEM support calls when they ask us why their setting didn't
  4879. // work. (It did work, they just have to log off and back on to see
  4880. // it.)
  4881. //
  4882. int CTray::_OnFactoryMessage(WPARAM wParam, LPARAM lParam)
  4883. {
  4884. switch (wParam)
  4885. {
  4886. case 0: // FACTORY_OEMLINK: factory.exe has dorked the OEM link
  4887. ClosePopupMenus();
  4888. _BuildStartMenu(); // Force a rebuild
  4889. return 1;
  4890. case 1: // FACTORY_MFU: factory.exe has written a new MFU
  4891. HandleFirstTime(); // Rebuild the default MFU
  4892. ClosePopupMenus();
  4893. _BuildStartMenu(); // Force a rebuild
  4894. return 1;
  4895. }
  4896. return 0;
  4897. }
  4898. #define CX_OFFSET g_cxEdge
  4899. #define CY_OFFSET g_cyEdge
  4900. //
  4901. // _MapNCToClient
  4902. //
  4903. // see comments in _TryForwardNCToClient
  4904. //
  4905. BOOL CTray::_MapNCToClient(LPARAM* plParam)
  4906. {
  4907. POINT pt = { GET_X_LPARAM(*plParam), GET_Y_LPARAM(*plParam) };
  4908. RECT rcClient;
  4909. GetClientRect(_hwnd, &rcClient);
  4910. MapWindowPoints(_hwnd, NULL, (LPPOINT)&rcClient, 2);
  4911. //
  4912. // point must be outside the client area and not on the
  4913. // resizable edge of the taskbar
  4914. //
  4915. if (!PtInRect(&rcClient, pt) && _PtOnResizableEdge(pt, &rcClient) == HTBORDER)
  4916. {
  4917. //
  4918. // fudge it over onto the client edge and return TRUE
  4919. //
  4920. if (pt.x < rcClient.left)
  4921. pt.x = rcClient.left + CX_OFFSET;
  4922. else if (pt.x > rcClient.right)
  4923. pt.x = rcClient.right - CX_OFFSET;
  4924. if (pt.y < rcClient.top)
  4925. pt.y = rcClient.top + CY_OFFSET;
  4926. else if (pt.y > rcClient.bottom)
  4927. pt.y = rcClient.bottom - CY_OFFSET;
  4928. *plParam = MAKELONG(pt.x, pt.y);
  4929. return TRUE;
  4930. }
  4931. //
  4932. // didn't pass the test. leave the point alone and return FALSE.
  4933. //
  4934. return FALSE;
  4935. }
  4936. HWND _TopChildWindowFromPoint(HWND hwnd, POINT pt)
  4937. {
  4938. HWND hwndLast = NULL;
  4939. hwnd = ChildWindowFromPoint(hwnd, pt);
  4940. while (hwnd && hwnd != hwndLast)
  4941. {
  4942. hwndLast = hwnd;
  4943. hwnd = ChildWindowFromPoint(hwnd, pt);
  4944. }
  4945. return hwndLast;
  4946. }
  4947. //
  4948. // _TryForwardNCToClient
  4949. //
  4950. // Hack! This exists to solve a usability problem. When you slam your
  4951. // mouse into the bottom corner of the screen and click, we want that to
  4952. // activate the start button. Similarly, when you slam your mouse below
  4953. // a Quick Launch button or task button and click, we want that to
  4954. // activate the button.
  4955. //
  4956. // We hack this by remapping the coordinate of NC mouse messages and
  4957. // manually forwarding to the appropriate window. We only do this for
  4958. // clicks on the edges non-resizable edge of the taskbar.
  4959. //
  4960. // We also warp the mouse cursor over to the new position. This is needed
  4961. // because e.g. if toolbar is the client window we're forwarding
  4962. // to, it will set capture and receive subsequent mouse messages. (And
  4963. // once it gets a mouse message outside the window, it will deselect the
  4964. // button and so the button won't get activated.)
  4965. //
  4966. // _MapNCToClient has the rules for figuring out if the click is on
  4967. // one of the edges we want and for remapping the coordinate into the
  4968. // client area.
  4969. //
  4970. BOOL CTray::_TryForwardNCToClient(UINT uMsg, LPARAM lParam)
  4971. {
  4972. if (_MapNCToClient(&lParam))
  4973. {
  4974. // see if this is over one of our windows
  4975. POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
  4976. MapWindowPoints(NULL, _hwnd, &pt, 1);
  4977. HWND hwnd = _TopChildWindowFromPoint(_hwnd, pt);
  4978. if (hwnd)
  4979. {
  4980. // warp the mouse cursor to this screen coord
  4981. SetCursorPos(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
  4982. // map to window coords
  4983. MapWindowPoints(_hwnd, hwnd, &pt, 1);
  4984. // set lparam to window coords
  4985. lParam = MAKELONG(pt.x, pt.y);
  4986. // map to client message
  4987. ASSERT(InRange(uMsg, WM_NCMOUSEFIRST, WM_NCMOUSELAST));
  4988. uMsg += (WM_LBUTTONDOWN - WM_NCLBUTTONDOWN);
  4989. // forward it
  4990. SendMessage(hwnd, uMsg, 0, lParam);
  4991. return TRUE;
  4992. }
  4993. }
  4994. return FALSE;
  4995. }
  4996. // --------------------------------------------------------------------------
  4997. // CTray::CountOfRunningPrograms
  4998. //
  4999. // Arguments: <none>
  5000. //
  5001. // Returns: DWORD
  5002. //
  5003. // Purpose: Iterates the window list. Looks for windows that are visible
  5004. // with a non-zero length window title. Gets that window process
  5005. // ID and keeps the IDs in a list. For each window iterated it
  5006. // checks against the list to see if the process is already
  5007. // tagged and if so doesn't add it again. Finally it returns the
  5008. // count of the unique processes handling open visible windows
  5009. // in the user's desktop.
  5010. //
  5011. // The list is fixed at 1000 processes (using stack space).
  5012. //
  5013. // History: 2000-06-29 vtan created
  5014. // --------------------------------------------------------------------------
  5015. static const int MAXIMUM_PROCESS_COUNT = 1000;
  5016. typedef struct
  5017. {
  5018. DWORD dwCount;
  5019. DWORD dwProcessIDs[MAXIMUM_PROCESS_COUNT];
  5020. } tProcessIDList;
  5021. bool FoundProcessID (tProcessIDList *pProcessIDList, DWORD dwProcessID)
  5022. {
  5023. bool fFound;
  5024. DWORD dwIndex;
  5025. for (fFound = false, dwIndex = 0; !fFound && (dwIndex < pProcessIDList->dwCount); ++dwIndex)
  5026. {
  5027. fFound = (pProcessIDList->dwProcessIDs[dwIndex] == dwProcessID);
  5028. }
  5029. return(fFound);
  5030. }
  5031. void AddProcessID (tProcessIDList *pProcessIDList, DWORD dwProcessID)
  5032. {
  5033. if (pProcessIDList->dwCount < MAXIMUM_PROCESS_COUNT)
  5034. {
  5035. pProcessIDList->dwProcessIDs[pProcessIDList->dwCount++] = dwProcessID;
  5036. }
  5037. }
  5038. BOOL CALLBACK CountOfRunningProgramsEnumWindowsProc (HWND hwnd, LPARAM lParam)
  5039. {
  5040. if ((GetShellWindow() != hwnd) && IsWindowVisible(hwnd))
  5041. {
  5042. DWORD dwThreadID, dwProcessID;
  5043. TCHAR szWindowTitle[256];
  5044. dwThreadID = GetWindowThreadProcessId(hwnd, &dwProcessID);
  5045. if ((InternalGetWindowText(hwnd, szWindowTitle, ARRAYSIZE(szWindowTitle)) > 0) &&
  5046. (szWindowTitle[0] != TEXT('\0')))
  5047. {
  5048. if (!FoundProcessID(reinterpret_cast<tProcessIDList*>(lParam), dwProcessID))
  5049. {
  5050. AddProcessID(reinterpret_cast<tProcessIDList*>(lParam), dwProcessID);
  5051. }
  5052. }
  5053. }
  5054. return(TRUE);
  5055. }
  5056. DWORD CTray::CountOfRunningPrograms()
  5057. {
  5058. tProcessIDList processIDList = {0};
  5059. TBOOL(EnumWindows(CountOfRunningProgramsEnumWindowsProc, reinterpret_cast<LPARAM>(&processIDList)));
  5060. return processIDList.dwCount;
  5061. }
  5062. // --------------------------------------------------------------------------
  5063. // CTray::_OnSessionChange
  5064. //
  5065. // Arguments: wParam = WTS_xxx notification.
  5066. // lParam = WTS_SESSION_NOTIFICATION struct pointer.
  5067. //
  5068. // Returns: LRESULT
  5069. //
  5070. // Purpose: Handles console/remote dis/reconnects.
  5071. //
  5072. // History: 2000-07-12 vtan created
  5073. // --------------------------------------------------------------------------
  5074. LRESULT CTray::_OnSessionChange(WPARAM wParam, LPARAM lParam)
  5075. {
  5076. ASSERTMSG(DWORD(lParam) == NtCurrentPeb()->SessionId, "Session ID mismatch in CTray::_OnSessionChange");
  5077. if ((WTS_CONSOLE_CONNECT == wParam) || (WTS_REMOTE_CONNECT == wParam) || (WTS_SESSION_UNLOCK == wParam))
  5078. {
  5079. _fIsDesktopConnected = TRUE;
  5080. }
  5081. else if ((WTS_CONSOLE_DISCONNECT == wParam) || (WTS_REMOTE_DISCONNECT == wParam) || (WTS_SESSION_LOCK == wParam))
  5082. {
  5083. _fIsDesktopConnected = FALSE;
  5084. }
  5085. if ((WTS_CONSOLE_CONNECT == wParam) || (WTS_REMOTE_CONNECT == wParam))
  5086. {
  5087. _RefreshStartMenu();
  5088. SHUpdateRecycleBinIcon();
  5089. }
  5090. else if ((WTS_SESSION_LOCK == wParam) || (WTS_SESSION_UNLOCK == wParam))
  5091. {
  5092. if (IsOS(OS_FASTUSERSWITCHING))
  5093. {
  5094. if (wParam == WTS_SESSION_LOCK)
  5095. {
  5096. ExplorerPlaySound(TEXT("WindowsLogoff"));
  5097. }
  5098. else if (wParam == WTS_SESSION_UNLOCK)
  5099. {
  5100. ExplorerPlaySound(TEXT("WindowsLogon"));
  5101. }
  5102. }
  5103. PostMessage(_hwnd, TM_WORKSTATIONLOCKED, (WTS_SESSION_LOCK == wParam), 0);
  5104. }
  5105. return 1;
  5106. }
  5107. LRESULT CTray::_NCPaint(HRGN hrgn)
  5108. {
  5109. ASSERT(_hTheme);
  5110. if (_fCanSizeMove || _fShowSizingBarAlways)
  5111. {
  5112. if ((INT_PTR)hrgn == 1)
  5113. hrgn = NULL;
  5114. HDC hdc = GetDCEx( _hwnd, hrgn, DCX_USESTYLE|DCX_WINDOW|DCX_LOCKWINDOWUPDATE|
  5115. ((hrgn != NULL) ? DCX_INTERSECTRGN|DCX_NODELETERGN : 0));
  5116. if (hdc)
  5117. {
  5118. RECT rc;
  5119. GetWindowRect(_hwnd, &rc);
  5120. OffsetRect(&rc, -rc.left, -rc.top);
  5121. _AdjustRectForSizingBar(_uStuckPlace, &rc, 0);
  5122. DrawThemeBackground(_hTheme, hdc, _GetPart(TRUE, _uStuckPlace), 0, &rc, 0);
  5123. ReleaseDC(_hwnd, hdc);
  5124. }
  5125. }
  5126. return 0;
  5127. }
  5128. LRESULT CTray::v_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  5129. {
  5130. static UINT uDDEExec = 0;
  5131. LRESULT lres = 0;
  5132. MSG msg;
  5133. msg.hwnd = hwnd;
  5134. msg.message = uMsg;
  5135. msg.wParam = wParam;
  5136. msg.lParam = lParam;
  5137. if (_pmbStartMenu &&
  5138. _pmbStartMenu->TranslateMenuMessage(&msg, &lres) == S_OK)
  5139. return lres;
  5140. if (_pmbStartPane &&
  5141. _pmbStartPane->TranslateMenuMessage(&msg, &lres) == S_OK)
  5142. return lres;
  5143. if (_pmbTasks &&
  5144. _pmbTasks->TranslateMenuMessage(&msg, &lres) == S_OK)
  5145. return lres;
  5146. wParam = msg.wParam;
  5147. lParam = msg.lParam;
  5148. INSTRUMENT_WNDPROC(SHCNFI_TRAY_WNDPROC, hwnd, uMsg, wParam, lParam);
  5149. switch (uMsg)
  5150. {
  5151. case WMTRAY_REGISTERHOTKEY:
  5152. return _RegisterHotkey(hwnd, (int)wParam);
  5153. case WMTRAY_UNREGISTERHOTKEY:
  5154. return _UnregisterHotkey(hwnd, (int)wParam);
  5155. case WMTRAY_SCREGISTERHOTKEY:
  5156. return _ShortcutRegisterHotkey(hwnd, (WORD)wParam, (ATOM)lParam);
  5157. case WMTRAY_SCUNREGISTERHOTKEY:
  5158. return _ShortcutUnregisterHotkey(hwnd, (WORD)wParam);
  5159. case WMTRAY_SETHOTKEYENABLE:
  5160. return _SetHotkeyEnable(hwnd, (BOOL)wParam);
  5161. case WMTRAY_QUERY_MENU:
  5162. return (LRESULT)_hmenuStart;
  5163. case WMTRAY_QUERY_VIEW:
  5164. return (LRESULT)_hwndTasks;
  5165. case WMTRAY_TOGGLEQL:
  5166. return _ToggleQL((int)lParam);
  5167. case WM_COPYDATA:
  5168. // Check for NULL it can happen if user runs out of selectors or memory...
  5169. if (lParam)
  5170. {
  5171. switch (((PCOPYDATASTRUCT)lParam)->dwData) {
  5172. case TCDM_NOTIFY:
  5173. {
  5174. BOOL bRefresh = FALSE;
  5175. lres = _trayNotify.TrayNotify(_hwndNotify, (HWND)wParam, (PCOPYDATASTRUCT)lParam, &bRefresh);
  5176. if (bRefresh)
  5177. {
  5178. SizeWindows();
  5179. }
  5180. return(lres);
  5181. }
  5182. case TCDM_APPBAR:
  5183. return _OnAppBarMessage((PCOPYDATASTRUCT)lParam);
  5184. case TCDM_LOADINPROC:
  5185. return (UINT)_LoadInProc((PCOPYDATASTRUCT)lParam);
  5186. }
  5187. }
  5188. return FALSE;
  5189. case WM_NCCALCSIZE:
  5190. if (_hTheme)
  5191. {
  5192. if ((_fCanSizeMove || _fShowSizingBarAlways) && lParam)
  5193. {
  5194. _AdjustRectForSizingBar(_uStuckPlace, (LPRECT)lParam, -1);
  5195. }
  5196. return 0;
  5197. }
  5198. else
  5199. {
  5200. goto L_default;
  5201. }
  5202. break;
  5203. case WM_NCLBUTTONDBLCLK:
  5204. if (!_TryForwardNCToClient(uMsg, lParam))
  5205. {
  5206. if (IsPosInHwnd(lParam, _hwndNotify))
  5207. {
  5208. _Command(IDM_SETTIME);
  5209. // Hack! If you click on the tray clock, this tells the tooltip
  5210. // "Hey, I'm using this thing; stop putting up a tip for me."
  5211. // You can get the tooltip to lose track of when it needs to
  5212. // reset the "stop it!" flag and you get stuck in "stop it!" mode.
  5213. // It's particularly easy to make happen on Terminal Server.
  5214. //
  5215. // So let's assume that the only reason people click on the
  5216. // tray clock is to change the time. when they change the time,
  5217. // kick the tooltip in the head to reset the "stop it!" flag.
  5218. SendMessage(_hwndTrayTips, TTM_POP, 0, 0);
  5219. }
  5220. }
  5221. break;
  5222. case WM_NCLBUTTONDOWN:
  5223. case WM_NCLBUTTONUP:
  5224. if (!_TryForwardNCToClient(uMsg, lParam))
  5225. {
  5226. goto L_WM_NCMOUSEMOVE;
  5227. }
  5228. break;
  5229. case WM_NCMOUSEMOVE:
  5230. L_WM_NCMOUSEMOVE:
  5231. if (IsPosInHwnd(lParam, _hwndNotify))
  5232. {
  5233. MSG msgInner;
  5234. msgInner.lParam = lParam;
  5235. msgInner.wParam = wParam;
  5236. msgInner.message = uMsg;
  5237. msgInner.hwnd = hwnd;
  5238. SendMessage(_hwndTrayTips, TTM_RELAYEVENT, 0, (LPARAM)(LPMSG)&msgInner);
  5239. if (uMsg == WM_NCLBUTTONDOWN)
  5240. _SetFocus(_hwndNotify);
  5241. }
  5242. goto DoDefault;
  5243. case WM_CREATE:
  5244. return _OnCreate(hwnd);
  5245. case WM_DESTROY:
  5246. return _HandleDestroy();
  5247. #ifdef DEBUG
  5248. case WM_QUERYENDSESSION:
  5249. TraceMsg(DM_SHUTDOWN, "Tray.wp WM_QUERYENDSESSION");
  5250. goto DoDefault;
  5251. #endif
  5252. case WM_ENDSESSION:
  5253. // save our settings if we are shutting down
  5254. if (wParam)
  5255. {
  5256. if (lParam | ENDSESSION_LOGOFF)
  5257. {
  5258. _fIsLogoff = TRUE;
  5259. _RecomputeAllWorkareas();
  5260. }
  5261. _SaveTrayAndDesktop();
  5262. ShowWindow(_hwnd, SW_HIDE);
  5263. ShowWindow(v_hwndDesktop, SW_HIDE);
  5264. DestroyWindow(_hwnd);
  5265. }
  5266. break;
  5267. case WM_PRINTCLIENT:
  5268. case WM_PAINT:
  5269. {
  5270. RECT rc;
  5271. PAINTSTRUCT ps;
  5272. HDC hdc = (HDC)wParam;
  5273. if (hdc == 0)
  5274. hdc = BeginPaint(hwnd, &ps);
  5275. GetClientRect(hwnd, &rc);
  5276. if (_hTheme)
  5277. {
  5278. RECT rcClip;
  5279. if (GetClipBox(hdc, &rcClip) == NULLREGION)
  5280. rcClip = rc;
  5281. DrawThemeBackground(_hTheme, hdc, _GetPart(FALSE, _uStuckPlace), 0, &rc, &rcClip);
  5282. }
  5283. else
  5284. {
  5285. FillRect(hdc, &rc, (HBRUSH)(COLOR_3DFACE + 1));
  5286. // draw etched line around on either side of the bandsite
  5287. MapWindowPoints(HWND_DESKTOP, hwnd, (LPPOINT)&rc, 2);
  5288. InflateRect(&rc, g_cxEdge, g_cyEdge);
  5289. DrawEdge(hdc, &rc, EDGE_ETCHED, BF_TOPLEFT);
  5290. }
  5291. if (wParam == 0)
  5292. EndPaint(hwnd, &ps);
  5293. }
  5294. break;
  5295. case WM_ERASEBKGND:
  5296. if (_hTheme)
  5297. {
  5298. if (!_fSkipErase)
  5299. {
  5300. RECT rc;
  5301. GetClientRect(hwnd, &rc);
  5302. DrawThemeBackground(_hTheme, (HDC)wParam, _GetPart(FALSE, _uStuckPlace), 0, &rc, NULL);
  5303. // Only draw the first time to prevent piece-mail taskbar painting
  5304. _fSkipErase = TRUE;
  5305. }
  5306. return 1;
  5307. }
  5308. else
  5309. {
  5310. goto DoDefault;
  5311. }
  5312. break;
  5313. case WM_NCPAINT:
  5314. if (_hTheme)
  5315. {
  5316. return _NCPaint((HRGN)wParam);
  5317. }
  5318. else
  5319. {
  5320. goto DoDefault;
  5321. }
  5322. break;
  5323. case WM_POWER:
  5324. case WM_POWERBROADCAST:
  5325. _PropagateMessage(hwnd, uMsg, wParam, lParam);
  5326. _HandlePowerStatus(uMsg, wParam, lParam);
  5327. goto DoDefault;
  5328. case WM_DEVICECHANGE:
  5329. lres = _OnDeviceChange(hwnd, wParam, lParam);
  5330. if (lres == 0)
  5331. {
  5332. goto DoDefault;
  5333. }
  5334. break;
  5335. case WM_NOTIFY:
  5336. {
  5337. NMHDR *pnm = (NMHDR*)lParam;
  5338. if (!BandSite_HandleMessage(_ptbs, hwnd, uMsg, wParam, lParam, &lres)) {
  5339. switch (pnm->code)
  5340. {
  5341. case SEN_DDEEXECUTE:
  5342. if (((LPNMHDR)lParam)->idFrom == 0)
  5343. {
  5344. LPNMVIEWFOLDER pnmPost = DDECreatePostNotify((LPNMVIEWFOLDER)pnm);
  5345. if (pnmPost)
  5346. {
  5347. PostMessage(hwnd, GetDDEExecMsg(), 0, (LPARAM)pnmPost);
  5348. return TRUE;
  5349. }
  5350. }
  5351. break;
  5352. case NM_STARTWAIT:
  5353. case NM_ENDWAIT:
  5354. _OnWaitCursorNotify((NMHDR *)lParam);
  5355. PostMessage(v_hwndDesktop, ((NMHDR*)lParam)->code == NM_STARTWAIT ? DTM_STARTWAIT : DTM_ENDWAIT,
  5356. 0, 0); // forward it along
  5357. break;
  5358. case NM_THEMECHANGED:
  5359. // Force the start button to recalc its size
  5360. _sizeStart.cx = 0;
  5361. SizeWindows();
  5362. break;
  5363. case TTN_NEEDTEXT:
  5364. //
  5365. // Make the clock manage its own tooltip.
  5366. //
  5367. return SendMessage(_GetClockWindow(), WM_NOTIFY, wParam, lParam);
  5368. case TTN_SHOW:
  5369. SetWindowZorder(_hwndTrayTips, HWND_TOP);
  5370. break;
  5371. }
  5372. }
  5373. break;
  5374. }
  5375. case WM_CLOSE:
  5376. _DoExitWindows(v_hwndDesktop);
  5377. break;
  5378. case WM_NCHITTEST:
  5379. {
  5380. RECT r1;
  5381. POINT pt;
  5382. GetClientRect(hwnd, &r1);
  5383. MapWindowPoints(hwnd, NULL, (LPPOINT)&r1, 2);
  5384. pt.x = GET_X_LPARAM(lParam);
  5385. pt.y = GET_Y_LPARAM(lParam);
  5386. _SetUnhideTimer(pt.x, pt.y);
  5387. // If the user can't size or move the taskbar, then just say
  5388. // they hit something useless
  5389. if (!_fCanSizeMove)
  5390. {
  5391. return HTBORDER;
  5392. }
  5393. else if (PtInRect(&r1, pt))
  5394. {
  5395. // allow dragging if mouse is in client area of _hwnd
  5396. return HTCAPTION;
  5397. }
  5398. else
  5399. {
  5400. return _PtOnResizableEdge(pt, &r1);
  5401. }
  5402. }
  5403. break;
  5404. case WM_WINDOWPOSCHANGING:
  5405. _HandleWindowPosChanging((LPWINDOWPOS)lParam);
  5406. break;
  5407. case WM_ENTERSIZEMOVE:
  5408. DebugMsg(DM_TRAYDOCK, TEXT("Tray -- WM_ENTERSIZEMOVE"));
  5409. g_fInSizeMove = TRUE;
  5410. GetCursorPos((LPPOINT)&_rcSizeMoveIgnore);
  5411. _rcSizeMoveIgnore.right = _rcSizeMoveIgnore.left;
  5412. _rcSizeMoveIgnore.bottom = _rcSizeMoveIgnore.top;
  5413. InflateRect(&_rcSizeMoveIgnore, GetSystemMetrics(SM_CXICON),
  5414. GetSystemMetrics(SM_CYICON));
  5415. //
  5416. // unclip the tray from the current monitor.
  5417. // keeping the tray properly clipped in the MoveSize loop is extremely
  5418. // hairy and provides almost no benefit. we'll re-clip when it lands.
  5419. //
  5420. _ClipWindow(FALSE);
  5421. // Remember the old monitor we were on
  5422. _hmonOld = _hmonStuck;
  5423. // set up for WM_MOVING/WM_SIZING messages
  5424. _uMoveStuckPlace = (UINT)-1;
  5425. _fSysSizing = TRUE;
  5426. if (!g_fDragFullWindows)
  5427. {
  5428. SendMessage(_hwndRebar, WM_SETREDRAW, FALSE, 0);
  5429. }
  5430. break;
  5431. case WM_EXITSIZEMOVE:
  5432. DebugMsg(DM_TRAYDOCK, TEXT("Tray -- WM_EXITSIZEMOVE"));
  5433. // done sizing
  5434. _fSysSizing = FALSE;
  5435. _fDeferedPosRectChange = FALSE;
  5436. if (!g_fDragFullWindows)
  5437. {
  5438. SendMessage(_hwndRebar, WM_SETREDRAW, TRUE, 0);
  5439. }
  5440. //
  5441. // kick the size code one last time after the loop is done.
  5442. // NOTE: we rely on the WM_SIZE code re-clipping the tray.
  5443. //
  5444. PostMessage(hwnd, WM_SIZE, 0, 0L);
  5445. g_fInSizeMove = FALSE;
  5446. break;
  5447. case WM_MOVING:
  5448. _HandleMoving(wParam, (LPRECT)lParam);
  5449. break;
  5450. case WM_ENTERMENULOOP:
  5451. // DebugMsg(DM_TRACE, "c.twp: Enter menu loop.");
  5452. _HandleEnterMenuLoop();
  5453. break;
  5454. case WM_EXITMENULOOP:
  5455. // DebugMsg(DM_TRACE, "c.twp: Exit menu loop.");
  5456. _HandleExitMenuLoop();
  5457. break;
  5458. case WM_TIMER:
  5459. if (IDT_SERVICE0 <= wParam && wParam <= IDT_SERVICELAST)
  5460. return _OnTimerService(uMsg, wParam, lParam);
  5461. _HandleTimer(wParam);
  5462. break;
  5463. case WM_SIZING:
  5464. _HandleSizing(wParam, (LPRECT)lParam, _uStuckPlace);
  5465. break;
  5466. case WM_SIZE:
  5467. _HandleSize();
  5468. break;
  5469. case WM_DISPLAYCHANGE:
  5470. // NOTE: we get WM_DISPLAYCHANGE in the below two situations
  5471. // 1. a display size changes (HMON will not change in USER)
  5472. // 2. a display goes away or gets added (HMON will change even if
  5473. // the monitor that went away has nothing to do with our hmonStuck)
  5474. // In the above two situations we actually need to do different things
  5475. // because in 1, we do not want to update our hmonStuck because we might
  5476. // end up on another monitor, but in 2 we do want to update hmonStuck because
  5477. // our hmon is invalid
  5478. // The way we handle this is to call GetMonitorInfo on our old HMONITOR
  5479. // and see if it's still valid, if not, we update it by calling _SetStuckMonitor
  5480. // all these code is in _ScreenSizeChange;
  5481. _ScreenSizeChange(hwnd);
  5482. // Force the Start Pane to rebuild because a change in color depth
  5483. // causes themes to run around destroying fonts (ruining the OOBE
  5484. // text) and we need to reload our bitmaps for the new color depth
  5485. // anyway.
  5486. ::PostMessage(_hwnd, SBM_REBUILDMENU, 0, 0);
  5487. break;
  5488. // Don't go to default wnd proc for this one...
  5489. case WM_INPUTLANGCHANGEREQUEST:
  5490. return(LRESULT)0L;
  5491. case WM_GETMINMAXINFO:
  5492. ((MINMAXINFO *)lParam)->ptMinTrackSize.x = g_cxFrame;
  5493. ((MINMAXINFO *)lParam)->ptMinTrackSize.y = g_cyFrame;
  5494. break;
  5495. case WM_WININICHANGE:
  5496. if (lParam && (0 == lstrcmpi((LPCTSTR)lParam, TEXT("SaveTaskbar"))))
  5497. {
  5498. _SaveTrayAndDesktop();
  5499. }
  5500. else
  5501. {
  5502. BandSite_HandleMessage(_ptbs, hwnd, uMsg, wParam, lParam, NULL);
  5503. _PropagateMessage(hwnd, uMsg, wParam, lParam);
  5504. _OnWinIniChange(hwnd, wParam, lParam);
  5505. }
  5506. if (lParam)
  5507. TraceMsg(TF_TRAY, "Tray Got: lParam=%s", (LPCSTR)lParam);
  5508. break;
  5509. case WM_TIMECHANGE:
  5510. _PropagateMessage(hwnd, uMsg, wParam, lParam);
  5511. break;
  5512. case WM_SYSCOLORCHANGE:
  5513. _OnNewSystemSizes();
  5514. BandSite_HandleMessage(_ptbs, hwnd, uMsg, wParam, lParam, NULL);
  5515. _PropagateMessage(hwnd, uMsg, wParam, lParam);
  5516. break;
  5517. case WM_SETCURSOR:
  5518. if (_iWaitCount) {
  5519. SetCursor(LoadCursor(NULL, IDC_APPSTARTING));
  5520. return TRUE;
  5521. } else
  5522. goto DoDefault;
  5523. case WM_SETFOCUS:
  5524. IUnknown_UIActivateIO(_ptbs, TRUE, NULL);
  5525. break;
  5526. case WM_SYSCHAR:
  5527. if (wParam == TEXT(' ')) {
  5528. HMENU hmenu;
  5529. int idCmd;
  5530. SHSetWindowBits(hwnd, GWL_STYLE, WS_SYSMENU, WS_SYSMENU);
  5531. hmenu = GetSystemMenu(hwnd, FALSE);
  5532. if (hmenu) {
  5533. EnableMenuItem(hmenu, SC_RESTORE, MFS_GRAYED | MF_BYCOMMAND);
  5534. EnableMenuItem(hmenu, SC_MAXIMIZE, MFS_GRAYED | MF_BYCOMMAND);
  5535. EnableMenuItem(hmenu, SC_MINIMIZE, MFS_GRAYED | MF_BYCOMMAND);
  5536. EnableMenuItem(hmenu, SC_MOVE, (_fCanSizeMove ? MFS_ENABLED : MFS_GRAYED) | MF_BYCOMMAND);
  5537. EnableMenuItem(hmenu, SC_SIZE, (_fCanSizeMove ? MFS_ENABLED : MFS_GRAYED) | MF_BYCOMMAND);
  5538. idCmd = _TrackMenu(hmenu);
  5539. if (idCmd)
  5540. SendMessage(_hwnd, WM_SYSCOMMAND, idCmd, 0L);
  5541. }
  5542. SHSetWindowBits(hwnd, GWL_STYLE, WS_SYSMENU, 0L);
  5543. }
  5544. break;
  5545. case WM_SYSCOMMAND:
  5546. // if we are sizing, make the full screen accessible
  5547. switch (wParam & 0xFFF0) {
  5548. case SC_CLOSE:
  5549. _DoExitWindows(v_hwndDesktop);
  5550. break;
  5551. default:
  5552. goto DoDefault;
  5553. }
  5554. break;
  5555. case TM_DESKTOPSTATE:
  5556. _OnDesktopState(lParam);
  5557. break;
  5558. case TM_RAISEDESKTOP:
  5559. _RaiseDesktop((BOOL)wParam, FALSE);
  5560. break;
  5561. #ifdef DEBUG
  5562. case TM_NEXTCTL:
  5563. #endif
  5564. case TM_UIACTIVATEIO:
  5565. case TM_ONFOCUSCHANGEIS:
  5566. _OnFocusMsg(uMsg, wParam, lParam);
  5567. break;
  5568. case TM_MARSHALBS: // wParam=IID lRes=pstm
  5569. return BandSite_OnMarshallBS(wParam, lParam);
  5570. case TM_SETTIMER:
  5571. case TM_KILLTIMER:
  5572. return _OnTimerService(uMsg, wParam, lParam);
  5573. break;
  5574. case TM_FACTORY:
  5575. return _OnFactoryMessage(wParam, lParam);
  5576. case TM_ACTASTASKSW:
  5577. _ActAsSwitcher();
  5578. break;
  5579. case TM_RELAYPOSCHANGED:
  5580. _AppBarNotifyAll((HMONITOR)lParam, ABN_POSCHANGED, (HWND)wParam, 0);
  5581. break;
  5582. case TM_BRINGTOTOP:
  5583. SetWindowZorder((HWND)wParam, HWND_TOP);
  5584. break;
  5585. case TM_WARNNOAUTOHIDE:
  5586. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.twp collision UI request"));
  5587. //
  5588. // this may look a little funny but what we do is post this message all
  5589. // over the place and ignore it when we think it is a bad time to put
  5590. // up a message (like the middle of a fulldrag...)
  5591. //
  5592. // wParam tells us if we need to try to clear the state
  5593. // the lowword of _SetAutoHideState's return tells if anything changed
  5594. //
  5595. if ((!_fSysSizing || !g_fDragFullWindows) &&
  5596. (!wParam || LOWORD(_SetAutoHideState(FALSE))))
  5597. {
  5598. ShellMessageBox(hinstCabinet, hwnd,
  5599. MAKEINTRESOURCE(IDS_ALREADYAUTOHIDEBAR),
  5600. MAKEINTRESOURCE(IDS_TASKBAR), MB_OK | MB_ICONINFORMATION);
  5601. }
  5602. else
  5603. {
  5604. DebugMsg(DM_TRAYDOCK, TEXT("TRAYDOCK.twp blowing off extraneous collision UI request"));
  5605. }
  5606. break;
  5607. case TM_PRIVATECOMMAND:
  5608. _HandlePrivateCommand(lParam);
  5609. break;
  5610. case TM_HANDLEDELAYBOOTSTUFF:
  5611. _HandleDelayBootStuff();
  5612. break;
  5613. case TM_SHELLSERVICEOBJECTS:
  5614. _ssomgr.LoadRegObjects();
  5615. break;
  5616. case TM_CHANGENOTIFY:
  5617. _HandleChangeNotify(wParam, lParam);
  5618. break;
  5619. case TM_GETHMONITOR:
  5620. *((HMONITOR *)lParam) = _hmonStuck;
  5621. break;
  5622. case TM_DOTRAYPROPERTIES:
  5623. DoProperties(TPF_TASKBARPAGE);
  5624. break;
  5625. case TM_STARTUPAPPSLAUNCHED:
  5626. PostMessage(_hwndNotify, TNM_STARTUPAPPSLAUNCHED, 0, 0);
  5627. break;
  5628. case TM_LANGUAGEBAND:
  5629. return _ToggleLanguageBand(lParam);
  5630. case WM_NCRBUTTONUP:
  5631. uMsg = WM_CONTEXTMENU;
  5632. wParam = (WPARAM)_hwndTasks;
  5633. goto L_WM_CONTEXTMENU;
  5634. case WM_CONTEXTMENU:
  5635. L_WM_CONTEXTMENU:
  5636. if (!SHRestricted(REST_NOTRAYCONTEXTMENU))
  5637. {
  5638. if (((HWND)wParam) == _hwndStart)
  5639. {
  5640. // Don't display of the Start Menu is up.
  5641. if (SendMessage(_hwndStart, BM_GETSTATE, 0, 0) & BST_PUSHED)
  5642. break;
  5643. _fFromStart = TRUE;
  5644. StartMenuContextMenu(_hwnd, (DWORD)lParam);
  5645. _fFromStart = FALSE;
  5646. }
  5647. else if (IsPosInHwnd(lParam, _hwndNotify) || SHIsChildOrSelf(_hwndNotify, GetFocus()) == S_OK)
  5648. {
  5649. // if click was inthe clock, include
  5650. // the time
  5651. _ContextMenu((DWORD)lParam, TRUE);
  5652. }
  5653. else
  5654. {
  5655. BandSite_HandleMessage(_ptbs, hwnd, uMsg, wParam, lParam, &lres);
  5656. }
  5657. }
  5658. break;
  5659. case WM_INITMENUPOPUP:
  5660. case WM_MEASUREITEM:
  5661. case WM_DRAWITEM:
  5662. case WM_MENUCHAR:
  5663. // Don't call bandsite message handler when code path started via the start button context menu
  5664. if (!_fFromStart)
  5665. {
  5666. BandSite_HandleMessage(_ptbs, hwnd, uMsg, wParam, lParam, &lres);
  5667. }
  5668. break;
  5669. case TM_DOEXITWINDOWS:
  5670. _DoExitWindows(v_hwndDesktop);
  5671. break;
  5672. case TM_HANDLESTARTUPFAILED:
  5673. _OnHandleStartupFailed();
  5674. break;
  5675. case WM_HOTKEY:
  5676. if (wParam < GHID_FIRST)
  5677. {
  5678. _HandleHotKey((WORD)wParam);
  5679. }
  5680. else
  5681. {
  5682. _HandleGlobalHotkey(wParam);
  5683. }
  5684. break;
  5685. case WM_COMMAND:
  5686. if (!BandSite_HandleMessage(_ptbs, hwnd, uMsg, wParam, lParam, &lres))
  5687. _Command(GET_WM_COMMAND_ID(wParam, lParam));
  5688. break;
  5689. case SBM_CANCELMENU:
  5690. ClosePopupMenus();
  5691. break;
  5692. case SBM_REBUILDMENU:
  5693. _BuildStartMenu();
  5694. break;
  5695. case WM_WINDOWPOSCHANGED:
  5696. _AppBarActivationChange2(hwnd, _uStuckPlace);
  5697. SendMessage(_hwndNotify, TNM_TRAYPOSCHANGED, 0, 0);
  5698. goto DoDefault;
  5699. case WM_LBUTTONDOWN:
  5700. case WM_RBUTTONDOWN:
  5701. case WM_MBUTTONDOWN:
  5702. if (_hwndStartBalloon)
  5703. {
  5704. RECT rc;
  5705. POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
  5706. GetWindowRect(_hwndStartBalloon, &rc);
  5707. MapWindowRect(HWND_DESKTOP, _hwnd, &rc);
  5708. if (PtInRect(&rc, pt))
  5709. {
  5710. ShowWindow(_hwndStartBalloon, SW_HIDE);
  5711. _DontShowTheStartButtonBalloonAnyMore();
  5712. _DestroyStartButtonBalloon();
  5713. }
  5714. }
  5715. break;
  5716. case TM_SETPUMPHOOK:
  5717. ATOMICRELEASE(_pmbTasks);
  5718. ATOMICRELEASE(_pmpTasks);
  5719. if (wParam && lParam)
  5720. {
  5721. _pmbTasks = (IMenuBand*)wParam;
  5722. _pmbTasks->AddRef();
  5723. _pmpTasks = (IMenuPopup*)lParam;
  5724. _pmpTasks->AddRef();
  5725. }
  5726. break;
  5727. case WM_ACTIVATE:
  5728. _AppBarActivationChange2(hwnd, _uStuckPlace);
  5729. if (wParam != WA_INACTIVE)
  5730. {
  5731. Unhide();
  5732. }
  5733. else
  5734. {
  5735. // When tray is deactivated, remove our keyboard cues:
  5736. //
  5737. SendMessage(hwnd, WM_CHANGEUISTATE,
  5738. MAKEWPARAM(UIS_SET, UISF_HIDEFOCUS | UISF_HIDEACCEL), 0);
  5739. IUnknown_UIActivateIO(_ptbs, FALSE, NULL);
  5740. }
  5741. //
  5742. // Tray activation is a good time to do a reality check
  5743. // (make sure "always-on-top" agrees with actual window
  5744. // position, make sure there are no ghost buttons, etc).
  5745. //
  5746. RealityCheck();
  5747. goto L_default;
  5748. case WM_WTSSESSION_CHANGE:
  5749. {
  5750. lres = _OnSessionChange(wParam, lParam);
  5751. break;
  5752. }
  5753. case WM_THEMECHANGED:
  5754. {
  5755. if (_hTheme)
  5756. {
  5757. CloseThemeData(_hTheme);
  5758. _hTheme = NULL;
  5759. }
  5760. if (wParam)
  5761. {
  5762. _hTheme = OpenThemeData(_hwnd, c_wzTaskbarTheme);
  5763. _fShowSizingBarAlways = (_uAutoHide & AH_ON) ? TRUE : FALSE;
  5764. if (_hTheme)
  5765. {
  5766. GetThemeBool(_hTheme, 0, 0, TMT_ALWAYSSHOWSIZINGBAR, &_fShowSizingBarAlways);
  5767. }
  5768. _UpdateVertical(_uStuckPlace, TRUE);
  5769. // Force Refresh of frame
  5770. SetWindowPos(_hwnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
  5771. }
  5772. // Force the start button to recalc its size
  5773. _sizeStart.cx = 0;
  5774. _StartButtonReset();
  5775. InvalidateRect(_hwnd, NULL, TRUE);
  5776. // Force the Start Pane to rebuild with new theme
  5777. ::PostMessage(_hwnd, SBM_REBUILDMENU, 0, 0);
  5778. SetWindowStyle(_hwnd, WS_BORDER | WS_THICKFRAME, !_hTheme);
  5779. }
  5780. break;
  5781. case TM_WORKSTATIONLOCKED:
  5782. {
  5783. // Desktop locked status changed...
  5784. BOOL fIsDesktopLocked = (BOOL) wParam;
  5785. if (_fIsDesktopLocked != fIsDesktopLocked)
  5786. {
  5787. _fIsDesktopLocked = fIsDesktopLocked;
  5788. _fIsLogoff = FALSE;
  5789. _RecomputeAllWorkareas();
  5790. PostMessage(_hwndNotify, TNM_WORKSTATIONLOCKED, wParam, 0);
  5791. }
  5792. }
  5793. break;
  5794. case TM_SHOWTRAYBALLOON:
  5795. PostMessage(_hwndNotify, TNM_SHOWTRAYBALLOON, wParam, 0);
  5796. break;
  5797. case TM_STARTMENUDISMISSED:
  5798. // 107561 - call CoFreeUnusedLibraries() peridically to free up dlls - ZekeL - 4-MAY-2001
  5799. // specifically to support MSONSEXT (webfolders) being used in RecentDocs
  5800. // after a file has been opened via webfolders. we get the icon via
  5801. // their namespace but then COM holds on to the DLL for a while (forever?)
  5802. // calling CoFreeUnusedLibraries() does the trick
  5803. SetTimer(_hwnd, IDT_COFREEUNUSED, 3 * 60 * 1000, NULL);
  5804. break;
  5805. case MM_MIXM_CONTROL_CHANGE:
  5806. Mixer_ControlChange(wParam, lParam);
  5807. break;
  5808. default:
  5809. L_default:
  5810. if (uMsg == GetDDEExecMsg())
  5811. {
  5812. ASSERT(lParam && 0 == ((LPNMHDR)lParam)->idFrom);
  5813. DDEHandleViewFolderNotify(NULL, _hwnd, (LPNMVIEWFOLDER)lParam);
  5814. LocalFree((LPNMVIEWFOLDER)lParam);
  5815. return TRUE;
  5816. }
  5817. else if (uMsg == _uStartButtonBalloonTip)
  5818. {
  5819. _ShowStartButtonToolTip();
  5820. }
  5821. else if (uMsg == _uLogoffUser)
  5822. {
  5823. // Log off the current user (message from U&P control panel)
  5824. ExitWindowsEx(EWX_LOGOFF, 0);
  5825. }
  5826. else if (uMsg == _uMsgEnableUserTrackedBalloonTips)
  5827. {
  5828. PostMessage(_hwndNotify, TNM_ENABLEUSERTRACKINGINFOTIPS, wParam, 0);
  5829. }
  5830. else if (uMsg == _uWinMM_DeviceChange)
  5831. {
  5832. Mixer_MMDeviceChange();
  5833. }
  5834. DoDefault:
  5835. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  5836. }
  5837. return lres;
  5838. }
  5839. void CTray::_DoExitWindows(HWND hwnd)
  5840. {
  5841. static BOOL s_fShellShutdown = FALSE;
  5842. if (!s_fShellShutdown)
  5843. {
  5844. if (_Restricted(hwnd, REST_NOCLOSE))
  5845. return;
  5846. {
  5847. UEMFireEvent(&UEMIID_SHELL, UEME_CTLSESSION, UEMF_XEVENT, FALSE, -1);
  5848. // really #ifdef DEBUG, but want for testing
  5849. // however can't do unconditionally due to perf
  5850. if (ERROR_SUCCESS == SHGetValue(HKEY_CURRENT_USER, REGSTR_EXPLORER_ADVANCED, TEXT("StartMenuForceRefresh"),
  5851. NULL, NULL, NULL) || GetAsyncKeyState(VK_SHIFT) < 0)
  5852. {
  5853. _RefreshStartMenu();
  5854. }
  5855. }
  5856. _SaveTrayAndDesktop();
  5857. _uModalMode = MM_SHUTDOWN;
  5858. ExitWindowsDialog(hwnd);
  5859. // NB User can have problems if the focus is forcebly changed to the desktop while
  5860. // shutting down since it tries to serialize the whole process by making windows sys-modal.
  5861. // If we hit this code at just the wrong moment (ie just after the sharing dialog appears)
  5862. // the desktop will become sys-modal so you can't switch back to the sharing dialog
  5863. // and you won't be able to shutdown.
  5864. // SetForegroundWindow(hwnd);
  5865. // SetFocus(hwnd);
  5866. _uModalMode = 0;
  5867. if ((GetKeyState(VK_SHIFT) < 0) && (GetKeyState(VK_CONTROL) < 0) && (GetKeyState(VK_MENU) < 0))
  5868. {
  5869. // User cancelled...
  5870. // The shift key means exit the tray...
  5871. // ??? - Used to destroy all cabinets...
  5872. // PostQuitMessage(0);
  5873. g_fFakeShutdown = TRUE; // Don't blow away session state; the session will survive
  5874. TraceMsg(TF_TRAY, "c.dew: Posting quit message for tid=%#08x hwndDesk=%x(IsWnd=%d) hwndTray=%x(IsWnd=%d)", GetCurrentThreadId(),
  5875. v_hwndDesktop,IsWindow(v_hwndDesktop), _hwnd,IsWindow(_hwnd));
  5876. // 1 means close all the shell windows too
  5877. PostMessage(v_hwndDesktop, WM_QUIT, 0, 1);
  5878. PostMessage(_hwnd, WM_QUIT, 0, 0);
  5879. s_fShellShutdown = TRUE;
  5880. }
  5881. }
  5882. }
  5883. void CTray::_SaveTray(void)
  5884. {
  5885. if (SHRestricted(REST_NOSAVESET))
  5886. return;
  5887. if (SHRestricted(REST_CLEARRECENTDOCSONEXIT))
  5888. ClearRecentDocumentsAndMRUStuff(FALSE);
  5889. //
  5890. // Don't persist tray stuff if in safe mode. We want this
  5891. // to be a temporary mode where the UI settings don't stick.
  5892. //
  5893. if (GetSystemMetrics(SM_CLEANBOOT) == 0)
  5894. {
  5895. _SaveTrayStuff();
  5896. }
  5897. }
  5898. DWORD WINAPI CTray::PropertiesThreadProc(void* pv)
  5899. {
  5900. return c_tray._PropertiesThreadProc(PtrToUlong(pv));
  5901. }
  5902. DWORD CTray::_PropertiesThreadProc(DWORD dwFlags)
  5903. {
  5904. HWND hwnd;
  5905. RECT rc;
  5906. DWORD dwExStyle = WS_EX_TOOLWINDOW;
  5907. GetWindowRect(_hwndStart, &rc);
  5908. dwExStyle |= IS_BIDI_LOCALIZED_SYSTEM() ? dwExStyleRTLMirrorWnd : 0L;
  5909. _hwndProp = hwnd = CreateWindowEx(dwExStyle, TEXT("static"), NULL, 0 ,
  5910. rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hinstCabinet, NULL);
  5911. #define IDI_STTASKBR 40 // stolen from shell32\ids.h
  5912. if (_hwndProp)
  5913. {
  5914. // Get the Alt+Tab icon right
  5915. HICON hicoStub = LoadIcon(GetModuleHandle(TEXT("SHELL32")), MAKEINTRESOURCE(IDI_STTASKBR));
  5916. SendMessage(_hwndProp, WM_SETICON, ICON_BIG, (LPARAM)hicoStub);
  5917. // SwitchToThisWindow(hwnd, TRUE);
  5918. // SetForegroundWindow(hwnd);
  5919. DoTaskBarProperties(hwnd, dwFlags);
  5920. _hwndProp = NULL;
  5921. DestroyWindow(hwnd);
  5922. if (hicoStub)
  5923. DestroyIcon(hicoStub);
  5924. }
  5925. return TRUE;
  5926. }
  5927. #define RUNWAITSECS 5
  5928. void CTray::DoProperties(DWORD dwFlags)
  5929. {
  5930. if (!_Restricted(_hwnd, REST_NOSETTASKBAR))
  5931. {
  5932. int i = RUNWAITSECS;
  5933. while (_hwndProp == ((HWND)-1) &&i--)
  5934. {
  5935. // we're in the process of coming up. wait
  5936. Sleep(1000);
  5937. }
  5938. // failed! blow it off.
  5939. if (_hwndProp == (HWND)-1)
  5940. {
  5941. _hwndProp = NULL;
  5942. }
  5943. if (_hwndProp)
  5944. {
  5945. // there's a window out there... activate it
  5946. SwitchToThisWindow(GetLastActivePopup(_hwndProp), TRUE);
  5947. }
  5948. else
  5949. {
  5950. _hwndProp = (HWND)-1;
  5951. if (!SHCreateThread(PropertiesThreadProc, IntToPtr(dwFlags), CTF_COINIT, NULL))
  5952. {
  5953. _hwndProp = NULL;
  5954. }
  5955. }
  5956. }
  5957. }
  5958. BOOL CTray::TileEnumProc(HWND hwnd, LPARAM lParam)
  5959. {
  5960. CTray* ptray = (CTray*)lParam;
  5961. if (IsWindowVisible(hwnd) && !IsIconic(hwnd) &&
  5962. ((GetWindowLong(hwnd, GWL_STYLE) & WS_CAPTION) == WS_CAPTION) &&
  5963. (hwnd != ptray->_hwnd) && hwnd != v_hwndDesktop)
  5964. {
  5965. return FALSE; // we *can* tile this guy
  5966. }
  5967. return TRUE; // we *cannot* tile this guy
  5968. }
  5969. HMENU CTray::BuildContextMenu(BOOL fIncludeTime)
  5970. {
  5971. HMENU hmContext = LoadMenuPopup(MAKEINTRESOURCE(MENU_TRAYCONTEXT));
  5972. if (!hmContext)
  5973. return NULL;
  5974. if (fIncludeTime)
  5975. {
  5976. if (_trayNotify.GetIsNoTrayItemsDisplayPolicyEnabled())
  5977. {
  5978. // We know the position of IDM_NOTIFYCUST from the menu resource...
  5979. DeleteMenu(hmContext, 1, MF_BYPOSITION);
  5980. }
  5981. else
  5982. {
  5983. UINT uEnable = MF_BYCOMMAND;
  5984. if (_trayNotify.GetIsNoAutoTrayPolicyEnabled() || !_trayNotify.GetIsAutoTrayEnabledByUser())
  5985. {
  5986. uEnable |= MFS_DISABLED;
  5987. }
  5988. else
  5989. {
  5990. uEnable |= MFS_ENABLED;
  5991. }
  5992. EnableMenuItem(hmContext, IDM_NOTIFYCUST, uEnable);
  5993. }
  5994. }
  5995. else
  5996. {
  5997. INSTRUMENT_STATECHANGE(SHCNFI_STATE_TRAY_CONTEXT);
  5998. for (int i = 2; i >= 0; i--) // separator, IDM_SETTIME, IDM_NOTIFYCUST,
  5999. {
  6000. DeleteMenu(hmContext, i, MF_BYPOSITION);
  6001. }
  6002. }
  6003. CheckMenuItem(hmContext, IDM_LOCKTASKBAR,
  6004. MF_BYCOMMAND | (_fCanSizeMove ? MF_UNCHECKED : MF_CHECKED));
  6005. // Don't let users accidentally check lock the taskbar when the taskbar is zero height
  6006. RECT rc;
  6007. GetClientRect(_hwnd, &rc);
  6008. EnableMenuItem(hmContext, IDM_LOCKTASKBAR,
  6009. MF_BYCOMMAND | ((_IsSizeMoveRestricted() || (RECTHEIGHT(rc) == 0)) ? MFS_DISABLED : MFS_ENABLED));
  6010. if (!_fUndoEnabled || !_pPositions)
  6011. {
  6012. DeleteMenu(hmContext, IDM_UNDO, MF_BYCOMMAND);
  6013. }
  6014. else
  6015. {
  6016. TCHAR szTemplate[30];
  6017. TCHAR szCommand[30];
  6018. TCHAR szMenu[64];
  6019. LoadString(hinstCabinet, IDS_UNDOTEMPLATE, szTemplate, ARRAYSIZE(szTemplate));
  6020. LoadString(hinstCabinet, _pPositions->idRes, szCommand, ARRAYSIZE(szCommand));
  6021. wsprintf(szMenu, szTemplate, szCommand);
  6022. ModifyMenu(hmContext, IDM_UNDO, MF_BYCOMMAND | MF_STRING, IDM_UNDO, szMenu);
  6023. }
  6024. if (g_fDesktopRaised)
  6025. {
  6026. TCHAR szHideDesktop[64];
  6027. LoadString(hinstCabinet, IDS_HIDEDESKTOP, szHideDesktop, ARRAYSIZE(szHideDesktop));
  6028. ModifyMenu(hmContext, IDM_TOGGLEDESKTOP, MF_BYCOMMAND | MF_STRING, IDM_TOGGLEDESKTOP, szHideDesktop);
  6029. }
  6030. if (!_CanTileAnyWindows())
  6031. {
  6032. EnableMenuItem(hmContext, IDM_CASCADE, MFS_GRAYED | MF_BYCOMMAND);
  6033. EnableMenuItem(hmContext, IDM_HORIZTILE, MFS_GRAYED | MF_BYCOMMAND);
  6034. EnableMenuItem(hmContext, IDM_VERTTILE, MFS_GRAYED | MF_BYCOMMAND);
  6035. }
  6036. HKEY hKeyPolicy;
  6037. if (RegOpenKeyEx(HKEY_CURRENT_USER,
  6038. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System"),
  6039. 0, KEY_READ, &hKeyPolicy) == ERROR_SUCCESS)
  6040. {
  6041. DWORD dwType, dwData = 0, dwSize = sizeof(dwData);
  6042. RegQueryValueEx(hKeyPolicy, TEXT("DisableTaskMgr"), NULL,
  6043. &dwType, (LPBYTE) &dwData, &dwSize);
  6044. RegCloseKey(hKeyPolicy);
  6045. if (dwData)
  6046. EnableMenuItem(hmContext, IDM_SHOWTASKMAN, MFS_GRAYED | MF_BYCOMMAND);
  6047. }
  6048. return hmContext;
  6049. }
  6050. void CTray::ContextMenuInvoke(int idCmd)
  6051. {
  6052. if (idCmd)
  6053. {
  6054. if (idCmd < IDM_TRAYCONTEXTFIRST)
  6055. {
  6056. BandSite_HandleMenuCommand(_ptbs, idCmd);
  6057. }
  6058. else
  6059. {
  6060. _Command(idCmd);
  6061. }
  6062. }
  6063. }
  6064. //
  6065. // CTray::AsyncSaveSettings
  6066. //
  6067. // We need to save our tray settings, but there may be a bunch
  6068. // of these calls coming, (at startup time or when dragging
  6069. // items in the task bar) so gather them up into one save that
  6070. // will happen in at least 2 seconds.
  6071. //
  6072. void CTray::AsyncSaveSettings()
  6073. {
  6074. if (!_fHandledDelayBootStuff) // no point in saving if we're not done booting
  6075. return;
  6076. KillTimer(_hwnd, IDT_SAVESETTINGS);
  6077. SetTimer(_hwnd, IDT_SAVESETTINGS, 2000, NULL);
  6078. }
  6079. void CTray::_ContextMenu(DWORD dwPos, BOOL fIncludeTime)
  6080. {
  6081. POINT pt = {LOWORD(dwPos), HIWORD(dwPos)};
  6082. SwitchToThisWindow(_hwnd, TRUE);
  6083. SetForegroundWindow(_hwnd);
  6084. SendMessage(_hwndTrayTips, TTM_ACTIVATE, FALSE, 0L);
  6085. if (dwPos != (DWORD)-1 &&
  6086. IsChildOrHWND(_hwndRebar, WindowFromPoint(pt)))
  6087. {
  6088. // if the context menu came from below us, reflect down
  6089. BandSite_HandleMessage(_ptbs, _hwnd, WM_CONTEXTMENU, 0, dwPos, NULL);
  6090. }
  6091. else
  6092. {
  6093. HMENU hmenu;
  6094. if (dwPos == (DWORD)-1)
  6095. {
  6096. HWND hwnd = GetFocus();
  6097. pt.x = pt.y = 0;
  6098. ClientToScreen(hwnd, &pt);
  6099. dwPos = MAKELONG(pt.x, pt.y);
  6100. }
  6101. hmenu = BuildContextMenu(fIncludeTime);
  6102. if (hmenu)
  6103. {
  6104. int idCmd;
  6105. BandSite_AddMenus(_ptbs, hmenu, 0, 0, IDM_TRAYCONTEXTFIRST);
  6106. idCmd = TrackPopupMenu(hmenu, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN,
  6107. GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos), 0, _hwnd, NULL);
  6108. DestroyMenu(hmenu);
  6109. ContextMenuInvoke(idCmd);
  6110. }
  6111. }
  6112. SendMessage(_hwndTrayTips, TTM_ACTIVATE, TRUE, 0L);
  6113. }
  6114. void _RunFileDlg(HWND hwnd, UINT idIcon, LPCITEMIDLIST pidlWorkingDir, UINT idTitle, UINT idPrompt, DWORD dwFlags)
  6115. {
  6116. HICON hIcon;
  6117. LPCTSTR lpszTitle;
  6118. LPCTSTR lpszPrompt;
  6119. TCHAR szTitle[256];
  6120. TCHAR szPrompt[256];
  6121. TCHAR szWorkingDir[MAX_PATH];
  6122. dwFlags |= RFD_USEFULLPATHDIR;
  6123. szWorkingDir[0] = 0;
  6124. hIcon = idIcon ? LoadIcon(hinstCabinet, MAKEINTRESOURCE(idIcon)) : NULL;
  6125. if (!pidlWorkingDir || !SHGetPathFromIDList(pidlWorkingDir, szWorkingDir))
  6126. {
  6127. // This is either the Tray, or some non-file system folder, so
  6128. // we will "suggest" the Desktop as a working dir, but if the
  6129. // user types a full path, we will use that instead. This is
  6130. // what WIN31 Progman did (except they started in the Windows
  6131. // dir instead of the Desktop).
  6132. goto UseDesktop;
  6133. }
  6134. // if it's a removable dir, make sure it's still there
  6135. if (szWorkingDir[0])
  6136. {
  6137. int idDrive = PathGetDriveNumber(szWorkingDir);
  6138. if ((idDrive != -1))
  6139. {
  6140. UINT dtype = DriveType(idDrive);
  6141. if (((dtype == DRIVE_REMOVABLE) || (dtype == DRIVE_CDROM))
  6142. && !PathFileExists(szWorkingDir))
  6143. {
  6144. goto UseDesktop;
  6145. }
  6146. }
  6147. }
  6148. //
  6149. // Check if this is a directory. Notice that it could be a in-place
  6150. // navigated document.
  6151. //
  6152. if (PathIsDirectory(szWorkingDir)) {
  6153. goto UseWorkingDir;
  6154. }
  6155. UseDesktop:
  6156. SHGetSpecialFolderPath(hwnd, szWorkingDir, CSIDL_DESKTOPDIRECTORY, FALSE);
  6157. UseWorkingDir:
  6158. if (idTitle)
  6159. {
  6160. LoadString(hinstCabinet, idTitle, szTitle, ARRAYSIZE(szTitle));
  6161. lpszTitle = szTitle;
  6162. }
  6163. else
  6164. lpszTitle = NULL;
  6165. if (idPrompt)
  6166. {
  6167. LoadString(hinstCabinet, idPrompt, szPrompt, ARRAYSIZE(szPrompt));
  6168. lpszPrompt = szPrompt;
  6169. }
  6170. else
  6171. lpszPrompt = NULL;
  6172. RunFileDlg(hwnd, hIcon, szWorkingDir, lpszTitle, lpszPrompt, dwFlags);
  6173. }
  6174. BOOL CTray::SavePosEnumProc(HWND hwnd, LPARAM lParam)
  6175. {
  6176. // dont need to entercritical here since we are only ever
  6177. // called from SaveWindowPositions, which as already entered the critical secion
  6178. // for _pPositions
  6179. ASSERTCRITICAL;
  6180. CTray* ptray = (CTray*)lParam;
  6181. ASSERT(ptray->_pPositions);
  6182. if (IsWindowVisible(hwnd) &&
  6183. (hwnd != ptray->_hwnd) &&
  6184. (hwnd != v_hwndDesktop))
  6185. {
  6186. HWNDANDPLACEMENT hap;
  6187. hap.wp.length = sizeof(WINDOWPLACEMENT);
  6188. GetWindowPlacement(hwnd, &hap.wp);
  6189. if (hap.wp.showCmd != SW_SHOWMINIMIZED)
  6190. {
  6191. hap.hwnd = hwnd;
  6192. hap.fRestore = TRUE;
  6193. DSA_AppendItem(ptray->_pPositions->hdsaWP, &hap);
  6194. }
  6195. }
  6196. return TRUE;
  6197. }
  6198. void CTray::SaveWindowPositions(UINT idRes)
  6199. {
  6200. ENTERCRITICAL;
  6201. if (_pPositions)
  6202. {
  6203. if (_pPositions->hdsaWP)
  6204. DSA_DeleteAllItems(_pPositions->hdsaWP);
  6205. }
  6206. else
  6207. {
  6208. _pPositions = (LPWINDOWPOSITIONS)LocalAlloc(LPTR, sizeof(WINDOWPOSITIONS));
  6209. if (_pPositions)
  6210. {
  6211. _pPositions->hdsaWP = DSA_Create(sizeof(HWNDANDPLACEMENT), 4);
  6212. }
  6213. }
  6214. if (_pPositions)
  6215. {
  6216. _pPositions->idRes = idRes;
  6217. // CheckWindowPositions tested for these...
  6218. ASSERT(idRes == IDS_MINIMIZEALL || idRes == IDS_CASCADE || idRes == IDS_TILE);
  6219. EnumWindows(SavePosEnumProc, (LPARAM)this);
  6220. }
  6221. LEAVECRITICAL;
  6222. }
  6223. typedef struct
  6224. {
  6225. LPWINDOWPOSITIONS pPositions;
  6226. HWND hwndDesktop;
  6227. HWND hwndTray;
  6228. BOOL fPostLowerDesktop;
  6229. } RESTOREWNDDATA, *PRESTOREWNDDATA;
  6230. DWORD WINAPI RestoreWndPosThreadProc(void* pv)
  6231. {
  6232. PRESTOREWNDDATA pWndData = (PRESTOREWNDDATA)pv;
  6233. if (pWndData && pWndData->pPositions)
  6234. {
  6235. LPHWNDANDPLACEMENT phap;
  6236. LONG iAnimate;
  6237. ANIMATIONINFO ami;
  6238. ami.cbSize = sizeof(ANIMATIONINFO);
  6239. SystemParametersInfo(SPI_GETANIMATION, sizeof(ami), &ami, FALSE);
  6240. iAnimate = ami.iMinAnimate;
  6241. ami.iMinAnimate = FALSE;
  6242. SystemParametersInfo(SPI_SETANIMATION, sizeof(ami), &ami, FALSE);
  6243. if (pWndData->pPositions->hdsaWP)
  6244. {
  6245. for (int i = DSA_GetItemCount(pWndData->pPositions->hdsaWP) - 1 ; i >= 0; i--)
  6246. {
  6247. phap = (LPHWNDANDPLACEMENT)DSA_GetItemPtr(pWndData->pPositions->hdsaWP, i);
  6248. if (IsWindow(phap->hwnd))
  6249. {
  6250. #ifndef WPF_ASYNCWINDOWPLACEMENT
  6251. #define WPF_ASYNCWINDOWPLACEMENT 0x0004
  6252. #endif
  6253. // pass this async.
  6254. if (!IsHungAppWindow(phap->hwnd))
  6255. {
  6256. phap->wp.length = sizeof(WINDOWPLACEMENT);
  6257. phap->wp.flags |= WPF_ASYNCWINDOWPLACEMENT;
  6258. if (phap->fRestore)
  6259. {
  6260. // only restore those guys we've actually munged.
  6261. SetWindowPlacement(phap->hwnd, &phap->wp);
  6262. }
  6263. }
  6264. }
  6265. }
  6266. }
  6267. ami.iMinAnimate = iAnimate;
  6268. SystemParametersInfo(SPI_SETANIMATION, sizeof(ami), &ami, FALSE);
  6269. _DestroySavedWindowPositions(pWndData->pPositions);
  6270. if (pWndData->fPostLowerDesktop)
  6271. {
  6272. PostMessage(pWndData->hwndDesktop, DTM_RAISE, (WPARAM)pWndData->hwndTray, DTRF_LOWER);
  6273. }
  6274. delete pWndData;
  6275. }
  6276. return 1;
  6277. }
  6278. BOOL CTray::_RestoreWindowPositions(BOOL fPostLowerDesktop)
  6279. {
  6280. BOOL fRet = FALSE;
  6281. ENTERCRITICAL;
  6282. if (_pPositions)
  6283. {
  6284. PRESTOREWNDDATA pWndData = new RESTOREWNDDATA;
  6285. if (pWndData)
  6286. {
  6287. pWndData->pPositions = _pPositions;
  6288. pWndData->fPostLowerDesktop = fPostLowerDesktop;
  6289. pWndData->hwndDesktop = v_hwndDesktop;
  6290. pWndData->hwndTray = _hwnd;
  6291. if (SHCreateThread(RestoreWndPosThreadProc, pWndData, 0, NULL))
  6292. {
  6293. fRet = TRUE;
  6294. _pPositions = NULL;
  6295. }
  6296. else
  6297. {
  6298. delete pWndData;
  6299. }
  6300. }
  6301. }
  6302. LEAVECRITICAL;
  6303. return fRet;
  6304. }
  6305. void _DestroySavedWindowPositions(LPWINDOWPOSITIONS pPositions)
  6306. {
  6307. ENTERCRITICAL;
  6308. if (pPositions)
  6309. {
  6310. // free the global struct
  6311. DSA_Destroy(pPositions->hdsaWP);
  6312. LocalFree(pPositions);
  6313. }
  6314. LEAVECRITICAL;
  6315. }
  6316. void CTray::HandleWindowDestroyed(HWND hwnd)
  6317. {
  6318. // enter critical section so we dont corrupt the hdsaWP
  6319. ENTERCRITICAL;
  6320. if (_pPositions)
  6321. {
  6322. int i = DSA_GetItemCount(_pPositions->hdsaWP) - 1;
  6323. for (; i >= 0; i--) {
  6324. LPHWNDANDPLACEMENT phap = (LPHWNDANDPLACEMENT)DSA_GetItemPtr(_pPositions->hdsaWP, i);
  6325. if (phap->hwnd == hwnd || !IsWindow(phap->hwnd)) {
  6326. DSA_DeleteItem(_pPositions->hdsaWP, i);
  6327. }
  6328. }
  6329. if (!DSA_GetItemCount(_pPositions->hdsaWP))
  6330. {
  6331. _DestroySavedWindowPositions(_pPositions);
  6332. _pPositions = NULL;
  6333. }
  6334. }
  6335. LEAVECRITICAL;
  6336. }
  6337. // Allow us to bump the activation of the run dlg hidden window.
  6338. // Certain apps (Norton Desktop setup) use the active window at RunDlg time
  6339. // as the parent for their dialogs. If that window disappears then they fault.
  6340. // We don't want the tray to get the activation coz it will cause it to appeare
  6341. // if you're in auto-hide mode.
  6342. LRESULT WINAPI RunDlgStaticSubclassWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  6343. {
  6344. switch (uMsg)
  6345. {
  6346. case WM_ACTIVATE:
  6347. if (wParam == WA_ACTIVE)
  6348. {
  6349. // Bump the activation to the desktop.
  6350. if (v_hwndDesktop)
  6351. {
  6352. SetForegroundWindow(v_hwndDesktop);
  6353. return 0;
  6354. }
  6355. }
  6356. break;
  6357. case WM_NOTIFY:
  6358. // relay it to the tray
  6359. return SendMessage(v_hwndTray, uMsg, wParam, lParam);
  6360. }
  6361. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  6362. }
  6363. DWORD WINAPI CTray::RunDlgThreadProc(void *pv)
  6364. {
  6365. return c_tray._RunDlgThreadProc((HANDLE)pv);
  6366. }
  6367. BOOL _IsBrowserWindow(HWND hwnd)
  6368. {
  6369. static const TCHAR* c_szClasses[] =
  6370. {
  6371. TEXT("ExploreWClass"),
  6372. TEXT("CabinetWClass"),
  6373. TEXT("IEFrame"),
  6374. };
  6375. TCHAR szClass[32];
  6376. GetClassName(hwnd, szClass, ARRAYSIZE(szClass));
  6377. for (int i = 0; i < ARRAYSIZE(c_szClasses); i++)
  6378. {
  6379. if (lstrcmpi(szClass, c_szClasses[i]) == 0)
  6380. {
  6381. return TRUE;
  6382. }
  6383. }
  6384. return FALSE;
  6385. }
  6386. DWORD CTray::_RunDlgThreadProc(HANDLE hdata)
  6387. {
  6388. RECT rc, rcTemp;
  6389. HRESULT hrInit = SHCoInitialize();
  6390. // 99/04/12 #316424 vtan: Get the rectangle for the "Start" button.
  6391. // If this is off the screen the tray is probably in auto hide mode.
  6392. // In this case offset the rectangle into the monitor where it should
  6393. // belong. This may be up, down, left or right depending on the
  6394. // position of the tray.
  6395. // First thing to do is to establish the dimensions of the monitor on
  6396. // which the tray resides. If no monitor can be found then use the
  6397. // primary monitor.
  6398. MONITORINFO monitorInfo;
  6399. monitorInfo.cbSize = sizeof(monitorInfo);
  6400. if (GetMonitorInfo(_hmonStuck, &monitorInfo) == 0)
  6401. {
  6402. TBOOL(SystemParametersInfo(SPI_GETWORKAREA, 0, &monitorInfo.rcMonitor, 0));
  6403. }
  6404. // Get the co-ordinates of the "Start" button.
  6405. GetWindowRect(_hwndStart, &rc);
  6406. // Look for an intersection in the monitor.
  6407. if (IntersectRect(&rcTemp, &rc, &monitorInfo.rcMonitor) == 0)
  6408. {
  6409. LONG lDeltaX, lDeltaY;
  6410. // Does not exist in the monitor. Move the co-ordinates by the
  6411. // width or height of the tray so that it does.
  6412. // This bizarre arithmetic is used because _ComputeHiddenRect()
  6413. // takes into account the frame and that right/bottom of RECT
  6414. // is exclusive in GDI.
  6415. lDeltaX = _sStuckWidths.cx - g_cxFrame;
  6416. lDeltaY = _sStuckWidths.cy - g_cyFrame;
  6417. if (rc.left < monitorInfo.rcMonitor.left)
  6418. {
  6419. --lDeltaX;
  6420. lDeltaY = 0;
  6421. }
  6422. else if (rc.top < monitorInfo.rcMonitor.top)
  6423. {
  6424. lDeltaX = 0;
  6425. --lDeltaY;
  6426. }
  6427. else if (rc.right > monitorInfo.rcMonitor.right)
  6428. {
  6429. lDeltaX = -lDeltaX;
  6430. lDeltaY = 0;
  6431. }
  6432. else if (rc.bottom > monitorInfo.rcMonitor.bottom)
  6433. {
  6434. lDeltaX = 0;
  6435. lDeltaY = -lDeltaY;
  6436. }
  6437. TBOOL(OffsetRect(&rc, lDeltaX, lDeltaY));
  6438. }
  6439. HWND hwnd = CreateWindowEx(WS_EX_TOOLWINDOW, TEXT("static"), NULL, 0 ,
  6440. rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hinstCabinet, NULL);
  6441. if (hwnd)
  6442. {
  6443. BOOL fSimple = FALSE;
  6444. HANDLE hMemWorkDir = NULL;
  6445. LPITEMIDLIST pidlWorkingDir = NULL;
  6446. // Subclass it.
  6447. SubclassWindow(hwnd, RunDlgStaticSubclassWndProc);
  6448. if (hdata)
  6449. SetProp(hwnd, TEXT("WaitingThreadID"), hdata);
  6450. if (!SHRestricted(REST_STARTRUNNOHOMEPATH))
  6451. {
  6452. // On NT, we like to start apps in the HOMEPATH directory. This
  6453. // should be the current directory for the current process.
  6454. TCHAR szDir[MAX_PATH];
  6455. TCHAR szPath[MAX_PATH];
  6456. GetEnvironmentVariable(TEXT("HOMEDRIVE"), szDir, ARRAYSIZE(szDir));
  6457. GetEnvironmentVariable(TEXT("HOMEPATH"), szPath, ARRAYSIZE(szPath));
  6458. if (PathAppend(szDir, szPath) && PathIsDirectory(szDir))
  6459. {
  6460. pidlWorkingDir = SHSimpleIDListFromPath(szDir);
  6461. if (pidlWorkingDir)
  6462. {
  6463. // free it the "simple" way...
  6464. fSimple = TRUE;
  6465. }
  6466. }
  6467. }
  6468. if (!pidlWorkingDir)
  6469. {
  6470. // If the last active window was a folder/explorer window with the
  6471. // desktop as root, use its as the current dir
  6472. if (_hwndLastActive)
  6473. {
  6474. ENTERCRITICAL;
  6475. if (_hwndLastActive && !IsMinimized(_hwndLastActive) && _IsBrowserWindow(_hwndLastActive))
  6476. {
  6477. SendMessageTimeout(_hwndLastActive, CWM_CLONEPIDL, GetCurrentProcessId(), 0, SMTO_ABORTIFHUNG | SMTO_BLOCK, 500, (DWORD_PTR*)&hMemWorkDir);
  6478. pidlWorkingDir = (LPITEMIDLIST)SHLockShared(hMemWorkDir, GetCurrentProcessId());
  6479. }
  6480. LEAVECRITICAL;
  6481. }
  6482. }
  6483. _RunFileDlg(hwnd, 0, pidlWorkingDir, 0, 0, 0);
  6484. if (pidlWorkingDir)
  6485. {
  6486. if (fSimple)
  6487. {
  6488. ILFree(pidlWorkingDir);
  6489. }
  6490. else
  6491. {
  6492. SHUnlockShared(pidlWorkingDir);
  6493. }
  6494. }
  6495. if (hMemWorkDir)
  6496. {
  6497. ASSERT(fSimple == FALSE);
  6498. SHFreeShared(hMemWorkDir, GetCurrentProcessId());
  6499. }
  6500. if (hdata)
  6501. {
  6502. RemoveProp(hwnd, TEXT("WaitingThreadID"));
  6503. }
  6504. DestroyWindow(hwnd);
  6505. }
  6506. SHCoUninitialize(hrInit);
  6507. return TRUE;
  6508. }
  6509. void CTray::_RunDlg()
  6510. {
  6511. HANDLE hEvent;
  6512. void *pvThreadParam;
  6513. if (!_Restricted(_hwnd, REST_NORUN))
  6514. {
  6515. TCHAR szRunDlgTitle[MAX_PATH];
  6516. HWND hwndOldRun;
  6517. LoadString(hinstCabinet, IDS_RUNDLGTITLE, szRunDlgTitle, ARRAYSIZE(szRunDlgTitle));
  6518. // See if there is already a run dialog up, and if so, try to activate it
  6519. hwndOldRun = FindWindow(WC_DIALOG, szRunDlgTitle);
  6520. if (hwndOldRun)
  6521. {
  6522. DWORD dwPID;
  6523. GetWindowThreadProcessId(hwndOldRun, &dwPID);
  6524. if (dwPID == GetCurrentProcessId())
  6525. {
  6526. if (IsWindowVisible(hwndOldRun))
  6527. {
  6528. SetForegroundWindow(hwndOldRun);
  6529. return;
  6530. }
  6531. }
  6532. }
  6533. // Create an event so we can wait for the run dlg to appear before
  6534. // continue - this allows it to capture any type-ahead.
  6535. hEvent = CreateEvent(NULL, TRUE, FALSE, TEXT("MSShellRunDlgReady"));
  6536. if (hEvent)
  6537. pvThreadParam = IntToPtr(GetCurrentThreadId());
  6538. else
  6539. pvThreadParam = NULL;
  6540. if (SHQueueUserWorkItem(RunDlgThreadProc, pvThreadParam, 0, 0, NULL, NULL, TPS_LONGEXECTIME | TPS_DEMANDTHREAD))
  6541. {
  6542. if (hEvent)
  6543. {
  6544. SHProcessMessagesUntilEvent(NULL, hEvent, 10 * 1000);
  6545. DebugMsg(DM_TRACE, TEXT("c.t_rd: Done waiting."));
  6546. }
  6547. }
  6548. if (hEvent)
  6549. CloseHandle(hEvent);
  6550. }
  6551. }
  6552. void CTray::_ExploreCommonStartMenu(BOOL bExplore)
  6553. {
  6554. TCHAR szPath[MAX_PATH];
  6555. TCHAR szCmdLine[MAX_PATH + 50];
  6556. //
  6557. // Get the common start menu path.
  6558. //
  6559. // we want to force the directory to exist, but not on W95 machines
  6560. if (!SHGetSpecialFolderPath(NULL, szPath, CSIDL_COMMON_STARTMENU, FALSE))
  6561. {
  6562. return;
  6563. }
  6564. //
  6565. // If we are starting in explorer view, then the command line
  6566. // has a "/e, " before the quoted diretory.
  6567. //
  6568. if (bExplore)
  6569. {
  6570. lstrcpy(szCmdLine, TEXT("explorer.exe /e, \""));
  6571. }
  6572. else
  6573. {
  6574. lstrcpy(szCmdLine, TEXT("explorer.exe \""));
  6575. }
  6576. lstrcat(szCmdLine, szPath);
  6577. lstrcat(szCmdLine, TEXT("\""));
  6578. // Initialize process startup info
  6579. STARTUPINFO si = {0};
  6580. si.cb = sizeof(si);
  6581. si.dwFlags = STARTF_USESHOWWINDOW;
  6582. si.wShowWindow = SW_SHOWNORMAL;
  6583. // Start explorer
  6584. PROCESS_INFORMATION pi = {0};
  6585. if (CreateProcess(NULL, szCmdLine, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi))
  6586. {
  6587. // Close the process and thread handles
  6588. CloseHandle(pi.hProcess);
  6589. CloseHandle(pi.hThread);
  6590. }
  6591. }
  6592. int CTray::_GetQuickLaunchID()
  6593. {
  6594. int iQLBandID = -1;
  6595. DWORD dwBandID;
  6596. for (int i = 0; (iQLBandID == -1) && SUCCEEDED(_ptbs->EnumBands(i, &dwBandID)); i++)
  6597. {
  6598. if (BandSite_TestBandCLSID(_ptbs, dwBandID, CLSID_ISFBand) == S_OK)
  6599. {
  6600. IUnknown* punk;
  6601. if (SUCCEEDED(_ptbs->GetBandObject(dwBandID, IID_PPV_ARG(IUnknown, &punk))))
  6602. {
  6603. VARIANTARG v = {0};
  6604. v.vt = VT_I4;
  6605. if (SUCCEEDED(IUnknown_Exec(punk, &CLSID_ISFBand, 1, 0, NULL, &v)))
  6606. {
  6607. if ((v.vt == VT_I4) && (CSIDL_APPDATA == (DWORD)v.lVal))
  6608. {
  6609. iQLBandID = (int)dwBandID;
  6610. }
  6611. }
  6612. punk->Release();
  6613. }
  6614. }
  6615. }
  6616. return iQLBandID;
  6617. }
  6618. int CTray::_ToggleQL(int iVisible)
  6619. {
  6620. int iQLBandID = _GetQuickLaunchID();
  6621. bool fOldVisible = (-1 != iQLBandID);
  6622. bool fNewVisible = (0 != iVisible);
  6623. if ((iVisible != -1) && (fNewVisible != fOldVisible))
  6624. {
  6625. if (fNewVisible)
  6626. {
  6627. LPITEMIDLIST pidl;
  6628. if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA, &pidl)))
  6629. {
  6630. TCHAR szPath[MAX_PATH];
  6631. SHGetPathFromIDList(pidl, szPath);
  6632. PathCombine(szPath, szPath, L"Microsoft\\Internet Explorer\\Quick Launch");
  6633. ILFree(pidl);
  6634. pidl = ILCreateFromPath(szPath);
  6635. if (pidl)
  6636. {
  6637. IFolderBandPriv *pfbp;
  6638. // create an ISF band to show folders as hotlinks
  6639. if (SUCCEEDED(CoCreateInstance(CLSID_ISFBand, NULL, CLSCTX_INPROC, IID_PPV_ARG(IFolderBandPriv, &pfbp))))
  6640. {
  6641. IShellFolderBand* psfb;
  6642. if (SUCCEEDED(pfbp->QueryInterface(IID_PPV_ARG(IShellFolderBand, &psfb))))
  6643. {
  6644. if (SUCCEEDED(psfb->InitializeSFB(NULL, pidl)))
  6645. {
  6646. pfbp->SetNoText(TRUE);
  6647. VARIANTARG v;
  6648. v.vt = VT_I4;
  6649. v.lVal = CSIDL_APPDATA;
  6650. IUnknown_Exec(psfb, &CLSID_ISFBand, 1, 0, &v, NULL);
  6651. v.lVal = UEMIND_SHELL; // UEMIND_SHELL/BROWSER
  6652. IUnknown_Exec(psfb, &CGID_ShellDocView, SHDVID_UEMLOG, 0, &v, NULL);
  6653. IDeskBand* ptb;
  6654. if (SUCCEEDED(pfbp->QueryInterface(IID_PPV_ARG(IDeskBand, &ptb))))
  6655. {
  6656. HRESULT hr = _ptbs->AddBand(ptb);
  6657. if (SUCCEEDED(hr))
  6658. {
  6659. _ptbs->SetBandState(ShortFromResult(hr), BSSF_NOTITLE, BSSF_NOTITLE);
  6660. }
  6661. ptb->Release();
  6662. }
  6663. }
  6664. psfb->Release();
  6665. }
  6666. pfbp->Release();
  6667. }
  6668. ILFree(pidl);
  6669. }
  6670. }
  6671. }
  6672. else
  6673. {
  6674. int iBandID;
  6675. do {
  6676. iBandID = _GetQuickLaunchID();
  6677. if (iBandID != -1)
  6678. {
  6679. _ptbs->RemoveBand(iBandID);
  6680. }
  6681. } while (iBandID != -1);
  6682. }
  6683. }
  6684. return iQLBandID;
  6685. }
  6686. void CTray::StartMenuContextMenu(HWND hwnd, DWORD dwPos)
  6687. {
  6688. LPITEMIDLIST pidlStart = SHCloneSpecialIDList(hwnd, CSIDL_STARTMENU, TRUE);
  6689. INSTRUMENT_STATECHANGE(SHCNFI_STATE_TRAY_CONTEXT_START);
  6690. HandleFullScreenApp(NULL);
  6691. SetForegroundWindow(hwnd);
  6692. if (pidlStart)
  6693. {
  6694. LPITEMIDLIST pidlLast = ILClone(ILFindLastID(pidlStart));
  6695. ILRemoveLastID(pidlStart);
  6696. if (pidlLast)
  6697. {
  6698. IShellFolder *psf = BindToFolder(pidlStart);
  6699. if (psf)
  6700. {
  6701. HMENU hmenu = CreatePopupMenu();
  6702. if (hmenu)
  6703. {
  6704. IContextMenu *pcm;
  6705. HRESULT hr = psf->GetUIObjectOf(hwnd, 1, (LPCITEMIDLIST*)&pidlLast, IID_X_PPV_ARG(IContextMenu, NULL, &pcm));
  6706. if (SUCCEEDED(hr))
  6707. {
  6708. hr = pcm->QueryContextMenu(hmenu, 0, IDSYSPOPUP_FIRST, IDSYSPOPUP_LAST, CMF_VERBSONLY);
  6709. if (SUCCEEDED(hr))
  6710. {
  6711. int idCmd;
  6712. TCHAR szCommon[MAX_PATH];
  6713. //Add the menu to invoke the "Start Menu Properties"
  6714. LoadString (hinstCabinet, IDS_STARTMENUPROP, szCommon, ARRAYSIZE(szCommon));
  6715. AppendMenu (hmenu, MF_STRING, IDSYSPOPUP_STARTMENUPROP, szCommon);
  6716. if (!SHRestricted(REST_NOCOMMONGROUPS))
  6717. {
  6718. // If the user has access to the Common Start Menu, then we can add those items. If not,
  6719. // then we should not.
  6720. BOOL fAddCommon = (S_OK == SHGetFolderPath(NULL, CSIDL_COMMON_STARTMENU, NULL, 0, szCommon));
  6721. if (fAddCommon)
  6722. fAddCommon = IsUserAnAdmin();
  6723. // Since we don't show this on the start button when the user is not an admin, don't show it here... I guess...
  6724. if (fAddCommon)
  6725. {
  6726. AppendMenu (hmenu, MF_SEPARATOR, 0, NULL);
  6727. LoadString (hinstCabinet, IDS_OPENCOMMON, szCommon, ARRAYSIZE(szCommon));
  6728. AppendMenu (hmenu, MF_STRING, IDSYSPOPUP_OPENCOMMON, szCommon);
  6729. LoadString (hinstCabinet, IDS_EXPLORECOMMON, szCommon, ARRAYSIZE(szCommon));
  6730. AppendMenu (hmenu, MF_STRING, IDSYSPOPUP_EXPLORECOMMON, szCommon);
  6731. }
  6732. }
  6733. if (dwPos == (DWORD)-1)
  6734. {
  6735. idCmd = _TrackMenu(hmenu);
  6736. }
  6737. else
  6738. {
  6739. SendMessage(_hwndTrayTips, TTM_ACTIVATE, FALSE, 0L);
  6740. idCmd = TrackPopupMenu(hmenu,
  6741. TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN,
  6742. GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos), 0, hwnd, NULL);
  6743. SendMessage(_hwndTrayTips, TTM_ACTIVATE, TRUE, 0L);
  6744. }
  6745. switch(idCmd)
  6746. {
  6747. case 0: //User did not select a menu item; so, nothing to do!
  6748. break;
  6749. case IDSYSPOPUP_OPENCOMMON:
  6750. _ExploreCommonStartMenu(FALSE);
  6751. break;
  6752. case IDSYSPOPUP_EXPLORECOMMON:
  6753. _ExploreCommonStartMenu(TRUE);
  6754. break;
  6755. case IDSYSPOPUP_STARTMENUPROP:
  6756. DoProperties(TPF_STARTMENUPAGE);
  6757. break;
  6758. default:
  6759. TCHAR szPath[MAX_PATH];
  6760. CMINVOKECOMMANDINFOEX ici = {0};
  6761. #ifdef UNICODE
  6762. CHAR szPathAnsi[MAX_PATH];
  6763. #endif
  6764. ici.cbSize = sizeof(CMINVOKECOMMANDINFOEX);
  6765. ici.hwnd = hwnd;
  6766. ici.lpVerb = (LPSTR)MAKEINTRESOURCE(idCmd - IDSYSPOPUP_FIRST);
  6767. ici.nShow = SW_NORMAL;
  6768. #ifdef UNICODE
  6769. SHGetPathFromIDListA(pidlStart, szPathAnsi);
  6770. SHGetPathFromIDList(pidlStart, szPath);
  6771. ici.lpDirectory = szPathAnsi;
  6772. ici.lpDirectoryW = szPath;
  6773. ici.fMask |= CMIC_MASK_UNICODE;
  6774. #else
  6775. SHGetPathFromIDList(pidlStart, szPath);
  6776. ici.lpDirectory = szPath;
  6777. #endif
  6778. pcm->InvokeCommand((LPCMINVOKECOMMANDINFO)&ici);
  6779. break;
  6780. } // Switch(idCmd)
  6781. }
  6782. pcm->Release();
  6783. }
  6784. DestroyMenu(hmenu);
  6785. }
  6786. psf->Release();
  6787. }
  6788. ILFree(pidlLast);
  6789. }
  6790. ILFree(pidlStart);
  6791. }
  6792. }
  6793. void GiveDesktopFocus()
  6794. {
  6795. SetForegroundWindow(v_hwndDesktop);
  6796. SendMessage(v_hwndDesktop, DTM_UIACTIVATEIO, (WPARAM) TRUE, /*dtb*/0);
  6797. }
  6798. /*----------------------------------------------------------
  6799. Purpose: loads the given resource string and executes it.
  6800. The resource string should follow this format:
  6801. "program.exe>parameters"
  6802. If there are no parameters, the format should simply be:
  6803. "program.exe"
  6804. */
  6805. void _ExecResourceCmd(UINT ids)
  6806. {
  6807. TCHAR szCmd[2*MAX_PATH];
  6808. if (LoadString(hinstCabinet, ids, szCmd, SIZECHARS(szCmd)))
  6809. {
  6810. SHELLEXECUTEINFO sei = {0};
  6811. // Find list of parameters (if any)
  6812. LPTSTR pszParam = StrChr(szCmd, TEXT('>'));
  6813. if (pszParam)
  6814. {
  6815. // Replace the '>' with a null terminator
  6816. *pszParam = 0;
  6817. pszParam++;
  6818. }
  6819. sei.cbSize = sizeof(sei);
  6820. sei.nShow = SW_SHOWNORMAL;
  6821. sei.lpFile = szCmd;
  6822. sei.lpParameters = pszParam;
  6823. ShellExecuteEx(&sei);
  6824. }
  6825. }
  6826. void CTray::_RefreshStartMenu()
  6827. {
  6828. if (_pmbStartMenu)
  6829. {
  6830. IUnknown_Exec(_pmbStartMenu, &CLSID_MenuBand, MBANDCID_REFRESH, 0, NULL, NULL);
  6831. }
  6832. else if (_pmpStartPane)
  6833. {
  6834. IUnknown_Exec(_pmpStartPane, &CLSID_MenuBand, MBANDCID_REFRESH, 0, NULL, NULL);
  6835. }
  6836. _RefreshSettings();
  6837. _UpdateBandSiteStyle();
  6838. }
  6839. BOOL CTray::_CanMinimizeAll()
  6840. {
  6841. #ifdef FEATURE_STARTPAGE
  6842. if (Tray_ShowStartPageEnabled())
  6843. return FALSE;
  6844. #endif
  6845. return (_hwndTasks && SendMessage(_hwndTasks, TBC_CANMINIMIZEALL, 0, 0));
  6846. }
  6847. BOOL CTray::_MinimizeAll(BOOL fPostRaiseDesktop)
  6848. {
  6849. BOOL fRet = FALSE;
  6850. if (_hwndTasks)
  6851. {
  6852. fRet = (BOOL)SendMessage(_hwndTasks, TBC_MINIMIZEALL, (WPARAM)_hwnd, (LPARAM)fPostRaiseDesktop);
  6853. }
  6854. return fRet;
  6855. }
  6856. extern void _UpdateNotifySetting(BOOL fNotifySetting);
  6857. //
  6858. // Due to the weirdness of PnP, if the eject request occurs on a thread
  6859. // that contains windows, the eject stalls for 15 seconds. So do it
  6860. // on its own thread.
  6861. //
  6862. DWORD CALLBACK _EjectThreadProc(LPVOID lpThreadParameter)
  6863. {
  6864. CM_Request_Eject_PC();
  6865. return 0;
  6866. }
  6867. void CTray::_Command(UINT idCmd)
  6868. {
  6869. INSTRUMENT_ONCOMMAND(SHCNFI_TRAYCOMMAND, _hwnd, idCmd);
  6870. switch (idCmd) {
  6871. case IDM_CONTROLS:
  6872. case IDM_PRINTERS:
  6873. _ShowFolder(_hwnd,
  6874. idCmd == IDM_CONTROLS ? CSIDL_CONTROLS : CSIDL_PRINTERS, COF_USEOPENSETTINGS);
  6875. break;
  6876. case IDM_EJECTPC:
  6877. // Must use SHCreateThread and not a queued workitem because
  6878. // a workitem might inherit a thread that has windows on it.
  6879. // CTF_INSIST: In emergency, eject synchronously. This stalls
  6880. // for 15 seconds but it's better than nothing.
  6881. SHCreateThread(_EjectThreadProc, NULL, CTF_INSIST, NULL);
  6882. break;
  6883. case IDM_LOGOFF:
  6884. // Let the desktop get a chance to repaint to get rid of the
  6885. // start menu bits before bringing up the logoff dialog box.
  6886. UpdateWindow(_hwnd);
  6887. Sleep(100);
  6888. _SaveTrayAndDesktop();
  6889. LogoffWindowsDialog(v_hwndDesktop);
  6890. break;
  6891. case IDM_MU_DISCONNECT:
  6892. // Do the same sleep as above for the same reason.
  6893. UpdateWindow(_hwnd);
  6894. Sleep(100);
  6895. DisconnectWindowsDialog(v_hwndDesktop);
  6896. break;
  6897. case IDM_EXITWIN:
  6898. // Do the same sleep as above for the same reason.
  6899. UpdateWindow(_hwnd);
  6900. Sleep(100);
  6901. _DoExitWindows(v_hwndDesktop);
  6902. break;
  6903. case IDM_TOGGLEDESKTOP:
  6904. _RaiseDesktop(!g_fDesktopRaised, TRUE);
  6905. break;
  6906. case IDM_FILERUN:
  6907. _RunDlg();
  6908. break;
  6909. case IDM_MINIMIZEALLHOTKEY:
  6910. _HandleGlobalHotkey(GHID_MINIMIZEALL);
  6911. break;
  6912. #ifdef DEBUG
  6913. case IDM_SIZEUP:
  6914. {
  6915. RECT rcView;
  6916. GetWindowRect(_hwndRebar, &rcView);
  6917. MapWindowPoints(HWND_DESKTOP, _hwnd, (LPPOINT)&rcView, 2);
  6918. rcView.bottom -= 18;
  6919. SetWindowPos(_hwndRebar, NULL, 0, 0, RECTWIDTH(rcView), RECTHEIGHT(rcView), SWP_NOMOVE | SWP_NOZORDER);
  6920. }
  6921. break;
  6922. case IDM_SIZEDOWN:
  6923. {
  6924. RECT rcView;
  6925. GetWindowRect(_hwndRebar, &rcView);
  6926. MapWindowPoints(HWND_DESKTOP, _hwnd, (LPPOINT)&rcView, 2);
  6927. rcView.bottom += 18;
  6928. SetWindowPos(_hwndRebar, NULL, 0, 0, RECTWIDTH(rcView), RECTHEIGHT(rcView), SWP_NOMOVE | SWP_NOZORDER);
  6929. }
  6930. break;
  6931. #endif
  6932. case IDM_MINIMIZEALL:
  6933. // minimize all window
  6934. _MinimizeAll(FALSE);
  6935. _fUndoEnabled = TRUE;
  6936. break;
  6937. case IDM_UNDO:
  6938. _RestoreWindowPositions(FALSE);
  6939. break;
  6940. case IDM_SETTIME:
  6941. // run the default applet in timedate.cpl
  6942. SHRunControlPanel(TEXT("timedate.cpl"), _hwnd);
  6943. break;
  6944. case IDM_NOTIFYCUST:
  6945. DoProperties(TPF_TASKBARPAGE | TPF_INVOKECUSTOMIZE);
  6946. break;
  6947. case IDM_LOCKTASKBAR:
  6948. {
  6949. BOOL fCanSizeMove = !_fCanSizeMove; // toggle
  6950. SHRegSetUSValue(REGSTR_EXPLORER_ADVANCED, TEXT("TaskbarSizeMove"),
  6951. REG_DWORD, &fCanSizeMove , sizeof(DWORD), SHREGSET_FORCE_HKCU);
  6952. _RefreshSettings();
  6953. _UpdateBandSiteStyle();
  6954. }
  6955. break;
  6956. case IDM_SHOWTASKMAN:
  6957. RunSystemMonitor();
  6958. break;
  6959. case IDM_CASCADE:
  6960. case IDM_VERTTILE:
  6961. case IDM_HORIZTILE:
  6962. if (_CanTileAnyWindows())
  6963. {
  6964. SaveWindowPositions((idCmd == IDM_CASCADE) ? IDS_CASCADE : IDS_TILE);
  6965. _AppBarNotifyAll(NULL, ABN_WINDOWARRANGE, NULL, TRUE);
  6966. if (idCmd == IDM_CASCADE)
  6967. {
  6968. CascadeWindows(GetDesktopWindow(), 0, NULL, 0, NULL);
  6969. }
  6970. else
  6971. {
  6972. TileWindows(GetDesktopWindow(), ((idCmd == IDM_VERTTILE)?
  6973. MDITILE_VERTICAL : MDITILE_HORIZONTAL), NULL, 0, NULL);
  6974. }
  6975. // do it *before* ABN_xxx so don't get 'indirect' moves
  6976. // REVIEW or should it be after?
  6977. // CheckWindowPositions();
  6978. _fUndoEnabled = FALSE;
  6979. SetTimer(_hwnd, IDT_ENABLEUNDO, 500, NULL);
  6980. _AppBarNotifyAll(NULL, ABN_WINDOWARRANGE, NULL, FALSE);
  6981. }
  6982. break;
  6983. case IDM_TRAYPROPERTIES:
  6984. DoProperties(TPF_TASKBARPAGE);
  6985. break;
  6986. case IDM_SETTINGSASSIST:
  6987. SHCreateThread(SettingsUIThreadProc, NULL, 0, NULL);
  6988. break;
  6989. case IDM_HELPSEARCH:
  6990. _ExecResourceCmd(IDS_HELP_CMD);
  6991. break;
  6992. // NB The Alt-s comes in here.
  6993. case IDC_KBSTART:
  6994. SetForegroundWindow(_hwnd);
  6995. // This pushes the start button and causes the start menu to popup.
  6996. SendMessage(_hwndStart, BM_SETSTATE, TRUE, 0);
  6997. // This forces the button back up.
  6998. SendMessage(_hwndStart, BM_SETSTATE, FALSE, 0);
  6999. break;
  7000. case IDC_ASYNCSTART:
  7001. #if 0 // (for testing UAssist locking code)
  7002. UEMFireEvent(&UEMIID_SHELL, UEME_DBSLEEP, UEMF_XEVENT, -1, (LPARAM)10000);
  7003. #endif
  7004. #ifdef DEBUG
  7005. if (GetAsyncKeyState(VK_SHIFT) < 0)
  7006. {
  7007. UEMFireEvent(&UEMIID_SHELL, UEME_CTLSESSION, UEMF_XEVENT, TRUE, -1);
  7008. _RefreshStartMenu();
  7009. }
  7010. #endif
  7011. // Make sure the button is down.
  7012. // DebugMsg(DM_TRACE, "c.twp: IDC_START.");
  7013. // Make sure the Start button is down.
  7014. if (!_bMainMenuInit && SendMessage(_hwndStart, BM_GETSTATE, 0, 0) & BST_PUSHED)
  7015. {
  7016. // DebugMsg(DM_TRACE, "c.twp: Start button down.");
  7017. // Set the focus.
  7018. _SetFocus(_hwndStart);
  7019. _ToolbarMenu();
  7020. }
  7021. break;
  7022. // NB LButtonDown on the Start button come in here.
  7023. // Space-bar stuff also comes in here.
  7024. case IDC_START:
  7025. // User gets a bit confused with space-bar tuff (the popup ends up
  7026. // getting the key-up and beeps).
  7027. PostMessage(_hwnd, WM_COMMAND, IDC_ASYNCSTART, 0);
  7028. break;
  7029. case FCIDM_FINDFILES:
  7030. SHFindFiles(NULL, NULL);
  7031. break;
  7032. case FCIDM_FINDCOMPUTER:
  7033. SHFindComputer(NULL, NULL);
  7034. break;
  7035. case FCIDM_REFRESH:
  7036. _RefreshStartMenu();
  7037. break;
  7038. case FCIDM_NEXTCTL:
  7039. {
  7040. MSG msg = { 0, WM_KEYDOWN, VK_TAB };
  7041. HWND hwndFocus = GetFocus();
  7042. // Since we are Tab or Shift Tab we should turn the focus rect on.
  7043. //
  7044. // Note: we don't need to do this in the GiveDesktopFocus cases below,
  7045. // but in those cases we're probably already in the UIS_CLEAR UISF_HIDEFOCUS
  7046. // state so this message is cheap to send.
  7047. //
  7048. SendMessage(_hwnd, WM_UPDATEUISTATE, MAKEWPARAM(UIS_CLEAR,
  7049. UISF_HIDEFOCUS), 0);
  7050. BOOL fShift = GetAsyncKeyState(VK_SHIFT) < 0;
  7051. if (hwndFocus && (IsChildOrHWND(_hwndStart, hwndFocus)))
  7052. {
  7053. if (fShift)
  7054. {
  7055. // gotta deactivate manually
  7056. GiveDesktopFocus();
  7057. }
  7058. else
  7059. {
  7060. IUnknown_UIActivateIO(_ptbs, TRUE, &msg);
  7061. }
  7062. }
  7063. else if (hwndFocus && (IsChildOrHWND(_hwndNotify, hwndFocus)))
  7064. {
  7065. if (fShift)
  7066. {
  7067. IUnknown_UIActivateIO(_ptbs, TRUE, &msg);
  7068. }
  7069. else
  7070. {
  7071. GiveDesktopFocus();
  7072. }
  7073. }
  7074. else
  7075. {
  7076. if (IUnknown_TranslateAcceleratorIO(_ptbs, &msg) != S_OK)
  7077. {
  7078. if (fShift)
  7079. {
  7080. _SetFocus(_hwndStart);
  7081. }
  7082. else
  7083. {
  7084. // if you tab forward out of the bands, the next focus guy is the tray notify set
  7085. _SetFocus(_hwndNotify);
  7086. }
  7087. }
  7088. }
  7089. }
  7090. break;
  7091. case IDM_MU_SECURITY:
  7092. MuSecurity();
  7093. break;
  7094. }
  7095. }
  7096. //// Start menu/Tray tab as a drop target
  7097. HRESULT CStartDropTarget::_GetStartMenuDropTarget(IDropTarget** pptgt)
  7098. {
  7099. HRESULT hr = E_FAIL;
  7100. *pptgt = NULL;
  7101. LPITEMIDLIST pidlStart = SHCloneSpecialIDList(NULL, CSIDL_STARTMENU, TRUE);
  7102. if (pidlStart)
  7103. {
  7104. IShellFolder *psf = BindToFolder(pidlStart);
  7105. if (psf)
  7106. {
  7107. hr = psf->CreateViewObject(_ptray->_hwnd, IID_PPV_ARG(IDropTarget, pptgt));
  7108. psf->Release();
  7109. }
  7110. ILFree(pidlStart);
  7111. }
  7112. return hr;
  7113. }
  7114. STDMETHODIMP CDropTargetBase::QueryInterface(REFIID riid, void ** ppvObj)
  7115. {
  7116. static const QITAB qit[] =
  7117. {
  7118. QITABENT(CDropTargetBase, IDropTarget),
  7119. { 0 },
  7120. };
  7121. return QISearch(this, qit, riid, ppvObj);
  7122. }
  7123. STDMETHODIMP_(ULONG) CDropTargetBase::AddRef()
  7124. {
  7125. return 2;
  7126. }
  7127. STDMETHODIMP_(ULONG) CDropTargetBase::Release()
  7128. {
  7129. return 1;
  7130. }
  7131. STDMETHODIMP CDropTargetBase::DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
  7132. {
  7133. _ptray->_SetUnhideTimer(ptl.x, ptl.y);
  7134. HWND hwndLock = _ptray->_hwnd; // no clippy
  7135. _DragEnter(hwndLock, ptl, pdtobj);
  7136. return S_OK;
  7137. }
  7138. STDMETHODIMP CDropTargetBase::DragOver(DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
  7139. {
  7140. _ptray->_SetUnhideTimer(ptl.x, ptl.y);
  7141. _DragMove(_ptray->_hwndStart, ptl);
  7142. return S_OK;
  7143. }
  7144. STDMETHODIMP CDropTargetBase::DragLeave()
  7145. {
  7146. DAD_DragLeave();
  7147. return S_OK;
  7148. }
  7149. STDMETHODIMP CDropTargetBase::Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
  7150. {
  7151. DAD_DragLeave();
  7152. return S_OK;
  7153. }
  7154. //
  7155. // There are two different policies for the Start Button depending on
  7156. // whether we are in Classic mode or Personal (New Start Pane) mode.
  7157. //
  7158. // Classic mode: Drops onto the Start Button are treated as if they
  7159. // were drops into the CSIDL_STARTMENU folder.
  7160. //
  7161. // Personal mode: Drops onto the Start Button are treated as if they
  7162. // were drops into the pin list.
  7163. //
  7164. CStartDropTarget::CStartDropTarget() : CDropTargetBase(IToClass(CTray, _dtStart, this))
  7165. {
  7166. }
  7167. CTrayDropTarget::CTrayDropTarget() : CDropTargetBase(IToClass(CTray, _dtTray, this))
  7168. {
  7169. }
  7170. STDMETHODIMP CTrayDropTarget::DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
  7171. {
  7172. *pdwEffect = DROPEFFECT_NONE;
  7173. return CDropTargetBase::DragEnter(pdtobj, grfKeyState, ptl, pdwEffect);
  7174. }
  7175. STDMETHODIMP CTrayDropTarget::DragOver(DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
  7176. {
  7177. *pdwEffect = DROPEFFECT_NONE;
  7178. return CDropTargetBase::DragOver(grfKeyState, ptl, pdwEffect);
  7179. }
  7180. void CStartDropTarget::_StartAutoOpenTimer(POINTL *pptl)
  7181. {
  7182. POINT pt = { pptl->x, pptl->y };
  7183. RECT rc;
  7184. //Make sure it really is in the start menu..
  7185. GetWindowRect(_ptray->_hwndStart, &rc);
  7186. if (PtInRect(&rc,pt))
  7187. {
  7188. SetTimer(_ptray->_hwnd, IDT_STARTMENU, 1000, NULL);
  7189. }
  7190. }
  7191. STDMETHODIMP CStartDropTarget::DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
  7192. {
  7193. HRESULT hr;
  7194. if (Tray_StartPanelEnabled())
  7195. {
  7196. // Personal mode: Treat it as an add to the pin list.
  7197. if (_ptray->_psmpin && _ptray->_psmpin->IsPinnable(pdtobj, SMPINNABLE_REJECTSLOWMEDIA, NULL) == S_OK)
  7198. {
  7199. _dwEffectsAllowed = DROPEFFECT_LINK;
  7200. }
  7201. else
  7202. {
  7203. _dwEffectsAllowed = DROPEFFECT_NONE;
  7204. }
  7205. *pdwEffect &= _dwEffectsAllowed;
  7206. // Always start the AutoOpen timer because once we open, the user
  7207. // can drop onto other things which may have different drop policies
  7208. // from the pin list.
  7209. _StartAutoOpenTimer(&ptl);
  7210. hr = S_OK;
  7211. }
  7212. else
  7213. {
  7214. // Classic mode: Treat it as a drop on the Start Menu folder.
  7215. IDropTarget* ptgt;
  7216. _dwEffectsAllowed = DROPEFFECT_LINK;
  7217. hr = _GetStartMenuDropTarget(&ptgt);
  7218. if (SUCCEEDED(hr))
  7219. {
  7220. // Check to make sure that we're going to accept the drop before we expand the start menu.
  7221. ptgt->DragEnter(pdtobj, grfKeyState, ptl,
  7222. pdwEffect);
  7223. // DROPEFFECT_NONE means it ain't gonna work, so don't popup the Start Menu.
  7224. if (*pdwEffect != DROPEFFECT_NONE)
  7225. {
  7226. _StartAutoOpenTimer(&ptl);
  7227. }
  7228. ptgt->DragLeave();
  7229. ptgt->Release();
  7230. }
  7231. }
  7232. CDropTargetBase::DragEnter(pdtobj, grfKeyState, ptl, pdwEffect);
  7233. return hr;
  7234. }
  7235. STDMETHODIMP CStartDropTarget::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  7236. {
  7237. *pdwEffect = (_dwEffectsAllowed & DROPEFFECT_LINK);
  7238. return CDropTargetBase::DragOver(grfKeyState, pt, pdwEffect);
  7239. }
  7240. STDMETHODIMP CStartDropTarget::DragLeave()
  7241. {
  7242. KillTimer(_ptray->_hwnd, IDT_STARTMENU);
  7243. return CDropTargetBase::DragLeave();
  7244. }
  7245. STDMETHODIMP CStartDropTarget::Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  7246. {
  7247. KillTimer(_ptray->_hwnd, IDT_STARTMENU);
  7248. HRESULT hr;
  7249. if (Tray_StartPanelEnabled())
  7250. {
  7251. // Personal mode: Treat it as an add to the pin list.
  7252. LPITEMIDLIST pidl;
  7253. if (_ptray->_psmpin && _ptray->_psmpin->IsPinnable(pdtobj, SMPINNABLE_REJECTSLOWMEDIA, &pidl) == S_OK)
  7254. {
  7255. // Delete it from the pin list if it's already there because
  7256. // we want to move it to the bottom.
  7257. _ptray->_psmpin->Modify(pidl, NULL);
  7258. // Now add it to the bottom.
  7259. _ptray->_psmpin->Modify(NULL, pidl);
  7260. ILFree(pidl);
  7261. hr = S_OK;
  7262. }
  7263. else
  7264. {
  7265. hr = E_FAIL;
  7266. }
  7267. }
  7268. else
  7269. {
  7270. IDropTarget* pdrop;
  7271. hr = _GetStartMenuDropTarget(&pdrop);
  7272. if (SUCCEEDED(hr))
  7273. {
  7274. if (!Tray_StartPanelEnabled())
  7275. {
  7276. POINTL ptDrop = { 0, 0 };
  7277. DWORD grfKeyStateDrop = 0;
  7278. *pdwEffect &= DROPEFFECT_LINK;
  7279. pdrop->DragEnter(pdtobj, grfKeyStateDrop, ptDrop, pdwEffect);
  7280. hr = pdrop->Drop(pdtobj, grfKeyStateDrop, ptDrop, pdwEffect);
  7281. pdrop->DragLeave();
  7282. }
  7283. pdrop->Release();
  7284. }
  7285. }
  7286. DAD_DragLeave();
  7287. return hr;
  7288. }
  7289. void CTray::_RegisterDropTargets()
  7290. {
  7291. THR(RegisterDragDrop(_hwndStart, &_dtStart));
  7292. THR(RegisterDragDrop(_hwnd, &_dtTray));
  7293. // It is not a serious error if this fails; it just means that
  7294. // drag/drop to the Start Button will not add to the pin list
  7295. CoCreateInstance(CLSID_StartMenuPin, NULL, CLSCTX_INPROC_SERVER,
  7296. IID_PPV_ARG(IStartMenuPin, &_psmpin));
  7297. }
  7298. void CTray::_RevokeDropTargets()
  7299. {
  7300. RevokeDragDrop(_hwndStart);
  7301. RevokeDragDrop(_hwnd);
  7302. ATOMICRELEASET(_psmpin, IStartMenuPin);
  7303. }
  7304. void CTray::_HandleGlobalHotkey(WPARAM wParam)
  7305. {
  7306. INSTRUMENT_HOTKEY(SHCNFI_GLOBALHOTKEY, wParam);
  7307. switch(wParam)
  7308. {
  7309. case GHID_RUN:
  7310. _RunDlg();
  7311. break;
  7312. case GHID_MINIMIZEALL:
  7313. if (_CanMinimizeAll())
  7314. _MinimizeAll(FALSE);
  7315. SetForegroundWindow(v_hwndDesktop);
  7316. break;
  7317. case GHID_UNMINIMIZEALL:
  7318. _RestoreWindowPositions(FALSE);
  7319. break;
  7320. case GHID_HELP:
  7321. _Command(IDM_HELPSEARCH);
  7322. break;
  7323. case GHID_DESKTOP:
  7324. _RaiseDesktop(!g_fDesktopRaised, TRUE);
  7325. break;
  7326. case GHID_TRAYNOTIFY:
  7327. SwitchToThisWindow(_hwnd, TRUE);
  7328. SetForegroundWindow(_hwnd);
  7329. _SetFocus(_hwndNotify);
  7330. break;
  7331. case GHID_EXPLORER:
  7332. _ShowFolder(_hwnd, CSIDL_DRIVES, COF_CREATENEWWINDOW | COF_EXPLORE);
  7333. break;
  7334. case GHID_FINDFILES:
  7335. if (!SHRestricted(REST_NOFIND))
  7336. _Command(FCIDM_FINDFILES);
  7337. break;
  7338. case GHID_FINDCOMPUTER:
  7339. if (!SHRestricted(REST_NOFIND))
  7340. _Command(FCIDM_FINDCOMPUTER);
  7341. break;
  7342. case GHID_TASKTAB:
  7343. case GHID_TASKSHIFTTAB:
  7344. if (GetForegroundWindow() != _hwnd)
  7345. SetForegroundWindow(_hwnd);
  7346. SendMessage(_hwndTasks, TBC_TASKTAB, wParam == GHID_TASKTAB ? 1 : -1, 0L);
  7347. break;
  7348. case GHID_SYSPROPERTIES:
  7349. #define IDS_SYSDMCPL 0x2334 // from shelldll
  7350. SHRunControlPanel(MAKEINTRESOURCE(IDS_SYSDMCPL), _hwnd);
  7351. break;
  7352. }
  7353. }
  7354. void CTray::_UnregisterGlobalHotkeys()
  7355. {
  7356. for (int i = GHID_FIRST; i < GHID_MAX; i++)
  7357. {
  7358. UnregisterHotKey(_hwnd, i);
  7359. }
  7360. }
  7361. void CTray::_RegisterGlobalHotkeys()
  7362. {
  7363. int i;
  7364. // Are the Windows keys restricted?
  7365. DWORD dwRestricted = SHRestricted(REST_NOWINKEYS);
  7366. for (i = GHID_FIRST ; i < GHID_MAX; i++)
  7367. {
  7368. // If the Windows Keys are Not restricted or it's not a Windows key
  7369. if (!((HIWORD(GlobalKeylist[i - GHID_FIRST]) & MOD_WIN) && dwRestricted))
  7370. {
  7371. // Then register it.
  7372. RegisterHotKey(_hwnd, i, HIWORD(GlobalKeylist[i - GHID_FIRST]), LOWORD(GlobalKeylist[i - GHID_FIRST]));
  7373. }
  7374. }
  7375. }
  7376. void CTray::_RaiseDesktop(BOOL fRaise, BOOL fRestoreWindows)
  7377. {
  7378. if (v_hwndDesktop && (fRaise == !g_fDesktopRaised) && !_fProcessingDesktopRaise)
  7379. {
  7380. _fProcessingDesktopRaise = TRUE;
  7381. BOOL fPostMessage = TRUE;
  7382. if (fRaise)
  7383. {
  7384. HWND hwndFG = GetForegroundWindow();
  7385. // If no window has focus then set focus to the tray
  7386. if (hwndFG)
  7387. {
  7388. hwndFG = _hwnd;
  7389. }
  7390. if (!_hwndFocusBeforeRaise)
  7391. {
  7392. // See if the Foreground Window had a popup window
  7393. _hwndFocusBeforeRaise = GetLastActivePopup(hwndFG);
  7394. }
  7395. if (!IsWindowVisible(_hwndFocusBeforeRaise))
  7396. {
  7397. _hwndFocusBeforeRaise = hwndFG;
  7398. }
  7399. // _MinimizeAll will save the windows positions synchronously, and will minimize the
  7400. // the windows on a background thread
  7401. _fMinimizedAllBeforeRaise = _CanMinimizeAll();
  7402. if (_fMinimizedAllBeforeRaise)
  7403. {
  7404. fPostMessage = !_MinimizeAll(TRUE);
  7405. }
  7406. }
  7407. else
  7408. {
  7409. if (fRestoreWindows)
  7410. {
  7411. HWND hwnd = _hwndFocusBeforeRaise;
  7412. if (_fMinimizedAllBeforeRaise)
  7413. {
  7414. // Since the windows are restored on a seperate thread, I want the make that the
  7415. // desktop is not raised until they are done, so the window restore thread will
  7416. // actually post the message for raising the desktop
  7417. fPostMessage = !_RestoreWindowPositions(TRUE);
  7418. }
  7419. SetForegroundWindow(hwnd);
  7420. if (hwnd == _hwnd)
  7421. {
  7422. _SetFocus(_hwndStart);
  7423. }
  7424. }
  7425. _hwndFocusBeforeRaise = NULL;
  7426. }
  7427. #ifdef FEATURE_STARTPAGE
  7428. if (Tray_ShowStartPageEnabled())
  7429. {
  7430. if (fPostMessage)
  7431. SendMessage(v_hwndDesktop, DTM_RAISE, (WPARAM)_hwnd, fRaise ? DTRF_RAISE : DTRF_LOWER);
  7432. }
  7433. else
  7434. #endif
  7435. {
  7436. if (fPostMessage)
  7437. PostMessage(v_hwndDesktop, DTM_RAISE, (WPARAM)_hwnd, fRaise ? DTRF_RAISE : DTRF_LOWER);
  7438. }
  7439. }
  7440. }
  7441. void CTray::_OnDesktopState(LPARAM lParam)
  7442. {
  7443. g_fDesktopRaised = (!(lParam & DTRF_LOWER));
  7444. DAD_ShowDragImage(FALSE); // unlock the drag sink if we are dragging.
  7445. if (!g_fDesktopRaised)
  7446. {
  7447. HandleFullScreenApp(NULL);
  7448. }
  7449. else
  7450. {
  7451. // if the desktop is raised, we need to force the tray to be always on top
  7452. // until it's lowered again
  7453. _ResetZorder();
  7454. }
  7455. DAD_ShowDragImage(TRUE); // unlock the drag sink if we are dragging.
  7456. _fProcessingDesktopRaise = FALSE;
  7457. }
  7458. BOOL CTray::_ToggleLanguageBand(BOOL fShowIt)
  7459. {
  7460. HRESULT hr = E_FAIL;
  7461. DWORD dwBandID;
  7462. BOOL fFound = FALSE;
  7463. for (int i = 0; !fFound && SUCCEEDED(_ptbs->EnumBands(i, &dwBandID)); i++)
  7464. {
  7465. if (BandSite_TestBandCLSID(_ptbs, dwBandID, CLSID_MSUTBDeskBand) == S_OK)
  7466. {
  7467. fFound = TRUE;
  7468. }
  7469. }
  7470. BOOL fShow = fFound;
  7471. if (fShowIt && !fFound)
  7472. {
  7473. IDeskBand* pdb;
  7474. HRESULT hr = CoCreateInstance(CLSID_MSUTBDeskBand, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IDeskBand, &pdb));
  7475. if (SUCCEEDED(hr))
  7476. {
  7477. hr = _ptbs->AddBand(pdb);
  7478. fShow = TRUE;
  7479. pdb->Release();
  7480. }
  7481. }
  7482. else if (!fShowIt && fFound)
  7483. {
  7484. hr = _ptbs->RemoveBand(dwBandID);
  7485. if (SUCCEEDED(hr))
  7486. {
  7487. fShow = FALSE;
  7488. }
  7489. }
  7490. return fShow;
  7491. }
  7492. // Process the message by propagating it to all of our child windows
  7493. typedef struct
  7494. {
  7495. UINT uMsg;
  7496. WPARAM wP;
  7497. LPARAM lP;
  7498. CTray* ptray;
  7499. } CABPM;
  7500. BOOL CTray::PropagateEnumProc(HWND hwnd, LPARAM lParam)
  7501. {
  7502. CABPM *ppm = (CABPM *)lParam;
  7503. if (SHIsChildOrSelf(ppm->ptray->_hwndRebar, hwnd) == S_OK)
  7504. {
  7505. return TRUE;
  7506. }
  7507. SendMessage(hwnd, ppm->uMsg, ppm->wP, ppm->lP);
  7508. return TRUE;
  7509. }
  7510. void CTray::_PropagateMessage(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
  7511. {
  7512. CABPM pm = {uMessage, wParam, lParam, this};
  7513. ASSERT(hwnd != _hwndRebar);
  7514. EnumChildWindows(hwnd, PropagateEnumProc, (LPARAM)&pm);
  7515. }
  7516. //
  7517. // Called from SETTINGS.DLL when the tray property sheet needs
  7518. // to be activated. See SettingsUIThreadProc below.
  7519. //
  7520. // Also used by desktop2\deskhost.cpp to get to the tray properties.
  7521. //
  7522. void WINAPI Tray_DoProperties(DWORD dwFlags)
  7523. {
  7524. c_tray.DoProperties(dwFlags);
  7525. }
  7526. DWORD WINAPI CTray::SettingsUIThreadProc(void *pv)
  7527. {
  7528. //
  7529. // Open up the "Settings Wizards" UI.
  7530. //
  7531. HMODULE hmodSettings = LoadLibrary(TEXT("settings.dll"));
  7532. if (NULL != hmodSettings)
  7533. {
  7534. //
  7535. // Entry point in SETTINGS.DLL is ordinal 1.
  7536. // Don't want to export this entry point by name.
  7537. //
  7538. PSETTINGSUIENTRY pfDllEntry = (PSETTINGSUIENTRY)GetProcAddress(hmodSettings, (LPCSTR)1);
  7539. if (NULL != pfDllEntry)
  7540. {
  7541. //
  7542. // This call will open and run the UI.
  7543. // The thread's message loop is inside settings.dll.
  7544. // This call will not return until the settings UI has been closed.
  7545. //
  7546. (*pfDllEntry)(Tray_DoProperties);
  7547. }
  7548. FreeLibrary(hmodSettings);
  7549. }
  7550. return 0;
  7551. }
  7552. void _MigrateIEXPLORE(HKEY hkBrowser)
  7553. {
  7554. TCHAR szAppName[MAX_PATH];
  7555. LONG cb = sizeof(szAppName);
  7556. if (ERROR_SUCCESS == RegQueryValue(hkBrowser, NULL, szAppName, &cb))
  7557. {
  7558. if (0 == lstrcmp(szAppName, TEXT("Internet Explorer")))
  7559. {
  7560. TraceMsg(TF_WARNING, "Migrating old StartMenuInternet setting (you just upgraded from build 2465+)");
  7561. // copy in the good value
  7562. lstrcpy(szAppName, TEXT("iexplore.exe"));
  7563. // this will fail if the user is not an admin, oh well.
  7564. if (ERROR_SUCCESS == RegSetValueEx(hkBrowser, NULL, 0, REG_SZ, (BYTE *)szAppName, sizeof(TCHAR) * (lstrlen(szAppName)+1)))
  7565. {
  7566. // Now tell everybody about the change
  7567. SHSendMessageBroadcast(WM_SETTINGCHANGE, 0, (LPARAM)TEXT("Software\\Clients\\StartMenuInternet"));
  7568. }
  7569. }
  7570. }
  7571. }
  7572. //
  7573. // This function is called whenever we detect a change to the default
  7574. // browser registration in HKCR\http\shell\open\command.
  7575. //
  7576. // For compatibility with old browsers, if the default browser (URL handler)
  7577. // is not XP-aware, then auto-generate a StartMenuInternet client
  7578. // registration and set it as the default.
  7579. //
  7580. void CTray::_MigrateOldBrowserSettings()
  7581. {
  7582. // We want only one person to do this work per machine (though it doesn't
  7583. // hurt to have more than one person do it; it's just pointless), so try
  7584. // to filter out people who clearly didn't instigate the key change.
  7585. //
  7586. if (!_fIsDesktopLocked && _fIsDesktopConnected)
  7587. {
  7588. // If the user does not have write access then we can't migrate the
  7589. // setting... (In which case there was nothing to migrate anyway
  7590. // since you need to be administrator to change the default browser...)
  7591. HKEY hkBrowser;
  7592. DWORD dwDisposition;
  7593. if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Clients\\StartMenuInternet"),
  7594. 0, NULL, REG_OPTION_NON_VOLATILE,
  7595. KEY_READ | KEY_WRITE, NULL, &hkBrowser, &dwDisposition) == ERROR_SUCCESS)
  7596. {
  7597. TCHAR szCommand[MAX_PATH];
  7598. DWORD cch = ARRAYSIZE(szCommand);
  7599. // It is important that we use AssocQueryString to parse the
  7600. // executable, because Netscape has a habit of registering
  7601. // their path incorrectly (they forget to quote the space in
  7602. // "Program Files") but AssocQueryString has special recovery
  7603. // code to detect and repair that case...
  7604. if (SUCCEEDED(AssocQueryString(ASSOCF_NOUSERSETTINGS,
  7605. ASSOCSTR_EXECUTABLE, L"http",
  7606. L"open", szCommand, &cch)) &&
  7607. szCommand[0])
  7608. {
  7609. TCHAR szAppName[MAX_PATH];
  7610. lstrcpyn(szAppName, PathFindFileName(szCommand), ARRAYSIZE(szAppName));
  7611. // You might think that we need to special-case MSN Explorer,
  7612. // since they shipped before XP RTM'd, and convert MSN6.EXE
  7613. // to "MSN Explorer", but that's not true because
  7614. // they never take over as the default http handler, so we
  7615. // will never see them here!
  7616. // TODO - Remove _MigrateIXPLORE post-whistler. (saml 010622)
  7617. // we do need to special-case the string "Internet Explorer"
  7618. // which was written out starting with build 2465 (post-B2!)
  7619. // We want ie.inx to continue to specify FLG_ADDREG_NOCLOBBER (=2) on software\client\startmenuinternet,
  7620. // since we really don't want want to clobber this value
  7621. // Therefore, just special-case migrate the known bad value to the new good value ("iexplore.exe")
  7622. _MigrateIEXPLORE(hkBrowser);
  7623. // Create a registration for the new default browser if necessary.
  7624. // We keep our hands off once we see a DefaultIcon key, since that
  7625. // proves that the application is XP-aware.
  7626. // When IE Access is turned off, StartMenuInternet\IExplore.exe is
  7627. // also removed so that IE will not appear in "Customize Start Menu"
  7628. // dialog box. Do not migrate IE.
  7629. HKEY hkClient;
  7630. if ( 0 != lstrcmpi(szAppName, TEXT("IEXPLORE.EXE")) &&
  7631. RegCreateKeyEx(hkBrowser, szAppName, 0, NULL, REG_OPTION_NON_VOLATILE,
  7632. KEY_WRITE, NULL, &hkClient, &dwDisposition) == ERROR_SUCCESS)
  7633. {
  7634. if (dwDisposition == REG_CREATED_NEW_KEY)
  7635. {
  7636. TCHAR szFriendly[MAX_PATH];
  7637. cch = ARRAYSIZE(szFriendly);
  7638. if (SUCCEEDED(AssocQueryString(ASSOCF_NOUSERSETTINGS | ASSOCF_INIT_BYEXENAME | ASSOCF_VERIFY,
  7639. ASSOCSTR_FRIENDLYAPPNAME, szCommand,
  7640. NULL, szFriendly, &cch)))
  7641. {
  7642. // Set the friendly name
  7643. RegSetValueEx(hkClient, TEXT("LocalizedString"), 0, REG_SZ, (BYTE*)szFriendly, sizeof(TCHAR) * (cch + 1));
  7644. // Set the command string (properly quoted)
  7645. PathQuoteSpaces(szCommand);
  7646. SHSetValue(hkClient, TEXT("shell\\open\\command"), NULL,
  7647. REG_SZ, szCommand, sizeof(TCHAR) * (1 + lstrlen(szCommand)));
  7648. }
  7649. }
  7650. LONG l = 0;
  7651. if (RegQueryValue(hkClient, TEXT("DefaultIcon"), NULL, &l) == ERROR_FILE_NOT_FOUND)
  7652. {
  7653. // Set it as the system default
  7654. RegSetValueEx(hkBrowser, NULL, 0, REG_SZ, (BYTE*)szAppName, sizeof(TCHAR) * (lstrlen(szAppName) + 1));
  7655. // Now tell everybody about the change
  7656. SHSendMessageBroadcast(WM_SETTINGCHANGE, 0, (LPARAM)TEXT("Software\\Clients\\StartMenuInternet"));
  7657. }
  7658. RegCloseKey(hkClient);
  7659. }
  7660. }
  7661. RegCloseKey(hkBrowser);
  7662. }
  7663. }
  7664. // Restart the monitoring of the registry...
  7665. // (RegNotifyChangeKeyValue is good for only one shot.)
  7666. // Some apps (like Opera) delete the key as part of their registration,
  7667. // which causes our HKEY to go bad, so close it and make a new one.
  7668. if (_hkHTTP)
  7669. {
  7670. RegCloseKey(_hkHTTP);
  7671. _hkHTTP = NULL;
  7672. }
  7673. //
  7674. // Note! We have to register on HKCR\http\shell recursively
  7675. // even though we only care about HKCR\http\shell\open\command.
  7676. // The reason is that shell\open\command might not exist (IE
  7677. // deletes it as part of its uninstall) and you can't register
  7678. // a wait on a key that doesn't exist. We don't want to create
  7679. // a blank key on our own, because that means "To launch a web
  7680. // browser, run the null string as a command," which doesn't work
  7681. // too great.
  7682. //
  7683. if (RegCreateKeyEx(HKEY_CLASSES_ROOT, TEXT("http\\shell"),
  7684. 0, NULL, REG_OPTION_NON_VOLATILE,
  7685. KEY_ENUMERATE_SUB_KEYS |
  7686. KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_NOTIFY,
  7687. NULL, &_hkHTTP, NULL) == ERROR_SUCCESS)
  7688. {
  7689. RegNotifyChangeKeyValue(_hkHTTP, TRUE,
  7690. REG_NOTIFY_CHANGE_NAME |
  7691. REG_NOTIFY_CHANGE_LAST_SET,
  7692. _hHTTPEvent, TRUE);
  7693. }
  7694. }
  7695. void CTray::_MigrateOldBrowserSettingsCB(PVOID lpParameter, BOOLEAN)
  7696. {
  7697. //
  7698. // Sleep a little while so the app can finish installing all the
  7699. // registry keys it wants before we start cleaning up behind it.
  7700. //
  7701. Sleep(1000);
  7702. CTray *self = (CTray *)lpParameter;
  7703. self->_MigrateOldBrowserSettings();
  7704. }
  7705. //
  7706. // *** WARNING ***
  7707. //
  7708. // This is a private interface EXPLORER.EXE exposes to SHDOCVW, which
  7709. // allows SHDOCVW (mostly desktop) to access tray. All member must be
  7710. // thread safe!
  7711. //
  7712. CDeskTray::CDeskTray()
  7713. {
  7714. _ptray = IToClass(CTray, _desktray, this);
  7715. }
  7716. HRESULT CDeskTray::QueryInterface(REFIID riid, void ** ppvObj)
  7717. {
  7718. #if 0 // no IID_IDeskTray yet defined
  7719. static const QITAB qit[] =
  7720. {
  7721. QITABENT(CDeskTray, IDeskTray),
  7722. { 0 },
  7723. };
  7724. return QISearch(this, qit, riid, ppvObj);
  7725. #else
  7726. return E_NOTIMPL;
  7727. #endif
  7728. }
  7729. ULONG CDeskTray::AddRef()
  7730. {
  7731. return 2;
  7732. }
  7733. ULONG CDeskTray::Release()
  7734. {
  7735. return 1;
  7736. }
  7737. HRESULT CDeskTray::GetTrayWindow(HWND* phwndTray)
  7738. {
  7739. ASSERT(_ptray->_hwnd);
  7740. *phwndTray = _ptray->_hwnd;
  7741. return S_OK;
  7742. }
  7743. HRESULT CDeskTray::SetDesktopWindow(HWND hwndDesktop)
  7744. {
  7745. ASSERT(v_hwndDesktop == NULL);
  7746. v_hwndDesktop = hwndDesktop;
  7747. return S_OK;
  7748. }
  7749. UINT CDeskTray::AppBarGetState()
  7750. {
  7751. return (_ptray->_uAutoHide ? ABS_AUTOHIDE : 0) |
  7752. (_ptray->_fAlwaysOnTop ? ABS_ALWAYSONTOP : 0);
  7753. }
  7754. //*** CDeskTray::SetVar -- set an explorer variable (var#i := value)
  7755. // ENTRY/EXIT
  7756. // var id# of variable to be changed
  7757. // value value to be assigned
  7758. // NOTES
  7759. // WARNING: thread safety is up to caller!
  7760. // notes: currently only called in 1 place, but extra generality is cheap
  7761. // minimal cost
  7762. HRESULT CDeskTray::SetVar(int var, DWORD value)
  7763. {
  7764. extern BOOL g_fExitExplorer;
  7765. TraceMsg(DM_TRACE, "c.cdt_sv: set var(%d):=%d", var, value);
  7766. switch (var) {
  7767. case SVTRAY_EXITEXPLORER:
  7768. TraceMsg(DM_TRACE, "c.cdt_sv: set g_fExitExplorer:=%d", value);
  7769. g_fExitExplorer = value;
  7770. WriteCleanShutdown(1);
  7771. break;
  7772. default:
  7773. ASSERT(0);
  7774. return S_FALSE;
  7775. }
  7776. return S_OK;
  7777. }