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.

1208 lines
31 KiB

  1. #include "local.h"
  2. #include "resource.h"
  3. #include <limits.h>
  4. #include <mluisupp.h>
  5. #include "chcommon.h"
  6. #define DM_HSFOLDER 0
  7. STDAPI AddToFavorites(HWND hwnd, LPCITEMIDLIST pidlCur, LPCTSTR pszTitle,
  8. BOOL fDisplayUI, IOleCommandTarget *pCommandTarget, IHTMLDocument2 *pDoc);
  9. /*********************************************************************
  10. StrHash implementation
  11. *********************************************************************/
  12. //////////////////////////////////////////////////////////////////////
  13. // StrHashNode
  14. StrHash::StrHashNode::StrHashNode(LPCTSTR psz, void* pv, int fCopy,
  15. StrHashNode* next) {
  16. ASSERT(psz);
  17. pszKey = (fCopy ? StrDup(psz) : psz);
  18. pvVal = pv; // don't know the size -- you'll have to destroy
  19. this->fCopy = fCopy;
  20. this->next = next;
  21. }
  22. StrHash::StrHashNode::~StrHashNode() {
  23. if (fCopy)
  24. {
  25. LocalFree(const_cast<LPTSTR>(pszKey));
  26. pszKey = NULL;
  27. }
  28. }
  29. //////////////////////////////////////////////////////////////////////
  30. // StrHash
  31. const unsigned int StrHash::sc_auPrimes[] = {
  32. 29, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593
  33. };
  34. const unsigned int StrHash::c_uNumPrimes = 11;
  35. const unsigned int StrHash::c_uFirstPrime = 4;
  36. // load factor is computed as (n * USHRT_MAX / t) where 'n' is #elts in table
  37. // and 't' is table size
  38. const unsigned int StrHash::c_uMaxLoadFactor = ((USHRT_MAX * 100) / 95); // .95
  39. StrHash::StrHash(int fCaseInsensitive) {
  40. nCurPrime = c_uFirstPrime;
  41. nBuckets = sc_auPrimes[nCurPrime];
  42. // create an array of buckets and null out each one
  43. ppshnHashChain = new StrHashNode* [nBuckets];
  44. if (ppshnHashChain) {
  45. for (unsigned int i = 0; i < nBuckets; ++i)
  46. ppshnHashChain[i] = NULL;
  47. }
  48. nElements = 0;
  49. _fCaseInsensitive = fCaseInsensitive;
  50. }
  51. StrHash::~StrHash() {
  52. if (ppshnHashChain) {
  53. // delete all nodes first, then delete the chain
  54. for (unsigned int u = 0; u < nBuckets; ++u) {
  55. StrHashNode* pshnTemp = ppshnHashChain[u];
  56. while(pshnTemp) {
  57. StrHashNode* pshnNext = pshnTemp->next;
  58. delete pshnTemp;
  59. pshnTemp = pshnNext;
  60. }
  61. }
  62. delete [] ppshnHashChain;
  63. }
  64. }
  65. #ifdef DEBUG
  66. // Needed so that this stuff doesn't show
  67. // up as a leak when it is freed from someother thread
  68. void
  69. StrHash::_RemoveHashNodesFromMemList() {
  70. if (ppshnHashChain) {
  71. // remove all hasnodes from mem list first, then delete the chain
  72. for (unsigned int u = 0; u < nBuckets; ++u) {
  73. StrHashNode* pshnTemp = ppshnHashChain[u];
  74. while(pshnTemp) {
  75. StrHashNode* pshnNext = pshnTemp->next;
  76. pshnTemp = pshnNext;
  77. }
  78. }
  79. }
  80. }
  81. // Needed by the thread to which this object was
  82. // sent to add it on to the mem list to detect leaks
  83. void
  84. StrHash::_AddHashNodesFromMemList() {
  85. if (ppshnHashChain) {
  86. // add all nodes into mem list
  87. for (unsigned int u = 0; u < nBuckets; ++u) {
  88. StrHashNode* pshnTemp = ppshnHashChain[u];
  89. while(pshnTemp) {
  90. StrHashNode* pshnNext = pshnTemp->next;
  91. pshnTemp = pshnNext;
  92. }
  93. }
  94. }
  95. }
  96. #endif //DEBUG
  97. // returns the void* value if its there and NULL if its not
  98. void* StrHash::insertUnique(LPCTSTR pszKey, int fCopy, void* pvVal) {
  99. unsigned int uBucketNum = _hashValue(pszKey, nBuckets);
  100. StrHashNode* pshnNewElt;
  101. if ((pshnNewElt = _findKey(pszKey, uBucketNum)))
  102. return pshnNewElt->pvVal;
  103. if (_prepareForInsert())
  104. uBucketNum = _hashValue(pszKey, nBuckets);
  105. pshnNewElt =
  106. new StrHashNode(pszKey, pvVal, fCopy,
  107. ppshnHashChain[uBucketNum]);
  108. if (pshnNewElt && ppshnHashChain)
  109. ppshnHashChain[uBucketNum] = pshnNewElt;
  110. return NULL;
  111. }
  112. void* StrHash::retrieve(LPCTSTR pszKey) {
  113. if (!pszKey) return 0;
  114. unsigned int uBucketNum = _hashValue(pszKey, nBuckets);
  115. StrHashNode* pshn = _findKey(pszKey, uBucketNum);
  116. return (pshn ? pshn->pvVal : NULL);
  117. }
  118. // dynamically grow the hash table if necessary
  119. // return TRUE if rehashing was done
  120. int StrHash::_prepareForInsert() {
  121. ++nElements; // we'te adding an element
  122. if ((_loadFactor() >= c_uMaxLoadFactor) &&
  123. (nCurPrime++ <= c_uNumPrimes)) {
  124. //--- grow the hashTable by rehashing everything:
  125. // set up new hashTable
  126. unsigned int nBucketsOld = nBuckets;
  127. nBuckets = sc_auPrimes[nCurPrime];
  128. StrHashNode** ppshnHashChainOld = ppshnHashChain;
  129. ppshnHashChain = new StrHashNode* [nBuckets];
  130. if (ppshnHashChain && ppshnHashChainOld) {
  131. unsigned int u;
  132. for (u = 0; u < nBuckets; ++u)
  133. ppshnHashChain[u] = NULL;
  134. // rehash by traversing all buckets
  135. for (u = 0; u < nBucketsOld; ++u) {
  136. StrHashNode* pshnTemp = ppshnHashChainOld[u];
  137. while (pshnTemp) {
  138. unsigned int uBucket = _hashValue(pshnTemp->pszKey, nBuckets);
  139. StrHashNode* pshnNext = pshnTemp->next;
  140. pshnTemp->next = ppshnHashChain[uBucket];
  141. ppshnHashChain[uBucket] = pshnTemp;
  142. pshnTemp = pshnNext;
  143. }
  144. }
  145. delete [] ppshnHashChainOld;
  146. }
  147. return 1;
  148. } // if needs rehashing
  149. return 0;
  150. }
  151. /*
  152. // this variant of Weinberger's hash algorithm was taken from
  153. // packager.cpp (ie source)
  154. unsigned int _oldhashValuePJW(const char* c_pszStr, unsigned int nBuckets) {
  155. unsigned long h = 0L;
  156. while(*c_pszStr)
  157. h = ((h << 4) + *(c_pszStr++) + (h >> 28));
  158. return (h % nBuckets);
  159. }
  160. */
  161. // this variant of Weinberger's hash algorithm is adapted from
  162. // Aho/Sethi/Ullman (the Dragon Book) p436
  163. // in an empircal test using hostname data, this one resulted in less
  164. // collisions than the function listed above.
  165. // the two constants (24 and 0xf0000000) should be recalculated for 64-bit
  166. // when applicable
  167. #define DOWNCASE(x) ( (((x) >= TEXT('A')) && ((x) <= TEXT('Z')) ) ? (((x) - TEXT('A')) + TEXT('a')) : (x) )
  168. unsigned int StrHash::_hashValue(LPCTSTR pszStr, unsigned int nBuckets) {
  169. if (pszStr) {
  170. unsigned long h = 0L, g;
  171. TCHAR c;
  172. while((c = *(pszStr++))) {
  173. h = (h << 4) + ((_fCaseInsensitive ? DOWNCASE(c) : c));
  174. if ( (g = h & 0xf0000000) )
  175. h ^= (g >> 24) ^ g;
  176. }
  177. return (h % nBuckets);
  178. }
  179. return 0;
  180. }
  181. StrHash::StrHashNode* StrHash::_findKey(LPCTSTR pszStr, unsigned int uBucketNum) {
  182. StrHashNode* pshnTemp = ppshnHashChain[uBucketNum];
  183. while(pshnTemp) {
  184. if (!((_fCaseInsensitive ? StrCmpI : StrCmp)(pszStr, pshnTemp->pszKey)))
  185. return pshnTemp;
  186. pshnTemp = pshnTemp->next;
  187. }
  188. return NULL;
  189. }
  190. unsigned int StrHash::_loadFactor() {
  191. return ( (nElements * USHRT_MAX) / nBuckets );
  192. }
  193. /* a small driver to test the hash function
  194. by reading values into stdin and reporting
  195. if they're duplicates -- run it against this
  196. perl script:
  197. while(<>) {
  198. chomp;
  199. if ($log{$_}++) {
  200. ++$dups;
  201. }
  202. }
  203. print "$dups duplicates.\n";
  204. void driver_to_test_strhash_module() {
  205. StrHash strHash;
  206. char s[4096];
  207. int dups = 0;
  208. while(cin >> s) {
  209. if (strHash.insertUnique(s, 1, ((void*)1)))
  210. ++dups;
  211. else
  212. ;//cout << s << endl;
  213. }
  214. cout << dups << " duplicates." << endl;
  215. }
  216. */
  217. /**********************************************************************
  218. OrderedList
  219. **********************************************************************/
  220. // pass in uSize == 0 if you want no size limit
  221. OrderedList::OrderedList(unsigned int uSize) {
  222. this->uSize = uSize;
  223. uCount = 0;
  224. peltHead = NULL;
  225. }
  226. OrderedList::~OrderedList() {
  227. OrderedList::Element *peltTrav = peltHead;
  228. while (peltTrav) {
  229. OrderedList::Element *peltTemp = peltTrav;
  230. peltTrav = peltTrav->next;
  231. delete peltTemp;
  232. }
  233. }
  234. #ifdef DEBUG
  235. // Needed to avoid bogus leak detection
  236. void
  237. OrderedList::_RemoveElementsFromMemlist(){
  238. OrderedList::Element *peltTrav = peltHead;
  239. while (peltTrav) {
  240. OrderedList::Element *peltTemp = peltTrav;
  241. peltTrav = peltTrav->next;
  242. }
  243. }
  244. void
  245. OrderedList::_AddElementsToMemlist(){
  246. OrderedList::Element *peltTrav = peltHead;
  247. while (peltTrav) {
  248. OrderedList::Element *peltTemp = peltTrav;
  249. peltTrav = peltTrav->next;
  250. }
  251. }
  252. #endif //DEBUG
  253. void OrderedList::insert(OrderedList::Element *pelt) {
  254. // find insertion point
  255. OrderedList::Element* peltPrev = NULL;
  256. OrderedList::Element* peltTemp = peltHead;
  257. if (pelt)
  258. {
  259. while(peltTemp && (peltTemp->compareWith(pelt) < 0)) {
  260. peltPrev = peltTemp;
  261. peltTemp = peltTemp->next;
  262. }
  263. if (peltPrev) {
  264. peltPrev->next = pelt;
  265. pelt->next = peltTemp;
  266. }
  267. else {
  268. pelt->next = peltHead;
  269. peltHead = pelt;
  270. }
  271. // is list too full? erase smallest element
  272. if ((++uCount > uSize) && (uSize)) {
  273. ASSERT(peltHead);
  274. peltTemp = peltHead;
  275. peltHead = peltHead->next;
  276. delete peltTemp;
  277. --uCount;
  278. }
  279. }
  280. }
  281. // YOU must delete elements that come from this one
  282. OrderedList::Element *OrderedList::removeFirst() {
  283. OrderedList::Element *peltRet = peltHead;
  284. if (peltHead) {
  285. --uCount;
  286. peltHead = peltHead->next;
  287. }
  288. return peltRet;
  289. }
  290. //
  291. // AlignPidl
  292. //
  293. // Check if the pidl is dword aligned. If not reallign them by reallocating the
  294. // pidl. If the pidls do get reallocated the caller must free them via
  295. // FreeRealignPidl.
  296. //
  297. HRESULT AlignPidl(LPCITEMIDLIST* ppidl, BOOL* pfRealigned)
  298. {
  299. ASSERT(ppidl);
  300. ASSERT(pfRealigned);
  301. HRESULT hr = S_OK;
  302. *pfRealigned = (BOOL)((ULONG_PTR)*ppidl & 3);
  303. if (*pfRealigned)
  304. hr = (*ppidl = ILClone(*ppidl)) ? S_OK : E_OUTOFMEMORY;
  305. return hr;
  306. }
  307. //
  308. // AlignPidls
  309. //
  310. // AlignPidls realigns pidls for methonds that receive an array of pidls
  311. // (i.e. GetUIObjectOf). In this case a new array of pidl pointer needs to get
  312. // reallocated since we don't want to stomp on the callers pointer array.
  313. //
  314. HRESULT AlignPidlArray(LPCITEMIDLIST* apidl, int cidl, LPCITEMIDLIST** papidl,
  315. BOOL* pfRealigned)
  316. {
  317. ASSERT((apidl != NULL) || (cidl==0))
  318. ASSERT(pfRealigned);
  319. ASSERT(papidl);
  320. HRESULT hr = S_OK;
  321. *pfRealigned = FALSE;
  322. // Check if any pidl needs to be realigned. If anyone needs realigning
  323. // realign all of them.
  324. for (int i = 0; i < cidl && !*pfRealigned; i++)
  325. *pfRealigned = (BOOL)((ULONG_PTR)apidl[i] & 3);
  326. if (*pfRealigned)
  327. {
  328. // Use a temp pointer in case apidl and papidl are aliased (the most
  329. // likely case).
  330. LPCITEMIDLIST* apidlTemp = (LPCITEMIDLIST*)LocalAlloc(LPTR,
  331. cidl * sizeof(LPCITEMIDLIST));
  332. if (apidlTemp)
  333. {
  334. for (i = 0; i < cidl && SUCCEEDED(hr); i++)
  335. {
  336. apidlTemp[i] = ILClone(apidl[i]);
  337. if (NULL == apidlTemp[i])
  338. {
  339. for (int j = 0; j < i; j++)
  340. ILFree((LPITEMIDLIST)apidlTemp[j]);
  341. LocalFree(apidlTemp);
  342. apidlTemp = NULL;
  343. hr = E_OUTOFMEMORY;
  344. }
  345. }
  346. if (SUCCEEDED(hr))
  347. *papidl = apidlTemp;
  348. }
  349. else
  350. {
  351. hr = E_OUTOFMEMORY;
  352. }
  353. }
  354. return hr;
  355. }
  356. void FreeRealignedPidlArray(LPCITEMIDLIST* apidl, int cidl)
  357. {
  358. ASSERT(apidl)
  359. ASSERT(cidl > 0);
  360. for (int i = 0; i < cidl; i++)
  361. ILFree((LPITEMIDLIST)apidl[i]);
  362. LocalFree(apidl);
  363. apidl = NULL;
  364. return;
  365. }
  366. UINT MergeMenuHierarchy(HMENU hmenuDst, HMENU hmenuSrc, UINT idcMin, UINT idcMax)
  367. {
  368. UINT idcMaxUsed = idcMin;
  369. int imi = GetMenuItemCount(hmenuSrc);
  370. while (--imi >= 0)
  371. {
  372. MENUITEMINFO mii = { sizeof(mii), MIIM_ID | MIIM_SUBMENU, 0, 0, 0, NULL, NULL, NULL, 0, NULL, 0 };
  373. if (GetMenuItemInfo(hmenuSrc, imi, TRUE, &mii))
  374. {
  375. UINT idcT = Shell_MergeMenus(GetMenuFromID(hmenuDst, mii.wID),
  376. mii.hSubMenu, 0, idcMin, idcMax, MM_ADDSEPARATOR | MM_SUBMENUSHAVEIDS);
  377. idcMaxUsed = max(idcMaxUsed, idcT);
  378. }
  379. }
  380. return idcMaxUsed;
  381. }
  382. #undef ZONES_PANE_WIDTH
  383. #define ZONES_PANE_WIDTH 120
  384. void ResizeStatusBar(HWND hwnd, BOOL fInit)
  385. {
  386. HWND hwndStatus = NULL;
  387. RECT rc = {0};
  388. LPSHELLBROWSER psb = FileCabinet_GetIShellBrowser(hwnd);
  389. UINT cx;
  390. int ciParts[] = {-1, -1};
  391. if (!psb)
  392. return;
  393. psb->GetControlWindow(FCW_STATUS, &hwndStatus);
  394. if (fInit)
  395. {
  396. int nParts = 0;
  397. psb->SendControlMsg(FCW_STATUS, SB_GETPARTS, 0, 0L, (LRESULT*)&nParts);
  398. for (int n = 0; n < nParts; n ++)
  399. {
  400. psb->SendControlMsg(FCW_STATUS, SB_SETTEXT, n, (LPARAM)TEXT(""), NULL);
  401. psb->SendControlMsg(FCW_STATUS, SB_SETICON, n, NULL, NULL);
  402. }
  403. psb->SendControlMsg(FCW_STATUS, SB_SETPARTS, 0, 0L, NULL);
  404. }
  405. GetClientRect(hwndStatus, &rc);
  406. cx = rc.right;
  407. ciParts[0] = cx - ZONES_PANE_WIDTH;
  408. psb->SendControlMsg(FCW_STATUS, SB_SETPARTS, ARRAYSIZE(ciParts), (LPARAM)ciParts, NULL);
  409. }
  410. HRESULT _ArrangeFolder(HWND hwnd, UINT uID)
  411. {
  412. switch (uID)
  413. {
  414. case IDM_SORTBYTITLE:
  415. case IDM_SORTBYADDRESS:
  416. case IDM_SORTBYVISITED:
  417. case IDM_SORTBYUPDATED:
  418. ShellFolderView_ReArrange(hwnd, uID - IDM_SORTBYTITLE);
  419. break;
  420. case IDM_SORTBYNAME:
  421. case IDM_SORTBYADDRESS2:
  422. case IDM_SORTBYSIZE:
  423. case IDM_SORTBYEXPIRES2:
  424. case IDM_SORTBYMODIFIED:
  425. case IDM_SORTBYACCESSED:
  426. case IDM_SORTBYCHECKED:
  427. ShellFolderView_ReArrange(hwnd, uID - IDM_SORTBYNAME);
  428. break;
  429. default:
  430. return E_FAIL;
  431. }
  432. return NOERROR;
  433. }
  434. STDMETHODIMP CDetailsOfFolder::QueryInterface(REFIID riid, void **ppv)
  435. {
  436. static const QITAB qit[] = {
  437. QITABENT(CDetailsOfFolder, IShellDetails),
  438. { 0 },
  439. };
  440. return QISearch(this, qit, riid, ppv);
  441. }
  442. STDMETHODIMP_(ULONG) CDetailsOfFolder::AddRef()
  443. {
  444. return InterlockedIncrement(&_cRef);
  445. }
  446. STDMETHODIMP_(ULONG) CDetailsOfFolder::Release()
  447. {
  448. if (InterlockedDecrement(&_cRef))
  449. return _cRef;
  450. delete this;
  451. return 0;
  452. }
  453. HRESULT CDetailsOfFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *pdi)
  454. {
  455. return _psf->GetDetailsOf(pidl, iColumn, pdi);
  456. }
  457. HRESULT CDetailsOfFolder::ColumnClick(UINT iColumn)
  458. {
  459. ShellFolderView_ReArrange(_hwnd, iColumn);
  460. return NOERROR;
  461. }
  462. STDMETHODIMP CFolderArrangeMenu::QueryInterface(REFIID riid, void **ppv)
  463. {
  464. static const QITAB qit[] = {
  465. QITABENT(CFolderArrangeMenu, IContextMenu), // IID_IContextMenu
  466. { 0 },
  467. };
  468. return QISearch(this, qit, riid, ppv);
  469. }
  470. STDMETHODIMP_(ULONG) CFolderArrangeMenu::AddRef()
  471. {
  472. return InterlockedIncrement(&_cRef);
  473. }
  474. STDMETHODIMP_(ULONG) CFolderArrangeMenu::Release()
  475. {
  476. if (InterlockedDecrement(&_cRef))
  477. return _cRef;
  478. delete this;
  479. return 0;
  480. }
  481. HRESULT CFolderArrangeMenu::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst,UINT idCmdLast, UINT uFlags)
  482. {
  483. USHORT cItems = 0;
  484. if (uFlags == CMF_NORMAL)
  485. {
  486. HMENU hmenuHist = LoadMenu(MLGetHinst(), MAKEINTRESOURCE(_idMenu));
  487. if (hmenuHist)
  488. {
  489. cItems = MergeMenuHierarchy(hmenu, hmenuHist, idCmdFirst, idCmdLast);
  490. DestroyMenu(hmenuHist);
  491. }
  492. }
  493. SetMenuDefaultItem(hmenu, indexMenu, MF_BYPOSITION);
  494. return ResultFromShort(cItems); // number of menu items
  495. }
  496. STDMETHODIMP CFolderArrangeMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
  497. {
  498. if (HIWORD(pici->lpVerb) == 0)
  499. return _ArrangeFolder(pici->hwnd, LOWORD(pici->lpVerb));
  500. return E_INVALIDARG;
  501. }
  502. STDMETHODIMP CFolderArrangeMenu::GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT *pwRes,
  503. LPSTR pszName, UINT cchMax)
  504. {
  505. HRESULT hres = S_OK;
  506. if (uFlags == GCS_HELPTEXTA)
  507. {
  508. MLLoadStringA((UINT)idCmd + IDS_MH_FIRST, pszName, cchMax);
  509. }
  510. else if (uFlags == GCS_HELPTEXTW)
  511. {
  512. MLLoadStringW((UINT)idCmd + IDS_MH_FIRST, (LPWSTR)pszName, cchMax);
  513. }
  514. else
  515. hres = E_FAIL;
  516. return hres;
  517. }
  518. HRESULT _GetShortcut(LPCTSTR pszUrl, REFIID riid, void **ppv)
  519. {
  520. IUniformResourceLocator *purl;
  521. HRESULT hr = CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER,
  522. IID_IUniformResourceLocator, (void **)&purl);
  523. if (SUCCEEDED(hr))
  524. {
  525. hr = purl->SetURL(pszUrl, TRUE);
  526. if (SUCCEEDED(hr))
  527. hr = purl->QueryInterface(riid, ppv);
  528. purl->Release();
  529. }
  530. return hr;
  531. }
  532. BOOL _TitleIsGood(LPCWSTR psz)
  533. {
  534. DWORD scheme = GetUrlScheme(psz);
  535. return (!PathIsFilePath(psz) && (URL_SCHEME_INVALID == scheme || URL_SCHEME_UNKNOWN == scheme));
  536. }
  537. //////////////////////////////////////////////////////////////////////////////
  538. //
  539. // CBaseItem Object
  540. //
  541. //////////////////////////////////////////////////////////////////////////////
  542. CBaseItem::CBaseItem()
  543. {
  544. DllAddRef();
  545. InitClipboardFormats();
  546. _cRef = 1;
  547. }
  548. CBaseItem::~CBaseItem()
  549. {
  550. if (_ppidl)
  551. {
  552. for (UINT i = 0; i < _cItems; i++)
  553. {
  554. if (_ppidl[i])
  555. ILFree((LPITEMIDLIST)_ppidl[i]);
  556. }
  557. LocalFree((HLOCAL)_ppidl);
  558. _ppidl = NULL;
  559. }
  560. DllRelease();
  561. }
  562. HRESULT CBaseItem::Initialize(HWND hwnd, UINT cidl, LPCITEMIDLIST *ppidl)
  563. {
  564. HRESULT hres;
  565. _ppidl = (LPCITEMIDLIST *)LocalAlloc(LPTR, cidl * sizeof(LPCITEMIDLIST));
  566. if (_ppidl)
  567. {
  568. _hwndOwner = hwnd;
  569. _cItems = cidl;
  570. hres = S_OK;
  571. for (UINT i = 0; i < cidl; i++)
  572. {
  573. _ppidl[i] = ILClone(ppidl[i]);
  574. if (!_ppidl[i])
  575. {
  576. hres = E_OUTOFMEMORY;
  577. break;
  578. }
  579. }
  580. }
  581. else
  582. hres = E_OUTOFMEMORY;
  583. return hres;
  584. }
  585. //////////////////////////////////
  586. //
  587. // IUnknown Methods...
  588. //
  589. HRESULT CBaseItem::QueryInterface(REFIID iid, void **ppv)
  590. {
  591. HRESULT hres;
  592. static const QITAB qit[] = {
  593. QITABENT(CBaseItem, IContextMenu),
  594. QITABENT(CBaseItem, IDataObject),
  595. QITABENT(CBaseItem, IExtractIconA),
  596. QITABENT(CBaseItem, IExtractIconW),
  597. QITABENT(CBaseItem, IQueryInfo),
  598. { 0 },
  599. };
  600. hres = QISearch(this, qit, iid, ppv);
  601. if (FAILED(hres) && iid == IID_ICache)
  602. {
  603. *ppv = (LPVOID)this; // for our friends
  604. AddRef();
  605. hres = S_OK;
  606. }
  607. return hres;
  608. }
  609. ULONG CBaseItem::AddRef()
  610. {
  611. return InterlockedIncrement(&_cRef);
  612. }
  613. ULONG CBaseItem::Release()
  614. {
  615. if (InterlockedDecrement(&_cRef))
  616. return _cRef;
  617. delete this;
  618. return 0;
  619. }
  620. //////////////////////////////////
  621. //
  622. // IQueryInfo Methods
  623. //
  624. HRESULT CBaseItem::GetInfoFlags(DWORD *pdwFlags)
  625. {
  626. LPCITEMIDLIST pidl = _ppidl[0];
  627. LPCTSTR pszUrl = _PidlToSourceUrl(pidl);
  628. *pdwFlags = QIF_CACHED;
  629. if (pszUrl)
  630. {
  631. pszUrl = _StripHistoryUrlToUrl(pszUrl);
  632. BOOL fCached = TRUE;
  633. if (UrlHitsNet(pszUrl) && !UrlIsMappedOrInCache(pszUrl))
  634. {
  635. fCached = FALSE;
  636. }
  637. if (!fCached)
  638. *pdwFlags &= ~QIF_CACHED;
  639. }
  640. return S_OK;
  641. }
  642. //////////////////////////////////
  643. //
  644. // IExtractIconA Methods...
  645. //
  646. HRESULT CBaseItem::Extract(LPCSTR pcszFile, UINT uIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT ucIconSize)
  647. {
  648. return S_FALSE;
  649. }
  650. //////////////////////////////////
  651. //
  652. // IExtractIconW Methods...
  653. //
  654. HRESULT CBaseItem::GetIconLocation(UINT uFlags, LPWSTR pwzIconFile, UINT ucchMax, PINT pniIcon, PUINT puFlags)
  655. {
  656. CHAR szIconFile[MAX_PATH];
  657. HRESULT hr = GetIconLocation(uFlags, szIconFile, ARRAYSIZE(szIconFile), pniIcon, puFlags);
  658. if (SUCCEEDED(hr))
  659. AnsiToUnicode(szIconFile, pwzIconFile, ucchMax);
  660. return hr;
  661. }
  662. HRESULT CBaseItem::Extract(LPCWSTR pcwzFile, UINT uIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT ucIconSize)
  663. {
  664. CHAR szFile[MAX_PATH];
  665. UnicodeToAnsi(pcwzFile, szFile, ARRAYSIZE(szFile));
  666. return Extract(szFile, uIconIndex, phiconLarge, phiconSmall, ucIconSize);
  667. }
  668. //////////////////////////////////
  669. //
  670. // IContextMenu Methods
  671. //
  672. HRESULT CBaseItem::_AddToFavorites(int nIndex)
  673. {
  674. HRESULT hr = S_OK;
  675. LPITEMIDLIST pidlUrl = NULL;
  676. TCHAR szParsedUrl[MAX_URL_STRING];
  677. // NOTE: This URL came from the user, so we need to clean it up.
  678. // If the user entered "yahoo.com" or "Search Get Rich Quick",
  679. // it will be turned into a search URL by ParseURLFromOutsideSourceW().
  680. DWORD cchParsedUrl = ARRAYSIZE(szParsedUrl);
  681. LPCTSTR pszUrl = _GetUrl(nIndex);
  682. if (pszUrl && !ParseURLFromOutsideSource(pszUrl, szParsedUrl, &cchParsedUrl, NULL))
  683. {
  684. StrCpyN(szParsedUrl, pszUrl, ARRAYSIZE(szParsedUrl));
  685. }
  686. hr = IEParseDisplayName(CP_ACP, szParsedUrl, &pidlUrl);
  687. if (SUCCEEDED(hr))
  688. {
  689. LPCTSTR pszTitle;
  690. LPCUTSTR pszuTitle = _GetURLTitle( _ppidl[nIndex]);
  691. if ((pszuTitle == NULL) || (ualstrlen(pszuTitle) == 0))
  692. pszuTitle = _GetUrl(nIndex);
  693. TSTR_ALIGNED_STACK_COPY(&pszTitle,pszuTitle);
  694. AddToFavorites(_hwndOwner, pidlUrl, pszTitle, TRUE, NULL, NULL);
  695. ILFree(pidlUrl);
  696. hr = S_OK;
  697. }
  698. return hr;
  699. }
  700. STDMETHODIMP CBaseItem::GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT *pwReserved,
  701. LPSTR pszName, UINT cchMax)
  702. {
  703. HRESULT hres = E_FAIL;
  704. TraceMsg(DM_HSFOLDER, "hci - cm - GetCommandString() called.");
  705. if ((uFlags == GCS_VERBA) || (uFlags == GCS_VERBW))
  706. {
  707. LPCSTR pszSrc = NULL;
  708. switch(idCmd)
  709. {
  710. case RSVIDM_OPEN:
  711. pszSrc = c_szOpen;
  712. break;
  713. case RSVIDM_COPY:
  714. pszSrc = c_szCopy;
  715. break;
  716. case RSVIDM_DELCACHE:
  717. pszSrc = c_szDelcache;
  718. break;
  719. case RSVIDM_PROPERTIES:
  720. pszSrc = c_szProperties;
  721. break;
  722. }
  723. if (pszSrc)
  724. {
  725. if (uFlags == GCS_VERBA)
  726. StrCpyNA(pszName, pszSrc, cchMax);
  727. else if (uFlags == GCS_VERBW) // GCS_VERB === GCS_VERBW
  728. SHAnsiToUnicode(pszSrc, (LPWSTR)pszName, cchMax);
  729. else
  730. ASSERT(0);
  731. hres = S_OK;
  732. }
  733. }
  734. else if (uFlags == GCS_HELPTEXTA || uFlags == GCS_HELPTEXTW)
  735. {
  736. switch(idCmd)
  737. {
  738. case RSVIDM_OPEN:
  739. case RSVIDM_COPY:
  740. case RSVIDM_DELCACHE:
  741. case RSVIDM_PROPERTIES:
  742. if (uFlags == GCS_HELPTEXTA)
  743. {
  744. MLLoadStringA(IDS_SB_FIRST+ (UINT)idCmd, pszName, cchMax);
  745. }
  746. else
  747. {
  748. MLLoadStringW(IDS_SB_FIRST+ (UINT)idCmd, (LPWSTR)pszName, cchMax);
  749. }
  750. hres = NOERROR;
  751. break;
  752. default:
  753. break;
  754. }
  755. }
  756. return hres;
  757. }
  758. //////////////////////////////////
  759. //
  760. // IDataObject Methods...
  761. //
  762. HRESULT CBaseItem::GetDataHere(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
  763. {
  764. TraceMsg(DM_HSFOLDER, "hci - do - GetDataHere() called.");
  765. return E_NOTIMPL;
  766. }
  767. HRESULT CBaseItem::GetCanonicalFormatEtc(LPFORMATETC pFEIn, LPFORMATETC pFEOut)
  768. {
  769. TraceMsg(DM_HSFOLDER, "hci - do - GetCanonicalFormatEtc() called.");
  770. return DATA_S_SAMEFORMATETC;
  771. }
  772. HRESULT CBaseItem::SetData(LPFORMATETC pFE, LPSTGMEDIUM pSTM, BOOL fRelease)
  773. {
  774. TraceMsg(DM_HSFOLDER, "hci - do - SetData() called.");
  775. return E_NOTIMPL;
  776. }
  777. HRESULT CBaseItem::DAdvise(LPFORMATETC pFE, DWORD grfAdv, LPADVISESINK pAdvSink, DWORD *pdwConnection)
  778. {
  779. return OLE_E_ADVISENOTSUPPORTED;
  780. }
  781. HRESULT CBaseItem::DUnadvise(DWORD dwConnection)
  782. {
  783. return OLE_E_ADVISENOTSUPPORTED;
  784. }
  785. HRESULT CBaseItem::EnumDAdvise(LPENUMSTATDATA *ppEnum)
  786. {
  787. return OLE_E_ADVISENOTSUPPORTED;
  788. }
  789. //////////////////////////////////////////////////////////////////////////////
  790. //
  791. // Helper Routines
  792. //
  793. //////////////////////////////////////////////////////////////////////////////
  794. LPCTSTR CBaseItem::_GetDisplayUrlForPidl(LPCITEMIDLIST pidl, LPTSTR pszDisplayUrl, DWORD dwDisplayUrl)
  795. {
  796. LPCTSTR pszUrl = _StripHistoryUrlToUrl(_PidlToSourceUrl(pidl));
  797. if (pszUrl && PrepareURLForDisplay(pszUrl, pszDisplayUrl, &dwDisplayUrl))
  798. {
  799. pszUrl = pszDisplayUrl;
  800. }
  801. return pszUrl;
  802. }
  803. HRESULT CBaseItem::_CreateFileDescriptorA(LPSTGMEDIUM pSTM)
  804. {
  805. TCHAR urlTitleBuf[ MAX_URL_STRING ];
  806. LPCUTSTR ua_urlTitle;
  807. LPCTSTR urlTitle;
  808. pSTM->tymed = TYMED_HGLOBAL;
  809. pSTM->pUnkForRelease = NULL;
  810. FILEGROUPDESCRIPTORA *pfgd = (FILEGROUPDESCRIPTORA*)GlobalAlloc(GPTR, sizeof(FILEGROUPDESCRIPTORA) + (_cItems-1) * sizeof(FILEDESCRIPTORA));
  811. if (pfgd == NULL)
  812. {
  813. TraceMsg(DM_HSFOLDER, "hci - Couldn't alloc file descriptor");
  814. return E_OUTOFMEMORY;
  815. }
  816. pfgd->cItems = _cItems; // set the number of items
  817. for (UINT i = 0; i < _cItems; i++)
  818. {
  819. FILEDESCRIPTORA *pfd = &(pfgd->fgd[i]);
  820. UINT cchFilename;
  821. //
  822. // Derive an aligned copy of the url title
  823. //
  824. ua_urlTitle = _GetURLTitle( _ppidl[i] );
  825. if (TSTR_ALIGNED(ua_urlTitle) == FALSE) {
  826. ualstrcpyn( urlTitleBuf, ua_urlTitle, ARRAYSIZE(urlTitleBuf));
  827. urlTitle = urlTitleBuf;
  828. } else {
  829. urlTitle = (LPCTSTR)ua_urlTitle;
  830. }
  831. SHTCharToAnsi(urlTitle, pfd->cFileName, ARRAYSIZE(pfd->cFileName) );
  832. MakeLegalFilenameA(pfd->cFileName);
  833. cchFilename = lstrlenA(pfd->cFileName);
  834. SHTCharToAnsi(L".URL", pfd->cFileName+cchFilename, ARRAYSIZE(pfd->cFileName)-cchFilename);
  835. }
  836. pSTM->hGlobal = pfgd;
  837. return S_OK;
  838. }
  839. // this format is explicitly ANSI, hence no TCHAR stuff
  840. HRESULT CBaseItem::_CreateURL(LPSTGMEDIUM pSTM)
  841. {
  842. DWORD cchSize;
  843. LPCTSTR pszURL = _StripHistoryUrlToUrl(_PidlToSourceUrl(_ppidl[0]));
  844. if (!pszURL)
  845. return E_FAIL;
  846. // render the url
  847. cchSize = lstrlen(pszURL) + 1;
  848. pSTM->tymed = TYMED_HGLOBAL;
  849. pSTM->pUnkForRelease = NULL;
  850. pSTM->hGlobal = GlobalAlloc(GPTR, cchSize * sizeof(CHAR));
  851. if (pSTM->hGlobal)
  852. {
  853. TCharToAnsi(pszURL, (LPSTR)pSTM->hGlobal, cchSize);
  854. return S_OK;
  855. }
  856. return E_OUTOFMEMORY;
  857. }
  858. HRESULT CBaseItem::_CreatePrefDropEffect(LPSTGMEDIUM pSTM)
  859. {
  860. pSTM->tymed = TYMED_HGLOBAL;
  861. pSTM->pUnkForRelease = NULL;
  862. pSTM->hGlobal = GlobalAlloc(GPTR, sizeof(DWORD));
  863. if (pSTM->hGlobal)
  864. {
  865. *((LPDWORD)pSTM->hGlobal) = DROPEFFECT_COPY;
  866. return S_OK;
  867. }
  868. return E_OUTOFMEMORY;
  869. }
  870. HRESULT CBaseItem::_CreateFileContents(LPSTGMEDIUM pSTM, LONG lindex)
  871. {
  872. HRESULT hr;
  873. // make sure the index is in a valid range.
  874. ASSERT((unsigned)lindex < _cItems);
  875. ASSERT(lindex >= 0);
  876. // here's a partial fix for when ole sometimes passes in -1 for lindex
  877. if (lindex == -1)
  878. {
  879. if (_cItems == 1)
  880. lindex = 0;
  881. else
  882. return E_FAIL;
  883. }
  884. pSTM->tymed = TYMED_ISTREAM;
  885. pSTM->pUnkForRelease = NULL;
  886. hr = CreateStreamOnHGlobal(NULL, TRUE, &pSTM->pstm);
  887. if (SUCCEEDED(hr))
  888. {
  889. LARGE_INTEGER li = {0L, 0L};
  890. IUniformResourceLocator *purl;
  891. hr = CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER,
  892. IID_IUniformResourceLocator, (void **)&purl);
  893. if (SUCCEEDED(hr))
  894. {
  895. TCHAR szDecoded[MAX_URL_STRING];
  896. ConditionallyDecodeUTF8(_GetUrlForPidl(_ppidl[lindex]),
  897. szDecoded, ARRAYSIZE(szDecoded));
  898. hr = purl->SetURL(szDecoded, TRUE);
  899. if (SUCCEEDED(hr))
  900. {
  901. IPersistStream *pps;
  902. hr = purl->QueryInterface(IID_IPersistStream, (LPVOID *)&pps);
  903. if (SUCCEEDED(hr))
  904. {
  905. hr = pps->Save(pSTM->pstm, TRUE);
  906. pps->Release();
  907. }
  908. }
  909. purl->Release();
  910. }
  911. pSTM->pstm->Seek(li, STREAM_SEEK_SET, NULL);
  912. }
  913. return hr;
  914. }
  915. HRESULT CBaseItem::_CreateHTEXT(LPSTGMEDIUM pSTM)
  916. {
  917. UINT i;
  918. UINT cbAlloc = sizeof(TCHAR); // null terminator
  919. TCHAR szDisplayUrl[INTERNET_MAX_URL_LENGTH];
  920. for (i = 0; i < _cItems; i++)
  921. {
  922. LPCTSTR pszUrl = _GetDisplayUrlForPidl(_ppidl[i], szDisplayUrl, ARRAYSIZE(szDisplayUrl));
  923. if (!pszUrl)
  924. return E_FAIL;
  925. char szAnsiUrl[MAX_URL_STRING];
  926. TCharToAnsi(pszUrl, szAnsiUrl, ARRAYSIZE(szAnsiUrl));
  927. // 2 extra for carriage return and newline
  928. cbAlloc += sizeof(CHAR) * (lstrlenA(szAnsiUrl) + 2);
  929. }
  930. // render the url
  931. pSTM->tymed = TYMED_HGLOBAL;
  932. pSTM->pUnkForRelease = NULL;
  933. pSTM->hGlobal = GlobalAlloc(GPTR, cbAlloc);
  934. if (pSTM->hGlobal)
  935. {
  936. LPSTR pszHTEXT = (LPSTR)pSTM->hGlobal;
  937. int cchHTEXT = cbAlloc / sizeof(CHAR);
  938. for (i = 0; i < _cItems; i++)
  939. {
  940. if (i && cchHTEXT > 2)
  941. {
  942. *pszHTEXT++ = 0xD;
  943. *pszHTEXT++ = 0xA;
  944. cchHTEXT -= 2;
  945. }
  946. LPCTSTR pszUrl = _GetDisplayUrlForPidl(_ppidl[i], szDisplayUrl, ARRAYSIZE(szDisplayUrl));
  947. if (pszUrl)
  948. {
  949. int cchUrl = lstrlen(pszUrl);
  950. TCharToAnsi(pszUrl, pszHTEXT, cchHTEXT);
  951. pszHTEXT += cchUrl;
  952. cchHTEXT -= cchUrl;
  953. }
  954. }
  955. return S_OK;
  956. }
  957. return E_OUTOFMEMORY;
  958. }
  959. HRESULT CBaseItem::_CreateUnicodeTEXT(LPSTGMEDIUM pSTM)
  960. {
  961. UINT i;
  962. UINT cbAlloc = sizeof(WCHAR); // null terminator
  963. WCHAR szDisplayUrl[INTERNET_MAX_URL_LENGTH];
  964. for (i = 0; i < _cItems; i++)
  965. {
  966. ConditionallyDecodeUTF8(_GetUrlForPidl(_ppidl[i]),
  967. szDisplayUrl, ARRAYSIZE(szDisplayUrl));
  968. if (!*szDisplayUrl)
  969. return E_FAIL;
  970. cbAlloc += sizeof(WCHAR) * (lstrlenW(szDisplayUrl) + 2);
  971. }
  972. // render the url
  973. pSTM->tymed = TYMED_HGLOBAL;
  974. pSTM->pUnkForRelease = NULL;
  975. pSTM->hGlobal = GlobalAlloc(GPTR, cbAlloc);
  976. if (pSTM->hGlobal)
  977. {
  978. LPTSTR pszHTEXT = (LPTSTR)pSTM->hGlobal;
  979. int cchHTEXT = cbAlloc / sizeof(WCHAR);
  980. for (i = 0; i < _cItems; i++)
  981. {
  982. if (i && cchHTEXT > 2)
  983. {
  984. *pszHTEXT++ = 0xD;
  985. *pszHTEXT++ = 0xA;
  986. cchHTEXT -= 2;
  987. }
  988. ConditionallyDecodeUTF8(_GetUrlForPidl(_ppidl[i]),
  989. szDisplayUrl, ARRAYSIZE(szDisplayUrl));
  990. int cchUrl = lstrlenW(szDisplayUrl);
  991. StrCpyN(pszHTEXT, szDisplayUrl, cchHTEXT);
  992. pszHTEXT += cchUrl;
  993. cchHTEXT -= cchUrl;
  994. }
  995. return S_OK;
  996. }
  997. return E_OUTOFMEMORY;
  998. }