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.

1399 lines
39 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997
  5. //
  6. // File: trayagnt.cpp
  7. //
  8. // Contents: tray notification agent
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 01-14-1997 rayen (Raymond Endres) Created
  15. //
  16. //----------------------------------------------------------------------------
  17. #include "private.h"
  18. #include "updateui.h"
  19. #include "chanmgr.h"
  20. #include "chanmgrp.h"
  21. #include "shguidp.h"
  22. #include "offline.h"
  23. #include "offl_cpp.h"
  24. //xnotfmgr - can probably nuke most of this file
  25. #undef TF_THISMODULE
  26. #define TF_THISMODULE TF_TRAYAGENT
  27. extern const TCHAR c_szTrayUI[] = TEXT("BogusClassName");
  28. const TCHAR c_szTrayMenu[] = TEXT("TrayMenu");
  29. #if WANT_REGISTRY_LOG
  30. const TCHAR c_szLog[] = TEXT("\\Log");
  31. const TCHAR c_szLogMaxIndex[] = TEXT("MaxIndex");
  32. #endif
  33. typedef struct _tagCHANNELIMAGEDATA
  34. {
  35. CHAR szPath[MAX_PATH];
  36. CHAR szHash[MAX_PATH];
  37. int iIndex;
  38. UINT uFlags;
  39. int iImageIndex;
  40. } CHANNELIMAGEDATA, *PCHANNELIMAGEDATA;
  41. CTrayUI *g_pTrayUI; // TrayUI object (not COM), separate from TrayAgent for now
  42. DWORD WINAPI UpdateRequest(UINT idCmd, INotification *);
  43. HRESULT UpdateNotifyReboot(void);
  44. extern BOOL OnConnectedNotification(void);
  45. extern BOOL OnDisconnectedNotification(void);
  46. extern HRESULT LoadWithCookie(LPCTSTR, OOEBuf *, DWORD *, SUBSCRIPTIONCOOKIE *);
  47. void DoReboot(void);
  48. void IdleBegin(HWND hwnd);
  49. void IdleEnd(void);
  50. // Private message sent by Channel Screen Saver to
  51. // periodically initiate relaunch of the screen saver.
  52. #define WM_LOADSCREENSAVER (WM_USER+550)
  53. extern BOOL ReloadChannelScreenSaver(); // from SSSEPROX.CPP
  54. #ifdef DEBUG
  55. extern INotificationSink * g_pOfflineTraySink;
  56. HRESULT RunTest()
  57. {
  58. //xnotfmgr
  59. INotificationMgr * pMgr = NULL;
  60. INotification * pNotf = NULL;
  61. HRESULT hr;
  62. hr = GetNotificationMgr(&pMgr);
  63. if (FAILED(hr) || !pMgr)
  64. return E_FAIL;
  65. hr = pMgr->CreateNotification(
  66. NOTIFICATIONTYPE_AGENT_START,
  67. 0, NULL, &pNotf, 0);
  68. if (SUCCEEDED(hr) && !pNotf)
  69. hr = E_FAIL;
  70. if (SUCCEEDED(hr))
  71. hr = pMgr->DeliverNotification(pNotf, CLSID_WebCrawlerAgent,
  72. DM_DELIVER_DEFAULT_PROCESS |
  73. DM_THROTTLE_MODE |
  74. DM_NEED_COMPLETIONREPORT
  75. ,g_pOfflineTraySink,0,0);
  76. SAFERELEASE(pNotf);
  77. SAFERELEASE(pMgr);
  78. return hr;
  79. }
  80. #endif
  81. HRESULT CancelAllDownloads()
  82. {
  83. //xnotfmgr
  84. HRESULT hr = S_OK;
  85. INotificationMgr * pMgr = NULL;
  86. IEnumNotification * pRunEnum = NULL;
  87. IEnumNotification * pThrEnum = NULL;
  88. hr = GetNotificationMgr(&pMgr);
  89. if (FAILED(hr)) {
  90. return hr;
  91. }
  92. hr = pMgr->GetEnumNotification(EF_NOTIFICATION_INPROGRESS, &pRunEnum);
  93. if (SUCCEEDED(hr)) {
  94. hr = pMgr->GetEnumNotification(EF_NOTIFICATION_THROTTLED, &pThrEnum);
  95. }
  96. if (FAILED(hr)) {
  97. SAFERELEASE(pRunEnum);
  98. SAFERELEASE(pThrEnum);
  99. SAFERELEASE(pMgr);
  100. return hr;
  101. }
  102. INotification *pNotCancel = NULL;
  103. hr = pMgr->CreateNotification(NOTIFICATIONTYPE_TASKS_ABORT,
  104. (NOTIFICATIONFLAGS)0,
  105. NULL,
  106. &pNotCancel,
  107. 0);
  108. if (FAILED(hr) || !pNotCancel){
  109. SAFERELEASE(pMgr);
  110. SAFERELEASE(pRunEnum);
  111. SAFERELEASE(pThrEnum);
  112. return E_FAIL;
  113. }
  114. NOTIFICATIONITEM item = {0};
  115. ULONG cItems = 0;
  116. item.cbSize = sizeof(NOTIFICATIONITEM);
  117. hr = pThrEnum->Next(1, &item, &cItems);
  118. while ( SUCCEEDED(hr) && cItems )
  119. {
  120. CLSID cookie;
  121. BOOL bAbort = FALSE;
  122. if (item.NotificationType == NOTIFICATIONTYPE_AGENT_START
  123. // REVIEW big hack.
  124. && item.clsidDest != CLSID_ConnectionAgent)
  125. {
  126. bAbort = TRUE;
  127. cookie = item.NotificationCookie;
  128. }
  129. SAFERELEASE(item.pNotification);
  130. item.cbSize = sizeof(NOTIFICATIONITEM);
  131. cItems = 0;
  132. hr = pThrEnum->Next(1, &item, &cItems);
  133. // REVIEW. If we put the following statement before
  134. // the Next statement, we can delete the package and then break the
  135. // enumerator.
  136. if (bAbort) {
  137. HRESULT hr1 = pMgr->DeliverReport(pNotCancel, &cookie, 0);
  138. ASSERT(SUCCEEDED(hr1));
  139. }
  140. }
  141. cItems = 0;
  142. item.cbSize = sizeof(NOTIFICATIONITEM);
  143. hr = pRunEnum->Next(1, &item, &cItems);
  144. while ( SUCCEEDED(hr) && cItems )
  145. {
  146. CLSID cookie;
  147. BOOL bAbort = FALSE;
  148. if (item.NotificationType == NOTIFICATIONTYPE_AGENT_START
  149. // REVIEW big hack.
  150. && item.clsidDest != CLSID_ConnectionAgent)
  151. {
  152. bAbort = TRUE;
  153. cookie = item.NotificationCookie;
  154. }
  155. SAFERELEASE(item.pNotification);
  156. item.cbSize = sizeof(NOTIFICATIONITEM);
  157. cItems = 0;
  158. hr = pRunEnum->Next(1, &item, &cItems);
  159. // REVIEW. We don't seem to have the same problem. Just try to be
  160. // cautious.
  161. if (bAbort) {
  162. HRESULT hr1 = pMgr->DeliverReport(pNotCancel, &cookie, 0);
  163. ASSERT(SUCCEEDED(hr1));
  164. }
  165. }
  166. SAFERELEASE(pMgr);
  167. SAFERELEASE(pNotCancel);
  168. SAFERELEASE(pRunEnum);
  169. SAFERELEASE(pThrEnum);
  170. return hr;
  171. }
  172. //
  173. // Get the path of channel containing the given URL.
  174. //
  175. HRESULT GetChannelPath(LPCSTR pszURL, LPTSTR pszPath, int cch,
  176. IChannelMgrPriv** ppIChannelMgrPriv)
  177. {
  178. ASSERT(pszURL);
  179. ASSERT(pszPath || 0 == cch);
  180. ASSERT(ppIChannelMgrPriv);
  181. HRESULT hr;
  182. BOOL bCoinit = FALSE;
  183. hr = CoCreateInstance(CLSID_ChannelMgr, NULL, CLSCTX_INPROC_SERVER,
  184. IID_IChannelMgrPriv, (void**)ppIChannelMgrPriv);
  185. if ((hr == CO_E_NOTINITIALIZED || hr == REGDB_E_IIDNOTREG) &&
  186. SUCCEEDED(CoInitialize(NULL)))
  187. {
  188. bCoinit = TRUE;
  189. hr = CoCreateInstance(CLSID_ChannelMgr, NULL, CLSCTX_INPROC_SERVER,
  190. IID_IChannelMgrPriv, (void**)ppIChannelMgrPriv);
  191. }
  192. if (SUCCEEDED(hr))
  193. {
  194. ASSERT(*ppIChannelMgrPriv);
  195. IChannelMgr* pIChannelMgr;
  196. hr = (*ppIChannelMgrPriv)->QueryInterface(IID_IChannelMgr,
  197. (void**)&pIChannelMgr);
  198. if (SUCCEEDED(hr))
  199. {
  200. ASSERT(pIChannelMgr);
  201. WCHAR wszURL[INTERNET_MAX_URL_LENGTH];
  202. MyStrToOleStrN(wszURL, ARRAYSIZE(wszURL), pszURL);
  203. IEnumChannels* pIEnumChannels;
  204. hr = pIChannelMgr->EnumChannels(CHANENUM_ALLFOLDERS | CHANENUM_PATH,
  205. wszURL, &pIEnumChannels);
  206. if (SUCCEEDED(hr))
  207. {
  208. ASSERT(pIEnumChannels);
  209. CHANNELENUMINFO ci;
  210. if (S_OK == pIEnumChannels->Next(1, &ci, NULL))
  211. {
  212. MyOleStrToStrN(pszPath, cch, ci.pszPath);
  213. CoTaskMemFree(ci.pszPath);
  214. }
  215. else
  216. {
  217. hr = E_FAIL;
  218. }
  219. pIEnumChannels->Release();
  220. }
  221. pIChannelMgr->Release();
  222. }
  223. }
  224. if (bCoinit)
  225. CoUninitialize();
  226. ASSERT((SUCCEEDED(hr) && *ppIChannelMgrPriv) || FAILED(hr));
  227. return hr;
  228. }
  229. //
  230. // Update channel
  231. //
  232. HRESULT UpdateChannel(IChannelMgrPriv* pIChannelMgrPriv, LPCSTR pszURL)
  233. {
  234. ASSERT(pIChannelMgrPriv);
  235. ASSERT(pszURL);
  236. HRESULT hr;
  237. IChannelMgr* pIChannelMgr;
  238. hr = pIChannelMgrPriv->QueryInterface(IID_IChannelMgr,
  239. (void**)&pIChannelMgr);
  240. if (SUCCEEDED(hr))
  241. {
  242. ASSERT(pIChannelMgr);
  243. WCHAR wszURL[INTERNET_MAX_URL_LENGTH];
  244. MyStrToOleStrN(wszURL, ARRAYSIZE(wszURL), pszURL);
  245. IEnumChannels* pIEnumChannels;
  246. hr = pIChannelMgr->EnumChannels(CHANENUM_ALLFOLDERS | CHANENUM_PATH,
  247. wszURL, &pIEnumChannels);
  248. if (SUCCEEDED(hr))
  249. {
  250. ASSERT(pIEnumChannels);
  251. CHANNELENUMINFO ci;
  252. //
  253. // Update all instances of this channel.
  254. //
  255. while (S_OK == pIEnumChannels->Next(1, &ci, NULL))
  256. {
  257. char szPath[MAX_PATH];
  258. MyOleStrToStrN(szPath, ARRAYSIZE(szPath), ci.pszPath);
  259. // Removed to give UPDATEIMAGE (gleams) a better chance.
  260. //SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH, (void*)szPath,
  261. // NULL);
  262. CoTaskMemFree(ci.pszPath);
  263. }
  264. pIEnumChannels->Release();
  265. }
  266. pIChannelMgr->Release();
  267. }
  268. return hr;
  269. }
  270. //
  271. // Gather data that will be used to update a channel image.
  272. //
  273. HRESULT PreUpdateChannelImage(IChannelMgrPriv* pIChannelMgrPriv,
  274. CHANNELIMAGEDATA* pcid)
  275. {
  276. ASSERT(pcid);
  277. ASSERT(pIChannelMgrPriv);
  278. return (pIChannelMgrPriv)->PreUpdateChannelImage(pcid->szPath,
  279. pcid->szHash,
  280. &pcid->iIndex,
  281. &pcid->uFlags,
  282. &pcid->iImageIndex);
  283. }
  284. //
  285. // Update a channel image.
  286. //
  287. HRESULT UpdateChannelImage(IChannelMgrPriv* pIChannelMgrPriv,
  288. CHANNELIMAGEDATA* pcid)
  289. {
  290. ASSERT(pcid);
  291. ASSERT(pIChannelMgrPriv);
  292. WCHAR wszHash[MAX_PATH];
  293. MyStrToOleStrN(wszHash, ARRAYSIZE(wszHash), pcid->szHash);
  294. return pIChannelMgrPriv->UpdateChannelImage(wszHash, pcid->iIndex,
  295. pcid->uFlags,
  296. pcid->iImageIndex);
  297. }
  298. //----------------------------------------------------------------------------
  299. // Tray Agent object
  300. //----------------------------------------------------------------------------
  301. CTrayAgent::CTrayAgent()
  302. {
  303. DBG("Creating CTrayAgent object");
  304. //
  305. // Maintain global count of objects in webcheck.dll
  306. //
  307. DllAddRef();
  308. //
  309. // Initialize object member variables
  310. //
  311. m_cRef = 1;
  312. #ifdef DEBUG
  313. m_AptThreadId = GetCurrentThreadId();
  314. #endif
  315. }
  316. CTrayAgent::~CTrayAgent()
  317. {
  318. //
  319. // Maintain global count of objects
  320. //
  321. DllRelease();
  322. //
  323. // Release/delete any resources
  324. //
  325. DBG("Destroyed CTrayAgent object");
  326. }
  327. //
  328. // IUnknown members
  329. //
  330. STDMETHODIMP_(ULONG) CTrayAgent::AddRef(void)
  331. {
  332. return ++m_cRef;
  333. }
  334. STDMETHODIMP_(ULONG) CTrayAgent::Release(void)
  335. {
  336. if( 0L != --m_cRef )
  337. return m_cRef;
  338. delete this;
  339. return 0L;
  340. }
  341. STDMETHODIMP CTrayAgent::QueryInterface(REFIID riid, void ** ppv)
  342. {
  343. *ppv = NULL;
  344. //xnotfmgr
  345. //
  346. // Currently just support INotificationSink
  347. //
  348. if ((IID_IUnknown == riid) ||
  349. (IID_INotificationSink == riid))
  350. {
  351. *ppv = (INotificationSink *)this;
  352. }
  353. //
  354. // Addref through the interface
  355. //
  356. if( NULL != *ppv )
  357. {
  358. ((LPUNKNOWN)*ppv)->AddRef();
  359. return NOERROR;
  360. }
  361. return ResultFromScode(E_NOINTERFACE);
  362. }
  363. //
  364. // INotificationSink member(s)
  365. //
  366. STDMETHODIMP CTrayAgent::OnNotification(
  367. LPNOTIFICATION pNotification,
  368. LPNOTIFICATIONREPORT pNotificationReport,
  369. DWORD dwReserved)
  370. {
  371. //xnotfmgr
  372. DBG("CTrayAgent::OnNotification called");
  373. ASSERT(pNotification);
  374. ASSERT(GetCurrentThreadId() == m_AptThreadId);
  375. //
  376. // Extract Notification Type.
  377. //
  378. HRESULT hr;
  379. NOTIFICATIONTYPE notfType;
  380. hr = pNotification->GetNotificationInfo(&notfType, NULL, NULL, NULL, 0);
  381. ASSERT(SUCCEEDED(hr));
  382. if (notfType == NOTIFICATIONTYPE_CONFIG_CHANGED)
  383. {
  384. DBG("CTrayAgent::OnNotification - config changed");
  385. //
  386. // The global properties have changed and we must respond.
  387. //
  388. ASSERT(g_pTrayUI); // Fault here means NotificationMgr calling me in wrong process
  389. if (g_pTrayUI)
  390. g_pTrayUI->ConfigChanged();
  391. return S_OK;
  392. }
  393. else if (notfType == NOTIFICATIONTYPE_BEGIN_REPORT) {
  394. DBG("CTrayAgent::OnNotification - begin report");
  395. ASSERT(g_pTrayUI);
  396. if (g_pTrayUI)
  397. g_pTrayUI->OnBeginReport(pNotification);
  398. return S_OK;
  399. }
  400. else if (notfType == NOTIFICATIONTYPE_AGENT_START)
  401. {
  402. DBG("CTrayAgent::OnNotification - agent start (update now)");
  403. //
  404. // The user chose Update Subscriptions Now.
  405. // Is this the best notification to use for this?
  406. // Are there any properties we care about? Like a guid to trigger
  407. // a specific one?
  408. //
  409. ASSERT(g_pTrayUI); // Fault here means NotificationMgr calling me in wrong process
  410. if (g_pTrayUI)
  411. g_pTrayUI->UpdateNow(pNotification);
  412. return S_OK;
  413. }
  414. else if (notfType == NOTIFICATIONTYPE_END_REPORT)
  415. {
  416. DBG("CTrayAgent::OnNotification - end report");
  417. ASSERT(g_pTrayUI);
  418. if (g_pTrayUI)
  419. g_pTrayUI->OnEndReport(pNotification);
  420. #if WANT_REGISTRY_LOG
  421. //
  422. // Log all the End Reports
  423. //
  424. BSTR bstrStatus = NULL;
  425. CLSID cookie;
  426. if (g_pTrayUI &&
  427. SUCCEEDED(ReadBSTR(pNotification,NULL, c_szPropStatusString, &bstrStatus))
  428. && SUCCEEDED(ReadGUID(pNotification, NULL, c_szStartCookie, &cookie)))
  429. {
  430. g_pTrayUI->AddToLog(bstrStatus, CLSID_NULL, cookie);
  431. } else {
  432. DBG_WARN("CTrayAgent::OnNotification/End Report - Not status str");
  433. }
  434. SAFEFREEBSTR(bstrStatus);
  435. #endif
  436. //
  437. // Read the status code from the end report.
  438. //
  439. SCODE scEndStatus;
  440. hr = ReadSCODE(pNotification, NULL, c_szPropStatusCode, &scEndStatus);
  441. if (SUCCEEDED(hr) && SUCCEEDED(scEndStatus))
  442. {
  443. //
  444. // Special feature for desktop HTML:
  445. // If we receive an end report with "DesktopComponent=1" in it,
  446. // let the desktop know that it needs to refresh itself. We always
  447. // do this instead of only on "changes detected" because desktop
  448. // component authors don't want to change their CDFs.
  449. //
  450. DWORD dwRet;
  451. HRESULT hr2 = ReadDWORD(pNotification, NULL, c_szPropDesktopComponent, &dwRet);
  452. if (SUCCEEDED(hr2) && (dwRet == 1))
  453. {
  454. IActiveDesktop *pAD = NULL;
  455. hr2 = CoCreateInstance(CLSID_ActiveDesktop, NULL, CLSCTX_INPROC_SERVER, IID_IActiveDesktop, (void**)&pAD);
  456. DBGASSERT(SUCCEEDED(hr2), "Unable to create ActiveDesktop in order to refresh desktop component");
  457. if (SUCCEEDED(hr2))
  458. {
  459. ASSERT(pAD);
  460. pAD->ApplyChanges(AD_APPLY_FORCE | AD_APPLY_REFRESH | AD_APPLY_BUFFERED_REFRESH);
  461. pAD->Release();
  462. }
  463. }
  464. }
  465. //
  466. // If the delivery agent succeeded and changes were detected
  467. // notify the appropriate code.
  468. //
  469. if (SUCCEEDED(hr) && SUCCEEDED(scEndStatus) && (S_FALSE != scEndStatus))
  470. {
  471. //
  472. // Gleam the Internet Shortcut for the URL if requested. (EnableShortcutGleam=1)
  473. // NOTE: End Reports without changes (S_FALSE) were filtered above.
  474. //
  475. DWORD dwRet;
  476. hr = ReadDWORD(pNotification, NULL, c_szPropEnableShortcutGleam, &dwRet);
  477. if (SUCCEEDED(hr) && dwRet)
  478. {
  479. LPSTR strURL = NULL;
  480. hr = ReadAnsiSTR(pNotification, NULL, c_szPropURL, &strURL);
  481. if (SUCCEEDED(hr))
  482. {
  483. PROPVARIANT propvar;
  484. PropVariantInit(&propvar);
  485. hr = IntSiteHelper(strURL, &c_rgPropRead[PROP_FLAGS], &propvar, 1, FALSE);
  486. if (SUCCEEDED(hr) && (VT_UI4 == propvar.vt))
  487. {
  488. // Set our flag without disturbing the others.
  489. propvar.ulVal |= PIDISF_RECENTLYCHANGED;
  490. }
  491. else
  492. {
  493. // Be sure to clear the variant if it wasn't a DWORD.
  494. PropVariantClear(&propvar);
  495. propvar.vt = VT_UI4;
  496. propvar.ulVal = PIDISF_RECENTLYCHANGED;
  497. }
  498. //
  499. // Update channels.
  500. //
  501. hr = ReadDWORD(pNotification, NULL, c_szPropChannel, &dwRet);
  502. BOOL bChannel = SUCCEEDED(hr) && dwRet;
  503. CHANNELIMAGEDATA cid = {0};
  504. IChannelMgrPriv* pIChannelMgrPriv = NULL;
  505. HRESULT hr2 = E_FAIL;
  506. if (bChannel)
  507. {
  508. hr2 = GetChannelPath(strURL, cid.szPath,
  509. ARRAYSIZE(cid.szPath),
  510. &pIChannelMgrPriv);
  511. if (SUCCEEDED(hr2))
  512. hr2 = PreUpdateChannelImage(pIChannelMgrPriv, &cid);
  513. }
  514. hr = IntSiteHelper(strURL, &c_rgPropRead[PROP_FLAGS], &propvar, 1, TRUE);
  515. DBGASSERT(SUCCEEDED(hr), "CTrayAgent::OnNotification - failed to set gleam.");
  516. if (bChannel && SUCCEEDED(hr2))
  517. {
  518. ASSERT(pIChannelMgrPriv);
  519. pIChannelMgrPriv->InvalidateCdfCache();
  520. UpdateChannelImage(pIChannelMgrPriv, &cid);
  521. UpdateChannel(pIChannelMgrPriv, strURL);
  522. pIChannelMgrPriv->Release();
  523. }
  524. }
  525. MemFree(strURL); // Free the string allocated by ReadAnsiSTR().
  526. }
  527. //
  528. // Send Email to notify the user if requested (EmailNotification=1)
  529. // NOTE: End Reports without changes (S_FALSE) were filtered above.
  530. //
  531. hr = ReadDWORD(pNotification, NULL, c_szPropEmailNotf, &dwRet);
  532. if (SUCCEEDED(hr) && dwRet)
  533. {
  534. hr = SendEmailFromNotification(pNotification);
  535. }
  536. }
  537. else
  538. {
  539. DBG_WARN("CTrayAgent::OnNotification - unchanged or failed end report");
  540. }
  541. return S_OK;
  542. }
  543. else if (notfType == NOTIFICATIONTYPE_DISCONNECT_FROM_INTERNET)
  544. {
  545. OnDisconnectedNotification();
  546. return S_OK;
  547. }
  548. else if (notfType == NOTIFICATIONTYPE_CONNECT_TO_INTERNET )
  549. {
  550. OnConnectedNotification();
  551. return S_OK;
  552. }
  553. else
  554. {
  555. //
  556. // TrayAgent doesn't handle this notification
  557. //
  558. DBG("CTrayAgent::OnNotification - unknown notification");
  559. return S_OK;
  560. }
  561. }
  562. //----------------------------------------------------------------------------
  563. // TrayUI object (not COM)
  564. //----------------------------------------------------------------------------
  565. LRESULT CALLBACK TrayUI_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  566. {
  567. //xnotfmgr
  568. //
  569. // We need this annoying global to make single and double left click work nicely.
  570. // (USER should have a WM_LBUTTONSINGLECLK message.)
  571. //
  572. static int iLeftClick = 0;
  573. static POINT pt;
  574. switch (uMsg)
  575. {
  576. case WM_USER: // Subscription icon was clicked
  577. ASSERT(g_pTrayUI);
  578. switch (lParam)
  579. {
  580. #ifdef DEBUG
  581. case WM_RBUTTONUP:
  582. if (iLeftClick) {
  583. ASSERT(1 == iLeftClick);
  584. KillTimer(hwnd, TIMER_ID_DBL_CLICK);
  585. iLeftClick = 0;
  586. }
  587. GetCursorPos(&pt);
  588. g_pTrayUI->OpenContextMenu(&pt);
  589. break;
  590. case WM_LBUTTONUP:
  591. if (0 == iLeftClick) // first left click up
  592. {
  593. UINT uRet;
  594. GetCursorPos(&pt);
  595. uRet = SetTimer(hwnd, TIMER_ID_DBL_CLICK, GetDoubleClickTime(), NULL);
  596. ASSERT(uRet);
  597. iLeftClick = 1;
  598. }
  599. else // second left click up
  600. {
  601. ASSERT(1 == iLeftClick);
  602. KillTimer(hwnd, TIMER_ID_DBL_CLICK);
  603. iLeftClick = 0;
  604. g_pTrayUI->OpenSubscriptionFolder();
  605. }
  606. break;
  607. #endif
  608. case UM_NEEDREBOOT:
  609. // forward reboot required flag to update agent
  610. if (FAILED(UpdateNotifyReboot()))
  611. DoReboot();
  612. break;
  613. }
  614. return 0;
  615. case WM_TIMER:
  616. switch(wParam) {
  617. case TIMER_ID_DBL_CLICK:
  618. // Timer went off so it was a single click
  619. KillTimer(hwnd, TIMER_ID_DBL_CLICK);
  620. if (1 == iLeftClick) {
  621. iLeftClick = 0;
  622. g_pTrayUI->OpenContextMenu(&pt);
  623. }
  624. break;
  625. } /* switch */
  626. break;
  627. // Process the Infodelivery Admin Policies on WM_WININICHANGE lParam="Policy"
  628. case WM_WININICHANGE:
  629. if (lParam && !lstrcmpi((LPCTSTR)lParam, TEXT("policy")))
  630. {
  631. ProcessInfodeliveryPolicies();
  632. }
  633. // FEATURE: This should be done on Policy and another filter, not for
  634. // all changes. (The other filter hasn't been defined yet.)
  635. // TODO: handle this in the new architecture!
  636. //SetNotificationMgrRestrictions(NULL);
  637. break;
  638. case WM_LOADSCREENSAVER:
  639. {
  640. EVAL(ReloadChannelScreenSaver());
  641. break;
  642. }
  643. default:
  644. break;
  645. }
  646. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  647. }
  648. CTrayUI::CTrayUI(void)
  649. {
  650. // There should only be one of these objects
  651. ASSERT(!g_pTrayUI);
  652. // Assert that we're zero initialized.
  653. ASSERT(!m_hwnd);
  654. #if WANT_REGISTRY_LOG
  655. ASSERT(!m_cLogs);
  656. #endif
  657. ASSERT(!m_cUpdates);
  658. ASSERT(!m_fUpdatingTrayIcon);
  659. #ifdef DEBUG
  660. m_AptThreadId = GetCurrentThreadId();
  661. #endif
  662. }
  663. CTrayUI::~CTrayUI(void)
  664. {
  665. //
  666. // Clean up any BSTRs we have around
  667. //
  668. // ZDC Detect ongoing updates?
  669. ASSERT(m_cUpdates >= 0);
  670. #if WANT_REGISTRY_LOG
  671. ASSERT(m_cLogs >= 0);
  672. ASSERT(m_cLogs < TRAYUI_CLOGS);
  673. for (int i = 0; i < m_cLogs; i++)
  674. {
  675. SAFEFREEBSTR(m_aLogEntry[i].bstrStatus);
  676. }
  677. #endif
  678. }
  679. #if WANT_REGISTRY_LOG
  680. #define TRAYLOGVERSION 716
  681. STDMETHODIMP WriteSingleEntry(PLogEntry pLog, LPCTSTR szSubKey, int index)
  682. {
  683. ASSERT(pLog && szSubKey);
  684. ASSERT(index >= 0);
  685. ASSERT(index < TRAYUI_CLOGS);
  686. // Check to see if it's a valid log entry.
  687. if (!(pLog->bstrStatus)) {
  688. ASSERT(0);
  689. return E_INVALIDARG;
  690. }
  691. TCHAR szLogName[16];
  692. wsprintf(szLogName, TEXT("%d"), index);
  693. CRegStream * prLog = new CRegStream(HKEY_CURRENT_USER, szSubKey, szLogName);
  694. if (prLog) {
  695. CLSID clsidAgent = pLog->clsidAgent;
  696. CLSID cookie = pLog->startCookie;
  697. FILETIME ftLog = pLog->ftLog;
  698. int versionNumber = TRAYLOGVERSION;
  699. BSTR bstrStatus = pLog->bstrStatus;
  700. DWORD cbWritten;
  701. int len;
  702. prLog->Write(&versionNumber, sizeof(int), &cbWritten);
  703. ASSERT(sizeof(int) == cbWritten);
  704. prLog->Write(&clsidAgent, sizeof(CLSID), &cbWritten);
  705. ASSERT(sizeof(CLSID) == cbWritten);
  706. prLog->Write(&cookie, sizeof(CLSID), &cbWritten);
  707. ASSERT(sizeof(CLSID) == cbWritten);
  708. prLog->Write(&ftLog, sizeof(FILETIME), &cbWritten);
  709. ASSERT(sizeof(FILETIME) == cbWritten);
  710. len = lstrlenW(bstrStatus);
  711. prLog->Write(&len, sizeof(int), &cbWritten);
  712. ASSERT(sizeof(int) == cbWritten);
  713. len *= sizeof(WCHAR);
  714. prLog->Write(bstrStatus, len, &cbWritten);
  715. ASSERT(len == (int)cbWritten);
  716. delete prLog;
  717. return S_OK;
  718. } else {
  719. return E_FAIL;
  720. }
  721. }
  722. STDMETHODIMP ReadSingleEntry(PLogEntry pLog, LPCTSTR szSubKey, int index)
  723. {
  724. ASSERT(pLog && szSubKey);
  725. ASSERT(index >= 0);
  726. ASSERT(index < TRAYUI_CLOGS);
  727. // Check to see if it's a valid log entry.
  728. if (pLog->bstrStatus) {
  729. ASSERT(0);
  730. SAFEFREEBSTR(pLog->bstrStatus);
  731. }
  732. TCHAR szLogName[16];
  733. HRESULT hrLog = E_INVALIDARG;
  734. wsprintf(szLogName, TEXT("%d"), index);
  735. CRegStream * prLog = new CRegStream(HKEY_CURRENT_USER, szSubKey, szLogName);
  736. if (prLog && (FALSE == prLog->m_fNewStream)) {
  737. CLSID clsidAgent;
  738. CLSID cookie;
  739. FILETIME ftLog;
  740. int versionNumber;
  741. BSTR bstrStatus = NULL;
  742. DWORD cbWritten;
  743. int len;
  744. if (SUCCEEDED(prLog->Read(&versionNumber, sizeof(int), &cbWritten))
  745. && (sizeof(int) == cbWritten)
  746. && (TRAYLOGVERSION == versionNumber))
  747. {
  748. hrLog = ERROR_SUCCESS;
  749. }
  750. if (ERROR_SUCCESS == hrLog) {
  751. hrLog = E_INVALIDARG;
  752. if (SUCCEEDED(prLog->Read(&clsidAgent, sizeof(CLSID), &cbWritten))
  753. && (sizeof(CLSID) == cbWritten))
  754. {
  755. hrLog = ERROR_SUCCESS;
  756. }
  757. }
  758. if (ERROR_SUCCESS == hrLog) {
  759. hrLog = E_INVALIDARG;
  760. if (SUCCEEDED(prLog->Read(&cookie, sizeof(CLSID), &cbWritten))
  761. && (sizeof(CLSID) == cbWritten))
  762. {
  763. hrLog = ERROR_SUCCESS;
  764. }
  765. }
  766. if (ERROR_SUCCESS == hrLog) {
  767. hrLog = E_INVALIDARG;
  768. if (SUCCEEDED(prLog->Read(&ftLog, sizeof(FILETIME), &cbWritten))
  769. && (sizeof(FILETIME) == cbWritten))
  770. {
  771. hrLog = ERROR_SUCCESS;
  772. }
  773. }
  774. if (ERROR_SUCCESS == hrLog) {
  775. hrLog = E_INVALIDARG;
  776. if (SUCCEEDED(prLog->Read(&len, sizeof(int), &cbWritten))
  777. && (sizeof(int) == cbWritten)
  778. && (len < INTERNET_MAX_URL_LENGTH)
  779. && (bstrStatus = SysAllocStringLen(NULL, len))
  780. && SUCCEEDED(prLog->Read(bstrStatus, len * sizeof(WCHAR), &cbWritten))
  781. && (len * sizeof(WCHAR) == (int)cbWritten))
  782. {
  783. hrLog = ERROR_SUCCESS;
  784. bstrStatus[len] = 0;
  785. }
  786. }
  787. if (ERROR_SUCCESS == hrLog) {
  788. pLog->clsidAgent = clsidAgent;
  789. pLog->startCookie = cookie;
  790. pLog->ftLog = ftLog;
  791. pLog->bstrStatus = bstrStatus;
  792. #ifdef DEBUG
  793. WCHAR wszCookie[GUIDSTR_MAX];
  794. TCHAR tmpTSTR[INTERNET_MAX_URL_LENGTH];
  795. StringFromGUID2(cookie, wszCookie, ARRAYSIZE(wszCookie));
  796. MyOleStrToStrN(tmpTSTR, ARRAYSIZE(wszCookie), wszCookie);
  797. TraceMsg(TF_THISMODULE, TEXT("TrayUI:LoadLog - %s(cookie)"), tmpTSTR);
  798. MyOleStrToStrN(tmpTSTR, ARRAYSIZE(tmpTSTR), bstrStatus);
  799. TraceMsg(TF_THISMODULE, TEXT("TrayUI:LoadLog - %s(status)"), tmpTSTR);
  800. SYSTEMTIME stLog;
  801. FileTimeToSystemTime(&ftLog, &stLog);
  802. GetTimeFormat(LOCALE_SYSTEM_DEFAULT, LOCALE_NOUSEROVERRIDE,
  803. &stLog, NULL, tmpTSTR, ARRAYSIZE(tmpTSTR));
  804. TraceMsg(TF_THISMODULE, TEXT("TrayUI:LoadLog - %s(time)"), tmpTSTR);
  805. #endif
  806. } else {
  807. SAFEFREEBSTR(bstrStatus);
  808. }
  809. }
  810. if (prLog)
  811. delete prLog;
  812. return hrLog;
  813. }
  814. STDMETHODIMP CTrayUI::SyncLogWithReg(int index, BOOL fWriteMax)
  815. {
  816. if ((index < 0) || (index >= m_cLogs))
  817. return S_FALSE;
  818. TCHAR szSubKey[1024];
  819. ASSERT((lstrlen(c_szRegKey) + lstrlen(c_szLog) + 2) < 1024);
  820. #error Potential Buffer overflow:
  821. lstrcpy(szSubKey, c_szRegKey);
  822. lstrcat(szSubKey, c_szLog);
  823. HRESULT hr = E_FAIL;
  824. hr = WriteSingleEntry(&(m_aLogEntry[index]), szSubKey, index);
  825. if ((ERROR_SUCCESS == hr) && fWriteMax) {
  826. CRegStream * prs =
  827. new CRegStream(HKEY_CURRENT_USER, szSubKey, c_szLogMaxIndex);
  828. DWORD cbWritten;
  829. if (prs) {
  830. prs->Write(&m_cLogs, sizeof(int), &cbWritten);
  831. ASSERT(sizeof(int) == cbWritten);
  832. delete prs;
  833. } else {
  834. hr = E_FAIL;
  835. }
  836. }
  837. return hr;
  838. }
  839. STDMETHODIMP CTrayUI::SaveLogToReg(void)
  840. {
  841. HRESULT hr = S_OK;
  842. TCHAR szSubKey[1024];
  843. ASSERT((lstrlen(c_szRegKey) + lstrlen(c_szLog) + 2) < 1024);
  844. #error Potential Buffer overflow:
  845. lstrcpy(szSubKey, c_szRegKey);
  846. lstrcat(szSubKey, c_szLog);
  847. int index = 0;
  848. int cIndex = 0;
  849. ULONG cbWritten;
  850. int maxIndex = m_cLogs;
  851. for (; index < maxIndex; index ++) {
  852. if (SUCCEEDED(
  853. WriteSingleEntry(&(m_aLogEntry[index]), szSubKey, cIndex)
  854. )
  855. )
  856. {
  857. cIndex ++;
  858. }
  859. }
  860. CRegStream * prs =
  861. new CRegStream(HKEY_CURRENT_USER, szSubKey, c_szLogMaxIndex);
  862. if (prs) {
  863. prs->Write(&cIndex, sizeof(int), &cbWritten);
  864. ASSERT(sizeof(int) == cbWritten);
  865. delete prs;
  866. }
  867. return hr;
  868. }
  869. STDMETHODIMP CTrayUI::LoadLogFromReg(void)
  870. {
  871. HRESULT hr = S_OK;
  872. TCHAR szSubKey[1024];
  873. ASSERT((lstrlen(c_szRegKey) + lstrlen(c_szLog) + 2) < 1024);
  874. #error Potential Buffer overflow:
  875. lstrcpy(szSubKey, c_szRegKey);
  876. lstrcat(szSubKey, c_szLog);
  877. m_cLogs = 0;
  878. int index = 0;
  879. ULONG cbWritten;
  880. int len = 0;
  881. int maxIndex = 0;
  882. CRegStream * prs = new CRegStream(HKEY_CURRENT_USER, szSubKey, c_szLogMaxIndex);
  883. if (!prs) {
  884. hr = E_FAIL;
  885. } else if (TRUE == prs->m_fNewStream) {
  886. hr = E_FAIL;
  887. } else {
  888. if (SUCCEEDED(prs->Read(&maxIndex, sizeof(int), &cbWritten))
  889. && (sizeof(int) == cbWritten) && (maxIndex >= 0))
  890. {
  891. FILETIME ftFirst;
  892. SYSTEMTIME stNow;
  893. if (TRAYUI_CLOGS < maxIndex) {
  894. maxIndex = TRAYUI_CLOGS;
  895. }
  896. m_cLogPtr = -1;
  897. GetSystemTime(&stNow);
  898. SystemTimeToFileTime(&stNow, &ftFirst);
  899. for (; index < maxIndex; index ++)
  900. {
  901. PLogEntry pLog = &(m_aLogEntry[m_cLogs]);
  902. if (SUCCEEDED(ReadSingleEntry(pLog, szSubKey, index))) {
  903. if (-1 == CompareFileTime(&(pLog->ftLog), &ftFirst)) {
  904. ftFirst= pLog->ftLog;
  905. m_cLogPtr = m_cLogs;
  906. }
  907. m_cLogs ++;
  908. }
  909. }
  910. // m_cLogPtr points to the oldest log. If we haven't used up
  911. // all log space m_cLogPtr should point to 0. We then adjust
  912. // it to the next available log slot.
  913. if (m_cLogs < TRAYUI_CLOGS) {
  914. ASSERT(m_cLogPtr == 0);
  915. m_cLogPtr = m_cLogs;
  916. }
  917. }
  918. }
  919. if (prs)
  920. delete prs;
  921. return hr;
  922. }
  923. STDMETHODIMP CTrayUI::AddToLog(BSTR bstrStatus, CLSID clsidAgent, CLSID startCookie)
  924. {
  925. ASSERT(bstrStatus);
  926. BSTR bstrTmp = NULL;
  927. bstrTmp = SysAllocString(bstrStatus);
  928. if (bstrTmp == NULL)
  929. return E_OUTOFMEMORY;
  930. PLogEntry pLog = &(m_aLogEntry[m_cLogPtr]);
  931. pLog->bstrStatus = bstrTmp;
  932. pLog->clsidAgent = clsidAgent;
  933. pLog->startCookie = startCookie;
  934. SYSTEMTIME stNow;
  935. GetSystemTime(&stNow);
  936. SystemTimeToFileTime(&stNow, &(pLog->ftLog));
  937. if (m_cLogPtr == m_cLogs) {
  938. m_cLogs ++;
  939. SyncLogWithReg(m_cLogPtr, TRUE);
  940. } else {
  941. SyncLogWithReg(m_cLogPtr, FALSE);
  942. }
  943. m_cLogPtr ++;
  944. m_cLogPtr %= TRAYUI_CLOGS;
  945. return S_OK;
  946. }
  947. #endif // WANT_REGISTRY_LOG
  948. STDMETHODIMP CTrayUI::InitTrayUI(void)
  949. {
  950. // shouldn't already be initialized
  951. ASSERT(NULL == m_hwnd);
  952. // create a hidden window
  953. WNDCLASS wndclass;
  954. wndclass.style = 0;
  955. wndclass.lpfnWndProc = TrayUI_WndProc;
  956. wndclass.cbClsExtra = 0;
  957. wndclass.cbWndExtra = 0;
  958. wndclass.hInstance = g_hInst;
  959. wndclass.hIcon = NULL;
  960. wndclass.hCursor = NULL;
  961. wndclass.hbrBackground = NULL;
  962. wndclass.lpszMenuName = NULL;
  963. wndclass.lpszClassName = c_szTrayUI;
  964. RegisterClass (&wndclass) ;
  965. m_hwnd = CreateWindow(c_szTrayUI,
  966. c_szTrayUI,
  967. WS_OVERLAPPEDWINDOW,
  968. CW_USEDEFAULT,
  969. CW_USEDEFAULT,
  970. CW_USEDEFAULT,
  971. CW_USEDEFAULT,
  972. NULL,
  973. NULL,
  974. g_hInst,
  975. NULL);
  976. DBGASSERT(m_hwnd, "failed to create TrayUI window");
  977. if (NULL == m_hwnd)
  978. return ERROR_NOT_ENOUGH_MEMORY;
  979. ShowWindow(m_hwnd, SW_HIDE);
  980. //
  981. // Add an icon to tray after seeing if it's enabled in the registry.
  982. //
  983. ASSERT(FALSE == m_fUpdatingTrayIcon);
  984. // turn on idle monitoring
  985. IdleBegin(m_hwnd);
  986. return S_OK;
  987. }
  988. STDMETHODIMP CTrayUI::DestroyTrayUI(void)
  989. {
  990. // stop idle monitoring
  991. IdleEnd();
  992. if (m_hwnd)
  993. {
  994. BOOL bRet;
  995. bRet = DestroyWindow(m_hwnd);
  996. ASSERT(bRet);
  997. m_hwnd = NULL;
  998. }
  999. return S_OK;
  1000. }
  1001. STDMETHODIMP CTrayUI::OpenSubscriptionFolder(void)
  1002. {
  1003. #ifdef DEBUG
  1004. // WARNING: This is copied from shdocvw and it might change post beta 1.
  1005. TCHAR szSubPath[MAX_PATH];
  1006. DWORD dwSize = SIZEOF(szSubPath);
  1007. if (ReadRegValue(HKEY_LOCAL_MACHINE, REGSTR_PATH_SUBSCRIPTION,
  1008. REGSTR_VAL_DIRECTORY, (LPBYTE)szSubPath, dwSize) == FALSE)
  1009. {
  1010. TCHAR szWindows[MAX_PATH];
  1011. GetWindowsDirectory(szWindows, ARRAYSIZE(szWindows));
  1012. PathCombine(szSubPath, szWindows, TEXT("Subscriptions"));
  1013. }
  1014. SHELLEXECUTEINFO shei;
  1015. ZeroMemory(&shei, sizeof(shei));
  1016. shei.cbSize = sizeof(shei);
  1017. shei.lpFile = szSubPath;
  1018. shei.nShow = SW_SHOWNORMAL;
  1019. ShellExecuteEx(&shei);
  1020. #endif
  1021. return S_OK;
  1022. }
  1023. STDMETHODIMP CTrayUI::OpenContextMenu(POINT * pPoint)
  1024. {
  1025. #ifdef DEBUG
  1026. int iCmd;
  1027. HMENU hMenu;
  1028. TCHAR menuString[MAX_PATH];
  1029. ASSERT(pPoint);
  1030. // SetForegroundWindow(hwnd);
  1031. hMenu = CreatePopupMenu();
  1032. if (!hMenu)
  1033. return E_FAIL;
  1034. // MLLoadString(IDS_SHOWPROG, menuString, MAX_PATH);
  1035. // AppendMenu(hMenu, MF_STRING, IDS_SHOWPROG, menuString);
  1036. MLLoadString(IDS_CANCELDL, menuString, MAX_PATH);
  1037. AppendMenu(hMenu, MF_STRING, IDS_CANCELDL, menuString);
  1038. MLLoadString(IDS_VIEW_SUBS, menuString, MAX_PATH);
  1039. AppendMenu(hMenu, MF_STRING, IDS_VIEW_SUBS, menuString);
  1040. SetMenuDefaultItem(hMenu, IDS_CANCELDL, FALSE);
  1041. if (hMenu)
  1042. {
  1043. //
  1044. // Set the owner window to be foreground as a hack so the
  1045. // popup menu disappears when the user clicks elsewhere.
  1046. //
  1047. BOOL bRet;
  1048. ASSERT(m_hwnd);
  1049. bRet = SetForegroundWindow(m_hwnd);
  1050. ASSERT(bRet);
  1051. iCmd = TrackPopupMenu(hMenu, TPM_RETURNCMD | TPM_NONOTIFY | TPM_RIGHTBUTTON,
  1052. pPoint->x, pPoint->y, 0, m_hwnd, NULL);
  1053. DestroyMenu(hMenu);
  1054. MSG msgTmp;
  1055. while (PeekMessage(&msgTmp, m_hwnd, WM_LBUTTONDOWN, WM_LBUTTONUP, PM_REMOVE)) {
  1056. DispatchMessage(&msgTmp);
  1057. }
  1058. }
  1059. switch (iCmd)
  1060. {
  1061. case IDS_SHOWPROG:
  1062. RunTest();
  1063. break;
  1064. case IDS_CANCELDL:
  1065. CancelAllDownloads();
  1066. break;
  1067. case IDS_VIEW_SUBS:
  1068. OpenSubscriptionFolder();
  1069. break;
  1070. default:
  1071. break;
  1072. }
  1073. #endif
  1074. return S_OK;
  1075. }
  1076. STDMETHODIMP CTrayUI::UpdateNow(INotification * pNotification)
  1077. {
  1078. //
  1079. // Update Subscriptions Now
  1080. // We really don't want to do this on the caller's thread. We should
  1081. // always get here through a notification on the appartment thread.
  1082. // (No direct calls from other threads are allowed to avoid race
  1083. // conditions at startup.)
  1084. ASSERT(GetCurrentThreadId() == m_AptThreadId);
  1085. // Essentially we do a PostThreadMessage here to the updating thread.
  1086. return UpdateRequest(UM_ONREQUEST, pNotification);
  1087. }
  1088. STDMETHODIMP CTrayUI::SetTrayIcon(DWORD fUpdating)
  1089. {
  1090. #ifdef DEBUG
  1091. if (fUpdating == m_fUpdatingTrayIcon) {
  1092. return S_OK;
  1093. }
  1094. if (fUpdating)
  1095. {
  1096. BOOL bRet;
  1097. NOTIFYICONDATA NotifyIconData;
  1098. NotifyIconData.cbSize = sizeof(NOTIFYICONDATA);
  1099. NotifyIconData.hWnd = m_hwnd;
  1100. NotifyIconData.uID = 0;
  1101. NotifyIconData.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
  1102. NotifyIconData.uCallbackMessage = WM_USER;
  1103. NotifyIconData.hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_TRAYICON));
  1104. ASSERT(NotifyIconData.hIcon);
  1105. bRet = MLLoadString(IDS_TRAY_TOOLTIP, NotifyIconData.szTip, ARRAYSIZE(NotifyIconData.szTip));
  1106. ASSERT(bRet);
  1107. bRet = Shell_NotifyIcon(NIM_ADD, &NotifyIconData);
  1108. ASSERT(bRet);
  1109. }
  1110. else
  1111. {
  1112. // Remove the tray icon
  1113. BOOL bRet;
  1114. NOTIFYICONDATA NotifyIconData;
  1115. NotifyIconData.cbSize = sizeof(NOTIFYICONDATA);
  1116. NotifyIconData.hWnd = m_hwnd;
  1117. NotifyIconData.uID = 0;
  1118. NotifyIconData.uFlags = 0;
  1119. bRet = Shell_NotifyIcon(NIM_DELETE, &NotifyIconData);
  1120. ASSERT(bRet);
  1121. }
  1122. m_fUpdatingTrayIcon = fUpdating;
  1123. #endif
  1124. return S_OK;
  1125. }
  1126. STDMETHODIMP CTrayUI::ConfigChanged(void)
  1127. {
  1128. return S_OK;
  1129. }
  1130. STDMETHODIMP CTrayUI::OnEndReport(INotification * pNot)
  1131. {
  1132. //xnotfmgr
  1133. ASSERT(pNot);
  1134. CLSID cookie;
  1135. if (SUCCEEDED(ReadGUID(pNot, NULL, c_szStartCookie, &cookie)))
  1136. {
  1137. DBGIID("TrayAgent::OnEndReport - ", cookie);
  1138. UpdateRequest(UM_ENDREPORT, pNot);
  1139. LONG lTmp = InterlockedDecrement(&m_cUpdates);
  1140. if (!lTmp)
  1141. SetTrayIcon(FALSE);
  1142. OOEBuf ooeBuf;
  1143. LPMYPIDL newPidl = NULL;
  1144. DWORD dwSize = 0;
  1145. ZeroMemory((void *)&ooeBuf, sizeof(OOEBuf));
  1146. HRESULT hr = LoadWithCookie(NULL, &ooeBuf, &dwSize, &cookie);
  1147. if (SUCCEEDED(hr))
  1148. {
  1149. newPidl = COfflineFolderEnum::NewPidl(dwSize);
  1150. if (newPidl) {
  1151. CopyToMyPooe(&ooeBuf, &(newPidl->ooe));
  1152. _GenerateEvent(SHCNE_UPDATEITEM, (LPITEMIDLIST)newPidl, NULL);
  1153. COfflineFolderEnum::FreePidl(newPidl);
  1154. }
  1155. }
  1156. }
  1157. return S_OK;
  1158. }
  1159. STDMETHODIMP CTrayUI::OnBeginReport(INotification * pNot)
  1160. {
  1161. //xnotfmgr
  1162. ASSERT(pNot);
  1163. CLSID cookie;
  1164. if (SUCCEEDED(ReadGUID(pNot, NULL, c_szStartCookie, &cookie)))
  1165. {
  1166. DBGIID("TrayAgent::OnBeginReport - ", cookie);
  1167. UpdateRequest(UM_BEGINREPORT, pNot);
  1168. InterlockedIncrement(&m_cUpdates);
  1169. SetTrayIcon(TRUE);
  1170. }
  1171. return S_OK;
  1172. }