xref: /reactos/dll/win32/shell32/CDefView.cpp (revision 4572aad1)
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 OnNCDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
312         LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
313         LRESULT OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
314         LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
315         LRESULT OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
316         LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
317         LRESULT OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
318         LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
319         LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
320         LRESULT OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
321         LRESULT OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
322         LRESULT OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
323         LRESULT OnInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
324 
325         static ATL::CWndClassInfo& GetWndClassInfo()
326         {
327             static ATL::CWndClassInfo wc =
328             {
329                 {   sizeof(WNDCLASSEX), CS_PARENTDC, StartWindowProc,
330                     0, 0, NULL, NULL,
331                     LoadCursor(NULL, IDC_ARROW), NULL, NULL, L"SHELLDLL_DefView", NULL
332                 },
333                 NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
334             };
335             return wc;
336         }
337 
338         virtual WNDPROC GetWindowProc()
339         {
340             return WindowProc;
341         }
342 
343         static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
344         {
345             CDefView *pThis;
346             LRESULT  result;
347 
348             // Must hold a reference during message handling
349             pThis = reinterpret_cast<CDefView *>(hWnd);
350             pThis->AddRef();
351             result = CWindowImpl<CDefView, CWindow, CControlWinTraits>::WindowProc(hWnd, uMsg, wParam, lParam);
352             pThis->Release();
353             return result;
354         }
355 
356         BEGIN_MSG_MAP(CDefView)
357         MESSAGE_HANDLER(WM_SIZE, OnSize)
358         MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
359         MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)
360         MESSAGE_HANDLER(WM_NCCREATE, OnNCCreate)
361         MESSAGE_HANDLER(WM_NCDESTROY, OnNCDestroy)
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     return reinterpret_cast<PCUITEMID_CHILD>(m_ListView.GetItemData(i));
871 }
872 
873 PCUITEMID_CHILD CDefView::_PidlByItem(LVITEM& lvItem)
874 {
875     return reinterpret_cast<PCUITEMID_CHILD>(lvItem.lParam);
876 }
877 
878 /**********************************************************
879 *  LV_FindItemByPidl()
880 */
881 int CDefView::LV_FindItemByPidl(PCUITEMID_CHILD pidl)
882 {
883     int cItems = m_ListView.GetItemCount();
884 
885     for (int i = 0; i<cItems; i++)
886     {
887         PCUITEMID_CHILD currentpidl = _PidlByItem(i);
888         if (ILIsEqual(pidl, currentpidl))
889             return i;
890     }
891     return -1;
892 }
893 
894 /**********************************************************
895 * LV_AddItem()
896 */
897 int CDefView::LV_AddItem(PCUITEMID_CHILD pidl)
898 {
899     LVITEMW lvItem;
900 
901     TRACE("(%p)(pidl=%p)\n", this, pidl);
902 
903     if (_DoFolderViewCB(SFVM_ADDINGOBJECT, 0, (LPARAM)pidl) == S_FALSE)
904         return -1;
905 
906     lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;    /*set the mask*/
907     lvItem.iItem = m_ListView.GetItemCount();             /*add the item to the end of the list*/
908     lvItem.iSubItem = 0;
909     lvItem.lParam = reinterpret_cast<LPARAM>(ILClone(pidl)); /*set the item's data*/
910     lvItem.pszText = LPSTR_TEXTCALLBACKW;                 /*get text on a callback basis*/
911     lvItem.iImage = I_IMAGECALLBACK;                      /*get the image on a callback basis*/
912     lvItem.stateMask = LVIS_CUT;
913 
914     return m_ListView.InsertItem(&lvItem);
915 }
916 
917 /**********************************************************
918 * LV_DeleteItem()
919 */
920 BOOLEAN CDefView::LV_DeleteItem(PCUITEMID_CHILD pidl)
921 {
922     int nIndex;
923 
924     TRACE("(%p)(pidl=%p)\n", this, pidl);
925 
926     nIndex = LV_FindItemByPidl(pidl);
927 
928     return m_ListView.DeleteItem(nIndex);
929 }
930 
931 /**********************************************************
932 * LV_RenameItem()
933 */
934 BOOLEAN CDefView::LV_RenameItem(PCUITEMID_CHILD pidlOld, PCUITEMID_CHILD pidlNew)
935 {
936     int nItem;
937     LVITEMW lvItem;
938 
939     TRACE("(%p)(pidlold=%p pidlnew=%p)\n", this, pidlOld, pidlNew);
940 
941     nItem = LV_FindItemByPidl(pidlOld);
942 
943     if ( -1 != nItem )
944     {
945         lvItem.mask = LVIF_PARAM;        /* only the pidl */
946         lvItem.iItem = nItem;
947         lvItem.iSubItem = 0;
948         m_ListView.GetItem(&lvItem);
949 
950         LPVOID oldPidl = reinterpret_cast<LPVOID>(lvItem.lParam);   /* Store the old pidl until the new item is replaced */
951 
952         lvItem.mask = LVIF_PARAM | LVIF_IMAGE | LVIF_TEXT;
953         lvItem.iItem = nItem;
954         lvItem.iSubItem = 0;
955         lvItem.lParam = reinterpret_cast<LPARAM>(ILClone(pidlNew));    /* set the item's data */
956         lvItem.pszText = LPSTR_TEXTCALLBACKW;
957         lvItem.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidlNew, 0);
958         m_ListView.SetItem(&lvItem);
959         m_ListView.Update(nItem);
960 
961         SHFree(oldPidl);                /* Now that the new item is in place, we can safely release the old pidl */
962 
963         return TRUE;                    /* FIXME: better handling */
964     }
965 
966     return FALSE;
967 }
968 
969 /**********************************************************
970 * LV_ProdItem()
971 */
972 BOOLEAN CDefView::LV_ProdItem(PCUITEMID_CHILD pidl)
973 {
974     int nItem;
975     LVITEMW lvItem;
976 
977     TRACE("(%p)(pidl=%p)\n", this, pidl);
978 
979     nItem = LV_FindItemByPidl(pidl);
980 
981     if (-1 != nItem)
982     {
983         lvItem.mask = LVIF_IMAGE;
984         lvItem.iItem = nItem;
985         lvItem.iSubItem = 0;
986         lvItem.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
987         m_ListView.SetItem(&lvItem);
988         m_ListView.Update(nItem);
989         return TRUE;
990     }
991 
992     return FALSE;
993 }
994 
995 /**********************************************************
996 * ShellView_FillList()
997 *
998 * - gets the objectlist from the shellfolder
999 * - sorts the list
1000 * - fills the list into the view
1001 */
1002 INT CALLBACK CDefView::fill_list(LPVOID ptr, LPVOID arg)
1003 {
1004     PITEMID_CHILD pidl = static_cast<PITEMID_CHILD>(ptr);
1005     CDefView *pThis = static_cast<CDefView *>(arg);
1006 
1007     /* in a commdlg This works as a filemask*/
1008     if (pThis->IncludeObject(pidl) == S_OK)
1009         pThis->LV_AddItem(pidl);
1010 
1011     SHFree(pidl);
1012     return TRUE;
1013 }
1014 
1015 HRESULT CDefView::FillList()
1016 {
1017     CComPtr<IEnumIDList> pEnumIDList;
1018     PITEMID_CHILD pidl;
1019     DWORD         dwFetched;
1020     HRESULT       hRes;
1021     HDPA          hdpa;
1022     DWORD         dFlags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS;
1023     DWORD dwValue, cbValue;
1024 
1025     TRACE("%p\n", this);
1026 
1027     /* determine if there is a setting to show all the hidden files/folders */
1028     dwValue = 1;
1029     cbValue = sizeof(dwValue);
1030     SHGetValueW(HKEY_CURRENT_USER,
1031                 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
1032                 L"Hidden", NULL, &dwValue, &cbValue);
1033     if (dwValue == 1)
1034     {
1035         dFlags |= SHCONTF_INCLUDEHIDDEN;
1036         m_ListView.SendMessageW(LVM_SETCALLBACKMASK, LVIS_CUT, 0);
1037     }
1038 
1039     dwValue = 0;
1040     cbValue = sizeof(dwValue);
1041     SHGetValueW(HKEY_CURRENT_USER,
1042                 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
1043                 L"ShowSuperHidden", NULL, &dwValue, &cbValue);
1044     if (dwValue)
1045     {
1046         dFlags |= SHCONTF_INCLUDESUPERHIDDEN;
1047         m_ListView.SendMessageW(LVM_SETCALLBACKMASK, LVIS_CUT, 0);
1048     }
1049 
1050     /* get the itemlist from the shfolder */
1051     hRes = m_pSFParent->EnumObjects(m_hWnd, dFlags, &pEnumIDList);
1052     if (hRes != S_OK)
1053     {
1054         if (hRes == S_FALSE)
1055             return(NOERROR);
1056         return(hRes);
1057     }
1058 
1059     /* create a pointer array */
1060     hdpa = DPA_Create(16);
1061     if (!hdpa)
1062     {
1063         return(E_OUTOFMEMORY);
1064     }
1065 
1066     /* copy the items into the array*/
1067     while((S_OK == pEnumIDList->Next(1, &pidl, &dwFetched)) && dwFetched)
1068     {
1069         if (DPA_InsertPtr(hdpa, 0x7fff, pidl) == -1)
1070         {
1071             SHFree(pidl);
1072         }
1073     }
1074 
1075     /*turn the listview's redrawing off*/
1076     m_ListView.SetRedraw(FALSE);
1077 
1078     DPA_DestroyCallback( hdpa, fill_list, this);
1079 
1080     /* sort the array */
1081     if (m_pSF2Parent)
1082     {
1083         m_pSF2Parent->GetDefaultColumn(NULL, (ULONG*)&m_sortInfo.nHeaderID, NULL);
1084     }
1085     else
1086     {
1087         FIXME("no m_pSF2Parent\n");
1088     }
1089     m_sortInfo.bIsAscending = TRUE;
1090     _Sort();
1091 
1092     if (m_viewinfo_data.hbmBack)
1093     {
1094         ::DeleteObject(m_viewinfo_data.hbmBack);
1095         m_viewinfo_data.hbmBack = NULL;
1096     }
1097 
1098     // load custom background image and custom text color
1099     m_viewinfo_data.cbSize = sizeof(m_viewinfo_data);
1100     _DoFolderViewCB(SFVM_GET_CUSTOMVIEWINFO, 0, (LPARAM)&m_viewinfo_data);
1101 
1102     /*turn the listview's redrawing back on and force it to draw*/
1103     m_ListView.SetRedraw(TRUE);
1104 
1105     UpdateListColors();
1106 
1107     if (!(m_FolderSettings.fFlags & FWF_DESKTOP))
1108     {
1109         // redraw now
1110         m_ListView.InvalidateRect(NULL, TRUE);
1111     }
1112 
1113     _DoFolderViewCB(SFVM_LISTREFRESHED, 0, 0);
1114 
1115     return S_OK;
1116 }
1117 
1118 LRESULT CDefView::OnShowWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1119 {
1120     if (m_ListView.IsWindow())
1121         m_ListView.UpdateWindow();
1122     bHandled = FALSE;
1123     return 0;
1124 }
1125 
1126 LRESULT CDefView::OnGetDlgCode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1127 {
1128     return m_ListView.SendMessageW(uMsg, 0, 0);
1129 }
1130 
1131 LRESULT CDefView::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1132 {
1133     if (!m_Destroyed)
1134     {
1135         m_Destroyed = TRUE;
1136         if (m_hMenu)
1137         {
1138             DestroyMenu(m_hMenu);
1139             m_hMenu = NULL;
1140         }
1141         RevokeDragDrop(m_hWnd);
1142         SHChangeNotifyDeregister(m_hNotify);
1143         m_hNotify = NULL;
1144         SHFree(m_pidlParent);
1145         m_pidlParent = NULL;
1146     }
1147     bHandled = FALSE;
1148     return 0;
1149 }
1150 
1151 LRESULT CDefView::OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1152 {
1153     /* redirect to parent */
1154     if (m_FolderSettings.fFlags & (FWF_DESKTOP | FWF_TRANSPARENT))
1155         return SendMessageW(GetParent(), WM_ERASEBKGND, wParam, lParam);
1156 
1157     bHandled = FALSE;
1158     return 0;
1159 }
1160 
1161 static VOID
1162 DrawTileBitmap(HDC hDC, LPCRECT prc, HBITMAP hbm, INT nWidth, INT nHeight, INT dx, INT dy)
1163 {
1164     INT x0 = prc->left, y0 = prc->top, x1 = prc->right, y1 = prc->bottom;
1165     x0 += dx;
1166     y0 += dy;
1167 
1168     HDC hMemDC = CreateCompatibleDC(hDC);
1169     HGDIOBJ hbmOld = SelectObject(hMemDC, hbm);
1170 
1171     for (INT y = y0; y < y1; y += nHeight)
1172     {
1173         for (INT x = x0; x < x1; x += nWidth)
1174         {
1175             BitBlt(hDC, x, y, nWidth, nHeight, hMemDC, 0, 0, SRCCOPY);
1176         }
1177     }
1178 
1179     SelectObject(hMemDC, hbmOld);
1180     DeleteDC(hMemDC);
1181 }
1182 
1183 LRESULT CDefView::OnPrintClient(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1184 {
1185     HDC hDC = (HDC)wParam;
1186 
1187     RECT rc;
1188     ::GetClientRect(m_ListView, &rc);
1189 
1190     if (m_viewinfo_data.hbmBack)
1191     {
1192         BITMAP bm;
1193         if (::GetObject(m_viewinfo_data.hbmBack, sizeof(BITMAP), &bm))
1194         {
1195             INT dx = -(::GetScrollPos(m_ListView, SB_HORZ) % bm.bmWidth);
1196             INT dy = -(::GetScrollPos(m_ListView, SB_VERT) % bm.bmHeight);
1197             DrawTileBitmap(hDC, &rc, m_viewinfo_data.hbmBack, bm.bmWidth, bm.bmHeight, dx, dy);
1198         }
1199     }
1200     else
1201     {
1202         FillRect(hDC, &rc, GetSysColorBrush(COLOR_WINDOW));
1203     }
1204 
1205     bHandled = TRUE;
1206 
1207     return TRUE;
1208 }
1209 
1210 LRESULT CDefView::OnSysColorChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1211 {
1212     /* Update desktop labels color */
1213     UpdateListColors();
1214 
1215     /* Forward WM_SYSCOLORCHANGE to common controls */
1216     return m_ListView.SendMessageW(uMsg, 0, 0);
1217 }
1218 
1219 LRESULT CDefView::OnGetShellBrowser(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1220 {
1221     return reinterpret_cast<LRESULT>(m_pShellBrowser.p);
1222 }
1223 
1224 LRESULT CDefView::OnNCCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1225 {
1226     this->AddRef();
1227     bHandled = FALSE;
1228     return 0;
1229 }
1230 
1231 LRESULT CDefView::OnNCDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1232 {
1233     this->Release();
1234     bHandled = FALSE;
1235     return 0;
1236 }
1237 
1238 /**********************************************************
1239 *  ShellView_OnCreate()
1240 */
1241 LRESULT CDefView::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1242 {
1243     CComPtr<IDropTarget>     pdt;
1244     CComPtr<IPersistFolder2> ppf2;
1245 
1246     TRACE("%p\n", this);
1247 
1248     if (SUCCEEDED(QueryInterface(IID_PPV_ARG(IDropTarget, &pdt))))
1249     {
1250         if (FAILED(RegisterDragDrop(m_hWnd, pdt)))
1251             ERR("Registering Drag Drop Failed\n");
1252     }
1253 
1254     /* register for receiving notifications */
1255     m_pSFParent->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
1256     if (ppf2)
1257     {
1258         ppf2->GetCurFolder(&m_pidlParent);
1259     }
1260 
1261     if (CreateList())
1262     {
1263         if (InitList())
1264         {
1265             FillList();
1266         }
1267     }
1268 
1269     if (m_FolderSettings.fFlags & FWF_DESKTOP)
1270     {
1271         HWND hwndSB;
1272         m_pShellBrowser->GetWindow(&hwndSB);
1273         SetShellWindowEx(hwndSB, m_ListView);
1274     }
1275 
1276     SHChangeNotifyEntry ntreg[1];
1277     ntreg[0].fRecursive = FALSE;
1278     ntreg[0].pidl = m_pidlParent;
1279     m_hNotify = SHChangeNotifyRegister(m_hWnd,
1280                                        SHCNRF_InterruptLevel | SHCNRF_ShellLevel |
1281                                        SHCNRF_NewDelivery,
1282                                        SHCNE_ALLEVENTS, SHV_CHANGE_NOTIFY,
1283                                        1, ntreg);
1284 
1285     /* _DoFolderViewCB(SFVM_GETNOTIFY, ??  ??) */
1286 
1287     m_hAccel = LoadAcceleratorsW(shell32_hInstance, MAKEINTRESOURCEW(IDA_SHELLVIEW));
1288 
1289     BOOL bPreviousParentSpecial = m_isParentFolderSpecial;
1290 
1291     /* A folder is special if it is the Desktop folder,
1292      * a network folder, or a Control Panel folder. */
1293     m_isParentFolderSpecial = _ILIsDesktop(m_pidlParent) || _ILIsNetHood(m_pidlParent)
1294         || _ILIsControlPanel(ILFindLastID(m_pidlParent));
1295 
1296     /* Only force StatusBar part refresh if the state
1297      * changed from the previous folder. */
1298     if (bPreviousParentSpecial != m_isParentFolderSpecial)
1299     {
1300         /* This handles changing StatusBar parts. */
1301         _ForceStatusBarResize();
1302     }
1303 
1304     UpdateStatusbar();
1305 
1306     return S_OK;
1307 }
1308 
1309 /**********************************************************
1310  *    #### Handling of the menus ####
1311  */
1312 
1313 extern "C" DWORD WINAPI SHMenuIndexFromID(HMENU hMenu, UINT uID);
1314 
1315 HMENU GetSubmenuByID(HMENU hmenu, UINT id)
1316 {
1317     MENUITEMINFOW mii = {sizeof(mii), MIIM_SUBMENU};
1318     if (::GetMenuItemInfoW(hmenu, id, FALSE, &mii))
1319         return mii.hSubMenu;
1320 
1321     return NULL;
1322 }
1323 
1324 /* ReallyGetMenuItemID returns the id of an item even if it opens a submenu,
1325    GetMenuItemID returns -1 if the specified item opens a submenu */
1326 UINT ReallyGetMenuItemID(HMENU hmenu, int i)
1327 {
1328     MENUITEMINFOW mii = {sizeof(mii), MIIM_ID};
1329     if (::GetMenuItemInfoW(hmenu, i, TRUE, &mii))
1330         return mii.wID;
1331 
1332     return UINT_MAX;
1333 }
1334 
1335 HRESULT CDefView::FillFileMenu()
1336 {
1337     HMENU hFileMenu = GetSubmenuByID(m_hMenu, FCIDM_MENU_FILE);
1338     if (!hFileMenu)
1339         return E_FAIL;
1340 
1341     /* Cleanup the items added previously */
1342     for (int i = GetMenuItemCount(hFileMenu) - 1; i >= 0; i--)
1343     {
1344         UINT id = GetMenuItemID(hFileMenu, i);
1345         if (id < FCIDM_BROWSERFIRST || id > FCIDM_BROWSERLAST)
1346             DeleteMenu(hFileMenu, i, MF_BYPOSITION);
1347     }
1348 
1349     m_cidl = m_ListView.GetSelectedCount();
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((m_cidl ? SVGIO_SELECTION : SVGIO_BACKGROUND), 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 (pidl)
3118     {
3119         *item = LV_FindItemByPidl(ILFindLastID(pidl));
3120         m_ListView.DeleteItem(*item);
3121     }
3122     else
3123     {
3124         *item = 0;
3125         m_ListView.DeleteAllItems();
3126     }
3127 
3128     return S_OK;
3129 }
3130 
3131 HRESULT STDMETHODCALLTYPE CDefView::GetObjectCount(UINT *count)
3132 {
3133     TRACE("(%p)->(%p)\n", this, count);
3134     *count = m_ListView.GetItemCount();
3135     return S_OK;
3136 }
3137 
3138 HRESULT STDMETHODCALLTYPE CDefView::SetObjectCount(UINT count, UINT flags)
3139 {
3140     FIXME("(%p)->(%d %x) stub\n", this, count, flags);
3141     return E_NOTIMPL;
3142 }
3143 
3144 HRESULT STDMETHODCALLTYPE CDefView::UpdateObject(PITEMID_CHILD pidl_old, PITEMID_CHILD pidl_new, UINT *item)
3145 {
3146     FIXME("(%p)->(%p %p %p) stub\n", this, pidl_old, pidl_new, item);
3147     return E_NOTIMPL;
3148 }
3149 
3150 HRESULT STDMETHODCALLTYPE CDefView::RefreshObject(PITEMID_CHILD pidl, UINT *item)
3151 {
3152     FIXME("(%p)->(%p %p) stub\n", this, pidl, item);
3153     return E_NOTIMPL;
3154 }
3155 
3156 HRESULT STDMETHODCALLTYPE CDefView::SetRedraw(BOOL redraw)
3157 {
3158     TRACE("(%p)->(%d)\n", this, redraw);
3159     m_ListView.SetRedraw(redraw);
3160     return S_OK;
3161 }
3162 
3163 HRESULT STDMETHODCALLTYPE CDefView::GetSelectedCount(UINT *count)
3164 {
3165     FIXME("(%p)->(%p) stub\n", this, count);
3166     return E_NOTIMPL;
3167 }
3168 
3169 HRESULT STDMETHODCALLTYPE CDefView::GetSelectedObjects(PCUITEMID_CHILD **pidl, UINT *items)
3170 {
3171     TRACE("(%p)->(%p %p)\n", this, pidl, items);
3172 
3173     *items = GetSelections();
3174 
3175     if (*items)
3176     {
3177         *pidl = static_cast<PCUITEMID_CHILD *>(LocalAlloc(0, *items * sizeof(PCUITEMID_CHILD)));
3178         if (!*pidl)
3179         {
3180             return E_OUTOFMEMORY;
3181         }
3182 
3183         /* it's documented that caller shouldn't PIDLs, only array itself */
3184         memcpy(*pidl, m_apidl, *items * sizeof(PCUITEMID_CHILD));
3185     }
3186 
3187     return S_OK;
3188 }
3189 
3190 HRESULT STDMETHODCALLTYPE CDefView::IsDropOnSource(IDropTarget *drop_target)
3191 {
3192     if ((m_iDragOverItem == -1 || m_pCurDropTarget == NULL) &&
3193         (m_pSourceDataObject.p))
3194     {
3195         return S_OK;
3196     }
3197 
3198     return S_FALSE;
3199 }
3200 
3201 HRESULT STDMETHODCALLTYPE CDefView::GetDragPoint(POINT *pt)
3202 {
3203     if (!pt)
3204         return E_INVALIDARG;
3205 
3206     *pt = m_ptFirstMousePos;
3207     return S_OK;
3208 }
3209 
3210 HRESULT STDMETHODCALLTYPE CDefView::GetDropPoint(POINT *pt)
3211 {
3212     FIXME("(%p)->(%p) stub\n", this, pt);
3213     return E_NOTIMPL;
3214 }
3215 
3216 HRESULT STDMETHODCALLTYPE CDefView::MoveIcons(IDataObject *obj)
3217 {
3218     TRACE("(%p)->(%p)\n", this, obj);
3219     return E_NOTIMPL;
3220 }
3221 
3222 HRESULT STDMETHODCALLTYPE CDefView::SetItemPos(PCUITEMID_CHILD pidl, POINT *pt)
3223 {
3224     FIXME("(%p)->(%p %p) stub\n", this, pidl, pt);
3225     return E_NOTIMPL;
3226 }
3227 
3228 HRESULT STDMETHODCALLTYPE CDefView::IsBkDropTarget(IDropTarget *drop_target)
3229 {
3230     FIXME("(%p)->(%p) stub\n", this, drop_target);
3231     return E_NOTIMPL;
3232 }
3233 
3234 HRESULT STDMETHODCALLTYPE CDefView::SetClipboard(BOOL move)
3235 {
3236     FIXME("(%p)->(%d) stub\n", this, move);
3237     return E_NOTIMPL;
3238 }
3239 
3240 HRESULT STDMETHODCALLTYPE CDefView::SetPoints(IDataObject *obj)
3241 {
3242     FIXME("(%p)->(%p) stub\n", this, obj);
3243     return E_NOTIMPL;
3244 }
3245 
3246 HRESULT STDMETHODCALLTYPE CDefView::GetItemSpacing(ITEMSPACING *spacing)
3247 {
3248     FIXME("(%p)->(%p) stub\n", this, spacing);
3249     return E_NOTIMPL;
3250 }
3251 
3252 HRESULT STDMETHODCALLTYPE CDefView::SetCallback(IShellFolderViewCB  *new_cb, IShellFolderViewCB **old_cb)
3253 {
3254     if (old_cb)
3255         *old_cb = m_pShellFolderViewCB.Detach();
3256 
3257     m_pShellFolderViewCB = new_cb;
3258     return S_OK;
3259 }
3260 
3261 HRESULT STDMETHODCALLTYPE CDefView::Select(UINT flags)
3262 {
3263     FIXME("(%p)->(%d) stub\n", this, flags);
3264     return E_NOTIMPL;
3265 }
3266 
3267 HRESULT STDMETHODCALLTYPE CDefView::QuerySupport(UINT *support)
3268 {
3269     TRACE("(%p)->(%p)\n", this, support);
3270     return S_OK;
3271 }
3272 
3273 HRESULT STDMETHODCALLTYPE CDefView::SetAutomationObject(IDispatch *disp)
3274 {
3275     FIXME("(%p)->(%p) stub\n", this, disp);
3276     return E_NOTIMPL;
3277 }
3278 
3279 /**********************************************************
3280  * ISVOleCmdTarget_QueryStatus (IOleCommandTarget)
3281  */
3282 HRESULT WINAPI CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText)
3283 {
3284     FIXME("(%p)->(%p(%s) 0x%08x %p %p\n",
3285           this, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
3286 
3287     if (!prgCmds)
3288         return E_INVALIDARG;
3289 
3290     for (UINT i = 0; i < cCmds; i++)
3291     {
3292         FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID);
3293         prgCmds[i].cmdf = 0;
3294     }
3295 
3296     return OLECMDERR_E_UNKNOWNGROUP;
3297 }
3298 
3299 /**********************************************************
3300  * ISVOleCmdTarget_Exec (IOleCommandTarget)
3301  *
3302  * nCmdID is the OLECMDID_* enumeration
3303  */
3304 HRESULT WINAPI CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
3305 {
3306     FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n",
3307           this, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut);
3308 
3309     if (!pguidCmdGroup)
3310         return OLECMDERR_E_UNKNOWNGROUP;
3311 
3312     if (IsEqualCLSID(*pguidCmdGroup, m_Category))
3313     {
3314         if (nCmdID == FCIDM_SHVIEW_AUTOARRANGE)
3315         {
3316             if (V_VT(pvaIn) != VT_INT_PTR)
3317                 return OLECMDERR_E_NOTSUPPORTED;
3318 
3319             TPMPARAMS params;
3320             params.cbSize = sizeof(params);
3321             params.rcExclude = *(RECT*) V_INTREF(pvaIn);
3322 
3323             if (m_hMenuViewModes)
3324             {
3325                 /* Duplicate all but the last two items of the view modes menu */
3326                 HMENU hmenuViewPopup = CreatePopupMenu();
3327                 Shell_MergeMenus(hmenuViewPopup, m_hMenuViewModes, 0, 0, 0xFFFF, 0);
3328                 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION);
3329                 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION);
3330                 CheckViewMode(hmenuViewPopup);
3331                 TrackPopupMenuEx(hmenuViewPopup, TPM_LEFTALIGN | TPM_TOPALIGN, params.rcExclude.left, params.rcExclude.bottom, m_hWndParent, &params);
3332                 ::DestroyMenu(hmenuViewPopup);
3333             }
3334 
3335             // pvaOut is VT_I4 with value 0x403 (cmd id of the new mode maybe?)
3336             V_VT(pvaOut) = VT_I4;
3337             V_I4(pvaOut) = 0x403;
3338         }
3339     }
3340 
3341     if (IsEqualIID(*pguidCmdGroup, CGID_Explorer) &&
3342             (nCmdID == 0x29) &&
3343             (nCmdexecopt == 4) && pvaOut)
3344         return S_OK;
3345 
3346     if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView) &&
3347             (nCmdID == 9) &&
3348             (nCmdexecopt == 0))
3349         return 1;
3350 
3351     return OLECMDERR_E_UNKNOWNGROUP;
3352 }
3353 
3354 /**********************************************************
3355  * ISVDropTarget implementation
3356  */
3357 
3358 /******************************************************************************
3359  * drag_notify_subitem [Internal]
3360  *
3361  * Figure out the shellfolder object, which is currently under the mouse cursor
3362  * and notify it via the IDropTarget interface.
3363  */
3364 
3365 #define SCROLLAREAWIDTH 20
3366 
3367 HRESULT CDefView::drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3368 {
3369     LONG lResult;
3370     HRESULT hr;
3371     RECT clientRect;
3372 
3373     /* The key state on drop doesn't have MK_LBUTTON or MK_RBUTTON because it
3374        reflects the key state after the user released the button, so we need
3375        to remember the last key state when the button was pressed */
3376     m_grfKeyState = grfKeyState;
3377 
3378     /* Map from global to client coordinates and query the index of the listview-item, which is
3379      * currently under the mouse cursor. */
3380     LVHITTESTINFO htinfo = {{pt.x, pt.y}, LVHT_ONITEM};
3381     ScreenToClient(&htinfo.pt);
3382     lResult = m_ListView.HitTest(&htinfo);
3383 
3384     /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */
3385     ::GetClientRect(m_ListView, &clientRect);
3386     if (htinfo.pt.x == m_ptLastMousePos.x && htinfo.pt.y == m_ptLastMousePos.y &&
3387             (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH ||
3388              htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH ))
3389     {
3390         m_cScrollDelay = (m_cScrollDelay + 1) % 5; /* DragOver is called every 50 ms */
3391         if (m_cScrollDelay == 0)
3392         {
3393             /* Mouse did hover another 250 ms over the scroll-area */
3394             if (htinfo.pt.x < SCROLLAREAWIDTH)
3395                 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEUP, 0);
3396 
3397             if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH)
3398                 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEDOWN, 0);
3399 
3400             if (htinfo.pt.y < SCROLLAREAWIDTH)
3401                 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEUP, 0);
3402 
3403             if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH)
3404                 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEDOWN, 0);
3405         }
3406     }
3407     else
3408     {
3409         m_cScrollDelay = 0; /* Reset, if the cursor is not over the listview's scroll-area */
3410     }
3411 
3412     m_ptLastMousePos = htinfo.pt;
3413     ::ClientToListView(m_ListView, &m_ptLastMousePos);
3414 
3415     /* We need to check if we drag the selection over itself */
3416     if (lResult != -1 && m_pSourceDataObject.p != NULL)
3417     {
3418         PCUITEMID_CHILD pidl = _PidlByItem(lResult);
3419 
3420         for (UINT i = 0; i < m_cidl; i++)
3421         {
3422             if (pidl == m_apidl[i])
3423             {
3424                 /* The item that is being draged is hovering itself. */
3425                 lResult = -1;
3426                 break;
3427             }
3428         }
3429     }
3430 
3431     /* If we are still over the previous sub-item, notify it via DragOver and return. */
3432     if (m_pCurDropTarget && lResult == m_iDragOverItem)
3433         return m_pCurDropTarget->DragOver(grfKeyState, pt, pdwEffect);
3434 
3435     /* We've left the previous sub-item, notify it via DragLeave and Release it. */
3436     if (m_pCurDropTarget)
3437     {
3438         PCUITEMID_CHILD pidl = _PidlByItem(m_iDragOverItem);
3439         if (pidl)
3440             SelectItem(pidl, 0);
3441 
3442         m_pCurDropTarget->DragLeave();
3443         m_pCurDropTarget.Release();
3444     }
3445 
3446     m_iDragOverItem = lResult;
3447 
3448     if (lResult == -1)
3449     {
3450         /* We are not above one of the listview's subitems. Bind to the parent folder's
3451          * DropTarget interface. */
3452         hr = m_pSFParent->CreateViewObject(NULL, IID_PPV_ARG(IDropTarget,&m_pCurDropTarget));
3453     }
3454     else
3455     {
3456         /* Query the relative PIDL of the shellfolder object represented by the currently
3457          * dragged over listview-item ... */
3458         PCUITEMID_CHILD pidl = _PidlByItem(lResult);
3459 
3460         /* ... and bind m_pCurDropTarget to the IDropTarget interface of an UIObject of this object */
3461         hr = m_pSFParent->GetUIObjectOf(m_ListView, 1, &pidl, IID_NULL_PPV_ARG(IDropTarget, &m_pCurDropTarget));
3462     }
3463 
3464     IUnknown_SetSite(m_pCurDropTarget, (IShellView *)this);
3465 
3466     /* If anything failed, m_pCurDropTarget should be NULL now, which ought to be a save state. */
3467     if (FAILED(hr))
3468     {
3469         *pdwEffect = DROPEFFECT_NONE;
3470         return hr;
3471     }
3472 
3473     if (m_iDragOverItem != -1)
3474     {
3475         SelectItem(m_iDragOverItem, SVSI_SELECT);
3476     }
3477 
3478     /* Notify the item just entered via DragEnter. */
3479     return m_pCurDropTarget->DragEnter(m_pCurDataObject, grfKeyState, pt, pdwEffect);
3480 }
3481 
3482 HRESULT WINAPI CDefView::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3483 {
3484     if (*pdwEffect == DROPEFFECT_NONE)
3485         return S_OK;
3486 
3487     /* Get a hold on the data object for later calls to DragEnter on the sub-folders */
3488     m_pCurDataObject = pDataObject;
3489 
3490     HRESULT hr = drag_notify_subitem(grfKeyState, pt, pdwEffect);
3491     if (SUCCEEDED(hr))
3492     {
3493         POINT ptClient = {pt.x, pt.y};
3494         ScreenToClient(&ptClient);
3495         ImageList_DragEnter(m_hWnd, ptClient.x, ptClient.y);
3496     }
3497 
3498     return hr;
3499 }
3500 
3501 HRESULT WINAPI CDefView::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3502 {
3503     POINT ptClient = {pt.x, pt.y};
3504     ScreenToClient(&ptClient);
3505     ImageList_DragMove(ptClient.x, ptClient.y);
3506     return drag_notify_subitem(grfKeyState, pt, pdwEffect);
3507 }
3508 
3509 HRESULT WINAPI CDefView::DragLeave()
3510 {
3511     ImageList_DragLeave(m_hWnd);
3512 
3513     if (m_pCurDropTarget)
3514     {
3515         m_pCurDropTarget->DragLeave();
3516         m_pCurDropTarget.Release();
3517     }
3518 
3519     if (m_pCurDataObject != NULL)
3520     {
3521         m_pCurDataObject.Release();
3522     }
3523 
3524     m_iDragOverItem = 0;
3525 
3526     return S_OK;
3527 }
3528 
3529 INT CDefView::_FindInsertableIndexFromPoint(POINT pt)
3530 {
3531     RECT rcBound;
3532     INT i, nCount = m_ListView.GetItemCount();
3533     DWORD dwSpacing;
3534     INT dx, dy;
3535     BOOL bSmall = ((m_ListView.GetStyle() & LVS_TYPEMASK) != LVS_ICON);
3536 
3537     /* FIXME: LVM_GETORIGIN is broken. See CORE-17266 */
3538     pt.x += m_ListView.GetScrollPos(SB_HORZ);
3539     pt.y += m_ListView.GetScrollPos(SB_VERT);
3540 
3541     if (m_ListView.GetStyle() & LVS_ALIGNLEFT)
3542     {
3543         // vertically
3544         for (i = 0; i < nCount; ++i)
3545         {
3546             dwSpacing = ListView_GetItemSpacing(m_ListView, bSmall);
3547             dx = LOWORD(dwSpacing);
3548             dy = HIWORD(dwSpacing);
3549             ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS);
3550             rcBound.right = rcBound.left + dx;
3551             rcBound.bottom = rcBound.top + dy;
3552             if (pt.x < rcBound.right && pt.y < (rcBound.top + rcBound.bottom) / 2)
3553             {
3554                 return i;
3555             }
3556         }
3557         for (i = nCount - 1; i >= 0; --i)
3558         {
3559             ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS);
3560             if (rcBound.left < pt.x && rcBound.top < pt.y)
3561             {
3562                 return i + 1;
3563             }
3564         }
3565     }
3566     else
3567     {
3568         // horizontally
3569         for (i = 0; i < nCount; ++i)
3570         {
3571             dwSpacing = ListView_GetItemSpacing(m_ListView, bSmall);
3572             dx = LOWORD(dwSpacing);
3573             dy = HIWORD(dwSpacing);
3574             ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS);
3575             rcBound.right = rcBound.left + dx;
3576             rcBound.bottom = rcBound.top + dy;
3577             if (pt.y < rcBound.bottom && pt.x < rcBound.left)
3578             {
3579                 return i;
3580             }
3581             if (pt.y < rcBound.bottom && pt.x < rcBound.right)
3582             {
3583                 return i + 1;
3584             }
3585         }
3586         for (i = nCount - 1; i >= 0; --i)
3587         {
3588             ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS);
3589             if (rcBound.left < pt.x && rcBound.top < pt.y)
3590             {
3591                 return i + 1;
3592             }
3593         }
3594     }
3595 
3596     return nCount;
3597 }
3598 
3599 void CDefView::_HandleStatusBarResize(int nWidth)
3600 {
3601     LRESULT lResult;
3602 
3603     if (m_isParentFolderSpecial)
3604     {
3605         int nPartArray[] = {-1};
3606         m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, _countof(nPartArray), (LPARAM)nPartArray, &lResult);
3607         return;
3608     }
3609 
3610     int nFileSizePartLength = 125;
3611     const int nLocationPartLength = 150;
3612     const int nRightPartsLength = nFileSizePartLength + nLocationPartLength;
3613     int nObjectsPartLength = nWidth - nRightPartsLength;
3614 
3615     /* If the window is small enough just divide each part into thirds
3616      * This is the behavior of Windows Server 2003. */
3617     if (nObjectsPartLength <= nLocationPartLength)
3618         nObjectsPartLength = nFileSizePartLength = nWidth / 3;
3619 
3620     int nPartArray[] = {nObjectsPartLength, nObjectsPartLength + nFileSizePartLength, -1};
3621 
3622     m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, _countof(nPartArray), (LPARAM)nPartArray, &lResult);
3623 }
3624 
3625 void CDefView::_ForceStatusBarResize()
3626 {
3627     /* Get the handle for the status bar */
3628     HWND fStatusBar;
3629     m_pShellBrowser->GetControlWindow(FCW_STATUS, &fStatusBar);
3630 
3631     /* Get the size of our status bar */
3632     RECT statusBarSize;
3633     ::GetWindowRect(fStatusBar, &statusBarSize);
3634 
3635     /* Resize the status bar */
3636     _HandleStatusBarResize(statusBarSize.right - statusBarSize.left);
3637 }
3638 
3639 typedef CSimpleMap<LPARAM, INT> CLParamIndexMap;
3640 
3641 static INT CALLBACK
3642 SelectionMoveCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
3643 {
3644     CLParamIndexMap *pmap = (CLParamIndexMap *)lParamSort;
3645     INT i1 = pmap->Lookup(lParam1), i2 = pmap->Lookup(lParam2);
3646     if (i1 < i2)
3647         return -1;
3648     if (i1 > i2)
3649         return 1;
3650     return 0;
3651 }
3652 
3653 void CDefView::_MoveSelectionOnAutoArrange(POINT pt)
3654 {
3655     // get insertable index from position
3656     INT iPosition = _FindInsertableIndexFromPoint(pt);
3657 
3658     // create identity mapping of indexes
3659     CSimpleArray<INT> array;
3660     INT nCount = m_ListView.GetItemCount();
3661     for (INT i = 0; i < nCount; ++i)
3662     {
3663         array.Add(i);
3664     }
3665 
3666     // re-ordering mapping
3667     INT iItem = -1;
3668     while ((iItem = m_ListView.GetNextItem(iItem, LVNI_SELECTED)) >= 0)
3669     {
3670         INT iFrom = iItem, iTo = iPosition;
3671         if (iFrom < iTo)
3672             --iTo;
3673         if (iFrom >= nCount)
3674             iFrom = nCount - 1;
3675         if (iTo >= nCount)
3676             iTo = nCount - 1;
3677 
3678         // shift indexes by swapping (like a bucket relay)
3679         if (iFrom < iTo)
3680         {
3681             for (INT i = iFrom; i < iTo; ++i)
3682             {
3683                 // swap array[i] and array[i + 1]
3684                 INT tmp = array[i];
3685                 array[i] = array[i + 1];
3686                 array[i + 1] = tmp;
3687             }
3688         }
3689         else
3690         {
3691             for (INT i = iFrom; i > iTo; --i)
3692             {
3693                 // swap array[i] and array[i - 1]
3694                 INT tmp = array[i];
3695                 array[i] = array[i - 1];
3696                 array[i - 1] = tmp;
3697             }
3698         }
3699     }
3700 
3701     // create mapping (ListView's lParam to index) from array
3702     CLParamIndexMap map;
3703     for (INT i = 0; i < nCount; ++i)
3704     {
3705         LPARAM lParam = m_ListView.GetItemData(array[i]);
3706         map.Add(lParam, i);
3707     }
3708 
3709     // finally sort
3710     m_ListView.SortItems(SelectionMoveCompareFunc, &map);
3711 }
3712 
3713 HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3714 {
3715     ImageList_DragLeave(m_hWnd);
3716     ImageList_EndDrag();
3717 
3718     if ((IsDropOnSource(NULL) == S_OK) &&
3719         (*pdwEffect & DROPEFFECT_MOVE) &&
3720         (m_grfKeyState & MK_LBUTTON))
3721     {
3722         if (m_pCurDropTarget)
3723         {
3724             m_pCurDropTarget->DragLeave();
3725             m_pCurDropTarget.Release();
3726         }
3727 
3728         POINT ptDrop = { pt.x, pt.y };
3729         ::ScreenToClient(m_ListView, &ptDrop);
3730         ::ClientToListView(m_ListView, &ptDrop);
3731         m_ptLastMousePos = ptDrop;
3732 
3733         m_ListView.SetRedraw(FALSE);
3734         if (m_ListView.GetStyle() & LVS_AUTOARRANGE)
3735         {
3736             _MoveSelectionOnAutoArrange(m_ptLastMousePos);
3737         }
3738         else
3739         {
3740             POINT ptItem;
3741             INT iItem = -1;
3742             while ((iItem = m_ListView.GetNextItem(iItem, LVNI_SELECTED)) >= 0)
3743             {
3744                 if (m_ListView.GetItemPosition(iItem, &ptItem))
3745                 {
3746                     ptItem.x += m_ptLastMousePos.x - m_ptFirstMousePos.x;
3747                     ptItem.y += m_ptLastMousePos.y - m_ptFirstMousePos.y;
3748                     m_ListView.SetItemPosition(iItem, &ptItem);
3749                 }
3750             }
3751         }
3752         m_ListView.SetRedraw(TRUE);
3753     }
3754     else if (m_pCurDropTarget)
3755     {
3756         m_pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect);
3757         m_pCurDropTarget.Release();
3758     }
3759 
3760     m_pCurDataObject.Release();
3761     m_iDragOverItem = 0;
3762     return S_OK;
3763 }
3764 
3765 /**********************************************************
3766  * ISVDropSource implementation
3767  */
3768 
3769 HRESULT WINAPI CDefView::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
3770 {
3771     TRACE("(%p)\n", this);
3772 
3773     if (fEscapePressed)
3774         return DRAGDROP_S_CANCEL;
3775     else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON))
3776         return DRAGDROP_S_DROP;
3777     else
3778         return S_OK;
3779 }
3780 
3781 HRESULT WINAPI CDefView::GiveFeedback(DWORD dwEffect)
3782 {
3783     TRACE("(%p)\n", this);
3784 
3785     return DRAGDROP_S_USEDEFAULTCURSORS;
3786 }
3787 
3788 /**********************************************************
3789  * ISVViewObject implementation
3790  */
3791 
3792 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)
3793 {
3794     FIXME("Stub: this=%p\n", this);
3795 
3796     return E_NOTIMPL;
3797 }
3798 
3799 HRESULT WINAPI CDefView::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet)
3800 {
3801     FIXME("Stub: this=%p\n", this);
3802 
3803     return E_NOTIMPL;
3804 }
3805 
3806 HRESULT WINAPI CDefView::Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze)
3807 {
3808     FIXME("Stub: this=%p\n", this);
3809 
3810     return E_NOTIMPL;
3811 }
3812 
3813 HRESULT WINAPI CDefView::Unfreeze(DWORD dwFreeze)
3814 {
3815     FIXME("Stub: this=%p\n", this);
3816 
3817     return E_NOTIMPL;
3818 }
3819 
3820 HRESULT WINAPI CDefView::SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink)
3821 {
3822     FIXME("partial stub: %p 0x%08x 0x%08x %p\n", this, aspects, advf, pAdvSink);
3823 
3824     /* FIXME: we set the AdviseSink, but never use it to send any advice */
3825     m_pAdvSink = pAdvSink;
3826     m_dwAspects = aspects;
3827     m_dwAdvf = advf;
3828 
3829     return S_OK;
3830 }
3831 
3832 HRESULT WINAPI CDefView::GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink)
3833 {
3834     TRACE("this=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n", this, pAspects, pAdvf, ppAdvSink);
3835 
3836     if (ppAdvSink)
3837     {
3838         *ppAdvSink = m_pAdvSink;
3839         m_pAdvSink.p->AddRef();
3840     }
3841 
3842     if (pAspects)
3843         *pAspects = m_dwAspects;
3844 
3845     if (pAdvf)
3846         *pAdvf = m_dwAdvf;
3847 
3848     return S_OK;
3849 }
3850 
3851 HRESULT STDMETHODCALLTYPE CDefView::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
3852 {
3853     if (IsEqualIID(guidService, SID_IShellBrowser))
3854         return m_pShellBrowser->QueryInterface(riid, ppvObject);
3855     else if(IsEqualIID(guidService, SID_IFolderView))
3856         return QueryInterface(riid, ppvObject);
3857 
3858     return E_NOINTERFACE;
3859 }
3860 
3861 HRESULT CDefView::_MergeToolbar()
3862 {
3863     CComPtr<IExplorerToolbar> ptb;
3864     HRESULT hr = S_OK;
3865 
3866     hr = IUnknown_QueryService(m_pShellBrowser, IID_IExplorerToolbar, IID_PPV_ARG(IExplorerToolbar, &ptb));
3867     if (FAILED(hr))
3868         return hr;
3869 
3870     m_Category = CGID_DefViewFrame;
3871 
3872     hr = ptb->SetCommandTarget(static_cast<IOleCommandTarget*>(this), &m_Category, 0);
3873     if (FAILED(hr))
3874         return hr;
3875 
3876     if (hr == S_FALSE)
3877         return S_OK;
3878 
3879 #if 0
3880     hr = ptb->AddButtons(&m_Category, buttonsCount, buttons);
3881     if (FAILED(hr))
3882         return hr;
3883 #endif
3884 
3885     return S_OK;
3886 }
3887 
3888 HRESULT CDefView::_DoFolderViewCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
3889 {
3890     HRESULT hr = E_NOTIMPL;
3891 
3892     if (m_pShellFolderViewCB)
3893     {
3894         hr = m_pShellFolderViewCB->MessageSFVCB(uMsg, wParam, lParam);
3895     }
3896 
3897     return hr;
3898 }
3899 
3900 HRESULT CDefView_CreateInstance(IShellFolder *pFolder, REFIID riid, LPVOID * ppvOut)
3901 {
3902     return ShellObjectCreatorInit<CDefView>(pFolder, riid, ppvOut);
3903 }
3904 
3905 HRESULT WINAPI SHCreateShellFolderViewEx(
3906     LPCSFV psvcbi,    /* [in] shelltemplate struct */
3907     IShellView **ppsv) /* [out] IShellView pointer */
3908 {
3909     CComPtr<IShellView> psv;
3910     HRESULT hRes;
3911 
3912     TRACE("sf=%p pidl=%p cb=%p mode=0x%08x parm=%p\n",
3913       psvcbi->pshf, psvcbi->pidl, psvcbi->pfnCallback,
3914       psvcbi->fvm, psvcbi->psvOuter);
3915 
3916     *ppsv = NULL;
3917     hRes = CDefView_CreateInstance(psvcbi->pshf, IID_PPV_ARG(IShellView, &psv));
3918     if (FAILED_UNEXPECTEDLY(hRes))
3919         return hRes;
3920 
3921     *ppsv = psv.Detach();
3922     return hRes;
3923 }
3924 
3925 HRESULT WINAPI SHCreateShellFolderView(const SFV_CREATE *pcsfv,
3926                         IShellView **ppsv)
3927 {
3928     CComPtr<IShellView> psv;
3929     HRESULT hRes;
3930 
3931     if (!ppsv)
3932         return E_INVALIDARG;
3933 
3934     *ppsv = NULL;
3935 
3936     if (!pcsfv || pcsfv->cbSize != sizeof(*pcsfv))
3937         return E_INVALIDARG;
3938 
3939     TRACE("sf=%p outer=%p callback=%p\n",
3940       pcsfv->pshf, pcsfv->psvOuter, pcsfv->psfvcb);
3941 
3942     hRes = CDefView_CreateInstance(pcsfv->pshf, IID_PPV_ARG(IShellView, &psv));
3943     if (FAILED(hRes))
3944         return hRes;
3945 
3946     if (pcsfv->psfvcb)
3947     {
3948         CComPtr<IShellFolderView> sfv;
3949         if (SUCCEEDED(psv->QueryInterface(IID_PPV_ARG(IShellFolderView, &sfv))))
3950         {
3951             sfv->SetCallback(pcsfv->psfvcb, NULL);
3952         }
3953     }
3954 
3955     *ppsv = psv.Detach();
3956     return hRes;
3957 }
3958