1 /*
2  * PROJECT:     ReactOS API tests
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Test for IShellFolderViewCB
5  * COPYRIGHT:   Copyright 2017 Mark Jansen (mark.jansen@reactos.org)
6  */
7 
8 #include "shelltest.h"
9 #include <atlsimpcoll.h>
10 #include <stdio.h>
11 #include <shellutils.h>
12 //#include <msgtrace.h>
13 
14 static DWORD g_WinVersion;
15 #define WINVER_VISTA   0x0600
16 
17 #ifndef SFVM_SELECTIONCHANGED
18 #define SFVM_SELECTIONCHANGED          8 /* undocumented */
19 #define SFVM_DRAWMENUITEM              9 /* undocumented */
20 #define SFVM_MEASUREMENUITEM          10 /* undocumented */
21 #define SFVM_EXITMENULOOP             11 /* undocumented */
22 #define SFVM_VIEWRELEASE              12 /* undocumented */
23 #define SFVM_GETNAMELENGTH            13 /* undocumented */
24 #define SFVM_WINDOWCLOSING            16 /* undocumented */
25 #define SFVM_LISTREFRESHED            17 /* undocumented */
26 #define SFVM_WINDOWFOCUSED            18 /* undocumented */
27 #define SFVM_REGISTERCOPYHOOK         20 /* undocumented */
28 #define SFVM_COPYHOOKCALLBACK         21 /* undocumented */
29 #define SFVM_UNMERGEFROMMENU          28 /* undocumented */
30 #define SFVM_ADDINGOBJECT             29 /* undocumented */
31 #define SFVM_REMOVINGOBJECT           30 /* undocumented */
32 #define SFVM_GETCOMMANDDIR            33 /* undocumented */
33 #define SFVM_GETCOLUMNSTREAM          34 /* undocumented */
34 #define SFVM_CANSELECTALL             35 /* undocumented */
35 #define SFVM_ISSTRICTREFRESH          37 /* undocumented */
36 #define SFVM_ISCHILDOBJECT            38 /* undocumented */
37 #define SFVM_GETEXTVIEWS              40 /* undocumented */
38 #define SFVM_GET_CUSTOMVIEWINFO       77 /* undocumented */
39 #define SFVM_ENUMERATEDITEMS          79 /* undocumented */
40 #define SFVM_GET_VIEW_DATA            80 /* undocumented */
41 #define SFVM_GET_WEBVIEW_LAYOUT       82 /* undocumented */
42 #define SFVM_GET_WEBVIEW_CONTENT      83 /* undocumented */
43 #define SFVM_GET_WEBVIEW_TASKS        84 /* undocumented */
44 #define SFVM_GET_WEBVIEW_THEME        86 /* undocumented */
45 #define SFVM_GETDEFERREDVIEWSETTINGS  92 /* undocumented */
46 #endif
47 
48 #define DUM_MSG_GetWindow               400
49 #define DUM_MSG_ContextSensitiveHelp    401
50 #define DUM_MSG_InsertMenusSB           402
51 #define DUM_MSG_SetMenuSB               403
52 #define DUM_MSG_RemoveMenusSB           404
53 #define DUM_MSG_SetStatusTextSB         405
54 #define DUM_MSG_EnableModelessSB        406
55 #define DUM_MSG_TranslateAcceleratorSB  407
56 #define DUM_MSG_BrowseObject            408
57 #define DUM_MSG_GetViewStateStream      409
58 #define DUM_MSG_GetControlWindow        410
59 #define DUM_MSG_SendControlMsg          411
60 #define DUM_MSG_QueryActiveShellView    412
61 #define DUM_MSG_OnViewWindowActive      413
62 #define DUM_MSG_SetToolbarItems         414
63 
64 
msg2str(UINT uMsg)65 const char* msg2str(UINT uMsg)
66 {
67     static char buf[2][50];
68     static int index = 0;
69     index ^= 1;
70 
71     switch (uMsg)
72     {
73     case SFVM_MERGEMENU: return "SFVM_MERGEMENU";
74     case SFVM_INVOKECOMMAND: return "SFVM_INVOKECOMMAND";
75     case SFVM_GETHELPTEXT: return "SFVM_GETHELPTEXT";
76     case SFVM_GETTOOLTIPTEXT: return "SFVM_GETTOOLTIPTEXT";
77     case SFVM_GETBUTTONINFO: return "SFVM_GETBUTTONINFO";
78     case SFVM_GETBUTTONS: return "SFVM_GETBUTTONS";
79     case SFVM_INITMENUPOPUP: return "SFVM_INITMENUPOPUP";
80     case SFVM_SELECTIONCHANGED: return "SFVM_SELECTIONCHANGED";
81     case SFVM_DRAWMENUITEM: return "SFVM_DRAWMENUITEM";
82     case SFVM_MEASUREMENUITEM: return "SFVM_MEASUREMENUITEM";
83     case SFVM_EXITMENULOOP: return "SFVM_EXITMENULOOP";
84     case SFVM_VIEWRELEASE: return "SFVM_VIEWRELEASE";
85     case SFVM_GETNAMELENGTH: return "SFVM_GETNAMELENGTH";
86     case SFVM_FSNOTIFY: return "SFVM_FSNOTIFY";
87     case SFVM_WINDOWCREATED: return "SFVM_WINDOWCREATED";
88     case SFVM_WINDOWCLOSING: return "SFVM_WINDOWCLOSING";
89     case SFVM_LISTREFRESHED: return "SFVM_LISTREFRESHED";
90     case SFVM_WINDOWFOCUSED: return "SFVM_WINDOWFOCUSED";
91     case SFVM_REGISTERCOPYHOOK: return "SFVM_REGISTERCOPYHOOK";
92     case SFVM_COPYHOOKCALLBACK: return "SFVM_COPYHOOKCALLBACK";
93     case SFVM_GETDETAILSOF: return "SFVM_GETDETAILSOF";
94     case SFVM_COLUMNCLICK: return "SFVM_COLUMNCLICK";
95     case SFVM_QUERYFSNOTIFY: return "SFVM_QUERYFSNOTIFY";
96     case SFVM_DEFITEMCOUNT: return "SFVM_DEFITEMCOUNT";
97     case SFVM_DEFVIEWMODE: return "SFVM_DEFVIEWMODE";
98     case SFVM_UNMERGEFROMMENU: return "SFVM_UNMERGEFROMMENU";
99     case SFVM_ADDINGOBJECT: return "SFVM_ADDINGOBJECT";
100     case SFVM_REMOVINGOBJECT: return "SFVM_REMOVINGOBJECT";
101     case SFVM_UPDATESTATUSBAR: return "SFVM_UPDATESTATUSBAR";
102     case SFVM_BACKGROUNDENUM: return "SFVM_BACKGROUNDENUM";
103     case SFVM_GETCOMMANDDIR: return "SFVM_GETCOMMANDDIR";
104     case SFVM_GETCOLUMNSTREAM: return "SFVM_GETCOLUMNSTREAM";
105     case SFVM_CANSELECTALL: return "SFVM_CANSELECTALL";
106     case SFVM_DIDDRAGDROP: return "SFVM_DIDDRAGDROP";
107     case SFVM_ISSTRICTREFRESH: return "SFVM_ISSTRICTREFRESH";
108     case SFVM_ISCHILDOBJECT: return "SFVM_ISCHILDOBJECT";
109     case SFVM_SETISFV: return "SFVM_SETISFV";
110     case SFVM_GETEXTVIEWS: return "SFVM_GETEXTVIEWS";
111     case SFVM_THISIDLIST: return "SFVM_THISIDLIST";
112     case SFVM_ADDPROPERTYPAGES: return "SFVM_ADDPROPERTYPAGES";
113     case SFVM_BACKGROUNDENUMDONE: return "SFVM_BACKGROUNDENUMDONE";
114     case SFVM_GETNOTIFY: return "SFVM_GETNOTIFY";
115     case SFVM_GETSORTDEFAULTS: return "SFVM_GETSORTDEFAULTS";
116     case SFVM_SIZE: return "SFVM_SIZE";
117     case SFVM_GETZONE: return "SFVM_GETZONE";
118     case SFVM_GETPANE: return "SFVM_GETPANE";
119     case SFVM_GETHELPTOPIC: return "SFVM_GETHELPTOPIC";
120     case SFVM_GETANIMATION: return "SFVM_GETANIMATION";
121     case SFVM_GET_CUSTOMVIEWINFO: return "SFVM_GET_CUSTOMVIEWINFO";
122     case SFVM_ENUMERATEDITEMS: return "SFVM_ENUMERATEDITEMS";
123     case SFVM_GET_VIEW_DATA: return "SFVM_GET_VIEW_DATA";
124     case SFVM_GET_WEBVIEW_LAYOUT: return "SFVM_GET_WEBVIEW_LAYOUT";
125     case SFVM_GET_WEBVIEW_CONTENT: return "SFVM_GET_WEBVIEW_CONTENT";
126     case SFVM_GET_WEBVIEW_TASKS: return "SFVM_GET_WEBVIEW_TASKS";
127     case SFVM_GET_WEBVIEW_THEME: return "SFVM_GET_WEBVIEW_THEME";
128     case SFVM_GETDEFERREDVIEWSETTINGS: return "SFVM_GET_WEBVIEW_THEME";
129 
130     case DUM_MSG_GetWindow: return "|GetWindow|";
131     case DUM_MSG_ContextSensitiveHelp: return "|ContextSensitiveHelp|";
132     case DUM_MSG_InsertMenusSB: return "|InsertMenusSB|";
133     case DUM_MSG_SetMenuSB: return "|SetMenuSB|";
134     case DUM_MSG_RemoveMenusSB: return "|RemoveMenusSB|";
135     case DUM_MSG_SetStatusTextSB: return "|SetStatusTextSB|";
136     case DUM_MSG_EnableModelessSB: return "|EnableModelessSB|";
137     case DUM_MSG_TranslateAcceleratorSB: return "|TranslateAcceleratorSB|";
138     case DUM_MSG_BrowseObject: return "|BrowseObject|";
139     case DUM_MSG_GetViewStateStream: return "|GetViewStateStream|";
140     case DUM_MSG_GetControlWindow: return "|GetControlWindow|";
141     case DUM_MSG_SendControlMsg: return "|SendControlMsg|";
142     case DUM_MSG_QueryActiveShellView: return "|QueryActiveShellView|";
143     case DUM_MSG_OnViewWindowActive: return "|OnViewWindowActive|";
144     case DUM_MSG_SetToolbarItems: return "|SetToolbarItems|";
145     default:
146         sprintf(buf[index], "[%u]", uMsg);
147         return buf[index];
148     }
149 }
150 
151 
152 #define PTR_VALUE   0xf7f7f7f7
153 
154 struct message
155 {
messagemessage156     message(UINT msg, WPARAM wp, LPARAM lp) : uMsg(msg), wParam(wp), lParam(lp) { ; }
157 
158     UINT uMsg;
159     WPARAM wParam;
160     LPARAM lParam;
161 };
162 
163 CSimpleArray<message> g_Received;
164 
clear_list()165 void clear_list()
166 {
167     g_Received.RemoveAll();
168 }
169 
add_msg(UINT uMsg,WPARAM wParam,LPARAM lParam)170 void add_msg(UINT uMsg, WPARAM wParam, LPARAM lParam)
171 {
172     g_Received.Add(message(uMsg, wParam, lParam));
173 }
174 
print_list_(const CSimpleArray<message> & input,const char * file,int line)175 void print_list_(const CSimpleArray<message>& input, const char* file, int line)
176 {
177     trace_(file, line)("Got list:\n");
178     for (int n = 0; n < input.GetSize(); ++n)
179     {
180         const message& msg = input[n];
181         trace_(file, line)("msg: %d(%s), wParam:0x%x, lParam:0x%lx\n", msg.uMsg, msg2str(msg.uMsg), msg.wParam, msg.lParam);
182     }
183     trace_(file, line)("End of list.\n");
184 }
185 
compare_list_(const CSimpleArray<message> & input,const message * compare,const char * file,int line)186 void compare_list_(const CSimpleArray<message>& input, const message* compare, const char* file, int line)
187 {
188     int input_item = 0;
189     int compare_item = 0;
190     LONG old_failures = winetest_get_failures();
191     while (compare[compare_item].uMsg && input_item < input.GetSize())
192     {
193         const message& inp = input[input_item];
194         const message& cmp = compare[compare_item];
195         if (cmp.uMsg == inp.uMsg)
196         {
197             if (cmp.lParam != (LPARAM)PTR_VALUE)
198             {
199                 ok_(file, line)(cmp.lParam == inp.lParam, "Expected lParam to be 0x%lx, was 0x%lx for %i(%s)\n",
200                                 cmp.lParam, inp.lParam, compare_item, msg2str(cmp.uMsg));
201             }
202             else
203             {
204                 ok_(file, line)(inp.lParam != 0, "Expected lParam to be a pointer, was 0 for %i(%s)\n",
205                                 compare_item, msg2str(cmp.uMsg));
206             }
207             if (cmp.wParam != PTR_VALUE)
208             {
209                 ok_(file, line)(cmp.wParam == inp.wParam, "Expected wParam to be 0x%x, was 0x%x for %i(%s)\n",
210                                 cmp.wParam, inp.wParam, compare_item, msg2str(cmp.uMsg));
211             }
212             else
213             {
214                 ok_(file, line)(inp.wParam != 0, "Expected wParam to be a pointer, was 0 for %i(%s)\n",
215                                 compare_item, msg2str(cmp.uMsg));
216             }
217             compare_item++;
218         }
219         else
220         {
221             /* We skip unknown items for now */
222         }
223 
224         input_item++;
225     }
226 
227     while (compare[compare_item].uMsg)
228     {
229         ok_(file, line)(0, "Message %i(%s) not found\n", compare_item, msg2str(compare[compare_item].uMsg));
230         compare_item++;
231     }
232     if (old_failures != winetest_get_failures())
233     {
234         print_list_(input, file, line);
235     }
236 }
237 
238 #define compare_list(cmp)   compare_list_(g_Received, cmp, __FILE__, __LINE__)
239 #define print_list()        print_list_(g_Received, __FILE__, __LINE__)
240 
241 
242 LONG g_AddRef = 0;
243 LONG g_Release = 0;
244 
245 class CFolderViewCB :
246     public IShellFolderViewCB
247 {
248 public:
CFolderViewCB(void)249     CFolderViewCB(void) :
250         m_RefCount(1)
251     {
252     }
QueryInterface(REFIID riid,void ** ppvObject)253     virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void  **ppvObject)
254     {
255         if (riid == IID_IShellFolderViewCB)
256         {
257             *ppvObject = static_cast<IShellFolderViewCB*>(this);
258             AddRef();
259             return S_OK;
260         }
261         return E_NOINTERFACE;
262     }
AddRef(void)263     virtual ULONG STDMETHODCALLTYPE AddRef(void)
264     {
265         InterlockedIncrement(&g_AddRef);
266         return InterlockedIncrement(&m_RefCount);
267     }
Release(void)268     virtual ULONG STDMETHODCALLTYPE Release(void)
269     {
270         InterlockedIncrement(&g_Release);
271         return InterlockedDecrement(&m_RefCount);
272     }
MessageSFVCB(UINT uMsg,WPARAM wParam,LPARAM lParam)273     virtual HRESULT STDMETHODCALLTYPE MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
274     {
275         //DbgPrint("MessageSFVCB(uMsg:%s, wParam:%u, lParam:%u\n", msg2str(uMsg), wParam, lParam);
276         add_msg(uMsg, wParam, lParam);
277         return E_NOTIMPL;
278     }
279 private:
280     LONG m_RefCount;
281 };
282 
283 
WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)284 static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
285 {
286     if (msg == WM_DESTROY)
287     {
288         PostQuitMessage(0);
289         return 0;
290     }
291     return DefWindowProc(hwnd, msg, wParam, lParam);
292 }
293 
294 
295 class CDummyShellBrowser : public IShellBrowser
296 {
297 public:
298     HWND m_hwnd;
CDummyShellBrowser()299     CDummyShellBrowser()
300     {
301         static const TCHAR* class_name = TEXT("DUMMY_TEST_CLASS");
302         WNDCLASSEX wx = {};
303         wx.cbSize = sizeof(WNDCLASSEX);
304         wx.lpfnWndProc = WndProc;
305         wx.hInstance = GetModuleHandle(NULL);
306         wx.lpszClassName = class_name;
307         wx.style = CS_DBLCLKS;
308         RegisterClassEx(&wx);
309         m_hwnd = CreateWindowEx(0, class_name, TEXT("dummy_name"), WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
310         ShowWindow(m_hwnd, SW_SHOW);
311     }
312 
313     // *** IUnknown methods ***
QueryInterface(REFIID riid,void ** ppvObject)314     virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void  **ppvObject)
315     {
316         if (riid == IID_IShellBrowser || riid == IID_IUnknown)
317         {
318             *ppvObject = this;
319             return S_OK;
320         }
321         return E_NOINTERFACE;
322     }
AddRef(void)323     virtual ULONG STDMETHODCALLTYPE AddRef(void)
324     {
325         return 2;
326     }
Release(void)327     virtual ULONG STDMETHODCALLTYPE Release(void)
328     {
329         return 1;
330     }
331 
332     // *** IOleWindow methods ***
GetWindow(HWND * phwnd)333     virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *phwnd)
334     {
335         //DbgPrint("%s()\n", __FUNCTION__);
336         *phwnd = m_hwnd;
337         add_msg(DUM_MSG_GetWindow, NULL, NULL);
338         return S_OK;
339     }
ContextSensitiveHelp(BOOL fEnterMode)340     virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode)
341     {
342         //DbgPrint("%s()\n", __FUNCTION__);
343         add_msg(DUM_MSG_ContextSensitiveHelp, NULL, NULL);
344         return E_NOTIMPL;
345     }
346 
347     // *** IShellBrowser methods ***
InsertMenusSB(HMENU hmenuShared,LPOLEMENUGROUPWIDTHS lpMenuWidths)348     virtual HRESULT STDMETHODCALLTYPE InsertMenusSB(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths)
349     {
350         //DbgPrint("%s()\n", __FUNCTION__);
351         add_msg(DUM_MSG_InsertMenusSB, NULL, NULL);
352         return S_OK;
353     }
SetMenuSB(HMENU hmenuShared,HOLEMENU holemenuRes,HWND hwndActiveObject)354     virtual HRESULT STDMETHODCALLTYPE SetMenuSB(HMENU hmenuShared, HOLEMENU holemenuRes, HWND hwndActiveObject)
355     {
356         //DbgPrint("%s()\n", __FUNCTION__);
357         add_msg(DUM_MSG_SetMenuSB, NULL, NULL);
358         return S_OK;
359     }
RemoveMenusSB(HMENU hmenuShared)360     virtual HRESULT STDMETHODCALLTYPE RemoveMenusSB(HMENU hmenuShared)
361     {
362         //DbgPrint("%s()\n", __FUNCTION__);
363         add_msg(DUM_MSG_RemoveMenusSB, NULL, NULL);
364         return E_NOTIMPL;
365     }
SetStatusTextSB(LPCWSTR pszStatusText)366     virtual HRESULT STDMETHODCALLTYPE SetStatusTextSB(LPCWSTR pszStatusText)
367     {
368         //DbgPrint("%s()\n", __FUNCTION__);
369         add_msg(DUM_MSG_SetStatusTextSB, NULL, NULL);
370         return E_NOTIMPL;
371     }
EnableModelessSB(BOOL fEnable)372     virtual HRESULT STDMETHODCALLTYPE EnableModelessSB(BOOL fEnable)
373     {
374         //DbgPrint("%s()\n", __FUNCTION__);
375         add_msg(DUM_MSG_EnableModelessSB, NULL, NULL);
376         return E_NOTIMPL;
377     }
TranslateAcceleratorSB(MSG * pmsg,WORD wID)378     virtual HRESULT STDMETHODCALLTYPE TranslateAcceleratorSB(MSG *pmsg, WORD wID)
379     {
380         //DbgPrint("%s()\n", __FUNCTION__);
381         add_msg(DUM_MSG_TranslateAcceleratorSB, NULL, NULL);
382         return E_NOTIMPL;
383     }
BrowseObject(PCUIDLIST_RELATIVE pidl,UINT wFlags)384     virtual HRESULT STDMETHODCALLTYPE BrowseObject(PCUIDLIST_RELATIVE pidl,UINT wFlags)
385     {
386         //DbgPrint("%s()\n", __FUNCTION__);
387         add_msg(DUM_MSG_BrowseObject, NULL, NULL);
388         return E_NOTIMPL;
389     }
GetViewStateStream(DWORD grfMode,IStream ** ppStrm)390     virtual HRESULT STDMETHODCALLTYPE GetViewStateStream(DWORD grfMode,IStream **ppStrm)
391     {
392         //DbgPrint("%s()\n", __FUNCTION__);
393         add_msg(DUM_MSG_GetViewStateStream, NULL, NULL);
394         return E_NOTIMPL;
395     }
GetControlWindow(UINT id,HWND * phwnd)396     virtual HRESULT STDMETHODCALLTYPE GetControlWindow(UINT id,HWND *phwnd)
397     {
398         //DbgPrint("%s()\n", __FUNCTION__);
399         add_msg(DUM_MSG_GetControlWindow, NULL, NULL);
400         return E_NOTIMPL;
401     }
SendControlMsg(UINT id,UINT uMsg,WPARAM wParam,LPARAM lParam,LRESULT * pret)402     virtual HRESULT STDMETHODCALLTYPE SendControlMsg(UINT id,UINT uMsg,WPARAM wParam,LPARAM lParam,LRESULT *pret)
403     {
404         //DbgPrint("%s()\n", __FUNCTION__);
405         add_msg(DUM_MSG_SendControlMsg, NULL, NULL);
406         return E_NOTIMPL;
407     }
QueryActiveShellView(IShellView ** ppshv)408     virtual HRESULT STDMETHODCALLTYPE QueryActiveShellView(IShellView **ppshv)
409     {
410         //DbgPrint("%s()\n", __FUNCTION__);
411         add_msg(DUM_MSG_QueryActiveShellView, NULL, NULL);
412         return E_NOTIMPL;
413     }
OnViewWindowActive(IShellView * pshv)414     virtual HRESULT STDMETHODCALLTYPE OnViewWindowActive(IShellView *pshv)
415     {
416         //DbgPrint("%s()\n", __FUNCTION__);
417         add_msg(DUM_MSG_OnViewWindowActive, NULL, NULL);
418         return E_NOTIMPL;
419     }
SetToolbarItems(LPTBBUTTONSB lpButtons,UINT nButtons,UINT uFlags)420     virtual HRESULT STDMETHODCALLTYPE SetToolbarItems(LPTBBUTTONSB lpButtons,UINT nButtons,UINT uFlags)
421     {
422         //DbgPrint("%s()\n", __FUNCTION__);
423         add_msg(DUM_MSG_SetToolbarItems, NULL, NULL);
424         return E_NOTIMPL;
425     }
426 };
427 
428 
START_TEST(IShellFolderViewCB)429 START_TEST(IShellFolderViewCB)
430 {
431     RTL_OSVERSIONINFOEXW rtlinfo = { sizeof(rtlinfo) };
432     void (__stdcall* pRtlGetVersion)(RTL_OSVERSIONINFOEXW*);
433     pRtlGetVersion = (void (__stdcall*)(RTL_OSVERSIONINFOEXW*))GetProcAddress(GetModuleHandleA("ntdll"), "RtlGetVersion");
434     pRtlGetVersion(&rtlinfo);
435     g_WinVersion = (rtlinfo.dwMajorVersion << 8) | rtlinfo.dwMinorVersion;
436 
437     CoInitialize(NULL);
438     CFolderViewCB cb;
439 
440     CComPtr<IShellFolder> desktop;
441 
442     HRESULT hr = SHGetDesktopFolder(&desktop);
443     ok_hex(hr, S_OK);
444     if (!desktop)
445         return;
446 
447     SFV_CREATE sfvc = { sizeof(sfvc), desktop };
448     sfvc.psfvcb = &cb;
449     IShellView* psv = NULL;
450 
451     g_AddRef = 0;
452     g_Release = 0;
453 
454     hr = SHCreateShellFolderView(&sfvc, &psv);
455     ok_hex(hr, S_OK);
456     if (!SUCCEEDED(hr))
457         return;
458 
459     ok_int(g_AddRef, 1);
460     ok_int(g_Release, 0);
461 
462     clear_list();
463 
464     HWND wnd;
465     RECT rc = { 0 };
466     FOLDERSETTINGS fs = { FVM_DETAILS, 0 };
467     CDummyShellBrowser dum;
468     hr = psv->CreateViewWindow(NULL, &fs, &dum, &rc, &wnd);
469 
470 
471     static message init_list[] =
472     {
473         /* ... */
474         message(DUM_MSG_GetWindow, 0, 0),
475         /* Some unknown messages here, and multiple SFVM_GET_WEBVIEW_THEME + SFVM_GETSORTDEFAULTS + SFVM_GETCOLUMNSTREAM */
476         message(SFVM_SIZE, 0, 0),
477         /* ... */
478         message(DUM_MSG_InsertMenusSB, 0, 0),
479         message(SFVM_MERGEMENU, 0, PTR_VALUE),
480         message(DUM_MSG_SetMenuSB, 0, 0),
481         /* ... */
482         message(SFVM_WINDOWCREATED, PTR_VALUE, 0),
483         /* ... */
484 
485         message(SFVM_GETBUTTONINFO, 0, PTR_VALUE),
486         message(SFVM_GETBUTTONS, PTR_VALUE, PTR_VALUE),
487         message(DUM_MSG_SetToolbarItems, 0, 0),
488 
489         message(0, 0, 0)
490     };
491 
492 
493     static message init_list_vista[] =
494     {
495         /* Some unknown messages here */
496         message(DUM_MSG_GetWindow, 0, 0),
497         /* Some unknown messages here, and multiple SFVM_GET_WEBVIEW_THEME + SFVM_GETSORTDEFAULTS + SFVM_GETCOLUMNSTREAM */
498         message(SFVM_SIZE, 0, 0),
499         message(SFVM_WINDOWCREATED, PTR_VALUE, 0),
500         /* Some unknown messages here */
501         message(DUM_MSG_InsertMenusSB, 0, 0),
502         message(SFVM_MERGEMENU, 0, PTR_VALUE),
503         message(DUM_MSG_SetMenuSB, 0, 0),
504 
505         message(0, 0, 0)
506     };
507 
508     if (g_WinVersion < WINVER_VISTA)
509     {
510         compare_list(init_list);
511     }
512     else
513     {
514         compare_list(init_list_vista);
515     }
516     clear_list();
517 
518     hr = psv->Refresh();
519     //ok_hex(hr, S_FALSE);
520 
521     static message refresh_list[] =
522     {
523         message(SFVM_LISTREFRESHED, 1, 0),
524 
525         message(SFVM_UNMERGEFROMMENU, 0, PTR_VALUE),
526         message(DUM_MSG_SetMenuSB, 0, 0),
527         message(DUM_MSG_RemoveMenusSB, 0, 0),
528         message(DUM_MSG_InsertMenusSB, 0, 0),
529         message(SFVM_MERGEMENU, 0, PTR_VALUE),
530         message(DUM_MSG_SetMenuSB, 0, 0),
531 
532         message(0, 0, 0)
533     };
534 
535     static message refresh_list_vista[] =
536     {
537         message(SFVM_LISTREFRESHED, 1, 0),
538 
539         message(SFVM_UNMERGEFROMMENU, 0, PTR_VALUE),
540         message(DUM_MSG_SetMenuSB, 0, 0),
541         message(DUM_MSG_RemoveMenusSB, 0, 0),
542         message(DUM_MSG_InsertMenusSB, 0, 0),
543         message(SFVM_MERGEMENU, 0, PTR_VALUE),
544         message(DUM_MSG_SetMenuSB, 0, 0),
545         /* Some messages here, like SFVM_GET_WEBVIEW_THEME, SFVM_GETSORTDEFAULTS, SFVM_GETCOLUMNSTREAM */
546         message(SFVM_UNMERGEFROMMENU, 0, PTR_VALUE),
547         message(DUM_MSG_SetMenuSB, 0, 0),
548         message(DUM_MSG_RemoveMenusSB, 0, 0),
549         message(DUM_MSG_InsertMenusSB, 0, 0),
550         message(SFVM_MERGEMENU, 0, PTR_VALUE),
551         message(DUM_MSG_SetMenuSB, 0, 0),
552 
553         message(0, 0, 0)
554     };
555 
556     if (g_WinVersion < WINVER_VISTA)
557     {
558         compare_list(refresh_list);
559     }
560     else
561     {
562         compare_list(refresh_list_vista);
563     }
564     clear_list();
565 
566     hr = psv->DestroyViewWindow();
567 
568     static message destroy_list[] =
569     {
570         message(SFVM_UNMERGEFROMMENU, 0, PTR_VALUE),
571         message(DUM_MSG_SetMenuSB, 0, 0),
572         message(DUM_MSG_RemoveMenusSB, 0, 0),
573         message(SFVM_WINDOWCLOSING, PTR_VALUE, 0),
574 
575         message(0, 0, 0)
576     };
577 
578     compare_list(destroy_list);
579     clear_list();
580 
581     CComPtr<IShellFolderView> folderView;
582     hr = psv->QueryInterface(IID_PPV_ARG(IShellFolderView, &folderView));
583     ok_hex(hr, S_OK);
584     if (SUCCEEDED(hr))
585     {
586         IShellFolderViewCB* oldPtr;
587 
588         hr = folderView->SetCallback(NULL, &oldPtr);
589         ok_int(g_AddRef, 1);
590         ok_int(g_Release, 0);
591 
592         /* Last pointer is not optional! */
593         IShellFolderViewCB* oldPtr2;
594         hr = folderView->SetCallback(oldPtr, &oldPtr2);
595         ok_int(g_AddRef, 2);
596         ok_int(g_Release, 0);
597     }
598 
599     ULONG refCount = psv->Release();
600     ok(refCount == 1, "refCount = %lu\n", refCount);
601 
602     static message release_list[] =
603     {
604         message(SFVM_VIEWRELEASE, 0, 0),
605 
606         message(0, 0, 0)
607     };
608 
609     /* Investigate why this fails */
610     if (refCount == 0)
611     {
612         compare_list(release_list);
613     }
614 }
615