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