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 OnNCDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 312 LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 313 LRESULT OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 314 LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 315 LRESULT OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 316 LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 317 LRESULT OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 318 LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 319 LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 320 LRESULT OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 321 LRESULT OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 322 LRESULT OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 323 LRESULT OnInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 324 325 static ATL::CWndClassInfo& GetWndClassInfo() 326 { 327 static ATL::CWndClassInfo wc = 328 { 329 { sizeof(WNDCLASSEX), CS_PARENTDC, StartWindowProc, 330 0, 0, NULL, NULL, 331 LoadCursor(NULL, IDC_ARROW), NULL, NULL, L"SHELLDLL_DefView", NULL 332 }, 333 NULL, NULL, IDC_ARROW, TRUE, 0, _T("") 334 }; 335 return wc; 336 } 337 338 virtual WNDPROC GetWindowProc() 339 { 340 return WindowProc; 341 } 342 343 static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 344 { 345 CDefView *pThis; 346 LRESULT result; 347 348 // Must hold a reference during message handling 349 pThis = reinterpret_cast<CDefView *>(hWnd); 350 pThis->AddRef(); 351 result = CWindowImpl<CDefView, CWindow, CControlWinTraits>::WindowProc(hWnd, uMsg, wParam, lParam); 352 pThis->Release(); 353 return result; 354 } 355 356 BEGIN_MSG_MAP(CDefView) 357 MESSAGE_HANDLER(WM_SIZE, OnSize) 358 MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) 359 MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus) 360 MESSAGE_HANDLER(WM_NCCREATE, OnNCCreate) 361 MESSAGE_HANDLER(WM_NCDESTROY, OnNCDestroy) 362 MESSAGE_HANDLER(WM_CREATE, OnCreate) 363 MESSAGE_HANDLER(WM_ACTIVATE, OnActivate) 364 MESSAGE_HANDLER(WM_NOTIFY, OnNotify) 365 MESSAGE_HANDLER(WM_COMMAND, OnCommand) 366 MESSAGE_HANDLER(SHV_CHANGE_NOTIFY, OnChangeNotify) 367 MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu) 368 MESSAGE_HANDLER(WM_DRAWITEM, OnCustomItem) 369 MESSAGE_HANDLER(WM_MEASUREITEM, OnCustomItem) 370 MESSAGE_HANDLER(WM_SHOWWINDOW, OnShowWindow) 371 MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode) 372 MESSAGE_HANDLER(WM_DESTROY, OnDestroy) 373 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) 374 MESSAGE_HANDLER(WM_PRINTCLIENT, OnPrintClient) 375 MESSAGE_HANDLER(WM_SYSCOLORCHANGE, OnSysColorChange) 376 MESSAGE_HANDLER(CWM_GETISHELLBROWSER, OnGetShellBrowser) 377 MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) 378 MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup) 379 END_MSG_MAP() 380 381 BEGIN_COM_MAP(CDefView) 382 // Windows returns E_NOINTERFACE for IOleWindow 383 // COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow) 384 COM_INTERFACE_ENTRY_IID(IID_IShellView, IShellView) 385 COM_INTERFACE_ENTRY_IID(IID_CDefView, IShellView) 386 COM_INTERFACE_ENTRY_IID(IID_IShellView2, IShellView2) 387 COM_INTERFACE_ENTRY_IID(IID_IFolderView, IFolderView) 388 COM_INTERFACE_ENTRY_IID(IID_IShellFolderView, IShellFolderView) 389 COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget) 390 COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget) 391 COM_INTERFACE_ENTRY_IID(IID_IDropSource, IDropSource) 392 COM_INTERFACE_ENTRY_IID(IID_IViewObject, IViewObject) 393 COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider) 394 END_COM_MAP() 395 }; 396 397 /*menu items */ 398 #define IDM_VIEW_FILES (FCIDM_SHVIEWFIRST + 0x500) 399 #define IDM_VIEW_IDW (FCIDM_SHVIEWFIRST + 0x501) 400 #define IDM_MYFILEITEM (FCIDM_SHVIEWFIRST + 0x502) 401 402 #define ID_LISTVIEW 1 403 404 /*windowsx.h */ 405 #define GET_WM_COMMAND_ID(wp, lp) LOWORD(wp) 406 #define GET_WM_COMMAND_HWND(wp, lp) (HWND)(lp) 407 #define GET_WM_COMMAND_CMD(wp, lp) HIWORD(wp) 408 409 typedef void (CALLBACK *PFNSHGETSETTINGSPROC)(LPSHELLFLAGSTATE lpsfs, DWORD dwMask); 410 411 CDefView::CDefView() : 412 m_ListView(), 413 m_hWndParent(NULL), 414 m_hMenu(NULL), 415 m_hMenuArrangeModes(NULL), 416 m_hMenuViewModes(NULL), 417 m_hContextMenu(NULL), 418 m_bmenuBarInitialized(FALSE), 419 m_uState(0), 420 m_cidl(0), 421 m_apidl(NULL), 422 m_pidlParent(NULL), 423 m_hNotify(0), 424 m_hAccel(NULL), 425 m_dwAspects(0), 426 m_dwAdvf(0), 427 m_iDragOverItem(0), 428 m_cScrollDelay(0), 429 m_isEditing(FALSE), 430 m_isParentFolderSpecial(FALSE), 431 m_Destroyed(FALSE) 432 { 433 ZeroMemory(&m_FolderSettings, sizeof(m_FolderSettings)); 434 ZeroMemory(&m_sortInfo, sizeof(m_sortInfo)); 435 ZeroMemory(&m_ptLastMousePos, sizeof(m_ptLastMousePos)); 436 ZeroMemory(&m_Category, sizeof(m_Category)); 437 m_viewinfo_data.clrText = GetSysColor(COLOR_WINDOWTEXT); 438 m_viewinfo_data.clrTextBack = GetSysColor(COLOR_WINDOW); 439 m_viewinfo_data.hbmBack = NULL; 440 441 m_hMyComputerIcon = LoadIconW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_COMPUTER_DESKTOP)); 442 } 443 444 CDefView::~CDefView() 445 { 446 TRACE(" destroying IShellView(%p)\n", this); 447 448 _DoFolderViewCB(SFVM_VIEWRELEASE, 0, 0); 449 450 if (m_viewinfo_data.hbmBack) 451 { 452 ::DeleteObject(m_viewinfo_data.hbmBack); 453 m_viewinfo_data.hbmBack = NULL; 454 } 455 456 if (m_hWnd) 457 { 458 DestroyViewWindow(); 459 } 460 461 SHFree(m_apidl); 462 } 463 464 HRESULT WINAPI CDefView::Initialize(IShellFolder *shellFolder) 465 { 466 m_pSFParent = shellFolder; 467 shellFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, &m_pSF2Parent)); 468 469 return S_OK; 470 } 471 472 /********************************************************** 473 * 474 * ##### helperfunctions for communication with ICommDlgBrowser ##### 475 */ 476 HRESULT CDefView::IncludeObject(PCUITEMID_CHILD pidl) 477 { 478 HRESULT ret = S_OK; 479 480 if (m_pCommDlgBrowser.p != NULL) 481 { 482 TRACE("ICommDlgBrowser::IncludeObject pidl=%p\n", pidl); 483 ret = m_pCommDlgBrowser->IncludeObject(this, pidl); 484 TRACE("-- returns 0x%08x\n", ret); 485 } 486 487 return ret; 488 } 489 490 HRESULT CDefView::OnDefaultCommand() 491 { 492 HRESULT ret = S_FALSE; 493 494 if (m_pCommDlgBrowser.p != NULL) 495 { 496 TRACE("ICommDlgBrowser::OnDefaultCommand\n"); 497 ret = m_pCommDlgBrowser->OnDefaultCommand(this); 498 TRACE("-- returns 0x%08x\n", ret); 499 } 500 501 return ret; 502 } 503 504 HRESULT CDefView::OnStateChange(UINT uFlags) 505 { 506 HRESULT ret = S_FALSE; 507 508 if (m_pCommDlgBrowser.p != NULL) 509 { 510 TRACE("ICommDlgBrowser::OnStateChange flags=%x\n", uFlags); 511 ret = m_pCommDlgBrowser->OnStateChange(this, uFlags); 512 TRACE("--\n"); 513 } 514 515 return ret; 516 } 517 /********************************************************** 518 * set the toolbar of the filedialog buttons 519 * 520 * - activates the buttons from the shellbrowser according to 521 * the view state 522 */ 523 void CDefView::CheckToolbar() 524 { 525 LRESULT result; 526 527 TRACE("\n"); 528 529 if (m_pCommDlgBrowser != NULL) 530 { 531 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_CHECKBUTTON, 532 FCIDM_TB_SMALLICON, (m_FolderSettings.ViewMode == FVM_LIST) ? TRUE : FALSE, &result); 533 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_CHECKBUTTON, 534 FCIDM_TB_REPORTVIEW, (m_FolderSettings.ViewMode == FVM_DETAILS) ? TRUE : FALSE, &result); 535 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON, 536 FCIDM_TB_SMALLICON, TRUE, &result); 537 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON, 538 FCIDM_TB_REPORTVIEW, TRUE, &result); 539 } 540 } 541 542 void CDefView::UpdateStatusbar() 543 { 544 WCHAR szFormat[MAX_PATH] = {0}; 545 WCHAR szPartText[MAX_PATH] = {0}; 546 UINT cSelectedItems; 547 548 cSelectedItems = m_ListView.GetSelectedCount(); 549 if (cSelectedItems) 550 { 551 LoadStringW(shell32_hInstance, IDS_OBJECTS_SELECTED, szFormat, _countof(szFormat)); 552 StringCchPrintfW(szPartText, _countof(szPartText), szFormat, cSelectedItems); 553 } 554 else 555 { 556 LoadStringW(shell32_hInstance, IDS_OBJECTS, szFormat, _countof(szFormat)); 557 StringCchPrintfW(szPartText, _countof(szPartText), szFormat, m_ListView.GetItemCount()); 558 } 559 560 LRESULT lResult; 561 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXT, 0, (LPARAM)szPartText, &lResult); 562 563 /* Don't bother with the extra processing if we only have one StatusBar part. */ 564 if (!m_isParentFolderSpecial) 565 { 566 DWORD uTotalFileSize = 0; 567 WORD uFileFlags = LVNI_ALL; 568 LPARAM pIcon = NULL; 569 INT nItem = -1; 570 bool bIsOnlyFoldersSelected = true; 571 572 /* If we have something selected then only count selected file sizes. */ 573 if (cSelectedItems) 574 { 575 uFileFlags = LVNI_SELECTED; 576 } 577 578 while ((nItem = m_ListView.GetNextItem(nItem, uFileFlags)) >= 0) 579 { 580 PCUITEMID_CHILD pidl = _PidlByItem(nItem); 581 582 uTotalFileSize += _ILGetFileSize(pidl, NULL, 0); 583 584 if (!_ILIsFolder(pidl)) 585 { 586 bIsOnlyFoldersSelected = false; 587 } 588 } 589 590 /* Don't show the file size text if there is 0 bytes in the folder 591 * OR we only have folders selected. */ 592 if ((cSelectedItems && !bIsOnlyFoldersSelected) || uTotalFileSize) 593 { 594 StrFormatByteSizeW(uTotalFileSize, szPartText, _countof(szPartText)); 595 } 596 else 597 { 598 *szPartText = 0; 599 } 600 601 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXT, 1, (LPARAM)szPartText, &lResult); 602 603 /* If we are in a Recycle Bin folder then show no text for the location part. */ 604 if (!_ILIsBitBucket(m_pidlParent)) 605 { 606 LoadStringW(shell32_hInstance, IDS_MYCOMPUTER, szPartText, _countof(szPartText)); 607 pIcon = (LPARAM)m_hMyComputerIcon; 608 } 609 610 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETICON, 2, pIcon, &lResult); 611 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXT, 2, (LPARAM)szPartText, &lResult); 612 } 613 } 614 615 /********************************************************** 616 * 617 * ##### helperfunctions for initializing the view ##### 618 */ 619 620 /********************************************************** 621 * ShellView_CreateList() 622 * 623 * - creates the list view window 624 */ 625 BOOL CDefView::CreateList() 626 { 627 HRESULT hr; 628 DWORD dwStyle, dwExStyle; 629 UINT ViewMode; 630 631 TRACE("%p\n", this); 632 633 dwStyle = WS_TABSTOP | WS_VISIBLE | WS_CHILDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | 634 LVS_SHAREIMAGELISTS | LVS_EDITLABELS | LVS_AUTOARRANGE; 635 dwExStyle = WS_EX_CLIENTEDGE; 636 637 if (m_FolderSettings.fFlags & FWF_DESKTOP) 638 dwStyle |= LVS_ALIGNLEFT; 639 else 640 dwStyle |= LVS_ALIGNTOP | LVS_SHOWSELALWAYS; 641 642 ViewMode = m_FolderSettings.ViewMode; 643 hr = _DoFolderViewCB(SFVM_DEFVIEWMODE, 0, (LPARAM)&ViewMode); 644 if (SUCCEEDED(hr)) 645 { 646 if (ViewMode >= FVM_FIRST && ViewMode <= FVM_LAST) 647 m_FolderSettings.ViewMode = ViewMode; 648 else 649 ERR("Ignoring invalid ViewMode from SFVM_DEFVIEWMODE: %u (was: %u)\n", ViewMode, m_FolderSettings.ViewMode); 650 } 651 652 switch (m_FolderSettings.ViewMode) 653 { 654 case FVM_ICON: 655 dwStyle |= LVS_ICON; 656 break; 657 658 case FVM_DETAILS: 659 dwStyle |= LVS_REPORT; 660 break; 661 662 case FVM_SMALLICON: 663 dwStyle |= LVS_SMALLICON; 664 break; 665 666 case FVM_LIST: 667 dwStyle |= LVS_LIST; 668 break; 669 670 default: 671 dwStyle |= LVS_LIST; 672 break; 673 } 674 675 if (m_FolderSettings.fFlags & FWF_AUTOARRANGE) 676 dwStyle |= LVS_AUTOARRANGE; 677 678 if (m_FolderSettings.fFlags & FWF_SNAPTOGRID) 679 dwExStyle |= LVS_EX_SNAPTOGRID; 680 681 if (m_FolderSettings.fFlags & FWF_DESKTOP) 682 m_FolderSettings.fFlags |= FWF_NOCLIENTEDGE | FWF_NOSCROLL; 683 684 if (m_FolderSettings.fFlags & FWF_SINGLESEL) 685 dwStyle |= LVS_SINGLESEL; 686 687 if (m_FolderSettings.fFlags & FWF_NOCLIENTEDGE) 688 dwExStyle &= ~WS_EX_CLIENTEDGE; 689 690 RECT rcListView = {0,0,0,0}; 691 m_ListView.Create(m_hWnd, rcListView, L"FolderView", dwStyle, dwExStyle, ID_LISTVIEW); 692 693 if (!m_ListView) 694 return FALSE; 695 696 m_sortInfo.bIsAscending = TRUE; 697 m_sortInfo.nHeaderID = -1; 698 m_sortInfo.nLastHeaderID = -1; 699 700 /* UpdateShellSettings(); */ 701 return TRUE; 702 } 703 704 void CDefView::UpdateListColors() 705 { 706 if (m_FolderSettings.fFlags & FWF_DESKTOP) 707 { 708 /* Check if drop shadows option is enabled */ 709 BOOL bDropShadow = FALSE; 710 DWORD cbDropShadow = sizeof(bDropShadow); 711 712 /* 713 * The desktop ListView always take the default desktop colours, by 714 * remaining transparent and letting user32/win32k paint itself the 715 * desktop background color, if any. 716 */ 717 m_ListView.SetBkColor(CLR_NONE); 718 719 SHGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced", 720 L"ListviewShadow", NULL, &bDropShadow, &cbDropShadow); 721 if (bDropShadow) 722 { 723 /* Set the icon background transparent */ 724 m_ListView.SetTextBkColor(CLR_NONE); 725 m_ListView.SetTextColor(RGB(255, 255, 255)); 726 m_ListView.SetExtendedListViewStyle(LVS_EX_TRANSPARENTSHADOWTEXT, LVS_EX_TRANSPARENTSHADOWTEXT); 727 } 728 else 729 { 730 /* Set the icon background as the same colour as the desktop */ 731 COLORREF crDesktop = GetSysColor(COLOR_DESKTOP); 732 m_ListView.SetTextBkColor(crDesktop); 733 if (GetRValue(crDesktop) + GetGValue(crDesktop) + GetBValue(crDesktop) > 128 * 3) 734 m_ListView.SetTextColor(RGB(0, 0, 0)); 735 else 736 m_ListView.SetTextColor(RGB(255, 255, 255)); 737 m_ListView.SetExtendedListViewStyle(0, LVS_EX_TRANSPARENTSHADOWTEXT); 738 } 739 } 740 else 741 { 742 // text background color 743 COLORREF clrTextBack = m_viewinfo_data.clrTextBack; 744 m_ListView.SetTextBkColor(clrTextBack); 745 746 // text color 747 COLORREF clrText; 748 if (m_viewinfo_data.clrText != CLR_INVALID) 749 clrText = m_viewinfo_data.clrText; 750 else 751 clrText = GetSysColor(COLOR_WINDOWTEXT); 752 753 m_ListView.SetTextColor(clrText); 754 755 // Background is painted by the parent via WM_PRINTCLIENT. 756 m_ListView.SetExtendedListViewStyle(LVS_EX_TRANSPARENTBKGND, LVS_EX_TRANSPARENTBKGND); 757 } 758 } 759 760 /********************************************************** 761 * ShellView_InitList() 762 * 763 * - adds all needed columns to the shellview 764 */ 765 BOOL CDefView::InitList() 766 { 767 SHELLDETAILS sd; 768 WCHAR szTemp[50]; 769 HIMAGELIST big_icons, small_icons; 770 771 TRACE("%p\n", this); 772 773 m_ListView.DeleteAllItems(); 774 775 m_hMenuArrangeModes = CreateMenu(); 776 777 if (m_pSF2Parent) 778 { 779 for (int i = 0; 1; i++) 780 { 781 if (FAILED(m_pSF2Parent->GetDetailsOf(NULL, i, &sd))) 782 break; 783 StrRetToStrNW( szTemp, 50, &sd.str, NULL); 784 m_ListView.InsertColumn(i, szTemp, sd.fmt, sd.cxChar * 8); 785 786 InsertMenuW(m_hMenuArrangeModes, -1, MF_STRING, 0x30 + i, szTemp); 787 } 788 789 InsertMenuW(m_hMenuArrangeModes, -1, MF_BYPOSITION | MF_SEPARATOR, 0, 0); 790 } 791 else 792 { 793 FIXME("no m_pSF2Parent\n"); 794 } 795 796 Shell_GetImageLists(&big_icons, &small_icons); 797 m_ListView.SetImageList(big_icons, LVSIL_NORMAL); 798 m_ListView.SetImageList(small_icons, LVSIL_SMALL); 799 800 return TRUE; 801 } 802 803 /************************************************************************* 804 * ShellView_ListViewCompareItems 805 * 806 * Compare Function for the Listview (FileOpen Dialog) 807 * 808 * PARAMS 809 * lParam1 [I] the first ItemIdList to compare with 810 * lParam2 [I] the second ItemIdList to compare with 811 * lpData [I] The column ID for the header Ctrl to process 812 * 813 * RETURNS 814 * A negative value if the first item should precede the second, 815 * a positive value if the first item should follow the second, 816 * or zero if the two items are equivalent 817 */ 818 INT CALLBACK CDefView::ListViewCompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lpData) 819 { 820 PCUIDLIST_RELATIVE pidl1 = reinterpret_cast<PCUIDLIST_RELATIVE>(lParam1); 821 PCUIDLIST_RELATIVE pidl2 = reinterpret_cast<PCUIDLIST_RELATIVE>(lParam2); 822 CDefView *pThis = reinterpret_cast<CDefView*>(lpData); 823 824 HRESULT hres = pThis->m_pSFParent->CompareIDs(pThis->m_sortInfo.nHeaderID, pidl1, pidl2); 825 if (FAILED_UNEXPECTEDLY(hres)) 826 return 0; 827 828 SHORT nDiff = HRESULT_CODE(hres); 829 if (!pThis->m_sortInfo.bIsAscending) 830 nDiff = -nDiff; 831 return nDiff; 832 } 833 834 BOOL CDefView::_Sort() 835 { 836 HWND hHeader; 837 HDITEM hColumn; 838 839 if (m_ListView.GetWindowLongPtr(GWL_STYLE) & LVS_NOSORTHEADER) 840 return TRUE; 841 842 hHeader = (HWND)m_ListView.SendMessage(LVM_GETHEADER, 0, 0); 843 ZeroMemory(&hColumn, sizeof(hColumn)); 844 845 /* If the sorting column changed, remove the sorting style from the old column */ 846 if ( (m_sortInfo.nLastHeaderID != -1) && 847 (m_sortInfo.nLastHeaderID != m_sortInfo.nHeaderID) ) 848 { 849 hColumn.mask = HDI_FORMAT; 850 Header_GetItem(hHeader, m_sortInfo.nLastHeaderID, &hColumn); 851 hColumn.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN); 852 Header_SetItem(hHeader, m_sortInfo.nLastHeaderID, &hColumn); 853 } 854 855 /* Set the sorting style to the new column */ 856 hColumn.mask = HDI_FORMAT; 857 Header_GetItem(hHeader, m_sortInfo.nHeaderID, &hColumn); 858 859 hColumn.fmt &= (m_sortInfo.bIsAscending ? ~HDF_SORTDOWN : ~HDF_SORTUP ); 860 hColumn.fmt |= (m_sortInfo.bIsAscending ? HDF_SORTUP : HDF_SORTDOWN); 861 Header_SetItem(hHeader, m_sortInfo.nHeaderID, &hColumn); 862 863 /* Sort the list, using the current values of nHeaderID and bIsAscending */ 864 m_sortInfo.nLastHeaderID = m_sortInfo.nHeaderID; 865 return m_ListView.SortItems(ListViewCompareItems, this); 866 } 867 868 PCUITEMID_CHILD CDefView::_PidlByItem(int i) 869 { 870 return reinterpret_cast<PCUITEMID_CHILD>(m_ListView.GetItemData(i)); 871 } 872 873 PCUITEMID_CHILD CDefView::_PidlByItem(LVITEM& lvItem) 874 { 875 return reinterpret_cast<PCUITEMID_CHILD>(lvItem.lParam); 876 } 877 878 /********************************************************** 879 * LV_FindItemByPidl() 880 */ 881 int CDefView::LV_FindItemByPidl(PCUITEMID_CHILD pidl) 882 { 883 int cItems = m_ListView.GetItemCount(); 884 885 for (int i = 0; i<cItems; i++) 886 { 887 PCUITEMID_CHILD currentpidl = _PidlByItem(i); 888 if (ILIsEqual(pidl, currentpidl)) 889 return i; 890 } 891 return -1; 892 } 893 894 /********************************************************** 895 * LV_AddItem() 896 */ 897 int CDefView::LV_AddItem(PCUITEMID_CHILD pidl) 898 { 899 LVITEMW lvItem; 900 901 TRACE("(%p)(pidl=%p)\n", this, pidl); 902 903 if (_DoFolderViewCB(SFVM_ADDINGOBJECT, 0, (LPARAM)pidl) == S_FALSE) 904 return -1; 905 906 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM; /*set the mask*/ 907 lvItem.iItem = m_ListView.GetItemCount(); /*add the item to the end of the list*/ 908 lvItem.iSubItem = 0; 909 lvItem.lParam = reinterpret_cast<LPARAM>(ILClone(pidl)); /*set the item's data*/ 910 lvItem.pszText = LPSTR_TEXTCALLBACKW; /*get text on a callback basis*/ 911 lvItem.iImage = I_IMAGECALLBACK; /*get the image on a callback basis*/ 912 lvItem.stateMask = LVIS_CUT; 913 914 return m_ListView.InsertItem(&lvItem); 915 } 916 917 /********************************************************** 918 * LV_DeleteItem() 919 */ 920 BOOLEAN CDefView::LV_DeleteItem(PCUITEMID_CHILD pidl) 921 { 922 int nIndex; 923 924 TRACE("(%p)(pidl=%p)\n", this, pidl); 925 926 nIndex = LV_FindItemByPidl(pidl); 927 928 return m_ListView.DeleteItem(nIndex); 929 } 930 931 /********************************************************** 932 * LV_RenameItem() 933 */ 934 BOOLEAN CDefView::LV_RenameItem(PCUITEMID_CHILD pidlOld, PCUITEMID_CHILD pidlNew) 935 { 936 int nItem; 937 LVITEMW lvItem; 938 939 TRACE("(%p)(pidlold=%p pidlnew=%p)\n", this, pidlOld, pidlNew); 940 941 nItem = LV_FindItemByPidl(pidlOld); 942 943 if ( -1 != nItem ) 944 { 945 lvItem.mask = LVIF_PARAM; /* only the pidl */ 946 lvItem.iItem = nItem; 947 lvItem.iSubItem = 0; 948 m_ListView.GetItem(&lvItem); 949 950 LPVOID oldPidl = reinterpret_cast<LPVOID>(lvItem.lParam); /* Store the old pidl until the new item is replaced */ 951 952 lvItem.mask = LVIF_PARAM | LVIF_IMAGE | LVIF_TEXT; 953 lvItem.iItem = nItem; 954 lvItem.iSubItem = 0; 955 lvItem.lParam = reinterpret_cast<LPARAM>(ILClone(pidlNew)); /* set the item's data */ 956 lvItem.pszText = LPSTR_TEXTCALLBACKW; 957 lvItem.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidlNew, 0); 958 m_ListView.SetItem(&lvItem); 959 m_ListView.Update(nItem); 960 961 SHFree(oldPidl); /* Now that the new item is in place, we can safely release the old pidl */ 962 963 return TRUE; /* FIXME: better handling */ 964 } 965 966 return FALSE; 967 } 968 969 /********************************************************** 970 * LV_ProdItem() 971 */ 972 BOOLEAN CDefView::LV_ProdItem(PCUITEMID_CHILD pidl) 973 { 974 int nItem; 975 LVITEMW lvItem; 976 977 TRACE("(%p)(pidl=%p)\n", this, pidl); 978 979 nItem = LV_FindItemByPidl(pidl); 980 981 if (-1 != nItem) 982 { 983 lvItem.mask = LVIF_IMAGE; 984 lvItem.iItem = nItem; 985 lvItem.iSubItem = 0; 986 lvItem.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0); 987 m_ListView.SetItem(&lvItem); 988 m_ListView.Update(nItem); 989 return TRUE; 990 } 991 992 return FALSE; 993 } 994 995 /********************************************************** 996 * ShellView_FillList() 997 * 998 * - gets the objectlist from the shellfolder 999 * - sorts the list 1000 * - fills the list into the view 1001 */ 1002 INT CALLBACK CDefView::fill_list(LPVOID ptr, LPVOID arg) 1003 { 1004 PITEMID_CHILD pidl = static_cast<PITEMID_CHILD>(ptr); 1005 CDefView *pThis = static_cast<CDefView *>(arg); 1006 1007 /* in a commdlg This works as a filemask*/ 1008 if (pThis->IncludeObject(pidl) == S_OK) 1009 pThis->LV_AddItem(pidl); 1010 1011 SHFree(pidl); 1012 return TRUE; 1013 } 1014 1015 HRESULT CDefView::FillList() 1016 { 1017 CComPtr<IEnumIDList> pEnumIDList; 1018 PITEMID_CHILD pidl; 1019 DWORD dwFetched; 1020 HRESULT hRes; 1021 HDPA hdpa; 1022 DWORD dFlags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS; 1023 DWORD dwValue, cbValue; 1024 1025 TRACE("%p\n", this); 1026 1027 /* determine if there is a setting to show all the hidden files/folders */ 1028 dwValue = 1; 1029 cbValue = sizeof(dwValue); 1030 SHGetValueW(HKEY_CURRENT_USER, 1031 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced", 1032 L"Hidden", NULL, &dwValue, &cbValue); 1033 if (dwValue == 1) 1034 { 1035 dFlags |= SHCONTF_INCLUDEHIDDEN; 1036 m_ListView.SendMessageW(LVM_SETCALLBACKMASK, LVIS_CUT, 0); 1037 } 1038 1039 dwValue = 0; 1040 cbValue = sizeof(dwValue); 1041 SHGetValueW(HKEY_CURRENT_USER, 1042 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced", 1043 L"ShowSuperHidden", NULL, &dwValue, &cbValue); 1044 if (dwValue) 1045 { 1046 dFlags |= SHCONTF_INCLUDESUPERHIDDEN; 1047 m_ListView.SendMessageW(LVM_SETCALLBACKMASK, LVIS_CUT, 0); 1048 } 1049 1050 /* get the itemlist from the shfolder */ 1051 hRes = m_pSFParent->EnumObjects(m_hWnd, dFlags, &pEnumIDList); 1052 if (hRes != S_OK) 1053 { 1054 if (hRes == S_FALSE) 1055 return(NOERROR); 1056 return(hRes); 1057 } 1058 1059 /* create a pointer array */ 1060 hdpa = DPA_Create(16); 1061 if (!hdpa) 1062 { 1063 return(E_OUTOFMEMORY); 1064 } 1065 1066 /* copy the items into the array*/ 1067 while((S_OK == pEnumIDList->Next(1, &pidl, &dwFetched)) && dwFetched) 1068 { 1069 if (DPA_InsertPtr(hdpa, 0x7fff, pidl) == -1) 1070 { 1071 SHFree(pidl); 1072 } 1073 } 1074 1075 /*turn the listview's redrawing off*/ 1076 m_ListView.SetRedraw(FALSE); 1077 1078 DPA_DestroyCallback( hdpa, fill_list, this); 1079 1080 /* sort the array */ 1081 if (m_pSF2Parent) 1082 { 1083 m_pSF2Parent->GetDefaultColumn(NULL, (ULONG*)&m_sortInfo.nHeaderID, NULL); 1084 } 1085 else 1086 { 1087 FIXME("no m_pSF2Parent\n"); 1088 } 1089 m_sortInfo.bIsAscending = TRUE; 1090 _Sort(); 1091 1092 if (m_viewinfo_data.hbmBack) 1093 { 1094 ::DeleteObject(m_viewinfo_data.hbmBack); 1095 m_viewinfo_data.hbmBack = NULL; 1096 } 1097 1098 // load custom background image and custom text color 1099 m_viewinfo_data.cbSize = sizeof(m_viewinfo_data); 1100 _DoFolderViewCB(SFVM_GET_CUSTOMVIEWINFO, 0, (LPARAM)&m_viewinfo_data); 1101 1102 /*turn the listview's redrawing back on and force it to draw*/ 1103 m_ListView.SetRedraw(TRUE); 1104 1105 UpdateListColors(); 1106 1107 if (!(m_FolderSettings.fFlags & FWF_DESKTOP)) 1108 { 1109 // redraw now 1110 m_ListView.InvalidateRect(NULL, TRUE); 1111 } 1112 1113 _DoFolderViewCB(SFVM_LISTREFRESHED, 0, 0); 1114 1115 return S_OK; 1116 } 1117 1118 LRESULT CDefView::OnShowWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 1119 { 1120 if (m_ListView.IsWindow()) 1121 m_ListView.UpdateWindow(); 1122 bHandled = FALSE; 1123 return 0; 1124 } 1125 1126 LRESULT CDefView::OnGetDlgCode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 1127 { 1128 return m_ListView.SendMessageW(uMsg, 0, 0); 1129 } 1130 1131 LRESULT CDefView::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 1132 { 1133 if (!m_Destroyed) 1134 { 1135 m_Destroyed = TRUE; 1136 if (m_hMenu) 1137 { 1138 DestroyMenu(m_hMenu); 1139 m_hMenu = NULL; 1140 } 1141 RevokeDragDrop(m_hWnd); 1142 SHChangeNotifyDeregister(m_hNotify); 1143 m_hNotify = NULL; 1144 SHFree(m_pidlParent); 1145 m_pidlParent = NULL; 1146 } 1147 bHandled = FALSE; 1148 return 0; 1149 } 1150 1151 LRESULT CDefView::OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 1152 { 1153 /* redirect to parent */ 1154 if (m_FolderSettings.fFlags & (FWF_DESKTOP | FWF_TRANSPARENT)) 1155 return SendMessageW(GetParent(), WM_ERASEBKGND, wParam, lParam); 1156 1157 bHandled = FALSE; 1158 return 0; 1159 } 1160 1161 static VOID 1162 DrawTileBitmap(HDC hDC, LPCRECT prc, HBITMAP hbm, INT nWidth, INT nHeight, INT dx, INT dy) 1163 { 1164 INT x0 = prc->left, y0 = prc->top, x1 = prc->right, y1 = prc->bottom; 1165 x0 += dx; 1166 y0 += dy; 1167 1168 HDC hMemDC = CreateCompatibleDC(hDC); 1169 HGDIOBJ hbmOld = SelectObject(hMemDC, hbm); 1170 1171 for (INT y = y0; y < y1; y += nHeight) 1172 { 1173 for (INT x = x0; x < x1; x += nWidth) 1174 { 1175 BitBlt(hDC, x, y, nWidth, nHeight, hMemDC, 0, 0, SRCCOPY); 1176 } 1177 } 1178 1179 SelectObject(hMemDC, hbmOld); 1180 DeleteDC(hMemDC); 1181 } 1182 1183 LRESULT CDefView::OnPrintClient(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 1184 { 1185 HDC hDC = (HDC)wParam; 1186 1187 RECT rc; 1188 ::GetClientRect(m_ListView, &rc); 1189 1190 if (m_viewinfo_data.hbmBack) 1191 { 1192 BITMAP bm; 1193 if (::GetObject(m_viewinfo_data.hbmBack, sizeof(BITMAP), &bm)) 1194 { 1195 INT dx = -(::GetScrollPos(m_ListView, SB_HORZ) % bm.bmWidth); 1196 INT dy = -(::GetScrollPos(m_ListView, SB_VERT) % bm.bmHeight); 1197 DrawTileBitmap(hDC, &rc, m_viewinfo_data.hbmBack, bm.bmWidth, bm.bmHeight, dx, dy); 1198 } 1199 } 1200 else 1201 { 1202 FillRect(hDC, &rc, GetSysColorBrush(COLOR_WINDOW)); 1203 } 1204 1205 bHandled = TRUE; 1206 1207 return TRUE; 1208 } 1209 1210 LRESULT CDefView::OnSysColorChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 1211 { 1212 /* Update desktop labels color */ 1213 UpdateListColors(); 1214 1215 /* Forward WM_SYSCOLORCHANGE to common controls */ 1216 return m_ListView.SendMessageW(uMsg, 0, 0); 1217 } 1218 1219 LRESULT CDefView::OnGetShellBrowser(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 1220 { 1221 return reinterpret_cast<LRESULT>(m_pShellBrowser.p); 1222 } 1223 1224 LRESULT CDefView::OnNCCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 1225 { 1226 this->AddRef(); 1227 bHandled = FALSE; 1228 return 0; 1229 } 1230 1231 LRESULT CDefView::OnNCDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 1232 { 1233 this->Release(); 1234 bHandled = FALSE; 1235 return 0; 1236 } 1237 1238 /********************************************************** 1239 * ShellView_OnCreate() 1240 */ 1241 LRESULT CDefView::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 1242 { 1243 CComPtr<IDropTarget> pdt; 1244 CComPtr<IPersistFolder2> ppf2; 1245 1246 TRACE("%p\n", this); 1247 1248 if (SUCCEEDED(QueryInterface(IID_PPV_ARG(IDropTarget, &pdt)))) 1249 { 1250 if (FAILED(RegisterDragDrop(m_hWnd, pdt))) 1251 ERR("Registering Drag Drop Failed\n"); 1252 } 1253 1254 /* register for receiving notifications */ 1255 m_pSFParent->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2)); 1256 if (ppf2) 1257 { 1258 ppf2->GetCurFolder(&m_pidlParent); 1259 } 1260 1261 if (CreateList()) 1262 { 1263 if (InitList()) 1264 { 1265 FillList(); 1266 } 1267 } 1268 1269 if (m_FolderSettings.fFlags & FWF_DESKTOP) 1270 { 1271 HWND hwndSB; 1272 m_pShellBrowser->GetWindow(&hwndSB); 1273 SetShellWindowEx(hwndSB, m_ListView); 1274 } 1275 1276 SHChangeNotifyEntry ntreg[1]; 1277 ntreg[0].fRecursive = FALSE; 1278 ntreg[0].pidl = m_pidlParent; 1279 m_hNotify = SHChangeNotifyRegister(m_hWnd, 1280 SHCNRF_InterruptLevel | SHCNRF_ShellLevel | 1281 SHCNRF_NewDelivery, 1282 SHCNE_ALLEVENTS, SHV_CHANGE_NOTIFY, 1283 1, ntreg); 1284 1285 /* _DoFolderViewCB(SFVM_GETNOTIFY, ?? ??) */ 1286 1287 m_hAccel = LoadAcceleratorsW(shell32_hInstance, MAKEINTRESOURCEW(IDA_SHELLVIEW)); 1288 1289 BOOL bPreviousParentSpecial = m_isParentFolderSpecial; 1290 1291 /* A folder is special if it is the Desktop folder, 1292 * a network folder, or a Control Panel folder. */ 1293 m_isParentFolderSpecial = _ILIsDesktop(m_pidlParent) || _ILIsNetHood(m_pidlParent) 1294 || _ILIsControlPanel(ILFindLastID(m_pidlParent)); 1295 1296 /* Only force StatusBar part refresh if the state 1297 * changed from the previous folder. */ 1298 if (bPreviousParentSpecial != m_isParentFolderSpecial) 1299 { 1300 /* This handles changing StatusBar parts. */ 1301 _ForceStatusBarResize(); 1302 } 1303 1304 UpdateStatusbar(); 1305 1306 return S_OK; 1307 } 1308 1309 /********************************************************** 1310 * #### Handling of the menus #### 1311 */ 1312 1313 extern "C" DWORD WINAPI SHMenuIndexFromID(HMENU hMenu, UINT uID); 1314 1315 HMENU GetSubmenuByID(HMENU hmenu, UINT id) 1316 { 1317 MENUITEMINFOW mii = {sizeof(mii), MIIM_SUBMENU}; 1318 if (::GetMenuItemInfoW(hmenu, id, FALSE, &mii)) 1319 return mii.hSubMenu; 1320 1321 return NULL; 1322 } 1323 1324 /* ReallyGetMenuItemID returns the id of an item even if it opens a submenu, 1325 GetMenuItemID returns -1 if the specified item opens a submenu */ 1326 UINT ReallyGetMenuItemID(HMENU hmenu, int i) 1327 { 1328 MENUITEMINFOW mii = {sizeof(mii), MIIM_ID}; 1329 if (::GetMenuItemInfoW(hmenu, i, TRUE, &mii)) 1330 return mii.wID; 1331 1332 return UINT_MAX; 1333 } 1334 1335 HRESULT CDefView::FillFileMenu() 1336 { 1337 HMENU hFileMenu = GetSubmenuByID(m_hMenu, FCIDM_MENU_FILE); 1338 if (!hFileMenu) 1339 return E_FAIL; 1340 1341 /* Cleanup the items added previously */ 1342 for (int i = GetMenuItemCount(hFileMenu) - 1; i >= 0; i--) 1343 { 1344 UINT id = GetMenuItemID(hFileMenu, i); 1345 if (id < FCIDM_BROWSERFIRST || id > FCIDM_BROWSERLAST) 1346 DeleteMenu(hFileMenu, i, MF_BYPOSITION); 1347 } 1348 1349 m_cidl = m_ListView.GetSelectedCount(); 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((m_cidl ? SVGIO_SELECTION : SVGIO_BACKGROUND), 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 (pidl) 3118 { 3119 *item = LV_FindItemByPidl(ILFindLastID(pidl)); 3120 m_ListView.DeleteItem(*item); 3121 } 3122 else 3123 { 3124 *item = 0; 3125 m_ListView.DeleteAllItems(); 3126 } 3127 3128 return S_OK; 3129 } 3130 3131 HRESULT STDMETHODCALLTYPE CDefView::GetObjectCount(UINT *count) 3132 { 3133 TRACE("(%p)->(%p)\n", this, count); 3134 *count = m_ListView.GetItemCount(); 3135 return S_OK; 3136 } 3137 3138 HRESULT STDMETHODCALLTYPE CDefView::SetObjectCount(UINT count, UINT flags) 3139 { 3140 FIXME("(%p)->(%d %x) stub\n", this, count, flags); 3141 return E_NOTIMPL; 3142 } 3143 3144 HRESULT STDMETHODCALLTYPE CDefView::UpdateObject(PITEMID_CHILD pidl_old, PITEMID_CHILD pidl_new, UINT *item) 3145 { 3146 FIXME("(%p)->(%p %p %p) stub\n", this, pidl_old, pidl_new, item); 3147 return E_NOTIMPL; 3148 } 3149 3150 HRESULT STDMETHODCALLTYPE CDefView::RefreshObject(PITEMID_CHILD pidl, UINT *item) 3151 { 3152 FIXME("(%p)->(%p %p) stub\n", this, pidl, item); 3153 return E_NOTIMPL; 3154 } 3155 3156 HRESULT STDMETHODCALLTYPE CDefView::SetRedraw(BOOL redraw) 3157 { 3158 TRACE("(%p)->(%d)\n", this, redraw); 3159 m_ListView.SetRedraw(redraw); 3160 return S_OK; 3161 } 3162 3163 HRESULT STDMETHODCALLTYPE CDefView::GetSelectedCount(UINT *count) 3164 { 3165 FIXME("(%p)->(%p) stub\n", this, count); 3166 return E_NOTIMPL; 3167 } 3168 3169 HRESULT STDMETHODCALLTYPE CDefView::GetSelectedObjects(PCUITEMID_CHILD **pidl, UINT *items) 3170 { 3171 TRACE("(%p)->(%p %p)\n", this, pidl, items); 3172 3173 *items = GetSelections(); 3174 3175 if (*items) 3176 { 3177 *pidl = static_cast<PCUITEMID_CHILD *>(LocalAlloc(0, *items * sizeof(PCUITEMID_CHILD))); 3178 if (!*pidl) 3179 { 3180 return E_OUTOFMEMORY; 3181 } 3182 3183 /* it's documented that caller shouldn't PIDLs, only array itself */ 3184 memcpy(*pidl, m_apidl, *items * sizeof(PCUITEMID_CHILD)); 3185 } 3186 3187 return S_OK; 3188 } 3189 3190 HRESULT STDMETHODCALLTYPE CDefView::IsDropOnSource(IDropTarget *drop_target) 3191 { 3192 if ((m_iDragOverItem == -1 || m_pCurDropTarget == NULL) && 3193 (m_pSourceDataObject.p)) 3194 { 3195 return S_OK; 3196 } 3197 3198 return S_FALSE; 3199 } 3200 3201 HRESULT STDMETHODCALLTYPE CDefView::GetDragPoint(POINT *pt) 3202 { 3203 if (!pt) 3204 return E_INVALIDARG; 3205 3206 *pt = m_ptFirstMousePos; 3207 return S_OK; 3208 } 3209 3210 HRESULT STDMETHODCALLTYPE CDefView::GetDropPoint(POINT *pt) 3211 { 3212 FIXME("(%p)->(%p) stub\n", this, pt); 3213 return E_NOTIMPL; 3214 } 3215 3216 HRESULT STDMETHODCALLTYPE CDefView::MoveIcons(IDataObject *obj) 3217 { 3218 TRACE("(%p)->(%p)\n", this, obj); 3219 return E_NOTIMPL; 3220 } 3221 3222 HRESULT STDMETHODCALLTYPE CDefView::SetItemPos(PCUITEMID_CHILD pidl, POINT *pt) 3223 { 3224 FIXME("(%p)->(%p %p) stub\n", this, pidl, pt); 3225 return E_NOTIMPL; 3226 } 3227 3228 HRESULT STDMETHODCALLTYPE CDefView::IsBkDropTarget(IDropTarget *drop_target) 3229 { 3230 FIXME("(%p)->(%p) stub\n", this, drop_target); 3231 return E_NOTIMPL; 3232 } 3233 3234 HRESULT STDMETHODCALLTYPE CDefView::SetClipboard(BOOL move) 3235 { 3236 FIXME("(%p)->(%d) stub\n", this, move); 3237 return E_NOTIMPL; 3238 } 3239 3240 HRESULT STDMETHODCALLTYPE CDefView::SetPoints(IDataObject *obj) 3241 { 3242 FIXME("(%p)->(%p) stub\n", this, obj); 3243 return E_NOTIMPL; 3244 } 3245 3246 HRESULT STDMETHODCALLTYPE CDefView::GetItemSpacing(ITEMSPACING *spacing) 3247 { 3248 FIXME("(%p)->(%p) stub\n", this, spacing); 3249 return E_NOTIMPL; 3250 } 3251 3252 HRESULT STDMETHODCALLTYPE CDefView::SetCallback(IShellFolderViewCB *new_cb, IShellFolderViewCB **old_cb) 3253 { 3254 if (old_cb) 3255 *old_cb = m_pShellFolderViewCB.Detach(); 3256 3257 m_pShellFolderViewCB = new_cb; 3258 return S_OK; 3259 } 3260 3261 HRESULT STDMETHODCALLTYPE CDefView::Select(UINT flags) 3262 { 3263 FIXME("(%p)->(%d) stub\n", this, flags); 3264 return E_NOTIMPL; 3265 } 3266 3267 HRESULT STDMETHODCALLTYPE CDefView::QuerySupport(UINT *support) 3268 { 3269 TRACE("(%p)->(%p)\n", this, support); 3270 return S_OK; 3271 } 3272 3273 HRESULT STDMETHODCALLTYPE CDefView::SetAutomationObject(IDispatch *disp) 3274 { 3275 FIXME("(%p)->(%p) stub\n", this, disp); 3276 return E_NOTIMPL; 3277 } 3278 3279 /********************************************************** 3280 * ISVOleCmdTarget_QueryStatus (IOleCommandTarget) 3281 */ 3282 HRESULT WINAPI CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText) 3283 { 3284 FIXME("(%p)->(%p(%s) 0x%08x %p %p\n", 3285 this, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText); 3286 3287 if (!prgCmds) 3288 return E_INVALIDARG; 3289 3290 for (UINT i = 0; i < cCmds; i++) 3291 { 3292 FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID); 3293 prgCmds[i].cmdf = 0; 3294 } 3295 3296 return OLECMDERR_E_UNKNOWNGROUP; 3297 } 3298 3299 /********************************************************** 3300 * ISVOleCmdTarget_Exec (IOleCommandTarget) 3301 * 3302 * nCmdID is the OLECMDID_* enumeration 3303 */ 3304 HRESULT WINAPI CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut) 3305 { 3306 FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n", 3307 this, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut); 3308 3309 if (!pguidCmdGroup) 3310 return OLECMDERR_E_UNKNOWNGROUP; 3311 3312 if (IsEqualCLSID(*pguidCmdGroup, m_Category)) 3313 { 3314 if (nCmdID == FCIDM_SHVIEW_AUTOARRANGE) 3315 { 3316 if (V_VT(pvaIn) != VT_INT_PTR) 3317 return OLECMDERR_E_NOTSUPPORTED; 3318 3319 TPMPARAMS params; 3320 params.cbSize = sizeof(params); 3321 params.rcExclude = *(RECT*) V_INTREF(pvaIn); 3322 3323 if (m_hMenuViewModes) 3324 { 3325 /* Duplicate all but the last two items of the view modes menu */ 3326 HMENU hmenuViewPopup = CreatePopupMenu(); 3327 Shell_MergeMenus(hmenuViewPopup, m_hMenuViewModes, 0, 0, 0xFFFF, 0); 3328 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION); 3329 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION); 3330 CheckViewMode(hmenuViewPopup); 3331 TrackPopupMenuEx(hmenuViewPopup, TPM_LEFTALIGN | TPM_TOPALIGN, params.rcExclude.left, params.rcExclude.bottom, m_hWndParent, ¶ms); 3332 ::DestroyMenu(hmenuViewPopup); 3333 } 3334 3335 // pvaOut is VT_I4 with value 0x403 (cmd id of the new mode maybe?) 3336 V_VT(pvaOut) = VT_I4; 3337 V_I4(pvaOut) = 0x403; 3338 } 3339 } 3340 3341 if (IsEqualIID(*pguidCmdGroup, CGID_Explorer) && 3342 (nCmdID == 0x29) && 3343 (nCmdexecopt == 4) && pvaOut) 3344 return S_OK; 3345 3346 if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView) && 3347 (nCmdID == 9) && 3348 (nCmdexecopt == 0)) 3349 return 1; 3350 3351 return OLECMDERR_E_UNKNOWNGROUP; 3352 } 3353 3354 /********************************************************** 3355 * ISVDropTarget implementation 3356 */ 3357 3358 /****************************************************************************** 3359 * drag_notify_subitem [Internal] 3360 * 3361 * Figure out the shellfolder object, which is currently under the mouse cursor 3362 * and notify it via the IDropTarget interface. 3363 */ 3364 3365 #define SCROLLAREAWIDTH 20 3366 3367 HRESULT CDefView::drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) 3368 { 3369 LONG lResult; 3370 HRESULT hr; 3371 RECT clientRect; 3372 3373 /* The key state on drop doesn't have MK_LBUTTON or MK_RBUTTON because it 3374 reflects the key state after the user released the button, so we need 3375 to remember the last key state when the button was pressed */ 3376 m_grfKeyState = grfKeyState; 3377 3378 /* Map from global to client coordinates and query the index of the listview-item, which is 3379 * currently under the mouse cursor. */ 3380 LVHITTESTINFO htinfo = {{pt.x, pt.y}, LVHT_ONITEM}; 3381 ScreenToClient(&htinfo.pt); 3382 lResult = m_ListView.HitTest(&htinfo); 3383 3384 /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */ 3385 ::GetClientRect(m_ListView, &clientRect); 3386 if (htinfo.pt.x == m_ptLastMousePos.x && htinfo.pt.y == m_ptLastMousePos.y && 3387 (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH || 3388 htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH )) 3389 { 3390 m_cScrollDelay = (m_cScrollDelay + 1) % 5; /* DragOver is called every 50 ms */ 3391 if (m_cScrollDelay == 0) 3392 { 3393 /* Mouse did hover another 250 ms over the scroll-area */ 3394 if (htinfo.pt.x < SCROLLAREAWIDTH) 3395 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEUP, 0); 3396 3397 if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH) 3398 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEDOWN, 0); 3399 3400 if (htinfo.pt.y < SCROLLAREAWIDTH) 3401 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEUP, 0); 3402 3403 if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH) 3404 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEDOWN, 0); 3405 } 3406 } 3407 else 3408 { 3409 m_cScrollDelay = 0; /* Reset, if the cursor is not over the listview's scroll-area */ 3410 } 3411 3412 m_ptLastMousePos = htinfo.pt; 3413 ::ClientToListView(m_ListView, &m_ptLastMousePos); 3414 3415 /* We need to check if we drag the selection over itself */ 3416 if (lResult != -1 && m_pSourceDataObject.p != NULL) 3417 { 3418 PCUITEMID_CHILD pidl = _PidlByItem(lResult); 3419 3420 for (UINT i = 0; i < m_cidl; i++) 3421 { 3422 if (pidl == m_apidl[i]) 3423 { 3424 /* The item that is being draged is hovering itself. */ 3425 lResult = -1; 3426 break; 3427 } 3428 } 3429 } 3430 3431 /* If we are still over the previous sub-item, notify it via DragOver and return. */ 3432 if (m_pCurDropTarget && lResult == m_iDragOverItem) 3433 return m_pCurDropTarget->DragOver(grfKeyState, pt, pdwEffect); 3434 3435 /* We've left the previous sub-item, notify it via DragLeave and Release it. */ 3436 if (m_pCurDropTarget) 3437 { 3438 PCUITEMID_CHILD pidl = _PidlByItem(m_iDragOverItem); 3439 if (pidl) 3440 SelectItem(pidl, 0); 3441 3442 m_pCurDropTarget->DragLeave(); 3443 m_pCurDropTarget.Release(); 3444 } 3445 3446 m_iDragOverItem = lResult; 3447 3448 if (lResult == -1) 3449 { 3450 /* We are not above one of the listview's subitems. Bind to the parent folder's 3451 * DropTarget interface. */ 3452 hr = m_pSFParent->CreateViewObject(NULL, IID_PPV_ARG(IDropTarget,&m_pCurDropTarget)); 3453 } 3454 else 3455 { 3456 /* Query the relative PIDL of the shellfolder object represented by the currently 3457 * dragged over listview-item ... */ 3458 PCUITEMID_CHILD pidl = _PidlByItem(lResult); 3459 3460 /* ... and bind m_pCurDropTarget to the IDropTarget interface of an UIObject of this object */ 3461 hr = m_pSFParent->GetUIObjectOf(m_ListView, 1, &pidl, IID_NULL_PPV_ARG(IDropTarget, &m_pCurDropTarget)); 3462 } 3463 3464 IUnknown_SetSite(m_pCurDropTarget, (IShellView *)this); 3465 3466 /* If anything failed, m_pCurDropTarget should be NULL now, which ought to be a save state. */ 3467 if (FAILED(hr)) 3468 { 3469 *pdwEffect = DROPEFFECT_NONE; 3470 return hr; 3471 } 3472 3473 if (m_iDragOverItem != -1) 3474 { 3475 SelectItem(m_iDragOverItem, SVSI_SELECT); 3476 } 3477 3478 /* Notify the item just entered via DragEnter. */ 3479 return m_pCurDropTarget->DragEnter(m_pCurDataObject, grfKeyState, pt, pdwEffect); 3480 } 3481 3482 HRESULT WINAPI CDefView::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) 3483 { 3484 if (*pdwEffect == DROPEFFECT_NONE) 3485 return S_OK; 3486 3487 /* Get a hold on the data object for later calls to DragEnter on the sub-folders */ 3488 m_pCurDataObject = pDataObject; 3489 3490 HRESULT hr = drag_notify_subitem(grfKeyState, pt, pdwEffect); 3491 if (SUCCEEDED(hr)) 3492 { 3493 POINT ptClient = {pt.x, pt.y}; 3494 ScreenToClient(&ptClient); 3495 ImageList_DragEnter(m_hWnd, ptClient.x, ptClient.y); 3496 } 3497 3498 return hr; 3499 } 3500 3501 HRESULT WINAPI CDefView::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) 3502 { 3503 POINT ptClient = {pt.x, pt.y}; 3504 ScreenToClient(&ptClient); 3505 ImageList_DragMove(ptClient.x, ptClient.y); 3506 return drag_notify_subitem(grfKeyState, pt, pdwEffect); 3507 } 3508 3509 HRESULT WINAPI CDefView::DragLeave() 3510 { 3511 ImageList_DragLeave(m_hWnd); 3512 3513 if (m_pCurDropTarget) 3514 { 3515 m_pCurDropTarget->DragLeave(); 3516 m_pCurDropTarget.Release(); 3517 } 3518 3519 if (m_pCurDataObject != NULL) 3520 { 3521 m_pCurDataObject.Release(); 3522 } 3523 3524 m_iDragOverItem = 0; 3525 3526 return S_OK; 3527 } 3528 3529 INT CDefView::_FindInsertableIndexFromPoint(POINT pt) 3530 { 3531 RECT rcBound; 3532 INT i, nCount = m_ListView.GetItemCount(); 3533 DWORD dwSpacing; 3534 INT dx, dy; 3535 BOOL bSmall = ((m_ListView.GetStyle() & LVS_TYPEMASK) != LVS_ICON); 3536 3537 /* FIXME: LVM_GETORIGIN is broken. See CORE-17266 */ 3538 pt.x += m_ListView.GetScrollPos(SB_HORZ); 3539 pt.y += m_ListView.GetScrollPos(SB_VERT); 3540 3541 if (m_ListView.GetStyle() & LVS_ALIGNLEFT) 3542 { 3543 // vertically 3544 for (i = 0; i < nCount; ++i) 3545 { 3546 dwSpacing = ListView_GetItemSpacing(m_ListView, bSmall); 3547 dx = LOWORD(dwSpacing); 3548 dy = HIWORD(dwSpacing); 3549 ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS); 3550 rcBound.right = rcBound.left + dx; 3551 rcBound.bottom = rcBound.top + dy; 3552 if (pt.x < rcBound.right && pt.y < (rcBound.top + rcBound.bottom) / 2) 3553 { 3554 return i; 3555 } 3556 } 3557 for (i = nCount - 1; i >= 0; --i) 3558 { 3559 ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS); 3560 if (rcBound.left < pt.x && rcBound.top < pt.y) 3561 { 3562 return i + 1; 3563 } 3564 } 3565 } 3566 else 3567 { 3568 // horizontally 3569 for (i = 0; i < nCount; ++i) 3570 { 3571 dwSpacing = ListView_GetItemSpacing(m_ListView, bSmall); 3572 dx = LOWORD(dwSpacing); 3573 dy = HIWORD(dwSpacing); 3574 ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS); 3575 rcBound.right = rcBound.left + dx; 3576 rcBound.bottom = rcBound.top + dy; 3577 if (pt.y < rcBound.bottom && pt.x < rcBound.left) 3578 { 3579 return i; 3580 } 3581 if (pt.y < rcBound.bottom && pt.x < rcBound.right) 3582 { 3583 return i + 1; 3584 } 3585 } 3586 for (i = nCount - 1; i >= 0; --i) 3587 { 3588 ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS); 3589 if (rcBound.left < pt.x && rcBound.top < pt.y) 3590 { 3591 return i + 1; 3592 } 3593 } 3594 } 3595 3596 return nCount; 3597 } 3598 3599 void CDefView::_HandleStatusBarResize(int nWidth) 3600 { 3601 LRESULT lResult; 3602 3603 if (m_isParentFolderSpecial) 3604 { 3605 int nPartArray[] = {-1}; 3606 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, _countof(nPartArray), (LPARAM)nPartArray, &lResult); 3607 return; 3608 } 3609 3610 int nFileSizePartLength = 125; 3611 const int nLocationPartLength = 150; 3612 const int nRightPartsLength = nFileSizePartLength + nLocationPartLength; 3613 int nObjectsPartLength = nWidth - nRightPartsLength; 3614 3615 /* If the window is small enough just divide each part into thirds 3616 * This is the behavior of Windows Server 2003. */ 3617 if (nObjectsPartLength <= nLocationPartLength) 3618 nObjectsPartLength = nFileSizePartLength = nWidth / 3; 3619 3620 int nPartArray[] = {nObjectsPartLength, nObjectsPartLength + nFileSizePartLength, -1}; 3621 3622 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, _countof(nPartArray), (LPARAM)nPartArray, &lResult); 3623 } 3624 3625 void CDefView::_ForceStatusBarResize() 3626 { 3627 /* Get the handle for the status bar */ 3628 HWND fStatusBar; 3629 m_pShellBrowser->GetControlWindow(FCW_STATUS, &fStatusBar); 3630 3631 /* Get the size of our status bar */ 3632 RECT statusBarSize; 3633 ::GetWindowRect(fStatusBar, &statusBarSize); 3634 3635 /* Resize the status bar */ 3636 _HandleStatusBarResize(statusBarSize.right - statusBarSize.left); 3637 } 3638 3639 typedef CSimpleMap<LPARAM, INT> CLParamIndexMap; 3640 3641 static INT CALLBACK 3642 SelectionMoveCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) 3643 { 3644 CLParamIndexMap *pmap = (CLParamIndexMap *)lParamSort; 3645 INT i1 = pmap->Lookup(lParam1), i2 = pmap->Lookup(lParam2); 3646 if (i1 < i2) 3647 return -1; 3648 if (i1 > i2) 3649 return 1; 3650 return 0; 3651 } 3652 3653 void CDefView::_MoveSelectionOnAutoArrange(POINT pt) 3654 { 3655 // get insertable index from position 3656 INT iPosition = _FindInsertableIndexFromPoint(pt); 3657 3658 // create identity mapping of indexes 3659 CSimpleArray<INT> array; 3660 INT nCount = m_ListView.GetItemCount(); 3661 for (INT i = 0; i < nCount; ++i) 3662 { 3663 array.Add(i); 3664 } 3665 3666 // re-ordering mapping 3667 INT iItem = -1; 3668 while ((iItem = m_ListView.GetNextItem(iItem, LVNI_SELECTED)) >= 0) 3669 { 3670 INT iFrom = iItem, iTo = iPosition; 3671 if (iFrom < iTo) 3672 --iTo; 3673 if (iFrom >= nCount) 3674 iFrom = nCount - 1; 3675 if (iTo >= nCount) 3676 iTo = nCount - 1; 3677 3678 // shift indexes by swapping (like a bucket relay) 3679 if (iFrom < iTo) 3680 { 3681 for (INT i = iFrom; i < iTo; ++i) 3682 { 3683 // swap array[i] and array[i + 1] 3684 INT tmp = array[i]; 3685 array[i] = array[i + 1]; 3686 array[i + 1] = tmp; 3687 } 3688 } 3689 else 3690 { 3691 for (INT i = iFrom; i > iTo; --i) 3692 { 3693 // swap array[i] and array[i - 1] 3694 INT tmp = array[i]; 3695 array[i] = array[i - 1]; 3696 array[i - 1] = tmp; 3697 } 3698 } 3699 } 3700 3701 // create mapping (ListView's lParam to index) from array 3702 CLParamIndexMap map; 3703 for (INT i = 0; i < nCount; ++i) 3704 { 3705 LPARAM lParam = m_ListView.GetItemData(array[i]); 3706 map.Add(lParam, i); 3707 } 3708 3709 // finally sort 3710 m_ListView.SortItems(SelectionMoveCompareFunc, &map); 3711 } 3712 3713 HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) 3714 { 3715 ImageList_DragLeave(m_hWnd); 3716 ImageList_EndDrag(); 3717 3718 if ((IsDropOnSource(NULL) == S_OK) && 3719 (*pdwEffect & DROPEFFECT_MOVE) && 3720 (m_grfKeyState & MK_LBUTTON)) 3721 { 3722 if (m_pCurDropTarget) 3723 { 3724 m_pCurDropTarget->DragLeave(); 3725 m_pCurDropTarget.Release(); 3726 } 3727 3728 POINT ptDrop = { pt.x, pt.y }; 3729 ::ScreenToClient(m_ListView, &ptDrop); 3730 ::ClientToListView(m_ListView, &ptDrop); 3731 m_ptLastMousePos = ptDrop; 3732 3733 m_ListView.SetRedraw(FALSE); 3734 if (m_ListView.GetStyle() & LVS_AUTOARRANGE) 3735 { 3736 _MoveSelectionOnAutoArrange(m_ptLastMousePos); 3737 } 3738 else 3739 { 3740 POINT ptItem; 3741 INT iItem = -1; 3742 while ((iItem = m_ListView.GetNextItem(iItem, LVNI_SELECTED)) >= 0) 3743 { 3744 if (m_ListView.GetItemPosition(iItem, &ptItem)) 3745 { 3746 ptItem.x += m_ptLastMousePos.x - m_ptFirstMousePos.x; 3747 ptItem.y += m_ptLastMousePos.y - m_ptFirstMousePos.y; 3748 m_ListView.SetItemPosition(iItem, &ptItem); 3749 } 3750 } 3751 } 3752 m_ListView.SetRedraw(TRUE); 3753 } 3754 else if (m_pCurDropTarget) 3755 { 3756 m_pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect); 3757 m_pCurDropTarget.Release(); 3758 } 3759 3760 m_pCurDataObject.Release(); 3761 m_iDragOverItem = 0; 3762 return S_OK; 3763 } 3764 3765 /********************************************************** 3766 * ISVDropSource implementation 3767 */ 3768 3769 HRESULT WINAPI CDefView::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) 3770 { 3771 TRACE("(%p)\n", this); 3772 3773 if (fEscapePressed) 3774 return DRAGDROP_S_CANCEL; 3775 else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON)) 3776 return DRAGDROP_S_DROP; 3777 else 3778 return S_OK; 3779 } 3780 3781 HRESULT WINAPI CDefView::GiveFeedback(DWORD dwEffect) 3782 { 3783 TRACE("(%p)\n", this); 3784 3785 return DRAGDROP_S_USEDEFAULTCURSORS; 3786 } 3787 3788 /********************************************************** 3789 * ISVViewObject implementation 3790 */ 3791 3792 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) 3793 { 3794 FIXME("Stub: this=%p\n", this); 3795 3796 return E_NOTIMPL; 3797 } 3798 3799 HRESULT WINAPI CDefView::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet) 3800 { 3801 FIXME("Stub: this=%p\n", this); 3802 3803 return E_NOTIMPL; 3804 } 3805 3806 HRESULT WINAPI CDefView::Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze) 3807 { 3808 FIXME("Stub: this=%p\n", this); 3809 3810 return E_NOTIMPL; 3811 } 3812 3813 HRESULT WINAPI CDefView::Unfreeze(DWORD dwFreeze) 3814 { 3815 FIXME("Stub: this=%p\n", this); 3816 3817 return E_NOTIMPL; 3818 } 3819 3820 HRESULT WINAPI CDefView::SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink) 3821 { 3822 FIXME("partial stub: %p 0x%08x 0x%08x %p\n", this, aspects, advf, pAdvSink); 3823 3824 /* FIXME: we set the AdviseSink, but never use it to send any advice */ 3825 m_pAdvSink = pAdvSink; 3826 m_dwAspects = aspects; 3827 m_dwAdvf = advf; 3828 3829 return S_OK; 3830 } 3831 3832 HRESULT WINAPI CDefView::GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink) 3833 { 3834 TRACE("this=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n", this, pAspects, pAdvf, ppAdvSink); 3835 3836 if (ppAdvSink) 3837 { 3838 *ppAdvSink = m_pAdvSink; 3839 m_pAdvSink.p->AddRef(); 3840 } 3841 3842 if (pAspects) 3843 *pAspects = m_dwAspects; 3844 3845 if (pAdvf) 3846 *pAdvf = m_dwAdvf; 3847 3848 return S_OK; 3849 } 3850 3851 HRESULT STDMETHODCALLTYPE CDefView::QueryService(REFGUID guidService, REFIID riid, void **ppvObject) 3852 { 3853 if (IsEqualIID(guidService, SID_IShellBrowser)) 3854 return m_pShellBrowser->QueryInterface(riid, ppvObject); 3855 else if(IsEqualIID(guidService, SID_IFolderView)) 3856 return QueryInterface(riid, ppvObject); 3857 3858 return E_NOINTERFACE; 3859 } 3860 3861 HRESULT CDefView::_MergeToolbar() 3862 { 3863 CComPtr<IExplorerToolbar> ptb; 3864 HRESULT hr = S_OK; 3865 3866 hr = IUnknown_QueryService(m_pShellBrowser, IID_IExplorerToolbar, IID_PPV_ARG(IExplorerToolbar, &ptb)); 3867 if (FAILED(hr)) 3868 return hr; 3869 3870 m_Category = CGID_DefViewFrame; 3871 3872 hr = ptb->SetCommandTarget(static_cast<IOleCommandTarget*>(this), &m_Category, 0); 3873 if (FAILED(hr)) 3874 return hr; 3875 3876 if (hr == S_FALSE) 3877 return S_OK; 3878 3879 #if 0 3880 hr = ptb->AddButtons(&m_Category, buttonsCount, buttons); 3881 if (FAILED(hr)) 3882 return hr; 3883 #endif 3884 3885 return S_OK; 3886 } 3887 3888 HRESULT CDefView::_DoFolderViewCB(UINT uMsg, WPARAM wParam, LPARAM lParam) 3889 { 3890 HRESULT hr = E_NOTIMPL; 3891 3892 if (m_pShellFolderViewCB) 3893 { 3894 hr = m_pShellFolderViewCB->MessageSFVCB(uMsg, wParam, lParam); 3895 } 3896 3897 return hr; 3898 } 3899 3900 HRESULT CDefView_CreateInstance(IShellFolder *pFolder, REFIID riid, LPVOID * ppvOut) 3901 { 3902 return ShellObjectCreatorInit<CDefView>(pFolder, riid, ppvOut); 3903 } 3904 3905 HRESULT WINAPI SHCreateShellFolderViewEx( 3906 LPCSFV psvcbi, /* [in] shelltemplate struct */ 3907 IShellView **ppsv) /* [out] IShellView pointer */ 3908 { 3909 CComPtr<IShellView> psv; 3910 HRESULT hRes; 3911 3912 TRACE("sf=%p pidl=%p cb=%p mode=0x%08x parm=%p\n", 3913 psvcbi->pshf, psvcbi->pidl, psvcbi->pfnCallback, 3914 psvcbi->fvm, psvcbi->psvOuter); 3915 3916 *ppsv = NULL; 3917 hRes = CDefView_CreateInstance(psvcbi->pshf, IID_PPV_ARG(IShellView, &psv)); 3918 if (FAILED_UNEXPECTEDLY(hRes)) 3919 return hRes; 3920 3921 *ppsv = psv.Detach(); 3922 return hRes; 3923 } 3924 3925 HRESULT WINAPI SHCreateShellFolderView(const SFV_CREATE *pcsfv, 3926 IShellView **ppsv) 3927 { 3928 CComPtr<IShellView> psv; 3929 HRESULT hRes; 3930 3931 if (!ppsv) 3932 return E_INVALIDARG; 3933 3934 *ppsv = NULL; 3935 3936 if (!pcsfv || pcsfv->cbSize != sizeof(*pcsfv)) 3937 return E_INVALIDARG; 3938 3939 TRACE("sf=%p outer=%p callback=%p\n", 3940 pcsfv->pshf, pcsfv->psvOuter, pcsfv->psfvcb); 3941 3942 hRes = CDefView_CreateInstance(pcsfv->pshf, IID_PPV_ARG(IShellView, &psv)); 3943 if (FAILED(hRes)) 3944 return hRes; 3945 3946 if (pcsfv->psfvcb) 3947 { 3948 CComPtr<IShellFolderView> sfv; 3949 if (SUCCEEDED(psv->QueryInterface(IID_PPV_ARG(IShellFolderView, &sfv)))) 3950 { 3951 sfv->SetCallback(pcsfv->psfvcb, NULL); 3952 } 3953 } 3954 3955 *ppsv = psv.Detach(); 3956 return hRes; 3957 } 3958