00e310397f4a0a637d01b391f2a65b05b9e3b18d
[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;
1577
1578 hMenu = CreatePopupMenu();
1579 if (!hMenu)
1580 return 0;
1581
1582 hResult = GetItemObject( bUseSelection ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &m_pCM));
1583 if (FAILED_UNEXPECTEDLY( hResult))
1584 goto cleanup;
1585
1586 hResult = m_pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_NORMAL);
1587 if (FAILED_UNEXPECTEDLY( hResult))
1588 goto cleanup;
1589
1590 if (bUseSelection)
1591 {
1592 // FIXME: we should cache this....
1593 SFGAOF rfg = SFGAO_BROWSABLE | SFGAO_CANCOPY | SFGAO_CANLINK | SFGAO_CANMOVE | SFGAO_CANDELETE | SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSTEM | SFGAO_FOLDER;
1594 hResult = m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &rfg);
1595 if (FAILED_UNEXPECTEDLY(hResult))
1596 return 0;
1597
1598 if (!(rfg & SFGAO_CANMOVE) && uCommand == FCIDM_SHVIEW_CUT)
1599 return 0;
1600 if (!(rfg & SFGAO_CANCOPY) && uCommand == FCIDM_SHVIEW_COPY)
1601 return 0;
1602 if (!(rfg & SFGAO_CANDELETE) && uCommand == FCIDM_SHVIEW_DELETE)
1603 return 0;
1604 if (!(rfg & SFGAO_CANRENAME) && uCommand == FCIDM_SHVIEW_RENAME)
1605 return 0;
1606 if (!(rfg & SFGAO_HASPROPSHEET) && uCommand == FCIDM_SHVIEW_PROPERTIES)
1607 return 0;
1608 }
1609
1610 InvokeContextMenuCommand(uCommand);
1611
1612 cleanup:
1613 if (m_pCM)
1614 {
1615 IUnknown_SetSite(m_pCM, NULL);
1616 m_pCM.Release();
1617 }
1618
1619 if (hMenu)
1620 DestroyMenu(hMenu);
1621
1622 return 0;
1623 }
1624
1625 /**********************************************************
1626 * ##### message handling #####
1627 */
1628
1629 /**********************************************************
1630 * ShellView_OnSize()
1631 */
1632 LRESULT CDefView::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1633 {
1634 WORD wWidth, wHeight;
1635
1636 wWidth = LOWORD(lParam);
1637 wHeight = HIWORD(lParam);
1638
1639 TRACE("%p width=%u height=%u\n", this, wWidth, wHeight);
1640
1641 /* Resize the ListView to fit our window */
1642 if (m_ListView)
1643 {
1644 ::MoveWindow(m_ListView, 0, 0, wWidth, wHeight, TRUE);
1645 }
1646
1647 _DoFolderViewCB(SFVM_SIZE, 0, 0);
1648
1649 return 0;
1650 }
1651
1652 /**********************************************************
1653 * ShellView_OnDeactivate()
1654 *
1655 * NOTES
1656 * internal
1657 */
1658 void CDefView::OnDeactivate()
1659 {
1660 TRACE("%p\n", this);
1661
1662 if (m_uState != SVUIA_DEACTIVATE)
1663 {
1664 // TODO: cleanup menu after deactivation
1665
1666 m_uState = SVUIA_DEACTIVATE;
1667 }
1668 }
1669
1670 void CDefView::DoActivate(UINT uState)
1671 {
1672 TRACE("%p uState=%x\n", this, uState);
1673
1674 /*don't do anything if the state isn't really changing */
1675 if (m_uState == uState)
1676 {
1677 return;
1678 }
1679
1680 if (uState == SVUIA_DEACTIVATE)
1681 {
1682 OnDeactivate();
1683 }
1684 else
1685 {
1686 if(m_hMenu && !m_bmenuBarInitialized)
1687 {
1688 FillEditMenu();
1689 FillViewMenu();
1690 m_pShellBrowser->SetMenuSB(m_hMenu, 0, m_hWnd);
1691 m_bmenuBarInitialized = TRUE;
1692 }
1693
1694 if (SVUIA_ACTIVATE_FOCUS == uState)
1695 {
1696 m_ListView.SetFocus();
1697 }
1698 }
1699
1700 m_uState = uState;
1701 TRACE("--\n");
1702 }
1703
1704 /**********************************************************
1705 * ShellView_OnActivate()
1706 */
1707 LRESULT CDefView::OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1708 {
1709 DoActivate(SVUIA_ACTIVATE_FOCUS);
1710 return 0;
1711 }
1712
1713 /**********************************************************
1714 * ShellView_OnSetFocus()
1715 *
1716 */
1717 LRESULT CDefView::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1718 {
1719 TRACE("%p\n", this);
1720
1721 /* Tell the browser one of our windows has received the focus. This
1722 should always be done before merging menus (OnActivate merges the
1723 menus) if one of our windows has the focus.*/
1724
1725 m_pShellBrowser->OnViewWindowActive(this);
1726 DoActivate(SVUIA_ACTIVATE_FOCUS);
1727
1728 /* Set the focus to the listview */
1729 m_ListView.SetFocus();
1730
1731 /* Notify the ICommDlgBrowser interface */
1732 OnStateChange(CDBOSC_SETFOCUS);
1733
1734 return 0;
1735 }
1736
1737 /**********************************************************
1738 * ShellView_OnKillFocus()
1739 */
1740 LRESULT CDefView::OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1741 {
1742 TRACE("(%p) stub\n", this);
1743
1744 DoActivate(SVUIA_ACTIVATE_NOFOCUS);
1745 /* Notify the ICommDlgBrowser */
1746 OnStateChange(CDBOSC_KILLFOCUS);
1747
1748 return 0;
1749 }
1750
1751 /**********************************************************
1752 * ShellView_OnCommand()
1753 *
1754 * NOTES
1755 * the CmdID's are the ones from the context menu
1756 */
1757 LRESULT CDefView::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1758 {
1759 DWORD dwCmdID;
1760 DWORD dwCmd;
1761 HWND hwndCmd;
1762 int nCount;
1763
1764 dwCmdID = GET_WM_COMMAND_ID(wParam, lParam);
1765 dwCmd = GET_WM_COMMAND_CMD(wParam, lParam);
1766 hwndCmd = GET_WM_COMMAND_HWND(wParam, lParam);
1767
1768 TRACE("(%p)->(0x%08x 0x%08x %p) stub\n", this, dwCmdID, dwCmd, hwndCmd);
1769
1770 switch (dwCmdID)
1771 {
1772 case FCIDM_SHVIEW_SMALLICON:
1773 m_FolderSettings.ViewMode = FVM_SMALLICON;
1774 m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_SMALLICON);
1775 CheckToolbar();
1776 break;
1777
1778 case FCIDM_SHVIEW_BIGICON:
1779 m_FolderSettings.ViewMode = FVM_ICON;
1780 m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_ICON);
1781 CheckToolbar();
1782 break;
1783
1784 case FCIDM_SHVIEW_LISTVIEW:
1785 m_FolderSettings.ViewMode = FVM_LIST;
1786 m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_LIST);
1787 CheckToolbar();
1788 break;
1789
1790 case FCIDM_SHVIEW_REPORTVIEW:
1791 m_FolderSettings.ViewMode = FVM_DETAILS;
1792 m_ListView.ModifyStyle(LVS_TYPEMASK, LVS_REPORT);
1793 CheckToolbar();
1794 break;
1795
1796 /* the menu-ID's for sorting are 0x30... see shrec.rc */
1797 case 0x30:
1798 case 0x31:
1799 case 0x32:
1800 case 0x33:
1801 m_sortInfo.nHeaderID = dwCmdID - 0x30;
1802 m_sortInfo.bIsAscending = TRUE;
1803 _Sort();
1804 break;
1805
1806 case FCIDM_SHVIEW_SNAPTOGRID:
1807 m_ListView.Arrange(LVA_SNAPTOGRID);
1808 break;
1809 case FCIDM_SHVIEW_ALIGNTOGRID:
1810 if (_GetSnapToGrid() == S_OK)
1811 m_ListView.SetExtendedListViewStyle(0, LVS_EX_SNAPTOGRID);
1812 else
1813 ArrangeGrid();
1814 break;
1815 case FCIDM_SHVIEW_AUTOARRANGE:
1816 if (GetAutoArrange() == S_OK)
1817 m_ListView.ModifyStyle(LVS_AUTOARRANGE, 0);
1818 else
1819 AutoArrange();
1820 break;
1821 case FCIDM_SHVIEW_SELECTALL:
1822 m_ListView.SetItemState(-1, LVIS_SELECTED, LVIS_SELECTED);
1823 break;
1824
1825 case FCIDM_SHVIEW_INVERTSELECTION:
1826 nCount = m_ListView.GetItemCount();
1827 for (int i=0; i < nCount; i++)
1828 m_ListView.SetItemState(i, m_ListView.GetItemState(i, LVIS_SELECTED) ? 0 : LVIS_SELECTED, LVIS_SELECTED);
1829 break;
1830
1831 case FCIDM_SHVIEW_REFRESH:
1832 Refresh();
1833 break;
1834
1835 case FCIDM_SHVIEW_DELETE:
1836 case FCIDM_SHVIEW_CUT:
1837 case FCIDM_SHVIEW_COPY:
1838 case FCIDM_SHVIEW_RENAME:
1839 case FCIDM_SHVIEW_PROPERTIES:
1840 case FCIDM_SHVIEW_COPYTO:
1841 case FCIDM_SHVIEW_MOVETO:
1842 if (SHRestricted(REST_NOVIEWCONTEXTMENU))
1843 return 0;
1844
1845 return OnExplorerCommand(dwCmdID, TRUE);
1846
1847 case FCIDM_SHVIEW_INSERT:
1848 case FCIDM_SHVIEW_UNDO:
1849 case FCIDM_SHVIEW_INSERTLINK:
1850 case FCIDM_SHVIEW_NEWFOLDER:
1851 return OnExplorerCommand(dwCmdID, FALSE);
1852 default:
1853 /* WM_COMMAND messages from the file menu are routed to the CDefView so as to let m_pCM handle the command */
1854 if (m_pCM && dwCmd == 0)
1855 {
1856 InvokeContextMenuCommand(dwCmdID);
1857 }
1858 }
1859
1860 return 0;
1861 }
1862
1863 static BOOL
1864 SelectExtOnRename(void)
1865 {
1866 HKEY hKey;
1867 LONG error;
1868 DWORD dwValue = FALSE, cbValue;
1869
1870 error = RegOpenKeyExW(HKEY_CURRENT_USER,
1871 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer",
1872 0, KEY_READ, &hKey);
1873 if (error)
1874 return dwValue;
1875
1876 cbValue = sizeof(dwValue);
1877 RegQueryValueExW(hKey, L"SelectExtOnRename", NULL, NULL, (LPBYTE)&dwValue, &cbValue);
1878
1879 RegCloseKey(hKey);
1880 return !!dwValue;
1881 }
1882
1883 /**********************************************************
1884 * ShellView_OnNotify()
1885 */
1886
1887 LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1888 {
1889 UINT CtlID;
1890 LPNMHDR lpnmh;
1891 LPNMLISTVIEW lpnmlv;
1892 NMLVDISPINFOW *lpdi;
1893 PCUITEMID_CHILD pidl;
1894 BOOL unused;
1895
1896 CtlID = wParam;
1897 lpnmh = (LPNMHDR)lParam;
1898 lpnmlv = (LPNMLISTVIEW)lpnmh;
1899 lpdi = (NMLVDISPINFOW *)lpnmh;
1900
1901 TRACE("%p CtlID=%u lpnmh->code=%x\n", this, CtlID, lpnmh->code);
1902
1903 switch (lpnmh->code)
1904 {
1905 case NM_SETFOCUS:
1906 TRACE("-- NM_SETFOCUS %p\n", this);
1907 OnSetFocus(0, 0, 0, unused);
1908 break;
1909
1910 case NM_KILLFOCUS:
1911 TRACE("-- NM_KILLFOCUS %p\n", this);
1912 OnDeactivate();
1913 /* Notify the ICommDlgBrowser interface */
1914 OnStateChange(CDBOSC_KILLFOCUS);
1915 break;
1916
1917 case NM_CUSTOMDRAW:
1918 TRACE("-- NM_CUSTOMDRAW %p\n", this);
1919 return CDRF_DODEFAULT;
1920
1921 case NM_RELEASEDCAPTURE:
1922 TRACE("-- NM_RELEASEDCAPTURE %p\n", this);
1923 break;
1924
1925 case NM_CLICK:
1926 TRACE("-- NM_CLICK %p\n", this);
1927 break;
1928
1929 case NM_RCLICK:
1930 TRACE("-- NM_RCLICK %p\n", this);
1931 break;
1932
1933 case NM_DBLCLK:
1934 TRACE("-- NM_DBLCLK %p\n", this);
1935 OpenSelectedItems();
1936 break;
1937
1938 case NM_RETURN:
1939 TRACE("-- NM_RETURN %p\n", this);
1940 OpenSelectedItems();
1941 break;
1942
1943 case HDN_ENDTRACKW:
1944 TRACE("-- HDN_ENDTRACKW %p\n", this);
1945 /*nColumn1 = m_ListView.GetColumnWidth(0);
1946 nColumn2 = m_ListView.GetColumnWidth(1);*/
1947 break;
1948
1949 case LVN_DELETEITEM:
1950 TRACE("-- LVN_DELETEITEM %p\n", this);
1951
1952 /*delete the pidl because we made a copy of it*/
1953 SHFree(reinterpret_cast<LPVOID>(lpnmlv->lParam));
1954
1955 break;
1956
1957 case LVN_DELETEALLITEMS:
1958 TRACE("-- LVN_DELETEALLITEMS %p\n", this);
1959 return FALSE;
1960
1961 case LVN_INSERTITEM:
1962 TRACE("-- LVN_INSERTITEM (STUB)%p\n", this);
1963 break;
1964
1965 case LVN_ITEMACTIVATE:
1966 TRACE("-- LVN_ITEMACTIVATE %p\n", this);
1967 OnStateChange(CDBOSC_SELCHANGE); /* the browser will get the IDataObject now */
1968 break;
1969
1970 case LVN_COLUMNCLICK:
1971 m_sortInfo.nHeaderID = lpnmlv->iSubItem;
1972 if (m_sortInfo.nLastHeaderID == m_sortInfo.nHeaderID)
1973 m_sortInfo.bIsAscending = !m_sortInfo.bIsAscending;
1974 else
1975 m_sortInfo.bIsAscending = TRUE;
1976 _Sort();
1977 break;
1978
1979 case LVN_GETDISPINFOA:
1980 case LVN_GETDISPINFOW:
1981 TRACE("-- LVN_GETDISPINFO %p\n", this);
1982 pidl = _PidlByItem(lpdi->item);
1983
1984 if (lpdi->item.mask & LVIF_TEXT) /* text requested */
1985 {
1986 if (m_pSF2Parent)
1987 {
1988 SHELLDETAILS sd;
1989 if (FAILED_UNEXPECTEDLY(m_pSF2Parent->GetDetailsOf(pidl, lpdi->item.iSubItem, &sd)))
1990 break;
1991
1992 if (lpnmh->code == LVN_GETDISPINFOA)
1993 {
1994 /* shouldn't happen */
1995 NMLVDISPINFOA *lpdiA = (NMLVDISPINFOA *)lpnmh;
1996 StrRetToStrNA( lpdiA->item.pszText, lpdiA->item.cchTextMax, &sd.str, NULL);
1997 TRACE("-- text=%s\n", lpdiA->item.pszText);
1998 }
1999 else /* LVN_GETDISPINFOW */
2000 {
2001 StrRetToStrNW( lpdi->item.pszText, lpdi->item.cchTextMax, &sd.str, NULL);
2002 TRACE("-- text=%s\n", debugstr_w(lpdi->item.pszText));
2003 }
2004 }
2005 else
2006 {
2007 FIXME("no m_pSF2Parent\n");
2008 }
2009 }
2010 if(lpdi->item.mask & LVIF_IMAGE) /* image requested */
2011 {
2012 lpdi->item.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
2013 }
2014 if(lpdi->item.mask & LVIF_STATE)
2015 {
2016 ULONG attributes = SFGAO_HIDDEN;
2017 if (SUCCEEDED(m_pSFParent->GetAttributesOf(1, &pidl, &attributes)))
2018 {
2019 if (attributes & SFGAO_HIDDEN)
2020 {
2021 lpdi->item.state |= LVIS_CUT;
2022 }
2023 }
2024 }
2025 lpdi->item.mask |= LVIF_DI_SETITEM;
2026 break;
2027
2028 case LVN_ITEMCHANGED:
2029 TRACE("-- LVN_ITEMCHANGED %p\n", this);
2030 OnStateChange(CDBOSC_SELCHANGE); /* the browser will get the IDataObject now */
2031 UpdateStatusbar();
2032 _DoFolderViewCB(SFVM_SELECTIONCHANGED, NULL/* FIXME */, NULL/* FIXME */);
2033 break;
2034
2035 case LVN_BEGINDRAG:
2036 case LVN_BEGINRDRAG:
2037 TRACE("-- LVN_BEGINDRAG\n");
2038
2039 if (GetSelections())
2040 {
2041 CComPtr<IDataObject> pda;
2042 DWORD dwAttributes = SFGAO_CANCOPY | SFGAO_CANLINK;
2043 DWORD dwEffect = DROPEFFECT_MOVE;
2044
2045 if (SUCCEEDED(m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, IID_NULL_PPV_ARG(IDataObject, &pda))))
2046 {
2047 LPNMLISTVIEW params = (LPNMLISTVIEW)lParam;
2048
2049 if (SUCCEEDED(m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &dwAttributes)))
2050 {
2051 dwEffect |= dwAttributes & (SFGAO_CANCOPY | SFGAO_CANLINK);
2052 }
2053
2054 CComPtr<IAsyncOperation> piaso;
2055 if (SUCCEEDED(pda->QueryInterface(IID_PPV_ARG(IAsyncOperation, &piaso))))
2056 {
2057 piaso->SetAsyncMode(TRUE);
2058 }
2059
2060 DWORD dwEffect2;
2061
2062 m_pSourceDataObject = pda;
2063 m_ptFirstMousePos = params->ptAction;
2064 ClientToScreen(&m_ptFirstMousePos);
2065 ::ClientToListView(m_ListView, &m_ptFirstMousePos);
2066
2067 HIMAGELIST big_icons, small_icons;
2068 Shell_GetImageLists(&big_icons, &small_icons);
2069 PCUITEMID_CHILD pidl = _PidlByItem(params->iItem);
2070 int iIcon = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
2071 POINT ptItem;
2072 m_ListView.GetItemPosition(params->iItem, &ptItem);
2073
2074 ImageList_BeginDrag(big_icons, iIcon, params->ptAction.x - ptItem.x, params->ptAction.y - ptItem.y);
2075
2076 DoDragDrop(pda, this, dwEffect, &dwEffect2);
2077
2078 m_pSourceDataObject.Release();
2079 }
2080 }
2081 break;
2082
2083 case LVN_BEGINLABELEDITW:
2084 {
2085 DWORD dwAttr = SFGAO_CANRENAME;
2086 pidl = _PidlByItem(lpdi->item);
2087
2088 TRACE("-- LVN_BEGINLABELEDITW %p\n", this);
2089
2090 m_pSFParent->GetAttributesOf(1, &pidl, &dwAttr);
2091 if (SFGAO_CANRENAME & dwAttr)
2092 {
2093 HWND hEdit = reinterpret_cast<HWND>(m_ListView.SendMessage(LVM_GETEDITCONTROL));
2094 SHLimitInputEdit(hEdit, m_pSFParent);
2095
2096 /* smartass-renaming: See CORE-15242 */
2097 if (!(dwAttr & SFGAO_FOLDER) && (dwAttr & SFGAO_FILESYSTEM) &&
2098 (lpdi->item.mask & LVIF_TEXT) && !SelectExtOnRename())
2099 {
2100 WCHAR szFullPath[MAX_PATH];
2101 PIDLIST_ABSOLUTE pidlFull = ILCombine(m_pidlParent, pidl);
2102 SHGetPathFromIDListW(pidlFull, szFullPath);
2103
2104 if (!SHELL_FS_HideExtension(szFullPath))
2105 {
2106 LPWSTR pszText = lpdi->item.pszText;
2107 LPWSTR pchDotExt = PathFindExtensionW(pszText);
2108 ::PostMessageW(hEdit, EM_SETSEL, 0, pchDotExt - pszText);
2109 ::PostMessageW(hEdit, EM_SCROLLCARET, 0, 0);
2110 }
2111
2112 ILFree(pidlFull);
2113 }
2114
2115 m_isEditing = TRUE;
2116 return FALSE;
2117 }
2118
2119 return TRUE;
2120 }
2121
2122 case LVN_ENDLABELEDITW:
2123 {
2124 TRACE("-- LVN_ENDLABELEDITW %p\n", this);
2125
2126 m_isEditing = FALSE;
2127
2128 if (lpdi->item.pszText)
2129 {
2130 HRESULT hr;
2131 LVITEMW lvItem;
2132
2133 pidl = _PidlByItem(lpdi->item);
2134 PITEMID_CHILD pidlNew = NULL;
2135 hr = m_pSFParent->SetNameOf(0, pidl, lpdi->item.pszText, SHGDN_INFOLDER, &pidlNew);
2136
2137 if (SUCCEEDED(hr) && pidlNew)
2138 {
2139 lvItem.mask = LVIF_PARAM|LVIF_IMAGE;
2140 lvItem.iItem = lpdi->item.iItem;
2141 lvItem.iSubItem = 0;
2142 lvItem.lParam = reinterpret_cast<LPARAM>(pidlNew);
2143 lvItem.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidlNew, 0);
2144 m_ListView.SetItem(&lvItem);
2145 m_ListView.Update(lpdi->item.iItem);
2146 return TRUE;
2147 }
2148 }
2149
2150 return FALSE;
2151 }
2152
2153 default:
2154 TRACE("-- %p WM_COMMAND %x unhandled\n", this, lpnmh->code);
2155 break;
2156 }
2157
2158 return 0;
2159 }
2160
2161 /*
2162 * This is just a quick hack to make the desktop work correctly.
2163 * ITranslateShellChangeNotify's IsChildID is undocumented, but most likely the way that
2164 * a folder should know if it should update upon a change notification.
2165 * It is exported by merged folders at a minimum.
2166 */
2167 static BOOL ILIsParentOrSpecialParent(PCIDLIST_ABSOLUTE pidl1, PCIDLIST_ABSOLUTE pidl2)
2168 {
2169 if (!pidl1 || !pidl2)
2170 return FALSE;
2171 if (ILIsParent(pidl1, pidl2, TRUE))
2172 return TRUE;
2173
2174 if (_ILIsDesktop(pidl1))
2175 {
2176 PIDLIST_ABSOLUTE deskpidl;
2177 SHGetFolderLocation(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 0, &deskpidl);
2178 if (ILIsParent(deskpidl, pidl2, TRUE))
2179 {
2180 ILFree(deskpidl);
2181 return TRUE;
2182 }
2183 ILFree(deskpidl);
2184 SHGetFolderLocation(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL, 0, &deskpidl);
2185 if (ILIsParent(deskpidl, pidl2, TRUE))
2186 {
2187 ILFree(deskpidl);
2188 return TRUE;
2189 }
2190 ILFree(deskpidl);
2191 }
2192
2193 WCHAR szPath1[MAX_PATH], szPath2[MAX_PATH];
2194 LPITEMIDLIST pidl2Clone = ILClone(pidl2);
2195 ILRemoveLastID(pidl2Clone);
2196 if (SHGetPathFromIDListW(pidl1, szPath1) &&
2197 SHGetPathFromIDListW(pidl2Clone, szPath2))
2198 {
2199 if (lstrcmpiW(szPath1, szPath2) == 0)
2200 {
2201 ILFree(pidl2Clone);
2202 return TRUE;
2203 }
2204 }
2205 ILFree(pidl2Clone);
2206
2207 return FALSE;
2208 }
2209
2210 /**********************************************************
2211 * ShellView_OnChange()
2212 */
2213 LRESULT CDefView::OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2214 {
2215 HANDLE hChange = (HANDLE)wParam;
2216 DWORD dwProcID = (DWORD)lParam;
2217 PIDLIST_ABSOLUTE *Pidls;
2218 LONG lEvent;
2219 HANDLE hLock = SHChangeNotification_Lock(hChange, dwProcID, &Pidls, &lEvent);
2220 if (hLock == NULL)
2221 {
2222 ERR("hLock == NULL\n");
2223 return FALSE;
2224 }
2225
2226 BOOL bParent0 = ILIsParentOrSpecialParent(m_pidlParent, Pidls[0]);
2227 BOOL bParent1 = ILIsParentOrSpecialParent(m_pidlParent, Pidls[1]);
2228
2229 TRACE("(%p)(%p,%p,0x%08x)\n", this, Pidls[0], Pidls[1], lParam);
2230
2231 lEvent &= ~SHCNE_INTERRUPT;
2232 switch (lEvent)
2233 {
2234 case SHCNE_MKDIR:
2235 case SHCNE_CREATE:
2236 if (bParent0)
2237 {
2238 if (LV_FindItemByPidl(ILFindLastID(Pidls[0])) == -1)
2239 {
2240 LV_AddItem(ILFindLastID(Pidls[0]));
2241 }
2242 else
2243 {
2244 LV_ProdItem(ILFindLastID(Pidls[0]));
2245 }
2246 }
2247 break;
2248
2249 case SHCNE_RMDIR:
2250 case SHCNE_DELETE:
2251 if (bParent0)
2252 LV_DeleteItem(ILFindLastID(Pidls[0]));
2253 break;
2254
2255 case SHCNE_RENAMEFOLDER:
2256 case SHCNE_RENAMEITEM:
2257 if (bParent0 && bParent1)
2258 LV_RenameItem(ILFindLastID(Pidls[0]), ILFindLastID(Pidls[1]));
2259 else if (bParent0)
2260 LV_DeleteItem(ILFindLastID(Pidls[0]));
2261 else if (bParent1)
2262 LV_AddItem(ILFindLastID(Pidls[1]));
2263 break;
2264
2265 case SHCNE_UPDATEITEM:
2266 if (bParent0)
2267 LV_RenameItem(ILFindLastID(Pidls[0]), ILFindLastID(Pidls[0]));
2268 break;
2269
2270 case SHCNE_UPDATEDIR:
2271 Refresh();
2272 break;
2273 }
2274
2275 SHChangeNotification_Unlock(hLock);
2276 return TRUE;
2277 }
2278
2279 HRESULT SHGetMenuIdFromMenuMsg(UINT uMsg, LPARAM lParam, UINT *CmdId);
2280 HRESULT SHSetMenuIdInMenuMsg(UINT uMsg, LPARAM lParam, UINT CmdId);
2281
2282 /**********************************************************
2283 * CDefView::OnCustomItem
2284 */
2285 LRESULT CDefView::OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2286 {
2287 if (!m_pCM.p)
2288 {
2289 /* no menu */
2290 ERR("no menu!!!\n");
2291 return FALSE;
2292 }
2293
2294 /* The lParam of WM_DRAWITEM WM_MEASUREITEM contain a menu id and this also needs to
2295 be changed to a menu identifier offset */
2296 UINT CmdID;
2297 HRESULT hres = SHGetMenuIdFromMenuMsg(uMsg, lParam, &CmdID);
2298 if (SUCCEEDED(hres))
2299 SHSetMenuIdInMenuMsg(uMsg, lParam, CmdID - CONTEXT_MENU_BASE_ID);
2300
2301 /* Forward the message to the IContextMenu2 */
2302 LRESULT result;
2303 hres = SHForwardContextMenuMsg(m_pCM, uMsg, wParam, lParam, &result, TRUE);
2304
2305 return (SUCCEEDED(hres));
2306 }
2307
2308 LRESULT CDefView::OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2309 {
2310 /* Wallpaper setting affects drop shadows effect */
2311 if (wParam == SPI_SETDESKWALLPAPER || wParam == 0)
2312 UpdateListColors();
2313
2314 return S_OK;
2315 }
2316
2317 /**********************************************************
2318 * CDefView::OnInitMenuPopup
2319 */
2320 LRESULT CDefView::OnInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2321 {
2322 HMENU hmenu = (HMENU) wParam;
2323 int nPos = LOWORD(lParam);
2324 UINT menuItemId;
2325
2326 OnCustomItem(uMsg, wParam, lParam, bHandled);
2327
2328 HMENU hViewMenu = GetSubmenuByID(m_hMenu, FCIDM_MENU_VIEW);
2329
2330 if (GetSelections() == 0)
2331 {
2332 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_CUT, MF_GRAYED);
2333 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_COPY, MF_GRAYED);
2334 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_RENAME, MF_GRAYED);
2335 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_COPYTO, MF_GRAYED);
2336 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_MOVETO, MF_GRAYED);
2337 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_DELETE, MF_GRAYED);
2338 }
2339 else
2340 {
2341 // FIXME: Check copyable
2342 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_CUT, MF_ENABLED);
2343 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_COPY, MF_ENABLED);
2344 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_RENAME, MF_ENABLED);
2345 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_COPYTO, MF_ENABLED);
2346 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_MOVETO, MF_ENABLED);
2347 ::EnableMenuItem(hmenu, FCIDM_SHVIEW_DELETE, MF_ENABLED);
2348 }
2349
2350 /* Lets try to find out what the hell wParam is */
2351 if (hmenu == GetSubMenu(m_hMenu, nPos))
2352 menuItemId = ReallyGetMenuItemID(m_hMenu, nPos);
2353 else if (hViewMenu && hmenu == GetSubMenu(hViewMenu, nPos))
2354 menuItemId = ReallyGetMenuItemID(hViewMenu, nPos);
2355 else if (m_hContextMenu && hmenu == GetSubMenu(m_hContextMenu, nPos))
2356 menuItemId = ReallyGetMenuItemID(m_hContextMenu, nPos);
2357 else
2358 return FALSE;
2359
2360 switch (menuItemId)
2361 {
2362 case FCIDM_MENU_FILE:
2363 FillFileMenu();
2364 break;
2365 case FCIDM_MENU_VIEW:
2366 case FCIDM_SHVIEW_VIEW:
2367 CheckViewMode(hmenu);
2368 break;
2369 case FCIDM_SHVIEW_ARRANGE:
2370 FillArrangeAsMenu(hmenu);
2371 break;
2372 }
2373
2374 return FALSE;
2375 }
2376
2377 /**********************************************************
2378 *
2379 *
2380 * The INTERFACE of the IShellView object
2381 *
2382 *
2383 **********************************************************
2384 */
2385
2386 /**********************************************************
2387 * ShellView_GetWindow
2388 */
2389 HRESULT WINAPI CDefView::GetWindow(HWND *phWnd)
2390 {
2391 TRACE("(%p)\n", this);
2392
2393 *phWnd = m_hWnd;
2394
2395 return S_OK;
2396 }
2397
2398 HRESULT WINAPI CDefView::ContextSensitiveHelp(BOOL fEnterMode)
2399 {
2400 FIXME("(%p) stub\n", this);
2401
2402 return E_NOTIMPL;
2403 }
2404
2405 /**********************************************************
2406 * IShellView_TranslateAccelerator
2407 *
2408 * FIXME:
2409 * use the accel functions
2410 */
2411 HRESULT WINAPI CDefView::TranslateAccelerator(LPMSG lpmsg)
2412 {
2413 if (m_isEditing)
2414 return S_FALSE;
2415
2416 if (lpmsg->message >= WM_KEYFIRST && lpmsg->message <= WM_KEYLAST)
2417 {
2418 if (::TranslateAcceleratorW(m_hWnd, m_hAccel, lpmsg) != 0)
2419 return S_OK;
2420
2421 TRACE("-- key=0x%04lx\n", lpmsg->wParam) ;
2422 }
2423
2424 return m_pShellBrowser->TranslateAcceleratorSB(lpmsg, 0);
2425 }
2426
2427 HRESULT WINAPI CDefView::EnableModeless(BOOL fEnable)
2428 {
2429 FIXME("(%p) stub\n", this);
2430
2431 return E_NOTIMPL;
2432 }
2433
2434 HRESULT WINAPI CDefView::UIActivate(UINT uState)
2435 {
2436 // CHAR szName[MAX_PATH];
2437 LRESULT lResult;
2438 int nPartArray[1] = { -1};
2439
2440 TRACE("(%p)->(state=%x) stub\n", this, uState);
2441
2442 /* don't do anything if the state isn't really changing */
2443 if (m_uState == uState)
2444 {
2445 return S_OK;
2446 }
2447
2448 /* OnActivate handles the menu merging and internal state */
2449 DoActivate(uState);
2450
2451 /* only do This if we are active */
2452 if (uState != SVUIA_DEACTIVATE)
2453 {
2454
2455 /*
2456 GetFolderPath is not a method of IShellFolder
2457 IShellFolder_GetFolderPath( m_pSFParent, szName, sizeof(szName) );
2458 */
2459 /* set the number of parts */
2460 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, 1, (LPARAM)nPartArray, &lResult);
2461
2462 /* set the text for the parts */
2463 /*
2464 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXTA, 0, (LPARAM)szName, &lResult);
2465 */
2466 }
2467
2468 return S_OK;
2469 }
2470
2471 HRESULT WINAPI CDefView::Refresh()
2472 {
2473 TRACE("(%p)\n", this);
2474
2475 _DoFolderViewCB(SFVM_LISTREFRESHED, TRUE, 0);
2476
2477 m_ListView.DeleteAllItems();
2478 FillList();
2479
2480 return S_OK;
2481 }
2482
2483 HRESULT WINAPI CDefView::CreateViewWindow(IShellView *lpPrevView, LPCFOLDERSETTINGS lpfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd)
2484 {
2485 return CreateViewWindow3(psb, lpPrevView, SV3CVW3_DEFAULT,
2486 (FOLDERFLAGS)lpfs->fFlags, (FOLDERFLAGS)lpfs->fFlags, (FOLDERVIEWMODE)lpfs->ViewMode, NULL, prcView, phWnd);
2487 }
2488
2489 HRESULT WINAPI CDefView::DestroyViewWindow()
2490 {
2491 TRACE("(%p)\n", this);
2492
2493 /* Make absolutely sure all our UI is cleaned up */
2494 UIActivate(SVUIA_DEACTIVATE);
2495
2496 if (m_hAccel)
2497 {
2498 // "Accelerator tables loaded from resources are freed automatically when the application terminates." -- MSDN
2499 m_hAccel = NULL;
2500 }
2501
2502 if (m_hMenuArrangeModes)
2503 {
2504 DestroyMenu(m_hMenuArrangeModes);
2505 m_hMenuArrangeModes = NULL;
2506 }
2507
2508 if (m_hMenuViewModes)
2509 {
2510 DestroyMenu(m_hMenuViewModes);
2511 m_hMenuViewModes = NULL;
2512 }
2513
2514 if (m_hMenu)
2515 {
2516 DestroyMenu(m_hMenu);
2517 m_hMenu = NULL;
2518 }
2519
2520 if (m_ListView)
2521 {
2522 m_ListView.DestroyWindow();
2523 }
2524
2525 if (m_hWnd)
2526 {
2527 _DoFolderViewCB(SFVM_WINDOWCLOSING, (WPARAM)m_hWnd, 0);
2528 DestroyWindow();
2529 }
2530
2531 m_pShellBrowser.Release();
2532 m_pCommDlgBrowser.Release();
2533
2534 return S_OK;
2535 }
2536
2537 HRESULT WINAPI CDefView::GetCurrentInfo(LPFOLDERSETTINGS lpfs)
2538 {
2539 TRACE("(%p)->(%p) vmode=%x flags=%x\n", this, lpfs,
2540 m_FolderSettings.ViewMode, m_FolderSettings.fFlags);
2541
2542 if (!lpfs)
2543 return E_INVALIDARG;
2544
2545 *lpfs = m_FolderSettings;
2546 return S_OK;
2547 }
2548
2549 HRESULT WINAPI CDefView::AddPropertySheetPages(DWORD dwReserved, LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam)
2550 {
2551 FIXME("(%p) stub\n", this);
2552
2553 return E_NOTIMPL;
2554 }
2555
2556 HRESULT WINAPI CDefView::SaveViewState()
2557 {
2558 FIXME("(%p) stub\n", this);
2559
2560 return S_OK;
2561 }
2562
2563 HRESULT WINAPI CDefView::SelectItem(PCUITEMID_CHILD pidl, UINT uFlags)
2564 {
2565 int i;
2566
2567 TRACE("(%p)->(pidl=%p, 0x%08x) stub\n", this, pidl, uFlags);
2568
2569 i = LV_FindItemByPidl(pidl);
2570 if (i == -1)
2571 return S_OK;
2572
2573 LVITEMW lvItem = {0};
2574 lvItem.mask = LVIF_STATE;
2575 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
2576
2577 while (m_ListView.GetItem(&lvItem))
2578 {
2579 if (lvItem.iItem == i)
2580 {
2581 if (uFlags & SVSI_SELECT)
2582 lvItem.state |= LVIS_SELECTED;
2583 else
2584 lvItem.state &= ~LVIS_SELECTED;
2585
2586 if (uFlags & SVSI_FOCUSED)
2587 lvItem.state |= LVIS_FOCUSED;
2588 else
2589 lvItem.state &= ~LVIS_FOCUSED;
2590 }
2591 else
2592 {
2593 if (uFlags & SVSI_DESELECTOTHERS)
2594 {
2595 lvItem.state &= ~LVIS_SELECTED;
2596 }
2597 lvItem.state &= ~LVIS_FOCUSED;
2598 }
2599
2600 m_ListView.SetItem(&lvItem);
2601 lvItem.iItem++;
2602 }
2603
2604 if (uFlags & SVSI_ENSUREVISIBLE)
2605 m_ListView.EnsureVisible(i, FALSE);
2606
2607 if((uFlags & SVSI_EDIT) == SVSI_EDIT)
2608 m_ListView.EditLabel(i);
2609
2610 return S_OK;
2611 }
2612
2613 HRESULT WINAPI CDefView::GetItemObject(UINT uItem, REFIID riid, LPVOID *ppvOut)
2614 {
2615 HRESULT hr = E_NOINTERFACE;
2616
2617 TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n", this, uItem, debugstr_guid(&riid), ppvOut);
2618
2619 if (!ppvOut)
2620 return E_INVALIDARG;
2621
2622 *ppvOut = NULL;
2623
2624 switch (uItem)
2625 {
2626 case SVGIO_BACKGROUND:
2627 if (IsEqualIID(riid, IID_IContextMenu))
2628 {
2629 hr = CDefViewBckgrndMenu_CreateInstance(m_pSF2Parent, riid, ppvOut);
2630 if (FAILED_UNEXPECTEDLY(hr))
2631 return hr;
2632
2633 IUnknown_SetSite(*((IUnknown**)ppvOut), (IShellView *)this);
2634 }
2635 else if (IsEqualIID(riid, IID_IDispatch))
2636 {
2637 if (m_pShellFolderViewDual == NULL)
2638 {
2639 hr = CDefViewDual_Constructor(riid, (LPVOID*)&m_pShellFolderViewDual);
2640 if (FAILED_UNEXPECTEDLY(hr))
2641 return hr;
2642 }
2643 hr = m_pShellFolderViewDual->QueryInterface(riid, ppvOut);
2644 }
2645 break;
2646
2647 case SVGIO_SELECTION:
2648 GetSelections();
2649 hr = m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, riid, 0, ppvOut);
2650 if (FAILED_UNEXPECTEDLY(hr))
2651 return hr;
2652
2653 if (IsEqualIID(riid, IID_IContextMenu))
2654 IUnknown_SetSite(*((IUnknown**)ppvOut), (IShellView *)this);
2655
2656 break;
2657 }
2658
2659 TRACE("-- (%p)->(interface=%p)\n", this, *ppvOut);
2660
2661 return hr;
2662 }
2663
2664 HRESULT STDMETHODCALLTYPE CDefView::GetCurrentViewMode(UINT *pViewMode)
2665 {
2666 TRACE("(%p)->(%p), stub\n", this, pViewMode);
2667
2668 if (!pViewMode)
2669 return E_INVALIDARG;
2670
2671 *pViewMode = m_FolderSettings.ViewMode;
2672 return S_OK;
2673 }
2674
2675 HRESULT STDMETHODCALLTYPE CDefView::SetCurrentViewMode(UINT ViewMode)
2676 {
2677 DWORD dwStyle;
2678 TRACE("(%p)->(%u), stub\n", this, ViewMode);
2679
2680 /* It's not redundant to check FVM_AUTO because it's a (UINT)-1 */
2681 if (((INT)ViewMode < FVM_FIRST || (INT)ViewMode > FVM_LAST) && ((INT)ViewMode != FVM_AUTO))
2682 return E_INVALIDARG;
2683
2684 /* Windows before Vista uses LVM_SETVIEW and possibly
2685 LVM_SETEXTENDEDLISTVIEWSTYLE to set the style of the listview,
2686 while later versions seem to accomplish this through other
2687 means. */
2688 switch (ViewMode)
2689 {
2690 case FVM_ICON:
2691 dwStyle = LVS_ICON;
2692 break;
2693 case FVM_DETAILS:
2694 dwStyle = LVS_REPORT;
2695 break;
2696 case FVM_SMALLICON:
2697 dwStyle = LVS_SMALLICON;
2698 break;
2699 case FVM_LIST:
2700 dwStyle = LVS_LIST;
2701 break;
2702 default:
2703 {
2704 FIXME("ViewMode %d not implemented\n", ViewMode);
2705 dwStyle = LVS_LIST;
2706 break;
2707 }
2708 }
2709
2710 m_ListView.ModifyStyle(LVS_TYPEMASK, dwStyle);
2711
2712 /* This will not necessarily be the actual mode set above.
2713 This mimics the behavior of Windows XP. */
2714 m_FolderSettings.ViewMode = ViewMode;
2715
2716 return S_OK;
2717 }
2718
2719 HRESULT STDMETHODCALLTYPE CDefView::GetFolder(REFIID riid, void **ppv)
2720 {
2721 if (m_pSFParent == NULL)
2722 return E_FAIL;
2723
2724 return m_pSFParent->QueryInterface(riid, ppv);
2725 }
2726
2727 HRESULT STDMETHODCALLTYPE CDefView::Item(int iItemIndex, PITEMID_CHILD *ppidl)
2728 {
2729 PCUITEMID_CHILD pidl = _PidlByItem(iItemIndex);
2730 if (pidl)
2731 {
2732 *ppidl = ILClone(pidl);
2733 return S_OK;
2734 }
2735
2736 *ppidl = 0;
2737 return E_INVALIDARG;
2738 }
2739
2740 HRESULT STDMETHODCALLTYPE CDefView::ItemCount(UINT uFlags, int *pcItems)
2741 {
2742 TRACE("(%p)->(%u %p)\n", this, uFlags, pcItems);
2743
2744 if (uFlags != SVGIO_ALLVIEW)
2745 FIXME("some flags unsupported, %x\n", uFlags & ~SVGIO_ALLVIEW);
2746
2747 *pcItems = m_ListView.GetItemCount();
2748
2749 return S_OK;
2750 }
2751
2752 HRESULT STDMETHODCALLTYPE CDefView::Items(UINT uFlags, REFIID riid, void **ppv)
2753 {
2754 return E_NOTIMPL;
2755 }
2756
2757 HRESULT STDMETHODCALLTYPE CDefView::GetSelectionMarkedItem(int *piItem)
2758 {
2759 TRACE("(%p)->(%p)\n", this, piItem);
2760
2761 *piItem = m_ListView.GetSelectionMark();
2762
2763 return S_OK;
2764 }
2765
2766 HRESULT STDMETHODCALLTYPE CDefView::GetFocusedItem(int *piItem)
2767 {
2768 TRACE("(%p)->(%p)\n", this, piItem);
2769
2770 *piItem = m_ListView.GetNextItem(-1, LVNI_FOCUSED);
2771
2772 return S_OK;
2773 }
2774
2775 HRESULT STDMETHODCALLTYPE CDefView::GetItemPosition(PCUITEMID_CHILD pidl, POINT *ppt)
2776 {
2777 int lvIndex = LV_FindItemByPidl(pidl);
2778 if (lvIndex == -1 || ppt == NULL)
2779 return E_INVALIDARG;
2780
2781 m_ListView.GetItemPosition(lvIndex, ppt);
2782 return S_OK;
2783 }
2784
2785 HRESULT STDMETHODCALLTYPE CDefView::GetSpacing(POINT *ppt)
2786 {
2787 TRACE("(%p)->(%p)\n", this, ppt);
2788
2789 if (!m_ListView)
2790 return S_FALSE;
2791
2792 if (ppt)
2793 {
2794 SIZE spacing;
2795 m_ListView.GetItemSpacing(spacing);
2796
2797 ppt->x = spacing.cx;
2798 ppt->y = spacing.cy;
2799 }
2800
2801 return S_OK;
2802 }
2803
2804 HRESULT STDMETHODCALLTYPE CDefView::GetDefaultSpacing(POINT *ppt)
2805 {
2806 return E_NOTIMPL;
2807 }
2808
2809 HRESULT STDMETHODCALLTYPE CDefView::GetAutoArrange()
2810 {
2811 return ((m_ListView.GetStyle() & LVS_AUTOARRANGE) ? S_OK : S_FALSE);
2812 }
2813
2814 HRESULT CDefView::_GetSnapToGrid()
2815 {
2816 DWORD dwExStyle = (DWORD)m_ListView.SendMessage(LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
2817 return ((dwExStyle & LVS_EX_SNAPTOGRID) ? S_OK : S_FALSE);
2818 }
2819
2820 HRESULT STDMETHODCALLTYPE CDefView::SelectItem(int iItem, DWORD dwFlags)
2821 {
2822 LVITEMW lvItem;
2823
2824 TRACE("(%p)->(%d, %x)\n", this, iItem, dwFlags);
2825
2826 lvItem.state = 0;
2827 lvItem.stateMask = LVIS_SELECTED;
2828
2829 if (dwFlags & SVSI_ENSUREVISIBLE)
2830 m_ListView.EnsureVisible(iItem, 0);
2831
2832 /* all items */
2833 if (dwFlags & SVSI_DESELECTOTHERS)
2834 m_ListView.SetItemState(-1, 0, LVIS_SELECTED);
2835
2836 /* this item */
2837 if (dwFlags & SVSI_SELECT)
2838 lvItem.state |= LVIS_SELECTED;
2839
2840 if (dwFlags & SVSI_FOCUSED)
2841 lvItem.stateMask |= LVIS_FOCUSED;
2842
2843 m_ListView.SetItemState(iItem, lvItem.state, lvItem.stateMask);
2844
2845 if ((dwFlags & SVSI_EDIT) == SVSI_EDIT)
2846 m_ListView.EditLabel(iItem);
2847
2848 return S_OK;
2849 }
2850
2851 HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItems(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, POINT *apt, DWORD dwFlags)
2852 {
2853 /* Reset the selection */
2854 m_ListView.SetItemState(-1, 0, LVIS_SELECTED);
2855
2856 int lvIndex;
2857 for (UINT i = 0 ; i < m_cidl; i++)
2858 {
2859 lvIndex = LV_FindItemByPidl(apidl[i]);
2860 if (lvIndex != -1)
2861 {
2862 SelectItem(lvIndex, dwFlags);
2863 m_ListView.SetItemPosition(lvIndex, &apt[i]);
2864 }
2865 }
2866
2867 return S_OK;
2868 }
2869
2870 /**********************************************************
2871 * IShellView2 implementation
2872 */
2873
2874 HRESULT STDMETHODCALLTYPE CDefView::GetView(SHELLVIEWID *view_guid, ULONG view_type)
2875 {
2876 FIXME("(%p)->(%p, %lu) stub\n", this, view_guid, view_type);
2877 return E_NOTIMPL;
2878 }
2879
2880 HRESULT STDMETHODCALLTYPE CDefView::CreateViewWindow2(LPSV2CVW2_PARAMS view_params)
2881 {
2882 return CreateViewWindow3(view_params->psbOwner, view_params->psvPrev,
2883 SV3CVW3_DEFAULT, (FOLDERFLAGS)view_params->pfs->fFlags, (FOLDERFLAGS)view_params->pfs->fFlags,
2884 (FOLDERVIEWMODE)view_params->pfs->ViewMode, view_params->pvid, view_params->prcView, &view_params->hwndView);
2885 }
2886
2887 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)
2888 {
2889 OLEMENUGROUPWIDTHS omw = { { 0, 0, 0, 0, 0, 0 } };
2890
2891 *hwnd = NULL;
2892
2893 TRACE("(%p)->(shlview=%p shlbrs=%p rec=%p hwnd=%p vmode=%x flags=%x)\n", this, psvPrevious, psb, prcView, hwnd, mode, flags);
2894 if (prcView != NULL)
2895 TRACE("-- left=%i top=%i right=%i bottom=%i\n", prcView->left, prcView->top, prcView->right, prcView->bottom);
2896
2897 /* Validate the Shell Browser */
2898 if (psb == NULL || m_hWnd)
2899 return E_UNEXPECTED;
2900
2901 if (view_flags != SV3CVW3_DEFAULT)
2902 FIXME("unsupported view flags 0x%08x\n", view_flags);
2903
2904 /* Set up the member variables */
2905 m_pShellBrowser = psb;
2906 m_FolderSettings.ViewMode = mode;
2907 m_FolderSettings.fFlags = mask & flags;
2908
2909 if (view_id)
2910 {
2911 if (IsEqualIID(*view_id, VID_LargeIcons))
2912 m_FolderSettings.ViewMode = FVM_ICON;
2913 else if (IsEqualIID(*view_id, VID_SmallIcons))
2914 m_FolderSettings.ViewMode = FVM_SMALLICON;
2915 else if (IsEqualIID(*view_id, VID_List))
2916 m_FolderSettings.ViewMode = FVM_LIST;
2917 else if (IsEqualIID(*view_id, VID_Details))
2918 m_FolderSettings.ViewMode = FVM_DETAILS;
2919 else if (IsEqualIID(*view_id, VID_Thumbnails))
2920 m_FolderSettings.ViewMode = FVM_THUMBNAIL;
2921 else if (IsEqualIID(*view_id, VID_Tile))
2922 m_FolderSettings.ViewMode = FVM_TILE;
2923 else if (IsEqualIID(*view_id, VID_ThumbStrip))
2924 m_FolderSettings.ViewMode = FVM_THUMBSTRIP;
2925 else
2926 FIXME("Ignoring unrecognized VID %s\n", debugstr_guid(view_id));
2927 }
2928
2929 /* Get our parent window */
2930 m_pShellBrowser->GetWindow(&m_hWndParent);
2931
2932 /* Try to get the ICommDlgBrowserInterface, adds a reference !!! */
2933 m_pCommDlgBrowser = NULL;
2934 if (SUCCEEDED(m_pShellBrowser->QueryInterface(IID_PPV_ARG(ICommDlgBrowser, &m_pCommDlgBrowser))))
2935 {
2936 TRACE("-- CommDlgBrowser\n");
2937 }
2938
2939 Create(m_hWndParent, prcView, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP, 0, 0U);
2940 if (m_hWnd == NULL)
2941 return E_FAIL;
2942
2943 *hwnd = m_hWnd;
2944
2945 CheckToolbar();
2946
2947 if (!*hwnd)
2948 return E_FAIL;
2949
2950 _DoFolderViewCB(SFVM_WINDOWCREATED, (WPARAM)m_hWnd, 0);
2951
2952 SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
2953 UpdateWindow();
2954
2955 if (!m_hMenu)
2956 {
2957 m_hMenu = CreateMenu();
2958 m_pShellBrowser->InsertMenusSB(m_hMenu, &omw);
2959 TRACE("-- after fnInsertMenusSB\n");
2960 }
2961
2962 _MergeToolbar();
2963
2964 return S_OK;
2965 }
2966
2967 HRESULT STDMETHODCALLTYPE CDefView::HandleRename(LPCITEMIDLIST new_pidl)
2968 {
2969 FIXME("(%p)->(%p) stub\n", this, new_pidl);
2970 return E_NOTIMPL;
2971 }
2972
2973 HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItem(LPCITEMIDLIST item, UINT flags, POINT *point)
2974 {
2975 FIXME("(%p)->(%p, %u, %p) stub\n", this, item, flags, point);
2976 return E_NOTIMPL;
2977 }
2978
2979 /**********************************************************
2980 * IShellFolderView implementation
2981 */
2982 HRESULT STDMETHODCALLTYPE CDefView::Rearrange(LPARAM sort)
2983 {
2984 FIXME("(%p)->(%ld) stub\n", this, sort);
2985 return E_NOTIMPL;
2986 }
2987
2988 HRESULT STDMETHODCALLTYPE CDefView::GetArrangeParam(LPARAM *sort)
2989 {
2990 FIXME("(%p)->(%p) stub\n", this, sort);
2991 return E_NOTIMPL;
2992 }
2993
2994 HRESULT STDMETHODCALLTYPE CDefView::ArrangeGrid()
2995 {
2996 m_ListView.SetExtendedListViewStyle(LVS_EX_SNAPTOGRID, LVS_EX_SNAPTOGRID);
2997 return S_OK;
2998 }
2999
3000 HRESULT STDMETHODCALLTYPE CDefView::AutoArrange()
3001 {
3002 m_ListView.ModifyStyle(0, LVS_AUTOARRANGE);
3003 m_ListView.Arrange(LVA_DEFAULT);
3004 return S_OK;
3005 }
3006
3007 HRESULT STDMETHODCALLTYPE CDefView::AddObject(PITEMID_CHILD pidl, UINT *item)
3008 {
3009 TRACE("(%p)->(%p %p)\n", this, pidl, item);
3010 *item = LV_AddItem(pidl);
3011 return (int)*item >= 0 ? S_OK : E_OUTOFMEMORY;
3012 }
3013
3014 HRESULT STDMETHODCALLTYPE CDefView::GetObject(PITEMID_CHILD *pidl, UINT item)
3015 {
3016 TRACE("(%p)->(%p %d)\n", this, pidl, item);
3017 return Item(item, pidl);
3018 }
3019
3020 HRESULT STDMETHODCALLTYPE CDefView::RemoveObject(PITEMID_CHILD pidl, UINT *item)
3021 {
3022
3023 TRACE("(%p)->(%p %p)\n", this, pidl, item);
3024
3025 if (pidl)
3026 {
3027 *item = LV_FindItemByPidl(ILFindLastID(pidl));
3028 m_ListView.DeleteItem(*item);
3029 }
3030 else
3031 {
3032 *item = 0;
3033 m_ListView.DeleteAllItems();
3034 }
3035
3036 return S_OK;
3037 }
3038
3039 HRESULT STDMETHODCALLTYPE CDefView::GetObjectCount(UINT *count)
3040 {
3041 TRACE("(%p)->(%p)\n", this, count);
3042 *count = m_ListView.GetItemCount();
3043 return S_OK;
3044 }
3045
3046 HRESULT STDMETHODCALLTYPE CDefView::SetObjectCount(UINT count, UINT flags)
3047 {
3048 FIXME("(%p)->(%d %x) stub\n", this, count, flags);
3049 return E_NOTIMPL;
3050 }
3051
3052 HRESULT STDMETHODCALLTYPE CDefView::UpdateObject(PITEMID_CHILD pidl_old, PITEMID_CHILD pidl_new, UINT *item)
3053 {
3054 FIXME("(%p)->(%p %p %p) stub\n", this, pidl_old, pidl_new, item);
3055 return E_NOTIMPL;
3056 }
3057
3058 HRESULT STDMETHODCALLTYPE CDefView::RefreshObject(PITEMID_CHILD pidl, UINT *item)
3059 {
3060 FIXME("(%p)->(%p %p) stub\n", this, pidl, item);
3061 return E_NOTIMPL;
3062 }
3063
3064 HRESULT STDMETHODCALLTYPE CDefView::SetRedraw(BOOL redraw)
3065 {
3066 TRACE("(%p)->(%d)\n", this, redraw);
3067 m_ListView.SetRedraw(redraw);
3068 return S_OK;
3069 }
3070
3071 HRESULT STDMETHODCALLTYPE CDefView::GetSelectedCount(UINT *count)
3072 {
3073 FIXME("(%p)->(%p) stub\n", this, count);
3074 return E_NOTIMPL;
3075 }
3076
3077 HRESULT STDMETHODCALLTYPE CDefView::GetSelectedObjects(PCUITEMID_CHILD **pidl, UINT *items)
3078 {
3079 TRACE("(%p)->(%p %p)\n", this, pidl, items);
3080
3081 *items = GetSelections();
3082
3083 if (*items)
3084 {
3085 *pidl = static_cast<PCUITEMID_CHILD *>(LocalAlloc(0, *items * sizeof(PCUITEMID_CHILD)));
3086 if (!*pidl)
3087 {
3088 return E_OUTOFMEMORY;
3089 }
3090
3091 /* it's documented that caller shouldn't PIDLs, only array itself */
3092 memcpy(*pidl, m_apidl, *items * sizeof(PCUITEMID_CHILD));
3093 }
3094
3095 return S_OK;
3096 }
3097
3098 HRESULT STDMETHODCALLTYPE CDefView::IsDropOnSource(IDropTarget *drop_target)
3099 {
3100 if ((m_iDragOverItem == -1 || m_pCurDropTarget == NULL) &&
3101 (m_pSourceDataObject.p))
3102 {
3103 return S_OK;
3104 }
3105
3106 return S_FALSE;
3107 }
3108
3109 HRESULT STDMETHODCALLTYPE CDefView::GetDragPoint(POINT *pt)
3110 {
3111 if (!pt)
3112 return E_INVALIDARG;
3113
3114 *pt = m_ptFirstMousePos;
3115 return S_OK;
3116 }
3117
3118 HRESULT STDMETHODCALLTYPE CDefView::GetDropPoint(POINT *pt)
3119 {
3120 FIXME("(%p)->(%p) stub\n", this, pt);
3121 return E_NOTIMPL;
3122 }
3123
3124 HRESULT STDMETHODCALLTYPE CDefView::MoveIcons(IDataObject *obj)
3125 {
3126 TRACE("(%p)->(%p)\n", this, obj);
3127 return E_NOTIMPL;
3128 }
3129
3130 HRESULT STDMETHODCALLTYPE CDefView::SetItemPos(PCUITEMID_CHILD pidl, POINT *pt)
3131 {
3132 FIXME("(%p)->(%p %p) stub\n", this, pidl, pt);
3133 return E_NOTIMPL;
3134 }
3135
3136 HRESULT STDMETHODCALLTYPE CDefView::IsBkDropTarget(IDropTarget *drop_target)
3137 {
3138 FIXME("(%p)->(%p) stub\n", this, drop_target);
3139 return E_NOTIMPL;
3140 }
3141
3142 HRESULT STDMETHODCALLTYPE CDefView::SetClipboard(BOOL move)
3143 {
3144 FIXME("(%p)->(%d) stub\n", this, move);
3145 return E_NOTIMPL;
3146 }
3147
3148 HRESULT STDMETHODCALLTYPE CDefView::SetPoints(IDataObject *obj)
3149 {
3150 FIXME("(%p)->(%p) stub\n", this, obj);
3151 return E_NOTIMPL;
3152 }
3153
3154 HRESULT STDMETHODCALLTYPE CDefView::GetItemSpacing(ITEMSPACING *spacing)
3155 {
3156 FIXME("(%p)->(%p) stub\n", this, spacing);
3157 return E_NOTIMPL;
3158 }
3159
3160 HRESULT STDMETHODCALLTYPE CDefView::SetCallback(IShellFolderViewCB *new_cb, IShellFolderViewCB **old_cb)
3161 {
3162 if (old_cb)
3163 *old_cb = m_pShellFolderViewCB.Detach();
3164
3165 m_pShellFolderViewCB = new_cb;
3166 return S_OK;
3167 }
3168
3169 HRESULT STDMETHODCALLTYPE CDefView::Select(UINT flags)
3170 {
3171 FIXME("(%p)->(%d) stub\n", this, flags);
3172 return E_NOTIMPL;
3173 }
3174
3175 HRESULT STDMETHODCALLTYPE CDefView::QuerySupport(UINT *support)
3176 {
3177 TRACE("(%p)->(%p)\n", this, support);
3178 return S_OK;
3179 }
3180
3181 HRESULT STDMETHODCALLTYPE CDefView::SetAutomationObject(IDispatch *disp)
3182 {
3183 FIXME("(%p)->(%p) stub\n", this, disp);
3184 return E_NOTIMPL;
3185 }
3186
3187 /**********************************************************
3188 * ISVOleCmdTarget_QueryStatus (IOleCommandTarget)
3189 */
3190 HRESULT WINAPI CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText)
3191 {
3192 FIXME("(%p)->(%p(%s) 0x%08x %p %p\n",
3193 this, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
3194
3195 if (!prgCmds)
3196 return E_INVALIDARG;
3197
3198 for (UINT i = 0; i < cCmds; i++)
3199 {
3200 FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID);
3201 prgCmds[i].cmdf = 0;
3202 }
3203
3204 return OLECMDERR_E_UNKNOWNGROUP;
3205 }
3206
3207 /**********************************************************
3208 * ISVOleCmdTarget_Exec (IOleCommandTarget)
3209 *
3210 * nCmdID is the OLECMDID_* enumeration
3211 */
3212 HRESULT WINAPI CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
3213 {
3214 FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n",
3215 this, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut);
3216
3217 if (!pguidCmdGroup)
3218 return OLECMDERR_E_UNKNOWNGROUP;
3219
3220 if (IsEqualCLSID(*pguidCmdGroup, m_Category))
3221 {
3222 if (nCmdID == FCIDM_SHVIEW_AUTOARRANGE)
3223 {
3224 if (V_VT(pvaIn) != VT_INT_PTR)
3225 return OLECMDERR_E_NOTSUPPORTED;
3226
3227 TPMPARAMS params;
3228 params.cbSize = sizeof(params);
3229 params.rcExclude = *(RECT*) V_INTREF(pvaIn);
3230
3231 if (m_hMenuViewModes)
3232 {
3233 /* Duplicate all but the last two items of the view modes menu */
3234 HMENU hmenuViewPopup = CreatePopupMenu();
3235 Shell_MergeMenus(hmenuViewPopup, m_hMenuViewModes, 0, 0, 0xFFFF, 0);
3236 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION);
3237 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION);
3238 CheckViewMode(hmenuViewPopup);
3239 TrackPopupMenuEx(hmenuViewPopup, TPM_LEFTALIGN | TPM_TOPALIGN, params.rcExclude.left, params.rcExclude.bottom, m_hWndParent, &params);
3240 ::DestroyMenu(hmenuViewPopup);
3241 }
3242
3243 // pvaOut is VT_I4 with value 0x403 (cmd id of the new mode maybe?)
3244 V_VT(pvaOut) = VT_I4;
3245 V_I4(pvaOut) = 0x403;
3246 }
3247 }
3248
3249 if (IsEqualIID(*pguidCmdGroup, CGID_Explorer) &&
3250 (nCmdID == 0x29) &&
3251 (nCmdexecopt == 4) && pvaOut)
3252 return S_OK;
3253
3254 if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView) &&
3255 (nCmdID == 9) &&
3256 (nCmdexecopt == 0))
3257 return 1;
3258
3259 return OLECMDERR_E_UNKNOWNGROUP;
3260 }
3261
3262 /**********************************************************
3263 * ISVDropTarget implementation
3264 */
3265
3266 /******************************************************************************
3267 * drag_notify_subitem [Internal]
3268 *
3269 * Figure out the shellfolder object, which is currently under the mouse cursor
3270 * and notify it via the IDropTarget interface.
3271 */
3272
3273 #define SCROLLAREAWIDTH 20
3274
3275 HRESULT CDefView::drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3276 {
3277 LONG lResult;
3278 HRESULT hr;
3279 RECT clientRect;
3280
3281 /* The key state on drop doesn't have MK_LBUTTON or MK_RBUTTON because it
3282 reflects the key state after the user released the button, so we need
3283 to remember the last key state when the button was pressed */
3284 m_grfKeyState = grfKeyState;
3285
3286 /* Map from global to client coordinates and query the index of the listview-item, which is
3287 * currently under the mouse cursor. */
3288 LVHITTESTINFO htinfo = {{pt.x, pt.y}, LVHT_ONITEM};
3289 ScreenToClient(&htinfo.pt);
3290 lResult = m_ListView.HitTest(&htinfo);
3291
3292 /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */
3293 ::GetClientRect(m_ListView, &clientRect);
3294 if (htinfo.pt.x == m_ptLastMousePos.x && htinfo.pt.y == m_ptLastMousePos.y &&
3295 (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH ||
3296 htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH ))
3297 {
3298 m_cScrollDelay = (m_cScrollDelay + 1) % 5; /* DragOver is called every 50 ms */
3299 if (m_cScrollDelay == 0)
3300 {
3301 /* Mouse did hover another 250 ms over the scroll-area */
3302 if (htinfo.pt.x < SCROLLAREAWIDTH)
3303 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEUP, 0);
3304
3305 if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH)
3306 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEDOWN, 0);
3307
3308 if (htinfo.pt.y < SCROLLAREAWIDTH)
3309 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEUP, 0);
3310
3311 if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH)
3312 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEDOWN, 0);
3313 }
3314 }
3315 else
3316 {
3317 m_cScrollDelay = 0; /* Reset, if the cursor is not over the listview's scroll-area */
3318 }
3319
3320 m_ptLastMousePos = htinfo.pt;
3321 ::ClientToListView(m_ListView, &m_ptLastMousePos);
3322
3323 /* We need to check if we drag the selection over itself */
3324 if (lResult != -1 && m_pSourceDataObject.p != NULL)
3325 {
3326 PCUITEMID_CHILD pidl = _PidlByItem(lResult);
3327
3328 for (UINT i = 0; i < m_cidl; i++)
3329 {
3330 if (pidl == m_apidl[i])
3331 {
3332 /* The item that is being draged is hovering itself. */
3333 lResult = -1;
3334 break;
3335 }
3336 }
3337 }
3338
3339 /* If we are still over the previous sub-item, notify it via DragOver and return. */
3340 if (m_pCurDropTarget && lResult == m_iDragOverItem)
3341 return m_pCurDropTarget->DragOver(grfKeyState, pt, pdwEffect);
3342
3343 /* We've left the previous sub-item, notify it via DragLeave and Release it. */
3344 if (m_pCurDropTarget)
3345 {
3346 PCUITEMID_CHILD pidl = _PidlByItem(m_iDragOverItem);
3347 if (pidl)
3348 SelectItem(pidl, 0);
3349
3350 m_pCurDropTarget->DragLeave();
3351 m_pCurDropTarget.Release();
3352 }
3353
3354 m_iDragOverItem = lResult;
3355
3356 if (lResult == -1)
3357 {
3358 /* We are not above one of the listview's subitems. Bind to the parent folder's
3359 * DropTarget interface. */
3360 hr = m_pSFParent->CreateViewObject(NULL, IID_PPV_ARG(IDropTarget,&m_pCurDropTarget));
3361 }
3362 else
3363 {
3364 /* Query the relative PIDL of the shellfolder object represented by the currently
3365 * dragged over listview-item ... */
3366 PCUITEMID_CHILD pidl = _PidlByItem(lResult);
3367
3368 /* ... and bind m_pCurDropTarget to the IDropTarget interface of an UIObject of this object */
3369 hr = m_pSFParent->GetUIObjectOf(m_ListView, 1, &pidl, IID_NULL_PPV_ARG(IDropTarget, &m_pCurDropTarget));
3370 }
3371
3372 IUnknown_SetSite(m_pCurDropTarget, (IShellView *)this);
3373
3374 /* If anything failed, m_pCurDropTarget should be NULL now, which ought to be a save state. */
3375 if (FAILED(hr))
3376 {
3377 *pdwEffect = DROPEFFECT_NONE;
3378 return hr;
3379 }
3380
3381 if (m_iDragOverItem != -1)
3382 {
3383 SelectItem(m_iDragOverItem, SVSI_SELECT);
3384 }
3385
3386 /* Notify the item just entered via DragEnter. */
3387 return m_pCurDropTarget->DragEnter(m_pCurDataObject, grfKeyState, pt, pdwEffect);
3388 }
3389
3390 HRESULT WINAPI CDefView::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3391 {
3392 if (*pdwEffect == DROPEFFECT_NONE)
3393 return S_OK;
3394
3395 /* Get a hold on the data object for later calls to DragEnter on the sub-folders */
3396 m_pCurDataObject = pDataObject;
3397
3398 HRESULT hr = drag_notify_subitem(grfKeyState, pt, pdwEffect);
3399 if (SUCCEEDED(hr))
3400 {
3401 POINT ptClient = {pt.x, pt.y};
3402 ScreenToClient(&ptClient);
3403 ImageList_DragEnter(m_hWnd, ptClient.x, ptClient.y);
3404 }
3405
3406 return hr;
3407 }
3408
3409 HRESULT WINAPI CDefView::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3410 {
3411 POINT ptClient = {pt.x, pt.y};
3412 ScreenToClient(&ptClient);
3413 ImageList_DragMove(ptClient.x, ptClient.y);
3414 return drag_notify_subitem(grfKeyState, pt, pdwEffect);
3415 }
3416
3417 HRESULT WINAPI CDefView::DragLeave()
3418 {
3419 ImageList_DragLeave(m_hWnd);
3420
3421 if (m_pCurDropTarget)
3422 {
3423 m_pCurDropTarget->DragLeave();
3424 m_pCurDropTarget.Release();
3425 }
3426
3427 if (m_pCurDataObject != NULL)
3428 {
3429 m_pCurDataObject.Release();
3430 }
3431
3432 m_iDragOverItem = 0;
3433
3434 return S_OK;
3435 }
3436
3437 INT CDefView::_FindInsertableIndexFromPoint(POINT pt)
3438 {
3439 RECT rcBound;
3440 INT i, nCount = m_ListView.GetItemCount();
3441 DWORD dwSpacing;
3442 INT dx, dy;
3443 BOOL bSmall = ((m_ListView.GetStyle() & LVS_TYPEMASK) != LVS_ICON);
3444
3445 /* FIXME: LVM_GETORIGIN is broken. See CORE-17266 */
3446 pt.x += m_ListView.GetScrollPos(SB_HORZ);
3447 pt.y += m_ListView.GetScrollPos(SB_VERT);
3448
3449 if (m_ListView.GetStyle() & LVS_ALIGNLEFT)
3450 {
3451 // vertically
3452 for (i = 0; i < nCount; ++i)
3453 {
3454 dwSpacing = ListView_GetItemSpacing(m_ListView, bSmall);
3455 dx = LOWORD(dwSpacing);
3456 dy = HIWORD(dwSpacing);
3457 ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS);
3458 rcBound.right = rcBound.left + dx;
3459 rcBound.bottom = rcBound.top + dy;
3460 if (pt.x < rcBound.right && pt.y < (rcBound.top + rcBound.bottom) / 2)
3461 {
3462 return i;
3463 }
3464 }
3465 for (i = nCount - 1; i >= 0; --i)
3466 {
3467 ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS);
3468 if (rcBound.left < pt.x && rcBound.top < pt.y)
3469 {
3470 return i + 1;
3471 }
3472 }
3473 }
3474 else
3475 {
3476 // horizontally
3477 for (i = 0; i < nCount; ++i)
3478 {
3479 dwSpacing = ListView_GetItemSpacing(m_ListView, bSmall);
3480 dx = LOWORD(dwSpacing);
3481 dy = HIWORD(dwSpacing);
3482 ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS);
3483 rcBound.right = rcBound.left + dx;
3484 rcBound.bottom = rcBound.top + dy;
3485 if (pt.y < rcBound.bottom && pt.x < rcBound.left)
3486 {
3487 return i;
3488 }
3489 if (pt.y < rcBound.bottom && pt.x < rcBound.right)
3490 {
3491 return i + 1;
3492 }
3493 }
3494 for (i = nCount - 1; i >= 0; --i)
3495 {
3496 ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS);
3497 if (rcBound.left < pt.x && rcBound.top < pt.y)
3498 {
3499 return i + 1;
3500 }
3501 }
3502 }
3503
3504 return nCount;
3505 }
3506
3507 typedef CSimpleMap<LPARAM, INT> CLParamIndexMap;
3508
3509 static INT CALLBACK
3510 SelectionMoveCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
3511 {
3512 CLParamIndexMap *pmap = (CLParamIndexMap *)lParamSort;
3513 INT i1 = pmap->Lookup(lParam1), i2 = pmap->Lookup(lParam2);
3514 if (i1 < i2)
3515 return -1;
3516 if (i1 > i2)
3517 return 1;
3518 return 0;
3519 }
3520
3521 void CDefView::_MoveSelectionOnAutoArrange(POINT pt)
3522 {
3523 // get insertable index from position
3524 INT iPosition = _FindInsertableIndexFromPoint(pt);
3525
3526 // create identity mapping of indexes
3527 CSimpleArray<INT> array;
3528 INT nCount = m_ListView.GetItemCount();
3529 for (INT i = 0; i < nCount; ++i)
3530 {
3531 array.Add(i);
3532 }
3533
3534 // re-ordering mapping
3535 INT iItem = -1;
3536 while ((iItem = m_ListView.GetNextItem(iItem, LVNI_SELECTED)) >= 0)
3537 {
3538 INT iFrom = iItem, iTo = iPosition;
3539 if (iFrom < iTo)
3540 --iTo;
3541 if (iFrom >= nCount)
3542 iFrom = nCount - 1;
3543 if (iTo >= nCount)
3544 iTo = nCount - 1;
3545
3546 // shift indexes by swapping (like a bucket relay)
3547 if (iFrom < iTo)
3548 {
3549 for (INT i = iFrom; i < iTo; ++i)
3550 {
3551 // swap array[i] and array[i + 1]
3552 INT tmp = array[i];
3553 array[i] = array[i + 1];
3554 array[i + 1] = tmp;
3555 }
3556 }
3557 else
3558 {
3559 for (INT i = iFrom; i > iTo; --i)
3560 {
3561 // swap array[i] and array[i - 1]
3562 INT tmp = array[i];
3563 array[i] = array[i - 1];
3564 array[i - 1] = tmp;
3565 }
3566 }
3567 }
3568
3569 // create mapping (ListView's lParam to index) from array
3570 CLParamIndexMap map;
3571 for (INT i = 0; i < nCount; ++i)
3572 {
3573 LPARAM lParam = m_ListView.GetItemData(array[i]);
3574 map.Add(lParam, i);
3575 }
3576
3577 // finally sort
3578 m_ListView.SortItems(SelectionMoveCompareFunc, &map);
3579 }
3580
3581 HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3582 {
3583 ImageList_DragLeave(m_hWnd);
3584 ImageList_EndDrag();
3585
3586 if ((IsDropOnSource(NULL) == S_OK) &&
3587 (*pdwEffect & DROPEFFECT_MOVE) &&
3588 (m_grfKeyState & MK_LBUTTON))
3589 {
3590 if (m_pCurDropTarget)
3591 {
3592 m_pCurDropTarget->DragLeave();
3593 m_pCurDropTarget.Release();
3594 }
3595
3596 POINT ptDrop = { pt.x, pt.y };
3597 ::ScreenToClient(m_ListView, &ptDrop);
3598 ::ClientToListView(m_ListView, &ptDrop);
3599 m_ptLastMousePos = ptDrop;
3600
3601 m_ListView.SetRedraw(FALSE);
3602 if (m_ListView.GetStyle() & LVS_AUTOARRANGE)
3603 {
3604 _MoveSelectionOnAutoArrange(m_ptLastMousePos);
3605 }
3606 else
3607 {
3608 POINT ptItem;
3609 INT iItem = -1;
3610 while ((iItem = m_ListView.GetNextItem(iItem, LVNI_SELECTED)) >= 0)
3611 {
3612 if (m_ListView.GetItemPosition(iItem, &ptItem))
3613 {
3614 ptItem.x += m_ptLastMousePos.x - m_ptFirstMousePos.x;
3615 ptItem.y += m_ptLastMousePos.y - m_ptFirstMousePos.y;
3616 m_ListView.SetItemPosition(iItem, &ptItem);
3617 }
3618 }
3619 }
3620 m_ListView.SetRedraw(TRUE);
3621 }
3622 else if (m_pCurDropTarget)
3623 {
3624 m_pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect);
3625 m_pCurDropTarget.Release();
3626 }
3627
3628 m_pCurDataObject.Release();
3629 m_iDragOverItem = 0;
3630 return S_OK;
3631 }
3632
3633 /**********************************************************
3634 * ISVDropSource implementation
3635 */
3636
3637 HRESULT WINAPI CDefView::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
3638 {
3639 TRACE("(%p)\n", this);
3640
3641 if (fEscapePressed)
3642 return DRAGDROP_S_CANCEL;
3643 else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON))
3644 return DRAGDROP_S_DROP;
3645 else
3646 return S_OK;
3647 }
3648
3649 HRESULT WINAPI CDefView::GiveFeedback(DWORD dwEffect)
3650 {
3651 TRACE("(%p)\n", this);
3652
3653 return DRAGDROP_S_USEDEFAULTCURSORS;
3654 }
3655
3656 /**********************************************************
3657 * ISVViewObject implementation
3658 */
3659
3660 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)
3661 {
3662 FIXME("Stub: this=%p\n", this);
3663
3664 return E_NOTIMPL;
3665 }
3666
3667 HRESULT WINAPI CDefView::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet)
3668 {
3669 FIXME("Stub: this=%p\n", this);
3670
3671 return E_NOTIMPL;
3672 }
3673
3674 HRESULT WINAPI CDefView::Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze)
3675 {
3676 FIXME("Stub: this=%p\n", this);
3677
3678 return E_NOTIMPL;
3679 }
3680
3681 HRESULT WINAPI CDefView::Unfreeze(DWORD dwFreeze)
3682 {
3683 FIXME("Stub: this=%p\n", this);
3684
3685 return E_NOTIMPL;
3686 }
3687
3688 HRESULT WINAPI CDefView::SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink)
3689 {
3690 FIXME("partial stub: %p 0x%08x 0x%08x %p\n", this, aspects, advf, pAdvSink);
3691
3692 /* FIXME: we set the AdviseSink, but never use it to send any advice */
3693 m_pAdvSink = pAdvSink;
3694 m_dwAspects = aspects;
3695 m_dwAdvf = advf;
3696
3697 return S_OK;
3698 }
3699
3700 HRESULT WINAPI CDefView::GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink)
3701 {
3702 TRACE("this=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n", this, pAspects, pAdvf, ppAdvSink);
3703
3704 if (ppAdvSink)
3705 {
3706 *ppAdvSink = m_pAdvSink;
3707 m_pAdvSink.p->AddRef();
3708 }
3709
3710 if (pAspects)
3711 *pAspects = m_dwAspects;
3712
3713 if (pAdvf)
3714 *pAdvf = m_dwAdvf;
3715
3716 return S_OK;
3717 }
3718
3719 HRESULT STDMETHODCALLTYPE CDefView::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
3720 {
3721 if (IsEqualIID(guidService, SID_IShellBrowser))
3722 return m_pShellBrowser->QueryInterface(riid, ppvObject);
3723 else if(IsEqualIID(guidService, SID_IFolderView))
3724 return QueryInterface(riid, ppvObject);
3725
3726 return E_NOINTERFACE;
3727 }
3728
3729 HRESULT CDefView::_MergeToolbar()
3730 {
3731 CComPtr<IExplorerToolbar> ptb;
3732 HRESULT hr = S_OK;
3733
3734 hr = IUnknown_QueryService(m_pShellBrowser, IID_IExplorerToolbar, IID_PPV_ARG(IExplorerToolbar, &ptb));
3735 if (FAILED(hr))
3736 return hr;
3737
3738 m_Category = CGID_DefViewFrame;
3739
3740 hr = ptb->SetCommandTarget(static_cast<IOleCommandTarget*>(this), &m_Category, 0);
3741 if (FAILED(hr))
3742 return hr;
3743
3744 if (hr == S_FALSE)
3745 return S_OK;
3746
3747 #if 0
3748 hr = ptb->AddButtons(&m_Category, buttonsCount, buttons);
3749 if (FAILED(hr))
3750 return hr;
3751 #endif
3752
3753 return S_OK;
3754 }
3755
3756 HRESULT CDefView::_DoFolderViewCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
3757 {
3758 HRESULT hr = E_NOTIMPL;
3759
3760 if (m_pShellFolderViewCB)
3761 {
3762 hr = m_pShellFolderViewCB->MessageSFVCB(uMsg, wParam, lParam);
3763 }
3764
3765 return hr;
3766 }
3767
3768 HRESULT CDefView_CreateInstance(IShellFolder *pFolder, REFIID riid, LPVOID * ppvOut)
3769 {
3770 return ShellObjectCreatorInit<CDefView>(pFolder, riid, ppvOut);
3771 }
3772
3773 HRESULT WINAPI SHCreateShellFolderViewEx(
3774 LPCSFV psvcbi, /* [in] shelltemplate struct */
3775 IShellView **ppsv) /* [out] IShellView pointer */
3776 {
3777 CComPtr<IShellView> psv;
3778 HRESULT hRes;
3779
3780 TRACE("sf=%p pidl=%p cb=%p mode=0x%08x parm=%p\n",
3781 psvcbi->pshf, psvcbi->pidl, psvcbi->pfnCallback,
3782 psvcbi->fvm, psvcbi->psvOuter);
3783
3784 *ppsv = NULL;
3785 hRes = CDefView_CreateInstance(psvcbi->pshf, IID_PPV_ARG(IShellView, &psv));
3786 if (FAILED_UNEXPECTEDLY(hRes))
3787 return hRes;
3788
3789 *ppsv = psv.Detach();
3790 return hRes;
3791 }
3792
3793 HRESULT WINAPI SHCreateShellFolderView(const SFV_CREATE *pcsfv,
3794 IShellView **ppsv)
3795 {
3796 CComPtr<IShellView> psv;
3797 HRESULT hRes;
3798
3799 if (!ppsv)
3800 return E_INVALIDARG;
3801
3802 *ppsv = NULL;
3803
3804 if (!pcsfv || pcsfv->cbSize != sizeof(*pcsfv))
3805 return E_INVALIDARG;
3806
3807 TRACE("sf=%p outer=%p callback=%p\n",
3808 pcsfv->pshf, pcsfv->psvOuter, pcsfv->psfvcb);
3809
3810 hRes = CDefView_CreateInstance(pcsfv->pshf, IID_PPV_ARG(IShellView, &psv));
3811 if (FAILED(hRes))
3812 return hRes;
3813
3814 if (pcsfv->psfvcb)
3815 {
3816 CComPtr<IShellFolderView> sfv;
3817 if (SUCCEEDED(psv->QueryInterface(IID_PPV_ARG(IShellFolderView, &sfv))))
3818 {
3819 sfv->SetCallback(pcsfv->psfvcb, NULL);
3820 }
3821 }
3822
3823 *ppsv = psv.Detach();
3824 return hRes;
3825 }