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