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