Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

820 lines
27 KiB

  1. #include "cabinet.h"
  2. #include "traycmn.h"
  3. #include "trayreg.h"
  4. #include "trayitem.h"
  5. #include "shellapi.h"
  6. #include "util.h"
  7. #include "strsafe.h"
  8. BOOL CTrayItemRegistry::_DestroyIconInfoCB(TNPersistStreamData * pData, LPVOID pData2)
  9. {
  10. delete [] pData;
  11. return TRUE;
  12. }
  13. void CTrayItemRegistry::_QueryRegValue(HKEY hkey, LPTSTR pszValue, ULONG* puVal, ULONG uDefault, DWORD dwValSize)
  14. {
  15. if (hkey)
  16. {
  17. DWORD dwSize = dwValSize;
  18. if (ERROR_SUCCESS != RegQueryValueEx(hkey, pszValue, NULL, NULL, (LPBYTE) puVal, &dwSize))
  19. *puVal = uDefault;
  20. }
  21. }
  22. void CTrayItemRegistry::IncChevronInfoTipShownInRegistry(BOOL bUserClickedInfoTip/*=FALSE*/)
  23. {
  24. HKEY hKey = NULL;
  25. if (_bShowChevronInfoTip)
  26. {
  27. if (bUserClickedInfoTip)
  28. {
  29. // If the user has clicked the info tip, do not show it in subsequent
  30. // sessions...
  31. _dwTimesChevronInfoTipShown = MAX_CHEVRON_INFOTIP_SHOWN;
  32. }
  33. else
  34. {
  35. _dwTimesChevronInfoTipShown ++;
  36. }
  37. if ( (_dwTimesChevronInfoTipShown <= MAX_CHEVRON_INFOTIP_SHOWN) &&
  38. (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, SZ_TRAYNOTIFY_REGKEY, 0, KEY_WRITE, &hKey)) )
  39. {
  40. RegSetValueEx(hKey, SZ_INFOTIP_REGVALUE, 0, REG_DWORD,
  41. (LPBYTE) &_dwTimesChevronInfoTipShown, sizeof(DWORD));
  42. RegCloseKey(hKey);
  43. }
  44. }
  45. // The chevron infotip can be shown only once per session...
  46. _bShowChevronInfoTip = FALSE;
  47. }
  48. void CTrayItemRegistry::InitRegistryValues(UINT uIconListFlags)
  49. {
  50. HKEY hkeyTrayNotify = NULL;
  51. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, SZ_TRAYNOTIFY_REGKEY, 0, KEY_QUERY_VALUE, &hkeyTrayNotify))
  52. {
  53. // Load the countdown interval for the items when added to the tray
  54. _QueryRegValue(hkeyTrayNotify, SZ_ICON_COUNTDOWN_VALUE, &_uPrimaryCountdown, TT_ICON_COUNTDOWN_INTERVAL,
  55. sizeof(DWORD));
  56. // The length of time for which an item can reside in the past items tray, from
  57. // when it was last used...
  58. _QueryRegValue(hkeyTrayNotify, SZ_ICONCLEANUP_VALUE, &_uValidLastUseTimePeriod, TT_ICONCLEANUP_INTERVAL,
  59. sizeof(DWORD));
  60. // The number of times the chevron info tip has been shown...
  61. // - assume that it hasnt been shown before...
  62. _QueryRegValue(hkeyTrayNotify, SZ_INFOTIP_REGVALUE, &_dwTimesChevronInfoTipShown, 0, sizeof(DWORD));
  63. if (_dwTimesChevronInfoTipShown < MAX_CHEVRON_INFOTIP_SHOWN)
  64. _bShowChevronInfoTip = TRUE;
  65. else
  66. _bShowChevronInfoTip = FALSE;
  67. // The ticking interval for the internal timers for CUserEventTimer, when the
  68. // CUserEventTimer counts the time for which the item is resident in the tray
  69. _QueryRegValue(hkeyTrayNotify, SZ_ICONDEMOTE_TIMER_TICK_VALUE, &_uIconDemoteTimerTickInterval,
  70. UET_ICONDEMOTE_TIMER_TICK_INTERVAL, sizeof(ULONG));
  71. // The ticking interval for the internal timers for CUserEventTimer, when the
  72. // CUserEventTimer counts the time for which the balloon tips show on an item in
  73. // the tray
  74. _QueryRegValue(hkeyTrayNotify, SZ_INFOTIP_TIMER_TICK_VALUE, &_uInfoTipTimerTickInterval,
  75. UET_INFOTIP_TIMER_TICK_INTERVAL, sizeof(ULONG));
  76. RegCloseKey(hkeyTrayNotify);
  77. }
  78. else
  79. {
  80. _uPrimaryCountdown = TT_ICON_COUNTDOWN_INTERVAL;
  81. _uValidLastUseTimePeriod = TT_ICONCLEANUP_INTERVAL;
  82. _dwTimesChevronInfoTipShown = 0;
  83. _bShowChevronInfoTip = TRUE;
  84. _uIconDemoteTimerTickInterval = UET_ICONDEMOTE_TIMER_TICK_INTERVAL;
  85. _uInfoTipTimerTickInterval = UET_INFOTIP_TIMER_TICK_INTERVAL;
  86. }
  87. // Is the automatic tray (the new Whistler tray feature) enabled ?
  88. _fNoAutoTrayPolicyEnabled = (SHRestricted(REST_NOAUTOTRAYNOTIFY) != 0);
  89. _fAutoTrayEnabledByUser = _IsAutoTrayEnabledInRegistry();
  90. // Load the icon info from the previous session...
  91. InitTrayItemStream(STGM_READ, NULL, NULL);
  92. if (!_himlPastItemsIconList)
  93. {
  94. _himlPastItemsIconList = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
  95. uIconListFlags, 0, 1);
  96. }
  97. }
  98. UINT CTrayItemRegistry::GetTimerTickInterval(int nTimerFlag)
  99. {
  100. switch(nTimerFlag)
  101. {
  102. case TF_ICONDEMOTE_TIMER:
  103. return (UINT) _uIconDemoteTimerTickInterval;
  104. case TF_INFOTIP_TIMER:
  105. return (UINT) _uInfoTipTimerTickInterval;
  106. }
  107. ASSERT(FALSE);
  108. return 0;
  109. }
  110. void CTrayItemRegistry::InitTrayItemStream(DWORD dwStreamMode,
  111. PFNTRAYNOTIFYCALLBACK pfnTrayNotifyCB, void *pCBData)
  112. {
  113. BOOL bDeleteIconStreamRegValue = FALSE;
  114. IStream * pStream = SHOpenRegStream( HKEY_CURRENT_USER,
  115. SZ_TRAYNOTIFY_REGKEY,
  116. SZ_ITEMSTREAMS_REGVALUE,
  117. dwStreamMode );
  118. if (pStream && SUCCEEDED(IStream_Reset(pStream)))
  119. {
  120. if (dwStreamMode == STGM_READ)
  121. {
  122. _LoadTrayItemStream(pStream, pfnTrayNotifyCB, pCBData);
  123. }
  124. else
  125. {
  126. ASSERT(dwStreamMode == STGM_WRITE);
  127. if (FAILED(_SaveTrayItemStream(pStream, pfnTrayNotifyCB, pCBData)))
  128. bDeleteIconStreamRegValue = TRUE;
  129. }
  130. pStream->Release();
  131. }
  132. if (bDeleteIconStreamRegValue)
  133. {
  134. HKEY hKey;
  135. if (RegOpenKeyEx(HKEY_CURRENT_USER, SZ_TRAYNOTIFY_REGKEY, 0, KEY_WRITE, &hKey) == ERROR_SUCCESS)
  136. {
  137. ASSERT(hKey);
  138. RegDeleteValue(hKey, SZ_ITEMSTREAMS_REGVALUE);
  139. RegCloseKey(hKey);
  140. }
  141. }
  142. }
  143. BOOL CTrayItemRegistry::_LoadIconsFromRegStream(DWORD dwItemStreamSignature)
  144. {
  145. ASSERT(_himlPastItemsIconList == NULL);
  146. IStream * pStream = SHOpenRegStream( HKEY_CURRENT_USER,
  147. SZ_TRAYNOTIFY_REGKEY,
  148. SZ_ICONSTREAMS_REGVALUE,
  149. STGM_READ );
  150. if (pStream)
  151. {
  152. TNPersistentIconStreamHeader tnPISH = {0};
  153. if (SUCCEEDED(IStream_Read(pStream, &tnPISH, sizeof(TNPersistentIconStreamHeader))))
  154. {
  155. if ( (tnPISH.dwSize == sizeof(TNPersistentIconStreamHeader)) &&
  156. (_IsValidStreamHeaderVersion(tnPISH.dwVersion)) &&
  157. (tnPISH.dwSignature == dwItemStreamSignature) &&
  158. (tnPISH.cIcons > 0) )
  159. {
  160. LARGE_INTEGER c_li0 = { 0, 0 };
  161. c_li0.LowPart = tnPISH.dwOffset;
  162. if (S_OK == pStream->Seek(c_li0, STREAM_SEEK_SET, NULL))
  163. {
  164. _himlPastItemsIconList = ImageList_Read(pStream);
  165. }
  166. }
  167. }
  168. pStream->Release();
  169. }
  170. return (_himlPastItemsIconList != NULL);
  171. }
  172. HRESULT CTrayItemRegistry::_LoadTrayItemStream(IStream *pstm, PFNTRAYNOTIFYCALLBACK pfnTrayNotifyCB,
  173. void *pCBData)
  174. {
  175. HRESULT hr;
  176. TNPersistStreamHeader persStmHeader = {0};
  177. ASSERT(pstm);
  178. hr = IStream_Read(pstm, &persStmHeader, sizeof(persStmHeader));
  179. if (SUCCEEDED(hr))
  180. {
  181. if ( (persStmHeader.dwSize != sizeof(TNPersistStreamHeader)) ||
  182. (!_IsValidStreamHeaderVersion(persStmHeader.dwVersion)) ||
  183. (persStmHeader.dwSignature != TNH_SIGNATURE) ||
  184. (persStmHeader.cIcons <= 0) )
  185. {
  186. return E_FAIL;
  187. }
  188. LARGE_INTEGER c_li0 = { 0, 0 };
  189. c_li0.LowPart = persStmHeader.dwOffset;
  190. if (S_OK == (hr = pstm->Seek(c_li0, STREAM_SEEK_SET, NULL)))
  191. {
  192. if (!_dpaPersistentItemInfo)
  193. {
  194. if (!_dpaPersistentItemInfo.Create(10))
  195. return E_FAIL;
  196. }
  197. ASSERT( (persStmHeader.dwVersion != TNH_VERSION_ONE) &&
  198. (persStmHeader.dwVersion != TNH_VERSION_TWO) &&
  199. (persStmHeader.dwVersion != TNH_VERSION_THREE) );
  200. for (int i = 0; i < (int)(persStmHeader.cIcons); ++i)
  201. {
  202. TNPersistStreamData * ptnpd = new TNPersistStreamData;
  203. if (ptnpd)
  204. {
  205. hr = IStream_Read(pstm, ptnpd, _SizeOfPersistStreamData(persStmHeader.dwVersion));
  206. if (SUCCEEDED(hr))
  207. {
  208. if (persStmHeader.dwVersion == TNH_VERSION_FOUR)
  209. {
  210. ptnpd->guidItem = GUID_NULL;
  211. }
  212. }
  213. if (FAILED(hr) || (_dpaPersistentItemInfo.AppendPtr(ptnpd) == -1))
  214. {
  215. delete (ptnpd);
  216. _dpaPersistentItemInfo.DestroyCallback(_DestroyIconInfoCB, NULL);
  217. _DestroyPastItemsIconList();
  218. hr = E_FAIL;
  219. break;
  220. }
  221. }
  222. else
  223. {
  224. _dpaPersistentItemInfo.DestroyCallback(_DestroyIconInfoCB, NULL);
  225. _DestroyPastItemsIconList();
  226. hr = E_OUTOFMEMORY;
  227. break;
  228. }
  229. }
  230. if (SUCCEEDED(hr))
  231. {
  232. if (!_LoadIconsFromRegStream(persStmHeader.dwSignature))
  233. {
  234. if (_dpaPersistentItemInfo)
  235. {
  236. for (int i = _dpaPersistentItemInfo.GetPtrCount()-1; i >= 0; i--)
  237. {
  238. (_dpaPersistentItemInfo.GetPtr(i))->nImageIndex = INVALID_IMAGE_INDEX;
  239. }
  240. }
  241. }
  242. }
  243. }
  244. }
  245. return hr;
  246. }
  247. // TO DO : 1. Maybe we can avoid 2 stream writes of the header, maybe a seek will work directly
  248. // 2. If failed, dont store anything, esp. avoid 2 writes
  249. HRESULT CTrayItemRegistry::_SaveTrayItemStream(IStream *pstm, PFNTRAYNOTIFYCALLBACK pfnTrayNotifyCB,
  250. void *pCBData)
  251. {
  252. HRESULT hr;
  253. DWORD nWrittenIcons = 0;
  254. TNPersistStreamHeader persStmHeader;
  255. persStmHeader.dwSize = sizeof(TNPersistStreamHeader);
  256. persStmHeader.dwVersion = TNH_VERSION_FIVE;
  257. persStmHeader.dwSignature = TNH_SIGNATURE;
  258. // The Bang Icon(s) dont count...
  259. persStmHeader.cIcons = 0;
  260. persStmHeader.dwOffset = persStmHeader.dwSize;
  261. hr = IStream_Write(pstm, &persStmHeader, sizeof(persStmHeader));
  262. if (SUCCEEDED(hr))
  263. {
  264. // Write the icons in the current session...
  265. // Since the icons are added to the front of the tray toolbar, the icons
  266. // in the front of the tray are the ones that have been added last. So
  267. // maintain this order in writing the icon data into the stream.
  268. INT_PTR i = 0;
  269. CTrayItem * pti = NULL;
  270. HICON hIcon = NULL;
  271. do
  272. {
  273. TRAYCBRET trayCBRet = {0};
  274. pti = NULL;
  275. hIcon = NULL;
  276. if (pfnTrayNotifyCB(i, pCBData, TRAYCBARG_ALL, &trayCBRet))
  277. {
  278. pti = trayCBRet.pti;
  279. hIcon = trayCBRet.hIcon;
  280. if (pti && pti->ShouldSaveIcon())
  281. {
  282. int nPastSessionIndex = DoesIconExistFromPreviousSession(pti,
  283. pti->szIconText, hIcon);
  284. if (nPastSessionIndex != -1)
  285. {
  286. DeletePastItem(nPastSessionIndex);
  287. }
  288. TNPersistStreamData tnPersistData = {0};
  289. if (_FillPersistData(&tnPersistData, pti, trayCBRet.hIcon))
  290. {
  291. if (SUCCEEDED(hr = IStream_Write(pstm, &tnPersistData, sizeof(tnPersistData))))
  292. {
  293. nWrittenIcons ++;
  294. }
  295. else
  296. {
  297. // If we failed to store the item, then remove its corresponding icon
  298. // from the icon image list...
  299. // Since this icon was appended to the end of the list, and we remove it
  300. // we dont need to update all the other item image indices, as they will
  301. // not be affected...
  302. ImageList_Remove(_himlPastItemsIconList, (INT) i);
  303. }
  304. }
  305. }
  306. if (hIcon)
  307. DestroyIcon(hIcon);
  308. }
  309. else
  310. {
  311. break;
  312. }
  313. i++;
  314. }
  315. while (TRUE);
  316. // Write out the icons from the previous sessions..
  317. if (_dpaPersistentItemInfo)
  318. {
  319. INT_PTR nIcons = _dpaPersistentItemInfo.GetPtrCount();
  320. for (i = 0; i < nIcons; i++)
  321. {
  322. TNPersistStreamData * ptnpd = _dpaPersistentItemInfo.GetPtr(i);
  323. ASSERT(ptnpd);
  324. BOOL bWritten = FALSE;
  325. if (_IsIconLastUseValid(ptnpd->wYear, ptnpd->wMonth))
  326. {
  327. if (SUCCEEDED(hr = IStream_Write(pstm, ptnpd, sizeof(TNPersistStreamData))))
  328. {
  329. nWrittenIcons++;
  330. bWritten = TRUE;
  331. }
  332. }
  333. if (!bWritten)
  334. {
  335. if (ImageList_Remove(_himlPastItemsIconList, (INT) i))
  336. UpdateImageIndices(i);
  337. }
  338. }
  339. }
  340. }
  341. if (nWrittenIcons <= 0)
  342. return E_FAIL;
  343. else
  344. {
  345. _SaveIconsToRegStream();
  346. }
  347. if (FAILED(hr) || nWrittenIcons > 0)
  348. {
  349. persStmHeader.cIcons = nWrittenIcons;
  350. if (SUCCEEDED(hr = IStream_Reset(pstm)))
  351. hr = IStream_Write(pstm, &persStmHeader, sizeof(persStmHeader));
  352. }
  353. return hr;
  354. }
  355. void CTrayItemRegistry::UpdateImageIndices(INT_PTR nDeletedImageIndex)
  356. {
  357. if (!_dpaPersistentItemInfo)
  358. return;
  359. INT_PTR nPastItemCount = _dpaPersistentItemInfo.GetPtrCount();
  360. for (INT_PTR i = 0; i < nPastItemCount; i++)
  361. {
  362. TNPersistStreamData * ptnpd = _dpaPersistentItemInfo.GetPtr(i);
  363. if (ptnpd)
  364. {
  365. if (ptnpd->nImageIndex > nDeletedImageIndex)
  366. {
  367. ptnpd->nImageIndex --;
  368. }
  369. else if (ptnpd->nImageIndex == nDeletedImageIndex)
  370. {
  371. ptnpd->nImageIndex = INVALID_IMAGE_INDEX;
  372. }
  373. }
  374. }
  375. }
  376. BOOL CTrayItemRegistry::_SaveIconsToRegStream()
  377. {
  378. BOOL bStreamWritten = FALSE;
  379. if (_himlPastItemsIconList)
  380. {
  381. IStream * pStream = SHOpenRegStream( HKEY_CURRENT_USER,
  382. SZ_TRAYNOTIFY_REGKEY,
  383. SZ_ICONSTREAMS_REGVALUE,
  384. STGM_WRITE );
  385. if (pStream)
  386. {
  387. TNPersistentIconStreamHeader tnPISH = {0};
  388. tnPISH.dwSize = sizeof(TNPersistentIconStreamHeader);
  389. tnPISH.dwVersion = TNH_VERSION_FIVE;
  390. tnPISH.dwSignature = TNH_SIGNATURE;
  391. tnPISH.cIcons = ImageList_GetImageCount(_himlPastItemsIconList);
  392. tnPISH.dwOffset = tnPISH.dwSize;
  393. if (tnPISH.cIcons > 0)
  394. {
  395. if (SUCCEEDED(IStream_Write(pStream, &tnPISH, sizeof(TNPersistentIconStreamHeader))))
  396. {
  397. if (ImageList_Write(_himlPastItemsIconList, pStream))
  398. {
  399. bStreamWritten = TRUE;
  400. }
  401. }
  402. }
  403. pStream->Release();
  404. }
  405. }
  406. if (!bStreamWritten)
  407. {
  408. HKEY hKey;
  409. if (RegOpenKeyEx(HKEY_CURRENT_USER, SZ_TRAYNOTIFY_REGKEY, 0, KEY_WRITE, &hKey) == ERROR_SUCCESS)
  410. {
  411. ASSERT(hKey);
  412. RegDeleteValue(hKey, SZ_ICONSTREAMS_REGVALUE);
  413. RegCloseKey(hKey);
  414. }
  415. }
  416. return bStreamWritten;
  417. }
  418. BOOL CTrayItemRegistry::_IsIconLastUseValid(WORD wYear, WORD wMonth)
  419. {
  420. SYSTEMTIME currentTime = {0};
  421. GetLocalTime(&currentTime);
  422. ULONG nCount = 0;
  423. // wYear/wMonth CANNOT be greater than currentTime.wYear/currentTime.wMonth
  424. while (nCount < _uValidLastUseTimePeriod)
  425. {
  426. if (wYear == currentTime.wYear && wMonth == currentTime.wMonth)
  427. break;
  428. wMonth++;
  429. if (wMonth > 12)
  430. {
  431. wYear ++;
  432. wMonth = 1;
  433. }
  434. nCount++;
  435. }
  436. return (nCount < _uValidLastUseTimePeriod);
  437. }
  438. BOOL CTrayItemRegistry::_IsAutoTrayEnabledInRegistry()
  439. {
  440. return (SHRegGetBoolUSValue(SZ_EXPLORER_REGKEY, SZ_AUTOTRAY_REGVALUE, FALSE, TRUE));
  441. }
  442. BOOL CTrayItemRegistry::SetIsAutoTrayEnabledInRegistry(BOOL bAutoTray)
  443. {
  444. HKEY hKey;
  445. ASSERT(!_fNoAutoTrayPolicyEnabled);
  446. if (_fAutoTrayEnabledByUser != bAutoTray)
  447. {
  448. _fAutoTrayEnabledByUser = bAutoTray;
  449. DWORD dwAutoTray = (bAutoTray ? 1 : 0);
  450. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, SZ_EXPLORER_REGKEY, 0, KEY_WRITE, &hKey))
  451. {
  452. RegSetValueEx(hKey, SZ_AUTOTRAY_REGVALUE, 0, REG_DWORD, (LPBYTE) &dwAutoTray, sizeof(DWORD));
  453. RegCloseKey(hKey);
  454. }
  455. return TRUE;
  456. }
  457. return FALSE;
  458. }
  459. INT_PTR CTrayItemRegistry::CheckAndRestorePersistentIconSettings (
  460. CTrayItem * pti,
  461. LPTSTR pszIconToolTip,
  462. HICON hIcon
  463. )
  464. {
  465. // If we have icon information from the previous session..
  466. int i = -1;
  467. if (_dpaPersistentItemInfo)
  468. {
  469. i = DoesIconExistFromPreviousSession(pti, pszIconToolTip, hIcon);
  470. if (i != -1)
  471. {
  472. ASSERT(i >= 0 && i < _dpaPersistentItemInfo.GetPtrCount());
  473. TNPersistStreamData * ptnpd = _dpaPersistentItemInfo.GetPtr(i);
  474. ASSERT(ptnpd);
  475. _RestorePersistentIconSettings(ptnpd, pti);
  476. return i;
  477. }
  478. }
  479. return (-1);
  480. }
  481. //
  482. // Since we have already taken the previous-session info for this icon,
  483. // there is no need to hold it in our HDPA array...
  484. //
  485. void CTrayItemRegistry::DeletePastItem(INT_PTR nIndex)
  486. {
  487. if (nIndex != -1)
  488. {
  489. ASSERT((nIndex >= 0) && (nIndex < _dpaPersistentItemInfo.GetPtrCount()));
  490. TNPersistStreamData * ptnpd = _dpaPersistentItemInfo.GetPtr(nIndex);
  491. if (ptnpd)
  492. {
  493. if (_himlPastItemsIconList && (ptnpd->nImageIndex != INVALID_IMAGE_INDEX))
  494. {
  495. if (ImageList_Remove(_himlPastItemsIconList, ptnpd->nImageIndex))
  496. UpdateImageIndices(ptnpd->nImageIndex);
  497. }
  498. delete(ptnpd);
  499. }
  500. _dpaPersistentItemInfo.DeletePtr((int)nIndex);
  501. }
  502. }
  503. void CTrayItemRegistry::_RestorePersistentIconSettings(TNPersistStreamData * ptnpd, CTrayItem * pti)
  504. {
  505. ASSERT(ptnpd);
  506. pti->SetDemoted(ptnpd->bDemoted);
  507. pti->dwUserPref = ptnpd->dwUserPref;
  508. // if (NULL == lstrcpyn(pti->szExeName, ptnpd->szExeName, lstrlen(ptnpd->szExeName)+1))
  509. // pti->szExeName[0] = '\0';
  510. if (pti->IsStartupIcon())
  511. {
  512. if (ptnpd->bStartupIcon)
  513. {
  514. pti->uNumSeconds = ptnpd->uNumSeconds;
  515. #define MAX_NUM_SECONDS_VALUE TT_ICON_COUNTDOWN_INTERVAL/1000
  516. #define NUM_SECONDS_THRESHOLD 30
  517. if (ptnpd->uNumSeconds > MAX_NUM_SECONDS_VALUE - NUM_SECONDS_THRESHOLD)
  518. pti->uNumSeconds = MAX_NUM_SECONDS_VALUE - NUM_SECONDS_THRESHOLD;
  519. }
  520. else
  521. // If it wasnt a startup icon in the previous session, then dont take the acculumated time
  522. pti->uNumSeconds = 0;
  523. }
  524. // If it is not a startup icon, the accumulated time doesnt matter
  525. }
  526. int CTrayItemRegistry::DoesIconExistFromPreviousSession (
  527. CTrayItem * pti,
  528. LPTSTR pszIconToolTip,
  529. HICON hIcon
  530. )
  531. {
  532. ASSERT(pti);
  533. if (!_dpaPersistentItemInfo)
  534. return -1;
  535. if (pti->szExeName)
  536. {
  537. for (int i = 0; i < _dpaPersistentItemInfo.GetPtrCount(); i++)
  538. {
  539. TNPersistStreamData * ptnpd = _dpaPersistentItemInfo.GetPtr(i);
  540. ASSERT(ptnpd);
  541. if (lstrcmpi(pti->szExeName, ptnpd->szExeName) == 0)
  542. {
  543. if (ptnpd->uID == pti->uID)
  544. return i;
  545. if (hIcon)
  546. {
  547. HICON hIconNew = DuplicateIcon(NULL, hIcon);
  548. HICON hIconOld = NULL;
  549. if (ptnpd->nImageIndex != INVALID_IMAGE_INDEX)
  550. hIconOld = ImageList_GetIcon(_himlPastItemsIconList, ptnpd->nImageIndex, ILD_NORMAL);
  551. BOOL bRet = FALSE;
  552. if (hIconNew && hIconOld)
  553. {
  554. bRet = SHAreIconsEqual(hIconNew, hIconOld);
  555. }
  556. if (hIconNew)
  557. DestroyIcon(hIconNew);
  558. if (hIconOld)
  559. DestroyIcon(hIconOld);
  560. if (bRet)
  561. return i;
  562. }
  563. // We need to check this case for animating icons. We do not know
  564. // which icon is showing at the moment the item was deleted from the
  565. // tray.
  566. // For instance, in the "Network Connections" item, any of 3
  567. // "animating" icons could be showing when the item was deleted from
  568. // the tray. In this case, the SHAreIconsEqual check (between the
  569. // Past icon and the current icon) will fail, still the icons
  570. // represent the same item.
  571. // There is *no* sure way to catch this case. Adding a tooltip check
  572. // would strengthen our check. If the two icons have the same tooltip
  573. // text (till the '\n'), then they will be eliminated.
  574. // Of course, if an exe placed two icons in the tray, and gave them
  575. // different IDs but the same tooltip, then one of them will be deemed
  576. // to be a dupe of the other. But an app shouldnt be placing two icons
  577. // on the tray if their tips are different.
  578. if (pszIconToolTip)
  579. {
  580. LPTSTR szTemp = NULL;
  581. int nCharToCompare = lstrlen(pszIconToolTip);
  582. if ((szTemp = StrChr(pszIconToolTip, (TCHAR)'\n')) != NULL)
  583. {
  584. nCharToCompare = szTemp-pszIconToolTip;
  585. }
  586. if (StrCmpNI(pszIconToolTip, ptnpd->szIconText, nCharToCompare) == 0)
  587. return i;
  588. }
  589. }
  590. }
  591. }
  592. return -1;
  593. }
  594. // Returns TRUE to indicate the function succeeded, fails only if the index is invalid
  595. // *pbStat is set to TRUE if pni is filled in, FALSE if pni is not filled in. pni might
  596. // not be filled in, if the item specified by index doesnt meet specific criteria.
  597. BOOL CTrayItemRegistry::GetTrayItem(INT_PTR nIndex, CNotificationItem * pni, BOOL * pbStat)
  598. {
  599. if (!_dpaPersistentItemInfo || (nIndex < 0) || (nIndex >= _dpaPersistentItemInfo.GetPtrCount()))
  600. {
  601. *pbStat = FALSE;
  602. return FALSE;
  603. }
  604. TNPersistStreamData * ptnpd = _dpaPersistentItemInfo.GetPtr(nIndex);
  605. if (ptnpd && _IsIconLastUseValid(ptnpd->wYear, ptnpd->wMonth))
  606. {
  607. *pni = ptnpd; // C++ magic...
  608. if (ptnpd->nImageIndex != INVALID_IMAGE_INDEX)
  609. pni->hIcon = ImageList_GetIcon(_himlPastItemsIconList, ptnpd->nImageIndex, ILD_NORMAL);
  610. *pbStat = TRUE;
  611. return TRUE;
  612. }
  613. *pbStat = FALSE;
  614. return TRUE;
  615. }
  616. BOOL CTrayItemRegistry::SetPastItemPreference(LPNOTIFYITEM pNotifyItem)
  617. {
  618. if (_dpaPersistentItemInfo && pNotifyItem->pszExeName[0] != 0)
  619. {
  620. for (INT_PTR i = _dpaPersistentItemInfo.GetPtrCount()-1; i >= 0; --i)
  621. {
  622. TNPersistStreamData * ptnpd = _dpaPersistentItemInfo.GetPtr(i);
  623. if (ptnpd && ptnpd->uID == pNotifyItem->uID &&
  624. lstrcmpi(ptnpd->szExeName, pNotifyItem->pszExeName) == 0)
  625. {
  626. ptnpd->dwUserPref = pNotifyItem->dwUserPref;
  627. return TRUE;
  628. }
  629. }
  630. }
  631. return FALSE;
  632. }
  633. BOOL CTrayItemRegistry::AddToPastItems(CTrayItem * pti, HICON hIcon)
  634. {
  635. if (!_dpaPersistentItemInfo)
  636. _dpaPersistentItemInfo.Create(10);
  637. if (_dpaPersistentItemInfo)
  638. {
  639. TNPersistStreamData * ptnPersistData = new TNPersistStreamData;
  640. if (ptnPersistData)
  641. {
  642. if (_FillPersistData(ptnPersistData, pti, hIcon))
  643. {
  644. if (_dpaPersistentItemInfo.InsertPtr(0, ptnPersistData) != -1)
  645. {
  646. return TRUE;
  647. }
  648. }
  649. delete(ptnPersistData);
  650. }
  651. }
  652. return FALSE;
  653. }
  654. BOOL CTrayItemRegistry::_FillPersistData(TNPersistStreamData * ptnPersistData, CTrayItem * pti, HICON hIcon)
  655. {
  656. SYSTEMTIME currentTime = {0};
  657. GetLocalTime(&currentTime);
  658. if (SUCCEEDED(StringCchCopy(ptnPersistData->szExeName, ARRAYSIZE(ptnPersistData->szExeName), pti->szExeName)))
  659. {
  660. ptnPersistData->uID = pti->uID;
  661. ptnPersistData->bDemoted = pti->IsDemoted();
  662. ptnPersistData->dwUserPref = pti->dwUserPref;
  663. ptnPersistData->wYear = currentTime.wYear;
  664. ptnPersistData->wMonth = currentTime.wMonth;
  665. ptnPersistData->bStartupIcon = pti->IsStartupIcon();
  666. ptnPersistData->nImageIndex = _AddPastIcon(-1, hIcon);
  667. memcpy(&(ptnPersistData->guidItem), &(pti->guidItem), sizeof(pti->guidItem));
  668. StringCchCopy(ptnPersistData->szIconText, ARRAYSIZE(ptnPersistData->szIconText), pti->szIconText);
  669. if (pti->IsStartupIcon())
  670. {
  671. ptnPersistData->uNumSeconds = pti->uNumSeconds;
  672. }
  673. return TRUE;
  674. }
  675. return FALSE;
  676. }
  677. UINT_PTR CTrayItemRegistry::_SizeOfPersistStreamData(DWORD dwVersion)
  678. {
  679. ASSERT((dwVersion == TNH_VERSION_FOUR) || (dwVersion == TNH_VERSION_FIVE));
  680. if (dwVersion == TNH_VERSION_FOUR)
  681. return FIELD_OFFSET(TNPersistStreamData, guidItem);
  682. return sizeof(TNPersistStreamData);
  683. }