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.

1461 lines
37 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: T M A I N . C P P
  7. //
  8. // Contents: Main code for UPnP Shell tray object
  9. //
  10. // Notes:
  11. //
  12. // Author: jeffspr 19 Jan 2000
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include <upscmn.h>
  18. #include "tfind.h"
  19. #include <ncreg.h>
  20. #include <ncfile.h>
  21. #include <lm.h>
  22. #include "clist.h"
  23. #include "clistndn.h"
  24. #include "tconst.h"
  25. DWORD g_dwDeviceFinderCookie = 0;
  26. LONG g_lFindData = 0;
  27. const TCHAR c_szUPnPDeviceList[] = TEXT("PersistedDeviceUDNs");
  28. const DWORD c_dwTimeout = 10000;
  29. CONST TCHAR c_szMainWindowClassName[] = TEXT("UPnP Notification Monitor");
  30. CONST TCHAR c_szMainWindowTitle[] = TEXT("UPnP Notification Monitor");
  31. CONST TCHAR c_szNameMap[] = TEXT("FriendlyNames");
  32. UINT g_iTotalBalloons = 0;
  33. BOOL g_fTrayPresent = FALSE;
  34. BOOL g_fCoInitialized = FALSE;
  35. HWND g_hwnd = NULL;
  36. BOOL g_fDialogLaunched = FALSE;
  37. BOOL g_fSearchInProgress = FALSE;
  38. VOID OpenContextMenu(HWND hwnd, POINT * pPoint);
  39. VOID OnTaskBarIconRButtonUp(HWND hwnd);
  40. VOID DeInitTrayData(VOID);
  41. LRESULT CALLBACK DiscoveredDevicesDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  42. VOID AddTrayIcon(HWND hwnd, INT iDevices, PTSTR szName)
  43. {
  44. NOTIFYICONDATA nid = {0};
  45. INT iTrayID = IDI_TRAYICON;
  46. HICON hiconTray = LoadIcon(_Module.GetResourceInstance(),
  47. MAKEINTRESOURCE(IDI_TRAYICON));
  48. if (hiconTray)
  49. {
  50. nid.uID = 0;
  51. nid.cbSize = sizeof(NOTIFYICONDATA);
  52. nid.hWnd = hwnd;
  53. nid.uCallbackMessage = WM_USER_TRAYCALLBACK;
  54. nid.hIcon = hiconTray;
  55. nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_INFO;
  56. nid.uTimeout = c_dwTimeout;
  57. nid.dwInfoFlags = NIIF_INFO;
  58. TCHAR * szTitle = NULL;
  59. TCHAR * szInfo = NULL;
  60. TCHAR * szInstructions = NULL;
  61. if (iDevices == 1)
  62. {
  63. _tcsncpy(nid.szInfoTitle, szName, celems(nid.szInfoTitle));
  64. nid.szInfoTitle[celems(nid.szInfoTitle) - 1] = TEXT('\0');
  65. szInfo = TszFromWsz(WszLoadIds(IDS_UPNPTRAYUI_VIEWINFO_1));
  66. if(szInfo)
  67. _tcscpy(nid.szInfo, szInfo);
  68. else
  69. {
  70. TraceTag(ttidShellFolder, "AddTrayIcon:"
  71. "Memory Allocation Failed");
  72. }
  73. }
  74. else
  75. {
  76. szTitle = TszFromWsz(WszLoadIds(IDS_UPNPTRAYUI_DEVICES_DISCOVERED));
  77. if(szTitle)
  78. _tcscpy(nid.szInfoTitle, szTitle);
  79. else
  80. {
  81. TraceTag(ttidShellFolder, "AddTrayIcon:"
  82. "Memory Allocation Failed");
  83. }
  84. szInfo = TszFromWsz(WszLoadIds(IDS_UPNPTRAYUI_VIEWINFO_N));
  85. if(szInfo)
  86. _tcscpy(nid.szInfo, szInfo);
  87. else
  88. {
  89. TraceTag(ttidShellFolder, "AddTrayIcon:"
  90. "Memory Allocation Failed");
  91. }
  92. };
  93. szInstructions = TszFromWsz(WszLoadIds(IDS_UPNPTRAYUI_INSTRUCTIONS));
  94. if(szInstructions)
  95. _tcscpy(nid.szTip, szInstructions);
  96. else
  97. {
  98. TraceTag(ttidShellFolder, "AddTrayIcon:"
  99. "Memory Allocation Failed");
  100. }
  101. delete szTitle;
  102. delete szInfo;
  103. delete szInstructions;
  104. g_iTotalBalloons++;
  105. }
  106. g_fTrayPresent = Shell_NotifyIcon(NIM_ADD, &nid);
  107. if (g_fTrayPresent)
  108. {
  109. g_fDialogLaunched = FALSE;
  110. }
  111. }
  112. //+---------------------------------------------------------------------------
  113. //
  114. // Function: ForceTrayBalloon
  115. //
  116. // Purpose: Force the tray balloon to come back up because the user
  117. // hasn't yet touched it.
  118. //
  119. // Arguments:
  120. // hwnd [in] Our tray window
  121. //
  122. // Returns:
  123. //
  124. // Author: jeffspr 28 Jan 2000
  125. //
  126. // Notes:
  127. //
  128. VOID ForceTrayBalloon(HWND hwnd, INT iDevices, PTSTR szName)
  129. {
  130. NOTIFYICONDATA nid ={0};
  131. nid.uID = 0;
  132. nid.cbSize = sizeof(NOTIFYICONDATA);
  133. nid.hWnd = hwnd;
  134. nid.uFlags = NIF_INFO;
  135. nid.uTimeout = c_dwTimeout;
  136. nid.dwInfoFlags = NIIF_INFO;
  137. TCHAR * szTitle = NULL;
  138. TCHAR * szInfo = NULL;
  139. TCHAR * szInstructions = NULL;
  140. if (iDevices == 1)
  141. {
  142. _tcsncpy(nid.szInfoTitle, szName, celems(nid.szInfoTitle));
  143. nid.szInfoTitle[celems(nid.szInfoTitle) - 1] = TEXT('\0');
  144. szInfo = TszFromWsz(WszLoadIds(IDS_UPNPTRAYUI_VIEWINFO_1));
  145. if(szInfo)
  146. _tcscpy(nid.szInfo, szInfo);
  147. else
  148. {
  149. TraceTag(ttidShellFolder, "ForceTrayBalloon:"
  150. "Memory Allocation Failed");
  151. }
  152. }
  153. else
  154. {
  155. szTitle = TszFromWsz(WszLoadIds(IDS_UPNPTRAYUI_DEVICES_DISCOVERED));
  156. if(szTitle)
  157. _tcscpy(nid.szInfoTitle, szTitle);
  158. else
  159. {
  160. TraceTag(ttidShellFolder, "ForceTrayBalloon:"
  161. "Memory Allocation Failed");
  162. }
  163. szInfo = TszFromWsz(WszLoadIds(IDS_UPNPTRAYUI_VIEWINFO_N));
  164. if(szInfo)
  165. _tcscpy(nid.szInfo, szInfo);
  166. else
  167. {
  168. TraceTag(ttidShellFolder, "ForceTrayBalloon:"
  169. "Memory Allocation Failed");
  170. }
  171. };
  172. szInstructions = TszFromWsz(WszLoadIds(IDS_UPNPTRAYUI_INSTRUCTIONS));
  173. if(szInstructions)
  174. _tcscpy(nid.szTip, szInstructions);
  175. else
  176. {
  177. TraceTag(ttidShellFolder, "ForceTrayBalloon:"
  178. "Memory Allocation Failed");
  179. }
  180. delete szTitle;
  181. delete szInfo;
  182. delete szInstructions;
  183. g_iTotalBalloons++;
  184. g_fTrayPresent = Shell_NotifyIcon(NIM_MODIFY, &nid);
  185. }
  186. //+---------------------------------------------------------------------------
  187. //
  188. // Function: RemoveTrayIcon
  189. //
  190. // Purpose: Remove the UPNP Monitor icon from the tray. This is done when
  191. // the devices dialog has gone away.
  192. //
  193. // Arguments:
  194. // hwnd [in] Our tray window
  195. //
  196. // Returns:
  197. //
  198. // Author: jeffspr 28 Jan 2000
  199. //
  200. // Notes:
  201. //
  202. VOID RemoveTrayIcon(HWND hwnd)
  203. {
  204. if (g_fTrayPresent)
  205. {
  206. NOTIFYICONDATA nid = {0};
  207. nid.uID = 0;
  208. nid.cbSize = sizeof(NOTIFYICONDATA);
  209. nid.hWnd = hwnd;
  210. nid.uCallbackMessage = WM_USER_TRAYCALLBACK;
  211. nid.uFlags = 0;
  212. g_fTrayPresent = !(Shell_NotifyIcon(NIM_DELETE, &nid));
  213. }
  214. }
  215. //+---------------------------------------------------------------------------
  216. //
  217. // Function: HrCreateShortcut
  218. //
  219. // Purpose: Create a shortcut for the item passed in.
  220. //
  221. // Arguments:
  222. // lpszExe [in] What this is a shortcut to.
  223. // lpszLink [in] The file location for the shortcut
  224. // lpszDesc [in] Description (name that will appear)
  225. //
  226. // Returns:
  227. //
  228. // Author: jeffspr 13 Jan 2000
  229. //
  230. // Notes:
  231. //
  232. HRESULT HrCreateShortcut (HWND hwnd, LPCTSTR lpszLink, LPCTSTR szUdn)
  233. {
  234. HRESULT hr = S_OK;
  235. IShellFolder * psfDeskTop = NULL;
  236. LPWSTR wszUdn = NULL;
  237. LPWSTR wszLink = NULL;
  238. wszUdn = WszFromTsz(szUdn);
  239. wszLink = WszFromTsz(lpszLink);
  240. if (!wszUdn || !wszLink)
  241. {
  242. hr = E_OUTOFMEMORY;
  243. goto Error;
  244. }
  245. CoInitialize(NULL);
  246. // Create a pidl for the connection
  247. //
  248. // (tongl 2/16/00): we are now a delegated folder, the pidl must be constructed
  249. // within the IShellFolder object using the allocator set by IDelegate.
  250. // We call parseDisplayName giving the UDN to get the absolute pidl
  251. // (i.e. including the pidl for any parent folders)
  252. //
  253. hr = SHGetDesktopFolder(&psfDeskTop);
  254. if (SUCCEEDED(hr))
  255. {
  256. Assert(psfDeskTop);
  257. LPITEMIDLIST pidlFull = NULL;
  258. LPWSTR pszNotifyString;
  259. pszNotifyString = CreateChangeNotifyString(wszUdn);
  260. if (pszNotifyString)
  261. {
  262. hr = psfDeskTop->ParseDisplayName( NULL, // hwndOwner
  263. NULL, // pbcReserved
  264. pszNotifyString, // lpszDisplayName
  265. NULL, // pchEaten,
  266. &pidlFull, // ppidl,
  267. NULL // pdwAttributes
  268. );
  269. delete [] pszNotifyString;
  270. }
  271. else
  272. {
  273. hr = E_OUTOFMEMORY;
  274. }
  275. if (SUCCEEDED(hr))
  276. {
  277. Assert(pidlFull);
  278. IShellLink *psl = NULL;
  279. hr = CoCreateInstance(CLSID_ShellLink, NULL,
  280. CLSCTX_INPROC_SERVER,
  281. IID_IShellLink, (LPVOID*)&psl);
  282. if (SUCCEEDED(hr))
  283. {
  284. IPersistFile *ppf = NULL;
  285. // Set the combined IDL
  286. //
  287. hr = psl->SetIDList(pidlFull);
  288. if (SUCCEEDED(hr))
  289. {
  290. hr = psl->QueryInterface(IID_IPersistFile,
  291. (LPVOID *)&ppf);
  292. if (SUCCEEDED(hr))
  293. {
  294. // Create the link file.
  295. //
  296. hr = ppf->Save(wszLink, TRUE);
  297. ReleaseObj(ppf);
  298. }
  299. }
  300. ReleaseObj(psl);
  301. }
  302. FreeIDL(pidlFull);
  303. }
  304. ReleaseObj(psfDeskTop);
  305. }
  306. Error:
  307. free(wszUdn);
  308. free(wszLink);
  309. TraceError("HrCreateShortcut", hr);
  310. return hr;
  311. }
  312. //+---------------------------------------------------------------------------
  313. //
  314. // Function: OnTrayViewDevices
  315. //
  316. // Purpose: If one new device in the list, bring up dialog to create
  317. // shortcut. In either case bring up NetworkNeighborhood
  318. // folder.
  319. //
  320. // Arguments:
  321. // hwnd [in] Our parent hwnd.
  322. //
  323. // Returns:
  324. //
  325. // Author: tongl 25 Feb 2000
  326. //
  327. // Notes:
  328. //
  329. VOID OnTrayViewDevices(HWND hwnd)
  330. {
  331. if (g_fDialogLaunched)
  332. return;
  333. g_fDialogLaunched = TRUE;
  334. RemoveTrayIcon(g_hwnd);
  335. NewDeviceNode * pNDN = NULL;
  336. // In any case:
  337. // 1) persist discovered devices so they don't show as new devices
  338. // again
  339. // Walk through the new device list and add them to the known
  340. // device list
  341. //
  342. BOOL fFind = g_CListNewDeviceNode.FFirst(&pNDN);
  343. while (fFind)
  344. {
  345. LPTSTR pszUdn = TszDupTsz(pNDN->pszUDN);
  346. if (pszUdn)
  347. {
  348. BOOL fResult;
  349. fResult = g_CListUDN.FAdd(pszUdn);
  350. if (!fResult)
  351. {
  352. TraceTag(ttidShellFolder,
  353. "OnTrayViewDevices: "
  354. "could not add UDN to g_CListUDN");
  355. delete [] pszUdn;
  356. }
  357. }
  358. else
  359. {
  360. TraceTag(ttidShellFolder,
  361. "OnTrayViewDevices: "
  362. "could not copy UDN");
  363. }
  364. fFind = g_CListNewDeviceNode.FNext(&pNDN);
  365. }
  366. // save the known device list to registry
  367. HrSaveTrayData();
  368. // flush the new devices list
  369. g_CListNewDeviceNode.Flush();
  370. // allow tray icons to be added for new devices
  371. g_fDialogLaunched = FALSE;
  372. // 2) bring up the folder
  373. HrOpenSpecialShellFolder(hwnd, CSIDL_NETWORK);
  374. }
  375. //+---------------------------------------------------------------------------
  376. //
  377. // Function: OnTrayLButtonDown
  378. //
  379. // Purpose: Message processing for an LBUTTONDOWN message on the tray
  380. // icon
  381. //
  382. // Arguments:
  383. // hwnd [in] Our tray window
  384. //
  385. // Returns:
  386. //
  387. // Author: jeffspr 28 Jan 2000
  388. //
  389. // Notes:
  390. //
  391. VOID OnTrayLButtonDown(HWND hwnd)
  392. {
  393. // Otherwise, launch it.
  394. //
  395. OnTrayViewDevices(hwnd);
  396. }
  397. //+---------------------------------------------------------------------------
  398. //
  399. // Function: OnTrayLButtonUp
  400. //
  401. // Purpose: Message processing for an LBUTTONUP message on the tray icon
  402. //
  403. // Arguments:
  404. // hwnd [in] Our tray window
  405. //
  406. // Returns:
  407. //
  408. // Author: jeffspr 28 Jan 2000
  409. //
  410. // Notes:
  411. //
  412. VOID OnTrayLButtonUp(HWND hwnd)
  413. {
  414. // Remove the tray icon since we're loading the dialog box and won't have
  415. // any items to display there anymore.
  416. //
  417. }
  418. //+---------------------------------------------------------------------------
  419. //
  420. // Function: ProcessTrayCallback
  421. //
  422. // Purpose: Message processing for the tray icon callback messages.
  423. // Mostly these are button up/down events
  424. //
  425. // Arguments:
  426. // hwnd [in] Our tray window
  427. // wParam [in] standard tray callback param. see usage below
  428. // lParam [in] standard tray callback param. see usage below
  429. //
  430. // Returns:
  431. //
  432. // Author: jeffspr 28 Jan 2000
  433. //
  434. // Notes:
  435. //
  436. VOID ProcessTrayCallback(
  437. HWND hwnd,
  438. WPARAM wParam,
  439. LPARAM lParam)
  440. {
  441. UINT uID = (UINT) wParam;
  442. UINT uMouseMsg = (UINT) lParam;
  443. DWORD dwError = 0;
  444. switch (uMouseMsg)
  445. {
  446. case WM_LBUTTONDOWN:
  447. OnTrayLButtonDown(hwnd);
  448. break;
  449. case WM_LBUTTONUP:
  450. OnTrayLButtonUp(hwnd);
  451. break;
  452. case WM_RBUTTONUP:
  453. OnTaskBarIconRButtonUp(hwnd);
  454. break;
  455. }
  456. }
  457. //+---------------------------------------------------------------------------
  458. //
  459. // Function: MainWindowProc
  460. //
  461. // Purpose: Main window for the tray monitor
  462. //
  463. // Arguments:
  464. // hwnd [in] Standard
  465. // unMsg [in] Standard
  466. // wParam [in] Standard
  467. // lParam [in] Standard
  468. //
  469. // Returns:
  470. //
  471. // Author: jeffspr 28 Jan 2000
  472. //
  473. // Notes:
  474. //
  475. LRESULT CALLBACK MainWindowProc (
  476. HWND hwnd,
  477. UINT unMsg,
  478. WPARAM wParam,
  479. LPARAM lParam)
  480. {
  481. BOOL fDoDefault = FALSE;
  482. LRESULT lr = 0;
  483. HRESULT hr = S_OK;
  484. switch (unMsg)
  485. {
  486. case WM_CREATE:
  487. g_hwnd = hwnd;
  488. hr = HrInitTrayData();
  489. if (SUCCEEDED(hr))
  490. {
  491. hr = HrStartSearch();
  492. }
  493. break;
  494. case WM_DESTROY:
  495. hr = HrSaveTrayData();
  496. if (SUCCEEDED(hr))
  497. {
  498. RemoveTrayIcon(hwnd);
  499. DeInitTrayData();
  500. }
  501. g_hwnd = NULL;
  502. PostQuitMessage (0);
  503. break;
  504. case WM_USER_TRAYCALLBACK:
  505. ProcessTrayCallback(hwnd, wParam, lParam);
  506. break;
  507. default:
  508. fDoDefault = TRUE;
  509. }
  510. if (fDoDefault)
  511. {
  512. lr = DefWindowProc (hwnd, unMsg, wParam, lParam);
  513. }
  514. return lr;
  515. }
  516. VOID OnTaskBarIconRButtonUp(HWND hwnd)
  517. {
  518. POINT pt;
  519. GetCursorPos(&pt);
  520. OpenContextMenu(hwnd, &pt);
  521. }
  522. #if (WINVER > 0x0400)
  523. VOID SetIconFocus(HWND hwnd)
  524. {
  525. NOTIFYICONDATA nid;
  526. ZeroMemory (&nid, sizeof(nid));
  527. nid.cbSize = sizeof(NOTIFYICONDATA);
  528. nid.hWnd = hwnd;
  529. nid.uID = 0;
  530. Shell_NotifyIcon(NIM_SETFOCUS, &nid);
  531. }
  532. #endif
  533. VOID OpenContextMenu(HWND hwnd, POINT * pPoint)
  534. {
  535. HRESULT hr = S_OK;
  536. INT iCmd = 0;
  537. INT iMenu = 0;
  538. HMENU hmenu = 0;
  539. BOOL fDisconnected = FALSE;
  540. INT iIdCustomMin = -1;
  541. INT iIdCustomMax = -1;
  542. BOOL fBranded = FALSE;
  543. // Find the connection info based on the tray icon id.
  544. //
  545. hmenu = LoadMenu(_Module.GetResourceInstance(),
  546. MAKEINTRESOURCE(POPUP_TRAY));
  547. if (hmenu)
  548. {
  549. // Get the first menu from the popup. For some reason, this hack is
  550. // required instead of tracking on the outside menu
  551. //
  552. HMENU hmenuTrack = GetSubMenu(hmenu, 0);
  553. // Set the default menu item
  554. //
  555. SetMenuDefaultItem(hmenuTrack, CMIDM_TRAY_VIEW_DEVICES, FALSE);
  556. // Set the owner window to be foreground as a hack so the
  557. // popup menu disappears when the user clicks elsewhere.
  558. //
  559. SetForegroundWindow(hwnd);
  560. // Part of the above hack. Bring up the menu and figure out the result
  561. iCmd = TrackPopupMenu(hmenuTrack, TPM_RETURNCMD | TPM_NONOTIFY | TPM_RIGHTBUTTON,
  562. pPoint->x, pPoint->y, 0, hwnd, NULL);
  563. DestroyMenu(hmenu);
  564. MSG msgTmp;
  565. while (PeekMessage(&msgTmp, hwnd, WM_LBUTTONDOWN, WM_LBUTTONUP, PM_REMOVE))
  566. {
  567. DispatchMessage(&msgTmp);
  568. }
  569. // Process the command
  570. //
  571. switch (iCmd)
  572. {
  573. case CMIDM_TRAY_VIEW_DEVICES:
  574. // (TongL) - per design change 2/22/00
  575. OnTrayViewDevices(hwnd);
  576. break;
  577. // Tray menu cancelled without selection
  578. //
  579. case 0:
  580. break;
  581. // Unknown command
  582. //
  583. default:
  584. break;
  585. }
  586. // Shift the focus back to the shell
  587. //
  588. #if (WINVER > 0x0400)
  589. SetIconFocus(hwnd);
  590. #endif
  591. }
  592. }
  593. HWND StartUPnPTray()
  594. {
  595. WNDCLASSEX wcex;
  596. // Register our window class.
  597. //
  598. ZeroMemory (&wcex, sizeof(wcex));
  599. wcex.cbSize = sizeof(wcex);
  600. wcex.style = CS_HREDRAW | CS_VREDRAW;
  601. wcex.lpfnWndProc = MainWindowProc;
  602. wcex.hInstance = _Module.GetResourceInstance();
  603. wcex.hCursor = LoadCursor (NULL, IDC_ARROW);
  604. wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  605. wcex.lpszClassName = c_szMainWindowClassName;
  606. if (RegisterClassEx (&wcex))
  607. {
  608. // Create our main window.
  609. //
  610. HWND hwnd;
  611. hwnd = CreateWindowEx (
  612. 0,
  613. c_szMainWindowClassName,
  614. c_szMainWindowTitle,
  615. WS_OVERLAPPEDWINDOW,
  616. 0, 0, 0, 0,
  617. NULL,
  618. NULL,
  619. _Module.GetResourceInstance(),
  620. NULL);
  621. if (hwnd)
  622. {
  623. ShowWindow (hwnd, SW_HIDE);
  624. return hwnd;
  625. }
  626. }
  627. return NULL;
  628. }
  629. HRESULT HrRegisterInGit(IUnknown *punk, DWORD *pdwCookie)
  630. {
  631. HRESULT hr = S_OK;
  632. IGlobalInterfaceTable * pgit;
  633. pgit = NULL;
  634. hr = CoCreateInstance(CLSID_StdGlobalInterfaceTable,
  635. NULL,
  636. CLSCTX_INPROC_SERVER,
  637. IID_IGlobalInterfaceTable,
  638. (LPVOID*)&pgit);
  639. if (SUCCEEDED(hr))
  640. {
  641. hr = pgit->RegisterInterfaceInGlobal(punk, IID_IUPnPDeviceFinder,
  642. pdwCookie);
  643. pgit->Release();
  644. }
  645. TraceError("HrRegisterInGit", hr);
  646. return hr;
  647. }
  648. HRESULT HrGetDeviceFinderFromGit(IUPnPDeviceFinder **ppdf)
  649. {
  650. HRESULT hr = S_OK;
  651. IGlobalInterfaceTable * pgit;
  652. pgit = NULL;
  653. hr = CoCreateInstance(CLSID_StdGlobalInterfaceTable,
  654. NULL,
  655. CLSCTX_INPROC_SERVER,
  656. IID_IGlobalInterfaceTable,
  657. (LPVOID*)&pgit);
  658. if (SUCCEEDED(hr))
  659. {
  660. hr = pgit->GetInterfaceFromGlobal(g_dwDeviceFinderCookie,
  661. IID_IUPnPDeviceFinder,
  662. (LPVOID *)ppdf);
  663. pgit->Release();
  664. }
  665. TraceError("HrGetDeviceFinderFromGit", hr);
  666. return hr;
  667. }
  668. VOID UnregisterInGit(DWORD dwCookie)
  669. {
  670. HRESULT hr = S_OK;
  671. IGlobalInterfaceTable * pgit;
  672. pgit = NULL;
  673. hr = CoCreateInstance(CLSID_StdGlobalInterfaceTable,
  674. NULL,
  675. CLSCTX_INPROC_SERVER,
  676. IID_IGlobalInterfaceTable,
  677. (LPVOID*)&pgit);
  678. if (SUCCEEDED(hr))
  679. {
  680. hr = pgit->RevokeInterfaceFromGlobal(dwCookie);
  681. pgit->Release();
  682. }
  683. TraceError("HrUnregisterInGit", hr);
  684. }
  685. //+---------------------------------------------------------------------------
  686. //
  687. // Function: HrInitTrayData
  688. //
  689. // Purpose: Load the tray data during app (or service) startup
  690. //
  691. // Arguments:
  692. // (none)
  693. //
  694. // Returns:
  695. //
  696. // Author: jeffspr 9 Dec 1999
  697. //
  698. // Notes:
  699. //
  700. HRESULT HrInitTrayData()
  701. {
  702. HRESULT hr = HrLoadPersistedDevices();
  703. Assert(!g_dwDeviceFinderCookie);
  704. if (!g_fCoInitialized)
  705. {
  706. hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  707. if (SUCCEEDED(hr))
  708. {
  709. g_fCoInitialized = TRUE;
  710. IUPnPDeviceFinder * pdfTray = NULL;
  711. hr = CoCreateInstance(CLSID_UPnPDeviceFinder,
  712. NULL,
  713. CLSCTX_INPROC_SERVER,
  714. IID_IUPnPDeviceFinder,
  715. (void **)&pdfTray);
  716. if (SUCCEEDED(hr))
  717. {
  718. hr = HrRegisterInGit(pdfTray, &g_dwDeviceFinderCookie);
  719. pdfTray->Release();
  720. }
  721. }
  722. }
  723. TraceHr(ttidShellTray, FAL, hr, FALSE, "HrInitTrayData");
  724. return hr;
  725. }
  726. VOID DeInitTrayData()
  727. {
  728. g_CListFolderDeviceNode.Flush();
  729. g_CListNewDeviceNode.Flush();
  730. g_CListUDN.Flush();
  731. g_CListNameMap.Flush();
  732. UnregisterInGit(g_dwDeviceFinderCookie);
  733. if (g_fCoInitialized)
  734. {
  735. CoUninitialize();
  736. }
  737. }
  738. HRESULT HrStartSearch()
  739. {
  740. HRESULT hr = S_OK;
  741. if (!g_fSearchInProgress && g_dwDeviceFinderCookie)
  742. {
  743. CComObject<CUPnPMonitorDeviceFinderCallback> * pCallback = NULL;
  744. TraceTag(ttidShellTray, "DeviceFinderCallback created. Turn on "
  745. "thread id tracing to get useful info");
  746. IUPnPDeviceFinderCallback * pudfc = NULL;
  747. pCallback->CreateInstance(&pCallback);
  748. hr = pCallback->QueryInterface(IID_IUPnPDeviceFinderCallback,
  749. (LPVOID *)&pudfc);
  750. if (S_OK == hr)
  751. {
  752. // Find the devices
  753. //
  754. BSTR bstrFind = NULL;
  755. hr = HrSysAllocString(L"upnp:rootdevice", &bstrFind);
  756. if (SUCCEEDED(hr))
  757. {
  758. LONG lFindData = 0;
  759. IUPnPDeviceFinder * pdfTray = NULL;
  760. hr = HrGetDeviceFinderFromGit(&pdfTray);
  761. if (SUCCEEDED(hr))
  762. {
  763. if (g_lFindData)
  764. {
  765. // Cancel outstanding search first
  766. hr = pdfTray->CancelAsyncFind(g_lFindData);
  767. }
  768. if (SUCCEEDED(hr))
  769. {
  770. hr = pdfTray->CreateAsyncFind(bstrFind, 0, pudfc, &g_lFindData);
  771. if (SUCCEEDED(hr))
  772. {
  773. g_fSearchInProgress = TRUE;
  774. hr = pdfTray->StartAsyncFind(g_lFindData);
  775. if (FAILED(hr))
  776. {
  777. g_fSearchInProgress = FALSE;
  778. }
  779. // This has been handed off to the device finder now
  780. ReleaseObj(pudfc);
  781. }
  782. }
  783. ReleaseObj(pdfTray);
  784. }
  785. ::SysFreeString(bstrFind);
  786. }
  787. }
  788. else
  789. {
  790. hr = E_OUTOFMEMORY;
  791. TraceError("Failed to create callback object in "
  792. "StartUPnPFind", hr);
  793. }
  794. }
  795. else
  796. {
  797. TraceTag(ttidShellTray, "Not starting search again since we are already"
  798. " searching...");
  799. }
  800. TraceError("HrStartSearch", hr);
  801. return hr;
  802. }
  803. HRESULT HrSaveTrayData()
  804. {
  805. HRESULT hr = HrSavePersistedDevices();
  806. TraceHr(ttidShellTray, FAL, hr, FALSE, "HrSaveTrayData");
  807. return hr;
  808. }
  809. //+---------------------------------------------------------------------------
  810. //
  811. // Function: HrOpenUPnPRegRoot
  812. //
  813. // Purpose: Open the UPnP registry root, and return it to the caller
  814. //
  815. // Arguments:
  816. // phkeyRegRoot [out] Return var for HKEY
  817. //
  818. // Returns:
  819. //
  820. // Author: jeffspr 13 Dec 1999
  821. //
  822. // Notes:
  823. //
  824. HRESULT HrOpenUPnPRegRoot(HKEY * phkeyRegRoot)
  825. {
  826. HRESULT hr = S_OK;
  827. HKEY hkeyRegRoot = NULL;
  828. DWORD dwDisposition = 0;
  829. hr = HrRegCreateKeyEx(
  830. HKEY_CURRENT_USER,
  831. c_szUPnPRegRoot,
  832. REG_OPTION_NON_VOLATILE,
  833. KEY_ALL_ACCESS,
  834. NULL,
  835. &hkeyRegRoot,
  836. &dwDisposition);
  837. if (SUCCEEDED(hr))
  838. {
  839. *phkeyRegRoot = hkeyRegRoot;
  840. }
  841. return hr;
  842. }
  843. //+---------------------------------------------------------------------------
  844. //
  845. // Function: HrInputUDNListFromRegistry
  846. //
  847. // Purpose: Import UDN lists from registry.
  848. //
  849. // Arguments:
  850. // hkeyList [in] HKEY to read from
  851. // pszValue [in] Registry value to load
  852. // pCList [in] CList to populate
  853. //
  854. // Returns:
  855. //
  856. // Author: jeffspr 18 Jan 2000
  857. //
  858. // Notes:
  859. //
  860. HRESULT HrInputUDNListFromRegistry(HKEY hkeyList,
  861. LPCTSTR pszValue,
  862. CListString * pCList)
  863. {
  864. HRESULT hr = S_OK;
  865. LPBYTE pbDevices = NULL;
  866. DWORD dwSize = 0;
  867. DWORD dwType = REG_MULTI_SZ;
  868. Assert(hkeyList);
  869. Assert(pszValue);
  870. Assert(pCList);
  871. // Query the multi-sz from our registry location.
  872. //
  873. hr = HrRegQueryValueWithAlloc (
  874. hkeyList,
  875. pszValue,
  876. &dwType,
  877. &pbDevices,
  878. &dwSize);
  879. if (SUCCEEDED(hr))
  880. {
  881. // Walk through the multi-sz and copy into our UDN list
  882. //
  883. TCHAR * pszIterate = (TCHAR *) pbDevices;
  884. while (pszIterate[0] != TEXT('\0'))
  885. {
  886. pCList->FAdd(TszDupTsz(pszIterate));
  887. pszIterate += (_tcslen(pszIterate) + 1);
  888. }
  889. delete pbDevices;
  890. }
  891. else
  892. {
  893. // Ignore this, just means that we don't have any devices listed yet.
  894. //
  895. if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
  896. {
  897. hr = S_OK;
  898. }
  899. }
  900. return hr;
  901. }
  902. //+---------------------------------------------------------------------------
  903. //
  904. // Function: HrInputNameMapFromRegistry
  905. //
  906. // Purpose: Reads the mapping between UDN and friendly name from the
  907. // registry into the given list
  908. //
  909. // Arguments:
  910. // hkeyParent [in] Parent HKEY of UPnP
  911. // pCList [in out] List to add items to
  912. //
  913. // Returns: S_OK if success, E_OUTOFMEMORY if no memory, Win32 error
  914. // otherwise
  915. //
  916. // Author: danielwe 2000/10/25
  917. //
  918. // Notes:
  919. //
  920. HRESULT HrInputNameMapFromRegistry(HKEY hkeyParent, CListNameMap * pCList)
  921. {
  922. HRESULT hr = S_OK;
  923. HKEY hkey;
  924. Assert(hkeyParent);
  925. Assert(pCList);
  926. hr = HrRegOpenKeyEx(hkeyParent, c_szNameMap, KEY_READ, &hkey);
  927. if (SUCCEEDED(hr))
  928. {
  929. WCHAR szValueName[MAX_PATH];
  930. WCHAR szValueData[MAX_PATH];
  931. DWORD cbValueName;
  932. DWORD cbValueData;
  933. DWORD dwIndex = 0;
  934. DWORD dwType;
  935. do
  936. {
  937. cbValueName = MAX_PATH;
  938. cbValueData = MAX_PATH;
  939. // Enumerate each value name
  940. hr = HrRegEnumValue(hkey, dwIndex, szValueName, &cbValueName,
  941. &dwType, (LPBYTE)szValueData, &cbValueData);
  942. if (S_OK == hr)
  943. {
  944. NAME_MAP * pnm;
  945. pnm = new NAME_MAP;
  946. if (pnm)
  947. {
  948. pnm->szName = TszDupTsz(szValueData);
  949. if (!pnm->szName)
  950. {
  951. hr = E_OUTOFMEMORY;
  952. break;
  953. }
  954. pnm->szUdn = TszDupTsz(szValueName);
  955. if (!pnm->szUdn)
  956. {
  957. hr = E_OUTOFMEMORY;
  958. break;
  959. }
  960. pCList->FAdd(pnm);
  961. }
  962. else
  963. {
  964. hr = E_OUTOFMEMORY;
  965. break;
  966. }
  967. }
  968. ++dwIndex;
  969. } while (S_OK == hr);
  970. if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr)
  971. {
  972. hr = S_OK;
  973. }
  974. RegCloseKey(hkey);
  975. }
  976. TraceError("HrInputNameMapFromRegistry", hr);
  977. return hr;
  978. }
  979. //+---------------------------------------------------------------------------
  980. //
  981. // Function: HrSaveNameMapToRegistry
  982. //
  983. // Purpose: Persists the in-memory mapping of UDN to friendly name into
  984. // the registry
  985. //
  986. // Arguments:
  987. // hkeyParent [in] Parent HKEY of UPnP
  988. // pCList [in out] List to add items to
  989. //
  990. // Returns: S_OK if success, E_OUTOFMEMORY if no memory, Win32 error
  991. // otherwise
  992. //
  993. // Author: danielwe 2000/10/25
  994. //
  995. // Notes:
  996. //
  997. HRESULT HrSaveNameMapToRegistry(HKEY hkeyParent, CListNameMap * pCList)
  998. {
  999. HRESULT hr = S_OK;
  1000. HKEY hkey;
  1001. Assert(hkeyParent);
  1002. Assert(pCList);
  1003. hr = HrRegCreateKeyEx(hkeyParent, c_szNameMap, 0, KEY_ALL_ACCESS, NULL,
  1004. &hkey, NULL);
  1005. if (SUCCEEDED(hr))
  1006. {
  1007. BOOL fRet;
  1008. NAME_MAP * pnm;
  1009. fRet = pCList->FFirst(&pnm);
  1010. while (fRet && SUCCEEDED(hr))
  1011. {
  1012. hr = HrRegSetSz(hkey, pnm->szUdn, pnm->szName);
  1013. fRet = pCList->FNext(&pnm);
  1014. }
  1015. RegCloseKey(hkey);
  1016. }
  1017. TraceError("HrSaveNameMapToRegistry", hr);
  1018. return hr;
  1019. }
  1020. //+---------------------------------------------------------------------------
  1021. //
  1022. // Function: HrLoadPersistedDevices
  1023. //
  1024. // Purpose: Load the persisted device list out of the registry
  1025. // and populate our linked lists before we start the
  1026. // UPnP device finder.
  1027. //
  1028. // Arguments:
  1029. // (none)
  1030. //
  1031. // Returns:
  1032. //
  1033. // Author: jeffspr 9 Dec 1999
  1034. //
  1035. // Notes:
  1036. //
  1037. HRESULT HrLoadPersistedDevices()
  1038. {
  1039. HRESULT hr = S_OK;
  1040. HKEY hkeyRegRoot = NULL;
  1041. hr = HrOpenUPnPRegRoot(&hkeyRegRoot);
  1042. if (SUCCEEDED(hr))
  1043. {
  1044. hr = HrInputUDNListFromRegistry(hkeyRegRoot, c_szUPnPDeviceList, &g_CListUDN);
  1045. if (SUCCEEDED(hr))
  1046. {
  1047. hr = HrInputNameMapFromRegistry(hkeyRegRoot, &g_CListNameMap);
  1048. }
  1049. }
  1050. RegSafeCloseKey(hkeyRegRoot);
  1051. TraceHr(ttidShellTray, FAL, hr, FALSE, "HrLoadPersistedDevices");
  1052. return hr;
  1053. }
  1054. //+---------------------------------------------------------------------------
  1055. //
  1056. // Function: HrSaveUDNListToRegistry
  1057. //
  1058. // Purpose: Save a PTSTR CList object to a multi-sz in the given key
  1059. //
  1060. // Arguments:
  1061. // hkeyList [in] Reg key to write to
  1062. // pszValue [in] Reg value name
  1063. // pCList [in] List object to process
  1064. //
  1065. // Returns:
  1066. //
  1067. // Author: jeffspr 19 Jan 2000
  1068. //
  1069. // Notes:
  1070. //
  1071. HRESULT HrSaveUDNListToRegistry(HKEY hkeyList,
  1072. LPCTSTR pszValue,
  1073. CListString * pCList)
  1074. {
  1075. HRESULT hr = S_OK;
  1076. DWORD dwStringSize = 0;
  1077. LPTSTR pszFind = NULL;
  1078. LPBYTE pbBuffer = NULL;
  1079. BOOL fReturn = pCList->FFirst(&pszFind);
  1080. while (fReturn)
  1081. {
  1082. dwStringSize += (_tcslen(pszFind) + 1);
  1083. fReturn = pCList->FNext(&pszFind);
  1084. }
  1085. // If there aren't any items, then we need at least a trailing NULL
  1086. //
  1087. if (dwStringSize == 0)
  1088. {
  1089. dwStringSize++;
  1090. }
  1091. pbBuffer = new BYTE[(dwStringSize+1) * sizeof(TCHAR)];
  1092. if (!pbBuffer)
  1093. {
  1094. TraceTag(ttidShellTray, "Failed to allocate blob for persisted device write");
  1095. hr = E_OUTOFMEMORY;
  1096. }
  1097. else
  1098. {
  1099. LPTSTR pszOffset = (LPTSTR) pbBuffer;
  1100. DWORD dwStringUsedTotal = 0;
  1101. DWORD dwStringUsedTemp = 0;
  1102. pszOffset[0] = TEXT('\0'); // just in case we don't add any items
  1103. fReturn = pCList->FFirst(&pszFind);
  1104. while (fReturn)
  1105. {
  1106. dwStringUsedTemp = (_tcslen(pszFind) + 1);
  1107. dwStringUsedTotal += dwStringUsedTemp;
  1108. Assert(dwStringUsedTotal <= dwStringSize);
  1109. _tcscpy(pszOffset, pszFind);
  1110. pszOffset += dwStringUsedTemp;
  1111. // Set the terminating double-NULL
  1112. //
  1113. pszOffset[0] = TEXT('\0');
  1114. // Get the next item from the list.
  1115. //
  1116. fReturn = pCList->FNext(&pszFind);
  1117. }
  1118. // Make sure we cover the minimal case
  1119. //
  1120. if (dwStringUsedTotal == 0)
  1121. dwStringUsedTotal = 1; // we have at least a double-NULL
  1122. // Save our string back into the registry
  1123. //
  1124. hr = HrRegSetValueEx (
  1125. hkeyList,
  1126. pszValue,
  1127. REG_MULTI_SZ,
  1128. (const BYTE *)pbBuffer,
  1129. (dwStringUsedTotal + 1) * sizeof(TCHAR));
  1130. }
  1131. TraceHr(ttidShellTray, FAL, hr, FALSE, "HrSaveUDNListToRegistry");
  1132. return hr;
  1133. }
  1134. //+---------------------------------------------------------------------------
  1135. //
  1136. // Function: HrSavePersistedDevices
  1137. //
  1138. // Purpose: Write our list back to the registry
  1139. //
  1140. // Arguments:
  1141. // (none)
  1142. //
  1143. // Returns:
  1144. //
  1145. // Author: jeffspr 13 Dec 1999
  1146. //
  1147. // Notes:
  1148. //
  1149. HRESULT HrSavePersistedDevices()
  1150. {
  1151. HRESULT hr = S_OK;
  1152. HKEY hkeyRegRoot = NULL;
  1153. hr = HrOpenUPnPRegRoot(&hkeyRegRoot);
  1154. if (SUCCEEDED(hr))
  1155. {
  1156. hr = HrSaveUDNListToRegistry(hkeyRegRoot, c_szUPnPDeviceList, &g_CListUDN);
  1157. if (SUCCEEDED(hr))
  1158. {
  1159. hr = HrSaveNameMapToRegistry(hkeyRegRoot, &g_CListNameMap);
  1160. }
  1161. }
  1162. RegSafeCloseKey(hkeyRegRoot);
  1163. TraceHr(ttidShellTray, FAL, hr, FALSE, "HrSavePersistedDevices");
  1164. return hr;
  1165. }
  1166. //+---------------------------------------------------------------------------
  1167. //
  1168. // Function: FIsJoinedToDomain
  1169. //
  1170. // Purpose: Returns whether or not the machine is joined to a domain
  1171. //
  1172. // Arguments:
  1173. // (none)
  1174. //
  1175. // Returns: TRUE if joined, FALSE if not
  1176. //
  1177. // Author: danielwe 2001/04/16
  1178. //
  1179. // Notes:
  1180. //
  1181. BOOL FIsJoinedToDomain()
  1182. {
  1183. LPTSTR szDomain;
  1184. NETSETUP_JOIN_STATUS njs;
  1185. if (NERR_Success == NetGetJoinInformation(NULL, &szDomain, &njs))
  1186. {
  1187. NetApiBufferFree(szDomain);
  1188. return !!(njs == NetSetupDomainName);
  1189. }
  1190. return FALSE;
  1191. }
  1192. //+---------------------------------------------------------------------------
  1193. //
  1194. // Function: HrUpdateTrayInfo
  1195. //
  1196. // Purpose: Update the tray as needed. This should get called at the
  1197. // initial SearchComplete and for every new device afterwards
  1198. // to make sure that we have the correct tooltip and add
  1199. // the tray icon again as needed
  1200. //
  1201. // Arguments:
  1202. // (none)
  1203. //
  1204. // Returns:
  1205. //
  1206. // Author: jeffspr 28 Jan 2000
  1207. //
  1208. // Notes:
  1209. //
  1210. HRESULT HrUpdateTrayInfo()
  1211. {
  1212. HRESULT hr = S_OK;
  1213. NewDeviceNode * pNDN = NULL;
  1214. int iElements = 0;
  1215. // retrieve number of new devices pending...
  1216. iElements = g_CListNewDeviceNode.GetCount();
  1217. BOOL fRet = g_CListNewDeviceNode.FFirst(&pNDN);
  1218. TCHAR szDisplayName[MAX_PATH];
  1219. if (fRet)
  1220. {
  1221. _tcscpy(szDisplayName, TEXT(""));
  1222. _tcsncat(szDisplayName, pNDN->pszDisplayName, MAX_PATH - 1);
  1223. }
  1224. // check if we need to add the tray icon
  1225. if (fRet && (iElements > 0) && (!g_fTrayPresent) && (!g_fDialogLaunched))
  1226. {
  1227. if (!FIsJoinedToDomain())
  1228. {
  1229. AddTrayIcon(g_hwnd, iElements, szDisplayName);
  1230. }
  1231. }
  1232. else if ((iElements == 0) && (g_fTrayPresent))
  1233. {
  1234. // no more devices...
  1235. RemoveTrayIcon(g_hwnd);
  1236. }
  1237. TraceHr(ttidShellTray, FAL, hr, FALSE, "HrUpdateTrayInfo");
  1238. return hr;
  1239. }
  1240. //+---------------------------------------------------------------------------
  1241. //
  1242. // Function: HrInitializeUI
  1243. //
  1244. // Purpose: Initialize the tray
  1245. //
  1246. // Arguments:
  1247. // (none)
  1248. //
  1249. // Returns:
  1250. //
  1251. // Author: jeffspr 28 Jan 2000
  1252. //
  1253. // Notes:
  1254. //
  1255. HRESULT HrInitializeUI()
  1256. {
  1257. HRESULT hr = HrUpdateTrayInfo();
  1258. TraceHr(ttidShellTray, FAL, hr, FALSE, "HrInitializeUI");
  1259. return hr;
  1260. }