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.

1355 lines
41 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: I S H E L L F . C P P
  7. //
  8. // Contents: IShellFolder implementation for CConnectionFolder
  9. //
  10. // Notes: The IShellFolder interface is used to manage folders within
  11. // the namespace. Objects that support IShellFolder are
  12. // usually created by other shell folder objects, with the root
  13. // object (the Desktop shell folder) being returned from the
  14. // SHGetDesktopFolder function.
  15. //
  16. // Author: jeffspr 22 Sep 1997
  17. //
  18. //----------------------------------------------------------------------------
  19. #include "pch.h"
  20. #pragma hdrstop
  21. #include "foldinc.h" // Standard shell\folder includes
  22. #include "cfutils.h" // Connections folder utilities
  23. #include "foldres.h"
  24. #include "ncnetcon.h"
  25. #include "droptarget.h"
  26. #include "ncperms.h"
  27. #include "ncras.h"
  28. #include "cmdtable.h"
  29. #include "webview.h"
  30. #define ENABLE_CONNECTION_TOOLTIP
  31. const WCHAR c_szNetworkConnections[] = L"NetworkConnections";
  32. //+---------------------------------------------------------------------------
  33. //
  34. // Member: CConnectionFolder::ParseDisplayName
  35. //
  36. // Purpose: Translates a file object or folder's display name into an
  37. // item identifier.
  38. //
  39. // Arguments:
  40. // hwndOwner [in] Handle of owner window
  41. // pbcReserved [in] Reserved
  42. // lpszDisplayName [in] Pointer to diplay name
  43. // pchEaten [out] Pointer to value for parsed characters
  44. // ppidl [out] Pointer to new item identifier list
  45. // pdwAttributes [out] Address receiving attributes of file object
  46. //
  47. // Returns: Returns NOERROR if successful or an OLE-defined error
  48. // value otherwise
  49. //
  50. // Author: jeffspr 18 Oct 1997
  51. STDMETHODIMP CConnectionFolder::ParseDisplayName(
  52. HWND hwndOwner,
  53. LPBC pbcReserved,
  54. LPOLESTR lpszDisplayName,
  55. ULONG * pchEaten,
  56. LPITEMIDLIST * ppidl,
  57. ULONG * pdwAttributes)
  58. {
  59. HRESULT hr = S_OK;
  60. TraceFileFunc(ttidShellFolder);
  61. if (!ppidl)
  62. {
  63. return E_POINTER;
  64. }
  65. *ppidl = NULL;
  66. if ((lpszDisplayName == NULL) ||
  67. (wcslen(lpszDisplayName) < (c_cchGuidWithTerm - 1)))
  68. {
  69. return E_INVALIDARG;
  70. }
  71. while (*lpszDisplayName == ':')
  72. {
  73. lpszDisplayName++;
  74. }
  75. if (*lpszDisplayName != '{')
  76. {
  77. return E_INVALIDARG;
  78. }
  79. GUID guid;
  80. if (SUCCEEDED(CLSIDFromString(lpszDisplayName, &guid)))
  81. {
  82. if (g_ccl.IsInitialized() == FALSE)
  83. {
  84. g_ccl.HrRefreshConManEntries();
  85. }
  86. PCONFOLDPIDL pidl;
  87. hr = g_ccl.HrFindPidlByGuid(&guid, pidl);
  88. if (S_OK == hr)
  89. {
  90. *ppidl = pidl.TearOffItemIdList();
  91. TraceTag(ttidShellFolderIface, "IShellFolder::ParseDisplayName generated PIDL: 0x%08x", *ppidl);
  92. }
  93. else
  94. {
  95. hr = E_FILE_NOT_FOUND;
  96. }
  97. }
  98. else
  99. {
  100. return(E_FAIL);
  101. }
  102. if (SUCCEEDED(hr) && pdwAttributes)
  103. {
  104. LPCITEMIDLIST pidlArr[1];
  105. pidlArr[0] = *ppidl;
  106. hr = GetAttributesOf(1, pidlArr, pdwAttributes);
  107. }
  108. return hr;
  109. }
  110. //+---------------------------------------------------------------------------
  111. //
  112. // Member: CConnectionFolder::EnumObjects
  113. //
  114. // Purpose: Determines the contents of a folder by creating an item
  115. // enumeration object (a set of item identifiers) that can be
  116. // retrieved using the IEnumIDList interface.
  117. //
  118. // Arguments:
  119. // hwndOwner [in] Handle of owner window
  120. // grfFlags [in] Items to include in enumeration
  121. // ppenumIDList [out] Pointer to IEnumIDList
  122. //
  123. // Returns: Returns NOERROR if successful or an OLE-defined error
  124. // value otherwise
  125. //
  126. // Author: jeffspr 18 Oct 1997
  127. //
  128. // Notes:
  129. //
  130. STDMETHODIMP CConnectionFolder::EnumObjects(
  131. HWND hwndOwner,
  132. DWORD grfFlags,
  133. LPENUMIDLIST * ppenumIDList)
  134. {
  135. TraceFileFunc(ttidShellFolder);
  136. HRESULT hr = NOERROR;
  137. Assert(ppenumIDList);
  138. NETCFG_TRY
  139. // Create the IEnumIDList object (CConnectionFolderEnum)
  140. //
  141. hr = CConnectionFolderEnum::CreateInstance (
  142. IID_IEnumIDList,
  143. reinterpret_cast<void**>(ppenumIDList));
  144. if (SUCCEEDED(hr))
  145. {
  146. Assert(*ppenumIDList);
  147. // Call the PidlInitialize function to allow the enumeration
  148. // object to copy the list.
  149. //
  150. reinterpret_cast<CConnectionFolderEnum *>(*ppenumIDList)->PidlInitialize(
  151. FALSE, m_pidlFolderRoot, m_dwEnumerationType);
  152. }
  153. else
  154. {
  155. // On all failures, this should be NULL.
  156. if (*ppenumIDList)
  157. {
  158. ReleaseObj(*ppenumIDList);
  159. }
  160. *ppenumIDList = NULL;
  161. }
  162. NETCFG_CATCH(hr)
  163. TraceHr(ttidError, FAL, hr, FALSE, "CConnectionFolder::EnumObjects");
  164. return hr;
  165. }
  166. //+---------------------------------------------------------------------------
  167. //
  168. // Member: CConnectionFolder::BindToObject
  169. //
  170. // Purpose: Creates an IShellFolder object for a subfolder.
  171. //
  172. // Arguments:
  173. // pidl [in] Pointer to an ITEMIDLIST
  174. // pbcReserved [in] Reserved - specify NULL
  175. // riid [in] Interface to return
  176. // ppvOut [out] Address that receives interface pointer;
  177. //
  178. // Returns: Returns NOERROR if successful or an OLE-defined error
  179. // value otherwise
  180. //
  181. // Author: jeffspr 18 Oct 1997
  182. //
  183. // Notes: We don't need this function, since we don't have subfolders.
  184. //
  185. STDMETHODIMP CConnectionFolder::BindToObject(
  186. LPCITEMIDLIST pidl,
  187. LPBC pbcReserved,
  188. REFIID riid,
  189. LPVOID * ppvOut)
  190. {
  191. TraceFileFunc(ttidShellFolder);
  192. // Note - If we add code here, then we ought to param check pidl
  193. //
  194. Assert(pidl);
  195. *ppvOut = NULL;
  196. return E_NOTIMPL;
  197. }
  198. //+---------------------------------------------------------------------------
  199. //
  200. // Member: CConnectionFolder::BindToStorage
  201. //
  202. // Purpose: Reserved for a future use. This method should
  203. // return E_NOTIMPL.
  204. //
  205. // Arguments:
  206. // pidl [] Pointer to an ITEMIDLIST
  207. // pbcReserved [] Reserved�specify NULL
  208. // riid [] Interface to return
  209. // ppvObj [] Address that receives interface pointer);
  210. //
  211. // Returns: E_NOTIMPL always
  212. //
  213. // Author: jeffspr 18 Oct 1997
  214. //
  215. // Notes:
  216. //
  217. STDMETHODIMP CConnectionFolder::BindToStorage(
  218. LPCITEMIDLIST pidl,
  219. LPBC pbcReserved,
  220. REFIID riid,
  221. LPVOID * ppvObj)
  222. {
  223. TraceFileFunc(ttidShellFolder);
  224. // Note - If we add code here, then we ought to param check pidl
  225. //
  226. Assert(pidl);
  227. *ppvObj = NULL;
  228. return E_NOTIMPL;
  229. }
  230. //+---------------------------------------------------------------------------
  231. //
  232. // Member: CConnectionFolder::CompareIDs
  233. //
  234. // Purpose: Determines the relative ordering of two file objects or
  235. // folders, given their item identifier lists.
  236. //
  237. // Arguments:
  238. // lParam [in] Type of comparison to perform
  239. // pidl1 [in] Address of ITEMIDLIST structure
  240. // pidl2 [in] Address of ITEMIDLIST structure
  241. //
  242. // Returns: Returns a handle to a result code. If this method is
  243. // successful, the CODE field of the status code (SCODE) has
  244. // the following meaning:
  245. //
  246. // CODE field Meaning
  247. // ---------- -------
  248. // Less than zero The first item should precede the second
  249. // (pidl1 < pidl2).
  250. // Greater than zero The first item should follow the second
  251. // (pidl1 > pidl2)
  252. // Zero The two items are the same (pidl1 = pidl2)
  253. //
  254. // Author: jeffspr 18 Oct 1997
  255. //
  256. // Notes: Passing 0 as the lParam indicates sort by name.
  257. // 0x00000001-0x7fffffff are for folder specific sorting rules.
  258. // 0x80000000-0xfffffff are used the system.
  259. //
  260. STDMETHODIMP CConnectionFolder::CompareIDs(
  261. LPARAM lParam,
  262. LPCITEMIDLIST pidl1,
  263. LPCITEMIDLIST pidl2)
  264. {
  265. TraceFileFunc(ttidShellFolder);
  266. HRESULT hr = S_OK;
  267. int iCompare = 0;
  268. CONFOLDENTRY pccfe1;
  269. CONFOLDENTRY pccfe2;
  270. PCONFOLDPIDL pcfp1;
  271. PCONFOLDPIDL pcfp2;
  272. ConnListEntry cle1;
  273. ConnListEntry cle2;
  274. PCWSTR pszString1 = NULL;
  275. PCWSTR pszString2 = NULL;
  276. INT iStringID1 = 0;
  277. INT iStringID2 = 0;
  278. hr = pcfp1.InitializeFromItemIDList(pidl1);
  279. if (SUCCEEDED(hr))
  280. {
  281. hr = pcfp2.InitializeFromItemIDList(pidl2);
  282. }
  283. // Make sure that the pidls passed in are our pidls.
  284. //
  285. if (FAILED(hr))
  286. {
  287. hr = E_INVALIDARG;
  288. goto Exit;
  289. }
  290. if (WIZARD_NOT_WIZARD != pcfp1->wizWizard && WIZARD_NOT_WIZARD != pcfp2->wizWizard)
  291. {
  292. hr = ResultFromShort(0);
  293. if (pcfp1->wizWizard > pcfp2->wizWizard)
  294. hr = ResultFromShort(-1);
  295. if (pcfp1->wizWizard < pcfp2->wizWizard)
  296. hr = ResultFromShort(1);
  297. goto Exit;
  298. }
  299. // If the first item is a wizard, then it comes first.
  300. //
  301. if (WIZARD_NOT_WIZARD != pcfp1->wizWizard)
  302. {
  303. hr = ResultFromShort(-1);
  304. goto Exit;
  305. }
  306. // If the second item is a wizard, then, well, you get the picture.
  307. //
  308. if (WIZARD_NOT_WIZARD != pcfp2->wizWizard)
  309. {
  310. hr = ResultFromShort(1);
  311. goto Exit;
  312. }
  313. // Note: (jeffspr) & SHC... should be removed once Victor Tan checks in a fix
  314. // for the IShellFolder2 params being used in IShellFolder
  315. //
  316. switch(lParam & SHCIDS_COLUMNMASK)
  317. {
  318. case ICOL_NAME:
  319. {
  320. // Check the name. If the name is the same, then we need to
  321. // check the GUID as well, because we HAVE TO allow duplicate names,
  322. // and this function is used to uniquely identify connections for
  323. // notification purposes
  324. //
  325. LPCWSTR szPcfpName1 = pcfp1->PszGetNamePointer() ? pcfp1->PszGetNamePointer() : L"\0";
  326. LPCWSTR szPcfpName2 = pcfp2->PszGetNamePointer() ? pcfp2->PszGetNamePointer() : L"\0";
  327. iCompare = lstrcmpW(szPcfpName1, szPcfpName2);
  328. if (iCompare == 0)
  329. {
  330. if (!InlineIsEqualGUID(pcfp1->guidId, pcfp2->guidId))
  331. {
  332. // Doesn't really matter which order we put them
  333. // in, as long as we call them non-equal
  334. iCompare = -1;
  335. }
  336. }
  337. }
  338. break;
  339. case ICOL_TYPE:
  340. {
  341. MapNCMToResourceId(pcfp1->ncm, pcfp1->dwCharacteristics, &iStringID1);
  342. MapNCMToResourceId(pcfp2->ncm, pcfp2->dwCharacteristics, &iStringID2);
  343. pszString1 = (PWSTR) SzLoadIds(iStringID1);
  344. pszString2 = (PWSTR) SzLoadIds(iStringID2);
  345. if (pszString1 && pszString2)
  346. {
  347. iCompare = lstrcmpW(pszString1, pszString2);
  348. }
  349. }
  350. break;
  351. case ICOL_STATUS:
  352. {
  353. WCHAR szString1[CONFOLD_MAX_STATUS_LENGTH];
  354. WCHAR szString2[CONFOLD_MAX_STATUS_LENGTH];
  355. MapNCSToComplexStatus(pcfp1->ncs, pcfp1->ncm, pcfp1->ncsm, pcfp1->dwCharacteristics, szString1, CONFOLD_MAX_STATUS_LENGTH, pcfp1->guidId);
  356. MapNCSToComplexStatus(pcfp2->ncs, pcfp2->ncm, pcfp1->ncsm, pcfp2->dwCharacteristics, szString2, CONFOLD_MAX_STATUS_LENGTH, pcfp2->guidId);
  357. iCompare = lstrcmpW(szString1, szString2);
  358. }
  359. break;
  360. case ICOL_DEVICE_NAME:
  361. {
  362. LPCWSTR szPcfpDeviceName1 = pcfp1->PszGetDeviceNamePointer() ? pcfp1->PszGetDeviceNamePointer() : L"\0";
  363. LPCWSTR szPcfpDeviceName2 = pcfp2->PszGetDeviceNamePointer() ? pcfp2->PszGetDeviceNamePointer() : L"\0";
  364. iCompare = lstrcmpW(szPcfpDeviceName1, szPcfpDeviceName2);
  365. }
  366. break;
  367. case ICOL_OWNER:
  368. {
  369. pszString1 = PszGetOwnerStringFromCharacteristics(pszGetUserName(), pcfp1->dwCharacteristics);
  370. pszString2 = PszGetOwnerStringFromCharacteristics(pszGetUserName(), pcfp2->dwCharacteristics);
  371. iCompare = lstrcmpW(pszString1, pszString2);
  372. }
  373. break;
  374. case ICOL_PHONEORHOSTADDRESS:
  375. {
  376. LPCWSTR szPcfpPhoneHostAddress1 = pcfp1->PszGetPhoneOrHostAddressPointer() ? pcfp1->PszGetPhoneOrHostAddressPointer() : L"\0";
  377. LPCWSTR szPcfpPhoneHostAddress2 = pcfp2->PszGetPhoneOrHostAddressPointer() ? pcfp2->PszGetPhoneOrHostAddressPointer() : L"\0";
  378. iCompare = lstrcmpW(szPcfpPhoneHostAddress1, szPcfpPhoneHostAddress2);
  379. }
  380. break;
  381. default:
  382. // AssertFmt(FALSE, FAL, "Shell bug - Sorting on unknown category. Column = %x", (lParam & SHCIDS_COLUMNMASK));
  383. hr = E_INVALIDARG;
  384. break;
  385. }
  386. if (SUCCEEDED(hr))
  387. {
  388. hr = ResultFromShort(iCompare);
  389. }
  390. Exit:
  391. // If these were allocated instead of cached, delete them
  392. //
  393. TraceHr(ttidError, FAL, hr,
  394. (ResultFromShort(-1) == hr) || (ResultFromShort(1) == hr),
  395. "CConnectionFolder::CompareIDs");
  396. return hr;
  397. }
  398. //+---------------------------------------------------------------------------
  399. //
  400. // Member: CConnectionFolder::CreateViewObject
  401. //
  402. // Purpose: Creates a view object of a folder.
  403. //
  404. // Arguments:
  405. // hwndOwner [in] Handle of owner window
  406. // riid [in] Interface identifier
  407. // ppvOut [none] Reserved
  408. //
  409. // Returns: Returns NOERROR if successful or an OLE defined error
  410. // value otherwise.
  411. //
  412. // Author: jeffspr 18 Oct 1997
  413. //
  414. // Notes:
  415. //
  416. STDMETHODIMP CConnectionFolder::CreateViewObject(
  417. HWND hwndOwner,
  418. REFIID riid,
  419. LPVOID * ppvOut)
  420. {
  421. TraceFileFunc(ttidShellFolder);
  422. HRESULT hr = E_NOINTERFACE;
  423. Assert(ppvOut);
  424. Assert(this);
  425. // Pre-initialize the out param, per OLE guidelines
  426. //
  427. *ppvOut = NULL;
  428. if (riid == IID_IShellView)
  429. {
  430. if (FHasPermission(NCPERM_OpenConnectionsFolder))
  431. {
  432. SFV_CREATE sfv = {0};
  433. sfv.cbSize = sizeof(sfv);
  434. sfv.pshf = dynamic_cast<IShellFolder2*>(this);
  435. sfv.psfvcb = dynamic_cast<IShellFolderViewCB*>(this);
  436. // Note: The shell never gets around to freeing the last view
  437. // when shutting down...
  438. //
  439. hr = SHCreateShellFolderView(&sfv, &m_pShellView);
  440. if (SUCCEEDED(hr))
  441. {
  442. *ppvOut = m_pShellView;
  443. DWORD dwErr = 0;
  444. // Get the state of the "ManualDial" flag from RAS
  445. // so we can initialize our global
  446. //
  447. dwErr = RasUserGetManualDial(
  448. hwndOwner,
  449. FALSE,
  450. (PBOOL) (&g_fOperatorAssistEnabled));
  451. // Ignore the error (don't shove it in the Hr), because
  452. // we still want to run even if we failed to get the value
  453. // Trace it, though
  454. Assert(dwErr == 0);
  455. TraceHr(ttidShellFolder, FAL, HRESULT_FROM_WIN32(dwErr), FALSE,
  456. "RasUserGetManualDial call from CreateViewObject");
  457. }
  458. }
  459. else
  460. {
  461. TraceTag(ttidShellFolder, "No permission to open connections folder (FHasPermission returned 0)");
  462. AssertSz(FALSE, "get off!");
  463. if (hwndOwner)
  464. {
  465. NcMsgBox(_Module.GetResourceInstance(), hwndOwner,
  466. IDS_CONFOLD_WARNING_CAPTION,
  467. IDS_CONFOLD_NO_PERMISSIONS_FOR_OPEN,
  468. MB_ICONEXCLAMATION | MB_OK);
  469. hr = HRESULT_FROM_WIN32(ERROR_CANCELLED); // user saw the error
  470. }
  471. else
  472. {
  473. hr = E_ACCESSDENIED;
  474. }
  475. }
  476. }
  477. else if (riid == IID_IContextMenu)
  478. {
  479. // Create our context menu object for the background CMs.
  480. //
  481. hr = CConnectionFolderContextMenu::CreateInstance (
  482. IID_IContextMenu,
  483. reinterpret_cast<void**>(ppvOut),
  484. CMT_BACKGROUND,
  485. hwndOwner,
  486. PCONFOLDPIDLVEC(NULL),
  487. this);
  488. if (SUCCEEDED(hr))
  489. {
  490. Assert(*ppvOut);
  491. }
  492. }
  493. else if (riid == IID_ICategoryProvider)
  494. {
  495. // Create our context menu object for the background CMs.
  496. //
  497. CComPtr<IDefCategoryProvider> pDevCategoryProvider;
  498. hr = CoCreateInstance(CLSID_DefCategoryProvider, NULL, CLSCTX_ALL, IID_IDefCategoryProvider, reinterpret_cast<LPVOID *>(&pDevCategoryProvider));
  499. if (SUCCEEDED(hr))
  500. {
  501. SHCOLUMNID pscidType, pscidPhoneOrHostAddress;
  502. MapColumnToSCID(ICOL_TYPE, &pscidType);
  503. MapColumnToSCID(ICOL_PHONEORHOSTADDRESS, &pscidPhoneOrHostAddress);
  504. SHCOLUMNID pscidExclude[2];
  505. pscidExclude[0].fmtid = GUID_NETSHELL_PROPS;
  506. pscidExclude[0].pid = ICOL_PHONEORHOSTADDRESS;
  507. pscidExclude[1].fmtid = GUID_NULL;
  508. pscidExclude[1].pid = 0;
  509. CATLIST catList[] =
  510. {
  511. {&GUID_NULL, NULL}
  512. };
  513. if (SUCCEEDED(hr))
  514. {
  515. pDevCategoryProvider->Initialize(&GUID_NETSHELL_PROPS,
  516. &pscidType,
  517. pscidExclude,
  518. NULL,
  519. catList,
  520. this);
  521. hr = pDevCategoryProvider->QueryInterface(IID_ICategoryProvider, ppvOut);
  522. }
  523. }
  524. }
  525. else
  526. {
  527. goto Exit;
  528. }
  529. Exit:
  530. TraceHr(ttidError, FAL, hr, (E_NOINTERFACE == hr),
  531. "CConnectionFolder::CreateViewObject");
  532. return hr;
  533. }
  534. //+---------------------------------------------------------------------------
  535. //
  536. // Member: CConnectionFolder::GetAttributesOf
  537. //
  538. // Purpose: Retrieves the attributes that all passed-in objects (file
  539. // objects or subfolders) have in common.
  540. //
  541. // Arguments:
  542. // cidl [in] Number of file objects
  543. // apidl [in] Pointer to array of pointers to ITEMIDLIST structures
  544. // rgfInOut [out] Address of value containing attributes of the
  545. // file objects
  546. //
  547. // Returns: Returns NOERROR if successful or an OLE-defined error
  548. // value otherwise.
  549. //
  550. // Author: jeffspr 18 Oct 1997
  551. //
  552. // Notes:
  553. //
  554. STDMETHODIMP CConnectionFolder::GetAttributesOf(
  555. UINT cidl,
  556. LPCITEMIDLIST * apidl,
  557. ULONG * rgfInOut)
  558. {
  559. TraceFileFunc(ttidShellFolder);
  560. HRESULT hr = S_OK;
  561. ULONG rgfMask = 0;
  562. PCONFOLDPIDL pcfp;
  563. if (cidl > 0)
  564. {
  565. PCONFOLDPIDLVEC pcfpVec;
  566. hr = PConfoldPidlVecFromItemIdListArray(apidl, cidl, pcfpVec);
  567. if (FAILED(hr))
  568. {
  569. return E_INVALIDARG;
  570. }
  571. // Prepopulate with all values (removed CANCOPY and CANMOVE)
  572. //
  573. rgfMask = SFGAO_CANDELETE |
  574. SFGAO_CANRENAME |
  575. SFGAO_CANLINK |
  576. SFGAO_HASPROPSHEET;
  577. // Disable propsheets for > 1 connection
  578. //
  579. if (cidl > 1)
  580. {
  581. rgfMask &= ~SFGAO_HASPROPSHEET;
  582. }
  583. PCONFOLDPIDLVEC::const_iterator iterLoop;
  584. for (iterLoop = pcfpVec.begin(); iterLoop != pcfpVec.end(); iterLoop++)
  585. {
  586. // Translate the PIDL to our struct, and check for wizard inclusion.
  587. // If so, then we don't support anything but "link". If not, then
  588. // we support all of the standard actions
  589. const PCONFOLDPIDL& pcfp = *iterLoop;
  590. if(!pcfp.empty())
  591. {
  592. if (((*rgfInOut) & SFGAO_VALIDATE))
  593. {
  594. ConnListEntry cleDontCare;
  595. hr = g_ccl.HrFindConnectionByGuid(&(pcfp->guidId), cleDontCare);
  596. if (hr != S_OK)
  597. {
  598. // Note: Remove this when we get RAS notifications, because
  599. // we will ALWAYS have the information we need to find the connections
  600. // We're doing this because the CM folks are creating RAS icons on the
  601. // desktop without us knowing about it.
  602. //
  603. // If we didn't find it, then flush the cache and try again.
  604. //
  605. if (S_FALSE == hr)
  606. {
  607. hr = g_ccl.HrRefreshConManEntries();
  608. if (SUCCEEDED(hr))
  609. {
  610. hr = g_ccl.HrFindConnectionByGuid(&(pcfp->guidId), cleDontCare);
  611. if (hr != S_OK)
  612. {
  613. hr = E_FAIL;
  614. goto Exit;
  615. }
  616. }
  617. }
  618. else
  619. {
  620. hr = E_FAIL;
  621. goto Exit;
  622. }
  623. }
  624. }
  625. if (WIZARD_NOT_WIZARD != pcfp->wizWizard)
  626. {
  627. // No support for delete/rename/etc, since it's the wizard.
  628. // However, we want to provide our own "delete" warning when the
  629. // wizard is selected along with deleteable connections
  630. //
  631. rgfMask = SFGAO_CANLINK | SFGAO_CANDELETE;
  632. }
  633. if (pcfp->dwCharacteristics & NCCF_BRANDED)
  634. {
  635. if ( !fIsConnectedStatus(pcfp->ncs) && (pcfp->ncs != NCS_DISCONNECTING) )
  636. {
  637. rgfMask |= SFGAO_GHOSTED;
  638. }
  639. }
  640. if (pcfp->dwCharacteristics & NCCF_INCOMING_ONLY)
  641. {
  642. rgfMask &= ~SFGAO_CANLINK;
  643. }
  644. // Mask out the unavailable attributes for this connection
  645. //
  646. if (!(pcfp->dwCharacteristics & NCCF_ALLOW_RENAME) || !HasPermissionToRenameConnection(pcfp))
  647. {
  648. rgfMask &= ~SFGAO_CANRENAME;
  649. }
  650. #if 0 // If I mask this out, I can't give user feedback for objects that can't be deleted.
  651. if (pcfp->dwCharacteristics & NCCF_ALLOW_REMOVAL)
  652. {
  653. rgfMask |= SFGAO_CANDELETE;
  654. }
  655. #endif
  656. }
  657. }
  658. }
  659. else
  660. {
  661. // Apparently, we're called with 0 objects to indicate that we're
  662. // supposed to return flags for the folder itself, not an individual
  663. // object. Weird.
  664. rgfMask = SFGAO_CANCOPY |
  665. SFGAO_CANDELETE |
  666. SFGAO_CANMOVE |
  667. SFGAO_CANRENAME |
  668. SFGAO_DROPTARGET;
  669. }
  670. Exit:
  671. if (SUCCEEDED(hr))
  672. {
  673. *rgfInOut &= rgfMask;
  674. }
  675. return hr;
  676. }
  677. //+---------------------------------------------------------------------------
  678. //
  679. // Member: CConnectionFolder::GetUIObjectOf
  680. //
  681. // Purpose: Creates a COM object that can be used to carry out actions
  682. // on the specified file objects or folders, typically, to
  683. // create context menus or carry out drag-and-drop operations.
  684. //
  685. // Arguments:
  686. // hwndOwner [in] Handle to owner window
  687. // cidl [in] Number of objects specified in apidl
  688. // apidl [in] Pointer to an array of pointers to an ITEMIDLIST
  689. // riid [in] Interface to return
  690. // prgfInOut [none] Reserved
  691. // ppvOut [out] Address to receive interface pointer
  692. //
  693. // Returns: Returns NOERROR if successful or an OLE-defined error
  694. // value otherwise
  695. //
  696. // Author: jeffspr 18 Oct 1997
  697. //
  698. // Notes:
  699. //
  700. STDMETHODIMP CConnectionFolder::GetUIObjectOf(
  701. HWND hwndOwner,
  702. UINT cidl,
  703. LPCITEMIDLIST * apidl,
  704. REFIID riid,
  705. UINT * prgfInOut,
  706. LPVOID * ppvOut)
  707. {
  708. TraceFileFunc(ttidShellFolder);
  709. HRESULT hr = E_NOINTERFACE;
  710. NETCFG_TRY
  711. if (cidl >= 1)
  712. {
  713. Assert(apidl);
  714. Assert(apidl[0]);
  715. Assert(ppvOut);
  716. if (riid == IID_IDataObject)
  717. {
  718. // Need to initialize so the SUCCEEED check below doesn't fail.
  719. //
  720. hr = S_OK;
  721. if (m_pidlFolderRoot.empty())
  722. {
  723. hr = HrGetConnectionsFolderPidl(m_pidlFolderRoot);
  724. }
  725. if (SUCCEEDED(hr))
  726. {
  727. Assert(!m_pidlFolderRoot.empty());
  728. // Internal IDataObject impl removed. Replaced with common
  729. // shell code.
  730. //
  731. hr = CIDLData_CreateFromIDArray(m_pidlFolderRoot.GetItemIdList(), cidl, apidl, (IDataObject **) ppvOut);
  732. }
  733. }
  734. else if (riid == IID_IContextMenu)
  735. {
  736. PCONFOLDPIDLVEC pcfpVec;
  737. hr = PConfoldPidlVecFromItemIdListArray(apidl, cidl, pcfpVec);
  738. if (FAILED(hr))
  739. {
  740. return E_INVALIDARG;
  741. }
  742. // Create our context menu object for the background CMs.
  743. //
  744. if (SUCCEEDED(hr))
  745. {
  746. hr = CConnectionFolderContextMenu::CreateInstance (
  747. IID_IContextMenu,
  748. reinterpret_cast<void**>(ppvOut),
  749. CMT_OBJECT,
  750. hwndOwner,
  751. pcfpVec,
  752. this);
  753. if (SUCCEEDED(hr))
  754. {
  755. Assert(*ppvOut);
  756. }
  757. else
  758. {
  759. hr = E_NOINTERFACE;
  760. }
  761. }
  762. }
  763. else if (riid == IID_IExtractIconA || riid == IID_IExtractIconW)
  764. {
  765. if (cidl == 1)
  766. {
  767. hr = CConnectionFolderExtractIcon::CreateInstance (
  768. apidl[0],
  769. riid,
  770. reinterpret_cast<void**>(ppvOut));
  771. if (SUCCEEDED(hr))
  772. {
  773. Assert(*ppvOut);
  774. }
  775. }
  776. else
  777. {
  778. hr = E_NOINTERFACE;
  779. }
  780. }
  781. else if (riid == IID_IDropTarget)
  782. {
  783. hr = E_NOINTERFACE;
  784. }
  785. else if (riid == IID_IQueryAssociations)
  786. {
  787. CComPtr<IQueryAssociations> pQueryAssociations;
  788. hr = AssocCreate(CLSID_QueryAssociations, IID_IQueryAssociations, reinterpret_cast<LPVOID *>(&pQueryAssociations));
  789. if (SUCCEEDED(hr))
  790. {
  791. hr = pQueryAssociations->Init(0, c_szNetworkConnections, NULL, NULL);
  792. if (SUCCEEDED(hr))
  793. {
  794. hr = pQueryAssociations->QueryInterface(IID_IQueryAssociations, ppvOut);
  795. }
  796. }
  797. }
  798. else if (riid == IID_IQueryInfo)
  799. {
  800. #ifdef ENABLE_CONNECTION_TOOLTIP
  801. if (cidl == 1)
  802. {
  803. PCONFOLDPIDLVEC pcfpVec;
  804. hr = PConfoldPidlVecFromItemIdListArray(apidl, cidl, pcfpVec);
  805. if (FAILED(hr))
  806. {
  807. return E_INVALIDARG;
  808. }
  809. const PCONFOLDPIDL& pcfp = *pcfpVec.begin();
  810. // Create the IQueryInfo interface
  811. hr = CConnectionFolderQueryInfo::CreateInstance (
  812. IID_IQueryInfo,
  813. reinterpret_cast<void**>(ppvOut));
  814. if (SUCCEEDED(hr))
  815. {
  816. Assert(*ppvOut);
  817. reinterpret_cast<CConnectionFolderQueryInfo *>
  818. (*ppvOut)->PidlInitialize(*pcfpVec.begin());
  819. // Normalize return code
  820. //
  821. hr = NOERROR;
  822. }
  823. }
  824. else
  825. {
  826. AssertSz(FALSE, "GetUIObjectOf asked for query info for more than one item!");
  827. hr = E_NOINTERFACE;
  828. }
  829. #else
  830. hr = E_NOINTERFACE;
  831. #endif // ENABLE_CONNECTION_TOOLTIP
  832. }
  833. else
  834. {
  835. TraceTag(ttidShellFolder, "CConnectionFolder::GetUIObjectOf asked for object "
  836. "that it didn't know how to create. 0x%08x", riid.Data1);
  837. hr = E_NOINTERFACE;
  838. }
  839. }
  840. if (FAILED(hr))
  841. {
  842. *ppvOut = NULL;
  843. }
  844. NETCFG_CATCH(hr)
  845. TraceHr(ttidError, FAL, hr, (hr == E_NOINTERFACE), "CConnectionFolder::GetUIObjectOf");
  846. return hr;
  847. }
  848. //+---------------------------------------------------------------------------
  849. //
  850. // Member: CConnectionFolder::GetDisplayNameOf
  851. //
  852. // Purpose: Retrieves the display name for the specified file object or
  853. // subfolder, returning it in a STRRET structure.
  854. //
  855. // Arguments:
  856. // pidl [in] Pointer to an ITEMIDLIST
  857. // uFlags [in] Type of display to return
  858. // lpName [out] Pointer to a STRRET structure
  859. //
  860. // Returns: Returns NOERROR if successful or an OLE-defined error
  861. // value otherwise.
  862. //
  863. // Author: jeffspr 18 Oct 1997
  864. //
  865. // Notes:
  866. //
  867. STDMETHODIMP CConnectionFolder::GetDisplayNameOf(
  868. LPCITEMIDLIST pidl,
  869. DWORD uFlags,
  870. LPSTRRET lpName)
  871. {
  872. TraceFileFunc(ttidShellFolder);
  873. HRESULT hr = S_OK;
  874. PWSTR pszStrToCopy = NULL;
  875. Assert(lpName);
  876. if (!pidl || !lpName)
  877. {
  878. return E_INVALIDARG;
  879. }
  880. PCONFOLDPIDL pcfpLatestVersion;
  881. PCONFOLDPIDL pcfpLatestVersionCached;
  882. PCONFOLDPIDL98 pcfp98;
  883. CONFOLDPIDLTYPE cfpt = GetPidlType(pidl);
  884. switch (cfpt)
  885. {
  886. case PIDL_TYPE_V1:
  887. case PIDL_TYPE_V2:
  888. if (FAILED(pcfpLatestVersion.InitializeFromItemIDList(pidl)))
  889. {
  890. return E_INVALIDARG;
  891. }
  892. break;
  893. case PIDL_TYPE_98:
  894. if (FAILED(pcfp98.InitializeFromItemIDList(pidl)))
  895. {
  896. return E_INVALIDARG;
  897. }
  898. break;
  899. default:
  900. AssertSz(FALSE, "CConnectionFolder::GetDisplayNameOf - Invalid PIDL");
  901. return E_INVALIDARG;
  902. break;
  903. }
  904. if ( (PIDL_TYPE_V1 == cfpt) || (PIDL_TYPE_V2 == cfpt) )
  905. {
  906. #ifdef DBG
  907. // Throw these in here just so I can quickly peek at the values
  908. // set while I'm dorking around in the debugger.
  909. //
  910. DWORD dwInFolder = (uFlags & SHGDN_INFOLDER);
  911. DWORD dwForAddressBar = (uFlags & SHGDN_FORADDRESSBAR);
  912. DWORD dwForParsing = (uFlags & SHGDN_FORPARSING);
  913. #endif
  914. // Find the correct string for the display name. For the wizard, we get it
  915. // from the resources. Otherwise, we use the actual connection name
  916. //
  917. lpName->uType = STRRET_WSTR;
  918. if (uFlags & SHGDN_FORPARSING)
  919. {
  920. lpName->pOleStr = (LPWSTR)SHAlloc(c_cbGuidWithTerm);
  921. if (lpName->pOleStr == NULL)
  922. {
  923. return(ERROR_NOT_ENOUGH_MEMORY);
  924. }
  925. if (StringFromGUID2(pcfpLatestVersion->clsid, lpName->pOleStr, c_cbGuidWithTerm) == 0)
  926. {
  927. return(ERROR_INVALID_NAME);
  928. }
  929. return(S_OK);
  930. }
  931. else if (WIZARD_MNC == pcfpLatestVersion->wizWizard)
  932. {
  933. pszStrToCopy = (PWSTR) SzLoadIds(IDS_CONFOLD_WIZARD_DISPLAY_NAME);
  934. }
  935. else if (WIZARD_HNW == pcfpLatestVersion->wizWizard)
  936. {
  937. pszStrToCopy = (PWSTR) SzLoadIds(IDS_CONFOLD_HOMENET_WIZARD_DISPLAY_NAME);
  938. }
  939. else
  940. {
  941. hr = g_ccl.HrGetCachedPidlCopyFromPidl(pcfpLatestVersion, pcfpLatestVersionCached);
  942. if (S_OK == hr)
  943. {
  944. pszStrToCopy = pcfpLatestVersionCached->PszGetNamePointer();
  945. }
  946. else
  947. {
  948. pszStrToCopy = pcfpLatestVersion->PszGetNamePointer();
  949. hr = S_OK;
  950. }
  951. }
  952. Assert(pszStrToCopy);
  953. // Allocate a new POLESTR block, which the shell can then free,
  954. // and copy the displayable portion to it.
  955. //
  956. // Note that &lpName->pOleStr is likely misaligned.
  957. //
  958. LPWSTR pOleStr;
  959. pOleStr = lpName->pOleStr;
  960. hr = HrDupeShellString(pszStrToCopy, &pOleStr );
  961. lpName->pOleStr = pOleStr;
  962. }
  963. else if (PIDL_TYPE_98 == cfpt)
  964. {
  965. // Raid#214057, handle win98 pidl for shortcuts
  966. // Return the offset to the string because we store the display
  967. // name in the opaque structure.
  968. lpName->uType = STRRET_OFFSET;
  969. lpName->uOffset = _IOffset(CONFOLDPIDL98, szaName);
  970. }
  971. else
  972. {
  973. // not a valid connections pidl (neither Win2K nor Win98).
  974. //
  975. hr = E_INVALIDARG;
  976. }
  977. TraceHr(ttidError, FAL, hr, FALSE, "CConnectionFolder::GetDisplayNameOf");
  978. return hr;
  979. }
  980. //+---------------------------------------------------------------------------
  981. //
  982. // Member: CConnectionFolder::SetNameOf
  983. //
  984. // Purpose: Changes the name of a file object or subfolder, changing its
  985. // item identifier in the process.
  986. //
  987. // Arguments:
  988. // hwndOwner [in] Handle of owner window
  989. // pidl [in] Pointer to an ITEMIDLIST structure
  990. // lpszName [in] Pointer to string specifying new display name
  991. // uFlags [in] Type of name specified in lpszName
  992. // ppidlOut [out] Pointer to new ITEMIDLIST
  993. //
  994. // Returns: Returns NOERROR if successful or an OLE-defined error
  995. // value otherwise.
  996. //
  997. // Author: jeffspr 18 Oct 1997
  998. //
  999. // Notes:
  1000. //
  1001. STDMETHODIMP CConnectionFolder::SetNameOf(
  1002. HWND hwndOwner,
  1003. LPCITEMIDLIST pidlShell,
  1004. LPCOLESTR lpszName,
  1005. DWORD uFlags,
  1006. LPITEMIDLIST * ppidlOut)
  1007. {
  1008. TraceFileFunc(ttidShellFolder);
  1009. HRESULT hr = NOERROR;
  1010. /*
  1011. PWSTR pszWarning = NULL;
  1012. INetConnection * pNetCon = NULL;
  1013. LPITEMIDLIST pidlNew = NULL;
  1014. BOOL fRefresh = FALSE;
  1015. BOOL fActivating = FALSE;
  1016. PCONFOLDENTRY pccfe = NULL;
  1017. */
  1018. PCONFOLDPIDL pcfp;
  1019. Assert(hwndOwner);
  1020. Assert(pidlShell);
  1021. Assert(lpszName);
  1022. if (!pidlShell && !lpszName)
  1023. {
  1024. hr = E_INVALIDARG;
  1025. }
  1026. else
  1027. {
  1028. // check lpszName for validity
  1029. if (!FIsValidConnectionName(lpszName))
  1030. {
  1031. (void) NcMsgBox(
  1032. _Module.GetResourceInstance(),
  1033. hwndOwner,
  1034. IDS_CONFOLD_RENAME_FAIL_CAPTION,
  1035. IDS_CONFOLD_RENAME_INVALID,
  1036. MB_OK | MB_ICONEXCLAMATION);
  1037. hr = HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
  1038. }
  1039. if (SUCCEEDED(hr))
  1040. {
  1041. // Get what's current from the cache so rename works properly
  1042. //
  1043. PCONFOLDPIDL pcfpShell;
  1044. hr = pcfpShell.InitializeFromItemIDList(pidlShell);
  1045. if (SUCCEEDED(hr))
  1046. {
  1047. hr = g_ccl.HrGetCachedPidlCopyFromPidl(pcfpShell, pcfp);
  1048. if (SUCCEEDED(hr))
  1049. {
  1050. PCONFOLDPIDL pidlOut;
  1051. hr = HrRenameConnectionInternal(pcfp, m_pidlFolderRoot, lpszName, TRUE, hwndOwner, pidlOut);
  1052. if ( (ppidlOut) && (SUCCEEDED(hr)) )
  1053. {
  1054. *ppidlOut = pidlOut.TearOffItemIdList();
  1055. }
  1056. }
  1057. }
  1058. }
  1059. }
  1060. if (FAILED(hr) && (ppidlOut))
  1061. {
  1062. *ppidlOut = NULL;
  1063. }
  1064. TraceHr(ttidError, FAL, hr, FALSE, "CConnectionFolder::SetNameOf");
  1065. return hr;
  1066. }
  1067. STDMETHODIMP CConnectionFolder::MessageSFVCB(
  1068. UINT uMsg,
  1069. WPARAM wParam,
  1070. LPARAM lParam)
  1071. {
  1072. TraceFileFunc(ttidShellFolder);
  1073. HRESULT hr = RealMessage(uMsg, wParam, lParam);
  1074. if (FAILED(hr))
  1075. {
  1076. switch (uMsg)
  1077. {
  1078. case DVM_INVOKECOMMAND:
  1079. if ((CMIDM_RENAME == wParam) && m_hwndMain && m_pShellView)
  1080. {
  1081. PCONFOLDPIDLVEC apidlSelected;
  1082. PCONFOLDPIDLVEC apidlCache;
  1083. hr = HrShellView_GetSelectedObjects(m_hwndMain, apidlSelected);
  1084. if (SUCCEEDED(hr))
  1085. {
  1086. // If there are objects, try to get the cached versions
  1087. if (!apidlSelected.empty())
  1088. {
  1089. hr = HrCloneRgIDL(apidlSelected, TRUE, TRUE, apidlCache);
  1090. }
  1091. }
  1092. if (SUCCEEDED(hr))
  1093. {
  1094. Assert(apidlCache.size() == 1);
  1095. if (apidlCache.size() == 1)
  1096. {
  1097. hr = m_pShellView->SelectItem(apidlCache[0].GetItemIdList(), SVSI_EDIT);
  1098. }
  1099. else
  1100. {
  1101. hr = E_INVALIDARG;
  1102. }
  1103. }
  1104. }
  1105. break;
  1106. case SFVM_HWNDMAIN:
  1107. // _hwndMain = (HWND)lParam;
  1108. hr = S_OK;
  1109. break;
  1110. }
  1111. }
  1112. return hr;
  1113. }
  1114. /*
  1115. //+---------------------------------------------------------------------------
  1116. //
  1117. // Member: CConnectionFolder::GetOverlayIndex
  1118. //
  1119. // Purpose: Adds icon overlays to connections that need them
  1120. //
  1121. // Arguments:
  1122. // pidlItem [in] Pidl to item in question
  1123. // pIndex [out] Address of overlay index into system image list
  1124. //
  1125. //
  1126. // Returns: Returns NOERROR if successful or an OLE-defined error
  1127. // value otherwise.
  1128. //
  1129. // Author: kenwic 10 May 2000 created, support for sharing overlay
  1130. //
  1131. // Notes:
  1132. //
  1133. STDMETHODIMP CConnectionFolder::GetOverlayIndex(
  1134. LPCITEMIDLIST pidlItem,
  1135. int* pIndex)
  1136. {
  1137. TraceFileFunc(ttidShellFolder);
  1138. HRESULT hResult = E_FAIL;
  1139. *pIndex = -1;
  1140. // check to see if connection is sharing, and if so add sharing hand overlay
  1141. // i can't call HrNetConFromPidl, because it asserts if passed the wizard icon
  1142. PCONFOLDPIDL pcfpItem;
  1143. pcfpItem.InitializeFromItemIDList(pidlItem);
  1144. CONFOLDENTRY pConnectionFolderEntry;
  1145. hResult = pcfpItem.ConvertToConFoldEntry(pConnectionFolderEntry);
  1146. if(SUCCEEDED(hResult))
  1147. {
  1148. if(FALSE == pConnectionFolderEntry.GetWizard()) // sharing the wizard is not yet supported
  1149. {
  1150. if(NCCF_SHARED & pConnectionFolderEntry.GetCharacteristics())
  1151. {
  1152. *pIndex = SHGetIconOverlayIndex(NULL, IDO_SHGIOI_SHARE);
  1153. hResult = S_OK;
  1154. }
  1155. else
  1156. {
  1157. hResult = E_FAIL; // the docs for IShellIconOverlay are wrong, we must return failure to deny the icon
  1158. }
  1159. }
  1160. else
  1161. {
  1162. hResult = E_FAIL;
  1163. }
  1164. }
  1165. TraceHr(ttidShellFolder, FAL, hResult, TRUE, "CConnectionFolder::GetOverlayIndex");
  1166. return hResult;
  1167. }
  1168. //+---------------------------------------------------------------------------
  1169. //
  1170. // Member: CConnectionFolder::GetOverlayIconIndex
  1171. //
  1172. // Purpose: Adds icon overlays to connections that need them
  1173. //
  1174. // Arguments:
  1175. // pidlItem [in] Pidl to item in question
  1176. // pIconIndex [out] Address of index into system image list
  1177. //
  1178. //
  1179. // Returns: Returns NOERROR if successful or an OLE-defined error
  1180. // value otherwise.
  1181. //
  1182. // Author: kenwic 10 May 2000 created
  1183. //
  1184. // Notes:
  1185. //
  1186. STDMETHODIMP CConnectionFolder::GetOverlayIconIndex(
  1187. LPCITEMIDLIST pidlItem,
  1188. int* pIconIndex)
  1189. {
  1190. TraceFileFunc(ttidShellFolder);
  1191. *pIconIndex = -1;
  1192. HRESULT hResult = GetOverlayIndex(pidlItem, pIconIndex);
  1193. if(SUCCEEDED(hResult))
  1194. {
  1195. *pIconIndex = INDEXTOOVERLAYMASK(*pIconIndex);
  1196. }
  1197. TraceHr(ttidShellFolder, FAL, hResult, TRUE, "CConnectionFolder::GetOverlayIconIndex");
  1198. return hResult;
  1199. }*/