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