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