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