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 1811 Shell_MergeMenus(hFileMenu, hmenu, 0, 0, 0xFFFF, MM_ADDSEPARATOR | MM_SUBMENUSHAVEIDS); 1812 1813 ::DestroyMenu(hmenu); 1814 1815 return S_OK; 1816 } 1817 1818 HRESULT CDefView::FillEditMenu() 1819 { 1820 HMENU hEditMenu = GetSubmenuByID(m_hMenu, FCIDM_MENU_EDIT); 1821 if (!hEditMenu) 1822 return E_FAIL; 1823 1824 HMENU hmenuContents = ::LoadMenuW(shell32_hInstance, L"MENU_003"); 1825 if (!hmenuContents) 1826 return E_FAIL; 1827 1828 Shell_MergeMenus(hEditMenu, hmenuContents, 0, 0, 0xFFFF, 0); 1829 1830 ::DestroyMenu(hmenuContents); 1831 1832 return S_OK; 1833 } 1834 1835 HRESULT CDefView::FillViewMenu() 1836 { 1837 HMENU hViewMenu = GetSubmenuByID(m_hMenu, FCIDM_MENU_VIEW); 1838 if (!hViewMenu) 1839 return E_FAIL; 1840 1841 m_hMenuViewModes = ::LoadMenuW(shell32_hInstance, L"MENU_001"); 1842 if (!m_hMenuViewModes) 1843 return E_FAIL; 1844 1845 UINT i = SHMenuIndexFromID(hViewMenu, FCIDM_MENU_VIEW_SEP_OPTIONS); 1846 Shell_MergeMenus(hViewMenu, m_hMenuViewModes, i, 0, 0xFFFF, MM_ADDSEPARATOR | MM_DONTREMOVESEPS | MM_SUBMENUSHAVEIDS); 1847 1848 return S_OK; 1849 } 1850 1851 HRESULT CDefView::FillArrangeAsMenu(HMENU hmenuArrange) 1852 { 1853 bool forceMerge = false; 1854 UINT currentSortId = DVIDM_ARRANGESORT_FIRST + m_sortInfo.ListColumn; 1855 1856 // Make sure the column we currently sort by is in the menu 1857 RemoveMenu(m_hMenuArrangeModes, DVIDM_ARRANGESORT_LAST, MF_BYCOMMAND); 1858 if (m_sortInfo.ListColumn >= DEFVIEW_ARRANGESORT_MAXENUM) 1859 { 1860 C_ASSERT(DEFVIEW_ARRANGESORT_MAXENUM < DEFVIEW_ARRANGESORT_MAX); 1861 C_ASSERT(DVIDM_ARRANGESORT_FIRST + DEFVIEW_ARRANGESORT_MAXENUM == DVIDM_ARRANGESORT_LAST); 1862 WCHAR buf[MAX_PATH]; 1863 LVCOLUMN lvc; 1864 lvc.mask = LVCF_TEXT; 1865 lvc.pszText = buf; 1866 lvc.cchTextMax = _countof(buf); 1867 currentSortId = DVIDM_ARRANGESORT_LAST; 1868 forceMerge = true; 1869 ListView_GetColumn(m_ListView.m_hWnd, m_sortInfo.ListColumn, &lvc); 1870 AppendMenuItem(m_hMenuArrangeModes, MF_STRING, currentSortId, lvc.pszText, m_sortInfo.ListColumn); 1871 } 1872 1873 // Prepend the sort-by items unless they are aleady there 1874 if (GetMenuItemID(hmenuArrange, 0) == FCIDM_SHVIEW_AUTOARRANGE || forceMerge) 1875 { 1876 Shell_MergeMenus(hmenuArrange, m_hMenuArrangeModes, 0, 0, 0xFFFF, MM_ADDSEPARATOR); 1877 } 1878 1879 CheckMenuRadioItem(hmenuArrange, 1880 DVIDM_ARRANGESORT_FIRST, DVIDM_ARRANGESORT_LAST, 1881 currentSortId, MF_BYCOMMAND); 1882 1883 if (m_FolderSettings.ViewMode == FVM_DETAILS || m_FolderSettings.ViewMode == FVM_LIST) 1884 { 1885 EnableMenuItem(hmenuArrange, FCIDM_SHVIEW_AUTOARRANGE, MF_BYCOMMAND | MF_GRAYED); 1886 EnableMenuItem(hmenuArrange, FCIDM_SHVIEW_ALIGNTOGRID, MF_BYCOMMAND | MF_GRAYED); 1887 } 1888 else 1889 { 1890 EnableMenuItem(hmenuArrange, FCIDM_SHVIEW_AUTOARRANGE, MF_BYCOMMAND); 1891 EnableMenuItem(hmenuArrange, FCIDM_SHVIEW_ALIGNTOGRID, MF_BYCOMMAND); 1892 1893 if (GetAutoArrange() == S_OK) 1894 CheckMenuItem(hmenuArrange, FCIDM_SHVIEW_AUTOARRANGE, MF_CHECKED); 1895 else 1896 CheckMenuItem(hmenuArrange, FCIDM_SHVIEW_AUTOARRANGE, MF_UNCHECKED); 1897 1898 if (_GetSnapToGrid() == S_OK) 1899 CheckMenuItem(hmenuArrange, FCIDM_SHVIEW_ALIGNTOGRID, MF_CHECKED); 1900 else 1901 CheckMenuItem(hmenuArrange, FCIDM_SHVIEW_ALIGNTOGRID, MF_UNCHECKED); 1902 } 1903 1904 return S_OK; 1905 } 1906 1907 HRESULT CDefView::CheckViewMode(HMENU hmenuView) 1908 { 1909 if (m_FolderSettings.ViewMode >= FVM_FIRST && m_FolderSettings.ViewMode <= FVM_LAST) 1910 { 1911 UINT iItemFirst = FCIDM_SHVIEW_BIGICON; 1912 UINT iItemLast = iItemFirst + FVM_LAST - FVM_FIRST; 1913 UINT iItem = iItemFirst + m_FolderSettings.ViewMode - FVM_FIRST; 1914 CheckMenuRadioItem(hmenuView, iItemFirst, iItemLast, iItem, MF_BYCOMMAND); 1915 } 1916 1917 return S_OK; 1918 } 1919 1920 LRESULT CDefView::DoColumnContextMenu(LPARAM lParam) 1921 { 1922 const UINT maxItems = 15; // Feels about right 1923 const UINT idMore = 0x1337; 1924 UINT idFirst = idMore + 1, idLast = idFirst; 1925 UINT lastValidListCol = 0; // Keep track of where the new column should be inserted 1926 UINT showMore = GetKeyState(VK_SHIFT) < 0; 1927 POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; 1928 HWND hWndHdr = ListView_GetHeader(m_ListView.m_hWnd); 1929 1930 if (lParam == ~0) 1931 { 1932 RECT r; 1933 ::GetWindowRect(hWndHdr, &r); 1934 pt.x = r.left + ((r.right - r.left) / 2); 1935 pt.y = r.top + ((r.bottom - r.top) / 2); 1936 } 1937 1938 HMENU hMenu = CreatePopupMenu(); 1939 if (!hMenu) 1940 return 0; 1941 1942 for (UINT foldCol = 0;; ++foldCol) 1943 { 1944 WCHAR buf[MAX_PATH]; 1945 SHELLDETAILS sd; 1946 sd.str.uType = !STRRET_WSTR; 1947 if (FAILED(GetDetailsByFolderColumn(NULL, foldCol, sd))) 1948 break; 1949 if (FAILED(StrRetToStrNW(buf, _countof(buf), &sd.str, NULL))) 1950 break; 1951 1952 SHCOLSTATEF state = 0; 1953 if (!m_pSF2Parent || FAILED(m_pSF2Parent->GetDefaultColumnState(foldCol, &state))) 1954 state = 0; 1955 showMore |= (state & (SHCOLSTATE_SECONDARYUI)); 1956 1957 UINT mf = MF_STRING; 1958 HRESULT listCol = MapFolderColumnToListColumn(foldCol); 1959 1960 if (foldCol == 0) 1961 mf |= MF_CHECKED | MF_GRAYED | MF_DISABLED; // Force column 0 1962 else if (state & (SHCOLSTATE_SECONDARYUI | SHCOLSTATE_HIDDEN)) 1963 continue; 1964 else if (SUCCEEDED(listCol)) 1965 mf |= MF_CHECKED; 1966 1967 if (AppendMenuItem(hMenu, mf, idLast, buf, lastValidListCol + 1)) 1968 { 1969 idLast++; 1970 if (SUCCEEDED(listCol)) 1971 lastValidListCol = listCol; 1972 } 1973 1974 if (idLast - idFirst == maxItems) 1975 { 1976 showMore++; 1977 break; 1978 } 1979 } 1980 1981 if (showMore) 1982 { 1983 #if 0 // TODO 1984 InsertMenuW(hMenu, -1, MF_SEPARATOR, 0, NULL); 1985 InsertMenuW(hMenu, -1, MF_STRING, idMore, L"More..."); 1986 #endif 1987 } 1988 1989 // A cludge to force the cursor to update so we are not stuck with "size left/right" if 1990 // the right-click was on a column divider. 1991 ::PostMessage(m_ListView.m_hWnd, WM_SETCURSOR, (WPARAM) m_ListView.m_hWnd, HTCLIENT); 1992 1993 // Note: Uses the header as the owner so CDefView::OnInitMenuPopup does not mess us up. 1994 UINT idCmd = TrackPopupMenu(hMenu, TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, 1995 pt.x, pt.y, 0, hWndHdr, NULL); 1996 if (idCmd == idMore) 1997 { 1998 FIXME("Open More dialog\n"); 1999 } 2000 else if (idCmd) 2001 { 2002 UINT foldCol = idCmd - idFirst; 2003 HRESULT listCol = MapFolderColumnToListColumn(foldCol); 2004 if (SUCCEEDED(listCol)) 2005 { 2006 ListView_DeleteColumn(m_ListView.m_hWnd, listCol); 2007 } 2008 else 2009 { 2010 listCol = (UINT) GetMenuItemDataById(hMenu, idCmd); 2011 LoadColumn(foldCol, listCol, TRUE); 2012 } 2013 ColumnListChanged(); 2014 } 2015 DestroyMenu(hMenu); 2016 return 0; 2017 } 2018 2019 /********************************************************** 2020 * ShellView_GetSelections() 2021 * 2022 * - fills the m_apidl list with the selected objects 2023 * 2024 * RETURNS 2025 * number of selected items 2026 */ 2027 UINT CDefView::GetSelections() 2028 { 2029 UINT count = m_ListView.GetSelectedCount(); 2030 if (count > m_cidl || !count || !m_apidl) // !count to free possibly large cache, !m_apidl to make sure m_apidl is a valid pointer 2031 { 2032 SHFree(m_apidl); 2033 m_apidl = static_cast<PCUITEMID_CHILD*>(SHAlloc(count * sizeof(PCUITEMID_CHILD))); 2034 if (!m_apidl) 2035 { 2036 m_cidl = 0; 2037 return 0; 2038 } 2039 } 2040 m_cidl = count; 2041 2042 TRACE("-- Items selected =%u\n", m_cidl); 2043 2044 ASSERT(m_ListView); 2045 2046 UINT i = 0; 2047 int lvIndex = -1; 2048 while ((lvIndex = m_ListView.GetNextItem(lvIndex, LVNI_SELECTED)) > -1) 2049 { 2050 m_apidl[i] = _PidlByItem(lvIndex); 2051 i++; 2052 if (i == m_cidl) 2053 break; 2054 TRACE("-- selected Item found\n"); 2055 } 2056 2057 return m_cidl; 2058 } 2059 2060 HRESULT CDefView::InvokeContextMenuCommand(CComPtr<IContextMenu>& pCM, LPCSTR lpVerb, POINT* pt) 2061 { 2062 CMINVOKECOMMANDINFOEX cmi; 2063 2064 ZeroMemory(&cmi, sizeof(cmi)); 2065 cmi.cbSize = sizeof(cmi); 2066 cmi.hwnd = m_hWnd; 2067 cmi.lpVerb = lpVerb; 2068 cmi.nShow = SW_SHOW; 2069 2070 if (GetKeyState(VK_SHIFT) < 0) 2071 cmi.fMask |= CMIC_MASK_SHIFT_DOWN; 2072 2073 if (GetKeyState(VK_CONTROL) < 0) 2074 cmi.fMask |= CMIC_MASK_CONTROL_DOWN; 2075 2076 if (pt) 2077 { 2078 cmi.fMask |= CMIC_MASK_PTINVOKE; 2079 cmi.ptInvoke = *pt; 2080 } 2081 2082 WCHAR szDirW[MAX_PATH] = L""; 2083 CHAR szDirA[MAX_PATH]; 2084 if (SUCCEEDED(_DoFolderViewCB(SFVM_GETCOMMANDDIR, _countof(szDirW), (LPARAM)szDirW)) && 2085 *szDirW != UNICODE_NULL) 2086 { 2087 SHUnicodeToAnsi(szDirW, szDirA, _countof(szDirA)); 2088 cmi.fMask |= CMIC_MASK_UNICODE; 2089 cmi.lpDirectory = szDirA; 2090 cmi.lpDirectoryW = szDirW; 2091 } 2092 2093 HRESULT hr = pCM->InvokeCommand((LPCMINVOKECOMMANDINFO)&cmi); 2094 // Most of our callers will do this, but if they would forget (File menu!) 2095 IUnknown_SetSite(pCM, NULL); 2096 pCM.Release(); 2097 2098 if (FAILED_UNEXPECTEDLY(hr)) 2099 return hr; 2100 2101 return S_OK; 2102 } 2103 2104 HRESULT CDefView::OpenSelectedItems() 2105 { 2106 HMENU hMenu; 2107 UINT uCommand; 2108 HRESULT hResult; 2109 2110 if (m_ListView.GetSelectedCount() == 0) 2111 return S_OK; 2112 2113 hResult = OnDefaultCommand(); 2114 if (hResult == S_OK) 2115 return hResult; 2116 2117 hMenu = CreatePopupMenu(); 2118 if (!hMenu) 2119 return E_FAIL; 2120 2121 CComPtr<IContextMenu> pCM; 2122 hResult = GetItemObject(SVGIO_SELECTION, IID_PPV_ARG(IContextMenu, &pCM)); 2123 MenuCleanup _(pCM, hMenu); 2124 if (FAILED_UNEXPECTEDLY(hResult)) 2125 return hResult; 2126 2127 UINT cmf = CMF_DEFAULTONLY | GetContextMenuFlags(m_pShellBrowser, 0); 2128 hResult = pCM->QueryContextMenu(hMenu, 0, DVIDM_CONTEXTMENU_FIRST, DVIDM_CONTEXTMENU_LAST, cmf); 2129 if (FAILED_UNEXPECTEDLY(hResult)) 2130 return hResult; 2131 2132 uCommand = GetMenuDefaultItem(hMenu, FALSE, 0); 2133 if (uCommand == (UINT)-1) 2134 { 2135 ERR("GetMenuDefaultItem returned -1\n"); 2136 return E_FAIL; 2137 } 2138 2139 InvokeContextMenuCommand(pCM, MAKEINTRESOURCEA(uCommand), NULL); 2140 2141 return hResult; 2142 } 2143 2144 LRESULT CDefView::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 2145 { 2146 POINT pt = { pt.x = GET_X_LPARAM(lParam), pt.y = GET_Y_LPARAM(lParam) }; 2147 UINT uCommand; 2148 HRESULT hResult; 2149 2150 TRACE("(%p)\n", this); 2151 2152 if (m_hContextMenu != NULL) 2153 { 2154 ERR("HACK: Aborting context menu in nested call\n"); 2155 return 0; 2156 } 2157 2158 HWND hWndHdr = ListView_GetHeader(m_ListView.m_hWnd); 2159 RECT r; 2160 if (::GetWindowRect(hWndHdr, &r) && PtInRect(&r, pt) && ::IsWindowVisible(hWndHdr)) 2161 { 2162 return DoColumnContextMenu(lParam); 2163 } 2164 2165 m_hContextMenu = CreatePopupMenu(); 2166 if (!m_hContextMenu) 2167 return E_FAIL; 2168 2169 if (lParam != ~0) // unless app key (menu key) was pressed 2170 { 2171 LV_HITTESTINFO hittest = { pt }; 2172 ScreenToClient(&hittest.pt); 2173 m_ListView.HitTest(&hittest); 2174 2175 // Right-Clicked item is selected? If selected, no selection change. 2176 // If not selected, then reset the selection and select the item. 2177 if ((hittest.flags & LVHT_ONITEM) && 2178 m_ListView.GetItemState(hittest.iItem, LVIS_SELECTED) != LVIS_SELECTED) 2179 { 2180 SelectItem(hittest.iItem, SVSI_SELECT | SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE); 2181 } 2182 } 2183 2184 UINT count = m_ListView.GetSelectedCount(); 2185 // In case we still have this left over, clean it up 2186 hResult = GetItemObject(count ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &m_pCM)); 2187 MenuCleanup _(m_pCM, m_hContextMenu); 2188 if (FAILED_UNEXPECTEDLY(hResult)) 2189 return 0; 2190 2191 UINT cmf = GetContextMenuFlags(m_pShellBrowser, SFGAO_CANRENAME); 2192 // Use 1 as the first id we want. 0 means that user canceled the menu 2193 hResult = m_pCM->QueryContextMenu(m_hContextMenu, 0, CONTEXT_MENU_BASE_ID, DVIDM_CONTEXTMENU_LAST, cmf); 2194 if (FAILED_UNEXPECTEDLY(hResult)) 2195 return 0; 2196 2197 if (m_pCommDlgBrowser && !(GetCommDlgViewFlags() & CDB2GVF_NOSELECTVERB)) 2198 { 2199 HMENU hMenuSource = LoadMenuW(_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCEW(IDM_DVSELECT)); 2200 Shell_MergeMenus(m_hContextMenu, GetSubMenu(hMenuSource, 0), 0, DVIDM_COMMDLG_SELECT, 0xffff, MM_ADDSEPARATOR | MM_DONTREMOVESEPS); 2201 DestroyMenu(hMenuSource); 2202 SetMenuDefaultItem(m_hContextMenu, DVIDM_COMMDLG_SELECT, MF_BYCOMMAND); 2203 // TODO: ICommDlgBrowser2::GetDefaultMenuText == S_OK 2204 } 2205 2206 // There is no position requested, so try to find one 2207 if (lParam == ~0) 2208 { 2209 HWND hFocus = ::GetFocus(); 2210 int lvIndex = -1; 2211 2212 if (hFocus == m_ListView.m_hWnd || m_ListView.IsChild(hFocus)) 2213 { 2214 // Is there an item focused and selected? 2215 lvIndex = m_ListView.GetNextItem(-1, LVNI_SELECTED | LVNI_FOCUSED); 2216 // If not, find the first selected item 2217 if (lvIndex < 0) 2218 lvIndex = m_ListView.GetNextItem(-1, LVNI_SELECTED); 2219 } 2220 2221 // We got something 2222 if (lvIndex > -1) 2223 { 2224 // Find the center of the icon 2225 RECT rc = { LVIR_ICON }; 2226 m_ListView.SendMessage(LVM_GETITEMRECT, lvIndex, (LPARAM)&rc); 2227 pt.x = (rc.right + rc.left) / 2; 2228 pt.y = (rc.bottom + rc.top) / 2; 2229 } 2230 else 2231 { 2232 // We have to drop it somewhere 2233 pt.x = pt.y = 0; 2234 } 2235 2236 m_ListView.ClientToScreen(&pt); 2237 } 2238 2239 CComPtr<ICommDlgBrowser2> pcdb2; 2240 if (m_pCommDlgBrowser && SUCCEEDED(m_pCommDlgBrowser->QueryInterface(IID_PPV_ARG(ICommDlgBrowser2, &pcdb2)))) 2241 pcdb2->Notify(static_cast<IShellView*>(this), CDB2N_CONTEXTMENU_START); 2242 2243 // This runs the message loop, calling back to us with f.e. WM_INITPOPUP (hence why m_hContextMenu and m_pCM exist) 2244 uCommand = TrackPopupMenu(m_hContextMenu, 2245 TPM_LEFTALIGN | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, 2246 pt.x, pt.y, 0, m_hWnd, NULL); 2247 if (uCommand >= DVIDM_ARRANGESORT_FIRST && uCommand <= DVIDM_ARRANGESORT_LAST) 2248 { 2249 SendMessage(WM_COMMAND, uCommand, 0); 2250 } 2251 else if (uCommand != 0 && !(uCommand == DVIDM_COMMDLG_SELECT && OnDefaultCommand() == S_OK)) 2252 { 2253 InvokeContextMenuCommand(m_pCM, MAKEINTRESOURCEA(uCommand - CONTEXT_MENU_BASE_ID), &pt); 2254 } 2255 2256 if (pcdb2) 2257 pcdb2->Notify(static_cast<IShellView*>(this), CDB2N_CONTEXTMENU_DONE); 2258 return 0; 2259 } 2260 2261 LRESULT CDefView::OnExplorerCommand(UINT uCommand, BOOL bUseSelection) 2262 { 2263 HRESULT hResult; 2264 HMENU hMenu = NULL; 2265 2266 CComPtr<IContextMenu> pCM; 2267 hResult = GetItemObject(bUseSelection ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &pCM)); 2268 if (FAILED_UNEXPECTEDLY(hResult)) 2269 return 0; 2270 2271 MenuCleanup _(pCM, hMenu); 2272 2273 if ((uCommand != FCIDM_SHVIEW_DELETE) && (uCommand != FCIDM_SHVIEW_RENAME)) 2274 { 2275 hMenu = CreatePopupMenu(); 2276 if (!hMenu) 2277 return 0; 2278 2279 hResult = pCM->QueryContextMenu(hMenu, 0, DVIDM_CONTEXTMENU_FIRST, DVIDM_CONTEXTMENU_LAST, CMF_NORMAL); 2280 if (FAILED_UNEXPECTEDLY(hResult)) 2281 return 0; 2282 } 2283 2284 if (bUseSelection) 2285 { 2286 // FIXME: we should cache this 2287 SFGAOF rfg = SFGAO_BROWSABLE | SFGAO_CANCOPY | SFGAO_CANLINK | SFGAO_CANMOVE | SFGAO_CANDELETE | SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSTEM | SFGAO_FOLDER; 2288 hResult = m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &rfg); 2289 if (FAILED_UNEXPECTEDLY(hResult)) 2290 return 0; 2291 2292 if (!(rfg & SFGAO_CANMOVE) && uCommand == FCIDM_SHVIEW_CUT) 2293 return 0; 2294 if (!(rfg & SFGAO_CANCOPY) && uCommand == FCIDM_SHVIEW_COPY) 2295 return 0; 2296 if (!(rfg & SFGAO_CANDELETE) && uCommand == FCIDM_SHVIEW_DELETE) 2297 return 0; 2298 if (!(rfg & SFGAO_CANRENAME) && uCommand == FCIDM_SHVIEW_RENAME) 2299 return 0; 2300 if (!(rfg & SFGAO_HASPROPSHEET) && uCommand == FCIDM_SHVIEW_PROPERTIES) 2301 return 0; 2302 } 2303 2304 // FIXME: We should probably use the objects position? 2305 InvokeContextMenuCommand(pCM, MAKEINTRESOURCEA(uCommand), NULL); 2306 return 0; 2307 } 2308 2309 // ##### message handling ##### 2310 2311 LRESULT CDefView::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 2312 { 2313 WORD wWidth, wHeight; 2314 2315 wWidth = LOWORD(lParam); 2316 wHeight = HIWORD(lParam); 2317 2318 TRACE("%p width=%u height=%u\n", this, wWidth, wHeight); 2319 2320 // WM_SIZE can come before WM_CREATE 2321 if (!m_ListView) 2322 return 0; 2323 2324 /* Resize the ListView to fit our window */ 2325 ::MoveWindow(m_ListView, 0, 0, wWidth, wHeight, TRUE); 2326 2327 _DoFolderViewCB(SFVM_SIZE, 0, 0); 2328 2329 _ForceStatusBarResize(); 2330 UpdateStatusbar(); 2331 2332 return 0; 2333 } 2334 2335 // internal 2336 void CDefView::OnDeactivate() 2337 { 2338 TRACE("%p\n", this); 2339 2340 if (m_uState != SVUIA_DEACTIVATE) 2341 { 2342 // TODO: cleanup menu after deactivation 2343 m_uState = SVUIA_DEACTIVATE; 2344 } 2345 } 2346 2347 void CDefView::DoActivate(UINT uState) 2348 { 2349 TRACE("%p uState=%x\n", this, uState); 2350 2351 // don't do anything if the state isn't really changing 2352 if (m_uState == uState) 2353 { 2354 return; 2355 } 2356 2357 if (uState == SVUIA_DEACTIVATE) 2358 { 2359 OnDeactivate(); 2360 } 2361 else 2362 { 2363 if(m_hMenu && !m_bmenuBarInitialized) 2364 { 2365 FillEditMenu(); 2366 FillViewMenu(); 2367 m_pShellBrowser->SetMenuSB(m_hMenu, 0, m_hWnd); 2368 m_bmenuBarInitialized = TRUE; 2369 } 2370 2371 if (SVUIA_ACTIVATE_FOCUS == uState) 2372 { 2373 m_ListView.SetFocus(); 2374 } 2375 } 2376 2377 m_uState = uState; 2378 TRACE("--\n"); 2379 } 2380 2381 void CDefView::_DoCopyToMoveToFolder(BOOL bCopy) 2382 { 2383 if (!GetSelections()) 2384 return; 2385 2386 SFGAOF rfg = SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_FILESYSTEM; 2387 HRESULT hr = m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &rfg); 2388 if (FAILED_UNEXPECTEDLY(hr)) 2389 return; 2390 2391 if (!bCopy && !(rfg & SFGAO_CANMOVE)) 2392 return; 2393 if (bCopy && !(rfg & SFGAO_CANCOPY)) 2394 return; 2395 2396 CComPtr<IContextMenu> pCM; 2397 hr = m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, IID_IContextMenu, 0, (void **)&pCM); 2398 if (FAILED_UNEXPECTEDLY(hr)) 2399 return; 2400 2401 InvokeContextMenuCommand(pCM, (bCopy ? "copyto" : "moveto"), NULL); 2402 } 2403 2404 LRESULT CDefView::OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 2405 { 2406 DoActivate(SVUIA_ACTIVATE_FOCUS); 2407 return 0; 2408 } 2409 2410 LRESULT CDefView::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 2411 { 2412 TRACE("%p\n", this); 2413 2414 /* Tell the browser one of our windows has received the focus. This 2415 should always be done before merging menus (OnActivate merges the 2416 menus) if one of our windows has the focus.*/ 2417 2418 m_pShellBrowser->OnViewWindowActive(this); 2419 DoActivate(SVUIA_ACTIVATE_FOCUS); 2420 2421 /* Set the focus to the listview */ 2422 m_ListView.SetFocus(); 2423 2424 /* Notify the ICommDlgBrowser interface */ 2425 OnStateChange(CDBOSC_SETFOCUS); 2426 2427 return 0; 2428 } 2429 2430 LRESULT CDefView::OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 2431 { 2432 TRACE("(%p) stub\n", this); 2433 2434 DoActivate(SVUIA_ACTIVATE_NOFOCUS); 2435 /* Notify the ICommDlgBrowser */ 2436 OnStateChange(CDBOSC_KILLFOCUS); 2437 2438 return 0; 2439 } 2440 2441 // the CmdID's are the ones from the context menu 2442 LRESULT CDefView::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 2443 { 2444 DWORD dwCmdID; 2445 DWORD dwCmd; 2446 HWND hwndCmd; 2447 int nCount; 2448 2449 dwCmdID = GET_WM_COMMAND_ID(wParam, lParam); 2450 dwCmd = GET_WM_COMMAND_CMD(wParam, lParam); 2451 hwndCmd = GET_WM_COMMAND_HWND(wParam, lParam); 2452 2453 TRACE("(%p)->(0x%08x 0x%08x %p) stub\n", this, dwCmdID, dwCmd, hwndCmd); 2454 2455 if (dwCmdID >= DVIDM_ARRANGESORT_FIRST && dwCmdID <= DVIDM_ARRANGESORT_LAST) 2456 { 2457 UINT listCol = (UINT)GetMenuItemDataById(m_hMenuArrangeModes, dwCmdID); 2458 _Sort(listCol); 2459 return 0; 2460 } 2461 2462 switch (dwCmdID) 2463 { 2464 case FCIDM_SHVIEW_SMALLICON: 2465 m_FolderSettings.ViewMode = FVM_SMALLICON; 2466 m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_SMALLICON); 2467 CheckToolbar(); 2468 break; 2469 case FCIDM_SHVIEW_BIGICON: 2470 m_FolderSettings.ViewMode = FVM_ICON; 2471 m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_ICON); 2472 CheckToolbar(); 2473 break; 2474 case FCIDM_SHVIEW_LISTVIEW: 2475 m_FolderSettings.ViewMode = FVM_LIST; 2476 m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_LIST); 2477 CheckToolbar(); 2478 break; 2479 case FCIDM_SHVIEW_REPORTVIEW: 2480 m_FolderSettings.ViewMode = FVM_DETAILS; 2481 m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_REPORT); 2482 CheckToolbar(); 2483 break; 2484 case FCIDM_SHVIEW_SNAPTOGRID: 2485 m_ListView.Arrange(LVA_SNAPTOGRID); 2486 break; 2487 case FCIDM_SHVIEW_ALIGNTOGRID: 2488 if (_GetSnapToGrid() == S_OK) 2489 m_ListView.SetExtendedListViewStyle(0, LVS_EX_SNAPTOGRID); 2490 else 2491 ArrangeGrid(); 2492 break; 2493 case FCIDM_SHVIEW_AUTOARRANGE: 2494 if (GetAutoArrange() == S_OK) 2495 m_ListView.ModifyStyle(LVS_AUTOARRANGE, 0); 2496 else 2497 AutoArrange(); 2498 break; 2499 case FCIDM_SHVIEW_SELECTALL: 2500 if (_DoFolderViewCB(SFVM_CANSELECTALL, 0, 0) != S_FALSE) 2501 m_ListView.SetItemState(-1, LVIS_SELECTED, LVIS_SELECTED); 2502 break; 2503 case FCIDM_SHVIEW_INVERTSELECTION: 2504 nCount = m_ListView.GetItemCount(); 2505 for (int i=0; i < nCount; i++) 2506 m_ListView.SetItemState(i, m_ListView.GetItemState(i, LVIS_SELECTED) ? 0 : LVIS_SELECTED, LVIS_SELECTED); 2507 break; 2508 case FCIDM_SHVIEW_REFRESH: 2509 Refresh(); 2510 break; 2511 case FCIDM_SHVIEW_DELETE: 2512 case FCIDM_SHVIEW_CUT: 2513 case FCIDM_SHVIEW_COPY: 2514 case FCIDM_SHVIEW_RENAME: 2515 case FCIDM_SHVIEW_PROPERTIES: 2516 if (SHRestricted(REST_NOVIEWCONTEXTMENU)) 2517 return 0; 2518 return OnExplorerCommand(dwCmdID, TRUE); 2519 case FCIDM_SHVIEW_COPYTO: 2520 case FCIDM_SHVIEW_MOVETO: 2521 _DoCopyToMoveToFolder(dwCmdID == FCIDM_SHVIEW_COPYTO); 2522 return 0; 2523 case FCIDM_SHVIEW_INSERT: 2524 case FCIDM_SHVIEW_UNDO: 2525 case FCIDM_SHVIEW_INSERTLINK: 2526 case FCIDM_SHVIEW_NEWFOLDER: 2527 return OnExplorerCommand(dwCmdID, FALSE); 2528 default: 2529 // WM_COMMAND messages from file menu are routed to CDefView to let m_pFileMenu handle them 2530 if (m_pFileMenu && dwCmd == 0) 2531 { 2532 HMENU Dummy = NULL; 2533 MenuCleanup _(m_pFileMenu, Dummy); 2534 InvokeContextMenuCommand(m_pFileMenu, MAKEINTRESOURCEA(dwCmdID), NULL); 2535 } 2536 } 2537 2538 return 0; 2539 } 2540 2541 static BOOL 2542 SelectExtOnRename(void) 2543 { 2544 HKEY hKey; 2545 LONG error; 2546 DWORD dwValue = FALSE, cbValue; 2547 2548 error = RegOpenKeyExW(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER, 0, KEY_READ, &hKey); 2549 if (error) 2550 return dwValue; 2551 2552 cbValue = sizeof(dwValue); 2553 RegQueryValueExW(hKey, L"SelectExtOnRename", NULL, NULL, (LPBYTE)&dwValue, &cbValue); 2554 2555 RegCloseKey(hKey); 2556 return !!dwValue; 2557 } 2558 2559 LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 2560 { 2561 UINT CtlID; 2562 LPNMHDR lpnmh; 2563 LPNMLISTVIEW lpnmlv; 2564 NMLVDISPINFOW *lpdi; 2565 PCUITEMID_CHILD pidl; 2566 BOOL unused; 2567 2568 CtlID = wParam; 2569 lpnmh = (LPNMHDR)lParam; 2570 lpnmlv = (LPNMLISTVIEW)lpnmh; 2571 lpdi = (NMLVDISPINFOW *)lpnmh; 2572 2573 TRACE("%p CtlID=%u lpnmh->code=%x\n", this, CtlID, lpnmh->code); 2574 2575 switch (lpnmh->code) 2576 { 2577 case NM_SETFOCUS: 2578 TRACE("-- NM_SETFOCUS %p\n", this); 2579 OnSetFocus(0, 0, 0, unused); 2580 break; 2581 case NM_KILLFOCUS: 2582 TRACE("-- NM_KILLFOCUS %p\n", this); 2583 OnDeactivate(); 2584 /* Notify the ICommDlgBrowser interface */ 2585 OnStateChange(CDBOSC_KILLFOCUS); 2586 break; 2587 case NM_CUSTOMDRAW: 2588 TRACE("-- NM_CUSTOMDRAW %p\n", this); 2589 return CDRF_DODEFAULT; 2590 case NM_RELEASEDCAPTURE: 2591 TRACE("-- NM_RELEASEDCAPTURE %p\n", this); 2592 break; 2593 case NM_CLICK: 2594 TRACE("-- NM_CLICK %p\n", this); 2595 break; 2596 case NM_RCLICK: 2597 TRACE("-- NM_RCLICK %p\n", this); 2598 break; 2599 case NM_DBLCLK: 2600 TRACE("-- NM_DBLCLK %p\n", this); 2601 OpenSelectedItems(); 2602 break; 2603 case NM_RETURN: 2604 TRACE("-- NM_RETURN %p\n", this); 2605 OpenSelectedItems(); 2606 break; 2607 case HDN_ENDTRACKW: 2608 TRACE("-- HDN_ENDTRACKW %p\n", this); 2609 //nColumn1 = m_ListView.GetColumnWidth(0); 2610 //nColumn2 = m_ListView.GetColumnWidth(1); 2611 break; 2612 case LVN_DELETEITEM: 2613 TRACE("-- LVN_DELETEITEM %p\n", this); 2614 /*delete the pidl because we made a copy of it*/ 2615 SHFree(reinterpret_cast<LPVOID>(lpnmlv->lParam)); 2616 break; 2617 case LVN_DELETEALLITEMS: 2618 TRACE("-- LVN_DELETEALLITEMS %p\n", this); 2619 return FALSE; 2620 case LVN_INSERTITEM: 2621 TRACE("-- LVN_INSERTITEM (STUB)%p\n", this); 2622 break; 2623 case LVN_ITEMACTIVATE: 2624 TRACE("-- LVN_ITEMACTIVATE %p\n", this); 2625 OnStateChange(CDBOSC_SELCHANGE); // browser will get the IDataObject 2626 break; 2627 case LVN_COLUMNCLICK: 2628 { 2629 UINT foldercol = MapListColumnToFolderColumn(lpnmlv->iSubItem); 2630 HRESULT hr = S_FALSE; 2631 if (m_pSDParent) 2632 hr = m_pSDParent->ColumnClick(foldercol); 2633 if (hr != S_OK) 2634 hr = _DoFolderViewCB(SFVM_COLUMNCLICK, foldercol, 0); 2635 if (hr != S_OK) 2636 _Sort(lpnmlv->iSubItem); 2637 break; 2638 } 2639 case LVN_GETDISPINFOA: 2640 case LVN_GETDISPINFOW: 2641 TRACE("-- LVN_GETDISPINFO %p\n", this); 2642 pidl = _PidlByItem(lpdi->item); 2643 2644 if (lpdi->item.mask & LVIF_TEXT) /* text requested */ 2645 { 2646 SHELLDETAILS sd; 2647 if (FAILED_UNEXPECTEDLY(GetDetailsByListColumn(pidl, lpdi->item.iSubItem, sd))) 2648 break; 2649 2650 if (lpnmh->code == LVN_GETDISPINFOA) 2651 { 2652 /* shouldn't happen */ 2653 NMLVDISPINFOA *lpdiA = (NMLVDISPINFOA *)lpnmh; 2654 StrRetToStrNA( lpdiA->item.pszText, lpdiA->item.cchTextMax, &sd.str, NULL); 2655 TRACE("-- text=%s\n", lpdiA->item.pszText); 2656 } 2657 else /* LVN_GETDISPINFOW */ 2658 { 2659 StrRetToStrNW( lpdi->item.pszText, lpdi->item.cchTextMax, &sd.str, NULL); 2660 TRACE("-- text=%s\n", debugstr_w(lpdi->item.pszText)); 2661 } 2662 } 2663 if(lpdi->item.mask & LVIF_IMAGE) /* image requested */ 2664 { 2665 lpdi->item.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0); 2666 } 2667 if(lpdi->item.mask & LVIF_STATE) 2668 { 2669 ULONG attributes = SFGAO_HIDDEN; 2670 if (SUCCEEDED(m_pSFParent->GetAttributesOf(1, &pidl, &attributes))) 2671 { 2672 if (attributes & SFGAO_HIDDEN) 2673 lpdi->item.state |= LVIS_CUT; 2674 } 2675 } 2676 lpdi->item.mask |= LVIF_DI_SETITEM; 2677 break; 2678 case LVN_ITEMCHANGED: 2679 TRACE("-- LVN_ITEMCHANGED %p\n", this); 2680 if ((lpnmlv->uOldState ^ lpnmlv->uNewState) & (LVIS_SELECTED | LVIS_FOCUSED)) 2681 { 2682 OnStateChange(CDBOSC_SELCHANGE); // browser will get the IDataObject 2683 // FIXME: Use LVIS_DROPHILITED instead in drag_notify_subitem 2684 if (!m_ScheduledStatusbarUpdate && (m_iDragOverItem == -1 || m_pCurDropTarget == NULL)) 2685 { 2686 m_ScheduledStatusbarUpdate = true; 2687 PostMessage(SHV_UPDATESTATUSBAR, 0, 0); 2688 } 2689 _DoFolderViewCB(SFVM_SELECTIONCHANGED, NULL/* FIXME */, NULL/* FIXME */); 2690 } 2691 break; 2692 case LVN_BEGINDRAG: 2693 case LVN_BEGINRDRAG: 2694 TRACE("-- LVN_BEGINDRAG\n"); 2695 if (GetSelections()) 2696 { 2697 CComPtr<IDataObject> pda; 2698 DWORD dwAttributes = SFGAO_CANCOPY | SFGAO_CANLINK; 2699 DWORD dwEffect = DROPEFFECT_MOVE; 2700 2701 if (SUCCEEDED(m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, IID_NULL_PPV_ARG(IDataObject, &pda)))) 2702 { 2703 LPNMLISTVIEW params = (LPNMLISTVIEW)lParam; 2704 2705 if (SUCCEEDED(m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &dwAttributes))) 2706 dwEffect |= dwAttributes & (SFGAO_CANCOPY | SFGAO_CANLINK); 2707 2708 CComPtr<IAsyncOperation> piaso; 2709 if (SUCCEEDED(pda->QueryInterface(IID_PPV_ARG(IAsyncOperation, &piaso)))) 2710 piaso->SetAsyncMode(TRUE); 2711 2712 DWORD dwEffect2; 2713 2714 m_pSourceDataObject = pda; 2715 m_ptFirstMousePos = params->ptAction; 2716 ClientToScreen(&m_ptFirstMousePos); 2717 ::ClientToListView(m_ListView, &m_ptFirstMousePos); 2718 2719 HIMAGELIST big_icons, small_icons; 2720 Shell_GetImageLists(&big_icons, &small_icons); 2721 PCUITEMID_CHILD pidl = _PidlByItem(params->iItem); 2722 int iIcon = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0); 2723 POINT ptItem; 2724 m_ListView.GetItemPosition(params->iItem, &ptItem); 2725 2726 ImageList_BeginDrag(big_icons, iIcon, params->ptAction.x - ptItem.x, params->ptAction.y - ptItem.y); 2727 DoDragDrop(pda, this, dwEffect, &dwEffect2); 2728 m_pSourceDataObject.Release(); 2729 } 2730 } 2731 break; 2732 case LVN_BEGINLABELEDITW: 2733 { 2734 DWORD dwAttr = SFGAO_CANRENAME; 2735 pidl = _PidlByItem(lpdi->item); 2736 2737 TRACE("-- LVN_BEGINLABELEDITW %p\n", this); 2738 2739 m_pSFParent->GetAttributesOf(1, &pidl, &dwAttr); 2740 if (SFGAO_CANRENAME & dwAttr) 2741 { 2742 HWND hEdit = reinterpret_cast<HWND>(m_ListView.SendMessage(LVM_GETEDITCONTROL)); 2743 SHLimitInputEdit(hEdit, m_pSFParent); 2744 2745 // smartass-renaming: See CORE-15242 2746 if (!(dwAttr & SFGAO_FOLDER) && (dwAttr & SFGAO_FILESYSTEM) && 2747 (lpdi->item.mask & LVIF_TEXT) && !SelectExtOnRename()) 2748 { 2749 WCHAR szFullPath[MAX_PATH]; 2750 PIDLIST_ABSOLUTE pidlFull = ILCombine(m_pidlParent, pidl); 2751 SHGetPathFromIDListW(pidlFull, szFullPath); 2752 2753 INT cchLimit = 0; 2754 _DoFolderViewCB(SFVM_GETNAMELENGTH, (WPARAM)pidlFull, (LPARAM)&cchLimit); 2755 if (cchLimit) 2756 ::SendMessageW(hEdit, EM_SETLIMITTEXT, cchLimit, 0); 2757 2758 if (!SHELL_FS_HideExtension(szFullPath)) 2759 { 2760 LPWSTR pszText = lpdi->item.pszText; 2761 LPWSTR pchDotExt = PathFindExtensionW(pszText); 2762 ::PostMessageW(hEdit, EM_SETSEL, 0, pchDotExt - pszText); 2763 ::PostMessageW(hEdit, EM_SCROLLCARET, 0, 0); 2764 } 2765 2766 ILFree(pidlFull); 2767 } 2768 2769 m_isEditing = TRUE; 2770 return FALSE; 2771 } 2772 return TRUE; 2773 } 2774 case LVN_ENDLABELEDITW: 2775 { 2776 TRACE("-- LVN_ENDLABELEDITW %p\n", this); 2777 m_isEditing = FALSE; 2778 2779 if (lpdi->item.pszText) 2780 { 2781 HRESULT hr; 2782 LVITEMW lvItem; 2783 2784 pidl = _PidlByItem(lpdi->item); 2785 PITEMID_CHILD pidlNew = NULL; 2786 hr = m_pSFParent->SetNameOf(0, pidl, lpdi->item.pszText, SHGDN_INFOLDER, &pidlNew); 2787 2788 if (SUCCEEDED(hr) && pidlNew) 2789 { 2790 lvItem.mask = LVIF_PARAM|LVIF_IMAGE; 2791 lvItem.iItem = lpdi->item.iItem; 2792 lvItem.iSubItem = 0; 2793 lvItem.lParam = reinterpret_cast<LPARAM>(pidlNew); 2794 lvItem.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidlNew, 0); 2795 m_ListView.SetItem(&lvItem); 2796 m_ListView.Update(lpdi->item.iItem); 2797 return TRUE; 2798 } 2799 } 2800 2801 return FALSE; 2802 } 2803 default: 2804 TRACE("-- %p WM_COMMAND %x unhandled\n", this, lpnmh->code); 2805 break; 2806 } 2807 2808 return 0; 2809 } 2810 2811 // This is just a quick hack to make the desktop work correctly. 2812 // ITranslateShellChangeNotify's IsChildID is undocumented, but most likely the 2813 // way that a folder should know if it should update upon a change notification. 2814 // It is exported by merged folders at a minimum. 2815 static BOOL ILIsParentOrSpecialParent(PCIDLIST_ABSOLUTE pidl1, PCIDLIST_ABSOLUTE pidl2) 2816 { 2817 if (!pidl1 || !pidl2) 2818 return FALSE; 2819 if (ILIsParent(pidl1, pidl2, TRUE)) 2820 return TRUE; 2821 2822 CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidl2Clone(ILClone(pidl2)); 2823 ILRemoveLastID(pidl2Clone); 2824 return ILIsEqual(pidl1, pidl2Clone); 2825 } 2826 2827 LRESULT CDefView::OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 2828 { 2829 // The change notify can come before WM_CREATE 2830 if (!m_ListView) 2831 return FALSE; 2832 2833 HANDLE hChange = (HANDLE)wParam; 2834 DWORD dwProcID = (DWORD)lParam; 2835 PIDLIST_ABSOLUTE *Pidls; 2836 LONG lEvent; 2837 HANDLE hLock = SHChangeNotification_Lock(hChange, dwProcID, &Pidls, &lEvent); 2838 if (hLock == NULL) 2839 { 2840 ERR("hLock == NULL\n"); 2841 return FALSE; 2842 } 2843 2844 TRACE("(%p)(%p,%p,%p)\n", this, Pidls[0], Pidls[1], lParam); 2845 2846 if (_DoFolderViewCB(SFVM_FSNOTIFY, (WPARAM)Pidls, lEvent) == S_FALSE) 2847 return FALSE; 2848 2849 // Translate child IDLs. 2850 // SHSimpleIDListFromPathW creates fake PIDLs (lacking some attributes) 2851 HRESULT hr; 2852 PITEMID_CHILD child0 = NULL, child1 = NULL; 2853 CComHeapPtr<ITEMIDLIST_RELATIVE> pidl0Temp, pidl1Temp; 2854 if (_ILIsSpecialFolder(Pidls[0]) || ILIsParentOrSpecialParent(m_pidlParent, Pidls[0])) 2855 { 2856 child0 = ILFindLastID(Pidls[0]); 2857 hr = SHGetRealIDL(m_pSFParent, child0, &pidl0Temp); 2858 if (SUCCEEDED(hr)) 2859 child0 = pidl0Temp; 2860 } 2861 if (_ILIsSpecialFolder(Pidls[1]) || ILIsParentOrSpecialParent(m_pidlParent, Pidls[1])) 2862 { 2863 child1 = ILFindLastID(Pidls[1]); 2864 hr = SHGetRealIDL(m_pSFParent, child1, &pidl1Temp); 2865 if (SUCCEEDED(hr)) 2866 child1 = pidl1Temp; 2867 } 2868 2869 lEvent &= ~SHCNE_INTERRUPT; 2870 switch (lEvent) 2871 { 2872 case SHCNE_MKDIR: 2873 case SHCNE_CREATE: 2874 case SHCNE_DRIVEADD: 2875 if (!child0) 2876 break; 2877 if (LV_FindItemByPidl(child0) < 0) 2878 LV_AddItem(child0); 2879 else 2880 LV_UpdateItem(child0); 2881 break; 2882 case SHCNE_RMDIR: 2883 case SHCNE_DELETE: 2884 case SHCNE_DRIVEREMOVED: 2885 if (child0) 2886 LV_DeleteItem(child0); 2887 break; 2888 case SHCNE_RENAMEFOLDER: 2889 case SHCNE_RENAMEITEM: 2890 if (child0 && child1) 2891 LV_RenameItem(child0, child1); 2892 else if (child0) 2893 LV_DeleteItem(child0); 2894 else if (child1) 2895 LV_AddItem(child1); 2896 break; 2897 case SHCNE_UPDATEITEM: 2898 if (child0) 2899 LV_UpdateItem(child0); 2900 break; 2901 case SHCNE_UPDATEIMAGE: 2902 case SHCNE_MEDIAINSERTED: 2903 case SHCNE_MEDIAREMOVED: 2904 case SHCNE_ASSOCCHANGED: 2905 LV_RefreshIcons(); 2906 break; 2907 case SHCNE_UPDATEDIR: 2908 case SHCNE_ATTRIBUTES: 2909 Refresh(); 2910 UpdateStatusbar(); 2911 break; 2912 case SHCNE_FREESPACE: 2913 UpdateStatusbar(); 2914 break; 2915 } 2916 2917 SHChangeNotification_Unlock(hLock); 2918 return TRUE; 2919 } 2920 2921 HRESULT SHGetMenuIdFromMenuMsg(UINT uMsg, LPARAM lParam, UINT *CmdId); 2922 HRESULT SHSetMenuIdInMenuMsg(UINT uMsg, LPARAM lParam, UINT CmdId); 2923 2924 LRESULT CDefView::OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 2925 { 2926 if (!m_pCM) 2927 { 2928 /* no menu */ 2929 ERR("no context menu\n"); 2930 return FALSE; 2931 } 2932 2933 // lParam of WM_DRAWITEM WM_MEASUREITEM contains a menu id and 2934 // this also needs to be changed to a menu identifier offset 2935 UINT CmdID; 2936 HRESULT hres = SHGetMenuIdFromMenuMsg(uMsg, lParam, &CmdID); 2937 if (SUCCEEDED(hres)) 2938 SHSetMenuIdInMenuMsg(uMsg, lParam, CmdID - CONTEXT_MENU_BASE_ID); 2939 2940 /* Forward the message to the IContextMenu2 */ 2941 LRESULT result; 2942 hres = SHForwardContextMenuMsg(m_pCM, uMsg, wParam, lParam, &result, TRUE); 2943 2944 return (SUCCEEDED(hres)); 2945 } 2946 2947 LRESULT CDefView::OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 2948 { 2949 /* Wallpaper setting affects drop shadows effect */ 2950 if (wParam == SPI_SETDESKWALLPAPER || wParam == 0) 2951 UpdateListColors(); 2952 2953 return S_OK; 2954 } 2955 2956 LRESULT CDefView::OnInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 2957 { 2958 HMENU hmenu = (HMENU) wParam; 2959 int nPos = LOWORD(lParam); 2960 UINT menuItemId; 2961 2962 if (m_pCM) 2963 OnCustomItem(uMsg, wParam, lParam, bHandled); 2964 2965 HMENU hViewMenu = GetSubmenuByID(m_hMenu, FCIDM_MENU_VIEW); 2966 2967 if (GetSelections() == 0) 2968 { 2969 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_CUT, MF_GRAYED); 2970 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_COPY, MF_GRAYED); 2971 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_RENAME, MF_GRAYED); 2972 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_COPYTO, MF_GRAYED); 2973 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_MOVETO, MF_GRAYED); 2974 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_DELETE, MF_GRAYED); 2975 } 2976 else 2977 { 2978 // FIXME: Check copyable 2979 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_CUT, MF_ENABLED); 2980 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_COPY, MF_ENABLED); 2981 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_RENAME, MF_ENABLED); 2982 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_COPYTO, MF_ENABLED); 2983 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_MOVETO, MF_ENABLED); 2984 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_DELETE, MF_ENABLED); 2985 } 2986 2987 /* Lets try to find out what the hell wParam is */ 2988 if (hmenu == GetSubMenu(m_hMenu, nPos)) 2989 menuItemId = ReallyGetMenuItemID(m_hMenu, nPos); 2990 else if (hViewMenu && hmenu == GetSubMenu(hViewMenu, nPos)) 2991 menuItemId = ReallyGetMenuItemID(hViewMenu, nPos); 2992 else if (m_hContextMenu && hmenu == GetSubMenu(m_hContextMenu, nPos)) 2993 menuItemId = ReallyGetMenuItemID(m_hContextMenu, nPos); 2994 else 2995 return FALSE; 2996 2997 switch (menuItemId) 2998 { 2999 case FCIDM_MENU_FILE: 3000 FillFileMenu(); 3001 break; 3002 case FCIDM_MENU_VIEW: 3003 case FCIDM_SHVIEW_VIEW: 3004 CheckViewMode(hmenu); 3005 break; 3006 case FCIDM_SHVIEW_ARRANGE: 3007 FillArrangeAsMenu(hmenu); 3008 break; 3009 } 3010 3011 return FALSE; 3012 } 3013 3014 3015 // The INTERFACE of the IShellView object 3016 3017 HRESULT WINAPI CDefView::GetWindow(HWND *phWnd) 3018 { 3019 TRACE("(%p)\n", this); 3020 3021 *phWnd = m_hWnd; 3022 3023 return S_OK; 3024 } 3025 3026 HRESULT WINAPI CDefView::ContextSensitiveHelp(BOOL fEnterMode) 3027 { 3028 FIXME("(%p) stub\n", this); 3029 3030 return E_NOTIMPL; 3031 } 3032 3033 // FIXME: use the accel functions 3034 HRESULT WINAPI CDefView::TranslateAccelerator(LPMSG lpmsg) 3035 { 3036 if (m_isEditing) 3037 return S_FALSE; 3038 3039 if (lpmsg->message >= WM_KEYFIRST && lpmsg->message <= WM_KEYLAST) 3040 { 3041 if (::TranslateAcceleratorW(m_hWnd, m_hAccel, lpmsg) != 0) 3042 return S_OK; 3043 3044 TRACE("-- key=0x%04lx\n", lpmsg->wParam); 3045 } 3046 3047 return m_pShellBrowser->TranslateAcceleratorSB(lpmsg, 0); 3048 } 3049 3050 HRESULT WINAPI CDefView::EnableModeless(BOOL fEnable) 3051 { 3052 FIXME("(%p)\n", this); 3053 return E_NOTIMPL; 3054 } 3055 3056 HRESULT WINAPI CDefView::UIActivate(UINT uState) 3057 { 3058 TRACE("(%p)->(state=%x)\n", this, uState); 3059 3060 // don't do anything if the state isn't changing 3061 if (m_uState == uState) 3062 return S_OK; 3063 3064 // OnActivate handles the menu merging and internal state 3065 DoActivate(uState); 3066 3067 // only do this if we are active 3068 if (uState != SVUIA_DEACTIVATE) 3069 { 3070 _ForceStatusBarResize(); 3071 3072 // Set the text for the status bar 3073 UpdateStatusbar(); 3074 } 3075 3076 return S_OK; 3077 } 3078 3079 HRESULT WINAPI CDefView::Refresh() 3080 { 3081 TRACE("(%p)\n", this); 3082 3083 _DoFolderViewCB(SFVM_LISTREFRESHED, TRUE, 0); 3084 3085 m_ListView.DeleteAllItems(); 3086 FillList(); 3087 3088 return S_OK; 3089 } 3090 3091 HRESULT WINAPI CDefView::CreateViewWindow(IShellView *lpPrevView, LPCFOLDERSETTINGS lpfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd) 3092 { 3093 return CreateViewWindow3(psb, lpPrevView, SV3CVW3_DEFAULT, 3094 (FOLDERFLAGS)lpfs->fFlags, (FOLDERFLAGS)lpfs->fFlags, (FOLDERVIEWMODE)lpfs->ViewMode, NULL, prcView, phWnd); 3095 } 3096 3097 HRESULT WINAPI CDefView::DestroyViewWindow() 3098 { 3099 TRACE("(%p)\n", this); 3100 3101 /* Make absolutely sure all our UI is cleaned up */ 3102 UIActivate(SVUIA_DEACTIVATE); 3103 3104 if (m_hAccel) 3105 { 3106 // MSDN: Accelerator tables loaded from resources are freed automatically when application terminates 3107 m_hAccel = NULL; 3108 } 3109 3110 if (m_hMenuArrangeModes) 3111 { 3112 DestroyMenu(m_hMenuArrangeModes); 3113 m_hMenuArrangeModes = NULL; 3114 } 3115 3116 if (m_hMenuViewModes) 3117 { 3118 DestroyMenu(m_hMenuViewModes); 3119 m_hMenuViewModes = NULL; 3120 } 3121 3122 if (m_hMenu) 3123 { 3124 DestroyMenu(m_hMenu); 3125 m_hMenu = NULL; 3126 } 3127 3128 if (m_ListView) 3129 { 3130 m_ListView.DestroyWindow(); 3131 } 3132 3133 if (m_hWnd) 3134 { 3135 _DoFolderViewCB(SFVM_WINDOWCLOSING, (WPARAM)m_hWnd, 0); 3136 DestroyWindow(); 3137 } 3138 3139 m_pShellBrowser.Release(); 3140 m_pCommDlgBrowser.Release(); 3141 3142 return S_OK; 3143 } 3144 3145 HRESULT WINAPI CDefView::GetCurrentInfo(LPFOLDERSETTINGS lpfs) 3146 { 3147 TRACE("(%p)->(%p) vmode=%x flags=%x\n", this, lpfs, 3148 m_FolderSettings.ViewMode, m_FolderSettings.fFlags); 3149 3150 if (!lpfs) 3151 return E_INVALIDARG; 3152 3153 *lpfs = m_FolderSettings; 3154 return S_OK; 3155 } 3156 3157 HRESULT WINAPI CDefView::AddPropertySheetPages(DWORD dwReserved, LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam) 3158 { 3159 TRACE("(%p)->(0x%lX, %p, %p)\n", this, dwReserved, lpfn, lparam); 3160 3161 SFVM_PROPPAGE_DATA Data = { dwReserved, lpfn, lparam }; 3162 _DoFolderViewCB(SFVM_ADDPROPERTYPAGES, 0, (LPARAM)&Data); 3163 return S_OK; 3164 } 3165 3166 static HRESULT Read(IStream *pS, LPVOID buffer, ULONG cb) 3167 { 3168 ULONG read; 3169 HRESULT hr = pS->Read(buffer, cb, &read); 3170 return FAILED(hr) ? hr : (cb == read ? S_OK : HResultFromWin32(ERROR_MORE_DATA)); 3171 } 3172 3173 static DWORD ReadDWORD(IPropertyBag *pPB, LPCWSTR name, DWORD def) 3174 { 3175 DWORD value; 3176 HRESULT hr = SHPropertyBag_ReadDWORD(pPB, name, &value); 3177 return SUCCEEDED(hr) ? value : def; 3178 } 3179 3180 HRESULT CDefView::GetDefaultViewStream(DWORD Stgm, IStream **ppStream) 3181 { 3182 CLSID clsid; 3183 HRESULT hr = IUnknown_GetClassID(m_pSFParent, &clsid); 3184 if (SUCCEEDED(hr)) 3185 { 3186 WCHAR path[MAX_PATH], name[39]; 3187 wsprintfW(path, L"%s\\%s", REGSTR_PATH_EXPLORER, L"Streams\\Default"); 3188 StringFromGUID2(clsid, name, 39); 3189 *ppStream = SHOpenRegStream2W(HKEY_CURRENT_USER, path, name, Stgm); 3190 hr = *ppStream ? S_OK : E_FAIL; 3191 } 3192 return hr; 3193 } 3194 3195 static HRESULT LoadColumnsStream(PERSISTCOLUMNS &cols, IStream *pS) 3196 { 3197 HRESULT hr = Read(pS, &cols, FIELD_OFFSET(PERSISTCOLUMNS, Columns)); 3198 if (FAILED(hr)) 3199 return hr; 3200 if (cols.Signature != PERSISTCOLUMNS::SIG || cols.Count > cols.MAXCOUNT) 3201 return HResultFromWin32(ERROR_INVALID_DATA); 3202 return Read(pS, &cols.Columns, sizeof(*cols.Columns) * cols.Count); 3203 } 3204 3205 HRESULT CDefView::LoadViewState() 3206 { 3207 PERSISTCLASSICVIEWSTATE cvs; 3208 PERSISTCOLUMNS cols; 3209 CComPtr<IStream> pS; 3210 CComPtr<IPropertyBag> pPB; 3211 bool fallback = false; 3212 HRESULT hrColumns = E_FAIL; 3213 HRESULT hr = IUnknown_QueryServicePropertyBag(m_pShellBrowser, SHGVSPB_FOLDER, IID_PPV_ARG(IPropertyBag, &pPB)); 3214 if (SUCCEEDED(hr)) 3215 { 3216 DWORD data; 3217 if (FAILED(hr = SHPropertyBag_ReadDWORD(pPB, L"Mode", &data))) 3218 goto loadfallback; 3219 cvs.FolderSettings.ViewMode = data; 3220 cvs.FolderSettings.fFlags = ReadDWORD(pPB, L"FFlags", FWF_NOGROUPING); 3221 data = ReadDWORD(pPB, L"Sort", ~0ul); 3222 cvs.SortColId = data != ~0ul ? (WORD)data : LISTVIEW_SORT_INFO::UNSPECIFIEDCOLUMN; 3223 cvs.SortDir = (INT8)ReadDWORD(pPB, L"SortDir", 1); 3224 if (SUCCEEDED(hrColumns = SHPropertyBag_ReadStream(pPB, L"ColInfo", &pS))) 3225 hrColumns = LoadColumnsStream(cols, pS); 3226 } 3227 else 3228 { 3229 if (FAILED(hr = (m_pShellBrowser ? m_pShellBrowser->GetViewStateStream(STGM_READ, &pS) : E_UNEXPECTED))) 3230 { 3231 loadfallback: 3232 hr = GetDefaultViewStream(STGM_READ, &pS); 3233 fallback = true; 3234 } 3235 if (FAILED(hr) || FAILED(hr = Read(pS, &cvs, sizeof(cvs)))) 3236 return hr; 3237 if (cvs.Signature != cvs.SIG) 3238 return HResultFromWin32(ERROR_INVALID_DATA); 3239 hrColumns = LoadColumnsStream(cols, pS); 3240 } 3241 m_FolderSettings.ViewMode = cvs.FolderSettings.ViewMode; 3242 m_FolderSettings.fFlags &= ~cvs.VALIDFWF; 3243 m_FolderSettings.fFlags |= cvs.FolderSettings.fFlags & cvs.VALIDFWF; 3244 if (SUCCEEDED(hrColumns)) 3245 { 3246 BOOL failed = FALSE; 3247 if ((m_LoadColumnsList = DPA_Create(cols.Count)) != NULL) 3248 { 3249 for (UINT i = 0; i < cols.Count; ++i) 3250 { 3251 failed |= !DPA_SetPtr(m_LoadColumnsList, i, UlongToPtr(cols.Columns[i])); 3252 } 3253 } 3254 if (failed || !cols.Count) 3255 { 3256 DPA_Destroy(m_LoadColumnsList); 3257 m_LoadColumnsList = NULL; 3258 } 3259 } 3260 m_sortInfo.bLoadedFromViewState = !fallback && m_LoadColumnsList && cvs.SortColId != LISTVIEW_SORT_INFO::UNSPECIFIEDCOLUMN; 3261 m_sortInfo.bColumnIsFolderColumn = TRUE; 3262 m_sortInfo.Direction = cvs.SortDir > 0 ? 1 : -1; 3263 m_sortInfo.ListColumn = cvs.SortColId; 3264 return hr; 3265 } 3266 3267 HRESULT CDefView::SaveViewState(IStream *pStream) 3268 { 3269 if (!m_ListView.m_hWnd) 3270 return E_UNEXPECTED; 3271 int sortcol = MapListColumnToFolderColumn(m_sortInfo.ListColumn); 3272 PERSISTCLASSICVIEWSTATE cvs; 3273 cvs.SortColId = sortcol >= 0 ? (WORD)sortcol : 0; 3274 cvs.SortDir = m_sortInfo.Direction; 3275 PERSISTCOLUMNS cols; 3276 cols.Signature = PERSISTCOLUMNS::SIG; 3277 cols.Count = 0; 3278 LVCOLUMN lvc; 3279 lvc.mask = LVCF_WIDTH | LVCF_SUBITEM; 3280 for (UINT i = 0, j = 0; i < PERSISTCOLUMNS::MAXCOUNT && ListView_GetColumn(m_ListView, j, &lvc); ++j) 3281 { 3282 HRESULT hr = MapListColumnToFolderColumn(lvc.iSubItem); 3283 if (SUCCEEDED(hr)) 3284 { 3285 cols.Columns[i] = MAKELONG(hr, lvc.cx); 3286 cols.Count = ++i; 3287 } 3288 } 3289 UINT cbColumns = FIELD_OFFSET(PERSISTCOLUMNS, Columns) + (sizeof(*cols.Columns) * cols.Count); 3290 UpdateFolderViewFlags(); 3291 3292 IPropertyBag *pPB; 3293 HRESULT hr = S_OK; 3294 if (pStream) 3295 { 3296 pStream->AddRef(); 3297 goto stream; 3298 } 3299 hr = IUnknown_QueryServicePropertyBag(m_pShellBrowser, SHGVSPB_FOLDER, IID_PPV_ARG(IPropertyBag, &pPB)); 3300 if (SUCCEEDED(hr)) 3301 { 3302 UINT uViewMode; 3303 GetCurrentViewMode(&uViewMode); 3304 hr = SHPropertyBag_WriteDWORD(pPB, L"Mode", uViewMode); 3305 SHPropertyBag_WriteDWORD(pPB, L"FFlags", m_FolderSettings.fFlags); 3306 SHPropertyBag_WriteDWORD(pPB, L"Sort", cvs.SortColId); 3307 SHPropertyBag_WriteDWORD(pPB, L"SortDir", cvs.SortDir); 3308 pStream = cols.Count ? SHCreateMemStream((LPBYTE)&cols, cbColumns) : NULL; 3309 if (!pStream || FAILED(SHPropertyBag_WriteStream(pPB, L"ColInfo", pStream))) 3310 SHPropertyBag_Delete(pPB, L"ColInfo"); 3311 #if 0 // TODO 3312 WCHAR name[MAX_PATH]; 3313 memcpy(name, L"ItemPos", sizeof(L"ItemPos")); 3314 if (SHGetPerScreenResName(name + 7, _countof(name) - 7, 0)) 3315 { 3316 if (GetAutoArrange() == S_FALSE) 3317 // TODO: Save listview item positions 3318 else 3319 SHPropertyBag_Delete(pPB, name); 3320 } 3321 #endif 3322 pPB->Release(); 3323 } 3324 else if (SUCCEEDED(hr = (m_pShellBrowser ? m_pShellBrowser->GetViewStateStream(STGM_WRITE, &pStream) : E_UNEXPECTED))) 3325 { 3326 stream: 3327 ULONG written; 3328 cvs.Signature = cvs.SIG; 3329 cvs.FolderSettings = m_FolderSettings; 3330 hr = pStream->Write(&cvs, sizeof(cvs), &written); 3331 if (SUCCEEDED(hr)) 3332 hr = pStream->Write(&cols, cbColumns, &written); 3333 } 3334 if (pStream) 3335 pStream->Release(); 3336 return hr; 3337 } 3338 3339 HRESULT WINAPI CDefView::SaveViewState() 3340 { 3341 if (!(m_FolderSettings.fFlags & FWF_NOBROWSERVIEWSTATE)) 3342 return SaveViewState(NULL); 3343 return S_FALSE; 3344 } 3345 3346 #define UPDATEFOLDERVIEWFLAGS(bits, bit, set) ( (bits) = ((bits) & ~(bit)) | ((set) ? (bit) : 0) ) 3347 void CDefView::UpdateFolderViewFlags() 3348 { 3349 UPDATEFOLDERVIEWFLAGS(m_FolderSettings.fFlags, FWF_AUTOARRANGE, GetAutoArrange() == S_OK); 3350 UPDATEFOLDERVIEWFLAGS(m_FolderSettings.fFlags, FWF_SNAPTOGRID, _GetSnapToGrid() == S_OK); 3351 UPDATEFOLDERVIEWFLAGS(m_FolderSettings.fFlags, FWF_NOGROUPING, !ListView_IsGroupViewEnabled(m_ListView.m_hWnd)); 3352 } 3353 3354 HRESULT WINAPI CDefView::SelectItem(PCUITEMID_CHILD pidl, UINT uFlags) 3355 { 3356 int i; 3357 3358 TRACE("(%p)->(pidl=%p, 0x%08x) stub\n", this, pidl, uFlags); 3359 3360 if (!m_ListView) 3361 { 3362 ERR("!m_ListView\n"); 3363 return E_FAIL; 3364 } 3365 3366 i = LV_FindItemByPidl(pidl); 3367 if (i == -1) 3368 return S_OK; 3369 3370 LVITEMW lvItem = {0}; 3371 lvItem.mask = LVIF_STATE; 3372 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED; 3373 3374 while (m_ListView.GetItem(&lvItem)) 3375 { 3376 if (lvItem.iItem == i) 3377 { 3378 if (uFlags & SVSI_SELECT) 3379 lvItem.state |= LVIS_SELECTED; 3380 else 3381 lvItem.state &= ~LVIS_SELECTED; 3382 3383 if (uFlags & SVSI_FOCUSED) 3384 lvItem.state |= LVIS_FOCUSED; 3385 else 3386 lvItem.state &= ~LVIS_FOCUSED; 3387 } 3388 else 3389 { 3390 if (uFlags & SVSI_DESELECTOTHERS) 3391 { 3392 lvItem.state &= ~LVIS_SELECTED; 3393 } 3394 lvItem.state &= ~LVIS_FOCUSED; 3395 } 3396 3397 m_ListView.SetItem(&lvItem); 3398 lvItem.iItem++; 3399 } 3400 3401 if (uFlags & SVSI_ENSUREVISIBLE) 3402 m_ListView.EnsureVisible(i, FALSE); 3403 3404 if((uFlags & SVSI_EDIT) == SVSI_EDIT) 3405 m_ListView.EditLabel(i); 3406 3407 return S_OK; 3408 } 3409 3410 HRESULT WINAPI CDefView::GetItemObject(UINT uItem, REFIID riid, LPVOID *ppvOut) 3411 { 3412 HRESULT hr = E_NOINTERFACE; 3413 3414 TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n", this, uItem, debugstr_guid(&riid), ppvOut); 3415 3416 if (!ppvOut) 3417 return E_INVALIDARG; 3418 3419 *ppvOut = NULL; 3420 3421 switch (uItem) 3422 { 3423 case SVGIO_BACKGROUND: 3424 if (IsEqualIID(riid, IID_IContextMenu)) 3425 { 3426 hr = CDefViewBckgrndMenu_CreateInstance(m_pSF2Parent, riid, ppvOut); 3427 if (FAILED_UNEXPECTEDLY(hr)) 3428 return hr; 3429 3430 IUnknown_SetSite(*((IUnknown**)ppvOut), (IShellView *)this); 3431 } 3432 else if (IsEqualIID(riid, IID_IDispatch)) 3433 { 3434 if (m_pShellFolderViewDual == NULL) 3435 { 3436 hr = CDefViewDual_Constructor(riid, (LPVOID*)&m_pShellFolderViewDual); 3437 if (FAILED_UNEXPECTEDLY(hr)) 3438 return hr; 3439 } 3440 hr = m_pShellFolderViewDual->QueryInterface(riid, ppvOut); 3441 } 3442 break; 3443 case SVGIO_SELECTION: 3444 GetSelections(); 3445 hr = m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, riid, 0, ppvOut); 3446 if (FAILED_UNEXPECTEDLY(hr)) 3447 return hr; 3448 3449 if (IsEqualIID(riid, IID_IContextMenu)) 3450 IUnknown_SetSite(*((IUnknown**)ppvOut), (IShellView *)this); 3451 3452 break; 3453 } 3454 3455 TRACE("-- (%p)->(interface=%p)\n", this, *ppvOut); 3456 3457 return hr; 3458 } 3459 3460 FOLDERVIEWMODE CDefView::GetDefaultViewMode() 3461 { 3462 FOLDERVIEWMODE mode = ((m_FolderSettings.fFlags & FWF_DESKTOP) || !IsOS(OS_SERVERADMINUI)) ? FVM_ICON : FVM_DETAILS; 3463 FOLDERVIEWMODE temp = mode; 3464 if (SUCCEEDED(_DoFolderViewCB(SFVM_DEFVIEWMODE, 0, (LPARAM)&temp)) && temp >= FVM_FIRST && temp <= FVM_LAST) 3465 mode = temp; 3466 return mode; 3467 } 3468 3469 HRESULT STDMETHODCALLTYPE CDefView::GetCurrentViewMode(UINT *pViewMode) 3470 { 3471 TRACE("(%p)->(%p), stub\n", this, pViewMode); 3472 3473 if (!pViewMode) 3474 return E_INVALIDARG; 3475 3476 *pViewMode = m_FolderSettings.ViewMode; 3477 return S_OK; 3478 } 3479 3480 HRESULT STDMETHODCALLTYPE CDefView::SetCurrentViewMode(UINT ViewMode) 3481 { 3482 DWORD dwStyle; 3483 TRACE("(%p)->(%u), stub\n", this, ViewMode); 3484 3485 /* It's not redundant to check FVM_AUTO because it's a (UINT)-1 */ 3486 if (((INT)ViewMode < FVM_FIRST || (INT)ViewMode > FVM_LAST) && ((INT)ViewMode != FVM_AUTO)) 3487 return E_INVALIDARG; 3488 3489 /* Windows before Vista uses LVM_SETVIEW and possibly 3490 LVM_SETEXTENDEDLISTVIEWSTYLE to set the style of the listview, 3491 while later versions seem to accomplish this through other 3492 means. */ 3493 switch (ViewMode) 3494 { 3495 case FVM_ICON: 3496 dwStyle = LVS_ICON; 3497 break; 3498 case FVM_DETAILS: 3499 dwStyle = LVS_REPORT; 3500 break; 3501 case FVM_SMALLICON: 3502 dwStyle = LVS_SMALLICON; 3503 break; 3504 case FVM_LIST: 3505 dwStyle = LVS_LIST; 3506 break; 3507 default: 3508 { 3509 FIXME("ViewMode %d not implemented\n", ViewMode); 3510 dwStyle = LVS_LIST; 3511 break; 3512 } 3513 } 3514 3515 m_ListView.ModifyStyle(LVS_TYPEMASK, dwStyle); 3516 3517 /* This will not necessarily be the actual mode set above. 3518 This mimics the behavior of Windows XP. */ 3519 m_FolderSettings.ViewMode = ViewMode; 3520 3521 return S_OK; 3522 } 3523 3524 HRESULT STDMETHODCALLTYPE CDefView::GetFolder(REFIID riid, void **ppv) 3525 { 3526 if (m_pSFParent == NULL) 3527 return E_FAIL; 3528 3529 return m_pSFParent->QueryInterface(riid, ppv); 3530 } 3531 3532 HRESULT STDMETHODCALLTYPE CDefView::Item(int iItemIndex, PITEMID_CHILD *ppidl) 3533 { 3534 PCUITEMID_CHILD pidl = _PidlByItem(iItemIndex); 3535 if (pidl) 3536 { 3537 *ppidl = ILClone(pidl); 3538 return S_OK; 3539 } 3540 3541 *ppidl = 0; 3542 return E_INVALIDARG; 3543 } 3544 3545 HRESULT STDMETHODCALLTYPE CDefView::ItemCount(UINT uFlags, int *pcItems) 3546 { 3547 TRACE("(%p)->(%u %p)\n", this, uFlags, pcItems); 3548 3549 if (uFlags != SVGIO_ALLVIEW) 3550 FIXME("some flags unsupported, %x\n", uFlags & ~SVGIO_ALLVIEW); 3551 3552 *pcItems = m_ListView.GetItemCount(); 3553 3554 return S_OK; 3555 } 3556 3557 HRESULT STDMETHODCALLTYPE CDefView::Items(UINT uFlags, REFIID riid, void **ppv) 3558 { 3559 return E_NOTIMPL; 3560 } 3561 3562 HRESULT STDMETHODCALLTYPE CDefView::GetSelectionMarkedItem(int *piItem) 3563 { 3564 TRACE("(%p)->(%p)\n", this, piItem); 3565 3566 *piItem = m_ListView.GetSelectionMark(); 3567 3568 return S_OK; 3569 } 3570 3571 HRESULT STDMETHODCALLTYPE CDefView::GetFocusedItem(int *piItem) 3572 { 3573 TRACE("(%p)->(%p)\n", this, piItem); 3574 3575 *piItem = m_ListView.GetNextItem(-1, LVNI_FOCUSED); 3576 3577 return S_OK; 3578 } 3579 3580 HRESULT STDMETHODCALLTYPE CDefView::GetItemPosition(PCUITEMID_CHILD pidl, POINT *ppt) 3581 { 3582 if (!m_ListView) 3583 { 3584 ERR("!m_ListView\n"); 3585 return E_FAIL; 3586 } 3587 3588 int lvIndex = LV_FindItemByPidl(pidl); 3589 if (lvIndex == -1 || ppt == NULL) 3590 return E_INVALIDARG; 3591 3592 m_ListView.GetItemPosition(lvIndex, ppt); 3593 return S_OK; 3594 } 3595 3596 HRESULT STDMETHODCALLTYPE CDefView::GetSpacing(POINT *ppt) 3597 { 3598 TRACE("(%p)->(%p)\n", this, ppt); 3599 3600 if (!m_ListView) 3601 { 3602 ERR("!m_ListView\n"); 3603 return S_FALSE; 3604 } 3605 3606 if (ppt) 3607 { 3608 SIZE spacing; 3609 m_ListView.GetItemSpacing(spacing); 3610 3611 ppt->x = spacing.cx; 3612 ppt->y = spacing.cy; 3613 } 3614 3615 return S_OK; 3616 } 3617 3618 HRESULT STDMETHODCALLTYPE CDefView::GetDefaultSpacing(POINT *ppt) 3619 { 3620 return E_NOTIMPL; 3621 } 3622 3623 HRESULT STDMETHODCALLTYPE CDefView::GetAutoArrange() 3624 { 3625 return ((m_ListView.GetStyle() & LVS_AUTOARRANGE) ? S_OK : S_FALSE); 3626 } 3627 3628 HRESULT CDefView::_GetSnapToGrid() 3629 { 3630 DWORD dwExStyle = (DWORD)m_ListView.SendMessage(LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); 3631 return ((dwExStyle & LVS_EX_SNAPTOGRID) ? S_OK : S_FALSE); 3632 } 3633 3634 HRESULT STDMETHODCALLTYPE CDefView::SelectItem(int iItem, DWORD dwFlags) 3635 { 3636 LVITEMW lvItem; 3637 3638 TRACE("(%p)->(%d, %x)\n", this, iItem, dwFlags); 3639 3640 lvItem.state = 0; 3641 lvItem.stateMask = LVIS_SELECTED; 3642 3643 if (dwFlags & SVSI_ENSUREVISIBLE) 3644 m_ListView.EnsureVisible(iItem, 0); 3645 3646 /* all items */ 3647 if (dwFlags & SVSI_DESELECTOTHERS) 3648 m_ListView.SetItemState(-1, 0, LVIS_SELECTED); 3649 3650 /* this item */ 3651 if (dwFlags & SVSI_SELECT) 3652 lvItem.state |= LVIS_SELECTED; 3653 3654 if (dwFlags & SVSI_FOCUSED) 3655 lvItem.stateMask |= LVIS_FOCUSED; 3656 3657 m_ListView.SetItemState(iItem, lvItem.state, lvItem.stateMask); 3658 3659 if ((dwFlags & SVSI_EDIT) == SVSI_EDIT) 3660 m_ListView.EditLabel(iItem); 3661 3662 return S_OK; 3663 } 3664 3665 HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItems(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, POINT *apt, DWORD dwFlags) 3666 { 3667 ASSERT(m_ListView); 3668 3669 /* Reset the selection */ 3670 m_ListView.SetItemState(-1, 0, LVIS_SELECTED); 3671 3672 int lvIndex; 3673 for (UINT i = 0 ; i < cidl; i++) 3674 { 3675 lvIndex = LV_FindItemByPidl(apidl[i]); 3676 if (lvIndex != -1) 3677 { 3678 SelectItem(lvIndex, dwFlags); 3679 m_ListView.SetItemPosition(lvIndex, &apt[i]); 3680 } 3681 } 3682 3683 return S_OK; 3684 } 3685 3686 3687 // IShellView2 implementation 3688 3689 HRESULT STDMETHODCALLTYPE CDefView::GetView(SHELLVIEWID *view_guid, ULONG view_type) 3690 { 3691 FIXME("(%p)->(%p, %lu) stub\n", this, view_guid, view_type); 3692 return E_NOTIMPL; 3693 } 3694 3695 HRESULT STDMETHODCALLTYPE CDefView::CreateViewWindow2(LPSV2CVW2_PARAMS view_params) 3696 { 3697 return CreateViewWindow3(view_params->psbOwner, view_params->psvPrev, 3698 SV3CVW3_DEFAULT, (FOLDERFLAGS)view_params->pfs->fFlags, (FOLDERFLAGS)view_params->pfs->fFlags, 3699 (FOLDERVIEWMODE)view_params->pfs->ViewMode, view_params->pvid, view_params->prcView, &view_params->hwndView); 3700 } 3701 3702 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) 3703 { 3704 OLEMENUGROUPWIDTHS omw = { { 0, 0, 0, 0, 0, 0 } }; 3705 const UINT SUPPORTED_SV3CVW3 = SV3CVW3_FORCEVIEWMODE | SV3CVW3_FORCEFOLDERFLAGS; 3706 const UINT IGNORE_FWF = FWF_OWNERDATA; // FIXME: Support this 3707 3708 *hwnd = NULL; 3709 3710 TRACE("(%p)->(shlview=%p shlbrs=%p rec=%p hwnd=%p vmode=%x flags=%x)\n", this, psvPrevious, psb, prcView, hwnd, mode, flags); 3711 if (prcView != NULL) 3712 TRACE("-- left=%i top=%i right=%i bottom=%i\n", prcView->left, prcView->top, prcView->right, prcView->bottom); 3713 3714 /* Validate the Shell Browser */ 3715 if (psb == NULL || m_hWnd) 3716 return E_UNEXPECTED; 3717 3718 if (view_flags & ~SUPPORTED_SV3CVW3) 3719 FIXME("unsupported view flags 0x%08x\n", view_flags & ~SUPPORTED_SV3CVW3); 3720 3721 if (mode == FVM_AUTO) 3722 mode = GetDefaultViewMode(); 3723 3724 /* Set up the member variables */ 3725 m_pShellBrowser = psb; 3726 m_FolderSettings.ViewMode = mode; 3727 m_FolderSettings.fFlags = (mask & flags) & ~IGNORE_FWF; 3728 3729 if (view_id) 3730 { 3731 if (IsEqualIID(*view_id, VID_LargeIcons)) 3732 m_FolderSettings.ViewMode = FVM_ICON; 3733 else if (IsEqualIID(*view_id, VID_SmallIcons)) 3734 m_FolderSettings.ViewMode = FVM_SMALLICON; 3735 else if (IsEqualIID(*view_id, VID_List)) 3736 m_FolderSettings.ViewMode = FVM_LIST; 3737 else if (IsEqualIID(*view_id, VID_Details)) 3738 m_FolderSettings.ViewMode = FVM_DETAILS; 3739 else if (IsEqualIID(*view_id, VID_Thumbnails)) 3740 m_FolderSettings.ViewMode = FVM_THUMBNAIL; 3741 else if (IsEqualIID(*view_id, VID_Tile)) 3742 m_FolderSettings.ViewMode = FVM_TILE; 3743 else if (IsEqualIID(*view_id, VID_ThumbStrip)) 3744 m_FolderSettings.ViewMode = FVM_THUMBSTRIP; 3745 else 3746 FIXME("Ignoring unrecognized VID %s\n", debugstr_guid(view_id)); 3747 } 3748 const UINT requestedViewMode = m_FolderSettings.ViewMode; 3749 3750 /* Get our parent window */ 3751 m_pShellBrowser->GetWindow(&m_hWndParent); 3752 _DoFolderViewCB(SFVM_HWNDMAIN, 0, (LPARAM)m_hWndParent); 3753 3754 /* Try to get the ICommDlgBrowserInterface, adds a reference !!! */ 3755 m_pCommDlgBrowser = NULL; 3756 if (SUCCEEDED(m_pShellBrowser->QueryInterface(IID_PPV_ARG(ICommDlgBrowser, &m_pCommDlgBrowser)))) 3757 { 3758 TRACE("-- CommDlgBrowser\n"); 3759 } 3760 3761 LoadViewState(); 3762 if (view_flags & SV3CVW3_FORCEVIEWMODE) 3763 m_FolderSettings.ViewMode = requestedViewMode; 3764 if (view_flags & SV3CVW3_FORCEFOLDERFLAGS) 3765 m_FolderSettings.fFlags = (mask & flags) & ~IGNORE_FWF; 3766 3767 RECT rcView = *prcView; 3768 Create(m_hWndParent, rcView, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP, 0, 0U); 3769 if (m_hWnd == NULL) 3770 return E_FAIL; 3771 3772 *hwnd = m_hWnd; 3773 3774 CheckToolbar(); 3775 3776 if (!*hwnd) 3777 return E_FAIL; 3778 3779 _DoFolderViewCB(SFVM_WINDOWCREATED, (WPARAM)m_hWnd, 0); 3780 3781 SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); 3782 UpdateWindow(); 3783 3784 if (!m_hMenu) 3785 { 3786 m_hMenu = CreateMenu(); 3787 m_pShellBrowser->InsertMenusSB(m_hMenu, &omw); 3788 TRACE("-- after fnInsertMenusSB\n"); 3789 } 3790 3791 _MergeToolbar(); 3792 3793 return S_OK; 3794 } 3795 3796 HRESULT STDMETHODCALLTYPE CDefView::HandleRename(LPCITEMIDLIST new_pidl) 3797 { 3798 FIXME("(%p)->(%p) stub\n", this, new_pidl); 3799 return E_NOTIMPL; 3800 } 3801 3802 HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItem(LPCITEMIDLIST item, UINT flags, POINT *point) 3803 { 3804 FIXME("(%p)->(%p, %u, %p) stub\n", this, item, flags, point); 3805 return E_NOTIMPL; 3806 } 3807 3808 // IShellFolderView implementation 3809 3810 HRESULT STDMETHODCALLTYPE CDefView::Rearrange(LPARAM sort) 3811 { 3812 FIXME("(%p)->(%ld) stub\n", this, sort); 3813 return E_NOTIMPL; 3814 } 3815 3816 HRESULT STDMETHODCALLTYPE CDefView::GetArrangeParam(LPARAM *sort) 3817 { 3818 FIXME("(%p)->(%p) stub\n", this, sort); 3819 return E_NOTIMPL; 3820 } 3821 3822 HRESULT STDMETHODCALLTYPE CDefView::ArrangeGrid() 3823 { 3824 m_ListView.SetExtendedListViewStyle(LVS_EX_SNAPTOGRID, LVS_EX_SNAPTOGRID); 3825 return S_OK; 3826 } 3827 3828 HRESULT STDMETHODCALLTYPE CDefView::AutoArrange() 3829 { 3830 m_ListView.ModifyStyle(0, LVS_AUTOARRANGE); 3831 m_ListView.Arrange(LVA_DEFAULT); 3832 return S_OK; 3833 } 3834 3835 HRESULT STDMETHODCALLTYPE CDefView::AddObject(PITEMID_CHILD pidl, UINT *item) 3836 { 3837 TRACE("(%p)->(%p %p)\n", this, pidl, item); 3838 if (!m_ListView) 3839 { 3840 ERR("!m_ListView\n"); 3841 return E_FAIL; 3842 } 3843 *item = LV_AddItem(pidl); 3844 return (int)*item >= 0 ? S_OK : E_OUTOFMEMORY; 3845 } 3846 3847 HRESULT STDMETHODCALLTYPE CDefView::GetObject(PITEMID_CHILD *pidl, UINT item) 3848 { 3849 TRACE("(%p)->(%p %d)\n", this, pidl, item); 3850 return Item(item, pidl); 3851 } 3852 3853 HRESULT STDMETHODCALLTYPE CDefView::RemoveObject(PITEMID_CHILD pidl, UINT *item) 3854 { 3855 TRACE("(%p)->(%p %p)\n", this, pidl, item); 3856 3857 if (!m_ListView) 3858 { 3859 ERR("!m_ListView\n"); 3860 return E_FAIL; 3861 } 3862 3863 if (pidl) 3864 { 3865 *item = LV_FindItemByPidl(ILFindLastID(pidl)); 3866 m_ListView.DeleteItem(*item); 3867 } 3868 else 3869 { 3870 *item = 0; 3871 m_ListView.DeleteAllItems(); 3872 } 3873 3874 return S_OK; 3875 } 3876 3877 HRESULT STDMETHODCALLTYPE CDefView::GetObjectCount(UINT *count) 3878 { 3879 TRACE("(%p)->(%p)\n", this, count); 3880 *count = m_ListView.GetItemCount(); 3881 return S_OK; 3882 } 3883 3884 HRESULT STDMETHODCALLTYPE CDefView::SetObjectCount(UINT count, UINT flags) 3885 { 3886 FIXME("(%p)->(%d %x) stub\n", this, count, flags); 3887 return E_NOTIMPL; 3888 } 3889 3890 HRESULT STDMETHODCALLTYPE CDefView::UpdateObject(PITEMID_CHILD pidl_old, PITEMID_CHILD pidl_new, UINT *item) 3891 { 3892 FIXME("(%p)->(%p %p %p) stub\n", this, pidl_old, pidl_new, item); 3893 return E_NOTIMPL; 3894 } 3895 3896 HRESULT STDMETHODCALLTYPE CDefView::RefreshObject(PITEMID_CHILD pidl, UINT *item) 3897 { 3898 FIXME("(%p)->(%p %p) stub\n", this, pidl, item); 3899 return E_NOTIMPL; 3900 } 3901 3902 HRESULT STDMETHODCALLTYPE CDefView::SetRedraw(BOOL redraw) 3903 { 3904 TRACE("(%p)->(%d)\n", this, redraw); 3905 if (m_ListView) 3906 m_ListView.SetRedraw(redraw); 3907 return S_OK; 3908 } 3909 3910 HRESULT STDMETHODCALLTYPE CDefView::GetSelectedCount(UINT *count) 3911 { 3912 FIXME("(%p)->(%p) stub\n", this, count); 3913 return E_NOTIMPL; 3914 } 3915 3916 HRESULT STDMETHODCALLTYPE CDefView::GetSelectedObjects(PCUITEMID_CHILD **pidl, UINT *items) 3917 { 3918 TRACE("(%p)->(%p %p)\n", this, pidl, items); 3919 3920 *items = GetSelections(); 3921 3922 if (*items) 3923 { 3924 *pidl = static_cast<PCUITEMID_CHILD *>(LocalAlloc(0, *items * sizeof(PCUITEMID_CHILD))); 3925 if (!*pidl) 3926 { 3927 return E_OUTOFMEMORY; 3928 } 3929 3930 /* it's documented that caller shouldn't PIDLs, only array itself */ 3931 memcpy(*pidl, m_apidl, *items * sizeof(PCUITEMID_CHILD)); 3932 } 3933 3934 return S_OK; 3935 } 3936 3937 HRESULT STDMETHODCALLTYPE CDefView::IsDropOnSource(IDropTarget *drop_target) 3938 { 3939 if ((m_iDragOverItem == -1 || m_pCurDropTarget == NULL) && 3940 (m_pSourceDataObject.p)) 3941 { 3942 return S_OK; 3943 } 3944 3945 return S_FALSE; 3946 } 3947 3948 HRESULT STDMETHODCALLTYPE CDefView::GetDragPoint(POINT *pt) 3949 { 3950 if (!pt) 3951 return E_INVALIDARG; 3952 3953 *pt = m_ptFirstMousePos; 3954 return S_OK; 3955 } 3956 3957 HRESULT STDMETHODCALLTYPE CDefView::GetDropPoint(POINT *pt) 3958 { 3959 FIXME("(%p)->(%p) stub\n", this, pt); 3960 return E_NOTIMPL; 3961 } 3962 3963 HRESULT STDMETHODCALLTYPE CDefView::MoveIcons(IDataObject *obj) 3964 { 3965 TRACE("(%p)->(%p)\n", this, obj); 3966 return E_NOTIMPL; 3967 } 3968 3969 HRESULT STDMETHODCALLTYPE CDefView::SetItemPos(PCUITEMID_CHILD pidl, POINT *pt) 3970 { 3971 FIXME("(%p)->(%p %p) stub\n", this, pidl, pt); 3972 return E_NOTIMPL; 3973 } 3974 3975 HRESULT STDMETHODCALLTYPE CDefView::IsBkDropTarget(IDropTarget *drop_target) 3976 { 3977 FIXME("(%p)->(%p) stub\n", this, drop_target); 3978 return E_NOTIMPL; 3979 } 3980 3981 HRESULT STDMETHODCALLTYPE CDefView::SetClipboard(BOOL move) 3982 { 3983 FIXME("(%p)->(%d) stub\n", this, move); 3984 return E_NOTIMPL; 3985 } 3986 3987 HRESULT STDMETHODCALLTYPE CDefView::SetPoints(IDataObject *obj) 3988 { 3989 FIXME("(%p)->(%p) stub\n", this, obj); 3990 return E_NOTIMPL; 3991 } 3992 3993 HRESULT STDMETHODCALLTYPE CDefView::GetItemSpacing(ITEMSPACING *spacing) 3994 { 3995 FIXME("(%p)->(%p) stub\n", this, spacing); 3996 return E_NOTIMPL; 3997 } 3998 3999 HRESULT STDMETHODCALLTYPE CDefView::SetCallback(IShellFolderViewCB *new_cb, IShellFolderViewCB **old_cb) 4000 { 4001 if (old_cb) 4002 *old_cb = m_pShellFolderViewCB.Detach(); 4003 4004 m_pShellFolderViewCB = new_cb; 4005 m_pFolderFilter = NULL; 4006 if (new_cb) 4007 new_cb->QueryInterface(IID_PPV_ARG(IFolderFilter, &m_pFolderFilter)); 4008 return S_OK; 4009 } 4010 4011 HRESULT STDMETHODCALLTYPE CDefView::Select(UINT flags) 4012 { 4013 FIXME("(%p)->(%d) stub\n", this, flags); 4014 return E_NOTIMPL; 4015 } 4016 4017 HRESULT STDMETHODCALLTYPE CDefView::QuerySupport(UINT *support) 4018 { 4019 TRACE("(%p)->(%p)\n", this, support); 4020 return S_OK; 4021 } 4022 4023 HRESULT STDMETHODCALLTYPE CDefView::SetAutomationObject(IDispatch *disp) 4024 { 4025 FIXME("(%p)->(%p) stub\n", this, disp); 4026 return E_NOTIMPL; 4027 } 4028 4029 HRESULT WINAPI CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText) 4030 { 4031 FIXME("(%p)->(%p(%s) 0x%08x %p %p\n", 4032 this, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText); 4033 4034 if (!prgCmds) 4035 return E_INVALIDARG; 4036 4037 for (UINT i = 0; i < cCmds; i++) 4038 { 4039 FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID); 4040 prgCmds[i].cmdf = 0; 4041 } 4042 4043 return OLECMDERR_E_UNKNOWNGROUP; 4044 } 4045 4046 /// 4047 // ISVOleCmdTarget_Exec(IOleCommandTarget) 4048 // 4049 // nCmdID is the OLECMDID_* enumeration 4050 HRESULT WINAPI CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut) 4051 { 4052 FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n", 4053 this, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut); 4054 4055 if (!pguidCmdGroup) 4056 return OLECMDERR_E_UNKNOWNGROUP; 4057 4058 if (IsEqualCLSID(*pguidCmdGroup, m_Category)) 4059 { 4060 if (nCmdID == FCIDM_SHVIEW_AUTOARRANGE) 4061 { 4062 if (V_VT(pvaIn) != VT_INT_PTR) 4063 return OLECMDERR_E_NOTSUPPORTED; 4064 4065 TPMPARAMS params; 4066 params.cbSize = sizeof(params); 4067 params.rcExclude = *(RECT*) V_INTREF(pvaIn); 4068 4069 if (m_hMenuViewModes) 4070 { 4071 // Duplicate all but the last two items of the view modes menu 4072 HMENU hmenuViewPopup = CreatePopupMenu(); 4073 Shell_MergeMenus(hmenuViewPopup, m_hMenuViewModes, 0, 0, 0xFFFF, 0); 4074 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION); 4075 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION); 4076 CheckViewMode(hmenuViewPopup); 4077 TrackPopupMenuEx(hmenuViewPopup, TPM_LEFTALIGN | TPM_TOPALIGN, params.rcExclude.left, params.rcExclude.bottom, m_hWndParent, ¶ms); 4078 ::DestroyMenu(hmenuViewPopup); 4079 } 4080 4081 // pvaOut is VT_I4 with value 0x403 (cmd id of the new mode maybe?) 4082 V_VT(pvaOut) = VT_I4; 4083 V_I4(pvaOut) = 0x403; 4084 } 4085 } 4086 4087 if (IsEqualIID(*pguidCmdGroup, CGID_Explorer) && 4088 (nCmdID == 0x29) && 4089 (nCmdexecopt == 4) && pvaOut) 4090 return S_OK; 4091 4092 if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView) && 4093 (nCmdID == 9) && 4094 (nCmdexecopt == 0)) 4095 return 1; 4096 4097 if (IsEqualIID(*pguidCmdGroup, CGID_DefView)) 4098 { 4099 CComPtr<IStream> pStream; 4100 WCHAR SubKey[MAX_PATH]; 4101 switch (nCmdID) 4102 { 4103 case DVCMDID_SET_DEFAULTFOLDER_SETTINGS: 4104 SHDeleteKey(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\ShellNoRoam\\Bags"); 4105 if (SUCCEEDED(GetDefaultViewStream(STGM_WRITE, &pStream))) 4106 SaveViewState(pStream); 4107 break; 4108 case DVCMDID_RESET_DEFAULTFOLDER_SETTINGS: 4109 wsprintfW(SubKey, L"%s\\%s", REGSTR_PATH_EXPLORER, L"Streams\\Default"); 4110 SHDeleteKey(HKEY_CURRENT_USER, SubKey); 4111 SHDeleteKey(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\ShellNoRoam\\Bags"); 4112 m_FolderSettings.fFlags |= FWF_NOBROWSERVIEWSTATE; // Don't let this folder save itself 4113 break; 4114 } 4115 } 4116 4117 return OLECMDERR_E_UNKNOWNGROUP; 4118 } 4119 4120 /********************************************************** 4121 * ISVDropTarget implementation 4122 */ 4123 4124 /****************************************************************************** 4125 * drag_notify_subitem [Internal] 4126 * 4127 * Figure out the shellfolder object, which is currently under the mouse cursor 4128 * and notify it via the IDropTarget interface. 4129 */ 4130 4131 #define SCROLLAREAWIDTH 20 4132 4133 HRESULT CDefView::drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) 4134 { 4135 LONG lResult; 4136 HRESULT hr; 4137 RECT clientRect; 4138 4139 /* The key state on drop doesn't have MK_LBUTTON or MK_RBUTTON because it 4140 reflects the key state after the user released the button, so we need 4141 to remember the last key state when the button was pressed */ 4142 m_grfKeyState = grfKeyState; 4143 4144 // Map from global to client coordinates and query the index of the 4145 // listview-item, which is currently under the mouse cursor. 4146 LVHITTESTINFO htinfo = {{pt.x, pt.y}, LVHT_ONITEM}; 4147 ScreenToClient(&htinfo.pt); 4148 lResult = m_ListView.HitTest(&htinfo); 4149 4150 /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */ 4151 ::GetClientRect(m_ListView, &clientRect); 4152 if (htinfo.pt.x == m_ptLastMousePos.x && htinfo.pt.y == m_ptLastMousePos.y && 4153 (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH || 4154 htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH)) 4155 { 4156 m_cScrollDelay = (m_cScrollDelay + 1) % 5; // DragOver is called every 50 ms 4157 if (m_cScrollDelay == 0) 4158 { 4159 /* Mouse did hover another 250 ms over the scroll-area */ 4160 if (htinfo.pt.x < SCROLLAREAWIDTH) 4161 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEUP, 0); 4162 4163 if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH) 4164 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEDOWN, 0); 4165 4166 if (htinfo.pt.y < SCROLLAREAWIDTH) 4167 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEUP, 0); 4168 4169 if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH) 4170 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEDOWN, 0); 4171 } 4172 } 4173 else 4174 { 4175 m_cScrollDelay = 0; // Reset, if cursor is not over the listview's scroll-area 4176 } 4177 4178 m_ptLastMousePos = htinfo.pt; 4179 ::ClientToListView(m_ListView, &m_ptLastMousePos); 4180 4181 /* We need to check if we drag the selection over itself */ 4182 if (lResult != -1 && m_pSourceDataObject.p != NULL) 4183 { 4184 PCUITEMID_CHILD pidl = _PidlByItem(lResult); 4185 4186 for (UINT i = 0; i < m_cidl; i++) 4187 { 4188 if (pidl == m_apidl[i]) 4189 { 4190 /* The item that is being draged is hovering itself. */ 4191 lResult = -1; 4192 break; 4193 } 4194 } 4195 } 4196 4197 // If we are still over the previous sub-item, notify it via DragOver and return 4198 if (m_pCurDropTarget && lResult == m_iDragOverItem) 4199 return m_pCurDropTarget->DragOver(grfKeyState, pt, pdwEffect); 4200 4201 // We've left the previous sub-item, notify it via DragLeave and release it 4202 if (m_pCurDropTarget) 4203 { 4204 PCUITEMID_CHILD pidl = _PidlByItem(m_iDragOverItem); 4205 if (pidl) 4206 SelectItem(pidl, 0); 4207 4208 m_pCurDropTarget->DragLeave(); 4209 m_pCurDropTarget.Release(); 4210 } 4211 4212 m_iDragOverItem = lResult; 4213 4214 if (lResult == -1) 4215 { 4216 // We are not above one of the listview's subitems. Bind to the 4217 // parent folder's DropTarget interface. 4218 hr = m_pSFParent->CreateViewObject(NULL, IID_PPV_ARG(IDropTarget,&m_pCurDropTarget)); 4219 } 4220 else 4221 { 4222 // Query the relative PIDL of the shellfolder object represented 4223 // by the currently dragged over listview-item ... 4224 PCUITEMID_CHILD pidl = _PidlByItem(lResult); 4225 4226 // ... and bind m_pCurDropTarget to the IDropTarget interface of an UIObject of this object 4227 hr = m_pSFParent->GetUIObjectOf(m_ListView, 1, &pidl, IID_NULL_PPV_ARG(IDropTarget, &m_pCurDropTarget)); 4228 } 4229 4230 IUnknown_SetSite(m_pCurDropTarget, (IShellView *)this); 4231 4232 // If anything failed, m_pCurDropTarget should be NULL now, which ought to be a save state 4233 if (FAILED(hr)) 4234 { 4235 *pdwEffect = DROPEFFECT_NONE; 4236 return hr; 4237 } 4238 4239 if (m_iDragOverItem != -1) 4240 { 4241 SelectItem(m_iDragOverItem, SVSI_SELECT); 4242 } 4243 4244 // Notify the item just entered via DragEnter 4245 return m_pCurDropTarget->DragEnter(m_pCurDataObject, grfKeyState, pt, pdwEffect); 4246 } 4247 4248 HRESULT WINAPI CDefView::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) 4249 { 4250 if (*pdwEffect == DROPEFFECT_NONE) 4251 return S_OK; 4252 4253 /* Get a hold on the data object for later calls to DragEnter on the sub-folders */ 4254 m_pCurDataObject = pDataObject; 4255 4256 HRESULT hr = drag_notify_subitem(grfKeyState, pt, pdwEffect); 4257 if (SUCCEEDED(hr)) 4258 { 4259 POINT ptClient = {pt.x, pt.y}; 4260 ScreenToClient(&ptClient); 4261 ImageList_DragEnter(m_hWnd, ptClient.x, ptClient.y); 4262 } 4263 4264 return hr; 4265 } 4266 4267 HRESULT WINAPI CDefView::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) 4268 { 4269 POINT ptClient = {pt.x, pt.y}; 4270 ScreenToClient(&ptClient); 4271 ImageList_DragMove(ptClient.x, ptClient.y); 4272 return drag_notify_subitem(grfKeyState, pt, pdwEffect); 4273 } 4274 4275 HRESULT WINAPI CDefView::DragLeave() 4276 { 4277 ImageList_DragLeave(m_hWnd); 4278 4279 if (m_pCurDropTarget) 4280 { 4281 m_pCurDropTarget->DragLeave(); 4282 m_pCurDropTarget.Release(); 4283 } 4284 4285 if (m_pCurDataObject != NULL) 4286 { 4287 m_pCurDataObject.Release(); 4288 } 4289 4290 m_iDragOverItem = 0; 4291 4292 return S_OK; 4293 } 4294 4295 INT CDefView::_FindInsertableIndexFromPoint(POINT pt) 4296 { 4297 RECT rcBound; 4298 INT i, nCount = m_ListView.GetItemCount(); 4299 DWORD dwSpacing; 4300 INT dx, dy; 4301 BOOL bSmall = ((m_ListView.GetStyle() & LVS_TYPEMASK) != LVS_ICON); 4302 4303 // FIXME: LVM_GETORIGIN is broken. See CORE-17266 4304 pt.x += m_ListView.GetScrollPos(SB_HORZ); 4305 pt.y += m_ListView.GetScrollPos(SB_VERT); 4306 4307 if (m_ListView.GetStyle() & LVS_ALIGNLEFT) 4308 { 4309 // vertically 4310 for (i = 0; i < nCount; ++i) 4311 { 4312 dwSpacing = ListView_GetItemSpacing(m_ListView, bSmall); 4313 dx = LOWORD(dwSpacing); 4314 dy = HIWORD(dwSpacing); 4315 ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS); 4316 rcBound.right = rcBound.left + dx; 4317 rcBound.bottom = rcBound.top + dy; 4318 if (pt.x < rcBound.right && pt.y < (rcBound.top + rcBound.bottom) / 2) 4319 { 4320 return i; 4321 } 4322 } 4323 for (i = nCount - 1; i >= 0; --i) 4324 { 4325 ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS); 4326 if (rcBound.left < pt.x && rcBound.top < pt.y) 4327 { 4328 return i + 1; 4329 } 4330 } 4331 } 4332 else 4333 { 4334 // horizontally 4335 for (i = 0; i < nCount; ++i) 4336 { 4337 dwSpacing = ListView_GetItemSpacing(m_ListView, bSmall); 4338 dx = LOWORD(dwSpacing); 4339 dy = HIWORD(dwSpacing); 4340 ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS); 4341 rcBound.right = rcBound.left + dx; 4342 rcBound.bottom = rcBound.top + dy; 4343 if (pt.y < rcBound.bottom && pt.x < rcBound.left) 4344 { 4345 return i; 4346 } 4347 if (pt.y < rcBound.bottom && pt.x < rcBound.right) 4348 { 4349 return i + 1; 4350 } 4351 } 4352 for (i = nCount - 1; i >= 0; --i) 4353 { 4354 ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS); 4355 if (rcBound.left < pt.x && rcBound.top < pt.y) 4356 { 4357 return i + 1; 4358 } 4359 } 4360 } 4361 4362 return nCount; 4363 } 4364 4365 void CDefView::_HandleStatusBarResize(int nWidth) 4366 { 4367 LRESULT lResult; 4368 4369 if (m_isParentFolderSpecial) 4370 { 4371 int nPartArray[] = {-1}; 4372 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, _countof(nPartArray), (LPARAM)nPartArray, &lResult); 4373 return; 4374 } 4375 4376 int nFileSizePartLength = 125; 4377 const int nLocationPartLength = 150; 4378 const int nRightPartsLength = nFileSizePartLength + nLocationPartLength; 4379 int nObjectsPartLength = nWidth - nRightPartsLength; 4380 4381 // If the window is small enough just divide each part into thirds 4382 // to match the behavior of Windows Server 2003 4383 if (nObjectsPartLength <= nLocationPartLength) 4384 nObjectsPartLength = nFileSizePartLength = nWidth / 3; 4385 4386 int nPartArray[] = {nObjectsPartLength, nObjectsPartLength + nFileSizePartLength, -1}; 4387 4388 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, _countof(nPartArray), (LPARAM)nPartArray, &lResult); 4389 } 4390 4391 void CDefView::_ForceStatusBarResize() 4392 { 4393 // Get the handle for the status bar 4394 HWND fStatusBar; 4395 m_pShellBrowser->GetControlWindow(FCW_STATUS, &fStatusBar); 4396 4397 // Get the size of our status bar 4398 RECT statusBarSize; 4399 ::GetWindowRect(fStatusBar, &statusBarSize); 4400 4401 // Resize the status bar 4402 _HandleStatusBarResize(statusBarSize.right - statusBarSize.left); 4403 } 4404 4405 typedef CSimpleMap<LPARAM, INT> CLParamIndexMap; 4406 4407 static INT CALLBACK 4408 SelectionMoveCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) 4409 { 4410 CLParamIndexMap *pmap = (CLParamIndexMap *)lParamSort; 4411 INT i1 = pmap->Lookup(lParam1), i2 = pmap->Lookup(lParam2); 4412 if (i1 < i2) 4413 return -1; 4414 if (i1 > i2) 4415 return 1; 4416 return 0; 4417 } 4418 4419 void CDefView::_MoveSelectionOnAutoArrange(POINT pt) 4420 { 4421 // get insertable index from position 4422 INT iPosition = _FindInsertableIndexFromPoint(pt); 4423 4424 // create identity mapping of indexes 4425 CSimpleArray<INT> array; 4426 INT nCount = m_ListView.GetItemCount(); 4427 for (INT i = 0; i < nCount; ++i) 4428 { 4429 array.Add(i); 4430 } 4431 4432 // re-ordering mapping 4433 INT iItem = -1; 4434 while ((iItem = m_ListView.GetNextItem(iItem, LVNI_SELECTED)) >= 0) 4435 { 4436 INT iFrom = iItem, iTo = iPosition; 4437 if (iFrom < iTo) 4438 --iTo; 4439 if (iFrom >= nCount) 4440 iFrom = nCount - 1; 4441 if (iTo >= nCount) 4442 iTo = nCount - 1; 4443 4444 // shift indexes by swapping (like a bucket relay) 4445 if (iFrom < iTo) 4446 { 4447 for (INT i = iFrom; i < iTo; ++i) 4448 { 4449 // swap array[i] and array[i + 1] 4450 INT tmp = array[i]; 4451 array[i] = array[i + 1]; 4452 array[i + 1] = tmp; 4453 } 4454 } 4455 else 4456 { 4457 for (INT i = iFrom; i > iTo; --i) 4458 { 4459 // swap array[i] and array[i - 1] 4460 INT tmp = array[i]; 4461 array[i] = array[i - 1]; 4462 array[i - 1] = tmp; 4463 } 4464 } 4465 } 4466 4467 // create mapping (ListView's lParam to index) from array 4468 CLParamIndexMap map; 4469 for (INT i = 0; i < nCount; ++i) 4470 { 4471 LPARAM lParam = m_ListView.GetItemData(array[i]); 4472 map.Add(lParam, i); 4473 } 4474 4475 // finally sort 4476 m_ListView.SortItems(SelectionMoveCompareFunc, &map); 4477 } 4478 4479 HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) 4480 { 4481 ImageList_DragLeave(m_hWnd); 4482 ImageList_EndDrag(); 4483 4484 if ((IsDropOnSource(NULL) == S_OK) && 4485 (*pdwEffect & DROPEFFECT_MOVE) && 4486 (m_grfKeyState & MK_LBUTTON)) 4487 { 4488 if (m_pCurDropTarget) 4489 { 4490 m_pCurDropTarget->DragLeave(); 4491 m_pCurDropTarget.Release(); 4492 } 4493 4494 POINT ptDrop = { pt.x, pt.y }; 4495 ::ScreenToClient(m_ListView, &ptDrop); 4496 ::ClientToListView(m_ListView, &ptDrop); 4497 m_ptLastMousePos = ptDrop; 4498 4499 m_ListView.SetRedraw(FALSE); 4500 if (m_ListView.GetStyle() & LVS_AUTOARRANGE) 4501 { 4502 _MoveSelectionOnAutoArrange(m_ptLastMousePos); 4503 } 4504 else 4505 { 4506 POINT ptItem; 4507 INT iItem = -1; 4508 while ((iItem = m_ListView.GetNextItem(iItem, LVNI_SELECTED)) >= 0) 4509 { 4510 if (m_ListView.GetItemPosition(iItem, &ptItem)) 4511 { 4512 ptItem.x += m_ptLastMousePos.x - m_ptFirstMousePos.x; 4513 ptItem.y += m_ptLastMousePos.y - m_ptFirstMousePos.y; 4514 m_ListView.SetItemPosition(iItem, &ptItem); 4515 } 4516 } 4517 } 4518 m_ListView.SetRedraw(TRUE); 4519 } 4520 else if (m_pCurDropTarget) 4521 { 4522 m_pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect); 4523 m_pCurDropTarget.Release(); 4524 } 4525 4526 m_pCurDataObject.Release(); 4527 m_iDragOverItem = 0; 4528 return S_OK; 4529 } 4530 4531 HRESULT WINAPI CDefView::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) 4532 { 4533 TRACE("(%p)\n", this); 4534 4535 if (fEscapePressed) 4536 return DRAGDROP_S_CANCEL; 4537 else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON)) 4538 return DRAGDROP_S_DROP; 4539 else 4540 return S_OK; 4541 } 4542 4543 HRESULT WINAPI CDefView::GiveFeedback(DWORD dwEffect) 4544 { 4545 TRACE("(%p)\n", this); 4546 4547 return DRAGDROP_S_USEDEFAULTCURSORS; 4548 } 4549 4550 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) 4551 { 4552 FIXME("Stub: this=%p\n", this); 4553 return E_NOTIMPL; 4554 } 4555 4556 HRESULT WINAPI CDefView::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet) 4557 { 4558 FIXME("Stub: this=%p\n", this); 4559 return E_NOTIMPL; 4560 } 4561 4562 HRESULT WINAPI CDefView::Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze) 4563 { 4564 FIXME("Stub: this=%p\n", this); 4565 return E_NOTIMPL; 4566 } 4567 4568 HRESULT WINAPI CDefView::Unfreeze(DWORD dwFreeze) 4569 { 4570 FIXME("Stub: this=%p\n", this); 4571 return E_NOTIMPL; 4572 } 4573 4574 HRESULT WINAPI CDefView::SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink) 4575 { 4576 FIXME("partial stub: %p 0x%08x 0x%08x %p\n", this, aspects, advf, pAdvSink); 4577 4578 // FIXME: we set the AdviseSink, but never use it to send any advice 4579 m_pAdvSink = pAdvSink; 4580 m_dwAspects = aspects; 4581 m_dwAdvf = advf; 4582 4583 return S_OK; 4584 } 4585 4586 HRESULT WINAPI CDefView::GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink) 4587 { 4588 TRACE("this=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n", this, pAspects, pAdvf, ppAdvSink); 4589 4590 if (ppAdvSink) 4591 { 4592 *ppAdvSink = m_pAdvSink; 4593 m_pAdvSink.p->AddRef(); 4594 } 4595 4596 if (pAspects) 4597 *pAspects = m_dwAspects; 4598 4599 if (pAdvf) 4600 *pAdvf = m_dwAdvf; 4601 4602 return S_OK; 4603 } 4604 4605 HRESULT STDMETHODCALLTYPE CDefView::QueryService(REFGUID guidService, REFIID riid, void **ppvObject) 4606 { 4607 if (IsEqualIID(guidService, SID_IShellBrowser)) 4608 return m_pShellBrowser->QueryInterface(riid, ppvObject); 4609 else if(IsEqualIID(guidService, SID_IFolderView)) 4610 return QueryInterface(riid, ppvObject); 4611 4612 return E_NOINTERFACE; 4613 } 4614 4615 HRESULT CDefView::_MergeToolbar() 4616 { 4617 CComPtr<IExplorerToolbar> ptb; 4618 HRESULT hr = S_OK; 4619 4620 hr = IUnknown_QueryService(m_pShellBrowser, IID_IExplorerToolbar, IID_PPV_ARG(IExplorerToolbar, &ptb)); 4621 if (FAILED(hr)) 4622 return hr; 4623 4624 m_Category = CGID_DefViewFrame; 4625 4626 hr = ptb->SetCommandTarget(static_cast<IOleCommandTarget*>(this), &m_Category, 0); 4627 if (FAILED(hr)) 4628 return hr; 4629 4630 if (hr == S_FALSE) 4631 return S_OK; 4632 4633 #if 0 4634 hr = ptb->AddButtons(&m_Category, buttonsCount, buttons); 4635 if (FAILED(hr)) 4636 return hr; 4637 #endif 4638 4639 return S_OK; 4640 } 4641 4642 HRESULT CDefView::_DoFolderViewCB(UINT uMsg, WPARAM wParam, LPARAM lParam) 4643 { 4644 HRESULT hr = E_NOTIMPL; 4645 4646 if (m_pShellFolderViewCB) 4647 { 4648 hr = m_pShellFolderViewCB->MessageSFVCB(uMsg, wParam, lParam); 4649 } 4650 4651 return hr; 4652 } 4653 4654 HRESULT CDefView_CreateInstance(IShellFolder *pFolder, REFIID riid, LPVOID * ppvOut) 4655 { 4656 return ShellObjectCreatorInit<CDefView>(pFolder, riid, ppvOut); 4657 } 4658 4659 HRESULT WINAPI SHCreateShellFolderView(const SFV_CREATE *pcsfv, 4660 IShellView **ppsv) 4661 { 4662 CComPtr<IShellView> psv; 4663 HRESULT hRes; 4664 4665 if (!ppsv) 4666 return E_INVALIDARG; 4667 4668 *ppsv = NULL; 4669 4670 if (!pcsfv || pcsfv->cbSize != sizeof(*pcsfv)) 4671 return E_INVALIDARG; 4672 4673 TRACE("sf=%p outer=%p callback=%p\n", 4674 pcsfv->pshf, pcsfv->psvOuter, pcsfv->psfvcb); 4675 4676 hRes = CDefView_CreateInstance(pcsfv->pshf, IID_PPV_ARG(IShellView, &psv)); 4677 if (FAILED(hRes)) 4678 return hRes; 4679 4680 if (pcsfv->psfvcb) 4681 { 4682 CComPtr<IShellFolderView> sfv; 4683 if (SUCCEEDED(psv->QueryInterface(IID_PPV_ARG(IShellFolderView, &sfv)))) 4684 { 4685 sfv->SetCallback(pcsfv->psfvcb, NULL); 4686 } 4687 } 4688 4689 *ppsv = psv.Detach(); 4690 return hRes; 4691 } 4692