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