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