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