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/heap.h"
42 #include "wine/test.h"
43 
44 #include "msg.h"
45 
46 #ifdef __REACTOS__
47 #include <reactos/undocshell.h>
48 #endif
49 
50 #define LISTVIEW_SEQ_INDEX  0
51 #define NUM_MSG_SEQUENCES   1
52 
53 DEFINE_GUID(IID_IPersistHistory, 0x91a565c1, 0xe38f, 0x11d0, 0x94, 0xbf, 0x00, 0xa0, 0xc9, 0x05, 0x5c, 0xbf);
54 
55 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
56 
57 static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
58 {
59     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
60     static LONG defwndproc_counter = 0;
61     struct message msg = { 0 };
62     LRESULT ret;
63 
64     msg.message = message;
65     msg.flags = sent|wparam|lparam;
66     if (defwndproc_counter) msg.flags |= defwinproc;
67     msg.wParam = wParam;
68     msg.lParam = lParam;
69     add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
70 
71     defwndproc_counter++;
72     ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
73     defwndproc_counter--;
74     return ret;
75 }
76 
77 static HWND subclass_listview(HWND hwnd)
78 {
79     WNDPROC oldproc;
80     HWND listview;
81 
82     /* listview is a first child */
83     listview = FindWindowExA(hwnd, NULL, WC_LISTVIEWA, NULL);
84     if(!listview)
85     {
86         /* .. except for some versions of Windows XP, where things
87            are slightly more complicated. */
88         HWND hwnd_tmp;
89         hwnd_tmp = FindWindowExA(hwnd, NULL, "DUIViewWndClassName", NULL);
90         hwnd_tmp = FindWindowExA(hwnd_tmp, NULL, "DirectUIHWND", NULL);
91         hwnd_tmp = FindWindowExA(hwnd_tmp, NULL, "CtrlNotifySink", NULL);
92         listview = FindWindowExA(hwnd_tmp, NULL, WC_LISTVIEWA, NULL);
93     }
94 
95     oldproc = (WNDPROC)SetWindowLongPtrA(listview, GWLP_WNDPROC,
96                                         (LONG_PTR)listview_subclass_proc);
97     SetWindowLongPtrA(listview, GWLP_USERDATA, (LONG_PTR)oldproc);
98 
99     return listview;
100 }
101 
102 static UINT get_msg_count(struct msg_sequence **seq, int sequence_index, UINT message)
103 {
104     struct msg_sequence *msg_seq = seq[sequence_index];
105     UINT i, count = 0;
106 
107     for(i = 0; i < msg_seq->count ; i++)
108         if(msg_seq->sequence[i].message == message)
109             count++;
110 
111     return count;
112 }
113 
114 /* Checks that every message in the sequence seq is also present in
115  * the UINT array msgs */
116 static void verify_msgs_in_(struct msg_sequence *seq, const UINT *msgs,
117                            const char *file, int line)
118 {
119     UINT i, j, msg, failcount = 0;
120     for(i = 0; i < seq->count; i++)
121     {
122         BOOL found = FALSE;
123         msg = seq->sequence[i].message;
124         for(j = 0; msgs[j] != 0; j++)
125             if(msgs[j] == msg) found = TRUE;
126 
127         if(!found)
128         {
129             failcount++;
130             trace("Unexpected message %d\n", msg);
131         }
132     }
133     ok_(file, line) (!failcount, "%d failures.\n", failcount);
134     flush_sequences(sequences, NUM_MSG_SEQUENCES);
135 }
136 
137 #define verify_msgs_in(seq, msgs)               \
138     verify_msgs_in_(seq, msgs, __FILE__, __LINE__)
139 
140 /* dummy IDataObject implementation */
141 typedef struct {
142     IDataObject IDataObject_iface;
143     LONG ref;
144 } IDataObjectImpl;
145 
146 static const IDataObjectVtbl IDataObjectImpl_Vtbl;
147 
148 static inline IDataObjectImpl *impl_from_IDataObject(IDataObject *iface)
149 {
150     return CONTAINING_RECORD(iface, IDataObjectImpl, IDataObject_iface);
151 }
152 
153 static IDataObject* IDataObjectImpl_Construct(void)
154 {
155     IDataObjectImpl *obj;
156 
157     obj = heap_alloc(sizeof(*obj));
158     obj->IDataObject_iface.lpVtbl = &IDataObjectImpl_Vtbl;
159     obj->ref = 1;
160 
161     return &obj->IDataObject_iface;
162 }
163 
164 static HRESULT WINAPI IDataObjectImpl_QueryInterface(IDataObject *iface, REFIID riid, void **ppvObj)
165 {
166     IDataObjectImpl *This = impl_from_IDataObject(iface);
167 
168     if (IsEqualIID(riid, &IID_IUnknown) ||
169         IsEqualIID(riid, &IID_IDataObject))
170     {
171         *ppvObj = &This->IDataObject_iface;
172     }
173 
174     if(*ppvObj)
175     {
176         IDataObject_AddRef(iface);
177         return S_OK;
178     }
179 
180     return E_NOINTERFACE;
181 }
182 
183 static ULONG WINAPI IDataObjectImpl_AddRef(IDataObject * iface)
184 {
185     IDataObjectImpl *This = impl_from_IDataObject(iface);
186     return InterlockedIncrement(&This->ref);
187 }
188 
189 static ULONG WINAPI IDataObjectImpl_Release(IDataObject * iface)
190 {
191     IDataObjectImpl *This = impl_from_IDataObject(iface);
192     ULONG ref = InterlockedDecrement(&This->ref);
193 
194     if (!ref)
195         heap_free(This);
196 
197     return ref;
198 }
199 
200 static HRESULT WINAPI IDataObjectImpl_GetData(IDataObject *iface, FORMATETC *pformat, STGMEDIUM *pmedium)
201 {
202     return E_NOTIMPL;
203 }
204 
205 static HRESULT WINAPI IDataObjectImpl_GetDataHere(IDataObject *iface, FORMATETC *pformat, STGMEDIUM *pmedium)
206 {
207     return E_NOTIMPL;
208 }
209 
210 static HRESULT WINAPI IDataObjectImpl_QueryGetData(IDataObject *iface, FORMATETC *pformat)
211 {
212     return E_NOTIMPL;
213 }
214 
215 static HRESULT WINAPI IDataObjectImpl_GetCanonicalFormatEtc(
216     IDataObject *iface, FORMATETC *pformatIn, FORMATETC *pformatOut)
217 {
218     return E_NOTIMPL;
219 }
220 
221 static HRESULT WINAPI IDataObjectImpl_SetData(
222     IDataObject *iface, FORMATETC *pformat, STGMEDIUM *pmedium, BOOL release)
223 {
224     return E_NOTIMPL;
225 }
226 
227 static HRESULT WINAPI IDataObjectImpl_EnumFormatEtc(
228     IDataObject *iface, DWORD direction, IEnumFORMATETC **ppenumFormatEtc)
229 {
230     return E_NOTIMPL;
231 }
232 
233 static HRESULT WINAPI IDataObjectImpl_DAdvise(
234     IDataObject *iface, FORMATETC *pformatetc, DWORD advf, IAdviseSink *pSink, DWORD *pConnection)
235 {
236     return E_NOTIMPL;
237 }
238 
239 static HRESULT WINAPI IDataObjectImpl_DUnadvise(IDataObject *iface, DWORD connection)
240 {
241     return E_NOTIMPL;
242 }
243 
244 static HRESULT WINAPI IDataObjectImpl_EnumDAdvise(IDataObject *iface, IEnumSTATDATA **ppenumAdvise)
245 {
246     return E_NOTIMPL;
247 }
248 
249 static const IDataObjectVtbl IDataObjectImpl_Vtbl =
250 {
251     IDataObjectImpl_QueryInterface,
252     IDataObjectImpl_AddRef,
253     IDataObjectImpl_Release,
254     IDataObjectImpl_GetData,
255     IDataObjectImpl_GetDataHere,
256     IDataObjectImpl_QueryGetData,
257     IDataObjectImpl_GetCanonicalFormatEtc,
258     IDataObjectImpl_SetData,
259     IDataObjectImpl_EnumFormatEtc,
260     IDataObjectImpl_DAdvise,
261     IDataObjectImpl_DUnadvise,
262     IDataObjectImpl_EnumDAdvise
263 };
264 
265 /* dummy IShellBrowser implementation */
266 typedef struct {
267     IShellBrowser IShellBrowser_iface;
268     LONG ref;
269 } IShellBrowserImpl;
270 
271 static const IShellBrowserVtbl IShellBrowserImpl_Vtbl;
272 
273 static inline IShellBrowserImpl *impl_from_IShellBrowser(IShellBrowser *iface)
274 {
275     return CONTAINING_RECORD(iface, IShellBrowserImpl, IShellBrowser_iface);
276 }
277 
278 static IShellBrowser* IShellBrowserImpl_Construct(void)
279 {
280     IShellBrowserImpl *browser;
281 
282     browser = heap_alloc(sizeof(*browser));
283     browser->IShellBrowser_iface.lpVtbl = &IShellBrowserImpl_Vtbl;
284     browser->ref = 1;
285 
286     return &browser->IShellBrowser_iface;
287 }
288 
289 static HRESULT WINAPI IShellBrowserImpl_QueryInterface(IShellBrowser *iface,
290                                             REFIID riid,
291                                             LPVOID *ppvObj)
292 {
293     IShellBrowserImpl *This = impl_from_IShellBrowser(iface);
294 
295     *ppvObj = NULL;
296 
297     if(IsEqualIID(riid, &IID_IUnknown)   ||
298        IsEqualIID(riid, &IID_IOleWindow) ||
299        IsEqualIID(riid, &IID_IShellBrowser))
300     {
301         *ppvObj = &This->IShellBrowser_iface;
302     }
303 
304     if(*ppvObj)
305     {
306         IShellBrowser_AddRef(iface);
307         return S_OK;
308     }
309 
310     return E_NOINTERFACE;
311 }
312 
313 static ULONG WINAPI IShellBrowserImpl_AddRef(IShellBrowser * iface)
314 {
315     IShellBrowserImpl *This = impl_from_IShellBrowser(iface);
316     return InterlockedIncrement(&This->ref);
317 }
318 
319 static ULONG WINAPI IShellBrowserImpl_Release(IShellBrowser * iface)
320 {
321     IShellBrowserImpl *This = impl_from_IShellBrowser(iface);
322     ULONG ref = InterlockedDecrement(&This->ref);
323 
324     if (!ref)
325         heap_free(This);
326 
327     return ref;
328 }
329 
330 static HRESULT WINAPI IShellBrowserImpl_GetWindow(IShellBrowser *iface,
331                                            HWND *phwnd)
332 {
333     if (phwnd) *phwnd = GetDesktopWindow();
334     return S_OK;
335 }
336 
337 static HRESULT WINAPI IShellBrowserImpl_ContextSensitiveHelp(IShellBrowser *iface,
338                                                       BOOL fEnterMode)
339 {
340     return E_NOTIMPL;
341 }
342 
343 static HRESULT WINAPI IShellBrowserImpl_BrowseObject(IShellBrowser *iface,
344                                               LPCITEMIDLIST pidl,
345                                               UINT wFlags)
346 {
347     return E_NOTIMPL;
348 }
349 
350 static HRESULT WINAPI IShellBrowserImpl_EnableModelessSB(IShellBrowser *iface,
351                                               BOOL fEnable)
352 
353 {
354     return E_NOTIMPL;
355 }
356 
357 static HRESULT WINAPI IShellBrowserImpl_GetControlWindow(IShellBrowser *iface,
358                                               UINT id,
359                                               HWND *lphwnd)
360 
361 {
362     return E_NOTIMPL;
363 }
364 
365 static HRESULT WINAPI IShellBrowserImpl_GetViewStateStream(IShellBrowser *iface,
366                                                 DWORD mode,
367                                                 LPSTREAM *pStrm)
368 
369 {
370     return E_NOTIMPL;
371 }
372 
373 static HRESULT WINAPI IShellBrowserImpl_InsertMenusSB(IShellBrowser *iface,
374                                            HMENU hmenuShared,
375                                            LPOLEMENUGROUPWIDTHS lpMenuWidths)
376 
377 {
378     return E_NOTIMPL;
379 }
380 
381 static HRESULT WINAPI IShellBrowserImpl_OnViewWindowActive(IShellBrowser *iface,
382                                                 IShellView *ppshv)
383 
384 {
385     return E_NOTIMPL;
386 }
387 
388 static HRESULT WINAPI IShellBrowserImpl_QueryActiveShellView(IShellBrowser *iface,
389                                                   IShellView **ppshv)
390 
391 {
392     return E_NOTIMPL;
393 }
394 
395 static HRESULT WINAPI IShellBrowserImpl_RemoveMenusSB(IShellBrowser *iface,
396                                            HMENU hmenuShared)
397 
398 {
399     return E_NOTIMPL;
400 }
401 
402 static HRESULT WINAPI IShellBrowserImpl_SendControlMsg(IShellBrowser *iface,
403                                             UINT id,
404                                             UINT uMsg,
405                                             WPARAM wParam,
406                                             LPARAM lParam,
407                                             LRESULT *pret)
408 
409 {
410     return E_NOTIMPL;
411 }
412 
413 static HRESULT WINAPI IShellBrowserImpl_SetMenuSB(IShellBrowser *iface,
414                                        HMENU hmenuShared,
415                                        HOLEMENU holemenuReserved,
416                                        HWND hwndActiveObject)
417 
418 {
419     return E_NOTIMPL;
420 }
421 
422 static HRESULT WINAPI IShellBrowserImpl_SetStatusTextSB(IShellBrowser *iface,
423                                              LPCOLESTR lpszStatusText)
424 
425 {
426     return E_NOTIMPL;
427 }
428 
429 static HRESULT WINAPI IShellBrowserImpl_SetToolbarItems(IShellBrowser *iface,
430                                              LPTBBUTTON lpButtons,
431                                              UINT nButtons,
432                                              UINT uFlags)
433 
434 {
435     return E_NOTIMPL;
436 }
437 
438 static HRESULT WINAPI IShellBrowserImpl_TranslateAcceleratorSB(IShellBrowser *iface,
439                                                     LPMSG lpmsg,
440                                                     WORD wID)
441 
442 {
443     return E_NOTIMPL;
444 }
445 
446 static const IShellBrowserVtbl IShellBrowserImpl_Vtbl =
447 {
448     IShellBrowserImpl_QueryInterface,
449     IShellBrowserImpl_AddRef,
450     IShellBrowserImpl_Release,
451     IShellBrowserImpl_GetWindow,
452     IShellBrowserImpl_ContextSensitiveHelp,
453     IShellBrowserImpl_InsertMenusSB,
454     IShellBrowserImpl_SetMenuSB,
455     IShellBrowserImpl_RemoveMenusSB,
456     IShellBrowserImpl_SetStatusTextSB,
457     IShellBrowserImpl_EnableModelessSB,
458     IShellBrowserImpl_TranslateAcceleratorSB,
459     IShellBrowserImpl_BrowseObject,
460     IShellBrowserImpl_GetViewStateStream,
461     IShellBrowserImpl_GetControlWindow,
462     IShellBrowserImpl_SendControlMsg,
463     IShellBrowserImpl_QueryActiveShellView,
464     IShellBrowserImpl_OnViewWindowActive,
465     IShellBrowserImpl_SetToolbarItems
466 };
467 
468 static const struct message empty_seq[] = {
469     { 0 }
470 };
471 
472 static const struct message folderview_getspacing_seq[] = {
473     { LVM_GETITEMSPACING, wparam|sent, FALSE },
474     { 0 }
475 };
476 
477 static const struct message folderview_getselectionmarked_seq[] = {
478     { LVM_GETSELECTIONMARK, sent },
479     { 0 }
480 };
481 
482 static const struct message folderview_getfocused_seq[] = {
483     { LVM_GETNEXTITEM, sent|wparam|lparam|optional, -1, LVNI_FOCUSED },
484     { 0 }
485 };
486 
487 static HRESULT WINAPI shellbrowser_QueryInterface(IShellBrowser *iface, REFIID riid, void **ppv)
488 {
489     *ppv = NULL;
490 
491     if (IsEqualGUID(&IID_IShellBrowser, riid) ||
492         IsEqualGUID(&IID_IOleWindow, riid) ||
493         IsEqualGUID(&IID_IUnknown, riid))
494     {
495         *ppv = iface;
496     }
497 
498     if (*ppv)
499     {
500         IUnknown_AddRef((IUnknown*)*ppv);
501         return S_OK;
502     }
503 
504     return E_NOINTERFACE;
505 }
506 
507 static ULONG WINAPI shellbrowser_AddRef(IShellBrowser *iface)
508 {
509     return 2;
510 }
511 
512 static ULONG WINAPI shellbrowser_Release(IShellBrowser *iface)
513 {
514     return 1;
515 }
516 
517 static HRESULT WINAPI shellbrowser_GetWindow(IShellBrowser *iface, HWND *phwnd)
518 {
519     *phwnd = GetDesktopWindow();
520     return S_OK;
521 }
522 
523 static HRESULT WINAPI shellbrowser_ContextSensitiveHelp(IShellBrowser *iface, BOOL mode)
524 {
525     ok(0, "unexpected\n");
526     return E_NOTIMPL;
527 }
528 
529 static HRESULT WINAPI shellbrowser_InsertMenusSB(IShellBrowser *iface, HMENU hmenuShared,
530     OLEMENUGROUPWIDTHS *menuwidths)
531 {
532     return E_NOTIMPL;
533 }
534 
535 static HRESULT WINAPI shellbrowser_SetMenuSB(IShellBrowser *iface, HMENU hmenuShared,
536     HOLEMENU holemenuReserved, HWND hwndActiveObject)
537 {
538     return E_NOTIMPL;
539 }
540 
541 static HRESULT WINAPI shellbrowser_RemoveMenusSB(IShellBrowser *iface, HMENU hmenuShared)
542 {
543     return E_NOTIMPL;
544 }
545 
546 static HRESULT WINAPI shellbrowser_SetStatusTextSB(IShellBrowser *iface, LPCOLESTR text)
547 {
548     ok(0, "unexpected\n");
549     return E_NOTIMPL;
550 }
551 
552 static HRESULT WINAPI shellbrowser_EnableModelessSB(IShellBrowser *iface, BOOL enable)
553 {
554     ok(0, "unexpected\n");
555     return E_NOTIMPL;
556 }
557 
558 static HRESULT WINAPI shellbrowser_TranslateAcceleratorSB(IShellBrowser *iface, MSG *pmsg, WORD wID)
559 {
560     ok(0, "unexpected\n");
561     return E_NOTIMPL;
562 }
563 
564 static HRESULT WINAPI shellbrowser_BrowseObject(IShellBrowser *iface, LPCITEMIDLIST pidl, UINT flags)
565 {
566     ok(0, "unexpected\n");
567     return E_NOTIMPL;
568 }
569 
570 static HRESULT WINAPI shellbrowser_GetViewStateStream(IShellBrowser *iface, DWORD mode, IStream **stream)
571 {
572     return E_NOTIMPL;
573 }
574 
575 static HRESULT WINAPI shellbrowser_GetControlWindow(IShellBrowser *iface, UINT id, HWND *phwnd)
576 {
577     return E_NOTIMPL;
578 }
579 
580 static HRESULT WINAPI shellbrowser_SendControlMsg(IShellBrowser *iface, UINT id, UINT uMsg,
581     WPARAM wParam, LPARAM lParam, LRESULT *pret)
582 {
583     return E_NOTIMPL;
584 }
585 
586 static HRESULT WINAPI shellbrowser_QueryActiveShellView(IShellBrowser *iface, IShellView **view)
587 {
588     ok(0, "unexpected\n");
589     return E_NOTIMPL;
590 }
591 
592 static HRESULT WINAPI shellbrowser_OnViewWindowActive(IShellBrowser *iface, IShellView *view)
593 {
594     ok(0, "unexpected\n");
595     return E_NOTIMPL;
596 }
597 
598 static HRESULT WINAPI shellbrowser_SetToolbarItems(IShellBrowser *iface, LPTBBUTTONSB buttons,
599     UINT count, UINT flags)
600 {
601     return E_NOTIMPL;
602 }
603 
604 static const IShellBrowserVtbl shellbrowservtbl = {
605     shellbrowser_QueryInterface,
606     shellbrowser_AddRef,
607     shellbrowser_Release,
608     shellbrowser_GetWindow,
609     shellbrowser_ContextSensitiveHelp,
610     shellbrowser_InsertMenusSB,
611     shellbrowser_SetMenuSB,
612     shellbrowser_RemoveMenusSB,
613     shellbrowser_SetStatusTextSB,
614     shellbrowser_EnableModelessSB,
615     shellbrowser_TranslateAcceleratorSB,
616     shellbrowser_BrowseObject,
617     shellbrowser_GetViewStateStream,
618     shellbrowser_GetControlWindow,
619     shellbrowser_SendControlMsg,
620     shellbrowser_QueryActiveShellView,
621     shellbrowser_OnViewWindowActive,
622     shellbrowser_SetToolbarItems
623 };
624 
625 static IShellBrowser test_shellbrowser = { &shellbrowservtbl };
626 
627 static void test_CreateViewWindow(void)
628 {
629     IShellFolder *desktop;
630     HWND hwnd_view, hwnd2;
631     FOLDERSETTINGS settings;
632     IShellView *view;
633     IDropTarget *dt;
634     HRESULT hr;
635     RECT r = {0};
636     ULONG ref1, ref2;
637     IUnknown *unk;
638 
639     hr = SHGetDesktopFolder(&desktop);
640     ok(hr == S_OK, "got (0x%08x)\n", hr);
641 
642     hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
643     ok(hr == S_OK, "got (0x%08x)\n", hr);
644 
645     hr = IShellView_QueryInterface(view, &IID_CDefView, (void **)&unk);
646     ok(hr == S_OK, "got (0x%08x)\n", hr);
647     ok(unk == (IUnknown *)view, "got %p\n", unk);
648     IUnknown_Release(unk);
649 
650 if (0)
651 {
652     /* crashes on native */
653     IShellView_CreateViewWindow(view, NULL, &settings, NULL, NULL, NULL);
654 }
655 
656     settings.ViewMode = FVM_ICON;
657     settings.fFlags = 0;
658     hwnd_view = (HWND)0xdeadbeef;
659     hr = IShellView_CreateViewWindow(view, NULL, &settings, NULL, NULL, &hwnd_view);
660     ok(hr == E_UNEXPECTED, "got (0x%08x)\n", hr);
661     ok(hwnd_view == 0, "got %p\n", hwnd_view);
662 
663     hwnd_view = (HWND)0xdeadbeef;
664     hr = IShellView_CreateViewWindow(view, NULL, &settings, NULL, &r, &hwnd_view);
665     ok(hr == E_UNEXPECTED, "got (0x%08x)\n", hr);
666     ok(hwnd_view == 0, "got %p\n", hwnd_view);
667 
668     hwnd_view = NULL;
669     hr = IShellView_CreateViewWindow(view, NULL, &settings, &test_shellbrowser, &r, &hwnd_view);
670     ok(hr == S_OK || broken(hr == S_FALSE), "got (0x%08x)\n", hr);
671     ok(hwnd_view != 0, "got %p\n", hwnd_view);
672 
673     hwnd2 = (HWND)0xdeadbeef;
674     hr = IShellView_CreateViewWindow(view, NULL, &settings, &test_shellbrowser, &r, &hwnd2);
675     ok(hr == E_UNEXPECTED, "got (0x%08x)\n", hr);
676     ok(hwnd2 == NULL, "got %p\n", hwnd2);
677 
678     /* ::DragLeave without drag operation */
679     hr = IShellView_QueryInterface(view, &IID_IDropTarget, (void**)&dt);
680     ok(hr == S_OK, "got (0x%08x)\n", hr);
681     hr = IDropTarget_DragLeave(dt);
682     ok(hr == S_OK, "got (0x%08x)\n", hr);
683     IDropTarget_Release(dt);
684 
685     IShellView_AddRef(view);
686     ref1 = IShellView_Release(view);
687     hr = IShellView_DestroyViewWindow(view);
688     ok(hr == S_OK, "got (0x%08x)\n", hr);
689     ok(!IsWindow(hwnd_view), "hwnd %p still valid\n", hwnd_view);
690     ref2 = IShellView_Release(view);
691     ok(ref1 > ref2, "expected %u > %u\n", ref1, ref2);
692     ref1 = ref2;
693 
694     /* Show that releasing the shell view does not destroy the window */
695     hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
696     ok(hr == S_OK, "got (0x%08x)\n", hr);
697     hwnd_view = NULL;
698     hr = IShellView_CreateViewWindow(view, NULL, &settings, &test_shellbrowser, &r, &hwnd_view);
699     ok(hr == S_OK || broken(hr == S_FALSE), "got (0x%08x)\n", hr);
700     ok(hwnd_view != NULL, "got %p\n", hwnd_view);
701     ok(IsWindow(hwnd_view), "hwnd %p still valid\n", hwnd_view);
702     ref2 = IShellView_Release(view);
703     ok(ref2 != 0, "ref2 = %u\n", ref2);
704     ok(ref2 > ref1, "expected %u > %u\n", ref2, ref1);
705     ok(IsWindow(hwnd_view), "hwnd %p still valid\n", hwnd_view);
706     DestroyWindow(hwnd_view);
707 
708     IShellFolder_Release(desktop);
709 }
710 
711 static void test_IFolderView(void)
712 {
713     IShellFolder *desktop, *folder;
714     FOLDERSETTINGS settings;
715     IShellView *view;
716     IShellBrowser *browser;
717     IFolderView2 *fv2;
718     IFolderView *fv;
719     IUnknown *unk;
720     HWND hwnd_view, hwnd_list;
721     PITEMID_CHILD pidl;
722     HRESULT hr;
723     INT ret, count;
724     POINT pt;
725     RECT r;
726 
727     hr = SHGetDesktopFolder(&desktop);
728     ok(hr == S_OK, "got (0x%08x)\n", hr);
729 
730     hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
731     ok(hr == S_OK, "got (0x%08x)\n", hr);
732 
733     hr = IShellView_QueryInterface(view, &IID_IFolderView, (void**)&fv);
734     if (hr != S_OK)
735     {
736         win_skip("IFolderView not supported by desktop folder\n");
737         IShellView_Release(view);
738         IShellFolder_Release(desktop);
739         return;
740     }
741 
742     /* call methods before window creation */
743     hr = IFolderView_GetSpacing(fv, NULL);
744     ok(hr == S_FALSE || broken(hr == S_OK) /* win7 */, "got (0x%08x)\n", hr);
745 
746     pidl = (void*)0xdeadbeef;
747     hr = IFolderView_Item(fv, 0, &pidl);
748     ok(hr == E_INVALIDARG || broken(hr == E_FAIL) /* < Vista */, "got (0x%08x)\n", hr);
749     ok(pidl == 0 || broken(pidl == (void*)0xdeadbeef) /* < Vista */, "got %p\n", pidl);
750 
751 if (0)
752 {
753     /* crashes on Vista and Win2k8 - List not created yet case */
754     IFolderView_GetSpacing(fv, &pt);
755 
756     /* crashes on XP */
757     IFolderView_GetSelectionMarkedItem(fv, NULL);
758     IFolderView_GetFocusedItem(fv, NULL);
759 
760     /* crashes on Vista+ */
761     IFolderView_Item(fv, 0, NULL);
762 }
763 
764     browser = IShellBrowserImpl_Construct();
765 
766     settings.ViewMode = FVM_ICON;
767     settings.fFlags = 0;
768     hwnd_view = (HWND)0xdeadbeef;
769     SetRect(&r, 0, 0, 100, 100);
770     hr = IShellView_CreateViewWindow(view, NULL, &settings, browser, &r, &hwnd_view);
771     ok(hr == S_OK, "got (0x%08x)\n", hr);
772     ok(IsWindow(hwnd_view), "got %p\n", hwnd_view);
773 
774     hwnd_list = subclass_listview(hwnd_view);
775     if (!hwnd_list)
776     {
777         win_skip("Failed to subclass ListView control\n");
778         IShellBrowser_Release(browser);
779         IFolderView_Release(fv);
780         IShellView_Release(view);
781         IShellFolder_Release(desktop);
782         return;
783     }
784 
785     /* IFolderView::GetSpacing */
786     flush_sequences(sequences, NUM_MSG_SEQUENCES);
787     hr = IFolderView_GetSpacing(fv, NULL);
788     ok(hr == S_OK, "got (0x%08x)\n", hr);
789     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, empty_seq, "IFolderView::GetSpacing, empty", FALSE);
790 
791     flush_sequences(sequences, NUM_MSG_SEQUENCES);
792     hr = IFolderView_GetSpacing(fv, &pt);
793     ok(hr == S_OK, "got (0x%08x)\n", hr);
794     /* fails with empty sequence on win7 for unknown reason */
795     if (sequences[LISTVIEW_SEQ_INDEX]->count)
796     {
797         ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_getspacing_seq, "IFolderView::GetSpacing", FALSE);
798         ok(pt.x > 0, "got %d\n", pt.x);
799         ok(pt.y > 0, "got %d\n", pt.y);
800         ret = SendMessageA(hwnd_list, LVM_GETITEMSPACING, 0, 0);
801         ok(pt.x == LOWORD(ret) && pt.y == HIWORD(ret), "got (%d, %d)\n", LOWORD(ret), HIWORD(ret));
802     }
803 
804     /* IFolderView::ItemCount */
805 if (0)
806 {
807     /* crashes on XP */
808     IFolderView_ItemCount(fv, SVGIO_ALLVIEW, NULL);
809 }
810 
811     flush_sequences(sequences, NUM_MSG_SEQUENCES);
812     IFolderView_ItemCount(fv, SVGIO_ALLVIEW, &count);
813 
814     /* IFolderView::GetSelectionMarkedItem */
815 if (0)
816 {
817     /* crashes on XP */
818     IFolderView_GetSelectionMarkedItem(fv, NULL);
819 }
820 
821     flush_sequences(sequences, NUM_MSG_SEQUENCES);
822     hr = IFolderView_GetSelectionMarkedItem(fv, &ret);
823     if (count)
824         ok(hr == S_OK, "got (0x%08x)\n", hr);
825     else
826         ok(hr == S_FALSE, "got (0x%08x)\n", hr);
827     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_getselectionmarked_seq,
828                 "IFolderView::GetSelectionMarkedItem", FALSE);
829 
830     /* IFolderView::GetFocusedItem */
831     flush_sequences(sequences, NUM_MSG_SEQUENCES);
832     hr = IFolderView_GetFocusedItem(fv, &ret);
833     if (count)
834         ok(hr == S_OK, "got (0x%08x)\n", hr);
835     else
836         ok(hr == S_FALSE, "got (0x%08x)\n", hr);
837     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_getfocused_seq,
838                 "IFolderView::GetFocusedItem", FALSE);
839 
840     /* IFolderView::GetFolder, just return pointer */
841 if (0)
842 {
843     /* crashes on XP */
844     IFolderView_GetFolder(fv, NULL, (void**)&folder);
845     IFolderView_GetFolder(fv, NULL, NULL);
846 }
847 
848     hr = IFolderView_GetFolder(fv, &IID_IShellFolder, NULL);
849     ok(hr == E_POINTER, "got (0x%08x)\n", hr);
850 
851     hr = IFolderView_GetFolder(fv, &IID_IShellFolder, (void**)&folder);
852     ok(hr == S_OK, "got (0x%08x)\n", hr);
853     ok(desktop == folder, "\n");
854     if (folder) IShellFolder_Release(folder);
855 
856     hr = IFolderView_GetFolder(fv, &IID_IUnknown, (void**)&unk);
857     ok(hr == S_OK, "got (0x%08x)\n", hr);
858     if (unk) IUnknown_Release(unk);
859 
860     hr = IFolderView_QueryInterface(fv, &IID_IFolderView2, (void**)&fv2);
861     if (hr != S_OK)
862         win_skip("IFolderView2 is not supported.\n");
863     if (fv2) IFolderView2_Release(fv2);
864 
865     hr = IShellView_DestroyViewWindow(view);
866     ok(hr == S_OK, "got (0x%08x)\n", hr);
867     ok(!IsWindow(hwnd_view), "hwnd %p still valid\n", hwnd_view);
868 
869     IShellBrowser_Release(browser);
870     IFolderView_Release(fv);
871     IShellView_Release(view);
872     IShellFolder_Release(desktop);
873 }
874 
875 static void test_GetItemObject(void)
876 {
877     IShellFolder *desktop;
878     IShellView *view;
879     IUnknown *unk;
880     HRESULT hr;
881 
882     hr = SHGetDesktopFolder(&desktop);
883     ok(hr == S_OK, "got (0x%08x)\n", hr);
884 
885     hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
886     ok(hr == S_OK, "got (0x%08x)\n", hr);
887 
888     /* from documentation three interfaces are supported for SVGIO_BACKGROUND:
889        IContextMenu, IDispatch, IPersistHistory */
890     hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IContextMenu, (void**)&unk);
891     ok(hr == S_OK, "got (0x%08x)\n", hr);
892     IUnknown_Release(unk);
893 
894     unk = NULL;
895     hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&unk);
896     ok(hr == S_OK || broken(hr == E_NOTIMPL) /* NT4 */, "got (0x%08x)\n", hr);
897     if (unk) IUnknown_Release(unk);
898 
899     unk = NULL;
900     hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IPersistHistory, (void**)&unk);
901     todo_wine ok(hr == S_OK || broken(hr == E_NOTIMPL) /* W9x, NT4 */, "got (0x%08x)\n", hr);
902     if (unk) IUnknown_Release(unk);
903 
904     /* example of unsupported interface, base for IPersistHistory */
905     hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IPersist, (void**)&unk);
906     ok(hr == E_NOINTERFACE || broken(hr == E_NOTIMPL) /* W2K */, "got (0x%08x)\n", hr);
907 
908     IShellView_Release(view);
909     IShellFolder_Release(desktop);
910 }
911 
912 static void test_IShellFolderView(void)
913 {
914     IShellFolderView *folderview;
915     IShellFolder *desktop;
916     IShellView *view;
917     IDataObject *obj;
918     UINT i;
919     HRESULT hr;
920 
921     hr = SHGetDesktopFolder(&desktop);
922     ok(hr == S_OK, "got (0x%08x)\n", hr);
923 
924     hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
925     ok(hr == S_OK, "got (0x%08x)\n", hr);
926 
927     hr = IShellView_QueryInterface(view, &IID_IShellFolderView, (void**)&folderview);
928     if (hr != S_OK)
929     {
930         win_skip("IShellView doesn't provide IShellFolderView on this platform\n");
931         IShellView_Release(view);
932         IShellFolder_Release(desktop);
933         return;
934     }
935 
936     /* ::MoveIcons */
937     obj = IDataObjectImpl_Construct();
938     hr = IShellFolderView_MoveIcons(folderview, obj);
939     ok(hr == E_NOTIMPL || broken(hr == S_OK) /* W98 */, "got (0x%08x)\n", hr);
940     IDataObject_Release(obj);
941 
942     /* ::SetRedraw without list created */
943     hr = IShellFolderView_SetRedraw(folderview, TRUE);
944     ok(hr == S_OK, "got (0x%08x)\n", hr);
945 
946     /* ::QuerySupport */
947     hr = IShellFolderView_QuerySupport(folderview, NULL);
948     ok(hr == S_OK, "got (0x%08x)\n", hr);
949     i = 0xdeadbeef;
950     hr = IShellFolderView_QuerySupport(folderview, &i);
951     ok(hr == S_OK, "got (0x%08x)\n", hr);
952     ok(i == 0xdeadbeef, "got %d\n", i);
953 
954     /* ::RemoveObject */
955     i = 0xdeadbeef;
956     hr = IShellFolderView_RemoveObject(folderview, NULL, &i);
957     ok(hr == S_OK || hr == E_FAIL, "got (0x%08x)\n", hr);
958     if (hr == S_OK) ok(i == 0 || broken(i == 0xdeadbeef) /* Vista, 2k8 */,
959                        "got %d\n", i);
960 
961     IShellFolderView_Release(folderview);
962 
963     IShellView_Release(view);
964     IShellFolder_Release(desktop);
965 }
966 
967 static void test_IOleWindow(void)
968 {
969     IShellFolder *desktop;
970     IShellView *view;
971     IOleWindow *wnd;
972     HRESULT hr;
973 
974     hr = SHGetDesktopFolder(&desktop);
975     ok(hr == S_OK, "got (0x%08x)\n", hr);
976 
977     hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
978     ok(hr == S_OK, "got (0x%08x)\n", hr);
979 
980     hr = IShellView_QueryInterface(view, &IID_IOleWindow, (void**)&wnd);
981     ok(hr == E_NOINTERFACE, "got (0x%08x)\n", hr);
982 
983     /* IShellView::ContextSensitiveHelp */
984     hr = IShellView_ContextSensitiveHelp(view, TRUE);
985     ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
986     hr = IShellView_ContextSensitiveHelp(view, FALSE);
987     ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
988 
989     IShellView_Release(view);
990     IShellFolder_Release(desktop);
991 }
992 
993 static const struct message folderview_setcurrentviewmode1_2_prevista[] = {
994     { LVM_SETVIEW, sent|wparam, LV_VIEW_ICON},
995     { LVM_SETIMAGELIST, sent|wparam, 0},
996     { LVM_SETIMAGELIST, sent|wparam, 1},
997     { 0x105a, sent},
998     { LVM_SETBKIMAGEW, sent|optional},    /* w2k3 */
999     { LVM_GETBKCOLOR, sent|optional},     /* w2k3 */
1000     { LVM_GETTEXTBKCOLOR, sent|optional}, /* w2k3 */
1001     { LVM_GETTEXTCOLOR, sent|optional},   /* w2k3 */
1002     { LVM_SETEXTENDEDLISTVIEWSTYLE, sent|optional|wparam, 0xc8}, /* w2k3 */
1003     { LVM_ARRANGE, sent },
1004     { LVM_ARRANGE, sent|optional },       /* WinXP */
1005     { 0 }
1006 };
1007 
1008 static const struct message folderview_setcurrentviewmode3_prevista[] = {
1009     { LVM_SETVIEW, sent|wparam, LV_VIEW_LIST},
1010     { LVM_SETIMAGELIST, sent|wparam, 0},
1011     { LVM_SETIMAGELIST, sent|wparam, 1},
1012     { 0x105a, sent},
1013     { LVM_SETBKIMAGEW, sent|optional},    /* w2k3 */
1014     { LVM_GETBKCOLOR, sent|optional},     /* w2k3 */
1015     { LVM_GETTEXTBKCOLOR, sent|optional}, /* w2k3 */
1016     { LVM_GETTEXTCOLOR, sent|optional},   /* w2k3 */
1017     { LVM_SETEXTENDEDLISTVIEWSTYLE, sent|optional|wparam, 0xc8}, /* w2k3 */
1018     { 0 }
1019 };
1020 
1021 static const struct message folderview_setcurrentviewmode4_prevista[] = {
1022     { LVM_GETHEADER, sent},
1023     { LVM_GETITEMCOUNT, sent|optional },
1024     { LVM_SETSELECTEDCOLUMN, sent},
1025     { WM_NOTIFY, sent },
1026     { WM_NOTIFY, sent },
1027     { WM_NOTIFY, sent },
1028     { WM_NOTIFY, sent },
1029     { LVM_SETVIEW, sent|wparam, LV_VIEW_DETAILS},
1030     { LVM_SETIMAGELIST, sent|wparam, 0},
1031     { LVM_SETIMAGELIST, sent|wparam, 1},
1032     { 0x105a, sent},
1033     { LVM_SETBKIMAGEW, sent|optional},    /* w2k3 */
1034     { LVM_GETBKCOLOR, sent|optional},     /* w2k3 */
1035     { LVM_GETTEXTBKCOLOR, sent|optional}, /* w2k3 */
1036     { LVM_GETTEXTCOLOR, sent|optional},   /* w2k3 */
1037     { LVM_SETEXTENDEDLISTVIEWSTYLE, sent|optional|wparam, 0xc8}, /* w2k3 */
1038     { 0 }
1039 };
1040 
1041 /* XP, SetCurrentViewMode(5)
1042    108e - LVM_SETVIEW (LV_VIEW_ICON);
1043    1036 - LVM_SETEXTEDEDLISTVIEWSTYLE (0x8000, 0)
1044    100c/104c repeated X times
1045    1003 - LVM_SETIMAGELIST
1046    1035 - LVM_SETICONSPACING
1047    1004 - LVM_GETITEMCOUNT
1048    105a - ?
1049    1016 - LVM_ARRANGE
1050    1016 - LVM_ARRANGE
1051 */
1052 
1053 /* XP, SetCurrentViewMode(6)
1054    1036 - LVM_SETEXTENDEDLISTVIEWSTYLE (0x8000, 0)
1055    1035 - LVM_SETICONSPACING
1056    1003 - LVM_SETIMAGELIST
1057    1003 - LVM_SETIMAGELIST
1058    100c/104c repeated X times
1059    10a2 - LVM_SETTILEVIEWINFO
1060    108e - LVM_SETVIEW (LV_VIEW_TILE)
1061    1003 - LVM_SETIMAGELIST
1062    105a - ?
1063    1016 - LVM_ARRANGE
1064    1016 - LVM_ARRANGE
1065 */
1066 
1067 /* XP, SetCurrentViewMode (7)
1068    10a2 - LVM_SETTILEVIEWINFO
1069    108e - LVM_SETVIEW (LV_VIEW_ICON)
1070    1004/10a4 (LVM_GETITEMCOUNT/LVM_SETTILEINFO) X times
1071    1016 - LVM_ARRANGE
1072    1016 - LVM_ARRANGE
1073    ...
1074    LVM_SETEXTENDEDLISTVIEWSTYLE (0x40000, 0x40000)
1075    ...
1076    LVM_SETEXTENDEDLISTVIEWSTYLE (0x8000, 0x8000)
1077 */
1078 
1079 static void test_GetSetCurrentViewMode(void)
1080 {
1081     IShellFolder *desktop;
1082     IShellView *sview;
1083     IFolderView *fview;
1084     IShellBrowser *browser;
1085     FOLDERSETTINGS fs;
1086     UINT viewmode;
1087     HWND hwnd;
1088     RECT rc = {0, 0, 10, 10};
1089     HRESULT hr;
1090     UINT i;
1091     static const int winxp_res[11] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
1092     static const int win2k3_res[11] = {0, 1, 2, 3, 4, 5, 6, 5, 8, 0, 0};
1093     static const int vista_res[11] = {0, 1, 5, 3, 4, 5, 6, 7, 7, 0, 0};
1094     static const int win7_res[11] = {1, 1, 1, 3, 4, 1, 6, 1, 8, 8, 8};
1095 
1096     hr = SHGetDesktopFolder(&desktop);
1097     ok(hr == S_OK, "got (0x%08x)\n", hr);
1098 
1099     hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&sview);
1100     ok(hr == S_OK, "got (0x%08x)\n", hr);
1101 
1102     fs.ViewMode = 1;
1103     fs.fFlags = 0;
1104     browser = IShellBrowserImpl_Construct();
1105     hr = IShellView_CreateViewWindow(sview, NULL, &fs, browser, &rc, &hwnd);
1106     ok(hr == S_OK || broken(hr == S_FALSE /*Win2k*/ ), "got (0x%08x)\n", hr);
1107 
1108     hr = IShellView_QueryInterface(sview, &IID_IFolderView, (void**)&fview);
1109     ok(hr == S_OK || broken(hr == E_NOINTERFACE), "got (0x%08x)\n", hr);
1110     if(SUCCEEDED(hr))
1111     {
1112         HWND hwnd_lv;
1113         UINT count;
1114 
1115         if (0)
1116         {
1117             /* Crashes under Win7/WinXP */
1118             IFolderView_GetCurrentViewMode(fview, NULL);
1119         }
1120 
1121         hr = IFolderView_GetCurrentViewMode(fview, &viewmode);
1122         ok(hr == S_OK, "got (0x%08x)\n", hr);
1123         ok(viewmode == 1, "ViewMode was %d\n", viewmode);
1124 
1125         hr = IFolderView_SetCurrentViewMode(fview, FVM_AUTO);
1126         ok(hr == S_OK, "got (0x%08x)\n", hr);
1127 
1128         hr = IFolderView_SetCurrentViewMode(fview, 0);
1129         ok(hr == E_INVALIDARG || broken(hr == S_OK),
1130            "got (0x%08x)\n", hr);
1131 
1132         hr = IFolderView_GetCurrentViewMode(fview, &viewmode);
1133         ok(hr == S_OK, "got (0x%08x)\n", hr);
1134 
1135         for(i = 1; i < 9; i++)
1136         {
1137             hr = IFolderView_SetCurrentViewMode(fview, i);
1138             ok(hr == S_OK || (i == 8 && hr == E_INVALIDARG /*Vista*/),
1139                "(%d) got (0x%08x)\n", i, hr);
1140 
1141             hr = IFolderView_GetCurrentViewMode(fview, &viewmode);
1142             ok(hr == S_OK, "(%d) got (0x%08x)\n", i, hr);
1143 
1144             /* Wine currently behaves like winxp here. */
1145             ok((viewmode == win7_res[i]) || (viewmode == vista_res[i]) ||
1146                (viewmode == win2k3_res[i]) || (viewmode == winxp_res[i]),
1147                "(%d) got %d\n",i , viewmode);
1148         }
1149 
1150         hr = IFolderView_SetCurrentViewMode(fview, 9);
1151         ok(hr == E_INVALIDARG || broken(hr == S_OK),
1152            "got (0x%08x)\n", hr);
1153 
1154         /* Test messages */
1155         hwnd_lv = subclass_listview(hwnd);
1156         ok(hwnd_lv != NULL, "Failed to subclass listview\n");
1157         if(hwnd_lv)
1158         {
1159             /* Vista seems to set the viewmode by other means than
1160                sending messages. At least no related messages are
1161                captured by subclassing.
1162             */
1163             BOOL vista_plus = FALSE;
1164             static const UINT vista_plus_msgs[] = {
1165                 WM_SETREDRAW, WM_NOTIFY, WM_NOTIFYFORMAT, WM_QUERYUISTATE,
1166                 WM_MENUCHAR, WM_WINDOWPOSCHANGING, WM_NCCALCSIZE, WM_WINDOWPOSCHANGED,
1167                 WM_PARENTNOTIFY, LVM_GETHEADER, 0 };
1168 
1169             flush_sequences(sequences, NUM_MSG_SEQUENCES);
1170             hr = IFolderView_SetCurrentViewMode(fview, 1);
1171             ok(hr == S_OK, "got 0x%08x\n", hr);
1172 
1173             /* WM_SETREDRAW is not sent in versions before Vista. */
1174             vista_plus = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, WM_SETREDRAW);
1175             if(vista_plus)
1176                 verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
1177             else
1178                 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_setcurrentviewmode1_2_prevista,
1179                             "IFolderView::SetCurrentViewMode(1)", TRUE);
1180 
1181             hr = IFolderView_SetCurrentViewMode(fview, 2);
1182             ok(hr == S_OK, "got 0x%08x\n", hr);
1183             if(vista_plus)
1184                 verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
1185             else
1186                 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_setcurrentviewmode1_2_prevista,
1187                             "IFolderView::SetCurrentViewMode(2)", TRUE);
1188 
1189             hr = IFolderView_SetCurrentViewMode(fview, 3);
1190             ok(hr == S_OK, "got 0x%08x\n", hr);
1191             if(vista_plus)
1192                 verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
1193             else
1194                 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_setcurrentviewmode3_prevista,
1195                             "IFolderView::SetCurrentViewMode(3)", TRUE);
1196 
1197             hr = IFolderView_SetCurrentViewMode(fview, 4);
1198             ok(hr == S_OK, "got 0x%08x\n", hr);
1199             if(vista_plus)
1200                 verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
1201             else
1202                 ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_setcurrentviewmode4_prevista,
1203                             "IFolderView::SetCurrentViewMode(4)", TRUE);
1204 
1205             hr = IFolderView_SetCurrentViewMode(fview, 5);
1206             ok(hr == S_OK, "got 0x%08x\n", hr);
1207             todo_wine
1208             {
1209                 if(vista_plus)
1210                 {
1211                     verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
1212                 }
1213                 else
1214                 {
1215                     count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETVIEW);
1216                     ok(count == 1, "LVM_SETVIEW sent %d times.\n", count);
1217                     count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETEXTENDEDLISTVIEWSTYLE);
1218                     ok(count == 1 || count == 2, "LVM_SETEXTENDEDLISTVIEWSTYLE sent %d times.\n", count);
1219                     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1220                 }
1221             }
1222 
1223             hr = IFolderView_SetCurrentViewMode(fview, 6);
1224             ok(hr == S_OK, "got 0x%08x\n", hr);
1225             todo_wine
1226             {
1227                 if(vista_plus)
1228                 {
1229                     verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
1230                 }
1231                 else
1232                 {
1233                     count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETVIEW);
1234                     ok(count == 1, "LVM_SETVIEW sent %d times.\n", count);
1235                     count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETEXTENDEDLISTVIEWSTYLE);
1236                     ok(count == 1 || count == 2, "LVM_SETEXTENDEDLISTVIEWSTYLE sent %d times.\n", count);
1237                     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1238                 }
1239             }
1240 
1241             hr = IFolderView_SetCurrentViewMode(fview, 7);
1242             ok(hr == S_OK, "got 0x%08x\n", hr);
1243             todo_wine
1244             {
1245                 if(vista_plus)
1246                 {
1247                     verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
1248                 }
1249                 else
1250                 {
1251                     count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETVIEW);
1252                     ok(count == 1, "LVM_SETVIEW sent %d times.\n", count);
1253                     count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETEXTENDEDLISTVIEWSTYLE);
1254                     ok(count == 2, "LVM_SETEXTENDEDLISTVIEWSTYLE sent %d times.\n", count);
1255                     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1256                 }
1257             }
1258 
1259             hr = IFolderView_SetCurrentViewMode(fview, 8);
1260             ok(hr == S_OK || broken(hr == E_INVALIDARG /* Vista */), "got 0x%08x\n", hr);
1261             todo_wine
1262             {
1263                 if(vista_plus)
1264                 {
1265                     verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
1266                 }
1267                 else
1268                 {
1269                     count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETVIEW);
1270                     ok(count == 1, "LVM_SETVIEW sent %d times.\n", count);
1271                     count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETEXTENDEDLISTVIEWSTYLE);
1272                     ok(count == 2, "LVM_SETEXTENDEDLISTVIEWSTYLE sent %d times.\n", count);
1273                     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1274                 }
1275             }
1276 
1277             hr = IFolderView_GetCurrentViewMode(fview, &viewmode);
1278             ok(hr == S_OK, "Failed to get current viewmode.\n");
1279             ok_sequence(sequences, LISTVIEW_SEQ_INDEX, empty_seq,
1280                         "IFolderView::GetCurrentViewMode", FALSE);
1281         }
1282 
1283         IFolderView_Release(fview);
1284     }
1285     else
1286     {
1287         skip("No IFolderView for the desktop folder.\n");
1288     }
1289 
1290     IShellBrowser_Release(browser);
1291     IShellView_DestroyViewWindow(sview);
1292     IShellView_Release(sview);
1293     IShellFolder_Release(desktop);
1294 }
1295 
1296 static void test_IOleCommandTarget(void)
1297 {
1298     IShellFolder *psf_desktop;
1299     IShellView *psv;
1300     IOleCommandTarget *poct;
1301     HRESULT hr;
1302 
1303     hr = SHGetDesktopFolder(&psf_desktop);
1304     ok(hr == S_OK, "got (0x%08x)\n", hr);
1305 
1306     hr = IShellFolder_CreateViewObject(psf_desktop, NULL, &IID_IShellView, (void**)&psv);
1307     ok(hr == S_OK, "got (0x%08x)\n", hr);
1308     if(SUCCEEDED(hr))
1309     {
1310         hr = IShellView_QueryInterface(psv, &IID_IOleCommandTarget, (void**)&poct);
1311         ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* Win95/NT4 */, "Got 0x%08x\n", hr);
1312         if(SUCCEEDED(hr))
1313         {
1314             OLECMD oc;
1315 
1316             hr = IOleCommandTarget_QueryStatus(poct, NULL, 0, NULL, NULL);
1317             ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
1318 
1319             oc.cmdID = 1;
1320             hr = IOleCommandTarget_QueryStatus(poct, NULL, 0, &oc, NULL);
1321             ok(hr == OLECMDERR_E_UNKNOWNGROUP, "Got 0x%08x\n", hr);
1322 
1323             oc.cmdID = 1;
1324             hr = IOleCommandTarget_QueryStatus(poct, NULL, 1, &oc, NULL);
1325             ok(hr == OLECMDERR_E_UNKNOWNGROUP, "Got 0x%08x\n", hr);
1326 
1327             hr = IOleCommandTarget_Exec(poct, NULL, 0, 0, NULL, NULL);
1328             ok(hr == OLECMDERR_E_UNKNOWNGROUP, "Got 0x%08x\n", hr);
1329 
1330             IOleCommandTarget_Release(poct);
1331         }
1332 
1333         IShellView_Release(psv);
1334     }
1335 
1336     IShellFolder_Release(psf_desktop);
1337 }
1338 
1339 static void test_SHCreateShellFolderView(void)
1340 {
1341     IShellFolder *desktop;
1342     IShellView *psv;
1343     SFV_CREATE sfvc;
1344     ULONG refCount;
1345     IUnknown *unk;
1346     HRESULT hr;
1347 
1348     hr = SHGetDesktopFolder(&desktop);
1349     ok(hr == S_OK, "got (0x%08x)\n", hr);
1350 
1351     if (0)
1352     {
1353         /* crash on win7 */
1354         SHCreateShellFolderView(NULL, NULL);
1355     }
1356 
1357     psv = (void *)0xdeadbeef;
1358     hr = SHCreateShellFolderView(NULL, &psv);
1359     ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
1360     ok(psv == NULL, "psv = %p\n", psv);
1361 
1362     memset(&sfvc, 0, sizeof(sfvc));
1363     psv = (void *)0xdeadbeef;
1364     hr = SHCreateShellFolderView(&sfvc, &psv);
1365     ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
1366     ok(psv == NULL, "psv = %p\n", psv);
1367 
1368     memset(&sfvc, 0, sizeof(sfvc));
1369     sfvc.cbSize = sizeof(sfvc) - 1;
1370     psv = (void *)0xdeadbeef;
1371     hr = SHCreateShellFolderView(&sfvc, &psv);
1372     ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
1373     ok(psv == NULL, "psv = %p\n", psv);
1374 
1375     memset(&sfvc, 0, sizeof(sfvc));
1376     sfvc.cbSize = sizeof(sfvc) + 1;
1377     psv = (void *)0xdeadbeef;
1378     hr = SHCreateShellFolderView(&sfvc, &psv);
1379     ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
1380     ok(psv == NULL, "psv = %p\n", psv);
1381 
1382 if (0)
1383 {
1384     /* Crashes on NULL 'pshf' on XP/2k3 */
1385     memset(&sfvc, 0, sizeof(sfvc));
1386     sfvc.cbSize = sizeof(sfvc);
1387     psv = (void *)0xdeadbeef;
1388     hr = SHCreateShellFolderView(&sfvc, &psv);
1389     ok(hr == E_UNEXPECTED, "Got 0x%08x\n", hr);
1390     ok(psv == NULL, "psv = %p\n", psv);
1391 }
1392     memset(&sfvc, 0, sizeof(sfvc));
1393     sfvc.cbSize = sizeof(sfvc) - 1;
1394     sfvc.pshf = desktop;
1395     psv = (void *)0xdeadbeef;
1396     hr = SHCreateShellFolderView(&sfvc, &psv);
1397     ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
1398     ok(psv == NULL, "psv = %p\n", psv);
1399 
1400     memset(&sfvc, 0, sizeof(sfvc));
1401     sfvc.cbSize = sizeof(sfvc);
1402     sfvc.pshf = desktop;
1403     psv = NULL;
1404     hr = SHCreateShellFolderView(&sfvc, &psv);
1405     ok(hr == S_OK, "Got 0x%08x\n", hr);
1406     ok(psv != NULL, "psv = %p\n", psv);
1407 
1408     hr = IShellView_QueryInterface(psv, &IID_CDefView, (void **)&unk);
1409     ok(hr == S_OK, "got (0x%08x)\n", hr);
1410     ok(unk == (IUnknown *)psv, "got %p\n", unk);
1411     IUnknown_Release(unk);
1412 
1413     refCount = IShellView_Release(psv);
1414     ok(refCount == 0, "refCount = %u\n", refCount);
1415 
1416     IShellFolder_Release(desktop);
1417 }
1418 
1419 static void test_SHCreateShellFolderViewEx(void)
1420 {
1421     IShellFolder *desktop;
1422     IShellView *psv;
1423     ULONG refCount;
1424     IUnknown *unk;
1425     HRESULT hr;
1426     CSFV csfv;
1427 
1428     hr = SHGetDesktopFolder(&desktop);
1429     ok(hr == S_OK, "got (0x%08x)\n", hr);
1430 
1431     if (0)
1432     {
1433         /* crash on win7 */
1434         SHCreateShellFolderViewEx(NULL, NULL);
1435         SHCreateShellFolderViewEx(NULL, &psv);
1436         SHCreateShellFolderViewEx(&csfv, NULL);
1437     }
1438 
1439     memset(&csfv, 0, sizeof(csfv));
1440     csfv.pshf = desktop;
1441     psv = NULL;
1442     hr = SHCreateShellFolderViewEx(&csfv, &psv);
1443     ok(hr == S_OK, "Got 0x%08x\n", hr);
1444     ok(psv != NULL, "psv = %p\n", psv);
1445 
1446     hr = IShellView_QueryInterface(psv, &IID_CDefView, (void **)&unk);
1447     ok(hr == S_OK, "got (0x%08x)\n", hr);
1448     ok(unk == (IUnknown *)psv, "got %p\n", unk);
1449     IUnknown_Release(unk);
1450 
1451     refCount = IShellView_Release(psv);
1452     ok(refCount == 0, "refCount = %u\n", refCount);
1453 
1454 if (0)
1455 {
1456     /* Crashes on null shellfolder, on XP/2k3 */
1457     memset(&csfv, 0, sizeof(csfv));
1458     csfv.pshf = NULL;
1459     psv = (void *)0xdeadbeef;
1460     hr = SHCreateShellFolderViewEx(&csfv, &psv);
1461     ok(hr == E_UNEXPECTED, "Got 0x%08x\n", hr);
1462     ok(psv == NULL, "psv = %p\n", psv);
1463 }
1464     memset(&csfv, 0, sizeof(csfv));
1465     csfv.cbSize = sizeof(csfv);
1466     csfv.pshf = desktop;
1467     psv = NULL;
1468     hr = SHCreateShellFolderViewEx(&csfv, &psv);
1469     ok(hr == S_OK, "Got 0x%08x\n", hr);
1470     ok(psv != NULL, "psv = %p\n", psv);
1471     if (psv)
1472     {
1473         refCount = IShellView_Release(psv);
1474         ok(refCount == 0, "refCount = %u\n", refCount);
1475     }
1476 
1477     IShellFolder_Release(desktop);
1478 }
1479 
1480 static void test_newmenu(void)
1481 {
1482     IUnknown *unk, *unk2;
1483     HRESULT hr;
1484 
1485     hr = CoCreateInstance(&CLSID_NewMenu, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&unk);
1486 todo_wine
1487     ok(hr == S_OK, "Failed to create NewMenu object, hr %#x.\n", hr);
1488     if (hr != S_OK)
1489     {
1490         skip("NewMenu is not supported.\n");
1491         return;
1492     }
1493 
1494     hr = IUnknown_QueryInterface(unk, &IID_IShellExtInit, (void **)&unk2);
1495     ok(hr == S_OK, "Failed to get IShellExtInit, hr %#x.\n", hr);
1496     IUnknown_Release(unk2);
1497 
1498     hr = IUnknown_QueryInterface(unk, &IID_IContextMenu3, (void **)&unk2);
1499     ok(hr == S_OK, "Failed to get IContextMenu3, hr %#x.\n", hr);
1500     IUnknown_Release(unk2);
1501 
1502     hr = IUnknown_QueryInterface(unk, &IID_IObjectWithSite, (void **)&unk2);
1503     ok(hr == S_OK, "Failed to get IObjectWithSite, hr %#x.\n", hr);
1504     IUnknown_Release(unk2);
1505 
1506     IUnknown_Release(unk);
1507 }
1508 
1509 START_TEST(shlview)
1510 {
1511     OleInitialize(NULL);
1512 
1513     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
1514 
1515     test_CreateViewWindow();
1516     test_IFolderView();
1517     test_GetItemObject();
1518     test_IShellFolderView();
1519     test_IOleWindow();
1520     test_GetSetCurrentViewMode();
1521     test_IOleCommandTarget();
1522     test_SHCreateShellFolderView();
1523     test_SHCreateShellFolderViewEx();
1524     test_newmenu();
1525 
1526     OleUninitialize();
1527 }
1528