ReactOS 0.4.15-dev-6679-g945ee4b
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 if (!m_ListView)
549 return;
550
551 cSelectedItems = m_ListView.GetSelectedCount();
552 if (cSelectedItems)
553 {
555 StringCchPrintfW(szPartText, _countof(szPartText), szFormat, cSelectedItems);
556 }
557 else
558 {
559 LoadStringW(shell32_hInstance, IDS_OBJECTS, szFormat, _countof(szFormat));
560 StringCchPrintfW(szPartText, _countof(szPartText), szFormat, m_ListView.GetItemCount());
561 }
562
563 LRESULT lResult;
564 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXT, 0, (LPARAM)szPartText, &lResult);
565
566 /* Don't bother with the extra processing if we only have one StatusBar part. */
568 {
569 DWORD uTotalFileSize = 0;
570 WORD uFileFlags = LVNI_ALL;
571 LPARAM pIcon = NULL;
572 INT nItem = -1;
573 bool bIsOnlyFoldersSelected = true;
574
575 /* If we have something selected then only count selected file sizes. */
576 if (cSelectedItems)
577 {
578 uFileFlags = LVNI_SELECTED;
579 }
580
581 while ((nItem = m_ListView.GetNextItem(nItem, uFileFlags)) >= 0)
582 {
583 PCUITEMID_CHILD pidl = _PidlByItem(nItem);
584
585 uTotalFileSize += _ILGetFileSize(pidl, NULL, 0);
586
587 if (!_ILIsFolder(pidl))
588 {
589 bIsOnlyFoldersSelected = false;
590 }
591 }
592
593 /* Don't show the file size text if there is 0 bytes in the folder
594 * OR we only have folders selected. */
595 if ((cSelectedItems && !bIsOnlyFoldersSelected) || uTotalFileSize)
596 {
597 StrFormatByteSizeW(uTotalFileSize, szPartText, _countof(szPartText));
598 }
599 else
600 {
601 *szPartText = 0;
602 }
603
604 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXT, 1, (LPARAM)szPartText, &lResult);
605
606 /* If we are in a Recycle Bin folder then show no text for the location part. */
608 {
609 LoadStringW(shell32_hInstance, IDS_MYCOMPUTER, szPartText, _countof(szPartText));
610 pIcon = (LPARAM)m_hMyComputerIcon;
611 }
612
613 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETICON, 2, pIcon, &lResult);
614 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXT, 2, (LPARAM)szPartText, &lResult);
615 }
616}
617
618/**********************************************************
619 *
620 * ##### helperfunctions for initializing the view #####
621 */
622
623/**********************************************************
624* ShellView_CreateList()
625*
626* - creates the list view window
627*/
629{
630 HRESULT hr;
631 DWORD dwStyle, dwExStyle;
632 UINT ViewMode;
633
634 TRACE("%p\n", this);
635
638 dwExStyle = WS_EX_CLIENTEDGE;
639
641 dwStyle |= LVS_ALIGNLEFT;
642 else
643 dwStyle |= LVS_ALIGNTOP | LVS_SHOWSELALWAYS;
644
645 ViewMode = m_FolderSettings.ViewMode;
646 hr = _DoFolderViewCB(SFVM_DEFVIEWMODE, 0, (LPARAM)&ViewMode);
647 if (SUCCEEDED(hr))
648 {
649 if (ViewMode >= FVM_FIRST && ViewMode <= FVM_LAST)
650 m_FolderSettings.ViewMode = ViewMode;
651 else
652 ERR("Ignoring invalid ViewMode from SFVM_DEFVIEWMODE: %u (was: %u)\n", ViewMode, m_FolderSettings.ViewMode);
653 }
654
656 {
657 case FVM_ICON:
658 dwStyle |= LVS_ICON;
659 break;
660
661 case FVM_DETAILS:
662 dwStyle |= LVS_REPORT;
663 break;
664
665 case FVM_SMALLICON:
666 dwStyle |= LVS_SMALLICON;
667 break;
668
669 case FVM_LIST:
670 dwStyle |= LVS_LIST;
671 break;
672
673 default:
674 dwStyle |= LVS_LIST;
675 break;
676 }
677
679 dwStyle |= LVS_AUTOARRANGE;
680
682 dwExStyle |= LVS_EX_SNAPTOGRID;
683
686
688 dwStyle |= LVS_SINGLESEL;
689
691 dwExStyle &= ~WS_EX_CLIENTEDGE;
692
693 RECT rcListView = {0,0,0,0};
694 m_ListView.Create(m_hWnd, rcListView, L"FolderView", dwStyle, dwExStyle, ID_LISTVIEW);
695
696 if (!m_ListView)
697 return FALSE;
698
702
703 /* UpdateShellSettings(); */
704 return TRUE;
705}
706
708{
710 {
711 /* Check if drop shadows option is enabled */
712 BOOL bDropShadow = FALSE;
713 DWORD cbDropShadow = sizeof(bDropShadow);
714
715 /*
716 * The desktop ListView always take the default desktop colours, by
717 * remaining transparent and letting user32/win32k paint itself the
718 * desktop background color, if any.
719 */
721
722 SHGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
723 L"ListviewShadow", NULL, &bDropShadow, &cbDropShadow);
724 if (bDropShadow)
725 {
726 /* Set the icon background transparent */
728 m_ListView.SetTextColor(RGB(255, 255, 255));
729 m_ListView.SetExtendedListViewStyle(LVS_EX_TRANSPARENTSHADOWTEXT, LVS_EX_TRANSPARENTSHADOWTEXT);
730 }
731 else
732 {
733 /* Set the icon background as the same colour as the desktop */
735 m_ListView.SetTextBkColor(crDesktop);
736 if (GetRValue(crDesktop) + GetGValue(crDesktop) + GetBValue(crDesktop) > 128 * 3)
737 m_ListView.SetTextColor(RGB(0, 0, 0));
738 else
739 m_ListView.SetTextColor(RGB(255, 255, 255));
740 m_ListView.SetExtendedListViewStyle(0, LVS_EX_TRANSPARENTSHADOWTEXT);
741 }
742 }
743 else
744 {
745 // text background color
747 m_ListView.SetTextBkColor(clrTextBack);
748
749 // text color
750 COLORREF clrText;
752 clrText = m_viewinfo_data.clrText;
753 else
754 clrText = GetSysColor(COLOR_WINDOWTEXT);
755
756 m_ListView.SetTextColor(clrText);
757
758 // Background is painted by the parent via WM_PRINTCLIENT.
759 m_ListView.SetExtendedListViewStyle(LVS_EX_TRANSPARENTBKGND, LVS_EX_TRANSPARENTBKGND);
760 }
761}
762
763/**********************************************************
764* ShellView_InitList()
765*
766* - adds all needed columns to the shellview
767*/
769{
771 WCHAR szTemp[50];
772 HIMAGELIST big_icons, small_icons;
773
774 TRACE("%p\n", this);
775
777
779
780 if (m_pSF2Parent)
781 {
782 for (int i = 0; 1; i++)
783 {
784 if (FAILED(m_pSF2Parent->GetDetailsOf(NULL, i, &sd)))
785 break;
786 StrRetToStrNW( szTemp, 50, &sd.str, NULL);
787 m_ListView.InsertColumn(i, szTemp, sd.fmt, sd.cxChar * 8);
788
789 InsertMenuW(m_hMenuArrangeModes, -1, MF_STRING, 0x30 + i, szTemp);
790 }
791
793 }
794 else
795 {
796 FIXME("no m_pSF2Parent\n");
797 }
798
799 Shell_GetImageLists(&big_icons, &small_icons);
801 m_ListView.SetImageList(small_icons, LVSIL_SMALL);
802
803 return TRUE;
804}
805
806/*************************************************************************
807 * ShellView_ListViewCompareItems
808 *
809 * Compare Function for the Listview (FileOpen Dialog)
810 *
811 * PARAMS
812 * lParam1 [I] the first ItemIdList to compare with
813 * lParam2 [I] the second ItemIdList to compare with
814 * lpData [I] The column ID for the header Ctrl to process
815 *
816 * RETURNS
817 * A negative value if the first item should precede the second,
818 * a positive value if the first item should follow the second,
819 * or zero if the two items are equivalent
820 */
822{
823 PCUIDLIST_RELATIVE pidl1 = reinterpret_cast<PCUIDLIST_RELATIVE>(lParam1);
824 PCUIDLIST_RELATIVE pidl2 = reinterpret_cast<PCUIDLIST_RELATIVE>(lParam2);
825 CDefView *pThis = reinterpret_cast<CDefView*>(lpData);
826
827 HRESULT hres = pThis->m_pSFParent->CompareIDs(pThis->m_sortInfo.nHeaderID, pidl1, pidl2);
829 return 0;
830
831 SHORT nDiff = HRESULT_CODE(hres);
832 if (!pThis->m_sortInfo.bIsAscending)
833 nDiff = -nDiff;
834 return nDiff;
835}
836
838{
839 HWND hHeader;
840 HDITEM hColumn;
841
842 if (m_ListView.GetWindowLongPtr(GWL_STYLE) & LVS_NOSORTHEADER)
843 return TRUE;
844
845 hHeader = (HWND)m_ListView.SendMessage(LVM_GETHEADER, 0, 0);
846 ZeroMemory(&hColumn, sizeof(hColumn));
847
848 /* If the sorting column changed, remove the sorting style from the old column */
849 if ( (m_sortInfo.nLastHeaderID != -1) &&
851 {
852 hColumn.mask = HDI_FORMAT;
853 Header_GetItem(hHeader, m_sortInfo.nLastHeaderID, &hColumn);
854 hColumn.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN);
855 Header_SetItem(hHeader, m_sortInfo.nLastHeaderID, &hColumn);
856 }
857
858 /* Set the sorting style to the new column */
859 hColumn.mask = HDI_FORMAT;
860 Header_GetItem(hHeader, m_sortInfo.nHeaderID, &hColumn);
861
862 hColumn.fmt &= (m_sortInfo.bIsAscending ? ~HDF_SORTDOWN : ~HDF_SORTUP );
863 hColumn.fmt |= (m_sortInfo.bIsAscending ? HDF_SORTUP : HDF_SORTDOWN);
864 Header_SetItem(hHeader, m_sortInfo.nHeaderID, &hColumn);
865
866 /* Sort the list, using the current values of nHeaderID and bIsAscending */
869}
870
872{
873 if (!m_ListView)
874 return nullptr;
875 return reinterpret_cast<PCUITEMID_CHILD>(m_ListView.GetItemData(i));
876}
877
879{
880 if (!m_ListView)
881 return nullptr;
882 return reinterpret_cast<PCUITEMID_CHILD>(lvItem.lParam);
883}
884
885/**********************************************************
886* LV_FindItemByPidl()
887*/
889{
891
892 int cItems = m_ListView.GetItemCount();
893
894 for (int i = 0; i<cItems; i++)
895 {
896 PCUITEMID_CHILD currentpidl = _PidlByItem(i);
897 if (ILIsEqual(pidl, currentpidl))
898 return i;
899 }
900 return -1;
901}
902
903/**********************************************************
904* LV_AddItem()
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 the mask*/
918 lvItem.iItem = m_ListView.GetItemCount(); /*add the item to the end of the list*/
919 lvItem.iSubItem = 0;
920 lvItem.lParam = reinterpret_cast<LPARAM>(ILClone(pidl)); /*set the item's data*/
921 lvItem.pszText = LPSTR_TEXTCALLBACKW; /*get text on a callback basis*/
922 lvItem.iImage = I_IMAGECALLBACK; /*get the image on a callback basis*/
923 lvItem.stateMask = LVIS_CUT;
924
925 return m_ListView.InsertItem(&lvItem);
926}
927
928/**********************************************************
929* LV_DeleteItem()
930*/
932{
933 int nIndex;
934
935 TRACE("(%p)(pidl=%p)\n", this, pidl);
936
938
939 nIndex = LV_FindItemByPidl(pidl);
940 if (nIndex < 0)
941 return FALSE;
942
943 return m_ListView.DeleteItem(nIndex);
944}
945
946/**********************************************************
947* LV_RenameItem()
948*/
950{
951 int nItem;
952 LVITEMW lvItem;
953
954 TRACE("(%p)(pidlold=%p pidlnew=%p)\n", this, pidlOld, pidlNew);
955
957
958 nItem = LV_FindItemByPidl(pidlOld);
959
960 if ( -1 != nItem )
961 {
962 lvItem.mask = LVIF_PARAM; /* only the pidl */
963 lvItem.iItem = nItem;
964 lvItem.iSubItem = 0;
965 m_ListView.GetItem(&lvItem);
966
967 LPVOID oldPidl = reinterpret_cast<LPVOID>(lvItem.lParam); /* Store the old pidl until the new item is replaced */
968
969 lvItem.mask = LVIF_PARAM | LVIF_IMAGE | LVIF_TEXT;
970 lvItem.iItem = nItem;
971 lvItem.iSubItem = 0;
972 lvItem.lParam = reinterpret_cast<LPARAM>(ILClone(pidlNew)); /* set the item's data */
975 m_ListView.SetItem(&lvItem);
976 m_ListView.Update(nItem);
977
978 SHFree(oldPidl); /* Now that the new item is in place, we can safely release the old pidl */
979
980 return TRUE; /* FIXME: better handling */
981 }
982
983 return FALSE;
984}
985
986/**********************************************************
987* LV_ProdItem()
988*/
990{
991 int nItem;
992 LVITEMW lvItem;
993
994 TRACE("(%p)(pidl=%p)\n", this, pidl);
995
997
998 nItem = LV_FindItemByPidl(pidl);
999
1000 if (-1 != nItem)
1001 {
1002 lvItem.mask = LVIF_IMAGE;
1003 lvItem.iItem = nItem;
1004 lvItem.iSubItem = 0;
1006 m_ListView.SetItem(&lvItem);
1007 m_ListView.Update(nItem);
1008 return TRUE;
1009 }
1010
1011 return FALSE;
1012}
1013
1014/**********************************************************
1015* ShellView_FillList()
1016*
1017* - gets the objectlist from the shellfolder
1018* - sorts the list
1019* - fills the list into the view
1020*/
1022{
1023 PITEMID_CHILD pidl = static_cast<PITEMID_CHILD>(ptr);
1024 CDefView *pThis = static_cast<CDefView *>(arg);
1025
1026 /* in a commdlg This works as a filemask*/
1027 if (pThis->IncludeObject(pidl) == S_OK && pThis->m_ListView)
1028 pThis->LV_AddItem(pidl);
1029
1030 SHFree(pidl);
1031 return TRUE;
1032}
1033
1035{
1036 CComPtr<IEnumIDList> pEnumIDList;
1037 PITEMID_CHILD pidl;
1038 DWORD dwFetched;
1039 HRESULT hRes;
1040 HDPA hdpa;
1041 DWORD dFlags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS;
1042 DWORD dwValue, cbValue;
1043
1044 TRACE("%p\n", this);
1045
1046 /* determine if there is a setting to show all the hidden files/folders */
1047 dwValue = 1;
1048 cbValue = sizeof(dwValue);
1050 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
1051 L"Hidden", NULL, &dwValue, &cbValue);
1052 if (dwValue == 1)
1053 {
1054 dFlags |= SHCONTF_INCLUDEHIDDEN;
1055 m_ListView.SendMessageW(LVM_SETCALLBACKMASK, LVIS_CUT, 0);
1056 }
1057
1058 dwValue = 0;
1059 cbValue = sizeof(dwValue);
1061 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
1062 L"ShowSuperHidden", NULL, &dwValue, &cbValue);
1063 if (dwValue)
1064 {
1065 dFlags |= SHCONTF_INCLUDESUPERHIDDEN;
1066 m_ListView.SendMessageW(LVM_SETCALLBACKMASK, LVIS_CUT, 0);
1067 }
1068
1069 /* get the itemlist from the shfolder */
1070 hRes = m_pSFParent->EnumObjects(m_hWnd, dFlags, &pEnumIDList);
1071 if (hRes != S_OK)
1072 {
1073 if (hRes == S_FALSE)
1074 return(NOERROR);
1075 return(hRes);
1076 }
1077
1078 /* create a pointer array */
1079 hdpa = DPA_Create(16);
1080 if (!hdpa)
1081 {
1082 return(E_OUTOFMEMORY);
1083 }
1084
1085 /* copy the items into the array*/
1086 while((S_OK == pEnumIDList->Next(1, &pidl, &dwFetched)) && dwFetched)
1087 {
1088 if (DPA_InsertPtr(hdpa, 0x7fff, pidl) == -1)
1089 {
1090 SHFree(pidl);
1091 }
1092 }
1093
1094 /*turn the listview's redrawing off*/
1096
1097 DPA_DestroyCallback( hdpa, fill_list, this);
1098
1099 /* sort the array */
1100 if (m_pSF2Parent)
1101 {
1102 m_pSF2Parent->GetDefaultColumn(NULL, (ULONG*)&m_sortInfo.nHeaderID, NULL);
1103 }
1104 else
1105 {
1106 FIXME("no m_pSF2Parent\n");
1107 }
1109 _Sort();
1110
1112 {
1115 }
1116
1117 // load custom background image and custom text color
1120
1121 /*turn the listview's redrawing back on and force it to draw*/
1123
1125
1127 {
1128 // redraw now
1129 m_ListView.InvalidateRect(NULL, TRUE);
1130 }
1131
1133
1134 return S_OK;
1135}
1136
1138{
1139 if (m_ListView.IsWindow())
1140 m_ListView.UpdateWindow();
1141 bHandled = FALSE;
1142 return 0;
1143}
1144
1146{
1147 return m_ListView.SendMessageW(uMsg, 0, 0);
1148}
1149
1151{
1152 if (!m_Destroyed)
1153 {
1154 m_Destroyed = TRUE;
1155 if (m_hMenu)
1156 {
1158 m_hMenu = NULL;
1159 }
1162 m_hNotify = NULL;
1165 }
1166 bHandled = FALSE;
1167 return 0;
1168}
1169
1171{
1172 /* redirect to parent */
1175
1176 bHandled = FALSE;
1177 return 0;
1178}
1179
1180static VOID
1182{
1183 INT x0 = prc->left, y0 = prc->top, x1 = prc->right, y1 = prc->bottom;
1184 x0 += dx;
1185 y0 += dy;
1186
1187 HDC hMemDC = CreateCompatibleDC(hDC);
1188 HGDIOBJ hbmOld = SelectObject(hMemDC, hbm);
1189
1190 for (INT y = y0; y < y1; y += nHeight)
1191 {
1192 for (INT x = x0; x < x1; x += nWidth)
1193 {
1194 BitBlt(hDC, x, y, nWidth, nHeight, hMemDC, 0, 0, SRCCOPY);
1195 }
1196 }
1197
1198 SelectObject(hMemDC, hbmOld);
1199 DeleteDC(hMemDC);
1200}
1201
1203{
1204 HDC hDC = (HDC)wParam;
1205
1206 RECT rc;
1208
1210 {
1211 BITMAP bm;
1212 if (::GetObject(m_viewinfo_data.hbmBack, sizeof(BITMAP), &bm))
1213 {
1214 INT dx = -(::GetScrollPos(m_ListView, SB_HORZ) % bm.bmWidth);
1215 INT dy = -(::GetScrollPos(m_ListView, SB_VERT) % bm.bmHeight);
1216 DrawTileBitmap(hDC, &rc, m_viewinfo_data.hbmBack, bm.bmWidth, bm.bmHeight, dx, dy);
1217 }
1218 }
1219 else
1220 {
1222 }
1223
1224 bHandled = TRUE;
1225
1226 return TRUE;
1227}
1228
1230{
1231 /* Update desktop labels color */
1233
1234 /* Forward WM_SYSCOLORCHANGE to common controls */
1235 return m_ListView.SendMessageW(uMsg, 0, 0);
1236}
1237
1239{
1240 return reinterpret_cast<LRESULT>(m_pShellBrowser.p);
1241}
1242
1244{
1245 this->AddRef();
1246 bHandled = FALSE;
1247 return 0;
1248}
1249
1251{
1252 this->Release();
1253}
1254
1255/**********************************************************
1256* ShellView_OnCreate()
1257*/
1259{
1262
1263 TRACE("%p\n", this);
1264
1266 {
1267 if (FAILED(RegisterDragDrop(m_hWnd, pdt)))
1268 ERR("Registering Drag Drop Failed\n");
1269 }
1270
1271 /* register for receiving notifications */
1272 m_pSFParent->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
1273 if (ppf2)
1274 {
1275 ppf2->GetCurFolder(&m_pidlParent);
1276 }
1277
1278 if (CreateList())
1279 {
1280 if (InitList())
1281 {
1282 FillList();
1283 }
1284 }
1285
1287 {
1288 HWND hwndSB;
1289 m_pShellBrowser->GetWindow(&hwndSB);
1291 }
1292
1293 SHChangeNotifyEntry ntreg[1];
1294 ntreg[0].fRecursive = FALSE;
1295 ntreg[0].pidl = m_pidlParent;
1300 1, ntreg);
1301
1302 /* _DoFolderViewCB(SFVM_GETNOTIFY, ?? ??) */
1303
1305
1306 BOOL bPreviousParentSpecial = m_isParentFolderSpecial;
1307
1308 /* A folder is special if it is the Desktop folder,
1309 * a network folder, or a Control Panel folder. */
1312
1313 /* Only force StatusBar part refresh if the state
1314 * changed from the previous folder. */
1315 if (bPreviousParentSpecial != m_isParentFolderSpecial)
1316 {
1317 /* This handles changing StatusBar parts. */
1319 }
1320
1322
1323 return S_OK;
1324}
1325
1326/**********************************************************
1327 * #### Handling of the menus ####
1328 */
1329
1330extern "C" DWORD WINAPI SHMenuIndexFromID(HMENU hMenu, UINT uID);
1331
1333{
1334 MENUITEMINFOW mii = {sizeof(mii), MIIM_SUBMENU};
1335 if (::GetMenuItemInfoW(hmenu, id, FALSE, &mii))
1336 return mii.hSubMenu;
1337
1338 return NULL;
1339}
1340
1341/* ReallyGetMenuItemID returns the id of an item even if it opens a submenu,
1342 GetMenuItemID returns -1 if the specified item opens a submenu */
1344{
1345 MENUITEMINFOW mii = {sizeof(mii), MIIM_ID};
1346 if (::GetMenuItemInfoW(hmenu, i, TRUE, &mii))
1347 return mii.wID;
1348
1349 return UINT_MAX;
1350}
1351
1353{
1355 if (!hFileMenu)
1356 return E_FAIL;
1357
1358 /* Cleanup the items added previously */
1359 for (int i = GetMenuItemCount(hFileMenu) - 1; i >= 0; i--)
1360 {
1361 UINT id = GetMenuItemID(hFileMenu, i);
1362 if (id < FCIDM_BROWSERFIRST || id > FCIDM_BROWSERLAST)
1363 DeleteMenu(hFileMenu, i, MF_BYPOSITION);
1364 }
1365
1366 /* In case we still have this left over, clean it up! */
1367 if (m_pFileMenu)
1368 {
1371 }
1372 /* Store the context menu in m_pFileMenu and keep it in order to invoke the selected command later on */
1375 return hr;
1376
1378
1379 hr = m_pFileMenu->QueryContextMenu(hmenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, 0);
1381 return hr;
1382
1383 // TODO: filter or something
1384
1385 Shell_MergeMenus(hFileMenu, hmenu, 0, 0, 0xFFFF, MM_ADDSEPARATOR | MM_SUBMENUSHAVEIDS);
1386
1388
1389 return S_OK;
1390}
1391
1393{
1395 if (!hEditMenu)
1396 return E_FAIL;
1397
1398 HMENU hmenuContents = ::LoadMenuW(shell32_hInstance, L"MENU_003");
1399 if (!hmenuContents)
1400 return E_FAIL;
1401
1402 Shell_MergeMenus(hEditMenu, hmenuContents, 0, 0, 0xFFFF, 0);
1403
1404 ::DestroyMenu(hmenuContents);
1405
1406 return S_OK;
1407}
1408
1410{
1412 if (!hViewMenu)
1413 return E_FAIL;
1414
1416 if (!m_hMenuViewModes)
1417 return E_FAIL;
1418
1421
1422 return S_OK;
1423}
1424
1426{
1427 /* We only need to fill this once */
1428 if (GetMenuItemID(hmenuArrange, 0) == FCIDM_SHVIEW_AUTOARRANGE)
1429 {
1430 Shell_MergeMenus(hmenuArrange, m_hMenuArrangeModes, 0, 0, 0xFFFF,0);
1431 }
1432
1433 /* Also check the menu item according to which we sort */
1434 CheckMenuRadioItem(hmenuArrange,
1435 0x30,
1436 0x100,
1437 m_sortInfo.nHeaderID + 0x30,
1438 MF_BYCOMMAND);
1439
1441 {
1444 }
1445 else
1446 {
1449
1450 if (GetAutoArrange() == S_OK)
1452 else
1454
1455 if (_GetSnapToGrid() == S_OK)
1457 else
1459 }
1460
1461
1462 return S_OK;
1463}
1464
1466{
1468 {
1469 UINT iItemFirst = FCIDM_SHVIEW_BIGICON;
1470 UINT iItemLast = iItemFirst + FVM_LAST - FVM_FIRST;
1471 UINT iItem = iItemFirst + m_FolderSettings.ViewMode - FVM_FIRST;
1472 CheckMenuRadioItem(hmenuView, iItemFirst, iItemLast, iItem, MF_BYCOMMAND);
1473 }
1474
1475 return S_OK;
1476}
1477
1478/**********************************************************
1479* ShellView_GetSelections()
1480*
1481* - fills the m_apidl list with the selected objects
1482*
1483* RETURNS
1484* number of selected items
1485*/
1487{
1488 SHFree(m_apidl);
1489
1491 m_apidl = static_cast<PCUITEMID_CHILD*>(SHAlloc(m_cidl * sizeof(PCUITEMID_CHILD)));
1492 if (!m_apidl)
1493 {
1494 m_cidl = 0;
1495 return 0;
1496 }
1497
1498 TRACE("-- Items selected =%u\n", m_cidl);
1499
1501
1502 UINT i = 0;
1503 int lvIndex = -1;
1504 while ((lvIndex = m_ListView.GetNextItem(lvIndex, LVNI_SELECTED)) > -1)
1505 {
1506 m_apidl[i] = _PidlByItem(lvIndex);
1507 i++;
1508 if (i == m_cidl)
1509 break;
1510 TRACE("-- selected Item found\n");
1511 }
1512
1513 return m_cidl;
1514}
1515
1517{
1518 CMINVOKECOMMANDINFOEX cmi;
1519
1520 ZeroMemory(&cmi, sizeof(cmi));
1521 cmi.cbSize = sizeof(cmi);
1522 cmi.lpVerb = MAKEINTRESOURCEA(uCommand);
1523 cmi.hwnd = m_hWnd;
1524
1525 if (GetKeyState(VK_SHIFT) & 0x8000)
1526 cmi.fMask |= CMIC_MASK_SHIFT_DOWN;
1527
1528 if (GetKeyState(VK_CONTROL) & 0x8000)
1529 cmi.fMask |= CMIC_MASK_CONTROL_DOWN;
1530
1531 if (pt)
1532 {
1533 cmi.fMask |= CMIC_MASK_PTINVOKE;
1534 cmi.ptInvoke = *pt;
1535 }
1536
1537 HRESULT hr = pCM->InvokeCommand((LPCMINVOKECOMMANDINFO)&cmi);
1538 // Most of our callers will do this, but in case they don't do that (File menu!)
1539 IUnknown_SetSite(pCM, NULL);
1540 pCM.Release();
1541
1543 return hr;
1544
1545 return S_OK;
1546}
1547
1548/**********************************************************
1549 * ShellView_OpenSelectedItems()
1550 */
1552{
1553 HMENU hMenu;
1554 UINT uCommand;
1555 HRESULT hResult;
1556
1558 if (m_cidl == 0)
1559 return S_OK;
1560
1561 hResult = OnDefaultCommand();
1562 if (hResult == S_OK)
1563 return hResult;
1564
1565 hMenu = CreatePopupMenu();
1566 if (!hMenu)
1567 return E_FAIL;
1568
1571 MenuCleanup _(pCM, hMenu);
1572 if (FAILED_UNEXPECTEDLY(hResult))
1573 return hResult;
1574
1575 hResult = pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_DEFAULTONLY);
1576 if (FAILED_UNEXPECTEDLY(hResult))
1577 return hResult;
1578
1579 uCommand = GetMenuDefaultItem(hMenu, FALSE, 0);
1580 if (uCommand == (UINT)-1)
1581 {
1582 ERR("GetMenuDefaultItem returned -1\n");
1583 return E_FAIL;
1584 }
1585
1586 InvokeContextMenuCommand(pCM, uCommand, NULL);
1587
1588 return hResult;
1589}
1590
1591/**********************************************************
1592 * ShellView_DoContextMenu()
1593 */
1595{
1596 POINT pt;
1597 UINT uCommand;
1598 HRESULT hResult;
1599
1600 TRACE("(%p)\n", this);
1601
1602 if (m_hContextMenu != NULL)
1603 {
1604 ERR("HACK: Aborting context menu in nested call!\n");
1605 return 0;
1606 }
1607
1609 if (!m_hContextMenu)
1610 return E_FAIL;
1611
1612 if (lParam != ~0) // unless app key (menu key) was pressed
1613 {
1614 pt.x = GET_X_LPARAM(lParam);
1615 pt.y = GET_Y_LPARAM(lParam);
1616
1617 LV_HITTESTINFO hittest = { pt };
1618 ScreenToClient(&hittest.pt);
1619 m_ListView.HitTest(&hittest);
1620
1621 // Right-Clicked item is selected? If selected, no selection change.
1622 // If not selected, then reset the selection and select the item.
1623 if ((hittest.flags & LVHT_ONITEM) &&
1625 {
1626 SelectItem(hittest.iItem, SVSI_SELECT | SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE);
1627 }
1628 }
1629
1631 /* In case we still have this left over, clean it up! */
1634 if (FAILED_UNEXPECTEDLY(hResult))
1635 return 0;
1636
1637 /* Use 1 as the first id as we want 0 the mean that the user canceled the menu */
1638 hResult = m_pCM->QueryContextMenu(m_hContextMenu, 0, CONTEXT_MENU_BASE_ID, FCIDM_SHVIEWLAST, CMF_NORMAL);
1639 if (FAILED_UNEXPECTEDLY(hResult))
1640 return 0;
1641
1642 /* There is no position requested, so try to find one */
1643 if (lParam == ~0)
1644 {
1645 HWND hFocus = ::GetFocus();
1646 int lvIndex = -1;
1647
1648 if (hFocus == m_ListView.m_hWnd || m_ListView.IsChild(hFocus))
1649 {
1650 /* Is there an item focused and selected? */
1652 /* If not, find the first selected item */
1653 if (lvIndex < 0)
1654 lvIndex = m_ListView.GetNextItem(-1, LVIS_SELECTED);
1655 }
1656
1657 /* We got something */
1658 if (lvIndex > -1)
1659 {
1660 /* Let's find the center of the icon */
1661 RECT rc = { LVIR_ICON };
1662 m_ListView.SendMessage(LVM_GETITEMRECT, lvIndex, (LPARAM)&rc);
1663 pt.x = (rc.right + rc.left) / 2;
1664 pt.y = (rc.bottom + rc.top) / 2;
1665 }
1666 else
1667 {
1668 /* We have to drop it somewhere.. */
1669 pt.x = pt.y = 0;
1670 }
1671
1672 m_ListView.ClientToScreen(&pt);
1673 }
1674
1675 // This runs the message loop, calling back to us with f.e. WM_INITPOPUP (hence why m_hContextMenu and m_pCM exist)
1676 uCommand = TrackPopupMenu(m_hContextMenu,
1678 pt.x, pt.y, 0, m_hWnd, NULL);
1679 if (uCommand == 0)
1680 return 0;
1681
1682 if (uCommand == FCIDM_SHVIEW_OPEN && OnDefaultCommand() == S_OK)
1683 return 0;
1684
1686
1687 return 0;
1688}
1689
1691{
1692 HRESULT hResult;
1693 HMENU hMenu = NULL;
1694
1696 hResult = GetItemObject( bUseSelection ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &pCM));
1697 if (FAILED_UNEXPECTEDLY(hResult))
1698 return 0;
1699
1700 MenuCleanup _(pCM, hMenu);
1701
1702 if ((uCommand != FCIDM_SHVIEW_DELETE) && (uCommand != FCIDM_SHVIEW_RENAME))
1703 {
1704 hMenu = CreatePopupMenu();
1705 if (!hMenu)
1706 return 0;
1707
1708 hResult = pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_NORMAL);
1709 if (FAILED_UNEXPECTEDLY(hResult))
1710 return 0;
1711 }
1712
1713 if (bUseSelection)
1714 {
1715 // FIXME: we should cache this....
1716 SFGAOF rfg = SFGAO_BROWSABLE | SFGAO_CANCOPY | SFGAO_CANLINK | SFGAO_CANMOVE | SFGAO_CANDELETE | SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSTEM | SFGAO_FOLDER;
1717 hResult = m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &rfg);
1718 if (FAILED_UNEXPECTEDLY(hResult))
1719 return 0;
1720
1721 if (!(rfg & SFGAO_CANMOVE) && uCommand == FCIDM_SHVIEW_CUT)
1722 return 0;
1723 if (!(rfg & SFGAO_CANCOPY) && uCommand == FCIDM_SHVIEW_COPY)
1724 return 0;
1725 if (!(rfg & SFGAO_CANDELETE) && uCommand == FCIDM_SHVIEW_DELETE)
1726 return 0;
1727 if (!(rfg & SFGAO_CANRENAME) && uCommand == FCIDM_SHVIEW_RENAME)
1728 return 0;
1729 if (!(rfg & SFGAO_HASPROPSHEET) && uCommand == FCIDM_SHVIEW_PROPERTIES)
1730 return 0;
1731 }
1732
1733 // FIXME: We should probably use the objects position?
1734 InvokeContextMenuCommand(pCM, uCommand, NULL);
1735 return 0;
1736}
1737
1738/**********************************************************
1739 * ##### message handling #####
1740 */
1741
1742/**********************************************************
1743* ShellView_OnSize()
1744*/
1746{
1747 WORD wWidth, wHeight;
1748
1749 wWidth = LOWORD(lParam);
1750 wHeight = HIWORD(lParam);
1751
1752 TRACE("%p width=%u height=%u\n", this, wWidth, wHeight);
1753
1754 // WM_SIZE can come before WM_CREATE
1755 if (!m_ListView)
1756 return 0;
1757
1758 /* Resize the ListView to fit our window */
1759 ::MoveWindow(m_ListView, 0, 0, wWidth, wHeight, TRUE);
1760
1762
1763 _HandleStatusBarResize(wWidth);
1765
1766 return 0;
1767}
1768
1769/**********************************************************
1770* ShellView_OnDeactivate()
1771*
1772* NOTES
1773* internal
1774*/
1776{
1777 TRACE("%p\n", this);
1778
1780 {
1781 // TODO: cleanup menu after deactivation
1782
1784 }
1785}
1786
1788{
1789 TRACE("%p uState=%x\n", this, uState);
1790
1791 /*don't do anything if the state isn't really changing */
1792 if (m_uState == uState)
1793 {
1794 return;
1795 }
1796
1797 if (uState == SVUIA_DEACTIVATE)
1798 {
1799 OnDeactivate();
1800 }
1801 else
1802 {
1804 {
1805 FillEditMenu();
1806 FillViewMenu();
1807 m_pShellBrowser->SetMenuSB(m_hMenu, 0, m_hWnd);
1809 }
1810
1811 if (SVUIA_ACTIVATE_FOCUS == uState)
1812 {
1813 m_ListView.SetFocus();
1814 }
1815 }
1816
1817 m_uState = uState;
1818 TRACE("--\n");
1819}
1820
1821/**********************************************************
1822* ShellView_OnActivate()
1823*/
1825{
1827 return 0;
1828}
1829
1830/**********************************************************
1831* ShellView_OnSetFocus()
1832*
1833*/
1835{
1836 TRACE("%p\n", this);
1837
1838 /* Tell the browser one of our windows has received the focus. This
1839 should always be done before merging menus (OnActivate merges the
1840 menus) if one of our windows has the focus.*/
1841
1842 m_pShellBrowser->OnViewWindowActive(this);
1844
1845 /* Set the focus to the listview */
1846 m_ListView.SetFocus();
1847
1848 /* Notify the ICommDlgBrowser interface */
1849 OnStateChange(CDBOSC_SETFOCUS);
1850
1851 return 0;
1852}
1853
1854/**********************************************************
1855* ShellView_OnKillFocus()
1856*/
1858{
1859 TRACE("(%p) stub\n", this);
1860
1862 /* Notify the ICommDlgBrowser */
1863 OnStateChange(CDBOSC_KILLFOCUS);
1864
1865 return 0;
1866}
1867
1868/**********************************************************
1869* ShellView_OnCommand()
1870*
1871* NOTES
1872* the CmdID's are the ones from the context menu
1873*/
1875{
1876 DWORD dwCmdID;
1877 DWORD dwCmd;
1878 HWND hwndCmd;
1879 int nCount;
1880
1881 dwCmdID = GET_WM_COMMAND_ID(wParam, lParam);
1883 hwndCmd = GET_WM_COMMAND_HWND(wParam, lParam);
1884
1885 TRACE("(%p)->(0x%08x 0x%08x %p) stub\n", this, dwCmdID, dwCmd, hwndCmd);
1886
1887 switch (dwCmdID)
1888 {
1892 CheckToolbar();
1893 break;
1894
1897 m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_ICON);
1898 CheckToolbar();
1899 break;
1900
1903 m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_LIST);
1904 CheckToolbar();
1905 break;
1906
1909 m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_REPORT);
1910 CheckToolbar();
1911 break;
1912
1913 /* the menu-ID's for sorting are 0x30... see shrec.rc */
1914 case 0x30:
1915 case 0x31:
1916 case 0x32:
1917 case 0x33:
1918 m_sortInfo.nHeaderID = dwCmdID - 0x30;
1920 _Sort();
1921 break;
1922
1925 break;
1927 if (_GetSnapToGrid() == S_OK)
1929 else
1930 ArrangeGrid();
1931 break;
1933 if (GetAutoArrange() == S_OK)
1934 m_ListView.ModifyStyle(LVS_AUTOARRANGE, 0);
1935 else
1936 AutoArrange();
1937 break;
1940 break;
1941
1943 nCount = m_ListView.GetItemCount();
1944 for (int i=0; i < nCount; i++)
1946 break;
1947
1949 Refresh();
1950 break;
1951
1953 case FCIDM_SHVIEW_CUT:
1954 case FCIDM_SHVIEW_COPY:
1960 return 0;
1961
1962 return OnExplorerCommand(dwCmdID, TRUE);
1963
1965 case FCIDM_SHVIEW_UNDO:
1968 return OnExplorerCommand(dwCmdID, FALSE);
1969 default:
1970 /* WM_COMMAND messages from the file menu are routed to the CDefView so as to let m_pFileMenu handle the command */
1971 if (m_pFileMenu && dwCmd == 0)
1972 {
1973 HMENU Dummy = NULL;
1974 MenuCleanup _(m_pFileMenu, Dummy);
1976 }
1977 }
1978
1979 return 0;
1980}
1981
1982static BOOL
1984{
1985 HKEY hKey;
1986 LONG error;
1987 DWORD dwValue = FALSE, cbValue;
1988
1990 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer",
1991 0, KEY_READ, &hKey);
1992 if (error)
1993 return dwValue;
1994
1995 cbValue = sizeof(dwValue);
1996 RegQueryValueExW(hKey, L"SelectExtOnRename", NULL, NULL, (LPBYTE)&dwValue, &cbValue);
1997
1999 return !!dwValue;
2000}
2001
2002/**********************************************************
2003* ShellView_OnNotify()
2004*/
2005
2007{
2008 UINT CtlID;
2009 LPNMHDR lpnmh;
2010 LPNMLISTVIEW lpnmlv;
2011 NMLVDISPINFOW *lpdi;
2012 PCUITEMID_CHILD pidl;
2013 BOOL unused;
2014
2015 CtlID = wParam;
2016 lpnmh = (LPNMHDR)lParam;
2017 lpnmlv = (LPNMLISTVIEW)lpnmh;
2018 lpdi = (NMLVDISPINFOW *)lpnmh;
2019
2020 TRACE("%p CtlID=%u lpnmh->code=%x\n", this, CtlID, lpnmh->code);
2021
2022 switch (lpnmh->code)
2023 {
2024 case NM_SETFOCUS:
2025 TRACE("-- NM_SETFOCUS %p\n", this);
2026 OnSetFocus(0, 0, 0, unused);
2027 break;
2028
2029 case NM_KILLFOCUS:
2030 TRACE("-- NM_KILLFOCUS %p\n", this);
2031 OnDeactivate();
2032 /* Notify the ICommDlgBrowser interface */
2033 OnStateChange(CDBOSC_KILLFOCUS);
2034 break;
2035
2036 case NM_CUSTOMDRAW:
2037 TRACE("-- NM_CUSTOMDRAW %p\n", this);
2038 return CDRF_DODEFAULT;
2039
2040 case NM_RELEASEDCAPTURE:
2041 TRACE("-- NM_RELEASEDCAPTURE %p\n", this);
2042 break;
2043
2044 case NM_CLICK:
2045 TRACE("-- NM_CLICK %p\n", this);
2046 break;
2047
2048 case NM_RCLICK:
2049 TRACE("-- NM_RCLICK %p\n", this);
2050 break;
2051
2052 case NM_DBLCLK:
2053 TRACE("-- NM_DBLCLK %p\n", this);
2055 break;
2056
2057 case NM_RETURN:
2058 TRACE("-- NM_RETURN %p\n", this);
2060 break;
2061
2062 case HDN_ENDTRACKW:
2063 TRACE("-- HDN_ENDTRACKW %p\n", this);
2064 /*nColumn1 = m_ListView.GetColumnWidth(0);
2065 nColumn2 = m_ListView.GetColumnWidth(1);*/
2066 break;
2067
2068 case LVN_DELETEITEM:
2069 TRACE("-- LVN_DELETEITEM %p\n", this);
2070
2071 /*delete the pidl because we made a copy of it*/
2072 SHFree(reinterpret_cast<LPVOID>(lpnmlv->lParam));
2073
2074 break;
2075
2076 case LVN_DELETEALLITEMS:
2077 TRACE("-- LVN_DELETEALLITEMS %p\n", this);
2078 return FALSE;
2079
2080 case LVN_INSERTITEM:
2081 TRACE("-- LVN_INSERTITEM (STUB)%p\n", this);
2082 break;
2083
2084 case LVN_ITEMACTIVATE:
2085 TRACE("-- LVN_ITEMACTIVATE %p\n", this);
2086 OnStateChange(CDBOSC_SELCHANGE); /* the browser will get the IDataObject now */
2087 break;
2088
2089 case LVN_COLUMNCLICK:
2090 m_sortInfo.nHeaderID = lpnmlv->iSubItem;
2093 else
2095 _Sort();
2096 break;
2097
2098 case LVN_GETDISPINFOA:
2099 case LVN_GETDISPINFOW:
2100 TRACE("-- LVN_GETDISPINFO %p\n", this);
2101 pidl = _PidlByItem(lpdi->item);
2102
2103 if (lpdi->item.mask & LVIF_TEXT) /* text requested */
2104 {
2105 if (m_pSF2Parent)
2106 {
2108 if (FAILED_UNEXPECTEDLY(m_pSF2Parent->GetDetailsOf(pidl, lpdi->item.iSubItem, &sd)))
2109 break;
2110
2111 if (lpnmh->code == LVN_GETDISPINFOA)
2112 {
2113 /* shouldn't happen */
2114 NMLVDISPINFOA *lpdiA = (NMLVDISPINFOA *)lpnmh;
2115 StrRetToStrNA( lpdiA->item.pszText, lpdiA->item.cchTextMax, &sd.str, NULL);
2116 TRACE("-- text=%s\n", lpdiA->item.pszText);
2117 }
2118 else /* LVN_GETDISPINFOW */
2119 {
2120 StrRetToStrNW( lpdi->item.pszText, lpdi->item.cchTextMax, &sd.str, NULL);
2121 TRACE("-- text=%s\n", debugstr_w(lpdi->item.pszText));
2122 }
2123 }
2124 else
2125 {
2126 FIXME("no m_pSF2Parent\n");
2127 }
2128 }
2129 if(lpdi->item.mask & LVIF_IMAGE) /* image requested */
2130 {
2132 }
2133 if(lpdi->item.mask & LVIF_STATE)
2134 {
2135 ULONG attributes = SFGAO_HIDDEN;
2136 if (SUCCEEDED(m_pSFParent->GetAttributesOf(1, &pidl, &attributes)))
2137 {
2138 if (attributes & SFGAO_HIDDEN)
2139 {
2140 lpdi->item.state |= LVIS_CUT;
2141 }
2142 }
2143 }
2144 lpdi->item.mask |= LVIF_DI_SETITEM;
2145 break;
2146
2147 case LVN_ITEMCHANGED:
2148 TRACE("-- LVN_ITEMCHANGED %p\n", this);
2149 OnStateChange(CDBOSC_SELCHANGE); /* the browser will get the IDataObject now */
2151 _DoFolderViewCB(SFVM_SELECTIONCHANGED, NULL/* FIXME */, NULL/* FIXME */);
2152 break;
2153
2154 case LVN_BEGINDRAG:
2155 case LVN_BEGINRDRAG:
2156 TRACE("-- LVN_BEGINDRAG\n");
2157
2158 if (GetSelections())
2159 {
2161 DWORD dwAttributes = SFGAO_CANCOPY | SFGAO_CANLINK;
2162 DWORD dwEffect = DROPEFFECT_MOVE;
2163
2164 if (SUCCEEDED(m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, IID_NULL_PPV_ARG(IDataObject, &pda))))
2165 {
2167
2168 if (SUCCEEDED(m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &dwAttributes)))
2169 {
2170 dwEffect |= dwAttributes & (SFGAO_CANCOPY | SFGAO_CANLINK);
2171 }
2172
2174 if (SUCCEEDED(pda->QueryInterface(IID_PPV_ARG(IAsyncOperation, &piaso))))
2175 {
2176 piaso->SetAsyncMode(TRUE);
2177 }
2178
2179 DWORD dwEffect2;
2180
2181 m_pSourceDataObject = pda;
2182 m_ptFirstMousePos = params->ptAction;
2185
2186 HIMAGELIST big_icons, small_icons;
2187 Shell_GetImageLists(&big_icons, &small_icons);
2188 PCUITEMID_CHILD pidl = _PidlByItem(params->iItem);
2189 int iIcon = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
2190 POINT ptItem;
2191 m_ListView.GetItemPosition(params->iItem, &ptItem);
2192
2193 ImageList_BeginDrag(big_icons, iIcon, params->ptAction.x - ptItem.x, params->ptAction.y - ptItem.y);
2194
2195 DoDragDrop(pda, this, dwEffect, &dwEffect2);
2196
2198 }
2199 }
2200 break;
2201
2203 {
2204 DWORD dwAttr = SFGAO_CANRENAME;
2205 pidl = _PidlByItem(lpdi->item);
2206
2207 TRACE("-- LVN_BEGINLABELEDITW %p\n", this);
2208
2209 m_pSFParent->GetAttributesOf(1, &pidl, &dwAttr);
2210 if (SFGAO_CANRENAME & dwAttr)
2211 {
2212 HWND hEdit = reinterpret_cast<HWND>(m_ListView.SendMessage(LVM_GETEDITCONTROL));
2214
2215 /* smartass-renaming: See CORE-15242 */
2216 if (!(dwAttr & SFGAO_FOLDER) && (dwAttr & SFGAO_FILESYSTEM) &&
2217 (lpdi->item.mask & LVIF_TEXT) && !SelectExtOnRename())
2218 {
2219 WCHAR szFullPath[MAX_PATH];
2220 PIDLIST_ABSOLUTE pidlFull = ILCombine(m_pidlParent, pidl);
2221 SHGetPathFromIDListW(pidlFull, szFullPath);
2222
2223 if (!SHELL_FS_HideExtension(szFullPath))
2224 {
2225 LPWSTR pszText = lpdi->item.pszText;
2226 LPWSTR pchDotExt = PathFindExtensionW(pszText);
2227 ::PostMessageW(hEdit, EM_SETSEL, 0, pchDotExt - pszText);
2229 }
2230
2231 ILFree(pidlFull);
2232 }
2233
2234 m_isEditing = TRUE;
2235 return FALSE;
2236 }
2237
2238 return TRUE;
2239 }
2240
2241 case LVN_ENDLABELEDITW:
2242 {
2243 TRACE("-- LVN_ENDLABELEDITW %p\n", this);
2244
2246
2247 if (lpdi->item.pszText)
2248 {
2249 HRESULT hr;
2250 LVITEMW lvItem;
2251
2252 pidl = _PidlByItem(lpdi->item);
2253 PITEMID_CHILD pidlNew = NULL;
2254 hr = m_pSFParent->SetNameOf(0, pidl, lpdi->item.pszText, SHGDN_INFOLDER, &pidlNew);
2255
2256 if (SUCCEEDED(hr) && pidlNew)
2257 {
2258 lvItem.mask = LVIF_PARAM|LVIF_IMAGE;
2259 lvItem.iItem = lpdi->item.iItem;
2260 lvItem.iSubItem = 0;
2261 lvItem.lParam = reinterpret_cast<LPARAM>(pidlNew);
2263 m_ListView.SetItem(&lvItem);
2264 m_ListView.Update(lpdi->item.iItem);
2265 return TRUE;
2266 }
2267 }
2268
2269 return FALSE;
2270 }
2271
2272 default:
2273 TRACE("-- %p WM_COMMAND %x unhandled\n", this, lpnmh->code);
2274 break;
2275 }
2276
2277 return 0;
2278}
2279
2280/*
2281 * This is just a quick hack to make the desktop work correctly.
2282 * ITranslateShellChangeNotify's IsChildID is undocumented, but most likely the way that
2283 * a folder should know if it should update upon a change notification.
2284 * It is exported by merged folders at a minimum.
2285 */
2287{
2288 if (!pidl1 || !pidl2)
2289 return FALSE;
2290 if (ILIsParent(pidl1, pidl2, TRUE))
2291 return TRUE;
2292
2293 if (_ILIsDesktop(pidl1))
2294 {
2295 PIDLIST_ABSOLUTE deskpidl;
2297 if (ILIsParent(deskpidl, pidl2, TRUE))
2298 {
2299 ILFree(deskpidl);
2300 return TRUE;
2301 }
2302 ILFree(deskpidl);
2304 if (ILIsParent(deskpidl, pidl2, TRUE))
2305 {
2306 ILFree(deskpidl);
2307 return TRUE;
2308 }
2309 ILFree(deskpidl);
2310 }
2311
2312 WCHAR szPath1[MAX_PATH], szPath2[MAX_PATH];
2313 LPITEMIDLIST pidl2Clone = ILClone(pidl2);
2314 ILRemoveLastID(pidl2Clone);
2315 if (SHGetPathFromIDListW(pidl1, szPath1) &&
2316 SHGetPathFromIDListW(pidl2Clone, szPath2))
2317 {
2318 if (lstrcmpiW(szPath1, szPath2) == 0)
2319 {
2320 ILFree(pidl2Clone);
2321 return TRUE;
2322 }
2323 }
2324 ILFree(pidl2Clone);
2325
2326 return FALSE;
2327}
2328
2329/**********************************************************
2330* ShellView_OnChange()
2331*/
2333{
2334 // The change notify can come before WM_CREATE.
2335 if (!m_ListView)
2336 return FALSE;
2337
2338 HANDLE hChange = (HANDLE)wParam;
2339 DWORD dwProcID = (DWORD)lParam;
2340 PIDLIST_ABSOLUTE *Pidls;
2341 LONG lEvent;
2342 HANDLE hLock = SHChangeNotification_Lock(hChange, dwProcID, &Pidls, &lEvent);
2343 if (hLock == NULL)
2344 {
2345 ERR("hLock == NULL\n");
2346 return FALSE;
2347 }
2348
2349 BOOL bParent0 = ILIsParentOrSpecialParent(m_pidlParent, Pidls[0]);
2350 BOOL bParent1 = ILIsParentOrSpecialParent(m_pidlParent, Pidls[1]);
2351
2352 TRACE("(%p)(%p,%p,0x%08x)\n", this, Pidls[0], Pidls[1], lParam);
2353
2354 lEvent &= ~SHCNE_INTERRUPT;
2355 switch (lEvent)
2356 {
2357 case SHCNE_MKDIR:
2358 case SHCNE_CREATE:
2359 if (bParent0)
2360 {
2361 if (LV_FindItemByPidl(ILFindLastID(Pidls[0])) == -1)
2362 {
2363 LV_AddItem(ILFindLastID(Pidls[0]));
2364 }
2365 else
2366 {
2367 LV_ProdItem(ILFindLastID(Pidls[0]));
2368 }
2369 }
2370 break;
2371
2372 case SHCNE_RMDIR:
2373 case SHCNE_DELETE:
2374 if (bParent0)
2375 LV_DeleteItem(ILFindLastID(Pidls[0]));
2376 break;
2377
2378 case SHCNE_RENAMEFOLDER:
2379 case SHCNE_RENAMEITEM:
2380 if (bParent0 && bParent1)
2381 LV_RenameItem(ILFindLastID(Pidls[0]), ILFindLastID(Pidls[1]));
2382 else if (bParent0)
2383 LV_DeleteItem(ILFindLastID(Pidls[0]));
2384 else if (bParent1)
2385 LV_AddItem(ILFindLastID(Pidls[1]));
2386 break;
2387
2388 case SHCNE_UPDATEITEM:
2389 if (bParent0)
2390 LV_RenameItem(ILFindLastID(Pidls[0]), ILFindLastID(Pidls[0]));
2391 break;
2392
2393 case SHCNE_UPDATEDIR:
2394 Refresh();
2395 break;
2396 }
2397
2399 return TRUE;
2400}
2401
2404
2405/**********************************************************
2406* CDefView::OnCustomItem
2407*/
2409{
2410 if (!m_pCM)
2411 {
2412 /* no menu */
2413 ERR("no context menu!!!\n");
2414 return FALSE;
2415 }
2416
2417 /* The lParam of WM_DRAWITEM WM_MEASUREITEM contain a menu id and this also needs to
2418 be changed to a menu identifier offset */
2419 UINT CmdID;
2420 HRESULT hres = SHGetMenuIdFromMenuMsg(uMsg, lParam, &CmdID);
2421 if (SUCCEEDED(hres))
2423
2424 /* Forward the message to the IContextMenu2 */
2427
2428 return (SUCCEEDED(hres));
2429}
2430
2432{
2433 /* Wallpaper setting affects drop shadows effect */
2434 if (wParam == SPI_SETDESKWALLPAPER || wParam == 0)
2436
2437 return S_OK;
2438}
2439
2440/**********************************************************
2441* CDefView::OnInitMenuPopup
2442*/
2444{
2445 HMENU hmenu = (HMENU) wParam;
2446 int nPos = LOWORD(lParam);
2447 UINT menuItemId;
2448
2449 if (m_pCM)
2450 {
2451 OnCustomItem(uMsg, wParam, lParam, bHandled);
2452 }
2453
2455
2456 if (GetSelections() == 0)
2457 {
2464 }
2465 else
2466 {
2467 // FIXME: Check copyable
2474 }
2475
2476 /* Lets try to find out what the hell wParam is */
2477 if (hmenu == GetSubMenu(m_hMenu, nPos))
2478 menuItemId = ReallyGetMenuItemID(m_hMenu, nPos);
2479 else if (hViewMenu && hmenu == GetSubMenu(hViewMenu, nPos))
2480 menuItemId = ReallyGetMenuItemID(hViewMenu, nPos);
2481 else if (m_hContextMenu && hmenu == GetSubMenu(m_hContextMenu, nPos))
2482 menuItemId = ReallyGetMenuItemID(m_hContextMenu, nPos);
2483 else
2484 return FALSE;
2485
2486 switch (menuItemId)
2487 {
2488 case FCIDM_MENU_FILE:
2489 FillFileMenu();
2490 break;
2491 case FCIDM_MENU_VIEW:
2492 case FCIDM_SHVIEW_VIEW:
2494 break;
2497 break;
2498 }
2499
2500 return FALSE;
2501}
2502
2503/**********************************************************
2504*
2505*
2506* The INTERFACE of the IShellView object
2507*
2508*
2509**********************************************************
2510*/
2511
2512/**********************************************************
2513* ShellView_GetWindow
2514*/
2516{
2517 TRACE("(%p)\n", this);
2518
2519 *phWnd = m_hWnd;
2520
2521 return S_OK;
2522}
2523
2525{
2526 FIXME("(%p) stub\n", this);
2527
2528 return E_NOTIMPL;
2529}
2530
2531/**********************************************************
2532* IShellView_TranslateAccelerator
2533*
2534* FIXME:
2535* use the accel functions
2536*/
2538{
2539 if (m_isEditing)
2540 return S_FALSE;
2541
2542 if (lpmsg->message >= WM_KEYFIRST && lpmsg->message <= WM_KEYLAST)
2543 {
2544 if (::TranslateAcceleratorW(m_hWnd, m_hAccel, lpmsg) != 0)
2545 return S_OK;
2546
2547 TRACE("-- key=0x%04lx\n", lpmsg->wParam) ;
2548 }
2549
2550 return m_pShellBrowser->TranslateAcceleratorSB(lpmsg, 0);
2551}
2552
2554{
2555 FIXME("(%p) stub\n", this);
2556
2557 return E_NOTIMPL;
2558}
2559
2561{
2562 TRACE("(%p)->(state=%x) stub\n", this, uState);
2563
2564 /* don't do anything if the state isn't really changing */
2565 if (m_uState == uState)
2566 {
2567 return S_OK;
2568 }
2569
2570 /* OnActivate handles the menu merging and internal state */
2571 DoActivate(uState);
2572
2573 /* only do This if we are active */
2574 if (uState != SVUIA_DEACTIVATE)
2575 {
2577
2578 /* Set the text for the status bar */
2580 }
2581
2582 return S_OK;
2583}
2584
2586{
2587 TRACE("(%p)\n", this);
2588
2590
2592 FillList();
2593
2594 return S_OK;
2595}
2596
2598{
2599 return CreateViewWindow3(psb, lpPrevView, SV3CVW3_DEFAULT,
2600 (FOLDERFLAGS)lpfs->fFlags, (FOLDERFLAGS)lpfs->fFlags, (FOLDERVIEWMODE)lpfs->ViewMode, NULL, prcView, phWnd);
2601}
2602
2604{
2605 TRACE("(%p)\n", this);
2606
2607 /* Make absolutely sure all our UI is cleaned up */
2609
2610 if (m_hAccel)
2611 {
2612 // "Accelerator tables loaded from resources are freed automatically when the application terminates." -- MSDN
2613 m_hAccel = NULL;
2614 }
2615
2617 {
2620 }
2621
2622 if (m_hMenuViewModes)
2623 {
2626 }
2627
2628 if (m_hMenu)
2629 {
2631 m_hMenu = NULL;
2632 }
2633
2634 if (m_ListView)
2635 {
2636 m_ListView.DestroyWindow();
2637 }
2638
2639 if (m_hWnd)
2640 {
2642 DestroyWindow();
2643 }
2644
2647
2648 return S_OK;
2649}
2650
2652{
2653 TRACE("(%p)->(%p) vmode=%x flags=%x\n", this, lpfs,
2655
2656 if (!lpfs)
2657 return E_INVALIDARG;
2658
2659 *lpfs = m_FolderSettings;
2660 return S_OK;
2661}
2662
2664{
2665 FIXME("(%p) stub\n", this);
2666
2667 return E_NOTIMPL;
2668}
2669
2671{
2672 FIXME("(%p) stub\n", this);
2673
2674 return S_OK;
2675}
2676
2678{
2679 int i;
2680
2681 TRACE("(%p)->(pidl=%p, 0x%08x) stub\n", this, pidl, uFlags);
2682
2683 if (!m_ListView)
2684 {
2685 ERR("!m_ListView\n");
2686 return E_FAIL;
2687 }
2688
2689 i = LV_FindItemByPidl(pidl);
2690 if (i == -1)
2691 return S_OK;
2692
2693 LVITEMW lvItem = {0};
2694 lvItem.mask = LVIF_STATE;
2696
2697 while (m_ListView.GetItem(&lvItem))
2698 {
2699 if (lvItem.iItem == i)
2700 {
2701 if (uFlags & SVSI_SELECT)
2702 lvItem.state |= LVIS_SELECTED;
2703 else
2704 lvItem.state &= ~LVIS_SELECTED;
2705
2706 if (uFlags & SVSI_FOCUSED)
2707 lvItem.state |= LVIS_FOCUSED;
2708 else
2709 lvItem.state &= ~LVIS_FOCUSED;
2710 }
2711 else
2712 {
2713 if (uFlags & SVSI_DESELECTOTHERS)
2714 {
2715 lvItem.state &= ~LVIS_SELECTED;
2716 }
2717 lvItem.state &= ~LVIS_FOCUSED;
2718 }
2719
2720 m_ListView.SetItem(&lvItem);
2721 lvItem.iItem++;
2722 }
2723
2724 if (uFlags & SVSI_ENSUREVISIBLE)
2726
2727 if((uFlags & SVSI_EDIT) == SVSI_EDIT)
2729
2730 return S_OK;
2731}
2732
2734{
2736
2737 TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n", this, uItem, debugstr_guid(&riid), ppvOut);
2738
2739 if (!ppvOut)
2740 return E_INVALIDARG;
2741
2742 *ppvOut = NULL;
2743
2744 switch (uItem)
2745 {
2746 case SVGIO_BACKGROUND:
2747 if (IsEqualIID(riid, IID_IContextMenu))
2748 {
2751 return hr;
2752
2753 IUnknown_SetSite(*((IUnknown**)ppvOut), (IShellView *)this);
2754 }
2755 else if (IsEqualIID(riid, IID_IDispatch))
2756 {
2758 {
2761 return hr;
2762 }
2763 hr = m_pShellFolderViewDual->QueryInterface(riid, ppvOut);
2764 }
2765 break;
2766
2767 case SVGIO_SELECTION:
2768 GetSelections();
2769 hr = m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, riid, 0, ppvOut);
2771 return hr;
2772
2773 if (IsEqualIID(riid, IID_IContextMenu))
2774 IUnknown_SetSite(*((IUnknown**)ppvOut), (IShellView *)this);
2775
2776 break;
2777 }
2778
2779 TRACE("-- (%p)->(interface=%p)\n", this, *ppvOut);
2780
2781 return hr;
2782}
2783
2785{
2786 TRACE("(%p)->(%p), stub\n", this, pViewMode);
2787
2788 if (!pViewMode)
2789 return E_INVALIDARG;
2790
2791 *pViewMode = m_FolderSettings.ViewMode;
2792 return S_OK;
2793}
2794
2796{
2797 DWORD dwStyle;
2798 TRACE("(%p)->(%u), stub\n", this, ViewMode);
2799
2800 /* It's not redundant to check FVM_AUTO because it's a (UINT)-1 */
2801 if (((INT)ViewMode < FVM_FIRST || (INT)ViewMode > FVM_LAST) && ((INT)ViewMode != FVM_AUTO))
2802 return E_INVALIDARG;
2803
2804 /* Windows before Vista uses LVM_SETVIEW and possibly
2805 LVM_SETEXTENDEDLISTVIEWSTYLE to set the style of the listview,
2806 while later versions seem to accomplish this through other
2807 means. */
2808 switch (ViewMode)
2809 {
2810 case FVM_ICON:
2811 dwStyle = LVS_ICON;
2812 break;
2813 case FVM_DETAILS:
2814 dwStyle = LVS_REPORT;
2815 break;
2816 case FVM_SMALLICON:
2817 dwStyle = LVS_SMALLICON;
2818 break;
2819 case FVM_LIST:
2820 dwStyle = LVS_LIST;
2821 break;
2822 default:
2823 {
2824 FIXME("ViewMode %d not implemented\n", ViewMode);
2825 dwStyle = LVS_LIST;
2826 break;
2827 }
2828 }
2829
2830 m_ListView.ModifyStyle(LVS_TYPEMASK, dwStyle);
2831
2832 /* This will not necessarily be the actual mode set above.
2833 This mimics the behavior of Windows XP. */
2834 m_FolderSettings.ViewMode = ViewMode;
2835
2836 return S_OK;
2837}
2838
2840{
2841 if (m_pSFParent == NULL)
2842 return E_FAIL;
2843
2844 return m_pSFParent->QueryInterface(riid, ppv);
2845}
2846
2848{
2849 PCUITEMID_CHILD pidl = _PidlByItem(iItemIndex);
2850 if (pidl)
2851 {
2852 *ppidl = ILClone(pidl);
2853 return S_OK;
2854 }
2855
2856 *ppidl = 0;
2857 return E_INVALIDARG;
2858}
2859
2861{
2862 TRACE("(%p)->(%u %p)\n", this, uFlags, pcItems);
2863
2864 if (uFlags != SVGIO_ALLVIEW)
2865 FIXME("some flags unsupported, %x\n", uFlags & ~SVGIO_ALLVIEW);
2866
2868
2869 return S_OK;
2870}
2871
2873{
2874 return E_NOTIMPL;
2875}
2876
2878{
2879 TRACE("(%p)->(%p)\n", this, piItem);
2880
2881 *piItem = m_ListView.GetSelectionMark();
2882
2883 return S_OK;
2884}
2885
2887{
2888 TRACE("(%p)->(%p)\n", this, piItem);
2889
2890 *piItem = m_ListView.GetNextItem(-1, LVNI_FOCUSED);
2891
2892 return S_OK;
2893}
2894
2896{
2897 if (!m_ListView)
2898 {
2899 ERR("!m_ListView\n");
2900 return E_FAIL;
2901 }
2902
2903 int lvIndex = LV_FindItemByPidl(pidl);
2904 if (lvIndex == -1 || ppt == NULL)
2905 return E_INVALIDARG;
2906
2907 m_ListView.GetItemPosition(lvIndex, ppt);
2908 return S_OK;
2909}
2910
2912{
2913 TRACE("(%p)->(%p)\n", this, ppt);
2914
2915 if (!m_ListView)
2916 {
2917 ERR("!m_ListView\n");
2918 return S_FALSE;
2919 }
2920
2921 if (ppt)
2922 {
2923 SIZE spacing;
2924 m_ListView.GetItemSpacing(spacing);
2925
2926 ppt->x = spacing.cx;
2927 ppt->y = spacing.cy;
2928 }
2929
2930 return S_OK;
2931}
2932
2934{
2935 return E_NOTIMPL;
2936}
2937
2939{
2940 return ((m_ListView.GetStyle() & LVS_AUTOARRANGE) ? S_OK : S_FALSE);
2941}
2942
2944{
2945 DWORD dwExStyle = (DWORD)m_ListView.SendMessage(LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
2946 return ((dwExStyle & LVS_EX_SNAPTOGRID) ? S_OK : S_FALSE);
2947}
2948
2950{
2951 LVITEMW lvItem;
2952
2953 TRACE("(%p)->(%d, %x)\n", this, iItem, dwFlags);
2954
2955 lvItem.state = 0;
2956 lvItem.stateMask = LVIS_SELECTED;
2957
2958 if (dwFlags & SVSI_ENSUREVISIBLE)
2959 m_ListView.EnsureVisible(iItem, 0);
2960
2961 /* all items */
2962 if (dwFlags & SVSI_DESELECTOTHERS)
2964
2965 /* this item */
2966 if (dwFlags & SVSI_SELECT)
2967 lvItem.state |= LVIS_SELECTED;
2968
2969 if (dwFlags & SVSI_FOCUSED)
2970 lvItem.stateMask |= LVIS_FOCUSED;
2971
2972 m_ListView.SetItemState(iItem, lvItem.state, lvItem.stateMask);
2973
2974 if ((dwFlags & SVSI_EDIT) == SVSI_EDIT)
2975 m_ListView.EditLabel(iItem);
2976
2977 return S_OK;
2978}
2979
2981{
2983
2984 /* Reset the selection */
2986
2987 int lvIndex;
2988 for (UINT i = 0 ; i < m_cidl; i++)
2989 {
2990 lvIndex = LV_FindItemByPidl(apidl[i]);
2991 if (lvIndex != -1)
2992 {
2993 SelectItem(lvIndex, dwFlags);
2994 m_ListView.SetItemPosition(lvIndex, &apt[i]);
2995 }
2996 }
2997
2998 return S_OK;
2999}
3000
3001/**********************************************************
3002 * IShellView2 implementation
3003 */
3004
3006{
3007 FIXME("(%p)->(%p, %lu) stub\n", this, view_guid, view_type);
3008 return E_NOTIMPL;
3009}
3010
3012{
3013 return CreateViewWindow3(view_params->psbOwner, view_params->psvPrev,
3014 SV3CVW3_DEFAULT, (FOLDERFLAGS)view_params->pfs->fFlags, (FOLDERFLAGS)view_params->pfs->fFlags,
3015 (FOLDERVIEWMODE)view_params->pfs->ViewMode, view_params->pvid, view_params->prcView, &view_params->hwndView);
3016}
3017
3019{
3020 OLEMENUGROUPWIDTHS omw = { { 0, 0, 0, 0, 0, 0 } };
3021
3022 *hwnd = NULL;
3023
3024 TRACE("(%p)->(shlview=%p shlbrs=%p rec=%p hwnd=%p vmode=%x flags=%x)\n", this, psvPrevious, psb, prcView, hwnd, mode, flags);
3025 if (prcView != NULL)
3026 TRACE("-- left=%i top=%i right=%i bottom=%i\n", prcView->left, prcView->top, prcView->right, prcView->bottom);
3027
3028 /* Validate the Shell Browser */
3029 if (psb == NULL || m_hWnd)
3030 return E_UNEXPECTED;
3031
3032 if (view_flags != SV3CVW3_DEFAULT)
3033 FIXME("unsupported view flags 0x%08x\n", view_flags);
3034
3035 /* Set up the member variables */
3036 m_pShellBrowser = psb;
3039
3040 if (view_id)
3041 {
3042 if (IsEqualIID(*view_id, VID_LargeIcons))
3044 else if (IsEqualIID(*view_id, VID_SmallIcons))
3046 else if (IsEqualIID(*view_id, VID_List))
3048 else if (IsEqualIID(*view_id, VID_Details))
3050 else if (IsEqualIID(*view_id, VID_Thumbnails))
3052 else if (IsEqualIID(*view_id, VID_Tile))
3054 else if (IsEqualIID(*view_id, VID_ThumbStrip))
3056 else
3057 FIXME("Ignoring unrecognized VID %s\n", debugstr_guid(view_id));
3058 }
3059
3060 /* Get our parent window */
3061 m_pShellBrowser->GetWindow(&m_hWndParent);
3062
3063 /* Try to get the ICommDlgBrowserInterface, adds a reference !!! */
3066 {
3067 TRACE("-- CommDlgBrowser\n");
3068 }
3069
3071 if (m_hWnd == NULL)
3072 return E_FAIL;
3073
3074 *hwnd = m_hWnd;
3075
3076 CheckToolbar();
3077
3078 if (!*hwnd)
3079 return E_FAIL;
3080
3082
3084 UpdateWindow();
3085
3086 if (!m_hMenu)
3087 {
3088 m_hMenu = CreateMenu();
3089 m_pShellBrowser->InsertMenusSB(m_hMenu, &omw);
3090 TRACE("-- after fnInsertMenusSB\n");
3091 }
3092
3093 _MergeToolbar();
3094
3095 return S_OK;
3096}
3097
3099{
3100 FIXME("(%p)->(%p) stub\n", this, new_pidl);
3101 return E_NOTIMPL;
3102}
3103
3105{
3106 FIXME("(%p)->(%p, %u, %p) stub\n", this, item, flags, point);
3107 return E_NOTIMPL;
3108}
3109
3110/**********************************************************
3111 * IShellFolderView implementation
3112 */
3114{
3115 FIXME("(%p)->(%ld) stub\n", this, sort);
3116 return E_NOTIMPL;
3117}
3118
3120{
3121 FIXME("(%p)->(%p) stub\n", this, sort);
3122 return E_NOTIMPL;
3123}
3124
3126{
3128 return S_OK;
3129}
3130
3132{
3133 m_ListView.ModifyStyle(0, LVS_AUTOARRANGE);
3135 return S_OK;
3136}
3137
3139{
3140 TRACE("(%p)->(%p %p)\n", this, pidl, item);
3141 if (!m_ListView)
3142 {
3143 ERR("!m_ListView\n");
3144 return E_FAIL;
3145 }
3146 *item = LV_AddItem(pidl);
3147 return (int)*item >= 0 ? S_OK : E_OUTOFMEMORY;
3148}
3149
3151{
3152 TRACE("(%p)->(%p %d)\n", this, pidl, item);
3153 return Item(item, pidl);
3154}
3155
3157{
3158 TRACE("(%p)->(%p %p)\n", this, pidl, item);
3159
3160 if (!m_ListView)
3161 {
3162 ERR("!m_ListView\n");
3163 return E_FAIL;
3164 }
3165
3166 if (pidl)
3167 {
3170 }
3171 else
3172 {
3173 *item = 0;
3175 }
3176
3177 return S_OK;
3178}
3179
3181{
3182 TRACE("(%p)->(%p)\n", this, count);
3184 return S_OK;
3185}
3186
3188{
3189 FIXME("(%p)->(%d %x) stub\n", this, count, flags);
3190 return E_NOTIMPL;
3191}
3192
3194{
3195 FIXME("(%p)->(%p %p %p) stub\n", this, pidl_old, pidl_new, item);
3196 return E_NOTIMPL;
3197}
3198
3200{
3201 FIXME("(%p)->(%p %p) stub\n", this, pidl, item);
3202 return E_NOTIMPL;
3203}
3204
3206{
3207 TRACE("(%p)->(%d)\n", this, redraw);
3208 if (m_ListView)
3210 return S_OK;
3211}
3212
3214{
3215 FIXME("(%p)->(%p) stub\n", this, count);
3216 return E_NOTIMPL;
3217}
3218
3220{
3221 TRACE("(%p)->(%p %p)\n", this, pidl, items);
3222
3223 *items = GetSelections();
3224
3225 if (*items)
3226 {
3227 *pidl = static_cast<PCUITEMID_CHILD *>(LocalAlloc(0, *items * sizeof(PCUITEMID_CHILD)));
3228 if (!*pidl)
3229 {
3230 return E_OUTOFMEMORY;
3231 }
3232
3233 /* it's documented that caller shouldn't PIDLs, only array itself */
3234 memcpy(*pidl, m_apidl, *items * sizeof(PCUITEMID_CHILD));
3235 }
3236
3237 return S_OK;
3238}
3239
3241{
3242 if ((m_iDragOverItem == -1 || m_pCurDropTarget == NULL) &&
3244 {
3245 return S_OK;
3246 }
3247
3248 return S_FALSE;
3249}
3250
3252{
3253 if (!pt)
3254 return E_INVALIDARG;
3255
3257 return S_OK;
3258}
3259
3261{
3262 FIXME("(%p)->(%p) stub\n", this, pt);
3263 return E_NOTIMPL;
3264}
3265
3267{
3268 TRACE("(%p)->(%p)\n", this, obj);
3269 return E_NOTIMPL;
3270}
3271
3273{
3274 FIXME("(%p)->(%p %p) stub\n", this, pidl, pt);
3275 return E_NOTIMPL;
3276}
3277
3279{
3280 FIXME("(%p)->(%p) stub\n", this, drop_target);
3281 return E_NOTIMPL;
3282}
3283
3285{
3286 FIXME("(%p)->(%d) stub\n", this, move);
3287 return E_NOTIMPL;
3288}
3289
3291{
3292 FIXME("(%p)->(%p) stub\n", this, obj);
3293 return E_NOTIMPL;
3294}
3295
3297{
3298 FIXME("(%p)->(%p) stub\n", this, spacing);
3299 return E_NOTIMPL;
3300}
3301
3302HRESULT STDMETHODCALLTYPE CDefView::SetCallback(IShellFolderViewCB *new_cb, IShellFolderViewCB **old_cb)
3303{
3304 if (old_cb)
3305 *old_cb = m_pShellFolderViewCB.Detach();
3306
3307 m_pShellFolderViewCB = new_cb;
3308 return S_OK;
3309}
3310
3312{
3313 FIXME("(%p)->(%d) stub\n", this, flags);
3314 return E_NOTIMPL;
3315}
3316
3318{
3319 TRACE("(%p)->(%p)\n", this, support);
3320 return S_OK;
3321}
3322
3324{
3325 FIXME("(%p)->(%p) stub\n", this, disp);
3326 return E_NOTIMPL;
3327}
3328
3329/**********************************************************
3330 * ISVOleCmdTarget_QueryStatus (IOleCommandTarget)
3331 */
3332HRESULT WINAPI CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText)
3333{
3334 FIXME("(%p)->(%p(%s) 0x%08x %p %p\n",
3335 this, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
3336
3337 if (!prgCmds)
3338 return E_INVALIDARG;
3339
3340 for (UINT i = 0; i < cCmds; i++)
3341 {
3342 FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID);
3343 prgCmds[i].cmdf = 0;
3344 }
3345
3346 return OLECMDERR_E_UNKNOWNGROUP;
3347}
3348
3349/**********************************************************
3350 * ISVOleCmdTarget_Exec (IOleCommandTarget)
3351 *
3352 * nCmdID is the OLECMDID_* enumeration
3353 */
3354HRESULT WINAPI CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
3355{
3356 FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n",
3357 this, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut);
3358
3359 if (!pguidCmdGroup)
3360 return OLECMDERR_E_UNKNOWNGROUP;
3361
3362 if (IsEqualCLSID(*pguidCmdGroup, m_Category))
3363 {
3364 if (nCmdID == FCIDM_SHVIEW_AUTOARRANGE)
3365 {
3366 if (V_VT(pvaIn) != VT_INT_PTR)
3367 return OLECMDERR_E_NOTSUPPORTED;
3368
3370 params.cbSize = sizeof(params);
3371 params.rcExclude = *(RECT*) V_INTREF(pvaIn);
3372
3373 if (m_hMenuViewModes)
3374 {
3375 /* Duplicate all but the last two items of the view modes menu */
3376 HMENU hmenuViewPopup = CreatePopupMenu();
3377 Shell_MergeMenus(hmenuViewPopup, m_hMenuViewModes, 0, 0, 0xFFFF, 0);
3378 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION);
3379 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION);
3380 CheckViewMode(hmenuViewPopup);
3381 TrackPopupMenuEx(hmenuViewPopup, TPM_LEFTALIGN | TPM_TOPALIGN, params.rcExclude.left, params.rcExclude.bottom, m_hWndParent, &params);
3382 ::DestroyMenu(hmenuViewPopup);
3383 }
3384
3385 // pvaOut is VT_I4 with value 0x403 (cmd id of the new mode maybe?)
3386 V_VT(pvaOut) = VT_I4;
3387 V_I4(pvaOut) = 0x403;
3388 }
3389 }
3390
3391 if (IsEqualIID(*pguidCmdGroup, CGID_Explorer) &&
3392 (nCmdID == 0x29) &&
3393 (nCmdexecopt == 4) && pvaOut)
3394 return S_OK;
3395
3396 if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView) &&
3397 (nCmdID == 9) &&
3398 (nCmdexecopt == 0))
3399 return 1;
3400
3401 return OLECMDERR_E_UNKNOWNGROUP;
3402}
3403
3404/**********************************************************
3405 * ISVDropTarget implementation
3406 */
3407
3408/******************************************************************************
3409 * drag_notify_subitem [Internal]
3410 *
3411 * Figure out the shellfolder object, which is currently under the mouse cursor
3412 * and notify it via the IDropTarget interface.
3413 */
3414
3415#define SCROLLAREAWIDTH 20
3416
3418{
3419 LONG lResult;
3420 HRESULT hr;
3421 RECT clientRect;
3422
3423 /* The key state on drop doesn't have MK_LBUTTON or MK_RBUTTON because it
3424 reflects the key state after the user released the button, so we need
3425 to remember the last key state when the button was pressed */
3426 m_grfKeyState = grfKeyState;
3427
3428 /* Map from global to client coordinates and query the index of the listview-item, which is
3429 * currently under the mouse cursor. */
3430 LVHITTESTINFO htinfo = {{pt.x, pt.y}, LVHT_ONITEM};
3431 ScreenToClient(&htinfo.pt);
3432 lResult = m_ListView.HitTest(&htinfo);
3433
3434 /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */
3435 ::GetClientRect(m_ListView, &clientRect);
3436 if (htinfo.pt.x == m_ptLastMousePos.x && htinfo.pt.y == m_ptLastMousePos.y &&
3437 (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH ||
3438 htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH ))
3439 {
3440 m_cScrollDelay = (m_cScrollDelay + 1) % 5; /* DragOver is called every 50 ms */
3441 if (m_cScrollDelay == 0)
3442 {
3443 /* Mouse did hover another 250 ms over the scroll-area */
3444 if (htinfo.pt.x < SCROLLAREAWIDTH)
3445 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEUP, 0);
3446
3447 if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH)
3448 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEDOWN, 0);
3449
3450 if (htinfo.pt.y < SCROLLAREAWIDTH)
3451 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEUP, 0);
3452
3453 if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH)
3454 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEDOWN, 0);
3455 }
3456 }
3457 else
3458 {
3459 m_cScrollDelay = 0; /* Reset, if the cursor is not over the listview's scroll-area */
3460 }
3461
3462 m_ptLastMousePos = htinfo.pt;
3464
3465 /* We need to check if we drag the selection over itself */
3466 if (lResult != -1 && m_pSourceDataObject.p != NULL)
3467 {
3468 PCUITEMID_CHILD pidl = _PidlByItem(lResult);
3469
3470 for (UINT i = 0; i < m_cidl; i++)
3471 {
3472 if (pidl == m_apidl[i])
3473 {
3474 /* The item that is being draged is hovering itself. */
3475 lResult = -1;
3476 break;
3477 }
3478 }
3479 }
3480
3481 /* If we are still over the previous sub-item, notify it via DragOver and return. */
3482 if (m_pCurDropTarget && lResult == m_iDragOverItem)
3483 return m_pCurDropTarget->DragOver(grfKeyState, pt, pdwEffect);
3484
3485 /* We've left the previous sub-item, notify it via DragLeave and Release it. */
3486 if (m_pCurDropTarget)
3487 {
3489 if (pidl)
3490 SelectItem(pidl, 0);
3491
3492 m_pCurDropTarget->DragLeave();
3494 }
3495
3496 m_iDragOverItem = lResult;
3497
3498 if (lResult == -1)
3499 {
3500 /* We are not above one of the listview's subitems. Bind to the parent folder's
3501 * DropTarget interface. */
3503 }
3504 else
3505 {
3506 /* Query the relative PIDL of the shellfolder object represented by the currently
3507 * dragged over listview-item ... */
3508 PCUITEMID_CHILD pidl = _PidlByItem(lResult);
3509
3510 /* ... and bind m_pCurDropTarget to the IDropTarget interface of an UIObject of this object */
3511 hr = m_pSFParent->GetUIObjectOf(m_ListView, 1, &pidl, IID_NULL_PPV_ARG(IDropTarget, &m_pCurDropTarget));
3512 }
3513
3515
3516 /* If anything failed, m_pCurDropTarget should be NULL now, which ought to be a save state. */
3517 if (FAILED(hr))
3518 {
3519 *pdwEffect = DROPEFFECT_NONE;
3520 return hr;
3521 }
3522
3523 if (m_iDragOverItem != -1)
3524 {
3525 SelectItem(m_iDragOverItem, SVSI_SELECT);
3526 }
3527
3528 /* Notify the item just entered via DragEnter. */
3529 return m_pCurDropTarget->DragEnter(m_pCurDataObject, grfKeyState, pt, pdwEffect);
3530}
3531
3532HRESULT WINAPI CDefView::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3533{
3534 if (*pdwEffect == DROPEFFECT_NONE)
3535 return S_OK;
3536
3537 /* Get a hold on the data object for later calls to DragEnter on the sub-folders */
3538 m_pCurDataObject = pDataObject;
3539
3540 HRESULT hr = drag_notify_subitem(grfKeyState, pt, pdwEffect);
3541 if (SUCCEEDED(hr))
3542 {
3543 POINT ptClient = {pt.x, pt.y};
3544 ScreenToClient(&ptClient);
3545 ImageList_DragEnter(m_hWnd, ptClient.x, ptClient.y);
3546 }
3547
3548 return hr;
3549}
3550
3552{
3553 POINT ptClient = {pt.x, pt.y};
3554 ScreenToClient(&ptClient);
3555 ImageList_DragMove(ptClient.x, ptClient.y);
3556 return drag_notify_subitem(grfKeyState, pt, pdwEffect);
3557}
3558
3560{
3562
3563 if (m_pCurDropTarget)
3564 {
3565 m_pCurDropTarget->DragLeave();
3567 }
3568
3569 if (m_pCurDataObject != NULL)
3570 {
3572 }
3573
3574 m_iDragOverItem = 0;
3575
3576 return S_OK;
3577}
3578
3580{
3581 RECT rcBound;
3582 INT i, nCount = m_ListView.GetItemCount();
3583 DWORD dwSpacing;
3584 INT dx, dy;
3585 BOOL bSmall = ((m_ListView.GetStyle() & LVS_TYPEMASK) != LVS_ICON);
3586
3587 /* FIXME: LVM_GETORIGIN is broken. See CORE-17266 */
3588 pt.x += m_ListView.GetScrollPos(SB_HORZ);
3589 pt.y += m_ListView.GetScrollPos(SB_VERT);
3590
3591 if (m_ListView.GetStyle() & LVS_ALIGNLEFT)
3592 {
3593 // vertically
3594 for (i = 0; i < nCount; ++i)
3595 {
3596 dwSpacing = ListView_GetItemSpacing(m_ListView, bSmall);
3597 dx = LOWORD(dwSpacing);
3598 dy = HIWORD(dwSpacing);
3600 rcBound.right = rcBound.left + dx;
3601 rcBound.bottom = rcBound.top + dy;
3602 if (pt.x < rcBound.right && pt.y < (rcBound.top + rcBound.bottom) / 2)
3603 {
3604 return i;
3605 }
3606 }
3607 for (i = nCount - 1; i >= 0; --i)
3608 {
3610 if (rcBound.left < pt.x && rcBound.top < pt.y)
3611 {
3612 return i + 1;
3613 }
3614 }
3615 }
3616 else
3617 {
3618 // horizontally
3619 for (i = 0; i < nCount; ++i)
3620 {
3621 dwSpacing = ListView_GetItemSpacing(m_ListView, bSmall);
3622 dx = LOWORD(dwSpacing);
3623 dy = HIWORD(dwSpacing);
3625 rcBound.right = rcBound.left + dx;
3626 rcBound.bottom = rcBound.top + dy;
3627 if (pt.y < rcBound.bottom && pt.x < rcBound.left)
3628 {
3629 return i;
3630 }
3631 if (pt.y < rcBound.bottom && pt.x < rcBound.right)
3632 {
3633 return i + 1;
3634 }
3635 }
3636 for (i = nCount - 1; i >= 0; --i)
3637 {
3639 if (rcBound.left < pt.x && rcBound.top < pt.y)
3640 {
3641 return i + 1;
3642 }
3643 }
3644 }
3645
3646 return nCount;
3647}
3648
3650{
3651 LRESULT lResult;
3652
3654 {
3655 int nPartArray[] = {-1};
3656 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, _countof(nPartArray), (LPARAM)nPartArray, &lResult);
3657 return;
3658 }
3659
3660 int nFileSizePartLength = 125;
3661 const int nLocationPartLength = 150;
3662 const int nRightPartsLength = nFileSizePartLength + nLocationPartLength;
3663 int nObjectsPartLength = nWidth - nRightPartsLength;
3664
3665 /* If the window is small enough just divide each part into thirds
3666 * This is the behavior of Windows Server 2003. */
3667 if (nObjectsPartLength <= nLocationPartLength)
3668 nObjectsPartLength = nFileSizePartLength = nWidth / 3;
3669
3670 int nPartArray[] = {nObjectsPartLength, nObjectsPartLength + nFileSizePartLength, -1};
3671
3672 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, _countof(nPartArray), (LPARAM)nPartArray, &lResult);
3673}
3674
3676{
3677 /* Get the handle for the status bar */
3678 HWND fStatusBar;
3679 m_pShellBrowser->GetControlWindow(FCW_STATUS, &fStatusBar);
3680
3681 /* Get the size of our status bar */
3682 RECT statusBarSize;
3683 ::GetWindowRect(fStatusBar, &statusBarSize);
3684
3685 /* Resize the status bar */
3686 _HandleStatusBarResize(statusBarSize.right - statusBarSize.left);
3687}
3688
3690
3691static INT CALLBACK
3692SelectionMoveCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
3693{
3694 CLParamIndexMap *pmap = (CLParamIndexMap *)lParamSort;
3695 INT i1 = pmap->Lookup(lParam1), i2 = pmap->Lookup(lParam2);
3696 if (i1 < i2)
3697 return -1;
3698 if (i1 > i2)
3699 return 1;
3700 return 0;
3701}
3702
3704{
3705 // get insertable index from position
3707
3708 // create identity mapping of indexes
3710 INT nCount = m_ListView.GetItemCount();
3711 for (INT i = 0; i < nCount; ++i)
3712 {
3713 array.Add(i);
3714 }
3715
3716 // re-ordering mapping
3717 INT iItem = -1;
3718 while ((iItem = m_ListView.GetNextItem(iItem, LVNI_SELECTED)) >= 0)
3719 {
3720 INT iFrom = iItem, iTo = iPosition;
3721 if (iFrom < iTo)
3722 --iTo;
3723 if (iFrom >= nCount)
3724 iFrom = nCount - 1;
3725 if (iTo >= nCount)
3726 iTo = nCount - 1;
3727
3728 // shift indexes by swapping (like a bucket relay)
3729 if (iFrom < iTo)
3730 {
3731 for (INT i = iFrom; i < iTo; ++i)
3732 {
3733 // swap array[i] and array[i + 1]
3734 INT tmp = array[i];
3735 array[i] = array[i + 1];
3736 array[i + 1] = tmp;
3737 }
3738 }
3739 else
3740 {
3741 for (INT i = iFrom; i > iTo; --i)
3742 {
3743 // swap array[i] and array[i - 1]
3744 INT tmp = array[i];
3745 array[i] = array[i - 1];
3746 array[i - 1] = tmp;
3747 }
3748 }
3749 }
3750
3751 // create mapping (ListView's lParam to index) from array
3753 for (INT i = 0; i < nCount; ++i)
3754 {
3756 map.Add(lParam, i);
3757 }
3758
3759 // finally sort
3761}
3762
3763HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3764{
3767
3768 if ((IsDropOnSource(NULL) == S_OK) &&
3769 (*pdwEffect & DROPEFFECT_MOVE) &&
3771 {
3772 if (m_pCurDropTarget)
3773 {
3774 m_pCurDropTarget->DragLeave();
3776 }
3777
3778 POINT ptDrop = { pt.x, pt.y };
3779 ::ScreenToClient(m_ListView, &ptDrop);
3781 m_ptLastMousePos = ptDrop;
3782
3784 if (m_ListView.GetStyle() & LVS_AUTOARRANGE)
3785 {
3787 }
3788 else
3789 {
3790 POINT ptItem;
3791 INT iItem = -1;
3792 while ((iItem = m_ListView.GetNextItem(iItem, LVNI_SELECTED)) >= 0)
3793 {
3794 if (m_ListView.GetItemPosition(iItem, &ptItem))
3795 {
3798 m_ListView.SetItemPosition(iItem, &ptItem);
3799 }
3800 }
3801 }
3803 }
3804 else if (m_pCurDropTarget)
3805 {
3806 m_pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect);
3808 }
3809
3811 m_iDragOverItem = 0;
3812 return S_OK;
3813}
3814
3815/**********************************************************
3816 * ISVDropSource implementation
3817 */
3818
3820{
3821 TRACE("(%p)\n", this);
3822
3823 if (fEscapePressed)
3824 return DRAGDROP_S_CANCEL;
3825 else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON))
3826 return DRAGDROP_S_DROP;
3827 else
3828 return S_OK;
3829}
3830
3832{
3833 TRACE("(%p)\n", this);
3834
3836}
3837
3838/**********************************************************
3839 * ISVViewObject implementation
3840 */
3841
3842HRESULT 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)
3843{
3844 FIXME("Stub: this=%p\n", this);
3845
3846 return E_NOTIMPL;
3847}
3848
3849HRESULT WINAPI CDefView::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet)
3850{
3851 FIXME("Stub: this=%p\n", this);
3852
3853 return E_NOTIMPL;
3854}
3855
3856HRESULT WINAPI CDefView::Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze)
3857{
3858 FIXME("Stub: this=%p\n", this);
3859
3860 return E_NOTIMPL;
3861}
3862
3864{
3865 FIXME("Stub: this=%p\n", this);
3866
3867 return E_NOTIMPL;
3868}
3869
3871{
3872 FIXME("partial stub: %p 0x%08x 0x%08x %p\n", this, aspects, advf, pAdvSink);
3873
3874 /* FIXME: we set the AdviseSink, but never use it to send any advice */
3875 m_pAdvSink = pAdvSink;
3876 m_dwAspects = aspects;
3877 m_dwAdvf = advf;
3878
3879 return S_OK;
3880}
3881
3883{
3884 TRACE("this=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n", this, pAspects, pAdvf, ppAdvSink);
3885
3886 if (ppAdvSink)
3887 {
3888 *ppAdvSink = m_pAdvSink;
3889 m_pAdvSink.p->AddRef();
3890 }
3891
3892 if (pAspects)
3893 *pAspects = m_dwAspects;
3894
3895 if (pAdvf)
3896 *pAdvf = m_dwAdvf;
3897
3898 return S_OK;
3899}
3900
3902{
3903 if (IsEqualIID(guidService, SID_IShellBrowser))
3904 return m_pShellBrowser->QueryInterface(riid, ppvObject);
3905 else if(IsEqualIID(guidService, SID_IFolderView))
3906 return QueryInterface(riid, ppvObject);
3907
3908 return E_NOINTERFACE;
3909}
3910
3912{
3914 HRESULT hr = S_OK;
3915
3916 hr = IUnknown_QueryService(m_pShellBrowser, IID_IExplorerToolbar, IID_PPV_ARG(IExplorerToolbar, &ptb));
3917 if (FAILED(hr))
3918 return hr;
3919
3920 m_Category = CGID_DefViewFrame;
3921
3922 hr = ptb->SetCommandTarget(static_cast<IOleCommandTarget*>(this), &m_Category, 0);
3923 if (FAILED(hr))
3924 return hr;
3925
3926 if (hr == S_FALSE)
3927 return S_OK;
3928
3929#if 0
3930 hr = ptb->AddButtons(&m_Category, buttonsCount, buttons);
3931 if (FAILED(hr))
3932 return hr;
3933#endif
3934
3935 return S_OK;
3936}
3937
3939{
3941
3943 {
3944 hr = m_pShellFolderViewCB->MessageSFVCB(uMsg, wParam, lParam);
3945 }
3946
3947 return hr;
3948}
3949
3951{
3952 return ShellObjectCreatorInit<CDefView>(pFolder, riid, ppvOut);
3953}
3954
3956 LPCSFV psvcbi, /* [in] shelltemplate struct */
3957 IShellView **ppsv) /* [out] IShellView pointer */
3958{
3960 HRESULT hRes;
3961
3962 TRACE("sf=%p pidl=%p cb=%p mode=0x%08x parm=%p\n",
3963 psvcbi->pshf, psvcbi->pidl, psvcbi->pfnCallback,
3964 psvcbi->fvm, psvcbi->psvOuter);
3965
3966 *ppsv = NULL;
3967 hRes = CDefView_CreateInstance(psvcbi->pshf, IID_PPV_ARG(IShellView, &psv));
3968 if (FAILED_UNEXPECTEDLY(hRes))