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