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