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