xref: /reactos/dll/win32/shell32/CDefView.cpp (revision 6ef7b676)
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;
1577 
1578     hMenu = CreatePopupMenu();
1579     if (!hMenu)
1580         return 0;
1581 
1582     hResult = GetItemObject( bUseSelection ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &m_pCM));
1583     if (FAILED_UNEXPECTEDLY( hResult))
1584         goto cleanup;
1585 
1586     hResult = m_pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_NORMAL);
1587     if (FAILED_UNEXPECTEDLY( hResult))
1588         goto cleanup;
1589 
1590     if (bUseSelection)
1591     {
1592         // FIXME: we should cache this....
1593         SFGAOF rfg = SFGAO_BROWSABLE | SFGAO_CANCOPY | SFGAO_CANLINK | SFGAO_CANMOVE | SFGAO_CANDELETE | SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSTEM | SFGAO_FOLDER;
1594         hResult = m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &rfg);
1595         if (FAILED_UNEXPECTEDLY(hResult))
1596             return 0;
1597 
1598         if (!(rfg & SFGAO_CANMOVE) && uCommand == FCIDM_SHVIEW_CUT)
1599             return 0;
1600         if (!(rfg & SFGAO_CANCOPY) && uCommand == FCIDM_SHVIEW_COPY)
1601             return 0;
1602         if (!(rfg & SFGAO_CANDELETE) && uCommand == FCIDM_SHVIEW_DELETE)
1603             return 0;
1604         if (!(rfg & SFGAO_CANRENAME) && uCommand == FCIDM_SHVIEW_RENAME)
1605             return 0;
1606         if (!(rfg & SFGAO_HASPROPSHEET) && uCommand == FCIDM_SHVIEW_PROPERTIES)
1607             return 0;
1608     }
1609 
1610     InvokeContextMenuCommand(uCommand);
1611 
1612 cleanup:
1613     if (m_pCM)
1614     {
1615         IUnknown_SetSite(m_pCM, NULL);
1616         m_pCM.Release();
1617     }
1618 
1619     if (hMenu)
1620         DestroyMenu(hMenu);
1621 
1622     return 0;
1623 }
1624 
1625 /**********************************************************
1626  *    ##### message handling #####
1627  */
1628 
1629 /**********************************************************
1630 *  ShellView_OnSize()
1631 */
1632 LRESULT CDefView::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1633 {
1634     WORD wWidth, wHeight;
1635 
1636     wWidth  = LOWORD(lParam);
1637     wHeight = HIWORD(lParam);
1638 
1639     TRACE("%p width=%u height=%u\n", this, wWidth, wHeight);
1640 
1641     /* Resize the ListView to fit our window */
1642     if (m_ListView)
1643     {
1644         ::MoveWindow(m_ListView, 0, 0, wWidth, wHeight, TRUE);
1645     }
1646 
1647     _DoFolderViewCB(SFVM_SIZE, 0, 0);
1648 
1649     return 0;
1650 }
1651 
1652 /**********************************************************
1653 * ShellView_OnDeactivate()
1654 *
1655 * NOTES
1656 *  internal
1657 */
1658 void CDefView::OnDeactivate()
1659 {
1660     TRACE("%p\n", this);
1661 
1662     if (m_uState != SVUIA_DEACTIVATE)
1663     {
1664         // TODO: cleanup menu after deactivation
1665 
1666         m_uState = SVUIA_DEACTIVATE;
1667     }
1668 }
1669 
1670 void CDefView::DoActivate(UINT uState)
1671 {
1672     TRACE("%p uState=%x\n", this, uState);
1673 
1674     /*don't do anything if the state isn't really changing */
1675     if (m_uState == uState)
1676     {
1677         return;
1678     }
1679 
1680     if (uState == SVUIA_DEACTIVATE)
1681     {
1682         OnDeactivate();
1683     }
1684     else
1685     {
1686         if(m_hMenu && !m_bmenuBarInitialized)
1687         {
1688             FillEditMenu();
1689             FillViewMenu();
1690             m_pShellBrowser->SetMenuSB(m_hMenu, 0, m_hWnd);
1691             m_bmenuBarInitialized = TRUE;
1692         }
1693 
1694         if (SVUIA_ACTIVATE_FOCUS == uState)
1695         {
1696             m_ListView.SetFocus();
1697         }
1698     }
1699 
1700     m_uState = uState;
1701     TRACE("--\n");
1702 }
1703 
1704 /**********************************************************
1705 * ShellView_OnActivate()
1706 */
1707 LRESULT CDefView::OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1708 {
1709     DoActivate(SVUIA_ACTIVATE_FOCUS);
1710     return 0;
1711 }
1712 
1713 /**********************************************************
1714 *  ShellView_OnSetFocus()
1715 *
1716 */
1717 LRESULT CDefView::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1718 {
1719     TRACE("%p\n", this);
1720 
1721     /* Tell the browser one of our windows has received the focus. This
1722     should always be done before merging menus (OnActivate merges the
1723     menus) if one of our windows has the focus.*/
1724 
1725     m_pShellBrowser->OnViewWindowActive(this);
1726     DoActivate(SVUIA_ACTIVATE_FOCUS);
1727 
1728     /* Set the focus to the listview */
1729     m_ListView.SetFocus();
1730 
1731     /* Notify the ICommDlgBrowser interface */
1732     OnStateChange(CDBOSC_SETFOCUS);
1733 
1734     return 0;
1735 }
1736 
1737 /**********************************************************
1738 * ShellView_OnKillFocus()
1739 */
1740 LRESULT CDefView::OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1741 {
1742     TRACE("(%p) stub\n", this);
1743 
1744     DoActivate(SVUIA_ACTIVATE_NOFOCUS);
1745     /* Notify the ICommDlgBrowser */
1746     OnStateChange(CDBOSC_KILLFOCUS);
1747 
1748     return 0;
1749 }
1750 
1751 /**********************************************************
1752 * ShellView_OnCommand()
1753 *
1754 * NOTES
1755 *    the CmdID's are the ones from the context menu
1756 */
1757 LRESULT CDefView::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1758 {
1759     DWORD dwCmdID;
1760     DWORD dwCmd;
1761     HWND  hwndCmd;
1762     int   nCount;
1763 
1764     dwCmdID = GET_WM_COMMAND_ID(wParam, lParam);
1765     dwCmd = GET_WM_COMMAND_CMD(wParam, lParam);
1766     hwndCmd = GET_WM_COMMAND_HWND(wParam, lParam);
1767 
1768     TRACE("(%p)->(0x%08x 0x%08x %p) stub\n", this, dwCmdID, dwCmd, hwndCmd);
1769 
1770     switch (dwCmdID)
1771     {
1772         case FCIDM_SHVIEW_SMALLICON:
1773             m_FolderSettings.ViewMode = FVM_SMALLICON;
1774             m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_SMALLICON);
1775             CheckToolbar();
1776             break;
1777 
1778         case FCIDM_SHVIEW_BIGICON:
1779             m_FolderSettings.ViewMode = FVM_ICON;
1780             m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_ICON);
1781             CheckToolbar();
1782             break;
1783 
1784         case FCIDM_SHVIEW_LISTVIEW:
1785             m_FolderSettings.ViewMode = FVM_LIST;
1786             m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_LIST);
1787             CheckToolbar();
1788             break;
1789 
1790         case FCIDM_SHVIEW_REPORTVIEW:
1791             m_FolderSettings.ViewMode = FVM_DETAILS;
1792             m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_REPORT);
1793             CheckToolbar();
1794             break;
1795 
1796         /* the menu-ID's for sorting are 0x30... see shrec.rc */
1797         case 0x30:
1798         case 0x31:
1799         case 0x32:
1800         case 0x33:
1801             m_sortInfo.nHeaderID = dwCmdID - 0x30;
1802             m_sortInfo.bIsAscending = TRUE;
1803             _Sort();
1804             break;
1805 
1806         case FCIDM_SHVIEW_SNAPTOGRID:
1807             m_ListView.Arrange(LVA_SNAPTOGRID);
1808             break;
1809         case FCIDM_SHVIEW_ALIGNTOGRID:
1810             if (_GetSnapToGrid() == S_OK)
1811                 m_ListView.SetExtendedListViewStyle(0, LVS_EX_SNAPTOGRID);
1812             else
1813                 ArrangeGrid();
1814             break;
1815         case FCIDM_SHVIEW_AUTOARRANGE:
1816             if (GetAutoArrange() == S_OK)
1817                 m_ListView.ModifyStyle(LVS_AUTOARRANGE, 0);
1818             else
1819                 AutoArrange();
1820             break;
1821         case FCIDM_SHVIEW_SELECTALL:
1822             m_ListView.SetItemState(-1, LVIS_SELECTED, LVIS_SELECTED);
1823             break;
1824 
1825         case FCIDM_SHVIEW_INVERTSELECTION:
1826             nCount = m_ListView.GetItemCount();
1827             for (int i=0; i < nCount; i++)
1828                 m_ListView.SetItemState(i, m_ListView.GetItemState(i, LVIS_SELECTED) ? 0 : LVIS_SELECTED, LVIS_SELECTED);
1829             break;
1830 
1831         case FCIDM_SHVIEW_REFRESH:
1832             Refresh();
1833             break;
1834 
1835         case FCIDM_SHVIEW_DELETE:
1836         case FCIDM_SHVIEW_CUT:
1837         case FCIDM_SHVIEW_COPY:
1838         case FCIDM_SHVIEW_RENAME:
1839         case FCIDM_SHVIEW_PROPERTIES:
1840         case FCIDM_SHVIEW_COPYTO:
1841         case FCIDM_SHVIEW_MOVETO:
1842             if (SHRestricted(REST_NOVIEWCONTEXTMENU))
1843                 return 0;
1844 
1845             return OnExplorerCommand(dwCmdID, TRUE);
1846 
1847         case FCIDM_SHVIEW_INSERT:
1848         case FCIDM_SHVIEW_UNDO:
1849         case FCIDM_SHVIEW_INSERTLINK:
1850         case FCIDM_SHVIEW_NEWFOLDER:
1851             return OnExplorerCommand(dwCmdID, FALSE);
1852         default:
1853             /* WM_COMMAND messages from the file menu are routed to the CDefView so as to let m_pCM handle the command */
1854             if (m_pCM && dwCmd == 0)
1855             {
1856                 InvokeContextMenuCommand(dwCmdID);
1857             }
1858     }
1859 
1860     return 0;
1861 }
1862 
1863 static BOOL
1864 SelectExtOnRename(void)
1865 {
1866     HKEY hKey;
1867     LONG error;
1868     DWORD dwValue = FALSE, cbValue;
1869 
1870     error = RegOpenKeyExW(HKEY_CURRENT_USER,
1871                           L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer",
1872                           0, KEY_READ, &hKey);
1873     if (error)
1874         return dwValue;
1875 
1876     cbValue = sizeof(dwValue);
1877     RegQueryValueExW(hKey, L"SelectExtOnRename", NULL, NULL, (LPBYTE)&dwValue, &cbValue);
1878 
1879     RegCloseKey(hKey);
1880     return !!dwValue;
1881 }
1882 
1883 /**********************************************************
1884 * ShellView_OnNotify()
1885 */
1886 
1887 LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1888 {
1889     UINT                                CtlID;
1890     LPNMHDR                                lpnmh;
1891     LPNMLISTVIEW                        lpnmlv;
1892     NMLVDISPINFOW                        *lpdi;
1893     PCUITEMID_CHILD                     pidl;
1894     BOOL                                unused;
1895 
1896     CtlID = wParam;
1897     lpnmh = (LPNMHDR)lParam;
1898     lpnmlv = (LPNMLISTVIEW)lpnmh;
1899     lpdi = (NMLVDISPINFOW *)lpnmh;
1900 
1901     TRACE("%p CtlID=%u lpnmh->code=%x\n", this, CtlID, lpnmh->code);
1902 
1903     switch (lpnmh->code)
1904     {
1905         case NM_SETFOCUS:
1906             TRACE("-- NM_SETFOCUS %p\n", this);
1907             OnSetFocus(0, 0, 0, unused);
1908             break;
1909 
1910         case NM_KILLFOCUS:
1911             TRACE("-- NM_KILLFOCUS %p\n", this);
1912             OnDeactivate();
1913             /* Notify the ICommDlgBrowser interface */
1914             OnStateChange(CDBOSC_KILLFOCUS);
1915             break;
1916 
1917         case NM_CUSTOMDRAW:
1918             TRACE("-- NM_CUSTOMDRAW %p\n", this);
1919             return CDRF_DODEFAULT;
1920 
1921         case NM_RELEASEDCAPTURE:
1922             TRACE("-- NM_RELEASEDCAPTURE %p\n", this);
1923             break;
1924 
1925         case NM_CLICK:
1926             TRACE("-- NM_CLICK %p\n", this);
1927             break;
1928 
1929         case NM_RCLICK:
1930             TRACE("-- NM_RCLICK %p\n", this);
1931             break;
1932 
1933         case NM_DBLCLK:
1934             TRACE("-- NM_DBLCLK %p\n", this);
1935             OpenSelectedItems();
1936             break;
1937 
1938         case NM_RETURN:
1939             TRACE("-- NM_RETURN %p\n", this);
1940             OpenSelectedItems();
1941             break;
1942 
1943         case HDN_ENDTRACKW:
1944             TRACE("-- HDN_ENDTRACKW %p\n", this);
1945             /*nColumn1 = m_ListView.GetColumnWidth(0);
1946             nColumn2 = m_ListView.GetColumnWidth(1);*/
1947             break;
1948 
1949         case LVN_DELETEITEM:
1950             TRACE("-- LVN_DELETEITEM %p\n", this);
1951 
1952             /*delete the pidl because we made a copy of it*/
1953             SHFree(reinterpret_cast<LPVOID>(lpnmlv->lParam));
1954 
1955             break;
1956 
1957         case LVN_DELETEALLITEMS:
1958             TRACE("-- LVN_DELETEALLITEMS %p\n", this);
1959             return FALSE;
1960 
1961         case LVN_INSERTITEM:
1962             TRACE("-- LVN_INSERTITEM (STUB)%p\n", this);
1963             break;
1964 
1965         case LVN_ITEMACTIVATE:
1966             TRACE("-- LVN_ITEMACTIVATE %p\n", this);
1967             OnStateChange(CDBOSC_SELCHANGE);  /* the browser will get the IDataObject now */
1968             break;
1969 
1970         case LVN_COLUMNCLICK:
1971             m_sortInfo.nHeaderID = lpnmlv->iSubItem;
1972             if (m_sortInfo.nLastHeaderID == m_sortInfo.nHeaderID)
1973                 m_sortInfo.bIsAscending = !m_sortInfo.bIsAscending;
1974             else
1975                 m_sortInfo.bIsAscending = TRUE;
1976             _Sort();
1977             break;
1978 
1979         case LVN_GETDISPINFOA:
1980         case LVN_GETDISPINFOW:
1981             TRACE("-- LVN_GETDISPINFO %p\n", this);
1982             pidl = _PidlByItem(lpdi->item);
1983 
1984             if (lpdi->item.mask & LVIF_TEXT)    /* text requested */
1985             {
1986                 if (m_pSF2Parent)
1987                 {
1988                     SHELLDETAILS sd;
1989                     if (FAILED_UNEXPECTEDLY(m_pSF2Parent->GetDetailsOf(pidl, lpdi->item.iSubItem, &sd)))
1990                         break;
1991 
1992                     if (lpnmh->code == LVN_GETDISPINFOA)
1993                     {
1994                         /* shouldn't happen */
1995                         NMLVDISPINFOA *lpdiA = (NMLVDISPINFOA *)lpnmh;
1996                         StrRetToStrNA( lpdiA->item.pszText, lpdiA->item.cchTextMax, &sd.str, NULL);
1997                         TRACE("-- text=%s\n", lpdiA->item.pszText);
1998                     }
1999                     else /* LVN_GETDISPINFOW */
2000                     {
2001                         StrRetToStrNW( lpdi->item.pszText, lpdi->item.cchTextMax, &sd.str, NULL);
2002                         TRACE("-- text=%s\n", debugstr_w(lpdi->item.pszText));
2003                     }
2004                 }
2005                 else
2006                 {
2007                     FIXME("no m_pSF2Parent\n");
2008                 }
2009             }
2010             if(lpdi->item.mask & LVIF_IMAGE)    /* image requested */
2011             {
2012                 lpdi->item.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
2013             }
2014             if(lpdi->item.mask & LVIF_STATE)
2015             {
2016                 ULONG attributes = SFGAO_HIDDEN;
2017                 if (SUCCEEDED(m_pSFParent->GetAttributesOf(1, &pidl, &attributes)))
2018                 {
2019                     if (attributes & SFGAO_HIDDEN)
2020                     {
2021                         lpdi->item.state |= LVIS_CUT;
2022                     }
2023                 }
2024             }
2025             lpdi->item.mask |= LVIF_DI_SETITEM;
2026             break;
2027 
2028         case LVN_ITEMCHANGED:
2029             TRACE("-- LVN_ITEMCHANGED %p\n", this);
2030             OnStateChange(CDBOSC_SELCHANGE);  /* the browser will get the IDataObject now */
2031             UpdateStatusbar();
2032             _DoFolderViewCB(SFVM_SELECTIONCHANGED, NULL/* FIXME */, NULL/* FIXME */);
2033             break;
2034 
2035         case LVN_BEGINDRAG:
2036         case LVN_BEGINRDRAG:
2037             TRACE("-- LVN_BEGINDRAG\n");
2038 
2039             if (GetSelections())
2040             {
2041                 CComPtr<IDataObject> pda;
2042                 DWORD dwAttributes = SFGAO_CANCOPY | SFGAO_CANLINK;
2043                 DWORD dwEffect = DROPEFFECT_MOVE;
2044 
2045                 if (SUCCEEDED(m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, IID_NULL_PPV_ARG(IDataObject, &pda))))
2046                 {
2047                     LPNMLISTVIEW params = (LPNMLISTVIEW)lParam;
2048 
2049                     if (SUCCEEDED(m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &dwAttributes)))
2050                     {
2051                         dwEffect |= dwAttributes & (SFGAO_CANCOPY | SFGAO_CANLINK);
2052                     }
2053 
2054                     CComPtr<IAsyncOperation> piaso;
2055                     if (SUCCEEDED(pda->QueryInterface(IID_PPV_ARG(IAsyncOperation, &piaso))))
2056                     {
2057                         piaso->SetAsyncMode(TRUE);
2058                     }
2059 
2060                     DWORD dwEffect2;
2061 
2062                     m_pSourceDataObject = pda;
2063                     m_ptFirstMousePos = params->ptAction;
2064                     ClientToScreen(&m_ptFirstMousePos);
2065                     ::ClientToListView(m_ListView, &m_ptFirstMousePos);
2066 
2067                     HIMAGELIST big_icons, small_icons;
2068                     Shell_GetImageLists(&big_icons, &small_icons);
2069                     PCUITEMID_CHILD pidl = _PidlByItem(params->iItem);
2070                     int iIcon = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
2071                     POINT ptItem;
2072                     m_ListView.GetItemPosition(params->iItem, &ptItem);
2073 
2074                     ImageList_BeginDrag(big_icons, iIcon, params->ptAction.x - ptItem.x, params->ptAction.y - ptItem.y);
2075 
2076                     DoDragDrop(pda, this, dwEffect, &dwEffect2);
2077 
2078                     m_pSourceDataObject.Release();
2079                 }
2080             }
2081             break;
2082 
2083         case LVN_BEGINLABELEDITW:
2084         {
2085             DWORD dwAttr = SFGAO_CANRENAME;
2086             pidl = _PidlByItem(lpdi->item);
2087 
2088             TRACE("-- LVN_BEGINLABELEDITW %p\n", this);
2089 
2090             m_pSFParent->GetAttributesOf(1, &pidl, &dwAttr);
2091             if (SFGAO_CANRENAME & dwAttr)
2092             {
2093                 HWND hEdit = reinterpret_cast<HWND>(m_ListView.SendMessage(LVM_GETEDITCONTROL));
2094                 SHLimitInputEdit(hEdit, m_pSFParent);
2095 
2096                 LPWSTR pszText = lpdi->item.pszText;
2097                 if (!(dwAttr & (SFGAO_LINK | SFGAO_FOLDER)) && (dwAttr & SFGAO_FILESYSTEM) &&
2098                     (lpdi->item.mask & LVIF_TEXT) &&
2099                     !SelectExtOnRename() && !SHELL_FS_HideExtension(pszText))
2100                 {
2101                     LPWSTR pchDotExt = PathFindExtensionW(pszText);
2102                     ::PostMessageW(hEdit, EM_SETSEL, 0, pchDotExt - pszText);
2103                     ::PostMessageW(hEdit, EM_SCROLLCARET, 0, 0);
2104                 }
2105 
2106                 m_isEditing = TRUE;
2107                 return FALSE;
2108             }
2109 
2110             return TRUE;
2111         }
2112 
2113         case LVN_ENDLABELEDITW:
2114         {
2115             TRACE("-- LVN_ENDLABELEDITW %p\n", this);
2116 
2117             m_isEditing = FALSE;
2118 
2119             if (lpdi->item.pszText)
2120             {
2121                 HRESULT hr;
2122                 LVITEMW lvItem;
2123 
2124                 pidl = _PidlByItem(lpdi->item);
2125                 PITEMID_CHILD pidlNew = NULL;
2126                 hr = m_pSFParent->SetNameOf(0, pidl, lpdi->item.pszText, SHGDN_INFOLDER, &pidlNew);
2127 
2128                 if (SUCCEEDED(hr) && pidlNew)
2129                 {
2130                     lvItem.mask = LVIF_PARAM|LVIF_IMAGE;
2131                     lvItem.iItem = lpdi->item.iItem;
2132                     lvItem.iSubItem = 0;
2133                     lvItem.lParam = reinterpret_cast<LPARAM>(pidlNew);
2134                     lvItem.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidlNew, 0);
2135                     m_ListView.SetItem(&lvItem);
2136                     m_ListView.Update(lpdi->item.iItem);
2137                     return TRUE;
2138                 }
2139             }
2140 
2141             return FALSE;
2142         }
2143 
2144         default:
2145             TRACE("-- %p WM_COMMAND %x unhandled\n", this, lpnmh->code);
2146             break;
2147     }
2148 
2149     return 0;
2150 }
2151 
2152 /*
2153  * This is just a quick hack to make the desktop work correctly.
2154  * ITranslateShellChangeNotify's IsChildID is undocumented, but most likely the way that
2155  * a folder should know if it should update upon a change notification.
2156  * It is exported by merged folders at a minimum.
2157  */
2158 static BOOL ILIsParentOrSpecialParent(PCIDLIST_ABSOLUTE pidl1, PCIDLIST_ABSOLUTE pidl2)
2159 {
2160     if (!pidl1 || !pidl2)
2161         return FALSE;
2162     if (ILIsParent(pidl1, pidl2, TRUE))
2163         return TRUE;
2164 
2165     if (_ILIsDesktop(pidl1))
2166     {
2167         PIDLIST_ABSOLUTE deskpidl;
2168         SHGetFolderLocation(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 0, &deskpidl);
2169         if (ILIsParent(deskpidl, pidl2, TRUE))
2170         {
2171             ILFree(deskpidl);
2172             return TRUE;
2173         }
2174         ILFree(deskpidl);
2175         SHGetFolderLocation(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL, 0, &deskpidl);
2176         if (ILIsParent(deskpidl, pidl2, TRUE))
2177         {
2178             ILFree(deskpidl);
2179             return TRUE;
2180         }
2181         ILFree(deskpidl);
2182     }
2183 
2184     WCHAR szPath1[MAX_PATH], szPath2[MAX_PATH];
2185     LPITEMIDLIST pidl2Clone = ILClone(pidl2);
2186     ILRemoveLastID(pidl2Clone);
2187     if (SHGetPathFromIDListW(pidl1, szPath1) &&
2188         SHGetPathFromIDListW(pidl2Clone, szPath2))
2189     {
2190         if (lstrcmpiW(szPath1, szPath2) == 0)
2191         {
2192             ILFree(pidl2Clone);
2193             return TRUE;
2194         }
2195     }
2196     ILFree(pidl2Clone);
2197 
2198     return FALSE;
2199 }
2200 
2201 /**********************************************************
2202 * ShellView_OnChange()
2203 */
2204 LRESULT CDefView::OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2205 {
2206     HANDLE hChange = (HANDLE)wParam;
2207     DWORD dwProcID = (DWORD)lParam;
2208     PIDLIST_ABSOLUTE *Pidls;
2209     LONG lEvent;
2210     HANDLE hLock = SHChangeNotification_Lock(hChange, dwProcID, &Pidls, &lEvent);
2211     if (hLock == NULL)
2212     {
2213         ERR("hLock == NULL\n");
2214         return FALSE;
2215     }
2216 
2217     BOOL bParent0 = ILIsParentOrSpecialParent(m_pidlParent, Pidls[0]);
2218     BOOL bParent1 = ILIsParentOrSpecialParent(m_pidlParent, Pidls[1]);
2219 
2220     TRACE("(%p)(%p,%p,0x%08x)\n", this, Pidls[0], Pidls[1], lParam);
2221 
2222     lEvent &= ~SHCNE_INTERRUPT;
2223     switch (lEvent)
2224     {
2225         case SHCNE_MKDIR:
2226         case SHCNE_CREATE:
2227             if (bParent0)
2228             {
2229                 if (LV_FindItemByPidl(ILFindLastID(Pidls[0])) == -1)
2230                 {
2231                     LV_AddItem(ILFindLastID(Pidls[0]));
2232                 }
2233                 else
2234                 {
2235                     LV_ProdItem(ILFindLastID(Pidls[0]));
2236                 }
2237             }
2238             break;
2239 
2240         case SHCNE_RMDIR:
2241         case SHCNE_DELETE:
2242             if (bParent0)
2243                 LV_DeleteItem(ILFindLastID(Pidls[0]));
2244             break;
2245 
2246         case SHCNE_RENAMEFOLDER:
2247         case SHCNE_RENAMEITEM:
2248             if (bParent0 && bParent1)
2249                 LV_RenameItem(ILFindLastID(Pidls[0]), ILFindLastID(Pidls[1]));
2250             else if (bParent0)
2251                 LV_DeleteItem(ILFindLastID(Pidls[0]));
2252             else if (bParent1)
2253                 LV_AddItem(ILFindLastID(Pidls[1]));
2254             break;
2255 
2256         case SHCNE_UPDATEITEM:
2257             if (bParent0)
2258                 LV_RenameItem(ILFindLastID(Pidls[0]), ILFindLastID(Pidls[0]));
2259             break;
2260 
2261         case SHCNE_UPDATEDIR:
2262             Refresh();
2263             break;
2264     }
2265 
2266     SHChangeNotification_Unlock(hLock);
2267     return TRUE;
2268 }
2269 
2270 HRESULT SHGetMenuIdFromMenuMsg(UINT uMsg, LPARAM lParam, UINT *CmdId);
2271 HRESULT SHSetMenuIdInMenuMsg(UINT uMsg, LPARAM lParam, UINT CmdId);
2272 
2273 /**********************************************************
2274 *  CDefView::OnCustomItem
2275 */
2276 LRESULT CDefView::OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2277 {
2278     if (!m_pCM.p)
2279     {
2280         /* no menu */
2281         ERR("no menu!!!\n");
2282         return FALSE;
2283     }
2284 
2285     /* The lParam of WM_DRAWITEM WM_MEASUREITEM contain a menu id and this also needs to
2286        be changed to a menu identifier offset */
2287     UINT CmdID;
2288     HRESULT hres = SHGetMenuIdFromMenuMsg(uMsg, lParam, &CmdID);
2289     if (SUCCEEDED(hres))
2290         SHSetMenuIdInMenuMsg(uMsg, lParam, CmdID - CONTEXT_MENU_BASE_ID);
2291 
2292     /* Forward the message to the IContextMenu2 */
2293     LRESULT result;
2294     hres = SHForwardContextMenuMsg(m_pCM, uMsg, wParam, lParam, &result, TRUE);
2295 
2296     return (SUCCEEDED(hres));
2297 }
2298 
2299 LRESULT CDefView::OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2300 {
2301     /* Wallpaper setting affects drop shadows effect */
2302     if (wParam == SPI_SETDESKWALLPAPER || wParam == 0)
2303         UpdateListColors();
2304 
2305     return S_OK;
2306 }
2307 
2308 /**********************************************************
2309 *  CDefView::OnInitMenuPopup
2310 */
2311 LRESULT CDefView::OnInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2312 {
2313     HMENU hmenu = (HMENU) wParam;
2314     int nPos = LOWORD(lParam);
2315     UINT  menuItemId;
2316 
2317     OnCustomItem(uMsg, wParam, lParam, bHandled);
2318 
2319     HMENU hViewMenu = GetSubmenuByID(m_hMenu, FCIDM_MENU_VIEW);
2320 
2321     if (GetSelections() == 0)
2322     {
2323         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_CUT, MF_GRAYED);
2324         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_COPY, MF_GRAYED);
2325         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_RENAME, MF_GRAYED);
2326         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_COPYTO, MF_GRAYED);
2327         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_MOVETO, MF_GRAYED);
2328         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_DELETE, MF_GRAYED);
2329     }
2330     else
2331     {
2332         // FIXME: Check copyable
2333         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_CUT, MF_ENABLED);
2334         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_COPY, MF_ENABLED);
2335         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_RENAME, MF_ENABLED);
2336         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_COPYTO, MF_ENABLED);
2337         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_MOVETO, MF_ENABLED);
2338         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_DELETE, MF_ENABLED);
2339     }
2340 
2341     /* Lets try to find out what the hell wParam is */
2342     if (hmenu == GetSubMenu(m_hMenu, nPos))
2343         menuItemId = ReallyGetMenuItemID(m_hMenu, nPos);
2344     else if (hViewMenu && hmenu == GetSubMenu(hViewMenu, nPos))
2345         menuItemId = ReallyGetMenuItemID(hViewMenu, nPos);
2346     else if (m_hContextMenu && hmenu == GetSubMenu(m_hContextMenu, nPos))
2347         menuItemId = ReallyGetMenuItemID(m_hContextMenu, nPos);
2348     else
2349         return FALSE;
2350 
2351     switch (menuItemId)
2352     {
2353     case FCIDM_MENU_FILE:
2354         FillFileMenu();
2355         break;
2356     case FCIDM_MENU_VIEW:
2357     case FCIDM_SHVIEW_VIEW:
2358         CheckViewMode(hmenu);
2359         break;
2360     case FCIDM_SHVIEW_ARRANGE:
2361         FillArrangeAsMenu(hmenu);
2362         break;
2363     }
2364 
2365     return FALSE;
2366 }
2367 
2368 /**********************************************************
2369 *
2370 *
2371 *  The INTERFACE of the IShellView object
2372 *
2373 *
2374 **********************************************************
2375 */
2376 
2377 /**********************************************************
2378 *  ShellView_GetWindow
2379 */
2380 HRESULT WINAPI CDefView::GetWindow(HWND *phWnd)
2381 {
2382     TRACE("(%p)\n", this);
2383 
2384     *phWnd = m_hWnd;
2385 
2386     return S_OK;
2387 }
2388 
2389 HRESULT WINAPI CDefView::ContextSensitiveHelp(BOOL fEnterMode)
2390 {
2391     FIXME("(%p) stub\n", this);
2392 
2393     return E_NOTIMPL;
2394 }
2395 
2396 /**********************************************************
2397 * IShellView_TranslateAccelerator
2398 *
2399 * FIXME:
2400 *  use the accel functions
2401 */
2402 HRESULT WINAPI CDefView::TranslateAccelerator(LPMSG lpmsg)
2403 {
2404     if (m_isEditing)
2405         return S_FALSE;
2406 
2407     if (lpmsg->message >= WM_KEYFIRST && lpmsg->message <= WM_KEYLAST)
2408     {
2409         if (::TranslateAcceleratorW(m_hWnd, m_hAccel, lpmsg) != 0)
2410             return S_OK;
2411 
2412         TRACE("-- key=0x%04lx\n", lpmsg->wParam) ;
2413     }
2414 
2415     return m_pShellBrowser->TranslateAcceleratorSB(lpmsg, 0);
2416 }
2417 
2418 HRESULT WINAPI CDefView::EnableModeless(BOOL fEnable)
2419 {
2420     FIXME("(%p) stub\n", this);
2421 
2422     return E_NOTIMPL;
2423 }
2424 
2425 HRESULT WINAPI CDefView::UIActivate(UINT uState)
2426 {
2427     // CHAR szName[MAX_PATH];
2428     LRESULT lResult;
2429     int nPartArray[1] = { -1};
2430 
2431     TRACE("(%p)->(state=%x) stub\n", this, uState);
2432 
2433     /* don't do anything if the state isn't really changing */
2434     if (m_uState == uState)
2435     {
2436         return S_OK;
2437     }
2438 
2439     /* OnActivate handles the menu merging and internal state */
2440     DoActivate(uState);
2441 
2442     /* only do This if we are active */
2443     if (uState != SVUIA_DEACTIVATE)
2444     {
2445 
2446         /*
2447             GetFolderPath is not a method of IShellFolder
2448             IShellFolder_GetFolderPath( m_pSFParent, szName, sizeof(szName) );
2449         */
2450         /* set the number of parts */
2451         m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, 1, (LPARAM)nPartArray, &lResult);
2452 
2453         /* set the text for the parts */
2454         /*
2455             m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXTA, 0, (LPARAM)szName, &lResult);
2456         */
2457     }
2458 
2459     return S_OK;
2460 }
2461 
2462 HRESULT WINAPI CDefView::Refresh()
2463 {
2464     TRACE("(%p)\n", this);
2465 
2466     _DoFolderViewCB(SFVM_LISTREFRESHED, TRUE, 0);
2467 
2468     m_ListView.DeleteAllItems();
2469     FillList();
2470 
2471     return S_OK;
2472 }
2473 
2474 HRESULT WINAPI CDefView::CreateViewWindow(IShellView *lpPrevView, LPCFOLDERSETTINGS lpfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd)
2475 {
2476     return CreateViewWindow3(psb, lpPrevView, SV3CVW3_DEFAULT,
2477         (FOLDERFLAGS)lpfs->fFlags, (FOLDERFLAGS)lpfs->fFlags, (FOLDERVIEWMODE)lpfs->ViewMode, NULL, prcView, phWnd);
2478 }
2479 
2480 HRESULT WINAPI CDefView::DestroyViewWindow()
2481 {
2482     TRACE("(%p)\n", this);
2483 
2484     /* Make absolutely sure all our UI is cleaned up */
2485     UIActivate(SVUIA_DEACTIVATE);
2486 
2487     if (m_hAccel)
2488     {
2489         // "Accelerator tables loaded from resources are freed automatically when the application terminates." -- MSDN
2490         m_hAccel = NULL;
2491     }
2492 
2493     if (m_hMenuArrangeModes)
2494     {
2495         DestroyMenu(m_hMenuArrangeModes);
2496         m_hMenuArrangeModes = NULL;
2497     }
2498 
2499     if (m_hMenuViewModes)
2500     {
2501         DestroyMenu(m_hMenuViewModes);
2502         m_hMenuViewModes = NULL;
2503     }
2504 
2505     if (m_hMenu)
2506     {
2507         DestroyMenu(m_hMenu);
2508         m_hMenu = NULL;
2509     }
2510 
2511     if (m_ListView)
2512     {
2513         m_ListView.DestroyWindow();
2514     }
2515 
2516     if (m_hWnd)
2517     {
2518         _DoFolderViewCB(SFVM_WINDOWCLOSING, (WPARAM)m_hWnd, 0);
2519         DestroyWindow();
2520     }
2521 
2522     m_pShellBrowser.Release();
2523     m_pCommDlgBrowser.Release();
2524 
2525     return S_OK;
2526 }
2527 
2528 HRESULT WINAPI CDefView::GetCurrentInfo(LPFOLDERSETTINGS lpfs)
2529 {
2530     TRACE("(%p)->(%p) vmode=%x flags=%x\n", this, lpfs,
2531           m_FolderSettings.ViewMode, m_FolderSettings.fFlags);
2532 
2533     if (!lpfs)
2534         return E_INVALIDARG;
2535 
2536     *lpfs = m_FolderSettings;
2537     return S_OK;
2538 }
2539 
2540 HRESULT WINAPI CDefView::AddPropertySheetPages(DWORD dwReserved, LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam)
2541 {
2542     FIXME("(%p) stub\n", this);
2543 
2544     return E_NOTIMPL;
2545 }
2546 
2547 HRESULT WINAPI CDefView::SaveViewState()
2548 {
2549     FIXME("(%p) stub\n", this);
2550 
2551     return S_OK;
2552 }
2553 
2554 HRESULT WINAPI CDefView::SelectItem(PCUITEMID_CHILD pidl, UINT uFlags)
2555 {
2556     int i;
2557 
2558     TRACE("(%p)->(pidl=%p, 0x%08x) stub\n", this, pidl, uFlags);
2559 
2560     i = LV_FindItemByPidl(pidl);
2561     if (i == -1)
2562         return S_OK;
2563 
2564     LVITEMW lvItem = {0};
2565     lvItem.mask = LVIF_STATE;
2566     lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
2567 
2568     while (m_ListView.GetItem(&lvItem))
2569     {
2570         if (lvItem.iItem == i)
2571         {
2572             if (uFlags & SVSI_SELECT)
2573                 lvItem.state |= LVIS_SELECTED;
2574             else
2575                 lvItem.state &= ~LVIS_SELECTED;
2576 
2577             if (uFlags & SVSI_FOCUSED)
2578                 lvItem.state |= LVIS_FOCUSED;
2579             else
2580                 lvItem.state &= ~LVIS_FOCUSED;
2581         }
2582         else
2583         {
2584             if (uFlags & SVSI_DESELECTOTHERS)
2585             {
2586                 lvItem.state &= ~LVIS_SELECTED;
2587             }
2588             lvItem.state &= ~LVIS_FOCUSED;
2589         }
2590 
2591         m_ListView.SetItem(&lvItem);
2592         lvItem.iItem++;
2593     }
2594 
2595     if (uFlags & SVSI_ENSUREVISIBLE)
2596         m_ListView.EnsureVisible(i, FALSE);
2597 
2598     if((uFlags & SVSI_EDIT) == SVSI_EDIT)
2599         m_ListView.EditLabel(i);
2600 
2601     return S_OK;
2602 }
2603 
2604 HRESULT WINAPI CDefView::GetItemObject(UINT uItem, REFIID riid, LPVOID *ppvOut)
2605 {
2606     HRESULT hr = E_NOINTERFACE;
2607 
2608     TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n", this, uItem, debugstr_guid(&riid), ppvOut);
2609 
2610     if (!ppvOut)
2611         return E_INVALIDARG;
2612 
2613     *ppvOut = NULL;
2614 
2615     switch (uItem)
2616     {
2617         case SVGIO_BACKGROUND:
2618             if (IsEqualIID(riid, IID_IContextMenu))
2619             {
2620                 hr = CDefViewBckgrndMenu_CreateInstance(m_pSF2Parent, riid, ppvOut);
2621                 if (FAILED_UNEXPECTEDLY(hr))
2622                     return hr;
2623 
2624                 IUnknown_SetSite(*((IUnknown**)ppvOut), (IShellView *)this);
2625             }
2626             else if (IsEqualIID(riid, IID_IDispatch))
2627             {
2628                 if (m_pShellFolderViewDual == NULL)
2629                 {
2630                     hr = CDefViewDual_Constructor(riid, (LPVOID*)&m_pShellFolderViewDual);
2631                     if (FAILED_UNEXPECTEDLY(hr))
2632                         return hr;
2633                 }
2634                 hr = m_pShellFolderViewDual->QueryInterface(riid, ppvOut);
2635             }
2636             break;
2637 
2638         case SVGIO_SELECTION:
2639             GetSelections();
2640             hr = m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, riid, 0, ppvOut);
2641             if (FAILED_UNEXPECTEDLY(hr))
2642                 return hr;
2643 
2644             if (IsEqualIID(riid, IID_IContextMenu))
2645                 IUnknown_SetSite(*((IUnknown**)ppvOut), (IShellView *)this);
2646 
2647             break;
2648     }
2649 
2650     TRACE("-- (%p)->(interface=%p)\n", this, *ppvOut);
2651 
2652     return hr;
2653 }
2654 
2655 HRESULT STDMETHODCALLTYPE CDefView::GetCurrentViewMode(UINT *pViewMode)
2656 {
2657     TRACE("(%p)->(%p), stub\n", this, pViewMode);
2658 
2659     if (!pViewMode)
2660         return E_INVALIDARG;
2661 
2662     *pViewMode = m_FolderSettings.ViewMode;
2663     return S_OK;
2664 }
2665 
2666 HRESULT STDMETHODCALLTYPE CDefView::SetCurrentViewMode(UINT ViewMode)
2667 {
2668     DWORD dwStyle;
2669     TRACE("(%p)->(%u), stub\n", this, ViewMode);
2670 
2671     /* It's not redundant to check FVM_AUTO because it's a (UINT)-1 */
2672     if (((INT)ViewMode < FVM_FIRST || (INT)ViewMode > FVM_LAST) && ((INT)ViewMode != FVM_AUTO))
2673         return E_INVALIDARG;
2674 
2675     /* Windows before Vista uses LVM_SETVIEW and possibly
2676        LVM_SETEXTENDEDLISTVIEWSTYLE to set the style of the listview,
2677        while later versions seem to accomplish this through other
2678        means. */
2679     switch (ViewMode)
2680     {
2681         case FVM_ICON:
2682             dwStyle = LVS_ICON;
2683             break;
2684         case FVM_DETAILS:
2685             dwStyle = LVS_REPORT;
2686             break;
2687         case FVM_SMALLICON:
2688             dwStyle = LVS_SMALLICON;
2689             break;
2690         case FVM_LIST:
2691             dwStyle = LVS_LIST;
2692             break;
2693         default:
2694         {
2695             FIXME("ViewMode %d not implemented\n", ViewMode);
2696             dwStyle = LVS_LIST;
2697             break;
2698         }
2699     }
2700 
2701     m_ListView.ModifyStyle(LVS_TYPEMASK, dwStyle);
2702 
2703     /* This will not necessarily be the actual mode set above.
2704        This mimics the behavior of Windows XP. */
2705     m_FolderSettings.ViewMode = ViewMode;
2706 
2707     return S_OK;
2708 }
2709 
2710 HRESULT STDMETHODCALLTYPE CDefView::GetFolder(REFIID riid, void **ppv)
2711 {
2712     if (m_pSFParent == NULL)
2713         return E_FAIL;
2714 
2715     return m_pSFParent->QueryInterface(riid, ppv);
2716 }
2717 
2718 HRESULT STDMETHODCALLTYPE CDefView::Item(int iItemIndex, PITEMID_CHILD *ppidl)
2719 {
2720     PCUITEMID_CHILD pidl = _PidlByItem(iItemIndex);
2721     if (pidl)
2722     {
2723         *ppidl = ILClone(pidl);
2724         return S_OK;
2725     }
2726 
2727     *ppidl = 0;
2728     return E_INVALIDARG;
2729 }
2730 
2731 HRESULT STDMETHODCALLTYPE CDefView::ItemCount(UINT uFlags, int *pcItems)
2732 {
2733     TRACE("(%p)->(%u %p)\n", this, uFlags, pcItems);
2734 
2735     if (uFlags != SVGIO_ALLVIEW)
2736         FIXME("some flags unsupported, %x\n", uFlags & ~SVGIO_ALLVIEW);
2737 
2738     *pcItems = m_ListView.GetItemCount();
2739 
2740     return S_OK;
2741 }
2742 
2743 HRESULT STDMETHODCALLTYPE CDefView::Items(UINT uFlags, REFIID riid, void **ppv)
2744 {
2745     return E_NOTIMPL;
2746 }
2747 
2748 HRESULT STDMETHODCALLTYPE CDefView::GetSelectionMarkedItem(int *piItem)
2749 {
2750     TRACE("(%p)->(%p)\n", this, piItem);
2751 
2752     *piItem = m_ListView.GetSelectionMark();
2753 
2754     return S_OK;
2755 }
2756 
2757 HRESULT STDMETHODCALLTYPE CDefView::GetFocusedItem(int *piItem)
2758 {
2759     TRACE("(%p)->(%p)\n", this, piItem);
2760 
2761     *piItem = m_ListView.GetNextItem(-1, LVNI_FOCUSED);
2762 
2763     return S_OK;
2764 }
2765 
2766 HRESULT STDMETHODCALLTYPE CDefView::GetItemPosition(PCUITEMID_CHILD pidl, POINT *ppt)
2767 {
2768     int lvIndex = LV_FindItemByPidl(pidl);
2769     if (lvIndex == -1 || ppt == NULL)
2770         return E_INVALIDARG;
2771 
2772     m_ListView.GetItemPosition(lvIndex, ppt);
2773     return S_OK;
2774 }
2775 
2776 HRESULT STDMETHODCALLTYPE CDefView::GetSpacing(POINT *ppt)
2777 {
2778     TRACE("(%p)->(%p)\n", this, ppt);
2779 
2780     if (!m_ListView)
2781         return S_FALSE;
2782 
2783     if (ppt)
2784     {
2785         SIZE spacing;
2786         m_ListView.GetItemSpacing(spacing);
2787 
2788         ppt->x = spacing.cx;
2789         ppt->y = spacing.cy;
2790     }
2791 
2792     return S_OK;
2793 }
2794 
2795 HRESULT STDMETHODCALLTYPE CDefView::GetDefaultSpacing(POINT *ppt)
2796 {
2797     return E_NOTIMPL;
2798 }
2799 
2800 HRESULT STDMETHODCALLTYPE CDefView::GetAutoArrange()
2801 {
2802     return ((m_ListView.GetStyle() & LVS_AUTOARRANGE) ? S_OK : S_FALSE);
2803 }
2804 
2805 HRESULT CDefView::_GetSnapToGrid()
2806 {
2807     DWORD dwExStyle = (DWORD)m_ListView.SendMessage(LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
2808     return ((dwExStyle & LVS_EX_SNAPTOGRID) ? S_OK : S_FALSE);
2809 }
2810 
2811 HRESULT STDMETHODCALLTYPE CDefView::SelectItem(int iItem, DWORD dwFlags)
2812 {
2813     LVITEMW lvItem;
2814 
2815     TRACE("(%p)->(%d, %x)\n", this, iItem, dwFlags);
2816 
2817     lvItem.state = 0;
2818     lvItem.stateMask = LVIS_SELECTED;
2819 
2820     if (dwFlags & SVSI_ENSUREVISIBLE)
2821         m_ListView.EnsureVisible(iItem, 0);
2822 
2823     /* all items */
2824     if (dwFlags & SVSI_DESELECTOTHERS)
2825         m_ListView.SetItemState(-1, 0, LVIS_SELECTED);
2826 
2827     /* this item */
2828     if (dwFlags & SVSI_SELECT)
2829         lvItem.state |= LVIS_SELECTED;
2830 
2831     if (dwFlags & SVSI_FOCUSED)
2832         lvItem.stateMask |= LVIS_FOCUSED;
2833 
2834     m_ListView.SetItemState(iItem, lvItem.state, lvItem.stateMask);
2835 
2836     if ((dwFlags & SVSI_EDIT) == SVSI_EDIT)
2837         m_ListView.EditLabel(iItem);
2838 
2839     return S_OK;
2840 }
2841 
2842 HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItems(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, POINT *apt, DWORD dwFlags)
2843 {
2844     /* Reset the selection */
2845     m_ListView.SetItemState(-1, 0, LVIS_SELECTED);
2846 
2847     int lvIndex;
2848     for (UINT i = 0 ; i < m_cidl; i++)
2849     {
2850         lvIndex = LV_FindItemByPidl(apidl[i]);
2851         if (lvIndex != -1)
2852         {
2853             SelectItem(lvIndex, dwFlags);
2854             m_ListView.SetItemPosition(lvIndex, &apt[i]);
2855         }
2856     }
2857 
2858     return S_OK;
2859 }
2860 
2861 /**********************************************************
2862  * IShellView2 implementation
2863  */
2864 
2865 HRESULT STDMETHODCALLTYPE CDefView::GetView(SHELLVIEWID *view_guid, ULONG view_type)
2866 {
2867     FIXME("(%p)->(%p, %lu) stub\n", this, view_guid, view_type);
2868     return E_NOTIMPL;
2869 }
2870 
2871 HRESULT STDMETHODCALLTYPE CDefView::CreateViewWindow2(LPSV2CVW2_PARAMS view_params)
2872 {
2873     return CreateViewWindow3(view_params->psbOwner, view_params->psvPrev,
2874         SV3CVW3_DEFAULT, (FOLDERFLAGS)view_params->pfs->fFlags, (FOLDERFLAGS)view_params->pfs->fFlags,
2875         (FOLDERVIEWMODE)view_params->pfs->ViewMode, view_params->pvid, view_params->prcView, &view_params->hwndView);
2876 }
2877 
2878 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)
2879 {
2880     OLEMENUGROUPWIDTHS omw = { { 0, 0, 0, 0, 0, 0 } };
2881 
2882     *hwnd = NULL;
2883 
2884     TRACE("(%p)->(shlview=%p shlbrs=%p rec=%p hwnd=%p vmode=%x flags=%x)\n", this, psvPrevious, psb, prcView, hwnd, mode, flags);
2885     if (prcView != NULL)
2886         TRACE("-- left=%i top=%i right=%i bottom=%i\n", prcView->left, prcView->top, prcView->right, prcView->bottom);
2887 
2888     /* Validate the Shell Browser */
2889     if (psb == NULL || m_hWnd)
2890         return E_UNEXPECTED;
2891 
2892     if (view_flags != SV3CVW3_DEFAULT)
2893         FIXME("unsupported view flags 0x%08x\n", view_flags);
2894 
2895     /* Set up the member variables */
2896     m_pShellBrowser = psb;
2897     m_FolderSettings.ViewMode = mode;
2898     m_FolderSettings.fFlags = mask & flags;
2899 
2900     if (view_id)
2901     {
2902         if (IsEqualIID(*view_id, VID_LargeIcons))
2903             m_FolderSettings.ViewMode = FVM_ICON;
2904         else if (IsEqualIID(*view_id, VID_SmallIcons))
2905             m_FolderSettings.ViewMode = FVM_SMALLICON;
2906         else if (IsEqualIID(*view_id, VID_List))
2907             m_FolderSettings.ViewMode = FVM_LIST;
2908         else if (IsEqualIID(*view_id, VID_Details))
2909             m_FolderSettings.ViewMode = FVM_DETAILS;
2910         else if (IsEqualIID(*view_id, VID_Thumbnails))
2911             m_FolderSettings.ViewMode = FVM_THUMBNAIL;
2912         else if (IsEqualIID(*view_id, VID_Tile))
2913             m_FolderSettings.ViewMode = FVM_TILE;
2914         else if (IsEqualIID(*view_id, VID_ThumbStrip))
2915             m_FolderSettings.ViewMode = FVM_THUMBSTRIP;
2916         else
2917             FIXME("Ignoring unrecognized VID %s\n", debugstr_guid(view_id));
2918     }
2919 
2920     /* Get our parent window */
2921     m_pShellBrowser->GetWindow(&m_hWndParent);
2922 
2923     /* Try to get the ICommDlgBrowserInterface, adds a reference !!! */
2924     m_pCommDlgBrowser = NULL;
2925     if (SUCCEEDED(m_pShellBrowser->QueryInterface(IID_PPV_ARG(ICommDlgBrowser, &m_pCommDlgBrowser))))
2926     {
2927         TRACE("-- CommDlgBrowser\n");
2928     }
2929 
2930     Create(m_hWndParent, prcView, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP, 0, 0U);
2931     if (m_hWnd == NULL)
2932         return E_FAIL;
2933 
2934     *hwnd = m_hWnd;
2935 
2936     CheckToolbar();
2937 
2938     if (!*hwnd)
2939         return E_FAIL;
2940 
2941     _DoFolderViewCB(SFVM_WINDOWCREATED, (WPARAM)m_hWnd, 0);
2942 
2943     SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
2944     UpdateWindow();
2945 
2946     if (!m_hMenu)
2947     {
2948         m_hMenu = CreateMenu();
2949         m_pShellBrowser->InsertMenusSB(m_hMenu, &omw);
2950         TRACE("-- after fnInsertMenusSB\n");
2951     }
2952 
2953     _MergeToolbar();
2954 
2955     return S_OK;
2956 }
2957 
2958 HRESULT STDMETHODCALLTYPE CDefView::HandleRename(LPCITEMIDLIST new_pidl)
2959 {
2960     FIXME("(%p)->(%p) stub\n", this, new_pidl);
2961     return E_NOTIMPL;
2962 }
2963 
2964 HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItem(LPCITEMIDLIST item, UINT flags, POINT *point)
2965 {
2966     FIXME("(%p)->(%p, %u, %p) stub\n", this, item, flags, point);
2967     return E_NOTIMPL;
2968 }
2969 
2970 /**********************************************************
2971  * IShellFolderView implementation
2972  */
2973 HRESULT STDMETHODCALLTYPE CDefView::Rearrange(LPARAM sort)
2974 {
2975     FIXME("(%p)->(%ld) stub\n", this, sort);
2976     return E_NOTIMPL;
2977 }
2978 
2979 HRESULT STDMETHODCALLTYPE CDefView::GetArrangeParam(LPARAM *sort)
2980 {
2981     FIXME("(%p)->(%p) stub\n", this, sort);
2982     return E_NOTIMPL;
2983 }
2984 
2985 HRESULT STDMETHODCALLTYPE CDefView::ArrangeGrid()
2986 {
2987     m_ListView.SetExtendedListViewStyle(LVS_EX_SNAPTOGRID, LVS_EX_SNAPTOGRID);
2988     return S_OK;
2989 }
2990 
2991 HRESULT STDMETHODCALLTYPE CDefView::AutoArrange()
2992 {
2993     m_ListView.ModifyStyle(0, LVS_AUTOARRANGE);
2994     m_ListView.Arrange(LVA_DEFAULT);
2995     return S_OK;
2996 }
2997 
2998 HRESULT STDMETHODCALLTYPE CDefView::AddObject(PITEMID_CHILD pidl, UINT *item)
2999 {
3000     TRACE("(%p)->(%p %p)\n", this, pidl, item);
3001     *item = LV_AddItem(pidl);
3002     return (int)*item >= 0 ? S_OK : E_OUTOFMEMORY;
3003 }
3004 
3005 HRESULT STDMETHODCALLTYPE CDefView::GetObject(PITEMID_CHILD *pidl, UINT item)
3006 {
3007     TRACE("(%p)->(%p %d)\n", this, pidl, item);
3008     return Item(item, pidl);
3009 }
3010 
3011 HRESULT STDMETHODCALLTYPE CDefView::RemoveObject(PITEMID_CHILD pidl, UINT *item)
3012 {
3013 
3014     TRACE("(%p)->(%p %p)\n", this, pidl, item);
3015 
3016     if (pidl)
3017     {
3018         *item = LV_FindItemByPidl(ILFindLastID(pidl));
3019         m_ListView.DeleteItem(*item);
3020     }
3021     else
3022     {
3023         *item = 0;
3024         m_ListView.DeleteAllItems();
3025     }
3026 
3027     return S_OK;
3028 }
3029 
3030 HRESULT STDMETHODCALLTYPE CDefView::GetObjectCount(UINT *count)
3031 {
3032     TRACE("(%p)->(%p)\n", this, count);
3033     *count = m_ListView.GetItemCount();
3034     return S_OK;
3035 }
3036 
3037 HRESULT STDMETHODCALLTYPE CDefView::SetObjectCount(UINT count, UINT flags)
3038 {
3039     FIXME("(%p)->(%d %x) stub\n", this, count, flags);
3040     return E_NOTIMPL;
3041 }
3042 
3043 HRESULT STDMETHODCALLTYPE CDefView::UpdateObject(PITEMID_CHILD pidl_old, PITEMID_CHILD pidl_new, UINT *item)
3044 {
3045     FIXME("(%p)->(%p %p %p) stub\n", this, pidl_old, pidl_new, item);
3046     return E_NOTIMPL;
3047 }
3048 
3049 HRESULT STDMETHODCALLTYPE CDefView::RefreshObject(PITEMID_CHILD pidl, UINT *item)
3050 {
3051     FIXME("(%p)->(%p %p) stub\n", this, pidl, item);
3052     return E_NOTIMPL;
3053 }
3054 
3055 HRESULT STDMETHODCALLTYPE CDefView::SetRedraw(BOOL redraw)
3056 {
3057     TRACE("(%p)->(%d)\n", this, redraw);
3058     m_ListView.SetRedraw(redraw);
3059     return S_OK;
3060 }
3061 
3062 HRESULT STDMETHODCALLTYPE CDefView::GetSelectedCount(UINT *count)
3063 {
3064     FIXME("(%p)->(%p) stub\n", this, count);
3065     return E_NOTIMPL;
3066 }
3067 
3068 HRESULT STDMETHODCALLTYPE CDefView::GetSelectedObjects(PCUITEMID_CHILD **pidl, UINT *items)
3069 {
3070     TRACE("(%p)->(%p %p)\n", this, pidl, items);
3071 
3072     *items = GetSelections();
3073 
3074     if (*items)
3075     {
3076         *pidl = static_cast<PCUITEMID_CHILD *>(LocalAlloc(0, *items * sizeof(PCUITEMID_CHILD)));
3077         if (!*pidl)
3078         {
3079             return E_OUTOFMEMORY;
3080         }
3081 
3082         /* it's documented that caller shouldn't PIDLs, only array itself */
3083         memcpy(*pidl, m_apidl, *items * sizeof(PCUITEMID_CHILD));
3084     }
3085 
3086     return S_OK;
3087 }
3088 
3089 HRESULT STDMETHODCALLTYPE CDefView::IsDropOnSource(IDropTarget *drop_target)
3090 {
3091     if ((m_iDragOverItem == -1 || m_pCurDropTarget == NULL) &&
3092         (m_pSourceDataObject.p))
3093     {
3094         return S_OK;
3095     }
3096 
3097     return S_FALSE;
3098 }
3099 
3100 HRESULT STDMETHODCALLTYPE CDefView::GetDragPoint(POINT *pt)
3101 {
3102     if (!pt)
3103         return E_INVALIDARG;
3104 
3105     *pt = m_ptFirstMousePos;
3106     return S_OK;
3107 }
3108 
3109 HRESULT STDMETHODCALLTYPE CDefView::GetDropPoint(POINT *pt)
3110 {
3111     FIXME("(%p)->(%p) stub\n", this, pt);
3112     return E_NOTIMPL;
3113 }
3114 
3115 HRESULT STDMETHODCALLTYPE CDefView::MoveIcons(IDataObject *obj)
3116 {
3117     TRACE("(%p)->(%p)\n", this, obj);
3118     return E_NOTIMPL;
3119 }
3120 
3121 HRESULT STDMETHODCALLTYPE CDefView::SetItemPos(PCUITEMID_CHILD pidl, POINT *pt)
3122 {
3123     FIXME("(%p)->(%p %p) stub\n", this, pidl, pt);
3124     return E_NOTIMPL;
3125 }
3126 
3127 HRESULT STDMETHODCALLTYPE CDefView::IsBkDropTarget(IDropTarget *drop_target)
3128 {
3129     FIXME("(%p)->(%p) stub\n", this, drop_target);
3130     return E_NOTIMPL;
3131 }
3132 
3133 HRESULT STDMETHODCALLTYPE CDefView::SetClipboard(BOOL move)
3134 {
3135     FIXME("(%p)->(%d) stub\n", this, move);
3136     return E_NOTIMPL;
3137 }
3138 
3139 HRESULT STDMETHODCALLTYPE CDefView::SetPoints(IDataObject *obj)
3140 {
3141     FIXME("(%p)->(%p) stub\n", this, obj);
3142     return E_NOTIMPL;
3143 }
3144 
3145 HRESULT STDMETHODCALLTYPE CDefView::GetItemSpacing(ITEMSPACING *spacing)
3146 {
3147     FIXME("(%p)->(%p) stub\n", this, spacing);
3148     return E_NOTIMPL;
3149 }
3150 
3151 HRESULT STDMETHODCALLTYPE CDefView::SetCallback(IShellFolderViewCB  *new_cb, IShellFolderViewCB **old_cb)
3152 {
3153     if (old_cb)
3154         *old_cb = m_pShellFolderViewCB.Detach();
3155 
3156     m_pShellFolderViewCB = new_cb;
3157     return S_OK;
3158 }
3159 
3160 HRESULT STDMETHODCALLTYPE CDefView::Select(UINT flags)
3161 {
3162     FIXME("(%p)->(%d) stub\n", this, flags);
3163     return E_NOTIMPL;
3164 }
3165 
3166 HRESULT STDMETHODCALLTYPE CDefView::QuerySupport(UINT *support)
3167 {
3168     TRACE("(%p)->(%p)\n", this, support);
3169     return S_OK;
3170 }
3171 
3172 HRESULT STDMETHODCALLTYPE CDefView::SetAutomationObject(IDispatch *disp)
3173 {
3174     FIXME("(%p)->(%p) stub\n", this, disp);
3175     return E_NOTIMPL;
3176 }
3177 
3178 /**********************************************************
3179  * ISVOleCmdTarget_QueryStatus (IOleCommandTarget)
3180  */
3181 HRESULT WINAPI CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText)
3182 {
3183     FIXME("(%p)->(%p(%s) 0x%08x %p %p\n",
3184           this, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
3185 
3186     if (!prgCmds)
3187         return E_INVALIDARG;
3188 
3189     for (UINT i = 0; i < cCmds; i++)
3190     {
3191         FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID);
3192         prgCmds[i].cmdf = 0;
3193     }
3194 
3195     return OLECMDERR_E_UNKNOWNGROUP;
3196 }
3197 
3198 /**********************************************************
3199  * ISVOleCmdTarget_Exec (IOleCommandTarget)
3200  *
3201  * nCmdID is the OLECMDID_* enumeration
3202  */
3203 HRESULT WINAPI CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
3204 {
3205     FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n",
3206           this, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut);
3207 
3208     if (!pguidCmdGroup)
3209         return OLECMDERR_E_UNKNOWNGROUP;
3210 
3211     if (IsEqualCLSID(*pguidCmdGroup, m_Category))
3212     {
3213         if (nCmdID == FCIDM_SHVIEW_AUTOARRANGE)
3214         {
3215             if (V_VT(pvaIn) != VT_INT_PTR)
3216                 return OLECMDERR_E_NOTSUPPORTED;
3217 
3218             TPMPARAMS params;
3219             params.cbSize = sizeof(params);
3220             params.rcExclude = *(RECT*) V_INTREF(pvaIn);
3221 
3222             if (m_hMenuViewModes)
3223             {
3224                 /* Duplicate all but the last two items of the view modes menu */
3225                 HMENU hmenuViewPopup = CreatePopupMenu();
3226                 Shell_MergeMenus(hmenuViewPopup, m_hMenuViewModes, 0, 0, 0xFFFF, 0);
3227                 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION);
3228                 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION);
3229                 CheckViewMode(hmenuViewPopup);
3230                 TrackPopupMenuEx(hmenuViewPopup, TPM_LEFTALIGN | TPM_TOPALIGN, params.rcExclude.left, params.rcExclude.bottom, m_hWndParent, &params);
3231                 ::DestroyMenu(hmenuViewPopup);
3232             }
3233 
3234             // pvaOut is VT_I4 with value 0x403 (cmd id of the new mode maybe?)
3235             V_VT(pvaOut) = VT_I4;
3236             V_I4(pvaOut) = 0x403;
3237         }
3238     }
3239 
3240     if (IsEqualIID(*pguidCmdGroup, CGID_Explorer) &&
3241             (nCmdID == 0x29) &&
3242             (nCmdexecopt == 4) && pvaOut)
3243         return S_OK;
3244 
3245     if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView) &&
3246             (nCmdID == 9) &&
3247             (nCmdexecopt == 0))
3248         return 1;
3249 
3250     return OLECMDERR_E_UNKNOWNGROUP;
3251 }
3252 
3253 /**********************************************************
3254  * ISVDropTarget implementation
3255  */
3256 
3257 /******************************************************************************
3258  * drag_notify_subitem [Internal]
3259  *
3260  * Figure out the shellfolder object, which is currently under the mouse cursor
3261  * and notify it via the IDropTarget interface.
3262  */
3263 
3264 #define SCROLLAREAWIDTH 20
3265 
3266 HRESULT CDefView::drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3267 {
3268     LONG lResult;
3269     HRESULT hr;
3270     RECT clientRect;
3271 
3272     /* The key state on drop doesn't have MK_LBUTTON or MK_RBUTTON because it
3273        reflects the key state after the user released the button, so we need
3274        to remember the last key state when the button was pressed */
3275     m_grfKeyState = grfKeyState;
3276 
3277     /* Map from global to client coordinates and query the index of the listview-item, which is
3278      * currently under the mouse cursor. */
3279     LVHITTESTINFO htinfo = {{pt.x, pt.y}, LVHT_ONITEM};
3280     ScreenToClient(&htinfo.pt);
3281     lResult = m_ListView.HitTest(&htinfo);
3282 
3283     /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */
3284     ::GetClientRect(m_ListView, &clientRect);
3285     if (htinfo.pt.x == m_ptLastMousePos.x && htinfo.pt.y == m_ptLastMousePos.y &&
3286             (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH ||
3287              htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH ))
3288     {
3289         m_cScrollDelay = (m_cScrollDelay + 1) % 5; /* DragOver is called every 50 ms */
3290         if (m_cScrollDelay == 0)
3291         {
3292             /* Mouse did hover another 250 ms over the scroll-area */
3293             if (htinfo.pt.x < SCROLLAREAWIDTH)
3294                 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEUP, 0);
3295 
3296             if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH)
3297                 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEDOWN, 0);
3298 
3299             if (htinfo.pt.y < SCROLLAREAWIDTH)
3300                 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEUP, 0);
3301 
3302             if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH)
3303                 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEDOWN, 0);
3304         }
3305     }
3306     else
3307     {
3308         m_cScrollDelay = 0; /* Reset, if the cursor is not over the listview's scroll-area */
3309     }
3310 
3311     m_ptLastMousePos = htinfo.pt;
3312     ::ClientToListView(m_ListView, &m_ptLastMousePos);
3313 
3314     /* We need to check if we drag the selection over itself */
3315     if (lResult != -1 && m_pSourceDataObject.p != NULL)
3316     {
3317         PCUITEMID_CHILD pidl = _PidlByItem(lResult);
3318 
3319         for (UINT i = 0; i < m_cidl; i++)
3320         {
3321             if (pidl == m_apidl[i])
3322             {
3323                 /* The item that is being draged is hovering itself. */
3324                 lResult = -1;
3325                 break;
3326             }
3327         }
3328     }
3329 
3330     /* If we are still over the previous sub-item, notify it via DragOver and return. */
3331     if (m_pCurDropTarget && lResult == m_iDragOverItem)
3332         return m_pCurDropTarget->DragOver(grfKeyState, pt, pdwEffect);
3333 
3334     /* We've left the previous sub-item, notify it via DragLeave and Release it. */
3335     if (m_pCurDropTarget)
3336     {
3337         PCUITEMID_CHILD pidl = _PidlByItem(m_iDragOverItem);
3338         if (pidl)
3339             SelectItem(pidl, 0);
3340 
3341         m_pCurDropTarget->DragLeave();
3342         m_pCurDropTarget.Release();
3343     }
3344 
3345     m_iDragOverItem = lResult;
3346 
3347     if (lResult == -1)
3348     {
3349         /* We are not above one of the listview's subitems. Bind to the parent folder's
3350          * DropTarget interface. */
3351         hr = m_pSFParent->CreateViewObject(NULL, IID_PPV_ARG(IDropTarget,&m_pCurDropTarget));
3352     }
3353     else
3354     {
3355         /* Query the relative PIDL of the shellfolder object represented by the currently
3356          * dragged over listview-item ... */
3357         PCUITEMID_CHILD pidl = _PidlByItem(lResult);
3358 
3359         /* ... and bind m_pCurDropTarget to the IDropTarget interface of an UIObject of this object */
3360         hr = m_pSFParent->GetUIObjectOf(m_ListView, 1, &pidl, IID_NULL_PPV_ARG(IDropTarget, &m_pCurDropTarget));
3361     }
3362 
3363     IUnknown_SetSite(m_pCurDropTarget, (IShellView *)this);
3364 
3365     /* If anything failed, m_pCurDropTarget should be NULL now, which ought to be a save state. */
3366     if (FAILED(hr))
3367     {
3368         *pdwEffect = DROPEFFECT_NONE;
3369         return hr;
3370     }
3371 
3372     if (m_iDragOverItem != -1)
3373     {
3374         SelectItem(m_iDragOverItem, SVSI_SELECT);
3375     }
3376 
3377     /* Notify the item just entered via DragEnter. */
3378     return m_pCurDropTarget->DragEnter(m_pCurDataObject, grfKeyState, pt, pdwEffect);
3379 }
3380 
3381 HRESULT WINAPI CDefView::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3382 {
3383     if (*pdwEffect == DROPEFFECT_NONE)
3384         return S_OK;
3385 
3386     /* Get a hold on the data object for later calls to DragEnter on the sub-folders */
3387     m_pCurDataObject = pDataObject;
3388 
3389     HRESULT hr = drag_notify_subitem(grfKeyState, pt, pdwEffect);
3390     if (SUCCEEDED(hr))
3391     {
3392         POINT ptClient = {pt.x, pt.y};
3393         ScreenToClient(&ptClient);
3394         ImageList_DragEnter(m_hWnd, ptClient.x, ptClient.y);
3395     }
3396 
3397     return hr;
3398 }
3399 
3400 HRESULT WINAPI CDefView::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3401 {
3402     POINT ptClient = {pt.x, pt.y};
3403     ScreenToClient(&ptClient);
3404     ImageList_DragMove(ptClient.x, ptClient.y);
3405     return drag_notify_subitem(grfKeyState, pt, pdwEffect);
3406 }
3407 
3408 HRESULT WINAPI CDefView::DragLeave()
3409 {
3410     ImageList_DragLeave(m_hWnd);
3411 
3412     if (m_pCurDropTarget)
3413     {
3414         m_pCurDropTarget->DragLeave();
3415         m_pCurDropTarget.Release();
3416     }
3417 
3418     if (m_pCurDataObject != NULL)
3419     {
3420         m_pCurDataObject.Release();
3421     }
3422 
3423     m_iDragOverItem = 0;
3424 
3425     return S_OK;
3426 }
3427 
3428 INT CDefView::_FindInsertableIndexFromPoint(POINT pt)
3429 {
3430     RECT rcBound;
3431     INT i, nCount = m_ListView.GetItemCount();
3432     DWORD dwSpacing;
3433     INT dx, dy;
3434     BOOL bSmall = ((m_ListView.GetStyle() & LVS_TYPEMASK) != LVS_ICON);
3435 
3436     /* FIXME: LVM_GETORIGIN is broken. See CORE-17266 */
3437     pt.x += m_ListView.GetScrollPos(SB_HORZ);
3438     pt.y += m_ListView.GetScrollPos(SB_VERT);
3439 
3440     if (m_ListView.GetStyle() & LVS_ALIGNLEFT)
3441     {
3442         // vertically
3443         for (i = 0; i < nCount; ++i)
3444         {
3445             dwSpacing = ListView_GetItemSpacing(m_ListView, bSmall);
3446             dx = LOWORD(dwSpacing);
3447             dy = HIWORD(dwSpacing);
3448             ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS);
3449             rcBound.right = rcBound.left + dx;
3450             rcBound.bottom = rcBound.top + dy;
3451             if (pt.x < rcBound.right && pt.y < (rcBound.top + rcBound.bottom) / 2)
3452             {
3453                 return i;
3454             }
3455         }
3456         for (i = nCount - 1; i >= 0; --i)
3457         {
3458             ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS);
3459             if (rcBound.left < pt.x && rcBound.top < pt.y)
3460             {
3461                 return i + 1;
3462             }
3463         }
3464     }
3465     else
3466     {
3467         // horizontally
3468         for (i = 0; i < nCount; ++i)
3469         {
3470             dwSpacing = ListView_GetItemSpacing(m_ListView, bSmall);
3471             dx = LOWORD(dwSpacing);
3472             dy = HIWORD(dwSpacing);
3473             ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS);
3474             rcBound.right = rcBound.left + dx;
3475             rcBound.bottom = rcBound.top + dy;
3476             if (pt.y < rcBound.bottom && pt.x < rcBound.left)
3477             {
3478                 return i;
3479             }
3480             if (pt.y < rcBound.bottom && pt.x < rcBound.right)
3481             {
3482                 return i + 1;
3483             }
3484         }
3485         for (i = nCount - 1; i >= 0; --i)
3486         {
3487             ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS);
3488             if (rcBound.left < pt.x && rcBound.top < pt.y)
3489             {
3490                 return i + 1;
3491             }
3492         }
3493     }
3494 
3495     return nCount;
3496 }
3497 
3498 typedef CSimpleMap<LPARAM, INT> CLParamIndexMap;
3499 
3500 static INT CALLBACK
3501 SelectionMoveCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
3502 {
3503     CLParamIndexMap *pmap = (CLParamIndexMap *)lParamSort;
3504     INT i1 = pmap->Lookup(lParam1), i2 = pmap->Lookup(lParam2);
3505     if (i1 < i2)
3506         return -1;
3507     if (i1 > i2)
3508         return 1;
3509     return 0;
3510 }
3511 
3512 void CDefView::_MoveSelectionOnAutoArrange(POINT pt)
3513 {
3514     // get insertable index from position
3515     INT iPosition = _FindInsertableIndexFromPoint(pt);
3516 
3517     // create identity mapping of indexes
3518     CSimpleArray<INT> array;
3519     INT nCount = m_ListView.GetItemCount();
3520     for (INT i = 0; i < nCount; ++i)
3521     {
3522         array.Add(i);
3523     }
3524 
3525     // re-ordering mapping
3526     INT iItem = -1;
3527     while ((iItem = m_ListView.GetNextItem(iItem, LVNI_SELECTED)) >= 0)
3528     {
3529         INT iFrom = iItem, iTo = iPosition;
3530         if (iFrom < iTo)
3531             --iTo;
3532         if (iFrom >= nCount)
3533             iFrom = nCount - 1;
3534         if (iTo >= nCount)
3535             iTo = nCount - 1;
3536 
3537         // shift indexes by swapping (like a bucket relay)
3538         if (iFrom < iTo)
3539         {
3540             for (INT i = iFrom; i < iTo; ++i)
3541             {
3542                 // swap array[i] and array[i + 1]
3543                 INT tmp = array[i];
3544                 array[i] = array[i + 1];
3545                 array[i + 1] = tmp;
3546             }
3547         }
3548         else
3549         {
3550             for (INT i = iFrom; i > iTo; --i)
3551             {
3552                 // swap array[i] and array[i - 1]
3553                 INT tmp = array[i];
3554                 array[i] = array[i - 1];
3555                 array[i - 1] = tmp;
3556             }
3557         }
3558     }
3559 
3560     // create mapping (ListView's lParam to index) from array
3561     CLParamIndexMap map;
3562     for (INT i = 0; i < nCount; ++i)
3563     {
3564         LPARAM lParam = m_ListView.GetItemData(array[i]);
3565         map.Add(lParam, i);
3566     }
3567 
3568     // finally sort
3569     m_ListView.SortItems(SelectionMoveCompareFunc, &map);
3570 }
3571 
3572 HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3573 {
3574     ImageList_DragLeave(m_hWnd);
3575     ImageList_EndDrag();
3576 
3577     if ((IsDropOnSource(NULL) == S_OK) &&
3578         (*pdwEffect & DROPEFFECT_MOVE) &&
3579         (m_grfKeyState & MK_LBUTTON))
3580     {
3581         if (m_pCurDropTarget)
3582         {
3583             m_pCurDropTarget->DragLeave();
3584             m_pCurDropTarget.Release();
3585         }
3586 
3587         POINT ptDrop = { pt.x, pt.y };
3588         ::ScreenToClient(m_ListView, &ptDrop);
3589         ::ClientToListView(m_ListView, &ptDrop);
3590         m_ptLastMousePos = ptDrop;
3591 
3592         m_ListView.SetRedraw(FALSE);
3593         if (m_ListView.GetStyle() & LVS_AUTOARRANGE)
3594         {
3595             _MoveSelectionOnAutoArrange(m_ptLastMousePos);
3596         }
3597         else
3598         {
3599             POINT ptItem;
3600             INT iItem = -1;
3601             while ((iItem = m_ListView.GetNextItem(iItem, LVNI_SELECTED)) >= 0)
3602             {
3603                 if (m_ListView.GetItemPosition(iItem, &ptItem))
3604                 {
3605                     ptItem.x += m_ptLastMousePos.x - m_ptFirstMousePos.x;
3606                     ptItem.y += m_ptLastMousePos.y - m_ptFirstMousePos.y;
3607                     m_ListView.SetItemPosition(iItem, &ptItem);
3608                 }
3609             }
3610         }
3611         m_ListView.SetRedraw(TRUE);
3612     }
3613     else if (m_pCurDropTarget)
3614     {
3615         m_pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect);
3616         m_pCurDropTarget.Release();
3617     }
3618 
3619     m_pCurDataObject.Release();
3620     m_iDragOverItem = 0;
3621     return S_OK;
3622 }
3623 
3624 /**********************************************************
3625  * ISVDropSource implementation
3626  */
3627 
3628 HRESULT WINAPI CDefView::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
3629 {
3630     TRACE("(%p)\n", this);
3631 
3632     if (fEscapePressed)
3633         return DRAGDROP_S_CANCEL;
3634     else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON))
3635         return DRAGDROP_S_DROP;
3636     else
3637         return S_OK;
3638 }
3639 
3640 HRESULT WINAPI CDefView::GiveFeedback(DWORD dwEffect)
3641 {
3642     TRACE("(%p)\n", this);
3643 
3644     return DRAGDROP_S_USEDEFAULTCURSORS;
3645 }
3646 
3647 /**********************************************************
3648  * ISVViewObject implementation
3649  */
3650 
3651 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)
3652 {
3653     FIXME("Stub: this=%p\n", this);
3654 
3655     return E_NOTIMPL;
3656 }
3657 
3658 HRESULT WINAPI CDefView::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet)
3659 {
3660     FIXME("Stub: this=%p\n", this);
3661 
3662     return E_NOTIMPL;
3663 }
3664 
3665 HRESULT WINAPI CDefView::Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze)
3666 {
3667     FIXME("Stub: this=%p\n", this);
3668 
3669     return E_NOTIMPL;
3670 }
3671 
3672 HRESULT WINAPI CDefView::Unfreeze(DWORD dwFreeze)
3673 {
3674     FIXME("Stub: this=%p\n", this);
3675 
3676     return E_NOTIMPL;
3677 }
3678 
3679 HRESULT WINAPI CDefView::SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink)
3680 {
3681     FIXME("partial stub: %p 0x%08x 0x%08x %p\n", this, aspects, advf, pAdvSink);
3682 
3683     /* FIXME: we set the AdviseSink, but never use it to send any advice */
3684     m_pAdvSink = pAdvSink;
3685     m_dwAspects = aspects;
3686     m_dwAdvf = advf;
3687 
3688     return S_OK;
3689 }
3690 
3691 HRESULT WINAPI CDefView::GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink)
3692 {
3693     TRACE("this=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n", this, pAspects, pAdvf, ppAdvSink);
3694 
3695     if (ppAdvSink)
3696     {
3697         *ppAdvSink = m_pAdvSink;
3698         m_pAdvSink.p->AddRef();
3699     }
3700 
3701     if (pAspects)
3702         *pAspects = m_dwAspects;
3703 
3704     if (pAdvf)
3705         *pAdvf = m_dwAdvf;
3706 
3707     return S_OK;
3708 }
3709 
3710 HRESULT STDMETHODCALLTYPE CDefView::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
3711 {
3712     if (IsEqualIID(guidService, SID_IShellBrowser))
3713         return m_pShellBrowser->QueryInterface(riid, ppvObject);
3714     else if(IsEqualIID(guidService, SID_IFolderView))
3715         return QueryInterface(riid, ppvObject);
3716 
3717     return E_NOINTERFACE;
3718 }
3719 
3720 HRESULT CDefView::_MergeToolbar()
3721 {
3722     CComPtr<IExplorerToolbar> ptb;
3723     HRESULT hr = S_OK;
3724 
3725     hr = IUnknown_QueryService(m_pShellBrowser, IID_IExplorerToolbar, IID_PPV_ARG(IExplorerToolbar, &ptb));
3726     if (FAILED(hr))
3727         return hr;
3728 
3729     m_Category = CGID_DefViewFrame;
3730 
3731     hr = ptb->SetCommandTarget(static_cast<IOleCommandTarget*>(this), &m_Category, 0);
3732     if (FAILED(hr))
3733         return hr;
3734 
3735     if (hr == S_FALSE)
3736         return S_OK;
3737 
3738 #if 0
3739     hr = ptb->AddButtons(&m_Category, buttonsCount, buttons);
3740     if (FAILED(hr))
3741         return hr;
3742 #endif
3743 
3744     return S_OK;
3745 }
3746 
3747 HRESULT CDefView::_DoFolderViewCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
3748 {
3749     HRESULT hr = E_NOTIMPL;
3750 
3751     if (m_pShellFolderViewCB)
3752     {
3753         hr = m_pShellFolderViewCB->MessageSFVCB(uMsg, wParam, lParam);
3754     }
3755 
3756     return hr;
3757 }
3758 
3759 HRESULT CDefView_CreateInstance(IShellFolder *pFolder, REFIID riid, LPVOID * ppvOut)
3760 {
3761     return ShellObjectCreatorInit<CDefView>(pFolder, riid, ppvOut);
3762 }
3763 
3764 HRESULT WINAPI SHCreateShellFolderViewEx(
3765     LPCSFV psvcbi,    /* [in] shelltemplate struct */
3766     IShellView **ppsv) /* [out] IShellView pointer */
3767 {
3768     CComPtr<IShellView> psv;
3769     HRESULT hRes;
3770 
3771     TRACE("sf=%p pidl=%p cb=%p mode=0x%08x parm=%p\n",
3772       psvcbi->pshf, psvcbi->pidl, psvcbi->pfnCallback,
3773       psvcbi->fvm, psvcbi->psvOuter);
3774 
3775     *ppsv = NULL;
3776     hRes = CDefView_CreateInstance(psvcbi->pshf, IID_PPV_ARG(IShellView, &psv));
3777     if (FAILED_UNEXPECTEDLY(hRes))
3778         return hRes;
3779 
3780     *ppsv = psv.Detach();
3781     return hRes;
3782 }
3783 
3784 HRESULT WINAPI SHCreateShellFolderView(const SFV_CREATE *pcsfv,
3785                         IShellView **ppsv)
3786 {
3787     CComPtr<IShellView> psv;
3788     HRESULT hRes;
3789 
3790     if (!ppsv)
3791         return E_INVALIDARG;
3792 
3793     *ppsv = NULL;
3794 
3795     if (!pcsfv || pcsfv->cbSize != sizeof(*pcsfv))
3796         return E_INVALIDARG;
3797 
3798     TRACE("sf=%p outer=%p callback=%p\n",
3799       pcsfv->pshf, pcsfv->psvOuter, pcsfv->psfvcb);
3800 
3801     hRes = CDefView_CreateInstance(pcsfv->pshf, IID_PPV_ARG(IShellView, &psv));
3802     if (FAILED(hRes))
3803         return hRes;
3804 
3805     if (pcsfv->psfvcb)
3806     {
3807         CComPtr<IShellFolderView> sfv;
3808         if (SUCCEEDED(psv->QueryInterface(IID_PPV_ARG(IShellFolderView, &sfv))))
3809         {
3810             sfv->SetCallback(pcsfv->psfvcb, NULL);
3811         }
3812     }
3813 
3814     *ppsv = psv.Detach();
3815     return hRes;
3816 }
3817