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