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