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