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