xref: /reactos/dll/win32/shell32/CDefView.cpp (revision d6eebaa4)
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     if (!selcount)
1811     {
1812         DeleteMenu(hmenu, FCIDM_SHVIEW_VIEW, MF_BYCOMMAND);
1813         DeleteMenu(hmenu, FCIDM_SHVIEW_ARRANGE, MF_BYCOMMAND);
1814         DeleteMenu(hmenu, FCIDM_SHVIEW_REFRESH, MF_BYCOMMAND);
1815     }
1816 
1817     Shell_MergeMenus(hFileMenu, hmenu, 0, 0, 0xFFFF, MM_ADDSEPARATOR | MM_SUBMENUSHAVEIDS);
1818     ::DestroyMenu(hmenu);
1819     return S_OK;
1820 }
1821 
1822 HRESULT CDefView::FillEditMenu()
1823 {
1824     HMENU hEditMenu = GetSubmenuByID(m_hMenu, FCIDM_MENU_EDIT);
1825     if (!hEditMenu)
1826         return E_FAIL;
1827 
1828     HMENU hmenuContents = ::LoadMenuW(shell32_hInstance, L"MENU_003");
1829     if (!hmenuContents)
1830         return E_FAIL;
1831 
1832     Shell_MergeMenus(hEditMenu, hmenuContents, 0, 0, 0xFFFF, 0);
1833 
1834     ::DestroyMenu(hmenuContents);
1835 
1836     return S_OK;
1837 }
1838 
1839 HRESULT CDefView::FillViewMenu()
1840 {
1841     HMENU hViewMenu = GetSubmenuByID(m_hMenu, FCIDM_MENU_VIEW);
1842     if (!hViewMenu)
1843         return E_FAIL;
1844 
1845     m_hMenuViewModes = ::LoadMenuW(shell32_hInstance, L"MENU_001");
1846     if (!m_hMenuViewModes)
1847         return E_FAIL;
1848 
1849     UINT i = SHMenuIndexFromID(hViewMenu, FCIDM_MENU_VIEW_SEP_OPTIONS);
1850     Shell_MergeMenus(hViewMenu, m_hMenuViewModes, i, 0, 0xFFFF, MM_ADDSEPARATOR | MM_DONTREMOVESEPS | MM_SUBMENUSHAVEIDS);
1851 
1852     return S_OK;
1853 }
1854 
1855 HRESULT CDefView::FillArrangeAsMenu(HMENU hmenuArrange)
1856 {
1857     bool forceMerge = false;
1858     UINT currentSortId = DVIDM_ARRANGESORT_FIRST + m_sortInfo.ListColumn;
1859 
1860     // Make sure the column we currently sort by is in the menu
1861     RemoveMenu(m_hMenuArrangeModes, DVIDM_ARRANGESORT_LAST, MF_BYCOMMAND);
1862     if (m_sortInfo.ListColumn >= DEFVIEW_ARRANGESORT_MAXENUM)
1863     {
1864         C_ASSERT(DEFVIEW_ARRANGESORT_MAXENUM < DEFVIEW_ARRANGESORT_MAX);
1865         C_ASSERT(DVIDM_ARRANGESORT_FIRST + DEFVIEW_ARRANGESORT_MAXENUM == DVIDM_ARRANGESORT_LAST);
1866         WCHAR buf[MAX_PATH];
1867         LVCOLUMN lvc;
1868         lvc.mask = LVCF_TEXT;
1869         lvc.pszText = buf;
1870         lvc.cchTextMax = _countof(buf);
1871         currentSortId = DVIDM_ARRANGESORT_LAST;
1872         forceMerge = true;
1873         ListView_GetColumn(m_ListView.m_hWnd, m_sortInfo.ListColumn, &lvc);
1874         AppendMenuItem(m_hMenuArrangeModes, MF_STRING, currentSortId, lvc.pszText, m_sortInfo.ListColumn);
1875     }
1876 
1877     // Prepend the sort-by items unless they are aleady there
1878     if (GetMenuItemID(hmenuArrange, 0) == FCIDM_SHVIEW_AUTOARRANGE || forceMerge)
1879     {
1880         Shell_MergeMenus(hmenuArrange, m_hMenuArrangeModes, 0, 0, 0xFFFF, MM_ADDSEPARATOR);
1881     }
1882 
1883     CheckMenuRadioItem(hmenuArrange,
1884                        DVIDM_ARRANGESORT_FIRST, DVIDM_ARRANGESORT_LAST,
1885                        currentSortId, MF_BYCOMMAND);
1886 
1887     if (m_FolderSettings.ViewMode == FVM_DETAILS || m_FolderSettings.ViewMode == FVM_LIST)
1888     {
1889         EnableMenuItem(hmenuArrange, FCIDM_SHVIEW_AUTOARRANGE, MF_BYCOMMAND | MF_GRAYED);
1890         EnableMenuItem(hmenuArrange, FCIDM_SHVIEW_ALIGNTOGRID, MF_BYCOMMAND | MF_GRAYED);
1891     }
1892     else
1893     {
1894         EnableMenuItem(hmenuArrange, FCIDM_SHVIEW_AUTOARRANGE, MF_BYCOMMAND);
1895         EnableMenuItem(hmenuArrange, FCIDM_SHVIEW_ALIGNTOGRID, MF_BYCOMMAND);
1896 
1897         if (GetAutoArrange() == S_OK)
1898             CheckMenuItem(hmenuArrange, FCIDM_SHVIEW_AUTOARRANGE, MF_CHECKED);
1899         else
1900             CheckMenuItem(hmenuArrange, FCIDM_SHVIEW_AUTOARRANGE, MF_UNCHECKED);
1901 
1902         if (_GetSnapToGrid() == S_OK)
1903             CheckMenuItem(hmenuArrange, FCIDM_SHVIEW_ALIGNTOGRID, MF_CHECKED);
1904         else
1905             CheckMenuItem(hmenuArrange, FCIDM_SHVIEW_ALIGNTOGRID, MF_UNCHECKED);
1906     }
1907 
1908     return S_OK;
1909 }
1910 
1911 HRESULT CDefView::CheckViewMode(HMENU hmenuView)
1912 {
1913     if (m_FolderSettings.ViewMode >= FVM_FIRST && m_FolderSettings.ViewMode <= FVM_LAST)
1914     {
1915         UINT iItemFirst = FCIDM_SHVIEW_BIGICON;
1916         UINT iItemLast = iItemFirst + FVM_LAST - FVM_FIRST;
1917         UINT iItem = iItemFirst + m_FolderSettings.ViewMode - FVM_FIRST;
1918         CheckMenuRadioItem(hmenuView, iItemFirst, iItemLast, iItem, MF_BYCOMMAND);
1919     }
1920 
1921     return S_OK;
1922 }
1923 
1924 LRESULT CDefView::DoColumnContextMenu(LPARAM lParam)
1925 {
1926     const UINT maxItems = 15; // Feels about right
1927     const UINT idMore = 0x1337;
1928     UINT idFirst = idMore + 1, idLast = idFirst;
1929     UINT lastValidListCol = 0; // Keep track of where the new column should be inserted
1930     UINT showMore = GetKeyState(VK_SHIFT) < 0;
1931     POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
1932     HWND hWndHdr = ListView_GetHeader(m_ListView.m_hWnd);
1933 
1934     if (lParam == ~0)
1935     {
1936         RECT r;
1937         ::GetWindowRect(hWndHdr, &r);
1938         pt.x = r.left + ((r.right - r.left) / 2);
1939         pt.y = r.top + ((r.bottom - r.top) / 2);
1940     }
1941 
1942     HMENU hMenu = CreatePopupMenu();
1943     if (!hMenu)
1944         return 0;
1945 
1946     for (UINT foldCol = 0;; ++foldCol)
1947     {
1948         WCHAR buf[MAX_PATH];
1949         SHELLDETAILS sd;
1950         sd.str.uType = !STRRET_WSTR;
1951         if (FAILED(GetDetailsByFolderColumn(NULL, foldCol, sd)))
1952             break;
1953         if (FAILED(StrRetToStrNW(buf, _countof(buf), &sd.str, NULL)))
1954             break;
1955 
1956         SHCOLSTATEF state = 0;
1957         if (!m_pSF2Parent || FAILED(m_pSF2Parent->GetDefaultColumnState(foldCol, &state)))
1958             state = 0;
1959         showMore |= (state & (SHCOLSTATE_SECONDARYUI));
1960 
1961         UINT mf = MF_STRING;
1962         HRESULT listCol = MapFolderColumnToListColumn(foldCol);
1963 
1964         if (foldCol == 0)
1965             mf |= MF_CHECKED | MF_GRAYED | MF_DISABLED; // Force column 0
1966         else if (state & (SHCOLSTATE_SECONDARYUI | SHCOLSTATE_HIDDEN))
1967             continue;
1968         else if (SUCCEEDED(listCol))
1969             mf |= MF_CHECKED;
1970 
1971         if (AppendMenuItem(hMenu, mf, idLast, buf, lastValidListCol + 1))
1972         {
1973             idLast++;
1974             if (SUCCEEDED(listCol))
1975                 lastValidListCol = listCol;
1976         }
1977 
1978         if (idLast - idFirst == maxItems)
1979         {
1980             showMore++;
1981             break;
1982         }
1983     }
1984 
1985     if (showMore)
1986     {
1987 #if 0 // TODO
1988         InsertMenuW(hMenu, -1, MF_SEPARATOR, 0, NULL);
1989         InsertMenuW(hMenu, -1, MF_STRING, idMore, L"More...");
1990 #endif
1991     }
1992 
1993     // A cludge to force the cursor to update so we are not stuck with "size left/right" if
1994     // the right-click was on a column divider.
1995     ::PostMessage(m_ListView.m_hWnd, WM_SETCURSOR, (WPARAM) m_ListView.m_hWnd, HTCLIENT);
1996 
1997     // Note: Uses the header as the owner so CDefView::OnInitMenuPopup does not mess us up.
1998     UINT idCmd = TrackPopupMenu(hMenu, TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
1999                                 pt.x, pt.y, 0, hWndHdr, NULL);
2000     if (idCmd == idMore)
2001     {
2002         FIXME("Open More dialog\n");
2003     }
2004     else if (idCmd)
2005     {
2006         UINT foldCol = idCmd - idFirst;
2007         HRESULT listCol = MapFolderColumnToListColumn(foldCol);
2008         if (SUCCEEDED(listCol))
2009         {
2010             ListView_DeleteColumn(m_ListView.m_hWnd, listCol);
2011         }
2012         else
2013         {
2014             listCol = (UINT) GetMenuItemDataById(hMenu, idCmd);
2015             LoadColumn(foldCol, listCol, TRUE);
2016         }
2017         ColumnListChanged();
2018     }
2019     DestroyMenu(hMenu);
2020     return 0;
2021 }
2022 
2023 /**********************************************************
2024 *   ShellView_GetSelections()
2025 *
2026 * - fills the m_apidl list with the selected objects
2027 *
2028 * RETURNS
2029 *  number of selected items
2030 */
2031 UINT CDefView::GetSelections()
2032 {
2033     UINT count = m_ListView.GetSelectedCount();
2034     if (count > m_cidl || !count || !m_apidl) // !count to free possibly large cache, !m_apidl to make sure m_apidl is a valid pointer
2035     {
2036         SHFree(m_apidl);
2037         m_apidl = static_cast<PCUITEMID_CHILD*>(SHAlloc(count * sizeof(PCUITEMID_CHILD)));
2038         if (!m_apidl)
2039         {
2040             m_cidl = 0;
2041             return 0;
2042         }
2043     }
2044     m_cidl = count;
2045 
2046     TRACE("-- Items selected =%u\n", m_cidl);
2047 
2048     ASSERT(m_ListView);
2049 
2050     UINT i = 0;
2051     int lvIndex = -1;
2052     while ((lvIndex = m_ListView.GetNextItem(lvIndex, LVNI_SELECTED)) > -1)
2053     {
2054         m_apidl[i] = _PidlByItem(lvIndex);
2055         i++;
2056         if (i == m_cidl)
2057              break;
2058         TRACE("-- selected Item found\n");
2059     }
2060 
2061     return m_cidl;
2062 }
2063 
2064 HRESULT CDefView::InvokeContextMenuCommand(CComPtr<IContextMenu>& pCM, LPCSTR lpVerb, POINT* pt)
2065 {
2066     CMINVOKECOMMANDINFOEX cmi;
2067 
2068     ZeroMemory(&cmi, sizeof(cmi));
2069     cmi.cbSize = sizeof(cmi);
2070     cmi.hwnd = m_hWnd;
2071     cmi.lpVerb = lpVerb;
2072     cmi.nShow = SW_SHOW;
2073 
2074     if (GetKeyState(VK_SHIFT) < 0)
2075         cmi.fMask |= CMIC_MASK_SHIFT_DOWN;
2076 
2077     if (GetKeyState(VK_CONTROL) < 0)
2078         cmi.fMask |= CMIC_MASK_CONTROL_DOWN;
2079 
2080     if (pt)
2081     {
2082         cmi.fMask |= CMIC_MASK_PTINVOKE;
2083         cmi.ptInvoke = *pt;
2084     }
2085 
2086     WCHAR szDirW[MAX_PATH] = L"";
2087     CHAR szDirA[MAX_PATH];
2088     if (SUCCEEDED(_DoFolderViewCB(SFVM_GETCOMMANDDIR, _countof(szDirW), (LPARAM)szDirW)) &&
2089         *szDirW != UNICODE_NULL)
2090     {
2091         SHUnicodeToAnsi(szDirW, szDirA, _countof(szDirA));
2092         cmi.fMask |= CMIC_MASK_UNICODE;
2093         cmi.lpDirectory = szDirA;
2094         cmi.lpDirectoryW = szDirW;
2095     }
2096 
2097     HRESULT hr = pCM->InvokeCommand((LPCMINVOKECOMMANDINFO)&cmi);
2098     // Most of our callers will do this, but if they would forget (File menu!)
2099     IUnknown_SetSite(pCM, NULL);
2100     pCM.Release();
2101 
2102     if (FAILED_UNEXPECTEDLY(hr))
2103         return hr;
2104 
2105     return S_OK;
2106 }
2107 
2108 HRESULT CDefView::OpenSelectedItems()
2109 {
2110     HMENU hMenu;
2111     UINT uCommand;
2112     HRESULT hResult;
2113 
2114     if (m_ListView.GetSelectedCount() == 0)
2115         return S_OK;
2116 
2117     hResult = OnDefaultCommand();
2118     if (hResult == S_OK)
2119         return hResult;
2120 
2121     hMenu = CreatePopupMenu();
2122     if (!hMenu)
2123         return E_FAIL;
2124 
2125     CComPtr<IContextMenu> pCM;
2126     hResult = GetItemObject(SVGIO_SELECTION, IID_PPV_ARG(IContextMenu, &pCM));
2127     MenuCleanup _(pCM, hMenu);
2128     if (FAILED_UNEXPECTEDLY(hResult))
2129         return hResult;
2130 
2131     UINT cmf = CMF_DEFAULTONLY | GetContextMenuFlags(m_pShellBrowser, 0);
2132     hResult = pCM->QueryContextMenu(hMenu, 0, DVIDM_CONTEXTMENU_FIRST, DVIDM_CONTEXTMENU_LAST, cmf);
2133     if (FAILED_UNEXPECTEDLY(hResult))
2134         return hResult;
2135 
2136     uCommand = GetMenuDefaultItem(hMenu, FALSE, 0);
2137     if (uCommand == (UINT)-1)
2138     {
2139         ERR("GetMenuDefaultItem returned -1\n");
2140         return E_FAIL;
2141     }
2142 
2143     InvokeContextMenuCommand(pCM, MAKEINTRESOURCEA(uCommand), NULL);
2144 
2145     return hResult;
2146 }
2147 
2148 LRESULT CDefView::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2149 {
2150     POINT pt = { pt.x = GET_X_LPARAM(lParam), pt.y = GET_Y_LPARAM(lParam) };
2151     UINT    uCommand;
2152     HRESULT hResult;
2153 
2154     TRACE("(%p)\n", this);
2155 
2156     if (m_hContextMenu != NULL)
2157     {
2158         ERR("HACK: Aborting context menu in nested call\n");
2159         return 0;
2160     }
2161 
2162     HWND hWndHdr = ListView_GetHeader(m_ListView.m_hWnd);
2163     RECT r;
2164     if (::GetWindowRect(hWndHdr, &r) && PtInRect(&r, pt) && ::IsWindowVisible(hWndHdr))
2165     {
2166         return DoColumnContextMenu(lParam);
2167     }
2168 
2169     m_hContextMenu = CreatePopupMenu();
2170     if (!m_hContextMenu)
2171         return E_FAIL;
2172 
2173     if (lParam != ~0) // unless app key (menu key) was pressed
2174     {
2175         LV_HITTESTINFO hittest = { pt };
2176         ScreenToClient(&hittest.pt);
2177         m_ListView.HitTest(&hittest);
2178 
2179         // Right-Clicked item is selected? If selected, no selection change.
2180         // If not selected, then reset the selection and select the item.
2181         if ((hittest.flags & LVHT_ONITEM) &&
2182             m_ListView.GetItemState(hittest.iItem, LVIS_SELECTED) != LVIS_SELECTED)
2183         {
2184             SelectItem(hittest.iItem, SVSI_SELECT | SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE);
2185         }
2186     }
2187 
2188     UINT count = m_ListView.GetSelectedCount();
2189     // In case we still have this left over, clean it up
2190     hResult = GetItemObject(count ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &m_pCM));
2191     MenuCleanup _(m_pCM, m_hContextMenu);
2192     if (FAILED_UNEXPECTEDLY(hResult))
2193         return 0;
2194 
2195     UINT cmf = GetContextMenuFlags(m_pShellBrowser, SFGAO_CANRENAME);
2196     // Use 1 as the first id we want. 0 means that user canceled the menu
2197     hResult = m_pCM->QueryContextMenu(m_hContextMenu, 0, CONTEXT_MENU_BASE_ID, DVIDM_CONTEXTMENU_LAST, cmf);
2198     if (FAILED_UNEXPECTEDLY(hResult))
2199         return 0;
2200 
2201     if (m_pCommDlgBrowser && !(GetCommDlgViewFlags() & CDB2GVF_NOSELECTVERB))
2202     {
2203         HMENU hMenuSource = LoadMenuW(_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCEW(IDM_DVSELECT));
2204         Shell_MergeMenus(m_hContextMenu, GetSubMenu(hMenuSource, 0), 0, DVIDM_COMMDLG_SELECT, 0xffff, MM_ADDSEPARATOR | MM_DONTREMOVESEPS);
2205         DestroyMenu(hMenuSource);
2206         SetMenuDefaultItem(m_hContextMenu, DVIDM_COMMDLG_SELECT, MF_BYCOMMAND);
2207         // TODO: ICommDlgBrowser2::GetDefaultMenuText == S_OK
2208     }
2209 
2210     // There is no position requested, so try to find one
2211     if (lParam == ~0)
2212     {
2213         HWND hFocus = ::GetFocus();
2214         int lvIndex = -1;
2215 
2216         if (hFocus == m_ListView.m_hWnd || m_ListView.IsChild(hFocus))
2217         {
2218             // Is there an item focused and selected?
2219             lvIndex = m_ListView.GetNextItem(-1, LVNI_SELECTED | LVNI_FOCUSED);
2220             // If not, find the first selected item
2221             if (lvIndex < 0)
2222                 lvIndex = m_ListView.GetNextItem(-1, LVNI_SELECTED);
2223         }
2224 
2225         // We got something
2226         if (lvIndex > -1)
2227         {
2228             // Find the center of the icon
2229             RECT rc = { LVIR_ICON };
2230             m_ListView.SendMessage(LVM_GETITEMRECT, lvIndex, (LPARAM)&rc);
2231             pt.x = (rc.right + rc.left) / 2;
2232             pt.y = (rc.bottom + rc.top) / 2;
2233         }
2234         else
2235         {
2236             // We have to drop it somewhere
2237             pt.x = pt.y = 0;
2238         }
2239 
2240         m_ListView.ClientToScreen(&pt);
2241     }
2242 
2243     CComPtr<ICommDlgBrowser2> pcdb2;
2244     if (m_pCommDlgBrowser && SUCCEEDED(m_pCommDlgBrowser->QueryInterface(IID_PPV_ARG(ICommDlgBrowser2, &pcdb2))))
2245         pcdb2->Notify(static_cast<IShellView*>(this), CDB2N_CONTEXTMENU_START);
2246 
2247     // This runs the message loop, calling back to us with f.e. WM_INITPOPUP (hence why m_hContextMenu and m_pCM exist)
2248     uCommand = TrackPopupMenu(m_hContextMenu,
2249                               TPM_LEFTALIGN | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
2250                               pt.x, pt.y, 0, m_hWnd, NULL);
2251     if (uCommand >= DVIDM_ARRANGESORT_FIRST && uCommand <= DVIDM_ARRANGESORT_LAST)
2252     {
2253         SendMessage(WM_COMMAND, uCommand, 0);
2254     }
2255     else if (uCommand != 0 && !(uCommand == DVIDM_COMMDLG_SELECT && OnDefaultCommand() == S_OK))
2256     {
2257         InvokeContextMenuCommand(m_pCM, MAKEINTRESOURCEA(uCommand - CONTEXT_MENU_BASE_ID), &pt);
2258     }
2259 
2260     if (pcdb2)
2261         pcdb2->Notify(static_cast<IShellView*>(this), CDB2N_CONTEXTMENU_DONE);
2262     return 0;
2263 }
2264 
2265 LRESULT CDefView::OnExplorerCommand(UINT uCommand, BOOL bUseSelection)
2266 {
2267     HRESULT hResult;
2268     HMENU hMenu = NULL;
2269 
2270     CComPtr<IContextMenu> pCM;
2271     hResult = GetItemObject(bUseSelection ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &pCM));
2272     if (FAILED_UNEXPECTEDLY(hResult))
2273         return 0;
2274 
2275     MenuCleanup _(pCM, hMenu);
2276 
2277     if ((uCommand != FCIDM_SHVIEW_DELETE) && (uCommand != FCIDM_SHVIEW_RENAME))
2278     {
2279         hMenu = CreatePopupMenu();
2280         if (!hMenu)
2281             return 0;
2282 
2283         hResult = pCM->QueryContextMenu(hMenu, 0, DVIDM_CONTEXTMENU_FIRST, DVIDM_CONTEXTMENU_LAST, CMF_NORMAL);
2284         if (FAILED_UNEXPECTEDLY(hResult))
2285             return 0;
2286     }
2287 
2288     if (bUseSelection)
2289     {
2290         // FIXME: we should cache this
2291         SFGAOF rfg = SFGAO_BROWSABLE | SFGAO_CANCOPY | SFGAO_CANLINK | SFGAO_CANMOVE | SFGAO_CANDELETE | SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSTEM | SFGAO_FOLDER;
2292         hResult = m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &rfg);
2293         if (FAILED_UNEXPECTEDLY(hResult))
2294             return 0;
2295 
2296         if (!(rfg & SFGAO_CANMOVE) && uCommand == FCIDM_SHVIEW_CUT)
2297             return 0;
2298         if (!(rfg & SFGAO_CANCOPY) && uCommand == FCIDM_SHVIEW_COPY)
2299             return 0;
2300         if (!(rfg & SFGAO_CANDELETE) && uCommand == FCIDM_SHVIEW_DELETE)
2301             return 0;
2302         if (!(rfg & SFGAO_CANRENAME) && uCommand == FCIDM_SHVIEW_RENAME)
2303             return 0;
2304         if (!(rfg & SFGAO_HASPROPSHEET) && uCommand == FCIDM_SHVIEW_PROPERTIES)
2305             return 0;
2306     }
2307 
2308     // FIXME: We should probably use the objects position?
2309     InvokeContextMenuCommand(pCM, MAKEINTRESOURCEA(uCommand), NULL);
2310     return 0;
2311 }
2312 
2313 // ##### message handling #####
2314 
2315 LRESULT CDefView::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2316 {
2317     WORD wWidth, wHeight;
2318 
2319     wWidth  = LOWORD(lParam);
2320     wHeight = HIWORD(lParam);
2321 
2322     TRACE("%p width=%u height=%u\n", this, wWidth, wHeight);
2323 
2324     // WM_SIZE can come before WM_CREATE
2325     if (!m_ListView)
2326         return 0;
2327 
2328     /* Resize the ListView to fit our window */
2329     ::MoveWindow(m_ListView, 0, 0, wWidth, wHeight, TRUE);
2330 
2331     _DoFolderViewCB(SFVM_SIZE, 0, 0);
2332 
2333     _ForceStatusBarResize();
2334     UpdateStatusbar();
2335 
2336     return 0;
2337 }
2338 
2339 // internal
2340 void CDefView::OnDeactivate()
2341 {
2342     TRACE("%p\n", this);
2343 
2344     if (m_uState != SVUIA_DEACTIVATE)
2345     {
2346         // TODO: cleanup menu after deactivation
2347         m_uState = SVUIA_DEACTIVATE;
2348     }
2349 }
2350 
2351 void CDefView::DoActivate(UINT uState)
2352 {
2353     TRACE("%p uState=%x\n", this, uState);
2354 
2355     // don't do anything if the state isn't really changing
2356     if (m_uState == uState)
2357     {
2358         return;
2359     }
2360 
2361     if (uState == SVUIA_DEACTIVATE)
2362     {
2363         OnDeactivate();
2364     }
2365     else
2366     {
2367         if(m_hMenu && !m_bmenuBarInitialized)
2368         {
2369             FillEditMenu();
2370             FillViewMenu();
2371             m_pShellBrowser->SetMenuSB(m_hMenu, 0, m_hWnd);
2372             m_bmenuBarInitialized = TRUE;
2373         }
2374 
2375         if (SVUIA_ACTIVATE_FOCUS == uState)
2376         {
2377             m_ListView.SetFocus();
2378         }
2379     }
2380 
2381     m_uState = uState;
2382     TRACE("--\n");
2383 }
2384 
2385 void CDefView::_DoCopyToMoveToFolder(BOOL bCopy)
2386 {
2387     if (!GetSelections())
2388         return;
2389 
2390     SFGAOF rfg = SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_FILESYSTEM;
2391     HRESULT hr = m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &rfg);
2392     if (FAILED_UNEXPECTEDLY(hr))
2393         return;
2394 
2395     if (!bCopy && !(rfg & SFGAO_CANMOVE))
2396         return;
2397     if (bCopy && !(rfg & SFGAO_CANCOPY))
2398         return;
2399 
2400     CComPtr<IContextMenu> pCM;
2401     hr = m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, IID_IContextMenu, 0, (void **)&pCM);
2402     if (FAILED_UNEXPECTEDLY(hr))
2403         return;
2404 
2405     InvokeContextMenuCommand(pCM, (bCopy ? "copyto" : "moveto"), NULL);
2406 }
2407 
2408 LRESULT CDefView::OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2409 {
2410     DoActivate(SVUIA_ACTIVATE_FOCUS);
2411     return 0;
2412 }
2413 
2414 LRESULT CDefView::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2415 {
2416     TRACE("%p\n", this);
2417 
2418     /* Tell the browser one of our windows has received the focus. This
2419     should always be done before merging menus (OnActivate merges the
2420     menus) if one of our windows has the focus.*/
2421 
2422     m_pShellBrowser->OnViewWindowActive(this);
2423     DoActivate(SVUIA_ACTIVATE_FOCUS);
2424 
2425     /* Set the focus to the listview */
2426     m_ListView.SetFocus();
2427 
2428     /* Notify the ICommDlgBrowser interface */
2429     OnStateChange(CDBOSC_SETFOCUS);
2430 
2431     return 0;
2432 }
2433 
2434 LRESULT CDefView::OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2435 {
2436     TRACE("(%p) stub\n", this);
2437 
2438     DoActivate(SVUIA_ACTIVATE_NOFOCUS);
2439     /* Notify the ICommDlgBrowser */
2440     OnStateChange(CDBOSC_KILLFOCUS);
2441 
2442     return 0;
2443 }
2444 
2445 // the CmdID's are the ones from the context menu
2446 LRESULT CDefView::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2447 {
2448     DWORD dwCmdID;
2449     DWORD dwCmd;
2450     HWND  hwndCmd;
2451     int   nCount;
2452 
2453     dwCmdID = GET_WM_COMMAND_ID(wParam, lParam);
2454     dwCmd = GET_WM_COMMAND_CMD(wParam, lParam);
2455     hwndCmd = GET_WM_COMMAND_HWND(wParam, lParam);
2456 
2457     TRACE("(%p)->(0x%08x 0x%08x %p) stub\n", this, dwCmdID, dwCmd, hwndCmd);
2458 
2459     if (dwCmdID >= DVIDM_ARRANGESORT_FIRST && dwCmdID <= DVIDM_ARRANGESORT_LAST)
2460     {
2461         UINT listCol = (UINT)GetMenuItemDataById(m_hMenuArrangeModes, dwCmdID);
2462         _Sort(listCol);
2463         return 0;
2464     }
2465 
2466     switch (dwCmdID)
2467     {
2468         case FCIDM_SHVIEW_SMALLICON:
2469             m_FolderSettings.ViewMode = FVM_SMALLICON;
2470             m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_SMALLICON);
2471             CheckToolbar();
2472             break;
2473         case FCIDM_SHVIEW_BIGICON:
2474             m_FolderSettings.ViewMode = FVM_ICON;
2475             m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_ICON);
2476             CheckToolbar();
2477             break;
2478         case FCIDM_SHVIEW_LISTVIEW:
2479             m_FolderSettings.ViewMode = FVM_LIST;
2480             m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_LIST);
2481             CheckToolbar();
2482             break;
2483         case FCIDM_SHVIEW_REPORTVIEW:
2484             m_FolderSettings.ViewMode = FVM_DETAILS;
2485             m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_REPORT);
2486             CheckToolbar();
2487             break;
2488         case FCIDM_SHVIEW_SNAPTOGRID:
2489             m_ListView.Arrange(LVA_SNAPTOGRID);
2490             break;
2491         case FCIDM_SHVIEW_ALIGNTOGRID:
2492             if (_GetSnapToGrid() == S_OK)
2493                 m_ListView.SetExtendedListViewStyle(0, LVS_EX_SNAPTOGRID);
2494             else
2495                 ArrangeGrid();
2496             break;
2497         case FCIDM_SHVIEW_AUTOARRANGE:
2498             if (GetAutoArrange() == S_OK)
2499                 m_ListView.ModifyStyle(LVS_AUTOARRANGE, 0);
2500             else
2501                 AutoArrange();
2502             break;
2503         case FCIDM_SHVIEW_SELECTALL:
2504             if (_DoFolderViewCB(SFVM_CANSELECTALL, 0, 0) != S_FALSE)
2505                 m_ListView.SetItemState(-1, LVIS_SELECTED, LVIS_SELECTED);
2506             break;
2507         case FCIDM_SHVIEW_INVERTSELECTION:
2508             nCount = m_ListView.GetItemCount();
2509             for (int i=0; i < nCount; i++)
2510                 m_ListView.SetItemState(i, m_ListView.GetItemState(i, LVIS_SELECTED) ? 0 : LVIS_SELECTED, LVIS_SELECTED);
2511             break;
2512         case FCIDM_SHVIEW_REFRESH:
2513             Refresh();
2514             break;
2515         case FCIDM_SHVIEW_DELETE:
2516         case FCIDM_SHVIEW_CUT:
2517         case FCIDM_SHVIEW_COPY:
2518         case FCIDM_SHVIEW_RENAME:
2519         case FCIDM_SHVIEW_PROPERTIES:
2520             if (SHRestricted(REST_NOVIEWCONTEXTMENU))
2521                 return 0;
2522             return OnExplorerCommand(dwCmdID, TRUE);
2523         case FCIDM_SHVIEW_COPYTO:
2524         case FCIDM_SHVIEW_MOVETO:
2525             _DoCopyToMoveToFolder(dwCmdID == FCIDM_SHVIEW_COPYTO);
2526             return 0;
2527         case FCIDM_SHVIEW_INSERT:
2528         case FCIDM_SHVIEW_UNDO:
2529         case FCIDM_SHVIEW_INSERTLINK:
2530         case FCIDM_SHVIEW_NEWFOLDER:
2531             return OnExplorerCommand(dwCmdID, FALSE);
2532         default:
2533             // WM_COMMAND messages from file menu are routed to CDefView to let m_pFileMenu handle them
2534             if (m_pFileMenu && dwCmd == 0)
2535             {
2536                 HMENU Dummy = NULL;
2537                 MenuCleanup _(m_pFileMenu, Dummy);
2538                 InvokeContextMenuCommand(m_pFileMenu, MAKEINTRESOURCEA(dwCmdID), NULL);
2539             }
2540     }
2541 
2542     return 0;
2543 }
2544 
2545 static BOOL
2546 SelectExtOnRename(void)
2547 {
2548     HKEY hKey;
2549     LONG error;
2550     DWORD dwValue = FALSE, cbValue;
2551 
2552     error = RegOpenKeyExW(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER, 0, KEY_READ, &hKey);
2553     if (error)
2554         return dwValue;
2555 
2556     cbValue = sizeof(dwValue);
2557     RegQueryValueExW(hKey, L"SelectExtOnRename", NULL, NULL, (LPBYTE)&dwValue, &cbValue);
2558 
2559     RegCloseKey(hKey);
2560     return !!dwValue;
2561 }
2562 
2563 LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2564 {
2565     UINT             CtlID;
2566     LPNMHDR          lpnmh;
2567     LPNMLISTVIEW     lpnmlv;
2568     NMLVDISPINFOW    *lpdi;
2569     PCUITEMID_CHILD  pidl;
2570     BOOL             unused;
2571 
2572     CtlID = wParam;
2573     lpnmh = (LPNMHDR)lParam;
2574     lpnmlv = (LPNMLISTVIEW)lpnmh;
2575     lpdi = (NMLVDISPINFOW *)lpnmh;
2576 
2577     TRACE("%p CtlID=%u lpnmh->code=%x\n", this, CtlID, lpnmh->code);
2578 
2579     switch (lpnmh->code)
2580     {
2581         case NM_SETFOCUS:
2582             TRACE("-- NM_SETFOCUS %p\n", this);
2583             OnSetFocus(0, 0, 0, unused);
2584             break;
2585         case NM_KILLFOCUS:
2586             TRACE("-- NM_KILLFOCUS %p\n", this);
2587             OnDeactivate();
2588             /* Notify the ICommDlgBrowser interface */
2589             OnStateChange(CDBOSC_KILLFOCUS);
2590             break;
2591         case NM_CUSTOMDRAW:
2592             TRACE("-- NM_CUSTOMDRAW %p\n", this);
2593             return CDRF_DODEFAULT;
2594         case NM_RELEASEDCAPTURE:
2595             TRACE("-- NM_RELEASEDCAPTURE %p\n", this);
2596             break;
2597         case NM_CLICK:
2598             TRACE("-- NM_CLICK %p\n", this);
2599             break;
2600         case NM_RCLICK:
2601             TRACE("-- NM_RCLICK %p\n", this);
2602             break;
2603         case NM_DBLCLK:
2604             TRACE("-- NM_DBLCLK %p\n", this);
2605             OpenSelectedItems();
2606             break;
2607         case NM_RETURN:
2608             TRACE("-- NM_RETURN %p\n", this);
2609             OpenSelectedItems();
2610             break;
2611         case HDN_ENDTRACKW:
2612             TRACE("-- HDN_ENDTRACKW %p\n", this);
2613             //nColumn1 = m_ListView.GetColumnWidth(0);
2614             //nColumn2 = m_ListView.GetColumnWidth(1);
2615             break;
2616         case LVN_DELETEITEM:
2617             TRACE("-- LVN_DELETEITEM %p\n", this);
2618             /*delete the pidl because we made a copy of it*/
2619             SHFree(reinterpret_cast<LPVOID>(lpnmlv->lParam));
2620             break;
2621         case LVN_DELETEALLITEMS:
2622             TRACE("-- LVN_DELETEALLITEMS %p\n", this);
2623             return FALSE;
2624         case LVN_INSERTITEM:
2625             TRACE("-- LVN_INSERTITEM (STUB)%p\n", this);
2626             break;
2627         case LVN_ITEMACTIVATE:
2628             TRACE("-- LVN_ITEMACTIVATE %p\n", this);
2629             OnStateChange(CDBOSC_SELCHANGE); // browser will get the IDataObject
2630             break;
2631         case LVN_COLUMNCLICK:
2632         {
2633             UINT foldercol = MapListColumnToFolderColumn(lpnmlv->iSubItem);
2634             HRESULT hr = S_FALSE;
2635             if (m_pSDParent)
2636                 hr = m_pSDParent->ColumnClick(foldercol);
2637             if (hr != S_OK)
2638                 hr = _DoFolderViewCB(SFVM_COLUMNCLICK, foldercol, 0);
2639             if (hr != S_OK)
2640                 _Sort(lpnmlv->iSubItem);
2641             break;
2642         }
2643         case LVN_GETDISPINFOA:
2644         case LVN_GETDISPINFOW:
2645             TRACE("-- LVN_GETDISPINFO %p\n", this);
2646             pidl = _PidlByItem(lpdi->item);
2647 
2648             if (lpdi->item.mask & LVIF_TEXT)    /* text requested */
2649             {
2650                 SHELLDETAILS sd;
2651                 if (FAILED_UNEXPECTEDLY(GetDetailsByListColumn(pidl, lpdi->item.iSubItem, sd)))
2652                     break;
2653 
2654                 if (lpnmh->code == LVN_GETDISPINFOA)
2655                 {
2656                     /* shouldn't happen */
2657                     NMLVDISPINFOA *lpdiA = (NMLVDISPINFOA *)lpnmh;
2658                     StrRetToStrNA( lpdiA->item.pszText, lpdiA->item.cchTextMax, &sd.str, NULL);
2659                     TRACE("-- text=%s\n", lpdiA->item.pszText);
2660                 }
2661                 else /* LVN_GETDISPINFOW */
2662                 {
2663                     StrRetToStrNW( lpdi->item.pszText, lpdi->item.cchTextMax, &sd.str, NULL);
2664                     TRACE("-- text=%s\n", debugstr_w(lpdi->item.pszText));
2665                 }
2666             }
2667             if(lpdi->item.mask & LVIF_IMAGE)    /* image requested */
2668             {
2669                 lpdi->item.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
2670             }
2671             if(lpdi->item.mask & LVIF_STATE)
2672             {
2673                 ULONG attributes = SFGAO_HIDDEN;
2674                 if (SUCCEEDED(m_pSFParent->GetAttributesOf(1, &pidl, &attributes)))
2675                 {
2676                     if (attributes & SFGAO_HIDDEN)
2677                         lpdi->item.state |= LVIS_CUT;
2678                 }
2679             }
2680             lpdi->item.mask |= LVIF_DI_SETITEM;
2681             break;
2682         case LVN_ITEMCHANGED:
2683             TRACE("-- LVN_ITEMCHANGED %p\n", this);
2684             if ((lpnmlv->uOldState ^ lpnmlv->uNewState) & (LVIS_SELECTED | LVIS_FOCUSED))
2685             {
2686                 OnStateChange(CDBOSC_SELCHANGE); // browser will get the IDataObject
2687                 // FIXME: Use LVIS_DROPHILITED instead in drag_notify_subitem
2688                 if (!m_ScheduledStatusbarUpdate && (m_iDragOverItem == -1 || m_pCurDropTarget == NULL))
2689                 {
2690                     m_ScheduledStatusbarUpdate = true;
2691                     PostMessage(SHV_UPDATESTATUSBAR, 0, 0);
2692                 }
2693                 _DoFolderViewCB(SFVM_SELECTIONCHANGED, NULL/* FIXME */, NULL/* FIXME */);
2694             }
2695             break;
2696         case LVN_BEGINDRAG:
2697         case LVN_BEGINRDRAG:
2698             TRACE("-- LVN_BEGINDRAG\n");
2699             if (GetSelections())
2700             {
2701                 CComPtr<IDataObject> pda;
2702                 DWORD dwAttributes = SFGAO_CANCOPY | SFGAO_CANLINK;
2703                 DWORD dwEffect = DROPEFFECT_MOVE;
2704 
2705                 if (SUCCEEDED(m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, IID_NULL_PPV_ARG(IDataObject, &pda))))
2706                 {
2707                     LPNMLISTVIEW params = (LPNMLISTVIEW)lParam;
2708 
2709                     if (SUCCEEDED(m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &dwAttributes)))
2710                         dwEffect |= dwAttributes & (SFGAO_CANCOPY | SFGAO_CANLINK);
2711 
2712                     CComPtr<IAsyncOperation> piaso;
2713                     if (SUCCEEDED(pda->QueryInterface(IID_PPV_ARG(IAsyncOperation, &piaso))))
2714                         piaso->SetAsyncMode(TRUE);
2715 
2716                     DWORD dwEffect2;
2717 
2718                     m_pSourceDataObject = pda;
2719                     m_ptFirstMousePos = params->ptAction;
2720                     ClientToScreen(&m_ptFirstMousePos);
2721                     ::ClientToListView(m_ListView, &m_ptFirstMousePos);
2722 
2723                     HIMAGELIST big_icons, small_icons;
2724                     Shell_GetImageLists(&big_icons, &small_icons);
2725                     PCUITEMID_CHILD pidl = _PidlByItem(params->iItem);
2726                     int iIcon = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
2727                     POINT ptItem;
2728                     m_ListView.GetItemPosition(params->iItem, &ptItem);
2729 
2730                     ImageList_BeginDrag(big_icons, iIcon, params->ptAction.x - ptItem.x, params->ptAction.y - ptItem.y);
2731                     DoDragDrop(pda, this, dwEffect, &dwEffect2);
2732                     m_pSourceDataObject.Release();
2733                 }
2734             }
2735             break;
2736         case LVN_BEGINLABELEDITW:
2737         {
2738             DWORD dwAttr = SFGAO_CANRENAME;
2739             pidl = _PidlByItem(lpdi->item);
2740 
2741             TRACE("-- LVN_BEGINLABELEDITW %p\n", this);
2742 
2743             m_pSFParent->GetAttributesOf(1, &pidl, &dwAttr);
2744             if (SFGAO_CANRENAME & dwAttr)
2745             {
2746                 HWND hEdit = reinterpret_cast<HWND>(m_ListView.SendMessage(LVM_GETEDITCONTROL));
2747                 SHLimitInputEdit(hEdit, m_pSFParent);
2748 
2749                 // smartass-renaming: See CORE-15242
2750                 if (!(dwAttr & SFGAO_FOLDER) && (dwAttr & SFGAO_FILESYSTEM) &&
2751                     (lpdi->item.mask & LVIF_TEXT) && !SelectExtOnRename())
2752                 {
2753                     WCHAR szFullPath[MAX_PATH];
2754                     PIDLIST_ABSOLUTE pidlFull = ILCombine(m_pidlParent, pidl);
2755                     SHGetPathFromIDListW(pidlFull, szFullPath);
2756 
2757                     INT cchLimit = 0;
2758                     _DoFolderViewCB(SFVM_GETNAMELENGTH, (WPARAM)pidlFull, (LPARAM)&cchLimit);
2759                     if (cchLimit)
2760                         ::SendMessageW(hEdit, EM_SETLIMITTEXT, cchLimit, 0);
2761 
2762                     if (!SHELL_FS_HideExtension(szFullPath))
2763                     {
2764                         LPWSTR pszText = lpdi->item.pszText;
2765                         LPWSTR pchDotExt = PathFindExtensionW(pszText);
2766                         ::PostMessageW(hEdit, EM_SETSEL, 0, pchDotExt - pszText);
2767                         ::PostMessageW(hEdit, EM_SCROLLCARET, 0, 0);
2768                     }
2769 
2770                     ILFree(pidlFull);
2771                 }
2772 
2773                 m_isEditing = TRUE;
2774                 return FALSE;
2775             }
2776             return TRUE;
2777         }
2778         case LVN_ENDLABELEDITW:
2779         {
2780             TRACE("-- LVN_ENDLABELEDITW %p\n", this);
2781             m_isEditing = FALSE;
2782 
2783             if (lpdi->item.pszText)
2784             {
2785                 HRESULT hr;
2786                 LVITEMW lvItem;
2787 
2788                 pidl = _PidlByItem(lpdi->item);
2789                 PITEMID_CHILD pidlNew = NULL;
2790                 hr = m_pSFParent->SetNameOf(0, pidl, lpdi->item.pszText, SHGDN_INFOLDER, &pidlNew);
2791 
2792                 if (SUCCEEDED(hr) && pidlNew)
2793                 {
2794                     lvItem.mask = LVIF_PARAM|LVIF_IMAGE;
2795                     lvItem.iItem = lpdi->item.iItem;
2796                     lvItem.iSubItem = 0;
2797                     lvItem.lParam = reinterpret_cast<LPARAM>(pidlNew);
2798                     lvItem.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidlNew, 0);
2799                     m_ListView.SetItem(&lvItem);
2800                     m_ListView.Update(lpdi->item.iItem);
2801                     return TRUE;
2802                 }
2803             }
2804 
2805             return FALSE;
2806         }
2807         default:
2808             TRACE("-- %p WM_COMMAND %x unhandled\n", this, lpnmh->code);
2809             break;
2810     }
2811 
2812     return 0;
2813 }
2814 
2815 // This is just a quick hack to make the desktop work correctly.
2816 // ITranslateShellChangeNotify's IsChildID is undocumented, but most likely the
2817 // way that a folder should know if it should update upon a change notification.
2818 // It is exported by merged folders at a minimum.
2819 static BOOL ILIsParentOrSpecialParent(PCIDLIST_ABSOLUTE pidl1, PCIDLIST_ABSOLUTE pidl2)
2820 {
2821     if (!pidl1 || !pidl2)
2822         return FALSE;
2823     if (ILIsParent(pidl1, pidl2, TRUE))
2824         return TRUE;
2825 
2826     CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidl2Clone(ILClone(pidl2));
2827     ILRemoveLastID(pidl2Clone);
2828     return ILIsEqual(pidl1, pidl2Clone);
2829 }
2830 
2831 LRESULT CDefView::OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2832 {
2833     // The change notify can come before WM_CREATE
2834     if (!m_ListView)
2835         return FALSE;
2836 
2837     HANDLE hChange = (HANDLE)wParam;
2838     DWORD dwProcID = (DWORD)lParam;
2839     PIDLIST_ABSOLUTE *Pidls;
2840     LONG lEvent;
2841     HANDLE hLock = SHChangeNotification_Lock(hChange, dwProcID, &Pidls, &lEvent);
2842     if (hLock == NULL)
2843     {
2844         ERR("hLock == NULL\n");
2845         return FALSE;
2846     }
2847 
2848     TRACE("(%p)(%p,%p,%p)\n", this, Pidls[0], Pidls[1], lParam);
2849 
2850     if (_DoFolderViewCB(SFVM_FSNOTIFY, (WPARAM)Pidls, lEvent) == S_FALSE)
2851         return FALSE;
2852 
2853     // Translate child IDLs.
2854     // SHSimpleIDListFromPathW creates fake PIDLs (lacking some attributes)
2855     HRESULT hr;
2856     PITEMID_CHILD child0 = NULL, child1 = NULL;
2857     CComHeapPtr<ITEMIDLIST_RELATIVE> pidl0Temp, pidl1Temp;
2858     if (_ILIsSpecialFolder(Pidls[0]) || ILIsParentOrSpecialParent(m_pidlParent, Pidls[0]))
2859     {
2860         child0 = ILFindLastID(Pidls[0]);
2861         hr = SHGetRealIDL(m_pSFParent, child0, &pidl0Temp);
2862         if (SUCCEEDED(hr))
2863             child0 = pidl0Temp;
2864     }
2865     if (_ILIsSpecialFolder(Pidls[1]) || ILIsParentOrSpecialParent(m_pidlParent, Pidls[1]))
2866     {
2867         child1 = ILFindLastID(Pidls[1]);
2868         hr = SHGetRealIDL(m_pSFParent, child1, &pidl1Temp);
2869         if (SUCCEEDED(hr))
2870             child1 = pidl1Temp;
2871     }
2872 
2873     lEvent &= ~SHCNE_INTERRUPT;
2874     switch (lEvent)
2875     {
2876         case SHCNE_MKDIR:
2877         case SHCNE_CREATE:
2878         case SHCNE_DRIVEADD:
2879             if (!child0)
2880                 break;
2881             if (LV_FindItemByPidl(child0) < 0)
2882                 LV_AddItem(child0);
2883             else
2884                 LV_UpdateItem(child0);
2885             break;
2886         case SHCNE_RMDIR:
2887         case SHCNE_DELETE:
2888         case SHCNE_DRIVEREMOVED:
2889             if (child0)
2890                 LV_DeleteItem(child0);
2891             break;
2892         case SHCNE_RENAMEFOLDER:
2893         case SHCNE_RENAMEITEM:
2894             if (child0 && child1)
2895                 LV_RenameItem(child0, child1);
2896             else if (child0)
2897                 LV_DeleteItem(child0);
2898             else if (child1)
2899                 LV_AddItem(child1);
2900             break;
2901         case SHCNE_UPDATEITEM:
2902             if (child0)
2903                 LV_UpdateItem(child0);
2904             break;
2905         case SHCNE_UPDATEIMAGE:
2906         case SHCNE_MEDIAINSERTED:
2907         case SHCNE_MEDIAREMOVED:
2908         case SHCNE_ASSOCCHANGED:
2909             LV_RefreshIcons();
2910             break;
2911         case SHCNE_UPDATEDIR:
2912         case SHCNE_ATTRIBUTES:
2913             Refresh();
2914             UpdateStatusbar();
2915             break;
2916         case SHCNE_FREESPACE:
2917             UpdateStatusbar();
2918             break;
2919     }
2920 
2921     SHChangeNotification_Unlock(hLock);
2922     return TRUE;
2923 }
2924 
2925 HRESULT SHGetMenuIdFromMenuMsg(UINT uMsg, LPARAM lParam, UINT *CmdId);
2926 HRESULT SHSetMenuIdInMenuMsg(UINT uMsg, LPARAM lParam, UINT CmdId);
2927 
2928 LRESULT CDefView::OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2929 {
2930     if (!m_pCM)
2931     {
2932         /* no menu */
2933         ERR("no context menu\n");
2934         return FALSE;
2935     }
2936 
2937     // lParam of WM_DRAWITEM WM_MEASUREITEM contains a menu id and
2938     // this also needs to be changed to a menu identifier offset
2939     UINT CmdID;
2940     HRESULT hres = SHGetMenuIdFromMenuMsg(uMsg, lParam, &CmdID);
2941     if (SUCCEEDED(hres))
2942         SHSetMenuIdInMenuMsg(uMsg, lParam, CmdID - CONTEXT_MENU_BASE_ID);
2943 
2944     /* Forward the message to the IContextMenu2 */
2945     LRESULT result;
2946     hres = SHForwardContextMenuMsg(m_pCM, uMsg, wParam, lParam, &result, TRUE);
2947 
2948     return (SUCCEEDED(hres));
2949 }
2950 
2951 LRESULT CDefView::OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2952 {
2953     /* Wallpaper setting affects drop shadows effect */
2954     if (wParam == SPI_SETDESKWALLPAPER || wParam == 0)
2955         UpdateListColors();
2956 
2957     return S_OK;
2958 }
2959 
2960 LRESULT CDefView::OnInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2961 {
2962     HMENU hmenu = (HMENU) wParam;
2963     int nPos = LOWORD(lParam);
2964     UINT  menuItemId;
2965 
2966     if (m_pCM)
2967         OnCustomItem(uMsg, wParam, lParam, bHandled);
2968 
2969     HMENU hViewMenu = GetSubmenuByID(m_hMenu, FCIDM_MENU_VIEW);
2970 
2971     if (GetSelections() == 0)
2972     {
2973         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_CUT, MF_GRAYED);
2974         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_COPY, MF_GRAYED);
2975         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_RENAME, MF_GRAYED);
2976         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_COPYTO, MF_GRAYED);
2977         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_MOVETO, MF_GRAYED);
2978         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_DELETE, MF_GRAYED);
2979     }
2980     else
2981     {
2982         // FIXME: Check copyable
2983         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_CUT, MF_ENABLED);
2984         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_COPY, MF_ENABLED);
2985         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_RENAME, MF_ENABLED);
2986         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_COPYTO, MF_ENABLED);
2987         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_MOVETO, MF_ENABLED);
2988         ::EnableMenuItem(hmenu, FCIDM_SHVIEW_DELETE, MF_ENABLED);
2989     }
2990 
2991     /* Lets try to find out what the hell wParam is */
2992     if (hmenu == GetSubMenu(m_hMenu, nPos))
2993         menuItemId = ReallyGetMenuItemID(m_hMenu, nPos);
2994     else if (hViewMenu && hmenu == GetSubMenu(hViewMenu, nPos))
2995         menuItemId = ReallyGetMenuItemID(hViewMenu, nPos);
2996     else if (m_hContextMenu && hmenu == GetSubMenu(m_hContextMenu, nPos))
2997         menuItemId = ReallyGetMenuItemID(m_hContextMenu, nPos);
2998     else
2999         return FALSE;
3000 
3001     switch (menuItemId)
3002     {
3003     case FCIDM_MENU_FILE:
3004         FillFileMenu();
3005         break;
3006     case FCIDM_MENU_VIEW:
3007     case FCIDM_SHVIEW_VIEW:
3008         CheckViewMode(hmenu);
3009         break;
3010     case FCIDM_SHVIEW_ARRANGE:
3011         FillArrangeAsMenu(hmenu);
3012         break;
3013     }
3014 
3015     return FALSE;
3016 }
3017 
3018 
3019 // The INTERFACE of the IShellView object
3020 
3021 HRESULT WINAPI CDefView::GetWindow(HWND *phWnd)
3022 {
3023     TRACE("(%p)\n", this);
3024 
3025     *phWnd = m_hWnd;
3026 
3027     return S_OK;
3028 }
3029 
3030 HRESULT WINAPI CDefView::ContextSensitiveHelp(BOOL fEnterMode)
3031 {
3032     FIXME("(%p) stub\n", this);
3033 
3034     return E_NOTIMPL;
3035 }
3036 
3037 // FIXME: use the accel functions
3038 HRESULT WINAPI CDefView::TranslateAccelerator(LPMSG lpmsg)
3039 {
3040     if (m_isEditing)
3041         return S_FALSE;
3042 
3043     if (lpmsg->message >= WM_KEYFIRST && lpmsg->message <= WM_KEYLAST)
3044     {
3045         if (::TranslateAcceleratorW(m_hWnd, m_hAccel, lpmsg) != 0)
3046             return S_OK;
3047 
3048         TRACE("-- key=0x%04lx\n", lpmsg->wParam);
3049     }
3050 
3051     return m_pShellBrowser->TranslateAcceleratorSB(lpmsg, 0);
3052 }
3053 
3054 HRESULT WINAPI CDefView::EnableModeless(BOOL fEnable)
3055 {
3056     FIXME("(%p)\n", this);
3057     return E_NOTIMPL;
3058 }
3059 
3060 HRESULT WINAPI CDefView::UIActivate(UINT uState)
3061 {
3062     TRACE("(%p)->(state=%x)\n", this, uState);
3063 
3064     // don't do anything if the state isn't changing
3065     if (m_uState == uState)
3066         return S_OK;
3067 
3068     // OnActivate handles the menu merging and internal state
3069     DoActivate(uState);
3070 
3071     // only do this if we are active
3072     if (uState != SVUIA_DEACTIVATE)
3073     {
3074         _ForceStatusBarResize();
3075 
3076         // Set the text for the status bar
3077         UpdateStatusbar();
3078     }
3079 
3080     return S_OK;
3081 }
3082 
3083 HRESULT WINAPI CDefView::Refresh()
3084 {
3085     TRACE("(%p)\n", this);
3086 
3087     _DoFolderViewCB(SFVM_LISTREFRESHED, TRUE, 0);
3088 
3089     m_ListView.DeleteAllItems();
3090     FillList();
3091 
3092     return S_OK;
3093 }
3094 
3095 HRESULT WINAPI CDefView::CreateViewWindow(IShellView *lpPrevView, LPCFOLDERSETTINGS lpfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd)
3096 {
3097     return CreateViewWindow3(psb, lpPrevView, SV3CVW3_DEFAULT,
3098         (FOLDERFLAGS)lpfs->fFlags, (FOLDERFLAGS)lpfs->fFlags, (FOLDERVIEWMODE)lpfs->ViewMode, NULL, prcView, phWnd);
3099 }
3100 
3101 HRESULT WINAPI CDefView::DestroyViewWindow()
3102 {
3103     TRACE("(%p)\n", this);
3104 
3105     /* Make absolutely sure all our UI is cleaned up */
3106     UIActivate(SVUIA_DEACTIVATE);
3107 
3108     if (m_hAccel)
3109     {
3110         // MSDN: Accelerator tables loaded from resources are freed automatically when application terminates
3111         m_hAccel = NULL;
3112     }
3113 
3114     if (m_hMenuArrangeModes)
3115     {
3116         DestroyMenu(m_hMenuArrangeModes);
3117         m_hMenuArrangeModes = NULL;
3118     }
3119 
3120     if (m_hMenuViewModes)
3121     {
3122         DestroyMenu(m_hMenuViewModes);
3123         m_hMenuViewModes = NULL;
3124     }
3125 
3126     if (m_hMenu)
3127     {
3128         DestroyMenu(m_hMenu);
3129         m_hMenu = NULL;
3130     }
3131 
3132     if (m_ListView)
3133     {
3134         m_ListView.DestroyWindow();
3135     }
3136 
3137     if (m_hWnd)
3138     {
3139         _DoFolderViewCB(SFVM_WINDOWCLOSING, (WPARAM)m_hWnd, 0);
3140         DestroyWindow();
3141     }
3142 
3143     m_pShellBrowser.Release();
3144     m_pCommDlgBrowser.Release();
3145 
3146     return S_OK;
3147 }
3148 
3149 HRESULT WINAPI CDefView::GetCurrentInfo(LPFOLDERSETTINGS lpfs)
3150 {
3151     TRACE("(%p)->(%p) vmode=%x flags=%x\n", this, lpfs,
3152           m_FolderSettings.ViewMode, m_FolderSettings.fFlags);
3153 
3154     if (!lpfs)
3155         return E_INVALIDARG;
3156 
3157     *lpfs = m_FolderSettings;
3158     return S_OK;
3159 }
3160 
3161 HRESULT WINAPI CDefView::AddPropertySheetPages(DWORD dwReserved, LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam)
3162 {
3163     TRACE("(%p)->(0x%lX, %p, %p)\n", this, dwReserved, lpfn, lparam);
3164 
3165     SFVM_PROPPAGE_DATA Data = { dwReserved, lpfn, lparam };
3166     _DoFolderViewCB(SFVM_ADDPROPERTYPAGES, 0, (LPARAM)&Data);
3167     return S_OK;
3168 }
3169 
3170 static HRESULT Read(IStream *pS, LPVOID buffer, ULONG cb)
3171 {
3172     ULONG read;
3173     HRESULT hr = pS->Read(buffer, cb, &read);
3174     return FAILED(hr) ? hr : (cb == read ? S_OK : HResultFromWin32(ERROR_MORE_DATA));
3175 }
3176 
3177 static DWORD ReadDWORD(IPropertyBag *pPB, LPCWSTR name, DWORD def)
3178 {
3179     DWORD value;
3180     HRESULT hr = SHPropertyBag_ReadDWORD(pPB, name, &value);
3181     return SUCCEEDED(hr) ? value : def;
3182 }
3183 
3184 HRESULT CDefView::GetDefaultViewStream(DWORD Stgm, IStream **ppStream)
3185 {
3186     CLSID clsid;
3187     HRESULT hr = IUnknown_GetClassID(m_pSFParent, &clsid);
3188     if (SUCCEEDED(hr))
3189     {
3190         WCHAR path[MAX_PATH], name[39];
3191         wsprintfW(path, L"%s\\%s", REGSTR_PATH_EXPLORER, L"Streams\\Default");
3192         StringFromGUID2(clsid, name, 39);
3193         *ppStream = SHOpenRegStream2W(HKEY_CURRENT_USER, path, name, Stgm);
3194         hr = *ppStream ? S_OK : E_FAIL;
3195     }
3196     return hr;
3197 }
3198 
3199 static HRESULT LoadColumnsStream(PERSISTCOLUMNS &cols, IStream *pS)
3200 {
3201     HRESULT hr = Read(pS, &cols, FIELD_OFFSET(PERSISTCOLUMNS, Columns));
3202     if (FAILED(hr))
3203         return hr;
3204     if (cols.Signature != PERSISTCOLUMNS::SIG || cols.Count > cols.MAXCOUNT)
3205         return HResultFromWin32(ERROR_INVALID_DATA);
3206     return Read(pS, &cols.Columns, sizeof(*cols.Columns) * cols.Count);
3207 }
3208 
3209 HRESULT CDefView::LoadViewState()
3210 {
3211     PERSISTCLASSICVIEWSTATE cvs;
3212     PERSISTCOLUMNS cols;
3213     CComPtr<IStream> pS;
3214     CComPtr<IPropertyBag> pPB;
3215     bool fallback = false;
3216     HRESULT hrColumns = E_FAIL;
3217     HRESULT hr = IUnknown_QueryServicePropertyBag(m_pShellBrowser, SHGVSPB_FOLDER, IID_PPV_ARG(IPropertyBag, &pPB));
3218     if (SUCCEEDED(hr))
3219     {
3220         DWORD data;
3221         if (FAILED(hr = SHPropertyBag_ReadDWORD(pPB, L"Mode", &data)))
3222             goto loadfallback;
3223         cvs.FolderSettings.ViewMode = data;
3224         cvs.FolderSettings.fFlags = ReadDWORD(pPB, L"FFlags", FWF_NOGROUPING);
3225         data = ReadDWORD(pPB, L"Sort", ~0ul);
3226         cvs.SortColId = data != ~0ul ? (WORD)data : LISTVIEW_SORT_INFO::UNSPECIFIEDCOLUMN;
3227         cvs.SortDir = (INT8)ReadDWORD(pPB, L"SortDir", 1);
3228         if (SUCCEEDED(hrColumns = SHPropertyBag_ReadStream(pPB, L"ColInfo", &pS)))
3229             hrColumns = LoadColumnsStream(cols, pS);
3230     }
3231     else
3232     {
3233         if (FAILED(hr = (m_pShellBrowser ? m_pShellBrowser->GetViewStateStream(STGM_READ, &pS) : E_UNEXPECTED)))
3234         {
3235         loadfallback:
3236             hr = GetDefaultViewStream(STGM_READ, &pS);
3237             fallback = true;
3238         }
3239         if (FAILED(hr) || FAILED(hr = Read(pS, &cvs, sizeof(cvs))))
3240             return hr;
3241         if (cvs.Signature != cvs.SIG)
3242             return HResultFromWin32(ERROR_INVALID_DATA);
3243         hrColumns = LoadColumnsStream(cols, pS);
3244     }
3245     m_FolderSettings.ViewMode = cvs.FolderSettings.ViewMode;
3246     m_FolderSettings.fFlags &= ~cvs.VALIDFWF;
3247     m_FolderSettings.fFlags |= cvs.FolderSettings.fFlags & cvs.VALIDFWF;
3248     if (SUCCEEDED(hrColumns))
3249     {
3250         BOOL failed = FALSE;
3251         if ((m_LoadColumnsList = DPA_Create(cols.Count)) != NULL)
3252         {
3253             for (UINT i = 0; i < cols.Count; ++i)
3254             {
3255                 failed |= !DPA_SetPtr(m_LoadColumnsList, i, UlongToPtr(cols.Columns[i]));
3256             }
3257         }
3258         if (failed || !cols.Count)
3259         {
3260             DPA_Destroy(m_LoadColumnsList);
3261             m_LoadColumnsList = NULL;
3262         }
3263     }
3264     m_sortInfo.bLoadedFromViewState = !fallback && m_LoadColumnsList && cvs.SortColId != LISTVIEW_SORT_INFO::UNSPECIFIEDCOLUMN;
3265     m_sortInfo.bColumnIsFolderColumn = TRUE;
3266     m_sortInfo.Direction = cvs.SortDir > 0 ? 1 : -1;
3267     m_sortInfo.ListColumn = cvs.SortColId;
3268     return hr;
3269 }
3270 
3271 HRESULT CDefView::SaveViewState(IStream *pStream)
3272 {
3273     if (!m_ListView.m_hWnd)
3274         return E_UNEXPECTED;
3275     int sortcol = MapListColumnToFolderColumn(m_sortInfo.ListColumn);
3276     PERSISTCLASSICVIEWSTATE cvs;
3277     cvs.SortColId = sortcol >= 0 ? (WORD)sortcol : 0;
3278     cvs.SortDir = m_sortInfo.Direction;
3279     PERSISTCOLUMNS cols;
3280     cols.Signature = PERSISTCOLUMNS::SIG;
3281     cols.Count = 0;
3282     LVCOLUMN lvc;
3283     lvc.mask = LVCF_WIDTH | LVCF_SUBITEM;
3284     for (UINT i = 0, j = 0; i < PERSISTCOLUMNS::MAXCOUNT && ListView_GetColumn(m_ListView, j, &lvc); ++j)
3285     {
3286         HRESULT hr = MapListColumnToFolderColumn(lvc.iSubItem);
3287         if (SUCCEEDED(hr))
3288         {
3289             cols.Columns[i] = MAKELONG(hr, lvc.cx);
3290             cols.Count = ++i;
3291         }
3292     }
3293     UINT cbColumns = FIELD_OFFSET(PERSISTCOLUMNS, Columns) + (sizeof(*cols.Columns) * cols.Count);
3294     UpdateFolderViewFlags();
3295 
3296     IPropertyBag *pPB;
3297     HRESULT hr = S_OK;
3298     if (pStream)
3299     {
3300         pStream->AddRef();
3301         goto stream;
3302     }
3303     hr = IUnknown_QueryServicePropertyBag(m_pShellBrowser, SHGVSPB_FOLDER, IID_PPV_ARG(IPropertyBag, &pPB));
3304     if (SUCCEEDED(hr))
3305     {
3306         UINT uViewMode;
3307         GetCurrentViewMode(&uViewMode);
3308         hr = SHPropertyBag_WriteDWORD(pPB, L"Mode", uViewMode);
3309         SHPropertyBag_WriteDWORD(pPB, L"FFlags", m_FolderSettings.fFlags);
3310         SHPropertyBag_WriteDWORD(pPB, L"Sort", cvs.SortColId);
3311         SHPropertyBag_WriteDWORD(pPB, L"SortDir", cvs.SortDir);
3312         pStream = cols.Count ? SHCreateMemStream((LPBYTE)&cols, cbColumns) : NULL;
3313         if (!pStream || FAILED(SHPropertyBag_WriteStream(pPB, L"ColInfo", pStream)))
3314             SHPropertyBag_Delete(pPB, L"ColInfo");
3315 #if 0 // TODO
3316         WCHAR name[MAX_PATH];
3317         memcpy(name, L"ItemPos", sizeof(L"ItemPos"));
3318         if (SHGetPerScreenResName(name + 7, _countof(name) - 7, 0))
3319         {
3320             if (GetAutoArrange() == S_FALSE)
3321                 // TODO: Save listview item positions
3322             else
3323                 SHPropertyBag_Delete(pPB, name);
3324         }
3325 #endif
3326         pPB->Release();
3327     }
3328     else if (SUCCEEDED(hr = (m_pShellBrowser ? m_pShellBrowser->GetViewStateStream(STGM_WRITE, &pStream) : E_UNEXPECTED)))
3329     {
3330     stream:
3331         ULONG written;
3332         cvs.Signature = cvs.SIG;
3333         cvs.FolderSettings = m_FolderSettings;
3334         hr = pStream->Write(&cvs, sizeof(cvs), &written);
3335         if (SUCCEEDED(hr))
3336             hr = pStream->Write(&cols, cbColumns, &written);
3337     }
3338     if (pStream)
3339         pStream->Release();
3340     return hr;
3341 }
3342 
3343 HRESULT WINAPI CDefView::SaveViewState()
3344 {
3345     if (!(m_FolderSettings.fFlags & FWF_NOBROWSERVIEWSTATE))
3346         return SaveViewState(NULL);
3347     return S_FALSE;
3348 }
3349 
3350 #define UPDATEFOLDERVIEWFLAGS(bits, bit, set) ( (bits) = ((bits) & ~(bit)) | ((set) ? (bit) : 0) )
3351 void CDefView::UpdateFolderViewFlags()
3352 {
3353     UPDATEFOLDERVIEWFLAGS(m_FolderSettings.fFlags, FWF_AUTOARRANGE, GetAutoArrange() == S_OK);
3354     UPDATEFOLDERVIEWFLAGS(m_FolderSettings.fFlags, FWF_SNAPTOGRID, _GetSnapToGrid() == S_OK);
3355     UPDATEFOLDERVIEWFLAGS(m_FolderSettings.fFlags, FWF_NOGROUPING, !ListView_IsGroupViewEnabled(m_ListView.m_hWnd));
3356 }
3357 
3358 HRESULT WINAPI CDefView::SelectItem(PCUITEMID_CHILD pidl, UINT uFlags)
3359 {
3360     int i;
3361 
3362     TRACE("(%p)->(pidl=%p, 0x%08x) stub\n", this, pidl, uFlags);
3363 
3364     if (!m_ListView)
3365     {
3366         ERR("!m_ListView\n");
3367         return E_FAIL;
3368     }
3369 
3370     i = LV_FindItemByPidl(pidl);
3371     if (i == -1)
3372         return S_OK;
3373 
3374     LVITEMW lvItem = {0};
3375     lvItem.mask = LVIF_STATE;
3376     lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
3377 
3378     while (m_ListView.GetItem(&lvItem))
3379     {
3380         if (lvItem.iItem == i)
3381         {
3382             if (uFlags & SVSI_SELECT)
3383                 lvItem.state |= LVIS_SELECTED;
3384             else
3385                 lvItem.state &= ~LVIS_SELECTED;
3386 
3387             if (uFlags & SVSI_FOCUSED)
3388                 lvItem.state |= LVIS_FOCUSED;
3389             else
3390                 lvItem.state &= ~LVIS_FOCUSED;
3391         }
3392         else
3393         {
3394             if (uFlags & SVSI_DESELECTOTHERS)
3395             {
3396                 lvItem.state &= ~LVIS_SELECTED;
3397             }
3398             lvItem.state &= ~LVIS_FOCUSED;
3399         }
3400 
3401         m_ListView.SetItem(&lvItem);
3402         lvItem.iItem++;
3403     }
3404 
3405     if (uFlags & SVSI_ENSUREVISIBLE)
3406         m_ListView.EnsureVisible(i, FALSE);
3407 
3408     if((uFlags & SVSI_EDIT) == SVSI_EDIT)
3409         m_ListView.EditLabel(i);
3410 
3411     return S_OK;
3412 }
3413 
3414 HRESULT WINAPI CDefView::GetItemObject(UINT uItem, REFIID riid, LPVOID *ppvOut)
3415 {
3416     HRESULT hr = E_NOINTERFACE;
3417 
3418     TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n", this, uItem, debugstr_guid(&riid), ppvOut);
3419 
3420     if (!ppvOut)
3421         return E_INVALIDARG;
3422 
3423     *ppvOut = NULL;
3424 
3425     switch (uItem)
3426     {
3427         case SVGIO_BACKGROUND:
3428             if (IsEqualIID(riid, IID_IContextMenu))
3429             {
3430                 hr = CDefViewBckgrndMenu_CreateInstance(m_pSF2Parent, riid, ppvOut);
3431                 if (FAILED_UNEXPECTEDLY(hr))
3432                     return hr;
3433 
3434                 IUnknown_SetSite(*((IUnknown**)ppvOut), (IShellView *)this);
3435             }
3436             else if (IsEqualIID(riid, IID_IDispatch))
3437             {
3438                 if (m_pShellFolderViewDual == NULL)
3439                 {
3440                     hr = CDefViewDual_Constructor(riid, (LPVOID*)&m_pShellFolderViewDual);
3441                     if (FAILED_UNEXPECTEDLY(hr))
3442                         return hr;
3443                 }
3444                 hr = m_pShellFolderViewDual->QueryInterface(riid, ppvOut);
3445             }
3446             break;
3447         case SVGIO_SELECTION:
3448             GetSelections();
3449             hr = m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, riid, 0, ppvOut);
3450             if (FAILED_UNEXPECTEDLY(hr))
3451                 return hr;
3452 
3453             if (IsEqualIID(riid, IID_IContextMenu))
3454                 IUnknown_SetSite(*((IUnknown**)ppvOut), (IShellView *)this);
3455 
3456             break;
3457     }
3458 
3459     TRACE("-- (%p)->(interface=%p)\n", this, *ppvOut);
3460 
3461     return hr;
3462 }
3463 
3464 FOLDERVIEWMODE CDefView::GetDefaultViewMode()
3465 {
3466     FOLDERVIEWMODE mode = ((m_FolderSettings.fFlags & FWF_DESKTOP) || !IsOS(OS_SERVERADMINUI)) ? FVM_ICON : FVM_DETAILS;
3467     FOLDERVIEWMODE temp = mode;
3468     if (SUCCEEDED(_DoFolderViewCB(SFVM_DEFVIEWMODE, 0, (LPARAM)&temp)) && temp >= FVM_FIRST && temp <= FVM_LAST)
3469         mode = temp;
3470     return mode;
3471 }
3472 
3473 HRESULT STDMETHODCALLTYPE CDefView::GetCurrentViewMode(UINT *pViewMode)
3474 {
3475     TRACE("(%p)->(%p), stub\n", this, pViewMode);
3476 
3477     if (!pViewMode)
3478         return E_INVALIDARG;
3479 
3480     *pViewMode = m_FolderSettings.ViewMode;
3481     return S_OK;
3482 }
3483 
3484 HRESULT STDMETHODCALLTYPE CDefView::SetCurrentViewMode(UINT ViewMode)
3485 {
3486     DWORD dwStyle;
3487     TRACE("(%p)->(%u), stub\n", this, ViewMode);
3488 
3489     /* It's not redundant to check FVM_AUTO because it's a (UINT)-1 */
3490     if (((INT)ViewMode < FVM_FIRST || (INT)ViewMode > FVM_LAST) && ((INT)ViewMode != FVM_AUTO))
3491         return E_INVALIDARG;
3492 
3493     /* Windows before Vista uses LVM_SETVIEW and possibly
3494        LVM_SETEXTENDEDLISTVIEWSTYLE to set the style of the listview,
3495        while later versions seem to accomplish this through other
3496        means. */
3497     switch (ViewMode)
3498     {
3499         case FVM_ICON:
3500             dwStyle = LVS_ICON;
3501             break;
3502         case FVM_DETAILS:
3503             dwStyle = LVS_REPORT;
3504             break;
3505         case FVM_SMALLICON:
3506             dwStyle = LVS_SMALLICON;
3507             break;
3508         case FVM_LIST:
3509             dwStyle = LVS_LIST;
3510             break;
3511         default:
3512         {
3513             FIXME("ViewMode %d not implemented\n", ViewMode);
3514             dwStyle = LVS_LIST;
3515             break;
3516         }
3517     }
3518 
3519     m_ListView.ModifyStyle(LVS_TYPEMASK, dwStyle);
3520 
3521     /* This will not necessarily be the actual mode set above.
3522        This mimics the behavior of Windows XP. */
3523     m_FolderSettings.ViewMode = ViewMode;
3524 
3525     return S_OK;
3526 }
3527 
3528 HRESULT STDMETHODCALLTYPE CDefView::GetFolder(REFIID riid, void **ppv)
3529 {
3530     if (m_pSFParent == NULL)
3531         return E_FAIL;
3532 
3533     return m_pSFParent->QueryInterface(riid, ppv);
3534 }
3535 
3536 HRESULT STDMETHODCALLTYPE CDefView::Item(int iItemIndex, PITEMID_CHILD *ppidl)
3537 {
3538     PCUITEMID_CHILD pidl = _PidlByItem(iItemIndex);
3539     if (pidl)
3540     {
3541         *ppidl = ILClone(pidl);
3542         return S_OK;
3543     }
3544 
3545     *ppidl = 0;
3546     return E_INVALIDARG;
3547 }
3548 
3549 HRESULT STDMETHODCALLTYPE CDefView::ItemCount(UINT uFlags, int *pcItems)
3550 {
3551     TRACE("(%p)->(%u %p)\n", this, uFlags, pcItems);
3552 
3553     if (uFlags != SVGIO_ALLVIEW)
3554         FIXME("some flags unsupported, %x\n", uFlags & ~SVGIO_ALLVIEW);
3555 
3556     *pcItems = m_ListView.GetItemCount();
3557 
3558     return S_OK;
3559 }
3560 
3561 HRESULT STDMETHODCALLTYPE CDefView::Items(UINT uFlags, REFIID riid, void **ppv)
3562 {
3563     return E_NOTIMPL;
3564 }
3565 
3566 HRESULT STDMETHODCALLTYPE CDefView::GetSelectionMarkedItem(int *piItem)
3567 {
3568     TRACE("(%p)->(%p)\n", this, piItem);
3569 
3570     *piItem = m_ListView.GetSelectionMark();
3571 
3572     return S_OK;
3573 }
3574 
3575 HRESULT STDMETHODCALLTYPE CDefView::GetFocusedItem(int *piItem)
3576 {
3577     TRACE("(%p)->(%p)\n", this, piItem);
3578 
3579     *piItem = m_ListView.GetNextItem(-1, LVNI_FOCUSED);
3580 
3581     return S_OK;
3582 }
3583 
3584 HRESULT STDMETHODCALLTYPE CDefView::GetItemPosition(PCUITEMID_CHILD pidl, POINT *ppt)
3585 {
3586     if (!m_ListView)
3587     {
3588         ERR("!m_ListView\n");
3589         return E_FAIL;
3590     }
3591 
3592     int lvIndex = LV_FindItemByPidl(pidl);
3593     if (lvIndex == -1 || ppt == NULL)
3594         return E_INVALIDARG;
3595 
3596     m_ListView.GetItemPosition(lvIndex, ppt);
3597     return S_OK;
3598 }
3599 
3600 HRESULT STDMETHODCALLTYPE CDefView::GetSpacing(POINT *ppt)
3601 {
3602     TRACE("(%p)->(%p)\n", this, ppt);
3603 
3604     if (!m_ListView)
3605     {
3606         ERR("!m_ListView\n");
3607         return S_FALSE;
3608     }
3609 
3610     if (ppt)
3611     {
3612         SIZE spacing;
3613         m_ListView.GetItemSpacing(spacing);
3614 
3615         ppt->x = spacing.cx;
3616         ppt->y = spacing.cy;
3617     }
3618 
3619     return S_OK;
3620 }
3621 
3622 HRESULT STDMETHODCALLTYPE CDefView::GetDefaultSpacing(POINT *ppt)
3623 {
3624     return E_NOTIMPL;
3625 }
3626 
3627 HRESULT STDMETHODCALLTYPE CDefView::GetAutoArrange()
3628 {
3629     return ((m_ListView.GetStyle() & LVS_AUTOARRANGE) ? S_OK : S_FALSE);
3630 }
3631 
3632 HRESULT CDefView::_GetSnapToGrid()
3633 {
3634     DWORD dwExStyle = (DWORD)m_ListView.SendMessage(LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
3635     return ((dwExStyle & LVS_EX_SNAPTOGRID) ? S_OK : S_FALSE);
3636 }
3637 
3638 HRESULT STDMETHODCALLTYPE CDefView::SelectItem(int iItem, DWORD dwFlags)
3639 {
3640     LVITEMW lvItem;
3641 
3642     TRACE("(%p)->(%d, %x)\n", this, iItem, dwFlags);
3643 
3644     lvItem.state = 0;
3645     lvItem.stateMask = LVIS_SELECTED;
3646 
3647     if (dwFlags & SVSI_ENSUREVISIBLE)
3648         m_ListView.EnsureVisible(iItem, 0);
3649 
3650     /* all items */
3651     if (dwFlags & SVSI_DESELECTOTHERS)
3652         m_ListView.SetItemState(-1, 0, LVIS_SELECTED);
3653 
3654     /* this item */
3655     if (dwFlags & SVSI_SELECT)
3656         lvItem.state |= LVIS_SELECTED;
3657 
3658     if (dwFlags & SVSI_FOCUSED)
3659         lvItem.stateMask |= LVIS_FOCUSED;
3660 
3661     m_ListView.SetItemState(iItem, lvItem.state, lvItem.stateMask);
3662 
3663     if ((dwFlags & SVSI_EDIT) == SVSI_EDIT)
3664         m_ListView.EditLabel(iItem);
3665 
3666     return S_OK;
3667 }
3668 
3669 HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItems(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, POINT *apt, DWORD dwFlags)
3670 {
3671     ASSERT(m_ListView);
3672 
3673     /* Reset the selection */
3674     m_ListView.SetItemState(-1, 0, LVIS_SELECTED);
3675 
3676     int lvIndex;
3677     for (UINT i = 0 ; i < cidl; i++)
3678     {
3679         lvIndex = LV_FindItemByPidl(apidl[i]);
3680         if (lvIndex != -1)
3681         {
3682             SelectItem(lvIndex, dwFlags);
3683             m_ListView.SetItemPosition(lvIndex, &apt[i]);
3684         }
3685     }
3686 
3687     return S_OK;
3688 }
3689 
3690 
3691 // IShellView2 implementation
3692 
3693 HRESULT STDMETHODCALLTYPE CDefView::GetView(SHELLVIEWID *view_guid, ULONG view_type)
3694 {
3695     FIXME("(%p)->(%p, %lu) stub\n", this, view_guid, view_type);
3696     return E_NOTIMPL;
3697 }
3698 
3699 HRESULT STDMETHODCALLTYPE CDefView::CreateViewWindow2(LPSV2CVW2_PARAMS view_params)
3700 {
3701     return CreateViewWindow3(view_params->psbOwner, view_params->psvPrev,
3702         SV3CVW3_DEFAULT, (FOLDERFLAGS)view_params->pfs->fFlags, (FOLDERFLAGS)view_params->pfs->fFlags,
3703         (FOLDERVIEWMODE)view_params->pfs->ViewMode, view_params->pvid, view_params->prcView, &view_params->hwndView);
3704 }
3705 
3706 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)
3707 {
3708     OLEMENUGROUPWIDTHS omw = { { 0, 0, 0, 0, 0, 0 } };
3709     const UINT SUPPORTED_SV3CVW3 = SV3CVW3_FORCEVIEWMODE | SV3CVW3_FORCEFOLDERFLAGS;
3710     const UINT IGNORE_FWF = FWF_OWNERDATA; // FIXME: Support this
3711 
3712     *hwnd = NULL;
3713 
3714     TRACE("(%p)->(shlview=%p shlbrs=%p rec=%p hwnd=%p vmode=%x flags=%x)\n", this, psvPrevious, psb, prcView, hwnd, mode, flags);
3715     if (prcView != NULL)
3716         TRACE("-- left=%i top=%i right=%i bottom=%i\n", prcView->left, prcView->top, prcView->right, prcView->bottom);
3717 
3718     /* Validate the Shell Browser */
3719     if (psb == NULL || m_hWnd)
3720         return E_UNEXPECTED;
3721 
3722     if (view_flags & ~SUPPORTED_SV3CVW3)
3723         FIXME("unsupported view flags 0x%08x\n", view_flags & ~SUPPORTED_SV3CVW3);
3724 
3725     if (mode == FVM_AUTO)
3726         mode = GetDefaultViewMode();
3727 
3728     /* Set up the member variables */
3729     m_pShellBrowser = psb;
3730     m_FolderSettings.ViewMode = mode;
3731     m_FolderSettings.fFlags = (mask & flags) & ~IGNORE_FWF;
3732 
3733     if (view_id)
3734     {
3735         if (IsEqualIID(*view_id, VID_LargeIcons))
3736             m_FolderSettings.ViewMode = FVM_ICON;
3737         else if (IsEqualIID(*view_id, VID_SmallIcons))
3738             m_FolderSettings.ViewMode = FVM_SMALLICON;
3739         else if (IsEqualIID(*view_id, VID_List))
3740             m_FolderSettings.ViewMode = FVM_LIST;
3741         else if (IsEqualIID(*view_id, VID_Details))
3742             m_FolderSettings.ViewMode = FVM_DETAILS;
3743         else if (IsEqualIID(*view_id, VID_Thumbnails))
3744             m_FolderSettings.ViewMode = FVM_THUMBNAIL;
3745         else if (IsEqualIID(*view_id, VID_Tile))
3746             m_FolderSettings.ViewMode = FVM_TILE;
3747         else if (IsEqualIID(*view_id, VID_ThumbStrip))
3748             m_FolderSettings.ViewMode = FVM_THUMBSTRIP;
3749         else
3750             FIXME("Ignoring unrecognized VID %s\n", debugstr_guid(view_id));
3751     }
3752     const UINT requestedViewMode = m_FolderSettings.ViewMode;
3753 
3754     /* Get our parent window */
3755     m_pShellBrowser->GetWindow(&m_hWndParent);
3756     _DoFolderViewCB(SFVM_HWNDMAIN, 0, (LPARAM)m_hWndParent);
3757 
3758     /* Try to get the ICommDlgBrowserInterface, adds a reference !!! */
3759     m_pCommDlgBrowser = NULL;
3760     if (SUCCEEDED(m_pShellBrowser->QueryInterface(IID_PPV_ARG(ICommDlgBrowser, &m_pCommDlgBrowser))))
3761     {
3762         TRACE("-- CommDlgBrowser\n");
3763     }
3764 
3765     LoadViewState();
3766     if (view_flags & SV3CVW3_FORCEVIEWMODE)
3767         m_FolderSettings.ViewMode = requestedViewMode;
3768     if (view_flags & SV3CVW3_FORCEFOLDERFLAGS)
3769         m_FolderSettings.fFlags = (mask & flags) & ~IGNORE_FWF;
3770 
3771     RECT rcView = *prcView;
3772     Create(m_hWndParent, rcView, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP, 0, 0U);
3773     if (m_hWnd == NULL)
3774         return E_FAIL;
3775 
3776     *hwnd = m_hWnd;
3777 
3778     CheckToolbar();
3779 
3780     if (!*hwnd)
3781         return E_FAIL;
3782 
3783     _DoFolderViewCB(SFVM_WINDOWCREATED, (WPARAM)m_hWnd, 0);
3784 
3785     SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
3786     UpdateWindow();
3787 
3788     if (!m_hMenu)
3789     {
3790         m_hMenu = CreateMenu();
3791         m_pShellBrowser->InsertMenusSB(m_hMenu, &omw);
3792         TRACE("-- after fnInsertMenusSB\n");
3793     }
3794 
3795     _MergeToolbar();
3796 
3797     return S_OK;
3798 }
3799 
3800 HRESULT STDMETHODCALLTYPE CDefView::HandleRename(LPCITEMIDLIST new_pidl)
3801 {
3802     FIXME("(%p)->(%p) stub\n", this, new_pidl);
3803     return E_NOTIMPL;
3804 }
3805 
3806 HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItem(LPCITEMIDLIST item, UINT flags, POINT *point)
3807 {
3808     FIXME("(%p)->(%p, %u, %p) stub\n", this, item, flags, point);
3809     return E_NOTIMPL;
3810 }
3811 
3812 // IShellFolderView implementation
3813 
3814 HRESULT STDMETHODCALLTYPE CDefView::Rearrange(LPARAM sort)
3815 {
3816     FIXME("(%p)->(%ld) stub\n", this, sort);
3817     return E_NOTIMPL;
3818 }
3819 
3820 HRESULT STDMETHODCALLTYPE CDefView::GetArrangeParam(LPARAM *sort)
3821 {
3822     FIXME("(%p)->(%p) stub\n", this, sort);
3823     return E_NOTIMPL;
3824 }
3825 
3826 HRESULT STDMETHODCALLTYPE CDefView::ArrangeGrid()
3827 {
3828     m_ListView.SetExtendedListViewStyle(LVS_EX_SNAPTOGRID, LVS_EX_SNAPTOGRID);
3829     return S_OK;
3830 }
3831 
3832 HRESULT STDMETHODCALLTYPE CDefView::AutoArrange()
3833 {
3834     m_ListView.ModifyStyle(0, LVS_AUTOARRANGE);
3835     m_ListView.Arrange(LVA_DEFAULT);
3836     return S_OK;
3837 }
3838 
3839 HRESULT STDMETHODCALLTYPE CDefView::AddObject(PITEMID_CHILD pidl, UINT *item)
3840 {
3841     TRACE("(%p)->(%p %p)\n", this, pidl, item);
3842     if (!m_ListView)
3843     {
3844         ERR("!m_ListView\n");
3845         return E_FAIL;
3846     }
3847     *item = LV_AddItem(pidl);
3848     return (int)*item >= 0 ? S_OK : E_OUTOFMEMORY;
3849 }
3850 
3851 HRESULT STDMETHODCALLTYPE CDefView::GetObject(PITEMID_CHILD *pidl, UINT item)
3852 {
3853     TRACE("(%p)->(%p %d)\n", this, pidl, item);
3854     return Item(item, pidl);
3855 }
3856 
3857 HRESULT STDMETHODCALLTYPE CDefView::RemoveObject(PITEMID_CHILD pidl, UINT *item)
3858 {
3859     TRACE("(%p)->(%p %p)\n", this, pidl, item);
3860 
3861     if (!m_ListView)
3862     {
3863         ERR("!m_ListView\n");
3864         return E_FAIL;
3865     }
3866 
3867     if (pidl)
3868     {
3869         *item = LV_FindItemByPidl(ILFindLastID(pidl));
3870         m_ListView.DeleteItem(*item);
3871     }
3872     else
3873     {
3874         *item = 0;
3875         m_ListView.DeleteAllItems();
3876     }
3877 
3878     return S_OK;
3879 }
3880 
3881 HRESULT STDMETHODCALLTYPE CDefView::GetObjectCount(UINT *count)
3882 {
3883     TRACE("(%p)->(%p)\n", this, count);
3884     *count = m_ListView.GetItemCount();
3885     return S_OK;
3886 }
3887 
3888 HRESULT STDMETHODCALLTYPE CDefView::SetObjectCount(UINT count, UINT flags)
3889 {
3890     FIXME("(%p)->(%d %x) stub\n", this, count, flags);
3891     return E_NOTIMPL;
3892 }
3893 
3894 HRESULT STDMETHODCALLTYPE CDefView::UpdateObject(PITEMID_CHILD pidl_old, PITEMID_CHILD pidl_new, UINT *item)
3895 {
3896     FIXME("(%p)->(%p %p %p) stub\n", this, pidl_old, pidl_new, item);
3897     return E_NOTIMPL;
3898 }
3899 
3900 HRESULT STDMETHODCALLTYPE CDefView::RefreshObject(PITEMID_CHILD pidl, UINT *item)
3901 {
3902     FIXME("(%p)->(%p %p) stub\n", this, pidl, item);
3903     return E_NOTIMPL;
3904 }
3905 
3906 HRESULT STDMETHODCALLTYPE CDefView::SetRedraw(BOOL redraw)
3907 {
3908     TRACE("(%p)->(%d)\n", this, redraw);
3909     if (m_ListView)
3910         m_ListView.SetRedraw(redraw);
3911     return S_OK;
3912 }
3913 
3914 HRESULT STDMETHODCALLTYPE CDefView::GetSelectedCount(UINT *count)
3915 {
3916     FIXME("(%p)->(%p) stub\n", this, count);
3917     return E_NOTIMPL;
3918 }
3919 
3920 HRESULT STDMETHODCALLTYPE CDefView::GetSelectedObjects(PCUITEMID_CHILD **pidl, UINT *items)
3921 {
3922     TRACE("(%p)->(%p %p)\n", this, pidl, items);
3923 
3924     *items = GetSelections();
3925 
3926     if (*items)
3927     {
3928         *pidl = static_cast<PCUITEMID_CHILD *>(LocalAlloc(0, *items * sizeof(PCUITEMID_CHILD)));
3929         if (!*pidl)
3930         {
3931             return E_OUTOFMEMORY;
3932         }
3933 
3934         /* it's documented that caller shouldn't PIDLs, only array itself */
3935         memcpy(*pidl, m_apidl, *items * sizeof(PCUITEMID_CHILD));
3936     }
3937 
3938     return S_OK;
3939 }
3940 
3941 HRESULT STDMETHODCALLTYPE CDefView::IsDropOnSource(IDropTarget *drop_target)
3942 {
3943     if ((m_iDragOverItem == -1 || m_pCurDropTarget == NULL) &&
3944         (m_pSourceDataObject.p))
3945     {
3946         return S_OK;
3947     }
3948 
3949     return S_FALSE;
3950 }
3951 
3952 HRESULT STDMETHODCALLTYPE CDefView::GetDragPoint(POINT *pt)
3953 {
3954     if (!pt)
3955         return E_INVALIDARG;
3956 
3957     *pt = m_ptFirstMousePos;
3958     return S_OK;
3959 }
3960 
3961 HRESULT STDMETHODCALLTYPE CDefView::GetDropPoint(POINT *pt)
3962 {
3963     FIXME("(%p)->(%p) stub\n", this, pt);
3964     return E_NOTIMPL;
3965 }
3966 
3967 HRESULT STDMETHODCALLTYPE CDefView::MoveIcons(IDataObject *obj)
3968 {
3969     TRACE("(%p)->(%p)\n", this, obj);
3970     return E_NOTIMPL;
3971 }
3972 
3973 HRESULT STDMETHODCALLTYPE CDefView::SetItemPos(PCUITEMID_CHILD pidl, POINT *pt)
3974 {
3975     FIXME("(%p)->(%p %p) stub\n", this, pidl, pt);
3976     return E_NOTIMPL;
3977 }
3978 
3979 HRESULT STDMETHODCALLTYPE CDefView::IsBkDropTarget(IDropTarget *drop_target)
3980 {
3981     FIXME("(%p)->(%p) stub\n", this, drop_target);
3982     return E_NOTIMPL;
3983 }
3984 
3985 HRESULT STDMETHODCALLTYPE CDefView::SetClipboard(BOOL move)
3986 {
3987     FIXME("(%p)->(%d) stub\n", this, move);
3988     return E_NOTIMPL;
3989 }
3990 
3991 HRESULT STDMETHODCALLTYPE CDefView::SetPoints(IDataObject *obj)
3992 {
3993     FIXME("(%p)->(%p) stub\n", this, obj);
3994     return E_NOTIMPL;
3995 }
3996 
3997 HRESULT STDMETHODCALLTYPE CDefView::GetItemSpacing(ITEMSPACING *spacing)
3998 {
3999     FIXME("(%p)->(%p) stub\n", this, spacing);
4000     return E_NOTIMPL;
4001 }
4002 
4003 HRESULT STDMETHODCALLTYPE CDefView::SetCallback(IShellFolderViewCB  *new_cb, IShellFolderViewCB **old_cb)
4004 {
4005     if (old_cb)
4006         *old_cb = m_pShellFolderViewCB.Detach();
4007 
4008     m_pShellFolderViewCB = new_cb;
4009     m_pFolderFilter = NULL;
4010     if (new_cb)
4011         new_cb->QueryInterface(IID_PPV_ARG(IFolderFilter, &m_pFolderFilter));
4012     return S_OK;
4013 }
4014 
4015 HRESULT STDMETHODCALLTYPE CDefView::Select(UINT flags)
4016 {
4017     FIXME("(%p)->(%d) stub\n", this, flags);
4018     return E_NOTIMPL;
4019 }
4020 
4021 HRESULT STDMETHODCALLTYPE CDefView::QuerySupport(UINT *support)
4022 {
4023     TRACE("(%p)->(%p)\n", this, support);
4024     return S_OK;
4025 }
4026 
4027 HRESULT STDMETHODCALLTYPE CDefView::SetAutomationObject(IDispatch *disp)
4028 {
4029     FIXME("(%p)->(%p) stub\n", this, disp);
4030     return E_NOTIMPL;
4031 }
4032 
4033 HRESULT WINAPI CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText)
4034 {
4035     FIXME("(%p)->(%p(%s) 0x%08x %p %p\n",
4036           this, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
4037 
4038     if (!prgCmds)
4039         return E_INVALIDARG;
4040 
4041     for (UINT i = 0; i < cCmds; i++)
4042     {
4043         FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID);
4044         prgCmds[i].cmdf = 0;
4045     }
4046 
4047     return OLECMDERR_E_UNKNOWNGROUP;
4048 }
4049 
4050 ///
4051 // ISVOleCmdTarget_Exec(IOleCommandTarget)
4052 //
4053 // nCmdID is the OLECMDID_* enumeration
4054 HRESULT WINAPI CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
4055 {
4056     FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n",
4057           this, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut);
4058 
4059     if (!pguidCmdGroup)
4060         return OLECMDERR_E_UNKNOWNGROUP;
4061 
4062     if (IsEqualCLSID(*pguidCmdGroup, m_Category))
4063     {
4064         if (nCmdID == FCIDM_SHVIEW_AUTOARRANGE)
4065         {
4066             if (V_VT(pvaIn) != VT_INT_PTR)
4067                 return OLECMDERR_E_NOTSUPPORTED;
4068 
4069             TPMPARAMS params;
4070             params.cbSize = sizeof(params);
4071             params.rcExclude = *(RECT*) V_INTREF(pvaIn);
4072 
4073             if (m_hMenuViewModes)
4074             {
4075                 // Duplicate all but the last two items of the view modes menu
4076                 HMENU hmenuViewPopup = CreatePopupMenu();
4077                 Shell_MergeMenus(hmenuViewPopup, m_hMenuViewModes, 0, 0, 0xFFFF, 0);
4078                 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION);
4079                 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION);
4080                 CheckViewMode(hmenuViewPopup);
4081                 TrackPopupMenuEx(hmenuViewPopup, TPM_LEFTALIGN | TPM_TOPALIGN, params.rcExclude.left, params.rcExclude.bottom, m_hWndParent, &params);
4082                 ::DestroyMenu(hmenuViewPopup);
4083             }
4084 
4085             // pvaOut is VT_I4 with value 0x403 (cmd id of the new mode maybe?)
4086             V_VT(pvaOut) = VT_I4;
4087             V_I4(pvaOut) = 0x403;
4088         }
4089     }
4090 
4091     if (IsEqualIID(*pguidCmdGroup, CGID_Explorer) &&
4092             (nCmdID == 0x29) &&
4093             (nCmdexecopt == 4) && pvaOut)
4094         return S_OK;
4095 
4096     if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView) &&
4097             (nCmdID == 9) &&
4098             (nCmdexecopt == 0))
4099         return 1;
4100 
4101     if (IsEqualIID(*pguidCmdGroup, CGID_DefView))
4102     {
4103         CComPtr<IStream> pStream;
4104         WCHAR SubKey[MAX_PATH];
4105         switch (nCmdID)
4106         {
4107             case DVCMDID_SET_DEFAULTFOLDER_SETTINGS:
4108                 SHDeleteKey(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\ShellNoRoam\\Bags");
4109                 if (SUCCEEDED(GetDefaultViewStream(STGM_WRITE, &pStream)))
4110                     SaveViewState(pStream);
4111                 break;
4112             case DVCMDID_RESET_DEFAULTFOLDER_SETTINGS:
4113                 wsprintfW(SubKey, L"%s\\%s", REGSTR_PATH_EXPLORER, L"Streams\\Default");
4114                 SHDeleteKey(HKEY_CURRENT_USER, SubKey);
4115                 SHDeleteKey(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\ShellNoRoam\\Bags");
4116                 m_FolderSettings.fFlags |= FWF_NOBROWSERVIEWSTATE; // Don't let this folder save itself
4117                 break;
4118         }
4119     }
4120 
4121     return OLECMDERR_E_UNKNOWNGROUP;
4122 }
4123 
4124 /**********************************************************
4125  * ISVDropTarget implementation
4126  */
4127 
4128 /******************************************************************************
4129  * drag_notify_subitem [Internal]
4130  *
4131  * Figure out the shellfolder object, which is currently under the mouse cursor
4132  * and notify it via the IDropTarget interface.
4133  */
4134 
4135 #define SCROLLAREAWIDTH 20
4136 
4137 HRESULT CDefView::drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
4138 {
4139     LONG lResult;
4140     HRESULT hr;
4141     RECT clientRect;
4142 
4143     /* The key state on drop doesn't have MK_LBUTTON or MK_RBUTTON because it
4144        reflects the key state after the user released the button, so we need
4145        to remember the last key state when the button was pressed */
4146     m_grfKeyState = grfKeyState;
4147 
4148     // Map from global to client coordinates and query the index of the
4149     // listview-item, which is currently under the mouse cursor.
4150     LVHITTESTINFO htinfo = {{pt.x, pt.y}, LVHT_ONITEM};
4151     ScreenToClient(&htinfo.pt);
4152     lResult = m_ListView.HitTest(&htinfo);
4153 
4154     /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */
4155     ::GetClientRect(m_ListView, &clientRect);
4156     if (htinfo.pt.x == m_ptLastMousePos.x && htinfo.pt.y == m_ptLastMousePos.y &&
4157             (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH ||
4158              htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH))
4159     {
4160         m_cScrollDelay = (m_cScrollDelay + 1) % 5; // DragOver is called every 50 ms
4161         if (m_cScrollDelay == 0)
4162         {
4163             /* Mouse did hover another 250 ms over the scroll-area */
4164             if (htinfo.pt.x < SCROLLAREAWIDTH)
4165                 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEUP, 0);
4166 
4167             if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH)
4168                 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEDOWN, 0);
4169 
4170             if (htinfo.pt.y < SCROLLAREAWIDTH)
4171                 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEUP, 0);
4172 
4173             if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH)
4174                 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEDOWN, 0);
4175         }
4176     }
4177     else
4178     {
4179         m_cScrollDelay = 0; // Reset, if cursor is not over the listview's scroll-area
4180     }
4181 
4182     m_ptLastMousePos = htinfo.pt;
4183     ::ClientToListView(m_ListView, &m_ptLastMousePos);
4184 
4185     /* We need to check if we drag the selection over itself */
4186     if (lResult != -1 && m_pSourceDataObject.p != NULL)
4187     {
4188         PCUITEMID_CHILD pidl = _PidlByItem(lResult);
4189 
4190         for (UINT i = 0; i < m_cidl; i++)
4191         {
4192             if (pidl == m_apidl[i])
4193             {
4194                 /* The item that is being draged is hovering itself. */
4195                 lResult = -1;
4196                 break;
4197             }
4198         }
4199     }
4200 
4201     // If we are still over the previous sub-item, notify it via DragOver and return
4202     if (m_pCurDropTarget && lResult == m_iDragOverItem)
4203         return m_pCurDropTarget->DragOver(grfKeyState, pt, pdwEffect);
4204 
4205     // We've left the previous sub-item, notify it via DragLeave and release it
4206     if (m_pCurDropTarget)
4207     {
4208         PCUITEMID_CHILD pidl = _PidlByItem(m_iDragOverItem);
4209         if (pidl)
4210             SelectItem(pidl, 0);
4211 
4212         m_pCurDropTarget->DragLeave();
4213         m_pCurDropTarget.Release();
4214     }
4215 
4216     m_iDragOverItem = lResult;
4217 
4218     if (lResult == -1)
4219     {
4220         // We are not above one of the listview's subitems. Bind to the
4221         // parent folder's DropTarget interface.
4222         hr = m_pSFParent->CreateViewObject(NULL, IID_PPV_ARG(IDropTarget,&m_pCurDropTarget));
4223     }
4224     else
4225     {
4226         // Query the relative PIDL of the shellfolder object represented
4227         // by the currently dragged over listview-item ...
4228         PCUITEMID_CHILD pidl = _PidlByItem(lResult);
4229 
4230         // ... and bind m_pCurDropTarget to the IDropTarget interface of an UIObject of this object
4231         hr = m_pSFParent->GetUIObjectOf(m_ListView, 1, &pidl, IID_NULL_PPV_ARG(IDropTarget, &m_pCurDropTarget));
4232     }
4233 
4234     IUnknown_SetSite(m_pCurDropTarget, (IShellView *)this);
4235 
4236     // If anything failed, m_pCurDropTarget should be NULL now, which ought to be a save state
4237     if (FAILED(hr))
4238     {
4239         *pdwEffect = DROPEFFECT_NONE;
4240         return hr;
4241     }
4242 
4243     if (m_iDragOverItem != -1)
4244     {
4245         SelectItem(m_iDragOverItem, SVSI_SELECT);
4246     }
4247 
4248     // Notify the item just entered via DragEnter
4249     return m_pCurDropTarget->DragEnter(m_pCurDataObject, grfKeyState, pt, pdwEffect);
4250 }
4251 
4252 HRESULT WINAPI CDefView::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
4253 {
4254     if (*pdwEffect == DROPEFFECT_NONE)
4255         return S_OK;
4256 
4257     /* Get a hold on the data object for later calls to DragEnter on the sub-folders */
4258     m_pCurDataObject = pDataObject;
4259 
4260     HRESULT hr = drag_notify_subitem(grfKeyState, pt, pdwEffect);
4261     if (SUCCEEDED(hr))
4262     {
4263         POINT ptClient = {pt.x, pt.y};
4264         ScreenToClient(&ptClient);
4265         ImageList_DragEnter(m_hWnd, ptClient.x, ptClient.y);
4266     }
4267 
4268     return hr;
4269 }
4270 
4271 HRESULT WINAPI CDefView::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
4272 {
4273     POINT ptClient = {pt.x, pt.y};
4274     ScreenToClient(&ptClient);
4275     ImageList_DragMove(ptClient.x, ptClient.y);
4276     return drag_notify_subitem(grfKeyState, pt, pdwEffect);
4277 }
4278 
4279 HRESULT WINAPI CDefView::DragLeave()
4280 {
4281     ImageList_DragLeave(m_hWnd);
4282 
4283     if (m_pCurDropTarget)
4284     {
4285         m_pCurDropTarget->DragLeave();
4286         m_pCurDropTarget.Release();
4287     }
4288 
4289     if (m_pCurDataObject != NULL)
4290     {
4291         m_pCurDataObject.Release();
4292     }
4293 
4294     m_iDragOverItem = 0;
4295 
4296     return S_OK;
4297 }
4298 
4299 INT CDefView::_FindInsertableIndexFromPoint(POINT pt)
4300 {
4301     RECT rcBound;
4302     INT i, nCount = m_ListView.GetItemCount();
4303     DWORD dwSpacing;
4304     INT dx, dy;
4305     BOOL bSmall = ((m_ListView.GetStyle() & LVS_TYPEMASK) != LVS_ICON);
4306 
4307     // FIXME: LVM_GETORIGIN is broken. See CORE-17266
4308     pt.x += m_ListView.GetScrollPos(SB_HORZ);
4309     pt.y += m_ListView.GetScrollPos(SB_VERT);
4310 
4311     if (m_ListView.GetStyle() & LVS_ALIGNLEFT)
4312     {
4313         // vertically
4314         for (i = 0; i < nCount; ++i)
4315         {
4316             dwSpacing = ListView_GetItemSpacing(m_ListView, bSmall);
4317             dx = LOWORD(dwSpacing);
4318             dy = HIWORD(dwSpacing);
4319             ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS);
4320             rcBound.right = rcBound.left + dx;
4321             rcBound.bottom = rcBound.top + dy;
4322             if (pt.x < rcBound.right && pt.y < (rcBound.top + rcBound.bottom) / 2)
4323             {
4324                 return i;
4325             }
4326         }
4327         for (i = nCount - 1; i >= 0; --i)
4328         {
4329             ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS);
4330             if (rcBound.left < pt.x && rcBound.top < pt.y)
4331             {
4332                 return i + 1;
4333             }
4334         }
4335     }
4336     else
4337     {
4338         // horizontally
4339         for (i = 0; i < nCount; ++i)
4340         {
4341             dwSpacing = ListView_GetItemSpacing(m_ListView, bSmall);
4342             dx = LOWORD(dwSpacing);
4343             dy = HIWORD(dwSpacing);
4344             ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS);
4345             rcBound.right = rcBound.left + dx;
4346             rcBound.bottom = rcBound.top + dy;
4347             if (pt.y < rcBound.bottom && pt.x < rcBound.left)
4348             {
4349                 return i;
4350             }
4351             if (pt.y < rcBound.bottom && pt.x < rcBound.right)
4352             {
4353                 return i + 1;
4354             }
4355         }
4356         for (i = nCount - 1; i >= 0; --i)
4357         {
4358             ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS);
4359             if (rcBound.left < pt.x && rcBound.top < pt.y)
4360             {
4361                 return i + 1;
4362             }
4363         }
4364     }
4365 
4366     return nCount;
4367 }
4368 
4369 void CDefView::_HandleStatusBarResize(int nWidth)
4370 {
4371     LRESULT lResult;
4372 
4373     if (m_isParentFolderSpecial)
4374     {
4375         int nPartArray[] = {-1};
4376         m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, _countof(nPartArray), (LPARAM)nPartArray, &lResult);
4377         return;
4378     }
4379 
4380     int nFileSizePartLength = 125;
4381     const int nLocationPartLength = 150;
4382     const int nRightPartsLength = nFileSizePartLength + nLocationPartLength;
4383     int nObjectsPartLength = nWidth - nRightPartsLength;
4384 
4385     // If the window is small enough just divide each part into thirds
4386     // to match the behavior of Windows Server 2003
4387     if (nObjectsPartLength <= nLocationPartLength)
4388         nObjectsPartLength = nFileSizePartLength = nWidth / 3;
4389 
4390     int nPartArray[] = {nObjectsPartLength, nObjectsPartLength + nFileSizePartLength, -1};
4391 
4392     m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, _countof(nPartArray), (LPARAM)nPartArray, &lResult);
4393 }
4394 
4395 void CDefView::_ForceStatusBarResize()
4396 {
4397     // Get the handle for the status bar
4398     HWND fStatusBar;
4399     m_pShellBrowser->GetControlWindow(FCW_STATUS, &fStatusBar);
4400 
4401     // Get the size of our status bar
4402     RECT statusBarSize;
4403     ::GetWindowRect(fStatusBar, &statusBarSize);
4404 
4405     // Resize the status bar
4406     _HandleStatusBarResize(statusBarSize.right - statusBarSize.left);
4407 }
4408 
4409 typedef CSimpleMap<LPARAM, INT> CLParamIndexMap;
4410 
4411 static INT CALLBACK
4412 SelectionMoveCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
4413 {
4414     CLParamIndexMap *pmap = (CLParamIndexMap *)lParamSort;
4415     INT i1 = pmap->Lookup(lParam1), i2 = pmap->Lookup(lParam2);
4416     if (i1 < i2)
4417         return -1;
4418     if (i1 > i2)
4419         return 1;
4420     return 0;
4421 }
4422 
4423 void CDefView::_MoveSelectionOnAutoArrange(POINT pt)
4424 {
4425     // get insertable index from position
4426     INT iPosition = _FindInsertableIndexFromPoint(pt);
4427 
4428     // create identity mapping of indexes
4429     CSimpleArray<INT> array;
4430     INT nCount = m_ListView.GetItemCount();
4431     for (INT i = 0; i < nCount; ++i)
4432     {
4433         array.Add(i);
4434     }
4435 
4436     // re-ordering mapping
4437     INT iItem = -1;
4438     while ((iItem = m_ListView.GetNextItem(iItem, LVNI_SELECTED)) >= 0)
4439     {
4440         INT iFrom = iItem, iTo = iPosition;
4441         if (iFrom < iTo)
4442             --iTo;
4443         if (iFrom >= nCount)
4444             iFrom = nCount - 1;
4445         if (iTo >= nCount)
4446             iTo = nCount - 1;
4447 
4448         // shift indexes by swapping (like a bucket relay)
4449         if (iFrom < iTo)
4450         {
4451             for (INT i = iFrom; i < iTo; ++i)
4452             {
4453                 // swap array[i] and array[i + 1]
4454                 INT tmp = array[i];
4455                 array[i] = array[i + 1];
4456                 array[i + 1] = tmp;
4457             }
4458         }
4459         else
4460         {
4461             for (INT i = iFrom; i > iTo; --i)
4462             {
4463                 // swap array[i] and array[i - 1]
4464                 INT tmp = array[i];
4465                 array[i] = array[i - 1];
4466                 array[i - 1] = tmp;
4467             }
4468         }
4469     }
4470 
4471     // create mapping (ListView's lParam to index) from array
4472     CLParamIndexMap map;
4473     for (INT i = 0; i < nCount; ++i)
4474     {
4475         LPARAM lParam = m_ListView.GetItemData(array[i]);
4476         map.Add(lParam, i);
4477     }
4478 
4479     // finally sort
4480     m_ListView.SortItems(SelectionMoveCompareFunc, &map);
4481 }
4482 
4483 HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
4484 {
4485     ImageList_DragLeave(m_hWnd);
4486     ImageList_EndDrag();
4487 
4488     if ((IsDropOnSource(NULL) == S_OK) &&
4489         (*pdwEffect & DROPEFFECT_MOVE) &&
4490         (m_grfKeyState & MK_LBUTTON))
4491     {
4492         if (m_pCurDropTarget)
4493         {
4494             m_pCurDropTarget->DragLeave();
4495             m_pCurDropTarget.Release();
4496         }
4497 
4498         POINT ptDrop = { pt.x, pt.y };
4499         ::ScreenToClient(m_ListView, &ptDrop);
4500         ::ClientToListView(m_ListView, &ptDrop);
4501         m_ptLastMousePos = ptDrop;
4502 
4503         m_ListView.SetRedraw(FALSE);
4504         if (m_ListView.GetStyle() & LVS_AUTOARRANGE)
4505         {
4506             _MoveSelectionOnAutoArrange(m_ptLastMousePos);
4507         }
4508         else
4509         {
4510             POINT ptItem;
4511             INT iItem = -1;
4512             while ((iItem = m_ListView.GetNextItem(iItem, LVNI_SELECTED)) >= 0)
4513             {
4514                 if (m_ListView.GetItemPosition(iItem, &ptItem))
4515                 {
4516                     ptItem.x += m_ptLastMousePos.x - m_ptFirstMousePos.x;
4517                     ptItem.y += m_ptLastMousePos.y - m_ptFirstMousePos.y;
4518                     m_ListView.SetItemPosition(iItem, &ptItem);
4519                 }
4520             }
4521         }
4522         m_ListView.SetRedraw(TRUE);
4523     }
4524     else if (m_pCurDropTarget)
4525     {
4526         m_pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect);
4527         m_pCurDropTarget.Release();
4528     }
4529 
4530     m_pCurDataObject.Release();
4531     m_iDragOverItem = 0;
4532     return S_OK;
4533 }
4534 
4535 HRESULT WINAPI CDefView::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
4536 {
4537     TRACE("(%p)\n", this);
4538 
4539     if (fEscapePressed)
4540         return DRAGDROP_S_CANCEL;
4541     else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON))
4542         return DRAGDROP_S_DROP;
4543     else
4544         return S_OK;
4545 }
4546 
4547 HRESULT WINAPI CDefView::GiveFeedback(DWORD dwEffect)
4548 {
4549     TRACE("(%p)\n", this);
4550 
4551     return DRAGDROP_S_USEDEFAULTCURSORS;
4552 }
4553 
4554 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)
4555 {
4556     FIXME("Stub: this=%p\n", this);
4557     return E_NOTIMPL;
4558 }
4559 
4560 HRESULT WINAPI CDefView::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet)
4561 {
4562     FIXME("Stub: this=%p\n", this);
4563     return E_NOTIMPL;
4564 }
4565 
4566 HRESULT WINAPI CDefView::Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze)
4567 {
4568     FIXME("Stub: this=%p\n", this);
4569     return E_NOTIMPL;
4570 }
4571 
4572 HRESULT WINAPI CDefView::Unfreeze(DWORD dwFreeze)
4573 {
4574     FIXME("Stub: this=%p\n", this);
4575     return E_NOTIMPL;
4576 }
4577 
4578 HRESULT WINAPI CDefView::SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink)
4579 {
4580     FIXME("partial stub: %p 0x%08x 0x%08x %p\n", this, aspects, advf, pAdvSink);
4581 
4582     // FIXME: we set the AdviseSink, but never use it to send any advice
4583     m_pAdvSink = pAdvSink;
4584     m_dwAspects = aspects;
4585     m_dwAdvf = advf;
4586 
4587     return S_OK;
4588 }
4589 
4590 HRESULT WINAPI CDefView::GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink)
4591 {
4592     TRACE("this=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n", this, pAspects, pAdvf, ppAdvSink);
4593 
4594     if (ppAdvSink)
4595     {
4596         *ppAdvSink = m_pAdvSink;
4597         m_pAdvSink.p->AddRef();
4598     }
4599 
4600     if (pAspects)
4601         *pAspects = m_dwAspects;
4602 
4603     if (pAdvf)
4604         *pAdvf = m_dwAdvf;
4605 
4606     return S_OK;
4607 }
4608 
4609 HRESULT STDMETHODCALLTYPE CDefView::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
4610 {
4611     if (IsEqualIID(guidService, SID_IShellBrowser))
4612         return m_pShellBrowser->QueryInterface(riid, ppvObject);
4613     else if(IsEqualIID(guidService, SID_IFolderView))
4614         return QueryInterface(riid, ppvObject);
4615 
4616     return E_NOINTERFACE;
4617 }
4618 
4619 HRESULT CDefView::_MergeToolbar()
4620 {
4621     CComPtr<IExplorerToolbar> ptb;
4622     HRESULT hr = S_OK;
4623 
4624     hr = IUnknown_QueryService(m_pShellBrowser, IID_IExplorerToolbar, IID_PPV_ARG(IExplorerToolbar, &ptb));
4625     if (FAILED(hr))
4626         return hr;
4627 
4628     m_Category = CGID_DefViewFrame;
4629 
4630     hr = ptb->SetCommandTarget(static_cast<IOleCommandTarget*>(this), &m_Category, 0);
4631     if (FAILED(hr))
4632         return hr;
4633 
4634     if (hr == S_FALSE)
4635         return S_OK;
4636 
4637 #if 0
4638     hr = ptb->AddButtons(&m_Category, buttonsCount, buttons);
4639     if (FAILED(hr))
4640         return hr;
4641 #endif
4642 
4643     return S_OK;
4644 }
4645 
4646 HRESULT CDefView::_DoFolderViewCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
4647 {
4648     HRESULT hr = E_NOTIMPL;
4649 
4650     if (m_pShellFolderViewCB)
4651     {
4652         hr = m_pShellFolderViewCB->MessageSFVCB(uMsg, wParam, lParam);
4653     }
4654 
4655     return hr;
4656 }
4657 
4658 HRESULT CDefView_CreateInstance(IShellFolder *pFolder, REFIID riid, LPVOID * ppvOut)
4659 {
4660     return ShellObjectCreatorInit<CDefView>(pFolder, riid, ppvOut);
4661 }
4662 
4663 HRESULT WINAPI SHCreateShellFolderView(const SFV_CREATE *pcsfv,
4664     IShellView **ppsv)
4665 {
4666     CComPtr<IShellView> psv;
4667     HRESULT hRes;
4668 
4669     if (!ppsv)
4670         return E_INVALIDARG;
4671 
4672     *ppsv = NULL;
4673 
4674     if (!pcsfv || pcsfv->cbSize != sizeof(*pcsfv))
4675         return E_INVALIDARG;
4676 
4677     TRACE("sf=%p outer=%p callback=%p\n",
4678       pcsfv->pshf, pcsfv->psvOuter, pcsfv->psfvcb);
4679 
4680     hRes = CDefView_CreateInstance(pcsfv->pshf, IID_PPV_ARG(IShellView, &psv));
4681     if (FAILED(hRes))
4682         return hRes;
4683 
4684     if (pcsfv->psfvcb)
4685     {
4686         CComPtr<IShellFolderView> sfv;
4687         if (SUCCEEDED(psv->QueryInterface(IID_PPV_ARG(IShellFolderView, &sfv))))
4688         {
4689             sfv->SetCallback(pcsfv->psfvcb, NULL);
4690         }
4691     }
4692 
4693     *ppsv = psv.Detach();
4694     return hRes;
4695 }
4696