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.

1752 lines
46 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 CUPnPDeviceFolder
  9. // Implemention of CUPnPDeviceFoldPidl
  10. //
  11. // Notes: The IShellFolder interface is used to manage folders within
  12. // the namespace. Objects that support IShellFolder are
  13. // usually created by other shell folder objects, with the root
  14. // object (the Desktop shell folder) being returned from the
  15. // SHGetDesktopFolder function.
  16. //
  17. // Author: jeffspr 22 Sep 1997
  18. //
  19. //----------------------------------------------------------------------------
  20. #include "pch.h"
  21. #pragma hdrstop
  22. #include <upscmn.h>
  23. #include "tfind.h"
  24. #include "clist.h"
  25. #include "clistndn.h"
  26. #include "tconst.h"
  27. CUPnPDeviceFoldPidl::CUPnPDeviceFoldPidl()
  28. {
  29. // if these change, the UPNPUI_PIDL_HEADER structure
  30. // above needs to change to be the right size
  31. // Why we used 4 different types, I don't know...
  32. Assert(2 == sizeof(WORD));
  33. Assert(2 == sizeof(USHORT));
  34. Assert(4 == sizeof(DWORD));
  35. Assert(4 == sizeof(ULONG));
  36. m_pszName = NULL;
  37. m_pszUrl = NULL;
  38. m_pszUdn = NULL;
  39. m_pszType = NULL;
  40. m_pszDesc = NULL;
  41. }
  42. CUPnPDeviceFoldPidl::~CUPnPDeviceFoldPidl()
  43. {
  44. if (m_pszName)
  45. {
  46. delete [] m_pszName;
  47. }
  48. if (m_pszUrl)
  49. {
  50. delete [] m_pszUrl;
  51. }
  52. if (m_pszUdn)
  53. {
  54. delete [] m_pszUdn;
  55. }
  56. if (m_pszType)
  57. {
  58. delete [] m_pszType;
  59. }
  60. if (m_pszDesc)
  61. {
  62. delete [] m_pszDesc;
  63. }
  64. }
  65. HRESULT
  66. CUPnPDeviceFoldPidl::HrInit(FolderDeviceNode * pDeviceNode)
  67. {
  68. Assert(!m_pszName);
  69. Assert(!m_pszUrl);
  70. Assert(!m_pszUdn);
  71. Assert(!m_pszType);
  72. Assert(!m_pszDesc);
  73. Assert(pDeviceNode);
  74. Assert(pDeviceNode->pszDisplayName);
  75. Assert(pDeviceNode->pszPresentationURL);
  76. Assert(pDeviceNode->pszUDN);
  77. Assert(pDeviceNode->pszType);
  78. HRESULT hr;
  79. LPWSTR pszName;
  80. LPWSTR pszUrl;
  81. LPWSTR pszUdn;
  82. LPWSTR pszType;
  83. LPWSTR pszDesc;
  84. ULONG cchName;
  85. ULONG cchUrl;
  86. ULONG cchUdn;
  87. ULONG cchType;
  88. ULONG cchDesc;
  89. hr = E_OUTOFMEMORY;
  90. pszName = NULL;
  91. pszUrl = NULL;
  92. pszUdn = NULL;
  93. pszType = NULL;
  94. pszDesc = NULL;
  95. // Get the size of the name, and tack on a trailing NULL (since we now
  96. // have something else in the buffer behind it.
  97. //
  98. cchName = lstrlenW(pDeviceNode->pszDisplayName);
  99. pszName = new WCHAR [cchName + 1];
  100. if (!pszName)
  101. {
  102. goto Cleanup;
  103. }
  104. cchUrl = lstrlenW(pDeviceNode->pszPresentationURL);
  105. pszUrl = new WCHAR [cchUrl + 1];
  106. if (!pszUrl)
  107. {
  108. goto Cleanup;
  109. }
  110. cchUdn = lstrlenW(pDeviceNode->pszUDN);
  111. pszUdn = new WCHAR [cchUdn + 1];
  112. if (!pszUdn)
  113. {
  114. goto Cleanup;
  115. }
  116. cchType = lstrlenW(pDeviceNode->pszType);
  117. pszType = new WCHAR [cchType + 1];
  118. if (!pszType)
  119. {
  120. goto Cleanup;
  121. }
  122. cchDesc = lstrlenW(pDeviceNode->pszDescription);
  123. pszDesc = new WCHAR [cchDesc + 1];
  124. if (!pszDesc)
  125. {
  126. goto Cleanup;
  127. }
  128. // everything that can fail has succeeded.
  129. hr = S_OK;
  130. // We don't need to check these since we know there's
  131. // enough room.
  132. wcscpy(pszName, pDeviceNode->pszDisplayName);
  133. wcscpy(pszUrl, pDeviceNode->pszPresentationURL);
  134. wcscpy(pszUdn, pDeviceNode->pszUDN);
  135. wcscpy(pszType, pDeviceNode->pszType);
  136. wcscpy(pszDesc, pDeviceNode->pszDescription);
  137. m_pszName = pszName;
  138. m_pszUrl = pszUrl;
  139. m_pszUdn = pszUdn;
  140. m_pszType = pszType;
  141. m_pszDesc = pszDesc;
  142. Cleanup:
  143. if (FAILED(hr))
  144. {
  145. if (pszName)
  146. {
  147. delete [] pszName;
  148. }
  149. if (pszUrl)
  150. {
  151. delete [] pszUrl;
  152. }
  153. if (pszUdn)
  154. {
  155. delete [] pszUdn;
  156. }
  157. if (pszType)
  158. {
  159. delete [] pszType;
  160. }
  161. if (pszDesc)
  162. {
  163. delete [] pszDesc;
  164. }
  165. }
  166. Assert(FImplies(SUCCEEDED(hr), pszName));
  167. Assert(FImplies(SUCCEEDED(hr), pszUrl));
  168. Assert(FImplies(SUCCEEDED(hr), pszUdn));
  169. Assert(FImplies(SUCCEEDED(hr), pszType));
  170. Assert(FImplies(SUCCEEDED(hr), pszDesc));
  171. return hr;
  172. }
  173. HRESULT
  174. HrCopyUnalignedBytesToNewString(BYTE * pByteData,
  175. ULONG cbData,
  176. LPWSTR * ppszResult)
  177. {
  178. Assert(ppszResult);
  179. HRESULT hr;
  180. LPWSTR pszResult;
  181. ULONG cchMax;
  182. hr = S_OK;
  183. pszResult = NULL;
  184. {
  185. BOOL fInvalid;
  186. fInvalid = IsBadReadPtr(pByteData, cbData);
  187. if (fInvalid)
  188. {
  189. hr = E_POINTER;
  190. goto Cleanup;
  191. }
  192. }
  193. if (!cbData || cbData % sizeof(WCHAR))
  194. {
  195. hr = E_INVALIDARG;
  196. goto Cleanup;
  197. }
  198. cchMax = (cbData / sizeof(WCHAR)) - 1;
  199. pszResult = new WCHAR [ cchMax + 1 ];
  200. if (!pszResult)
  201. {
  202. hr = E_OUTOFMEMORY;
  203. goto Cleanup;
  204. }
  205. ::CopyMemory(pszResult, pByteData, cbData);
  206. // make sure that the data is null-terminated.
  207. pszResult[cchMax] = UNICODE_NULL;
  208. Cleanup:
  209. if (FAILED(hr))
  210. {
  211. if (pszResult)
  212. {
  213. delete [] pszResult;
  214. pszResult = NULL;
  215. }
  216. }
  217. *ppszResult = pszResult;
  218. TraceError("HrCopyUnalignedBytesToNewString", hr);
  219. return hr;
  220. }
  221. HRESULT
  222. CUPnPDeviceFoldPidl::HrInit(PUPNPDEVICEFOLDPIDL pidl)
  223. {
  224. Assert(!m_pszName);
  225. Assert(!m_pszUrl);
  226. Assert(!m_pszUdn);
  227. Assert(!m_pszType);
  228. Assert(!m_pszDesc);
  229. HRESULT hr;
  230. UNALIGNED UPNPUI_PIDL_HEADER * puph;
  231. LPWSTR pszName;
  232. LPWSTR pszUrl;
  233. LPWSTR pszUdn;
  234. LPWSTR pszType;
  235. LPWSTR pszDesc;
  236. hr = S_OK;
  237. puph = (UPNPUI_PIDL_HEADER *) pidl;
  238. pszName = NULL;
  239. pszUrl = NULL;
  240. pszUdn = NULL;
  241. pszType = NULL;
  242. pszDesc = NULL;
  243. {
  244. BOOL fInvalid;
  245. fInvalid = IsBadReadPtr(pidl, sizeof(UPNPUI_PIDL_HEADER));
  246. if (fInvalid)
  247. {
  248. hr = E_POINTER;
  249. goto Cleanup;
  250. }
  251. }
  252. // minimal version checking should have happened already,
  253. // so we just assert that everything is ok here
  254. //
  255. Assert(UPNPDEVICEFOLDPIDL_LEADID == puph->uLeadId);
  256. Assert(UPNPDEVICEFOLDPIDL_TRAILID == puph->uTrailId);
  257. {
  258. BYTE * pbString;
  259. ULONG ulOffset;
  260. ULONG cb;
  261. pbString = (BYTE *)pidl;
  262. ulOffset = puph->ulNameOffset;
  263. ulOffset += sizeof(UPNPUI_PIDL_HEADER);
  264. cb = puph->cbName;
  265. pbString += ulOffset;
  266. hr = HrCopyUnalignedBytesToNewString(pbString,
  267. cb,
  268. &pszName);
  269. if (FAILED(hr))
  270. {
  271. goto Cleanup;
  272. }
  273. }
  274. {
  275. BYTE * pbString;
  276. ULONG ulOffset;
  277. ULONG cb;
  278. pbString = (BYTE *)pidl;
  279. ulOffset = puph->ulUrlOffset;
  280. ulOffset += sizeof(UPNPUI_PIDL_HEADER);
  281. cb = puph->cbUrl;
  282. pbString += ulOffset;
  283. hr = HrCopyUnalignedBytesToNewString(pbString,
  284. cb,
  285. &pszUrl);
  286. if (FAILED(hr))
  287. {
  288. goto Cleanup;
  289. }
  290. }
  291. {
  292. BYTE * pbString;
  293. ULONG ulOffset;
  294. ULONG cb;
  295. pbString = (BYTE *)pidl;
  296. ulOffset = puph->ulUdnOffset;
  297. ulOffset += sizeof(UPNPUI_PIDL_HEADER);
  298. cb = puph->cbUdn;
  299. pbString += ulOffset;
  300. hr = HrCopyUnalignedBytesToNewString(pbString,
  301. cb,
  302. &pszUdn);
  303. if (FAILED(hr))
  304. {
  305. goto Cleanup;
  306. }
  307. }
  308. {
  309. BYTE * pbString;
  310. ULONG ulOffset;
  311. ULONG cb;
  312. pbString = (BYTE *)pidl;
  313. ulOffset = puph->ulTypeOffset;
  314. ulOffset += sizeof(UPNPUI_PIDL_HEADER);
  315. cb = puph->cbType;
  316. pbString += ulOffset;
  317. hr = HrCopyUnalignedBytesToNewString(pbString,
  318. cb,
  319. &pszType);
  320. if (FAILED(hr))
  321. {
  322. goto Cleanup;
  323. }
  324. }
  325. {
  326. BYTE * pbString;
  327. ULONG ulOffset;
  328. ULONG cb;
  329. pbString = (BYTE *)pidl;
  330. ulOffset = puph->ulDescOffset;
  331. ulOffset += sizeof(UPNPUI_PIDL_HEADER);
  332. cb = puph->cbDesc;
  333. pbString += ulOffset;
  334. hr = HrCopyUnalignedBytesToNewString(pbString,
  335. cb,
  336. &pszDesc);
  337. if (FAILED(hr))
  338. {
  339. goto Cleanup;
  340. }
  341. }
  342. m_pszName = pszName;
  343. m_pszUrl = pszUrl;
  344. m_pszUdn = pszUdn;
  345. m_pszType = pszType;
  346. m_pszDesc = pszDesc;
  347. Cleanup:
  348. if (FAILED(hr))
  349. {
  350. if (pszName)
  351. {
  352. delete [] pszName;
  353. }
  354. if (pszUrl)
  355. {
  356. delete [] pszUrl;
  357. }
  358. if (pszUdn)
  359. {
  360. delete [] pszUdn;
  361. }
  362. if (pszType)
  363. {
  364. delete [] pszType;
  365. }
  366. if (pszDesc)
  367. {
  368. delete [] pszDesc;
  369. }
  370. }
  371. Assert(FImplies(SUCCEEDED(hr), pszName));
  372. Assert(FImplies(SUCCEEDED(hr), pszUrl));
  373. Assert(FImplies(SUCCEEDED(hr), pszUdn));
  374. Assert(FImplies(SUCCEEDED(hr), pszType));
  375. Assert(FImplies(SUCCEEDED(hr), pszDesc));
  376. TraceError("CUPnPDeviceFoldPidl::HrInit", hr);
  377. return hr;
  378. }
  379. HRESULT
  380. CUPnPDeviceFoldPidl::HrPersist(IMalloc * pMalloc, LPITEMIDLIST * ppidl)
  381. {
  382. Assert(m_pszName);
  383. Assert(m_pszUrl);
  384. Assert(m_pszUdn);
  385. Assert(m_pszType);
  386. Assert(m_pszDesc);
  387. Assert(pMalloc);
  388. Assert(ppidl);
  389. HRESULT hr;
  390. ULONG cbTotalPidlSize;
  391. ULONG cbName;
  392. ULONG cbUrl;
  393. ULONG cbUdn;
  394. ULONG cbType;
  395. ULONG cbDesc;
  396. ULONG ulNameOffset;
  397. ULONG ulUrlOffset;
  398. ULONG ulUdnOffset;
  399. ULONG ulTypeOffset;
  400. ULONG ulDescOffset;
  401. UNALIGNED UPNPUI_PIDL_HEADER * puph;
  402. LPBYTE pbData;
  403. hr = S_OK;
  404. pbData = NULL;
  405. cbName = wcslen(m_pszName);
  406. cbName = (cbName + 1) * sizeof(WCHAR);
  407. cbUrl = wcslen(m_pszUrl);
  408. cbUrl = (cbUrl + 1) * sizeof(WCHAR);
  409. cbUdn = wcslen(m_pszUdn);
  410. cbUdn = (cbUdn + 1) * sizeof(WCHAR);
  411. cbType = wcslen(m_pszType);
  412. cbType = (cbType + 1) * sizeof(WCHAR);
  413. cbDesc = wcslen(m_pszDesc);
  414. cbDesc = (cbDesc + 1) * sizeof(WCHAR);
  415. ulNameOffset = 0;
  416. ulUrlOffset = ulNameOffset + cbName;
  417. ulUdnOffset = ulUrlOffset + cbUrl;
  418. ulTypeOffset = ulUdnOffset + cbUdn;
  419. ulDescOffset = ulTypeOffset + cbType;
  420. cbTotalPidlSize = sizeof(UPNPUI_PIDL_HEADER);
  421. cbTotalPidlSize += cbName;
  422. cbTotalPidlSize += cbUrl;
  423. cbTotalPidlSize += cbUdn;
  424. cbTotalPidlSize += cbType;
  425. cbTotalPidlSize += cbDesc;
  426. // don't count the PIDL-terminating bytes in the size
  427. //
  428. pbData = (BYTE *) pMalloc->Alloc(cbTotalPidlSize +
  429. FIELD_OFFSET(ITEMIDLIST, mkid.cb) + sizeof(USHORT));
  430. if (!pbData)
  431. {
  432. hr = E_OUTOFMEMORY;
  433. TraceError("CUPnPDeviceFoldPidl::HrPersist: Alloc()", hr);
  434. goto Cleanup;
  435. }
  436. // delegate folder alert: since we're a delete folder, the Alloc() above
  437. // doesn't just allocate the bytes we asked for, but rather a bunch for our
  438. // delegate folder prefix, then the bytes we asked for. We need to skip
  439. // the prefix bytes and just write to our own.
  440. puph = (UPNPUI_PIDL_HEADER *)ConvertToUPnPDevicePIDL((ITEMIDLIST*)pbData);
  441. puph->iCB = cbTotalPidlSize;
  442. puph->uLeadId = UPNPDEVICEFOLDPIDL_LEADID;
  443. puph->dwVersion = UP_DEVICE_FOLDER_IDL_VERSION;
  444. puph->uTrailId = UPNPDEVICEFOLDPIDL_TRAILID;
  445. puph->uVOID = 0;
  446. puph->dwCharacteristics = 0;
  447. puph->ulNameOffset = ulNameOffset;
  448. puph->cbName = cbName;
  449. puph->ulUrlOffset = ulUrlOffset;
  450. puph->cbUrl = cbUrl;
  451. puph->ulUdnOffset = ulUdnOffset;
  452. puph->cbUdn = cbUdn;
  453. puph->ulTypeOffset = ulTypeOffset;
  454. puph->cbType = cbType;
  455. puph->ulDescOffset = ulDescOffset;
  456. puph->cbDesc = cbDesc;
  457. {
  458. LPBYTE pbDynamicField;
  459. LPBYTE pbName;
  460. LPBYTE pbUrl;
  461. LPBYTE pbUdn;
  462. LPBYTE pbType;
  463. LPBYTE pbDesc;
  464. // note: this has to be puph (not pbData) because we still
  465. // have to skip the "delegate folder prefix" junk.
  466. pbDynamicField = ((BYTE *)puph) + sizeof(UPNPUI_PIDL_HEADER);
  467. pbName = pbDynamicField + ulNameOffset;
  468. pbUrl = pbDynamicField + ulUrlOffset;
  469. pbUdn = pbDynamicField + ulUdnOffset;
  470. pbType = pbDynamicField + ulTypeOffset;
  471. pbDesc = pbDynamicField + ulDescOffset;
  472. ::CopyMemory(pbName, m_pszName, cbName);
  473. ::CopyMemory(pbUrl, m_pszUrl, cbUrl);
  474. ::CopyMemory(pbUdn, m_pszUdn, cbUdn);
  475. ::CopyMemory(pbType, m_pszType, cbType);
  476. ::CopyMemory(pbDesc, m_pszDesc, cbDesc);
  477. }
  478. {
  479. // terminate the PIDL
  480. LPITEMIDLIST pidlNext;
  481. pidlNext = ILNext((LPITEMIDLIST)puph);
  482. Assert((FIELD_OFFSET(ITEMIDLIST, mkid.cb) +
  483. sizeof(pidlNext->mkid.cb)) == sizeof(USHORT));
  484. pidlNext->mkid.cb = 0;
  485. }
  486. Cleanup:
  487. Assert(FImplies(FAILED(hr), !pbData));
  488. Assert(FImplies(SUCCEEDED(hr), pbData));
  489. *ppidl = (LPITEMIDLIST)pbData;
  490. TraceError("CUPnPDeviceFoldPidl::HrPersist", hr);
  491. return hr;
  492. }
  493. PCWSTR
  494. CUPnPDeviceFoldPidl::PszGetNamePointer() const
  495. {
  496. return m_pszName;
  497. }
  498. PCWSTR
  499. CUPnPDeviceFoldPidl::PszGetURLPointer() const
  500. {
  501. return m_pszUrl;
  502. }
  503. PCWSTR
  504. CUPnPDeviceFoldPidl::PszGetUDNPointer() const
  505. {
  506. return m_pszUdn;
  507. }
  508. PCWSTR
  509. CUPnPDeviceFoldPidl::PszGetTypePointer() const
  510. {
  511. return m_pszType;
  512. }
  513. PCWSTR
  514. CUPnPDeviceFoldPidl::PszGetDescriptionPointer() const
  515. {
  516. return m_pszDesc;
  517. }
  518. HRESULT CUPnPDeviceFoldPidl::HrSetName(PCWSTR szName)
  519. {
  520. HRESULT hr = S_OK;
  521. if (szName)
  522. {
  523. // Free old name
  524. delete [] m_pszName;
  525. // Copy in new name
  526. m_pszName = WszDupWsz(szName);
  527. if (!m_pszName)
  528. {
  529. hr = E_OUTOFMEMORY;
  530. }
  531. }
  532. TraceError("CUPnPDeviceFoldPidl::HrSetName", hr);
  533. return hr;
  534. }
  535. //+---------------------------------------------------------------------------
  536. //
  537. // Member: CUPnPDeviceFolder::HrMakeUPnPDevicePidl
  538. //
  539. // Purpose: Private function of the folder object that constructs the
  540. // UPNP device pidl using the delegated allocator
  541. //
  542. // Arguments:
  543. // FolderDeviceNode [in] Structure that contains all the
  544. // strings we need for the pidl
  545. // ppidl [out] The result pidl
  546. //
  547. // Returns: Returns NOERROR if successful or an OLE-defined error
  548. // value otherwise
  549. //
  550. // Author: tongl 15 Feb 2000
  551. //
  552. // Notes:
  553. //
  554. HRESULT CUPnPDeviceFolder::HrMakeUPnPDevicePidl(FolderDeviceNode * pDeviceNode,
  555. LPITEMIDLIST * ppidl)
  556. {
  557. HRESULT hr;
  558. CUPnPDeviceFoldPidl udfp;
  559. hr = udfp.HrInit(pDeviceNode);
  560. if (SUCCEEDED(hr))
  561. {
  562. hr = udfp.HrPersist(m_pDelegateMalloc, ppidl);
  563. }
  564. return hr;
  565. }
  566. HRESULT CUPnPDeviceFolder::HrMakeUPnPDevicePidl(IUPnPDevice * pDevice,
  567. LPITEMIDLIST * ppidl)
  568. {
  569. HRESULT hr = S_OK;
  570. Assert(pDevice);
  571. BSTR bstrUDN = NULL;
  572. BSTR bstrDisplayName = NULL;
  573. BSTR bstrType = NULL;
  574. BSTR bstrPresentationURL = NULL;
  575. BSTR bstrDescription = NULL;
  576. Assert(pDevice);
  577. pDevice->AddRef();
  578. hr = pDevice->get_UniqueDeviceName(&bstrUDN);
  579. if (SUCCEEDED(hr))
  580. {
  581. hr = pDevice->get_FriendlyName(&bstrDisplayName);
  582. if (SUCCEEDED(hr))
  583. {
  584. hr = pDevice->get_Type(&bstrType);
  585. if (SUCCEEDED(hr))
  586. {
  587. hr = pDevice->get_PresentationURL(&bstrPresentationURL);
  588. if (SUCCEEDED(hr))
  589. {
  590. hr = pDevice->get_Description(&bstrDescription);
  591. if (SUCCEEDED(hr))
  592. {
  593. FolderDeviceNode * pDevNode = new FolderDeviceNode;
  594. if (pDevNode)
  595. {
  596. // the buffers in FolderDeviceNode are MAX_PATH
  597. // wide, so we can only copy MAX_PATH - 1 chars
  598. // and still have room for the terminating null
  599. //
  600. CONST SIZE_T cchMax = MAX_PATH - 1;
  601. Assert(bstrUDN);
  602. wcscpy(pDevNode->pszUDN, L"");
  603. wcsncat(pDevNode->pszUDN,(PWSTR)bstrUDN,cchMax);
  604. Assert(bstrDisplayName);
  605. wcscpy(pDevNode->pszDisplayName, L"");
  606. wcsncat(pDevNode->pszDisplayName,(PWSTR)bstrDisplayName,cchMax);
  607. Assert(bstrType);
  608. wcscpy(pDevNode->pszType, L"");
  609. wcsncat(pDevNode->pszType,(PWSTR)bstrType,cchMax);
  610. wcscpy(pDevNode->pszPresentationURL, L"");
  611. if (bstrPresentationURL)
  612. {
  613. wcsncat(pDevNode->pszPresentationURL,
  614. (PWSTR)bstrPresentationURL,
  615. cchMax);
  616. }
  617. wcscpy(pDevNode->pszDescription, L"");
  618. if (bstrDescription)
  619. {
  620. wcsncat(pDevNode->pszDescription,
  621. (PWSTR)bstrDescription,
  622. cchMax);
  623. }
  624. hr = HrMakeUPnPDevicePidl(pDevNode, ppidl);
  625. }
  626. else
  627. {
  628. hr = E_OUTOFMEMORY;
  629. }
  630. }
  631. else
  632. {
  633. TraceTag(ttidShellFolder, "Failed in pDevice->get_Description from HrMakeUPnPDevicePidl");
  634. }
  635. }
  636. else
  637. {
  638. TraceTag(ttidShellFolder, "Failed in pDevice->get_PresentationURL from HrMakeUPnPDevicePidl");
  639. }
  640. }
  641. else
  642. {
  643. TraceTag(ttidShellFolder, "Failed in pDevice->get_Type from HrMakeUPnPDevicePidl");
  644. }
  645. }
  646. else
  647. {
  648. TraceTag(ttidShellFolder, "Failed in pDevice->get_FriendlyName from HrMakeUPnPDevicePidl");
  649. }
  650. }
  651. else
  652. {
  653. TraceTag(ttidShellFolder, "Failed in pDevice->get_UniqueDeviceName from HrMakeUPnPDevicePidl");
  654. }
  655. SysFreeString(bstrUDN);
  656. SysFreeString(bstrDisplayName);
  657. SysFreeString(bstrPresentationURL);
  658. SysFreeString(bstrType);
  659. SysFreeString(bstrDescription);
  660. ReleaseObj(pDevice);
  661. TraceError("CUPnPDeviceFolder::HrMakeUPnPDevicePidl", hr);
  662. return hr;
  663. }
  664. //+---------------------------------------------------------------------------
  665. //
  666. // Member: CUPnPDeviceFolder::ParseDisplayName
  667. //
  668. // Purpose: Translates a file object or folder's display name into an
  669. // item identifier.
  670. //
  671. // Arguments:
  672. // hwndOwner [in] Handle of owner window
  673. // pbcReserved [in] Reserved
  674. // lpszDisplayName [in] Pointer to diplay name
  675. // pchEaten [out] Pointer to value for parsed characters
  676. // ppidl [out] Pointer to new item identifier list
  677. // pdwAttributes [out] Address receiving attributes of file object
  678. //
  679. // Returns: Returns NOERROR if successful or an OLE-defined error
  680. // value otherwise
  681. //
  682. // Author: tongl 16 Feb 2000
  683. //
  684. // Notes:
  685. //
  686. STDMETHODIMP CUPnPDeviceFolder::ParseDisplayName(
  687. HWND hwndOwner,
  688. LPBC pbcReserved,
  689. LPOLESTR lpszDisplayName,
  690. ULONG * pchEaten,
  691. LPITEMIDLIST * ppidl,
  692. ULONG * pdwAttributes)
  693. {
  694. TraceTag(ttidShellFolderIface, "CUPnPDeviceFolder::ParseDisplayName");
  695. HRESULT hr = S_OK;
  696. // note: this is bogus, but we're doing this all over...
  697. Assert(lpszDisplayName);
  698. Assert(ppidl);
  699. *ppidl = NULL;
  700. // first, make sure that this is one of our display names:
  701. // it must start with c_szDelegateFolderPrefix
  702. //
  703. int result;
  704. result = wcsncmp(lpszDisplayName,
  705. c_szDelegateFolderPrefix,
  706. c_cchDelegateFolderPrefix);
  707. if (0 == result)
  708. {
  709. LPCWSTR pszUdn = NULL;
  710. LPITEMIDLIST pidlDevice = NULL;
  711. FolderDeviceNode * pDeviceNode = NULL;
  712. // this is OK since lpszDisplayName is an LPOLESTR
  713. pszUdn = lpszDisplayName + c_cchDelegateFolderPrefix;
  714. // search our list of devices and try to find a matching UDN
  715. if (g_CListFolderDeviceNode.FFind(pszUdn, &pDeviceNode))
  716. {
  717. Assert(pDeviceNode);
  718. // yes, this is one of our devices, construct the pidl using
  719. // the allocator we are given
  720. hr = HrMakeUPnPDevicePidl(pDeviceNode, &pidlDevice);
  721. if (SUCCEEDED(hr))
  722. {
  723. Assert(pidlDevice);
  724. *ppidl = pidlDevice;
  725. if (pdwAttributes)
  726. {
  727. *pdwAttributes = 0;
  728. }
  729. }
  730. }
  731. else
  732. {
  733. // no, we don't have such a device in the list
  734. // (tongl): try to do a SearchByUDN before we fail the call,
  735. // as this may be a device discovered by the search from the
  736. // tray icon, and we are asked for the pidl to create a shortcut.
  737. BSTR bstrUdn = NULL;
  738. IUPnPDeviceFinder * pdf = NULL;
  739. bstrUdn = ::SysAllocString(pszUdn);
  740. if (bstrUdn)
  741. {
  742. hr = CoCreateInstance(CLSID_UPnPDeviceFinder, NULL, CLSCTX_INPROC_SERVER,
  743. IID_IUPnPDeviceFinder, (LPVOID *)&pdf);
  744. if (SUCCEEDED(hr))
  745. {
  746. IUPnPDevice * pdev = NULL;
  747. hr = pdf->FindByUDN(bstrUdn, &pdev);
  748. if (S_OK == hr)
  749. {
  750. hr = HrMakeUPnPDevicePidl(pdev, &pidlDevice);
  751. ReleaseObj(pdev);
  752. }
  753. ReleaseObj(pdf);
  754. }
  755. ::SysFreeString(bstrUdn);
  756. }
  757. else
  758. {
  759. hr = E_OUTOFMEMORY;
  760. TraceError("CUPnPDeviceFolder::ParseDisplayName: "
  761. "SysAllocString", hr);
  762. }
  763. }
  764. }
  765. else
  766. {
  767. TraceTag(ttidShellFolderIface,
  768. "CUPnPDeviceFolder::ParseDisplayName: "
  769. "passed non-upnp display name");
  770. hr = E_FAIL;
  771. }
  772. TraceHr(ttidShellFolder, FAL, hr, FALSE, "CUPnPDeviceFolder::ParseDisplayName");
  773. return hr;
  774. }
  775. //+---------------------------------------------------------------------------
  776. //
  777. // Member: CUPnPDeviceFolder::EnumObjects
  778. //
  779. // Purpose: Determines the contents of a folder by creating an item
  780. // enumeration object (a set of item identifiers) that can be
  781. // retrieved using the IEnumIDList interface.
  782. //
  783. // Arguments:
  784. // hwndOwner [in] Handle of owner window
  785. // grfFlags [in] Items to include in enumeration
  786. // ppenumIDList [out] Pointer to IEnumIDList
  787. //
  788. // Returns: Returns NOERROR if successful or an OLE-defined error
  789. // value otherwise
  790. //
  791. // Author: jeffspr 18 Oct 1997
  792. //
  793. // Notes:
  794. //
  795. STDMETHODIMP CUPnPDeviceFolder::EnumObjects(
  796. HWND hwndOwner,
  797. DWORD grfFlags,
  798. LPENUMIDLIST * ppenumIDList)
  799. {
  800. HRESULT hr = NOERROR;
  801. Assert(ppenumIDList);
  802. *ppenumIDList = NULL;
  803. if ((grfFlags & SHCONTF_FOLDERS) && !(grfFlags & SHCONTF_NONFOLDERS))
  804. {
  805. // if shell wants to enumerate only folders, we don't return anything
  806. hr = E_NOTIMPL;
  807. }
  808. else
  809. {
  810. // Create the IEnumIDList object (CUPnPDeviceFolderEnum)
  811. //
  812. hr = CUPnPDeviceFolderEnum::CreateInstance (
  813. IID_IEnumIDList,
  814. reinterpret_cast<void**>(ppenumIDList));
  815. if (SUCCEEDED(hr))
  816. {
  817. Assert(*ppenumIDList);
  818. // Call the PidlInitialize function to allow the enumeration
  819. // object to copy the list.
  820. //
  821. reinterpret_cast<CUPnPDeviceFolderEnum *>(*ppenumIDList)->Initialize(
  822. m_pidlFolderRoot, this);
  823. }
  824. else
  825. {
  826. // On all failures, this should be NULL.
  827. if (*ppenumIDList)
  828. {
  829. ReleaseObj(*ppenumIDList);
  830. }
  831. *ppenumIDList = NULL;
  832. }
  833. }
  834. TraceHr(ttidError, FAL, hr, FALSE, "CUPnPDeviceFolder::EnumObjects");
  835. return hr;
  836. }
  837. //+---------------------------------------------------------------------------
  838. //
  839. // Member: CUPnPDeviceFolder::BindToObject
  840. //
  841. // Purpose: Creates an IShellFolder object for a subfolder.
  842. //
  843. // Arguments:
  844. // pidl [in] Pointer to an ITEMIDLIST
  845. // pbcReserved [in] Reserved - specify NULL
  846. // riid [in] Interface to return
  847. // ppvOut [out] Address that receives interface pointer;
  848. //
  849. // Returns: Returns NOERROR if successful or an OLE-defined error
  850. // value otherwise
  851. //
  852. // Author: jeffspr 18 Oct 1997
  853. //
  854. // Notes: We don't need this function, since we don't have subfolders.
  855. //
  856. STDMETHODIMP CUPnPDeviceFolder::BindToObject(
  857. LPCITEMIDLIST pidl,
  858. LPBC pbcReserved,
  859. REFIID riid,
  860. LPVOID * ppvOut)
  861. {
  862. HRESULT hr = E_NOTIMPL;
  863. // Note - If we add code here, then we ought to param check pidl
  864. //
  865. Assert(pidl);
  866. *ppvOut = NULL;
  867. TraceHr(ttidShellFolder, FAL, hr, FALSE, "CUPnPDeviceFolder::BindToObject");
  868. return hr;
  869. }
  870. //+---------------------------------------------------------------------------
  871. //
  872. // Member: CUPnPDeviceFolder::BindToStorage
  873. //
  874. // Purpose: Reserved for a future use. This method should
  875. // return E_NOTIMPL.
  876. //
  877. // Arguments:
  878. // pidl [] Pointer to an ITEMIDLIST
  879. // pbcReserved [] Reserved�specify NULL
  880. // riid [] Interface to return
  881. // ppvObj [] Address that receives interface pointer);
  882. //
  883. // Returns: E_NOTIMPL always
  884. //
  885. // Author: jeffspr 18 Oct 1997
  886. //
  887. // Notes:
  888. //
  889. STDMETHODIMP CUPnPDeviceFolder::BindToStorage(
  890. LPCITEMIDLIST pidl,
  891. LPBC pbcReserved,
  892. REFIID riid,
  893. LPVOID * ppvObj)
  894. {
  895. HRESULT hr = E_NOTIMPL;
  896. // Note - If we add code here, then we ought to param check pidl
  897. //
  898. Assert(pidl);
  899. *ppvObj = NULL;
  900. TraceHr(ttidShellFolder, FAL, hr, FALSE, "CUPnPDeviceFolder::BindToStorage");
  901. return hr;
  902. }
  903. //+---------------------------------------------------------------------------
  904. //
  905. // Member: CUPnPDeviceFolder::CompareIDs
  906. //
  907. // Purpose: Determines the relative ordering of two file objects or
  908. // folders, given their item identifier lists.
  909. //
  910. // Arguments:
  911. // lParam [in] Type of comparison to perform
  912. // pidl1 [in] Address of ITEMIDLIST structure
  913. // pidl2 [in] Address of ITEMIDLIST structure
  914. //
  915. // Returns: Returns a handle to a result code. If this method is
  916. // successful, the CODE field of the status code (SCODE) has
  917. // the following meaning:
  918. //
  919. // CODE field Meaning
  920. // ---------- -------
  921. // Less than zero The first item should precede the second
  922. // (pidl1 < pidl2).
  923. // Greater than zero The first item should follow the second
  924. // (pidl1 > pidl2)
  925. // Zero The two items are the same (pidl1 = pidl2)
  926. //
  927. // Author: jeffspr 18 Oct 1997
  928. //
  929. // Notes: Passing 0 as the lParam indicates sort by name.
  930. // 0x00000001-0x7fffffff are for folder specific sorting rules.
  931. // 0x80000000-0xfffffff are used the system.
  932. //
  933. STDMETHODIMP CUPnPDeviceFolder::CompareIDs(
  934. LPARAM lParam,
  935. LPCITEMIDLIST pidl1,
  936. LPCITEMIDLIST pidl2)
  937. {
  938. HRESULT hr = S_OK;
  939. PUPNPDEVICEFOLDPIDL pupdfp1 = NULL;
  940. PUPNPDEVICEFOLDPIDL pupdfp2 = NULL;
  941. CUPnPDeviceFoldPidl udfp1;
  942. CUPnPDeviceFoldPidl udfp2;
  943. LPCWSTR psz1;
  944. LPCWSTR psz2;
  945. CONST INT ciTieBreaker = -1;
  946. int iCompare = 0;
  947. int result;
  948. TraceTag(ttidShellFolderIface, "OBJ: CUPnPDeviceFolder::CompareIDs");
  949. // Make sure that the pidls passed in are our pidls.
  950. //
  951. if (!FIsUPnPDeviceFoldPidl(pidl1) || !FIsUPnPDeviceFoldPidl(pidl2))
  952. {
  953. hr = E_INVALIDARG;
  954. goto Exit;
  955. }
  956. pupdfp1 = ConvertToUPnPDevicePIDL(pidl1);
  957. pupdfp2 = ConvertToUPnPDevicePIDL(pidl2);
  958. hr = udfp1.HrInit(pupdfp1);
  959. if (FAILED(hr))
  960. {
  961. goto Exit;
  962. }
  963. hr = udfp2.HrInit(pupdfp2);
  964. if (FAILED(hr))
  965. {
  966. goto Exit;
  967. }
  968. // We use the following procedure to compare PIDLs:
  969. // 1. If two UDNs are the same, the PIDLs are the same
  970. // 2. Otherwise, the PIDLs _must_ be different, and
  971. // A. will be sorted based on the desired column
  972. // B. If the column text matches, we'll return
  973. // ciTieBreaker (-1), so that the PIDLs are
  974. // distinguished.
  975. //
  976. psz1 = udfp1.PszGetUDNPointer();
  977. psz2 = udfp2.PszGetUDNPointer();
  978. Assert(psz1 && psz2);
  979. result = wcscmp(psz1, psz2);
  980. if (0 == result)
  981. {
  982. // The UDNs match, these are effectively the same PIDL
  983. TraceTag(ttidShellFolder, "CUPnPDeviceFolder::CompareIDs: "
  984. "UDN equal, automatically returning equality");
  985. iCompare = 0;
  986. }
  987. else
  988. {
  989. // Sort based on the desired column
  990. switch(lParam & SHCIDS_COLUMNMASK)
  991. {
  992. case ICOL_NAME:
  993. psz1 = udfp1.PszGetNamePointer();
  994. psz2 = udfp2.PszGetNamePointer();
  995. break;
  996. case ICOL_URL:
  997. psz1 = udfp1.PszGetURLPointer();
  998. psz2 = udfp2.PszGetURLPointer();
  999. break;
  1000. case ICOL_UDN:
  1001. psz1 = udfp1.PszGetUDNPointer();
  1002. psz2 = udfp2.PszGetUDNPointer();
  1003. break;
  1004. case ICOL_TYPE:
  1005. psz1 = udfp1.PszGetTypePointer();
  1006. psz2 = udfp2.PszGetTypePointer();
  1007. break;
  1008. default:
  1009. AssertSz(FALSE, "Sorting on unknown category");
  1010. break;
  1011. }
  1012. Assert(psz1 && psz2);
  1013. iCompare = _wcsicmp(psz1, psz2);
  1014. // Ensure that we don't return equality
  1015. if (0 == iCompare)
  1016. {
  1017. TraceTag(ttidShellFolder, "CUPnPDeviceFolder::CompareIDs: "
  1018. "UDNs unequal but column-text equal, breaking tie");
  1019. iCompare = ciTieBreaker;
  1020. }
  1021. }
  1022. if (SUCCEEDED(hr))
  1023. {
  1024. hr = ResultFromShort(iCompare);
  1025. }
  1026. TraceTag(ttidShellFolder, "CUPnPDeviceFolder::CompareIDs: returning %d", iCompare);
  1027. Exit:
  1028. TraceHr(ttidError, FAL, hr, SUCCEEDED(hr), "CUPnPDeviceFolder::CompareIDs");
  1029. return hr;
  1030. }
  1031. //+---------------------------------------------------------------------------
  1032. //
  1033. // Member: CUPnPDeviceFolder::CreateViewObject
  1034. //
  1035. // Purpose: Creates a view object of a folder.
  1036. //
  1037. // Arguments:
  1038. // hwndOwner [in] Handle of owner window
  1039. // riid [in] Interface identifier
  1040. // ppvOut [none] Reserved
  1041. //
  1042. // Returns: Returns NOERROR if successful or an OLE defined error
  1043. // value otherwise.
  1044. //
  1045. // Author: jeffspr 18 Oct 1997
  1046. //
  1047. // Notes:
  1048. //
  1049. STDMETHODIMP CUPnPDeviceFolder::CreateViewObject(
  1050. HWND hwndOwner,
  1051. REFIID riid,
  1052. LPVOID * ppvOut)
  1053. {
  1054. HRESULT hr = E_NOINTERFACE;
  1055. TraceTag(ttidShellFolderIface, "OBJ: CUPnPDeviceFolder::CreateViewObject");
  1056. Assert(ppvOut);
  1057. // Pre-initialize the out param, per OLE guidelines
  1058. //
  1059. *ppvOut = NULL;
  1060. // (tongl) We are a delegate folder now, CreateViewObject is never called.
  1061. return E_NOTIMPL;
  1062. }
  1063. //+---------------------------------------------------------------------------
  1064. //
  1065. // Member: CUPnPDeviceFolder::GetAttributesOf
  1066. //
  1067. // Purpose: Retrieves the attributes that all passed-in objects (file
  1068. // objects or subfolders) have in common.
  1069. //
  1070. // Arguments:
  1071. // cidl [in] Number of file objects
  1072. // apidl [in] Pointer to array of pointers to ITEMIDLIST structures
  1073. // rgfInOut [out] Address of value containing attributes of the
  1074. // file objects
  1075. //
  1076. // Returns: Returns NOERROR if successful or an OLE-defined error
  1077. // value otherwise.
  1078. //
  1079. // Author: jeffspr 18 Oct 1997
  1080. //
  1081. // Notes:
  1082. //
  1083. STDMETHODIMP CUPnPDeviceFolder::GetAttributesOf(
  1084. UINT cidl,
  1085. LPCITEMIDLIST * apidl,
  1086. ULONG * rgfInOut)
  1087. {
  1088. HRESULT hr = S_OK;
  1089. ULONG rgfMask = 0;
  1090. PUPNPDEVICEFOLDPIDL pupdfp = NULL;
  1091. TraceTag(ttidShellFolderIface, "OBJ: CUPnPDeviceFolder::GetAttributesOf");
  1092. if (cidl > 0)
  1093. {
  1094. // Prepopulate with all values (removed CANCOPY and CANMOVE)
  1095. //
  1096. rgfMask = /* SFGAO_CANDELETE | */ // Don't support delete
  1097. SFGAO_CANRENAME |
  1098. SFGAO_CANLINK |
  1099. SFGAO_HASPROPSHEET;
  1100. // Disable propsheets for > 1 object
  1101. //
  1102. if (cidl > 1)
  1103. {
  1104. rgfMask &= ~SFGAO_HASPROPSHEET;
  1105. }
  1106. }
  1107. else
  1108. {
  1109. // Apparently, we're called with 0 objects to indicate that we're
  1110. // supposed to return flags for the folder itself, not an individual
  1111. // object. Weird.
  1112. rgfMask = SFGAO_CANCOPY |
  1113. SFGAO_CANDELETE |
  1114. SFGAO_CANMOVE |
  1115. SFGAO_CANRENAME;
  1116. }
  1117. if (SUCCEEDED(hr))
  1118. {
  1119. *rgfInOut &= rgfMask;
  1120. }
  1121. return hr;
  1122. }
  1123. //+---------------------------------------------------------------------------
  1124. //
  1125. // Member: CUPnPDeviceFolder::GetUIObjectOf
  1126. //
  1127. // Purpose: Creates a COM object that can be used to carry out actions
  1128. // on the specified file objects or folders, typically, to
  1129. // create context menus or carry out drag-and-drop operations.
  1130. //
  1131. // Arguments:
  1132. // hwndOwner [in] Handle to owner window
  1133. // cidl [in] Number of objects specified in apidl
  1134. // apidl [in] Pointer to an array of pointers to an ITEMIDLIST
  1135. // riid [in] Interface to return
  1136. // prgfInOut [none] Reserved
  1137. // ppvOut [out] Address to receive interface pointer
  1138. //
  1139. // Returns: Returns NOERROR if successful or an OLE-defined error
  1140. // value otherwise
  1141. //
  1142. // Author: jeffspr 18 Oct 1997
  1143. //
  1144. // Notes:
  1145. //
  1146. STDMETHODIMP CUPnPDeviceFolder::GetUIObjectOf(
  1147. HWND hwndOwner,
  1148. UINT cidl,
  1149. LPCITEMIDLIST * apidl,
  1150. REFIID riid,
  1151. UINT * prgfInOut,
  1152. LPVOID * ppvOut)
  1153. {
  1154. HRESULT hr = E_NOINTERFACE;
  1155. TraceTag(ttidShellFolderIface, "OBJ: CUPnPDeviceFolder::GetUIObjectOf");
  1156. if (cidl >= 1)
  1157. {
  1158. Assert(apidl);
  1159. Assert(apidl[0]);
  1160. Assert(ppvOut);
  1161. if (riid == IID_IDataObject)
  1162. {
  1163. // Need to initialize so the SUCCEEED check below doesn't fail.
  1164. //
  1165. hr = S_OK;
  1166. Assert(m_pidlFolderRoot);
  1167. if (SUCCEEDED(hr))
  1168. {
  1169. Assert(m_pidlFolderRoot);
  1170. // Internal IDataObject impl removed. Replaced with common
  1171. // shell code.
  1172. //
  1173. hr = CIDLData_CreateFromIDArray(m_pidlFolderRoot, cidl, apidl, (IDataObject **) ppvOut);
  1174. }
  1175. }
  1176. else if (riid == IID_IContextMenu)
  1177. {
  1178. // Create our context menu object if only one device is selected
  1179. //
  1180. hr = CUPnPDeviceFolderContextMenu::CreateInstance (
  1181. IID_IContextMenu,
  1182. reinterpret_cast<void**>(ppvOut),
  1183. CMT_OBJECT,
  1184. hwndOwner,
  1185. cidl,
  1186. apidl,
  1187. this);
  1188. if (SUCCEEDED(hr))
  1189. {
  1190. Assert(*ppvOut);
  1191. }
  1192. else
  1193. {
  1194. hr = E_NOINTERFACE;
  1195. }
  1196. }
  1197. else if (riid == IID_IExtractIconA || riid == IID_IExtractIconW)
  1198. {
  1199. if (cidl == 1)
  1200. {
  1201. hr = CUPnPDeviceFolderExtractIcon::CreateInstance (
  1202. apidl[0],
  1203. riid,
  1204. reinterpret_cast<void**>(ppvOut));
  1205. if(SUCCEEDED(hr))
  1206. {
  1207. hr = reinterpret_cast<CUPnPDeviceFolderExtractIcon *>
  1208. (*ppvOut)->Initialize((LPITEMIDLIST)apidl[0]);
  1209. }
  1210. if (SUCCEEDED(hr))
  1211. {
  1212. Assert(*ppvOut);
  1213. }
  1214. }
  1215. else
  1216. {
  1217. hr = E_NOINTERFACE;
  1218. }
  1219. }
  1220. else if (riid == IID_IDropTarget)
  1221. {
  1222. // We don't support drag/drop
  1223. //
  1224. hr = E_NOINTERFACE;
  1225. }
  1226. else if (riid == IID_IQueryInfo)
  1227. {
  1228. if (cidl == 1)
  1229. {
  1230. // Create the IQueryInfo interface
  1231. hr = CUPnPDeviceFolderQueryInfo::CreateInstance (
  1232. IID_IQueryInfo,
  1233. reinterpret_cast<void**>(ppvOut));
  1234. if (SUCCEEDED(hr))
  1235. {
  1236. Assert(*ppvOut);
  1237. reinterpret_cast<CUPnPDeviceFolderQueryInfo *>
  1238. (*ppvOut)->PidlInitialize((LPITEMIDLIST)apidl[0]);
  1239. // Normalize return code
  1240. //
  1241. hr = NOERROR;
  1242. }
  1243. }
  1244. else
  1245. {
  1246. AssertSz(FALSE, "GetUIObjectOf asked for query info for more than one item!");
  1247. hr = E_NOINTERFACE;
  1248. }
  1249. }
  1250. else
  1251. {
  1252. TraceTag(ttidShellFolder, "CUPnPDeviceFolder::GetUIObjectOf asked for object "
  1253. "that it didn't know how to create. 0x%08x", riid.Data1);
  1254. hr = E_NOINTERFACE;
  1255. }
  1256. }
  1257. if (FAILED(hr))
  1258. {
  1259. *ppvOut = NULL;
  1260. }
  1261. TraceHr(ttidError, FAL, hr, (hr == E_NOINTERFACE), "CUPnPDeviceFolder::GetUIObjectOf");
  1262. return hr;
  1263. }
  1264. //+---------------------------------------------------------------------------
  1265. //
  1266. // Function: HrTszToStrRet
  1267. //
  1268. // Purpose: Convert a TCHAR string to a STRRET, depending on the platform
  1269. //
  1270. // Arguments:
  1271. // pszName [in] input string
  1272. // pStrRet [in/out] output STRRET
  1273. //
  1274. // Returns:
  1275. //
  1276. // Author: jeffspr 25 Jan 2000
  1277. //
  1278. // Notes:
  1279. //
  1280. HRESULT HrTszToStrRet(LPCTSTR pszName, STRRET *pStrRet)
  1281. {
  1282. HRESULT hr = S_OK;
  1283. #ifdef UNICODE
  1284. pStrRet->uType = STRRET_WSTR;
  1285. // Allocate a new POLESTR block, which the shell can then free,
  1286. // and copy the displayable portion to it.
  1287. //
  1288. hr = HrDupeShellString(
  1289. pszName,
  1290. &pStrRet->pOleStr);
  1291. #else
  1292. pStrRet->uType = STRRET_CSTR;
  1293. lstrcpyn(pStrRet->cStr, pszName, celems(pStrRet->cStr));
  1294. hr = S_OK;
  1295. #endif
  1296. return hr;
  1297. }
  1298. //+---------------------------------------------------------------------------
  1299. //
  1300. // Member: CUPnPDeviceFolder::GetDisplayNameOf
  1301. //
  1302. // Purpose: Retrieves the display name for the specified file object or
  1303. // subfolder, returning it in a STRRET structure.
  1304. //
  1305. // Arguments:
  1306. // pidl [in] Pointer to an ITEMIDLIST
  1307. // uFlags [in] Type of display to return
  1308. // lpName [out] Pointer to a STRRET structure
  1309. //
  1310. // Returns: Returns NOERROR if successful or an OLE-defined error
  1311. // value otherwise.
  1312. //
  1313. // Author: jeffspr 18 Oct 1997
  1314. //
  1315. // Notes:
  1316. //
  1317. STDMETHODIMP CUPnPDeviceFolder::GetDisplayNameOf(
  1318. LPCITEMIDLIST pidl,
  1319. DWORD uFlags,
  1320. LPSTRRET lpName)
  1321. {
  1322. HRESULT hr = S_OK;
  1323. PCWSTR pwszStrToCopy = NULL;
  1324. PTSTR pszTemp = NULL;
  1325. PUPNPDEVICEFOLDPIDL pupdfp = NULL;
  1326. TraceTag(ttidShellFolderIface, "OBJ: CUPnPDeviceFolder::GetDisplayNameOf");
  1327. Assert(pidl);
  1328. Assert(lpName);
  1329. if (!pidl || !lpName)
  1330. {
  1331. hr = E_INVALIDARG;
  1332. }
  1333. else if (FIsUPnPDeviceFoldPidl(pidl))
  1334. {
  1335. CUPnPDeviceFoldPidl udfp;
  1336. pupdfp = ConvertToUPnPDevicePIDL(pidl);
  1337. #ifdef DBG
  1338. // Throw these in here just so I can quickly peek at the values
  1339. // set while I'm dorking around in the debugger.
  1340. //
  1341. DWORD dwInFolder = (uFlags & SHGDN_INFOLDER);
  1342. DWORD dwForAddressBar = (uFlags & SHGDN_FORADDRESSBAR);
  1343. DWORD dwForParsing = (uFlags & SHGDN_FORPARSING);
  1344. #endif
  1345. if (uFlags & SHGDN_FORPARSING)
  1346. {
  1347. #if 0
  1348. AssertSz(FALSE, "SHGDN_FORPARSING support NYI in GetDisplayNameOf");
  1349. #endif
  1350. }
  1351. hr = udfp.HrInit(pupdfp);
  1352. if (SUCCEEDED(hr))
  1353. {
  1354. pwszStrToCopy = udfp.PszGetNamePointer();
  1355. Assert(pwszStrToCopy);
  1356. pszTemp = TszFromWsz(pwszStrToCopy);
  1357. if (!pszTemp)
  1358. {
  1359. hr = E_OUTOFMEMORY;
  1360. }
  1361. else
  1362. {
  1363. hr = HrTszToStrRet(pszTemp, lpName);
  1364. free((PVOID) pszTemp);
  1365. }
  1366. }
  1367. }
  1368. else
  1369. {
  1370. // not a valid connections pidl (neither Win2K nor Win98).
  1371. //
  1372. hr = E_INVALIDARG;
  1373. }
  1374. TraceHr(ttidError, FAL, hr, FALSE, "CUPnPDeviceFolder::GetDisplayNameOf");
  1375. return hr;
  1376. }
  1377. //+---------------------------------------------------------------------------
  1378. //
  1379. // Member: CUPnPDeviceFolder::SetNameOf
  1380. //
  1381. // Purpose: Changes the name of a file object or subfolder, changing its
  1382. // item identifier in the process.
  1383. //
  1384. // Arguments:
  1385. // hwndOwner [in] Handle of owner window
  1386. // pidl [in] Pointer to an ITEMIDLIST structure
  1387. // lpszName [in] Pointer to string specifying new display name
  1388. // uFlags [in] Type of name specified in lpszName
  1389. // ppidlOut [out] Pointer to new ITEMIDLIST
  1390. //
  1391. // Returns: Returns NOERROR if successful or an OLE-defined error
  1392. // value otherwise.
  1393. //
  1394. // Author: jeffspr 18 Oct 1997
  1395. //
  1396. // Notes:
  1397. //
  1398. STDMETHODIMP CUPnPDeviceFolder::SetNameOf(
  1399. HWND hwndOwner,
  1400. LPCITEMIDLIST pidl,
  1401. LPCOLESTR lpszName,
  1402. DWORD uFlags,
  1403. LPITEMIDLIST * ppidlOut)
  1404. {
  1405. HRESULT hr = S_OK;
  1406. PUPNPDEVICEFOLDPIDL pupdfp = NULL;
  1407. TraceTag(ttidShellFolderIface, "OBJ: CUPnPDeviceFolder::SetNameOf");
  1408. Assert(hwndOwner);
  1409. Assert(pidl);
  1410. Assert(lpszName);
  1411. if (!pidl && !lpszName)
  1412. {
  1413. hr = E_INVALIDARG;
  1414. }
  1415. else if (!*lpszName)
  1416. {
  1417. hr = S_OK;
  1418. }
  1419. else if (FIsUPnPDeviceFoldPidl(pidl))
  1420. {
  1421. CUPnPDeviceFoldPidl udfp;
  1422. pupdfp = ConvertToUPnPDevicePIDL(pidl);
  1423. hr = udfp.HrInit(pupdfp);
  1424. if (SUCCEEDED(hr))
  1425. {
  1426. // Change the name of the item in the PIDL
  1427. hr = udfp.HrSetName(lpszName);
  1428. }
  1429. if (SUCCEEDED(hr))
  1430. {
  1431. LPITEMIDLIST pidlOut;
  1432. // Persist the PIDL data to a new PIDL so we can generate an event
  1433. // for it
  1434. hr = udfp.HrPersist(m_pDelegateMalloc, &pidlOut);
  1435. if (SUCCEEDED(hr))
  1436. {
  1437. NAME_MAP * pnm;
  1438. pnm = new NAME_MAP;
  1439. if (pnm)
  1440. {
  1441. // Copy the name and UDN to a struct to keep in a list
  1442. // of mapped UDNs to friendly names.
  1443. //
  1444. pnm->szName = TszDupTsz(udfp.PszGetNamePointer());
  1445. if (!pnm->szName)
  1446. {
  1447. hr = E_OUTOFMEMORY;
  1448. }
  1449. else
  1450. {
  1451. pnm->szUdn = TszDupTsz(udfp.PszGetUDNPointer());
  1452. if (!pnm->szUdn)
  1453. {
  1454. hr = E_OUTOFMEMORY;
  1455. }
  1456. else
  1457. {
  1458. // Delete the item and re-add it again
  1459. g_CListNameMap.FDelete(udfp.PszGetUDNPointer());
  1460. g_CListNameMap.FAdd(pnm);
  1461. // Notify the shell of the rename
  1462. GenerateEvent(SHCNE_RENAMEITEM, m_pidlFolderRoot,
  1463. pidl, pidlOut);
  1464. FolderDeviceNode * pDeviceNode;
  1465. if (g_CListFolderDeviceNode.FFind(pnm->szUdn,
  1466. &pDeviceNode))
  1467. {
  1468. // Delete the node's old name and give it the new
  1469. // one
  1470. //
  1471. wcscpy(pDeviceNode->pszDisplayName,
  1472. pnm->szName);
  1473. }
  1474. }
  1475. }
  1476. }
  1477. else
  1478. {
  1479. hr = E_OUTOFMEMORY;
  1480. }
  1481. if (ppidlOut)
  1482. {
  1483. *ppidlOut = pidlOut;
  1484. }
  1485. else
  1486. {
  1487. FreeIDL(pidlOut);
  1488. }
  1489. }
  1490. }
  1491. }
  1492. else
  1493. {
  1494. // not a valid UPnP pidl
  1495. //
  1496. hr = E_INVALIDARG;
  1497. }
  1498. TraceHr(ttidError, FAL, hr, FALSE, "CUPnPDeviceFolder::SetNameOf");
  1499. return hr;
  1500. }