Leaked source code of windows server 2003
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.

1214 lines
32 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. ASSERT( 0 != _cRef );
  449. ULONG cRef = InterlockedDecrement(&_cRef);
  450. if ( 0 == cRef )
  451. {
  452. delete this;
  453. }
  454. return cRef;
  455. }
  456. HRESULT CDetailsOfFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *pdi)
  457. {
  458. return _psf->GetDetailsOf(pidl, iColumn, pdi);
  459. }
  460. HRESULT CDetailsOfFolder::ColumnClick(UINT iColumn)
  461. {
  462. ShellFolderView_ReArrange(_hwnd, iColumn);
  463. return NOERROR;
  464. }
  465. STDMETHODIMP CFolderArrangeMenu::QueryInterface(REFIID riid, void **ppv)
  466. {
  467. static const QITAB qit[] = {
  468. QITABENT(CFolderArrangeMenu, IContextMenu), // IID_IContextMenu
  469. { 0 },
  470. };
  471. return QISearch(this, qit, riid, ppv);
  472. }
  473. STDMETHODIMP_(ULONG) CFolderArrangeMenu::AddRef()
  474. {
  475. return InterlockedIncrement(&_cRef);
  476. }
  477. STDMETHODIMP_(ULONG) CFolderArrangeMenu::Release()
  478. {
  479. ASSERT( 0 != _cRef );
  480. ULONG cRef = InterlockedDecrement(&_cRef);
  481. if ( 0 == cRef )
  482. {
  483. delete this;
  484. }
  485. return cRef;
  486. }
  487. HRESULT CFolderArrangeMenu::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst,UINT idCmdLast, UINT uFlags)
  488. {
  489. USHORT cItems = 0;
  490. if (uFlags == CMF_NORMAL)
  491. {
  492. HMENU hmenuHist = LoadMenu(MLGetHinst(), MAKEINTRESOURCE(_idMenu));
  493. if (hmenuHist)
  494. {
  495. cItems = MergeMenuHierarchy(hmenu, hmenuHist, idCmdFirst, idCmdLast);
  496. DestroyMenu(hmenuHist);
  497. }
  498. }
  499. SetMenuDefaultItem(hmenu, indexMenu, MF_BYPOSITION);
  500. return ResultFromShort(cItems); // number of menu items
  501. }
  502. STDMETHODIMP CFolderArrangeMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
  503. {
  504. if (HIWORD(pici->lpVerb) == 0)
  505. return _ArrangeFolder(pici->hwnd, LOWORD(pici->lpVerb));
  506. return E_INVALIDARG;
  507. }
  508. STDMETHODIMP CFolderArrangeMenu::GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT *pwRes,
  509. LPSTR pszName, UINT cchMax)
  510. {
  511. HRESULT hres = S_OK;
  512. if (uFlags == GCS_HELPTEXTA)
  513. {
  514. MLLoadStringA((UINT)idCmd + IDS_MH_FIRST, pszName, cchMax);
  515. }
  516. else if (uFlags == GCS_HELPTEXTW)
  517. {
  518. MLLoadStringW((UINT)idCmd + IDS_MH_FIRST, (LPWSTR)pszName, cchMax);
  519. }
  520. else
  521. hres = E_FAIL;
  522. return hres;
  523. }
  524. HRESULT _GetShortcut(LPCTSTR pszUrl, REFIID riid, void **ppv)
  525. {
  526. IUniformResourceLocator *purl;
  527. HRESULT hr = CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER,
  528. IID_IUniformResourceLocator, (void **)&purl);
  529. if (SUCCEEDED(hr))
  530. {
  531. hr = purl->SetURL(pszUrl, TRUE);
  532. if (SUCCEEDED(hr))
  533. hr = purl->QueryInterface(riid, ppv);
  534. purl->Release();
  535. }
  536. return hr;
  537. }
  538. BOOL _TitleIsGood(LPCWSTR psz)
  539. {
  540. DWORD scheme = GetUrlScheme(psz);
  541. return (!PathIsFilePath(psz) && (URL_SCHEME_INVALID == scheme || URL_SCHEME_UNKNOWN == scheme));
  542. }
  543. //////////////////////////////////////////////////////////////////////////////
  544. //
  545. // CBaseItem Object
  546. //
  547. //////////////////////////////////////////////////////////////////////////////
  548. CBaseItem::CBaseItem()
  549. {
  550. DllAddRef();
  551. InitClipboardFormats();
  552. _cRef = 1;
  553. }
  554. CBaseItem::~CBaseItem()
  555. {
  556. if (_ppidl)
  557. {
  558. for (UINT i = 0; i < _cItems; i++)
  559. {
  560. if (_ppidl[i])
  561. ILFree((LPITEMIDLIST)_ppidl[i]);
  562. }
  563. LocalFree((HLOCAL)_ppidl);
  564. _ppidl = NULL;
  565. }
  566. DllRelease();
  567. }
  568. HRESULT CBaseItem::Initialize(HWND hwnd, UINT cidl, LPCITEMIDLIST *ppidl)
  569. {
  570. HRESULT hres;
  571. _ppidl = (LPCITEMIDLIST *)LocalAlloc(LPTR, cidl * sizeof(LPCITEMIDLIST));
  572. if (_ppidl)
  573. {
  574. _hwndOwner = hwnd;
  575. _cItems = cidl;
  576. hres = S_OK;
  577. for (UINT i = 0; i < cidl; i++)
  578. {
  579. _ppidl[i] = ILClone(ppidl[i]);
  580. if (!_ppidl[i])
  581. {
  582. hres = E_OUTOFMEMORY;
  583. break;
  584. }
  585. }
  586. }
  587. else
  588. hres = E_OUTOFMEMORY;
  589. return hres;
  590. }
  591. //////////////////////////////////
  592. //
  593. // IUnknown Methods...
  594. //
  595. HRESULT CBaseItem::QueryInterface(REFIID iid, void **ppv)
  596. {
  597. HRESULT hres;
  598. static const QITAB qit[] = {
  599. QITABENT(CBaseItem, IContextMenu),
  600. QITABENT(CBaseItem, IDataObject),
  601. QITABENT(CBaseItem, IExtractIconA),
  602. QITABENT(CBaseItem, IExtractIconW),
  603. QITABENT(CBaseItem, IQueryInfo),
  604. { 0 },
  605. };
  606. hres = QISearch(this, qit, iid, ppv);
  607. if (FAILED(hres) && iid == IID_ICache)
  608. {
  609. *ppv = (LPVOID)this; // for our friends
  610. AddRef();
  611. hres = S_OK;
  612. }
  613. return hres;
  614. }
  615. ULONG CBaseItem::AddRef()
  616. {
  617. return InterlockedIncrement(&_cRef);
  618. }
  619. ULONG CBaseItem::Release()
  620. {
  621. ASSERT( 0 != _cRef );
  622. ULONG cRef = InterlockedDecrement(&_cRef);
  623. if ( 0 == cRef )
  624. {
  625. delete this;
  626. }
  627. return cRef;
  628. }
  629. //////////////////////////////////
  630. //
  631. // IQueryInfo Methods
  632. //
  633. HRESULT CBaseItem::GetInfoFlags(DWORD *pdwFlags)
  634. {
  635. LPCITEMIDLIST pidl = _ppidl[0];
  636. LPCTSTR pszUrl = _PidlToSourceUrl(pidl);
  637. *pdwFlags = QIF_CACHED;
  638. if (pszUrl)
  639. {
  640. pszUrl = _StripHistoryUrlToUrl(pszUrl);
  641. BOOL fCached = TRUE;
  642. if (UrlHitsNet(pszUrl) && !UrlIsMappedOrInCache(pszUrl))
  643. {
  644. fCached = FALSE;
  645. }
  646. if (!fCached)
  647. *pdwFlags &= ~QIF_CACHED;
  648. }
  649. return S_OK;
  650. }
  651. //////////////////////////////////
  652. //
  653. // IExtractIconA Methods...
  654. //
  655. HRESULT CBaseItem::Extract(LPCSTR pcszFile, UINT uIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT ucIconSize)
  656. {
  657. return S_FALSE;
  658. }
  659. //////////////////////////////////
  660. //
  661. // IExtractIconW Methods...
  662. //
  663. HRESULT CBaseItem::GetIconLocation(UINT uFlags, LPWSTR pwzIconFile, UINT ucchMax, PINT pniIcon, PUINT puFlags)
  664. {
  665. CHAR szIconFile[MAX_PATH];
  666. HRESULT hr = GetIconLocation(uFlags, szIconFile, ARRAYSIZE(szIconFile), pniIcon, puFlags);
  667. if (SUCCEEDED(hr))
  668. AnsiToUnicode(szIconFile, pwzIconFile, ucchMax);
  669. return hr;
  670. }
  671. HRESULT CBaseItem::Extract(LPCWSTR pcwzFile, UINT uIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT ucIconSize)
  672. {
  673. CHAR szFile[MAX_PATH];
  674. UnicodeToAnsi(pcwzFile, szFile, ARRAYSIZE(szFile));
  675. return Extract(szFile, uIconIndex, phiconLarge, phiconSmall, ucIconSize);
  676. }
  677. //////////////////////////////////
  678. //
  679. // IContextMenu Methods
  680. //
  681. HRESULT CBaseItem::_AddToFavorites(int nIndex)
  682. {
  683. HRESULT hr = S_OK;
  684. LPITEMIDLIST pidlUrl = NULL;
  685. TCHAR szParsedUrl[MAX_URL_STRING];
  686. // NOTE: This URL came from the user, so we need to clean it up.
  687. // If the user entered "yahoo.com" or "Search Get Rich Quick",
  688. // it will be turned into a search URL by ParseURLFromOutsideSourceW().
  689. DWORD cchParsedUrl = ARRAYSIZE(szParsedUrl);
  690. LPCTSTR pszUrl = _GetUrl(nIndex);
  691. if (pszUrl && !ParseURLFromOutsideSource(pszUrl, szParsedUrl, &cchParsedUrl, NULL))
  692. {
  693. StrCpyN(szParsedUrl, pszUrl, ARRAYSIZE(szParsedUrl));
  694. }
  695. hr = IEParseDisplayName(CP_ACP, szParsedUrl, &pidlUrl);
  696. if (SUCCEEDED(hr))
  697. {
  698. LPCTSTR pszTitle;
  699. LPCUTSTR pszuTitle = _GetURLTitle( _ppidl[nIndex]);
  700. if ((pszuTitle == NULL) || (ualstrlen(pszuTitle) == 0))
  701. pszuTitle = _GetUrl(nIndex);
  702. TSTR_ALIGNED_STACK_COPY(&pszTitle,pszuTitle);
  703. AddToFavorites(_hwndOwner, pidlUrl, pszTitle, TRUE, NULL, NULL);
  704. ILFree(pidlUrl);
  705. hr = S_OK;
  706. }
  707. return hr;
  708. }
  709. STDMETHODIMP CBaseItem::GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT *pwReserved,
  710. LPSTR pszName, UINT cchMax)
  711. {
  712. HRESULT hres = E_FAIL;
  713. TraceMsg(DM_HSFOLDER, "hci - cm - GetCommandString() called.");
  714. if ((uFlags == GCS_VERBA) || (uFlags == GCS_VERBW))
  715. {
  716. LPCSTR pszSrc = NULL;
  717. switch(idCmd)
  718. {
  719. case RSVIDM_OPEN:
  720. pszSrc = c_szOpen;
  721. break;
  722. case RSVIDM_COPY:
  723. pszSrc = c_szCopy;
  724. break;
  725. case RSVIDM_DELCACHE:
  726. pszSrc = c_szDelcache;
  727. break;
  728. case RSVIDM_PROPERTIES:
  729. pszSrc = c_szProperties;
  730. break;
  731. }
  732. if (pszSrc)
  733. {
  734. if (uFlags == GCS_VERBA)
  735. StrCpyNA(pszName, pszSrc, cchMax);
  736. else if (uFlags == GCS_VERBW) // GCS_VERB === GCS_VERBW
  737. SHAnsiToUnicode(pszSrc, (LPWSTR)pszName, cchMax);
  738. else
  739. ASSERT(0);
  740. hres = S_OK;
  741. }
  742. }
  743. else if (uFlags == GCS_HELPTEXTA || uFlags == GCS_HELPTEXTW)
  744. {
  745. switch(idCmd)
  746. {
  747. case RSVIDM_OPEN:
  748. case RSVIDM_COPY:
  749. case RSVIDM_DELCACHE:
  750. case RSVIDM_PROPERTIES:
  751. if (uFlags == GCS_HELPTEXTA)
  752. {
  753. MLLoadStringA(IDS_SB_FIRST+ (UINT)idCmd, pszName, cchMax);
  754. }
  755. else
  756. {
  757. MLLoadStringW(IDS_SB_FIRST+ (UINT)idCmd, (LPWSTR)pszName, cchMax);
  758. }
  759. hres = NOERROR;
  760. break;
  761. default:
  762. break;
  763. }
  764. }
  765. return hres;
  766. }
  767. //////////////////////////////////
  768. //
  769. // IDataObject Methods...
  770. //
  771. HRESULT CBaseItem::GetDataHere(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
  772. {
  773. TraceMsg(DM_HSFOLDER, "hci - do - GetDataHere() called.");
  774. return E_NOTIMPL;
  775. }
  776. HRESULT CBaseItem::GetCanonicalFormatEtc(LPFORMATETC pFEIn, LPFORMATETC pFEOut)
  777. {
  778. TraceMsg(DM_HSFOLDER, "hci - do - GetCanonicalFormatEtc() called.");
  779. return DATA_S_SAMEFORMATETC;
  780. }
  781. HRESULT CBaseItem::SetData(LPFORMATETC pFE, LPSTGMEDIUM pSTM, BOOL fRelease)
  782. {
  783. TraceMsg(DM_HSFOLDER, "hci - do - SetData() called.");
  784. return E_NOTIMPL;
  785. }
  786. HRESULT CBaseItem::DAdvise(LPFORMATETC pFE, DWORD grfAdv, LPADVISESINK pAdvSink, DWORD *pdwConnection)
  787. {
  788. return OLE_E_ADVISENOTSUPPORTED;
  789. }
  790. HRESULT CBaseItem::DUnadvise(DWORD dwConnection)
  791. {
  792. return OLE_E_ADVISENOTSUPPORTED;
  793. }
  794. HRESULT CBaseItem::EnumDAdvise(LPENUMSTATDATA *ppEnum)
  795. {
  796. return OLE_E_ADVISENOTSUPPORTED;
  797. }
  798. //////////////////////////////////////////////////////////////////////////////
  799. //
  800. // Helper Routines
  801. //
  802. //////////////////////////////////////////////////////////////////////////////
  803. LPCTSTR CBaseItem::_GetDisplayUrlForPidl(LPCITEMIDLIST pidl, LPTSTR pszDisplayUrl, DWORD dwDisplayUrl)
  804. {
  805. LPCTSTR pszUrl = _StripHistoryUrlToUrl(_PidlToSourceUrl(pidl));
  806. if (pszUrl && PrepareURLForDisplay(pszUrl, pszDisplayUrl, &dwDisplayUrl))
  807. {
  808. pszUrl = pszDisplayUrl;
  809. }
  810. return pszUrl;
  811. }
  812. HRESULT CBaseItem::_CreateFileDescriptorA(LPSTGMEDIUM pSTM)
  813. {
  814. TCHAR urlTitleBuf[ MAX_URL_STRING ];
  815. LPCUTSTR ua_urlTitle;
  816. LPCTSTR urlTitle;
  817. pSTM->tymed = TYMED_HGLOBAL;
  818. pSTM->pUnkForRelease = NULL;
  819. FILEGROUPDESCRIPTORA *pfgd = (FILEGROUPDESCRIPTORA*)GlobalAlloc(GPTR, sizeof(FILEGROUPDESCRIPTORA) + (_cItems-1) * sizeof(FILEDESCRIPTORA));
  820. if (pfgd == NULL)
  821. {
  822. TraceMsg(DM_HSFOLDER, "hci - Couldn't alloc file descriptor");
  823. return E_OUTOFMEMORY;
  824. }
  825. pfgd->cItems = _cItems; // set the number of items
  826. for (UINT i = 0; i < _cItems; i++)
  827. {
  828. FILEDESCRIPTORA *pfd = &(pfgd->fgd[i]);
  829. UINT cchFilename;
  830. //
  831. // Derive an aligned copy of the url title
  832. //
  833. ua_urlTitle = _GetURLTitle( _ppidl[i] );
  834. if (TSTR_ALIGNED(ua_urlTitle) == FALSE) {
  835. ualstrcpyn( urlTitleBuf, ua_urlTitle, ARRAYSIZE(urlTitleBuf));
  836. urlTitle = urlTitleBuf;
  837. } else {
  838. urlTitle = (LPCTSTR)ua_urlTitle;
  839. }
  840. SHTCharToAnsi(urlTitle, pfd->cFileName, ARRAYSIZE(pfd->cFileName) );
  841. MakeLegalFilenameA(pfd->cFileName, ARRAYSIZE(pfd->cFileName));
  842. cchFilename = lstrlenA(pfd->cFileName);
  843. SHTCharToAnsi(L".URL", pfd->cFileName+cchFilename, ARRAYSIZE(pfd->cFileName)-cchFilename);
  844. }
  845. pSTM->hGlobal = pfgd;
  846. return S_OK;
  847. }
  848. // this format is explicitly ANSI, hence no TCHAR stuff
  849. HRESULT CBaseItem::_CreateURL(LPSTGMEDIUM pSTM)
  850. {
  851. DWORD cchSize;
  852. LPCTSTR pszURL = _StripHistoryUrlToUrl(_PidlToSourceUrl(_ppidl[0]));
  853. if (!pszURL)
  854. return E_FAIL;
  855. // render the url
  856. cchSize = lstrlen(pszURL) + 1;
  857. pSTM->tymed = TYMED_HGLOBAL;
  858. pSTM->pUnkForRelease = NULL;
  859. pSTM->hGlobal = GlobalAlloc(GPTR, cchSize * sizeof(CHAR));
  860. if (pSTM->hGlobal)
  861. {
  862. TCharToAnsi(pszURL, (LPSTR)pSTM->hGlobal, cchSize);
  863. return S_OK;
  864. }
  865. return E_OUTOFMEMORY;
  866. }
  867. HRESULT CBaseItem::_CreatePrefDropEffect(LPSTGMEDIUM pSTM)
  868. {
  869. pSTM->tymed = TYMED_HGLOBAL;
  870. pSTM->pUnkForRelease = NULL;
  871. pSTM->hGlobal = GlobalAlloc(GPTR, sizeof(DWORD));
  872. if (pSTM->hGlobal)
  873. {
  874. *((LPDWORD)pSTM->hGlobal) = DROPEFFECT_COPY;
  875. return S_OK;
  876. }
  877. return E_OUTOFMEMORY;
  878. }
  879. HRESULT CBaseItem::_CreateFileContents(LPSTGMEDIUM pSTM, LONG lindex)
  880. {
  881. HRESULT hr;
  882. // make sure the index is in a valid range.
  883. ASSERT((unsigned)lindex < _cItems);
  884. ASSERT(lindex >= 0);
  885. // here's a partial fix for when ole sometimes passes in -1 for lindex
  886. if (lindex == -1)
  887. {
  888. if (_cItems == 1)
  889. lindex = 0;
  890. else
  891. return E_FAIL;
  892. }
  893. pSTM->tymed = TYMED_ISTREAM;
  894. pSTM->pUnkForRelease = NULL;
  895. hr = CreateStreamOnHGlobal(NULL, TRUE, &pSTM->pstm);
  896. if (SUCCEEDED(hr))
  897. {
  898. LARGE_INTEGER li = {0L, 0L};
  899. IUniformResourceLocator *purl;
  900. hr = CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER,
  901. IID_IUniformResourceLocator, (void **)&purl);
  902. if (SUCCEEDED(hr))
  903. {
  904. TCHAR szDecoded[MAX_URL_STRING];
  905. ConditionallyDecodeUTF8(_GetUrlForPidl(_ppidl[lindex]),
  906. szDecoded, ARRAYSIZE(szDecoded));
  907. hr = purl->SetURL(szDecoded, TRUE);
  908. if (SUCCEEDED(hr))
  909. {
  910. IPersistStream *pps;
  911. hr = purl->QueryInterface(IID_IPersistStream, (LPVOID *)&pps);
  912. if (SUCCEEDED(hr))
  913. {
  914. hr = pps->Save(pSTM->pstm, TRUE);
  915. pps->Release();
  916. }
  917. }
  918. purl->Release();
  919. }
  920. pSTM->pstm->Seek(li, STREAM_SEEK_SET, NULL);
  921. }
  922. return hr;
  923. }
  924. HRESULT CBaseItem::_CreateHTEXT(LPSTGMEDIUM pSTM)
  925. {
  926. UINT i;
  927. UINT cbAlloc = sizeof(TCHAR); // null terminator
  928. TCHAR szDisplayUrl[INTERNET_MAX_URL_LENGTH];
  929. for (i = 0; i < _cItems; i++)
  930. {
  931. LPCTSTR pszUrl = _GetDisplayUrlForPidl(_ppidl[i], szDisplayUrl, ARRAYSIZE(szDisplayUrl));
  932. if (!pszUrl)
  933. return E_FAIL;
  934. char szAnsiUrl[MAX_URL_STRING];
  935. TCharToAnsi(pszUrl, szAnsiUrl, ARRAYSIZE(szAnsiUrl));
  936. // 2 extra for carriage return and newline
  937. cbAlloc += sizeof(CHAR) * (lstrlenA(szAnsiUrl) + 2);
  938. }
  939. // render the url
  940. pSTM->tymed = TYMED_HGLOBAL;
  941. pSTM->pUnkForRelease = NULL;
  942. pSTM->hGlobal = GlobalAlloc(GPTR, cbAlloc);
  943. if (pSTM->hGlobal)
  944. {
  945. LPSTR pszHTEXT = (LPSTR)pSTM->hGlobal;
  946. int cchHTEXT = cbAlloc / sizeof(CHAR);
  947. for (i = 0; i < _cItems; i++)
  948. {
  949. if (i && cchHTEXT > 2)
  950. {
  951. *pszHTEXT++ = 0xD;
  952. *pszHTEXT++ = 0xA;
  953. cchHTEXT -= 2;
  954. }
  955. LPCTSTR pszUrl = _GetDisplayUrlForPidl(_ppidl[i], szDisplayUrl, ARRAYSIZE(szDisplayUrl));
  956. if (pszUrl)
  957. {
  958. int cchUrl = lstrlen(pszUrl);
  959. TCharToAnsi(pszUrl, pszHTEXT, cchHTEXT);
  960. pszHTEXT += cchUrl;
  961. cchHTEXT -= cchUrl;
  962. }
  963. }
  964. return S_OK;
  965. }
  966. return E_OUTOFMEMORY;
  967. }
  968. HRESULT CBaseItem::_CreateUnicodeTEXT(LPSTGMEDIUM pSTM)
  969. {
  970. UINT i;
  971. UINT cbAlloc = sizeof(WCHAR); // null terminator
  972. WCHAR szDisplayUrl[INTERNET_MAX_URL_LENGTH];
  973. for (i = 0; i < _cItems; i++)
  974. {
  975. ConditionallyDecodeUTF8(_GetUrlForPidl(_ppidl[i]),
  976. szDisplayUrl, ARRAYSIZE(szDisplayUrl));
  977. if (!*szDisplayUrl)
  978. return E_FAIL;
  979. cbAlloc += sizeof(WCHAR) * (lstrlenW(szDisplayUrl) + 2);
  980. }
  981. // render the url
  982. pSTM->tymed = TYMED_HGLOBAL;
  983. pSTM->pUnkForRelease = NULL;
  984. pSTM->hGlobal = GlobalAlloc(GPTR, cbAlloc);
  985. if (pSTM->hGlobal)
  986. {
  987. LPTSTR pszHTEXT = (LPTSTR)pSTM->hGlobal;
  988. int cchHTEXT = cbAlloc / sizeof(WCHAR);
  989. for (i = 0; i < _cItems; i++)
  990. {
  991. if (i && cchHTEXT > 2)
  992. {
  993. *pszHTEXT++ = 0xD;
  994. *pszHTEXT++ = 0xA;
  995. cchHTEXT -= 2;
  996. }
  997. ConditionallyDecodeUTF8(_GetUrlForPidl(_ppidl[i]),
  998. szDisplayUrl, ARRAYSIZE(szDisplayUrl));
  999. int cchUrl = lstrlenW(szDisplayUrl);
  1000. StrCpyN(pszHTEXT, szDisplayUrl, cchHTEXT);
  1001. pszHTEXT += cchUrl;
  1002. cchHTEXT -= cchUrl;
  1003. }
  1004. return S_OK;
  1005. }
  1006. return E_OUTOFMEMORY;
  1007. }