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