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