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