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