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