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