ReactOS 0.4.15-dev-8339-g4028de8
CDefView.cpp
Go to the documentation of this file.
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/*
28TODO:
29- Load/Save the view state from/into the stream provided by the ShellBrowser unless FWF_NOBROWSERVIEWSTATE is set.
30- When editing starts on item, set edit text to for editing value.
31- Fix shell view to handle view mode popup exec.
32- The background context menu should have a pidl just like foreground menus. This
33 causes crashes when dynamic handlers try to use the NULL pidl.
34- Reorder of columns doesn't work - might be bug in comctl32
35*/
36
37#include "precomp.h"
38
39#include <atlwin.h>
40#include <ui/rosctrls.h>
41
43
44// It would be easier to allocate these from 1 and up but the original code used the entire
45// FCIDM_SHVIEWFIRST..FCIDM_SHVIEWLAST range when dealing with IContextMenu and to avoid
46// breaking anything relying on this we will allocate our ranges from the end instead.
47enum {
48 DEFVIEW_ARRANGESORT_MAXENUM = 9, // Limit the number of the visible columns we will display in the submenu
49 DEFVIEW_ARRANGESORT_MAX = DEFVIEW_ARRANGESORT_MAXENUM + 1, // Reserve one extra for the current sort-by column
52
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.
58};
59#undef FCIDM_SHVIEWLAST // Don't use this constant, change DVIDM_CONTEXTMENU_LAST if you need a new id.
60
61typedef struct
62{
66
67#define SHV_CHANGE_NOTIFY (WM_USER + 0x1111)
68#define SHV_UPDATESTATUSBAR (WM_USER + 0x1112)
69
70// For the context menu of the def view, the id of the items are based on 1 because we need
71// to call TrackPopupMenu and let it use the 0 value as an indication that the menu was canceled
72#define CONTEXT_MENU_BASE_ID 1
73
74static UINT
76{
77 UINT cmf = CMF_NORMAL;
78 if (GetKeyState(VK_SHIFT) < 0)
79 cmf |= CMF_EXTENDEDVERBS;
80 if (sfgao & SFGAO_CANRENAME)
81 cmf |= CMF_CANRENAME;
82 HWND hwnd = NULL;
83 if (pSB && SUCCEEDED(pSB->GetControlWindow(FCW_TREE, &hwnd)) && hwnd)
84 cmf |= CMF_EXPLORE;
85 return cmf;
86}
87
88// Convert client coordinates to listview coordinates
89static void
91{
92 POINT Origin = {};
93
94 // FIXME: LVM_GETORIGIN is broken. See CORE-17266
95 if (!ListView_GetOrigin(hwndLV, &Origin))
96 return;
97
98 ppt->x += Origin.x;
99 ppt->y += Origin.y;
100}
101
102// Helper struct to automatically cleanup the IContextMenu
103// We want to explicitly reset the Site, so there are no circular references
105{
108
110 : m_pCM(pCM), m_hMenu(menu)
111 {
112 }
114 {
115 if (m_hMenu)
116 {
118 m_hMenu = NULL;
119 }
120 if (m_pCM)
121 {
123 m_pCM.Release();
124 }
125 }
126};
127
129{
130 MENUITEMINFOW mii;
131 mii.cbSize = sizeof(mii);
133 mii.fState = MF & (MFS_CHECKED | MFS_DISABLED);
134 mii.fType = MF & ~mii.fState;
135 mii.wID = Id;
136 mii.dwTypeData = const_cast<LPWSTR>(String);
137 mii.dwItemData = Data;
138 return InsertMenuItemW(hMenu, -1, TRUE, &mii);
139}
140
142{
143 MENUITEMINFOW mii;
144 mii.cbSize = FIELD_OFFSET(MENUITEMINFOW, hbmpItem);
145 mii.fMask = MIIM_DATA;
146 if (GetMenuItemInfoW(hMenu, Id, FALSE, &mii))
147 return mii.dwItemData;
148 else
149 return 0;
150}
151
153{
154 MENUITEMINFOW mii = {sizeof(mii), MIIM_SUBMENU};
155 if (::GetMenuItemInfoW(hmenu, id, FALSE, &mii))
156 return mii.hSubMenu;
157
158 return NULL;
159}
160
161/* ReallyGetMenuItemID returns the id of an item even if it opens a submenu,
162 GetMenuItemID returns -1 if the specified item opens a submenu */
164{
165 MENUITEMINFOW mii = {sizeof(mii), MIIM_ID};
166 if (::GetMenuItemInfoW(hmenu, i, TRUE, &mii))
167 return mii.wID;
168
169 return UINT_MAX;
170}
171
173{
174 UINT ret = 0;
175 HDC hDC = GetDC(hwnd);
176 if (hDC)
177 {
180 SelectObject(hDC, hOrg);
182 }
183 return ret;
184}
185
186class CDefView :
187 public CWindowImpl<CDefView, CWindow, CControlWinTraits>,
188 public CComObjectRootEx<CComMultiThreadModelNoCS>,
189 public IShellView3,
190 public IFolderView,
191 public IShellFolderView,
192 public IOleCommandTarget,
193 public IDropTarget,
194 public IDropSource,
195 public IViewObject,
196 public IServiceProvider
197{
198private:
209 HMENU m_hMenu; // Handle to the menu bar of the browser
210 HMENU m_hMenuArrangeModes; // Handle to the popup menu with the arrange modes
211 HMENU m_hMenuViewModes; // Handle to the popup menu with the view modes
212 HMENU m_hContextMenu; // Handle to the open context menu
220 ULONG m_hNotify; // Change notification handle
221 HACCEL m_hAccel;
225 // for drag and drop
227 CComPtr<IDropTarget> m_pCurDropTarget; // The sub-item, which is currently dragged over
228 CComPtr<IDataObject> m_pCurDataObject; // The dragged data-object
229 LONG m_iDragOverItem; // Dragged over item's index, if m_pCurDropTarget != NULL
230 UINT m_cScrollDelay; // Send a WM_*SCROLL msg every 250 ms during drag-scroll
231 POINT m_ptLastMousePos; // Mouse position at last DragOver call
232 POINT m_ptFirstMousePos; // Mouse position when the drag operation started
234 //
237
241
245
247
249 BOOL _Sort(int Col = -1);
256 void _DoCopyToMoveToFolder(BOOL bCopy);
258
259public:
260 CDefView();
261 ~CDefView();
266 void UpdateStatusbar();
267 void CheckToolbar();
269 void UpdateListColors();
270 BOOL InitList();
271 static INT CALLBACK ListViewCompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lpData);
272
277 HRESULT LoadColumn(UINT FoldCol, UINT ListCol, BOOL Insert);
278 HRESULT LoadColumns(UINT *pColList = NULL, UINT ColListCount = 0);
279 void ColumnListChanged();
283 int LV_AddItem(PCUITEMID_CHILD pidl);
287 void LV_RefreshIcon(INT iItem);
288 void LV_RefreshIcons();
290 HRESULT FillList(BOOL IsRefreshCommand = TRUE);
294 HRESULT FillArrangeAsMenu(HMENU hmenuArrange);
295 HRESULT CheckViewMode(HMENU hmenuView);
299 void OnDeactivate();
300 void DoActivate(UINT uState);
301 HRESULT drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
303 LRESULT OnExplorerCommand(UINT uCommand, BOOL bUseSelection);
304
305 // *** IOleWindow methods ***
306 STDMETHOD(GetWindow)(HWND *lphwnd) override;
307 STDMETHOD(ContextSensitiveHelp)(BOOL fEnterMode) override;
308
309 // *** IShellView methods ***
310 STDMETHOD(TranslateAccelerator)(MSG *pmsg) override;
311 STDMETHOD(EnableModeless)(BOOL fEnable) override;
312 STDMETHOD(UIActivate)(UINT uState) override;
313 STDMETHOD(Refresh)() override;
314 STDMETHOD(CreateViewWindow)(IShellView *psvPrevious, LPCFOLDERSETTINGS pfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd) override;
315 STDMETHOD(DestroyViewWindow)() override;
318 STDMETHOD(SaveViewState)() override;
319 STDMETHOD(SelectItem)(PCUITEMID_CHILD pidlItem, SVSIF uFlags) override;
320 STDMETHOD(GetItemObject)(UINT uItem, REFIID riid, void **ppv) override;
321
322 // *** IShellView2 methods ***
323 STDMETHOD(GetView)(SHELLVIEWID *view_guid, ULONG view_type) override;
324 STDMETHOD(CreateViewWindow2)(LPSV2CVW2_PARAMS view_params) override;
325 STDMETHOD(HandleRename)(LPCITEMIDLIST new_pidl) override;
327
328 // *** IShellView3 methods ***
330 IShellBrowser *psb,
331 IShellView *psvPrevious,
332 SV3CVW3_FLAGS view_flags,
336 const SHELLVIEWID *view_id,
337 const RECT *prcView,
338 HWND *hwnd) override;
339
340 // *** IFolderView methods ***
341 STDMETHOD(GetCurrentViewMode)(UINT *pViewMode) override;
342 STDMETHOD(SetCurrentViewMode)(UINT ViewMode) override;
343 STDMETHOD(GetFolder)(REFIID riid, void **ppv) override;
344 STDMETHOD(Item)(int iItemIndex, PITEMID_CHILD *ppidl) override;
345 STDMETHOD(ItemCount)(UINT uFlags, int *pcItems) override;
346 STDMETHOD(Items)(UINT uFlags, REFIID riid, void **ppv) override;
347 STDMETHOD(GetSelectionMarkedItem)(int *piItem) override;
348 STDMETHOD(GetFocusedItem)(int *piItem) override;
349 STDMETHOD(GetItemPosition)(PCUITEMID_CHILD pidl, POINT *ppt) override;
350 STDMETHOD(GetSpacing)(POINT *ppt) override;
351 STDMETHOD(GetDefaultSpacing)(POINT *ppt) override;
352 STDMETHOD(GetAutoArrange)() override;
353 STDMETHOD(SelectItem)(int iItem, DWORD dwFlags) override;
355
356 // *** IShellFolderView methods ***
357 STDMETHOD(Rearrange)(LPARAM sort) override;
359 STDMETHOD(ArrangeGrid)() override;
360 STDMETHOD(AutoArrange)() override;
361 STDMETHOD(AddObject)(PITEMID_CHILD pidl, UINT *item) override;
362 STDMETHOD(GetObject)(PITEMID_CHILD *pidl, UINT item) override;
363 STDMETHOD(RemoveObject)(PITEMID_CHILD pidl, UINT *item) override;
366 STDMETHOD(UpdateObject)(PITEMID_CHILD pidl_old, PITEMID_CHILD pidl_new, UINT *item) override;
368 STDMETHOD(SetRedraw)(BOOL redraw) override;
371 STDMETHOD(IsDropOnSource)(IDropTarget *drop_target) override;
372 STDMETHOD(GetDragPoint)(POINT *pt) override;
373 STDMETHOD(GetDropPoint)(POINT *pt) override;
375 STDMETHOD(SetItemPos)(PCUITEMID_CHILD pidl, POINT *pt) override;
376 STDMETHOD(IsBkDropTarget)(IDropTarget *drop_target) override;
377 STDMETHOD(SetClipboard)(BOOL move) override;
379 STDMETHOD(GetItemSpacing)(ITEMSPACING *spacing) override;
380 STDMETHOD(SetCallback)(IShellFolderViewCB *new_cb, IShellFolderViewCB **old_cb) override;
381 STDMETHOD(Select)(UINT flags) override;
382 STDMETHOD(QuerySupport)(UINT *support) override;
383 STDMETHOD(SetAutomationObject)(IDispatch *disp) override;
384
385 // *** IOleCommandTarget methods ***
386 STDMETHOD(QueryStatus)(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText) override;
387 STDMETHOD(Exec)(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut) override;
388
389 // *** IDropTarget methods ***
390 STDMETHOD(DragEnter)(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) override;
391 STDMETHOD(DragOver)(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) override;
392 STDMETHOD(DragLeave)() override;
393 STDMETHOD(Drop)(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) override;
394
395 // *** IDropSource methods ***
396 STDMETHOD(QueryContinueDrag)(BOOL fEscapePressed, DWORD grfKeyState) override;
397 STDMETHOD(GiveFeedback)(DWORD dwEffect) override;
398
399 // *** IViewObject methods ***
400 STDMETHOD(Draw)(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd,
401 HDC hdcTargetDev, HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL lprcWBounds,
402 BOOL (STDMETHODCALLTYPE *pfnContinue)(ULONG_PTR dwContinue), ULONG_PTR dwContinue) override;
403 STDMETHOD(GetColorSet)(DWORD dwDrawAspect, LONG lindex, void *pvAspect,
404 DVTARGETDEVICE *ptd, HDC hicTargetDev, LOGPALETTE **ppColorSet) override;
405 STDMETHOD(Freeze)(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze) override;
406 STDMETHOD(Unfreeze)(DWORD dwFreeze) override;
407 STDMETHOD(SetAdvise)(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink) override;
408 STDMETHOD(GetAdvise)(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink) override;
409
410 // *** IServiceProvider methods ***
411 STDMETHOD(QueryService)(REFGUID guidService, REFIID riid, void **ppvObject) override;
412
413 // Message handlers
416 LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
422 LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
424 LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
428 LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
429 LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
435
436 virtual VOID OnFinalMessage(HWND) override;
437
439 {
440 static ATL::CWndClassInfo wc =
441 {
443 0, 0, NULL, NULL,
444 LoadCursor(NULL, IDC_ARROW), NULL, NULL, L"SHELLDLL_DefView", NULL
445 },
446 NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
447 };
448 return wc;
449 }
450
452 {
453 return WindowProc;
454 }
455
457 {
458 CDefView *pThis;
460
461 // Must hold a reference during message handling
462 pThis = reinterpret_cast<CDefView *>(hWnd);
463 pThis->AddRef();
465 pThis->Release();
466 return result;
467 }
468
493
495 // Windows returns E_NOINTERFACE for IOleWindow
496 // COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow)
497 COM_INTERFACE_ENTRY_IID(IID_IShellView, IShellView)
499 COM_INTERFACE_ENTRY_IID(IID_IShellView2, IShellView2)
500 COM_INTERFACE_ENTRY_IID(IID_IShellView3, IShellView3)
501 COM_INTERFACE_ENTRY_IID(IID_IFolderView, IFolderView)
502 COM_INTERFACE_ENTRY_IID(IID_IShellFolderView, IShellFolderView)
503 COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget)
504 COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget)
505 COM_INTERFACE_ENTRY_IID(IID_IDropSource, IDropSource)
507 COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider)
509};
510
511#define ID_LISTVIEW 1
512
513// windowsx.h
514#define GET_WM_COMMAND_ID(wp, lp) LOWORD(wp)
515#define GET_WM_COMMAND_HWND(wp, lp) (HWND)(lp)
516#define GET_WM_COMMAND_CMD(wp, lp) HIWORD(wp)
517
519
521 m_ListView(),
523 m_hMenu(NULL),
528 m_uState(0),
529 m_cidl(0),
530 m_apidl(NULL),
532 m_hNotify(0),
533 m_hAccel(NULL),
534 m_dwAspects(0),
535 m_dwAdvf(0),
542{
550
553}
554
556{
557 TRACE(" destroying IShellView(%p)\n", this);
558
560
562 {
565 }
566
567 if (m_hWnd)
568 {
570 }
571
574}
575
577{
578 m_pSFParent = shellFolder;
580 shellFolder->QueryInterface(IID_PPV_ARG(IShellDetails, &m_pSDParent));
581
582 return S_OK;
583}
584
585// ##### helperfunctions for communication with ICommDlgBrowser #####
586
588{
589 HRESULT ret = S_OK;
590
591 if (m_pCommDlgBrowser.p != NULL)
592 {
593 TRACE("ICommDlgBrowser::IncludeObject pidl=%p\n", pidl);
594 ret = m_pCommDlgBrowser->IncludeObject(this, pidl);
595 TRACE("-- returns 0x%08x\n", ret);
596 }
597
598 return ret;
599}
600
602{
604
605 if (m_pCommDlgBrowser.p != NULL)
606 {
607 TRACE("ICommDlgBrowser::OnDefaultCommand\n");
608 ret = m_pCommDlgBrowser->OnDefaultCommand(this);
609 TRACE("-- returns 0x%08x\n", ret);
610 }
611
612 return ret;
613}
614
616{
618
619 if (m_pCommDlgBrowser.p != NULL)
620 {
621 TRACE("ICommDlgBrowser::OnStateChange flags=%x\n", uFlags);
622 ret = m_pCommDlgBrowser->OnStateChange(this, uFlags);
623 TRACE("--\n");
624 }
625
626 return ret;
627}
628/**********************************************************
629 * set the toolbar of the filedialog buttons
630 *
631 * - activates the buttons from the shellbrowser according to
632 * the view state
633 */
635{
637
638 TRACE("\n");
639
640 if (m_pCommDlgBrowser != NULL)
641 {
642 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_CHECKBUTTON,
644 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_CHECKBUTTON,
646 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON,
648 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON,
650 }
651}
652
654{
655 WCHAR szFormat[MAX_PATH] = {0};
656 WCHAR szPartText[MAX_PATH] = {0};
657 UINT cSelectedItems;
658
659 if (!m_ListView)
660 return;
661
662 cSelectedItems = m_ListView.GetSelectedCount();
663 if (cSelectedItems)
664 {
666 StringCchPrintfW(szPartText, _countof(szPartText), szFormat, cSelectedItems);
667 }
668 else
669 {
670 LoadStringW(shell32_hInstance, IDS_OBJECTS, szFormat, _countof(szFormat));
671 StringCchPrintfW(szPartText, _countof(szPartText), szFormat, m_ListView.GetItemCount());
672 }
673
674 LRESULT lResult;
675 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXT, 0, (LPARAM)szPartText, &lResult);
676
677 // Don't bother with the extra processing if we only have one StatusBar part
679 {
680 UINT64 uTotalFileSize = 0;
681 WORD uFileFlags = LVNI_ALL;
682 LPARAM pIcon = NULL;
683 INT nItem = -1;
684 bool bIsOnlyFoldersSelected = true;
685
686 // If we have something selected then only count selected file sizes
687 if (cSelectedItems)
688 {
689 uFileFlags = LVNI_SELECTED;
690 }
691
692 while ((nItem = m_ListView.GetNextItem(nItem, uFileFlags)) >= 0)
693 {
694 PCUITEMID_CHILD pidl = _PidlByItem(nItem);
695
696 uTotalFileSize += _ILGetFileSize(pidl, NULL, 0);
697
698 if (!_ILIsFolder(pidl))
699 {
700 bIsOnlyFoldersSelected = false;
701 }
702 }
703
704 // Don't show the file size text if there is 0 bytes in the folder
705 // OR we only have folders selected
706 if ((cSelectedItems && !bIsOnlyFoldersSelected) || uTotalFileSize)
707 {
708 StrFormatByteSizeW(uTotalFileSize, szPartText, _countof(szPartText));
709 }
710 else
711 {
712 *szPartText = 0;
713 }
714
715 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXT, 1, (LPARAM)szPartText, &lResult);
716
717 // If we are in a Recycle Bin then show no text for the location part
719 {
720 LoadStringW(shell32_hInstance, IDS_MYCOMPUTER, szPartText, _countof(szPartText));
721 pIcon = (LPARAM)m_hMyComputerIcon;
722 }
723
724 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETICON, 2, pIcon, &lResult);
725 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXT, 2, (LPARAM)szPartText, &lResult);
726 }
727
728 SFGAOF att = 0;
729 if (cSelectedItems > 0)
730 {
731 UINT maxquery = 42; // Checking the attributes can be slow, only check small selections (_DoCopyToMoveToFolder will verify the full array)
732 att = SFGAO_CANCOPY | SFGAO_CANMOVE;
733 if (cSelectedItems <= maxquery && (!GetSelections() || FAILED(m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &att))))
734 att = 0;
735 }
736 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON, FCIDM_SHVIEW_COPYTO, (att & SFGAO_CANCOPY) != 0, &lResult);
737 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON, FCIDM_SHVIEW_MOVETO, (att & SFGAO_CANMOVE) != 0, &lResult);
738}
739
741{
744 return 0;
745}
746
747
748// ##### helperfunctions for initializing the view #####
749
750// creates the list view window
752{
753 HRESULT hr;
754 DWORD dwStyle, dwExStyle, ListExStyle;
755 UINT ViewMode;
756
757 TRACE("%p\n", this);
758
760 LVS_SHAREIMAGELISTS | LVS_EDITLABELS | LVS_AUTOARRANGE; // FIXME: Why is LVS_AUTOARRANGE here?
761 dwExStyle = WS_EX_CLIENTEDGE;
762 ListExStyle = 0;
763
765 {
767 dwStyle |= LVS_ALIGNLEFT;
768 }
769 else
770 {
771 dwStyle |= LVS_SHOWSELALWAYS; // MSDN says FWF_SHOWSELALWAYS is deprecated, always turn on for folders
773 ListExStyle = LVS_EX_DOUBLEBUFFER;
774 }
775
776 ViewMode = m_FolderSettings.ViewMode;
777 hr = _DoFolderViewCB(SFVM_DEFVIEWMODE, 0, (LPARAM)&ViewMode);
778 if (SUCCEEDED(hr))
779 {
780 if (ViewMode >= FVM_FIRST && ViewMode <= FVM_LAST)
781 m_FolderSettings.ViewMode = ViewMode;
782 else
783 ERR("Ignoring invalid ViewMode from SFVM_DEFVIEWMODE: %u (was: %u)\n", ViewMode, m_FolderSettings.ViewMode);
784 }
785
787 {
788 case FVM_ICON:
789 dwStyle |= LVS_ICON;
790 break;
791 case FVM_DETAILS:
792 dwStyle |= LVS_REPORT;
793 break;
794 case FVM_SMALLICON:
795 dwStyle |= LVS_SMALLICON;
796 break;
797 case FVM_LIST:
798 dwStyle |= LVS_LIST;
799 break;
800 default:
801 dwStyle |= LVS_LIST;
802 break;
803 }
804
806 dwStyle |= LVS_AUTOARRANGE;
807
809 ListExStyle |= LVS_EX_SNAPTOGRID;
810
812 dwStyle |= LVS_SINGLESEL;
813
815 ListExStyle |= LVS_EX_FULLROWSELECT;
816
818 (!SHELL_GetSetting(SSF_DOUBLECLICKINWEBVIEW, fDoubleClickInWebView) && !SHELL_GetSetting(SSF_WIN95CLASSIC, fWin95Classic)))
820
822 dwStyle |= LVS_NOCOLUMNHEADER;
823
824#if 0
825 // FIXME: Because this is a negative, everyone gets the new flag by default unless they
826 // opt out. This code should be enabled when shell looks like Vista instead of 2003
828 ListExStyle |= LVS_EX_HEADERINALLVIEWS;
829#endif
830
832 dwExStyle &= ~WS_EX_CLIENTEDGE;
833
834 RECT rcListView = {0,0,0,0};
835 m_ListView.Create(m_hWnd, rcListView, L"FolderView", dwStyle, dwExStyle, ID_LISTVIEW);
836
837 if (!m_ListView)
838 return FALSE;
839
841
844
845 /* UpdateShellSettings(); */
846 return TRUE;
847}
848
850{
852 {
853 /* Check if drop shadows option is enabled */
854 BOOL bDropShadow = FALSE;
855 DWORD cbDropShadow = sizeof(bDropShadow);
856
857 /*
858 * The desktop ListView always take the default desktop colours, by
859 * remaining transparent and letting user32/win32k paint itself the
860 * desktop background color, if any.
861 */
863
864 SHGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
865 L"ListviewShadow", NULL, &bDropShadow, &cbDropShadow);
866 if (bDropShadow)
867 {
868 /* Set the icon background transparent */
870 m_ListView.SetTextColor(RGB(255, 255, 255));
871 m_ListView.SetExtendedListViewStyle(LVS_EX_TRANSPARENTSHADOWTEXT, LVS_EX_TRANSPARENTSHADOWTEXT);
872 }
873 else
874 {
875 /* Set the icon background as the same colour as the desktop */
877 m_ListView.SetTextBkColor(crDesktop);
878 if (GetRValue(crDesktop) + GetGValue(crDesktop) + GetBValue(crDesktop) > 128 * 3)
879 m_ListView.SetTextColor(RGB(0, 0, 0));
880 else
881 m_ListView.SetTextColor(RGB(255, 255, 255));
882 m_ListView.SetExtendedListViewStyle(0, LVS_EX_TRANSPARENTSHADOWTEXT);
883 }
884 }
885 else
886 {
887 // text background color
889 m_ListView.SetTextBkColor(clrTextBack);
890
891 // text color
892 COLORREF clrText;
894 clrText = m_viewinfo_data.clrText;
895 else
896 clrText = GetSysColor(COLOR_WINDOWTEXT);
897
898 m_ListView.SetTextColor(clrText);
899
900 // Background is painted by the parent via WM_PRINTCLIENT
901 m_ListView.SetExtendedListViewStyle(LVS_EX_TRANSPARENTBKGND, LVS_EX_TRANSPARENTBKGND);
902 }
903}
904
905// adds all needed columns to the shellview
907{
908 HIMAGELIST big_icons, small_icons;
909
910 TRACE("%p\n", this);
911
913
914 Shell_GetImageLists(&big_icons, &small_icons);
916 m_ListView.SetImageList(small_icons, LVSIL_SMALL);
917
919 LoadColumns();
920 return TRUE;
921}
922
923/**********************************************************
924* Column handling
925*/
927{
928 LVCOLUMN lvc;
929 lvc.mask = LVCF_SUBITEM;
930 if (!ListView_GetColumn(List, Col, &lvc))
931 return E_FAIL;
932 else
933 return lvc.iSubItem;
934}
935
937{
938 // This function is only called during column management, performance is not critical.
939 for (UINT i = 0;; ++i)
940 {
942 if ((UINT)r == FoldCol)
943 return i;
944 else if (FAILED(r))
945 return r;
946 }
947}
948
950{
951 // This function is called every time a LVITEM::iSubItem is mapped to
952 // a folder column (calls to GetDetailsOf etc.) and should be fast.
954 {
956 if (ListCol < count)
957 {
959 assert(col >= 0 && col == SHGetLVColumnSubItem(m_ListView.m_hWnd, ListCol));
960 return col;
961 }
962 else if (count)
963 {
964 TRACE("m_ListToFolderColMap cache miss while mapping %d\n", ListCol);
965 }
966 }
967 return SHGetLVColumnSubItem(m_ListView.m_hWnd, ListCol);
968}
969
971{
972 // According to learn.microsoft.com/en-us/windows/win32/shell/sfvm-getdetailsof
973 // the query order is IShellFolder2, IShellDetails, SFVM_GETDETAILSOF.
974 HRESULT hr;
975 if (m_pSF2Parent)
976 {
977 hr = m_pSF2Parent->GetDetailsOf(pidl, FoldCol, &sd);
978 }
979 if (FAILED(hr) && m_pSDParent)
980 {
981 hr = m_pSDParent->GetDetailsOf(pidl, FoldCol, &sd);
982 }
983#if 0 // TODO
984 if (FAILED(hr))
985 {
986 FIXME("Try SFVM_GETDETAILSOF\n");
987 }
988#endif
989 return hr;
990}
991
993{
995 if (SUCCEEDED(hr))
996 return GetDetailsByFolderColumn(pidl, hr, sd);
997 ERR("Unable to determine folder column from list column %d\n", (int) ListCol);
998 return hr;
999}
1000
1001HRESULT CDefView::LoadColumn(UINT FoldCol, UINT ListCol, BOOL Insert)
1002{
1005 HRESULT hr;
1006
1007 sd.str.uType = !STRRET_WSTR; // Make sure "uninitialized" uType is not WSTR
1008 hr = GetDetailsByFolderColumn(NULL, FoldCol, sd);
1009 if (FAILED(hr))
1010 return hr;
1011 hr = StrRetToStrNW(buf, _countof(buf), &sd.str, NULL);
1012 if (FAILED(hr))
1013 return hr;
1014
1015 UINT chavewidth = CalculateCharWidth(m_ListView.m_hWnd);
1016 if (!chavewidth)
1017 chavewidth = 6; // 6 is a reasonable default fallback
1018
1019 LVCOLUMN lvc;
1020 lvc.mask = LVCF_TEXT | LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM;
1021 lvc.pszText = buf;
1022 lvc.fmt = sd.fmt;
1023 lvc.cx = sd.cxChar * chavewidth; // FIXME: DPI?
1024 lvc.iSubItem = FoldCol; // Used by MapFolderColumnToListColumn & MapListColumnToFolderColumn
1025 if ((int)ListCol == -1)
1026 {
1027 assert(Insert); // You can insert at the end but you can't change something that is not there
1028 if (Insert)
1029 ListCol = 0x7fffffff;
1030 }
1031 if (Insert)
1032 ListView_InsertColumn(m_ListView.m_hWnd, ListCol, &lvc);
1033 else
1034 ListView_SetColumn(m_ListView.m_hWnd, ListCol, &lvc);
1035 return S_OK;
1036}
1037
1038HRESULT CDefView::LoadColumns(UINT *pColList, UINT ColListCount)
1039{
1040 HWND hWndHdr = ListView_GetHeader(m_ListView.m_hWnd);
1041 UINT newColCount = 0, oldColCount = Header_GetItemCount(hWndHdr);
1042 UINT foldCol, i;
1043 HRESULT hr = S_FALSE;
1044
1046 for (i = 0, foldCol = 0;; ++foldCol)
1047 {
1048 if (newColCount >= 0xffff)
1049 break; // CompareIDs limit reached
1050
1051 if (pColList)
1052 {
1053 if (i >= ColListCount)
1054 break;
1055 foldCol = pColList[i++];
1056 }
1057
1058 SHCOLSTATEF state = 0;
1059 if (!m_pSF2Parent || FAILED(m_pSF2Parent->GetDefaultColumnState(foldCol, &state)))
1061
1062 if (foldCol == 0)
1063 {
1064 // Force the first column
1065 }
1066 else if (state & SHCOLSTATE_HIDDEN)
1067 {
1068 continue;
1069 }
1070 else if (!pColList && !(state & SHCOLSTATE_ONBYDEFAULT))
1071 {
1072 continue;
1073 }
1074
1075 bool insert = newColCount >= oldColCount;
1076 UINT listCol = insert ? -1 : newColCount;
1077 hr = LoadColumn(foldCol, listCol, insert);
1078 if (FAILED(hr))
1079 {
1080 if (!pColList)
1081 hr = S_OK; // No more items, we are done
1082 break;
1083 }
1084 ++newColCount;
1085 }
1086 for (i = newColCount; i < oldColCount; ++i)
1087 {
1089 }
1090
1093 assert(SUCCEEDED(MapFolderColumnToListColumn(0))); // We don't allow turning off the Name column
1094 return hr;
1095}
1096
1098{
1100 m_ListToFolderColMap = NULL; // No cache while we are building the cache
1102 for (UINT i = 0;; ++i)
1103 {
1105 if (FAILED(hr))
1106 break; // No more columns
1107 if (!DPA_SetPtr(cache, i, (void*)(INT_PTR) hr))
1108 break; // Cannot allow holes in the cache, must stop now.
1109 }
1111
1112 for (;;)
1113 {
1115 break;
1116 }
1118 if (hMenu)
1119 {
1120 hMenu = GetSubmenuByID(hMenu, FCIDM_SHVIEW_ARRANGE);
1121 for (UINT i = DVIDM_ARRANGESORT_FIRST; i <= DVIDM_ARRANGESORT_LAST && hMenu; ++i)
1122 {
1123 RemoveMenu(hMenu, i, MF_BYCOMMAND);
1124 }
1125 if ((int) GetMenuItemID(hMenu, 0) <= 0)
1126 RemoveMenu(hMenu, 0, MF_BYPOSITION); // Separator
1127 }
1129 LVCOLUMN lvc;
1130 lvc.mask = LVCF_TEXT;
1131 lvc.pszText = buf;
1132 lvc.cchTextMax = _countof(buf);
1133 for (UINT listCol = 0; listCol < DEFVIEW_ARRANGESORT_MAXENUM; ++listCol)
1134 {
1135 if (!ListView_GetColumn(m_ListView.m_hWnd, listCol, &lvc))
1136 break;
1137 HRESULT foldCol = MapListColumnToFolderColumn(listCol);
1138 assert(SUCCEEDED(foldCol));
1140 DVIDM_ARRANGESORT_FIRST + listCol, lvc.pszText, listCol);
1141 }
1142
1143 ListView_RedrawItems(m_ListView.m_hWnd, 0, 0x7fffffff);
1144 m_ListView.InvalidateRect(NULL, TRUE);
1145}
1146
1147/*************************************************************************
1148 * ShellView_ListViewCompareItems
1149 *
1150 * Compare Function for the Listview (FileOpen Dialog)
1151 *
1152 * PARAMS
1153 * lParam1 [I] the first ItemIdList to compare with
1154 * lParam2 [I] the second ItemIdList to compare with
1155 * lpData [I] The column ID for the header Ctrl to process
1156 *
1157 * RETURNS
1158 * A negative value if the first item should precede the second,
1159 * a positive value if the first item should follow the second,
1160 * or zero if the two items are equivalent
1161 */
1163{
1164 PCUIDLIST_RELATIVE pidl1 = reinterpret_cast<PCUIDLIST_RELATIVE>(lParam1);
1165 PCUIDLIST_RELATIVE pidl2 = reinterpret_cast<PCUIDLIST_RELATIVE>(lParam2);
1166 CDefView *pThis = reinterpret_cast<CDefView*>(lpData);
1167
1168 HRESULT hres = pThis->m_pSFParent->CompareIDs(pThis->m_sortInfo.ListColumn, pidl1, pidl2);
1170 return 0;
1171
1172 SHORT nDiff = HRESULT_CODE(hres);
1173 if (!pThis->m_sortInfo.bIsAscending)
1174 nDiff = -nDiff;
1175 return nDiff;
1176}
1177
1179{
1180 HWND hHeader;
1181 HDITEM hColumn;
1182 int prevCol = m_sortInfo.ListColumn;
1183
1184 // FIXME: Is this correct? Who sets this style?
1185 // And if it is set, should it also block sorting using the menu?
1186 // Any why should it block sorting when the view is loaded initially?
1187 if (m_ListView.GetWindowLongPtr(GWL_STYLE) & LVS_NOSORTHEADER)
1188 return TRUE;
1189
1190 hHeader = ListView_GetHeader(m_ListView.m_hWnd);
1191 if (Col != -1)
1192 {
1193 if (Col >= Header_GetItemCount(hHeader))
1194 {
1195 ERR("Sort column out of range\n");
1196 return FALSE;
1197 }
1198
1199 if (prevCol == Col)
1201 else
1203 m_sortInfo.ListColumn = Col;
1204 }
1205
1206 /* If the sorting column changed, remove the sorting style from the old column */
1207 if (prevCol != -1 && prevCol != m_sortInfo.ListColumn)
1208 {
1209 hColumn.mask = HDI_FORMAT;
1210 Header_GetItem(hHeader, prevCol, &hColumn);
1211 hColumn.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN);
1212 Header_SetItem(hHeader, prevCol, &hColumn);
1213 }
1214
1215 /* Set the sorting style on the new column */
1216 hColumn.mask = HDI_FORMAT;
1217 Header_GetItem(hHeader, m_sortInfo.ListColumn, &hColumn);
1218 hColumn.fmt &= (m_sortInfo.bIsAscending ? ~HDF_SORTDOWN : ~HDF_SORTUP );
1219 hColumn.fmt |= (m_sortInfo.bIsAscending ? HDF_SORTUP : HDF_SORTDOWN);
1220 Header_SetItem(hHeader, m_sortInfo.ListColumn, &hColumn);
1221
1222 /* Sort the list, using the current values of ListColumn and bIsAscending */
1224}
1225
1227{
1228 if (!m_ListView)
1229 return nullptr;
1230 return reinterpret_cast<PCUITEMID_CHILD>(m_ListView.GetItemData(i));
1231}
1232
1234{
1235 if (!m_ListView)
1236 return nullptr;
1237 return reinterpret_cast<PCUITEMID_CHILD>(lvItem.lParam);
1238}
1239
1241{
1243
1244 int cItems = m_ListView.GetItemCount();
1245
1246 for (int i = 0; i<cItems; i++)
1247 {
1248 PCUITEMID_CHILD currentpidl = _PidlByItem(i);
1249 if (ILIsEqual(pidl, currentpidl))
1250 return i;
1251 }
1252 return -1;
1253}
1254
1256{
1257 LVITEMW lvItem;
1258
1259 TRACE("(%p)(pidl=%p)\n", this, pidl);
1260
1262
1264 return -1;
1265
1266 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM; // set mask
1267 lvItem.iItem = m_ListView.GetItemCount(); // add item to lists end
1268 lvItem.iSubItem = 0;
1269 lvItem.lParam = reinterpret_cast<LPARAM>(ILClone(pidl)); // set item's data
1270 lvItem.pszText = LPSTR_TEXTCALLBACKW; // get text on a callback basis
1271 lvItem.iImage = I_IMAGECALLBACK; // get image on a callback basis
1272 lvItem.stateMask = LVIS_CUT;
1273
1274 return m_ListView.InsertItem(&lvItem);
1275}
1276
1278{
1279 int nIndex;
1280
1281 TRACE("(%p)(pidl=%p)\n", this, pidl);
1282
1284
1285 nIndex = LV_FindItemByPidl(pidl);
1286 if (nIndex < 0)
1287 return FALSE;
1288
1290
1291 return m_ListView.DeleteItem(nIndex);
1292}
1293
1295{
1296 int nItem;
1297 LVITEMW lvItem;
1298
1299 TRACE("(%p)(pidlold=%p pidlnew=%p)\n", this, pidlOld, pidlNew);
1300
1302
1303 nItem = LV_FindItemByPidl(pidlOld);
1304
1305 if (-1 != nItem)
1306 {
1307 lvItem.mask = LVIF_PARAM; // only the pidl
1308 lvItem.iItem = nItem;
1309 lvItem.iSubItem = 0;
1310 m_ListView.GetItem(&lvItem);
1311
1312 // Store old pidl until new item is replaced
1313 LPVOID oldPidl = reinterpret_cast<LPVOID>(lvItem.lParam);
1314
1315 lvItem.mask = LVIF_PARAM | LVIF_IMAGE | LVIF_TEXT;
1316 lvItem.iItem = nItem;
1317 lvItem.iSubItem = 0;
1318 lvItem.lParam = reinterpret_cast<LPARAM>(ILClone(pidlNew)); // set item's data
1321 m_ListView.SetItem(&lvItem);
1322 m_ListView.Update(nItem);
1323
1324 // Now that the new item is in place, we can safely release the old pidl
1325 SHFree(oldPidl);
1326
1327 return TRUE; // FIXME: better handling
1328 }
1329
1330 return FALSE;
1331}
1332
1334{
1335 int nItem;
1336 LVITEMW lvItem;
1337
1338 TRACE("(%p)(pidl=%p)\n", this, pidl);
1339
1341
1342 nItem = LV_FindItemByPidl(pidl);
1343
1344 if (-1 != nItem)
1345 {
1347
1348 lvItem.mask = LVIF_IMAGE;
1349 lvItem.iItem = nItem;
1350 lvItem.iSubItem = 0;
1352 m_ListView.SetItem(&lvItem);
1353 m_ListView.Update(nItem);
1354 return TRUE;
1355 }
1356
1357 return FALSE;
1358}
1359
1361{
1363
1364 LVITEMW lvItem = { LVIF_IMAGE };
1365 lvItem.iItem = iItem;
1366 lvItem.iImage = I_IMAGECALLBACK;
1367 m_ListView.SetItem(&lvItem);
1368 m_ListView.Update(iItem);
1369}
1370
1372{
1374
1375 for (INT iItem = -1;;)
1376 {
1377 iItem = ListView_GetNextItem(m_ListView, iItem, LVNI_ALL);
1378 if (iItem == -1)
1379 break;
1380
1381 LV_RefreshIcon(iItem);
1382 }
1383}
1384
1386{
1387 PITEMID_CHILD pidl = static_cast<PITEMID_CHILD>(ptr);
1388 CDefView *pThis = static_cast<CDefView *>(arg);
1389
1390 // in a commdlg this works as a filemask
1391 if (pThis->IncludeObject(pidl) == S_OK && pThis->m_ListView)
1392 pThis->LV_AddItem(pidl);
1393
1394 SHFree(pidl);
1395 return TRUE;
1396}
1397
1399// - gets the objectlist from the shellfolder
1400// - sorts the list
1401// - fills the list into the view
1403{
1404 CComPtr<IEnumIDList> pEnumIDList;
1405 PITEMID_CHILD pidl;
1406 DWORD dwFetched;
1407 HRESULT hRes;
1408 HDPA hdpa;
1409 DWORD dFlags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS;
1410
1411 TRACE("%p\n", this);
1412
1413 SHELLSTATE shellstate;
1415 if (shellstate.fShowAllObjects)
1416 {
1417 dFlags |= SHCONTF_INCLUDEHIDDEN;
1418 m_ListView.SendMessageW(LVM_SETCALLBACKMASK, LVIS_CUT, 0);
1419 }
1420 if (shellstate.fShowSuperHidden)
1421 {
1422 dFlags |= SHCONTF_INCLUDESUPERHIDDEN;
1423 m_ListView.SendMessageW(LVM_SETCALLBACKMASK, LVIS_CUT, 0);
1424 }
1425
1426 // get the itemlist from the shfolder
1427 hRes = m_pSFParent->EnumObjects(m_hWnd, dFlags, &pEnumIDList);
1428 if (hRes != S_OK)
1429 {
1430 if (hRes == S_FALSE)
1431 return(NOERROR);
1432 return(hRes);
1433 }
1434
1435 // create a pointer array
1436 hdpa = DPA_Create(16);
1437 if (!hdpa)
1438 return(E_OUTOFMEMORY);
1439
1440 // copy the items into the array
1441 while((S_OK == pEnumIDList->Next(1, &pidl, &dwFetched)) && dwFetched)
1442 {
1443 if (DPA_InsertPtr(hdpa, 0x7fff, pidl) == -1)
1444 {
1445 SHFree(pidl);
1446 }
1447 }
1448
1449 // turn listview's redrawing off
1451
1452 DPA_DestroyCallback( hdpa, fill_list, this);
1453
1454 /* sort the array */
1455 int sortCol = -1;
1456 if (!IsRefreshCommand) // Are we loading for the first time?
1457 {
1459 sortCol = 0; // In case the folder does not know/care
1460 if (m_pSF2Parent)
1461 {
1462 ULONG folderSortCol = sortCol, dummy;
1463 HRESULT hr = m_pSF2Parent->GetDefaultColumn(NULL, &folderSortCol, &dummy);
1464 if (SUCCEEDED(hr))
1465 hr = MapFolderColumnToListColumn(folderSortCol);
1466 if (SUCCEEDED(hr))
1467 sortCol = (int) hr;
1468 }
1469 }
1470 _Sort(sortCol);
1471
1473 {
1476 }
1477
1478 // load custom background image and custom text color
1481
1482 // turn listview's redrawing back on and force it to draw
1484
1486
1488 {
1489 // redraw now
1490 m_ListView.InvalidateRect(NULL, TRUE);
1491 }
1492
1494
1495 return S_OK;
1496}
1497
1499{
1500 if (m_ListView.IsWindow())
1501 m_ListView.UpdateWindow();
1502 bHandled = FALSE;
1503 return 0;
1504}
1505
1507{
1508 return m_ListView.SendMessageW(uMsg, 0, 0);
1509}
1510
1512{
1513 if (!m_Destroyed)
1514 {
1515 m_Destroyed = TRUE;
1516 if (m_hMenu)
1517 {
1519 m_hMenu = NULL;
1520 }
1523 m_hNotify = NULL;
1526 }
1527 bHandled = FALSE;
1528 return 0;
1529}
1530
1532{
1533 /* redirect to parent */
1536
1537 bHandled = FALSE;
1538 return 0;
1539}
1540
1541static VOID
1543{
1544 INT x0 = prc->left, y0 = prc->top, x1 = prc->right, y1 = prc->bottom;
1545 x0 += dx;
1546 y0 += dy;
1547
1548 HDC hMemDC = CreateCompatibleDC(hDC);
1549 HGDIOBJ hbmOld = SelectObject(hMemDC, hbm);
1550
1551 for (INT y = y0; y < y1; y += nHeight)
1552 {
1553 for (INT x = x0; x < x1; x += nWidth)
1554 {
1555 BitBlt(hDC, x, y, nWidth, nHeight, hMemDC, 0, 0, SRCCOPY);
1556 }
1557 }
1558
1559 SelectObject(hMemDC, hbmOld);
1560 DeleteDC(hMemDC);
1561}
1562
1564{
1565 HDC hDC = (HDC)wParam;
1566
1567 RECT rc;
1569
1571 {
1572 BITMAP bm;
1573 if (::GetObject(m_viewinfo_data.hbmBack, sizeof(BITMAP), &bm))
1574 {
1575 INT dx = -(::GetScrollPos(m_ListView, SB_HORZ) % bm.bmWidth);
1576 INT dy = -(::GetScrollPos(m_ListView, SB_VERT) % bm.bmHeight);
1577 DrawTileBitmap(hDC, &rc, m_viewinfo_data.hbmBack, bm.bmWidth, bm.bmHeight, dx, dy);
1578 }
1579 }
1580 else
1581 {
1583 }
1584
1585 bHandled = TRUE;
1586
1587 return TRUE;
1588}
1589
1591{
1592 /* Update desktop labels color */
1594
1595 /* Forward WM_SYSCOLORCHANGE to common controls */
1596 return m_ListView.SendMessageW(uMsg, 0, 0);
1597}
1598
1600{
1601 return reinterpret_cast<LRESULT>(m_pShellBrowser.p);
1602}
1603
1605{
1606 this->AddRef();
1607 bHandled = FALSE;
1608 return 0;
1609}
1610
1612{
1613 this->Release();
1614}
1615
1617{
1620
1621 TRACE("%p\n", this);
1622
1624 {
1625 if (FAILED(RegisterDragDrop(m_hWnd, pdt)))
1626 ERR("Error Registering DragDrop\n");
1627 }
1628
1629 /* register for receiving notifications */
1630 m_pSFParent->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
1631 if (ppf2)
1632 {
1633 ppf2->GetCurFolder(&m_pidlParent);
1634 }
1635
1636 if (CreateList())
1637 {
1638 if (InitList())
1639 {
1640 FillList(FALSE);
1641 }
1642 }
1643
1645 {
1646 HWND hwndSB;
1647 m_pShellBrowser->GetWindow(&hwndSB);
1649 }
1650
1651 // Set up change notification
1652 LPITEMIDLIST pidlTarget = NULL;
1653 LONG fEvents = 0;
1654 HRESULT hr = _DoFolderViewCB(SFVM_GETNOTIFY, (WPARAM)&pidlTarget, (LPARAM)&fEvents);
1655 if (FAILED(hr) || (!pidlTarget && !fEvents))
1656 {
1657 pidlTarget = m_pidlParent;
1658 fEvents = SHCNE_ALLEVENTS;
1659 }
1660 SHChangeNotifyEntry ntreg = {};
1662 if (FAILED(hr))
1663 {
1664 ntreg.fRecursive = FALSE;
1665 ntreg.pidl = pidlTarget;
1666 }
1670 fEvents, SHV_CHANGE_NOTIFY,
1671 1, &ntreg);
1672
1674
1675 BOOL bPreviousParentSpecial = m_isParentFolderSpecial;
1676
1677 // A folder is special if it is the Desktop folder,
1678 // a network folder, or a Control Panel folder
1681
1682 // Only force StatusBar part refresh if the state
1683 // changed from the previous folder
1684 if (bPreviousParentSpecial != m_isParentFolderSpecial)
1685 {
1686 // This handles changing StatusBar parts
1688 }
1689
1691
1692 return S_OK;
1693}
1694
1695// #### Handling of the menus ####
1696
1697extern "C" DWORD WINAPI SHMenuIndexFromID(HMENU hMenu, UINT uID);
1698
1700{
1702 if (!hFileMenu)
1703 return E_FAIL;
1704
1705 /* Cleanup the items added previously */
1706 for (int i = GetMenuItemCount(hFileMenu) - 1; i >= 0; i--)
1707 {
1708 UINT id = GetMenuItemID(hFileMenu, i);
1709 if (id < FCIDM_BROWSERFIRST || id > FCIDM_BROWSERLAST)
1710 DeleteMenu(hFileMenu, i, MF_BYPOSITION);
1711 }
1712
1713 // In case we still have this left over, clean it up
1714 if (m_pFileMenu)
1715 {
1718 }
1719 UINT selcount = m_ListView.GetSelectedCount();
1720 // Store context menu in m_pFileMenu and keep it to invoke the selected command later on
1723 return hr;
1724
1726
1727 UINT cmf = GetContextMenuFlags(m_pShellBrowser, SFGAO_CANRENAME);
1728 hr = m_pFileMenu->QueryContextMenu(hmenu, 0, DVIDM_CONTEXTMENU_FIRST, DVIDM_CONTEXTMENU_LAST, cmf);
1730 return hr;
1731
1732 // TODO: filter or something
1733
1734 Shell_MergeMenus(hFileMenu, hmenu, 0, 0, 0xFFFF, MM_ADDSEPARATOR | MM_SUBMENUSHAVEIDS);
1735
1737
1738 return S_OK;
1739}
1740
1742{
1744 if (!hEditMenu)
1745 return E_FAIL;
1746
1747 HMENU hmenuContents = ::LoadMenuW(shell32_hInstance, L"MENU_003");
1748 if (!hmenuContents)
1749 return E_FAIL;
1750
1751 Shell_MergeMenus(hEditMenu, hmenuContents, 0, 0, 0xFFFF, 0);
1752
1753 ::DestroyMenu(hmenuContents);
1754
1755 return S_OK;
1756}
1757
1759{
1761 if (!hViewMenu)
1762 return E_FAIL;
1763
1765 if (!m_hMenuViewModes)
1766 return E_FAIL;
1767
1770
1771 return S_OK;
1772}
1773
1775{
1776 bool forceMerge = false;
1778
1779 // Make sure the column we currently sort by is in the menu
1782 {
1786 LVCOLUMN lvc;
1787 lvc.mask = LVCF_TEXT;
1788 lvc.pszText = buf;
1789 lvc.cchTextMax = _countof(buf);
1790 currentSortId = DVIDM_ARRANGESORT_LAST;
1791 forceMerge = true;
1793 AppendMenuItem(m_hMenuArrangeModes, MF_STRING, currentSortId, lvc.pszText, m_sortInfo.ListColumn);
1794 }
1795
1796 // Prepend the sort-by items unless they are aleady there
1797 if (GetMenuItemID(hmenuArrange, 0) == FCIDM_SHVIEW_AUTOARRANGE || forceMerge)
1798 {
1799 Shell_MergeMenus(hmenuArrange, m_hMenuArrangeModes, 0, 0, 0xFFFF, MM_ADDSEPARATOR);
1800 }
1801
1802 CheckMenuRadioItem(hmenuArrange,
1804 currentSortId, MF_BYCOMMAND);
1805
1807 {
1810 }
1811 else
1812 {
1815
1816 if (GetAutoArrange() == S_OK)
1818 else
1820
1821 if (_GetSnapToGrid() == S_OK)
1823 else
1825 }
1826
1827 return S_OK;
1828}
1829
1831{
1833 {
1834 UINT iItemFirst = FCIDM_SHVIEW_BIGICON;
1835 UINT iItemLast = iItemFirst + FVM_LAST - FVM_FIRST;
1836 UINT iItem = iItemFirst + m_FolderSettings.ViewMode - FVM_FIRST;
1837 CheckMenuRadioItem(hmenuView, iItemFirst, iItemLast, iItem, MF_BYCOMMAND);
1838 }
1839
1840 return S_OK;
1841}
1842
1844{
1845 const UINT maxItems = 15; // Feels about right
1846 const UINT idMore = 0x1337;
1847 UINT idFirst = idMore + 1, idLast = idFirst;
1848 UINT lastValidListCol = 0; // Keep track of where the new column should be inserted
1849 UINT showMore = GetKeyState(VK_SHIFT) < 0;
1851 HWND hWndHdr = ListView_GetHeader(m_ListView.m_hWnd);
1852
1853 if (lParam == ~0)
1854 {
1855 RECT r;
1856 ::GetWindowRect(hWndHdr, &r);
1857 pt.x = r.left + ((r.right - r.left) / 2);
1858 pt.y = r.top + ((r.bottom - r.top) / 2);
1859 }
1860
1861 HMENU hMenu = CreatePopupMenu();
1862 if (!hMenu)
1863 return 0;
1864
1865 for (UINT foldCol = 0;; ++foldCol)
1866 {
1869 sd.str.uType = !STRRET_WSTR;
1870 if (FAILED(GetDetailsByFolderColumn(NULL, foldCol, sd)))
1871 break;
1872 if (FAILED(StrRetToStrNW(buf, _countof(buf), &sd.str, NULL)))
1873 break;
1874
1875 SHCOLSTATEF state = 0;
1876 if (!m_pSF2Parent || FAILED(m_pSF2Parent->GetDefaultColumnState(foldCol, &state)))
1877 state = 0;
1878 showMore |= (state & (SHCOLSTATE_SECONDARYUI));
1879
1880 UINT mf = MF_STRING;
1881 HRESULT listCol = MapFolderColumnToListColumn(foldCol);
1882
1883 if (foldCol == 0)
1884 mf |= MF_CHECKED | MF_GRAYED | MF_DISABLED; // Force column 0
1886 continue;
1887 else if (SUCCEEDED(listCol))
1888 mf |= MF_CHECKED;
1889
1890 if (AppendMenuItem(hMenu, mf, idLast, buf, lastValidListCol + 1))
1891 {
1892 idLast++;
1893 if (SUCCEEDED(listCol))
1894 lastValidListCol = listCol;
1895 }
1896
1897 if (idLast - idFirst == maxItems)
1898 {
1899 showMore++;
1900 break;
1901 }
1902 }
1903
1904 if (showMore)
1905 {
1906#if 0 // TODO
1907 InsertMenuW(hMenu, -1, MF_SEPARATOR, 0, NULL);
1908 InsertMenuW(hMenu, -1, MF_STRING, idMore, L"More...");
1909#endif
1910 }
1911
1912 // A cludge to force the cursor to update so we are not stuck with "size left/right" if
1913 // the right-click was on a column divider.
1915
1916 // Note: Uses the header as the owner so CDefView::OnInitMenuPopup does not mess us up.
1918 pt.x, pt.y, 0, hWndHdr, NULL);
1919 if (idCmd == idMore)
1920 {
1921 FIXME("Open More dialog\n");
1922 }
1923 else if (idCmd)
1924 {
1925 UINT foldCol = idCmd - idFirst;
1926 HRESULT listCol = MapFolderColumnToListColumn(foldCol);
1927 if (SUCCEEDED(listCol))
1928 {
1929 ListView_DeleteColumn(m_ListView.m_hWnd, listCol);
1930 }
1931 else
1932 {
1933 listCol = (UINT) GetMenuItemDataById(hMenu, idCmd);
1934 LoadColumn(foldCol, listCol, TRUE);
1935 }
1937 }
1938 DestroyMenu(hMenu);
1939 return 0;
1940}
1941
1942/**********************************************************
1943* ShellView_GetSelections()
1944*
1945* - fills the m_apidl list with the selected objects
1946*
1947* RETURNS
1948* number of selected items
1949*/
1951{
1953 if (count > m_cidl || !count || !m_apidl) // !count to free possibly large cache, !m_apidl to make sure m_apidl is a valid pointer
1954 {
1955 SHFree(m_apidl);
1956 m_apidl = static_cast<PCUITEMID_CHILD*>(SHAlloc(count * sizeof(PCUITEMID_CHILD)));
1957 if (!m_apidl)
1958 {
1959 m_cidl = 0;
1960 return 0;
1961 }
1962 }
1963 m_cidl = count;
1964
1965 TRACE("-- Items selected =%u\n", m_cidl);
1966
1968
1969 UINT i = 0;
1970 int lvIndex = -1;
1971 while ((lvIndex = m_ListView.GetNextItem(lvIndex, LVNI_SELECTED)) > -1)
1972 {
1973 m_apidl[i] = _PidlByItem(lvIndex);
1974 i++;
1975 if (i == m_cidl)
1976 break;
1977 TRACE("-- selected Item found\n");
1978 }
1979
1980 return m_cidl;
1981}
1982
1984{
1985 CMINVOKECOMMANDINFOEX cmi;
1986
1987 ZeroMemory(&cmi, sizeof(cmi));
1988 cmi.cbSize = sizeof(cmi);
1989 cmi.hwnd = m_hWnd;
1990 cmi.lpVerb = lpVerb;
1991 cmi.nShow = SW_SHOW;
1992
1993 if (GetKeyState(VK_SHIFT) < 0)
1994 cmi.fMask |= CMIC_MASK_SHIFT_DOWN;
1995
1997 cmi.fMask |= CMIC_MASK_CONTROL_DOWN;
1998
1999 if (pt)
2000 {
2001 cmi.fMask |= CMIC_MASK_PTINVOKE;
2002 cmi.ptInvoke = *pt;
2003 }
2004
2005 WCHAR szDirW[MAX_PATH] = L"";
2006 CHAR szDirA[MAX_PATH];
2008 *szDirW != UNICODE_NULL)
2009 {
2010 SHUnicodeToAnsi(szDirW, szDirA, _countof(szDirA));
2011 cmi.fMask |= CMIC_MASK_UNICODE;
2012 cmi.lpDirectory = szDirA;
2013 cmi.lpDirectoryW = szDirW;
2014 }
2015
2016 HRESULT hr = pCM->InvokeCommand((LPCMINVOKECOMMANDINFO)&cmi);
2017 // Most of our callers will do this, but if they would forget (File menu!)
2018 IUnknown_SetSite(pCM, NULL);
2019 pCM.Release();
2020
2022 return hr;
2023
2024 return S_OK;
2025}
2026
2028{
2029 HMENU hMenu;
2030 UINT uCommand;
2031 HRESULT hResult;
2032
2033 if (m_ListView.GetSelectedCount() == 0)
2034 return S_OK;
2035
2036 hResult = OnDefaultCommand();
2037 if (hResult == S_OK)
2038 return hResult;
2039
2040 hMenu = CreatePopupMenu();
2041 if (!hMenu)
2042 return E_FAIL;
2043
2046 MenuCleanup _(pCM, hMenu);
2047 if (FAILED_UNEXPECTEDLY(hResult))
2048 return hResult;
2049
2050 UINT cmf = CMF_DEFAULTONLY | GetContextMenuFlags(m_pShellBrowser, 0);
2051 hResult = pCM->QueryContextMenu(hMenu, 0, DVIDM_CONTEXTMENU_FIRST, DVIDM_CONTEXTMENU_LAST, cmf);
2052 if (FAILED_UNEXPECTEDLY(hResult))
2053 return hResult;
2054
2055 uCommand = GetMenuDefaultItem(hMenu, FALSE, 0);
2056 if (uCommand == (UINT)-1)
2057 {
2058 ERR("GetMenuDefaultItem returned -1\n");
2059 return E_FAIL;
2060 }
2061
2063
2064 return hResult;
2065}
2066
2068{
2070 UINT uCommand;
2071 HRESULT hResult;
2072
2073 TRACE("(%p)\n", this);
2074
2075 if (m_hContextMenu != NULL)
2076 {
2077 ERR("HACK: Aborting context menu in nested call\n");
2078 return 0;
2079 }
2080
2081 HWND hWndHdr = ListView_GetHeader(m_ListView.m_hWnd);
2082 RECT r;
2083 if (::GetWindowRect(hWndHdr, &r) && PtInRect(&r, pt) && ::IsWindowVisible(hWndHdr))
2084 {
2086 }
2087
2089 if (!m_hContextMenu)
2090 return E_FAIL;
2091
2092 if (lParam != ~0) // unless app key (menu key) was pressed
2093 {
2094 LV_HITTESTINFO hittest = { pt };
2095 ScreenToClient(&hittest.pt);
2096 m_ListView.HitTest(&hittest);
2097
2098 // Right-Clicked item is selected? If selected, no selection change.
2099 // If not selected, then reset the selection and select the item.
2100 if ((hittest.flags & LVHT_ONITEM) &&
2102 {
2103 SelectItem(hittest.iItem, SVSI_SELECT | SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE);
2104 }
2105 }
2106
2108 // In case we still have this left over, clean it up
2111 if (FAILED_UNEXPECTEDLY(hResult))
2112 return 0;
2113
2114 UINT cmf = GetContextMenuFlags(m_pShellBrowser, SFGAO_CANRENAME);
2115 // Use 1 as the first id we want. 0 means that user canceled the menu
2116 hResult = m_pCM->QueryContextMenu(m_hContextMenu, 0, CONTEXT_MENU_BASE_ID, DVIDM_CONTEXTMENU_LAST, cmf);
2117 if (FAILED_UNEXPECTEDLY(hResult))
2118 return 0;
2119
2120 // There is no position requested, so try to find one
2121 if (lParam == ~0)
2122 {
2123 HWND hFocus = ::GetFocus();
2124 int lvIndex = -1;
2125
2126 if (hFocus == m_ListView.m_hWnd || m_ListView.IsChild(hFocus))
2127 {
2128 // Is there an item focused and selected?
2130 // If not, find the first selected item
2131 if (lvIndex < 0)
2132 lvIndex = m_ListView.GetNextItem(-1, LVIS_SELECTED);
2133 }
2134
2135 // We got something
2136 if (lvIndex > -1)
2137 {
2138 // Find the center of the icon
2139 RECT rc = { LVIR_ICON };
2140 m_ListView.SendMessage(LVM_GETITEMRECT, lvIndex, (LPARAM)&rc);
2141 pt.x = (rc.right + rc.left) / 2;
2142 pt.y = (rc.bottom + rc.top) / 2;
2143 }
2144 else
2145 {
2146 // We have to drop it somewhere
2147 pt.x = pt.y = 0;
2148 }
2149
2150 m_ListView.ClientToScreen(&pt);
2151 }
2152
2153 // This runs the message loop, calling back to us with f.e. WM_INITPOPUP (hence why m_hContextMenu and m_pCM exist)
2154 uCommand = TrackPopupMenu(m_hContextMenu,
2156 pt.x, pt.y, 0, m_hWnd, NULL);
2157 if (uCommand == 0)
2158 return 0;
2159
2160 if (uCommand >= DVIDM_ARRANGESORT_FIRST && uCommand <= DVIDM_ARRANGESORT_LAST)
2161 return SendMessage(WM_COMMAND, uCommand, 0);
2162
2163 if (uCommand == FCIDM_SHVIEW_OPEN && OnDefaultCommand() == S_OK)
2164 return 0;
2165
2167
2168 return 0;
2169}
2170
2172{
2173 HRESULT hResult;
2174 HMENU hMenu = NULL;
2175
2177 hResult = GetItemObject(bUseSelection ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &pCM));
2178 if (FAILED_UNEXPECTEDLY(hResult))
2179 return 0;
2180
2181 MenuCleanup _(pCM, hMenu);
2182
2183 if ((uCommand != FCIDM_SHVIEW_DELETE) && (uCommand != FCIDM_SHVIEW_RENAME))
2184 {
2185 hMenu = CreatePopupMenu();
2186 if (!hMenu)
2187 return 0;
2188
2189 hResult = pCM->QueryContextMenu(hMenu, 0, DVIDM_CONTEXTMENU_FIRST, DVIDM_CONTEXTMENU_LAST, CMF_NORMAL);
2190 if (FAILED_UNEXPECTEDLY(hResult))
2191 return 0;
2192 }
2193
2194 if (bUseSelection)
2195 {
2196 // FIXME: we should cache this
2197 SFGAOF rfg = SFGAO_BROWSABLE | SFGAO_CANCOPY | SFGAO_CANLINK | SFGAO_CANMOVE | SFGAO_CANDELETE | SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSTEM | SFGAO_FOLDER;
2198 hResult = m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &rfg);
2199 if (FAILED_UNEXPECTEDLY(hResult))
2200 return 0;
2201
2202 if (!(rfg & SFGAO_CANMOVE) && uCommand == FCIDM_SHVIEW_CUT)
2203 return 0;
2204 if (!(rfg & SFGAO_CANCOPY) && uCommand == FCIDM_SHVIEW_COPY)
2205 return 0;
2206 if (!(rfg & SFGAO_CANDELETE) && uCommand == FCIDM_SHVIEW_DELETE)
2207 return 0;
2208 if (!(rfg & SFGAO_CANRENAME) && uCommand == FCIDM_SHVIEW_RENAME)
2209 return 0;
2210 if (!(rfg & SFGAO_HASPROPSHEET) && uCommand == FCIDM_SHVIEW_PROPERTIES)
2211 return 0;
2212 }
2213
2214 // FIXME: We should probably use the objects position?
2216 return 0;
2217}
2218
2219// ##### message handling #####
2220
2222{
2223 WORD wWidth, wHeight;
2224
2225 wWidth = LOWORD(lParam);
2226 wHeight = HIWORD(lParam);
2227
2228 TRACE("%p width=%u height=%u\n", this, wWidth, wHeight);
2229
2230 // WM_SIZE can come before WM_CREATE
2231 if (!m_ListView)
2232 return 0;
2233
2234 /* Resize the ListView to fit our window */
2235 ::MoveWindow(m_ListView, 0, 0, wWidth, wHeight, TRUE);
2236
2238
2241
2242 return 0;
2243}
2244
2245// internal
2247{
2248 TRACE("%p\n", this);
2249
2251 {
2252 // TODO: cleanup menu after deactivation
2254 }
2255}
2256
2258{
2259 TRACE("%p uState=%x\n", this, uState);
2260
2261 // don't do anything if the state isn't really changing
2262 if (m_uState == uState)
2263 {
2264 return;
2265 }
2266
2267 if (uState == SVUIA_DEACTIVATE)
2268 {
2269 OnDeactivate();
2270 }
2271 else
2272 {
2274 {
2275 FillEditMenu();
2276 FillViewMenu();
2277 m_pShellBrowser->SetMenuSB(m_hMenu, 0, m_hWnd);
2279 }
2280
2281 if (SVUIA_ACTIVATE_FOCUS == uState)
2282 {
2283 m_ListView.SetFocus();
2284 }
2285 }
2286
2287 m_uState = uState;
2288 TRACE("--\n");
2289}
2290
2292{
2293 if (!GetSelections())
2294 return;
2295
2296 SFGAOF rfg = SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_FILESYSTEM;
2297 HRESULT hr = m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &rfg);
2299 return;
2300
2301 if (!bCopy && !(rfg & SFGAO_CANMOVE))
2302 return;
2303 if (bCopy && !(rfg & SFGAO_CANCOPY))
2304 return;
2305
2307 hr = m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, IID_IContextMenu, 0, (void **)&pCM);
2309 return;
2310
2311 InvokeContextMenuCommand(pCM, (bCopy ? "copyto" : "moveto"), NULL);
2312}
2313
2315{
2317 return 0;
2318}
2319
2321{
2322 TRACE("%p\n", this);
2323
2324 /* Tell the browser one of our windows has received the focus. This
2325 should always be done before merging menus (OnActivate merges the
2326 menus) if one of our windows has the focus.*/
2327
2328 m_pShellBrowser->OnViewWindowActive(this);
2330
2331 /* Set the focus to the listview */
2332 m_ListView.SetFocus();
2333
2334 /* Notify the ICommDlgBrowser interface */
2335 OnStateChange(CDBOSC_SETFOCUS);
2336
2337 return 0;
2338}
2339
2341{
2342 TRACE("(%p) stub\n", this);
2343
2345 /* Notify the ICommDlgBrowser */
2346 OnStateChange(CDBOSC_KILLFOCUS);
2347
2348 return 0;
2349}
2350
2351// the CmdID's are the ones from the context menu
2353{
2354 DWORD dwCmdID;
2355 DWORD dwCmd;
2356 HWND hwndCmd;
2357 int nCount;
2358
2359 dwCmdID = GET_WM_COMMAND_ID(wParam, lParam);
2361 hwndCmd = GET_WM_COMMAND_HWND(wParam, lParam);
2362
2363 TRACE("(%p)->(0x%08x 0x%08x %p) stub\n", this, dwCmdID, dwCmd, hwndCmd);
2364
2365 if (dwCmdID >= DVIDM_ARRANGESORT_FIRST && dwCmdID <= DVIDM_ARRANGESORT_LAST)
2366 {
2367 UINT listCol = (UINT)GetMenuItemDataById(m_hMenuArrangeModes, dwCmdID);
2368 _Sort(listCol);
2369 return 0;
2370 }
2371
2372 switch (dwCmdID)
2373 {
2377 CheckToolbar();
2378 break;
2381 m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_ICON);
2382 CheckToolbar();
2383 break;
2386 m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_LIST);
2387 CheckToolbar();
2388 break;
2391 m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_REPORT);
2392 CheckToolbar();
2393 break;
2396 break;
2398 if (_GetSnapToGrid() == S_OK)
2400 else
2401 ArrangeGrid();
2402 break;
2404 if (GetAutoArrange() == S_OK)
2405 m_ListView.ModifyStyle(LVS_AUTOARRANGE, 0);
2406 else
2407 AutoArrange();
2408 break;
2412 break;
2414 nCount = m_ListView.GetItemCount();
2415 for (int i=0; i < nCount; i++)
2417 break;
2419 Refresh();
2420 break;
2422 case FCIDM_SHVIEW_CUT:
2423 case FCIDM_SHVIEW_COPY:
2427 return 0;
2428 return OnExplorerCommand(dwCmdID, TRUE);
2432 return 0;
2434 case FCIDM_SHVIEW_UNDO:
2437 return OnExplorerCommand(dwCmdID, FALSE);
2438 default:
2439 // WM_COMMAND messages from file menu are routed to CDefView to let m_pFileMenu handle them
2440 if (m_pFileMenu && dwCmd == 0)
2441 {
2442 HMENU Dummy = NULL;
2443 MenuCleanup _(m_pFileMenu, Dummy);
2445 }
2446 }
2447
2448 return 0;
2449}
2450
2451static BOOL
2453{
2454 HKEY hKey;
2455 LONG error;
2456 DWORD dwValue = FALSE, cbValue;
2457
2459 if (error)
2460 return dwValue;
2461
2462 cbValue = sizeof(dwValue);
2463 RegQueryValueExW(hKey, L"SelectExtOnRename", NULL, NULL, (LPBYTE)&dwValue, &cbValue);
2464
2466 return !!dwValue;
2467}
2468
2470{
2471 UINT CtlID;
2472 LPNMHDR lpnmh;
2473 LPNMLISTVIEW lpnmlv;
2474 NMLVDISPINFOW *lpdi;
2475 PCUITEMID_CHILD pidl;
2476 BOOL unused;
2477
2478 CtlID = wParam;
2479 lpnmh = (LPNMHDR)lParam;
2480 lpnmlv = (LPNMLISTVIEW)lpnmh;
2481 lpdi = (NMLVDISPINFOW *)lpnmh;
2482
2483 TRACE("%p CtlID=%u lpnmh->code=%x\n", this, CtlID, lpnmh->code);
2484
2485 switch (lpnmh->code)
2486 {
2487 case NM_SETFOCUS:
2488 TRACE("-- NM_SETFOCUS %p\n", this);
2489 OnSetFocus(0, 0, 0, unused);
2490 break;
2491 case NM_KILLFOCUS:
2492 TRACE("-- NM_KILLFOCUS %p\n", this);
2493 OnDeactivate();
2494 /* Notify the ICommDlgBrowser interface */
2495 OnStateChange(CDBOSC_KILLFOCUS);
2496 break;
2497 case NM_CUSTOMDRAW:
2498 TRACE("-- NM_CUSTOMDRAW %p\n", this);
2499 return CDRF_DODEFAULT;
2500 case NM_RELEASEDCAPTURE:
2501 TRACE("-- NM_RELEASEDCAPTURE %p\n", this);
2502 break;
2503 case NM_CLICK:
2504 TRACE("-- NM_CLICK %p\n", this);
2505 break;
2506 case NM_RCLICK:
2507 TRACE("-- NM_RCLICK %p\n", this);
2508 break;
2509 case NM_DBLCLK:
2510 TRACE("-- NM_DBLCLK %p\n", this);
2512 break;
2513 case NM_RETURN:
2514 TRACE("-- NM_RETURN %p\n", this);
2516 break;
2517 case HDN_ENDTRACKW:
2518 TRACE("-- HDN_ENDTRACKW %p\n", this);
2519 //nColumn1 = m_ListView.GetColumnWidth(0);
2520 //nColumn2 = m_ListView.GetColumnWidth(1);
2521 break;
2522 case LVN_DELETEITEM:
2523 TRACE("-- LVN_DELETEITEM %p\n", this);
2524 /*delete the pidl because we made a copy of it*/
2525 SHFree(reinterpret_cast<LPVOID>(lpnmlv->lParam));
2526 break;
2527 case LVN_DELETEALLITEMS:
2528 TRACE("-- LVN_DELETEALLITEMS %p\n", this);
2529 return FALSE;
2530 case LVN_INSERTITEM:
2531 TRACE("-- LVN_INSERTITEM (STUB)%p\n", this);
2532 break;
2533 case LVN_ITEMACTIVATE:
2534 TRACE("-- LVN_ITEMACTIVATE %p\n", this);
2535 OnStateChange(CDBOSC_SELCHANGE); // browser will get the IDataObject
2536 break;
2537 case LVN_COLUMNCLICK:
2538 {
2539 UINT foldercol = MapListColumnToFolderColumn(lpnmlv->iSubItem);
2540 HRESULT hr = S_FALSE;
2541 if (m_pSDParent)
2542 hr = m_pSDParent->ColumnClick(foldercol);
2543 if (hr != S_OK)
2544 hr = _DoFolderViewCB(SFVM_COLUMNCLICK, foldercol, 0);
2545 if (hr != S_OK)
2546 _Sort(lpnmlv->iSubItem);
2547 break;
2548 }
2549 case LVN_GETDISPINFOA:
2550 case LVN_GETDISPINFOW:
2551 TRACE("-- LVN_GETDISPINFO %p\n", this);
2552 pidl = _PidlByItem(lpdi->item);
2553
2554 if (lpdi->item.mask & LVIF_TEXT) /* text requested */
2555 {
2558 break;
2559
2560 if (lpnmh->code == LVN_GETDISPINFOA)
2561 {
2562 /* shouldn't happen */
2563 NMLVDISPINFOA *lpdiA = (NMLVDISPINFOA *)lpnmh;
2564 StrRetToStrNA( lpdiA->item.pszText, lpdiA->item.cchTextMax, &sd.str, NULL);
2565 TRACE("-- text=%s\n", lpdiA->item.pszText);
2566 }
2567 else /* LVN_GETDISPINFOW */
2568 {
2569 StrRetToStrNW( lpdi->item.pszText, lpdi->item.cchTextMax, &sd.str, NULL);
2570 TRACE("-- text=%s\n", debugstr_w(lpdi->item.pszText));
2571 }
2572 }
2573 if(lpdi->item.mask & LVIF_IMAGE) /* image requested */
2574 {
2576 }
2577 if(lpdi->item.mask & LVIF_STATE)
2578 {
2579 ULONG attributes = SFGAO_HIDDEN;
2580 if (SUCCEEDED(m_pSFParent->GetAttributesOf(1, &pidl, &attributes)))
2581 {
2582 if (attributes & SFGAO_HIDDEN)
2583 lpdi->item.state |= LVIS_CUT;
2584 }
2585 }
2586 lpdi->item.mask |= LVIF_DI_SETITEM;
2587 break;
2588 case LVN_ITEMCHANGED:
2589 TRACE("-- LVN_ITEMCHANGED %p\n", this);
2590 OnStateChange(CDBOSC_SELCHANGE); // browser will get the IDataObject
2592 {
2595 }
2596 _DoFolderViewCB(SFVM_SELECTIONCHANGED, NULL/* FIXME */, NULL/* FIXME */);
2597 break;
2598 case LVN_BEGINDRAG:
2599 case LVN_BEGINRDRAG:
2600 TRACE("-- LVN_BEGINDRAG\n");
2601 if (GetSelections())
2602 {
2604 DWORD dwAttributes = SFGAO_CANCOPY | SFGAO_CANLINK;
2605 DWORD dwEffect = DROPEFFECT_MOVE;
2606
2607 if (SUCCEEDED(m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, IID_NULL_PPV_ARG(IDataObject, &pda))))
2608 {
2610
2611 if (SUCCEEDED(m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &dwAttributes)))
2612 dwEffect |= dwAttributes & (SFGAO_CANCOPY | SFGAO_CANLINK);
2613
2615 if (SUCCEEDED(pda->QueryInterface(IID_PPV_ARG(IAsyncOperation, &piaso))))
2616 piaso->SetAsyncMode(TRUE);
2617
2618 DWORD dwEffect2;
2619
2620 m_pSourceDataObject = pda;
2621 m_ptFirstMousePos = params->ptAction;
2624
2625 HIMAGELIST big_icons, small_icons;
2626 Shell_GetImageLists(&big_icons, &small_icons);
2627 PCUITEMID_CHILD pidl = _PidlByItem(params->iItem);
2628 int iIcon = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
2629 POINT ptItem;
2630 m_ListView.GetItemPosition(params->iItem, &ptItem);
2631
2632 ImageList_BeginDrag(big_icons, iIcon, params->ptAction.x - ptItem.x, params->ptAction.y - ptItem.y);
2633 DoDragDrop(pda, this, dwEffect, &dwEffect2);
2635 }
2636 }
2637 break;
2639 {
2640 DWORD dwAttr = SFGAO_CANRENAME;
2641 pidl = _PidlByItem(lpdi->item);
2642
2643 TRACE("-- LVN_BEGINLABELEDITW %p\n", this);
2644
2645 m_pSFParent->GetAttributesOf(1, &pidl, &dwAttr);
2646 if (SFGAO_CANRENAME & dwAttr)
2647 {
2648 HWND hEdit = reinterpret_cast<HWND>(m_ListView.SendMessage(LVM_GETEDITCONTROL));
2650
2651 // smartass-renaming: See CORE-15242
2652 if (!(dwAttr & SFGAO_FOLDER) && (dwAttr & SFGAO_FILESYSTEM) &&
2653 (lpdi->item.mask & LVIF_TEXT) && !SelectExtOnRename())
2654 {
2655 WCHAR szFullPath[MAX_PATH];
2656 PIDLIST_ABSOLUTE pidlFull = ILCombine(m_pidlParent, pidl);
2657 SHGetPathFromIDListW(pidlFull, szFullPath);
2658
2659 INT cchLimit = 0;
2660 _DoFolderViewCB(SFVM_GETNAMELENGTH, (WPARAM)pidlFull, (LPARAM)&cchLimit);
2661 if (cchLimit)
2662 ::SendMessageW(hEdit, EM_SETLIMITTEXT, cchLimit, 0);
2663
2664 if (!SHELL_FS_HideExtension(szFullPath))
2665 {
2666 LPWSTR pszText = lpdi->item.pszText;
2667 LPWSTR pchDotExt = PathFindExtensionW(pszText);
2668 ::PostMessageW(hEdit, EM_SETSEL, 0, pchDotExt - pszText);
2670 }
2671
2672 ILFree(pidlFull);
2673 }
2674
2675 m_isEditing = TRUE;
2676 return FALSE;
2677 }
2678 return TRUE;
2679 }
2680 case LVN_ENDLABELEDITW:
2681 {
2682 TRACE("-- LVN_ENDLABELEDITW %p\n", this);
2684
2685 if (lpdi->item.pszText)
2686 {
2687 HRESULT hr;
2688 LVITEMW lvItem;
2689
2690 pidl = _PidlByItem(lpdi->item);
2691 PITEMID_CHILD pidlNew = NULL;
2692 hr = m_pSFParent->SetNameOf(0, pidl, lpdi->item.pszText, SHGDN_INFOLDER, &pidlNew);
2693
2694 if (SUCCEEDED(hr) && pidlNew)
2695 {
2696 lvItem.mask = LVIF_PARAM|LVIF_IMAGE;
2697 lvItem.iItem = lpdi->item.iItem;
2698 lvItem.iSubItem = 0;
2699 lvItem.lParam = reinterpret_cast<LPARAM>(pidlNew);
2701 m_ListView.SetItem(&lvItem);
2702 m_ListView.Update(lpdi->item.iItem);
2703 return TRUE;
2704 }
2705 }
2706
2707 return FALSE;
2708 }
2709 default:
2710 TRACE("-- %p WM_COMMAND %x unhandled\n", this, lpnmh->code);
2711 break;
2712 }
2713
2714 return 0;
2715}
2716
2717// This is just a quick hack to make the desktop work correctly.
2718// ITranslateShellChangeNotify's IsChildID is undocumented, but most likely the
2719// way that a folder should know if it should update upon a change notification.
2720// It is exported by merged folders at a minimum.
2722{
2723 if (!pidl1 || !pidl2)
2724 return FALSE;
2725 if (ILIsParent(pidl1, pidl2, TRUE))
2726 return TRUE;
2727
2728 CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidl2Clone(ILClone(pidl2));
2729 ILRemoveLastID(pidl2Clone);
2730 return ILIsEqual(pidl1, pidl2Clone);
2731}
2732
2734{
2735 // The change notify can come before WM_CREATE
2736 if (!m_ListView)
2737 return FALSE;
2738
2739 HANDLE hChange = (HANDLE)wParam;
2740 DWORD dwProcID = (DWORD)lParam;
2741 PIDLIST_ABSOLUTE *Pidls;
2742 LONG lEvent;
2743 HANDLE hLock = SHChangeNotification_Lock(hChange, dwProcID, &Pidls, &lEvent);
2744 if (hLock == NULL)
2745 {
2746 ERR("hLock == NULL\n");
2747 return FALSE;
2748 }
2749
2750 TRACE("(%p)(%p,%p,%p)\n", this, Pidls[0], Pidls[1], lParam);
2751
2753 return FALSE;
2754
2755 // Translate child IDLs.
2756 // SHSimpleIDListFromPathW creates fake PIDLs (lacking some attributes)
2757 HRESULT hr;
2758 PITEMID_CHILD child0 = NULL, child1 = NULL;
2759 CComHeapPtr<ITEMIDLIST_RELATIVE> pidl0Temp, pidl1Temp;
2760 if (_ILIsSpecialFolder(Pidls[0]) || ILIsParentOrSpecialParent(m_pidlParent, Pidls[0]))
2761 {
2762 child0 = ILFindLastID(Pidls[0]);
2763 hr = SHGetRealIDL(m_pSFParent, child0, &pidl0Temp);
2764 if (SUCCEEDED(hr))
2765 child0 = pidl0Temp;
2766 }
2767 if (_ILIsSpecialFolder(Pidls[1]) || ILIsParentOrSpecialParent(m_pidlParent, Pidls[1]))
2768 {
2769 child1 = ILFindLastID(Pidls[1]);
2770 hr = SHGetRealIDL(m_pSFParent, child1, &pidl1Temp);
2771 if (SUCCEEDED(hr))
2772 child1 = pidl1Temp;
2773 }
2774
2775 lEvent &= ~SHCNE_INTERRUPT;
2776 switch (lEvent)
2777 {
2778 case SHCNE_MKDIR:
2779 case SHCNE_CREATE:
2780 case SHCNE_DRIVEADD:
2781 if (!child0)
2782 break;
2783 if (LV_FindItemByPidl(child0) < 0)
2784 LV_AddItem(child0);
2785 else
2786 LV_UpdateItem(child0);
2787 break;
2788 case SHCNE_RMDIR:
2789 case SHCNE_DELETE:
2790 case SHCNE_DRIVEREMOVED:
2791 if (child0)
2792 LV_DeleteItem(child0);
2793 break;
2794 case SHCNE_RENAMEFOLDER:
2795 case SHCNE_RENAMEITEM:
2796 if (child0 && child1)
2797 LV_RenameItem(child0, child1);
2798 else if (child0)
2799 LV_DeleteItem(child0);
2800 else if (child1)
2801 LV_AddItem(child1);
2802 break;
2803 case SHCNE_UPDATEITEM:
2804 if (child0)
2805 LV_UpdateItem(child0);
2806 break;
2807 case SHCNE_UPDATEIMAGE:
2809 case SHCNE_MEDIAREMOVED:
2810 case SHCNE_ASSOCCHANGED:
2812 break;
2813 case SHCNE_UPDATEDIR:
2814 case SHCNE_ATTRIBUTES:
2815 Refresh();
2817 break;
2818 case SHCNE_FREESPACE:
2820 break;
2821 }
2822
2824 return TRUE;
2825}
2826
2829
2831{
2832 if (!m_pCM)
2833 {
2834 /* no menu */
2835 ERR("no context menu\n");
2836 return FALSE;
2837 }
2838
2839 // lParam of WM_DRAWITEM WM_MEASUREITEM contains a menu id and
2840 // this also needs to be changed to a menu identifier offset
2841 UINT CmdID;
2842 HRESULT hres = SHGetMenuIdFromMenuMsg(uMsg, lParam, &CmdID);
2843 if (SUCCEEDED(hres))
2845
2846 /* Forward the message to the IContextMenu2 */
2849
2850 return (SUCCEEDED(hres));
2851}
2852
2854{
2855 /* Wallpaper setting affects drop shadows effect */
2856 if (wParam == SPI_SETDESKWALLPAPER || wParam == 0)
2858
2859 return S_OK;
2860}
2861
2863{
2864 HMENU hmenu = (HMENU) wParam;
2865 int nPos = LOWORD(lParam);
2866 UINT menuItemId;
2867
2868 if (m_pCM)
2869 OnCustomItem(uMsg, wParam, lParam, bHandled);
2870
2872
2873 if (GetSelections() == 0)
2874 {
2881 }
2882 else
2883 {
2884 // FIXME: Check copyable
2891 }
2892
2893 /* Lets try to find out what the hell wParam is */
2894 if (hmenu == GetSubMenu(m_hMenu, nPos))
2895 menuItemId = ReallyGetMenuItemID(m_hMenu, nPos);
2896 else if (hViewMenu && hmenu == GetSubMenu(hViewMenu, nPos))
2897 menuItemId = ReallyGetMenuItemID(hViewMenu, nPos);
2898 else if (m_hContextMenu && hmenu == GetSubMenu(m_hContextMenu, nPos))
2899 menuItemId = ReallyGetMenuItemID(m_hContextMenu, nPos);
2900 else
2901 return FALSE;
2902
2903 switch (menuItemId)
2904 {
2905 case FCIDM_MENU_FILE:
2906 FillFileMenu();
2907 break;
2908 case FCIDM_MENU_VIEW:
2909 case FCIDM_SHVIEW_VIEW:
2911 break;
2914 break;
2915 }
2916
2917 return FALSE;
2918}
2919
2920
2921// The INTERFACE of the IShellView object
2922
2924{
2925 TRACE("(%p)\n", this);
2926
2927 *phWnd = m_hWnd;
2928
2929 return S_OK;
2930}
2931
2933{
2934 FIXME("(%p) stub\n", this);
2935
2936 return E_NOTIMPL;
2937}
2938
2939// FIXME: use the accel functions
2941{
2942 if (m_isEditing)
2943 return S_FALSE;
2944
2945 if (lpmsg->message >= WM_KEYFIRST && lpmsg->message <= WM_KEYLAST)
2946 {
2947 if (::TranslateAcceleratorW(m_hWnd, m_hAccel, lpmsg) != 0)
2948 return S_OK;
2949
2950 TRACE("-- key=0x%04lx\n", lpmsg->wParam);
2951 }
2952
2953 return m_pShellBrowser->TranslateAcceleratorSB(lpmsg, 0);
2954}
2955
2957{
2958 FIXME("(%p)\n", this);
2959 return E_NOTIMPL;
2960}
2961
2963{
2964 TRACE("(%p)->(state=%x)\n", this, uState);
2965
2966 // don't do anything if the state isn't changing
2967 if (m_uState == uState)
2968 return S_OK;
2969
2970 // OnActivate handles the menu merging and internal state
2971 DoActivate(uState);
2972
2973 // only do this if we are active
2974 if (uState != SVUIA_DEACTIVATE)
2975 {
2977
2978 // Set the text for the status bar
2980 }
2981
2982 return S_OK;
2983}
2984
2986{
2987 TRACE("(%p)\n", this);
2988
2990
2992 FillList();
2993
2994 return S_OK;
2995}
2996
2998{
2999 return CreateViewWindow3(psb, lpPrevView, SV3CVW3_DEFAULT,
3000 (FOLDERFLAGS)lpfs->fFlags, (FOLDERFLAGS)lpfs->fFlags, (FOLDERVIEWMODE)lpfs->ViewMode, NULL, prcView, phWnd);
3001}
3002
3004{
3005 TRACE("(%p)\n", this);
3006
3007 /* Make absolutely sure all our UI is cleaned up */
3009
3010 if (m_hAccel)
3011 {
3012 // MSDN: Accelerator tables loaded from resources are freed automatically when application terminates
3013 m_hAccel = NULL;
3014 }
3015
3017 {
3020 }
3021
3022 if (m_hMenuViewModes)
3023 {
3026 }
3027
3028 if (m_hMenu)
3029 {
3031 m_hMenu = NULL;
3032 }
3033
3034 if (m_ListView)
3035 {
3036 m_ListView.DestroyWindow();
3037 }
3038
3039 if (m_hWnd)
3040 {
3042 DestroyWindow();
3043 }
3044
3047
3048 return S_OK;
3049}
3050
3052{
3053 TRACE("(%p)->(%p) vmode=%x flags=%x\n", this, lpfs,
3055
3056 if (!lpfs)
3057 return E_INVALIDARG;
3058
3059 *lpfs = m_FolderSettings;
3060 return S_OK;
3061}
3062
3064{
3065 TRACE("(%p)->(0x%lX, %p, %p)\n", this, dwReserved, lpfn, lparam);
3066
3069 return S_OK;
3070}
3071
3073{
3074 FIXME("(%p) stub\n", this);
3075
3076 return S_OK;
3077}
3078
3080{
3081 int i;
3082
3083 TRACE("(%p)->(pidl=%p, 0x%08x) stub\n", this, pidl, uFlags);
3084
3085 if (!m_ListView)
3086 {
3087 ERR("!m_ListView\n");
3088 return E_FAIL;
3089 }
3090
3091 i = LV_FindItemByPidl(pidl);
3092 if (i == -1)
3093 return S_OK;
3094
3095 LVITEMW lvItem = {0};
3096 lvItem.mask = LVIF_STATE;
3098
3099 while (m_ListView.GetItem(&lvItem))
3100 {
3101 if (lvItem.iItem == i)
3102 {
3103 if (uFlags & SVSI_SELECT)
3104 lvItem.state |= LVIS_SELECTED;
3105 else
3106 lvItem.state &= ~LVIS_SELECTED;
3107
3108 if (uFlags & SVSI_FOCUSED)
3109 lvItem.state |= LVIS_FOCUSED;
3110 else
3111 lvItem.state &= ~LVIS_FOCUSED;
3112 }
3113 else
3114 {
3115 if (uFlags & SVSI_DESELECTOTHERS)
3116 {
3117 lvItem.state &= ~LVIS_SELECTED;
3118 }
3119 lvItem.state &= ~LVIS_FOCUSED;
3120 }
3121
3122 m_ListView.SetItem(&lvItem);
3123 lvItem.iItem++;
3124 }
3125
3126 if (uFlags & SVSI_ENSUREVISIBLE)
3128
3129 if((uFlags & SVSI_EDIT) == SVSI_EDIT)
3131
3132 return S_OK;
3133}
3134
3136{
3138
3139 TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n", this, uItem, debugstr_guid(&riid), ppvOut);
3140
3141 if (!ppvOut)
3142 return E_INVALIDARG;
3143
3144 *ppvOut = NULL;
3145
3146 switch (uItem)
3147 {
3148 case SVGIO_BACKGROUND:
3149 if (IsEqualIID(riid, IID_IContextMenu))
3150 {
3153 return hr;
3154
3155 IUnknown_SetSite(*((IUnknown**)ppvOut), (IShellView *)this);
3156 }
3157 else if (IsEqualIID(riid, IID_IDispatch))
3158 {
3160 {
3163 return hr;
3164 }
3165 hr = m_pShellFolderViewDual->QueryInterface(riid, ppvOut);
3166 }
3167 break;
3168 case SVGIO_SELECTION:
3169 GetSelections();
3170 hr = m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, riid, 0, ppvOut);
3172 return hr;
3173
3174 if (IsEqualIID(riid, IID_IContextMenu))
3175 IUnknown_SetSite(*((IUnknown**)ppvOut), (IShellView *)this);
3176
3177 break;
3178 }
3179
3180 TRACE("-- (%p)->(interface=%p)\n", this, *ppvOut);
3181
3182 return hr;
3183}
3184
3186{
3187 TRACE("(%p)->(%p), stub\n", this, pViewMode);
3188
3189 if (!pViewMode)
3190 return E_INVALIDARG;
3191
3192 *pViewMode = m_FolderSettings.ViewMode;
3193 return S_OK;
3194}
3195
3197{
3198 DWORD dwStyle;
3199 TRACE("(%p)->(%u), stub\n", this, ViewMode);
3200
3201 /* It's not redundant to check FVM_AUTO because it's a (UINT)-1 */
3202 if (((INT)ViewMode < FVM_FIRST || (INT)ViewMode > FVM_LAST) && ((INT)ViewMode != FVM_AUTO))
3203 return E_INVALIDARG;
3204
3205 /* Windows before Vista uses LVM_SETVIEW and possibly
3206 LVM_SETEXTENDEDLISTVIEWSTYLE to set the style of the listview,
3207 while later versions seem to accomplish this through other
3208 means. */
3209 switch (ViewMode)
3210 {
3211 case FVM_ICON:
3212 dwStyle = LVS_ICON;
3213 break;
3214 case FVM_DETAILS:
3215 dwStyle = LVS_REPORT;
3216 break;
3217 case FVM_SMALLICON:
3218 dwStyle = LVS_SMALLICON;
3219 break;
3220 case FVM_LIST:
3221 dwStyle = LVS_LIST;
3222 break;
3223 default:
3224 {
3225 FIXME("ViewMode %d not implemented\n", ViewMode);
3226 dwStyle = LVS_LIST;
3227 break;
3228 }
3229 }
3230
3231 m_ListView.ModifyStyle(LVS_TYPEMASK, dwStyle);
3232
3233 /* This will not necessarily be the actual mode set above.
3234 This mimics the behavior of Windows XP. */
3235 m_FolderSettings.ViewMode = ViewMode;
3236
3237 return S_OK;
3238}
3239
3241{
3242 if (m_pSFParent == NULL)
3243 return E_FAIL;
3244
3245 return m_pSFParent->QueryInterface(riid, ppv);
3246}
3247
3249{
3250 PCUITEMID_CHILD pidl = _PidlByItem(iItemIndex);
3251 if (pidl)
3252 {
3253 *ppidl = ILClone(pidl);
3254 return S_OK;
3255 }
3256
3257 *ppidl = 0;
3258 return E_INVALIDARG;
3259}
3260
3262{
3263 TRACE("(%p)->(%u %p)\n", this, uFlags, pcItems);
3264
3265 if (uFlags != SVGIO_ALLVIEW)
3266 FIXME("some flags unsupported, %x\n", uFlags & ~SVGIO_ALLVIEW);
3267
3269
3270 return S_OK;
3271}
3272
3274{
3275 return E_NOTIMPL;
3276}
3277
3279{
3280 TRACE("(%p)->(%p)\n", this, piItem);
3281
3282 *piItem = m_ListView.GetSelectionMark();
3283
3284 return S_OK;
3285}
3286
3288{
3289 TRACE("(%p)->(%p)\n", this, piItem);
3290
3291 *piItem = m_ListView.GetNextItem(-1, LVNI_FOCUSED);
3292
3293 return S_OK;
3294}
3295
3297{
3298 if (!m_ListView)
3299 {
3300 ERR("!m_ListView\n");
3301 return E_FAIL;
3302 }
3303
3304 int lvIndex = LV_FindItemByPidl(pidl);
3305 if (lvIndex == -1 || ppt == NULL)
3306 return E_INVALIDARG;
3307
3308 m_ListView.GetItemPosition(lvIndex, ppt);
3309 return S_OK;
3310}
3311
3313{
3314 TRACE("(%p)->(%p)\n", this, ppt);
3315
3316 if (!m_ListView)
3317 {
3318 ERR("!m_ListView\n");
3319 return S_FALSE;
3320 }
3321
3322 if (ppt)
3323 {
3324 SIZE spacing;
3325 m_ListView.GetItemSpacing(spacing);
3326
3327 ppt->x = spacing.cx;
3328 ppt->y = spacing.cy;
3329 }
3330
3331 return S_OK;
3332}
3333
3335{
3336 return E_NOTIMPL;
3337}
3338
3340{
3341 return ((m_ListView.GetStyle() & LVS_AUTOARRANGE) ? S_OK : S_FALSE);
3342}
3343
3345{
3346 DWORD dwExStyle = (DWORD)m_ListView.SendMessage(LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
3347 return ((dwExStyle & LVS_EX_SNAPTOGRID) ? S_OK : S_FALSE);
3348}
3349
3351{
3352 LVITEMW lvItem;
3353
3354 TRACE("(%p)->(%d, %x)\n", this, iItem, dwFlags);
3355
3356 lvItem.state = 0;
3357 lvItem.stateMask = LVIS_SELECTED;
3358
3359 if (dwFlags & SVSI_ENSUREVISIBLE)
3360 m_ListView.EnsureVisible(iItem, 0);
3361
3362 /* all items */
3363 if (dwFlags & SVSI_DESELECTOTHERS)
3365
3366 /* this item */
3367 if (dwFlags & SVSI_SELECT)
3368 lvItem.state |= LVIS_SELECTED;
3369
3370 if (dwFlags & SVSI_FOCUSED)
3371 lvItem.stateMask |= LVIS_FOCUSED;
3372
3373 m_ListView.SetItemState(iItem, lvItem.state, lvItem.stateMask);
3374
3375 if ((dwFlags & SVSI_EDIT) == SVSI_EDIT)
3376 m_ListView.EditLabel(iItem);
3377
3378 return S_OK;
3379}
3380
3382{
3384
3385 /* Reset the selection */
3387
3388 int lvIndex;
3389 for (UINT i = 0 ; i < cidl; i++)
3390 {
3391 lvIndex = LV_FindItemByPidl(apidl[i]);
3392 if (lvIndex != -1)
3393 {
3394 SelectItem(lvIndex, dwFlags);
3395 m_ListView.SetItemPosition(lvIndex, &apt[i]);
3396 }
3397 }
3398
3399 return S_OK;
3400}
3401
3402
3403// IShellView2 implementation
3404
3406{
3407 FIXME("(%p)->(%p, %lu) stub\n", this, view_guid, view_type);
3408 return E_NOTIMPL;
3409}
3410
3412{
3413 return CreateViewWindow3(view_params->psbOwner, view_params->psvPrev,
3414 SV3CVW3_DEFAULT, (FOLDERFLAGS)view_params->pfs->fFlags, (FOLDERFLAGS)view_params->pfs->fFlags,
3415 (FOLDERVIEWMODE)view_params->pfs->ViewMode, view_params->pvid, view_params->prcView, &view_params->hwndView);
3416}
3417
3419{
3420 OLEMENUGROUPWIDTHS omw = { { 0, 0, 0, 0, 0, 0 } };
3421
3422 *hwnd = NULL;
3423
3424 TRACE("(%p)->(shlview=%p shlbrs=%p rec=%p hwnd=%p vmode=%x flags=%x)\n", this, psvPrevious, psb, prcView, hwnd, mode, flags);
3425 if (prcView != NULL)
3426 TRACE("-- left=%i top=%i right=%i bottom=%i\n", prcView->left, prcView->top, prcView->right, prcView->bottom);
3427
3428 /* Validate the Shell Browser */
3429 if (psb == NULL || m_hWnd)
3430 return E_UNEXPECTED;
3431
3432 if (view_flags != SV3CVW3_DEFAULT)
3433 FIXME("unsupported view flags 0x%08x\n", view_flags);
3434
3435 /* Set up the member variables */
3436 m_pShellBrowser = psb;
3439
3440 if (view_id)
3441 {
3442 if (IsEqualIID(*view_id, VID_LargeIcons))
3444 else if (IsEqualIID(*view_id, VID_SmallIcons))
3446 else if (IsEqualIID(*view_id, VID_List))
3448 else if (IsEqualIID(*view_id, VID_Details))
3450 else if (IsEqualIID(*view_id, VID_Thumbnails))
3452 else if (IsEqualIID(*view_id, VID_Tile))
3454 else if (IsEqualIID(*view_id, VID_ThumbStrip))
3456 else
3457 FIXME("Ignoring unrecognized VID %s\n", debugstr_guid(view_id));
3458 }
3459
3460 /* Get our parent window */
3461 m_pShellBrowser->GetWindow(&m_hWndParent);
3462
3463 /* Try to get the ICommDlgBrowserInterface, adds a reference !!! */
3466 {
3467 TRACE("-- CommDlgBrowser\n");
3468 }
3469
3470 RECT rcView = *prcView;
3472 if (m_hWnd == NULL)
3473 return E_FAIL;
3474
3475 *hwnd = m_hWnd;
3476
3477 CheckToolbar();
3478
3479 if (!*hwnd)
3480 return E_FAIL;
3481
3483
3485 UpdateWindow();
3486
3487 if (!m_hMenu)
3488 {
3489 m_hMenu = CreateMenu();
3490 m_pShellBrowser->InsertMenusSB(m_hMenu, &omw);
3491 TRACE("-- after fnInsertMenusSB\n");
3492 }
3493
3494 _MergeToolbar();
3495
3496 return S_OK;
3497}
3498
3500{
3501 FIXME("(%p)->(%p) stub\n", this, new_pidl);
3502 return E_NOTIMPL;
3503}
3504
3506{
3507 FIXME("(%p)->(%p, %u, %p) stub\n", this, item, flags, point);
3508 return E_NOTIMPL;
3509}
3510
3511// IShellFolderView implementation
3512
3514{
3515 FIXME("(%p)->(%ld) stub\n", this, sort);
3516 return E_NOTIMPL;
3517}
3518
3520{
3521 FIXME("(%p)->(%p) stub\n", this, sort);
3522 return E_NOTIMPL;
3523}
3524
3526{
3528 return S_OK;
3529}
3530
3532{
3533 m_ListView.ModifyStyle(0, LVS_AUTOARRANGE);
3535 return S_OK;
3536}
3537
3539{
3540 TRACE("(%p)->(%p %p)\n", this, pidl, item);
3541 if (!m_ListView)
3542 {
3543 ERR("!m_ListView\n");
3544 return E_FAIL;
3545 }
3546 *item = LV_AddItem(pidl);
3547 return (int)*item >= 0 ? S_OK : E_OUTOFMEMORY;
3548}
3549
3551{
3552 TRACE("(%p)->(%p %d)\n", this, pidl, item);
3553 return Item(item, pidl);
3554}
3555
3557{
3558 TRACE("(%p)->(%p %p)\n", this, pidl, item);
3559
3560 if (!m_ListView)
3561 {
3562 ERR("!m_ListView\n");
3563 return E_FAIL;
3564 }
3565
3566 if (pidl)
3567 {
3570 }
3571 else
3572 {
3573 *item = 0;
3575 }
3576
3577 return S_OK;
3578}
3579
3581{
3582 TRACE("(%p)->(%p)\n", this, count);
3584 return S_OK;
3585}
3586
3588{
3589 FIXME("(%p)->(%d %x) stub\n", this, count, flags);
3590 return E_NOTIMPL;
3591}
3592
3594{
3595 FIXME("(%p)->(%p %p %p) stub\n", this, pidl_old, pidl_new, item);
3596 return E_NOTIMPL;
3597}
3598
3600{
3601 FIXME("(%p)->(%p %p) stub\n", this, pidl, item);
3602 return E_NOTIMPL;
3603}
3604
3606{
3607 TRACE("(%p)->(%d)\n", this, redraw);
3608 if (m_ListView)
3610 return S_OK;
3611}
3612
3614{
3615 FIXME("(%p)->(%p) stub\n", this, count);
3616 return E_NOTIMPL;
3617}
3618
3620{
3621 TRACE("(%p)->(%p %p)\n", this, pidl, items);
3622
3623 *items = GetSelections();
3624
3625 if (*items)
3626 {
3627 *pidl = static_cast<PCUITEMID_CHILD *>(LocalAlloc(0, *items * sizeof(PCUITEMID_CHILD)));
3628 if (!*pidl)
3629 {
3630 return E_OUTOFMEMORY;
3631 }
3632
3633 /* it's documented that caller shouldn't PIDLs, only array itself */
3634 memcpy(*pidl, m_apidl, *items * sizeof(PCUITEMID_CHILD));
3635 }
3636
3637 return S_OK;
3638}
3639
3641{
3642 if ((m_iDragOverItem == -1 || m_pCurDropTarget == NULL) &&
3644 {
3645 return S_OK;
3646 }
3647
3648 return S_FALSE;
3649}
3650
3652{
3653 if (!pt)
3654 return E_INVALIDARG;
3655
3657 return S_OK;
3658}
3659
3661{
3662 FIXME("(%p)->(%p) stub\n", this, pt);
3663 return E_NOTIMPL;
3664}
3665
3667{
3668 TRACE("(%p)->(%p)\n", this, obj);
3669 return E_NOTIMPL;
3670}
3671
3673{
3674 FIXME("(%p)->(%p %p) stub\n", this, pidl, pt);
3675 return E_NOTIMPL;
3676}
3677
3679{
3680 FIXME("(%p)->(%p) stub\n", this, drop_target);
3681 return E_NOTIMPL;
3682}
3683
3685{
3686 FIXME("(%p)->(%d) stub\n", this, move);
3687 return E_NOTIMPL;
3688}
3689
3691{
3692 FIXME("(%p)->(%p) stub\n", this, obj);
3693 return E_NOTIMPL;
3694}
3695
3697{
3698 FIXME("(%p)->(%p) stub\n", this, spacing);
3699 return E_NOTIMPL;
3700}
3701
3702HRESULT STDMETHODCALLTYPE CDefView::SetCallback(IShellFolderViewCB *new_cb, IShellFolderViewCB **old_cb)
3703{
3704 if (old_cb)
3705 *old_cb = m_pShellFolderViewCB.Detach();
3706
3707 m_pShellFolderViewCB = new_cb;
3708 return S_OK;
3709}
3710
3712{
3713 FIXME("(%p)->(%d) stub\n", this, flags);
3714 return E_NOTIMPL;
3715}
3716
3718{
3719 TRACE("(%p)->(%p)\n", this, support);
3720 return S_OK;
3721}
3722
3724{
3725 FIXME("(%p)->(%p) stub\n", this, disp);
3726 return E_NOTIMPL;
3727}
3728
3729HRESULT WINAPI CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText)
3730{
3731 FIXME("(%p)->(%p(%s) 0x%08x %p %p\n",
3732 this, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
3733
3734 if (!prgCmds)
3735 return E_INVALIDARG;
3736
3737 for (UINT i = 0; i < cCmds; i++)
3738 {
3739 FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID);
3740 prgCmds[i].cmdf = 0;
3741 }
3742
3743 return OLECMDERR_E_UNKNOWNGROUP;
3744}
3745
3747// ISVOleCmdTarget_Exec(IOleCommandTarget)
3748//
3749// nCmdID is the OLECMDID_* enumeration
3750HRESULT WINAPI CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
3751{
3752 FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n",
3753 this, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut);
3754
3755 if (!pguidCmdGroup)
3756 return OLECMDERR_E_UNKNOWNGROUP;
3757
3758 if (IsEqualCLSID(*pguidCmdGroup, m_Category))
3759 {
3760 if (nCmdID == FCIDM_SHVIEW_AUTOARRANGE)
3761 {
3762 if (V_VT(pvaIn) != VT_INT_PTR)
3763 return OLECMDERR_E_NOTSUPPORTED;
3764
3766 params.cbSize = sizeof(params);
3767 params.rcExclude = *(RECT*) V_INTREF(pvaIn);
3768
3769 if (m_hMenuViewModes)
3770 {
3771 // Duplicate all but the last two items of the view modes menu
3772 HMENU hmenuViewPopup = CreatePopupMenu();
3773 Shell_MergeMenus(hmenuViewPopup, m_hMenuViewModes, 0, 0, 0xFFFF, 0);
3774 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION);
3775 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION);
3776 CheckViewMode(hmenuViewPopup);
3777 TrackPopupMenuEx(hmenuViewPopup, TPM_LEFTALIGN | TPM_TOPALIGN, params.rcExclude.left, params.rcExclude.bottom, m_hWndParent, &params);
3778 ::DestroyMenu(hmenuViewPopup);
3779 }
3780
3781 // pvaOut is VT_I4 with value 0x403 (cmd id of the new mode maybe?)
3782 V_VT(pvaOut) = VT_I4;
3783 V_I4(pvaOut) = 0x403;
3784 }
3785 }
3786
3787 if (IsEqualIID(*pguidCmdGroup, CGID_Explorer) &&
3788 (nCmdID == 0x29) &&
3789 (nCmdexecopt == 4) && pvaOut)
3790 return S_OK;
3791
3792 if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView) &&
3793 (nCmdID == 9) &&
3794 (nCmdexecopt == 0))
3795 return 1;
3796
3797 if (IsEqualIID(*pguidCmdGroup, CGID_DefView))
3798 {
3799 WCHAR SubKey[MAX_PATH];
3800 switch (nCmdID)
3801 {
3803 SHDeleteKey(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\ShellNoRoam\\Bags");
3804 FIXME("Save current as default\n");
3805 break;
3807 wsprintfW(SubKey, L"%s\\%s", REGSTR_PATH_EXPLORER, L"Streams\\Default");
3809 SHDeleteKey(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\ShellNoRoam\\Bags");
3810 break;
3811 }
3812 }
3813
3814 return OLECMDERR_E_UNKNOWNGROUP;
3815}
3816
3817/**********************************************************
3818 * ISVDropTarget implementation
3819 */
3820
3821/******************************************************************************
3822 * drag_notify_subitem [Internal]
3823 *
3824 * Figure out the shellfolder object, which is currently under the mouse cursor
3825 * and notify it via the IDropTarget interface.
3826 */
3827
3828#define SCROLLAREAWIDTH 20
3829
3831{
3832 LONG lResult;
3833 HRESULT hr;
3834 RECT clientRect;
3835
3836 /* The key state on drop doesn't have MK_LBUTTON or MK_RBUTTON because it
3837 reflects the key state after the user released the button, so we need
3838 to remember the last key state when the button was pressed */
3839 m_grfKeyState = grfKeyState;
3840
3841 // Map from global to client coordinates and query the index of the
3842 // listview-item, which is currently under the mouse cursor.
3843 LVHITTESTINFO htinfo = {{pt.x, pt.y}, LVHT_ONITEM};
3844 ScreenToClient(&htinfo.pt);
3845 lResult = m_ListView.HitTest(&htinfo);
3846
3847 /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */
3848 ::GetClientRect(m_ListView, &clientRect);
3849 if</