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