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