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