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