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.

15427 lines
482 KiB

  1. #include "shellprv.h"
  2. #include <regstr.h>
  3. #include <shellp.h>
  4. #include <htmlhelp.h>
  5. #include "ole2dup.h"
  6. #include "ids.h"
  7. #include "defview.h"
  8. #include "lvutil.h"
  9. #include "idlcomm.h"
  10. #include "filetbl.h"
  11. #include "undo.h"
  12. #include "vdate.h"
  13. #include "cnctnpt.h"
  14. #include "ovrlaymn.h"
  15. #include "_security.h"
  16. #include "unicpp\dutil.h"
  17. #include "uemapp.h"
  18. #include "unicpp\deskhtm.h"
  19. #include "unicpp\dcomp.h"
  20. #include "datautil.h"
  21. #include "defvphst.h"
  22. #include <shdispid.h>
  23. #include <limits.h>
  24. #include "prop.h"
  25. #include <mshtmcid.h>
  26. #include "dvtasks.h"
  27. #include "category.h"
  28. #include "ViewState.h"
  29. #include <initguid.h>
  30. #include <guids.h>
  31. #include <CommonControls.h>
  32. #include "clsobj.h"
  33. #include <sfview.h>
  34. #include "defviewp.h"
  35. #include "shellp.h"
  36. #include "duiview.h"
  37. #include "enumidlist.h"
  38. #include "util.h"
  39. #include "foldertypes.h"
  40. #include <dpa.h>
  41. #include "views.h"
  42. #include "defcm.h"
  43. #include "contextmenu.h"
  44. // a "default" view to trick the browser into letting us delay viewmode selection
  45. // {6C6720F7-4B22-4CAA-82D6-502BB6F85A9A}
  46. DEFINE_GUID(VID_DefaultView, 0x6C6720F7L, 0x4B22, 0x4CAA, 0x82, 0xD6, 0x50, 0x2B, 0xB6, 0xF8, 0x5A, 0x9A);
  47. void DisableActiveDesktop();
  48. STDAPI_(void) CFSFolder_UpdateIcon(IShellFolder *psf, LPCITEMIDLIST pidl);
  49. STDAPI_(void) SetPositionItemsPoints(IFolderView* psfv, LPCITEMIDLIST* apidl, UINT cidl, IDataObject* pdtobj, POINT* ptDrag);
  50. void UpdateGridSizes(BOOL fDesktop, HWND hwndListview, int nWorkAreas, LPRECT prcWork, BOOL fMinimizeGutterSpace);
  51. #define ID_LISTVIEW 1
  52. #define ID_STATIC 2
  53. extern BOOL g_fDraggingOverSource;
  54. #define IsDefaultState(_dvHead) ((_dvHead).dvState.lParamSort == 0 && \
  55. (_dvHead).dvState.iDirection == 1 && \
  56. (_dvHead).dvState.iLastColumnClick == -1 && \
  57. (_dvHead).ptScroll.x == 0 && (_dvHead).ptScroll.y == 0)
  58. HMODULE g_hmodNTSHRUI = NULL;
  59. typedef struct
  60. {
  61. POINT pt;
  62. ITEMIDLIST idl;
  63. } DVITEM;
  64. //
  65. // Note that it returns NULL, if iItem is -1.
  66. //
  67. // determine if color is light or dark
  68. #define COLORISLIGHT(clr) ((5*GetGValue((clr)) + 2*GetRValue((clr)) + GetBValue((clr))) > 8*128)
  69. void EnableCombinedView(CDefView *pdsv, BOOL fEnable);
  70. BOOL IsBarricadeGloballyOff();
  71. VARIANT_BOOL GetBarricadeStatus(LPCTSTR pszValueName);
  72. BOOL GetBarricadeValueNameFromPidl(LPCITEMIDLIST pidl, LPTSTR pszValueName, UINT cch);
  73. HRESULT SetBarricadeStatus(LPCTSTR pszValueName, VARIANT_BOOL bShowBarricade);
  74. // Command Strings
  75. // !! warning. Some ContextMenu handlers do not do a case-insensitive
  76. // check of the command so keep the case the same everywhere
  77. TCHAR const c_szCut[] = TEXT("cut");
  78. TCHAR const c_szCopy[] = TEXT("copy");
  79. TCHAR const c_szLink[] = TEXT("link");
  80. TCHAR const c_szProperties[] = TEXT("properties");
  81. TCHAR const c_szPaste[] = TEXT("paste");
  82. TCHAR const c_szPasteLink[] = TEXT("pastelink");
  83. TCHAR const c_szRename[] = TEXT("rename");
  84. TCHAR const c_szDelete[] = TEXT("delete");
  85. TCHAR const c_szNewFolder[] = TEXT(CMDSTR_NEWFOLDERA);
  86. char const c_szDeleteA[] = "delete";
  87. char const c_szNewFolderA[] = CMDSTR_NEWFOLDERA;
  88. char const c_szPrintA[] = "print";
  89. WCHAR const c_szPrintW[] = L"print";
  90. DWORD CDefView::_Attributes(LPCITEMIDLIST pidl, DWORD dwAttribs)
  91. {
  92. return SHGetAttributes(_pshf, pidl, dwAttribs);
  93. }
  94. // IDefViewSafety
  95. HRESULT CDefView::IsSafePage()
  96. {
  97. HRESULT hr = E_ACCESSDENIED;
  98. WCHAR wszCurrentMoniker[MAX_PATH];
  99. if (SUCCEEDED(_cFrame._GetCurrentWebViewMoniker(wszCurrentMoniker,
  100. ARRAYSIZE(wszCurrentMoniker))))
  101. {
  102. hr = SHRegisterValidateTemplate(wszCurrentMoniker,
  103. SHRVT_VALIDATE | SHRVT_PROMPTUSER | SHRVT_REGISTERIFPROMPTOK);
  104. }
  105. return hr;
  106. }
  107. // IDVGetEnum
  108. HRESULT CDefView::SetEnumReadyCallback(PFDVENUMREADYBALLBACK pfn, void *pvData)
  109. {
  110. _pfnEnumReadyCallback = pfn;
  111. _pvEnumCallbackData = pvData;
  112. return S_OK;
  113. }
  114. BOOL FilterOnAttributes(DWORD dwAttributes, DWORD grfEnumFlags)
  115. {
  116. if (dwAttributes & SFGAO_FOLDER)
  117. {
  118. if (!(grfEnumFlags & SHCONTF_FOLDERS))
  119. return FALSE; // item is folder but client does not want folders
  120. }
  121. else if (!(grfEnumFlags & SHCONTF_NONFOLDERS))
  122. {
  123. return FALSE; // item is file, but client only wants folders
  124. }
  125. if (!(grfEnumFlags & SHCONTF_INCLUDEHIDDEN) &&
  126. (dwAttributes & SFGAO_HIDDEN))
  127. return FALSE; // item is hidden by client wants non hidden
  128. return TRUE;
  129. }
  130. HRESULT CDefView::CreateEnumIDListFromContents(LPCITEMIDLIST pidlFolder, DWORD grfEnumFlags, IEnumIDList **ppenum)
  131. {
  132. HRESULT hr = E_FAIL;
  133. LPITEMIDLIST pidlView = _GetViewPidl();
  134. if (pidlView)
  135. {
  136. if (ILIsEqual(pidlFolder, pidlView) && (grfEnumFlags & _GetEnumFlags()) == grfEnumFlags)
  137. {
  138. LPCITEMIDLIST *apidl;
  139. UINT cItems;
  140. hr = _GetItemObjects(&apidl, SVGIO_ALLVIEW, &cItems);
  141. if (SUCCEEDED(hr))
  142. {
  143. for (UINT i = 0; i < cItems; i++)
  144. {
  145. if (!FilterOnAttributes(_Attributes(apidl[i], SFGAO_FOLDER | SFGAO_HIDDEN), grfEnumFlags))
  146. {
  147. apidl[i] = apidl[cItems - 1];
  148. cItems--;
  149. i--;
  150. }
  151. }
  152. hr = CreateIEnumIDListOnIDLists(apidl, cItems, ppenum);
  153. LocalFree(apidl);
  154. }
  155. }
  156. ILFree(pidlView);
  157. }
  158. return hr;
  159. }
  160. HRESULT CDefView::_OnDefaultCommand()
  161. {
  162. return _pcdb ? _pcdb->OnDefaultCommand(_psvOuter ? _psvOuter : this) : E_NOTIMPL;
  163. }
  164. HRESULT CDefView::_OnStateChange(UINT code)
  165. {
  166. return _pcdb ? _pcdb->OnStateChange(_psvOuter ? _psvOuter : this, code) : E_NOTIMPL;
  167. }
  168. HRESULT CDefView::_IncludeObject(LPCITEMIDLIST pidl)
  169. {
  170. if (_pcdb)
  171. return _pcdb->IncludeObject(_psvOuter ? _psvOuter : this, pidl);
  172. else
  173. {
  174. IFolderFilter *psff = _cCallback.GetISFF();
  175. return psff ? psff->ShouldShow(_pshf, NULL, pidl) : S_OK;
  176. }
  177. }
  178. HRESULT CDefView::CallCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
  179. {
  180. return _cCallback.CallCB(uMsg, wParam, lParam);
  181. }
  182. void CDefView::RegisterSFVEvents(IUnknown * pTarget, BOOL fConnect)
  183. {
  184. ConnectToConnectionPoint(SAFECAST(this, IShellView2 *),
  185. DIID_DShellFolderViewEvents, fConnect, pTarget, &_dwConnectionCookie, NULL);
  186. }
  187. // fires dispatch events to clients (address bar, webview, etc).
  188. // this translates return values of false into "ERROR_CANCELLED"
  189. HRESULT CDefView::_FireEvent(DISPID dispid)
  190. {
  191. HRESULT hr;
  192. VARIANT varResult = {0};
  193. SHINVOKEPARAMS inv = {0};
  194. inv.dispidMember = dispid;
  195. inv.piid = &IID_NULL;
  196. inv.wFlags = DISPATCH_METHOD;
  197. inv.pvarResult = &varResult;
  198. if (SUCCEEDED(IUnknown_CPContainerInvokeIndirect(_pauto, DIID_DShellFolderViewEvents, &inv)))
  199. {
  200. if ((VT_BOOL == varResult.vt) && (VARIANT_FALSE == varResult.boolVal))
  201. {
  202. hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
  203. }
  204. else
  205. {
  206. hr = S_OK;
  207. }
  208. VariantClear(&varResult);
  209. }
  210. else
  211. hr = S_FALSE;
  212. return hr;
  213. }
  214. BOOL CDefView::_IsPositionedView()
  215. {
  216. return !_fGroupView && ((_fs.ViewMode == FVM_ICON) || (_fs.ViewMode == FVM_SMALLICON) ||
  217. (_fs.ViewMode == FVM_TILE) || (_fs.ViewMode == FVM_THUMBNAIL) ||
  218. (_fs.ViewMode == FVM_THUMBSTRIP));
  219. }
  220. // reposition the selected items in a listview by dx, dy
  221. void CDefView::_MoveSelectedItems(int dx, int dy, BOOL fAbsolute)
  222. {
  223. SendMessage(_hwndListview, WM_SETREDRAW, FALSE, 0);
  224. for (int i = ListView_GetNextItem(_hwndListview, -1, LVNI_SELECTED);
  225. i >= 0;
  226. i = ListView_GetNextItem(_hwndListview, i, LVNI_SELECTED))
  227. {
  228. if (fAbsolute)
  229. {
  230. _SetItemPosition(i, dx, dy);
  231. }
  232. else
  233. {
  234. POINT pt;
  235. ListView_GetItemPosition(_hwndListview, i, &pt);
  236. pt.x += dx;
  237. pt.y += dy;
  238. _SetItemPosition(i, pt.x, pt.y);
  239. }
  240. }
  241. SendMessage(_hwndListview, WM_SETREDRAW, TRUE, 0);
  242. }
  243. void CDefView::_SameViewMoveIcons()
  244. {
  245. POINT ptDrop;
  246. BOOL fAbsolute = FALSE;
  247. // We'll use the insert mark rect (if available) to determine a drop point
  248. if (_GetInsertPoint(&ptDrop))
  249. fAbsolute = TRUE; // Move all items to this point.
  250. else
  251. {
  252. ptDrop = _ptDrop;
  253. ptDrop.x -= _ptDragAnchor.x;
  254. ptDrop.y -= _ptDragAnchor.y;
  255. LVUtil_ClientToLV(_hwndListview, &ptDrop);
  256. }
  257. ASSERT(_IsPositionedView());
  258. _MoveSelectedItems(ptDrop.x, ptDrop.y, fAbsolute);
  259. }
  260. BOOL _DoesRegkeyExist(HKEY hkRoot, LPCTSTR pszSubkey)
  261. {
  262. LONG l = 0;
  263. return RegQueryValue(hkRoot, pszSubkey, NULL, &l) == ERROR_SUCCESS;
  264. }
  265. //
  266. // This function checks if the current HTML wallpaper is the default
  267. // wallpaper and returns TRUE if so. If the wallpaper is the default wallpaper,
  268. // it reads the colors from the registry. If the colors are missing, then it
  269. // supplies the default colors.
  270. //
  271. BOOL CDefView::_GetColorsFromHTMLdoc(COLORREF *pclrTextBk, COLORREF *pclrHotlight)
  272. {
  273. // make sure the HTML document has reached ready-state interactive
  274. COLORREF clrBackground;
  275. BOOL bRet = SUCCEEDED(_cFrame._GetHTMLBackgroundColor(&clrBackground));
  276. if (bRet)
  277. {
  278. // The following are the standard colors supported on desktop
  279. const COLORREF c_VgaColorTable[] =
  280. {
  281. 0x000000, // Black
  282. 0x000080,
  283. 0x0000FF,
  284. 0x008000,
  285. 0x008080,
  286. 0x00FF00, // Green
  287. 0x00FFFF, // Yellow
  288. 0x800000,
  289. 0x800080,
  290. 0x808000,
  291. 0x808080,
  292. 0xF0CAA6,
  293. 0xF0FBFF,
  294. 0xFF0000, // Blue
  295. 0xFF00FF, // Magenta
  296. 0xFFFF00, // cobalt
  297. 0xFFFFFF // White
  298. };
  299. // Check if the given background color is a standard color.
  300. // If not, use the system background (COLOR_BACKGROUND).
  301. *pclrTextBk = GetSysColor(COLOR_BACKGROUND); // default
  302. for (int i = 0; i < ARRAYSIZE(c_VgaColorTable); i++)
  303. {
  304. if (c_VgaColorTable[i] == clrBackground)
  305. {
  306. *pclrTextBk = clrBackground; // standard, so use it
  307. break;
  308. }
  309. }
  310. if (COLORISLIGHT(*pclrTextBk))
  311. *pclrHotlight = 0x000000; //Black as hightlight color!
  312. else
  313. *pclrHotlight = 0xFFFFFF; //White as highlight color!
  314. }
  315. return bRet;
  316. }
  317. // Set the colors for the folder - taking care if it's the desktop.
  318. void CDefView::_SetFolderColors()
  319. {
  320. COLORREF clrText, clrTextBk, clrWindow;
  321. // Is this view for the desktop?
  322. if (_IsDesktop())
  323. {
  324. COLORREF clrHotlight;
  325. Shell_SysColorChange();
  326. // If we show HTML wallpaper, then get the appropriate colors too!
  327. if (_fCombinedView && _GetColorsFromHTMLdoc(&clrTextBk, &clrHotlight))
  328. {
  329. // Set the Hotlight color!
  330. ListView_SetHotlightColor(_hwndListview, clrHotlight);
  331. }
  332. else
  333. {
  334. // Yep.
  335. // Clear the background color of the desktop to make it
  336. // properly handle transparency.
  337. clrTextBk = GetSysColor(COLOR_BACKGROUND);
  338. //Reset the Hotlight color sothat the system color can be used.
  339. ListView_SetHotlightColor(_hwndListview, CLR_DEFAULT);
  340. }
  341. // set a text color that will show up over desktop color
  342. if (COLORISLIGHT(clrTextBk))
  343. clrText = 0x000000; // black
  344. else
  345. clrText = 0xFFFFFF; // white
  346. clrWindow = CLR_NONE; // Assume transparent
  347. //
  348. // if there is no wallpaper or pattern we can use
  349. // a solid color for the ListView. otherwise we
  350. // need to use a transparent ListView, this is much
  351. // slower so dont do it unless we need to.
  352. //
  353. // Don't do this optimization if USER is going to paint
  354. // some magic text on the desktop, such as
  355. //
  356. // "FailSafe" (SM_CLEANBOOT)
  357. // "Debug" (SM_DEBUG)
  358. // "Build ####" (REGSTR_PATH_DESKTOP\PaintDesktopVersion)
  359. // "Evaluation Version"
  360. //
  361. // too bad there is no SPI_GETWALLPAPER, we need to read
  362. // from WIN.INI.
  363. //
  364. TCHAR szWallpaper[128], szPattern[128];
  365. DWORD dwPaintVersion = 0;
  366. szWallpaper[0] = 0;
  367. szPattern[0] = 0;
  368. HKEY hkey;
  369. if (RegOpenKey(HKEY_CURRENT_USER, REGSTR_PATH_DESKTOP, &hkey) == 0)
  370. {
  371. UINT cb = sizeof(szWallpaper);
  372. SHQueryValueEx(hkey, TEXT("Wallpaper"), NULL, NULL, (LPBYTE)szWallpaper, (ULONG*)&cb);
  373. cb = sizeof(szPattern);
  374. SHQueryValueEx(hkey, TEXT("Pattern"), NULL, NULL, (LPBYTE)szPattern, (ULONG*)&cb);
  375. cb = sizeof(dwPaintVersion);
  376. SHQueryValueEx(hkey, TEXT("PaintDesktopVersion"), NULL, NULL, (LPBYTE)&dwPaintVersion, (ULONG*)&cb);
  377. // Other external criteria for painting the version
  378. //
  379. // - This is a beta version (has an expiration date)
  380. // - A test certificate is installed
  381. //
  382. if (dwPaintVersion == 0 && IsOS(OS_WIN2000ORGREATER))
  383. {
  384. #define REGSTR_PATH_LM_ROOTCERTIFICATES \
  385. TEXT("SOFTWARE\\Microsoft\\SystemCertificates\\Root\\Certificates")
  386. #define REGSTR_PATH_GPO_ROOTCERTIFICATES \
  387. TEXT("SOFTWARE\\Policies\\Microsoft\\SystemCertificates\\Root\\Certificates")
  388. #define REGSTR_KEY_TESTCERTIFICATE \
  389. TEXT("2BD63D28D7BCD0E251195AEB519243C13142EBC3")
  390. dwPaintVersion = (0 != USER_SHARED_DATA->SystemExpirationDate.QuadPart) ||
  391. _DoesRegkeyExist(HKEY_LOCAL_MACHINE, REGSTR_PATH_LM_ROOTCERTIFICATES TEXT("\\") REGSTR_KEY_TESTCERTIFICATE) ||
  392. _DoesRegkeyExist(HKEY_LOCAL_MACHINE, REGSTR_PATH_GPO_ROOTCERTIFICATES TEXT("\\") REGSTR_KEY_TESTCERTIFICATE) ||
  393. _DoesRegkeyExist(HKEY_CURRENT_USER, REGSTR_PATH_GPO_ROOTCERTIFICATES TEXT("\\") REGSTR_KEY_TESTCERTIFICATE);
  394. }
  395. RegCloseKey(hkey);
  396. }
  397. if (_fCombinedView ||
  398. (GetSystemMetrics(SM_CLEANBOOT) == 0 &&
  399. GetSystemMetrics(SM_DEBUG) == 0 &&
  400. !dwPaintVersion &&
  401. (!_fHasDeskWallPaper) &&
  402. (szWallpaper[0] == 0 || szWallpaper[0] == TEXT('(')) &&
  403. (szPattern[0] == 0 || szPattern[0] == TEXT('('))))
  404. {
  405. clrWindow = GetSysColor(COLOR_BACKGROUND);
  406. }
  407. }
  408. else
  409. {
  410. // Nope.
  411. clrWindow = GetSysColor(COLOR_WINDOW);
  412. clrTextBk = clrWindow;
  413. clrText = GetSysColor(COLOR_WINDOWTEXT);
  414. if (_fs.fFlags & FWF_TRANSPARENT)
  415. {
  416. IWebBrowser2 *pwb;
  417. if (SUCCEEDED(IUnknown_QueryService(_psb, SID_SContainerDispatch, IID_PPV_ARG(IWebBrowser2, &pwb))))
  418. {
  419. IDispatch *pdisp;
  420. if (SUCCEEDED(pwb->get_Parent(&pdisp)))
  421. {
  422. IUnknown_HTMLBackgroundColor(pdisp, &clrWindow);
  423. pdisp->Release();
  424. }
  425. pwb->Release();
  426. }
  427. }
  428. }
  429. if (!_fClassic && ISVALIDCOLOR(_crCustomColors[CRID_CUSTOMTEXTBACKGROUND]))
  430. clrTextBk = _crCustomColors[CRID_CUSTOMTEXTBACKGROUND];
  431. if (!_fClassic && ISVALIDCOLOR(_crCustomColors[CRID_CUSTOMTEXT]))
  432. clrText = _crCustomColors[CRID_CUSTOMTEXT];
  433. BOOL bChange = FALSE;
  434. if (clrWindow != ListView_GetBkColor(_hwndListview))
  435. bChange = ListView_SetBkColor(_hwndListview, clrWindow);
  436. if (clrTextBk != ListView_GetTextBkColor(_hwndListview))
  437. bChange = ListView_SetTextBkColor(_hwndListview, clrTextBk);
  438. if (clrText != ListView_GetTextColor(_hwndListview))
  439. bChange = ListView_SetTextColor(_hwndListview, clrText);
  440. if (bChange)
  441. InvalidateRect(_hwndListview, NULL, TRUE);
  442. }
  443. UINT CDefView::_UxGetView()
  444. {
  445. UINT uView = LV_VIEW_ICON;
  446. if (!_IsDesktop())
  447. {
  448. switch (_fs.ViewMode)
  449. {
  450. case FVM_LIST:
  451. uView = LV_VIEW_LIST;
  452. break;
  453. case FVM_DETAILS:
  454. uView = LV_VIEW_DETAILS;
  455. break;
  456. case FVM_SMALLICON:
  457. case FVM_THUMBNAIL:
  458. case FVM_THUMBSTRIP:
  459. case FVM_ICON:
  460. uView = LV_VIEW_ICON;
  461. break;
  462. case FVM_TILE:
  463. uView = LV_VIEW_TILE;
  464. break;
  465. default:
  466. TraceMsg(TF_WARNING, "Unknown ViewMode value");
  467. break;
  468. }
  469. }
  470. return uView;
  471. }
  472. #define ViewRequiresColumns(x) ((x) == FVM_DETAILS || (x) == FVM_TILE)
  473. DWORD CDefView::_LVStyleFromView()
  474. {
  475. DWORD dwStyle;
  476. if (_IsDesktop())
  477. {
  478. dwStyle = LVS_NOSCROLL | LVS_ALIGNLEFT;
  479. }
  480. else
  481. {
  482. dwStyle = LVS_SHOWSELALWAYS; // make sure selection is visible
  483. }
  484. // dwStyle |= _UxGetView();
  485. // The listview view is no longer set using the window style, so the call to the
  486. // view mapping code has been commented out.
  487. // APPCOMPAT: This may be an issue, if apps are depending the exstyle bits on the listview hwnd
  488. // in defview. If so, we can set them, but we must take care to exclude any bits outside the 2bit
  489. // "view range" in the extended style (namely, tile view)
  490. if (_IsAutoArrange())
  491. dwStyle |= LVS_AUTOARRANGE;
  492. if (_fs.fFlags & FWF_SINGLESEL)
  493. dwStyle |= LVS_SINGLESEL;
  494. if (_fs.fFlags & FWF_ALIGNLEFT)
  495. dwStyle |= LVS_ALIGNLEFT;
  496. if (_fs.fFlags & FWF_NOSCROLL)
  497. dwStyle |= LVS_NOSCROLL;
  498. return dwStyle;
  499. }
  500. DWORD CDefView::_LVExStyleFromView()
  501. {
  502. DWORD dwLVExStyle = 0;
  503. if (_fs.fFlags & FWF_SNAPTOGRID)
  504. dwLVExStyle |= LVS_EX_SNAPTOGRID;
  505. if (_fs.fFlags & FWF_CHECKSELECT)
  506. dwLVExStyle |= LVS_EX_CHECKBOXES|LVS_EX_SIMPLESELECT;
  507. return dwLVExStyle;
  508. }
  509. HRESULT CDefView::_GetDetailsHelper(int i, DETAILSINFO *pdi)
  510. {
  511. HRESULT hr = E_NOTIMPL;
  512. if (_pshf2)
  513. {
  514. hr = _pshf2->GetDetailsOf(pdi->pidl, i, (SHELLDETAILS *)&pdi->fmt);
  515. }
  516. if (FAILED(hr)) // Don't make NSEs impl all of IShellFolder2
  517. {
  518. if (_psd)
  519. {
  520. // HACK: pdi->fmt is the same layout as SHELLDETAILS
  521. hr = _psd->GetDetailsOf(pdi->pidl, i, (SHELLDETAILS *)&pdi->fmt);
  522. }
  523. else if (HasCB())
  524. {
  525. hr = CallCB(SFVM_GETDETAILSOF, i, (LPARAM)pdi);
  526. }
  527. }
  528. return hr;
  529. }
  530. // Determine if the given defview state struct has valid
  531. // state info. If is doesn't, this function massages the
  532. // values so it does.
  533. UINT CDefView::_GetHeaderCount()
  534. {
  535. UINT cCols = 0;
  536. HWND hwndHead = ListView_GetHeader(_hwndListview);
  537. if (hwndHead)
  538. {
  539. cCols = Header_GetItemCount(hwndHead);
  540. }
  541. return cCols;
  542. }
  543. void CDefView::AddColumns()
  544. {
  545. // so we do this once
  546. if (_bLoadedColumns)
  547. return;
  548. _bLoadedColumns = TRUE;
  549. // I also use this as a flag for whether to free pColHdr
  550. //
  551. // Calculate a reasonable size to initialize the column width to.
  552. _cxChar = GetControlCharWidth(_hwndListview);
  553. // Check whether there is any column enumerator (ShellDetails or callback)
  554. if (_psd || _pshf2 || HasCB())
  555. {
  556. // Some shell extensions return S_OK and NULL pstmCols.
  557. IStream *pstmCols = NULL;
  558. if (SUCCEEDED(CallCB(SFVM_GETCOLSAVESTREAM, STGM_READ, (LPARAM)&pstmCols)) && pstmCols)
  559. {
  560. _vs.LoadColumns(this, pstmCols);
  561. pstmCols->Release();
  562. }
  563. // Verify that this has been initialized. This may not be if there was no state stream.
  564. _vs.InitializeColumns(this);
  565. for (UINT i = 0; i < _vs.GetColumnCount(); ++i)
  566. {
  567. if (_IsColumnInListView(i))
  568. {
  569. UINT iVisible = _RealToVisibleCol(i);
  570. LV_COLUMN col;
  571. col.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  572. col.fmt = _vs.GetColumnFormat(i);
  573. // If column width is not specified in the desktop.ini.......
  574. col.cx = _vs.GetColumnWidth(iVisible, _vs.GetColumnCharCount(i) * _cxChar);
  575. col.pszText = _vs.GetColumnName(i);
  576. col.cchTextMax = MAX_COLUMN_NAME_LEN;
  577. col.iSubItem = i;
  578. if (col.fmt & LVCFMT_COL_HAS_IMAGES)
  579. {
  580. ListView_SetExtendedListViewStyleEx(_hwndListview, LVS_EX_SUBITEMIMAGES, LVS_EX_SUBITEMIMAGES);
  581. col.fmt &= ~LVCFMT_COL_HAS_IMAGES;
  582. }
  583. ListView_InsertColumn(_hwndListview, iVisible, &col);
  584. }
  585. }
  586. // Set the header control to have zero margin around bitmaps, for the sort arrows
  587. Header_SetBitmapMargin(ListView_GetHeader(_hwndListview), 0);
  588. ListView_SetExtendedListViewStyleEx(_hwndListview,
  589. LVS_EX_HEADERDRAGDROP | LVS_EX_LABELTIP,
  590. LVS_EX_HEADERDRAGDROP | LVS_EX_LABELTIP);
  591. //We added columns; so, just sync the Column order.
  592. _vs.SyncColumnOrder(this, TRUE);
  593. }
  594. // use real numbers, not visible
  595. int cCols = (int)_vs.GetColumnCount();
  596. if (_vs._iLastColumnClick >= cCols)
  597. {
  598. _vs.InitWithDefaults(this);
  599. if (_vs._iLastColumnClick >= cCols ||
  600. _vs._lParamSort >= cCols)
  601. {
  602. // our defaults won't work on this view....
  603. // hard code these defaults
  604. _vs._lParamSort = 0;
  605. _vs._iDirection = 1;
  606. _vs._iLastColumnClick = -1;
  607. }
  608. }
  609. }
  610. void CDefView::InitSelectionMode()
  611. {
  612. _dwSelectionMode = 0;
  613. if (_fs.fFlags & FWF_SINGLECLICKACTIVATE)
  614. {
  615. _dwSelectionMode = LVS_EX_TRACKSELECT | LVS_EX_ONECLICKACTIVATE;
  616. }
  617. else if (!_fClassic)
  618. {
  619. SHELLSTATE ss;
  620. SHGetSetSettings(&ss, SSF_DOUBLECLICKINWEBVIEW, FALSE);
  621. if (!ss.fDoubleClickInWebView)
  622. _dwSelectionMode = LVS_EX_TRACKSELECT | LVS_EX_ONECLICKACTIVATE;
  623. }
  624. }
  625. void CDefView::_UpdateSelectionMode()
  626. {
  627. InitSelectionMode();
  628. ListView_SetExtendedListViewStyleEx(_hwndListview, LVS_EX_TRACKSELECT | LVS_EX_ONECLICKACTIVATE | LVS_EX_TWOCLICKACTIVATE, _dwSelectionMode);
  629. }
  630. DWORD _GetUnderlineStyles()
  631. {
  632. DWORD dwUnderline = ICON_IE;
  633. // Read the icon underline settings.
  634. DWORD cb = sizeof(dwUnderline);
  635. SHRegGetUSValue(TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"),
  636. TEXT("IconUnderline"), NULL, &dwUnderline, &cb, FALSE, &dwUnderline, cb);
  637. // If it says to use the IE link settings, read them in.
  638. if (dwUnderline == ICON_IE)
  639. {
  640. dwUnderline = ICON_YES;
  641. TCHAR szUnderline[8];
  642. cb = sizeof(szUnderline);
  643. SHRegGetUSValue(TEXT("Software\\Microsoft\\Internet Explorer\\Main"),
  644. TEXT("Anchor Underline"), NULL, szUnderline, &cb, FALSE, szUnderline, cb);
  645. // Convert the string to an ICON_ value.
  646. if (!lstrcmpi(szUnderline, TEXT("hover")))
  647. dwUnderline = ICON_HOVER;
  648. else if (!lstrcmpi(szUnderline, TEXT("no")))
  649. dwUnderline = ICON_NO;
  650. else
  651. dwUnderline = ICON_YES;
  652. }
  653. // Convert the ICON_ value into an LVS_EX value.
  654. DWORD dwExStyle;
  655. switch (dwUnderline)
  656. {
  657. case ICON_NO:
  658. dwExStyle = 0;
  659. break;
  660. case ICON_HOVER:
  661. dwExStyle = LVS_EX_UNDERLINEHOT;
  662. break;
  663. case ICON_YES:
  664. dwExStyle = LVS_EX_UNDERLINEHOT | LVS_EX_UNDERLINECOLD;
  665. break;
  666. }
  667. return dwExStyle;
  668. }
  669. void CDefView::_UpdateUnderlines()
  670. {
  671. // Set the new LVS_EX_UNDERLINE flags.
  672. ListView_SetExtendedListViewStyleEx(_hwndListview, LVS_EX_UNDERLINEHOT | LVS_EX_UNDERLINECOLD, _GetUnderlineStyles());
  673. }
  674. void CDefView::_SetSysImageList()
  675. {
  676. HIMAGELIST himlLarge, himlSmall;
  677. Shell_GetImageLists(&himlLarge, &himlSmall);
  678. ListView_SetImageList(_hwndListview, himlLarge, LVSIL_NORMAL);
  679. ListView_SetImageList(_hwndListview, himlSmall, LVSIL_SMALL);
  680. }
  681. void CDefView::_SetTileview()
  682. {
  683. IImageList* piml;
  684. if (SUCCEEDED(SHGetImageList(SHIL_EXTRALARGE, IID_PPV_ARG(IImageList, &piml))))
  685. {
  686. ListView_SetImageList(_hwndListview, IImageListToHIMAGELIST(piml), LVSIL_NORMAL);
  687. piml->Release();
  688. }
  689. }
  690. BOOL CDefView::_IsUsingFullIconSelection()
  691. {
  692. // This is a temporary method of turning on the new selection style.
  693. // We will enable this via Folder Options when the Touzts determines the string to use.
  694. BOOL fUseNewSelectionStyle = FALSE;
  695. SystemParametersInfo(SPI_GETFLATMENU, 0, (void *)&fUseNewSelectionStyle, 0);
  696. return fUseNewSelectionStyle;
  697. }
  698. LRESULT CDefView::_OnCreate(HWND hWnd)
  699. {
  700. _hwndView = hWnd;
  701. _hmenuCur = NULL;
  702. _uState = SVUIA_DEACTIVATE;
  703. _hAccel = LoadAccelerators(HINST_THISDLL, MAKEINTRESOURCE(ACCEL_DEFVIEW));
  704. // Note that we are going to get a WM_SIZE message soon, which will
  705. // place this window correctly
  706. // Map the ViewMode to the proper listview style
  707. DWORD dwStyle = _LVStyleFromView() | LVS_EDITLABELS;
  708. DWORD dwExStyle = 0;
  709. // If the parent window is mirrored then the treeview window will inheret the mirroring flag
  710. // And we need the reading order to be Left to right, which is the right to left in the mirrored mode.
  711. if (IS_WINDOW_RTL_MIRRORED(hWnd))
  712. {
  713. // This means left to right reading order because this window will be mirrored.
  714. dwExStyle |= WS_EX_RTLREADING;
  715. }
  716. // don't set this as in webview this is normally off, having this
  717. // set causes a 3d edge to flash on in a refresh
  718. if (!_ShouldShowWebView() && !_IsDesktop() && !(_fs.fFlags & FWF_NOCLIENTEDGE))
  719. {
  720. dwExStyle |= WS_EX_CLIENTEDGE;
  721. }
  722. if (_IsOwnerData())
  723. dwStyle |= LVS_OWNERDATA;
  724. _hwndListview = CreateWindowEx(dwExStyle, WC_LISTVIEW, TEXT("FolderView"), // MSAA name
  725. dwStyle | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | LVS_SHAREIMAGELISTS,
  726. 0, 0, 0, 0, hWnd, (HMENU)ID_LISTVIEW, HINST_THISDLL, NULL);
  727. if (_hwndListview)
  728. {
  729. // Set up non-viewmode-dependant listview information here.
  730. // Other flags are set up in _SwitchToViewFVM
  731. DWORD dwLVExStyle = _LVExStyleFromView() | LVS_EX_INFOTIP | LVS_EX_LABELTIP;
  732. if (_IsDesktop())
  733. {
  734. if (GetNumberOfMonitors() > 1)
  735. dwLVExStyle |= LVS_EX_MULTIWORKAREAS;
  736. }
  737. else
  738. {
  739. dwLVExStyle |= LVS_EX_DOUBLEBUFFER; // Enable double buffering for all but desktop for affects
  740. }
  741. // turn on infotips -- window was just created, so all LVS_EX bits are off
  742. ListView_SetExtendedListViewStyle(_hwndListview, dwLVExStyle);
  743. // Get the proper RTL bits to pass on to our child windows
  744. _fmt = 0;
  745. // Be sure that the OS is supporting the flags DATE_LTRREADING and DATE_RTLREADING
  746. if (g_bBiDiPlatform)
  747. {
  748. // Get the date format reading order
  749. LCID locale = GetUserDefaultLCID();
  750. if ((PRIMARYLANGID(LANGIDFROMLCID(locale)) == LANG_ARABIC))
  751. {
  752. // Get the real list view windows ExStyle.
  753. // [msadek]; we shouldn't check for either WS_EX_RTLREADING OR RTL_MIRRORED_WINDOW
  754. // on localized builds we have both of them to display dirve letters,..etc correctly
  755. // on enabled builds we have none of them. let's check on RTL_MIRRORED_WINDOW only
  756. if (GetWindowLong(_hwndListview, GWL_EXSTYLE) & RTL_MIRRORED_WINDOW)
  757. _fmt = LVCFMT_RIGHT_TO_LEFT;
  758. else
  759. _fmt = LVCFMT_LEFT_TO_RIGHT;
  760. }
  761. }
  762. // Get hwndInfotip (the control for all listview infotips).
  763. HWND hwndInfotip = ListView_GetToolTips(_hwndListview);
  764. if (hwndInfotip)
  765. {
  766. // make the tooltip window to be topmost window (set the TTS_TOPMOST style bit for the tooltip)
  767. SetWindowPos(hwndInfotip, HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  768. // Initialize hwndInfotip.
  769. _InitInfotipControl(hwndInfotip);
  770. }
  771. _UpdateUnderlines();
  772. // IShellDetails for old callers, new guys use IShellFolder2
  773. ASSERT(_psd == NULL);
  774. _pshf->CreateViewObject(_hwndMain, IID_PPV_ARG(IShellDetails, &_psd));
  775. // App compat - some apps need columns loaded first thing
  776. if (SHGetAppCompatFlags(ACF_LOADCOLUMNHANDLER) & ACF_LOADCOLUMNHANDLER)
  777. {
  778. AddColumns();
  779. }
  780. _SetFolderColors();
  781. }
  782. // Create _hwndInfotip (the control for all non-listview infotips).
  783. _hwndInfotip = _CreateInfotipControl(hWnd);
  784. if (_hwndInfotip)
  785. {
  786. // Initialize _hwndInfotip.
  787. _InitInfotipControl(_hwndInfotip);
  788. }
  789. return _hwndListview ? 0 : -1; // 0 is success, -1 is failure from WM_CREATE
  790. }
  791. HWND CDefView::_CreateInfotipControl(HWND hwndParent)
  792. {
  793. // hwndInfotip is currently expected to be destroyed by destruction of
  794. // the parent hwnd (hwndParent). Thus, hwndParent should not be NULL.
  795. ASSERT(hwndParent != NULL); // Sanity check.
  796. // Create hwndInfotip.
  797. return ::CreateWindowEx(
  798. IS_WINDOW_RTL_MIRRORED(hwndParent) || IS_BIDI_LOCALIZED_SYSTEM()
  799. ? WS_EX_LAYOUTRTL
  800. : 0,
  801. TOOLTIPS_CLASS,
  802. NULL,
  803. 0,
  804. CW_USEDEFAULT,
  805. CW_USEDEFAULT,
  806. CW_USEDEFAULT,
  807. CW_USEDEFAULT,
  808. hwndParent,
  809. NULL,
  810. g_hinst,
  811. NULL);
  812. }
  813. void CDefView::_InitInfotipControl(HWND hwndInfotip)
  814. {
  815. ASSERT(hwndInfotip);
  816. // Set the length of time the pointer must remain stationary within a tool's
  817. // bounding rectangle before the ToolTip window appears to 2 times the default.
  818. INT iTime = ::SendMessage(hwndInfotip, TTM_GETDELAYTIME, TTDT_INITIAL, 0);
  819. ::SendMessage(hwndInfotip, TTM_SETDELAYTIME, TTDT_INITIAL, (LPARAM)(INT)MAKELONG(iTime * 2, 0));
  820. // Set the length of time a ToolTip window remains visible if the pointer
  821. // is stationary within a tool's bounding rectangle to a very large value.
  822. ::SendMessage(hwndInfotip, TTM_SETDELAYTIME, TTDT_AUTOPOP, (LPARAM)(INT)MAKELONG(MAXSHORT, 0));
  823. }
  824. // "Auto" AutoArrange means re-position if we are in a positioned view
  825. // and the listview is not in auto-arrange mode. we do this to re-layout
  826. // the icons in cases where that makes sense
  827. HRESULT CDefView::_AutoAutoArrange(DWORD dwReserved)
  828. {
  829. if (!_fUserPositionedItems && _IsPositionedView() &&
  830. !(GetWindowStyle(_hwndListview) & LVS_AUTOARRANGE))
  831. {
  832. ListView_Arrange(_hwndListview, LVA_DEFAULT);
  833. }
  834. return S_OK;
  835. }
  836. LRESULT CDefView::WndSize(HWND hWnd)
  837. {
  838. RECT rc;
  839. // We need to dismiss "name edit" mode, if we are in.
  840. _DismissEdit();
  841. // Get the client size.
  842. GetClientRect(hWnd, &rc);
  843. // Set the Static to be the Client size.
  844. if (_hwndStatic)
  845. {
  846. MoveWindow(_hwndStatic, rc.left, rc.top,
  847. rc.right-rc.left, rc.bottom-rc.top, TRUE);
  848. HWND hAnimate = ::GetWindow (_hwndStatic, GW_CHILD);
  849. if (hAnimate)
  850. {
  851. MoveWindow(hAnimate, rc.left, rc.top,
  852. rc.right-rc.left, rc.bottom-rc.top, TRUE);
  853. }
  854. RedrawWindow(_hwndStatic, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN);
  855. }
  856. // Set all windows to their new rectangles.
  857. _cFrame.SetRect(&rc);
  858. // Don't resize _hwndListview if a DefViewOC is using it.
  859. //
  860. // If we're waiting for a Web View (!_fCanActivateNow), then it
  861. // doesn't make sense to resize the _hwndListview -- just extra
  862. // work, right? But in the non-WebView case, it's this first
  863. // resize which sets the listview size, and then there are no
  864. // more. Unfortunately, the first resize comes in when the
  865. // _hwndListview is created, which is *before* _fCanActivateNow
  866. // can possibly be set.
  867. if (!_fGetWindowLV && !_pDUIView)
  868. {
  869. SetWindowPos(_hwndListview, NULL, rc.left, rc.top,
  870. rc.right - rc.left, rc.bottom - rc.top, SWP_NOZORDER | SWP_NOACTIVATE);
  871. OnResizeListView();
  872. }
  873. if (_pDUIView)
  874. {
  875. _pDUIView->SetSize (&rc);
  876. _AutoAutoArrange(0);
  877. }
  878. CallCB(SFVM_SIZE, 0, 0);
  879. return 1;
  880. }
  881. UINT _GetMenuIDFromViewMode(UINT uViewMode)
  882. {
  883. ASSERTMSG(FVM_FIRST <= uViewMode && uViewMode <= FVM_LAST, "_GetMenuIDFromViewMode received unknown uViewMode");
  884. return SFVIDM_VIEW_FIRSTVIEW + uViewMode - FVM_FIRST;
  885. }
  886. void CDefView::CheckToolbar()
  887. {
  888. if (SHGetAppCompatFlags(ACF_WIN95DEFVIEW) & ACF_WIN95DEFVIEW)
  889. {
  890. int idCmdCurView = _GetMenuIDFromViewMode(_fs.ViewMode);
  891. // preserve win95 behavior for dumb corel apps
  892. for (int idCmd = SFVIDM_VIEW_ICON; idCmd <= SFVIDM_VIEW_DETAILS; idCmd++)
  893. {
  894. _psb->SendControlMsg(
  895. FCW_TOOLBAR, TB_CHECKBUTTON, idCmd, (LPARAM)(idCmd == idCmdCurView), NULL);
  896. }
  897. }
  898. }
  899. void CDefView::OnListViewDelete(int iItem, LPITEMIDLIST pidlToFree, BOOL fCallCB)
  900. {
  901. LPCITEMIDLIST pidlReal = _GetPIDLParam((LPARAM)pidlToFree, iItem);
  902. if (fCallCB)
  903. {
  904. CallCB(SFVM_DELETEITEM, 0, (LPARAM)pidlReal);
  905. }
  906. ILFree(pidlToFree); // NULL in owner data case
  907. }
  908. // NOTE: many keys are handled as accelerators
  909. void CDefView::HandleKeyDown(LV_KEYDOWN *pnmhdr)
  910. {
  911. // REVIEW: these are things not handled by accelerators, see if we can
  912. // make them all based on accelerators
  913. switch (pnmhdr->wVKey)
  914. {
  915. case VK_ESCAPE:
  916. if (_bHaveCutStuff)
  917. OleSetClipboard(NULL);
  918. break;
  919. }
  920. }
  921. // This function checks to see if we are in virtual mode or not. If we are in
  922. // virtual mode, we always need to ask our folder we are viewing for the item and
  923. // not the listview.
  924. LPCITEMIDLIST CDefView::_GetPIDL(int i)
  925. {
  926. if (_IsOwnerData())
  927. {
  928. LPCITEMIDLIST pidl = NULL;
  929. CallCB(SFVM_GETITEMIDLIST, i, (LPARAM)&pidl);
  930. return pidl;
  931. }
  932. return (LPCITEMIDLIST)LVUtil_GetLParam(_hwndListview, i);
  933. }
  934. LPCITEMIDLIST CDefView::_GetPIDLParam(LPARAM lParam, int i)
  935. {
  936. return lParam ? (LPCITEMIDLIST)lParam : _GetPIDL(i);
  937. }
  938. // returns an array of LPCITEMIDLIST for objects in the view (selected or all)
  939. // the "focused" item is always in array entry 0. this array contains poitners to pidls
  940. // owned stored in the listview, so YOU SHOULD NOT FREE THEM OR MESS WITH THEM IN ANYWAY.
  941. // this also implies the lifetime of this array must be shorter than the listview
  942. // data it points to. that is if the view changes under you you are hosed.
  943. //
  944. // Notes: this function returns LP*C*ITEMIDLIST. The caller is not
  945. // supposed alter or delete them. Their lifetime are very short (until the
  946. // list view is modified).
  947. typedef struct
  948. {
  949. LPCITEMIDLIST pidl;
  950. POINT pt;
  951. int iItem;
  952. } POS_SORT_INFO;
  953. // standard compare returns
  954. // -1 1 < 2
  955. // 0 1 = 2
  956. // 1 1 > 2
  957. //
  958. // NOTE: in the RTL_MIRRORED_WINDOW case the coords are reversed for us
  959. int _CmpTopToBottomLeftToRight(POS_SORT_INFO *psi1, POS_SORT_INFO *psi2, LPARAM lParam)
  960. {
  961. int iCmp = psi1->pt.y - psi2->pt.y;
  962. if (0 == iCmp)
  963. {
  964. iCmp = psi1->pt.x - psi2->pt.x;
  965. }
  966. return iCmp;
  967. }
  968. int _CmpLeftToRightTopToBottom(POS_SORT_INFO *psi1, POS_SORT_INFO *psi2, LPARAM lParam)
  969. {
  970. int iCmp = psi1->pt.x - psi2->pt.x;
  971. if (0 == iCmp)
  972. {
  973. iCmp = psi1->pt.y - psi2->pt.y;
  974. }
  975. return iCmp;
  976. }
  977. CDPA<POS_SORT_INFO>::_PFNDPACOMPARE _GetSortFunction(HWND hwndListview)
  978. {
  979. if (GetWindowStyle(hwndListview) & LVS_ALIGNLEFT)
  980. {
  981. return _CmpLeftToRightTopToBottom; // desktop LV_VIEW_ICON case
  982. }
  983. else
  984. {
  985. UINT uViewMode = ListView_GetView(hwndListview);
  986. switch (uViewMode)
  987. {
  988. case LV_VIEW_DETAILS:
  989. case LV_VIEW_LIST:
  990. return _CmpLeftToRightTopToBottom;
  991. case LV_VIEW_TILE:
  992. case LV_VIEW_ICON:
  993. default:
  994. return _CmpTopToBottomLeftToRight;
  995. }
  996. }
  997. }
  998. UINT CDefView::_GetItemArray(LPCITEMIDLIST apidl[], UINT capidl, UINT uWhat)
  999. {
  1000. UINT cItems = 0;
  1001. if ((uWhat & SVGIO_TYPE_MASK) == SVGIO_SELECTION)
  1002. {
  1003. cItems = ListView_GetSelectedCount(_hwndListview);
  1004. }
  1005. else if ((uWhat & SVGIO_TYPE_MASK) == SVGIO_CHECKED)
  1006. {
  1007. int iItem = ListView_GetItemCount(_hwndListview) - 1;
  1008. for (; iItem >= 0; iItem--)
  1009. {
  1010. if (ListView_GetCheckState(_hwndListview, iItem))
  1011. cItems++;
  1012. }
  1013. }
  1014. else
  1015. {
  1016. cItems = ListView_GetItemCount(_hwndListview);
  1017. }
  1018. if (apidl)
  1019. {
  1020. UINT uType = (SVGIO_SELECTION == (uWhat & SVGIO_TYPE_MASK)) ? LVNI_SELECTED : LVNI_ALL;
  1021. BOOL bArrayFilled = FALSE; // gets set on success of the sort code path
  1022. // optimize the 1 case, the sort below is not needed
  1023. if (!(SVGIO_FLAG_VIEWORDER & uWhat) && (capidl > 1))
  1024. {
  1025. CDPA<POS_SORT_INFO> dpaItemInfo;
  1026. // pick a grow size of capidl so that we get a single alloc
  1027. // when we add the first item to the array
  1028. if (dpaItemInfo.Create(capidl))
  1029. {
  1030. POS_SORT_INFO *ppsi = new POS_SORT_INFO[capidl];
  1031. if (ppsi)
  1032. {
  1033. int iDPAIndex = 0;
  1034. for (int iListView = ListView_GetNextItem(_hwndListview, -1, uType);
  1035. iListView >= 0;
  1036. iListView = ListView_GetNextItem(_hwndListview, iListView, uType))
  1037. {
  1038. // if we want checked then it must be checked, otherwise just return (or skip)
  1039. if ((SVGIO_CHECKED != (uWhat & SVGIO_TYPE_MASK)) || ListView_GetCheckState(_hwndListview, iListView))
  1040. {
  1041. ppsi[iDPAIndex].pidl = _GetPIDL(iListView);
  1042. ppsi[iDPAIndex].iItem = iListView;
  1043. ListView_GetItemPosition(_hwndListview, iListView, &ppsi[iDPAIndex].pt);
  1044. // this may fail, but we catch that case below
  1045. dpaItemInfo.SetPtr(iDPAIndex, &ppsi[iDPAIndex]);
  1046. iDPAIndex++;
  1047. }
  1048. }
  1049. // make sure the DPA got all of the items, if not
  1050. // we fall through to the unsorted case
  1051. if (dpaItemInfo.GetPtrCount() == capidl)
  1052. {
  1053. dpaItemInfo.Sort(_GetSortFunction(_hwndListview), 0);
  1054. int iFirstItem = ListView_GetNextItem(_hwndListview, -1, LVNI_FOCUSED);
  1055. // compute the start index in the dpa based on iFirstItem. this is to
  1056. // rotate the array so that iFirstItem is first in the list
  1057. for (iDPAIndex = 0; iDPAIndex < dpaItemInfo.GetPtrCount(); iDPAIndex++)
  1058. {
  1059. if (dpaItemInfo.FastGetPtr(iDPAIndex)->iItem == iFirstItem)
  1060. {
  1061. break; // iDPAIndex setup for loop below
  1062. }
  1063. }
  1064. for (int i = 0; i < dpaItemInfo.GetPtrCount(); i++, iDPAIndex++)
  1065. {
  1066. if (iDPAIndex >= dpaItemInfo.GetPtrCount())
  1067. iDPAIndex = 0; // wrap back to zero
  1068. apidl[i] = dpaItemInfo.FastGetPtr(iDPAIndex)->pidl;
  1069. }
  1070. bArrayFilled = TRUE; // we have the results we want
  1071. delete [] ppsi;
  1072. }
  1073. }
  1074. dpaItemInfo.Destroy();
  1075. }
  1076. }
  1077. if (!bArrayFilled)
  1078. {
  1079. for (int i = 0, iListView = ListView_GetNextItem(_hwndListview, -1, uType);
  1080. iListView >= 0;
  1081. iListView = ListView_GetNextItem(_hwndListview, iListView, uType))
  1082. {
  1083. // if we want checked then it must be checked, otherwise just return (or skip)
  1084. if ((SVGIO_CHECKED != (uWhat & SVGIO_TYPE_MASK)) || ListView_GetCheckState(_hwndListview, iListView))
  1085. {
  1086. apidl[i++] = _GetPIDL(iListView);
  1087. }
  1088. }
  1089. }
  1090. }
  1091. return cItems;
  1092. }
  1093. //
  1094. // get the array of IDList from the selection and calls
  1095. // IShellFolder::GetUIObjectOf member to get the specified UI object
  1096. // interface.
  1097. //
  1098. HRESULT CDefView::_GetUIObjectFromItem(REFIID riid, void **ppv, UINT uWhat, BOOL fSetPoints)
  1099. {
  1100. LPCITEMIDLIST *apidl;
  1101. UINT cItems;
  1102. HRESULT hr;
  1103. if (SVGIO_SELECTION == (uWhat & SVGIO_TYPE_MASK))
  1104. {
  1105. hr = GetSelectedObjects(&apidl, &cItems);
  1106. }
  1107. else
  1108. {
  1109. hr = _GetItemObjects(&apidl, uWhat, &cItems);
  1110. }
  1111. if (SUCCEEDED(hr))
  1112. {
  1113. if (cItems)
  1114. {
  1115. hr = _pshf->GetUIObjectOf(_hwndMain, cItems, apidl, riid, 0, ppv);
  1116. if (SUCCEEDED(hr) && (IID_IDataObject == riid) && fSetPoints)
  1117. {
  1118. _SetPoints(cItems, apidl, (IDataObject *)*ppv);
  1119. }
  1120. LocalFree((HLOCAL)apidl);
  1121. }
  1122. else
  1123. hr = E_INVALIDARG;
  1124. }
  1125. return hr;
  1126. }
  1127. // If the browser has a Tree then we want to use explore.
  1128. UINT CDefView::_GetExplorerFlag()
  1129. {
  1130. return IsExplorerBrowser(_psb) ? CMF_EXPLORE : 0;
  1131. }
  1132. // creates a selection object out of the current selection.
  1133. IShellItemArray* CDefView::_CreateSelectionShellItemArray(void)
  1134. {
  1135. IShellItemArray *pSelectionObj = NULL;
  1136. LPCITEMIDLIST *apidl;
  1137. UINT cItems;
  1138. if (SUCCEEDED(_GetItemObjects(&apidl, SVGIO_SELECTION | SVGIO_FLAG_VIEWORDER, &cItems)) && cItems)
  1139. {
  1140. SHCreateShellItemArray(NULL, _pshf, cItems, apidl, &pSelectionObj);
  1141. LocalFree(apidl);
  1142. }
  1143. return pSelectionObj;
  1144. }
  1145. DWORD CDefView::_AttributesFromSel(DWORD dwAttributesNeeded)
  1146. {
  1147. // If this gets hit then chances are it's a performance problem...
  1148. //
  1149. if (_fSelectionChangePending)
  1150. {
  1151. TraceMsg(TF_WARNING, "Potential perf badness: may be asking for attributes during OnLVNUpdateItem!");
  1152. if (_pSelectionShellItemArray)
  1153. ATOMICRELEASE(_pSelectionShellItemArray);
  1154. _pSelectionShellItemArray = _CreateSelectionShellItemArray();
  1155. }
  1156. DWORD dwAttributes = 0;
  1157. if (_pSelectionShellItemArray)
  1158. {
  1159. _pSelectionShellItemArray->GetAttributes(SIATTRIBFLAGS_APPCOMPAT, dwAttributesNeeded, &dwAttributes);
  1160. }
  1161. return dwAttributes;
  1162. }
  1163. // IContextMenuSite:
  1164. // Defview's context menu implementation isn't very clean. As a temporary step towards
  1165. // cleaning it up (CONTEXT and BACK_CONTEXT are intermingled), use the new DOCONTEXTMENUPOPUP range
  1166. //
  1167. HRESULT CDefView::DoContextMenuPopup(IUnknown* punkCM, UINT fFlags, POINT pt)
  1168. {
  1169. return _DoContextMenuPopup(punkCM, fFlags, pt, FALSE);
  1170. }
  1171. HRESULT CDefView::_DoContextMenuPopup(IUnknown* punk, UINT fFlags, POINT pt, BOOL fListviewItem)
  1172. {
  1173. IContextMenu* pcm;
  1174. HRESULT hr = punk->QueryInterface(IID_PPV_ARG(IContextMenu, &pcm));
  1175. if (SUCCEEDED(hr))
  1176. {
  1177. hr = E_OUTOFMEMORY;
  1178. HMENU hmContext = CreatePopupMenu();
  1179. if (hmContext)
  1180. {
  1181. fFlags |= _GetExplorerFlag();
  1182. if (0 > GetKeyState(VK_SHIFT))
  1183. fFlags |= CMF_EXTENDEDVERBS;
  1184. IContextMenu3* pcm3;
  1185. if (SUCCEEDED(pcm->QueryInterface(IID_PPV_ARG(IContextMenu3, &pcm3))))
  1186. {
  1187. fFlags |= CMF_ICM3;
  1188. pcm3->Release();
  1189. }
  1190. // Give the context menu a site if it doesn't have one already
  1191. IUnknown* punkSite;
  1192. if (SUCCEEDED(IUnknown_GetSite(pcm, IID_PPV_ARG(IUnknown, &punkSite))))
  1193. {
  1194. punkSite->Release();
  1195. }
  1196. else
  1197. {
  1198. IUnknown_SetSite(pcm, SAFECAST(this, IShellView2*));
  1199. }
  1200. hr = pcm->QueryContextMenu(hmContext, 0, SFVIDM_BACK_CONTEXT_FIRST, SFVIDM_BACK_CONTEXT_LAST, fFlags);
  1201. if (SUCCEEDED(hr))
  1202. {
  1203. // Must preinitialize to NULL; Adaptec Easy CD Creator 3.5 does not
  1204. // null out the pointer on failure.
  1205. ICommDlgBrowser2 *pcdb2 = NULL;
  1206. _psb->QueryInterface(IID_PPV_ARG(ICommDlgBrowser2, &pcdb2));
  1207. // If this is the common dialog browser, we need to make the
  1208. // default command "Select" so that double-clicking (which is
  1209. // open in common dialog) makes sense.
  1210. if (_IsCommonDialog())
  1211. {
  1212. // make sure this is an item
  1213. if (fListviewItem)
  1214. {
  1215. HMENU hmSelect = SHLoadPopupMenu(HINST_THISDLL, POPUP_COMMDLG_POPUPMERGE);
  1216. // If we have a pointer to the ICommDlgBrowser2 interface
  1217. // query if this interface wants to change the text of the
  1218. // default verb. This interface is needed in the common print
  1219. // dialog to change the default text from 'Select' to 'Print'.
  1220. if (pcdb2)
  1221. {
  1222. WCHAR szTextW[MAX_PATH] = {0};
  1223. if (pcdb2->GetDefaultMenuText(this, szTextW, ARRAYSIZE(szTextW)) == S_OK)
  1224. {
  1225. MENUITEMINFO mi = {0};
  1226. mi.cbSize = sizeof(mi);
  1227. mi.fMask = MIIM_TYPE;
  1228. mi.fType = MFT_STRING;
  1229. mi.dwTypeData = szTextW;
  1230. SetMenuItemInfo(hmSelect, 0, MF_BYPOSITION, &mi);
  1231. }
  1232. }
  1233. // NOTE: Since commdlg always eats the default command,
  1234. // we don't care what id we assign hmSelect, as long as it
  1235. // doesn't conflict with any other context menu id.
  1236. // SFVIDM_CONTEXT_FIRST-1 won't conflict with anyone.
  1237. Shell_MergeMenus(hmContext, hmSelect, 0,
  1238. (UINT)(SFVIDM_BACK_CONTEXT_FIRST-1), (UINT)-1,
  1239. MM_ADDSEPARATOR);
  1240. SetMenuDefaultItem(hmContext, 0, MF_BYPOSITION);
  1241. DestroyMenu(hmSelect);
  1242. }
  1243. }
  1244. _SHPrettyMenu(hmContext);
  1245. // If this is the common dialog browser 2, we need inform it
  1246. // the context menu is has started. This notifiction is use in
  1247. // the common print dialog on NT which hosts the printers folder.
  1248. // Common dialog want to relselect the printer object if the user
  1249. // selected the context menu from the background.
  1250. if (pcdb2)
  1251. {
  1252. pcdb2->Notify(this, CDB2N_CONTEXTMENU_START);
  1253. }
  1254. // To reduce some menu message forwarding, throw away _pcmFile if we have one
  1255. // (Since we can't have a TrackPopupMenu and a File menu open at the same time)
  1256. IUnknown_SetSite(_pcmFile, NULL);
  1257. ATOMICRELEASE(_pcmFile);
  1258. // stash pcm in _pcmContextMenuPopup so we can forward menu messages
  1259. ASSERT(NULL==_pcmContextMenuPopup);
  1260. _pcmContextMenuPopup = pcm;
  1261. _pcmContextMenuPopup->AddRef();
  1262. int idDefault = GetMenuDefaultItem(hmContext, MF_BYCOMMAND, 0);
  1263. int idCmd = TrackPopupMenu(hmContext,
  1264. TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN,
  1265. pt.x, pt.y, 0, _hwndView, NULL);
  1266. ATOMICRELEASE(_pcmContextMenuPopup);
  1267. if ((idCmd == idDefault) &&
  1268. _OnDefaultCommand() == S_OK)
  1269. {
  1270. // commdlg browser ate the default command
  1271. }
  1272. else if (idCmd == 0)
  1273. {
  1274. // No item selected
  1275. }
  1276. else if (idCmd >= SFVIDM_BACK_CONTEXT_FIRST && idCmd <= SFVIDM_BACK_CONTEXT_LAST)
  1277. {
  1278. idCmd -= SFVIDM_BACK_CONTEXT_FIRST;
  1279. // We need to special case the rename command (just in case a legacy contextmenu impl relied on this behavior)
  1280. TCHAR szCommandString[64];
  1281. ContextMenu_GetCommandStringVerb(pcm, idCmd, szCommandString, ARRAYSIZE(szCommandString));
  1282. if (lstrcmpi(szCommandString, c_szRename) == 0)
  1283. {
  1284. DoRename();
  1285. }
  1286. else
  1287. {
  1288. CMINVOKECOMMANDINFOEX ici = { 0 };
  1289. ici.cbSize = sizeof(ici);
  1290. ici.hwnd = _hwndMain;
  1291. ici.lpVerb = IntToPtr_(LPCSTR, idCmd);
  1292. ici.nShow = SW_NORMAL;
  1293. ici.ptInvoke = pt;
  1294. ici.fMask |= CMIC_MASK_PTINVOKE | CMIC_MASK_FLAG_LOG_USAGE;
  1295. // record if shift or control was being held down
  1296. SetICIKeyModifiers(&ici.fMask);
  1297. _InvokeContextMenu(pcm, &ici);
  1298. }
  1299. }
  1300. else
  1301. {
  1302. RIPMSG(FALSE, "CDefView::DoContextMenuPopup - Some IContextMenu inserted an ID out of our range. Ignoring.");
  1303. }
  1304. // If this is the common dialog browser 2, we need inform it
  1305. // the context menu is done. This notifiction is use in
  1306. // the common print dialog on NT which hosts the printers folder.
  1307. // Common dialog want to relselect the printer object if the user
  1308. // selected the context menu from the background.
  1309. if (pcdb2)
  1310. {
  1311. pcdb2->Notify(this, CDB2N_CONTEXTMENU_DONE);
  1312. pcdb2->Release();
  1313. }
  1314. }
  1315. DestroyMenu(hmContext);
  1316. }
  1317. // Always remove the site even if we didn't set it -- once used, the IContextMenu is dead.
  1318. IUnknown_SetSite(pcm, NULL);
  1319. pcm->Release();
  1320. }
  1321. return hr;
  1322. }
  1323. void CDefView::ContextMenu(DWORD dwPos)
  1324. {
  1325. int iItem;
  1326. UINT fFlags = 0;
  1327. POINT pt;
  1328. if (SHRestricted(REST_NOVIEWCONTEXTMENU))
  1329. {
  1330. return;
  1331. }
  1332. // if shell32's global copy of the stopwatch mode is not init'd yet, init it now.
  1333. if (g_dwStopWatchMode == 0xffffffff)
  1334. g_dwStopWatchMode = StopWatchMode();
  1335. if (g_dwStopWatchMode)
  1336. StopWatch_Start(SWID_MENU, TEXT("Defview ContextMenu Start"), SPMODE_SHELL | SPMODE_DEBUGOUT);
  1337. if (IsWindowVisible(_hwndListview) && (IsChildOrSelf(_hwndListview, GetFocus()) == S_OK))
  1338. {
  1339. // Find the selected item
  1340. iItem = ListView_GetNextItem(_hwndListview, -1, LVNI_SELECTED);
  1341. }
  1342. else
  1343. {
  1344. iItem = -1;
  1345. }
  1346. if (dwPos == (DWORD) -1)
  1347. {
  1348. if (iItem != -1)
  1349. {
  1350. RECT rc;
  1351. int iItemFocus = ListView_GetNextItem(_hwndListview, -1, LVNI_FOCUSED|LVNI_SELECTED);
  1352. if (iItemFocus == -1)
  1353. iItemFocus = iItem;
  1354. //
  1355. // Note that LV_GetItemRect returns it in client coordinate!
  1356. //
  1357. ListView_GetItemRect(_hwndListview, iItemFocus, &rc, LVIR_ICON);
  1358. pt.x = (rc.left + rc.right) / 2;
  1359. pt.y = (rc.top + rc.bottom) / 2;
  1360. }
  1361. else
  1362. {
  1363. pt.x = pt.y = 0;
  1364. }
  1365. MapWindowPoints(_hwndListview, HWND_DESKTOP, &pt, 1);
  1366. }
  1367. else
  1368. {
  1369. pt.x = GET_X_LPARAM(dwPos);
  1370. pt.y = GET_Y_LPARAM(dwPos);
  1371. }
  1372. IContextMenu* pcm;
  1373. LPARAM uemEvent;
  1374. if (iItem == -1)
  1375. {
  1376. DECLAREWAITCURSOR;
  1377. SetWaitCursor();
  1378. // use the background context menu wrapper
  1379. GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &pcm));
  1380. ResetWaitCursor();
  1381. // set the max range for these, so that they are unaffected...
  1382. uemEvent = _IsDesktop() ? UIBL_CTXTDESKBKGND : UIBL_CTXTDEFBKGND;
  1383. }
  1384. else
  1385. {
  1386. fFlags |= CMF_CANRENAME;
  1387. // One or more items are selected, let the folder add menuitems.
  1388. _CreateSelectionContextMenu(IID_PPV_ARG(IContextMenu, &pcm));
  1389. uemEvent = _IsDesktop() ? UIBL_CTXTDESKITEM : UIBL_CTXTDEFITEM;
  1390. }
  1391. UEMFireEvent(&UEMIID_SHELL, UEME_INSTRBROWSER, UEMF_INSTRUMENT, UIBW_UICONTEXT, uemEvent);
  1392. if (g_dwStopWatchMode)
  1393. StopWatch_Stop(SWID_MENU, TEXT("Defview ContextMenu Stop (!SafeToDefaultVerb)"), SPMODE_SHELL | SPMODE_DEBUGOUT);
  1394. if (IsSafeToDefaultVerb() && pcm)
  1395. {
  1396. _DoContextMenuPopup(pcm, fFlags, pt, iItem != -1);
  1397. }
  1398. ATOMICRELEASE(pcm);
  1399. }
  1400. BOOL CDefView::_GetItemSpacing(ITEMSPACING *pis)
  1401. {
  1402. DWORD dwSize = ListView_GetItemSpacing(_hwndListview, TRUE);
  1403. pis->cxSmall = GET_X_LPARAM(dwSize);
  1404. pis->cySmall = GET_Y_LPARAM(dwSize);
  1405. dwSize = ListView_GetItemSpacing(_hwndListview, FALSE);
  1406. pis->cxLarge = GET_X_LPARAM(dwSize);
  1407. pis->cyLarge = GET_Y_LPARAM(dwSize);
  1408. return _fs.ViewMode != FVM_ICON;
  1409. }
  1410. BOOL _DidDropOnRecycleBin(IDataObject *pdtobj)
  1411. {
  1412. CLSID clsid;
  1413. return SUCCEEDED(DataObj_GetDropTarget(pdtobj, &clsid)) &&
  1414. IsEqualCLSID(clsid, CLSID_RecycleBin);
  1415. }
  1416. void CDefView::_SetPoints(UINT cidl, LPCITEMIDLIST *apidl, IDataObject *pdtobj)
  1417. {
  1418. POINT pt;
  1419. GetDragPoint(&pt);
  1420. ::SetPositionItemsPoints(SAFECAST(this, IFolderView*), apidl, cidl, pdtobj, &pt);
  1421. }
  1422. LRESULT CDefView::_OnBeginDrag(NM_LISTVIEW * pnm)
  1423. {
  1424. POINT ptOffset = pnm->ptAction; // hwndLV client coords
  1425. // This DefView is used as a drag source so we need to see if it's
  1426. // is hosted by something that can disguise the action.
  1427. if (S_OK != _ZoneCheck(PUAF_NOUI, URLACTION_SHELL_WEBVIEW_VERB))
  1428. {
  1429. // This DefView is hosted in HTML, so we need to turn off the
  1430. // ability of this defview from being a drag source.
  1431. return 0;
  1432. }
  1433. _OnDelayedSelectionChange();
  1434. if (FAILED(_FireEvent(DISPID_BEGINDRAG))) // script canceles dragging
  1435. return 0;
  1436. DWORD dwEffect = _AttributesFromSel(SFGAO_CANDELETE | DROPEFFECT_LINK | DROPEFFECT_MOVE | DROPEFFECT_COPY);
  1437. // Turn on DROPEFFECT_MOVE for any deleteable item
  1438. // (this is so the item can be dragged to the recycle bin)
  1439. if (SFGAO_CANDELETE & dwEffect)
  1440. {
  1441. dwEffect |= DROPEFFECT_MOVE;
  1442. }
  1443. // Mask out all attribute bits that aren't also DROPEFFECT bits:
  1444. dwEffect &= (DROPEFFECT_LINK | DROPEFFECT_MOVE | DROPEFFECT_COPY);
  1445. // Somebody began dragging in our window, so store that fact
  1446. _bDragSource = TRUE;
  1447. // save away the anchor point
  1448. _ptDragAnchor = pnm->ptAction;
  1449. LVUtil_ClientToLV(_hwndListview, &_ptDragAnchor);
  1450. ClientToScreen(_hwndListview, &ptOffset); // now in screen
  1451. // can't use _pdoSelection here since we need fSetPoints
  1452. IDataObject *pdtobj;
  1453. if (SUCCEEDED(_GetUIObjectFromItem(IID_PPV_ARG(IDataObject, &pdtobj), SVGIO_SELECTION, TRUE)))
  1454. {
  1455. // Give the source a chance to alter the drop effect.
  1456. CallCB(SFVM_ALTERDROPEFFECT, (WPARAM)&dwEffect, (LPARAM)pdtobj);
  1457. if (DAD_SetDragImageFromWindow(_hwndListview, &ptOffset, pdtobj))
  1458. {
  1459. if (DRAGDROP_S_DROP == SHDoDragDrop(_hwndMain, pdtobj, NULL, dwEffect, &dwEffect))
  1460. {
  1461. if (S_OK != CallCB(SFVM_DIDDRAGDROP, (WPARAM)dwEffect, (LPARAM)pdtobj))
  1462. {
  1463. // the return of DROPEFFECT_MOVE tells us we need to delete the data
  1464. // see if we need to do that now...
  1465. // NOTE: we can't trust the dwEffect return result from DoDragDrop() because
  1466. // some apps (adobe photoshop) return this when you drag a file on them that
  1467. // they intend to open. so we invented the "PreformedEffect" as a way to
  1468. // know what the real value is, that is why we test both of these.
  1469. if ((DROPEFFECT_MOVE == dwEffect) &&
  1470. (DROPEFFECT_MOVE == DataObj_GetDWORD(pdtobj, g_cfPerformedDropEffect, DROPEFFECT_NONE)))
  1471. {
  1472. // enable UI for the recycle bin case (the data will be lost
  1473. // as the recycle bin really can't recycle stuff that is not files)
  1474. UINT uFlags = _DidDropOnRecycleBin(pdtobj) ? 0 : CMIC_MASK_FLAG_NO_UI;
  1475. SHInvokeCommandOnDataObject(_hwndMain, NULL, pdtobj, uFlags,c_szDeleteA);
  1476. }
  1477. }
  1478. }
  1479. //
  1480. // We need to clear the dragged image only if we still have the drag context.
  1481. //
  1482. DAD_SetDragImage((HIMAGELIST)-1, NULL);
  1483. }
  1484. pdtobj->Release();
  1485. }
  1486. _bDragSource = FALSE; // All done dragging
  1487. return 0;
  1488. }
  1489. void CDefView::_FocusOnSomething(void)
  1490. {
  1491. int iFocus = ListView_GetNextItem(_hwndListview, -1, LVNI_FOCUSED);
  1492. if (iFocus == -1)
  1493. {
  1494. if (ListView_GetItemCount(_hwndListview) > 0)
  1495. {
  1496. // set the focus on the first item.
  1497. ListView_SetItemState(_hwndListview, 0, LVIS_FOCUSED, LVIS_FOCUSED);
  1498. }
  1499. }
  1500. }
  1501. HRESULT CDefView::_InvokeContextMenu(IContextMenu *pcm, CMINVOKECOMMANDINFOEX *pici)
  1502. {
  1503. TCHAR szWorkingDir[MAX_PATH];
  1504. CHAR szWorkingDirAnsi[MAX_PATH];
  1505. if (SUCCEEDED(CallCB(SFVM_GETWORKINGDIR, ARRAYSIZE(szWorkingDir), (LPARAM)szWorkingDir)))
  1506. {
  1507. // Fill in both the ansi working dir and the unicode one
  1508. // since we don't know who's gonna be processing this thing.
  1509. SHUnicodeToAnsi(szWorkingDir, szWorkingDirAnsi, ARRAYSIZE(szWorkingDirAnsi));
  1510. pici->lpDirectory = szWorkingDirAnsi;
  1511. pici->lpDirectoryW = szWorkingDir;
  1512. pici->fMask |= CMIC_MASK_UNICODE;
  1513. }
  1514. // In case the ptInvoke field was not already set for us, guess where
  1515. // that could be. (dli) maybe should let the caller set all points
  1516. if (!(pici->fMask & CMIC_MASK_PTINVOKE))
  1517. {
  1518. if (GetCursorPos(&pici->ptInvoke))
  1519. pici->fMask |= CMIC_MASK_PTINVOKE;
  1520. }
  1521. pici->fMask |= CMIC_MASK_ASYNCOK;
  1522. _OnDelayedSelectionChange();
  1523. HRESULT hr = _FireEvent(DISPID_VERBINVOKED);
  1524. if (SUCCEEDED(hr))
  1525. hr = pcm->InvokeCommand((LPCMINVOKECOMMANDINFO)pici);
  1526. return hr;
  1527. }
  1528. DWORD CDefView::_GetNeededSecurityAction(void)
  1529. {
  1530. DWORD dwUrlAction = 0;
  1531. if (!(SFGAO_FOLDER & _AttributesFromSel(SFGAO_FOLDER)))
  1532. {
  1533. // If we are hosted by Trident, Zone Check Action.
  1534. IUnknown *punk;
  1535. if (SUCCEEDED(_psb->QueryInterface(IID_IIsWebBrowserSB, (void **)&punk)))
  1536. {
  1537. dwUrlAction = URLACTION_SHELL_VERB;
  1538. punk->Release();
  1539. }
  1540. else if (_fGetWindowLV)
  1541. {
  1542. // If we are using WebView, Zone Check Action.
  1543. dwUrlAction = URLACTION_SHELL_WEBVIEW_VERB;
  1544. }
  1545. }
  1546. return dwUrlAction;
  1547. }
  1548. HRESULT CDefView::_ZoneCheck(DWORD dwFlags, DWORD dwAllowAction)
  1549. {
  1550. HRESULT hr = S_OK;
  1551. DWORD dwUrlAction = _GetNeededSecurityAction();
  1552. if (dwUrlAction && (dwUrlAction != dwAllowAction))
  1553. {
  1554. // First check if our parent wants to generate our context (Zone/URL).
  1555. IInternetHostSecurityManager *pihsm;
  1556. hr = IUnknown_QueryService(_psb, IID_IInternetHostSecurityManager, IID_PPV_ARG(IInternetHostSecurityManager, &pihsm));
  1557. if (FAILED(hr) && _cFrame._pDocView)
  1558. {
  1559. // Yes, so if we are in WebView mode, check the instance of Trident that is
  1560. // displaying the WebView content, because that content could discuise the DefView
  1561. // and make the user unknowingly do something bad.
  1562. hr = IUnknown_QueryService(_cFrame._pDocView, IID_IInternetHostSecurityManager, IID_PPV_ARG(IInternetHostSecurityManager, &pihsm));
  1563. }
  1564. if (SUCCEEDED(hr))
  1565. {
  1566. // This is the prefered way to do the zone check.
  1567. hr = ZoneCheckHost(pihsm, dwUrlAction, dwFlags | PUAF_FORCEUI_FOREGROUND);
  1568. pihsm->Release();
  1569. }
  1570. else
  1571. {
  1572. // No, we were not able to get the interface. So fall back to zone checking the
  1573. // URL that comes from the pidl we are at.
  1574. TCHAR szPathSource[MAX_PATH];
  1575. if (_GetPath(szPathSource))
  1576. {
  1577. // Try to get a IInternetSecurityMgrSite so our UI will be modal.
  1578. IInternetSecurityMgrSite *pisms;
  1579. if (SUCCEEDED(IUnknown_QueryService(_psb, SID_STopLevelBrowser, IID_PPV_ARG(IInternetSecurityMgrSite, &pisms))))
  1580. {
  1581. // TODO: Have this object support IInternetSecurityMgrSite in case our parent doesn't provide one.
  1582. // Make that code support ::GetWindow() and ::EnableModless() or we won't get the modal behavior
  1583. // needed for VB and AOL.
  1584. hr = ZoneCheckUrl(szPathSource, dwUrlAction, dwFlags | PUAF_ISFILE | PUAF_FORCEUI_FOREGROUND, pisms);
  1585. pisms->Release();
  1586. }
  1587. }
  1588. }
  1589. }
  1590. return hr;
  1591. }
  1592. BOOL CDefView::IsSafeToDefaultVerb(void)
  1593. {
  1594. return S_OK == _ZoneCheck(PUAF_WARN_IF_DENIED, 0);
  1595. }
  1596. HRESULT CDefView::_InvokeContextMenuVerb(IContextMenu* pcm, LPCSTR pszVerb, UINT uKeyFlags, DWORD dwCMMask)
  1597. {
  1598. DECLAREWAITCURSOR;
  1599. SetWaitCursor();
  1600. CMINVOKECOMMANDINFOEX ici = {0};
  1601. ici.cbSize = sizeof(ici);
  1602. ici.hwnd = _hwndMain;
  1603. ici.nShow = SW_NORMAL;
  1604. ici.fMask = dwCMMask;
  1605. // Get the point where the double click is invoked.
  1606. GetMsgPos(&ici.ptInvoke);
  1607. ici.fMask |= CMIC_MASK_PTINVOKE;
  1608. // record if shift or control was being held down
  1609. SetICIKeyModifiers(&ici.fMask);
  1610. IUnknown_SetSite(pcm, SAFECAST(this, IOleCommandTarget *));
  1611. // Security note: we assume all non default verbs safe
  1612. HRESULT hr;
  1613. if (pszVerb ||
  1614. (IsSafeToDefaultVerb() && SUCCEEDED(_FireEvent(DISPID_DEFAULTVERBINVOKED))))
  1615. {
  1616. WCHAR szVerbW[128];
  1617. if (pszVerb)
  1618. {
  1619. ici.lpVerb = pszVerb;
  1620. SHAnsiToUnicode(pszVerb, szVerbW, ARRAYSIZE(szVerbW));
  1621. ici.lpVerbW = szVerbW;
  1622. ici.fMask |= CMIC_MASK_UNICODE;
  1623. }
  1624. HMENU hmenu = CreatePopupMenu();
  1625. if (hmenu)
  1626. {
  1627. UINT fFlags = _GetExplorerFlag();
  1628. if (NULL == pszVerb)
  1629. fFlags |= CMF_DEFAULTONLY; // optmization
  1630. // SHIFT + dbl click does a Explore by default
  1631. if (uKeyFlags & LVKF_SHIFT)
  1632. fFlags |= CMF_EXPLORE;
  1633. pcm->QueryContextMenu(hmenu, 0, CONTEXTMENU_IDCMD_FIRST, CONTEXTMENU_IDCMD_LAST, fFlags);
  1634. if (pszVerb)
  1635. hr = S_OK;
  1636. else
  1637. {
  1638. UINT idCmd = GetMenuDefaultItem(hmenu, MF_BYCOMMAND, GMDI_GOINTOPOPUPS);
  1639. if (idCmd == -1)
  1640. {
  1641. hr = E_FAIL;
  1642. }
  1643. else
  1644. {
  1645. ici.lpVerb = (LPSTR)MAKEINTRESOURCE(idCmd - CONTEXTMENU_IDCMD_FIRST);
  1646. hr = S_OK;
  1647. }
  1648. }
  1649. if (SUCCEEDED(hr))
  1650. {
  1651. // need to reset it so that user won't blow off the app starting cursor
  1652. // also so that if we won't leave the wait cursor up when we're not waiting
  1653. // (like in a prop sheet or something that has a message loop
  1654. ResetWaitCursor();
  1655. hcursor_wait_cursor_save = NULL;
  1656. hr = _InvokeContextMenu(pcm, &ici);
  1657. }
  1658. DestroyMenu(hmenu);
  1659. }
  1660. else
  1661. {
  1662. hr = E_OUTOFMEMORY;
  1663. }
  1664. }
  1665. else
  1666. {
  1667. hr = E_ACCESSDENIED;
  1668. }
  1669. IUnknown_SetSite(pcm, NULL);
  1670. if (hcursor_wait_cursor_save)
  1671. ResetWaitCursor();
  1672. return hr;
  1673. }
  1674. HRESULT CDefView::_InvokeContextMenuVerbOnSelection(LPCSTR pszVerb, UINT uKeyFlags, DWORD dwCMMask)
  1675. {
  1676. if (NULL == pszVerb)
  1677. {
  1678. if (_IsDesktop())
  1679. UEMFireEvent(&UEMIID_SHELL, UEME_UISCUT, UEMF_XEVENT, -1, (LPARAM)-1);
  1680. if (S_OK == _OnDefaultCommand())
  1681. {
  1682. return S_FALSE; /* commdlg browser ate the message */
  1683. }
  1684. if (uKeyFlags & LVKF_ALT)
  1685. pszVerb = "properties";
  1686. }
  1687. // Dealing with context menus can be slow
  1688. DECLAREWAITCURSOR;
  1689. SetWaitCursor();
  1690. IContextMenu *pcmSel;
  1691. HRESULT hr = _CreateSelectionContextMenu(IID_PPV_ARG(IContextMenu, &pcmSel));
  1692. if (SUCCEEDED(hr))
  1693. _LogDesktopLinksAndRegitems();
  1694. ResetWaitCursor(); // undo the cursor since the below _Invoke needs to control cursor shape
  1695. if (SUCCEEDED(hr))
  1696. {
  1697. hr = _InvokeContextMenuVerb(pcmSel, pszVerb, uKeyFlags, dwCMMask);
  1698. pcmSel->Release();
  1699. }
  1700. return hr;
  1701. }
  1702. //
  1703. // We want to keep track of which desktop regitems and links the user is using.
  1704. // This lets the desktop cleaner app know which ones can safely be
  1705. // cleaned up.
  1706. //
  1707. // Be careful - there are many race conditions... You have to do the
  1708. // GetSelectedObjects before any InvokeCommands are done, because the
  1709. // InvokeCommand calls might change the selection state. But you also
  1710. // have to use the result of GetSelectedObjects immediately, because
  1711. // it returns pidls that are owned by the defview, and if a filesys
  1712. // notify comes in, you might end up with pidls that have been freed.
  1713. //
  1714. // So we just do all the work up front, before actually invoking anything.
  1715. // This does mean that if the invoke fails, we still log the usage,
  1716. // but that seems like a small price to pay.
  1717. //
  1718. void CDefView::_LogDesktopLinksAndRegitems()
  1719. {
  1720. if (_IsDesktop())
  1721. {
  1722. LPCITEMIDLIST *apidl;
  1723. UINT cItems;
  1724. if (SUCCEEDED(GetSelectedObjects(&apidl, &cItems)) && apidl)
  1725. {
  1726. for (UINT i = 0; i < cItems; i++)
  1727. {
  1728. TCHAR szDisplayName[GUIDSTR_MAX+2]; // +2 for leading "::"
  1729. if (SUCCEEDED(DisplayNameOf(_pshf, apidl[i], SHGDN_INFOLDER | SHGDN_FORPARSING,
  1730. szDisplayName, ARRAYSIZE(szDisplayName))))
  1731. {
  1732. if (_Attributes(apidl[i], SFGAO_LINK))
  1733. {
  1734. // its a link
  1735. UEMFireEvent(&UEMIID_SHELL, UEME_RUNPATH, UEMF_XEVENT, -1, (LPARAM)szDisplayName);
  1736. }
  1737. else if (IsRegItemName(szDisplayName, NULL))
  1738. {
  1739. // it's a regitem
  1740. UEMFireEvent(&UEMIID_SHELL, UEME_RUNPATH, UEMF_XEVENT, -1, (LPARAM)szDisplayName);
  1741. }
  1742. }
  1743. }
  1744. LocalFree((HLOCAL)apidl);
  1745. }
  1746. }
  1747. }
  1748. void CDefView::_UpdateColData(CBackgroundColInfo *pbgci)
  1749. {
  1750. UINT iItem = ListView_MapIDToIndex(_hwndListview, pbgci->GetId());
  1751. if (iItem != -1)
  1752. {
  1753. UINT uiCol = pbgci->GetColumn();
  1754. if (_IsColumnInListView(uiCol))
  1755. {
  1756. UINT iVisCol = _RealToVisibleCol(uiCol);
  1757. ListView_SetItemText(_hwndListview, iItem, iVisCol, (LPTSTR)pbgci->GetText());
  1758. }
  1759. }
  1760. delete pbgci;
  1761. }
  1762. void CDefView::_UpdateIcon(LPITEMIDLIST pidl, UINT iIcon)
  1763. {
  1764. int i = _FindItem(pidl, NULL, FALSE, FALSE);
  1765. if (i >= 0)
  1766. {
  1767. LV_ITEM item = {0};
  1768. item.mask = LVIF_IMAGE;
  1769. item.iItem = i;
  1770. item.iImage = iIcon;
  1771. ListView_SetItem(_hwndListview, &item);
  1772. }
  1773. ILFree(pidl);
  1774. }
  1775. void CDefView::_UpdateGroup(CBackgroundGroupInfo* pbggi)
  1776. {
  1777. if (pbggi->VerifyGroupExists(_hwndListview, _pcat))
  1778. {
  1779. int iItem = ListView_MapIDToIndex(_hwndListview, pbggi->GetId());
  1780. if (iItem != -1)
  1781. {
  1782. LVITEM lvi = {0};
  1783. lvi.mask = LVIF_GROUPID;
  1784. lvi.iGroupId = pbggi->GetGroupId();
  1785. lvi.iItem = iItem;
  1786. ListView_SetItem(_hwndListview, &lvi);
  1787. }
  1788. delete pbggi;
  1789. }
  1790. }
  1791. void CDefView::_UpdateOverlay(int iList, int iOverlay)
  1792. {
  1793. ASSERT (iList >= 0);
  1794. if (_IsOwnerData())
  1795. {
  1796. // In the ownerdata case, tell the owner that the overlay changed
  1797. CallCB(SFVM_SETICONOVERLAY, iList, iOverlay);
  1798. ListView_RedrawItems(_hwndListview, iList, iList);
  1799. }
  1800. else
  1801. {
  1802. ListView_SetItemState(_hwndListview, iList, INDEXTOOVERLAYMASK(iOverlay), LVIS_OVERLAYMASK);
  1803. }
  1804. }
  1805. HRESULT CDefView::_GetIconAsync(LPCITEMIDLIST pidl, int *piIcon, BOOL fCanWait)
  1806. {
  1807. HRESULT hr;
  1808. // if we are not an owner-data view then try to extract asynchronously
  1809. UINT flags = (_IsOwnerData() ? 0 : GIL_ASYNC);
  1810. if (GIL_ASYNC & flags)
  1811. {
  1812. hr = SHMapIDListToImageListIndexAsync(_pScheduler, _pshf, pidl, flags, _AsyncIconTaskCallback, this, NULL, piIcon, NULL);
  1813. if (SUCCEEDED(hr))
  1814. {
  1815. return S_OK; // indicate that we got the real icon
  1816. }
  1817. else if (hr == E_PENDING)
  1818. {
  1819. hr = S_FALSE; // the icon index we have is a placeholder
  1820. }
  1821. }
  1822. else
  1823. {
  1824. hr = SHGetIconFromPIDL(_pshf, _psi, pidl, flags, piIcon);
  1825. }
  1826. return hr;
  1827. }
  1828. void CDefView::_AsyncIconTaskCallback(LPCITEMIDLIST pidl, void *pvData, void *pvHint, INT iIconIndex, INT iOpenIconIndex)
  1829. {
  1830. CDefView *pdv = (CDefView *)pvData;
  1831. ASSERT(pdv);
  1832. if (pdv)
  1833. {
  1834. LPITEMIDLIST pidlClone = ILClone(pidl);
  1835. if (pidlClone && !PostMessage(pdv->_hwndView, WM_DSV_UPDATEICON, (WPARAM)pidlClone, (LPARAM)iIconIndex))
  1836. ILFree(pidlClone);
  1837. }
  1838. }
  1839. HRESULT CDefView::_GetOverlayIndexAsync(LPCITEMIDLIST pidl, int iList)
  1840. {
  1841. IRunnableTask * pTask;
  1842. HRESULT hr = CIconOverlayTask_CreateInstance(this, pidl, iList, &pTask);
  1843. if (SUCCEEDED(hr))
  1844. {
  1845. _AddTask(pTask, TOID_DVIconOverlay, 0, TASK_PRIORITY_GET_ICON, ADDTASK_ATEND);
  1846. pTask->Release();
  1847. }
  1848. return hr;
  1849. }
  1850. //
  1851. // Returns: if the cursor is over a listview item, its index; otherwise, -1.
  1852. //
  1853. int CDefView::_HitTest(const POINT *ppt, BOOL fIgnoreEdge)
  1854. {
  1855. LV_HITTESTINFO info;
  1856. if (!_IsListviewVisible())
  1857. return -1;
  1858. info.pt = *ppt;
  1859. int iRet = ListView_HitTest(_hwndListview, &info);
  1860. if (-1 != iRet && fIgnoreEdge)
  1861. {
  1862. // If we're in one of these large image area modes, and the caller says
  1863. // it's okay to ignore "edge" hits, then pretend the user is over nothing.
  1864. // Tile mode only ignores the left edge of the icon, since the right edge
  1865. // is all text (and usually shorter than the tile width anyway).
  1866. if (_IsTileMode() && (info.flags & LVHT_ONLEFTSIDEOFICON))
  1867. iRet = -1;
  1868. else if (_IsImageMode() && (info.flags & (LVHT_ONLEFTSIDEOFICON|LVHT_ONRIGHTSIDEOFICON)))
  1869. iRet = -1;
  1870. }
  1871. return iRet;
  1872. }
  1873. void CDefView::_OnGetInfoTip(NMLVGETINFOTIP *plvn)
  1874. {
  1875. if (!SHShowInfotips())
  1876. return;
  1877. LPCITEMIDLIST pidl = _GetPIDL(plvn->iItem);
  1878. if (pidl)
  1879. {
  1880. ATOMICRELEASE(_pBackgroundInfoTip); // Release the previous value, if any
  1881. HRESULT hr = E_FAIL;
  1882. _pBackgroundInfoTip = new CBackgroundInfoTip(&hr, plvn);
  1883. if (_pBackgroundInfoTip && SUCCEEDED(hr))
  1884. {
  1885. LPITEMIDLIST pidlFolder = _GetViewPidl();
  1886. if (pidlFolder)
  1887. {
  1888. CStatusBarAndInfoTipTask *pTask;
  1889. hr = CStatusBarAndInfoTipTask_CreateInstance(pidlFolder, pidl, 0, 0, _pBackgroundInfoTip, _hwndView, _pScheduler, &pTask);
  1890. if (SUCCEEDED(hr))
  1891. {
  1892. if (_pScheduler)
  1893. {
  1894. // make sure there are no other background infotip tasks going on...
  1895. _pScheduler->RemoveTasks(TOID_DVBackgroundInfoTip, ITSAT_DEFAULT_LPARAM, FALSE);
  1896. }
  1897. _AddTask(pTask, TOID_DVBackgroundInfoTip, 0, TASK_PRIORITY_INFOTIP, ADDTASK_ATEND);
  1898. pTask->Release();
  1899. }
  1900. ILFree(pidlFolder);
  1901. }
  1902. }
  1903. }
  1904. // Do not show a tip while the processing is happening in the background
  1905. plvn->pszText[0] = 0;
  1906. }
  1907. HRESULT CDefView::_OnViewWindowActive()
  1908. {
  1909. IShellView *psv = _psvOuter ? _psvOuter : SAFECAST(this, IShellView*);
  1910. return _psb->OnViewWindowActive(psv);
  1911. }
  1912. // CLR_NONE is a special value that never matches a valid RGB
  1913. COLORREF g_crAltColor = CLR_NONE; // uninitialized magic value
  1914. COLORREF g_crAltEncryptedColor = CLR_NONE; // uninitialized magic value
  1915. DWORD GetRegColor(COLORREF clrDefault, LPCTSTR pszName, COLORREF *pValue)
  1916. {
  1917. // Fetch the alternate color (for compression) if supplied.
  1918. if (*pValue == CLR_NONE) // initialized yet?
  1919. {
  1920. DWORD cbData = sizeof(*pValue);
  1921. if (FAILED(SKGetValue(SHELLKEY_HKCU_EXPLORER, NULL, pszName, NULL, pValue, &cbData)))
  1922. {
  1923. *pValue = clrDefault; // default value
  1924. }
  1925. }
  1926. return *pValue;
  1927. }
  1928. LRESULT CDefView::_GetDisplayInfo(LV_DISPINFO *plvdi)
  1929. {
  1930. LPCITEMIDLIST pidl = _GetPIDLParam(plvdi->item.lParam, plvdi->item.iItem);
  1931. if (pidl && (plvdi->item.mask & (DEFVIEW_LISTCALLBACK_FLAGS)))
  1932. {
  1933. ASSERT(IsValidPIDL(pidl));
  1934. ASSERT(plvdi->item.iSubItem != 0 ? ViewRequiresColumns(_fs.ViewMode) : TRUE);
  1935. LV_ITEM item = {0};
  1936. item.mask = plvdi->item.mask & (DEFVIEW_LISTCALLBACK_FLAGS);
  1937. item.iItem = plvdi->item.iItem;
  1938. item.iImage = plvdi->item.iImage = -1; // for iSubItem != 0 case
  1939. if ((plvdi->item.iSubItem == 0) && (item.mask & LVIF_IMAGE))
  1940. {
  1941. // If the folder supports IShellIconOverlay then only need to ask for ghosted, else
  1942. // we need to do the old stuff...
  1943. DWORD uFlags = _Attributes(pidl, _psio ? SFGAO_GHOSTED : SFGAO_LINK | SFGAO_SHARE | SFGAO_GHOSTED);
  1944. // set the mask
  1945. item.mask |= LVIF_STATE;
  1946. plvdi->item.mask |= LVIF_STATE;
  1947. item.stateMask = LVIS_OVERLAYMASK;
  1948. // Pick the right overlay icon. The order is significant.
  1949. item.state = 0;
  1950. if (_psio)
  1951. {
  1952. int iOverlayIndex = SFV_ICONOVERLAY_UNSET;
  1953. if (_IsOwnerData())
  1954. {
  1955. // Note: we are passing SFV_ICONOVERLAY_DEFAULT here because
  1956. // some owners do not respond to SFVM_GETICONOVERLAY might return
  1957. // iOverlayIndex unchanged and it will get
  1958. iOverlayIndex = SFV_ICONOVERLAY_DEFAULT;
  1959. CallCB(SFVM_GETICONOVERLAY, plvdi->item.iItem, (LPARAM)&iOverlayIndex);
  1960. if (iOverlayIndex > 0)
  1961. {
  1962. item.stateMask |= LVIS_OVERLAYMASK;
  1963. item.state |= INDEXTOOVERLAYMASK(iOverlayIndex);
  1964. }
  1965. }
  1966. if (iOverlayIndex == SFV_ICONOVERLAY_UNSET)
  1967. {
  1968. iOverlayIndex = OI_ASYNC;
  1969. HRESULT hr = _psio->GetOverlayIndex(pidl, &iOverlayIndex);
  1970. if (E_PENDING == hr)
  1971. _GetOverlayIndexAsync(pidl, item.iItem);
  1972. else if (S_OK == hr)
  1973. {
  1974. ASSERT(iOverlayIndex >= 0);
  1975. ASSERT(iOverlayIndex < MAX_OVERLAY_IMAGES);
  1976. // In the owner data case, tell the owner we got an Overlay index
  1977. if (_IsOwnerData())
  1978. CallCB(SFVM_SETICONOVERLAY, item.iItem, iOverlayIndex);
  1979. item.state = INDEXTOOVERLAYMASK(iOverlayIndex);
  1980. }
  1981. }
  1982. }
  1983. else
  1984. {
  1985. if (uFlags & SFGAO_LINK)
  1986. {
  1987. item.state = INDEXTOOVERLAYMASK(II_LINK - II_OVERLAYFIRST + 1);
  1988. }
  1989. else if (uFlags & SFGAO_SHARE)
  1990. {
  1991. item.state = INDEXTOOVERLAYMASK(II_SHARE - II_OVERLAYFIRST + 1);
  1992. }
  1993. }
  1994. if (uFlags & SFGAO_GHOSTED)
  1995. {
  1996. item.stateMask |= LVIS_CUT;
  1997. item.state |= LVIS_CUT;
  1998. }
  1999. else
  2000. {
  2001. item.stateMask |= LVIS_CUT;
  2002. item.state &= ~LVIS_CUT;
  2003. }
  2004. plvdi->item.stateMask = item.stateMask;
  2005. plvdi->item.state = item.state;
  2006. // Get the image
  2007. if (_IsOwnerData() && !_IsImageMode())
  2008. {
  2009. CallCB(SFVM_GETITEMICONINDEX, plvdi->item.iItem, (LPARAM)&item.iImage);
  2010. }
  2011. if (item.iImage == -1)
  2012. {
  2013. if (_IsImageMode())
  2014. {
  2015. // Check if the item is visible. If it is not, then the image was
  2016. // probably asked for by the thumbnail read ahead task, in which case, we set a
  2017. // different priority.
  2018. if (ListView_IsItemVisible(_hwndListview, item.iItem))
  2019. {
  2020. if (S_OK != ExtractItem((UINT*)&item.iImage, item.iItem, pidl, TRUE, FALSE, PRIORITY_P5))
  2021. {
  2022. _CacheDefaultThumbnail(pidl, &item.iImage);
  2023. }
  2024. }
  2025. else
  2026. {
  2027. // Likely from read ahead task.
  2028. ExtractItem((UINT*)&item.iImage, item.iItem, pidl, TRUE, FALSE, PRIORITY_READAHEAD_EXTRACT);
  2029. }
  2030. }
  2031. else
  2032. _GetIconAsync(pidl, &item.iImage, TRUE);
  2033. }
  2034. plvdi->item.iImage = item.iImage;
  2035. }
  2036. if (item.mask & LVIF_TEXT)
  2037. {
  2038. if (plvdi->item.cchTextMax)
  2039. *plvdi->item.pszText = 0;
  2040. // Note that we do something different for index 0 = NAME
  2041. if (plvdi->item.iSubItem == 0)
  2042. {
  2043. DisplayNameOf(_pshf, pidl, SHGDN_INFOLDER, plvdi->item.pszText, plvdi->item.cchTextMax);
  2044. }
  2045. else
  2046. {
  2047. // on the first slow column complete all of the other columns (assumed to be slow)
  2048. // now so we get good caching from the col handlers
  2049. UINT iReal = _VisibleToRealCol(plvdi->item.iSubItem);
  2050. if (_vs.GetColumnState(iReal) & SHCOLSTATE_SLOW)
  2051. {
  2052. UINT cCols = _vs.GetColumnCount();
  2053. for (UINT iVisCol = plvdi->item.iSubItem; iReal < cCols; iReal++)
  2054. {
  2055. if (_IsColumnInListView(iReal))
  2056. {
  2057. ASSERT(_vs.GetColumnState(iReal) & SHCOLSTATE_SLOW);
  2058. UINT uId = ListView_MapIndexToID(_hwndListview, plvdi->item.iItem);
  2059. // in the async case set the text to nothing (NULL). this will
  2060. // prevent another call to ListView_GetItemText() from invoking us
  2061. ListView_SetItemText(_hwndListview, plvdi->item.iItem, iVisCol++, NULL);
  2062. IRunnableTask *pTask;
  2063. if (SUCCEEDED(CExtendedColumnTask_CreateInstance(this, pidl, uId, _fmt, iReal, &pTask)))
  2064. {
  2065. _AddTask(pTask, TOID_DVBackgroundEnum, 0, TASK_PRIORITY_FILE_PROPS, ADDTASK_ATEND);
  2066. pTask->Release();
  2067. }
  2068. }
  2069. }
  2070. return 0; // bail!
  2071. }
  2072. DETAILSINFO di;
  2073. di.pidl = pidl;
  2074. di.fmt = _fmt;
  2075. di.iImage = -1; // Assume for now no image...
  2076. if (SUCCEEDED(_GetDetailsHelper(iReal, &di)))
  2077. {
  2078. StrRetToBuf(&di.str, pidl, plvdi->item.pszText, plvdi->item.cchTextMax);
  2079. if ((di.iImage != -1) && (plvdi->item.mask & LVIF_IMAGE))
  2080. {
  2081. plvdi->item.iImage = di.iImage;
  2082. }
  2083. }
  2084. }
  2085. }
  2086. if ((item.mask & LVIF_GROUPID) && _fGroupView)
  2087. {
  2088. plvdi->item.mask |= LVIF_GROUPID;
  2089. plvdi->item.iGroupId = _GetGroupForItem(plvdi->item.iItem, pidl);
  2090. }
  2091. if (item.mask & LVIF_COLUMNS)
  2092. {
  2093. if (_fScrolling)
  2094. {
  2095. // Ignore any column requests if we're currently scrolling. However, don't
  2096. // return zero for the number of columns, return I_COLUMNSCALLBACK instead, because
  2097. // we do still want listview to call us back to ask for them if it is every displaying
  2098. // this guy while we're not scrolling.
  2099. plvdi->item.cColumns = I_COLUMNSCALLBACK;
  2100. plvdi->item.puColumns = NULL;
  2101. _fRequestedTileDuringScroll = TRUE;
  2102. }
  2103. else
  2104. {
  2105. if (_IsOwnerData())
  2106. {
  2107. AddColumns();
  2108. if (plvdi->item.cColumns > 1)
  2109. {
  2110. // hack special case for the find folder
  2111. if (_MapSCIDToColumn(&SCID_DIRECTORY, &plvdi->item.puColumns[0]))
  2112. plvdi->item.cColumns = 1;
  2113. }
  2114. }
  2115. else
  2116. {
  2117. BOOL fGotColumns = FALSE;
  2118. // Start a task to extract the important columns for this item.
  2119. LPCITEMIDLIST pidl = _GetPIDL(plvdi->item.iItem);
  2120. if (pidl)
  2121. {
  2122. plvdi->item.cColumns = TILEVIEWLINES;
  2123. if (SUCCEEDED(_PeekColumnsCache(NULL, pidl, plvdi->item.puColumns, &plvdi->item.cColumns)))
  2124. {
  2125. // Make sure columns are loaded
  2126. AddColumns();
  2127. _FixupColumnsForTileview(plvdi->item.puColumns, plvdi->item.cColumns);
  2128. fGotColumns = TRUE;
  2129. }
  2130. else
  2131. {
  2132. IRunnableTask *pTask;
  2133. UINT uId = ListView_MapIndexToID(_hwndListview, plvdi->item.iItem);
  2134. if (SUCCEEDED(CFileTypePropertiesTask_CreateInstance(this, pidl, TILEVIEWLINES, uId, &pTask))) //pidl gets cloned
  2135. {
  2136. _AddTask(pTask, TOID_DVFileTypeProperties, 0, TASK_PRIORITY_FILE_PROPS, ADDTASK_ATEND);
  2137. pTask->Release();
  2138. }
  2139. }
  2140. }
  2141. if (!fGotColumns)
  2142. {
  2143. plvdi->item.cColumns = 0;
  2144. plvdi->item.puColumns = NULL;
  2145. }
  2146. }
  2147. }
  2148. }
  2149. if (plvdi->item.iSubItem == 0)
  2150. plvdi->item.mask |= LVIF_DI_SETITEM; // always store the name
  2151. }
  2152. return 0;
  2153. }
  2154. int CALLBACK GroupCompare(int iGroup1, int iGroup2, void *pvData)
  2155. {
  2156. ICategorizer* pcat = (ICategorizer*)pvData;
  2157. HRESULT hr = pcat->CompareCategory(CATSORT_DEFAULT, (DWORD)iGroup1, (DWORD)iGroup2);
  2158. return ShortFromResult(hr);
  2159. }
  2160. void CDefView::_OnCategoryTaskAdd()
  2161. {
  2162. _fInBackgroundGrouping = TRUE;
  2163. _GlobeAnimation(TRUE);
  2164. _ShowSearchUI(TRUE);
  2165. }
  2166. void CDefView::_OnCategoryTaskDone()
  2167. {
  2168. _fInBackgroundGrouping = FALSE;
  2169. _GlobeAnimation(FALSE);
  2170. _ShowSearchUI(FALSE);
  2171. if (_pidlSelectAndPosition)
  2172. {
  2173. POINT pt = {0}; // Don't care: Groups don't have a position
  2174. SelectAndPositionItem(_pidlSelectAndPosition, _uSelectAndPositionFlags, &pt);
  2175. Pidl_Set(&_pidlSelectAndPosition, NULL);
  2176. _uSelectAndPositionFlags = 0;
  2177. }
  2178. }
  2179. DWORD CDefView::_GetGroupForItem(int iItem, LPCITEMIDLIST pidl)
  2180. {
  2181. DWORD dwGroup = I_GROUPIDNONE;
  2182. if (_fGroupView)
  2183. {
  2184. if (_fSlowGroup)
  2185. {
  2186. UINT uId = ListView_MapIndexToID(_hwndListview, iItem);
  2187. IRunnableTask* pTask;
  2188. if (SUCCEEDED(CCategoryTask_Create(this, pidl, uId, &pTask)))
  2189. {
  2190. // Need to get the globe/search stuff kicked off while within the CreateViewWindow2 call,
  2191. // so do it here instead of a posted message in the above constructor
  2192. _OnCategoryTaskAdd();
  2193. _AddTask(pTask, TOID_DVBackgroundGroup, 0, TASK_PRIORITY_GROUP, ADDTASK_ATEND);
  2194. pTask->Release();
  2195. }
  2196. }
  2197. else
  2198. {
  2199. _pcat->GetCategory(1, (LPCITEMIDLIST*)&pidl, &dwGroup);
  2200. if (!ListView_HasGroup(_hwndListview, dwGroup))
  2201. {
  2202. CATEGORY_INFO ci;
  2203. _pcat->GetCategoryInfo(dwGroup, &ci);
  2204. LVINSERTGROUPSORTED igrp;
  2205. igrp.pfnGroupCompare = GroupCompare;
  2206. igrp.pvData = (void *)_pcat;
  2207. igrp.lvGroup.cbSize = sizeof(LVGROUP);
  2208. igrp.lvGroup.mask = LVGF_HEADER | LVGF_GROUPID;
  2209. igrp.lvGroup.pszHeader= ci.wszName;
  2210. igrp.lvGroup.iGroupId = (int)dwGroup;
  2211. ListView_InsertGroupSorted(_hwndListview, &igrp);
  2212. }
  2213. }
  2214. }
  2215. return dwGroup;
  2216. }
  2217. BOOL CDefView::_EnsureSCIDCache()
  2218. {
  2219. BOOL bRet = FALSE;
  2220. if (_hdsaSCIDCache)
  2221. {
  2222. bRet = TRUE;
  2223. }
  2224. else if (_pshf2)
  2225. {
  2226. _hdsaSCIDCache = DSA_Create(sizeof(SHCOLUMNID), 30);
  2227. if (_hdsaSCIDCache)
  2228. {
  2229. SHCOLUMNID scid;
  2230. for (UINT iCol = 0; SUCCEEDED(_pshf2->MapColumnToSCID(iCol, &scid)); iCol++)
  2231. {
  2232. // ignore failure, just means we can't find the thing
  2233. DSA_AppendItem(_hdsaSCIDCache, &scid);
  2234. }
  2235. bRet = TRUE;
  2236. }
  2237. }
  2238. return bRet;
  2239. }
  2240. BOOL CDefView::_MapSCIDToColumn(const SHCOLUMNID *pscid, UINT *pnColumn)
  2241. {
  2242. BOOL bRet = FALSE;
  2243. *pnColumn = 0;
  2244. if (_EnsureSCIDCache())
  2245. {
  2246. UINT cCol = DSA_GetItemCount(_hdsaSCIDCache);
  2247. for (UINT iCol = 0; iCol < cCol; iCol++)
  2248. {
  2249. SHCOLUMNID scid;
  2250. DSA_GetItem(_hdsaSCIDCache, iCol, &scid);
  2251. if (IsEqualSCID(*pscid, scid))
  2252. {
  2253. *pnColumn = iCol;
  2254. bRet = TRUE;
  2255. break;
  2256. }
  2257. }
  2258. }
  2259. return bRet;
  2260. }
  2261. HRESULT CDefView::_GetPropertyUI(IPropertyUI **pppui)
  2262. {
  2263. if (!_ppui)
  2264. SHCoCreateInstance(NULL, &CLSID_PropertiesUI, NULL, IID_PPV_ARG(IPropertyUI, &_ppui));
  2265. return _ppui ? _ppui->QueryInterface(IID_PPV_ARG(IPropertyUI, pppui)) : E_NOTIMPL;
  2266. }
  2267. HRESULT CDefView::_PeekColumnsCache(PTSTR pszPath, LPCITEMIDLIST pidl, UINT rguColumns[], UINT *pcColumns)
  2268. {
  2269. TCHAR szPath[MAX_PATH];
  2270. if (pszPath == NULL)
  2271. pszPath = szPath;
  2272. // NOTE - need to replace this with GetDetailsEx(SCID_CANONICALTYPE) to support
  2273. // caching properly. then we dont need to sniff attributes or the name in order to get
  2274. // a nice caching index.
  2275. HRESULT hr = DisplayNameOf(_pshf, pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, pszPath, MAX_PATH);
  2276. if (SUCCEEDED(hr))
  2277. {
  2278. LPCWSTR pszExt = _Attributes(pidl, SFGAO_FOLDER) ? NULL : PathFindExtension(pszPath);
  2279. hr = E_FAIL;
  2280. // Check file table cache:
  2281. ENTERCRITICAL;
  2282. SHCOLUMNID *pscidCached;
  2283. UINT cSCIDCached = pszExt ? LookupFileSCIDs(pszExt, &pscidCached) : 0; //Handle no extension case by not looking up in cache
  2284. LEAVECRITICAL;
  2285. if (cSCIDCached) // Found the SCIDs cache in the file table
  2286. {
  2287. UINT nFilled = 0;
  2288. // Found it... we don't need to check the registry
  2289. for (UINT nSCID = 0; nSCID < cSCIDCached && nFilled < *pcColumns; nSCID++)
  2290. {
  2291. if (_MapSCIDToColumn(&pscidCached[nSCID], &rguColumns[nFilled]))
  2292. nFilled++;
  2293. }
  2294. *pcColumns = nFilled;
  2295. LocalFree(pscidCached);
  2296. hr = S_OK;
  2297. }
  2298. }
  2299. return hr;
  2300. }
  2301. // Get the important columns for this guy, based on file extension
  2302. // pidl: The pidl of the item in question
  2303. // puColumns[]: The array which will get filled with important column indicies
  2304. // pcColumns IN: specifies how big rguColumns[] is. OUT: specified how many slots got filled.
  2305. HRESULT CDefView::_GetImportantColumns(LPCITEMIDLIST pidl, UINT rguColumns[], UINT *pcColumns)
  2306. {
  2307. TCHAR szPath[MAX_PATH];
  2308. // We need to ensure that the columns are loaded here
  2309. if (!_bLoadedColumns)
  2310. {
  2311. DWORD_PTR lRes = 0;
  2312. if (!SendMessageTimeout(_hwndView, WM_DSV_ENSURE_COLUMNS_LOADED, 0, 0, SMTO_NORMAL, 5000, &lRes) || lRes == 0)
  2313. return E_FAIL;
  2314. }
  2315. HRESULT hr = _PeekColumnsCache(szPath, pidl, rguColumns, pcColumns);
  2316. if (FAILED(hr))
  2317. {
  2318. IQueryAssociations *pqa;
  2319. hr = _pshf->GetUIObjectOf(_hwndMain, 1, &pidl, IID_PPV_ARG_NULL(IQueryAssociations, &pqa));
  2320. if (SUCCEEDED(hr))
  2321. {
  2322. IPropertyUI *ppui;
  2323. hr = _GetPropertyUI(&ppui);
  2324. if (SUCCEEDED(hr))
  2325. {
  2326. TCHAR szProps[INFOTIPSIZE];
  2327. DWORD cchOut = ARRAYSIZE(szProps);
  2328. hr = pqa->GetString(0, ASSOCSTR_TILEINFO, NULL, szProps, &cchOut);
  2329. if (SUCCEEDED(hr))
  2330. {
  2331. UINT cNumColumns = 0; // # of items in rguColumns
  2332. UINT cSCID = 0; // # of items in rgscid
  2333. SHCOLUMNID rgscid[64]; // reasonable upper bound
  2334. ULONG chEaten = 0; // loop variable ParsePropertyName updates this
  2335. while ((cSCID < ARRAYSIZE(rgscid)) &&
  2336. SUCCEEDED(ppui->ParsePropertyName(szProps, &rgscid[cSCID].fmtid, &rgscid[cSCID].pid, &chEaten)))
  2337. {
  2338. // Map SCID to a column (while there are more column slots)
  2339. if ((cNumColumns < *pcColumns) &&
  2340. _MapSCIDToColumn(&rgscid[cSCID], &rguColumns[cNumColumns]))
  2341. {
  2342. cNumColumns++;
  2343. cSCID++;
  2344. }
  2345. }
  2346. *pcColumns = cNumColumns;
  2347. LPCWSTR pszExt = _Attributes(pidl, SFGAO_FOLDER) ? NULL : PathFindExtension(szPath);
  2348. if (pszExt)
  2349. {
  2350. // cache for future use, except if there's no extension (cache key)
  2351. ENTERCRITICAL;
  2352. AddFileSCIDs(pszExt, rgscid, cSCID);
  2353. LEAVECRITICAL;
  2354. }
  2355. }
  2356. ppui->Release();
  2357. }
  2358. pqa->Release();
  2359. }
  2360. }
  2361. return hr;
  2362. }
  2363. void CDefView::_FixupColumnsForTileview(UINT *rguColumns, UINT cColumns)
  2364. {
  2365. // Make sure these columns are added to listview (ie. visible).
  2366. // And then map the columns in rguColumns from real columns to visible columns
  2367. for (UINT i = 0; i < cColumns; i++)
  2368. {
  2369. _AddTileColumn(rguColumns[i]);
  2370. }
  2371. // Now, also add the sorted by column, if it hasn't been added yet.
  2372. if (!_fSetTileViewSortedCol)
  2373. {
  2374. _fSetTileViewSortedCol = TRUE;
  2375. // It's ok if we don't actually set it. It's the thought that counts.
  2376. if (_vs._lParamSort != -1)
  2377. {
  2378. _AddTileColumn(_vs._lParamSort);
  2379. // And set it selected, if we're not in groupview
  2380. if (!_fGroupView)
  2381. {
  2382. ListView_SetSelectedColumn(_hwndListview, _RealToVisibleCol(_vs._lParamSort));
  2383. }
  2384. }
  2385. }
  2386. // This must be done after all the _AddTileColumns, or else the visible col #'s will be off.
  2387. for (UINT i = 0; i < cColumns; i++)
  2388. {
  2389. rguColumns[i] = _RealToVisibleCol(rguColumns[i]);
  2390. }
  2391. }
  2392. void CDefView::_SetImportantColumns(CBackgroundTileInfo *pbgTileInfo)
  2393. {
  2394. UINT cColumns = pbgTileInfo->GetColumnCount();
  2395. UINT *rguColumns = pbgTileInfo->GetColumns();
  2396. LVTILEINFO ti = {0};
  2397. ti.cbSize = sizeof(ti);
  2398. ti.cColumns = cColumns;
  2399. ti.puColumns = rguColumns;
  2400. ti.iItem = ListView_MapIDToIndex(_hwndListview, pbgTileInfo->GetId());
  2401. if (ti.iItem != -1)
  2402. {
  2403. _FixupColumnsForTileview(rguColumns, cColumns);
  2404. // have the listview store the per item tile info that we have computed
  2405. ListView_SetTileInfo(_hwndListview, &ti);
  2406. }
  2407. delete pbgTileInfo;
  2408. }
  2409. // Ensures if we're in tileview, that the tileviewinfo is set.
  2410. void CDefView::_SetView(UINT fvm)
  2411. {
  2412. // Update our internal state
  2413. _fs.ViewMode = fvm;
  2414. // Map the ViewMode into a listview mode
  2415. DWORD iView = LV_VIEW_ICON;
  2416. // Now switch the listview
  2417. switch (fvm)
  2418. {
  2419. case FVM_ICON:
  2420. case FVM_SMALLICON:
  2421. case FVM_THUMBNAIL:
  2422. case FVM_THUMBSTRIP:
  2423. iView = LV_VIEW_ICON;
  2424. break;
  2425. case FVM_LIST:
  2426. iView = LV_VIEW_LIST;
  2427. break;
  2428. case FVM_TILE:
  2429. iView = LV_VIEW_TILE;
  2430. break;
  2431. case FVM_DETAILS:
  2432. iView = LV_VIEW_DETAILS;
  2433. break;
  2434. default:
  2435. ASSERTMSG(FALSE, "_SetView got an invalid ViewMode!");
  2436. break;
  2437. }
  2438. if (iView == LV_VIEW_TILE)
  2439. {
  2440. RECT rcLabelMargin = {1, 1, 1, 1}; // This gives us some room around the label, so the focus rect doesn't clip part of the text
  2441. LVTILEVIEWINFO lvtvi = {0};
  2442. lvtvi.cbSize = sizeof(lvtvi);
  2443. lvtvi.dwMask = LVTVIM_TILESIZE | LVTVIM_COLUMNS | LVTVIM_LABELMARGIN;
  2444. lvtvi.dwFlags = LVTVIF_AUTOSIZE;
  2445. lvtvi.cLines = TILEVIEWLINES;
  2446. lvtvi.rcLabelMargin = rcLabelMargin;
  2447. ListView_SetTileViewInfo(_hwndListview, &lvtvi);
  2448. }
  2449. ListView_SetView(_hwndListview, iView);
  2450. _FireEvent(DISPID_VIEWMODECHANGED);
  2451. }
  2452. // rename the selection based on the new name for the renamed item
  2453. // this makes it easy to rename groups of files to a common base name
  2454. HRESULT CDefView::_DoBulkRename(LPCITEMIDLIST pidlNewName)
  2455. {
  2456. LPCITEMIDLIST *apidl;
  2457. UINT cItems;
  2458. HRESULT hr = _GetItemObjects(&apidl, SVGIO_SELECTION, &cItems);
  2459. if (SUCCEEDED(hr))
  2460. {
  2461. if (cItems > 1) // only interesting if more than 1
  2462. {
  2463. TCHAR szBase[MAX_PATH]; // seed file name used to generate other names
  2464. hr = DisplayNameOf(_pshf, pidlNewName, SHGDN_INFOLDER | SHGDN_FORPARSING, szBase, ARRAYSIZE(szBase));
  2465. if (SUCCEEDED(hr))
  2466. {
  2467. if (!SHGetAttributes(_pshf, pidlNewName, SFGAO_FOLDER))
  2468. PathRemoveExtension(szBase); // remove the extension, if it is a file
  2469. UINT cBase = 1; // one based counter, start at "File (1)"
  2470. // if input contains (#) use that as the sequence # base
  2471. LPWSTR psz = StrChr(szBase, TEXT('('));
  2472. if (psz)
  2473. {
  2474. cBase = StrToInt(psz + 1) + 1; // start at this in sequence
  2475. *psz = 0; // remove the (#) from the base name
  2476. }
  2477. PathRemoveBlanks(szBase); // clean away leading/trailing blanks
  2478. // start at 1, skipping the focused item, renaming all others in the array
  2479. for (UINT i = 1; (i < cItems) && SUCCEEDED(hr); i++)
  2480. {
  2481. TCHAR szOld[MAX_PATH];
  2482. hr = DisplayNameOf(_pshf, apidl[i], SHGDN_INFOLDER | SHGDN_FORPARSING, szOld, ARRAYSIZE(szOld));
  2483. if (SUCCEEDED(hr))
  2484. {
  2485. // Clone the pidl since isf->SetNameOf can result in synchronous update item
  2486. // that can free the ListView owned apidl[i].
  2487. LPITEMIDLIST pidlOldName = ILClone(apidl[i]);
  2488. if (pidlOldName)
  2489. {
  2490. // if the new name we produce conflicts with a name that
  2491. // already exists we will retry up to 100 times
  2492. for (UINT cRetry = 0; cRetry < 100; cRetry++)
  2493. {
  2494. WCHAR szName[MAX_PATH];
  2495. wnsprintf(szName, ARRAYSIZE(szName), TEXT("%s (%d)%s"), szBase, cBase, PathFindExtension(szOld));
  2496. hr = _pshf->SetNameOf(NULL, pidlOldName, szName, SHGDN_INFOLDER | SHGDN_FORPARSING, NULL);
  2497. if (SUCCEEDED(hr))
  2498. {
  2499. // force sync change notify update to make sure
  2500. // all renames come through (avoid UPDATEDIR)
  2501. SHChangeNotifyHandleEvents();
  2502. cBase++;
  2503. break; // did this one successfully
  2504. }
  2505. else if (HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) == hr ||
  2506. HRESULT_FROM_WIN32(ERROR_FILE_EXISTS) == hr)
  2507. {
  2508. cBase++;
  2509. hr = S_OK; // and keep trying
  2510. }
  2511. else
  2512. {
  2513. break; // other error, exit
  2514. }
  2515. }
  2516. ILFree(pidlOldName);
  2517. }
  2518. }
  2519. }
  2520. }
  2521. }
  2522. LocalFree(apidl);
  2523. }
  2524. return hr;
  2525. }
  2526. LRESULT CDefView::_OnLVNotify(NM_LISTVIEW *plvn)
  2527. {
  2528. switch (plvn->hdr.code)
  2529. {
  2530. case NM_KILLFOCUS:
  2531. // force update on inactive to not ruin save bits
  2532. _OnStateChange(CDBOSC_KILLFOCUS);
  2533. if (GetForegroundWindow() != _hwndMain)
  2534. UpdateWindow(_hwndListview);
  2535. _fHasListViewFocus = FALSE;
  2536. _EnableDisableTBButtons();
  2537. break;
  2538. case NM_SETFOCUS:
  2539. {
  2540. if (!_fDestroying)
  2541. {
  2542. if (_cFrame.IsWebView()) // Do OLE stuff
  2543. {
  2544. UIActivate(SVUIA_ACTIVATE_FOCUS);
  2545. }
  2546. else
  2547. {
  2548. // We should call IShellBrowser::OnViewWindowActive() before
  2549. // calling its InsertMenus().
  2550. _OnViewWindowActive();
  2551. _OnStateChange(CDBOSC_SETFOCUS);
  2552. OnActivate(SVUIA_ACTIVATE_FOCUS);
  2553. _FocusOnSomething();
  2554. _UpdateStatusBar(FALSE);
  2555. }
  2556. _fHasListViewFocus = TRUE;
  2557. _EnableDisableTBButtons();
  2558. }
  2559. break;
  2560. }
  2561. case NM_RCLICK:
  2562. // on the shift+right-click case we want to deselect everything and select just our item if it is
  2563. // not already selected. if we dont do this, then listview gets confused (because he thinks
  2564. // shift means extend selection, but in the right click case it dosent!) and will bring up the
  2565. // context menu for whatever is currently selected instead of what the user just right clicked on.
  2566. if ((GetKeyState(VK_SHIFT) < 0) &&
  2567. (plvn->iItem >= 0) &&
  2568. !(ListView_GetItemState(_hwndListview, plvn->iItem, LVIS_SELECTED) & LVIS_SELECTED))
  2569. {
  2570. // clear any currently slected items
  2571. ListView_SetItemState(_hwndListview, -1, 0, LVIS_SELECTED);
  2572. // select the guy that was just right-clicked on
  2573. ListView_SetItemState(_hwndListview, plvn->iItem, LVIS_SELECTED, LVIS_SELECTED);
  2574. }
  2575. break;
  2576. case LVN_ENDSCROLL:
  2577. {
  2578. // This means we're scrolling. Ignore requests for LVIF_COLUMNS while we're
  2579. // scrolling to speed things up.
  2580. // We don't want to ignore requests for LVIF_COLUMNS when we're owner data, because
  2581. // owner data listviews always callback for info on what to display. (The result would
  2582. // be already-present tileinfo vanishing while scrolling, since we'd be ignoring requests
  2583. // for what to display)
  2584. if ((_fs.ViewMode == FVM_TILE) && !_IsOwnerData())
  2585. {
  2586. SetTimer(_hwndView, DV_IDTIMER_SCROLL_TIMEOUT, 250, NULL);
  2587. if (!_fScrolling)
  2588. {
  2589. _fScrolling = TRUE;
  2590. // We don't reset this on every LVN_ENDSCROLL - only if this is the first time
  2591. // we've scrolled since a stable (non-scrolling) state
  2592. _fRequestedTileDuringScroll = FALSE;
  2593. }
  2594. }
  2595. }
  2596. break;
  2597. case LVN_GETINFOTIP:
  2598. _OnGetInfoTip((NMLVGETINFOTIP *)plvn);
  2599. break;
  2600. case LVN_ITEMACTIVATE:
  2601. if (!_fDisabled)
  2602. {
  2603. //in win95 if user left clicks on one click activate icon and then right
  2604. //clicks on it (within double click time interval), the icon is launched
  2605. //and context menu appears on top of it -- it does not disappear.
  2606. //furthermore the context menu cannot be destroyed but stays on top of
  2607. //any window and items on it are not accessible. to avoid this
  2608. //send cancel mode to itself to destroy context before the icon is
  2609. //launched
  2610. if (_hwndView)
  2611. SendMessage(_hwndView, WM_CANCELMODE, 0, 0);
  2612. _InvokeContextMenuVerbOnSelection(NULL, ((NMITEMACTIVATE *)plvn)->uKeyFlags, CMIC_MASK_FLAG_LOG_USAGE);
  2613. }
  2614. break;
  2615. case NM_CUSTOMDRAW:
  2616. {
  2617. LPNMLVCUSTOMDRAW pcd = (LPNMLVCUSTOMDRAW)plvn;
  2618. switch (pcd->nmcd.dwDrawStage)
  2619. {
  2620. case CDDS_PREPAINT:
  2621. {
  2622. return _fShowCompColor ? CDRF_NOTIFYITEMDRAW : CDRF_DODEFAULT;
  2623. }
  2624. case CDDS_ITEMPREPAINT:
  2625. {
  2626. LRESULT lres = CDRF_DODEFAULT;
  2627. LPCITEMIDLIST pidl = _GetPIDLParam(pcd->nmcd.lItemlParam, (int)pcd->nmcd.dwItemSpec);
  2628. if (pidl)
  2629. {
  2630. DWORD dwAttribs = _Attributes(pidl, SFGAO_COMPRESSED | SFGAO_ENCRYPTED);
  2631. // only one or the other, can never be both
  2632. if (dwAttribs & SFGAO_COMPRESSED)
  2633. {
  2634. // default value of Blue
  2635. pcd->clrText = GetRegColor(RGB(0, 0, 255), TEXT("AltColor"), &g_crAltColor);
  2636. }
  2637. else if (dwAttribs & SFGAO_ENCRYPTED)
  2638. {
  2639. // default value Luna Mid Green
  2640. pcd->clrText = GetRegColor(RGB(19, 146, 13), TEXT("AltEncryptionColor"), &g_crAltEncryptedColor);
  2641. }
  2642. }
  2643. if (_IsImageMode() && pcd->nmcd.hdc && (_dwRecClrDepth <= 8))
  2644. {
  2645. HPALETTE hpal = NULL;
  2646. if (SUCCEEDED(_GetBrowserPalette(&hpal)))
  2647. {
  2648. // Since we are a child of the browser, we should always take a back seat to thier palette selection
  2649. _hpalOld = SelectPalette(pcd->nmcd.hdc, hpal, TRUE);
  2650. RealizePalette(pcd->nmcd.hdc);
  2651. lres |= CDRF_NOTIFYPOSTPAINT;
  2652. }
  2653. }
  2654. return lres;
  2655. }
  2656. case CDDS_ITEMPOSTPAINT:
  2657. if (_IsImageMode() && _hpalOld && pcd->nmcd.hdc)
  2658. {
  2659. SelectPalette(pcd->nmcd.hdc, _hpalOld, TRUE);
  2660. _hpalOld = NULL;
  2661. }
  2662. break;
  2663. }
  2664. }
  2665. return CDRF_DODEFAULT;
  2666. case LVN_BEGINDRAG:
  2667. case LVN_BEGINRDRAG:
  2668. if (_fDisabled)
  2669. return FALSE; /* commdlg doesn't want user dragging */
  2670. return _OnBeginDrag(plvn);
  2671. case LVN_ITEMCHANGING:
  2672. if (_fDisabled)
  2673. return TRUE;
  2674. break;
  2675. // Something changed in the listview. Delete any data that
  2676. // we might have cached away.
  2677. case LVN_ITEMCHANGED:
  2678. if (plvn->uChanged & LVIF_STATE)
  2679. {
  2680. if (!_fIgnoreItemChanged)
  2681. {
  2682. // The rest only cares about SELCHANGE messages (avoid LVIS_DRAGSELECT, etc)
  2683. if ((plvn->uNewState ^ plvn->uOldState) & (LVIS_SELECTED | LVIS_FOCUSED))
  2684. {
  2685. //if we are the drag source then dont send selection change message
  2686. if (!_bDragSource)
  2687. {
  2688. _OnStateChange(CDBOSC_SELCHANGE);
  2689. }
  2690. OnLVSelectionChange(plvn);
  2691. }
  2692. else if ((plvn->uNewState ^ plvn->uOldState) & (LVIS_STATEIMAGEMASK))
  2693. {
  2694. if (!_bDragSource)
  2695. {
  2696. _OnStateChange(CDBOSC_STATECHANGE);
  2697. }
  2698. }
  2699. }
  2700. }
  2701. break;
  2702. // owner data state changed: e.g. search results
  2703. case LVN_ODSTATECHANGED:
  2704. {
  2705. NM_ODSTATECHANGE *pnm = (NM_ODSTATECHANGE *)plvn;
  2706. // for now handle only selection changes
  2707. if ((pnm->uOldState ^ pnm->uNewState) & (LVIS_SELECTED | LVIS_FOCUSED))
  2708. {
  2709. _OnLVSelectionChange(-1, pnm->uOldState, pnm->uNewState, 0);
  2710. }
  2711. }
  2712. break;
  2713. case LVN_DELETEITEM:
  2714. OnListViewDelete(plvn->iItem, (LPITEMIDLIST)plvn->lParam, TRUE);
  2715. break;
  2716. case LVN_COLUMNCLICK:
  2717. // allow clicking on columns to set the sort order
  2718. if (_fGroupView)
  2719. {
  2720. BOOL fAllowArrange = TRUE;
  2721. UINT iRealColumn = _VisibleToRealCol(plvn->iSubItem);
  2722. SHCOLUMNID scid;
  2723. if (SUCCEEDED(_pshf2->MapColumnToSCID(iRealColumn, &scid)))
  2724. {
  2725. ICategoryProvider* pcp = NULL;
  2726. if (SUCCEEDED(_pshf->CreateViewObject(NULL, IID_PPV_ARG(ICategoryProvider, &pcp))))
  2727. {
  2728. // returns S_FALSE to remove.
  2729. if (S_FALSE == pcp->CanCategorizeOnSCID(&scid))
  2730. {
  2731. fAllowArrange = FALSE;
  2732. }
  2733. }
  2734. }
  2735. if (fAllowArrange)
  2736. _ArrangeBy(iRealColumn + SFVIDM_GROUPSFIRST);
  2737. }
  2738. else if (_pshf2 || _psd || HasCB())
  2739. {
  2740. LPARAM lParamSort = _vs._lParamSort;
  2741. LONG iLastColumnClick = _vs._iLastColumnClick,
  2742. iLastSortDirection = _vs._iDirection; // push sort state
  2743. // Folder doesn't know which columns are on or off, so communication with folder uses real col #s
  2744. UINT iRealColumn = _VisibleToRealCol(plvn->iSubItem);
  2745. // seeral ways to do this... each can defer to the
  2746. // ultimate default that is defview calling itself.
  2747. HRESULT hr = S_FALSE;
  2748. if (_psd)
  2749. hr = _psd->ColumnClick(iRealColumn);
  2750. if (hr != S_OK)
  2751. hr = CallCB(SFVM_COLUMNCLICK, iRealColumn, 0);
  2752. if (hr != S_OK)
  2753. hr = Rearrange(iRealColumn);
  2754. // Allows iLastColumnClick to stay valid during the above calls
  2755. if (SUCCEEDED(hr))
  2756. _vs._iLastColumnClick = iRealColumn;
  2757. else
  2758. {
  2759. // We failed somewhere so pop the sort state.
  2760. _vs._iDirection = iLastSortDirection;
  2761. _vs._iLastColumnClick = (int)_vs._lParamSort;
  2762. _vs._lParamSort = lParamSort ;
  2763. _SetSortFeedback();
  2764. _vs._iLastColumnClick = iLastColumnClick;
  2765. }
  2766. }
  2767. break;
  2768. case LVN_KEYDOWN:
  2769. HandleKeyDown(((LV_KEYDOWN *)plvn));
  2770. break;
  2771. #define plvdi ((LV_DISPINFO *)plvn)
  2772. case LVN_BEGINLABELEDIT:
  2773. {
  2774. LPCITEMIDLIST pidl = _GetPIDLParam(plvdi->item.lParam, plvdi->item.iItem);
  2775. if (!pidl || !_Attributes(pidl, SFGAO_CANRENAME))
  2776. {
  2777. MessageBeep(0);
  2778. return TRUE; // Don't allow label edit
  2779. }
  2780. _fInLabelEdit = TRUE;
  2781. HWND hwndEdit = ListView_GetEditControl(_hwndListview);
  2782. if (hwndEdit)
  2783. {
  2784. int cchMax = 0;
  2785. CallCB(SFVM_GETCCHMAX, (WPARAM)pidl, (LPARAM)&cchMax);
  2786. if (cchMax)
  2787. {
  2788. ASSERT(cchMax < 1024);
  2789. SendMessage(hwndEdit, EM_LIMITTEXT, cchMax, 0);
  2790. }
  2791. TCHAR szName[MAX_PATH];
  2792. if (SUCCEEDED(DisplayNameOf(_pshf, pidl, SHGDN_INFOLDER | SHGDN_FOREDITING, szName, ARRAYSIZE(szName))))
  2793. {
  2794. SetWindowText(hwndEdit, szName);
  2795. }
  2796. SHLimitInputEdit(hwndEdit, _pshf);
  2797. }
  2798. }
  2799. break;
  2800. case LVN_ENDLABELEDIT:
  2801. _fInLabelEdit = FALSE;
  2802. if (plvdi->item.pszText)
  2803. {
  2804. LPCITEMIDLIST pidl = _GetPIDLParam(plvdi->item.lParam, plvdi->item.iItem);
  2805. if (pidl)
  2806. {
  2807. // this set site is questionable as folder should not have any state
  2808. // associated with the view. but this is needed for FTP so it can
  2809. // do an EnableModless for it's UI
  2810. IUnknown_SetSite(_pshf, SAFECAST(this, IOleCommandTarget *));
  2811. // Clone the pidl since isf->SetNameOf can result in a synchronous update item that
  2812. // will free the listview owned pidl.
  2813. LPITEMIDLIST pidlOldName = ILClone(pidl);
  2814. if (pidlOldName)
  2815. {
  2816. LPITEMIDLIST pidlNewName = NULL; // paranoid about bad SetNameOf() impls
  2817. if (SUCCEEDED(_pshf->SetNameOf(_hwndMain, pidlOldName, plvdi->item.pszText, SHGDN_INFOLDER, &pidlNewName)))
  2818. {
  2819. ASSERT(NULL != pidlNewName); // folders need to implement this
  2820. if (pidlNewName)
  2821. {
  2822. _DoBulkRename(pidlNewName);
  2823. ILFree(pidlNewName);
  2824. }
  2825. SHChangeNotifyHandleEvents();
  2826. _OnStateChange(CDBOSC_RENAME);
  2827. }
  2828. else
  2829. {
  2830. SendMessage(_hwndListview, LVM_EDITLABEL, plvdi->item.iItem, (LPARAM)plvdi->item.pszText);
  2831. }
  2832. ILFree(pidlOldName);
  2833. }
  2834. IUnknown_SetSite(_pshf, NULL);
  2835. }
  2836. }
  2837. else
  2838. {
  2839. // The user canceled. so return TRUE to let things like the mouse
  2840. // click be processed.
  2841. return TRUE;
  2842. }
  2843. break;
  2844. case LVN_GETDISPINFO:
  2845. return _GetDisplayInfo(plvdi);
  2846. case LVN_ODFINDITEM:
  2847. // We are owner data so we need to find the item for the user...
  2848. {
  2849. int iItem = -1;
  2850. if (SUCCEEDED(CallCB(SFVM_ODFINDITEM, (WPARAM)&iItem, (LPARAM)plvn)))
  2851. return iItem;
  2852. return -1; // Not Found
  2853. }
  2854. case LVN_ODCACHEHINT:
  2855. // Just a hint we don't care about return values
  2856. CallCB(SFVM_ODCACHEHINT, 0, (LPARAM)plvn);
  2857. break;
  2858. case LVN_GETEMPTYTEXT:
  2859. if (HasCB())
  2860. {
  2861. if ((plvdi->item.mask & LVIF_TEXT) &&
  2862. SUCCEEDED(CallCB(SFVM_GETEMPTYTEXT, (WPARAM)(plvdi->item.cchTextMax), (LPARAM)(plvdi->item.pszText))))
  2863. return TRUE;
  2864. }
  2865. break;
  2866. }
  2867. #undef lpdi
  2868. #undef plvdi
  2869. return 0;
  2870. }
  2871. // FEATURE -- implement enabling/disabling of other toolbar buttons. We can enable/disable
  2872. // based on the current selection, but the problem is that some of the buttons work
  2873. // for other guys when defview doesn't have focus. Specifically, cut/copy/paste work
  2874. // for the folders pane. If we're going to enable/disable these buttons based on the
  2875. // selection, then we'll need to have a mechanism that lets the active band (such as
  2876. // folders) also have a say about the button state. That is too much work right now.
  2877. static const UINT c_BtnCmds[] =
  2878. {
  2879. SFVIDM_EDIT_COPYTO,
  2880. SFVIDM_EDIT_MOVETO,
  2881. #ifdef ENABLEDISABLEBUTTONS
  2882. SFVIDM_EDIT_COPY,
  2883. SFVIDM_EDIT_CUT,
  2884. #endif
  2885. };
  2886. static const DWORD c_BtnAttr[] =
  2887. {
  2888. SFGAO_CANCOPY,
  2889. SFGAO_CANMOVE,
  2890. #ifdef ENABLEDISABLEBUTTONS
  2891. SFGAO_CANCOPY,
  2892. SFGAO_CANMOVE,
  2893. #endif
  2894. };
  2895. #define SFGAO_RELEVANT (SFGAO_CANCOPY | SFGAO_CANMOVE)
  2896. // Description:
  2897. // Called by toolbar infrastructure to determine whether to display a given
  2898. // toolbar button in the "enabled" or "disabled" state.
  2899. //
  2900. // Return:
  2901. // TRUE display toolbar button in enabled state
  2902. // FALSE display toolbar button in disabled state
  2903. //
  2904. BOOL CDefView::_ShouldEnableToolbarButton(UINT uiCmd, DWORD dwAttr, int iIndex)
  2905. {
  2906. COMPILETIME_ASSERT(sizeof(c_BtnCmds) == sizeof(c_BtnAttr));
  2907. BOOL bEnable;
  2908. switch (uiCmd)
  2909. {
  2910. case SFVIDM_VIEW_VIEWMENU:
  2911. bEnable = !_fBarrierDisplayed;
  2912. break;
  2913. default:
  2914. {
  2915. DWORD dwBtnAttr;
  2916. if (iIndex != -1)
  2917. {
  2918. // Caller was nice and figured out dest index for us
  2919. dwBtnAttr = c_BtnAttr[iIndex];
  2920. }
  2921. else
  2922. {
  2923. // Look for the command ourselves
  2924. dwBtnAttr = SHSearchMapInt((int*)c_BtnCmds, (int*)c_BtnAttr, ARRAYSIZE(c_BtnCmds), uiCmd);
  2925. if (dwBtnAttr == -1)
  2926. {
  2927. // We don't care about this button, just enable it.
  2928. return TRUE;
  2929. }
  2930. }
  2931. // Disable any button we care about while listview is inactive.
  2932. bEnable = BOOLIFY(dwAttr & dwBtnAttr) && _fHasListViewFocus;
  2933. break;
  2934. }
  2935. }
  2936. return bEnable;
  2937. }
  2938. // As a perf enhancement, we cache the attributes of the currently selected
  2939. // files/folders in a FS view only. This is to avoid n^2 traversals of the
  2940. // selected items as we select/unselect them. These cached attributes
  2941. // should not be used for anything other than determining toolbar button
  2942. // states and should be revisited if we add toolbar buttons that care about
  2943. // much more than the attributes used by Move to & Copy to.
  2944. BOOL CDefView::_GetCachedToolbarSelectionAttrs(ULONG *pdwAttr)
  2945. {
  2946. BOOL fResult = FALSE;
  2947. CLSID clsid;
  2948. HRESULT hr = IUnknown_GetClassID(_pshf, &clsid);
  2949. if (SUCCEEDED(hr) && IsEqualGUID(CLSID_ShellFSFolder, clsid))
  2950. {
  2951. UINT iCount;
  2952. if (SUCCEEDED(GetSelectedCount(&iCount)) &&
  2953. (iCount > 0) && (_uCachedSelCount > 0))
  2954. {
  2955. *pdwAttr = _uCachedSelAttrs;
  2956. fResult = TRUE;
  2957. }
  2958. }
  2959. return fResult;
  2960. }
  2961. void CDefView::_SetCachedToolbarSelectionAttrs(ULONG dwAttrs)
  2962. {
  2963. if (SUCCEEDED(GetSelectedCount(&_uCachedSelCount)))
  2964. _uCachedSelAttrs = dwAttrs;
  2965. else
  2966. _uCachedSelCount = 0;
  2967. }
  2968. void CDefView::_EnableDisableTBButtons()
  2969. {
  2970. if (!IsEqualGUID(_clsid, GUID_NULL))
  2971. {
  2972. IExplorerToolbar *piet;
  2973. if (SUCCEEDED(IUnknown_QueryService(_psb, SID_SExplorerToolbar, IID_PPV_ARG(IExplorerToolbar, &piet))))
  2974. {
  2975. ULONG dwAttr;
  2976. if (!_GetCachedToolbarSelectionAttrs(&dwAttr))
  2977. dwAttr = _AttributesFromSel(SFGAO_RELEVANT);
  2978. for (int i = 0; i < ARRAYSIZE(c_BtnCmds); i++)
  2979. _EnableToolbarButton(piet, c_BtnCmds[i], _ShouldEnableToolbarButton(c_BtnCmds[i], dwAttr, i));
  2980. _SetCachedToolbarSelectionAttrs(dwAttr);
  2981. piet->Release();
  2982. }
  2983. }
  2984. }
  2985. // Description:
  2986. // Enables or disables a specified button on the toolbar.
  2987. //
  2988. void CDefView::EnableToolbarButton(UINT uiCmd, BOOL bEnable)
  2989. {
  2990. if (!IsEqualGUID(_clsid, GUID_NULL))
  2991. {
  2992. IExplorerToolbar *piet;
  2993. if (SUCCEEDED(IUnknown_QueryService(_psb, SID_SExplorerToolbar, IID_PPV_ARG(IExplorerToolbar, &piet))))
  2994. {
  2995. _EnableToolbarButton(piet, uiCmd, bEnable);
  2996. piet->Release();
  2997. }
  2998. }
  2999. }
  3000. // Description:
  3001. // Enables or disables a specified button on the toolbar.
  3002. //
  3003. // Note:
  3004. // This is an _internal_ method only.
  3005. // External calls should use EnableToolbarButton().
  3006. // Caller is responsible for ensuring this object uses IExplorerToolbar mechanism.
  3007. //
  3008. void CDefView::_EnableToolbarButton(IExplorerToolbar *piet, UINT uiCmd, BOOL bEnable)
  3009. {
  3010. ASSERT(!IsEqualGUID(_clsid, GUID_NULL)); // Required or piet cannot be valid.
  3011. ASSERT(piet); // Required or we're not using IExplorerToolbar mechanism.
  3012. UINT uiState;
  3013. if (SUCCEEDED(piet->GetState(&_clsid, uiCmd, &uiState)))
  3014. {
  3015. if (bEnable)
  3016. uiState |= TBSTATE_ENABLED;
  3017. else
  3018. uiState &= ~TBSTATE_ENABLED;
  3019. piet->SetState(&_clsid, uiCmd, uiState);
  3020. }
  3021. }
  3022. void CDefView::_OnContentsChanged()
  3023. {
  3024. // use a timer to delay sending a gazillion content change messages to automation.
  3025. // todo: see what duiview has to do with this stuff.
  3026. // only fire event if someone is listening
  3027. if (_pauto || _pDUIView)
  3028. {
  3029. // delay for 100ms
  3030. SetTimer(_hwndView, DV_IDTIMER_NOTIFY_AUTOMATION_CONTENTSCHANGED, 100, NULL);
  3031. }
  3032. if (!_pDUIView)
  3033. {
  3034. _fRcvdContentsChangeBeforeDuiViewCreated = TRUE;
  3035. }
  3036. }
  3037. void CDefView::_OnDelayedContentsChanged()
  3038. {
  3039. KillTimer(_hwndView, DV_IDTIMER_NOTIFY_AUTOMATION_CONTENTSCHANGED);
  3040. // update dui, would be better if there were different handlers in CDUIView
  3041. // but go through selection changed for now.
  3042. ATOMICRELEASE(_pSelectionShellItemArray);
  3043. _pSelectionShellItemArray = _CreateSelectionShellItemArray();
  3044. if (_pDUIView)
  3045. {
  3046. if (_fBarrierDisplayed != _QueryBarricadeState())
  3047. {
  3048. //
  3049. // Yet another DUI special-case.
  3050. // If the barrier state has changed, we need to
  3051. // tell DUIView about it so that the DUI right-pane
  3052. // content is reconstructed. This is required to make
  3053. // Control Panel update it's right-pane content when
  3054. // webview is turned on/off.
  3055. //
  3056. _fBarrierDisplayed = !_fBarrierDisplayed;
  3057. _pDUIView->EnableBarrier (_fBarrierDisplayed);
  3058. }
  3059. _pDUIView->OnContentsChange(_pSelectionShellItemArray);
  3060. }
  3061. _FireEvent(DISPID_CONTENTSCHANGED);
  3062. }
  3063. // WARNING: don't add any code here that is expensive in anyway!
  3064. // we get many many of these notifies and if we slow this routine down
  3065. // we mess select all and large selection perf.
  3066. //
  3067. // you can add expensive code to the WM_DSV_SENDSELECTIONCHANGED handler _OnSelectionChanged,
  3068. // that happens after all of the sel change notifies go through.
  3069. //
  3070. // or you can add really expensive code to the double-click-timeout delayed _OnDelayedSelectionChange.
  3071. //
  3072. void CDefView::OnLVSelectionChange(NM_LISTVIEW *plvn)
  3073. {
  3074. _OnLVSelectionChange(plvn->iItem, plvn->uOldState, plvn->uNewState, plvn->lParam);
  3075. }
  3076. void CDefView::_OnLVSelectionChange(int iItem, UINT uOldState, UINT uNewState, LPARAM lParam)
  3077. {
  3078. // Do selection changed stuff on a selection change only
  3079. if ((uOldState ^ uNewState) & LVIS_SELECTED)
  3080. {
  3081. // Tell the defview client that the selection may have changed
  3082. SFVM_SELCHANGE_DATA dvsci;
  3083. dvsci.uNewState = uNewState;
  3084. dvsci.uOldState = uOldState;
  3085. dvsci.lParamItem = lParam;
  3086. CallCB(SFVM_SELCHANGE, MAKEWPARAM(SFVIDM_CLIENT_FIRST, iItem), (LPARAM)&dvsci);
  3087. }
  3088. // Notify the dispach that the focus changed..
  3089. _PostSelectionChangedMessage(uOldState ^ uNewState);
  3090. }
  3091. void CDefView::_PostSelectionChangedMessage(UINT uSelectionStateChanged)
  3092. {
  3093. if (!_fSelectionChangePending)
  3094. {
  3095. _uSelectionStateChanged = uSelectionStateChanged;
  3096. // RACE CONDITION FIX (edwardp & buzzr)
  3097. // It is imperative to set _fSelectionChangePending _before_ posting
  3098. // WM_DSV_SENDSELECTIONCHANGED. Otherwise, a race condition ensues
  3099. // whereby we could handle the message via _OnSelectionChanged()
  3100. // whose first line sets _fSelectionChangePending = FALSE before we
  3101. // have set it to TRUE here. This means _fSelectionChangePending
  3102. // will never again be set to FALSE (since the this thread will be
  3103. // rescheduled, set it to TRUE, and the action of clearing it will
  3104. // already be past). This was happening with 100% reproducability
  3105. // with our background CGetCommandStateTask for WIA devices. The
  3106. // symptom most noticeable was that the DUI pane (task lists and
  3107. // details) no longer updated with each selection change.
  3108. _fSelectionChangePending = TRUE;
  3109. PostMessage(_hwndView, WM_DSV_SENDSELECTIONCHANGED, 0, 0);
  3110. }
  3111. else
  3112. {
  3113. _uSelectionStateChanged |= uSelectionStateChanged;
  3114. }
  3115. }
  3116. void CDefView::_OnSelectionChanged() // handles WM_DSV_SENDSELECTIONCHANGED
  3117. {
  3118. _fSelectionChangePending = FALSE; // release this first so code we call doesn't think we're "pending" any more
  3119. if (_uSelectionStateChanged & LVIS_SELECTED)
  3120. {
  3121. // Get and cache the data object for the current selection
  3122. ATOMICRELEASE(_pSelectionShellItemArray);
  3123. _pSelectionShellItemArray = _CreateSelectionShellItemArray();
  3124. // Update DUIView
  3125. if (_pDUIView)
  3126. _pDUIView->OnSelectionChange(_pSelectionShellItemArray);
  3127. _UpdateStatusBar(FALSE);
  3128. _EnableDisableTBButtons();
  3129. }
  3130. // Only fire selection change events if someone is listening
  3131. // and if the selection changed event was not caused by going into Edit mode (why?)
  3132. if (_pauto && !_fInLabelEdit)
  3133. {
  3134. // Send out the selection changed notification to the automation after a delay.
  3135. if (!_bAutoSelChangeTimerSet)
  3136. {
  3137. _bAutoSelChangeTimerSet = TRUE;
  3138. _uAutoSelChangeState = _uSelectionStateChanged;
  3139. }
  3140. else
  3141. {
  3142. _uAutoSelChangeState |= _uSelectionStateChanged;
  3143. }
  3144. // But not too long, since parts of our UI update when they receive this event.
  3145. // (Update the timer every time to keep delaying it during rapid selection change events)
  3146. SetTimer(_hwndView, DV_IDTIMER_NOTIFY_AUTOMATION_SELCHANGE, GetDoubleClickTime()/2, NULL);
  3147. }
  3148. }
  3149. void CDefView::_OnDelayedSelectionChange() // handles DV_IDTIMER_NOTIFY_AUTOMATION_SELCHANGE
  3150. {
  3151. if (_bAutoSelChangeTimerSet)
  3152. {
  3153. KillTimer(_hwndView, DV_IDTIMER_NOTIFY_AUTOMATION_SELCHANGE);
  3154. if (_uAutoSelChangeState & LVIS_SELECTED)
  3155. _FireEvent(DISPID_SELECTIONCHANGED);
  3156. if (_uAutoSelChangeState & LVIS_FOCUSED)
  3157. _FireEvent(DISPID_FOCUSCHANGED);
  3158. _bAutoSelChangeTimerSet = FALSE;
  3159. }
  3160. }
  3161. void CDefView::_PostNoItemStateChangedMessage()
  3162. {
  3163. if (_pauto && !_fNoItemStateChangePending)
  3164. {
  3165. PostMessage(_hwndView, WM_DSV_SENDNOITEMSTATECHANGED, 0, 0);
  3166. _fNoItemStateChangePending = TRUE;
  3167. }
  3168. }
  3169. void CDefView::_OnNoItemStateChanged()
  3170. {
  3171. _FireEvent(DISPID_NOITEMSTATE_CHANGED);
  3172. _fNoItemStateChangePending = FALSE;
  3173. }
  3174. void CDefView::_PostEnumDoneMessage()
  3175. {
  3176. PostMessage(_hwndView, WM_DSV_FILELISTENUMDONE, 0, 0);
  3177. }
  3178. void CDefView::_PostFillDoneMessage()
  3179. {
  3180. _ShowSearchUI(TRUE);
  3181. PostMessage(_hwndView, WM_DSV_FILELISTFILLDONE, 0, 0);
  3182. }
  3183. void CDefView::_OnEnumDoneMessage()
  3184. {
  3185. if (_pauto)
  3186. _FireEvent(DISPID_FILELISTENUMDONE);
  3187. if (_pfnEnumReadyCallback)
  3188. _pfnEnumReadyCallback(_pvEnumCallbackData);
  3189. }
  3190. #define IN_VIEW_BMP 0x8000
  3191. #define EXT_VIEW_GOES_HERE 0x4000
  3192. #define PRIVATE_TB_FLAGS (IN_VIEW_BMP | EXT_VIEW_GOES_HERE)
  3193. #define IN_STD_BMP 0x0000
  3194. LRESULT CDefView::_OnNotify(NMHDR *pnm)
  3195. {
  3196. switch (pnm->idFrom)
  3197. {
  3198. case ID_LISTVIEW:
  3199. return _OnLVNotify((NM_LISTVIEW *)pnm);
  3200. case FCIDM_TOOLBAR:
  3201. return _TBNotify(pnm);
  3202. default:
  3203. switch (pnm->code)
  3204. {
  3205. case TTN_NEEDTEXT:
  3206. #define ptt ((LPTOOLTIPTEXT)pnm)
  3207. _GetToolTipText(ptt->hdr.idFrom, ptt->szText, ARRAYSIZE(ptt->szText));
  3208. #undef ptt
  3209. break;
  3210. case NM_RCLICK:
  3211. if (GetParent(pnm->hwndFrom) == _hwndListview)
  3212. {
  3213. POINT p;
  3214. GetMsgPos(&p);
  3215. _DoColumnsMenu(p.x, p.y);
  3216. return 1; // To keep normal context menu from appearing
  3217. }
  3218. }
  3219. }
  3220. return 0;
  3221. }
  3222. // ask the folder for the default column state
  3223. DWORD CDefView::_DefaultColumnState(UINT iCol)
  3224. {
  3225. DWORD dwState;
  3226. if (_pshf2)
  3227. {
  3228. if (FAILED(_pshf2->GetDefaultColumnState(iCol, &dwState)))
  3229. {
  3230. dwState = SHCOLSTATE_ONBYDEFAULT; // deal with E_NOTIMPL GetDefaultColumState implementations
  3231. }
  3232. }
  3233. else
  3234. {
  3235. dwState = SHCOLSTATE_ONBYDEFAULT;
  3236. }
  3237. return dwState;
  3238. }
  3239. // SHCOLSTATE_ONBYDEFAULT
  3240. //
  3241. // columns that are turn on for this view (are displayed in the UI)
  3242. BOOL CDefView::_IsDetailsColumn(UINT iCol)
  3243. {
  3244. return (_vs.GetColumnState(iCol) & SHCOLSTATE_ONBYDEFAULT) ? TRUE : FALSE;
  3245. }
  3246. BOOL CDefView::_IsColumnInListView(UINT iCol)
  3247. {
  3248. return ((_vs.GetColumnState(iCol) & SHCOLSTATE_ONBYDEFAULT) ||
  3249. (_vs.GetTransientColumnState(iCol) & SHTRANSCOLSTATE_TILEVIEWCOLUMN)) ? TRUE : FALSE;
  3250. }
  3251. BOOL CDefView::_IsTileViewColumn(UINT iCol)
  3252. {
  3253. return (_vs.GetTransientColumnState(iCol) & SHTRANSCOLSTATE_TILEVIEWCOLUMN) ? TRUE : FALSE;
  3254. }
  3255. // SHCOLSTATE_HIDDEN
  3256. //
  3257. // columns that should not be displayed in the UI, but are exposed from
  3258. // the psf2->GetDetailsEx(). this is a way to have programtic access to properties
  3259. // that don't show up in details view
  3260. BOOL CDefView::_IsColumnHidden(UINT uCol)
  3261. {
  3262. return (_vs.GetColumnState(uCol) & SHCOLSTATE_HIDDEN) ? TRUE : FALSE;
  3263. }
  3264. #define COL_CM_MAXITEMS 25 // how many item show up in context menu before more ... is inserted
  3265. HRESULT CDefView::AddColumnsToMenu(HMENU hm, DWORD dwBase)
  3266. {
  3267. BOOL bNeedMoreMenu = FALSE;
  3268. HRESULT hr = E_FAIL;
  3269. if (_vs._hdsaColumns)
  3270. {
  3271. AppendMenu(hm, MF_STRING | MF_CHECKED | MF_GRAYED, dwBase, _vs.GetColumnName(0));
  3272. for (UINT i = 1; i < min(COL_CM_MAXITEMS, _vs.GetColumnCount()); i++)
  3273. {
  3274. DWORD dwFlags = _vs.GetColumnState(i);
  3275. if (!(dwFlags & SHCOLSTATE_HIDDEN))
  3276. {
  3277. if (dwFlags & SHCOLSTATE_SECONDARYUI)
  3278. bNeedMoreMenu = TRUE;
  3279. else
  3280. AppendMenu(hm, MF_STRING | (dwFlags & SHCOLSTATE_ONBYDEFAULT) ? MF_CHECKED : 0,
  3281. dwBase + i, _vs.GetColumnName(i));
  3282. }
  3283. }
  3284. if (bNeedMoreMenu || (_vs.GetColumnCount() > COL_CM_MAXITEMS))
  3285. {
  3286. TCHAR szMore[MAX_COLUMN_NAME_LEN];
  3287. LoadString(HINST_THISDLL, IDS_COL_CM_MORE, szMore, ARRAYSIZE(szMore));
  3288. AppendMenu(hm, MF_SEPARATOR, 0, NULL);
  3289. AppendMenu(hm, MF_STRING, SFVIDM_VIEW_COLSETTINGS, szMore);
  3290. }
  3291. hr = S_OK;
  3292. }
  3293. return hr;
  3294. }
  3295. UINT CDefView::_RealToVisibleCol(UINT iReal)
  3296. {
  3297. ASSERT(_bLoadedColumns && _vs.GetColumnCount());
  3298. int iVisible = -1; // start here to get zero based result
  3299. int cMax = min(_vs.GetColumnCount() - 1, iReal);
  3300. for (int i = 0; i <= cMax; i++)
  3301. {
  3302. if (_IsColumnInListView(i))
  3303. {
  3304. iVisible++;
  3305. }
  3306. }
  3307. ASSERT(-1 != iVisible);
  3308. return iVisible;
  3309. }
  3310. // map listview (zero based) column indexes
  3311. // indexs (zero based)
  3312. UINT CDefView::_VisibleToRealCol(UINT iVisible)
  3313. {
  3314. ASSERT(_bLoadedColumns && _vs.GetColumnCount());
  3315. for (UINT i = 0, cVisibleSeen = 0; i < _vs.GetColumnCount(); i++)
  3316. {
  3317. if (_IsColumnInListView(i))
  3318. {
  3319. if (cVisibleSeen == iVisible)
  3320. {
  3321. return i;
  3322. }
  3323. cVisibleSeen++;
  3324. }
  3325. }
  3326. ASSERT(0); // should never get a vis col not in the real
  3327. return 0;
  3328. }
  3329. void CDefView::_AddTileColumn(UINT uCol)
  3330. {
  3331. if (_IsColumnInListView(uCol))
  3332. {
  3333. // All we need to do is make sure it's marked as a tile column
  3334. _vs.SetTransientColumnState(uCol, SHTRANSCOLSTATE_TILEVIEWCOLUMN, SHTRANSCOLSTATE_TILEVIEWCOLUMN);
  3335. return;
  3336. }
  3337. _vs.SetTransientColumnState(uCol, SHTRANSCOLSTATE_TILEVIEWCOLUMN, SHTRANSCOLSTATE_TILEVIEWCOLUMN);
  3338. // Now that we set the transient state, we can get the new visible column index
  3339. // for this guy, and add it to the listview.
  3340. UINT uColVis = _RealToVisibleCol(uCol);
  3341. _AddColumnToListView(uCol, uColVis);
  3342. // We now need to reset the tile info for each item. We can make an optimization:
  3343. // if this column was added at the end (i.e. biggest visible column), it won't affect
  3344. // any of the current tiles, so we don't need to do this. Passing -1 gives us the
  3345. // largest visible index.
  3346. if (_RealToVisibleCol(-1) != uColVis)
  3347. {
  3348. _ResetTileInfo(uColVis, TRUE);
  3349. }
  3350. }
  3351. // Remove all columns that were added because of tileview (unless they were also
  3352. // added for other reasons).
  3353. // Note: This should only be called when leaving tileview, since we do not reset the
  3354. // items' tileinfo.
  3355. void CDefView::_RemoveTileColumns()
  3356. {
  3357. for (UINT uCol = 0; uCol < _vs.GetColumnCount(); uCol++)
  3358. {
  3359. if (_IsTileViewColumn(uCol))
  3360. {
  3361. // First nuke the tile bit.
  3362. UINT uColVis = _RealToVisibleCol(uCol);
  3363. _vs.SetTransientColumnState(uCol, SHTRANSCOLSTATE_TILEVIEWCOLUMN, 0);
  3364. // Then go ahead and remove it from listview if it wasn't a details column
  3365. if (!_IsDetailsColumn(uCol))
  3366. {
  3367. ListView_DeleteColumn(_hwndListview, uColVis);
  3368. }
  3369. }
  3370. }
  3371. }
  3372. // This method resets the tileinfo for each item in the listview, based on which
  3373. // visible column we just added or removed.
  3374. // uColVis = the visible column that was added or removed.
  3375. // Note: This must be called prior to there being any tileinfo in the listview containing
  3376. // a reference to this new column.
  3377. void CDefView::_ResetTileInfo(UINT uColVis, BOOL bAdded)
  3378. {
  3379. if (!_IsOwnerData())
  3380. {
  3381. UINT rguColumns[TILEVIEWLINES];
  3382. for (int i = 0; i < ListView_GetItemCount(_hwndListview); i++)
  3383. {
  3384. UINT uColBoundary = uColVis;
  3385. LVITEM lvi;
  3386. lvi.mask = LVIF_COLUMNS | LVIF_NORECOMPUTE;
  3387. lvi.iSubItem = 0;
  3388. lvi.iItem = i;
  3389. lvi.cColumns = ARRAYSIZE(rguColumns);
  3390. lvi.puColumns = rguColumns;
  3391. if (!ListView_GetItem(_hwndListview, &lvi))
  3392. continue;
  3393. if ((lvi.cColumns == 0) || (lvi.cColumns == I_COLUMNSCALLBACK))
  3394. {
  3395. continue;
  3396. }
  3397. ASSERT(lvi.cColumns <= ARRAYSIZE(rguColumns)); // If for some reason listview has more, there's a problem
  3398. UINT *puColumn = lvi.puColumns;
  3399. BOOL bChange = FALSE;
  3400. // Adjust the column numbers as needed: up for added, down for removed.
  3401. int iIncDec = bAdded ? 1 : -1;
  3402. if (!bAdded)
  3403. {
  3404. // What is this doing? If we've added a column X, we need to adjust columns
  3405. // from X on up. If we've removed a column X, we need to adjust columns from
  3406. // X+1 on up. So basically, instead of doing (*puColumn > uColBoundary), we're
  3407. // doing (*puColumn >= (uColBoundary+1)). So we can do the same ">=" expression
  3408. // whether or not bAdded, avoiding an if check in the loop.
  3409. uColBoundary++;
  3410. }
  3411. for (UINT uCol = 0; uCol < lvi.cColumns; uCol++, puColumn++)
  3412. {
  3413. if (*puColumn >= uColBoundary)
  3414. {
  3415. (*puColumn) = (UINT)(iIncDec + (int)(*puColumn)); // Inc or dec.
  3416. bChange = TRUE;
  3417. }
  3418. }
  3419. if (bChange) // If there were any changes, set the ti back.
  3420. {
  3421. LVTILEINFO ti;
  3422. ti.cbSize = sizeof(ti);
  3423. ti.iItem = lvi.iItem;
  3424. ti.cColumns = lvi.cColumns;
  3425. ti.puColumns = lvi.puColumns;
  3426. ListView_SetTileInfo(_hwndListview, &ti);
  3427. }
  3428. }
  3429. }
  3430. }
  3431. // Called when leaving tileview, this "cleans the slate" so that we reload the
  3432. // columns properly when re-entering tileview at a later time.
  3433. void CDefView::_RemoveTileInfo()
  3434. {
  3435. if (!_IsOwnerData())
  3436. {
  3437. for (int i = 0; i < ListView_GetItemCount(_hwndListview); i++)
  3438. {
  3439. LVTILEINFO ti = {0};
  3440. ti.cbSize = sizeof(ti);
  3441. ti.iItem = i;
  3442. ti.cColumns = I_COLUMNSCALLBACK;
  3443. ListView_SetTileInfo(_hwndListview, &ti);
  3444. }
  3445. }
  3446. }
  3447. // uCol is a real column number, not visible column number
  3448. // This method toggles the SHCOLSTATE_ONBYDEFAULT bit of the column,
  3449. // and adds or removes the column as necessary.
  3450. BOOL CDefView::_HandleColumnToggle(UINT uCol, BOOL bRefresh)
  3451. {
  3452. BOOL fWasOn = _IsColumnInListView(uCol); // if its off now, we are adding it
  3453. BOOL fWasDetailsColumn = _IsDetailsColumn(uCol);
  3454. UINT uColVisOld = _RealToVisibleCol(uCol);
  3455. _vs.SetColumnState(uCol, SHCOLSTATE_ONBYDEFAULT, fWasDetailsColumn ? 0 : SHCOLSTATE_ONBYDEFAULT);
  3456. BOOL fIsOn = _IsColumnInListView(uCol); // This could == fWasOn if it's a tileview column
  3457. UINT uColVis = _RealToVisibleCol(uCol);
  3458. if (fIsOn != fWasOn)
  3459. {
  3460. if (!fWasOn)
  3461. {
  3462. _AddColumnToListView(uCol, uColVis);
  3463. if (_fs.ViewMode == FVM_TILE)
  3464. {
  3465. _ResetTileInfo(uColVis, TRUE);
  3466. }
  3467. }
  3468. else
  3469. {
  3470. _vs.RemoveColumn(uColVisOld);
  3471. ListView_DeleteColumn(_hwndListview, uColVisOld);
  3472. if (_fs.ViewMode == FVM_TILE)
  3473. {
  3474. _ResetTileInfo(uColVisOld, FALSE);
  3475. }
  3476. if (_vs._lParamSort == (int) uCol)
  3477. {
  3478. UINT iNewVis = _VisibleToRealCol(0);
  3479. Rearrange(iNewVis);
  3480. }
  3481. if (ListView_GetSelectedColumn(_hwndListview) == (UINT)uCol)
  3482. ListView_SetSelectedColumn(_hwndListview, -1);
  3483. }
  3484. }
  3485. if (bRefresh)
  3486. {
  3487. ListView_RedrawItems(_hwndListview, 0, 0x7fff);
  3488. InvalidateRect(_hwndListview, NULL, TRUE);
  3489. UpdateWindow(_hwndListview);
  3490. }
  3491. return TRUE;
  3492. }
  3493. // uCol = Real column number. uColVis = add it as this visible column.
  3494. void CDefView::_AddColumnToListView(UINT uCol, UINT uColVis)
  3495. {
  3496. LV_COLUMN col = {0};
  3497. // Adding a column
  3498. col.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  3499. col.fmt = _vs.GetColumnFormat(uCol);
  3500. col.cx = _vs.GetColumnCharCount(uCol) * _cxChar; // Use default width
  3501. col.pszText = _vs.GetColumnName(uCol);
  3502. col.cchTextMax = MAX_COLUMN_NAME_LEN;
  3503. col.iSubItem = uCol; // not vis
  3504. // This is all odd... Find Files uses this, but i think it should be LVCFMT_COL_IMAGE
  3505. if (col.fmt & LVCFMT_COL_HAS_IMAGES)
  3506. {
  3507. ListView_SetExtendedListViewStyleEx(_hwndListview, LVS_EX_SUBITEMIMAGES, LVS_EX_SUBITEMIMAGES);
  3508. col.fmt &= ~LVCFMT_COL_HAS_IMAGES;
  3509. }
  3510. if (-1 != ListView_InsertColumn(_hwndListview, uColVis, &col))
  3511. {
  3512. // now add it to our DSA
  3513. _vs.AppendColumn(uColVis, (USHORT) col.cx, uColVis);
  3514. if (!_fGroupView && (_vs._lParamSort == (int)uCol))
  3515. {
  3516. ListView_SetSelectedColumn(_hwndListview, uColVis);
  3517. }
  3518. }
  3519. }
  3520. void SetHeaderSort(HWND hwndHead, int iCol, UINT sortFlags)
  3521. {
  3522. HDITEM hdi = {HDI_FORMAT};
  3523. Header_GetItem(hwndHead, iCol, &hdi);
  3524. hdi.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN);
  3525. hdi.fmt |= sortFlags;
  3526. Header_SetItem(hwndHead, iCol, &hdi);
  3527. }
  3528. void CDefView::_SetSortFeedback()
  3529. {
  3530. HWND hwndHead = ListView_GetHeader(_hwndListview);
  3531. // the _IsOwnerData() is bad. this keeps search from getting sort UI feedback.
  3532. // to fix this implement a mode where the sort has not been determined and thus we don't
  3533. // display any sort feedback. regular folders could use this too as after items have
  3534. // been added the view is not really sorted
  3535. if (!hwndHead || _IsOwnerData())
  3536. return;
  3537. BOOL fRemoveBitmapFromLastHeader = TRUE;
  3538. int iColLast = _RealToVisibleCol(_vs._iLastColumnClick);
  3539. int iCol = _RealToVisibleCol((UINT)_vs._lParamSort);
  3540. if (_fGroupView)
  3541. {
  3542. SetHeaderSort(hwndHead, iCol, 0);
  3543. }
  3544. else
  3545. {
  3546. ListView_SetSelectedColumn(_hwndListview, iCol);
  3547. SetHeaderSort(hwndHead, iCol, _vs._iDirection > 0 ? HDF_SORTUP : HDF_SORTDOWN);
  3548. // Only remove the bitmap if the last header is not the one we are currently sorting by
  3549. if (iColLast == iCol)
  3550. fRemoveBitmapFromLastHeader = FALSE;
  3551. }
  3552. if (fRemoveBitmapFromLastHeader && iColLast != -1)
  3553. {
  3554. SetHeaderSort(hwndHead, iColLast, 0);
  3555. }
  3556. }
  3557. // use the folder to compare two items, falling back if the lParam is not understood by
  3558. // that folder.
  3559. // 99/05/18 #341468 vtan: If the first comparison fails it may be because
  3560. // lParamSort is not understood by IShellFolder::CompareIDs (perhaps it's
  3561. // an extended column that might not be installed any more)
  3562. // In this case get the default comparison method
  3563. // and use that. If that fails use 0 which should hopefully not fail. If
  3564. // the 0 case fails we are toast with an assert.
  3565. HRESULT CDefView::_CompareIDsFallback(LPARAM lParam, LPCITEMIDLIST p1, LPCITEMIDLIST p2)
  3566. {
  3567. HRESULT hr = _pshf->CompareIDs(lParam, p1, p2);
  3568. if (FAILED(hr))
  3569. {
  3570. LPARAM lParamSort;
  3571. _vs.GetDefaults(this, &lParamSort, NULL, NULL);
  3572. hr = _pshf->CompareIDs(lParamSort | (SHCIDS_ALLFIELDS & lParam), p1, p2);
  3573. if (FAILED(hr))
  3574. {
  3575. // even that did not work, fall back to zero based compare (pluse the all fields flag)
  3576. hr = _pshf->CompareIDs((SHCIDS_ALLFIELDS & lParam), p1, p2);
  3577. }
  3578. }
  3579. ASSERT(SUCCEEDED(hr));
  3580. return hr;
  3581. }
  3582. // compare two items, taking into account the sort direction
  3583. int CDefView::_CompareIDsDirection(LPARAM lParam, LPCITEMIDLIST p1, LPCITEMIDLIST p2)
  3584. {
  3585. ASSERT(_vs._iDirection != 0);
  3586. HRESULT hr = _CompareIDsFallback(lParam, (LPITEMIDLIST)p1, (LPITEMIDLIST)p2);
  3587. return ShortFromResult(hr) * _vs._iDirection;
  3588. }
  3589. // p1 and p2 are pointers to the lv_item's LPARAM, which is currently the pidl
  3590. int CALLBACK CDefView::_Compare(void *p1, void *p2, LPARAM lParam)
  3591. {
  3592. CDefView *pdv = (CDefView *)lParam;
  3593. return pdv->_CompareIDsDirection(pdv->_vs._lParamSort, (LPITEMIDLIST)p1, (LPITEMIDLIST)p2);
  3594. }
  3595. typedef struct
  3596. {
  3597. VARIANT var;
  3598. BOOL fIsFolder;
  3599. } VARIANT_AND_FOLDER;
  3600. typedef struct
  3601. {
  3602. VARIANT_AND_FOLDER *pvars;
  3603. SHCOLUMNID scid;
  3604. CDefView *pdv;
  3605. } VARIANT_SORT_INFO;
  3606. int CALLBACK _CompareVariantCallback(LPARAM dw1, LPARAM dw2, LPARAM lParam)
  3607. {
  3608. VARIANT_SORT_INFO *psi = (VARIANT_SORT_INFO *)lParam;
  3609. int iRet = 0;
  3610. // Always put the folders first
  3611. if (psi->pvars[dw1].fIsFolder)
  3612. {
  3613. if (!psi->pvars[dw2].fIsFolder)
  3614. iRet = -1;
  3615. }
  3616. else if (psi->pvars[dw2].fIsFolder)
  3617. {
  3618. iRet = 1;
  3619. }
  3620. if (0 == iRet)
  3621. {
  3622. iRet = CompareVariants(psi->pvars[dw1].var, psi->pvars[dw2].var);
  3623. }
  3624. return iRet * psi->pdv->_vs._iDirection;
  3625. }
  3626. #define LV_NOFROZENITEM -1
  3627. HRESULT CDefView::_Sort(void)
  3628. {
  3629. HRESULT hr = CallCB(SFVM_ARRANGE, 0, _vs._lParamSort);
  3630. if (FAILED(hr))
  3631. {
  3632. hr = HRESULT_FROM_WIN32(ERROR_CAN_NOT_COMPLETE);
  3633. int iIndexRecycleBin = LV_NOFROZENITEM;
  3634. POINT ptRecycleBin;
  3635. _SetSortFeedback();
  3636. // For desktop, we need to freeze the recycle bin position before we arrage other icons.
  3637. if (_fPositionRecycleBin)
  3638. {
  3639. iIndexRecycleBin = _FreezeRecycleBin(&ptRecycleBin);
  3640. _fPositionRecycleBin = FALSE;
  3641. }
  3642. // This is semi-bogus for defview to care whether the column is extended or not.
  3643. // We could have modified the ISF::CompareIDs() to handle extended columns, but
  3644. // then it would only have the pidls, and would have to re-extract any data, so
  3645. // its much faster if we separate out the extended columns, and take advantage
  3646. // of listview's caching abilities.
  3647. DWORD dwState = _DefaultColumnState((UINT)_vs._lParamSort);
  3648. SHCOLUMNID scid;
  3649. HRESULT hrMapColumn = E_FAIL;
  3650. if (_pshf2)
  3651. hrMapColumn = _pshf2->MapColumnToSCID((UINT)_vs._lParamSort, &scid);
  3652. // SHCOLSTATE_PREFER_VARCMP tells us that the folder's CompareIDs()
  3653. // produces the same result as comparing the variants. this is an optimization
  3654. // for folders who's CompareIDs() are slow (bit bucket)
  3655. if (_IsOwnerData() || (dwState & (SHCOLSTATE_EXTENDED | SHCOLSTATE_PREFER_VARCMP)))
  3656. {
  3657. if (_GetBackgroundTaskCount(TOID_DVBackgroundEnum) == 0)
  3658. {
  3659. int cItems = ListView_GetItemCount(_hwndListview);
  3660. if (cItems)
  3661. {
  3662. VARIANT_SORT_INFO vsi;
  3663. BOOL fOkToProceed = TRUE;
  3664. if ((UINT)_vs._lParamSort == 0)
  3665. {
  3666. vsi.scid = SCID_NAME;
  3667. }
  3668. else if (SUCCEEDED(hrMapColumn))
  3669. {
  3670. vsi.scid = scid;
  3671. }
  3672. else
  3673. {
  3674. fOkToProceed = FALSE;
  3675. hr = hrMapColumn;
  3676. }
  3677. if (fOkToProceed)
  3678. {
  3679. vsi.pvars = new VARIANT_AND_FOLDER[cItems];
  3680. if (vsi.pvars)
  3681. {
  3682. vsi.pdv = this;
  3683. for (int i = 0; i < cItems; i++)
  3684. {
  3685. LPCITEMIDLIST pidl = _GetPIDL(i);
  3686. if (pidl)
  3687. {
  3688. DWORD dwAttrib = SHGetAttributes(_pshf, pidl, SFGAO_FOLDER);
  3689. vsi.pvars[i].fIsFolder = dwAttrib & SFGAO_FOLDER;
  3690. if ((UINT)_vs._lParamSort == 0) // This is the NAME column
  3691. {
  3692. WCHAR szName[MAX_PATH];
  3693. if (SUCCEEDED(DisplayNameOf(_pshf, pidl, SHGDN_INFOLDER | SHGDN_NORMAL, szName, ARRAYSIZE(szName))))
  3694. {
  3695. InitVariantFromStr(&vsi.pvars[i].var, szName);
  3696. }
  3697. }
  3698. else
  3699. {
  3700. _pshf2->GetDetailsEx(pidl, &vsi.scid, &vsi.pvars[i].var);
  3701. }
  3702. }
  3703. }
  3704. hr = CallCB(SFVM_SORTLISTDATA, (LPARAM)_CompareVariantCallback, (LPARAM)&vsi);
  3705. // dont send a LVM_SORTITEMS to an ownerdraw or comctl32 will rip
  3706. if (FAILED(hr) && !_IsOwnerData() && ListView_SortItemsEx(_hwndListview, _CompareVariantCallback, (LPARAM)&vsi))
  3707. hr = S_OK;
  3708. for (int i = 0; i < cItems; i++)
  3709. {
  3710. VariantClear(&vsi.pvars[i].var);
  3711. }
  3712. delete vsi.pvars;
  3713. }
  3714. }
  3715. }
  3716. }
  3717. }
  3718. else
  3719. {
  3720. ASSERT(!_IsOwnerData()) // dont send a LVM_SORTITEMS to an ownerdraw or comctl32 will rip
  3721. if (ListView_SortItems(_hwndListview, _Compare, (LPARAM)this))
  3722. hr = S_OK;
  3723. }
  3724. //If we froze recycle-bin earlier, now is the time to put it in it's default position.
  3725. if (iIndexRecycleBin != LV_NOFROZENITEM)
  3726. _SetRecycleBinInDefaultPosition(&ptRecycleBin);
  3727. }
  3728. return hr;
  3729. }
  3730. // this should NOT check for whether the item is already in the listview
  3731. // if it does, we'll have some serious performance problems
  3732. int CDefView::_AddObject(LPITEMIDLIST pidl) // takes ownership of pidl.
  3733. {
  3734. int iItem = -1;
  3735. // Check the commdlg hook to see if we should include this
  3736. // object.
  3737. if ((S_OK == _IncludeObject(pidl)) &&
  3738. (S_FALSE != CallCB(SFVM_INSERTITEM, 0, (LPARAM)pidl)))
  3739. {
  3740. LV_ITEM item = {0};
  3741. item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_COLUMNS;
  3742. item.iItem = INT_MAX; // add at end
  3743. item.iImage = I_IMAGECALLBACK;
  3744. item.pszText = LPSTR_TEXTCALLBACK;
  3745. item.lParam = (LPARAM)pidl; // Takes pidl ownership.
  3746. item.cColumns = I_COLUMNSCALLBACK; // REVIEW: why not fill this in like the _UpdateObject call? That would fix the problem where GroupBy doesn't keep the "Searching UI" going...
  3747. iItem = ListView_InsertItem(_hwndListview, &item);
  3748. if (iItem < 0)
  3749. {
  3750. ILFree(pidl);
  3751. }
  3752. else if (_bBkFilling)
  3753. {
  3754. _pEnumTask->_AddToPending(pidl);
  3755. }
  3756. _OnContentsChanged();
  3757. if (iItem == 0)
  3758. {
  3759. _PostNoItemStateChangedMessage();
  3760. }
  3761. }
  3762. else
  3763. {
  3764. ILFree(pidl);
  3765. }
  3766. return iItem;
  3767. }
  3768. // Find an item in the view
  3769. int CDefView::_FindItem(LPCITEMIDLIST pidl, LPITEMIDLIST *ppidlFound, BOOL fSamePtr, BOOL fForwards)
  3770. {
  3771. RIP(ILFindLastID(pidl) == pidl);
  3772. int cItems = ListView_GetItemCount(_hwndListview);
  3773. if (_iLastFind >= cItems)
  3774. _iLastFind = 0;
  3775. int iItem = _iLastFind;
  3776. if (SUCCEEDED(CallCB(SFVM_INDEXOFITEMIDLIST, (WPARAM)&iItem, (LPARAM)pidl)))
  3777. {
  3778. if (ppidlFound)
  3779. *ppidlFound = (LPITEMIDLIST)_GetPIDL(iItem); // cast as caller knows how to free this
  3780. }
  3781. else
  3782. {
  3783. iItem = -1; // assume failure
  3784. for (int cCounter = 0, i = _iLastFind; cCounter < cItems; cCounter++)
  3785. {
  3786. LPCITEMIDLIST pidlT = _GetPIDL(i);
  3787. ASSERT(pidlT);
  3788. if (pidlT)
  3789. {
  3790. if ((pidlT == pidl) ||
  3791. (!fSamePtr && (0 == ResultFromShort(_pshf->CompareIDs(0, pidl, pidlT)))))
  3792. {
  3793. if (ppidlFound)
  3794. *ppidlFound = (LPITEMIDLIST)pidlT; // cast as callers know how to free
  3795. _iLastFind = iItem = i; // success
  3796. // TraceMsg(TF_DEFVIEW, "####FIND CACHE RESULT --- %s by %d", cCounter < iItem ? TEXT("WIN") : TEXT("LOSE"), iItem - cCounter);
  3797. break;
  3798. }
  3799. }
  3800. if (fForwards)
  3801. {
  3802. i = (i+1)%cItems;
  3803. }
  3804. else
  3805. {
  3806. i = (i > 0)?(i - 1):(cItems-1);
  3807. }
  3808. }
  3809. if (-1 == iItem)
  3810. {
  3811. _iLastFind = 0; // didn't find it, reset this for next time
  3812. }
  3813. }
  3814. return iItem;
  3815. }
  3816. int CDefView::_FindItemHint(LPCITEMIDLIST pidl, int iItem)
  3817. {
  3818. _iLastFind = iItem;
  3819. return _FindItem(pidl, NULL, FALSE, FALSE);
  3820. }
  3821. // This is slightly different than the Above find item. This one
  3822. // uses some extra variables to keep track of previous group and
  3823. // "Wiggles". This "Wiggle" allows for effecient non-sequential
  3824. // application of group info
  3825. int CDefView::_FindGroupItem(LPITEMIDLIST pidl)
  3826. {
  3827. int cItems = ListView_GetItemCount(_hwndListview);
  3828. if (_iLastFoundCat >= cItems)
  3829. _iLastFoundCat = 0;
  3830. int iItem = -1; // assume falure
  3831. for (int cCounter = 0, i = _iLastFoundCat; cCounter < cItems; cCounter++)
  3832. {
  3833. LPCITEMIDLIST pidlT = _GetPIDL(i);
  3834. ASSERT(pidlT);
  3835. if (pidlT)
  3836. {
  3837. if (0 == ResultFromShort(_pshf->CompareIDs(0, pidl, pidlT)) )
  3838. {
  3839. if (_iLastFoundCat > i)
  3840. _iIncrementCat = -1;
  3841. else
  3842. _iIncrementCat = 1;
  3843. _iLastFoundCat = iItem = i; // success
  3844. break;
  3845. }
  3846. }
  3847. i += _iIncrementCat;
  3848. if (i < 0)
  3849. i = cItems - 1;
  3850. if (i >= cItems)
  3851. i = 0;
  3852. }
  3853. if (-1 == iItem)
  3854. {
  3855. _iLastFoundCat = 0; // didn't find it, reset this for next time
  3856. }
  3857. return iItem;
  3858. }
  3859. // Function to process the SFVM_REMOVEOBJECT message, by searching
  3860. // through the list for a match of the pidl. If a match is found, the
  3861. // item is removed from the list and the index number is returned, else
  3862. // -1 is returned.
  3863. int CDefView::_RemoveObject(LPCITEMIDLIST pidl, BOOL fSamePtr)
  3864. {
  3865. int i = 0;
  3866. // Docfind will pass in a null pointer to tell us that it wants
  3867. // to refresh the window by deleting all of the items from it.
  3868. if (pidl == NULL)
  3869. {
  3870. CallCB(SFVM_DELETEITEM, 0, 0); // view callback notify
  3871. ListView_DeleteAllItems(_hwndListview);
  3872. _PostNoItemStateChangedMessage();
  3873. _OnContentsChanged();
  3874. }
  3875. else
  3876. {
  3877. // Non null go look for item.
  3878. i = _FindItem(pidl, NULL, fSamePtr);
  3879. if (i >= 0)
  3880. {
  3881. RECT rc;
  3882. UINT uState = ListView_GetItemState(_hwndListview, i, LVIS_ALL);
  3883. if (uState & LVIS_FOCUSED)
  3884. ListView_GetItemRect(_hwndListview, i, &rc, LVIR_ICON);
  3885. if (_bBkFilling)
  3886. _pEnumTask->_DeleteFromPending(pidl); // removes the pointer from the pending list.
  3887. ListView_DeleteItem(_hwndListview, i);
  3888. // we deleted the focused item.. replace the focus to the nearest item.
  3889. if (uState & LVIS_FOCUSED)
  3890. {
  3891. int iFocus = i;
  3892. if (_IsPositionedView() || _fGroupView)
  3893. {
  3894. LV_FINDINFO lvfi = {0};
  3895. lvfi.flags = LVFI_NEARESTXY;
  3896. lvfi.pt.x = rc.left;
  3897. lvfi.pt.y = rc.top;
  3898. iFocus = ListView_FindItem(_hwndListview, -1, &lvfi);
  3899. }
  3900. else
  3901. {
  3902. if (ListView_GetItemCount(_hwndListview) >= iFocus)
  3903. iFocus--;
  3904. }
  3905. if (iFocus != -1)
  3906. {
  3907. ListView_SetItemState(_hwndListview, iFocus, LVIS_FOCUSED, LVIS_FOCUSED);
  3908. ListView_EnsureVisible(_hwndListview, iFocus, FALSE);
  3909. }
  3910. else
  3911. {
  3912. // RAID 372130
  3913. // Notify image preview control to update its image (to
  3914. // nothing). The image preview control uses focus change
  3915. // events to track when it should update the image it is
  3916. // displaying. When it receives a focus change event, it
  3917. // queries the listview to see which item has focus, then
  3918. // displays that item in the image preview window. When
  3919. // the last item in the listview is deleted, we need to
  3920. // fire a focus change event to the image preview control
  3921. // even though the focus has not changed to another item.
  3922. // This way, the image preview control realizes there is
  3923. // nothing with focus, and correctly displays as empty.
  3924. if (_fs.ViewMode == FVM_THUMBSTRIP)
  3925. _ThumbstripSendImagePreviewFocusChangeEvent();
  3926. }
  3927. }
  3928. // Notify automation if the listview is now empty
  3929. UINT uCount = 0;
  3930. GetObjectCount(&uCount);
  3931. if (!uCount)
  3932. {
  3933. _PostNoItemStateChangedMessage();
  3934. }
  3935. _OnContentsChanged();
  3936. }
  3937. }
  3938. return i;
  3939. }
  3940. // search the list for a match of the first pidl. If a match is found,
  3941. // the item is updated to the second pidl...
  3942. int CDefView::_UpdateObject(LPCITEMIDLIST pidlOld, LPCITEMIDLIST pidlNew)
  3943. {
  3944. LPITEMIDLIST pidlOldToFree;
  3945. int i = _FindItem(pidlOld, &pidlOldToFree, FALSE);
  3946. if (i >= 0)
  3947. {
  3948. if (_IsOwnerData())
  3949. {
  3950. if (SUCCEEDED(CallCB(SFVM_SETITEMIDLIST, i, (LPARAM)pidlNew)))
  3951. {
  3952. // Invalidate the rectangle so we update the item...
  3953. RECT rc;
  3954. ListView_GetItemRect(_hwndListview, i, &rc, LVIR_BOUNDS);
  3955. InvalidateRect(_hwndListview, &rc, FALSE);
  3956. ListView_Update(_hwndListview, i);
  3957. _OnContentsChanged();
  3958. }
  3959. else
  3960. {
  3961. i = -1; // we failed, try to cleanup and bail.
  3962. }
  3963. }
  3964. else
  3965. {
  3966. LPITEMIDLIST pidlNewClone = ILClone(pidlNew);
  3967. if (pidlNewClone)
  3968. {
  3969. LV_ITEM item = {0};
  3970. // We found the item so lets now update it in the
  3971. // the view.
  3972. item.mask = LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE;
  3973. item.iItem = i;
  3974. item.pszText = LPSTR_TEXTCALLBACK;
  3975. item.iImage = I_IMAGECALLBACK;
  3976. item.lParam = (LPARAM)pidlNewClone;
  3977. // if selected, deselect it
  3978. UINT uState = ListView_GetItemState(_hwndListview, i, LVIS_FOCUSED|LVIS_SELECTED);
  3979. if (uState & (LVIS_FOCUSED|LVIS_SELECTED))
  3980. {
  3981. _OnLVSelectionChange(i, uState, 0, (LPARAM)pidlOldToFree);
  3982. }
  3983. // remove the item.
  3984. CallCB(SFVM_DELETEITEM, 0, (LPARAM)pidlOldToFree);
  3985. // now insert it with a new pidl
  3986. CallCB(SFVM_INSERTITEM, 0, (LPARAM)pidlNewClone);
  3987. // if it was selected, select it again
  3988. if (uState & (LVIS_FOCUSED|LVIS_SELECTED))
  3989. {
  3990. _OnLVSelectionChange(i, 0, uState, (LPARAM)pidlNewClone);
  3991. }
  3992. if (_fGroupView)
  3993. {
  3994. item.mask |= LVIF_GROUPID;
  3995. item.iGroupId = (int)_GetGroupForItem(item.iItem, pidlNewClone);
  3996. }
  3997. ListView_SetItem(_hwndListview, &item);
  3998. int cCols = _GetHeaderCount();
  3999. for (item.iSubItem++; item.iSubItem < cCols; item.iSubItem++)
  4000. {
  4001. ListView_SetItemText(_hwndListview, item.iItem, item.iSubItem,
  4002. LPSTR_TEXTCALLBACK);
  4003. }
  4004. //
  4005. // Warning!!! Only free pidlOldToFree *after* calling ListView_SetItem. ListView_SetItem
  4006. // can call back asking for image info on the old pidl!
  4007. //
  4008. // Now delete the item but don't call the callback since we did that already.
  4009. OnListViewDelete(i, pidlOldToFree, FALSE);
  4010. _OnContentsChanged();
  4011. }
  4012. else
  4013. {
  4014. i = -1;
  4015. }
  4016. }
  4017. }
  4018. return i;
  4019. }
  4020. //
  4021. // invalidates all items with the given image index.
  4022. //
  4023. // or update all items if iImage == -1
  4024. //
  4025. void CDefView::_UpdateImage(int iImage)
  4026. {
  4027. // -1 means update all
  4028. // reset the imagelists incase the size has changed, and do
  4029. // a full update.
  4030. if (iImage == -1)
  4031. {
  4032. if (_IsImageMode())
  4033. {
  4034. _RemoveThumbviewTasks();
  4035. _pImageCache->Flush(TRUE);
  4036. _SetThumbview();
  4037. }
  4038. else if (_IsTileMode())
  4039. {
  4040. _SetTileview();
  4041. }
  4042. else
  4043. {
  4044. _SetSysImageList();
  4045. }
  4046. _ReloadContent();
  4047. }
  4048. else
  4049. {
  4050. // get a dc so we can optimize for visible/not visible cases
  4051. HDC hdcLV = GetDC(_hwndListview);
  4052. // scan the listview updating any items which match
  4053. LV_ITEM item = {0};
  4054. int cItems = ListView_GetItemCount(_hwndListview);
  4055. for (item.iItem = 0; item.iItem < cItems; item.iItem++)
  4056. {
  4057. item.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_NORECOMPUTE;
  4058. ListView_GetItem(_hwndListview, &item);
  4059. int iImageOld = item.iImage;
  4060. if (item.iImage == iImage) // this filters I_IMAGECALLBACK for us
  4061. {
  4062. RECT rc;
  4063. LPCITEMIDLIST pidl = _GetPIDLParam(item.lParam, item.iItem);
  4064. CFSFolder_UpdateIcon(_pshf, pidl);
  4065. //
  4066. // if the item is visible then we don't want to flicker so just
  4067. // kick off an async extract. if the item is not visible then
  4068. // leave it for later by slamming in I_IMAGECALLBACK.
  4069. //
  4070. item.iImage = I_IMAGECALLBACK;
  4071. if (!_IsImageMode() && ListView_GetItemRect(_hwndListview, item.iItem, &rc, LVIR_ICON) &&
  4072. RectVisible(hdcLV, &rc))
  4073. {
  4074. int iImageNew;
  4075. HRESULT hr = _GetIconAsync(pidl, &iImageNew, FALSE);
  4076. if (hr == S_FALSE)
  4077. continue;
  4078. if (SUCCEEDED(hr))
  4079. {
  4080. if (iImageNew == iImageOld)
  4081. {
  4082. ListView_RedrawItems(_hwndListview, item.iItem, item.iItem);
  4083. continue;
  4084. }
  4085. item.iImage = iImageNew;
  4086. }
  4087. }
  4088. item.mask = LVIF_IMAGE;
  4089. item.iSubItem = 0;
  4090. ListView_SetItem(_hwndListview, &item);
  4091. }
  4092. }
  4093. ReleaseDC(_hwndListview, hdcLV);
  4094. }
  4095. }
  4096. // Function to process the SFVM_REFRESHOBJECT message, by searching
  4097. // through the list for a match of the first pidl. If a match is found,
  4098. // the item is redrawn.
  4099. int CDefView::_RefreshObject(LPITEMIDLIST *ppidl)
  4100. {
  4101. int i = _FindItem(ppidl[0], NULL, FALSE);
  4102. if (i >= 0)
  4103. ListView_RedrawItems(_hwndListview, i, i);
  4104. return i;
  4105. }
  4106. HRESULT CDefView::_GetItemObjects(LPCITEMIDLIST **ppidl, UINT uWhat, UINT *pcItems)
  4107. {
  4108. *pcItems = _GetItemArray(NULL, 0, uWhat);
  4109. if (ppidl)
  4110. {
  4111. *ppidl = NULL;
  4112. if (*pcItems)
  4113. {
  4114. *ppidl = (LPCITEMIDLIST *)LocalAlloc(LPTR, sizeof(*ppidl) * (*pcItems));
  4115. if (*ppidl)
  4116. _GetItemArray(*ppidl, *pcItems, uWhat);
  4117. else
  4118. return E_OUTOFMEMORY;
  4119. }
  4120. }
  4121. return S_OK;
  4122. }
  4123. void CDefView::_SetItemPosition(int i, int x, int y)
  4124. {
  4125. ListView_SetItemPosition32(_hwndListview, i, x, y);
  4126. _fUserPositionedItems = TRUE;
  4127. }
  4128. void CDefView::_SetItemPos(LPSFV_SETITEMPOS psip)
  4129. {
  4130. int i = _FindItem(psip->pidl, NULL, FALSE);
  4131. if (i >= 0)
  4132. {
  4133. _SetItemPosition(i, psip->pt.x, psip->pt.y);
  4134. }
  4135. }
  4136. // "View State" here refers to column information and icon positions
  4137. BOOL CDefView::GetViewState()
  4138. {
  4139. BOOL bRet = FALSE;
  4140. IPropertyBag* ppb;
  4141. if (SUCCEEDED(IUnknown_QueryServicePropertyBag(_psb, SHGVSPB_FOLDER, IID_PPV_ARG(IPropertyBag, &ppb))))
  4142. {
  4143. DWORD dw;
  4144. // Check if we've saved state before (first check) or if we may want to
  4145. // try upgrading some settings if we haven't saved state before (second check)
  4146. if (SUCCEEDED(SHPropertyBag_ReadDWORD(ppb, VS_PROPSTR_MODE, &dw)) ||
  4147. SUCCEEDED(SHPropertyBag_ReadDWORD(ppb, VS_PROPSTR_FFLAGS, &dw)))
  4148. {
  4149. bRet = SUCCEEDED(_vs.LoadFromPropertyBag(this, ppb));
  4150. }
  4151. else
  4152. {
  4153. IStream* pstm;
  4154. if (SUCCEEDED(_LoadGlobalViewState(&pstm)))
  4155. {
  4156. _vs.LoadFromStream(this, pstm);
  4157. bRet = TRUE;
  4158. pstm->Release();
  4159. }
  4160. }
  4161. ppb->Release();
  4162. }
  4163. else
  4164. {
  4165. // 99/02/05 #226140 vtan: Try to get the view state stream
  4166. // from ShellBrowser. If that fails then look for a global
  4167. // view state stream that is stored when the user clicks on
  4168. // the "Like Current Folder" in the View tab of folder settings.
  4169. // IShellBrowser::GetViewStateStream() match the dwDefRevCount
  4170. // of the cabinet state to make sure that it's valid.
  4171. IStream *pstm;
  4172. if (SUCCEEDED(_psb->GetViewStateStream(STGM_READ, &pstm)) ||
  4173. SUCCEEDED(_LoadGlobalViewState(&pstm)))
  4174. {
  4175. _vs.LoadFromStream(this, pstm);
  4176. pstm->Release();
  4177. bRet = TRUE;
  4178. }
  4179. }
  4180. return bRet;
  4181. }
  4182. void CDefView::_UpdateEnumerationFlags()
  4183. {
  4184. SHELLSTATE ss;
  4185. SHGetSetSettings(&ss, SSF_SHOWALLOBJECTS | SSF_SHOWCOMPCOLOR, FALSE);
  4186. _fShowAllObjects = ss.fShowAllObjects;
  4187. // Don't allow compression coloring on the desktop proper
  4188. _fShowCompColor = _IsDesktop() ? FALSE : ss.fShowCompColor;
  4189. }
  4190. // starts and stops the spinning Globe animation
  4191. // indicating that we are in the process of navigating to
  4192. // a directory
  4193. void CDefView::_GlobeAnimation(BOOL fStartSpinning, BOOL fForceStop)
  4194. {
  4195. if (_fGlobeCanSpin)
  4196. {
  4197. DWORD dwCmdID = 0;
  4198. if (fStartSpinning)
  4199. {
  4200. if (_crefGlobeSpin++ == 0)
  4201. {
  4202. dwCmdID = CBRANDIDM_STARTGLOBEANIMATION;
  4203. }
  4204. }
  4205. else
  4206. {
  4207. ASSERT(_crefGlobeSpin > 0);
  4208. if (fForceStop || (--_crefGlobeSpin == 0))
  4209. {
  4210. dwCmdID = CBRANDIDM_STOPGLOBEANIMATION;
  4211. // our navigation is over, never spin again
  4212. _fGlobeCanSpin = FALSE;
  4213. }
  4214. }
  4215. if (dwCmdID)
  4216. {
  4217. IUnknown_QueryServiceExec(_psb, SID_SBrandBand, &CGID_BrandCmdGroup, dwCmdID, 0, NULL, NULL);
  4218. }
  4219. }
  4220. }
  4221. LRESULT SearchingUIWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  4222. {
  4223. switch (uMsg)
  4224. {
  4225. case GET_WM_CTLCOLOR_MSG(CTLCOLOR_STATIC):
  4226. SetBkColor(GET_WM_CTLCOLOR_HDC(wParam, lParam, uMsg),
  4227. GetSysColor(COLOR_WINDOW));
  4228. return (LRESULT)GetSysColorBrush(COLOR_WINDOW);
  4229. default:
  4230. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  4231. }
  4232. return 0;
  4233. }
  4234. void CDefView::_ShowSearchUI(BOOL fStartSearchWindow)
  4235. {
  4236. if (_fAllowSearchingWindow || _crefSearchWindow) // once started, make sure our refcount finishes
  4237. {
  4238. if (fStartSearchWindow)
  4239. {
  4240. if (_crefSearchWindow++ == 0)
  4241. {
  4242. // The static window could already exist during a refresh
  4243. if (!_hwndStatic)
  4244. {
  4245. _hwndStatic = SHCreateWorkerWindowW((WNDPROC)SearchingUIWndProc, _hwndView, 0,
  4246. WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
  4247. NULL, NULL);
  4248. if (_hwndStatic)
  4249. {
  4250. HWND hAnimate = CreateWindowEx(0, ANIMATE_CLASS, c_szNULL,
  4251. WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | ACS_TRANSPARENT | ACS_AUTOPLAY | ACS_CENTER,
  4252. 0, 0, 0, 0, _hwndStatic, (HMENU)ID_STATIC, HINST_THISDLL, NULL);
  4253. if (hAnimate)
  4254. {
  4255. RECT rc;
  4256. GetClientRect(_hwndView, &rc);
  4257. // Move this window to the top so the user sees the "looking" icon
  4258. // We are in a "normal" view. We need to do this always or the
  4259. // Flashlight doesn't appear. It tested safe with WebView on.
  4260. SetWindowPos(_hwndStatic, HWND_TOP, 0, 0, rc.right, rc.bottom, 0);
  4261. SetWindowPos(hAnimate, HWND_TOP, 0, 0, rc.right, rc.bottom, SWP_NOZORDER);
  4262. _OnMoveWindowToTop(_hwndStatic);
  4263. SetTimer(_hwndView, DV_IDTIMER_START_ANI, 2000, NULL); // 2 second timer
  4264. }
  4265. }
  4266. }
  4267. ShowHideListView();
  4268. }
  4269. }
  4270. else
  4271. {
  4272. if (0 == _crefSearchWindow) // if _ShowSearchUI(FALSE) gets called before _ShowSearchUI(TRUE)
  4273. {
  4274. _fAllowSearchingWindow = FALSE;
  4275. }
  4276. else if (--_crefSearchWindow == 0)
  4277. {
  4278. _fAllowSearchingWindow = FALSE;
  4279. ShowHideListView();
  4280. }
  4281. }
  4282. }
  4283. }
  4284. // this is only called from within SHCNE_* don't put up ui on the enum error.
  4285. void CDefView::_FullViewUpdate(BOOL fUpdateItem)
  4286. {
  4287. if (fUpdateItem)
  4288. _ReloadContent(); // the folder we're looking at has changed
  4289. else
  4290. FillObjectsShowHide(FALSE); // our contents have changed
  4291. }
  4292. void CDefView::_ShowControl(UINT idControl, int idCmd)
  4293. {
  4294. IBrowserService *pbs;
  4295. if (SUCCEEDED(_psb->QueryInterface(IID_PPV_ARG(IBrowserService, &pbs))))
  4296. {
  4297. pbs->ShowControlWindow(idControl, idCmd);
  4298. pbs->Release();
  4299. }
  4300. }
  4301. BOOL IsSingleWindowBrowsing(void)
  4302. {
  4303. CABINETSTATE cs;
  4304. TBOOL(ReadCabinetState(&cs, sizeof(cs)));
  4305. return !BOOLIFY(cs.fNewWindowMode);
  4306. }
  4307. // This function does three things:
  4308. // 1 - Alter the size of the parent to best fit around the items we have.
  4309. // 2 - Set the default icon view mode
  4310. // 3 - Make sure the correct toolbars are showing
  4311. //
  4312. void CDefView::_BestFit()
  4313. {
  4314. // Only bestfit once
  4315. if (_fs.fFlags & FWF_BESTFITWINDOW)
  4316. {
  4317. _fs.fFlags &= ~FWF_BESTFITWINDOW;
  4318. // Make sure the correct toolbars are showing the first time this folder is displayed
  4319. //
  4320. int iITbar = SBSC_HIDE;
  4321. int iStdBar = SBSC_HIDE;
  4322. switch (_uDefToolbar)
  4323. {
  4324. case HIWORD(TBIF_INTERNETBAR):
  4325. iITbar = SBSC_SHOW;
  4326. goto ShowToolbar;
  4327. case HIWORD(TBIF_STANDARDTOOLBAR):
  4328. iStdBar = SBSC_SHOW;
  4329. goto ShowToolbar;
  4330. case HIWORD(TBIF_NOTOOLBAR):
  4331. ShowToolbar:
  4332. _ShowControl(FCW_INTERNETBAR, iITbar);
  4333. _ShowControl(FCW_TOOLBAR, iStdBar);
  4334. break;
  4335. }
  4336. }
  4337. }
  4338. void CDefView::_ClearPostedMsgs(HWND hwnd)
  4339. {
  4340. MSG msg;
  4341. while (PeekMessage(&msg, hwnd, WM_DSV_UPDATEICON, WM_DSV_UPDATEICON, PM_REMOVE))
  4342. {
  4343. // PeekMessage(hwnd) can return messages posted to CHILDREN of this hwnd...
  4344. // Verify that the message was really for us.
  4345. //
  4346. if (msg.hwnd == hwnd)
  4347. {
  4348. TraceMsg(TF_DEFVIEW, "DefView: WM_DSV_UPDATEICON after WM_DESTROY!!!");
  4349. LPITEMIDLIST pidl = (LPITEMIDLIST) msg.wParam;
  4350. ILFree(pidl);
  4351. }
  4352. }
  4353. while (PeekMessage(&msg, hwnd, WM_DSV_UPDATECOLDATA, WM_DSV_UPDATECOLDATA, PM_REMOVE))
  4354. {
  4355. // PeekMessage(hwnd) can return messages posted to CHILDREN of this hwnd...
  4356. // Verify that the message was really for us.
  4357. //
  4358. if (msg.hwnd == hwnd)
  4359. {
  4360. TraceMsg(TF_DEFVIEW, "DefView: WM_DSV_UPDATECOLDATA after WM_DESTROY!!!");
  4361. delete (CBackgroundColInfo*)msg.lParam;
  4362. }
  4363. }
  4364. while (PeekMessage(&msg, hwnd, WM_DSV_DELAYSTATUSBARUPDATE, WM_DSV_DELAYSTATUSBARUPDATE, PM_REMOVE))
  4365. {
  4366. if (msg.hwnd == hwnd)
  4367. {
  4368. LocalFree((void *)msg.lParam);
  4369. }
  4370. }
  4371. while (PeekMessage(&msg, hwnd, WM_DSV_SETIMPORTANTCOLUMNS, WM_DSV_SETIMPORTANTCOLUMNS, PM_REMOVE))
  4372. {
  4373. // PeekMessage(hwnd) can return messages posted to CHILDREN of this hwnd...
  4374. // Verify that the message was really for us.
  4375. //
  4376. if (msg.hwnd == hwnd)
  4377. {
  4378. TraceMsg(TF_DEFVIEW, "DefView: WM_DSV_SETIMPORTANTCOLUMNS after WM_DESTROY!!!");
  4379. delete (CBackgroundTileInfo*)msg.lParam;
  4380. }
  4381. }
  4382. while (PeekMessage(&msg, hwnd, WM_DSV_SETITEMGROUP, WM_DSV_SETITEMGROUP, PM_REMOVE))
  4383. {
  4384. // PeekMessage(hwnd) can return messages posted to CHILDREN of this hwnd...
  4385. // Verify that the message was really for us.
  4386. //
  4387. if (msg.hwnd == hwnd)
  4388. {
  4389. TraceMsg(TF_DEFVIEW, "DefView: WM_DSV_SETITEMGROUP after WM_DESTROY!!!");
  4390. delete (CBackgroundGroupInfo*)msg.lParam;
  4391. }
  4392. }
  4393. while (PeekMessage(&msg, hwnd, WM_DSV_UPDATETHUMBNAIL, WM_DSV_UPDATETHUMBNAIL, PM_REMOVE))
  4394. {
  4395. // PeekMessage(hwnd) can return messages posted to CHILDREN of this hwnd...
  4396. // Verify that the message was really for us.
  4397. //
  4398. if (msg.hwnd == hwnd)
  4399. {
  4400. TraceMsg(TF_DEFVIEW, "DefView: WM_DSV_UPDATETHUMBNAIL after WM_DESTROY!!!");
  4401. _CleanupUpdateThumbnail((DSV_UPDATETHUMBNAIL*)msg.lParam);
  4402. }
  4403. }
  4404. while (PeekMessage(&msg, hwnd, WM_DSV_POSTCREATEINFOTIP, WM_DSV_POSTCREATEINFOTIP, PM_REMOVE))
  4405. {
  4406. // PeekMessage(hwnd) can return messages posted to CHILDREN of this hwnd...
  4407. // Verify that the message was really for us.
  4408. //
  4409. if (msg.hwnd == hwnd)
  4410. {
  4411. TraceMsg(TF_DEFVIEW, "DefView: WM_DSV_POSTCREATEINFOTIP after WM_DESTROY!!!");
  4412. _OnPostCreateInfotipCleanup((TOOLINFO *)msg.wParam);
  4413. }
  4414. }
  4415. }
  4416. void CDefView::_CallRefresh(BOOL fPreRefresh)
  4417. {
  4418. if (fPreRefresh)
  4419. {
  4420. IUnknown_Exec(_pshf, NULL, OLECMDID_REFRESH, 0, NULL, NULL);
  4421. }
  4422. CallCB(SFVM_REFRESH, fPreRefresh, 0);
  4423. }
  4424. void CDefView::FillDone()
  4425. {
  4426. SendMessage(_hwndListview, WM_SETREDRAW, (WPARAM)FALSE, 0);
  4427. _fListviewRedraw = TRUE;
  4428. AddRef(); // hold a ref to ourself while in this function.
  4429. _fAllowSearchingWindow = FALSE;
  4430. _PostFillDoneMessage();
  4431. if (_bBkFilling)
  4432. _OnStopBackgroundEnum();
  4433. HRESULT hr = _pEnumTask->FillObjectsDoneToView();
  4434. _pEnumTask->Release();
  4435. _pEnumTask = NULL;
  4436. if (SUCCEEDED(hr))
  4437. {
  4438. // Clear our error state, if we were in one
  4439. _fEnumFailed = FALSE;
  4440. if (_fSyncOnFillDone)
  4441. {
  4442. _vs.Sync(this, TRUE);
  4443. _fSyncOnFillDone = FALSE;
  4444. }
  4445. ShowHideListView();
  4446. // set the focus on the first item.
  4447. _FocusOnSomething();
  4448. _DoThumbnailReadAhead();
  4449. }
  4450. else
  4451. {
  4452. // The fill objects failed for some reason, go into error mode
  4453. TraceMsg(TF_WARNING, "::FillObjects failed to enumerate for some reason");
  4454. _fEnumFailed = TRUE;
  4455. ShowHideListView();
  4456. }
  4457. // Tell the defview client that this window has been refreshed
  4458. _CallRefresh(FALSE);
  4459. _OnContentsChanged();
  4460. _UpdateStatusBar(TRUE);
  4461. _PostEnumDoneMessage();
  4462. Release();
  4463. SendMessage(_hwndListview, WM_SETREDRAW, (WPARAM)TRUE, 0);
  4464. _fListviewRedraw = FALSE;
  4465. }
  4466. HRESULT CDefView::_OnStartBackgroundEnum()
  4467. {
  4468. _GlobeAnimation(TRUE);
  4469. _ShowSearchUI(TRUE);
  4470. _bBkFilling = TRUE;
  4471. return S_OK;
  4472. }
  4473. HRESULT CDefView::_OnStopBackgroundEnum()
  4474. {
  4475. _bBkFilling = FALSE;
  4476. _GlobeAnimation(FALSE);
  4477. _ShowSearchUI(FALSE);
  4478. return S_OK;
  4479. }
  4480. HRESULT CDefView::_OnBackgroundEnumDone()
  4481. {
  4482. FillDone();
  4483. _UpdateStatusBar(FALSE);
  4484. CallCB(SFVM_BACKGROUNDENUMDONE, 0, 0);
  4485. return S_OK;
  4486. }
  4487. HRESULT EmptyBkgrndThread(IShellTaskScheduler *pScheduler)
  4488. {
  4489. HRESULT hr = S_OK;
  4490. if (pScheduler)
  4491. {
  4492. // empty the queue and wait until it is empty.....
  4493. hr = pScheduler->RemoveTasks(TOID_NULL, ITSAT_DEFAULT_LPARAM, TRUE);
  4494. }
  4495. return hr;
  4496. }
  4497. DWORD CDefView::_GetEnumFlags()
  4498. {
  4499. // Setup the enum flags.
  4500. DWORD grfEnumFlags = SHCONTF_NONFOLDERS;
  4501. if (_fShowAllObjects)
  4502. grfEnumFlags |= SHCONTF_INCLUDEHIDDEN;
  4503. //Is this View in Common Dialog
  4504. if (!(grfEnumFlags & SHCONTF_INCLUDEHIDDEN))
  4505. {
  4506. // Ask Common dialog if its wants to show all files
  4507. ICommDlgBrowser2 *pcdb2;
  4508. if (SUCCEEDED(_psb->QueryInterface(IID_PPV_ARG(ICommDlgBrowser2, &pcdb2))))
  4509. {
  4510. DWORD dwFlags = 0;
  4511. pcdb2->GetViewFlags(&dwFlags);
  4512. if (dwFlags & CDB2GVF_SHOWALLFILES)
  4513. grfEnumFlags |= SHCONTF_INCLUDEHIDDEN;
  4514. pcdb2->Release();
  4515. }
  4516. }
  4517. if (!(_fs.fFlags & FWF_NOSUBFOLDERS))
  4518. grfEnumFlags |= SHCONTF_FOLDERS;
  4519. return grfEnumFlags;
  4520. }
  4521. HRESULT CDefView::FillObjectsShowHide(BOOL fInteractive)
  4522. {
  4523. HRESULT hr = S_OK;
  4524. DECLAREWAITCURSOR;
  4525. SetWaitCursor(); // This is a potentially long operation
  4526. // To get here we're either not enumerating at all,
  4527. // or we are enumerating on the background thread,
  4528. // or we got re-entered
  4529. ASSERT((!_pEnumTask&&!_bBkFilling) || (_pEnumTask));
  4530. if (_pEnumTask)
  4531. {
  4532. if (fInteractive)
  4533. {
  4534. // This is in response to the user pressing F5,
  4535. // assume the current enumeration will be valid
  4536. hr = S_FALSE;
  4537. }
  4538. else if (!_bBkFilling)
  4539. {
  4540. // We're not on the background but we have a _pEnumTask, this means
  4541. // that we got re-entered during the below call to FillObjectsToDPA.
  4542. // Assume the current enumeration attempt will be valid
  4543. hr = S_FALSE;
  4544. }
  4545. else
  4546. {
  4547. if (_pScheduler)
  4548. {
  4549. // An UPDATEDIR or equivalent happened, anything already enumerated could be bad.
  4550. // Tell the current enumeration task to give up
  4551. _pScheduler->RemoveTasks(TOID_DVBackgroundEnum, ITSAT_DEFAULT_LPARAM, FALSE);
  4552. _pScheduler->RemoveTasks(TOID_DVBackgroundGroup, ITSAT_DEFAULT_LPARAM, TRUE);
  4553. }
  4554. ASSERT(_bBkFilling);
  4555. _OnStopBackgroundEnum();
  4556. _pEnumTask->Release();
  4557. _pEnumTask = NULL;
  4558. }
  4559. }
  4560. if (S_OK==hr)
  4561. {
  4562. _pEnumTask = new CDefviewEnumTask(this);
  4563. if (_pEnumTask)
  4564. {
  4565. // Note: It is possible for us to get re-entered during FillObjectsToDPA,
  4566. // since we pass our HWND to the enumerator.
  4567. _pEnumTask->FillObjectsToDPA(fInteractive);
  4568. hr = _pEnumTask->FillObjectsDPAToDone();
  4569. }
  4570. else
  4571. {
  4572. _fEnumFailed = TRUE;
  4573. ShowHideListView();
  4574. hr = E_OUTOFMEMORY;
  4575. }
  4576. }
  4577. ResetWaitCursor();
  4578. return hr;
  4579. }
  4580. // This implementation uses following assumptions.
  4581. // (1) The IShellFolder uses CDefFolderMenu.
  4582. // (2) The CDefFolderMenu always add the folder at the top.
  4583. #define EC_SELECTION 0
  4584. #define EC_BACKGROUND 1
  4585. #define EC_EITHER 3
  4586. HRESULT CDefView::_ExplorerCommand(UINT idFCIDM)
  4587. {
  4588. HRESULT hr = E_FAIL;
  4589. static struct {
  4590. UINT idmFC;
  4591. UINT fBackground;
  4592. LPCTSTR pszVerb;
  4593. } const c_idMap[] = {
  4594. { SFVIDM_FILE_RENAME, EC_SELECTION, c_szRename },
  4595. { SFVIDM_FILE_DELETE, EC_SELECTION, c_szDelete },
  4596. { SFVIDM_FILE_PROPERTIES, EC_EITHER, c_szProperties },
  4597. { SFVIDM_EDIT_COPY, EC_SELECTION, c_szCopy },
  4598. { SFVIDM_EDIT_CUT, EC_SELECTION, c_szCut },
  4599. { SFVIDM_FILE_LINK, EC_SELECTION, c_szLink },
  4600. { SFVIDM_EDIT_PASTE, EC_BACKGROUND, c_szPaste },
  4601. { SFVIDM_EDIT_PASTELINK, EC_BACKGROUND, c_szPasteLink },
  4602. };
  4603. for (int i = 0; i < ARRAYSIZE(c_idMap); i++)
  4604. {
  4605. if (c_idMap[i].idmFC == idFCIDM)
  4606. {
  4607. IContextMenu *pcm;
  4608. if (c_idMap[i].fBackground == EC_BACKGROUND)
  4609. {
  4610. hr = _pshf->CreateViewObject(_hwndMain, IID_PPV_ARG(IContextMenu, &pcm));
  4611. }
  4612. else
  4613. {
  4614. hr = _CreateSelectionContextMenu(IID_PPV_ARG(IContextMenu, &pcm));
  4615. if (FAILED(hr) && (c_idMap[i].fBackground == EC_EITHER) && !ListView_GetSelectedCount(_hwndListview))
  4616. {
  4617. hr = _pshf->CreateViewObject(_hwndMain, IID_PPV_ARG(IContextMenu, &pcm));
  4618. }
  4619. }
  4620. if (SUCCEEDED(hr))
  4621. {
  4622. CMINVOKECOMMANDINFOEX ici = {0};
  4623. ici.cbSize = sizeof(ici);
  4624. ici.hwnd = _hwndMain;
  4625. ici.nShow = SW_NORMAL;
  4626. // record if shift or control was being held down
  4627. SetICIKeyModifiers(&ici.fMask);
  4628. // Fill in both the ansi verb and the unicode verb since we
  4629. // don't know who is going to be processing this thing.
  4630. CHAR szVerbAnsi[40];
  4631. SHUnicodeToAnsi(c_idMap[i].pszVerb, szVerbAnsi, ARRAYSIZE(szVerbAnsi));
  4632. ici.lpVerb = szVerbAnsi;
  4633. ici.lpVerbW = c_idMap[i].pszVerb;
  4634. ici.fMask |= CMIC_MASK_UNICODE;
  4635. HMENU hmenu = CreatePopupMenu();
  4636. if (hmenu)
  4637. {
  4638. IUnknown_SetSite(pcm, SAFECAST(this, IOleCommandTarget *));
  4639. pcm->QueryContextMenu(hmenu, 0, CONTEXTMENU_IDCMD_FIRST, CONTEXTMENU_IDCMD_LAST, 0);
  4640. _bContextMenuMode = TRUE;
  4641. hr = _InvokeContextMenu(pcm, &ici);
  4642. _bContextMenuMode = FALSE;
  4643. DestroyMenu(hmenu);
  4644. IUnknown_SetSite(pcm, NULL);
  4645. }
  4646. pcm->Release();
  4647. }
  4648. else
  4649. {
  4650. // keys are pressed when there is no selection.
  4651. MessageBeep(0);
  4652. }
  4653. break;
  4654. }
  4655. ASSERT(i < ARRAYSIZE(c_idMap));
  4656. }
  4657. return hr;
  4658. }
  4659. STDAPI_(BOOL) Def_IsPasteAvailable(IDropTarget *pdtgt, DWORD *pdwEffect);
  4660. BOOL CDefView::_AllowCommand(UINT uID)
  4661. {
  4662. DWORD dwAttribsIn;
  4663. DWORD dwEffect;
  4664. switch (uID)
  4665. {
  4666. case SFVIDM_EDIT_PASTE:
  4667. return Def_IsPasteAvailable(_pdtgtBack, &dwEffect);
  4668. case SFVIDM_EDIT_PASTELINK:
  4669. Def_IsPasteAvailable(_pdtgtBack, &dwEffect);
  4670. return dwEffect & DROPEFFECT_LINK;
  4671. case SFVIDM_EDIT_COPY:
  4672. dwAttribsIn = SFGAO_CANCOPY;
  4673. break;
  4674. case SFVIDM_EDIT_CUT:
  4675. dwAttribsIn = SFGAO_CANMOVE;
  4676. break;
  4677. case SFVIDM_FILE_DELETE:
  4678. dwAttribsIn = SFGAO_CANDELETE;
  4679. break;
  4680. case SFVIDM_FILE_LINK:
  4681. dwAttribsIn = SFGAO_CANLINK;
  4682. break;
  4683. case SFVIDM_FILE_PROPERTIES:
  4684. dwAttribsIn = SFGAO_HASPROPSHEET;
  4685. break;
  4686. default:
  4687. ASSERT(FALSE);
  4688. return FALSE;
  4689. }
  4690. return _AttributesFromSel(dwAttribsIn) & dwAttribsIn;
  4691. }
  4692. // return copy of pidl of folder we're viewing
  4693. LPITEMIDLIST CDefView::_GetViewPidl()
  4694. {
  4695. LPITEMIDLIST pidl;
  4696. if (SHGetIDListFromUnk(_pshf, &pidl) != S_OK) // S_FALSE is success by empty
  4697. {
  4698. if (SUCCEEDED(CallCB(SFVM_THISIDLIST, 0, (LPARAM)&pidl)))
  4699. {
  4700. ASSERT(pidl);
  4701. }
  4702. else if (_SetupNotifyData() && _pidlMonitor)
  4703. {
  4704. pidl = ILClone(_pidlMonitor);
  4705. }
  4706. }
  4707. return pidl;
  4708. }
  4709. inline BOOL CDefView::_ItemsDeferred()
  4710. {
  4711. return _hdsaSelect != NULL;
  4712. }
  4713. BOOL CDefView::_IsListviewVisible()
  4714. {
  4715. return _fListViewShown;
  4716. }
  4717. inline BOOL CDefView::_IsOwnerData()
  4718. {
  4719. return _fs.fFlags & FWF_OWNERDATA;
  4720. }
  4721. inline BOOL CDefView::_IsCommonDialog()
  4722. {
  4723. return NULL != _pcdb;
  4724. }
  4725. BOOL CDefView::_IsDesktop()
  4726. {
  4727. return _fs.fFlags & FWF_DESKTOP;
  4728. }
  4729. BOOL CDefView::_IsViewDesktop()
  4730. {
  4731. BOOL bDesktop = FALSE;
  4732. LPITEMIDLIST pidl = _GetViewPidl();
  4733. if (pidl)
  4734. {
  4735. bDesktop = ILIsEmpty(pidl);
  4736. ILFree(pidl);
  4737. }
  4738. return bDesktop;
  4739. }
  4740. // access to the current views name ala IShellFolder::GetDisplayNameOf()
  4741. HRESULT CDefView::_GetNameAndFlags(UINT gdnFlags, LPTSTR pszPath, UINT cch, DWORD *pdwFlags)
  4742. {
  4743. *pszPath = 0;
  4744. HRESULT hr;
  4745. LPITEMIDLIST pidl = _GetViewPidl();
  4746. if (pidl)
  4747. {
  4748. hr = SHGetNameAndFlags(pidl, gdnFlags, pszPath, cch, pdwFlags);
  4749. ILFree(pidl);
  4750. }
  4751. else
  4752. hr = E_OUTOFMEMORY;
  4753. return hr;
  4754. }
  4755. // returns TRUE if the current view is a file system folder, returns the path
  4756. BOOL CDefView::_GetPath(LPTSTR pszPath)
  4757. {
  4758. *pszPath = 0;
  4759. LPITEMIDLIST pidl = _GetViewPidl();
  4760. if (pidl)
  4761. {
  4762. SHGetPathFromIDList(pidl, pszPath);
  4763. ILFree(pidl);
  4764. }
  4765. return *pszPath != 0;
  4766. }
  4767. EXTERN_C TCHAR const c_szHtmlWindowsHlp[] = TEXT("windows.chm");
  4768. // web view background colors, click mode, etc have changed
  4769. //
  4770. void CDefView::_UpdateListviewColors()
  4771. {
  4772. // First clear out our state
  4773. for (int i = 0; i < ARRAYSIZE(_crCustomColors); i++)
  4774. _crCustomColors[i] = CLR_MYINVALID;
  4775. // Then read the registry/desktop.ini
  4776. LPCTSTR pszLegacyWatermark = NULL;
  4777. SFVM_CUSTOMVIEWINFO_DATA cvi = {0};
  4778. if (SUCCEEDED(CallCB(SFVM_GETCUSTOMVIEWINFO, (WPARAM)0, (LPARAM)&cvi)))
  4779. {
  4780. if (!_IsCommonDialog() && !_IsDesktop())
  4781. {
  4782. // Set up the listview image, if any
  4783. if (*cvi.szIconAreaImage)
  4784. {
  4785. pszLegacyWatermark = cvi.szIconAreaImage;
  4786. }
  4787. // change the differing stuff
  4788. //
  4789. if (!_fClassic)
  4790. {
  4791. for (i = 0; i < ARRAYSIZE(_crCustomColors); i++)
  4792. {
  4793. COLORREF cr = cvi.crCustomColors[i];
  4794. if (ISVALIDCOLOR(cr))
  4795. {
  4796. _crCustomColors[i] = PALETTERGB(0, 0, 0) | cr;
  4797. }
  4798. }
  4799. // if there was an image specified but no custom text background,
  4800. // set to CLR_NONE so the listview text is transparent
  4801. // get combined view custom colors
  4802. if (!ISVALIDCOLOR(_crCustomColors[CRID_CUSTOMTEXTBACKGROUND]) && cvi.szIconAreaImage[0])
  4803. {
  4804. _crCustomColors[CRID_CUSTOMTEXTBACKGROUND] = CLR_NONE;
  4805. }
  4806. }
  4807. }
  4808. }
  4809. _SetLegacyWatermark(pszLegacyWatermark);
  4810. _SetFolderColors();
  4811. _UpdateSelectionMode();
  4812. }
  4813. BOOL CDefView::_IsReportView()
  4814. {
  4815. return (_UxGetView() == LV_VIEW_DETAILS);
  4816. }
  4817. BOOL CDefView::HasCurrentViewWindowFocus()
  4818. {
  4819. BOOL fRet = false;
  4820. HWND hwndCurrentFocus = GetFocus();
  4821. if (hwndCurrentFocus)
  4822. {
  4823. fRet = (SHIsChildOrSelf(_hwndListview, hwndCurrentFocus) == S_OK);
  4824. }
  4825. return fRet;
  4826. }
  4827. HWND CDefView::ViewWindowSetFocus()
  4828. {
  4829. SetFocus(_hwndListview);
  4830. if (!_IsDesktop())
  4831. {
  4832. _cFrame._uState = SVUIA_ACTIVATE_FOCUS;
  4833. }
  4834. return _hwndListview;
  4835. }
  4836. HRESULT CDefView::_GetSFVMViewState(UINT uViewMode, SFVM_VIEW_DATA* pvi)
  4837. {
  4838. HRESULT hr = CallCB(SFVM_GETVIEWDATA, (WPARAM)uViewMode, (LPARAM)pvi);
  4839. if (FAILED(hr))
  4840. {
  4841. pvi->dwOptions = SFVMQVI_NORMAL;
  4842. }
  4843. return hr;
  4844. }
  4845. HRESULT CDefView::_GetSFVMViewInfoTemplate(UINT uViewMode, SFVM_WEBVIEW_TEMPLATE_DATA* pvit)
  4846. {
  4847. return CallCB(SFVM_GETWEBVIEW_TEMPLATE, (WPARAM)uViewMode, (LPARAM)pvit);;
  4848. }
  4849. HRESULT CDefView::_GetWebViewMoniker(LPWSTR pszMoniker, DWORD cchMoniker)
  4850. {
  4851. SFVM_WEBVIEW_TEMPLATE_DATA vit;
  4852. if (SUCCEEDED(_GetSFVMViewInfoTemplate(_fs.ViewMode, &vit)))
  4853. {
  4854. StrCpyN(pszMoniker, vit.szWebView, cchMoniker);
  4855. }
  4856. else
  4857. {
  4858. pszMoniker[0] = L'\0';
  4859. }
  4860. return *pszMoniker ? S_OK : E_FAIL;
  4861. }
  4862. // Show or hide Web View content
  4863. //
  4864. // This does not affect the View Mode of the listview (it does tweak desktop listview for _fCombinedView stuff)
  4865. //
  4866. // fShow==TRUE -> hr is success/fail of showing web view
  4867. // fShow==FALSE -> hr is E_FAIL (nobody looks at return code of turning web view off)
  4868. //
  4869. HRESULT CDefView::_SwitchToWebView(BOOL fShow)
  4870. {
  4871. HRESULT hr = E_FAIL;
  4872. // Cache the focus/select state across this transition
  4873. BOOL bSetFocusRequired = HasCurrentViewWindowFocus();
  4874. if (fShow)
  4875. {
  4876. // For now, the desktop is always a combined view...
  4877. if (_IsDesktop())
  4878. {
  4879. BOOL fCombinedViewOld = (BOOL)_fCombinedView;
  4880. SHELLSTATE ss;
  4881. SHGetSetSettings(&ss, SSF_HIDEICONS | SSF_DESKTOPHTML | SSF_STARTPANELON, FALSE);
  4882. // Does the user want desktop in HyperText view?
  4883. if (ss.fDesktopHTML)
  4884. _fCombinedView = TRUE;
  4885. if (ss.fHideIcons)
  4886. _fs.fFlags |= FWF_NOICONS;
  4887. else
  4888. _fs.fFlags &= ~FWF_NOICONS;
  4889. if (_fCombinedView && !fCombinedViewOld)
  4890. {
  4891. EnableCombinedView(this, TRUE);
  4892. ListView_SetExtendedListViewStyleEx(_hwndListview, LVS_EX_REGIONAL, LVS_EX_REGIONAL);
  4893. _SetFolderColors();
  4894. }
  4895. }
  4896. WCHAR wszMoniker[MAX_PATH];
  4897. hr = _GetWebViewMoniker(wszMoniker, ARRAYSIZE(wszMoniker));
  4898. if (SUCCEEDED(hr))
  4899. {
  4900. if (_IsDesktop())
  4901. {
  4902. IActiveDesktopP *piadp;
  4903. if (SUCCEEDED(SHCoCreateInstance(NULL, &CLSID_ActiveDesktop, NULL, IID_PPV_ARG(IActiveDesktopP, &piadp))))
  4904. {
  4905. piadp->EnsureUpdateHTML();
  4906. piadp->Release();
  4907. }
  4908. hr = _cFrame.ShowWebView(wszMoniker);
  4909. }
  4910. else if (SHRestricted(REST_REVERTWEBVIEWSECURITY))
  4911. {
  4912. hr = _cFrame.ShowWebView(wszMoniker);
  4913. }
  4914. else if (!_fUserRejectedWebViewTemplate)
  4915. {
  4916. WCHAR szTemplate[MAX_PATH];
  4917. DWORD cchTemplate = ARRAYSIZE(szTemplate);
  4918. if (PathIsURL(wszMoniker))
  4919. {
  4920. hr = PathCreateFromUrl(wszMoniker, szTemplate, &cchTemplate, 0);
  4921. }
  4922. else
  4923. {
  4924. StrCpyN(szTemplate, wszMoniker, ARRAYSIZE(szTemplate));
  4925. hr = S_OK;
  4926. }
  4927. if (SUCCEEDED(hr))
  4928. {
  4929. DWORD dwFlags = SHRVT_VALIDATE | SHRVT_ALLOW_INTRANET;
  4930. if (SHRestricted(REST_ALLOWUNHASHEDWEBVIEW))
  4931. {
  4932. dwFlags |= SHRVT_PROMPTUSER | SHRVT_REGISTERIFPROMPTOK;
  4933. }
  4934. hr = SHRegisterValidateTemplate(szTemplate, dwFlags);
  4935. if (SUCCEEDED(hr))
  4936. {
  4937. hr = _cFrame.ShowWebView(wszMoniker);
  4938. }
  4939. else
  4940. {
  4941. _fUserRejectedWebViewTemplate = TRUE;
  4942. }
  4943. }
  4944. }
  4945. }
  4946. if (FAILED(hr))
  4947. {
  4948. fShow = FALSE;
  4949. }
  4950. else
  4951. {
  4952. RECT rcClient;
  4953. // Make sure the new view is the correct size
  4954. GetClientRect(_hwndView, &rcClient);
  4955. _cFrame.SetRect(&rcClient);
  4956. ShowHideListView();
  4957. }
  4958. }
  4959. if (!fShow)
  4960. {
  4961. _cFrame.HideWebView();
  4962. // If we were combined, then get the listview out of region mode and
  4963. // reset the color scheme. Also, turn off the combined bit.
  4964. if (_fCombinedView)
  4965. {
  4966. _fCombinedView = FALSE;
  4967. ListView_SetExtendedListViewStyleEx(_hwndListview, LVS_EX_REGIONAL, 0);
  4968. EnableCombinedView(this, FALSE);
  4969. _SetFolderColors();
  4970. }
  4971. }
  4972. // restore focus/select state -- if we switched to web view it will put much of
  4973. // this into a "pending" state until the listview is re-shown inside the web content
  4974. //
  4975. if (bSetFocusRequired)
  4976. {
  4977. CallCB(SFVM_SETFOCUS, 0, 0);
  4978. ViewWindowSetFocus();
  4979. }
  4980. CheckToolbar();
  4981. _EnableDisableTBButtons();
  4982. // make sure that the listview settings get refreshed anyway (back image)
  4983. _UpdateListviewColors();
  4984. return hr;
  4985. }
  4986. void CDefView::_RemoveThumbviewTasks()
  4987. {
  4988. if (_pScheduler)
  4989. {
  4990. _pScheduler->RemoveTasks(TOID_ExtractImageTask, ITSAT_DEFAULT_LPARAM, FALSE);
  4991. _pScheduler->RemoveTasks(TOID_CheckCacheTask, ITSAT_DEFAULT_LPARAM, FALSE);
  4992. _pScheduler->RemoveTasks(TOID_ReadAheadHandler, ITSAT_DEFAULT_LPARAM, FALSE);
  4993. _fReadAhead = FALSE;
  4994. }
  4995. }
  4996. //
  4997. // This function checkes to see if the list view needs to be shown; then shows it.
  4998. // If it needs to be hidden, hides it! You must call this function every time
  4999. // you change a bit of state that could change the show/hide state of listview.
  5000. //
  5001. // Let me repeat that: call this function EVERY TIME you change state that
  5002. // affects our show/hide.
  5003. //
  5004. HRESULT CDefView::ShowHideListView()
  5005. {
  5006. // NOTE: this is where most of the flicker bugs come from -- showing the
  5007. // listview too early. This is touchy code, so be careful when you change it.
  5008. // And plese document all changes for future generations. Thanks.
  5009. //
  5010. // Standard "is listview shown" check
  5011. //
  5012. // If our view hasn't been UIActivate()d yet, then we are waiting until
  5013. // the IShellBrowser selects us as the active view.
  5014. //
  5015. // App compat for above UIActivate() change:
  5016. // Adaptec Easy CD Creator never calls IShellView::UIActivate.
  5017. // They got away with it because UIActivate didn't used to do much,
  5018. // but now we use UIActivate to decide when to show our icons. They forget
  5019. // to call it and the icons never show up.
  5020. // So if we are in Win95 Defview compatibility mode, then
  5021. // go ahead and show the icons now. The app gets flicker, but at least
  5022. // the icons show up at all.
  5023. //
  5024. // Don't show the listview if we're told to not show it, or we see an error during enum.
  5025. //
  5026. // If we're enumerating in the background, don't show
  5027. //
  5028. // Potential problem: We used to defer SelectPendingSelectedItems until:
  5029. // "_fListViewShown && (_cFrame._dwConnectionCookie /*&& !_cFrame._fReadyStateInteractiveProcessed*/)"
  5030. // Selecting before readystatedone may pose a problem, but I don't see how it could
  5031. // be a problem unless showing the view early is a problem as well, which this code didn't check.
  5032. //
  5033. if ((!_cFrame.IsWebView() || _fGetWindowLV || _fCombinedView) // we think icons should be visible
  5034. && (_uState != SVUIA_DEACTIVATE || (SHGetAppCompatFlags(ACF_WIN95DEFVIEW) & ACF_WIN95DEFVIEW)) // async defview means we don't show before we transition out of DEACTIVE
  5035. && !(BOOLIFY(_fs.fFlags & FWF_NOICONS)) // check if we've been told to not show icons
  5036. && !_fEnumFailed // failed enumeration wants _hwndView to show through, not _hwndListview
  5037. && !(_crefSearchWindow && _hwndStatic) // keep the listview hidden while we show the "searching" window
  5038. )
  5039. {
  5040. // Make sure we do each transition only once - we do more than just show the window
  5041. if (!_fListViewShown)
  5042. {
  5043. _fListViewShown = TRUE;
  5044. // Bring this to the top while showing it to avoid a second paint when
  5045. // _hwndStatic is destroyed (listview has optimizations when hidden,
  5046. // and it will repaint when once shown even if though it may be obscured)
  5047. //
  5048. SetWindowPos(_hwndListview, HWND_TOP, 0, 0, 0, 0,
  5049. SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW);
  5050. _OnMoveWindowToTop(_hwndListview);
  5051. // Remove _hwndStatic after listview is moved to top to avoid a re-paint
  5052. if (_hwndStatic)
  5053. {
  5054. DestroyWindow(_hwndStatic);
  5055. _hwndStatic = NULL;
  5056. }
  5057. // if we need to select items, do it now that the window is shown
  5058. SelectPendingSelectedItems();
  5059. }
  5060. }
  5061. else
  5062. {
  5063. if (_fListViewShown)
  5064. {
  5065. _fListViewShown = FALSE;
  5066. ShowWindow(_hwndListview, SW_HIDE);
  5067. }
  5068. // If FWF_NOICONS is set and the enumertion went to the background thread we need
  5069. // to make sure that we turn of the searchui.
  5070. if (BOOLIFY(_fs.fFlags & FWF_NOICONS) && _hwndStatic && 0 == _crefSearchWindow)
  5071. {
  5072. DestroyWindow(_hwndStatic);
  5073. _hwndStatic = NULL;
  5074. }
  5075. }
  5076. return S_OK;
  5077. }
  5078. IShellItemArray* CDefView::_GetFolderAsShellItemArray()
  5079. {
  5080. if (!_pFolderShellItemArray && _pshfParent && _pidlRelative)
  5081. {
  5082. SHCreateShellItemArray(NULL, _pshfParent, 1, (LPCITEMIDLIST *)&_pidlRelative, &_pFolderShellItemArray);
  5083. }
  5084. return _pFolderShellItemArray;
  5085. }
  5086. // if the attributes dwAttribMask for pdo exactly match dwAttribValue, this item should be enabled
  5087. HRESULT CDefView::_CheckAttribs(IShellItemArray *psiItemArray, DWORD dwAttribMask, DWORD dwAttribValue, UISTATE* puisState)
  5088. {
  5089. DWORD dwAttrib = 0;
  5090. HRESULT hr;
  5091. if (NULL == psiItemArray)
  5092. {
  5093. psiItemArray = _GetFolderAsShellItemArray();
  5094. }
  5095. if (psiItemArray)
  5096. {
  5097. hr = psiItemArray->GetAttributes(SIATTRIBFLAGS_APPCOMPAT, dwAttribMask, &dwAttrib);
  5098. if (FAILED(hr))
  5099. dwAttrib = 0;
  5100. }
  5101. else
  5102. hr = S_OK;
  5103. *puisState = (dwAttribValue == dwAttrib) ? UIS_ENABLED : UIS_HIDDEN;
  5104. return hr;
  5105. }
  5106. HRESULT CDefView::_CanWrite(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  5107. {
  5108. CDefView* pThis = (CDefView*)(void*)pv;
  5109. return pThis->_CheckAttribs(psiItemArray, SFGAO_READONLY|SFGAO_STORAGE, SFGAO_STORAGE, puisState);
  5110. }
  5111. HRESULT CDefView::_CanRename(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  5112. {
  5113. CDefView* pThis = (CDefView*)(void*)pv;
  5114. return pThis->_CheckAttribs(psiItemArray, SFGAO_CANRENAME, SFGAO_CANRENAME, puisState);
  5115. }
  5116. HRESULT CDefView::_CanMove(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  5117. {
  5118. CDefView* pThis = (CDefView*)(void*)pv;
  5119. return pThis->_CheckAttribs(psiItemArray, SFGAO_CANMOVE, SFGAO_CANMOVE, puisState);
  5120. }
  5121. HRESULT CDefView::_CanCopy(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  5122. {
  5123. CDefView* pThis = (CDefView*)(void*)pv;
  5124. return pThis->_CheckAttribs(psiItemArray,SFGAO_CANCOPY, SFGAO_CANCOPY, puisState);
  5125. }
  5126. HRESULT CDefView::_CanPublish(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  5127. {
  5128. CDefView* pThis = (CDefView*)(void*)pv;
  5129. *puisState = UIS_HIDDEN;
  5130. if (pThis->_wvLayout.dwLayout & SFVMWVL_NOPUBLISH)
  5131. {
  5132. // bail out early with UIS_HIDDEN, we dont show the verb
  5133. return S_OK;
  5134. }
  5135. // Iterate first 10 items because that is what old code did before
  5136. // switching to IShellItemArray. Since the attribs that are
  5137. // being requested for are already being cached in the ShellItemArray
  5138. // may as well always ask for all.
  5139. if (psiItemArray)
  5140. {
  5141. IEnumShellItems *pEnumShellItems;
  5142. if (SUCCEEDED(psiItemArray->EnumItems(&pEnumShellItems)))
  5143. {
  5144. IShellItem *pShellItem;
  5145. DWORD dwIterationCount = 0;
  5146. BOOL fHide = FALSE, fHasStreams = FALSE, fHasStorages = FALSE;
  5147. while (!fHide && (dwIterationCount < 10) && (S_OK == pEnumShellItems->Next(1, &pShellItem, NULL)))
  5148. {
  5149. SFGAOF dwAttribs = SFGAO_STORAGE | SFGAO_STREAM;
  5150. HRESULT hrAttribs = pShellItem->GetAttributes(dwAttribs, &dwAttribs);
  5151. pShellItem->Release();
  5152. pShellItem = NULL; // null to catch if we use it again.
  5153. if (SUCCEEDED(hrAttribs))
  5154. {
  5155. if (!(dwAttribs & (SFGAO_STORAGE | SFGAO_STREAM)))
  5156. {
  5157. // if this item doesn't have either storage or stream, hide the task.
  5158. fHide = TRUE;
  5159. }
  5160. else if (dwAttribs & SFGAO_STREAM)
  5161. {
  5162. // if we have a folder and files, hide the task.
  5163. fHide = fHasStorages;
  5164. fHasStreams = TRUE;
  5165. }
  5166. else if (dwAttribs & SFGAO_STORAGE)
  5167. {
  5168. // if we have multiple folders or a folder and files, hide the task.
  5169. fHide = fHasStorages || fHasStreams;
  5170. fHasStorages = TRUE;
  5171. }
  5172. }
  5173. ++dwIterationCount;
  5174. }
  5175. if (!fHide)
  5176. *puisState = UIS_ENABLED;
  5177. pEnumShellItems->Release();
  5178. }
  5179. }
  5180. else
  5181. {
  5182. // if nothing is selected, enable the task if the current folder is a storage.
  5183. LPITEMIDLIST pidl = pThis->_GetViewPidl();
  5184. if (pidl)
  5185. {
  5186. if (SHGetAttributes(NULL, pidl, SFGAO_STORAGE))
  5187. {
  5188. *puisState = UIS_ENABLED;
  5189. }
  5190. ILFree(pidl);
  5191. }
  5192. }
  5193. return S_OK;
  5194. }
  5195. // Note - _DoesStaticMenuHaveVerb only checks the first pidl in the data object for now
  5196. // So only use it for single-selections
  5197. // -DSheldon
  5198. BOOL CDefView::_DoesStaticMenuHaveVerb(IShellItemArray *psiItemArray, LPCWSTR pszVerb)
  5199. {
  5200. BOOL fHasVerb = FALSE;
  5201. IShellItem *pshItem;
  5202. // get first shellItem in the array.
  5203. if (SUCCEEDED(psiItemArray->GetItemAt(0,&pshItem)))
  5204. {
  5205. IQueryAssociations* pqa;
  5206. if (SUCCEEDED(pshItem->BindToHandler(NULL, BHID_SFUIObject, IID_PPV_ARG(IQueryAssociations, &pqa))))
  5207. {
  5208. DWORD cch = 0;
  5209. fHasVerb = SUCCEEDED(pqa->GetString(0, ASSOCSTR_COMMAND, pszVerb, NULL, &cch));
  5210. pqa->Release();
  5211. }
  5212. pshItem->Release();
  5213. }
  5214. return fHasVerb;
  5215. }
  5216. HRESULT CDefView::_GetFullPathNameAt(IShellItemArray *psiItemArray,DWORD dwIndex,LPOLESTR *pszPath)
  5217. {
  5218. HRESULT hr = E_FAIL;
  5219. IShellItem *pShellItem;
  5220. if (NULL == psiItemArray || NULL == pszPath)
  5221. {
  5222. ASSERT(psiItemArray);
  5223. ASSERT(pszPath);
  5224. return E_INVALIDARG;
  5225. }
  5226. // get the path of the first item in the ShellArray.
  5227. hr = psiItemArray->GetItemAt(dwIndex,&pShellItem);
  5228. if (SUCCEEDED(hr))
  5229. {
  5230. hr = pShellItem->GetDisplayName(SIGDN_FILESYSPATH,pszPath);
  5231. pShellItem->Release();
  5232. }
  5233. return hr;
  5234. }
  5235. HRESULT CDefView::_CanShare(IUnknown* pv,IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  5236. {
  5237. HRESULT hr = E_FAIL;
  5238. CDefView* pThis = (CDefView*)(void*)pv;
  5239. *puisState = UIS_DISABLED;
  5240. if (!psiItemArray)
  5241. {
  5242. psiItemArray = pThis->_GetFolderAsShellItemArray();
  5243. }
  5244. if (psiItemArray)
  5245. {
  5246. #ifdef DEBUG
  5247. // Sanity check.
  5248. DWORD dwNumItems;
  5249. ASSERT(S_OK == psiItemArray->GetCount(&dwNumItems));
  5250. ASSERT(1 == dwNumItems);
  5251. #endif
  5252. IShellItem *psi;
  5253. hr = psiItemArray->GetItemAt(0, &psi);
  5254. if (SUCCEEDED(hr))
  5255. {
  5256. // Retrieve pidl.
  5257. LPITEMIDLIST pidl;
  5258. hr = SHGetIDListFromUnk(psi, &pidl);
  5259. if (SUCCEEDED(hr))
  5260. {
  5261. // Retrieve path and attributes.
  5262. WCHAR szPath[MAX_PATH];
  5263. DWORD dwAttributes = SFGAO_LINK;
  5264. hr = SHGetNameAndFlags(pidl, SHGDN_FORPARSING, szPath, ARRAYSIZE(szPath), &dwAttributes);
  5265. if (SUCCEEDED(hr) && !(dwAttributes & SFGAO_LINK) && !PathIsRemote(szPath))
  5266. {
  5267. if (!g_hmodNTSHRUI)
  5268. {
  5269. g_hmodNTSHRUI = LoadLibrary(L"ntshrui.dll");
  5270. }
  5271. if (g_hmodNTSHRUI)
  5272. {
  5273. PFNCANSHAREFOLDERW pfnCanShareFolder = (PFNCANSHAREFOLDERW)GetProcAddress(g_hmodNTSHRUI, "CanShareFolderW");
  5274. if (pfnCanShareFolder)
  5275. {
  5276. *puisState = (S_OK == pfnCanShareFolder(szPath)) ? UIS_ENABLED : UIS_DISABLED;
  5277. }
  5278. }
  5279. }
  5280. ILFree(pidl);
  5281. }
  5282. psi->Release();
  5283. }
  5284. }
  5285. return hr;
  5286. }
  5287. HRESULT CDefView::_CanEmail(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  5288. {
  5289. DWORD dwAttributes = 0;
  5290. // Prevent people from attempting to e-mail non-filesystem objects.
  5291. // Attempting to attach such objects to an e-mail message fails.
  5292. // An example of this type of failure is attempting to e-mail
  5293. // connectoids in the "Network Connections" folder.
  5294. if (psiItemArray)
  5295. {
  5296. psiItemArray->GetAttributes(SIATTRIBFLAGS_APPCOMPAT, SFGAO_FILESYSTEM, &dwAttributes);
  5297. }
  5298. *puisState = dwAttributes & SFGAO_FILESYSTEM ? UIS_ENABLED : UIS_DISABLED;
  5299. return S_OK;
  5300. }
  5301. HRESULT CDefView::_CanPrint(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  5302. {
  5303. if (!(((CDefView*)(void*)pv)->_wvLayout.dwLayout & SFVMWVL_NOPRINT))
  5304. return _HasPrintVerb(pv, psiItemArray, fOkToBeSlow, puisState);
  5305. *puisState = UIS_HIDDEN;
  5306. return S_OK;
  5307. }
  5308. HRESULT CDefView::_HasPrintVerb(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  5309. {
  5310. CDefView* pThis = (CDefView*)(void*)pv;
  5311. if (!psiItemArray)
  5312. {
  5313. psiItemArray = pThis->_GetFolderAsShellItemArray();
  5314. }
  5315. BOOL fHasPrint = _DoesStaticMenuHaveVerb(psiItemArray,c_szPrintW);
  5316. *puisState = (fHasPrint) ? UIS_ENABLED : UIS_HIDDEN;
  5317. return S_OK;
  5318. }
  5319. HRESULT CDefView::_CanDelete(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  5320. {
  5321. CDefView* pThis = (CDefView*)(void*)pv;
  5322. return pThis->_CheckAttribs(psiItemArray, SFGAO_CANDELETE, SFGAO_CANDELETE, puisState);
  5323. }
  5324. // determines if defview is hosted over the system drive root or not
  5325. BOOL CDefView::_IsSystemDrive(void)
  5326. {
  5327. TCHAR szPath[MAX_PATH];
  5328. TCHAR szSystemDrive[4];
  5329. BOOL bResult = FALSE;
  5330. if (SUCCEEDED(_GetPath(szPath)))
  5331. {
  5332. SHExpandEnvironmentStrings (TEXT("%SystemDrive%\\"), szSystemDrive, ARRAYSIZE(szSystemDrive));
  5333. if (!lstrcmpi(szPath, szSystemDrive))
  5334. {
  5335. bResult = TRUE;
  5336. }
  5337. }
  5338. return bResult;
  5339. }
  5340. HRESULT CDefView::_CanViewDrives(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  5341. {
  5342. CDefView* pThis = (CDefView*)(void*)pv;
  5343. *puisState = UIS_DISABLED;
  5344. if (pThis->_wvContent.dwFlags & SFVMWVF_BARRICADE)
  5345. {
  5346. if (pThis->_fBarrierDisplayed)
  5347. {
  5348. if (pThis->_IsSystemDrive())
  5349. {
  5350. *puisState = UIS_ENABLED;
  5351. }
  5352. }
  5353. }
  5354. return S_OK;
  5355. }
  5356. HRESULT CDefView::_CanHideDrives(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  5357. {
  5358. CDefView* pThis = (CDefView*)(void*)pv;
  5359. *puisState = UIS_DISABLED;
  5360. if (pThis->_wvContent.dwFlags & SFVMWVF_BARRICADE)
  5361. {
  5362. if (!pThis->_fBarrierDisplayed)
  5363. {
  5364. if (pThis->_IsSystemDrive())
  5365. {
  5366. *puisState = UIS_ENABLED;
  5367. }
  5368. }
  5369. }
  5370. return S_OK;
  5371. }
  5372. HRESULT CDefView::_CanViewFolder(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  5373. {
  5374. CDefView* pThis = (CDefView*)(void*)pv;
  5375. *puisState = UIS_DISABLED;
  5376. if (pThis->_wvContent.dwFlags & SFVMWVF_BARRICADE)
  5377. {
  5378. if (pThis->_fBarrierDisplayed)
  5379. {
  5380. if (!pThis->_IsSystemDrive())
  5381. {
  5382. *puisState = UIS_ENABLED;
  5383. }
  5384. }
  5385. }
  5386. return S_OK;
  5387. }
  5388. HRESULT CDefView::_CanHideFolder(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  5389. {
  5390. CDefView* pThis = (CDefView*)(void*)pv;
  5391. *puisState = UIS_DISABLED;
  5392. if (pThis->_wvContent.dwFlags & SFVMWVF_BARRICADE)
  5393. {
  5394. if (!pThis->_fBarrierDisplayed)
  5395. {
  5396. if (!pThis->_IsSystemDrive())
  5397. {
  5398. *puisState = UIS_ENABLED;
  5399. }
  5400. }
  5401. }
  5402. return S_OK;
  5403. }
  5404. HRESULT CDefView::_DoVerb(IShellItemArray *psiItemArray, LPCSTR pszVerbA)
  5405. {
  5406. HRESULT hr = E_FAIL;
  5407. if (NULL== psiItemArray)
  5408. {
  5409. IContextMenu* pcm;
  5410. hr = GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &pcm));
  5411. if (SUCCEEDED(hr))
  5412. {
  5413. hr = _InvokeContextMenuVerb(pcm, pszVerbA, 0, CMIC_MASK_FLAG_LOG_USAGE);
  5414. pcm->Release();
  5415. }
  5416. }
  5417. else
  5418. {
  5419. ASSERT(psiItemArray == _pSelectionShellItemArray);
  5420. hr = _InvokeContextMenuVerbOnSelection(pszVerbA, 0, CMIC_MASK_FLAG_LOG_USAGE);
  5421. }
  5422. return hr;
  5423. }
  5424. HRESULT CDefView::_DoDropOnClsid(REFCLSID clsidDrop, IDataObject* pdo)
  5425. {
  5426. HRESULT hr = E_FAIL;
  5427. IDataObject *pdoFree = NULL;
  5428. if (!pdo)
  5429. {
  5430. IShellItemArray *pFolder = _GetFolderAsShellItemArray();
  5431. if (pFolder)
  5432. {
  5433. hr = pFolder->BindToHandler(NULL, BHID_DataObject, IID_PPV_ARG(IDataObject, &pdoFree));
  5434. if (SUCCEEDED(hr))
  5435. {
  5436. pdo = pdoFree;
  5437. }
  5438. else
  5439. {
  5440. pdoFree = NULL;
  5441. }
  5442. }
  5443. }
  5444. if (pdo)
  5445. {
  5446. hr = SHSimulateDropOnClsid(clsidDrop, SAFECAST(this, IOleCommandTarget *), pdo);
  5447. }
  5448. ATOMICRELEASE(pdoFree); // may be NULL
  5449. return hr;
  5450. }
  5451. HRESULT CDefView::_OnNewFolder(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  5452. {
  5453. CDefView* pThis = (CDefView*)(void*)pv;
  5454. return pThis->_DoVerb(psiItemArray,c_szNewFolderA);
  5455. }
  5456. HRESULT CDefView::_OnRename(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  5457. {
  5458. CDefView* pThis = (CDefView*)(void*)pv;
  5459. return pThis->DoRename();
  5460. }
  5461. HRESULT CDefView::_OnMove(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  5462. {
  5463. CDefView* pThis = (CDefView*)(void*)pv;
  5464. return pThis->_DoMoveOrCopyTo(CLSID_MoveToMenu, psiItemArray);
  5465. }
  5466. HRESULT CDefView::_OnCopy(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  5467. {
  5468. CDefView* pThis = (CDefView*)(void*)pv;
  5469. return pThis->_DoMoveOrCopyTo(CLSID_CopyToMenu, psiItemArray);
  5470. }
  5471. HRESULT CDefView::_OnPublish(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  5472. {
  5473. HRESULT hr = S_OK;
  5474. IDataObject *pdo = NULL;
  5475. CDefView* pThis = (CDefView*)(void*)pv;
  5476. if (psiItemArray)
  5477. {
  5478. hr = psiItemArray->BindToHandler(NULL, BHID_DataObject, IID_PPV_ARG(IDataObject, &pdo));
  5479. }
  5480. if (SUCCEEDED(hr))
  5481. {
  5482. hr = pThis->_DoDropOnClsid(CLSID_PublishDropTarget, pdo);
  5483. }
  5484. ATOMICRELEASE(pdo); // may be NULL
  5485. return hr;
  5486. }
  5487. HRESULT CDefView::_OnShare(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  5488. {
  5489. HRESULT hr = E_FAIL;
  5490. CDefView* pThis = (CDefView*)(void*)pv;
  5491. if (!psiItemArray)
  5492. {
  5493. psiItemArray = pThis->_GetFolderAsShellItemArray();
  5494. }
  5495. if (NULL != psiItemArray)
  5496. {
  5497. LPOLESTR pszPath;
  5498. hr = pThis->_GetFullPathNameAt(psiItemArray, 0, &pszPath);
  5499. if (SUCCEEDED(hr))
  5500. {
  5501. if (!g_hmodNTSHRUI)
  5502. {
  5503. g_hmodNTSHRUI = LoadLibrary(L"ntshrui.dll");
  5504. }
  5505. if (g_hmodNTSHRUI)
  5506. {
  5507. PFNSHOWSHAREFOLDERUIW pfnShowShareFolderUI = (PFNSHOWSHAREFOLDERUIW) GetProcAddress(g_hmodNTSHRUI, "ShowShareFolderUIW");
  5508. if (pfnShowShareFolderUI)
  5509. {
  5510. pfnShowShareFolderUI(pThis->_hwndMain, pszPath);
  5511. }
  5512. }
  5513. CoTaskMemFree(pszPath);
  5514. }
  5515. }
  5516. return hr;
  5517. }
  5518. HRESULT CDefView::_OnEmail(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  5519. {
  5520. HRESULT hr = E_FAIL;
  5521. IDataObject *pdo = NULL;
  5522. if (psiItemArray)
  5523. {
  5524. hr = psiItemArray->BindToHandler(NULL,BHID_DataObject,IID_PPV_ARG(IDataObject,&pdo));
  5525. }
  5526. if (SUCCEEDED(hr))
  5527. {
  5528. CDefView* pThis = (CDefView*)(void*)pv;
  5529. BOOL bNoFilesFoundToEmail = TRUE;
  5530. INamespaceWalk *pnsw;
  5531. hr = CoCreateInstance(CLSID_NamespaceWalker, NULL, CLSCTX_INPROC, IID_PPV_ARG(INamespaceWalk, &pnsw));
  5532. if (SUCCEEDED(hr))
  5533. {
  5534. // Note:
  5535. // To mirror the behaviour of the selection context menu's "Send To->
  5536. // Mail Recipient", don't traverse links, mail the link file itself.
  5537. hr = pnsw->Walk(pdo, NSWF_DONT_TRAVERSE_LINKS, 0, NULL);
  5538. if (SUCCEEDED(hr))
  5539. {
  5540. UINT cItems;
  5541. LPITEMIDLIST *ppidls;
  5542. hr = pnsw->GetIDArrayResult(&cItems, &ppidls);
  5543. if (SUCCEEDED(hr))
  5544. {
  5545. if (cItems)
  5546. {
  5547. IDataObject* pdoWalk;
  5548. hr = SHCreateFileDataObject(&c_idlDesktop, cItems, (LPCITEMIDLIST *)ppidls, NULL, (IDataObject **)&pdoWalk);
  5549. if (SUCCEEDED(hr))
  5550. {
  5551. hr = pThis->_DoDropOnClsid(CLSID_MailRecipient, pdoWalk);
  5552. bNoFilesFoundToEmail = FALSE;
  5553. pdoWalk->Release();
  5554. }
  5555. }
  5556. FreeIDListArray(ppidls, cItems);
  5557. }
  5558. }
  5559. pnsw->Release();
  5560. }
  5561. if (bNoFilesFoundToEmail)
  5562. {
  5563. // No items found to e-mail (selected folders contained no files).
  5564. ShellMessageBox(
  5565. HINST_THISDLL,
  5566. pThis->_hwndMain,
  5567. MAKEINTRESOURCE(IDS_NOFILESTOEMAIL),
  5568. NULL,
  5569. MB_OK | MB_ICONERROR);
  5570. }
  5571. pdo->Release();
  5572. }
  5573. return hr;
  5574. }
  5575. HRESULT CDefView::_OnPrint(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  5576. {
  5577. CDefView* pThis = (CDefView*)(void*)pv;
  5578. return pThis->_DoVerb(psiItemArray,c_szPrintA);
  5579. }
  5580. HRESULT CDefView::_OnDelete(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  5581. {
  5582. CDefView* pThis = (CDefView*)(void*)pv;
  5583. return pThis->_DoVerb(psiItemArray,c_szDeleteA);
  5584. }
  5585. HRESULT CDefView::RemoveBarricade (void)
  5586. {
  5587. LPITEMIDLIST pidl = _GetViewPidl();
  5588. if (pidl)
  5589. {
  5590. TCHAR szValueName[MAX_PATH];
  5591. if (GetBarricadeValueNameFromPidl(pidl, szValueName, ARRAYSIZE(szValueName)))
  5592. {
  5593. SetBarricadeStatus (szValueName, VARIANT_FALSE);
  5594. }
  5595. ILFree(pidl);
  5596. }
  5597. // Restore "View" menu commands which were stripped.
  5598. RecreateMenus();
  5599. // Enable "View Menu" button on the toolbar.
  5600. EnableToolbarButton(SFVIDM_VIEW_VIEWMENU, TRUE);
  5601. _fBarrierDisplayed = FALSE;
  5602. return _pDUIView->EnableBarrier(FALSE);
  5603. }
  5604. HRESULT CDefView::_OnView(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  5605. {
  5606. CDefView* pThis = (CDefView*)(void*)pv;
  5607. return pThis->RemoveBarricade();
  5608. }
  5609. HRESULT CDefView::_OnHide(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  5610. {
  5611. CDefView* pThis = (CDefView*)(void*)pv;
  5612. LPITEMIDLIST pidl = pThis->_GetViewPidl();
  5613. if (pidl)
  5614. {
  5615. TCHAR szValueName[MAX_PATH];
  5616. if (GetBarricadeValueNameFromPidl(pidl, szValueName, ARRAYSIZE(szValueName)))
  5617. {
  5618. SetBarricadeStatus(szValueName, VARIANT_TRUE);
  5619. }
  5620. ILFree(pidl);
  5621. }
  5622. // Disable "View Menu" button on the toolbar.
  5623. pThis->EnableToolbarButton(SFVIDM_VIEW_VIEWMENU, FALSE);
  5624. pThis->_fBarrierDisplayed = TRUE;
  5625. return pThis->_pDUIView->EnableBarrier(TRUE);
  5626. }
  5627. HRESULT CDefView::_OnAddRemovePrograms(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  5628. {
  5629. HCURSOR hcOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
  5630. SHRunControlPanel(L"appwiz.cpl", NULL);
  5631. SetCursor(hcOld);
  5632. return S_OK;
  5633. }
  5634. HRESULT CDefView::_OnSearchFiles(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  5635. {
  5636. CDefView* pThis = (CDefView*)(void*)pv;
  5637. return IUnknown_ShowBrowserBar (pThis->_psb, CLSID_FileSearchBand, TRUE);
  5638. }
  5639. const WVTASKITEM c_DefviewBlockadeTaskHeader = WVTI_HEADER_ENTRY(L"shell32.dll", IDS_HEADER_DEFVIEW_BLOCKADE, IDS_HEADER_DEFVIEW_BLOCKADE, IDS_HEADER_DEFVIEW_BLOCKADE, IDS_HEADER_DEFVIEW_BLOCKADE, IDS_HEADER_DEFVIEW_BLOCKADE_TT);
  5640. const WVTASKITEM c_DefviewBlockadeTasks[] =
  5641. {
  5642. WVTI_ENTRY_ALL(UICID_ViewContents, L"shell32.dll", IDS_TASK_DEFVIEW_VIEWCONTENTS_DRIVE, IDS_TASK_DEFVIEW_VIEWCONTENTS_DRIVE_TT, IDI_STSPROGS, CDefView::_CanViewDrives, CDefView::_OnView),
  5643. WVTI_ENTRY_ALL(UICID_HideContents, L"shell32.dll", IDS_TASK_DEFVIEW_HIDECONTENTS_DRIVE, IDS_TASK_DEFVIEW_HIDECONTENTS_DRIVE_TT, IDI_STSPROGS, CDefView::_CanHideDrives, CDefView::_OnHide),
  5644. WVTI_ENTRY_ALL(UICID_ViewContents, L"shell32.dll", IDS_TASK_DEFVIEW_VIEWCONTENTS_FOLDER, IDS_TASK_DEFVIEW_VIEWCONTENTS_FOLDER_TT,IDI_STSPROGS, CDefView::_CanViewFolder, CDefView::_OnView),
  5645. WVTI_ENTRY_ALL(UICID_HideContents, L"shell32.dll", IDS_TASK_DEFVIEW_HIDECONTENTS_FOLDER, IDS_TASK_DEFVIEW_HIDECONTENTS_FOLDER_TT,IDI_STSPROGS, CDefView::_CanHideFolder, CDefView::_OnHide),
  5646. WVTI_ENTRY_ALL(UICID_AddRemovePrograms, L"shell32.dll", IDS_TASK_ARP, IDS_TASK_ARP_TT, IDI_CPCAT_ARP, NULL, CDefView::_OnAddRemovePrograms),
  5647. WVTI_ENTRY_ALL(UICID_SearchFiles, L"shell32.dll", IDS_TASK_SEARCHFORFILES, IDS_TASK_SEARCHFORFILES_TT, IDI_STFIND, NULL, CDefView::_OnSearchFiles),
  5648. };
  5649. const WVTASKITEM c_DefviewFileFolderTasksHeaders = WVTI_HEADER(L"shell32.dll", IDS_HEADER_FILEFOLDER, IDS_HEADER_FILEFOLDER_TT);
  5650. const WVTASKITEM c_DefviewItemFolderTasksHeaders = WVTI_HEADER(L"shell32.dll", IDS_HEADER_ITEMFOLDER, IDS_HEADER_ITEMFOLDER_TT);
  5651. const WVTASKITEM c_DefviewFileFolderTasks[] =
  5652. {
  5653. WVTI_ENTRY_NOSELECTION(UICID_NewFolder, L"shell32.dll", IDS_TASK_CURFOLDER_NEWFOLDER, IDS_TASK_CURFOLDER_NEWFOLDER_TT, IDI_TASK_NEWFOLDER, CDefView::_CanWrite,
  5654. CDefView::_OnNewFolder),
  5655. WVTI_ENTRY_TITLE(UICID_Rename, L"shell32.dll", IDS_TASK_RENAME_FILE, IDS_TASK_RENAME_FOLDER, 0, IDS_TASK_RENAME_FILE_TT, IDI_TASK_RENAME, CDefView::_CanRename,
  5656. CDefView::_OnRename),
  5657. WVTI_ENTRY_TITLE(UICID_Move, L"shell32.dll", IDS_TASK_MOVE_FILE, IDS_TASK_MOVE_FOLDER, IDS_TASK_MOVE_ITEMS, IDS_TASK_MOVE_TT, IDI_TASK_MOVE, CDefView::_CanMove,
  5658. CDefView::_OnMove),
  5659. WVTI_ENTRY_ALL_TITLE(UICID_Copy, L"shell32.dll", 0, IDS_TASK_COPY_FILE, IDS_TASK_COPY_FOLDER, IDS_TASK_COPY_ITEMS, IDS_TASK_COPY_TT, IDI_TASK_COPY, CDefView::_CanCopy,
  5660. CDefView::_OnCopy),
  5661. WVTI_ENTRY_ALL_TITLE(UICID_Publish, L"shell32.dll", IDS_TASK_PUBLISH_FOLDER, IDS_TASK_PUBLISH_FILE,IDS_TASK_PUBLISH_FOLDER, IDS_TASK_PUBLISH_ITEMS, IDS_TASK_PUBLISH_TT, IDI_TASK_PUBLISH, CDefView::_CanPublish,
  5662. CDefView::_OnPublish),
  5663. WVTI_ENTRY_ALL_TITLE(UICID_Share, L"shell32.dll", IDS_TASK_SHARE_FOLDER, 0, IDS_TASK_SHARE_FOLDER, 0, IDS_TASK_SHARE_TT, IDI_TASK_SHARE, CDefView::_CanShare,
  5664. CDefView::_OnShare),
  5665. WVTI_ENTRY_TITLE(UICID_Email, L"shell32.dll", IDS_TASK_EMAIL_FILE, IDS_TASK_EMAIL_FOLDER, IDS_TASK_EMAIL_ITEMS, IDS_TASK_EMAIL_TT, IDI_TASK_EMAILFILE, CDefView::_CanEmail,
  5666. CDefView::_OnEmail),
  5667. WVTI_ENTRY_TITLE(UICID_Print, L"shell32.dll", IDS_TASK_PRINT_FILE, 0, 0, IDS_TASK_PRINT_TT, IDI_TASK_PRINT, CDefView::_CanPrint,
  5668. CDefView::_OnPrint),
  5669. WVTI_ENTRY_TITLE(UICID_Delete, L"shell32.dll", IDS_TASK_DELETE_FILE, IDS_TASK_DELETE_FOLDER, IDS_TASK_DELETE_ITEMS, IDS_TASK_DELETE_TT, IDI_TASK_DELETE, CDefView::_CanDelete,
  5670. CDefView::_OnDelete),
  5671. };
  5672. const size_t c_cDefviewFileFolderTasks = ARRAYSIZE(c_DefviewFileFolderTasks);
  5673. const WVTASKITEM c_DefviewItemFolderTasks[] =
  5674. {
  5675. WVTI_ENTRY_NOSELECTION(UICID_NewFolder, L"shell32.dll", IDS_TASK_CURFOLDER_NEWFOLDER, IDS_TASK_CURFOLDER_NEWFOLDER_TT, IDI_TASK_NEWFOLDER, CDefView::_CanWrite,
  5676. CDefView::_OnNewFolder),
  5677. WVTI_ENTRY_TITLE(UICID_Rename, L"shell32.dll", IDS_TASK_RENAME_ITEM, IDS_TASK_RENAME_FOLDER, 0, IDS_TASK_RENAME_ITEM_TT, IDI_TASK_RENAME, CDefView::_CanRename,
  5678. CDefView::_OnRename),
  5679. WVTI_ENTRY_TITLE(UICID_Move, L"shell32.dll", IDS_TASK_MOVE_ITEM, IDS_TASK_MOVE_FOLDER, IDS_TASK_MOVE_ITEMS, IDS_TASK_MOVE_TT, IDI_TASK_MOVE, CDefView::_CanMove,
  5680. CDefView::_OnMove),
  5681. WVTI_ENTRY_ALL_TITLE(UICID_Copy, L"shell32.dll", 0, IDS_TASK_COPY_ITEM, IDS_TASK_COPY_FOLDER, IDS_TASK_COPY_ITEMS, IDS_TASK_COPY_TT, IDI_TASK_COPY, CDefView::_CanCopy,
  5682. CDefView::_OnCopy),
  5683. WVTI_ENTRY_ALL_TITLE(UICID_Share, L"shell32.dll", IDS_TASK_SHARE_FOLDER, 0, IDS_TASK_SHARE_FOLDER, 0, IDS_TASK_SHARE_TT, IDI_TASK_SHARE, CDefView::_CanShare,
  5684. CDefView::_OnShare),
  5685. WVTI_ENTRY_TITLE(UICID_Delete, L"shell32.dll", IDS_TASK_DELETE_ITEM, IDS_TASK_DELETE_FOLDER, IDS_TASK_DELETE_ITEMS, IDS_TASK_DELETE_TT, IDI_TASK_DELETE, CDefView::_CanDelete,
  5686. CDefView::_OnDelete),
  5687. };
  5688. const size_t c_cDefviewItemFolderTasks = ARRAYSIZE(c_DefviewItemFolderTasks);
  5689. const WVTASKITEM c_DefviewOtherPlaces = WVTI_HEADER_ENTRY(L"shell32.dll", IDS_HEADER_OTHER_PLACES, IDS_HEADER_OTHER_PLACES, IDS_HEADER_OTHER_PLACES, IDS_HEADER_OTHER_PLACES, IDS_HEADER_OTHER_PLACES_TT);
  5690. const WVTASKITEM c_DefviewDetails = WVTI_HEADER_ENTRY(L"shell32.dll", IDS_HEADER_DETAILS, IDS_HEADER_DETAILS, IDS_HEADER_DETAILS, IDS_HEADER_DETAILS, IDS_HEADER_DETAILS_TT);
  5691. const WVTASKITEM* CDefView::_FindTaskItem(REFGUID guidCanonicalName)
  5692. {
  5693. const BOOL bFileFolderTasks = _wvLayout.dwLayout & SFVMWVL_FILES;
  5694. const WVTASKITEM *paTasks = bFileFolderTasks ? c_DefviewFileFolderTasks : c_DefviewItemFolderTasks;
  5695. const size_t cTasks = bFileFolderTasks ? c_cDefviewFileFolderTasks : c_cDefviewItemFolderTasks;
  5696. for (size_t i = 0; i < cTasks; i++)
  5697. if (IsEqualGUID(*(paTasks[i].pguidCanonicalName), guidCanonicalName))
  5698. return &paTasks[i];
  5699. return NULL;
  5700. }
  5701. HRESULT CDefView::get_Name(REFGUID guidCanonicalName, IShellItemArray *psiItemArray, LPWSTR *ppszName)
  5702. {
  5703. const WVTASKITEM* pTask = _FindTaskItem(guidCanonicalName);
  5704. if (pTask)
  5705. return CWVTASKITEM::get_Name(pTask, psiItemArray, ppszName);
  5706. return E_FAIL;
  5707. }
  5708. HRESULT CDefView::get_Icon(REFGUID guidCanonicalName, IShellItemArray *psiItemArray, LPWSTR *ppszIcon)
  5709. {
  5710. const WVTASKITEM* pTask = _FindTaskItem(guidCanonicalName);
  5711. if (pTask)
  5712. return CWVTASKITEM::get_Icon(pTask, psiItemArray, ppszIcon);
  5713. return E_FAIL;
  5714. }
  5715. HRESULT CDefView::get_Tooltip(REFGUID guidCanonicalName, IShellItemArray *psiItemArray, LPWSTR *ppszInfotip)
  5716. {
  5717. const WVTASKITEM* pTask = _FindTaskItem(guidCanonicalName);
  5718. if (pTask)
  5719. return CWVTASKITEM::get_Tooltip(pTask, psiItemArray, ppszInfotip);
  5720. return E_FAIL;
  5721. }
  5722. HRESULT CDefView::get_State(REFGUID guidCanonicalName, IShellItemArray *psiItemArray, UISTATE* puisState)
  5723. {
  5724. const WVTASKITEM* pTask = _FindTaskItem(guidCanonicalName);
  5725. if (pTask)
  5726. return CWVTASKITEM::get_State(pTask, SAFECAST(this, IShellView2*), psiItemArray, TRUE, puisState);
  5727. return E_FAIL;
  5728. }
  5729. HRESULT CDefView::Invoke(REFGUID guidCanonicalName, IShellItemArray *psiItemArray, IBindCtx *pbc)
  5730. {
  5731. const WVTASKITEM* pTask = _FindTaskItem(guidCanonicalName);
  5732. if (pTask)
  5733. return CWVTASKITEM::Invoke(pTask, SAFECAST(this, IShellView2*), psiItemArray, pbc);
  5734. return E_FAIL;
  5735. }
  5736. HRESULT CDefView::_GetDefaultWebviewContent(BOOL bFileFolderTasks)
  5737. {
  5738. if (!_wvTasks.penumSpecialTasks)
  5739. {
  5740. if (_wvContent.dwFlags & SFVMWVF_BARRICADE)
  5741. {
  5742. // defview provides a default penumSpecialTasks for barricaded folders
  5743. Create_IUIElement(&c_DefviewBlockadeTaskHeader, &(_wvContent.pSpecialTaskHeader));
  5744. Create_IEnumUICommand((IUnknown*)(void*)this, c_DefviewBlockadeTasks, ARRAYSIZE(c_DefviewBlockadeTasks), &(_wvTasks.penumSpecialTasks));
  5745. }
  5746. }
  5747. if (!_wvTasks.penumFolderTasks)
  5748. {
  5749. if (_wvContent.pFolderTaskHeader)
  5750. _wvContent.pFolderTaskHeader->Release();
  5751. Create_IUIElement(bFileFolderTasks ? &c_DefviewFileFolderTasksHeaders : &c_DefviewItemFolderTasksHeaders, &(_wvContent.pFolderTaskHeader));
  5752. Create_IEnumUICommand(
  5753. (IUnknown*)(void*)this,
  5754. bFileFolderTasks ? c_DefviewFileFolderTasks : c_DefviewItemFolderTasks,
  5755. bFileFolderTasks ? c_cDefviewFileFolderTasks : c_cDefviewItemFolderTasks,
  5756. &(_wvTasks.penumFolderTasks));
  5757. }
  5758. if (!_wvContent.penumOtherPlaces)
  5759. {
  5760. LPCTSTR rgCSIDLs[] = { MAKEINTRESOURCE(CSIDL_PERSONAL), MAKEINTRESOURCE(CSIDL_COMMON_DOCUMENTS), MAKEINTRESOURCE(CSIDL_NETWORK) };
  5761. LPITEMIDLIST pidl = _GetViewPidl();
  5762. CreateIEnumIDListOnCSIDLs(pidl, rgCSIDLs, ARRAYSIZE(rgCSIDLs), &_wvContent.penumOtherPlaces);
  5763. if (pidl)
  5764. ILFree(pidl);
  5765. }
  5766. ASSERT(NULL==_pOtherPlacesHeader);
  5767. Create_IUIElement(&c_DefviewOtherPlaces, &_pOtherPlacesHeader);
  5768. ASSERT(NULL==_pDetailsHeader);
  5769. Create_IUIElement(&c_DefviewDetails, &_pDetailsHeader);
  5770. return S_OK;
  5771. }
  5772. void CDefView::_FreeWebViewContentData()
  5773. {
  5774. ATOMICRELEASE(_wvContent.pSpecialTaskHeader);
  5775. ATOMICRELEASE(_wvContent.pFolderTaskHeader);
  5776. ATOMICRELEASE(_wvContent.penumOtherPlaces);
  5777. ATOMICRELEASE(_wvTasks.penumSpecialTasks);
  5778. ATOMICRELEASE(_wvTasks.penumFolderTasks);
  5779. ATOMICRELEASE(_pOtherPlacesHeader);
  5780. ATOMICRELEASE(_pDetailsHeader);
  5781. _fQueryWebViewData = FALSE;
  5782. _wvLayout.dwLayout = -1; // an invalid value
  5783. }
  5784. BOOL CDefView::_QueryBarricadeState()
  5785. {
  5786. BOOL bResult = FALSE;
  5787. LPITEMIDLIST pidl = _GetViewPidl();
  5788. if (pidl)
  5789. {
  5790. //
  5791. // Control panel is a special case.
  5792. // The barricade is used to represent 'category view' which can
  5793. // be turned on/off by the user. We must always ask control panel
  5794. // if it's barricade is on or off.
  5795. //
  5796. BOOL bIsControlPanel = FALSE;
  5797. LPITEMIDLIST pidlControlPanel;
  5798. if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidlControlPanel)))
  5799. {
  5800. bIsControlPanel = ILIsEqual(pidl, pidlControlPanel);
  5801. ILFree (pidlControlPanel);
  5802. }
  5803. if (bIsControlPanel)
  5804. {
  5805. SFVM_WEBVIEW_CONTENT_DATA wvc;
  5806. if (SUCCEEDED(CallCB(SFVM_GETWEBVIEWCONTENT, 0, (LPARAM)&wvc)))
  5807. {
  5808. //
  5809. // Control Panel doesn't provide all the standard
  5810. // webview content so it's doing nothing more than setting
  5811. // the dwFlags member. Assert to ensure this doesn't
  5812. // change in the future without us knowing about it.
  5813. //
  5814. ASSERT(NULL == wvc.pIntroText);
  5815. ASSERT(NULL == wvc.pSpecialTaskHeader);
  5816. ASSERT(NULL == wvc.pFolderTaskHeader);
  5817. ASSERT(NULL == wvc.penumOtherPlaces);
  5818. bResult = (0 != (SFVMWVF_BARRICADE & wvc.dwFlags));
  5819. }
  5820. }
  5821. else if (_wvContent.dwFlags & SFVMWVF_BARRICADE)
  5822. {
  5823. if (!IsBarricadeGloballyOff())
  5824. {
  5825. TCHAR szValueName[MAX_PATH];
  5826. if (GetBarricadeValueNameFromPidl(pidl, szValueName, ARRAYSIZE(szValueName)))
  5827. {
  5828. if (VARIANT_TRUE == GetBarricadeStatus(szValueName))
  5829. {
  5830. bResult = TRUE;
  5831. }
  5832. }
  5833. }
  5834. }
  5835. ILFree(pidl);
  5836. }
  5837. return bResult;
  5838. }
  5839. void CDefView::_ShowLegacyWatermark()
  5840. {
  5841. BOOL fShowLegacyWatermark = TRUE;
  5842. LVBKIMAGE lvbki = {0};
  5843. if (_pszLegacyWatermark)
  5844. {
  5845. lvbki.ulFlags = LVBKIF_SOURCE_URL | LVBKIF_STYLE_TILE;
  5846. lvbki.pszImage = _pszLegacyWatermark;
  5847. }
  5848. else
  5849. {
  5850. // this code path is used to clear the watermark
  5851. lvbki.ulFlags = LVBKIF_TYPE_WATERMARK;
  5852. // if we're turning off the legacy watermark, we may have to turn on the theme one
  5853. if (_idThemeWatermark && _pDUIView)
  5854. {
  5855. fShowLegacyWatermark = FALSE;
  5856. }
  5857. }
  5858. if (fShowLegacyWatermark)
  5859. ListView_SetBkImage(_hwndListview, &lvbki);
  5860. else
  5861. _ShowThemeWatermark();
  5862. }
  5863. void CDefView::_ShowThemeWatermark()
  5864. {
  5865. BOOL fShowLegacyWatermark = TRUE;
  5866. if (_idThemeWatermark && _pDUIView)
  5867. {
  5868. HINSTANCE hinstTheme = _pDUIView->_GetThemeHinst();
  5869. LVBKIMAGE lvbki = {0};
  5870. lvbki.ulFlags = LVBKIF_TYPE_WATERMARK;
  5871. lvbki.hbm = DUILoadBitmap(hinstTheme, _idThemeWatermark, LR_DEFAULTCOLOR);
  5872. if (lvbki.hbm)
  5873. {
  5874. // If the window color doesn't match the background color of the watermark,
  5875. // then we'll hide the watermark.
  5876. HDC hDC = CreateCompatibleDC(NULL);
  5877. if (hDC)
  5878. {
  5879. HBITMAP hOldBitmap;
  5880. hOldBitmap = (HBITMAP)SelectObject (hDC, lvbki.hbm);
  5881. if (GetPixel(hDC, 0, 0) != GetSysColor(COLOR_WINDOW))
  5882. {
  5883. _idThemeWatermark = 0;
  5884. }
  5885. SelectObject (hDC, hOldBitmap);
  5886. DeleteDC (hDC);
  5887. }
  5888. if (_idThemeWatermark && ListView_SetBkImage(_hwndListview, &lvbki))
  5889. {
  5890. fShowLegacyWatermark = FALSE;
  5891. }
  5892. else
  5893. {
  5894. DeleteObject(lvbki.hbm);
  5895. }
  5896. }
  5897. if (fShowLegacyWatermark)
  5898. _idThemeWatermark = 0; // something failed, pretend we don't have one
  5899. }
  5900. // usually this will just hide the previous watermark
  5901. if (fShowLegacyWatermark)
  5902. {
  5903. _ShowLegacyWatermark();
  5904. }
  5905. }
  5906. void CDefView::_SetThemeWatermark()
  5907. {
  5908. UINT idThemeWatermark = 0;
  5909. if (_pDUIView)
  5910. {
  5911. const WVTHEME* pwvTheme = _pDUIView->GetThemeInfo();
  5912. if (pwvTheme && pwvTheme->idListviewWatermark)
  5913. {
  5914. HINSTANCE hinstTheme = _pDUIView->_GetThemeHinst();
  5915. if (HINST_THISDLL != hinstTheme)
  5916. {
  5917. // Only add the watermark if the machine is fast enough...
  5918. if (SHRegGetBoolUSValue(REGSTR_EXPLORER_ADVANCED, TEXT("ListviewWatermark"),
  5919. FALSE, // Don't ignore HKCU
  5920. FALSE)) // Assume not fast enough
  5921. {
  5922. idThemeWatermark = pwvTheme->idListviewWatermark;
  5923. }
  5924. }
  5925. }
  5926. }
  5927. if (idThemeWatermark != _idThemeWatermark)
  5928. {
  5929. _idThemeWatermark = idThemeWatermark;
  5930. // Since DUI Document view isn't themed, legacy watermarks have precedence there.
  5931. // Might as well have them take precedence for My Pictures too...
  5932. if (!_pszLegacyWatermark)
  5933. {
  5934. _ShowThemeWatermark();
  5935. }
  5936. }
  5937. }
  5938. void CDefView::_SetLegacyWatermark(LPCTSTR pszLegacyWatermark)
  5939. {
  5940. Str_SetPtr(&_pszLegacyWatermark, pszLegacyWatermark);
  5941. _ShowLegacyWatermark();
  5942. }
  5943. HRESULT CDefView::_TryShowWebView(UINT fvmNew, UINT fvmOld)
  5944. {
  5945. SFVM_WEBVIEW_LAYOUT_DATA sfvmwvld = {0};
  5946. HRESULT hr = E_FAIL;
  5947. BOOL fShowDUI = FALSE;
  5948. // The desktop IShellFolder doesn't know if it's in-frame or in the real desktop,
  5949. // so only ask it for new DUIView if we're not the actual desktop.
  5950. if (!_IsDesktop())
  5951. {
  5952. // Supporting SFVM_GETWEBVIEWLAYOUT means the folder wants our new
  5953. // DUI View and they support SFVM_GETWEBVIEWCONTENT
  5954. //
  5955. hr = CallCB(SFVM_GETWEBVIEWLAYOUT, (WPARAM)fvmNew, (LPARAM)&sfvmwvld);
  5956. fShowDUI = SUCCEEDED(hr);
  5957. }
  5958. // This folder doesn't specify the new DUIView, try the old WebView stuff
  5959. if (!fShowDUI)
  5960. {
  5961. WCHAR wszMoniker[MAX_PATH];
  5962. hr = _GetWebViewMoniker(wszMoniker, ARRAYSIZE(wszMoniker));
  5963. if (SUCCEEDED(hr))
  5964. {
  5965. if(_pDUIView) //Hide it only if we are switching from DUI
  5966. _TryHideWebView(); // just in case we're switching from DUI to Web View (can happen when customizing)
  5967. if (wszMoniker[0])
  5968. {
  5969. hr = _SwitchToWebView(TRUE);
  5970. }
  5971. }
  5972. // Okay, we don't have Web View, use the default DUI View
  5973. if (FAILED(hr))
  5974. {
  5975. sfvmwvld.dwLayout = SFVMWVL_NORMAL;
  5976. fShowDUI = TRUE;
  5977. }
  5978. }
  5979. if (fShowDUI)
  5980. {
  5981. hr = S_OK;
  5982. _cFrame.HideWebView(); // just in case we're switching from Web View to DUI View (can happen when customizing)
  5983. if (sfvmwvld.dwLayout != _wvLayout.dwLayout)
  5984. {
  5985. if (!_fQueryWebViewData) // instead of this we could allow per-layout tasks...
  5986. {
  5987. CallCB(SFVM_GETWEBVIEWTHEME, 0, (LPARAM)&_wvTheme);
  5988. // _FreeWebViewContentData(); if we have per-layout tasks...
  5989. if (FAILED(CallCB(SFVM_GETWEBVIEWCONTENT, 0, (LPARAM)&_wvContent)))
  5990. {
  5991. ZeroMemory(&_wvContent, sizeof(_wvContent));
  5992. }
  5993. if (0 == (SFVMWVF_ENUMTASKS & _wvContent.dwFlags))
  5994. {
  5995. //
  5996. // View wants standard task sections.
  5997. // Non-standard task sections are enumerated in duiview.
  5998. //
  5999. if (FAILED(CallCB(SFVM_GETWEBVIEWTASKS, 0, (LPARAM)&_wvTasks)))
  6000. {
  6001. ZeroMemory(&_wvTasks, sizeof(_wvTasks));
  6002. }
  6003. _GetDefaultWebviewContent(sfvmwvld.dwLayout & SFVMWVL_FILES);
  6004. }
  6005. _fQueryWebViewData = TRUE;
  6006. }
  6007. CopyMemory(&_wvLayout, &sfvmwvld, sizeof(_wvLayout));
  6008. _wvLayout.punkPreview = NULL;
  6009. if (_pDUIView)
  6010. {
  6011. _pDUIView->EnablePreview(sfvmwvld.punkPreview);
  6012. }
  6013. else
  6014. {
  6015. _pDUIView = Create_CDUIView(this);
  6016. if (_pDUIView)
  6017. {
  6018. _fBarrierDisplayed = _QueryBarricadeState();
  6019. if (SUCCEEDED(_pDUIView->Initialize(_fBarrierDisplayed,
  6020. sfvmwvld.punkPreview)))
  6021. {
  6022. if (((SFVMWVF_ENUMTASKS | SFVMWVF_CONTENTSCHANGE) & _wvContent.dwFlags) &&
  6023. _fRcvdContentsChangeBeforeDuiViewCreated)
  6024. {
  6025. //
  6026. // If the webview provider dynamically enumerates
  6027. // tasks or wants to be refreshed when contents change,
  6028. // (i.e. Control Panel), AND we received a 'contents change'
  6029. // before DUI View was created, initiate a 'contents change' now.
  6030. // Otherwise, such providers will not receive a 'contents change'
  6031. // and thus will not display their dynamic webview content.
  6032. //
  6033. _OnContentsChanged();
  6034. }
  6035. }
  6036. else
  6037. {
  6038. _pDUIView->Release();
  6039. _pDUIView = NULL;
  6040. }
  6041. }
  6042. }
  6043. }
  6044. else
  6045. {
  6046. // except potentially refresh if we need to add/remove our DUI Details minipreview
  6047. if (_pDUIView && (_IsImageMode(fvmNew) != _IsImageMode(fvmOld)))
  6048. _pDUIView->OnSelectionChange(_pSelectionShellItemArray);
  6049. }
  6050. ATOMICRELEASE(sfvmwvld.punkPreview);
  6051. }
  6052. _SetThemeWatermark();
  6053. return hr;
  6054. }
  6055. HRESULT CDefView::_TryHideWebView()
  6056. {
  6057. if (_pDUIView)
  6058. {
  6059. _pDUIView->DetachListview(); // so we detach and re-parent the listview synchronously
  6060. //
  6061. // Ensure DUser has shut down and handled all DUser messages
  6062. // before we release our ref on CDUIView.
  6063. //
  6064. _pDUIView->UnInitializeDirectUI();
  6065. _pDUIView->Release();
  6066. _pDUIView = NULL; // * necessary * because this is used internally as a state (must be BEFORE WndSize() below)
  6067. _wvLayout.dwLayout = -1; // an invalid value
  6068. _fListViewShown = FALSE; // CDUIView::DetachListview() does a SW_HIDE on the listview
  6069. WndSize(_hwndView); // resize _hwndView to account for DUI disappearing (otherwise
  6070. // it will still be the smaller size expecting DUI to be drawn
  6071. // next to it)
  6072. ShowHideListView();
  6073. }
  6074. else
  6075. {
  6076. _SwitchToWebView(FALSE);
  6077. }
  6078. return S_OK;
  6079. }
  6080. // we are switching the listview view mode in this function, not dorking with web view content.
  6081. //
  6082. HRESULT CDefView::_SwitchToViewFVM(UINT fvmNew, UINT uiType)
  6083. {
  6084. HRESULT hr = S_OK;
  6085. UINT fvmOld = _fs.ViewMode;
  6086. ASSERT(_hwndListview);
  6087. HWND hwndCurrentFocus = GetFocus();
  6088. BOOL bSetFocusRequired = HasCurrentViewWindowFocus();
  6089. if (SWITCHTOVIEW_WEBVIEWONLY != uiType)
  6090. {
  6091. // if we haven't loaded the columns yet, do that now
  6092. // Don't pre-load the columns for TileView, we are delaying the load on purpose for perf reasons.
  6093. if (fvmNew == FVM_DETAILS)
  6094. {
  6095. AddColumns();
  6096. _SetSortFeedback();
  6097. }
  6098. else if (fvmNew == FVM_THUMBSTRIP)
  6099. {
  6100. // Thumbstrip makes no sense in non-webview, fall back to thumbnail
  6101. if (!_ShouldShowWebView())
  6102. {
  6103. fvmNew = FVM_THUMBNAIL;
  6104. }
  6105. }
  6106. // Combined view only applies to large icon view
  6107. if (_fCombinedView && fvmNew != FVM_ICON)
  6108. {
  6109. _fCombinedView = FALSE;
  6110. ListView_SetExtendedListViewStyleEx(_hwndListview, LVS_EX_REGIONAL, 0);
  6111. _SetFolderColors();
  6112. }
  6113. // First we turn OFF view specific stuff that is no longer needed
  6114. switch (fvmOld)
  6115. {
  6116. case FVM_THUMBSTRIP:
  6117. if (FVM_THUMBSTRIP != fvmNew)
  6118. {
  6119. ListView_SetExtendedListViewStyleEx(_hwndListview, LVS_EX_SINGLEROW, 0);
  6120. // we may have forced thumbstrip to auto-arrange, undo that if so
  6121. if (!(_fs.fFlags & FWF_AUTOARRANGE))
  6122. {
  6123. SHSetWindowBits(_hwndListview, GWL_STYLE, LVS_AUTOARRANGE, 0);
  6124. }
  6125. }
  6126. // fall through
  6127. case FVM_THUMBNAIL:
  6128. if (!_IsImageMode(fvmNew))
  6129. {
  6130. _ResetThumbview();
  6131. // Since we are switching from thumbnail view, remove any thumbnail extraction tasks
  6132. _RemoveThumbviewTasks();
  6133. if (_fs.fFlags & FWF_OWNERDATA)
  6134. {
  6135. InvalidateRect(_hwndListview, NULL, TRUE);
  6136. }
  6137. else
  6138. {
  6139. ListView_InvalidateImageIndexes(_hwndListview);
  6140. }
  6141. }
  6142. break;
  6143. case FVM_TILE:
  6144. if (!_IsTileMode(fvmNew))
  6145. {
  6146. if (_pScheduler)
  6147. _pScheduler->RemoveTasks(TOID_DVFileTypeProperties, ITSAT_DEFAULT_LPARAM, TRUE);
  6148. // Remove the columns that
  6149. // were pulled in because of tileview.
  6150. _RemoveTileColumns();
  6151. }
  6152. break;
  6153. }
  6154. _SetView(fvmNew); // we can now switch the listview around
  6155. // Now that'we no longer in tileview, we can reset the tileinfo. If we were to do it
  6156. // prior to changing the view, then listview would start asking us for the tileinformation
  6157. // for each item again, and we'd pull in the tile columns again.
  6158. if (fvmOld == FVM_TILE)
  6159. {
  6160. _RemoveTileInfo();
  6161. }
  6162. // Third, turn ON view specific stuff
  6163. //
  6164. switch (fvmNew)
  6165. {
  6166. case FVM_THUMBSTRIP:
  6167. if (FVM_THUMBSTRIP!=fvmOld)
  6168. {
  6169. ListView_SetExtendedListViewStyleEx(_hwndListview, LVS_EX_SINGLEROW, LVS_EX_SINGLEROW);
  6170. // thumbstrip can not be in group view
  6171. if (_fGroupView)
  6172. _ToggleGrouping();
  6173. // thumbstrip is always in auto-arrange
  6174. if (!(_fs.fFlags & FWF_AUTOARRANGE))
  6175. {
  6176. _ClearItemPositions();
  6177. SHSetWindowBits(_hwndListview, GWL_STYLE, LVS_AUTOARRANGE, LVS_AUTOARRANGE);
  6178. }
  6179. }
  6180. // fall through
  6181. case FVM_THUMBNAIL:
  6182. if (!_IsImageMode(fvmOld))
  6183. {
  6184. if (GetKeyState(VK_SHIFT) < 0)
  6185. {
  6186. _fs.fFlags ^= FWF_HIDEFILENAMES; // toggle
  6187. }
  6188. _SetThumbview();
  6189. _DoThumbnailReadAhead();
  6190. RECT rc = {1, 3, 4, 4};
  6191. ListView_SetViewMargins(_hwndListview, &rc);
  6192. }
  6193. break;
  6194. case FVM_TILE:
  6195. if (!_IsTileMode(fvmOld))
  6196. {
  6197. _SetTileview();
  6198. RECT rc = {3, 4, 4, 1};
  6199. ListView_SetViewMargins(_hwndListview, &rc);
  6200. }
  6201. break;
  6202. default:
  6203. _SetSysImageList();
  6204. {
  6205. RECT rc = {1, 3, 4, 0};
  6206. ListView_SetViewMargins(_hwndListview, &rc);
  6207. }
  6208. break;
  6209. }
  6210. }
  6211. if (SWITCHTOVIEW_NOWEBVIEW != uiType)
  6212. {
  6213. // New to Whistler: a view mode transition may also entail a web view template change
  6214. if (_ShouldShowWebView())
  6215. {
  6216. _TryShowWebView(fvmNew, fvmOld);
  6217. _AutoAutoArrange(0);
  6218. hr = S_OK; // we don't care about failure since we still get icons
  6219. }
  6220. else
  6221. {
  6222. _TryHideWebView();
  6223. }
  6224. }
  6225. if (SWITCHTOVIEW_WEBVIEWONLY != uiType)
  6226. {
  6227. ShowHideListView();
  6228. _AutoAutoArrange(0);
  6229. if (bSetFocusRequired)
  6230. {
  6231. // _hwndListview is the current view window. Let's set focus to it.
  6232. CallCB(SFVM_SETFOCUS, 0, 0);
  6233. ViewWindowSetFocus();
  6234. // notify image preview control to update its image
  6235. if (fvmNew == FVM_THUMBSTRIP)
  6236. _ThumbstripSendImagePreviewFocusChangeEvent();
  6237. }
  6238. else
  6239. {
  6240. SetFocus(hwndCurrentFocus);
  6241. }
  6242. CheckToolbar();
  6243. // update menus, i.e. add Choose Columns to the view menu if Details view is selected
  6244. // or remove it otherwise
  6245. RecreateMenus();
  6246. _EnableDisableTBButtons();
  6247. }
  6248. return hr;
  6249. }
  6250. // Description:
  6251. // Notify image preview control to update its image. The image preview
  6252. // control uses focus change events to track when it should update the image
  6253. // it is displaying. When it receives a focus change event, it queries the
  6254. // listview to see which item has focus, then displays that item in the
  6255. // image preview window. When nothing in the listview has focus (such as
  6256. // when it has no items), the image preview window displays as empty.
  6257. //
  6258. // This method fires the "focus changed" event which is picked up by the
  6259. // image preview control, and causes it to update the image it's displaying.
  6260. //
  6261. void CDefView::_ThumbstripSendImagePreviewFocusChangeEvent()
  6262. {
  6263. ASSERT(_fs.ViewMode == FVM_THUMBSTRIP);
  6264. _FireEvent(DISPID_FOCUSCHANGED);
  6265. }
  6266. int CDefView::CheckCurrentViewMenuItem(HMENU hmenu)
  6267. {
  6268. int iCurViewMenuItem = _GetMenuIDFromViewMode(_fs.ViewMode);
  6269. CheckMenuRadioItem(hmenu, SFVIDM_VIEW_FIRSTVIEW, SFVIDM_VIEW_LASTVIEW,
  6270. iCurViewMenuItem, MF_BYCOMMAND | MF_CHECKED);
  6271. return iCurViewMenuItem;
  6272. }
  6273. const UINT c_aiNonCustomizableFolders[] = {
  6274. CSIDL_WINDOWS,
  6275. CSIDL_SYSTEM,
  6276. CSIDL_SYSTEMX86,
  6277. CSIDL_PROGRAM_FILES,
  6278. CSIDL_PROGRAM_FILESX86,
  6279. CSIDL_PERSONAL,
  6280. CSIDL_MYDOCUMENTS,
  6281. CSIDL_MYMUSIC,
  6282. CSIDL_MYPICTURES,
  6283. CSIDL_MYVIDEO,
  6284. CSIDL_COMMON_DOCUMENTS,
  6285. CSIDL_COMMON_MUSIC,
  6286. CSIDL_COMMON_PICTURES,
  6287. CSIDL_COMMON_VIDEO
  6288. };
  6289. // since we moved to the property bag this check is fast; we don't probe to see if we can create desktop.ini
  6290. // or anything.
  6291. BOOL IsCustomizable(LPCITEMIDLIST pidlFolder)
  6292. {
  6293. BOOL fCustomizable = FALSE;
  6294. if (!SHRestricted(REST_NOCUSTOMIZETHISFOLDER) && !SHRestricted(REST_CLASSICSHELL))
  6295. {
  6296. // Check if this is a file system folder.
  6297. // customization requires the folder being a regular file system
  6298. // folder. FILESYSTEMANCESTOR is the key bit here
  6299. #define SFGAO_CUST_BITS (SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR)
  6300. ULONG rgfFolderAttr = SFGAO_CUST_BITS;
  6301. TCHAR szPath[MAX_PATH];
  6302. if (SUCCEEDED(SHGetNameAndFlags(pidlFolder, SHGDN_FORPARSING, szPath, ARRAYSIZE(szPath), &rgfFolderAttr)) &&
  6303. (SFGAO_CUST_BITS == (rgfFolderAttr & SFGAO_CUST_BITS)))
  6304. {
  6305. if (!PathIsOneOf(szPath, c_aiNonCustomizableFolders, ARRAYSIZE(c_aiNonCustomizableFolders)) &&
  6306. (!PathIsRoot(szPath) || PathIsUNCServerShare(szPath)) &&
  6307. !SHRestricted(REST_NOCUSTOMIZEWEBVIEW))
  6308. {
  6309. IPropertyBag *ppb;
  6310. if (SUCCEEDED(SHGetViewStatePropertyBag(pidlFolder, VS_BAGSTR_EXPLORER, SHGVSPB_PERUSER | SHGVSPB_PERFOLDER, IID_PPV_ARG(IPropertyBag, &ppb))))
  6311. {
  6312. fCustomizable = TRUE;
  6313. ppb->Release();
  6314. }
  6315. }
  6316. }
  6317. }
  6318. return fCustomizable;
  6319. }
  6320. // wrapper around IsCustomizable to save some state, plus some defview-specific logic.
  6321. BOOL CDefView::_CachedIsCustomizable()
  6322. {
  6323. if (_IsDesktop() || _IsViewDesktop() || _IsCommonDialog())
  6324. {
  6325. _iCustomizable = NOT_CUSTOMIZABLE;
  6326. }
  6327. if (_iCustomizable == DONTKNOW_IF_CUSTOMIZABLE)
  6328. {
  6329. LPITEMIDLIST pidl = _GetViewPidl();
  6330. if (pidl)
  6331. {
  6332. _iCustomizable = IsCustomizable(pidl) ? YES_CUSTOMIZABLE : NOT_CUSTOMIZABLE;
  6333. ILFree(pidl);
  6334. }
  6335. }
  6336. return (_iCustomizable != NOT_CUSTOMIZABLE);
  6337. }
  6338. BOOL CDefView::_InvokeCustomization()
  6339. {
  6340. BOOL fRet = FALSE;
  6341. if (!_CachedIsCustomizable())
  6342. {
  6343. //If not customizable, put up this error message!
  6344. ShellMessageBox(HINST_THISDLL, _hwndMain, MAKEINTRESOURCE(IDS_NOTCUSTOMIZABLE), NULL,
  6345. MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
  6346. return FALSE; // ...and bail out!
  6347. }
  6348. //Save the view state first.
  6349. SaveViewState();
  6350. LPITEMIDLIST pidl = _GetViewPidl();
  6351. if (pidl)
  6352. {
  6353. TCHAR szSheetName[25];
  6354. LoadString(HINST_THISDLL, IDS_CUSTOMIZE, szSheetName, ARRAYSIZE(szSheetName));
  6355. SHELLEXECUTEINFO sei =
  6356. {
  6357. SIZEOF(sei),
  6358. SEE_MASK_INVOKEIDLIST, // fMask
  6359. _hwndMain, // hwnd
  6360. c_szProperties, // lpVerb
  6361. NULL, // lpFile
  6362. szSheetName, // lpParameters
  6363. NULL, // lpDirectory
  6364. SW_SHOWNORMAL, // nShow
  6365. NULL, // hInstApp
  6366. pidl, // lpIDList
  6367. NULL, // lpClass
  6368. 0, // hkeyClass
  6369. 0, // dwHotKey
  6370. NULL // hIcon
  6371. };
  6372. fRet = ShellExecuteEx(&sei);
  6373. ILFree(pidl);
  6374. }
  6375. return fRet;
  6376. }
  6377. struct {
  6378. UINT uiSfvidm;
  6379. DWORD dwOlecmdid;
  6380. } const c_CmdTable[] = {
  6381. { SFVIDM_EDIT_CUT, OLECMDID_CUT },
  6382. { SFVIDM_EDIT_COPY, OLECMDID_COPY },
  6383. { SFVIDM_EDIT_PASTE, OLECMDID_PASTE },
  6384. { SFVIDM_FILE_DELETE, OLECMDID_DELETE },
  6385. { SFVIDM_FILE_PROPERTIES, OLECMDID_PROPERTIES },
  6386. };
  6387. DWORD OlecmdidFromSfvidm(UINT uiSfvidm)
  6388. {
  6389. DWORD dwOlecmdid = 0;
  6390. for (int i = 0; i < ARRAYSIZE(c_CmdTable); i++)
  6391. {
  6392. if (c_CmdTable[i].uiSfvidm == uiSfvidm)
  6393. {
  6394. dwOlecmdid = c_CmdTable[i].dwOlecmdid;
  6395. break;
  6396. }
  6397. }
  6398. return dwOlecmdid;
  6399. }
  6400. void HideIE4DesktopChannelBar()
  6401. {
  6402. HWND hwndChannelBar;
  6403. //Check if the channel bar is currently running. If so, turn it off!
  6404. if ((hwndChannelBar = FindWindowEx(GetShellWindow(), NULL, TEXT("BaseBar"), TEXT("ChanApp"))) ||
  6405. (hwndChannelBar = FindWindowEx(NULL, NULL, TEXT("BaseBar"), TEXT("ChanApp")))) // can be a toplevel window
  6406. {
  6407. //Close the channel bar.
  6408. PostMessage(hwndChannelBar, WM_CLOSE, 0, 0);
  6409. }
  6410. }
  6411. // Wrapper around _SwitchToWebView to do desktop-specific stuff
  6412. LRESULT CDefView::_SwitchDesktopHTML(BOOL fShow)
  6413. {
  6414. LRESULT lRes;
  6415. if (fShow)
  6416. {
  6417. // Do this early to give the desktop a chance to regenerate it's webview template
  6418. _CallRefresh(TRUE);
  6419. lRes = SUCCEEDED(_SwitchToWebView(TRUE));
  6420. if (lRes)
  6421. {
  6422. HideIE4DesktopChannelBar();
  6423. }
  6424. }
  6425. else
  6426. {
  6427. _SwitchToWebView(FALSE);
  6428. CoFreeUnusedLibraries();
  6429. lRes = TRUE;
  6430. }
  6431. return lRes;
  6432. }
  6433. void CDefView::_DoColumnsMenu(int x, int y) // X and Y are screen coordinates
  6434. {
  6435. HMENU hmenu = CreatePopupMenu();
  6436. if (hmenu)
  6437. {
  6438. AddColumnsToMenu(hmenu, SFVIDM_COLUMN_FIRST);
  6439. int item = TrackPopupMenu(hmenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD,
  6440. x, y, 0, _hwndListview, NULL);
  6441. DestroyMenu(hmenu);
  6442. // validate item first
  6443. if (item == SFVIDM_VIEW_COLSETTINGS)
  6444. {
  6445. CColumnDlg ccd(this);
  6446. AddColumns();
  6447. ccd.ShowDialog(_hwndMain);
  6448. }
  6449. else if (item > SFVIDM_COLUMN_FIRST)
  6450. {
  6451. _HandleColumnToggle(item - SFVIDM_COLUMN_FIRST, TRUE);
  6452. }
  6453. }
  6454. }
  6455. BOOL CDefView::_ArrangeBy(UINT idCmd)
  6456. {
  6457. int iColumn = idCmd - SFVIDM_GROUPSFIRST;
  6458. BOOL fAllowToggle = TRUE;
  6459. // We want to enter group by if We already have a group, or if this is an extended grouping
  6460. if ((_fGroupView || InRange(idCmd, SFVIDM_GROUPSEXTENDEDFIRST, SFVIDM_GROUPSEXTENDEDLAST)) &&
  6461. !(_fs.ViewMode == FVM_LIST))
  6462. {
  6463. _GroupBy(idCmd);
  6464. iColumn = 0; // Arrange by name, when grouping
  6465. fAllowToggle = FALSE; // Always arrange in ascending order
  6466. }
  6467. return S_OK == _OnRearrange(iColumn, fAllowToggle);
  6468. }
  6469. BOOL CDefView::_InitArrangeMenu(HMENU hmInit)
  6470. {
  6471. MENUITEMINFO mii = {0};
  6472. mii.cbSize = sizeof(mii);
  6473. mii.fMask = MIIM_SUBMENU;
  6474. GetMenuItemInfo(hmInit, SFVIDM_MENU_ARRANGE, MF_BYCOMMAND, &mii);
  6475. HMENU hmenuCtx = mii.hSubMenu;
  6476. if (hmenuCtx)
  6477. {
  6478. int idToCheck = -1;
  6479. AddColumns();
  6480. UINT cVisible = _RealToVisibleCol(-1) + 1; // count
  6481. ICategoryProvider* pcp = NULL;
  6482. _pshf->CreateViewObject(NULL, IID_PPV_ARG(ICategoryProvider, &pcp));
  6483. while (1)
  6484. {
  6485. MENUITEMINFO miiSep = {0};
  6486. miiSep.cbSize = sizeof(mii);
  6487. miiSep.fMask = MIIM_ID | MIIM_TYPE;
  6488. miiSep.wID = -1;
  6489. if (!GetMenuItemInfo(hmenuCtx, 0, MF_BYPOSITION, &miiSep) ||
  6490. miiSep.wID == SFVIDM_GROUPSEP)
  6491. {
  6492. break;
  6493. }
  6494. DeleteMenu(hmenuCtx, 0, MF_BYPOSITION);
  6495. }
  6496. UINT iInsert = 0;
  6497. for (UINT i = 0; i < cVisible; i++)
  6498. {
  6499. BOOL fAddItem = TRUE;
  6500. UINT iReal = _VisibleToRealCol(i);
  6501. if (_IsDetailsColumn(iReal))
  6502. {
  6503. // See if the category Provider wants to exclude this column when groupview is enabled
  6504. if (pcp && _fGroupView)
  6505. {
  6506. SHCOLUMNID scid;
  6507. if (SUCCEEDED(_pshf2->MapColumnToSCID(iReal, &scid)))
  6508. {
  6509. // returns S_FALSE to remove.
  6510. fAddItem = (S_OK == pcp->CanCategorizeOnSCID(&scid));
  6511. }
  6512. }
  6513. if (fAddItem)
  6514. {
  6515. WCHAR wszName[MAX_COLUMN_NAME_LEN];
  6516. BOOL bpuiName = FALSE;
  6517. IPropertyUI *ppui;
  6518. // Attempt to retrieve mnemonic name from IPropertyUI interface.
  6519. if (_pshf2 && SUCCEEDED(_GetPropertyUI(&ppui)))
  6520. {
  6521. SHCOLUMNID scid;
  6522. if (SUCCEEDED(_pshf2->MapColumnToSCID(iReal, &scid)))
  6523. {
  6524. bpuiName = SUCCEEDED(ppui->GetDisplayName(scid.fmtid, scid.pid, PUIFNF_MNEMONIC, wszName, ARRAYSIZE(wszName)));
  6525. }
  6526. ppui->Release();
  6527. }
  6528. MENUITEMINFO miiItem = {0};
  6529. miiItem.cbSize = sizeof(mii);
  6530. miiItem.fMask = MIIM_ID | MIIM_TYPE;
  6531. miiItem.fType = MFT_STRING;
  6532. miiItem.wID = iReal + SFVIDM_GROUPSFIRST;
  6533. miiItem.dwTypeData = bpuiName ? wszName : _vs.GetColumnName(iReal);
  6534. InsertMenuItem(hmenuCtx, iInsert++, TRUE, &miiItem);
  6535. }
  6536. }
  6537. }
  6538. _InitExtendedGroups(pcp, hmenuCtx, iInsert, &idToCheck);
  6539. // Only do the Bullets if we're in auto arrange mode or if we are in details.
  6540. if (_IsAutoArrange() || _fGroupView || _fs.ViewMode == FVM_DETAILS)
  6541. {
  6542. if (idToCheck == -1)
  6543. {
  6544. // Since we're not going to have more than 4million columns, this case should suffice
  6545. idToCheck = (int)_vs._lParamSort + SFVIDM_GROUPSFIRST;
  6546. if (_fGroupView &&
  6547. !(_fs.ViewMode == FVM_LIST))
  6548. {
  6549. idToCheck = MapSCIDToColumn(_pshf2, &_vs._scidDetails) + SFVIDM_GROUPSFIRST;
  6550. }
  6551. }
  6552. CheckMenuRadioItem(hmenuCtx, SFVIDM_GROUPSFIRST, SFVIDM_GROUPSEXTENDEDLAST, idToCheck, MF_BYCOMMAND | MF_CHECKED);
  6553. }
  6554. if (pcp)
  6555. pcp->Release();
  6556. }
  6557. DWORD dwGroupEnableFlags = MF_GRAYED;
  6558. if (_pshf2 && // Needs to implement IShellFolder2
  6559. !_IsViewDesktop() && // Doesn't work on the desktop
  6560. !(_fs.ViewMode == FVM_LIST) && // Doesn't work in 'List' View
  6561. !(_fs.ViewMode == FVM_THUMBSTRIP) &&// Doesn't work in 'ThumbStrip' View
  6562. !(_fs.fFlags & FWF_OWNERDATA)) // Doesn't work for ownerdata lists (search)
  6563. {
  6564. dwGroupEnableFlags = MF_ENABLED;
  6565. CheckMenuItem(hmenuCtx, SFVIDM_GROUPBY, MF_BYCOMMAND | (_fGroupView?MF_CHECKED:0));
  6566. }
  6567. EnableMenuItem(hmenuCtx, SFVIDM_GROUPBY, MF_BYCOMMAND | dwGroupEnableFlags);
  6568. _SHPrettyMenu(hmenuCtx);
  6569. return TRUE;
  6570. }
  6571. BOOL CDefView::_InitExtendedGroups(ICategoryProvider* pcp, HMENU hmenuCtx, int iIndex, int* piIdToCheck)
  6572. {
  6573. if (!pcp)
  6574. return FALSE;
  6575. *piIdToCheck = -1;
  6576. if (_hdaCategories == NULL)
  6577. {
  6578. _hdaCategories = DSA_Create(sizeof(GUID), 5);
  6579. if (_hdaCategories)
  6580. {
  6581. IEnumGUID* penum;
  6582. if (SUCCEEDED(pcp->EnumCategories(&penum)))
  6583. {
  6584. GUID guidCat;
  6585. while (S_OK == penum->Next(1, &guidCat, NULL))
  6586. {
  6587. DSA_AppendItem(_hdaCategories, (void*)&guidCat);
  6588. }
  6589. penum->Release();
  6590. }
  6591. }
  6592. }
  6593. if (_hdaCategories)
  6594. {
  6595. int id = SFVIDM_GROUPSEXTENDEDFIRST;
  6596. TCHAR szName[MAX_PATH];
  6597. TCHAR szCurrentName[MAX_PATH];
  6598. WCHAR wszName[MAX_PATH];
  6599. GUID* pguidCat;
  6600. szCurrentName[0] = 0;
  6601. if (_pcat)
  6602. {
  6603. _pcat->GetDescription(szCurrentName, ARRAYSIZE(szCurrentName));
  6604. }
  6605. MENUITEMINFO mii = {0};
  6606. mii.cbSize = sizeof(MENUITEMINFO);
  6607. mii.fMask = MIIM_ID | MIIM_TYPE;
  6608. mii.fType = MFT_SEPARATOR;
  6609. mii.wID = -1;
  6610. InsertMenuItem(hmenuCtx, iIndex, TRUE, &mii);
  6611. iIndex++;
  6612. int cCategories = DSA_GetItemCount(_hdaCategories);
  6613. for (int i = 0; i < cCategories; i++)
  6614. {
  6615. pguidCat = (GUID*)DSA_GetItemPtr(_hdaCategories, i);
  6616. if (SUCCEEDED(pcp->GetCategoryName(pguidCat, wszName, ARRAYSIZE(wszName))))
  6617. {
  6618. SHUnicodeToTChar(wszName, szName, ARRAYSIZE(szName));
  6619. MENUITEMINFO mii = {0};
  6620. mii.cbSize = sizeof(MENUITEMINFO);
  6621. mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID;
  6622. mii.fType = MFT_STRING;
  6623. mii.dwItemData = (DWORD_PTR)pguidCat;
  6624. mii.wID = id;
  6625. mii.dwTypeData = szName;
  6626. mii.cch = ARRAYSIZE(szName);
  6627. InsertMenuItem(hmenuCtx, iIndex, TRUE, &mii);
  6628. if (lstrcmpi(szCurrentName, szName) == 0)
  6629. {
  6630. *piIdToCheck = id;
  6631. }
  6632. id++;
  6633. iIndex++;
  6634. }
  6635. }
  6636. }
  6637. return TRUE;
  6638. }
  6639. BOOL CDefView::_CategorizeOnSCID(const SHCOLUMNID* pscid)
  6640. {
  6641. BOOL fRet = FALSE;
  6642. _fSlowGroup = FALSE;
  6643. if (IsEqualSCID(*pscid, SCID_NAME))
  6644. {
  6645. if (SUCCEEDED(CAlphaCategorizer_Create(_pshf2, IID_PPV_ARG(ICategorizer, &_pcat))))
  6646. {
  6647. _vs._guidGroupID = CLSID_AlphabeticalCategorizer;
  6648. fRet = TRUE;
  6649. }
  6650. }
  6651. else if (IsEqualSCID(*pscid, SCID_SIZE))
  6652. {
  6653. if (SUCCEEDED(CSizeCategorizer_Create(_pshf2, IID_PPV_ARG(ICategorizer, &_pcat))))
  6654. {
  6655. _vs._guidGroupID = CLSID_SizeCategorizer;
  6656. fRet = TRUE;
  6657. }
  6658. }
  6659. else if (IsEqualSCID(*pscid, SCID_WRITETIME) ||
  6660. IsEqualSCID(*pscid, SCID_CREATETIME) ||
  6661. IsEqualSCID(*pscid, SCID_ACCESSTIME) ||
  6662. IsEqualSCID(*pscid, SCID_DATEDELETED))
  6663. {
  6664. if (SUCCEEDED(CTimeCategorizer_Create(_pshf2, pscid, IID_PPV_ARG(ICategorizer, &_pcat))))
  6665. {
  6666. _vs._guidGroupID = CLSID_TimeCategorizer;
  6667. fRet = TRUE;
  6668. }
  6669. }
  6670. else
  6671. {
  6672. _fSlowGroup = TRUE;
  6673. if (SUCCEEDED(CDetailCategorizer_Create(*pscid, _pshf2, IID_PPV_ARG(ICategorizer, &_pcat))))
  6674. {
  6675. _vs._guidGroupID = CLSID_DetailCategorizer;
  6676. fRet = TRUE;
  6677. }
  6678. }
  6679. if (fRet)
  6680. {
  6681. _vs._scidDetails = *pscid;
  6682. }
  6683. return fRet;
  6684. }
  6685. // slow groups have an architecture problem, after 5000 items in the view
  6686. // the message queue overflows from groupdone messages and its all bad.
  6687. // this ends up hanging the static flashlight window around because of resulting
  6688. // refcount issues.
  6689. // the only view that both defaults to a slow group and could have 5000 items is the
  6690. // cd burning folder. lou says its too late to change the interface now to let the
  6691. // categorizer decide if its slow or not, so just special case it here.
  6692. // everything works if its a fast group (and its actually fast anyway).
  6693. BOOL CDefView::_IsSlowGroup(const GUID *pguid)
  6694. {
  6695. BOOL fSlow = TRUE;
  6696. if (IsEqualGUID(*pguid, CLSID_MergedCategorizer))
  6697. {
  6698. fSlow = FALSE;
  6699. }
  6700. // room to grow if we need to special case others
  6701. return fSlow;
  6702. }
  6703. BOOL CDefView::_CategorizeOnGUID(const GUID* pguid, const SHCOLUMNID* pscid)
  6704. {
  6705. BOOL fRet = FALSE;
  6706. if (_pshf2)
  6707. {
  6708. _fGroupView = FALSE; // Just in case the create fails
  6709. if (_pScheduler)
  6710. _pScheduler->RemoveTasks(TOID_DVBackgroundGroup, ITSAT_DEFAULT_LPARAM, TRUE);
  6711. ATOMICRELEASE(_pcat);
  6712. ListView_RemoveAllGroups(_hwndListview);
  6713. ICategoryProvider* pcp;
  6714. if (SUCCEEDED(_pshf->CreateViewObject(NULL, IID_PPV_ARG(ICategoryProvider, &pcp))))
  6715. {
  6716. GUID guidGroup = *pguid;
  6717. if (pscid && S_OK != pcp->GetCategoryForSCID(const_cast<SHCOLUMNID*>(pscid), &guidGroup))
  6718. {
  6719. fRet = _CategorizeOnSCID(pscid);
  6720. }
  6721. else
  6722. {
  6723. _fSlowGroup = _IsSlowGroup(&guidGroup);
  6724. if (SUCCEEDED(pcp->CreateCategory(&guidGroup, IID_PPV_ARG(ICategorizer, &_pcat))))
  6725. {
  6726. _vs._guidGroupID = guidGroup;
  6727. if (pscid)
  6728. {
  6729. _vs._scidDetails = *pscid;
  6730. }
  6731. else
  6732. {
  6733. ZeroMemory(&_vs._scidDetails, sizeof(SHCOLUMNID));
  6734. }
  6735. fRet = TRUE;
  6736. }
  6737. }
  6738. pcp->Release();
  6739. }
  6740. else
  6741. {
  6742. if (pscid)
  6743. fRet = _CategorizeOnSCID(pscid);
  6744. }
  6745. }
  6746. if (fRet)
  6747. {
  6748. _ClearItemPositions();
  6749. _fGroupView = TRUE;
  6750. SHSetWindowBits(_hwndListview, GWL_STYLE, LVS_AUTOARRANGE, LVS_AUTOARRANGE);
  6751. // We're enabling groupview, so turn off the selected column
  6752. // (this will make it so tiles do not show the selected column as their first column)
  6753. ListView_SetSelectedColumn(_hwndListview, -1);
  6754. if (_fSlowGroup)
  6755. _fAllowSearchingWindow = TRUE;
  6756. ListView_EnableGroupView(_hwndListview, TRUE);
  6757. }
  6758. return fRet;
  6759. }
  6760. void CDefView::_GroupBy(int iColumn)
  6761. {
  6762. _fGroupView = FALSE; // Just in case the create fails
  6763. if (_pshf2)
  6764. {
  6765. if (InRange(iColumn, SFVIDM_GROUPSEXTENDEDFIRST, SFVIDM_GROUPSEXTENDEDLAST))
  6766. {
  6767. int iIndex = iColumn - SFVIDM_GROUPSEXTENDEDFIRST;
  6768. GUID* pguid = (GUID*)DSA_GetItemPtr(_hdaCategories, iIndex);
  6769. if (pguid)
  6770. {
  6771. _CategorizeOnGUID(pguid, NULL);
  6772. }
  6773. }
  6774. else
  6775. {
  6776. SHCOLUMNID scid;
  6777. iColumn -= SFVIDM_GROUPSFIRST;
  6778. if (SUCCEEDED(_pshf2->MapColumnToSCID(iColumn, &scid)))
  6779. {
  6780. _CategorizeOnGUID(&CLSID_DetailCategorizer, &scid);
  6781. }
  6782. }
  6783. // Make sure the arrows on details view look right...
  6784. _SetSortFeedback();
  6785. }
  6786. }
  6787. void CDefView::_ToggleGrouping()
  6788. {
  6789. if (_fGroupView)
  6790. {
  6791. _fGroupView = FALSE;
  6792. if (_pScheduler)
  6793. _pScheduler->RemoveTasks(TOID_DVBackgroundGroup, ITSAT_DEFAULT_LPARAM, TRUE);
  6794. ListView_EnableGroupView(_hwndListview, FALSE);
  6795. ListView_RemoveAllGroups(_hwndListview);
  6796. ListView_SetSelectedColumn(_hwndListview, _vs._lParamSort);
  6797. _SetSortFeedback();
  6798. _OnRearrange(_vs._lParamSort, FALSE);
  6799. }
  6800. else if (FVM_THUMBSTRIP != _fs.ViewMode) // Thumbstrip can never go into groupby mode
  6801. {
  6802. // If we have a categorizer, then we can just reenable grouping.
  6803. if (_pcat)
  6804. {
  6805. _fGroupView = TRUE;
  6806. ListView_EnableGroupView(_hwndListview, TRUE);
  6807. ListView_SetSelectedColumn(_hwndListview, -1);
  6808. _SetSortFeedback();
  6809. }
  6810. else
  6811. {
  6812. // If we don't, then we need to go get one.
  6813. _GroupBy((int)_vs._lParamSort + SFVIDM_GROUPSFIRST);
  6814. }
  6815. }
  6816. }
  6817. LRESULT CDefView::_OnDefviewEditCommand(UINT uID)
  6818. {
  6819. // if we are in label edit mode, don't allowany of the buttons......
  6820. if (_fInLabelEdit)
  6821. {
  6822. MessageBeep(0);
  6823. return 1;
  6824. }
  6825. if (_AllowCommand(uID))
  6826. {
  6827. HRESULT hr = _ExplorerCommand(uID);
  6828. if (FAILED(hr) && (hr != HRESULT_FROM_WIN32(ERROR_CANCELLED)))
  6829. {
  6830. MessageBeep(0);
  6831. }
  6832. return 1;
  6833. }
  6834. else
  6835. {
  6836. return 0;
  6837. }
  6838. }
  6839. HRESULT CDefView::_DoMoveOrCopyTo(REFCLSID clsid, IShellItemArray *psiItemArray)
  6840. {
  6841. IDataObject *pdo = NULL;
  6842. IContextMenu *pcm;
  6843. HRESULT hr = E_FAIL;
  6844. if (!psiItemArray)
  6845. {
  6846. psiItemArray = _GetFolderAsShellItemArray();
  6847. }
  6848. if (psiItemArray)
  6849. {
  6850. hr = psiItemArray->BindToHandler(NULL,BHID_DataObject,IID_PPV_ARG(IDataObject, &pdo));
  6851. }
  6852. if (SUCCEEDED(hr))
  6853. {
  6854. hr = SHCoCreateInstance(NULL, &clsid, NULL, IID_PPV_ARG(IContextMenu, &pcm));
  6855. if (SUCCEEDED(hr))
  6856. {
  6857. IUnknown_SetSite(pcm, SAFECAST(this, IDropTarget *)); // Needed to go modal during UI
  6858. IShellExtInit* psei;
  6859. hr = pcm->QueryInterface(IID_PPV_ARG(IShellExtInit, &psei));
  6860. if (SUCCEEDED(hr))
  6861. {
  6862. LPITEMIDLIST pidlFolder = _GetViewPidl();
  6863. if (pidlFolder)
  6864. {
  6865. psei->Initialize(pidlFolder, pdo, NULL);
  6866. ILFree(pidlFolder);
  6867. }
  6868. CMINVOKECOMMANDINFO ici = {0};
  6869. ici.hwnd = _hwndMain;
  6870. hr = pcm->InvokeCommand(&ici);
  6871. psei->Release();
  6872. }
  6873. IUnknown_SetSite(pcm, NULL);
  6874. pcm->Release();
  6875. }
  6876. pdo->Release();
  6877. }
  6878. return hr;
  6879. }
  6880. void CDefView::_OnSetWebView(BOOL fOn)
  6881. {
  6882. if (fOn)
  6883. {
  6884. _TryShowWebView(_fs.ViewMode, _fs.ViewMode);
  6885. }
  6886. else
  6887. {
  6888. _TryHideWebView();
  6889. }
  6890. }
  6891. LRESULT CDefView::_OnCommand(IContextMenu *pcmToInvoke, WPARAM wParam, LPARAM lParam)
  6892. {
  6893. UINT uID = GET_WM_COMMAND_ID(wParam, lParam);
  6894. if (InRange(uID, SFVIDM_GROUPSFIRST, SFVIDM_GROUPSEXTENDEDLAST))
  6895. {
  6896. _ArrangeBy(uID);
  6897. return 1;
  6898. }
  6899. else if (InRange(uID, SFVIDM_CONTEXT_FIRST, SFVIDM_CONTEXT_LAST))
  6900. {
  6901. UINT uCMBias = SFVIDM_CONTEXT_FIRST;
  6902. if (_pcmFile)
  6903. {
  6904. IContextMenu* pcmToInvoke = _pcmFile;
  6905. pcmToInvoke->AddRef();
  6906. // We need to special case the rename command
  6907. TCHAR szCommandString[64];
  6908. ContextMenu_GetCommandStringVerb(pcmToInvoke, uID - SFVIDM_CONTEXT_FIRST, szCommandString, ARRAYSIZE(szCommandString));
  6909. if (lstrcmpi(szCommandString, c_szRename) == 0)
  6910. {
  6911. DoRename();
  6912. }
  6913. else
  6914. {
  6915. CMINVOKECOMMANDINFOEX ici = { 0 };
  6916. ici.cbSize = sizeof(CMINVOKECOMMANDINFOEX);
  6917. ici.hwnd = _hwndMain;
  6918. ici.lpVerb = (LPSTR)MAKEINTRESOURCE(uID - SFVIDM_CONTEXT_FIRST);
  6919. ici.nShow = SW_NORMAL;
  6920. ici.fMask = CMIC_MASK_FLAG_LOG_USAGE;
  6921. int iItemSelect = ListView_GetNextItem(_hwndListview, -1, LVNI_SELECTED);
  6922. if (iItemSelect != -1)
  6923. {
  6924. RECT rcItem;
  6925. ListView_GetItemRect(_hwndListview, iItemSelect, &rcItem, LVIR_BOUNDS);
  6926. MapWindowPoints(_hwndListview, HWND_DESKTOP, (POINT *)&rcItem, 2);
  6927. ici.ptInvoke.x = (rcItem.left + rcItem.right) / 2;
  6928. ici.ptInvoke.y = (rcItem.top + rcItem.bottom) / 2;
  6929. ici.fMask |= CMIC_MASK_PTINVOKE;
  6930. }
  6931. // record if shift or control was being held down
  6932. SetICIKeyModifiers(&ici.fMask);
  6933. _InvokeContextMenu(pcmToInvoke, &ici);
  6934. }
  6935. //Since we are releaseing our only hold on the context menu, release the site.
  6936. IUnknown_SetSite(pcmToInvoke, NULL);
  6937. pcmToInvoke->Release(); // undo our gaurd ref
  6938. ATOMICRELEASE(_pcmFile); // once used, it can't be used again
  6939. }
  6940. return 0;
  6941. }
  6942. #ifdef DEBUG
  6943. else if (InRange(uID, SFVIDM_BACK_CONTEXT_FIRST, SFVIDM_BACK_CONTEXT_LAST))
  6944. {
  6945. RIPMSG(FALSE, "_OnCommand should not get this context menu invoke...");
  6946. }
  6947. #endif
  6948. else if (InRange(uID, SFVIDM_CLIENT_FIRST, SFVIDM_CLIENT_LAST) && HasCB())
  6949. {
  6950. // view callback range
  6951. CallCB(SFVM_INVOKECOMMAND, uID - SFVIDM_CLIENT_FIRST, 0);
  6952. return 0;
  6953. }
  6954. // First check for commands that always go to this defview
  6955. switch (uID)
  6956. {
  6957. case SFVIDM_GROUPBY:
  6958. _ToggleGrouping();
  6959. break;
  6960. case SFVIDM_EDIT_UNDO:
  6961. // if we are in label edit mode, don't allowany of the buttons......
  6962. if (_fInLabelEdit)
  6963. {
  6964. MessageBeep(0);
  6965. return 0;
  6966. }
  6967. Undo(_hwndMain);
  6968. break;
  6969. case SFVIDM_VIEW_COLSETTINGS:
  6970. {
  6971. CColumnDlg ccd(this);
  6972. AddColumns();
  6973. ccd.ShowDialog(_hwndMain);
  6974. break;
  6975. }
  6976. case SFVIDM_VIEW_VIEWMENU:
  6977. {
  6978. // if we are in label edit mode, don't allow any of the buttons......
  6979. if (_fInLabelEdit)
  6980. {
  6981. MessageBeep(0);
  6982. return 0;
  6983. }
  6984. LPCDFVCMDDATA pcd = (LPCDFVCMDDATA)lParam;
  6985. if (pcd && pcd->pva && pcd->pva->byref)
  6986. {
  6987. LPRECT prect = (LPRECT)pcd->pva->byref;
  6988. IContextMenu* pcm;
  6989. if (SUCCEEDED(_Create_BackgrndHMENU(TRUE, IID_PPV_ARG(IContextMenu, &pcm))))
  6990. {
  6991. POINT pt = { prect->left, prect->bottom};
  6992. DoContextMenuPopup(pcm, 0, pt);
  6993. pcm->Release();
  6994. }
  6995. }
  6996. }
  6997. break;
  6998. case SFVIDM_VIEW_TILE:
  6999. //
  7000. // AppCompat: Pre WinXP 0x702E used to be SFVIDM_VIEW_VIEWMENU, now it's SFVIDM_VIEW_TILE.
  7001. // Corel apps send 0x702E to get the ViewMenu on the SaveAs dialogs. Of course that no
  7002. // longer works since 0x702E switches them to TileMode. Luckily SFVIDM_VIEW_VIEWMENU has
  7003. // a non-NULL lParam while SFVIDM_VIEW_TILE always has a NULL lParam so we can tell the
  7004. // two apart. So when Corel sends a 0x702E with a non-NULL lParam they mean SFVIDM_VIEW_VIEWMENU
  7005. // and when they send a 0x702E with a NULL lParam they mean SFVIDM_VIEW_TILE.
  7006. //
  7007. COMPILETIME_ASSERT(SFVIDM_VIEW_TILE == 0x702E); //see above app compat comments.
  7008. if (lParam && (SHGetAppCompatFlags(ACF_WIN95DEFVIEW) & ACF_WIN95DEFVIEW))
  7009. {
  7010. return _OnCommand(pcmToInvoke, SFVIDM_VIEW_VIEWMENU, lParam); // change this into a SFVIDM_VIEW_VIEWMENU
  7011. }
  7012. // Fall through ...
  7013. case SFVIDM_VIEW_ICON:
  7014. case SFVIDM_VIEW_SMALLICON:
  7015. case SFVIDM_VIEW_THUMBNAIL:
  7016. case SFVIDM_VIEW_THUMBSTRIP:
  7017. case SFVIDM_VIEW_LIST:
  7018. case SFVIDM_VIEW_DETAILS:
  7019. COMPILETIME_ASSERT(FVM_ICON == (SFVIDM_VIEW_ICON-SFVIDM_VIEW_FIRST));
  7020. COMPILETIME_ASSERT(FVM_SMALLICON == (SFVIDM_VIEW_SMALLICON-SFVIDM_VIEW_FIRST));
  7021. COMPILETIME_ASSERT(FVM_THUMBNAIL == (SFVIDM_VIEW_THUMBNAIL-SFVIDM_VIEW_FIRST));
  7022. COMPILETIME_ASSERT(FVM_THUMBSTRIP == (SFVIDM_VIEW_THUMBSTRIP-SFVIDM_VIEW_FIRST));
  7023. COMPILETIME_ASSERT(FVM_LIST == (SFVIDM_VIEW_LIST-SFVIDM_VIEW_FIRST));
  7024. COMPILETIME_ASSERT(FVM_TILE == (SFVIDM_VIEW_TILE-SFVIDM_VIEW_FIRST));
  7025. COMPILETIME_ASSERT(FVM_DETAILS == (SFVIDM_VIEW_DETAILS-SFVIDM_VIEW_FIRST));
  7026. SetCurrentViewMode(uID - SFVIDM_VIEW_FIRST);
  7027. break;
  7028. case SFVIDM_DESKTOPHTML_WEBCONTENT:
  7029. {
  7030. // we have removed this button, but we need to keep this for message for other things
  7031. BOOL bHasVisibleNonLocalPicture = FALSE;
  7032. SHELLSTATE ss;
  7033. SHGetSetSettings(&ss, SSF_DESKTOPHTML, FALSE); // Get the setting
  7034. ss.fDesktopHTML = !ss.fDesktopHTML; // Toggle the state
  7035. if (ss.fDesktopHTML && !IsICWCompleted())
  7036. {
  7037. IActiveDesktop *pIAD;
  7038. if (SUCCEEDED(SHCoCreateInstance(NULL, &CLSID_ActiveDesktop, NULL, IID_PPV_ARG(IActiveDesktop, &pIAD))))
  7039. {
  7040. bHasVisibleNonLocalPicture = (DisableUndisplayableComponents(pIAD) != 0);
  7041. pIAD->Release();
  7042. }
  7043. }
  7044. if (!bHasVisibleNonLocalPicture)
  7045. {
  7046. SHELLSTATE ss2;
  7047. SHGetSetSettings(&ss, SSF_DESKTOPHTML, TRUE); // Write back the new
  7048. // Now read back the current setting - only call _SwitchDesktopHTML if the current
  7049. // setting and the one we just set agree. If they don't that means someone changed
  7050. // the setting during the above call and we shouldn't do any more work or our state
  7051. // will get messed up.
  7052. SHGetSetSettings(&ss2, SSF_DESKTOPHTML, FALSE);
  7053. if (ss.fDesktopHTML == ss2.fDesktopHTML)
  7054. {
  7055. _SwitchDesktopHTML(BOOLIFY(ss.fDesktopHTML));
  7056. }
  7057. }
  7058. }
  7059. break;
  7060. case SFVIDM_DESKTOPHTML_ICONS:
  7061. case SFVIDM_ARRANGE_DISPLAYICONS: // (buzzr) I'm leaving SFVIDM_ARRANGE_DISPLAYICONS
  7062. { // for backwards compat. It used to be a
  7063. SHELLSTATE ss; // menu entry on POPUP_SFV_BACKGROUND.
  7064. DWORD dwValue;
  7065. // Toggle the cached state
  7066. _fs.fFlags ^= FWF_NOICONS;
  7067. ss.fHideIcons = ((_fs.fFlags & FWF_NOICONS) != 0);
  7068. dwValue = ss.fHideIcons ? 1 : 0;
  7069. // Since this value is currrently stored under the "advanced" reg tree we need
  7070. // to explicitly write to the registry or the value won't persist properly via
  7071. // SHGetSetSettings.
  7072. SHSetValue(HKEY_CURRENT_USER,
  7073. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"),
  7074. TEXT("HideIcons"), REG_DWORD, &dwValue, sizeof(dwValue));
  7075. // Finally set the ShellState and perform the action!
  7076. SHGetSetSettings(&ss, SSF_HIDEICONS, TRUE);
  7077. // Since this SFVIDM_ comes from the menu, we better already be active (or
  7078. // this SW_SHOW could make us visible before we want to be seen).
  7079. ASSERT(_uState != SVUIA_DEACTIVATE);
  7080. ActiveDesktop_ApplyChanges();
  7081. ShowHideListView();
  7082. }
  7083. break;
  7084. case SFVIDM_DESKTOPHTML_LOCK:
  7085. {
  7086. DWORD dwFlags = GetDesktopFlags();
  7087. dwFlags ^= COMPONENTS_LOCKED;
  7088. SetDesktopFlags(COMPONENTS_LOCKED, dwFlags);
  7089. ActiveDesktop_ApplyChanges();
  7090. }
  7091. break;
  7092. case SFVIDM_DESKTOPHTML_WIZARD:
  7093. {
  7094. // launch desktop cleanup wizard
  7095. SHRunDLLThread(NULL, TEXT("fldrclnr.dll,Wizard_RunDLL all"), SW_SHOWNORMAL);
  7096. }
  7097. break;
  7098. case SFVIDM_EDIT_COPYTO:
  7099. case SFVIDM_EDIT_MOVETO:
  7100. {
  7101. // if we are in label edit mode, don't allowany of the buttons......
  7102. if (_fInLabelEdit)
  7103. {
  7104. MessageBeep(0);
  7105. return 0;
  7106. }
  7107. if (_pSelectionShellItemArray)
  7108. {
  7109. _DoMoveOrCopyTo(((uID == SFVIDM_EDIT_COPYTO) ? CLSID_CopyToMenu : CLSID_MoveToMenu), _pSelectionShellItemArray);
  7110. }
  7111. }
  7112. break;
  7113. case SFVIDM_FILE_PROPERTIES:
  7114. if (SHRestricted(REST_NOVIEWCONTEXTMENU))
  7115. break;
  7116. // else fall through...
  7117. case SFVIDM_EDIT_PASTE:
  7118. case SFVIDM_EDIT_PASTELINK:
  7119. case SFVIDM_EDIT_COPY:
  7120. case SFVIDM_EDIT_CUT:
  7121. case SFVIDM_FILE_LINK:
  7122. case SFVIDM_FILE_DELETE:
  7123. if (!_OnDefviewEditCommand(uID))
  7124. {
  7125. // REVIEW: this looks like a hack.
  7126. // there's got to be a cleaner way of doing this...
  7127. //
  7128. LPDFVCMDDATA pcd = (LPDFVCMDDATA)lParam;
  7129. // Try translating the SFVIDM value into a standard
  7130. // OLECMDID value, so that the caller can try applying
  7131. // it to a different object.
  7132. if (!IsBadWritePtr(pcd, sizeof(*pcd)))
  7133. {
  7134. pcd->nCmdIDTranslated = OlecmdidFromSfvidm(uID);
  7135. }
  7136. }
  7137. break;
  7138. case SFVIDM_TOOL_OPTIONS:
  7139. if (!SHRestricted(REST_NOFOLDEROPTIONS))
  7140. {
  7141. IUnknown_Exec(_psb, &CGID_Explorer, SBCMDID_OPTIONS, 0, NULL, NULL);
  7142. }
  7143. break;
  7144. #ifdef DEBUG
  7145. case SFVIDM_DEBUG_WEBVIEW:
  7146. _cFrame._ShowWebViewContent();
  7147. break;
  7148. #endif // DEBUG
  7149. case SFVIDM_HELP_TOPIC:
  7150. // Don't call WinHelp when we are in the common dialog.
  7151. if (!_IsCommonDialog())
  7152. {
  7153. // Use a callback to see if the namespace has requested a different help file name and/or topic
  7154. SFVM_HELPTOPIC_DATA htd;
  7155. HWND hwndDesktop = GetDesktopWindow();
  7156. SHTCharToUnicode(c_szHtmlWindowsHlp, htd.wszHelpFile, ARRAYSIZE(htd.wszHelpFile));
  7157. htd.wszHelpTopic[0] = 0;
  7158. if (SUCCEEDED(CallCB(SFVM_GETHELPTOPIC, 0, (LPARAM)&htd)))
  7159. {
  7160. if (URL_SCHEME_MSHELP == GetUrlSchemeW(htd.wszHelpTopic))
  7161. {
  7162. //
  7163. // Callback specified an HSS help URL.
  7164. //
  7165. SHELLEXECUTEINFOW sei = {0};
  7166. sei.cbSize = sizeof(sei);
  7167. sei.lpFile = htd.wszHelpTopic;
  7168. sei.hwnd = hwndDesktop;
  7169. sei.nShow = SW_NORMAL;
  7170. ShellExecuteExW(&sei);
  7171. }
  7172. else
  7173. {
  7174. HtmlHelp(hwndDesktop, htd.wszHelpFile, HH_HELP_FINDER, htd.wszHelpTopic[0] ? (DWORD_PTR)htd.wszHelpTopic : 0);
  7175. }
  7176. }
  7177. else
  7178. {
  7179. // ask the shell dispatch object to display Help for us
  7180. IShellDispatch *psd;
  7181. if (SUCCEEDED(SHCoCreateInstance(NULL, &CLSID_Shell, NULL, IID_PPV_ARG(IShellDispatch, &psd))))
  7182. {
  7183. psd->Help();
  7184. psd->Release();
  7185. }
  7186. }
  7187. }
  7188. break;
  7189. case SFVIDM_VIEW_CUSTOMWIZARD:
  7190. _InvokeCustomization();
  7191. break;
  7192. case SFVIDM_MISC_HARDREFRESH:
  7193. _fAllowSearchingWindow = TRUE;
  7194. _FreeWebViewContentData();
  7195. _ReloadContent(TRUE); // have to enumerate before _GetDefaultViewMode() will be accurate
  7196. SetCurrentViewMode(_GetDefaultViewMode()); // even if fvm is the same, it will update webview if it changed
  7197. Refresh();
  7198. break;
  7199. case SFVIDM_MISC_SETWEBVIEW:
  7200. SetCurrentViewMode(_fs.ViewMode); // re-setting the fvm updates everything (turning web view off can switch from Thumbstrip to Thumbnail!)
  7201. Refresh(); // we want to refresh when we switch turn webview on/off, since some icons appear/disappear on the transition
  7202. break;
  7203. case SFVIDM_MISC_REFRESH:
  7204. _fAllowSearchingWindow = TRUE;
  7205. Refresh();
  7206. break;
  7207. default:
  7208. // check for commands that need to be sent to the active object
  7209. switch (uID)
  7210. {
  7211. case SFVIDM_ARRANGE_AUTO:
  7212. _fs.fFlags ^= FWF_AUTOARRANGE; // toggle
  7213. _ClearItemPositions();
  7214. SHSetWindowBits(_hwndListview, GWL_STYLE, LVS_AUTOARRANGE, _IsAutoArrange() ? LVS_AUTOARRANGE : 0);
  7215. break;
  7216. case SFVIDM_ARRANGE_GRID:
  7217. ListView_Arrange(_hwndListview, LVA_SNAPTOGRID);
  7218. break;
  7219. case SFVIDM_ARRANGE_AUTOGRID:
  7220. {
  7221. _fs.fFlags ^= FWF_SNAPTOGRID;
  7222. DWORD dwLVFlags = ListView_GetExtendedListViewStyle(_hwndListview);
  7223. dwLVFlags ^= LVS_EX_SNAPTOGRID;
  7224. ListView_SetExtendedListViewStyle(_hwndListview, dwLVFlags);
  7225. //if this is desktop, we need to change the icon spacing.
  7226. UpdateGridSizes(_IsDesktop(), _hwndListview, 0, NULL, BOOLIFY(dwLVFlags & LVS_EX_SNAPTOGRID));
  7227. // if ActiveDesktop on, need to refresh, otherwise, can just arrange
  7228. SHELLSTATE ss = {0};
  7229. SHGetSetSettings( &ss, SSF_DESKTOPHTML, FALSE);
  7230. if (ss.fDesktopHTML)
  7231. {
  7232. Refresh();
  7233. }
  7234. else
  7235. {
  7236. if ((dwLVFlags & LVS_EX_SNAPTOGRID))
  7237. {
  7238. ListView_Arrange(_hwndListview, LVA_SNAPTOGRID);
  7239. }
  7240. }
  7241. }
  7242. break;
  7243. default:
  7244. // Normal view, we know what to do
  7245. switch (uID)
  7246. {
  7247. case SFVIDM_SELECT_ALL:
  7248. {
  7249. DECLAREWAITCURSOR;
  7250. if (CallCB(SFVM_SELECTALL, 0, 0) != S_FALSE)
  7251. {
  7252. SetWaitCursor();
  7253. SetFocus(_hwndListview);
  7254. ListView_SetItemState(_hwndListview, -1, LVIS_SELECTED, LVIS_SELECTED);
  7255. // make the first item in the view the focused guy
  7256. ListView_SetItemState(_hwndListview, 0, LVIS_FOCUSED, LVIS_FOCUSED);
  7257. ResetWaitCursor();
  7258. }
  7259. break;
  7260. }
  7261. case SFVIDM_DESELECT_ALL:
  7262. ListView_SetItemState(_hwndListview, -1, 0, LVIS_SELECTED);
  7263. break;
  7264. case SFVIDM_SELECT_INVERT:
  7265. {
  7266. DECLAREWAITCURSOR;
  7267. SetWaitCursor();
  7268. SetFocus(_hwndListview);
  7269. int iItem = -1;
  7270. while ((iItem = ListView_GetNextItem(_hwndListview, iItem, 0)) != -1)
  7271. {
  7272. // flip the selection bit on each item
  7273. UINT flag = ListView_GetItemState(_hwndListview, iItem, LVIS_SELECTED);
  7274. flag ^= LVNI_SELECTED;
  7275. ListView_SetItemState(_hwndListview, iItem, flag, LVIS_SELECTED);
  7276. }
  7277. ResetWaitCursor();
  7278. break;
  7279. }
  7280. case SFVIDM_FILE_RENAME:
  7281. DoRename();
  7282. break;
  7283. default:
  7284. return 1;
  7285. }
  7286. }
  7287. }
  7288. return 0;
  7289. }
  7290. LPITEMIDLIST CDefView::_ObjectExists(LPCITEMIDLIST pidl, BOOL fGlobal)
  7291. {
  7292. LPITEMIDLIST pidlReal = NULL;
  7293. // 365069 - global events also come through here - ZekeL - 16-APR-2001
  7294. // this means that that the pidl may not be one level. if its deeper
  7295. // then for us this item doesnt exist. this enforces our assert
  7296. if (pidl && !ILIsEmpty(pidl) && (!fGlobal || ILIsEmpty(_ILNext(pidl))))
  7297. {
  7298. ASSERTMSG(ILFindLastID(pidl) == pidl, "defview doesnt expect recursive notification");
  7299. SHGetRealIDL(_pshf, pidl, &pidlReal);
  7300. }
  7301. return pidlReal;
  7302. }
  7303. void CDefView::_OnRename(LPCITEMIDLIST* ppidl)
  7304. {
  7305. if (_pidlMonitor)
  7306. {
  7307. if (!ILIsParent(_pidlMonitor, ppidl[0], TRUE))
  7308. {
  7309. // move to this folder
  7310. _OnFSNotify(SHCNE_CREATE, &ppidl[1]);
  7311. }
  7312. else if (!ILIsParent(_pidlMonitor, ppidl[1], TRUE))
  7313. {
  7314. // move from this folder
  7315. _OnFSNotify(SHCNE_DELETE, &ppidl[0]);
  7316. }
  7317. else
  7318. {
  7319. // rename within this folder
  7320. // _pidlMonitor is guaranteed to be immediate parent of both pidls so ILFindLastID is okay.
  7321. LPCITEMIDLIST pidlOld = ILFindLastID(ppidl[0]);
  7322. LPITEMIDLIST pidlNew = _ObjectExists(ILFindLastID(ppidl[1]), FALSE);
  7323. if (pidlNew)
  7324. {
  7325. _UpdateObject(pidlOld, pidlNew);
  7326. ILFree(pidlNew);
  7327. }
  7328. }
  7329. }
  7330. }
  7331. //
  7332. // SFVM_UPDATESTATUSBAR return values:
  7333. //
  7334. // failure code = Callback did not do anything, we must do it all
  7335. //
  7336. // Otherwise, the GetScode(hr) is a bitmask describing what the app
  7337. // wants us to do.
  7338. //
  7339. // 0 - App wants us to do nothing (S_OK) - message handled completely
  7340. // 1 - App wants us to set the default text (but not initialize)
  7341. //
  7342. // <other bits reserved for future use>
  7343. void CDefView::_UpdateStatusBar(BOOL fInitialize)
  7344. {
  7345. HRESULT hr;
  7346. // We have to clear the contents here since some clients (like the ftp client) return S_OK from
  7347. // the callback but do not set the text of the bar
  7348. HWND hwndStatus;
  7349. if (_psb && SUCCEEDED(_psb->GetControlWindow(FCW_STATUS, &hwndStatus)) && hwndStatus)
  7350. {
  7351. _fBackgroundStatusTextValid = FALSE;
  7352. SendMessage(hwndStatus, SB_SETTEXT, (WPARAM)0, (LPARAM)_TEXT(""));
  7353. }
  7354. if (_bBkFilling || FAILED(hr = CallCB(SFVM_UPDATESTATUSBAR, fInitialize, 0)))
  7355. {
  7356. // Client wants us to do everything
  7357. _DoStatusBar(fInitialize);
  7358. }
  7359. else if (hr & SFVUSB_INITED)
  7360. {
  7361. // Client wants us to do text but not initialize
  7362. _DoStatusBar(FALSE);
  7363. }
  7364. }
  7365. // Returns TRUE iff we are supposed to show Web View content on this view.
  7366. // For the most part it follows SSF_WEBVIEW for normal folders and SSF_DESKTOPHTML for the desktop
  7367. //
  7368. BOOL CDefView::_ShouldShowWebView()
  7369. {
  7370. // No webview for common dialogs
  7371. if (_IsCommonDialog())
  7372. {
  7373. return FALSE;
  7374. }
  7375. // No webview in cleanboot mode
  7376. if (GetSystemMetrics(SM_CLEANBOOT))
  7377. return FALSE;
  7378. BOOL bForceWebViewOn;
  7379. if (SUCCEEDED(CallCB(SFVM_FORCEWEBVIEW, (WPARAM)&bForceWebViewOn, 0)))
  7380. {
  7381. return bForceWebViewOn;
  7382. }
  7383. // Quattro Pro (QPW) doesn't know how SHChangeNotify works,
  7384. // so when they want to refresh My Computer, they create an IShellView,
  7385. // invoke its CreateViewWindow(), invoke its Refresh(), then DestroyWindow
  7386. // the window and release the view. The IShellBrowser they pass
  7387. // to CreateViewWindow is allocated on the stack (!), and they expect
  7388. // that their Release() be the last one. Creating an async view keeps
  7389. // the object alive, so when the view is complete, we try to talk to the
  7390. // IShellBrowser and fault because it's already gone.
  7391. //
  7392. // The Zip Archives (from Aeco Systems) is another messed up App.
  7393. // They neither implement IPersistFolder2 (so we can't get their pidl) nor
  7394. // set the pidl to the shellfolderviewcb object. They don't implement
  7395. // IShellFolder2 either. Webview is practically useless for them.
  7396. //
  7397. // Adaptec Easy CD Creator 3.5 is in the same boat.
  7398. //
  7399. SHELLSTATE ss;
  7400. SHGetSetSettings(&ss, SSF_WIN95CLASSIC | SSF_DESKTOPHTML | SSF_WEBVIEW, FALSE);
  7401. // If the "no web view" flag is set (potential WebOC case) then return false;
  7402. if (_fs.fFlags & FWF_NOWEBVIEW)
  7403. return FALSE;
  7404. if (_IsDesktop())
  7405. {
  7406. return ss.fDesktopHTML;
  7407. }
  7408. else
  7409. {
  7410. return ss.fWebView &&
  7411. !(SHGetAppCompatFlags(ACF_OLDCREATEVIEWWND) & ACF_OLDCREATEVIEWWND) &&
  7412. !(SHGetObjectCompatFlags(_pshf, NULL) & OBJCOMPATF_NO_WEBVIEW);
  7413. }
  7414. }
  7415. // takes ownership of pidlNew since _AddObject takes ownership.
  7416. void CDefView::_AddOrUpdateItem(LPCITEMIDLIST pidlOld, LPITEMIDLIST pidlNew)
  7417. {
  7418. if (_FindItem(pidlOld, NULL, FALSE) != -1)
  7419. {
  7420. _UpdateObject(pidlOld, pidlNew);
  7421. ILFree(pidlNew);
  7422. }
  7423. else
  7424. {
  7425. // check if the shellfolder says this new guy shouldn't be enumerated.
  7426. if (!_Attributes(pidlNew, SFGAO_NONENUMERATED))
  7427. {
  7428. _AddObject(pidlNew); // takes pidl ownership.
  7429. }
  7430. else
  7431. {
  7432. ILFree(pidlNew);
  7433. }
  7434. }
  7435. }
  7436. #define FSNDEBUG
  7437. // WM_DSV_FSNOTIFY message
  7438. LRESULT CDefView::_OnFSNotify(LONG lNotification, LPCITEMIDLIST* ppidl)
  7439. {
  7440. LPITEMIDLIST pidl;
  7441. LPCITEMIDLIST pidlItem;
  7442. //
  7443. // Note that renames between directories are changed to
  7444. // create/delete pairs by SHChangeNotify.
  7445. //
  7446. #ifdef DEBUG
  7447. #ifdef FSNDEBUG
  7448. TCHAR szPath[MAX_PATH];
  7449. TraceMsg(TF_DEFVIEW, "CDefView::_OnFSNotify, hwnd = %d lEvent = %d", _hwndView, lNotification);
  7450. switch (lNotification)
  7451. {
  7452. case SHCNE_RENAMEITEM:
  7453. case SHCNE_RENAMEFOLDER:
  7454. // two pidls
  7455. SHGetPathFromIDList(ppidl[0], szPath);
  7456. TraceMsg(TF_DEFVIEW, "CDefView::_OnFSNotify: hwnd %d, %s", _hwndView, szPath);
  7457. SHGetPathFromIDList(ppidl[1], szPath);
  7458. TraceMsg(TF_DEFVIEW, "CDefView::_OnFSNotify: hwnd %d, %s", _hwndView, szPath);
  7459. break;
  7460. case SHCNE_CREATE:
  7461. case SHCNE_DELETE:
  7462. case SHCNE_MKDIR:
  7463. case SHCNE_RMDIR:
  7464. case SHCNE_MEDIAINSERTED:
  7465. case SHCNE_MEDIAREMOVED:
  7466. case SHCNE_DRIVEREMOVED:
  7467. case SHCNE_DRIVEADD:
  7468. case SHCNE_NETSHARE:
  7469. case SHCNE_NETUNSHARE:
  7470. case SHCNE_ATTRIBUTES:
  7471. case SHCNE_UPDATEDIR:
  7472. case SHCNE_UPDATEITEM:
  7473. case SHCNE_SERVERDISCONNECT:
  7474. case SHCNE_DRIVEADDGUI:
  7475. case SHCNE_EXTENDED_EVENT:
  7476. // one pidl
  7477. SHGetPathFromIDList(ppidl[0], szPath);
  7478. TraceMsg(TF_DEFVIEW, "CDefView::_OnFSNotify: hwnd %d, %s", _hwndView, szPath);
  7479. break;
  7480. case SHCNE_UPDATEIMAGE:
  7481. // DWORD wrapped inside a pidl
  7482. TraceMsg(TF_DEFVIEW, "CDefView::_OnFSNotify: hwnd %d, %08x", _hwndView,
  7483. ((LPSHChangeDWORDAsIDList)ppidl[0])->dwItem1);
  7484. break;
  7485. case SHCNE_ASSOCCHANGED:
  7486. // No parameters
  7487. break;
  7488. }
  7489. #endif
  7490. #endif
  7491. // we may be registered for notifications on pidls that are different from
  7492. // the one returned by _GetViewPidl (ftp folder).
  7493. switch (lNotification)
  7494. {
  7495. case SHCNE_DRIVEADD:
  7496. case SHCNE_CREATE:
  7497. case SHCNE_MKDIR:
  7498. pidlItem = _pidlMonitor ? ILFindChild(_pidlMonitor, ppidl[0]) : NULL;
  7499. pidl = _ObjectExists(pidlItem, FALSE);
  7500. if (pidl)
  7501. {
  7502. _AddOrUpdateItem(pidlItem, pidl);
  7503. }
  7504. break;
  7505. case SHCNE_DRIVEREMOVED:
  7506. case SHCNE_DELETE:
  7507. case SHCNE_RMDIR:
  7508. pidlItem = _pidlMonitor ? ILFindChild(_pidlMonitor, ppidl[0]) : NULL;
  7509. if (pidlItem)
  7510. {
  7511. ASSERTMSG(ILFindLastID(pidlItem) == pidlItem, "defview doesnt expect recursive notification");
  7512. _RemoveObject((LPITEMIDLIST)pidlItem, FALSE);
  7513. }
  7514. break;
  7515. case SHCNE_RENAMEITEM:
  7516. case SHCNE_RENAMEFOLDER:
  7517. _OnRename(ppidl);
  7518. break;
  7519. case SHCNE_UPDATEIMAGE:
  7520. // the system image cache is changing
  7521. // ppidl[0] is a IDLIST of image indexs that have changed
  7522. if (ppidl && ppidl[1])
  7523. {
  7524. // this event is generated instead of a normal UPDATEIMAGE so that we can handle the
  7525. // cross process case....
  7526. // handle the notification
  7527. int iImage = SHHandleUpdateImage(ppidl[1]);
  7528. if (iImage != -1)
  7529. {
  7530. _UpdateImage(iImage);
  7531. }
  7532. }
  7533. else if (ppidl && ppidl[0])
  7534. {
  7535. int iImage = *(int UNALIGNED *)((BYTE *)ppidl[0] + 2);
  7536. _UpdateImage(iImage);
  7537. }
  7538. break;
  7539. case SHCNE_ASSOCCHANGED:
  7540. // For this one we will call refresh as we may need to reextract
  7541. // the icons and the like. Later we can optimize this somewhat if
  7542. // we can detect which ones changed and only update those.
  7543. _ReloadContent();
  7544. break;
  7545. case SHCNE_ATTRIBUTES: // these all mean the same thing
  7546. case SHCNE_MEDIAINSERTED:
  7547. case SHCNE_MEDIAREMOVED:
  7548. case SHCNE_NETUNSHARE:
  7549. case SHCNE_NETSHARE:
  7550. case SHCNE_UPDATEITEM:
  7551. if (ppidl)
  7552. {
  7553. LPCITEMIDLIST pidlOld = _pidlMonitor ? ILFindChild(_pidlMonitor, ppidl[0]) : NULL;
  7554. LPITEMIDLIST pidlNew = _ObjectExists(pidlOld, SHCNE_GLOBALEVENTS & lNotification);
  7555. if (pidlNew)
  7556. {
  7557. _AddOrUpdateItem(pidlOld, pidlNew);
  7558. }
  7559. else
  7560. {
  7561. // If we do not have any subobjects and the passed in pidl is the same as
  7562. // this views pidl then refresh all the items.
  7563. LPITEMIDLIST pidlView = _GetViewPidl();
  7564. if (pidlView)
  7565. {
  7566. if (ILIsEqual(ppidl[0], pidlView))
  7567. {
  7568. _FullViewUpdate(SHCNE_UPDATEITEM == lNotification);
  7569. }
  7570. ILFree(pidlView);
  7571. }
  7572. }
  7573. }
  7574. else // ppidl == NULL means update all items (re-enum them)
  7575. {
  7576. _FullViewUpdate(SHCNE_UPDATEITEM == lNotification);
  7577. }
  7578. break;
  7579. case SHCNE_FREESPACE:
  7580. TCHAR szPath[MAX_PATH];
  7581. if (_GetPath(szPath))
  7582. {
  7583. int idDrive = PathGetDriveNumber(szPath);
  7584. if (idDrive != -1)
  7585. {
  7586. DWORD dwChangedDrives = *(DWORD UNALIGNED *)((BYTE *)ppidl[0] + 2);
  7587. if (((1 << idDrive) & dwChangedDrives))
  7588. {
  7589. _UpdateStatusBar(TRUE);
  7590. }
  7591. }
  7592. }
  7593. break;
  7594. default:
  7595. TraceMsg(TF_DEFVIEW, "DefView: unknown FSNotify %08lX, doing full update", lNotification);
  7596. _FullViewUpdate(FALSE);
  7597. break;
  7598. }
  7599. _UpdateStatusBar(FALSE);
  7600. return 0;
  7601. }
  7602. // called when some of our objects get put on the clipboard
  7603. LRESULT CDefView::_OnSetClipboard(BOOL bMove)
  7604. {
  7605. if (bMove) // move
  7606. {
  7607. // mark all selected items as being "cut"
  7608. int i = -1;
  7609. while ((i = ListView_GetNextItem(_hwndListview, i, LVIS_SELECTED)) != -1)
  7610. {
  7611. ListView_SetItemState(_hwndListview, i, LVIS_CUT, LVIS_CUT);
  7612. _bHaveCutStuff = TRUE;
  7613. }
  7614. // join the clipboard viewer chain so we will know when to
  7615. // "uncut" our selected items.
  7616. if (_bHaveCutStuff)
  7617. {
  7618. ASSERT(!_bClipViewer);
  7619. ASSERT(_hwndNextViewer == NULL);
  7620. _hwndNextViewer = SetClipboardViewer(_hwndView);
  7621. _bClipViewer = TRUE;
  7622. }
  7623. }
  7624. return 0;
  7625. }
  7626. // called when the clipboard get changed, clear any items in the "cut" state
  7627. //
  7628. LRESULT CDefView::_OnClipboardChange()
  7629. {
  7630. //
  7631. // if we dont have any cut stuff we dont care.
  7632. //
  7633. if (!_bHaveCutStuff)
  7634. return 0;
  7635. ASSERT(_bClipViewer);
  7636. _RestoreAllGhostedFileView();
  7637. _bHaveCutStuff = FALSE;
  7638. //
  7639. // unhook from the clipboard viewer chain.
  7640. //
  7641. ChangeClipboardChain(_hwndView, _hwndNextViewer);
  7642. _bClipViewer = FALSE;
  7643. _hwndNextViewer = NULL;
  7644. return 0;
  7645. }
  7646. //
  7647. // Note: this function returns the point in Listview Coordinate
  7648. // space. So any hit testing done with this needs to be converted
  7649. // back to Client coordinate space...
  7650. BOOL CDefView::_GetDropPoint(POINT *ppt)
  7651. {
  7652. // Check whether we already have gotten the drop anchor (before any
  7653. // menu processing)
  7654. if (_bDropAnchor)
  7655. {
  7656. // We'll use the insert mark rect (if available) to determine a drop point
  7657. if (!_GetInsertPoint(ppt))
  7658. {
  7659. *ppt = _ptDrop; // Otherwise use _ptDrop
  7660. LVUtil_ClientToLV(_hwndListview, ppt);
  7661. }
  7662. }
  7663. else if (_bMouseMenu)
  7664. {
  7665. *ppt = _ptDragAnchor;
  7666. return TRUE;
  7667. }
  7668. else
  7669. {
  7670. // We need the most up-to-date cursor information, since this
  7671. // may be called during a drop, and the last time the current
  7672. // thread called GetMessage was about 10 minutes ago
  7673. GetCursorPos(ppt);
  7674. LVUtil_ScreenToLV(_hwndListview, ppt);
  7675. }
  7676. return _bDropAnchor;
  7677. }
  7678. // This uses the listview's insertmark to determinie an insert point
  7679. // Returns FALSE if a point could not be determined, TRUE otherwise
  7680. // The coordinates returned are in listview coordinate space.
  7681. BOOL CDefView::_GetInsertPoint(POINT *ppt)
  7682. {
  7683. if (_IsAutoArrange() || (_fs.fFlags & FWF_SNAPTOGRID))
  7684. {
  7685. RECT rcInsert;
  7686. if (ListView_GetInsertMarkRect(_hwndListview, &rcInsert))
  7687. {
  7688. LONG dwStyle = GetWindowLong(_hwndListview, GWL_STYLE);
  7689. BOOL fHorizontal = (_fs.fFlags & FWF_ALIGNLEFT);
  7690. if (fHorizontal)
  7691. {
  7692. ppt->x = (rcInsert.right + rcInsert.left) / 2; // Drop in middle of insertmark rect
  7693. ppt->y = rcInsert.top;
  7694. }
  7695. else
  7696. {
  7697. ppt->x = rcInsert.left;
  7698. ppt->y = (rcInsert.bottom + rcInsert.top) / 2; // Drop in middle of insertmark rect
  7699. }
  7700. return TRUE;
  7701. }
  7702. }
  7703. return FALSE;
  7704. }
  7705. BOOL CDefView::_GetDragPoint(POINT *ppt)
  7706. {
  7707. BOOL fSource = _bDragSource || _bMouseMenu;
  7708. if (fSource)
  7709. {
  7710. // if anchor from mouse activity
  7711. *ppt = _ptDragAnchor;
  7712. }
  7713. else
  7714. {
  7715. // if anchor from keyboard activity... use the focused item
  7716. int i = ListView_GetNextItem(_hwndListview, -1, LVNI_FOCUSED);
  7717. if (i != -1)
  7718. {
  7719. ListView_GetItemPosition(_hwndListview, i, ppt);
  7720. }
  7721. else
  7722. {
  7723. ppt->x = ppt->y = 0;
  7724. }
  7725. }
  7726. return fSource;
  7727. }
  7728. void CDefView::_PaintErrMsg(HWND hWnd)
  7729. {
  7730. PAINTSTRUCT ps;
  7731. HDC hdc = BeginPaint(hWnd, &ps);
  7732. // if we're in an error state, make sure we're not in webview
  7733. if (_cFrame.IsWebView())
  7734. {
  7735. _SwitchToWebView(FALSE);
  7736. }
  7737. RECT rc;
  7738. GetClientRect(hWnd, &rc);
  7739. DrawEdge(hdc, &rc, EDGE_SUNKEN, BF_RECT | BF_SOFT | BF_ADJUST | BF_MIDDLE);
  7740. EndPaint(hWnd, &ps);
  7741. }
  7742. //
  7743. // The default status bar looks like this:
  7744. //
  7745. // No items selected: "nn object(s)" nn = total objects in folder
  7746. // One item selected: <InfoTip for selected item> if item supports InfoTip
  7747. // Else: "nn object(s) selected" nn = num selected objects
  7748. //
  7749. //
  7750. void CDefView::_DoStatusBar(BOOL fInitialize)
  7751. {
  7752. HWND hwndStatus;
  7753. if (_psb && SUCCEEDED(_psb->GetControlWindow(FCW_STATUS, &hwndStatus)) && hwndStatus)
  7754. {
  7755. // Some of the failure cases do not null hwnd...
  7756. UINT uMsg = IDS_FSSTATUSSELECTED;
  7757. if (fInitialize)
  7758. {
  7759. int ciParts[] = {-1};
  7760. SendMessage(hwndStatus, SB_SETPARTS, ARRAYSIZE(ciParts), (LPARAM)ciParts);
  7761. }
  7762. if (_bBkFilling && ListView_GetSelectedCount(_hwndListview) == 0)
  7763. {
  7764. _fBackgroundStatusTextValid = FALSE;
  7765. LPWSTR pszStatus = ShellConstructMessageString(HINST_THISDLL, MAKEINTRESOURCE(IDS_FSSTATUSSEARCHING));
  7766. // We are not checking if the alloc succeeded in ShellConstructMessageString since both
  7767. // SendMessage and LocalFree can take NULL as inputs.
  7768. SendMessage(hwndStatus, SB_SETTEXT, (WPARAM)0, (LPARAM)pszStatus);
  7769. LocalFree((void *)pszStatus);
  7770. }
  7771. else
  7772. {
  7773. LPCITEMIDLIST *apidl = NULL;
  7774. int nMsgParam = ListView_GetSelectedCount(_hwndListview);
  7775. switch (nMsgParam)
  7776. {
  7777. case 0:
  7778. // No objects selected; show total item count
  7779. nMsgParam = ListView_GetItemCount(_hwndListview);
  7780. uMsg = IDS_FSSTATUSBASE;
  7781. break;
  7782. case 1:
  7783. UINT cItems;
  7784. GetSelectedObjects(&apidl, &cItems);
  7785. break;
  7786. }
  7787. LPITEMIDLIST pidlFolder = _GetViewPidl();
  7788. if (pidlFolder)
  7789. {
  7790. CStatusBarAndInfoTipTask *pTask;
  7791. if (SUCCEEDED(CStatusBarAndInfoTipTask_CreateInstance(pidlFolder, apidl ? *apidl : NULL, uMsg, nMsgParam, NULL, _hwndView, _pScheduler, &pTask)))
  7792. {
  7793. if (_pScheduler)
  7794. {
  7795. // make sure there are no other status bar background tasks going on...
  7796. _pScheduler->RemoveTasks(TOID_DVBackgroundStatusBar, ITSAT_DEFAULT_LPARAM, FALSE);
  7797. }
  7798. _fBackgroundStatusTextValid = TRUE;
  7799. _AddTask(pTask, TOID_DVBackgroundStatusBar, 0, TASK_PRIORITY_INFOTIP, ADDTASK_ATEND);
  7800. pTask->Release();
  7801. }
  7802. ILFree(pidlFolder);
  7803. }
  7804. if (apidl)
  7805. LocalFree(apidl);
  7806. }
  7807. }
  7808. }
  7809. void CDefView::_OnWinIniChangeDesktop(WPARAM wParam, LPCTSTR pszSection)
  7810. {
  7811. if (pszSection)
  7812. {
  7813. if (!lstrcmpi(pszSection, TEXT("ToggleDesktop")))
  7814. {
  7815. _OnCommand(NULL, SFVIDM_DESKTOPHTML_WEBCONTENT, 0);
  7816. }
  7817. else if (!lstrcmpi(pszSection, TEXT("RefreshDesktop")))
  7818. {
  7819. if (FAILED(Refresh()))
  7820. {
  7821. SHELLSTATE ss;
  7822. //Refresh failed because the new template didn't exist
  7823. //Toggle the Registry settings back to Icons-only mode!
  7824. ss.fDesktopHTML = FALSE;
  7825. SHGetSetSettings(&ss, SSF_DESKTOPHTML, TRUE); // Write back the new
  7826. }
  7827. }
  7828. else if (!lstrcmpi(pszSection, TEXT("BufferedRefresh")))
  7829. {
  7830. //See if we have already started a timer to refresh
  7831. if (!_fRefreshBuffered)
  7832. {
  7833. TraceMsg(TF_DEFVIEW, "A Buffered refresh starts the timer");
  7834. SetTimer(_hwndView, DV_IDTIMER_BUFFERED_REFRESH, 5000, NULL); // 5 sec
  7835. _fRefreshBuffered = TRUE;
  7836. }
  7837. else //If refresh is already buffered, don't do anything!
  7838. {
  7839. TraceMsg(TF_DEFVIEW, "A buffered refresh occured while another is pending");
  7840. }
  7841. }
  7842. else
  7843. {
  7844. if (wParam == SPI_SETDESKWALLPAPER || wParam == SPI_SETDESKPATTERN)
  7845. {
  7846. _SetFolderColors();
  7847. }
  7848. }
  7849. }
  7850. else
  7851. {
  7852. switch(wParam)
  7853. {
  7854. case SPI_SETDESKWALLPAPER:
  7855. case SPI_SETDESKPATTERN:
  7856. _SetFolderColors();
  7857. break;
  7858. case SPI_ICONHORIZONTALSPACING:
  7859. case SPI_ICONVERTICALSPACING:
  7860. if (_IsDesktop())
  7861. {
  7862. DWORD dwLVExStyle = ListView_GetExtendedListViewStyle(_hwndListview);
  7863. UpdateGridSizes(TRUE, _hwndListview, 0, NULL, BOOLIFY(dwLVExStyle & LVS_EX_SNAPTOGRID));
  7864. }
  7865. break;
  7866. }
  7867. }
  7868. }
  7869. void CDefView::_OnWinIniChange(WPARAM wParam, LPCTSTR pszSection)
  7870. {
  7871. if ((wParam == SPI_GETICONTITLELOGFONT) ||
  7872. ((wParam == 0) && pszSection && !lstrcmpi(pszSection, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\IconUnderline"))))
  7873. {
  7874. _UpdateUnderlines();
  7875. }
  7876. if (pszSection && !lstrcmpi(pszSection, TEXT("VisualEffects")))
  7877. {
  7878. Refresh();
  7879. }
  7880. // Why all this code? It's a rare event -- just kick off a refresh...
  7881. if (!wParam || (pszSection && !lstrcmpi(pszSection, TEXT("intl"))))
  7882. {
  7883. // has the time format changed while we're in details mode?
  7884. if (ViewRequiresColumns(_fs.ViewMode) && !_IsOwnerData())
  7885. {
  7886. InvalidateRect(_hwndListview, NULL, TRUE);
  7887. // 99/04/13 #320903 vtan: If the date format has changed then iterate
  7888. // the entire list looking for extended columns of type date and
  7889. // resetting them to LPSTR_TEXTCALLBACK effectively dumping the cache.
  7890. // For performance improvement it's possible to collect an array of
  7891. // visible columns and reset that array. It will still involve TWO
  7892. // for loops.
  7893. int iItemCount = ListView_GetItemCount(_hwndListview);
  7894. for (int iItem = 0; iItem < iItemCount; ++iItem)
  7895. {
  7896. for (UINT uiRealColumn = 0; uiRealColumn < _vs.GetColumnCount(); ++uiRealColumn)
  7897. {
  7898. DWORD dwFlags = _vs.GetColumnState(uiRealColumn);
  7899. if (((dwFlags & SHCOLSTATE_EXTENDED) != 0) &&
  7900. ((dwFlags & SHCOLSTATE_TYPEMASK) == SHCOLSTATE_TYPE_DATE))
  7901. {
  7902. UINT uiVisibleColumn = _RealToVisibleCol(uiRealColumn);
  7903. ListView_SetItemText(_hwndListview, iItem, uiVisibleColumn, LPSTR_TEXTCALLBACK);
  7904. }
  7905. }
  7906. }
  7907. }
  7908. }
  7909. //
  7910. // we may need to rebuild the icon cache.
  7911. //
  7912. if (wParam == SPI_SETICONMETRICS ||
  7913. wParam == SPI_SETNONCLIENTMETRICS)
  7914. {
  7915. if (_IsImageMode())
  7916. {
  7917. _SetThumbview();
  7918. }
  7919. else if (_IsTileMode())
  7920. {
  7921. _SetTileview();
  7922. }
  7923. else
  7924. {
  7925. _SetSysImageList();
  7926. }
  7927. }
  7928. //
  7929. // we need to invalidate the cursor cache
  7930. //
  7931. if (wParam == SPI_SETCURSORS)
  7932. {
  7933. DAD_InvalidateCursors();
  7934. }
  7935. if ((wParam == SPI_SETMENUANIMATION) && _pDUIView)
  7936. {
  7937. _pDUIView->ManageAnimations(FALSE);
  7938. }
  7939. if (!wParam && !pszSection && _pDUIView)
  7940. {
  7941. if (_fBarrierDisplayed != _QueryBarricadeState())
  7942. {
  7943. _fBarrierDisplayed = !_fBarrierDisplayed;
  7944. _pDUIView->EnableBarrier (_fBarrierDisplayed);
  7945. }
  7946. }
  7947. if (_IsDesktop())
  7948. {
  7949. _OnWinIniChangeDesktop(wParam, pszSection);
  7950. }
  7951. }
  7952. void CDefView::_SetDefaultViewSettings()
  7953. {
  7954. // only do this if we've actually shown the view...
  7955. // (ie, there's no _hwndStatic)
  7956. // and we're not the desktop
  7957. // and we're not an exstended view
  7958. // and we are not in an explorer (tree pane on)
  7959. if (!_hwndStatic && !_IsDesktop() && !IsExplorerBrowser(_psb))
  7960. {
  7961. SHELLSTATE ss;
  7962. ss.lParamSort = (LONG)_vs._lParamSort;
  7963. ss.iSortDirection = _vs._iDirection;
  7964. SHGetSetSettings(&ss, SSF_SORTCOLUMNS, TRUE);
  7965. }
  7966. }
  7967. HWND CDefView::GetChildViewWindow()
  7968. {
  7969. if (_cFrame.IsWebView())
  7970. return _cFrame.GetExtendedViewWindow();
  7971. return _hwndListview;
  7972. }
  7973. void CDefView::_SetFocus()
  7974. {
  7975. // if it's a combined view then we need to give focus to listview
  7976. if (!_fCombinedView && _cFrame.IsWebView() && !_fActivateLV)
  7977. {
  7978. _OnViewWindowActive();
  7979. if (_cFrame._pOleObj)
  7980. {
  7981. MSG msg = {_hwndView, WM_KEYDOWN, VK_TAB, 0xf0001};
  7982. // HACKHACK!!! MUST set state here! idealy shbrowse should call
  7983. // UIActivate on the view but that breaks dochost stuff.
  7984. // if we did not set the state here, trident would call
  7985. // CSFVSite::ActivateMe that would not forward the call to obj::UIActivate
  7986. // and therefore nothing would get focus (actually trident would have it
  7987. // but it would not be visible). Note that this behavior happens only
  7988. // second time around, i.e. on init UIActivate is called and everything
  7989. // works fine, but if we tab from address bar onto the view, that's when
  7990. // the stuff gets broken.
  7991. OnActivate(SVUIA_ACTIVATE_FOCUS);
  7992. _cFrame._UIActivateIO(TRUE, &msg);
  7993. }
  7994. }
  7995. else
  7996. {
  7997. CallCB(SFVM_SETFOCUS, 0, 0);
  7998. if (_hwndListview)
  7999. SetFocus(_hwndListview);
  8000. if (!_IsDesktop())
  8001. {
  8002. _cFrame._uState = SVUIA_ACTIVATE_FOCUS;
  8003. }
  8004. }
  8005. }
  8006. LRESULT CALLBACK CDefView::s_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  8007. {
  8008. LRESULT lres = 0;
  8009. CDefView * pThis;
  8010. ULONG_PTR cookie = 0;
  8011. if (WM_NCCREATE == uMsg)
  8012. {
  8013. pThis = (CDefView*)((LPCREATESTRUCT)lParam)->lpCreateParams;
  8014. if (pThis)
  8015. {
  8016. pThis->AddRef();
  8017. SetWindowLongPtr(hWnd, 0, (LONG_PTR)pThis);
  8018. }
  8019. }
  8020. else
  8021. {
  8022. pThis = (CDefView*)GetWindowLongPtr(hWnd, 0);
  8023. }
  8024. // FUSION: When defview calls out to 3rd party code we want it to use
  8025. // the process default context. This means that the 3rd party code will get
  8026. // v5 in the explorer process. However, if shell32 is hosted in a v6 process,
  8027. // then the 3rd party code will still get v6.
  8028. // Future enhancements to this codepath may include using the fusion manifest
  8029. // tab <noinherit> which basically surplants the activat(null) in the following
  8030. // codepath. This disables the automatic activation from user32 for the duration
  8031. // of this wndproc, essentially doing this null push.
  8032. ActivateActCtx(NULL, &cookie);
  8033. if (pThis)
  8034. lres = pThis->WndProc(hWnd, uMsg, wParam, lParam);
  8035. else
  8036. lres = DefWindowProc(hWnd, uMsg, wParam, lParam);
  8037. if (cookie != 0)
  8038. DeactivateActCtx(0, cookie);
  8039. return lres;
  8040. }
  8041. BOOL CDefView::_OnAppCommand(UINT cmd, UINT uDevice, DWORD dwKeys)
  8042. {
  8043. BOOL bHandled = FALSE;
  8044. switch (cmd)
  8045. {
  8046. case APPCOMMAND_MEDIA_PLAY_PAUSE:
  8047. if (S_OK == _InvokeContextMenuVerbOnSelection("play", 0, 0))
  8048. bHandled = TRUE;
  8049. break;
  8050. }
  8051. return bHandled;
  8052. }
  8053. HRESULT CDefView::_ForwardMenuMessages(DWORD dwID, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plResult, BOOL* pfHandled)
  8054. {
  8055. if (InRange(dwID, SFVIDM_BACK_CONTEXT_FIRST, SFVIDM_BACK_CONTEXT_LAST))
  8056. {
  8057. if (pfHandled)
  8058. *pfHandled = TRUE;
  8059. return SHForwardContextMenuMsg(_pcmContextMenuPopup, uMsg, wParam, lParam, plResult, TRUE);
  8060. }
  8061. else if (InRange(dwID, SFVIDM_CONTEXT_FIRST, SFVIDM_CONTEXT_LAST))
  8062. {
  8063. if (pfHandled)
  8064. *pfHandled = TRUE;
  8065. return SHForwardContextMenuMsg(_pcmFile, uMsg, wParam, lParam, plResult, TRUE);
  8066. }
  8067. if (pfHandled)
  8068. *pfHandled = FALSE;
  8069. return E_FAIL;
  8070. }
  8071. LRESULT CDefView::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  8072. {
  8073. LRESULT l;
  8074. DWORD dwID;
  8075. switch (uMsg)
  8076. {
  8077. // IShellBrowser forwards these to the IShellView.
  8078. // Dochost also forwards them down to the IOleObject, so we should do it too...
  8079. case WM_SYSCOLORCHANGE:
  8080. {
  8081. HDITEM hdi = {HDI_FORMAT, 0, NULL, NULL, 0, 0, 0, 0, 0};
  8082. HWND hwndHead = ListView_GetHeader(_hwndListview);
  8083. // We only want to update the sort arrows if they are already present.
  8084. if (hwndHead)
  8085. {
  8086. Header_GetItem(hwndHead, _vs._lParamSort, &hdi);
  8087. if (hdi.fmt & HDF_BITMAP)
  8088. _SetSortFeedback();
  8089. }
  8090. // fall through
  8091. }
  8092. case WM_WININICHANGE:
  8093. _sizeThumbnail.cx = -1;
  8094. // fall through
  8095. case WM_ENTERSIZEMOVE:
  8096. case WM_EXITSIZEMOVE:
  8097. case WM_FONTCHANGE:
  8098. if (_cFrame.IsWebView())
  8099. {
  8100. HWND hwndExt = _cFrame.GetExtendedViewWindow();
  8101. if (hwndExt)
  8102. {
  8103. SendMessage(hwndExt, uMsg, wParam, lParam);
  8104. }
  8105. }
  8106. break;
  8107. }
  8108. switch (uMsg)
  8109. {
  8110. case WM_DESTROY:
  8111. if (GetKeyState(VK_CONTROL) < 0)
  8112. _SetDefaultViewSettings();
  8113. // Dont need our web view data any more
  8114. _FreeWebViewContentData();
  8115. // We don't flush these on WM_EXITMENULOOP any more, so do it here
  8116. IUnknown_SetSite(_pcmFile, NULL);
  8117. ATOMICRELEASE(_pcmFile);
  8118. EmptyBkgrndThread(_pScheduler);
  8119. ATOMICRELEASE(_pScheduler);
  8120. // do this after our task scheduler is gone, since one of it's
  8121. // items may be on the background task scheduler (or DUI may be
  8122. // talking to it on the background) and it may need it's site chain.
  8123. IUnknown_SetSite(_cCallback.GetSFVCB(), NULL);
  8124. if (_pDiskCache)
  8125. {
  8126. // at this point we assume that we have no lock,
  8127. _pDiskCache->Close(NULL);
  8128. ATOMICRELEASE(_pDiskCache);
  8129. }
  8130. // Depending on when it is closed we may have an outstanding post
  8131. // to us about the rest of the fill data which we should try to
  8132. // process in order to keep from leaking stuff...
  8133. // logically hWnd == _hwndView, but we already zeroed
  8134. // _hwndView so use hWnd
  8135. _ClearPostedMsgs(hWnd);
  8136. //
  8137. // remove ourself as a clipboard viewer
  8138. //
  8139. if (_bClipViewer)
  8140. {
  8141. ChangeClipboardChain(hWnd, _hwndNextViewer);
  8142. _bClipViewer = FALSE;
  8143. _hwndNextViewer = NULL;
  8144. }
  8145. if (_uRegister)
  8146. {
  8147. ULONG uRegister = _uRegister;
  8148. _uRegister = 0;
  8149. SHChangeNotifyDeregister(uRegister);
  8150. }
  8151. ATOMICRELEASE(_psd);
  8152. ATOMICRELEASE(_pdtgtBack);
  8153. if (_hwndListview)
  8154. {
  8155. if (_IsDesktop()) // only the desktop can have a combined view (e.g. Active Desktop)
  8156. {
  8157. EnableCombinedView(this, FALSE);
  8158. }
  8159. if (_bRegisteredDragDrop)
  8160. RevokeDragDrop(_hwndListview);
  8161. }
  8162. SetAutomationObject(NULL); // cleanup refs we may be holding
  8163. if (IsWindow(_hwndInfotip))
  8164. {
  8165. DestroyWindow(_hwndInfotip);
  8166. _hwndInfotip = NULL;
  8167. }
  8168. break;
  8169. case WM_CREATE:
  8170. return _OnCreate(hWnd);
  8171. case WM_DSV_DELAYED_DESTROYWND:
  8172. DestroyWindow(hWnd);
  8173. break;
  8174. case WM_NCDESTROY:
  8175. _hwndView = NULL;
  8176. SetWindowLongPtr(hWnd, 0, 0);
  8177. // get rid of extra junk in the icon cache
  8178. IconCacheFlush(FALSE);
  8179. if (_pDUIView)
  8180. {
  8181. //
  8182. // We must uninitialize DUser prior to releasing
  8183. // _pDUIView so that all DUser gadgets are properly destroyed.
  8184. // We used to call DirectUI::UnInitThread() in the CDUIView dtor.
  8185. // However, since both CDefView and the various 'task' DUI
  8186. // elements maintain a ref to CDUIView, we got into scenarios where
  8187. // one of the 'task' elements held the final ref to CDUIView. That
  8188. // resulted in the destruction of that 'task' element causing
  8189. // uninitialization of DUser in the middle of a DUser call stack.
  8190. // That's bad.
  8191. // Uninitializing DUser here causes DUser to handle all pending
  8192. // messages and destroy all it's gadgets on it's own terms.
  8193. //
  8194. _pDUIView->UnInitializeDirectUI();
  8195. _pDUIView->Release();
  8196. _pDUIView = NULL;
  8197. }
  8198. // release our reference generated during WM_NCCREATE in static wndproc
  8199. Release();
  8200. break;
  8201. case WM_ENABLE:
  8202. _fDisabled = !wParam;
  8203. break;
  8204. case WM_ERASEBKGND:
  8205. {
  8206. COLORREF cr = ListView_GetBkColor(_hwndListview);
  8207. if (cr == CLR_NONE)
  8208. return SendMessage(_hwndMain, uMsg, wParam, lParam);
  8209. //Turning On EraseBkgnd. This is required so as to avoid the
  8210. //painting issue - when the listview is not visible and
  8211. //invalidation occurs.
  8212. HBRUSH hbr = CreateSolidBrush(cr);
  8213. RECT rc;
  8214. GetClientRect(hWnd, &rc);
  8215. FillRect((HDC)wParam, &rc, hbr);
  8216. DeleteObject(hbr);
  8217. }
  8218. // We want to reduce flash
  8219. return 1;
  8220. case WM_PAINT:
  8221. if (_fEnumFailed)
  8222. _PaintErrMsg(hWnd);
  8223. else
  8224. goto DoDefWndProc;
  8225. break;
  8226. case WM_LBUTTONUP:
  8227. if (_fEnumFailed)
  8228. PostMessage(hWnd, WM_KEYDOWN, (WPARAM)VK_F5, 0);
  8229. else
  8230. goto DoDefWndProc;
  8231. break;
  8232. case WM_SETFOCUS:
  8233. if (!_fDestroying) // Ignore if we are destroying _hwndView.
  8234. {
  8235. _SetFocus();
  8236. }
  8237. break;
  8238. case WM_MOUSEACTIVATE:
  8239. //
  8240. // this keeps our window from coming to the front on button down
  8241. // instead, we activate the window on the up click
  8242. //
  8243. if (LOWORD(lParam) != HTCLIENT)
  8244. goto DoDefWndProc;
  8245. LV_HITTESTINFO lvhti;
  8246. GetCursorPos(&lvhti.pt);
  8247. ScreenToClient(_hwndListview, &lvhti.pt);
  8248. ListView_HitTest(_hwndListview, &lvhti);
  8249. if (lvhti.iItem != -1 && lvhti.flags & LVHT_ONITEM)
  8250. return MA_NOACTIVATE;
  8251. else
  8252. return MA_ACTIVATE;
  8253. case WM_ACTIVATE:
  8254. // force update on inactive to not ruin save bits
  8255. if (wParam == WA_INACTIVE)
  8256. UpdateWindow(_hwndListview);
  8257. // if active view created, call active object to allow it to visualize activation.
  8258. if (_cFrame._pActive)
  8259. _cFrame._pActive->OnFrameWindowActivate((BOOL)wParam);
  8260. break;
  8261. case WM_SIZE:
  8262. return WndSize(hWnd);
  8263. case WM_NOTIFY:
  8264. {
  8265. #ifdef DEBUG
  8266. // DefView_OnNotify sometimes destroys the pnm, so we need to save
  8267. // the code while we can. (E.g., common dialog single-click activate.
  8268. // LVN_ITEMACTIVATE causes us to dismiss the common dialog, which
  8269. // does a DestroyViewWindow, which destroys the ListView
  8270. // which destroys the NMHDR!)
  8271. UINT code = ((NMHDR *)lParam)->code;
  8272. #endif
  8273. AddRef(); // just in case
  8274. l = _OnNotify((NMHDR *)lParam);
  8275. Release(); // release
  8276. return l;
  8277. }
  8278. case WM_CONTEXTMENU:
  8279. if (!_fDisabled)
  8280. {
  8281. if (lParam != (LPARAM) -1)
  8282. {
  8283. _bMouseMenu = TRUE;
  8284. _ptDragAnchor.x = GET_X_LPARAM(lParam);
  8285. _ptDragAnchor.y = GET_Y_LPARAM(lParam);
  8286. LVUtil_ScreenToLV(_hwndListview, &_ptDragAnchor);
  8287. }
  8288. // Note: in deview inside a defview we can have problems of the
  8289. // parent destroying us when we change views, so we better addref/release
  8290. // around this...
  8291. AddRef();
  8292. _bContextMenuMode = TRUE;
  8293. ContextMenu((DWORD) lParam);
  8294. _bContextMenuMode = FALSE;
  8295. _bMouseMenu = FALSE;
  8296. Release();
  8297. }
  8298. break;
  8299. case WM_COMMAND:
  8300. return _OnCommand(NULL, wParam, lParam);
  8301. case WM_APPCOMMAND:
  8302. if (!_OnAppCommand(GET_APPCOMMAND_LPARAM(lParam), GET_DEVICE_LPARAM(lParam), GET_KEYSTATE_LPARAM(lParam)))
  8303. goto DoDefWndProc;
  8304. break;
  8305. case WM_DSV_DISABLEACTIVEDESKTOP:
  8306. DisableActiveDesktop();
  8307. break;
  8308. case WM_DSV_DELAYWINDOWCREATE:
  8309. CallCB(SFVM_DELAYWINDOWCREATE, (WPARAM)_hwndView, 0);
  8310. break;
  8311. case WM_DSV_BACKGROUNDENUMDONE:
  8312. // Make sure this notify is from our enumeration task (it could be from a previous one)
  8313. if ((CDefviewEnumTask *)lParam == _pEnumTask)
  8314. _OnBackgroundEnumDone();
  8315. break;
  8316. case WM_DSV_GROUPINGDONE:
  8317. _OnCategoryTaskDone();
  8318. break;
  8319. case WM_DSV_FILELISTENUMDONE:
  8320. _OnEnumDoneMessage();
  8321. break;
  8322. case WM_DSV_FILELISTFILLDONE:
  8323. _ShowSearchUI(FALSE);
  8324. break;
  8325. case WM_DSV_UPDATETHUMBNAIL:
  8326. {
  8327. DSV_UPDATETHUMBNAIL* putn = (DSV_UPDATETHUMBNAIL*)lParam;
  8328. if (_IsImageMode()) // some messages may come in after the view mode is changed.
  8329. {
  8330. _UpdateThumbnail(putn->iItem, putn->iImage, putn->pidl);
  8331. }
  8332. _CleanupUpdateThumbnail(putn);
  8333. }
  8334. break;
  8335. case WM_DSV_POSTCREATEINFOTIP:
  8336. _OnPostCreateInfotip((TOOLINFO *)wParam, lParam);
  8337. break;
  8338. case WM_DSV_FSNOTIFY:
  8339. {
  8340. LPITEMIDLIST *ppidl;
  8341. LONG lEvent;
  8342. LPSHChangeNotificationLock pshcnl = SHChangeNotification_Lock((HANDLE)wParam, (DWORD)lParam, &ppidl, &lEvent);
  8343. if (pshcnl)
  8344. {
  8345. if (_fDisabled ||
  8346. (CallCB(SFVM_FSNOTIFY, (WPARAM)ppidl, (LPARAM)lEvent) == S_FALSE))
  8347. {
  8348. lParam = 0;
  8349. }
  8350. else
  8351. {
  8352. lParam = _OnFSNotify(lEvent, (LPCITEMIDLIST*)ppidl);
  8353. }
  8354. SHChangeNotification_Unlock(pshcnl);
  8355. }
  8356. }
  8357. return lParam;
  8358. // the background thread's callback will post this message to us
  8359. // when it has finished extracting a icon in the background.
  8360. //
  8361. // wParam is PIDL
  8362. // lParam is iIconIndex
  8363. case WM_DSV_UPDATEICON:
  8364. _UpdateIcon((LPITEMIDLIST)wParam, (UINT)lParam);
  8365. break;
  8366. case WM_DSV_SETITEMGROUP:
  8367. _UpdateGroup((CBackgroundGroupInfo*)lParam);
  8368. break;
  8369. case WM_DSV_UPDATECOLDATA:
  8370. _UpdateColData((CBackgroundColInfo*)lParam);
  8371. break;
  8372. case WM_DSV_UPDATEOVERLAY:
  8373. _UpdateOverlay((int)wParam, (int)lParam);
  8374. break;
  8375. case WM_DSV_SETIMPORTANTCOLUMNS:
  8376. _SetImportantColumns((CBackgroundTileInfo*)lParam);
  8377. break;
  8378. case WM_DSV_SHOWDRAGIMAGE:
  8379. return DAD_ShowDragImage((BOOL)lParam);
  8380. case WM_DSV_DELAYSTATUSBARUPDATE:
  8381. {
  8382. HWND hwndStatus;
  8383. LPWSTR pszStatus = (LPWSTR)lParam;
  8384. if (_fBackgroundStatusTextValid)
  8385. {
  8386. _fBackgroundStatusTextValid = FALSE;
  8387. // Now prepare the text and post it to the status bar window.
  8388. _psb->GetControlWindow(FCW_STATUS, &hwndStatus);
  8389. if (hwndStatus)
  8390. {
  8391. SendMessage(hwndStatus, SB_SETTEXT, (WPARAM)0, (LPARAM)pszStatus);
  8392. }
  8393. }
  8394. LocalFree((void *)pszStatus);
  8395. }
  8396. break;
  8397. case WM_DSV_DELAYINFOTIP:
  8398. if ((CBackgroundInfoTip *)wParam == _pBackgroundInfoTip && _pBackgroundInfoTip->_fReady)
  8399. {
  8400. LRESULT lRet = SendMessage(_hwndListview, LVM_SETINFOTIP, NULL, (LPARAM)&_pBackgroundInfoTip->_lvSetInfoTip);
  8401. ATOMICRELEASE(_pBackgroundInfoTip);
  8402. return lRet;
  8403. }
  8404. break;
  8405. case WM_DSV_ENSURE_COLUMNS_LOADED:
  8406. if (!_fDestroying)
  8407. {
  8408. AddColumns();
  8409. return 1;
  8410. }
  8411. break;
  8412. case GET_WM_CTLCOLOR_MSG(CTLCOLOR_STATIC):
  8413. SetBkColor(GET_WM_CTLCOLOR_HDC(wParam, lParam, uMsg),
  8414. GetSysColor(COLOR_WINDOW));
  8415. return (LRESULT)GetSysColorBrush(COLOR_WINDOW);
  8416. case WM_DRAWCLIPBOARD:
  8417. if (_hwndNextViewer != NULL)
  8418. SendMessage(_hwndNextViewer, uMsg, wParam, lParam);
  8419. if (_bClipViewer)
  8420. return _OnClipboardChange();
  8421. break;
  8422. case WM_CHANGECBCHAIN:
  8423. if ((HWND)wParam == _hwndNextViewer)
  8424. {
  8425. _hwndNextViewer = (HWND)lParam;
  8426. return TRUE;
  8427. }
  8428. if (_hwndNextViewer != NULL)
  8429. return SendMessage(_hwndNextViewer, uMsg, wParam, lParam);
  8430. break;
  8431. case WM_WININICHANGE:
  8432. _OnWinIniChange(wParam, (LPCTSTR)lParam);
  8433. SendMessage(_hwndListview, uMsg, wParam, lParam);
  8434. break;
  8435. case WM_THEMECHANGED:
  8436. PostMessage(_hwndView, WM_COMMAND, (WPARAM)SFVIDM_MISC_REFRESH, 0);
  8437. break;
  8438. case WM_SHELLNOTIFY:
  8439. #define SHELLNOTIFY_SETDESKWALLPAPER 0x0004
  8440. if (wParam == SHELLNOTIFY_SETDESKWALLPAPER)
  8441. {
  8442. if (_IsDesktop())
  8443. {
  8444. _fHasDeskWallPaper = (lParam != 0);
  8445. _SetFolderColors();
  8446. }
  8447. }
  8448. break;
  8449. // What we would like out of these menu messages:
  8450. // WM_ENTERMENULOOP
  8451. // WM_INITMENUPOPUP
  8452. // for File.Edit.View...: handle ourselves (merge in _pcmFile etc) and forward to IShellFolderViewCB for init
  8453. // for submenus or context menus: forward to whatever IContextMenu owns the popup
  8454. // WM_INITMENUPOPUP for next menu, etc
  8455. // WM_EXITMENULOOP
  8456. // PostMessage(WM_DSV_MENUTERM)
  8457. // WM_COMMAND comes in, if a menu item was selected
  8458. // Forward to the correct object to handle
  8459. // WM_DSV_MENUTERM
  8460. // clean up File.Edit.View... (release _pcmFile etc), and forward to IShellFolderViewCB for cleanup
  8461. //
  8462. // From previous comments here, it sounds like we don't get proper WM_ENTERMENULOOP / WM_EXITMENULOOP.
  8463. // I suspect this is a behavior change since Win95. (This probably happened when we changed
  8464. // the browser's HMENU to our own custom menu bar implementation way back in IE4...)
  8465. //
  8466. // Previous code also posted WM_DSV_MENUTERM *twice* -- another relic from the Edit menu days...
  8467. //
  8468. // If we try to clean up on WM_EXITMENULOOP, then we'll free _pcmFile etc when
  8469. // the File menu closes. This caused us problems when we tried to merge _pcmFile
  8470. // into the Edit menu. (We should have used _pcmEdit and cleaned up on WM_UNINITMENUPOPUP.)
  8471. // This is no longer a problem for defview, but it is a problem for the IShellFolderViewCB
  8472. // which can merge into any of File.Edit.View... menus. (In fact, no code in the source tree
  8473. // does anything on SFVM_EXITMENULOOP.)
  8474. //
  8475. // We could free up _pcmFile early (when the File menu goes away) if we want,
  8476. // but there doesn't seem to be any harm in letting it sit around.
  8477. // So rip out this unused WM_EXITMENULOOP/WM_DSVMENUTERM/_OnMenuTermination code.
  8478. //
  8479. case WM_INITMENU:
  8480. _OnInitMenu();
  8481. break;
  8482. case WM_INITMENUPOPUP:
  8483. _OnInitMenuPopup((HMENU)wParam, LOWORD(lParam), HIWORD(lParam));
  8484. break;
  8485. case WM_TIMER:
  8486. KillTimer(hWnd, (UINT) wParam);
  8487. // Ignore if we're in the middle of destroying the window
  8488. if (_fDestroying)
  8489. break;
  8490. if (DV_IDTIMER_START_ANI == wParam)
  8491. {
  8492. if (_hwndStatic)
  8493. {
  8494. WCHAR szName[128];
  8495. HINSTANCE hinst;
  8496. if (S_OK != CallCB(SFVM_GETANIMATION, (WPARAM)&hinst, (LPARAM)szName))
  8497. {
  8498. hinst = g_hinst;
  8499. StrCpyW(szName, L"#150");
  8500. }
  8501. HWND hAnimate = ::GetWindow (_hwndStatic, GW_CHILD);
  8502. if (hAnimate)
  8503. {
  8504. // Animate_OpenEx() except we want the W version always
  8505. SendMessage(hAnimate, ACM_OPENW, (WPARAM)hinst, (LPARAM)szName);
  8506. }
  8507. }
  8508. }
  8509. else if (DV_IDTIMER_BUFFERED_REFRESH == wParam)
  8510. {
  8511. if (_fRefreshBuffered)
  8512. {
  8513. _fRefreshBuffered = FALSE;
  8514. PostMessage(_hwndView, WM_KEYDOWN, (WPARAM)VK_F5, 0);
  8515. TraceMsg(TF_DEFVIEW, "Buffered Refresh timer causes actual refresh");
  8516. }
  8517. }
  8518. else if (DV_IDTIMER_NOTIFY_AUTOMATION_SELCHANGE == wParam)
  8519. {
  8520. _OnDelayedSelectionChange();
  8521. }
  8522. else if (DV_IDTIMER_NOTIFY_AUTOMATION_CONTENTSCHANGED == wParam)
  8523. {
  8524. _OnDelayedContentsChanged();
  8525. }
  8526. else if (DV_IDTIMER_DISKCACHE == wParam)
  8527. {
  8528. DWORD dwMode;
  8529. if (_pDiskCache->GetMode(&dwMode) == S_OK && _pDiskCache->IsLocked() == S_FALSE)
  8530. {
  8531. // two seconds since last access, close the cache.
  8532. _pDiskCache->Close(NULL);
  8533. }
  8534. if (_GetBackgroundTaskCount(TOID_NULL) == 0)
  8535. {
  8536. // there is nothing in the queue pending, so quit listening...
  8537. KillTimer(hWnd, DV_IDTIMER_DISKCACHE);
  8538. }
  8539. break;
  8540. }
  8541. else if (DV_IDTIMER_SCROLL_TIMEOUT == wParam)
  8542. {
  8543. // Scroll timer expired.
  8544. TraceMsg(TF_DEFVIEW, "SCROLL TIMEOUT");
  8545. _fScrolling = FALSE;
  8546. // Now we send a paint to listview, so it will send us more requests for tileinformation
  8547. // that we ignored during scrolling.
  8548. if (_fRequestedTileDuringScroll)
  8549. {
  8550. InvalidateRect(_hwndListview, NULL, FALSE);
  8551. }
  8552. }
  8553. else
  8554. {
  8555. ASSERT(FALSE); // nobody is handling this timer id!
  8556. }
  8557. break;
  8558. case WM_SETCURSOR:
  8559. if (_hwndStatic)
  8560. {
  8561. SetCursor(LoadCursor(NULL, IDC_WAIT));
  8562. return TRUE;
  8563. }
  8564. goto DoDefWndProc;
  8565. case WM_DRAWITEM:
  8566. #define lpdis ((LPDRAWITEMSTRUCT)lParam)
  8567. dwID = lpdis->itemID;
  8568. if (lpdis->CtlType != ODT_MENU)
  8569. return 0;
  8570. if (InRange(lpdis->itemID, SFVIDM_CLIENT_FIRST, SFVIDM_CLIENT_LAST) && HasCB())
  8571. {
  8572. CallCB(SFVM_DRAWITEM, SFVIDM_CLIENT_FIRST, lParam);
  8573. return 1;
  8574. }
  8575. else
  8576. {
  8577. LRESULT lResult = 0;
  8578. _ForwardMenuMessages(dwID, uMsg, wParam, lParam, &lResult, NULL);
  8579. return lResult;
  8580. }
  8581. #undef lpdis
  8582. case WM_MEASUREITEM:
  8583. #define lpmis ((LPMEASUREITEMSTRUCT)lParam)
  8584. dwID = lpmis->itemID;
  8585. if (lpmis->CtlType != ODT_MENU)
  8586. return 0;
  8587. if (InRange(lpmis->itemID, SFVIDM_CLIENT_FIRST, SFVIDM_CLIENT_LAST) && HasCB())
  8588. {
  8589. CallCB(SFVM_MEASUREITEM, SFVIDM_CLIENT_FIRST, lParam);
  8590. return 1;
  8591. }
  8592. else
  8593. {
  8594. LRESULT lResult = 0;
  8595. _ForwardMenuMessages(dwID, uMsg, wParam, lParam, &lResult, NULL);
  8596. return lResult;
  8597. }
  8598. case WM_MENUCHAR:
  8599. if (_pcmFile)
  8600. {
  8601. LRESULT lResult;
  8602. HRESULT hr = SHForwardContextMenuMsg(_pcmFile, uMsg, wParam, lParam, &lResult, FALSE);
  8603. if (hr == S_OK)
  8604. return lResult;
  8605. }
  8606. if (_pcmContextMenuPopup)
  8607. {
  8608. LRESULT lResult;
  8609. HRESULT hr = SHForwardContextMenuMsg(_pcmContextMenuPopup, uMsg, wParam, lParam, &lResult, FALSE);
  8610. if (hr == S_OK)
  8611. return lResult;
  8612. }
  8613. return MAKELONG(0, MNC_IGNORE);
  8614. // there are two possible ways to put help texts in the
  8615. // status bar, (1) processing WM_MENUSELECT or (2) handling MenuHelp
  8616. // messages. (1) is compatible with OLE, but (2) is required anyway
  8617. // for tooltips.
  8618. //
  8619. case WM_MENUSELECT:
  8620. _OnMenuSelect(GET_WM_MENUSELECT_CMD(wParam, lParam), GET_WM_MENUSELECT_FLAGS(wParam, lParam), GET_WM_MENUSELECT_HMENU(wParam, lParam));
  8621. break;
  8622. case WM_SYSCOLORCHANGE:
  8623. _SetFolderColors();
  8624. SendMessage(_hwndListview, uMsg, wParam, lParam);
  8625. _rgbBackColor = CLR_INVALID;
  8626. break;
  8627. case SVM_SELECTITEM:
  8628. SelectItem((LPCITEMIDLIST)lParam, (int) wParam);
  8629. break;
  8630. case SVM_SELECTANDPOSITIONITEM:
  8631. {
  8632. SFM_SAP * psap = (SFM_SAP*)lParam;
  8633. for (UINT i = 0; i < wParam; psap++, i++)
  8634. SelectAndPositionItem(psap->pidl, psap->uSelectFlags, psap->fMove ? &psap->pt : NULL);
  8635. break;
  8636. }
  8637. case WM_PALETTECHANGED:
  8638. if (_IsImageMode())
  8639. {
  8640. InvalidateRect(_hwndListview, NULL, FALSE);
  8641. return TRUE;
  8642. }
  8643. // else Fall Through
  8644. case WM_QUERYNEWPALETTE:
  8645. if (_IsImageMode())
  8646. {
  8647. return FALSE; // Let Browser handle palette management
  8648. }
  8649. else
  8650. {
  8651. HWND hwndT = GetChildViewWindow();
  8652. if (!hwndT)
  8653. goto DoDefWndProc;
  8654. return SendMessage(hwndT, uMsg, wParam, lParam);
  8655. }
  8656. case WM_DSV_REARRANGELISTVIEW:
  8657. _ShowAndActivate();
  8658. break;
  8659. case WM_DSV_SENDSELECTIONCHANGED:
  8660. _OnSelectionChanged();
  8661. break;
  8662. case WM_DSV_SENDNOITEMSTATECHANGED:
  8663. _OnNoItemStateChanged();
  8664. break;
  8665. case WM_DSV_DESKHTML_CHANGES:
  8666. if (_IsDesktop())
  8667. {
  8668. IADesktopP2 *piadp2;
  8669. if (SUCCEEDED(SHCoCreateInstance(NULL, &CLSID_ActiveDesktop, NULL, IID_PPV_ARG(IADesktopP2, &piadp2))))
  8670. {
  8671. IActiveDesktopP *piadpp;
  8672. // 98/11/23 #254482 vtan: When making changes using dynamic
  8673. // HTML don't forget to update the "desktop.htt" file so
  8674. // that it's in sync with the registry BEFORE using DHTML.
  8675. if (SUCCEEDED(piadp2->QueryInterface(IID_PPV_ARG(IActiveDesktopP, &piadpp))))
  8676. {
  8677. piadpp->EnsureUpdateHTML(); // ignore result
  8678. piadpp->Release();
  8679. }
  8680. piadp2->MakeDynamicChanges(_cFrame._pOleObj);
  8681. piadp2->Release();
  8682. }
  8683. }
  8684. break;
  8685. // Toggling the New Start Menu on/off causes My Computer, etc.
  8686. // desktop icons to dynamically hide/show themselves.
  8687. case WM_DSV_STARTPAGE_TURNONOFF:
  8688. _ReloadContent(FALSE);
  8689. break;
  8690. case WM_DSV_ADJUSTRECYCLEBINPOSITION:
  8691. {
  8692. // We need to move the recycle bin to it's default position.
  8693. POINT ptRecycleBin;
  8694. int iIndexRecycleBin = _FreezeRecycleBin(&ptRecycleBin);
  8695. if (iIndexRecycleBin != LV_NOFROZENITEM)
  8696. _SetRecycleBinInDefaultPosition(&ptRecycleBin);
  8697. }
  8698. break;
  8699. default:
  8700. DoDefWndProc:
  8701. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  8702. }
  8703. return 0;
  8704. }
  8705. // don't test the result as this will fail on the second call
  8706. void CDefView::_RegisterWindow(void)
  8707. {
  8708. WNDCLASS wc = {0};
  8709. // don't want vredraw and hredraw because that causes horrible
  8710. // flicker expecially with full drag
  8711. wc.style = CS_PARENTDC;
  8712. wc.lpfnWndProc = CDefView::s_WndProc;
  8713. wc.cbWndExtra = sizeof(CDefView *);
  8714. wc.hInstance = HINST_THISDLL;
  8715. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  8716. wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  8717. wc.lpszClassName = TEXT("SHELLDLL_DefView");
  8718. RegisterClass(&wc);
  8719. }
  8720. CDefView::~CDefView()
  8721. {
  8722. _uState = SVUIA_DEACTIVATE;
  8723. // Sanity check.
  8724. ASSERT(_tlistPendingInfotips.GetHeadPosition() == NULL);
  8725. DebugMsg(TF_LIFE, TEXT("dtor CDefView %x"), this);
  8726. //
  8727. // Just in case, there is a left over.
  8728. //
  8729. _dvdt.LeaveAndReleaseData();
  8730. //
  8731. // We need to give it a chance to clean up.
  8732. //
  8733. CallCB(SFVM_PRERELEASE, 0, 0);
  8734. DestroyViewWindow();
  8735. ATOMICRELEASE(_pSelectionShellItemArray);
  8736. ATOMICRELEASE(_pFolderShellItemArray);
  8737. ATOMICRELEASE(_pScheduler);
  8738. //
  8739. // We should release _psb after _pshf (for docfindx)
  8740. //
  8741. ATOMICRELEASE(_pshf);
  8742. ATOMICRELEASE(_pshf2);
  8743. ATOMICRELEASE(_pshfParent);
  8744. ATOMICRELEASE(_pshf2Parent);
  8745. ILFree(_pidlRelative);
  8746. ATOMICRELEASE(_psi);
  8747. ATOMICRELEASE(_psio);
  8748. ATOMICRELEASE(_pcdb);
  8749. ATOMICRELEASE(_psb);
  8750. ATOMICRELEASE(_psd);
  8751. IUnknown_SetSite(_pcmFile, NULL);
  8752. ATOMICRELEASE(_pcmFile);
  8753. ATOMICRELEASE(_pcat);
  8754. ATOMICRELEASE(_pImageCache);
  8755. ATOMICRELEASE(_pDiskCache);
  8756. DSA_Destroy(_hdaCategories);
  8757. DSA_Destroy(_hdsaSCIDCache);
  8758. // NOTE we dont release psvOuter
  8759. // it has a ref on us
  8760. if (_pbtn)
  8761. LocalFree(_pbtn);
  8762. //
  8763. // Cleanup _dvdt
  8764. //
  8765. _dvdt.ReleaseDataObject();
  8766. _dvdt.ReleaseCurrentDropTarget();
  8767. _ClearPendingSelectedItems();
  8768. ATOMICRELEASE(_pauto);
  8769. ATOMICRELEASE(_padvise);
  8770. if (_hmenuCur)
  8771. {
  8772. DestroyMenu(_hmenuCur);
  8773. }
  8774. ATOMICRELEASE(_pBackgroundInfoTip);
  8775. ATOMICRELEASE(_ppui);
  8776. if (_pidlSelectAndPosition)
  8777. ILFree(_pidlSelectAndPosition);
  8778. Str_SetPtr(&_pszLegacyWatermark, NULL);
  8779. }
  8780. HRESULT CDefView::_AddTask(IRunnableTask *pTask, REFTASKOWNERID rTID, DWORD_PTR lParam, DWORD dwPriority, DWORD grfFlags)
  8781. {
  8782. HRESULT hr = E_FAIL;
  8783. if (_pScheduler)
  8784. {
  8785. if (grfFlags & ADDTASK_ONLYONCE)
  8786. {
  8787. hr = _pScheduler->MoveTask(rTID, lParam, dwPriority, (grfFlags & ADDTASK_ATFRONT ? ITSSFLAG_TASK_PLACEINFRONT : ITSSFLAG_TASK_PLACEINBACK));
  8788. }
  8789. if (hr != S_OK) // If we didn't move it, add it
  8790. {
  8791. hr = _pScheduler->AddTask2(pTask, rTID, lParam, dwPriority, (grfFlags & ADDTASK_ATFRONT ? ITSSFLAG_TASK_PLACEINFRONT : ITSSFLAG_TASK_PLACEINBACK));
  8792. }
  8793. }
  8794. return hr;
  8795. }
  8796. // Get the number of running tasks of the indicated task ID.
  8797. UINT CDefView::_GetBackgroundTaskCount(REFTASKOWNERID rtid)
  8798. {
  8799. return _pScheduler ? _pScheduler->CountTasks(rtid) : 0;
  8800. }
  8801. const TBBUTTON c_tbDefView[] = {
  8802. { VIEW_MOVETO | IN_VIEW_BMP, SFVIDM_EDIT_MOVETO, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1},
  8803. { VIEW_COPYTO | IN_VIEW_BMP, SFVIDM_EDIT_COPYTO, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1},
  8804. { STD_DELETE | IN_STD_BMP, SFVIDM_FILE_DELETE, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1},
  8805. { STD_UNDO | IN_STD_BMP, SFVIDM_EDIT_UNDO, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1},
  8806. { 0, 0, TBSTATE_ENABLED, BTNS_SEP, {0,0}, 0, -1 },
  8807. { VIEW_VIEWMENU | IN_VIEW_BMP, SFVIDM_VIEW_VIEWMENU, TBSTATE_ENABLED, BTNS_WHOLEDROPDOWN, {0,0}, 0, -1},
  8808. // hidden buttons (off by default, available only via customize dialog)
  8809. { STD_PROPERTIES | IN_STD_BMP, SFVIDM_FILE_PROPERTIES, TBSTATE_HIDDEN | TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1},
  8810. { STD_CUT | IN_STD_BMP, SFVIDM_EDIT_CUT, TBSTATE_HIDDEN | TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1},
  8811. { STD_COPY | IN_STD_BMP, SFVIDM_EDIT_COPY, TBSTATE_HIDDEN | TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1},
  8812. { STD_PASTE | IN_STD_BMP, SFVIDM_EDIT_PASTE, TBSTATE_HIDDEN | TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1},
  8813. { VIEW_OPTIONS | IN_VIEW_BMP, SFVIDM_TOOL_OPTIONS, TBSTATE_HIDDEN | TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1},
  8814. };
  8815. const TBBUTTON c_tbDefViewWebView[] = {
  8816. //{ 0, 0, TBSTATE_ENABLED, BTNS_SEP, {0,0}, 0, -1 },
  8817. { VIEW_VIEWMENU | IN_VIEW_BMP, SFVIDM_VIEW_VIEWMENU, TBSTATE_ENABLED, BTNS_WHOLEDROPDOWN, {0,0}, 0, -1},
  8818. // hidden buttons (off by default, available only via customize dialog)
  8819. { VIEW_MOVETO | IN_VIEW_BMP, SFVIDM_EDIT_MOVETO, TBSTATE_HIDDEN | TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1},
  8820. { VIEW_COPYTO | IN_VIEW_BMP, SFVIDM_EDIT_COPYTO, TBSTATE_HIDDEN | TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1},
  8821. { STD_DELETE | IN_STD_BMP, SFVIDM_FILE_DELETE, TBSTATE_HIDDEN | TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1},
  8822. { STD_UNDO | IN_STD_BMP, SFVIDM_EDIT_UNDO, TBSTATE_HIDDEN | TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1},
  8823. { STD_PROPERTIES | IN_STD_BMP, SFVIDM_FILE_PROPERTIES, TBSTATE_HIDDEN | TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1},
  8824. { STD_CUT | IN_STD_BMP, SFVIDM_EDIT_CUT, TBSTATE_HIDDEN | TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1},
  8825. { STD_COPY | IN_STD_BMP, SFVIDM_EDIT_COPY, TBSTATE_HIDDEN | TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1},
  8826. { STD_PASTE | IN_STD_BMP, SFVIDM_EDIT_PASTE, TBSTATE_HIDDEN | TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1},
  8827. { VIEW_OPTIONS | IN_VIEW_BMP, SFVIDM_TOOL_OPTIONS, TBSTATE_HIDDEN | TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1},
  8828. };
  8829. // win95 defview toolbar, used for corel apphack
  8830. const TBBUTTON c_tbDefView95[] = {
  8831. { STD_CUT | IN_STD_BMP, SFVIDM_EDIT_CUT, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1},
  8832. { STD_COPY | IN_STD_BMP, SFVIDM_EDIT_COPY, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1},
  8833. { STD_PASTE | IN_STD_BMP, SFVIDM_EDIT_PASTE, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1},
  8834. { 0, 0, TBSTATE_ENABLED, BTNS_SEP, {0,0}, 0, -1 },
  8835. { STD_UNDO | IN_STD_BMP, SFVIDM_EDIT_UNDO, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1},
  8836. { 0, 0, TBSTATE_ENABLED, BTNS_SEP, {0,0}, 0, -1 },
  8837. { STD_DELETE | IN_STD_BMP, SFVIDM_FILE_DELETE, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1},
  8838. { STD_PROPERTIES | IN_STD_BMP, SFVIDM_FILE_PROPERTIES, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1},
  8839. { 0, 0, TBSTATE_ENABLED, BTNS_SEP, {0,0}, 0, -1 },
  8840. // the bitmap indexes here are relative to the view bitmap
  8841. { VIEW_LARGEICONS | IN_VIEW_BMP, SFVIDM_VIEW_ICON, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1 },
  8842. { VIEW_SMALLICONS | IN_VIEW_BMP, SFVIDM_VIEW_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1 },
  8843. { VIEW_LIST | IN_VIEW_BMP, SFVIDM_VIEW_LIST, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1 },
  8844. { VIEW_DETAILS | IN_VIEW_BMP, SFVIDM_VIEW_DETAILS, TBSTATE_ENABLED, BTNS_BUTTON, {0,0}, 0, -1 },
  8845. };
  8846. LRESULT CDefView::_TBNotify(NMHDR *pnm)
  8847. {
  8848. LPTBNOTIFY ptbn = (LPTBNOTIFY)pnm;
  8849. switch (pnm->code)
  8850. {
  8851. case TBN_BEGINDRAG:
  8852. _OnMenuSelect(ptbn->iItem, 0, 0);
  8853. break;
  8854. }
  8855. return 0;
  8856. }
  8857. BOOL CDefView::_MergeIExplorerToolbar(UINT cExtButtons)
  8858. {
  8859. BOOL fRet = FALSE;
  8860. IExplorerToolbar *piet;
  8861. if (SUCCEEDED(IUnknown_QueryService(_psb, SID_SExplorerToolbar, IID_PPV_ARG(IExplorerToolbar, &piet))))
  8862. {
  8863. BOOL fGotClsid = TRUE;
  8864. DWORD dwFlags = 0;
  8865. if (cExtButtons == 0)
  8866. {
  8867. // This shf has no buttons to merge in; use the standard defview
  8868. // clsid so that the shf shares standard toolbar customization.
  8869. _clsid = CGID_DefViewFrame;
  8870. }
  8871. else if (SUCCEEDED(IUnknown_GetClassID(_pshf, &_clsid)))
  8872. {
  8873. // This shf has buttons to merge in; use its clsid
  8874. // so that this shf gets separate customization persistence.
  8875. // The shf might expect us to provide room for two lines of
  8876. // text (since that was the default in IE4).
  8877. dwFlags |= VBF_TWOLINESTEXT;
  8878. }
  8879. else
  8880. {
  8881. // This shf has buttons to merge in but doesn't implement
  8882. // IPersist::GetClassID; so we can't use IExplorerToolbar mechanism.
  8883. fGotClsid = FALSE;
  8884. }
  8885. if (fGotClsid)
  8886. {
  8887. HRESULT hr = piet->SetCommandTarget((IUnknown *)SAFECAST(this, IOleCommandTarget *), &_clsid, dwFlags);
  8888. if (SUCCEEDED(hr))
  8889. {
  8890. // If hr == S_FALSE, another defview merged in its buttons under the
  8891. // same clsid, and they're still there. So no need to call AddButtons.
  8892. if (hr != S_FALSE)
  8893. hr = piet->AddButtons(&_clsid, _cButtons, _pbtn);
  8894. if (SUCCEEDED(hr))
  8895. {
  8896. fRet = TRUE;
  8897. }
  8898. }
  8899. }
  8900. piet->Release();
  8901. }
  8902. return fRet;
  8903. }
  8904. int _FirstHiddenButton(TBBUTTON* ptbn, int cButtons)
  8905. {
  8906. for (int i = 0; i < cButtons; i++)
  8907. {
  8908. if (ptbn[i].fsState & TBSTATE_HIDDEN)
  8909. break;
  8910. }
  8911. return i;
  8912. }
  8913. void CDefView::_CopyDefViewButton(PTBBUTTON ptbbDest, PTBBUTTON ptbbSrc)
  8914. {
  8915. *ptbbDest = *ptbbSrc;
  8916. if (!(ptbbDest->fsStyle & BTNS_SEP))
  8917. {
  8918. // Fix up bitmap offset depending on whether this is a "view" bitmap or a "standard" bitmap
  8919. if (ptbbDest->iBitmap & IN_VIEW_BMP)
  8920. ptbbDest->iBitmap = (int)((ptbbDest->iBitmap & ~PRIVATE_TB_FLAGS) + _iViewBMOffset);
  8921. else
  8922. ptbbDest->iBitmap = (int)(ptbbDest->iBitmap + _iStdBMOffset);
  8923. }
  8924. }
  8925. //
  8926. // Here's the deal with _GetButtons
  8927. //
  8928. // DefView has some buttons, and its callback client may have some buttons.
  8929. //
  8930. // Some of defview's buttons are visible on the toolbar by default, and some only show
  8931. // up if you customize the toolbar.
  8932. //
  8933. // We specify which buttons are hidden by default by marking them with TBSTATE_HIDDEN in
  8934. // the declaration of c_tbDefView. We assume all such buttons are in a continuous block at
  8935. // the end of c_tbDefView.
  8936. //
  8937. // We return in ppbtn a pointer to an array of all the buttons, including those not shown
  8938. // by default. We put the buttons not shown by default at the end of this array. We pass
  8939. // back in pcButtons the count of visible buttons, and in pcTotalButtons the count of visible
  8940. // and hidden buttons.
  8941. //
  8942. // The int return value is the number of client buttons in the array.
  8943. //
  8944. int CDefView::_GetButtons(PTBBUTTON* ppbtn, LPINT pcButtons, LPINT pcTotalButtons)
  8945. {
  8946. int cVisibleBtns = 0; // count of visible defview + client buttons
  8947. TBINFO tbinfo;
  8948. tbinfo.uFlags = TBIF_APPEND;
  8949. tbinfo.cbuttons = 0;
  8950. // Does the client want to prepend/append a toolbar?
  8951. CallCB(SFVM_GETBUTTONINFO, 0, (LPARAM)&tbinfo);
  8952. _uDefToolbar = HIWORD(tbinfo.uFlags);
  8953. tbinfo.uFlags &= 0xffff;
  8954. // tbDefView needs to be big enough to hold either c_tbDefView or c_tbDefView95
  8955. COMPILETIME_ASSERT(ARRAYSIZE(c_tbDefView95) >= ARRAYSIZE(c_tbDefView));
  8956. TBBUTTON tbDefView[ARRAYSIZE(c_tbDefView95)];
  8957. int cDefViewBtns; // total count of defview buttons
  8958. if (SHGetAppCompatFlags(ACF_WIN95DEFVIEW) & ACF_WIN95DEFVIEW)
  8959. {
  8960. memcpy(tbDefView, c_tbDefView95, sizeof(TBBUTTON) * ARRAYSIZE(c_tbDefView95));
  8961. cDefViewBtns = ARRAYSIZE(c_tbDefView95);
  8962. }
  8963. else if (_cFrame.IsWebView() || _pDUIView)
  8964. {
  8965. memcpy(tbDefView, c_tbDefViewWebView, sizeof(TBBUTTON) * ARRAYSIZE(c_tbDefViewWebView));
  8966. cDefViewBtns = ARRAYSIZE(c_tbDefViewWebView);
  8967. }
  8968. else
  8969. {
  8970. memcpy(tbDefView, c_tbDefView, sizeof(TBBUTTON) * ARRAYSIZE(c_tbDefView));
  8971. cDefViewBtns = ARRAYSIZE(c_tbDefView);
  8972. }
  8973. int cVisibleDefViewBtns = _FirstHiddenButton(tbDefView, cDefViewBtns); // count of visible defview buttons
  8974. TBBUTTON *pbtn = (TBBUTTON *)LocalAlloc(LPTR, (cDefViewBtns + tbinfo.cbuttons) * sizeof(*pbtn));
  8975. if (pbtn)
  8976. {
  8977. int iStart = 0;
  8978. cVisibleBtns = tbinfo.cbuttons + cVisibleDefViewBtns;
  8979. // Have the client fill in its buttons
  8980. switch (tbinfo.uFlags)
  8981. {
  8982. case TBIF_PREPEND:
  8983. CallCB(SFVM_GETBUTTONS,
  8984. MAKEWPARAM(SFVIDM_CLIENT_FIRST, tbinfo.cbuttons),
  8985. (LPARAM)pbtn);
  8986. iStart = tbinfo.cbuttons;
  8987. break;
  8988. case TBIF_APPEND:
  8989. CallCB(SFVM_GETBUTTONS,
  8990. MAKEWPARAM(SFVIDM_CLIENT_FIRST, tbinfo.cbuttons),
  8991. (LPARAM)&pbtn[cVisibleDefViewBtns]);
  8992. iStart = 0;
  8993. break;
  8994. case TBIF_REPLACE:
  8995. CallCB(SFVM_GETBUTTONS,
  8996. MAKEWPARAM(SFVIDM_CLIENT_FIRST, tbinfo.cbuttons),
  8997. (LPARAM)pbtn);
  8998. cVisibleBtns = tbinfo.cbuttons;
  8999. cVisibleDefViewBtns = 0;
  9000. break;
  9001. default:
  9002. RIPMSG(0, "View callback passed an invalid TBINFO flag");
  9003. break;
  9004. }
  9005. // Fill in visible defview buttons
  9006. for (int i = 0; i < cVisibleDefViewBtns; i++)
  9007. {
  9008. // Visible defview button block gets added at iStart
  9009. _CopyDefViewButton(&pbtn[i + iStart], &tbDefView[i]);
  9010. }
  9011. // Fill in hidden defview buttons
  9012. for (i = cVisibleDefViewBtns; i < cDefViewBtns; i++)
  9013. {
  9014. // Hidden defview button block gets added after visible & client buttons
  9015. _CopyDefViewButton(&pbtn[i + tbinfo.cbuttons], &tbDefView[i]);
  9016. // If this rips a visible button got mixed in with the hidden block
  9017. ASSERT(pbtn[i + tbinfo.cbuttons].fsState & TBSTATE_HIDDEN);
  9018. // Rip off the hidden bit
  9019. pbtn[i + tbinfo.cbuttons].fsState &= ~TBSTATE_HIDDEN;
  9020. }
  9021. }
  9022. ASSERT(ppbtn);
  9023. ASSERT(pcButtons);
  9024. ASSERT(pcTotalButtons);
  9025. *ppbtn = pbtn;
  9026. *pcButtons = cVisibleBtns;
  9027. *pcTotalButtons = tbinfo.cbuttons + cDefViewBtns;
  9028. return tbinfo.cbuttons;
  9029. }
  9030. void CDefView::MergeToolBar(BOOL bCanRestore)
  9031. {
  9032. TBADDBITMAP ab;
  9033. ab.hInst = HINST_COMMCTRL; // hinstCommctrl
  9034. ab.nID = IDB_STD_SMALL_COLOR; // std bitmaps
  9035. _psb->SendControlMsg(FCW_TOOLBAR, TB_ADDBITMAP, 8, (LPARAM)&ab, &_iStdBMOffset);
  9036. ab.nID = IDB_VIEW_SMALL_COLOR; // std view bitmaps
  9037. _psb->SendControlMsg(FCW_TOOLBAR, TB_ADDBITMAP, 8, (LPARAM)&ab, &_iViewBMOffset);
  9038. if (_pbtn)
  9039. LocalFree(_pbtn);
  9040. int cExtButtons = _GetButtons(&_pbtn, &_cButtons, &_cTotalButtons);
  9041. if (_pbtn && !_MergeIExplorerToolbar(cExtButtons))
  9042. {
  9043. // if we're able to do the new IExplorerToolbar merge method, great...
  9044. // if not, we use the old style
  9045. _psb->SetToolbarItems(_pbtn, _cButtons, FCT_MERGE);
  9046. CDefView::CheckToolbar();
  9047. }
  9048. }
  9049. STDMETHODIMP CDefView::GetWindow(HWND *phwnd)
  9050. {
  9051. *phwnd = _hwndView;
  9052. return S_OK;
  9053. }
  9054. STDMETHODIMP CDefView::ContextSensitiveHelp(BOOL fEnterMode)
  9055. {
  9056. return E_NOTIMPL;
  9057. }
  9058. STDMETHODIMP CDefView::EnableModeless(BOOL fEnable)
  9059. {
  9060. // We have no modeless window to be enabled/disabled
  9061. return S_OK;
  9062. }
  9063. HRESULT CDefView::_ReloadListviewContent()
  9064. {
  9065. // HACK: We always call IsShared with fUpdateCache=FALSE for performance.
  9066. // However, we need to update the cache when the user explicitly tell
  9067. // us to "Refresh". This is not the ideal place to put this code, but
  9068. // we have no other choice.
  9069. TCHAR szPathAny[MAX_PATH];
  9070. _UpdateSelectionMode();
  9071. // finish any pending edits
  9072. SendMessage(_hwndListview, LVM_EDITLABEL, (WPARAM)-1, 0);
  9073. GetWindowsDirectory(szPathAny, ARRAYSIZE(szPathAny));
  9074. IsShared(szPathAny, TRUE);
  9075. // HACK: strange way to notify folder that we're refreshing
  9076. ULONG rgf = SFGAO_VALIDATE;
  9077. _pshf->GetAttributesOf(0, NULL, &rgf);
  9078. //
  9079. // if a item is selected, make sure it gets nuked from the icon
  9080. // cache, this is a last resort type thing, select a item and
  9081. // hit F5 to fix all your problems.
  9082. //
  9083. int iItem = ListView_GetNextItem(_hwndListview, -1, LVNI_SELECTED);
  9084. if (iItem != -1)
  9085. CFSFolder_UpdateIcon(_pshf, _GetPIDL(iItem));
  9086. // We should not save the selection if doing refresh.
  9087. _ClearPendingSelectedItems();
  9088. // 01/05/21 #399284: Don't save/restore the state and nuke objects if there's a background process using them
  9089. if(!_bBkFilling)
  9090. {
  9091. // First we have to save all the icon positions, so they will be restored
  9092. // properly during the FillObjectsShowHide
  9093. SaveViewState();
  9094. // 99/04/07 #309965 vtan: Persist the view state (above). Make sure
  9095. // our internal representation is the same as the one on the disk
  9096. // by dumping our cache and reloading the information.
  9097. GetViewState();
  9098. // To make it look like the refesh is doing something, clear
  9099. // all the icons from the view before we start enumerating.
  9100. _RemoveObject(NULL, FALSE);
  9101. _fSyncOnFillDone = TRUE; // apply the just-saved view state when we finish enumeration
  9102. }
  9103. return FillObjectsShowHide(TRUE);
  9104. }
  9105. HRESULT CDefView::_ReloadContent(BOOL fForce)
  9106. {
  9107. if (_bReEntrantReload)
  9108. {
  9109. return S_FALSE;
  9110. }
  9111. _bReEntrantReload = TRUE;
  9112. HRESULT hrExtView = S_OK;
  9113. HRESULT hrNormalView = S_OK;
  9114. SHELLSTATE ss;
  9115. // Tell the defview client that this window is about to be refreshed
  9116. _CallRefresh(TRUE);
  9117. // make sure that the CommandIds and the Uids match by recreating the menus
  9118. RecreateMenus();
  9119. // If the global SSF_WIN95CLASSIC state changed, we need to muck with the UI.
  9120. SHGetSetSettings(&ss, SSF_WIN95CLASSIC, FALSE);
  9121. // Show webview and pane again if we are forced OR the view has changed.
  9122. if (fForce || (BOOLIFY(ss.fWin95Classic) != BOOLIFY(_fClassic)))
  9123. {
  9124. _fClassic = ss.fWin95Classic;
  9125. _UpdateListviewColors();
  9126. }
  9127. if (_ShouldShowWebView())
  9128. {
  9129. // We need to save the icon positions before we refresh the view.
  9130. SaveViewState();
  9131. if (_pDUIView)
  9132. {
  9133. hrExtView = _pDUIView->Refresh();
  9134. }
  9135. else
  9136. {
  9137. _TryShowWebView(_fs.ViewMode, _fs.ViewMode);
  9138. }
  9139. }
  9140. else
  9141. {
  9142. _TryHideWebView(); // make sure it's off
  9143. }
  9144. // We want to preserve the earlier error if any
  9145. hrNormalView = _ReloadListviewContent();
  9146. _bReEntrantReload = FALSE;
  9147. return FAILED(hrExtView) ? hrExtView : hrNormalView;
  9148. }
  9149. STDMETHODIMP CDefView::Refresh()
  9150. {
  9151. // See if some refreshes were buffered
  9152. if (_fRefreshBuffered)
  9153. {
  9154. //Since we are refreshing it right now. Kill the timer.
  9155. TraceMsg(TF_DEFVIEW, "Buffered Refresh Timer Killed by regular Refresh");
  9156. KillTimer(_hwndView, DV_IDTIMER_BUFFERED_REFRESH);
  9157. _fRefreshBuffered = FALSE;
  9158. }
  9159. // If desktop is in modal state, do not attempt to refresh.
  9160. // If we do, we endup destroying Trident object when it is in modal state.
  9161. if (_IsDesktop() && _fDesktopModal)
  9162. {
  9163. // Remember that we could not refresh the desktop because it was in
  9164. // a modal state.
  9165. _fDesktopRefreshPending = TRUE;
  9166. return S_OK;
  9167. }
  9168. // make sure we have the latest
  9169. SHRefreshSettings();
  9170. _UpdateRegFlags();
  9171. if (_IsDesktop())
  9172. {
  9173. SHELLSTATE ss = {0};
  9174. SHGetSetSettings(&ss, SSF_DESKTOPHTML, FALSE);
  9175. // The following code is not needed because _ReloadContent() takes care of switching to
  9176. // web-view.
  9177. // _SwitchDesktopHTML(BOOLIFY(ss.fDesktopHTML));
  9178. if (ss.fDesktopHTML)
  9179. {
  9180. // For backward compatibility, hide the desktop channel bar.
  9181. HideIE4DesktopChannelBar();
  9182. // ActiveDesktop is not part of shdocvw's browser session count
  9183. // so when we refresh, we must tell wininet to reset the session
  9184. // count otherwise we will not hit the net.
  9185. MyInternetSetOption(NULL, INTERNET_OPTION_RESET_URLCACHE_SESSION, NULL, 0);
  9186. }
  9187. }
  9188. return _ReloadContent(TRUE);
  9189. }
  9190. STDMETHODIMP CDefView::CreateViewWindow(IShellView *psvPrevious,
  9191. LPCFOLDERSETTINGS pfs, IShellBrowser *psb, RECT *prc, HWND *phWnd)
  9192. {
  9193. SV2CVW2_PARAMS cParams = {0};
  9194. cParams.cbSize = sizeof(SV2CVW2_PARAMS);
  9195. cParams.psvPrev = psvPrevious;
  9196. cParams.pfs = pfs;
  9197. cParams.psbOwner = psb;
  9198. cParams.prcView = prc;
  9199. HRESULT hr = CreateViewWindow2(&cParams);
  9200. *phWnd = cParams.hwndView;
  9201. if (SUCCEEDED(hr) &&
  9202. (SHGetAppCompatFlags(ACF_OLDCREATEVIEWWND) & ACF_OLDCREATEVIEWWND))
  9203. {
  9204. //
  9205. // CreateViewWindow was documented as returning S_OK on success,
  9206. // but IE4 changed the function to return S_FALSE if the defview
  9207. // was created async.
  9208. //
  9209. // PowerDesk relies on the old behavior.
  9210. // So does Quattro Pro.
  9211. //
  9212. hr = S_OK;
  9213. }
  9214. return hr;
  9215. }
  9216. STDMETHODIMP CDefView::HandleRename(LPCITEMIDLIST pidl)
  9217. {
  9218. HRESULT hr = E_FAIL;
  9219. // Gross, but if no PIDL passed in use the GetObject(-2) hack to get the selected object...
  9220. // Don't need to free as it wsa not cloned...
  9221. if (!pidl)
  9222. {
  9223. GetObject((LPITEMIDLIST*)&pidl, (UINT)-2);
  9224. }
  9225. else
  9226. {
  9227. RIP(ILFindLastID(pidl) == pidl);
  9228. if (ILFindLastID(pidl) != pidl)
  9229. {
  9230. return E_INVALIDARG;
  9231. }
  9232. }
  9233. hr = SelectAndPositionItem(pidl, SVSI_SELECT, NULL);
  9234. if (SUCCEEDED(hr))
  9235. hr = SelectAndPositionItem(pidl, SVSI_EDIT, NULL);
  9236. return hr;
  9237. }
  9238. // IViewObject
  9239. HRESULT CDefView::GetColorSet(DWORD dwAspect, LONG lindex, void *pvAspect,
  9240. DVTARGETDEVICE *ptd, HDC hicTargetDev, LOGPALETTE **ppColorSet)
  9241. {
  9242. if (_cFrame.IsWebView() && _cFrame._pvoActive)
  9243. {
  9244. return _cFrame._pvoActive->GetColorSet(dwAspect, lindex, pvAspect,
  9245. ptd, hicTargetDev, ppColorSet);
  9246. }
  9247. if (ppColorSet)
  9248. *ppColorSet = NULL;
  9249. return E_FAIL;
  9250. }
  9251. HRESULT CDefView::Freeze(DWORD, LONG, void *, DWORD *pdwFreeze)
  9252. {
  9253. return E_NOTIMPL;
  9254. }
  9255. HRESULT CDefView::Unfreeze(DWORD)
  9256. {
  9257. return E_NOTIMPL;
  9258. }
  9259. HRESULT CDefView::SetAdvise(DWORD dwAspect, DWORD advf, IAdviseSink *pSink)
  9260. {
  9261. if (dwAspect != DVASPECT_CONTENT)
  9262. return DV_E_DVASPECT;
  9263. if (advf & ~(ADVF_PRIMEFIRST | ADVF_ONLYONCE))
  9264. return E_INVALIDARG;
  9265. if (pSink != _padvise)
  9266. {
  9267. ATOMICRELEASE(_padvise);
  9268. _padvise = pSink;
  9269. if (_padvise)
  9270. _padvise->AddRef();
  9271. }
  9272. if (_padvise)
  9273. {
  9274. _advise_aspect = dwAspect;
  9275. _advise_advf = advf;
  9276. if (advf & ADVF_PRIMEFIRST)
  9277. PropagateOnViewChange(dwAspect, -1);
  9278. }
  9279. else
  9280. _advise_aspect = _advise_advf = 0;
  9281. return S_OK;
  9282. }
  9283. HRESULT CDefView::GetAdvise(DWORD *pdwAspect, DWORD *padvf,
  9284. IAdviseSink **ppSink)
  9285. {
  9286. if (pdwAspect)
  9287. *pdwAspect = _advise_aspect;
  9288. if (padvf)
  9289. *padvf = _advise_advf;
  9290. if (ppSink)
  9291. {
  9292. if (_padvise)
  9293. _padvise->AddRef();
  9294. *ppSink = _padvise;
  9295. }
  9296. return S_OK;
  9297. }
  9298. HRESULT CDefView::Draw(DWORD, LONG, void *, DVTARGETDEVICE *, HDC, HDC,
  9299. const RECTL *, const RECTL *, BOOL (*)(ULONG_PTR), ULONG_PTR)
  9300. {
  9301. return E_NOTIMPL;
  9302. }
  9303. void CDefView::PropagateOnViewChange(DWORD dwAspect, LONG lindex)
  9304. {
  9305. dwAspect &= _advise_aspect;
  9306. if (dwAspect && _padvise)
  9307. {
  9308. IAdviseSink *pSink = _padvise;
  9309. IUnknown *punkRelease;
  9310. if (_advise_advf & ADVF_ONLYONCE)
  9311. {
  9312. punkRelease = pSink;
  9313. _padvise = NULL;
  9314. _advise_aspect = _advise_advf = 0;
  9315. }
  9316. else
  9317. punkRelease = NULL;
  9318. pSink->OnViewChange(dwAspect, lindex);
  9319. ATOMICRELEASE(punkRelease);
  9320. }
  9321. }
  9322. void CDefView::PropagateOnClose()
  9323. {
  9324. //
  9325. // we aren't closing ourselves, just somebody under us...
  9326. // ...reflect this up the chain as a view change.
  9327. //
  9328. if (_padvise)
  9329. PropagateOnViewChange(_advise_aspect, -1);
  9330. }
  9331. UINT CDefView::_ValidateViewMode(UINT uViewMode)
  9332. {
  9333. UINT uViewModeDefault = FVM_ICON;
  9334. if (uViewMode >= FVM_FIRST && uViewMode <= FVM_LAST)
  9335. {
  9336. uViewModeDefault = uViewMode;
  9337. #ifdef DEBUG
  9338. if (!_ViewSupported(uViewMode))
  9339. {
  9340. // Whoa! the default is excluded? Ignore it.
  9341. TraceMsg(TF_WARNING, "Bug in IShellFolderViewCB client: returned a default viewmode that is excluded");
  9342. }
  9343. #endif
  9344. }
  9345. else
  9346. {
  9347. TraceMsg(TF_WARNING, "Bug in IShellFolderViewCB client: returned invalid viewmode");
  9348. }
  9349. return uViewModeDefault;
  9350. }
  9351. UINT CDefView::_GetDefaultViewMode()
  9352. {
  9353. UINT uViewMode = FVM_ICON;
  9354. CallCB(SFVM_DEFVIEWMODE, 0, (LPARAM)&uViewMode);
  9355. return _ValidateViewMode(uViewMode);
  9356. }
  9357. void CDefView::_GetDeferredViewSettings(UINT* puViewMode)
  9358. {
  9359. SFVM_DEFERRED_VIEW_SETTINGS sdvsSettings;
  9360. ZeroMemory(&sdvsSettings, sizeof(sdvsSettings));
  9361. if (SUCCEEDED(CallCB(SFVM_GETDEFERREDVIEWSETTINGS, 0, (LPARAM)&sdvsSettings)))
  9362. {
  9363. _vs._lParamSort = sdvsSettings.uSortCol;
  9364. _vs._iDirection = sdvsSettings.iSortDirection >= 0 ? 1 : -1;
  9365. *puViewMode = _ValidateViewMode(sdvsSettings.fvm);
  9366. _fs.fFlags = (_fs.fFlags & ~FWF_AUTOARRANGE) | (sdvsSettings.fFlags & FWF_AUTOARRANGE);
  9367. SHSetWindowBits(_hwndListview, GWL_STYLE, LVS_AUTOARRANGE, _IsAutoArrange() ? LVS_AUTOARRANGE : 0);
  9368. if (sdvsSettings.fGroupView && (*puViewMode != FVM_THUMBSTRIP))
  9369. {
  9370. SHCOLUMNID scid;
  9371. if SUCCEEDED(_pshf2->MapColumnToSCID(sdvsSettings.uSortCol, &scid))
  9372. {
  9373. _CategorizeOnGUID(&CLSID_DetailCategorizer, &scid);
  9374. }
  9375. }
  9376. }
  9377. else
  9378. {
  9379. *puViewMode = _GetDefaultViewMode();
  9380. }
  9381. }
  9382. BOOL CDefView::_ViewSupported(UINT uView)
  9383. {
  9384. SFVM_VIEW_DATA vi;
  9385. _GetSFVMViewState(uView, &vi);
  9386. BOOL fIncludeView;
  9387. if (vi.dwOptions == SFVMQVI_INCLUDE)
  9388. fIncludeView = TRUE;
  9389. else if (vi.dwOptions == SFVMQVI_EXCLUDE)
  9390. fIncludeView = FALSE;
  9391. else
  9392. fIncludeView = uView != FVM_THUMBSTRIP; // by default, everything is included except FVM_THUMBSTRIP
  9393. return fIncludeView;
  9394. }
  9395. STDMETHODIMP CDefView::GetView(SHELLVIEWID* pvid, ULONG uView)
  9396. {
  9397. HRESULT hr;
  9398. if ((int)uView >= 0)
  9399. {
  9400. // start with the first supported view
  9401. UINT fvm = FVM_FIRST;
  9402. while (fvm <= FVM_LAST && !_ViewSupported(fvm))
  9403. fvm++;
  9404. // find fvm associated with index uView
  9405. for (ULONG i = 0; fvm <= FVM_LAST && i < uView; fvm++, i++)
  9406. {
  9407. // skip unsupported views
  9408. while (fvm <= FVM_LAST && !_ViewSupported(fvm))
  9409. fvm++;
  9410. }
  9411. if (fvm <= FVM_LAST)
  9412. {
  9413. hr = SVIDFromViewMode((FOLDERVIEWMODE)fvm, pvid);
  9414. }
  9415. else if (i == uView)
  9416. {
  9417. // enumerate the "default view" so the browser doesn't throw it out later
  9418. *pvid = VID_DefaultView;
  9419. hr = S_OK;
  9420. }
  9421. else
  9422. {
  9423. hr = E_INVALIDARG;
  9424. }
  9425. }
  9426. else
  9427. {
  9428. // We're being asked about specific view info:
  9429. switch (uView)
  9430. {
  9431. case SV2GV_CURRENTVIEW:
  9432. hr = SVIDFromViewMode((FOLDERVIEWMODE)_fs.ViewMode, pvid);
  9433. break;
  9434. case SV2GV_DEFAULTVIEW:
  9435. // tell the browser "default" so we can pick the right one later on
  9436. *pvid = VID_DefaultView;
  9437. hr = S_OK;
  9438. break;
  9439. default:
  9440. hr = E_INVALIDARG;
  9441. break;
  9442. }
  9443. }
  9444. return hr;
  9445. }
  9446. // For Folder Advanced Options flags that we check often, it's better
  9447. // to cache the values as flags. Update them here.
  9448. void CDefView::_UpdateRegFlags()
  9449. {
  9450. DWORD dwValue, cbSize = sizeof(dwValue);
  9451. if (ERROR_SUCCESS == SHGetValue(HKEY_CURRENT_USER,
  9452. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"),
  9453. TEXT("ClassicViewState"), NULL, &dwValue, &cbSize)
  9454. && dwValue)
  9455. {
  9456. _fWin95ViewState = TRUE;
  9457. }
  9458. else
  9459. {
  9460. _fWin95ViewState = FALSE;
  9461. }
  9462. }
  9463. BOOL CDefView::_SetupNotifyData()
  9464. {
  9465. if (!_pidlMonitor && !_lFSEvents)
  9466. {
  9467. LPCITEMIDLIST pidl = NULL;
  9468. LONG lEvents = 0;
  9469. if (SUCCEEDED(CallCB(SFVM_GETNOTIFY, (WPARAM)&pidl, (LPARAM)&lEvents)))
  9470. {
  9471. _pidlMonitor = pidl;
  9472. _lFSEvents = lEvents;
  9473. }
  9474. }
  9475. return _pidlMonitor || _lFSEvents;
  9476. }
  9477. void CDefView::_ShowViewEarly()
  9478. {
  9479. // Show the window early (what old code did)
  9480. SetWindowPos(_hwndView, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW);
  9481. _OnMoveWindowToTop(_hwndView);
  9482. UpdateWindow(_hwndView);
  9483. }
  9484. BOOL LV_FindWorkArea(RECT rcWorkAreas[], int nWorkAreas, POINT *ppt, int *piWorkArea)
  9485. {
  9486. for (int iWork = 0; iWork < nWorkAreas; iWork++)
  9487. {
  9488. if (PtInRect(&rcWorkAreas[iWork], *ppt))
  9489. {
  9490. *piWorkArea = iWork;
  9491. return TRUE;
  9492. }
  9493. }
  9494. *piWorkArea = 0; // default case is the primary work area
  9495. return FALSE;
  9496. }
  9497. void CDefView::_ClearItemPositions()
  9498. {
  9499. _fUserPositionedItems = FALSE;
  9500. _vs.ClearPositionData();
  9501. }
  9502. //
  9503. // This function finds the Recycle bin icon and freezes it. It also freezes the bottom right corner
  9504. // slot sothat no icon can occupy it.
  9505. //
  9506. int CDefView::_FreezeRecycleBin(POINT *ppt)
  9507. {
  9508. int iIndexRecycleBin = -1;
  9509. if (_IsDesktop())
  9510. {
  9511. LPITEMIDLIST pidlRecycleBin;
  9512. if (SUCCEEDED(SHGetFolderLocation(NULL, CSIDL_BITBUCKET, NULL, 0, &pidlRecycleBin)))
  9513. {
  9514. //Find the index of the recycle bin in the listview.
  9515. iIndexRecycleBin = _FindItem(pidlRecycleBin, NULL, FALSE);
  9516. if (iIndexRecycleBin >= 0) //If we don't find recycle bin, we don't have anything to do!
  9517. {
  9518. //Freeze the recycle item (prevent it from moving)
  9519. ListView_SetFrozenItem(_hwndListview, TRUE, iIndexRecycleBin);
  9520. RECT rcItem;
  9521. ListView_GetItemRect(_hwndListview, iIndexRecycleBin, &rcItem, LVIR_SELECTBOUNDS);
  9522. //Get the ViewRect.
  9523. RECT rcViewRect;
  9524. int nWorkAreas = 0;
  9525. //Get the number of work-areas
  9526. ListView_GetNumberOfWorkAreas(_hwndListview, &nWorkAreas);
  9527. if (nWorkAreas > 1)
  9528. {
  9529. ASSERT(nWorkAreas <= LV_MAX_WORKAREAS);
  9530. RECT rcWorkAreas[LV_MAX_WORKAREAS];
  9531. int iCurWorkArea = 0;
  9532. //Get all the work areas!
  9533. ListView_GetWorkAreas(_hwndListview, nWorkAreas, &rcWorkAreas[0]);
  9534. //Find which work area the Recycle-bin currently lies.
  9535. LV_FindWorkArea(rcWorkAreas, nWorkAreas, (LPPOINT)(&rcItem.left), &iCurWorkArea);
  9536. CopyRect(&rcViewRect, &rcWorkAreas[iCurWorkArea]);
  9537. }
  9538. else
  9539. {
  9540. ListView_GetViewRect(_hwndListview, &rcViewRect);
  9541. }
  9542. //Calculate the bottom-right corner of this slot
  9543. POINT ptRecycleBin;
  9544. ptRecycleBin.x = rcViewRect.right;
  9545. ptRecycleBin.y = rcViewRect.bottom;
  9546. //Freeze this slot sothat no other icon can occupy this.
  9547. ListView_SetFrozenSlot(_hwndListview, TRUE, &ptRecycleBin);
  9548. RECT rcIcon;
  9549. ListView_GetItemRect(_hwndListview, iIndexRecycleBin, &rcIcon, LVIR_ICON);
  9550. ppt->x = rcViewRect.right - RECTWIDTH(rcIcon) - (RECTWIDTH(rcItem) - RECTWIDTH(rcIcon))/2;
  9551. ppt->y = rcViewRect.bottom - RECTHEIGHT(rcItem);
  9552. }
  9553. ILFree(pidlRecycleBin);
  9554. }
  9555. }
  9556. return iIndexRecycleBin;
  9557. }
  9558. //
  9559. // This function moves the RecycleBin item to the given location and then unfreezes the item and
  9560. // the frozen slot.
  9561. //
  9562. void CDefView::_SetRecycleBinInDefaultPosition(POINT *ppt)
  9563. {
  9564. // If a sorting has happened since an item was frozen, the index of that item would have changed.
  9565. // So, get the index of the recycle bin here.
  9566. int iIndexRecycleBin = ListView_GetFrozenItem(_hwndListview);
  9567. if (iIndexRecycleBin != LV_NOFROZENITEM)
  9568. {
  9569. //Move the recycle-bin icon to it's default position
  9570. _SetItemPosition(iIndexRecycleBin, ppt->x, ppt->y);
  9571. //Unfreeze the slot
  9572. ListView_SetFrozenSlot(_hwndListview, FALSE, NULL); //FALSE ==> Unfreeze!
  9573. //Unfreeze the recycle bin
  9574. ListView_SetFrozenItem(_hwndListview, FALSE, 0); //FALSE ==> Unfreeze!
  9575. //Since we repositioned recyclebin earlier, we need to save it in the registry.
  9576. //Do we need this?
  9577. // SaveViewState();
  9578. }
  9579. }
  9580. STDMETHODIMP CDefView::CreateViewWindow2(LPSV2CVW2_PARAMS pParams)
  9581. {
  9582. if (g_dwProfileCAP & 0x00000001)
  9583. StopCAP();
  9584. if (pParams->cbSize < sizeof(SV2CVW2_PARAMS))
  9585. return E_INVALIDARG;
  9586. pParams->hwndView = NULL;
  9587. _RegisterWindow();
  9588. if (_hwndView || !pParams->psbOwner)
  9589. return E_UNEXPECTED;
  9590. DECLAREWAITCURSOR;
  9591. SetWaitCursor();
  9592. // Need to leave this code as is. Previously, we had changed it to
  9593. // pParams->psbOwner->QueryInterface(IID_PPV_ARG(IShellBrowser, &_psb));
  9594. // However, this breaks Corel Quattro Pro 8 in their filesave dialog.
  9595. // They pass in some sort of dummy "stub" IShellBrowser. QI'ing it for IShellBrowser
  9596. // will do nothing, and thus _psb will remain null, and we crash. Restoring it to
  9597. // the old way, _psb will be their "stub", but still valid, IShellBrowser.
  9598. // Look for other comments for "Quattro Pro" in this file to see why they pass
  9599. // in this stub.
  9600. // (do this before doing the GetWindowRect)
  9601. _psb = pParams->psbOwner;
  9602. _psb->AddRef();
  9603. ASSERT(_psb); // much of our code assumes this to be valid w/o checking
  9604. #ifdef _X86_
  9605. // Verify that the CHijaakObjectWithSite is properly laid out
  9606. COMPILETIME_ASSERT(FIELD_OFFSET(CDefView, _psfHijaak) + sizeof(_psfHijaak) ==
  9607. FIELD_OFFSET(CDefView, _psb));
  9608. #endif
  9609. _fGlobeCanSpin = TRUE;
  9610. _GlobeAnimation(TRUE);
  9611. HRESULT hr;
  9612. SHELLSTATE ss; // we will need these bits later on
  9613. SHGetSetSettings(&ss, SSF_WIN95CLASSIC | SSF_DESKTOPHTML | SSF_WEBVIEW | SSF_STARTPANELON, FALSE);
  9614. _pshf->QueryInterface(IID_PPV_ARG(IShellIcon, &_psi));
  9615. _pshf->QueryInterface(IID_PPV_ARG(IShellIconOverlay, &_psio));
  9616. pParams->psbOwner->QueryInterface(IID_PPV_ARG(ICommDlgBrowser, &_pcdb));
  9617. // listview starts out in large icon mode, we will switch to the proper view shortly
  9618. _fs.ViewMode = FVM_ICON;
  9619. // refetch FWF_ after browser supplied versions stomped our copy
  9620. _fs.fFlags = pParams->pfs->fFlags & ~FWF_OWNERDATA;
  9621. CallCB(SFVM_FOLDERSETTINGSFLAGS, 0, (LPARAM)&_fs.fFlags);
  9622. // pvid takes precedence over pfs->ViewMode
  9623. UINT fvm = pParams->pfs->ViewMode;
  9624. if (pParams->pvid)
  9625. {
  9626. if (IsEqualIID(*pParams->pvid, VID_DefaultView))
  9627. fvm = FVM_LAST + 1; // not a real view -- we will pick after enumeration
  9628. else
  9629. ViewModeFromSVID(pParams->pvid, (FOLDERVIEWMODE *)&fvm);
  9630. }
  9631. // This should never fail
  9632. _psb->GetWindow(&_hwndMain);
  9633. ASSERT(IsWindow(_hwndMain));
  9634. CallCB(SFVM_HWNDMAIN, 0, (LPARAM)_hwndMain);
  9635. // We need to restore the column widths and icon positions before showing the window
  9636. if (!GetViewState())
  9637. {
  9638. // Icon positions are not available; Therefore, it is a clean install
  9639. // and we need to position recycle bin if this is Desktop.
  9640. _fPositionRecycleBin = BOOLIFY(_IsDesktop());
  9641. }
  9642. _fSyncOnFillDone = TRUE; // apply the just-loaded view state when we finish enumeration
  9643. // if there was a previous view that we know about, update our column state
  9644. if (_fWin95ViewState && pParams->psvPrev)
  9645. {
  9646. _vs.InitFromPreviousView(pParams->psvPrev);
  9647. }
  9648. _pEnumTask = new CDefviewEnumTask(this);
  9649. if (_pEnumTask &&
  9650. CreateWindowEx(IS_WINDOW_RTL_MIRRORED(_hwndMain) ? dwExStyleRTLMirrorWnd : 0,
  9651. TEXT("SHELLDLL_DefView"), NULL,
  9652. WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_TABSTOP,
  9653. pParams->prcView->left, pParams->prcView->top,
  9654. pParams->prcView->right - pParams->prcView->left,
  9655. pParams->prcView->bottom - pParams->prcView->top,
  9656. _hwndMain, NULL, HINST_THISDLL, this))
  9657. {
  9658. // See if they want to overwrite the selection object
  9659. if (_fs.fFlags & FWF_OWNERDATA)
  9660. {
  9661. // Only used in owner data.
  9662. ILVRange *plvr = NULL;
  9663. CallCB(SFVM_GETODRANGEOBJECT, LVSR_SELECTION, (LPARAM)&plvr);
  9664. if (plvr)
  9665. {
  9666. ListView_SetLVRangeObject(_hwndListview, LVSR_SELECTION, plvr);
  9667. plvr->Release(); // We assume the lv will hold onto it...
  9668. }
  9669. plvr = NULL;
  9670. CallCB(SFVM_GETODRANGEOBJECT, LVSR_CUT, (LPARAM)&plvr);
  9671. if (plvr)
  9672. {
  9673. ListView_SetLVRangeObject(_hwndListview, LVSR_CUT, plvr);
  9674. plvr->Release(); // We assume the lv will hold onto it...
  9675. }
  9676. }
  9677. // This needs to be done before calling _BestFit (used to be in _FillObjects)
  9678. // so that the parent can handle size changes effectively.
  9679. pParams->hwndView = _hwndView;
  9680. // Since ::FillObjects can take a while we force a paint now
  9681. // before any items are added so we don't see the gray background of
  9682. // the explorer window for a long time.
  9683. //
  9684. // We used to do this after determining "async-ness" of the view, which
  9685. // required us to pick the webview template. We want to postpone that
  9686. // decision so force the repaint in the same scenarios that we otherwise
  9687. // would have (non-webview or desktop).
  9688. //
  9689. // Make an educated guess here, if we get it wrong, we fix it up below.
  9690. //
  9691. if (!_ShouldShowWebView() || _IsDesktop())
  9692. {
  9693. _ShowViewEarly();
  9694. }
  9695. // Try and fill the listview synchronously with view creation.
  9696. //
  9697. _fAllowSearchingWindow = TRUE;
  9698. hr = _pEnumTask->FillObjectsToDPA(TRUE);
  9699. if (SUCCEEDED(hr))
  9700. {
  9701. // Setting the view mode has to happen after SFVM_ENUMERATEDITEMS
  9702. // NOTE: this also AddColumns() if the new view requires them
  9703. if (FVM_LAST + 1 == fvm)
  9704. _GetDeferredViewSettings(&fvm);
  9705. // Don't call SetCurrentViewMode since it clears position data and we may have read in
  9706. // position data via GetViewState but haven't used it yet. Call _SwitchToViewFVM directly.
  9707. hr = _SwitchToViewFVM(fvm, SWITCHTOVIEW_NOWEBVIEW);
  9708. // The following bits depend on the result of _SwitchToViewFVM.
  9709. // It returns the value from turning on web view,
  9710. // this is used to determine async defview behavior (so we have
  9711. // an answer to the SHDVID_CANACTIVATENOW question the browser
  9712. // will soon ask us).
  9713. //
  9714. // Note: Desktop synchronous, even for web view
  9715. //
  9716. if (SUCCEEDED(hr) && _IsDesktop())
  9717. hr = S_OK;
  9718. _fCanActivateNow = (S_OK == hr); // S_FALSE implies async waiting for ReadyStateInteractive
  9719. _fIsAsyncDefView = !BOOLIFY(_fCanActivateNow); // needed in a separate bit since _fCanActivateNow changes
  9720. // This has to happen after _SwitchToViewFVM so it can calculate
  9721. // the correct size of the window
  9722. _BestFit();
  9723. // Tell the defview client that this windows has been initialized
  9724. // Note that this must come before _pEnumTask->FillObjectsDPAToDone() so that the status bar displays
  9725. // (Disk Free space xxGB) correctly in explorer view.
  9726. CallCB(SFVM_WINDOWCREATED, (WPARAM)_hwndView, 0);
  9727. //
  9728. // If this is desktop, we need to calc and upgrade the grid sizes.
  9729. // (This is needed because the SnapToGrid may be ON and the default grid size
  9730. // will result in large gutter space on the edges).
  9731. //
  9732. if (_IsDesktop())
  9733. {
  9734. DWORD dwLVExStyle = ListView_GetExtendedListViewStyle(_hwndListview);
  9735. //
  9736. //Since the work areas are NOT yet set for the desktop's listview (because this is too early
  9737. //in it's creation, we pass just one work area and the view rect as work area here.)
  9738. //
  9739. UpdateGridSizes(TRUE, _hwndListview, 1, pParams->prcView, BOOLIFY(dwLVExStyle & LVS_EX_SNAPTOGRID));
  9740. }
  9741. // Doing this after _BestFit means we dont need to auto-auto arrange
  9742. _pEnumTask->FillObjectsDPAToDone();
  9743. // splitting this function call in half means that we won't call WebView with contents changed for initial population
  9744. _SwitchToViewFVM(fvm, SWITCHTOVIEW_WEBVIEWONLY);
  9745. // If we're activating now, make sure we did the synchronous thing up above...
  9746. // (If not, do it now -- otherwise defview may never be shown)
  9747. if (_fCanActivateNow && !(!_ShouldShowWebView() || _IsDesktop()))
  9748. {
  9749. _ShowViewEarly();
  9750. }
  9751. if (_IsDesktop())
  9752. {
  9753. HideIE4DesktopChannelBar();
  9754. }
  9755. // turn on proper background and colors
  9756. _fClassic = ss.fWin95Classic;
  9757. _UpdateListviewColors();
  9758. // this needs to be done after the enumeration
  9759. if (_SetupNotifyData())
  9760. {
  9761. SHChangeNotifyEntry fsne = {0};
  9762. if (FAILED(CallCB(SFVM_QUERYFSNOTIFY, 0, (LPARAM)&fsne)))
  9763. {
  9764. // Reset entry
  9765. fsne.pidl = _pidlMonitor;
  9766. fsne.fRecursive = FALSE;
  9767. }
  9768. int iSources = (_lFSEvents & SHCNE_DISKEVENTS) ? SHCNRF_ShellLevel | SHCNRF_InterruptLevel : SHCNRF_ShellLevel;
  9769. LONG lEvents = _lFSEvents | SHCNE_UPDATEIMAGE | SHCNE_UPDATEDIR;
  9770. _uRegister = SHChangeNotifyRegister(_hwndView, SHCNRF_NewDelivery | iSources,
  9771. lEvents, WM_DSV_FSNOTIFY, 1, &fsne);
  9772. }
  9773. // We do the toolbar before the menu bar to avoid flash
  9774. if (!_IsDesktop())
  9775. MergeToolBar(TRUE);
  9776. // Note: it's okay for the CreateViewObject(&_pdtgtBack) to fail
  9777. ASSERT(_pdtgtBack == NULL);
  9778. _pshf->CreateViewObject(_hwndMain, IID_PPV_ARG(IDropTarget, &_pdtgtBack));
  9779. // we don't really need to register drag drop when in the shell because
  9780. // our frame does it for us. we still need it here for comdlg and other
  9781. // hosts.. but for the desktop, let the desktpo frame take care of this
  9782. // so that they can do webbar d/d creation
  9783. if (!_IsDesktop())
  9784. {
  9785. THR(RegisterDragDrop(_hwndListview, SAFECAST(this, IDropTarget*)));
  9786. _bRegisteredDragDrop = TRUE;
  9787. }
  9788. ASSERT(SUCCEEDED(hr))
  9789. PostMessage(_hwndView, WM_DSV_DELAYWINDOWCREATE, 0, 0);
  9790. if (SUCCEEDED(CallCB(SFVM_QUERYCOPYHOOK, 0, 0)))
  9791. AddCopyHook();
  9792. if (SUCCEEDED(_GetIPersistHistoryObject(NULL)))
  9793. {
  9794. IBrowserService *pbs;
  9795. if (SUCCEEDED(_psb->QueryInterface(IID_PPV_ARG(IBrowserService, &pbs))))
  9796. {
  9797. IOleObject *pole;
  9798. IStream *pstm;
  9799. IBindCtx *pbc;
  9800. pbs->GetHistoryObject(&pole, &pstm, &pbc);
  9801. if (pole)
  9802. {
  9803. IUnknown_SetSite(pole, SAFECAST(this, IShellView2*)); // Set the back pointer.
  9804. if (pstm)
  9805. {
  9806. IPersistHistory *pph;
  9807. if (SUCCEEDED(pole->QueryInterface(IID_PPV_ARG(IPersistHistory, &pph))))
  9808. {
  9809. pph->LoadHistory(pstm, pbc);
  9810. pph->Release();
  9811. }
  9812. pstm->Release();
  9813. }
  9814. IUnknown_SetSite(pole, NULL); // just to be safe...
  9815. if (pbc)
  9816. pbc->Release();
  9817. pole->Release();
  9818. }
  9819. pbs->Release();
  9820. }
  9821. }
  9822. if (_psb && !_dwProffered)
  9823. {
  9824. // Proffer DVGetEnum service: this connects CDefView with the tree control for
  9825. // optimized navigation.
  9826. IUnknown_ProfferService(_psb, SID_SFolderView, SAFECAST(this, IServiceProvider *), &_dwProffered);
  9827. // Failure here does not require special handling
  9828. }
  9829. }
  9830. else
  9831. {
  9832. // Cleanup - enum failed.
  9833. DestroyViewWindow();
  9834. }
  9835. }
  9836. else
  9837. {
  9838. hr = E_OUTOFMEMORY;
  9839. }
  9840. _GlobeAnimation(FALSE);
  9841. ResetWaitCursor();
  9842. return hr;
  9843. }
  9844. struct SCHEDULER_AND_HWND {
  9845. IShellTaskScheduler *pScheduler;
  9846. HWND hwnd;
  9847. };
  9848. STDMETHODIMP CDefView::DestroyViewWindow()
  9849. {
  9850. if (_fDestroying)
  9851. return S_OK;
  9852. if (_psb && _dwProffered)
  9853. {
  9854. // Revoke DVGetEnum service
  9855. IUnknown_ProfferService(_psb, SID_SFolderView, NULL, &_dwProffered);
  9856. // Failure here does not require special handling
  9857. }
  9858. // Make sure that we stop the spinning globe before going away.
  9859. _GlobeAnimation(FALSE, TRUE);
  9860. _fDestroying = TRUE;
  9861. // 99/04/16 #326158 vtan: Loop thru the headers looking for
  9862. // stray HBITMAPs which need to be DeleteObject'd. Don't bother
  9863. // setting it back the header is about to be dumped.
  9864. // NOTE: Make sure this gets executed BEFORE the view gets
  9865. // dumped below in DestoryViewWindow().
  9866. if (IsWindow(_hwndListview))
  9867. {
  9868. HWND hwndHeader = ListView_GetHeader(_hwndListview);
  9869. if (IsWindow(hwndHeader))
  9870. {
  9871. int iHeaderCount = Header_GetItemCount(hwndHeader);
  9872. for (int i = 0; i < iHeaderCount; ++i)
  9873. {
  9874. HDITEM hdi = {0};
  9875. hdi.mask = HDI_BITMAP;
  9876. Header_GetItem(hwndHeader, i, &hdi);
  9877. if (hdi.hbm != NULL)
  9878. TBOOL(DeleteObject(hdi.hbm));
  9879. }
  9880. }
  9881. }
  9882. _cFrame.HideWebView();
  9883. //
  9884. // Just in case...
  9885. //
  9886. OnDeactivate();
  9887. if (IsWindow(_hwndView))
  9888. {
  9889. //
  9890. // This is a bit lazy implementation, but minimum code.
  9891. //
  9892. RemoveCopyHook();
  9893. // Tell the defview client that this window will be destroyed
  9894. CallCB(SFVM_WINDOWDESTROY, (WPARAM)_hwndView, 0);
  9895. }
  9896. if (IsWindow(_hwndView))
  9897. {
  9898. if (_pScheduler)
  9899. {
  9900. // empty the queue but do NOT wait until it is empty.....
  9901. _pScheduler->RemoveTasks(TOID_NULL, ITSAT_DEFAULT_LPARAM, FALSE);
  9902. // If there is still a task going, then kill our window later, as to not
  9903. // block the UI thread.
  9904. #ifdef DEBUG
  9905. // Stress the feature in debug mode
  9906. if (1)
  9907. #else
  9908. if (_GetBackgroundTaskCount(TOID_NULL) > 0)
  9909. #endif
  9910. {
  9911. ShowWindow(_hwndView, SW_HIDE);
  9912. // We are NOT passing 'this' defview pointer to the background thread
  9913. // because we do not want the destructor of defview to be called on any
  9914. // thread other than the one it was created on.
  9915. SCHEDULER_AND_HWND *pData = (SCHEDULER_AND_HWND *)LocalAlloc(LPTR, sizeof(*pData));
  9916. if (pData)
  9917. {
  9918. _pScheduler->AddRef();
  9919. pData->pScheduler = _pScheduler;
  9920. pData->hwnd = _hwndView;
  9921. // We need to keep Browseui loaded because we depend on the CShellTaskScheduler
  9922. // to be still around when our background task executes. Browseui can be unloaded by COM when
  9923. // we CoUninit from this thread.
  9924. if (SHQueueUserWorkItem(CDefView::BackgroundDestroyWindow, pData, 0, NULL, NULL, "browseui.dll", 0))
  9925. goto exit;
  9926. else
  9927. {
  9928. LocalFree(pData);
  9929. _pScheduler->Release();
  9930. }
  9931. }
  9932. }
  9933. }
  9934. DestroyWindow(_hwndView);
  9935. }
  9936. exit:
  9937. return S_OK;
  9938. }
  9939. DWORD CDefView::BackgroundDestroyWindow(void *pvData)
  9940. {
  9941. SCHEDULER_AND_HWND *pData = (SCHEDULER_AND_HWND *)pvData;
  9942. // Note: the window coud have been already destroyed before we get here
  9943. // in the case where the frame gets closed down.
  9944. if (IsWindow(pData->hwnd))
  9945. {
  9946. // Remove all tasks
  9947. EmptyBkgrndThread(pData->pScheduler);
  9948. // We need to release before we post to ensure that browseui doesn't get unloaded from under us (pScheduler is
  9949. // in browseui.dll). Browseui can get unloaded when we uninitialize OLE's MTA, even if there are still refs on the DLL.
  9950. pData->pScheduler->Release();
  9951. PostMessage(pData->hwnd, WM_DSV_DELAYED_DESTROYWND, 0, 0);
  9952. }
  9953. else
  9954. {
  9955. pData->pScheduler->Release();
  9956. }
  9957. LocalFree(pData);
  9958. return 0;
  9959. }
  9960. void CDefView::_MergeViewMenu(HMENU hmenuViewParent, HMENU hmenuMerge)
  9961. {
  9962. HMENU hmenuView = _GetMenuFromID(hmenuViewParent, FCIDM_MENU_VIEW);
  9963. if (hmenuView)
  9964. {
  9965. #ifdef DEBUG
  9966. DWORD dwValue;
  9967. DWORD cbSize = sizeof(dwValue);
  9968. if (ERROR_SUCCESS == SHGetValue(HKEY_CURRENT_USER,
  9969. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"),
  9970. TEXT("DebugWebView"), NULL, &dwValue, &cbSize)
  9971. && dwValue)
  9972. {
  9973. MENUITEMINFO mi = {0};
  9974. mi.cbSize = sizeof(mi);
  9975. mi.fMask = MIIM_TYPE|MIIM_ID;
  9976. mi.fType = MFT_STRING;
  9977. mi.dwTypeData = TEXT("Show WebView Content");
  9978. mi.wID = SFVIDM_DEBUG_WEBVIEW;
  9979. InsertMenuItem(hmenuMerge, -1, MF_BYPOSITION, &mi);
  9980. }
  9981. #endif
  9982. //
  9983. // Find the "options" separator in the view menu.
  9984. //
  9985. int index = MenuIndexFromID(hmenuView, FCIDM_MENU_VIEW_SEP_OPTIONS);
  9986. //
  9987. // Here, index is the index of he "optoins" separator if it has;
  9988. // otherwise, it is -1.
  9989. //
  9990. // Add the separator above (in addition to existing one if any).
  9991. InsertMenu(hmenuView, index, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
  9992. // Then merge our menu between two separators (or right below if only one).
  9993. if (index != -1)
  9994. {
  9995. index++;
  9996. }
  9997. Shell_MergeMenus(hmenuView, hmenuMerge, (UINT)index, 0, (UINT)-1, MM_SUBMENUSHAVEIDS);
  9998. }
  9999. }
  10000. void CDefView::_SetUpMenus(UINT uState)
  10001. {
  10002. //
  10003. // If this is desktop, don't bother creating menu
  10004. //
  10005. if (!_IsDesktop())
  10006. {
  10007. OnDeactivate();
  10008. ASSERT(_hmenuCur == NULL);
  10009. HMENU hMenu = CreateMenu();
  10010. if (hMenu)
  10011. {
  10012. HMENU hMergeMenu;
  10013. OLEMENUGROUPWIDTHS mwidth = { { 0, 0, 0, 0, 0, 0 } };
  10014. _hmenuCur = hMenu;
  10015. _psb->InsertMenusSB(hMenu, &mwidth);
  10016. if (uState == SVUIA_ACTIVATE_FOCUS)
  10017. {
  10018. hMergeMenu = LoadMenu(HINST_THISDLL, MAKEINTRESOURCE(POPUP_SFV_MAINMERGE));
  10019. if (hMergeMenu)
  10020. {
  10021. // NOTE: hard coded references to offsets in this menu
  10022. Shell_MergeMenus(_GetMenuFromID(hMenu, FCIDM_MENU_FILE),
  10023. GetSubMenu(hMergeMenu, 0), (UINT)0, 0, (UINT)-1,
  10024. MM_ADDSEPARATOR | MM_SUBMENUSHAVEIDS | MM_DONTREMOVESEPS);
  10025. Shell_MergeMenus(_GetMenuFromID(hMenu, FCIDM_MENU_EDIT),
  10026. GetSubMenu(hMergeMenu, 1), (UINT)-1, 0, (UINT)-1,
  10027. MM_ADDSEPARATOR | MM_SUBMENUSHAVEIDS | MM_DONTREMOVESEPS);
  10028. _MergeViewMenu(hMenu, GetSubMenu(hMergeMenu, 2));
  10029. Shell_MergeMenus(_GetMenuFromID(hMenu, FCIDM_MENU_HELP),
  10030. GetSubMenu(hMergeMenu, 3), (UINT)0, 0, (UINT)-1,
  10031. MM_ADDSEPARATOR | MM_SUBMENUSHAVEIDS);
  10032. DestroyMenu(hMergeMenu);
  10033. }
  10034. }
  10035. else
  10036. {
  10037. hMergeMenu = LoadMenu(HINST_THISDLL, MAKEINTRESOURCE(POPUP_SFV_MAINMERGENF));
  10038. if (hMergeMenu)
  10039. {
  10040. // NOTE: hard coded references to offsets in this menu
  10041. // top half of edit menu
  10042. Shell_MergeMenus(_GetMenuFromID(hMenu, FCIDM_MENU_EDIT),
  10043. GetSubMenu(hMergeMenu, 0), (UINT)0, 0, (UINT)-1,
  10044. MM_ADDSEPARATOR | MM_SUBMENUSHAVEIDS);
  10045. // bottom half of edit menu
  10046. Shell_MergeMenus(_GetMenuFromID(hMenu, FCIDM_MENU_EDIT),
  10047. GetSubMenu(hMergeMenu, 1), (UINT)-1, 0, (UINT)-1,
  10048. MM_SUBMENUSHAVEIDS);
  10049. // view menu
  10050. _MergeViewMenu(hMenu, GetSubMenu(hMergeMenu, 2));
  10051. Shell_MergeMenus(_GetMenuFromID(hMenu, FCIDM_MENU_HELP),
  10052. GetSubMenu(hMergeMenu, 3), (UINT)0, 0, (UINT)-1,
  10053. MM_ADDSEPARATOR | MM_SUBMENUSHAVEIDS);
  10054. DestroyMenu(hMergeMenu);
  10055. }
  10056. }
  10057. // Allow the client to merge its own menus
  10058. UINT indexClient = GetMenuItemCount(hMenu)-1;
  10059. QCMINFO info = { hMenu, indexClient, SFVIDM_CLIENT_FIRST, SFVIDM_CLIENT_LAST };
  10060. CallCB(SFVM_MERGEMENU, 0, (LPARAM)&info);
  10061. _psb->SetMenuSB(hMenu, NULL, _hwndView);
  10062. }
  10063. }
  10064. }
  10065. // set up the menus based on our activation state
  10066. //
  10067. BOOL CDefView::OnActivate(UINT uState)
  10068. {
  10069. if (_uState != uState)
  10070. {
  10071. _SetUpMenus(uState);
  10072. _uState = uState;
  10073. }
  10074. return TRUE;
  10075. }
  10076. BOOL CDefView::OnDeactivate()
  10077. {
  10078. if (_hmenuCur || (_uState != SVUIA_DEACTIVATE))
  10079. {
  10080. if (!_IsDesktop())
  10081. {
  10082. ASSERT(_hmenuCur);
  10083. CallCB(SFVM_UNMERGEMENU, 0, (LPARAM)_hmenuCur);
  10084. _psb->SetMenuSB(NULL, NULL, NULL);
  10085. _psb->RemoveMenusSB(_hmenuCur);
  10086. DestroyMenu(_hmenuCur);
  10087. _hmenuCur = NULL;
  10088. }
  10089. _uState = SVUIA_DEACTIVATE;
  10090. }
  10091. return TRUE;
  10092. }
  10093. void CDefView::_OnMoveWindowToTop(HWND hwnd)
  10094. {
  10095. //
  10096. // Let the browser know that this has happened
  10097. //
  10098. VARIANT var;
  10099. var.vt = VT_INT_PTR;
  10100. var.byref = hwnd;
  10101. IUnknown_Exec(_psb, &CGID_Explorer, SBCMDID_ONVIEWMOVETOTOP, 0, &var, NULL);
  10102. }
  10103. //
  10104. // This function activates the view window. Note that activating it
  10105. // will not change the focus (while setting the focus will activate it).
  10106. //
  10107. STDMETHODIMP CDefView::UIActivate(UINT uState)
  10108. {
  10109. if (SVUIA_DEACTIVATE == uState)
  10110. {
  10111. OnDeactivate();
  10112. ASSERT(_hmenuCur==NULL);
  10113. }
  10114. else
  10115. {
  10116. if (_fIsAsyncDefView)
  10117. {
  10118. // Need to show the defview window for the Async Case only. Showing
  10119. // it earlier causes repaint problems(Bug 275266). Showing the window
  10120. // here for the Sync case also causes problems - when the client
  10121. // creates a Synchronous Defview and then hides it later which gets
  10122. // lost with this SetWindowPos (Bug 355392).
  10123. SetWindowPos(_hwndView, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW);
  10124. UpdateWindow(_hwndView);
  10125. _OnMoveWindowToTop(_hwndView);
  10126. }
  10127. if (uState == SVUIA_ACTIVATE_NOFOCUS)
  10128. {
  10129. // we lost focus
  10130. // if in web view and we have valid ole obj (just being paranoid)
  10131. if (!_fCombinedView && _cFrame.IsWebView() && _cFrame._pOleObj)
  10132. {
  10133. _cFrame._UIActivateIO(FALSE, NULL);
  10134. }
  10135. }
  10136. // We may be waiting for ReadyState_Interactive. If requested,
  10137. // we should activate before then...
  10138. //
  10139. // When we boot, the desktop paints ugly white screen for several
  10140. // seconds before it shows the HTML content. This is because: the
  10141. // following code switches the oleobj even before it reaches readystate
  10142. // interactive. For desktop, we skip this here. When the new object
  10143. // reaches readystate interactive, we will show it!
  10144. if (!_IsDesktop())
  10145. {
  10146. _cFrame._SwitchToNewOleObj();
  10147. // NOTE: The browser IP/UI-activates us when we become the
  10148. // current active view! We want to resize and show windows
  10149. // at that time. But if we're still waiting for _fCanActivateNow
  10150. // (ie, ReadyStateInteractive), then we need to cache this request
  10151. // and do it later. NOTE: if Trident caches the focus (done w/ TAB)
  10152. // then we don't need to do anything here...
  10153. //
  10154. if (uState == SVUIA_ACTIVATE_FOCUS)
  10155. {
  10156. _SetFocus();
  10157. // _SetFocus can set _uState without causing our menu to
  10158. // get created and merged. Clear it here so that OnActivate does the
  10159. // right thing.
  10160. if (!_hmenuCur)
  10161. _uState = SVUIA_DEACTIVATE;
  10162. }
  10163. }
  10164. // else we are the desktop; do we also need to steal focus?
  10165. else if (uState == SVUIA_ACTIVATE_FOCUS)
  10166. {
  10167. HWND hwnd = GetFocus();
  10168. if (SHIsChildOrSelf(_hwndView, hwnd) != S_OK)
  10169. _SetFocus();
  10170. }
  10171. // OnActivate must follow _SetFocus
  10172. OnActivate(uState);
  10173. ShowHideListView();
  10174. ASSERT(_IsDesktop() || _hmenuCur);
  10175. _cFrame._UpdateZonesStatusPane(NULL);
  10176. }
  10177. return S_OK;
  10178. }
  10179. STDMETHODIMP CDefView::GetCurrentInfo(LPFOLDERSETTINGS pfs)
  10180. {
  10181. *pfs = _fs;
  10182. return S_OK;
  10183. }
  10184. BOOL IsBackSpace(const MSG *pMsg)
  10185. {
  10186. return pMsg && (pMsg->message == WM_KEYDOWN) && (pMsg->wParam == VK_BACK);
  10187. }
  10188. extern int IsVK_TABCycler(MSG *pMsg);
  10189. //***
  10190. // NOTES
  10191. // try ListView->TA first
  10192. // then if that fails try WebView->TA iff it has focus.
  10193. // then if that fails and it's a TAB we do WebView->UIAct
  10194. STDMETHODIMP CDefView::TranslateAccelerator(LPMSG pmsg)
  10195. {
  10196. // 1st, try ListView
  10197. if (_fInLabelEdit)
  10198. {
  10199. // the second clause stops us passing mouse key clicks to the toolbar if we are in label edit mode...
  10200. if (WM_KEYDOWN == pmsg->message || WM_KEYUP == pmsg->message)
  10201. {
  10202. // process this msg so the exploer does not get to translate
  10203. TranslateMessage(pmsg);
  10204. DispatchMessage(pmsg);
  10205. return S_OK; // we handled it
  10206. }
  10207. else
  10208. return S_FALSE;
  10209. }
  10210. // If we are in classic mode and if it's a tab and the listview doesn't have focus already, receive the tab.
  10211. else if (IsVK_TABCycler(pmsg) && !(_cFrame.IsWebView() || _pDUIView) && (GetFocus() != _hwndListview))
  10212. {
  10213. _SetFocus();
  10214. return S_OK;
  10215. }
  10216. if (GetFocus() == _hwndListview)
  10217. {
  10218. if (::TranslateAccelerator(_hwndView, _hAccel, pmsg))
  10219. {
  10220. // we know we have a normal view, therefore this is
  10221. // the right translate accelerator to use, otherwise the
  10222. // common dialogs will fail to get any accelerated keys.
  10223. return S_OK;
  10224. }
  10225. else if (WM_KEYDOWN == pmsg->message || WM_SYSKEYDOWN == pmsg->message)
  10226. {
  10227. // MSHTML eats these keys for frameset scrolling, but we
  10228. // want to get them to our wndproc . . . translate 'em ourself
  10229. //
  10230. switch (pmsg->wParam)
  10231. {
  10232. case VK_LEFT:
  10233. case VK_RIGHT:
  10234. // only go through here if alt is not down.
  10235. // don't intercept all alt combinations because
  10236. // alt-enter means something
  10237. // this is for alt-left/right compat with IE
  10238. if (GetAsyncKeyState(VK_MENU) < 0)
  10239. break;
  10240. // fall through
  10241. case VK_UP:
  10242. case VK_DOWN:
  10243. case VK_HOME:
  10244. case VK_END:
  10245. case VK_PRIOR:
  10246. case VK_NEXT:
  10247. case VK_RETURN:
  10248. case VK_F10:
  10249. TranslateMessage(pmsg);
  10250. DispatchMessage(pmsg);
  10251. return S_OK;
  10252. }
  10253. }
  10254. }
  10255. // 1.5th, before we pass it down, see whether shell browser handles it.
  10256. // we do this to make sure that webview has the same accelerator semantics
  10257. // no matter what view(s) are active.
  10258. // note that this is arguably inconsistent w/ the 'pass it to whoever has
  10259. // focus'.
  10260. //
  10261. // however *don't* do this if:
  10262. // - we're in a dialog (in which case the buttons should come 1st)
  10263. // (comdlg's shellbrowser xxx::TA impl is broken it always does S_OK)
  10264. // - it's a TAB (which is always checked last)
  10265. // - it's a BACKSPACE (we should give the currently active object the first chance).
  10266. // However, in this case, we should call TranslateAcceleratorSB() AFTER we've tried
  10267. // calling TranslateAccelerator() on the currently active control (_pActive) in
  10268. // _cFrame->OnTranslateAccelerator().
  10269. //
  10270. // note: if you muck w/ this code careful not to regress the following:
  10271. // - ie41:62140: mnemonics broken after folder selected in organize favs
  10272. // - ie41:62419: TAB activates addr and menu if folder selected in explorer
  10273. if (!_IsCommonDialog() && !IsVK_TABCycler(pmsg) && !IsBackSpace(pmsg))
  10274. if (S_OK == _psb->TranslateAcceleratorSB(pmsg, 0))
  10275. return S_OK;
  10276. BOOL bTabOffLastTridentStop = FALSE;
  10277. BOOL bHadIOFocus = (_cFrame._HasFocusIO() == S_OK); // Cache this here before the _cFrame.OnTA() call below
  10278. // 2nd, try WebView if it's active
  10279. if (IsVK_TABCycler(pmsg) && _pDUIView)
  10280. {
  10281. if (_pDUIView->Navigate(GetAsyncKeyState(VK_SHIFT) >= 0))
  10282. return S_OK;
  10283. }
  10284. if (_cFrame.IsWebView() && (S_OK == _cFrame.OnTranslateAccelerator(pmsg, &bTabOffLastTridentStop)))
  10285. {
  10286. return S_OK;
  10287. }
  10288. // We've given _pActive->TranslateAccelerator() the first shot in
  10289. // _cFrame.OnTranslateAccelerator, but it failed. Let's try the shell browser.
  10290. if (IsBackSpace(pmsg) && (S_OK == _psb->TranslateAcceleratorSB(pmsg, 0)))
  10291. return S_OK;
  10292. // 3rd, ???
  10293. if (::TranslateAccelerator(_hwndView, _hAccel, pmsg))
  10294. return S_OK;
  10295. // 4th, if it's a TAB, cycle to next guy
  10296. // hack: we fake a bunch of the TAB-activation handshaking
  10297. if (IsVK_TABCycler(pmsg) && _cFrame.IsWebView())
  10298. {
  10299. HRESULT hr;
  10300. BOOL fBack = (GetAsyncKeyState(VK_SHIFT) < 0);
  10301. if (!bHadIOFocus && bTabOffLastTridentStop)
  10302. {
  10303. // We were at the last tab stop in trident when the browser called defview->TA().
  10304. // When we called TA() on trident above, it must've told us that we are tabbing
  10305. // off the last tab stop (bTabOffLastTridentStop). This will leave us not setting focus
  10306. // on anything. But, we have to set focus to something. We can do this by calling TA()
  10307. // on trident again, which will set focus on the first tab stop again.
  10308. return _cFrame.OnTranslateAccelerator(pmsg, &bTabOffLastTridentStop);
  10309. }
  10310. else if (_cFrame._HasFocusIO() == S_OK)
  10311. {
  10312. // ExtView has focus, and doesn't want the TAB.
  10313. // this means we're TABing off of it.
  10314. // no matter what, deactivate it (since we're TABing off).
  10315. // if the view is next in the TAB order, (pseudo-)activate it,
  10316. // and return S_OK since we've handled it.
  10317. // o.w. return S_OK so our parent will activate whoever's next
  10318. // in the TAB order.
  10319. hr = _cFrame._UIActivateIO(FALSE, NULL);
  10320. ASSERT(hr == S_OK);
  10321. // in web view listview already has focus so don't give it again
  10322. // that's not the case with desktop
  10323. if (fBack && _IsDesktop())
  10324. {
  10325. SetFocus(_hwndListview);
  10326. return S_OK;
  10327. }
  10328. return S_FALSE;
  10329. }
  10330. else
  10331. {
  10332. if (!fBack)
  10333. {
  10334. hr = _cFrame._UIActivateIO(TRUE, pmsg);
  10335. ASSERT(hr == S_OK || hr == S_FALSE);
  10336. return hr;
  10337. }
  10338. }
  10339. }
  10340. return S_FALSE;
  10341. }
  10342. // Description:
  10343. // Regenerates the CDefView's menus. Used for regaining any menu items
  10344. // which may have been stripped via DeleteMenu(), as occurs for various
  10345. // particular view states.
  10346. //
  10347. // Example: Transitioning to a barricaded view automatically strips out
  10348. // a number of commands from the "View" menu which are not appropriate
  10349. // for the barricaded view. Thus, on the transition back out of the
  10350. // barricaded view, the menus must be recreated in order to regain
  10351. // any/all the menu items stripped (this is not to say a number of
  10352. // them may not be stripped again if we're just transitioning to
  10353. // another view which doesn't want them in there!).
  10354. //
  10355. void CDefView::RecreateMenus()
  10356. {
  10357. UINT uState = _uState;
  10358. _SetUpMenus(uState); // Note _SetupMenus() calls OnDeactivate()
  10359. _uState = uState; // which sets _uState to SVUIA_DEACTIVATE.
  10360. }
  10361. void CDefView::InitViewMenu(HMENU hmInit)
  10362. {
  10363. // Initialize view menu accordingly...
  10364. if (_fBarrierDisplayed)
  10365. _InitViewMenuWhenBarrierDisplayed(hmInit);
  10366. else
  10367. _InitViewMenuWhenBarrierNotDisplayed(hmInit);
  10368. // Remove any extraneous menu separators arising from initialization.
  10369. _SHPrettyMenu(hmInit);
  10370. }
  10371. // Description:
  10372. // Used to initialize the entries of the "View" menu and its associated
  10373. // submenus whenever a soft barrier is being displayed.
  10374. //
  10375. // Note:
  10376. // This method is also employed when "Category View" is being used in
  10377. // browsing the Control Panel.
  10378. //
  10379. void CDefView::_InitViewMenuWhenBarrierDisplayed(HMENU hmenuView)
  10380. {
  10381. // If "list view" is not visible (i.e. we're in Category View in the
  10382. // Control Panel, or we're looking at a barricaded folder), we strip
  10383. // out the following stuff from the View menu:
  10384. //
  10385. // Filmstrip
  10386. // Thumbnails
  10387. // Tiles
  10388. // Icons
  10389. // List
  10390. // Details
  10391. // -------------------
  10392. // Arrange Icons By ->
  10393. // -------------------
  10394. // Choose Details...
  10395. // Customize This Folder...
  10396. // Remove menu entries.
  10397. DeleteMenu(hmenuView, SFVIDM_VIEW_THUMBSTRIP, MF_BYCOMMAND);
  10398. DeleteMenu(hmenuView, SFVIDM_VIEW_THUMBNAIL, MF_BYCOMMAND);
  10399. DeleteMenu(hmenuView, SFVIDM_VIEW_TILE, MF_BYCOMMAND);
  10400. DeleteMenu(hmenuView, SFVIDM_VIEW_ICON, MF_BYCOMMAND);
  10401. DeleteMenu(hmenuView, SFVIDM_VIEW_LIST, MF_BYCOMMAND);
  10402. DeleteMenu(hmenuView, SFVIDM_VIEW_DETAILS, MF_BYCOMMAND);
  10403. DeleteMenu(hmenuView, SFVIDM_MENU_ARRANGE, MF_BYCOMMAND);
  10404. DeleteMenu(hmenuView, SFVIDM_VIEW_COLSETTINGS, MF_BYCOMMAND);
  10405. DeleteMenu(hmenuView, SFVIDM_VIEW_CUSTOMWIZARD, MF_BYCOMMAND);
  10406. }
  10407. // Description:
  10408. // Used to initialize the entries of the "View" menu and its associated
  10409. // submenus whenever a soft barrier is not being displayed.
  10410. //
  10411. void CDefView::_InitViewMenuWhenBarrierNotDisplayed(HMENU hmenuView)
  10412. {
  10413. DWORD dwListViewFlags = ListView_GetExtendedListViewStyle(_hwndListview);
  10414. UINT uEnabled = (MF_ENABLED | MF_BYCOMMAND);
  10415. UINT uDisabled = (MF_GRAYED | MF_BYCOMMAND);
  10416. UINT uChecked = (MF_CHECKED | MF_BYCOMMAND);
  10417. UINT uUnchecked = (MF_UNCHECKED | MF_BYCOMMAND);
  10418. UINT uAAEnable; // Auto Arrange
  10419. UINT uAACheck;
  10420. UINT uAGrEnable; // Align to Grid
  10421. UINT uAGrCheck;
  10422. // Initialize "view" menu entries.
  10423. _InitViewMenuViewsWhenBarrierNotDisplayed(hmenuView);
  10424. // Initialize "Arrange Icons By ->" submenu.
  10425. _InitArrangeMenu(hmenuView);
  10426. // Determine and set appropriate enable state for "Auto Arrange" and "Align to Grid".
  10427. if (_IsPositionedView() && _IsListviewVisible() && !(_fs.ViewMode == FVM_THUMBSTRIP))
  10428. uAAEnable = uAGrEnable = uEnabled;
  10429. else
  10430. uAAEnable = uAGrEnable = uDisabled;
  10431. EnableMenuItem(hmenuView, SFVIDM_ARRANGE_AUTO, uAAEnable);
  10432. EnableMenuItem(hmenuView, SFVIDM_ARRANGE_AUTOGRID, uAGrEnable);
  10433. // Determine and set appropriate check state for "Auto Arrange" and "Align to Grid".
  10434. uAACheck = (((uAAEnable == uEnabled) || _fGroupView || (_fs.ViewMode == FVM_THUMBSTRIP)) && _IsAutoArrange())
  10435. ? uChecked
  10436. : uUnchecked;
  10437. uAGrCheck = (((uAGrEnable == uEnabled) || _fGroupView) && (dwListViewFlags & LVS_EX_SNAPTOGRID))
  10438. ? uChecked
  10439. : uUnchecked;
  10440. CheckMenuItem(hmenuView, SFVIDM_ARRANGE_AUTO, uAACheck);
  10441. CheckMenuItem(hmenuView, SFVIDM_ARRANGE_AUTOGRID, uAGrCheck);
  10442. // If icons are not being shown (such as can be set on the
  10443. // desktop), disable ALL icon-arrangement related commands.
  10444. if (!_IsListviewVisible())
  10445. {
  10446. HMENU hArrangeSubMenu;
  10447. UINT uID;
  10448. int i = 0;
  10449. // Retrieve "Arrange Icons By ->" submenu.
  10450. hArrangeSubMenu = GetSubMenu(hmenuView, 2);
  10451. // Iterate and disable until we get to "Show Icons".
  10452. while (1)
  10453. {
  10454. uID = GetMenuItemID(hArrangeSubMenu, i);
  10455. if ((uID == SFVIDM_DESKTOPHTML_ICONS) || (uID == (UINT)-1))
  10456. break;
  10457. else
  10458. EnableMenuItem(hArrangeSubMenu, i, MF_GRAYED | MF_BYPOSITION);
  10459. i++;
  10460. }
  10461. }
  10462. else if (!_ShouldShowWebView())
  10463. {
  10464. // If Web View is off, then thumbstrip will never work...
  10465. DeleteMenu(hmenuView, SFVIDM_VIEW_THUMBSTRIP, MF_BYCOMMAND);
  10466. }
  10467. // Remove "Customize This Folder..." if folder is not customizable.
  10468. if (!_CachedIsCustomizable())
  10469. {
  10470. // The Folder Option "Classic style" and the shell restriction WIN95CLASSIC
  10471. // should be the same. (Per ChristoB, otherwise admin's never understand what
  10472. // the restriction means.) Since we want this to change DEFAULTs, and still
  10473. // allow the user to turn on Web View, we don't remove the customize wizard here.
  10474. int iIndex = MenuIndexFromID(hmenuView, SFVIDM_VIEW_CUSTOMWIZARD);
  10475. if (iIndex != -1)
  10476. {
  10477. DeleteMenu(hmenuView, iIndex + 1, MF_BYPOSITION); // Remove Menu seperator
  10478. DeleteMenu(hmenuView, iIndex, MF_BYPOSITION); // Remove Customize
  10479. }
  10480. }
  10481. }
  10482. // Description:
  10483. // Initializes the "view" entries on a view menu. This involves stripping
  10484. // out any "view" entries for unsupported views, and additionally checking
  10485. // of the appropriate "view" entry for the current view.
  10486. //
  10487. // Note:
  10488. // This method should not be called if a soft barrier is being displayed.
  10489. // Remember that in this case there is no concept of a view, so why
  10490. // would someone be attempting to initialize "view" menu entries.
  10491. //
  10492. void CDefView::_InitViewMenuViewsWhenBarrierNotDisplayed(HMENU hmenuView)
  10493. {
  10494. ASSERT(!_fBarrierDisplayed);
  10495. // Remove menu entries for unsupported views.
  10496. for (UINT fvm = FVM_FIRST; fvm <= FVM_LAST; fvm++)
  10497. if (!_ViewSupported(fvm))
  10498. DeleteMenu(hmenuView, SFVIDM_VIEW_FIRSTVIEW + fvm - FVM_FIRST, MF_BYCOMMAND);
  10499. // "Check" menu entry for current view.
  10500. CheckCurrentViewMenuItem(hmenuView);
  10501. }
  10502. void CDefView::_GetCBText(UINT_PTR id, UINT uMsgT, UINT uMsgA, UINT uMsgW, LPTSTR psz, UINT cch)
  10503. {
  10504. *psz = 0;
  10505. WCHAR szW[MAX_PATH];
  10506. if (SUCCEEDED(CallCB(uMsgW, MAKEWPARAM(id - SFVIDM_CLIENT_FIRST, ARRAYSIZE(szW)), (LPARAM)szW)))
  10507. SHUnicodeToTChar(szW, psz, cch);
  10508. else
  10509. {
  10510. char szA[MAX_PATH];
  10511. if (SUCCEEDED(CallCB(uMsgA, MAKEWPARAM(id - SFVIDM_CLIENT_FIRST, ARRAYSIZE(szA)), (LPARAM)szA)))
  10512. SHAnsiToTChar(szA, psz, cch);
  10513. else
  10514. CallCB(uMsgT, MAKEWPARAM(id - SFVIDM_CLIENT_FIRST, cch), (LPARAM)psz);
  10515. }
  10516. }
  10517. void CDefView::_GetMenuHelpText(UINT_PTR id, LPTSTR pszText, UINT cchText)
  10518. {
  10519. *pszText = 0;
  10520. if ((InRange(id, SFVIDM_CONTEXT_FIRST, SFVIDM_CONTEXT_LAST) && _pcmFile) ||
  10521. (InRange(id, SFVIDM_BACK_CONTEXT_FIRST, SFVIDM_BACK_CONTEXT_LAST) && _pcmContextMenuPopup))
  10522. {
  10523. UINT uCMBias = SFVIDM_CONTEXT_FIRST;
  10524. IContextMenu *pcmSel = NULL;
  10525. if (InRange(id, SFVIDM_CONTEXT_FIRST, SFVIDM_CONTEXT_LAST))
  10526. {
  10527. pcmSel = _pcmFile;
  10528. uCMBias = SFVIDM_CONTEXT_FIRST;
  10529. }
  10530. else if (InRange(id, SFVIDM_BACK_CONTEXT_FIRST, SFVIDM_BACK_CONTEXT_LAST))
  10531. {
  10532. pcmSel = _pcmContextMenuPopup;
  10533. uCMBias = SFVIDM_BACK_CONTEXT_FIRST;
  10534. }
  10535. // First try to get the stardard help string
  10536. pcmSel->GetCommandString(id - uCMBias, GCS_HELPTEXT, NULL,
  10537. (LPSTR)pszText, cchText);
  10538. if (*pszText == 0)
  10539. {
  10540. // If we didn't get anything, try to grab the ansi version
  10541. CHAR szText[MAX_PATH];
  10542. szText[0] = 0; // Don't start with garbage in case of failure...
  10543. pcmSel->GetCommandString(id - uCMBias, GCS_HELPTEXTA, NULL,
  10544. szText, ARRAYSIZE(szText));
  10545. SHAnsiToUnicode(szText, pszText, cchText);
  10546. }
  10547. }
  10548. else if (InRange(id, SFVIDM_CLIENT_FIRST, SFVIDM_CLIENT_LAST) && HasCB())
  10549. {
  10550. _GetCBText(id, SFVM_GETHELPTEXT, SFVM_GETHELPTEXTA, SFVM_GETHELPTEXTW, pszText, cchText);
  10551. }
  10552. else if (InRange(id, SFVIDM_GROUPSFIRST, SFVIDM_GROUPSLAST))
  10553. {
  10554. TCHAR sz[MAX_PATH];
  10555. int idHelp = _fGroupView?IDS_GROUPBY_HELPTEXT:IDS_ARRANGEBY_HELPTEXT;
  10556. LoadString(HINST_THISDLL, idHelp, sz, ARRAYSIZE(sz));
  10557. wsprintf(pszText, sz, _vs.GetColumnName((UINT)id - SFVIDM_GROUPSFIRST));
  10558. }
  10559. else if (InRange(id, SFVIDM_GROUPSEXTENDEDFIRST, SFVIDM_GROUPSEXTENDEDLAST))
  10560. {
  10561. // Can't think of anything descriptive
  10562. }
  10563. else if (InRange(id, SFVIDM_FIRST, SFVIDM_LAST))
  10564. {
  10565. if ((id == SFVIDM_EDIT_UNDO) && IsUndoAvailable())
  10566. {
  10567. GetUndoText(pszText, cchText, UNDO_STATUSTEXT);
  10568. }
  10569. else
  10570. {
  10571. UINT idHelp = (UINT)id + SFVIDS_MH_FIRST;
  10572. // Unfortunatly, this starts to hit other ranges, so I'm just hard coding this one instead of
  10573. // using the table. If you add more, we need another table method of associating ids and help strings
  10574. if (id == SFVIDM_GROUPBY)
  10575. idHelp = IDS_GROUPBYITEM_HELPTEXT;
  10576. LoadString(HINST_THISDLL, idHelp, pszText, cchText);
  10577. }
  10578. }
  10579. }
  10580. void CDefView::_GetToolTipText(UINT_PTR id, LPTSTR pszText, UINT cchText)
  10581. {
  10582. VDATEINPUTBUF(pszText, TCHAR, cchText);
  10583. *pszText = 0;
  10584. if (InRange(id, SFVIDM_CLIENT_FIRST, SFVIDM_CLIENT_LAST) && HasCB())
  10585. {
  10586. _GetCBText(id, SFVM_GETTOOLTIPTEXT, SFVM_GETTOOLTIPTEXTA, SFVM_GETTOOLTIPTEXTW, pszText, cchText);
  10587. }
  10588. else if (InRange(id, SFVIDM_FIRST, SFVIDM_LAST))
  10589. {
  10590. if (id == SFVIDM_EDIT_UNDO)
  10591. {
  10592. if (IsUndoAvailable())
  10593. {
  10594. GetUndoText(pszText, cchText, UNDO_MENUTEXT);
  10595. return;
  10596. }
  10597. }
  10598. LoadString(HINST_THISDLL, (UINT)(IDS_TT_SFVIDM_FIRST + id), pszText, cchText);
  10599. }
  10600. else
  10601. {
  10602. // REVIEW: This might be an assert situation: missing tooltip info...
  10603. TraceMsg(TF_WARNING, "_GetToolTipText: tip request for unknown object");
  10604. }
  10605. }
  10606. LRESULT CDefView::_OnMenuSelect(UINT id, UINT mf, HMENU hmenu)
  10607. {
  10608. TCHAR szHelpText[80 + 2*MAX_PATH]; // Lots of stack!
  10609. // If we dismissed the edit restore our status bar...
  10610. if (!hmenu && LOWORD(mf)==0xffff)
  10611. {
  10612. _psb->SendControlMsg(FCW_STATUS, SB_SIMPLE, 0, 0, NULL);
  10613. return 0;
  10614. }
  10615. if (mf & (MF_SYSMENU | MF_SEPARATOR))
  10616. return 0;
  10617. szHelpText[0] = 0; // in case of failures below
  10618. if (mf & MF_POPUP)
  10619. {
  10620. MENUITEMINFO miiSubMenu;
  10621. miiSubMenu.cbSize = sizeof(MENUITEMINFO);
  10622. miiSubMenu.fMask = MIIM_ID;
  10623. miiSubMenu.cch = 0; // just in case
  10624. if (!GetMenuItemInfo(hmenu, id, TRUE, &miiSubMenu))
  10625. return 0;
  10626. // Change the parameters to simulate a "normal" menu item
  10627. id = miiSubMenu.wID;
  10628. mf &= ~MF_POPUP;
  10629. }
  10630. _GetMenuHelpText(id, szHelpText, ARRAYSIZE(szHelpText));
  10631. _fBackgroundStatusTextValid = FALSE;
  10632. _psb->SendControlMsg(FCW_STATUS, SB_SETTEXT, SBT_NOBORDERS | 255, (LPARAM)szHelpText, NULL);
  10633. _psb->SendControlMsg(FCW_STATUS, SB_SIMPLE, 1, 0, NULL);
  10634. return 0;
  10635. }
  10636. //
  10637. // This function dismisses the name edit mode if there is any.
  10638. //
  10639. // REVIEW: Moving the focus away from the edit window will
  10640. // dismiss the name edit mode. Should we introduce
  10641. // a LV_DISMISSEDIT instead?
  10642. //
  10643. void CDefView::_DismissEdit()
  10644. {
  10645. if (_uState == SVUIA_ACTIVATE_FOCUS)
  10646. {
  10647. ListView_CancelEditLabel(_hwndListview);
  10648. }
  10649. }
  10650. void CDefView::_OnInitMenu()
  10651. {
  10652. // We need to dismiss the edit mode if it is any.
  10653. _DismissEdit();
  10654. }
  10655. void _RemoveContextMenuItems(HMENU hmInit)
  10656. {
  10657. int i;
  10658. for (i = GetMenuItemCount(hmInit) - 1; i >= 0; --i)
  10659. {
  10660. MENUITEMINFO mii;
  10661. mii.cbSize = sizeof(mii);
  10662. mii.fMask = MIIM_ID | MIIM_ID;
  10663. mii.cch = 0; // just in case
  10664. if (GetMenuItemInfo(hmInit, i, TRUE, &mii))
  10665. {
  10666. if (InRange(mii.wID, SFVIDM_CONTEXT_FIRST, SFVIDM_CONTEXT_LAST))
  10667. {
  10668. TraceMsg(TF_DEFVIEW, "_RemoveContextMenuItems: setting bDeleteItems at %d, %d", i, mii.wID);
  10669. //bDeleteItems = TRUE;
  10670. DeleteMenu(hmInit, i, MF_BYPOSITION);
  10671. }
  10672. }
  10673. }
  10674. }
  10675. BOOL HasClientItems(HMENU hmenu)
  10676. {
  10677. int cItems = GetMenuItemCount(hmenu);
  10678. for (int i = 0; i < cItems; i++)
  10679. {
  10680. UINT id = GetMenuItemID(hmenu, i);
  10681. if (InRange(id, SFVIDM_CLIENT_FIRST, SFVIDM_CLIENT_LAST))
  10682. return TRUE;
  10683. }
  10684. return FALSE;
  10685. }
  10686. LRESULT CDefView::_OnInitMenuPopup(HMENU hmInit, int nIndex, BOOL fSystemMenu)
  10687. {
  10688. if (_hmenuCur)
  10689. {
  10690. // This old code makes sure we only switch on the wID for one of our top-level windows
  10691. // The id shouldn't be re-used, so this probably isn't needed. But it doesn't hurt...
  10692. //
  10693. MENUITEMINFO mii = {0};
  10694. mii.cbSize = sizeof(mii);
  10695. mii.fMask = MIIM_SUBMENU | MIIM_ID;
  10696. if (GetMenuItemInfo(_hmenuCur, nIndex, TRUE, &mii) && mii.hSubMenu == hmInit)
  10697. {
  10698. switch (mii.wID)
  10699. {
  10700. case FCIDM_MENU_FILE:
  10701. // PERF note: we could avoid the rip-down-and-re-build our File menu
  10702. // if we have a _pcmFile and the _uState is the same as last
  10703. // time and the selection is identical to last time.
  10704. // First of all, clean up our last _pcmFile usage:
  10705. // remove all the menu items we've added
  10706. // remove the named separators for defcm
  10707. _RemoveContextMenuItems(hmInit);
  10708. SHUnprepareMenuForDefcm(hmInit, SFVIDM_CONTEXT_FIRST, SFVIDM_CONTEXT_LAST);
  10709. IUnknown_SetSite(_pcmFile, NULL);
  10710. ATOMICRELEASE(_pcmFile);
  10711. // Second, handle the focus/nofocus menus
  10712. if (_uState == SVUIA_ACTIVATE_FOCUS)
  10713. {
  10714. // Enable/disable our menuitems in the "File" pulldown.
  10715. Def_InitFileCommands(_AttributesFromSel(SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_CANLINK | SFGAO_HASPROPSHEET),
  10716. hmInit, SFVIDM_FIRST, FALSE);
  10717. // Collect our new _pcmFile context menu
  10718. IContextMenu* pcmSel = NULL;
  10719. _CreateSelectionContextMenu(IID_PPV_ARG(IContextMenu, &pcmSel));
  10720. IContextMenu* pcmBack = NULL;
  10721. _pshf->CreateViewObject(_hwndMain, IID_PPV_ARG(IContextMenu, &pcmBack));
  10722. IContextMenu* rgpcm[] = { pcmSel, pcmBack };
  10723. Create_ContextMenuOnContextMenuArray(rgpcm, ARRAYSIZE(rgpcm), IID_PPV_ARG(IContextMenu, &_pcmFile));
  10724. if (pcmSel)
  10725. pcmSel->Release();
  10726. if (pcmBack)
  10727. pcmBack->Release();
  10728. }
  10729. else if (_uState == SVUIA_ACTIVATE_NOFOCUS)
  10730. {
  10731. _pshf->CreateViewObject(_hwndMain, IID_PPV_ARG(IContextMenu, &_pcmFile));
  10732. }
  10733. // Third, merge in the context menu items
  10734. {
  10735. HRESULT hrPrepare = SHPrepareMenuForDefcm(hmInit, 0, 0, SFVIDM_CONTEXT_FIRST, SFVIDM_CONTEXT_LAST);
  10736. if (_pcmFile)
  10737. {
  10738. IUnknown_SetSite(_pcmFile, SAFECAST(this, IShellView2*));
  10739. _pcmFile->QueryContextMenu(hmInit, 0, SFVIDM_CONTEXT_FIRST, SFVIDM_CONTEXT_LAST, CMF_DVFILE | CMF_NODEFAULT);
  10740. }
  10741. SHPrettyMenuForDefcm(hmInit, 0, SFVIDM_CONTEXT_FIRST, SFVIDM_CONTEXT_LAST, hrPrepare);
  10742. }
  10743. break;
  10744. case FCIDM_MENU_EDIT:
  10745. // Enable/disable menuitems in the "Edit" pulldown.
  10746. Def_InitEditCommands(_AttributesFromSel(SFGAO_CANCOPY | SFGAO_CANMOVE), hmInit, SFVIDM_FIRST, _pdtgtBack, 0);
  10747. _SHPrettyMenu(hmInit);
  10748. break;
  10749. case FCIDM_MENU_VIEW:
  10750. InitViewMenu(hmInit);
  10751. break;
  10752. }
  10753. }
  10754. }
  10755. // Check for a context menu's popup:
  10756. // assume the first item in the menu identifies the range
  10757. BOOL fHandled;
  10758. _ForwardMenuMessages(GetMenuItemID(hmInit, 0), WM_INITMENUPOPUP, (WPARAM)hmInit, MAKELPARAM(nIndex, fSystemMenu), NULL, &fHandled);
  10759. // Maybe this is the callback's menu then?
  10760. if (!fHandled && _hmenuCur && HasCB() && HasClientItems(hmInit))
  10761. {
  10762. CallCB(SFVM_INITMENUPOPUP, MAKEWPARAM(SFVIDM_CLIENT_FIRST, nIndex), (LPARAM)hmInit);
  10763. }
  10764. return 0;
  10765. }
  10766. // IShellView::AddPropertySheetPages
  10767. STDMETHODIMP CDefView::AddPropertySheetPages(DWORD dwRes, LPFNADDPROPSHEETPAGE lpfn, LPARAM lParam)
  10768. {
  10769. SFVM_PROPPAGE_DATA data;
  10770. ASSERT(IS_VALID_CODE_PTR(lpfn, FNADDPROPSHEETPAGE));
  10771. data.dwReserved = dwRes;
  10772. data.pfn = lpfn;
  10773. data.lParam = lParam;
  10774. // Call the callback to add pages
  10775. CallCB(SFVM_ADDPROPERTYPAGES, 0, (LPARAM)&data);
  10776. return S_OK;
  10777. }
  10778. STDMETHODIMP CDefView::SaveViewState()
  10779. {
  10780. HRESULT hr;
  10781. IPropertyBag* ppb;
  10782. hr = IUnknown_QueryServicePropertyBag(_psb, SHGVSPB_FOLDER, IID_PPV_ARG(IPropertyBag, &ppb));
  10783. if (SUCCEEDED(hr))
  10784. {
  10785. hr = _vs.SaveToPropertyBag(this, ppb);
  10786. ppb->Release();
  10787. }
  10788. else
  10789. {
  10790. IStream *pstm;
  10791. hr = _psb->GetViewStateStream(STGM_WRITE, &pstm);
  10792. if (SUCCEEDED(hr))
  10793. {
  10794. hr = _vs.SaveToStream(this, pstm);
  10795. pstm->Release();
  10796. }
  10797. else
  10798. {
  10799. // There are cases where we may not save out the complete view state
  10800. // but we do want to save out the column information (like Docfind...)
  10801. if (SUCCEEDED(CallCB(SFVM_GETCOLSAVESTREAM, STGM_READ, (LPARAM)&pstm)))
  10802. {
  10803. hr = _vs.SaveColumns(this, pstm);
  10804. pstm->Release();
  10805. }
  10806. }
  10807. }
  10808. return hr;
  10809. }
  10810. // 99/02/05 #226140 vtan: Function used to get the storage
  10811. // stream for the default view state of the current DefView.
  10812. // Typically this will be CLSID_ShellFSFolder but can be
  10813. // others.
  10814. HRESULT CDefView::_GetStorageStream (DWORD grfMode, IStream* *ppIStream)
  10815. {
  10816. *ppIStream = NULL;
  10817. CLSID clsid;
  10818. HRESULT hr = IUnknown_GetClassID(_pshf, &clsid);
  10819. if (SUCCEEDED(hr))
  10820. {
  10821. TCHAR szCLSID[64]; // enough for the CLSID
  10822. if (IsEqualGUID(CLSID_MyDocuments, clsid))
  10823. clsid = CLSID_ShellFSFolder;
  10824. TINT(SHStringFromGUID(clsid, szCLSID, ARRAYSIZE(szCLSID)));
  10825. *ppIStream = OpenRegStream(HKEY_CURRENT_USER,
  10826. REGSTR_PATH_EXPLORER TEXT("\\Streams\\Defaults"), szCLSID, grfMode);
  10827. if (*ppIStream == NULL)
  10828. hr = E_FAIL;
  10829. }
  10830. return hr;
  10831. }
  10832. // 99/02/05 #226140 vtan: Function called from DefView's
  10833. // implementation of IOleCommandTarget::Exec() which is
  10834. // invoked from CShellBrowser2::SetAsDefFolderSettings().
  10835. HRESULT CDefView::_SaveGlobalViewState(void)
  10836. {
  10837. IStream *pstm;
  10838. HRESULT hr = _GetStorageStream(STGM_WRITE, &pstm);
  10839. if (SUCCEEDED(hr))
  10840. {
  10841. hr = _vs.SaveToStream(this, pstm);
  10842. if (SUCCEEDED(hr))
  10843. {
  10844. hr = (ERROR_SUCCESS == SHDeleteKey(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Windows\\ShellNoRoam\\Bags"))) ? S_OK : E_FAIL;
  10845. }
  10846. pstm->Release();
  10847. }
  10848. return hr;
  10849. }
  10850. // 99/02/05 #226140 vtan: Function called from
  10851. // GetViewState to get the default view state
  10852. // for this class.
  10853. HRESULT CDefView::_LoadGlobalViewState(IStream* *ppIStream)
  10854. {
  10855. return _GetStorageStream(STGM_READ, ppIStream);
  10856. }
  10857. // 99/02/09 #226140 vtan: Function used to reset the
  10858. // global view states stored by deleting the key
  10859. // that stores all of them.
  10860. HRESULT CDefView::_ResetGlobalViewState(void)
  10861. {
  10862. SHDeleteKey(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER TEXT("\\Streams\\Defaults"));
  10863. LONG lRetVal = SHDeleteKey(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Windows\\ShellNoRoam\\Bags"));
  10864. return (ERROR_SUCCESS == lRetVal) ? S_OK : E_FAIL;
  10865. }
  10866. void CDefView::_RestoreAllGhostedFileView()
  10867. {
  10868. ListView_SetItemState(_hwndListview, -1, 0, LVIS_CUT);
  10869. UINT c = ListView_GetItemCount(_hwndListview);
  10870. for (UINT i = 0; i < c; i++)
  10871. {
  10872. if (_Attributes(_GetPIDL(i), SFGAO_GHOSTED))
  10873. ListView_SetItemState(_hwndListview, i, LVIS_CUT, LVIS_CUT);
  10874. }
  10875. }
  10876. HRESULT CDefView::SelectAndPositionItem(LPCITEMIDLIST pidlItem, UINT uFlags, POINT *ppt)
  10877. {
  10878. HRESULT hr;
  10879. if (NULL == pidlItem)
  10880. hr = _SelectAndPosition(-1, uFlags, ppt);
  10881. else if (ILFindLastID(pidlItem) == pidlItem)
  10882. {
  10883. if (_fInBackgroundGrouping)
  10884. {
  10885. Pidl_Set(&_pidlSelectAndPosition, pidlItem);
  10886. _uSelectAndPositionFlags = uFlags;
  10887. hr = S_OK;
  10888. }
  10889. else
  10890. {
  10891. int iItem = _FindItem(pidlItem, NULL, FALSE);
  10892. if (iItem != -1)
  10893. hr = _SelectAndPosition(iItem, uFlags, ppt);
  10894. else
  10895. hr = S_OK;
  10896. }
  10897. }
  10898. else
  10899. {
  10900. RIP(ILFindLastID(pidlItem) == pidlItem);
  10901. hr = E_INVALIDARG;
  10902. }
  10903. return hr;
  10904. }
  10905. HRESULT CDefView::_SelectAndPosition(int iItem, UINT uFlags, POINT *ppt)
  10906. {
  10907. HRESULT hr = S_OK; // assume all is good
  10908. // See if we should first deselect everything else
  10909. if (-1 == iItem)
  10910. {
  10911. if (uFlags == SVSI_DESELECTOTHERS)
  10912. {
  10913. ListView_SetItemState(_hwndListview, -1, 0, LVIS_SELECTED);
  10914. _RestoreAllGhostedFileView();
  10915. }
  10916. else
  10917. {
  10918. hr = E_INVALIDARG; // I only know how to deselect everything
  10919. }
  10920. }
  10921. else
  10922. {
  10923. if (_pDUIView)
  10924. {
  10925. _fBarrierDisplayed = FALSE;
  10926. _pDUIView->EnableBarrier(FALSE);
  10927. }
  10928. if (uFlags & SVSI_TRANSLATEPT)
  10929. {
  10930. //The caller is asking us to take this point and convert it from screen Coords
  10931. // to the Client of the Listview.
  10932. LVUtil_ScreenToLV(_hwndListview, ppt);
  10933. }
  10934. // set the position first so that the ensure visible scrolls to
  10935. // the new position
  10936. if (ppt)
  10937. {
  10938. _SetItemPosition(iItem, ppt->x, ppt->y);
  10939. }
  10940. else if ((SVSI_POSITIONITEM & uFlags) && _bMouseMenu && _IsPositionedView())
  10941. {
  10942. _SetItemPosition(iItem, _ptDragAnchor.x, _ptDragAnchor.y);
  10943. }
  10944. if ((uFlags & SVSI_EDIT) == SVSI_EDIT)
  10945. {
  10946. // Grab focus if the listview (or any of it's children) don't already have focus
  10947. HWND hwndFocus = GetFocus();
  10948. if (SHIsChildOrSelf(_hwndListview, hwndFocus) != S_OK)
  10949. SetFocus(_hwndListview);
  10950. ListView_EditLabel(_hwndListview, iItem);
  10951. }
  10952. else
  10953. {
  10954. // change the item state
  10955. if (!(uFlags & SVSI_NOSTATECHANGE))
  10956. {
  10957. UINT stateMask = LVIS_SELECTED;
  10958. UINT state = (uFlags & SVSI_SELECT) ? LVIS_SELECTED : 0;
  10959. if (uFlags & SVSI_FOCUSED)
  10960. {
  10961. state |= LVIS_FOCUSED;
  10962. stateMask |= LVIS_FOCUSED;
  10963. }
  10964. // See if we should first deselect everything else
  10965. if (uFlags & SVSI_DESELECTOTHERS)
  10966. {
  10967. ListView_SetItemState(_hwndListview, -1, 0, LVIS_SELECTED);
  10968. _RestoreAllGhostedFileView();
  10969. }
  10970. ListView_SetItemState(_hwndListview, iItem, state, stateMask);
  10971. }
  10972. if (uFlags & SVSI_ENSUREVISIBLE)
  10973. ListView_EnsureVisible(_hwndListview, iItem, FALSE);
  10974. // we should only set focus when SVUIA_ACTIVATE_FOCUS
  10975. // bug fixing that might break find target code
  10976. if (uFlags & SVSI_FOCUSED)
  10977. SetFocus(_hwndListview);
  10978. if (uFlags & SVSI_SELECTIONMARK)
  10979. ListView_SetSelectionMark(_hwndListview, iItem);
  10980. // if this is a check select view then set the state of that item accordingly
  10981. if (_fs.fFlags & FWF_CHECKSELECT)
  10982. ListView_SetCheckState(_hwndListview, iItem, (uFlags & SVSI_CHECK));
  10983. }
  10984. }
  10985. return hr;
  10986. }
  10987. STDMETHODIMP CDefView::SelectItem(int iItem, DWORD uFlags)
  10988. {
  10989. return _SelectAndPosition(iItem, uFlags, NULL);
  10990. }
  10991. typedef struct {
  10992. LPITEMIDLIST pidl;
  10993. UINT uFlagsSelect;
  10994. } DELAY_SEL_ITEM;
  10995. STDMETHODIMP CDefView::SelectItem(LPCITEMIDLIST pidlItem, UINT uFlags)
  10996. {
  10997. // if the listview isn't shown, there's nothing to select yet.
  10998. // Likewise if we are in the process of being created we should defer.
  10999. if (!_IsListviewVisible())
  11000. {
  11001. if (!_hdsaSelect)
  11002. {
  11003. _hdsaSelect = DSA_Create(sizeof(DELAY_SEL_ITEM), 4);
  11004. if (!_hdsaSelect)
  11005. return E_OUTOFMEMORY;
  11006. }
  11007. HRESULT hr = E_OUTOFMEMORY;
  11008. DELAY_SEL_ITEM dvdsi;
  11009. dvdsi.pidl = ILClone(pidlItem);
  11010. if (dvdsi.pidl)
  11011. {
  11012. dvdsi.uFlagsSelect = uFlags;
  11013. if (DSA_AppendItem(_hdsaSelect, &dvdsi) == DSA_ERR)
  11014. ILFree(dvdsi.pidl);
  11015. else
  11016. hr = S_OK;
  11017. }
  11018. return hr;
  11019. }
  11020. return SelectAndPositionItem(pidlItem, uFlags, NULL);
  11021. }
  11022. // IFolderView
  11023. STDMETHODIMP CDefView::GetCurrentViewMode(UINT *pViewMode)
  11024. {
  11025. *pViewMode = _fs.ViewMode;
  11026. return S_OK;
  11027. }
  11028. STDMETHODIMP CDefView::SetCurrentViewMode(UINT uViewMode)
  11029. {
  11030. ASSERT(FVM_FIRST <= uViewMode && uViewMode <= FVM_LAST);
  11031. if (uViewMode != _vs._ViewMode)
  11032. _ClearItemPositions();
  11033. return _SwitchToViewFVM(uViewMode);
  11034. }
  11035. STDMETHODIMP CDefView::GetFolder(REFIID riid, void **ppv)
  11036. {
  11037. if (_pshf)
  11038. return _pshf->QueryInterface(riid, ppv);
  11039. *ppv = NULL;
  11040. return E_NOINTERFACE;
  11041. }
  11042. STDMETHODIMP CDefView::Item(int iItemIndex, LPITEMIDLIST *ppidl)
  11043. {
  11044. HRESULT hr = E_FAIL;
  11045. LPCITEMIDLIST pidl = _GetPIDL(iItemIndex);
  11046. if (pidl)
  11047. {
  11048. hr = SHILClone(pidl, ppidl);
  11049. }
  11050. return hr;
  11051. }
  11052. STDMETHODIMP CDefView::ItemCount(UINT uFlags, int *pcItems)
  11053. {
  11054. *pcItems = _GetItemArray(NULL, NULL, uFlags);
  11055. return S_OK;
  11056. }
  11057. HRESULT CDefView::_EnumThings(UINT uWhat, IEnumIDList **ppenum)
  11058. {
  11059. *ppenum = NULL;
  11060. LPCITEMIDLIST *apidl;
  11061. UINT cItems;
  11062. HRESULT hr = _GetItemObjects(&apidl, uWhat, &cItems);
  11063. if (SUCCEEDED(hr))
  11064. {
  11065. hr = CreateIEnumIDListOnIDLists(apidl, cItems, ppenum);
  11066. LocalFree(apidl);
  11067. }
  11068. return hr;
  11069. }
  11070. STDMETHODIMP CDefView::Items(UINT uWhat, REFIID riid, void **ppv)
  11071. {
  11072. HRESULT hr = E_NOINTERFACE;
  11073. if (IID_IEnumIDList == riid)
  11074. {
  11075. hr = _EnumThings(uWhat, (IEnumIDList**)ppv);
  11076. }
  11077. else if (IID_IDataObject == riid)
  11078. {
  11079. if ((uWhat & SVGIO_TYPE_MASK) == SVGIO_SELECTION)
  11080. {
  11081. if (_pSelectionShellItemArray)
  11082. {
  11083. hr = _pSelectionShellItemArray->BindToHandler(NULL, BHID_DataObject, riid, ppv);
  11084. }
  11085. }
  11086. else
  11087. {
  11088. hr = _GetUIObjectFromItem(riid, ppv, uWhat, FALSE);
  11089. }
  11090. }
  11091. return hr;
  11092. }
  11093. // inverse of ::SelectItem(..., SVSI_SELECTIONMARK)
  11094. STDMETHODIMP CDefView::GetSelectionMarkedItem(int *piItem)
  11095. {
  11096. *piItem = ListView_GetSelectionMark(_hwndListview);
  11097. return (-1 == *piItem) ? S_FALSE : S_OK;
  11098. }
  11099. STDMETHODIMP CDefView::GetFocusedItem(int *piItem)
  11100. {
  11101. *piItem = ListView_GetNextItem(_hwndListview, -1, LVNI_FOCUSED);
  11102. return (-1 == *piItem) ? S_FALSE : S_OK;
  11103. }
  11104. BOOL CDefView::_GetItemPosition(LPCITEMIDLIST pidl, POINT *ppt)
  11105. {
  11106. int i = _FindItem(pidl, NULL, FALSE);
  11107. if (i != -1)
  11108. return ListView_GetItemPosition(_hwndListview, i, ppt);
  11109. return FALSE;
  11110. }
  11111. STDMETHODIMP CDefView::GetItemPosition(LPCITEMIDLIST pidl, POINT *ppt)
  11112. {
  11113. return _GetItemPosition(pidl, ppt) ? S_OK : E_FAIL;
  11114. }
  11115. STDMETHODIMP CDefView::GetSpacing(POINT* ppt)
  11116. {
  11117. if (ppt)
  11118. {
  11119. if (_fs.ViewMode != FVM_TILE)
  11120. {
  11121. BOOL fSmall;
  11122. switch (_fs.ViewMode)
  11123. {
  11124. case FVM_SMALLICON:
  11125. case FVM_LIST:
  11126. case FVM_DETAILS:
  11127. fSmall = TRUE;
  11128. break;
  11129. case FVM_ICON:
  11130. case FVM_THUMBNAIL:
  11131. case FVM_THUMBSTRIP:
  11132. default:
  11133. fSmall = FALSE;
  11134. break;
  11135. }
  11136. DWORD dwSize = ListView_GetItemSpacing(_hwndListview, fSmall);
  11137. ppt->x = GET_X_LPARAM(dwSize);
  11138. ppt->y = GET_Y_LPARAM(dwSize);
  11139. }
  11140. else
  11141. {
  11142. LVTILEVIEWINFO tvi;
  11143. tvi.cbSize = sizeof(tvi);
  11144. tvi.dwMask = LVTVIM_TILESIZE;
  11145. if (ListView_GetTileViewInfo(_hwndListview, &tvi))
  11146. {
  11147. ppt->x = tvi.sizeTile.cx;
  11148. ppt->y = tvi.sizeTile.cy;
  11149. }
  11150. else
  11151. {
  11152. // guess.
  11153. ppt->x = 216;
  11154. ppt->y = 56;
  11155. }
  11156. }
  11157. }
  11158. return _IsPositionedView() ? S_OK : S_FALSE;
  11159. }
  11160. STDMETHODIMP CDefView::GetDefaultSpacing(POINT* ppt)
  11161. {
  11162. ASSERT(ppt);
  11163. if (_fs.ViewMode != FVM_THUMBNAIL && _fs.ViewMode != FVM_THUMBSTRIP && _fs.ViewMode != FVM_TILE)
  11164. {
  11165. DWORD dwSize = ListView_GetItemSpacing(_hwndListview, FALSE);
  11166. ppt->x = GET_X_LPARAM(dwSize);
  11167. ppt->y = GET_Y_LPARAM(dwSize);
  11168. }
  11169. else
  11170. {
  11171. // Bug #163528 (edwardp 8/15/00) Should get this data from comctl.
  11172. ppt->x = GetSystemMetrics(SM_CXICONSPACING);
  11173. ppt->y = GetSystemMetrics(SM_CYICONSPACING);
  11174. }
  11175. return S_OK;
  11176. }
  11177. // IShellFolderView
  11178. STDMETHODIMP CDefView::GetAutoArrange()
  11179. {
  11180. return _IsAutoArrange() ? S_OK : S_FALSE;
  11181. }
  11182. void CDefView::_ClearPendingSelectedItems()
  11183. {
  11184. if (_hdsaSelect)
  11185. {
  11186. HDSA hdsa = _hdsaSelect;
  11187. _hdsaSelect = NULL;
  11188. int cItems = DSA_GetItemCount(hdsa);
  11189. for (int i = 0; i < cItems; i++)
  11190. {
  11191. DELAY_SEL_ITEM *pdvdsi = (DELAY_SEL_ITEM*)DSA_GetItemPtr(hdsa, i);
  11192. if (pdvdsi)
  11193. ILFree(pdvdsi->pidl);
  11194. }
  11195. DSA_Destroy(hdsa);
  11196. }
  11197. }
  11198. // Call this whenever the state changes such that SelectItem (above)
  11199. void CDefView::SelectPendingSelectedItems()
  11200. {
  11201. ASSERT(_IsListviewVisible());
  11202. if (_hdsaSelect)
  11203. {
  11204. //
  11205. // Listview quirk: If the following conditions are met..
  11206. //
  11207. // 1. WM_SETREDRAW(FALSE) or ShowWindow(SW_HIDE)
  11208. // 2. Listview has never painted yet
  11209. // 3. LVS_LIST
  11210. //
  11211. // then ListView_LGetRects doesn't work. And consequently,
  11212. // everything that relies on known item rectangles (e.g.,
  11213. // LVM_ENSUREVISIBLE, sent by below SelectItem call) doesn't work.
  11214. //
  11215. // (1) ShowHideListView did a ShowWindow(SW_SHOW), but
  11216. // FillDone does a WM_SETREDRAW(FALSE).
  11217. // check _fListviewRedraw to see if condition (1) is met
  11218. //
  11219. // (2) We just showed the listview, if it's the first time,
  11220. // then Condition (2) has been met
  11221. //
  11222. // But wait, there's also a listview bug where SetWindowPos
  11223. // doesn't trigger it into thinking that the window is visible.
  11224. // So you have to send a manual WM_SHOWWINDOW, too.
  11225. //
  11226. // So if we detect that condition (3) is also met, we temporarily
  11227. // enable redraw (thereby cancelling condition 1), tell listview
  11228. // "No really, you're visible" -- this tickles it into computing
  11229. // column stuff -- then turn redraw back off.
  11230. //
  11231. if (_fListviewRedraw &&
  11232. (GetWindowStyle(_hwndListview) & LVS_TYPEMASK) == LVS_LIST)
  11233. {
  11234. // Evil hack (fix comctl32.dll v6.0 someday NTRAID#182448)
  11235. SendMessage(_hwndListview, WM_SETREDRAW, (WPARAM)TRUE, 0);
  11236. SendMessage(_hwndListview, WM_SHOWWINDOW, TRUE, 0);
  11237. SendMessage(_hwndListview, WM_SETREDRAW, (WPARAM)FALSE, 0);
  11238. }
  11239. // End of listview hack workaround
  11240. HDSA hdsa = _hdsaSelect;
  11241. _hdsaSelect = NULL;
  11242. int cItems = DSA_GetItemCount(hdsa);
  11243. for (int i = 0; i < cItems; i++)
  11244. {
  11245. DELAY_SEL_ITEM *pdvdsi = (DELAY_SEL_ITEM*)DSA_GetItemPtr(hdsa, i);
  11246. if (pdvdsi)
  11247. {
  11248. SelectItem(pdvdsi->pidl, pdvdsi->uFlagsSelect);
  11249. ILFree(pdvdsi->pidl);
  11250. }
  11251. }
  11252. DSA_Destroy(hdsa);
  11253. }
  11254. }
  11255. HRESULT CDefView::_GetIPersistHistoryObject(IPersistHistory **ppph)
  11256. {
  11257. // See to see if specific folder wants to handle it...
  11258. HRESULT hr = CallCB(SFVM_GETIPERSISTHISTORY, 0, (LPARAM)ppph);
  11259. if (FAILED(hr))
  11260. {
  11261. // Here we can decide if we want to default should be to always save
  11262. // the default defview stuff or not. For now we will assume that we do
  11263. if (ppph)
  11264. {
  11265. CDefViewPersistHistory *pdvph = new CDefViewPersistHistory();
  11266. if (pdvph)
  11267. {
  11268. hr = pdvph->QueryInterface(IID_PPV_ARG(IPersistHistory, ppph));
  11269. pdvph->Release();
  11270. }
  11271. else
  11272. {
  11273. *ppph = NULL;
  11274. hr = E_OUTOFMEMORY;
  11275. }
  11276. }
  11277. else
  11278. hr = S_FALSE; // still succeeds but can detect on other side if desired...
  11279. }
  11280. return hr;
  11281. }
  11282. STDMETHODIMP CDefView::GetItemObject(UINT uWhat, REFIID riid, void **ppv)
  11283. {
  11284. HRESULT hr = E_NOINTERFACE;
  11285. *ppv = NULL;
  11286. switch (uWhat & SVGIO_TYPE_MASK)
  11287. {
  11288. case SVGIO_BACKGROUND:
  11289. if (IsEqualIID(riid, IID_IContextMenu) ||
  11290. IsEqualIID(riid, IID_IContextMenu2) ||
  11291. IsEqualIID(riid, IID_IContextMenu3))
  11292. {
  11293. hr = _CBackgrndMenu_CreateInstance(riid, ppv);
  11294. }
  11295. else if (IsEqualIID(riid, IID_IDispatch) ||
  11296. IsEqualIID(riid, IID_IDefViewScript))
  11297. {
  11298. if (!_pauto)
  11299. {
  11300. // try to create an Instance of the Shell disipatch for folder views...
  11301. IDispatch *pdisp;
  11302. if (SUCCEEDED(SHExtCoCreateInstance(NULL, &CLSID_ShellFolderView, NULL,
  11303. IID_PPV_ARG(IDispatch, &pdisp))))
  11304. {
  11305. SetAutomationObject(pdisp); // we hold a ref here
  11306. ASSERT(_pauto); // the above grabbed this
  11307. pdisp->Release();
  11308. }
  11309. }
  11310. // return the IDispath interface.
  11311. if (_pauto)
  11312. hr = _pauto->QueryInterface(riid, ppv);
  11313. }
  11314. else if (IsEqualIID(riid, IID_IPersistHistory))
  11315. {
  11316. // See if the folder wants a chance at this. The main
  11317. // case for this is the search results windows.
  11318. hr = _GetIPersistHistoryObject((IPersistHistory**)ppv);
  11319. if (SUCCEEDED(hr))
  11320. {
  11321. IUnknown_SetSite((IUnknown*)*ppv, SAFECAST(this, IShellView2*));
  11322. }
  11323. }
  11324. else if (_cFrame.IsWebView() && _cFrame._pOleObj)
  11325. {
  11326. hr = _cFrame._pOleObj->QueryInterface(riid, ppv);
  11327. }
  11328. break;
  11329. case SVGIO_ALLVIEW:
  11330. if (_hwndStatic)
  11331. {
  11332. DECLAREWAITCURSOR;
  11333. SetWaitCursor();
  11334. do
  11335. {
  11336. // If _hwndStatic is around, we must be filling the
  11337. // view in a background thread, so we will peek for
  11338. // messages to it (so SendMessages will get through)
  11339. // and dispatch only _hwndStatic messages so we get the
  11340. // animation effect.
  11341. // Note there is no timeout, so this could take
  11342. // a while on a slow link, but there really isn't
  11343. // much else I can do
  11344. MSG msg;
  11345. // Since _hwndStatic can only be destroyed on a WM_DSV_BACKGROUNDENUMDONE
  11346. // message, we should never get a RIP
  11347. // We also need to allow WM_DSV_FILELISTFILLDONE since it can destroy _hwndStatic
  11348. if (PeekMessage(&msg, _hwndView, WM_DSV_BACKGROUNDENUMDONE,
  11349. WM_DSV_BACKGROUNDENUMDONE, PM_REMOVE) ||
  11350. PeekMessage(&msg, _hwndView, WM_DSV_FILELISTFILLDONE,
  11351. WM_DSV_FILELISTFILLDONE, PM_REMOVE) ||
  11352. PeekMessage(&msg, _hwndView, WM_DSV_GROUPINGDONE,
  11353. WM_DSV_GROUPINGDONE, PM_REMOVE) ||
  11354. PeekMessage(&msg, _hwndStatic, 0, 0, PM_REMOVE))
  11355. {
  11356. TranslateMessage(&msg);
  11357. DispatchMessage(&msg);
  11358. }
  11359. } while (_hwndStatic);
  11360. ResetWaitCursor();
  11361. }
  11362. // Fall through
  11363. case SVGIO_SELECTION:
  11364. hr = _GetUIObjectFromItem(riid, ppv, uWhat, TRUE);
  11365. break;
  11366. }
  11367. return hr;
  11368. }
  11369. HRESULT CDefView::PreCreateInfotip(HWND hwndContaining, UINT_PTR uToolID, LPRECT prectTool)
  11370. {
  11371. ASSERT(hwndContaining != NULL);
  11372. ASSERT(_FindPendingInfotip(hwndContaining, uToolID, NULL, FALSE) == S_FALSE);
  11373. PENDING_INFOTIP *ppi = new PENDING_INFOTIP;
  11374. HRESULT hr;
  11375. if (ppi)
  11376. {
  11377. ppi->hwndContaining = hwndContaining;
  11378. ppi->uToolID = uToolID;
  11379. ppi->rectTool = *prectTool;
  11380. if (_tlistPendingInfotips.AddTail(ppi))
  11381. {
  11382. hr = S_OK;
  11383. }
  11384. else
  11385. {
  11386. hr = E_OUTOFMEMORY;
  11387. delete ppi;
  11388. }
  11389. }
  11390. else
  11391. {
  11392. hr = E_OUTOFMEMORY;
  11393. }
  11394. return hr;
  11395. }
  11396. HRESULT CDefView::PostCreateInfotip(HWND hwndContaining, UINT_PTR uToolID, HINSTANCE hinst, UINT_PTR uInfotipID, LPARAM lParam)
  11397. {
  11398. ASSERT(hwndContaining != NULL);
  11399. TOOLINFO *pti = new TOOLINFO;
  11400. HRESULT hr;
  11401. if (pti)
  11402. {
  11403. pti->cbSize = sizeof(TOOLINFO);
  11404. pti->uFlags = 0;
  11405. pti->hwnd = hwndContaining;
  11406. pti->uId = uToolID;
  11407. //pti->rect = initialized in _OnPostCreateInfotip()
  11408. pti->hinst = hinst;
  11409. pti->lpszText = (LPWSTR)uInfotipID;
  11410. pti->lParam = lParam;
  11411. hr = PostMessage(_hwndView, WM_DSV_POSTCREATEINFOTIP, (WPARAM)pti, lParam) ? S_OK : E_FAIL;
  11412. if (FAILED(hr))
  11413. {
  11414. delete pti;
  11415. }
  11416. }
  11417. else
  11418. {
  11419. hr = E_OUTOFMEMORY;
  11420. }
  11421. return hr;
  11422. }
  11423. HRESULT CDefView::PostCreateInfotip(HWND hwndContaining, UINT_PTR uToolID, LPCWSTR pwszInfotip, LPARAM lParam)
  11424. {
  11425. HRESULT hr = SHStrDup(pwszInfotip, (LPWSTR *)&pwszInfotip);
  11426. if (SUCCEEDED(hr))
  11427. {
  11428. hr = PostCreateInfotip(hwndContaining, uToolID, NULL, (UINT_PTR)pwszInfotip, lParam);
  11429. if (FAILED(hr))
  11430. {
  11431. CoTaskMemFree((LPVOID)pwszInfotip);
  11432. }
  11433. }
  11434. return hr;
  11435. }
  11436. HRESULT CDefView::_OnPostCreateInfotip(TOOLINFO *pti, LPARAM lParam)
  11437. {
  11438. HRESULT hr = _FindPendingInfotip(pti->hwnd, pti->uId, &pti->rect, TRUE);
  11439. if (hr == S_OK)
  11440. {
  11441. hr = SendMessage(_hwndInfotip, TTM_ADDTOOL, 0, (LPARAM)pti) ? S_OK : E_FAIL;
  11442. }
  11443. _OnPostCreateInfotipCleanup(pti);
  11444. return hr;
  11445. }
  11446. HRESULT CDefView::_OnPostCreateInfotipCleanup(TOOLINFO *pti)
  11447. {
  11448. if (!pti->hinst)
  11449. CoTaskMemFree(pti->lpszText);
  11450. delete pti;
  11451. return S_OK;
  11452. }
  11453. HRESULT CDefView::_FindPendingInfotip(HWND hwndContaining, UINT_PTR uToolID, LPRECT prectTool, BOOL bRemoveAndDestroy)
  11454. {
  11455. CLISTPOS posNext = _tlistPendingInfotips.GetHeadPosition();
  11456. CLISTPOS posCurrent;
  11457. PENDING_INFOTIP *ppi;
  11458. HRESULT hr = S_FALSE;
  11459. while (posNext)
  11460. {
  11461. posCurrent = posNext;
  11462. ppi = _tlistPendingInfotips.GetNext(posNext);
  11463. if (ppi->hwndContaining == hwndContaining && ppi->uToolID == uToolID)
  11464. {
  11465. if (bRemoveAndDestroy)
  11466. {
  11467. if (prectTool)
  11468. {
  11469. // Use prectTool as out param.
  11470. *prectTool = ppi->rectTool;
  11471. }
  11472. _tlistPendingInfotips.RemoveAt(posCurrent);
  11473. delete ppi;
  11474. }
  11475. else
  11476. {
  11477. if (prectTool)
  11478. {
  11479. // Use prectTool as in param.
  11480. ppi->rectTool = *prectTool;
  11481. }
  11482. }
  11483. hr = S_OK;
  11484. break;
  11485. }
  11486. }
  11487. // Post Contition -- callers expect only S_OK or S_FALSE.
  11488. ASSERT(hr == S_OK || hr == S_FALSE);
  11489. return hr;
  11490. }
  11491. HRESULT CDefView::CreateInfotip(HWND hwndContaining, UINT_PTR uToolID, LPRECT prectTool, HINSTANCE hinst, UINT_PTR uInfotipID, LPARAM lParam)
  11492. {
  11493. ASSERT(hwndContaining != NULL);
  11494. // CreateInfotip() is not for use with PreCreateInfotip()/PostCreateInfotip().
  11495. ASSERT(_FindPendingInfotip(hwndContaining, uToolID, NULL, FALSE) == S_FALSE);
  11496. TOOLINFO ti;
  11497. ti.cbSize = sizeof(TOOLINFO);
  11498. ti.uFlags = 0;
  11499. ti.hwnd = hwndContaining;
  11500. ti.uId = uToolID;
  11501. ti.rect = *prectTool;
  11502. ti.hinst = hinst;
  11503. ti.lpszText = (LPWSTR)uInfotipID;
  11504. ti.lParam = lParam;
  11505. return SendMessage(_hwndInfotip, TTM_ADDTOOL, 0, (LPARAM)&ti) ? S_OK : E_FAIL;
  11506. }
  11507. HRESULT CDefView::CreateInfotip(HWND hwndContaining, UINT_PTR uToolID, LPRECT prectTool, LPCWSTR pwszInfotip, LPARAM lParam)
  11508. {
  11509. return CreateInfotip(hwndContaining, uToolID, prectTool, NULL, (UINT_PTR)pwszInfotip, lParam);
  11510. }
  11511. HRESULT CDefView::DestroyInfotip(HWND hwndContaining, UINT_PTR uToolID)
  11512. {
  11513. ASSERT(hwndContaining != NULL);
  11514. if (_FindPendingInfotip(hwndContaining, uToolID, NULL, TRUE) == S_FALSE)
  11515. {
  11516. TOOLINFO ti;
  11517. ZeroMemory(&ti, sizeof(TOOLINFO));
  11518. ti.cbSize = sizeof(TOOLINFO);
  11519. ti.hwnd = hwndContaining;
  11520. ti.uId = uToolID;
  11521. SendMessage(_hwndInfotip, TTM_DELTOOL, 0, (LPARAM)&ti);
  11522. }
  11523. return S_OK;
  11524. }
  11525. // Note:
  11526. // Coordinates in prectTool must be relative to the hwnd in hwndContaining.
  11527. //
  11528. HRESULT CDefView::RepositionInfotip(HWND hwndContaining, UINT_PTR uToolID, LPRECT prectTool)
  11529. {
  11530. if (_FindPendingInfotip(hwndContaining, uToolID, prectTool, FALSE) == S_FALSE)
  11531. {
  11532. TOOLINFO ti;
  11533. ZeroMemory(&ti, sizeof(TOOLINFO));
  11534. ti.cbSize = sizeof(TOOLINFO);
  11535. ti.hwnd = hwndContaining;
  11536. ti.uId = uToolID;
  11537. ti.rect = *prectTool;
  11538. SendMessage(_hwndInfotip, TTM_NEWTOOLRECT, 0, (LPARAM)&ti);
  11539. }
  11540. return S_OK;
  11541. }
  11542. HRESULT CDefView::RelayInfotipMessage(HWND hwndFrom, UINT uMsg, WPARAM wParam, LPARAM lParam)
  11543. {
  11544. HRESULT hr;
  11545. if (_hwndInfotip)
  11546. {
  11547. MSG msg;
  11548. msg.hwnd = hwndFrom;
  11549. msg.message = uMsg;
  11550. msg.wParam = wParam;
  11551. msg.lParam = lParam;
  11552. SendMessage(_hwndInfotip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
  11553. hr = S_OK;
  11554. }
  11555. else
  11556. {
  11557. hr = E_FAIL;
  11558. }
  11559. return hr;
  11560. }
  11561. STDMETHODIMP CDefView::QueryInterface(REFIID riid, void **ppvObj)
  11562. {
  11563. static const QITAB qit[] = {
  11564. QITABENT(CDefView, IShellView2), // IID_IShellView2
  11565. QITABENTMULTI(CDefView, IShellView, IShellView2), // IID_IShellView
  11566. QITABENT(CDefView, IViewObject), // IID_IViewObject
  11567. QITABENT(CDefView, IDropTarget), // IID_IDropTarget
  11568. QITABENT(CDefView, IShellFolderView), // IID_IShellFolderView
  11569. QITABENT(CDefView, IFolderView), // IID_IFolderView
  11570. QITABENT(CDefView, IOleCommandTarget), // IID_IOleCommandTarget
  11571. QITABENT(CDefView, IServiceProvider), // IID_IServiceProvider
  11572. QITABENT(CDefView, IDefViewFrame3), // IID_IDefViewFrame
  11573. QITABENT(CDefView, IDefViewFrame), // IID_IDefViewFrame
  11574. QITABENT(CDefView, IDocViewSite), // IID_IDocViewSite
  11575. QITABENT(CDefView, IInternetSecurityMgrSite), // IID_IInternetSecurityMgrSite
  11576. QITABENT(CDefView, IObjectWithSite), // IID_IObjectWithSite
  11577. QITABENT(CDefView, IPersistIDList), // IID_IPersistIDList
  11578. QITABENT(CDefView, IDVGetEnum), // IID_IDVGetEnum
  11579. QITABENT(CDefView, IContextMenuSite), // IID_IContextMenuSite
  11580. QITABENT(CDefView, IDefViewSafety), // IID_IDefViewSafety
  11581. QITABENT(CDefView, IUICommandTarget), // IID_IUICommandTarget
  11582. { 0 }
  11583. };
  11584. HRESULT hr = QISearch(this, qit, riid, ppvObj);
  11585. if (FAILED(hr))
  11586. {
  11587. // special case this one as it simply casts this...
  11588. if (IsEqualIID(riid, IID_CDefView))
  11589. {
  11590. *ppvObj = (void *)this;
  11591. AddRef();
  11592. hr = S_OK;
  11593. }
  11594. }
  11595. return hr;
  11596. }
  11597. STDMETHODIMP_(ULONG) CDefView::AddRef()
  11598. {
  11599. return InterlockedIncrement(&_cRef);
  11600. }
  11601. STDMETHODIMP_(ULONG) CDefView::Release()
  11602. {
  11603. if (InterlockedDecrement(&_cRef))
  11604. return _cRef;
  11605. delete this;
  11606. return 0;
  11607. }
  11608. //===========================================================================
  11609. // Constructor of CDefView class
  11610. //===========================================================================
  11611. CDefView::CDefView(IShellFolder *psf, IShellFolderViewCB *psfvcb,
  11612. IShellView *psvOuter) : _cRef(1), _cCallback(psfvcb)
  11613. {
  11614. psf->QueryInterface(IID_PPV_ARG(IShellFolder, &_pshf));
  11615. psf->QueryInterface(IID_PPV_ARG(IShellFolder2, &_pshf2));
  11616. LPITEMIDLIST pidlFull = _GetViewPidl();
  11617. if (pidlFull)
  11618. {
  11619. LPCITEMIDLIST pidlRelative;
  11620. if (SUCCEEDED(SHBindToFolderIDListParent(NULL, pidlFull, IID_PPV_ARG(IShellFolder, &_pshfParent), &pidlRelative)))
  11621. {
  11622. _pidlRelative = ILClone(pidlRelative);
  11623. _pshfParent->QueryInterface(IID_PPV_ARG(IShellFolder2, &_pshf2Parent));
  11624. }
  11625. ILFree(pidlFull);
  11626. }
  11627. CallCB(SFVM_FOLDERSETTINGSFLAGS, 0, (LPARAM)&_fs.fFlags);
  11628. _vs.InitWithDefaults(this);
  11629. _rgbBackColor = CLR_INVALID;
  11630. _sizeThumbnail.cx = -1; // non init state
  11631. _iIncrementCat = 1;
  11632. _wvLayout.dwLayout = -1; // an invalid value
  11633. // NOTE we dont AddRef() psvOuter
  11634. // it has a ref on us
  11635. _psvOuter = psvOuter;
  11636. // the client needs this info to be able to do anything with us,
  11637. // so set it REALLY early on in the creation process
  11638. IUnknown_SetSite(_cCallback.GetSFVCB(), SAFECAST(this, IShellFolderView*));
  11639. for (int i = 0; i < ARRAYSIZE(_crCustomColors); i++)
  11640. _crCustomColors[i] = CLR_MYINVALID;
  11641. _UpdateRegFlags();
  11642. IDLData_InitializeClipboardFormats();
  11643. if (SUCCEEDED(CoCreateInstance(CLSID_ShellTaskScheduler, NULL, CLSCTX_INPROC, IID_PPV_ARG(IShellTaskScheduler2, &_pScheduler))))
  11644. {
  11645. // init a set a 60 second timeout
  11646. _pScheduler->Status(ITSSFLAG_KILL_ON_DESTROY, DEFVIEW_THREAD_IDLE_TIMEOUT);
  11647. }
  11648. // Catch unexpected STACK allocations which would break us.
  11649. ASSERT(_hwndInfotip == NULL);
  11650. }
  11651. STDAPI SHCreateShellFolderView(const SFV_CREATE* pcsfv, IShellView ** ppsv)
  11652. {
  11653. *ppsv = NULL;
  11654. HRESULT hr = E_INVALIDARG;
  11655. if (pcsfv && sizeof(*pcsfv) == pcsfv->cbSize)
  11656. {
  11657. CDefView *pdsv = new CDefView(pcsfv->pshf, pcsfv->psfvcb, pcsfv->psvOuter);
  11658. if (pdsv)
  11659. {
  11660. *ppsv = pdsv;
  11661. hr = S_OK;
  11662. }
  11663. }
  11664. return hr;
  11665. }
  11666. void CDVDropTarget::LeaveAndReleaseData()
  11667. {
  11668. DragLeave();
  11669. }
  11670. void CDVDropTarget::ReleaseDataObject()
  11671. {
  11672. ATOMICRELEASE(_pdtobj);
  11673. }
  11674. void CDVDropTarget::ReleaseCurrentDropTarget()
  11675. {
  11676. CDefView *pdv = IToClass(CDefView, _dvdt, this);
  11677. if (_pdtgtCur)
  11678. {
  11679. _pdtgtCur->DragLeave();
  11680. ATOMICRELEASE(_pdtgtCur);
  11681. }
  11682. pdv->_itemCur = -2;
  11683. // WARNING: Never touch pdv->itemOver in this function.
  11684. }
  11685. HRESULT CDVDropTarget::DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
  11686. {
  11687. CDefView *pdv = IToClass(CDefView, _dvdt, this);
  11688. IUnknown_Set((IUnknown **)&_pdtobj, pdtobj);
  11689. // Don't allow a drop from our webview content to ourself!
  11690. _fIgnoreSource = FALSE;
  11691. IOleCommandTarget* pct;
  11692. if (pdv->_cFrame.IsWebView() && SUCCEEDED(pdv->_cFrame.GetCommandTarget(&pct)))
  11693. {
  11694. VARIANTARG v = {0};
  11695. if (SUCCEEDED(pct->Exec(&CGID_ShellDocView, SHDVID_ISDRAGSOURCE, 0, NULL, &v)))
  11696. {
  11697. pct->Release();
  11698. if (v.lVal)
  11699. {
  11700. *pdwEffect = DROPEFFECT_NONE;
  11701. _fIgnoreSource = TRUE;
  11702. return S_OK;
  11703. }
  11704. }
  11705. }
  11706. g_fDraggingOverSource = FALSE;
  11707. _grfKeyState = grfKeyState;
  11708. ASSERT(_pdtgtCur == NULL);
  11709. // don't really need to do this, but this sets the target state
  11710. ReleaseCurrentDropTarget();
  11711. _itemOver = -2;
  11712. //
  11713. // In case of Desktop, we should not lock the enter screen.
  11714. //
  11715. HWND hwndLock = pdv->_IsDesktop() ? pdv->_hwndView : pdv->_hwndMain;
  11716. GetWindowRect(hwndLock, &_rcLockWindow);
  11717. DAD_DragEnterEx3(hwndLock, ptl, pdtobj);
  11718. DAD_InitScrollData(&_asd);
  11719. _ptLast.x = _ptLast.y = 0x7fffffff; // put bogus value to force redraw
  11720. return S_OK;
  11721. }
  11722. #define DVAE_BEFORE 0x01
  11723. #define DVAE_AFTER 0x02
  11724. // this MUST set pdwEffect to 0 or DROPEFFECT_MOVE if it's a default drag drop
  11725. // in the same window
  11726. void CDefView::_AlterEffect(DWORD grfKeyState, DWORD *pdwEffect, UINT uFlags)
  11727. {
  11728. g_fDraggingOverSource = FALSE;
  11729. if (_IsDropOnSource(NULL))
  11730. {
  11731. if (_IsPositionedView())
  11732. {
  11733. // If this is default drag & drop, enable move.
  11734. if (uFlags & DVAE_AFTER)
  11735. {
  11736. if ((grfKeyState & (MK_LBUTTON | MK_CONTROL | MK_SHIFT | MK_ALT)) == MK_LBUTTON)
  11737. {
  11738. *pdwEffect = DROPEFFECT_MOVE;
  11739. g_fDraggingOverSource = TRUE;
  11740. }
  11741. else if (grfKeyState & MK_RBUTTON)
  11742. {
  11743. *pdwEffect |= DROPEFFECT_MOVE;
  11744. }
  11745. }
  11746. }
  11747. else
  11748. {
  11749. if (uFlags & DVAE_BEFORE)
  11750. {
  11751. // No. Disable move.
  11752. *pdwEffect &= ~DROPEFFECT_MOVE;
  11753. // default drag & drop, disable all.
  11754. if ((grfKeyState & (MK_LBUTTON | MK_CONTROL | MK_SHIFT | MK_ALT)) == MK_LBUTTON)
  11755. {
  11756. *pdwEffect = 0;
  11757. }
  11758. }
  11759. }
  11760. }
  11761. }
  11762. HRESULT CDVDropTarget::DragOver(DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
  11763. {
  11764. CDefView *pdv = IToClass(CDefView, _dvdt, this);
  11765. HRESULT hr = S_OK;
  11766. DWORD dwEffectScroll = 0;
  11767. DWORD dwEffectOut = 0;
  11768. DWORD dwEffectOutToCache;
  11769. BOOL fSameImage = FALSE;
  11770. if (_fIgnoreSource)
  11771. {
  11772. // for parity with win2k behavior, we need to bail out from DragOver
  11773. // if we hit the SHDVID_ISDRAGSOURCE in DragEnter.
  11774. // this is so when you have a stretched background in active desktop and
  11775. // show desktop icons is off, when you drag the background image around
  11776. // you'll get DROPEFFECT_NONE instead of a bad DROPEFFECT_COPY.
  11777. *pdwEffect = DROPEFFECT_NONE;
  11778. return S_OK;
  11779. }
  11780. POINT pt = {ptl.x, ptl.y}; // in screen coords
  11781. RECT rc;
  11782. GetWindowRect(pdv->_hwndListview, &rc);
  11783. BOOL fInRect = PtInRect(&rc, pt);
  11784. ScreenToClient(pdv->_hwndListview, &pt); // now in client
  11785. // assume coords of our window match listview
  11786. if (DAD_AutoScroll(pdv->_hwndListview, &_asd, &pt))
  11787. dwEffectScroll = DROPEFFECT_SCROLL;
  11788. // hilight an item, or unhilight all items (DropTarget returns -1)
  11789. int itemNew = fInRect ? pdv->_HitTest(&pt, TRUE) : -1;
  11790. // If we are dragging over on a different item, get its IDropTarget
  11791. // interface or adjust itemNew to -1.
  11792. if (_itemOver != itemNew)
  11793. {
  11794. IDropTarget *pdtgtNew = NULL;
  11795. _dwLastTime = GetTickCount(); // keep track for auto-expanding the tree
  11796. _itemOver = itemNew;
  11797. // Avoid dropping onto drag source objects.
  11798. if ((itemNew != -1) && pdv->_bDragSource)
  11799. {
  11800. UINT uState = ListView_GetItemState(pdv->_hwndListview, itemNew, LVIS_SELECTED);
  11801. if (uState & LVIS_SELECTED)
  11802. itemNew = -1;
  11803. }
  11804. // If we are dragging over an item, try to get its IDropTarget.
  11805. if (itemNew != -1)
  11806. {
  11807. // We are dragging over an item.
  11808. LPCITEMIDLIST apidl[1] = { pdv->_GetPIDL(itemNew) };
  11809. if (apidl[0])
  11810. {
  11811. pdv->_pshf->GetUIObjectOf(pdv->_hwndMain, 1, apidl, IID_PPV_ARG_NULL(IDropTarget, &pdtgtNew));
  11812. ASSERT(itemNew != pdv->_itemCur); // MUST not be the same
  11813. }
  11814. if (pdtgtNew == NULL)
  11815. {
  11816. // If the item is not a drop target, don't hightlight it
  11817. // treat it as transparent.
  11818. itemNew = -1;
  11819. }
  11820. }
  11821. // If the new target is different from the current one, switch it.
  11822. if (pdv->_itemCur != itemNew)
  11823. {
  11824. // Release previous drop target, if any.
  11825. ReleaseCurrentDropTarget();
  11826. ASSERT(_pdtgtCur==NULL);
  11827. // Update pdv->_itemCur which indicates the current target.
  11828. // (Note that it might be different from _itemOver).
  11829. pdv->_itemCur = itemNew;
  11830. // If we are dragging over the background or over non-sink item,
  11831. // get the drop target for the folder.
  11832. if (itemNew == -1)
  11833. {
  11834. // We are dragging over the background, this can be NULL
  11835. ASSERT(pdtgtNew == NULL);
  11836. _pdtgtCur = pdv->_pdtgtBack;
  11837. if (_pdtgtCur)
  11838. _pdtgtCur->AddRef();
  11839. }
  11840. else
  11841. {
  11842. ASSERT(pdtgtNew);
  11843. _pdtgtCur = pdtgtNew;
  11844. }
  11845. // Hilight the sink item (itemNew != -1) or unhilight all (-1).
  11846. LVUtil_DragSelectItem(pdv->_hwndListview, itemNew);
  11847. // Call IDropTarget::DragEnter of the target object.
  11848. if (_pdtgtCur)
  11849. {
  11850. // pdwEffect is in/out parameter.
  11851. dwEffectOut = *pdwEffect; // pdwEffect in
  11852. // Special case if we are dragging within a source window
  11853. pdv->_AlterEffect(grfKeyState, &dwEffectOut, DVAE_BEFORE);
  11854. hr = _pdtgtCur->DragEnter(_pdtobj, grfKeyState, ptl, &dwEffectOut);
  11855. pdv->_AlterEffect(grfKeyState, &dwEffectOut, DVAE_AFTER);
  11856. }
  11857. else
  11858. {
  11859. ASSERT(dwEffectOut==0);
  11860. pdv->_AlterEffect(grfKeyState, &dwEffectOut, DVAE_BEFORE | DVAE_AFTER);
  11861. }
  11862. TraceMsg(TF_DEFVIEW, "CDV::DragOver dwEIn=%x, dwEOut=%x", *pdwEffect, dwEffectOut);
  11863. }
  11864. else
  11865. {
  11866. ASSERT(pdtgtNew == NULL); // It must be NULL
  11867. goto NoChange;
  11868. }
  11869. // Every time we're over a new item, record this information so we can handle the insertmark.
  11870. _fItemOverNotADropTarget = (itemNew == -1);
  11871. }
  11872. else
  11873. {
  11874. NoChange:
  11875. if (_itemOver != -1)
  11876. {
  11877. DWORD dwNow = GetTickCount();
  11878. if ((dwNow - _dwLastTime) >= 1000)
  11879. {
  11880. _dwLastTime = dwNow;
  11881. // DAD_ShowDragImage(FALSE);
  11882. // OpenItem(pdv, _itemOver);
  11883. // DAD_ShowDragImage(TRUE);
  11884. }
  11885. }
  11886. //
  11887. // No change in the selection. We assume that *pdwEffect stays
  11888. // the same during the same drag-loop as long as the key state doesn't change.
  11889. //
  11890. if ((_grfKeyState != grfKeyState) && _pdtgtCur)
  11891. {
  11892. // Note that pdwEffect is in/out parameter.
  11893. dwEffectOut = *pdwEffect; // pdwEffect in
  11894. // Special case if we are dragging within a source window
  11895. pdv->_AlterEffect(grfKeyState, &dwEffectOut, DVAE_BEFORE);
  11896. hr = _pdtgtCur->DragOver(grfKeyState, ptl, &dwEffectOut);
  11897. pdv->_AlterEffect(grfKeyState, &dwEffectOut, DVAE_AFTER);
  11898. }
  11899. else
  11900. {
  11901. // Same item and same key state. Use the previous dwEffectOut.
  11902. dwEffectOut = _dwEffectOut;
  11903. fSameImage = TRUE;
  11904. hr = S_OK;
  11905. }
  11906. }
  11907. // Cache the calculated dwEffectOut (BEFORE making local modifications below).
  11908. dwEffectOutToCache = dwEffectOut;
  11909. // Activate/deactivate insertmark, if appropriate.
  11910. LVINSERTMARK lvim = { sizeof(LVINSERTMARK), 0, -1, 0 };
  11911. if (_fItemOverNotADropTarget)
  11912. {
  11913. // Only do the insertion mark stuff if we're in a view mode that makes sense for these:
  11914. if (pdv->_IsAutoArrange() || (pdv->_fs.fFlags & FWF_SNAPTOGRID))
  11915. {
  11916. ListView_InsertMarkHitTest(pdv->_hwndListview, &pt, &lvim);
  11917. if (pdv->_bDragSource && pdv->_IsAutoArrange() && (lvim.iItem == -1))
  11918. {
  11919. // a "move" drop here won't do anything so set the effect appropriately
  11920. if (dwEffectOut & DROPEFFECT_MOVE)
  11921. {
  11922. // fall back to "copy" drop effect (if supported)
  11923. if (*pdwEffect & DROPEFFECT_COPY)
  11924. {
  11925. dwEffectOut |= DROPEFFECT_COPY;
  11926. }
  11927. // fall back to "link" drop effect (if supported)
  11928. else if (*pdwEffect & DROPEFFECT_LINK)
  11929. {
  11930. dwEffectOut |= DROPEFFECT_LINK;
  11931. }
  11932. // fall back to no drop effect
  11933. dwEffectOut &= ~DROPEFFECT_MOVE;
  11934. }
  11935. // NOTE: a DROPEFFECT_MOVE still comes through the ::Drop for a left-drop...
  11936. // we might want to remember that we're exclududing move (_bDragSourceDropOnDragItem)
  11937. }
  11938. }
  11939. }
  11940. ListView_SetInsertMark(pdv->_hwndListview, &lvim);
  11941. _grfKeyState = grfKeyState; // store these for the next Drop
  11942. _dwEffectOut = dwEffectOutToCache; // and DragOver
  11943. // OLE does not call IDropTarget::Drop if we return something
  11944. // valid. We force OLE call it by returning DROPEFFECT_SCROLL.
  11945. if (g_fDraggingOverSource)
  11946. dwEffectScroll = DROPEFFECT_SCROLL;
  11947. *pdwEffect = dwEffectOut | dwEffectScroll; // pdwEffect out
  11948. if (!(fSameImage && pt.x == _ptLast.x && pt.y == _ptLast.y))
  11949. {
  11950. HWND hwndLock = pdv->_IsDesktop() ? pdv->_hwndView : pdv->_hwndMain;
  11951. DAD_DragMoveEx(hwndLock, ptl);
  11952. _ptLast.x = ptl.x;
  11953. _ptLast.y = ptl.y;
  11954. }
  11955. return hr;
  11956. }
  11957. HRESULT CDVDropTarget::DragLeave()
  11958. {
  11959. CDefView *pdv = IToClass(CDefView, _dvdt, this);
  11960. //
  11961. // Make it possible to call it more than necessary.
  11962. //
  11963. if (_pdtobj)
  11964. {
  11965. TraceMsg(TF_DEFVIEW, "CDVDropTarget::DragLeave");
  11966. ReleaseCurrentDropTarget();
  11967. _itemOver = -2;
  11968. ReleaseDataObject();
  11969. DAD_DragLeave();
  11970. LVUtil_DragSelectItem(pdv->_hwndListview, -1);
  11971. }
  11972. g_fDraggingOverSource = FALSE;
  11973. ASSERT(_pdtgtCur == NULL);
  11974. ASSERT(_pdtobj == NULL);
  11975. LVINSERTMARK lvim = { sizeof(LVINSERTMARK), 0, -1, 0 }; // clear insert mark (-1)
  11976. ListView_SetInsertMark(pdv->_hwndListview, &lvim);
  11977. return S_OK;
  11978. }
  11979. HRESULT CDVDropTarget::Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  11980. {
  11981. CDefView *pdv = IToClass(CDefView, _dvdt, this);
  11982. IUnknown_Set((IUnknown **)&_pdtobj, pdtobj);
  11983. pdv->_ptDrop.x = pt.x;
  11984. pdv->_ptDrop.y = pt.y;
  11985. ScreenToClient(pdv->_hwndListview, &pdv->_ptDrop);
  11986. //
  11987. // handle moves within the same window here.
  11988. // depend on _AlterEffect forcing in DROPEFFECT_MOVE and only
  11989. // dropeffect move when drag in same window
  11990. //
  11991. // Notes: We need to use _grfKeyState instead of grfKeyState
  11992. // to see if the left mouse was used or not during dragging.
  11993. //
  11994. pdv->_AlterEffect(_grfKeyState, pdwEffect, DVAE_BEFORE | DVAE_AFTER);
  11995. if ((_grfKeyState & MK_LBUTTON) && (*pdwEffect == DROPEFFECT_MOVE) &&
  11996. (pdv->_IsDropOnSource(NULL)))
  11997. {
  11998. // This means we are left-dropping on ourselves, so we just move
  11999. // the icons.
  12000. DAD_DragLeave();
  12001. pdv->_SameViewMoveIcons();
  12002. SetForegroundWindow(pdv->_hwndMain);
  12003. ASSERT(pdv->_bDropAnchor == FALSE);
  12004. *pdwEffect = 0; // the underlying objects didn't 'move' anywhere
  12005. ReleaseCurrentDropTarget();
  12006. }
  12007. else if (_pdtgtCur)
  12008. {
  12009. // use this local because if pdtgtCur::Drop does a UnlockWindow
  12010. // then hits an error and needs to put up a dialog,
  12011. // we could get re-entered and clobber the defview's pdtgtCur
  12012. IDropTarget *pdtgtCur = _pdtgtCur;
  12013. _pdtgtCur = NULL;
  12014. //
  12015. // HACK ALERT!!!!
  12016. //
  12017. // If we don't call LVUtil_DragEnd here, we'll be able to leave
  12018. // dragged icons visible when the menu is displayed. However, because
  12019. // we are calling IDropTarget::Drop() which may create some modeless
  12020. // dialog box or something, we can not ensure the locked state of
  12021. // the list view -- LockWindowUpdate() can lock only one window at
  12022. // a time. Therefore, we skip this call only if the pdtgtCur
  12023. // is a subclass of CIDLDropTarget, assuming its Drop calls
  12024. // CDefView::DragEnd (or CIDLDropTarget_DragDropMenu) appropriately.
  12025. //
  12026. pdv->_bDropAnchor = TRUE;
  12027. if (!DoesDropTargetSupportDAD(pdtgtCur))
  12028. {
  12029. // This will hide the dragged image.
  12030. DAD_DragLeave();
  12031. // reset the drag image list so that the user
  12032. // can start another drag&drop while we are in this
  12033. // Drop() member function call.
  12034. DAD_SetDragImage(NULL, NULL);
  12035. }
  12036. // Special case if we are dragging within a source window
  12037. pdv->_AlterEffect(grfKeyState, pdwEffect, DVAE_BEFORE | DVAE_AFTER);
  12038. IUnknown_SetSite(pdtgtCur, SAFECAST(pdv, IShellView2*));
  12039. pdtgtCur->Drop(pdtobj, grfKeyState, pt, pdwEffect);
  12040. IUnknown_SetSite(pdtgtCur, NULL);
  12041. pdtgtCur->Release();
  12042. DAD_DragLeave();
  12043. pdv->_bDropAnchor = FALSE;
  12044. }
  12045. else
  12046. {
  12047. // We come here if Drop is called without DragMove (with DragEnter).
  12048. *pdwEffect = 0;
  12049. }
  12050. DragLeave(); // DoDragDrop does not call DragLeave() after Drop()
  12051. return S_OK;
  12052. }
  12053. //
  12054. // HACK ALERT!!! (see CDVDropTarget::Drop as well)
  12055. //
  12056. // All the subclasses of CIDLDropTarget MUST call this function from
  12057. // within its Drop() member function. Calling CIDLDropTarget_DragDropMenu()
  12058. // is sufficient because it calls CDefView::UnlockWindow.
  12059. //
  12060. // lego... make this a #define in defview.h
  12061. #ifndef DefView_UnlockWindow
  12062. void DefView_UnlockWindow()
  12063. {
  12064. DAD_DragLeave();
  12065. }
  12066. #endif
  12067. BOOL CDefView::_IsBkDropTarget(IDropTarget *pdtg)
  12068. {
  12069. BOOL fRet = FALSE;
  12070. if (_bContextMenuMode)
  12071. {
  12072. if (ListView_GetSelectedCount(_hwndListview) == 0)
  12073. {
  12074. fRet = TRUE;
  12075. }
  12076. }
  12077. POINT pt;
  12078. if (!fRet)
  12079. {
  12080. if (_GetInsertPoint(&pt)) // If there is an insert point, then the background is the drop target.
  12081. return TRUE;
  12082. if (_GetDropPoint(&pt))
  12083. {
  12084. // The Drop point is returned in internal listview coordinates
  12085. // space, so we need to convert it back to client space
  12086. // before we call this function...
  12087. LVUtil_LVToClient(_hwndListview, &pt);
  12088. if (_HitTest(&pt) == -1)
  12089. {
  12090. fRet = TRUE;
  12091. }
  12092. }
  12093. }
  12094. return fRet;
  12095. }
  12096. // IShellFolderView::Rearrange
  12097. STDMETHODIMP CDefView::Rearrange(LPARAM lParamSort)
  12098. {
  12099. return _OnRearrange(lParamSort, TRUE);
  12100. }
  12101. // end user initiated arrange (click on col header, etc)
  12102. HRESULT CDefView::_OnRearrange(LPARAM lParamSort, BOOL fAllowToggle)
  12103. {
  12104. DECLAREWAITCURSOR;
  12105. _vs._iLastColumnClick = (int) _vs._lParamSort;
  12106. _vs._lParamSort = lParamSort;
  12107. // toggle the direction of the sort if on the same column
  12108. if (fAllowToggle && !_IsPositionedView() && _vs._iLastColumnClick == (int) lParamSort)
  12109. _vs._iDirection = -_vs._iDirection;
  12110. else
  12111. _vs._iDirection = 1;
  12112. SetWaitCursor();
  12113. HRESULT hr = _Sort();
  12114. // reset to the state that no items have been moved if currently in a positioned mode
  12115. // so auto-arraning works.
  12116. if (_IsPositionedView())
  12117. {
  12118. _ClearItemPositions();
  12119. }
  12120. ResetWaitCursor();
  12121. return hr;
  12122. }
  12123. STDMETHODIMP CDefView::ArrangeGrid()
  12124. {
  12125. _OnCommand(NULL, GET_WM_COMMAND_MPS(SFVIDM_ARRANGE_GRID, 0, 0));
  12126. return S_OK;
  12127. }
  12128. STDMETHODIMP CDefView::AutoArrange()
  12129. {
  12130. _OnCommand(NULL, GET_WM_COMMAND_MPS(SFVIDM_ARRANGE_AUTO, 0, 0));
  12131. return S_OK;
  12132. }
  12133. STDMETHODIMP CDefView::GetArrangeParam(LPARAM *plParamSort)
  12134. {
  12135. *plParamSort = _vs._lParamSort;
  12136. return S_OK;
  12137. }
  12138. STDMETHODIMP CDefView::AddObject(LPITEMIDLIST pidl, UINT *puItem)
  12139. {
  12140. LPITEMIDLIST pidlCopy = ILClone(pidl);
  12141. if (pidlCopy)
  12142. {
  12143. *puItem = _AddObject(pidlCopy); // takes pidl ownership.
  12144. }
  12145. else
  12146. {
  12147. *puItem = (UINT)-1;
  12148. }
  12149. // must cast to "int" because UINTs are never negative so we would
  12150. // otherwise never be able to detect failure
  12151. return (int)*puItem >= 0 ? S_OK : E_OUTOFMEMORY;
  12152. }
  12153. STDMETHODIMP CDefView::GetObjectCount(UINT *puCount)
  12154. {
  12155. *puCount = ListView_GetItemCount(_hwndListview);
  12156. return S_OK;
  12157. }
  12158. STDMETHODIMP CDefView::SetObjectCount(UINT uCount, UINT dwFlags)
  12159. {
  12160. // Mask over to the flags that map directly accross
  12161. DWORD dw = dwFlags & SFVSOC_NOSCROLL;
  12162. UINT uCountOld = 0;
  12163. GetObjectCount(&uCountOld);
  12164. if ((dwFlags & SFVSOC_INVALIDATE_ALL) == 0)
  12165. dw |= LVSICF_NOINVALIDATEALL; // gross transform
  12166. HRESULT hr = (HRESULT)SendMessage(_hwndListview, LVM_SETITEMCOUNT, (WPARAM)uCount, (LPARAM)dw);
  12167. // Notify automation if we're going from 0 to 1 or more items
  12168. if (!uCountOld && uCount)
  12169. {
  12170. _PostNoItemStateChangedMessage();
  12171. }
  12172. return hr;
  12173. }
  12174. STDMETHODIMP CDefView::GetObject(LPITEMIDLIST *ppidl, UINT uItem)
  12175. {
  12176. // Worse hack, if -42 then return our own pidl...
  12177. if (uItem == (UINT)-42)
  12178. {
  12179. *ppidl = (LPITEMIDLIST)_pidlMonitor;
  12180. return *ppidl ? S_OK : E_UNEXPECTED;
  12181. }
  12182. // Hack, if item is -2, this implies return the focused item
  12183. if (uItem == (UINT)-2)
  12184. uItem = ListView_GetNextItem(_hwndListview, -1, LVNI_FOCUSED);
  12185. *ppidl = (LPITEMIDLIST)_GetPIDL(uItem); // cast due to bad interface def
  12186. return *ppidl ? S_OK : E_UNEXPECTED;
  12187. }
  12188. STDMETHODIMP CDefView::RemoveObject(LPITEMIDLIST pidl, UINT *puItem)
  12189. {
  12190. *puItem = _RemoveObject(pidl, FALSE);
  12191. // must cast to "int" because UINTs are never negative so we would
  12192. // otherwise never be able to detect failure
  12193. return (int)*puItem >= 0 ? S_OK : E_INVALIDARG;
  12194. }
  12195. STDMETHODIMP CDefView::UpdateObject(LPITEMIDLIST pidlOld, LPITEMIDLIST pidlNew, UINT *puItem)
  12196. {
  12197. *puItem = _UpdateObject(pidlOld, pidlNew);
  12198. return (int)(*puItem) >= 0 ? S_OK : E_INVALIDARG;
  12199. }
  12200. STDMETHODIMP CDefView::RefreshObject(LPITEMIDLIST pidl, UINT *puItem)
  12201. {
  12202. *puItem = _RefreshObject(&pidl);
  12203. // must cast to "int" because UINTs are never negative so we would
  12204. // otherwise never be able to detect failure
  12205. return (int)*puItem >= 0 ? S_OK : E_INVALIDARG;
  12206. }
  12207. STDMETHODIMP CDefView::SetRedraw(BOOL bRedraw)
  12208. {
  12209. SendMessage(_hwndListview, WM_SETREDRAW, (WPARAM)bRedraw, 0);
  12210. return S_OK;
  12211. }
  12212. STDMETHODIMP CDefView::GetSelectedObjects(LPCITEMIDLIST **pppidl, UINT *puItems)
  12213. {
  12214. return _GetItemObjects(pppidl, SVGIO_SELECTION, puItems);
  12215. }
  12216. STDMETHODIMP CDefView::GetSelectedCount(UINT *puSelected)
  12217. {
  12218. *puSelected = ListView_GetSelectedCount(_hwndListview);
  12219. return S_OK;
  12220. }
  12221. BOOL CDefView::_IsDropOnSource(IDropTarget *pdtgt)
  12222. {
  12223. // context menu paste (_bMouseMenu shows context menu, cut stuff shows source)
  12224. if (_bMouseMenu && _bHaveCutStuff)
  12225. {
  12226. int iItem = ListView_GetNextItem(_hwndListview, -1, LVNI_SELECTED);
  12227. if (iItem == -1)
  12228. return TRUE;
  12229. }
  12230. if (_itemCur != -1 || !_bDragSource)
  12231. {
  12232. // We did not drag onto the background of the source
  12233. return FALSE;
  12234. }
  12235. return TRUE;
  12236. }
  12237. STDMETHODIMP CDefView::IsDropOnSource(IDropTarget *pDropTarget)
  12238. {
  12239. return _IsDropOnSource(pDropTarget) ? S_OK : S_FALSE;
  12240. }
  12241. STDMETHODIMP CDefView::MoveIcons(IDataObject *pdtobj)
  12242. {
  12243. return E_NOTIMPL;
  12244. }
  12245. STDMETHODIMP CDefView::GetDropPoint(POINT *ppt)
  12246. {
  12247. return _GetDropPoint(ppt) ? S_OK : S_FALSE;
  12248. }
  12249. STDMETHODIMP CDefView::GetDragPoint(POINT *ppt)
  12250. {
  12251. return _GetDragPoint(ppt) ? S_OK : S_FALSE;
  12252. }
  12253. STDMETHODIMP CDefView::SetItemPos(LPCITEMIDLIST pidl, POINT *ppt)
  12254. {
  12255. SFV_SETITEMPOS sip;
  12256. sip.pidl = pidl;
  12257. sip.pt = *ppt;
  12258. _SetItemPos(&sip);
  12259. return S_OK;
  12260. }
  12261. STDMETHODIMP CDefView::IsBkDropTarget(IDropTarget *pDropTarget)
  12262. {
  12263. return _IsBkDropTarget(pDropTarget) ? S_OK : S_FALSE;
  12264. }
  12265. STDMETHODIMP CDefView::SetClipboard(BOOL bMove)
  12266. {
  12267. _OnSetClipboard(bMove); // do this always, even if not current active view
  12268. return S_OK;
  12269. }
  12270. // defcm.cpp asks us to setup the points of the currently selected objects
  12271. // into the data object on Copy/Cut commands
  12272. STDMETHODIMP CDefView::SetPoints(IDataObject *pdtobj)
  12273. {
  12274. LPCITEMIDLIST *apidl;
  12275. UINT cItems;
  12276. HRESULT hr = GetSelectedObjects(&apidl, &cItems);
  12277. if (SUCCEEDED(hr) && cItems)
  12278. {
  12279. _SetPoints(cItems, apidl, pdtobj);
  12280. LocalFree((HLOCAL)apidl);
  12281. }
  12282. return hr;
  12283. }
  12284. STDMETHODIMP CDefView::GetItemSpacing(ITEMSPACING *pSpacing)
  12285. {
  12286. return _GetItemSpacing(pSpacing) ? S_OK : S_FALSE;
  12287. }
  12288. STDMETHODIMP CDefView::SetCallback(IShellFolderViewCB* pNewCB, IShellFolderViewCB** ppOldCB)
  12289. {
  12290. *ppOldCB = NULL;
  12291. return _cCallback.SetCallback(pNewCB, ppOldCB);
  12292. }
  12293. const UINT c_rgiSelectFlags[][2] =
  12294. {
  12295. { SFVS_SELECT_ALLITEMS, SFVIDM_SELECT_ALL },
  12296. { SFVS_SELECT_NONE, SFVIDM_DESELECT_ALL },
  12297. { SFVS_SELECT_INVERT, SFVIDM_SELECT_INVERT }
  12298. };
  12299. STDMETHODIMP CDefView::Select(UINT dwFlags)
  12300. {
  12301. // translate the flag into the menu ID
  12302. for (int i = 0; i < ARRAYSIZE(c_rgiSelectFlags); i++)
  12303. {
  12304. if (c_rgiSelectFlags[i][0] == dwFlags)
  12305. {
  12306. return (HRESULT)_OnCommand(NULL, c_rgiSelectFlags[i][1], 0);
  12307. }
  12308. }
  12309. return E_INVALIDARG;
  12310. }
  12311. STDMETHODIMP CDefView::QuerySupport(UINT * pdwSupport)
  12312. {
  12313. // *pdwSupport is an in/out param, we leave the out == in
  12314. return S_OK; // DefView supports all the operations...
  12315. }
  12316. STDMETHODIMP CDefView::SetAutomationObject(IDispatch *pdisp)
  12317. {
  12318. // release back pointers
  12319. IUnknown_SetOwner(_pauto, NULL);
  12320. IUnknown_SetSite(_pauto, NULL);
  12321. IUnknown_Set((IUnknown **)&_pauto, pdisp); // hold or free _pauto
  12322. // this connects the automation object to our view, so it can implement
  12323. // stuff like "SelectedItems"
  12324. IUnknown_SetOwner(_pauto, SAFECAST(this, IShellFolderView *));
  12325. // use the browser as the site so OM related QueryService calls will find
  12326. // the browser above us as the place to do security checks instead of defivew
  12327. // this is stuff that depends on the zone of the caller as the security check
  12328. IUnknown_SetSite(_pauto, _psb);
  12329. return S_OK;
  12330. }
  12331. STDMETHODIMP CDefView::SelectAndPositionItems(UINT cidl, LPCITEMIDLIST* apidl, POINT* apt, DWORD dwFlags)
  12332. {
  12333. for (UINT i = 0; i < cidl; i++)
  12334. SelectAndPositionItem(apidl[i], dwFlags, apt ? &apt[i] : NULL);
  12335. return S_OK;
  12336. }
  12337. // -------------- auto scroll stuff --------------
  12338. BOOL _AddTimeSample(AUTO_SCROLL_DATA *pad, const POINT *ppt, DWORD dwTime)
  12339. {
  12340. pad->pts[pad->iNextSample] = *ppt;
  12341. pad->dwTimes[pad->iNextSample] = dwTime;
  12342. pad->iNextSample++;
  12343. if (pad->iNextSample == ARRAYSIZE(pad->pts))
  12344. pad->bFull = TRUE;
  12345. pad->iNextSample = pad->iNextSample % ARRAYSIZE(pad->pts);
  12346. return pad->bFull;
  12347. }
  12348. #ifdef DEBUG
  12349. // for debugging, verify we have good averages
  12350. DWORD g_time = 0;
  12351. int g_distance = 0;
  12352. #endif
  12353. int _CurrentVelocity(AUTO_SCROLL_DATA *pad)
  12354. {
  12355. int i, iStart, iNext;
  12356. int dx, dy, distance;
  12357. DWORD time;
  12358. ASSERT(pad->bFull);
  12359. distance = 0;
  12360. time = 1; // avoid div by zero
  12361. i = iStart = pad->iNextSample % ARRAYSIZE(pad->pts);
  12362. do {
  12363. iNext = (i + 1) % ARRAYSIZE(pad->pts);
  12364. dx = abs(pad->pts[i].x - pad->pts[iNext].x);
  12365. dy = abs(pad->pts[i].y - pad->pts[iNext].y);
  12366. distance += (dx + dy);
  12367. time += abs(pad->dwTimes[i] - pad->dwTimes[iNext]);
  12368. i = iNext;
  12369. } while (i != iStart);
  12370. #ifdef DEBUG
  12371. g_time = time;
  12372. g_distance = distance;
  12373. #endif
  12374. // scale this so we don't loose accuracy
  12375. return (distance * 1024) / time;
  12376. }
  12377. // NOTE: this is duplicated in shell32.dll
  12378. //
  12379. // checks to see if we are at the end position of a scroll bar
  12380. // to avoid scrolling when not needed (avoid flashing)
  12381. //
  12382. // in:
  12383. // code SB_VERT or SB_HORZ
  12384. // bDown FALSE is up or left
  12385. // TRUE is down or right
  12386. BOOL CanScroll(HWND hwnd, int code, BOOL bDown)
  12387. {
  12388. SCROLLINFO si;
  12389. si.cbSize = sizeof(si);
  12390. si.fMask = (SIF_RANGE | SIF_PAGE | SIF_POS);
  12391. GetScrollInfo(hwnd, code, &si);
  12392. if (bDown)
  12393. {
  12394. if (si.nPage)
  12395. si.nMax -= si.nPage - 1;
  12396. return si.nPos < si.nMax;
  12397. }
  12398. else
  12399. {
  12400. return si.nPos > si.nMin;
  12401. }
  12402. }
  12403. #define DSD_NONE 0x0000
  12404. #define DSD_UP 0x0001
  12405. #define DSD_DOWN 0x0002
  12406. #define DSD_LEFT 0x0004
  12407. #define DSD_RIGHT 0x0008
  12408. DWORD DAD_DragScrollDirection(HWND hwnd, const POINT *ppt)
  12409. {
  12410. RECT rcOuter, rc;
  12411. DWORD dwDSD = DSD_NONE;
  12412. DWORD dwStyle = GetWindowLong(hwnd, GWL_STYLE);
  12413. #define g_cxVScroll GetSystemMetrics(SM_CXVSCROLL)
  12414. #define g_cyHScroll GetSystemMetrics(SM_CYHSCROLL)
  12415. GetClientRect(hwnd, &rc);
  12416. if (dwStyle & WS_HSCROLL)
  12417. rc.bottom -= g_cyHScroll;
  12418. if (dwStyle & WS_VSCROLL)
  12419. rc.right -= g_cxVScroll;
  12420. // the explorer forwards us drag/drop things outside of our client area
  12421. // so we need to explictly test for that before we do things
  12422. //
  12423. rcOuter = rc;
  12424. InflateRect(&rcOuter, g_cxSmIcon, g_cySmIcon);
  12425. InflateRect(&rc, -g_cxIcon, -g_cyIcon);
  12426. if (!PtInRect(&rc, *ppt) && PtInRect(&rcOuter, *ppt))
  12427. {
  12428. // Yep - can we scroll?
  12429. if (dwStyle & WS_HSCROLL)
  12430. {
  12431. if (ppt->x < rc.left)
  12432. {
  12433. if (CanScroll(hwnd, SB_HORZ, FALSE))
  12434. dwDSD |= DSD_LEFT;
  12435. }
  12436. else if (ppt->x > rc.right)
  12437. {
  12438. if (CanScroll(hwnd, SB_HORZ, TRUE))
  12439. dwDSD |= DSD_RIGHT;
  12440. }
  12441. }
  12442. if (dwStyle & WS_VSCROLL)
  12443. {
  12444. if (ppt->y < rc.top)
  12445. {
  12446. if (CanScroll(hwnd, SB_VERT, FALSE))
  12447. dwDSD |= DSD_UP;
  12448. }
  12449. else if (ppt->y > rc.bottom)
  12450. {
  12451. if (CanScroll(hwnd, SB_VERT, TRUE))
  12452. dwDSD |= DSD_DOWN;
  12453. }
  12454. }
  12455. }
  12456. return dwDSD;
  12457. }
  12458. #define SCROLL_FREQUENCY (GetDoubleClickTime()/2) // 1 line scroll every 1/4 second
  12459. #define MIN_SCROLL_VELOCITY 20 // scaled mouse velocity
  12460. BOOL WINAPI DAD_AutoScroll(HWND hwnd, AUTO_SCROLL_DATA *pad, const POINT *pptNow)
  12461. {
  12462. // first time we've been called, init our state
  12463. int v;
  12464. DWORD dwTimeNow = GetTickCount();
  12465. DWORD dwDSD = DAD_DragScrollDirection(hwnd, pptNow);
  12466. if (!_AddTimeSample(pad, pptNow, dwTimeNow))
  12467. return dwDSD;
  12468. v = _CurrentVelocity(pad);
  12469. if (v <= MIN_SCROLL_VELOCITY)
  12470. {
  12471. // Nope, do some scrolling.
  12472. if ((dwTimeNow - pad->dwLastScroll) < SCROLL_FREQUENCY)
  12473. dwDSD = 0;
  12474. if (dwDSD & DSD_UP)
  12475. {
  12476. DAD_ShowDragImage(FALSE);
  12477. FORWARD_WM_VSCROLL(hwnd, NULL, SB_LINEUP, 1, SendMessage);
  12478. }
  12479. else if (dwDSD & DSD_DOWN)
  12480. {
  12481. DAD_ShowDragImage(FALSE);
  12482. FORWARD_WM_VSCROLL(hwnd, NULL, SB_LINEDOWN, 1, SendMessage);
  12483. }
  12484. if (dwDSD & DSD_LEFT)
  12485. {
  12486. DAD_ShowDragImage(FALSE);
  12487. FORWARD_WM_HSCROLL(hwnd, NULL, SB_LINEUP, 1, SendMessage);
  12488. }
  12489. else if (dwDSD & DSD_RIGHT)
  12490. {
  12491. DAD_ShowDragImage(FALSE);
  12492. FORWARD_WM_HSCROLL(hwnd, NULL, SB_LINEDOWN, 1, SendMessage);
  12493. }
  12494. DAD_ShowDragImage(TRUE);
  12495. if (dwDSD)
  12496. {
  12497. TraceMsg(TF_DEFVIEW, "v=%d", v);
  12498. pad->dwLastScroll = dwTimeNow;
  12499. }
  12500. }
  12501. return dwDSD; // bits set if in scroll region
  12502. }
  12503. // warning: global data holding COM objects that may span apartment boundaries
  12504. // be very careful
  12505. HDSA g_hdsaDefViewCopyHook = NULL;
  12506. typedef struct {
  12507. HWND hwndView;
  12508. CDefView *pdv;
  12509. } DVCOPYHOOK;
  12510. void CDefView::AddCopyHook()
  12511. {
  12512. ENTERCRITICAL;
  12513. if (!g_hdsaDefViewCopyHook)
  12514. {
  12515. g_hdsaDefViewCopyHook = DSA_Create(sizeof(DVCOPYHOOK), 4);
  12516. TraceMsg(TF_DEFVIEW, "AddCopyHook creating the dsa");
  12517. }
  12518. if (g_hdsaDefViewCopyHook)
  12519. {
  12520. DVCOPYHOOK dvch = { _hwndView, this };
  12521. ASSERT(dvch.hwndView);
  12522. if (DSA_AppendItem(g_hdsaDefViewCopyHook, &dvch)!=-1)
  12523. {
  12524. AddRef();
  12525. TraceMsg(TF_DEFVIEW, "AddCopyHook successfully added (total=%d)",
  12526. DSA_GetItemCount(g_hdsaDefViewCopyHook));
  12527. }
  12528. }
  12529. LEAVECRITICAL;
  12530. }
  12531. int CDefView::FindCopyHook(BOOL fRemoveInvalid)
  12532. {
  12533. ASSERTCRITICAL;
  12534. if (g_hdsaDefViewCopyHook)
  12535. {
  12536. int item = DSA_GetItemCount(g_hdsaDefViewCopyHook);
  12537. while (--item >= 0)
  12538. {
  12539. const DVCOPYHOOK *pdvch = (const DVCOPYHOOK *)DSA_GetItemPtr(g_hdsaDefViewCopyHook, item);
  12540. if (pdvch)
  12541. {
  12542. if (fRemoveInvalid)
  12543. {
  12544. if (!IsWindow(pdvch->hwndView))
  12545. {
  12546. TraceMsg(TF_WARNING, "FindCopyHook: found a invalid element, removing...");
  12547. DSA_DeleteItem(g_hdsaDefViewCopyHook, item);
  12548. continue;
  12549. }
  12550. }
  12551. if ((pdvch->hwndView == _hwndView) && (pdvch->pdv == this))
  12552. {
  12553. return item;
  12554. }
  12555. }
  12556. else
  12557. {
  12558. ASSERT(0);
  12559. }
  12560. }
  12561. }
  12562. return -1; // not found
  12563. }
  12564. void CDefView::RemoveCopyHook()
  12565. {
  12566. IShellView *psv = NULL;
  12567. ENTERCRITICAL;
  12568. if (g_hdsaDefViewCopyHook)
  12569. {
  12570. int item = FindCopyHook(TRUE);
  12571. if (item != -1)
  12572. {
  12573. DVCOPYHOOK *pdvch = (DVCOPYHOOK *)DSA_GetItemPtr(g_hdsaDefViewCopyHook, item);
  12574. psv = pdvch->pdv;
  12575. TraceMsg(TF_DEFVIEW, "RemoveCopyHook removing an element");
  12576. DSA_DeleteItem(g_hdsaDefViewCopyHook, item);
  12577. //
  12578. // If this is the last guy, destroy it.
  12579. //
  12580. if (DSA_GetItemCount(g_hdsaDefViewCopyHook) == 0)
  12581. {
  12582. TraceMsg(TF_DEFVIEW, "RemoveCopyHook destroying hdsa (no element)");
  12583. DSA_Destroy(g_hdsaDefViewCopyHook);
  12584. g_hdsaDefViewCopyHook = NULL;
  12585. }
  12586. }
  12587. }
  12588. LEAVECRITICAL;
  12589. //
  12590. // Release it outside the critical section.
  12591. //
  12592. ATOMICRELEASE(psv);
  12593. }
  12594. STDAPI_(UINT) DefView_CopyHook(const COPYHOOKINFO *pchi)
  12595. {
  12596. UINT idRet = IDYES;
  12597. if (g_hdsaDefViewCopyHook==NULL)
  12598. {
  12599. return idRet;
  12600. }
  12601. for (int item = 0; ; item++)
  12602. {
  12603. DVCOPYHOOK dvch = { NULL, NULL };
  12604. // We should minimize this critical section (and must not
  12605. // call pfnCallBack which may popup UI!).
  12606. ENTERCRITICAL;
  12607. if (g_hdsaDefViewCopyHook && DSA_GetItem(g_hdsaDefViewCopyHook, item, &dvch))
  12608. {
  12609. dvch.pdv->AddRef();
  12610. }
  12611. LEAVECRITICAL;
  12612. if (dvch.pdv)
  12613. {
  12614. if (IsWindow(dvch.hwndView))
  12615. {
  12616. HRESULT hr = dvch.pdv->CallCB(SFVM_NOTIFYCOPYHOOK, 0, (LPARAM)pchi);
  12617. ATOMICRELEASE(dvch.pdv);
  12618. if (SUCCEEDED(hr) && (hr != S_OK))
  12619. {
  12620. idRet = HRESULT_CODE(hr);
  12621. ASSERT(idRet==IDYES || idRet==IDCANCEL || idRet==IDNO);
  12622. break;
  12623. }
  12624. item++;
  12625. }
  12626. else
  12627. {
  12628. TraceMsg(TF_DEFVIEW, "DefView_CopyHook list has an invalid element");
  12629. ATOMICRELEASE(dvch.pdv);
  12630. }
  12631. }
  12632. else
  12633. {
  12634. break; // no more item.
  12635. }
  12636. }
  12637. return idRet;
  12638. }
  12639. // IOleCommandTarget stuff - just forward to the webview
  12640. STDMETHODIMP CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
  12641. {
  12642. HRESULT hr = OLECMDERR_E_UNKNOWNGROUP;
  12643. BOOL fQSCalled = FALSE;
  12644. if (_cFrame.IsWebView())
  12645. {
  12646. IOleCommandTarget* pct;
  12647. if (SUCCEEDED(_cFrame.GetCommandTarget(&pct)))
  12648. {
  12649. hr = pct->QueryStatus(pguidCmdGroup, cCmds, rgCmds, pcmdtext);
  12650. fQSCalled = SUCCEEDED(hr);
  12651. pct->Release();
  12652. }
  12653. }
  12654. if (pguidCmdGroup == NULL)
  12655. {
  12656. if (rgCmds == NULL)
  12657. return E_INVALIDARG;
  12658. for (UINT i = 0; i < cCmds; i++)
  12659. {
  12660. // ONLY say that we support the stuff we support in ::OnExec
  12661. switch (rgCmds[i].cmdID)
  12662. {
  12663. case OLECMDID_REFRESH:
  12664. rgCmds[i].cmdf = OLECMDF_ENABLED;
  12665. break;
  12666. default:
  12667. // don't disable if the webview has already answered
  12668. if (!fQSCalled)
  12669. {
  12670. rgCmds[i].cmdf = 0;
  12671. }
  12672. break;
  12673. }
  12674. }
  12675. }
  12676. else if (IsEqualGUID(_clsid, *pguidCmdGroup))
  12677. {
  12678. if (pcmdtext)
  12679. {
  12680. switch (pcmdtext->cmdtextf)
  12681. {
  12682. case OLECMDTEXTF_NAME:
  12683. // It's a query for the button tooltip text.
  12684. ASSERT(cCmds == 1);
  12685. _GetToolTipText(rgCmds[0].cmdID, pcmdtext->rgwz, pcmdtext->cwBuf);
  12686. // ensure NULL termination
  12687. pcmdtext->rgwz[pcmdtext->cwBuf - 1] = 0;
  12688. pcmdtext->cwActual = lstrlenW(pcmdtext->rgwz);
  12689. hr = S_OK;
  12690. break;
  12691. default:
  12692. hr = E_FAIL;
  12693. break;
  12694. }
  12695. }
  12696. else
  12697. {
  12698. DWORD dwAttr = _AttributesFromSel(SFGAO_RELEVANT);
  12699. for (UINT i = 0; i < cCmds; i++)
  12700. {
  12701. if (_ShouldEnableToolbarButton(rgCmds[i].cmdID, dwAttr, -1))
  12702. rgCmds[i].cmdf = OLECMDF_ENABLED;
  12703. else
  12704. rgCmds[i].cmdf = 0;
  12705. }
  12706. hr = S_OK;
  12707. }
  12708. }
  12709. return hr;
  12710. }
  12711. STDMETHODIMP CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
  12712. {
  12713. HRESULT hr;
  12714. // Hold a ref to ourselves on Exec. In the camera name space if the view context menu is up when the camera
  12715. // is unplugged, explorer faults because the view is torn down and the context menu exec tries to unwind
  12716. // after defview is gone. This holds a ref on defview while in exec so defview doesn't dissappear.
  12717. //
  12718. AddRef();
  12719. hr = _Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
  12720. Release();
  12721. return hr;
  12722. }
  12723. HRESULT CDefView::_Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
  12724. {
  12725. HRESULT hr = OLECMDERR_E_UNKNOWNGROUP;
  12726. if (pguidCmdGroup == NULL)
  12727. {
  12728. switch (nCmdID)
  12729. {
  12730. case OLECMDID_REFRESH:
  12731. _fAllowSearchingWindow = TRUE; // this exec typically comes from a user action (F5, Refresh)
  12732. if (FAILED(_ReloadContent()))
  12733. {
  12734. //This invalidation deletes the WebView and also avoid
  12735. //unpainted areas in ListView areas whose paint messages
  12736. //are eaten by the visible WebView
  12737. InvalidateRect(_hwndView, NULL, TRUE);
  12738. }
  12739. hr = S_OK;
  12740. break;
  12741. }
  12742. }
  12743. else if (IsEqualGUID(CGID_DefView, *pguidCmdGroup))
  12744. {
  12745. switch (nCmdID)
  12746. {
  12747. case DVID_SETASDEFAULT:
  12748. // 99/02/05 #226140 vtan: Exec command issued from
  12749. // CShellBrowser2::_SaveDefViewDefaultFolderSettings()
  12750. // when user clicks "Like Current Folder" in folder
  12751. // options "View" tab.
  12752. ASSERTMSG(nCmdexecopt == OLECMDEXECOPT_DODEFAULT, "nCmdexecopt must be OLECMDEXECOPT_DODEFAULT");
  12753. ASSERTMSG(pvarargIn == NULL, "pvarargIn must be NULL");
  12754. ASSERTMSG(pvarargOut == NULL, "pvarargOut must be NULL");
  12755. hr = _SaveGlobalViewState();
  12756. break;
  12757. case DVID_RESETDEFAULT:
  12758. // 99/02/05 #226140 vtan: Exec command issued from
  12759. // CShellBrowser2::_ResetDefViewDefaultFolderSettings()
  12760. // when user clicks "Reset All Folders" in folder
  12761. // options "View" tab.
  12762. ASSERTMSG(nCmdexecopt == OLECMDEXECOPT_DODEFAULT, "nCmdexecopt must be OLECMDEXECOPT_DODEFAULT");
  12763. ASSERTMSG(pvarargIn == NULL, "pvarargIn must be NULL");
  12764. ASSERTMSG(pvarargOut == NULL, "pvarargOut must be NULL");
  12765. hr = _ResetGlobalViewState();
  12766. break;
  12767. default:
  12768. break;
  12769. }
  12770. }
  12771. else if (IsEqualGUID(CGID_ShellDocView, *pguidCmdGroup))
  12772. {
  12773. switch (nCmdID)
  12774. {
  12775. case SHDVID_CANACTIVATENOW:
  12776. return _fCanActivateNow ? S_OK : S_FALSE;
  12777. // NOTE: for a long time IOleCommandTarget was implemented
  12778. // BUT it wasn't in the QI! At this late stage of the game
  12779. // I'll be paranoid and not forward everything down to the
  12780. // webview. We'll just pick off CANACTIVATENOW...
  12781. //
  12782. default:
  12783. return OLECMDERR_E_UNKNOWNGROUP;
  12784. }
  12785. }
  12786. else if (IsEqualGUID(CGID_Explorer, *pguidCmdGroup))
  12787. {
  12788. switch (nCmdID)
  12789. {
  12790. case SBCMDID_GETPANE:
  12791. V_I4(pvarargOut) = PANE_NONE;
  12792. CallCB(SFVM_GETPANE, nCmdexecopt, (LPARAM)&V_I4(pvarargOut));
  12793. return S_OK;
  12794. case SBCMDID_MIXEDZONE:
  12795. if (pvarargOut)
  12796. return _cFrame._GetCurrentZone(NULL, pvarargOut);
  12797. break;
  12798. default:
  12799. break;
  12800. }
  12801. }
  12802. else if (IsEqualGUID(IID_IExplorerToolbar, *pguidCmdGroup))
  12803. {
  12804. // handle the ones coming FROM itbar:
  12805. switch (nCmdID)
  12806. {
  12807. case ETCMDID_GETBUTTONS:
  12808. pvarargOut->vt = VT_BYREF;
  12809. pvarargOut->byref = (void *)_pbtn;
  12810. *pvarargIn->plVal = _cTotalButtons;
  12811. return S_OK;
  12812. case ETCMDID_RELOADBUTTONS:
  12813. MergeToolBar(TRUE);
  12814. return S_OK;
  12815. }
  12816. }
  12817. else if (IsEqualGUID(_clsid, *pguidCmdGroup))
  12818. {
  12819. UEMFireEvent(&UEMIID_BROWSER, UEME_UITOOLBAR, UEMF_XEVENT, UIG_OTHER, nCmdID);
  12820. DFVCMDDATA cd;
  12821. cd.pva = pvarargIn;
  12822. cd.hwnd = _hwndMain;
  12823. cd.nCmdIDTranslated = 0;
  12824. _OnCommand(NULL, nCmdID, (LPARAM)&cd);
  12825. }
  12826. // no need to pass OLECMDID_REFRESH on to the webview, as we
  12827. // just nuked and replaced the webview above -- a super refresh of sorts.
  12828. if (_cFrame.IsWebView() && hr != S_OK)
  12829. {
  12830. // Do not pass IDM_PARSECOMPLETE back to MSHTML. This will cause them to load mshtmled.dll
  12831. // unecessarily for webview which is a significant performance hit.
  12832. if (!(pguidCmdGroup && IsEqualGUID(CGID_MSHTML, *pguidCmdGroup) && (nCmdID == IDM_PARSECOMPLETE)))
  12833. {
  12834. IOleCommandTarget* pct;
  12835. if (SUCCEEDED(_cFrame.GetCommandTarget(&pct)))
  12836. {
  12837. hr = pct->Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
  12838. pct->Release();
  12839. }
  12840. }
  12841. }
  12842. return hr;
  12843. }
  12844. void CDefView::_ShowAndActivate()
  12845. {
  12846. // Can't call SetFocus because it rips focus away from such nice
  12847. // UI elements like the TREE pane...
  12848. // UIActivate will steal focus only if _uState is SVUIA_ACTIVATE_FOCUS
  12849. UIActivate(_uState);
  12850. }
  12851. // IDefViewFrame (available only through QueryService from sfvext!)
  12852. //
  12853. HRESULT CDefView::GetShellFolder(IShellFolder **ppsf)
  12854. {
  12855. *ppsf = _pshf;
  12856. if (*ppsf)
  12857. _pshf->AddRef();
  12858. return *ppsf ? S_OK : E_FAIL;
  12859. }
  12860. // IDefViewFrame3
  12861. //
  12862. HRESULT CDefView::GetWindowLV(HWND * phwnd)
  12863. {
  12864. if (!_IsDesktop())
  12865. {
  12866. if (!_fGetWindowLV)
  12867. {
  12868. _fGetWindowLV = TRUE;
  12869. // Caller will call ShowHideListView for us
  12870. *phwnd = _hwndListview;
  12871. }
  12872. TraceMsg(TF_DEFVIEW, "GetWindowLV - TAKEN");
  12873. return S_OK;
  12874. }
  12875. else
  12876. {
  12877. *phwnd = NULL;
  12878. return E_FAIL;
  12879. }
  12880. }
  12881. HRESULT CDefView::OnResizeListView()
  12882. {
  12883. _AutoAutoArrange(0);
  12884. return S_OK;
  12885. }
  12886. HRESULT CDefView::ReleaseWindowLV()
  12887. {
  12888. _fGetWindowLV = FALSE;
  12889. WndSize(_hwndView); // Make sure we resize _hwndListview
  12890. ShowHideListView();
  12891. return S_OK;
  12892. }
  12893. HRESULT CDefView::DoRename()
  12894. {
  12895. return HandleRename(NULL);
  12896. }
  12897. // IServiceProvider
  12898. STDMETHODIMP CDefView::QueryService(REFGUID guidService, REFIID riid, void **ppv)
  12899. {
  12900. HRESULT hr = E_FAIL;
  12901. *ppv = NULL;
  12902. if (guidService == SID_DefView) // private service ID
  12903. {
  12904. // DefViewOCs request this interface
  12905. if (riid != IID_IDefViewFrame || !_IsDesktop())
  12906. hr = QueryInterface(riid, ppv);
  12907. }
  12908. else if (guidService == SID_ShellTaskScheduler)
  12909. {
  12910. if (_pScheduler)
  12911. {
  12912. hr = _pScheduler->QueryInterface(riid, ppv);
  12913. }
  12914. }
  12915. else if ((guidService == SID_SContextMenuSite) ||
  12916. (guidService == SID_SFolderView)) // documented service ID
  12917. {
  12918. hr = QueryInterface(riid, ppv);
  12919. }
  12920. else if (guidService == SID_ShellFolderViewCB) // access to the view callback object
  12921. {
  12922. IShellFolderViewCB * psfvcb = _cCallback.GetSFVCB();
  12923. if (psfvcb)
  12924. hr = psfvcb->QueryInterface(riid, ppv);
  12925. }
  12926. else if (guidService == SID_WebViewObject)
  12927. {
  12928. if (_cFrame.IsWebView())
  12929. {
  12930. if (_cFrame._pOleObj)
  12931. {
  12932. //
  12933. // We hit this codepath while navigating away (while saving history),
  12934. // so there should not be any pending _cFrame._pOleObjNew as this
  12935. // view is going to be destroyed.
  12936. //
  12937. ASSERTMSG(!_cFrame._pOleObjNew, "Ambiguous Oleobj while peristing trident history in webview");
  12938. hr = _cFrame._pOleObj->QueryInterface(riid, ppv);
  12939. }
  12940. else if (_cFrame._pOleObjNew)
  12941. {
  12942. //
  12943. // We hit this codepath if we are navigating to the view (while loading history),
  12944. // we have not yet called _cFrame._SwitchToNewOleObj(), so we'll use
  12945. // the pending oleobj as CDefViewPersistHistory::LoadHistory()
  12946. // expects to get the right IPersistHistory interface from it.
  12947. //
  12948. hr = _cFrame._pOleObjNew->QueryInterface(riid, ppv);
  12949. }
  12950. }
  12951. }
  12952. else if (guidService == SID_SProgressUI)
  12953. {
  12954. // return a new instance of the progress dialog to the caller
  12955. hr = CoCreateInstance(CLSID_ProgressDialog, NULL, CLSCTX_INPROC_SERVER, riid, ppv);
  12956. }
  12957. else if (_psb)
  12958. {
  12959. hr = IUnknown_QueryService(_psb, guidService, riid, ppv); // send up the to the browser
  12960. }
  12961. else
  12962. {
  12963. hr = IUnknown_QueryService(_punkSite, guidService, riid, ppv); // or our site
  12964. }
  12965. return hr;
  12966. }
  12967. STDMETHODIMP CDefView::OnSetTitle(VARIANTARG *pvTitle)
  12968. {
  12969. return E_NOTIMPL;
  12970. }
  12971. BOOL CDefView::_LoadCategory(GUID *pguidGroupID)
  12972. {
  12973. BOOL fRet = FALSE;
  12974. LPITEMIDLIST pidl = _GetViewPidl();
  12975. if (pidl)
  12976. {
  12977. IPropertyBag *ppb;
  12978. if (SUCCEEDED(IUnknown_QueryServicePropertyBag(_psb, SHGVSPB_FOLDER, IID_PPV_ARG(IPropertyBag, &ppb))))
  12979. {
  12980. fRet = SUCCEEDED(SHPropertyBag_ReadGUID(ppb, TEXT("Categorize"), pguidGroupID));
  12981. ppb->Release();
  12982. }
  12983. ILFree(pidl);
  12984. }
  12985. return fRet;
  12986. }
  12987. void SHGetThumbnailSize(SIZE *psize)
  12988. {
  12989. psize->cx = psize->cy = 96;
  12990. DWORD dw = 0, cb = sizeof(dw);
  12991. SHRegGetUSValue(TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"),
  12992. TEXT("ThumbnailSize"), NULL, &dw, &cb, FALSE, NULL, 0);
  12993. if (dw >= 32 && dw <= 256) // constrain to reason
  12994. {
  12995. psize->cx = psize->cy = (int)dw;
  12996. }
  12997. }
  12998. void SHGetThumbnailSizeForThumbsDB(SIZE *psize)
  12999. {
  13000. SHGetThumbnailSize(psize);
  13001. // Due to tnail.cpp restriction buffer sizes, we can only go to 120 (since that's all we've tested at)
  13002. if (psize->cx > 120)
  13003. psize->cx = psize->cy = 120;
  13004. }
  13005. void CDefView::_GetThumbnailSize(SIZE *psize)
  13006. {
  13007. if (-1 == _sizeThumbnail.cx)
  13008. {
  13009. SHGetThumbnailSize(&_sizeThumbnail);
  13010. }
  13011. *psize = _sizeThumbnail;
  13012. }
  13013. #ifdef _X86_
  13014. //************
  13015. //
  13016. // More of the Hijaak Hack
  13017. //
  13018. // We return no attributes (specifically, Hijaak looks for
  13019. // SFGAO_FILESYSTEM) and Hijaak will say, "Whoa, I don't know
  13020. // how to patch this guy; I'll leave it alone."
  13021. STDAPI FakeHijaak_GetAttributesOf(void *_this, UINT cidl, LPCITEMIDLIST *apidl, ULONG *rgfInOut)
  13022. {
  13023. *rgfInOut = 0; // Move along, nothing to see here
  13024. return S_OK;
  13025. }
  13026. const struct FakeHijaakFolderVtbl
  13027. {
  13028. FARPROC Dummy[9];
  13029. FARPROC GetAttributesOf;
  13030. } c_FakeHijaakFolderVtbl = { { 0 }, (FARPROC)FakeHijaak_GetAttributesOf };
  13031. const LPVOID c_FakeHijaakFolder = (const LPVOID)&c_FakeHijaakFolderVtbl;
  13032. //
  13033. // End of the Hijaak Hack
  13034. //
  13035. //************
  13036. #endif // _X86_
  13037. CBackgroundDefviewInfo::CBackgroundDefviewInfo(LPCITEMIDLIST pidl, UINT uId) :
  13038. _pidl(pidl), _uId(uId)
  13039. {
  13040. }
  13041. CBackgroundDefviewInfo::~CBackgroundDefviewInfo (void)
  13042. {
  13043. ILFree(const_cast<LPITEMIDLIST>(_pidl));
  13044. }
  13045. CBackgroundColInfo::CBackgroundColInfo(LPCITEMIDLIST pidl, UINT uId, UINT uiCol, STRRET& strRet) :
  13046. CBackgroundDefviewInfo(pidl, uId),
  13047. _uiCol(uiCol)
  13048. {
  13049. StrRetToBuf(&strRet, NULL, const_cast<TCHAR*>(_szText), ARRAYSIZE(_szText));
  13050. }
  13051. CBackgroundColInfo::~CBackgroundColInfo(void)
  13052. {
  13053. }
  13054. // Takes ownership of pidl, copies rguColumns.
  13055. CBackgroundTileInfo::CBackgroundTileInfo(LPCITEMIDLIST pidl, UINT uId, UINT rguColumns[], UINT cColumns) :
  13056. CBackgroundDefviewInfo(pidl, uId),
  13057. _cColumns(cColumns)
  13058. {
  13059. ASSERT(cColumns <= (UINT)TILEVIEWLINES);
  13060. for (UINT i = 0; i < cColumns; i++)
  13061. _rguColumns[i] = rguColumns[i];
  13062. }
  13063. CBackgroundTileInfo::~CBackgroundTileInfo(void)
  13064. {
  13065. }
  13066. // Helper function that scales the given size by some percentage where the percentage
  13067. // is defined in the resources for the localizers to adjust as approp. Range is 0 to 30% larger
  13068. INT ScaleSizeBasedUponLocalization (INT iSize)
  13069. {
  13070. TCHAR szPercentageIncrease [3];
  13071. INT iReturnValue = iSize;
  13072. INT iPercentageIncrease;
  13073. if (iSize > 0)
  13074. {
  13075. if (LoadString(HINST_THISDLL, IDS_SIZE_INCREASE_PERCENTAGE, szPercentageIncrease, ARRAYSIZE(szPercentageIncrease)))
  13076. {
  13077. iPercentageIncrease = StrToInt(szPercentageIncrease);
  13078. if (iPercentageIncrease > 0)
  13079. {
  13080. if (iPercentageIncrease > 30)
  13081. {
  13082. iPercentageIncrease = 30;
  13083. }
  13084. iReturnValue += ((iPercentageIncrease * iSize) / 100);
  13085. }
  13086. }
  13087. }
  13088. return iReturnValue;
  13089. }
  13090. CBackgroundGroupInfo::CBackgroundGroupInfo (LPCITEMIDLIST pidl, UINT uId, DWORD dwGroupId):
  13091. CBackgroundDefviewInfo(pidl, uId), _dwGroupId(dwGroupId)
  13092. {
  13093. }
  13094. BOOL CBackgroundGroupInfo::VerifyGroupExists(HWND hwnd, ICategorizer* pcat)
  13095. {
  13096. if (!pcat)
  13097. return FALSE;
  13098. if (!ListView_HasGroup(hwnd, _dwGroupId))
  13099. {
  13100. CATEGORY_INFO ci;
  13101. pcat->GetCategoryInfo(_dwGroupId, &ci);
  13102. LVINSERTGROUPSORTED igrp;
  13103. igrp.pfnGroupCompare = GroupCompare;
  13104. igrp.pvData = (void *)pcat;
  13105. igrp.lvGroup.cbSize = sizeof(LVGROUP);
  13106. igrp.lvGroup.mask = LVGF_HEADER | LVGF_GROUPID;
  13107. igrp.lvGroup.pszHeader= ci.wszName;
  13108. igrp.lvGroup.iGroupId = (int)_dwGroupId;
  13109. ListView_InsertGroupSorted(hwnd, &igrp);
  13110. }
  13111. return TRUE;
  13112. }