Reactos
at listview 4856 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 = LV_VIEW_ICON; break; 3633 case FVM_SMALLICON: dwStyle = LV_VIEW_SMALLICON; break; 3634 case FVM_LIST: dwStyle = LV_VIEW_LIST; break; 3635 case FVM_DETAILS: dwStyle = LV_VIEW_DETAILS; break; 3636 case FVM_TILE: dwStyle = LV_VIEW_TILE; break; 3637 default: 3638 FIXME("ViewMode %d not implemented\n", ViewMode); 3639 dwStyle = LV_VIEW_LIST; 3640 break; 3641 } 3642 3643 // m_ListView.ModifyStyle(LVS_TYPEMASK, dwStyle); 3644 m_ListView.SetListViewStyle(dwStyle); 3645 3646 /* This will not necessarily be the actual mode set above. 3647 This mimics the behavior of Windows XP. */ 3648 m_FolderSettings.ViewMode = ViewMode; 3649 CheckToolbar(); 3650 return S_OK; 3651} 3652 3653HRESULT STDMETHODCALLTYPE CDefView::GetFolder(REFIID riid, void **ppv) 3654{ 3655 if (m_pSFParent == NULL) 3656 return E_FAIL; 3657 3658 return m_pSFParent->QueryInterface(riid, ppv); 3659} 3660 3661HRESULT STDMETHODCALLTYPE CDefView::Item(int iItemIndex, PITEMID_CHILD *ppidl) 3662{ 3663 PCUITEMID_CHILD pidl = _PidlByItem(iItemIndex); 3664 if (pidl) 3665 { 3666 *ppidl = ILClone(pidl); 3667 return S_OK; 3668 } 3669 3670 *ppidl = 0; 3671 return E_INVALIDARG; 3672} 3673 3674HRESULT STDMETHODCALLTYPE CDefView::ItemCount(UINT uFlags, int *pcItems) 3675{ 3676 TRACE("(%p)->(%u %p)\n", this, uFlags, pcItems); 3677 if (uFlags != SVGIO_ALLVIEW && uFlags != SVGIO_SELECTION) 3678 FIXME("some flags unsupported, %x\n", uFlags & ~(SVGIO_ALLVIEW | SVGIO_SELECTION)); 3679 if ((uFlags & SVGIO_TYPE_MASK) == SVGIO_SELECTION) 3680 *pcItems = m_ListView.GetSelectedCount(); 3681 else 3682 *pcItems = m_ListView.GetItemCount(); 3683 return S_OK; 3684} 3685 3686HRESULT STDMETHODCALLTYPE CDefView::Items(UINT uFlags, REFIID riid, void **ppv) 3687{ 3688 return E_NOTIMPL; 3689} 3690 3691HRESULT STDMETHODCALLTYPE CDefView::GetSelectionMarkedItem(int *piItem) 3692{ 3693 TRACE("(%p)->(%p)\n", this, piItem); 3694 3695 *piItem = m_ListView.GetSelectionMark(); 3696 3697 return S_OK; 3698} 3699 3700HRESULT STDMETHODCALLTYPE CDefView::GetFocusedItem(int *piItem) 3701{ 3702 TRACE("(%p)->(%p)\n", this, piItem); 3703 3704 *piItem = m_ListView.GetNextItem(-1, LVNI_FOCUSED); 3705 3706 return S_OK; 3707} 3708 3709HRESULT STDMETHODCALLTYPE CDefView::GetItemPosition(PCUITEMID_CHILD pidl, POINT *ppt) 3710{ 3711 if (!m_ListView) 3712 { 3713 ERR("!m_ListView\n"); 3714 return E_FAIL; 3715 } 3716 3717 int lvIndex = LV_FindItemByPidl(pidl); 3718 if (lvIndex == -1 || ppt == NULL) 3719 return E_INVALIDARG; 3720 3721 m_ListView.GetItemPosition(lvIndex, ppt); 3722 return S_OK; 3723} 3724 3725HRESULT STDMETHODCALLTYPE CDefView::GetSpacing(POINT *ppt) 3726{ 3727 TRACE("(%p)->(%p)\n", this, ppt); 3728 3729 if (!m_ListView) 3730 { 3731 ERR("!m_ListView\n"); 3732 return S_FALSE; 3733 } 3734 3735 if (ppt) 3736 { 3737 SIZE spacing; 3738 m_ListView.GetItemSpacing(spacing); 3739 3740 ppt->x = spacing.cx; 3741 ppt->y = spacing.cy; 3742 } 3743 3744 return S_OK; 3745} 3746 3747HRESULT STDMETHODCALLTYPE CDefView::GetDefaultSpacing(POINT *ppt) 3748{ 3749 return E_NOTIMPL; 3750} 3751 3752HRESULT STDMETHODCALLTYPE CDefView::GetAutoArrange() 3753{ 3754 return ((m_ListView.GetStyle() & LVS_AUTOARRANGE) ? S_OK : S_FALSE); 3755} 3756 3757HRESULT CDefView::_GetSnapToGrid() 3758{ 3759 DWORD dwExStyle = (DWORD)m_ListView.SendMessage(LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); 3760 return ((dwExStyle & LVS_EX_SNAPTOGRID) ? S_OK : S_FALSE); 3761} 3762 3763HRESULT STDMETHODCALLTYPE CDefView::SelectItem(int iItem, DWORD dwFlags) 3764{ 3765 LVITEMW lvItem; 3766 3767 TRACE("(%p)->(%d, %x)\n", this, iItem, dwFlags); 3768 3769 lvItem.state = 0; 3770 lvItem.stateMask = LVIS_SELECTED; 3771 3772 if (dwFlags & SVSI_ENSUREVISIBLE) 3773 m_ListView.EnsureVisible(iItem, 0); 3774 3775 /* all items */ 3776 if (dwFlags & SVSI_DESELECTOTHERS) 3777 m_ListView.SetItemState(-1, 0, LVIS_SELECTED); 3778 3779 /* this item */ 3780 if (dwFlags & SVSI_SELECT) 3781 lvItem.state |= LVIS_SELECTED; 3782 3783 if (dwFlags & SVSI_FOCUSED) 3784 lvItem.stateMask |= LVIS_FOCUSED; 3785 3786 m_ListView.SetItemState(iItem, lvItem.state, lvItem.stateMask); 3787 3788 if ((dwFlags & SVSI_EDIT) == SVSI_EDIT) 3789 m_ListView.EditLabel(iItem); 3790 3791 return S_OK; 3792} 3793 3794HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItems(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, POINT *apt, DWORD dwFlags) 3795{ 3796 ASSERT(m_ListView); 3797 m_ListView.SetItemState(-1, 0, LVIS_SELECTED); // Reset the selection 3798 for (UINT i = 0 ; i < cidl; i++) 3799 { 3800 int lvIndex = LV_FindItemByPidl(apidl[i]); 3801 if (lvIndex != -1) 3802 SelectAndPositionItem(lvIndex, dwFlags, apt ? &apt[i] : NULL); 3803 } 3804 return S_OK; 3805} 3806 3807 3808// IShellView2 implementation 3809 3810HRESULT STDMETHODCALLTYPE CDefView::GetView(SHELLVIEWID *pVid, ULONG view_type) 3811{ 3812 if (view_type == SV2GV_DEFAULTVIEW) 3813 { 3814 *pVid = VID_Default; 3815 return S_OK; 3816 } 3817 if (view_type == SV2GV_CURRENTVIEW) 3818 view_type = m_FolderSettings.ViewMode; 3819 if ((int)view_type < 0) 3820 return E_UNEXPECTED; 3821 3822 view_type += FVM_FIRST; 3823 if (!IsSupportedFolderViewMode(view_type)) 3824 return E_INVALIDARG; 3825 *pVid = *FolderViewModeToShellViewId(view_type); 3826 return S_OK; 3827} 3828 3829HRESULT STDMETHODCALLTYPE CDefView::CreateViewWindow2(LPSV2CVW2_PARAMS view_params) 3830{ 3831 return CreateViewWindow3(view_params->psbOwner, view_params->psvPrev, 3832 SV3CVW3_DEFAULT, (FOLDERFLAGS)view_params->pfs->fFlags, (FOLDERFLAGS)view_params->pfs->fFlags, 3833 (FOLDERVIEWMODE)view_params->pfs->ViewMode, view_params->pvid, view_params->prcView, &view_params->hwndView); 3834} 3835 3836HRESULT 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) 3837{ 3838 OLEMENUGROUPWIDTHS omw = { { 0, 0, 0, 0, 0, 0 } }; 3839 const UINT SUPPORTED_SV3CVW3 = SV3CVW3_FORCEVIEWMODE | SV3CVW3_FORCEFOLDERFLAGS; 3840 const UINT IGNORE_FWF = FWF_OWNERDATA; // FIXME: Support this 3841 3842 *hwnd = NULL; 3843 3844 TRACE("(%p)->(shlview=%p shlbrs=%p rec=%p hwnd=%p vmode=%x flags=%x)\n", this, psvPrevious, psb, prcView, hwnd, mode, flags); 3845 if (prcView != NULL) 3846 TRACE("-- left=%i top=%i right=%i bottom=%i\n", prcView->left, prcView->top, prcView->right, prcView->bottom); 3847 3848 /* Validate the Shell Browser */ 3849 if (psb == NULL || m_hWnd) 3850 return E_UNEXPECTED; 3851 3852 if (view_flags & ~SUPPORTED_SV3CVW3) 3853 FIXME("unsupported view flags 0x%08x\n", view_flags & ~SUPPORTED_SV3CVW3); 3854 3855 /* Set up the member variables */ 3856 m_pShellBrowser = psb; 3857 m_FolderSettings.ViewMode = mode; 3858 m_FolderSettings.fFlags = (mask & flags) & ~IGNORE_FWF; 3859 3860 if (view_id) 3861 { 3862 FOLDERVIEWMODE temp = (FOLDERVIEWMODE)ShellViewIdToFolderViewMode(view_id); 3863 if (IsSupportedFolderViewMode(temp)) 3864 mode = temp; 3865 else if (*view_id == VID_Default) 3866 mode = FVM_AUTO; 3867 else 3868 FIXME("Ignoring unrecognized VID %s\n", debugstr_guid(view_id)); 3869 } 3870 if (mode == FVM_AUTO) 3871 m_FolderSettings.ViewMode = GetDefaultViewMode(); 3872 3873 if (!IsSupportedFolderViewMode(m_FolderSettings.ViewMode)) 3874 { 3875 ERR("Ignoring %s FVM %u\n", FolderViewModeToShellViewId(m_FolderSettings.ViewMode) 3876 ? "unsupported" : "invalid", m_FolderSettings.ViewMode); 3877 m_FolderSettings.ViewMode = FVM_ICON; 3878 } 3879 const UINT requestedViewMode = m_FolderSettings.ViewMode; 3880 3881 /* Get our parent window */ 3882 m_pShellBrowser->GetWindow(&m_hWndParent); 3883 _DoFolderViewCB(SFVM_HWNDMAIN, 0, (LPARAM)m_hWndParent); 3884 3885 /* Try to get the ICommDlgBrowserInterface, adds a reference !!! */ 3886 m_pCommDlgBrowser = NULL; 3887 if (SUCCEEDED(m_pShellBrowser->QueryInterface(IID_PPV_ARG(ICommDlgBrowser, &m_pCommDlgBrowser)))) 3888 { 3889 TRACE("-- CommDlgBrowser\n"); 3890 } 3891 3892 LoadViewState(); 3893 if (view_flags & SV3CVW3_FORCEVIEWMODE) 3894 m_FolderSettings.ViewMode = requestedViewMode; 3895 if (view_flags & SV3CVW3_FORCEFOLDERFLAGS) 3896 m_FolderSettings.fFlags = (mask & flags) & ~IGNORE_FWF; 3897 3898 RECT rcView = *prcView; 3899 Create(m_hWndParent, rcView, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP, 0, 0U); 3900 if (m_hWnd == NULL) 3901 return E_FAIL; 3902 3903 *hwnd = m_hWnd; 3904 3905 CheckToolbar(); 3906 3907 if (!*hwnd) 3908 return E_FAIL; 3909 3910 _DoFolderViewCB(SFVM_WINDOWCREATED, (WPARAM)m_hWnd, 0); 3911 3912 SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); 3913 UpdateWindow(); 3914 3915 if (!m_hMenu) 3916 { 3917 m_hMenu = CreateMenu(); 3918 m_pShellBrowser->InsertMenusSB(m_hMenu, &omw); 3919 TRACE("-- after fnInsertMenusSB\n"); 3920 } 3921 3922 _MergeToolbar(); 3923 3924 return S_OK; 3925} 3926 3927HRESULT STDMETHODCALLTYPE CDefView::HandleRename(LPCITEMIDLIST pidl) 3928{ 3929 if (!pidl) 3930 { 3931 int idx = m_ListView.GetNextItem(-1, LVNI_SELECTED | LVNI_FOCUSED); 3932 if (idx < 0) 3933 idx = m_ListView.GetNextItem(-1, LVNI_SELECTED); 3934 pidl = _PidlByItem(idx); 3935 } 3936 if (ILFindLastID(pidl) != pidl) 3937 return E_INVALIDARG; 3938 return SelectItem(pidl, SVSI_EDIT | SVSI_ENSUREVISIBLE | SVSI_FOCUSED | SVSI_SELECT); 3939} 3940 3941HRESULT CDefView::SelectAndPositionItem(int Idx, UINT fSVSI, POINT *ppt) 3942{ 3943 if (Idx == -1) 3944 return fSVSI == SVSI_DESELECTOTHERS ? SelectItem(-2, fSVSI) : E_INVALIDARG; 3945 if (ppt) 3946 m_ListView.SetItemPosition(Idx, ppt); 3947 return SelectItem(Idx, fSVSI); // After SetItemPosition for SVSI_ENSUREVISIBLE 3948} 3949 3950HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItem(LPCITEMIDLIST item, UINT flags, POINT *point) 3951{ 3952 if (!item) 3953 return SelectAndPositionItem(-1, flags, point); 3954 int idx = LV_FindItemByPidl(item); 3955 return idx != -1 ? SelectAndPositionItem(idx, flags, point) : S_FALSE; 3956} 3957 3958// IShellFolderView implementation 3959 3960HRESULT STDMETHODCALLTYPE CDefView::Rearrange(LPARAM sort) 3961{ 3962 _Sort(LOWORD(sort & SHCIDS_COLUMNMASK)); 3963 return S_OK; 3964} 3965 3966HRESULT STDMETHODCALLTYPE CDefView::GetArrangeParam(LPARAM *sort) 3967{ 3968 int col = m_sortInfo.ListColumn; 3969 *sort = col != LISTVIEW_SORT_INFO::UNSPECIFIEDCOLUMN ? col : 0; 3970 return col != LISTVIEW_SORT_INFO::UNSPECIFIEDCOLUMN ? S_OK : S_FALSE; 3971} 3972 3973HRESULT STDMETHODCALLTYPE CDefView::ArrangeGrid() 3974{ 3975 m_ListView.SetExtendedListViewStyle(LVS_EX_SNAPTOGRID, LVS_EX_SNAPTOGRID); 3976 return S_OK; 3977} 3978 3979HRESULT STDMETHODCALLTYPE CDefView::AutoArrange() 3980{ 3981 m_ListView.ModifyStyle(0, LVS_AUTOARRANGE); 3982 m_ListView.Arrange(LVA_DEFAULT); 3983 return S_OK; 3984} 3985 3986HRESULT STDMETHODCALLTYPE CDefView::AddObject(PITEMID_CHILD pidl, UINT *item) 3987{ 3988 TRACE("(%p)->(%p %p)\n", this, pidl, item); 3989 if (!m_ListView) 3990 { 3991 ERR("!m_ListView\n"); 3992 return E_FAIL; 3993 } 3994 *item = LV_AddItem(pidl); 3995 return (int)*item >= 0 ? S_OK : E_OUTOFMEMORY; 3996} 3997 3998HRESULT STDMETHODCALLTYPE CDefView::GetObject(PITEMID_CHILD *pidl, UINT item) 3999{ 4000 TRACE("(%p)->(%p %d)\n", this, pidl, item); 4001 return Item(item, pidl); 4002} 4003 4004HRESULT STDMETHODCALLTYPE CDefView::RemoveObject(PITEMID_CHILD pidl, UINT *item) 4005{ 4006 TRACE("(%p)->(%p %p)\n", this, pidl, item); 4007 4008 if (!m_ListView) 4009 { 4010 ERR("!m_ListView\n"); 4011 return E_FAIL; 4012 } 4013 4014 if (pidl) 4015 { 4016 *item = LV_FindItemByPidl(ILFindLastID(pidl)); 4017 m_ListView.DeleteItem(*item); 4018 } 4019 else 4020 { 4021 *item = 0; 4022 m_ListView.DeleteAllItems(); 4023 } 4024 4025 return S_OK; 4026} 4027 4028HRESULT STDMETHODCALLTYPE CDefView::GetObjectCount(UINT *count) 4029{ 4030 TRACE("(%p)->(%p)\n", this, count); 4031 *count = m_ListView.GetItemCount(); 4032 return S_OK; 4033} 4034 4035HRESULT STDMETHODCALLTYPE CDefView::SetObjectCount(UINT count, UINT flags) 4036{ 4037 FIXME("(%p)->(%d %x) stub\n", this, count, flags); 4038 return E_NOTIMPL; 4039} 4040 4041HRESULT STDMETHODCALLTYPE CDefView::UpdateObject(PITEMID_CHILD pidl_old, PITEMID_CHILD pidl_new, UINT *item) 4042{ 4043 FIXME("(%p)->(%p %p %p) stub\n", this, pidl_old, pidl_new, item); 4044 return E_NOTIMPL; 4045} 4046 4047HRESULT STDMETHODCALLTYPE CDefView::RefreshObject(PITEMID_CHILD pidl, UINT *item) 4048{ 4049 FIXME("(%p)->(%p %p) stub\n", this, pidl, item); 4050 return E_NOTIMPL; 4051} 4052 4053HRESULT STDMETHODCALLTYPE CDefView::SetRedraw(BOOL redraw) 4054{ 4055 TRACE("(%p)->(%d)\n", this, redraw); 4056 if (m_ListView) 4057 m_ListView.SetRedraw(redraw); 4058 return S_OK; 4059} 4060 4061HRESULT STDMETHODCALLTYPE CDefView::GetSelectedCount(UINT *count) 4062{ 4063 *count = m_ListView.GetSelectedCount(); 4064 return S_OK; 4065} 4066 4067HRESULT STDMETHODCALLTYPE CDefView::GetSelectedObjects(PCUITEMID_CHILD **pidl, UINT *items) 4068{ 4069 TRACE("(%p)->(%p %p)\n", this, pidl, items); 4070 4071 *items = GetSelections(); 4072 4073 if (*items) 4074 { 4075 *pidl = static_cast<PCUITEMID_CHILD *>(LocalAlloc(0, *items * sizeof(PCUITEMID_CHILD))); 4076 if (!*pidl) 4077 { 4078 return E_OUTOFMEMORY; 4079 } 4080 4081 // It's documented that caller shouldn't free the PIDLs, only the array itself 4082 memcpy(*pidl, m_apidl, *items * sizeof(PCUITEMID_CHILD)); 4083 } 4084 4085 return S_OK; 4086} 4087 4088HRESULT STDMETHODCALLTYPE CDefView::IsDropOnSource(IDropTarget *drop_target) 4089{ 4090 if ((m_iDragOverItem == -1 || m_pCurDropTarget == NULL) && 4091 (m_pSourceDataObject.p)) 4092 { 4093 return S_OK; 4094 } 4095 4096 return S_FALSE; 4097} 4098 4099HRESULT STDMETHODCALLTYPE CDefView::GetDragPoint(POINT *pt) 4100{ 4101 if (!pt) 4102 return E_INVALIDARG; 4103 4104 *pt = m_ptFirstMousePos; 4105 return S_OK; 4106} 4107 4108HRESULT STDMETHODCALLTYPE CDefView::GetDropPoint(POINT *pt) 4109{ 4110 FIXME("(%p)->(%p) stub\n", this, pt); 4111 return E_NOTIMPL; 4112} 4113 4114HRESULT STDMETHODCALLTYPE CDefView::MoveIcons(IDataObject *obj) 4115{ 4116 TRACE("(%p)->(%p)\n", this, obj); 4117 return E_NOTIMPL; 4118} 4119 4120HRESULT STDMETHODCALLTYPE CDefView::SetItemPos(PCUITEMID_CHILD pidl, POINT *pt) 4121{ 4122 FIXME("(%p)->(%p %p) stub\n", this, pidl, pt); 4123 return E_NOTIMPL; 4124} 4125 4126HRESULT STDMETHODCALLTYPE CDefView::IsBkDropTarget(IDropTarget *drop_target) 4127{ 4128 FIXME("(%p)->(%p) stub\n", this, drop_target); 4129 return E_NOTIMPL; 4130} 4131 4132HRESULT STDMETHODCALLTYPE CDefView::SetClipboard(BOOL move) 4133{ 4134 if (!move) 4135 return S_OK; 4136 4137 UINT CutCount = 0; 4138 for (int i = -1; (i = m_ListView.GetNextItem(i, LVNI_SELECTED)) != -1;) 4139 { 4140 if (!CutCount++) 4141 { 4142 // Turn off the LVIS_CUT LVM_SETCALLBACKMASK optimization 4143 m_ListView.SendMessageW(LVM_SETCALLBACKMASK, m_ListView.SendMessageW(LVM_GETCALLBACKMASK, 0, 0) & ~LVIS_CUT, 0); 4144 RefreshGhostedState(); 4145 } 4146 m_ListView.SetItemState(i, LVIS_CUT, LVIS_CUT); 4147 } 4148 if (CutCount) 4149 { 4150 m_ClipboardChain.Hook(m_hWnd); 4151 m_HasCutItems = true; 4152 } 4153 return S_OK; 4154} 4155 4156HRESULT STDMETHODCALLTYPE CDefView::SetPoints(IDataObject *obj) 4157{ 4158 FIXME("(%p)->(%p) stub\n", this, obj); 4159 return E_NOTIMPL; 4160} 4161 4162HRESULT STDMETHODCALLTYPE CDefView::GetItemSpacing(ITEMSPACING *spacing) 4163{ 4164 FIXME("(%p)->(%p) stub\n", this, spacing); 4165 return E_NOTIMPL; 4166} 4167 4168HRESULT STDMETHODCALLTYPE CDefView::SetCallback(IShellFolderViewCB *new_cb, IShellFolderViewCB **old_cb) 4169{ 4170 if (old_cb) 4171 *old_cb = m_pShellFolderViewCB.Detach(); 4172 4173 m_pShellFolderViewCB = new_cb; 4174 m_pFolderFilter = NULL; 4175 if (new_cb) 4176 new_cb->QueryInterface(IID_PPV_ARG(IFolderFilter, &m_pFolderFilter)); 4177 return S_OK; 4178} 4179 4180HRESULT STDMETHODCALLTYPE CDefView::Select(UINT flags) 4181{ 4182 FIXME("(%p)->(%d) stub\n", this, flags); 4183 return E_NOTIMPL; 4184} 4185 4186HRESULT STDMETHODCALLTYPE CDefView::QuerySupport(UINT *support) 4187{ 4188 TRACE("(%p)->(%p)\n", this, support); 4189 return S_OK; 4190} 4191 4192HRESULT STDMETHODCALLTYPE CDefView::SetAutomationObject(IDispatch *disp) 4193{ 4194 FIXME("(%p)->(%p) stub\n", this, disp); 4195 return E_NOTIMPL; 4196} 4197 4198HRESULT WINAPI CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText) 4199{ 4200 FIXME("(%p)->(%p(%s) 0x%08x %p %p\n", 4201 this, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText); 4202 4203 if (!prgCmds) 4204 return E_INVALIDARG; 4205 4206 for (UINT i = 0; i < cCmds; i++) 4207 { 4208 FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID); 4209 prgCmds[i].cmdf = 0; 4210 } 4211 4212 return OLECMDERR_E_UNKNOWNGROUP; 4213} 4214 4215/// 4216// ISVOleCmdTarget_Exec(IOleCommandTarget) 4217// 4218// nCmdID is the OLECMDID_* enumeration 4219HRESULT WINAPI CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut) 4220{ 4221 FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n", 4222 this, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut); 4223 4224 if (!pguidCmdGroup) 4225 return OLECMDERR_E_UNKNOWNGROUP; 4226 4227 if (IsEqualCLSID(*pguidCmdGroup, m_Category)) 4228 { 4229 if (nCmdID == FCIDM_SHVIEW_AUTOARRANGE) 4230 { 4231 if (V_VT(pvaIn) != VT_INT_PTR) 4232 return OLECMDERR_E_NOTSUPPORTED; 4233 4234 TPMPARAMS params; 4235 params.cbSize = sizeof(params); 4236 params.rcExclude = *(RECT*) V_INTREF(pvaIn); 4237 4238 if (m_hMenuViewModes) 4239 { 4240 // Duplicate all but the last two items of the view modes menu 4241 HMENU hmenuViewPopup = CreatePopupMenu(); 4242 Shell_MergeMenus(hmenuViewPopup, m_hMenuViewModes, 0, 0, 0xFFFF, 0); 4243 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION); 4244 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION); 4245 CheckViewMode(hmenuViewPopup); 4246 TrackPopupMenuEx(hmenuViewPopup, TPM_LEFTALIGN | TPM_TOPALIGN, params.rcExclude.left, params.rcExclude.bottom, m_hWndParent, &params); 4247 ::DestroyMenu(hmenuViewPopup); 4248 } 4249 4250 // pvaOut is VT_I4 with value 0x403 (cmd id of the new mode maybe?) 4251 V_VT(pvaOut) = VT_I4; 4252 V_I4(pvaOut) = 0x403; 4253 } 4254 } 4255 4256 if (IsEqualIID(*pguidCmdGroup, CGID_Explorer) && 4257 (nCmdID == 0x29) && 4258 (nCmdexecopt == 4) && pvaOut) 4259 return S_OK; 4260 4261 if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView) && 4262 (nCmdID == 9) && 4263 (nCmdexecopt == 0)) 4264 return 1; 4265 4266 if (IsEqualIID(*pguidCmdGroup, CGID_DefView)) 4267 { 4268 CComPtr<IStream> pStream; 4269 WCHAR SubKey[MAX_PATH]; 4270 switch (nCmdID) 4271 { 4272 case DVCMDID_SET_DEFAULTFOLDER_SETTINGS: 4273 SHDeleteKey(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\ShellNoRoam\\Bags"); 4274 if (SUCCEEDED(GetDefaultViewStream(STGM_WRITE, &pStream))) 4275 SaveViewState(pStream); 4276 return S_OK; 4277 case DVCMDID_RESET_DEFAULTFOLDER_SETTINGS: 4278 PathCombineW(SubKey, REGSTR_PATH_EXPLORER, L"Streams\\Default"); 4279 SHDeleteKey(HKEY_CURRENT_USER, SubKey); 4280 SHDeleteKey(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\ShellNoRoam\\Bags"); 4281 m_FolderSettings.fFlags |= FWF_NOBROWSERVIEWSTATE; // Don't let this folder save itself 4282 return S_OK; 4283 } 4284 } 4285 4286 return OLECMDERR_E_UNKNOWNGROUP; 4287} 4288 4289/********************************************************** 4290 * ISVDropTarget implementation 4291 */ 4292 4293/****************************************************************************** 4294 * drag_notify_subitem [Internal] 4295 * 4296 * Figure out the shellfolder object, which is currently under the mouse cursor 4297 * and notify it via the IDropTarget interface. 4298 */ 4299 4300#define SCROLLAREAWIDTH 20 4301 4302HRESULT CDefView::drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) 4303{ 4304 LONG lResult; 4305 HRESULT hr; 4306 RECT clientRect; 4307 4308 /* The key state on drop doesn't have MK_LBUTTON or MK_RBUTTON because it 4309 reflects the key state after the user released the button, so we need 4310 to remember the last key state when the button was pressed */ 4311 m_grfKeyState = grfKeyState; 4312 4313 // Map from global to client coordinates and query the index of the 4314 // listview-item, which is currently under the mouse cursor. 4315 LVHITTESTINFO htinfo = {{pt.x, pt.y}, LVHT_ONITEM}; 4316 ScreenToClient(&htinfo.pt); 4317 lResult = m_ListView.HitTest(&htinfo); 4318 4319 /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */ 4320 ::GetClientRect(m_ListView, &clientRect); 4321 if (htinfo.pt.x == m_ptLastMousePos.x && htinfo.pt.y == m_ptLastMousePos.y && 4322 (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH || 4323 htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH)) 4324 { 4325 m_cScrollDelay = (m_cScrollDelay + 1) % 5; // DragOver is called every 50 ms 4326 if (m_cScrollDelay == 0) 4327 { 4328 /* Mouse did hover another 250 ms over the scroll-area */ 4329 if (htinfo.pt.x < SCROLLAREAWIDTH) 4330 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEUP, 0); 4331 4332 if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH) 4333 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEDOWN, 0); 4334 4335 if (htinfo.pt.y < SCROLLAREAWIDTH) 4336 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEUP, 0); 4337 4338 if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH) 4339 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEDOWN, 0); 4340 } 4341 } 4342 else 4343 { 4344 m_cScrollDelay = 0; // Reset, if cursor is not over the listview's scroll-area 4345 } 4346 4347 m_ptLastMousePos = htinfo.pt; 4348 ::ClientToListView(m_ListView, &m_ptLastMousePos); 4349 4350 /* We need to check if we drag the selection over itself */ 4351 if (lResult != -1 && m_pSourceDataObject.p != NULL) 4352 { 4353 PCUITEMID_CHILD pidl = _PidlByItem(lResult); 4354 4355 for (UINT i = 0; i < m_cidl; i++) 4356 { 4357 if (pidl == m_apidl[i]) 4358 { 4359 /* The item that is being draged is hovering itself. */ 4360 lResult = -1; 4361 break; 4362 } 4363 } 4364 } 4365 4366 // If we are still over the previous sub-item, notify it via DragOver and return 4367 if (m_pCurDropTarget && lResult == m_iDragOverItem) 4368 return m_pCurDropTarget->DragOver(grfKeyState, pt, pdwEffect); 4369 4370 // We've left the previous sub-item, notify it via DragLeave and release it 4371 if (m_pCurDropTarget) 4372 { 4373 PCUITEMID_CHILD pidl = _PidlByItem(m_iDragOverItem); 4374 if (pidl) 4375 SelectItem(pidl, 0); 4376 4377 m_pCurDropTarget->DragLeave(); 4378 m_pCurDropTarget.Release(); 4379 } 4380 4381 m_iDragOverItem = lResult; 4382 4383 if (lResult == -1) 4384 { 4385 // We are not above one of the listview's subitems. Bind to the 4386 // parent folder's DropTarget interface. 4387 hr = m_pSFParent->CreateViewObject(NULL, IID_PPV_ARG(IDropTarget,&m_pCurDropTarget)); 4388 } 4389 else 4390 { 4391 // Query the relative PIDL of the shellfolder object represented 4392 // by the currently dragged over listview-item ... 4393 PCUITEMID_CHILD pidl = _PidlByItem(lResult); 4394 4395 // ... and bind m_pCurDropTarget to the IDropTarget interface of an UIObject of this object 4396 hr = m_pSFParent->GetUIObjectOf(m_ListView, 1, &pidl, IID_NULL_PPV_ARG(IDropTarget, &m_pCurDropTarget)); 4397 } 4398 4399 IUnknown_SetSite(m_pCurDropTarget, (IShellView *)this); 4400 4401 // If anything failed, m_pCurDropTarget should be NULL now, which ought to be a save state 4402 if (FAILED(hr)) 4403 { 4404 *pdwEffect = DROPEFFECT_NONE; 4405 return hr; 4406 } 4407 4408 if (m_iDragOverItem != -1) 4409 { 4410 SelectItem(m_iDragOverItem, SVSI_SELECT); 4411 } 4412 4413 // Notify the item just entered via DragEnter 4414 return m_pCurDropTarget->DragEnter(m_pCurDataObject, grfKeyState, pt, pdwEffect); 4415} 4416 4417HRESULT WINAPI CDefView::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) 4418{ 4419 if (*pdwEffect == DROPEFFECT_NONE) 4420 return S_OK; 4421 4422 /* Get a hold on the data object for later calls to DragEnter on the sub-folders */ 4423 m_pCurDataObject = pDataObject; 4424 4425 HRESULT hr = drag_notify_subitem(grfKeyState, pt, pdwEffect); 4426 if (SUCCEEDED(hr)) 4427 { 4428 POINT ptClient = {pt.x, pt.y}; 4429 ScreenToClient(&ptClient); 4430 ImageList_DragEnter(m_hWnd, ptClient.x, ptClient.y); 4431 } 4432 4433 return hr; 4434} 4435 4436HRESULT WINAPI CDefView::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) 4437{ 4438 POINT ptClient = {pt.x, pt.y}; 4439 ScreenToClient(&ptClient); 4440 ImageList_DragMove(ptClient.x, ptClient.y); 4441 return drag_notify_subitem(grfKeyState, pt, pdwEffect); 4442} 4443 4444HRESULT WINAPI CDefView::DragLeave() 4445{ 4446 ImageList_DragLeave(m_hWnd); 4447 4448 if (m_pCurDropTarget) 4449 { 4450 m_pCurDropTarget->DragLeave(); 4451 m_pCurDropTarget.Release(); 4452 } 4453 4454 if (m_pCurDataObject != NULL) 4455 { 4456 m_pCurDataObject.Release(); 4457 } 4458 4459 m_iDragOverItem = 0; 4460 4461 return S_OK; 4462} 4463 4464INT CDefView::_FindInsertableIndexFromPoint(POINT pt) 4465{ 4466 RECT rcBound; 4467 INT i, nCount = m_ListView.GetItemCount(); 4468 DWORD dwSpacing; 4469 INT dx, dy; 4470 BOOL bSmall = ((m_ListView.GetStyle() & LVS_TYPEMASK) != LVS_ICON); 4471 4472 // FIXME: LVM_GETORIGIN is broken. See CORE-17266 4473 pt.x += m_ListView.GetScrollPos(SB_HORZ); 4474 pt.y += m_ListView.GetScrollPos(SB_VERT); 4475 4476 if (m_ListView.GetStyle() & LVS_ALIGNLEFT) 4477 { 4478 // vertically 4479 for (i = 0; i < nCount; ++i) 4480 { 4481 dwSpacing = ListView_GetItemSpacing(m_ListView, bSmall); 4482 dx = LOWORD(dwSpacing); 4483 dy = HIWORD(dwSpacing); 4484 ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS); 4485 rcBound.right = rcBound.left + dx; 4486 rcBound.bottom = rcBound.top + dy; 4487 if (pt.x < rcBound.right && pt.y < (rcBound.top + rcBound.bottom) / 2) 4488 { 4489 return i; 4490 } 4491 } 4492 for (i = nCount - 1; i >= 0; --i) 4493 { 4494 ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS); 4495 if (rcBound.left < pt.x && rcBound.top < pt.y) 4496 { 4497 return i + 1; 4498 } 4499 } 4500 } 4501 else 4502 { 4503 // horizontally 4504 for (i = 0; i < nCount; ++i) 4505 { 4506 dwSpacing = ListView_GetItemSpacing(m_ListView, bSmall); 4507 dx = LOWORD(dwSpacing); 4508 dy = HIWORD(dwSpacing); 4509 ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS); 4510 rcBound.right = rcBound.left + dx; 4511 rcBound.bottom = rcBound.top + dy; 4512 if (pt.y < rcBound.bottom && pt.x < rcBound.left) 4513 { 4514 return i; 4515 } 4516 if (pt.y < rcBound.bottom && pt.x < rcBound.right) 4517 { 4518 return i + 1; 4519 } 4520 } 4521 for (i = nCount - 1; i >= 0; --i) 4522 { 4523 ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS); 4524 if (rcBound.left < pt.x && rcBound.top < pt.y) 4525 { 4526 return i + 1; 4527 } 4528 } 4529 } 4530 4531 return nCount; 4532} 4533 4534void CDefView::_HandleStatusBarResize(int nWidth) 4535{ 4536 LRESULT lResult; 4537 4538 if (!m_isFullStatusBar) 4539 { 4540 int nPartArray[] = {-1}; 4541 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, _countof(nPartArray), (LPARAM)nPartArray, &lResult); 4542 return; 4543 } 4544 4545 int nFileSizePartLength = 125; 4546 const int nLocationPartLength = 150; 4547 const int nRightPartsLength = nFileSizePartLength + nLocationPartLength; 4548 int nObjectsPartLength = nWidth - nRightPartsLength; 4549 4550 // If the window is small enough just divide each part into thirds 4551 // to match the behavior of Windows Server 2003 4552 if (nObjectsPartLength <= nLocationPartLength) 4553 nObjectsPartLength = nFileSizePartLength = nWidth / 3; 4554 4555 int nPartArray[] = {nObjectsPartLength, nObjectsPartLength + nFileSizePartLength, -1}; 4556 4557 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, _countof(nPartArray), (LPARAM)nPartArray, &lResult); 4558} 4559 4560void CDefView::_ForceStatusBarResize() 4561{ 4562 // Get the handle for the status bar 4563 HWND fStatusBar; 4564 m_pShellBrowser->GetControlWindow(FCW_STATUS, &fStatusBar); 4565 4566 // Get the size of our status bar 4567 RECT statusBarSize; 4568 ::GetWindowRect(fStatusBar, &statusBarSize); 4569 4570 // Resize the status bar 4571 _HandleStatusBarResize(statusBarSize.right - statusBarSize.left); 4572} 4573 4574typedef CSimpleMap<LPARAM, INT> CLParamIndexMap; 4575 4576static INT CALLBACK 4577SelectionMoveCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) 4578{ 4579 CLParamIndexMap *pmap = (CLParamIndexMap *)lParamSort; 4580 INT i1 = pmap->Lookup(lParam1), i2 = pmap->Lookup(lParam2); 4581 if (i1 < i2) 4582 return -1; 4583 if (i1 > i2) 4584 return 1; 4585 return 0; 4586} 4587 4588void CDefView::_MoveSelectionOnAutoArrange(POINT pt) 4589{ 4590 // get insertable index from position 4591 INT iPosition = _FindInsertableIndexFromPoint(pt); 4592 4593 // create identity mapping of indexes 4594 CSimpleArray<INT> array; 4595 INT nCount = m_ListView.GetItemCount(); 4596 for (INT i = 0; i < nCount; ++i) 4597 { 4598 array.Add(i); 4599 } 4600 4601 // re-ordering mapping 4602 INT iItem = -1; 4603 while ((iItem = m_ListView.GetNextItem(iItem, LVNI_SELECTED)) >= 0) 4604 { 4605 INT iFrom = iItem, iTo = iPosition; 4606 if (iFrom < iTo) 4607 --iTo; 4608 if (iFrom >= nCount) 4609 iFrom = nCount - 1; 4610 if (iTo >= nCount) 4611 iTo = nCount - 1; 4612 4613 // shift indexes by swapping (like a bucket relay) 4614 if (iFrom < iTo) 4615 { 4616 for (INT i = iFrom; i < iTo; ++i) 4617 { 4618 // swap array[i] and array[i + 1] 4619 INT tmp = array[i]; 4620 array[i] = array[i + 1]; 4621 array[i + 1] = tmp; 4622 } 4623 } 4624 else 4625 { 4626 for (INT i = iFrom; i > iTo; --i) 4627 { 4628 // swap array[i] and array[i - 1] 4629 INT tmp = array[i]; 4630 array[i] = array[i - 1]; 4631 array[i - 1] = tmp; 4632 } 4633 } 4634 } 4635 4636 // create mapping (ListView's lParam to index) from array 4637 CLParamIndexMap map; 4638 for (INT i = 0; i < nCount; ++i) 4639 { 4640 LPARAM lParam = m_ListView.GetItemData(array[i]); 4641 map.Add(lParam, i); 4642 } 4643 4644 // finally sort 4645 m_ListView.SortItems(SelectionMoveCompareFunc, &map); 4646} 4647 4648HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) 4649{ 4650 ImageList_DragLeave(m_hWnd); 4651 ImageList_EndDrag(); 4652 4653 if ((IsDropOnSource(NULL) == S_OK) && 4654 (*pdwEffect & DROPEFFECT_MOVE) && 4655 (m_grfKeyState & MK_LBUTTON)) 4656 { 4657 if (m_pCurDropTarget) 4658 { 4659 m_pCurDropTarget->DragLeave(); 4660 m_pCurDropTarget.Release(); 4661 } 4662 4663 POINT ptDrop = { pt.x, pt.y }; 4664 ::ScreenToClient(m_ListView, &ptDrop); 4665 ::ClientToListView(m_ListView, &ptDrop); 4666 m_ptLastMousePos = ptDrop; 4667 4668 m_ListView.SetRedraw(FALSE); 4669 if (m_ListView.GetStyle() & LVS_AUTOARRANGE) 4670 { 4671 _MoveSelectionOnAutoArrange(m_ptLastMousePos); 4672 } 4673 else 4674 { 4675 POINT ptItem; 4676 INT iItem = -1; 4677 while ((iItem = m_ListView.GetNextItem(iItem, LVNI_SELECTED)) >= 0) 4678 { 4679 if (m_ListView.GetItemPosition(iItem, &ptItem)) 4680 { 4681 ptItem.x += m_ptLastMousePos.x - m_ptFirstMousePos.x; 4682 ptItem.y += m_ptLastMousePos.y - m_ptFirstMousePos.y; 4683 m_ListView.SetItemPosition(iItem, &ptItem); 4684 } 4685 } 4686 } 4687 m_ListView.SetRedraw(TRUE); 4688 } 4689 else if (m_pCurDropTarget) 4690 { 4691 m_pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect); 4692 m_pCurDropTarget.Release(); 4693 } 4694 4695 m_pCurDataObject.Release(); 4696 m_iDragOverItem = 0; 4697 return S_OK; 4698} 4699 4700HRESULT WINAPI CDefView::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) 4701{ 4702 TRACE("(%p)\n", this); 4703 4704 if (fEscapePressed) 4705 return DRAGDROP_S_CANCEL; 4706 else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON)) 4707 return DRAGDROP_S_DROP; 4708 else 4709 return S_OK; 4710} 4711 4712HRESULT WINAPI CDefView::GiveFeedback(DWORD dwEffect) 4713{ 4714 TRACE("(%p)\n", this); 4715 4716 return DRAGDROP_S_USEDEFAULTCURSORS; 4717} 4718 4719HRESULT 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) 4720{ 4721 FIXME("Stub: this=%p\n", this); 4722 return E_NOTIMPL; 4723} 4724 4725HRESULT WINAPI CDefView::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet) 4726{ 4727 FIXME("Stub: this=%p\n", this); 4728 return E_NOTIMPL; 4729} 4730 4731HRESULT WINAPI CDefView::Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze) 4732{ 4733 FIXME("Stub: this=%p\n", this); 4734 return E_NOTIMPL; 4735} 4736 4737HRESULT WINAPI CDefView::Unfreeze(DWORD dwFreeze) 4738{ 4739 FIXME("Stub: this=%p\n", this); 4740 return E_NOTIMPL; 4741} 4742 4743HRESULT WINAPI CDefView::SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink) 4744{ 4745 FIXME("partial stub: %p 0x%08x 0x%08x %p\n", this, aspects, advf, pAdvSink); 4746 4747 // FIXME: we set the AdviseSink, but never use it to send any advice 4748 m_pAdvSink = pAdvSink; 4749 m_dwAspects = aspects; 4750 m_dwAdvf = advf; 4751 4752 return S_OK; 4753} 4754 4755HRESULT WINAPI CDefView::GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink) 4756{ 4757 TRACE("this=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n", this, pAspects, pAdvf, ppAdvSink); 4758 4759 if (ppAdvSink) 4760 { 4761 *ppAdvSink = m_pAdvSink; 4762 m_pAdvSink.p->AddRef(); 4763 } 4764 4765 if (pAspects) 4766 *pAspects = m_dwAspects; 4767 4768 if (pAdvf) 4769 *pAdvf = m_dwAdvf; 4770 4771 return S_OK; 4772} 4773 4774HRESULT STDMETHODCALLTYPE CDefView::QueryService(REFGUID guidService, REFIID riid, void **ppvObject) 4775{ 4776 if (IsEqualIID(guidService, SID_SFolderView)) 4777 return QueryInterface(riid, ppvObject); 4778 return m_pShellBrowser ? IUnknown_QueryService(m_pShellBrowser, guidService, riid, ppvObject) : E_NOINTERFACE; 4779} 4780 4781HRESULT CDefView::_MergeToolbar() 4782{ 4783 CComPtr<IExplorerToolbar> ptb; 4784 HRESULT hr = S_OK; 4785 4786 hr = IUnknown_QueryService(m_pShellBrowser, IID_IExplorerToolbar, IID_PPV_ARG(IExplorerToolbar, &ptb)); 4787 if (FAILED(hr)) 4788 return hr; 4789 4790 m_Category = CGID_DefViewFrame; 4791 4792 hr = ptb->SetCommandTarget(static_cast<IOleCommandTarget*>(this), &m_Category, 0); 4793 if (FAILED(hr)) 4794 return hr; 4795 4796 if (hr == S_FALSE) 4797 return S_OK; 4798 4799#if 0 4800 hr = ptb->AddButtons(&m_Category, buttonsCount, buttons); 4801 if (FAILED(hr)) 4802 return hr; 4803#endif 4804 4805 return S_OK; 4806} 4807 4808HRESULT CDefView::_DoFolderViewCB(UINT uMsg, WPARAM wParam, LPARAM lParam) 4809{ 4810 HRESULT hr = E_NOTIMPL; 4811 4812 if (m_pShellFolderViewCB) 4813 { 4814 hr = m_pShellFolderViewCB->MessageSFVCB(uMsg, wParam, lParam); 4815 } 4816 4817 return hr; 4818} 4819 4820HRESULT CDefView_CreateInstance(IShellFolder *pFolder, REFIID riid, LPVOID * ppvOut) 4821{ 4822 return ShellObjectCreatorInit<CDefView>(pFolder, riid, ppvOut); 4823} 4824 4825HRESULT WINAPI SHCreateShellFolderView(const SFV_CREATE *pcsfv, IShellView **ppsv) 4826{ 4827 CComPtr<IShellView> psv; 4828 HRESULT hRes; 4829 4830 if (!ppsv) 4831 return E_INVALIDARG; 4832 4833 *ppsv = NULL; 4834 4835 if (!pcsfv || pcsfv->cbSize != sizeof(*pcsfv)) 4836 return E_INVALIDARG; 4837 4838 TRACE("sf=%p outer=%p callback=%p\n", 4839 pcsfv->pshf, pcsfv->psvOuter, pcsfv->psfvcb); 4840 4841 hRes = CDefView_CreateInstance(pcsfv->pshf, IID_PPV_ARG(IShellView, &psv)); 4842 if (FAILED(hRes)) 4843 return hRes; 4844 4845 if (pcsfv->psfvcb) 4846 { 4847 CComPtr<IShellFolderView> sfv; 4848 if (SUCCEEDED(psv->QueryInterface(IID_PPV_ARG(IShellFolderView, &sfv)))) 4849 { 4850 sfv->SetCallback(pcsfv->psfvcb, NULL); 4851 } 4852 } 4853 4854 *ppsv = psv.Detach(); 4855 return hRes; 4856}