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.

1496 lines
51 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: S H U T I L . C P P
  7. //
  8. // Contents: Various shell utilities to be used by the connections shell
  9. //
  10. // Notes:
  11. //
  12. // Author: jeffspr 21 Oct 1997
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include <wtypes.h>
  18. #include <ntddndis.h>
  19. #include <ndisprv.h>
  20. #include <devioctl.h>
  21. #include <ndispnp.h>
  22. #include "foldinc.h" // Standard shell\folder includes
  23. #include "ncnetcon.h" // FreeNetconProperties
  24. #include "smcent.h" // Statmon central
  25. #include "ctrayui.h" // For flushing tray messages
  26. extern HWND g_hwndTray;
  27. //+---------------------------------------------------------------------------
  28. //
  29. // Function: HrDupeShellStringLength
  30. //
  31. // Purpose: Duplicate a string using SHAlloc, so we can return it to the
  32. // shell. This is required because the shell typically releases
  33. // the strings that we pass it (so we need to use their
  34. // allocator).
  35. //
  36. // Arguments:
  37. // pszInput [in] String to duplicate
  38. // cchInput [in] Count of characters to copy (not including null term)
  39. // ppszOutput [out] Return pointer for the newly allocated string.
  40. //
  41. // Returns:
  42. //
  43. // Author: jeffspr 21 Oct 1997
  44. //
  45. // Notes:
  46. //
  47. HRESULT HrDupeShellStringLength(
  48. PCWSTR pszInput,
  49. ULONG cchInput,
  50. PWSTR * ppszOutput)
  51. {
  52. HRESULT hr = S_OK;
  53. Assert(pszInput);
  54. Assert(ppszOutput);
  55. ULONG cbString = (cchInput + 1) * sizeof(WCHAR);
  56. // Allocate a new POLESTR block, which the shell can then free.
  57. //
  58. PWSTR pszOutput = (PWSTR) SHAlloc(cbString);
  59. // If the alloc failed, return E_OUTOFMEMORY
  60. //
  61. if (NULL != pszOutput)
  62. {
  63. // Copy the memory into the alloc'd block
  64. //
  65. CopyMemory(pszOutput, pszInput, cbString);
  66. pszOutput[cchInput] = 0;
  67. *ppszOutput = pszOutput;
  68. }
  69. else
  70. {
  71. *ppszOutput = NULL;
  72. hr = E_OUTOFMEMORY;
  73. }
  74. TraceHr(ttidError, FAL, hr, FALSE, "HrDupeShellStringLength");
  75. return hr;
  76. }
  77. //+---------------------------------------------------------------------------
  78. //
  79. // Function: HrLoadPopupMenu
  80. //
  81. // Purpose: Load a popup menu as the first child of a loadable parent
  82. // menu
  83. //
  84. // Arguments:
  85. // hinst [in] Our instance handle
  86. // id [in] ID of the parent menu
  87. // phmenu [out] Return pointer for the popup menu
  88. //
  89. // Returns:
  90. //
  91. // Author: jeffspr 27 Oct 1997
  92. //
  93. // Notes:
  94. //
  95. HRESULT HrLoadPopupMenu(
  96. HINSTANCE hinst,
  97. UINT id,
  98. HMENU * phmenu)
  99. {
  100. HRESULT hr = S_OK;
  101. HMENU hmParent = NULL;
  102. HMENU hmPopup = NULL;
  103. Assert(id);
  104. Assert(hinst);
  105. Assert(phmenu);
  106. // Load the parent menu
  107. //
  108. hmParent = LoadMenu(hinst, MAKEINTRESOURCE(id));
  109. if (NULL == hmParent)
  110. {
  111. AssertSz(FALSE, "Can't load parent menu in HrLoadPopupMenu");
  112. hr = HrFromLastWin32Error();
  113. }
  114. else
  115. {
  116. // Load the popup from the parent (first submenu), then
  117. // remove the parent menu
  118. //
  119. hmPopup = GetSubMenu(hmParent, 0);
  120. RemoveMenu(hmParent, 0, MF_BYPOSITION);
  121. DestroyMenu(hmParent);
  122. }
  123. if (phmenu)
  124. {
  125. *phmenu = hmPopup;
  126. }
  127. TraceHr(ttidError, FAL, hr, FALSE, "HrLoadPopupMenu");
  128. return hr;
  129. }
  130. HRESULT HrGetMenuFromID(
  131. HMENU hmenuMain,
  132. UINT uID,
  133. HMENU * phmenu)
  134. {
  135. HRESULT hr = S_OK;
  136. HMENU hmenuReturn = NULL;
  137. MENUITEMINFO mii;
  138. Assert(hmenuMain);
  139. Assert(uID);
  140. Assert(phmenu);
  141. ZeroMemory(&mii, sizeof(MENUITEMINFO));
  142. mii.cbSize = sizeof(mii);
  143. mii.fMask = MIIM_SUBMENU;
  144. mii.cch = 0; // just in case
  145. if (!GetMenuItemInfo(hmenuMain, uID, FALSE, &mii))
  146. {
  147. hr = E_FAIL;
  148. }
  149. else
  150. {
  151. hmenuReturn = mii.hSubMenu;
  152. }
  153. if (phmenu)
  154. {
  155. *phmenu = mii.hSubMenu;
  156. }
  157. TraceHr(ttidError, FAL, hr, FALSE, "HrGetMenuFromID");
  158. return hr;
  159. }
  160. INT IMergePopupMenus(
  161. HMENU hmMain,
  162. HMENU hmMerge,
  163. int idCmdFirst,
  164. int idCmdLast)
  165. {
  166. HRESULT hr = S_OK;
  167. int iCount = 0;
  168. int idTemp = 0;
  169. int idMax = idCmdFirst;
  170. HMENU hmFromId = NULL;
  171. for (iCount = GetMenuItemCount(hmMerge) - 1; iCount >= 0; --iCount)
  172. {
  173. MENUITEMINFO mii;
  174. mii.cbSize = sizeof(mii);
  175. mii.fMask = MIIM_ID | MIIM_SUBMENU;
  176. mii.cch = 0; // just in case
  177. if (!GetMenuItemInfo(hmMerge, iCount, TRUE, &mii))
  178. {
  179. TraceHr(ttidError, FAL, E_FAIL, FALSE, "GetMenuItemInfo failed in iMergePopupMenus");
  180. continue;
  181. }
  182. hr = HrGetMenuFromID(hmMain, mii.wID, &hmFromId);
  183. if (SUCCEEDED(hr))
  184. {
  185. idTemp = Shell_MergeMenus(
  186. hmFromId,
  187. mii.hSubMenu,
  188. 0,
  189. idCmdFirst,
  190. idCmdLast,
  191. MM_ADDSEPARATOR | MM_SUBMENUSHAVEIDS);
  192. if (idMax < idTemp)
  193. {
  194. idMax = idTemp;
  195. }
  196. }
  197. else
  198. {
  199. TraceHr(ttidError, FAL, E_FAIL, FALSE, "HrGetMenuFromId failed in iMergePopupMenus");
  200. continue;
  201. }
  202. }
  203. return idMax;
  204. }
  205. VOID MergeMenu(
  206. HINSTANCE hinst,
  207. UINT idMainMerge,
  208. UINT idPopupMerge,
  209. LPQCMINFO pqcm)
  210. {
  211. HMENU hmMerge = NULL;
  212. UINT idMax = 0;
  213. UINT idTemp = 0;
  214. Assert(pqcm);
  215. Assert(idMainMerge);
  216. Assert(hinst);
  217. idMax = pqcm->idCmdFirst;
  218. if (idMainMerge
  219. && (SUCCEEDED(HrLoadPopupMenu(hinst, idMainMerge, &hmMerge))))
  220. {
  221. Assert(hmMerge);
  222. if (hmMerge)
  223. {
  224. idMax = Shell_MergeMenus(
  225. pqcm->hmenu,
  226. hmMerge,
  227. pqcm->indexMenu,
  228. pqcm->idCmdFirst,
  229. pqcm->idCmdLast,
  230. MM_SUBMENUSHAVEIDS);
  231. DestroyMenu(hmMerge);
  232. }
  233. }
  234. if (idPopupMerge
  235. && (hmMerge = LoadMenu(hinst, MAKEINTRESOURCE(idPopupMerge))) != NULL)
  236. {
  237. idTemp = IMergePopupMenus(
  238. pqcm->hmenu,
  239. hmMerge,
  240. pqcm->idCmdFirst,
  241. pqcm->idCmdLast);
  242. if (idMax < idTemp)
  243. {
  244. idMax = idTemp;
  245. }
  246. DestroyMenu(hmMerge);
  247. }
  248. pqcm->idCmdFirst = idMax;
  249. }
  250. LPITEMIDLIST ILCombinePriv(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidls);
  251. //+---------------------------------------------------------------------------
  252. //
  253. // Function: GenerateEvent
  254. //
  255. // Purpose: Generate a Shell Notification event.
  256. //
  257. // Arguments:
  258. // lEventId [in] The event ID to post
  259. // pidlFolder [in] Folder pidl
  260. // pidlIn [in] First pidl that we reference
  261. // pidlNewIn [in] If needed, the second pidl.
  262. //
  263. // Returns:
  264. //
  265. // Author: jeffspr 16 Dec 1997
  266. //
  267. // Notes:
  268. //
  269. VOID GenerateEvent(
  270. LONG lEventId,
  271. const PCONFOLDPIDLFOLDER& pidlFolder,
  272. const PCONFOLDPIDL& pidlIn,
  273. LPCITEMIDLIST pidlNewIn)
  274. {
  275. // Build an absolute pidl from the folder pidl + the object pidl
  276. //
  277. LPITEMIDLIST pidl = ILCombinePriv(pidlFolder.GetItemIdList(), pidlIn.GetItemIdList());
  278. if (pidl)
  279. {
  280. // If we have two pidls, call the notify with both
  281. //
  282. if (pidlNewIn)
  283. {
  284. // Build the second absolute pidl
  285. //
  286. LPITEMIDLIST pidlNew = ILCombinePriv(pidlFolder.GetItemIdList(), pidlNewIn);
  287. if (pidlNew)
  288. {
  289. // Make the notification, and free the new pidl
  290. //
  291. SHChangeNotify(lEventId, SHCNF_IDLIST, pidl, pidlNew);
  292. FreeIDL(pidlNew);
  293. }
  294. }
  295. else
  296. {
  297. // Make the single-pidl notification
  298. //
  299. SHChangeNotify(lEventId, SHCNF_IDLIST, pidl, NULL);
  300. }
  301. // Always refresh, then free the newly allocated pidl
  302. //
  303. SHChangeNotifyHandleEvents();
  304. FreeIDL(pidl);
  305. }
  306. }
  307. VOID ForceRefresh(HWND hwnd)
  308. {
  309. TraceFileFunc(ttidShellFolder);
  310. LPSHELLBROWSER psb = FileCabinet_GetIShellBrowser(hwnd);
  311. LPSHELLVIEW psv = NULL;
  312. // Did we get the shellview?
  313. #if 0 // We can't require this, since we may need to refresh without a folder
  314. // actually being open
  315. AssertSz(psb, "FileCabinet_GetIShellBrowser failed in ForceRefresh()");
  316. #endif
  317. if (psb && SUCCEEDED(psb->QueryActiveShellView(&psv)))
  318. {
  319. // Flush our connection list, which will force us to re-enumerate
  320. // on refresh
  321. //
  322. g_ccl.FlushConnectionList();
  323. Assert(psv);
  324. if (psv)
  325. {
  326. psv->Refresh();
  327. psv->Release();
  328. }
  329. }
  330. else
  331. {
  332. // In the case where we don't have a window to go off of, we'll just flush
  333. // and refresh the list.
  334. g_ccl.HrRefreshConManEntries();
  335. }
  336. }
  337. //+---------------------------------------------------------------------------
  338. //
  339. // Function: HrDeleteFromCclAndNotifyShell
  340. //
  341. // Purpose: Remove an object from the connection list and notify the
  342. // shell that it's going away. We call this when a user has
  343. // deleted a connection, and when a disconnect has caused a
  344. // connection to go away (as in an incoming connection)
  345. //
  346. // Arguments:
  347. // pidlFolder [in] Our folder pidl
  348. // pidlConnection [in] The pidl for this connection
  349. // ccfe [in] Our ConFoldEntry
  350. //
  351. // Returns:
  352. //
  353. // Author: jeffspr 22 Jul 1998
  354. //
  355. // Notes:
  356. //
  357. HRESULT HrDeleteFromCclAndNotifyShell(
  358. const PCONFOLDPIDLFOLDER& pidlFolder,
  359. const PCONFOLDPIDL& pidlConnection,
  360. const CONFOLDENTRY& ccfe)
  361. {
  362. HRESULT hr = S_OK;
  363. BOOL fFlushPosts = FALSE;
  364. Assert(!pidlConnection.empty());
  365. Assert(!ccfe.empty());
  366. // Notify the shell that the object has gone away
  367. //
  368. if (!pidlFolder.empty())
  369. {
  370. GenerateEvent(SHCNE_DELETE, pidlFolder, pidlConnection, NULL);
  371. }
  372. if (!ccfe.empty())
  373. {
  374. // Remove this connection from the global list
  375. //
  376. hr = g_ccl.HrRemove(ccfe, &fFlushPosts);
  377. }
  378. // If we need to clear the tray PostMessages due to tray icon changes,
  379. // do so.
  380. //
  381. if (fFlushPosts && g_hwndTray)
  382. {
  383. FlushTrayPosts(g_hwndTray);
  384. }
  385. TraceHr(ttidShellFolder, FAL, hr, FALSE, "HrDeleteFromCclAndNotifyShell");
  386. return hr;
  387. }
  388. //+---------------------------------------------------------------------------
  389. //
  390. // Function: HrUpdateConnectionStatus
  391. //
  392. // Purpose: Update the connection status in the connection list, and perform the
  393. // appropriate tray actions to add/remove the item. Update the shell
  394. //
  395. // Arguments:
  396. // pcfp [in] pidl for this connection
  397. // ncs [in] new connection status
  398. // pidlFolder [in] our folder pidl
  399. // fUseCharacter [in] dwCharacter is valid
  400. // dwCharacter [in] if fUseCharacter was specified as TRUE, update the
  401. // characteristics using this value.
  402. //
  403. // Returns:
  404. //
  405. // Author: jeffspr 28 Aug 1998
  406. //
  407. // Notes:
  408. //
  409. HRESULT HrUpdateConnectionStatus(
  410. const PCONFOLDPIDL& pcfp,
  411. NETCON_STATUS ncs,
  412. const PCONFOLDPIDLFOLDER& pidlFolder,
  413. BOOL fUseCharacter,
  414. DWORD dwCharacter)
  415. {
  416. HRESULT hr = S_OK;
  417. HRESULT hrFind = S_OK;
  418. ConnListEntry cle;
  419. // Raid #310390: If this is a RAS connection, we need to double check the status..
  420. CONFOLDENTRY ccfeDup;
  421. hrFind = g_ccl.HrFindConnectionByGuid(&(pcfp->guidId), cle);
  422. if (S_OK == hrFind)
  423. {
  424. Assert(!cle.ccfe.empty());
  425. if (!cle.ccfe.empty())
  426. {
  427. if ((NCS_DISCONNECTED == ncs) &&
  428. (cle.ccfe.GetCharacteristics() & NCCF_OUTGOING_ONLY))
  429. {
  430. hr = ccfeDup.HrDupFolderEntry(cle.ccfe);
  431. if (FAILED(hr))
  432. {
  433. ccfeDup.clear();
  434. }
  435. }
  436. }
  437. }
  438. if (!ccfeDup.empty())
  439. {
  440. // Raid #310390: If this is a Ras connection, then double check
  441. // the status
  442. HRESULT hrRas = S_OK;
  443. INetConnection * pNetCon = NULL;
  444. hrRas = ccfeDup.HrGetNetCon(IID_INetConnection,
  445. reinterpret_cast<VOID**>(&pNetCon));
  446. if (SUCCEEDED(hrRas))
  447. {
  448. NETCON_PROPERTIES * pProps;
  449. hrRas = pNetCon->GetProperties(&pProps);
  450. if (SUCCEEDED(hrRas))
  451. {
  452. if (ncs != pProps->Status)
  453. {
  454. TraceTag(ttidShellFolder, "Resetting status, notified "
  455. "status: %d, actual status: %d",
  456. ncs, pProps->Status);
  457. ncs = pProps->Status;
  458. }
  459. FreeNetconProperties(pProps);
  460. }
  461. ReleaseObj(pNetCon);
  462. }
  463. }
  464. // MAKE SURE TO -- Release this lock in either find case below
  465. //
  466. g_ccl.AcquireWriteLock();
  467. hrFind = g_ccl.HrFindConnectionByGuid(&(pcfp->guidId), cle);
  468. if (hrFind == S_OK)
  469. {
  470. Assert(!cle.ccfe.empty());
  471. if (!cle.ccfe.empty())
  472. {
  473. cle.ccfe.SetNetConStatus(ncs);
  474. if (fUseCharacter)
  475. {
  476. cle.ccfe.SetCharacteristics(dwCharacter);
  477. }
  478. const GUID ConnectionGuid = pcfp->guidId; // Fix IA64 alignment.
  479. g_ccl.HrUpdateConnectionByGuid(&ConnectionGuid, cle);
  480. }
  481. // Update the tray icon
  482. //
  483. GUID guidId;
  484. guidId = pcfp->guidId;
  485. hr = g_ccl.HrUpdateTrayIconByGuid(&guidId, TRUE);
  486. g_ccl.ReleaseWriteLock();
  487. // Close statistics window if disconnecting
  488. if (NCS_DISCONNECTED == ncs || NCS_MEDIA_DISCONNECTED == ncs)
  489. {
  490. CNetStatisticsCentral * pnsc = NULL;
  491. HRESULT hrStatmon = S_OK;
  492. hrStatmon = CNetStatisticsCentral::HrGetNetStatisticsCentral(&pnsc, FALSE);
  493. if (S_OK == hrStatmon)
  494. {
  495. GUID guidId;
  496. guidId = pcfp->guidId;
  497. pnsc->CloseStatusMonitor(&guidId);
  498. ReleaseObj(pnsc);
  499. }
  500. }
  501. PCONFOLDPIDL pidlUpdated;
  502. cle.ccfe.ConvertToPidl(pidlUpdated);
  503. RefreshFolderItem(pidlFolder, pcfp, pidlUpdated); // Update the folder icon
  504. }
  505. else
  506. {
  507. g_ccl.ReleaseWriteLock();
  508. LPCWSTR pszName = pcfp->PszGetNamePointer();
  509. TraceTag(ttidShellFolder, "HrUpdateConnectionStatus: Connection not found "
  510. "in cache: %S. Connection deleted prior to notification?",
  511. pszName ? pszName : L"<name missing>");
  512. }
  513. TraceHr(ttidShellFolder, FAL, hr, FALSE, "HrUpdateConnectionStatus");
  514. return hr;
  515. }
  516. //+---------------------------------------------------------------------------
  517. //
  518. // Function: HrOnNotifyUpdateStatus
  519. //
  520. // Purpose: Process Connection sink notifications -- Try to make good
  521. // decisions about where we can ignore notifications to prevent
  522. // unnecessary requeries or icon updates.
  523. //
  524. // Arguments:
  525. // pidlFolder [in] The pidl information for our folder.
  526. // pidlCached [in] Pidl generated from our connection cache
  527. // ncsNew [in] The new connection state
  528. //
  529. // Returns:
  530. //
  531. // Author: jeffspr 29 Apr 1999
  532. //
  533. // Notes:
  534. //
  535. HRESULT HrOnNotifyUpdateStatus(
  536. const PCONFOLDPIDLFOLDER& pidlFolder,
  537. const PCONFOLDPIDL& pidlCached,
  538. NETCON_STATUS ncsNew)
  539. {
  540. HRESULT hr = S_OK;
  541. NETCFG_TRY
  542. PCONFOLDPIDL pcfp = pidlCached;
  543. Assert(!pidlCached.empty());
  544. // Filter out the multilink resume case, meaning that we get a
  545. // connecting/connected notification on a link that's already active.
  546. //
  547. if ( (NCS_CONNECTED == pcfp->ncs) &&
  548. ((ncsNew == NCS_CONNECTING) || NCS_CONNECTED == ncsNew))
  549. {
  550. TraceTag(ttidShellFolder, "HrOnNotifyUpdateStatus: Multi-link resume "
  551. "('connecting' while 'connected')");
  552. }
  553. else
  554. {
  555. // If we're in the process of dialing, and the user cancels the
  556. // dialer, we'll get "disconnecting" state. This is normally the
  557. // same as "connected" icon-wise, but if we've never gotten connected,
  558. // we don't want the icon to flash "connected" before going to the
  559. // disconnected state
  560. //
  561. if ((pcfp->ncs == NCS_CONNECTING) && (ncsNew == NCS_DISCONNECTING))
  562. {
  563. TraceTag(ttidShellFolder, "HrOnNotifyUpdateStatus: Ignoring "
  564. "disconnecting notification during cancel of incomplete dial");
  565. }
  566. else
  567. {
  568. // Ignore the update if the connection status hasn't really changed.
  569. //
  570. if (pcfp->ncs != ncsNew)
  571. {
  572. // This is a true state change that we want to show
  573. //
  574. hr = HrUpdateConnectionStatus(pcfp, ncsNew, pidlFolder, FALSE, 0);
  575. }
  576. }
  577. }
  578. NETCFG_CATCH(hr)
  579. return hr;
  580. }
  581. HRESULT HrOnNotifyUpdateConnection(
  582. const PCONFOLDPIDLFOLDER& pidlFolder,
  583. const GUID * pguid,
  584. NETCON_MEDIATYPE ncm,
  585. NETCON_SUBMEDIATYPE ncsm,
  586. NETCON_STATUS ncs,
  587. DWORD dwCharacteristics,
  588. PCWSTR pszwName,
  589. PCWSTR pszwDeviceName,
  590. PCWSTR pszwPhoneNumberOrHostAddress)
  591. {
  592. HRESULT hr = S_OK;
  593. HRESULT hrFind = S_FALSE;
  594. BOOL fIconChanged = FALSE;
  595. NETCFG_TRY
  596. ConnListEntry cle;
  597. PCONFOLDPIDL pidlFind;
  598. PCONFOLDPIDL pidlOld;
  599. PCONFOLDPIDLFOLDER pidlFolderAlloc;
  600. // If the folder pidl wasn't passed in, then we'll go through the hassle of
  601. // getting it ourselves.
  602. //
  603. if (pidlFolder.empty())
  604. {
  605. hr = HrGetConnectionsFolderPidl(pidlFolderAlloc);
  606. if (FAILED(hr))
  607. {
  608. return hr;
  609. }
  610. }
  611. else
  612. {
  613. pidlFolderAlloc = pidlFolder;
  614. }
  615. g_ccl.AcquireWriteLock();
  616. // Find the connection using the GUID. Cast the const away from the GUID
  617. //
  618. hrFind = g_ccl.HrFindConnectionByGuid(pguid, cle);
  619. if (S_OK == hrFind)
  620. {
  621. TraceTag(ttidShellFolder, "Notify: Pre-Update %S, Ncm: %d, Ncs: %d, Char: 0x%08x",
  622. cle.ccfe.GetName(), cle.ccfe.GetNetConMediaType(), cle.ccfe.GetNetConStatus(),
  623. cle.ccfe.GetCharacteristics());
  624. // Did the icon state change?
  625. //
  626. if ((cle.ccfe.GetCharacteristics() & NCCF_SHOW_ICON) !=
  627. (dwCharacteristics & NCCF_SHOW_ICON))
  628. {
  629. fIconChanged = TRUE;
  630. }
  631. // Is this a new "set default" command? If so we need to search for any other defaults and
  632. // unset them first
  633. if ( (dwCharacteristics & NCCF_DEFAULT) &&
  634. !(cle.ccfe.GetCharacteristics() & NCCF_DEFAULT) )
  635. {
  636. PCONFOLDPIDL pidlDefault;
  637. // Not the end of the world if this doesn't work, so use a HrT.
  638. HRESULT hrT = g_ccl.HrUnsetCurrentDefault(pidlDefault);
  639. if (S_OK == hrT)
  640. {
  641. // Let the shell know about the new state of affairs
  642. GenerateEvent(SHCNE_UPDATEITEM, pidlFolderAlloc, pidlDefault, NULL);
  643. }
  644. }
  645. // Save the old version of the pidl for the connection so we can use
  646. // it to determine which notifications we need.
  647. //
  648. CONFOLDENTRY &ccfe = cle.ccfe;
  649. // Very important to release the lock before doing any thing which
  650. // calls back into the shell. (e.g. GenerateEvent)
  651. //
  652. cle.ccfe.ConvertToPidl(pidlOld);
  653. // Save old status so we know whether or not to send the status change
  654. // notifications
  655. //
  656. ccfe.UpdateData(CCFE_CHANGE_MEDIATYPE |
  657. CCFE_CHANGE_STATUS |
  658. CCFE_CHANGE_CHARACTERISTICS |
  659. CCFE_CHANGE_NAME |
  660. CCFE_CHANGE_DEVICENAME |
  661. CCFE_CHANGE_PHONEORHOSTADDRESS,
  662. ncm,
  663. ncsm,
  664. ncs,
  665. dwCharacteristics,
  666. pszwName,
  667. pszwDeviceName,
  668. pszwPhoneNumberOrHostAddress); // NULL means go figure it out yourself...
  669. g_ccl.HrUpdateConnectionByGuid(pguid, cle);
  670. TraceTag(ttidShellFolder, "Notify: Post-Update %S, Ncm: %d, Ncs: %d, Char: 0x%08x, Icon change: %d",
  671. ccfe.GetName(), ccfe.GetNetConMediaType(), ccfe.GetNetConStatus(),
  672. ccfe.GetCharacteristics(),
  673. fIconChanged);
  674. // Get the pidl for the connection so we can use it to notify
  675. // the shell further below.
  676. //
  677. ccfe.ConvertToPidl(pidlFind);
  678. g_ccl.ReleaseWriteLock();
  679. }
  680. else
  681. {
  682. // If the connection wasn't found in the cache, then it's likely that
  683. // the notification engine is giving us a notification for a connection
  684. // that hasn't yet been given to us.
  685. //
  686. g_ccl.ReleaseWriteLock();
  687. if (S_FALSE == hrFind)
  688. {
  689. TraceTag(ttidShellFolder, "Notify: Modify notification received on a connection we don't know about");
  690. }
  691. else
  692. {
  693. TraceTag(ttidShellFolder, "Notify: Modify: Error occurred during find of connection. hr = 0x%08x", hr);
  694. }
  695. }
  696. if (S_OK == hrFind)
  697. {
  698. if ( !(pidlFind.empty() || pidlOld.empty()) )
  699. {
  700. // Don't do the update if the status isn't changing.
  701. //
  702. // Don't want to croak on a bad return code here.
  703. //
  704. (VOID) HrOnNotifyUpdateStatus(pidlFolderAlloc, pidlOld, ncs);
  705. if (fIconChanged)
  706. {
  707. hr = g_ccl.HrUpdateTrayIconByGuid(pguid, TRUE);
  708. TraceTag(ttidShellFolder, "Returned from HrUpdateTrayIconByGuid", hr);
  709. }
  710. GenerateEvent(SHCNE_UPDATEITEM, pidlFolderAlloc, pidlFind, NULL);
  711. }
  712. // Update status monitor title (LAN case)
  713. CNetStatisticsCentral * pnsc = NULL;
  714. HRESULT hrStatmon = S_OK;
  715. hrStatmon = CNetStatisticsCentral::HrGetNetStatisticsCentral(&pnsc, FALSE);
  716. if (S_OK == hrStatmon)
  717. {
  718. pnsc->UpdateTitle(pguid, pszwName);
  719. ReleaseObj(pnsc);
  720. }
  721. }
  722. NETCFG_CATCH(hr)
  723. TraceHr(ttidShellFolder, FAL, hr, FALSE, "HrOnNotifyUpdateConnection");
  724. return hr;
  725. }
  726. BOOL g_fInRefreshAlready = FALSE;
  727. BOOL g_fRefreshAgain = FALSE;
  728. //+---------------------------------------------------------------------------
  729. //
  730. // Function: HrForceRefreshNoFlush
  731. //
  732. // Purpose: Force a refresh, but without wiping out all existing data.
  733. // This lets us keep as much state as possible intact, while
  734. // also letting us remove old items and adding new items (doing
  735. // the correct things with tray icons and such along the way).
  736. //
  737. // Arguments:
  738. // pidlFolder [in] Our folder pidl
  739. //
  740. // Returns:
  741. //
  742. // Author: jeffspr 28 Aug 1999
  743. //
  744. // Notes:
  745. //
  746. HRESULT HrForceRefreshNoFlush(const PCONFOLDPIDLFOLDER& pidlFolder)
  747. {
  748. HRESULT hr = S_OK;
  749. CConnectionList * pccl = NULL;
  750. NETCFG_TRY
  751. PCONFOLDPIDLFOLDER pidlFolderAlloc;
  752. TraceTag(ttidShellFolder, "HrForceRefreshNoFlush");
  753. g_fRefreshAgain = TRUE;
  754. // If we're refreshing, then tell the thread already in here that it
  755. // should refresh again.
  756. //
  757. if (!g_fInRefreshAlready)
  758. {
  759. // This starts out being set, then we'll turn it off. If someone
  760. // turns it back on while we're in this long function, then we'll
  761. // do it again
  762. //
  763. while (g_fRefreshAgain)
  764. {
  765. g_fInRefreshAlready = TRUE; // We're now in refresh
  766. g_fRefreshAgain = FALSE;
  767. if (pidlFolder.empty())
  768. {
  769. hr = HrGetConnectionsFolderPidl(pidlFolderAlloc);
  770. }
  771. else
  772. {
  773. pidlFolderAlloc = pidlFolder;
  774. }
  775. if (SUCCEEDED(hr))
  776. {
  777. // First, create the secondary connection list in order to compare the known
  778. // state with the recently requested refresh state
  779. //
  780. pccl = new CConnectionList();
  781. if (!pccl)
  782. {
  783. hr = E_OUTOFMEMORY;
  784. AssertSz(FALSE, "Couldn't create CConnectionList in HrForceRefreshNoFlush");
  785. }
  786. else
  787. {
  788. PCONFOLDPIDLVEC apidl;
  789. PCONFOLDPIDLVEC apidlCached;
  790. PCONFOLDPIDLVEC::const_iterator iterLoop = 0;
  791. // Initialize the list. FALSE means we don't want to tie this
  792. // list to the tray
  793. //
  794. pccl->Initialize(FALSE, FALSE);
  795. // Retrieve the entries from the connection manager.
  796. //
  797. hr = pccl->HrRetrieveConManEntries(apidl);
  798. if (SUCCEEDED(hr))
  799. {
  800. TraceTag(ttidShellFolder, "HrForceRefreshNoFlush -- %d entries retrieved", apidl.size);
  801. // Loop through the connections. If there are new connections
  802. // here that aren't in the cache, then add them and do the appropriate
  803. // icon updates
  804. //
  805. for (iterLoop = apidl.begin(); iterLoop != apidl.end(); iterLoop++)
  806. {
  807. PCONFOLDPIDL pcfp = *iterLoop;
  808. CONFOLDENTRY ccfe;
  809. // We don't need to update the wizard.
  810. //
  811. if (WIZARD_NOT_WIZARD == pcfp->wizWizard)
  812. {
  813. // Convert to the confoldentry
  814. //
  815. hr = iterLoop->ConvertToConFoldEntry(ccfe);
  816. if (SUCCEEDED(hr))
  817. {
  818. // ConnListEntry cle;
  819. ConnListEntry cleDontCare;
  820. hr = g_ccl.HrFindConnectionByGuid(&(pcfp->guidId), cleDontCare);
  821. if (S_FALSE == hr)
  822. {
  823. if ((ccfe.GetCharacteristics() & NCCF_INCOMING_ONLY) &&
  824. (ccfe.GetNetConStatus() == NCS_DISCONNECTED) && (ccfe.GetNetConMediaType() != NCM_NONE))
  825. {
  826. TraceTag(ttidShellFolder, "Ignoring transient incoming connection (new, but status is disconnected)");
  827. }
  828. else
  829. {
  830. TraceTag(ttidShellFolder, "HrForceRefreshNoFlush -- New connection: %S", ccfe.GetName());
  831. // Insert the connection in the connection list
  832. //
  833. hr = g_ccl.HrInsert(ccfe);
  834. if (SUCCEEDED(hr))
  835. {
  836. // the connection list has taken control of this structure
  837. //
  838. TraceTag(ttidShellFolder,
  839. "HrForceRefreshNoFlush -- successfully added connection to list. Notifying shell");
  840. // don't delete ccfe on success. g_ccl owns it after an
  841. // insert.
  842. //
  843. GenerateEvent(SHCNE_CREATE, pidlFolderAlloc, *iterLoop, NULL);
  844. }
  845. else
  846. {
  847. TraceHr(ttidShellFolder, FAL, hr, FALSE, "HrForceRefreshNoFlush -- Failed to insert connection into shell");
  848. }
  849. }
  850. }
  851. else
  852. {
  853. // Update the connection properties for this connection
  854. //
  855. hr = HrOnNotifyUpdateConnection(
  856. pidlFolderAlloc,
  857. &(ccfe.GetGuidID()),
  858. ccfe.GetNetConMediaType(),
  859. ccfe.GetNetConSubMediaType(),
  860. ccfe.GetNetConStatus(),
  861. ccfe.GetCharacteristics(),
  862. ccfe.GetName(),
  863. ccfe.GetDeviceName(),
  864. ccfe.GetPhoneOrHostAddress());
  865. }
  866. }
  867. }
  868. }
  869. }
  870. else
  871. {
  872. TraceHr(ttidShellFolder, FAL, hr, FALSE,
  873. "HrForceRefreshNoFlush -- Failed to retrieve Conman entries");
  874. }
  875. // Retrieve a pidl list from the connection cache. This should not force a
  876. // reload (which would defeat the purpose of the whole operation).
  877. //
  878. hr = g_ccl.HrRetrieveConManEntries(apidlCached);
  879. if (SUCCEEDED(hr))
  880. {
  881. for (iterLoop = apidlCached.begin(); iterLoop != apidlCached.end(); iterLoop++)
  882. {
  883. CONFOLDENTRY ccfe;
  884. Assert(!iterLoop->empty());
  885. if (!iterLoop->empty())
  886. {
  887. const PCONFOLDPIDL& pcfp = *iterLoop;
  888. // If it's not a wizard pidl, then update the
  889. // icon data.
  890. //
  891. if (WIZARD_NOT_WIZARD == pcfp->wizWizard)
  892. {
  893. ConnListEntry cle;
  894. BOOL fDeadIncoming = FALSE;
  895. hr = pccl->HrFindConnectionByGuid(&(pcfp->guidId), cle);
  896. if (hr == S_OK)
  897. {
  898. DWORD dwChars = cle.ccfe.GetCharacteristics();
  899. NETCON_STATUS ncs = cle.ccfe.GetNetConStatus();
  900. NETCON_MEDIATYPE ncm = cle.ccfe.GetNetConMediaType();
  901. // Figure out whether this is a transient incoming connection
  902. // (enumerated, but disconnected)
  903. //
  904. if ((ncs == NCS_DISCONNECTED) &&
  905. (ncm != NCM_NONE) &&
  906. (dwChars & NCCF_INCOMING_ONLY))
  907. {
  908. fDeadIncoming = TRUE;
  909. }
  910. }
  911. // If it was either not found or is a dead incoming connection
  912. // (disconnected), blow it away from the list.
  913. //
  914. if ((S_FALSE == hr) || (fDeadIncoming))
  915. {
  916. hr = iterLoop->ConvertToConFoldEntry(ccfe);
  917. if (SUCCEEDED(hr))
  918. {
  919. hr = HrDeleteFromCclAndNotifyShell(pidlFolderAlloc,
  920. *iterLoop, ccfe);
  921. // Assuming that succeeded (or hr will be S_OK if
  922. // the HrGet... wasn't called)
  923. //
  924. if (SUCCEEDED(hr))
  925. {
  926. GenerateEvent(SHCNE_DELETE, pidlFolderAlloc,
  927. *iterLoop, NULL);
  928. }
  929. }
  930. }
  931. }
  932. }
  933. }
  934. }
  935. pccl->Uninitialize();
  936. delete pccl;
  937. pccl = NULL;
  938. }
  939. }
  940. if (g_fRefreshAgain)
  941. {
  942. TraceTag(ttidShellFolder, "Looping back for another refresh since g_fRefreshAgain got set");
  943. }
  944. } // end while (g_fRefreshAgain)
  945. // Mark us as not being in the function
  946. //
  947. g_fInRefreshAlready = FALSE;
  948. }
  949. else
  950. {
  951. TraceTag(ttidShellFolder, "Marking for additional refresh and exiting");
  952. }
  953. NETCFG_CATCH(hr)
  954. TraceHr(ttidShellFolder, FAL, hr, FALSE, "HrForceRefreshNoFlush");
  955. return hr;
  956. }
  957. //+---------------------------------------------------------------------------
  958. //
  959. // Function: HrShellView_GetSelectedObjects
  960. //
  961. // Purpose: Get the selected data objects. We only care about the first
  962. // one (we'll ignore the rest)
  963. //
  964. // Arguments:
  965. // hwnd [in] Our window handle
  966. // papidlSelection [out] Return array for selected pidls
  967. // lpcidl [out] Count of returned pidls
  968. //
  969. // Returns: S_OK if 1 or more items are selected.
  970. // S_FALSE if 0 items are selected
  971. // OLE HRESULT otherwise
  972. //
  973. // Author: jeffspr 13 Jan 1998
  974. //
  975. // Notes:
  976. //
  977. HRESULT HrShellView_GetSelectedObjects(
  978. HWND hwnd,
  979. PCONFOLDPIDLVEC& apidlSelection)
  980. {
  981. HRESULT hr = S_OK;
  982. LPCITEMIDLIST * apidl = NULL;
  983. UINT cpidl = 0;
  984. // Get the selected object list from the shell
  985. //
  986. cpidl = ShellFolderView_GetSelectedObjects(hwnd, &apidl);
  987. // If the GetSelectedObjects failed, NULL out the return
  988. // params.
  989. //
  990. if (-1 == cpidl)
  991. {
  992. cpidl = 0;
  993. apidl = NULL;
  994. hr = E_OUTOFMEMORY;
  995. }
  996. else
  997. {
  998. // If no items were selected, return S_FALSE
  999. //
  1000. if (0 == cpidl)
  1001. {
  1002. Assert(!apidl);
  1003. hr = S_FALSE;
  1004. }
  1005. }
  1006. // Fill in the out params
  1007. //
  1008. if (SUCCEEDED(hr))
  1009. {
  1010. hr = PConfoldPidlVecFromItemIdListArray(apidl, cpidl, apidlSelection);
  1011. SHFree(apidl);
  1012. }
  1013. TraceHr(ttidError, FAL, hr, (S_FALSE == hr),
  1014. "HrShellView_GetSelectedObjects");
  1015. return hr;
  1016. }
  1017. //+---------------------------------------------------------------------------
  1018. //
  1019. // Function: HrGetConnectionPidlWithRefresh
  1020. //
  1021. // Purpose: Utility function used by HrCreateDesktopIcon and HrLaunchConnection
  1022. //
  1023. // Arguments:
  1024. // guidId: GUID of the connection
  1025. // ppidlCon: PIDL of the connection, if found
  1026. //
  1027. // Returns: S_OK if succeeded
  1028. // S_FALSE if the GUID does not match any existing connection
  1029. // standard error code otherwise
  1030. //
  1031. // Author: tongl 19 Feb 1999
  1032. //
  1033. // Notes:
  1034. //
  1035. HRESULT HrGetConnectionPidlWithRefresh(const GUID& guidId,
  1036. PCONFOLDPIDL& ppidlCon)
  1037. {
  1038. HRESULT hr = S_OK;
  1039. NETCFG_TRY
  1040. PCONFOLDPIDL pidlCon;
  1041. CConnectionFolderEnum * pCFEnum = NULL;
  1042. DWORD dwFetched = 0;
  1043. // refresh the folder before we enumerate
  1044. PCONFOLDPIDLFOLDER pidlEmpty;
  1045. hr = HrForceRefreshNoFlush(pidlEmpty);
  1046. if (SUCCEEDED(hr))
  1047. {
  1048. // Create the IEnumIDList object (CConnectionFolderEnum)
  1049. //
  1050. hr = CConnectionFolderEnum::CreateInstance (
  1051. IID_IEnumIDList,
  1052. (VOID **)&pCFEnum);
  1053. if (SUCCEEDED(hr))
  1054. {
  1055. Assert(pCFEnum);
  1056. // Call the PidlInitialize function to allow the enumeration
  1057. // object to copy the list.
  1058. //
  1059. pCFEnum->PidlInitialize(TRUE, pidlEmpty, CFCOPT_ENUMALL);
  1060. while (SUCCEEDED(hr) && (S_FALSE != hr))
  1061. {
  1062. // Clear out the previous results, if any.
  1063. //
  1064. dwFetched = 0;
  1065. // Get the next connection
  1066. //
  1067. LPITEMIDLIST pitemIdList;
  1068. hr = pCFEnum->Next(1, &pitemIdList, &dwFetched);
  1069. pidlCon.InitializeFromItemIDList(pitemIdList);
  1070. if (S_OK == hr)
  1071. {
  1072. if (pidlCon->guidId == guidId)
  1073. {
  1074. hr = S_OK;
  1075. ppidlCon = pidlCon;
  1076. break;
  1077. }
  1078. }
  1079. }
  1080. }
  1081. ReleaseObj(pCFEnum);
  1082. }
  1083. NETCFG_CATCH(hr)
  1084. return hr;
  1085. }
  1086. //+---------------------------------------------------------------------------
  1087. //
  1088. // Function: HrRenameConnectionInternal
  1089. //
  1090. // Purpose: The shared portion for renaming a connection through the
  1091. // connections folder UI and the export function
  1092. //
  1093. // Arguments:
  1094. // pszInput [in] String to duplicate
  1095. // cchInput [in] Count of characters to copy (not including null term)
  1096. // ppszOutput [out] Return pointer for the newly allocated string.
  1097. //
  1098. // Returns:
  1099. //
  1100. // Author: tongl 26 May 1999
  1101. //
  1102. // Notes:
  1103. //
  1104. HRESULT HrRenameConnectionInternal(
  1105. const PCONFOLDPIDL& pidlCon,
  1106. const PCONFOLDPIDLFOLDER& pidlFolderRoot,
  1107. LPCWSTR pszNewName,
  1108. BOOL fRaiseError,
  1109. HWND hwndOwner,
  1110. PCONFOLDPIDL& ppidlOut)
  1111. {
  1112. HRESULT hr = S_OK;
  1113. NETCFG_TRY
  1114. INetConnection * pNetCon = NULL;
  1115. PCONFOLDPIDL pidlNew;
  1116. BOOL fRefresh = FALSE;
  1117. BOOL fActivating = FALSE;
  1118. CONFOLDENTRY ccfe;
  1119. PCWSTR pszReservedName;
  1120. if (fRaiseError)
  1121. {
  1122. Assert(hwndOwner);
  1123. }
  1124. Assert(FImplies(fRaiseError,IsWindow(hwndOwner)));
  1125. Assert(pszNewName);
  1126. if ( (pidlCon.empty()) || !pszNewName )
  1127. {
  1128. hr = E_INVALIDARG;
  1129. }
  1130. else
  1131. {
  1132. hr = pidlCon.ConvertToConFoldEntry(ccfe);
  1133. if (SUCCEEDED(hr))
  1134. {
  1135. // Do a case sensitive compare to see if the new name is exactly
  1136. // the same as the old one. If yes then, we ignore renaming.
  1137. //
  1138. if (lstrcmpW(ccfe.GetName(), pszNewName) == 0)
  1139. {
  1140. hr = S_FALSE;
  1141. // Create a dupe pidl, if needed
  1142. if (!ppidlOut.empty())
  1143. {
  1144. pidlNew.ILClone(pidlCon);
  1145. }
  1146. }
  1147. else
  1148. {
  1149. // New name is either completely different from the old one or
  1150. // differs just in the case.
  1151. //
  1152. CONFOLDENTRY cfEmpty;
  1153. hr = HrCheckForActivation(pidlCon, cfEmpty, &fActivating);
  1154. if (S_OK == hr)
  1155. {
  1156. if (fActivating)
  1157. {
  1158. // You can't rename an activating connection
  1159. //
  1160. TraceTag(ttidShellFolder, "Can not rename an activating connection");
  1161. hr = E_FAIL;
  1162. if (fRaiseError)
  1163. {
  1164. NcMsgBox(_Module.GetResourceInstance(),
  1165. hwndOwner,
  1166. IDS_CONFOLD_ERROR_RENAME_ACTIVATING_CAPTION,
  1167. IDS_CONFOLD_ERROR_RENAME_ACTIVATING,
  1168. MB_ICONEXCLAMATION);
  1169. }
  1170. }
  1171. else
  1172. {
  1173. // If the old and new names differ in their case only then, we don't
  1174. // need to check if the new name already exists.
  1175. if (lstrcmpiW(ccfe.GetName(), pszNewName) == 0)
  1176. {
  1177. // New name differs from the old name in case only.
  1178. hr = S_FALSE;
  1179. }
  1180. else
  1181. {
  1182. pszReservedName = SzLoadIds( IDS_CONFOLD_INCOMING_CONN );
  1183. if ( lstrcmpiW(pszNewName, pszReservedName) == 0 ) {
  1184. hr = HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
  1185. }
  1186. else {
  1187. // New name is completely different, need to check if
  1188. // we already have the new name in our list
  1189. //
  1190. ConnListEntry cleDontCare;
  1191. hr = g_ccl.HrFindConnectionByName((PWSTR)pszNewName, cleDontCare);
  1192. }
  1193. }
  1194. // if (SUCCEEDED(hr))
  1195. {
  1196. // If there's no duplicate in the list, attempt to set the
  1197. // new name in the connection
  1198. //
  1199. if (hr == S_FALSE)
  1200. {
  1201. // Convert our persist data back to a INetConnection pointer.
  1202. //
  1203. hr = HrNetConFromPidl(pidlCon, &pNetCon);
  1204. if (SUCCEEDED(hr))
  1205. {
  1206. Assert(pNetCon);
  1207. // Call the connection's Rename with the new name
  1208. //
  1209. hr = pNetCon->Rename(pszNewName);
  1210. if (SUCCEEDED(hr))
  1211. {
  1212. GUID guidId;
  1213. fRefresh = TRUE;
  1214. // Update the name in the cache
  1215. //
  1216. guidId = pidlCon->guidId;
  1217. // Note: There is a race condition with notify.cpp:
  1218. // CConnectionNotifySink::ConnectionRenamed\HrUpdateNameByGuid can also update this
  1219. hr = g_ccl.HrUpdateNameByGuid(
  1220. &guidId,
  1221. (PWSTR) pszNewName,
  1222. pidlNew,
  1223. TRUE); // Force the issue. it's an update, not a request
  1224. GenerateEvent(
  1225. SHCNE_RENAMEITEM,
  1226. pidlFolderRoot,
  1227. pidlCon,
  1228. pidlNew.GetItemIdList());
  1229. }
  1230. if (fRaiseError && FAILED(hr))
  1231. {
  1232. // Leave hr at this value, as it will cause the UI to leave
  1233. // the object in the "rename in progress" state, so the user
  1234. // can change it again and hit enter.
  1235. //
  1236. if (HRESULT_FROM_WIN32(ERROR_DUP_NAME) == hr)
  1237. {
  1238. // Bring up the message box for the known DUPLICATE_NAME
  1239. // error
  1240. (void) NcMsgBox(
  1241. _Module.GetResourceInstance(),
  1242. hwndOwner,
  1243. IDS_CONFOLD_RENAME_FAIL_CAPTION,
  1244. IDS_CONFOLD_RENAME_DUPLICATE,
  1245. MB_OK | MB_ICONEXCLAMATION);
  1246. }
  1247. else
  1248. {
  1249. // Bring up the generic failure error, with the win32 text
  1250. //
  1251. (void) NcMsgBoxWithWin32ErrorText(
  1252. DwWin32ErrorFromHr (hr),
  1253. _Module.GetResourceInstance(),
  1254. hwndOwner,
  1255. IDS_CONFOLD_RENAME_FAIL_CAPTION,
  1256. IDS_TEXT_WITH_WIN32_ERROR,
  1257. IDS_CONFOLD_RENAME_OTHER_FAIL,
  1258. MB_OK | MB_ICONEXCLAMATION);
  1259. }
  1260. }
  1261. ReleaseObj(pNetCon); // RAID 180252
  1262. }
  1263. }
  1264. else
  1265. {
  1266. if ( hr == HRESULT_FROM_WIN32(ERROR_INVALID_NAME) ) {
  1267. if(fRaiseError)
  1268. {
  1269. // Bring up the invalid name message box.
  1270. // error
  1271. (void) NcMsgBox(
  1272. _Module.GetResourceInstance(),
  1273. hwndOwner,
  1274. IDS_CONFOLD_RENAME_FAIL_CAPTION,
  1275. IDS_CONFOLD_RENAME_INCOMING_CONN,
  1276. MB_OK | MB_ICONEXCLAMATION);
  1277. }
  1278. }
  1279. else {
  1280. // A duplicate name was found. Return an error.
  1281. //
  1282. hr = HRESULT_FROM_WIN32(ERROR_FILE_EXISTS);
  1283. if(fRaiseError)
  1284. {
  1285. // Bring up the message box for the known DUPLICATE_NAME
  1286. // error
  1287. (void) NcMsgBox(
  1288. _Module.GetResourceInstance(),
  1289. hwndOwner,
  1290. IDS_CONFOLD_RENAME_FAIL_CAPTION,
  1291. IDS_CONFOLD_RENAME_DUPLICATE,
  1292. MB_OK | MB_ICONEXCLAMATION);
  1293. }
  1294. }
  1295. }
  1296. }
  1297. }
  1298. }
  1299. }
  1300. }
  1301. }
  1302. if (S_OK == hr)
  1303. {
  1304. Assert(!pidlNew.empty());
  1305. ppidlOut = pidlNew;
  1306. }
  1307. if (S_FALSE == hr)
  1308. {
  1309. hr = E_FAIL;
  1310. }
  1311. // Fill in the return parameter
  1312. //
  1313. NETCFG_CATCH(hr)
  1314. TraceHr(ttidError, FAL, hr, FALSE, "HrRenameConnectionInternal");
  1315. return hr;
  1316. }