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