2 * Unit test of the IShellView
4 * Copyright 2010 Nikolay Sivov for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
41 #include "wine/test.h"
45 #define LISTVIEW_SEQ_INDEX 0
46 #define NUM_MSG_SEQUENCES 1
48 DEFINE_GUID(IID_IPersistHistory, 0x91a565c1, 0xe38f, 0x11d0, 0x94, 0xbf, 0x00, 0xa0, 0xc9, 0x05, 0x5c, 0xbf);
50 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
52 static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
54 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
55 static LONG defwndproc_counter = 0;
59 trace("listview: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
61 msg.message = message;
62 msg.flags = sent|wparam|lparam;
63 if (defwndproc_counter) msg.flags |= defwinproc;
66 add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
69 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
74 static HWND subclass_listview(HWND hwnd)
79 /* listview is a first child */
80 listview = FindWindowExA(hwnd, NULL, WC_LISTVIEWA, NULL);
83 /* .. except for some versions of Windows XP, where things
84 are slightly more complicated. */
86 hwnd_tmp = FindWindowExA(hwnd, NULL, "DUIViewWndClassName", NULL);
87 hwnd_tmp = FindWindowExA(hwnd_tmp, NULL, "DirectUIHWND", NULL);
88 hwnd_tmp = FindWindowExA(hwnd_tmp, NULL, "CtrlNotifySink", NULL);
89 listview = FindWindowExA(hwnd_tmp, NULL, WC_LISTVIEWA, NULL);
92 oldproc = (WNDPROC)SetWindowLongPtrA(listview, GWLP_WNDPROC,
93 (LONG_PTR)listview_subclass_proc);
94 SetWindowLongPtrA(listview, GWLP_USERDATA, (LONG_PTR)oldproc);
99 /* dummy IDataObject implementation */
101 const IDataObjectVtbl *lpVtbl;
105 static const IDataObjectVtbl IDataObjectImpl_Vtbl;
107 static IDataObject* IDataObjectImpl_Construct(void)
109 IDataObjectImpl *obj;
111 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
112 obj->lpVtbl = &IDataObjectImpl_Vtbl;
115 return (IDataObject*)obj;
118 static HRESULT WINAPI IDataObjectImpl_QueryInterface(IDataObject *iface, REFIID riid, void **ppvObj)
120 IDataObjectImpl *This = (IDataObjectImpl *)iface;
122 if (IsEqualIID(riid, &IID_IUnknown) ||
123 IsEqualIID(riid, &IID_IDataObject))
130 IUnknown_AddRef(iface);
134 return E_NOINTERFACE;
137 static ULONG WINAPI IDataObjectImpl_AddRef(IDataObject * iface)
139 IDataObjectImpl *This = (IDataObjectImpl *)iface;
140 return InterlockedIncrement(&This->ref);
143 static ULONG WINAPI IDataObjectImpl_Release(IDataObject * iface)
145 IDataObjectImpl *This = (IDataObjectImpl *)iface;
146 ULONG ref = InterlockedDecrement(&This->ref);
150 HeapFree(GetProcessHeap(), 0, This);
156 static HRESULT WINAPI IDataObjectImpl_GetData(IDataObject *iface, FORMATETC *pformat, STGMEDIUM *pmedium)
161 static HRESULT WINAPI IDataObjectImpl_GetDataHere(IDataObject *iface, FORMATETC *pformat, STGMEDIUM *pmedium)
166 static HRESULT WINAPI IDataObjectImpl_QueryGetData(IDataObject *iface, FORMATETC *pformat)
171 static HRESULT WINAPI IDataObjectImpl_GetCanonicalFormatEtc(
172 IDataObject *iface, FORMATETC *pformatIn, FORMATETC *pformatOut)
177 static HRESULT WINAPI IDataObjectImpl_SetData(
178 IDataObject *iface, FORMATETC *pformat, STGMEDIUM *pmedium, BOOL release)
183 static HRESULT WINAPI IDataObjectImpl_EnumFormatEtc(
184 IDataObject *iface, DWORD direction, IEnumFORMATETC **ppenumFormatEtc)
189 static HRESULT WINAPI IDataObjectImpl_DAdvise(
190 IDataObject *iface, FORMATETC *pformatetc, DWORD advf, IAdviseSink *pSink, DWORD *pConnection)
195 static HRESULT WINAPI IDataObjectImpl_DUnadvise(IDataObject *iface, DWORD connection)
200 static HRESULT WINAPI IDataObjectImpl_EnumDAdvise(IDataObject *iface, IEnumSTATDATA **ppenumAdvise)
205 static const IDataObjectVtbl IDataObjectImpl_Vtbl =
207 IDataObjectImpl_QueryInterface,
208 IDataObjectImpl_AddRef,
209 IDataObjectImpl_Release,
210 IDataObjectImpl_GetData,
211 IDataObjectImpl_GetDataHere,
212 IDataObjectImpl_QueryGetData,
213 IDataObjectImpl_GetCanonicalFormatEtc,
214 IDataObjectImpl_SetData,
215 IDataObjectImpl_EnumFormatEtc,
216 IDataObjectImpl_DAdvise,
217 IDataObjectImpl_DUnadvise,
218 IDataObjectImpl_EnumDAdvise
221 /* dummy IShellBrowser implementation */
223 const IShellBrowserVtbl *lpVtbl;
227 static const IShellBrowserVtbl IShellBrowserImpl_Vtbl;
229 static IShellBrowser* IShellBrowserImpl_Construct(void)
231 IShellBrowserImpl *browser;
233 browser = HeapAlloc(GetProcessHeap(), 0, sizeof(*browser));
234 browser->lpVtbl = &IShellBrowserImpl_Vtbl;
237 return (IShellBrowser*)browser;
240 static HRESULT WINAPI IShellBrowserImpl_QueryInterface(IShellBrowser *iface,
244 IShellBrowserImpl *This = (IShellBrowserImpl *)iface;
248 if(IsEqualIID(riid, &IID_IUnknown) ||
249 IsEqualIID(riid, &IID_IOleWindow) ||
250 IsEqualIID(riid, &IID_IShellBrowser))
257 IUnknown_AddRef(iface);
261 return E_NOINTERFACE;
264 static ULONG WINAPI IShellBrowserImpl_AddRef(IShellBrowser * iface)
266 IShellBrowserImpl *This = (IShellBrowserImpl *)iface;
267 return InterlockedIncrement(&This->ref);
270 static ULONG WINAPI IShellBrowserImpl_Release(IShellBrowser * iface)
272 IShellBrowserImpl *This = (IShellBrowserImpl *)iface;
273 ULONG ref = InterlockedDecrement(&This->ref);
277 HeapFree(GetProcessHeap(), 0, This);
283 static HRESULT WINAPI IShellBrowserImpl_GetWindow(IShellBrowser *iface,
286 if (phwnd) *phwnd = GetDesktopWindow();
290 static HRESULT WINAPI IShellBrowserImpl_ContextSensitiveHelp(IShellBrowser *iface,
296 static HRESULT WINAPI IShellBrowserImpl_BrowseObject(IShellBrowser *iface,
303 static HRESULT WINAPI IShellBrowserImpl_EnableModelessSB(IShellBrowser *iface,
310 static HRESULT WINAPI IShellBrowserImpl_GetControlWindow(IShellBrowser *iface,
318 static HRESULT WINAPI IShellBrowserImpl_GetViewStateStream(IShellBrowser *iface,
326 static HRESULT WINAPI IShellBrowserImpl_InsertMenusSB(IShellBrowser *iface,
328 LPOLEMENUGROUPWIDTHS lpMenuWidths)
334 static HRESULT WINAPI IShellBrowserImpl_OnViewWindowActive(IShellBrowser *iface,
341 static HRESULT WINAPI IShellBrowserImpl_QueryActiveShellView(IShellBrowser *iface,
348 static HRESULT WINAPI IShellBrowserImpl_RemoveMenusSB(IShellBrowser *iface,
355 static HRESULT WINAPI IShellBrowserImpl_SendControlMsg(IShellBrowser *iface,
366 static HRESULT WINAPI IShellBrowserImpl_SetMenuSB(IShellBrowser *iface,
368 HOLEMENU holemenuReserved,
369 HWND hwndActiveObject)
375 static HRESULT WINAPI IShellBrowserImpl_SetStatusTextSB(IShellBrowser *iface,
376 LPCOLESTR lpszStatusText)
382 static HRESULT WINAPI IShellBrowserImpl_SetToolbarItems(IShellBrowser *iface,
383 LPTBBUTTON lpButtons,
391 static HRESULT WINAPI IShellBrowserImpl_TranslateAcceleratorSB(IShellBrowser *iface,
399 static const IShellBrowserVtbl IShellBrowserImpl_Vtbl =
401 IShellBrowserImpl_QueryInterface,
402 IShellBrowserImpl_AddRef,
403 IShellBrowserImpl_Release,
404 IShellBrowserImpl_GetWindow,
405 IShellBrowserImpl_ContextSensitiveHelp,
406 IShellBrowserImpl_InsertMenusSB,
407 IShellBrowserImpl_SetMenuSB,
408 IShellBrowserImpl_RemoveMenusSB,
409 IShellBrowserImpl_SetStatusTextSB,
410 IShellBrowserImpl_EnableModelessSB,
411 IShellBrowserImpl_TranslateAcceleratorSB,
412 IShellBrowserImpl_BrowseObject,
413 IShellBrowserImpl_GetViewStateStream,
414 IShellBrowserImpl_GetControlWindow,
415 IShellBrowserImpl_SendControlMsg,
416 IShellBrowserImpl_QueryActiveShellView,
417 IShellBrowserImpl_OnViewWindowActive,
418 IShellBrowserImpl_SetToolbarItems
421 static const struct message empty_seq[] = {
425 static const struct message folderview_getspacing_seq[] = {
426 { LVM_GETITEMSPACING, wparam|sent, FALSE },
430 static const struct message folderview_getselectionmarked_seq[] = {
431 { LVM_GETSELECTIONMARK, sent },
435 static const struct message folderview_getfocused_seq[] = {
436 { LVM_GETNEXTITEM, sent|wparam|lparam, -1, LVNI_FOCUSED },
440 static const struct message folderview_itemcount_seq[] = {
441 { LVM_GETITEMCOUNT, sent },
445 static void test_IShellView_CreateViewWindow(void)
447 IShellFolder *desktop;
448 FOLDERSETTINGS settings;
455 hr = SHGetDesktopFolder(&desktop);
456 ok(hr == S_OK, "got (0x%08x)\n", hr);
458 hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
459 ok(hr == S_OK, "got (0x%08x)\n", hr);
463 /* crashes on native */
464 hr = IShellView_CreateViewWindow(view, NULL, &settings, NULL, NULL, NULL);
467 settings.ViewMode = FVM_ICON;
469 hwnd_view = (HWND)0xdeadbeef;
470 hr = IShellView_CreateViewWindow(view, NULL, &settings, NULL, NULL, &hwnd_view);
471 ok(hr == E_UNEXPECTED, "got (0x%08x)\n", hr);
472 ok(hwnd_view == 0, "got %p\n", hwnd_view);
474 hwnd_view = (HWND)0xdeadbeef;
475 hr = IShellView_CreateViewWindow(view, NULL, &settings, NULL, &r, &hwnd_view);
476 ok(hr == E_UNEXPECTED, "got (0x%08x)\n", hr);
477 ok(hwnd_view == 0, "got %p\n", hwnd_view);
479 /* ::DragLeave without drag operation */
480 hr = IShellView_QueryInterface(view, &IID_IDropTarget, (void**)&dt);
481 ok(hr == S_OK, "got (0x%08x)\n", hr);
482 hr = IDropTarget_DragLeave(dt);
483 ok(hr == S_OK, "got (0x%08x)\n", hr);
484 IDropTarget_Release(dt);
486 IShellView_Release(view);
487 IShellFolder_Release(desktop);
490 static void test_IFolderView(void)
492 IShellFolder *desktop, *folder;
493 FOLDERSETTINGS settings;
495 IShellBrowser *browser;
497 HWND hwnd_view, hwnd_list;
505 hr = SHGetDesktopFolder(&desktop);
506 ok(hr == S_OK, "got (0x%08x)\n", hr);
508 hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
509 ok(hr == S_OK, "got (0x%08x)\n", hr);
511 hr = IShellView_QueryInterface(view, &IID_IFolderView, (void**)&fv);
514 win_skip("IFolderView not supported by desktop folder\n");
515 IShellView_Release(view);
516 IShellFolder_Release(desktop);
520 /* call methods before window creation */
521 hr = IFolderView_GetSpacing(fv, NULL);
522 ok(hr == S_FALSE || broken(hr == S_OK) /* win7 */, "got (0x%08x)\n", hr);
524 pidl = (void*)0xdeadbeef;
525 hr = IFolderView_Item(fv, 0, &pidl);
526 ok(hr == E_INVALIDARG || broken(hr == E_FAIL) /* < Vista */, "got (0x%08x)\n", hr);
527 ok(pidl == 0 || broken(pidl == (void*)0xdeadbeef) /* < Vista */, "got %p\n", pidl);
531 /* crashes on Vista and Win2k8 - List not created yet case */
532 hr = IFolderView_GetSpacing(fv, &pt);
535 hr = IFolderView_GetSelectionMarkedItem(fv, NULL);
536 hr = IFolderView_GetFocusedItem(fv, NULL);
538 /* crashes on Vista+ */
539 hr = IFolderView_Item(fv, 0, NULL);
542 browser = IShellBrowserImpl_Construct();
544 settings.ViewMode = FVM_ICON;
546 hwnd_view = (HWND)0xdeadbeef;
548 r.right = r.bottom = 100;
549 hr = IShellView_CreateViewWindow(view, NULL, &settings, browser, &r, &hwnd_view);
550 ok(hr == S_OK, "got (0x%08x)\n", hr);
551 ok(IsWindow(hwnd_view), "got %p\n", hwnd_view);
553 hwnd_list = subclass_listview(hwnd_view);
556 win_skip("Failed to subclass ListView control\n");
557 IShellBrowser_Release(browser);
558 IFolderView_Release(fv);
559 IShellView_Release(view);
560 IShellFolder_Release(desktop);
564 /* IFolderView::GetSpacing */
565 flush_sequences(sequences, NUM_MSG_SEQUENCES);
566 hr = IFolderView_GetSpacing(fv, NULL);
567 ok(hr == S_OK, "got (0x%08x)\n", hr);
568 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, empty_seq, "IFolderView::GetSpacing, empty", FALSE);
570 flush_sequences(sequences, NUM_MSG_SEQUENCES);
571 hr = IFolderView_GetSpacing(fv, &pt);
572 ok(hr == S_OK, "got (0x%08x)\n", hr);
573 /* fails with empty sequence on win7 for unknown reason */
574 if (sequences[LISTVIEW_SEQ_INDEX]->count)
576 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_getspacing_seq, "IFolderView::GetSpacing", FALSE);
577 ok(pt.x > 0, "got %d\n", pt.x);
578 ok(pt.y > 0, "got %d\n", pt.y);
579 ret = SendMessageA(hwnd_list, LVM_GETITEMSPACING, 0, 0);
580 ok(pt.x == LOWORD(ret) && pt.y == HIWORD(ret), "got (%d, %d)\n", LOWORD(ret), HIWORD(ret));
583 /* IFolderView::GetSelectionMarkedItem */
587 hr = IFolderView_GetSelectionMarkedItem(fv, NULL);
590 flush_sequences(sequences, NUM_MSG_SEQUENCES);
591 hr = IFolderView_GetSelectionMarkedItem(fv, &ret);
592 ok(hr == S_OK, "got (0x%08x)\n", hr);
593 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_getselectionmarked_seq,
594 "IFolderView::GetSelectionMarkedItem", FALSE);
596 /* IFolderView::GetFocusedItem */
597 flush_sequences(sequences, NUM_MSG_SEQUENCES);
598 hr = IFolderView_GetFocusedItem(fv, &ret);
599 ok(hr == S_OK, "got (0x%08x)\n", hr);
600 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_getfocused_seq,
601 "IFolderView::GetFocusedItem", FALSE);
603 /* IFolderView::GetFolder, just return pointer */
607 hr = IFolderView_GetFolder(fv, NULL, (void**)&folder);
608 hr = IFolderView_GetFolder(fv, NULL, NULL);
611 hr = IFolderView_GetFolder(fv, &IID_IShellFolder, NULL);
612 ok(hr == E_POINTER, "got (0x%08x)\n", hr);
614 ref1 = IShellFolder_AddRef(desktop);
615 IShellFolder_Release(desktop);
616 hr = IFolderView_GetFolder(fv, &IID_IShellFolder, (void**)&folder);
617 ok(hr == S_OK, "got (0x%08x)\n", hr);
618 ref2 = IShellFolder_AddRef(desktop);
619 IShellFolder_Release(desktop);
620 ok(ref1 == ref2, "expected same refcount, got %d\n", ref2);
621 ok(desktop == folder, "\n");
623 /* IFolderView::ItemCount */
627 hr = IFolderView_ItemCount(fv, SVGIO_ALLVIEW, NULL);
630 flush_sequences(sequences, NUM_MSG_SEQUENCES);
631 hr = IFolderView_ItemCount(fv, SVGIO_ALLVIEW, &ret);
632 ok(hr == S_OK, "got (0x%08x)\n", hr);
633 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_itemcount_seq,
634 "IFolderView::ItemCount", FALSE);
636 IShellBrowser_Release(browser);
637 IFolderView_Release(fv);
638 IShellView_Release(view);
639 IShellFolder_Release(desktop);
642 static void test_GetItemObject(void)
644 IShellFolder *desktop;
649 hr = SHGetDesktopFolder(&desktop);
650 ok(hr == S_OK, "got (0x%08x)\n", hr);
652 hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
653 ok(hr == S_OK, "got (0x%08x)\n", hr);
655 /* from documentation three interfaces are supported for SVGIO_BACKGROUND:
656 IContextMenu, IDispatch, IPersistHistory */
657 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IContextMenu, (void**)&unk);
658 ok(hr == S_OK, "got (0x%08x)\n", hr);
659 IUnknown_Release(unk);
662 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&unk);
663 todo_wine ok(hr == S_OK || broken(hr == E_NOTIMPL) /* NT4 */, "got (0x%08x)\n", hr);
664 if (unk) IUnknown_Release(unk);
667 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IPersistHistory, (void**)&unk);
668 todo_wine ok(hr == S_OK || broken(hr == E_NOTIMPL) /* W9x, NT4 */, "got (0x%08x)\n", hr);
669 if (unk) IUnknown_Release(unk);
671 /* example of unsupported interface, base for IPersistHistory */
672 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IPersist, (void**)&unk);
673 ok(hr == E_NOINTERFACE || broken(hr == E_NOTIMPL) /* W2K */, "got (0x%08x)\n", hr);
675 IShellView_Release(view);
676 IShellFolder_Release(desktop);
679 static void test_IShellFolderView(void)
681 IShellFolderView *folderview;
682 IShellFolder *desktop;
688 hr = SHGetDesktopFolder(&desktop);
689 ok(hr == S_OK, "got (0x%08x)\n", hr);
691 hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
692 ok(hr == S_OK, "got (0x%08x)\n", hr);
694 hr = IShellView_QueryInterface(view, &IID_IShellFolderView, (void**)&folderview);
697 win_skip("IShellView doesn't provide IShellFolderView on this platform\n");
698 IShellView_Release(view);
699 IShellFolder_Release(desktop);
704 obj = IDataObjectImpl_Construct();
705 hr = IShellFolderView_MoveIcons(folderview, obj);
706 ok(hr == E_NOTIMPL || broken(hr == S_OK) /* W98 */, "got (0x%08x)\n", hr);
707 IDataObject_Release(obj);
709 /* ::SetRedraw without list created */
710 hr = IShellFolderView_SetRedraw(folderview, TRUE);
711 ok(hr == S_OK, "got (0x%08x)\n", hr);
714 hr = IShellFolderView_QuerySupport(folderview, NULL);
715 ok(hr == S_OK, "got (0x%08x)\n", hr);
717 hr = IShellFolderView_QuerySupport(folderview, &i);
718 ok(hr == S_OK, "got (0x%08x)\n", hr);
719 ok(i == 0xdeadbeef, "got %d\n", i);
723 hr = IShellFolderView_RemoveObject(folderview, NULL, &i);
724 ok(hr == S_OK, "got (0x%08x)\n", hr);
725 ok(i == 0 || i == -1 /* Win7 */ || broken(i == 0xdeadbeef) /* Vista, 2k8 */,
728 IShellFolderView_Release(folderview);
730 IShellView_Release(view);
731 IShellFolder_Release(desktop);
734 static void test_IOleWindow(void)
736 IShellFolder *desktop;
740 hr = SHGetDesktopFolder(&desktop);
741 ok(hr == S_OK, "got (0x%08x)\n", hr);
743 hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
744 ok(hr == S_OK, "got (0x%08x)\n", hr);
746 /* IShellView::ContextSensitiveHelp */
747 hr = IShellView_ContextSensitiveHelp(view, TRUE);
748 ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
749 hr = IShellView_ContextSensitiveHelp(view, FALSE);
750 ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
752 IShellView_Release(view);
753 IShellFolder_Release(desktop);
760 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
762 test_IShellView_CreateViewWindow();
764 test_GetItemObject();
765 test_IShellFolderView();