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