wined3d: Don't set a NULL container of type WINED3D_CONTAINER_TEXTURE.
[wine] / dlls / shell32 / tests / ebrowser.c
1 /*
2  *    Unit tests for the Explorer Browser control
3  *
4  * Copyright 2010 David Hedberg
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 <stdio.h>
22
23 #define COBJMACROS
24
25 #include "shlobj.h"
26 #include "shlwapi.h"
27
28 #include "wine/test.h"
29
30 #include "initguid.h"
31 #include "mshtml.h"
32
33 /**********************************************************************
34  * Some IID's for test_SetSite.
35  */
36 DEFINE_GUID(IID_IBrowserSettings,     0xDD1E21CC, 0xE2C7, 0x402C, 0xBF,0x05, 0x10,0x32,0x8D,0x3F,0x6B,0xAD);
37 DEFINE_GUID(IID_IShellBrowserService, 0xDFBC7E30, 0xF9E5, 0x455F, 0x88,0xF8, 0xFA,0x98,0xC1,0xE4,0x94,0xCA);
38 DEFINE_GUID(IID_IShellTaskScheduler,  0x6CCB7BE0, 0x6807, 0x11D0, 0xB8,0x10, 0x00,0xC0,0x4F,0xD7,0x06,0xEC);
39 DEFINE_GUID(IID_IBrowserWithActivationNotification,
40                                       0x6DB89131, 0x7B4C, 0x4E1C, 0x8B,0x01, 0x5D,0x31,0x2C,0x9C,0x73,0x88);
41 DEFINE_GUID(IID_ILayoutModifier,      0x90B4135A, 0x95BA, 0x46EA, 0x8C,0xAA, 0xE0,0x5B,0x45,0xCD,0x80,0x1E);
42 DEFINE_GUID(CLSID_Desktop,            0x00021400, 0x0000, 0x0000, 0xC0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46);
43 DEFINE_GUID(IID_IFileDialogPrivate,   0xAC92FFC5, 0xF0E9, 0x455A, 0x90,0x6B, 0x4A,0x83,0xE7,0x4A,0x80,0x3B);
44 DEFINE_GUID(IID_IWebbrowserApp,       0x0002df05, 0x0000, 0x0000, 0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46);
45 DEFINE_GUID(IID_IBrowserSettings_Vista, 0xF81B80BC, 0x29D1, 0x4734, 0xB5,0x15, 0x77,0x24,0xBF,0xF1,0x60,0x01);
46 DEFINE_GUID(IID_IFolderTypeModifier,    0x04BA120E, 0xAD52, 0x4A2D, 0x98,0x07, 0x2D,0xA1,0x78,0xD0,0xC3,0xE1);
47 DEFINE_GUID(IID_IShellBrowserService_Vista, 0xF5A24314, 0x5B8B, 0x44FA, 0xBC,0x2E, 0x31,0x28,0x55,0x44,0xB5,0x20);
48 DEFINE_GUID(IID_IFileDialogPrivate_Vista, 0x2539E31C, 0x857F, 0x43C4, 0x88,0x72, 0x45,0xBD,0x6A,0x02,0x48,0x92);
49 DEFINE_GUID(SID_SMenuBandParent,      0x8C278EEC, 0x3EAB, 0x11D1, 0x8C,0xB0 ,0x00,0xC0,0x4F,0xD9,0x18,0xD0);
50 DEFINE_GUID(SID_SMenuPopup,           0xD1E7AFEB, 0x6A2E, 0x11D0, 0x8C,0x78, 0x00,0xC0,0x4F,0xD9,0x18,0xB4);
51 DEFINE_GUID(IID_IShellMenu,           0xEE1F7637, 0xE138, 0x11D1, 0x83,0x79, 0x00,0xC0,0x4F,0xD9,0x18,0xD0);
52
53 DEFINE_GUID(IID_UnknownInterface1,    0x3934E4C2, 0x8143, 0x4E4C, 0xA1,0xDC, 0x71,0x8F,0x85,0x63,0xF3,0x37);
54 DEFINE_GUID(IID_UnknownInterface2,    0x3E24A11C, 0x15B2, 0x4F71, 0xB8,0x1E, 0x00,0x8F,0x77,0x99,0x8E,0x9F);
55 DEFINE_GUID(IID_UnknownInterface3,    0xE38FE0F3, 0x3DB0, 0x47EE, 0xA3,0x14, 0x25,0xCF,0x7F,0x4B,0xF5,0x21);
56 DEFINE_GUID(IID_UnknownInterface4,    0xFAD451C2, 0xAF58, 0x4161, 0xB9,0xFF, 0x57,0xAF,0xBB,0xED,0x0A,0xD2);
57 DEFINE_GUID(IID_UnknownInterface5,    0xF80C2137, 0x5829, 0x4CE9, 0x9F,0x81, 0xA9,0x5E,0x15,0x9D,0xD8,0xD5);
58 DEFINE_GUID(IID_UnknownInterface6,    0xD7F81F62, 0x491F, 0x49BC, 0x89,0x1D, 0x56,0x65,0x08,0x5D,0xF9,0x69);
59 DEFINE_GUID(IID_UnknownInterface7,    0x68A4FDBA, 0xA48A, 0x4A86, 0xA3,0x29, 0x1B,0x69,0xB9,0xB1,0x9E,0x89);
60 DEFINE_GUID(IID_UnknownInterface8,    0xD3B1CAF5, 0xEC4F, 0x4B2E, 0xBC,0xB0, 0x60,0xD7,0x15,0xC9,0x3C,0xB2);
61 DEFINE_GUID(IID_UnknownInterface9,    0x9536CA39, 0x1ACB, 0x4AE6, 0xAD,0x27, 0x24,0x03,0xD0,0x4C,0xA2,0x8F);
62 DEFINE_GUID(IID_UnknownInterface10,   0xB722BE00, 0x4E68, 0x101B, 0xA2,0xBC, 0x00,0xAA,0x00,0x40,0x47,0x70);
63
64 static HWND hwnd;
65
66 static HRESULT (WINAPI *pSHCreateShellItem)(LPCITEMIDLIST,IShellFolder*,LPCITEMIDLIST,IShellItem**);
67 static HRESULT (WINAPI *pSHParseDisplayName)(LPCWSTR,IBindCtx*,LPITEMIDLIST*,SFGAOF,SFGAOF*);
68
69 static void init_function_pointers(void)
70 {
71     HMODULE hmod;
72
73     hmod = GetModuleHandleA("shell32.dll");
74     pSHCreateShellItem = (void*)GetProcAddress(hmod, "SHCreateShellItem");
75     pSHParseDisplayName = (void*)GetProcAddress(hmod, "SHParseDisplayName");
76 }
77
78 /*********************************************************************
79  * Some simple helpers
80  */
81 static HRESULT ebrowser_instantiate(IExplorerBrowser **peb)
82 {
83     return CoCreateInstance(&CLSID_ExplorerBrowser, NULL, CLSCTX_INPROC_SERVER,
84                             &IID_IExplorerBrowser, (void**)peb);
85 }
86
87 static HRESULT ebrowser_initialize(IExplorerBrowser *peb)
88 {
89     RECT rc;
90     rc.top = rc.left = 0; rc.bottom = rc.right = 500;
91     return IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
92 }
93
94 static HRESULT ebrowser_browse_to_desktop(IExplorerBrowser *peb)
95 {
96     LPITEMIDLIST pidl_desktop;
97     SHGetSpecialFolderLocation (hwnd, CSIDL_DESKTOP, &pidl_desktop);
98     return IExplorerBrowser_BrowseToIDList(peb, pidl_desktop, 0);
99 }
100
101 /* Process some messages */
102 static void process_msgs(void)
103 {
104     MSG msg;
105     while(PeekMessage( &msg, NULL, 0, 0, PM_REMOVE))
106     {
107         TranslateMessage(&msg);
108         DispatchMessage(&msg);
109     }
110 }
111
112 static void dbg_print_guid(const GUID *guid) {
113     WCHAR buf[MAX_PATH];
114
115     StringFromGUID2(guid, buf, MAX_PATH);
116     printf("guid:[%s]\n", wine_dbgstr_wn(buf, lstrlenW(buf)));
117 }
118
119 /*********************************************************************
120  * IExplorerBrowserEvents implementation
121  */
122 typedef struct {
123     const IExplorerBrowserEventsVtbl *lpVtbl;
124     LONG ref;
125     UINT pending, created, completed, failed;
126 } IExplorerBrowserEventsImpl;
127
128 static IExplorerBrowserEventsImpl ebev;
129
130 static HRESULT WINAPI IExplorerBrowserEvents_fnQueryInterface(IExplorerBrowserEvents *iface,
131                                                               REFIID riid, void **ppvObj)
132 {
133     ok(0, "Never called.\n");
134     return E_NOINTERFACE;
135 }
136
137 static ULONG WINAPI IExplorerBrowserEvents_fnAddRef(IExplorerBrowserEvents *iface)
138 {
139     IExplorerBrowserEventsImpl *This = (IExplorerBrowserEventsImpl*)iface;
140     return InterlockedIncrement(&This->ref);
141 }
142
143 static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface)
144 {
145     IExplorerBrowserEventsImpl *This = (IExplorerBrowserEventsImpl*)iface;
146     return InterlockedDecrement(&This->ref);
147 }
148
149 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationPending(IExplorerBrowserEvents *iface,
150                                                                    PCIDLIST_ABSOLUTE pidlFolder)
151 {
152     IExplorerBrowserEventsImpl *This = (IExplorerBrowserEventsImpl*)iface;
153     This->pending++;
154     return S_OK;
155 }
156
157 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBrowserEvents *iface,
158                                                                     PCIDLIST_ABSOLUTE pidlFolder)
159 {
160     IExplorerBrowserEventsImpl *This = (IExplorerBrowserEventsImpl*)iface;
161     This->completed++;
162     return S_OK;
163 }
164 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationFailed(IExplorerBrowserEvents *iface,
165                                                                   PCIDLIST_ABSOLUTE pidlFolder)
166 {
167     IExplorerBrowserEventsImpl *This = (IExplorerBrowserEventsImpl*)iface;
168     This->failed++;
169     return S_OK;
170 }
171 static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface,
172                                                              IShellView *psv)
173 {
174     IExplorerBrowserEventsImpl *This = (IExplorerBrowserEventsImpl*)iface;
175     This->created++;
176     return S_OK;
177 }
178
179 static const IExplorerBrowserEventsVtbl ebevents =
180 {
181     IExplorerBrowserEvents_fnQueryInterface,
182     IExplorerBrowserEvents_fnAddRef,
183     IExplorerBrowserEvents_fnRelease,
184     IExplorerBrowserEvents_fnOnNavigationPending,
185     IExplorerBrowserEvents_fnOnViewCreated,
186     IExplorerBrowserEvents_fnOnNavigationComplete,
187     IExplorerBrowserEvents_fnOnNavigationFailed
188 };
189
190 /*********************************************************************
191  * IServiceProvider Implementation
192  */
193 typedef struct {
194     const IServiceProviderVtbl *lpVtbl;
195     LONG ref;
196     struct services {
197         REFGUID service;
198         REFIID id;
199         int count;
200         void *punk;
201     } *interfaces;
202 } IServiceProviderImpl;
203
204 static HRESULT WINAPI IServiceProvider_fnQueryInterface(IServiceProvider *iface, REFIID riid, LPVOID *ppvObj)
205 {
206     *ppvObj = NULL;
207     if(IsEqualIID(riid, &IID_IServiceProvider))
208     {
209         *ppvObj = iface;
210         IServiceProvider_AddRef((IServiceProvider*)iface);
211         return S_OK;
212     }
213
214     if(IsEqualIID(riid, &IID_IOleCommandTarget))
215     {
216         /* Windows Vista. */
217         return E_NOINTERFACE;
218     }
219
220     ok(0, "Unexpected interface requested.\n");
221     trace("riid: "); dbg_print_guid(riid);
222     return E_NOINTERFACE;
223 }
224
225 static ULONG WINAPI IServiceProvider_fnAddRef(IServiceProvider *iface)
226 {
227     IServiceProviderImpl *This = (IServiceProviderImpl*)iface;
228     return InterlockedIncrement(&This->ref);
229 }
230
231 static ULONG WINAPI IServiceProvider_fnRelease(IServiceProvider *iface)
232 {
233     IServiceProviderImpl *This = (IServiceProviderImpl*)iface;
234     LONG ref = InterlockedDecrement(&This->ref);
235
236     if(!ref)
237         HeapFree(GetProcessHeap(), 0, This);
238
239     return ref;
240 }
241
242 static HRESULT WINAPI IServiceProvider_fnQueryService(IServiceProvider *iface,
243                                                       REFGUID guidService,
244                                                       REFIID riid,
245                                                       void **ppv)
246 {
247     IServiceProviderImpl *This = (IServiceProviderImpl*)iface;
248     BOOL was_in_list = FALSE;
249     IUnknown *punk = NULL;
250     UINT i;
251
252     *ppv = NULL;
253     for(i = 0; This->interfaces[i].service != NULL; i++)
254     {
255         if(IsEqualGUID(This->interfaces[i].service, guidService) &&
256            IsEqualIID(This->interfaces[i].id, riid))
257         {
258             was_in_list = TRUE;
259             This->interfaces[i].count++;
260             punk = This->interfaces[i].punk;
261             break;
262         }
263     }
264
265     ok(was_in_list, "-- Unknown service requested --\n");
266     if(!was_in_list)
267     {
268         trace("guidService: "); dbg_print_guid(guidService);
269         trace("riid: "); dbg_print_guid(riid);
270     }
271
272     /* Give back an interface, if any. */
273     if(punk)
274     {
275         *ppv = punk;
276         IUnknown_AddRef((IUnknown*)punk);
277         return S_OK;
278     }
279
280     return E_NOINTERFACE;
281 }
282
283 static const IServiceProviderVtbl spvtbl =
284 {
285     IServiceProvider_fnQueryInterface,
286     IServiceProvider_fnAddRef,
287     IServiceProvider_fnRelease,
288     IServiceProvider_fnQueryService
289 };
290
291 static IServiceProviderImpl *create_serviceprovider(void)
292 {
293     IServiceProviderImpl *sp = HeapAlloc(GetProcessHeap(), 0, sizeof(IServiceProviderImpl));
294     sp->lpVtbl = &spvtbl;
295     sp->ref = 1;
296     return sp;
297 }
298
299 static void test_QueryInterface(void)
300 {
301     IExplorerBrowser *peb;
302     IUnknown *punk;
303     HRESULT hr;
304     LONG lres;
305
306     hr = ebrowser_instantiate(&peb);
307     ok(hr == S_OK, "Got 0x%08x\n", hr);
308
309 #define test_qinterface(iid, exp)                                       \
310     do {                                                                \
311         hr = IExplorerBrowser_QueryInterface(peb, &iid, (void**)&punk); \
312         ok(hr == exp, "(%s:)Expected (0x%08x), got (0x%08x)\n",         \
313            #iid, exp, hr);                                              \
314         if(SUCCEEDED(hr)) IUnknown_Release(punk);                       \
315     } while(0)
316
317     test_qinterface(IID_IUnknown, S_OK);
318     test_qinterface(IID_IExplorerBrowser, S_OK);
319     test_qinterface(IID_IShellBrowser, S_OK);
320     todo_wine test_qinterface(IID_IOleWindow, S_OK);
321     test_qinterface(IID_ICommDlgBrowser, S_OK);
322     test_qinterface(IID_ICommDlgBrowser2, S_OK);
323     test_qinterface(IID_ICommDlgBrowser3, S_OK);
324     todo_wine test_qinterface(IID_IServiceProvider, S_OK);
325     test_qinterface(IID_IObjectWithSite, S_OK);
326     todo_wine test_qinterface(IID_IConnectionPointContainer, S_OK);
327     test_qinterface(IID_IOleObject, E_NOINTERFACE);
328     test_qinterface(IID_IViewObject, E_NOINTERFACE);
329     test_qinterface(IID_IViewObject2, E_NOINTERFACE);
330     test_qinterface(IID_IViewObjectEx, E_NOINTERFACE);
331     test_qinterface(IID_IConnectionPoint, E_NOINTERFACE);
332     test_qinterface(IID_IShellView, E_NOINTERFACE);
333     test_qinterface(IID_INameSpaceTreeControlEvents, E_NOINTERFACE);
334
335 #undef test_qinterface
336
337     lres = IExplorerBrowser_Release(peb);
338     ok(lres == 0, "Got %d\n", lres);
339 }
340
341 static void test_SB_misc(void)
342 {
343     IExplorerBrowser *peb;
344     IShellBrowser *psb;
345     IUnknown *punk;
346     HRESULT hr;
347     HWND retHwnd;
348     LRESULT lres;
349     LONG ref;
350
351     ebrowser_instantiate(&peb);
352     hr = IExplorerBrowser_QueryInterface(peb, &IID_IShellBrowser, (void**)&psb);
353     ok(hr == S_OK, "Got 0x%08x\n", hr);
354     if(FAILED(hr))
355     {
356         skip("Failed to get IShellBrowser interface.\n");
357         return;
358     }
359
360     /* Some unimplemented methods */
361     retHwnd = (HWND)0xDEADBEEF;
362     hr = IShellBrowser_GetControlWindow(psb, FCW_TOOLBAR, &retHwnd);
363     ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
364     ok(retHwnd == (HWND)0xDEADBEEF, "HWND overwritten\n");
365
366     hr = IShellBrowser_GetControlWindow(psb, FCW_STATUS, &retHwnd);
367     ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
368     ok(retHwnd == (HWND)0xDEADBEEF, "HWND overwritten\n");
369
370     hr = IShellBrowser_GetControlWindow(psb, FCW_TREE, &retHwnd);
371     ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
372     ok(retHwnd == (HWND)0xDEADBEEF, "HWND overwritten\n");
373
374     hr = IShellBrowser_GetControlWindow(psb, FCW_PROGRESS, &retHwnd);
375     ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
376     ok(retHwnd == (HWND)0xDEADBEEF, "HWND overwritten\n");
377
378     /* ::InsertMenuSB */
379     hr = IShellBrowser_InsertMenusSB(psb, NULL, NULL);
380     ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
381
382     /* ::RemoveMenusSB */
383     hr = IShellBrowser_RemoveMenusSB(psb, NULL);
384     ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
385
386     /* ::SetMenuSB */
387     hr = IShellBrowser_SetMenuSB(psb, NULL, NULL, NULL);
388     ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
389
390     /***** Before EB::Initialize *****/
391
392     /* ::GetWindow */
393     retHwnd = (HWND)0xDEADBEEF;
394     hr = IShellBrowser_GetWindow(psb, &retHwnd);
395     ok(hr == E_FAIL, "got (0x%08x)\n", hr);
396     ok(retHwnd == (HWND)0xDEADBEEF, "HWND overwritten\n");
397
398     todo_wine
399     {
400
401         /* ::SendControlMsg */
402         lres = 0xDEADBEEF;
403         hr = IShellBrowser_SendControlMsg(psb, FCW_STATUS, 0, 0, 0, &lres);
404         ok(hr == S_OK, "got (0x%08x)\n", hr);
405         ok(lres == 0, "lres was %ld\n", lres);
406
407         lres = 0xDEADBEEF;
408         hr = IShellBrowser_SendControlMsg(psb, FCW_TOOLBAR, TB_CHECKBUTTON,
409                                           FCIDM_TB_SMALLICON, TRUE, &lres);
410         ok(hr == S_OK, "got (0x%08x)\n", hr);
411         ok(lres == 0, "lres was %ld\n", lres);
412
413         hr = IShellBrowser_SendControlMsg(psb, FCW_STATUS, 0, 0, 0, NULL);
414         ok(hr == S_OK, "got (0x%08x)\n", hr);
415
416         hr = IShellBrowser_SendControlMsg(psb, FCW_TREE, 0, 0, 0, NULL);
417         ok(hr == S_OK, "got (0x%08x)\n", hr);
418
419         hr = IShellBrowser_SendControlMsg(psb, FCW_PROGRESS, 0, 0, 0, NULL);
420         ok(hr == S_OK, "got (0x%08x)\n", hr);
421     }
422
423     /* ::QueryActiveShellView */
424     hr = IShellBrowser_QueryActiveShellView(psb, (IShellView**)&punk);
425     ok(hr == E_FAIL, "got (0x%08x)\n", hr);
426
427     /* Initialize ExplorerBrowser */
428     ebrowser_initialize(peb);
429
430     /***** After EB::Initialize *****/
431
432     /* ::GetWindow */
433     hr = IShellBrowser_GetWindow(psb, &retHwnd);
434     ok(hr == S_OK, "got (0x%08x)\n", hr);
435     ok(GetParent(retHwnd) == hwnd, "The HWND returned is not our child.\n");
436
437     todo_wine
438     {
439         /* ::SendControlMsg */
440         hr = IShellBrowser_SendControlMsg(psb, FCW_STATUS, 0, 0, 0, NULL);
441         ok(hr == S_OK, "got (0x%08x)\n", hr);
442
443         lres = 0xDEADBEEF;
444         hr = IShellBrowser_SendControlMsg(psb, FCW_TOOLBAR, 0, 0, 0, &lres);
445         ok(hr == S_OK, "got (0x%08x)\n", hr);
446         ok(lres == 0, "lres was %ld\n", lres);
447
448         lres = 0xDEADBEEF;
449         hr = IShellBrowser_SendControlMsg(psb, FCW_STATUS, 0, 0, 0, &lres);
450         ok(hr == S_OK, "got (0x%08x)\n", hr);
451         ok(lres == 0, "lres was %ld\n", lres);
452
453         lres = 0xDEADBEEF;
454         hr = IShellBrowser_SendControlMsg(psb, 1234, 0, 0, 0, &lres);
455         ok(hr == S_OK, "got (0x%08x)\n", hr);
456         ok(lres == 0, "lres was %ld\n", lres);
457
458         /* Returns S_OK */
459         hr = IShellBrowser_SetStatusTextSB(psb, NULL);
460         ok(hr == S_OK, "got (0x%08x)\n", hr);
461
462         hr = IShellBrowser_ContextSensitiveHelp(psb, FALSE);
463         ok(hr == S_OK, "got (0x%08x)\n", hr);
464
465         hr = IShellBrowser_EnableModelessSB(psb, TRUE);
466         ok(hr == S_OK, "got (0x%08x)\n", hr);
467
468         hr = IShellBrowser_SetToolbarItems(psb, NULL, 1, 1);
469         ok(hr == S_OK, "got (0x%08x)\n", hr);
470     }
471
472     hr = IShellBrowser_QueryActiveShellView(psb, (IShellView**)&punk);
473     ok(hr == E_FAIL, "got (0x%08x)\n", hr);
474
475     IShellBrowser_Release(psb);
476     IExplorerBrowser_Destroy(peb);
477     IExplorerBrowser_Release(peb);
478
479     /* Browse to the desktop. */
480     ebrowser_instantiate(&peb);
481     ebrowser_initialize(peb);
482     IExplorerBrowser_QueryInterface(peb, &IID_IShellBrowser, (void**)&psb);
483
484     process_msgs();
485     hr = ebrowser_browse_to_desktop(peb);
486     ok(hr == S_OK, "got (0x%08x)\n", hr);
487     process_msgs();
488
489     /****** After Browsing *****/
490
491     hr = IShellBrowser_QueryActiveShellView(psb, (IShellView**)&punk);
492     ok(hr == S_OK, "got (0x%08x)\n", hr);
493     if(SUCCEEDED(hr)) IUnknown_Release(punk);
494
495     IShellBrowser_Release(psb);
496     IExplorerBrowser_Destroy(peb);
497     ref = IExplorerBrowser_Release(peb);
498     ok(ref == 0, "Got %d\n", ref);
499 }
500
501 static void test_initialization(void)
502 {
503     IExplorerBrowser *peb;
504     IShellBrowser *psb;
505     HRESULT hr;
506     ULONG lres;
507     RECT rc;
508
509     ebrowser_instantiate(&peb);
510
511     if(0)
512     {
513         /* Crashes on Windows 7 */
514         hr = IExplorerBrowser_Initialize(peb, NULL, NULL, NULL);
515         hr = IExplorerBrowser_Initialize(peb, hwnd, NULL, NULL);
516     }
517
518     ZeroMemory(&rc, sizeof(RECT));
519
520     hr = IExplorerBrowser_Initialize(peb, NULL, &rc, NULL);
521     ok(hr == E_INVALIDARG, "got (0x%08x)\n", hr);
522
523     hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
524     ok(hr == S_OK, "got (0x%08x)\n", hr);
525
526     /* Initialize twice */
527     hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
528     ok(hr == E_UNEXPECTED, "got (0x%08x)\n", hr);
529
530     hr = IExplorerBrowser_Destroy(peb);
531     ok(hr == S_OK, "got (0x%08x)\n", hr);
532
533     /* Initialize again */
534     hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
535     ok(hr == E_UNEXPECTED, "got (0x%08x)\n", hr);
536
537     /* Destroy again */
538     hr = IExplorerBrowser_Destroy(peb);
539     ok(hr == S_OK, "got (0x%08x)\n", hr);
540     lres = IExplorerBrowser_Release(peb);
541     ok(lres == 0, "Got %d\n", lres);
542
543     /* Initialize with a few different rectangles */
544     peb = NULL;
545     ebrowser_instantiate(&peb);
546     rc.left = 50; rc.top = 20; rc.right = 100; rc.bottom = 80;
547     hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
548     ok(hr == S_OK, "got (0x%08x)\n", hr);
549     hr = IExplorerBrowser_QueryInterface(peb, &IID_IShellBrowser, (void**)&psb);
550     ok(hr == S_OK, "Got 0x%08x\n", hr);
551     if(SUCCEEDED(hr))
552     {
553         HWND eb_hwnd;
554         RECT eb_rc;
555         char buf[1024];
556         LONG style, expected_style;
557         static const RECT exp_rc = {0, 0, 48, 58};
558
559         hr = IShellBrowser_GetWindow(psb, &eb_hwnd);
560         ok(hr == S_OK, "Got 0x%08x\n", hr);
561
562         GetClientRect(eb_hwnd, &eb_rc);
563         ok(EqualRect(&eb_rc, &exp_rc), "Got client rect (%d, %d)-(%d, %d)\n",
564            eb_rc.left, eb_rc.top, eb_rc.right, eb_rc.bottom);
565
566         GetWindowRect(eb_hwnd, &eb_rc);
567         ok(eb_rc.right - eb_rc.left == 50, "Got window width %d\n", eb_rc.right - eb_rc.left);
568         ok(eb_rc.bottom - eb_rc.top == 60, "Got window height %d\n", eb_rc.bottom - eb_rc.top);
569
570         buf[0] = '\0';
571         GetClassNameA(eb_hwnd, buf, 1024);
572         ok(!lstrcmpA(buf, "ExplorerBrowserControl"), "Unexpected classname %s\n", buf);
573
574         expected_style = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_BORDER;
575         style = GetWindowLongPtrW(eb_hwnd, GWL_STYLE);
576         todo_wine ok(style == expected_style, "Got style 0x%08x, expected 0x%08x\n", style, expected_style);
577
578         expected_style = WS_EX_CONTROLPARENT;
579         style = GetWindowLongPtrW(eb_hwnd, GWL_EXSTYLE);
580         ok(style == expected_style, "Got exstyle 0x%08x, expected 0x%08x\n", style, expected_style);
581
582         ok(GetParent(eb_hwnd) == hwnd, "GetParent returns %p\n", GetParent(eb_hwnd));
583
584         /* ::Destroy() destroys the window. */
585         ok(IsWindow(eb_hwnd), "eb_hwnd invalid.\n");
586         IExplorerBrowser_Destroy(peb);
587         ok(!IsWindow(eb_hwnd), "eb_hwnd valid.\n");
588
589         IShellBrowser_Release(psb);
590         lres = IExplorerBrowser_Release(peb);
591         ok(lres == 0, "Got refcount %d\n", lres);
592     }
593     else
594     {
595         skip("Skipping some tests.\n");
596
597         IExplorerBrowser_Destroy(peb);
598         lres = IExplorerBrowser_Release(peb);
599         ok(lres == 0, "Got refcount %d\n", lres);
600     }
601
602     ebrowser_instantiate(&peb);
603     rc.left = 0; rc.top = 0; rc.right = 0; rc.bottom = 0;
604     hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
605     ok(hr == S_OK, "got (0x%08x)\n", hr);
606     IExplorerBrowser_Destroy(peb);
607     lres = IExplorerBrowser_Release(peb);
608     ok(lres == 0, "Got refcount %d\n", lres);
609
610     ebrowser_instantiate(&peb);
611     rc.left = -1; rc.top = -1; rc.right = 1; rc.bottom = 1;
612     hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
613     ok(hr == S_OK, "got (0x%08x)\n", hr);
614     IExplorerBrowser_Destroy(peb);
615     lres = IExplorerBrowser_Release(peb);
616     ok(lres == 0, "Got refcount %d\n", lres);
617
618     ebrowser_instantiate(&peb);
619     rc.left = 10; rc.top = 10; rc.right = 5; rc.bottom = 5;
620     hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
621     ok(hr == S_OK, "got (0x%08x)\n", hr);
622     IExplorerBrowser_Destroy(peb);
623     lres = IExplorerBrowser_Release(peb);
624     ok(lres == 0, "Got refcount %d\n", lres);
625
626     ebrowser_instantiate(&peb);
627     rc.left = 10; rc.top = 10; rc.right = 5; rc.bottom = 5;
628     hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
629     ok(hr == S_OK, "got (0x%08x)\n", hr);
630     IExplorerBrowser_Destroy(peb);
631     lres = IExplorerBrowser_Release(peb);
632     ok(lres == 0, "Got refcount %d\n", lres);
633 }
634
635 static void test_SetSite(void)
636 {
637     IExplorerBrowser *peb;
638     IServiceProviderImpl *spimpl = create_serviceprovider();
639     IObjectWithSite *pow;
640     HRESULT hr;
641     LONG ref;
642     UINT i;
643     struct services expected[] = {
644         /* Win 7 */
645         { &SID_STopLevelBrowser,        &IID_ICommDlgBrowser2, 0, NULL },
646         { &SID_STopLevelBrowser,        &IID_IShellBrowserService, 0, NULL },
647         { &SID_STopLevelBrowser,        &IID_IShellBrowser, 0, NULL },
648         { &SID_STopLevelBrowser,        &IID_UnknownInterface8, 0, NULL },
649         { &SID_STopLevelBrowser,        &IID_IConnectionPointContainer, 0, NULL },
650         { &SID_STopLevelBrowser,        &IID_IProfferService, 0, NULL },
651         { &SID_STopLevelBrowser,        &IID_UnknownInterface9, 0, NULL },
652         { &SID_SExplorerBrowserFrame,   &IID_ICommDlgBrowser2, 0, NULL },
653         { &SID_SExplorerBrowserFrame,   &IID_ICommDlgBrowser3, 0, NULL },
654         { &SID_ExplorerPaneVisibility,  &IID_IExplorerPaneVisibility, 0, NULL },
655         { &IID_IFileDialogPrivate,      &IID_IFileDialogPrivate, 0, NULL },
656         { &IID_IFileDialogPrivate,      &IID_IFileDialog, 0, NULL },
657         { &IID_IShellTaskScheduler,     &IID_IShellTaskScheduler, 0, NULL },
658         { &IID_IShellTaskScheduler,     &IID_UnknownInterface2, 0, NULL },
659         { &IID_IWebbrowserApp,          &IID_IConnectionPointContainer, 0, NULL },
660         { &IID_IFolderView,             &IID_IFolderView, 0, NULL },
661         { &IID_ILayoutModifier,         &IID_ILayoutModifier, 0, NULL },
662         { &IID_IBrowserSettings,        &IID_IBrowserSettings, 0, NULL },
663         { &CLSID_Desktop,               &IID_IUnknown, 0, NULL },
664         { &IID_UnknownInterface1,       &IID_UnknownInterface1, 0, NULL },
665         { &IID_UnknownInterface3,       &IID_UnknownInterface3, 0, NULL },
666         { &IID_UnknownInterface4,       &IID_IUnknown, 0, NULL },
667         { &IID_UnknownInterface6,       &IID_UnknownInterface7, 0, NULL },
668         { &IID_IBrowserWithActivationNotification, &IID_IBrowserWithActivationNotification, 0, NULL },
669
670         /* Other services requested in Vista, Windows 2008 but not in Windows 7 */
671         { &IID_IBrowserSettings_Vista,  &IID_IBrowserSettings_Vista, 0, NULL },
672         { &IID_IFolderTypeModifier,     &IID_IFolderTypeModifier, 0, NULL },
673         { &SID_STopLevelBrowser,        &IID_IShellBrowserService_Vista, 0, NULL },
674         { &IID_UnknownInterface5,       &IID_UnknownInterface5, 0, NULL },
675         { &IID_ICommDlgBrowser,         &IID_ICommDlgBrowser, 0, NULL },
676         { &IID_IFileDialogPrivate_Vista,&IID_IFileDialogPrivate_Vista, 0, NULL},
677         { &IID_IFileDialogPrivate_Vista,&IID_IFileDialog, 0, NULL},
678         { &IID_UnknownInterface10,      &IID_IHTMLDocument2, 0, NULL},
679         { &SID_SMenuBandParent,         &IID_IOleCommandTarget, 0, NULL},
680         { &SID_SMenuBandParent,         &IID_IShellMenu, 0, NULL},
681         { &SID_STopLevelBrowser,        &IID_IOleWindow, 0, NULL},
682         { &SID_SMenuPopup,              &IID_IOleCommandTarget, 0, NULL},
683         { NULL }
684     };
685
686     ebrowser_instantiate(&peb);
687     IExplorerBrowser_SetOptions(peb, EBO_SHOWFRAMES);
688
689     hr = IExplorerBrowser_QueryInterface(peb, &IID_IObjectWithSite, (void**)&pow);
690     ok(hr == S_OK, "Got 0x%08x\n", hr);
691     if(SUCCEEDED(hr))
692     {
693         spimpl->interfaces = expected;
694
695         hr = IObjectWithSite_SetSite(pow, (IUnknown*)spimpl);
696         ok(hr == S_OK, "Got 0x%08x\n", hr);
697
698         if(FAILED(hr))
699             IObjectWithSite_Release(pow);
700     }
701
702     if(FAILED(hr))
703     {
704         skip("Failed to set site.\n");
705
706         IServiceProvider_Release((IServiceProvider*)spimpl);
707         IExplorerBrowser_Destroy(peb);
708         ref = IExplorerBrowser_Release(peb);
709         ok(ref == 0, "Got ref %d\n", ref);
710
711         return;
712     }
713
714     ShowWindow(hwnd, TRUE);
715     ebrowser_initialize(peb);
716     ebrowser_browse_to_desktop(peb);
717
718     for(i = 0; i < 10; i++)
719     {
720         Sleep(100);
721         process_msgs();
722     }
723     ShowWindow(hwnd, FALSE);
724
725     if(0)
726     {
727         for(i = 0; expected[i].service != NULL; i++)
728             if(!expected[i].count) trace("count %d was 0.\n", i);
729     }
730
731     /* Test when IServiceProvider is released. */
732     IServiceProvider_AddRef((IServiceProvider*)spimpl);
733     ref = IServiceProvider_Release((IServiceProvider*)spimpl);
734     ok(ref == 2, "Got ref %d\n", ref);
735
736     hr = IObjectWithSite_SetSite(pow, NULL);
737     ok(hr == S_OK, "Got 0x%08x\n", hr);
738
739     IServiceProvider_AddRef((IServiceProvider*)spimpl);
740     ref = IServiceProvider_Release((IServiceProvider*)spimpl);
741     ok(ref == 1, "Got ref %d\n", ref);
742
743     hr = IObjectWithSite_SetSite(pow, (IUnknown*)spimpl);
744     ok(hr == S_OK, "Got 0x%08x\n", hr);
745
746     IServiceProvider_AddRef((IServiceProvider*)spimpl);
747     ref = IServiceProvider_Release((IServiceProvider*)spimpl);
748     ok(ref == 2, "Got ref %d\n", ref);
749
750     IExplorerBrowser_Destroy(peb);
751
752     IServiceProvider_AddRef((IServiceProvider*)spimpl);
753     ref = IServiceProvider_Release((IServiceProvider*)spimpl);
754     ok(ref == 2, "Got ref %d\n", ref);
755
756     IObjectWithSite_Release(pow);
757     ref = IExplorerBrowser_Release(peb);
758     ok(ref == 0, "Got ref %d\n", ref);
759
760     ref = IServiceProvider_Release((IServiceProvider*)spimpl);
761     ok(ref == 0, "Got ref %d\n", ref);
762 }
763
764 static void test_basics(void)
765 {
766     IExplorerBrowser *peb;
767     IShellBrowser *psb;
768     FOLDERSETTINGS fs;
769     ULONG lres;
770     DWORD flags;
771     HDWP hdwp;
772     RECT rc;
773     HRESULT hr;
774
775     ebrowser_instantiate(&peb);
776     ebrowser_initialize(peb);
777
778     /* SetRect */
779     rc.left = 0; rc.top = 0; rc.right = 0; rc.bottom = 0;
780     hr = IExplorerBrowser_SetRect(peb, NULL, rc);
781     ok(hr == S_OK, "got (0x%08x)\n", hr);
782
783     rc.left = 100; rc.top = 100; rc.right = 10; rc.bottom = 10;
784     hr = IExplorerBrowser_SetRect(peb, NULL, rc);
785     ok(hr == S_OK, "got (0x%08x)\n", hr);
786
787     /* SetRect with DeferWindowPos */
788     rc.left = rc.top = 0; rc.right = rc.bottom = 10;
789     hdwp = BeginDeferWindowPos(1);
790     hr = IExplorerBrowser_SetRect(peb, &hdwp, rc);
791     ok(hr == S_OK, "got (0x%08x)\n", hr);
792     lres = EndDeferWindowPos(hdwp);
793     ok(lres, "EndDeferWindowPos failed.\n");
794
795     hdwp = NULL;
796     hr = IExplorerBrowser_SetRect(peb, &hdwp, rc);
797     ok(hr == S_OK, "got (0x%08x)\n", hr);
798     ok(hdwp == NULL, "got %p\n", hdwp);
799     lres = EndDeferWindowPos(hdwp);
800     ok(!lres, "EndDeferWindowPos succeeded unexpectedly.\n");
801
802     /* Test positioning */
803     rc.left = 10; rc.top = 20; rc.right = 50; rc.bottom = 50;
804     hr = IExplorerBrowser_SetRect(peb, NULL, rc);
805     ok(hr == S_OK, "got (0x%08x)\n", hr);
806     hr = IExplorerBrowser_QueryInterface(peb, &IID_IShellBrowser, (void**)&psb);
807     ok(hr == S_OK, "Got 0x%08x\n", hr);
808     if(SUCCEEDED(hr))
809     {
810         HWND eb_hwnd;
811         RECT eb_rc;
812         static const RECT exp_rc = {11, 21, 49, 49};
813
814         hr = IShellBrowser_GetWindow(psb, &eb_hwnd);
815         ok(hr == S_OK, "Got 0x%08x\n", hr);
816
817         GetClientRect(eb_hwnd, &eb_rc);
818         MapWindowPoints(eb_hwnd, hwnd, (POINT*)&eb_rc, 2);
819         ok(EqualRect(&eb_rc, &exp_rc), "Got rect (%d, %d) - (%d, %d)\n",
820            eb_rc.left, eb_rc.top, eb_rc.right, eb_rc.bottom);
821
822         IShellBrowser_Release(psb);
823     }
824
825     IExplorerBrowser_Destroy(peb);
826     IExplorerBrowser_Release(peb);
827
828     /* GetOptions/SetOptions*/
829     ebrowser_instantiate(&peb);
830
831     if(0) {
832         /* Crashes on Windows 7 */
833         IExplorerBrowser_GetOptions(peb, NULL);
834     }
835
836     hr = IExplorerBrowser_GetOptions(peb, &flags);
837     ok(hr == S_OK, "got (0x%08x)\n", hr);
838     ok(flags == 0, "got (0x%08x)\n", flags);
839
840     /* Settings preserved through Initialize. */
841     hr = IExplorerBrowser_SetOptions(peb, 0xDEADBEEF);
842     ok(hr == S_OK, "got (0x%08x)\n", hr);
843
844     ebrowser_initialize(peb);
845
846     hr = IExplorerBrowser_GetOptions(peb, &flags);
847     ok(flags == 0xDEADBEEF, "got (0x%08x)\n", flags);
848     ok(hr == S_OK, "got (0x%08x)\n", hr);
849
850     IExplorerBrowser_Destroy(peb);
851     IExplorerBrowser_Release(peb);
852
853     ebrowser_instantiate(&peb);
854     ebrowser_initialize(peb);
855
856     /* SetFolderSettings */
857     hr = IExplorerBrowser_SetFolderSettings(peb, NULL);
858     ok(hr == E_INVALIDARG, "got (0x%08x)\n", hr);
859     fs.ViewMode = 0; fs.fFlags = 0;
860     hr = IExplorerBrowser_SetFolderSettings(peb, &fs);
861     todo_wine ok(hr == E_INVALIDARG, "got (0x%08x)\n", hr);
862
863     /* TODO: Test after browsing somewhere. */
864
865     IExplorerBrowser_Destroy(peb);
866     lres = IExplorerBrowser_Release(peb);
867     ok(lres == 0, "Got %d\n", lres);
868 }
869
870 static void test_Advise(void)
871 {
872     IExplorerBrowser *peb;
873     IExplorerBrowserEvents *pebe;
874     DWORD cookies[10];
875     HRESULT hr;
876     UINT i, ref;
877
878     /* Set up our IExplorerBrowserEvents implementation */
879     ebev.lpVtbl = &ebevents;
880     pebe = (IExplorerBrowserEvents*) &ebev;
881
882     ebrowser_instantiate(&peb);
883
884     if(0)
885     {
886         /* Crashes on Windows 7 */
887         IExplorerBrowser_Advise(peb, pebe, NULL);
888         IExplorerBrowser_Advise(peb, NULL, &cookies[0]);
889     }
890
891     /* Using Unadvise with a cookie that has yet to be given out
892      * results in E_INVALIDARG */
893     hr = IExplorerBrowser_Unadvise(peb, 11);
894     ok(hr == E_INVALIDARG, "got (0x%08x)\n", hr);
895
896     /* Add some before initialization */
897     for(i = 0; i < 5; i++)
898     {
899         hr = IExplorerBrowser_Advise(peb, pebe, &cookies[i]);
900         ok(hr == S_OK, "got (0x%08x)\n", hr);
901     }
902
903     ebrowser_initialize(peb);
904
905     /* Add some after initialization */
906     for(i = 5; i < 10; i++)
907     {
908         hr = IExplorerBrowser_Advise(peb, pebe, &cookies[i]);
909         ok(hr == S_OK, "got (0x%08x)\n", hr);
910     }
911
912     ok(ebev.ref == 10, "Got %d\n", ebev.ref);
913
914     ebev.completed = 0;
915     ebrowser_browse_to_desktop(peb);
916     process_msgs();
917     ok(ebev.completed == 10, "Got %d\n", ebev.completed);
918
919     /* Remove a bunch somewhere in the middle */
920     for(i = 4; i < 8; i++)
921     {
922         hr = IExplorerBrowser_Unadvise(peb, cookies[i]);
923         ok(hr == S_OK, "got (0x%08x)\n", hr);
924     }
925
926     ebev.completed = 0;
927     ebrowser_browse_to_desktop(peb);
928     process_msgs();
929     ok(ebev.completed == 6, "Got %d\n", ebev.completed);
930
931     if(0)
932     {
933         /* Using unadvise with a previously unadvised cookie results
934          * in a crash. */
935         hr = IExplorerBrowser_Unadvise(peb, cookies[5]);
936     }
937
938     /* Remove the rest. */
939     for(i = 0; i < 10; i++)
940     {
941         if(i<4||i>7)
942         {
943             hr = IExplorerBrowser_Unadvise(peb, cookies[i]);
944             ok(hr == S_OK, "%d: got (0x%08x)\n", i, hr);
945         }
946     }
947
948     ok(ebev.ref == 0, "Got %d\n", ebev.ref);
949
950     ebev.completed = 0;
951     ebrowser_browse_to_desktop(peb);
952     process_msgs();
953     ok(ebev.completed == 0, "Got %d\n", ebev.completed);
954
955     /* ::Destroy implies ::Unadvise. */
956     hr = IExplorerBrowser_Advise(peb, pebe, &cookies[0]);
957     ok(hr == S_OK, "Got 0x%08x\n", hr);
958     ok(ebev.ref == 1, "Got %d\n", ebev.ref);
959
960     hr = IExplorerBrowser_Destroy(peb);
961     ok(hr == S_OK, "Got 0x%08x\n", hr);
962     ok(ebev.ref == 0, "Got %d\n", ebev.ref);
963
964     ref = IExplorerBrowser_Release(peb);
965     ok(!ref, "Got %d", ref);
966 }
967
968 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
969 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
970 {
971   size_t iLen;
972
973   if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
974     return NULL;
975
976   if (iLen)
977   {
978     lpszPath += iLen;
979     if (lpszPath[-1] != '\\')
980     {
981       *lpszPath++ = '\\';
982       *lpszPath = '\0';
983     }
984   }
985   return lpszPath;
986 }
987
988 static void test_browse_pidl_(IExplorerBrowser *peb, IExplorerBrowserEventsImpl *ebev,
989                               LPITEMIDLIST pidl, UINT uFlags,
990                               HRESULT hr_exp, UINT pending, UINT created, UINT failed, UINT completed,
991                               const char *file, int line)
992 {
993     HRESULT hr;
994     ebev->completed = ebev->created = ebev->pending = ebev->failed = 0;
995
996     hr = IExplorerBrowser_BrowseToIDList(peb, pidl, uFlags);
997     ok_(file, line) (hr == hr_exp, "BrowseToIDList returned 0x%08x\n", hr);
998     process_msgs();
999
1000     ok_(file, line)
1001         (ebev->pending == pending && ebev->created == created &&
1002          ebev->failed == failed && ebev->completed == completed,
1003          "Events occurred: %d, %d, %d, %d\n",
1004          ebev->pending, ebev->created, ebev->failed, ebev->completed);
1005 }
1006 #define test_browse_pidl(peb, ebev, pidl, uFlags, hr, p, cr, f, co)     \
1007     test_browse_pidl_(peb, ebev, pidl, uFlags, hr, p, cr, f, co, __FILE__, __LINE__)
1008
1009 static void test_browse_pidl_sb_(IExplorerBrowser *peb, IExplorerBrowserEventsImpl *ebev,
1010                                  LPITEMIDLIST pidl, UINT uFlags,
1011                                  HRESULT hr_exp, UINT pending, UINT created, UINT failed, UINT completed,
1012                                  const char *file, int line)
1013 {
1014     IShellBrowser *psb;
1015     HRESULT hr;
1016
1017     hr = IExplorerBrowser_QueryInterface(peb, &IID_IShellBrowser, (void**)&psb);
1018     ok_(file, line) (hr == S_OK, "QueryInterface returned 0x%08x\n", hr);
1019     if(SUCCEEDED(hr))
1020     {
1021         ebev->completed = ebev->created = ebev->pending = ebev->failed = 0;
1022
1023         hr = IShellBrowser_BrowseObject(psb, pidl, uFlags);
1024         ok_(file, line) (hr == hr_exp, "BrowseObject returned 0x%08x\n", hr);
1025         process_msgs();
1026
1027         ok_(file, line)
1028             (ebev->pending == pending && ebev->created == created &&
1029              ebev->failed == failed && ebev->completed == completed,
1030              "Events occurred: %d, %d, %d, %d\n",
1031              ebev->pending, ebev->created, ebev->failed, ebev->completed);
1032
1033         IShellBrowser_Release(psb);
1034     }
1035 }
1036 #define test_browse_pidl_sb(peb, ebev, pidl, uFlags, hr, p, cr, f, co)  \
1037     test_browse_pidl_sb_(peb, ebev, pidl, uFlags, hr, p, cr, f, co, __FILE__, __LINE__)
1038
1039 static void test_navigation(void)
1040 {
1041     IExplorerBrowser *peb, *peb2;
1042     IFolderView *pfv;
1043     IShellItem *psi;
1044     IShellFolder *psf;
1045     LPITEMIDLIST pidl_current, pidl_child;
1046     DWORD cookie, cookie2;
1047     HRESULT hr;
1048     LONG lres;
1049     WCHAR current_path[MAX_PATH];
1050     WCHAR child_path[MAX_PATH];
1051     static const WCHAR testfolderW[] =
1052         {'w','i','n','e','t','e','s','t','f','o','l','d','e','r','\0'};
1053
1054     ok(pSHParseDisplayName != NULL, "pSHParseDisplayName unexpectedly missing.\n");
1055     ok(pSHCreateShellItem != NULL, "pSHCreateShellItem unexpectedly missing.\n");
1056
1057     GetCurrentDirectoryW(MAX_PATH, current_path);
1058     if(!lstrlenW(current_path))
1059     {
1060         skip("Failed to create test-directory.\n");
1061         return;
1062     }
1063
1064     lstrcpyW(child_path, current_path);
1065     myPathAddBackslashW(child_path);
1066     lstrcatW(child_path, testfolderW);
1067
1068     CreateDirectoryW(child_path, NULL);
1069
1070     pSHParseDisplayName(current_path, NULL, &pidl_current, 0, NULL);
1071     pSHParseDisplayName(child_path, NULL, &pidl_child, 0, NULL);
1072
1073     ebrowser_instantiate(&peb);
1074     ebrowser_initialize(peb);
1075
1076     ebrowser_instantiate(&peb2);
1077     ebrowser_initialize(peb2);
1078
1079     /* Set up our IExplorerBrowserEvents implementation */
1080     ebev.lpVtbl = &ebevents;
1081
1082     IExplorerBrowser_Advise(peb, (IExplorerBrowserEvents*)&ebev, &cookie);
1083     IExplorerBrowser_Advise(peb2, (IExplorerBrowserEvents*)&ebev, &cookie2);
1084
1085     /* These should all fail */
1086     test_browse_pidl(peb, &ebev, 0, SBSP_ABSOLUTE | SBSP_RELATIVE, E_FAIL, 0, 0, 0, 0);
1087     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_ABSOLUTE | SBSP_RELATIVE, E_FAIL, 0, 0, 0, 0);
1088     test_browse_pidl(peb, &ebev, 0, SBSP_ABSOLUTE, E_INVALIDARG, 0, 0, 0, 0);
1089     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_ABSOLUTE, E_INVALIDARG, 0, 0, 0, 0);
1090     test_browse_pidl(peb, &ebev, 0, SBSP_RELATIVE, E_FAIL, 0, 0, 0, 0);
1091     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_RELATIVE, E_FAIL, 0, 0, 0, 0);
1092     test_browse_pidl(peb, &ebev, 0, SBSP_PARENT, E_FAIL, 0, 0, 0, 0);
1093     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_PARENT, E_FAIL, 0, 0, 0, 0);
1094     test_browse_pidl(peb, &ebev, 0, SBSP_NAVIGATEFORWARD, E_FAIL, 0, 0, 0, 0);
1095     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_NAVIGATEFORWARD, E_FAIL, 0, 0, 0, 0);
1096     test_browse_pidl(peb, &ebev, 0, SBSP_NAVIGATEBACK, E_FAIL, 0, 0, 0, 0);
1097     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_NAVIGATEBACK, E_FAIL, 0, 0, 0, 0);
1098
1099     /* "The first browse is synchronous" */
1100     test_browse_pidl(peb, &ebev, pidl_child, SBSP_ABSOLUTE, S_OK, 1, 1, 0, 1);
1101     test_browse_pidl_sb(peb2, &ebev, pidl_child, SBSP_ABSOLUTE, S_OK, 1, 1, 0, 1);
1102
1103     /* Navigate empty history */
1104     test_browse_pidl(peb, &ebev, 0, SBSP_NAVIGATEFORWARD, S_OK, 0, 0, 0, 0);
1105     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_NAVIGATEFORWARD, S_OK, 0, 0, 0, 0);
1106     test_browse_pidl(peb, &ebev, 0, SBSP_NAVIGATEBACK, S_OK, 0, 0, 0, 0);
1107     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_NAVIGATEBACK, S_OK, 0, 0, 0, 0);
1108
1109     /* Navigate history */
1110     test_browse_pidl(peb, &ebev, 0, SBSP_PARENT, S_OK, 1, 1, 0, 1);
1111     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_PARENT, S_OK, 1, 1, 0, 1);
1112     test_browse_pidl(peb, &ebev, 0, SBSP_NAVIGATEBACK, S_OK, 1, 1, 0, 1);
1113     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_NAVIGATEBACK, S_OK, 1, 1, 0, 1);
1114     test_browse_pidl(peb, &ebev, 0, SBSP_NAVIGATEFORWARD, S_OK, 1, 1, 0, 1);
1115     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_NAVIGATEFORWARD, S_OK, 1, 1, 0, 1);
1116     test_browse_pidl(peb, &ebev, 0, SBSP_ABSOLUTE, S_OK, 0, 0, 0, 0);
1117     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_ABSOLUTE, S_OK, 0, 0, 0, 0);
1118
1119     /* Relative navigation */
1120     test_browse_pidl(peb, &ebev, pidl_current, SBSP_ABSOLUTE, S_OK, 1, 0, 0, 1);
1121     test_browse_pidl_sb(peb2, &ebev, pidl_current, SBSP_ABSOLUTE, S_OK, 1, 0, 0, 1);
1122
1123     hr = IExplorerBrowser_GetCurrentView(peb, &IID_IFolderView, (void**)&pfv);
1124     ok(hr == S_OK, "Got 0x%08x\n", hr);
1125     if(SUCCEEDED(hr))
1126     {
1127         LPITEMIDLIST pidl_relative;
1128
1129         hr = IFolderView_GetFolder(pfv, &IID_IShellFolder, (void**)&psf);
1130         ok(hr == S_OK, "Got 0x%08x\n", hr);
1131         hr = IShellFolder_ParseDisplayName(psf, NULL, NULL, (LPWSTR)testfolderW,
1132                                            NULL, &pidl_relative, NULL);
1133         ok(hr == S_OK, "Got 0x%08x\n", hr);
1134
1135         /* Browsing to another location here before using the
1136          * pidl_relative would make ExplorerBrowser in Windows 7 show a
1137          * not-available dialog. Also, passing a relative pidl without
1138          * specifying SBSP_RELATIVE makes it look for the pidl on the
1139          * desktop
1140          */
1141
1142         test_browse_pidl(peb, &ebev, pidl_relative, SBSP_RELATIVE, S_OK, 1, 1, 0, 1);
1143         test_browse_pidl_sb(peb2, &ebev, pidl_relative, SBSP_RELATIVE, S_OK, 1, 1, 0, 1);
1144
1145         ILFree(pidl_relative);
1146         /* IShellFolder_Release(psf); */
1147         IFolderView_Release(pfv);
1148     }
1149
1150     /* misc **/
1151     test_browse_pidl(peb, &ebev, NULL, SBSP_ABSOLUTE, S_OK, 0, 0, 0, 0);
1152     test_browse_pidl_sb(peb2, &ebev, NULL, SBSP_ABSOLUTE, S_OK, 0, 0, 0, 0);
1153     test_browse_pidl(peb, &ebev, NULL, SBSP_DEFBROWSER, S_OK, 0, 0, 0, 0);
1154     test_browse_pidl_sb(peb2, &ebev, NULL, SBSP_DEFBROWSER, S_OK, 0, 0, 0, 0);
1155     test_browse_pidl(peb, &ebev, pidl_current, SBSP_SAMEBROWSER, S_OK, 1, 1, 0, 1);
1156     test_browse_pidl_sb(peb2, &ebev, pidl_current, SBSP_SAMEBROWSER, S_OK, 1, 1, 0, 1);
1157     test_browse_pidl(peb, &ebev, pidl_current, SBSP_SAMEBROWSER, S_OK, 1, 0, 0, 1);
1158     test_browse_pidl_sb(peb2, &ebev, pidl_current, SBSP_SAMEBROWSER, S_OK, 1, 0, 0, 1);
1159
1160     test_browse_pidl(peb, &ebev, pidl_current, SBSP_EXPLOREMODE, E_INVALIDARG, 0, 0, 0, 0);
1161     test_browse_pidl_sb(peb2, &ebev, pidl_current, SBSP_EXPLOREMODE, E_INVALIDARG, 0, 0, 0, 0);
1162     test_browse_pidl(peb, &ebev, pidl_current, SBSP_OPENMODE, S_OK, 1, 0, 0, 1);
1163     test_browse_pidl_sb(peb2, &ebev, pidl_current, SBSP_OPENMODE, S_OK, 1, 0, 0, 1);
1164
1165     /* SBSP_NEWBROWSER will return E_INVALIDARG, claims MSDN, but in
1166      * reality it works as one would expect (Windows 7 only?).
1167      */
1168     if(0)
1169     {
1170         IExplorerBrowser_BrowseToIDList(peb, NULL, SBSP_NEWBROWSER);
1171     }
1172
1173     hr = IExplorerBrowser_Unadvise(peb, cookie);
1174     ok(hr == S_OK, "Got 0x%08x\n", hr);
1175     IExplorerBrowser_Destroy(peb);
1176     process_msgs();
1177     hr = IExplorerBrowser_Unadvise(peb2, cookie2);
1178     ok(hr == S_OK, "Got 0x%08x\n", hr);
1179     IExplorerBrowser_Destroy(peb2);
1180     process_msgs();
1181
1182     /* Attempt browsing after destroyed */
1183     test_browse_pidl(peb, &ebev, pidl_child, SBSP_ABSOLUTE, HRESULT_FROM_WIN32(ERROR_BUSY), 0, 0, 0, 0);
1184     test_browse_pidl_sb(peb2, &ebev, pidl_child, SBSP_ABSOLUTE, HRESULT_FROM_WIN32(ERROR_BUSY), 0, 0, 0, 0);
1185
1186     lres = IExplorerBrowser_Release(peb);
1187     ok(lres == 0, "Got lres %d\n", lres);
1188     lres = IExplorerBrowser_Release(peb2);
1189     ok(lres == 0, "Got lres %d\n", lres);
1190
1191     /******************************************/
1192     /* Test some options that affect browsing */
1193
1194     ebrowser_instantiate(&peb);
1195     hr = IExplorerBrowser_Advise(peb, (IExplorerBrowserEvents*)&ebev, &cookie);
1196     ok(hr == S_OK, "Got 0x%08x\n", hr);
1197     hr = IExplorerBrowser_SetOptions(peb, EBO_NAVIGATEONCE);
1198     ok(hr == S_OK, "got (0x%08x)\n", hr);
1199     ebrowser_initialize(peb);
1200
1201     test_browse_pidl(peb, &ebev, pidl_current, 0, S_OK, 1, 1, 0, 1);
1202     test_browse_pidl(peb, &ebev, pidl_current, 0, E_FAIL, 0, 0, 0, 0);
1203
1204     hr = IExplorerBrowser_SetOptions(peb, 0);
1205     ok(hr == S_OK, "got (0x%08x)\n", hr);
1206
1207     test_browse_pidl(peb, &ebev, pidl_current, 0, S_OK, 1, 0, 0, 1);
1208     test_browse_pidl(peb, &ebev, pidl_current, 0, S_OK, 1, 0, 0, 1);
1209
1210     /* Difference in behavior lies where? */
1211     hr = IExplorerBrowser_SetOptions(peb, EBO_ALWAYSNAVIGATE);
1212     ok(hr == S_OK, "got (0x%08x)\n", hr);
1213
1214     test_browse_pidl(peb, &ebev, pidl_current, 0, S_OK, 1, 0, 0, 1);
1215     test_browse_pidl(peb, &ebev, pidl_current, 0, S_OK, 1, 0, 0, 1);
1216
1217     hr = IExplorerBrowser_Unadvise(peb, cookie);
1218     ok(hr == S_OK, "Got 0x%08x\n", hr);
1219
1220     IExplorerBrowser_Destroy(peb);
1221     lres = IExplorerBrowser_Release(peb);
1222     ok(lres == 0, "Got lres %d\n", lres);
1223
1224     /* BrowseToObject tests */
1225     ebrowser_instantiate(&peb);
1226     ebrowser_initialize(peb);
1227
1228     /* Browse to the desktop by passing an IShellFolder */
1229     hr = SHGetDesktopFolder(&psf);
1230     ok(hr == S_OK, "Got 0x%08x\n", hr);
1231     if(SUCCEEDED(hr))
1232     {
1233         hr = IExplorerBrowser_BrowseToObject(peb, (IUnknown*)psf, SBSP_DEFBROWSER);
1234         ok(hr == S_OK, "got (0x%08x)\n", hr);
1235         if(hr == S_OK) process_msgs();
1236
1237         IShellFolder_Release(psf);
1238     }
1239
1240     /* Browse to the current directory by passing a ShellItem */
1241     hr = pSHCreateShellItem(NULL, NULL, pidl_current, &psi);
1242     ok(hr == S_OK, "Got 0x%08x\n", hr);
1243     if(SUCCEEDED(hr))
1244     {
1245         hr = IExplorerBrowser_BrowseToObject(peb, (IUnknown*)psi, SBSP_DEFBROWSER);
1246         ok(hr == S_OK, "got (0x%08x)\n", hr);
1247         process_msgs();
1248
1249         IShellItem_Release(psi);
1250     }
1251
1252     IExplorerBrowser_Destroy(peb);
1253     lres = IExplorerBrowser_Release(peb);
1254     ok(lres == 0, "Got lres %d\n", lres);
1255
1256     /* Cleanup */
1257     RemoveDirectoryW(child_path);
1258     ILFree(pidl_current);
1259     ILFree(pidl_child);
1260 }
1261
1262 static void test_GetCurrentView(void)
1263 {
1264     IExplorerBrowser *peb;
1265     IUnknown *punk;
1266     HRESULT hr;
1267
1268     /* GetCurrentView */
1269     ebrowser_instantiate(&peb);
1270
1271     if(0)
1272     {
1273         /* Crashes under Windows 7 */
1274         hr = IExplorerBrowser_GetCurrentView(peb, NULL, NULL);
1275     }
1276     hr = IExplorerBrowser_GetCurrentView(peb, NULL, (void**)&punk);
1277     ok(hr == E_FAIL, "Got 0x%08x\n", hr);
1278
1279 #define test_gcv(iid, exp)                                              \
1280     do {                                                                \
1281         hr = IExplorerBrowser_GetCurrentView(peb, &iid, (void**)&punk); \
1282         ok(hr == exp, "(%s:)Expected (0x%08x), got: (0x%08x)\n",        \
1283            #iid ,exp, hr);                                              \
1284         if(SUCCEEDED(hr)) IUnknown_Release(punk);                       \
1285     } while(0)
1286
1287     test_gcv(IID_IUnknown, E_FAIL);
1288     test_gcv(IID_IUnknown, E_FAIL);
1289     test_gcv(IID_IShellView, E_FAIL);
1290     test_gcv(IID_IShellView2, E_FAIL);
1291     test_gcv(IID_IFolderView, E_FAIL);
1292     test_gcv(IID_IPersistFolder, E_FAIL);
1293     test_gcv(IID_IPersistFolder2, E_FAIL);
1294     test_gcv(IID_ICommDlgBrowser, E_FAIL);
1295     test_gcv(IID_ICommDlgBrowser2, E_FAIL);
1296     test_gcv(IID_ICommDlgBrowser3, E_FAIL);
1297
1298     ebrowser_initialize(peb);
1299     ebrowser_browse_to_desktop(peb);
1300
1301     test_gcv(IID_IUnknown, S_OK);
1302     test_gcv(IID_IUnknown, S_OK);
1303     test_gcv(IID_IShellView, S_OK);
1304     test_gcv(IID_IShellView2, S_OK);
1305     test_gcv(IID_IFolderView, S_OK);
1306     todo_wine test_gcv(IID_IPersistFolder, S_OK);
1307     test_gcv(IID_IPersistFolder2, E_NOINTERFACE);
1308     test_gcv(IID_ICommDlgBrowser, E_NOINTERFACE);
1309     test_gcv(IID_ICommDlgBrowser2, E_NOINTERFACE);
1310     test_gcv(IID_ICommDlgBrowser3, E_NOINTERFACE);
1311
1312 #undef test_gcv
1313
1314     IExplorerBrowser_Destroy(peb);
1315     IExplorerBrowser_Release(peb);
1316 }
1317
1318 static BOOL test_instantiate_control(void)
1319 {
1320     IExplorerBrowser *peb;
1321     HRESULT hr;
1322
1323     hr = ebrowser_instantiate(&peb);
1324     ok(hr == S_OK || hr == REGDB_E_CLASSNOTREG, "Got (0x%08x)\n", hr);
1325     if(FAILED(hr))
1326         return FALSE;
1327
1328     IExplorerBrowser_Release(peb);
1329     return TRUE;
1330 }
1331
1332 static void setup_window(void)
1333 {
1334     WNDCLASSW wc;
1335     static const WCHAR ebtestW[] = {'e','b','t','e','s','t',0};
1336
1337     ZeroMemory(&wc, sizeof(WNDCLASSW));
1338     wc.lpfnWndProc      = DefWindowProcW;
1339     wc.lpszClassName    = ebtestW;
1340     RegisterClassW(&wc);
1341     hwnd = CreateWindowExW(0, ebtestW, NULL, 0,
1342                            0, 0, 500, 500,
1343                            NULL, 0, 0, NULL);
1344     ok(hwnd != NULL, "Failed to create window for tests.\n");
1345 }
1346
1347 START_TEST(ebrowser)
1348 {
1349     OleInitialize(NULL);
1350
1351     if(!test_instantiate_control())
1352     {
1353         win_skip("No ExplorerBrowser control..\n");
1354         OleUninitialize();
1355         return;
1356     }
1357
1358     setup_window();
1359     init_function_pointers();
1360
1361     test_QueryInterface();
1362     test_SB_misc();
1363     test_initialization();
1364     test_basics();
1365     test_Advise();
1366     test_navigation();
1367     test_GetCurrentView();
1368     test_SetSite();
1369
1370     DestroyWindow(hwnd);
1371     OleUninitialize();
1372 }