shell32/tests: Fix test failures on old shell32 for FO_MOVE.
[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 = lParam1;
459     LPITEMIDLIST pItemIdList2 = 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 = SendMessageW(This->hWndList, LVM_GETITEMCOUNT, 0, 0); /*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==SendMessageW(This->hWndList, LVM_DELETEITEM, nIndex, 0))? 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 = SendMessageW(This->hWndList, LVM_GETSELECTEDCOUNT, 0, 0);
840         This->apidl = 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(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                                       &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 = 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 = 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 = 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_RETURN %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 dwEffect2;
1432                     DoDragDrop(pda, pds, dwEffect, &dwEffect2);
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_BEGINLABELEDITW %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 = SendMessageW(This->hWndList, LVM_GETSELECTEDCOUNT, 0, 0);
1498
1499                 /* get selected item */
1500                 if(i == 1)
1501                 {
1502                   /* get selected item */
1503                   i = SendMessageW(This->hWndList, LVM_GETNEXTITEM, -1, MAKELPARAM (LVNI_SELECTED, 0));
1504
1505                   SendMessageW(This->hWndList, LVM_ENSUREVISIBLE, i, 0);
1506                   SendMessageW(This->hWndList, LVM_EDITLABELW, i, 0);
1507                 }
1508               }
1509 #if 0
1510               TranslateAccelerator(This->hWnd, This->hAccel, &msg)
1511 #endif
1512               else if(plvKeyDown->wVKey == VK_DELETE)
1513               {
1514                 UINT i;
1515                 int item_index;
1516                 LVITEMA item;
1517                 LPITEMIDLIST* pItems;
1518                 ISFHelper *psfhlp;
1519
1520                 IShellFolder_QueryInterface(This->pSFParent, &IID_ISFHelper,
1521                         (LPVOID*)&psfhlp);
1522
1523                 if (psfhlp == NULL)
1524                   break;
1525
1526                 if(!(i = SendMessageW(This->hWndList, LVM_GETSELECTEDCOUNT, 0, 0)))
1527                   break;
1528
1529                 /* allocate memory for the pidl array */
1530                 pItems = HeapAlloc(GetProcessHeap(), 0,
1531                         sizeof(LPITEMIDLIST) * i);
1532
1533                 /* retrieve all selected items */
1534                 i = 0;
1535                 item_index = -1;
1536                 while(SendMessageW(This->hWndList, LVM_GETSELECTEDCOUNT, 0, 0) > i)
1537                 {
1538                   /* get selected item */
1539                   item_index = SendMessageW(This->hWndList, LVM_GETNEXTITEM, item_index,
1540                                             MAKELPARAM (LVNI_SELECTED, 0));
1541                   item.iItem = item_index;
1542                   item.mask = LVIF_PARAM;
1543                   SendMessageA(This->hWndList, LVM_GETITEMA, 0, (LPARAM) &item);
1544
1545                   /* get item pidl */
1546                   pItems[i] = (LPITEMIDLIST)item.lParam;
1547
1548                   i++;
1549                 }
1550
1551                 /* perform the item deletion */
1552                 ISFHelper_DeleteItems(psfhlp, i, (LPCITEMIDLIST*)pItems);
1553
1554                 /* free pidl array memory */
1555                 HeapFree(GetProcessHeap(), 0, pItems);
1556               }
1557
1558               /* Initiate a refresh */
1559               else if(plvKeyDown->wVKey == VK_F5)
1560               {
1561                 IShellView_Refresh((IShellView*)This);
1562               }
1563
1564               else if(plvKeyDown->wVKey == VK_BACK)
1565               {
1566                 LPSHELLBROWSER lpSb;
1567                 if((lpSb = (LPSHELLBROWSER)SendMessageW(This->hWndParent, CWM_GETISHELLBROWSER, 0, 0)))
1568                 {
1569                   IShellBrowser_BrowseObject(lpSb, NULL, SBSP_PARENT);
1570                 }
1571               }
1572
1573               else
1574                 FIXME("LVN_KEYDOWN key=0x%08x\n",plvKeyDown->wVKey);
1575             }
1576             break;
1577
1578           default:
1579             TRACE("-- %p WM_COMMAND %x unhandled\n", This, lpnmh->code);
1580             break;
1581         }
1582         return 0;
1583 }
1584
1585 /**********************************************************
1586 * ShellView_OnChange()
1587 */
1588
1589 static LRESULT ShellView_OnChange(IShellViewImpl * This, const LPCITEMIDLIST * Pidls, LONG wEventId)
1590 {
1591
1592         TRACE("(%p)(%p,%p,0x%08x)\n", This, Pidls[0], Pidls[1], wEventId);
1593         switch(wEventId)
1594         {
1595           case SHCNE_MKDIR:
1596           case SHCNE_CREATE:
1597             LV_AddItem(This, Pidls[0]);
1598             break;
1599           case SHCNE_RMDIR:
1600           case SHCNE_DELETE:
1601             LV_DeleteItem(This, Pidls[0]);
1602             break;
1603           case SHCNE_RENAMEFOLDER:
1604           case SHCNE_RENAMEITEM:
1605             LV_RenameItem(This, Pidls[0], Pidls[1]);
1606             break;
1607           case SHCNE_UPDATEITEM:
1608             break;
1609         }
1610         return TRUE;
1611 }
1612 /**********************************************************
1613 *  ShellView_WndProc
1614 */
1615
1616 static LRESULT CALLBACK ShellView_WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
1617 {
1618         IShellViewImpl * pThis = (IShellViewImpl*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
1619         LPCREATESTRUCTW lpcs;
1620
1621         TRACE("(hwnd=%p msg=%x wparm=%lx lparm=%lx)\n",hWnd, uMessage, wParam, lParam);
1622
1623         switch (uMessage)
1624         {
1625           case WM_NCCREATE:
1626             lpcs = (LPCREATESTRUCTW)lParam;
1627             pThis = lpcs->lpCreateParams;
1628             SetWindowLongPtrW(hWnd, GWLP_USERDATA, (ULONG_PTR)pThis);
1629             pThis->hWnd = hWnd;        /*set the window handle*/
1630             break;
1631
1632           case WM_SIZE:         return ShellView_OnSize(pThis,LOWORD(lParam), HIWORD(lParam));
1633           case WM_SETFOCUS:     return ShellView_OnSetFocus(pThis);
1634           case WM_KILLFOCUS:    return ShellView_OnKillFocus(pThis);
1635           case WM_CREATE:       return ShellView_OnCreate(pThis);
1636           case WM_ACTIVATE:     return ShellView_OnActivate(pThis, SVUIA_ACTIVATE_FOCUS);
1637           case WM_NOTIFY:       return ShellView_OnNotify(pThis,(UINT)wParam, (LPNMHDR)lParam);
1638           case WM_COMMAND:      return ShellView_OnCommand(pThis,
1639                                         GET_WM_COMMAND_ID(wParam, lParam),
1640                                         GET_WM_COMMAND_CMD(wParam, lParam),
1641                                         GET_WM_COMMAND_HWND(wParam, lParam));
1642           case SHV_CHANGE_NOTIFY: return ShellView_OnChange(pThis, (const LPCITEMIDLIST*)wParam, (LONG)lParam);
1643
1644           case WM_CONTEXTMENU:  ShellView_DoContextMenu(pThis, LOWORD(lParam), HIWORD(lParam), FALSE);
1645                                 return 0;
1646
1647           case WM_SHOWWINDOW:   UpdateWindow(pThis->hWndList);
1648                                 break;
1649
1650           case WM_GETDLGCODE:   return SendMessageA(pThis->hWndList,uMessage,0,0);
1651
1652           case WM_DESTROY:      
1653                                 RevokeDragDrop(pThis->hWnd);
1654                                 SHChangeNotifyDeregister(pThis->hNotify);
1655                                 break;
1656
1657           case WM_ERASEBKGND:
1658             if ((pThis->FolderSettings.fFlags & FWF_DESKTOP) ||
1659                 (pThis->FolderSettings.fFlags & FWF_TRANSPARENT))
1660               return 1;
1661             break;
1662         }
1663
1664         return DefWindowProcW(hWnd, uMessage, wParam, lParam);
1665 }
1666 /**********************************************************
1667 *
1668 *
1669 *  The INTERFACE of the IShellView object
1670 *
1671 *
1672 **********************************************************
1673 *  IShellView_QueryInterface
1674 */
1675 static HRESULT WINAPI IShellView_fnQueryInterface(IShellView2 * iface,REFIID riid, LPVOID *ppvObj)
1676 {
1677         IShellViewImpl *This = (IShellViewImpl *)iface;
1678
1679         TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
1680
1681         *ppvObj = NULL;
1682
1683         if(IsEqualIID(riid, &IID_IUnknown))
1684         {
1685           *ppvObj = This;
1686         }
1687         else if(IsEqualIID(riid, &IID_IShellView))
1688         {
1689           *ppvObj = This;
1690         }
1691         else if(IsEqualIID(riid, &IID_IShellView2))
1692         {
1693           *ppvObj = This;
1694         }
1695         else if(IsEqualIID(riid, &IID_IOleCommandTarget))
1696         {
1697           *ppvObj = &This->lpvtblOleCommandTarget;
1698         }
1699         else if(IsEqualIID(riid, &IID_IDropTarget))
1700         {
1701           *ppvObj = &This->lpvtblDropTarget;
1702         }
1703         else if(IsEqualIID(riid, &IID_IDropSource))
1704         {
1705           *ppvObj = &This->lpvtblDropSource;
1706         }
1707         else if(IsEqualIID(riid, &IID_IViewObject))
1708         {
1709           *ppvObj = &This->lpvtblViewObject;
1710         }
1711
1712         if(*ppvObj)
1713         {
1714           IUnknown_AddRef( (IUnknown*)*ppvObj );
1715           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
1716           return S_OK;
1717         }
1718         TRACE("-- Interface: E_NOINTERFACE\n");
1719         return E_NOINTERFACE;
1720 }
1721
1722 /**********************************************************
1723 *  IShellView_AddRef
1724 */
1725 static ULONG WINAPI IShellView_fnAddRef(IShellView2 * iface)
1726 {
1727         IShellViewImpl *This = (IShellViewImpl *)iface;
1728         ULONG refCount = InterlockedIncrement(&This->ref);
1729
1730         TRACE("(%p)->(count=%u)\n", This, refCount - 1);
1731
1732         return refCount;
1733 }
1734 /**********************************************************
1735 *  IShellView_Release
1736 */
1737 static ULONG WINAPI IShellView_fnRelease(IShellView2 * iface)
1738 {
1739         IShellViewImpl *This = (IShellViewImpl *)iface;
1740         ULONG refCount = InterlockedDecrement(&This->ref);
1741
1742         TRACE("(%p)->(count=%i)\n", This, refCount + 1);
1743
1744         if (!refCount)
1745         {
1746           TRACE(" destroying IShellView(%p)\n",This);
1747
1748           DestroyWindow(This->hWndList);
1749
1750           if(This->pSFParent)
1751             IShellFolder_Release(This->pSFParent);
1752
1753           if(This->pSF2Parent)
1754             IShellFolder2_Release(This->pSF2Parent);
1755
1756           SHFree(This->apidl);
1757
1758           if(This->pAdvSink)
1759             IAdviseSink_Release(This->pAdvSink);
1760
1761           HeapFree(GetProcessHeap(),0,This);
1762         }
1763         return refCount;
1764 }
1765
1766 /**********************************************************
1767 *  ShellView_GetWindow
1768 */
1769 static HRESULT WINAPI IShellView_fnGetWindow(IShellView2 * iface,HWND * phWnd)
1770 {
1771         IShellViewImpl *This = (IShellViewImpl *)iface;
1772
1773         TRACE("(%p)\n",This);
1774
1775         *phWnd = This->hWnd;
1776
1777         return S_OK;
1778 }
1779
1780 static HRESULT WINAPI IShellView_fnContextSensitiveHelp(IShellView2 * iface,BOOL fEnterMode)
1781 {
1782         IShellViewImpl *This = (IShellViewImpl *)iface;
1783
1784         FIXME("(%p) stub\n",This);
1785
1786         return E_NOTIMPL;
1787 }
1788
1789 /**********************************************************
1790 * IShellView_TranslateAccelerator
1791 *
1792 * FIXME:
1793 *  use the accel functions
1794 */
1795 static HRESULT WINAPI IShellView_fnTranslateAccelerator(IShellView2 * iface,LPMSG lpmsg)
1796 {
1797 #if 0
1798         IShellViewImpl *This = (IShellViewImpl *)iface;
1799
1800         FIXME("(%p)->(%p: hwnd=%x msg=%x lp=%x wp=%x) stub\n",This,lpmsg, lpmsg->hwnd, lpmsg->message, lpmsg->lParam, lpmsg->wParam);
1801 #endif
1802
1803         if ((lpmsg->message>=WM_KEYFIRST) && (lpmsg->message>=WM_KEYLAST))
1804         {
1805           TRACE("-- key=0x04%lx\n",lpmsg->wParam) ;
1806         }
1807         return S_FALSE; /* not handled */
1808 }
1809
1810 static HRESULT WINAPI IShellView_fnEnableModeless(IShellView2 * iface,BOOL fEnable)
1811 {
1812         IShellViewImpl *This = (IShellViewImpl *)iface;
1813
1814         FIXME("(%p) stub\n",This);
1815
1816         return E_NOTIMPL;
1817 }
1818
1819 static HRESULT WINAPI IShellView_fnUIActivate(IShellView2 * iface,UINT uState)
1820 {
1821         IShellViewImpl *This = (IShellViewImpl *)iface;
1822
1823 /*
1824         CHAR    szName[MAX_PATH];
1825 */
1826         LRESULT lResult;
1827         int     nPartArray[1] = {-1};
1828
1829         TRACE("(%p)->(state=%x) stub\n",This, uState);
1830
1831         /*don't do anything if the state isn't really changing*/
1832         if(This->uState == uState)
1833         {
1834           return S_OK;
1835         }
1836
1837         /*OnActivate handles the menu merging and internal state*/
1838         ShellView_OnActivate(This, uState);
1839
1840         /*only do This if we are active*/
1841         if(uState != SVUIA_DEACTIVATE)
1842         {
1843
1844 /*
1845           GetFolderPath is not a method of IShellFolder
1846           IShellFolder_GetFolderPath( This->pSFParent, szName, sizeof(szName) );
1847 */
1848           /* set the number of parts */
1849           IShellBrowser_SendControlMsg(This->pShellBrowser, FCW_STATUS, SB_SETPARTS, 1,
1850                                                         (LPARAM)nPartArray, &lResult);
1851
1852           /* set the text for the parts */
1853 /*
1854           IShellBrowser_SendControlMsg(This->pShellBrowser, FCW_STATUS, SB_SETTEXTA,
1855                                                         0, (LPARAM)szName, &lResult);
1856 */
1857         }
1858
1859         return S_OK;
1860 }
1861
1862 static HRESULT WINAPI IShellView_fnRefresh(IShellView2 * iface)
1863 {
1864         IShellViewImpl *This = (IShellViewImpl *)iface;
1865
1866         TRACE("(%p)\n",This);
1867
1868         SendMessageW(This->hWndList, LVM_DELETEALLITEMS, 0, 0);
1869         ShellView_FillList(This);
1870
1871         return S_OK;
1872 }
1873
1874 static HRESULT WINAPI IShellView_fnCreateViewWindow(IShellView2 *iface, IShellView *lpPrevView,
1875         LPCFOLDERSETTINGS lpfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd)
1876 {
1877     HRESULT hr;
1878     SV2CVW2_PARAMS view_params;
1879     view_params.cbSize = sizeof(view_params);
1880     view_params.psvPrev = lpPrevView;
1881     view_params.pfs = lpfs;
1882     view_params.psbOwner = psb;
1883     view_params.prcView = prcView;
1884     view_params.pvid = NULL;
1885     view_params.hwndView = 0;
1886
1887     TRACE("(%p) Forwarding to CreateViewWindow2\n", iface);
1888
1889     hr = IShellView2_CreateViewWindow2(iface, &view_params);
1890     *phWnd = view_params.hwndView;
1891
1892     return hr;
1893 }
1894
1895 static HRESULT WINAPI IShellView_fnDestroyViewWindow(IShellView2 * iface)
1896 {
1897         IShellViewImpl *This = (IShellViewImpl *)iface;
1898
1899         TRACE("(%p)\n",This);
1900
1901         /*Make absolutely sure all our UI is cleaned up.*/
1902         IShellView_UIActivate((IShellView*)This, SVUIA_DEACTIVATE);
1903
1904         if(This->hMenu)
1905         {
1906           DestroyMenu(This->hMenu);
1907         }
1908
1909         DestroyWindow(This->hWnd);
1910         if(This->pShellBrowser) IShellBrowser_Release(This->pShellBrowser);
1911         if(This->pCommDlgBrowser) ICommDlgBrowser_Release(This->pCommDlgBrowser);
1912
1913
1914         return S_OK;
1915 }
1916
1917 static HRESULT WINAPI IShellView_fnGetCurrentInfo(IShellView2 * iface, LPFOLDERSETTINGS lpfs)
1918 {
1919         IShellViewImpl *This = (IShellViewImpl *)iface;
1920
1921         TRACE("(%p)->(%p) vmode=%x flags=%x\n",This, lpfs,
1922                 This->FolderSettings.ViewMode, This->FolderSettings.fFlags);
1923
1924         if (!lpfs) return E_INVALIDARG;
1925
1926         *lpfs = This->FolderSettings;
1927         return NOERROR;
1928 }
1929
1930 static HRESULT WINAPI IShellView_fnAddPropertySheetPages(IShellView2 * iface, DWORD dwReserved,LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam)
1931 {
1932         IShellViewImpl *This = (IShellViewImpl *)iface;
1933
1934         FIXME("(%p) stub\n",This);
1935
1936         return E_NOTIMPL;
1937 }
1938
1939 static HRESULT WINAPI IShellView_fnSaveViewState(IShellView2 * iface)
1940 {
1941         IShellViewImpl *This = (IShellViewImpl *)iface;
1942
1943         FIXME("(%p) stub\n",This);
1944
1945         return S_OK;
1946 }
1947
1948 static HRESULT WINAPI IShellView_fnSelectItem(
1949         IShellView2 * iface,
1950         LPCITEMIDLIST pidl,
1951         UINT uFlags)
1952 {
1953         IShellViewImpl *This = (IShellViewImpl *)iface;
1954         int i;
1955
1956         TRACE("(%p)->(pidl=%p, 0x%08x) stub\n",This, pidl, uFlags);
1957
1958         i = LV_FindItemByPidl(This, pidl);
1959
1960         if (i != -1)
1961         {
1962           LVITEMW lvItem;
1963
1964           if(uFlags & SVSI_ENSUREVISIBLE)
1965             SendMessageW(This->hWndList, LVM_ENSUREVISIBLE, i, 0);
1966
1967           lvItem.mask = LVIF_STATE;
1968           lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
1969           lvItem.iItem = 0;
1970           lvItem.iSubItem = 0;
1971
1972           while(SendMessageW(This->hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem))
1973           {
1974             if (lvItem.iItem == i)
1975             {
1976               if (uFlags & SVSI_SELECT)
1977                 lvItem.state |= LVIS_SELECTED;
1978               else
1979                 lvItem.state &= ~LVIS_SELECTED;
1980
1981               if(uFlags & SVSI_FOCUSED)
1982                 lvItem.state &= ~LVIS_FOCUSED;
1983             }
1984             else
1985             {
1986               if (uFlags & SVSI_DESELECTOTHERS)
1987                 lvItem.state &= ~LVIS_SELECTED;
1988             }
1989             SendMessageW(This->hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
1990             lvItem.iItem++;
1991           }
1992
1993
1994           if(uFlags & SVSI_EDIT)
1995             SendMessageW(This->hWndList, LVM_EDITLABELW, i, 0);
1996
1997         }
1998         return S_OK;
1999 }
2000
2001 static HRESULT WINAPI IShellView_fnGetItemObject(IShellView2 * iface, UINT uItem, REFIID riid, LPVOID *ppvOut)
2002 {
2003         IShellViewImpl *This = (IShellViewImpl *)iface;
2004
2005         TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n",This, uItem, debugstr_guid(riid), ppvOut);
2006
2007         *ppvOut = NULL;
2008
2009         switch(uItem)
2010         {
2011           case SVGIO_BACKGROUND:
2012             *ppvOut = ISvBgCm_Constructor(This->pSFParent, FALSE);
2013             break;
2014
2015           case SVGIO_SELECTION:
2016             ShellView_GetSelections(This);
2017             IShellFolder_GetUIObjectOf(This->pSFParent, This->hWnd, This->cidl, (LPCITEMIDLIST*)This->apidl, riid, 0, ppvOut);
2018             break;
2019         }
2020         TRACE("-- (%p)->(interface=%p)\n",This, *ppvOut);
2021
2022         if(!*ppvOut) return E_OUTOFMEMORY;
2023
2024         return S_OK;
2025 }
2026
2027 static HRESULT WINAPI IShellView2_fnGetView(IShellView2* iface, SHELLVIEWID *view_guid, ULONG view_type)
2028 {
2029     FIXME("(%p)->(view_guid %s, view_type %#x) stub!\n", iface, debugstr_guid(view_guid), view_type);
2030     return E_NOTIMPL;
2031 }
2032
2033 static HRESULT WINAPI IShellView2_fnCreateViewWindow2(IShellView2* iface, LPSV2CVW2_PARAMS view_params)
2034 {
2035     IShellViewImpl *This = (IShellViewImpl *)iface;
2036     WNDCLASSW wc;
2037     HWND wnd;
2038
2039     TRACE("(%p)->(view_params %p)\n", iface, view_params);
2040
2041     if (view_params->cbSize != sizeof(*view_params))
2042     {
2043         FIXME("Got unexpected cbSize %#x\n", view_params->cbSize);
2044         return E_FAIL;
2045     }
2046
2047     TRACE("-- psvPrev %p, pfs %p, psbOwner %p, prcView %p\n",
2048             view_params->psvPrev, view_params->pfs, view_params->psbOwner, view_params->prcView);
2049     TRACE("-- vmode %#x, flags %#x, left %d, top %d, right %d, bottom %d\n",
2050             view_params->pfs->ViewMode, view_params->pfs->fFlags, view_params->prcView->left,
2051             view_params->prcView->top, view_params->prcView->right, view_params->prcView->bottom);
2052
2053     /* Set up the member variables */
2054     This->pShellBrowser = view_params->psbOwner;
2055     This->FolderSettings = *view_params->pfs;
2056
2057     if (view_params->pvid)
2058     {
2059         if (IsEqualGUID(view_params->pvid, &VID_LargeIcons))
2060             This->FolderSettings.ViewMode = FVM_ICON;
2061         else if (IsEqualGUID(view_params->pvid, &VID_SmallIcons))
2062             This->FolderSettings.ViewMode = FVM_SMALLICON;
2063         else if (IsEqualGUID(view_params->pvid, &VID_List))
2064             This->FolderSettings.ViewMode = FVM_LIST;
2065         else if (IsEqualGUID(view_params->pvid, &VID_Details))
2066             This->FolderSettings.ViewMode = FVM_DETAILS;
2067         else if (IsEqualGUID(view_params->pvid, &VID_Thumbnails))
2068             This->FolderSettings.ViewMode = FVM_THUMBNAIL;
2069         else if (IsEqualGUID(view_params->pvid, &VID_Tile))
2070             This->FolderSettings.ViewMode = FVM_TILE;
2071         else if (IsEqualGUID(view_params->pvid, &VID_ThumbStrip))
2072             This->FolderSettings.ViewMode = FVM_THUMBSTRIP;
2073         else
2074             FIXME("Ignoring unrecognized VID %s\n", debugstr_guid(view_params->pvid));
2075     }
2076
2077     /* Get our parent window */
2078     IShellBrowser_AddRef(This->pShellBrowser);
2079     IShellBrowser_GetWindow(This->pShellBrowser, &(This->hWndParent));
2080
2081     /* Try to get the ICommDlgBrowserInterface, adds a reference !!! */
2082     This->pCommDlgBrowser = NULL;
2083     if (SUCCEEDED(IShellBrowser_QueryInterface(This->pShellBrowser, &IID_ICommDlgBrowser, (void **)&This->pCommDlgBrowser)))
2084     {
2085         TRACE("-- CommDlgBrowser %p\n", This->pCommDlgBrowser);
2086     }
2087
2088     /* If our window class has not been registered, then do so */
2089     if (!GetClassInfoW(shell32_hInstance, SV_CLASS_NAME, &wc))
2090     {
2091         ZeroMemory(&wc, sizeof(wc));
2092         wc.style            = CS_HREDRAW | CS_VREDRAW;
2093         wc.lpfnWndProc      = ShellView_WndProc;
2094         wc.cbClsExtra       = 0;
2095         wc.cbWndExtra       = 0;
2096         wc.hInstance        = shell32_hInstance;
2097         wc.hIcon            = 0;
2098         wc.hCursor          = LoadCursorW(0, (LPWSTR)IDC_ARROW);
2099         wc.hbrBackground    = (HBRUSH)(COLOR_WINDOW + 1);
2100         wc.lpszMenuName     = NULL;
2101         wc.lpszClassName    = SV_CLASS_NAME;
2102
2103         if (!RegisterClassW(&wc)) return E_FAIL;
2104     }
2105
2106     wnd = CreateWindowExW(0, SV_CLASS_NAME, NULL, WS_CHILD | WS_TABSTOP,
2107             view_params->prcView->left, view_params->prcView->top,
2108             view_params->prcView->right - view_params->prcView->left,
2109             view_params->prcView->bottom - view_params->prcView->top,
2110             This->hWndParent, 0, shell32_hInstance, This);
2111
2112     CheckToolbar(This);
2113
2114     if (!wnd) return E_FAIL;
2115
2116     SetWindowPos(wnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
2117     UpdateWindow(wnd);
2118
2119     view_params->hwndView = wnd;
2120
2121     return S_OK;
2122 }
2123
2124 static HRESULT WINAPI IShellView2_fnHandleRename(IShellView2* iface, LPCITEMIDLIST new_pidl)
2125 {
2126     FIXME("(%p)->(new_pidl %p) stub!\n", iface, new_pidl);
2127     return E_NOTIMPL;
2128 }
2129
2130 static HRESULT WINAPI IShellView2_fnSelectAndPositionItem(IShellView2* iface, LPCITEMIDLIST item, UINT flags, POINT *point)
2131 {
2132     FIXME("(%p)->(item %p, flags %#x, point %p) stub!\n", iface, item, flags, point);
2133     return E_NOTIMPL;
2134 }
2135
2136 static const IShellView2Vtbl svvt =
2137 {
2138         IShellView_fnQueryInterface,
2139         IShellView_fnAddRef,
2140         IShellView_fnRelease,
2141         IShellView_fnGetWindow,
2142         IShellView_fnContextSensitiveHelp,
2143         IShellView_fnTranslateAccelerator,
2144         IShellView_fnEnableModeless,
2145         IShellView_fnUIActivate,
2146         IShellView_fnRefresh,
2147         IShellView_fnCreateViewWindow,
2148         IShellView_fnDestroyViewWindow,
2149         IShellView_fnGetCurrentInfo,
2150         IShellView_fnAddPropertySheetPages,
2151         IShellView_fnSaveViewState,
2152         IShellView_fnSelectItem,
2153         IShellView_fnGetItemObject,
2154         IShellView2_fnGetView,
2155         IShellView2_fnCreateViewWindow2,
2156         IShellView2_fnHandleRename,
2157         IShellView2_fnSelectAndPositionItem,
2158 };
2159
2160
2161 /**********************************************************
2162  * ISVOleCmdTarget_QueryInterface (IUnknown)
2163  */
2164 static HRESULT WINAPI ISVOleCmdTarget_QueryInterface(
2165         IOleCommandTarget *     iface,
2166         REFIID                  iid,
2167         LPVOID*                 ppvObj)
2168 {
2169         IShellViewImpl *This = impl_from_IOleCommandTarget(iface);
2170
2171         return IShellFolder_QueryInterface((IShellFolder*)This, iid, ppvObj);
2172 }
2173
2174 /**********************************************************
2175  * ISVOleCmdTarget_AddRef (IUnknown)
2176  */
2177 static ULONG WINAPI ISVOleCmdTarget_AddRef(
2178         IOleCommandTarget *     iface)
2179 {
2180         IShellViewImpl *This = impl_from_IOleCommandTarget(iface);
2181
2182         return IShellFolder_AddRef((IShellFolder*)This);
2183 }
2184
2185 /**********************************************************
2186  * ISVOleCmdTarget_Release (IUnknown)
2187  */
2188 static ULONG WINAPI ISVOleCmdTarget_Release(
2189         IOleCommandTarget *     iface)
2190 {
2191         IShellViewImpl *This = impl_from_IOleCommandTarget(iface);
2192
2193         return IShellFolder_Release((IShellFolder*)This);
2194 }
2195
2196 /**********************************************************
2197  * ISVOleCmdTarget_QueryStatus (IOleCommandTarget)
2198  */
2199 static HRESULT WINAPI ISVOleCmdTarget_QueryStatus(
2200         IOleCommandTarget *iface,
2201         const GUID* pguidCmdGroup,
2202         ULONG cCmds,
2203         OLECMD * prgCmds,
2204         OLECMDTEXT* pCmdText)
2205 {
2206     UINT i;
2207     IShellViewImpl *This = impl_from_IOleCommandTarget(iface);
2208
2209     FIXME("(%p)->(%p(%s) 0x%08x %p %p\n",
2210               This, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
2211
2212     if (!prgCmds)
2213         return E_POINTER;
2214     for (i = 0; i < cCmds; i++)
2215     {
2216         FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID);
2217         prgCmds[i].cmdf = 0;
2218     }
2219     return OLECMDERR_E_UNKNOWNGROUP;
2220 }
2221
2222 /**********************************************************
2223  * ISVOleCmdTarget_Exec (IOleCommandTarget)
2224  *
2225  * nCmdID is the OLECMDID_* enumeration
2226  */
2227 static HRESULT WINAPI ISVOleCmdTarget_Exec(
2228         IOleCommandTarget *iface,
2229         const GUID* pguidCmdGroup,
2230         DWORD nCmdID,
2231         DWORD nCmdexecopt,
2232         VARIANT* pvaIn,
2233         VARIANT* pvaOut)
2234 {
2235         IShellViewImpl *This = impl_from_IOleCommandTarget(iface);
2236
2237         FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n",
2238               This, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut);
2239
2240         if (IsEqualIID(pguidCmdGroup, &CGID_Explorer) &&
2241            (nCmdID == 0x29) &&
2242            (nCmdexecopt == 4) && pvaOut)
2243            return S_OK;
2244         if (IsEqualIID(pguidCmdGroup, &CGID_ShellDocView) &&
2245            (nCmdID == 9) &&
2246            (nCmdexecopt == 0))
2247            return 1;
2248
2249         return OLECMDERR_E_UNKNOWNGROUP;
2250 }
2251
2252 static const IOleCommandTargetVtbl ctvt =
2253 {
2254         ISVOleCmdTarget_QueryInterface,
2255         ISVOleCmdTarget_AddRef,
2256         ISVOleCmdTarget_Release,
2257         ISVOleCmdTarget_QueryStatus,
2258         ISVOleCmdTarget_Exec
2259 };
2260
2261 /**********************************************************
2262  * ISVDropTarget implementation
2263  */
2264
2265 static HRESULT WINAPI ISVDropTarget_QueryInterface(
2266         IDropTarget *iface,
2267         REFIID riid,
2268         LPVOID *ppvObj)
2269 {
2270         IShellViewImpl *This = impl_from_IDropTarget(iface);
2271
2272         TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
2273
2274         return IShellFolder_QueryInterface((IShellFolder*)This, riid, ppvObj);
2275 }
2276
2277 static ULONG WINAPI ISVDropTarget_AddRef( IDropTarget *iface)
2278 {
2279         IShellViewImpl *This = impl_from_IDropTarget(iface);
2280
2281         TRACE("(%p)->(count=%u)\n",This,This->ref);
2282
2283         return IShellFolder_AddRef((IShellFolder*)This);
2284 }
2285
2286 static ULONG WINAPI ISVDropTarget_Release( IDropTarget *iface)
2287 {
2288         IShellViewImpl *This = impl_from_IDropTarget(iface);
2289
2290         TRACE("(%p)->(count=%u)\n",This,This->ref);
2291
2292         return IShellFolder_Release((IShellFolder*)This);
2293 }
2294
2295 /******************************************************************************
2296  * drag_notify_subitem [Internal]
2297  *
2298  * Figure out the shellfolder object, which is currently under the mouse cursor
2299  * and notify it via the IDropTarget interface.
2300  */
2301
2302 #define SCROLLAREAWIDTH 20
2303
2304 static HRESULT drag_notify_subitem(IShellViewImpl *This, DWORD grfKeyState, POINTL pt,
2305     DWORD *pdwEffect)
2306 {
2307     LVHITTESTINFO htinfo;
2308     LVITEMW lvItem;
2309     LONG lResult;
2310     HRESULT hr;
2311     RECT clientRect;
2312
2313     /* Map from global to client coordinates and query the index of the listview-item, which is 
2314      * currently under the mouse cursor. */
2315     htinfo.pt.x = pt.x;
2316     htinfo.pt.y = pt.y;
2317     htinfo.flags = LVHT_ONITEM;
2318     ScreenToClient(This->hWndList, &htinfo.pt);
2319     lResult = SendMessageW(This->hWndList, LVM_HITTEST, 0, (LPARAM)&htinfo);
2320
2321     /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */
2322     GetClientRect(This->hWndList, &clientRect);
2323     if (htinfo.pt.x == This->ptLastMousePos.x && htinfo.pt.y == This->ptLastMousePos.y &&
2324         (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH ||
2325          htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH ))
2326     {
2327         This->cScrollDelay = (This->cScrollDelay + 1) % 5; /* DragOver is called every 50 ms */
2328         if (This->cScrollDelay == 0) { /* Mouse did hover another 250 ms over the scroll-area */
2329             if (htinfo.pt.x < SCROLLAREAWIDTH) 
2330                 SendMessageW(This->hWndList, WM_HSCROLL, SB_LINEUP, 0);
2331             if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH)
2332                 SendMessageW(This->hWndList, WM_HSCROLL, SB_LINEDOWN, 0);
2333             if (htinfo.pt.y < SCROLLAREAWIDTH)
2334                 SendMessageW(This->hWndList, WM_VSCROLL, SB_LINEUP, 0);
2335             if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH)
2336                 SendMessageW(This->hWndList, WM_VSCROLL, SB_LINEDOWN, 0);
2337         }
2338     } else {
2339         This->cScrollDelay = 0; /* Reset, if the cursor is not over the listview's scroll-area */
2340     }
2341     This->ptLastMousePos = htinfo.pt;
2342  
2343     /* If we are still over the previous sub-item, notify it via DragOver and return. */
2344     if (This->pCurDropTarget && lResult == This->iDragOverItem)
2345     return IDropTarget_DragOver(This->pCurDropTarget, grfKeyState, pt, pdwEffect);
2346   
2347     /* We've left the previous sub-item, notify it via DragLeave and Release it. */
2348     if (This->pCurDropTarget) {
2349         IDropTarget_DragLeave(This->pCurDropTarget);
2350         IDropTarget_Release(This->pCurDropTarget);
2351         This->pCurDropTarget = NULL;
2352     }
2353
2354     This->iDragOverItem = lResult;
2355     if (lResult == -1) {
2356         /* We are not above one of the listview's subitems. Bind to the parent folder's
2357          * DropTarget interface. */
2358         hr = IShellFolder_QueryInterface(This->pSFParent, &IID_IDropTarget, 
2359                                          (LPVOID*)&This->pCurDropTarget);
2360     } else {
2361         /* Query the relative PIDL of the shellfolder object represented by the currently
2362          * dragged over listview-item ... */
2363         lvItem.mask = LVIF_PARAM;
2364         lvItem.iItem = lResult;
2365         lvItem.iSubItem = 0;
2366         SendMessageW(This->hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
2367
2368         /* ... and bind pCurDropTarget to the IDropTarget interface of an UIObject of this object */
2369         hr = IShellFolder_GetUIObjectOf(This->pSFParent, This->hWndList, 1,
2370             (LPCITEMIDLIST*)&lvItem.lParam, &IID_IDropTarget, NULL, (LPVOID*)&This->pCurDropTarget);
2371     }
2372
2373     /* If anything failed, pCurDropTarget should be NULL now, which ought to be a save state. */
2374     if (FAILED(hr)) 
2375         return hr;
2376
2377     /* Notify the item just entered via DragEnter. */
2378     return IDropTarget_DragEnter(This->pCurDropTarget, This->pCurDataObject, grfKeyState, pt, pdwEffect);
2379 }
2380
2381 static HRESULT WINAPI ISVDropTarget_DragEnter(IDropTarget *iface, IDataObject *pDataObject,
2382     DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2383 {
2384     IShellViewImpl *This = impl_from_IDropTarget(iface);
2385
2386     /* Get a hold on the data object for later calls to DragEnter on the sub-folders */
2387     This->pCurDataObject = pDataObject;
2388     IDataObject_AddRef(pDataObject);
2389
2390     return drag_notify_subitem(This, grfKeyState, pt, pdwEffect);
2391 }
2392
2393 static HRESULT WINAPI ISVDropTarget_DragOver(IDropTarget *iface, DWORD grfKeyState, POINTL pt,
2394     DWORD *pdwEffect)
2395 {
2396     IShellViewImpl *This = impl_from_IDropTarget(iface);
2397     return drag_notify_subitem(This, grfKeyState, pt, pdwEffect);
2398 }
2399
2400 static HRESULT WINAPI ISVDropTarget_DragLeave(IDropTarget *iface) {
2401     IShellViewImpl *This = impl_from_IDropTarget(iface);
2402
2403     IDropTarget_DragLeave(This->pCurDropTarget);
2404
2405     IDropTarget_Release(This->pCurDropTarget);
2406     IDataObject_Release(This->pCurDataObject);
2407     This->pCurDataObject = NULL;
2408     This->pCurDropTarget = NULL;
2409     This->iDragOverItem = 0;
2410      
2411     return S_OK;
2412 }
2413
2414 static HRESULT WINAPI ISVDropTarget_Drop(IDropTarget *iface, IDataObject* pDataObject, 
2415     DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2416 {
2417     IShellViewImpl *This = impl_from_IDropTarget(iface);
2418
2419     IDropTarget_Drop(This->pCurDropTarget, pDataObject, grfKeyState, pt, pdwEffect);
2420
2421     IDropTarget_Release(This->pCurDropTarget);
2422     IDataObject_Release(This->pCurDataObject);
2423     This->pCurDataObject = NULL;
2424     This->pCurDropTarget = NULL;
2425     This->iDragOverItem = 0;
2426
2427     return S_OK;
2428 }
2429
2430 static const IDropTargetVtbl dtvt =
2431 {
2432         ISVDropTarget_QueryInterface,
2433         ISVDropTarget_AddRef,
2434         ISVDropTarget_Release,
2435         ISVDropTarget_DragEnter,
2436         ISVDropTarget_DragOver,
2437         ISVDropTarget_DragLeave,
2438         ISVDropTarget_Drop
2439 };
2440
2441 /**********************************************************
2442  * ISVDropSource implementation
2443  */
2444
2445 static HRESULT WINAPI ISVDropSource_QueryInterface(
2446         IDropSource *iface,
2447         REFIID riid,
2448         LPVOID *ppvObj)
2449 {
2450         IShellViewImpl *This = impl_from_IDropSource(iface);
2451
2452         TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
2453
2454         return IShellFolder_QueryInterface((IShellFolder*)This, riid, ppvObj);
2455 }
2456
2457 static ULONG WINAPI ISVDropSource_AddRef( IDropSource *iface)
2458 {
2459         IShellViewImpl *This = impl_from_IDropSource(iface);
2460
2461         TRACE("(%p)->(count=%u)\n",This,This->ref);
2462
2463         return IShellFolder_AddRef((IShellFolder*)This);
2464 }
2465
2466 static ULONG WINAPI ISVDropSource_Release( IDropSource *iface)
2467 {
2468         IShellViewImpl *This = impl_from_IDropSource(iface);
2469
2470         TRACE("(%p)->(count=%u)\n",This,This->ref);
2471
2472         return IShellFolder_Release((IShellFolder*)This);
2473 }
2474 static HRESULT WINAPI ISVDropSource_QueryContinueDrag(
2475         IDropSource *iface,
2476         BOOL fEscapePressed,
2477         DWORD grfKeyState)
2478 {
2479         IShellViewImpl *This = impl_from_IDropSource(iface);
2480         TRACE("(%p)\n",This);
2481
2482         if (fEscapePressed)
2483           return DRAGDROP_S_CANCEL;
2484         else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON))
2485           return DRAGDROP_S_DROP;
2486         else
2487           return NOERROR;
2488 }
2489
2490 static HRESULT WINAPI ISVDropSource_GiveFeedback(
2491         IDropSource *iface,
2492         DWORD dwEffect)
2493 {
2494         IShellViewImpl *This = impl_from_IDropSource(iface);
2495         TRACE("(%p)\n",This);
2496
2497         return DRAGDROP_S_USEDEFAULTCURSORS;
2498 }
2499
2500 static const IDropSourceVtbl dsvt =
2501 {
2502         ISVDropSource_QueryInterface,
2503         ISVDropSource_AddRef,
2504         ISVDropSource_Release,
2505         ISVDropSource_QueryContinueDrag,
2506         ISVDropSource_GiveFeedback
2507 };
2508 /**********************************************************
2509  * ISVViewObject implementation
2510  */
2511
2512 static HRESULT WINAPI ISVViewObject_QueryInterface(
2513         IViewObject *iface,
2514         REFIID riid,
2515         LPVOID *ppvObj)
2516 {
2517         IShellViewImpl *This = impl_from_IViewObject(iface);
2518
2519         TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
2520
2521         return IShellFolder_QueryInterface((IShellFolder*)This, riid, ppvObj);
2522 }
2523
2524 static ULONG WINAPI ISVViewObject_AddRef( IViewObject *iface)
2525 {
2526         IShellViewImpl *This = impl_from_IViewObject(iface);
2527
2528         TRACE("(%p)->(count=%u)\n",This,This->ref);
2529
2530         return IShellFolder_AddRef((IShellFolder*)This);
2531 }
2532
2533 static ULONG WINAPI ISVViewObject_Release( IViewObject *iface)
2534 {
2535         IShellViewImpl *This = impl_from_IViewObject(iface);
2536
2537         TRACE("(%p)->(count=%u)\n",This,This->ref);
2538
2539         return IShellFolder_Release((IShellFolder*)This);
2540 }
2541
2542 static HRESULT WINAPI ISVViewObject_Draw(
2543         IViewObject     *iface,
2544         DWORD dwDrawAspect,
2545         LONG lindex,
2546         void* pvAspect,
2547         DVTARGETDEVICE* ptd,
2548         HDC hdcTargetDev,
2549         HDC hdcDraw,
2550         LPCRECTL lprcBounds,
2551         LPCRECTL lprcWBounds,
2552         BOOL (CALLBACK *pfnContinue)(ULONG_PTR dwContinue),
2553         ULONG_PTR dwContinue)
2554 {
2555
2556         IShellViewImpl *This = impl_from_IViewObject(iface);
2557
2558         FIXME("Stub: This=%p\n",This);
2559
2560         return E_NOTIMPL;
2561 }
2562 static HRESULT WINAPI ISVViewObject_GetColorSet(
2563         IViewObject     *iface,
2564         DWORD dwDrawAspect,
2565         LONG lindex,
2566         void *pvAspect,
2567         DVTARGETDEVICE* ptd,
2568         HDC hicTargetDevice,
2569         LOGPALETTE** ppColorSet)
2570 {
2571
2572         IShellViewImpl *This = impl_from_IViewObject(iface);
2573
2574         FIXME("Stub: This=%p\n",This);
2575
2576         return E_NOTIMPL;
2577 }
2578 static HRESULT WINAPI ISVViewObject_Freeze(
2579         IViewObject     *iface,
2580         DWORD dwDrawAspect,
2581         LONG lindex,
2582         void* pvAspect,
2583         DWORD* pdwFreeze)
2584 {
2585
2586         IShellViewImpl *This = impl_from_IViewObject(iface);
2587
2588         FIXME("Stub: This=%p\n",This);
2589
2590         return E_NOTIMPL;
2591 }
2592 static HRESULT WINAPI ISVViewObject_Unfreeze(
2593         IViewObject     *iface,
2594         DWORD dwFreeze)
2595 {
2596
2597         IShellViewImpl *This = impl_from_IViewObject(iface);
2598
2599         FIXME("Stub: This=%p\n",This);
2600
2601         return E_NOTIMPL;
2602 }
2603 static HRESULT WINAPI ISVViewObject_SetAdvise(
2604         IViewObject     *iface,
2605         DWORD aspects,
2606         DWORD advf,
2607         IAdviseSink* pAdvSink)
2608 {
2609
2610         IShellViewImpl *This = impl_from_IViewObject(iface);
2611
2612         FIXME("partial stub: %p %08x %08x %p\n",
2613               This, aspects, advf, pAdvSink);
2614
2615         /* FIXME: we set the AdviseSink, but never use it to send any advice */
2616         This->pAdvSink = pAdvSink;
2617         This->dwAspects = aspects;
2618         This->dwAdvf = advf;
2619
2620         return S_OK;
2621 }
2622
2623 static HRESULT WINAPI ISVViewObject_GetAdvise(
2624         IViewObject     *iface,
2625         DWORD* pAspects,
2626         DWORD* pAdvf,
2627         IAdviseSink** ppAdvSink)
2628 {
2629
2630         IShellViewImpl *This = impl_from_IViewObject(iface);
2631
2632         TRACE("This=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n",
2633               This, pAspects, pAdvf, ppAdvSink);
2634
2635         if( ppAdvSink )
2636         {
2637                 IAdviseSink_AddRef( This->pAdvSink );
2638                 *ppAdvSink = This->pAdvSink;
2639         }
2640         if( pAspects )
2641                 *pAspects = This->dwAspects;
2642         if( pAdvf )
2643                 *pAdvf = This->dwAdvf;
2644
2645         return S_OK;
2646 }
2647
2648
2649 static const IViewObjectVtbl vovt =
2650 {
2651         ISVViewObject_QueryInterface,
2652         ISVViewObject_AddRef,
2653         ISVViewObject_Release,
2654         ISVViewObject_Draw,
2655         ISVViewObject_GetColorSet,
2656         ISVViewObject_Freeze,
2657         ISVViewObject_Unfreeze,
2658         ISVViewObject_SetAdvise,
2659         ISVViewObject_GetAdvise
2660 };