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