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