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