wined3d: IWineD3DBuffer_Unmap() can't fail.
[wine] / dlls / shell32 / tests / shlview.c
1 /*
2  * Unit test of the IShellView
3  *
4  * Copyright 2010 Nikolay Sivov for CodeWeavers
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include <stdarg.h>
22 #include <stdio.h>
23
24 #define COBJMACROS
25 #define CONST_VTABLE
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wtypes.h"
30 #include "shellapi.h"
31
32 #include "shlguid.h"
33 #include "shlobj.h"
34 #include "shobjidl.h"
35 #include "shlwapi.h"
36 #include "ocidl.h"
37 #include "oleauto.h"
38
39 #include "initguid.h"
40
41 #include "wine/test.h"
42
43 #include "msg.h"
44
45 #define LISTVIEW_SEQ_INDEX  0
46 #define NUM_MSG_SEQUENCES   1
47
48 DEFINE_GUID(IID_IPersistHistory, 0x91a565c1, 0xe38f, 0x11d0, 0x94, 0xbf, 0x00, 0xa0, 0xc9, 0x05, 0x5c, 0xbf);
49
50 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
51
52 static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
53 {
54     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
55     static LONG defwndproc_counter = 0;
56     LRESULT ret;
57     struct message msg;
58
59     trace("listview: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
60
61     msg.message = message;
62     msg.flags = sent|wparam|lparam;
63     if (defwndproc_counter) msg.flags |= defwinproc;
64     msg.wParam = wParam;
65     msg.lParam = lParam;
66     add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
67
68     defwndproc_counter++;
69     ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
70     defwndproc_counter--;
71     return ret;
72 }
73
74 static HWND subclass_listview(HWND hwnd)
75 {
76     WNDPROC oldproc;
77     HWND listview;
78
79     /* listview is a first child */
80     listview = FindWindowExA(hwnd, NULL, WC_LISTVIEWA, NULL);
81     if(!listview)
82     {
83         /* .. except for some versions of Windows XP, where things
84            are slightly more complicated. */
85         HWND hwnd_tmp;
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);
90     }
91
92     oldproc = (WNDPROC)SetWindowLongPtrA(listview, GWLP_WNDPROC,
93                                         (LONG_PTR)listview_subclass_proc);
94     SetWindowLongPtrA(listview, GWLP_USERDATA, (LONG_PTR)oldproc);
95
96     return listview;
97 }
98
99 static UINT get_msg_count(struct msg_sequence **seq, int sequence_index, UINT message)
100 {
101     struct msg_sequence *msg_seq = seq[sequence_index];
102     UINT i, count = 0;
103
104     for(i = 0; i < msg_seq->count ; i++)
105         if(msg_seq->sequence[i].message == message)
106             count++;
107
108     return count;
109 }
110
111 /* Checks that every message in the sequence seq is also present in
112  * the UINT array msgs */
113 static void verify_msgs_in_(struct msg_sequence *seq, const UINT *msgs,
114                            const char *file, int line)
115 {
116     UINT i, j, msg, failcount = 0;
117     for(i = 0; i < seq->count; i++)
118     {
119         BOOL found = FALSE;
120         msg = seq->sequence[i].message;
121         for(j = 0; msgs[j] != 0; j++)
122             if(msgs[j] == msg) found = TRUE;
123
124         if(!found)
125         {
126             failcount++;
127             trace("Unexpected message %d\n", msg);
128         }
129     }
130     ok_(file, line) (!failcount, "%d failures.\n", failcount);
131     flush_sequences(sequences, NUM_MSG_SEQUENCES);
132 }
133
134 #define verify_msgs_in(seq, msgs)               \
135     verify_msgs_in_(seq, msgs, __FILE__, __LINE__)
136
137 /* dummy IDataObject implementation */
138 typedef struct {
139     const IDataObjectVtbl *lpVtbl;
140     LONG ref;
141 } IDataObjectImpl;
142
143 static const IDataObjectVtbl IDataObjectImpl_Vtbl;
144
145 static IDataObject* IDataObjectImpl_Construct(void)
146 {
147     IDataObjectImpl *obj;
148
149     obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
150     obj->lpVtbl = &IDataObjectImpl_Vtbl;
151     obj->ref = 1;
152
153     return (IDataObject*)obj;
154 }
155
156 static HRESULT WINAPI IDataObjectImpl_QueryInterface(IDataObject *iface, REFIID riid, void **ppvObj)
157 {
158     IDataObjectImpl *This = (IDataObjectImpl *)iface;
159
160     if (IsEqualIID(riid, &IID_IUnknown) ||
161         IsEqualIID(riid, &IID_IDataObject))
162     {
163         *ppvObj = This;
164     }
165
166     if(*ppvObj)
167     {
168         IUnknown_AddRef(iface);
169         return S_OK;
170     }
171
172     return E_NOINTERFACE;
173 }
174
175 static ULONG WINAPI IDataObjectImpl_AddRef(IDataObject * iface)
176 {
177     IDataObjectImpl *This = (IDataObjectImpl *)iface;
178     return InterlockedIncrement(&This->ref);
179 }
180
181 static ULONG WINAPI IDataObjectImpl_Release(IDataObject * iface)
182 {
183     IDataObjectImpl *This = (IDataObjectImpl *)iface;
184     ULONG ref = InterlockedDecrement(&This->ref);
185
186     if (!ref)
187     {
188         HeapFree(GetProcessHeap(), 0, This);
189         return 0;
190     }
191     return ref;
192 }
193
194 static HRESULT WINAPI IDataObjectImpl_GetData(IDataObject *iface, FORMATETC *pformat, STGMEDIUM *pmedium)
195 {
196     return E_NOTIMPL;
197 }
198
199 static HRESULT WINAPI IDataObjectImpl_GetDataHere(IDataObject *iface, FORMATETC *pformat, STGMEDIUM *pmedium)
200 {
201     return E_NOTIMPL;
202 }
203
204 static HRESULT WINAPI IDataObjectImpl_QueryGetData(IDataObject *iface, FORMATETC *pformat)
205 {
206     return E_NOTIMPL;
207 }
208
209 static HRESULT WINAPI IDataObjectImpl_GetCanonicalFormatEtc(
210     IDataObject *iface, FORMATETC *pformatIn, FORMATETC *pformatOut)
211 {
212     return E_NOTIMPL;
213 }
214
215 static HRESULT WINAPI IDataObjectImpl_SetData(
216     IDataObject *iface, FORMATETC *pformat, STGMEDIUM *pmedium, BOOL release)
217 {
218     return E_NOTIMPL;
219 }
220
221 static HRESULT WINAPI IDataObjectImpl_EnumFormatEtc(
222     IDataObject *iface, DWORD direction, IEnumFORMATETC **ppenumFormatEtc)
223 {
224     return E_NOTIMPL;
225 }
226
227 static HRESULT WINAPI IDataObjectImpl_DAdvise(
228     IDataObject *iface, FORMATETC *pformatetc, DWORD advf, IAdviseSink *pSink, DWORD *pConnection)
229 {
230     return E_NOTIMPL;
231 }
232
233 static HRESULT WINAPI IDataObjectImpl_DUnadvise(IDataObject *iface, DWORD connection)
234 {
235     return E_NOTIMPL;
236 }
237
238 static HRESULT WINAPI IDataObjectImpl_EnumDAdvise(IDataObject *iface, IEnumSTATDATA **ppenumAdvise)
239 {
240     return E_NOTIMPL;
241 }
242
243 static const IDataObjectVtbl IDataObjectImpl_Vtbl =
244 {
245     IDataObjectImpl_QueryInterface,
246     IDataObjectImpl_AddRef,
247     IDataObjectImpl_Release,
248     IDataObjectImpl_GetData,
249     IDataObjectImpl_GetDataHere,
250     IDataObjectImpl_QueryGetData,
251     IDataObjectImpl_GetCanonicalFormatEtc,
252     IDataObjectImpl_SetData,
253     IDataObjectImpl_EnumFormatEtc,
254     IDataObjectImpl_DAdvise,
255     IDataObjectImpl_DUnadvise,
256     IDataObjectImpl_EnumDAdvise
257 };
258
259 /* dummy IShellBrowser implementation */
260 typedef struct {
261     const IShellBrowserVtbl *lpVtbl;
262     LONG ref;
263 } IShellBrowserImpl;
264
265 static const IShellBrowserVtbl IShellBrowserImpl_Vtbl;
266
267 static IShellBrowser* IShellBrowserImpl_Construct(void)
268 {
269     IShellBrowserImpl *browser;
270
271     browser = HeapAlloc(GetProcessHeap(), 0, sizeof(*browser));
272     browser->lpVtbl = &IShellBrowserImpl_Vtbl;
273     browser->ref = 1;
274
275     return (IShellBrowser*)browser;
276 }
277
278 static HRESULT WINAPI IShellBrowserImpl_QueryInterface(IShellBrowser *iface,
279                                             REFIID riid,
280                                             LPVOID *ppvObj)
281 {
282     IShellBrowserImpl *This = (IShellBrowserImpl *)iface;
283
284     *ppvObj = NULL;
285
286     if(IsEqualIID(riid, &IID_IUnknown)   ||
287        IsEqualIID(riid, &IID_IOleWindow) ||
288        IsEqualIID(riid, &IID_IShellBrowser))
289     {
290         *ppvObj = This;
291     }
292
293     if(*ppvObj)
294     {
295         IUnknown_AddRef(iface);
296         return S_OK;
297     }
298
299     return E_NOINTERFACE;
300 }
301
302 static ULONG WINAPI IShellBrowserImpl_AddRef(IShellBrowser * iface)
303 {
304     IShellBrowserImpl *This = (IShellBrowserImpl *)iface;
305     return InterlockedIncrement(&This->ref);
306 }
307
308 static ULONG WINAPI IShellBrowserImpl_Release(IShellBrowser * iface)
309 {
310     IShellBrowserImpl *This = (IShellBrowserImpl *)iface;
311     ULONG ref = InterlockedDecrement(&This->ref);
312
313     if (!ref)
314     {
315         HeapFree(GetProcessHeap(), 0, This);
316         return 0;
317     }
318     return ref;
319 }
320
321 static HRESULT WINAPI IShellBrowserImpl_GetWindow(IShellBrowser *iface,
322                                            HWND *phwnd)
323 {
324     if (phwnd) *phwnd = GetDesktopWindow();
325     return S_OK;
326 }
327
328 static HRESULT WINAPI IShellBrowserImpl_ContextSensitiveHelp(IShellBrowser *iface,
329                                                       BOOL fEnterMode)
330 {
331     return E_NOTIMPL;
332 }
333
334 static HRESULT WINAPI IShellBrowserImpl_BrowseObject(IShellBrowser *iface,
335                                               LPCITEMIDLIST pidl,
336                                               UINT wFlags)
337 {
338     return E_NOTIMPL;
339 }
340
341 static HRESULT WINAPI IShellBrowserImpl_EnableModelessSB(IShellBrowser *iface,
342                                               BOOL fEnable)
343
344 {
345     return E_NOTIMPL;
346 }
347
348 static HRESULT WINAPI IShellBrowserImpl_GetControlWindow(IShellBrowser *iface,
349                                               UINT id,
350                                               HWND *lphwnd)
351
352 {
353     return E_NOTIMPL;
354 }
355
356 static HRESULT WINAPI IShellBrowserImpl_GetViewStateStream(IShellBrowser *iface,
357                                                 DWORD mode,
358                                                 LPSTREAM *pStrm)
359
360 {
361     return E_NOTIMPL;
362 }
363
364 static HRESULT WINAPI IShellBrowserImpl_InsertMenusSB(IShellBrowser *iface,
365                                            HMENU hmenuShared,
366                                            LPOLEMENUGROUPWIDTHS lpMenuWidths)
367
368 {
369     return E_NOTIMPL;
370 }
371
372 static HRESULT WINAPI IShellBrowserImpl_OnViewWindowActive(IShellBrowser *iface,
373                                                 IShellView *ppshv)
374
375 {
376     return E_NOTIMPL;
377 }
378
379 static HRESULT WINAPI IShellBrowserImpl_QueryActiveShellView(IShellBrowser *iface,
380                                                   IShellView **ppshv)
381
382 {
383     return E_NOTIMPL;
384 }
385
386 static HRESULT WINAPI IShellBrowserImpl_RemoveMenusSB(IShellBrowser *iface,
387                                            HMENU hmenuShared)
388
389 {
390     return E_NOTIMPL;
391 }
392
393 static HRESULT WINAPI IShellBrowserImpl_SendControlMsg(IShellBrowser *iface,
394                                             UINT id,
395                                             UINT uMsg,
396                                             WPARAM wParam,
397                                             LPARAM lParam,
398                                             LRESULT *pret)
399
400 {
401     return E_NOTIMPL;
402 }
403
404 static HRESULT WINAPI IShellBrowserImpl_SetMenuSB(IShellBrowser *iface,
405                                        HMENU hmenuShared,
406                                        HOLEMENU holemenuReserved,
407                                        HWND hwndActiveObject)
408
409 {
410     return E_NOTIMPL;
411 }
412
413 static HRESULT WINAPI IShellBrowserImpl_SetStatusTextSB(IShellBrowser *iface,
414                                              LPCOLESTR lpszStatusText)
415
416 {
417     return E_NOTIMPL;
418 }
419
420 static HRESULT WINAPI IShellBrowserImpl_SetToolbarItems(IShellBrowser *iface,
421                                              LPTBBUTTON lpButtons,
422                                              UINT nButtons,
423                                              UINT uFlags)
424
425 {
426     return E_NOTIMPL;
427 }
428
429 static HRESULT WINAPI IShellBrowserImpl_TranslateAcceleratorSB(IShellBrowser *iface,
430                                                     LPMSG lpmsg,
431                                                     WORD wID)
432
433 {
434     return E_NOTIMPL;
435 }
436
437 static const IShellBrowserVtbl IShellBrowserImpl_Vtbl =
438 {
439     IShellBrowserImpl_QueryInterface,
440     IShellBrowserImpl_AddRef,
441     IShellBrowserImpl_Release,
442     IShellBrowserImpl_GetWindow,
443     IShellBrowserImpl_ContextSensitiveHelp,
444     IShellBrowserImpl_InsertMenusSB,
445     IShellBrowserImpl_SetMenuSB,
446     IShellBrowserImpl_RemoveMenusSB,
447     IShellBrowserImpl_SetStatusTextSB,
448     IShellBrowserImpl_EnableModelessSB,
449     IShellBrowserImpl_TranslateAcceleratorSB,
450     IShellBrowserImpl_BrowseObject,
451     IShellBrowserImpl_GetViewStateStream,
452     IShellBrowserImpl_GetControlWindow,
453     IShellBrowserImpl_SendControlMsg,
454     IShellBrowserImpl_QueryActiveShellView,
455     IShellBrowserImpl_OnViewWindowActive,
456     IShellBrowserImpl_SetToolbarItems
457 };
458
459 static const struct message empty_seq[] = {
460     { 0 }
461 };
462
463 static const struct message folderview_getspacing_seq[] = {
464     { LVM_GETITEMSPACING, wparam|sent, FALSE },
465     { 0 }
466 };
467
468 static const struct message folderview_getselectionmarked_seq[] = {
469     { LVM_GETSELECTIONMARK, sent },
470     { 0 }
471 };
472
473 static const struct message folderview_getfocused_seq[] = {
474     { LVM_GETNEXTITEM, sent|wparam|lparam|optional, -1, LVNI_FOCUSED },
475     { 0 }
476 };
477
478 static const struct message folderview_itemcount_seq[] = {
479     { LVM_GETITEMCOUNT, sent },
480     { 0 }
481 };
482
483 static void test_IShellView_CreateViewWindow(void)
484 {
485     IShellFolder *desktop;
486     FOLDERSETTINGS settings;
487     IShellView *view;
488     IDropTarget *dt;
489     HWND hwnd_view;
490     HRESULT hr;
491     RECT r = {0};
492
493     hr = SHGetDesktopFolder(&desktop);
494     ok(hr == S_OK, "got (0x%08x)\n", hr);
495
496     hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
497     ok(hr == S_OK, "got (0x%08x)\n", hr);
498
499 if (0)
500 {
501     /* crashes on native */
502     hr = IShellView_CreateViewWindow(view, NULL, &settings, NULL, NULL, NULL);
503 }
504
505     settings.ViewMode = FVM_ICON;
506     settings.fFlags = 0;
507     hwnd_view = (HWND)0xdeadbeef;
508     hr = IShellView_CreateViewWindow(view, NULL, &settings, NULL, NULL, &hwnd_view);
509     ok(hr == E_UNEXPECTED, "got (0x%08x)\n", hr);
510     ok(hwnd_view == 0, "got %p\n", hwnd_view);
511
512     hwnd_view = (HWND)0xdeadbeef;
513     hr = IShellView_CreateViewWindow(view, NULL, &settings, NULL, &r, &hwnd_view);
514     ok(hr == E_UNEXPECTED, "got (0x%08x)\n", hr);
515     ok(hwnd_view == 0, "got %p\n", hwnd_view);
516
517     /* ::DragLeave without drag operation */
518     hr = IShellView_QueryInterface(view, &IID_IDropTarget, (void**)&dt);
519     ok(hr == S_OK, "got (0x%08x)\n", hr);
520     hr = IDropTarget_DragLeave(dt);
521     ok(hr == S_OK, "got (0x%08x)\n", hr);
522     IDropTarget_Release(dt);
523
524     IShellView_Release(view);
525     IShellFolder_Release(desktop);
526 }
527
528 static void test_IFolderView(void)
529 {
530     IShellFolder *desktop, *folder;
531     FOLDERSETTINGS settings;
532     IShellView *view;
533     IShellBrowser *browser;
534     IFolderView *fv;
535     HWND hwnd_view, hwnd_list;
536     PITEMID_CHILD pidl;
537     HRESULT hr;
538     INT ret, count;
539     POINT pt;
540     LONG ref1, ref2;
541     RECT r;
542
543     hr = SHGetDesktopFolder(&desktop);
544     ok(hr == S_OK, "got (0x%08x)\n", hr);
545
546     hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
547     ok(hr == S_OK, "got (0x%08x)\n", hr);
548
549     hr = IShellView_QueryInterface(view, &IID_IFolderView, (void**)&fv);
550     if (hr != S_OK)
551     {
552         win_skip("IFolderView not supported by desktop folder\n");
553         IShellView_Release(view);
554         IShellFolder_Release(desktop);
555         return;
556     }
557
558     /* call methods before window creation */
559     hr = IFolderView_GetSpacing(fv, NULL);
560     ok(hr == S_FALSE || broken(hr == S_OK) /* win7 */, "got (0x%08x)\n", hr);
561
562     pidl = (void*)0xdeadbeef;
563     hr = IFolderView_Item(fv, 0, &pidl);
564     ok(hr == E_INVALIDARG || broken(hr == E_FAIL) /* < Vista */, "got (0x%08x)\n", hr);
565     ok(pidl == 0 || broken(pidl == (void*)0xdeadbeef) /* < Vista */, "got %p\n", pidl);
566
567 if (0)
568 {
569     /* crashes on Vista and Win2k8 - List not created yet case */
570     hr = IFolderView_GetSpacing(fv, &pt);
571
572     /* crashes on XP */
573     hr = IFolderView_GetSelectionMarkedItem(fv, NULL);
574     hr = IFolderView_GetFocusedItem(fv, NULL);
575
576     /* crashes on Vista+ */
577     hr = IFolderView_Item(fv, 0, NULL);
578 }
579
580     browser = IShellBrowserImpl_Construct();
581
582     settings.ViewMode = FVM_ICON;
583     settings.fFlags = 0;
584     hwnd_view = (HWND)0xdeadbeef;
585     r.left = r.top = 0;
586     r.right = r.bottom = 100;
587     hr = IShellView_CreateViewWindow(view, NULL, &settings, browser, &r, &hwnd_view);
588     ok(hr == S_OK, "got (0x%08x)\n", hr);
589     ok(IsWindow(hwnd_view), "got %p\n", hwnd_view);
590
591     hwnd_list = subclass_listview(hwnd_view);
592     if (!hwnd_list)
593     {
594         win_skip("Failed to subclass ListView control\n");
595         IShellBrowser_Release(browser);
596         IFolderView_Release(fv);
597         IShellView_Release(view);
598         IShellFolder_Release(desktop);
599         return;
600     }
601
602     /* IFolderView::GetSpacing */
603     flush_sequences(sequences, NUM_MSG_SEQUENCES);
604     hr = IFolderView_GetSpacing(fv, NULL);
605     ok(hr == S_OK, "got (0x%08x)\n", hr);
606     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, empty_seq, "IFolderView::GetSpacing, empty", FALSE);
607
608     flush_sequences(sequences, NUM_MSG_SEQUENCES);
609     hr = IFolderView_GetSpacing(fv, &pt);
610     ok(hr == S_OK, "got (0x%08x)\n", hr);
611     /* fails with empty sequence on win7 for unknown reason */
612     if (sequences[LISTVIEW_SEQ_INDEX]->count)
613     {
614         ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_getspacing_seq, "IFolderView::GetSpacing", FALSE);
615         ok(pt.x > 0, "got %d\n", pt.x);
616         ok(pt.y > 0, "got %d\n", pt.y);
617         ret = SendMessageA(hwnd_list, LVM_GETITEMSPACING, 0, 0);
618         ok(pt.x == LOWORD(ret) && pt.y == HIWORD(ret), "got (%d, %d)\n", LOWORD(ret), HIWORD(ret));
619     }
620
621     /* IFolderView::ItemCount */
622 if (0)
623 {
624     /* crashes on XP */
625     hr = IFolderView_ItemCount(fv, SVGIO_ALLVIEW, NULL);
626 }
627
628     flush_sequences(sequences, NUM_MSG_SEQUENCES);
629     hr = IFolderView_ItemCount(fv, SVGIO_ALLVIEW, &count);
630     ok(hr == S_OK, "got (0x%08x)\n", hr);
631     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, count ? folderview_itemcount_seq : empty_seq,
632                                   "IFolderView::ItemCount", FALSE);
633
634     /* IFolderView::GetSelectionMarkedItem */
635 if (0)
636 {
637     /* crashes on XP */
638     hr = IFolderView_GetSelectionMarkedItem(fv, NULL);
639 }
640
641     flush_sequences(sequences, NUM_MSG_SEQUENCES);
642     hr = IFolderView_GetSelectionMarkedItem(fv, &ret);
643     if (count)
644         ok(hr == S_OK, "got (0x%08x)\n", hr);
645     else
646         ok(hr == S_FALSE, "got (0x%08x)\n", hr);
647     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_getselectionmarked_seq,
648                 "IFolderView::GetSelectionMarkedItem", FALSE);
649
650     /* IFolderView::GetFocusedItem */
651     flush_sequences(sequences, NUM_MSG_SEQUENCES);
652     hr = IFolderView_GetFocusedItem(fv, &ret);
653     if (count)
654         ok(hr == S_OK, "got (0x%08x)\n", hr);
655     else
656         ok(hr == S_FALSE, "got (0x%08x)\n", hr);
657     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_getfocused_seq,
658                 "IFolderView::GetFocusedItem", FALSE);
659
660     /* IFolderView::GetFolder, just return pointer */
661 if (0)
662 {
663     /* crashes on XP */
664     hr = IFolderView_GetFolder(fv, NULL, (void**)&folder);
665     hr = IFolderView_GetFolder(fv, NULL, NULL);
666 }
667
668     hr = IFolderView_GetFolder(fv, &IID_IShellFolder, NULL);
669     ok(hr == E_POINTER, "got (0x%08x)\n", hr);
670
671     ref1 = IShellFolder_AddRef(desktop);
672     IShellFolder_Release(desktop);
673     hr = IFolderView_GetFolder(fv, &IID_IShellFolder, (void**)&folder);
674     ok(hr == S_OK, "got (0x%08x)\n", hr);
675     ref2 = IShellFolder_AddRef(desktop);
676     IShellFolder_Release(desktop);
677     ok(ref1 == ref2 || ref1 + 1 == ref2, /* >= vista */
678        "expected same refcount, got %d\n", ref2);
679     ok(desktop == folder, "\n");
680
681     IShellBrowser_Release(browser);
682     IFolderView_Release(fv);
683     IShellView_Release(view);
684     IShellFolder_Release(desktop);
685 }
686
687 static void test_GetItemObject(void)
688 {
689     IShellFolder *desktop;
690     IShellView *view;
691     IUnknown *unk;
692     HRESULT hr;
693
694     hr = SHGetDesktopFolder(&desktop);
695     ok(hr == S_OK, "got (0x%08x)\n", hr);
696
697     hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
698     ok(hr == S_OK, "got (0x%08x)\n", hr);
699
700     /* from documentation three interfaces are supported for SVGIO_BACKGROUND:
701        IContextMenu, IDispatch, IPersistHistory */
702     hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IContextMenu, (void**)&unk);
703     ok(hr == S_OK, "got (0x%08x)\n", hr);
704     IUnknown_Release(unk);
705
706     unk = NULL;
707     hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&unk);
708     todo_wine ok(hr == S_OK || broken(hr == E_NOTIMPL) /* NT4 */, "got (0x%08x)\n", hr);
709     if (unk) IUnknown_Release(unk);
710
711     unk = NULL;
712     hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IPersistHistory, (void**)&unk);
713     todo_wine ok(hr == S_OK || broken(hr == E_NOTIMPL) /* W9x, NT4 */, "got (0x%08x)\n", hr);
714     if (unk) IUnknown_Release(unk);
715
716     /* example of unsupported interface, base for IPersistHistory */
717     hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IPersist, (void**)&unk);
718     ok(hr == E_NOINTERFACE || broken(hr == E_NOTIMPL) /* W2K */, "got (0x%08x)\n", hr);
719
720     IShellView_Release(view);
721     IShellFolder_Release(desktop);
722 }
723
724 static void test_IShellFolderView(void)
725 {
726     IShellFolderView *folderview;
727     IShellFolder *desktop;
728     IShellView *view;
729     IDataObject *obj;
730     UINT i;
731     HRESULT hr;
732
733     hr = SHGetDesktopFolder(&desktop);
734     ok(hr == S_OK, "got (0x%08x)\n", hr);
735
736     hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
737     ok(hr == S_OK, "got (0x%08x)\n", hr);
738
739     hr = IShellView_QueryInterface(view, &IID_IShellFolderView, (void**)&folderview);
740     if (hr != S_OK)
741     {
742         win_skip("IShellView doesn't provide IShellFolderView on this platform\n");
743         IShellView_Release(view);
744         IShellFolder_Release(desktop);
745         return;
746     }
747
748     /* ::MoveIcons */
749     obj = IDataObjectImpl_Construct();
750     hr = IShellFolderView_MoveIcons(folderview, obj);
751     ok(hr == E_NOTIMPL || broken(hr == S_OK) /* W98 */, "got (0x%08x)\n", hr);
752     IDataObject_Release(obj);
753
754     /* ::SetRedraw without list created */
755     hr = IShellFolderView_SetRedraw(folderview, TRUE);
756     ok(hr == S_OK, "got (0x%08x)\n", hr);
757
758     /* ::QuerySupport */
759     hr = IShellFolderView_QuerySupport(folderview, NULL);
760     ok(hr == S_OK, "got (0x%08x)\n", hr);
761     i = 0xdeadbeef;
762     hr = IShellFolderView_QuerySupport(folderview, &i);
763     ok(hr == S_OK, "got (0x%08x)\n", hr);
764     ok(i == 0xdeadbeef, "got %d\n", i);
765
766     /* ::RemoveObject */
767     i = 0xdeadbeef;
768     hr = IShellFolderView_RemoveObject(folderview, NULL, &i);
769     ok(hr == S_OK, "got (0x%08x)\n", hr);
770     ok(i == 0 || i == -1 /* Win7 */ || broken(i == 0xdeadbeef) /* Vista, 2k8 */,
771         "got %d\n", i);
772
773     IShellFolderView_Release(folderview);
774
775     IShellView_Release(view);
776     IShellFolder_Release(desktop);
777 }
778
779 static void test_IOleWindow(void)
780 {
781     IShellFolder *desktop;
782     IShellView *view;
783     HRESULT hr;
784
785     hr = SHGetDesktopFolder(&desktop);
786     ok(hr == S_OK, "got (0x%08x)\n", hr);
787
788     hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
789     ok(hr == S_OK, "got (0x%08x)\n", hr);
790
791     /* IShellView::ContextSensitiveHelp */
792     hr = IShellView_ContextSensitiveHelp(view, TRUE);
793     ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
794     hr = IShellView_ContextSensitiveHelp(view, FALSE);
795     ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
796
797     IShellView_Release(view);
798     IShellFolder_Release(desktop);
799 }
800
801 static const struct message folderview_setcurrentviewmode1_2_prevista[] = {
802     { LVM_SETVIEW, sent|wparam, LV_VIEW_ICON},
803     { LVM_SETIMAGELIST, sent|wparam, 0},
804     { LVM_SETIMAGELIST, sent|wparam, 1},
805     { 0x105a, sent},
806     { LVM_SETBKIMAGEW, sent|optional},    /* w2k3 */
807     { LVM_GETBKCOLOR, sent|optional},     /* w2k3 */
808     { LVM_GETTEXTBKCOLOR, sent|optional}, /* w2k3 */
809     { LVM_GETTEXTCOLOR, sent|optional},   /* w2k3 */
810     { LVM_SETEXTENDEDLISTVIEWSTYLE, sent|optional|wparam, 0xc8}, /* w2k3 */
811     { LVM_ARRANGE, sent },
812     { LVM_ARRANGE, sent|optional },       /* WinXP */
813     { 0 }
814 };
815
816 static const struct message folderview_setcurrentviewmode3_prevista[] = {
817     { LVM_SETVIEW, sent|wparam, LV_VIEW_LIST},
818     { LVM_SETIMAGELIST, sent|wparam, 0},
819     { LVM_SETIMAGELIST, sent|wparam, 1},
820     { 0x105a, sent},
821     { LVM_SETBKIMAGEW, sent|optional},    /* w2k3 */
822     { LVM_GETBKCOLOR, sent|optional},     /* w2k3 */
823     { LVM_GETTEXTBKCOLOR, sent|optional}, /* w2k3 */
824     { LVM_GETTEXTCOLOR, sent|optional},   /* w2k3 */
825     { LVM_SETEXTENDEDLISTVIEWSTYLE, sent|optional|wparam, 0xc8}, /* w2k3 */
826     { 0 }
827 };
828
829 static const struct message folderview_setcurrentviewmode4_prevista[] = {
830     { LVM_GETHEADER, sent},
831     { LVM_GETITEMCOUNT, sent|optional },
832     { LVM_SETSELECTEDCOLUMN, sent},
833     { WM_NOTIFY, sent },
834     { WM_NOTIFY, sent },
835     { WM_NOTIFY, sent },
836     { WM_NOTIFY, sent },
837     { LVM_SETVIEW, sent|wparam, LV_VIEW_DETAILS},
838     { LVM_SETIMAGELIST, sent|wparam, 0},
839     { LVM_SETIMAGELIST, sent|wparam, 1},
840     { 0x105a, sent},
841     { LVM_SETBKIMAGEW, sent|optional},    /* w2k3 */
842     { LVM_GETBKCOLOR, sent|optional},     /* w2k3 */
843     { LVM_GETTEXTBKCOLOR, sent|optional}, /* w2k3 */
844     { LVM_GETTEXTCOLOR, sent|optional},   /* w2k3 */
845     { LVM_SETEXTENDEDLISTVIEWSTYLE, sent|optional|wparam, 0xc8}, /* w2k3 */
846     { 0 }
847 };
848
849 /* XP, SetCurrentViewMode(5)
850    108e - LVM_SETVIEW (LV_VIEW_ICON);
851    1036 - LVM_SETEXTEDEDLISTVIEWSTYLE (0x8000, 0)
852    100c/104c repeated X times
853    1003 - LVM_SETIMAGELIST
854    1035 - LVM_SETICONSPACING
855    1004 - LVM_GETITEMCOUNT
856    105a - ?
857    1016 - LVM_ARRANGE
858    1016 - LVM_ARRANGE
859 */
860
861 /* XP, SetCurrentViewMode(6)
862    1036 - LVM_SETEXTENDEDLISTVIEWSTYLE (0x8000, 0)
863    1035 - LVM_SETICONSPACING
864    1003 - LVM_SETIMAGELIST
865    1003 - LVM_SETIMAGELIST
866    100c/104c repeated X times
867    10a2 - LVM_SETTILEVIEWINFO
868    108e - LVM_SETVIEW (LV_VIEW_TILE)
869    1003 - LVM_SETIMAGELIST
870    105a - ?
871    1016 - LVM_ARRANGE
872    1016 - LVM_ARRANGE
873 */
874
875 /* XP, SetCurrentViewMode (7)
876    10a2 - LVM_SETTILEVIEWINFO
877    108e - LVM_SETVIEW (LV_VIEW_ICON)
878    1004/10a4 (LVM_GETITEMCOUNT/LVM_SETTILEINFO) X times
879    1016 - LVM_ARRANGE
880    1016 - LVM_ARRANGE
881    ...
882    LVM_SETEXTENDEDLISTVIEWSTYLE (0x40000, 0x40000)
883    ...
884    LVM_SETEXTENDEDLISTVIEWSTYLE (0x8000, 0x8000)
885 */
886
887 static void test_GetSetCurrentViewMode(void)
888 {
889     IShellFolder *desktop;
890     IShellView *sview;
891     IFolderView *fview;
892     IShellBrowser *browser;
893     FOLDERSETTINGS fs;
894     UINT viewmode;
895     HWND hwnd;
896     RECT rc = {0, 0, 10, 10};
897     HRESULT hr;
898     UINT i;
899     static const int winxp_res[11] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
900     static const int win2k3_res[11] = {0, 1, 2, 3, 4, 5, 6, 5, 8, 0, 0};
901     static const int vista_res[11] = {0, 1, 5, 3, 4, 5, 6, 7, 7, 0, 0};
902     static const int win7_res[11] = {1, 1, 1, 3, 4, 1, 6, 1, 8, 8, 8};
903
904     hr = SHGetDesktopFolder(&desktop);
905     ok(hr == S_OK, "got (0x%08x)\n", hr);
906
907     hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&sview);
908     ok(hr == S_OK, "got (0x%08x)\n", hr);
909
910     fs.ViewMode = 1;
911     fs.fFlags = 0;
912     browser = IShellBrowserImpl_Construct();
913     hr = IShellView_CreateViewWindow(sview, NULL, &fs, browser, &rc, &hwnd);
914     ok(hr == S_OK || broken(hr == S_FALSE /*Win2k*/ ), "got (0x%08x)\n", hr);
915
916     hr = IShellView_QueryInterface(sview, &IID_IFolderView, (void**)&fview);
917     ok(hr == S_OK || broken(hr == E_NOINTERFACE), "got (0x%08x)\n", hr);
918     if(SUCCEEDED(hr))
919     {
920         HWND hwnd_lv;
921         UINT count;
922
923         if(0)
924         {
925             /* Crashes under Win7/WinXP */
926             hr = IFolderView_GetCurrentViewMode(fview, NULL);
927         }
928
929         hr = IFolderView_GetCurrentViewMode(fview, &viewmode);
930         ok(hr == S_OK, "got (0x%08x)\n", hr);
931         ok(viewmode == 1, "ViewMode was %d\n", viewmode);
932
933         hr = IFolderView_SetCurrentViewMode(fview, FVM_AUTO);
934         ok(hr == S_OK, "got (0x%08x)\n", hr);
935
936         hr = IFolderView_SetCurrentViewMode(fview, 0);
937         ok(hr == E_INVALIDARG || broken(hr == S_OK),
938            "got (0x%08x)\n", hr);
939
940         hr = IFolderView_GetCurrentViewMode(fview, &viewmode);
941         ok(hr == S_OK, "got (0x%08x)\n", hr);
942
943         for(i = 1; i < 9; i++)
944         {
945             hr = IFolderView_SetCurrentViewMode(fview, i);
946             ok(hr == S_OK || (i == 8 && hr == E_INVALIDARG /*Vista*/),
947                "(%d) got (0x%08x)\n", i, hr);
948
949             hr = IFolderView_GetCurrentViewMode(fview, &viewmode);
950             ok(hr == S_OK, "(%d) got (0x%08x)\n", i, hr);
951
952             /* Wine currently behaves like winxp here. */
953             ok((viewmode == win7_res[i]) || (viewmode == vista_res[i]) ||
954                (viewmode == win2k3_res[i]) || (viewmode == winxp_res[i]),
955                "(%d) got %d\n",i , viewmode);
956         }
957
958         hr = IFolderView_SetCurrentViewMode(fview, 9);
959         ok(hr == E_INVALIDARG || broken(hr == S_OK),
960            "got (0x%08x)\n", hr);
961
962         /* Test messages */
963         hwnd_lv = subclass_listview(hwnd);
964         ok(hwnd_lv != NULL, "Failed to subclass listview\n");
965         if(hwnd_lv)
966         {
967             /* Vista seems to set the viewmode by other means than
968                sending messages. At least no related messages are
969                captured by subclassing.
970             */
971             BOOL vista_plus = FALSE;
972             static const UINT vista_plus_msgs[] = {
973                 WM_SETREDRAW, WM_NOTIFY, WM_NOTIFYFORMAT, WM_QUERYUISTATE,
974                 WM_MENUCHAR, WM_WINDOWPOSCHANGING, WM_NCCALCSIZE, WM_WINDOWPOSCHANGED,
975                 WM_PARENTNOTIFY, LVM_GETHEADER, 0 };
976
977             flush_sequences(sequences, NUM_MSG_SEQUENCES);
978             hr = IFolderView_SetCurrentViewMode(fview, 1);
979             ok(hr == S_OK, "got 0x%08x\n", hr);
980
981             /* WM_SETREDRAW is not sent in versions before Vista. */
982             vista_plus = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, WM_SETREDRAW);
983             if(vista_plus)
984                 verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
985             else
986                 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_setcurrentviewmode1_2_prevista,
987                             "IFolderView::SetCurrentViewMode(1)", TRUE);
988
989             hr = IFolderView_SetCurrentViewMode(fview, 2);
990             ok(hr == S_OK, "got 0x%08x\n", hr);
991             if(vista_plus)
992                 verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
993             else
994                 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_setcurrentviewmode1_2_prevista,
995                             "IFolderView::SetCurrentViewMode(2)", TRUE);
996
997             hr = IFolderView_SetCurrentViewMode(fview, 3);
998             ok(hr == S_OK, "got 0x%08x\n", hr);
999             if(vista_plus)
1000                 verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
1001             else
1002                 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_setcurrentviewmode3_prevista,
1003                             "IFolderView::SetCurrentViewMode(3)", TRUE);
1004
1005             hr = IFolderView_SetCurrentViewMode(fview, 4);
1006             ok(hr == S_OK, "got 0x%08x\n", hr);
1007             if(vista_plus)
1008                 verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
1009             else
1010                 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_setcurrentviewmode4_prevista,
1011                             "IFolderView::SetCurrentViewMode(4)", TRUE);
1012
1013             hr = IFolderView_SetCurrentViewMode(fview, 5);
1014             ok(hr == S_OK, "got 0x%08x\n", hr);
1015             todo_wine
1016             {
1017                 if(vista_plus)
1018                 {
1019                     verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
1020                 }
1021                 else
1022                 {
1023                     count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETVIEW);
1024                     ok(count == 1, "LVM_SETVIEW sent %d times.\n", count);
1025                     count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETEXTENDEDLISTVIEWSTYLE);
1026                     ok(count == 1 || count == 2, "LVM_SETEXTENDEDLISTVIEWSTYLE sent %d times.\n", count);
1027                     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1028                 }
1029             }
1030
1031             hr = IFolderView_SetCurrentViewMode(fview, 6);
1032             ok(hr == S_OK, "got 0x%08x\n", hr);
1033             todo_wine
1034             {
1035                 if(vista_plus)
1036                 {
1037                     verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
1038                 }
1039                 else
1040                 {
1041                     count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETVIEW);
1042                     ok(count == 1, "LVM_SETVIEW sent %d times.\n", count);
1043                     count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETEXTENDEDLISTVIEWSTYLE);
1044                     ok(count == 1 || count == 2, "LVM_SETEXTENDEDLISTVIEWSTYLE sent %d times.\n", count);
1045                     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1046                 }
1047             }
1048
1049             hr = IFolderView_SetCurrentViewMode(fview, 7);
1050             ok(hr == S_OK, "got 0x%08x\n", hr);
1051             todo_wine
1052             {
1053                 if(vista_plus)
1054                 {
1055                     verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
1056                 }
1057                 else
1058                 {
1059                     count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETVIEW);
1060                     ok(count == 1, "LVM_SETVIEW sent %d times.\n", count);
1061                     count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETEXTENDEDLISTVIEWSTYLE);
1062                     ok(count == 2, "LVM_SETEXTENDEDLISTVIEWSTYLE sent %d times.\n", count);
1063                     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1064                 }
1065             }
1066
1067             hr = IFolderView_SetCurrentViewMode(fview, 8);
1068             ok(hr == S_OK || broken(hr == E_INVALIDARG /* Vista */), "got 0x%08x\n", hr);
1069             todo_wine
1070             {
1071                 if(vista_plus)
1072                 {
1073                     verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
1074                 }
1075                 else
1076                 {
1077                     count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETVIEW);
1078                     ok(count == 1, "LVM_SETVIEW sent %d times.\n", count);
1079                     count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETEXTENDEDLISTVIEWSTYLE);
1080                     ok(count == 2, "LVM_SETEXTENDEDLISTVIEWSTYLE sent %d times.\n", count);
1081                     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1082                 }
1083             }
1084
1085             hr = IFolderView_GetCurrentViewMode(fview, &viewmode);
1086             ok(hr == S_OK, "Failed to get current viewmode.\n");
1087             ok_sequence(sequences, LISTVIEW_SEQ_INDEX, empty_seq,
1088                         "IFolderView::GetCurrentViewMode", FALSE);
1089         }
1090
1091         IFolderView_Release(fview);
1092     }
1093     else
1094     {
1095         skip("No IFolderView for the desktop folder.\n");
1096     }
1097
1098     IShellView_DestroyViewWindow(sview);
1099     IShellView_Release(sview);
1100     IShellFolder_Release(desktop);
1101 }
1102
1103 START_TEST(shlview)
1104 {
1105     OleInitialize(NULL);
1106
1107     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
1108
1109     test_IShellView_CreateViewWindow();
1110     test_IFolderView();
1111     test_GetItemObject();
1112     test_IShellFolderView();
1113     test_IOleWindow();
1114     test_GetSetCurrentViewMode();
1115
1116     OleUninitialize();
1117 }