ff05864eb80feda0f43f20da56a67e4ec0d2631f
[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 case CWM_GETISHELLBROWSER:
1857 return (LRESULT)pThis->pShellBrowser;
1858 }
1859 return DefWindowProcW(hWnd, uMessage, wParam, lParam);
1860 }
1861 /**********************************************************
1862 *
1863 *
1864 * The INTERFACE of the IShellView object
1865 *
1866 *
1867 **********************************************************
1868 * IShellView_QueryInterface
1869 */
1870 static HRESULT WINAPI IShellView_fnQueryInterface(IShellView * iface,REFIID riid, LPVOID *ppvObj)
1871 {
1872 IShellViewImpl *This = (IShellViewImpl *)iface;
1873
1874 TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
1875
1876 *ppvObj = NULL;
1877
1878 if(IsEqualIID(riid, &IID_IUnknown))
1879 {
1880 *ppvObj = This;
1881 }
1882 else if(IsEqualIID(riid, &IID_IShellView))
1883 {
1884 *ppvObj = (IShellView*)This;
1885 }
1886 else if(IsEqualIID(riid, &IID_IOleCommandTarget))
1887 {
1888 *ppvObj = (IOleCommandTarget*)&(This->lpvtblOleCommandTarget);
1889 }
1890 else if(IsEqualIID(riid, &IID_IDropTarget))
1891 {
1892 *ppvObj = (IDropTarget*)&(This->lpvtblDropTarget);
1893 }
1894 else if(IsEqualIID(riid, &IID_IDropSource))
1895 {
1896 *ppvObj = (IDropSource*)&(This->lpvtblDropSource);
1897 }
1898 else if(IsEqualIID(riid, &IID_IViewObject))
1899 {
1900 *ppvObj = (IViewObject*)&(This->lpvtblViewObject);
1901 }
1902
1903 if(*ppvObj)
1904 {
1905 IUnknown_AddRef( (IUnknown*)*ppvObj );
1906 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
1907 return S_OK;
1908 }
1909 TRACE("-- Interface: E_NOINTERFACE\n");
1910 return E_NOINTERFACE;
1911 }
1912
1913 /**********************************************************
1914 * IShellView_AddRef
1915 */
1916 static ULONG WINAPI IShellView_fnAddRef(IShellView * iface)
1917 {
1918 IShellViewImpl *This = (IShellViewImpl *)iface;
1919 ULONG refCount = InterlockedIncrement(&This->ref);
1920
1921 TRACE("(%p)->(count=%u)\n", This, refCount - 1);
1922
1923 return refCount;
1924 }
1925 /**********************************************************
1926 * IShellView_Release
1927 */
1928 static ULONG WINAPI IShellView_fnRelease(IShellView * iface)
1929 {
1930 IShellViewImpl *This = (IShellViewImpl *)iface;
1931 ULONG refCount = InterlockedDecrement(&This->ref);
1932
1933 TRACE("(%p)->(count=%i)\n", This, refCount + 1);
1934
1935 if (!refCount)
1936 {
1937 TRACE(" destroying IShellView(%p)\n",This);
1938
1939 DestroyWindow(This->hWndList);
1940
1941 if(This->pSFParent)
1942 IShellFolder_Release(This->pSFParent);
1943
1944 if(This->pSF2Parent)
1945 IShellFolder2_Release(This->pSF2Parent);
1946
1947 SHFree(This->apidl);
1948
1949 if(This->pAdvSink)
1950 IAdviseSink_Release(This->pAdvSink);
1951
1952 if (This->pCM)
1953 IContextMenu_Release(This->pCM);
1954
1955 HeapFree(GetProcessHeap(),0,This);
1956 }
1957 return refCount;
1958 }
1959
1960 /**********************************************************
1961 * ShellView_GetWindow
1962 */
1963 static HRESULT WINAPI IShellView_fnGetWindow(IShellView * iface,HWND * phWnd)
1964 {
1965 IShellViewImpl *This = (IShellViewImpl *)iface;
1966
1967 TRACE("(%p)\n",This);
1968
1969 *phWnd = This->hWnd;
1970
1971 return S_OK;
1972 }
1973
1974 static HRESULT WINAPI IShellView_fnContextSensitiveHelp(IShellView * iface,BOOL fEnterMode)
1975 {
1976 IShellViewImpl *This = (IShellViewImpl *)iface;
1977
1978 FIXME("(%p) stub\n",This);
1979
1980 return E_NOTIMPL;
1981 }
1982
1983 /**********************************************************
1984 * IShellView_TranslateAccelerator
1985 *
1986 * FIXME:
1987 * use the accel functions
1988 */
1989 static HRESULT WINAPI IShellView_fnTranslateAccelerator(IShellView * iface,LPMSG lpmsg)
1990 {
1991 #if 0
1992 IShellViewImpl *This = (IShellViewImpl *)iface;
1993
1994 FIXME("(%p)->(%p: hwnd=%x msg=%x lp=%x wp=%x) stub\n",This,lpmsg, lpmsg->hwnd, lpmsg->message, lpmsg->lParam, lpmsg->wParam);
1995 #endif
1996
1997 if ((lpmsg->message>=WM_KEYFIRST) && (lpmsg->message>=WM_KEYLAST))
1998 {
1999 TRACE("-- key=0x04%lx\n",lpmsg->wParam) ;
2000 }
2001 return S_FALSE; /* not handled */
2002 }
2003
2004 static HRESULT WINAPI IShellView_fnEnableModeless(IShellView * iface,BOOL fEnable)
2005 {
2006 IShellViewImpl *This = (IShellViewImpl *)iface;
2007
2008 FIXME("(%p) stub\n",This);
2009
2010 return E_NOTIMPL;
2011 }
2012
2013 static HRESULT WINAPI IShellView_fnUIActivate(IShellView * iface,UINT uState)
2014 {
2015 IShellViewImpl *This = (IShellViewImpl *)iface;
2016
2017 /*
2018 CHAR szName[MAX_PATH];
2019 */
2020 LRESULT lResult;
2021 int nPartArray[1] = {-1};
2022
2023 TRACE("(%p)->(state=%x) stub\n",This, uState);
2024
2025 /*don't do anything if the state isn't really changing*/
2026 if(This->uState == uState)
2027 {
2028 return S_OK;
2029 }
2030
2031 /*OnActivate handles the menu merging and internal state*/
2032 ShellView_OnActivate(This, uState);
2033
2034 /*only do This if we are active*/
2035 if(uState != SVUIA_DEACTIVATE)
2036 {
2037
2038 /*
2039 GetFolderPath is not a method of IShellFolder
2040 IShellFolder_GetFolderPath( This->pSFParent, szName, sizeof(szName) );
2041 */
2042 /* set the number of parts */
2043 IShellBrowser_SendControlMsg(This->pShellBrowser, FCW_STATUS, SB_SETPARTS, 1,
2044 (LPARAM)nPartArray, &lResult);
2045
2046 /* set the text for the parts */
2047 /*
2048 IShellBrowser_SendControlMsg(This->pShellBrowser, FCW_STATUS, SB_SETTEXTA,
2049 0, (LPARAM)szName, &lResult);
2050 */
2051 }
2052
2053 return S_OK;
2054 }
2055
2056 static HRESULT WINAPI IShellView_fnRefresh(IShellView * iface)
2057 {
2058 IShellViewImpl *This = (IShellViewImpl *)iface;
2059
2060 TRACE("(%p)\n",This);
2061
2062 SendMessageW(This->hWndList, LVM_DELETEALLITEMS, 0, 0);
2063 ShellView_FillList(This);
2064
2065 return S_OK;
2066 }
2067
2068 static HRESULT WINAPI IShellView_fnCreateViewWindow(
2069 IShellView * iface,
2070 IShellView *lpPrevView,
2071 LPCFOLDERSETTINGS lpfs,
2072 IShellBrowser * psb,
2073 RECT * prcView,
2074 HWND *phWnd)
2075 {
2076 IShellViewImpl *This = (IShellViewImpl *)iface;
2077
2078 WNDCLASSW wc;
2079 *phWnd = 0;
2080
2081
2082 TRACE("(%p)->(shlview=%p set=%p shlbrs=%p rec=%p hwnd=%p) incomplete\n",This, lpPrevView,lpfs, psb, prcView, phWnd);
2083 if (lpfs != NULL)
2084 TRACE("-- vmode=%x flags=%x\n", lpfs->ViewMode, lpfs->fFlags);
2085 if (prcView != NULL)
2086 TRACE("-- left=%i top=%i right=%i bottom=%i\n", prcView->left, prcView->top, prcView->right, prcView->bottom);
2087
2088 /* Validate the Shell Browser */
2089 if (psb == NULL)
2090 return E_UNEXPECTED;
2091
2092 /*set up the member variables*/
2093 This->pShellBrowser = psb;
2094 This->FolderSettings = *lpfs;
2095
2096 /*get our parent window*/
2097 IShellBrowser_AddRef(This->pShellBrowser);
2098 IShellBrowser_GetWindow(This->pShellBrowser, &(This->hWndParent));
2099
2100 /* try to get the ICommDlgBrowserInterface, adds a reference !!! */
2101 This->pCommDlgBrowser=NULL;
2102 if ( SUCCEEDED (IShellBrowser_QueryInterface( This->pShellBrowser,
2103 (REFIID)&IID_ICommDlgBrowser, (LPVOID*) &This->pCommDlgBrowser)))
2104 {
2105 TRACE("-- CommDlgBrowser\n");
2106 }
2107
2108 /*if our window class has not been registered, then do so*/
2109 if(!GetClassInfoW(shell32_hInstance, SV_CLASS_NAME, &wc))
2110 {
2111 ZeroMemory(&wc, sizeof(wc));
2112 wc.style = CS_HREDRAW | CS_VREDRAW;
2113 wc.lpfnWndProc = ShellView_WndProc;
2114 wc.cbClsExtra = 0;
2115 wc.cbWndExtra = 0;
2116 wc.hInstance = shell32_hInstance;
2117 wc.hIcon = 0;
2118 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
2119 wc.hbrBackground = (HBRUSH) (COLOR_BACKGROUND+1);
2120 wc.lpszMenuName = NULL;
2121 wc.lpszClassName = SV_CLASS_NAME;
2122
2123 if(!RegisterClassW(&wc))
2124 return E_FAIL;
2125 }
2126
2127 *phWnd = CreateWindowExW(0,
2128 SV_CLASS_NAME,
2129 NULL,
2130 WS_CHILD | WS_TABSTOP,
2131 prcView->left,
2132 prcView->top,
2133 prcView->right - prcView->left,
2134 prcView->bottom - prcView->top,
2135 This->hWndParent,
2136 0,
2137 shell32_hInstance,
2138 (LPVOID)This);
2139
2140 CheckToolbar(This);
2141
2142 if(!*phWnd) return E_FAIL;
2143
2144 SetWindowPos(*phWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
2145 UpdateWindow(*phWnd);
2146
2147 return S_OK;
2148 }
2149
2150 static HRESULT WINAPI IShellView_fnDestroyViewWindow(IShellView * iface)
2151 {
2152 IShellViewImpl *This = (IShellViewImpl *)iface;
2153
2154 TRACE("(%p)\n",This);
2155
2156 /*Make absolutely sure all our UI is cleaned up.*/
2157 IShellView_UIActivate((IShellView*)This, SVUIA_DEACTIVATE);
2158
2159 if(This->hMenu)
2160 {
2161 DestroyMenu(This->hMenu);
2162 }
2163
2164 DestroyWindow(This->hWnd);
2165 if(This->pShellBrowser) IShellBrowser_Release(This->pShellBrowser);
2166 if(This->pCommDlgBrowser) ICommDlgBrowser_Release(This->pCommDlgBrowser);
2167
2168
2169 return S_OK;
2170 }
2171
2172 static HRESULT WINAPI IShellView_fnGetCurrentInfo(IShellView * iface, LPFOLDERSETTINGS lpfs)
2173 {
2174 IShellViewImpl *This = (IShellViewImpl *)iface;
2175
2176 TRACE("(%p)->(%p) vmode=%x flags=%x\n",This, lpfs,
2177 This->FolderSettings.ViewMode, This->FolderSettings.fFlags);
2178
2179 if (!lpfs) return E_INVALIDARG;
2180
2181 *lpfs = This->FolderSettings;
2182 return NOERROR;
2183 }
2184
2185 static HRESULT WINAPI IShellView_fnAddPropertySheetPages(IShellView * iface, DWORD dwReserved,LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam)
2186 {
2187 IShellViewImpl *This = (IShellViewImpl *)iface;
2188
2189 FIXME("(%p) stub\n",This);
2190
2191 return E_NOTIMPL;
2192 }
2193
2194 static HRESULT WINAPI IShellView_fnSaveViewState(IShellView * iface)
2195 {
2196 IShellViewImpl *This = (IShellViewImpl *)iface;
2197
2198 FIXME("(%p) stub\n",This);
2199
2200 return S_OK;
2201 }
2202
2203 static HRESULT WINAPI IShellView_fnSelectItem(
2204 IShellView * iface,
2205 LPCITEMIDLIST pidl,
2206 UINT uFlags)
2207 {
2208 IShellViewImpl *This = (IShellViewImpl *)iface;
2209 int i;
2210
2211 TRACE("(%p)->(pidl=%p, 0x%08x) stub\n",This, pidl, uFlags);
2212
2213 i = LV_FindItemByPidl(This, pidl);
2214
2215 if (i != -1)
2216 {
2217 LVITEMW lvItem;
2218
2219 if(uFlags & SVSI_ENSUREVISIBLE)
2220 SendMessageW(This->hWndList, LVM_ENSUREVISIBLE, i, 0);
2221
2222 lvItem.mask = LVIF_STATE;
2223 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
2224 lvItem.iItem = 0;
2225 lvItem.iSubItem = 0;
2226
2227 while(SendMessageW(This->hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem))
2228 {
2229 if (lvItem.iItem == i)
2230 {
2231 if (uFlags & SVSI_SELECT)
2232 lvItem.state |= LVIS_SELECTED;
2233 else
2234 lvItem.state &= ~LVIS_SELECTED;
2235
2236 if(uFlags & SVSI_FOCUSED)
2237 lvItem.state &= ~LVIS_FOCUSED;
2238 }
2239 else
2240 {
2241 if (uFlags & SVSI_DESELECTOTHERS)
2242 lvItem.state &= ~LVIS_SELECTED;
2243 }
2244 SendMessageW(This->hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
2245 lvItem.iItem++;
2246 }
2247
2248
2249 if(uFlags & SVSI_EDIT)
2250 SendMessageW(This->hWndList, LVM_EDITLABELW, i, 0);
2251
2252 }
2253 return S_OK;
2254 }
2255
2256 static HRESULT WINAPI IShellView_fnGetItemObject(IShellView * iface, UINT uItem, REFIID riid, LPVOID *ppvOut)
2257 {
2258 HRESULT hr = E_FAIL;
2259 IShellViewImpl *This = (IShellViewImpl *)iface;
2260
2261 TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n",This, uItem, debugstr_guid(riid), ppvOut);
2262
2263 *ppvOut = NULL;
2264
2265 switch(uItem)
2266 {
2267 case SVGIO_BACKGROUND:
2268 //*ppvOut = ISvBgCm_Constructor(This->pSFParent, FALSE);
2269 CDefFolderMenu_Create2(NULL, NULL, This->cidl, (LPCITEMIDLIST*)This->apidl, This->pSFParent, NULL, 0, NULL, (IContextMenu**)ppvOut);
2270 if (!ppvOut) hr = E_OUTOFMEMORY;
2271 break;
2272
2273 case SVGIO_SELECTION:
2274 ShellView_GetSelections(This);
2275 hr = IShellFolder_GetUIObjectOf(This->pSFParent, This->hWnd, This->cidl, (LPCITEMIDLIST*)This->apidl, riid, 0, ppvOut);
2276 break;
2277 }
2278 TRACE("-- (%p)->(interface=%p)\n",This, *ppvOut);
2279
2280 return hr;
2281 }
2282
2283 static const IShellViewVtbl svvt =
2284 {
2285 IShellView_fnQueryInterface,
2286 IShellView_fnAddRef,
2287 IShellView_fnRelease,
2288 IShellView_fnGetWindow,
2289 IShellView_fnContextSensitiveHelp,
2290 IShellView_fnTranslateAccelerator,
2291 IShellView_fnEnableModeless,
2292 IShellView_fnUIActivate,
2293 IShellView_fnRefresh,
2294 IShellView_fnCreateViewWindow,
2295 IShellView_fnDestroyViewWindow,
2296 IShellView_fnGetCurrentInfo,
2297 IShellView_fnAddPropertySheetPages,
2298 IShellView_fnSaveViewState,
2299 IShellView_fnSelectItem,
2300 IShellView_fnGetItemObject
2301 };
2302
2303
2304 /**********************************************************
2305 * ISVOleCmdTarget_QueryInterface (IUnknown)
2306 */
2307 static HRESULT WINAPI ISVOleCmdTarget_QueryInterface(
2308 IOleCommandTarget * iface,
2309 REFIID iid,
2310 LPVOID* ppvObj)
2311 {
2312 IShellViewImpl *This = impl_from_IOleCommandTarget(iface);
2313
2314 return IShellFolder_QueryInterface((IShellFolder*)This, iid, ppvObj);
2315 }
2316
2317 /**********************************************************
2318 * ISVOleCmdTarget_AddRef (IUnknown)
2319 */
2320 static ULONG WINAPI ISVOleCmdTarget_AddRef(
2321 IOleCommandTarget * iface)
2322 {
2323 IShellViewImpl *This = impl_from_IOleCommandTarget(iface);
2324
2325 return IShellFolder_AddRef((IShellFolder*)This);
2326 }
2327
2328 /**********************************************************
2329 * ISVOleCmdTarget_Release (IUnknown)
2330 */
2331 static ULONG WINAPI ISVOleCmdTarget_Release(
2332 IOleCommandTarget * iface)
2333 {
2334 IShellViewImpl *This = impl_from_IOleCommandTarget(iface);
2335
2336 return IShellFolder_Release((IShellFolder*)This);
2337 }
2338
2339 /**********************************************************
2340 * ISVOleCmdTarget_QueryStatus (IOleCommandTarget)
2341 */
2342 static HRESULT WINAPI ISVOleCmdTarget_QueryStatus(
2343 IOleCommandTarget *iface,
2344 const GUID* pguidCmdGroup,
2345 ULONG cCmds,
2346 OLECMD * prgCmds,
2347 OLECMDTEXT* pCmdText)
2348 {
2349 UINT i;
2350 IShellViewImpl *This = impl_from_IOleCommandTarget(iface);
2351
2352 FIXME("(%p)->(%p(%s) 0x%08x %p %p\n",
2353 This, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
2354
2355 if (!prgCmds)
2356 return E_POINTER;
2357 for (i = 0; i < cCmds; i++)
2358 {
2359 FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID);
2360 prgCmds[i].cmdf = 0;
2361 }
2362 return OLECMDERR_E_UNKNOWNGROUP;
2363 }
2364
2365 /**********************************************************
2366 * ISVOleCmdTarget_Exec (IOleCommandTarget)
2367 *
2368 * nCmdID is the OLECMDID_* enumeration
2369 */
2370 static HRESULT WINAPI ISVOleCmdTarget_Exec(
2371 IOleCommandTarget *iface,
2372 const GUID* pguidCmdGroup,
2373 DWORD nCmdID,
2374 DWORD nCmdexecopt,
2375 VARIANT* pvaIn,
2376 VARIANT* pvaOut)
2377 {
2378 IShellViewImpl *This = impl_from_IOleCommandTarget(iface);
2379
2380 FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n",
2381 This, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut);
2382
2383 if (IsEqualIID(pguidCmdGroup, &CGID_Explorer) &&
2384 (nCmdID == 0x29) &&
2385 (nCmdexecopt == 4) && pvaOut)
2386 return S_OK;
2387 if (IsEqualIID(pguidCmdGroup, &CGID_ShellDocView) &&
2388 (nCmdID == 9) &&
2389 (nCmdexecopt == 0))
2390 return 1;
2391
2392 return OLECMDERR_E_UNKNOWNGROUP;
2393 }
2394
2395 static const IOleCommandTargetVtbl ctvt =
2396 {
2397 ISVOleCmdTarget_QueryInterface,
2398 ISVOleCmdTarget_AddRef,
2399 ISVOleCmdTarget_Release,
2400 ISVOleCmdTarget_QueryStatus,
2401 ISVOleCmdTarget_Exec
2402 };
2403
2404 /**********************************************************
2405 * ISVDropTarget implementation
2406 */
2407
2408 static HRESULT WINAPI ISVDropTarget_QueryInterface(
2409 IDropTarget *iface,
2410 REFIID riid,
2411 LPVOID *ppvObj)
2412 {
2413 IShellViewImpl *This = impl_from_IDropTarget(iface);
2414
2415 TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
2416
2417 return IShellFolder_QueryInterface((IShellFolder*)This, riid, ppvObj);
2418 }
2419
2420 static ULONG WINAPI ISVDropTarget_AddRef( IDropTarget *iface)
2421 {
2422 IShellViewImpl *This = impl_from_IDropTarget(iface);
2423
2424 TRACE("(%p)->(count=%u)\n",This,This->ref);
2425
2426 return IShellFolder_AddRef((IShellFolder*)This);
2427 }
2428
2429 static ULONG WINAPI ISVDropTarget_Release( IDropTarget *iface)
2430 {
2431 IShellViewImpl *This = impl_from_IDropTarget(iface);
2432
2433 TRACE("(%p)->(count=%u)\n",This,This->ref);
2434
2435 return IShellFolder_Release((IShellFolder*)This);
2436 }
2437
2438 /******************************************************************************
2439 * drag_notify_subitem [Internal]
2440 *
2441 * Figure out the shellfolder object, which is currently under the mouse cursor
2442 * and notify it via the IDropTarget interface.
2443 */
2444
2445 #define SCROLLAREAWIDTH 20
2446
2447 static HRESULT drag_notify_subitem(IShellViewImpl *This, DWORD grfKeyState, POINTL pt,
2448 DWORD *pdwEffect)
2449 {
2450 LVHITTESTINFO htinfo;
2451 LVITEMW lvItem;
2452 LONG lResult;
2453 HRESULT hr;
2454 RECT clientRect;
2455
2456 /* Map from global to client coordinates and query the index of the listview-item, which is
2457 * currently under the mouse cursor. */
2458 htinfo.pt.x = pt.x;
2459 htinfo.pt.y = pt.y;
2460 htinfo.flags = LVHT_ONITEM;
2461 ScreenToClient(This->hWndList, &htinfo.pt);
2462 lResult = SendMessageW(This->hWndList, LVM_HITTEST, 0, (LPARAM)&htinfo);
2463
2464 /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */
2465 GetClientRect(This->hWndList, &clientRect);
2466 if (htinfo.pt.x == This->ptLastMousePos.x && htinfo.pt.y == This->ptLastMousePos.y &&
2467 (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH ||
2468 htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH ))
2469 {
2470 This->cScrollDelay = (This->cScrollDelay + 1) % 5; /* DragOver is called every 50 ms */
2471 if (This->cScrollDelay == 0) { /* Mouse did hover another 250 ms over the scroll-area */
2472 if (htinfo.pt.x < SCROLLAREAWIDTH)
2473 SendMessageW(This->hWndList, WM_HSCROLL, SB_LINEUP, 0);
2474 if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH)
2475 SendMessageW(This->hWndList, WM_HSCROLL, SB_LINEDOWN, 0);
2476 if (htinfo.pt.y < SCROLLAREAWIDTH)
2477 SendMessageW(This->hWndList, WM_VSCROLL, SB_LINEUP, 0);
2478 if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH)
2479 SendMessageW(This->hWndList, WM_VSCROLL, SB_LINEDOWN, 0);
2480 }
2481 } else {
2482 This->cScrollDelay = 0; /* Reset, if the cursor is not over the listview's scroll-area */
2483 }
2484 This->ptLastMousePos = htinfo.pt;
2485
2486 /* If we are still over the previous sub-item, notify it via DragOver and return. */
2487 if (This->pCurDropTarget && lResult == This->iDragOverItem)
2488 return IDropTarget_DragOver(This->pCurDropTarget, grfKeyState, pt, pdwEffect);
2489
2490 /* We've left the previous sub-item, notify it via DragLeave and Release it. */
2491 if (This->pCurDropTarget) {
2492 IDropTarget_DragLeave(This->pCurDropTarget);
2493 IDropTarget_Release(This->pCurDropTarget);
2494 This->pCurDropTarget = NULL;
2495 }
2496
2497 This->iDragOverItem = lResult;
2498 if (lResult == -1) {
2499 /* We are not above one of the listview's subitems. Bind to the parent folder's
2500 * DropTarget interface. */
2501 hr = IShellFolder_QueryInterface(This->pSFParent, &IID_IDropTarget,
2502 (LPVOID*)&This->pCurDropTarget);
2503 } else {
2504 /* Query the relative PIDL of the shellfolder object represented by the currently
2505 * dragged over listview-item ... */
2506 lvItem.mask = LVIF_PARAM;
2507 lvItem.iItem = lResult;
2508 lvItem.iSubItem = 0;
2509 SendMessageW(This->hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
2510
2511 /* ... and bind pCurDropTarget to the IDropTarget interface of an UIObject of this object */
2512 hr = IShellFolder_GetUIObjectOf(This->pSFParent, This->hWndList, 1,
2513 (LPCITEMIDLIST*)&lvItem.lParam, &IID_IDropTarget, NULL, (LPVOID*)&This->pCurDropTarget);
2514 }
2515
2516 /* If anything failed, pCurDropTarget should be NULL now, which ought to be a save state. */
2517 if (FAILED(hr))
2518 return hr;
2519
2520 /* Notify the item just entered via DragEnter. */
2521 return IDropTarget_DragEnter(This->pCurDropTarget, This->pCurDataObject, grfKeyState, pt, pdwEffect);
2522 }
2523
2524 static HRESULT WINAPI ISVDropTarget_DragEnter(IDropTarget *iface, IDataObject *pDataObject,
2525 DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2526 {
2527 IShellViewImpl *This = impl_from_IDropTarget(iface);
2528
2529 /* Get a hold on the data object for later calls to DragEnter on the sub-folders */
2530 This->pCurDataObject = pDataObject;
2531 IDataObject_AddRef(pDataObject);
2532
2533 return drag_notify_subitem(This, grfKeyState, pt, pdwEffect);
2534 }
2535
2536 static HRESULT WINAPI ISVDropTarget_DragOver(IDropTarget *iface, DWORD grfKeyState, POINTL pt,
2537 DWORD *pdwEffect)
2538 {
2539 IShellViewImpl *This = impl_from_IDropTarget(iface);
2540 return drag_notify_subitem(This, grfKeyState, pt, pdwEffect);
2541 }
2542
2543 static HRESULT WINAPI ISVDropTarget_DragLeave(IDropTarget *iface) {
2544 IShellViewImpl *This = impl_from_IDropTarget(iface);
2545
2546 if (This->pCurDropTarget)
2547 {
2548 IDropTarget_DragLeave(This->pCurDropTarget);
2549 IDropTarget_Release(This->pCurDropTarget);
2550 This->pCurDropTarget = NULL;
2551 }
2552
2553 if (This->pCurDataObject != NULL)
2554 {
2555 IDataObject_Release(This->pCurDataObject);
2556 This->pCurDataObject = NULL;
2557 }
2558
2559 This->iDragOverItem = 0;
2560
2561 return S_OK;
2562 }
2563
2564 static HRESULT WINAPI ISVDropTarget_Drop(IDropTarget *iface, IDataObject* pDataObject,
2565 DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
2566 {
2567 IShellViewImpl *This = impl_from_IDropTarget(iface);
2568
2569 if (This->pCurDropTarget)
2570 {
2571 IDropTarget_Drop(This->pCurDropTarget, pDataObject, grfKeyState, pt, pdwEffect);
2572 IDropTarget_Release(This->pCurDropTarget);
2573 This->pCurDropTarget = NULL;
2574 }
2575
2576 if (This->pCurDataObject != NULL)
2577 {
2578 IDataObject_Release(This->pCurDataObject);
2579 This->pCurDataObject = NULL;
2580 }
2581
2582 This->iDragOverItem = 0;
2583
2584 return S_OK;
2585 }
2586
2587 static const IDropTargetVtbl dtvt =
2588 {
2589 ISVDropTarget_QueryInterface,
2590 ISVDropTarget_AddRef,
2591 ISVDropTarget_Release,
2592 ISVDropTarget_DragEnter,
2593 ISVDropTarget_DragOver,
2594 ISVDropTarget_DragLeave,
2595 ISVDropTarget_Drop
2596 };
2597
2598 /**********************************************************
2599 * ISVDropSource implementation
2600 */
2601
2602 static HRESULT WINAPI ISVDropSource_QueryInterface(
2603 IDropSource *iface,
2604 REFIID riid,
2605 LPVOID *ppvObj)
2606 {
2607 IShellViewImpl *This = impl_from_IDropSource(iface);
2608
2609 TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
2610
2611 return IShellFolder_QueryInterface((IShellFolder*)This, riid, ppvObj);
2612 }
2613
2614 static ULONG WINAPI ISVDropSource_AddRef( IDropSource *iface)
2615 {
2616 IShellViewImpl *This = impl_from_IDropSource(iface);
2617
2618 TRACE("(%p)->(count=%u)\n",This,This->ref);
2619
2620 return IShellFolder_AddRef((IShellFolder*)This);
2621 }
2622
2623 static ULONG WINAPI ISVDropSource_Release( IDropSource *iface)
2624 {
2625 IShellViewImpl *This = impl_from_IDropSource(iface);
2626
2627 TRACE("(%p)->(count=%u)\n",This,This->ref);
2628
2629 return IShellFolder_Release((IShellFolder*)This);
2630 }
2631 static HRESULT WINAPI ISVDropSource_QueryContinueDrag(
2632 IDropSource *iface,
2633 BOOL fEscapePressed,
2634 DWORD grfKeyState)
2635 {
2636 IShellViewImpl *This = impl_from_IDropSource(iface);
2637 TRACE("(%p)\n",This);
2638
2639 if (fEscapePressed)
2640 return DRAGDROP_S_CANCEL;
2641 else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON))
2642 return DRAGDROP_S_DROP;
2643 else
2644 return NOERROR;
2645 }
2646
2647 static HRESULT WINAPI ISVDropSource_GiveFeedback(
2648 IDropSource *iface,
2649 DWORD dwEffect)
2650 {
2651 IShellViewImpl *This = impl_from_IDropSource(iface);
2652 TRACE("(%p)\n",This);
2653
2654 return DRAGDROP_S_USEDEFAULTCURSORS;
2655 }
2656
2657 static const IDropSourceVtbl dsvt =
2658 {
2659 ISVDropSource_QueryInterface,
2660 ISVDropSource_AddRef,
2661 ISVDropSource_Release,
2662 ISVDropSource_QueryContinueDrag,
2663 ISVDropSource_GiveFeedback
2664 };
2665 /**********************************************************
2666 * ISVViewObject implementation
2667 */
2668
2669 static HRESULT WINAPI ISVViewObject_QueryInterface(
2670 IViewObject *iface,
2671 REFIID riid,
2672 LPVOID *ppvObj)
2673 {
2674 IShellViewImpl *This = impl_from_IViewObject(iface);
2675
2676 TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
2677
2678 return IShellFolder_QueryInterface((IShellFolder*)This, riid, ppvObj);
2679 }
2680
2681 static ULONG WINAPI ISVViewObject_AddRef( IViewObject *iface)
2682 {
2683 IShellViewImpl *This = impl_from_IViewObject(iface);
2684
2685 TRACE("(%p)->(count=%u)\n",This,This->ref);
2686
2687 return IShellFolder_AddRef((IShellFolder*)This);
2688 }
2689
2690 static ULONG WINAPI ISVViewObject_Release( IViewObject *iface)
2691 {
2692 IShellViewImpl *This = impl_from_IViewObject(iface);
2693
2694 TRACE("(%p)->(count=%u)\n",This,This->ref);
2695
2696 return IShellFolder_Release((IShellFolder*)This);
2697 }
2698
2699 static HRESULT WINAPI ISVViewObject_Draw(
2700 IViewObject *iface,
2701 DWORD dwDrawAspect,
2702 LONG lindex,
2703 void* pvAspect,
2704 DVTARGETDEVICE* ptd,
2705 HDC hdcTargetDev,
2706 HDC hdcDraw,
2707 LPCRECTL lprcBounds,
2708 LPCRECTL lprcWBounds,
2709 BOOL (CALLBACK *pfnContinue)(ULONG_PTR dwContinue),
2710 ULONG_PTR dwContinue)
2711 {
2712
2713 IShellViewImpl *This = impl_from_IViewObject(iface);
2714
2715 FIXME("Stub: This=%p\n",This);
2716
2717 return E_NOTIMPL;
2718 }
2719 static HRESULT WINAPI ISVViewObject_GetColorSet(
2720 IViewObject *iface,
2721 DWORD dwDrawAspect,
2722 LONG lindex,
2723 void *pvAspect,
2724 DVTARGETDEVICE* ptd,
2725 HDC hicTargetDevice,
2726 LOGPALETTE** ppColorSet)
2727 {
2728
2729 IShellViewImpl *This = impl_from_IViewObject(iface);
2730
2731 FIXME("Stub: This=%p\n",This);
2732
2733 return E_NOTIMPL;
2734 }
2735 static HRESULT WINAPI ISVViewObject_Freeze(
2736 IViewObject *iface,
2737 DWORD dwDrawAspect,
2738 LONG lindex,
2739 void* pvAspect,
2740 DWORD* pdwFreeze)
2741 {
2742
2743 IShellViewImpl *This = impl_from_IViewObject(iface);
2744
2745 FIXME("Stub: This=%p\n",This);
2746
2747 return E_NOTIMPL;
2748 }
2749 static HRESULT WINAPI ISVViewObject_Unfreeze(
2750 IViewObject *iface,
2751 DWORD dwFreeze)
2752 {
2753
2754 IShellViewImpl *This = impl_from_IViewObject(iface);
2755
2756 FIXME("Stub: This=%p\n",This);
2757
2758 return E_NOTIMPL;
2759 }
2760 static HRESULT WINAPI ISVViewObject_SetAdvise(
2761 IViewObject *iface,
2762 DWORD aspects,
2763 DWORD advf,
2764 IAdviseSink* pAdvSink)
2765 {
2766
2767 IShellViewImpl *This = impl_from_IViewObject(iface);
2768
2769 FIXME("partial stub: %p %08x %08x %p\n",
2770 This, aspects, advf, pAdvSink);
2771
2772 /* FIXME: we set the AdviseSink, but never use it to send any advice */
2773 This->pAdvSink = pAdvSink;
2774 This->dwAspects = aspects;
2775 This->dwAdvf = advf;
2776
2777 return S_OK;
2778 }
2779
2780 static HRESULT WINAPI ISVViewObject_GetAdvise(
2781 IViewObject *iface,
2782 DWORD* pAspects,
2783 DWORD* pAdvf,
2784 IAdviseSink** ppAdvSink)
2785 {
2786
2787 IShellViewImpl *This = impl_from_IViewObject(iface);
2788
2789 TRACE("This=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n",
2790 This, pAspects, pAdvf, ppAdvSink);
2791
2792 if( ppAdvSink )
2793 {
2794 IAdviseSink_AddRef( This->pAdvSink );
2795 *ppAdvSink = This->pAdvSink;
2796 }
2797 if( pAspects )
2798 *pAspects = This->dwAspects;
2799 if( pAdvf )
2800 *pAdvf = This->dwAdvf;
2801
2802 return S_OK;
2803 }
2804
2805
2806 static const IViewObjectVtbl vovt =
2807 {
2808 ISVViewObject_QueryInterface,
2809 ISVViewObject_AddRef,
2810 ISVViewObject_Release,
2811 ISVViewObject_Draw,
2812 ISVViewObject_GetColorSet,
2813 ISVViewObject_Freeze,
2814 ISVViewObject_Unfreeze,
2815 ISVViewObject_SetAdvise,
2816 ISVViewObject_GetAdvise
2817 };