[SHELL32] Initial partial IShellFolderViewCB implementation.
[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 VOID _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 void SetStyle(DWORD dwAdd, DWORD dwRemove);
129 BOOL CreateList();
130 void UpdateListColors();
131 BOOL InitList();
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("--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 %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 * change the style of the listview control
505 */
506 void CDefView::SetStyle(DWORD dwAdd, DWORD dwRemove)
507 {
508 DWORD tmpstyle;
509
510 TRACE("(%p)\n", this);
511
512 tmpstyle = ::GetWindowLongPtrW(m_ListView, GWL_STYLE);
513 ::SetWindowLongPtrW(m_ListView, GWL_STYLE, dwAdd | (tmpstyle & ~dwRemove));
514 }
515
516 /**********************************************************
517 * ShellView_CreateList()
518 *
519 * - creates the list view window
520 */
521 BOOL CDefView::CreateList()
522 {
523 DWORD dwStyle, dwExStyle;
524
525 TRACE("%p\n", this);
526
527 dwStyle = WS_TABSTOP | WS_VISIBLE | WS_CHILDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
528 LVS_SHAREIMAGELISTS | LVS_EDITLABELS | LVS_AUTOARRANGE;
529 dwExStyle = WS_EX_CLIENTEDGE;
530
531 if (m_FolderSettings.fFlags & FWF_DESKTOP)
532 dwStyle |= LVS_ALIGNLEFT;
533 else
534 dwStyle |= LVS_ALIGNTOP | LVS_SHOWSELALWAYS;
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 return S_OK;
1184 }
1185
1186 HRESULT CDefView::CheckViewMode(HMENU hmenuView)
1187 {
1188 if (m_FolderSettings.ViewMode >= FVM_FIRST && m_FolderSettings.ViewMode <= FVM_LAST)
1189 {
1190 UINT iItemFirst = FCIDM_SHVIEW_BIGICON;
1191 UINT iItemLast = iItemFirst + FVM_LAST - FVM_FIRST;
1192 UINT iItem = iItemFirst + m_FolderSettings.ViewMode - FVM_FIRST;
1193 CheckMenuRadioItem(hmenuView, iItemFirst, iItemLast, iItem, MF_BYCOMMAND);
1194 }
1195
1196 return S_OK;
1197 }
1198
1199 /**********************************************************
1200 * ShellView_GetSelections()
1201 *
1202 * - fills the m_apidl list with the selected objects
1203 *
1204 * RETURNS
1205 * number of selected items
1206 */
1207 UINT CDefView::GetSelections()
1208 {
1209 SHFree(m_apidl);
1210
1211 m_cidl = m_ListView.GetSelectedCount();
1212 m_apidl = static_cast<PCUITEMID_CHILD*>(SHAlloc(m_cidl * sizeof(PCUITEMID_CHILD)));
1213 if (!m_apidl)
1214 {
1215 m_cidl = 0;
1216 return 0;
1217 }
1218
1219 TRACE("-- Items selected =%u\n", m_cidl);
1220
1221 UINT i = 0;
1222 int lvIndex = -1;
1223 while ((lvIndex = m_ListView.GetNextItem(lvIndex, LVNI_SELECTED)) > -1)
1224 {
1225 m_apidl[i] = _PidlByItem(lvIndex);
1226 i++;
1227 if (i == m_cidl)
1228 break;
1229 TRACE("-- selected Item found\n");
1230 }
1231
1232 return m_cidl;
1233 }
1234
1235 HRESULT CDefView::InvokeContextMenuCommand(UINT uCommand)
1236 {
1237 CMINVOKECOMMANDINFO cmi;
1238
1239 ZeroMemory(&cmi, sizeof(cmi));
1240 cmi.cbSize = sizeof(cmi);
1241 cmi.lpVerb = MAKEINTRESOURCEA(uCommand);
1242 cmi.hwnd = m_hWnd;
1243
1244 if (GetKeyState(VK_SHIFT) & 0x8000)
1245 cmi.fMask |= CMIC_MASK_SHIFT_DOWN;
1246
1247 if (GetKeyState(VK_CONTROL) & 0x8000)
1248 cmi.fMask |= CMIC_MASK_CONTROL_DOWN;
1249
1250 HRESULT hr = m_pCM->InvokeCommand(&cmi);
1251 if (FAILED_UNEXPECTEDLY(hr))
1252 return hr;
1253
1254 return S_OK;
1255 }
1256
1257 /**********************************************************
1258 * ShellView_OpenSelectedItems()
1259 */
1260 HRESULT CDefView::OpenSelectedItems()
1261 {
1262 HMENU hMenu;
1263 UINT uCommand;
1264 HRESULT hResult;
1265
1266 m_cidl = m_ListView.GetSelectedCount();
1267 if (m_cidl == 0)
1268 return S_OK;
1269
1270 hResult = OnDefaultCommand();
1271 if (hResult == S_OK)
1272 return hResult;
1273
1274 hMenu = CreatePopupMenu();
1275 if (!hMenu)
1276 return E_FAIL;
1277
1278 hResult = GetItemObject(SVGIO_SELECTION, IID_PPV_ARG(IContextMenu, &m_pCM));
1279 if (FAILED_UNEXPECTEDLY(hResult))
1280 goto cleanup;
1281
1282 hResult = m_pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_DEFAULTONLY);
1283 if (FAILED_UNEXPECTEDLY(hResult))
1284 goto cleanup;
1285
1286 uCommand = GetMenuDefaultItem(hMenu, FALSE, 0);
1287 if (uCommand == (UINT)-1)
1288 {
1289 hResult = E_FAIL;
1290 goto cleanup;
1291 }
1292
1293 InvokeContextMenuCommand(uCommand);
1294
1295 cleanup:
1296
1297 if (hMenu)
1298 DestroyMenu(hMenu);
1299
1300 if (m_pCM)
1301 {
1302 IUnknown_SetSite(m_pCM, NULL);
1303 m_pCM.Release();
1304 }
1305
1306 return hResult;
1307 }
1308
1309 /**********************************************************
1310 * ShellView_DoContextMenu()
1311 */
1312 LRESULT CDefView::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1313 {
1314 WORD x, y;
1315 UINT uCommand;
1316 HRESULT hResult;
1317
1318 x = LOWORD(lParam);
1319 y = HIWORD(lParam);
1320
1321 TRACE("(%p)->(0x%08x 0x%08x) stub\n", this, x, y);
1322
1323 m_hContextMenu = CreatePopupMenu();
1324 if (!m_hContextMenu)
1325 return E_FAIL;
1326
1327 m_cidl = m_ListView.GetSelectedCount();
1328
1329 hResult = GetItemObject( m_cidl ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &m_pCM));
1330 if (FAILED_UNEXPECTEDLY(hResult))
1331 goto cleanup;
1332
1333 /* Use 1 as the first id as we want 0 the mean that the user canceled the menu */
1334 hResult = m_pCM->QueryContextMenu(m_hContextMenu, 0, CONTEXT_MENU_BASE_ID, FCIDM_SHVIEWLAST, CMF_NORMAL);
1335 if (FAILED_UNEXPECTEDLY(hResult))
1336 goto cleanup;
1337
1338 uCommand = TrackPopupMenu(m_hContextMenu,
1339 TPM_LEFTALIGN | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
1340 x, y, 0, m_hWnd, NULL);
1341 if (uCommand == 0)
1342 goto cleanup;
1343
1344 if (uCommand == FCIDM_SHVIEW_OPEN && OnDefaultCommand() == S_OK)
1345 goto cleanup;
1346
1347 InvokeContextMenuCommand(uCommand - CONTEXT_MENU_BASE_ID);
1348
1349 cleanup:
1350 if (m_pCM)
1351 {
1352 IUnknown_SetSite(m_pCM, NULL);
1353 m_pCM.Release();
1354 }
1355
1356 if (m_hContextMenu)
1357 {
1358 DestroyMenu(m_hContextMenu);
1359 m_hContextMenu = NULL;
1360 }
1361
1362 return 0;
1363 }
1364
1365 LRESULT CDefView::OnExplorerCommand(UINT uCommand, BOOL bUseSelection)
1366 {
1367 HRESULT hResult;
1368 HMENU hMenu;
1369
1370 hMenu = CreatePopupMenu();
1371 if (!hMenu)
1372 return 0;
1373
1374 hResult = GetItemObject( bUseSelection ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &m_pCM));
1375 if (FAILED_UNEXPECTEDLY( hResult))
1376 goto cleanup;
1377
1378 hResult = m_pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_NORMAL);
1379 if (FAILED_UNEXPECTEDLY( hResult))
1380 goto cleanup;
1381
1382 InvokeContextMenuCommand(uCommand);
1383
1384 cleanup:
1385 if (m_pCM)
1386 {
1387 IUnknown_SetSite(m_pCM, NULL);
1388 m_pCM.Release();
1389 }
1390
1391 if (hMenu)
1392 DestroyMenu(hMenu);
1393
1394 return 0;
1395 }
1396
1397 /**********************************************************
1398 * ##### message handling #####
1399 */
1400
1401 /**********************************************************
1402 * ShellView_OnSize()
1403 */
1404 LRESULT CDefView::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1405 {
1406 WORD wWidth, wHeight;
1407
1408 wWidth = LOWORD(lParam);
1409 wHeight = HIWORD(lParam);
1410
1411 TRACE("%p width=%u height=%u\n", this, wWidth, wHeight);
1412
1413 /* Resize the ListView to fit our window */
1414 if (m_ListView)
1415 {
1416 ::MoveWindow(m_ListView, 0, 0, wWidth, wHeight, TRUE);
1417 }
1418
1419 _DoFolderViewCB(SFVM_SIZE, 0, 0);
1420
1421 return 0;
1422 }
1423
1424 /**********************************************************
1425 * ShellView_OnDeactivate()
1426 *
1427 * NOTES
1428 * internal
1429 */
1430 void CDefView::OnDeactivate()
1431 {
1432 TRACE("%p\n", this);
1433
1434 if (m_uState != SVUIA_DEACTIVATE)
1435 {
1436 // TODO: cleanup menu after deactivation
1437
1438 m_uState = SVUIA_DEACTIVATE;
1439 }
1440 }
1441
1442 void CDefView::DoActivate(UINT uState)
1443 {
1444 TRACE("%p uState=%x\n", this, uState);
1445
1446 /*don't do anything if the state isn't really changing */
1447 if (m_uState == uState)
1448 {
1449 return;
1450 }
1451
1452 if (uState == SVUIA_DEACTIVATE)
1453 {
1454 OnDeactivate();
1455 }
1456 else
1457 {
1458 if(m_hMenu && !m_bmenuBarInitialized)
1459 {
1460 FillEditMenu();
1461 FillViewMenu();
1462 m_pShellBrowser->SetMenuSB(m_hMenu, 0, m_hWnd);
1463 m_bmenuBarInitialized = TRUE;
1464 }
1465
1466 if (SVUIA_ACTIVATE_FOCUS == uState)
1467 {
1468 m_ListView.SetFocus();
1469 }
1470 }
1471
1472 m_uState = uState;
1473 TRACE("--\n");
1474 }
1475
1476 /**********************************************************
1477 * ShellView_OnActivate()
1478 */
1479 LRESULT CDefView::OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1480 {
1481 DoActivate(SVUIA_ACTIVATE_FOCUS);
1482 return 0;
1483 }
1484
1485 /**********************************************************
1486 * ShellView_OnSetFocus()
1487 *
1488 */
1489 LRESULT CDefView::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1490 {
1491 TRACE("%p\n", this);
1492
1493 /* Tell the browser one of our windows has received the focus. This
1494 should always be done before merging menus (OnActivate merges the
1495 menus) if one of our windows has the focus.*/
1496
1497 m_pShellBrowser->OnViewWindowActive(this);
1498 DoActivate(SVUIA_ACTIVATE_FOCUS);
1499
1500 /* Set the focus to the listview */
1501 m_ListView.SetFocus();
1502
1503 /* Notify the ICommDlgBrowser interface */
1504 OnStateChange(CDBOSC_SETFOCUS);
1505
1506 return 0;
1507 }
1508
1509 /**********************************************************
1510 * ShellView_OnKillFocus()
1511 */
1512 LRESULT CDefView::OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1513 {
1514 TRACE("(%p) stub\n", this);
1515
1516 DoActivate(SVUIA_ACTIVATE_NOFOCUS);
1517 /* Notify the ICommDlgBrowser */
1518 OnStateChange(CDBOSC_KILLFOCUS);
1519
1520 return 0;
1521 }
1522
1523 /**********************************************************
1524 * ShellView_OnCommand()
1525 *
1526 * NOTES
1527 * the CmdID's are the ones from the context menu
1528 */
1529 LRESULT CDefView::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1530 {
1531 DWORD dwCmdID;
1532 DWORD dwCmd;
1533 HWND hwndCmd;
1534 int nCount;
1535
1536 dwCmdID = GET_WM_COMMAND_ID(wParam, lParam);
1537 dwCmd = GET_WM_COMMAND_CMD(wParam, lParam);
1538 hwndCmd = GET_WM_COMMAND_HWND(wParam, lParam);
1539
1540 TRACE("(%p)->(0x%08x 0x%08x %p) stub\n", this, dwCmdID, dwCmd, hwndCmd);
1541
1542 switch (dwCmdID)
1543 {
1544 case FCIDM_SHVIEW_SMALLICON:
1545 m_FolderSettings.ViewMode = FVM_SMALLICON;
1546 SetStyle (LVS_SMALLICON, LVS_TYPEMASK);
1547 CheckToolbar();
1548 break;
1549
1550 case FCIDM_SHVIEW_BIGICON:
1551 m_FolderSettings.ViewMode = FVM_ICON;
1552 SetStyle (LVS_ICON, LVS_TYPEMASK);
1553 CheckToolbar();
1554 break;
1555
1556 case FCIDM_SHVIEW_LISTVIEW:
1557 m_FolderSettings.ViewMode = FVM_LIST;
1558 SetStyle (LVS_LIST, LVS_TYPEMASK);
1559 CheckToolbar();
1560 break;
1561
1562 case FCIDM_SHVIEW_REPORTVIEW:
1563 m_FolderSettings.ViewMode = FVM_DETAILS;
1564 SetStyle (LVS_REPORT, LVS_TYPEMASK);
1565 CheckToolbar();
1566 break;
1567
1568 /* the menu-ID's for sorting are 0x30... see shrec.rc */
1569 case 0x30:
1570 case 0x31:
1571 case 0x32:
1572 case 0x33:
1573 m_sortInfo.nHeaderID = dwCmdID - 0x30;
1574 m_sortInfo.bIsAscending = TRUE;
1575 _Sort();
1576 break;
1577
1578 case FCIDM_SHVIEW_SNAPTOGRID:
1579 case FCIDM_SHVIEW_AUTOARRANGE:
1580 //FIXME
1581 break;
1582 case FCIDM_SHVIEW_SELECTALL:
1583 m_ListView.SetItemState(-1, LVIS_SELECTED, LVIS_SELECTED);
1584 break;
1585
1586 case FCIDM_SHVIEW_INVERTSELECTION:
1587 nCount = m_ListView.GetItemCount();
1588 for (int i=0; i < nCount; i++)
1589 m_ListView.SetItemState(i, m_ListView.GetItemState(i, LVIS_SELECTED) ? 0 : LVIS_SELECTED, LVIS_SELECTED);
1590 break;
1591
1592 case FCIDM_SHVIEW_REFRESH:
1593 Refresh();
1594 break;
1595
1596 case FCIDM_SHVIEW_DELETE:
1597 case FCIDM_SHVIEW_CUT:
1598 case FCIDM_SHVIEW_COPY:
1599 case FCIDM_SHVIEW_RENAME:
1600 case FCIDM_SHVIEW_PROPERTIES:
1601 return OnExplorerCommand(dwCmdID, TRUE);
1602
1603 case FCIDM_SHVIEW_INSERT:
1604 case FCIDM_SHVIEW_UNDO:
1605 case FCIDM_SHVIEW_INSERTLINK:
1606 case FCIDM_SHVIEW_NEWFOLDER:
1607 return OnExplorerCommand(dwCmdID, FALSE);
1608 default:
1609 /* WM_COMMAND messages from the file menu are routed to the CDefView so as to let m_pCM handle the command */
1610 if (m_pCM && dwCmd == 0)
1611 {
1612 InvokeContextMenuCommand(dwCmdID);
1613 }
1614 }
1615
1616 return 0;
1617 }
1618
1619 /**********************************************************
1620 * ShellView_OnNotify()
1621 */
1622
1623 LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1624 {
1625 UINT CtlID;
1626 LPNMHDR lpnmh;
1627 LPNMLISTVIEW lpnmlv;
1628 NMLVDISPINFOW *lpdi;
1629 PCUITEMID_CHILD pidl;
1630 BOOL unused;
1631
1632 CtlID = wParam;
1633 lpnmh = (LPNMHDR)lParam;
1634 lpnmlv = (LPNMLISTVIEW)lpnmh;
1635 lpdi = (NMLVDISPINFOW *)lpnmh;
1636
1637 TRACE("%p CtlID=%u lpnmh->code=%x\n", this, CtlID, lpnmh->code);
1638
1639 switch (lpnmh->code)
1640 {
1641 case NM_SETFOCUS:
1642 TRACE("-- NM_SETFOCUS %p\n", this);
1643 OnSetFocus(0, 0, 0, unused);
1644 break;
1645
1646 case NM_KILLFOCUS:
1647 TRACE("-- NM_KILLFOCUS %p\n", this);
1648 OnDeactivate();
1649 /* Notify the ICommDlgBrowser interface */
1650 OnStateChange(CDBOSC_KILLFOCUS);
1651 break;
1652
1653 case NM_CUSTOMDRAW:
1654 TRACE("-- NM_CUSTOMDRAW %p\n", this);
1655 return CDRF_DODEFAULT;
1656
1657 case NM_RELEASEDCAPTURE:
1658 TRACE("-- NM_RELEASEDCAPTURE %p\n", this);
1659 break;
1660
1661 case NM_CLICK:
1662 TRACE("-- NM_CLICK %p\n", this);
1663 break;
1664
1665 case NM_RCLICK:
1666 TRACE("-- NM_RCLICK %p\n", this);
1667 break;
1668
1669 case NM_DBLCLK:
1670 TRACE("-- NM_DBLCLK %p\n", this);
1671 OpenSelectedItems();
1672 break;
1673
1674 case NM_RETURN:
1675 TRACE("-- NM_RETURN %p\n", this);
1676 OpenSelectedItems();
1677 break;
1678
1679 case HDN_ENDTRACKW:
1680 TRACE("-- HDN_ENDTRACKW %p\n", this);
1681 /*nColumn1 = m_ListView.GetColumnWidth(0);
1682 nColumn2 = m_ListView.GetColumnWidth(1);*/
1683 break;
1684
1685 case LVN_DELETEITEM:
1686 TRACE("-- LVN_DELETEITEM %p\n", this);
1687
1688 /*delete the pidl because we made a copy of it*/
1689 SHFree(reinterpret_cast<LPVOID>(lpnmlv->lParam));
1690
1691 break;
1692
1693 case LVN_DELETEALLITEMS:
1694 TRACE("-- LVN_DELETEALLITEMS %p\n", this);
1695 return FALSE;
1696
1697 case LVN_INSERTITEM:
1698 TRACE("-- LVN_INSERTITEM (STUB)%p\n", this);
1699 break;
1700
1701 case LVN_ITEMACTIVATE:
1702 TRACE("-- LVN_ITEMACTIVATE %p\n", this);
1703 OnStateChange(CDBOSC_SELCHANGE); /* the browser will get the IDataObject now */
1704 break;
1705
1706 case LVN_COLUMNCLICK:
1707 m_sortInfo.nHeaderID = lpnmlv->iSubItem;
1708 if (m_sortInfo.nLastHeaderID == m_sortInfo.nHeaderID)
1709 m_sortInfo.bIsAscending = !m_sortInfo.bIsAscending;
1710 else
1711 m_sortInfo.bIsAscending = TRUE;
1712 _Sort();
1713 break;
1714
1715 case LVN_GETDISPINFOA:
1716 case LVN_GETDISPINFOW:
1717 TRACE("-- LVN_GETDISPINFO %p\n", this);
1718 pidl = _PidlByItem(lpdi->item);
1719
1720 if (lpdi->item.mask & LVIF_TEXT) /* text requested */
1721 {
1722 if (m_pSF2Parent)
1723 {
1724 SHELLDETAILS sd;
1725 if (FAILED_UNEXPECTEDLY(m_pSF2Parent->GetDetailsOf(pidl, lpdi->item.iSubItem, &sd)))
1726 break;
1727
1728 if (lpnmh->code == LVN_GETDISPINFOA)
1729 {
1730 /* shouldn't happen */
1731 NMLVDISPINFOA *lpdiA = (NMLVDISPINFOA *)lpnmh;
1732 StrRetToStrNA( lpdiA->item.pszText, lpdiA->item.cchTextMax, &sd.str, NULL);
1733 TRACE("-- text=%s\n", lpdiA->item.pszText);
1734 }
1735 else /* LVN_GETDISPINFOW */
1736 {
1737 StrRetToStrNW( lpdi->item.pszText, lpdi->item.cchTextMax, &sd.str, NULL);
1738 TRACE("-- text=%s\n", debugstr_w(lpdi->item.pszText));
1739 }
1740 }
1741 else
1742 {
1743 FIXME("no m_pSF2Parent\n");
1744 }
1745 }
1746 if(lpdi->item.mask & LVIF_IMAGE) /* image requested */
1747 {
1748 lpdi->item.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
1749 }
1750 if(lpdi->item.mask & LVIF_STATE)
1751 {
1752 ULONG attributes = SFGAO_HIDDEN;
1753 if (SUCCEEDED(m_pSFParent->GetAttributesOf(1, &pidl, &attributes)))
1754 {
1755 if (attributes & SFGAO_HIDDEN)
1756 {
1757 lpdi->item.state |= LVIS_CUT;
1758 }
1759 }
1760 }
1761 lpdi->item.mask |= LVIF_DI_SETITEM;
1762 break;
1763
1764 case LVN_ITEMCHANGED:
1765 TRACE("-- LVN_ITEMCHANGED %p\n", this);
1766 OnStateChange(CDBOSC_SELCHANGE); /* the browser will get the IDataObject now */
1767 UpdateStatusbar();
1768 _DoFolderViewCB(SFVM_SELECTIONCHANGED, NULL/* FIXME */, NULL/* FIXME */);
1769 break;
1770
1771 case LVN_BEGINDRAG:
1772 case LVN_BEGINRDRAG:
1773 TRACE("-- LVN_BEGINDRAG\n");
1774
1775 if (GetSelections())
1776 {
1777 CComPtr<IDataObject> pda;
1778 DWORD dwAttributes = SFGAO_CANCOPY | SFGAO_CANLINK;
1779 DWORD dwEffect = DROPEFFECT_MOVE;
1780
1781 if (SUCCEEDED(m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, IID_NULL_PPV_ARG(IDataObject, &pda))))
1782 {
1783 LPNMLISTVIEW params = (LPNMLISTVIEW)lParam;
1784
1785 if (SUCCEEDED(m_pSFParent->GetAttributesOf(m_cidl, m_apidl, &dwAttributes)))
1786 {
1787 dwEffect |= dwAttributes & (SFGAO_CANCOPY | SFGAO_CANLINK);
1788 }
1789
1790 CComPtr<IAsyncOperation> piaso;
1791 if (SUCCEEDED(pda->QueryInterface(IID_PPV_ARG(IAsyncOperation, &piaso))))
1792 {
1793 piaso->SetAsyncMode(TRUE);
1794 }
1795
1796 DWORD dwEffect2;
1797
1798 m_pSourceDataObject = pda;
1799 m_ptFirstMousePos = params->ptAction;
1800 ClientToScreen(&m_ptFirstMousePos);
1801
1802 HIMAGELIST big_icons, small_icons;
1803 Shell_GetImageLists(&big_icons, &small_icons);
1804 PCUITEMID_CHILD pidl = _PidlByItem(params->iItem);
1805 int iIcon = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
1806 POINT ptItem;
1807 m_ListView.GetItemPosition(params->iItem, &ptItem);
1808
1809 ImageList_BeginDrag(big_icons, iIcon, params->ptAction.x - ptItem.x, params->ptAction.y - ptItem.y);
1810
1811 DoDragDrop(pda, this, dwEffect, &dwEffect2);
1812
1813 m_pSourceDataObject.Release();
1814 }
1815 }
1816 break;
1817
1818 case LVN_BEGINLABELEDITW:
1819 {
1820 DWORD dwAttr = SFGAO_CANRENAME;
1821 pidl = _PidlByItem(lpdi->item);
1822
1823 TRACE("-- LVN_BEGINLABELEDITW %p\n", this);
1824
1825 m_pSFParent->GetAttributesOf(1, &pidl, &dwAttr);
1826 if (SFGAO_CANRENAME & dwAttr)
1827 {
1828 m_isEditing = TRUE;
1829 return FALSE;
1830 }
1831 return TRUE;
1832 }
1833
1834 case LVN_ENDLABELEDITW:
1835 {
1836 TRACE("-- LVN_ENDLABELEDITW %p\n", this);
1837
1838 m_isEditing = FALSE;
1839
1840 if (lpdi->item.pszText)
1841 {
1842 HRESULT hr;
1843 LVITEMW lvItem;
1844
1845 pidl = _PidlByItem(lpdi->item);
1846 PITEMID_CHILD pidlNew;
1847 hr = m_pSFParent->SetNameOf(0, pidl, lpdi->item.pszText, SHGDN_INFOLDER, &pidlNew);
1848
1849 if (SUCCEEDED(hr) && pidlNew)
1850 {
1851 lvItem.mask = LVIF_PARAM|LVIF_IMAGE;
1852 lvItem.iItem = lpdi->item.iItem;
1853 lvItem.iSubItem = 0;
1854 lvItem.lParam = reinterpret_cast<LPARAM>(pidlNew);
1855 lvItem.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidlNew, 0);
1856 m_ListView.SetItem(&lvItem);
1857 m_ListView.Update(lpdi->item.iItem);
1858 return TRUE;
1859 }
1860 }
1861
1862 return FALSE;
1863 }
1864
1865 default:
1866 TRACE("-- %p WM_COMMAND %x unhandled\n", this, lpnmh->code);
1867 break;
1868 }
1869
1870 return 0;
1871 }
1872
1873 /*
1874 * This is just a quick hack to make the desktop work correctly.
1875 * ITranslateShellChangeNotify's IsChildID is undocumented, but most likely the way that
1876 * a folder should know if it should update upon a change notification.
1877 * It is exported by merged folders at a minimum.
1878 */
1879 static BOOL ILIsParentOrSpecialParent(PCIDLIST_ABSOLUTE pidl1, PCIDLIST_ABSOLUTE pidl2)
1880 {
1881 if (!pidl1 || !pidl2)
1882 return FALSE;
1883 if (ILIsParent(pidl1, pidl2, TRUE))
1884 return TRUE;
1885
1886 if (_ILIsDesktop(pidl1))
1887 {
1888 PIDLIST_ABSOLUTE deskpidl;
1889 SHGetFolderLocation(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 0, &deskpidl);
1890 if (ILIsParent(deskpidl, pidl2, TRUE))
1891 {
1892 ILFree(deskpidl);
1893 return TRUE;
1894 }
1895 ILFree(deskpidl);
1896 SHGetFolderLocation(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL, 0, &deskpidl);
1897 if (ILIsParent(deskpidl, pidl2, TRUE))
1898 {
1899 ILFree(deskpidl);
1900 return TRUE;
1901 }
1902 ILFree(deskpidl);
1903 }
1904 return FALSE;
1905 }
1906
1907 /**********************************************************
1908 * ShellView_OnChange()
1909 */
1910 LRESULT CDefView::OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1911 {
1912 PCIDLIST_ABSOLUTE *Pidls = reinterpret_cast<PCIDLIST_ABSOLUTE*>(wParam);
1913 BOOL bParent0 = ILIsParentOrSpecialParent(m_pidlParent, Pidls[0]);
1914 BOOL bParent1 = ILIsParentOrSpecialParent(m_pidlParent, Pidls[1]);
1915
1916 TRACE("(%p)(%p,%p,0x%08x)\n", this, Pidls[0], Pidls[1], lParam);
1917
1918 switch (lParam &~ SHCNE_INTERRUPT)
1919 {
1920 case SHCNE_MKDIR:
1921 case SHCNE_CREATE:
1922 if (bParent0)
1923 {
1924 if (LV_FindItemByPidl(ILFindLastID(Pidls[0])) == -1)
1925 {
1926 LV_AddItem(ILFindLastID(Pidls[0]));
1927 }
1928 else
1929 {
1930 LV_ProdItem(ILFindLastID(Pidls[0]));
1931 }
1932 }
1933 break;
1934
1935 case SHCNE_RMDIR:
1936 case SHCNE_DELETE:
1937 if (bParent0)
1938 LV_DeleteItem(ILFindLastID(Pidls[0]));
1939 break;
1940
1941 case SHCNE_RENAMEFOLDER:
1942 case SHCNE_RENAMEITEM:
1943 if (bParent0 && bParent1)
1944 LV_RenameItem(ILFindLastID(Pidls[0]), ILFindLastID(Pidls[1]));
1945 else if (bParent0)
1946 LV_DeleteItem(ILFindLastID(Pidls[0]));
1947 else if (bParent1)
1948 LV_AddItem(ILFindLastID(Pidls[1]));
1949 break;
1950
1951 case SHCNE_UPDATEITEM:
1952 if (bParent0)
1953 LV_RenameItem(ILFindLastID(Pidls[0]), ILFindLastID(Pidls[0]));
1954 break;
1955
1956 case SHCNE_UPDATEDIR:
1957 Refresh();
1958 break;
1959 }
1960 return TRUE;
1961 }
1962
1963 HRESULT SHGetMenuIdFromMenuMsg(UINT uMsg, LPARAM lParam, UINT *CmdId);
1964 HRESULT SHSetMenuIdInMenuMsg(UINT uMsg, LPARAM lParam, UINT CmdId);
1965
1966 /**********************************************************
1967 * CDefView::OnCustomItem
1968 */
1969 LRESULT CDefView::OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1970 {
1971 if (!m_pCM.p)
1972 {
1973 /* no menu */
1974 ERR("no menu!!!\n");
1975 return FALSE;
1976 }
1977
1978 /* The lParam of WM_DRAWITEM WM_MEASUREITEM contain a menu id and this also needs to
1979 be changed to a menu identifier offset */
1980 UINT CmdID;
1981 HRESULT hres = SHGetMenuIdFromMenuMsg(uMsg, lParam, &CmdID);
1982 if (SUCCEEDED(hres))
1983 SHSetMenuIdInMenuMsg(uMsg, lParam, CmdID - CONTEXT_MENU_BASE_ID);
1984
1985 /* Forward the message to the IContextMenu2 */
1986 LRESULT result;
1987 hres = SHForwardContextMenuMsg(m_pCM, uMsg, wParam, lParam, &result, TRUE);
1988
1989 return (SUCCEEDED(hres));
1990 }
1991
1992 LRESULT CDefView::OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1993 {
1994 /* Wallpaper setting affects drop shadows effect */
1995 if (wParam == SPI_SETDESKWALLPAPER || wParam == 0)
1996 UpdateListColors();
1997
1998 return S_OK;
1999 }
2000
2001 /**********************************************************
2002 * CDefView::OnInitMenuPopup
2003 */
2004 LRESULT CDefView::OnInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
2005 {
2006 HMENU hmenu = (HMENU) wParam;
2007 int nPos = LOWORD(lParam);
2008 UINT menuItemId;
2009
2010 OnCustomItem(uMsg, wParam, lParam, bHandled);
2011
2012 HMENU hViewMenu = GetSubmenuByID(m_hMenu, FCIDM_MENU_VIEW);
2013
2014 /* Lets try to find out what the hell wParam is */
2015 if (hmenu == GetSubMenu(m_hMenu, nPos))
2016 menuItemId = ReallyGetMenuItemID(m_hMenu, nPos);
2017 else if (hViewMenu && hmenu == GetSubMenu(hViewMenu, nPos))
2018 menuItemId = ReallyGetMenuItemID(hViewMenu, nPos);
2019 else if (m_hContextMenu && hmenu == GetSubMenu(m_hContextMenu, nPos))
2020 menuItemId = ReallyGetMenuItemID(m_hContextMenu, nPos);
2021 else
2022 return FALSE;
2023
2024 switch (menuItemId)
2025 {
2026 case FCIDM_MENU_FILE:
2027 FillFileMenu();
2028 break;
2029 case FCIDM_MENU_VIEW:
2030 case FCIDM_SHVIEW_VIEW:
2031 CheckViewMode(hmenu);
2032 break;
2033 case FCIDM_SHVIEW_ARRANGE:
2034 FillArrangeAsMenu(hmenu);
2035 break;
2036 }
2037
2038 return FALSE;
2039 }
2040
2041 /**********************************************************
2042 *
2043 *
2044 * The INTERFACE of the IShellView object
2045 *
2046 *
2047 **********************************************************
2048 */
2049
2050 /**********************************************************
2051 * ShellView_GetWindow
2052 */
2053 HRESULT WINAPI CDefView::GetWindow(HWND *phWnd)
2054 {
2055 TRACE("(%p)\n", this);
2056
2057 *phWnd = m_hWnd;
2058
2059 return S_OK;
2060 }
2061
2062 HRESULT WINAPI CDefView::ContextSensitiveHelp(BOOL fEnterMode)
2063 {
2064 FIXME("(%p) stub\n", this);
2065
2066 return E_NOTIMPL;
2067 }
2068
2069 /**********************************************************
2070 * IShellView_TranslateAccelerator
2071 *
2072 * FIXME:
2073 * use the accel functions
2074 */
2075 HRESULT WINAPI CDefView::TranslateAccelerator(LPMSG lpmsg)
2076 {
2077 if (m_isEditing)
2078 return S_FALSE;
2079
2080 if (lpmsg->message >= WM_KEYFIRST && lpmsg->message <= WM_KEYLAST)
2081 {
2082 if (::TranslateAcceleratorW(m_hWnd, m_hAccel, lpmsg) != 0)
2083 return S_OK;
2084
2085 TRACE("-- key=0x04%lx\n", lpmsg->wParam) ;
2086 }
2087
2088 return m_pShellBrowser->TranslateAcceleratorSB(lpmsg, 0);
2089 }
2090
2091 HRESULT WINAPI CDefView::EnableModeless(BOOL fEnable)
2092 {
2093 FIXME("(%p) stub\n", this);
2094
2095 return E_NOTIMPL;
2096 }
2097
2098 HRESULT WINAPI CDefView::UIActivate(UINT uState)
2099 {
2100 // CHAR szName[MAX_PATH];
2101 LRESULT lResult;
2102 int nPartArray[1] = { -1};
2103
2104 TRACE("(%p)->(state=%x) stub\n", this, uState);
2105
2106 /* don't do anything if the state isn't really changing */
2107 if (m_uState == uState)
2108 {
2109 return S_OK;
2110 }
2111
2112 /* OnActivate handles the menu merging and internal state */
2113 DoActivate(uState);
2114
2115 /* only do This if we are active */
2116 if (uState != SVUIA_DEACTIVATE)
2117 {
2118
2119 /*
2120 GetFolderPath is not a method of IShellFolder
2121 IShellFolder_GetFolderPath( m_pSFParent, szName, sizeof(szName) );
2122 */
2123 /* set the number of parts */
2124 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, 1, (LPARAM)nPartArray, &lResult);
2125
2126 /* set the text for the parts */
2127 /*
2128 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXTA, 0, (LPARAM)szName, &lResult);
2129 */
2130 }
2131
2132 return S_OK;
2133 }
2134
2135 HRESULT WINAPI CDefView::Refresh()
2136 {
2137 TRACE("(%p)\n", this);
2138
2139 m_ListView.DeleteAllItems();
2140 FillList();
2141
2142 return S_OK;
2143 }
2144
2145 HRESULT WINAPI CDefView::CreateViewWindow(IShellView *lpPrevView, LPCFOLDERSETTINGS lpfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd)
2146 {
2147 return CreateViewWindow3(psb, lpPrevView, SV3CVW3_DEFAULT,
2148 (FOLDERFLAGS)lpfs->fFlags, (FOLDERFLAGS)lpfs->fFlags, (FOLDERVIEWMODE)lpfs->ViewMode, NULL, prcView, phWnd);
2149 }
2150
2151 HRESULT WINAPI CDefView::DestroyViewWindow()
2152 {
2153 TRACE("(%p)\n", this);
2154
2155 /* Make absolutely sure all our UI is cleaned up */
2156 UIActivate(SVUIA_DEACTIVATE);
2157
2158 if (m_hAccel)
2159 {
2160 // "Accelerator tables loaded from resources are freed automatically when the application terminates." -- MSDN
2161 m_hAccel = NULL;
2162 }
2163
2164 if (m_hMenuArrangeModes)
2165 {
2166 DestroyMenu(m_hMenuArrangeModes);
2167 m_hMenuArrangeModes = NULL;
2168 }
2169
2170 if (m_hMenuViewModes)
2171 {
2172 DestroyMenu(m_hMenuViewModes);
2173 m_hMenuViewModes = NULL;
2174 }
2175
2176 if (m_hMenu)
2177 {
2178 DestroyMenu(m_hMenu);
2179 m_hMenu = NULL;
2180 }
2181
2182 if (m_ListView)
2183 {
2184 m_ListView.DestroyWindow();
2185 }
2186
2187 if (m_hWnd)
2188 {
2189 DestroyWindow();
2190 }
2191
2192 m_pShellBrowser.Release();
2193 m_pCommDlgBrowser.Release();
2194
2195 return S_OK;
2196 }
2197
2198 HRESULT WINAPI CDefView::GetCurrentInfo(LPFOLDERSETTINGS lpfs)
2199 {
2200 TRACE("(%p)->(%p) vmode=%x flags=%x\n", this, lpfs,
2201 m_FolderSettings.ViewMode, m_FolderSettings.fFlags);
2202
2203 if (!lpfs)
2204 return E_INVALIDARG;
2205
2206 *lpfs = m_FolderSettings;
2207 return S_OK;
2208 }
2209
2210 HRESULT WINAPI CDefView::AddPropertySheetPages(DWORD dwReserved, LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam)
2211 {
2212 FIXME("(%p) stub\n", this);
2213
2214 return E_NOTIMPL;
2215 }
2216
2217 HRESULT WINAPI CDefView::SaveViewState()
2218 {
2219 FIXME("(%p) stub\n", this);
2220
2221 return S_OK;
2222 }
2223
2224 HRESULT WINAPI CDefView::SelectItem(PCUITEMID_CHILD pidl, UINT uFlags)
2225 {
2226 int i;
2227
2228 TRACE("(%p)->(pidl=%p, 0x%08x) stub\n", this, pidl, uFlags);
2229
2230 i = LV_FindItemByPidl(pidl);
2231 if (i == -1)
2232 return S_OK;
2233
2234 if(uFlags & SVSI_ENSUREVISIBLE)
2235 m_ListView.EnsureVisible(i, FALSE);
2236
2237 LVITEMW lvItem = {0};
2238 lvItem.mask = LVIF_STATE;
2239 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
2240
2241 while (m_ListView.GetItem(&lvItem))
2242 {
2243 if (lvItem.iItem == i)
2244 {
2245 if (uFlags & SVSI_SELECT)
2246 lvItem.state |= LVIS_SELECTED;
2247 else
2248 lvItem.state &= ~LVIS_SELECTED;
2249
2250 if (uFlags & SVSI_FOCUSED)
2251 lvItem.state &= ~LVIS_FOCUSED;
2252 }
2253 else
2254 {
2255 if (uFlags & SVSI_DESELECTOTHERS)
2256 lvItem.state &= ~LVIS_SELECTED;
2257 }
2258
2259 m_ListView.SetItem(&lvItem);
2260 lvItem.iItem++;
2261 }
2262
2263 if((uFlags & SVSI_EDIT) == SVSI_EDIT)
2264 m_ListView.EditLabel(i);
2265
2266 return S_OK;
2267 }
2268
2269 HRESULT WINAPI CDefView::GetItemObject(UINT uItem, REFIID riid, LPVOID *ppvOut)
2270 {
2271 HRESULT hr = E_NOINTERFACE;
2272
2273 TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n", this, uItem, debugstr_guid(&riid), ppvOut);
2274
2275 *ppvOut = NULL;
2276
2277 switch (uItem)
2278 {
2279 case SVGIO_BACKGROUND:
2280 if (IsEqualIID(riid, IID_IContextMenu))
2281 {
2282 if (!ppvOut)
2283 hr = E_OUTOFMEMORY;
2284
2285 hr = CDefViewBckgrndMenu_CreateInstance(m_pSF2Parent, riid, ppvOut);
2286 if (FAILED_UNEXPECTEDLY(hr))
2287 return hr;
2288
2289 IUnknown_SetSite(*((IUnknown**)ppvOut), (IShellView *)this);
2290 }
2291 else if (IsEqualIID(riid, IID_IDispatch))
2292 {
2293 if (m_pShellFolderViewDual == NULL)
2294 {
2295 hr = CDefViewDual_Constructor(riid, (LPVOID*)&m_pShellFolderViewDual);
2296 if (FAILED_UNEXPECTEDLY(hr))
2297 return hr;
2298 }
2299 hr = m_pShellFolderViewDual->QueryInterface(riid, ppvOut);
2300 }
2301 break;
2302
2303 case SVGIO_SELECTION:
2304 GetSelections();
2305 hr = m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, m_apidl, riid, 0, ppvOut);
2306 if (FAILED_UNEXPECTEDLY(hr))
2307 return hr;
2308
2309 if (IsEqualIID(riid, IID_IContextMenu))
2310 IUnknown_SetSite(*((IUnknown**)ppvOut), (IShellView *)this);
2311
2312 break;
2313 }
2314
2315 TRACE("-- (%p)->(interface=%p)\n", this, *ppvOut);
2316
2317 return hr;
2318 }
2319
2320 HRESULT STDMETHODCALLTYPE CDefView::GetCurrentViewMode(UINT *pViewMode)
2321 {
2322 TRACE("(%p)->(%p), stub\n", this, pViewMode);
2323
2324 if (!pViewMode)
2325 return E_INVALIDARG;
2326
2327 *pViewMode = m_FolderSettings.ViewMode;
2328 return S_OK;
2329 }
2330
2331 HRESULT STDMETHODCALLTYPE CDefView::SetCurrentViewMode(UINT ViewMode)
2332 {
2333 DWORD dwStyle;
2334 TRACE("(%p)->(%u), stub\n", this, ViewMode);
2335
2336 /* It's not redundant to check FVM_AUTO because it's a (UINT)-1 */
2337 if (((INT)ViewMode < FVM_FIRST || (INT)ViewMode > FVM_LAST) && ((INT)ViewMode != FVM_AUTO))
2338 return E_INVALIDARG;
2339
2340 /* Windows before Vista uses LVM_SETVIEW and possibly
2341 LVM_SETEXTENDEDLISTVIEWSTYLE to set the style of the listview,
2342 while later versions seem to accomplish this through other
2343 means. */
2344 switch (ViewMode)
2345 {
2346 case FVM_ICON:
2347 dwStyle = LVS_ICON;
2348 break;
2349 case FVM_DETAILS:
2350 dwStyle = LVS_REPORT;
2351 break;
2352 case FVM_SMALLICON:
2353 dwStyle = LVS_SMALLICON;
2354 break;
2355 case FVM_LIST:
2356 dwStyle = LVS_LIST;
2357 break;
2358 default:
2359 {
2360 FIXME("ViewMode %d not implemented\n", ViewMode);
2361 dwStyle = LVS_LIST;
2362 break;
2363 }
2364 }
2365
2366 SetStyle(dwStyle, LVS_TYPEMASK);
2367
2368 /* This will not necessarily be the actual mode set above.
2369 This mimics the behavior of Windows XP. */
2370 m_FolderSettings.ViewMode = ViewMode;
2371
2372 return S_OK;
2373 }
2374
2375 HRESULT STDMETHODCALLTYPE CDefView::GetFolder(REFIID riid, void **ppv)
2376 {
2377 if (m_pSFParent == NULL)
2378 return E_FAIL;
2379
2380 return m_pSFParent->QueryInterface(riid, ppv);
2381 }
2382
2383 HRESULT STDMETHODCALLTYPE CDefView::Item(int iItemIndex, PITEMID_CHILD *ppidl)
2384 {
2385 PCUITEMID_CHILD pidl = _PidlByItem(iItemIndex);
2386 if (pidl)
2387 {
2388 *ppidl = ILClone(pidl);
2389 return S_OK;
2390 }
2391
2392 *ppidl = 0;
2393 return E_INVALIDARG;
2394 }
2395
2396 HRESULT STDMETHODCALLTYPE CDefView::ItemCount(UINT uFlags, int *pcItems)
2397 {
2398 TRACE("(%p)->(%u %p)\n", this, uFlags, pcItems);
2399
2400 if (uFlags != SVGIO_ALLVIEW)
2401 FIXME("some flags unsupported, %x\n", uFlags & ~SVGIO_ALLVIEW);
2402
2403 *pcItems = m_ListView.GetItemCount();
2404
2405 return S_OK;
2406 }
2407
2408 HRESULT STDMETHODCALLTYPE CDefView::Items(UINT uFlags, REFIID riid, void **ppv)
2409 {
2410 return E_NOTIMPL;
2411 }
2412
2413 HRESULT STDMETHODCALLTYPE CDefView::GetSelectionMarkedItem(int *piItem)
2414 {
2415 TRACE("(%p)->(%p)\n", this, piItem);
2416
2417 *piItem = m_ListView.GetSelectionMark();
2418
2419 return S_OK;
2420 }
2421
2422 HRESULT STDMETHODCALLTYPE CDefView::GetFocusedItem(int *piItem)
2423 {
2424 TRACE("(%p)->(%p)\n", this, piItem);
2425
2426 *piItem = m_ListView.GetNextItem(-1, LVNI_FOCUSED);
2427
2428 return S_OK;
2429 }
2430
2431 HRESULT STDMETHODCALLTYPE CDefView::GetItemPosition(PCUITEMID_CHILD pidl, POINT *ppt)
2432 {
2433 int lvIndex = LV_FindItemByPidl(pidl);
2434 if (lvIndex == -1 || ppt == NULL)
2435 return E_INVALIDARG;
2436
2437 m_ListView.GetItemPosition(lvIndex, ppt);
2438 return S_OK;
2439 }
2440
2441 HRESULT STDMETHODCALLTYPE CDefView::GetSpacing(POINT *ppt)
2442 {
2443 TRACE("(%p)->(%p)\n", this, ppt);
2444
2445 if (!m_ListView)
2446 return S_FALSE;
2447
2448 if (ppt)
2449 {
2450 SIZE spacing;
2451 m_ListView.GetItemSpacing(spacing);
2452
2453 ppt->x = spacing.cx;
2454 ppt->y = spacing.cy;
2455 }
2456
2457 return S_OK;
2458 }
2459
2460 HRESULT STDMETHODCALLTYPE CDefView::GetDefaultSpacing(POINT *ppt)
2461 {
2462 return E_NOTIMPL;
2463 }
2464
2465 HRESULT STDMETHODCALLTYPE CDefView::GetAutoArrange()
2466 {
2467 return E_NOTIMPL;
2468 }
2469
2470 HRESULT STDMETHODCALLTYPE CDefView::SelectItem(int iItem, DWORD dwFlags)
2471 {
2472 LVITEMW lvItem;
2473
2474 TRACE("(%p)->(%d, %x)\n", this, iItem, dwFlags);
2475
2476 lvItem.state = 0;
2477 lvItem.stateMask = LVIS_SELECTED;
2478
2479 if (dwFlags & SVSI_ENSUREVISIBLE)
2480 m_ListView.EnsureVisible(iItem, 0);
2481
2482 /* all items */
2483 if (dwFlags & SVSI_DESELECTOTHERS)
2484 m_ListView.SetItemState(-1, 0, LVIS_SELECTED);
2485
2486 /* this item */
2487 if (dwFlags & SVSI_SELECT)
2488 lvItem.state |= LVIS_SELECTED;
2489
2490 if (dwFlags & SVSI_FOCUSED)
2491 lvItem.stateMask |= LVIS_FOCUSED;
2492
2493 m_ListView.SetItemState(iItem, lvItem.state, lvItem.stateMask);
2494
2495 if ((dwFlags & SVSI_EDIT) == SVSI_EDIT)
2496 m_ListView.EditLabel(iItem);
2497
2498 return S_OK;
2499 }
2500
2501 HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItems(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, POINT *apt, DWORD dwFlags)
2502 {
2503 /* Reset the selection */
2504 m_ListView.SetItemState(-1, 0, LVIS_SELECTED);
2505
2506 int lvIndex;
2507 for (UINT i = 0 ; i < m_cidl; i++)
2508 {
2509 lvIndex = LV_FindItemByPidl(apidl[i]);
2510 if (lvIndex != -1)
2511 {
2512 SelectItem(lvIndex, dwFlags);
2513 m_ListView.SetItemPosition(lvIndex, &apt[i]);
2514 }
2515 }
2516
2517 return S_OK;
2518 }
2519
2520 /**********************************************************
2521 * IShellView2 implementation
2522 */
2523
2524 HRESULT STDMETHODCALLTYPE CDefView::GetView(SHELLVIEWID *view_guid, ULONG view_type)
2525 {
2526 FIXME("(%p)->(%p, %lu) stub\n", this, view_guid, view_type);
2527 return E_NOTIMPL;
2528 }
2529
2530 HRESULT STDMETHODCALLTYPE CDefView::CreateViewWindow2(LPSV2CVW2_PARAMS view_params)
2531 {
2532 return CreateViewWindow3(view_params->psbOwner, view_params->psvPrev,
2533 SV3CVW3_DEFAULT, (FOLDERFLAGS)view_params->pfs->fFlags, (FOLDERFLAGS)view_params->pfs->fFlags,
2534 (FOLDERVIEWMODE)view_params->pfs->ViewMode, view_params->pvid, view_params->prcView, &view_params->hwndView);
2535 }
2536
2537 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)
2538 {
2539 OLEMENUGROUPWIDTHS omw = { { 0, 0, 0, 0, 0, 0 } };
2540
2541 *hwnd = NULL;
2542
2543 TRACE("(%p)->(shlview=%p shlbrs=%p rec=%p hwnd=%p vmode=%x flags=%x)\n", this, psvPrevious, psb, prcView, hwnd, mode, flags);
2544 if (prcView != NULL)
2545 TRACE("-- left=%i top=%i right=%i bottom=%i\n", prcView->left, prcView->top, prcView->right, prcView->bottom);
2546
2547 /* Validate the Shell Browser */
2548 if (psb == NULL || m_hWnd)
2549 return E_UNEXPECTED;
2550
2551 if (view_flags != SV3CVW3_DEFAULT)
2552 FIXME("unsupported view flags 0x%08x\n", view_flags);
2553
2554 /* Set up the member variables */
2555 m_pShellBrowser = psb;
2556 m_FolderSettings.ViewMode = mode;
2557 m_FolderSettings.fFlags = mask & flags;
2558
2559 if (view_id)
2560 {
2561 if (IsEqualIID(*view_id, VID_LargeIcons))
2562 m_FolderSettings.ViewMode = FVM_ICON;
2563 else if (IsEqualIID(*view_id, VID_SmallIcons))
2564 m_FolderSettings.ViewMode = FVM_SMALLICON;
2565 else if (IsEqualIID(*view_id, VID_List))
2566 m_FolderSettings.ViewMode = FVM_LIST;
2567 else if (IsEqualIID(*view_id, VID_Details))
2568 m_FolderSettings.ViewMode = FVM_DETAILS;
2569 else if (IsEqualIID(*view_id, VID_Thumbnails))
2570 m_FolderSettings.ViewMode = FVM_THUMBNAIL;
2571 else if (IsEqualIID(*view_id, VID_Tile))
2572 m_FolderSettings.ViewMode = FVM_TILE;
2573 else if (IsEqualIID(*view_id, VID_ThumbStrip))
2574 m_FolderSettings.ViewMode = FVM_THUMBSTRIP;
2575 else
2576 FIXME("Ignoring unrecognized VID %s\n", debugstr_guid(view_id));
2577 }
2578
2579 /* Get our parent window */
2580 m_pShellBrowser->GetWindow(&m_hWndParent);
2581
2582 /* Try to get the ICommDlgBrowserInterface, adds a reference !!! */
2583 m_pCommDlgBrowser = NULL;
2584 if (SUCCEEDED(m_pShellBrowser->QueryInterface(IID_PPV_ARG(ICommDlgBrowser, &m_pCommDlgBrowser))))
2585 {
2586 TRACE("-- CommDlgBrowser\n");
2587 }
2588
2589 Create(m_hWndParent, prcView, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP, 0, 0U);
2590 if (m_hWnd == NULL)
2591 return E_FAIL;
2592
2593 *hwnd = m_hWnd;
2594
2595 CheckToolbar();
2596
2597 if (!*hwnd)
2598 return E_FAIL;
2599
2600 _DoFolderViewCB(SFVM_WINDOWCREATED, (WPARAM)m_hWnd, NULL);
2601
2602 SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
2603 UpdateWindow();
2604
2605 if (!m_hMenu)
2606 {
2607 m_hMenu = CreateMenu();
2608 m_pShellBrowser->InsertMenusSB(m_hMenu, &omw);
2609 TRACE("-- after fnInsertMenusSB\n");
2610 }
2611
2612 _MergeToolbar();
2613
2614 return S_OK;
2615 }
2616
2617 HRESULT STDMETHODCALLTYPE CDefView::HandleRename(LPCITEMIDLIST new_pidl)
2618 {
2619 FIXME("(%p)->(%p) stub\n", this, new_pidl);
2620 return E_NOTIMPL;
2621 }
2622
2623 HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItem(LPCITEMIDLIST item, UINT flags, POINT *point)
2624 {
2625 FIXME("(%p)->(%p, %u, %p) stub\n", this, item, flags, point);
2626 return E_NOTIMPL;
2627 }
2628
2629 /**********************************************************
2630 * IShellFolderView implementation
2631 */
2632 HRESULT STDMETHODCALLTYPE CDefView::Rearrange(LPARAM sort)
2633 {
2634 FIXME("(%p)->(%ld) stub\n", this, sort);
2635 return E_NOTIMPL;
2636 }
2637
2638 HRESULT STDMETHODCALLTYPE CDefView::GetArrangeParam(LPARAM *sort)
2639 {
2640 FIXME("(%p)->(%p) stub\n", this, sort);
2641 return E_NOTIMPL;
2642 }
2643
2644 HRESULT STDMETHODCALLTYPE CDefView::ArrangeGrid()
2645 {
2646 FIXME("(%p) stub\n", this);
2647 return E_NOTIMPL;
2648 }
2649
2650 HRESULT STDMETHODCALLTYPE CDefView::AutoArrange()
2651 {
2652 FIXME("(%p) stub\n", this);
2653 return E_NOTIMPL;
2654 }
2655
2656 HRESULT STDMETHODCALLTYPE CDefView::AddObject(PITEMID_CHILD pidl, UINT *item)
2657 {
2658 FIXME("(%p)->(%p %p) stub\n", this, pidl, item);
2659 return E_NOTIMPL;
2660 }
2661
2662 HRESULT STDMETHODCALLTYPE CDefView::GetObject(PITEMID_CHILD *pidl, UINT item)
2663 {
2664 TRACE("(%p)->(%p %d)\n", this, pidl, item);
2665 return Item(item, pidl);
2666 }
2667
2668 HRESULT STDMETHODCALLTYPE CDefView::RemoveObject(PITEMID_CHILD pidl, UINT *item)
2669 {
2670
2671 TRACE("(%p)->(%p %p)\n", this, pidl, item);
2672
2673 if (pidl)
2674 {
2675 *item = LV_FindItemByPidl(ILFindLastID(pidl));
2676 m_ListView.DeleteItem(*item);
2677 }
2678 else
2679 {
2680 *item = 0;
2681 m_ListView.DeleteAllItems();
2682 }
2683
2684 return S_OK;
2685 }
2686
2687 HRESULT STDMETHODCALLTYPE CDefView::GetObjectCount(UINT *count)
2688 {
2689 TRACE("(%p)->(%p)\n", this, count);
2690 *count = m_ListView.GetItemCount();
2691 return S_OK;
2692 }
2693
2694 HRESULT STDMETHODCALLTYPE CDefView::SetObjectCount(UINT count, UINT flags)
2695 {
2696 FIXME("(%p)->(%d %x) stub\n", this, count, flags);
2697 return E_NOTIMPL;
2698 }
2699
2700 HRESULT STDMETHODCALLTYPE CDefView::UpdateObject(PITEMID_CHILD pidl_old, PITEMID_CHILD pidl_new, UINT *item)
2701 {
2702 FIXME("(%p)->(%p %p %p) stub\n", this, pidl_old, pidl_new, item);
2703 return E_NOTIMPL;
2704 }
2705
2706 HRESULT STDMETHODCALLTYPE CDefView::RefreshObject(PITEMID_CHILD pidl, UINT *item)
2707 {
2708 FIXME("(%p)->(%p %p) stub\n", this, pidl, item);
2709 return E_NOTIMPL;
2710 }
2711
2712 HRESULT STDMETHODCALLTYPE CDefView::SetRedraw(BOOL redraw)
2713 {
2714 TRACE("(%p)->(%d)\n", this, redraw);
2715 m_ListView.SetRedraw(redraw);
2716 return S_OK;
2717 }
2718
2719 HRESULT STDMETHODCALLTYPE CDefView::GetSelectedCount(UINT *count)
2720 {
2721 FIXME("(%p)->(%p) stub\n", this, count);
2722 return E_NOTIMPL;
2723 }
2724
2725 HRESULT STDMETHODCALLTYPE CDefView::GetSelectedObjects(PCUITEMID_CHILD **pidl, UINT *items)
2726 {
2727 TRACE("(%p)->(%p %p)\n", this, pidl, items);
2728
2729 *items = GetSelections();
2730
2731 if (*items)
2732 {
2733 *pidl = static_cast<PCUITEMID_CHILD *>(LocalAlloc(0, *items * sizeof(PCUITEMID_CHILD)));
2734 if (!*pidl)
2735 {
2736 return E_OUTOFMEMORY;
2737 }
2738
2739 /* it's documented that caller shouldn't PIDLs, only array itself */
2740 memcpy(*pidl, m_apidl, *items * sizeof(PCUITEMID_CHILD));
2741 }
2742
2743 return S_OK;
2744 }
2745
2746 HRESULT STDMETHODCALLTYPE CDefView::IsDropOnSource(IDropTarget *drop_target)
2747 {
2748 if ((m_iDragOverItem == -1 || m_pCurDropTarget == NULL) &&
2749 (m_pSourceDataObject.p))
2750 {
2751 return S_OK;
2752 }
2753
2754 return S_FALSE;
2755 }
2756
2757 HRESULT STDMETHODCALLTYPE CDefView::GetDragPoint(POINT *pt)
2758 {
2759 if (!pt)
2760 return E_INVALIDARG;
2761
2762 *pt = m_ptFirstMousePos;
2763 return S_OK;
2764 }
2765
2766 HRESULT STDMETHODCALLTYPE CDefView::GetDropPoint(POINT *pt)
2767 {
2768 FIXME("(%p)->(%p) stub\n", this, pt);
2769 return E_NOTIMPL;
2770 }
2771
2772 HRESULT STDMETHODCALLTYPE CDefView::MoveIcons(IDataObject *obj)
2773 {
2774 TRACE("(%p)->(%p)\n", this, obj);
2775 return E_NOTIMPL;
2776 }
2777
2778 HRESULT STDMETHODCALLTYPE CDefView::SetItemPos(PCUITEMID_CHILD pidl, POINT *pt)
2779 {
2780 FIXME("(%p)->(%p %p) stub\n", this, pidl, pt);
2781 return E_NOTIMPL;
2782 }
2783
2784 HRESULT STDMETHODCALLTYPE CDefView::IsBkDropTarget(IDropTarget *drop_target)
2785 {
2786 FIXME("(%p)->(%p) stub\n", this, drop_target);
2787 return E_NOTIMPL;
2788 }
2789
2790 HRESULT STDMETHODCALLTYPE CDefView::SetClipboard(BOOL move)
2791 {
2792 FIXME("(%p)->(%d) stub\n", this, move);
2793 return E_NOTIMPL;
2794 }
2795
2796 HRESULT STDMETHODCALLTYPE CDefView::SetPoints(IDataObject *obj)
2797 {
2798 FIXME("(%p)->(%p) stub\n", this, obj);
2799 return E_NOTIMPL;
2800 }
2801
2802 HRESULT STDMETHODCALLTYPE CDefView::GetItemSpacing(ITEMSPACING *spacing)
2803 {
2804 FIXME("(%p)->(%p) stub\n", this, spacing);
2805 return E_NOTIMPL;
2806 }
2807
2808 HRESULT STDMETHODCALLTYPE CDefView::SetCallback(IShellFolderViewCB *new_cb, IShellFolderViewCB **old_cb)
2809 {
2810 if (old_cb)
2811 *old_cb = m_pShellFolderViewCB.Detach();
2812
2813 m_pShellFolderViewCB = new_cb;
2814 return S_OK;
2815 }
2816
2817 HRESULT STDMETHODCALLTYPE CDefView::Select(UINT flags)
2818 {
2819 FIXME("(%p)->(%d) stub\n", this, flags);
2820 return E_NOTIMPL;
2821 }
2822
2823 HRESULT STDMETHODCALLTYPE CDefView::QuerySupport(UINT *support)
2824 {
2825 TRACE("(%p)->(%p)\n", this, support);
2826 return S_OK;
2827 }
2828
2829 HRESULT STDMETHODCALLTYPE CDefView::SetAutomationObject(IDispatch *disp)
2830 {
2831 FIXME("(%p)->(%p) stub\n", this, disp);
2832 return E_NOTIMPL;
2833 }
2834
2835 /**********************************************************
2836 * ISVOleCmdTarget_QueryStatus (IOleCommandTarget)
2837 */
2838 HRESULT WINAPI CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText)
2839 {
2840 FIXME("(%p)->(%p(%s) 0x%08x %p %p\n",
2841 this, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
2842
2843 if (!prgCmds)
2844 return E_INVALIDARG;
2845
2846 for (UINT i = 0; i < cCmds; i++)
2847 {
2848 FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID);
2849 prgCmds[i].cmdf = 0;
2850 }
2851
2852 return OLECMDERR_E_UNKNOWNGROUP;
2853 }
2854
2855 /**********************************************************
2856 * ISVOleCmdTarget_Exec (IOleCommandTarget)
2857 *
2858 * nCmdID is the OLECMDID_* enumeration
2859 */
2860 HRESULT WINAPI CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
2861 {
2862 FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n",
2863 this, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut);
2864
2865 if (!pguidCmdGroup)
2866 return OLECMDERR_E_UNKNOWNGROUP;
2867
2868 if (IsEqualCLSID(*pguidCmdGroup, m_Category))
2869 {
2870 if (nCmdID == FCIDM_SHVIEW_AUTOARRANGE)
2871 {
2872 if (V_VT(pvaIn) != VT_INT_PTR)
2873 return OLECMDERR_E_NOTSUPPORTED;
2874
2875 TPMPARAMS params;
2876 params.cbSize = sizeof(params);
2877 params.rcExclude = *(RECT*) V_INTREF(pvaIn);
2878
2879 if (m_hMenuViewModes)
2880 {
2881 /* Duplicate all but the last two items of the view modes menu */
2882 HMENU hmenuViewPopup = CreatePopupMenu();
2883 Shell_MergeMenus(hmenuViewPopup, m_hMenuViewModes, 0, 0, 0xFFFF, 0);
2884 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION);
2885 DeleteMenu(hmenuViewPopup, GetMenuItemCount(hmenuViewPopup) - 1, MF_BYPOSITION);
2886 CheckViewMode(hmenuViewPopup);
2887 TrackPopupMenuEx(hmenuViewPopup, TPM_LEFTALIGN | TPM_TOPALIGN, params.rcExclude.left, params.rcExclude.bottom, m_hWndParent, &params);
2888 ::DestroyMenu(hmenuViewPopup);
2889 }
2890
2891 // pvaOut is VT_I4 with value 0x403 (cmd id of the new mode maybe?)
2892 V_VT(pvaOut) = VT_I4;
2893 V_I4(pvaOut) = 0x403;
2894 }
2895 }
2896
2897 if (IsEqualIID(*pguidCmdGroup, CGID_Explorer) &&
2898 (nCmdID == 0x29) &&
2899 (nCmdexecopt == 4) && pvaOut)
2900 return S_OK;
2901
2902 if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView) &&
2903 (nCmdID == 9) &&
2904 (nCmdexecopt == 0))
2905 return 1;
2906
2907 return OLECMDERR_E_UNKNOWNGROUP;
2908 }
2909
2910 /**********************************************************
2911 * ISVDropTarget implementation
2912 */
2913
2914 /******************************************************************************
2915 * drag_notify_subitem [Internal]
2916 *
2917 * Figure out the shellfolder object, which is currently under the mouse cursor
2918 * and notify it via the IDropTarget interface.
2919 */
2920
2921 #define SCROLLAREAWIDTH 20
2922
2923 HRESULT CDefView::drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2924 {
2925 LONG lResult;
2926 HRESULT hr;
2927 RECT clientRect;
2928
2929 /* The key state on drop doesn't have MK_LBUTTON or MK_RBUTTON because it
2930 reflects the key state after the user released the button, so we need
2931 to remember the last key state when the button was pressed */
2932 m_grfKeyState = grfKeyState;
2933
2934 /* Map from global to client coordinates and query the index of the listview-item, which is
2935 * currently under the mouse cursor. */
2936 LVHITTESTINFO htinfo = {{pt.x, pt.y}, LVHT_ONITEM};
2937 ScreenToClient(&htinfo.pt);
2938 lResult = m_ListView.HitTest(&htinfo);
2939
2940 /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */
2941 ::GetClientRect(m_ListView, &clientRect);
2942 if (htinfo.pt.x == m_ptLastMousePos.x && htinfo.pt.y == m_ptLastMousePos.y &&
2943 (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH ||
2944 htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH ))
2945 {
2946 m_cScrollDelay = (m_cScrollDelay + 1) % 5; /* DragOver is called every 50 ms */
2947 if (m_cScrollDelay == 0)
2948 {
2949 /* Mouse did hover another 250 ms over the scroll-area */
2950 if (htinfo.pt.x < SCROLLAREAWIDTH)
2951 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEUP, 0);
2952
2953 if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH)
2954 m_ListView.SendMessageW(WM_HSCROLL, SB_LINEDOWN, 0);
2955
2956 if (htinfo.pt.y < SCROLLAREAWIDTH)
2957 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEUP, 0);
2958
2959 if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH)
2960 m_ListView.SendMessageW(WM_VSCROLL, SB_LINEDOWN, 0);
2961 }
2962 }
2963 else
2964 {
2965 m_cScrollDelay = 0; /* Reset, if the cursor is not over the listview's scroll-area */
2966 }
2967
2968 m_ptLastMousePos = htinfo.pt;
2969
2970 /* We need to check if we drag the selection over itself */
2971 if (lResult != -1 && m_pSourceDataObject.p != NULL)
2972 {
2973 PCUITEMID_CHILD pidl = _PidlByItem(lResult);
2974
2975 for (UINT i = 0; i < m_cidl; i++)
2976 {
2977 if (pidl == m_apidl[i])
2978 {
2979 /* The item that is being draged is hovering itself. */
2980 lResult = -1;
2981 break;
2982 }
2983 }
2984 }
2985
2986 /* If we are still over the previous sub-item, notify it via DragOver and return. */
2987 if (m_pCurDropTarget && lResult == m_iDragOverItem)
2988 return m_pCurDropTarget->DragOver(grfKeyState, pt, pdwEffect);
2989
2990 /* We've left the previous sub-item, notify it via DragLeave and Release it. */
2991 if (m_pCurDropTarget)
2992 {
2993 PCUITEMID_CHILD pidl = _PidlByItem(m_iDragOverItem);
2994 if (pidl)
2995 SelectItem(pidl, 0);
2996
2997 m_pCurDropTarget->DragLeave();
2998 m_pCurDropTarget.Release();
2999 }
3000
3001 m_iDragOverItem = lResult;
3002
3003 if (lResult == -1)
3004 {
3005 /* We are not above one of the listview's subitems. Bind to the parent folder's
3006 * DropTarget interface. */
3007 hr = m_pSFParent->CreateViewObject(NULL, IID_PPV_ARG(IDropTarget,&m_pCurDropTarget));
3008 }
3009 else
3010 {
3011 /* Query the relative PIDL of the shellfolder object represented by the currently
3012 * dragged over listview-item ... */
3013 PCUITEMID_CHILD pidl = _PidlByItem(lResult);
3014
3015 /* ... and bind m_pCurDropTarget to the IDropTarget interface of an UIObject of this object */
3016 hr = m_pSFParent->GetUIObjectOf(m_ListView, 1, &pidl, IID_NULL_PPV_ARG(IDropTarget, &m_pCurDropTarget));
3017 }
3018
3019 IUnknown_SetSite(m_pCurDropTarget, (IShellView *)this);
3020
3021 /* If anything failed, m_pCurDropTarget should be NULL now, which ought to be a save state. */
3022 if (FAILED(hr))
3023 {
3024 *pdwEffect = DROPEFFECT_NONE;
3025 return hr;
3026 }
3027
3028 if (m_iDragOverItem != -1)
3029 {
3030 SelectItem(m_iDragOverItem, SVSI_SELECT);
3031 }
3032
3033 /* Notify the item just entered via DragEnter. */
3034 return m_pCurDropTarget->DragEnter(m_pCurDataObject, grfKeyState, pt, pdwEffect);
3035 }
3036
3037 HRESULT WINAPI CDefView::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3038 {
3039 /* Get a hold on the data object for later calls to DragEnter on the sub-folders */
3040 m_pCurDataObject = pDataObject;
3041
3042 HRESULT hr = drag_notify_subitem(grfKeyState, pt, pdwEffect);
3043 if (SUCCEEDED(hr))
3044 {
3045 POINT ptClient = {pt.x, pt.y};
3046 ScreenToClient(&ptClient);
3047 ImageList_DragEnter(m_hWnd, ptClient.x, ptClient.y);
3048 }
3049
3050 return hr;
3051 }
3052
3053 HRESULT WINAPI CDefView::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3054 {
3055 POINT ptClient = {pt.x, pt.y};
3056 ScreenToClient(&ptClient);
3057 ImageList_DragMove(ptClient.x, ptClient.y);
3058 return drag_notify_subitem(grfKeyState, pt, pdwEffect);
3059 }
3060
3061 HRESULT WINAPI CDefView::DragLeave()
3062 {
3063 ImageList_DragLeave(m_hWnd);
3064
3065 if (m_pCurDropTarget)
3066 {
3067 m_pCurDropTarget->DragLeave();
3068 m_pCurDropTarget.Release();
3069 }
3070
3071 if (m_pCurDataObject != NULL)
3072 {
3073 m_pCurDataObject.Release();
3074 }
3075
3076 m_iDragOverItem = 0;
3077
3078 return S_OK;
3079 }
3080
3081 HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
3082 {
3083 ImageList_DragLeave(m_hWnd);
3084 ImageList_EndDrag();
3085
3086 if ((IsDropOnSource(NULL) == S_OK) &&
3087 (*pdwEffect & DROPEFFECT_MOVE) &&
3088 (m_grfKeyState & MK_LBUTTON))
3089 {
3090 if (m_pCurDropTarget)
3091 {
3092 m_pCurDropTarget->DragLeave();
3093 m_pCurDropTarget.Release();
3094 }
3095
3096 /* Restore the selection */
3097 m_ListView.SetItemState(-1, 0, LVIS_SELECTED);
3098 for (UINT i = 0 ; i < m_cidl; i++)
3099 SelectItem(m_apidl[i], SVSI_SELECT);
3100
3101 /* Reposition the items */
3102 int lvIndex = -1;
3103 while ((lvIndex = m_ListView.GetNextItem(lvIndex, LVNI_SELECTED)) > -1)
3104 {
3105 POINT ptItem;
3106 if (m_ListView.GetItemPosition(lvIndex, &ptItem))
3107 {
3108 ptItem.x += pt.x - m_ptFirstMousePos.x;
3109 ptItem.y += pt.y - m_ptFirstMousePos.y;
3110 m_ListView.SetItemPosition(lvIndex, &ptItem);
3111 }
3112 }
3113 }
3114 else if (m_pCurDropTarget)
3115 {
3116 m_pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect);
3117 m_pCurDropTarget.Release();
3118 }
3119
3120 m_pCurDataObject.Release();
3121 m_iDragOverItem = 0;
3122 return S_OK;
3123 }
3124
3125 /**********************************************************
3126 * ISVDropSource implementation
3127 */
3128
3129 HRESULT WINAPI CDefView::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
3130 {
3131 TRACE("(%p)\n", this);
3132
3133 if (fEscapePressed)
3134 return DRAGDROP_S_CANCEL;
3135 else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON))
3136 return DRAGDROP_S_DROP;
3137 else
3138 return S_OK;
3139 }
3140
3141 HRESULT WINAPI CDefView::GiveFeedback(DWORD dwEffect)
3142 {
3143 TRACE("(%p)\n", this);
3144
3145 return DRAGDROP_S_USEDEFAULTCURSORS;
3146 }
3147
3148 /**********************************************************
3149 * ISVViewObject implementation
3150 */
3151
3152 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)
3153 {
3154 FIXME("Stub: this=%p\n", this);
3155
3156 return E_NOTIMPL;
3157 }
3158
3159 HRESULT WINAPI CDefView::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet)
3160 {
3161 FIXME("Stub: this=%p\n", this);
3162
3163 return E_NOTIMPL;
3164 }
3165
3166 HRESULT WINAPI CDefView::Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze)
3167 {
3168 FIXME("Stub: this=%p\n", this);
3169
3170 return E_NOTIMPL;
3171 }
3172
3173 HRESULT WINAPI CDefView::Unfreeze(DWORD dwFreeze)
3174 {
3175 FIXME("Stub: this=%p\n", this);
3176
3177 return E_NOTIMPL;
3178 }
3179
3180 HRESULT WINAPI CDefView::SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink)
3181 {
3182 FIXME("partial stub: %p %08x %08x %p\n", this, aspects, advf, pAdvSink);
3183
3184 /* FIXME: we set the AdviseSink, but never use it to send any advice */
3185 m_pAdvSink = pAdvSink;
3186 m_dwAspects = aspects;
3187 m_dwAdvf = advf;
3188
3189 return S_OK;
3190 }
3191
3192 HRESULT WINAPI CDefView::GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink)
3193 {
3194 TRACE("this=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n", this, pAspects, pAdvf, ppAdvSink);
3195
3196 if (ppAdvSink)
3197 {
3198 *ppAdvSink = m_pAdvSink;
3199 m_pAdvSink.p->AddRef();
3200 }
3201
3202 if (pAspects)
3203 *pAspects = m_dwAspects;
3204
3205 if (pAdvf)
3206 *pAdvf = m_dwAdvf;
3207
3208 return S_OK;
3209 }
3210
3211 HRESULT STDMETHODCALLTYPE CDefView::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
3212 {
3213 if (IsEqualIID(guidService, SID_IShellBrowser))
3214 return m_pShellBrowser->QueryInterface(riid, ppvObject);
3215 else if(IsEqualIID(guidService, SID_IFolderView))
3216 return QueryInterface(riid, ppvObject);
3217
3218 return E_NOINTERFACE;
3219 }
3220
3221 HRESULT CDefView::_MergeToolbar()
3222 {
3223 CComPtr<IExplorerToolbar> ptb;
3224 HRESULT hr = S_OK;
3225
3226 hr = IUnknown_QueryService(m_pShellBrowser, IID_IExplorerToolbar, IID_PPV_ARG(IExplorerToolbar, &ptb));
3227 if (FAILED(hr))
3228 return hr;
3229
3230 m_Category = CGID_DefViewFrame;
3231
3232 hr = ptb->SetCommandTarget(static_cast<IOleCommandTarget*>(this), &m_Category, 0);
3233 if (FAILED(hr))
3234 return hr;
3235
3236 if (hr == S_FALSE)
3237 return S_OK;
3238
3239 #if 0
3240 hr = ptb->AddButtons(&m_Category, buttonsCount, buttons);
3241 if (FAILED(hr))
3242 return hr;
3243 #endif
3244
3245 return S_OK;
3246 }
3247
3248 VOID CDefView::_DoFolderViewCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
3249 {
3250 if (m_pShellFolderViewCB)
3251 {
3252 m_pShellFolderViewCB->MessageSFVCB(uMsg, wParam, lParam);
3253 }
3254 }
3255
3256 HRESULT CDefView_CreateInstance(IShellFolder *pFolder, REFIID riid, LPVOID * ppvOut)
3257 {
3258 return ShellObjectCreatorInit<CDefView>(pFolder, riid, ppvOut);
3259 }
3260
3261 HRESULT WINAPI SHCreateShellFolderViewEx(
3262 LPCSFV psvcbi, /* [in] shelltemplate struct */
3263 IShellView **ppsv) /* [out] IShellView pointer */
3264 {
3265 CComPtr<IShellView> psv;
3266 HRESULT hRes;
3267
3268 TRACE("sf=%p pidl=%p cb=%p mode=0x%08x parm=%p\n",
3269 psvcbi->pshf, psvcbi->pidl, psvcbi->pfnCallback,
3270 psvcbi->fvm, psvcbi->psvOuter);
3271
3272 *ppsv = NULL;
3273 hRes = CDefView_CreateInstance(psvcbi->pshf, IID_PPV_ARG(IShellView, &psv));
3274 if (FAILED_UNEXPECTEDLY(hRes))
3275 return hRes;
3276
3277 *ppsv = psv.Detach();
3278 return hRes;
3279 }
3280
3281 HRESULT WINAPI SHCreateShellFolderView(const SFV_CREATE *pcsfv,
3282 IShellView **ppsv)
3283 {
3284 CComPtr<IShellView> psv;
3285 HRESULT hRes;
3286
3287 *ppsv = NULL;
3288 if (!pcsfv || pcsfv->cbSize != sizeof(*pcsfv))
3289 return E_INVALIDARG;
3290
3291 TRACE("sf=%p outer=%p callback=%p\n",
3292 pcsfv->pshf, pcsfv->psvOuter, pcsfv->psfvcb);
3293
3294 hRes = CDefView_CreateInstance(pcsfv->pshf, IID_PPV_ARG(IShellView, &psv));
3295 if (FAILED(hRes))
3296 return hRes;
3297
3298 if (pcsfv->psfvcb)
3299 {
3300 CComPtr<IShellFolderView> sfv;
3301 if (SUCCEEDED(psv->QueryInterface(IID_PPV_ARG(IShellFolderView, &sfv))))
3302 {
3303 sfv->SetCallback(pcsfv->psfvcb, NULL);
3304 }
3305 }
3306
3307 *ppsv = psv.Detach();
3308 return hRes;
3309 }