Reactos
at master 4854 lines 157 kB view raw
1/* 2 * ShellView 3 * 4 * Copyright 1998,1999 <juergen.schmied@debitel.net> 5 * Copyright 2022 Russell Johnson <russell.johnson@superdark.net> 6 * 7 * This is the view visualizing the data provided by the shellfolder. 8 * No direct access to data from pidls should be done from here. 9 * 10 * This library is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU Lesser General Public 12 * License as published by the Free Software Foundation; either 13 * version 2.1 of the License, or (at your option) any later version. 14 * 15 * This library is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * Lesser General Public License for more details. 19 * 20 * You should have received a copy of the GNU Lesser General Public 21 * License along with this library; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 23 * 24 * FIXME: CheckToolbar: handle the "new folder" and "folder up" button 25 */ 26 27/* 28TODO: 29- When editing starts on item, set edit text to for editing value. 30- Fix shell view to handle view mode popup exec. 31- The background context menu should have a pidl just like foreground menus. This 32 causes crashes when dynamic handlers try to use the NULL pidl. 33- Reorder of columns doesn't work - might be bug in comctl32 34*/ 35 36#include "precomp.h" 37 38#include <atlwin.h> 39#include <ui/rosctrls.h> 40 41WINE_DEFAULT_DEBUG_CHANNEL(shell); 42 43// It would be easier to allocate these from 1 and up but the original code used the entire 44// FCIDM_SHVIEWFIRST..FCIDM_SHVIEWLAST range when dealing with IContextMenu and to avoid 45// breaking anything relying on this we will allocate our ranges from the end instead. 46enum { 47 DEFVIEW_ARRANGESORT_MAXENUM = 9, // Limit the number of the visible columns we will display in the submenu 48 DEFVIEW_ARRANGESORT_MAX = DEFVIEW_ARRANGESORT_MAXENUM + 1, // Reserve one extra for the current sort-by column 49 DVIDM_ARRANGESORT_LAST = FCIDM_SHVIEWLAST, 50 DVIDM_ARRANGESORT_FIRST = DVIDM_ARRANGESORT_LAST - (DEFVIEW_ARRANGESORT_MAX - 1), 51 DVIDM_COMMDLG_SELECT = DVIDM_ARRANGESORT_FIRST - 1, 52 53 DVIDM_CONTEXTMENU_LAST = DVIDM_COMMDLG_SELECT - 1, 54 // FIXME: FCIDM_SHVIEWFIRST is 0 and using that with QueryContextMenu is a 55 // bad idea because it hides bugs related to the ids in ici.lpVerb. 56 // CONTEXT_MENU_BASE_ID acknowledges this but failed to apply the fix everywhere. 57 DVIDM_CONTEXTMENU_FIRST = FCIDM_SHVIEWFIRST, 58}; 59#undef FCIDM_SHVIEWLAST // Don't use this constant, change DVIDM_CONTEXTMENU_LAST if you need a new id. 60 61struct LISTVIEW_SORT_INFO 62{ 63 INT8 Direction; 64 bool bLoadedFromViewState; 65 bool bColumnIsFolderColumn; 66 UINT8 Reserved; // Unused 67 INT ListColumn; 68 INT FolderColumn; // Only valid during a sorting operation 69 70 enum { UNSPECIFIEDCOLUMN = -1 }; 71 void Reset() 72 { 73 *(UINT*)this = 0; 74 ListColumn = UNSPECIFIEDCOLUMN; 75 } 76}; 77 78// For the context menu of the def view, the id of the items are based on 1 because we need 79// to call TrackPopupMenu and let it use the 0 value as an indication that the menu was canceled 80#define CONTEXT_MENU_BASE_ID 1 81 82struct PERSISTCOLUMNS 83{ 84 enum { MAXCOUNT = 100 }; 85 static const UINT SIG = ('R' << 0) | ('O' << 8) | ('S' << 16) | (('c') << 24); 86 UINT Signature; 87 UINT Count; 88 UINT Columns[MAXCOUNT]; 89}; 90 91struct PERSISTCLASSICVIEWSTATE 92{ 93 static const UINT SIG = ('R' << 0) | ('O' << 8) | ('S' << 16) | (('c' ^ 'v' ^ 's') << 24); 94 UINT Signature; 95 WORD SortColId; 96 INT8 SortDir; 97 static const UINT VALIDFWF = FWF_AUTOARRANGE | FWF_SNAPTOGRID | FWF_NOGROUPING; // Note: The desktop applies FWF_NOICONS when appropriate 98 FOLDERSETTINGS FolderSettings; 99}; 100 101static UINT 102GetContextMenuFlags(IShellBrowser *pSB, SFGAOF sfgao) 103{ 104 UINT cmf = CMF_NORMAL; 105 if (GetKeyState(VK_SHIFT) < 0) 106 cmf |= CMF_EXTENDEDVERBS; 107 if (sfgao & SFGAO_CANRENAME) 108 cmf |= CMF_CANRENAME; 109 HWND hwnd = NULL; 110 if (pSB && SUCCEEDED(pSB->GetControlWindow(FCW_TREE, &hwnd)) && hwnd) 111 cmf |= CMF_EXPLORE; 112 return cmf; 113} 114 115// Convert client coordinates to listview coordinates 116static void 117ClientToListView(HWND hwndLV, POINT *ppt) 118{ 119 POINT Origin = {}; 120 121 // FIXME: LVM_GETORIGIN is broken. See CORE-17266 122 if (!ListView_GetOrigin(hwndLV, &Origin)) 123 return; 124 125 ppt->x += Origin.x; 126 ppt->y += Origin.y; 127} 128 129// Helper struct to automatically cleanup the IContextMenu 130// We want to explicitly reset the Site, so there are no circular references 131struct MenuCleanup 132{ 133 CComPtr<IContextMenu> &m_pCM; 134 HMENU &m_hMenu; 135 136 MenuCleanup(CComPtr<IContextMenu> &pCM, HMENU& menu) 137 : m_pCM(pCM), m_hMenu(menu) 138 { 139 } 140 ~MenuCleanup() 141 { 142 if (m_pCM) 143 { 144 IUnknown_SetSite(m_pCM, NULL); 145 m_pCM.Release(); 146 } 147 if (m_hMenu) 148 { 149 DestroyMenu(m_hMenu); 150 m_hMenu = NULL; 151 } 152 } 153}; 154 155static BOOL AppendMenuItem(HMENU hMenu, UINT MF, UINT Id, LPCWSTR String, SIZE_T Data = 0) 156{ 157 MENUITEMINFOW mii; 158 mii.cbSize = sizeof(mii); 159 mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_DATA | MIIM_STATE; 160 mii.fState = MF & (MFS_CHECKED | MFS_DISABLED); 161 mii.fType = MF & ~mii.fState; 162 mii.wID = Id; 163 mii.dwTypeData = const_cast<LPWSTR>(String); 164 mii.dwItemData = Data; 165 return InsertMenuItemW(hMenu, -1, TRUE, &mii); 166} 167 168static SIZE_T GetMenuItemDataById(HMENU hMenu, UINT Id) 169{ 170 MENUITEMINFOW mii; 171 mii.cbSize = FIELD_OFFSET(MENUITEMINFOW, hbmpItem); 172 mii.fMask = MIIM_DATA; 173 if (GetMenuItemInfoW(hMenu, Id, FALSE, &mii)) 174 return mii.dwItemData; 175 else 176 return 0; 177} 178 179static HMENU GetSubmenuByID(HMENU hmenu, UINT id) 180{ 181 MENUITEMINFOW mii = {sizeof(mii), MIIM_SUBMENU}; 182 if (::GetMenuItemInfoW(hmenu, id, FALSE, &mii)) 183 return mii.hSubMenu; 184 185 return NULL; 186} 187 188/* ReallyGetMenuItemID returns the id of an item even if it opens a submenu, 189 GetMenuItemID returns -1 if the specified item opens a submenu */ 190static UINT ReallyGetMenuItemID(HMENU hmenu, int i) 191{ 192 MENUITEMINFOW mii = {sizeof(mii), MIIM_ID}; 193 if (::GetMenuItemInfoW(hmenu, i, TRUE, &mii)) 194 return mii.wID; 195 196 return UINT_MAX; 197} 198 199static UINT CalculateCharWidth(HWND hwnd) 200{ 201 UINT ret = 0; 202 HDC hDC = GetDC(hwnd); 203 if (hDC) 204 { 205 HGDIOBJ hOrg = SelectObject(hDC, (HGDIOBJ)SendMessage(hwnd, WM_GETFONT, 0, 0)); 206 ret = GdiGetCharDimensions(hDC, NULL, NULL); 207 SelectObject(hDC, hOrg); 208 ReleaseDC(hwnd, hDC); 209 } 210 return ret; 211} 212 213static inline COLORREF GetViewColor(COLORREF Clr, UINT SysFallback) 214{ 215 return Clr != CLR_INVALID ? Clr : GetSysColor(SysFallback); 216} 217 218#define VID_Default ( *(const SHELLVIEWID*)&IID_CDefView ) 219extern HRESULT ShellViewIdToFolderViewMode(const SHELLVIEWID *pVid); 220extern const SHELLVIEWID* FolderViewModeToShellViewId(UINT FVM); 221 222class CDefView : 223 public CWindowImpl<CDefView, CWindow, CControlWinTraits>, 224 public CComObjectRootEx<CComMultiThreadModelNoCS>, 225 public IShellView3, 226 public IFolderView, 227 public IShellFolderView, 228 public IOleCommandTarget, 229 public IDropTarget, 230 public IDropSource, 231 public IViewObject, 232 public IServiceProvider 233{ 234private: 235 CComPtr<IShellFolder> m_pSFParent; 236 CComPtr<IShellFolder2> m_pSF2Parent; 237 CComPtr<IShellDetails> m_pSDParent; 238 CComPtr<IShellFolderViewCB> m_pShellFolderViewCB; 239 CComPtr<IShellBrowser> m_pShellBrowser; 240 CComPtr<ICommDlgBrowser> m_pCommDlgBrowser; 241 CComPtr<IFolderFilter> m_pFolderFilter; 242 CComPtr<IShellFolderViewDual> m_pShellFolderViewDual; 243 ClipboardViewerChain m_ClipboardChain; 244 CListView m_ListView; 245 HWND m_hWndParent; 246 FOLDERSETTINGS m_FolderSettings; 247 HMENU m_hMenu; // Handle to the menu bar of the browser 248 HMENU m_hMenuArrangeModes; // Handle to the popup menu with the arrange modes 249 HMENU m_hMenuViewModes; // Handle to the popup menu with the view modes 250 HMENU m_hContextMenu; // Handle to the open context menu 251 BOOL m_bmenuBarInitialized; 252 UINT m_uState; 253 UINT m_cidl; 254 PCUITEMID_CHILD *m_apidl; 255 PIDLIST_ABSOLUTE m_pidlParent; 256 HDPA m_LoadColumnsList; 257 HDPA m_ListToFolderColMap; 258 LISTVIEW_SORT_INFO m_sortInfo; 259 ULONG m_hNotify; // Change notification handle 260 HACCEL m_hAccel; 261 DWORD m_dwAspects; 262 DWORD m_dwAdvf; 263 CComPtr<IAdviseSink> m_pAdvSink; 264 // for drag and drop 265 CComPtr<IDataObject> m_pSourceDataObject; 266 CComPtr<IDropTarget> m_pCurDropTarget; // The sub-item, which is currently dragged over 267 CComPtr<IDataObject> m_pCurDataObject; // The dragged data-object 268 LONG m_iDragOverItem; // Dragged over item's index, if m_pCurDropTarget != NULL 269 UINT m_cScrollDelay; // Send a WM_*SCROLL msg every 250 ms during drag-scroll 270 POINT m_ptLastMousePos; // Mouse position at last DragOver call 271 POINT m_ptFirstMousePos; // Mouse position when the drag operation started 272 DWORD m_grfKeyState; 273 // 274 CComPtr<IContextMenu> m_pCM; 275 CComPtr<IContextMenu> m_pFileMenu; 276 277 BOOL m_isEditing; 278 signed char m_SpecialFolder; 279 bool m_isFullStatusBar; 280 bool m_ScheduledStatusbarUpdate; 281 bool m_HasCutItems; 282 283 CLSID m_Category; 284 BOOL m_Destroyed; 285 SFVM_CUSTOMVIEWINFO_DATA m_viewinfo_data; 286 287 HICON m_hMyComputerIcon; 288 289 HRESULT _MergeToolbar(); 290 BOOL _Sort(int Col = -1); 291 HRESULT _DoFolderViewCB(UINT uMsg, WPARAM wParam, LPARAM lParam); 292 HRESULT _GetSnapToGrid(); 293 void _MoveSelectionOnAutoArrange(POINT pt); 294 INT _FindInsertableIndexFromPoint(POINT pt); 295 void _HandleStatusBarResize(int width); 296 void _ForceStatusBarResize(); 297 void _DoCopyToMoveToFolder(BOOL bCopy); 298 BOOL IsDesktop() const { return m_FolderSettings.fFlags & FWF_DESKTOP; } 299 300 inline BOOL IsSpecialFolder(int &csidl) const 301 { 302 csidl = m_SpecialFolder; 303 return m_SpecialFolder >= 0; 304 } 305 306public: 307 CDefView(); 308 ~CDefView(); 309 HRESULT WINAPI Initialize(IShellFolder *shellFolder); 310 HRESULT IncludeObject(PCUITEMID_CHILD pidl); 311 HRESULT OnDefaultCommand(); 312 HRESULT OnStateChange(UINT uFlags); 313 void UpdateStatusbar(); 314 void UpdateStatusbarLocation(); 315 void CheckToolbar(); 316 BOOL CreateList(); 317 void UpdateListColors(); 318 BOOL InitList(); 319 static INT CALLBACK ListViewCompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lpData); 320 321 HRESULT MapFolderColumnToListColumn(UINT FoldCol); 322 HRESULT MapListColumnToFolderColumn(UINT ListCol); 323 HRESULT GetDetailsByFolderColumn(PCUITEMID_CHILD pidl, UINT FoldCol, SHELLDETAILS &sd); 324 HRESULT GetDetailsByListColumn(PCUITEMID_CHILD pidl, UINT ListCol, SHELLDETAILS &sd); 325 HRESULT LoadColumn(UINT FoldCol, UINT ListCol, BOOL Insert, UINT ForceWidth = 0); 326 HRESULT LoadColumns(SIZE_T *pColList = NULL, UINT ColListCount = 0); 327 void ColumnListChanged(); 328 SFGAOF GetItemAttributes(PCUITEMID_CHILD pidl, UINT Query); 329 SFGAOF GetItemAttributes(int i, UINT Query); 330 void RefreshGhostedState(); 331 PCUITEMID_CHILD _PidlByItem(int i); 332 PCUITEMID_CHILD _PidlByItem(LVITEM& lvItem); 333 int LV_FindItemByPidl(PCUITEMID_CHILD pidl); 334 int LV_AddItem(PCUITEMID_CHILD pidl); 335 BOOLEAN LV_DeleteItem(PCUITEMID_CHILD pidl); 336 BOOLEAN LV_RenameItem(PCUITEMID_CHILD pidlOld, PCUITEMID_CHILD pidlNew); 337 BOOL LV_UpdateItem(INT nItem, PCUITEMID_CHILD pidl); 338 BOOL LV_UpdateItem(PCUITEMID_CHILD pidl); 339 void LV_RefreshIcon(INT iItem); 340 void LV_RefreshIcons(); 341 static INT CALLBACK fill_list(LPVOID ptr, LPVOID arg); 342 HRESULT FillList(BOOL IsRefreshCommand = TRUE); 343 HRESULT FillFileMenu(); 344 HRESULT FillEditMenu(); 345 HRESULT FillViewMenu(); 346 HRESULT FillArrangeAsMenu(HMENU hmenuArrange); 347 HRESULT CheckViewMode(HMENU hmenuView); 348 LRESULT DoColumnContextMenu(LRESULT lParam); 349 HRESULT SelectAndPositionItem(int Idx, UINT fSVSI, POINT *ppt); 350 UINT GetSelections(); 351 SFGAOF GetSelectionAttributes(SFGAOF Query); 352 HRESULT OpenSelectedItems(PCSTR pszVerb = NULL); 353 void OnDeactivate(); 354 void DoActivate(UINT uState); 355 HRESULT drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect); 356 HRESULT InvokeContextMenuCommand(CComPtr<IContextMenu>& pCM, LPCSTR lpVerb, POINT* pt = NULL, bool TryMapVerb = false); 357 LRESULT OnExplorerCommand(UINT uCommand, BOOL bUseSelection); 358 FOLDERVIEWMODE GetDefaultViewMode(); 359 HRESULT GetDefaultViewStream(DWORD Stgm, IStream **ppStream); 360 HRESULT LoadViewState(); 361 HRESULT SaveViewState(IStream *pStream); 362 void UpdateFolderViewFlags(); 363 UINT GetItemActivateFlags(); 364 365 DWORD GetCommDlgViewFlags() 366 { 367 CComPtr<ICommDlgBrowser2> pcdb2; 368 if (m_pCommDlgBrowser && SUCCEEDED(m_pCommDlgBrowser->QueryInterface(IID_PPV_ARG(ICommDlgBrowser2, &pcdb2)))) 369 { 370 DWORD flags; 371 if (SUCCEEDED(pcdb2->GetViewFlags(&flags))) 372 return flags; 373 } 374 return 0; 375 } 376 377 static inline bool IsSupportedFolderViewMode(int Mode) 378 { 379 return Mode >= FVM_FIRST && Mode <= FVM_DETAILS; // We don't support Tile nor Thumbstrip 380 } 381 382 // *** IOleWindow methods *** 383 STDMETHOD(GetWindow)(HWND *lphwnd) override; 384 STDMETHOD(ContextSensitiveHelp)(BOOL fEnterMode) override; 385 386 // *** IShellView methods *** 387 STDMETHOD(TranslateAccelerator)(MSG *pmsg) override; 388 STDMETHOD(EnableModeless)(BOOL fEnable) override; 389 STDMETHOD(UIActivate)(UINT uState) override; 390 STDMETHOD(Refresh)() override; 391 STDMETHOD(CreateViewWindow)(IShellView *psvPrevious, LPCFOLDERSETTINGS pfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd) override; 392 STDMETHOD(DestroyViewWindow)() override; 393 STDMETHOD(GetCurrentInfo)(LPFOLDERSETTINGS pfs) override; 394 STDMETHOD(AddPropertySheetPages)(DWORD dwReserved, LPFNSVADDPROPSHEETPAGE pfn, LPARAM lparam) override; 395 STDMETHOD(SaveViewState)() override; 396 STDMETHOD(SelectItem)(PCUITEMID_CHILD pidlItem, SVSIF uFlags) override; 397 STDMETHOD(GetItemObject)(UINT uItem, REFIID riid, void **ppv) override; 398 399 // *** IShellView2 methods *** 400 STDMETHOD(GetView)(SHELLVIEWID *pVid, ULONG view_type) override; 401 STDMETHOD(CreateViewWindow2)(LPSV2CVW2_PARAMS view_params) override; 402 STDMETHOD(HandleRename)(LPCITEMIDLIST pidl) override; 403 STDMETHOD(SelectAndPositionItem)(LPCITEMIDLIST item, UINT flags, POINT *point) override; 404 405 // *** IShellView3 methods *** 406 STDMETHOD(CreateViewWindow3)( 407 IShellBrowser *psb, 408 IShellView *psvPrevious, 409 SV3CVW3_FLAGS view_flags, 410 FOLDERFLAGS mask, 411 FOLDERFLAGS flags, 412 FOLDERVIEWMODE mode, 413 const SHELLVIEWID *view_id, 414 const RECT *prcView, 415 HWND *hwnd) override; 416 417 // *** IFolderView methods *** 418 STDMETHOD(GetCurrentViewMode)(UINT *pViewMode) override; 419 STDMETHOD(SetCurrentViewMode)(UINT ViewMode) override; 420 STDMETHOD(GetFolder)(REFIID riid, void **ppv) override; 421 STDMETHOD(Item)(int iItemIndex, PITEMID_CHILD *ppidl) override; 422 STDMETHOD(ItemCount)(UINT uFlags, int *pcItems) override; 423 STDMETHOD(Items)(UINT uFlags, REFIID riid, void **ppv) override; 424 STDMETHOD(GetSelectionMarkedItem)(int *piItem) override; 425 STDMETHOD(GetFocusedItem)(int *piItem) override; 426 STDMETHOD(GetItemPosition)(PCUITEMID_CHILD pidl, POINT *ppt) override; 427 STDMETHOD(GetSpacing)(POINT *ppt) override; 428 STDMETHOD(GetDefaultSpacing)(POINT *ppt) override; 429 STDMETHOD(GetAutoArrange)() override; 430 STDMETHOD(SelectItem)(int iItem, DWORD dwFlags) override; 431 STDMETHOD(SelectAndPositionItems)(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, POINT *apt, DWORD dwFlags) override; 432 433 // *** IShellFolderView methods *** 434 STDMETHOD(Rearrange)(LPARAM sort) override; 435 STDMETHOD(GetArrangeParam)(LPARAM *sort) override; 436 STDMETHOD(ArrangeGrid)() override; 437 STDMETHOD(AutoArrange)() override; 438 STDMETHOD(AddObject)(PITEMID_CHILD pidl, UINT *item) override; 439 STDMETHOD(GetObject)(PITEMID_CHILD *pidl, UINT item) override; 440 STDMETHOD(RemoveObject)(PITEMID_CHILD pidl, UINT *item) override; 441 STDMETHOD(GetObjectCount)(UINT *count) override; 442 STDMETHOD(SetObjectCount)(UINT count, UINT flags) override; 443 STDMETHOD(UpdateObject)(PITEMID_CHILD pidl_old, PITEMID_CHILD pidl_new, UINT *item) override; 444 STDMETHOD(RefreshObject)(PITEMID_CHILD pidl, UINT *item) override; 445 STDMETHOD(SetRedraw)(BOOL redraw) override; 446 STDMETHOD(GetSelectedCount)(UINT *count) override; 447 STDMETHOD(GetSelectedObjects)(PCUITEMID_CHILD **pidl, UINT *items) override; 448 STDMETHOD(IsDropOnSource)(IDropTarget *drop_target) override; 449 STDMETHOD(GetDragPoint)(POINT *pt) override; 450 STDMETHOD(GetDropPoint)(POINT *pt) override; 451 STDMETHOD(MoveIcons)(IDataObject *obj) override; 452 STDMETHOD(SetItemPos)(PCUITEMID_CHILD pidl, POINT *pt) override; 453 STDMETHOD(IsBkDropTarget)(IDropTarget *drop_target) override; 454 STDMETHOD(SetClipboard)(BOOL move) override; 455 STDMETHOD(SetPoints)(IDataObject *obj) override; 456 STDMETHOD(GetItemSpacing)(ITEMSPACING *spacing) override; 457 STDMETHOD(SetCallback)(IShellFolderViewCB *new_cb, IShellFolderViewCB **old_cb) override; 458 STDMETHOD(Select)(UINT flags) override; 459 STDMETHOD(QuerySupport)(UINT *support) override; 460 STDMETHOD(SetAutomationObject)(IDispatch *disp) override; 461 462 // *** IOleCommandTarget methods *** 463 STDMETHOD(QueryStatus)(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText) override; 464 STDMETHOD(Exec)(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut) override; 465 466 // *** IDropTarget methods *** 467 STDMETHOD(DragEnter)(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) override; 468 STDMETHOD(DragOver)(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) override; 469 STDMETHOD(DragLeave)() override; 470 STDMETHOD(Drop)(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) override; 471 472 // *** IDropSource methods *** 473 STDMETHOD(QueryContinueDrag)(BOOL fEscapePressed, DWORD grfKeyState) override; 474 STDMETHOD(GiveFeedback)(DWORD dwEffect) override; 475 476 // *** IViewObject methods *** 477 STDMETHOD(Draw)(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, 478 HDC hdcTargetDev, HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL lprcWBounds, 479 BOOL (STDMETHODCALLTYPE *pfnContinue)(ULONG_PTR dwContinue), ULONG_PTR dwContinue) override; 480 STDMETHOD(GetColorSet)(DWORD dwDrawAspect, LONG lindex, void *pvAspect, 481 DVTARGETDEVICE *ptd, HDC hicTargetDev, LOGPALETTE **ppColorSet) override; 482 STDMETHOD(Freeze)(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze) override; 483 STDMETHOD(Unfreeze)(DWORD dwFreeze) override; 484 STDMETHOD(SetAdvise)(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink) override; 485 STDMETHOD(GetAdvise)(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink) override; 486 487 // *** IServiceProvider methods *** 488 STDMETHOD(QueryService)(REFGUID guidService, REFIID riid, void **ppvObject) override; 489 490 // Message handlers 491 LRESULT OnShowWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 492 LRESULT OnGetDlgCode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 493 LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 494 LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 495 LRESULT OnPrintClient(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 496 LRESULT OnSysColorChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 497 LRESULT OnGetShellBrowser(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 498 LRESULT OnNCCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 499 LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 500 LRESULT OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 501 LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 502 LRESULT OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 503 LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 504 LRESULT OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 505 LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 506 LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 507 LRESULT OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 508 LRESULT OnUpdateStatusbar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 509 LRESULT OnMenuMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 510 LRESULT OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 511 LRESULT OnInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 512 LRESULT OnChangeCBChain(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 513 LRESULT OnDrawClipboard(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 514 515 virtual VOID OnFinalMessage(HWND) override; 516 517 static ATL::CWndClassInfo& GetWndClassInfo() 518 { 519 static ATL::CWndClassInfo wc = 520 { 521 { sizeof(WNDCLASSEX), CS_PARENTDC, StartWindowProc, 522 0, 0, NULL, NULL, 523 LoadCursor(NULL, IDC_ARROW), NULL, NULL, L"SHELLDLL_DefView", NULL 524 }, 525 NULL, NULL, IDC_ARROW, TRUE, 0, _T("") 526 }; 527 return wc; 528 } 529 530 virtual WNDPROC GetWindowProc() override 531 { 532 return WindowProc; 533 } 534 535 static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 536 { 537 CDefView *pThis; 538 LRESULT result; 539 540 // Must hold a reference during message handling 541 pThis = reinterpret_cast<CDefView *>(hWnd); 542 pThis->AddRef(); 543 result = CWindowImpl<CDefView, CWindow, CControlWinTraits>::WindowProc(hWnd, uMsg, wParam, lParam); 544 pThis->Release(); 545 return result; 546 } 547 548 BEGIN_MSG_MAP(CDefView) 549 MESSAGE_HANDLER(WM_SIZE, OnSize) 550 MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) 551 MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus) 552 MESSAGE_HANDLER(WM_NCCREATE, OnNCCreate) 553 MESSAGE_HANDLER(WM_CREATE, OnCreate) 554 MESSAGE_HANDLER(WM_ACTIVATE, OnActivate) 555 MESSAGE_HANDLER(WM_NOTIFY, OnNotify) 556 MESSAGE_HANDLER(WM_COMMAND, OnCommand) 557 MESSAGE_HANDLER(SHV_CHANGE_NOTIFY, OnChangeNotify) 558 MESSAGE_HANDLER(SHV_UPDATESTATUSBAR, OnUpdateStatusbar) 559 MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu) 560 MESSAGE_HANDLER(WM_DRAWITEM, OnMenuMessage) 561 MESSAGE_HANDLER(WM_MEASUREITEM, OnMenuMessage) 562 MESSAGE_HANDLER(WM_SHOWWINDOW, OnShowWindow) 563 MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode) 564 MESSAGE_HANDLER(WM_DESTROY, OnDestroy) 565 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) 566 MESSAGE_HANDLER(WM_PRINTCLIENT, OnPrintClient) 567 MESSAGE_HANDLER(WM_SYSCOLORCHANGE, OnSysColorChange) 568 MESSAGE_HANDLER(CWM_GETISHELLBROWSER, OnGetShellBrowser) 569 MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) 570 MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup) 571 MESSAGE_HANDLER(WM_CHANGECBCHAIN, OnChangeCBChain) 572 MESSAGE_HANDLER(WM_DRAWCLIPBOARD, OnDrawClipboard) 573 END_MSG_MAP() 574 575 BEGIN_COM_MAP(CDefView) 576 // Windows returns E_NOINTERFACE for IOleWindow 577 // COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow) 578 COM_INTERFACE_ENTRY_IID(IID_IShellView, IShellView) 579 COM_INTERFACE_ENTRY_IID(IID_CDefView, IShellView) 580 COM_INTERFACE_ENTRY_IID(IID_IShellView2, IShellView2) 581 COM_INTERFACE_ENTRY_IID(IID_IShellView3, IShellView3) 582 COM_INTERFACE_ENTRY_IID(IID_IFolderView, IFolderView) 583 COM_INTERFACE_ENTRY_IID(IID_IShellFolderView, IShellFolderView) 584 COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget) 585 COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget) 586 COM_INTERFACE_ENTRY_IID(IID_IDropSource, IDropSource) 587 COM_INTERFACE_ENTRY_IID(IID_IViewObject, IViewObject) 588 COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider) 589 END_COM_MAP() 590}; 591 592#define ID_LISTVIEW 1 593 594// windowsx.h 595#define GET_WM_COMMAND_ID(wp, lp) LOWORD(wp) 596#define GET_WM_COMMAND_HWND(wp, lp) (HWND)(lp) 597#define GET_WM_COMMAND_CMD(wp, lp) HIWORD(wp) 598 599typedef void (CALLBACK *PFNSHGETSETTINGSPROC)(LPSHELLFLAGSTATE lpsfs, DWORD dwMask); 600 601CDefView::CDefView() : 602 m_ListView(), 603 m_hWndParent(NULL), 604 m_hMenu(NULL), 605 m_hMenuArrangeModes(NULL), 606 m_hMenuViewModes(NULL), 607 m_hContextMenu(NULL), 608 m_bmenuBarInitialized(FALSE), 609 m_uState(0), 610 m_cidl(0), 611 m_apidl(NULL), 612 m_pidlParent(NULL), 613 m_LoadColumnsList(NULL), 614 m_hNotify(0), 615 m_hAccel(NULL), 616 m_dwAspects(0), 617 m_dwAdvf(0), 618 m_iDragOverItem(0), 619 m_cScrollDelay(0), 620 m_isEditing(FALSE), 621 m_SpecialFolder(-1), 622 m_isFullStatusBar(true), 623 m_ScheduledStatusbarUpdate(false), 624 m_HasCutItems(false), 625 m_Destroyed(FALSE) 626{ 627 ZeroMemory(&m_FolderSettings, sizeof(m_FolderSettings)); 628 ZeroMemory(&m_ptLastMousePos, sizeof(m_ptLastMousePos)); 629 ZeroMemory(&m_Category, sizeof(m_Category)); 630 m_viewinfo_data.clrText = CLR_INVALID; 631 m_viewinfo_data.clrTextBack = CLR_INVALID; 632 m_viewinfo_data.hbmBack = NULL; 633 634 m_sortInfo.Reset(); 635 m_ListToFolderColMap = DPA_Create(0); 636 m_hMyComputerIcon = LoadIconW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_COMPUTER_DESKTOP)); 637} 638 639CDefView::~CDefView() 640{ 641 TRACE(" destroying IShellView(%p)\n", this); 642 643 _DoFolderViewCB(SFVM_VIEWRELEASE, 0, 0); 644 645 if (m_viewinfo_data.hbmBack) 646 { 647 ::DeleteObject(m_viewinfo_data.hbmBack); 648 m_viewinfo_data.hbmBack = NULL; 649 } 650 651 if (m_hWnd) 652 { 653 DestroyViewWindow(); 654 } 655 656 SHFree(m_apidl); 657 DPA_Destroy(m_LoadColumnsList); 658 DPA_Destroy(m_ListToFolderColMap); 659} 660 661HRESULT WINAPI CDefView::Initialize(IShellFolder *shellFolder) 662{ 663 m_pSFParent = shellFolder; 664 shellFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, &m_pSF2Parent)); 665 shellFolder->QueryInterface(IID_PPV_ARG(IShellDetails, &m_pSDParent)); 666 667 return S_OK; 668} 669 670// ##### helperfunctions for communication with ICommDlgBrowser ##### 671 672HRESULT CDefView::IncludeObject(PCUITEMID_CHILD pidl) 673{ 674 HRESULT ret = S_OK; 675 if (m_pCommDlgBrowser && !(GetCommDlgViewFlags() & CDB2GVF_NOINCLUDEITEM)) 676 { 677 TRACE("ICommDlgBrowser::IncludeObject pidl=%p\n", pidl); 678 ret = m_pCommDlgBrowser->IncludeObject(this, pidl); 679 TRACE("-- returns 0x%08x\n", ret); 680 } 681 else if (m_pFolderFilter) 682 { 683 ret = m_pFolderFilter->ShouldShow(m_pSFParent, m_pidlParent, pidl); 684 } 685 return ret; 686} 687 688HRESULT CDefView::OnDefaultCommand() 689{ 690 HRESULT ret = S_FALSE; 691 692 if (m_pCommDlgBrowser.p != NULL) 693 { 694 TRACE("ICommDlgBrowser::OnDefaultCommand\n"); 695 ret = m_pCommDlgBrowser->OnDefaultCommand(this); 696 TRACE("-- returns 0x%08x\n", ret); 697 } 698 699 return ret; 700} 701 702HRESULT CDefView::OnStateChange(UINT uFlags) 703{ 704 HRESULT ret = S_FALSE; 705 706 if (m_pCommDlgBrowser.p != NULL) 707 { 708 TRACE("ICommDlgBrowser::OnStateChange flags=%x\n", uFlags); 709 ret = m_pCommDlgBrowser->OnStateChange(this, uFlags); 710 TRACE("--\n"); 711 } 712 713 return ret; 714} 715/********************************************************** 716 * set the toolbar of the filedialog buttons 717 * 718 * - activates the buttons from the shellbrowser according to 719 * the view state 720 */ 721void CDefView::CheckToolbar() 722{ 723 LRESULT result; 724 725 TRACE("\n"); 726 727 if (m_pCommDlgBrowser != NULL) 728 { 729 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_CHECKBUTTON, 730 FCIDM_TB_SMALLICON, (m_FolderSettings.ViewMode == FVM_LIST) ? TRUE : FALSE, &result); 731 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_CHECKBUTTON, 732 FCIDM_TB_REPORTVIEW, (m_FolderSettings.ViewMode == FVM_DETAILS) ? TRUE : FALSE, &result); 733 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON, 734 FCIDM_TB_SMALLICON, TRUE, &result); 735 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON, 736 FCIDM_TB_REPORTVIEW, TRUE, &result); 737 } 738} 739 740void CDefView::UpdateStatusbar() 741{ 742 WCHAR szFormat[MAX_PATH]; 743 WCHAR szPartText[MAX_PATH]; 744 UINT cSelectedItems; 745 746 if (!m_ListView) 747 return; 748 749 cSelectedItems = m_ListView.GetSelectedCount(); 750 if (cSelectedItems) 751 { 752 LoadStringW(shell32_hInstance, IDS_OBJECTS_SELECTED, szFormat, _countof(szFormat)); 753 StringCchPrintfW(szPartText, _countof(szPartText), szFormat, cSelectedItems); 754 } 755 else 756 { 757 LoadStringW(shell32_hInstance, IDS_OBJECTS, szFormat, _countof(szFormat)); 758 StringCchPrintfW(szPartText, _countof(szPartText), szFormat, m_ListView.GetItemCount()); 759 } 760 761 LRESULT lResult; 762 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXT, 0, (LPARAM)szPartText, &lResult); 763 764 // Don't bother with the extra processing if we only have one StatusBar part 765 if (m_isFullStatusBar) 766 { 767 UINT64 uTotalFileSize = 0; 768 WORD uFileFlags = LVNI_ALL; 769 INT nItem = -1; 770 bool bIsOnlyFoldersSelected = true; 771 772 // If we have something selected then only count selected file sizes 773 if (cSelectedItems) 774 { 775 uFileFlags = LVNI_SELECTED; 776 } 777 778 while ((nItem = m_ListView.GetNextItem(nItem, uFileFlags)) >= 0) 779 { 780 PCUITEMID_CHILD pidl = _PidlByItem(nItem); 781 782 uTotalFileSize += _ILGetFileSize(pidl, NULL, 0); 783 784 if (!_ILIsFolder(pidl)) 785 { 786 bIsOnlyFoldersSelected = false; 787 } 788 } 789 790 // Don't show the file size text if there is 0 bytes in the folder 791 // OR we only have folders selected 792 if ((cSelectedItems && !bIsOnlyFoldersSelected) || uTotalFileSize) 793 StrFormatByteSizeW(uTotalFileSize, szPartText, _countof(szPartText)); 794 else 795 *szPartText = 0; 796 797 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXT, 1, (LPARAM)szPartText, &lResult); 798 } 799 800 SFGAOF att = 0; 801 if (cSelectedItems > 0) 802 { 803 UINT maxquery = 42; // Checking the attributes can be slow, only check small selections (_DoCopyToMoveToFolder will verify the full array) 804 att = SFGAO_CANCOPY | SFGAO_CANMOVE; 805 if (cSelectedItems <= maxquery && (!GetSelections() || FAILED(m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &att)))) 806 att = 0; 807 } 808 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON, FCIDM_SHVIEW_COPYTO, (att & SFGAO_CANCOPY) != 0, &lResult); 809 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON, FCIDM_SHVIEW_MOVETO, (att & SFGAO_CANMOVE) != 0, &lResult); 810} 811 812void CDefView::UpdateStatusbarLocation() 813{ 814 LRESULT lResult; 815 LPARAM pIcon = NULL; 816 WCHAR szPartText[MAX_PATH]; 817 *szPartText = 0; 818 if (m_isFullStatusBar) 819 { 820 // If we are in a Recycle Bin then show no text for the location part 821 int csidl; 822 if (!IsSpecialFolder(csidl) || (csidl != CSIDL_NETWORK && csidl != CSIDL_BITBUCKET)) 823 { 824 LoadStringW(shell32_hInstance, IDS_MYCOMPUTER, szPartText, _countof(szPartText)); 825 pIcon = (LPARAM)m_hMyComputerIcon; 826 } 827 /*else if (csidl == CSIDL_NETWORK) // TODO: Figure out the type of share (My Computer/Local Intranet/Internet?) 828 { 829 ImageList_GetIconSize(ListView_GetImageList(m_ListView, LVSIL_SMALL), &x, &y); 830 pIcon = (LPARAM)LoadImage(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_MY_NETWORK_PLACES), 831 IMAGE_ICON, x, y, LR_SHARED); 832 }*/ 833 } 834 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETICON, 2, pIcon, &lResult); 835 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXT, 2, (LPARAM)szPartText, &lResult); 836} 837 838LRESULT CDefView::OnUpdateStatusbar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 839{ 840 m_ScheduledStatusbarUpdate = false; 841 UpdateStatusbar(); 842 return 0; 843} 844 845 846// ##### helperfunctions for initializing the view ##### 847 848// creates the list view window 849BOOL CDefView::CreateList() 850{ 851 DWORD dwStyle, dwExStyle, ListExStyle; 852 TRACE("%p\n", this); 853 854 dwStyle = WS_TABSTOP | WS_VISIBLE | WS_CHILDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | 855 LVS_SHAREIMAGELISTS | LVS_EDITLABELS | LVS_AUTOARRANGE; // FIXME: Remove LVS_AUTOARRANGE when the view is able to save ItemPos 856 dwExStyle = (m_FolderSettings.fFlags & FWF_NOCLIENTEDGE) ? 0 : WS_EX_CLIENTEDGE; 857 ListExStyle = LVS_EX_INFOTIP | LVS_EX_LABELTIP; 858 859 if (m_FolderSettings.fFlags & FWF_DESKTOP) 860 { 861 m_FolderSettings.fFlags |= FWF_NOCLIENTEDGE | FWF_NOSCROLL; 862 dwStyle |= LVS_ALIGNLEFT; 863 // LVS_EX_REGIONAL? 864 } 865 else 866 { 867 dwStyle |= LVS_SHOWSELALWAYS; // MSDN says FWF_SHOWSELALWAYS is deprecated, always turn on for folders 868 dwStyle |= (m_FolderSettings.fFlags & FWF_ALIGNLEFT) ? LVS_ALIGNLEFT : LVS_ALIGNTOP; 869#if 0 // FIXME: Temporarily disabled until ListView is fixed (CORE-19624, CORE-19818) 870 ListExStyle |= LVS_EX_DOUBLEBUFFER; 871#endif 872 } 873 874 switch (m_FolderSettings.ViewMode) 875 { 876 case FVM_ICON: 877 dwStyle |= LVS_ICON; 878 break; 879 case FVM_DETAILS: 880 dwStyle |= LVS_REPORT; 881 break; 882 case FVM_SMALLICON: 883 dwStyle |= LVS_SMALLICON; 884 break; 885 case FVM_LIST: 886 dwStyle |= LVS_LIST; 887 break; 888 default: 889 dwStyle |= LVS_LIST; 890 break; 891 } 892 893 if (m_FolderSettings.fFlags & FWF_AUTOARRANGE) 894 dwStyle |= LVS_AUTOARRANGE; 895 896 if (m_FolderSettings.fFlags & FWF_SNAPTOGRID) 897 ListExStyle |= LVS_EX_SNAPTOGRID; 898 899 if (m_FolderSettings.fFlags & FWF_SINGLESEL) 900 dwStyle |= LVS_SINGLESEL; 901 902 if (m_FolderSettings.fFlags & FWF_FULLROWSELECT) 903 ListExStyle |= LVS_EX_FULLROWSELECT; 904 905 ListExStyle |= GetItemActivateFlags(); 906 if (ListExStyle & LVS_EX_ONECLICKACTIVATE) 907 ListExStyle |= SHELL_GetIconUnderlineFlags(); 908 909 if (m_FolderSettings.fFlags & FWF_NOCOLUMNHEADER) 910 dwStyle |= LVS_NOCOLUMNHEADER; 911 912#if 0 913 // FIXME: Because this is a negative, everyone gets the new flag by default unless they 914 // opt out. This code should be enabled when shell looks like Vista instead of 2003 915 if (!(m_FolderSettings.fFlags & FWF_NOHEADERINALLVIEWS)) 916 ListExStyle |= LVS_EX_HEADERINALLVIEWS; 917#endif 918 919 if (m_FolderSettings.fFlags & FWF_NOCLIENTEDGE) 920 dwExStyle &= ~WS_EX_CLIENTEDGE; 921 922 RECT rcListView = {0,0,0,0}; 923 m_ListView.Create(m_hWnd, rcListView, L"FolderView", dwStyle, dwExStyle, ID_LISTVIEW); 924 925 if (!m_ListView) 926 return FALSE; 927 928 m_ListView.SetExtendedListViewStyle(ListExStyle); 929 930 /* UpdateShellSettings(); */ 931 return TRUE; 932} 933 934void CDefView::UpdateListColors() 935{ 936 if (m_FolderSettings.fFlags & FWF_DESKTOP) 937 { 938 /* Check if drop shadows option is enabled */ 939 BOOL bDropShadow = FALSE; 940 DWORD cbDropShadow = sizeof(bDropShadow); 941 942 /* 943 * The desktop ListView always take the default desktop colours, by 944 * remaining transparent and letting user32/win32k paint itself the 945 * desktop background color, if any. 946 */ 947 m_ListView.SetBkColor(CLR_NONE); 948 949 SHGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced", 950 L"ListviewShadow", NULL, &bDropShadow, &cbDropShadow); 951 if (bDropShadow) 952 { 953 /* Set the icon background transparent */ 954 m_ListView.SetTextBkColor(CLR_NONE); 955 m_ListView.SetTextColor(RGB(255, 255, 255)); 956 m_ListView.SetExtendedListViewStyle(LVS_EX_TRANSPARENTSHADOWTEXT, LVS_EX_TRANSPARENTSHADOWTEXT); 957 } 958 else 959 { 960 /* Set the icon background as the same colour as the desktop */ 961 COLORREF crDesktop = GetSysColor(COLOR_DESKTOP); 962 m_ListView.SetTextBkColor(crDesktop); 963 if (GetRValue(crDesktop) + GetGValue(crDesktop) + GetBValue(crDesktop) > 128 * 3) 964 m_ListView.SetTextColor(RGB(0, 0, 0)); 965 else 966 m_ListView.SetTextColor(RGB(255, 255, 255)); 967 m_ListView.SetExtendedListViewStyle(0, LVS_EX_TRANSPARENTSHADOWTEXT); 968 } 969 } 970 else 971 { 972 m_ListView.SetTextBkColor(GetViewColor(m_viewinfo_data.clrTextBack, COLOR_WINDOW)); 973 m_ListView.SetTextColor(GetViewColor(m_viewinfo_data.clrText, COLOR_WINDOWTEXT)); 974 975 // Background is painted by the parent via WM_PRINTCLIENT 976 m_ListView.SetExtendedListViewStyle(LVS_EX_TRANSPARENTBKGND, LVS_EX_TRANSPARENTBKGND); 977 } 978} 979 980// adds all needed columns to the shellview 981BOOL CDefView::InitList() 982{ 983 HIMAGELIST big_icons, small_icons; 984 985 TRACE("%p\n", this); 986 987 m_ListView.DeleteAllItems(); 988 989 Shell_GetImageLists(&big_icons, &small_icons); 990 m_ListView.SetImageList(big_icons, LVSIL_NORMAL); 991 m_ListView.SetImageList(small_icons, LVSIL_SMALL); 992 993 m_hMenuArrangeModes = CreateMenu(); 994 995 SIZE_T *pColumns = m_LoadColumnsList ? (SIZE_T*)DPA_GetPtrPtr(m_LoadColumnsList) : NULL; 996 UINT ColumnCount = pColumns ? DPA_GetPtrCount(m_LoadColumnsList) : 0; 997 LoadColumns(pColumns, ColumnCount); 998 if (m_sortInfo.bColumnIsFolderColumn) 999 { 1000 m_sortInfo.bColumnIsFolderColumn = FALSE; 1001 HRESULT hr = MapFolderColumnToListColumn(m_sortInfo.ListColumn); 1002 m_sortInfo.ListColumn = SUCCEEDED(hr) ? hr : 0; 1003 } 1004 return TRUE; 1005} 1006 1007/********************************************************** 1008* Column handling 1009*/ 1010static HRESULT SHGetLVColumnSubItem(HWND List, UINT Col) 1011{ 1012 LVCOLUMN lvc; 1013 lvc.mask = LVCF_SUBITEM; 1014 if (!ListView_GetColumn(List, Col, &lvc)) 1015 return E_FAIL; 1016 else 1017 return lvc.iSubItem; 1018} 1019 1020HRESULT CDefView::MapFolderColumnToListColumn(UINT FoldCol) 1021{ 1022 // This function is only called during column management, performance is not critical. 1023 for (UINT i = 0;; ++i) 1024 { 1025 HRESULT r = SHGetLVColumnSubItem(m_ListView.m_hWnd, i); 1026 if ((UINT)r == FoldCol) 1027 return i; 1028 else if (FAILED(r)) 1029 return r; 1030 } 1031} 1032 1033HRESULT CDefView::MapListColumnToFolderColumn(UINT ListCol) 1034{ 1035 // This function is called every time a LVITEM::iSubItem is mapped to 1036 // a folder column (calls to GetDetailsOf etc.) and should be fast. 1037 if (m_ListToFolderColMap) 1038 { 1039 UINT count = DPA_GetPtrCount(m_ListToFolderColMap); 1040 if (ListCol < count) 1041 { 1042 HRESULT col = (INT)(INT_PTR)DPA_FastGetPtr(m_ListToFolderColMap, ListCol); 1043 assert(col >= 0 && col == SHGetLVColumnSubItem(m_ListView.m_hWnd, ListCol)); 1044 return col; 1045 } 1046 else if (count) 1047 { 1048 TRACE("m_ListToFolderColMap cache miss while mapping %d\n", ListCol); 1049 } 1050 } 1051 return SHGetLVColumnSubItem(m_ListView.m_hWnd, ListCol); 1052} 1053 1054HRESULT CDefView::GetDetailsByFolderColumn(PCUITEMID_CHILD pidl, UINT FoldCol, SHELLDETAILS &sd) 1055{ 1056 // According to learn.microsoft.com/en-us/windows/win32/shell/sfvm-getdetailsof 1057 // the query order is IShellFolder2, IShellDetails, SFVM_GETDETAILSOF. 1058 HRESULT hr = E_FAIL; 1059 if (m_pSF2Parent) 1060 { 1061 hr = m_pSF2Parent->GetDetailsOf(pidl, FoldCol, &sd); 1062 } 1063 if (FAILED(hr) && m_pSDParent) 1064 { 1065 hr = m_pSDParent->GetDetailsOf(pidl, FoldCol, &sd); 1066 } 1067#if 0 // TODO 1068 if (FAILED(hr)) 1069 { 1070 FIXME("Try SFVM_GETDETAILSOF\n"); 1071 } 1072#endif 1073 return hr; 1074} 1075 1076HRESULT CDefView::GetDetailsByListColumn(PCUITEMID_CHILD pidl, UINT ListCol, SHELLDETAILS &sd) 1077{ 1078 HRESULT hr = MapListColumnToFolderColumn(ListCol); 1079 if (SUCCEEDED(hr)) 1080 return GetDetailsByFolderColumn(pidl, hr, sd); 1081 ERR("Unable to determine folder column from list column %d\n", (int) ListCol); 1082 return hr; 1083} 1084 1085HRESULT CDefView::LoadColumn(UINT FoldCol, UINT ListCol, BOOL Insert, UINT ForceWidth) 1086{ 1087 WCHAR buf[MAX_PATH]; 1088 SHELLDETAILS sd; 1089 HRESULT hr; 1090 1091 sd.str.uType = !STRRET_WSTR; // Make sure "uninitialized" uType is not WSTR 1092 hr = GetDetailsByFolderColumn(NULL, FoldCol, sd); 1093 if (FAILED(hr)) 1094 return hr; 1095 hr = StrRetToStrNW(buf, _countof(buf), &sd.str, NULL); 1096 if (FAILED(hr)) 1097 return hr; 1098 1099 UINT chavewidth = CalculateCharWidth(m_ListView.m_hWnd); 1100 if (!chavewidth) 1101 chavewidth = 6; // 6 is a reasonable default fallback 1102 1103 LVCOLUMN lvc; 1104 lvc.mask = LVCF_TEXT | LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM; 1105 lvc.pszText = buf; 1106 lvc.fmt = sd.fmt; 1107 lvc.cx = ForceWidth ? ForceWidth : (sd.cxChar * chavewidth); // FIXME: DPI? 1108 lvc.iSubItem = FoldCol; // Used by MapFolderColumnToListColumn & MapListColumnToFolderColumn 1109 if ((int)ListCol == -1) 1110 { 1111 assert(Insert); // You can insert at the end but you can't change something that is not there 1112 if (Insert) 1113 ListCol = 0x7fffffff; 1114 } 1115 if (Insert) 1116 ListView_InsertColumn(m_ListView.m_hWnd, ListCol, &lvc); 1117 else 1118 ListView_SetColumn(m_ListView.m_hWnd, ListCol, &lvc); 1119 return S_OK; 1120} 1121 1122HRESULT CDefView::LoadColumns(SIZE_T *pColList, UINT ColListCount) 1123{ 1124 HWND hWndHdr = ListView_GetHeader(m_ListView.m_hWnd); 1125 UINT newColCount = 0, oldColCount = Header_GetItemCount(hWndHdr); 1126 UINT width = 0, foldCol, i; 1127 HRESULT hr = S_FALSE; 1128 1129 m_ListView.SetRedraw(FALSE); 1130 for (i = 0, foldCol = 0;; ++foldCol) 1131 { 1132 if (newColCount >= 0xffff) 1133 break; // CompareIDs limit reached 1134 1135 if (pColList) 1136 { 1137 if (i >= ColListCount) 1138 break; 1139 width = HIWORD(pColList[i]); 1140 foldCol = LOWORD(pColList[i++]); 1141 } 1142 1143 SHCOLSTATEF state = 0; 1144 if (!m_pSF2Parent || FAILED(m_pSF2Parent->GetDefaultColumnState(foldCol, &state))) 1145 state = SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT; 1146 1147 if (foldCol == 0) 1148 { 1149 // Force the first column 1150 } 1151 else if (state & SHCOLSTATE_HIDDEN) 1152 { 1153 continue; 1154 } 1155 else if (!pColList && !(state & SHCOLSTATE_ONBYDEFAULT)) 1156 { 1157 continue; 1158 } 1159 1160 bool insert = newColCount >= oldColCount; 1161 UINT listCol = insert ? -1 : newColCount; 1162 hr = LoadColumn(foldCol, listCol, insert, width); 1163 if (FAILED(hr)) 1164 { 1165 if (!pColList) 1166 hr = S_OK; // No more items, we are done 1167 break; 1168 } 1169 ++newColCount; 1170 } 1171 for (i = newColCount; i < oldColCount; ++i) 1172 { 1173 ListView_DeleteColumn(m_ListView.m_hWnd, i); 1174 } 1175 1176 m_ListView.SetRedraw(TRUE); 1177 ColumnListChanged(); 1178 assert(SUCCEEDED(MapFolderColumnToListColumn(0))); // We don't allow turning off the Name column 1179 if (m_LoadColumnsList) 1180 { 1181 DPA_Destroy(m_LoadColumnsList); 1182 m_LoadColumnsList = NULL; 1183 } 1184 return hr; 1185} 1186 1187void CDefView::ColumnListChanged() 1188{ 1189 HDPA cache = m_ListToFolderColMap; 1190 m_ListToFolderColMap = NULL; // No cache while we are building the cache 1191 DPA_DeleteAllPtrs(cache); 1192 for (UINT i = 0;; ++i) 1193 { 1194 HRESULT hr = MapListColumnToFolderColumn(i); 1195 if (FAILED(hr)) 1196 break; // No more columns 1197 if (!DPA_SetPtr(cache, i, (void*)(INT_PTR) hr)) 1198 break; // Cannot allow holes in the cache, must stop now. 1199 } 1200 m_ListToFolderColMap = cache; 1201 1202 for (;;) 1203 { 1204 if (!RemoveMenu(m_hMenuArrangeModes, 0, MF_BYPOSITION)) 1205 break; 1206 } 1207 HMENU hMenu = GetSubmenuByID(m_hMenu, FCIDM_MENU_VIEW); 1208 if (hMenu) 1209 { 1210 hMenu = GetSubmenuByID(hMenu, FCIDM_SHVIEW_ARRANGE); 1211 for (UINT i = DVIDM_ARRANGESORT_FIRST; i <= DVIDM_ARRANGESORT_LAST && hMenu; ++i) 1212 { 1213 RemoveMenu(hMenu, i, MF_BYCOMMAND); 1214 } 1215 if ((int) GetMenuItemID(hMenu, 0) <= 0) 1216 RemoveMenu(hMenu, 0, MF_BYPOSITION); // Separator 1217 } 1218 WCHAR buf[MAX_PATH]; 1219 LVCOLUMN lvc; 1220 lvc.mask = LVCF_TEXT; 1221 lvc.pszText = buf; 1222 lvc.cchTextMax = _countof(buf); 1223 for (UINT listCol = 0; listCol < DEFVIEW_ARRANGESORT_MAXENUM; ++listCol) 1224 { 1225 if (!ListView_GetColumn(m_ListView.m_hWnd, listCol, &lvc)) 1226 break; 1227 HRESULT foldCol = MapListColumnToFolderColumn(listCol); 1228 assert(SUCCEEDED(foldCol)); 1229 DBG_UNREFERENCED_LOCAL_VARIABLE(foldCol); 1230 AppendMenuItem(m_hMenuArrangeModes, MF_STRING, 1231 DVIDM_ARRANGESORT_FIRST + listCol, lvc.pszText, listCol); 1232 } 1233 1234 ListView_RedrawItems(m_ListView.m_hWnd, 0, 0x7fffffff); 1235 m_ListView.InvalidateRect(NULL, TRUE); 1236} 1237 1238/************************************************************************* 1239 * ShellView_ListViewCompareItems 1240 * 1241 * Compare Function for the Listview (FileOpen Dialog) 1242 * 1243 * PARAMS 1244 * lParam1 [I] the first ItemIdList to compare with 1245 * lParam2 [I] the second ItemIdList to compare with 1246 * lpData [I] The column ID for the header Ctrl to process 1247 * 1248 * RETURNS 1249 * A negative value if the first item should precede the second, 1250 * a positive value if the first item should follow the second, 1251 * or zero if the two items are equivalent 1252 */ 1253INT CALLBACK CDefView::ListViewCompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lpData) 1254{ 1255 PCUIDLIST_RELATIVE pidl1 = reinterpret_cast<PCUIDLIST_RELATIVE>(lParam1); 1256 PCUIDLIST_RELATIVE pidl2 = reinterpret_cast<PCUIDLIST_RELATIVE>(lParam2); 1257 CDefView *pThis = reinterpret_cast<CDefView*>(lpData); 1258 1259 HRESULT hres = pThis->m_pSFParent->CompareIDs(pThis->m_sortInfo.FolderColumn, pidl1, pidl2); 1260 if (FAILED_UNEXPECTEDLY(hres)) 1261 return 0; 1262 1263 SHORT nDiff = HRESULT_CODE(hres); 1264 return nDiff * pThis->m_sortInfo.Direction; 1265} 1266 1267BOOL CDefView::_Sort(int Col) 1268{ 1269 HWND hHeader; 1270 HDITEM hColumn; 1271 int prevCol = m_sortInfo.ListColumn; 1272 m_sortInfo.bLoadedFromViewState = FALSE; 1273 1274 // FIXME: Is this correct? Who sets this style? 1275 // And if it is set, should it also block sorting using the menu? 1276 // Any why should it block sorting when the view is loaded initially? 1277 if (m_ListView.GetWindowLongPtr(GWL_STYLE) & LVS_NOSORTHEADER) 1278 return TRUE; 1279 1280 hHeader = ListView_GetHeader(m_ListView.m_hWnd); 1281 if (Col != -1) 1282 { 1283 if (Col >= Header_GetItemCount(hHeader)) 1284 { 1285 ERR("Sort column out of range\n"); 1286 return FALSE; 1287 } 1288 1289 if (prevCol == Col) 1290 m_sortInfo.Direction *= -1; 1291 else 1292 m_sortInfo.Direction = 0; 1293 m_sortInfo.ListColumn = Col; 1294 } 1295 if (!m_sortInfo.Direction) 1296 m_sortInfo.Direction += 1; 1297 1298 /* If the sorting column changed, remove the sorting style from the old column */ 1299 if (prevCol != -1 && prevCol != m_sortInfo.ListColumn) 1300 { 1301 hColumn.mask = HDI_FORMAT; 1302 Header_GetItem(hHeader, prevCol, &hColumn); 1303 hColumn.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN); 1304 Header_SetItem(hHeader, prevCol, &hColumn); 1305 } 1306 1307 /* Set the sorting style on the new column */ 1308 hColumn.mask = HDI_FORMAT; 1309 Header_GetItem(hHeader, m_sortInfo.ListColumn, &hColumn); 1310 hColumn.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP); 1311 hColumn.fmt |= (m_sortInfo.Direction > 0 ? HDF_SORTUP : HDF_SORTDOWN); 1312 Header_SetItem(hHeader, m_sortInfo.ListColumn, &hColumn); 1313 1314 m_sortInfo.FolderColumn = MapListColumnToFolderColumn(m_sortInfo.ListColumn); 1315 ASSERT(m_sortInfo.Direction == 1 || m_sortInfo.Direction == -1); 1316 return m_ListView.SortItems(ListViewCompareItems, this); 1317} 1318 1319SFGAOF CDefView::GetItemAttributes(PCUITEMID_CHILD pidl, UINT Query) 1320{ 1321 SFGAOF Attr = (SFGAOF)Query; 1322 return SUCCEEDED(m_pSFParent->GetAttributesOf(1, &pidl, &Attr)) ? (Attr & Query) : 0; 1323} 1324 1325SFGAOF CDefView::GetItemAttributes(int i, UINT Query) 1326{ 1327 PCUITEMID_CHILD pItem = _PidlByItem(i); 1328 return pItem ? GetItemAttributes(pItem, Query) : 0; 1329} 1330 1331PCUITEMID_CHILD CDefView::_PidlByItem(int i) 1332{ 1333 if (!m_ListView) 1334 return nullptr; 1335 return reinterpret_cast<PCUITEMID_CHILD>(m_ListView.GetItemData(i)); 1336} 1337 1338PCUITEMID_CHILD CDefView::_PidlByItem(LVITEM& lvItem) 1339{ 1340 if (!m_ListView) 1341 return nullptr; 1342 return reinterpret_cast<PCUITEMID_CHILD>(lvItem.lParam); 1343} 1344 1345int CDefView::LV_FindItemByPidl(PCUITEMID_CHILD pidl) 1346{ 1347 ASSERT(m_ListView && m_pSFParent); 1348 1349 int cItems = m_ListView.GetItemCount(); 1350 LPARAM lParam = m_pSF2Parent ? SHCIDS_CANONICALONLY : 0; 1351 for (int i = 0; i < cItems; i++) 1352 { 1353 PCUITEMID_CHILD currentpidl = _PidlByItem(i); 1354 HRESULT hr = m_pSFParent->CompareIDs(lParam, pidl, currentpidl); 1355 if (SUCCEEDED(hr)) 1356 { 1357 if (hr == S_EQUAL) 1358 return i; 1359 } 1360 else 1361 { 1362#if DBG 1363 for (i = 0; pidl && i < cItems; i++) 1364 { 1365 currentpidl = _PidlByItem(i); 1366 if (currentpidl && currentpidl->mkid.cb == pidl->mkid.cb && !memcmp(currentpidl, pidl, pidl->mkid.cb)) 1367 DbgPrint("Matched item #%d, broken CompareIDs?\n", i); 1368 } 1369#endif 1370 break; 1371 } 1372 } 1373 return -1; 1374} 1375 1376int CDefView::LV_AddItem(PCUITEMID_CHILD pidl) 1377{ 1378 LVITEMW lvItem; 1379 1380 TRACE("(%p)(pidl=%p)\n", this, pidl); 1381 1382 ASSERT(m_ListView); 1383 1384 if (_DoFolderViewCB(SFVM_ADDINGOBJECT, 0, (LPARAM)pidl) == S_FALSE) 1385 return -1; 1386 1387 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM; 1388 lvItem.iItem = m_ListView.GetItemCount(); // add item to lists end 1389 lvItem.iSubItem = 0; 1390 lvItem.lParam = reinterpret_cast<LPARAM>(ILClone(pidl)); // set item's data 1391 lvItem.pszText = LPSTR_TEXTCALLBACKW; // get text on a callback basis 1392 lvItem.iImage = I_IMAGECALLBACK; // get image on a callback basis 1393 lvItem.stateMask = LVIS_CUT; 1394 if (m_HasCutItems) 1395 { 1396 lvItem.mask |= LVIF_STATE; 1397 lvItem.state = GetItemAttributes(pidl, SFGAO_HIDDEN | SFGAO_GHOSTED) ? LVIS_CUT : 0; 1398 } 1399 1400 return m_ListView.InsertItem(&lvItem); 1401} 1402 1403BOOLEAN CDefView::LV_DeleteItem(PCUITEMID_CHILD pidl) 1404{ 1405 int nIndex; 1406 1407 TRACE("(%p)(pidl=%p)\n", this, pidl); 1408 1409 ASSERT(m_ListView); 1410 1411 nIndex = LV_FindItemByPidl(pidl); 1412 if (nIndex < 0) 1413 return FALSE; 1414 1415 _DoFolderViewCB(SFVM_REMOVINGOBJECT, 0, (LPARAM)pidl); 1416 1417 return m_ListView.DeleteItem(nIndex); 1418} 1419 1420BOOLEAN CDefView::LV_RenameItem(PCUITEMID_CHILD pidlOld, PCUITEMID_CHILD pidlNew) 1421{ 1422 int nItem; 1423 LVITEMW lvItem; 1424 1425 TRACE("(%p)(pidlold=%p pidlnew=%p)\n", this, pidlOld, pidlNew); 1426 1427 ASSERT(m_ListView); 1428 1429 nItem = LV_FindItemByPidl(pidlOld); 1430 1431 if (-1 != nItem) 1432 { 1433 lvItem.mask = LVIF_PARAM; // only the pidl 1434 lvItem.iItem = nItem; 1435 lvItem.iSubItem = 0; 1436 m_ListView.GetItem(&lvItem); 1437 1438 // Store old pidl until new item is replaced 1439 LPVOID oldPidl = reinterpret_cast<LPVOID>(lvItem.lParam); 1440 1441 lvItem.mask = LVIF_PARAM | LVIF_IMAGE | LVIF_TEXT; 1442 lvItem.iItem = nItem; 1443 lvItem.iSubItem = 0; 1444 lvItem.lParam = reinterpret_cast<LPARAM>(ILClone(pidlNew)); // set item's data 1445 lvItem.pszText = LPSTR_TEXTCALLBACKW; 1446 lvItem.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidlNew, 0); 1447 m_ListView.SetItem(&lvItem); 1448 m_ListView.Update(nItem); 1449 1450 // Now that the new item is in place, we can safely release the old pidl 1451 SHFree(oldPidl); 1452 1453 return TRUE; // FIXME: better handling 1454 } 1455 1456 return FALSE; 1457} 1458 1459BOOL CDefView::LV_UpdateItem(INT nItem, PCUITEMID_CHILD pidl) 1460{ 1461 BOOL bResult = FALSE; 1462 LVITEMW lvItem; 1463 if (nItem >= 0) 1464 { 1465 _DoFolderViewCB(SFVM_UPDATINGOBJECT, nItem, (LPARAM)pidl); 1466 1467 lvItem.mask = LVIF_IMAGE; 1468 lvItem.iItem = nItem; 1469 lvItem.iSubItem = 0; 1470 lvItem.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0); 1471 lvItem.stateMask = LVIS_CUT; 1472 if (m_HasCutItems) 1473 { 1474 lvItem.mask |= LVIF_STATE; 1475 lvItem.state = GetItemAttributes(pidl, SFGAO_HIDDEN | SFGAO_GHOSTED) ? LVIS_CUT : 0; 1476 } 1477 PCUITEMID_CHILD pidlOld = _PidlByItem(nItem); 1478 if (pidlOld && (lvItem.lParam = reinterpret_cast<LPARAM>(ILClone(pidl))) != NULL) 1479 lvItem.mask |= LVIF_PARAM; 1480 bResult = m_ListView.SetItem(&lvItem); 1481 if (bResult && lvItem.lParam && pidlOld) 1482 ILFree(const_cast<PUITEMID_CHILD>(pidlOld)); 1483 for (UINT i = 0; m_ListView.SetItemText(nItem, i, LPSTR_TEXTCALLBACK); ++i) {} // Update all columns 1484 } 1485 return bResult; 1486} 1487 1488BOOL CDefView::LV_UpdateItem(PCUITEMID_CHILD pidl) 1489{ 1490 TRACE("(%p)(pidl=%p)\n", this, pidl); 1491 ASSERT(m_ListView); 1492 INT nItem = LV_FindItemByPidl(pidl); 1493 return nItem >= 0 ? LV_UpdateItem(nItem, pidl) : FALSE; 1494} 1495 1496void CDefView::LV_RefreshIcon(INT iItem) 1497{ 1498 ASSERT(m_ListView); 1499 1500 LVITEMW lvItem = { LVIF_IMAGE }; 1501 lvItem.iItem = iItem; 1502 lvItem.iImage = I_IMAGECALLBACK; 1503 m_ListView.SetItem(&lvItem); 1504 m_ListView.Update(iItem); 1505} 1506 1507void CDefView::LV_RefreshIcons() 1508{ 1509 ASSERT(m_ListView); 1510 1511 for (INT iItem = -1;;) 1512 { 1513 iItem = ListView_GetNextItem(m_ListView, iItem, LVNI_ALL); 1514 if (iItem == -1) 1515 break; 1516 1517 LV_RefreshIcon(iItem); 1518 } 1519} 1520 1521INT CALLBACK CDefView::fill_list(LPVOID ptr, LPVOID arg) 1522{ 1523 PITEMID_CHILD pidl = static_cast<PITEMID_CHILD>(ptr); 1524 CDefView *pThis = static_cast<CDefView *>(arg); 1525 1526 // in a commdlg this works as a filemask 1527 if (pThis->IncludeObject(pidl) == S_OK && pThis->m_ListView) 1528 pThis->LV_AddItem(pidl); 1529 1530 SHFree(pidl); 1531 return TRUE; 1532} 1533 1534/// 1535// - gets the objectlist from the shellfolder 1536// - sorts the list 1537// - fills the list into the view 1538HRESULT CDefView::FillList(BOOL IsRefreshCommand) 1539{ 1540 CComPtr<IEnumIDList> pEnumIDList; 1541 PITEMID_CHILD pidl; 1542 DWORD dwFetched; 1543 HRESULT hRes; 1544 HDPA hdpa; 1545 DWORD dFlags = SHCONTF_NONFOLDERS | ((m_FolderSettings.fFlags & FWF_NOSUBFOLDERS) ? 0 : SHCONTF_FOLDERS); 1546 1547 TRACE("%p\n", this); 1548 1549 SHELLSTATE shellstate; 1550 SHGetSetSettings(&shellstate, SSF_SHOWALLOBJECTS | SSF_SHOWSUPERHIDDEN, FALSE); 1551 if (GetCommDlgViewFlags() & CDB2GVF_SHOWALLFILES) 1552 shellstate.fShowAllObjects = shellstate.fShowSuperHidden = TRUE; 1553 1554 if (shellstate.fShowAllObjects) 1555 { 1556 dFlags |= SHCONTF_INCLUDEHIDDEN; 1557 m_ListView.SendMessageW(LVM_SETCALLBACKMASK, LVIS_CUT, 0); 1558 } 1559 if (shellstate.fShowSuperHidden) 1560 { 1561 dFlags |= SHCONTF_INCLUDESUPERHIDDEN; 1562 m_ListView.SendMessageW(LVM_SETCALLBACKMASK, LVIS_CUT, 0); 1563 } 1564 1565 // get the itemlist from the shfolder 1566 hRes = m_pSFParent->EnumObjects(m_hWnd, dFlags, &pEnumIDList); 1567 if (hRes != S_OK) 1568 { 1569 if (hRes == S_FALSE) 1570 return(NOERROR); 1571 return(hRes); 1572 } 1573 1574 // create a pointer array 1575 hdpa = DPA_Create(16); 1576 if (!hdpa) 1577 return(E_OUTOFMEMORY); 1578 1579 // copy the items into the array 1580 while((S_OK == pEnumIDList->Next(1, &pidl, &dwFetched)) && dwFetched) 1581 { 1582 if (DPA_AppendPtr(hdpa, pidl) == -1) 1583 { 1584 SHFree(pidl); 1585 } 1586 } 1587 1588 // turn listview's redrawing off 1589 m_ListView.SetRedraw(FALSE); 1590 1591 DPA_DestroyCallback( hdpa, fill_list, this); 1592 1593 /* sort the array */ 1594 int sortCol = -1; 1595 if (!IsRefreshCommand && !m_sortInfo.bLoadedFromViewState) // Are we loading for the first time? 1596 { 1597 m_sortInfo.Direction = 0; 1598 sortCol = 0; // In case the folder does not know/care 1599 if (m_pSF2Parent) 1600 { 1601 ULONG folderSortCol = sortCol, dummy; 1602 HRESULT hr = m_pSF2Parent->GetDefaultColumn(NULL, &folderSortCol, &dummy); 1603 if (SUCCEEDED(hr)) 1604 hr = MapFolderColumnToListColumn(folderSortCol); 1605 if (SUCCEEDED(hr)) 1606 sortCol = (int) hr; 1607 } 1608 } 1609 _Sort(sortCol); 1610 1611 if (m_viewinfo_data.hbmBack) 1612 { 1613 ::DeleteObject(m_viewinfo_data.hbmBack); 1614 m_viewinfo_data.hbmBack = NULL; 1615 } 1616 1617 // load custom background image and custom text color 1618 m_viewinfo_data.cbSize = sizeof(m_viewinfo_data); 1619 _DoFolderViewCB(SFVM_GET_CUSTOMVIEWINFO, 0, (LPARAM)&m_viewinfo_data); 1620 1621 // turn listview's redrawing back on and force it to draw 1622 m_ListView.SetRedraw(TRUE); 1623 1624 UpdateListColors(); 1625 1626 if (!(m_FolderSettings.fFlags & FWF_DESKTOP)) 1627 { 1628 // redraw now 1629 m_ListView.InvalidateRect(NULL, TRUE); 1630 } 1631 1632 if (IsRefreshCommand) 1633 UpdateStatusbarLocation(); 1634 1635 _DoFolderViewCB(SFVM_LISTREFRESHED, 0, 0); 1636 1637 return S_OK; 1638} 1639 1640LRESULT CDefView::OnShowWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 1641{ 1642 if (m_ListView.IsWindow()) 1643 m_ListView.UpdateWindow(); 1644 bHandled = FALSE; 1645 return 0; 1646} 1647 1648LRESULT CDefView::OnGetDlgCode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 1649{ 1650 return m_ListView.SendMessageW(uMsg, 0, 0); 1651} 1652 1653LRESULT CDefView::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 1654{ 1655 if (!m_Destroyed) 1656 { 1657 m_Destroyed = TRUE; 1658 RevokeDragDrop(m_hWnd); 1659 SHChangeNotifyDeregister(m_hNotify); 1660 m_hNotify = NULL; 1661 m_ClipboardChain.Unhook(m_hWnd); 1662 if (m_pFileMenu) 1663 { 1664 IUnknown_SetSite(m_pFileMenu, NULL); 1665 m_pFileMenu = NULL; 1666 } 1667 if (m_hMenu) 1668 { 1669 DestroyMenu(m_hMenu); 1670 m_hMenu = NULL; 1671 } 1672 SHFree(m_pidlParent); 1673 m_pidlParent = NULL; 1674 } 1675 bHandled = FALSE; 1676 return 0; 1677} 1678 1679LRESULT CDefView::OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 1680{ 1681 /* redirect to parent */ 1682 if (m_FolderSettings.fFlags & (FWF_DESKTOP | FWF_TRANSPARENT)) 1683 return SendMessageW(GetParent(), WM_ERASEBKGND, wParam, lParam); 1684 1685 bHandled = FALSE; 1686 return 0; 1687} 1688 1689static VOID 1690DrawTileBitmap(HDC hDC, LPCRECT prc, HBITMAP hbm, INT nWidth, INT nHeight, INT dx, INT dy) 1691{ 1692 INT x0 = prc->left, y0 = prc->top, x1 = prc->right, y1 = prc->bottom; 1693 x0 += dx; 1694 y0 += dy; 1695 1696 HDC hMemDC = CreateCompatibleDC(hDC); 1697 HGDIOBJ hbmOld = SelectObject(hMemDC, hbm); 1698 1699 for (INT y = y0; y < y1; y += nHeight) 1700 { 1701 for (INT x = x0; x < x1; x += nWidth) 1702 { 1703 BitBlt(hDC, x, y, nWidth, nHeight, hMemDC, 0, 0, SRCCOPY); 1704 } 1705 } 1706 1707 SelectObject(hMemDC, hbmOld); 1708 DeleteDC(hMemDC); 1709} 1710 1711LRESULT CDefView::OnPrintClient(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 1712{ 1713 HDC hDC = (HDC)wParam; 1714 1715 RECT rc; 1716 ::GetClientRect(m_ListView, &rc); 1717 1718 if (m_viewinfo_data.hbmBack) 1719 { 1720 BITMAP bm; 1721 if (::GetObject(m_viewinfo_data.hbmBack, sizeof(BITMAP), &bm)) 1722 { 1723 INT dx = -(::GetScrollPos(m_ListView, SB_HORZ) % bm.bmWidth); 1724 INT dy = -(::GetScrollPos(m_ListView, SB_VERT) % bm.bmHeight); 1725 DrawTileBitmap(hDC, &rc, m_viewinfo_data.hbmBack, bm.bmWidth, bm.bmHeight, dx, dy); 1726 } 1727 } 1728 else 1729 { 1730 SHFillRectClr(hDC, &rc, GetViewColor(m_viewinfo_data.clrTextBack, COLOR_WINDOW)); 1731 } 1732 1733 bHandled = TRUE; 1734 1735 return TRUE; 1736} 1737 1738LRESULT CDefView::OnSysColorChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 1739{ 1740 /* Update desktop labels color */ 1741 UpdateListColors(); 1742 1743 /* Forward WM_SYSCOLORCHANGE to common controls */ 1744 return m_ListView.SendMessageW(uMsg, 0, 0); 1745} 1746 1747LRESULT CDefView::OnGetShellBrowser(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 1748{ 1749 return reinterpret_cast<LRESULT>(m_pShellBrowser.p); 1750} 1751 1752LRESULT CDefView::OnNCCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 1753{ 1754 this->AddRef(); 1755 bHandled = FALSE; 1756 return 0; 1757} 1758 1759VOID CDefView::OnFinalMessage(HWND) 1760{ 1761 this->Release(); 1762} 1763 1764LRESULT CDefView::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 1765{ 1766 CComPtr<IDropTarget> pdt; 1767 CComPtr<IPersistFolder2> ppf2; 1768 1769 TRACE("%p\n", this); 1770 1771 if (SUCCEEDED(QueryInterface(IID_PPV_ARG(IDropTarget, &pdt)))) 1772 { 1773 if (FAILED(RegisterDragDrop(m_hWnd, pdt))) 1774 ERR("Error Registering DragDrop\n"); 1775 } 1776 1777 /* register for receiving notifications */ 1778 m_pSFParent->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2)); 1779 if (ppf2) 1780 { 1781 ppf2->GetCurFolder(&m_pidlParent); 1782 } 1783 1784 if (CreateList()) 1785 { 1786 if (InitList()) 1787 { 1788 FillList(FALSE); 1789 } 1790 } 1791 1792 if (m_FolderSettings.fFlags & FWF_DESKTOP) 1793 { 1794 HWND hwndSB; 1795 m_pShellBrowser->GetWindow(&hwndSB); 1796 SetShellWindowEx(hwndSB, m_ListView); 1797 } 1798 1799 // Set up change notification 1800 LPITEMIDLIST pidlTarget = NULL; 1801 LONG fEvents = 0; 1802 HRESULT hr = _DoFolderViewCB(SFVM_GETNOTIFY, (WPARAM)&pidlTarget, (LPARAM)&fEvents); 1803 if (FAILED(hr) || (!pidlTarget && !fEvents)) // FIXME: MSDN says both zero means no notifications 1804 { 1805 pidlTarget = m_pidlParent; 1806 fEvents = SHCNE_ALLEVENTS; 1807 } 1808 SHChangeNotifyEntry ntreg = {}; 1809 hr = _DoFolderViewCB(SFVM_QUERYFSNOTIFY, 0, (LPARAM)&ntreg); 1810 if (FAILED(hr)) 1811 { 1812 ntreg.fRecursive = FALSE; 1813 ntreg.pidl = pidlTarget; 1814 } 1815 m_hNotify = SHChangeNotifyRegister(m_hWnd, 1816 SHCNRF_InterruptLevel | SHCNRF_ShellLevel | 1817 SHCNRF_NewDelivery, 1818 fEvents, SHV_CHANGE_NOTIFY, 1819 1, &ntreg); 1820 1821 m_hAccel = LoadAcceleratorsW(shell32_hInstance, MAKEINTRESOURCEW(IDA_SHELLVIEW)); 1822 1823 int bForceFullStatusBar = false; 1824 BOOL bIsFileSystem = SHGetAttributes(NULL, m_pidlParent, SFGAO_FILESYSTEM) & SFGAO_FILESYSTEM; 1825 m_SpecialFolder = bIsFileSystem ? -1 : 0x7f; // FS folder or "generic" CSIDL 1826 if (_ILIsDesktop(m_pidlParent)) 1827 { 1828 m_SpecialFolder = CSIDL_DESKTOP; 1829 } 1830 else if (IsEqualPersistClassID(ppf2, CLSID_RecycleBin)) 1831 { 1832 m_SpecialFolder = bForceFullStatusBar = CSIDL_BITBUCKET; 1833 } 1834 else if (bIsFileSystem) 1835 { 1836 CComHeapPtr<ITEMIDLIST> pidlNet(SHCloneSpecialIDList(NULL, CSIDL_NETWORK, FALSE)); 1837 if (ILIsParent(pidlNet, m_pidlParent, FALSE) && ILGetSize(pidlNet) < ILGetSize(m_pidlParent)) 1838 m_SpecialFolder = CSIDL_NETWORK; 1839 } 1840 m_isFullStatusBar = bIsFileSystem || bForceFullStatusBar; 1841 _ForceStatusBarResize(); // This handles changing StatusBar parts 1842 UpdateStatusbar(); 1843 UpdateStatusbarLocation(); 1844 1845 return S_OK; 1846} 1847 1848// #### Handling of the menus #### 1849 1850HRESULT CDefView::FillFileMenu() 1851{ 1852 HMENU hFileMenu = GetSubmenuByID(m_hMenu, FCIDM_MENU_FILE); 1853 if (!hFileMenu) 1854 return E_FAIL; 1855 1856 /* Cleanup the items added previously */ 1857 for (int i = GetMenuItemCount(hFileMenu) - 1; i >= 0; i--) 1858 { 1859 UINT id = GetMenuItemID(hFileMenu, i); 1860 if (id < FCIDM_BROWSERFIRST || id > FCIDM_BROWSERLAST) 1861 DeleteMenu(hFileMenu, i, MF_BYPOSITION); 1862 } 1863 1864 // In case we still have this left over, clean it up 1865 if (m_pFileMenu) 1866 { 1867 IUnknown_SetSite(m_pFileMenu, NULL); 1868 m_pFileMenu.Release(); 1869 } 1870 UINT selcount = m_ListView.GetSelectedCount(); 1871 // Store context menu in m_pFileMenu and keep it to invoke the selected command later on 1872 HRESULT hr = GetItemObject(selcount ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &m_pFileMenu)); 1873 if (FAILED_UNEXPECTEDLY(hr)) 1874 return hr; 1875 1876 HMENU hmenu = CreatePopupMenu(); 1877 1878 UINT cmf = GetContextMenuFlags(m_pShellBrowser, GetSelectionAttributes(SFGAO_CANRENAME)); 1879 hr = m_pFileMenu->QueryContextMenu(hmenu, 0, DVIDM_CONTEXTMENU_FIRST, DVIDM_CONTEXTMENU_LAST, cmf); 1880 if (FAILED_UNEXPECTEDLY(hr)) 1881 return hr; 1882 1883 // TODO: filter or something 1884 if (!selcount) 1885 { 1886 DeleteMenu(hmenu, FCIDM_SHVIEW_VIEW, MF_BYCOMMAND); 1887 DeleteMenu(hmenu, FCIDM_SHVIEW_ARRANGE, MF_BYCOMMAND); 1888 DeleteMenu(hmenu, FCIDM_SHVIEW_REFRESH, MF_BYCOMMAND); 1889 } 1890 1891 Shell_MergeMenus(hFileMenu, hmenu, 0, 0, 0xFFFF, MM_ADDSEPARATOR | MM_SUBMENUSHAVEIDS); 1892 ::DestroyMenu(hmenu); 1893 return S_OK; 1894} 1895 1896HRESULT CDefView::FillEditMenu() 1897{ 1898 HMENU hEditMenu = GetSubmenuByID(m_hMenu, FCIDM_MENU_EDIT); 1899 if (!hEditMenu) 1900 return E_FAIL; 1901 1902 HMENU hmenuContents = ::LoadMenuW(shell32_hInstance, L"MENU_003"); 1903 if (!hmenuContents) 1904 return E_FAIL; 1905 1906 Shell_MergeMenus(hEditMenu, hmenuContents, 0, 0, 0xFFFF, 0); 1907 1908 ::DestroyMenu(hmenuContents); 1909 1910 return S_OK; 1911} 1912 1913HRESULT CDefView::FillViewMenu() 1914{ 1915 HMENU hViewMenu = GetSubmenuByID(m_hMenu, FCIDM_MENU_VIEW); 1916 if (!hViewMenu) 1917 return E_FAIL; 1918 1919 m_hMenuViewModes = ::LoadMenuW(shell32_hInstance, L"MENU_001"); 1920 if (!m_hMenuViewModes) 1921 return E_FAIL; 1922 1923 UINT i = SHMenuIndexFromID(hViewMenu, FCIDM_MENU_VIEW_SEP_OPTIONS); 1924 Shell_MergeMenus(hViewMenu, m_hMenuViewModes, i, 0, 0xFFFF, MM_ADDSEPARATOR | MM_DONTREMOVESEPS | MM_SUBMENUSHAVEIDS); 1925 1926 return S_OK; 1927} 1928 1929HRESULT CDefView::FillArrangeAsMenu(HMENU hmenuArrange) 1930{ 1931 bool forceMerge = false; 1932 UINT currentSortId = DVIDM_ARRANGESORT_FIRST + m_sortInfo.ListColumn; 1933 1934 // Make sure the column we currently sort by is in the menu 1935 RemoveMenu(m_hMenuArrangeModes, DVIDM_ARRANGESORT_LAST, MF_BYCOMMAND); 1936 if (m_sortInfo.ListColumn >= DEFVIEW_ARRANGESORT_MAXENUM) 1937 { 1938 C_ASSERT(DEFVIEW_ARRANGESORT_MAXENUM < DEFVIEW_ARRANGESORT_MAX); 1939 C_ASSERT(DVIDM_ARRANGESORT_FIRST + DEFVIEW_ARRANGESORT_MAXENUM == DVIDM_ARRANGESORT_LAST); 1940 WCHAR buf[MAX_PATH]; 1941 LVCOLUMN lvc; 1942 lvc.mask = LVCF_TEXT; 1943 lvc.pszText = buf; 1944 lvc.cchTextMax = _countof(buf); 1945 currentSortId = DVIDM_ARRANGESORT_LAST; 1946 forceMerge = true; 1947 ListView_GetColumn(m_ListView.m_hWnd, m_sortInfo.ListColumn, &lvc); 1948 AppendMenuItem(m_hMenuArrangeModes, MF_STRING, currentSortId, lvc.pszText, m_sortInfo.ListColumn); 1949 } 1950 1951 // Prepend the sort-by items unless they are aleady there 1952 if (GetMenuItemID(hmenuArrange, 0) == FCIDM_SHVIEW_AUTOARRANGE || forceMerge) 1953 { 1954 Shell_MergeMenus(hmenuArrange, m_hMenuArrangeModes, 0, 0, 0xFFFF, MM_ADDSEPARATOR); 1955 } 1956 1957 CheckMenuRadioItem(hmenuArrange, 1958 DVIDM_ARRANGESORT_FIRST, DVIDM_ARRANGESORT_LAST, 1959 currentSortId, MF_BYCOMMAND); 1960 1961 if (m_FolderSettings.ViewMode == FVM_DETAILS || m_FolderSettings.ViewMode == FVM_LIST) 1962 { 1963 EnableMenuItem(hmenuArrange, FCIDM_SHVIEW_AUTOARRANGE, MF_BYCOMMAND | MF_GRAYED); 1964 EnableMenuItem(hmenuArrange, FCIDM_SHVIEW_ALIGNTOGRID, MF_BYCOMMAND | MF_GRAYED); 1965 } 1966 else 1967 { 1968 EnableMenuItem(hmenuArrange, FCIDM_SHVIEW_AUTOARRANGE, MF_BYCOMMAND); 1969 EnableMenuItem(hmenuArrange, FCIDM_SHVIEW_ALIGNTOGRID, MF_BYCOMMAND); 1970 1971 if (GetAutoArrange() == S_OK) 1972 CheckMenuItem(hmenuArrange, FCIDM_SHVIEW_AUTOARRANGE, MF_CHECKED); 1973 else 1974 CheckMenuItem(hmenuArrange, FCIDM_SHVIEW_AUTOARRANGE, MF_UNCHECKED); 1975 1976 if (_GetSnapToGrid() == S_OK) 1977 CheckMenuItem(hmenuArrange, FCIDM_SHVIEW_ALIGNTOGRID, MF_CHECKED); 1978 else 1979 CheckMenuItem(hmenuArrange, FCIDM_SHVIEW_ALIGNTOGRID, MF_UNCHECKED); 1980 } 1981 1982 return S_OK; 1983} 1984 1985HRESULT CDefView::CheckViewMode(HMENU hmenuView) 1986{ 1987 if (m_FolderSettings.ViewMode >= FVM_FIRST && m_FolderSettings.ViewMode <= FVM_LAST) 1988 { 1989 UINT iItemFirst = FCIDM_SHVIEW_BIGICON; 1990 UINT iItemLast = iItemFirst + FVM_LAST - FVM_FIRST; 1991 UINT iItem = iItemFirst + m_FolderSettings.ViewMode - FVM_FIRST; 1992 CheckMenuRadioItem(hmenuView, iItemFirst, iItemLast, iItem, MF_BYCOMMAND); 1993 } 1994 1995 return S_OK; 1996} 1997 1998LRESULT CDefView::DoColumnContextMenu(LPARAM lParam) 1999{ 2000 const UINT maxItems = 15; // Feels about right 2001 const UINT idMore = 0x1337; 2002 UINT idFirst = idMore + 1, idLast = idFirst; 2003 UINT lastValidListCol = 0; // Keep track of where the new column should be inserted 2004 UINT showMore = GetKeyState(VK_SHIFT) < 0; 2005 POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; 2006 HWND hWndHdr = ListView_GetHeader(m_ListView.m_hWnd); 2007 2008 if (lParam == ~0) 2009 { 2010 RECT r; 2011 ::GetWindowRect(hWndHdr, &r); 2012 pt.x = r.left + ((r.right - r.left) / 2); 2013 pt.y = r.top + ((r.bottom - r.top) / 2); 2014 } 2015 2016 HMENU hMenu = CreatePopupMenu(); 2017 if (!hMenu) 2018 return 0; 2019 2020 for (UINT foldCol = 0;; ++foldCol) 2021 { 2022 WCHAR buf[MAX_PATH]; 2023 SHELLDETAILS sd; 2024 sd.str.uType = !STRRET_WSTR; 2025 if (FAILED(GetDetailsByFolderColumn(NULL, foldCol, sd))) 2026 break; 2027 if (FAILED(StrRetToStrNW(buf, _countof(buf), &sd.str, NULL))) 2028 break; 2029 2030 SHCOLSTATEF state = 0; 2031 if (!m_pSF2Parent || FAILED(m_pSF2Parent->GetDefaultColumnState(foldCol, &state))) 2032 state = 0; 2033 showMore |= (state & (SHCOLSTATE_SECONDARYUI)); 2034 2035 UINT mf = MF_STRING; 2036 HRESULT listCol = MapFolderColumnToListColumn(foldCol); 2037 2038 if (foldCol == 0) 2039 mf |= MF_CHECKED | MF_GRAYED | MF_DISABLED; // Force column 0 2040 else if (state & (SHCOLSTATE_SECONDARYUI | SHCOLSTATE_HIDDEN)) 2041 continue; 2042 else if (SUCCEEDED(listCol)) 2043 mf |= MF_CHECKED; 2044 2045 if (AppendMenuItem(hMenu, mf, idLast, buf, lastValidListCol + 1)) 2046 { 2047 idLast++; 2048 if (SUCCEEDED(listCol)) 2049 lastValidListCol = listCol; 2050 } 2051 2052 if (idLast - idFirst == maxItems) 2053 { 2054 showMore++; 2055 break; 2056 } 2057 } 2058 2059 if (showMore) 2060 { 2061#if 0 // TODO 2062 InsertMenuW(hMenu, -1, MF_SEPARATOR, 0, NULL); 2063 InsertMenuW(hMenu, -1, MF_STRING, idMore, L"More..."); 2064#endif 2065 } 2066 2067 // A cludge to force the cursor to update so we are not stuck with "size left/right" if 2068 // the right-click was on a column divider. 2069 ::PostMessage(m_ListView.m_hWnd, WM_SETCURSOR, (WPARAM) m_ListView.m_hWnd, HTCLIENT); 2070 2071 // Note: Uses the header as the owner so CDefView::OnInitMenuPopup does not mess us up. 2072 UINT idCmd = TrackPopupMenu(hMenu, TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, 2073 pt.x, pt.y, 0, hWndHdr, NULL); 2074 if (idCmd == idMore) 2075 { 2076 FIXME("Open More dialog\n"); 2077 } 2078 else if (idCmd) 2079 { 2080 UINT foldCol = idCmd - idFirst; 2081 HRESULT listCol = MapFolderColumnToListColumn(foldCol); 2082 if (SUCCEEDED(listCol)) 2083 { 2084 ListView_DeleteColumn(m_ListView.m_hWnd, listCol); 2085 } 2086 else 2087 { 2088 listCol = (UINT) GetMenuItemDataById(hMenu, idCmd); 2089 LoadColumn(foldCol, listCol, TRUE); 2090 } 2091 ColumnListChanged(); 2092 } 2093 DestroyMenu(hMenu); 2094 return 0; 2095} 2096 2097/********************************************************** 2098* ShellView_GetSelections() 2099* 2100* - fills the m_apidl list with the selected objects 2101* 2102* RETURNS 2103* number of selected items 2104*/ 2105UINT CDefView::GetSelections() 2106{ 2107 UINT count = m_ListView.GetSelectedCount(); 2108 if (count > m_cidl || !count || !m_apidl) // !count to free possibly large cache, !m_apidl to make sure m_apidl is a valid pointer 2109 { 2110 SHFree(m_apidl); 2111 m_apidl = static_cast<PCUITEMID_CHILD*>(SHAlloc(count * sizeof(PCUITEMID_CHILD))); 2112 if (!m_apidl) 2113 { 2114 m_cidl = 0; 2115 return 0; 2116 } 2117 } 2118 m_cidl = count; 2119 2120 TRACE("-- Items selected =%u\n", m_cidl); 2121 2122 ASSERT(m_ListView); 2123 2124 UINT i = 0; 2125 int lvIndex = -1; 2126 while ((lvIndex = m_ListView.GetNextItem(lvIndex, LVNI_SELECTED)) > -1) 2127 { 2128 m_apidl[i] = _PidlByItem(lvIndex); 2129 i++; 2130 if (i == m_cidl) 2131 break; 2132 TRACE("-- selected Item found\n"); 2133 } 2134 2135 return m_cidl; 2136} 2137 2138SFGAOF CDefView::GetSelectionAttributes(SFGAOF Query) 2139{ 2140 if (!GetSelections()) 2141 return 0; 2142 SFGAOF Attr = Query; 2143 return SUCCEEDED(m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &Attr)) ? (Attr & Query) : 0; 2144} 2145 2146HRESULT CDefView::InvokeContextMenuCommand(CComPtr<IContextMenu>& pCM, LPCSTR lpVerb, POINT* pt, bool TryMapVerb) 2147{ 2148 CMINVOKECOMMANDINFOEX cmi; 2149 2150 ZeroMemory(&cmi, sizeof(cmi)); 2151 cmi.cbSize = sizeof(cmi); 2152 cmi.hwnd = m_hWnd; 2153 cmi.lpVerb = lpVerb; 2154 cmi.nShow = SW_SHOW; 2155 2156 WCHAR szverbW[sizeof("properties")]; 2157 static const WORD verbmap[] = { FCIDM_SHVIEW_DELETE, FCIDM_SHVIEW_RENAME, 2158 FCIDM_SHVIEW_PROPERTIES, FCIDM_SHVIEW_CREATELINK, 2159 FCIDM_SHVIEW_CUT, FCIDM_SHVIEW_COPY, FCIDM_SHVIEW_INSERT }; 2160 for (SIZE_T i = 0; TryMapVerb && i < _countof(verbmap); ++i) 2161 { 2162 if (cmi.lpVerb != MAKEINTRESOURCEA(verbmap[i])) 2163 continue; 2164 if (PCSTR pszverbA = MapFcidmCmdToVerb((UINT_PTR)cmi.lpVerb)) 2165 { 2166 // Map our internal commands to canonical verbs so non-shell32 menus can understand us 2167 SHAnsiToUnicode(pszverbA, szverbW, _countof(szverbW)); 2168 cmi.lpVerb = pszverbA; 2169 cmi.lpVerbW = szverbW; 2170 break; 2171 } 2172 } 2173 2174 if (GetKeyState(VK_SHIFT) < 0) 2175 cmi.fMask |= CMIC_MASK_SHIFT_DOWN; 2176 2177 if (GetKeyState(VK_CONTROL) < 0) 2178 cmi.fMask |= CMIC_MASK_CONTROL_DOWN; 2179 2180 if (pt) 2181 { 2182 cmi.fMask |= CMIC_MASK_PTINVOKE; 2183 cmi.ptInvoke = *pt; 2184 } 2185 2186 WCHAR szDirW[MAX_PATH] = L""; 2187 CHAR szDirA[MAX_PATH]; 2188 if (SUCCEEDED(_DoFolderViewCB(SFVM_GETCOMMANDDIR, _countof(szDirW), (LPARAM)szDirW)) && 2189 *szDirW != UNICODE_NULL) 2190 { 2191 SHUnicodeToAnsi(szDirW, szDirA, _countof(szDirA)); 2192 cmi.fMask |= CMIC_MASK_UNICODE; 2193 cmi.lpDirectory = szDirA; 2194 cmi.lpDirectoryW = szDirW; 2195 } 2196 2197 HRESULT hr = pCM->InvokeCommand((LPCMINVOKECOMMANDINFO)&cmi); 2198 // Most of our callers will do this, but if they would forget (File menu!) 2199 IUnknown_SetSite(pCM, NULL); 2200 pCM.Release(); 2201 2202 if (FAILED_UNEXPECTEDLY(hr)) 2203 return hr; 2204 2205 return S_OK; 2206} 2207 2208HRESULT CDefView::OpenSelectedItems(PCSTR pszVerb) 2209{ 2210 HMENU hMenu; 2211 UINT uCommand; 2212 HRESULT hResult; 2213 2214 if (m_ListView.GetSelectedCount() == 0) 2215 return S_OK; 2216 2217 hResult = OnDefaultCommand(); 2218 if (hResult == S_OK) 2219 return hResult; 2220 2221 hMenu = CreatePopupMenu(); 2222 if (!hMenu) 2223 return E_FAIL; 2224 2225 CComPtr<IContextMenu> pCM; 2226 hResult = GetItemObject(SVGIO_SELECTION, IID_PPV_ARG(IContextMenu, &pCM)); 2227 MenuCleanup _(pCM, hMenu); 2228 if (FAILED_UNEXPECTEDLY(hResult)) 2229 return hResult; 2230 2231 UINT cmf = CMF_DEFAULTONLY | GetContextMenuFlags(m_pShellBrowser, 0); 2232 hResult = pCM->QueryContextMenu(hMenu, 0, DVIDM_CONTEXTMENU_FIRST, DVIDM_CONTEXTMENU_LAST, cmf); 2233 if (FAILED_UNEXPECTEDLY(hResult)) 2234 return hResult; 2235 2236 uCommand = GetMenuDefaultItem(hMenu, FALSE, 0); 2237 if (uCommand == (UINT)-1 && !pszVerb) 2238 { 2239 ERR("GetMenuDefaultItem returned -1\n"); 2240 return E_FAIL; 2241 } 2242 if (!pszVerb) 2243 pszVerb = MAKEINTRESOURCEA(uCommand); 2244 2245 InvokeContextMenuCommand(pCM, pszVerb, NULL); 2246 2247 return hResult; 2248} 2249 2250LRESULT CDefView::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 2251{ 2252 POINT pt = { pt.x = GET_X_LPARAM(lParam), pt.y = GET_Y_LPARAM(lParam) }; 2253 UINT uCommand; 2254 HRESULT hResult; 2255 2256 TRACE("(%p)\n", this); 2257 2258 if (m_hContextMenu != NULL) 2259 { 2260 ERR("HACK: Aborting context menu in nested call\n"); 2261 return 0; 2262 } 2263 2264 HWND hWndHdr = ListView_GetHeader(m_ListView.m_hWnd); 2265 RECT r; 2266 if (::GetWindowRect(hWndHdr, &r) && PtInRect(&r, pt) && ::IsWindowVisible(hWndHdr)) 2267 { 2268 return DoColumnContextMenu(lParam); 2269 } 2270 2271 m_hContextMenu = CreatePopupMenu(); 2272 if (!m_hContextMenu) 2273 return E_FAIL; 2274 2275 if (lParam != ~0) // unless app key (menu key) was pressed 2276 { 2277 LV_HITTESTINFO hittest = { pt }; 2278 ScreenToClient(&hittest.pt); 2279 m_ListView.HitTest(&hittest); 2280 2281 // Right-Clicked item is selected? If selected, no selection change. 2282 // If not selected, then reset the selection and select the item. 2283 if ((hittest.flags & LVHT_ONITEM) && 2284 m_ListView.GetItemState(hittest.iItem, LVIS_SELECTED) != LVIS_SELECTED) 2285 { 2286 SelectItem(hittest.iItem, SVSI_SELECT | SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE); 2287 } 2288 } 2289 2290 UINT count = m_ListView.GetSelectedCount(); 2291 // In case we still have this left over, clean it up 2292 hResult = GetItemObject(count ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &m_pCM)); 2293 MenuCleanup _(m_pCM, m_hContextMenu); 2294 if (FAILED_UNEXPECTEDLY(hResult)) 2295 return 0; 2296 2297 UINT cmf = GetContextMenuFlags(m_pShellBrowser, GetSelectionAttributes(SFGAO_CANRENAME)); 2298 // Use 1 as the first id we want. 0 means that user canceled the menu 2299 hResult = m_pCM->QueryContextMenu(m_hContextMenu, 0, CONTEXT_MENU_BASE_ID, DVIDM_CONTEXTMENU_LAST, cmf); 2300 if (FAILED_UNEXPECTEDLY(hResult)) 2301 return 0; 2302 2303 if (m_pCommDlgBrowser && !(GetCommDlgViewFlags() & CDB2GVF_NOSELECTVERB)) 2304 { 2305 HMENU hMenuSource = LoadMenuW(_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCEW(IDM_DVSELECT)); 2306 Shell_MergeMenus(m_hContextMenu, GetSubMenu(hMenuSource, 0), 0, DVIDM_COMMDLG_SELECT, 0xffff, MM_ADDSEPARATOR | MM_DONTREMOVESEPS); 2307 DestroyMenu(hMenuSource); 2308 SetMenuDefaultItem(m_hContextMenu, DVIDM_COMMDLG_SELECT, MF_BYCOMMAND); 2309 // TODO: ICommDlgBrowser2::GetDefaultMenuText == S_OK 2310 } 2311 2312 // There is no position requested, so try to find one 2313 if (lParam == ~0) 2314 { 2315 HWND hFocus = ::GetFocus(); 2316 int lvIndex = -1; 2317 2318 if (hFocus == m_ListView.m_hWnd || m_ListView.IsChild(hFocus)) 2319 { 2320 // Is there an item focused and selected? 2321 lvIndex = m_ListView.GetNextItem(-1, LVNI_SELECTED | LVNI_FOCUSED); 2322 // If not, find the first selected item 2323 if (lvIndex < 0) 2324 lvIndex = m_ListView.GetNextItem(-1, LVNI_SELECTED); 2325 } 2326 2327 // We got something 2328 if (lvIndex > -1) 2329 { 2330 // Find the center of the icon 2331 RECT rc = { LVIR_ICON }; 2332 m_ListView.SendMessage(LVM_GETITEMRECT, lvIndex, (LPARAM)&rc); 2333 pt.x = (rc.right + rc.left) / 2; 2334 pt.y = (rc.bottom + rc.top) / 2; 2335 } 2336 else 2337 { 2338 // We have to drop it somewhere 2339 pt.x = pt.y = 0; 2340 } 2341 2342 m_ListView.ClientToScreen(&pt); 2343 } 2344 2345 CComPtr<ICommDlgBrowser2> pcdb2; 2346 if (m_pCommDlgBrowser && SUCCEEDED(m_pCommDlgBrowser->QueryInterface(IID_PPV_ARG(ICommDlgBrowser2, &pcdb2)))) 2347 pcdb2->Notify(static_cast<IShellView*>(this), CDB2N_CONTEXTMENU_START); 2348 2349 // This runs the message loop, calling back to us with f.e. WM_INITPOPUP (hence why m_hContextMenu and m_pCM exist) 2350 uCommand = TrackPopupMenu(m_hContextMenu, 2351 TPM_LEFTALIGN | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, 2352 pt.x, pt.y, 0, m_hWnd, NULL); 2353 if (uCommand >= DVIDM_ARRANGESORT_FIRST && uCommand <= DVIDM_ARRANGESORT_LAST) 2354 { 2355 SendMessage(WM_COMMAND, uCommand, 0); 2356 } 2357 else if (uCommand != 0 && !(uCommand == DVIDM_COMMDLG_SELECT && OnDefaultCommand() == S_OK)) 2358 { 2359 InvokeContextMenuCommand(m_pCM, MAKEINTRESOURCEA(uCommand - CONTEXT_MENU_BASE_ID), &pt); 2360 } 2361 2362 if (pcdb2) 2363 pcdb2->Notify(static_cast<IShellView*>(this), CDB2N_CONTEXTMENU_DONE); 2364 return 0; 2365} 2366 2367LRESULT CDefView::OnExplorerCommand(UINT uCommand, BOOL bUseSelection) 2368{ 2369 HRESULT hResult; 2370 HMENU hMenu = NULL; 2371 2372 CComPtr<IContextMenu> pCM; 2373 hResult = GetItemObject(bUseSelection ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &pCM)); 2374 if (FAILED_UNEXPECTEDLY(hResult)) 2375 return 0; 2376 2377 MenuCleanup _(pCM, hMenu); 2378 2379 if ((uCommand != FCIDM_SHVIEW_DELETE) && (uCommand != FCIDM_SHVIEW_RENAME)) 2380 { 2381 hMenu = CreatePopupMenu(); 2382 if (!hMenu) 2383 return 0; 2384 2385 hResult = pCM->QueryContextMenu(hMenu, 0, DVIDM_CONTEXTMENU_FIRST, DVIDM_CONTEXTMENU_LAST, CMF_NORMAL); 2386 if (FAILED_UNEXPECTEDLY(hResult)) 2387 return 0; 2388 } 2389 2390 if (bUseSelection) 2391 { 2392 // FIXME: we should cache this 2393 SFGAOF rfg = SFGAO_BROWSABLE | SFGAO_CANCOPY | SFGAO_CANLINK | SFGAO_CANMOVE | SFGAO_CANDELETE | SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSTEM | SFGAO_FOLDER; 2394 hResult = m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &rfg); 2395 if (FAILED_UNEXPECTEDLY(hResult)) 2396 return 0; 2397 2398 if (!(rfg & SFGAO_CANMOVE) && uCommand == FCIDM_SHVIEW_CUT) 2399 return 0; 2400 if (!(rfg & SFGAO_CANCOPY) && uCommand == FCIDM_SHVIEW_COPY) 2401 return 0; 2402 if (!(rfg & SFGAO_CANDELETE) && uCommand == FCIDM_SHVIEW_DELETE) 2403 return 0; 2404 if (!(rfg & SFGAO_CANRENAME) && uCommand == FCIDM_SHVIEW_RENAME) 2405 return 0; 2406 if (!(rfg & SFGAO_HASPROPSHEET) && uCommand == FCIDM_SHVIEW_PROPERTIES) 2407 return 0; 2408 } 2409 2410 // FIXME: We should probably use the objects position? 2411 InvokeContextMenuCommand(pCM, MAKEINTRESOURCEA(uCommand), NULL, true); 2412 return 0; 2413} 2414 2415// ##### message handling ##### 2416 2417LRESULT CDefView::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 2418{ 2419 WORD wWidth, wHeight; 2420 2421 wWidth = LOWORD(lParam); 2422 wHeight = HIWORD(lParam); 2423 2424 TRACE("%p width=%u height=%u\n", this, wWidth, wHeight); 2425 2426 // WM_SIZE can come before WM_CREATE 2427 if (!m_ListView) 2428 return 0; 2429 2430 /* Resize the ListView to fit our window */ 2431 ::MoveWindow(m_ListView, 0, 0, wWidth, wHeight, TRUE); 2432 2433 _DoFolderViewCB(SFVM_SIZE, 0, 0); 2434 2435 _ForceStatusBarResize(); 2436 UpdateStatusbar(); 2437 2438 return 0; 2439} 2440 2441// internal 2442void CDefView::OnDeactivate() 2443{ 2444 TRACE("%p\n", this); 2445 2446 if (m_uState != SVUIA_DEACTIVATE) 2447 { 2448 // TODO: cleanup menu after deactivation 2449 m_uState = SVUIA_DEACTIVATE; 2450 } 2451} 2452 2453void CDefView::DoActivate(UINT uState) 2454{ 2455 TRACE("%p uState=%x\n", this, uState); 2456 2457 // don't do anything if the state isn't really changing 2458 if (m_uState == uState) 2459 { 2460 return; 2461 } 2462 2463 if (uState == SVUIA_DEACTIVATE) 2464 { 2465 OnDeactivate(); 2466 } 2467 else 2468 { 2469 if(m_hMenu && !m_bmenuBarInitialized) 2470 { 2471 FillEditMenu(); 2472 FillViewMenu(); 2473 m_pShellBrowser->SetMenuSB(m_hMenu, 0, m_hWnd); 2474 m_bmenuBarInitialized = TRUE; 2475 } 2476 2477 if (SVUIA_ACTIVATE_FOCUS == uState) 2478 { 2479 m_ListView.SetFocus(); 2480 } 2481 } 2482 2483 m_uState = uState; 2484 TRACE("--\n"); 2485} 2486 2487void CDefView::_DoCopyToMoveToFolder(BOOL bCopy) 2488{ 2489 if (!GetSelections()) 2490 return; 2491 2492 SFGAOF rfg = SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_FILESYSTEM; 2493 HRESULT hr = m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &rfg); 2494 if (FAILED_UNEXPECTEDLY(hr)) 2495 return; 2496 2497 if (!bCopy && !(rfg & SFGAO_CANMOVE)) 2498 return; 2499 if (bCopy && !(rfg & SFGAO_CANCOPY)) 2500 return; 2501 2502 CComPtr<IContextMenu> pCM; 2503 hr = m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, IID_IContextMenu, 0, (void **)&pCM); 2504 if (FAILED_UNEXPECTEDLY(hr)) 2505 return; 2506 2507 InvokeContextMenuCommand(pCM, (bCopy ? "copyto" : "moveto"), NULL); 2508} 2509 2510LRESULT CDefView::OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 2511{ 2512 DoActivate(SVUIA_ACTIVATE_FOCUS); 2513 return 0; 2514} 2515 2516LRESULT CDefView::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 2517{ 2518 TRACE("%p\n", this); 2519 2520 /* Tell the browser one of our windows has received the focus. This 2521 should always be done before merging menus (OnActivate merges the 2522 menus) if one of our windows has the focus.*/ 2523 2524 m_pShellBrowser->OnViewWindowActive(this); 2525 DoActivate(SVUIA_ACTIVATE_FOCUS); 2526 2527 /* Set the focus to the listview */ 2528 m_ListView.SetFocus(); 2529 2530 /* Notify the ICommDlgBrowser interface */ 2531 OnStateChange(CDBOSC_SETFOCUS); 2532 2533 return 0; 2534} 2535 2536LRESULT CDefView::OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 2537{ 2538 TRACE("(%p) stub\n", this); 2539 2540 DoActivate(SVUIA_ACTIVATE_NOFOCUS); 2541 /* Notify the ICommDlgBrowser */ 2542 OnStateChange(CDBOSC_KILLFOCUS); 2543 2544 return 0; 2545} 2546 2547// the CmdID's are the ones from the context menu 2548LRESULT CDefView::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 2549{ 2550 DWORD dwCmdID; 2551 DWORD dwCmd; 2552 HWND hwndCmd; 2553 int nCount; 2554 2555 dwCmdID = GET_WM_COMMAND_ID(wParam, lParam); 2556 dwCmd = GET_WM_COMMAND_CMD(wParam, lParam); 2557 hwndCmd = GET_WM_COMMAND_HWND(wParam, lParam); 2558 2559 TRACE("(%p)->(0x%08x 0x%08x %p) stub\n", this, dwCmdID, dwCmd, hwndCmd); 2560 2561 if (dwCmdID >= DVIDM_ARRANGESORT_FIRST && dwCmdID <= DVIDM_ARRANGESORT_LAST) 2562 { 2563 UINT listCol = (UINT)GetMenuItemDataById(m_hMenuArrangeModes, dwCmdID); 2564 _Sort(listCol); 2565 return 0; 2566 } 2567 2568 switch (dwCmdID) 2569 { 2570 case FCIDM_SHVIEW_BIGICON: C_ASSERT(FCIDM_SHVIEW_BIGICON == 0x7029); 2571 case FCIDM_SHVIEW_SMALLICON: C_ASSERT(FCIDM_SHVIEW_SMALLICON == 0x702A); 2572 case FCIDM_SHVIEW_LISTVIEW: C_ASSERT(FCIDM_SHVIEW_LISTVIEW == 0x702B); 2573 case FCIDM_SHVIEW_REPORTVIEW: C_ASSERT(FCIDM_SHVIEW_REPORTVIEW == 0x702C); 2574 case 0x702D: 2575 case FCIDM_SHVIEW_TILEVIEW: C_ASSERT(FCIDM_SHVIEW_TILEVIEW == 0x702E); 2576 case 0x702F: 2577 SetCurrentViewMode(dwCmdID - FCIDM_SHVIEW_BIGICON + 1); 2578 break; 2579 case FCIDM_SHVIEW_SNAPTOGRID: 2580 m_ListView.Arrange(LVA_SNAPTOGRID); 2581 break; 2582 case FCIDM_SHVIEW_ALIGNTOGRID: 2583 if (_GetSnapToGrid() == S_OK) 2584 m_ListView.SetExtendedListViewStyle(0, LVS_EX_SNAPTOGRID); 2585 else 2586 ArrangeGrid(); 2587 break; 2588 case FCIDM_SHVIEW_AUTOARRANGE: 2589 if (GetAutoArrange() == S_OK) 2590 m_ListView.ModifyStyle(LVS_AUTOARRANGE, 0); 2591 else 2592 AutoArrange(); 2593 break; 2594 case FCIDM_SHVIEW_SELECTALL: 2595 if (_DoFolderViewCB(SFVM_CANSELECTALL, 0, 0) != S_FALSE) 2596 m_ListView.SetItemState(-1, LVIS_SELECTED, LVIS_SELECTED); 2597 break; 2598 case FCIDM_SHVIEW_INVERTSELECTION: 2599 nCount = m_ListView.GetItemCount(); 2600 for (int i=0; i < nCount; i++) 2601 m_ListView.SetItemState(i, m_ListView.GetItemState(i, LVIS_SELECTED) ^ LVIS_SELECTED, LVIS_SELECTED); 2602 break; 2603 case FCIDM_SHVIEW_DESELECTALL: 2604 m_ListView.SetItemState(-1, 0, LVIS_SELECTED); 2605 break; 2606 case FCIDM_SHVIEW_REFRESH: 2607 Refresh(); 2608 break; 2609 case FCIDM_SHVIEW_DELETE: 2610 case FCIDM_SHVIEW_CUT: 2611 case FCIDM_SHVIEW_COPY: 2612 case FCIDM_SHVIEW_RENAME: 2613 case FCIDM_SHVIEW_PROPERTIES: 2614 if (SHRestricted(REST_NOVIEWCONTEXTMENU)) 2615 return 0; 2616 return OnExplorerCommand(dwCmdID, TRUE); 2617 case FCIDM_SHVIEW_COPYTO: C_ASSERT(FCIDM_SHVIEW_COPYTO == 0x701e); 2618 case FCIDM_SHVIEW_MOVETO: C_ASSERT(FCIDM_SHVIEW_MOVETO == 0x701f); 2619 _DoCopyToMoveToFolder(dwCmdID == FCIDM_SHVIEW_COPYTO); 2620 return 0; 2621 case FCIDM_SHVIEW_INSERT: 2622 case FCIDM_SHVIEW_UNDO: 2623 case FCIDM_SHVIEW_INSERTLINK: 2624 case FCIDM_SHVIEW_NEWFOLDER: 2625 return OnExplorerCommand(dwCmdID, FALSE); 2626 default: 2627 // WM_COMMAND messages from file menu are routed to CDefView to let m_pFileMenu handle them 2628 if (m_pFileMenu && dwCmd == 0) 2629 { 2630 HMENU Dummy = NULL; 2631 MenuCleanup _(m_pFileMenu, Dummy); 2632 InvokeContextMenuCommand(m_pFileMenu, MAKEINTRESOURCEA(dwCmdID), NULL); 2633 } 2634 } 2635 2636 return 0; 2637} 2638 2639static BOOL 2640SelectExtOnRename(void) 2641{ 2642 HKEY hKey; 2643 LONG error; 2644 DWORD dwValue = FALSE, cbValue; 2645 2646 error = RegOpenKeyExW(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER, 0, KEY_READ, &hKey); 2647 if (error) 2648 return dwValue; 2649 2650 cbValue = sizeof(dwValue); 2651 RegQueryValueExW(hKey, L"SelectExtOnRename", NULL, NULL, (LPBYTE)&dwValue, &cbValue); 2652 2653 RegCloseKey(hKey); 2654 return !!dwValue; 2655} 2656 2657LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 2658{ 2659 UINT CtlID; 2660 LPNMHDR lpnmh; 2661 LPNMLISTVIEW lpnmlv; 2662 NMLVDISPINFOW *lpdi; 2663 PCUITEMID_CHILD pidl; 2664 BOOL unused; 2665 2666 CtlID = wParam; 2667 lpnmh = (LPNMHDR)lParam; 2668 lpnmlv = (LPNMLISTVIEW)lpnmh; 2669 lpdi = (NMLVDISPINFOW *)lpnmh; 2670 2671 TRACE("%p CtlID=%u lpnmh->code=%x\n", this, CtlID, lpnmh->code); 2672 2673 switch (lpnmh->code) 2674 { 2675 case NM_SETFOCUS: 2676 TRACE("-- NM_SETFOCUS %p\n", this); 2677 OnSetFocus(0, 0, 0, unused); 2678 break; 2679 case NM_KILLFOCUS: 2680 TRACE("-- NM_KILLFOCUS %p\n", this); 2681 OnDeactivate(); 2682 /* Notify the ICommDlgBrowser interface */ 2683 OnStateChange(CDBOSC_KILLFOCUS); 2684 break; 2685 case NM_CUSTOMDRAW: 2686 TRACE("-- NM_CUSTOMDRAW %p\n", this); 2687 return CDRF_DODEFAULT; 2688 case NM_RELEASEDCAPTURE: 2689 TRACE("-- NM_RELEASEDCAPTURE %p\n", this); 2690 break; 2691 case NM_CLICK: 2692 TRACE("-- NM_CLICK %p\n", this); 2693 break; 2694 case NM_RCLICK: 2695 TRACE("-- NM_RCLICK %p\n", this); 2696 break; 2697 case NM_DBLCLK: 2698 TRACE("-- NM_DBLCLK %p\n", this); 2699 break; 2700 case NM_RETURN: 2701 TRACE("-- NM_RETURN %p\n", this); 2702 break; 2703 case HDN_ENDTRACKW: 2704 TRACE("-- HDN_ENDTRACKW %p\n", this); 2705 //nColumn1 = m_ListView.GetColumnWidth(0); 2706 //nColumn2 = m_ListView.GetColumnWidth(1); 2707 break; 2708 case LVN_DELETEITEM: 2709 TRACE("-- LVN_DELETEITEM %p\n", this); 2710 /*delete the pidl because we made a copy of it*/ 2711 SHFree(reinterpret_cast<LPVOID>(lpnmlv->lParam)); 2712 break; 2713 case LVN_DELETEALLITEMS: 2714 TRACE("-- LVN_DELETEALLITEMS %p\n", this); 2715 return FALSE; 2716 case LVN_INSERTITEM: 2717 TRACE("-- LVN_INSERTITEM (STUB)%p\n", this); 2718 break; 2719 case LVN_ITEMACTIVATE: 2720 TRACE("-- LVN_ITEMACTIVATE %p\n", this); 2721 OpenSelectedItems(((NMITEMACTIVATE *)lpnmh)->uKeyFlags & LVKF_ALT ? "properties" : NULL); 2722 break; 2723 case LVN_COLUMNCLICK: 2724 { 2725 UINT foldercol = MapListColumnToFolderColumn(lpnmlv->iSubItem); 2726 HRESULT hr = S_FALSE; 2727 if (m_pSDParent) 2728 hr = m_pSDParent->ColumnClick(foldercol); 2729 if (hr != S_OK) 2730 hr = _DoFolderViewCB(SFVM_COLUMNCLICK, foldercol, 0); 2731 if (hr != S_OK) 2732 _Sort(lpnmlv->iSubItem); 2733 break; 2734 } 2735 case LVN_GETDISPINFOA: 2736 case LVN_GETDISPINFOW: 2737 TRACE("-- LVN_GETDISPINFO %p\n", this); 2738 pidl = _PidlByItem(lpdi->item); 2739 2740 if (lpdi->item.mask & LVIF_TEXT) /* text requested */ 2741 { 2742 SHELLDETAILS sd; 2743 if (FAILED_UNEXPECTEDLY(GetDetailsByListColumn(pidl, lpdi->item.iSubItem, sd))) 2744 break; 2745 2746 if (lpnmh->code == LVN_GETDISPINFOA) 2747 { 2748 /* shouldn't happen */ 2749 NMLVDISPINFOA *lpdiA = (NMLVDISPINFOA *)lpnmh; 2750 StrRetToStrNA( lpdiA->item.pszText, lpdiA->item.cchTextMax, &sd.str, NULL); 2751 TRACE("-- text=%s\n", lpdiA->item.pszText); 2752 } 2753 else /* LVN_GETDISPINFOW */ 2754 { 2755 StrRetToStrNW( lpdi->item.pszText, lpdi->item.cchTextMax, &sd.str, NULL); 2756 TRACE("-- text=%s\n", debugstr_w(lpdi->item.pszText)); 2757 } 2758 } 2759 if (lpdi->item.mask & LVIF_IMAGE) 2760 { 2761 lpdi->item.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0); 2762 } 2763 if (lpdi->item.mask & LVIF_STATE) 2764 { 2765 if ((lpdi->item.stateMask & LVIS_CUT) && GetItemAttributes(pidl, SFGAO_HIDDEN | SFGAO_GHOSTED)) 2766 lpdi->item.state |= LVIS_CUT; 2767 } 2768 lpdi->item.mask |= LVIF_DI_SETITEM; 2769 break; 2770 case LVN_ITEMCHANGED: 2771 TRACE("-- LVN_ITEMCHANGED %p\n", this); 2772 if ((lpnmlv->uOldState ^ lpnmlv->uNewState) & (LVIS_SELECTED | LVIS_FOCUSED)) 2773 { 2774 OnStateChange(CDBOSC_SELCHANGE); // browser will get the IDataObject 2775 // FIXME: Use LVIS_DROPHILITED instead in drag_notify_subitem 2776 if (!m_ScheduledStatusbarUpdate && (m_iDragOverItem == -1 || m_pCurDropTarget == NULL)) 2777 { 2778 m_ScheduledStatusbarUpdate = true; 2779 PostMessage(SHV_UPDATESTATUSBAR, 0, 0); 2780 } 2781 _DoFolderViewCB(SFVM_SELECTIONCHANGED, NULL/* FIXME */, NULL/* FIXME */); 2782 } 2783 break; 2784 case LVN_BEGINDRAG: 2785 case LVN_BEGINRDRAG: 2786 TRACE("-- LVN_BEGINDRAG\n"); 2787 if (GetSelections()) 2788 { 2789 CComPtr<IDataObject> pda; 2790 DWORD dwAttributes = SFGAO_CANCOPY | SFGAO_CANLINK; 2791 DWORD dwEffect = DROPEFFECT_MOVE; 2792 2793 if (SUCCEEDED(m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, IID_NULL_PPV_ARG(IDataObject, &pda)))) 2794 { 2795 LPNMLISTVIEW params = (LPNMLISTVIEW)lParam; 2796 2797 if (SUCCEEDED(m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &dwAttributes))) 2798 dwEffect |= dwAttributes & (SFGAO_CANCOPY | SFGAO_CANLINK); 2799 2800 CComPtr<IAsyncOperation> piaso; 2801 if (SUCCEEDED(pda->QueryInterface(IID_PPV_ARG(IAsyncOperation, &piaso)))) 2802 piaso->SetAsyncMode(TRUE); 2803 2804 DWORD dwEffect2; 2805 2806 m_pSourceDataObject = pda; 2807 m_ptFirstMousePos = params->ptAction; 2808 ClientToScreen(&m_ptFirstMousePos); 2809 ::ClientToListView(m_ListView, &m_ptFirstMousePos); 2810 2811 HIMAGELIST big_icons, small_icons; 2812 Shell_GetImageLists(&big_icons, &small_icons); 2813 PCUITEMID_CHILD pidl = _PidlByItem(params->iItem); 2814 int iIcon = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0); 2815 POINT ptItem; 2816 m_ListView.GetItemPosition(params->iItem, &ptItem); 2817 2818 ImageList_BeginDrag(big_icons, iIcon, params->ptAction.x - ptItem.x, params->ptAction.y - ptItem.y); 2819 DoDragDrop(pda, this, dwEffect, &dwEffect2); 2820 m_pSourceDataObject.Release(); 2821 } 2822 } 2823 break; 2824 case LVN_BEGINLABELEDITW: 2825 { 2826 TRACE("-- LVN_BEGINLABELEDITW %p\n", this); 2827 HWND hEdit = ListView_GetEditControl(m_ListView); 2828 pidl = _PidlByItem(lpdi->item); 2829 DWORD fAttr = pidl ? GetItemAttributes(pidl, SFGAO_CANRENAME | SFGAO_FOLDER | SFGAO_FILESYSTEM) : 0; 2830 if (!hEdit || !(fAttr & SFGAO_CANRENAME)) 2831 { 2832 MessageBeep(0xffffffff); 2833 return TRUE; 2834 } 2835 2836 WCHAR szName[MAX_PATH], *pszText = lpdi->item.pszText; 2837 if (SUCCEEDED(DisplayNameOfW(m_pSFParent, pidl, SHGDN_FOREDITING | SHGDN_INFOLDER, 2838 szName, _countof(szName)))) 2839 { 2840 pszText = szName; 2841 ::SetWindowText(hEdit, pszText); 2842 } 2843 2844 // smartass-renaming: See CORE-15242 2845 if (!(fAttr & SFGAO_FOLDER) && (fAttr & SFGAO_FILESYSTEM) && 2846 (lpdi->item.mask & LVIF_TEXT) && !SelectExtOnRename()) 2847 { 2848 CComHeapPtr<ITEMIDLIST_RELATIVE> pidlFull(ILCombine(m_pidlParent, pidl)); 2849 WCHAR szFullPath[MAX_PATH]; 2850 if (SHGetPathFromIDListW(pidlFull, szFullPath) && !SHELL_FS_HideExtension(szFullPath)) 2851 { 2852 LPWSTR pchDotExt = PathFindExtensionW(pszText); 2853 ::PostMessageW(hEdit, EM_SETSEL, 0, pchDotExt - pszText); 2854 ::PostMessageW(hEdit, EM_SCROLLCARET, 0, 0); 2855 } 2856 } 2857 2858 INT cchLimit = 0; 2859 _DoFolderViewCB(SFVM_GETNAMELENGTH, (WPARAM)pidl, (LPARAM)&cchLimit); 2860 if (cchLimit) 2861 ::SendMessageW(hEdit, EM_SETLIMITTEXT, cchLimit, 0); 2862 SHLimitInputEdit(hEdit, m_pSFParent); 2863 m_isEditing = TRUE; 2864 return FALSE; 2865 } 2866 case LVN_ENDLABELEDITW: 2867 { 2868 TRACE("-- LVN_ENDLABELEDITW %p\n", this); 2869 m_isEditing = FALSE; 2870 if (!lpdi->item.pszText) 2871 return TRUE; 2872 2873 pidl = _PidlByItem(lpdi->item); 2874 // We have to copy the old PIDL because SetNameOf might generate a SHCNE_UPDATEITEM 2875 // and that notification can cause us to call LV_UpdateItem and free the old PIDL too soon. 2876 CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidlOld(ILClone(pidl)); 2877 if (!pidlOld) 2878 { 2879 SHELL_ErrorBox(lpdi->hdr.hwndFrom, E_OUTOFMEMORY); 2880 return FALSE; 2881 } 2882 PITEMID_CHILD pidlNew = NULL; 2883 HRESULT hr = m_pSFParent->SetNameOf(0, pidlOld, lpdi->item.pszText, SHGDN_INFOLDER, &pidlNew); 2884 if (SUCCEEDED(hr) && pidlNew) 2885 { 2886 int iNew = LV_FindItemByPidl(pidlNew); 2887 if (iNew != lpdi->item.iItem && iNew >= 0) 2888 ILFree(pidlNew);// A SHCNE has updated the item already 2889 else if (!LV_UpdateItem(lpdi->item.iItem, pidlNew)) 2890 ILFree(pidlNew); 2891 OnStateChange(CDBOSC_RENAME); 2892 } 2893 else 2894 { 2895 ::PostMessageW(m_ListView, LVM_EDITLABEL, lpdi->item.iItem, 0); // Renaming failed, let the user try again 2896 } 2897 return FALSE; 2898 } 2899 default: 2900 TRACE("-- %p WM_COMMAND %x unhandled\n", this, lpnmh->code); 2901 break; 2902 } 2903 2904 return 0; 2905} 2906 2907// This is just a quick hack to make the desktop work correctly. 2908// ITranslateShellChangeNotify's IsChildID is undocumented, but most likely the 2909// way that a folder should know if it should update upon a change notification. 2910// It is exported by merged folders at a minimum. 2911static BOOL ILIsParentOrSpecialParent(PCIDLIST_ABSOLUTE pidl1, PCIDLIST_ABSOLUTE pidl2) 2912{ 2913 if (!pidl1 || !pidl2) 2914 return FALSE; 2915 if (ILIsParent(pidl1, pidl2, TRUE)) 2916 return TRUE; 2917 2918 CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidl2Clone(ILClone(pidl2)); 2919 ILRemoveLastID(pidl2Clone); 2920 return ILIsEqual(pidl1, pidl2Clone); 2921} 2922 2923LRESULT CDefView::OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 2924{ 2925 // The change notify can come before WM_CREATE 2926 if (!m_ListView) 2927 return FALSE; 2928 2929 HANDLE hChange = (HANDLE)wParam; 2930 DWORD dwProcID = (DWORD)lParam; 2931 PIDLIST_ABSOLUTE *Pidls; 2932 LONG lEvent; 2933 HANDLE hLock = SHChangeNotification_Lock(hChange, dwProcID, &Pidls, &lEvent); 2934 if (hLock == NULL) 2935 { 2936 ERR("hLock == NULL\n"); 2937 return FALSE; 2938 } 2939 lEvent &= ~SHCNE_INTERRUPT; 2940 TRACE("(%p)(%p,%p,%p) %#x\n", this, Pidls[0], Pidls[1], lParam, lEvent); 2941 2942 if (_DoFolderViewCB(SFVM_FSNOTIFY, (WPARAM)Pidls, lEvent) == S_FALSE) 2943 { 2944 SHChangeNotification_Unlock(hLock); 2945 return FALSE; 2946 } 2947 2948 // Translate child IDLs. 2949 // SHSimpleIDListFromPathW creates fake PIDLs (lacking some attributes) 2950 HRESULT hr; 2951 PITEMID_CHILD child0 = NULL, child1 = NULL; 2952 CComHeapPtr<ITEMIDLIST_RELATIVE> pidl0Temp, pidl1Temp; 2953 if (lEvent != SHCNE_UPDATEIMAGE && lEvent < SHCNE_EXTENDED_EVENT) 2954 { 2955 if (_ILIsSpecialFolder(Pidls[0]) || ILIsParentOrSpecialParent(m_pidlParent, Pidls[0])) 2956 { 2957 child0 = ILFindLastID(Pidls[0]); 2958 hr = SHGetRealIDL(m_pSFParent, child0, &pidl0Temp); 2959 if (SUCCEEDED(hr)) 2960 child0 = pidl0Temp; 2961 } 2962 if (_ILIsSpecialFolder(Pidls[1]) || ILIsParentOrSpecialParent(m_pidlParent, Pidls[1])) 2963 { 2964 child1 = ILFindLastID(Pidls[1]); 2965 hr = SHGetRealIDL(m_pSFParent, child1, &pidl1Temp); 2966 if (SUCCEEDED(hr)) 2967 child1 = pidl1Temp; 2968 } 2969 } 2970 2971 switch (lEvent) 2972 { 2973 case SHCNE_MKDIR: 2974 case SHCNE_CREATE: 2975 case SHCNE_DRIVEADD: 2976 if (!child0) 2977 break; 2978 if (LV_FindItemByPidl(child0) < 0) 2979 LV_AddItem(child0); 2980 else 2981 LV_UpdateItem(child0); 2982 break; 2983 case SHCNE_RMDIR: 2984 case SHCNE_DELETE: 2985 case SHCNE_DRIVEREMOVED: 2986 if (child0) 2987 LV_DeleteItem(child0); 2988 break; 2989 case SHCNE_RENAMEFOLDER: 2990 case SHCNE_RENAMEITEM: 2991 if (child0 && child1) 2992 LV_RenameItem(child0, child1); 2993 else if (child0) 2994 LV_DeleteItem(child0); 2995 else if (child1) 2996 LV_AddItem(child1); 2997 break; 2998 case SHCNE_UPDATEITEM: 2999 if (child0) 3000 LV_UpdateItem(child0); 3001 break; 3002 case SHCNE_UPDATEIMAGE: 3003 case SHCNE_MEDIAINSERTED: 3004 case SHCNE_MEDIAREMOVED: 3005 case SHCNE_ASSOCCHANGED: 3006 LV_RefreshIcons(); 3007 break; 3008 case SHCNE_UPDATEDIR: 3009 case SHCNE_ATTRIBUTES: 3010 if (child0) 3011 LV_UpdateItem(child0); 3012 else 3013 Refresh(); 3014 UpdateStatusbar(); 3015 break; 3016 case SHCNE_FREESPACE: 3017 UpdateStatusbar(); 3018 break; 3019 } 3020 3021 SHChangeNotification_Unlock(hLock); 3022 return TRUE; 3023} 3024 3025LRESULT CDefView::OnMenuMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 3026{ 3027 if (!m_pCM) 3028 { 3029 /* no menu */ 3030 ERR("no context menu\n"); 3031 return FALSE; 3032 } 3033 LRESULT result = 0; 3034 HRESULT hres = SHForwardContextMenuMsg(m_pCM, uMsg, wParam, lParam, &result, TRUE); 3035 return SUCCEEDED(hres); 3036} 3037 3038LRESULT CDefView::OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 3039{ 3040 /* Wallpaper setting affects drop shadows effect */ 3041 if (wParam == SPI_SETDESKWALLPAPER || wParam == 0) 3042 UpdateListColors(); 3043 3044 UINT ListExMask = LVS_EX_TRACKSELECT | LVS_EX_ONECLICKACTIVATE; 3045 UINT ListExBits = GetItemActivateFlags(); 3046 if (wParam == SPI_GETICONTITLELOGFONT || 3047 (lParam && !lstrcmpiW((PWSTR)lParam, REGSTR_PATH_EXPLORER L"\\IconUnderline"))) 3048 { 3049 ListExMask |= LVS_EX_UNDERLINEHOT | LVS_EX_UNDERLINECOLD; 3050 ListExBits |= SHELL_GetIconUnderlineFlags(); 3051 } 3052 m_ListView.SetExtendedListViewStyle(ListExBits, ListExMask); 3053 m_ListView.SendMessage(uMsg, wParam, lParam); 3054 return S_OK; 3055} 3056 3057LRESULT CDefView::OnInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 3058{ 3059 HMENU hmenu = (HMENU) wParam; 3060 int nPos = LOWORD(lParam); 3061 UINT menuItemId; 3062 3063 if (m_isEditing) 3064 ListView_CancelEditLabel(m_ListView); 3065 if (m_pCM) 3066 OnMenuMessage(uMsg, wParam, lParam, bHandled); 3067 3068 HMENU hViewMenu = GetSubmenuByID(m_hMenu, FCIDM_MENU_VIEW); 3069 3070 if (GetSelections() == 0) 3071 { 3072 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_CUT, MF_GRAYED); 3073 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_COPY, MF_GRAYED); 3074 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_RENAME, MF_GRAYED); 3075 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_COPYTO, MF_GRAYED); 3076 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_MOVETO, MF_GRAYED); 3077 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_DELETE, MF_GRAYED); 3078 } 3079 else 3080 { 3081 // FIXME: Check copyable 3082 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_CUT, MF_ENABLED); 3083 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_COPY, MF_ENABLED); 3084 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_RENAME, MF_ENABLED); 3085 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_COPYTO, MF_ENABLED); 3086 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_MOVETO, MF_ENABLED); 3087 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_DELETE, MF_ENABLED); 3088 } 3089 3090 /* Lets try to find out what the hell wParam is */ 3091 if (hmenu == GetSubMenu(m_hMenu, nPos)) 3092 menuItemId = ReallyGetMenuItemID(m_hMenu, nPos); 3093 else if (hViewMenu && hmenu == GetSubMenu(hViewMenu, nPos)) 3094 menuItemId = ReallyGetMenuItemID(hViewMenu, nPos); 3095 else if (m_hContextMenu && hmenu == GetSubMenu(m_hContextMenu, nPos)) 3096 menuItemId = ReallyGetMenuItemID(m_hContextMenu, nPos); 3097 else 3098 return FALSE; 3099 3100 switch (menuItemId) 3101 { 3102 case FCIDM_MENU_FILE: 3103 FillFileMenu(); 3104 break; 3105 case FCIDM_MENU_VIEW: 3106 case FCIDM_SHVIEW_VIEW: 3107 CheckViewMode(hmenu); 3108 break; 3109 case FCIDM_SHVIEW_ARRANGE: 3110 FillArrangeAsMenu(hmenu); 3111 break; 3112 } 3113 3114 return FALSE; 3115} 3116 3117LRESULT CDefView::OnChangeCBChain(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 3118{ 3119 bHandled = TRUE; 3120 return m_ClipboardChain.HandleChangeCBChain(wParam, lParam); 3121} 3122 3123LRESULT CDefView::OnDrawClipboard(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 3124{ 3125 bHandled = TRUE; 3126 const LRESULT res = m_ClipboardChain.HandleDrawClipboard(wParam, lParam); 3127 if (m_HasCutItems) 3128 { 3129 m_ClipboardChain.Unhook(m_hWnd); 3130 m_HasCutItems = false; 3131 m_ListView.SetItemState(-1, 0, LVIS_CUT); // Somebody copied or pasted, nothing can be "cut" anymore 3132 m_ListView.SendMessageW(LVM_SETCALLBACKMASK, m_ListView.SendMessageW(LVM_GETCALLBACKMASK, 0, 0) | LVIS_CUT, 0); 3133 } 3134 return res; 3135} 3136 3137void CDefView::RefreshGhostedState() 3138{ 3139 for (UINT i = 0, c = m_ListView.GetItemCount(); i < c; ++i) 3140 m_ListView.SetItemState(i, GetItemAttributes(i, SFGAO_HIDDEN | SFGAO_GHOSTED) ? LVIS_CUT : 0, LVIS_CUT); 3141} 3142 3143// The INTERFACE of the IShellView object 3144 3145HRESULT WINAPI CDefView::GetWindow(HWND *phWnd) 3146{ 3147 TRACE("(%p)\n", this); 3148 3149 *phWnd = m_hWnd; 3150 3151 return S_OK; 3152} 3153 3154HRESULT WINAPI CDefView::ContextSensitiveHelp(BOOL fEnterMode) 3155{ 3156 FIXME("(%p) stub\n", this); 3157 3158 return E_NOTIMPL; 3159} 3160 3161// FIXME: use the accel functions 3162HRESULT WINAPI CDefView::TranslateAccelerator(LPMSG lpmsg) 3163{ 3164 if (m_isEditing) 3165 return S_FALSE; 3166 3167 if (lpmsg->message >= WM_KEYFIRST && lpmsg->message <= WM_KEYLAST) 3168 { 3169 if (::TranslateAcceleratorW(m_hWnd, m_hAccel, lpmsg) != 0) 3170 return S_OK; 3171 3172 TRACE("-- key=0x%04lx\n", lpmsg->wParam); 3173 } 3174 3175 return m_pShellBrowser ? m_pShellBrowser->TranslateAcceleratorSB(lpmsg, 0) : S_FALSE; 3176} 3177 3178HRESULT WINAPI CDefView::EnableModeless(BOOL fEnable) 3179{ 3180 FIXME("(%p)\n", this); 3181 return E_NOTIMPL; 3182} 3183 3184HRESULT WINAPI CDefView::UIActivate(UINT uState) 3185{ 3186 TRACE("(%p)->(state=%x)\n", this, uState); 3187 3188 // don't do anything if the state isn't changing 3189 if (m_uState == uState) 3190 return S_OK; 3191 3192 // OnActivate handles the menu merging and internal state 3193 DoActivate(uState); 3194 3195 // only do this if we are active 3196 if (uState != SVUIA_DEACTIVATE) 3197 { 3198 _ForceStatusBarResize(); 3199 3200 // Set the text for the status bar 3201 UpdateStatusbar(); 3202 } 3203 3204 return S_OK; 3205} 3206 3207HRESULT WINAPI CDefView::Refresh() 3208{ 3209 TRACE("(%p)\n", this); 3210 3211 _DoFolderViewCB(SFVM_LISTREFRESHED, TRUE, 0); 3212 3213 m_ListView.DeleteAllItems(); 3214 FillList(); 3215 3216 return S_OK; 3217} 3218 3219HRESULT WINAPI CDefView::CreateViewWindow(IShellView *lpPrevView, LPCFOLDERSETTINGS lpfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd) 3220{ 3221 return CreateViewWindow3(psb, lpPrevView, SV3CVW3_DEFAULT, 3222 (FOLDERFLAGS)lpfs->fFlags, (FOLDERFLAGS)lpfs->fFlags, (FOLDERVIEWMODE)lpfs->ViewMode, NULL, prcView, phWnd); 3223} 3224 3225HRESULT WINAPI CDefView::DestroyViewWindow() 3226{ 3227 TRACE("(%p)\n", this); 3228 3229 /* Make absolutely sure all our UI is cleaned up */ 3230 UIActivate(SVUIA_DEACTIVATE); 3231 3232 if (m_hAccel) 3233 { 3234 // MSDN: Accelerator tables loaded from resources are freed automatically when application terminates 3235 m_hAccel = NULL; 3236 } 3237 3238 if (m_hMenuArrangeModes) 3239 { 3240 DestroyMenu(m_hMenuArrangeModes); 3241 m_hMenuArrangeModes = NULL; 3242 } 3243 3244 if (m_hMenuViewModes) 3245 { 3246 DestroyMenu(m_hMenuViewModes); 3247 m_hMenuViewModes = NULL; 3248 } 3249 3250 if (m_hMenu) 3251 { 3252 DestroyMenu(m_hMenu); 3253 m_hMenu = NULL; 3254 } 3255 3256 if (m_ListView) 3257 { 3258 m_ListView.DestroyWindow(); 3259 } 3260 3261 if (m_hWnd) 3262 { 3263 _DoFolderViewCB(SFVM_WINDOWCLOSING, (WPARAM)m_hWnd, 0); 3264 DestroyWindow(); 3265 } 3266 3267 m_pShellBrowser.Release(); 3268 m_pCommDlgBrowser.Release(); 3269 3270 return S_OK; 3271} 3272 3273HRESULT WINAPI CDefView::GetCurrentInfo(LPFOLDERSETTINGS lpfs) 3274{ 3275 TRACE("(%p)->(%p) vmode=%x flags=%x\n", this, lpfs, 3276 m_FolderSettings.ViewMode, m_FolderSettings.fFlags); 3277 3278 if (!lpfs) 3279 return E_INVALIDARG; 3280 3281 *lpfs = m_FolderSettings; 3282 return S_OK; 3283} 3284 3285HRESULT WINAPI CDefView::AddPropertySheetPages(DWORD dwReserved, LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam) 3286{ 3287 TRACE("(%p)->(0x%lX, %p, %p)\n", this, dwReserved, lpfn, lparam); 3288 3289 SFVM_PROPPAGE_DATA Data = { dwReserved, lpfn, lparam }; 3290 _DoFolderViewCB(SFVM_ADDPROPERTYPAGES, 0, (LPARAM)&Data); 3291 return S_OK; 3292} 3293 3294static HRESULT Read(IStream *pS, LPVOID buffer, ULONG cb) 3295{ 3296 ULONG read; 3297 HRESULT hr = pS->Read(buffer, cb, &read); 3298 return FAILED(hr) ? hr : (cb == read ? S_OK : HResultFromWin32(ERROR_MORE_DATA)); 3299} 3300 3301static DWORD ReadDWORD(IPropertyBag *pPB, LPCWSTR name, DWORD def) 3302{ 3303 DWORD value; 3304 HRESULT hr = SHPropertyBag_ReadDWORD(pPB, name, &value); 3305 return SUCCEEDED(hr) ? value : def; 3306} 3307 3308HRESULT CDefView::GetDefaultViewStream(DWORD Stgm, IStream **ppStream) 3309{ 3310 CLSID clsid; 3311 HRESULT hr = IUnknown_GetClassID(m_pSFParent, &clsid); 3312 if (SUCCEEDED(hr)) 3313 { 3314 WCHAR path[MAX_PATH], name[39]; 3315 wsprintfW(path, L"%s\\%s", REGSTR_PATH_EXPLORER, L"Streams\\Default"); 3316 StringFromGUID2(clsid, name, 39); 3317 *ppStream = SHOpenRegStream2W(HKEY_CURRENT_USER, path, name, Stgm); 3318 hr = *ppStream ? S_OK : E_FAIL; 3319 } 3320 return hr; 3321} 3322 3323static HRESULT LoadColumnsStream(PERSISTCOLUMNS &cols, IStream *pS) 3324{ 3325 HRESULT hr = Read(pS, &cols, FIELD_OFFSET(PERSISTCOLUMNS, Columns)); 3326 if (FAILED(hr)) 3327 return hr; 3328 if (cols.Signature != PERSISTCOLUMNS::SIG || cols.Count > cols.MAXCOUNT) 3329 return HResultFromWin32(ERROR_INVALID_DATA); 3330 return Read(pS, &cols.Columns, sizeof(*cols.Columns) * cols.Count); 3331} 3332 3333HRESULT CDefView::LoadViewState() 3334{ 3335 PERSISTCLASSICVIEWSTATE cvs; 3336 PERSISTCOLUMNS cols; 3337 CComPtr<IStream> pS; 3338 CComPtr<IPropertyBag> pPB; 3339 bool fallback = false; 3340 HRESULT hrColumns = E_FAIL; 3341 HRESULT hr = IUnknown_QueryServicePropertyBag(m_pShellBrowser, SHGVSPB_FOLDER, IID_PPV_ARG(IPropertyBag, &pPB)); 3342 if (SUCCEEDED(hr)) 3343 { 3344 DWORD data; 3345 if (FAILED(hr = SHPropertyBag_ReadDWORD(pPB, L"Mode", &data))) 3346 goto loadfallback; 3347 cvs.FolderSettings.ViewMode = data; 3348 cvs.FolderSettings.fFlags = ReadDWORD(pPB, L"FFlags", FWF_NOGROUPING); 3349 data = ReadDWORD(pPB, L"Sort", ~0ul); 3350 cvs.SortColId = data != ~0ul ? (WORD)data : LISTVIEW_SORT_INFO::UNSPECIFIEDCOLUMN; 3351 cvs.SortDir = (INT8)ReadDWORD(pPB, L"SortDir", 1); 3352 if (SUCCEEDED(hrColumns = SHPropertyBag_ReadStream(pPB, L"ColInfo", &pS))) 3353 hrColumns = LoadColumnsStream(cols, pS); 3354 } 3355 else 3356 { 3357 if (FAILED(hr = (m_pShellBrowser ? m_pShellBrowser->GetViewStateStream(STGM_READ, &pS) : E_UNEXPECTED))) 3358 { 3359 loadfallback: 3360 hr = GetDefaultViewStream(STGM_READ, &pS); 3361 fallback = true; 3362 } 3363 if (FAILED(hr) || FAILED(hr = Read(pS, &cvs, sizeof(cvs)))) 3364 return hr; 3365 if (cvs.Signature != cvs.SIG) 3366 return HResultFromWin32(ERROR_INVALID_DATA); 3367 hrColumns = LoadColumnsStream(cols, pS); 3368 } 3369 m_FolderSettings.ViewMode = cvs.FolderSettings.ViewMode; 3370 m_FolderSettings.fFlags &= ~cvs.VALIDFWF; 3371 m_FolderSettings.fFlags |= cvs.FolderSettings.fFlags & cvs.VALIDFWF; 3372 if (SUCCEEDED(hrColumns)) 3373 { 3374 BOOL failed = FALSE; 3375 if ((m_LoadColumnsList = DPA_Create(cols.Count)) != NULL) 3376 { 3377 for (UINT i = 0; i < cols.Count; ++i) 3378 { 3379 failed |= !DPA_SetPtr(m_LoadColumnsList, i, UlongToPtr(cols.Columns[i])); 3380 } 3381 } 3382 if (failed || !cols.Count) 3383 { 3384 DPA_Destroy(m_LoadColumnsList); 3385 m_LoadColumnsList = NULL; 3386 } 3387 } 3388 m_sortInfo.bLoadedFromViewState = !fallback && m_LoadColumnsList && (int)cvs.SortColId != LISTVIEW_SORT_INFO::UNSPECIFIEDCOLUMN; 3389 m_sortInfo.bColumnIsFolderColumn = TRUE; 3390 m_sortInfo.Direction = cvs.SortDir > 0 ? 1 : -1; 3391 m_sortInfo.ListColumn = cvs.SortColId; 3392 return hr; 3393} 3394 3395HRESULT CDefView::SaveViewState(IStream *pStream) 3396{ 3397 if (!m_ListView.m_hWnd) 3398 return E_UNEXPECTED; 3399 int sortcol = MapListColumnToFolderColumn(m_sortInfo.ListColumn); 3400 PERSISTCLASSICVIEWSTATE cvs; 3401 cvs.SortColId = sortcol >= 0 ? (WORD)sortcol : 0; 3402 cvs.SortDir = m_sortInfo.Direction; 3403 PERSISTCOLUMNS cols; 3404 cols.Signature = PERSISTCOLUMNS::SIG; 3405 cols.Count = 0; 3406 LVCOLUMN lvc; 3407 lvc.mask = LVCF_WIDTH; 3408 for (UINT i = 0, j = 0; i < PERSISTCOLUMNS::MAXCOUNT && ListView_GetColumn(m_ListView, j, &lvc); ++j) 3409 { 3410 HRESULT hr = MapListColumnToFolderColumn(j); 3411 if (SUCCEEDED(hr)) 3412 { 3413 cols.Columns[i] = MAKELONG(hr, lvc.cx); 3414 cols.Count = ++i; 3415 } 3416 } 3417 UINT cbColumns = FIELD_OFFSET(PERSISTCOLUMNS, Columns) + (sizeof(*cols.Columns) * cols.Count); 3418 UpdateFolderViewFlags(); 3419 3420 IPropertyBag *pPB; 3421 HRESULT hr = S_OK; 3422 if (pStream) 3423 { 3424 pStream->AddRef(); 3425 goto stream; 3426 } 3427 hr = IUnknown_QueryServicePropertyBag(m_pShellBrowser, SHGVSPB_FOLDER, IID_PPV_ARG(IPropertyBag, &pPB)); 3428 if (SUCCEEDED(hr)) 3429 { 3430 UINT uViewMode; 3431 GetCurrentViewMode(&uViewMode); 3432 hr = SHPropertyBag_WriteDWORD(pPB, L"Mode", uViewMode); 3433 SHPropertyBag_WriteDWORD(pPB, L"FFlags", m_FolderSettings.fFlags); 3434 SHPropertyBag_WriteDWORD(pPB, L"Sort", cvs.SortColId); 3435 SHPropertyBag_WriteDWORD(pPB, L"SortDir", cvs.SortDir); 3436 pStream = cols.Count ? SHCreateMemStream((LPBYTE)&cols, cbColumns) : NULL; 3437 if (!pStream || FAILED(SHPropertyBag_WriteStream(pPB, L"ColInfo", pStream))) 3438 SHPropertyBag_Delete(pPB, L"ColInfo"); 3439#if 0 // TODO 3440 WCHAR name[MAX_PATH]; 3441 memcpy(name, L"ItemPos", sizeof(L"ItemPos")); 3442 if (SHGetPerScreenResName(name + 7, _countof(name) - 7, 0)) 3443 { 3444 if (GetAutoArrange() == S_FALSE) 3445 // TODO: Save listview item positions 3446 else 3447 SHPropertyBag_Delete(pPB, name); 3448 } 3449#endif 3450 pPB->Release(); 3451 } 3452 else if (SUCCEEDED(hr = (m_pShellBrowser ? m_pShellBrowser->GetViewStateStream(STGM_WRITE, &pStream) : E_UNEXPECTED))) 3453 { 3454 stream: 3455 ULONG written; 3456 cvs.Signature = cvs.SIG; 3457 cvs.FolderSettings = m_FolderSettings; 3458 hr = pStream->Write(&cvs, sizeof(cvs), &written); 3459 if (SUCCEEDED(hr)) 3460 hr = pStream->Write(&cols, cbColumns, &written); 3461 } 3462 // TODO: else if (SUCCEEDED(_DoFolderViewCB(SFVM_GETCOLUMNSTREAM))) 3463 if (pStream) 3464 pStream->Release(); 3465 return hr; 3466} 3467 3468HRESULT WINAPI CDefView::SaveViewState() 3469{ 3470 if (!(m_FolderSettings.fFlags & FWF_NOBROWSERVIEWSTATE)) 3471 return SaveViewState(NULL); 3472 return S_FALSE; 3473} 3474 3475#define UPDATEFOLDERVIEWFLAGS(bits, bit, set) ( (bits) = ((bits) & ~(bit)) | ((set) ? (bit) : 0) ) 3476void CDefView::UpdateFolderViewFlags() 3477{ 3478 UPDATEFOLDERVIEWFLAGS(m_FolderSettings.fFlags, FWF_AUTOARRANGE, GetAutoArrange() == S_OK); 3479 UPDATEFOLDERVIEWFLAGS(m_FolderSettings.fFlags, FWF_SNAPTOGRID, _GetSnapToGrid() == S_OK); 3480 UPDATEFOLDERVIEWFLAGS(m_FolderSettings.fFlags, FWF_NOGROUPING, !ListView_IsGroupViewEnabled(m_ListView.m_hWnd)); 3481} 3482 3483UINT CDefView::GetItemActivateFlags() 3484{ 3485 SHELLSTATE ss; 3486 SHGetSetSettings(&ss, SSF_DOUBLECLICKINWEBVIEW | SSF_WIN95CLASSIC, FALSE); 3487 return ((m_FolderSettings.fFlags & FWF_SINGLECLICKACTIVATE) || (!ss.fDoubleClickInWebView && !ss.fWin95Classic)) 3488 ? (LVS_EX_TRACKSELECT | LVS_EX_ONECLICKACTIVATE) : 0; 3489} 3490 3491HRESULT WINAPI CDefView::SelectItem(PCUITEMID_CHILD pidl, UINT uFlags) 3492{ 3493 int i; 3494 3495 TRACE("(%p)->(pidl=%p, 0x%08x) stub\n", this, pidl, uFlags); 3496 3497 if (!m_ListView) 3498 { 3499 ERR("!m_ListView\n"); 3500 return E_FAIL; 3501 } 3502 3503 i = LV_FindItemByPidl(pidl); 3504 if (i == -1) 3505 return S_OK; 3506 3507 LVITEMW lvItem = {0}; 3508 lvItem.mask = LVIF_STATE; 3509 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED; 3510 3511 while (m_ListView.GetItem(&lvItem)) 3512 { 3513 if (lvItem.iItem == i) 3514 { 3515 if (uFlags & SVSI_SELECT) 3516 lvItem.state |= LVIS_SELECTED; 3517 else 3518 lvItem.state &= ~LVIS_SELECTED; 3519 3520 if (uFlags & SVSI_FOCUSED) 3521 lvItem.state |= LVIS_FOCUSED; 3522 else 3523 lvItem.state &= ~LVIS_FOCUSED; 3524 } 3525 else 3526 { 3527 if (uFlags & SVSI_DESELECTOTHERS) 3528 { 3529 lvItem.state &= ~LVIS_SELECTED; 3530 } 3531 lvItem.state &= ~LVIS_FOCUSED; 3532 } 3533 3534 m_ListView.SetItem(&lvItem); 3535 lvItem.iItem++; 3536 } 3537 3538 if (uFlags & SVSI_ENSUREVISIBLE) 3539 m_ListView.EnsureVisible(i, FALSE); 3540 3541 if((uFlags & SVSI_EDIT) == SVSI_EDIT) 3542 m_ListView.EditLabel(i); 3543 3544 return S_OK; 3545} 3546 3547HRESULT WINAPI CDefView::GetItemObject(UINT uItem, REFIID riid, LPVOID *ppvOut) 3548{ 3549 HRESULT hr = E_NOINTERFACE; 3550 3551 TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n", this, uItem, debugstr_guid(&riid), ppvOut); 3552 3553 if (!ppvOut) 3554 return E_INVALIDARG; 3555 3556 *ppvOut = NULL; 3557 3558 switch (uItem) 3559 { 3560 case SVGIO_BACKGROUND: 3561 if (IsEqualIID(riid, IID_IContextMenu)) 3562 { 3563 hr = CDefViewBckgrndMenu_CreateInstance(m_pSF2Parent, riid, ppvOut); 3564 if (FAILED_UNEXPECTEDLY(hr)) 3565 return hr; 3566 3567 IUnknown_SetSite(*((IUnknown**)ppvOut), (IShellView *)this); 3568 } 3569 else if (IsEqualIID(riid, IID_IDispatch)) 3570 { 3571 if (m_pShellFolderViewDual == NULL) 3572 { 3573 hr = CDefViewDual_Constructor(riid, (LPVOID*)&m_pShellFolderViewDual); 3574 if (FAILED_UNEXPECTEDLY(hr)) 3575 return hr; 3576 } 3577 hr = m_pShellFolderViewDual->QueryInterface(riid, ppvOut); 3578 } 3579 break; 3580 case SVGIO_SELECTION: 3581 GetSelections(); 3582 hr = m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, riid, 0, ppvOut); 3583 if (FAILED_UNEXPECTEDLY(hr)) 3584 return hr; 3585 3586 if (IsEqualIID(riid, IID_IContextMenu)) 3587 IUnknown_SetSite(*((IUnknown**)ppvOut), (IShellView *)this); 3588 3589 break; 3590 } 3591 3592 TRACE("-- (%p)->(interface=%p)\n", this, *ppvOut); 3593 3594 return hr; 3595} 3596 3597FOLDERVIEWMODE CDefView::GetDefaultViewMode() 3598{ 3599 FOLDERVIEWMODE mode = ((m_FolderSettings.fFlags & FWF_DESKTOP) || !IsOS(OS_SERVERADMINUI)) ? FVM_ICON : FVM_DETAILS; 3600 FOLDERVIEWMODE temp = mode; 3601 if (SUCCEEDED(_DoFolderViewCB(SFVM_DEFVIEWMODE, 0, (LPARAM)&temp)) && IsSupportedFolderViewMode(temp)) 3602 mode = temp; 3603 return mode; 3604} 3605 3606HRESULT STDMETHODCALLTYPE CDefView::GetCurrentViewMode(UINT *pViewMode) 3607{ 3608 TRACE("(%p)->(%p), stub\n", this, pViewMode); 3609 3610 if (!pViewMode) 3611 return E_INVALIDARG; 3612 3613 *pViewMode = m_FolderSettings.ViewMode; 3614 return S_OK; 3615} 3616 3617HRESULT STDMETHODCALLTYPE CDefView::SetCurrentViewMode(UINT ViewMode) 3618{ 3619 DWORD dwStyle; 3620 TRACE("(%p)->(%u), stub\n", this, ViewMode); 3621 3622 /* It's not redundant to check FVM_AUTO because it's a (UINT)-1 */ 3623 if (((INT)ViewMode < FVM_FIRST || (INT)ViewMode > FVM_LAST) && ((INT)ViewMode != FVM_AUTO)) 3624 return E_INVALIDARG; 3625 3626 /* Windows before Vista uses LVM_SETVIEW and possibly 3627 LVM_SETEXTENDEDLISTVIEWSTYLE to set the style of the listview, 3628 while later versions seem to accomplish this through other 3629 means. */ 3630 switch (ViewMode) 3631 { 3632 case FVM_ICON: dwStyle = LVS_ICON; break; 3633 case FVM_SMALLICON: dwStyle = LVS_SMALLICON; break; 3634 case FVM_LIST: dwStyle = LVS_LIST; break; 3635 case FVM_DETAILS: dwStyle = LVS_REPORT; break; 3636 default: 3637 FIXME("ViewMode %d not implemented\n", ViewMode); 3638 dwStyle = LVS_LIST; 3639 break; 3640 } 3641 3642 m_ListView.ModifyStyle(LVS_TYPEMASK, dwStyle); 3643 3644 /* This will not necessarily be the actual mode set above. 3645 This mimics the behavior of Windows XP. */ 3646 m_FolderSettings.ViewMode = ViewMode; 3647 CheckToolbar(); 3648 return S_OK; 3649} 3650 3651HRESULT STDMETHODCALLTYPE CDefView::GetFolder(REFIID riid, void **ppv) 3652{ 3653 if (m_pSFParent == NULL) 3654 return E_FAIL; 3655 3656 return m_pSFParent->QueryInterface(riid, ppv); 3657} 3658 3659HRESULT STDMETHODCALLTYPE CDefView::Item(int iItemIndex, PITEMID_CHILD *ppidl) 3660{ 3661 PCUITEMID_CHILD pidl = _PidlByItem(iItemIndex); 3662 if (pidl) 3663 { 3664 *ppidl = ILClone(pidl); 3665 return S_OK; 3666 } 3667 3668 *ppidl = 0; 3669 return E_INVALIDARG; 3670} 3671 3672HRESULT STDMETHODCALLTYPE CDefView::ItemCount(UINT uFlags, int *pcItems) 3673{ 3674 TRACE("(%p)->(%u %p)\n", this, uFlags, pcItems); 3675 if (uFlags != SVGIO_ALLVIEW && uFlags != SVGIO_SELECTION) 3676 FIXME("some flags unsupported, %x\n", uFlags & ~(SVGIO_ALLVIEW | SVGIO_SELECTION)); 3677 if ((uFlags & SVGIO_TYPE_MASK) == SVGIO_SELECTION) 3678 *pcItems = m_ListView.GetSelectedCount(); 3679 else 3680 *pcItems = m_ListView.GetItemCount(); 3681 return S_OK; 3682} 3683 3684HRESULT STDMETHODCALLTYPE CDefView::Items(UINT uFlags, REFIID riid, void **ppv) 3685{ 3686 return E_NOTIMPL; 3687} 3688 3689HRESULT STDMETHODCALLTYPE CDefView::GetSelectionMarkedItem(int *piItem) 3690{ 3691 TRACE("(%p)->(%p)\n", this, piItem); 3692 3693 *piItem = m_ListView.GetSelectionMark(); 3694 3695 return S_OK; 3696} 3697 3698HRESULT STDMETHODCALLTYPE CDefView::GetFocusedItem(int *piItem) 3699{ 3700 TRACE("(%p)->(%p)\n", this, piItem); 3701 3702 *piItem = m_ListView.GetNextItem(-1, LVNI_FOCUSED); 3703 3704 return S_OK; 3705} 3706 3707HRESULT STDMETHODCALLTYPE CDefView::GetItemPosition(PCUITEMID_CHILD pidl, POINT *ppt) 3708{ 3709 if (!m_ListView) 3710 { 3711 ERR("!m_ListView\n"); 3712 return E_FAIL; 3713 } 3714 3715 int lvIndex = LV_FindItemByPidl(pidl); 3716 if (lvIndex == -1 || ppt == NULL) 3717 return E_INVALIDARG; 3718 3719 m_ListView.GetItemPosition(lvIndex, ppt); 3720 return S_OK; 3721} 3722 3723HRESULT STDMETHODCALLTYPE CDefView::GetSpacing(POINT *ppt) 3724{ 3725 TRACE("(%p)->(%p)\n", this, ppt); 3726 3727 if (!m_ListView) 3728 { 3729 ERR("!m_ListView\n"); 3730 return S_FALSE; 3731 } 3732 3733 if (ppt) 3734 { 3735 SIZE spacing; 3736 m_ListView.GetItemSpacing(spacing); 3737 3738 ppt->x = spacing.cx; 3739 ppt->y = spacing.cy; 3740 } 3741 3742 return S_OK; 3743} 3744 3745HRESULT STDMETHODCALLTYPE CDefView::GetDefaultSpacing(POINT *ppt) 3746{ 3747 return E_NOTIMPL; 3748} 3749 3750HRESULT STDMETHODCALLTYPE CDefView::GetAutoArrange() 3751{ 3752 return ((m_ListView.GetStyle() & LVS_AUTOARRANGE) ? S_OK : S_FALSE); 3753} 3754 3755HRESULT CDefView::_GetSnapToGrid() 3756{ 3757 DWORD dwExStyle = (DWORD)m_ListView.SendMessage(LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); 3758 return ((dwExStyle & LVS_EX_SNAPTOGRID) ? S_OK : S_FALSE); 3759} 3760 3761HRESULT STDMETHODCALLTYPE CDefView::SelectItem(int iItem, DWORD dwFlags) 3762{ 3763 LVITEMW lvItem; 3764 3765 TRACE("(%p)->(%d, %x)\n", this, iItem, dwFlags); 3766 3767 lvItem.state = 0; 3768 lvItem.stateMask = LVIS_SELECTED; 3769 3770 if (dwFlags & SVSI_ENSUREVISIBLE) 3771 m_ListView.EnsureVisible(iItem, 0); 3772 3773 /* all items */ 3774 if (dwFlags & SVSI_DESELECTOTHERS) 3775 m_ListView.SetItemState(-1, 0, LVIS_SELECTED); 3776 3777 /* this item */ 3778 if (dwFlags & SVSI_SELECT) 3779 lvItem.state |= LVIS_SELECTED; 3780 3781 if (dwFlags & SVSI_FOCUSED) 3782 lvItem.stateMask |= LVIS_FOCUSED; 3783 3784 m_ListView.SetItemState(iItem, lvItem.state, lvItem.stateMask); 3785 3786 if ((dwFlags & SVSI_EDIT) == SVSI_EDIT) 3787 m_ListView.EditLabel(iItem); 3788 3789 return S_OK; 3790} 3791 3792HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItems(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, POINT *apt, DWORD dwFlags) 3793{ 3794 ASSERT(m_ListView); 3795 m_ListView.SetItemState(-1, 0, LVIS_SELECTED); // Reset the selection 3796 for (UINT i = 0 ; i < cidl; i++) 3797 { 3798 int lvIndex = LV_FindItemByPidl(apidl[i]); 3799 if (lvIndex != -1) 3800 SelectAndPositionItem(lvIndex, dwFlags, apt ? &apt[i] : NULL); 3801 } 3802 return S_OK; 3803} 3804 3805 3806// IShellView2 implementation 3807 3808HRESULT STDMETHODCALLTYPE CDefView::GetView(SHELLVIEWID *pVid, ULONG view_type) 3809{ 3810 if (view_type == SV2GV_DEFAULTVIEW) 3811 { 3812 *pVid = VID_Default; 3813 return S_OK; 3814 } 3815 if (view_type == SV2GV_CURRENTVIEW) 3816 view_type = m_FolderSettings.ViewMode; 3817 if ((int)view_type < 0) 3818 return E_UNEXPECTED; 3819 3820 view_type += FVM_FIRST; 3821 if (!IsSupportedFolderViewMode(view_type)) 3822 return E_INVALIDARG; 3823 *pVid = *FolderViewModeToShellViewId(view_type); 3824 return S_OK; 3825} 3826 3827HRESULT STDMETHODCALLTYPE CDefView::CreateViewWindow2(LPSV2CVW2_PARAMS view_params) 3828{ 3829 return CreateViewWindow3(view_params->psbOwner, view_params->psvPrev, 3830 SV3CVW3_DEFAULT, (FOLDERFLAGS)view_params->pfs->fFlags, (FOLDERFLAGS)view_params->pfs->fFlags, 3831 (FOLDERVIEWMODE)view_params->pfs->ViewMode, view_params->pvid, view_params->prcView, &view_params->hwndView); 3832} 3833 3834HRESULT STDMETHODCALLTYPE CDefView::CreateViewWindow3(IShellBrowser *psb, IShellView *psvPrevious, SV3CVW3_FLAGS view_flags, FOLDERFLAGS mask, FOLDERFLAGS flags, FOLDERVIEWMODE mode, const SHELLVIEWID *view_id, const RECT *prcView, HWND *hwnd) 3835{ 3836 OLEMENUGROUPWIDTHS omw = { { 0, 0, 0, 0, 0, 0 } }; 3837 const UINT SUPPORTED_SV3CVW3 = SV3CVW3_FORCEVIEWMODE | SV3CVW3_FORCEFOLDERFLAGS; 3838 const UINT IGNORE_FWF = FWF_OWNERDATA; // FIXME: Support this 3839 3840 *hwnd = NULL; 3841 3842 TRACE("(%p)->(shlview=%p shlbrs=%p rec=%p hwnd=%p vmode=%x flags=%x)\n", this, psvPrevious, psb, prcView, hwnd, mode, flags); 3843 if (prcView != NULL) 3844 TRACE("-- left=%i top=%i right=%i bottom=%i\n", prcView->left, prcView->top, prcView->right, prcView->bottom); 3845 3846 /* Validate the Shell Browser */ 3847 if (psb == NULL || m_hWnd) 3848 return E_UNEXPECTED; 3849 3850 if (view_flags & ~SUPPORTED_SV3CVW3) 3851 FIXME("unsupported view flags 0x%08x\n", view_flags & ~SUPPORTED_SV3CVW3); 3852 3853 /* Set up the member variables */ 3854 m_pShellBrowser = psb; 3855 m_FolderSettings.ViewMode = mode; 3856 m_FolderSettings.fFlags = (mask & flags) & ~IGNORE_FWF; 3857 3858 if (view_id) 3859 { 3860 FOLDERVIEWMODE temp = (FOLDERVIEWMODE)ShellViewIdToFolderViewMode(view_id); 3861 if (IsSupportedFolderViewMode(temp)) 3862 mode = temp; 3863 else if (*view_id == VID_Default) 3864 mode = FVM_AUTO; 3865 else 3866 FIXME("Ignoring unrecognized VID %s\n", debugstr_guid(view_id)); 3867 } 3868 if (mode == FVM_AUTO) 3869 m_FolderSettings.ViewMode = GetDefaultViewMode(); 3870 3871 if (!IsSupportedFolderViewMode(m_FolderSettings.ViewMode)) 3872 { 3873 ERR("Ignoring %s FVM %u\n", FolderViewModeToShellViewId(m_FolderSettings.ViewMode) 3874 ? "unsupported" : "invalid", m_FolderSettings.ViewMode); 3875 m_FolderSettings.ViewMode = FVM_ICON; 3876 } 3877 const UINT requestedViewMode = m_FolderSettings.ViewMode; 3878 3879 /* Get our parent window */ 3880 m_pShellBrowser->GetWindow(&m_hWndParent); 3881 _DoFolderViewCB(SFVM_HWNDMAIN, 0, (LPARAM)m_hWndParent); 3882 3883 /* Try to get the ICommDlgBrowserInterface, adds a reference !!! */ 3884 m_pCommDlgBrowser = NULL; 3885 if (SUCCEEDED(m_pShellBrowser->QueryInterface(IID_PPV_ARG(ICommDlgBrowser, &m_pCommDlgBrowser)))) 3886 { 3887 TRACE("-- CommDlgBrowser\n"); 3888 } 3889 3890 LoadViewState(); 3891 if (view_flags & SV3CVW3_FORCEVIEWMODE) 3892 m_FolderSettings.ViewMode = requestedViewMode; 3893 if (view_flags & SV3CVW3_FORCEFOLDERFLAGS) 3894 m_FolderSettings.fFlags = (mask & flags) & ~IGNORE_FWF; 3895 3896 RECT rcView = *prcView; 3897 Create(m_hWndParent, rcView, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP, 0, 0U); 3898 if (m_hWnd == NULL) 3899 return E_FAIL; 3900 3901 *hwnd = m_hWnd; 3902 3903 CheckToolbar(); 3904 3905 if (!*hwnd) 3906 return E_FAIL; 3907 3908 _DoFolderViewCB(SFVM_WINDOWCREATED, (WPARAM)m_hWnd, 0); 3909 3910 SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); 3911 UpdateWindow(); 3912 3913 if (!m_hMenu) 3914 { 3915 m_hMenu = CreateMenu(); 3916 m_pShellBrowser->InsertMenusSB(m_hMenu, &omw); 3917 TRACE("-- after fnInsertMenusSB\n"); 3918 } 3919 3920 _MergeToolbar(); 3921 3922 return S_OK; 3923} 3924 3925HRESULT STDMETHODCALLTYPE CDefView::HandleRename(LPCITEMIDLIST pidl) 3926{ 3927 if (!pidl) 3928 { 3929 int idx = m_ListView.GetNextItem(-1, LVNI_SELECTED | LVNI_FOCUSED); 3930 if (idx < 0) 3931 idx = m_ListView.GetNextItem(-1, LVNI_SELECTED); 3932 pidl = _PidlByItem(idx); 3933 } 3934 if (ILFindLastID(pidl) != pidl) 3935 return E_INVALIDARG; 3936 return SelectItem(pidl, SVSI_EDIT | SVSI_ENSUREVISIBLE | SVSI_FOCUSED | SVSI_SELECT); 3937} 3938 3939HRESULT CDefView::SelectAndPositionItem(int Idx, UINT fSVSI, POINT *ppt) 3940{ 3941 if (Idx == -1) 3942 return fSVSI == SVSI_DESELECTOTHERS ? SelectItem(-2, fSVSI) : E_INVALIDARG; 3943 if (ppt) 3944 m_ListView.SetItemPosition(Idx, ppt); 3945 return SelectItem(Idx, fSVSI); // After SetItemPosition for SVSI_ENSUREVISIBLE 3946} 3947 3948HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItem(LPCITEMIDLIST item, UINT flags, POINT *point) 3949{ 3950 if (!item) 3951 return SelectAndPositionItem(-1, flags, point); 3952 int idx = LV_FindItemByPidl(item); 3953 return idx != -1 ? SelectAndPositionItem(idx, flags, point) : S_FALSE; 3954} 3955 3956// IShellFolderView implementation 3957 3958HRESULT STDMETHODCALLTYPE CDefView::Rearrange(LPARAM sort) 3959{ 3960 _Sort(LOWORD(sort & SHCIDS_COLUMNMASK)); 3961 return S_OK; 3962} 3963 3964HRESULT STDMETHODCALLTYPE CDefView::GetArrangeParam(LPARAM *sort) 3965{ 3966 int col = m_sortInfo.ListColumn; 3967 *sort = col != LISTVIEW_SORT_INFO::UNSPECIFIEDCOLUMN ? col : 0; 3968 return col != LISTVIEW_SORT_INFO::UNSPECIFIEDCOLUMN ? S_OK : S_FALSE; 3969} 3970 3971HRESULT STDMETHODCALLTYPE CDefView::ArrangeGrid() 3972{ 3973 m_ListView.SetExtendedListViewStyle(LVS_EX_SNAPTOGRID, LVS_EX_SNAPTOGRID); 3974 return S_OK; 3975} 3976 3977HRESULT STDMETHODCALLTYPE CDefView::AutoArrange() 3978{ 3979 m_ListView.ModifyStyle(0, LVS_AUTOARRANGE); 3980 m_ListView.Arrange(LVA_DEFAULT); 3981 return S_OK; 3982} 3983 3984HRESULT STDMETHODCALLTYPE CDefView::AddObject(PITEMID_CHILD pidl, UINT *item) 3985{ 3986 TRACE("(%p)->(%p %p)\n", this, pidl, item); 3987 if (!m_ListView) 3988 { 3989 ERR("!m_ListView\n"); 3990 return E_FAIL; 3991 } 3992 *item = LV_AddItem(pidl); 3993 return (int)*item >= 0 ? S_OK : E_OUTOFMEMORY; 3994} 3995 3996HRESULT STDMETHODCALLTYPE CDefView::GetObject(PITEMID_CHILD *pidl, UINT item) 3997{ 3998 TRACE("(%p)->(%p %d)\n", this, pidl, item); 3999 return Item(item, pidl); 4000} 4001 4002HRESULT STDMETHODCALLTYPE CDefView::RemoveObject(PITEMID_CHILD pidl, UINT *item) 4003{ 4004 TRACE("(%p)->(%p %p)\n", this, pidl, item); 4005 4006 if (!m_ListView) 4007 { 4008 ERR("!m_ListView\n"); 4009 return E_FAIL; 4010 } 4011 4012 if (pidl) 4013 { 4014 *item = LV_FindItemByPidl(ILFindLastID(pidl)); 4015 m_ListView.DeleteItem(*item); 4016 } 4017 else 4018 { 4019 *item = 0; 4020 m_ListView.DeleteAllItems(); 4021 } 4022 4023 return S_OK; 4024} 4025 4026HRESULT STDMETHODCALLTYPE CDefView::GetObjectCount(UINT *count) 4027{ 4028 TRACE("(%p)->(%p)\n", this, count); 4029 *count = m_ListView.GetItemCount(); 4030 return S_OK; 4031} 4032 4033HRESULT STDMETHODCALLTYPE CDefView::SetObjectCount(UINT count, UINT flags) 4034{ 4035 FIXME("(%p)->(%d %x) stub\n", this, count, flags); 4036 return E_NOTIMPL; 4037} 4038 4039HRESULT STDMETHODCALLTYPE CDefView::UpdateObject(PITEMID_CHILD pidl_old, PITEMID_CHILD pidl_new, UINT *item) 4040{ 4041 FIXME("(%p)->(%p %p %p) stub\n", this, pidl_old, pidl_new, item); 4042 return E_NOTIMPL; 4043} 4044 4045HRESULT STDMETHODCALLTYPE CDefView::RefreshObject(PITEMID_CHILD pidl, UINT *item) 4046{ 4047 FIXME("(%p)->(%p %p) stub\n", this, pidl, item); 4048 return E_NOTIMPL; 4049} 4050 4051HRESULT STDMETHODCALLTYPE CDefView::SetRedraw(BOOL redraw) 4052{ 4053 TRACE("(%p)->(%d)\n", this, redraw); 4054 if (m_ListView) 4055 m_ListView.SetRedraw(redraw); 4056 return S_OK; 4057} 4058 4059HRESULT STDMETHODCALLTYPE CDefView::GetSelectedCount(UINT *count) 4060{ 4061 *count = m_ListView.GetSelectedCount(); 4062 return S_OK; 4063} 4064 4065HRESULT STDMETHODCALLTYPE CDefView::GetSelectedObjects(PCUITEMID_CHILD **pidl, UINT *items) 4066{ 4067 TRACE("(%p)->(%p %p)\n", this, pidl, items); 4068 4069 *items = GetSelections(); 4070 4071 if (*items) 4072 { 4073 *pidl = static_cast<PCUITEMID_CHILD *>(LocalAlloc(0, *items * sizeof(PCUITEMID_CHILD))); 4074 if (!*pidl) 4075 { 4076 return E_OUTOFMEMORY; 4077 } 4078 4079 // It's documented that caller shouldn't free the PIDLs, only the array itself 4080 memcpy(*pidl, m_apidl, *items * sizeof(PCUITEMID_CHILD)); 4081 } 4082 4083 return S_OK; 4084} 4085 4086HRESULT STDMETHODCALLTYPE CDefView::IsDropOnSource(IDropTarget *drop_target) 4087{ 4088 if ((m_iDragOverItem == -1 || m_pCurDropTarget == NULL) && 4089 (m_pSourceDataObject.p)) 4090 { 4091 return S_OK; 4092 } 4093 4094 return S_FALSE; 4095} 4096 4097HRESULT STDMETHODCALLTYPE CDefView::GetDragPoint(POINT *pt) 4098{ 4099 if (!pt) 4100 return E_INVALIDARG; 4101 4102 *pt = m_ptFirstMousePos; 4103 return S_OK; 4104} 4105 4106HRESULT STDMETHODCALLTYPE CDefView::GetDropPoint(POINT *pt) 4107{ 4108 FIXME("(%p)->(%p) stub\n", this, pt); 4109 return E_NOTIMPL; 4110} 4111 4112HRESULT STDMETHODCALLTYPE CDefView::MoveIcons(IDataObject *obj) 4113{ 4114 TRACE("(%p)->(%p)\n", this, obj); 4115 return E_NOTIMPL; 4116} 4117 4118HRESULT STDMETHODCALLTYPE CDefView::SetItemPos(PCUITEMID_CHILD pidl, POINT *pt) 4119{ 4120 FIXME("(%p)->(%p %p) stub\n", this, pidl, pt); 4121 return E_NOTIMPL; 4122} 4123 4124HRESULT STDMETHODCALLTYPE CDefView::IsBkDropTarget(IDropTarget *drop_target) 4125{ 4126 FIXME("(%p)->(%p) stub\n", this, drop_target); 4127 return E_NOTIMPL; 4128} 4129 4130HRESULT STDMETHODCALLTYPE CDefView::SetClipboard(BOOL move) 4131{ 4132 if (!move) 4133 return S_OK; 4134 4135 UINT CutCount = 0; 4136 for (int i = -1; (i = m_ListView.GetNextItem(i, LVNI_SELECTED)) != -1;) 4137 { 4138 if (!CutCount++) 4139 { 4140 // Turn off the LVIS_CUT LVM_SETCALLBACKMASK optimization 4141 m_ListView.SendMessageW(LVM_SETCALLBACKMASK, m_ListView.SendMessageW(LVM_GETCALLBACKMASK, 0, 0) & ~LVIS_CUT, 0); 4142 RefreshGhostedState(); 4143 } 4144 m_ListView.SetItemState(i, LVIS_CUT, LVIS_CUT); 4145 } 4146 if (CutCount) 4147 { 4148 m_ClipboardChain.Hook(m_hWnd); 4149 m_HasCutItems = true; 4150 } 4151 return S_OK; 4152} 4153 4154HRESULT STDMETHODCALLTYPE CDefView::SetPoints(IDataObject *obj) 4155{ 4156 FIXME("(%p)->(%p) stub\n", this, obj); 4157 return E_NOTIMPL; 4158} 4159 4160HRESULT STDMETHODCALLTYPE CDefView::GetItemSpacing(ITEMSPACING *spacing) 4161{ 4162 FIXME("(%p)->(%p) stub\n", this, spacing); 4163 return E_NOTIMPL; 4164} 4165 4166HRESULT STDMETHODCALLTYPE CDefView::SetCallback(IShellFolderViewCB *new_cb, IShellFolderViewCB **old_cb) 4167{ 4168 if (old_cb) 4169 *old_cb = m_pShellFolderViewCB.Detach(); 4170 4171 m_pShellFolderViewCB = new_cb; 4172 m_pFolderFilter = NULL; 4173 if (new_cb) 4174 new_cb->QueryInterface(IID_PPV_ARG(IFolderFilter, &m_pFolderFilter)); 4175 return S_OK; 4176} 4177 4178HRESULT STDMETHODCALLTYPE CDefView::Select(UINT flags) 4179{ 4180 FIXME("(%p)->(%d) stub\n", this, flags); 4181 return E_NOTIMPL; 4182} 4183 4184HRESULT STDMETHODCALLTYPE CDefView::QuerySupport(UINT *support) 4185{ 4186 TRACE("(%p)->(%p)\n", this, support); 4187 return S_OK; 4188} 4189 4190HRESULT STDMETHODCALLTYPE CDefView::SetAutomationObject(IDispatch *disp) 4191{ 4192 FIXME("(%p)->(%p) stub\n", this, disp); 4193 return E_NOTIMPL; 4194} 4195 4196HRESULT WINAPI CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText) 4197{ 4198 FIXME("(%p)->(%p(%s) 0x%08x %p %p\n", 4199 this, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText); 4200 4201 if (!prgCmds) 4202 return E_INVALIDARG; 4203 4204 for (UINT i = 0; i < cCmds; i++) 4205 { 4206 FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID); 4207 prgCmds[i].cmdf = 0; 4208 } 4209 4210 return OLECMDERR_E_UNKNOWNGROUP; 4211} 4212 4213/// 4214// ISVOleCmdTarget_Exec(IOleCommandTarget) 4215// 4216// nCmdID is the OLECMDID_* enumeration 4217HRESULT WINAPI CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut) 4218{ 4219 FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n", 4220 this, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut); 4221 4222 if (!pguidCmdGroup) 4223 return OLECMDERR_E_UNKNOWNGROUP; 4224 4225 if (IsEqualCLSID(*pguidCmdGroup, m_Category)) 4226 { 4227 if (nCmdID == FCIDM_SHVIEW_AUTOARRANGE) 4228 { 4229 if (V_VT(pvaIn) != VT_INT_PTR) 4230 return OLECMDERR_E_NOTSUPPORTED; 4231 4232 TPMPARAMS params; 4233 params.cbSize = sizeof(params); 4234 params.rcExclude = *(RECT*) V_INTREF(pvaIn); 4235 4236 if (m_hMenuViewModes) 4237 { 4238 // Duplicate all but the last two items of the view modes menu 4239 HMENU hmenuViewPopup = CreatePopupMenu(); 4240 Shell_MergeMenus(hmenuViewPopup, m_hMenuViewModes, 0, 0, 0xFFFF, 0); 4241 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION); 4242 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION); 4243 CheckViewMode(hmenuViewPopup); 4244 TrackPopupMenuEx(hmenuViewPopup, TPM_LEFTALIGN | TPM_TOPALIGN, params.rcExclude.left, params.rcExclude.bottom, m_hWndParent, &params); 4245 ::DestroyMenu(hmenuViewPopup); 4246 } 4247 4248 // pvaOut is VT_I4 with value 0x403 (cmd id of the new mode maybe?) 4249 V_VT(pvaOut) = VT_I4; 4250 V_I4(pvaOut) = 0x403; 4251 } 4252 } 4253 4254 if (IsEqualIID(*pguidCmdGroup, CGID_Explorer) && 4255 (nCmdID == 0x29) && 4256 (nCmdexecopt == 4) && pvaOut) 4257 return S_OK; 4258 4259 if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView) && 4260 (nCmdID == 9) && 4261 (nCmdexecopt == 0)) 4262 return 1; 4263 4264 if (IsEqualIID(*pguidCmdGroup, CGID_DefView)) 4265 { 4266 CComPtr<IStream> pStream; 4267 WCHAR SubKey[MAX_PATH]; 4268 switch (nCmdID) 4269 { 4270 case DVCMDID_SET_DEFAULTFOLDER_SETTINGS: 4271 SHDeleteKey(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\ShellNoRoam\\Bags"); 4272 if (SUCCEEDED(GetDefaultViewStream(STGM_WRITE, &pStream))) 4273 SaveViewState(pStream); 4274 return S_OK; 4275 case DVCMDID_RESET_DEFAULTFOLDER_SETTINGS: 4276 PathCombineW(SubKey, REGSTR_PATH_EXPLORER, L"Streams\\Default"); 4277 SHDeleteKey(HKEY_CURRENT_USER, SubKey); 4278 SHDeleteKey(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\ShellNoRoam\\Bags"); 4279 m_FolderSettings.fFlags |= FWF_NOBROWSERVIEWSTATE; // Don't let this folder save itself 4280 return S_OK; 4281 } 4282 } 4283 4284 return OLECMDERR_E_UNKNOWNGROUP; 4285} 4286 4287/********************************************************** 4288 * ISVDropTarget implementation 4289 */ 4290 4291/****************************************************************************** 4292 * drag_notify_subitem [Internal] 4293 * 4294 * Figure out the shellfolder object, which is currently under the mouse cursor 4295 * and notify it via the IDropTarget interface. 4296 */ 4297 4298#define SCROLLAREAWIDTH 20 4299 4300HRESULT CDefView::drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) 4301{ 4302 LONG lResult; 4303 HRESULT hr; 4304 RECT clientRect; 4305 4306 /* The key state on drop doesn't have MK_LBUTTON or MK_RBUTTON because it 4307 reflects the key state after the user released the button, so we need 4308 to remember the last key state when the button was pressed */ 4309 m_grfKeyState = grfKeyState; 4310 4311 // Map from global to client coordinates and query the index of the 4312 // listview-item, which is currently under the mouse cursor. 4313 LVHITTESTINFO htinfo = {{pt.x, pt.y}, LVHT_ONITEM}; 4314 ScreenToClient(&htinfo.pt); 4315 lResult = m_ListView.HitTest(&htinfo); 4316 4317 /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */ 4318 ::GetClientRect(m_ListView, &clientRect); 4319 if (htinfo.pt.x == m_ptLastMousePos.x && htinfo.pt.y == m_ptLastMousePos.y && 4320 (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH || 4321 htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH)) 4322 { 4323 m_cScrollDelay = (m_cScrollDelay + 1) % 5; // DragOver is called every 50 ms 4324 if (m_cScrollDelay == 0) 4325 { 4326 /* Mouse did hover another 250 ms over the scroll-area */ 4327 if (htinfo.pt.x < SCROLLAREAWIDTH) 4328 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEUP, 0); 4329 4330 if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH) 4331 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEDOWN, 0); 4332 4333 if (htinfo.pt.y < SCROLLAREAWIDTH) 4334 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEUP, 0); 4335 4336 if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH) 4337 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEDOWN, 0); 4338 } 4339 } 4340 else 4341 { 4342 m_cScrollDelay = 0; // Reset, if cursor is not over the listview's scroll-area 4343 } 4344 4345 m_ptLastMousePos = htinfo.pt; 4346 ::ClientToListView(m_ListView, &m_ptLastMousePos); 4347 4348 /* We need to check if we drag the selection over itself */ 4349 if (lResult != -1 && m_pSourceDataObject.p != NULL) 4350 { 4351 PCUITEMID_CHILD pidl = _PidlByItem(lResult); 4352 4353 for (UINT i = 0; i < m_cidl; i++) 4354 { 4355 if (pidl == m_apidl[i]) 4356 { 4357 /* The item that is being draged is hovering itself. */ 4358 lResult = -1; 4359 break; 4360 } 4361 } 4362 } 4363 4364 // If we are still over the previous sub-item, notify it via DragOver and return 4365 if (m_pCurDropTarget && lResult == m_iDragOverItem) 4366 return m_pCurDropTarget->DragOver(grfKeyState, pt, pdwEffect); 4367 4368 // We've left the previous sub-item, notify it via DragLeave and release it 4369 if (m_pCurDropTarget) 4370 { 4371 PCUITEMID_CHILD pidl = _PidlByItem(m_iDragOverItem); 4372 if (pidl) 4373 SelectItem(pidl, 0); 4374 4375 m_pCurDropTarget->DragLeave(); 4376 m_pCurDropTarget.Release(); 4377 } 4378 4379 m_iDragOverItem = lResult; 4380 4381 if (lResult == -1) 4382 { 4383 // We are not above one of the listview's subitems. Bind to the 4384 // parent folder's DropTarget interface. 4385 hr = m_pSFParent->CreateViewObject(NULL, IID_PPV_ARG(IDropTarget,&m_pCurDropTarget)); 4386 } 4387 else 4388 { 4389 // Query the relative PIDL of the shellfolder object represented 4390 // by the currently dragged over listview-item ... 4391 PCUITEMID_CHILD pidl = _PidlByItem(lResult); 4392 4393 // ... and bind m_pCurDropTarget to the IDropTarget interface of an UIObject of this object 4394 hr = m_pSFParent->GetUIObjectOf(m_ListView, 1, &pidl, IID_NULL_PPV_ARG(IDropTarget, &m_pCurDropTarget)); 4395 } 4396 4397 IUnknown_SetSite(m_pCurDropTarget, (IShellView *)this); 4398 4399 // If anything failed, m_pCurDropTarget should be NULL now, which ought to be a save state 4400 if (FAILED(hr)) 4401 { 4402 *pdwEffect = DROPEFFECT_NONE; 4403 return hr; 4404 } 4405 4406 if (m_iDragOverItem != -1) 4407 { 4408 SelectItem(m_iDragOverItem, SVSI_SELECT); 4409 } 4410 4411 // Notify the item just entered via DragEnter 4412 return m_pCurDropTarget->DragEnter(m_pCurDataObject, grfKeyState, pt, pdwEffect); 4413} 4414 4415HRESULT WINAPI CDefView::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) 4416{ 4417 if (*pdwEffect == DROPEFFECT_NONE) 4418 return S_OK; 4419 4420 /* Get a hold on the data object for later calls to DragEnter on the sub-folders */ 4421 m_pCurDataObject = pDataObject; 4422 4423 HRESULT hr = drag_notify_subitem(grfKeyState, pt, pdwEffect); 4424 if (SUCCEEDED(hr)) 4425 { 4426 POINT ptClient = {pt.x, pt.y}; 4427 ScreenToClient(&ptClient); 4428 ImageList_DragEnter(m_hWnd, ptClient.x, ptClient.y); 4429 } 4430 4431 return hr; 4432} 4433 4434HRESULT WINAPI CDefView::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) 4435{ 4436 POINT ptClient = {pt.x, pt.y}; 4437 ScreenToClient(&ptClient); 4438 ImageList_DragMove(ptClient.x, ptClient.y); 4439 return drag_notify_subitem(grfKeyState, pt, pdwEffect); 4440} 4441 4442HRESULT WINAPI CDefView::DragLeave() 4443{ 4444 ImageList_DragLeave(m_hWnd); 4445 4446 if (m_pCurDropTarget) 4447 { 4448 m_pCurDropTarget->DragLeave(); 4449 m_pCurDropTarget.Release(); 4450 } 4451 4452 if (m_pCurDataObject != NULL) 4453 { 4454 m_pCurDataObject.Release(); 4455 } 4456 4457 m_iDragOverItem = 0; 4458 4459 return S_OK; 4460} 4461 4462INT CDefView::_FindInsertableIndexFromPoint(POINT pt) 4463{ 4464 RECT rcBound; 4465 INT i, nCount = m_ListView.GetItemCount(); 4466 DWORD dwSpacing; 4467 INT dx, dy; 4468 BOOL bSmall = ((m_ListView.GetStyle() & LVS_TYPEMASK) != LVS_ICON); 4469 4470 // FIXME: LVM_GETORIGIN is broken. See CORE-17266 4471 pt.x += m_ListView.GetScrollPos(SB_HORZ); 4472 pt.y += m_ListView.GetScrollPos(SB_VERT); 4473 4474 if (m_ListView.GetStyle() & LVS_ALIGNLEFT) 4475 { 4476 // vertically 4477 for (i = 0; i < nCount; ++i) 4478 { 4479 dwSpacing = ListView_GetItemSpacing(m_ListView, bSmall); 4480 dx = LOWORD(dwSpacing); 4481 dy = HIWORD(dwSpacing); 4482 ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS); 4483 rcBound.right = rcBound.left + dx; 4484 rcBound.bottom = rcBound.top + dy; 4485 if (pt.x < rcBound.right && pt.y < (rcBound.top + rcBound.bottom) / 2) 4486 { 4487 return i; 4488 } 4489 } 4490 for (i = nCount - 1; i >= 0; --i) 4491 { 4492 ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS); 4493 if (rcBound.left < pt.x && rcBound.top < pt.y) 4494 { 4495 return i + 1; 4496 } 4497 } 4498 } 4499 else 4500 { 4501 // horizontally 4502 for (i = 0; i < nCount; ++i) 4503 { 4504 dwSpacing = ListView_GetItemSpacing(m_ListView, bSmall); 4505 dx = LOWORD(dwSpacing); 4506 dy = HIWORD(dwSpacing); 4507 ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS); 4508 rcBound.right = rcBound.left + dx; 4509 rcBound.bottom = rcBound.top + dy; 4510 if (pt.y < rcBound.bottom && pt.x < rcBound.left) 4511 { 4512 return i; 4513 } 4514 if (pt.y < rcBound.bottom && pt.x < rcBound.right) 4515 { 4516 return i + 1; 4517 } 4518 } 4519 for (i = nCount - 1; i >= 0; --i) 4520 { 4521 ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS); 4522 if (rcBound.left < pt.x && rcBound.top < pt.y) 4523 { 4524 return i + 1; 4525 } 4526 } 4527 } 4528 4529 return nCount; 4530} 4531 4532void CDefView::_HandleStatusBarResize(int nWidth) 4533{ 4534 LRESULT lResult; 4535 4536 if (!m_isFullStatusBar) 4537 { 4538 int nPartArray[] = {-1}; 4539 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, _countof(nPartArray), (LPARAM)nPartArray, &lResult); 4540 return; 4541 } 4542 4543 int nFileSizePartLength = 125; 4544 const int nLocationPartLength = 150; 4545 const int nRightPartsLength = nFileSizePartLength + nLocationPartLength; 4546 int nObjectsPartLength = nWidth - nRightPartsLength; 4547 4548 // If the window is small enough just divide each part into thirds 4549 // to match the behavior of Windows Server 2003 4550 if (nObjectsPartLength <= nLocationPartLength) 4551 nObjectsPartLength = nFileSizePartLength = nWidth / 3; 4552 4553 int nPartArray[] = {nObjectsPartLength, nObjectsPartLength + nFileSizePartLength, -1}; 4554 4555 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, _countof(nPartArray), (LPARAM)nPartArray, &lResult); 4556} 4557 4558void CDefView::_ForceStatusBarResize() 4559{ 4560 // Get the handle for the status bar 4561 HWND fStatusBar; 4562 m_pShellBrowser->GetControlWindow(FCW_STATUS, &fStatusBar); 4563 4564 // Get the size of our status bar 4565 RECT statusBarSize; 4566 ::GetWindowRect(fStatusBar, &statusBarSize); 4567 4568 // Resize the status bar 4569 _HandleStatusBarResize(statusBarSize.right - statusBarSize.left); 4570} 4571 4572typedef CSimpleMap<LPARAM, INT> CLParamIndexMap; 4573 4574static INT CALLBACK 4575SelectionMoveCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) 4576{ 4577 CLParamIndexMap *pmap = (CLParamIndexMap *)lParamSort; 4578 INT i1 = pmap->Lookup(lParam1), i2 = pmap->Lookup(lParam2); 4579 if (i1 < i2) 4580 return -1; 4581 if (i1 > i2) 4582 return 1; 4583 return 0; 4584} 4585 4586void CDefView::_MoveSelectionOnAutoArrange(POINT pt) 4587{ 4588 // get insertable index from position 4589 INT iPosition = _FindInsertableIndexFromPoint(pt); 4590 4591 // create identity mapping of indexes 4592 CSimpleArray<INT> array; 4593 INT nCount = m_ListView.GetItemCount(); 4594 for (INT i = 0; i < nCount; ++i) 4595 { 4596 array.Add(i); 4597 } 4598 4599 // re-ordering mapping 4600 INT iItem = -1; 4601 while ((iItem = m_ListView.GetNextItem(iItem, LVNI_SELECTED)) >= 0) 4602 { 4603 INT iFrom = iItem, iTo = iPosition; 4604 if (iFrom < iTo) 4605 --iTo; 4606 if (iFrom >= nCount) 4607 iFrom = nCount - 1; 4608 if (iTo >= nCount) 4609 iTo = nCount - 1; 4610 4611 // shift indexes by swapping (like a bucket relay) 4612 if (iFrom < iTo) 4613 { 4614 for (INT i = iFrom; i < iTo; ++i) 4615 { 4616 // swap array[i] and array[i + 1] 4617 INT tmp = array[i]; 4618 array[i] = array[i + 1]; 4619 array[i + 1] = tmp; 4620 } 4621 } 4622 else 4623 { 4624 for (INT i = iFrom; i > iTo; --i) 4625 { 4626 // swap array[i] and array[i - 1] 4627 INT tmp = array[i]; 4628 array[i] = array[i - 1]; 4629 array[i - 1] = tmp; 4630 } 4631 } 4632 } 4633 4634 // create mapping (ListView's lParam to index) from array 4635 CLParamIndexMap map; 4636 for (INT i = 0; i < nCount; ++i) 4637 { 4638 LPARAM lParam = m_ListView.GetItemData(array[i]); 4639 map.Add(lParam, i); 4640 } 4641 4642 // finally sort 4643 m_ListView.SortItems(SelectionMoveCompareFunc, &map); 4644} 4645 4646HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) 4647{ 4648 ImageList_DragLeave(m_hWnd); 4649 ImageList_EndDrag(); 4650 4651 if ((IsDropOnSource(NULL) == S_OK) && 4652 (*pdwEffect & DROPEFFECT_MOVE) && 4653 (m_grfKeyState & MK_LBUTTON)) 4654 { 4655 if (m_pCurDropTarget) 4656 { 4657 m_pCurDropTarget->DragLeave(); 4658 m_pCurDropTarget.Release(); 4659 } 4660 4661 POINT ptDrop = { pt.x, pt.y }; 4662 ::ScreenToClient(m_ListView, &ptDrop); 4663 ::ClientToListView(m_ListView, &ptDrop); 4664 m_ptLastMousePos = ptDrop; 4665 4666 m_ListView.SetRedraw(FALSE); 4667 if (m_ListView.GetStyle() & LVS_AUTOARRANGE) 4668 { 4669 _MoveSelectionOnAutoArrange(m_ptLastMousePos); 4670 } 4671 else 4672 { 4673 POINT ptItem; 4674 INT iItem = -1; 4675 while ((iItem = m_ListView.GetNextItem(iItem, LVNI_SELECTED)) >= 0) 4676 { 4677 if (m_ListView.GetItemPosition(iItem, &ptItem)) 4678 { 4679 ptItem.x += m_ptLastMousePos.x - m_ptFirstMousePos.x; 4680 ptItem.y += m_ptLastMousePos.y - m_ptFirstMousePos.y; 4681 m_ListView.SetItemPosition(iItem, &ptItem); 4682 } 4683 } 4684 } 4685 m_ListView.SetRedraw(TRUE); 4686 } 4687 else if (m_pCurDropTarget) 4688 { 4689 m_pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect); 4690 m_pCurDropTarget.Release(); 4691 } 4692 4693 m_pCurDataObject.Release(); 4694 m_iDragOverItem = 0; 4695 return S_OK; 4696} 4697 4698HRESULT WINAPI CDefView::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) 4699{ 4700 TRACE("(%p)\n", this); 4701 4702 if (fEscapePressed) 4703 return DRAGDROP_S_CANCEL; 4704 else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON)) 4705 return DRAGDROP_S_DROP; 4706 else 4707 return S_OK; 4708} 4709 4710HRESULT WINAPI CDefView::GiveFeedback(DWORD dwEffect) 4711{ 4712 TRACE("(%p)\n", this); 4713 4714 return DRAGDROP_S_USEDEFAULTCURSORS; 4715} 4716 4717HRESULT WINAPI CDefView::Draw(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hdcTargetDev, HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL lprcWBounds, BOOL (CALLBACK *pfnContinue)(ULONG_PTR dwContinue), ULONG_PTR dwContinue) 4718{ 4719 FIXME("Stub: this=%p\n", this); 4720 return E_NOTIMPL; 4721} 4722 4723HRESULT WINAPI CDefView::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet) 4724{ 4725 FIXME("Stub: this=%p\n", this); 4726 return E_NOTIMPL; 4727} 4728 4729HRESULT WINAPI CDefView::Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze) 4730{ 4731 FIXME("Stub: this=%p\n", this); 4732 return E_NOTIMPL; 4733} 4734 4735HRESULT WINAPI CDefView::Unfreeze(DWORD dwFreeze) 4736{ 4737 FIXME("Stub: this=%p\n", this); 4738 return E_NOTIMPL; 4739} 4740 4741HRESULT WINAPI CDefView::SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink) 4742{ 4743 FIXME("partial stub: %p 0x%08x 0x%08x %p\n", this, aspects, advf, pAdvSink); 4744 4745 // FIXME: we set the AdviseSink, but never use it to send any advice 4746 m_pAdvSink = pAdvSink; 4747 m_dwAspects = aspects; 4748 m_dwAdvf = advf; 4749 4750 return S_OK; 4751} 4752 4753HRESULT WINAPI CDefView::GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink) 4754{ 4755 TRACE("this=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n", this, pAspects, pAdvf, ppAdvSink); 4756 4757 if (ppAdvSink) 4758 { 4759 *ppAdvSink = m_pAdvSink; 4760 m_pAdvSink.p->AddRef(); 4761 } 4762 4763 if (pAspects) 4764 *pAspects = m_dwAspects; 4765 4766 if (pAdvf) 4767 *pAdvf = m_dwAdvf; 4768 4769 return S_OK; 4770} 4771 4772HRESULT STDMETHODCALLTYPE CDefView::QueryService(REFGUID guidService, REFIID riid, void **ppvObject) 4773{ 4774 if (IsEqualIID(guidService, SID_SFolderView)) 4775 return QueryInterface(riid, ppvObject); 4776 return m_pShellBrowser ? IUnknown_QueryService(m_pShellBrowser, guidService, riid, ppvObject) : E_NOINTERFACE; 4777} 4778 4779HRESULT CDefView::_MergeToolbar() 4780{ 4781 CComPtr<IExplorerToolbar> ptb; 4782 HRESULT hr = S_OK; 4783 4784 hr = IUnknown_QueryService(m_pShellBrowser, IID_IExplorerToolbar, IID_PPV_ARG(IExplorerToolbar, &ptb)); 4785 if (FAILED(hr)) 4786 return hr; 4787 4788 m_Category = CGID_DefViewFrame; 4789 4790 hr = ptb->SetCommandTarget(static_cast<IOleCommandTarget*>(this), &m_Category, 0); 4791 if (FAILED(hr)) 4792 return hr; 4793 4794 if (hr == S_FALSE) 4795 return S_OK; 4796 4797#if 0 4798 hr = ptb->AddButtons(&m_Category, buttonsCount, buttons); 4799 if (FAILED(hr)) 4800 return hr; 4801#endif 4802 4803 return S_OK; 4804} 4805 4806HRESULT CDefView::_DoFolderViewCB(UINT uMsg, WPARAM wParam, LPARAM lParam) 4807{ 4808 HRESULT hr = E_NOTIMPL; 4809 4810 if (m_pShellFolderViewCB) 4811 { 4812 hr = m_pShellFolderViewCB->MessageSFVCB(uMsg, wParam, lParam); 4813 } 4814 4815 return hr; 4816} 4817 4818HRESULT CDefView_CreateInstance(IShellFolder *pFolder, REFIID riid, LPVOID * ppvOut) 4819{ 4820 return ShellObjectCreatorInit<CDefView>(pFolder, riid, ppvOut); 4821} 4822 4823HRESULT WINAPI SHCreateShellFolderView(const SFV_CREATE *pcsfv, IShellView **ppsv) 4824{ 4825 CComPtr<IShellView> psv; 4826 HRESULT hRes; 4827 4828 if (!ppsv) 4829 return E_INVALIDARG; 4830 4831 *ppsv = NULL; 4832 4833 if (!pcsfv || pcsfv->cbSize != sizeof(*pcsfv)) 4834 return E_INVALIDARG; 4835 4836 TRACE("sf=%p outer=%p callback=%p\n", 4837 pcsfv->pshf, pcsfv->psvOuter, pcsfv->psfvcb); 4838 4839 hRes = CDefView_CreateInstance(pcsfv->pshf, IID_PPV_ARG(IShellView, &psv)); 4840 if (FAILED(hRes)) 4841 return hRes; 4842 4843 if (pcsfv->psfvcb) 4844 { 4845 CComPtr<IShellFolderView> sfv; 4846 if (SUCCEEDED(psv->QueryInterface(IID_PPV_ARG(IShellFolderView, &sfv)))) 4847 { 4848 sfv->SetCallback(pcsfv->psfvcb, NULL); 4849 } 4850 } 4851 4852 *ppsv = psv.Detach(); 4853 return hRes; 4854}