ReactOS 0.4.15-dev-5672-gf73ac17
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
97
98class CDefView :
99 public CWindowImpl<CDefView, CWindow, CControlWinTraits>,
100 public CComObjectRootEx<CComMultiThreadModelNoCS>,
101 public IShellView2,
102 public IFolderView,
103 public IShellFolderView,
104 public IOleCommandTarget,
105 public IDropTarget,
106 public IDropSource,
107 public IViewObject,
108 public IServiceProvider
109{
110 private:
120 HMENU m_hMenu; /* Handle to the menu bar of the browser */
121 HMENU m_hMenuArrangeModes; /* Handle to the popup menu with the arrange modes */
122 HMENU m_hMenuViewModes; /* Handle to the popup menu with the view modes */
123 HMENU m_hContextMenu; /* Handle to the open context menu */
130 ULONG m_hNotify; /* Change notification handle */
131 HACCEL m_hAccel;
135 // for drag and drop
137 CComPtr<IDropTarget> m_pCurDropTarget; /* The sub-item, which is currently dragged over */
138 CComPtr<IDataObject> m_pCurDataObject; /* The dragged data-object */
139 LONG m_iDragOverItem; /* Dragged over item's index, iff m_pCurDropTarget != NULL */
140 UINT m_cScrollDelay; /* Send a WM_*SCROLL msg every 250 ms during drag-scroll */
141 POINT m_ptLastMousePos; /* Mouse position at last DragOver call */
142 POINT m_ptFirstMousePos; /* Mouse position when the drag operation started */
144 //
147
150
154
156
157 private:
159 BOOL _Sort();
166
167 public:
168 CDefView();
169 ~CDefView();
174 void UpdateStatusbar();
175 void CheckToolbar();
177 void UpdateListColors();
178 BOOL InitList();
179 static INT CALLBACK ListViewCompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lpData);
180
184 int LV_AddItem(PCUITEMID_CHILD pidl);
193 HRESULT FillArrangeAsMenu(HMENU hmenuArrange);
194 HRESULT CheckViewMode(HMENU hmenuView);
197 void OnDeactivate();
198 void DoActivate(UINT uState);
199 HRESULT drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
201 LRESULT OnExplorerCommand(UINT uCommand, BOOL bUseSelection);
202
203 // *** IOleWindow methods ***
204 virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *lphwnd);
206
207 // *** IShellView methods ***
212 virtual HRESULT STDMETHODCALLTYPE CreateViewWindow(IShellView *psvPrevious, LPCFOLDERSETTINGS pfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd);
218 virtual HRESULT STDMETHODCALLTYPE GetItemObject(UINT uItem, REFIID riid, void **ppv);
219
220 // *** IShellView2 methods ***
225
226 // *** IShellView3 methods ***
227 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);
228
229 // *** IFolderView methods ***
233 virtual HRESULT STDMETHODCALLTYPE Item(int iItemIndex, PITEMID_CHILD *ppidl);
237 virtual HRESULT STDMETHODCALLTYPE GetFocusedItem(int *piItem);
244
245 // *** IShellFolderView methods ***
269 virtual HRESULT STDMETHODCALLTYPE SetCallback(IShellFolderViewCB *new_cb, IShellFolderViewCB **old_cb);
271 virtual HRESULT STDMETHODCALLTYPE QuerySupport(UINT *support);
273
274 // *** IOleCommandTarget methods ***
275 virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[ ], OLECMDTEXT *pCmdText);
276 virtual HRESULT STDMETHODCALLTYPE Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut);
277
278 // *** IDropTarget methods ***
279 virtual HRESULT STDMETHODCALLTYPE DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
280 virtual HRESULT STDMETHODCALLTYPE DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
282 virtual HRESULT STDMETHODCALLTYPE Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
283
284 // *** IDropSource methods ***
285 virtual HRESULT STDMETHODCALLTYPE QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState);
287
288 // *** IViewObject methods ***
289 virtual HRESULT STDMETHODCALLTYPE Draw(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd,
290 HDC hdcTargetDev, HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL lprcWBounds,
291 BOOL ( STDMETHODCALLTYPE *pfnContinue )(ULONG_PTR dwContinue), ULONG_PTR dwContinue);
292 virtual HRESULT STDMETHODCALLTYPE GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect,
293 DVTARGETDEVICE *ptd, HDC hicTargetDev, LOGPALETTE **ppColorSet);
294 virtual HRESULT STDMETHODCALLTYPE Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze);
295 virtual HRESULT STDMETHODCALLTYPE Unfreeze(DWORD dwFreeze);
296 virtual HRESULT STDMETHODCALLTYPE SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink);
297 virtual HRESULT STDMETHODCALLTYPE GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink);
298
299 // *** IServiceProvider methods ***
300 virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject);
301
302 // Message handlers
305 LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
311 LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
313 LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
317 LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
318 LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
323
324 virtual VOID OnFinalMessage(HWND) override;
325
327 {
328 static ATL::CWndClassInfo wc =
329 {
331 0, 0, NULL, NULL,
332 LoadCursor(NULL, IDC_ARROW), NULL, NULL, L"SHELLDLL_DefView", NULL
333 },
334 NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
335 };
336 return wc;
337 }
338
340 {
341 return WindowProc;
342 }
343
345 {
346 CDefView *pThis;
348
349 // Must hold a reference during message handling
350 pThis = reinterpret_cast<CDefView *>(hWnd);
351 pThis->AddRef();
353 pThis->Release();
354 return result;
355 }
356
380
382 // Windows returns E_NOINTERFACE for IOleWindow
383 // COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow)
384 COM_INTERFACE_ENTRY_IID(IID_IShellView, IShellView)
386 COM_INTERFACE_ENTRY_IID(IID_IShellView2, IShellView2)
387 COM_INTERFACE_ENTRY_IID(IID_IFolderView, IFolderView)
388 COM_INTERFACE_ENTRY_IID(IID_IShellFolderView, IShellFolderView)
389 COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget)
390 COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget)
391 COM_INTERFACE_ENTRY_IID(IID_IDropSource, IDropSource)
393 COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider)
395};
396
397/*menu items */
398#define IDM_VIEW_FILES (FCIDM_SHVIEWFIRST + 0x500)
399#define IDM_VIEW_IDW (FCIDM_SHVIEWFIRST + 0x501)
400#define IDM_MYFILEITEM (FCIDM_SHVIEWFIRST + 0x502)
401
402#define ID_LISTVIEW 1
403
404/*windowsx.h */
405#define GET_WM_COMMAND_ID(wp, lp) LOWORD(wp)
406#define GET_WM_COMMAND_HWND(wp, lp) (HWND)(lp)
407#define GET_WM_COMMAND_CMD(wp, lp) HIWORD(wp)
408
410
412 m_ListView(),
414 m_hMenu(NULL),
419 m_uState(0),
420 m_cidl(0),
421 m_apidl(NULL),
423 m_hNotify(0),
424 m_hAccel(NULL),
425 m_dwAspects(0),
426 m_dwAdvf(0),
432{
440
442}
443
445{
446 TRACE(" destroying IShellView(%p)\n", this);
447
449
451 {
454 }
455
456 if (m_hWnd)
457 {
459 }
460
462}
463
465{
466 m_pSFParent = shellFolder;
468
469 return S_OK;
470}
471
472/**********************************************************
473 *
474 * ##### helperfunctions for communication with ICommDlgBrowser #####
475 */
477{
478 HRESULT ret = S_OK;
479
480 if (m_pCommDlgBrowser.p != NULL)
481 {
482 TRACE("ICommDlgBrowser::IncludeObject pidl=%p\n", pidl);
483 ret = m_pCommDlgBrowser->IncludeObject(this, pidl);
484 TRACE("-- returns 0x%08x\n", ret);
485 }
486
487 return ret;
488}
489
491{
493
494 if (m_pCommDlgBrowser.p != NULL)
495 {
496 TRACE("ICommDlgBrowser::OnDefaultCommand\n");
497 ret = m_pCommDlgBrowser->OnDefaultCommand(this);
498 TRACE("-- returns 0x%08x\n", ret);
499 }
500
501 return ret;
502}
503
505{
507
508 if (m_pCommDlgBrowser.p != NULL)
509 {
510 TRACE("ICommDlgBrowser::OnStateChange flags=%x\n", uFlags);
511 ret = m_pCommDlgBrowser->OnStateChange(this, uFlags);
512 TRACE("--\n");
513 }
514
515 return ret;
516}
517/**********************************************************
518 * set the toolbar of the filedialog buttons
519 *
520 * - activates the buttons from the shellbrowser according to
521 * the view state
522 */
524{
526
527 TRACE("\n");
528
529 if (m_pCommDlgBrowser != NULL)
530 {
531 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_CHECKBUTTON,
533 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_CHECKBUTTON,
535 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON,
537 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON,
539 }
540}
541
543{
544 WCHAR szFormat[MAX_PATH] = {0};
545 WCHAR szPartText[MAX_PATH] = {0};
546 UINT cSelectedItems;
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 folder 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 *
617 * ##### helperfunctions for initializing the view #####
618 */
619
620/**********************************************************
621* ShellView_CreateList()
622*
623* - creates the list view window
624*/
626{
627 HRESULT hr;
628 DWORD dwStyle, dwExStyle;
629 UINT ViewMode;
630
631 TRACE("%p\n", this);
632
635 dwExStyle = WS_EX_CLIENTEDGE;
636
638 dwStyle |= LVS_ALIGNLEFT;
639 else
640 dwStyle |= LVS_ALIGNTOP | LVS_SHOWSELALWAYS;
641
642 ViewMode = m_FolderSettings.ViewMode;
643 hr = _DoFolderViewCB(SFVM_DEFVIEWMODE, 0, (LPARAM)&ViewMode);
644 if (SUCCEEDED(hr))
645 {
646 if (ViewMode >= FVM_FIRST && ViewMode <= FVM_LAST)
647 m_FolderSettings.ViewMode = ViewMode;
648 else
649 ERR("Ignoring invalid ViewMode from SFVM_DEFVIEWMODE: %u (was: %u)\n", ViewMode, m_FolderSettings.ViewMode);
650 }
651
653 {
654 case FVM_ICON:
655 dwStyle |= LVS_ICON;
656 break;
657
658 case FVM_DETAILS:
659 dwStyle |= LVS_REPORT;
660 break;
661
662 case FVM_SMALLICON:
663 dwStyle |= LVS_SMALLICON;
664 break;
665
666 case FVM_LIST:
667 dwStyle |= LVS_LIST;
668 break;
669
670 default:
671 dwStyle |= LVS_LIST;
672 break;
673 }
674
676 dwStyle |= LVS_AUTOARRANGE;
677
679 dwExStyle |= LVS_EX_SNAPTOGRID;
680
683
685 dwStyle |= LVS_SINGLESEL;
686
688 dwExStyle &= ~WS_EX_CLIENTEDGE;
689
690 RECT rcListView = {0,0,0,0};
691 m_ListView.Create(m_hWnd, rcListView, L"FolderView", dwStyle, dwExStyle, ID_LISTVIEW);
692
693 if (!m_ListView)
694 return FALSE;
695
699
700 /* UpdateShellSettings(); */
701 return TRUE;
702}
703
705{
707 {
708 /* Check if drop shadows option is enabled */
709 BOOL bDropShadow = FALSE;
710 DWORD cbDropShadow = sizeof(bDropShadow);
711
712 /*
713 * The desktop ListView always take the default desktop colours, by
714 * remaining transparent and letting user32/win32k paint itself the
715 * desktop background color, if any.
716 */
718
719 SHGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
720 L"ListviewShadow", NULL, &bDropShadow, &cbDropShadow);
721 if (bDropShadow)
722 {
723 /* Set the icon background transparent */
725 m_ListView.SetTextColor(RGB(255, 255, 255));
726 m_ListView.SetExtendedListViewStyle(LVS_EX_TRANSPARENTSHADOWTEXT, LVS_EX_TRANSPARENTSHADOWTEXT);
727 }
728 else
729 {
730 /* Set the icon background as the same colour as the desktop */
732 m_ListView.SetTextBkColor(crDesktop);
733 if (GetRValue(crDesktop) + GetGValue(crDesktop) + GetBValue(crDesktop) > 128 * 3)
734 m_ListView.SetTextColor(RGB(0, 0, 0));
735 else
736 m_ListView.SetTextColor(RGB(255, 255, 255));
737 m_ListView.SetExtendedListViewStyle(0, LVS_EX_TRANSPARENTSHADOWTEXT);
738 }
739 }
740 else
741 {
742 // text background color
744 m_ListView.SetTextBkColor(clrTextBack);
745
746 // text color
747 COLORREF clrText;
749 clrText = m_viewinfo_data.clrText;
750 else
751 clrText = GetSysColor(COLOR_WINDOWTEXT);
752
753 m_ListView.SetTextColor(clrText);
754
755 // Background is painted by the parent via WM_PRINTCLIENT.
756 m_ListView.SetExtendedListViewStyle(LVS_EX_TRANSPARENTBKGND, LVS_EX_TRANSPARENTBKGND);
757 }
758}
759
760/**********************************************************
761* ShellView_InitList()
762*
763* - adds all needed columns to the shellview
764*/
766{
768 WCHAR szTemp[50];
769 HIMAGELIST big_icons, small_icons;
770
771 TRACE("%p\n", this);
772
774
776
777 if (m_pSF2Parent)
778 {
779 for (int i = 0; 1; i++)
780 {
781 if (FAILED(m_pSF2Parent->GetDetailsOf(NULL, i, &sd)))
782 break;
783 StrRetToStrNW( szTemp, 50, &sd.str, NULL);
784 m_ListView.InsertColumn(i, szTemp, sd.fmt, sd.cxChar * 8);
785
786 InsertMenuW(m_hMenuArrangeModes, -1, MF_STRING, 0x30 + i, szTemp);
787 }
788
790 }
791 else
792 {
793 FIXME("no m_pSF2Parent\n");
794 }
795
796 Shell_GetImageLists(&big_icons, &small_icons);
798 m_ListView.SetImageList(small_icons, LVSIL_SMALL);
799
800 return TRUE;
801}
802
803/*************************************************************************
804 * ShellView_ListViewCompareItems
805 *
806 * Compare Function for the Listview (FileOpen Dialog)
807 *
808 * PARAMS
809 * lParam1 [I] the first ItemIdList to compare with
810 * lParam2 [I] the second ItemIdList to compare with
811 * lpData [I] The column ID for the header Ctrl to process
812 *
813 * RETURNS
814 * A negative value if the first item should precede the second,
815 * a positive value if the first item should follow the second,
816 * or zero if the two items are equivalent
817 */
819{
820 PCUIDLIST_RELATIVE pidl1 = reinterpret_cast<PCUIDLIST_RELATIVE>(lParam1);
821 PCUIDLIST_RELATIVE pidl2 = reinterpret_cast<PCUIDLIST_RELATIVE>(lParam2);
822 CDefView *pThis = reinterpret_cast<CDefView*>(lpData);
823
824 HRESULT hres = pThis->m_pSFParent->CompareIDs(pThis->m_sortInfo.nHeaderID, pidl1, pidl2);
826 return 0;
827
828 SHORT nDiff = HRESULT_CODE(hres);
829 if (!pThis->m_sortInfo.bIsAscending)
830 nDiff = -nDiff;
831 return nDiff;
832}
833
835{
836 HWND hHeader;
837 HDITEM hColumn;
838
839 if (m_ListView.GetWindowLongPtr(GWL_STYLE) & LVS_NOSORTHEADER)
840 return TRUE;
841
842 hHeader = (HWND)m_ListView.SendMessage(LVM_GETHEADER, 0, 0);
843 ZeroMemory(&hColumn, sizeof(hColumn));
844
845 /* If the sorting column changed, remove the sorting style from the old column */
846 if ( (m_sortInfo.nLastHeaderID != -1) &&
848 {
849 hColumn.mask = HDI_FORMAT;
850 Header_GetItem(hHeader, m_sortInfo.nLastHeaderID, &hColumn);
851 hColumn.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN);
852 Header_SetItem(hHeader, m_sortInfo.nLastHeaderID, &hColumn);
853 }
854
855 /* Set the sorting style to the new column */
856 hColumn.mask = HDI_FORMAT;
857 Header_GetItem(hHeader, m_sortInfo.nHeaderID, &hColumn);
858
859 hColumn.fmt &= (m_sortInfo.bIsAscending ? ~HDF_SORTDOWN : ~HDF_SORTUP );
860 hColumn.fmt |= (m_sortInfo.bIsAscending ? HDF_SORTUP : HDF_SORTDOWN);
861 Header_SetItem(hHeader, m_sortInfo.nHeaderID, &hColumn);
862
863 /* Sort the list, using the current values of nHeaderID and bIsAscending */
866}
867
869{
870 if (!m_ListView)
871 return nullptr;
872 return reinterpret_cast<PCUITEMID_CHILD>(m_ListView.GetItemData(i));
873}
874
876{
877 if (!m_ListView)
878 return nullptr;
879 return reinterpret_cast<PCUITEMID_CHILD>(lvItem.lParam);
880}
881
882/**********************************************************
883* LV_FindItemByPidl()
884*/
886{
887 int cItems = m_ListView.GetItemCount();
888
889 for (int i = 0; i<cItems; i++)
890 {
891 PCUITEMID_CHILD currentpidl = _PidlByItem(i);
892 if (ILIsEqual(pidl, currentpidl))
893 return i;
894 }
895 return -1;
896}
897
898/**********************************************************
899* LV_AddItem()
900*/
902{
903 LVITEMW lvItem;
904
905 TRACE("(%p)(pidl=%p)\n", this, pidl);
906
908 return -1;
909
910 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM; /*set the mask*/
911 lvItem.iItem = m_ListView.GetItemCount(); /*add the item to the end of the list*/
912 lvItem.iSubItem = 0;
913 lvItem.lParam = reinterpret_cast<LPARAM>(ILClone(pidl)); /*set the item's data*/
914 lvItem.pszText = LPSTR_TEXTCALLBACKW; /*get text on a callback basis*/
915 lvItem.iImage = I_IMAGECALLBACK; /*get the image on a callback basis*/
916 lvItem.stateMask = LVIS_CUT;
917
918 return m_ListView.InsertItem(&lvItem);
919}
920
921/**********************************************************
922* LV_DeleteItem()
923*/
925{
926 int nIndex;
927
928 TRACE("(%p)(pidl=%p)\n", this, pidl);
929
930 nIndex = LV_FindItemByPidl(pidl);
931
932 return m_ListView.DeleteItem(nIndex);
933}
934
935/**********************************************************
936* LV_RenameItem()
937*/
939{
940 int nItem;
941 LVITEMW lvItem;
942
943 TRACE("(%p)(pidlold=%p pidlnew=%p)\n", this, pidlOld, pidlNew);
944
945 nItem = LV_FindItemByPidl(pidlOld);
946
947 if ( -1 != nItem )
948 {
949 lvItem.mask = LVIF_PARAM; /* only the pidl */
950 lvItem.iItem = nItem;
951 lvItem.iSubItem = 0;
952 m_ListView.GetItem(&lvItem);
953
954 LPVOID oldPidl = reinterpret_cast<LPVOID>(lvItem.lParam); /* Store the old pidl until the new item is replaced */
955
956 lvItem.mask = LVIF_PARAM | LVIF_IMAGE | LVIF_TEXT;
957 lvItem.iItem = nItem;
958 lvItem.iSubItem = 0;
959 lvItem.lParam = reinterpret_cast<LPARAM>(ILClone(pidlNew)); /* set the item's data */
962 m_ListView.SetItem(&lvItem);
963 m_ListView.Update(nItem);
964
965 SHFree(oldPidl); /* Now that the new item is in place, we can safely release the old pidl */
966
967 return TRUE; /* FIXME: better handling */
968 }
969
970 return FALSE;
971}
972
973/**********************************************************
974* LV_ProdItem()
975*/
977{
978 int nItem;
979 LVITEMW lvItem;
980
981 TRACE("(%p)(pidl=%p)\n", this, pidl);
982
983 nItem = LV_FindItemByPidl(pidl);
984
985 if (-1 != nItem)
986 {
987 lvItem.mask = LVIF_IMAGE;
988 lvItem.iItem = nItem;
989 lvItem.iSubItem = 0;
991 m_ListView.SetItem(&lvItem);
992 m_ListView.Update(nItem);
993 return TRUE;
994 }
995
996 return FALSE;
997}
998
999/**********************************************************
1000* ShellView_FillList()
1001*
1002* - gets the objectlist from the shellfolder
1003* - sorts the list
1004* - fills the list into the view
1005*/
1007{
1008 PITEMID_CHILD pidl = static_cast<PITEMID_CHILD>(ptr);
1009 CDefView *pThis = static_cast<CDefView *>(arg);
1010
1011 /* in a commdlg This works as a filemask*/
1012 if (pThis->IncludeObject(pidl) == S_OK)
1013 pThis->LV_AddItem(pidl);
1014
1015 SHFree(pidl);
1016 return TRUE;
1017}
1018
1020{
1021 CComPtr<IEnumIDList> pEnumIDList;
1022 PITEMID_CHILD pidl;
1023 DWORD dwFetched;
1024 HRESULT hRes;
1025 HDPA hdpa;
1026 DWORD dFlags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS;
1027 DWORD dwValue, cbValue;
1028
1029 TRACE("%p\n", this);
1030
1031 /* determine if there is a setting to show all the hidden files/folders */
1032 dwValue = 1;
1033 cbValue = sizeof(dwValue);
1035 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
1036 L"Hidden", NULL, &dwValue, &cbValue);
1037 if (dwValue == 1)
1038 {
1039 dFlags |= SHCONTF_INCLUDEHIDDEN;
1040 m_ListView.SendMessageW(LVM_SETCALLBACKMASK, LVIS_CUT, 0);
1041 }
1042
1043 dwValue = 0;
1044 cbValue = sizeof(dwValue);
1046 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
1047 L"ShowSuperHidden", NULL, &dwValue, &cbValue);
1048 if (dwValue)
1049 {
1050 dFlags |= SHCONTF_INCLUDESUPERHIDDEN;
1051 m_ListView.SendMessageW(LVM_SETCALLBACKMASK, LVIS_CUT, 0);
1052 }
1053
1054 /* get the itemlist from the shfolder */
1055 hRes = m_pSFParent->EnumObjects(m_hWnd, dFlags, &pEnumIDList);
1056 if (hRes != S_OK)
1057 {
1058 if (hRes == S_FALSE)
1059 return(NOERROR);
1060 return(hRes);
1061 }
1062
1063 /* create a pointer array */
1064 hdpa = DPA_Create(16);
1065 if (!hdpa)
1066 {
1067 return(E_OUTOFMEMORY);
1068 }
1069
1070 /* copy the items into the array*/
1071 while((S_OK == pEnumIDList->Next(1, &pidl, &dwFetched)) && dwFetched)
1072 {
1073 if (DPA_InsertPtr(hdpa, 0x7fff, pidl) == -1)
1074 {
1075 SHFree(pidl);
1076 }
1077 }
1078
1079 /*turn the listview's redrawing off*/
1081
1082 DPA_DestroyCallback( hdpa, fill_list, this);
1083
1084 /* sort the array */
1085 if (m_pSF2Parent)
1086 {
1087 m_pSF2Parent->GetDefaultColumn(NULL, (ULONG*)&m_sortInfo.nHeaderID, NULL);
1088 }
1089 else
1090 {
1091 FIXME("no m_pSF2Parent\n");
1092 }
1094 _Sort();
1095
1097 {
1100 }
1101
1102 // load custom background image and custom text color
1105
1106 /*turn the listview's redrawing back on and force it to draw*/
1108
1110
1112 {
1113 // redraw now
1114 m_ListView.InvalidateRect(NULL, TRUE);
1115 }
1116
1118
1119 return S_OK;
1120}
1121
1123{
1124 if (m_ListView.IsWindow())
1125 m_ListView.UpdateWindow();
1126 bHandled = FALSE;
1127 return 0;
1128}
1129
1131{
1132 return m_ListView.SendMessageW(uMsg, 0, 0);
1133}
1134
1136{
1137 if (!m_Destroyed)
1138 {
1139 m_Destroyed = TRUE;
1140 if (m_hMenu)
1141 {
1143 m_hMenu = NULL;
1144 }
1147 m_hNotify = NULL;
1150 }
1151 bHandled = FALSE;
1152 return 0;
1153}
1154
1156{
1157 /* redirect to parent */
1160
1161 bHandled = FALSE;
1162 return 0;
1163}
1164
1165static VOID
1167{
1168 INT x0 = prc->left, y0 = prc->top, x1 = prc->right, y1 = prc->bottom;
1169 x0 += dx;
1170 y0 += dy;
1171
1172 HDC hMemDC = CreateCompatibleDC(hDC);
1173 HGDIOBJ hbmOld = SelectObject(hMemDC, hbm);
1174
1175 for (INT y = y0; y < y1; y += nHeight)
1176 {
1177 for (INT x = x0; x < x1; x += nWidth)
1178 {
1179 BitBlt(hDC, x, y, nWidth, nHeight, hMemDC, 0, 0, SRCCOPY);
1180 }
1181 }
1182
1183 SelectObject(hMemDC, hbmOld);
1184 DeleteDC(hMemDC);
1185}
1186
1188{
1189 HDC hDC = (HDC)wParam;
1190
1191 RECT rc;
1193
1195 {
1196 BITMAP bm;
1197 if (::GetObject(m_viewinfo_data.hbmBack, sizeof(BITMAP), &bm))
1198 {
1199 INT dx = -(::GetScrollPos(m_ListView, SB_HORZ) % bm.bmWidth);
1200 INT dy = -(::GetScrollPos(m_ListView, SB_VERT) % bm.bmHeight);
1201 DrawTileBitmap(hDC, &rc, m_viewinfo_data.hbmBack, bm.bmWidth, bm.bmHeight, dx, dy);
1202 }
1203 }
1204 else
1205 {
1207 }
1208
1209 bHandled = TRUE;
1210
1211 return TRUE;
1212}
1213
1215{
1216 /* Update desktop labels color */
1218
1219 /* Forward WM_SYSCOLORCHANGE to common controls */
1220 return m_ListView.SendMessageW(uMsg, 0, 0);
1221}
1222
1224{
1225 return reinterpret_cast<LRESULT>(m_pShellBrowser.p);
1226}
1227
1229{
1230 this->AddRef();
1231 bHandled = FALSE;
1232 return 0;
1233}
1234
1236{
1237 this->Release();
1238}
1239
1240/**********************************************************
1241* ShellView_OnCreate()
1242*/
1244{
1247
1248 TRACE("%p\n", this);
1249
1251 {
1252 if (FAILED(RegisterDragDrop(m_hWnd, pdt)))
1253 ERR("Registering Drag Drop Failed\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/**********************************************************
1312 * #### Handling of the menus ####
1313 */
1314
1315extern "C" DWORD WINAPI SHMenuIndexFromID(HMENU hMenu, UINT uID);
1316
1318{
1319 MENUITEMINFOW mii = {sizeof(mii), MIIM_SUBMENU};
1320 if (::GetMenuItemInfoW(hmenu, id, FALSE, &mii))
1321 return mii.hSubMenu;
1322
1323 return NULL;
1324}
1325
1326/* ReallyGetMenuItemID returns the id of an item even if it opens a submenu,
1327 GetMenuItemID returns -1 if the specified item opens a submenu */
1329{
1330 MENUITEMINFOW mii = {sizeof(mii), MIIM_ID};
1331 if (::GetMenuItemInfoW(hmenu, i, TRUE, &mii))
1332 return mii.wID;
1333
1334 return UINT_MAX;
1335}
1336
1338{
1340 if (!hFileMenu)
1341 return E_FAIL;
1342
1343 /* Cleanup the items added previously */
1344 for (int i = GetMenuItemCount(hFileMenu) - 1; i >= 0; i--)
1345 {
1346 UINT id = GetMenuItemID(hFileMenu, i);
1347 if (id < FCIDM_BROWSERFIRST || id > FCIDM_BROWSERLAST)
1348 DeleteMenu(hFileMenu, i, MF_BYPOSITION);
1349 }
1350
1352
1353 /* In case we still have this left over, clean it up! */
1354 if (m_pFileMenu)
1355 {
1358 }
1359 /* Store the context menu in m_pFileMenu and keep it in order to invoke the selected command later on */
1362 return hr;
1363
1365
1366 hr = m_pFileMenu->QueryContextMenu(hmenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, 0);
1368 return hr;
1369
1370 // TODO: filter or something
1371
1372 Shell_MergeMenus(hFileMenu, hmenu, 0, 0, 0xFFFF, MM_ADDSEPARATOR | MM_SUBMENUSHAVEIDS);
1373
1375
1376 return S_OK;
1377}
1378
1380{
1382 if (!hEditMenu)
1383 return E_FAIL;
1384
1385 HMENU hmenuContents = ::LoadMenuW(shell32_hInstance, L"MENU_003");
1386 if (!hmenuContents)
1387 return E_FAIL;
1388
1389 Shell_MergeMenus(hEditMenu, hmenuContents, 0, 0, 0xFFFF, 0);
1390
1391 ::DestroyMenu(hmenuContents);
1392
1393 return S_OK;
1394}
1395
1397{
1399 if (!hViewMenu)
1400 return E_FAIL;
1401
1403 if (!m_hMenuViewModes)
1404 return E_FAIL;
1405
1408
1409 return S_OK;
1410}
1411
1413{
1414 /* We only need to fill this once */
1415 if (GetMenuItemID(hmenuArrange, 0) == FCIDM_SHVIEW_AUTOARRANGE)
1416 {
1417 Shell_MergeMenus(hmenuArrange, m_hMenuArrangeModes, 0, 0, 0xFFFF,0);
1418 }
1419
1420 /* Also check the menu item according to which we sort */
1421 CheckMenuRadioItem(hmenuArrange,
1422 0x30,
1423 0x100,
1424 m_sortInfo.nHeaderID + 0x30,
1425 MF_BYCOMMAND);
1426
1428 {
1431 }
1432 else
1433 {
1436
1437 if (GetAutoArrange() == S_OK)
1439 else
1441
1442 if (_GetSnapToGrid() == S_OK)
1444 else
1446 }
1447
1448
1449 return S_OK;
1450}
1451
1453{
1455 {
1456 UINT iItemFirst = FCIDM_SHVIEW_BIGICON;
1457 UINT iItemLast = iItemFirst + FVM_LAST - FVM_FIRST;
1458 UINT iItem = iItemFirst + m_FolderSettings.ViewMode - FVM_FIRST;
1459 CheckMenuRadioItem(hmenuView, iItemFirst, iItemLast, iItem, MF_BYCOMMAND);
1460 }
1461
1462 return S_OK;
1463}
1464
1465/**********************************************************
1466* ShellView_GetSelections()
1467*
1468* - fills the m_apidl list with the selected objects
1469*
1470* RETURNS
1471* number of selected items
1472*/
1474{
1475 SHFree(m_apidl);
1476
1478 m_apidl = static_cast<PCUITEMID_CHILD*>(SHAlloc(m_cidl * sizeof(PCUITEMID_CHILD)));
1479 if (!m_apidl)
1480 {
1481 m_cidl = 0;
1482 return 0;
1483 }
1484
1485 TRACE("-- Items selected =%u\n", m_cidl);
1486
1487 UINT i = 0;
1488 int lvIndex = -1;
1489 while ((lvIndex = m_ListView.GetNextItem(lvIndex, LVNI_SELECTED)) > -1)
1490 {
1491 m_apidl[i] = _PidlByItem(lvIndex);
1492 i++;
1493 if (i == m_cidl)
1494 break;
1495 TRACE("-- selected Item found\n");
1496 }
1497
1498 return m_cidl;
1499}
1500
1502{
1503 CMINVOKECOMMANDINFOEX cmi;
1504
1505 ZeroMemory(&cmi, sizeof(cmi));
1506 cmi.cbSize = sizeof(cmi);
1507 cmi.lpVerb = MAKEINTRESOURCEA(uCommand);
1508 cmi.hwnd = m_hWnd;
1509
1510 if (GetKeyState(VK_SHIFT) & 0x8000)
1511 cmi.fMask |= CMIC_MASK_SHIFT_DOWN;
1512
1513 if (GetKeyState(VK_CONTROL) & 0x8000)
1514 cmi.fMask |= CMIC_MASK_CONTROL_DOWN;
1515
1516 if (pt)
1517 {
1518 cmi.fMask |= CMIC_MASK_PTINVOKE;
1519 cmi.ptInvoke = *pt;
1520 }
1521
1522 HRESULT hr = pCM->InvokeCommand((LPCMINVOKECOMMANDINFO)&cmi);
1523 // Most of our callers will do this, but in case they don't do that (File menu!)
1524 IUnknown_SetSite(pCM, NULL);
1525 pCM.Release();
1526
1528 return hr;
1529
1530 return S_OK;
1531}
1532
1533/**********************************************************
1534 * ShellView_OpenSelectedItems()
1535 */
1537{
1538 HMENU hMenu;
1539 UINT uCommand;
1540 HRESULT hResult;
1541
1543 if (m_cidl == 0)
1544 return S_OK;
1545
1546 hResult = OnDefaultCommand();
1547 if (hResult == S_OK)
1548 return hResult;
1549
1550 hMenu = CreatePopupMenu();
1551 if (!hMenu)
1552 return E_FAIL;
1553
1556 MenuCleanup _(pCM, hMenu);
1557 if (FAILED_UNEXPECTEDLY(hResult))
1558 return hResult;
1559
1560 hResult = pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_DEFAULTONLY);
1561 if (FAILED_UNEXPECTEDLY(hResult))
1562 return hResult;
1563
1564 uCommand = GetMenuDefaultItem(hMenu, FALSE, 0);
1565 if (uCommand == (UINT)-1)
1566 {
1567 ERR("GetMenuDefaultItem returned -1\n");
1568 return E_FAIL;
1569 }
1570
1571 InvokeContextMenuCommand(pCM, uCommand, NULL);
1572
1573 return hResult;
1574}
1575
1576/**********************************************************
1577 * ShellView_DoContextMenu()
1578 */
1580{
1581 POINT pt;
1582 UINT uCommand;
1583 HRESULT hResult;
1584
1585 TRACE("(%p)\n", this);
1586
1587 if (m_hContextMenu != NULL)
1588 {
1589 ERR("HACK: Aborting context menu in nested call!\n");
1590 return 0;
1591 }
1592
1594 if (!m_hContextMenu)
1595 return E_FAIL;
1596
1597 if (lParam != ~0) // unless app key (menu key) was pressed
1598 {
1599 pt.x = GET_X_LPARAM(lParam);
1600 pt.y = GET_Y_LPARAM(lParam);
1601
1602 LV_HITTESTINFO hittest = { pt };
1603 ScreenToClient(&hittest.pt);
1604 m_ListView.HitTest(&hittest);
1605
1606 // Right-Clicked item is selected? If selected, no selection change.
1607 // If not selected, then reset the selection and select the item.
1608 if ((hittest.flags & LVHT_ONITEM) &&
1610 {
1611 SelectItem(hittest.iItem, SVSI_SELECT | SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE);
1612 }
1613 }
1614
1616 /* In case we still have this left over, clean it up! */
1619 if (FAILED_UNEXPECTEDLY(hResult))
1620 return 0;
1621
1622 /* Use 1 as the first id as we want 0 the mean that the user canceled the menu */
1623 hResult = m_pCM->QueryContextMenu(m_hContextMenu, 0, CONTEXT_MENU_BASE_ID, FCIDM_SHVIEWLAST, CMF_NORMAL);
1624 if (FAILED_UNEXPECTEDLY(hResult))
1625 return 0;
1626
1627 /* There is no position requested, so try to find one */
1628 if (lParam == ~0)
1629 {
1630 HWND hFocus = ::GetFocus();
1631 int lvIndex = -1;
1632
1633 if (hFocus == m_ListView.m_hWnd || m_ListView.IsChild(hFocus))
1634 {
1635 /* Is there an item focused and selected? */
1637 /* If not, find the first selected item */
1638 if (lvIndex < 0)
1639 lvIndex = m_ListView.GetNextItem(-1, LVIS_SELECTED);
1640 }
1641
1642 /* We got something */
1643 if (lvIndex > -1)
1644 {
1645 /* Let's find the center of the icon */
1646 RECT rc = { LVIR_ICON };
1647 m_ListView.SendMessage(LVM_GETITEMRECT, lvIndex, (LPARAM)&rc);
1648 pt.x = (rc.right + rc.left) / 2;
1649 pt.y = (rc.bottom + rc.top) / 2;
1650 }
1651 else
1652 {
1653 /* We have to drop it somewhere.. */
1654 pt.x = pt.y = 0;
1655 }
1656
1657 m_ListView.ClientToScreen(&pt);
1658 }
1659
1660 // This runs the message loop, calling back to us with f.e. WM_INITPOPUP (hence why m_hContextMenu and m_pCM exist)
1661 uCommand = TrackPopupMenu(m_hContextMenu,
1663 pt.x, pt.y, 0, m_hWnd, NULL);
1664 if (uCommand == 0)
1665 return 0;
1666
1667 if (uCommand == FCIDM_SHVIEW_OPEN && OnDefaultCommand() == S_OK)
1668 return 0;
1669
1671
1672 return 0;
1673}
1674
1676{
1677 HRESULT hResult;
1678 HMENU hMenu = NULL;
1679
1681 hResult = GetItemObject( bUseSelection ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &pCM));
1682 if (FAILED_UNEXPECTEDLY(hResult))
1683 return 0;
1684
1685 MenuCleanup _(pCM, hMenu);
1686
1687 if ((uCommand != FCIDM_SHVIEW_DELETE) && (uCommand != FCIDM_SHVIEW_RENAME))
1688 {
1689 hMenu = CreatePopupMenu();
1690 if (!hMenu)
1691 return 0;
1692
1693 hResult = pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_NORMAL);
1694 if (FAILED_UNEXPECTEDLY(hResult))
1695 return 0;
1696 }
1697
1698 if (bUseSelection)
1699 {
1700 // FIXME: we should cache this....
1701 SFGAOF rfg = SFGAO_BROWSABLE | SFGAO_CANCOPY | SFGAO_CANLINK | SFGAO_CANMOVE | SFGAO_CANDELETE | SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSTEM | SFGAO_FOLDER;
1702 hResult = m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &rfg);
1703 if (FAILED_UNEXPECTEDLY(hResult))
1704 return 0;
1705
1706 if (!(rfg & SFGAO_CANMOVE) && uCommand == FCIDM_SHVIEW_CUT)
1707 return 0;
1708 if (!(rfg & SFGAO_CANCOPY) && uCommand == FCIDM_SHVIEW_COPY)
1709 return 0;
1710 if (!(rfg & SFGAO_CANDELETE) && uCommand == FCIDM_SHVIEW_DELETE)
1711 return 0;
1712 if (!(rfg & SFGAO_CANRENAME) && uCommand == FCIDM_SHVIEW_RENAME)
1713 return 0;
1714 if (!(rfg & SFGAO_HASPROPSHEET) && uCommand == FCIDM_SHVIEW_PROPERTIES)
1715 return 0;
1716 }
1717
1718 // FIXME: We should probably use the objects position?
1719 InvokeContextMenuCommand(pCM, uCommand, NULL);
1720 return 0;
1721}
1722
1723/**********************************************************
1724 * ##### message handling #####
1725 */
1726
1727/**********************************************************
1728* ShellView_OnSize()
1729*/
1731{
1732 WORD wWidth, wHeight;
1733
1734 wWidth = LOWORD(lParam);
1735 wHeight = HIWORD(lParam);
1736
1737 TRACE("%p width=%u height=%u\n", this, wWidth, wHeight);
1738
1739 /* Resize the ListView to fit our window */
1740 if (m_ListView)
1741 {
1742 ::MoveWindow(m_ListView, 0, 0, wWidth, wHeight, TRUE);
1743 }
1744
1746
1747 _HandleStatusBarResize(wWidth);
1749
1750 return 0;
1751}
1752
1753/**********************************************************
1754* ShellView_OnDeactivate()
1755*
1756* NOTES
1757* internal
1758*/
1760{
1761 TRACE("%p\n", this);
1762
1764 {
1765 // TODO: cleanup menu after deactivation
1766
1768 }
1769}
1770
1772{
1773 TRACE("%p uState=%x\n", this, uState);
1774
1775 /*don't do anything if the state isn't really changing */
1776 if (m_uState == uState)
1777 {
1778 return;
1779 }
1780
1781 if (uState == SVUIA_DEACTIVATE)
1782 {
1783 OnDeactivate();
1784 }
1785 else
1786 {
1788 {
1789 FillEditMenu();
1790 FillViewMenu();
1791 m_pShellBrowser->SetMenuSB(m_hMenu, 0, m_hWnd);
1793 }
1794
1795 if (SVUIA_ACTIVATE_FOCUS == uState)
1796 {
1797 m_ListView.SetFocus();
1798 }
1799 }
1800
1801 m_uState = uState;
1802 TRACE("--\n");
1803}
1804
1805/**********************************************************
1806* ShellView_OnActivate()
1807*/
1809{
1811 return 0;
1812}
1813
1814/**********************************************************
1815* ShellView_OnSetFocus()
1816*
1817*/
1819{
1820 TRACE("%p\n", this);
1821
1822 /* Tell the browser one of our windows has received the focus. This
1823 should always be done before merging menus (OnActivate merges the
1824 menus) if one of our windows has the focus.*/
1825
1826 m_pShellBrowser->OnViewWindowActive(this);
1828
1829 /* Set the focus to the listview */
1830 m_ListView.SetFocus();
1831
1832 /* Notify the ICommDlgBrowser interface */
1833 OnStateChange(CDBOSC_SETFOCUS);
1834
1835 return 0;
1836}
1837
1838/**********************************************************
1839* ShellView_OnKillFocus()
1840*/
1842{
1843 TRACE("(%p) stub\n", this);
1844
1846 /* Notify the ICommDlgBrowser */
1847 OnStateChange(CDBOSC_KILLFOCUS);
1848
1849 return 0;
1850}
1851
1852/**********************************************************
1853* ShellView_OnCommand()
1854*
1855* NOTES
1856* the CmdID's are the ones from the context menu
1857*/
1859{
1860 DWORD dwCmdID;
1861 DWORD dwCmd;
1862 HWND hwndCmd;
1863 int nCount;
1864
1865 dwCmdID = GET_WM_COMMAND_ID(wParam, lParam);
1867 hwndCmd = GET_WM_COMMAND_HWND(wParam, lParam);
1868
1869 TRACE("(%p)->(0x%08x 0x%08x %p) stub\n", this, dwCmdID, dwCmd, hwndCmd);
1870
1871 switch (dwCmdID)
1872 {
1876 CheckToolbar();
1877 break;
1878
1881 m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_ICON);
1882 CheckToolbar();
1883 break;
1884
1887 m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_LIST);
1888 CheckToolbar();
1889 break;
1890
1893 m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_REPORT);
1894 CheckToolbar();
1895 break;
1896
1897 /* the menu-ID's for sorting are 0x30... see shrec.rc */
1898 case 0x30:
1899 case 0x31:
1900 case 0x32:
1901 case 0x33:
1902 m_sortInfo.nHeaderID = dwCmdID - 0x30;
1904 _Sort();
1905 break;
1906
1909 break;
1911 if (_GetSnapToGrid() == S_OK)
1913 else
1914 ArrangeGrid();
1915 break;
1917 if (GetAutoArrange() == S_OK)
1918 m_ListView.ModifyStyle(LVS_AUTOARRANGE, 0);
1919 else
1920 AutoArrange();
1921 break;
1924 break;
1925
1927 nCount = m_ListView.GetItemCount();
1928 for (int i=0; i < nCount; i++)
1930 break;
1931
1933 Refresh();
1934 break;
1935
1937 case FCIDM_SHVIEW_CUT:
1938 case FCIDM_SHVIEW_COPY:
1944 return 0;
1945
1946 return OnExplorerCommand(dwCmdID, TRUE);
1947
1949 case FCIDM_SHVIEW_UNDO:
1952 return OnExplorerCommand(dwCmdID, FALSE);
1953 default:
1954 /* WM_COMMAND messages from the file menu are routed to the CDefView so as to let m_pFileMenu handle the command */
1955 if (m_pFileMenu && dwCmd == 0)
1956 {
1957 HMENU Dummy = NULL;
1958 MenuCleanup _(m_pFileMenu, Dummy);
1960 }
1961 }
1962
1963 return 0;
1964}
1965
1966static BOOL
1968{
1969 HKEY hKey;
1970 LONG error;
1971 DWORD dwValue = FALSE, cbValue;
1972
1974 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer",
1975 0, KEY_READ, &hKey);
1976 if (error)
1977 return dwValue;
1978
1979 cbValue = sizeof(dwValue);
1980 RegQueryValueExW(hKey, L"SelectExtOnRename", NULL, NULL, (LPBYTE)&dwValue, &cbValue);
1981
1983 return !!dwValue;
1984}
1985
1986/**********************************************************
1987* ShellView_OnNotify()
1988*/
1989
1991{
1992 UINT CtlID;
1993 LPNMHDR lpnmh;
1994 LPNMLISTVIEW lpnmlv;
1995 NMLVDISPINFOW *lpdi;
1996 PCUITEMID_CHILD pidl;
1997 BOOL unused;
1998
1999 CtlID = wParam;
2000 lpnmh = (LPNMHDR)lParam;
2001 lpnmlv = (LPNMLISTVIEW)lpnmh;
2002 lpdi = (NMLVDISPINFOW *)lpnmh;
2003
2004 TRACE("%p CtlID=%u lpnmh->code=%x\n", this, CtlID, lpnmh->code);
2005
2006 switch (lpnmh->code)
2007 {
2008 case NM_SETFOCUS:
2009 TRACE("-- NM_SETFOCUS %p\n", this);
2010 OnSetFocus(0, 0, 0, unused);
2011 break;
2012
2013 case NM_KILLFOCUS:
2014 TRACE("-- NM_KILLFOCUS %p\n", this);
2015 OnDeactivate();
2016 /* Notify the ICommDlgBrowser interface */
2017 OnStateChange(CDBOSC_KILLFOCUS);
2018 break;
2019
2020 case NM_CUSTOMDRAW:
2021 TRACE("-- NM_CUSTOMDRAW %p\n", this);
2022 return CDRF_DODEFAULT;
2023
2024 case NM_RELEASEDCAPTURE:
2025 TRACE("-- NM_RELEASEDCAPTURE %p\n", this);
2026 break;
2027
2028 case NM_CLICK:
2029 TRACE("-- NM_CLICK %p\n", this);
2030 break;
2031
2032 case NM_RCLICK:
2033 TRACE("-- NM_RCLICK %p\n", this);
2034 break;
2035
2036 case NM_DBLCLK:
2037 TRACE("-- NM_DBLCLK %p\n", this);
2039 break;
2040
2041 case NM_RETURN:
2042 TRACE("-- NM_RETURN %p\n", this);
2044 break;
2045
2046 case HDN_ENDTRACKW:
2047 TRACE("-- HDN_ENDTRACKW %p\n", this);
2048 /*nColumn1 = m_ListView.GetColumnWidth(0);
2049 nColumn2 = m_ListView.GetColumnWidth(1);*/
2050 break;
2051
2052 case LVN_DELETEITEM:
2053 TRACE("-- LVN_DELETEITEM %p\n", this);
2054
2055 /*delete the pidl because we made a copy of it*/
2056 SHFree(reinterpret_cast<LPVOID>(lpnmlv->lParam));
2057
2058 break;
2059
2060 case LVN_DELETEALLITEMS:
2061 TRACE("-- LVN_DELETEALLITEMS %p\n", this);
2062 return FALSE;
2063
2064 case LVN_INSERTITEM:
2065 TRACE("-- LVN_INSERTITEM (STUB)%p\n", this);
2066 break;
2067
2068 case LVN_ITEMACTIVATE:
2069 TRACE("-- LVN_ITEMACTIVATE %p\n", this);
2070 OnStateChange(CDBOSC_SELCHANGE); /* the browser will get the IDataObject now */
2071 break;
2072
2073 case LVN_COLUMNCLICK:
2074 m_sortInfo.nHeaderID = lpnmlv->iSubItem;
2077 else
2079 _Sort();
2080 break;
2081
2082 case LVN_GETDISPINFOA:
2083 case LVN_GETDISPINFOW:
2084 TRACE("-- LVN_GETDISPINFO %p\n", this);
2085 pidl = _PidlByItem(lpdi->item);
2086
2087 if (lpdi->item.mask & LVIF_TEXT) /* text requested */
2088 {
2089 if (m_pSF2Parent)
2090 {
2092 if (FAILED_UNEXPECTEDLY(m_pSF2Parent->GetDetailsOf(pidl, lpdi->item.iSubItem, &sd)))
2093 break;
2094
2095 if (lpnmh->code == LVN_GETDISPINFOA)
2096 {
2097 /* shouldn't happen */
2098 NMLVDISPINFOA *lpdiA = (NMLVDISPINFOA *)lpnmh;
2099 StrRetToStrNA( lpdiA->item.pszText, lpdiA->item.cchTextMax, &sd.str, NULL);
2100 TRACE("-- text=%s\n", lpdiA->item.pszText);
2101 }
2102 else /* LVN_GETDISPINFOW */
2103 {
2104 StrRetToStrNW( lpdi->item.pszText, lpdi->item.cchTextMax, &sd.str, NULL);
2105 TRACE("-- text=%s\n", debugstr_w(lpdi->item.pszText));
2106 }
2107 }
2108 else
2109 {
2110 FIXME("no m_pSF2Parent\n");
2111 }
2112 }
2113 if(lpdi->item.mask & LVIF_IMAGE) /* image requested */
2114 {
2116 }
2117 if(lpdi->item.mask & LVIF_STATE)
2118 {
2119 ULONG attributes = SFGAO_HIDDEN;
2120 if (SUCCEEDED(m_pSFParent->GetAttributesOf(1, &pidl, &attributes)))
2121 {
2122 if (attributes & SFGAO_HIDDEN)
2123 {
2124 lpdi->item.state |= LVIS_CUT;
2125 }
2126 }
2127 }
2128 lpdi->item.mask |= LVIF_DI_SETITEM;
2129 break;
2130
2131 case LVN_ITEMCHANGED:
2132 TRACE("-- LVN_ITEMCHANGED %p\n", this);
2133 OnStateChange(CDBOSC_SELCHANGE); /* the browser will get the IDataObject now */
2135 _DoFolderViewCB(SFVM_SELECTIONCHANGED, NULL/* FIXME */, NULL/* FIXME */);
2136 break;
2137
2138 case LVN_BEGINDRAG:
2139 case LVN_BEGINRDRAG:
2140 TRACE("-- LVN_BEGINDRAG\n");
2141
2142 if (GetSelections())
2143 {
2145 DWORD dwAttributes = SFGAO_CANCOPY | SFGAO_CANLINK;
2146 DWORD dwEffect = DROPEFFECT_MOVE;
2147
2148 if (SUCCEEDED(m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, IID_NULL_PPV_ARG(IDataObject, &pda))))
2149 {
2151
2152 if (SUCCEEDED(m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &dwAttributes)))
2153 {
2154 dwEffect |= dwAttributes & (SFGAO_CANCOPY | SFGAO_CANLINK);
2155 }
2156
2158 if (SUCCEEDED(pda->QueryInterface(IID_PPV_ARG(IAsyncOperation, &piaso))))
2159 {
2160 piaso->SetAsyncMode(TRUE);
2161 }
2162
2163 DWORD dwEffect2;
2164
2165 m_pSourceDataObject = pda;
2166 m_ptFirstMousePos = params->ptAction;
2169
2170 HIMAGELIST big_icons, small_icons;
2171 Shell_GetImageLists(&big_icons, &small_icons);
2172 PCUITEMID_CHILD pidl = _PidlByItem(params->iItem);
2173 int iIcon = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
2174 POINT ptItem;
2175 m_ListView.GetItemPosition(params->iItem, &ptItem);
2176
2177 ImageList_BeginDrag(big_icons, iIcon, params->ptAction.x - ptItem.x, params->ptAction.y - ptItem.y);
2178
2179 DoDragDrop(pda, this, dwEffect, &dwEffect2);
2180
2182 }
2183 }
2184 break;
2185
2187 {
2188 DWORD dwAttr = SFGAO_CANRENAME;
2189 pidl = _PidlByItem(lpdi->item);
2190
2191 TRACE("-- LVN_BEGINLABELEDITW %p\n", this);
2192
2193 m_pSFParent->GetAttributesOf(1, &pidl, &dwAttr);
2194 if (SFGAO_CANRENAME & dwAttr)
2195 {
2196 HWND hEdit = reinterpret_cast<HWND>(m_ListView.SendMessage(LVM_GETEDITCONTROL));
2198
2199 /* smartass-renaming: See CORE-15242 */
2200 if (!(dwAttr & SFGAO_FOLDER) && (dwAttr & SFGAO_FILESYSTEM) &&
2201 (lpdi->item.mask & LVIF_TEXT) && !SelectExtOnRename())
2202 {
2203 WCHAR szFullPath[MAX_PATH];
2204 PIDLIST_ABSOLUTE pidlFull = ILCombine(m_pidlParent, pidl);
2205 SHGetPathFromIDListW(pidlFull, szFullPath);
2206
2207 if (!SHELL_FS_HideExtension(szFullPath))
2208 {
2209 LPWSTR pszText = lpdi->item.pszText;
2210 LPWSTR pchDotExt = PathFindExtensionW(pszText);
2211 ::PostMessageW(hEdit, EM_SETSEL, 0, pchDotExt - pszText);
2213 }
2214
2215 ILFree(pidlFull);
2216 }
2217
2218 m_isEditing = TRUE;
2219 return FALSE;
2220 }
2221
2222 return TRUE;
2223 }
2224
2225 case LVN_ENDLABELEDITW:
2226 {
2227 TRACE("-- LVN_ENDLABELEDITW %p\n", this);
2228
2230
2231 if (lpdi->item.pszText)
2232 {
2233 HRESULT hr;
2234 LVITEMW lvItem;
2235
2236 pidl = _PidlByItem(lpdi->item);
2237 PITEMID_CHILD pidlNew = NULL;
2238 hr = m_pSFParent->SetNameOf(0, pidl, lpdi->item.pszText, SHGDN_INFOLDER, &pidlNew);
2239
2240 if (SUCCEEDED(hr) && pidlNew)
2241 {
2242 lvItem.mask = LVIF_PARAM|LVIF_IMAGE;
2243 lvItem.iItem = lpdi->item.iItem;
2244 lvItem.iSubItem = 0;
2245 lvItem.lParam = reinterpret_cast<LPARAM>(pidlNew);
2247 m_ListView.SetItem(&lvItem);
2248 m_ListView.Update(lpdi->item.iItem);
2249 return TRUE;
2250 }
2251 }
2252
2253 return FALSE;
2254 }
2255
2256 default:
2257 TRACE("-- %p WM_COMMAND %x unhandled\n", this, lpnmh->code);
2258 break;
2259 }
2260
2261 return 0;
2262}
2263
2264/*
2265 * This is just a quick hack to make the desktop work correctly.
2266 * ITranslateShellChangeNotify's IsChildID is undocumented, but most likely the way that
2267 * a folder should know if it should update upon a change notification.
2268 * It is exported by merged folders at a minimum.
2269 */
2271{
2272 if (!pidl1 || !pidl2)
2273 return FALSE;
2274 if (ILIsParent(pidl1, pidl2, TRUE))
2275 return TRUE;
2276
2277 if (_ILIsDesktop(pidl1))
2278 {
2279 PIDLIST_ABSOLUTE deskpidl;
2281 if (ILIsParent(deskpidl, pidl2, TRUE))
2282 {
2283 ILFree(deskpidl);
2284 return TRUE;
2285 }
2286 ILFree(deskpidl);
2288 if (ILIsParent(deskpidl, pidl2, TRUE))
2289 {
2290 ILFree(deskpidl);
2291 return TRUE;
2292 }
2293 ILFree(deskpidl);
2294 }
2295
2296 WCHAR szPath1[MAX_PATH], szPath2[MAX_PATH];
2297 LPITEMIDLIST pidl2Clone = ILClone(pidl2);
2298 ILRemoveLastID(pidl2Clone);
2299 if (SHGetPathFromIDListW(pidl1, szPath1) &&
2300 SHGetPathFromIDListW(pidl2Clone, szPath2))
2301 {
2302 if (lstrcmpiW(szPath1, szPath2) == 0)
2303 {
2304 ILFree(pidl2Clone);
2305 return TRUE;
2306 }
2307 }
2308 ILFree(pidl2Clone);
2309
2310 return FALSE;
2311}
2312
2313/**********************************************************
2314* ShellView_OnChange()
2315*/
2317{
2318 HANDLE hChange = (HANDLE)wParam;
2319 DWORD dwProcID = (DWORD)lParam;
2320 PIDLIST_ABSOLUTE *Pidls;
2321 LONG lEvent;
2322 HANDLE hLock = SHChangeNotification_Lock(hChange, dwProcID, &Pidls, &lEvent);
2323 if (hLock == NULL)
2324 {
2325 ERR("hLock == NULL\n");
2326 return FALSE;
2327 }
2328
2329 BOOL bParent0 = ILIsParentOrSpecialParent(m_pidlParent, Pidls[0]);
2330 BOOL bParent1 = ILIsParentOrSpecialParent(m_pidlParent, Pidls[1]);
2331
2332 TRACE("(%p)(%p,%p,0x%08x)\n", this, Pidls[0], Pidls[1], lParam);
2333
2334 lEvent &= ~SHCNE_INTERRUPT;
2335 switch (lEvent)
2336 {
2337 case SHCNE_MKDIR:
2338 case SHCNE_CREATE:
2339 if (bParent0)
2340 {
2341 if (LV_FindItemByPidl(ILFindLastID(Pidls[0])) == -1)
2342 {
2343 LV_AddItem(ILFindLastID(Pidls[0]));
2344 }
2345 else
2346 {
2347 LV_ProdItem(ILFindLastID(Pidls[0]));
2348 }
2349 }
2350 break;
2351
2352 case SHCNE_RMDIR:
2353 case SHCNE_DELETE:
2354 if (bParent0)
2355 LV_DeleteItem(ILFindLastID(Pidls[0]));
2356 break;
2357
2358 case SHCNE_RENAMEFOLDER:
2359 case SHCNE_RENAMEITEM:
2360 if (bParent0 && bParent1)
2361 LV_RenameItem(ILFindLastID(Pidls[0]), ILFindLastID(Pidls[1]));
2362 else if (bParent0)
2363 LV_DeleteItem(ILFindLastID(Pidls[0]));
2364 else if (bParent1)
2365 LV_AddItem(ILFindLastID(Pidls[1]));
2366 break;
2367
2368 case SHCNE_UPDATEITEM:
2369 if (bParent0)
2370 LV_RenameItem(ILFindLastID(Pidls[0]), ILFindLastID(Pidls[0]));
2371 break;
2372
2373 case SHCNE_UPDATEDIR:
2374 Refresh();
2375 break;
2376 }
2377
2379 return TRUE;
2380}
2381
2384
2385/**********************************************************
2386* CDefView::OnCustomItem
2387*/
2389{
2390 if (!m_pCM)
2391 {
2392 /* no menu */
2393 ERR("no context menu!!!\n");
2394 return FALSE;
2395 }
2396
2397 /* The lParam of WM_DRAWITEM WM_MEASUREITEM contain a menu id and this also needs to
2398 be changed to a menu identifier offset */
2399 UINT CmdID;
2400 HRESULT hres = SHGetMenuIdFromMenuMsg(uMsg, lParam, &CmdID);
2401 if (SUCCEEDED(hres))
2403
2404 /* Forward the message to the IContextMenu2 */
2407
2408 return (SUCCEEDED(hres));
2409}
2410
2412{
2413 /* Wallpaper setting affects drop shadows effect */
2414 if (wParam == SPI_SETDESKWALLPAPER || wParam == 0)
2416
2417 return S_OK;
2418}
2419
2420/**********************************************************
2421* CDefView::OnInitMenuPopup
2422*/
2424{
2425 HMENU hmenu = (HMENU) wParam;
2426 int nPos = LOWORD(lParam);
2427 UINT menuItemId;
2428
2429 if (m_pCM)
2430 {
2431 OnCustomItem(uMsg, wParam, lParam, bHandled);
2432 }
2433
2435
2436 if (GetSelections() == 0)
2437 {
2444 }
2445 else
2446 {
2447 // FIXME: Check copyable
2454 }
2455
2456 /* Lets try to find out what the hell wParam is */
2457 if (hmenu == GetSubMenu(m_hMenu, nPos))
2458 menuItemId = ReallyGetMenuItemID(m_hMenu, nPos);
2459 else if (hViewMenu && hmenu == GetSubMenu(hViewMenu, nPos))
2460 menuItemId = ReallyGetMenuItemID(hViewMenu, nPos);
2461 else if (m_hContextMenu && hmenu == GetSubMenu(m_hContextMenu, nPos))
2462 menuItemId = ReallyGetMenuItemID(m_hContextMenu, nPos);
2463 else
2464 return FALSE;
2465
2466 switch (menuItemId)
2467 {
2468 case FCIDM_MENU_FILE:
2469 FillFileMenu();
2470 break;
2471 case FCIDM_MENU_VIEW:
2472 case FCIDM_SHVIEW_VIEW:
2474 break;
2477 break;
2478 }
2479
2480 return FALSE;
2481}
2482
2483/**********************************************************
2484*
2485*
2486* The INTERFACE of the IShellView object
2487*
2488*
2489**********************************************************
2490*/
2491
2492/**********************************************************
2493* ShellView_GetWindow
2494*/
2496{
2497 TRACE("(%p)\n", this);
2498
2499 *phWnd = m_hWnd;
2500
2501 return S_OK;
2502}
2503
2505{
2506 FIXME("(%p) stub\n", this);
2507
2508 return E_NOTIMPL;
2509}
2510
2511/**********************************************************
2512* IShellView_TranslateAccelerator
2513*
2514* FIXME:
2515* use the accel functions
2516*/
2518{
2519 if (m_isEditing)
2520 return S_FALSE;
2521
2522 if (lpmsg->message >= WM_KEYFIRST && lpmsg->message <= WM_KEYLAST)
2523 {
2524 if (::TranslateAcceleratorW(m_hWnd, m_hAccel, lpmsg) != 0)
2525 return S_OK;
2526
2527 TRACE("-- key=0x%04lx\n", lpmsg->wParam) ;
2528 }
2529
2530 return m_pShellBrowser->TranslateAcceleratorSB(lpmsg, 0);
2531}
2532
2534{
2535 FIXME("(%p) stub\n", this);
2536
2537 return E_NOTIMPL;
2538}
2539
2541{
2542 TRACE("(%p)->(state=%x) stub\n", this, uState);
2543
2544 /* don't do anything if the state isn't really changing */
2545 if (m_uState == uState)
2546 {
2547 return S_OK;
2548 }
2549
2550 /* OnActivate handles the menu merging and internal state */
2551 DoActivate(uState);
2552
2553 /* only do This if we are active */
2554 if (uState != SVUIA_DEACTIVATE)
2555 {
2557
2558 /* Set the text for the status bar */
2560 }
2561
2562 return S_OK;
2563}
2564
2566{
2567 TRACE("(%p)\n", this);
2568
2570
2572 FillList();
2573
2574 return S_OK;
2575}
2576
2578{
2579 return CreateViewWindow3(psb, lpPrevView, SV3CVW3_DEFAULT,
2580 (FOLDERFLAGS)lpfs->fFlags, (FOLDERFLAGS)lpfs->fFlags, (FOLDERVIEWMODE)lpfs->ViewMode, NULL, prcView, phWnd);
2581}
2582
2584{
2585 TRACE("(%p)\n", this);
2586
2587 /* Make absolutely sure all our UI is cleaned up */
2589
2590 if (m_hAccel)
2591 {
2592 // "Accelerator tables loaded from resources are freed automatically when the application terminates." -- MSDN
2593 m_hAccel = NULL;
2594 }
2595
2597 {
2600 }
2601
2602 if (m_hMenuViewModes)
2603 {
2606 }
2607
2608 if (m_hMenu)
2609 {
2611 m_hMenu = NULL;
2612 }
2613
2614 if (m_ListView)
2615 {
2616 m_ListView.DestroyWindow();
2617 }
2618
2619 if (m_hWnd)
2620 {
2622 DestroyWindow();
2623 }
2624
2627
2628 return S_OK;
2629}
2630
2632{
2633 TRACE("(%p)->(%p) vmode=%x flags=%x\n", this, lpfs,
2635
2636 if (!lpfs)
2637 return E_INVALIDARG;
2638
2639 *lpfs = m_FolderSettings;
2640 return S_OK;
2641}
2642
2644{
2645 FIXME("(%p) stub\n", this);
2646
2647 return E_NOTIMPL;
2648}
2649
2651{
2652 FIXME("(%p) stub\n", this);
2653
2654 return S_OK;
2655}
2656
2658{
2659 int i;
2660
2661 TRACE("(%p)->(pidl=%p, 0x%08x) stub\n", this, pidl, uFlags);
2662
2663 i = LV_FindItemByPidl(pidl);
2664 if (i == -1)
2665 return S_OK;
2666
2667 LVITEMW lvItem = {0};
2668 lvItem.mask = LVIF_STATE;
2670
2671 while (m_ListView.GetItem(&lvItem))
2672 {
2673 if (lvItem.iItem == i)
2674 {
2675 if (uFlags & SVSI_SELECT)
2676 lvItem.state |= LVIS_SELECTED;
2677 else
2678 lvItem.state &= ~LVIS_SELECTED;
2679
2680 if (uFlags & SVSI_FOCUSED)
2681 lvItem.state |= LVIS_FOCUSED;
2682 else
2683 lvItem.state &= ~LVIS_FOCUSED;
2684 }
2685 else
2686 {
2687 if (uFlags & SVSI_DESELECTOTHERS)
2688 {
2689 lvItem.state &= ~LVIS_SELECTED;
2690 }
2691 lvItem.state &= ~LVIS_FOCUSED;
2692 }
2693
2694 m_ListView.SetItem(&lvItem);
2695 lvItem.iItem++;
2696 }
2697
2698 if (uFlags & SVSI_ENSUREVISIBLE)
2700
2701 if((uFlags & SVSI_EDIT) == SVSI_EDIT)
2703
2704 return S_OK;
2705}
2706
2708{
2710
2711 TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n", this, uItem, debugstr_guid(&riid), ppvOut);
2712
2713 if (!ppvOut)
2714 return E_INVALIDARG;
2715
2716 *ppvOut = NULL;
2717
2718 switch (uItem)
2719 {
2720 case SVGIO_BACKGROUND:
2721 if (IsEqualIID(riid, IID_IContextMenu))
2722 {
2725 return hr;
2726
2727 IUnknown_SetSite(*((IUnknown**)ppvOut), (IShellView *)this);
2728 }
2729 else if (IsEqualIID(riid, IID_IDispatch))
2730 {
2732 {
2735 return hr;
2736 }
2737 hr = m_pShellFolderViewDual->QueryInterface(riid, ppvOut);
2738 }
2739 break;
2740
2741 case SVGIO_SELECTION:
2742 GetSelections();
2743 hr = m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, riid, 0, ppvOut);
2745 return hr;
2746
2747 if (IsEqualIID(riid, IID_IContextMenu))
2748 IUnknown_SetSite(*((IUnknown**)ppvOut), (IShellView *)this);
2749
2750 break;
2751 }
2752
2753 TRACE("-- (%p)->(interface=%p)\n", this, *ppvOut);
2754
2755 return hr;
2756}
2757
2759{
2760 TRACE("(%p)->(%p), stub\n", this, pViewMode);
2761
2762 if (!pViewMode)
2763 return E_INVALIDARG;
2764
2765 *pViewMode = m_FolderSettings.ViewMode;
2766 return S_OK;
2767}
2768
2770{
2771 DWORD dwStyle;
2772 TRACE("(%p)->(%u), stub\n", this, ViewMode);
2773
2774 /* It's not redundant to check FVM_AUTO because it's a (UINT)-1 */
2775 if (((INT)ViewMode < FVM_FIRST || (INT)ViewMode > FVM_LAST) && ((INT)ViewMode != FVM_AUTO))
2776 return E_INVALIDARG;
2777
2778 /* Windows before Vista uses LVM_SETVIEW and possibly
2779 LVM_SETEXTENDEDLISTVIEWSTYLE to set the style of the listview,
2780 while later versions seem to accomplish this through other
2781 means. */
2782 switch (ViewMode)
2783 {
2784 case FVM_ICON:
2785 dwStyle = LVS_ICON;
2786 break;
2787 case FVM_DETAILS:
2788 dwStyle = LVS_REPORT;
2789 break;
2790 case FVM_SMALLICON:
2791 dwStyle = LVS_SMALLICON;
2792 break;
2793 case FVM_LIST:
2794 dwStyle = LVS_LIST;
2795 break;
2796 default:
2797 {
2798 FIXME("ViewMode %d not implemented\n", ViewMode);
2799 dwStyle = LVS_LIST;
2800 break;
2801 }
2802 }
2803
2804 m_ListView.ModifyStyle(LVS_TYPEMASK, dwStyle);
2805
2806 /* This will not necessarily be the actual mode set above.
2807 This mimics the behavior of Windows XP. */
2808 m_FolderSettings.ViewMode = ViewMode;
2809
2810 return S_OK;
2811}
2812
2814{
2815 if (m_pSFParent == NULL)
2816 return E_FAIL;
2817
2818 return m_pSFParent->QueryInterface(riid, ppv);
2819}
2820
2822{
2823 PCUITEMID_CHILD pidl = _PidlByItem(iItemIndex);
2824 if (pidl)
2825 {
2826 *ppidl = ILClone(pidl);
2827 return S_OK;
2828 }
2829
2830 *ppidl = 0;
2831 return E_INVALIDARG;
2832}
2833
2835{
2836 TRACE("(%p)->(%u %p)\n", this, uFlags, pcItems);
2837
2838 if (uFlags != SVGIO_ALLVIEW)
2839 FIXME("some flags unsupported, %x\n", uFlags & ~SVGIO_ALLVIEW);
2840
2842
2843 return S_OK;
2844}
2845
2847{
2848 return E_NOTIMPL;
2849}
2850
2852{
2853 TRACE("(%p)->(%p)\n", this, piItem);
2854
2855 *piItem = m_ListView.GetSelectionMark();
2856
2857 return S_OK;
2858}
2859
2861{
2862 TRACE("(%p)->(%p)\n", this, piItem);
2863
2864 *piItem = m_ListView.GetNextItem(-1, LVNI_FOCUSED);
2865
2866 return S_OK;
2867}
2868
2870{
2871 int lvIndex = LV_FindItemByPidl(pidl);
2872 if (lvIndex == -1 || ppt == NULL)
2873 return E_INVALIDARG;
2874
2875 m_ListView.GetItemPosition(lvIndex, ppt);
2876 return S_OK;
2877}
2878
2880{
2881 TRACE("(%p)->(%p)\n", this, ppt);
2882
2883 if (!m_ListView)
2884 return S_FALSE;
2885
2886 if (ppt)
2887 {
2888 SIZE spacing;
2889 m_ListView.GetItemSpacing(spacing);
2890
2891 ppt->x = spacing.cx;
2892 ppt->y = spacing.cy;
2893 }
2894
2895 return S_OK;
2896}
2897
2899{
2900 return E_NOTIMPL;
2901}
2902
2904{
2905 return ((m_ListView.GetStyle() & LVS_AUTOARRANGE) ? S_OK : S_FALSE);
2906}
2907
2909{
2910 DWORD dwExStyle = (DWORD)m_ListView.SendMessage(LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
2911 return ((dwExStyle & LVS_EX_SNAPTOGRID) ? S_OK : S_FALSE);
2912}
2913
2915{
2916 LVITEMW lvItem;
2917
2918 TRACE("(%p)->(%d, %x)\n", this, iItem, dwFlags);
2919
2920 lvItem.state = 0;
2921 lvItem.stateMask = LVIS_SELECTED;
2922
2923 if (dwFlags & SVSI_ENSUREVISIBLE)
2924 m_ListView.EnsureVisible(iItem, 0);
2925
2926 /* all items */
2927 if (dwFlags & SVSI_DESELECTOTHERS)
2929
2930 /* this item */
2931 if (dwFlags & SVSI_SELECT)
2932 lvItem.state |= LVIS_SELECTED;
2933
2934 if (dwFlags & SVSI_FOCUSED)
2935 lvItem.stateMask |= LVIS_FOCUSED;
2936
2937 m_ListView.SetItemState(iItem, lvItem.state, lvItem.stateMask);
2938
2939 if ((dwFlags & SVSI_EDIT) == SVSI_EDIT)
2940 m_ListView.EditLabel(iItem);
2941
2942 return S_OK;
2943}
2944
2946{
2947 /* Reset the selection */
2949
2950 int lvIndex;
2951 for (UINT i = 0 ; i < m_cidl; i++)
2952 {
2953 lvIndex = LV_FindItemByPidl(apidl[i]);
2954 if (lvIndex != -1)
2955 {
2956 SelectItem(lvIndex, dwFlags);
2957 m_ListView.SetItemPosition(lvIndex, &apt[i]);
2958 }
2959 }
2960
2961 return S_OK;
2962}
2963
2964/**********************************************************
2965 * IShellView2 implementation
2966 */
2967
2969{
2970 FIXME("(%p)->(%p, %lu) stub\n", this, view_guid, view_type);
2971 return E_NOTIMPL;
2972}
2973
2975{
2976 return CreateViewWindow3(view_params->psbOwner, view_params->psvPrev,
2977 SV3CVW3_DEFAULT, (FOLDERFLAGS)view_params->pfs->fFlags, (FOLDERFLAGS)view_params->pfs->fFlags,
2978 (FOLDERVIEWMODE)view_params->pfs->ViewMode, view_params->pvid, view_params->prcView, &view_params->hwndView);
2979}
2980
2982{
2983 OLEMENUGROUPWIDTHS omw = { { 0, 0, 0, 0, 0, 0 } };
2984
2985 *hwnd = NULL;
2986
2987 TRACE("(%p)->(shlview=%p shlbrs=%p rec=%p hwnd=%p vmode=%x flags=%x)\n", this, psvPrevious, psb, prcView, hwnd, mode, flags);
2988 if (prcView != NULL)
2989 TRACE("-- left=%i top=%i right=%i bottom=%i\n", prcView->left, prcView->top, prcView->right, prcView->bottom);
2990
2991 /* Validate the Shell Browser */
2992 if (psb == NULL || m_hWnd)
2993 return E_UNEXPECTED;
2994
2995 if (view_flags != SV3CVW3_DEFAULT)
2996 FIXME("unsupported view flags 0x%08x\n", view_flags);
2997
2998 /* Set up the member variables */
2999 m_pShellBrowser = psb;
3002
3003 if (view_id)
3004 {
3005 if (IsEqualIID(*view_id, VID_LargeIcons))
3007 else if (IsEqualIID(*view_id, VID_SmallIcons))
3009 else if (IsEqualIID(*view_id, VID_List))
3011 else if (IsEqualIID(*view_id, VID_Details))
3013 else if (IsEqualIID(*view_id, VID_Thumbnails))
3015 else if (IsEqualIID(*view_id, VID_Tile))
3017 else if (IsEqualIID(*view_id, VID_ThumbStrip))
3019 else
3020 FIXME("Ignoring unrecognized VID %s\n", debugstr_guid(view_id));
3021 }
3022
3023 /* Get our parent window */
3024 m_pShellBrowser->GetWindow(&m_hWndParent);
3025
3026 /* Try to get the ICommDlgBrowserInterface, adds a reference !!! */
3029 {
3030 TRACE("-- CommDlgBrowser\n");
3031 }
3032
3034 if (m_hWnd == NULL)
3035 return E_FAIL;
3036
3037 *hwnd = m_hWnd;
3038
3039 CheckToolbar();
3040
3041 if (!*hwnd)
3042 return E_FAIL;
3043
3045
3047 UpdateWindow();
3048
3049 if (!m_hMenu)
3050 {
3051 m_hMenu = CreateMenu();
3052 m_pShellBrowser->InsertMenusSB(m_hMenu, &omw);
3053 TRACE("-- after fnInsertMenusSB\n");
3054 }
3055
3056 _MergeToolbar();
3057
3058 return S_OK;
3059}
3060
3062{
3063 FIXME("(%p)->(%p) stub\n", this, new_pidl);
3064 return E_NOTIMPL;
3065}
3066
3068{
3069 FIXME("(%p)->(%p, %u, %p) stub\n", this, item, flags, point);
3070 return E_NOTIMPL;
3071}
3072
3073/**********************************************************
3074 * IShellFolderView implementation
3075 */
3077{
3078 FIXME("(%p)->(%ld) stub\n", this, sort);
3079 return E_NOTIMPL;
3080}
3081
3083{
3084 FIXME("(%p)->(%p) stub\n", this, sort);
3085 return E_NOTIMPL;
3086}
3087
3089{
3091 return S_OK;
3092}
3093
3095{
3096 m_ListView.ModifyStyle(0, LVS_AUTOARRANGE);
3098 return S_OK;
3099}
3100
3102{
3103 TRACE("(%p)->(%p %p)\n", this, pidl, item);
3104 *item = LV_AddItem(pidl);
3105 return (int)*item >= 0 ? S_OK : E_OUTOFMEMORY;
3106}
3107
3109{
3110 TRACE("(%p)->(%p %d)\n", this, pidl, item);
3111 return Item(item, pidl);
3112}
3113
3115{
3116
3117 TRACE("(%p)->(%p %p)\n", this, pidl, item);
3118
3119 if (!m_ListView)
3120 return E_FAIL;
3121
3122 if (pidl)
3123 {
3126 }
3127 else
3128 {
3129 *item = 0;
3131 }
3132
3133 return S_OK;
3134}
3135
3137{
3138 TRACE("(%p)->(%p)\n", this, count);
3140 return S_OK;
3141}
3142
3144{
3145 FIXME("(%p)->(%d %x) stub\n", this, count, flags);
3146 return E_NOTIMPL;
3147}
3148
3150{
3151 FIXME("(%p)->(%p %p %p) stub\n", this, pidl_old, pidl_new, item);
3152 return E_NOTIMPL;
3153}
3154
3156{
3157 FIXME("(%p)->(%p %p) stub\n", this, pidl, item);
3158 return E_NOTIMPL;
3159}
3160
3162{
3163 TRACE("(%p)->(%d)\n", this, redraw);
3164 if (m_ListView)
3166 return S_OK;
3167}
3168
3170{
3171 FIXME("(%p)->(%p) stub\n", this, count);
3172 return E_NOTIMPL;
3173}
3174
3176{
3177 TRACE("(%p)->(%p %p)\n", this, pidl, items);
3178
3179 *items = GetSelections();
3180
3181 if (*items)
3182 {
3183 *pidl = static_cast<PCUITEMID_CHILD *>(LocalAlloc(0, *items * sizeof(PCUITEMID_CHILD)));
3184 if (!*pidl)
3185 {
3186 return E_OUTOFMEMORY;
3187 }
3188
3189 /* it's documented that caller shouldn't PIDLs, only array itself */
3190 memcpy(*pidl, m_apidl, *items * sizeof(PCUITEMID_CHILD));
3191 }
3192
3193 return S_OK;
3194}
3195
3197{
3198 if ((m_iDragOverItem == -1 || m_pCurDropTarget == NULL) &&
3200 {
3201 return S_OK;
3202 }
3203
3204 return S_FALSE;
3205}
3206
3208{
3209 if (!pt)
3210 return E_INVALIDARG;
3211
3213 return S_OK;
3214}
3215
3217{
3218 FIXME("(%p)->(%p) stub\n", this, pt);
3219 return E_NOTIMPL;
3220}
3221
3223{
3224 TRACE("(%p)->(%p)\n", this, obj);
3225 return E_NOTIMPL;
3226}
3227
3229{
3230 FIXME("(%p)->(%p %p) stub\n", this, pidl, pt);
3231 return E_NOTIMPL;
3232}
3233
3235{
3236 FIXME("(%p)->(%p) stub\n", this, drop_target);
3237 return E_NOTIMPL;
3238}
3239
3241{
3242 FIXME("(%p)->(%d) stub\n", this, move);
3243 return E_NOTIMPL;
3244}
3245
3247{
3248 FIXME("(%p)->(%p) stub\n", this, obj);
3249 return E_NOTIMPL;
3250}
3251
3253{
3254 FIXME("(%p)->(%p) stub\n", this, spacing);
3255 return E_NOTIMPL;
3256}
3257
3258HRESULT STDMETHODCALLTYPE CDefView::SetCallback(IShellFolderViewCB *new_cb, IShellFolderViewCB **old_cb)
3259{
3260 if (old_cb)
3261 *old_cb = m_pShellFolderViewCB.Detach();
3262
3263 m_pShellFolderViewCB = new_cb;
3264 return S_OK;
3265}
3266
3268{
3269 FIXME("(%p)->(%d) stub\n", this, flags);
3270 return E_NOTIMPL;
3271}
3272
3274{
3275 TRACE("(%p)->(%p)\n", this, support);
3276 return S_OK;
3277}
3278
3280{
3281 FIXME("(%p)->(%p) stub\n", this, disp);
3282 return E_NOTIMPL;
3283}
3284
3285/**********************************************************
3286 * ISVOleCmdTarget_QueryStatus (IOleCommandTarget)
3287 */
3288HRESULT WINAPI CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText)
3289{
3290 FIXME("(%p)->(%p(%s) 0x%08x %p %p\n",
3291 this, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
3292
3293 if (!prgCmds)
3294 return E_INVALIDARG;
3295
3296 for (UINT i = 0; i < cCmds; i++)
3297 {
3298 FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID);
3299 prgCmds[i].cmdf = 0;
3300 }
3301
3302 return OLECMDERR_E_UNKNOWNGROUP;
3303}
3304
3305/**********************************************************
3306 * ISVOleCmdTarget_Exec (IOleCommandTarget)
3307 *
3308 * nCmdID is the OLECMDID_* enumeration
3309 */
3310HRESULT WINAPI CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
3311{
3312 FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n",
3313 this, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut);
3314
3315 if (!pguidCmdGroup)
3316 return OLECMDERR_E_UNKNOWNGROUP;
3317
3318 if (IsEqualCLSID(*pguidCmdGroup, m_Category))
3319 {
3320 if (nCmdID == FCIDM_SHVIEW_AUTOARRANGE)
3321 {
3322 if (V_VT(pvaIn) != VT_INT_PTR)
3323 return OLECMDERR_E_NOTSUPPORTED;
3324
3326 params.cbSize = sizeof(params);
3327 params.rcExclude = *(RECT*) V_INTREF(pvaIn);
3328
3329 if (m_hMenuViewModes)
3330 {
3331 /* Duplicate all but the last two items of the view modes menu */
3332 HMENU hmenuViewPopup = CreatePopupMenu();
3333 Shell_MergeMenus(hmenuViewPopup, m_hMenuViewModes, 0, 0, 0xFFFF, 0);
3334 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION);
3335 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION);
3336 CheckViewMode(hmenuViewPopup);
3337 TrackPopupMenuEx(hmenuViewPopup, TPM_LEFTALIGN | TPM_TOPALIGN, params.rcExclude.left, params.rcExclude.bottom, m_hWndParent, &params);
3338 ::DestroyMenu(hmenuViewPopup);
3339 }
3340
3341 // pvaOut is VT_I4 with value 0x403 (cmd id of the new mode maybe?)
3342 V_VT(pvaOut) = VT_I4;
3343 V_I4(pvaOut) = 0x403;
3344 }
3345 }
3346
3347 if (IsEqualIID(*pguidCmdGroup, CGID_Explorer) &&
3348 (nCmdID == 0x29) &&
3349 (nCmdexecopt == 4) && pvaOut)
3350 return S_OK;
3351
3352 if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView) &&
3353 (nCmdID == 9) &&
3354 (nCmdexecopt == 0))
3355 return 1;
3356
3357 return OLECMDERR_E_UNKNOWNGROUP;
3358}
3359
3360/**********************************************************
3361 * ISVDropTarget implementation
3362 */
3363
3364/******************************************************************************
3365 * drag_notify_subitem [Internal]
3366 *
3367 * Figure out the shellfolder object, which is currently under the mouse cursor
3368 * and notify it via the IDropTarget interface.
3369 */
3370
3371#define SCROLLAREAWIDTH 20
3372
3374{
3375 LONG lResult;
3376 HRESULT hr;
3377 RECT clientRect;
3378
3379 /* The key state on drop doesn't have MK_LBUTTON or MK_RBUTTON because it
3380 reflects the key state after the user released the button, so we need
3381 to remember the last key state when the button was pressed */
3382 m_grfKeyState = grfKeyState;
3383
3384 /* Map from global to client coordinates and query the index of the listview-item, which is
3385 * currently under the mouse cursor. */
3386 LVHITTESTINFO htinfo = {{pt.x, pt.y}, LVHT_ONITEM};
3387 ScreenToClient(&htinfo.pt);
3388 lResult = m_ListView.HitTest(&htinfo);
3389
3390 /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */
3391 ::GetClientRect(m_ListView, &clientRect);
3392 if (htinfo.pt.x == m_ptLastMousePos.x && htinfo.pt.y == m_ptLastMousePos.y &&
3393 (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH ||
3394 htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH ))
3395 {
3396 m_cScrollDelay = (m_cScrollDelay + 1) % 5; /* DragOver is called every 50 ms */
3397 if (m_cScrollDelay == 0)
3398 {
3399 /* Mouse did hover another 250 ms over the scroll-area */
3400 if (htinfo.pt.x < SCROLLAREAWIDTH)
3401 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEUP, 0);
3402
3403 if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH)
3404 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEDOWN, 0);
3405
3406 if (htinfo.pt.y < SCROLLAREAWIDTH)
3407 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEUP, 0);
3408
3409 if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH)
3410 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEDOWN, 0);
3411 }
3412 }
3413 else
3414 {
3415 m_cScrollDelay = 0; /* Reset, if the cursor is not over the listview's scroll-area */
3416 }
3417
3418 m_ptLastMousePos = htinfo.pt;
3420
3421 /* We need to check if we drag the selection over itself */
3422 if (lResult != -1 && m_pSourceDataObject.p != NULL)
3423 {
3424 PCUITEMID_CHILD pidl = _PidlByItem(lResult);
3425
3426 for (UINT i = 0; i < m_cidl; i++)
3427 {
3428 if (pidl == m_apidl[i])
3429 {
3430 /* The item that is being draged is hovering itself. */
3431 lResult = -1;
3432 break;
3433 }
3434 }
3435 }
3436
3437 /* If we are still over the previous sub-item, notify it via DragOver and return. */
3438 if (m_pCurDropTarget && lResult == m_iDragOverItem)
3439 return m_pCurDropTarget->DragOver(grfKeyState, pt, pdwEffect);
3440
3441 /* We've left the previous sub-item, notify it via DragLeave and Release it. */
3442 if (m_pCurDropTarget)
3443 {
3445 if (pidl)
3446 SelectItem(pidl, 0);
3447
3448 m_pCurDropTarget->DragLeave();
3450 }
3451
3452 m_iDragOverItem = lResult;
3453
3454 if (lResult == -1)
3455 {
3456 /* We are not above one of the listview's subitems. Bind to the parent folder's
3457 * DropTarget interface. */
3459 }
3460 else
3461 {
3462 /* Query the relative PIDL of the shellfolder object represented by the currently
3463 * dragged over listview-item ... */
3464 PCUITEMID_CHILD pidl = _PidlByItem(lResult);
3465
3466 /* ... and bind m_pCurDropTarget to the IDropTarget interface of an UIObject of this object */
3467 hr = m_pSFParent->GetUIObjectOf(m_ListView, 1, &pidl, IID_NULL_PPV_ARG(IDropTarget, &m_pCurDropTarget));
3468 }
3469
3471
3472 /* If anything failed, m_pCurDropTarget should be NULL now, which ought to be a save state. */
3473 if (FAILED(hr))
3474 {
3475 *pdwEffect = DROPEFFECT_NONE;
3476 return hr;
3477 }
3478
3479 if (m_iDragOverItem != -1)
3480 {
3481 SelectItem(m_iDragOverItem, SVSI_SELECT);
3482 }
3483
3484 /* Notify the item just entered via DragEnter. */
3485 return m_pCurDropTarget->DragEnter(m_pCurDataObject, grfKeyState, pt, pdwEffect);
3486}
3487
3488HRESULT WINAPI CDefView::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3489{
3490 if (*pdwEffect == DROPEFFECT_NONE)
3491 return S_OK;
3492
3493 /* Get a hold on the data object for later calls to DragEnter on the sub-folders */
3494 m_pCurDataObject = pDataObject;
3495
3496 HRESULT hr = drag_notify_subitem(grfKeyState, pt, pdwEffect);
3497 if (SUCCEEDED(hr))
3498 {
3499 POINT ptClient = {pt.x, pt.y};
3500 ScreenToClient(&ptClient);
3501 ImageList_DragEnter(m_hWnd, ptClient.x, ptClient.y);
3502 }
3503
3504 return hr;
3505}
3506
3508{
3509 POINT ptClient = {pt.x, pt.y};
3510 ScreenToClient(&ptClient);
3511 ImageList_DragMove(ptClient.x, ptClient.y);
3512 return drag_notify_subitem(grfKeyState, pt, pdwEffect);
3513}
3514
3516{
3518
3519 if (m_pCurDropTarget)
3520 {
3521 m_pCurDropTarget->DragLeave();
3523 }
3524
3525 if (m_pCurDataObject != NULL)
3526 {
3528 }
3529
3530 m_iDragOverItem = 0;
3531
3532 return S_OK;
3533}
3534
3536{
3537 RECT rcBound;
3538 INT i, nCount = m_ListView.GetItemCount();
3539 DWORD dwSpacing;
3540 INT dx, dy;
3541 BOOL bSmall = ((m_ListView.GetStyle() & LVS_TYPEMASK) != LVS_ICON);
3542
3543 /* FIXME: LVM_GETORIGIN is broken. See CORE-17266 */
3544 pt.x += m_ListView.GetScrollPos(SB_HORZ);
3545 pt.y += m_ListView.GetScrollPos(SB_VERT);
3546
3547 if (m_ListView.GetStyle() & LVS_ALIGNLEFT)
3548 {
3549 // vertically
3550 for (i = 0; i < nCount; ++i)
3551 {
3552 dwSpacing = ListView_GetItemSpacing(m_ListView, bSmall);
3553 dx = LOWORD(dwSpacing);
3554 dy = HIWORD(dwSpacing);
3556 rcBound.right = rcBound.left + dx;
3557 rcBound.bottom = rcBound.top + dy;
3558 if (pt.x < rcBound.right && pt.y < (rcBound.top + rcBound.bottom) / 2)
3559 {
3560 return i;
3561 }
3562 }
3563 for (i = nCount - 1; i >= 0; --i)
3564 {
3566 if (rcBound.left < pt.x && rcBound.top < pt.y)
3567 {
3568 return i + 1;
3569 }
3570 }
3571 }
3572 else
3573 {
3574 // horizontally
3575 for (i = 0; i < nCount; ++i)
3576 {
3577 dwSpacing = ListView_GetItemSpacing(m_ListView, bSmall);
3578 dx = LOWORD(dwSpacing);
3579 dy = HIWORD(dwSpacing);
3581 rcBound.right = rcBound.left + dx;
3582 rcBound.bottom = rcBound.top + dy;
3583 if (pt.y < rcBound.bottom && pt.x < rcBound.left)
3584 {
3585 return i;
3586 }
3587 if (pt.y < rcBound.bottom && pt.x < rcBound.right)
3588 {
3589 return i + 1;
3590 }
3591 }
3592 for (i = nCount - 1; i >= 0; --i)
3593 {
3595 if (rcBound.left < pt.x && rcBound.top < pt.y)
3596 {
3597 return i + 1;
3598 }
3599 }
3600 }
3601
3602 return nCount;
3603}
3604
3606{
3607 LRESULT lResult;
3608
3610 {
3611 int nPartArray[] = {-1};
3612 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, _countof(nPartArray), (LPARAM)nPartArray, &lResult);
3613 return;
3614 }
3615
3616 int nFileSizePartLength = 125;
3617 const int nLocationPartLength = 150;
3618 const int nRightPartsLength = nFileSizePartLength + nLocationPartLength;
3619 int nObjectsPartLength = nWidth - nRightPartsLength;
3620
3621 /* If the window is small enough just divide each part into thirds
3622 * This is the behavior of Windows Server 2003. */
3623 if (nObjectsPartLength <= nLocationPartLength)
3624 nObjectsPartLength = nFileSizePartLength = nWidth / 3;
3625
3626 int nPartArray[] = {nObjectsPartLength, nObjectsPartLength + nFileSizePartLength, -1};
3627
3628 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, _countof(nPartArray), (LPARAM)nPartArray, &lResult);
3629}
3630
3632{
3633 /* Get the handle for the status bar */
3634 HWND fStatusBar;
3635 m_pShellBrowser->GetControlWindow(FCW_STATUS, &fStatusBar);
3636
3637 /* Get the size of our status bar */
3638 RECT statusBarSize;
3639 ::GetWindowRect(fStatusBar, &statusBarSize);
3640
3641 /* Resize the status bar */
3642 _HandleStatusBarResize(statusBarSize.right - statusBarSize.left);
3643}
3644
3646
3647static INT CALLBACK
3648SelectionMoveCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
3649{
3650 CLParamIndexMap *pmap = (CLParamIndexMap *)lParamSort;
3651 INT i1 = pmap->Lookup(lParam1), i2 = pmap->Lookup(lParam2);
3652 if (i1 < i2)
3653 return -1;
3654 if (i1 > i2)
3655 return 1;
3656 return 0;
3657}
3658
3660{
3661 // get insertable index from position
3663
3664 // create identity mapping of indexes
3666 INT nCount = m_ListView.GetItemCount();
3667 for (INT i = 0; i < nCount; ++i)
3668 {
3669 array.Add(i);
3670 }
3671
3672 // re-ordering mapping
3673 INT iItem = -1;
3674 while ((iItem = m_ListView.GetNextItem(iItem, LVNI_SELECTED)) >= 0)
3675 {
3676 INT iFrom = iItem, iTo = iPosition;
3677 if (iFrom < iTo)
3678 --iTo;
3679 if (iFrom >= nCount)
3680 iFrom = nCount - 1;
3681 if (iTo >= nCount)
3682 iTo = nCount - 1;
3683
3684 // shift indexes by swapping (like a bucket relay)
3685 if (iFrom < iTo)
3686 {
3687 for (INT i = iFrom; i < iTo; ++i)
3688 {
3689 // swap array[i] and array[i + 1]
3690 INT tmp = array[i];
3691 array[i] = array[i + 1];
3692 array[i + 1] = tmp;
3693 }
3694 }
3695 else
3696 {
3697 for (INT i = iFrom; i > iTo; --i)
3698 {
3699 // swap array[i] and array[i - 1]
3700 INT tmp = array[i];
3701 array[i] = array[i - 1];
3702 array[i - 1] = tmp;
3703 }
3704 }
3705 }
3706
3707 // create mapping (ListView's lParam to index) from array
3709 for (INT i = 0; i < nCount; ++i)
3710 {
3712 map.Add(lParam, i);
3713 }
3714
3715 // finally sort
3717}
3718
3719HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3720{
3723
3724 if ((IsDropOnSource(NULL) == S_OK) &&
3725 (*pdwEffect & DROPEFFECT_MOVE) &&
3727 {
3728 if (m_pCurDropTarget)
3729 {
3730 m_pCurDropTarget->DragLeave();
3732 }
3733
3734 POINT ptDrop = { pt.x, pt.y };
3735 ::ScreenToClient(m_ListView, &ptDrop);
3737 m_ptLastMousePos = ptDrop;
3738
3740 if (m_ListView.GetStyle() & LVS_AUTOARRANGE)
3741 {
3743 }
3744 else
3745 {
3746 POINT ptItem;
3747 INT iItem = -1;
3748 while ((iItem = m_ListView.GetNextItem(iItem, LVNI_SELECTED)) >= 0)
3749 {
3750 if (m_ListView.GetItemPosition(iItem, &ptItem))
3751 {
3754 m_ListView.SetItemPosition(iItem, &ptItem);
3755 }
3756 }
3757 }
3759 }
3760 else if (m_pCurDropTarget)
3761 {
3762 m_pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect);
3764 }
3765
3767 m_iDragOverItem = 0;
3768 return S_OK;
3769}
3770
3771/**********************************************************
3772 * ISVDropSource implementation
3773 */
3774
3776{
3777 TRACE("(%p)\n", this);
3778
3779 if (fEscapePressed)
3780 return DRAGDROP_S_CANCEL;
3781 else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON))
3782 return DRAGDROP_S_DROP;
3783 else
3784 return S_OK;
3785}
3786
3788{
3789 TRACE("(%p)\n", this);
3790
3792}
3793
3794/**********************************************************
3795 * ISVViewObject implementation
3796 */
3797
3798HRESULT 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)
3799{
3800 FIXME("Stub: this=%p\n", this);
3801
3802 return E_NOTIMPL;
3803}
3804
3805HRESULT WINAPI CDefView::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet)
3806{
3807 FIXME("Stub: this=%p\n", this);
3808
3809 return E_NOTIMPL;
3810}
3811
3812HRESULT WINAPI CDefView::Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze)
3813{
3814 FIXME("Stub: this=%p\n", this);
3815
3816 return E_NOTIMPL;
3817}
3818
3820{
3821 FIXME("Stub: this=%p\n", this);
3822
3823 return E_NOTIMPL;
3824}
3825
3827{
3828 FIXME("partial stub: %p 0x%08x 0x%08x %p\n", this, aspects, advf, pAdvSink);
3829
3830 /* FIXME: we set the AdviseSink, but never use it to send any advice */
3831 m_pAdvSink = pAdvSink;
3832 m_dwAspects = aspects;
3833 m_dwAdvf = advf;
3834
3835 return S_OK;
3836}
3837
3839{
3840 TRACE("this=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n", this, pAspects, pAdvf, ppAdvSink);
3841
3842 if (ppAdvSink)
3843 {
3844 *ppAdvSink = m_pAdvSink;
3845 m_pAdvSink.p->AddRef();
3846 }
3847
3848 if (pAspects)
3849 *pAspects = m_dwAspects;
3850
3851 if (pAdvf)
3852 *pAdvf = m_dwAdvf;
3853
3854 return S_OK;
3855}
3856
3858{
3859 if (IsEqualIID(guidService, SID_IShellBrowser))
3860 return m_pShellBrowser->QueryInterface(riid, ppvObject);
3861 else if(IsEqualIID(guidService, SID_IFolderView))
3862 return QueryInterface(riid, ppvObject);
3863
3864 return E_NOINTERFACE;
3865}
3866
3868{
3870 HRESULT hr = S_OK;
3871
3872 hr = IUnknown_QueryService(m_pShellBrowser, IID_IExplorerToolbar, IID_PPV_ARG(IExplorerToolbar, &ptb));
3873 if (FAILED(hr))
3874 return hr;
3875
3876 m_Category = CGID_DefViewFrame;
3877
3878 hr = ptb->SetCommandTarget(static_cast<IOleCommandTarget*>(this), &m_Category, 0);
3879 if (FAILED(hr))
3880 return hr;
3881
3882 if (hr == S_FALSE)
3883 return S_OK;
3884
3885#if 0
3886 hr = ptb->AddButtons(&m_Category, buttonsCount, buttons);
3887 if (FAILED(hr))
3888 return hr;
3889#endif
3890
3891 return S_OK;
3892}
3893
3895{
3897
3899 {
3900 hr = m_pShellFolderViewCB->MessageSFVCB(uMsg, wParam, lParam);
3901 }
3902
3903 return hr;
3904}
3905
3907{
3908 return ShellObjectCreatorInit<CDefView>(pFolder, riid, ppvOut);
3909}
3910
3912 LPCSFV psvcbi, /* [in] shelltemplate struct */
3913 IShellView **ppsv) /* [out] IShellView pointer */
3914{
3916 HRESULT hRes;
3917
3918 TRACE("sf=%p pidl=%p cb=%p mode=0x%08x parm=%p\n",
3919 psvcbi->pshf, psvcbi->pidl, psvcbi->pfnCallback,
3920 psvcbi->fvm, psvcbi->psvOuter);
3921
3922 *ppsv = NULL;
3923 hRes = CDefView_CreateInstance(psvcbi->pshf, IID_PPV_ARG(IShellView, &psv));
3924 if (FAILED_UNEXPECTEDLY(hRes))
3925 return hRes;
3926
3927 *ppsv = psv.Detach();
3928 return hRes;
3929}
3930
3932 IShellView **ppsv)
3933{
3935 HRESULT hRes;
3936
3937 if (!ppsv)
3938 return E_INVALIDARG;
3939
3940 *ppsv = NULL;
3941
3942 if (!pcsfv || pcsfv->cbSize != sizeof(*pcsfv))
3943 return E_INVALIDARG;
3944
3945 TRACE("sf=%p outer=%p callback=%p\n",
3946 pcsfv->pshf, pcsfv->psvOuter, pcsfv->psfvcb);
3947
3948 hRes = CDefView_CreateInstance(pcsfv->pshf, IID_PPV_ARG(IShellView, &psv));
3949 if (FAILED(hRes))
3950 return hRes;
3951
3952 if (pcsfv->psfvcb)
3953 {
3955 if (SUCCEEDED(psv->QueryInterface(IID_PPV_ARG(IShellFolderView, &sfv))))
3956 {
3957 sfv->SetCallback(pcsfv->psfvcb, NULL);
3958 }
3959 }
3960
3961 *ppsv = psv.Detach();
3962 return hRes;
3963}
static HDC hDC
Definition: