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