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