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