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