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