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