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