Sync with trunk r63283
[reactos.git] / dll / win32 / shell32 / shlview.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: The order by part of the background context menu should be
24 * built according to the columns shown.
25 *
26 * FIXME: CheckToolbar: handle the "new folder" and "folder up" button
27 *
28 * FIXME: ShellView_FillList: consider sort orders
29 */
30
31 /*
32 TODO:
33 1. Load/Save the view state from/into the stream provided by the ShellBrowser.
34 2. Let the shell folder sort items.
35 3. Code to merge menus in the shellbrowser is incorrect.
36 4. Move the background context menu creation into shell view. It should store the
37 shell view HWND to send commands.
38 5. Send init, measure, and draw messages to context menu during tracking.
39 6. Shell view should do SetCommandTarget on internet toolbar.
40 7. When editing starts on item, set edit text to for editing value.
41 8. When shell view is called back for item info, let listview save the value.
42 9. Shell view should update status bar.
43 10. Fix shell view to handle view mode popup exec.
44 11. The background context menu should have a pidl just like foreground menus. This
45 causes crashes when dynamic handlers try to use the NULL pidl.
46 12. The SHELLDLL_DefView should not be filled with blue unconditionally. This causes
47 annoying flashing of blue even on XP, and is not correct.
48 13. Reorder of columns doesn't work - might be bug in comctl32
49 */
50
51 #include "precomp.h"
52
53 #include <atlwin.h>
54
55 WINE_DEFAULT_DEBUG_CHANNEL(shell);
56
57 #undef SV_CLASS_NAME
58
59 static const WCHAR SV_CLASS_NAME[] = {'S', 'H', 'E', 'L', 'L', 'D', 'L', 'L', '_', 'D', 'e', 'f', 'V', 'i', 'e', 'w', 0};
60
61 typedef struct
62 { BOOL bIsAscending;
63 INT nHeaderID;
64 INT nLastHeaderID;
65 } LISTVIEW_SORT_INFO, *LPLISTVIEW_SORT_INFO;
66
67 #define SHV_CHANGE_NOTIFY WM_USER + 0x1111
68
69 class CDefView :
70 public CWindowImpl<CDefView, CWindow, CControlWinTraits>,
71 public CComObjectRootEx<CComMultiThreadModelNoCS>,
72 public IShellView,
73 public IFolderView,
74 public IOleCommandTarget,
75 public IDropTarget,
76 public IDropSource,
77 public IViewObject,
78 public IServiceProvider
79 {
80 private:
81 CComPtr<IShellFolder> m_pSFParent;
82 CComPtr<IShellFolder2> m_pSF2Parent;
83 CComPtr<IShellBrowser> m_pShellBrowser;
84 CComPtr<ICommDlgBrowser> m_pCommDlgBrowser;
85 HWND m_hWndList; /* ListView control */
86 HWND m_hWndParent;
87 FOLDERSETTINGS m_FolderSettings;
88 HMENU m_hMenu;
89 UINT m_uState;
90 UINT m_cidl;
91 LPITEMIDLIST *m_apidl;
92 LISTVIEW_SORT_INFO m_sortInfo;
93 ULONG m_hNotify; /* change notification handle */
94 HACCEL m_hAccel;
95 DWORD m_dwAspects;
96 DWORD m_dwAdvf;
97 CComPtr<IAdviseSink> m_pAdvSink;
98 // for drag and drop
99 CComPtr<IDropTarget> m_pCurDropTarget; /* The sub-item, which is currently dragged over */
100 CComPtr<IDataObject> m_pCurDataObject; /* The dragged data-object */
101 LONG m_iDragOverItem; /* Dragged over item's index, iff m_pCurDropTarget != NULL */
102 UINT m_cScrollDelay; /* Send a WM_*SCROLL msg every 250 ms during drag-scroll */
103 POINT m_ptLastMousePos; /* Mouse position at last DragOver call */
104 //
105 CComPtr<IContextMenu> m_pCM;
106 public:
107 CDefView();
108 ~CDefView();
109 HRESULT WINAPI Initialize(IShellFolder *shellFolder);
110 HRESULT IncludeObject(LPCITEMIDLIST pidl);
111 HRESULT OnDefaultCommand();
112 HRESULT OnStateChange(UINT uFlags);
113 void CheckToolbar();
114 void SetStyle(DWORD dwAdd, DWORD dwRemove);
115 BOOL CreateList();
116 void UpdateListColors();
117 BOOL InitList();
118 static INT CALLBACK CompareItems(LPVOID lParam1, LPVOID lParam2, LPARAM lpData);
119 static INT CALLBACK ListViewCompareItems(LPVOID lParam1, LPVOID lParam2, LPARAM lpData);
120 int LV_FindItemByPidl(LPCITEMIDLIST pidl);
121 BOOLEAN LV_AddItem(LPCITEMIDLIST pidl);
122 BOOLEAN LV_DeleteItem(LPCITEMIDLIST pidl);
123 BOOLEAN LV_RenameItem(LPCITEMIDLIST pidlOld, LPCITEMIDLIST pidlNew);
124 static INT CALLBACK fill_list(LPVOID ptr, LPVOID arg);
125 HRESULT FillList();
126 HMENU BuildFileMenu();
127 void MergeFileMenu(HMENU hSubMenu);
128 void MergeViewMenu(HMENU hSubMenu);
129 UINT GetSelections();
130 HRESULT OpenSelectedItems();
131 void OnDeactivate();
132 void DoActivate(UINT uState);
133 HRESULT drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
134 LRESULT OnExplorerCommand(UINT uCommand, BOOL bUseSelection);
135
136 // *** IOleWindow methods ***
137 virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *lphwnd);
138 virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode);
139
140 // *** IShellView methods ***
141 virtual HRESULT STDMETHODCALLTYPE TranslateAccelerator(MSG *pmsg);
142 virtual HRESULT STDMETHODCALLTYPE EnableModeless(BOOL fEnable);
143 virtual HRESULT STDMETHODCALLTYPE UIActivate(UINT uState);
144 virtual HRESULT STDMETHODCALLTYPE Refresh();
145 virtual HRESULT STDMETHODCALLTYPE CreateViewWindow(IShellView *psvPrevious, LPCFOLDERSETTINGS pfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd);
146 virtual HRESULT STDMETHODCALLTYPE DestroyViewWindow();
147 virtual HRESULT STDMETHODCALLTYPE GetCurrentInfo(LPFOLDERSETTINGS pfs);
148 virtual HRESULT STDMETHODCALLTYPE AddPropertySheetPages(DWORD dwReserved, LPFNSVADDPROPSHEETPAGE pfn, LPARAM lparam);
149 virtual HRESULT STDMETHODCALLTYPE SaveViewState();
150 virtual HRESULT STDMETHODCALLTYPE SelectItem(LPCITEMIDLIST pidlItem, SVSIF uFlags);
151 virtual HRESULT STDMETHODCALLTYPE GetItemObject(UINT uItem, REFIID riid, void **ppv);
152
153 // *** IFolderView methods ***
154 virtual HRESULT STDMETHODCALLTYPE GetCurrentViewMode(UINT *pViewMode);
155 virtual HRESULT STDMETHODCALLTYPE SetCurrentViewMode(UINT ViewMode);
156 virtual HRESULT STDMETHODCALLTYPE GetFolder(REFIID riid, void **ppv);
157 virtual HRESULT STDMETHODCALLTYPE Item(int iItemIndex, LPITEMIDLIST *ppidl);
158 virtual HRESULT STDMETHODCALLTYPE ItemCount(UINT uFlags, int *pcItems);
159 virtual HRESULT STDMETHODCALLTYPE Items(UINT uFlags, REFIID riid, void **ppv);
160 virtual HRESULT STDMETHODCALLTYPE GetSelectionMarkedItem(int *piItem);
161 virtual HRESULT STDMETHODCALLTYPE GetFocusedItem(int *piItem);
162 virtual HRESULT STDMETHODCALLTYPE GetItemPosition(LPCITEMIDLIST pidl, POINT *ppt);
163 virtual HRESULT STDMETHODCALLTYPE GetSpacing(POINT *ppt);
164 virtual HRESULT STDMETHODCALLTYPE GetDefaultSpacing(POINT *ppt);
165 virtual HRESULT STDMETHODCALLTYPE GetAutoArrange();
166 virtual HRESULT STDMETHODCALLTYPE SelectItem(int iItem, DWORD dwFlags);
167 virtual HRESULT STDMETHODCALLTYPE SelectAndPositionItems(UINT cidl, LPCITEMIDLIST *apidl, POINT *apt, DWORD dwFlags);
168
169 // *** IOleCommandTarget methods ***
170 virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[ ], OLECMDTEXT *pCmdText);
171 virtual HRESULT STDMETHODCALLTYPE Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut);
172
173 // *** IDropTarget methods ***
174 virtual HRESULT STDMETHODCALLTYPE DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
175 virtual HRESULT STDMETHODCALLTYPE DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
176 virtual HRESULT STDMETHODCALLTYPE DragLeave();
177 virtual HRESULT STDMETHODCALLTYPE Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
178
179 // *** IDropSource methods ***
180 virtual HRESULT STDMETHODCALLTYPE QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState);
181 virtual HRESULT STDMETHODCALLTYPE GiveFeedback(DWORD dwEffect);
182
183 // *** IViewObject methods ***
184 virtual HRESULT STDMETHODCALLTYPE Draw(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd,
185 HDC hdcTargetDev, HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL lprcWBounds,
186 BOOL ( STDMETHODCALLTYPE *pfnContinue )(ULONG_PTR dwContinue), ULONG_PTR dwContinue);
187 virtual HRESULT STDMETHODCALLTYPE GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect,
188 DVTARGETDEVICE *ptd, HDC hicTargetDev, LOGPALETTE **ppColorSet);
189 virtual HRESULT STDMETHODCALLTYPE Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze);
190 virtual HRESULT STDMETHODCALLTYPE Unfreeze(DWORD dwFreeze);
191 virtual HRESULT STDMETHODCALLTYPE SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink);
192 virtual HRESULT STDMETHODCALLTYPE GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink);
193
194 // *** IServiceProvider methods ***
195 virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject);
196
197 // message handlers
198 LRESULT OnShowWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
199 LRESULT OnGetDlgCode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
200 LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
201 LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
202 LRESULT OnSysColorChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
203 LRESULT OnGetShellBrowser(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
204 LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
205 LRESULT OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
206 LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
207 LRESULT OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
208 LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
209 LRESULT OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
210 LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
211 LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
212 LRESULT OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
213 LRESULT OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
214 LRESULT OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
215
216 static ATL::CWndClassInfo& GetWndClassInfo()
217 {
218 static ATL::CWndClassInfo wc =
219 {
220 { sizeof(WNDCLASSEX), 0, StartWindowProc,
221 0, 0, NULL, NULL,
222 LoadCursor(NULL, IDC_ARROW), (HBRUSH)(COLOR_BACKGROUND + 1), NULL, SV_CLASS_NAME, NULL
223 },
224 NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
225 };
226 return wc;
227 }
228
229 virtual WNDPROC GetWindowProc()
230 {
231 return WindowProc;
232 }
233
234 static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
235 {
236 CDefView *pThis;
237 LRESULT result;
238
239 // must hold a reference during message handling
240 pThis = reinterpret_cast<CDefView *>(hWnd);
241 pThis->AddRef();
242 result = CWindowImpl<CDefView, CWindow, CControlWinTraits>::WindowProc(hWnd, uMsg, wParam, lParam);
243 pThis->Release();
244 return result;
245 }
246
247 BEGIN_MSG_MAP(CDefView)
248 MESSAGE_HANDLER(WM_SIZE, OnSize)
249 MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
250 MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)
251 MESSAGE_HANDLER(WM_CREATE, OnCreate)
252 MESSAGE_HANDLER(WM_ACTIVATE, OnActivate)
253 MESSAGE_HANDLER(WM_NOTIFY, OnNotify)
254 MESSAGE_HANDLER(WM_COMMAND, OnCommand)
255 MESSAGE_HANDLER(SHV_CHANGE_NOTIFY, OnChangeNotify)
256 MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu)
257 MESSAGE_HANDLER(WM_DRAWITEM, OnCustomItem)
258 MESSAGE_HANDLER(WM_MEASUREITEM, OnCustomItem)
259 MESSAGE_HANDLER(WM_SHOWWINDOW, OnShowWindow)
260 MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode)
261 MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
262 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
263 MESSAGE_HANDLER(WM_SYSCOLORCHANGE, OnSysColorChange)
264 MESSAGE_HANDLER(CWM_GETISHELLBROWSER, OnGetShellBrowser)
265 MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
266 END_MSG_MAP()
267
268 BEGIN_COM_MAP(CDefView)
269 COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow)
270 COM_INTERFACE_ENTRY_IID(IID_IShellView, IShellView)
271 COM_INTERFACE_ENTRY_IID(IID_IFolderView, IFolderView)
272 COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget)
273 COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget)
274 COM_INTERFACE_ENTRY_IID(IID_IDropSource, IDropSource)
275 COM_INTERFACE_ENTRY_IID(IID_IViewObject, IViewObject)
276 COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider)
277 END_COM_MAP()
278 };
279
280 /* ListView Header ID's */
281 #define LISTVIEW_COLUMN_NAME 0
282 #define LISTVIEW_COLUMN_SIZE 1
283 #define LISTVIEW_COLUMN_TYPE 2
284 #define LISTVIEW_COLUMN_TIME 3
285 #define LISTVIEW_COLUMN_ATTRIB 4
286
287 /*menu items */
288 #define IDM_VIEW_FILES (FCIDM_SHVIEWFIRST + 0x500)
289 #define IDM_VIEW_IDW (FCIDM_SHVIEWFIRST + 0x501)
290 #define IDM_MYFILEITEM (FCIDM_SHVIEWFIRST + 0x502)
291
292 #define ID_LISTVIEW 1
293
294 /*windowsx.h */
295 #define GET_WM_COMMAND_ID(wp, lp) LOWORD(wp)
296 #define GET_WM_COMMAND_HWND(wp, lp) (HWND)(lp)
297 #define GET_WM_COMMAND_CMD(wp, lp) HIWORD(wp)
298
299 /*
300 Items merged into the toolbar and the filemenu
301 */
302 typedef struct
303 { int idCommand;
304 int iImage;
305 int idButtonString;
306 int idMenuString;
307 BYTE bState;
308 BYTE bStyle;
309 } MYTOOLINFO, *LPMYTOOLINFO;
310
311 static const MYTOOLINFO Tools[] =
312 {
313 { FCIDM_SHVIEW_BIGICON, 0, 0, IDS_VIEW_LARGE, TBSTATE_ENABLED, BTNS_BUTTON },
314 { FCIDM_SHVIEW_SMALLICON, 0, 0, IDS_VIEW_SMALL, TBSTATE_ENABLED, BTNS_BUTTON },
315 { FCIDM_SHVIEW_LISTVIEW, 0, 0, IDS_VIEW_LIST, TBSTATE_ENABLED, BTNS_BUTTON },
316 { FCIDM_SHVIEW_REPORTVIEW, 0, 0, IDS_VIEW_DETAILS, TBSTATE_ENABLED, BTNS_BUTTON },
317 { -1, 0, 0, 0, 0, 0}
318 };
319
320 typedef void (CALLBACK *PFNSHGETSETTINGSPROC)(LPSHELLFLAGSTATE lpsfs, DWORD dwMask);
321
322 CDefView::CDefView()
323 {
324 m_hWndList = NULL;
325 m_hWndParent = NULL;
326 m_FolderSettings.fFlags = 0;
327 m_FolderSettings.ViewMode = 0;
328 m_hMenu = NULL;
329 m_uState = 0;
330 m_cidl = 0;
331 m_apidl = NULL;
332 m_sortInfo.bIsAscending = FALSE;
333 m_sortInfo.nHeaderID = 0;
334 m_sortInfo.nLastHeaderID = 0;
335 m_hNotify = 0;
336 m_hAccel = NULL;
337 m_dwAspects = 0;
338 m_dwAdvf = 0;
339 m_iDragOverItem = 0;
340 m_cScrollDelay = 0;
341 m_ptLastMousePos.x = 0;
342 m_ptLastMousePos.y = 0;
343 }
344
345 CDefView::~CDefView()
346 {
347 TRACE(" destroying IShellView(%p)\n", this);
348
349 SHFree(m_apidl);
350 }
351
352 HRESULT WINAPI CDefView::Initialize(IShellFolder *shellFolder)
353 {
354 m_pSFParent = shellFolder;
355 shellFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, &m_pSF2Parent));
356
357 return S_OK;
358 }
359
360 /**********************************************************
361 *
362 * ##### helperfunctions for communication with ICommDlgBrowser #####
363 */
364 HRESULT CDefView::IncludeObject(LPCITEMIDLIST pidl)
365 {
366 HRESULT ret = S_OK;
367
368 if (m_pCommDlgBrowser.p != NULL)
369 {
370 TRACE("ICommDlgBrowser::IncludeObject pidl=%p\n", pidl);
371 ret = m_pCommDlgBrowser->IncludeObject((IShellView *)this, pidl);
372 TRACE("--0x%08x\n", ret);
373 }
374
375 return ret;
376 }
377
378 HRESULT CDefView::OnDefaultCommand()
379 {
380 HRESULT ret = S_FALSE;
381
382 if (m_pCommDlgBrowser.p != NULL)
383 {
384 TRACE("ICommDlgBrowser::OnDefaultCommand\n");
385 ret = m_pCommDlgBrowser->OnDefaultCommand((IShellView *)this);
386 TRACE("-- returns %08x\n", ret);
387 }
388
389 return ret;
390 }
391
392 HRESULT CDefView::OnStateChange(UINT uFlags)
393 {
394 HRESULT ret = S_FALSE;
395
396 if (m_pCommDlgBrowser.p != NULL)
397 {
398 TRACE("ICommDlgBrowser::OnStateChange flags=%x\n", uFlags);
399 ret = m_pCommDlgBrowser->OnStateChange((IShellView *)this, uFlags);
400 TRACE("--\n");
401 }
402
403 return ret;
404 }
405 /**********************************************************
406 * set the toolbar of the filedialog buttons
407 *
408 * - activates the buttons from the shellbrowser according to
409 * the view state
410 */
411 void CDefView::CheckToolbar()
412 {
413 LRESULT result;
414
415 TRACE("\n");
416
417 if (m_pCommDlgBrowser != NULL)
418 {
419 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_CHECKBUTTON,
420 FCIDM_TB_SMALLICON, (m_FolderSettings.ViewMode == FVM_LIST) ? TRUE : FALSE, &result);
421 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_CHECKBUTTON,
422 FCIDM_TB_REPORTVIEW, (m_FolderSettings.ViewMode == FVM_DETAILS) ? TRUE : FALSE, &result);
423 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON,
424 FCIDM_TB_SMALLICON, TRUE, &result);
425 m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON,
426 FCIDM_TB_REPORTVIEW, TRUE, &result);
427 }
428 }
429
430 /**********************************************************
431 *
432 * ##### helperfunctions for initializing the view #####
433 */
434 /**********************************************************
435 * change the style of the listview control
436 */
437 void CDefView::SetStyle(DWORD dwAdd, DWORD dwRemove)
438 {
439 DWORD tmpstyle;
440
441 TRACE("(%p)\n", this);
442
443 tmpstyle = ::GetWindowLongPtrW(m_hWndList, GWL_STYLE);
444 ::SetWindowLongPtrW(m_hWndList, GWL_STYLE, dwAdd | (tmpstyle & ~dwRemove));
445 }
446
447 /**********************************************************
448 * ShellView_CreateList()
449 *
450 * - creates the list view window
451 */
452 BOOL CDefView::CreateList()
453 { DWORD dwStyle, dwExStyle;
454
455 TRACE("%p\n", this);
456
457 dwStyle = WS_TABSTOP | WS_VISIBLE | WS_CHILDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
458 LVS_SHAREIMAGELISTS | LVS_EDITLABELS | LVS_AUTOARRANGE;
459 dwExStyle = WS_EX_CLIENTEDGE;
460
461 if (m_FolderSettings.fFlags & FWF_DESKTOP)
462 dwStyle |= LVS_ALIGNLEFT;
463 else
464 dwStyle |= LVS_ALIGNTOP;
465
466 switch (m_FolderSettings.ViewMode)
467 {
468 case FVM_ICON:
469 dwStyle |= LVS_ICON;
470 break;
471
472 case FVM_DETAILS:
473 dwStyle |= LVS_REPORT;
474 break;
475
476 case FVM_SMALLICON:
477 dwStyle |= LVS_SMALLICON;
478 break;
479
480 case FVM_LIST:
481 dwStyle |= LVS_LIST;
482 break;
483
484 default:
485 dwStyle |= LVS_LIST;
486 break;
487 }
488
489 if (m_FolderSettings.fFlags & FWF_AUTOARRANGE)
490 dwStyle |= LVS_AUTOARRANGE;
491
492 if (m_FolderSettings.fFlags & FWF_DESKTOP)
493 m_FolderSettings.fFlags |= FWF_NOCLIENTEDGE | FWF_NOSCROLL;
494
495 if (m_FolderSettings.fFlags & FWF_SINGLESEL)
496 dwStyle |= LVS_SINGLESEL;
497
498 if (m_FolderSettings.fFlags & FWF_NOCLIENTEDGE)
499 dwExStyle &= ~WS_EX_CLIENTEDGE;
500
501 m_hWndList = CreateWindowExW( dwExStyle,
502 WC_LISTVIEWW,
503 NULL,
504 dwStyle,
505 0, 0, 0, 0,
506 m_hWnd,
507 (HMENU)ID_LISTVIEW,
508 shell32_hInstance,
509 NULL);
510
511 if (!m_hWndList)
512 return FALSE;
513
514 m_sortInfo.bIsAscending = TRUE;
515 m_sortInfo.nHeaderID = -1;
516 m_sortInfo.nLastHeaderID = -1;
517
518 UpdateListColors();
519
520 /* UpdateShellSettings(); */
521 return TRUE;
522 }
523
524 void CDefView::UpdateListColors()
525 {
526 if (m_FolderSettings.fFlags & FWF_DESKTOP)
527 {
528 /* Check if drop shadows option is enabled */
529 BOOL bDropShadow = FALSE;
530 DWORD cbDropShadow = sizeof(bDropShadow);
531 WCHAR wszBuf[16] = L"";
532
533 RegGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
534 L"ListviewShadow", RRF_RT_DWORD, NULL, &bDropShadow, &cbDropShadow);
535 if (bDropShadow && SystemParametersInfoW(SPI_GETDESKWALLPAPER, _countof(wszBuf), wszBuf, 0) && wszBuf[0])
536 {
537 SendMessageW(m_hWndList, LVM_SETTEXTBKCOLOR, 0, CLR_NONE);
538 SendMessageW(m_hWndList, LVM_SETBKCOLOR, 0, CLR_NONE);
539 SendMessageW(m_hWndList, LVM_SETTEXTCOLOR, 0, RGB(255, 255, 255));
540 SendMessageW(m_hWndList, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTSHADOWTEXT, LVS_EX_TRANSPARENTSHADOWTEXT);
541 }
542 else
543 {
544 COLORREF crDesktop = GetSysColor(COLOR_DESKTOP);
545 SendMessageW(m_hWndList, LVM_SETTEXTBKCOLOR, 0, crDesktop);
546 SendMessageW(m_hWndList, LVM_SETBKCOLOR, 0, crDesktop);
547 if (GetRValue(crDesktop) + GetGValue(crDesktop) + GetBValue(crDesktop) > 128 * 3)
548 SendMessageW(m_hWndList, LVM_SETTEXTCOLOR, 0, RGB(0, 0, 0));
549 else
550 SendMessageW(m_hWndList, LVM_SETTEXTCOLOR, 0, RGB(255, 255, 255));
551 SendMessageW(m_hWndList, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_TRANSPARENTSHADOWTEXT, 0);
552 }
553 }
554 }
555
556 /**********************************************************
557 * ShellView_InitList()
558 *
559 * - adds all needed columns to the shellview
560 */
561 BOOL CDefView::InitList()
562 {
563 LVCOLUMNW lvColumn;
564 SHELLDETAILS sd;
565 WCHAR szTemp[50];
566
567 TRACE("%p\n", this);
568
569 SendMessageW(m_hWndList, LVM_DELETEALLITEMS, 0, 0);
570
571 lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT;
572 lvColumn.pszText = szTemp;
573
574 if (m_pSF2Parent)
575 {
576 for (int i = 0; 1; i++)
577 {
578 if (FAILED(m_pSF2Parent->GetDetailsOf(NULL, i, &sd)))
579 break;
580
581 lvColumn.fmt = sd.fmt;
582 lvColumn.cx = sd.cxChar * 8; /* chars->pixel */
583 StrRetToStrNW( szTemp, 50, &sd.str, NULL);
584 SendMessageW(m_hWndList, LVM_INSERTCOLUMNW, i, (LPARAM) &lvColumn);
585 }
586 }
587 else
588 {
589 FIXME("no SF2\n");
590 }
591
592 SendMessageW(m_hWndList, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)ShellSmallIconList);
593 SendMessageW(m_hWndList, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)ShellBigIconList);
594
595 return TRUE;
596 }
597
598 /**********************************************************
599 * ShellView_CompareItems()
600 *
601 * NOTES
602 * internal, CALLBACK for DSA_Sort
603 */
604 INT CALLBACK CDefView::CompareItems(LPVOID lParam1, LPVOID lParam2, LPARAM lpData)
605 {
606 int ret;
607 TRACE("pidl1=%p pidl2=%p lpsf=%p\n", lParam1, lParam2, (LPVOID) lpData);
608
609 if (!lpData)
610 return 0;
611
612 ret = (SHORT)SCODE_CODE(((IShellFolder *)lpData)->CompareIDs(0, (LPITEMIDLIST)lParam1, (LPITEMIDLIST)lParam2));
613 TRACE("ret=%i\n", ret);
614
615 return ret;
616 }
617
618 /*************************************************************************
619 * ShellView_ListViewCompareItems
620 *
621 * Compare Function for the Listview (FileOpen Dialog)
622 *
623 * PARAMS
624 * lParam1 [I] the first ItemIdList to compare with
625 * lParam2 [I] the second ItemIdList to compare with
626 * lpData [I] The column ID for the header Ctrl to process
627 *
628 * RETURNS
629 * A negative value if the first item should precede the second,
630 * a positive value if the first item should follow the second,
631 * or zero if the two items are equivalent
632 *
633 * NOTES
634 * FIXME: function does what ShellView_CompareItems is supposed to do.
635 * unify it and figure out how to use the undocumented first parameter
636 * of IShellFolder_CompareIDs to do the job this function does and
637 * move this code to IShellFolder.
638 * make LISTVIEW_SORT_INFO obsolete
639 * the way this function works is only usable if we had only
640 * filesystemfolders (25/10/99 jsch)
641 */
642 INT CALLBACK CDefView::ListViewCompareItems(LPVOID lParam1, LPVOID lParam2, LPARAM lpData)
643 {
644 INT nDiff = 0;
645 FILETIME fd1, fd2;
646 char strName1[MAX_PATH], strName2[MAX_PATH];
647 BOOL bIsFolder1, bIsFolder2, bIsBothFolder;
648 LPITEMIDLIST pItemIdList1 = (LPITEMIDLIST) lParam1;
649 LPITEMIDLIST pItemIdList2 = (LPITEMIDLIST) lParam2;
650 LISTVIEW_SORT_INFO *pSortInfo = (LPLISTVIEW_SORT_INFO) lpData;
651
652
653 bIsFolder1 = _ILIsFolder(pItemIdList1);
654 bIsFolder2 = _ILIsFolder(pItemIdList2);
655 bIsBothFolder = bIsFolder1 && bIsFolder2;
656
657 /* When sorting between a File and a Folder, the Folder gets sorted first */
658 if ( (bIsFolder1 || bIsFolder2) && !bIsBothFolder)
659 {
660 nDiff = bIsFolder1 ? -1 : 1;
661 }
662 else
663 {
664 /* Sort by Time: Folders or Files can be sorted */
665
666 if(pSortInfo->nHeaderID == LISTVIEW_COLUMN_TIME)
667 {
668 _ILGetFileDateTime(pItemIdList1, &fd1);
669 _ILGetFileDateTime(pItemIdList2, &fd2);
670 nDiff = CompareFileTime(&fd2, &fd1);
671 }
672 /* Sort by Attribute: Folder or Files can be sorted */
673 else if(pSortInfo->nHeaderID == LISTVIEW_COLUMN_ATTRIB)
674 {
675 _ILGetFileAttributes(pItemIdList1, strName1, MAX_PATH);
676 _ILGetFileAttributes(pItemIdList2, strName2, MAX_PATH);
677 nDiff = lstrcmpiA(strName1, strName2);
678 }
679 /* Sort by FileName: Folder or Files can be sorted */
680 else if (pSortInfo->nHeaderID == LISTVIEW_COLUMN_NAME || bIsBothFolder)
681 {
682 /* Sort by Text */
683 _ILSimpleGetText(pItemIdList1, strName1, MAX_PATH);
684 _ILSimpleGetText(pItemIdList2, strName2, MAX_PATH);
685 nDiff = lstrcmpiA(strName1, strName2);
686 }
687 /* Sort by File Size, Only valid for Files */
688 else if (pSortInfo->nHeaderID == LISTVIEW_COLUMN_SIZE)
689 {
690 nDiff = (INT)(_ILGetFileSize(pItemIdList1, NULL, 0) - _ILGetFileSize(pItemIdList2, NULL, 0));
691 }
692 /* Sort by File Type, Only valid for Files */
693 else if (pSortInfo->nHeaderID == LISTVIEW_COLUMN_TYPE)
694 {
695 /* Sort by Type */
696 _ILGetFileType(pItemIdList1, strName1, MAX_PATH);
697 _ILGetFileType(pItemIdList2, strName2, MAX_PATH);
698 nDiff = lstrcmpiA(strName1, strName2);
699 }
700 }
701 /* If the Date, FileSize, FileType, Attrib was the same, sort by FileName */
702
703 if (nDiff == 0)
704 {
705 _ILSimpleGetText(pItemIdList1, strName1, MAX_PATH);
706 _ILSimpleGetText(pItemIdList2, strName2, MAX_PATH);
707 nDiff = lstrcmpiA(strName1, strName2);
708 }
709
710 if (!pSortInfo->bIsAscending)
711 {
712 nDiff = -nDiff;
713 }
714
715 return nDiff;
716 }
717
718 /**********************************************************
719 * LV_FindItemByPidl()
720 */
721 int CDefView::LV_FindItemByPidl(LPCITEMIDLIST pidl)
722 {
723 LVITEMW lvItem;
724 lvItem.iSubItem = 0;
725 lvItem.mask = LVIF_PARAM;
726
727 for (lvItem.iItem = 0;
728 SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
729 lvItem.iItem++)
730 {
731 LPITEMIDLIST currentpidl = (LPITEMIDLIST) lvItem.lParam;
732 HRESULT hr = m_pSFParent->CompareIDs(0, pidl, currentpidl);
733
734 if (SUCCEEDED(hr) && !HRESULT_CODE(hr))
735 {
736 return lvItem.iItem;
737 }
738 }
739 return -1;
740 }
741
742 /**********************************************************
743 * LV_AddItem()
744 */
745 BOOLEAN CDefView::LV_AddItem(LPCITEMIDLIST pidl)
746 {
747 LVITEMW lvItem;
748
749 TRACE("(%p)(pidl=%p)\n", this, pidl);
750
751 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM; /*set the mask*/
752 lvItem.iItem = ListView_GetItemCount(m_hWndList); /*add the item to the end of the list*/
753 lvItem.iSubItem = 0;
754 lvItem.lParam = (LPARAM) ILClone(ILFindLastID(pidl)); /*set the item's data*/
755 lvItem.pszText = LPSTR_TEXTCALLBACKW; /*get text on a callback basis*/
756 lvItem.iImage = I_IMAGECALLBACK; /*get the image on a callback basis*/
757
758 if (SendMessageW(m_hWndList, LVM_INSERTITEMW, 0, (LPARAM)&lvItem) == -1)
759 return FALSE;
760 else
761 return TRUE;
762 }
763
764 /**********************************************************
765 * LV_DeleteItem()
766 */
767 BOOLEAN CDefView::LV_DeleteItem(LPCITEMIDLIST pidl)
768 {
769 int nIndex;
770
771 TRACE("(%p)(pidl=%p)\n", this, pidl);
772
773 nIndex = LV_FindItemByPidl(ILFindLastID(pidl));
774
775 return (-1 == ListView_DeleteItem(m_hWndList, nIndex)) ? FALSE : TRUE;
776 }
777
778 /**********************************************************
779 * LV_RenameItem()
780 */
781 BOOLEAN CDefView::LV_RenameItem(LPCITEMIDLIST pidlOld, LPCITEMIDLIST pidlNew)
782 {
783 int nItem;
784 LVITEMW lvItem;
785
786 TRACE("(%p)(pidlold=%p pidlnew=%p)\n", this, pidlOld, pidlNew);
787
788 nItem = LV_FindItemByPidl(ILFindLastID(pidlOld));
789
790 if ( -1 != nItem )
791 {
792 lvItem.mask = LVIF_PARAM; /* only the pidl */
793 lvItem.iItem = nItem;
794 SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
795
796 SHFree((LPITEMIDLIST)lvItem.lParam);
797 lvItem.mask = LVIF_PARAM|LVIF_IMAGE;
798 lvItem.iItem = nItem;
799 lvItem.lParam = (LPARAM) ILClone(ILFindLastID(pidlNew)); /* set the item's data */
800 lvItem.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidlNew, 0);
801 SendMessageW(m_hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
802 SendMessageW(m_hWndList, LVM_UPDATE, nItem, 0);
803 return TRUE; /* FIXME: better handling */
804 }
805
806 return FALSE;
807 }
808
809 /**********************************************************
810 * ShellView_FillList()
811 *
812 * - gets the objectlist from the shellfolder
813 * - sorts the list
814 * - fills the list into the view
815 */
816 INT CALLBACK CDefView::fill_list( LPVOID ptr, LPVOID arg )
817 {
818 LPITEMIDLIST pidl = (LPITEMIDLIST)ptr;
819 CDefView *pThis = static_cast<CDefView *>(arg);
820 /* in a commdlg This works as a filemask*/
821 if (pThis->IncludeObject(pidl) == S_OK)
822 pThis->LV_AddItem(pidl);
823
824 SHFree(pidl);
825 return TRUE;
826 }
827
828 HRESULT CDefView::FillList()
829 {
830 LPENUMIDLIST pEnumIDList;
831 LPITEMIDLIST pidl;
832 DWORD dwFetched;
833 HRESULT hRes;
834 HDPA hdpa;
835
836 TRACE("%p\n", this);
837
838 /* get the itemlist from the shfolder*/
839 hRes = m_pSFParent->EnumObjects(m_hWnd, SHCONTF_NONFOLDERS | SHCONTF_FOLDERS, &pEnumIDList);
840 if (hRes != S_OK)
841 {
842 if (hRes == S_FALSE)
843 return(NOERROR);
844 return(hRes);
845 }
846
847 /* create a pointer array */
848 hdpa = DPA_Create(16);
849 if (!hdpa)
850 {
851 return(E_OUTOFMEMORY);
852 }
853
854 /* copy the items into the array*/
855 while((S_OK == pEnumIDList->Next(1, &pidl, &dwFetched)) && dwFetched)
856 {
857 if (DPA_InsertPtr(hdpa, 0x7fff, pidl) == -1)
858 {
859 SHFree(pidl);
860 }
861 }
862
863 /* sort the array */
864 DPA_Sort(hdpa, CompareItems, (LPARAM)m_pSFParent.p);
865
866 /*turn the listview's redrawing off*/
867 SendMessageA(m_hWndList, WM_SETREDRAW, FALSE, 0);
868
869 DPA_DestroyCallback( hdpa, fill_list, (void *)this);
870
871 /*turn the listview's redrawing back on and force it to draw*/
872 SendMessageA(m_hWndList, WM_SETREDRAW, TRUE, 0);
873
874 pEnumIDList->Release(); /* destroy the list*/
875
876 return S_OK;
877 }
878
879 LRESULT CDefView::OnShowWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
880 {
881 ::UpdateWindow(m_hWndList);
882 bHandled = FALSE;
883 return 0;
884 }
885
886 LRESULT CDefView::OnGetDlgCode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
887 {
888 return SendMessageW(m_hWndList, uMsg, 0, 0);
889 }
890
891 LRESULT CDefView::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
892 {
893 RevokeDragDrop(m_hWnd);
894 SHChangeNotifyDeregister(m_hNotify);
895 bHandled = FALSE;
896 return 0;
897 }
898
899 LRESULT CDefView::OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
900 {
901 if (m_FolderSettings.fFlags & (FWF_DESKTOP | FWF_TRANSPARENT))
902 return SendMessageW(GetParent(), WM_ERASEBKGND, wParam, lParam); /* redirect to parent */
903
904 bHandled = FALSE;
905 return 0;
906 }
907
908 LRESULT CDefView::OnSysColorChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
909 {
910 /* Update desktop labels color */
911 UpdateListColors();
912
913 /* Forward WM_SYSCOLORCHANGE to common controls */
914 return SendMessageW(m_hWndList, uMsg, 0, 0);
915 }
916
917 LRESULT CDefView::OnGetShellBrowser(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
918 {
919 return (LRESULT)m_pShellBrowser.p;
920 }
921
922 /**********************************************************
923 * ShellView_OnCreate()
924 */
925 LRESULT CDefView::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
926 {
927 CComPtr<IDropTarget> pdt;
928 SHChangeNotifyEntry ntreg;
929 CComPtr<IPersistFolder2> ppf2;
930
931 TRACE("%p\n", this);
932
933 if(CreateList())
934 {
935 if(InitList())
936 {
937 FillList();
938 }
939 }
940
941 if (SUCCEEDED(QueryInterface(IID_PPV_ARG(IDropTarget, &pdt))))
942 {
943 if (FAILED(RegisterDragDrop(m_hWnd, pdt)))
944 ERR("Registering Drag Drop Failed");
945 }
946
947 /* register for receiving notifications */
948 m_pSFParent->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
949 if (ppf2)
950 {
951 ppf2->GetCurFolder((LPITEMIDLIST*)&ntreg.pidl);
952 ntreg.fRecursive = TRUE;
953 m_hNotify = SHChangeNotifyRegister(m_hWnd, SHCNF_IDLIST, SHCNE_ALLEVENTS, SHV_CHANGE_NOTIFY, 1, &ntreg);
954 SHFree((LPITEMIDLIST)ntreg.pidl);
955 }
956
957 m_hAccel = LoadAcceleratorsA(shell32_hInstance, MAKEINTRESOURCEA( IDA_SHELLVIEW));
958
959 return S_OK;
960 }
961
962 /**********************************************************
963 * #### Handling of the menus ####
964 */
965
966 /**********************************************************
967 * ShellView_BuildFileMenu()
968 */
969 HMENU CDefView::BuildFileMenu()
970 { WCHAR szText[MAX_PATH];
971 MENUITEMINFOW mii;
972 int nTools, i;
973 HMENU hSubMenu;
974
975 TRACE("(%p)\n", this);
976
977 hSubMenu = CreatePopupMenu();
978 if (hSubMenu)
979 {
980 /*get the number of items in our global array*/
981 for(nTools = 0; Tools[nTools].idCommand != -1; nTools++) {}
982
983 /*add the menu items*/
984 for(i = 0; i < nTools; i++)
985 {
986 LoadStringW(shell32_hInstance, Tools[i].idMenuString, szText, MAX_PATH);
987
988 ZeroMemory(&mii, sizeof(mii));
989 mii.cbSize = sizeof(mii);
990 mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
991
992 if(BTNS_SEP != Tools[i].bStyle) /* no separator*/
993 {
994 mii.fType = MFT_STRING;
995 mii.fState = MFS_ENABLED;
996 mii.dwTypeData = szText;
997 mii.wID = Tools[i].idCommand;
998 }
999 else
1000 {
1001 mii.fType = MFT_SEPARATOR;
1002 }
1003 /* tack This item onto the end of the menu */
1004 InsertMenuItemW(hSubMenu, (UINT) - 1, TRUE, &mii);
1005 }
1006 }
1007
1008 TRACE("-- return (menu=%p)\n", hSubMenu);
1009 return hSubMenu;
1010 }
1011
1012 /**********************************************************
1013 * ShellView_MergeFileMenu()
1014 */
1015 void CDefView::MergeFileMenu(HMENU hSubMenu)
1016 {
1017 TRACE("(%p)->(submenu=%p) stub\n", this, hSubMenu);
1018
1019 if (hSubMenu)
1020 { /*insert This item at the beginning of the menu */
1021 _InsertMenuItemW(hSubMenu, 0, TRUE, 0, MFT_SEPARATOR, NULL, MFS_ENABLED);
1022 _InsertMenuItemW(hSubMenu, 0, TRUE, IDM_MYFILEITEM, MFT_STRING, L"dummy45", MFS_ENABLED);
1023 }
1024
1025 TRACE("--\n");
1026 }
1027
1028 /**********************************************************
1029 * ShellView_MergeViewMenu()
1030 */
1031 void CDefView::MergeViewMenu(HMENU hSubMenu)
1032 {
1033 TRACE("(%p)->(submenu=%p)\n", this, hSubMenu);
1034
1035 if (hSubMenu)
1036 {
1037 /*add a separator at the correct position in the menu*/
1038 MENUITEMINFOW mii;
1039 static WCHAR view[] = L"View";
1040
1041 _InsertMenuItemW(hSubMenu, FCIDM_MENU_VIEW_SEP_OPTIONS, FALSE, 0, MFT_SEPARATOR, NULL, MFS_ENABLED);
1042
1043 ZeroMemory(&mii, sizeof(mii));
1044 mii.cbSize = sizeof(mii);
1045 mii.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_DATA;
1046 mii.fType = MFT_STRING;
1047 mii.dwTypeData = view;
1048 mii.hSubMenu = LoadMenuW(shell32_hInstance, L"MENU_001");
1049 InsertMenuItemW(hSubMenu, FCIDM_MENU_VIEW_SEP_OPTIONS, FALSE, &mii);
1050 }
1051 }
1052
1053 /**********************************************************
1054 * ShellView_GetSelections()
1055 *
1056 * - fills the m_apidl list with the selected objects
1057 *
1058 * RETURNS
1059 * number of selected items
1060 */
1061 UINT CDefView::GetSelections()
1062 {
1063 LVITEMW lvItem;
1064 UINT i = 0;
1065
1066 SHFree(m_apidl);
1067
1068 m_cidl = ListView_GetSelectedCount(m_hWndList);
1069 m_apidl = (LPITEMIDLIST*)SHAlloc(m_cidl * sizeof(LPITEMIDLIST));
1070
1071 TRACE("selected=%i\n", m_cidl);
1072
1073 if (m_apidl)
1074 {
1075 TRACE("-- Items selected =%u\n", m_cidl);
1076
1077 lvItem.mask = LVIF_STATE | LVIF_PARAM;
1078 lvItem.stateMask = LVIS_SELECTED;
1079 lvItem.iItem = 0;
1080 lvItem.iSubItem = 0;
1081 lvItem.state = 0;
1082
1083 while(SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM)&lvItem) && (i < m_cidl))
1084 {
1085 if(lvItem.state & LVIS_SELECTED)
1086 {
1087 m_apidl[i] = (LPITEMIDLIST)lvItem.lParam;
1088 i++;
1089 if (i == m_cidl)
1090 break;
1091 TRACE("-- selected Item found\n");
1092 }
1093 lvItem.iItem++;
1094 }
1095 }
1096
1097 return m_cidl;
1098 }
1099
1100 /**********************************************************
1101 * ShellView_OpenSelectedItems()
1102 */
1103 HRESULT CDefView::OpenSelectedItems()
1104 {
1105 HMENU hMenu;
1106 CMINVOKECOMMANDINFO cmi;
1107 UINT uCommand;
1108 HRESULT hResult;
1109
1110 m_cidl = ListView_GetSelectedCount(m_hWndList);
1111 if (m_cidl == 0)
1112 return S_OK;
1113
1114 hResult = OnDefaultCommand();
1115 if (hResult == S_OK)
1116 return hResult;
1117
1118 hMenu = CreatePopupMenu();
1119 if (!hMenu)
1120 return E_FAIL;
1121
1122 hResult = GetItemObject( SVGIO_SELECTION, IID_PPV_ARG(IContextMenu, &m_pCM));
1123 if (FAILED(hResult))
1124 goto cleanup;
1125
1126 hResult = IUnknown_SetSite(m_pCM, (IShellView *)this);
1127 //if (FAILED( hResult))
1128 // goto cleanup;
1129
1130 hResult = m_pCM->QueryContextMenu(hMenu, 0, 0x20, 0x7fff, CMF_DEFAULTONLY);
1131 if (FAILED(hResult))
1132 goto cleanup;
1133
1134 uCommand = GetMenuDefaultItem(hMenu, FALSE, 0);
1135 if (uCommand == (UINT)-1)
1136 {
1137 hResult = E_FAIL;
1138 goto cleanup;
1139 }
1140
1141 ZeroMemory(&cmi, sizeof(cmi));
1142 cmi.cbSize = sizeof(cmi);
1143 cmi.lpVerb = (LPCSTR)MAKEINTRESOURCEA(uCommand);
1144 cmi.hwnd = m_hWnd;
1145
1146 hResult = m_pCM->InvokeCommand(&cmi);
1147
1148 cleanup:
1149
1150 if (hMenu)
1151 DestroyMenu(hMenu);
1152
1153 if (m_pCM)
1154 {
1155 IUnknown_SetSite(m_pCM, NULL);
1156 m_pCM.Release();
1157 }
1158
1159 return hResult;
1160 }
1161
1162 /**********************************************************
1163 * ShellView_DoContextMenu()
1164 */
1165 LRESULT CDefView::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1166 {
1167 WORD x;
1168 WORD y;
1169 UINT uCommand;
1170 HMENU hMenu;
1171 CMINVOKECOMMANDINFO cmi;
1172 HRESULT hResult;
1173
1174 // for some reason I haven't figured out, we sometimes recurse into this method
1175 if (m_pCM != NULL)
1176 return 0;
1177
1178 x = LOWORD(lParam);
1179 y = HIWORD(lParam);
1180
1181 TRACE("(%p)->(0x%08x 0x%08x) stub\n", this, x, y);
1182
1183 hMenu = CreatePopupMenu();
1184 if (!hMenu)
1185 return E_FAIL;
1186
1187 m_cidl = ListView_GetSelectedCount(m_hWndList);
1188
1189 hResult = GetItemObject( m_cidl ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &m_pCM));
1190 if (FAILED( hResult))
1191 goto cleanup;
1192
1193 hResult = IUnknown_SetSite(m_pCM, (IShellView *)this);
1194 //if (FAILED( hResult))
1195 // goto cleanup;
1196
1197 hResult = m_pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_NORMAL);
1198 if (FAILED( hResult))
1199 goto cleanup;
1200
1201 if (m_FolderSettings.fFlags & FWF_DESKTOP)
1202 SetMenuDefaultItem(hMenu, FCIDM_SHVIEW_OPEN, MF_BYCOMMAND);
1203
1204 uCommand = TrackPopupMenu(hMenu,
1205 TPM_LEFTALIGN | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
1206 x, y, 0, m_hWnd, NULL);
1207 if (uCommand == 0)
1208 goto cleanup;
1209
1210 if (uCommand == FCIDM_SHVIEW_OPEN && OnDefaultCommand() == S_OK)
1211 goto cleanup;
1212
1213 ZeroMemory(&cmi, sizeof(cmi));
1214 cmi.cbSize = sizeof(cmi);
1215 cmi.lpVerb = (LPCSTR)MAKEINTRESOURCEA(uCommand);
1216 cmi.hwnd = m_hWnd;
1217 m_pCM->InvokeCommand(&cmi);
1218
1219 cleanup:
1220
1221 if (m_pCM)
1222 {
1223 IUnknown_SetSite(m_pCM, NULL);
1224 m_pCM.Release();
1225 }
1226
1227 if (hMenu)
1228 DestroyMenu(hMenu);
1229
1230 return 0;
1231 }
1232
1233 LRESULT CDefView::OnExplorerCommand(UINT uCommand, BOOL bUseSelection)
1234 {
1235 HRESULT hResult;
1236 CMINVOKECOMMANDINFO cmi;
1237 HMENU hMenu;
1238
1239 hMenu = CreatePopupMenu();
1240 if (!hMenu)
1241 return 0;
1242
1243 hResult = GetItemObject( bUseSelection ? SVGIO_SELECTION : SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &m_pCM));
1244 if (FAILED( hResult))
1245 goto cleanup;
1246
1247 hResult = IUnknown_SetSite(m_pCM, (IShellView *)this);
1248 //if (FAILED( hResult))
1249 // goto cleanup;
1250
1251 hResult = m_pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_NORMAL);
1252 if (FAILED( hResult))
1253 goto cleanup;
1254
1255 ZeroMemory(&cmi, sizeof(cmi));
1256 cmi.cbSize = sizeof(cmi);
1257 cmi.lpVerb = (LPCSTR)MAKEINTRESOURCEA(uCommand);
1258 cmi.hwnd = m_hWnd;
1259 m_pCM->InvokeCommand(&cmi);
1260
1261 cleanup:
1262
1263 if (m_pCM)
1264 {
1265 IUnknown_SetSite(m_pCM, NULL);
1266 m_pCM.Release();
1267 }
1268
1269 if (hMenu)
1270 DestroyMenu(hMenu);
1271
1272 return 0;
1273 }
1274
1275 /**********************************************************
1276 * ##### message handling #####
1277 */
1278
1279 /**********************************************************
1280 * ShellView_OnSize()
1281 */
1282 LRESULT CDefView::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1283 {
1284 WORD wWidth;
1285 WORD wHeight;
1286
1287 wWidth = LOWORD(lParam);
1288 wHeight = HIWORD(lParam);
1289
1290 TRACE("%p width=%u height=%u\n", this, wWidth, wHeight);
1291
1292 /*resize the ListView to fit our window*/
1293 if (m_hWndList)
1294 {
1295 ::MoveWindow(m_hWndList, 0, 0, wWidth, wHeight, TRUE);
1296 }
1297
1298 return 0;
1299 }
1300
1301 /**********************************************************
1302 * ShellView_OnDeactivate()
1303 *
1304 * NOTES
1305 * internal
1306 */
1307 void CDefView::OnDeactivate()
1308 {
1309 TRACE("%p\n", this);
1310
1311 if (m_uState != SVUIA_DEACTIVATE)
1312 {
1313 if (m_hMenu)
1314 {
1315 m_pShellBrowser->SetMenuSB(0, 0, 0);
1316 m_pShellBrowser->RemoveMenusSB(m_hMenu);
1317 DestroyMenu(m_hMenu);
1318 m_hMenu = 0;
1319 }
1320
1321 m_uState = SVUIA_DEACTIVATE;
1322 }
1323 }
1324
1325 void CDefView::DoActivate(UINT uState)
1326 {
1327 OLEMENUGROUPWIDTHS omw = { {0, 0, 0, 0, 0, 0} };
1328 MENUITEMINFOA mii;
1329 CHAR szText[MAX_PATH];
1330
1331 TRACE("%p uState=%x\n", this, uState);
1332
1333 /*don't do anything if the state isn't really changing */
1334 if (m_uState == uState)
1335 {
1336 return;
1337 }
1338
1339 OnDeactivate();
1340
1341 /*only do This if we are active */
1342 if(uState != SVUIA_DEACTIVATE)
1343 {
1344 /*merge the menus */
1345 m_hMenu = CreateMenu();
1346
1347 if(m_hMenu)
1348 {
1349 m_pShellBrowser->InsertMenusSB(m_hMenu, &omw);
1350 TRACE("-- after fnInsertMenusSB\n");
1351
1352 /*build the top level menu get the menu item's text*/
1353 strcpy(szText, "dummy 31");
1354
1355 ZeroMemory(&mii, sizeof(mii));
1356 mii.cbSize = sizeof(mii);
1357 mii.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_STATE;
1358 mii.fType = MFT_STRING;
1359 mii.fState = MFS_ENABLED;
1360 mii.dwTypeData = szText;
1361 mii.hSubMenu = BuildFileMenu();
1362
1363 /*insert our menu into the menu bar*/
1364 if (mii.hSubMenu)
1365 {
1366 InsertMenuItemA(m_hMenu, FCIDM_MENU_HELP, FALSE, &mii);
1367 }
1368
1369 /*get the view menu so we can merge with it*/
1370 ZeroMemory(&mii, sizeof(mii));
1371 mii.cbSize = sizeof(mii);
1372 mii.fMask = MIIM_SUBMENU;
1373
1374 if (GetMenuItemInfoA(m_hMenu, FCIDM_MENU_VIEW, FALSE, &mii))
1375 {
1376 MergeViewMenu(mii.hSubMenu);
1377 }
1378
1379 /*add the items that should only be added if we have the focus*/
1380 if (SVUIA_ACTIVATE_FOCUS == uState)
1381 {
1382 /*get the file menu so we can merge with it */
1383 ZeroMemory(&mii, sizeof(mii));
1384 mii.cbSize = sizeof(mii);
1385 mii.fMask = MIIM_SUBMENU;
1386
1387 if (GetMenuItemInfoA(m_hMenu, FCIDM_MENU_FILE, FALSE, &mii))
1388 {
1389 MergeFileMenu(mii.hSubMenu);
1390 }
1391 }
1392
1393 TRACE("-- before fnSetMenuSB\n");
1394 m_pShellBrowser->SetMenuSB(m_hMenu, 0, m_hWnd);
1395 }
1396 }
1397 m_uState = uState;
1398 TRACE("--\n");
1399 }
1400
1401 /**********************************************************
1402 * ShellView_OnActivate()
1403 */
1404 LRESULT CDefView::OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1405 {
1406 DoActivate(SVUIA_ACTIVATE_FOCUS);
1407 return 0;
1408 }
1409
1410 /**********************************************************
1411 * ShellView_OnSetFocus()
1412 *
1413 */
1414 LRESULT CDefView::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1415 {
1416 TRACE("%p\n", this);
1417
1418 /* Tell the browser one of our windows has received the focus. This
1419 should always be done before merging menus (OnActivate merges the
1420 menus) if one of our windows has the focus.*/
1421
1422 m_pShellBrowser->OnViewWindowActive((IShellView *)this);
1423 DoActivate(SVUIA_ACTIVATE_FOCUS);
1424
1425 /* Set the focus to the listview */
1426 ::SetFocus(m_hWndList);
1427
1428 /* Notify the ICommDlgBrowser interface */
1429 OnStateChange(CDBOSC_SETFOCUS);
1430
1431 return 0;
1432 }
1433
1434 /**********************************************************
1435 * ShellView_OnKillFocus()
1436 */
1437 LRESULT CDefView::OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1438 {
1439 TRACE("(%p) stub\n", this);
1440
1441 DoActivate(SVUIA_ACTIVATE_NOFOCUS);
1442 /* Notify the ICommDlgBrowser */
1443 OnStateChange(CDBOSC_KILLFOCUS);
1444
1445 return 0;
1446 }
1447
1448 /**********************************************************
1449 * ShellView_OnCommand()
1450 *
1451 * NOTES
1452 * the CmdID's are the ones from the context menu
1453 */
1454 LRESULT CDefView::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1455 {
1456 DWORD dwCmdID;
1457 DWORD dwCmd;
1458 HWND hwndCmd;
1459
1460 dwCmdID = GET_WM_COMMAND_ID(wParam, lParam);
1461 dwCmd = GET_WM_COMMAND_CMD(wParam, lParam);
1462 hwndCmd = GET_WM_COMMAND_HWND(wParam, lParam);
1463
1464 TRACE("(%p)->(0x%08x 0x%08x %p) stub\n", this, dwCmdID, dwCmd, hwndCmd);
1465
1466 switch (dwCmdID)
1467 {
1468 case FCIDM_SHVIEW_SMALLICON:
1469 m_FolderSettings.ViewMode = FVM_SMALLICON;
1470 SetStyle (LVS_SMALLICON, LVS_TYPEMASK);
1471 CheckToolbar();
1472 break;
1473
1474 case FCIDM_SHVIEW_BIGICON:
1475 m_FolderSettings.ViewMode = FVM_ICON;
1476 SetStyle (LVS_ICON, LVS_TYPEMASK);
1477 CheckToolbar();
1478 break;
1479
1480 case FCIDM_SHVIEW_LISTVIEW:
1481 m_FolderSettings.ViewMode = FVM_LIST;
1482 SetStyle (LVS_LIST, LVS_TYPEMASK);
1483 CheckToolbar();
1484 break;
1485
1486 case FCIDM_SHVIEW_REPORTVIEW:
1487 m_FolderSettings.ViewMode = FVM_DETAILS;
1488 SetStyle (LVS_REPORT, LVS_TYPEMASK);
1489 CheckToolbar();
1490 break;
1491
1492 /* the menu-ID's for sorting are 0x30... see shrec.rc */
1493 case 0x30:
1494 case 0x31:
1495 case 0x32:
1496 case 0x33:
1497 m_sortInfo.nHeaderID = (LPARAM) (dwCmdID - 0x30);
1498 m_sortInfo.bIsAscending = TRUE;
1499 m_sortInfo.nLastHeaderID = m_sortInfo.nHeaderID;
1500 SendMessageA(m_hWndList, LVM_SORTITEMS, (WPARAM) &m_sortInfo, (LPARAM)ListViewCompareItems);
1501 break;
1502
1503 case FCIDM_SHVIEW_REFRESH:
1504 Refresh();
1505 break;
1506
1507 case FCIDM_SHVIEW_DELETE:
1508 case FCIDM_SHVIEW_CUT:
1509 case FCIDM_SHVIEW_COPY:
1510 case FCIDM_SHVIEW_RENAME:
1511 return OnExplorerCommand(dwCmdID, TRUE);
1512
1513 case FCIDM_SHVIEW_INSERT:
1514 case FCIDM_SHVIEW_UNDO:
1515 case FCIDM_SHVIEW_INSERTLINK:
1516 case FCIDM_SHVIEW_NEWFOLDER:
1517 return OnExplorerCommand(dwCmdID, FALSE);
1518 default:
1519 TRACE("-- COMMAND 0x%04x unhandled\n", dwCmdID);
1520 }
1521
1522 return 0;
1523 }
1524
1525 /**********************************************************
1526 * ShellView_OnNotify()
1527 */
1528
1529 LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1530 {
1531 UINT CtlID;
1532 LPNMHDR lpnmh;
1533 LPNMLISTVIEW lpnmlv;
1534 NMLVDISPINFOW *lpdi;
1535 LPITEMIDLIST pidl;
1536 BOOL unused;
1537
1538 CtlID = wParam;
1539 lpnmh = (LPNMHDR)lParam;
1540 lpnmlv = (LPNMLISTVIEW)lpnmh;
1541 lpdi = (NMLVDISPINFOW *)lpnmh;
1542
1543 TRACE("%p CtlID=%u lpnmh->code=%x\n", this, CtlID, lpnmh->code);
1544
1545 switch (lpnmh->code)
1546 {
1547 case NM_SETFOCUS:
1548 TRACE("-- NM_SETFOCUS %p\n", this);
1549 OnSetFocus(0, 0, 0, unused);
1550 break;
1551
1552 case NM_KILLFOCUS:
1553 TRACE("-- NM_KILLFOCUS %p\n", this);
1554 OnDeactivate();
1555 /* Notify the ICommDlgBrowser interface */
1556 OnStateChange(CDBOSC_KILLFOCUS);
1557 break;
1558
1559 case NM_CUSTOMDRAW:
1560 TRACE("-- NM_CUSTOMDRAW %p\n", this);
1561 return CDRF_DODEFAULT;
1562
1563 case NM_RELEASEDCAPTURE:
1564 TRACE("-- NM_RELEASEDCAPTURE %p\n", this);
1565 break;
1566
1567 case NM_CLICK:
1568 TRACE("-- NM_CLICK %p\n", this);
1569 break;
1570
1571 case NM_RCLICK:
1572 TRACE("-- NM_RCLICK %p\n", this);
1573 break;
1574
1575 case NM_DBLCLK:
1576 TRACE("-- NM_DBLCLK %p\n", this);
1577 OpenSelectedItems();
1578 break;
1579
1580 case NM_RETURN:
1581 TRACE("-- NM_RETURN %p\n", this);
1582 OpenSelectedItems();
1583 break;
1584
1585 case HDN_ENDTRACKW:
1586 TRACE("-- HDN_ENDTRACKW %p\n", this);
1587 /*nColumn1 = ListView_GetColumnWidth(m_hWndList, 0);
1588 nColumn2 = ListView_GetColumnWidth(m_hWndList, 1);*/
1589 break;
1590
1591 case LVN_DELETEITEM:
1592 TRACE("-- LVN_DELETEITEM %p\n", this);
1593 SHFree((LPITEMIDLIST)lpnmlv->lParam); /*delete the pidl because we made a copy of it*/
1594 break;
1595
1596 case LVN_DELETEALLITEMS:
1597 TRACE("-- LVN_DELETEALLITEMS %p\n", this);
1598 return FALSE;
1599
1600 case LVN_INSERTITEM:
1601 TRACE("-- LVN_INSERTITEM (STUB)%p\n", this);
1602 break;
1603
1604 case LVN_ITEMACTIVATE:
1605 TRACE("-- LVN_ITEMACTIVATE %p\n", this);
1606 OnStateChange(CDBOSC_SELCHANGE); /* the browser will get the IDataObject now */
1607 break;
1608
1609 case LVN_COLUMNCLICK:
1610 m_sortInfo.nHeaderID = lpnmlv->iSubItem;
1611 if (m_sortInfo.nLastHeaderID == m_sortInfo.nHeaderID)
1612 {
1613 m_sortInfo.bIsAscending = !m_sortInfo.bIsAscending;
1614 }
1615 else
1616 {
1617 m_sortInfo.bIsAscending = TRUE;
1618 }
1619 m_sortInfo.nLastHeaderID = m_sortInfo.nHeaderID;
1620
1621 SendMessageW(lpnmlv->hdr.hwndFrom, LVM_SORTITEMS, (WPARAM) &m_sortInfo, (LPARAM)ListViewCompareItems);
1622 break;
1623
1624 case LVN_GETDISPINFOA:
1625 case LVN_GETDISPINFOW:
1626 TRACE("-- LVN_GETDISPINFO %p\n", this);
1627 pidl = (LPITEMIDLIST)lpdi->item.lParam;
1628
1629 if (lpdi->item.mask & LVIF_TEXT) /* text requested */
1630 {
1631 if (m_pSF2Parent)
1632 {
1633 SHELLDETAILS sd;
1634 if (FAILED(m_pSF2Parent->GetDetailsOf(pidl, lpdi->item.iSubItem, &sd)))
1635 {
1636 FIXME("failed to get details\n");
1637 break;
1638 }
1639
1640 if (lpnmh->code == LVN_GETDISPINFOA)
1641 {
1642 /* shouldn't happen */
1643 NMLVDISPINFOA *lpdiA = (NMLVDISPINFOA *)lpnmh;
1644 StrRetToStrNA( lpdiA->item.pszText, lpdiA->item.cchTextMax, &sd.str, NULL);
1645 TRACE("-- text=%s\n", lpdiA->item.pszText);
1646 }
1647 else /* LVN_GETDISPINFOW */
1648 {
1649 StrRetToStrNW( lpdi->item.pszText, lpdi->item.cchTextMax, &sd.str, NULL);
1650 TRACE("-- text=%s\n", debugstr_w(lpdi->item.pszText));
1651 }
1652 }
1653 else
1654 {
1655 FIXME("no SF2\n");
1656 }
1657 }
1658 if(lpdi->item.mask & LVIF_IMAGE) /* image requested */
1659 {
1660 lpdi->item.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
1661 }
1662 lpdi->item.mask |= LVIF_DI_SETITEM;
1663 break;
1664
1665 case LVN_ITEMCHANGED:
1666 TRACE("-- LVN_ITEMCHANGED %p\n", this);
1667 OnStateChange(CDBOSC_SELCHANGE); /* the browser will get the IDataObject now */
1668 break;
1669
1670 case LVN_BEGINDRAG:
1671 case LVN_BEGINRDRAG:
1672 TRACE("-- LVN_BEGINDRAG\n");
1673
1674 if (GetSelections())
1675 {
1676 IDataObject * pda;
1677 DWORD dwAttributes = SFGAO_CANLINK;
1678 DWORD dwEffect = DROPEFFECT_COPY | DROPEFFECT_MOVE;
1679
1680 if (SUCCEEDED(m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, (LPCITEMIDLIST*)m_apidl, IID_IDataObject, 0, (LPVOID *)&pda)))
1681 {
1682 IDropSource * pds = (IDropSource *)this; /* own DropSource interface */
1683
1684 if (SUCCEEDED(m_pSFParent->GetAttributesOf(m_cidl, (LPCITEMIDLIST*)m_apidl, &dwAttributes)))
1685 {
1686 if (dwAttributes & SFGAO_CANLINK)
1687 {
1688 dwEffect |= DROPEFFECT_LINK;
1689 }
1690 }
1691
1692 CComPtr<IAsyncOperation> piaso;
1693 if (SUCCEEDED(pda->QueryInterface(IID_PPV_ARG(IAsyncOperation, &piaso))))
1694 {
1695 piaso->SetAsyncMode(TRUE);
1696 piaso->Release();
1697 }
1698
1699 if (pds)
1700 { DWORD dwEffect2;
1701 DoDragDrop(pda, pds, dwEffect, &dwEffect2);
1702 }
1703 pda->Release();
1704 }
1705 }
1706 break;
1707
1708 case LVN_BEGINLABELEDITW:
1709 {
1710 DWORD dwAttr = SFGAO_CANRENAME;
1711 pidl = (LPITEMIDLIST)lpdi->item.lParam;
1712
1713 TRACE("-- LVN_BEGINLABELEDITW %p\n", this);
1714
1715 m_pSFParent->GetAttributesOf(1, (LPCITEMIDLIST*)&pidl, &dwAttr);
1716 if (SFGAO_CANRENAME & dwAttr)
1717 {
1718 return FALSE;
1719 }
1720 return TRUE;
1721 }
1722
1723 case LVN_ENDLABELEDITW:
1724 {
1725 TRACE("-- LVN_ENDLABELEDITW %p\n", this);
1726 if (lpdi->item.pszText)
1727 {
1728 HRESULT hr;
1729 LVITEMW lvItem;
1730
1731 lvItem.iItem = lpdi->item.iItem;
1732 lvItem.iSubItem = 0;
1733 lvItem.mask = LVIF_PARAM;
1734 SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
1735
1736 pidl = (LPITEMIDLIST)lpdi->item.lParam;
1737 hr = m_pSFParent->SetNameOf(0, pidl, lpdi->item.pszText, SHGDN_INFOLDER, &pidl);
1738
1739 if (SUCCEEDED(hr) && pidl)
1740 {
1741 lvItem.mask = LVIF_PARAM|LVIF_IMAGE;
1742 lvItem.lParam = (LPARAM)pidl;
1743 lvItem.iImage = SHMapPIDLToSystemImageListIndex(m_pSFParent, pidl, 0);
1744 SendMessageW(m_hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
1745 SendMessageW(m_hWndList, LVM_UPDATE, lpdi->item.iItem, 0);
1746
1747 return TRUE;
1748 }
1749 }
1750
1751 return FALSE;
1752 }
1753
1754 case LVN_KEYDOWN:
1755 {
1756 LPNMLVKEYDOWN plvKeyDown = (LPNMLVKEYDOWN) lpnmh;
1757
1758 /* initiate a rename of the selected file or directory */
1759 if (plvKeyDown->wVKey == VK_BACK)
1760 {
1761 LPSHELLBROWSER lpSb;
1762 if ((lpSb = (LPSHELLBROWSER)SendMessageW(m_hWndParent, CWM_GETISHELLBROWSER, 0, 0)))
1763 {
1764 lpSb->BrowseObject(NULL, SBSP_PARENT);
1765 }
1766 }
1767
1768 else
1769 FIXME("LVN_KEYDOWN key=0x%08x\n", plvKeyDown->wVKey);
1770 }
1771 break;
1772
1773 default:
1774 TRACE("-- %p WM_COMMAND %x unhandled\n", this, lpnmh->code);
1775 break;
1776 }
1777
1778 return 0;
1779 }
1780
1781 /**********************************************************
1782 * ShellView_OnChange()
1783 */
1784 LRESULT CDefView::OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1785 {
1786 LPITEMIDLIST *Pidls;
1787
1788 Pidls = (LPITEMIDLIST *)wParam;
1789
1790 TRACE("(%p)(%p,%p,0x%08x)\n", this, Pidls[0], Pidls[1], lParam);
1791
1792 switch (lParam)
1793 {
1794 case SHCNE_MKDIR:
1795 case SHCNE_CREATE:
1796 LV_AddItem(Pidls[0]);
1797 break;
1798
1799 case SHCNE_RMDIR:
1800 case SHCNE_DELETE:
1801 LV_DeleteItem(Pidls[0]);
1802 break;
1803
1804 case SHCNE_RENAMEFOLDER:
1805 case SHCNE_RENAMEITEM:
1806 LV_RenameItem(Pidls[0], Pidls[1]);
1807 break;
1808
1809 case SHCNE_UPDATEITEM:
1810 LV_RenameItem(Pidls[0], Pidls[0]);
1811 break;
1812
1813 case SHCNE_UPDATEDIR:
1814 Refresh();
1815 break;
1816 }
1817 return TRUE;
1818 }
1819
1820 /**********************************************************
1821 * CDefView::OnCustomItem
1822 */
1823 LRESULT CDefView::OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1824 {
1825 if (!m_pCM.p)
1826 {
1827 /* no menu */
1828 ERR("no menu!!!\n");
1829 return FALSE;
1830 }
1831
1832 CComPtr<IContextMenu2> pCM2;
1833 HRESULT hres = m_pCM.p->QueryInterface(IID_PPV_ARG(IContextMenu2, &pCM2));
1834 if(FAILED(hres))
1835 return FALSE;
1836
1837 if (pCM2.p->HandleMenuMsg(uMsg, (WPARAM)m_hWnd, lParam) == S_OK)
1838 return TRUE;
1839 else
1840 return FALSE;
1841 }
1842
1843 LRESULT CDefView::OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
1844 {
1845 /* Wallpaper setting affects drop shadows effect */
1846 if (wParam == SPI_SETDESKWALLPAPER || wParam == 0)
1847 UpdateListColors();
1848
1849 return S_OK;
1850 }
1851
1852 /**********************************************************
1853 *
1854 *
1855 * The INTERFACE of the IShellView object
1856 *
1857 *
1858 **********************************************************
1859 */
1860
1861 /**********************************************************
1862 * ShellView_GetWindow
1863 */
1864 HRESULT WINAPI CDefView::GetWindow(HWND *phWnd)
1865 {
1866 TRACE("(%p)\n", this);
1867
1868 *phWnd = m_hWnd;
1869
1870 return S_OK;
1871 }
1872
1873 HRESULT WINAPI CDefView::ContextSensitiveHelp(BOOL fEnterMode)
1874 {
1875 FIXME("(%p) stub\n", this);
1876
1877 return E_NOTIMPL;
1878 }
1879
1880 /**********************************************************
1881 * IShellView_TranslateAccelerator
1882 *
1883 * FIXME:
1884 * use the accel functions
1885 */
1886 HRESULT WINAPI CDefView::TranslateAccelerator(LPMSG lpmsg)
1887 {
1888 if (lpmsg->message >= WM_KEYFIRST && lpmsg->message <= WM_KEYLAST)
1889 {
1890 if (::TranslateAcceleratorW(m_hWnd, m_hAccel, lpmsg) != 0)
1891 return S_OK;
1892
1893 /* FIXME: should call TranslateAcceleratorSB */
1894
1895 TRACE("-- key=0x04%lx\n", lpmsg->wParam) ;
1896 }
1897
1898 return S_FALSE; /* not handled */
1899 }
1900
1901 HRESULT WINAPI CDefView::EnableModeless(BOOL fEnable)
1902 {
1903 FIXME("(%p) stub\n", this);
1904
1905 return E_NOTIMPL;
1906 }
1907
1908 HRESULT WINAPI CDefView::UIActivate(UINT uState)
1909 {
1910 /*
1911 CHAR szName[MAX_PATH];
1912 */
1913 LRESULT lResult;
1914 int nPartArray[1] = { -1};
1915
1916 TRACE("(%p)->(state=%x) stub\n", this, uState);
1917
1918 /*don't do anything if the state isn't really changing*/
1919 if (m_uState == uState)
1920 {
1921 return S_OK;
1922 }
1923
1924 /*OnActivate handles the menu merging and internal state*/
1925 DoActivate(uState);
1926
1927 /*only do This if we are active*/
1928 if (uState != SVUIA_DEACTIVATE)
1929 {
1930
1931 /*
1932 GetFolderPath is not a method of IShellFolder
1933 IShellFolder_GetFolderPath( m_pSFParent, szName, sizeof(szName) );
1934 */
1935 /* set the number of parts */
1936 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, 1, (LPARAM)nPartArray, &lResult);
1937
1938 /* set the text for the parts */
1939 /*
1940 m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXTA, 0, (LPARAM)szName, &lResult);
1941 */
1942 }
1943
1944 return S_OK;
1945 }
1946
1947 HRESULT WINAPI CDefView::Refresh()
1948 {
1949 TRACE("(%p)\n", this);
1950
1951 SendMessageW(m_hWndList, LVM_DELETEALLITEMS, 0, 0);
1952 FillList();
1953
1954 return S_OK;
1955 }
1956
1957 HRESULT WINAPI CDefView::CreateViewWindow(IShellView *lpPrevView, LPCFOLDERSETTINGS lpfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd)
1958 {
1959 *phWnd = 0;
1960
1961 TRACE("(%p)->(shlview=%p set=%p shlbrs=%p rec=%p hwnd=%p) incomplete\n", this, lpPrevView, lpfs, psb, prcView, phWnd);
1962
1963 if (lpfs != NULL)
1964 TRACE("-- vmode=%x flags=%x\n", lpfs->ViewMode, lpfs->fFlags);
1965 if (prcView != NULL)
1966 TRACE("-- left=%i top=%i right=%i bottom=%i\n", prcView->left, prcView->top, prcView->right, prcView->bottom);
1967
1968 /* Validate the Shell Browser */
1969 if (psb == NULL)
1970 return E_UNEXPECTED;
1971
1972 /*set up the member variables*/
1973 m_pShellBrowser = psb;
1974 m_FolderSettings = *lpfs;
1975
1976 /*get our parent window*/
1977 m_pShellBrowser->GetWindow(&m_hWndParent);
1978
1979 /* try to get the ICommDlgBrowserInterface, adds a reference !!! */
1980 m_pCommDlgBrowser = NULL;
1981 if (SUCCEEDED(m_pShellBrowser->QueryInterface(IID_PPV_ARG(ICommDlgBrowser, &m_pCommDlgBrowser))))
1982 {
1983 TRACE("-- CommDlgBrowser\n");
1984 }
1985
1986 Create(m_hWndParent, prcView, NULL, WS_CHILD | WS_TABSTOP, 0, 0U);
1987 if (m_hWnd == NULL)
1988 return E_FAIL;
1989
1990 *phWnd = m_hWnd;
1991
1992 CheckToolbar();
1993
1994 if (!*phWnd)
1995 return E_FAIL;
1996
1997 SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
1998 UpdateWindow();
1999
2000 return S_OK;
2001 }
2002
2003 HRESULT WINAPI CDefView::DestroyViewWindow()
2004 {
2005 TRACE("(%p)\n", this);
2006
2007 /*Make absolutely sure all our UI is cleaned up.*/
2008 UIActivate(SVUIA_DEACTIVATE);
2009
2010 if (m_hMenu)
2011 {
2012 DestroyMenu(m_hMenu);
2013 }
2014
2015 DestroyWindow();
2016 m_pShellBrowser.Release();
2017 m_pCommDlgBrowser.Release();
2018
2019 return S_OK;
2020 }
2021
2022 HRESULT WINAPI CDefView::GetCurrentInfo(LPFOLDERSETTINGS lpfs)
2023 {
2024 TRACE("(%p)->(%p) vmode=%x flags=%x\n", this, lpfs,
2025 m_FolderSettings.ViewMode, m_FolderSettings.fFlags);
2026
2027 if (!lpfs)
2028 return E_INVALIDARG;
2029
2030 *lpfs = m_FolderSettings;
2031 return S_OK;
2032 }
2033
2034 HRESULT WINAPI CDefView::AddPropertySheetPages(DWORD dwReserved, LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam)
2035 {
2036 FIXME("(%p) stub\n", this);
2037
2038 return E_NOTIMPL;
2039 }
2040
2041 HRESULT WINAPI CDefView::SaveViewState()
2042 {
2043 FIXME("(%p) stub\n", this);
2044
2045 return S_OK;
2046 }
2047
2048 HRESULT WINAPI CDefView::SelectItem(LPCITEMIDLIST pidl, UINT uFlags)
2049 {
2050 int i;
2051
2052 TRACE("(%p)->(pidl=%p, 0x%08x) stub\n", this, pidl, uFlags);
2053
2054 i = LV_FindItemByPidl(pidl);
2055
2056 if (i != -1)
2057 {
2058 LVITEMW lvItem;
2059
2060 if(uFlags & SVSI_ENSUREVISIBLE)
2061 SendMessageW(m_hWndList, LVM_ENSUREVISIBLE, i, 0);
2062
2063 lvItem.mask = LVIF_STATE;
2064 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
2065 lvItem.iItem = 0;
2066 lvItem.iSubItem = 0;
2067
2068 while (SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem))
2069 {
2070 if (lvItem.iItem == i)
2071 {
2072 if (uFlags & SVSI_SELECT)
2073 lvItem.state |= LVIS_SELECTED;
2074 else
2075 lvItem.state &= ~LVIS_SELECTED;
2076
2077 if (uFlags & SVSI_FOCUSED)
2078 lvItem.state &= ~LVIS_FOCUSED;
2079 }
2080 else
2081 {
2082 if (uFlags & SVSI_DESELECTOTHERS)
2083 lvItem.state &= ~LVIS_SELECTED;
2084 }
2085
2086 SendMessageW(m_hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
2087 lvItem.iItem++;
2088 }
2089
2090
2091 if(uFlags & SVSI_EDIT)
2092 SendMessageW(m_hWndList, LVM_EDITLABELW, i, 0);
2093 }
2094
2095 return S_OK;
2096 }
2097
2098 HRESULT WINAPI CDefView::GetItemObject(UINT uItem, REFIID riid, LPVOID *ppvOut)
2099 {
2100 HRESULT hr = E_NOINTERFACE;
2101
2102 TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n", this, uItem, debugstr_guid(&riid), ppvOut);
2103
2104 *ppvOut = NULL;
2105
2106 switch (uItem)
2107 {
2108 case SVGIO_BACKGROUND:
2109 if (IsEqualIID(riid, IID_IContextMenu))
2110 {
2111 //*ppvOut = ISvBgCm_Constructor(m_pSFParent, FALSE);
2112 CDefFolderMenu_Create2(NULL, NULL, 0, NULL, m_pSFParent, NULL, 0, NULL, (IContextMenu**)ppvOut);
2113 if (!ppvOut)
2114 hr = E_OUTOFMEMORY;
2115 else
2116 hr = S_OK;
2117 }
2118 break;
2119
2120 case SVGIO_SELECTION:
2121 GetSelections();
2122 hr = m_pSFParent->GetUIObjectOf(m_hWnd, m_cidl, (LPCITEMIDLIST*)m_apidl, riid, 0, ppvOut);
2123 break;
2124 }
2125
2126 TRACE("-- (%p)->(interface=%p)\n", this, *ppvOut);
2127
2128 return hr;
2129 }
2130
2131 HRESULT STDMETHODCALLTYPE CDefView::GetCurrentViewMode(UINT *pViewMode)
2132 {
2133 TRACE("(%p)->(%p), stub\n", this, pViewMode);
2134
2135 if (!pViewMode)
2136 return E_INVALIDARG;
2137
2138 *pViewMode = m_FolderSettings.ViewMode;
2139 return S_OK;
2140 }
2141
2142 HRESULT STDMETHODCALLTYPE CDefView::SetCurrentViewMode(UINT ViewMode)
2143 {
2144 DWORD dwStyle;
2145 TRACE("(%p)->(%u), stub\n", this, ViewMode);
2146
2147 /* It's not redundant to check FVM_AUTO because it's a (UINT)-1 */
2148 if ((ViewMode < FVM_FIRST || ViewMode > FVM_LAST) && (ViewMode != (UINT)FVM_AUTO))
2149 return E_INVALIDARG;
2150
2151 /* Windows before Vista uses LVM_SETVIEW and possibly
2152 LVM_SETEXTENDEDLISTVIEWSTYLE to set the style of the listview,
2153 while later versions seem to accomplish this through other
2154 means. */
2155 switch (ViewMode)
2156 {
2157 case FVM_ICON:
2158 dwStyle = LVS_ICON;
2159 break;
2160 case FVM_DETAILS:
2161 dwStyle = LVS_REPORT;
2162 break;
2163 case FVM_SMALLICON:
2164 dwStyle = LVS_SMALLICON;
2165 break;
2166 case FVM_LIST:
2167 dwStyle = LVS_LIST;
2168 break;
2169 default:
2170 {
2171 FIXME("ViewMode %d not implemented\n", ViewMode);
2172 dwStyle = LVS_LIST;
2173 break;
2174 }
2175 }
2176
2177 SetStyle(dwStyle, LVS_TYPEMASK);
2178
2179 /* This will not necessarily be the actual mode set above.
2180 This mimics the behavior of Windows XP. */
2181 m_FolderSettings.ViewMode = ViewMode;
2182
2183 return S_OK;
2184 }
2185
2186 HRESULT STDMETHODCALLTYPE CDefView::GetFolder(REFIID riid, void **ppv)
2187 {
2188 if (m_pSFParent == NULL)
2189 return E_FAIL;
2190
2191 return m_pSFParent->QueryInterface(riid, ppv);
2192 }
2193
2194 HRESULT STDMETHODCALLTYPE CDefView::Item(int iItemIndex, LPITEMIDLIST *ppidl)
2195 {
2196 LVITEMW item;
2197
2198 TRACE("(%p)->(%d %p)\n", this, iItemIndex, ppidl);
2199
2200 item.mask = LVIF_PARAM;
2201 item.iItem = iItemIndex;
2202
2203 if (SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM)&item))
2204 {
2205 *ppidl = ILClone((PITEMID_CHILD)item.lParam);
2206 return S_OK;
2207 }
2208
2209 *ppidl = 0;
2210
2211 return E_INVALIDARG;
2212 }
2213
2214 HRESULT STDMETHODCALLTYPE CDefView::ItemCount(UINT uFlags, int *pcItems)
2215 {
2216 TRACE("(%p)->(%u %p)\n", this, uFlags, pcItems);
2217
2218 if (uFlags != SVGIO_ALLVIEW)
2219 FIXME("some flags unsupported, %x\n", uFlags & ~SVGIO_ALLVIEW);
2220
2221 *pcItems = SendMessageW(m_hWndList, LVM_GETITEMCOUNT, 0, 0);
2222
2223 return S_OK;
2224 }
2225
2226 HRESULT STDMETHODCALLTYPE CDefView::Items(UINT uFlags, REFIID riid, void **ppv)
2227 {
2228 return E_NOTIMPL;
2229 }
2230
2231 HRESULT STDMETHODCALLTYPE CDefView::GetSelectionMarkedItem(int *piItem)
2232 {
2233 TRACE("(%p)->(%p)\n", this, piItem);
2234
2235 *piItem = SendMessageW(m_hWndList, LVM_GETSELECTIONMARK, 0, 0);
2236
2237 return S_OK;
2238 }
2239
2240 HRESULT STDMETHODCALLTYPE CDefView::GetFocusedItem(int *piItem)
2241 {
2242 TRACE("(%p)->(%p)\n", this, piItem);
2243
2244 *piItem = SendMessageW(m_hWndList, LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
2245
2246 return S_OK;
2247 }
2248
2249 HRESULT STDMETHODCALLTYPE CDefView::GetItemPosition(LPCITEMIDLIST pidl, POINT *ppt)
2250 {
2251 return E_NOTIMPL;
2252 }
2253
2254 HRESULT STDMETHODCALLTYPE CDefView::GetSpacing(POINT *ppt)
2255 {
2256 TRACE("(%p)->(%p)\n", this, ppt);
2257
2258 if (NULL == m_hWndList) return S_FALSE;
2259
2260 if (ppt)
2261 {
2262 const DWORD ret = SendMessageW(m_hWndList, LVM_GETITEMSPACING, 0, 0);
2263
2264 ppt->x = LOWORD(ret);
2265 ppt->y = HIWORD(ret);
2266 }
2267
2268 return S_OK;
2269 }
2270
2271 HRESULT STDMETHODCALLTYPE CDefView::GetDefaultSpacing(POINT *ppt)
2272 {
2273 return E_NOTIMPL;
2274 }
2275
2276 HRESULT STDMETHODCALLTYPE CDefView::GetAutoArrange()
2277 {
2278 return E_NOTIMPL;
2279 }
2280
2281 HRESULT STDMETHODCALLTYPE CDefView::SelectItem(int iItem, DWORD dwFlags)
2282 {
2283 LVITEMW lvItem;
2284
2285 TRACE("(%p)->(%d, %x)\n", this, iItem, dwFlags);
2286
2287 lvItem.state = 0;
2288 lvItem.stateMask = LVIS_SELECTED;
2289
2290 if (dwFlags & SVSI_ENSUREVISIBLE)
2291 SendMessageW(m_hWndList, LVM_ENSUREVISIBLE, iItem, 0);
2292
2293 /* all items */
2294 if (dwFlags & SVSI_DESELECTOTHERS)
2295 SendMessageW(m_hWndList, LVM_SETITEMSTATE, -1, (LPARAM)&lvItem);
2296
2297 /* this item */
2298 if (dwFlags & SVSI_SELECT)
2299 lvItem.state |= LVIS_SELECTED;
2300
2301 if (dwFlags & SVSI_FOCUSED)
2302 lvItem.stateMask |= LVIS_FOCUSED;
2303
2304 SendMessageW(m_hWndList, LVM_SETITEMSTATE, iItem, (LPARAM)&lvItem);
2305
2306 if (dwFlags & SVSI_EDIT)
2307 SendMessageW(m_hWndList, LVM_EDITLABELW, iItem, 0);
2308
2309 return S_OK;
2310 }
2311
2312 HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItems(UINT cidl, LPCITEMIDLIST *apidl, POINT *apt, DWORD dwFlags)
2313 {
2314 return E_NOTIMPL;
2315 }
2316
2317 /**********************************************************
2318 * ISVOleCmdTarget_QueryStatus (IOleCommandTarget)
2319 */
2320 HRESULT WINAPI CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText)
2321 {
2322 FIXME("(%p)->(%p(%s) 0x%08x %p %p\n",
2323 this, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
2324
2325 if (!prgCmds)
2326 return E_INVALIDARG;
2327
2328 for (UINT i = 0; i < cCmds; i++)
2329 {
2330 FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID);
2331 prgCmds[i].cmdf = 0;
2332 }
2333
2334 return OLECMDERR_E_UNKNOWNGROUP;
2335 }
2336
2337 /**********************************************************
2338 * ISVOleCmdTarget_Exec (IOleCommandTarget)
2339 *
2340 * nCmdID is the OLECMDID_* enumeration
2341 */
2342 HRESULT WINAPI CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
2343 {
2344 FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n",
2345 this, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut);
2346
2347 if (!pguidCmdGroup)
2348 return OLECMDERR_E_UNKNOWNGROUP;
2349
2350 if (IsEqualIID(*pguidCmdGroup, CGID_Explorer) &&
2351 (nCmdID == 0x29) &&
2352 (nCmdexecopt == 4) && pvaOut)
2353 return S_OK;
2354
2355 if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView) &&
2356 (nCmdID == 9) &&
2357 (nCmdexecopt == 0))
2358 return 1;
2359
2360 return OLECMDERR_E_UNKNOWNGROUP;
2361 }
2362
2363 /**********************************************************
2364 * ISVDropTarget implementation
2365 */
2366
2367 /******************************************************************************
2368 * drag_notify_subitem [Internal]
2369 *
2370 * Figure out the shellfolder object, which is currently under the mouse cursor
2371 * and notify it via the IDropTarget interface.
2372 */
2373
2374 #define SCROLLAREAWIDTH 20
2375
2376 HRESULT CDefView::drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2377 {
2378 LVHITTESTINFO htinfo;
2379 LVITEMW lvItem;
2380 LONG lResult;
2381 HRESULT hr;
2382 RECT clientRect;
2383
2384 /* Map from global to client coordinates and query the index of the listview-item, which is
2385 * currently under the mouse cursor. */
2386 htinfo.pt.x = pt.x;
2387 htinfo.pt.y = pt.y;
2388 htinfo.flags = LVHT_ONITEM;
2389 ::ScreenToClient(m_hWndList, &htinfo.pt);
2390 lResult = SendMessageW(m_hWndList, LVM_HITTEST, 0, (LPARAM)&htinfo);
2391
2392 /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */
2393 ::GetClientRect(m_hWndList, &clientRect);
2394 if (htinfo.pt.x == m_ptLastMousePos.x && htinfo.pt.y == m_ptLastMousePos.y &&
2395 (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH ||
2396 htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH ))
2397 {
2398 m_cScrollDelay = (m_cScrollDelay + 1) % 5; /* DragOver is called every 50 ms */
2399 if (m_cScrollDelay == 0)
2400 {
2401 /* Mouse did hover another 250 ms over the scroll-area */
2402 if (htinfo.pt.x < SCROLLAREAWIDTH)
2403 SendMessageW(m_hWndList, WM_HSCROLL, SB_LINEUP, 0);
2404
2405 if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH)
2406 SendMessageW(m_hWndList, WM_HSCROLL, SB_LINEDOWN, 0);
2407
2408 if (htinfo.pt.y < SCROLLAREAWIDTH)
2409 SendMessageW(m_hWndList, WM_VSCROLL, SB_LINEUP, 0);
2410
2411 if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH)
2412 SendMessageW(m_hWndList, WM_VSCROLL, SB_LINEDOWN, 0);
2413 }
2414 }
2415 else
2416 {
2417 m_cScrollDelay = 0; /* Reset, if the cursor is not over the listview's scroll-area */
2418 }
2419
2420 m_ptLastMousePos = htinfo.pt;
2421
2422 /* If we are still over the previous sub-item, notify it via DragOver and return. */
2423 if (m_pCurDropTarget && lResult == m_iDragOverItem)
2424 return m_pCurDropTarget->DragOver(grfKeyState, pt, pdwEffect);
2425
2426 /* We've left the previous sub-item, notify it via DragLeave and Release it. */
2427 if (m_pCurDropTarget)
2428 {
2429 m_pCurDropTarget->DragLeave();
2430 m_pCurDropTarget.Release();
2431 }
2432
2433 m_iDragOverItem = lResult;
2434 if (lResult == -1)
2435 {
2436 /* We are not above one of the listview's subitems. Bind to the parent folder's
2437 * DropTarget interface. */
2438 hr = m_pSFParent->QueryInterface(IID_PPV_ARG(IDropTarget,&m_pCurDropTarget));
2439 }
2440 else
2441 {
2442 /* Query the relative PIDL of the shellfolder object represented by the currently
2443 * dragged over listview-item ... */
2444 lvItem.mask = LVIF_PARAM;
2445 lvItem.iItem = lResult;
2446 lvItem.iSubItem = 0;
2447 SendMessageW(m_hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
2448
2449 /* ... and bind m_pCurDropTarget to the IDropTarget interface of an UIObject of this object */
2450 hr = m_pSFParent->GetUIObjectOf(m_hWndList, 1,
2451 (LPCITEMIDLIST*)&lvItem.lParam, IID_IDropTarget, NULL, (LPVOID*)&m_pCurDropTarget);
2452 }
2453
2454 /* If anything failed, m_pCurDropTarget should be NULL now, which ought to be a save state. */
2455 if (FAILED(hr))
2456 return hr;
2457
2458 /* Notify the item just entered via DragEnter. */
2459 return m_pCurDropTarget->DragEnter(m_pCurDataObject, grfKeyState, pt, pdwEffect);
2460 }
2461
2462 HRESULT WINAPI CDefView::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2463 {
2464 /* Get a hold on the data object for later calls to DragEnter on the sub-folders */
2465 m_pCurDataObject = pDataObject;
2466 pDataObject->AddRef();
2467
2468 return drag_notify_subitem(grfKeyState, pt, pdwEffect);
2469 }
2470
2471 HRESULT WINAPI CDefView::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2472 {
2473 return drag_notify_subitem(grfKeyState, pt, pdwEffect);
2474 }
2475
2476 HRESULT WINAPI CDefView::DragLeave()
2477 {
2478 if (m_pCurDropTarget)
2479 {
2480 m_pCurDropTarget->DragLeave();
2481 m_pCurDropTarget.Release();
2482 }
2483
2484 if (m_pCurDataObject != NULL)
2485 {
2486 m_pCurDataObject.Release();
2487 }
2488
2489 m_iDragOverItem = 0;
2490
2491 return S_OK;
2492 }
2493
2494 HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2495 {
2496 if (m_pCurDropTarget)
2497 {
2498 m_pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect);
2499 m_pCurDropTarget.Release();
2500 }
2501
2502 m_pCurDataObject.Release();
2503 m_iDragOverItem = 0;
2504 return S_OK;
2505 }
2506
2507 /**********************************************************
2508 * ISVDropSource implementation
2509 */
2510
2511 HRESULT WINAPI CDefView::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
2512 {
2513 TRACE("(%p)\n", this);
2514
2515 if (fEscapePressed)
2516 return DRAGDROP_S_CANCEL;
2517 else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON))
2518 return DRAGDROP_S_DROP;
2519 else
2520 return S_OK;
2521 }
2522
2523 HRESULT WINAPI CDefView::GiveFeedback(DWORD dwEffect)
2524 {
2525 TRACE("(%p)\n", this);
2526
2527 return DRAGDROP_S_USEDEFAULTCURSORS;
2528 }
2529
2530 /**********************************************************
2531 * ISVViewObject implementation
2532 */
2533
2534 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)
2535 {
2536 FIXME("Stub: this=%p\n", this);
2537
2538 return E_NOTIMPL;
2539 }
2540
2541 HRESULT WINAPI CDefView::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet)
2542 {
2543 FIXME("Stub: this=%p\n", this);
2544
2545 return E_NOTIMPL;
2546 }
2547
2548 HRESULT WINAPI CDefView::Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze)
2549 {
2550 FIXME("Stub: this=%p\n", this);
2551
2552 return E_NOTIMPL;
2553 }
2554
2555 HRESULT WINAPI CDefView::Unfreeze(DWORD dwFreeze)
2556 {
2557 FIXME("Stub: this=%p\n", this);
2558
2559 return E_NOTIMPL;
2560 }
2561
2562 HRESULT WINAPI CDefView::SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink)
2563 {
2564 FIXME("partial stub: %p %08x %08x %p\n", this, aspects, advf, pAdvSink);
2565
2566 /* FIXME: we set the AdviseSink, but never use it to send any advice */
2567 m_pAdvSink = pAdvSink;
2568 m_dwAspects = aspects;
2569 m_dwAdvf = advf;
2570
2571 return S_OK;
2572 }
2573
2574 HRESULT WINAPI CDefView::GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink)
2575 {
2576 TRACE("this=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n", this, pAspects, pAdvf, ppAdvSink);
2577
2578 if (ppAdvSink)
2579 {
2580 *ppAdvSink = m_pAdvSink;
2581 m_pAdvSink.p->AddRef();
2582 }
2583
2584 if (pAspects)
2585 *pAspects = m_dwAspects;
2586
2587 if (pAdvf)
2588 *pAdvf = m_dwAdvf;
2589
2590 return S_OK;
2591 }
2592
2593 HRESULT STDMETHODCALLTYPE CDefView::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
2594 {
2595 if (IsEqualIID(guidService, SID_IShellBrowser))
2596 return m_pShellBrowser->QueryInterface(riid, ppvObject);
2597 else if(IsEqualIID(guidService, SID_IFolderView))
2598 return QueryInterface(riid, ppvObject);
2599
2600 return E_NOINTERFACE;
2601 }
2602
2603 /**********************************************************
2604 * IShellView_Constructor
2605 */
2606 HRESULT WINAPI IShellView_Constructor(IShellFolder *pFolder, IShellView **newView)
2607 {
2608 CComObject<CDefView> *theView;
2609 CComPtr<IShellView> result;
2610 HRESULT hResult;
2611
2612 if (newView == NULL)
2613 return E_POINTER;
2614
2615 *newView = NULL;
2616 ATLTRY (theView = new CComObject<CDefView>);
2617
2618 if (theView == NULL)
2619 return E_OUTOFMEMORY;
2620
2621 hResult = theView->QueryInterface(IID_PPV_ARG(IShellView, &result));
2622 if (FAILED (hResult))
2623 {
2624 delete theView;
2625 return hResult;
2626 }
2627
2628 hResult = theView->Initialize (pFolder);
2629 if (FAILED (hResult))
2630 return hResult;
2631 *newView = result.Detach ();
2632
2633 return S_OK;
2634 }