ReactOS 0.4.15-dev-7674-gc0b4db1
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.
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
44typedef struct
45{
50
51#define SHV_CHANGE_NOTIFY WM_USER + 0x1111
52
53// For the context menu of the def view, the id of the items are based on 1 because we need
54// to call TrackPopupMenu and let it use the 0 value as an indication that the menu was canceled
55#define CONTEXT_MENU_BASE_ID 1
56
57// Convert client coordinates to listview coordinates
58static void
60{
61 POINT Origin = {};
62
63 // FIXME: LVM_GETORIGIN is broken. See CORE-17266
64 if (!ListView_GetOrigin(hwndLV, &Origin))
65 return;
66
67 ppt->x += Origin.x;
68 ppt->y += Origin.y;
69}
70
71// Helper struct to automatically cleanup the IContextMenu
72// We want to explicitly reset the Site, so there are no circular references
74{
77
79 : m_pCM(pCM), m_hMenu(menu)
80 {
81 }
83 {
84 if (m_hMenu)
85 {
87 m_hMenu = NULL;
88 }
89 if (m_pCM)
90 {
92 m_pCM.Release();
93 }
94 }
95};
96
97class CDefView :
98 public CWindowImpl<CDefView, CWindow, CControlWinTraits>,
99 public CComObjectRootEx<CComMultiThreadModelNoCS>,
100 public IShellView2,
101 public IFolderView,
102 public IShellFolderView,
103 public IOleCommandTarget,
104 public IDropTarget,
105 public IDropSource,
106 public IViewObject,
107 public IServiceProvider
108{
109private:
119 HMENU m_hMenu; // Handle to the menu bar of the browser
120 HMENU m_hMenuArrangeModes; // Handle to the popup menu with the arrange modes
121 HMENU m_hMenuViewModes; // Handle to the popup menu with the view modes
122 HMENU m_hContextMenu; // Handle to the open context menu
129 ULONG m_hNotify; // Change notification handle
130 HACCEL m_hAccel;
134 // for drag and drop
136 CComPtr<IDropTarget> m_pCurDropTarget; // The sub-item, which is currently dragged over
137 CComPtr<IDataObject> m_pCurDataObject; // The dragged data-object
138 LONG m_iDragOverItem; // Dragged over item's index, if m_pCurDropTarget != NULL
139 UINT m_cScrollDelay; // Send a WM_*SCROLL msg every 250 ms during drag-scroll
140 POINT m_ptLastMousePos; // Mouse position at last DragOver call
141 POINT m_ptFirstMousePos; // Mouse position when the drag operation started
143 //
146
149
153
155
157 BOOL _Sort();
164 void _DoCopyToMoveToFolder(BOOL bCopy);
165
166public:
167 CDefView();
168 ~CDefView();
173 void UpdateStatusbar();
174 void CheckToolbar();
176 void UpdateListColors();
177 BOOL InitList();
178 static INT CALLBACK ListViewCompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lpData);
179
183 int LV_AddItem(PCUITEMID_CHILD pidl);
192 HRESULT FillArrangeAsMenu(HMENU hmenuArrange);
193 HRESULT CheckViewMode(HMENU hmenuView);
196 void OnDeactivate();
197 void DoActivate(UINT uState);
198 HRESULT drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
200 LRESULT OnExplorerCommand(UINT uCommand, BOOL bUseSelection);
201
202 // *** IOleWindow methods ***
203 virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *lphwnd);
205
206 // *** IShellView methods ***
211 virtual HRESULT STDMETHODCALLTYPE CreateViewWindow(IShellView *psvPrevious, LPCFOLDERSETTINGS pfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd);
217 virtual HRESULT STDMETHODCALLTYPE GetItemObject(UINT uItem, REFIID riid, void **ppv);
218
219 // *** IShellView2 methods ***
224
225 // *** IShellView3 methods ***
226 virtual HRESULT STDMETHODCALLTYPE CreateViewWindow3(IShellBrowser *psb, IShellView *psvPrevious, SV3CVW3_FLAGS view_flags, FOLDERFLAGS mask, FOLDERFLAGS flags, FOLDERVIEWMODE mode, const SHELLVIEWID *view_id, RECT *prcView, HWND *hwnd);
227
228 // *** IFolderView methods ***
232 virtual HRESULT STDMETHODCALLTYPE Item(int iItemIndex, PITEMID_CHILD *ppidl);
236 virtual HRESULT STDMETHODCALLTYPE GetFocusedItem(int *piItem);
243
244 // *** IShellFolderView methods ***
268 virtual HRESULT STDMETHODCALLTYPE SetCallback(IShellFolderViewCB *new_cb, IShellFolderViewCB **old_cb);
270 virtual HRESULT STDMETHODCALLTYPE QuerySupport(UINT *support);
272
273 // *** IOleCommandTarget methods ***
274 virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText);
275 virtual HRESULT STDMETHODCALLTYPE Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut);
276
277 // *** IDropTarget methods ***
278 virtual HRESULT STDMETHODCALLTYPE DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
279 virtual HRESULT STDMETHODCALLTYPE DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
281 virtual HRESULT STDMETHODCALLTYPE Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
282
283 // *** IDropSource methods ***
284 virtual HRESULT STDMETHODCALLTYPE QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState);
286
287 // *** IViewObject methods ***
288 virtual HRESULT STDMETHODCALLTYPE Draw(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd,
289 HDC hdcTargetDev, HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL lprcWBounds,
290 BOOL (STDMETHODCALLTYPE *pfnContinue)(ULONG_PTR dwContinue), ULONG_PTR dwContinue);
291 virtual HRESULT STDMETHODCALLTYPE GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect,
292 DVTARGETDEVICE *ptd, HDC hicTargetDev, LOGPALETTE **ppColorSet);
293 virtual HRESULT STDMETHODCALLTYPE Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze);
294 virtual HRESULT STDMETHODCALLTYPE Unfreeze(DWORD dwFreeze);
295 virtual HRESULT STDMETHODCALLTYPE SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink);
296 virtual HRESULT STDMETHODCALLTYPE GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink);
297
298 // *** IServiceProvider methods ***
299 virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject);
300
301 // Message handlers
304 LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
310 LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
312 LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
316 LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
317 LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
322
323 virtual VOID OnFinalMessage(HWND) override;
324
326 {
327 static ATL::CWndClassInfo wc =
328 {
330 0, 0, NULL, NULL,
331 LoadCursor(NULL, IDC_ARROW), NULL, NULL, L"SHELLDLL_DefView", NULL
332 },
333 NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
334 };
335 return wc;
336 }
337
339 {
340 return WindowProc;
341 }
342
344 {
345 CDefView *pThis;
347
348 // Must hold a reference during message handling
349 pThis = reinterpret_cast<CDefView *>(hWnd);
350 pThis->AddRef();
352 pThis->Release();
353 return result;
354 }
355
379
381 // Windows returns E_NOINTERFACE for IOleWindow
382 // COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow)
383 COM_INTERFACE_ENTRY_IID(IID_IShellView, IShellView)
385 COM_INTERFACE_ENTRY_IID(IID_IShellView2, IShellView2)
386 COM_INTERFACE_ENTRY_IID(IID_IFolderView, IFolderView)
387 COM_INTERFACE_ENTRY_IID(IID_IShellFolderView, IShellFolderView)
388 COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget)
389 COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget)
390 COM_INTERFACE_ENTRY_IID(IID_IDropSource, IDropSource)
392 COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider)
394};
395
396// menu items
397#define IDM_VIEW_FILES (FCIDM_SHVIEWFIRST + 0x500)
398#define IDM_VIEW_IDW (FCIDM_SHVIEWFIRST + 0x501)
399#define IDM_MYFILEITEM (FCIDM_SHVIEWFIRST + 0x502)
400
401#define ID_LISTVIEW 1
402
403// windowsx.h
404#define GET_WM_COMMAND_ID(wp, lp) LOWORD(wp)
405#define GET_WM_COMMAND_HWND(wp, lp) (HWND)(lp)
406#define GET_WM_COMMAND_CMD(wp, lp) HIWORD(wp)
407
409
411 m_ListView(),
413 m_hMenu(NULL),
418 m_uState(0),
419 m_cidl(0),
420 m_apidl(NULL),
422 m_hNotify(0),
423 m_hAccel(NULL),
424 m_dwAspects(0),
425 m_dwAdvf(0),
431{
439
441}
442
444{
445 TRACE(" destroying IShellView(%p)\n", this);
446
448
450 {
453 }
454
455 if (m_hWnd)
456 {
458 }
459
461}
462
464{
465 m_pSFParent = shellFolder;
467
468 return S_OK;
469}
470
471// ##### helperfunctions for communication with ICommDlgBrowser #####
472
474{
475 HRESULT ret = S_OK;
476
477 if (m_pCommDlgBrowser.p != NULL)
478 {
479 TRACE("ICommDlgBrowser::IncludeObject pidl=%p\n", pidl);
480 ret = m_pCommDlgBrowser->IncludeObject(this, pidl);
481 TRACE("-- returns 0x%08x\n", ret);
482 }
483
484 return ret;
485}
486
488{
490
491 if (m_pCommDlgBrowser.p != NULL)
492 {
493 TRACE("ICommDlgBrowser::OnDefaultCommand\n");
494 ret = m_pCommDlgBrowser->OnDefaultCommand(this);
495 TRACE("-- returns 0x%08x\n", ret);
496 }
497
498 return ret;
499}
500
502{
504
505 if (m_pCommDlgBrowser.p != NULL)
506 {
507 TRACE("ICommDlgBrowser::OnStateChange flags=%x\n", uFlags);
508 ret = m_pCommDlgBrowser->OnStateChange(this, uFlags);
509 TRACE("--\n");
510 }
511
512 return ret;
513}
514/**********************************************************
515 * set the toolbar of the filedialog buttons
516 *
517 * - activates the buttons from the shellbrowser according to
518 * the view state
519 */
521{
523
524 TRACE("\n");
525
526 if (m_pCommDlgBrowser != NULL)
527 {
528 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_CHECKBUTTON,
530 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_CHECKBUTTON,
532 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON,
534 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON,
536 }
537}
538
540{
541 WCHAR szFormat[MAX_PATH] = {0};
542 WCHAR szPartText[MAX_PATH] = {0};
543 UINT cSelectedItems;
544
545 if (!m_ListView)
546 return;
547
548 cSelectedItems = m_ListView.GetSelectedCount();
549 if (cSelectedItems)
550 {
552 StringCchPrintfW(szPartText, _countof(szPartText), szFormat, cSelectedItems);
553 }
554 else
555 {
556 LoadStringW(shell32_hInstance, IDS_OBJECTS, szFormat, _countof(szFormat));
557 StringCchPrintfW(szPartText, _countof(szPartText), szFormat, m_ListView.GetItemCount());
558 }
559
560 LRESULT lResult;
561 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXT, 0, (LPARAM)szPartText, &lResult);
562
563 // Don't bother with the extra processing if we only have one StatusBar part
565 {
566 DWORD uTotalFileSize = 0;
567 WORD uFileFlags = LVNI_ALL;
568 LPARAM pIcon = NULL;
569 INT nItem = -1;
570 bool bIsOnlyFoldersSelected = true;
571
572 // If we have something selected then only count selected file sizes
573 if (cSelectedItems)
574 {
575 uFileFlags = LVNI_SELECTED;
576 }
577
578 while ((nItem = m_ListView.GetNextItem(nItem, uFileFlags)) >= 0)
579 {
580 PCUITEMID_CHILD pidl = _PidlByItem(nItem);
581
582 uTotalFileSize += _ILGetFileSize(pidl, NULL, 0);
583
584 if (!_ILIsFolder(pidl))
585 {
586 bIsOnlyFoldersSelected = false;
587 }
588 }
589
590 // Don't show the file size text if there is 0 bytes in the folder
591 // OR we only have folders selected
592 if ((cSelectedItems && !bIsOnlyFoldersSelected) || uTotalFileSize)
593 {
594 StrFormatByteSizeW(uTotalFileSize, szPartText, _countof(szPartText));
595 }
596 else
597 {
598 *szPartText = 0;
599 }
600
601 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXT, 1, (LPARAM)szPartText, &lResult);
602
603 // If we are in a Recycle Bin then show no text for the location part
605 {
606 LoadStringW(shell32_hInstance, IDS_MYCOMPUTER, szPartText, _countof(szPartText));
607 pIcon = (LPARAM)m_hMyComputerIcon;
608 }
609
610 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETICON, 2, pIcon, &lResult);
611 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXT, 2, (LPARAM)szPartText, &lResult);
612 }
613}
614
615
616// ##### helperfunctions for initializing the view #####
617
618// creates the list view window
620{
621 HRESULT hr;
622 DWORD dwStyle, dwExStyle, ListExStyle;
623 UINT ViewMode;
624
625 TRACE("%p\n", this);
626
628 LVS_SHAREIMAGELISTS | LVS_EDITLABELS | LVS_AUTOARRANGE; // FIXME: Why is LVS_AUTOARRANGE here?
629 dwExStyle = WS_EX_CLIENTEDGE;
630 ListExStyle = 0;
631
633 {
635 dwStyle |= LVS_ALIGNLEFT;
636 }
637 else
638 {
639 dwStyle |= LVS_SHOWSELALWAYS; // MSDN says FWF_SHOWSELALWAYS is deprecated, always turn on for folders
641 ListExStyle = LVS_EX_DOUBLEBUFFER;
642 }
643
644 ViewMode = m_FolderSettings.ViewMode;
645 hr = _DoFolderViewCB(SFVM_DEFVIEWMODE, 0, (LPARAM)&ViewMode);
646 if (SUCCEEDED(hr))
647 {
648 if (ViewMode >= FVM_FIRST && ViewMode <= FVM_LAST)
649 m_FolderSettings.ViewMode = ViewMode;
650 else
651 ERR("Ignoring invalid ViewMode from SFVM_DEFVIEWMODE: %u (was: %u)\n", ViewMode, m_FolderSettings.ViewMode);
652 }
653
655 {
656 case FVM_ICON:
657 dwStyle |= LVS_ICON;
658 break;
659 case FVM_DETAILS:
660 dwStyle |= LVS_REPORT;
661 break;
662 case FVM_SMALLICON:
663 dwStyle |= LVS_SMALLICON;
664 break;
665 case FVM_LIST:
666 dwStyle |= LVS_LIST;
667 break;
668 default:
669 dwStyle |= LVS_LIST;
670 break;
671 }
672
674 dwStyle |= LVS_AUTOARRANGE;
675
677 ListExStyle |= LVS_EX_SNAPTOGRID;
678
680 dwStyle |= LVS_SINGLESEL;
681
683 ListExStyle |= LVS_EX_FULLROWSELECT;
684
687
689 dwStyle |= LVS_NOCOLUMNHEADER;
690
691#if 0
692 // FIXME: Because this is a negative, everyone gets the new flag by default unless they
693 // opt out. This code should be enabled when shell looks like Vista instead of 2003
695 ListExStyle |= LVS_EX_HEADERINALLVIEWS;
696#endif
697
699 dwExStyle &= ~WS_EX_CLIENTEDGE;
700
701 RECT rcListView = {0,0,0,0};
702 m_ListView.Create(m_hWnd, rcListView, L"FolderView", dwStyle, dwExStyle, ID_LISTVIEW);
703
704 if (!m_ListView)
705 return FALSE;
706
708
712
713 /* UpdateShellSettings(); */
714 return TRUE;
715}
716
718{
720 {
721 /* Check if drop shadows option is enabled */
722 BOOL bDropShadow = FALSE;
723 DWORD cbDropShadow = sizeof(bDropShadow);
724
725 /*
726 * The desktop ListView always take the default desktop colours, by
727 * remaining transparent and letting user32/win32k paint itself the
728 * desktop background color, if any.
729 */
731
732 SHGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
733 L"ListviewShadow", NULL, &bDropShadow, &cbDropShadow);
734 if (bDropShadow)
735 {
736 /* Set the icon background transparent */
738 m_ListView.SetTextColor(RGB(255, 255, 255));
739 m_ListView.SetExtendedListViewStyle(LVS_EX_TRANSPARENTSHADOWTEXT, LVS_EX_TRANSPARENTSHADOWTEXT);
740 }
741 else
742 {
743 /* Set the icon background as the same colour as the desktop */
745 m_ListView.SetTextBkColor(crDesktop);
746 if (GetRValue(crDesktop) + GetGValue(crDesktop) + GetBValue(crDesktop) > 128 * 3)
747 m_ListView.SetTextColor(RGB(0, 0, 0));
748 else
749 m_ListView.SetTextColor(RGB(255, 255, 255));
750 m_ListView.SetExtendedListViewStyle(0, LVS_EX_TRANSPARENTSHADOWTEXT);
751 }
752 }
753 else
754 {
755 // text background color
757 m_ListView.SetTextBkColor(clrTextBack);
758
759 // text color
760 COLORREF clrText;
762 clrText = m_viewinfo_data.clrText;
763 else
764 clrText = GetSysColor(COLOR_WINDOWTEXT);
765
766 m_ListView.SetTextColor(clrText);
767
768 // Background is painted by the parent via WM_PRINTCLIENT
769 m_ListView.SetExtendedListViewStyle(LVS_EX_TRANSPARENTBKGND, LVS_EX_TRANSPARENTBKGND);
770 }
771}
772
773// adds all needed columns to the shellview
775{
777 WCHAR szTemp[50];
778 HIMAGELIST big_icons, small_icons;
779
780 TRACE("%p\n", this);
781
783
785
786 if (m_pSF2Parent)
787 {
788 for (int i = 0; 1; i++)
789 {
790 if (FAILED(m_pSF2Parent->GetDetailsOf(NULL, i, &sd)))
791 break;
792 StrRetToStrNW( szTemp, 50, &sd.str, NULL);
793 m_ListView.InsertColumn(i, szTemp, sd.fmt, sd.cxChar * 8);
794
795 InsertMenuW(m_hMenuArrangeModes, -1, MF_STRING, 0x30 + i, szTemp);
796 }
797
799 }
800 else
801 {
802 FIXME("no m_pSF2Parent\n");
803 }
804
805 Shell_GetImageLists(&big_icons, &small_icons);
807 m_ListView.SetImageList(small_icons, LVSIL_SMALL);
808
809 return TRUE;
810}
811
812/*************************************************************************
813 * ShellView_ListViewCompareItems
814 *
815 * Compare Function for the Listview (FileOpen Dialog)
816 *
817 * PARAMS
818 * lParam1 [I] the first ItemIdList to compare with
819 * lParam2 [I] the second ItemIdList to compare with
820 * lpData [I] The column ID for the header Ctrl to process
821 *
822 * RETURNS
823 * A negative value if the first item should precede the second,
824 * a positive value if the first item should follow the second,
825 * or zero if the two items are equivalent
826 */
828{
829 PCUIDLIST_RELATIVE pidl1 = reinterpret_cast<PCUIDLIST_RELATIVE>(lParam1);
830 PCUIDLIST_RELATIVE pidl2 = reinterpret_cast<PCUIDLIST_RELATIVE>(lParam2);
831 CDefView *pThis = reinterpret_cast<CDefView*>(lpData);
832
833 HRESULT hres = pThis->m_pSFParent->CompareIDs(pThis->m_sortInfo.nHeaderID, pidl1, pidl2);
835 return 0;
836
837 SHORT nDiff = HRESULT_CODE(hres);
838 if (!pThis->m_sortInfo.bIsAscending)
839 nDiff = -nDiff;
840 return nDiff;
841}
842
844{
845 HWND hHeader;
846 HDITEM hColumn;
847
848 if (m_ListView.GetWindowLongPtr(GWL_STYLE) & LVS_NOSORTHEADER)
849 return TRUE;
850
851 hHeader = (HWND)m_ListView.SendMessage(LVM_GETHEADER, 0, 0);
852 ZeroMemory(&hColumn, sizeof(hColumn));
853
854 // If the sorting column changed, remove sorting style from the old column
855 if ( (m_sortInfo.nLastHeaderID != -1) &&
857 {
858 hColumn.mask = HDI_FORMAT;
859 Header_GetItem(hHeader, m_sortInfo.nLastHeaderID, &hColumn);
860 hColumn.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN);
861 Header_SetItem(hHeader, m_sortInfo.nLastHeaderID, &hColumn);
862 }
863
864 /* Set the sorting style to the new column */
865 hColumn.mask = HDI_FORMAT;
866 Header_GetItem(hHeader, m_sortInfo.nHeaderID, &hColumn);
867
868 hColumn.fmt &= (m_sortInfo.bIsAscending ? ~HDF_SORTDOWN : ~HDF_SORTUP );
869 hColumn.fmt |= (m_sortInfo.bIsAscending ? HDF_SORTUP : HDF_SORTDOWN);
870 Header_SetItem(hHeader, m_sortInfo.nHeaderID, &hColumn);
871
872 /* Sort the list, using the current values of nHeaderID and bIsAscending */
875}
876
878{
879 if (!m_ListView)
880 return nullptr;
881 return reinterpret_cast<PCUITEMID_CHILD>(m_ListView.GetItemData(i));
882}
883
885{
886 if (!m_ListView)
887 return nullptr;
888 return reinterpret_cast<PCUITEMID_CHILD>(lvItem.lParam);
889}
890
892{
894
895 int cItems = m_ListView.GetItemCount();
896
897 for (int i = 0; i<cItems; i++)
898 {
899 PCUITEMID_CHILD currentpidl = _PidlByItem(i);
900 if (ILIsEqual(pidl, currentpidl))
901 return i;
902 }
903 return -1;
904}
905
907{
908 LVITEMW lvItem;
909
910 TRACE("(%p)(pidl=%p)\n", this, pidl);
911
913
915 return -1;
916
917 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM; // set mask
918 lvItem.iItem = m_ListView.GetItemCount(); // add item to lists end
919 lvItem.iSubItem = 0;
920 lvItem.lParam = reinterpret_cast<LPARAM>(ILClone(pidl)); // set item's data
921 lvItem.pszText = LPSTR_TEXTCALLBACKW; // get text on a callback basis
922 lvItem.iImage = I_IMAGECALLBACK; // get image on a callback basis
923 lvItem.stateMask = LVIS_CUT;
924
925 return m_ListView.InsertItem(&lvItem);
926}
927
929{
930 int nIndex;
931
932 TRACE("(%p)(pidl=%p)\n", this, pidl);
933
935
936 nIndex = LV_FindItemByPidl(pidl);
937 if (nIndex < 0)
938 return FALSE;
939
940 return m_ListView.DeleteItem(nIndex);
941}
942
944{
945 int nItem;
946 LVITEMW lvItem;
947
948 TRACE("(%p)(pidlold=%p pidlnew=%p)\n", this, pidlOld, pidlNew);
949
951
952 nItem = LV_FindItemByPidl(pidlOld);
953
954 if (-1 != nItem)
955 {
956 lvItem.mask = LVIF_PARAM; // only the pidl
957 lvItem.iItem = nItem;
958 lvItem.iSubItem = 0;
959 m_ListView.GetItem(&lvItem);
960
961 // Store old pidl until new item is replaced
962 LPVOID oldPidl = reinterpret_cast<LPVOID>(lvItem.lParam);
963
964 lvItem.mask = LVIF_PARAM | LVIF_IMAGE | LVIF_TEXT;
965 lvItem.iItem = nItem;
966 lvItem.iSubItem = 0;
967 lvItem.lParam = reinterpret_cast<LPARAM>(ILClone(pidlNew)); // set item's data
970 m_ListView.SetItem(&lvItem);
971 m_ListView.Update(nItem);
972
973 // Now that the new item is in place, we can safely release the old pidl
974 SHFree(oldPidl);
975
976 return TRUE; // FIXME: better handling
977 }
978
979 return FALSE;
980}
981
983{
984 int nItem;
985 LVITEMW lvItem;
986
987 TRACE("(%p)(pidl=%p)\n", this, pidl);
988
990
991 nItem = LV_FindItemByPidl(pidl);
992
993 if (-1 != nItem)
994 {
995 lvItem.mask = LVIF_IMAGE;
996 lvItem.iItem = nItem;
997 lvItem.iSubItem = 0;
999 m_ListView.SetItem(&lvItem);
1000 m_ListView.Update(nItem);
1001 return TRUE;
1002 }
1003
1004 return FALSE;
1005}
1006
1008{
1009 PITEMID_CHILD pidl = static_cast<PITEMID_CHILD>(ptr);
1010 CDefView *pThis = static_cast<CDefView *>(arg);
1011
1012 // in a commdlg this works as a filemask
1013 if (pThis->IncludeObject(pidl) == S_OK && pThis->m_ListView)
1014 pThis->LV_AddItem(pidl);
1015
1016 SHFree(pidl);
1017 return TRUE;
1018}
1019
1021// - gets the objectlist from the shellfolder
1022// - sorts the list
1023// - fills the list into the view
1025{
1026 CComPtr<IEnumIDList> pEnumIDList;
1027 PITEMID_CHILD pidl;
1028 DWORD dwFetched;
1029 HRESULT hRes;
1030 HDPA hdpa;
1031 DWORD dFlags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS;
1032 DWORD dwValue, cbValue;
1033
1034 TRACE("%p\n", this);
1035
1036 // determine if there is a setting to show all the hidden files/folders
1037 dwValue = 1;
1038 cbValue = sizeof(dwValue);
1040 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
1041 L"Hidden", NULL, &dwValue, &cbValue);
1042 if (dwValue == 1)
1043 {
1044 dFlags |= SHCONTF_INCLUDEHIDDEN;
1045 m_ListView.SendMessageW(LVM_SETCALLBACKMASK, LVIS_CUT, 0);
1046 }
1047
1048 dwValue = 0;
1049 cbValue = sizeof(dwValue);
1051 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
1052 L"ShowSuperHidden", NULL, &dwValue, &cbValue);
1053 if (dwValue)
1054 {
1055 dFlags |= SHCONTF_INCLUDESUPERHIDDEN;
1056 m_ListView.SendMessageW(LVM_SETCALLBACKMASK, LVIS_CUT, 0);
1057 }
1058
1059 // get the itemlist from the shfolder
1060 hRes = m_pSFParent->EnumObjects(m_hWnd, dFlags, &pEnumIDList);
1061 if (hRes != S_OK)
1062 {
1063 if (hRes == S_FALSE)
1064 return(NOERROR);
1065 return(hRes);
1066 }
1067
1068 // create a pointer array
1069 hdpa = DPA_Create(16);
1070 if (!hdpa)
1071 return(E_OUTOFMEMORY);
1072
1073 // copy the items into the array
1074 while((S_OK == pEnumIDList->Next(1, &pidl, &dwFetched)) && dwFetched)
1075 {
1076 if (DPA_InsertPtr(hdpa, 0x7fff, pidl) == -1)
1077 {
1078 SHFree(pidl);
1079 }
1080 }
1081
1082 // turn listview's redrawing off
1084
1085 DPA_DestroyCallback( hdpa, fill_list, this);
1086
1087 /* sort the array */
1088 if (m_pSF2Parent)
1089 {
1090 m_pSF2Parent->GetDefaultColumn(NULL, (ULONG*)&m_sortInfo.nHeaderID, NULL);
1091 }
1092 else
1093 {
1094 FIXME("no m_pSF2Parent\n");
1095 }
1097 _Sort();
1098
1100 {
1103 }
1104
1105 // load custom background image and custom text color
1108
1109 // turn listview's redrawing back on and force it to draw
1111
1113
1115 {
1116 // redraw now
1117 m_ListView.InvalidateRect(NULL, TRUE);
1118 }
1119
1121
1122 return S_OK;
1123}
1124
1126{
1127 if (m_ListView.IsWindow())
1128 m_ListView.UpdateWindow();
1129 bHandled = FALSE;
1130 return 0;
1131}
1132
1134{
1135 return m_ListView.SendMessageW(uMsg, 0, 0);
1136}
1137
1139{
1140 if (!m_Destroyed)
1141 {
1142 m_Destroyed = TRUE;
1143 if (m_hMenu)
1144 {
1146 m_hMenu = NULL;
1147 }
1150 m_hNotify = NULL;
1153 }
1154 bHandled = FALSE;
1155 return 0;
1156}
1157
1159{
1160 /* redirect to parent */
1163
1164 bHandled = FALSE;
1165 return 0;
1166}
1167
1168static VOID
1170{
1171 INT x0 = prc->left, y0 = prc->top, x1 = prc->right, y1 = prc->bottom;
1172 x0 += dx;
1173 y0 += dy;
1174
1175 HDC hMemDC = CreateCompatibleDC(hDC);
1176 HGDIOBJ hbmOld = SelectObject(hMemDC, hbm);
1177
1178 for (INT y = y0; y < y1; y += nHeight)
1179 {
1180 for (INT x = x0; x < x1; x += nWidth)
1181 {
1182 BitBlt(hDC, x, y, nWidth, nHeight, hMemDC, 0, 0, SRCCOPY);
1183 }
1184 }
1185
1186 SelectObject(hMemDC, hbmOld);
1187 DeleteDC(hMemDC);
1188}
1189
1191{
1192 HDC hDC = (HDC)wParam;
1193
1194 RECT rc;
1196
1198 {
1199 BITMAP bm;
1200 if (::GetObject(m_viewinfo_data.hbmBack, sizeof(BITMAP), &bm))
1201 {
1202 INT dx = -(::GetScrollPos(m_ListView, SB_HORZ) % bm.bmWidth);
1203 INT dy = -(::GetScrollPos(m_ListView, SB_VERT) % bm.bmHeight);
1204 DrawTileBitmap(hDC, &rc, m_viewinfo_data.hbmBack, bm.bmWidth, bm.bmHeight, dx, dy);
1205 }
1206 }
1207 else
1208 {
1210 }
1211
1212 bHandled = TRUE;
1213
1214 return TRUE;
1215}
1216
1218{
1219 /* Update desktop labels color */
1221
1222 /* Forward WM_SYSCOLORCHANGE to common controls */
1223 return m_ListView.SendMessageW(uMsg, 0, 0);
1224}
1225
1227{
1228 return reinterpret_cast<LRESULT>(m_pShellBrowser.p);
1229}
1230
1232{
1233 this->AddRef();
1234 bHandled = FALSE;
1235 return 0;
1236}
1237
1239{
1240 this->Release();
1241}
1242
1244{
1247
1248 TRACE("%p\n", this);
1249
1251 {
1252 if (FAILED(RegisterDragDrop(m_hWnd, pdt)))
1253 ERR("Error Registering DragDrop\n");
1254 }
1255
1256 /* register for receiving notifications */
1257 m_pSFParent->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
1258 if (ppf2)
1259 {
1260 ppf2->GetCurFolder(&m_pidlParent);
1261 }
1262
1263 if (CreateList())
1264 {
1265 if (InitList())
1266 {
1267 FillList();
1268 }
1269 }
1270
1272 {
1273 HWND hwndSB;
1274 m_pShellBrowser->GetWindow(&hwndSB);
1276 }
1277
1278 SHChangeNotifyEntry ntreg[1];
1279 ntreg[0].fRecursive = FALSE;
1280 ntreg[0].pidl = m_pidlParent;
1285 1, ntreg);
1286
1287 //_DoFolderViewCB(SFVM_GETNOTIFY, ?? ??)
1288
1290
1291 BOOL bPreviousParentSpecial = m_isParentFolderSpecial;
1292
1293 // A folder is special if it is the Desktop folder,
1294 // a network folder, or a Control Panel folder
1297
1298 // Only force StatusBar part refresh if the state
1299 // changed from the previous folder
1300 if (bPreviousParentSpecial != m_isParentFolderSpecial)
1301 {
1302 // This handles changing StatusBar parts
1304 }
1305
1307
1308 return S_OK;
1309}
1310
1311// #### Handling of the menus ####
1312
1313extern "C" DWORD WINAPI SHMenuIndexFromID(HMENU hMenu, UINT uID);
1314
1316{
1317 MENUITEMINFOW mii = {sizeof(mii), MIIM_SUBMENU};
1318 if (::GetMenuItemInfoW(hmenu, id, FALSE, &mii))
1319 return mii.hSubMenu;
1320
1321 return NULL;
1322}
1323
1324// ReallyGetMenuItemID returns the id of an item even if it opens a submenu,
1325// GetMenuItemID returns -1 if the specified item opens a submenu
1327{
1328 MENUITEMINFOW mii = {sizeof(mii), MIIM_ID};
1329 if (::GetMenuItemInfoW(hmenu, i, TRUE, &mii))
1330 return mii.wID;
1331
1332 return UINT_MAX;
1333}
1334
1336{
1338 if (!hFileMenu)
1339 return E_FAIL;
1340
1341 /* Cleanup the items added previously */
1342 for (int i = GetMenuItemCount(hFileMenu) - 1; i >= 0; i--)
1343 {
1344 UINT id = GetMenuItemID(hFileMenu, i);
1345 if (id < FCIDM_BROWSERFIRST || id > FCIDM_BROWSERLAST)
1346 DeleteMenu(hFileMenu, i, MF_BYPOSITION);
1347 }
1348
1349 // In case we still have this left over, clean it up
1350 if (m_pFileMenu)
1351 {
1354 }
1355 // Store context menu in m_pFileMenu and keep it to invoke the selected command later on
1358 return hr;
1359
1361
1362 hr = m_pFileMenu->QueryContextMenu(hmenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, 0);
1364 return hr;
1365
1366 // TODO: filter or something
1367
1368 Shell_MergeMenus(hFileMenu, hmenu, 0, 0, 0xFFFF, MM_ADDSEPARATOR | MM_SUBMENUSHAVEIDS);
1369
1371
1372 return S_OK;
1373}
1374
1376{
1378 if (!hEditMenu)
1379 return E_FAIL;
1380
1381 HMENU hmenuContents = ::LoadMenuW(shell32_hInstance, L"MENU_003");
1382 if (!hmenuContents)
1383 return E_FAIL;
1384
1385 Shell_MergeMenus(hEditMenu, hmenuContents, 0, 0, 0xFFFF, 0);
1386
1387 ::DestroyMenu(hmenuContents);
1388
1389 return S_OK;
1390}
1391
1393{
1395 if (!hViewMenu)
1396 return E_FAIL;
1397
1399 if (!m_hMenuViewModes)
1400 return E_FAIL;
1401
1404
1405 return S_OK;
1406}
1407
1409{
1410 /* We only need to fill this once */
1411 if (GetMenuItemID(hmenuArrange, 0) == FCIDM_SHVIEW_AUTOARRANGE)
1412 {
1413 Shell_MergeMenus(hmenuArrange, m_hMenuArrangeModes, 0, 0, 0xFFFF,0);
1414 }
1415
1416 /* Also check the menu item according to which we sort */
1417 CheckMenuRadioItem(hmenuArrange,
1418 0x30,
1419 0x100,
1420 m_sortInfo.nHeaderID + 0x30,
1421 MF_BYCOMMAND);
1422
1424 {
1427 }
1428 else
1429 {
1432
1433 if (GetAutoArrange() == S_OK)
1435 else
1437
1438 if (_GetSnapToGrid() == S_OK)
1440 else
1442 }
1443
1444 return S_OK;
1445}
1446
1448{
1450 {
1451 UINT iItemFirst = FCIDM_SHVIEW_BIGICON;
1452 UINT iItemLast = iItemFirst + FVM_LAST - FVM_FIRST;
1453 UINT iItem = iItemFirst + m_FolderSettings.ViewMode - FVM_FIRST;
1454 CheckMenuRadioItem(hmenuView, iItemFirst, iItemLast, iItem, MF_BYCOMMAND);
1455 }
1456
1457 return S_OK;
1458}
1459
1461// - fills the m_apidl list with the selected objects
1462//
1463// RETURNS
1464// number of selected items
1466{
1467 SHFree(m_apidl);
1468
1470 m_apidl = static_cast<PCUITEMID_CHILD*>(SHAlloc(m_cidl * sizeof(PCUITEMID_CHILD)));
1471 if (!m_apidl)
1472 {
1473 m_cidl = 0;
1474 return 0;
1475 }
1476
1477 TRACE("-- Items selected =%u\n", m_cidl);
1478
1480
1481 UINT i = 0;
1482 int lvIndex = -1;
1483 while ((lvIndex = m_ListView.GetNextItem(lvIndex, LVNI_SELECTED)) > -1)
1484 {
1485 m_apidl[i] = _PidlByItem(lvIndex);
1486 i++;
1487 if (i == m_cidl)
1488 break;
1489 TRACE("-- selected Item found\n");
1490 }
1491
1492 return m_cidl;
1493}
1494
1496{
1497 CMINVOKECOMMANDINFOEX cmi;
1498
1499 ZeroMemory(&cmi, sizeof(cmi));
1500 cmi.cbSize = sizeof(cmi);
1501 cmi.hwnd = m_hWnd;
1502 cmi.lpVerb = lpVerb;
1503
1504 if (GetKeyState(VK_SHIFT) & 0x8000)
1505 cmi.fMask |= CMIC_MASK_SHIFT_DOWN;
1506
1507 if (GetKeyState(VK_CONTROL) & 0x8000)
1508 cmi.fMask |= CMIC_MASK_CONTROL_DOWN;
1509
1510 if (pt)
1511 {
1512 cmi.fMask |= CMIC_MASK_PTINVOKE;
1513 cmi.ptInvoke = *pt;
1514 }
1515
1516 HRESULT hr = pCM->InvokeCommand((LPCMINVOKECOMMANDINFO)&cmi);
1517 // Most of our callers will do this, but if they would forget (File menu!)
1518 IUnknown_SetSite(pCM, NULL);
1519 pCM.Release();
1520
1522 return hr;
1523
1524 return S_OK;
1525}
1526
1528{
1529 HMENU hMenu;
1530 UINT uCommand;
1531 HRESULT hResult;
1532
1534 if (m_cidl == 0)
1535 return S_OK;
1536
1537 hResult = OnDefaultCommand();
1538 if (hResult == S_OK)
1539 return hResult;
1540
1541 hMenu = CreatePopupMenu();
1542 if (!hMenu)
1543 return E_FAIL;
1544
1547 MenuCleanup _(pCM, hMenu);
1548 if (FAILED_UNEXPECTEDLY(hResult))
1549 return hResult;
1550
1551 hResult = pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_DEFAULTONLY);
1552 if (FAILED_UNEXPECTEDLY(hResult))
1553 return hResult;
1554
1555 uCommand = GetMenuDefaultItem(hMenu, FALSE, 0);
1556 if (uCommand == (UINT)-1)
1557 {
1558 ERR("GetMenuDefaultItem returned -1\n");
1559 return E_FAIL;
1560 }
1561
1563
1564 return hResult;
1565}
1566
1568{
1569 POINT pt;
1570 UINT uCommand;
1571 HRESULT hResult;
1572
1573 TRACE("(%p)\n", this);
1574
1575 if (m_hContextMenu != NULL)
1576 {
1577 ERR("HACK: Aborting context menu in nested call\n");
1578 return 0;
1579 }
1580
1582 if (!m_hContextMenu)
1583 return E_FAIL;
1584
1585 if (lParam != ~0) // unless app key (menu key) was pressed
1586 {
1587 pt.x = GET_X_LPARAM(lParam);
1588 pt.y = GET_Y_LPARAM(lParam);
1589
1590 LV_HITTESTINFO hittest = { pt };
1591 ScreenToClient(&hittest.pt);
1592 m_ListView.HitTest(&hittest);
1593
1594 // Right-Clicked item is selected? If selected, no selection change.
1595 // If not selected, then reset the selection and select the item.
1596 if ((hittest.flags & LVHT_ONITEM) &&
1598 {
1599 SelectItem(hittest.iItem, SVSI_SELECT | SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE);
1600 }
1601 }
1602
1604 // In case we still have this left over, clean it up
1607 if (FAILED_UNEXPECTEDLY(hResult))
1608 return 0;
1609
1610 // Use 1 as the first id we want. 0 means that user canceled the menu
1611 hResult = m_pCM->QueryContextMenu(m_hContextMenu, 0, CONTEXT_MENU_BASE_ID, FCIDM_SHVIEWLAST, CMF_NORMAL);
1612 if (FAILED_UNEXPECTEDLY(hResult))
1613 return 0;
1614
1615 // There is no position requested, so try to find one
1616 if (lParam == ~0)
1617 {
1618 HWND hFocus = ::GetFocus();
1619 int lvIndex = -1;
1620
1621 if (hFocus == m_ListView.m_hWnd || m_ListView.IsChild(hFocus))
1622 {
1623 // Is there an item focused and selected?
1625 // If not, find the first selected item
1626 if (lvIndex < 0)
1627 lvIndex = m_ListView.GetNextItem(-1, LVIS_SELECTED);
1628 }
1629
1630 // We got something
1631 if (lvIndex > -1)
1632 {
1633 // Find the center of the icon
1634 RECT rc = { LVIR_ICON };
1635 m_ListView.SendMessage(LVM_GETITEMRECT, lvIndex, (LPARAM)&rc);
1636 pt.x = (rc.right + rc.left) / 2;
1637 pt.y = (rc.bottom + rc.top) / 2;
1638 }
1639 else
1640 {
1641 // We have to drop it somewhere
1642 pt.x = pt.y = 0;
1643 }
1644
1645 m_ListView.ClientToScreen(&pt);
1646 }
1647
1648 // This runs the message loop, calling back to us with f.e. WM_INITPOPUP (hence why m_hContextMenu and m_pCM exist)
1649 uCommand = TrackPopupMenu(m_hContextMenu,
1651 pt.x, pt.y, 0, m_hWnd, NULL);
1652 if (uCommand == 0)
1653 return 0;
1654
1655 if (uCommand == FCIDM_SHVIEW_OPEN && OnDefaultCommand() == S_OK)
1656 return 0;
1657
1659
1660 return 0;
1661}
1662
1664{
1665 HRESULT hResult;
1666 HMENU hMenu = NULL;
1667
1669 hResult = GetItemObject(bUseSelection ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &pCM));
1670 if (FAILED_UNEXPECTEDLY(hResult))
1671 return 0;
1672
1673 MenuCleanup _(pCM, hMenu);
1674
1675 if ((uCommand != FCIDM_SHVIEW_DELETE) && (uCommand != FCIDM_SHVIEW_RENAME))
1676 {
1677 hMenu = CreatePopupMenu();
1678 if (!hMenu)
1679 return 0;
1680
1681 hResult = pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_NORMAL);
1682 if (FAILED_UNEXPECTEDLY(hResult))
1683 return 0;
1684 }
1685
1686 if (bUseSelection)
1687 {
1688 // FIXME: we should cache this
1689 SFGAOF rfg = SFGAO_BROWSABLE | SFGAO_CANCOPY | SFGAO_CANLINK | SFGAO_CANMOVE | SFGAO_CANDELETE | SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSTEM | SFGAO_FOLDER;
1690 hResult = m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &rfg);
1691 if (FAILED_UNEXPECTEDLY(hResult))
1692 return 0;
1693
1694 if (!(rfg & SFGAO_CANMOVE) && uCommand == FCIDM_SHVIEW_CUT)
1695 return 0;
1696 if (!(rfg & SFGAO_CANCOPY) && uCommand == FCIDM_SHVIEW_COPY)
1697 return 0;
1698 if (!(rfg & SFGAO_CANDELETE) && uCommand == FCIDM_SHVIEW_DELETE)
1699 return 0;
1700 if (!(rfg & SFGAO_CANRENAME) && uCommand == FCIDM_SHVIEW_RENAME)
1701 return 0;
1702 if (!(rfg & SFGAO_HASPROPSHEET) && uCommand == FCIDM_SHVIEW_PROPERTIES)
1703 return 0;
1704 }
1705
1706 // FIXME: We should probably use the objects position?
1708 return 0;
1709}
1710
1711// ##### message handling #####
1712
1714{
1715 WORD wWidth, wHeight;
1716
1717 wWidth = LOWORD(lParam);
1718 wHeight = HIWORD(lParam);
1719
1720 TRACE("%p width=%u height=%u\n", this, wWidth, wHeight);
1721
1722 // WM_SIZE can come before WM_CREATE
1723 if (!m_ListView)
1724 return 0;
1725
1726 /* Resize the ListView to fit our window */
1727 ::MoveWindow(m_ListView, 0, 0, wWidth, wHeight, TRUE);
1728
1730
1733
1734 return 0;
1735}
1736
1737// internal
1739{
1740 TRACE("%p\n", this);
1741
1743 {
1744 // TODO: cleanup menu after deactivation
1746 }
1747}
1748
1750{
1751 TRACE("%p uState=%x\n", this, uState);
1752
1753 // don't do anything if the state isn't really changing
1754 if (m_uState == uState)
1755 {
1756 return;
1757 }
1758
1759 if (uState == SVUIA_DEACTIVATE)
1760 {
1761 OnDeactivate();
1762 }
1763 else
1764 {
1766 {
1767 FillEditMenu();
1768 FillViewMenu();
1769 m_pShellBrowser->SetMenuSB(m_hMenu, 0, m_hWnd);
1771 }
1772
1773 if (SVUIA_ACTIVATE_FOCUS == uState)
1774 {
1775 m_ListView.SetFocus();
1776 }
1777 }
1778
1779 m_uState = uState;
1780 TRACE("--\n");
1781}
1782
1784{
1785 if (!GetSelections())
1786 return;
1787
1788 SFGAOF rfg = SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_FILESYSTEM;
1789 HRESULT hr = m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &rfg);
1791 return;
1792
1793 if (!bCopy && !(rfg & SFGAO_CANMOVE))
1794 return;
1795 if (bCopy && !(rfg & SFGAO_CANCOPY))
1796 return;
1797
1799 hr = m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, IID_IContextMenu, 0, (void **)&pCM);
1801 return;
1802
1803 InvokeContextMenuCommand(pCM, (bCopy ? "copyto" : "moveto"), NULL);
1804}
1805
1807{
1809 return 0;
1810}
1811
1813{
1814 TRACE("%p\n", this);
1815
1816 /* Tell the browser one of our windows has received the focus. This
1817 should always be done before merging menus (OnActivate merges the
1818 menus) if one of our windows has the focus.*/
1819
1820 m_pShellBrowser->OnViewWindowActive(this);
1822
1823 /* Set the focus to the listview */
1824 m_ListView.SetFocus();
1825
1826 /* Notify the ICommDlgBrowser interface */
1827 OnStateChange(CDBOSC_SETFOCUS);
1828
1829 return 0;
1830}
1831
1833{
1834 TRACE("(%p) stub\n", this);
1835
1837 /* Notify the ICommDlgBrowser */
1838 OnStateChange(CDBOSC_KILLFOCUS);
1839
1840 return 0;
1841}
1842
1843// the CmdID's are the ones from the context menu
1845{
1846 DWORD dwCmdID;
1847 DWORD dwCmd;
1848 HWND hwndCmd;
1849 int nCount;
1850
1851 dwCmdID = GET_WM_COMMAND_ID(wParam, lParam);
1853 hwndCmd = GET_WM_COMMAND_HWND(wParam, lParam);
1854
1855 TRACE("(%p)->(0x%08x 0x%08x %p) stub\n", this, dwCmdID, dwCmd, hwndCmd);
1856
1857 switch (dwCmdID)
1858 {
1862 CheckToolbar();
1863 break;
1866 m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_ICON);
1867 CheckToolbar();
1868 break;
1871 m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_LIST);
1872 CheckToolbar();
1873 break;
1876 m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_REPORT);
1877 CheckToolbar();
1878 break;
1879 /* the menu-ID's for sorting are 0x30... see shrec.rc */
1880 case 0x30:
1881 case 0x31:
1882 case 0x32:
1883 case 0x33:
1884 m_sortInfo.nHeaderID = dwCmdID - 0x30;
1886 _Sort();
1887 break;
1890 break;
1892 if (_GetSnapToGrid() == S_OK)
1894 else
1895 ArrangeGrid();
1896 break;
1898 if (GetAutoArrange() == S_OK)
1899 m_ListView.ModifyStyle(LVS_AUTOARRANGE, 0);
1900 else
1901 AutoArrange();
1902 break;
1905 break;
1907 nCount = m_ListView.GetItemCount();
1908 for (int i=0; i < nCount; i++)
1910 break;
1912 Refresh();
1913 break;
1915 case FCIDM_SHVIEW_CUT:
1916 case FCIDM_SHVIEW_COPY:
1920 return 0;
1921 return OnExplorerCommand(dwCmdID, TRUE);
1925 return 0;
1927 case FCIDM_SHVIEW_UNDO:
1930 return OnExplorerCommand(dwCmdID, FALSE);
1931 default:
1932 // WM_COMMAND messages from file menu are routed to CDefView to let m_pFileMenu handle them
1933 if (m_pFileMenu && dwCmd == 0)
1934 {
1935 HMENU Dummy = NULL;
1936 MenuCleanup _(m_pFileMenu, Dummy);
1938 }
1939 }
1940
1941 return 0;
1942}
1943
1944static BOOL
1946{
1947 HKEY hKey;
1948 LONG error;
1949 DWORD dwValue = FALSE, cbValue;
1950
1952 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer",
1953 0, KEY_READ, &hKey);
1954 if (error)
1955 return dwValue;
1956
1957 cbValue = sizeof(dwValue);
1958 RegQueryValueExW(hKey, L"SelectExtOnRename", NULL, NULL, (LPBYTE)&dwValue, &cbValue);
1959
1961 return !!dwValue;
1962}
1963
1965{
1966 UINT CtlID;
1967 LPNMHDR lpnmh;
1968 LPNMLISTVIEW lpnmlv;
1969 NMLVDISPINFOW *lpdi;
1970 PCUITEMID_CHILD pidl;
1971 BOOL unused;
1972
1973 CtlID = wParam;
1974 lpnmh = (LPNMHDR)lParam;
1975 lpnmlv = (LPNMLISTVIEW)lpnmh;
1976 lpdi = (NMLVDISPINFOW *)lpnmh;
1977
1978 TRACE("%p CtlID=%u lpnmh->code=%x\n", this, CtlID, lpnmh->code);
1979
1980 switch (lpnmh->code)
1981 {
1982 case NM_SETFOCUS:
1983 TRACE("-- NM_SETFOCUS %p\n", this);
1984 OnSetFocus(0, 0, 0, unused);
1985 break;
1986 case NM_KILLFOCUS:
1987 TRACE("-- NM_KILLFOCUS %p\n", this);
1988 OnDeactivate();
1989 /* Notify the ICommDlgBrowser interface */
1990 OnStateChange(CDBOSC_KILLFOCUS);
1991 break;
1992 case NM_CUSTOMDRAW:
1993 TRACE("-- NM_CUSTOMDRAW %p\n", this);
1994 return CDRF_DODEFAULT;
1995 case NM_RELEASEDCAPTURE:
1996 TRACE("-- NM_RELEASEDCAPTURE %p\n", this);
1997 break;
1998 case NM_CLICK:
1999 TRACE("-- NM_CLICK %p\n", this);
2000 break;
2001 case NM_RCLICK:
2002 TRACE("-- NM_RCLICK %p\n", this);
2003 break;
2004 case NM_DBLCLK:
2005 TRACE("-- NM_DBLCLK %p\n", this);
2007 break;
2008 case NM_RETURN:
2009 TRACE("-- NM_RETURN %p\n", this);
2011 break;
2012 case HDN_ENDTRACKW:
2013 TRACE("-- HDN_ENDTRACKW %p\n", this);
2014 //nColumn1 = m_ListView.GetColumnWidth(0);
2015 //nColumn2 = m_ListView.GetColumnWidth(1);
2016 break;
2017 case LVN_DELETEITEM:
2018 TRACE("-- LVN_DELETEITEM %p\n", this);
2019 /*delete the pidl because we made a copy of it*/
2020 SHFree(reinterpret_cast<LPVOID>(lpnmlv->lParam));
2021 break;
2022 case LVN_DELETEALLITEMS:
2023 TRACE("-- LVN_DELETEALLITEMS %p\n", this);
2024 return FALSE;
2025 case LVN_INSERTITEM:
2026 TRACE("-- LVN_INSERTITEM (STUB)%p\n", this);
2027 break;
2028 case LVN_ITEMACTIVATE:
2029 TRACE("-- LVN_ITEMACTIVATE %p\n", this);
2030 OnStateChange(CDBOSC_SELCHANGE); // browser will get the IDataObject
2031 break;
2032 case LVN_COLUMNCLICK:
2033 m_sortInfo.nHeaderID = lpnmlv->iSubItem;
2036 else
2038 _Sort();
2039 break;
2040 case LVN_GETDISPINFOA:
2041 case LVN_GETDISPINFOW:
2042 TRACE("-- LVN_GETDISPINFO %p\n", this);
2043 pidl = _PidlByItem(lpdi->item);
2044
2045 if (lpdi->item.mask & LVIF_TEXT) /* text requested */
2046 {
2047 if (m_pSF2Parent)
2048 {
2050 if (FAILED_UNEXPECTEDLY(m_pSF2Parent->GetDetailsOf(pidl, lpdi->item.iSubItem, &sd)))
2051 break;
2052
2053 if (lpnmh->code == LVN_GETDISPINFOA)
2054 {
2055 /* shouldn't happen */
2056 NMLVDISPINFOA *lpdiA = (NMLVDISPINFOA *)lpnmh;
2057 StrRetToStrNA( lpdiA->item.pszText, lpdiA->item.cchTextMax, &sd.str, NULL);
2058 TRACE("-- text=%s\n", lpdiA->item.pszText);
2059 }
2060 else /* LVN_GETDISPINFOW */
2061 {
2062 StrRetToStrNW( lpdi->item.pszText, lpdi->item.cchTextMax, &sd.str, NULL);
2063 TRACE("-- text=%s\n", debugstr_w(lpdi->item.pszText));
2064 }
2065 }
2066 else
2067 {
2068 FIXME("no m_pSF2Parent\n");
2069 }
2070 }
2071 if(lpdi->item.mask & LVIF_IMAGE) /* image requested */
2072 {
2074 }
2075 if(lpdi->item.mask & LVIF_STATE)
2076 {
2077 ULONG attributes = SFGAO_HIDDEN;
2078 if (SUCCEEDED(m_pSFParent->GetAttributesOf(1, &pidl, &attributes)))
2079 {
2080 if (attributes & SFGAO_HIDDEN)
2081 lpdi->item.state |= LVIS_CUT;
2082 }
2083 }
2084 lpdi->item.mask |= LVIF_DI_SETITEM;
2085 break;
2086 case LVN_ITEMCHANGED:
2087 TRACE("-- LVN_ITEMCHANGED %p\n", this);
2088 OnStateChange(CDBOSC_SELCHANGE); // browser will get the IDataObject
2090 _DoFolderViewCB(SFVM_SELECTIONCHANGED, NULL/* FIXME */, NULL/* FIXME */);
2091 break;
2092 case LVN_BEGINDRAG:
2093 case LVN_BEGINRDRAG:
2094 TRACE("-- LVN_BEGINDRAG\n");
2095 if (GetSelections())
2096 {
2098 DWORD dwAttributes = SFGAO_CANCOPY | SFGAO_CANLINK;
2099 DWORD dwEffect = DROPEFFECT_MOVE;
2100
2101 if (SUCCEEDED(m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, IID_NULL_PPV_ARG(IDataObject, &pda))))
2102 {
2104
2105 if (SUCCEEDED(m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &dwAttributes)))
2106 dwEffect |= dwAttributes & (SFGAO_CANCOPY | SFGAO_CANLINK);
2107
2109 if (SUCCEEDED(pda->QueryInterface(IID_PPV_ARG(IAsyncOperation, &piaso))))
2110 piaso->SetAsyncMode(TRUE);
2111
2112 DWORD dwEffect2;
2113
2114 m_pSourceDataObject = pda;
2115 m_ptFirstMousePos = params->ptAction;
2118
2119 HIMAGELIST big_icons, small_icons;
2120 Shell_GetImageLists(&big_icons, &small_icons);
2121 PCUITEMID_CHILD pidl = _PidlByItem(params->iItem);
2122 int iIcon = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
2123 POINT ptItem;
2124 m_ListView.GetItemPosition(params->iItem, &ptItem);
2125
2126 ImageList_BeginDrag(big_icons, iIcon, params->ptAction.x - ptItem.x, params->ptAction.y - ptItem.y);
2127 DoDragDrop(pda, this, dwEffect, &dwEffect2);
2129 }
2130 }
2131 break;
2133 {
2134 DWORD dwAttr = SFGAO_CANRENAME;
2135 pidl = _PidlByItem(lpdi->item);
2136
2137 TRACE("-- LVN_BEGINLABELEDITW %p\n", this);
2138
2139 m_pSFParent->GetAttributesOf(1, &pidl, &dwAttr);
2140 if (SFGAO_CANRENAME & dwAttr)
2141 {
2142 HWND hEdit = reinterpret_cast<HWND>(m_ListView.SendMessage(LVM_GETEDITCONTROL));
2144
2145 // smartass-renaming: See CORE-15242
2146 if (!(dwAttr & SFGAO_FOLDER) && (dwAttr & SFGAO_FILESYSTEM) &&
2147 (lpdi->item.mask & LVIF_TEXT) && !SelectExtOnRename())
2148 {
2149 WCHAR szFullPath[MAX_PATH];
2150 PIDLIST_ABSOLUTE pidlFull = ILCombine(m_pidlParent, pidl);
2151 SHGetPathFromIDListW(pidlFull, szFullPath);
2152
2153 if (!SHELL_FS_HideExtension(szFullPath))
2154 {
2155 LPWSTR pszText = lpdi->item.pszText;
2156 LPWSTR pchDotExt = PathFindExtensionW(pszText);
2157 ::PostMessageW(hEdit, EM_SETSEL, 0, pchDotExt - pszText);
2159 }
2160
2161 ILFree(pidlFull);
2162 }
2163
2164 m_isEditing = TRUE;
2165 return FALSE;
2166 }
2167 return TRUE;
2168 }
2169 case LVN_ENDLABELEDITW:
2170 {
2171 TRACE("-- LVN_ENDLABELEDITW %p\n", this);
2173
2174 if (lpdi->item.pszText)
2175 {
2176 HRESULT hr;
2177 LVITEMW lvItem;
2178
2179 pidl = _PidlByItem(lpdi->item);
2180 PITEMID_CHILD pidlNew = NULL;
2181 hr = m_pSFParent->SetNameOf(0, pidl, lpdi->item.pszText, SHGDN_INFOLDER, &pidlNew);
2182
2183 if (SUCCEEDED(hr) && pidlNew)
2184 {
2185 lvItem.mask = LVIF_PARAM|LVIF_IMAGE;
2186 lvItem.iItem = lpdi->item.iItem;
2187 lvItem.iSubItem = 0;
2188 lvItem.lParam = reinterpret_cast<LPARAM>(pidlNew);
2190 m_ListView.SetItem(&lvItem);
2191 m_ListView.Update(lpdi->item.iItem);
2192 return TRUE;
2193 }
2194 }
2195
2196 return FALSE;
2197 }
2198 default:
2199 TRACE("-- %p WM_COMMAND %x unhandled\n", this, lpnmh->code);
2200 break;
2201 }
2202
2203 return 0;
2204}
2205
2206// This is just a quick hack to make the desktop work correctly.
2207// ITranslateShellChangeNotify's IsChildID is undocumented, but most likely the
2208// way that a folder should know if it should update upon a change notification.
2209// It is exported by merged folders at a minimum.
2211{
2212 if (!pidl1 || !pidl2)
2213 return FALSE;
2214 if (ILIsParent(pidl1, pidl2, TRUE))
2215 return TRUE;
2216
2217 if (_ILIsDesktop(pidl1))
2218 {
2219 PIDLIST_ABSOLUTE deskpidl;
2221 if (ILIsParent(deskpidl, pidl2, TRUE))
2222 {
2223 ILFree(deskpidl);
2224 return TRUE;
2225 }
2226 ILFree(deskpidl);
2228 if (ILIsParent(deskpidl, pidl2, TRUE))
2229 {
2230 ILFree(deskpidl);
2231 return TRUE;
2232 }
2233 ILFree(deskpidl);
2234 }
2235
2236 WCHAR szPath1[MAX_PATH], szPath2[MAX_PATH];
2237 LPITEMIDLIST pidl2Clone = ILClone(pidl2);
2238 ILRemoveLastID(pidl2Clone);
2239 if (SHGetPathFromIDListW(pidl1, szPath1) &&
2240 SHGetPathFromIDListW(pidl2Clone, szPath2))
2241 {
2242 if (lstrcmpiW(szPath1, szPath2) == 0)
2243 {
2244 ILFree(pidl2Clone);
2245 return TRUE;
2246 }
2247 }
2248 ILFree(pidl2Clone);
2249
2250 return FALSE;
2251}
2252
2254{
2255 // The change notify can come before WM_CREATE
2256 if (!m_ListView)
2257 return FALSE;
2258
2259 HANDLE hChange = (HANDLE)wParam;
2260 DWORD dwProcID = (DWORD)lParam;
2261 PIDLIST_ABSOLUTE *Pidls;
2262 LONG lEvent;
2263 HANDLE hLock = SHChangeNotification_Lock(hChange, dwProcID, &Pidls, &lEvent);
2264 if (hLock == NULL)
2265 {
2266 ERR("hLock == NULL\n");
2267 return FALSE;
2268 }
2269
2270 BOOL bParent0 = ILIsParentOrSpecialParent(m_pidlParent, Pidls[0]);
2271 BOOL bParent1 = ILIsParentOrSpecialParent(m_pidlParent, Pidls[1]);
2272
2273 TRACE("(%p)(%p,%p,0x%08x)\n", this, Pidls[0], Pidls[1], lParam);
2274
2275 lEvent &= ~SHCNE_INTERRUPT;
2276 switch (lEvent)
2277 {
2278 case SHCNE_MKDIR:
2279 case SHCNE_CREATE:
2280 if (bParent0)
2281 {
2282 if (LV_FindItemByPidl(ILFindLastID(Pidls[0])) == -1)
2283 LV_AddItem(ILFindLastID(Pidls[0]));
2284 else
2285 LV_ProdItem(ILFindLastID(Pidls[0]));
2286 }
2287 break;
2288 case SHCNE_RMDIR:
2289 case SHCNE_DELETE:
2290 if (bParent0)
2291 LV_DeleteItem(ILFindLastID(Pidls[0]));
2292 break;
2293 case SHCNE_RENAMEFOLDER:
2294 case SHCNE_RENAMEITEM:
2295 if (bParent0 && bParent1)
2296 LV_RenameItem(ILFindLastID(Pidls[0]), ILFindLastID(Pidls[1]));
2297 else if (bParent0)
2298 LV_DeleteItem(ILFindLastID(Pidls[0]));
2299 else if (bParent1)
2300 LV_AddItem(ILFindLastID(Pidls[1]));
2301 break;
2302 case SHCNE_UPDATEITEM:
2303 if (bParent0)
2304 LV_RenameItem(ILFindLastID(Pidls[0]), ILFindLastID(Pidls[0]));
2305 break;
2306 case SHCNE_UPDATEDIR:
2307 Refresh();
2308 break;
2309 }
2310
2312 return TRUE;
2313}
2314
2317
2319{
2320 if (!m_pCM)
2321 {
2322 /* no menu */
2323 ERR("no context menu\n");
2324 return FALSE;
2325 }
2326
2327 // lParam of WM_DRAWITEM WM_MEASUREITEM contains a menu id and
2328 // this also needs to be changed to a menu identifier offset
2329 UINT CmdID;
2330 HRESULT hres = SHGetMenuIdFromMenuMsg(uMsg, lParam, &CmdID);
2331 if (SUCCEEDED(hres))
2333
2334 /* Forward the message to the IContextMenu2 */
2337
2338 return (SUCCEEDED(hres));
2339}
2340
2342{
2343 /* Wallpaper setting affects drop shadows effect */
2344 if (wParam == SPI_SETDESKWALLPAPER || wParam == 0)
2346
2347 return S_OK;
2348}
2349
2351{
2352 HMENU hmenu = (HMENU) wParam;
2353 int nPos = LOWORD(lParam);
2354 UINT menuItemId;
2355
2356 if (m_pCM)
2357 OnCustomItem(uMsg, wParam, lParam, bHandled);
2358
2360
2361 if (GetSelections() == 0)
2362 {
2369 }
2370 else
2371 {
2372 // FIXME: Check copyable
2379 }
2380
2381 /* Lets try to find out what the hell wParam is */
2382 if (hmenu == GetSubMenu(m_hMenu, nPos))
2383 menuItemId = ReallyGetMenuItemID(m_hMenu, nPos);
2384 else if (hViewMenu && hmenu == GetSubMenu(hViewMenu, nPos))
2385 menuItemId = ReallyGetMenuItemID(hViewMenu, nPos);
2386 else if (m_hContextMenu && hmenu == GetSubMenu(m_hContextMenu, nPos))
2387 menuItemId = ReallyGetMenuItemID(m_hContextMenu, nPos);
2388 else
2389 return FALSE;
2390
2391 switch (menuItemId)
2392 {
2393 case FCIDM_MENU_FILE:
2394 FillFileMenu();
2395 break;
2396 case FCIDM_MENU_VIEW:
2397 case FCIDM_SHVIEW_VIEW:
2399 break;
2402 break;
2403 }
2404
2405 return FALSE;
2406}
2407
2408
2409// The INTERFACE of the IShellView object
2410
2412{
2413 TRACE("(%p)\n", this);
2414
2415 *phWnd = m_hWnd;
2416
2417 return S_OK;
2418}
2419
2421{
2422 FIXME("(%p) stub\n", this);
2423
2424 return E_NOTIMPL;
2425}
2426
2427// FIXME: use the accel functions
2429{
2430 if (m_isEditing)
2431 return S_FALSE;
2432
2433 if (lpmsg->message >= WM_KEYFIRST && lpmsg->message <= WM_KEYLAST)
2434 {
2435 if (::TranslateAcceleratorW(m_hWnd, m_hAccel, lpmsg) != 0)
2436 return S_OK;
2437
2438 TRACE("-- key=0x%04lx\n", lpmsg->wParam);
2439 }
2440
2441 return m_pShellBrowser->TranslateAcceleratorSB(lpmsg, 0);
2442}
2443
2445{
2446 FIXME("(%p)\n", this);
2447 return E_NOTIMPL;
2448}
2449
2451{
2452 TRACE("(%p)->(state=%x)\n", this, uState);
2453
2454 // don't do anything if the state isn't changing
2455 if (m_uState == uState)
2456 return S_OK;
2457
2458 // OnActivate handles the menu merging and internal state
2459 DoActivate(uState);
2460
2461 // only do this if we are active
2462 if (uState != SVUIA_DEACTIVATE)
2463 {
2465
2466 // Set the text for the status bar
2468 }
2469
2470 return S_OK;
2471}
2472
2474{
2475 TRACE("(%p)\n", this);
2476
2478
2480 FillList();
2481
2482 return S_OK;
2483}
2484
2486{
2487 return CreateViewWindow3(psb, lpPrevView, SV3CVW3_DEFAULT,
2488 (FOLDERFLAGS)lpfs->fFlags, (FOLDERFLAGS)lpfs->fFlags, (FOLDERVIEWMODE)lpfs->ViewMode, NULL, prcView, phWnd);
2489}
2490
2492{
2493 TRACE("(%p)\n", this);
2494
2495 /* Make absolutely sure all our UI is cleaned up */
2497
2498 if (m_hAccel)
2499 {
2500 // MSDN: Accelerator tables loaded from resources are freed automatically when application terminates
2501 m_hAccel = NULL;
2502 }
2503
2505 {
2508 }
2509
2510 if (m_hMenuViewModes)
2511 {
2514 }
2515
2516 if (m_hMenu)
2517 {
2519 m_hMenu = NULL;
2520 }
2521
2522 if (m_ListView)
2523 {
2524 m_ListView.DestroyWindow();
2525 }
2526
2527 if (m_hWnd)
2528 {
2530 DestroyWindow();
2531 }
2532
2535
2536 return S_OK;
2537}
2538
2540{
2541 TRACE("(%p)->(%p) vmode=%x flags=%x\n", this, lpfs,
2543
2544 if (!lpfs)
2545 return E_INVALIDARG;
2546
2547 *lpfs = m_FolderSettings;
2548 return S_OK;
2549}
2550
2552{
2553 FIXME("(%p) stub\n", this);
2554
2555 return E_NOTIMPL;
2556}
2557
2559{
2560 FIXME("(%p) stub\n", this);
2561
2562 return S_OK;
2563}
2564
2566{
2567 int i;
2568
2569 TRACE("(%p)->(pidl=%p, 0x%08x) stub\n", this, pidl, uFlags);
2570
2571 if (!m_ListView)
2572 {
2573 ERR("!m_ListView\n");
2574 return E_FAIL;
2575 }
2576
2577 i = LV_FindItemByPidl(pidl);
2578 if (i == -1)
2579 return S_OK;
2580
2581 LVITEMW lvItem = {0};
2582 lvItem.mask = LVIF_STATE;
2584
2585 while (m_ListView.GetItem(&lvItem))
2586 {
2587 if (lvItem.iItem == i)
2588 {
2589 if (uFlags & SVSI_SELECT)
2590 lvItem.state |= LVIS_SELECTED;
2591 else
2592 lvItem.state &= ~LVIS_SELECTED;
2593
2594 if (uFlags & SVSI_FOCUSED)
2595 lvItem.state |= LVIS_FOCUSED;
2596 else
2597 lvItem.state &= ~LVIS_FOCUSED;
2598 }
2599 else
2600 {
2601 if (uFlags & SVSI_DESELECTOTHERS)
2602 {
2603 lvItem.state &= ~LVIS_SELECTED;
2604 }
2605 lvItem.state &= ~LVIS_FOCUSED;
2606 }
2607
2608 m_ListView.SetItem(&lvItem);
2609 lvItem.iItem++;
2610 }
2611
2612 if (uFlags & SVSI_ENSUREVISIBLE)
2614
2615 if((uFlags & SVSI_EDIT) == SVSI_EDIT)
2617
2618 return S_OK;
2619}
2620
2622{
2624
2625 TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n", this, uItem, debugstr_guid(&riid), ppvOut);
2626
2627 if (!ppvOut)
2628 return E_INVALIDARG;
2629
2630 *ppvOut = NULL;
2631
2632 switch (uItem)
2633 {
2634 case SVGIO_BACKGROUND:
2635 if (IsEqualIID(riid, IID_IContextMenu))
2636 {
2639 return hr;
2640
2641 IUnknown_SetSite(*((IUnknown**)ppvOut), (IShellView *)this);
2642 }
2643 else if (IsEqualIID(riid, IID_IDispatch))
2644 {
2646 {
2649 return hr;
2650 }
2651 hr = m_pShellFolderViewDual->QueryInterface(riid, ppvOut);
2652 }
2653 break;
2654 case SVGIO_SELECTION:
2655 GetSelections();
2656 hr = m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, riid, 0, ppvOut);
2658 return hr;
2659
2660 if (IsEqualIID(riid, IID_IContextMenu))
2661 IUnknown_SetSite(*((IUnknown**)ppvOut), (IShellView *)this);
2662
2663 break;
2664 }
2665
2666 TRACE("-- (%p)->(interface=%p)\n", this, *ppvOut);
2667
2668 return hr;
2669}
2670
2672{
2673 TRACE("(%p)->(%p), stub\n", this, pViewMode);
2674
2675 if (!pViewMode)
2676 return E_INVALIDARG;
2677
2678 *pViewMode = m_FolderSettings.ViewMode;
2679 return S_OK;
2680}
2681
2683{
2684 DWORD dwStyle;
2685 TRACE("(%p)->(%u), stub\n", this, ViewMode);
2686
2687 /* It's not redundant to check FVM_AUTO because it's a (UINT)-1 */
2688 if (((INT)ViewMode < FVM_FIRST || (INT)ViewMode > FVM_LAST) && ((INT)ViewMode != FVM_AUTO))
2689 return E_INVALIDARG;
2690
2691 /* Windows before Vista uses LVM_SETVIEW and possibly
2692 LVM_SETEXTENDEDLISTVIEWSTYLE to set the style of the listview,
2693 while later versions seem to accomplish this through other
2694 means. */
2695 switch (ViewMode)
2696 {
2697 case FVM_ICON:
2698 dwStyle = LVS_ICON;
2699 break;
2700 case FVM_DETAILS:
2701 dwStyle = LVS_REPORT;
2702 break;
2703 case FVM_SMALLICON:
2704 dwStyle = LVS_SMALLICON;
2705 break;
2706 case FVM_LIST:
2707 dwStyle = LVS_LIST;
2708 break;
2709 default:
2710 {
2711 FIXME("ViewMode %d not implemented\n", ViewMode);
2712 dwStyle = LVS_LIST;
2713 break;
2714 }
2715 }
2716
2717 m_ListView.ModifyStyle(LVS_TYPEMASK, dwStyle);
2718
2719 /* This will not necessarily be the actual mode set above.
2720 This mimics the behavior of Windows XP. */
2721 m_FolderSettings.ViewMode = ViewMode;
2722
2723 return S_OK;
2724}
2725
2727{
2728 if (m_pSFParent == NULL)
2729 return E_FAIL;
2730
2731 return m_pSFParent->QueryInterface(riid, ppv);
2732}
2733
2735{
2736 PCUITEMID_CHILD pidl = _PidlByItem(iItemIndex);
2737 if (pidl)
2738 {
2739 *ppidl = ILClone(pidl);
2740 return S_OK;
2741 }
2742
2743 *ppidl = 0;
2744 return E_INVALIDARG;
2745}
2746
2748{
2749 TRACE("(%p)->(%u %p)\n", this, uFlags, pcItems);
2750
2751 if (uFlags != SVGIO_ALLVIEW)
2752 FIXME("some flags unsupported, %x\n", uFlags & ~SVGIO_ALLVIEW);
2753
2755
2756 return S_OK;
2757}
2758
2760{
2761 return E_NOTIMPL;
2762}
2763
2765{
2766 TRACE("(%p)->(%p)\n", this, piItem);
2767
2768 *piItem = m_ListView.GetSelectionMark();
2769
2770 return S_OK;
2771}
2772
2774{
2775 TRACE("(%p)->(%p)\n", this, piItem);
2776
2777 *piItem = m_ListView.GetNextItem(-1, LVNI_FOCUSED);
2778
2779 return S_OK;
2780}
2781
2783{
2784 if (!m_ListView)
2785 {
2786 ERR("!m_ListView\n");
2787 return E_FAIL;
2788 }
2789
2790 int lvIndex = LV_FindItemByPidl(pidl);
2791 if (lvIndex == -1 || ppt == NULL)
2792 return E_INVALIDARG;
2793
2794 m_ListView.GetItemPosition(lvIndex, ppt);
2795 return S_OK;
2796}
2797
2799{
2800 TRACE("(%p)->(%p)\n", this, ppt);
2801
2802 if (!m_ListView)
2803 {
2804 ERR("!m_ListView\n");
2805 return S_FALSE;
2806 }
2807
2808 if (ppt)
2809 {
2810 SIZE spacing;
2811 m_ListView.GetItemSpacing(spacing);
2812
2813 ppt->x = spacing.cx;
2814 ppt->y = spacing.cy;
2815 }
2816
2817 return S_OK;
2818}
2819
2821{
2822 return E_NOTIMPL;
2823}
2824
2826{
2827 return ((m_ListView.GetStyle() & LVS_AUTOARRANGE) ? S_OK : S_FALSE);
2828}
2829
2831{
2832 DWORD dwExStyle = (DWORD)m_ListView.SendMessage(LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
2833 return ((dwExStyle & LVS_EX_SNAPTOGRID) ? S_OK : S_FALSE);
2834}
2835
2837{
2838 LVITEMW lvItem;
2839
2840 TRACE("(%p)->(%d, %x)\n", this, iItem, dwFlags);
2841
2842 lvItem.state = 0;
2843 lvItem.stateMask = LVIS_SELECTED;
2844
2845 if (dwFlags & SVSI_ENSUREVISIBLE)
2846 m_ListView.EnsureVisible(iItem, 0);
2847
2848 /* all items */
2849 if (dwFlags & SVSI_DESELECTOTHERS)
2851
2852 /* this item */
2853 if (dwFlags & SVSI_SELECT)
2854 lvItem.state |= LVIS_SELECTED;
2855
2856 if (dwFlags & SVSI_FOCUSED)
2857 lvItem.stateMask |= LVIS_FOCUSED;
2858
2859 m_ListView.SetItemState(iItem, lvItem.state, lvItem.stateMask);
2860
2861 if ((dwFlags & SVSI_EDIT) == SVSI_EDIT)
2862 m_ListView.EditLabel(iItem);
2863
2864 return S_OK;
2865}
2866
2868{
2870
2871 /* Reset the selection */
2873
2874 int lvIndex;
2875 for (UINT i = 0 ; i < m_cidl; i++)
2876 {
2877 lvIndex = LV_FindItemByPidl(apidl[i]);
2878 if (lvIndex != -1)
2879 {
2880 SelectItem(lvIndex, dwFlags);
2881 m_ListView.SetItemPosition(lvIndex, &apt[i]);
2882 }
2883 }
2884
2885 return S_OK;
2886}
2887
2888
2889// IShellView2 implementation
2890
2892{
2893 FIXME("(%p)->(%p, %lu) stub\n", this, view_guid, view_type);
2894 return E_NOTIMPL;
2895}
2896
2898{
2899 return CreateViewWindow3(view_params->psbOwner, view_params->psvPrev,
2900 SV3CVW3_DEFAULT, (FOLDERFLAGS)view_params->pfs->fFlags, (FOLDERFLAGS)view_params->pfs->fFlags,
2901 (FOLDERVIEWMODE)view_params->pfs->ViewMode, view_params->pvid, view_params->prcView, &view_params->hwndView);
2902}
2903
2905{
2906 OLEMENUGROUPWIDTHS omw = { { 0, 0, 0, 0, 0, 0 } };
2907
2908 *hwnd = NULL;
2909
2910 TRACE("(%p)->(shlview=%p shlbrs=%p rec=%p hwnd=%p vmode=%x flags=%x)\n", this, psvPrevious, psb, prcView, hwnd, mode, flags);
2911 if (prcView != NULL)
2912 TRACE("-- left=%i top=%i right=%i bottom=%i\n", prcView->left, prcView->top, prcView->right, prcView->bottom);
2913
2914 /* Validate the Shell Browser */
2915 if (psb == NULL || m_hWnd)
2916 return E_UNEXPECTED;
2917
2918 if (view_flags != SV3CVW3_DEFAULT)
2919 FIXME("unsupported view flags 0x%08x\n", view_flags);
2920
2921 /* Set up the member variables */
2922 m_pShellBrowser = psb;
2925
2926 if (view_id)
2927 {
2928 if (IsEqualIID(*view_id, VID_LargeIcons))
2930 else if (IsEqualIID(*view_id, VID_SmallIcons))
2932 else if (IsEqualIID(*view_id, VID_List))
2934 else if (IsEqualIID(*view_id, VID_Details))
2936 else if (IsEqualIID(*view_id, VID_Thumbnails))
2938 else if (IsEqualIID(*view_id, VID_Tile))
2940 else if (IsEqualIID(*view_id, VID_ThumbStrip))
2942 else
2943 FIXME("Ignoring unrecognized VID %s\n", debugstr_guid(view_id));
2944 }
2945
2946 /* Get our parent window */
2947 m_pShellBrowser->GetWindow(&m_hWndParent);
2948
2949 /* Try to get the ICommDlgBrowserInterface, adds a reference !!! */
2952 {
2953 TRACE("-- CommDlgBrowser\n");
2954 }
2955
2957 if (m_hWnd == NULL)
2958 return E_FAIL;
2959
2960 *hwnd = m_hWnd;
2961
2962 CheckToolbar();
2963
2964 if (!*hwnd)
2965 return E_FAIL;
2966
2968
2970 UpdateWindow();
2971
2972 if (!m_hMenu)
2973 {
2974 m_hMenu = CreateMenu();
2975 m_pShellBrowser->InsertMenusSB(m_hMenu, &omw);
2976 TRACE("-- after fnInsertMenusSB\n");
2977 }
2978
2979 _MergeToolbar();
2980
2981 return S_OK;
2982}
2983
2985{
2986 FIXME("(%p)->(%p) stub\n", this, new_pidl);
2987 return E_NOTIMPL;
2988}
2989
2991{
2992 FIXME("(%p)->(%p, %u, %p) stub\n", this, item, flags, point);
2993 return E_NOTIMPL;
2994}
2995
2996// IShellFolderView implementation
2997
2999{
3000 FIXME("(%p)->(%ld) stub\n", this, sort);
3001 return E_NOTIMPL;
3002}
3003
3005{
3006 FIXME("(%p)->(%p) stub\n", this, sort);
3007 return E_NOTIMPL;
3008}
3009
3011{
3013 return S_OK;
3014}
3015
3017{
3018 m_ListView.ModifyStyle(0, LVS_AUTOARRANGE);
3020 return S_OK;
3021}
3022
3024{
3025 TRACE("(%p)->(%p %p)\n", this, pidl, item);
3026 if (!m_ListView)
3027 {
3028 ERR("!m_ListView\n");
3029 return E_FAIL;
3030 }
3031 *item = LV_AddItem(pidl);
3032 return (int)*item >= 0 ? S_OK : E_OUTOFMEMORY;
3033}
3034
3036{
3037 TRACE("(%p)->(%p %d)\n", this, pidl, item);
3038 return Item(item, pidl);
3039}
3040
3042{
3043 TRACE("(%p)->(%p %p)\n", this, pidl, item);
3044
3045 if (!m_ListView)
3046 {
3047 ERR("!m_ListView\n");
3048 return E_FAIL;
3049 }
3050
3051 if (pidl)
3052 {
3055 }
3056 else
3057 {
3058 *item = 0;
3060 }
3061
3062 return S_OK;
3063}
3064
3066{
3067 TRACE("(%p)->(%p)\n", this, count);
3069 return S_OK;
3070}
3071
3073{
3074 FIXME("(%p)->(%d %x) stub\n", this, count, flags);
3075 return E_NOTIMPL;
3076}
3077
3079{
3080 FIXME("(%p)->(%p %p %p) stub\n", this, pidl_old, pidl_new, item);
3081 return E_NOTIMPL;
3082}
3083
3085{
3086 FIXME("(%p)->(%p %p) stub\n", this, pidl, item);
3087 return E_NOTIMPL;
3088}
3089
3091{
3092 TRACE("(%p)->(%d)\n", this, redraw);
3093 if (m_ListView)
3095 return S_OK;
3096}
3097
3099{
3100 FIXME("(%p)->(%p) stub\n", this, count);
3101 return E_NOTIMPL;
3102}
3103
3105{
3106 TRACE("(%p)->(%p %p)\n", this, pidl, items);
3107
3108 *items = GetSelections();
3109
3110 if (*items)
3111 {
3112 *pidl = static_cast<PCUITEMID_CHILD *>(LocalAlloc(0, *items * sizeof(PCUITEMID_CHILD)));
3113 if (!*pidl)
3114 {
3115 return E_OUTOFMEMORY;
3116 }
3117
3118 /* it's documented that caller shouldn't PIDLs, only array itself */
3119 memcpy(*pidl, m_apidl, *items * sizeof(PCUITEMID_CHILD));
3120 }
3121
3122 return S_OK;
3123}
3124
3126{
3127 if ((m_iDragOverItem == -1 || m_pCurDropTarget == NULL) &&
3129 {
3130 return S_OK;
3131 }
3132
3133 return S_FALSE;
3134}
3135
3137{
3138 if (!pt)
3139 return E_INVALIDARG;
3140
3142 return S_OK;
3143}
3144
3146{
3147 FIXME("(%p)->(%p) stub\n", this, pt);
3148 return E_NOTIMPL;
3149}
3150
3152{
3153 TRACE("(%p)->(%p)\n", this, obj);
3154 return E_NOTIMPL;
3155}
3156
3158{
3159 FIXME("(%p)->(%p %p) stub\n", this, pidl, pt);
3160 return E_NOTIMPL;
3161}
3162
3164{
3165 FIXME("(%p)->(%p) stub\n", this, drop_target);
3166 return E_NOTIMPL;
3167}
3168
3170{
3171 FIXME("(%p)->(%d) stub\n", this, move);
3172 return E_NOTIMPL;
3173}
3174
3176{
3177 FIXME("(%p)->(%p) stub\n", this, obj);
3178 return E_NOTIMPL;
3179}
3180
3182{
3183 FIXME("(%p)->(%p) stub\n", this, spacing);
3184 return E_NOTIMPL;
3185}
3186
3187HRESULT STDMETHODCALLTYPE CDefView::SetCallback(IShellFolderViewCB *new_cb, IShellFolderViewCB **old_cb)
3188{
3189 if (old_cb)
3190 *old_cb = m_pShellFolderViewCB.Detach();
3191
3192 m_pShellFolderViewCB = new_cb;
3193 return S_OK;
3194}
3195
3197{
3198 FIXME("(%p)->(%d) stub\n", this, flags);
3199 return E_NOTIMPL;
3200}
3201
3203{
3204 TRACE("(%p)->(%p)\n", this, support);
3205 return S_OK;
3206}
3207
3209{
3210 FIXME("(%p)->(%p) stub\n", this, disp);
3211 return E_NOTIMPL;
3212}
3213
3214HRESULT WINAPI CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText)
3215{
3216 FIXME("(%p)->(%p(%s) 0x%08x %p %p\n",
3217 this, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
3218
3219 if (!prgCmds)
3220 return E_INVALIDARG;
3221
3222 for (UINT i = 0; i < cCmds; i++)
3223 {
3224 FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID);
3225 prgCmds[i].cmdf = 0;
3226 }
3227
3228 return OLECMDERR_E_UNKNOWNGROUP;
3229}
3230
3232// ISVOleCmdTarget_Exec(IOleCommandTarget)
3233//
3234// nCmdID is the OLECMDID_* enumeration
3235HRESULT WINAPI CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
3236{
3237 FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n",
3238 this, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut);
3239
3240 if (!pguidCmdGroup)
3241 return OLECMDERR_E_UNKNOWNGROUP;
3242
3243 if (IsEqualCLSID(*pguidCmdGroup, m_Category))
3244 {
3245 if (nCmdID == FCIDM_SHVIEW_AUTOARRANGE)
3246 {
3247 if (V_VT(pvaIn) != VT_INT_PTR)
3248 return OLECMDERR_E_NOTSUPPORTED;
3249
3251 params.cbSize = sizeof(params);
3252 params.rcExclude = *(RECT*) V_INTREF(pvaIn);
3253
3254 if (m_hMenuViewModes)
3255 {
3256 // Duplicate all but the last two items of the view modes menu
3257 HMENU hmenuViewPopup = CreatePopupMenu();
3258 Shell_MergeMenus(hmenuViewPopup, m_hMenuViewModes, 0, 0, 0xFFFF, 0);
3259 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION);
3260 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION);
3261 CheckViewMode(hmenuViewPopup);
3262 TrackPopupMenuEx(hmenuViewPopup, TPM_LEFTALIGN | TPM_TOPALIGN, params.rcExclude.left, params.rcExclude.bottom, m_hWndParent, &params);
3263 ::DestroyMenu(hmenuViewPopup);
3264 }
3265
3266 // pvaOut is VT_I4 with value 0x403 (cmd id of the new mode maybe?)
3267 V_VT(pvaOut) = VT_I4;
3268 V_I4(pvaOut) = 0x403;
3269 }
3270 }
3271
3272 if (IsEqualIID(*pguidCmdGroup, CGID_Explorer) &&
3273 (nCmdID == 0x29) &&
3274 (nCmdexecopt == 4) && pvaOut)
3275 return S_OK;
3276
3277 if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView) &&
3278 (nCmdID == 9) &&
3279 (nCmdexecopt == 0))
3280 return 1;
3281
3282 return OLECMDERR_E_UNKNOWNGROUP;
3283}
3284
3285/**********************************************************
3286 * ISVDropTarget implementation
3287 */
3288
3289/******************************************************************************
3290 * drag_notify_subitem [Internal]
3291 *
3292 * Figure out the shellfolder object, which is currently under the mouse cursor
3293 * and notify it via the IDropTarget interface.
3294 */
3295
3296#define SCROLLAREAWIDTH 20
3297
3299{
3300 LONG lResult;
3301 HRESULT hr;
3302 RECT clientRect;
3303
3304 /* The key state on drop doesn't have MK_LBUTTON or MK_RBUTTON because it
3305 reflects the key state after the user released the button, so we need
3306 to remember the last key state when the button was pressed */
3307 m_grfKeyState = grfKeyState;
3308
3309 // Map from global to client coordinates and query the index of the
3310 // listview-item, which is currently under the mouse cursor.
3311 LVHITTESTINFO htinfo = {{pt.x, pt.y}, LVHT_ONITEM};
3312 ScreenToClient(&htinfo.pt);
3313 lResult = m_ListView.HitTest(&htinfo);
3314
3315 /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */
3316 ::GetClientRect(m_ListView, &clientRect);
3317 if (htinfo.pt.x == m_ptLastMousePos.x && htinfo.pt.y == m_ptLastMousePos.y &&
3318 (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH ||
3319 htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH))
3320 {
3321 m_cScrollDelay = (m_cScrollDelay + 1) % 5; // DragOver is called every 50 ms
3322 if (m_cScrollDelay == 0)
3323 {
3324 /* Mouse did hover another 250 ms over the scroll-area */
3325 if (htinfo.pt.x < SCROLLAREAWIDTH)
3326 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEUP, 0);
3327
3328 if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH)
3329 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEDOWN, 0);
3330
3331 if (htinfo.pt.y < SCROLLAREAWIDTH)
3332 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEUP, 0);
3333
3334 if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH)
3335 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEDOWN, 0);
3336 }
3337 }
3338 else
3339 {
3340 m_cScrollDelay = 0; // Reset, if cursor is not over the listview's scroll-area
3341 }
3342
3343 m_ptLastMousePos = htinfo.pt;
3345
3346 /* We need to check if we drag the selection over itself */
3347 if (lResult != -1 && m_pSourceDataObject.p != NULL)
3348 {
3349 PCUITEMID_CHILD pidl = _PidlByItem(lResult);
3350
3351 for (UINT i = 0; i < m_cidl; i++)
3352 {
3353 if (pidl == m_apidl[i])
3354 {
3355 /* The item that is being draged is hovering itself. */
3356 lResult = -1;
3357 break;
3358 }
3359 }
3360 }
3361
3362 // If we are still over the previous sub-item, notify it via DragOver and return
3363 if (m_pCurDropTarget && lResult == m_iDragOverItem)
3364 return m_pCurDropTarget->DragOver(grfKeyState, pt, pdwEffect);
3365
3366 // We've left the previous sub-item, notify it via DragLeave and release it
3367 if (m_pCurDropTarget)
3368 {
3370 if (pidl)
3371 SelectItem(pidl, 0);
3372
3373 m_pCurDropTarget->DragLeave();
3375 }
3376
3377 m_iDragOverItem = lResult;
3378
3379 if (lResult == -1)
3380 {
3381 // We are not above one of the listview's subitems. Bind to the
3382 // parent folder's DropTarget interface.
3384 }
3385 else
3386 {
3387 // Query the relative PIDL of the shellfolder object represented
3388 // by the currently dragged over listview-item ...
3389 PCUITEMID_CHILD pidl = _PidlByItem(lResult);
3390
3391 // ... and bind m_pCurDropTarget to the IDropTarget interface of an UIObject of this object
3392 hr = m_pSFParent->GetUIObjectOf(m_ListView, 1, &pidl, IID_NULL_PPV_ARG(IDropTarget, &m_pCurDropTarget));
3393 }
3394
3396
3397 // If anything failed, m_pCurDropTarget should be NULL now, which ought to be a save state
3398 if (FAILED(hr))
3399 {
3400 *pdwEffect = DROPEFFECT_NONE;
3401 return hr;
3402 }
3403
3404 if (m_iDragOverItem != -1)
3405 {
3406 SelectItem(m_iDragOverItem, SVSI_SELECT);
3407 }
3408
3409 // Notify the item just entered via DragEnter
3410 return m_pCurDropTarget->DragEnter(m_pCurDataObject, grfKeyState, pt, pdwEffect);
3411}
3412
3413HRESULT WINAPI CDefView::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3414{
3415 if (*pdwEffect == DROPEFFECT_NONE)
3416 return S_OK;
3417
3418 /* Get a hold on the data object for later calls to DragEnter on the sub-folders */
3419 m_pCurDataObject = pDataObject;
3420
3421 HRESULT hr = drag_notify_subitem(grfKeyState, pt, pdwEffect);
3422 if (SUCCEEDED(hr))
3423 {
3424 POINT ptClient = {pt.x, pt.y};
3425 ScreenToClient(&ptClient);
3426 ImageList_DragEnter(m_hWnd, ptClient.x, ptClient.y);
3427 }
3428
3429 return hr;
3430}
3431
3433{
3434 POINT ptClient = {pt.x, pt.y};
3435 ScreenToClient(&ptClient);
3436 ImageList_DragMove(ptClient.x, ptClient.y);
3437 return drag_notify_subitem(grfKeyState, pt, pdwEffect);
3438}
3439
3441{
3443
3444 if (m_pCurDropTarget)
3445 {
3446 m_pCurDropTarget->DragLeave();
3448 }
3449
3450 if (m_pCurDataObject != NULL)
3451 {
3453 }
3454
3455 m_iDragOverItem = 0;
3456
3457 return S_OK;
3458}
3459
3461{
3462 RECT rcBound;
3463 INT i, nCount = m_ListView.GetItemCount();
3464 DWORD dwSpacing;
3465 INT dx, dy;
3466 BOOL bSmall = ((m_ListView.GetStyle() & LVS_TYPEMASK) != LVS_ICON);
3467
3468 // FIXME: LVM_GETORIGIN is broken. See CORE-17266
3469 pt.x += m_ListView.GetScrollPos(SB_HORZ);
3470 pt.y += m_ListView.GetScrollPos(SB_VERT);
3471
3472 if (m_ListView.GetStyle() & LVS_ALIGNLEFT)
3473 {
3474 // vertically
3475 for (i = 0; i < nCount; ++i)
3476 {
3477 dwSpacing = ListView_GetItemSpacing(m_ListView, bSmall);
3478 dx = LOWORD(dwSpacing);
3479 dy = HIWORD(dwSpacing);
3481 rcBound.right = rcBound.left + dx;
3482 rcBound.bottom = rcBound.top + dy;
3483 if (pt.x < rcBound.right && pt.y < (rcBound.top + rcBound.bottom) / 2)
3484 {
3485 return i;
3486 }
3487 }
3488 for (i = nCount - 1; i >= 0; --i)
3489 {
3491 if (rcBound.left < pt.x && rcBound.top < pt.y)
3492 {
3493 return i + 1;
3494 }
3495 }
3496 }
3497 else
3498 {
3499 // horizontally
3500 for (i = 0; i < nCount; ++i)
3501 {
3502 dwSpacing = ListView_GetItemSpacing(m_ListView, bSmall);
3503 dx = LOWORD(dwSpacing);
3504 dy = HIWORD(dwSpacing);
3506 rcBound.right = rcBound.left + dx;
3507 rcBound.bottom = rcBound.top + dy;
3508 if (pt.y < rcBound.bottom && pt.x < rcBound.left)
3509 {
3510 return i;
3511 }
3512 if (pt.y < rcBound.bottom && pt.x < rcBound.right)
3513 {
3514 return i + 1;
3515 }
3516 }
3517 for (i = nCount - 1; i >= 0; --i)
3518 {
3520 if (rcBound.left < pt.x && rcBound.top < pt.y)
3521 {
3522 return i + 1;
3523 }
3524 }
3525 }
3526
3527 return nCount;
3528}
3529
3531{
3532 LRESULT lResult;
3533
3535 {
3536 int nPartArray[] = {-1};
3537 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, _countof(nPartArray), (LPARAM)nPartArray, &lResult);
3538 return;
3539 }
3540
3541 int nFileSizePartLength = 125;
3542 const int nLocationPartLength = 150;
3543 const int nRightPartsLength = nFileSizePartLength + nLocationPartLength;
3544 int nObjectsPartLength = nWidth - nRightPartsLength;
3545
3546 // If the window is small enough just divide each part into thirds
3547 // to match the behavior of Windows Server 2003
3548 if (nObjectsPartLength <= nLocationPartLength)
3549 nObjectsPartLength = nFileSizePartLength = nWidth / 3;
3550
3551 int nPartArray[] = {nObjectsPartLength, nObjectsPartLength + nFileSizePartLength, -1};
3552
3553 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, _countof(nPartArray), (LPARAM)nPartArray, &lResult);
3554}
3555
3557{
3558 // Get the handle for the status bar
3559 HWND fStatusBar;
3560 m_pShellBrowser->GetControlWindow(FCW_STATUS, &fStatusBar);
3561
3562 // Get the size of our status bar
3563 RECT statusBarSize;
3564 ::GetWindowRect(fStatusBar, &statusBarSize);
3565
3566 // Resize the status bar
3567 _HandleStatusBarResize(statusBarSize.right - statusBarSize.left);
3568}
3569
3571
3572static INT CALLBACK
3573SelectionMoveCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
3574{
3575 CLParamIndexMap *pmap = (CLParamIndexMap *)lParamSort;
3576 INT i1 = pmap->Lookup(lParam1), i2 = pmap->Lookup(lParam2);
3577 if (i1 < i2)
3578 return -1;
3579 if (i1 > i2)
3580 return 1;
3581 return 0;
3582}
3583
3585{
3586 // get insertable index from position
3588
3589 // create identity mapping of indexes
3591 INT nCount = m_ListView.GetItemCount();
3592 for (INT i = 0; i < nCount; ++i)
3593 {
3594 array.Add(i);
3595 }
3596
3597 // re-ordering mapping
3598 INT iItem = -1;
3599 while ((iItem = m_ListView.GetNextItem(iItem, LVNI_SELECTED)) >= 0)
3600 {
3601 INT iFrom = iItem, iTo = iPosition;
3602 if (iFrom < iTo)
3603 --iTo;
3604 if (iFrom >= nCount)
3605 iFrom = nCount - 1;
3606 if (iTo >= nCount)
3607 iTo = nCount - 1;
3608
3609 // shift indexes by swapping (like a bucket relay)
3610 if (iFrom < iTo)
3611 {
3612 for (INT i = iFrom; i < iTo; ++i)
3613 {
3614 // swap array[i] and array[i + 1]
3615 INT tmp = array[i];
3616 array[i] = array[i + 1];
3617 array[i + 1] = tmp;
3618 }
3619 }
3620 else
3621 {
3622 for (INT i = iFrom; i > iTo; --i)
3623 {
3624 // swap array[i] and array[i - 1]
3625 INT tmp = array[i];
3626 array[i] = array[i - 1];
3627 array[i - 1] = tmp;
3628 }
3629 }
3630 }
3631
3632 // create mapping (ListView's lParam to index) from array
3634 for (INT i = 0; i < nCount; ++i)
3635 {
3637 map.Add(lParam, i);
3638 }
3639
3640 // finally sort
3642}
3643
3644HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3645{
3648
3649 if ((IsDropOnSource(NULL) == S_OK) &&
3650 (*pdwEffect & DROPEFFECT_MOVE) &&
3652 {
3653 if (m_pCurDropTarget)
3654 {
3655 m_pCurDropTarget->DragLeave();
3657 }
3658
3659 POINT ptDrop = { pt.x, pt.y };
3660 ::ScreenToClient(m_ListView, &ptDrop);
3662 m_ptLastMousePos = ptDrop;
3663
3665 if (m_ListView.GetStyle() & LVS_AUTOARRANGE)
3666 {
3668 }
3669 else
3670 {
3671 POINT ptItem;
3672 INT iItem = -1;
3673 while ((iItem = m_ListView.GetNextItem(iItem, LVNI_SELECTED)) >= 0)
3674 {
3675 if (m_ListView.GetItemPosition(iItem, &ptItem))
3676 {
3679 m_ListView.SetItemPosition(iItem, &ptItem);
3680 }
3681 }
3682 }
3684 }
3685 else if (m_pCurDropTarget)
3686 {
3687 m_pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect);
3689 }
3690
3692 m_iDragOverItem = 0;
3693 return S_OK;
3694}
3695
3697{
3698 TRACE("(%p)\n", this);
3699
3700 if (fEscapePressed)
3701 return DRAGDROP_S_CANCEL;
3702 else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON))
3703 return DRAGDROP_S_DROP;
3704 else
3705 return S_OK;
3706}
3707
3709{
3710 TRACE("(%p)\n", this);
3711
3713}
3714
3715HRESULT 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)
3716{
3717 FIXME("Stub: this=%p\n", this);
3718 return E_NOTIMPL;
3719}
3720
3721HRESULT WINAPI CDefView::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet)
3722{
3723 FIXME("Stub: this=%p\n", this);
3724 return E_NOTIMPL;
3725}
3726
3727HRESULT WINAPI CDefView::Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze)
3728{
3729 FIXME("Stub: this=%p\n", this);
3730 return E_NOTIMPL;
3731}
3732
3734{
3735 FIXME("Stub: this=%p\n", this);
3736 return E_NOTIMPL;
3737}
3738
3740{
3741 FIXME("partial stub: %p 0x%08x 0x%08x %p\n", this, aspects, advf, pAdvSink);
3742
3743 // FIXME: we set the AdviseSink, but never use it to send any advice
3744 m_pAdvSink = pAdvSink;
3745 m_dwAspects = aspects;
3746 m_dwAdvf = advf;
3747
3748 return S_OK;
3749}
3750
3752{
3753 TRACE("this=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n", this, pAspects, pAdvf, ppAdvSink);
3754
3755 if (ppAdvSink)
3756 {
3757 *ppAdvSink = m_pAdvSink;
3758 m_pAdvSink.p->AddRef();
3759 }
3760
3761 if (pAspects)
3762 *pAspects = m_dwAspects;
3763
3764 if (pAdvf)
3765 *pAdvf = m_dwAdvf;
3766
3767 return S_OK;
3768}
3769
3771{
3772 if (IsEqualIID(guidService, SID_IShellBrowser))
3773 return m_pShellBrowser->QueryInterface(riid, ppvObject);
3774 else if(IsEqualIID(guidService, SID_IFolderView))
3775 return QueryInterface(riid, ppvObject);
3776
3777 return E_NOINTERFACE;
3778}
3779
3781{
3783 HRESULT hr = S_OK;
3784
3785 hr = IUnknown_QueryService(m_pShellBrowser, IID_IExplorerToolbar, IID_PPV_ARG(IExplorerToolbar, &ptb));
3786 if (FAILED(hr))
3787 return hr;
3788
3789 m_Category = CGID_DefViewFrame;
3790
3791 hr = ptb->SetCommandTarget(static_cast<IOleCommandTarget*>(this), &m_Category, 0);
3792 if (FAILED(hr))
3793 return hr;
3794
3795 if (hr == S_FALSE)
3796 return S_OK;
3797
3798#if 0
3799 hr = ptb->AddButtons(&m_Category, buttonsCount, buttons);
3800 if (FAILED(hr))
3801 return hr;
3802#endif
3803
3804 return S_OK;
3805}
3806
3808{
3810
3812 {
3813 hr = m_pShellFolderViewCB->MessageSFVCB(uMsg, wParam, lParam);
3814 }
3815
3816 return hr;
3817}
3818
3820{
3821 return ShellObjectCreatorInit<CDefView>(pFolder, riid, ppvOut);
3822}
3823
3825 LPCSFV psvcbi, // [in] shelltemplate struct
3826 IShellView **ppsv) // [out] IShellView pointer
3827{
3829 HRESULT hRes;
3830
3831 TRACE("sf=%p pidl=%p cb=%p mode=0x%08x parm=%p\n",
3832 psvcbi->pshf, psvcbi->pidl, psvcbi->pfnCallback,
3833 psvcbi->fvm, psvcbi->psvOuter);
3834
3835 *ppsv = NULL;
3836 hRes = CDefView_CreateInstance(psvcbi->pshf, IID_PPV_ARG(IShellView, &psv));
3837 if (FAILED_UNEXPECTEDLY(hRes))
3838 return hRes;
3839
3840 *ppsv = psv.Detach();
3841 return hRes;
3842}
3843
3845 IShellView **ppsv)
3846{
3848 HRESULT hRes;
3849
3850 if (!ppsv)
3851 return E_INVALIDARG;
3852
3853 *ppsv = NULL;
3854
3855 if (!pcsfv || pcsfv->cbSize != sizeof(*pcsfv))
3856 return E_INVALIDARG;
3857
3858 TRACE("sf=%p outer=%p callback=%p\n",
3859 pcsfv->pshf, pcsfv->psvOuter, pcsfv->psfvcb);
3860
3861 hRes = CDefView_CreateInstance(pcsfv->pshf, IID_PPV_ARG(IShellView, &psv));
3862 if (FAILED(hRes))
3863 return hRes;
3864
3865 if (pcsfv->psfvcb)
3866 {
3868 if (SUCCEEDED(psv->QueryInterface(IID_PPV_ARG(IShellFolderView, &sfv))))
3869 {
3870 sfv->SetCallback(pcsfv->psfvcb, NULL);
3871 }
3872 }
3873
3874 *ppsv = psv.Detach();
3875 return hRes;
3876}
static HDC hDC
Definition: 3dtext.c:33
BOOL _ILIsDesktop(LPCITEMIDLIST pidl)
Definition: CBandSite.h:24
HRESULT CDefViewBckgrndMenu_CreateInstance(IShellFolder *psf, REFIID riid, void **ppv)
HRESULT WINAPI CDefViewDual_Constructor(REFIID riid, LPVOID *ppvOut)
#define GET_WM_COMMAND_HWND(wp, lp)
Definition: CDefView.cpp:405
HMENU GetSubmenuByID(HMENU hmenu, UINT id)
Definition: CDefView.cpp:1315
CSimpleMap< LPARAM, INT > CLParamIndexMap
Definition: CDefView.cpp:3570
#define SCROLLAREAWIDTH
Definition: CDefView.cpp:3296
struct LISTVIEW_SORT_INFO * LPLISTVIEW_SORT_INFO
static BOOL ILIsParentOrSpecialParent(PCIDLIST_ABSOLUTE pidl1, PCIDLIST_ABSOLUTE pidl2)
Definition: CDefView.cpp:2210
void(CALLBACK * PFNSHGETSETTINGSPROC)(LPSHELLFLA