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