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.

2529 lines
80 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1998.
  5. //
  6. // File: T R A Y U I . C P P
  7. //
  8. // Contents: Tray window code for the CConnectionTray object.
  9. //
  10. // Notes:
  11. //
  12. // Author: jeffspr 13 Nov 1997
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include "foldinc.h" // Standard shell\tray includes
  18. #include "ctrayui.h"
  19. #include "cfutils.h"
  20. #include "loadicon.h"
  21. #include "ncmisc.h"
  22. #include "oncommand.h"
  23. #include "traymsgs.h"
  24. #include "trayres.h"
  25. #include "ndispnp.h"
  26. #include "ntddndis.h"
  27. #include <confold.h>
  28. #include <smcent.h>
  29. #include <smutil.h>
  30. #include <ncperms.h>
  31. #include "cfutils.h"
  32. #include "ac_ctrayui.h"
  33. const WCHAR c_szTrayClass[] = L"Connections Tray";
  34. const WCHAR c_szTipTrailer[] = L" ...";
  35. const WCHAR c_szDelayLoadKey[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\ShellServiceObjectDelayLoad";
  36. const WCHAR c_szDelayLoadName[] = L"Connections Tray";
  37. const WCHAR c_szDelayLoadClassID[] = L"7007ACCF-3202-11D1-AAD2-00805FC1270E";
  38. const DWORD c_dwBalloonTimeoutSeconds = 5;
  39. const WCHAR c_szDotDotDot[] = L"..."; // For balloon tip
  40. // don't change this unless you know better
  41. const UINT_PTR c_unTimerIdDblClick = 1;
  42. const INT c_idDefaultCMCommand = CMIDM_TRAY_STATUS;
  43. const INT c_idDefaultDisconCMCommand = CMIDM_OPEN_CONNECTIONS_FOLDER;
  44. const INT c_idDefaultDisconCMWirelessCommand = CMIDM_TRAY_WZCDLG_SHOW;
  45. CTrayUI * g_pCTrayUI; // TrayUI object (not COM)
  46. HWND g_hwndTray = NULL;
  47. //---[ Prototypes ]-----------------------------------------------------------
  48. VOID
  49. GetInitialBalloonText(
  50. INetStatisticsEngine* pnse,
  51. PWSTR pszBuf,
  52. DWORD dwSize);
  53. LRESULT
  54. CALLBACK
  55. CTrayUI_WndProc (
  56. HWND hwnd, // window handle
  57. UINT uiMessage, // type of message
  58. WPARAM wParam, // additional information
  59. LPARAM lParam); // additional information
  60. BOOL FInitFoldEnumerator(HWND hwnd, DWORD * pdwIconsAdded);
  61. VOID OnTaskBarIconRButtonUp(HWND hwnd, UINT uiIcon);
  62. VOID OnTaskBarIconBalloonClick(HWND hwnd, UINT uiIcon);
  63. VOID OnTaskBarIconLButtonDblClk(HWND hwnd, UINT uiIcon);
  64. HRESULT HrOpenContextMenu(HWND hwnd, POINT * pPoint, UINT uiIcon);
  65. // Window message handlers
  66. //
  67. LRESULT OnTrayWmCreate(HWND hwnd);
  68. LRESULT OnTrayWmDestroy(HWND hwnd);
  69. LRESULT OnTrayWmCommand(HWND hwnd, UINT uiMessage, WPARAM wParam, LPARAM lParam);
  70. LRESULT OnMyWMNotifyIcon(HWND hwnd, UINT uiMessage, WPARAM wParam, LPARAM lParam);
  71. LRESULT OnMyWMOpenStatus(HWND hwnd, WPARAM wParam, LPARAM lParam);
  72. LRESULT OnMyWMUpdateTrayIcon(HWND hwnd, WPARAM wParam, LPARAM lParam);
  73. LRESULT OnMyWMShowTrayIconBalloon (HWND hwnd, WPARAM wParam, LPARAM lParam);
  74. LRESULT OnMyWMFlushNoop(HWND hwnd, WPARAM wParam, LPARAM lParam);
  75. //+---------------------------------------------------------------------------
  76. //
  77. // Function: CopyAndAdvanceIfSpaceAvailable
  78. //
  79. // Purpose: Helper routine for FormatToolTip. This manages the current
  80. // pointer into the tooltip and the count of characters
  81. // remaining in the buffer.
  82. //
  83. // Arguments:
  84. // pchTip [in out] Current pointer into the tooltip.
  85. // cchRemaining [in out] Count of characters remaining in its buffer.
  86. // pszLine [in] New line to append to the tooltip.
  87. // cchLine [in] Count of characters in the line to append.
  88. // fInsertNewline [in] TRUE to insert a newline first.
  89. //
  90. // Returns: nothing
  91. //
  92. // Author: shaunco 7 Nov 1998
  93. //
  94. // Notes:
  95. //
  96. VOID
  97. CopyAndAdvanceIfSpaceAvailable (
  98. WCHAR*& pchTip,
  99. INT& cchRemaining,
  100. PCWSTR pszLine,
  101. INT cchLine,
  102. BOOL fInsertNewline)
  103. {
  104. TraceFileFunc(ttidSystray);
  105. if (cchLine < cchRemaining - (fInsertNewline) ? 1 : 0)
  106. {
  107. if (fInsertNewline)
  108. {
  109. *pchTip = L'\n';
  110. pchTip++;
  111. cchRemaining--;
  112. }
  113. lstrcpyW(pchTip, pszLine);
  114. pchTip += cchLine;
  115. cchRemaining -= cchLine;
  116. }
  117. }
  118. //+---------------------------------------------------------------------------
  119. //
  120. // Function: FormatToolTip
  121. //
  122. // Purpose: Format a tooltip for the connection with the matching
  123. // icon id.
  124. //
  125. // Arguments:
  126. // hwnd [in] Window handle of the tray.
  127. // uiIcon [in] Icon id of the tray icon.
  128. //
  129. // Returns: nothing
  130. //
  131. // Author: shaunco 7 Nov 1998
  132. //
  133. // Notes:
  134. //
  135. VOID
  136. FormatToolTip (
  137. HWND hwnd,
  138. UINT uiIcon)
  139. {
  140. TraceFileFunc(ttidSystray);
  141. HRESULT hr = S_OK;
  142. NETCON_STATUS ncs = NCS_CONNECTED;
  143. NETCON_MEDIATYPE ncm = NCM_NONE;
  144. NETCON_SUBMEDIATYPE ncsm = NCSM_NONE;
  145. tstring strName;
  146. WCHAR pszValue[64];
  147. WCHAR pszLine[256];
  148. INT cch;
  149. GUID gdPcleGuid;
  150. NOTIFYICONDATA nid;
  151. ZeroMemory(&nid, sizeof(nid));
  152. nid.cbSize = sizeof(NOTIFYICONDATA);
  153. nid.hWnd = hwnd;
  154. nid.uID = uiIcon;
  155. nid.uFlags = NIF_TIP;
  156. // Get the info on the connection so we know how to label the tooltip
  157. //
  158. ConnListEntry cle;
  159. hr = g_ccl.HrFindConnectionByTrayIconId(uiIcon, cle);
  160. if (hr == S_OK)
  161. {
  162. Assert(!cle.ccfe.empty());
  163. ncs = cle.ccfe.GetNetConStatus();
  164. gdPcleGuid = cle.ccfe.GetGuidID();
  165. ncm = cle.ccfe.GetNetConMediaType();
  166. ncsm = cle.ccfe.GetNetConSubMediaType();
  167. }
  168. else // Orphaned item -remove it.
  169. {
  170. NOTIFYICONDATA nid;
  171. ZeroMemory (&nid, sizeof(nid));
  172. nid.cbSize = sizeof(NOTIFYICONDATA);
  173. nid.hWnd = g_hwndTray;
  174. nid.uID = uiIcon;
  175. hr = HrShell_NotifyIcon(NIM_DELETE, &nid);
  176. TraceTag(ttidSystray, "WARNING: Removing Orphan Tray Icon: %d", uiIcon);
  177. return;
  178. }
  179. // g_ccl.ReleaseLock();
  180. // Media status based tool tip
  181. if (fIsConnectedStatus(ncs))
  182. {
  183. WCHAR* pchTip = nid.szTip;
  184. INT cchRemaining = celems(nid.szTip);
  185. // Get a copy of the current stats and the connection's name.
  186. //
  187. STATMON_ENGINEDATA* pData;
  188. hr = g_ccl.HrGetCurrentStatsForTrayIconId(uiIcon, &pData, &strName);
  189. if (S_OK == hr && pData)
  190. {
  191. UINT unTransmitSpeed = pData->SMED_SPEEDTRANSMITTING;
  192. UINT unRecieveSpeed = pData->SMED_SPEEDRECEIVING;
  193. UINT64 u64Sent = pData->SMED_BYTESTRANSMITTING;
  194. UINT64 u64Rcvd = pData->SMED_BYTESRECEIVING;
  195. INT idsSent = IDS_TOOLTIP_LINE_BYTES_SENT;
  196. INT idsRcvd = IDS_TOOLTIP_LINE_BYTES_RCVD;
  197. INFRASTRUCTURE_MODE infraStructureMode = pData->SMED_INFRASTRUCTURE_MODE;
  198. DWORD dwEncryption = pData->SMED_802_11_ENCRYPTION_ENABLED;
  199. INT iSignalStrength = pData->SMED_802_11_SIGNAL_STRENGTH;
  200. WCHAR szSSID[32];
  201. wcsncpy(szSSID, pData->SMED_802_11_SSID, celems(szSSID));
  202. WCHAR szNamePostFix[celems(nid.szTip)];
  203. ZeroMemory(szNamePostFix, celems(nid.szTip));
  204. if ((0 == u64Sent) && (0 == u64Rcvd))
  205. {
  206. // Use packets instead.
  207. //
  208. u64Sent = pData->SMED_PACKETSTRANSMITTING;
  209. u64Rcvd = pData->SMED_PACKETSRECEIVING;
  210. idsSent = IDS_TOOLTIP_LINE_PACKETS_SENT;
  211. idsRcvd = IDS_TOOLTIP_LINE_PACKETS_RCVD;
  212. }
  213. CoTaskMemFree(pData);
  214. pData = NULL;
  215. BOOL fNewLine = FALSE;
  216. // Speed
  217. //
  218. if ((unTransmitSpeed >0) || ( unRecieveSpeed >0))
  219. {
  220. FormatTransmittingReceivingSpeed (
  221. unTransmitSpeed,
  222. unRecieveSpeed,
  223. pszValue);
  224. cch = DwFormatString(SzLoadIds(IDS_TOOLTIP_LINE_SPEED), pszLine, celems(pszLine), pszValue);
  225. CopyAndAdvanceIfSpaceAvailable(pchTip, cchRemaining, pszLine, cch, FALSE);
  226. fNewLine = TRUE;
  227. }
  228. if ( (ncm == NCM_LAN) && (ncsm == NCSM_WIRELESS) )
  229. {
  230. switch (infraStructureMode)
  231. {
  232. case IM_NDIS802_11IBSS:
  233. DwFormatString(SzLoadIds(IDS_NAME_NETWORK), szNamePostFix, celems(szNamePostFix), SzLoadIds(IDS_TOOLTIP_ADHOC));
  234. break;
  235. case IM_NDIS802_11INFRASTRUCTURE:
  236. if (*szSSID)
  237. {
  238. DwFormatString(SzLoadIds(IDS_NAME_NETWORK), szNamePostFix, celems(szNamePostFix), szSSID);
  239. }
  240. else
  241. {
  242. DwFormatString(SzLoadIds(IDS_NAME_NETWORK), szNamePostFix, celems(szNamePostFix), SzLoadIds(IDS_TOOLTIP_INFRASTRUCTURE));
  243. }
  244. break;
  245. case IM_NDIS802_11AUTOUNKNOWN:
  246. case IM_NOT_SUPPORTED:
  247. default:
  248. break;
  249. }
  250. cch = DwFormatString(SzLoadIds(IDS_SIGNAL_STRENGTH), pszLine, celems(pszLine), PszGetRSSIString(iSignalStrength));
  251. CopyAndAdvanceIfSpaceAvailable(pchTip, cchRemaining, pszLine, cch, fNewLine);
  252. fNewLine = TRUE;
  253. }
  254. if ( IsMediaRASType(ncm) )
  255. {
  256. // Bytes or packets sent
  257. //
  258. Format64bitInteger(
  259. u64Sent,
  260. FALSE,
  261. pszValue,
  262. celems(pszValue));
  263. cch = DwFormatString(SzLoadIds(idsSent), pszLine, celems(pszLine), pszValue);
  264. CopyAndAdvanceIfSpaceAvailable(pchTip, cchRemaining, pszLine, cch, fNewLine);
  265. // Bytes or packets received
  266. //
  267. Format64bitInteger(
  268. u64Rcvd,
  269. FALSE,
  270. pszValue,
  271. celems(pszValue));
  272. cch = DwFormatString(SzLoadIds(idsRcvd), pszLine, celems(pszLine), pszValue);
  273. CopyAndAdvanceIfSpaceAvailable(pchTip, cchRemaining, pszLine, cch, TRUE);
  274. }
  275. // Name
  276. //
  277. if ((INT)(strName.length() + 1) < cchRemaining)
  278. {
  279. WCHAR pszTip [celems(nid.szTip)];
  280. lstrcpyW(pszTip, strName.c_str());
  281. if (*szNamePostFix)
  282. {
  283. lstrcatW(pszTip, szNamePostFix);
  284. }
  285. lstrcatW(pszTip, L"\n");
  286. lstrcatW(pszTip, nid.szTip);
  287. lstrcpyW(nid.szTip, pszTip);
  288. }
  289. }
  290. }
  291. else // MEDIA_DISCONNECTED
  292. {
  293. WCHAR* pchTip = nid.szTip;
  294. INT cchRemaining = celems(nid.szTip);
  295. BOOL fNewLine = FALSE;
  296. if (ncs == NCS_INVALID_ADDRESS)
  297. {
  298. UINT idString = IDS_CONTRAY_ADDRESS_INVALID_TOOLTIP;
  299. STATMON_ENGINEDATA* pData = NULL;
  300. tstring strName;
  301. hr = g_ccl.HrGetCurrentStatsForTrayIconId(uiIcon, &pData, &strName);
  302. if (S_OK == hr && pData)
  303. {
  304. if (STATIC_ADDR == pData->SMED_DHCP_ADDRESS_TYPE)
  305. {
  306. idString = IDS_CONTRAY_STATIC_ADDR_INVALID_TOOLTIP;
  307. }
  308. CoTaskMemFree(pData);
  309. }
  310. lstrcpynW(pszLine, SzLoadIds(idString), celems(pszLine));
  311. cch = wcslen(pszLine);
  312. }
  313. else
  314. {
  315. if ( (ncm == NCM_LAN) && (ncsm == NCSM_WIRELESS) )
  316. {
  317. lstrcpynW(pszLine, SzLoadIds(IDS_CONTRAY_WIRELESS_DISCONN_BALLOON), celems(pszLine));
  318. cch = wcslen(pszLine);
  319. }
  320. else
  321. {
  322. lstrcpynW(pszLine, SzLoadIds(IDS_CONTRAY_MEDIA_DISCONN_BALLOON), celems(pszLine));
  323. cch = wcslen(pszLine);
  324. }
  325. }
  326. CopyAndAdvanceIfSpaceAvailable(pchTip, cchRemaining, pszLine, cch, fNewLine);
  327. fNewLine = TRUE;
  328. hr = g_ccl.HrGetCurrentStatsForTrayIconId(uiIcon, NULL, &strName);
  329. if (SUCCEEDED(hr))
  330. {
  331. // Name
  332. //
  333. if ((INT)(strName.length() + 1) < cchRemaining)
  334. {
  335. WCHAR pszTip [celems(nid.szTip)];
  336. lstrcpyW(pszTip, strName.c_str());
  337. lstrcatW(pszTip, L"\n");
  338. lstrcatW(pszTip, nid.szTip);
  339. lstrcpyW(nid.szTip, pszTip);
  340. }
  341. }
  342. }
  343. hr = HrShell_NotifyIcon(NIM_MODIFY, &nid);
  344. }
  345. //+---------------------------------------------------------------------------
  346. //
  347. // Member: CTrayUI::CTrayUI
  348. //
  349. // Purpose: Constructor for the CTrayUI class. Initialize the base junk
  350. //
  351. // Arguments:
  352. // (none)
  353. //
  354. // Returns:
  355. //
  356. // Author: jeffspr 13 Nov 1997
  357. //
  358. // Notes:
  359. //
  360. CTrayUI::CTrayUI()
  361. {
  362. TraceFileFunc(ttidSystray);
  363. // There should only be one of these objects
  364. //
  365. Assert(!g_pCTrayUI);
  366. InitializeCriticalSection(&m_csLock);
  367. m_uiNextIconId = 0;
  368. m_uiNextHiddenIconId = UINT_MAX;
  369. }
  370. HRESULT CTrayUI::HrInitTrayUI(VOID)
  371. {
  372. TraceFileFunc(ttidSystray);
  373. HRESULT hr = S_OK;
  374. HWND hwnd;
  375. // create a hidden window
  376. //
  377. WNDCLASS wndclass;
  378. ZeroMemory (&wndclass, sizeof(wndclass));
  379. wndclass.lpfnWndProc = CTrayUI_WndProc;
  380. wndclass.hInstance = _Module.GetResourceInstance();
  381. wndclass.lpszClassName = c_szTrayClass;
  382. RegisterClass (&wndclass);
  383. hwnd = CreateWindow(c_szTrayClass,
  384. c_szTrayClass,
  385. WS_OVERLAPPEDWINDOW,
  386. CW_USEDEFAULT,
  387. CW_USEDEFAULT,
  388. CW_USEDEFAULT,
  389. CW_USEDEFAULT,
  390. NULL,
  391. NULL,
  392. _Module.GetResourceInstance(),
  393. NULL);
  394. if (hwnd)
  395. {
  396. // Assigned during WM_CREATE
  397. //
  398. Assert(hwnd == g_hwndTray);
  399. ShowWindow(hwnd, SW_HIDE);
  400. }
  401. else
  402. {
  403. hr = E_OUTOFMEMORY;
  404. }
  405. TraceHr(ttidSystray, FAL, hr, FALSE, "CTrayUI::HrInitTrayUI");
  406. return hr;
  407. }
  408. HRESULT CTrayUI::HrDestroyTrayUI(VOID)
  409. {
  410. TraceFileFunc(ttidSystray);
  411. HRESULT hr = S_OK;
  412. // Remove the tray icons before destroying ourselves
  413. //
  414. g_ccl.FlushTrayIcons();
  415. if (g_hwndTray)
  416. {
  417. // Don't bother checking the return code here. Most likely, this window
  418. // is already gone by the time the tray is calling our shutdown.. We'll
  419. // still grab the return code for debugging purposes, though.
  420. //
  421. BOOL fReturn = DestroyWindow(g_hwndTray);
  422. g_hwndTray = NULL;
  423. }
  424. TraceHr(ttidSystray, FAL, hr, FALSE, "CTrayUI::HrDestroyTrayUI");
  425. return S_OK;
  426. }
  427. VOID SetIconFocus(HWND hwnd, UINT uiIcon)
  428. {
  429. TraceFileFunc(ttidSystray);
  430. HRESULT hr;
  431. NOTIFYICONDATA nid;
  432. ZeroMemory (&nid, sizeof(nid));
  433. nid.cbSize = sizeof(NOTIFYICONDATA);
  434. nid.hWnd = hwnd;
  435. nid.uID = uiIcon;
  436. hr = HrShell_NotifyIcon(NIM_SETFOCUS, &nid);
  437. TraceHr(ttidSystray, FAL, hr, FALSE, "SetIconFocus");
  438. }
  439. //+---------------------------------------------------------------------------
  440. //
  441. // Function: CheckMenuPermissions
  442. //
  443. // Purpose: Update the tray items based on system policy
  444. //
  445. // Arguments:
  446. // hmenu [in] The tray context menu
  447. //
  448. // Returns:
  449. //
  450. // Author: jeffspr 8 Apr 1999
  451. //
  452. // Notes:
  453. //
  454. VOID CheckMenuPermissions(HMENU hmenu, const CONFOLDENTRY& ccfe)
  455. {
  456. TraceFileFunc(ttidSystray);
  457. // Check the permissions for bringing up statistics. If no,
  458. // then disable the context menu item
  459. //
  460. if (!FHasPermission(NCPERM_Statistics))
  461. {
  462. // Enable or disable the menu item, as appopriate
  463. //
  464. EnableMenuItem(
  465. hmenu,
  466. CMIDM_TRAY_STATUS,
  467. MF_GRAYED);
  468. }
  469. // Check the permission to disconnect
  470. BOOL fCanDisconnect = TRUE;
  471. switch(ccfe.GetNetConMediaType())
  472. {
  473. case NCM_LAN:
  474. case NCM_BRIDGE:
  475. fCanDisconnect = FHasPermission(NCPERM_LanConnect);
  476. if (!FHasPermission(NCPERM_Repair))
  477. {
  478. EnableMenuItem(
  479. hmenu,
  480. CMIDM_TRAY_REPAIR,
  481. MF_GRAYED);
  482. }
  483. break;
  484. case NCM_PPPOE:
  485. case NCM_DIRECT:
  486. case NCM_ISDN:
  487. case NCM_PHONE:
  488. case NCM_TUNNEL:
  489. case NCM_NONE:
  490. fCanDisconnect = FHasPermission(NCPERM_RasConnect);
  491. break;
  492. case NCM_SHAREDACCESSHOST_LAN:
  493. case NCM_SHAREDACCESSHOST_RAS:
  494. fCanDisconnect = TRUE; // group policy is enforced by the enumerator, if you can see it you can use it.
  495. break;
  496. default:
  497. AssertSz(FALSE, "Need to add a switch for this connection type in the menuing code");
  498. break;
  499. }
  500. if (!fCanDisconnect)
  501. {
  502. EnableMenuItem(
  503. hmenu,
  504. CMIDM_TRAY_DISCONNECT,
  505. MF_GRAYED);
  506. }
  507. }
  508. //+---------------------------------------------------------------------------
  509. //
  510. // Function: FAddMenuBranding
  511. //
  512. // Purpose: Process the CM branding tray menu extensions. Add them to the
  513. // menu if needed
  514. //
  515. // Arguments:
  516. // hmenu [in] Incoming hmenu
  517. // cfe [in] Our cache entry
  518. // IdMinMenuID [in] The smallest allowable menu ID to use
  519. // pMenuData [in] Menu Data
  520. // piIdCustomMin [out] Our custom range min
  521. // piIdCustomMax [out] Our custom range max
  522. //
  523. // Returns: TRUE if we added anything, FALSE if we didn't
  524. //
  525. // Author: jeffspr 8 Apr 1999
  526. //
  527. // Notes:
  528. //
  529. BOOL FAddMenuBranding(
  530. HMENU hmenu,
  531. const ConnListEntry& cle,
  532. INT IdMinMenuID,
  533. INT * piIdCustomMin,
  534. INT * piIdCustomMax)
  535. {
  536. TraceFileFunc(ttidSystray);
  537. BOOL fBranded = FALSE;
  538. int iIdCustomMin = -1;
  539. int iIdCustomMax = -1;
  540. HMENU hmenuTrack = NULL;
  541. Assert(hmenu);
  542. Assert(!cle.empty());
  543. Assert(!cle.ccfe.empty());
  544. if (cle.ccfe.GetCharacteristics() & NCCF_BRANDED)
  545. {
  546. // we may have custom menus for CM connections, merge them in
  547. //
  548. const CON_TRAY_MENU_DATA* pMenuData = cle.pctmd;
  549. if (pMenuData)
  550. {
  551. Assert(pMenuData->dwCount);
  552. int cMenuItems = GetMenuItemCount(hmenu);
  553. if (-1 == cMenuItems)
  554. {
  555. TraceLastWin32Error("GetMenuItemCount failed on tray menu");
  556. }
  557. else
  558. {
  559. BOOL fRet;
  560. MENUITEMINFO mii;
  561. // add a separator bar
  562. ZeroMemory(&mii, sizeof(mii));
  563. mii.cbSize = sizeof(mii);
  564. mii.fMask = MIIM_TYPE;
  565. mii.fType = MFT_SEPARATOR;
  566. fRet = InsertMenuItem( hmenu,
  567. cMenuItems++,
  568. TRUE, // fByPosition
  569. &mii);
  570. if (fRet)
  571. {
  572. DWORD dwCount = pMenuData->dwCount;
  573. CON_TRAY_MENU_ENTRY * pMenuEntry = pMenuData->pctme;
  574. // this is the first id for our custom menu items
  575. iIdCustomMin = CMIDM_FIRST+cMenuItems+1;
  576. iIdCustomMin = iIdCustomMin < IdMinMenuID ? IdMinMenuID : iIdCustomMin;
  577. iIdCustomMax = iIdCustomMin+dwCount;
  578. int iMenu = 0;
  579. while (dwCount)
  580. {
  581. Assert(pMenuEntry);
  582. fRet = AppendMenu( hmenu,
  583. MF_STRING,
  584. iIdCustomMin+iMenu,
  585. pMenuEntry->szwMenuText);
  586. if (!fRet)
  587. {
  588. DWORD dwError = GetLastError();
  589. TraceTag(ttidSystray, "Failed adding custom menu: %S, error: %d",
  590. pMenuEntry->szwMenuText,
  591. dwError);
  592. }
  593. // move to the next item
  594. iMenu++;
  595. dwCount--;
  596. pMenuEntry++;
  597. }
  598. // Mark it as branded to say "hey, we actually added items"
  599. //
  600. fBranded = TRUE;
  601. }
  602. }
  603. }
  604. }
  605. if (fBranded)
  606. {
  607. *piIdCustomMin = iIdCustomMin;
  608. *piIdCustomMax = iIdCustomMax;
  609. }
  610. return fBranded;
  611. }
  612. //+---------------------------------------------------------------------------
  613. //
  614. // Function: HrProcessBrandedTrayMenuCommand
  615. //
  616. // Purpose: Perform the custom action specified in the selected
  617. // branded menu
  618. //
  619. // Arguments:
  620. // iMenuEntry [in] Our branded command
  621. // pMenuData [in] Our branded menu struct
  622. //
  623. // Returns:
  624. //
  625. // Author: jeffspr 8 Apr 1999
  626. //
  627. // Notes:
  628. //
  629. HRESULT HrProcessBrandedTrayMenuCommand(
  630. INT iMenuEntry,
  631. const CON_TRAY_MENU_DATA * pMenuData)
  632. {
  633. TraceFileFunc(ttidSystray);
  634. HRESULT hr = S_OK;
  635. Assert(iMenuEntry != -1);
  636. Assert(pMenuData);
  637. DWORD dwCount = pMenuData->dwCount;
  638. Assert(dwCount > 0);
  639. CON_TRAY_MENU_ENTRY * pMenuEntry = pMenuData->pctme + iMenuEntry;
  640. Assert(pMenuEntry);
  641. SHELLEXECUTEINFO seiTemp = { 0 };
  642. // Fill in the data structure
  643. //
  644. seiTemp.cbSize = sizeof(SHELLEXECUTEINFO);
  645. seiTemp.fMask = SEE_MASK_DOENVSUBST;
  646. seiTemp.hwnd = NULL;
  647. seiTemp.lpVerb = NULL;
  648. seiTemp.lpFile = pMenuEntry->szwMenuCmdLine;
  649. seiTemp.lpParameters = pMenuEntry->szwMenuParams;
  650. seiTemp.lpDirectory = NULL;
  651. seiTemp.nShow = SW_SHOW;
  652. seiTemp.hInstApp = NULL;
  653. seiTemp.hProcess = NULL;
  654. // Launch the tool
  655. //
  656. if (!::ShellExecuteEx(&seiTemp))
  657. {
  658. hr = ::HrFromLastWin32Error();
  659. }
  660. TraceHr(ttidSystray, FAL, hr, FALSE, "HrProcessBrandedMenuCommand");
  661. return hr;
  662. }
  663. HRESULT HrOpenContextMenu(HWND hwnd, POINT * pPoint, UINT uiIcon)
  664. {
  665. TraceFileFunc(ttidSystray);
  666. HRESULT hr = S_OK;
  667. INT iCmd = 0;
  668. HMENU hmenu = 0;
  669. PCONFOLDPIDL pidlItem;
  670. BOOL fSetIconFocus = TRUE;
  671. INT iIdCustomMin = -1;
  672. INT iIdCustomMax = -1;
  673. BOOL fBranded = FALSE;
  674. Assert(pPoint);
  675. Assert(hwnd);
  676. // Find the connection info based on the tray icon id.
  677. //
  678. ConnListEntry cle;
  679. hr = g_ccl.HrFindConnectionByTrayIconId(uiIcon, cle);
  680. if (hr == S_OK)
  681. {
  682. Assert(!cle.ccfe.empty());
  683. if (!cle.ccfe.empty())
  684. {
  685. // Load the menu resource
  686. //
  687. INT iMenuToLoad = POPUP_CONTRAY_GENERIC_MENU_RAS;
  688. if (cle.ccfe.GetNetConStatus() == NCS_MEDIA_DISCONNECTED)
  689. {
  690. if (IsMediaLocalType(cle.ccfe.GetNetConMediaType()) &&
  691. (NCSM_WIRELESS == cle.ccfe.GetNetConSubMediaType()) )
  692. {
  693. iMenuToLoad = POPUP_CONTRAY_WIRELESS_DISCONNECTED_LAN;
  694. }
  695. else
  696. {
  697. iMenuToLoad = POPUP_CONTRAY_MEDIA_DISCONNECTED_MENU;
  698. }
  699. }
  700. else if (IsMediaLocalType(cle.ccfe.GetNetConMediaType()) || NCM_SHAREDACCESSHOST_LAN == cle.ccfe.GetNetConMediaType())
  701. {
  702. if (NCSM_WIRELESS == cle.ccfe.GetNetConSubMediaType())
  703. {
  704. iMenuToLoad = POPUP_CONTRAY_GENERIC_MENU_WIRELESS_LAN;
  705. }
  706. else
  707. {
  708. iMenuToLoad = POPUP_CONTRAY_GENERIC_MENU_LAN;
  709. }
  710. }
  711. hmenu = LoadMenu(_Module.GetResourceInstance(), MAKEINTRESOURCE(iMenuToLoad));
  712. if (!hmenu)
  713. {
  714. hr = E_FAIL;
  715. }
  716. if (SUCCEEDED(hr))
  717. {
  718. // Get the first menu from the popup. For some reason, this hack is
  719. // required instead of tracking on the outside menu
  720. //
  721. HMENU hmenuTrack = GetSubMenu(hmenu, 0);
  722. //Repair is only availabe for LAN and Bridge adapters
  723. if ( ((POPUP_CONTRAY_GENERIC_MENU_LAN == iMenuToLoad) ||
  724. (POPUP_CONTRAY_GENERIC_MENU_WIRELESS_LAN == iMenuToLoad)) &&
  725. (NCM_BRIDGE != cle.ccfe.GetNetConMediaType()) &&
  726. (NCM_LAN != cle.ccfe.GetNetConMediaType()) )
  727. {
  728. DeleteMenu(hmenuTrack,
  729. CMIDM_TRAY_REPAIR,
  730. MF_BYCOMMAND);
  731. }
  732. // Don't drop out of the loop if we can't get this right.
  733. //
  734. CheckMenuPermissions(hmenuTrack, cle.ccfe);
  735. fBranded = FAddMenuBranding(hmenuTrack, cle, CMIDM_TRAY_MAX+1, &iIdCustomMin, &iIdCustomMax);
  736. // Set the default menu item
  737. //
  738. if (cle.ccfe.GetNetConStatus() == NCS_MEDIA_DISCONNECTED)
  739. {
  740. if (IsMediaLocalType(cle.ccfe.GetNetConMediaType()) &&
  741. (NCSM_WIRELESS == cle.ccfe.GetNetConSubMediaType()) )
  742. {
  743. SetMenuDefaultItem(hmenuTrack, c_idDefaultDisconCMWirelessCommand, FALSE);
  744. }
  745. else
  746. {
  747. SetMenuDefaultItem(hmenuTrack, c_idDefaultDisconCMCommand, FALSE);
  748. }
  749. }
  750. else
  751. {
  752. SetMenuDefaultItem(hmenuTrack, c_idDefaultCMCommand, FALSE);
  753. }
  754. // Set the owner window to be foreground as a hack so the
  755. // popup menu disappears when the user clicks elsewhere.
  756. //
  757. SetForegroundWindow(hwnd);
  758. // Part of the above hack. Bring up the menu and figure out the result
  759. iCmd = TrackPopupMenu(hmenuTrack, TPM_RETURNCMD | TPM_NONOTIFY | TPM_RIGHTBUTTON,
  760. pPoint->x, pPoint->y, 0, hwnd, NULL);
  761. DestroyMenu(hmenu);
  762. MSG msgTmp;
  763. while (PeekMessage(&msgTmp, hwnd, WM_LBUTTONDOWN, WM_LBUTTONUP, PM_REMOVE))
  764. {
  765. DispatchMessage(&msgTmp);
  766. }
  767. // Process the command
  768. //
  769. switch (iCmd)
  770. {
  771. case CMIDM_OPEN_CONNECTIONS_FOLDER:
  772. hr = HrOpenConnectionsFolder();
  773. if (S_OK == hr)
  774. {
  775. // The folder should have focus
  776. fSetIconFocus = FALSE;
  777. }
  778. break;
  779. case CMIDM_TRAY_REPAIR:
  780. HrOnCommandFixInternal(
  781. cle.ccfe,
  782. g_hwndTray,
  783. NULL);
  784. break;
  785. case CMIDM_TRAY_WZCDLG_SHOW:
  786. {
  787. PCONFOLDPIDLVEC pcfpVec;
  788. PCONFOLDPIDL pcfp;
  789. hr = cle.ccfe.ConvertToPidl(pcfp);
  790. if (SUCCEEDED(hr))
  791. {
  792. pcfpVec.insert(pcfpVec.begin(), pcfp);
  793. HrOnCommandWZCDlgShow(pcfpVec,
  794. g_hwndTray,
  795. NULL);
  796. }
  797. }
  798. break;
  799. case CMIDM_TRAY_DISCONNECT:
  800. // Ignore the return from this. If it's NULL, we'll just
  801. // pass it in, and it just won't get refreshed properly
  802. //
  803. hr = HrOnCommandDisconnectInternal(
  804. cle.ccfe,
  805. g_hwndTray,
  806. NULL);
  807. // Normalize the return code on success. We don't care
  808. // if the dialog was canceled or not.
  809. //
  810. switch(hr)
  811. {
  812. // If succeeded, mark us as disconnected.
  813. //
  814. case S_OK:
  815. // If we disconnected and the icon went away, then don't
  816. // bother trying to set the focus back
  817. //
  818. fSetIconFocus = FALSE;
  819. break;
  820. // If S_FALSE, we didn't disconnect. Go ahead
  821. // and normalize the return code.
  822. //
  823. case S_FALSE:
  824. hr = S_OK;
  825. break;
  826. }
  827. break;
  828. case CMIDM_TRAY_STATUS:
  829. hr = HrOnCommandStatusInternal(cle.ccfe, FALSE);
  830. break;
  831. case 0:
  832. // Tray menu cancelled without selection
  833. break;
  834. default:
  835. if ((iCmd >= iIdCustomMin) && (iCmd < iIdCustomMax))
  836. {
  837. AssertSz(fBranded, "Hey, what fool added this command?");
  838. hr = HrProcessBrandedTrayMenuCommand(iCmd-iIdCustomMin, cle.pctmd);
  839. }
  840. else
  841. {
  842. AssertSz(FALSE, "Not in custom range, not a known command, what the...?");
  843. }
  844. break;
  845. }
  846. if (fSetIconFocus)
  847. {
  848. // Shift the focus back to the shell
  849. //
  850. SetIconFocus(hwnd, uiIcon);
  851. }
  852. }
  853. }
  854. else
  855. {
  856. // Data returned from the FindByIconId was bogus
  857. //
  858. hr = E_FAIL;
  859. }
  860. }
  861. else // Orphaned item -remove it.
  862. {
  863. NOTIFYICONDATA nid;
  864. ZeroMemory (&nid, sizeof(nid));
  865. nid.cbSize = sizeof(NOTIFYICONDATA);
  866. nid.hWnd = g_hwndTray;
  867. nid.uID = uiIcon;
  868. hr = HrShell_NotifyIcon(NIM_DELETE, &nid);
  869. TraceTag(ttidSystray, "WARNING: Connection not found opening context menu, hr: 0x%08x, uiIcon: %d", hr, uiIcon);
  870. // Removed this assert because we can have a valid state in the connections folder
  871. // where we've updated our cache but the PostMessages to remove the tray icons
  872. // haven't come through yet.
  873. //
  874. }
  875. return hr;
  876. }
  877. //+---------------------------------------------------------------------------
  878. //
  879. // Function: OnTrayWmCreate
  880. //
  881. // Purpose: Tray window message handler for WM_CREATE.
  882. // We will perform the connection enumeration and create the
  883. // appropriate taskbar icons, including the generic connection
  884. // icon if no connections were present.
  885. //
  886. // Arguments:
  887. // hwnd [in] Tray window
  888. //
  889. // Returns:
  890. //
  891. // Author: jeffspr 14 Dec 1997
  892. //
  893. // Notes:
  894. //
  895. LRESULT OnTrayWmCreate(HWND hwnd)
  896. {
  897. TraceFileFunc(ttidSystray);
  898. BOOL fResult = 0;
  899. DWORD dwIconsAdded = 0;
  900. // Do the connections enumeration and add the icons.
  901. // fResult it for debugging only. We'll always do everything here
  902. //
  903. fResult = FInitFoldEnumerator(hwnd, &dwIconsAdded);
  904. g_ccl.EnsureIconsPresent();
  905. ac_Register(hwnd); // homenet auto config service
  906. return 0;
  907. }
  908. //+---------------------------------------------------------------------------
  909. //
  910. // Function: OnTrayWmDestroy
  911. //
  912. // Purpose: Tray window message handler for WM_DESTROY.
  913. // We will perform the connection enumeration and create the
  914. // appropriate taskbar icons, including the generic connection
  915. // icon if no connections were present.
  916. //
  917. // Arguments:
  918. // hwnd [in] Tray window
  919. //
  920. // Returns:
  921. //
  922. // Author: jeffspr 14 Dec 1997
  923. //
  924. // Notes:
  925. //
  926. LRESULT OnTrayWmDestroy(HWND hwnd)
  927. {
  928. TraceFileFunc(ttidSystray);
  929. ac_Unregister(hwnd);
  930. return 0;
  931. }
  932. //+---------------------------------------------------------------------------
  933. //
  934. // Function: CTrayUI_WndProc
  935. //
  936. // Purpose: Window proc for the tray's hidden window
  937. //
  938. // Arguments:
  939. // hwnd [in] See windows documentation
  940. // uiMessage [in] See windows documentation
  941. // wParam [in] See windows documentation
  942. // lParam [in] See windows documentation
  943. //
  944. // Returns: See windows documentation
  945. //
  946. // Author: jeffspr 14 Dec 1997
  947. //
  948. // Notes:
  949. //
  950. LRESULT
  951. CALLBACK
  952. CTrayUI_WndProc (
  953. HWND hwnd, // window handle
  954. UINT uiMessage, // type of message
  955. WPARAM wParam, // additional information
  956. LPARAM lParam) // additional information
  957. {
  958. TraceFileFunc(ttidSystray);
  959. switch (uiMessage)
  960. {
  961. case WM_CREATE:
  962. // Note: Move this to a better place.
  963. g_hwndTray = hwnd;
  964. return OnTrayWmCreate(hwnd);
  965. case WM_DESTROY:
  966. return OnTrayWmDestroy(hwnd);
  967. case MYWM_NOTIFYICON:
  968. return OnMyWMNotifyIcon(hwnd, uiMessage, wParam, lParam);
  969. case MYWM_OPENSTATUS:
  970. return OnMyWMOpenStatus(hwnd, wParam, lParam);
  971. case MYWM_ADDTRAYICON:
  972. return OnMyWMAddTrayIcon(hwnd, wParam, lParam);
  973. case MYWM_REMOVETRAYICON:
  974. return OnMyWMRemoveTrayIcon(hwnd, wParam, lParam);
  975. case MYWM_UPDATETRAYICON:
  976. return OnMyWMUpdateTrayIcon(hwnd, wParam, lParam);
  977. case MYWM_SHOWBALLOON:
  978. return OnMyWMShowTrayIconBalloon(hwnd, wParam, lParam);
  979. case MYWM_FLUSHNOOP:
  980. return OnMyWMFlushNoop(hwnd, wParam, lParam);
  981. case WM_DEVICECHANGE:
  982. return ac_DeviceChange(hwnd, uiMessage, wParam, lParam);
  983. default: // Passes it on if unproccessed
  984. return (DefWindowProc (hwnd, uiMessage, wParam, lParam));
  985. }
  986. return (0);
  987. }
  988. //+---------------------------------------------------------------------------
  989. //
  990. // Function: HrDoMediaDisconnectedIcon
  991. //
  992. // Purpose: Add a Media-disconnected icon to the tray. We're in the
  993. // state where our cable is unplugged on a LAN adapter and
  994. // we want to inform the user of the situation
  995. //
  996. // Arguments:
  997. // pccfe [in] Our connection
  998. // fShowBalloon [in] Show the balloon tip?
  999. //
  1000. // Returns:
  1001. //
  1002. // Author: jeffspr 14 Jul 1999
  1003. //
  1004. // Notes:
  1005. //
  1006. HRESULT HrDoMediaDisconnectedIcon(const CONFOLDENTRY& pccfe, BOOL fShowBalloon)
  1007. {
  1008. TraceFileFunc(ttidSystray);
  1009. HRESULT hr = S_OK;
  1010. UINT uiIcon = 0;
  1011. TraceTag(ttidSystray, "HrDoMediaDisconnectedIcon");
  1012. DWORD dwLockingThreadId = 0;
  1013. hr = HrGetTrayIconLock(&(pccfe.GetGuidID()), &uiIcon, &dwLockingThreadId);
  1014. if (S_OK == hr)
  1015. {
  1016. if (uiIcon == BOGUS_TRAY_ICON_ID)
  1017. {
  1018. TraceTag(ttidSystray, "Adding MediaDisconnected icon for: %S", pccfe.GetName());
  1019. NETCON_MEDIATYPE ncm = pccfe.GetNetConMediaType();
  1020. if (IsMediaLocalType(ncm) || IsMediaSharedAccessHostType(ncm)) // ics beacon will say disconnected if it is in a unknown state.
  1021. {
  1022. HICON hiconTray = LoadIcon(_Module.GetResourceInstance(),
  1023. MAKEINTRESOURCE(IDI_CFT_DISCONNECTED));
  1024. if (hiconTray)
  1025. {
  1026. ConnListEntry cleFind;
  1027. g_ccl.AcquireWriteLock();
  1028. hr = g_ccl.HrFindConnectionByGuid(&(pccfe.GetGuidID()), cleFind);
  1029. if (S_OK == hr)
  1030. {
  1031. Assert(!cleFind.ccfe.empty());
  1032. g_ccl.HrUpdateTrayBalloonInfoByGuid(&(pccfe.GetGuidID()), BALLOON_USE_NCS, NULL, NULL);
  1033. g_ccl.ReleaseWriteLock();
  1034. NOTIFYICONDATA nid;
  1035. ZeroMemory (&nid, sizeof(nid));
  1036. nid.cbSize = sizeof(NOTIFYICONDATA);
  1037. nid.hWnd = g_hwndTray;
  1038. nid.uID = g_pCTrayUI->m_uiNextIconId++;
  1039. nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_STATE;
  1040. nid.uCallbackMessage = MYWM_NOTIFYICON;
  1041. nid.hIcon = hiconTray;
  1042. if (fShowBalloon)
  1043. {
  1044. nid.uFlags |= NIF_INFO;
  1045. nid.dwInfoFlags = NIIF_INFO | NIIF_NOSOUND;
  1046. nid.uTimeout = c_dwBalloonTimeoutSeconds * 1000;
  1047. if (lstrlenW(pccfe.GetName()) >= celems(nid.szInfoTitle))
  1048. {
  1049. lstrcpynW(nid.szInfoTitle, pccfe.GetName(),
  1050. celems(nid.szInfoTitle) -
  1051. celems(c_szDotDotDot) - 1);
  1052. lstrcatW(nid.szInfoTitle, c_szDotDotDot);
  1053. }
  1054. else
  1055. {
  1056. lstrcpyW(nid.szInfoTitle, pccfe.GetName());
  1057. }
  1058. if ( (pccfe.GetNetConMediaType() == NCM_LAN) && (pccfe.GetNetConSubMediaType() == NCSM_WIRELESS) )
  1059. {
  1060. lstrcpyW(nid.szInfo, SzLoadIds(IDS_CONTRAY_WIRELESS_DISCONN_BALLOON));
  1061. }
  1062. else
  1063. {
  1064. lstrcpyW(nid.szInfo, SzLoadIds(IDS_CONTRAY_MEDIA_DISCONN_BALLOON));
  1065. }
  1066. }
  1067. hr = HrShell_NotifyIcon(NIM_ADD, &nid);
  1068. if (SUCCEEDED(hr))
  1069. {
  1070. Assert(!pccfe.empty());
  1071. // Update the connection list with the new icon identifier
  1072. //
  1073. hr = g_ccl.HrUpdateTrayIconDataByGuid(
  1074. &(pccfe.GetGuidID()),
  1075. NULL,
  1076. NULL,
  1077. NULL,
  1078. nid.uID);
  1079. if (SUCCEEDED(hr))
  1080. {
  1081. hr = g_ccl.HrUpdateTrayBalloonInfoByGuid(&(pccfe.GetGuidID()), BALLOON_USE_NCS, NULL, NULL);
  1082. }
  1083. TraceTag(ttidSystray, "Successfully added mediadisconnected icon for %S, uiIcon: %d",
  1084. pccfe.GetName(), nid.uID);
  1085. }
  1086. }
  1087. else
  1088. {
  1089. g_ccl.ReleaseWriteLock();
  1090. }
  1091. }
  1092. }
  1093. else
  1094. {
  1095. AssertSz(IsMediaLocalType(pccfe.GetNetConMediaType()) || IsMediaSharedAccessHostType(pccfe.GetNetConMediaType()), "I need a dangling cable, not a phone line");
  1096. }
  1097. }
  1098. else
  1099. {
  1100. TraceTag(ttidSystray, "Preventing the addition of a duplicate media "
  1101. "disconnected icon. uiIcon == %d", uiIcon);
  1102. }
  1103. ReleaseTrayIconLock(&(pccfe.GetGuidID()));
  1104. }
  1105. else
  1106. {
  1107. TraceTag(ttidSystray, "Can't get tray icon lock in HrDoMediaDisconnectedIcon for uiIcon: %d as it has been locked by thread %d", uiIcon, dwLockingThreadId);
  1108. // Someone else is already mucking with this icon
  1109. hr = S_FALSE;
  1110. }
  1111. TraceHr(ttidSystray, FAL, hr, FALSE, "HrDoMediaDisconnectedIcon");
  1112. return hr;
  1113. }
  1114. //+---------------------------------------------------------------------------
  1115. //
  1116. // Function: OnMyWMAddTrayIcon
  1117. //
  1118. // Purpose: Process the status message for the tray window
  1119. //
  1120. // Arguments:
  1121. // hwnd [in]
  1122. // wParam [in] Pointer to CCONFOLDENTRY.
  1123. // lParam [in] TRUE if we are to briefly show the balloon.
  1124. //
  1125. // Returns:
  1126. //
  1127. // Author:
  1128. //
  1129. // Notes:
  1130. //
  1131. //
  1132. LRESULT OnMyWMAddTrayIcon(HWND hwnd, WPARAM wParam, LPARAM lParam)
  1133. {
  1134. TraceFileFunc(ttidSystray);
  1135. HRESULT hr = S_OK;
  1136. HICON hIcon = NULL;
  1137. INetStatisticsEngine * pnseStats = NULL;
  1138. IConnectionPoint * pcpStat = NULL;
  1139. CConnectionTrayStats * pccts = NULL;
  1140. CONFOLDENTRY pccfe;
  1141. BOOL fStaticIcon = FALSE;
  1142. BOOL fBrieflyShowBalloon = (BOOL) lParam;
  1143. NOTIFYICONDATA nid;
  1144. UINT uiIcon;
  1145. Assert(wParam);
  1146. pccfe.InitializeFromItemIdList(reinterpret_cast<LPCITEMIDLIST>(wParam));
  1147. ::SHFree(reinterpret_cast<LPITEMIDLIST>(wParam));
  1148. Assert(!pccfe.empty());
  1149. Assert(pccfe.FShouldHaveTrayIconDisplayed());
  1150. TraceTag(ttidSystray, "In OnMyWMAddTrayIcon message handler");
  1151. if (pccfe.GetNetConStatus() == NCS_MEDIA_DISCONNECTED)
  1152. {
  1153. hr = HrDoMediaDisconnectedIcon(pccfe, fBrieflyShowBalloon);
  1154. goto Exit;
  1155. }
  1156. // Raid #379459: If logged in as non-admin and incoming, don't show systray icon
  1157. if (FIsUserAdmin() ||
  1158. !(pccfe.GetCharacteristics() & NCCF_INCOMING_ONLY))
  1159. {
  1160. g_ccl.AcquireWriteLock();
  1161. DWORD dwLockingThreadId = 0;
  1162. hr = HrGetTrayIconLock(&(pccfe.GetGuidID()), &uiIcon, &dwLockingThreadId);
  1163. if (S_OK == hr)
  1164. {
  1165. ConnListEntry cle;
  1166. hr = g_ccl.HrFindConnectionByGuid(&(pccfe.GetGuidID()), cle);
  1167. if (S_OK == hr)
  1168. {
  1169. g_ccl.HrUpdateTrayBalloonInfoByGuid(&(pccfe.GetGuidID()), BALLOON_USE_NCS, NULL, NULL);
  1170. g_ccl.ReleaseWriteLock();
  1171. if (uiIcon == BOGUS_TRAY_ICON_ID)
  1172. {
  1173. // Try to load the branded tray icon, if present
  1174. //
  1175. if (pccfe.GetCharacteristics() & NCCF_BRANDED)
  1176. {
  1177. if (cle.pcbi && cle.pcbi->szwTrayIconPath)
  1178. {
  1179. hIcon = (HICON) LoadImage(
  1180. NULL,
  1181. cle.pcbi->szwTrayIconPath,
  1182. IMAGE_ICON,
  1183. 0, 0,
  1184. LR_LOADFROMFILE);
  1185. if (hIcon)
  1186. {
  1187. // When we create the ConTrayStats object, we'll mark it as having
  1188. // a static icon so we don't update it on stat changes.
  1189. //
  1190. fStaticIcon = TRUE;
  1191. }
  1192. }
  1193. }
  1194. // If either the branded icon wasn't present or didn't load, or there
  1195. // was no branding to begin with, load the standard icon
  1196. //
  1197. if (!hIcon)
  1198. {
  1199. INT iConnIcon = IGetCurrentConnectionTrayIconId(pccfe.GetNetConMediaType(), pccfe.GetNetConStatus(), SMDCF_NULL);
  1200. hIcon = g_pCTrayUI->GetCachedHIcon(iConnIcon);
  1201. }
  1202. }
  1203. ZeroMemory (&nid, sizeof(nid));
  1204. nid.cbSize = sizeof(NOTIFYICONDATA);
  1205. nid.hWnd = g_hwndTray;
  1206. nid.uID = g_pCTrayUI->m_uiNextIconId++;
  1207. nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_STATE;
  1208. nid.uCallbackMessage = MYWM_NOTIFYICON;
  1209. nid.hIcon = hIcon;
  1210. // If we're not static, then tell the tray that we're using the cached icons
  1211. //
  1212. if (!fStaticIcon)
  1213. {
  1214. nid.dwState = NIS_SHAREDICON;
  1215. if (IsMediaRASType(pccfe.GetNetConMediaType()) ||
  1216. (NCM_SHAREDACCESSHOST_RAS == pccfe.GetNetConMediaType()) ||
  1217. ( (NCM_LAN == pccfe.GetNetConSubMediaType()) &&
  1218. (NCSM_WIRELESS == pccfe.GetNetConSubMediaType()) )
  1219. )
  1220. {
  1221. nid.dwState |= NIS_SHOWALWAYS;
  1222. }
  1223. nid.dwStateMask = nid.dwState;
  1224. }
  1225. // Create the statistics objects
  1226. //
  1227. hr = HrGetStatisticsEngineForEntry(pccfe, &pnseStats, TRUE);
  1228. if (SUCCEEDED(hr))
  1229. {
  1230. // Advise the interface
  1231. hr = HrGetPcpFromPnse(pnseStats, &pcpStat);
  1232. if (SUCCEEDED(hr))
  1233. {
  1234. INetConnectionStatisticsNotifySink * pncsThis;
  1235. hr = CConnectionTrayStats::CreateInstance (
  1236. pccfe,
  1237. nid.uID,
  1238. fStaticIcon,
  1239. IID_INetConnectionStatisticsNotifySink,
  1240. reinterpret_cast<VOID**>(&pncsThis));
  1241. if (SUCCEEDED(hr))
  1242. {
  1243. pccts = reinterpret_cast<CConnectionTrayStats*>(pncsThis);
  1244. hr = pnseStats->StartStatistics();
  1245. if (SUCCEEDED(hr))
  1246. {
  1247. // Don't release this. We need to store it with
  1248. // the entry so we can UnAdvise later
  1249. //
  1250. hr = pcpStat->Advise(pncsThis, pccts->GetConPointCookie());
  1251. }
  1252. }
  1253. if (fBrieflyShowBalloon)
  1254. {
  1255. if ( (NCS_CONNECTED == pccfe.GetNetConStatus()) ||
  1256. (NCS_AUTHENTICATION_SUCCEEDED == pccfe.GetNetConStatus()) ||
  1257. (NCS_INVALID_ADDRESS == pccfe.GetNetConStatus()) )
  1258. {
  1259. nid.uFlags |= NIF_INFO;
  1260. nid.dwInfoFlags = NIIF_INFO | NIIF_NOSOUND;
  1261. nid.uTimeout = c_dwBalloonTimeoutSeconds * 1000;
  1262. WCHAR szBalloonStr[MAX_PATH];
  1263. UINT idTitle = (NCS_INVALID_ADDRESS == pccfe.GetNetConStatus()) ?
  1264. IDS_BALLOON_UNAVAILABLE : IDS_BALLOON_CONNECTED;
  1265. int dwMaxNameLen = celems(nid.szInfoTitle) - celems(c_szDotDotDot) - lstrlenW(SzLoadIds(IDS_BALLOON_CONNECTED)) - 1;
  1266. DwFormatString(SzLoadIds(idTitle), szBalloonStr, MAX_PATH, pccfe.GetName());
  1267. if (lstrlenW(szBalloonStr) >= dwMaxNameLen)
  1268. {
  1269. lstrcpyW(szBalloonStr, pccfe.GetName()); // Only use the Connection Name
  1270. if (lstrlenW(nid.szInfoTitle) >= dwMaxNameLen) // Still bigger?
  1271. {
  1272. lstrcpynW(nid.szInfoTitle, szBalloonStr, dwMaxNameLen);
  1273. lstrcatW(nid.szInfoTitle, c_szDotDotDot);
  1274. }
  1275. else
  1276. {
  1277. lstrcpyW(nid.szInfoTitle, szBalloonStr);
  1278. }
  1279. }
  1280. else
  1281. {
  1282. lstrcpyW(nid.szInfoTitle, szBalloonStr);
  1283. }
  1284. AssertSz(lstrlenW(nid.szInfoTitle) < celems(nid.szInfoTitle),
  1285. "Balloon tooltip text is too long!");
  1286. if (pccfe.GetNetConStatus() == NCS_INVALID_ADDRESS)
  1287. {
  1288. STATMON_ENGINEDATA* pData = NULL;
  1289. UINT idString = IDS_CONTRAY_ADDRESS_INVALID_BALLOON;
  1290. if (S_OK == pnseStats->GetStatistics(&pData) && pData)
  1291. {
  1292. if (STATIC_ADDR == pData->SMED_DHCP_ADDRESS_TYPE)
  1293. {
  1294. idString = IDS_CONTRAY_STATIC_ADDR_INVALID_BALLON;
  1295. }
  1296. CoTaskMemFree(pData);
  1297. }
  1298. lstrcpynW(nid.szInfo, SzLoadIds(idString), celems(nid.szInfo));
  1299. }
  1300. else
  1301. {
  1302. GetInitialBalloonText(
  1303. pnseStats,
  1304. nid.szInfo,
  1305. celems(nid.szInfo));
  1306. }
  1307. }
  1308. }
  1309. // Add the icon itself.
  1310. //
  1311. TraceTag(ttidSystray, "Adding shared shell icon: uID=%u, hIcon=0x%x",
  1312. nid.uID,
  1313. nid.hIcon);
  1314. hr = HrShell_NotifyIcon(NIM_ADD, &nid);
  1315. if (SUCCEEDED(hr) && pccts)
  1316. {
  1317. Assert(!pccfe.empty());
  1318. // Update the connection list with the new icon identifier
  1319. //
  1320. hr = g_ccl.HrUpdateTrayIconDataByGuid(
  1321. &(pccfe.GetGuidID()),
  1322. pccts,
  1323. pcpStat,
  1324. pnseStats,
  1325. nid.uID);
  1326. if (SUCCEEDED(hr))
  1327. {
  1328. hr = g_ccl.HrUpdateTrayBalloonInfoByGuid(&(pccfe.GetGuidID()), BALLOON_USE_NCS, NULL, NULL);
  1329. }
  1330. }
  1331. ::ReleaseObj(pccts);
  1332. ::ReleaseObj(pcpStat);
  1333. }
  1334. ::ReleaseObj(pnseStats);
  1335. }
  1336. }
  1337. else
  1338. {
  1339. g_ccl.ReleaseWriteLock();
  1340. }
  1341. // Release the lock on the tray icon
  1342. //
  1343. ReleaseTrayIconLock(&(pccfe.GetGuidID()));
  1344. }
  1345. else
  1346. {
  1347. g_ccl.ReleaseWriteLock();
  1348. // Could not obtain an icon lock
  1349. //
  1350. #ifdef DBG
  1351. if (S_FALSE == hr)
  1352. {
  1353. Assert(dwLockingThreadId);
  1354. TraceTag(ttidSystray, "Tray icon locked by thread id %d", dwLockingThreadId);
  1355. }
  1356. else
  1357. {
  1358. TraceTag(ttidError, "Could not obtain tray icon data for connection %S", pccfe.GetName());
  1359. }
  1360. #endif
  1361. hr = S_FALSE;
  1362. }
  1363. }
  1364. else
  1365. {
  1366. // Non-admin, or incoming connection
  1367. //
  1368. hr = S_FALSE;
  1369. }
  1370. Exit:
  1371. TraceHr(ttidSystray, FAL, hr, SUCCEEDED(hr), "OnMyWMAddTrayIcon");
  1372. return 0;
  1373. }
  1374. //+---------------------------------------------------------------------------
  1375. //
  1376. // Function: OnMyRemoveTrayIcon
  1377. //
  1378. // Purpose: Process the status message for the tray window
  1379. //
  1380. // Arguments:
  1381. // hwnd []
  1382. // wParam []
  1383. // lParam []
  1384. //
  1385. // Returns:
  1386. //
  1387. // Author:
  1388. //
  1389. // Notes:
  1390. //
  1391. //
  1392. LRESULT OnMyWMRemoveTrayIcon(HWND hwnd, WPARAM wParam, LPARAM lParam)
  1393. {
  1394. TraceFileFunc(ttidSystray);
  1395. HRESULT hr = E_FAIL;
  1396. GUID * pGuid = reinterpret_cast<GUID *>(lParam);
  1397. NOTIFYICONDATA nid;
  1398. // This is returned from a cle, hence should be locked
  1399. #ifdef VERYSTRICTCOMPILE
  1400. const CTrayIconData * pTrayIconData = reinterpret_cast<const CTrayIconData *>(wParam);
  1401. #else
  1402. CTrayIconData * pTrayIconData = reinterpret_cast<CTrayIconData *>(wParam);
  1403. #endif
  1404. TraceTag(ttidSystray, "In OnMyWMRemoveTrayIcon message handler");
  1405. ZeroMemory (&nid, sizeof(nid));
  1406. nid.cbSize = sizeof(NOTIFYICONDATA);
  1407. nid.hWnd = g_hwndTray;
  1408. // We'll make do if this wasn't passed in. What that means is that we may
  1409. // have a timing window where we are adding and removing these icons
  1410. // at such a rate that the add has occurred before the connection has
  1411. // had a chance to add the previous icon (so we don't know to remove it).
  1412. //
  1413. if (!pTrayIconData)
  1414. {
  1415. TraceTag(ttidSystray, "No tray icon data found, loading from cache");
  1416. Assert(pGuid);
  1417. g_ccl.AcquireWriteLock();
  1418. ConnListEntry cle;
  1419. hr = g_ccl.HrFindConnectionByGuid(pGuid, cle);
  1420. if (S_OK == hr)
  1421. {
  1422. TraceTag(ttidSystray, "Tray icon data found in cache");
  1423. Assert(!cle.empty())
  1424. if (cle.HasTrayIconData())
  1425. {
  1426. TraceTag(ttidSystray, "pTrayIconData was valid");
  1427. pTrayIconData = new CTrayIconData(*cle.GetTrayIconData());
  1428. if (!pTrayIconData)
  1429. {
  1430. g_ccl.ReleaseWriteLock();
  1431. return E_OUTOFMEMORY;
  1432. }
  1433. cle.DeleteTrayIconData();
  1434. g_ccl.HrUpdateConnectionByGuid(pGuid, cle);
  1435. }
  1436. }
  1437. g_ccl.ReleaseWriteLock();
  1438. // This is a copy that we should delete
  1439. //
  1440. delete pGuid;
  1441. pGuid = NULL;
  1442. }
  1443. if (pTrayIconData)
  1444. {
  1445. nid.uID = pTrayIconData->GetTrayIconId();
  1446. TraceTag(ttidSystray, "Removing tray icon with id=%u",
  1447. pTrayIconData->GetTrayIconId() );
  1448. int nCount = 5;
  1449. hr = E_FAIL; // Make sure we get at least one attempt in
  1450. while ((nCount--) && (S_OK != hr))
  1451. {
  1452. hr = HrShell_NotifyIcon(NIM_DELETE, &nid);
  1453. if (E_FAIL == hr)
  1454. {
  1455. TraceTag(ttidSystray, "Tray icon: %d failed in delete via "
  1456. "HrShell_NotifyIcon. Will retry shortly", pTrayIconData->GetTrayIconId() );
  1457. // Raid #370358
  1458. Sleep(500);
  1459. }
  1460. else
  1461. {
  1462. TraceTag(ttidSystray, "Tray icon: %d removed succesfully", pTrayIconData->GetTrayIconId());
  1463. }
  1464. }
  1465. // Unadvise the statistics interface
  1466. //
  1467. if (pTrayIconData->GetConnectionPoint() && pTrayIconData->GetConnectionTrayStats() )
  1468. {
  1469. pTrayIconData->GetConnectionPoint()->Unadvise(*pTrayIconData->GetConnectionTrayStats()->GetConPointCookie());
  1470. }
  1471. // Stop the statistics
  1472. //
  1473. if (pTrayIconData->GetNetStatisticsEngine() )
  1474. {
  1475. pTrayIconData->GetNetStatisticsEngine()->StopStatistics();
  1476. }
  1477. // Delete the structure
  1478. //
  1479. delete pTrayIconData;
  1480. }
  1481. TraceHr(ttidSystray, FAL, hr, FALSE, "OnMyWMRemoveTrayIcon");
  1482. return 0;
  1483. }
  1484. //+---------------------------------------------------------------------------
  1485. //
  1486. // Function: OnMyUpdateTrayIcon
  1487. //
  1488. // Purpose: Process the status message for the tray window
  1489. //
  1490. // Arguments:
  1491. // hwnd []
  1492. // wParam []
  1493. // lParam []
  1494. //
  1495. // Returns:
  1496. //
  1497. // Author:
  1498. //
  1499. // Notes:
  1500. //
  1501. //
  1502. LRESULT OnMyWMUpdateTrayIcon(HWND hwnd, WPARAM wParam, LPARAM lParam)
  1503. {
  1504. TraceFileFunc(ttidSystray);
  1505. if (g_pCTrayUI)
  1506. {
  1507. g_pCTrayUI->UpdateTrayIcon((UINT)wParam, (int)lParam);
  1508. }
  1509. return 0;
  1510. }
  1511. //+---------------------------------------------------------------------------
  1512. //
  1513. // Function: OnMyWMShowTrayIconBalloon
  1514. //
  1515. // Purpose: Puts balloon text on the icon for the tray window
  1516. // Change the state of the connection
  1517. //
  1518. // Arguments:
  1519. // hwnd [in]
  1520. // wParam [in]
  1521. // lParam [in] Point to CTrayBalloon structure
  1522. //
  1523. // Returns:
  1524. //
  1525. // Author:
  1526. //
  1527. // Notes:
  1528. //
  1529. //
  1530. LRESULT OnMyWMShowTrayIconBalloon(HWND hwnd, WPARAM wParam, LPARAM lParam)
  1531. {
  1532. TraceFileFunc(ttidSystray);
  1533. HRESULT hr = S_OK;
  1534. HRESULT hrFind = S_OK;
  1535. BOOL fLockHeld = FALSE;
  1536. Assert(lParam);
  1537. if (!lParam)
  1538. {
  1539. return FALSE;
  1540. }
  1541. CTrayBalloon * pTrayBalloon = reinterpret_cast<CTrayBalloon *>(lParam);
  1542. UINT uiIcon;
  1543. DWORD dwLockingThreadId = 0;
  1544. hr = HrGetTrayIconLock(&(pTrayBalloon->m_gdGuid), &uiIcon, &dwLockingThreadId);
  1545. if (S_OK == hr)
  1546. {
  1547. if (uiIcon != BOGUS_TRAY_ICON_ID)
  1548. {
  1549. ConnListEntry cleFind;
  1550. g_ccl.AcquireWriteLock();
  1551. hrFind = g_ccl.HrFindConnectionByGuid(&(pTrayBalloon->m_gdGuid), cleFind);
  1552. if (S_OK == hrFind)
  1553. {
  1554. Assert(!cleFind.ccfe.empty());
  1555. Assert(pTrayBalloon->m_pfnFuncCallback);
  1556. g_ccl.HrUpdateTrayBalloonInfoByGuid(&(pTrayBalloon->m_gdGuid), BALLOON_CALLBACK, pTrayBalloon->m_szCookie, pTrayBalloon->m_pfnFuncCallback);
  1557. g_ccl.ReleaseWriteLock();
  1558. NOTIFYICONDATA nid;
  1559. INT iIconResourceId;
  1560. iIconResourceId = IGetCurrentConnectionTrayIconId(
  1561. cleFind.ccfe.GetNetConMediaType(),
  1562. cleFind.ccfe.GetNetConStatus(),
  1563. 0);
  1564. ZeroMemory (&nid, sizeof(nid));
  1565. nid.cbSize = sizeof(NOTIFYICONDATA);
  1566. nid.hWnd = g_hwndTray;
  1567. nid.uID = uiIcon;
  1568. nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_STATE;
  1569. nid.hIcon = g_pCTrayUI->GetCachedHIcon(iIconResourceId);
  1570. nid.dwState = NIS_SHAREDICON;
  1571. nid.dwStateMask = nid.dwState;
  1572. nid.uCallbackMessage = MYWM_NOTIFYICON;
  1573. // Prepare the balloon data
  1574. nid.uFlags |= NIF_INFO;
  1575. nid.dwInfoFlags = NIIF_INFO | NIIF_NOSOUND;
  1576. nid.uTimeout = pTrayBalloon->m_dwTimeOut;
  1577. if (lstrlenW(cleFind.ccfe.GetName()) >= celems(nid.szInfoTitle))
  1578. {
  1579. lstrcpynW(nid.szInfoTitle, cleFind.ccfe.GetName(),
  1580. celems(nid.szInfoTitle) -
  1581. celems(c_szDotDotDot) - 1);
  1582. lstrcatW(nid.szInfoTitle, c_szDotDotDot);
  1583. }
  1584. else
  1585. {
  1586. lstrcpyW(nid.szInfoTitle, cleFind.ccfe.GetName());
  1587. }
  1588. lstrcpynW(nid.szInfo, pTrayBalloon->m_szMessage, celems(nid.szInfo));
  1589. // Display the balloon
  1590. HrShell_NotifyIcon(NIM_MODIFY, &nid);
  1591. }
  1592. else
  1593. {
  1594. g_ccl.ReleaseWriteLock();
  1595. }
  1596. }
  1597. else
  1598. {
  1599. TraceTag(ttidSystray, "No existing icon data!!!");
  1600. }
  1601. // Release the lock on the tray icon
  1602. //
  1603. ReleaseTrayIconLock(&(pTrayBalloon->m_gdGuid));
  1604. }
  1605. else
  1606. {
  1607. TraceTag(ttidSystray, "Can't get tray icon lock in OnMyWMShowTrayIconBalloon for uiIcon: %d as it has been locked by thread %d", uiIcon, dwLockingThreadId);
  1608. }
  1609. delete pTrayBalloon;
  1610. TraceHr(ttidSystray, FAL, hr, SUCCEEDED(hr), "OnMyWMShowTrayIconBalloon");
  1611. return 0;
  1612. }
  1613. //+---------------------------------------------------------------------------
  1614. //
  1615. // Function: OnMyWMOpenStatus
  1616. //
  1617. // Purpose: Process the status message for the tray window
  1618. //
  1619. // Arguments:
  1620. // hwnd []
  1621. // wParam []
  1622. // lParam []
  1623. //
  1624. // Returns:
  1625. //
  1626. // Author: jeffspr 15 Dec 1997
  1627. //
  1628. // Notes:
  1629. //
  1630. //
  1631. LRESULT OnMyWMOpenStatus(HWND hwnd, WPARAM wParam, LPARAM lParam)
  1632. {
  1633. TraceFileFunc(ttidSystray);
  1634. Assert(wParam);
  1635. CONFOLDENTRY pccfe;
  1636. pccfe.InitializeFromItemIdList(reinterpret_cast<LPCITEMIDLIST>(wParam));
  1637. BOOL fCreateEngine = (BOOL)lParam;
  1638. Assert(!pccfe.empty());
  1639. HRESULT hr;
  1640. ConnListEntry cle;
  1641. hr = g_ccl.HrFindConnectionByGuid(&(pccfe.GetGuidID()), cle);
  1642. if (S_OK == hr)
  1643. {
  1644. if (FHasPermission(NCPERM_Statistics))
  1645. {
  1646. if (!pccfe.empty())
  1647. {
  1648. INetStatisticsEngine* pnseNew;
  1649. hr = HrGetStatisticsEngineForEntry(pccfe, &pnseNew, fCreateEngine);
  1650. if (SUCCEEDED(hr))
  1651. {
  1652. hr = pnseNew->ShowStatusMonitor();
  1653. ReleaseObj(pnseNew);
  1654. }
  1655. else
  1656. {
  1657. TraceTag(ttidSystray,
  1658. "OnMyWMOpenStatus: Statistics Engine for connection %S has been removed."
  1659. "It's ok if this connection is being disconnected", pccfe.GetName());
  1660. }
  1661. }
  1662. }
  1663. }
  1664. return 0;
  1665. }
  1666. LRESULT OnMyWMNotifyIcon(HWND hwnd, UINT uiMessage, WPARAM wParam, LPARAM lParam)
  1667. {
  1668. TraceFileFunc(ttidSystray);
  1669. UINT uiIcon;
  1670. UINT uiMouseMsg;
  1671. uiIcon = (UINT) wParam;
  1672. uiMouseMsg = (UINT) lParam;
  1673. switch (uiMouseMsg)
  1674. {
  1675. case WM_MOUSEMOVE:
  1676. FormatToolTip(hwnd, uiIcon);
  1677. break;
  1678. case WM_RBUTTONUP:
  1679. OnTaskBarIconRButtonUp(hwnd, uiIcon);
  1680. break;
  1681. case NIN_BALLOONUSERCLICK:
  1682. OnTaskBarIconBalloonClick(hwnd, uiIcon);
  1683. break;
  1684. case WM_LBUTTONUP:
  1685. OnTaskBarIconLButtonDblClk(hwnd, uiIcon);
  1686. break;
  1687. }
  1688. return 0;
  1689. }
  1690. VOID OnTaskBarIconRButtonUp(HWND hwnd, UINT uiIcon)
  1691. {
  1692. TraceFileFunc(ttidSystray);
  1693. POINT pt;
  1694. GetCursorPos(&pt);
  1695. (VOID) HrOpenContextMenu(hwnd, &pt, uiIcon);
  1696. }
  1697. //+---------------------------------------------------------------------------
  1698. //
  1699. // Function: OnTaskBarIconLButtonDblClk
  1700. //
  1701. // Purpose: Message handler for the Left-button double click from
  1702. // a tray icon
  1703. //
  1704. // Arguments:
  1705. // hwnd [] Our window handle
  1706. // uiIcon [] Our Icon ID.
  1707. //
  1708. // Returns:
  1709. //
  1710. // Author: jeffspr 12 Jan 1998
  1711. //
  1712. // Notes:
  1713. //
  1714. VOID OnTaskBarIconLButtonDblClk(HWND hwnd, UINT uiIcon)
  1715. {
  1716. TraceFileFunc(ttidSystray);
  1717. HRESULT hr = S_OK;
  1718. if (GetKeyState(VK_SHIFT))
  1719. {
  1720. // Uh, nothing special to do here yet, but just in case...
  1721. }
  1722. // Perform the default context menu action
  1723. // Find the connection info based on the tray icon id.
  1724. //
  1725. ConnListEntry cle;
  1726. hr = g_ccl.HrFindConnectionByTrayIconId(uiIcon, cle);
  1727. if (hr == S_OK)
  1728. {
  1729. Assert(!cle.ccfe.empty());
  1730. if (!cle.ccfe.empty())
  1731. {
  1732. if (cle.ccfe.GetNetConStatus() == NCS_MEDIA_DISCONNECTED)
  1733. {
  1734. if (IsMediaLocalType(cle.ccfe.GetNetConMediaType()) &&
  1735. (NCSM_WIRELESS == cle.ccfe.GetNetConSubMediaType()) )
  1736. {
  1737. PCONFOLDPIDLVEC pcfpVec;
  1738. PCONFOLDPIDL pcfp;
  1739. hr = cle.ccfe.ConvertToPidl(pcfp);
  1740. if (SUCCEEDED(hr))
  1741. {
  1742. pcfpVec.insert(pcfpVec.begin(), pcfp);
  1743. HrOnCommandWZCDlgShow(pcfpVec,
  1744. g_hwndTray,
  1745. NULL);
  1746. }
  1747. }
  1748. else
  1749. {
  1750. hr = HrOpenConnectionsFolder();
  1751. }
  1752. }
  1753. else
  1754. {
  1755. switch(c_idDefaultCMCommand)
  1756. {
  1757. case CMIDM_TRAY_STATUS:
  1758. hr = HrOnCommandStatusInternal(cle.ccfe, FALSE);
  1759. break;
  1760. default:
  1761. AssertSz(FALSE, "Default tray context menu item unhandled");
  1762. break;
  1763. }
  1764. }
  1765. }
  1766. }
  1767. return;
  1768. }
  1769. DWORD WINAPI OnTaskBarIconBalloonClickThread(LPVOID lpParam)
  1770. {
  1771. HRESULT hr = E_FAIL;
  1772. CTrayBalloon *pTrayBalloon = reinterpret_cast<CTrayBalloon *>(lpParam);
  1773. Assert(pTrayBalloon);
  1774. FNBALLOONCLICK *pFNBalloonClick;
  1775. pFNBalloonClick = pTrayBalloon->m_pfnFuncCallback;
  1776. if (pFNBalloonClick)
  1777. {
  1778. hr = (pFNBalloonClick)(&(pTrayBalloon->m_gdGuid), pTrayBalloon->m_szAdapterName, pTrayBalloon->m_szCookie);
  1779. }
  1780. if (E_PENDING == hr)
  1781. {
  1782. MSG msg;
  1783. while (GetMessage (&msg, 0, 0, 0))
  1784. {
  1785. DispatchMessage (&msg);
  1786. }
  1787. hr = S_OK;
  1788. }
  1789. delete pTrayBalloon;
  1790. return hr;
  1791. }
  1792. //+---------------------------------------------------------------------------
  1793. //
  1794. // Function: OnTaskBarIconBalloonClick
  1795. //
  1796. // Purpose: Message handler for the balloon click from
  1797. // a tray icon
  1798. //
  1799. // Arguments:
  1800. // hwnd [] Our window handle
  1801. // uiIcon [] Our Icon ID.
  1802. //
  1803. // Returns:
  1804. //
  1805. // Author: deon 20 Mar 2001
  1806. //
  1807. // Notes:
  1808. //
  1809. VOID OnTaskBarIconBalloonClick(HWND hwnd, UINT uiIcon)
  1810. {
  1811. TraceFileFunc(ttidSystray);
  1812. HRESULT hr = S_OK;
  1813. if (GetKeyState(VK_SHIFT))
  1814. {
  1815. // Uh, nothing special to do here yet, but just in case...
  1816. }
  1817. // Perform the default context menu action
  1818. // Find the connection info based on the tray icon id.
  1819. //
  1820. ConnListEntry cle;
  1821. hr = g_ccl.HrFindConnectionByTrayIconId(uiIcon, cle);
  1822. if (hr == S_OK)
  1823. {
  1824. Assert(!cle.ccfe.empty());
  1825. if (!cle.ccfe.empty())
  1826. {
  1827. if (!cle.GetTrayIconData())
  1828. {
  1829. ASSERT (0);
  1830. }
  1831. switch ((cle.GetTrayIconData())->GetLastBalloonMessage())
  1832. {
  1833. case BALLOON_NOTHING:
  1834. AssertSz(NULL, "You didn't set the balloon");
  1835. break;
  1836. case BALLOON_CALLBACK:
  1837. {
  1838. CTrayBalloon *pTrayBalloon = new CTrayBalloon();
  1839. if (pTrayBalloon)
  1840. {
  1841. pTrayBalloon->m_gdGuid = cle.ccfe.GetGuidID();
  1842. pTrayBalloon->m_szCookie = SysAllocStringByteLen(reinterpret_cast<LPCSTR>(cle.GetTrayIconData()->GetLastBalloonCookie()), SysStringByteLen(cle.GetTrayIconData()->GetLastBalloonCookie()));
  1843. pTrayBalloon->m_pfnFuncCallback = cle.GetTrayIconData()->GetLastBalloonFunction();
  1844. pTrayBalloon->m_dwTimeOut= 0;
  1845. pTrayBalloon->m_szAdapterName = cle.ccfe.GetName();
  1846. CreateThread(NULL, STACK_SIZE_SMALL, OnTaskBarIconBalloonClickThread, pTrayBalloon, 0, NULL);
  1847. }
  1848. }
  1849. break;
  1850. case BALLOON_USE_NCS:
  1851. if (cle.ccfe.GetNetConStatus() == NCS_MEDIA_DISCONNECTED)
  1852. {
  1853. Assert(c_idDefaultDisconCMCommand == CMIDM_OPEN_CONNECTIONS_FOLDER);
  1854. hr = HrOpenConnectionsFolder();
  1855. }
  1856. else
  1857. {
  1858. switch(c_idDefaultCMCommand)
  1859. {
  1860. case CMIDM_TRAY_STATUS:
  1861. hr = HrOnCommandStatusInternal(cle.ccfe, FALSE);
  1862. break;
  1863. default:
  1864. AssertSz(FALSE, "Default tray context menu item unhandled");
  1865. break;
  1866. }
  1867. }
  1868. break;
  1869. default:
  1870. ASSERT (0);
  1871. break;
  1872. }
  1873. }
  1874. }
  1875. return;
  1876. }
  1877. //+---------------------------------------------------------------------------
  1878. //
  1879. // Function: OnMyWMFlushNoop
  1880. //
  1881. // Purpose: Process the MYWM_FLUSHNOOP message for the tray. This is used
  1882. // via SendMessage to clear the tray message queue.
  1883. //
  1884. // Arguments:
  1885. // hwnd [in] Our hwnd
  1886. // wParam [in] Unused
  1887. // lParam [in] Unused
  1888. //
  1889. // Returns:
  1890. //
  1891. // Author: jeffspr 30 Aug 1999
  1892. //
  1893. // Notes:
  1894. //
  1895. LRESULT OnMyWMFlushNoop(HWND hwnd, WPARAM wParam, LPARAM lParam)
  1896. {
  1897. TraceFileFunc(ttidSystray);
  1898. TraceTag(ttidSystray,
  1899. "Tray received tray FLUSH Noop. This should clear the tray message loop");
  1900. return 0;
  1901. }
  1902. //+---------------------------------------------------------------------------
  1903. //
  1904. // Function: FlushTrayPosts
  1905. //
  1906. // Purpose: Flush the tray message queue by doing a SendMessage of a NOOP
  1907. //
  1908. // Arguments:
  1909. // hwnd [in] Where to post to.
  1910. //
  1911. // Returns:
  1912. //
  1913. // Author: jeffspr 8 Sep 1999
  1914. //
  1915. // Notes:
  1916. //
  1917. VOID FlushTrayPosts(HWND hwnd)
  1918. {
  1919. TraceFileFunc(ttidSystray);
  1920. // Flush the tray posts
  1921. //
  1922. SendMessage(hwnd, MYWM_FLUSHNOOP, (WPARAM) 0, (LPARAM) 0);
  1923. }
  1924. BOOL FInitFoldEnumerator(HWND hwnd, DWORD * pdwIconsAdded)
  1925. {
  1926. TraceFileFunc(ttidSystray);
  1927. BOOL fReturn = FALSE;
  1928. HRESULT hr = S_OK;
  1929. CConnectionFolderEnum * pCFEnum = NULL;
  1930. PCONFOLDPIDL pidlCon;
  1931. DWORD dwFetched = 0;
  1932. DWORD dwIconsAdded = 0;
  1933. PCONFOLDPIDLFOLDER pidlFolder;
  1934. NETCFG_TRY
  1935. // Create the IEnumIDList object (CConnectionFolderEnum)
  1936. //
  1937. hr = CConnectionFolderEnum::CreateInstance (
  1938. IID_IEnumIDList,
  1939. (VOID **)&pCFEnum);
  1940. if (SUCCEEDED(hr))
  1941. {
  1942. Assert(pCFEnum);
  1943. // Call the PidlInitialize function to allow the enumeration
  1944. // object to copy the list.
  1945. //
  1946. PCONFOLDPIDLFOLDER pcfpEmpty;
  1947. pCFEnum->PidlInitialize(TRUE, pcfpEmpty, CFCOPT_ENUMALL);
  1948. }
  1949. if (SUCCEEDED(hr))
  1950. {
  1951. while (SUCCEEDED(hr) && (S_FALSE != hr))
  1952. {
  1953. // Clear out the previous results, if any.
  1954. //
  1955. pidlCon.Clear();
  1956. dwFetched = 0;
  1957. // Get the next connection
  1958. //
  1959. LPITEMIDLIST pTempItemIdList;
  1960. hr = pCFEnum->Next(1, &pTempItemIdList, &dwFetched);
  1961. if (S_OK == hr)
  1962. {
  1963. pidlCon.InitializeFromItemIDList(pTempItemIdList);
  1964. const PCONFOLDPIDL& pcfp = pidlCon;
  1965. // If it's not a wizard pidl, then update the
  1966. // icon data.
  1967. //
  1968. if (WIZARD_NOT_WIZARD == pcfp->wizWizard)
  1969. {
  1970. // If the folder pidl hasn't already been loaded
  1971. // then get it
  1972. //
  1973. if (pidlFolder.empty())
  1974. {
  1975. hr = HrGetConnectionsFolderPidl(pidlFolder);
  1976. }
  1977. // Assuming that succeeded (or hr will be S_OK if
  1978. // the HrGet... wasn't called)
  1979. //
  1980. if (SUCCEEDED(hr))
  1981. {
  1982. // Refresh this item -- this will make the desktop shortcuts
  1983. // update to the correct state.
  1984. //
  1985. RefreshFolderItem(pidlFolder, pidlCon, pidlCon, TRUE);
  1986. }
  1987. }
  1988. }
  1989. }
  1990. }
  1991. if (SUCCEEDED(hr))
  1992. {
  1993. // Normalize the return code.
  1994. //
  1995. hr = S_OK;
  1996. fReturn = TRUE;
  1997. // If the caller wants the fetched count
  1998. //
  1999. if (pdwIconsAdded)
  2000. {
  2001. *pdwIconsAdded = dwIconsAdded;
  2002. }
  2003. }
  2004. ReleaseObj(pCFEnum);
  2005. NETCFG_CATCH(hr)
  2006. TraceHr(ttidError, FAL, hr, FALSE, "FInitFoldEnumerator");
  2007. return fReturn;
  2008. }
  2009. HICON CTrayUI::GetCachedHIcon(INT iIconResourceId)
  2010. {
  2011. TraceFileFunc(ttidSystray);
  2012. CExceptionSafeLock esLock(&m_csLock);
  2013. HICON hIcon = m_mapIdToHicon [iIconResourceId];
  2014. if (!hIcon)
  2015. {
  2016. TraceTag(ttidSystray, "Loading HICON for resource id %u and adding it to our map.",
  2017. iIconResourceId);
  2018. hIcon = LoadIcon(_Module.GetResourceInstance(),
  2019. MAKEINTRESOURCE(iIconResourceId));
  2020. //AssertSz (hIcon, "Couldn't load a tray icon. You may ignore this "
  2021. // "assert and a default icon will be used.");
  2022. if (!hIcon)
  2023. {
  2024. hIcon = LoadIcon(_Module.GetResourceInstance(),
  2025. MAKEINTRESOURCE(IDI_LB_GEN_S_16));
  2026. AssertSz (hIcon, "Okay, now you're hosed. Couldn't load the "
  2027. "default icon either. email jeffspr.");
  2028. }
  2029. m_mapIdToHicon [iIconResourceId] = hIcon;
  2030. // Add a hidden icon to the tray so that the shell will cache it.
  2031. //
  2032. NOTIFYICONDATA nid;
  2033. ZeroMemory (&nid, sizeof(nid));
  2034. nid.cbSize = sizeof(NOTIFYICONDATA);
  2035. nid.hWnd = g_hwndTray;
  2036. nid.uID = m_uiNextHiddenIconId--;
  2037. nid.uFlags = NIF_ICON | NIF_STATE;
  2038. nid.hIcon = hIcon;
  2039. nid.dwState = NIS_HIDDEN;
  2040. nid.dwStateMask = nid.dwState;
  2041. /*
  2042. nid.uFlags |= NIF_TIP;
  2043. wsprintfW(nid.szTip, L"hidden: uID=%u, hIcon=0x%x", nid.uID, nid.hIcon);
  2044. */
  2045. TraceTag(ttidSystray, "Adding hidden shell icon: uID=%u, hIcon=0x%x",
  2046. nid.uID,
  2047. nid.hIcon);
  2048. HRESULT hr = HrShell_NotifyIcon(NIM_ADD, &nid);
  2049. if (SUCCEEDED(hr))
  2050. {
  2051. // We can now destroy the icon. This looks weird, but we're only
  2052. // going to use the hIcon for passing to Shell_NotifyIcon again
  2053. // when we add the shared icon with a different uID.
  2054. //
  2055. DestroyIcon(hIcon);
  2056. }
  2057. }
  2058. Assert (hIcon);
  2059. return hIcon;
  2060. }
  2061. VOID CTrayUI::UpdateTrayIcon(UINT uiTrayIconId,
  2062. INT iIconResourceId)
  2063. {
  2064. TraceFileFunc(ttidSystray);
  2065. NOTIFYICONDATA nid;
  2066. ZeroMemory (&nid, sizeof(nid));
  2067. nid.cbSize = sizeof(NOTIFYICONDATA);
  2068. nid.hWnd = g_hwndTray;
  2069. nid.uID = uiTrayIconId;
  2070. nid.uFlags = NIF_ICON | NIF_STATE;
  2071. nid.hIcon = GetCachedHIcon(iIconResourceId);
  2072. nid.dwState = NIS_SHAREDICON;
  2073. nid.dwStateMask = nid.dwState;
  2074. Shell_NotifyIcon(NIM_MODIFY, &nid);
  2075. }
  2076. VOID GetInitialBalloonText(INetStatisticsEngine* pnse,
  2077. PWSTR pszBuf,
  2078. DWORD dwSize)
  2079. {
  2080. TraceFileFunc(ttidSystray);
  2081. *pszBuf = 0;
  2082. if (pnse)
  2083. {
  2084. STATMON_ENGINEDATA* pData = NULL;
  2085. HRESULT hr = pnse->GetStatistics(&pData);
  2086. if (SUCCEEDED(hr) && pData)
  2087. {
  2088. if (pData->SMED_802_11_SSID && pData->SMED_802_11_SIGNAL_STRENGTH)
  2089. {
  2090. DwFormatString(SzLoadIds(IDS_TOOLTIP_WIRELESS_CONNECTED), pszBuf, dwSize,
  2091. pData->SMED_802_11_SSID, PszGetRSSIString(pData->SMED_802_11_SIGNAL_STRENGTH));
  2092. }
  2093. else
  2094. if ((pData->SMED_SPEEDTRANSMITTING>0) || (pData->SMED_SPEEDRECEIVING>0))
  2095. {
  2096. WCHAR pszValue [64];
  2097. // Format the transmitting (and possibly the receiving) speed
  2098. // into the buffer.
  2099. //
  2100. FormatTransmittingReceivingSpeed (
  2101. pData->SMED_SPEEDTRANSMITTING,
  2102. pData->SMED_SPEEDRECEIVING,
  2103. pszValue);
  2104. DwFormatString(SzLoadIds(IDS_TOOLTIP_LINE_SPEED), pszBuf, dwSize, pszValue);
  2105. }
  2106. CoTaskMemFree(pData);
  2107. }
  2108. }
  2109. // Provide a default.
  2110. //
  2111. if (!*pszBuf)
  2112. {
  2113. lstrcpyW(pszBuf, SzLoadIds(IDS_CONTRAY_INITIAL_BALLOON));
  2114. }
  2115. }
  2116. //+---------------------------------------------------------------------------
  2117. //
  2118. // Function: HrAddTrayExtension
  2119. //
  2120. // Purpose: Add the tray extension to the Shell's delay load key
  2121. //
  2122. // Arguments:
  2123. // (none)
  2124. //
  2125. // Returns:
  2126. //
  2127. // Author: jeffspr 28 Jul 1998
  2128. //
  2129. // Notes:
  2130. //
  2131. HRESULT HrAddTrayExtension()
  2132. {
  2133. TraceFileFunc(ttidSystray);
  2134. HRESULT hr = S_OK;
  2135. HKEY hkeyDelayLoad = NULL;
  2136. hr = HrRegCreateKeyEx(HKEY_LOCAL_MACHINE, c_szDelayLoadKey,
  2137. REG_OPTION_NON_VOLATILE, KEY_WRITE,
  2138. NULL, &hkeyDelayLoad, NULL);
  2139. if (SUCCEEDED(hr))
  2140. {
  2141. hr = HrRegSetString(hkeyDelayLoad, c_szDelayLoadName, c_szDelayLoadClassID);
  2142. RegCloseKey(hkeyDelayLoad);
  2143. }
  2144. TraceHr(ttidSystray, FAL, hr, FALSE, "HrAddTrayExtension");
  2145. return hr;
  2146. }
  2147. //+---------------------------------------------------------------------------
  2148. //
  2149. // Function: HrRemoveTrayExtension
  2150. //
  2151. // Purpose: Remove the tray extension from the shell's delay load key
  2152. //
  2153. // Arguments:
  2154. // (none)
  2155. //
  2156. // Returns:
  2157. //
  2158. // Author: jeffspr 28 Jul 1998
  2159. //
  2160. // Notes:
  2161. //
  2162. HRESULT HrRemoveTrayExtension()
  2163. {
  2164. TraceFileFunc(ttidSystray);
  2165. HRESULT hr = S_OK;
  2166. HKEY hkeyDelayLoad = NULL;
  2167. hr = HrRegCreateKeyEx(HKEY_LOCAL_MACHINE, c_szDelayLoadKey,
  2168. REG_OPTION_NON_VOLATILE, KEY_WRITE,
  2169. NULL, &hkeyDelayLoad, NULL);
  2170. if (SUCCEEDED(hr))
  2171. {
  2172. (void) HrRegDeleteValue(hkeyDelayLoad, c_szDelayLoadName);
  2173. RegCloseKey(hkeyDelayLoad);
  2174. }
  2175. TraceHr(ttidSystray, FAL, hr, FALSE, "HrRemoveTrayExtension");
  2176. return hr;
  2177. }