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