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