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);
82 oldproc = (WNDPROC)SetWindowLongPtrA(listview, GWLP_WNDPROC,
83 (LONG_PTR)listview_subclass_proc);
84 SetWindowLongPtrA(listview, GWLP_USERDATA, (LONG_PTR)oldproc);
89 /* dummy IDataObject implementation */
91 const IDataObjectVtbl *lpVtbl;
95 static const IDataObjectVtbl IDataObjectImpl_Vtbl;
97 IDataObject* IDataObjectImpl_Construct(void)
101 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
102 obj->lpVtbl = &IDataObjectImpl_Vtbl;
105 return (IDataObject*)obj;
108 static HRESULT WINAPI IDataObjectImpl_QueryInterface(IDataObject *iface, REFIID riid, void **ppvObj)
110 IDataObjectImpl *This = (IDataObjectImpl *)iface;
112 if (IsEqualIID(riid, &IID_IUnknown) ||
113 IsEqualIID(riid, &IID_IDataObject))
120 IUnknown_AddRef(iface);
124 return E_NOINTERFACE;
127 static ULONG WINAPI IDataObjectImpl_AddRef(IDataObject * iface)
129 IDataObjectImpl *This = (IDataObjectImpl *)iface;
130 return InterlockedIncrement(&This->ref);
133 static ULONG WINAPI IDataObjectImpl_Release(IDataObject * iface)
135 IDataObjectImpl *This = (IDataObjectImpl *)iface;
136 ULONG ref = InterlockedDecrement(&This->ref);
140 HeapFree(GetProcessHeap(), 0, This);
146 static HRESULT WINAPI IDataObjectImpl_GetData(IDataObject *iface, FORMATETC *pformat, STGMEDIUM *pmedium)
151 static HRESULT WINAPI IDataObjectImpl_GetDataHere(IDataObject *iface, FORMATETC *pformat, STGMEDIUM *pmedium)
156 static HRESULT WINAPI IDataObjectImpl_QueryGetData(IDataObject *iface, FORMATETC *pformat)
161 static HRESULT WINAPI IDataObjectImpl_GetCanonicalFormatEtc(
162 IDataObject *iface, FORMATETC *pformatIn, FORMATETC *pformatOut)
167 static HRESULT WINAPI IDataObjectImpl_SetData(
168 IDataObject *iface, FORMATETC *pformat, STGMEDIUM *pmedium, BOOL release)
173 static HRESULT WINAPI IDataObjectImpl_EnumFormatEtc(
174 IDataObject *iface, DWORD direction, IEnumFORMATETC **ppenumFormatEtc)
179 static HRESULT WINAPI IDataObjectImpl_DAdvise(
180 IDataObject *iface, FORMATETC *pformatetc, DWORD advf, IAdviseSink *pSink, DWORD *pConnection)
185 static HRESULT WINAPI IDataObjectImpl_DUnadvise(IDataObject *iface, DWORD connection)
190 static HRESULT WINAPI IDataObjectImpl_EnumDAdvise(IDataObject *iface, IEnumSTATDATA **ppenumAdvise)
195 static const IDataObjectVtbl IDataObjectImpl_Vtbl =
197 IDataObjectImpl_QueryInterface,
198 IDataObjectImpl_AddRef,
199 IDataObjectImpl_Release,
200 IDataObjectImpl_GetData,
201 IDataObjectImpl_GetDataHere,
202 IDataObjectImpl_QueryGetData,
203 IDataObjectImpl_GetCanonicalFormatEtc,
204 IDataObjectImpl_SetData,
205 IDataObjectImpl_EnumFormatEtc,
206 IDataObjectImpl_DAdvise,
207 IDataObjectImpl_DUnadvise,
208 IDataObjectImpl_EnumDAdvise
211 /* dummy IShellBrowser implementation */
213 const IShellBrowserVtbl *lpVtbl;
217 static const IShellBrowserVtbl IShellBrowserImpl_Vtbl;
219 IShellBrowser* IShellBrowserImpl_Construct(void)
221 IShellBrowserImpl *browser;
223 browser = HeapAlloc(GetProcessHeap(), 0, sizeof(*browser));
224 browser->lpVtbl = &IShellBrowserImpl_Vtbl;
227 return (IShellBrowser*)browser;
230 static HRESULT WINAPI IShellBrowserImpl_QueryInterface(IShellBrowser *iface,
234 IShellBrowserImpl *This = (IShellBrowserImpl *)iface;
238 if(IsEqualIID(riid, &IID_IUnknown) ||
239 IsEqualIID(riid, &IID_IOleWindow) ||
240 IsEqualIID(riid, &IID_IShellBrowser))
247 IUnknown_AddRef(iface);
251 return E_NOINTERFACE;
254 static ULONG WINAPI IShellBrowserImpl_AddRef(IShellBrowser * iface)
256 IShellBrowserImpl *This = (IShellBrowserImpl *)iface;
257 return InterlockedIncrement(&This->ref);
260 static ULONG WINAPI IShellBrowserImpl_Release(IShellBrowser * iface)
262 IShellBrowserImpl *This = (IShellBrowserImpl *)iface;
263 ULONG ref = InterlockedDecrement(&This->ref);
267 HeapFree(GetProcessHeap(), 0, This);
273 static HRESULT WINAPI IShellBrowserImpl_GetWindow(IShellBrowser *iface,
276 if (phwnd) *phwnd = GetDesktopWindow();
280 static HRESULT WINAPI IShellBrowserImpl_ContextSensitiveHelp(IShellBrowser *iface,
286 static HRESULT WINAPI IShellBrowserImpl_BrowseObject(IShellBrowser *iface,
293 static HRESULT WINAPI IShellBrowserImpl_EnableModelessSB(IShellBrowser *iface,
300 static HRESULT WINAPI IShellBrowserImpl_GetControlWindow(IShellBrowser *iface,
308 static HRESULT WINAPI IShellBrowserImpl_GetViewStateStream(IShellBrowser *iface,
316 static HRESULT WINAPI IShellBrowserImpl_InsertMenusSB(IShellBrowser *iface,
318 LPOLEMENUGROUPWIDTHS lpMenuWidths)
324 static HRESULT WINAPI IShellBrowserImpl_OnViewWindowActive(IShellBrowser *iface,
331 static HRESULT WINAPI IShellBrowserImpl_QueryActiveShellView(IShellBrowser *iface,
338 static HRESULT WINAPI IShellBrowserImpl_RemoveMenusSB(IShellBrowser *iface,
345 static HRESULT WINAPI IShellBrowserImpl_SendControlMsg(IShellBrowser *iface,
356 static HRESULT WINAPI IShellBrowserImpl_SetMenuSB(IShellBrowser *iface,
358 HOLEMENU holemenuReserved,
359 HWND hwndActiveObject)
365 static HRESULT WINAPI IShellBrowserImpl_SetStatusTextSB(IShellBrowser *iface,
366 LPCOLESTR lpszStatusText)
372 static HRESULT WINAPI IShellBrowserImpl_SetToolbarItems(IShellBrowser *iface,
373 LPTBBUTTON lpButtons,
381 static HRESULT WINAPI IShellBrowserImpl_TranslateAcceleratorSB(IShellBrowser *iface,
389 static const IShellBrowserVtbl IShellBrowserImpl_Vtbl =
391 IShellBrowserImpl_QueryInterface,
392 IShellBrowserImpl_AddRef,
393 IShellBrowserImpl_Release,
394 IShellBrowserImpl_GetWindow,
395 IShellBrowserImpl_ContextSensitiveHelp,
396 IShellBrowserImpl_InsertMenusSB,
397 IShellBrowserImpl_SetMenuSB,
398 IShellBrowserImpl_RemoveMenusSB,
399 IShellBrowserImpl_SetStatusTextSB,
400 IShellBrowserImpl_EnableModelessSB,
401 IShellBrowserImpl_TranslateAcceleratorSB,
402 IShellBrowserImpl_BrowseObject,
403 IShellBrowserImpl_GetViewStateStream,
404 IShellBrowserImpl_GetControlWindow,
405 IShellBrowserImpl_SendControlMsg,
406 IShellBrowserImpl_QueryActiveShellView,
407 IShellBrowserImpl_OnViewWindowActive,
408 IShellBrowserImpl_SetToolbarItems
411 static const struct message empty_seq[] = {
415 static const struct message folderview_getspacing_seq[] = {
416 { LVM_GETITEMSPACING, wparam|sent, FALSE },
420 static const struct message folderview_getselectionmarked_seq[] = {
421 { LVM_GETSELECTIONMARK, sent },
425 static const struct message folderview_getfocused_seq[] = {
426 { LVM_GETNEXTITEM, sent|wparam|lparam, -1, LVNI_FOCUSED },
430 static const struct message folderview_itemcount_seq[] = {
431 { LVM_GETITEMCOUNT, sent },
435 static void test_IShellView_CreateViewWindow(void)
437 IShellFolder *desktop;
438 FOLDERSETTINGS settings;
445 hr = SHGetDesktopFolder(&desktop);
446 ok(hr == S_OK, "got (0x%08x)\n", hr);
448 hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
449 ok(hr == S_OK, "got (0x%08x)\n", hr);
453 /* crashes on native */
454 hr = IShellView_CreateViewWindow(view, NULL, &settings, NULL, NULL, NULL);
457 settings.ViewMode = FVM_ICON;
459 hwnd_view = (HWND)0xdeadbeef;
460 hr = IShellView_CreateViewWindow(view, NULL, &settings, NULL, NULL, &hwnd_view);
461 ok(hr == E_UNEXPECTED, "got (0x%08x)\n", hr);
462 ok(hwnd_view == 0, "got %p\n", hwnd_view);
464 hwnd_view = (HWND)0xdeadbeef;
465 hr = IShellView_CreateViewWindow(view, NULL, &settings, NULL, &r, &hwnd_view);
466 ok(hr == E_UNEXPECTED, "got (0x%08x)\n", hr);
467 ok(hwnd_view == 0, "got %p\n", hwnd_view);
469 /* ::DragLeave without drag operation */
470 hr = IShellView_QueryInterface(view, &IID_IDropTarget, (void**)&dt);
471 ok(hr == S_OK, "got (0x%08x)\n", hr);
472 hr = IDropTarget_DragLeave(dt);
473 ok(hr == S_OK, "got (0x%08x)\n", hr);
474 IDropTarget_Release(dt);
476 IShellView_Release(view);
477 IShellFolder_Release(desktop);
480 static void test_IFolderView(void)
482 IShellFolder *desktop, *folder;
483 FOLDERSETTINGS settings;
485 IShellBrowser *browser;
487 HWND hwnd_view, hwnd_list;
495 hr = SHGetDesktopFolder(&desktop);
496 ok(hr == S_OK, "got (0x%08x)\n", hr);
498 hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
499 ok(hr == S_OK, "got (0x%08x)\n", hr);
501 hr = IShellView_QueryInterface(view, &IID_IFolderView, (void**)&fv);
504 win_skip("IFolderView not supported by desktop folder\n");
505 IShellView_Release(view);
506 IShellFolder_Release(desktop);
510 /* call methods before window creation */
511 hr = IFolderView_GetSpacing(fv, NULL);
512 ok(hr == S_FALSE || broken(hr == S_OK) /* win7 */, "got (0x%08x)\n", hr);
514 pidl = (void*)0xdeadbeef;
515 hr = IFolderView_Item(fv, 0, &pidl);
516 ok(hr == E_INVALIDARG || broken(hr == E_FAIL) /* < Vista */, "got (0x%08x)\n", hr);
517 ok(pidl == 0 || broken(pidl == (void*)0xdeadbeef) /* < Vista */, "got %p\n", pidl);
521 /* crashes on Vista and Win2k8 - List not created yet case */
522 hr = IFolderView_GetSpacing(fv, &pt);
525 hr = IFolderView_GetSelectionMarkedItem(fv, NULL);
526 hr = IFolderView_GetFocusedItem(fv, NULL);
528 /* crashes on Vista+ */
529 hr = IFolderView_Item(fv, 0, NULL);
532 browser = IShellBrowserImpl_Construct();
534 settings.ViewMode = FVM_ICON;
536 hwnd_view = (HWND)0xdeadbeef;
538 r.right = r.bottom = 100;
539 hr = IShellView_CreateViewWindow(view, NULL, &settings, browser, &r, &hwnd_view);
540 ok(hr == S_OK, "got (0x%08x)\n", hr);
541 ok(IsWindow(hwnd_view), "got %p\n", hwnd_view);
543 hwnd_list = subclass_listview(hwnd_view);
546 win_skip("Failed to subclass ListView control\n");
547 IShellBrowser_Release(browser);
548 IFolderView_Release(fv);
549 IShellView_Release(view);
550 IShellFolder_Release(desktop);
554 /* IFolderView::GetSpacing */
555 flush_sequences(sequences, NUM_MSG_SEQUENCES);
556 hr = IFolderView_GetSpacing(fv, NULL);
557 ok(hr == S_OK, "got (0x%08x)\n", hr);
558 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, empty_seq, "IFolderView::GetSpacing, empty", FALSE);
560 flush_sequences(sequences, NUM_MSG_SEQUENCES);
561 hr = IFolderView_GetSpacing(fv, &pt);
562 ok(hr == S_OK, "got (0x%08x)\n", hr);
563 /* fails with empty sequence on win7 for unknown reason */
564 if (sequences[LISTVIEW_SEQ_INDEX]->count)
566 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_getspacing_seq, "IFolderView::GetSpacing", FALSE);
567 ok(pt.x > 0, "got %d\n", pt.x);
568 ok(pt.y > 0, "got %d\n", pt.y);
569 ret = SendMessageA(hwnd_list, LVM_GETITEMSPACING, 0, 0);
570 ok(pt.x == LOWORD(ret) && pt.y == HIWORD(ret), "got (%d, %d)\n", LOWORD(ret), HIWORD(ret));
573 /* IFolderView::GetSelectionMarkedItem */
577 hr = IFolderView_GetSelectionMarkedItem(fv, NULL);
580 flush_sequences(sequences, NUM_MSG_SEQUENCES);
581 hr = IFolderView_GetSelectionMarkedItem(fv, &ret);
582 ok(hr == S_OK, "got (0x%08x)\n", hr);
583 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_getselectionmarked_seq,
584 "IFolderView::GetSelectionMarkedItem", FALSE);
586 /* IFolderView::GetFocusedItem */
587 flush_sequences(sequences, NUM_MSG_SEQUENCES);
588 hr = IFolderView_GetFocusedItem(fv, &ret);
589 ok(hr == S_OK, "got (0x%08x)\n", hr);
590 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_getfocused_seq,
591 "IFolderView::GetFocusedItem", FALSE);
593 /* IFolderView::GetFolder, just return pointer */
597 hr = IFolderView_GetFolder(fv, NULL, (void**)&folder);
598 hr = IFolderView_GetFolder(fv, NULL, NULL);
601 hr = IFolderView_GetFolder(fv, &IID_IShellFolder, NULL);
602 ok(hr == E_POINTER, "got (0x%08x)\n", hr);
604 ref1 = IShellFolder_AddRef(desktop);
605 IShellFolder_Release(desktop);
606 hr = IFolderView_GetFolder(fv, &IID_IShellFolder, (void**)&folder);
607 ok(hr == S_OK, "got (0x%08x)\n", hr);
608 ref2 = IShellFolder_AddRef(desktop);
609 IShellFolder_Release(desktop);
610 ok(ref1 == ref2, "expected same refcount, got %d\n", ref2);
611 ok(desktop == folder, "\n");
613 /* IFolderView::ItemCount */
617 hr = IFolderView_ItemCount(fv, SVGIO_ALLVIEW, NULL);
620 flush_sequences(sequences, NUM_MSG_SEQUENCES);
621 hr = IFolderView_ItemCount(fv, SVGIO_ALLVIEW, &ret);
622 ok(hr == S_OK, "got (0x%08x)\n", hr);
623 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_itemcount_seq,
624 "IFolderView::ItemCount", FALSE);
626 IShellBrowser_Release(browser);
627 IFolderView_Release(fv);
628 IShellView_Release(view);
629 IShellFolder_Release(desktop);
632 static void test_GetItemObject(void)
634 IShellFolder *desktop;
639 hr = SHGetDesktopFolder(&desktop);
640 ok(hr == S_OK, "got (0x%08x)\n", hr);
642 hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
643 ok(hr == S_OK, "got (0x%08x)\n", hr);
645 /* from documentation three interfaces are supported for SVGIO_BACKGROUND:
646 IContextMenu, IDispatch, IPersistHistory */
647 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IContextMenu, (void**)&unk);
648 ok(hr == S_OK, "got (0x%08x)\n", hr);
649 IUnknown_Release(unk);
652 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&unk);
653 todo_wine ok(hr == S_OK || broken(hr == E_NOTIMPL) /* NT4 */, "got (0x%08x)\n", hr);
654 if (unk) IUnknown_Release(unk);
657 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IPersistHistory, (void**)&unk);
658 todo_wine ok(hr == S_OK || broken(hr == E_NOTIMPL) /* W9x, NT4 */, "got (0x%08x)\n", hr);
659 if (unk) IUnknown_Release(unk);
661 /* example of unsupported interface, base for IPersistHistory */
662 hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IPersist, (void**)&unk);
663 ok(hr == E_NOINTERFACE || broken(hr == E_NOTIMPL) /* W2K */, "got (0x%08x)\n", hr);
665 IShellView_Release(view);
666 IShellFolder_Release(desktop);
669 static void test_IShellFolderView(void)
671 IShellFolderView *folderview;
672 IShellFolder *desktop;
678 hr = SHGetDesktopFolder(&desktop);
679 ok(hr == S_OK, "got (0x%08x)\n", hr);
681 hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
682 ok(hr == S_OK, "got (0x%08x)\n", hr);
684 hr = IShellView_QueryInterface(view, &IID_IShellFolderView, (void**)&folderview);
687 win_skip("IShellView doesn't provide IShellFolderView on this platform\n");
688 IShellView_Release(view);
689 IShellFolder_Release(desktop);
694 obj = IDataObjectImpl_Construct();
695 hr = IShellFolderView_MoveIcons(folderview, obj);
696 ok(hr == E_NOTIMPL || broken(hr == S_OK) /* W98 */, "got (0x%08x)\n", hr);
697 IDataObject_Release(obj);
699 /* ::SetRedraw without list created */
700 hr = IShellFolderView_SetRedraw(folderview, TRUE);
701 ok(hr == S_OK, "got (0x%08x)\n", hr);
704 hr = IShellFolderView_QuerySupport(folderview, NULL);
705 ok(hr == S_OK, "got (0x%08x)\n", hr);
707 hr = IShellFolderView_QuerySupport(folderview, &i);
708 ok(hr == S_OK, "got (0x%08x)\n", hr);
709 ok(i == 0xdeadbeef, "got %d\n", i);
713 hr = IShellFolderView_RemoveObject(folderview, NULL, &i);
714 ok(hr == S_OK, "got (0x%08x)\n", hr);
715 ok(i == 0 || i == -1 /* Win7 */ || broken(i == 0xdeadbeef) /* Vista, 2k8 */,
718 IShellFolderView_Release(folderview);
720 IShellView_Release(view);
721 IShellFolder_Release(desktop);
724 static void test_IOleWindow(void)
726 IShellFolder *desktop;
730 hr = SHGetDesktopFolder(&desktop);
731 ok(hr == S_OK, "got (0x%08x)\n", hr);
733 hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
734 ok(hr == S_OK, "got (0x%08x)\n", hr);
736 /* IShellView::ContextSensitiveHelp */
737 hr = IShellView_ContextSensitiveHelp(view, TRUE);
738 ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
739 hr = IShellView_ContextSensitiveHelp(view, FALSE);
740 ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
742 IShellView_Release(view);
743 IShellFolder_Release(desktop);
750 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
752 test_IShellView_CreateViewWindow();
754 test_GetItemObject();
755 test_IShellFolderView();