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