xref: /reactos/dll/win32/shell32/CDefView.cpp (revision 53221834)
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                 if (!(dwAttr & SFGAO_LINK) && (lpdi->item.mask & LVIF_TEXT) && !SelectExtOnRename())
2097                 {
2098                     LPWSTR pszText = lpdi->item.pszText;
2099                     LPWSTR pchDotExt = PathFindExtensionW(pszText);
2100                     ::PostMessageW(hEdit, EM_SETSEL, 0, pchDotExt - pszText);
2101                     ::PostMessageW(hEdit, EM_SCROLLCARET, 0, 0);
2102                 }
2103 
2104                 m_isEditing = TRUE;
2105                 return FALSE;
2106             }
2107 
2108             return TRUE;
2109         }
2110 
2111         case LVN_ENDLABELEDITW:
2112         {
2113             TRACE("-- LVN_ENDLABELEDITW %p\n", this);
2114 
2115             m_isEditing = FALSE;
2116 
2117             if (lpdi->item.pszText)
2118             {
2119                 HRESULT hr;
2120                 LVITEMW lvItem;
2121 
2122                 pidl = _PidlByItem(lpdi->item);
2123                 PITEMID_CHILD pidlNew = NULL;
2124                 hr = m_pSFParent->SetNameOf(0, pidl, lpdi->item.pszText, SHGDN_INFOLDER, &pidlNew);
2125 
2126                 if (SUCCEEDED(hr) && pidlNew)
2127                 {
2128                     lvItem.mask = LVIF_PARAM|LVIF_IMAGE;
2129                     lvItem.iItem = lpdi->item.iItem;
2130                     lvItem.iSubItem = 0;
2131                     lvItem.lParam = reinterpret_cast<LPARAM>(pidlNew);
2132                     lvItem.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidlNew, 0);
2133                     m_ListView.SetItem(&lvItem);
2134                     m_ListView.Update(lpdi->item.iItem);
2135                     return TRUE;
2136                 }
2137             }
2138 
2139             return FALSE;
2140         }
2141 
2142         default:
2143             TRACE("-- %p WM_COMMAND %x unhandled\n", this, lpnmh->code);
2144             break;
2145     }
2146 
2147     return 0;
2148 }
2149 
2150 /*
2151  * This is just a quick hack to make the desktop work correctly.
2152  * ITranslateShellChangeNotify's IsChildID is undocumented, but most likely the way that
2153  * a folder should know if it should update upon a change notification.
2154  * It is exported by merged folders at a minimum.
2155  */
2156 static BOOL ILIsParentOrSpecialParent(PCIDLIST_ABSOLUTE pidl1, PCIDLIST_ABSOLUTE pidl2)
2157 {
2158     if (!pidl1 || !pidl2)
2159         return FALSE;
2160     if (ILIsParent(pidl1, pidl2, TRUE))
2161         return TRUE;
2162 
2163     if (_ILIsDesktop(pidl1))
2164     {
2165         PIDLIST_ABSOLUTE deskpidl;
2166         SHGetFolderLocation(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 0, &deskpidl);
2167         if (ILIsParent(deskpidl, pidl2, TRUE))
2168         {
2169             ILFree(deskpidl);
2170             return TRUE;
2171         }
2172         ILFree(deskpidl);
2173         SHGetFolderLocation(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL, 0, &deskpidl);
2174         if (ILIsParent(deskpidl, pidl2, TRUE))
2175         {
2176             ILFree(deskpidl);
2177             return TRUE;
2178         }
2179         ILFree(deskpidl);
2180     }
2181 
2182     WCHAR szPath1[MAX_PATH], szPath2[MAX_PATH];
2183     LPITEMIDLIST pidl2Clone = ILClone(pidl2);
2184     ILRemoveLastID(pidl2Clone);
2185     if (SHGetPathFromIDListW(pidl1, szPath1) &&
2186         SHGetPathFromIDListW(pidl2Clone, szPath2))
2187     {
2188         if (lstrcmpiW(szPath1, szPath2) == 0)
2189         {
2190             ILFree(pidl2Clone);
2191             return TRUE;
2192         }
2193     }
2194     ILFree(pidl2Clone);
2195 
2196     return FALSE;
2197 }
2198 
2199 /**********************************************************
2200 * ShellView_OnChange()
2201 */
2202 LRESULT CDefView::OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2203 {
2204     HANDLE hChange = (HANDLE)wParam;
2205     DWORD dwProcID = (DWORD)lParam;
2206     PIDLIST_ABSOLUTE *Pidls;
2207     LONG lEvent;
2208     HANDLE hLock = SHChangeNotification_Lock(hChange, dwProcID, &Pidls, &lEvent);
2209     if (hLock == NULL)
2210     {
2211         ERR("hLock == NULL\n");
2212         return FALSE;
2213     }
2214 
2215     BOOL bParent0 = ILIsParentOrSpecialParent(m_pidlParent, Pidls[0]);
2216     BOOL bParent1 = ILIsParentOrSpecialParent(m_pidlParent, Pidls[1]);
2217 
2218     TRACE("(%p)(%p,%p,0x%08x)\n", this, Pidls[0], Pidls[1], lParam);
2219 
2220     lEvent &= ~SHCNE_INTERRUPT;
2221     switch (lEvent)
2222     {
2223         case SHCNE_MKDIR:
2224         case SHCNE_CREATE:
2225             if (bParent0)
2226             {
2227                 if (LV_FindItemByPidl(ILFindLastID(Pidls[0])) == -1)
2228                 {
2229                     LV_AddItem(ILFindLastID(Pidls[0]));
2230                 }
2231                 else
2232                 {
2233                     LV_ProdItem(ILFindLastID(Pidls[0]));
2234                 }
2235             }
2236             break;
2237 
2238         case SHCNE_RMDIR:
2239         case SHCNE_DELETE:
2240             if (bParent0)
2241                 LV_DeleteItem(ILFindLastID(Pidls[0]));
2242             break;
2243 
2244         case SHCNE_RENAMEFOLDER:
2245         case SHCNE_RENAMEITEM:
2246             if (bParent0 && bParent1)
2247                 LV_RenameItem(ILFindLastID(Pidls[0]), ILFindLastID(Pidls[1]));
2248             else if (bParent0)
2249                 LV_DeleteItem(ILFindLastID(Pidls[0]));
2250             else if (bParent1)
2251                 LV_AddItem(ILFindLastID(Pidls[1]));
2252             break;
2253 
2254         case SHCNE_UPDATEITEM:
2255             if (bParent0)
2256                 LV_RenameItem(ILFindLastID(Pidls[0]), ILFindLastID(Pidls[0]));
2257             break;
2258 
2259         case SHCNE_UPDATEDIR:
2260             Refresh();
2261             break;
2262     }
2263 
2264     SHChangeNotification_Unlock(hLock);
2265     return TRUE;
2266 }
2267 
2268 HRESULT SHGetMenuIdFromMenuMsg(UINT uMsg, LPARAM lParam, UINT *CmdId);
2269 HRESULT SHSetMenuIdInMenuMsg(UINT uMsg, LPARAM lParam, UINT CmdId);
2270 
2271 /**********************************************************
2272 *  CDefView::OnCustomItem
2273 */
2274 LRESULT CDefView::OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2275 {
2276     if (!m_pCM.p)
2277     {
2278         /* no menu */
2279         ERR("no menu!!!\n");
2280         return FALSE;
2281     }
2282 
2283     /* The lParam of WM_DRAWITEM WM_MEASUREITEM contain a menu id and this also needs to
2284        be changed to a menu identifier offset */
2285     UINT CmdID;
2286     HRESULT hres = SHGetMenuIdFromMenuMsg(uMsg, lParam, &CmdID);
2287     if (SUCCEEDED(hres))
2288         SHSetMenuIdInMenuMsg(uMsg, lParam, CmdID - CONTEXT_MENU_BASE_ID);
2289 
2290     /* Forward the message to the IContextMenu2 */
2291     LRESULT result;
2292     hres = SHForwardContextMenuMsg(m_pCM, uMsg, wParam, lParam, &result, TRUE);
2293 
2294     return (SUCCEEDED(hres));
2295 }
2296 
2297 LRESULT CDefView::OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2298 {
2299     /* Wallpaper setting affects drop shadows effect */
2300     if (wParam == SPI_SETDESKWALLPAPER || wParam == 0)
2301         UpdateListColors();
2302 
2303     return S_OK;
2304 }
2305 
2306 /**********************************************************
2307 *  CDefView::OnInitMenuPopup
2308 */
2309 LRESULT CDefView::OnInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2310 {
2311     HMENU hmenu = (HMENU) wParam;
2312     int nPos = LOWORD(lParam);
2313     UINT  menuItemId;
2314 
2315     OnCustomItem(uMsg, wParam, lParam, bHandled);
2316 
2317     HMENU hViewMenu = GetSubmenuByID(m_hMenu, FCIDM_MENU_VIEW);
2318 
2319     if (GetSelections() == 0)
2320     {
2321         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_CUT, MF_GRAYED);
2322         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_COPY, MF_GRAYED);
2323         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_RENAME, MF_GRAYED);
2324         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_COPYTO, MF_GRAYED);
2325         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_MOVETO, MF_GRAYED);
2326         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_DELETE, MF_GRAYED);
2327     }
2328     else
2329     {
2330         // FIXME: Check copyable
2331         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_CUT, MF_ENABLED);
2332         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_COPY, MF_ENABLED);
2333         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_RENAME, MF_ENABLED);
2334         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_COPYTO, MF_ENABLED);
2335         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_MOVETO, MF_ENABLED);
2336         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_DELETE, MF_ENABLED);
2337     }
2338 
2339     /* Lets try to find out what the hell wParam is */
2340     if (hmenu == GetSubMenu(m_hMenu, nPos))
2341         menuItemId = ReallyGetMenuItemID(m_hMenu, nPos);
2342     else if (hViewMenu && hmenu == GetSubMenu(hViewMenu, nPos))
2343         menuItemId = ReallyGetMenuItemID(hViewMenu, nPos);
2344     else if (m_hContextMenu && hmenu == GetSubMenu(m_hContextMenu, nPos))
2345         menuItemId = ReallyGetMenuItemID(m_hContextMenu, nPos);
2346     else
2347         return FALSE;
2348 
2349     switch (menuItemId)
2350     {
2351     case FCIDM_MENU_FILE:
2352         FillFileMenu();
2353         break;
2354     case FCIDM_MENU_VIEW:
2355     case FCIDM_SHVIEW_VIEW:
2356         CheckViewMode(hmenu);
2357         break;
2358     case FCIDM_SHVIEW_ARRANGE:
2359         FillArrangeAsMenu(hmenu);
2360         break;
2361     }
2362 
2363     return FALSE;
2364 }
2365 
2366 /**********************************************************
2367 *
2368 *
2369 *  The INTERFACE of the IShellView object
2370 *
2371 *
2372 **********************************************************
2373 */
2374 
2375 /**********************************************************
2376 *  ShellView_GetWindow
2377 */
2378 HRESULT WINAPI CDefView::GetWindow(HWND *phWnd)
2379 {
2380     TRACE("(%p)\n", this);
2381 
2382     *phWnd = m_hWnd;
2383 
2384     return S_OK;
2385 }
2386 
2387 HRESULT WINAPI CDefView::ContextSensitiveHelp(BOOL fEnterMode)
2388 {
2389     FIXME("(%p) stub\n", this);
2390 
2391     return E_NOTIMPL;
2392 }
2393 
2394 /**********************************************************
2395 * IShellView_TranslateAccelerator
2396 *
2397 * FIXME:
2398 *  use the accel functions
2399 */
2400 HRESULT WINAPI CDefView::TranslateAccelerator(LPMSG lpmsg)
2401 {
2402     if (m_isEditing)
2403         return S_FALSE;
2404 
2405     if (lpmsg->message >= WM_KEYFIRST && lpmsg->message <= WM_KEYLAST)
2406     {
2407         if (::TranslateAcceleratorW(m_hWnd, m_hAccel, lpmsg) != 0)
2408             return S_OK;
2409 
2410         TRACE("-- key=0x%04lx\n", lpmsg->wParam) ;
2411     }
2412 
2413     return m_pShellBrowser->TranslateAcceleratorSB(lpmsg, 0);
2414 }
2415 
2416 HRESULT WINAPI CDefView::EnableModeless(BOOL fEnable)
2417 {
2418     FIXME("(%p) stub\n", this);
2419 
2420     return E_NOTIMPL;
2421 }
2422 
2423 HRESULT WINAPI CDefView::UIActivate(UINT uState)
2424 {
2425     // CHAR szName[MAX_PATH];
2426     LRESULT lResult;
2427     int nPartArray[1] = { -1};
2428 
2429     TRACE("(%p)->(state=%x) stub\n", this, uState);
2430 
2431     /* don't do anything if the state isn't really changing */
2432     if (m_uState == uState)
2433     {
2434         return S_OK;
2435     }
2436 
2437     /* OnActivate handles the menu merging and internal state */
2438     DoActivate(uState);
2439 
2440     /* only do This if we are active */
2441     if (uState != SVUIA_DEACTIVATE)
2442     {
2443 
2444         /*
2445             GetFolderPath is not a method of IShellFolder
2446             IShellFolder_GetFolderPath( m_pSFParent, szName, sizeof(szName) );
2447         */
2448         /* set the number of parts */
2449         m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, 1, (LPARAM)nPartArray, &lResult);
2450 
2451         /* set the text for the parts */
2452         /*
2453             m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXTA, 0, (LPARAM)szName, &lResult);
2454         */
2455     }
2456 
2457     return S_OK;
2458 }
2459 
2460 HRESULT WINAPI CDefView::Refresh()
2461 {
2462     TRACE("(%p)\n", this);
2463 
2464     _DoFolderViewCB(SFVM_LISTREFRESHED, TRUE, 0);
2465 
2466     m_ListView.DeleteAllItems();
2467     FillList();
2468 
2469     return S_OK;
2470 }
2471 
2472 HRESULT WINAPI CDefView::CreateViewWindow(IShellView *lpPrevView, LPCFOLDERSETTINGS lpfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd)
2473 {
2474     return CreateViewWindow3(psb, lpPrevView, SV3CVW3_DEFAULT,
2475         (FOLDERFLAGS)lpfs->fFlags, (FOLDERFLAGS)lpfs->fFlags, (FOLDERVIEWMODE)lpfs->ViewMode, NULL, prcView, phWnd);
2476 }
2477 
2478 HRESULT WINAPI CDefView::DestroyViewWindow()
2479 {
2480     TRACE("(%p)\n", this);
2481 
2482     /* Make absolutely sure all our UI is cleaned up */
2483     UIActivate(SVUIA_DEACTIVATE);
2484 
2485     if (m_hAccel)
2486     {
2487         // "Accelerator tables loaded from resources are freed automatically when the application terminates." -- MSDN
2488         m_hAccel = NULL;
2489     }
2490 
2491     if (m_hMenuArrangeModes)
2492     {
2493         DestroyMenu(m_hMenuArrangeModes);
2494         m_hMenuArrangeModes = NULL;
2495     }
2496 
2497     if (m_hMenuViewModes)
2498     {
2499         DestroyMenu(m_hMenuViewModes);
2500         m_hMenuViewModes = NULL;
2501     }
2502 
2503     if (m_hMenu)
2504     {
2505         DestroyMenu(m_hMenu);
2506         m_hMenu = NULL;
2507     }
2508 
2509     if (m_ListView)
2510     {
2511         m_ListView.DestroyWindow();
2512     }
2513 
2514     if (m_hWnd)
2515     {
2516         _DoFolderViewCB(SFVM_WINDOWCLOSING, (WPARAM)m_hWnd, 0);
2517         DestroyWindow();
2518     }
2519 
2520     m_pShellBrowser.Release();
2521     m_pCommDlgBrowser.Release();
2522 
2523     return S_OK;
2524 }
2525 
2526 HRESULT WINAPI CDefView::GetCurrentInfo(LPFOLDERSETTINGS lpfs)
2527 {
2528     TRACE("(%p)->(%p) vmode=%x flags=%x\n", this, lpfs,
2529           m_FolderSettings.ViewMode, m_FolderSettings.fFlags);
2530 
2531     if (!lpfs)
2532         return E_INVALIDARG;
2533 
2534     *lpfs = m_FolderSettings;
2535     return S_OK;
2536 }
2537 
2538 HRESULT WINAPI CDefView::AddPropertySheetPages(DWORD dwReserved, LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam)
2539 {
2540     FIXME("(%p) stub\n", this);
2541 
2542     return E_NOTIMPL;
2543 }
2544 
2545 HRESULT WINAPI CDefView::SaveViewState()
2546 {
2547     FIXME("(%p) stub\n", this);
2548 
2549     return S_OK;
2550 }
2551 
2552 HRESULT WINAPI CDefView::SelectItem(PCUITEMID_CHILD pidl, UINT uFlags)
2553 {
2554     int i;
2555 
2556     TRACE("(%p)->(pidl=%p, 0x%08x) stub\n", this, pidl, uFlags);
2557 
2558     i = LV_FindItemByPidl(pidl);
2559     if (i == -1)
2560         return S_OK;
2561 
2562     LVITEMW lvItem = {0};
2563     lvItem.mask = LVIF_STATE;
2564     lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
2565 
2566     while (m_ListView.GetItem(&lvItem))
2567     {
2568         if (lvItem.iItem == i)
2569         {
2570             if (uFlags & SVSI_SELECT)
2571                 lvItem.state |= LVIS_SELECTED;
2572             else
2573                 lvItem.state &= ~LVIS_SELECTED;
2574 
2575             if (uFlags & SVSI_FOCUSED)
2576                 lvItem.state |= LVIS_FOCUSED;
2577             else
2578                 lvItem.state &= ~LVIS_FOCUSED;
2579         }
2580         else
2581         {
2582             if (uFlags & SVSI_DESELECTOTHERS)
2583             {
2584                 lvItem.state &= ~LVIS_SELECTED;
2585             }
2586             lvItem.state &= ~LVIS_FOCUSED;
2587         }
2588 
2589         m_ListView.SetItem(&lvItem);
2590         lvItem.iItem++;
2591     }
2592 
2593     if (uFlags & SVSI_ENSUREVISIBLE)
2594         m_ListView.EnsureVisible(i, FALSE);
2595 
2596     if((uFlags & SVSI_EDIT) == SVSI_EDIT)
2597         m_ListView.EditLabel(i);
2598 
2599     return S_OK;
2600 }
2601 
2602 HRESULT WINAPI CDefView::GetItemObject(UINT uItem, REFIID riid, LPVOID *ppvOut)
2603 {
2604     HRESULT hr = E_NOINTERFACE;
2605 
2606     TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n", this, uItem, debugstr_guid(&riid), ppvOut);
2607 
2608     if (!ppvOut)
2609         return E_INVALIDARG;
2610 
2611     *ppvOut = NULL;
2612 
2613     switch (uItem)
2614     {
2615         case SVGIO_BACKGROUND:
2616             if (IsEqualIID(riid, IID_IContextMenu))
2617             {
2618                 hr = CDefViewBckgrndMenu_CreateInstance(m_pSF2Parent, riid, ppvOut);
2619                 if (FAILED_UNEXPECTEDLY(hr))
2620                     return hr;
2621 
2622                 IUnknown_SetSite(*((IUnknown**)ppvOut), (IShellView *)this);
2623             }
2624             else if (IsEqualIID(riid, IID_IDispatch))
2625             {
2626                 if (m_pShellFolderViewDual == NULL)
2627                 {
2628                     hr = CDefViewDual_Constructor(riid, (LPVOID*)&m_pShellFolderViewDual);
2629                     if (FAILED_UNEXPECTEDLY(hr))
2630                         return hr;
2631                 }
2632                 hr = m_pShellFolderViewDual->QueryInterface(riid, ppvOut);
2633             }
2634             break;
2635 
2636         case SVGIO_SELECTION:
2637             GetSelections();
2638             hr = m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, riid, 0, ppvOut);
2639             if (FAILED_UNEXPECTEDLY(hr))
2640                 return hr;
2641 
2642             if (IsEqualIID(riid, IID_IContextMenu))
2643                 IUnknown_SetSite(*((IUnknown**)ppvOut), (IShellView *)this);
2644 
2645             break;
2646     }
2647 
2648     TRACE("-- (%p)->(interface=%p)\n", this, *ppvOut);
2649 
2650     return hr;
2651 }
2652 
2653 HRESULT STDMETHODCALLTYPE CDefView::GetCurrentViewMode(UINT *pViewMode)
2654 {
2655     TRACE("(%p)->(%p), stub\n", this, pViewMode);
2656 
2657     if (!pViewMode)
2658         return E_INVALIDARG;
2659 
2660     *pViewMode = m_FolderSettings.ViewMode;
2661     return S_OK;
2662 }
2663 
2664 HRESULT STDMETHODCALLTYPE CDefView::SetCurrentViewMode(UINT ViewMode)
2665 {
2666     DWORD dwStyle;
2667     TRACE("(%p)->(%u), stub\n", this, ViewMode);
2668 
2669     /* It's not redundant to check FVM_AUTO because it's a (UINT)-1 */
2670     if (((INT)ViewMode < FVM_FIRST || (INT)ViewMode > FVM_LAST) && ((INT)ViewMode != FVM_AUTO))
2671         return E_INVALIDARG;
2672 
2673     /* Windows before Vista uses LVM_SETVIEW and possibly
2674        LVM_SETEXTENDEDLISTVIEWSTYLE to set the style of the listview,
2675        while later versions seem to accomplish this through other
2676        means. */
2677     switch (ViewMode)
2678     {
2679         case FVM_ICON:
2680             dwStyle = LVS_ICON;
2681             break;
2682         case FVM_DETAILS:
2683             dwStyle = LVS_REPORT;
2684             break;
2685         case FVM_SMALLICON:
2686             dwStyle = LVS_SMALLICON;
2687             break;
2688         case FVM_LIST:
2689             dwStyle = LVS_LIST;
2690             break;
2691         default:
2692         {
2693             FIXME("ViewMode %d not implemented\n", ViewMode);
2694             dwStyle = LVS_LIST;
2695             break;
2696         }
2697     }
2698 
2699     m_ListView.ModifyStyle(LVS_TYPEMASK, dwStyle);
2700 
2701     /* This will not necessarily be the actual mode set above.
2702        This mimics the behavior of Windows XP. */
2703     m_FolderSettings.ViewMode = ViewMode;
2704 
2705     return S_OK;
2706 }
2707 
2708 HRESULT STDMETHODCALLTYPE CDefView::GetFolder(REFIID riid, void **ppv)
2709 {
2710     if (m_pSFParent == NULL)
2711         return E_FAIL;
2712 
2713     return m_pSFParent->QueryInterface(riid, ppv);
2714 }
2715 
2716 HRESULT STDMETHODCALLTYPE CDefView::Item(int iItemIndex, PITEMID_CHILD *ppidl)
2717 {
2718     PCUITEMID_CHILD pidl = _PidlByItem(iItemIndex);
2719     if (pidl)
2720     {
2721         *ppidl = ILClone(pidl);
2722         return S_OK;
2723     }
2724 
2725     *ppidl = 0;
2726     return E_INVALIDARG;
2727 }
2728 
2729 HRESULT STDMETHODCALLTYPE CDefView::ItemCount(UINT uFlags, int *pcItems)
2730 {
2731     TRACE("(%p)->(%u %p)\n", this, uFlags, pcItems);
2732 
2733     if (uFlags != SVGIO_ALLVIEW)
2734         FIXME("some flags unsupported, %x\n", uFlags & ~SVGIO_ALLVIEW);
2735 
2736     *pcItems = m_ListView.GetItemCount();
2737 
2738     return S_OK;
2739 }
2740 
2741 HRESULT STDMETHODCALLTYPE CDefView::Items(UINT uFlags, REFIID riid, void **ppv)
2742 {
2743     return E_NOTIMPL;
2744 }
2745 
2746 HRESULT STDMETHODCALLTYPE CDefView::GetSelectionMarkedItem(int *piItem)
2747 {
2748     TRACE("(%p)->(%p)\n", this, piItem);
2749 
2750     *piItem = m_ListView.GetSelectionMark();
2751 
2752     return S_OK;
2753 }
2754 
2755 HRESULT STDMETHODCALLTYPE CDefView::GetFocusedItem(int *piItem)
2756 {
2757     TRACE("(%p)->(%p)\n", this, piItem);
2758 
2759     *piItem = m_ListView.GetNextItem(-1, LVNI_FOCUSED);
2760 
2761     return S_OK;
2762 }
2763 
2764 HRESULT STDMETHODCALLTYPE CDefView::GetItemPosition(PCUITEMID_CHILD pidl, POINT *ppt)
2765 {
2766     int lvIndex = LV_FindItemByPidl(pidl);
2767     if (lvIndex == -1 || ppt == NULL)
2768         return E_INVALIDARG;
2769 
2770     m_ListView.GetItemPosition(lvIndex, ppt);
2771     return S_OK;
2772 }
2773 
2774 HRESULT STDMETHODCALLTYPE CDefView::GetSpacing(POINT *ppt)
2775 {
2776     TRACE("(%p)->(%p)\n", this, ppt);
2777 
2778     if (!m_ListView)
2779         return S_FALSE;
2780 
2781     if (ppt)
2782     {
2783         SIZE spacing;
2784         m_ListView.GetItemSpacing(spacing);
2785 
2786         ppt->x = spacing.cx;
2787         ppt->y = spacing.cy;
2788     }
2789 
2790     return S_OK;
2791 }
2792 
2793 HRESULT STDMETHODCALLTYPE CDefView::GetDefaultSpacing(POINT *ppt)
2794 {
2795     return E_NOTIMPL;
2796 }
2797 
2798 HRESULT STDMETHODCALLTYPE CDefView::GetAutoArrange()
2799 {
2800     return ((m_ListView.GetStyle() & LVS_AUTOARRANGE) ? S_OK : S_FALSE);
2801 }
2802 
2803 HRESULT CDefView::_GetSnapToGrid()
2804 {
2805     DWORD dwExStyle = (DWORD)m_ListView.SendMessage(LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
2806     return ((dwExStyle & LVS_EX_SNAPTOGRID) ? S_OK : S_FALSE);
2807 }
2808 
2809 HRESULT STDMETHODCALLTYPE CDefView::SelectItem(int iItem, DWORD dwFlags)
2810 {
2811     LVITEMW lvItem;
2812 
2813     TRACE("(%p)->(%d, %x)\n", this, iItem, dwFlags);
2814 
2815     lvItem.state = 0;
2816     lvItem.stateMask = LVIS_SELECTED;
2817 
2818     if (dwFlags & SVSI_ENSUREVISIBLE)
2819         m_ListView.EnsureVisible(iItem, 0);
2820 
2821     /* all items */
2822     if (dwFlags & SVSI_DESELECTOTHERS)
2823         m_ListView.SetItemState(-1, 0, LVIS_SELECTED);
2824 
2825     /* this item */
2826     if (dwFlags & SVSI_SELECT)
2827         lvItem.state |= LVIS_SELECTED;
2828 
2829     if (dwFlags & SVSI_FOCUSED)
2830         lvItem.stateMask |= LVIS_FOCUSED;
2831 
2832     m_ListView.SetItemState(iItem, lvItem.state, lvItem.stateMask);
2833 
2834     if ((dwFlags & SVSI_EDIT) == SVSI_EDIT)
2835         m_ListView.EditLabel(iItem);
2836 
2837     return S_OK;
2838 }
2839 
2840 HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItems(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, POINT *apt, DWORD dwFlags)
2841 {
2842     /* Reset the selection */
2843     m_ListView.SetItemState(-1, 0, LVIS_SELECTED);
2844 
2845     int lvIndex;
2846     for (UINT i = 0 ; i < m_cidl; i++)
2847     {
2848         lvIndex = LV_FindItemByPidl(apidl[i]);
2849         if (lvIndex != -1)
2850         {
2851             SelectItem(lvIndex, dwFlags);
2852             m_ListView.SetItemPosition(lvIndex, &apt[i]);
2853         }
2854     }
2855 
2856     return S_OK;
2857 }
2858 
2859 /**********************************************************
2860  * IShellView2 implementation
2861  */
2862 
2863 HRESULT STDMETHODCALLTYPE CDefView::GetView(SHELLVIEWID *view_guid, ULONG view_type)
2864 {
2865     FIXME("(%p)->(%p, %lu) stub\n", this, view_guid, view_type);
2866     return E_NOTIMPL;
2867 }
2868 
2869 HRESULT STDMETHODCALLTYPE CDefView::CreateViewWindow2(LPSV2CVW2_PARAMS view_params)
2870 {
2871     return CreateViewWindow3(view_params->psbOwner, view_params->psvPrev,
2872         SV3CVW3_DEFAULT, (FOLDERFLAGS)view_params->pfs->fFlags, (FOLDERFLAGS)view_params->pfs->fFlags,
2873         (FOLDERVIEWMODE)view_params->pfs->ViewMode, view_params->pvid, view_params->prcView, &view_params->hwndView);
2874 }
2875 
2876 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)
2877 {
2878     OLEMENUGROUPWIDTHS omw = { { 0, 0, 0, 0, 0, 0 } };
2879 
2880     *hwnd = NULL;
2881 
2882     TRACE("(%p)->(shlview=%p shlbrs=%p rec=%p hwnd=%p vmode=%x flags=%x)\n", this, psvPrevious, psb, prcView, hwnd, mode, flags);
2883     if (prcView != NULL)
2884         TRACE("-- left=%i top=%i right=%i bottom=%i\n", prcView->left, prcView->top, prcView->right, prcView->bottom);
2885 
2886     /* Validate the Shell Browser */
2887     if (psb == NULL || m_hWnd)
2888         return E_UNEXPECTED;
2889 
2890     if (view_flags != SV3CVW3_DEFAULT)
2891         FIXME("unsupported view flags 0x%08x\n", view_flags);
2892 
2893     /* Set up the member variables */
2894     m_pShellBrowser = psb;
2895     m_FolderSettings.ViewMode = mode;
2896     m_FolderSettings.fFlags = mask & flags;
2897 
2898     if (view_id)
2899     {
2900         if (IsEqualIID(*view_id, VID_LargeIcons))
2901             m_FolderSettings.ViewMode = FVM_ICON;
2902         else if (IsEqualIID(*view_id, VID_SmallIcons))
2903             m_FolderSettings.ViewMode = FVM_SMALLICON;
2904         else if (IsEqualIID(*view_id, VID_List))
2905             m_FolderSettings.ViewMode = FVM_LIST;
2906         else if (IsEqualIID(*view_id, VID_Details))
2907             m_FolderSettings.ViewMode = FVM_DETAILS;
2908         else if (IsEqualIID(*view_id, VID_Thumbnails))
2909             m_FolderSettings.ViewMode = FVM_THUMBNAIL;
2910         else if (IsEqualIID(*view_id, VID_Tile))
2911             m_FolderSettings.ViewMode = FVM_TILE;
2912         else if (IsEqualIID(*view_id, VID_ThumbStrip))
2913             m_FolderSettings.ViewMode = FVM_THUMBSTRIP;
2914         else
2915             FIXME("Ignoring unrecognized VID %s\n", debugstr_guid(view_id));
2916     }
2917 
2918     /* Get our parent window */
2919     m_pShellBrowser->GetWindow(&m_hWndParent);
2920 
2921     /* Try to get the ICommDlgBrowserInterface, adds a reference !!! */
2922     m_pCommDlgBrowser = NULL;
2923     if (SUCCEEDED(m_pShellBrowser->QueryInterface(IID_PPV_ARG(ICommDlgBrowser, &m_pCommDlgBrowser))))
2924     {
2925         TRACE("-- CommDlgBrowser\n");
2926     }
2927 
2928     Create(m_hWndParent, prcView, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP, 0, 0U);
2929     if (m_hWnd == NULL)
2930         return E_FAIL;
2931 
2932     *hwnd = m_hWnd;
2933 
2934     CheckToolbar();
2935 
2936     if (!*hwnd)
2937         return E_FAIL;
2938 
2939     _DoFolderViewCB(SFVM_WINDOWCREATED, (WPARAM)m_hWnd, 0);
2940 
2941     SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
2942     UpdateWindow();
2943 
2944     if (!m_hMenu)
2945     {
2946         m_hMenu = CreateMenu();
2947         m_pShellBrowser->InsertMenusSB(m_hMenu, &omw);
2948         TRACE("-- after fnInsertMenusSB\n");
2949     }
2950 
2951     _MergeToolbar();
2952 
2953     return S_OK;
2954 }
2955 
2956 HRESULT STDMETHODCALLTYPE CDefView::HandleRename(LPCITEMIDLIST new_pidl)
2957 {
2958     FIXME("(%p)->(%p) stub\n", this, new_pidl);
2959     return E_NOTIMPL;
2960 }
2961 
2962 HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItem(LPCITEMIDLIST item, UINT flags, POINT *point)
2963 {
2964     FIXME("(%p)->(%p, %u, %p) stub\n", this, item, flags, point);
2965     return E_NOTIMPL;
2966 }
2967 
2968 /**********************************************************
2969  * IShellFolderView implementation
2970  */
2971 HRESULT STDMETHODCALLTYPE CDefView::Rearrange(LPARAM sort)
2972 {
2973     FIXME("(%p)->(%ld) stub\n", this, sort);
2974     return E_NOTIMPL;
2975 }
2976 
2977 HRESULT STDMETHODCALLTYPE CDefView::GetArrangeParam(LPARAM *sort)
2978 {
2979     FIXME("(%p)->(%p) stub\n", this, sort);
2980     return E_NOTIMPL;
2981 }
2982 
2983 HRESULT STDMETHODCALLTYPE CDefView::ArrangeGrid()
2984 {
2985     m_ListView.SetExtendedListViewStyle(LVS_EX_SNAPTOGRID, LVS_EX_SNAPTOGRID);
2986     return S_OK;
2987 }
2988 
2989 HRESULT STDMETHODCALLTYPE CDefView::AutoArrange()
2990 {
2991     m_ListView.ModifyStyle(0, LVS_AUTOARRANGE);
2992     m_ListView.Arrange(LVA_DEFAULT);
2993     return S_OK;
2994 }
2995 
2996 HRESULT STDMETHODCALLTYPE CDefView::AddObject(PITEMID_CHILD pidl, UINT *item)
2997 {
2998     TRACE("(%p)->(%p %p)\n", this, pidl, item);
2999     *item = LV_AddItem(pidl);
3000     return (int)*item >= 0 ? S_OK : E_OUTOFMEMORY;
3001 }
3002 
3003 HRESULT STDMETHODCALLTYPE CDefView::GetObject(PITEMID_CHILD *pidl, UINT item)
3004 {
3005     TRACE("(%p)->(%p %d)\n", this, pidl, item);
3006     return Item(item, pidl);
3007 }
3008 
3009 HRESULT STDMETHODCALLTYPE CDefView::RemoveObject(PITEMID_CHILD pidl, UINT *item)
3010 {
3011 
3012     TRACE("(%p)->(%p %p)\n", this, pidl, item);
3013 
3014     if (pidl)
3015     {
3016         *item = LV_FindItemByPidl(ILFindLastID(pidl));
3017         m_ListView.DeleteItem(*item);
3018     }
3019     else
3020     {
3021         *item = 0;
3022         m_ListView.DeleteAllItems();
3023     }
3024 
3025     return S_OK;
3026 }
3027 
3028 HRESULT STDMETHODCALLTYPE CDefView::GetObjectCount(UINT *count)
3029 {
3030     TRACE("(%p)->(%p)\n", this, count);
3031     *count = m_ListView.GetItemCount();
3032     return S_OK;
3033 }
3034 
3035 HRESULT STDMETHODCALLTYPE CDefView::SetObjectCount(UINT count, UINT flags)
3036 {
3037     FIXME("(%p)->(%d %x) stub\n", this, count, flags);
3038     return E_NOTIMPL;
3039 }
3040 
3041 HRESULT STDMETHODCALLTYPE CDefView::UpdateObject(PITEMID_CHILD pidl_old, PITEMID_CHILD pidl_new, UINT *item)
3042 {
3043     FIXME("(%p)->(%p %p %p) stub\n", this, pidl_old, pidl_new, item);
3044     return E_NOTIMPL;
3045 }
3046 
3047 HRESULT STDMETHODCALLTYPE CDefView::RefreshObject(PITEMID_CHILD pidl, UINT *item)
3048 {
3049     FIXME("(%p)->(%p %p) stub\n", this, pidl, item);
3050     return E_NOTIMPL;
3051 }
3052 
3053 HRESULT STDMETHODCALLTYPE CDefView::SetRedraw(BOOL redraw)
3054 {
3055     TRACE("(%p)->(%d)\n", this, redraw);
3056     m_ListView.SetRedraw(redraw);
3057     return S_OK;
3058 }
3059 
3060 HRESULT STDMETHODCALLTYPE CDefView::GetSelectedCount(UINT *count)
3061 {
3062     FIXME("(%p)->(%p) stub\n", this, count);
3063     return E_NOTIMPL;
3064 }
3065 
3066 HRESULT STDMETHODCALLTYPE CDefView::GetSelectedObjects(PCUITEMID_CHILD **pidl, UINT *items)
3067 {
3068     TRACE("(%p)->(%p %p)\n", this, pidl, items);
3069 
3070     *items = GetSelections();
3071 
3072     if (*items)
3073     {
3074         *pidl = static_cast<PCUITEMID_CHILD *>(LocalAlloc(0, *items * sizeof(PCUITEMID_CHILD)));
3075         if (!*pidl)
3076         {
3077             return E_OUTOFMEMORY;
3078         }
3079 
3080         /* it's documented that caller shouldn't PIDLs, only array itself */
3081         memcpy(*pidl, m_apidl, *items * sizeof(PCUITEMID_CHILD));
3082     }
3083 
3084     return S_OK;
3085 }
3086 
3087 HRESULT STDMETHODCALLTYPE CDefView::IsDropOnSource(IDropTarget *drop_target)
3088 {
3089     if ((m_iDragOverItem == -1 || m_pCurDropTarget == NULL) &&
3090         (m_pSourceDataObject.p))
3091     {
3092         return S_OK;
3093     }
3094 
3095     return S_FALSE;
3096 }
3097 
3098 HRESULT STDMETHODCALLTYPE CDefView::GetDragPoint(POINT *pt)
3099 {
3100     if (!pt)
3101         return E_INVALIDARG;
3102 
3103     *pt = m_ptFirstMousePos;
3104     return S_OK;
3105 }
3106 
3107 HRESULT STDMETHODCALLTYPE CDefView::GetDropPoint(POINT *pt)
3108 {
3109     FIXME("(%p)->(%p) stub\n", this, pt);
3110     return E_NOTIMPL;
3111 }
3112 
3113 HRESULT STDMETHODCALLTYPE CDefView::MoveIcons(IDataObject *obj)
3114 {
3115     TRACE("(%p)->(%p)\n", this, obj);
3116     return E_NOTIMPL;
3117 }
3118 
3119 HRESULT STDMETHODCALLTYPE CDefView::SetItemPos(PCUITEMID_CHILD pidl, POINT *pt)
3120 {
3121     FIXME("(%p)->(%p %p) stub\n", this, pidl, pt);
3122     return E_NOTIMPL;
3123 }
3124 
3125 HRESULT STDMETHODCALLTYPE CDefView::IsBkDropTarget(IDropTarget *drop_target)
3126 {
3127     FIXME("(%p)->(%p) stub\n", this, drop_target);
3128     return E_NOTIMPL;
3129 }
3130 
3131 HRESULT STDMETHODCALLTYPE CDefView::SetClipboard(BOOL move)
3132 {
3133     FIXME("(%p)->(%d) stub\n", this, move);
3134     return E_NOTIMPL;
3135 }
3136 
3137 HRESULT STDMETHODCALLTYPE CDefView::SetPoints(IDataObject *obj)
3138 {
3139     FIXME("(%p)->(%p) stub\n", this, obj);
3140     return E_NOTIMPL;
3141 }
3142 
3143 HRESULT STDMETHODCALLTYPE CDefView::GetItemSpacing(ITEMSPACING *spacing)
3144 {
3145     FIXME("(%p)->(%p) stub\n", this, spacing);
3146     return E_NOTIMPL;
3147 }
3148 
3149 HRESULT STDMETHODCALLTYPE CDefView::SetCallback(IShellFolderViewCB  *new_cb, IShellFolderViewCB **old_cb)
3150 {
3151     if (old_cb)
3152         *old_cb = m_pShellFolderViewCB.Detach();
3153 
3154     m_pShellFolderViewCB = new_cb;
3155     return S_OK;
3156 }
3157 
3158 HRESULT STDMETHODCALLTYPE CDefView::Select(UINT flags)
3159 {
3160     FIXME("(%p)->(%d) stub\n", this, flags);
3161     return E_NOTIMPL;
3162 }
3163 
3164 HRESULT STDMETHODCALLTYPE CDefView::QuerySupport(UINT *support)
3165 {
3166     TRACE("(%p)->(%p)\n", this, support);
3167     return S_OK;
3168 }
3169 
3170 HRESULT STDMETHODCALLTYPE CDefView::SetAutomationObject(IDispatch *disp)
3171 {
3172     FIXME("(%p)->(%p) stub\n", this, disp);
3173     return E_NOTIMPL;
3174 }
3175 
3176 /**********************************************************
3177  * ISVOleCmdTarget_QueryStatus (IOleCommandTarget)
3178  */
3179 HRESULT WINAPI CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText)
3180 {
3181     FIXME("(%p)->(%p(%s) 0x%08x %p %p\n",
3182           this, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
3183 
3184     if (!prgCmds)
3185         return E_INVALIDARG;
3186 
3187     for (UINT i = 0; i < cCmds; i++)
3188     {
3189         FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID);
3190         prgCmds[i].cmdf = 0;
3191     }
3192 
3193     return OLECMDERR_E_UNKNOWNGROUP;
3194 }
3195 
3196 /**********************************************************
3197  * ISVOleCmdTarget_Exec (IOleCommandTarget)
3198  *
3199  * nCmdID is the OLECMDID_* enumeration
3200  */
3201 HRESULT WINAPI CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
3202 {
3203     FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n",
3204           this, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut);
3205 
3206     if (!pguidCmdGroup)
3207         return OLECMDERR_E_UNKNOWNGROUP;
3208 
3209     if (IsEqualCLSID(*pguidCmdGroup, m_Category))
3210     {
3211         if (nCmdID == FCIDM_SHVIEW_AUTOARRANGE)
3212         {
3213             if (V_VT(pvaIn) != VT_INT_PTR)
3214                 return OLECMDERR_E_NOTSUPPORTED;
3215 
3216             TPMPARAMS params;
3217             params.cbSize = sizeof(params);
3218             params.rcExclude = *(RECT*) V_INTREF(pvaIn);
3219 
3220             if (m_hMenuViewModes)
3221             {
3222                 /* Duplicate all but the last two items of the view modes menu */
3223                 HMENU hmenuViewPopup = CreatePopupMenu();
3224                 Shell_MergeMenus(hmenuViewPopup, m_hMenuViewModes, 0, 0, 0xFFFF, 0);
3225                 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION);
3226                 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION);
3227                 CheckViewMode(hmenuViewPopup);
3228                 TrackPopupMenuEx(hmenuViewPopup, TPM_LEFTALIGN | TPM_TOPALIGN, params.rcExclude.left, params.rcExclude.bottom, m_hWndParent, &params);
3229                 ::DestroyMenu(hmenuViewPopup);
3230             }
3231 
3232             // pvaOut is VT_I4 with value 0x403 (cmd id of the new mode maybe?)
3233             V_VT(pvaOut) = VT_I4;
3234             V_I4(pvaOut) = 0x403;
3235         }
3236     }
3237 
3238     if (IsEqualIID(*pguidCmdGroup, CGID_Explorer) &&
3239             (nCmdID == 0x29) &&
3240             (nCmdexecopt == 4) && pvaOut)
3241         return S_OK;
3242 
3243     if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView) &&
3244             (nCmdID == 9) &&
3245             (nCmdexecopt == 0))
3246         return 1;
3247 
3248     return OLECMDERR_E_UNKNOWNGROUP;
3249 }
3250 
3251 /**********************************************************
3252  * ISVDropTarget implementation
3253  */
3254 
3255 /******************************************************************************
3256  * drag_notify_subitem [Internal]
3257  *
3258  * Figure out the shellfolder object, which is currently under the mouse cursor
3259  * and notify it via the IDropTarget interface.
3260  */
3261 
3262 #define SCROLLAREAWIDTH 20
3263 
3264 HRESULT CDefView::drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3265 {
3266     LONG lResult;
3267     HRESULT hr;
3268     RECT clientRect;
3269 
3270     /* The key state on drop doesn't have MK_LBUTTON or MK_RBUTTON because it
3271        reflects the key state after the user released the button, so we need
3272        to remember the last key state when the button was pressed */
3273     m_grfKeyState = grfKeyState;
3274 
3275     /* Map from global to client coordinates and query the index of the listview-item, which is
3276      * currently under the mouse cursor. */
3277     LVHITTESTINFO htinfo = {{pt.x, pt.y}, LVHT_ONITEM};
3278     ScreenToClient(&htinfo.pt);
3279     lResult = m_ListView.HitTest(&htinfo);
3280 
3281     /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */
3282     ::GetClientRect(m_ListView, &clientRect);
3283     if (htinfo.pt.x == m_ptLastMousePos.x && htinfo.pt.y == m_ptLastMousePos.y &&
3284             (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH ||
3285              htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH ))
3286     {
3287         m_cScrollDelay = (m_cScrollDelay + 1) % 5; /* DragOver is called every 50 ms */
3288         if (m_cScrollDelay == 0)
3289         {
3290             /* Mouse did hover another 250 ms over the scroll-area */
3291             if (htinfo.pt.x < SCROLLAREAWIDTH)
3292                 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEUP, 0);
3293 
3294             if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH)
3295                 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEDOWN, 0);
3296 
3297             if (htinfo.pt.y < SCROLLAREAWIDTH)
3298                 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEUP, 0);
3299 
3300             if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH)
3301                 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEDOWN, 0);
3302         }
3303     }
3304     else
3305     {
3306         m_cScrollDelay = 0; /* Reset, if the cursor is not over the listview's scroll-area */
3307     }
3308 
3309     m_ptLastMousePos = htinfo.pt;
3310     ::ClientToListView(m_ListView, &m_ptLastMousePos);
3311 
3312     /* We need to check if we drag the selection over itself */
3313     if (lResult != -1 && m_pSourceDataObject.p != NULL)
3314     {
3315         PCUITEMID_CHILD pidl = _PidlByItem(lResult);
3316 
3317         for (UINT i = 0; i < m_cidl; i++)
3318         {
3319             if (pidl == m_apidl[i])
3320             {
3321                 /* The item that is being draged is hovering itself. */
3322                 lResult = -1;
3323                 break;
3324             }
3325         }
3326     }
3327 
3328     /* If we are still over the previous sub-item, notify it via DragOver and return. */
3329     if (m_pCurDropTarget && lResult == m_iDragOverItem)
3330         return m_pCurDropTarget->DragOver(grfKeyState, pt, pdwEffect);
3331 
3332     /* We've left the previous sub-item, notify it via DragLeave and Release it. */
3333     if (m_pCurDropTarget)
3334     {
3335         PCUITEMID_CHILD pidl = _PidlByItem(m_iDragOverItem);
3336         if (pidl)
3337             SelectItem(pidl, 0);
3338 
3339         m_pCurDropTarget->DragLeave();
3340         m_pCurDropTarget.Release();
3341     }
3342 
3343     m_iDragOverItem = lResult;
3344 
3345     if (lResult == -1)
3346     {
3347         /* We are not above one of the listview's subitems. Bind to the parent folder's
3348          * DropTarget interface. */
3349         hr = m_pSFParent->CreateViewObject(NULL, IID_PPV_ARG(IDropTarget,&m_pCurDropTarget));
3350     }
3351     else
3352     {
3353         /* Query the relative PIDL of the shellfolder object represented by the currently
3354          * dragged over listview-item ... */
3355         PCUITEMID_CHILD pidl = _PidlByItem(lResult);
3356 
3357         /* ... and bind m_pCurDropTarget to the IDropTarget interface of an UIObject of this object */
3358         hr = m_pSFParent->GetUIObjectOf(m_ListView, 1, &pidl, IID_NULL_PPV_ARG(IDropTarget, &m_pCurDropTarget));
3359     }
3360 
3361     IUnknown_SetSite(m_pCurDropTarget, (IShellView *)this);
3362 
3363     /* If anything failed, m_pCurDropTarget should be NULL now, which ought to be a save state. */
3364     if (FAILED(hr))
3365     {
3366         *pdwEffect = DROPEFFECT_NONE;
3367         return hr;
3368     }
3369 
3370     if (m_iDragOverItem != -1)
3371     {
3372         SelectItem(m_iDragOverItem, SVSI_SELECT);
3373     }
3374 
3375     /* Notify the item just entered via DragEnter. */
3376     return m_pCurDropTarget->DragEnter(m_pCurDataObject, grfKeyState, pt, pdwEffect);
3377 }
3378 
3379 HRESULT WINAPI CDefView::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3380 {
3381     if (*pdwEffect == DROPEFFECT_NONE)
3382         return S_OK;
3383 
3384     /* Get a hold on the data object for later calls to DragEnter on the sub-folders */
3385     m_pCurDataObject = pDataObject;
3386 
3387     HRESULT hr = drag_notify_subitem(grfKeyState, pt, pdwEffect);
3388     if (SUCCEEDED(hr))
3389     {
3390         POINT ptClient = {pt.x, pt.y};
3391         ScreenToClient(&ptClient);
3392         ImageList_DragEnter(m_hWnd, ptClient.x, ptClient.y);
3393     }
3394 
3395     return hr;
3396 }
3397 
3398 HRESULT WINAPI CDefView::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3399 {
3400     POINT ptClient = {pt.x, pt.y};
3401     ScreenToClient(&ptClient);
3402     ImageList_DragMove(ptClient.x, ptClient.y);
3403     return drag_notify_subitem(grfKeyState, pt, pdwEffect);
3404 }
3405 
3406 HRESULT WINAPI CDefView::DragLeave()
3407 {
3408     ImageList_DragLeave(m_hWnd);
3409 
3410     if (m_pCurDropTarget)
3411     {
3412         m_pCurDropTarget->DragLeave();
3413         m_pCurDropTarget.Release();
3414     }
3415 
3416     if (m_pCurDataObject != NULL)
3417     {
3418         m_pCurDataObject.Release();
3419     }
3420 
3421     m_iDragOverItem = 0;
3422 
3423     return S_OK;
3424 }
3425 
3426 INT CDefView::_FindInsertableIndexFromPoint(POINT pt)
3427 {
3428     RECT rcBound;
3429     INT i, nCount = m_ListView.GetItemCount();
3430     DWORD dwSpacing;
3431     INT dx, dy;
3432     BOOL bSmall = ((m_ListView.GetStyle() & LVS_TYPEMASK) != LVS_ICON);
3433 
3434     /* FIXME: LVM_GETORIGIN is broken. See CORE-17266 */
3435     pt.x += m_ListView.GetScrollPos(SB_HORZ);
3436     pt.y += m_ListView.GetScrollPos(SB_VERT);
3437 
3438     if (m_ListView.GetStyle() & LVS_ALIGNLEFT)
3439     {
3440         // vertically
3441         for (i = 0; i < nCount; ++i)
3442         {
3443             dwSpacing = ListView_GetItemSpacing(m_ListView, bSmall);
3444             dx = LOWORD(dwSpacing);
3445             dy = HIWORD(dwSpacing);
3446             ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS);
3447             rcBound.right = rcBound.left + dx;
3448             rcBound.bottom = rcBound.top + dy;
3449             if (pt.x < rcBound.right && pt.y < (rcBound.top + rcBound.bottom) / 2)
3450             {
3451                 return i;
3452             }
3453         }
3454         for (i = nCount - 1; i >= 0; --i)
3455         {
3456             ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS);
3457             if (rcBound.left < pt.x && rcBound.top < pt.y)
3458             {
3459                 return i + 1;
3460             }
3461         }
3462     }
3463     else
3464     {
3465         // horizontally
3466         for (i = 0; i < nCount; ++i)
3467         {
3468             dwSpacing = ListView_GetItemSpacing(m_ListView, bSmall);
3469             dx = LOWORD(dwSpacing);
3470             dy = HIWORD(dwSpacing);
3471             ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS);
3472             rcBound.right = rcBound.left + dx;
3473             rcBound.bottom = rcBound.top + dy;
3474             if (pt.y < rcBound.bottom && pt.x < rcBound.left)
3475             {
3476                 return i;
3477             }
3478             if (pt.y < rcBound.bottom && pt.x < rcBound.right)
3479             {
3480                 return i + 1;
3481             }
3482         }
3483         for (i = nCount - 1; i >= 0; --i)
3484         {
3485             ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS);
3486             if (rcBound.left < pt.x && rcBound.top < pt.y)
3487             {
3488                 return i + 1;
3489             }
3490         }
3491     }
3492 
3493     return nCount;
3494 }
3495 
3496 typedef CSimpleMap<LPARAM, INT> CLParamIndexMap;
3497 
3498 static INT CALLBACK
3499 SelectionMoveCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
3500 {
3501     CLParamIndexMap *pmap = (CLParamIndexMap *)lParamSort;
3502     INT i1 = pmap->Lookup(lParam1), i2 = pmap->Lookup(lParam2);
3503     if (i1 < i2)
3504         return -1;
3505     if (i1 > i2)
3506         return 1;
3507     return 0;
3508 }
3509 
3510 void CDefView::_MoveSelectionOnAutoArrange(POINT pt)
3511 {
3512     // get insertable index from position
3513     INT iPosition = _FindInsertableIndexFromPoint(pt);
3514 
3515     // create identity mapping of indexes
3516     CSimpleArray<INT> array;
3517     INT nCount = m_ListView.GetItemCount();
3518     for (INT i = 0; i < nCount; ++i)
3519     {
3520         array.Add(i);
3521     }
3522 
3523     // re-ordering mapping
3524     INT iItem = -1;
3525     while ((iItem = m_ListView.GetNextItem(iItem, LVNI_SELECTED)) >= 0)
3526     {
3527         INT iFrom = iItem, iTo = iPosition;
3528         if (iFrom < iTo)
3529             --iTo;
3530         if (iFrom >= nCount)
3531             iFrom = nCount - 1;
3532         if (iTo >= nCount)
3533             iTo = nCount - 1;
3534 
3535         // shift indexes by swapping (like a bucket relay)
3536         if (iFrom < iTo)
3537         {
3538             for (INT i = iFrom; i < iTo; ++i)
3539             {
3540                 // swap array[i] and array[i + 1]
3541                 INT tmp = array[i];
3542                 array[i] = array[i + 1];
3543                 array[i + 1] = tmp;
3544             }
3545         }
3546         else
3547         {
3548             for (INT i = iFrom; i > iTo; --i)
3549             {
3550                 // swap array[i] and array[i - 1]
3551                 INT tmp = array[i];
3552                 array[i] = array[i - 1];
3553                 array[i - 1] = tmp;
3554             }
3555         }
3556     }
3557 
3558     // create mapping (ListView's lParam to index) from array
3559     CLParamIndexMap map;
3560     for (INT i = 0; i < nCount; ++i)
3561     {
3562         LPARAM lParam = m_ListView.GetItemData(array[i]);
3563         map.Add(lParam, i);
3564     }
3565 
3566     // finally sort
3567     m_ListView.SortItems(SelectionMoveCompareFunc, &map);
3568 }
3569 
3570 HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3571 {
3572     ImageList_DragLeave(m_hWnd);
3573     ImageList_EndDrag();
3574 
3575     if ((IsDropOnSource(NULL) == S_OK) &&
3576         (*pdwEffect & DROPEFFECT_MOVE) &&
3577         (m_grfKeyState & MK_LBUTTON))
3578     {
3579         if (m_pCurDropTarget)
3580         {
3581             m_pCurDropTarget->DragLeave();
3582             m_pCurDropTarget.Release();
3583         }
3584 
3585         POINT ptDrop = { pt.x, pt.y };
3586         ::ScreenToClient(m_ListView, &ptDrop);
3587         ::ClientToListView(m_ListView, &ptDrop);
3588         m_ptLastMousePos = ptDrop;
3589 
3590         m_ListView.SetRedraw(FALSE);
3591         if (m_ListView.GetStyle() & LVS_AUTOARRANGE)
3592         {
3593             _MoveSelectionOnAutoArrange(m_ptLastMousePos);
3594         }
3595         else
3596         {
3597             POINT ptItem;
3598             INT iItem = -1;
3599             while ((iItem = m_ListView.GetNextItem(iItem, LVNI_SELECTED)) >= 0)
3600             {
3601                 if (m_ListView.GetItemPosition(iItem, &ptItem))
3602                 {
3603                     ptItem.x += m_ptLastMousePos.x - m_ptFirstMousePos.x;
3604                     ptItem.y += m_ptLastMousePos.y - m_ptFirstMousePos.y;
3605                     m_ListView.SetItemPosition(iItem, &ptItem);
3606                 }
3607             }
3608         }
3609         m_ListView.SetRedraw(TRUE);
3610     }
3611     else if (m_pCurDropTarget)
3612     {
3613         m_pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect);
3614         m_pCurDropTarget.Release();
3615     }
3616 
3617     m_pCurDataObject.Release();
3618     m_iDragOverItem = 0;
3619     return S_OK;
3620 }
3621 
3622 /**********************************************************
3623  * ISVDropSource implementation
3624  */
3625 
3626 HRESULT WINAPI CDefView::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
3627 {
3628     TRACE("(%p)\n", this);
3629 
3630     if (fEscapePressed)
3631         return DRAGDROP_S_CANCEL;
3632     else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON))
3633         return DRAGDROP_S_DROP;
3634     else
3635         return S_OK;
3636 }
3637 
3638 HRESULT WINAPI CDefView::GiveFeedback(DWORD dwEffect)
3639 {
3640     TRACE("(%p)\n", this);
3641 
3642     return DRAGDROP_S_USEDEFAULTCURSORS;
3643 }
3644 
3645 /**********************************************************
3646  * ISVViewObject implementation
3647  */
3648 
3649 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)
3650 {
3651     FIXME("Stub: this=%p\n", this);
3652 
3653     return E_NOTIMPL;
3654 }
3655 
3656 HRESULT WINAPI CDefView::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet)
3657 {
3658     FIXME("Stub: this=%p\n", this);
3659 
3660     return E_NOTIMPL;
3661 }
3662 
3663 HRESULT WINAPI CDefView::Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze)
3664 {
3665     FIXME("Stub: this=%p\n", this);
3666 
3667     return E_NOTIMPL;
3668 }
3669 
3670 HRESULT WINAPI CDefView::Unfreeze(DWORD dwFreeze)
3671 {
3672     FIXME("Stub: this=%p\n", this);
3673 
3674     return E_NOTIMPL;
3675 }
3676 
3677 HRESULT WINAPI CDefView::SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink)
3678 {
3679     FIXME("partial stub: %p 0x%08x 0x%08x %p\n", this, aspects, advf, pAdvSink);
3680 
3681     /* FIXME: we set the AdviseSink, but never use it to send any advice */
3682     m_pAdvSink = pAdvSink;
3683     m_dwAspects = aspects;
3684     m_dwAdvf = advf;
3685 
3686     return S_OK;
3687 }
3688 
3689 HRESULT WINAPI CDefView::GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink)
3690 {
3691     TRACE("this=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n", this, pAspects, pAdvf, ppAdvSink);
3692 
3693     if (ppAdvSink)
3694     {
3695         *ppAdvSink = m_pAdvSink;
3696         m_pAdvSink.p->AddRef();
3697     }
3698 
3699     if (pAspects)
3700         *pAspects = m_dwAspects;
3701 
3702     if (pAdvf)
3703         *pAdvf = m_dwAdvf;
3704 
3705     return S_OK;
3706 }
3707 
3708 HRESULT STDMETHODCALLTYPE CDefView::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
3709 {
3710     if (IsEqualIID(guidService, SID_IShellBrowser))
3711         return m_pShellBrowser->QueryInterface(riid, ppvObject);
3712     else if(IsEqualIID(guidService, SID_IFolderView))
3713         return QueryInterface(riid, ppvObject);
3714 
3715     return E_NOINTERFACE;
3716 }
3717 
3718 HRESULT CDefView::_MergeToolbar()
3719 {
3720     CComPtr<IExplorerToolbar> ptb;
3721     HRESULT hr = S_OK;
3722 
3723     hr = IUnknown_QueryService(m_pShellBrowser, IID_IExplorerToolbar, IID_PPV_ARG(IExplorerToolbar, &ptb));
3724     if (FAILED(hr))
3725         return hr;
3726 
3727     m_Category = CGID_DefViewFrame;
3728 
3729     hr = ptb->SetCommandTarget(static_cast<IOleCommandTarget*>(this), &m_Category, 0);
3730     if (FAILED(hr))
3731         return hr;
3732 
3733     if (hr == S_FALSE)
3734         return S_OK;
3735 
3736 #if 0
3737     hr = ptb->AddButtons(&m_Category, buttonsCount, buttons);
3738     if (FAILED(hr))
3739         return hr;
3740 #endif
3741 
3742     return S_OK;
3743 }
3744 
3745 HRESULT CDefView::_DoFolderViewCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
3746 {
3747     HRESULT hr = E_NOTIMPL;
3748 
3749     if (m_pShellFolderViewCB)
3750     {
3751         hr = m_pShellFolderViewCB->MessageSFVCB(uMsg, wParam, lParam);
3752     }
3753 
3754     return hr;
3755 }
3756 
3757 HRESULT CDefView_CreateInstance(IShellFolder *pFolder, REFIID riid, LPVOID * ppvOut)
3758 {
3759     return ShellObjectCreatorInit<CDefView>(pFolder, riid, ppvOut);
3760 }
3761 
3762 HRESULT WINAPI SHCreateShellFolderViewEx(
3763     LPCSFV psvcbi,    /* [in] shelltemplate struct */
3764     IShellView **ppsv) /* [out] IShellView pointer */
3765 {
3766     CComPtr<IShellView> psv;
3767     HRESULT hRes;
3768 
3769     TRACE("sf=%p pidl=%p cb=%p mode=0x%08x parm=%p\n",
3770       psvcbi->pshf, psvcbi->pidl, psvcbi->pfnCallback,
3771       psvcbi->fvm, psvcbi->psvOuter);
3772 
3773     *ppsv = NULL;
3774     hRes = CDefView_CreateInstance(psvcbi->pshf, IID_PPV_ARG(IShellView, &psv));
3775     if (FAILED_UNEXPECTEDLY(hRes))
3776         return hRes;
3777 
3778     *ppsv = psv.Detach();
3779     return hRes;
3780 }
3781 
3782 HRESULT WINAPI SHCreateShellFolderView(const SFV_CREATE *pcsfv,
3783                         IShellView **ppsv)
3784 {
3785     CComPtr<IShellView> psv;
3786     HRESULT hRes;
3787 
3788     if (!ppsv)
3789         return E_INVALIDARG;
3790 
3791     *ppsv = NULL;
3792 
3793     if (!pcsfv || pcsfv->cbSize != sizeof(*pcsfv))
3794         return E_INVALIDARG;
3795 
3796     TRACE("sf=%p outer=%p callback=%p\n",
3797       pcsfv->pshf, pcsfv->psvOuter, pcsfv->psfvcb);
3798 
3799     hRes = CDefView_CreateInstance(pcsfv->pshf, IID_PPV_ARG(IShellView, &psv));
3800     if (FAILED(hRes))
3801         return hRes;
3802 
3803     if (pcsfv->psfvcb)
3804     {
3805         CComPtr<IShellFolderView> sfv;
3806         if (SUCCEEDED(psv->QueryInterface(IID_PPV_ARG(IShellFolderView, &sfv))))
3807         {
3808             sfv->SetCallback(pcsfv->psfvcb, NULL);
3809         }
3810     }
3811 
3812     *ppsv = psv.Detach();
3813     return hRes;
3814 }
3815