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.

694 lines
19 KiB

  1. #include "shellprv.h"
  2. #include <shellp.h>
  3. #include <sfview.h>
  4. #include "basefvcb.h"
  5. #include "ids.h"
  6. #include "prop.h"
  7. CBaseShellFolderViewCB::CBaseShellFolderViewCB(LPCITEMIDLIST pidl, LONG lEvents)
  8. : _cRef(1), _hwndMain(NULL), _lEvents(lEvents)
  9. {
  10. _pidl = ILClone(pidl);
  11. }
  12. CBaseShellFolderViewCB::~CBaseShellFolderViewCB()
  13. {
  14. ILFree(_pidl); // accpets NULL
  15. }
  16. STDMETHODIMP CBaseShellFolderViewCB::QueryInterface(REFIID riid, void **ppv)
  17. {
  18. static const QITAB qit[] = {
  19. QITABENT(CBaseShellFolderViewCB, IShellFolderViewCB), // IID_IShellFolderViewCB
  20. QITABENT(CBaseShellFolderViewCB, IObjectWithSite), // IID_IObjectWithSite
  21. QITABENT(CBaseShellFolderViewCB, IServiceProvider), // IID_IServiceProvider
  22. { 0 },
  23. };
  24. return QISearch(this, qit, riid, ppv);
  25. }
  26. STDMETHODIMP_(ULONG) CBaseShellFolderViewCB::AddRef()
  27. {
  28. return InterlockedIncrement(&_cRef);
  29. }
  30. STDMETHODIMP_(ULONG) CBaseShellFolderViewCB::Release()
  31. {
  32. if (InterlockedDecrement(&_cRef))
  33. return _cRef;
  34. delete this;
  35. return 0;
  36. }
  37. STDMETHODIMP CBaseShellFolderViewCB::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
  38. {
  39. HRESULT hr = RealMessage(uMsg, wParam, lParam);
  40. if (FAILED(hr))
  41. {
  42. switch (uMsg)
  43. {
  44. case SFVM_HWNDMAIN:
  45. _hwndMain = (HWND)lParam;
  46. hr = S_OK;
  47. break;
  48. case SFVM_GETNOTIFY:
  49. *(LPCITEMIDLIST*)wParam = _pidl;
  50. *(LONG*)lParam = _lEvents;
  51. hr = S_OK;
  52. break;
  53. }
  54. }
  55. return hr;
  56. }
  57. class CWrapOldCallback : public CBaseShellFolderViewCB
  58. {
  59. public:
  60. CWrapOldCallback(LPCSFV pcsfv);
  61. STDMETHODIMP RealMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
  62. // IObjectWithSite
  63. STDMETHODIMP SetSite(IUnknown *punkSite);
  64. private:
  65. ~CWrapOldCallback();
  66. LPFNVIEWCALLBACK _pfnCB;
  67. IShellView* _psvOuter;
  68. IShellFolder *_psf;
  69. UINT _fvm;
  70. LPARAM _lSelChangeInfo;
  71. };
  72. CWrapOldCallback::CWrapOldCallback(LPCSFV pcsfv) : CBaseShellFolderViewCB(pcsfv->pidl, pcsfv->lEvents)
  73. {
  74. _psf = pcsfv->pshf;
  75. _psf->AddRef();
  76. _psvOuter = pcsfv->psvOuter;
  77. _fvm = pcsfv->fvm;
  78. _pfnCB = pcsfv->pfnCallback;
  79. }
  80. CWrapOldCallback::~CWrapOldCallback()
  81. {
  82. _psf->Release();
  83. }
  84. // Some older clients may not support IObjectWithSite::SetSite
  85. // For compat send them the old SFVM_SETISFV message
  86. HRESULT CWrapOldCallback::SetSite(IUnknown *punkSite)
  87. {
  88. HRESULT hr = CBaseShellFolderViewCB::SetSite( punkSite );
  89. MessageSFVCB( SFVM_SETISFV, 0, (LPARAM)punkSite );
  90. return hr;
  91. }
  92. STDMETHODIMP CWrapOldCallback::RealMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
  93. {
  94. DVSELCHANGEINFO dvsci;
  95. switch (uMsg)
  96. {
  97. case SFVM_DEFVIEWMODE:
  98. if (_fvm)
  99. *(UINT*)lParam = _fvm;
  100. break;
  101. case SFVM_SELCHANGE:
  102. {
  103. SFVM_SELCHANGE_DATA* pSelChange = (SFVM_SELCHANGE_DATA*)lParam;
  104. dvsci.uNewState = pSelChange->uNewState;
  105. dvsci.uOldState = pSelChange->uOldState;
  106. dvsci.plParam = &_lSelChangeInfo;
  107. dvsci.lParamItem = pSelChange->lParamItem;
  108. lParam = (LPARAM)&dvsci;
  109. break;
  110. }
  111. case SFVM_INSERTITEM:
  112. case SFVM_DELETEITEM:
  113. case SFVM_WINDOWCREATED:
  114. dvsci.plParam = &_lSelChangeInfo;
  115. dvsci.lParamItem = lParam;
  116. lParam = (LPARAM)&dvsci;
  117. break;
  118. case SFVM_REFRESH:
  119. case SFVM_SELECTALL:
  120. case SFVM_UPDATESTATUSBAR:
  121. case SFVM_SETFOCUS:
  122. case SFVM_PRERELEASE:
  123. lParam = _lSelChangeInfo;
  124. break;
  125. default:
  126. break;
  127. }
  128. // NOTE: The DVM_ messages are the same as the SFVM_ message
  129. return _pfnCB(_psvOuter, _psf, _hwndMain, uMsg, wParam, lParam);
  130. }
  131. LRESULT _ShellFolderViewMessage(IShellFolderView* psfv, UINT uMsg, LPARAM lParam)
  132. {
  133. UINT uScratch;
  134. switch (uMsg)
  135. {
  136. case SFVM_REARRANGE:
  137. psfv->Rearrange(lParam);
  138. break;
  139. case SFVM_ARRANGEGRID:
  140. psfv->ArrangeGrid();
  141. break;
  142. case SFVM_AUTOARRANGE:
  143. psfv->AutoArrange();
  144. break;
  145. case SFVM_GETAUTOARRANGE:
  146. return psfv->GetAutoArrange() == S_OK;
  147. case SFVM_GETARRANGEPARAM:
  148. psfv->GetArrangeParam(&lParam);
  149. return lParam;
  150. case SFVM_ADDOBJECT:
  151. if (SUCCEEDED(psfv->AddObject((LPITEMIDLIST)lParam, &uScratch))
  152. && (int)uScratch >= 0)
  153. {
  154. // New semantics make a copy of the IDList
  155. ILFree((LPITEMIDLIST)lParam);
  156. return uScratch;
  157. }
  158. return -1;
  159. case SFVM_GETOBJECTCOUNT:
  160. return SUCCEEDED(psfv->GetObjectCount(&uScratch)) ? uScratch : -1;
  161. case SFVM_GETOBJECT:
  162. {
  163. LPITEMIDLIST pidl;
  164. return SUCCEEDED(psfv->GetObject(&pidl, (UINT)lParam)) ? (LPARAM)pidl : NULL;
  165. }
  166. case SFVM_REMOVEOBJECT:
  167. return SUCCEEDED(psfv->RemoveObject((LPITEMIDLIST)lParam, &uScratch)) ? uScratch : -1;
  168. case SFVM_UPDATEOBJECT:
  169. {
  170. LPITEMIDLIST *ppidl = (LPITEMIDLIST*)lParam;
  171. if (SUCCEEDED(psfv->UpdateObject(ppidl[0], ppidl[1], &uScratch))
  172. && (int)uScratch >= 0)
  173. {
  174. // New semantics make a copy of the IDList
  175. ILFree(ppidl[1]);
  176. return uScratch;
  177. }
  178. return -1;
  179. }
  180. case SFVM_REFRESHOBJECT:
  181. {
  182. LPITEMIDLIST *ppidl = (LPITEMIDLIST*)lParam;
  183. return SUCCEEDED(psfv->RefreshObject(ppidl[0], &uScratch)) ? uScratch : -1;
  184. }
  185. case SFVM_SETREDRAW:
  186. psfv->SetRedraw(BOOLFROMPTR(lParam));
  187. break;
  188. case SFVM_GETSELECTEDOBJECTS:
  189. return SUCCEEDED(psfv->GetSelectedObjects((LPCITEMIDLIST**)lParam, &uScratch)) ? uScratch : -1;
  190. case SFVM_GETSELECTEDCOUNT:
  191. return SUCCEEDED(psfv->GetSelectedCount(&uScratch)) ? uScratch : -1;
  192. case SFVM_ISDROPONSOURCE:
  193. return psfv->IsDropOnSource((IDropTarget *)lParam) == S_OK;
  194. case SFVM_MOVEICONS:
  195. psfv->MoveIcons((IDataObject *)lParam);
  196. break;
  197. case SFVM_GETDROPPOINT:
  198. return psfv->GetDropPoint((POINT *)lParam) == S_OK;
  199. case SFVM_GETDRAGPOINT:
  200. return psfv->GetDragPoint((POINT *)lParam) == S_OK;
  201. case SFVM_SETITEMPOS:
  202. {
  203. SFV_SETITEMPOS* psip = (SFV_SETITEMPOS*)lParam;
  204. psfv->SetItemPos(psip->pidl, &psip->pt);
  205. break;
  206. }
  207. case SFVM_ISBKDROPTARGET:
  208. return psfv->IsBkDropTarget((IDropTarget *)lParam) == S_OK;
  209. case SFVM_SETCLIPBOARD:
  210. psfv->SetClipboard(lParam == DFM_CMD_MOVE);
  211. break;
  212. case SFVM_SETPOINTS:
  213. psfv->SetPoints((IDataObject *)lParam);
  214. return 0;
  215. case SFVM_GETITEMSPACING:
  216. return psfv->GetItemSpacing((LPITEMSPACING)lParam) == S_OK;
  217. default:
  218. // -1L is the default return value
  219. return 0;
  220. }
  221. return 1;
  222. }
  223. IShellFolderView* ShellFolderViewFromWindow(HWND hwnd)
  224. {
  225. IShellFolderView* psfv = NULL;
  226. // HPCView sometimes gets confused and passes HWND_BROADCAST as its
  227. // window. We can't let this reach FileCabinet_GetIShellBrowser or
  228. // we end up broadcasting the CWM_GETISHELLBROWSER message and screwing
  229. // up everybody in the system. (Not to mention that it will return TRUE,
  230. // indicating a successful broadcast, and then we fault thinking that
  231. // it's a vtbl.)
  232. if (hwnd && hwnd != HWND_BROADCAST)
  233. {
  234. IShellBrowser* psb = FileCabinet_GetIShellBrowser(hwnd);
  235. // Use !IS_INTRESOURCE() to protect against blatanly bogus values
  236. // that clearly aren't pointers to objects.
  237. if (!IS_INTRESOURCE(psb))
  238. {
  239. IShellView* psv;
  240. if (SUCCEEDED(psb->QueryActiveShellView(&psv)))
  241. {
  242. psv->QueryInterface(IID_PPV_ARG(IShellFolderView, &psfv));
  243. psv->Release();
  244. }
  245. }
  246. }
  247. return psfv;
  248. }
  249. STDAPI_(HWND) ShellFolderViewWindow(HWND hwnd)
  250. {
  251. HWND hwndRet = NULL;
  252. IShellBrowser *psb = FileCabinet_GetIShellBrowser(hwnd);
  253. if (psb)
  254. {
  255. IShellView *psv;
  256. if (SUCCEEDED(psb->QueryActiveShellView(&psv)))
  257. {
  258. IUnknown_GetWindow(psv, &hwndRet);
  259. psv->Release();
  260. }
  261. }
  262. return hwndRet;
  263. }
  264. // undoced shell32 export
  265. STDAPI_(IShellFolderViewCB *) SHGetShellFolderViewCB(HWND hwnd)
  266. {
  267. ASSERT(0);
  268. return NULL; // no one calls this (search of the NT code finds no callers)
  269. }
  270. // old msg based way of programming defview (pre dates IShellFolderView)
  271. STDAPI_(LRESULT) SHShellFolderView_Message(HWND hwnd, UINT uMsg, LPARAM lParam)
  272. {
  273. LRESULT lret = 0;
  274. IShellFolderView* psfv = ShellFolderViewFromWindow(hwnd);
  275. if (psfv)
  276. {
  277. lret = _ShellFolderViewMessage(psfv, uMsg, lParam);
  278. psfv->Release();
  279. }
  280. return lret;
  281. }
  282. STDAPI SHCreateShellFolderViewEx(LPCSFV pcsfv, IShellView **ppsv)
  283. {
  284. SFV_CREATE sfvc;
  285. sfvc.cbSize = sizeof(sfvc);
  286. sfvc.pshf = pcsfv->pshf;
  287. sfvc.psvOuter = pcsfv->psvOuter;
  288. sfvc.psfvcb = pcsfv->pfnCallback ? new CWrapOldCallback(pcsfv) : NULL;
  289. HRESULT hr = SHCreateShellFolderView(&sfvc, ppsv);
  290. if (sfvc.psfvcb)
  291. sfvc.psfvcb->Release();
  292. return hr;
  293. }
  294. STDAPI_(void) InitializeStatus(IUnknown *psite)
  295. {
  296. IShellBrowser *psb;
  297. if (SUCCEEDED(IUnknown_QueryService(psite, SID_STopLevelBrowser, IID_PPV_ARG(IShellBrowser, &psb))))
  298. {
  299. LONG_PTR nParts = 0, n;
  300. psb->SendControlMsg(FCW_STATUS, SB_GETPARTS, 0, 0, &nParts);
  301. for (n = 0; n < nParts; n ++)
  302. {
  303. psb->SendControlMsg(FCW_STATUS, SB_SETTEXT, n, (LPARAM)TEXT(""), NULL);
  304. psb->SendControlMsg(FCW_STATUS, SB_SETICON, n, (LPARAM)NULL, NULL);
  305. }
  306. psb->SendControlMsg(FCW_STATUS, SB_SETPARTS, 0, 0, NULL);
  307. psb->Release();
  308. }
  309. }
  310. //
  311. // The status bar partitioning has undergone several changes. Here's
  312. // what we've got right now:
  313. //
  314. // Pane 0 = Selection - all remaining space
  315. // Pane 1 = Size - just big enough to say 9,999 bytes (11 chars)
  316. // Pane 2 = Zone - just big enough to hold longest zone
  317. //
  318. STDAPI_(void) ResizeStatus(IUnknown *psite, UINT cx)
  319. {
  320. IShellBrowser *psb;
  321. if (SUCCEEDED(IUnknown_QueryService(psite, SID_STopLevelBrowser, IID_PPV_ARG(IShellBrowser, &psb))))
  322. {
  323. HWND hwndStatus;
  324. if (SUCCEEDED(psb->GetControlWindow(FCW_STATUS, &hwndStatus)) && hwndStatus)
  325. {
  326. RECT rc;
  327. int ciParts[3];
  328. int ciBorders[3];
  329. int cxPart;
  330. GetClientRect(hwndStatus, &rc);
  331. // Must also take status bar borders into account.
  332. psb->SendControlMsg(FCW_STATUS, SB_GETBORDERS, 0, (LPARAM)ciBorders, NULL);
  333. // We build the panes from right to left.
  334. ciParts[2] = -1;
  335. // The Zones part
  336. cxPart = ciBorders[0] + ZoneComputePaneSize(hwndStatus) + ciBorders[2];
  337. ciParts[1] = rc.right - cxPart;
  338. // The Size part
  339. HDC hdc = GetDC(hwndStatus);
  340. HFONT hfPrev = SelectFont(hdc, GetWindowFont(hwndStatus));
  341. SIZE siz;
  342. GetTextExtentPoint32(hdc, TEXT("0"), 1, &siz);
  343. SelectObject(hdc, hfPrev);
  344. ReleaseDC(hwndStatus, hdc);
  345. cxPart = ciBorders[0] + siz.cx * (11 + 2); // "+2" for slop
  346. ciParts[0] = ciParts[1] - cxPart;
  347. //
  348. // If we underflowed, then give up and just give everybody
  349. // one third.
  350. //
  351. if (ciParts[0] < 0)
  352. {
  353. ciParts[0] = rc.right / 3;
  354. ciParts[1] = 2 * ciParts[0];
  355. }
  356. psb->SendControlMsg(FCW_STATUS, SB_SETPARTS, ARRAYSIZE(ciParts), (LPARAM)ciParts, NULL);
  357. }
  358. psb->Release();
  359. }
  360. }
  361. STDAPI_(void) SetStatusText(IUnknown *psite, LPCTSTR *ppszText, int iStart, int iEnd)
  362. {
  363. IShellBrowser *psb;
  364. if (SUCCEEDED(IUnknown_QueryService(psite, SID_STopLevelBrowser, IID_PPV_ARG(IShellBrowser, &psb))))
  365. {
  366. for (; iStart <= iEnd; iStart++)
  367. {
  368. LPCTSTR psz;
  369. if (ppszText)
  370. {
  371. psz = *ppszText;
  372. ppszText++;
  373. }
  374. else
  375. psz = c_szNULL;
  376. psb->SendControlMsg(FCW_STATUS, SB_SETTEXT, (WPARAM)iStart, (LPARAM)psz, NULL);
  377. }
  378. psb->Release();
  379. }
  380. }
  381. STDAPI_(void) ViewShowSelectionState(IUnknown *psite, FSSELCHANGEINFO *pfssci)
  382. {
  383. TCHAR szTemp[20], szBytes[30];
  384. LPTSTR pszStatus = NULL;
  385. if (pfssci->nItems > 1)
  386. {
  387. pszStatus = ShellConstructMessageString(HINST_THISDLL, MAKEINTRESOURCE(IDS_FSSTATUSSELECTED),
  388. AddCommas(pfssci->nItems, szTemp, ARRAYSIZE(szTemp)));
  389. }
  390. if (pfssci->cNonFolders)
  391. ShortSizeFormat64(pfssci->cbBytes, szBytes, ARRAYSIZE(szBytes));
  392. else
  393. szBytes[0] = 0;
  394. LPCTSTR rgpsz[] = { pszStatus, szBytes };
  395. SetStatusText(psite, rgpsz, 0, 1);
  396. if (pszStatus)
  397. LocalFree(pszStatus);
  398. }
  399. HRESULT _UpdateDiskFreeSpace(LPCITEMIDLIST pidlFolder, FSSELCHANGEINFO *pfssci)
  400. {
  401. IShellFolder2 *psf2;
  402. LPCITEMIDLIST pidlLast;
  403. HRESULT hr = SHBindToIDListParent(pidlFolder, IID_PPV_ARG(IShellFolder2, &psf2), &pidlLast);
  404. if (SUCCEEDED(hr))
  405. {
  406. ULONGLONG ullTotalFreeCaller;
  407. hr = GetLongProperty(psf2, pidlLast, &SCID_FREESPACE, &ullTotalFreeCaller);
  408. if (SUCCEEDED(hr))
  409. {
  410. pfssci->cbFree = ullTotalFreeCaller;
  411. }
  412. else if (!ILIsEmpty(pidlFolder) && !ILIsEmpty(_ILNext(pidlFolder)))
  413. {
  414. // if there are at least 2 segments in the IDList rip off the
  415. // last item and recurse to compute the size
  416. LPITEMIDLIST pidl = ILCloneParent(pidlFolder);
  417. if (pidl)
  418. {
  419. hr = _UpdateDiskFreeSpace(pidl, pfssci);
  420. ILFree(pidl);
  421. }
  422. }
  423. psf2->Release();
  424. }
  425. return hr;
  426. }
  427. void _ShowNoSelectionState(IUnknown *psite, LPCITEMIDLIST pidlFolder, FSSELCHANGEINFO *pfssci)
  428. {
  429. TCHAR szTemp[30], szTempHidden[30], szFreeSpace[30];
  430. UINT ids = IDS_FSSTATUSBASE;
  431. // Assume we don't need freespace info
  432. szFreeSpace[0] = 0;
  433. // See if we need the freespace info (idDrive != -1)
  434. ULONGLONG cbFree = -1;
  435. if (pidlFolder && IsExplorerModeBrowser(psite))
  436. {
  437. if (pfssci->cbFree == -1)
  438. _UpdateDiskFreeSpace(pidlFolder, pfssci);
  439. // cbFree couldstill be -1 if GetDiskFreeSpace didn't get any info
  440. cbFree = pfssci->cbFree;
  441. if (cbFree != -1)
  442. {
  443. ShortSizeFormat64(pfssci->cbFree, szFreeSpace, ARRAYSIZE(szFreeSpace));
  444. ids += DIDS_FSSPACE; // Also show freespace
  445. }
  446. }
  447. // hidden files -> show "and nn hidden".
  448. if (pfssci->cHiddenFiles)
  449. ids += DIDS_FSHIDDEN;
  450. // Get the status string
  451. LPTSTR pszStatus = ShellConstructMessageString(HINST_THISDLL, IntToPtr_(LPCTSTR, ids),
  452. AddCommas(pfssci->cFiles, szTemp, ARRAYSIZE(szTemp)),
  453. AddCommas(pfssci->cHiddenFiles, szTempHidden, ARRAYSIZE(szTempHidden)),
  454. szFreeSpace);
  455. // Get the size portion
  456. StrFormatByteSize64(pfssci->cbSize, szTemp, ARRAYSIZE(szTemp));
  457. LPCTSTR rgpsz[] = { pszStatus, szTemp };
  458. SetStatusText(psite, rgpsz, 0, 1);
  459. LocalFree(pszStatus); // may be NULL
  460. }
  461. STDAPI ViewUpdateStatusBar(IUnknown *psite, LPCITEMIDLIST pidlFolder, FSSELCHANGEINFO *pfssci)
  462. {
  463. HRESULT hr = S_OK;
  464. switch (pfssci->nItems)
  465. {
  466. case 0:
  467. _ShowNoSelectionState(psite, pidlFolder, pfssci);
  468. hr = S_OK;
  469. break;
  470. case 1:
  471. ViewShowSelectionState(psite, pfssci); //Set the Size only.
  472. hr = SFVUSB_INITED; // Make defview set infotip as text
  473. break;
  474. default:
  475. ViewShowSelectionState(psite, pfssci);
  476. hr = S_OK;
  477. break;
  478. }
  479. return hr;
  480. }
  481. STDAPI_(void) ViewInsertDeleteItem(IShellFolder2 *psf, FSSELCHANGEINFO *pfssci, LPCITEMIDLIST pidl, int iMul)
  482. {
  483. ULONGLONG ullSize;
  484. if (SUCCEEDED(GetLongProperty(psf, pidl, &SCID_SIZE, &ullSize)))
  485. {
  486. pfssci->cFiles += iMul;
  487. pfssci->cbSize += iMul * ullSize;
  488. if (pfssci->cFiles <= 0)
  489. {
  490. pfssci->cbSize = 0;
  491. pfssci->cFiles = 0;
  492. }
  493. }
  494. else
  495. {
  496. // means a delete all
  497. pfssci->cFiles = 0;
  498. pfssci->cbSize = 0;
  499. pfssci->nItems = 0;
  500. pfssci->cbBytes = 0;
  501. pfssci->cNonFolders = 0;
  502. pfssci->cHiddenFiles = 0;
  503. }
  504. }
  505. STDAPI_(void) ViewSelChange(IShellFolder2 *psf, SFVM_SELCHANGE_DATA* pdvsci, FSSELCHANGEINFO *pfssci)
  506. {
  507. ULONGLONG ullSize;
  508. LPCITEMIDLIST pidl = (LPCITEMIDLIST)pdvsci->lParamItem;
  509. if (SUCCEEDED(GetLongProperty(psf, pidl, &SCID_SIZE, &ullSize)))
  510. {
  511. int iMul = -1;
  512. // Update selection count
  513. if (pdvsci->uNewState & LVIS_SELECTED)
  514. iMul = 1;
  515. else
  516. ASSERT(0 != pfssci->nItems);
  517. // assert that soemthing changed
  518. ASSERT((pdvsci->uOldState & LVIS_SELECTED) != (pdvsci->uNewState & LVIS_SELECTED));
  519. pfssci->nItems += iMul;
  520. pfssci->cbBytes += (iMul * ullSize);
  521. if (!SHGetAttributes(psf, pidl, SFGAO_FOLDER))
  522. pfssci->cNonFolders += iMul;
  523. }
  524. }
  525. STDAPI DefaultGetWebViewTemplateFromHandler(LPCTSTR pszKey, SFVM_WEBVIEW_TEMPLATE_DATA* pvit)
  526. {
  527. HRESULT hr = S_OK;
  528. TCHAR szKey[200];
  529. wnsprintf(szKey, ARRAYSIZE(szKey), TEXT("%s\\shellex\\ExtShellFolderViews\\{5984FFE0-28D4-11CF-AE66-08002B2E1262}"), pszKey);
  530. DWORD cbSize = sizeof(pvit->szWebView);
  531. if (ERROR_SUCCESS == SHGetValueW(HKEY_CLASSES_ROOT, szKey, TEXT("PersistMoniker"), NULL, pvit->szWebView, &cbSize))
  532. {
  533. //if the %UserAppData% exists, expand it!
  534. ExpandOtherVariables(pvit->szWebView, ARRAYSIZE(pvit->szWebView));
  535. }
  536. else
  537. {
  538. hr = E_FAIL;
  539. }
  540. return hr;
  541. }
  542. STDAPI DefaultGetWebViewTemplateFromClsid(REFCLSID clsid, SFVM_WEBVIEW_TEMPLATE_DATA* pvit)
  543. {
  544. TCHAR szHandler[6+40] = TEXT("CLSID\\"); // 6 for "CLSID\\", 40 for GUID
  545. SHStringFromGUID(clsid, &szHandler[6], ARRAYSIZE(szHandler)-6);
  546. return DefaultGetWebViewTemplateFromHandler(szHandler, pvit);
  547. }
  548. STDAPI DefaultGetWebViewTemplateFromPath(LPCTSTR pszDir, SFVM_WEBVIEW_TEMPLATE_DATA* pvit)
  549. {
  550. SHFOLDERCUSTOMSETTINGS fcs = {0};
  551. TCHAR szPath[MAX_PATH+40]; // slop for "webview://file://"
  552. fcs.dwSize = sizeof(fcs);
  553. fcs.dwMask = FCSM_WEBVIEWTEMPLATE;
  554. fcs.pszWebViewTemplate = szPath;
  555. fcs.cchWebViewTemplate = ARRAYSIZE(szPath);
  556. HRESULT hr = SHGetSetFolderCustomSettings(&fcs, pszDir, FCS_READ);
  557. if (SUCCEEDED(hr))
  558. {
  559. LPTSTR pszPath = szPath;
  560. // We want to allow relative paths for the file: protocol
  561. //
  562. if (0 == StrCmpNI(TEXT("file://"), pszPath, 7)) // ARRAYSIZE(TEXT("file://"))
  563. {
  564. pszPath += 7; // ARRAYSIZE(TEXT("file://"))
  565. }
  566. // for webview:// compatibility, keep this working:
  567. else if (0 == StrCmpNI(TEXT("webview://file://"), pszPath, 17)) // ARRAYSIZE(TEXT("webview://file://"))
  568. {
  569. pszPath += 17; // ARRAYSIZE(TEXT("webview://file://"))
  570. }
  571. // handle relative references...
  572. PathCombine(pszPath, pszDir, pszPath);
  573. StrCpyN(pvit->szWebView, szPath, ARRAYSIZE(pvit->szWebView));
  574. }
  575. return hr;
  576. }