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