hlink: Use ifaces instead of vtbl pointers in ExtensionService.
[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  * IExplorerPaneVisibility implementation
192  */
193 typedef struct
194 {
195     const IExplorerPaneVisibilityVtbl *lpVtbl;
196     LONG ref;
197     LONG count;
198     LONG np, cp, cp_o, cp_v, dp, pp, qp, aqp, unk; /* The panes */
199 } IExplorerPaneVisibilityImpl;
200
201 static HRESULT WINAPI IExplorerPaneVisibility_fnQueryInterface(IExplorerPaneVisibility *iface,
202                                                                REFIID riid, LPVOID *ppvObj)
203 {
204     ok(0, "Not called.\n");
205     trace("REFIID:"); dbg_print_guid(riid);
206     *ppvObj = NULL;
207     return E_NOINTERFACE;
208 }
209
210 static ULONG WINAPI IExplorerPaneVisibility_fnAddRef(IExplorerPaneVisibility *iface)
211 {
212     IExplorerPaneVisibilityImpl *This = (IExplorerPaneVisibilityImpl *)iface;
213     return InterlockedIncrement(&This->ref);
214 }
215
216 static ULONG WINAPI IExplorerPaneVisibility_fnRelease(IExplorerPaneVisibility *iface)
217 {
218     IExplorerPaneVisibilityImpl *This = (IExplorerPaneVisibilityImpl *)iface;
219     ULONG ref = InterlockedDecrement(&This->ref);
220
221     if(!ref)
222         HeapFree(GetProcessHeap(), 0, This);
223
224     return ref;
225 }
226
227 static HRESULT WINAPI IExplorerPaneVisibility_fnGetPaneState(IExplorerPaneVisibility *iface,
228                                                              REFEXPLORERPANE ep,
229                                                              EXPLORERPANESTATE *peps)
230 {
231     IExplorerPaneVisibilityImpl *This = (IExplorerPaneVisibilityImpl *)iface;
232     This->count++;
233
234     ok(ep != NULL, "ep is NULL.\n");
235     ok(peps != NULL, "peps is NULL.\n");
236     ok(*peps == 0, "got %d\n", *peps);
237
238     *peps = EPS_FORCE;
239     if(IsEqualGUID(&EP_NavPane, ep))                 This->np++;
240     else if(IsEqualGUID(&EP_Commands, ep))           This->cp++;
241     else if(IsEqualGUID(&EP_Commands_Organize, ep))  This->cp_o++;
242     else if(IsEqualGUID(&EP_Commands_View, ep))      This->cp_v++;
243     else if(IsEqualGUID(&EP_DetailsPane, ep))        This->dp++;
244     else if(IsEqualGUID(&EP_PreviewPane, ep))        This->pp++;
245     else if(IsEqualGUID(&EP_QueryPane, ep))          This->qp++;
246     else if(IsEqualGUID(&EP_AdvQueryPane, ep))       This->aqp++;
247     else
248     {
249         trace("Unknown explorer pane: "); dbg_print_guid(ep);
250         This->unk++;
251     }
252
253     return S_OK;
254 }
255
256 static const IExplorerPaneVisibilityVtbl epvvt =
257 {
258     IExplorerPaneVisibility_fnQueryInterface,
259     IExplorerPaneVisibility_fnAddRef,
260     IExplorerPaneVisibility_fnRelease,
261     IExplorerPaneVisibility_fnGetPaneState
262 };
263
264 static IExplorerPaneVisibilityImpl *create_explorerpanevisibility(void)
265 {
266     IExplorerPaneVisibilityImpl *epv;
267
268     epv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IExplorerPaneVisibilityImpl));
269     epv->lpVtbl = &epvvt;
270     epv->ref = 1;
271
272     return epv;
273 }
274
275 /*********************************************************************
276  * ICommDlgBrowser3 implementation
277  */
278 typedef struct
279 {
280     const ICommDlgBrowser3Vtbl *lpVtbl;
281     LONG ref;
282     UINT OnDefaultCommand, OnStateChange, IncludeObject;
283     UINT Notify, GetDefaultMenuText, GetViewFlags;
284     UINT OnColumnClicked, GetCurrentFilter, OnPreviewCreated;
285 } ICommDlgBrowser3Impl;
286
287 static HRESULT WINAPI ICommDlgBrowser3_fnQueryInterface(ICommDlgBrowser3 *iface, REFIID riid, LPVOID *ppvObj)
288 {
289     ok(0, "Not called.\n");
290     trace("riid:");    dbg_print_guid(riid);
291     *ppvObj = NULL;
292     return E_NOINTERFACE;
293 }
294
295 static ULONG WINAPI ICommDlgBrowser3_fnAddRef(ICommDlgBrowser3 *iface)
296 {
297     ICommDlgBrowser3Impl *This = (ICommDlgBrowser3Impl *)iface;
298     return InterlockedIncrement(&This->ref);
299 }
300
301 static ULONG WINAPI ICommDlgBrowser3_fnRelease(ICommDlgBrowser3 *iface)
302 {
303     ICommDlgBrowser3Impl *This = (ICommDlgBrowser3Impl *)iface;
304     ULONG ref = InterlockedDecrement(&This->ref);
305
306     if(!ref)
307         HeapFree(GetProcessHeap(), 0, This);
308
309     return ref;
310 }
311
312 static HRESULT WINAPI ICommDlgBrowser3_fnOnDefaultCommand(ICommDlgBrowser3* iface, IShellView *shv)
313 {
314     ICommDlgBrowser3Impl *This = (ICommDlgBrowser3Impl *)iface;
315     This->OnDefaultCommand++;
316     return E_NOTIMPL;
317 }
318
319 static HRESULT WINAPI ICommDlgBrowser3_fnOnStateChange(
320     ICommDlgBrowser3* iface,
321     IShellView *shv,
322     ULONG uChange)
323 {
324     ICommDlgBrowser3Impl *This = (ICommDlgBrowser3Impl *)iface;
325     This->OnStateChange++;
326     return E_NOTIMPL;
327 }
328
329 static HRESULT WINAPI ICommDlgBrowser3_fnIncludeObject(
330     ICommDlgBrowser3* iface,
331     IShellView *shv,
332     LPCITEMIDLIST pidl)
333 {
334     ICommDlgBrowser3Impl *This = (ICommDlgBrowser3Impl *)iface;
335     This->IncludeObject++;
336     return S_OK;
337 }
338
339 static HRESULT WINAPI ICommDlgBrowser3_fnNotify(
340     ICommDlgBrowser3* iface,
341     IShellView *ppshv,
342     DWORD dwNotifyType)
343 {
344     ICommDlgBrowser3Impl *This = (ICommDlgBrowser3Impl *)iface;
345     This->Notify++;
346     return E_NOTIMPL;
347 }
348
349 static HRESULT WINAPI ICommDlgBrowser3_fnGetDefaultMenuText(
350     ICommDlgBrowser3* iface,
351     IShellView *ppshv,
352     LPWSTR pszText,
353     int cchMax)
354 {
355     ICommDlgBrowser3Impl *This = (ICommDlgBrowser3Impl *)iface;
356     This->GetDefaultMenuText++;
357     return E_NOTIMPL;
358 }
359
360 static HRESULT WINAPI ICommDlgBrowser3_fnGetViewFlags(
361     ICommDlgBrowser3* iface,
362     DWORD *pdwFlags)
363 {
364     ICommDlgBrowser3Impl *This = (ICommDlgBrowser3Impl *)iface;
365     This->GetViewFlags++;
366     return E_NOTIMPL;
367 }
368
369 static HRESULT WINAPI ICommDlgBrowser3_fnOnColumnClicked(
370     ICommDlgBrowser3* iface,
371     IShellView *ppshv,
372     int iColumn)
373 {
374     ICommDlgBrowser3Impl *This = (ICommDlgBrowser3Impl *)iface;
375     This->OnColumnClicked++;
376     return E_NOTIMPL;
377 }
378
379 static HRESULT WINAPI ICommDlgBrowser3_fnGetCurrentFilter(
380     ICommDlgBrowser3* iface,
381     LPWSTR pszFileSpec,
382     int cchFileSpec)
383 {
384     ICommDlgBrowser3Impl *This = (ICommDlgBrowser3Impl *)iface;
385     This->GetCurrentFilter++;
386     return E_NOTIMPL;
387 }
388
389 static HRESULT WINAPI ICommDlgBrowser3_fnOnPreviewCreated(
390     ICommDlgBrowser3* iface,
391     IShellView *ppshv)
392 {
393     ICommDlgBrowser3Impl *This = (ICommDlgBrowser3Impl *)iface;
394     This->OnPreviewCreated++;
395     return E_NOTIMPL;
396 }
397
398 static const ICommDlgBrowser3Vtbl cdbvtbl =
399 {
400     ICommDlgBrowser3_fnQueryInterface,
401     ICommDlgBrowser3_fnAddRef,
402     ICommDlgBrowser3_fnRelease,
403     ICommDlgBrowser3_fnOnDefaultCommand,
404     ICommDlgBrowser3_fnOnStateChange,
405     ICommDlgBrowser3_fnIncludeObject,
406     ICommDlgBrowser3_fnNotify,
407     ICommDlgBrowser3_fnGetDefaultMenuText,
408     ICommDlgBrowser3_fnGetViewFlags,
409     ICommDlgBrowser3_fnOnColumnClicked,
410     ICommDlgBrowser3_fnGetCurrentFilter,
411     ICommDlgBrowser3_fnOnPreviewCreated
412 };
413
414 static ICommDlgBrowser3Impl *create_commdlgbrowser3(void)
415 {
416     ICommDlgBrowser3Impl *cdb;
417
418     cdb = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ICommDlgBrowser3Impl));
419     cdb->lpVtbl = &cdbvtbl;
420     cdb->ref = 1;
421
422     return cdb;
423 }
424
425 /*********************************************************************
426  * IServiceProvider Implementation
427  */
428 typedef struct {
429     const IServiceProviderVtbl *lpVtbl;
430     LONG ref;
431     struct services {
432         REFGUID service;
433         REFIID id;
434         int count;
435         void *punk;
436     } *interfaces;
437 } IServiceProviderImpl;
438
439 static HRESULT WINAPI IServiceProvider_fnQueryInterface(IServiceProvider *iface, REFIID riid, LPVOID *ppvObj)
440 {
441     *ppvObj = NULL;
442     if(IsEqualIID(riid, &IID_IServiceProvider))
443     {
444         *ppvObj = iface;
445         IServiceProvider_AddRef((IServiceProvider*)iface);
446         return S_OK;
447     }
448
449     if(IsEqualIID(riid, &IID_IOleCommandTarget))
450     {
451         /* Windows Vista. */
452         return E_NOINTERFACE;
453     }
454
455     ok(0, "Unexpected interface requested.\n");
456     trace("riid: "); dbg_print_guid(riid);
457     return E_NOINTERFACE;
458 }
459
460 static ULONG WINAPI IServiceProvider_fnAddRef(IServiceProvider *iface)
461 {
462     IServiceProviderImpl *This = (IServiceProviderImpl*)iface;
463     return InterlockedIncrement(&This->ref);
464 }
465
466 static ULONG WINAPI IServiceProvider_fnRelease(IServiceProvider *iface)
467 {
468     IServiceProviderImpl *This = (IServiceProviderImpl*)iface;
469     LONG ref = InterlockedDecrement(&This->ref);
470
471     if(!ref)
472         HeapFree(GetProcessHeap(), 0, This);
473
474     return ref;
475 }
476
477 static HRESULT WINAPI IServiceProvider_fnQueryService(IServiceProvider *iface,
478                                                       REFGUID guidService,
479                                                       REFIID riid,
480                                                       void **ppv)
481 {
482     IServiceProviderImpl *This = (IServiceProviderImpl*)iface;
483     BOOL was_in_list = FALSE;
484     IUnknown *punk = NULL;
485     UINT i;
486
487     *ppv = NULL;
488     for(i = 0; This->interfaces[i].service != NULL; i++)
489     {
490         if(IsEqualGUID(This->interfaces[i].service, guidService) &&
491            IsEqualIID(This->interfaces[i].id, riid))
492         {
493             was_in_list = TRUE;
494             This->interfaces[i].count++;
495             punk = This->interfaces[i].punk;
496             break;
497         }
498     }
499
500     ok(was_in_list, "-- Unknown service requested --\n");
501     if(!was_in_list)
502     {
503         trace("guidService: "); dbg_print_guid(guidService);
504         trace("riid: "); dbg_print_guid(riid);
505     }
506
507     /* Give back an interface, if any. */
508     if(punk)
509     {
510         *ppv = punk;
511         IUnknown_AddRef((IUnknown*)punk);
512         return S_OK;
513     }
514
515     return E_NOINTERFACE;
516 }
517
518 static const IServiceProviderVtbl spvtbl =
519 {
520     IServiceProvider_fnQueryInterface,
521     IServiceProvider_fnAddRef,
522     IServiceProvider_fnRelease,
523     IServiceProvider_fnQueryService
524 };
525
526 static IServiceProviderImpl *create_serviceprovider(void)
527 {
528     IServiceProviderImpl *sp = HeapAlloc(GetProcessHeap(), 0, sizeof(IServiceProviderImpl));
529     sp->lpVtbl = &spvtbl;
530     sp->ref = 1;
531     return sp;
532 }
533
534 static void test_QueryInterface(void)
535 {
536     IExplorerBrowser *peb;
537     IUnknown *punk;
538     HRESULT hr;
539     LONG lres;
540
541     hr = ebrowser_instantiate(&peb);
542     ok(hr == S_OK, "Got 0x%08x\n", hr);
543
544 #define test_qinterface(iid, exp)                                       \
545     do {                                                                \
546         hr = IExplorerBrowser_QueryInterface(peb, &iid, (void**)&punk); \
547         ok(hr == exp, "(%s:)Expected (0x%08x), got (0x%08x)\n",         \
548            #iid, exp, hr);                                              \
549         if(SUCCEEDED(hr)) IUnknown_Release(punk);                       \
550     } while(0)
551
552     test_qinterface(IID_IUnknown, S_OK);
553     test_qinterface(IID_IExplorerBrowser, S_OK);
554     test_qinterface(IID_IShellBrowser, S_OK);
555     todo_wine test_qinterface(IID_IOleWindow, S_OK);
556     test_qinterface(IID_ICommDlgBrowser, S_OK);
557     test_qinterface(IID_ICommDlgBrowser2, S_OK);
558     test_qinterface(IID_ICommDlgBrowser3, S_OK);
559     todo_wine test_qinterface(IID_IServiceProvider, S_OK);
560     test_qinterface(IID_IObjectWithSite, S_OK);
561     todo_wine test_qinterface(IID_IConnectionPointContainer, S_OK);
562     test_qinterface(IID_IOleObject, E_NOINTERFACE);
563     test_qinterface(IID_IViewObject, E_NOINTERFACE);
564     test_qinterface(IID_IViewObject2, E_NOINTERFACE);
565     test_qinterface(IID_IViewObjectEx, E_NOINTERFACE);
566     test_qinterface(IID_IConnectionPoint, E_NOINTERFACE);
567     test_qinterface(IID_IShellView, E_NOINTERFACE);
568     test_qinterface(IID_INameSpaceTreeControlEvents, E_NOINTERFACE);
569
570 #undef test_qinterface
571
572     lres = IExplorerBrowser_Release(peb);
573     ok(lres == 0, "Got %d\n", lres);
574 }
575
576 static void test_SB_misc(void)
577 {
578     IExplorerBrowser *peb;
579     IShellBrowser *psb;
580     IUnknown *punk;
581     HRESULT hr;
582     HWND retHwnd;
583     LRESULT lres;
584     LONG ref;
585
586     ebrowser_instantiate(&peb);
587     hr = IExplorerBrowser_QueryInterface(peb, &IID_IShellBrowser, (void**)&psb);
588     ok(hr == S_OK, "Got 0x%08x\n", hr);
589     if(FAILED(hr))
590     {
591         skip("Failed to get IShellBrowser interface.\n");
592         return;
593     }
594
595     /* Some unimplemented methods */
596     retHwnd = (HWND)0xDEADBEEF;
597     hr = IShellBrowser_GetControlWindow(psb, FCW_TOOLBAR, &retHwnd);
598     ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
599     ok(retHwnd == (HWND)0xDEADBEEF, "HWND overwritten\n");
600
601     hr = IShellBrowser_GetControlWindow(psb, FCW_STATUS, &retHwnd);
602     ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
603     ok(retHwnd == (HWND)0xDEADBEEF, "HWND overwritten\n");
604
605     hr = IShellBrowser_GetControlWindow(psb, FCW_TREE, &retHwnd);
606     ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
607     ok(retHwnd == (HWND)0xDEADBEEF, "HWND overwritten\n");
608
609     hr = IShellBrowser_GetControlWindow(psb, FCW_PROGRESS, &retHwnd);
610     ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
611     ok(retHwnd == (HWND)0xDEADBEEF, "HWND overwritten\n");
612
613     /* ::InsertMenuSB */
614     hr = IShellBrowser_InsertMenusSB(psb, NULL, NULL);
615     ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
616
617     /* ::RemoveMenusSB */
618     hr = IShellBrowser_RemoveMenusSB(psb, NULL);
619     ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
620
621     /* ::SetMenuSB */
622     hr = IShellBrowser_SetMenuSB(psb, NULL, NULL, NULL);
623     ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
624
625     /***** Before EB::Initialize *****/
626
627     /* ::GetWindow */
628     retHwnd = (HWND)0xDEADBEEF;
629     hr = IShellBrowser_GetWindow(psb, &retHwnd);
630     ok(hr == E_FAIL, "got (0x%08x)\n", hr);
631     ok(retHwnd == (HWND)0xDEADBEEF, "HWND overwritten\n");
632
633     todo_wine
634     {
635
636         /* ::SendControlMsg */
637         lres = 0xDEADBEEF;
638         hr = IShellBrowser_SendControlMsg(psb, FCW_STATUS, 0, 0, 0, &lres);
639         ok(hr == S_OK, "got (0x%08x)\n", hr);
640         ok(lres == 0, "lres was %ld\n", lres);
641
642         lres = 0xDEADBEEF;
643         hr = IShellBrowser_SendControlMsg(psb, FCW_TOOLBAR, TB_CHECKBUTTON,
644                                           FCIDM_TB_SMALLICON, TRUE, &lres);
645         ok(hr == S_OK, "got (0x%08x)\n", hr);
646         ok(lres == 0, "lres was %ld\n", lres);
647
648         hr = IShellBrowser_SendControlMsg(psb, FCW_STATUS, 0, 0, 0, NULL);
649         ok(hr == S_OK, "got (0x%08x)\n", hr);
650
651         hr = IShellBrowser_SendControlMsg(psb, FCW_TREE, 0, 0, 0, NULL);
652         ok(hr == S_OK, "got (0x%08x)\n", hr);
653
654         hr = IShellBrowser_SendControlMsg(psb, FCW_PROGRESS, 0, 0, 0, NULL);
655         ok(hr == S_OK, "got (0x%08x)\n", hr);
656     }
657
658     /* ::QueryActiveShellView */
659     hr = IShellBrowser_QueryActiveShellView(psb, (IShellView**)&punk);
660     ok(hr == E_FAIL, "got (0x%08x)\n", hr);
661
662     /* Initialize ExplorerBrowser */
663     ebrowser_initialize(peb);
664
665     /***** After EB::Initialize *****/
666
667     /* ::GetWindow */
668     hr = IShellBrowser_GetWindow(psb, &retHwnd);
669     ok(hr == S_OK, "got (0x%08x)\n", hr);
670     ok(GetParent(retHwnd) == hwnd, "The HWND returned is not our child.\n");
671
672     todo_wine
673     {
674         /* ::SendControlMsg */
675         hr = IShellBrowser_SendControlMsg(psb, FCW_STATUS, 0, 0, 0, NULL);
676         ok(hr == S_OK, "got (0x%08x)\n", hr);
677
678         lres = 0xDEADBEEF;
679         hr = IShellBrowser_SendControlMsg(psb, FCW_TOOLBAR, 0, 0, 0, &lres);
680         ok(hr == S_OK, "got (0x%08x)\n", hr);
681         ok(lres == 0, "lres was %ld\n", lres);
682
683         lres = 0xDEADBEEF;
684         hr = IShellBrowser_SendControlMsg(psb, FCW_STATUS, 0, 0, 0, &lres);
685         ok(hr == S_OK, "got (0x%08x)\n", hr);
686         ok(lres == 0, "lres was %ld\n", lres);
687
688         lres = 0xDEADBEEF;
689         hr = IShellBrowser_SendControlMsg(psb, 1234, 0, 0, 0, &lres);
690         ok(hr == S_OK, "got (0x%08x)\n", hr);
691         ok(lres == 0, "lres was %ld\n", lres);
692
693         /* Returns S_OK */
694         hr = IShellBrowser_SetStatusTextSB(psb, NULL);
695         ok(hr == S_OK, "got (0x%08x)\n", hr);
696
697         hr = IShellBrowser_ContextSensitiveHelp(psb, FALSE);
698         ok(hr == S_OK, "got (0x%08x)\n", hr);
699
700         hr = IShellBrowser_EnableModelessSB(psb, TRUE);
701         ok(hr == S_OK, "got (0x%08x)\n", hr);
702
703         hr = IShellBrowser_SetToolbarItems(psb, NULL, 1, 1);
704         ok(hr == S_OK, "got (0x%08x)\n", hr);
705     }
706
707     hr = IShellBrowser_QueryActiveShellView(psb, (IShellView**)&punk);
708     ok(hr == E_FAIL, "got (0x%08x)\n", hr);
709
710     IShellBrowser_Release(psb);
711     IExplorerBrowser_Destroy(peb);
712     IExplorerBrowser_Release(peb);
713
714     /* Browse to the desktop. */
715     ebrowser_instantiate(&peb);
716     ebrowser_initialize(peb);
717     IExplorerBrowser_QueryInterface(peb, &IID_IShellBrowser, (void**)&psb);
718
719     process_msgs();
720     hr = ebrowser_browse_to_desktop(peb);
721     ok(hr == S_OK, "got (0x%08x)\n", hr);
722     process_msgs();
723
724     /****** After Browsing *****/
725
726     hr = IShellBrowser_QueryActiveShellView(psb, (IShellView**)&punk);
727     ok(hr == S_OK, "got (0x%08x)\n", hr);
728     if(SUCCEEDED(hr)) IUnknown_Release(punk);
729
730     IShellBrowser_Release(psb);
731     IExplorerBrowser_Destroy(peb);
732     ref = IExplorerBrowser_Release(peb);
733     ok(ref == 0, "Got %d\n", ref);
734 }
735
736 static void test_initialization(void)
737 {
738     IExplorerBrowser *peb;
739     IShellBrowser *psb;
740     HRESULT hr;
741     ULONG lres;
742     RECT rc;
743
744     ebrowser_instantiate(&peb);
745
746     if(0)
747     {
748         /* Crashes on Windows 7 */
749         hr = IExplorerBrowser_Initialize(peb, NULL, NULL, NULL);
750         hr = IExplorerBrowser_Initialize(peb, hwnd, NULL, NULL);
751     }
752
753     ZeroMemory(&rc, sizeof(RECT));
754
755     hr = IExplorerBrowser_Initialize(peb, NULL, &rc, NULL);
756     ok(hr == E_INVALIDARG, "got (0x%08x)\n", hr);
757
758     hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
759     ok(hr == S_OK, "got (0x%08x)\n", hr);
760
761     /* Initialize twice */
762     hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
763     ok(hr == E_UNEXPECTED, "got (0x%08x)\n", hr);
764
765     hr = IExplorerBrowser_Destroy(peb);
766     ok(hr == S_OK, "got (0x%08x)\n", hr);
767
768     /* Initialize again */
769     hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
770     ok(hr == E_UNEXPECTED, "got (0x%08x)\n", hr);
771
772     /* Destroy again */
773     hr = IExplorerBrowser_Destroy(peb);
774     ok(hr == S_OK, "got (0x%08x)\n", hr);
775     lres = IExplorerBrowser_Release(peb);
776     ok(lres == 0, "Got %d\n", lres);
777
778     /* Initialize with a few different rectangles */
779     peb = NULL;
780     ebrowser_instantiate(&peb);
781     rc.left = 50; rc.top = 20; rc.right = 100; rc.bottom = 80;
782     hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
783     ok(hr == S_OK, "got (0x%08x)\n", hr);
784     hr = IExplorerBrowser_QueryInterface(peb, &IID_IShellBrowser, (void**)&psb);
785     ok(hr == S_OK, "Got 0x%08x\n", hr);
786     if(SUCCEEDED(hr))
787     {
788         HWND eb_hwnd;
789         RECT eb_rc;
790         char buf[1024];
791         LONG style, expected_style;
792         static const RECT exp_rc = {0, 0, 48, 58};
793
794         hr = IShellBrowser_GetWindow(psb, &eb_hwnd);
795         ok(hr == S_OK, "Got 0x%08x\n", hr);
796
797         GetClientRect(eb_hwnd, &eb_rc);
798         ok(EqualRect(&eb_rc, &exp_rc), "Got client rect (%d, %d)-(%d, %d)\n",
799            eb_rc.left, eb_rc.top, eb_rc.right, eb_rc.bottom);
800
801         GetWindowRect(eb_hwnd, &eb_rc);
802         ok(eb_rc.right - eb_rc.left == 50, "Got window width %d\n", eb_rc.right - eb_rc.left);
803         ok(eb_rc.bottom - eb_rc.top == 60, "Got window height %d\n", eb_rc.bottom - eb_rc.top);
804
805         buf[0] = '\0';
806         GetClassNameA(eb_hwnd, buf, 1024);
807         ok(!lstrcmpA(buf, "ExplorerBrowserControl"), "Unexpected classname %s\n", buf);
808
809         expected_style = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_BORDER;
810         style = GetWindowLongPtrW(eb_hwnd, GWL_STYLE);
811         todo_wine ok(style == expected_style, "Got style 0x%08x, expected 0x%08x\n", style, expected_style);
812
813         expected_style = WS_EX_CONTROLPARENT;
814         style = GetWindowLongPtrW(eb_hwnd, GWL_EXSTYLE);
815         ok(style == expected_style, "Got exstyle 0x%08x, expected 0x%08x\n", style, expected_style);
816
817         ok(GetParent(eb_hwnd) == hwnd, "GetParent returns %p\n", GetParent(eb_hwnd));
818
819         /* ::Destroy() destroys the window. */
820         ok(IsWindow(eb_hwnd), "eb_hwnd invalid.\n");
821         IExplorerBrowser_Destroy(peb);
822         ok(!IsWindow(eb_hwnd), "eb_hwnd valid.\n");
823
824         IShellBrowser_Release(psb);
825         lres = IExplorerBrowser_Release(peb);
826         ok(lres == 0, "Got refcount %d\n", lres);
827     }
828     else
829     {
830         skip("Skipping some tests.\n");
831
832         IExplorerBrowser_Destroy(peb);
833         lres = IExplorerBrowser_Release(peb);
834         ok(lres == 0, "Got refcount %d\n", lres);
835     }
836
837     ebrowser_instantiate(&peb);
838     rc.left = 0; rc.top = 0; rc.right = 0; rc.bottom = 0;
839     hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
840     ok(hr == S_OK, "got (0x%08x)\n", hr);
841     IExplorerBrowser_Destroy(peb);
842     lres = IExplorerBrowser_Release(peb);
843     ok(lres == 0, "Got refcount %d\n", lres);
844
845     ebrowser_instantiate(&peb);
846     rc.left = -1; rc.top = -1; rc.right = 1; rc.bottom = 1;
847     hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
848     ok(hr == S_OK, "got (0x%08x)\n", hr);
849     IExplorerBrowser_Destroy(peb);
850     lres = IExplorerBrowser_Release(peb);
851     ok(lres == 0, "Got refcount %d\n", lres);
852
853     ebrowser_instantiate(&peb);
854     rc.left = 10; rc.top = 10; rc.right = 5; rc.bottom = 5;
855     hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
856     ok(hr == S_OK, "got (0x%08x)\n", hr);
857     IExplorerBrowser_Destroy(peb);
858     lres = IExplorerBrowser_Release(peb);
859     ok(lres == 0, "Got refcount %d\n", lres);
860
861     ebrowser_instantiate(&peb);
862     rc.left = 10; rc.top = 10; rc.right = 5; rc.bottom = 5;
863     hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
864     ok(hr == S_OK, "got (0x%08x)\n", hr);
865     IExplorerBrowser_Destroy(peb);
866     lres = IExplorerBrowser_Release(peb);
867     ok(lres == 0, "Got refcount %d\n", lres);
868 }
869
870 static void test_SetSite(void)
871 {
872     IExplorerBrowser *peb;
873     IServiceProviderImpl *spimpl = create_serviceprovider();
874     ICommDlgBrowser3Impl *cdbimpl = create_commdlgbrowser3();
875     IExplorerPaneVisibilityImpl *epvimpl = create_explorerpanevisibility();
876     IObjectWithSite *pow;
877     HRESULT hr;
878     LONG ref;
879     UINT i;
880     struct services expected[] = {
881         /* Win 7 */
882         { &SID_STopLevelBrowser,        &IID_ICommDlgBrowser2, 0, cdbimpl },
883         { &SID_STopLevelBrowser,        &IID_IShellBrowserService, 0, NULL },
884         { &SID_STopLevelBrowser,        &IID_IShellBrowser, 0, NULL },
885         { &SID_STopLevelBrowser,        &IID_UnknownInterface8, 0, NULL },
886         { &SID_STopLevelBrowser,        &IID_IConnectionPointContainer, 0, NULL },
887         { &SID_STopLevelBrowser,        &IID_IProfferService, 0, NULL },
888         { &SID_STopLevelBrowser,        &IID_UnknownInterface9, 0, NULL },
889         { &SID_ExplorerPaneVisibility,  &IID_IExplorerPaneVisibility, 0, epvimpl },
890         { &SID_SExplorerBrowserFrame,   &IID_ICommDlgBrowser2, 0, cdbimpl },
891         { &SID_SExplorerBrowserFrame,   &IID_ICommDlgBrowser3, 0, cdbimpl },
892         { &IID_IFileDialogPrivate,      &IID_IFileDialogPrivate, 0, NULL },
893         { &IID_IFileDialogPrivate,      &IID_IFileDialog, 0, NULL },
894         { &IID_IShellTaskScheduler,     &IID_IShellTaskScheduler, 0, NULL },
895         { &IID_IShellTaskScheduler,     &IID_UnknownInterface2, 0, NULL },
896         { &IID_IWebbrowserApp,          &IID_IConnectionPointContainer, 0, NULL },
897         { &IID_IFolderView,             &IID_IFolderView, 0, NULL },
898         { &IID_ILayoutModifier,         &IID_ILayoutModifier, 0, NULL },
899         { &IID_IBrowserSettings,        &IID_IBrowserSettings, 0, NULL },
900         { &CLSID_Desktop,               &IID_IUnknown, 0, NULL },
901         { &IID_UnknownInterface1,       &IID_UnknownInterface1, 0, NULL },
902         { &IID_UnknownInterface3,       &IID_UnknownInterface3, 0, NULL },
903         { &IID_UnknownInterface4,       &IID_IUnknown, 0, NULL },
904         { &IID_UnknownInterface6,       &IID_UnknownInterface7, 0, NULL },
905         { &IID_IBrowserWithActivationNotification, &IID_IBrowserWithActivationNotification, 0, NULL },
906
907         /* Other services requested in Vista, Windows 2008 but not in Windows 7 */
908         { &IID_IBrowserSettings_Vista,  &IID_IBrowserSettings_Vista, 0, NULL },
909         { &IID_IFolderTypeModifier,     &IID_IFolderTypeModifier, 0, NULL },
910         { &SID_STopLevelBrowser,        &IID_IShellBrowserService_Vista, 0, NULL },
911         { &IID_UnknownInterface5,       &IID_UnknownInterface5, 0, NULL },
912         { &IID_ICommDlgBrowser,         &IID_ICommDlgBrowser, 0, cdbimpl },
913         { &IID_IFileDialogPrivate_Vista,&IID_IFileDialogPrivate_Vista, 0, NULL},
914         { &IID_IFileDialogPrivate_Vista,&IID_IFileDialog, 0, NULL},
915         { &IID_UnknownInterface10,      &IID_IHTMLDocument2, 0, NULL},
916         { &SID_SMenuBandParent,         &IID_IOleCommandTarget, 0, NULL},
917         { &SID_SMenuBandParent,         &IID_IShellMenu, 0, NULL},
918         { &SID_STopLevelBrowser,        &IID_IOleWindow, 0, NULL},
919         { &SID_SMenuPopup,              &IID_IOleCommandTarget, 0, NULL},
920         { NULL }
921     };
922
923     ebrowser_instantiate(&peb);
924     IExplorerBrowser_SetOptions(peb, EBO_SHOWFRAMES);
925
926     hr = IExplorerBrowser_QueryInterface(peb, &IID_IObjectWithSite, (void**)&pow);
927     ok(hr == S_OK, "Got 0x%08x\n", hr);
928     if(SUCCEEDED(hr))
929     {
930         spimpl->interfaces = expected;
931
932         hr = IObjectWithSite_SetSite(pow, (IUnknown*)spimpl);
933         ok(hr == S_OK, "Got 0x%08x\n", hr);
934
935         if(FAILED(hr))
936             IObjectWithSite_Release(pow);
937     }
938
939     if(FAILED(hr))
940     {
941         skip("Failed to set site.\n");
942
943         IServiceProvider_Release((IServiceProvider*)spimpl);
944         ICommDlgBrowser3_Release((ICommDlgBrowser3*)cdbimpl);
945         IExplorerPaneVisibility_Release((IExplorerPaneVisibility*)epvimpl);
946         IExplorerBrowser_Destroy(peb);
947         ref = IExplorerBrowser_Release(peb);
948         ok(ref == 0, "Got ref %d\n", ref);
949
950         return;
951     }
952
953     ShowWindow(hwnd, TRUE);
954     ebrowser_initialize(peb);
955     ebrowser_browse_to_desktop(peb);
956
957     for(i = 0; i < 10; i++)
958     {
959         Sleep(100);
960         process_msgs();
961     }
962     ShowWindow(hwnd, FALSE);
963
964     /* ICommDlgBrowser3 */
965     ok(!cdbimpl->OnDefaultCommand, "Got %d\n", cdbimpl->OnDefaultCommand);
966     todo_wine ok(cdbimpl->OnStateChange, "Got %d\n", cdbimpl->OnStateChange);
967     ok(cdbimpl->IncludeObject, "Got %d\n", cdbimpl->IncludeObject);
968     ok(!cdbimpl->Notify, "Got %d\n", cdbimpl->Notify);
969     ok(!cdbimpl->GetDefaultMenuText, "Got %d\n", cdbimpl->GetDefaultMenuText);
970     todo_wine ok(cdbimpl->GetViewFlags, "Got %d\n", cdbimpl->GetViewFlags);
971     ok(!cdbimpl->OnColumnClicked, "Got %d\n", cdbimpl->OnColumnClicked);
972     ok(!cdbimpl->GetCurrentFilter, "Got %d\n", cdbimpl->GetCurrentFilter);
973     todo_wine ok(cdbimpl->OnPreviewCreated, "Got %d\n", cdbimpl->OnPreviewCreated);
974
975     /* IExplorerPaneVisibility */
976     ok(epvimpl->np, "Got %d\n", epvimpl->np);
977     todo_wine ok(epvimpl->cp, "Got %d\n", epvimpl->cp);
978     todo_wine ok(epvimpl->cp_o, "Got %d\n", epvimpl->cp_o);
979     todo_wine ok(epvimpl->cp_v, "Got %d\n", epvimpl->cp_v);
980     todo_wine ok(epvimpl->dp, "Got %d\n", epvimpl->dp);
981     todo_wine ok(epvimpl->pp, "Got %d\n", epvimpl->pp);
982     ok(!epvimpl->qp, "Got %d\n", epvimpl->qp);
983     ok(!epvimpl->aqp, "Got %d\n", epvimpl->aqp);
984     ok(!epvimpl->unk, "Got %d\n", epvimpl->unk);
985
986     if(0)
987     {
988         for(i = 0; expected[i].service != NULL; i++)
989             if(!expected[i].count) trace("count %d was 0.\n", i);
990     }
991
992     /* Test when IServiceProvider is released. */
993     IServiceProvider_AddRef((IServiceProvider*)spimpl);
994     ref = IServiceProvider_Release((IServiceProvider*)spimpl);
995     ok(ref == 2, "Got ref %d\n", ref);
996
997     hr = IObjectWithSite_SetSite(pow, NULL);
998     ok(hr == S_OK, "Got 0x%08x\n", hr);
999
1000     IServiceProvider_AddRef((IServiceProvider*)spimpl);
1001     ref = IServiceProvider_Release((IServiceProvider*)spimpl);
1002     ok(ref == 1, "Got ref %d\n", ref);
1003
1004     hr = IObjectWithSite_SetSite(pow, (IUnknown*)spimpl);
1005     ok(hr == S_OK, "Got 0x%08x\n", hr);
1006
1007     IServiceProvider_AddRef((IServiceProvider*)spimpl);
1008     ref = IServiceProvider_Release((IServiceProvider*)spimpl);
1009     ok(ref == 2, "Got ref %d\n", ref);
1010
1011     IExplorerBrowser_Destroy(peb);
1012
1013     IServiceProvider_AddRef((IServiceProvider*)spimpl);
1014     ref = IServiceProvider_Release((IServiceProvider*)spimpl);
1015     ok(ref == 2, "Got ref %d\n", ref);
1016
1017     IObjectWithSite_Release(pow);
1018     ref = IExplorerBrowser_Release(peb);
1019     ok(ref == 0, "Got ref %d\n", ref);
1020
1021     ref = IServiceProvider_Release((IServiceProvider*)spimpl);
1022     ok(ref == 0, "Got ref %d\n", ref);
1023
1024     ref = ICommDlgBrowser3_Release((ICommDlgBrowser3*)cdbimpl);
1025     ok(ref == 0, "Got ref %d\n", ref);
1026     ref = IExplorerPaneVisibility_Release((IExplorerPaneVisibility*)epvimpl);
1027     ok(ref == 0, "Got ref %d\n", ref);
1028 }
1029
1030 static void test_basics(void)
1031 {
1032     IExplorerBrowser *peb;
1033     IShellBrowser *psb;
1034     FOLDERSETTINGS fs;
1035     ULONG lres;
1036     DWORD flags;
1037     HDWP hdwp;
1038     RECT rc;
1039     HRESULT hr;
1040     static const WCHAR winetest[] = {'W','i','n','e','T','e','s','t',0};
1041
1042     ebrowser_instantiate(&peb);
1043     ebrowser_initialize(peb);
1044
1045     /* SetRect */
1046     rc.left = 0; rc.top = 0; rc.right = 0; rc.bottom = 0;
1047     hr = IExplorerBrowser_SetRect(peb, NULL, rc);
1048     ok(hr == S_OK, "got (0x%08x)\n", hr);
1049
1050     rc.left = 100; rc.top = 100; rc.right = 10; rc.bottom = 10;
1051     hr = IExplorerBrowser_SetRect(peb, NULL, rc);
1052     ok(hr == S_OK, "got (0x%08x)\n", hr);
1053
1054     /* SetRect with DeferWindowPos */
1055     rc.left = rc.top = 0; rc.right = rc.bottom = 10;
1056     hdwp = BeginDeferWindowPos(1);
1057     hr = IExplorerBrowser_SetRect(peb, &hdwp, rc);
1058     ok(hr == S_OK, "got (0x%08x)\n", hr);
1059     lres = EndDeferWindowPos(hdwp);
1060     ok(lres, "EndDeferWindowPos failed.\n");
1061
1062     hdwp = NULL;
1063     hr = IExplorerBrowser_SetRect(peb, &hdwp, rc);
1064     ok(hr == S_OK, "got (0x%08x)\n", hr);
1065     ok(hdwp == NULL, "got %p\n", hdwp);
1066     lres = EndDeferWindowPos(hdwp);
1067     ok(!lres, "EndDeferWindowPos succeeded unexpectedly.\n");
1068
1069     /* Test positioning */
1070     rc.left = 10; rc.top = 20; rc.right = 50; rc.bottom = 50;
1071     hr = IExplorerBrowser_SetRect(peb, NULL, rc);
1072     ok(hr == S_OK, "got (0x%08x)\n", hr);
1073     hr = IExplorerBrowser_QueryInterface(peb, &IID_IShellBrowser, (void**)&psb);
1074     ok(hr == S_OK, "Got 0x%08x\n", hr);
1075     if(SUCCEEDED(hr))
1076     {
1077         HWND eb_hwnd;
1078         RECT eb_rc;
1079         static const RECT exp_rc = {11, 21, 49, 49};
1080         static const RECT exp_rc2 = {11, 21, 49, 24};
1081
1082         hr = IShellBrowser_GetWindow(psb, &eb_hwnd);
1083         ok(hr == S_OK, "Got 0x%08x\n", hr);
1084
1085         GetClientRect(eb_hwnd, &eb_rc);
1086         MapWindowPoints(eb_hwnd, hwnd, (POINT*)&eb_rc, 2);
1087         ok(EqualRect(&eb_rc, &exp_rc), "Got rect (%d, %d) - (%d, %d)\n",
1088            eb_rc.left, eb_rc.top, eb_rc.right, eb_rc.bottom);
1089
1090         /* Try resizing with invalid hdwp */
1091         rc.bottom = 25;
1092         hdwp = (HDWP)0xdeadbeef;
1093         hr = IExplorerBrowser_SetRect(peb, &hdwp, rc);
1094         ok(hr == E_FAIL, "Got 0x%08x\n", hr);
1095         GetClientRect(eb_hwnd, &eb_rc);
1096         MapWindowPoints(eb_hwnd, hwnd, (POINT*)&eb_rc, 2);
1097         ok(EqualRect(&eb_rc, &exp_rc), "Got rect (%d, %d) - (%d, %d)\n",
1098            eb_rc.left, eb_rc.top, eb_rc.right, eb_rc.bottom);
1099
1100         hdwp = NULL;
1101         hr = IExplorerBrowser_SetRect(peb, &hdwp, rc);
1102         ok(hr == S_OK, "Got 0x%08x\n", hr);
1103         GetClientRect(eb_hwnd, &eb_rc);
1104         MapWindowPoints(eb_hwnd, hwnd, (POINT*)&eb_rc, 2);
1105         ok(EqualRect(&eb_rc, &exp_rc2), "Got rect (%d, %d) - (%d, %d)\n",
1106            eb_rc.left, eb_rc.top, eb_rc.right, eb_rc.bottom);
1107
1108         IShellBrowser_Release(psb);
1109     }
1110
1111     IExplorerBrowser_Destroy(peb);
1112     IExplorerBrowser_Release(peb);
1113
1114     /* GetOptions/SetOptions*/
1115     ebrowser_instantiate(&peb);
1116
1117     if(0) {
1118         /* Crashes on Windows 7 */
1119         IExplorerBrowser_GetOptions(peb, NULL);
1120     }
1121
1122     hr = IExplorerBrowser_GetOptions(peb, &flags);
1123     ok(hr == S_OK, "got (0x%08x)\n", hr);
1124     ok(flags == 0, "got (0x%08x)\n", flags);
1125
1126     /* Settings preserved through Initialize. */
1127     hr = IExplorerBrowser_SetOptions(peb, 0xDEADBEEF);
1128     ok(hr == S_OK, "got (0x%08x)\n", hr);
1129
1130     ebrowser_initialize(peb);
1131
1132     hr = IExplorerBrowser_GetOptions(peb, &flags);
1133     ok(flags == 0xDEADBEEF, "got (0x%08x)\n", flags);
1134     ok(hr == S_OK, "got (0x%08x)\n", hr);
1135
1136     IExplorerBrowser_Destroy(peb);
1137     IExplorerBrowser_Release(peb);
1138
1139     ebrowser_instantiate(&peb);
1140     ebrowser_initialize(peb);
1141
1142     /* SetFolderSettings */
1143     hr = IExplorerBrowser_SetFolderSettings(peb, NULL);
1144     ok(hr == E_INVALIDARG, "got (0x%08x)\n", hr);
1145     fs.ViewMode = 0; fs.fFlags = 0;
1146     hr = IExplorerBrowser_SetFolderSettings(peb, &fs);
1147     todo_wine ok(hr == E_INVALIDARG, "got (0x%08x)\n", hr);
1148
1149     /* SetPropertyBag */
1150     hr = IExplorerBrowser_SetPropertyBag(peb, NULL);
1151     ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
1152     hr = IExplorerBrowser_SetPropertyBag(peb, winetest);
1153     ok(hr == S_OK, "Got 0x%08x\n", hr);
1154
1155     /* TODO: Test after browsing somewhere. */
1156
1157     IExplorerBrowser_Destroy(peb);
1158     lres = IExplorerBrowser_Release(peb);
1159     ok(lres == 0, "Got %d\n", lres);
1160 }
1161
1162 static void test_Advise(void)
1163 {
1164     IExplorerBrowser *peb;
1165     IExplorerBrowserEvents *pebe;
1166     DWORD cookies[10];
1167     HRESULT hr;
1168     UINT i, ref;
1169
1170     /* Set up our IExplorerBrowserEvents implementation */
1171     ebev.lpVtbl = &ebevents;
1172     pebe = (IExplorerBrowserEvents*) &ebev;
1173
1174     ebrowser_instantiate(&peb);
1175
1176     if(0)
1177     {
1178         /* Crashes on Windows 7 */
1179         IExplorerBrowser_Advise(peb, pebe, NULL);
1180         IExplorerBrowser_Advise(peb, NULL, &cookies[0]);
1181     }
1182
1183     /* Using Unadvise with a cookie that has yet to be given out
1184      * results in E_INVALIDARG */
1185     hr = IExplorerBrowser_Unadvise(peb, 11);
1186     ok(hr == E_INVALIDARG, "got (0x%08x)\n", hr);
1187
1188     /* Add some before initialization */
1189     for(i = 0; i < 5; i++)
1190     {
1191         hr = IExplorerBrowser_Advise(peb, pebe, &cookies[i]);
1192         ok(hr == S_OK, "got (0x%08x)\n", hr);
1193     }
1194
1195     ebrowser_initialize(peb);
1196
1197     /* Add some after initialization */
1198     for(i = 5; i < 10; i++)
1199     {
1200         hr = IExplorerBrowser_Advise(peb, pebe, &cookies[i]);
1201         ok(hr == S_OK, "got (0x%08x)\n", hr);
1202     }
1203
1204     ok(ebev.ref == 10, "Got %d\n", ebev.ref);
1205
1206     ebev.completed = 0;
1207     ebrowser_browse_to_desktop(peb);
1208     process_msgs();
1209     ok(ebev.completed == 10, "Got %d\n", ebev.completed);
1210
1211     /* Remove a bunch somewhere in the middle */
1212     for(i = 4; i < 8; i++)
1213     {
1214         hr = IExplorerBrowser_Unadvise(peb, cookies[i]);
1215         ok(hr == S_OK, "got (0x%08x)\n", hr);
1216     }
1217
1218     ebev.completed = 0;
1219     ebrowser_browse_to_desktop(peb);
1220     process_msgs();
1221     ok(ebev.completed == 6, "Got %d\n", ebev.completed);
1222
1223     if(0)
1224     {
1225         /* Using unadvise with a previously unadvised cookie results
1226          * in a crash. */
1227         hr = IExplorerBrowser_Unadvise(peb, cookies[5]);
1228     }
1229
1230     /* Remove the rest. */
1231     for(i = 0; i < 10; i++)
1232     {
1233         if(i<4||i>7)
1234         {
1235             hr = IExplorerBrowser_Unadvise(peb, cookies[i]);
1236             ok(hr == S_OK, "%d: got (0x%08x)\n", i, hr);
1237         }
1238     }
1239
1240     ok(ebev.ref == 0, "Got %d\n", ebev.ref);
1241
1242     ebev.completed = 0;
1243     ebrowser_browse_to_desktop(peb);
1244     process_msgs();
1245     ok(ebev.completed == 0, "Got %d\n", ebev.completed);
1246
1247     /* ::Destroy implies ::Unadvise. */
1248     hr = IExplorerBrowser_Advise(peb, pebe, &cookies[0]);
1249     ok(hr == S_OK, "Got 0x%08x\n", hr);
1250     ok(ebev.ref == 1, "Got %d\n", ebev.ref);
1251
1252     hr = IExplorerBrowser_Destroy(peb);
1253     ok(hr == S_OK, "Got 0x%08x\n", hr);
1254     ok(ebev.ref == 0, "Got %d\n", ebev.ref);
1255
1256     ref = IExplorerBrowser_Release(peb);
1257     ok(!ref, "Got %d\n", ref);
1258 }
1259
1260 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
1261 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
1262 {
1263   size_t iLen;
1264
1265   if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
1266     return NULL;
1267
1268   if (iLen)
1269   {
1270     lpszPath += iLen;
1271     if (lpszPath[-1] != '\\')
1272     {
1273       *lpszPath++ = '\\';
1274       *lpszPath = '\0';
1275     }
1276   }
1277   return lpszPath;
1278 }
1279
1280 static void test_browse_pidl_(IExplorerBrowser *peb, IExplorerBrowserEventsImpl *ebev,
1281                               LPITEMIDLIST pidl, UINT uFlags,
1282                               HRESULT hr_exp, UINT pending, UINT created, UINT failed, UINT completed,
1283                               const char *file, int line)
1284 {
1285     HRESULT hr;
1286     ebev->completed = ebev->created = ebev->pending = ebev->failed = 0;
1287
1288     hr = IExplorerBrowser_BrowseToIDList(peb, pidl, uFlags);
1289     ok_(file, line) (hr == hr_exp, "BrowseToIDList returned 0x%08x\n", hr);
1290     process_msgs();
1291
1292     ok_(file, line)
1293         (ebev->pending == pending && ebev->created == created &&
1294          ebev->failed == failed && ebev->completed == completed,
1295          "Events occurred: %d, %d, %d, %d\n",
1296          ebev->pending, ebev->created, ebev->failed, ebev->completed);
1297 }
1298 #define test_browse_pidl(peb, ebev, pidl, uFlags, hr, p, cr, f, co)     \
1299     test_browse_pidl_(peb, ebev, pidl, uFlags, hr, p, cr, f, co, __FILE__, __LINE__)
1300
1301 static void test_browse_pidl_sb_(IExplorerBrowser *peb, IExplorerBrowserEventsImpl *ebev,
1302                                  LPITEMIDLIST pidl, UINT uFlags,
1303                                  HRESULT hr_exp, UINT pending, UINT created, UINT failed, UINT completed,
1304                                  const char *file, int line)
1305 {
1306     IShellBrowser *psb;
1307     HRESULT hr;
1308
1309     hr = IExplorerBrowser_QueryInterface(peb, &IID_IShellBrowser, (void**)&psb);
1310     ok_(file, line) (hr == S_OK, "QueryInterface returned 0x%08x\n", hr);
1311     if(SUCCEEDED(hr))
1312     {
1313         ebev->completed = ebev->created = ebev->pending = ebev->failed = 0;
1314
1315         hr = IShellBrowser_BrowseObject(psb, pidl, uFlags);
1316         ok_(file, line) (hr == hr_exp, "BrowseObject returned 0x%08x\n", hr);
1317         process_msgs();
1318
1319         ok_(file, line)
1320             (ebev->pending == pending && ebev->created == created &&
1321              ebev->failed == failed && ebev->completed == completed,
1322              "Events occurred: %d, %d, %d, %d\n",
1323              ebev->pending, ebev->created, ebev->failed, ebev->completed);
1324
1325         IShellBrowser_Release(psb);
1326     }
1327 }
1328 #define test_browse_pidl_sb(peb, ebev, pidl, uFlags, hr, p, cr, f, co)  \
1329     test_browse_pidl_sb_(peb, ebev, pidl, uFlags, hr, p, cr, f, co, __FILE__, __LINE__)
1330
1331 static void test_navigation(void)
1332 {
1333     IExplorerBrowser *peb, *peb2;
1334     IFolderView *pfv;
1335     IShellItem *psi;
1336     IShellFolder *psf;
1337     LPITEMIDLIST pidl_current, pidl_child;
1338     DWORD cookie, cookie2;
1339     HRESULT hr;
1340     LONG lres;
1341     WCHAR current_path[MAX_PATH];
1342     WCHAR child_path[MAX_PATH];
1343     static const WCHAR testfolderW[] =
1344         {'w','i','n','e','t','e','s','t','f','o','l','d','e','r','\0'};
1345
1346     ok(pSHParseDisplayName != NULL, "pSHParseDisplayName unexpectedly missing.\n");
1347     ok(pSHCreateShellItem != NULL, "pSHCreateShellItem unexpectedly missing.\n");
1348
1349     GetCurrentDirectoryW(MAX_PATH, current_path);
1350     if(!lstrlenW(current_path))
1351     {
1352         skip("Failed to create test-directory.\n");
1353         return;
1354     }
1355
1356     lstrcpyW(child_path, current_path);
1357     myPathAddBackslashW(child_path);
1358     lstrcatW(child_path, testfolderW);
1359
1360     CreateDirectoryW(child_path, NULL);
1361
1362     pSHParseDisplayName(current_path, NULL, &pidl_current, 0, NULL);
1363     pSHParseDisplayName(child_path, NULL, &pidl_child, 0, NULL);
1364
1365     ebrowser_instantiate(&peb);
1366     ebrowser_initialize(peb);
1367
1368     ebrowser_instantiate(&peb2);
1369     ebrowser_initialize(peb2);
1370
1371     /* Set up our IExplorerBrowserEvents implementation */
1372     ebev.lpVtbl = &ebevents;
1373
1374     IExplorerBrowser_Advise(peb, (IExplorerBrowserEvents*)&ebev, &cookie);
1375     IExplorerBrowser_Advise(peb2, (IExplorerBrowserEvents*)&ebev, &cookie2);
1376
1377     /* These should all fail */
1378     test_browse_pidl(peb, &ebev, 0, SBSP_ABSOLUTE | SBSP_RELATIVE, E_FAIL, 0, 0, 0, 0);
1379     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_ABSOLUTE | SBSP_RELATIVE, E_FAIL, 0, 0, 0, 0);
1380     test_browse_pidl(peb, &ebev, 0, SBSP_ABSOLUTE, E_INVALIDARG, 0, 0, 0, 0);
1381     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_ABSOLUTE, E_INVALIDARG, 0, 0, 0, 0);
1382     test_browse_pidl(peb, &ebev, 0, SBSP_RELATIVE, E_FAIL, 0, 0, 0, 0);
1383     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_RELATIVE, E_FAIL, 0, 0, 0, 0);
1384     test_browse_pidl(peb, &ebev, 0, SBSP_PARENT, E_FAIL, 0, 0, 0, 0);
1385     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_PARENT, E_FAIL, 0, 0, 0, 0);
1386     test_browse_pidl(peb, &ebev, 0, SBSP_NAVIGATEFORWARD, E_FAIL, 0, 0, 0, 0);
1387     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_NAVIGATEFORWARD, E_FAIL, 0, 0, 0, 0);
1388     test_browse_pidl(peb, &ebev, 0, SBSP_NAVIGATEBACK, E_FAIL, 0, 0, 0, 0);
1389     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_NAVIGATEBACK, E_FAIL, 0, 0, 0, 0);
1390
1391     /* "The first browse is synchronous" */
1392     test_browse_pidl(peb, &ebev, pidl_child, SBSP_ABSOLUTE, S_OK, 1, 1, 0, 1);
1393     test_browse_pidl_sb(peb2, &ebev, pidl_child, SBSP_ABSOLUTE, S_OK, 1, 1, 0, 1);
1394
1395     /* Navigate empty history */
1396     test_browse_pidl(peb, &ebev, 0, SBSP_NAVIGATEFORWARD, S_OK, 0, 0, 0, 0);
1397     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_NAVIGATEFORWARD, S_OK, 0, 0, 0, 0);
1398     test_browse_pidl(peb, &ebev, 0, SBSP_NAVIGATEBACK, S_OK, 0, 0, 0, 0);
1399     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_NAVIGATEBACK, S_OK, 0, 0, 0, 0);
1400
1401     /* Navigate history */
1402     test_browse_pidl(peb, &ebev, 0, SBSP_PARENT, S_OK, 1, 1, 0, 1);
1403     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_PARENT, S_OK, 1, 1, 0, 1);
1404     test_browse_pidl(peb, &ebev, 0, SBSP_NAVIGATEBACK, S_OK, 1, 1, 0, 1);
1405     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_NAVIGATEBACK, S_OK, 1, 1, 0, 1);
1406     test_browse_pidl(peb, &ebev, 0, SBSP_NAVIGATEFORWARD, S_OK, 1, 1, 0, 1);
1407     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_NAVIGATEFORWARD, S_OK, 1, 1, 0, 1);
1408     test_browse_pidl(peb, &ebev, 0, SBSP_ABSOLUTE, S_OK, 0, 0, 0, 0);
1409     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_ABSOLUTE, S_OK, 0, 0, 0, 0);
1410
1411     /* Relative navigation */
1412     test_browse_pidl(peb, &ebev, pidl_current, SBSP_ABSOLUTE, S_OK, 1, 0, 0, 1);
1413     test_browse_pidl_sb(peb2, &ebev, pidl_current, SBSP_ABSOLUTE, S_OK, 1, 0, 0, 1);
1414
1415     hr = IExplorerBrowser_GetCurrentView(peb, &IID_IFolderView, (void**)&pfv);
1416     ok(hr == S_OK, "Got 0x%08x\n", hr);
1417     if(SUCCEEDED(hr))
1418     {
1419         LPITEMIDLIST pidl_relative;
1420
1421         hr = IFolderView_GetFolder(pfv, &IID_IShellFolder, (void**)&psf);
1422         ok(hr == S_OK, "Got 0x%08x\n", hr);
1423         hr = IShellFolder_ParseDisplayName(psf, NULL, NULL, (LPWSTR)testfolderW,
1424                                            NULL, &pidl_relative, NULL);
1425         ok(hr == S_OK, "Got 0x%08x\n", hr);
1426
1427         /* Browsing to another location here before using the
1428          * pidl_relative would make ExplorerBrowser in Windows 7 show a
1429          * not-available dialog. Also, passing a relative pidl without
1430          * specifying SBSP_RELATIVE makes it look for the pidl on the
1431          * desktop
1432          */
1433
1434         test_browse_pidl(peb, &ebev, pidl_relative, SBSP_RELATIVE, S_OK, 1, 1, 0, 1);
1435         test_browse_pidl_sb(peb2, &ebev, pidl_relative, SBSP_RELATIVE, S_OK, 1, 1, 0, 1);
1436
1437         ILFree(pidl_relative);
1438         /* IShellFolder_Release(psf); */
1439         IFolderView_Release(pfv);
1440     }
1441
1442     /* misc **/
1443     test_browse_pidl(peb, &ebev, NULL, SBSP_ABSOLUTE, S_OK, 0, 0, 0, 0);
1444     test_browse_pidl_sb(peb2, &ebev, NULL, SBSP_ABSOLUTE, S_OK, 0, 0, 0, 0);
1445     test_browse_pidl(peb, &ebev, NULL, SBSP_DEFBROWSER, S_OK, 0, 0, 0, 0);
1446     test_browse_pidl_sb(peb2, &ebev, NULL, SBSP_DEFBROWSER, S_OK, 0, 0, 0, 0);
1447     test_browse_pidl(peb, &ebev, pidl_current, SBSP_SAMEBROWSER, S_OK, 1, 1, 0, 1);
1448     test_browse_pidl_sb(peb2, &ebev, pidl_current, SBSP_SAMEBROWSER, S_OK, 1, 1, 0, 1);
1449     test_browse_pidl(peb, &ebev, pidl_current, SBSP_SAMEBROWSER, S_OK, 1, 0, 0, 1);
1450     test_browse_pidl_sb(peb2, &ebev, pidl_current, SBSP_SAMEBROWSER, S_OK, 1, 0, 0, 1);
1451
1452     test_browse_pidl(peb, &ebev, pidl_current, SBSP_EXPLOREMODE, E_INVALIDARG, 0, 0, 0, 0);
1453     test_browse_pidl_sb(peb2, &ebev, pidl_current, SBSP_EXPLOREMODE, E_INVALIDARG, 0, 0, 0, 0);
1454     test_browse_pidl(peb, &ebev, pidl_current, SBSP_OPENMODE, S_OK, 1, 0, 0, 1);
1455     test_browse_pidl_sb(peb2, &ebev, pidl_current, SBSP_OPENMODE, S_OK, 1, 0, 0, 1);
1456
1457     /* SBSP_NEWBROWSER will return E_INVALIDARG, claims MSDN, but in
1458      * reality it works as one would expect (Windows 7 only?).
1459      */
1460     if(0)
1461     {
1462         IExplorerBrowser_BrowseToIDList(peb, NULL, SBSP_NEWBROWSER);
1463     }
1464
1465     hr = IExplorerBrowser_Unadvise(peb, cookie);
1466     ok(hr == S_OK, "Got 0x%08x\n", hr);
1467     IExplorerBrowser_Destroy(peb);
1468     process_msgs();
1469     hr = IExplorerBrowser_Unadvise(peb2, cookie2);
1470     ok(hr == S_OK, "Got 0x%08x\n", hr);
1471     IExplorerBrowser_Destroy(peb2);
1472     process_msgs();
1473
1474     /* Attempt browsing after destroyed */
1475     test_browse_pidl(peb, &ebev, pidl_child, SBSP_ABSOLUTE, HRESULT_FROM_WIN32(ERROR_BUSY), 0, 0, 0, 0);
1476     test_browse_pidl_sb(peb2, &ebev, pidl_child, SBSP_ABSOLUTE, HRESULT_FROM_WIN32(ERROR_BUSY), 0, 0, 0, 0);
1477
1478     lres = IExplorerBrowser_Release(peb);
1479     ok(lres == 0, "Got lres %d\n", lres);
1480     lres = IExplorerBrowser_Release(peb2);
1481     ok(lres == 0, "Got lres %d\n", lres);
1482
1483     /******************************************/
1484     /* Test some options that affect browsing */
1485
1486     ebrowser_instantiate(&peb);
1487     hr = IExplorerBrowser_Advise(peb, (IExplorerBrowserEvents*)&ebev, &cookie);
1488     ok(hr == S_OK, "Got 0x%08x\n", hr);
1489     hr = IExplorerBrowser_SetOptions(peb, EBO_NAVIGATEONCE);
1490     ok(hr == S_OK, "got (0x%08x)\n", hr);
1491     ebrowser_initialize(peb);
1492
1493     test_browse_pidl(peb, &ebev, pidl_current, 0, S_OK, 1, 1, 0, 1);
1494     test_browse_pidl(peb, &ebev, pidl_current, 0, E_FAIL, 0, 0, 0, 0);
1495
1496     hr = IExplorerBrowser_SetOptions(peb, 0);
1497     ok(hr == S_OK, "got (0x%08x)\n", hr);
1498
1499     test_browse_pidl(peb, &ebev, pidl_current, 0, S_OK, 1, 0, 0, 1);
1500     test_browse_pidl(peb, &ebev, pidl_current, 0, S_OK, 1, 0, 0, 1);
1501
1502     /* Difference in behavior lies where? */
1503     hr = IExplorerBrowser_SetOptions(peb, EBO_ALWAYSNAVIGATE);
1504     ok(hr == S_OK, "got (0x%08x)\n", hr);
1505
1506     test_browse_pidl(peb, &ebev, pidl_current, 0, S_OK, 1, 0, 0, 1);
1507     test_browse_pidl(peb, &ebev, pidl_current, 0, S_OK, 1, 0, 0, 1);
1508
1509     hr = IExplorerBrowser_Unadvise(peb, cookie);
1510     ok(hr == S_OK, "Got 0x%08x\n", hr);
1511
1512     IExplorerBrowser_Destroy(peb);
1513     lres = IExplorerBrowser_Release(peb);
1514     ok(lres == 0, "Got lres %d\n", lres);
1515
1516     /* BrowseToObject tests */
1517     ebrowser_instantiate(&peb);
1518     ebrowser_initialize(peb);
1519
1520     /* Browse to the desktop by passing an IShellFolder */
1521     hr = SHGetDesktopFolder(&psf);
1522     ok(hr == S_OK, "Got 0x%08x\n", hr);
1523     if(SUCCEEDED(hr))
1524     {
1525         hr = IExplorerBrowser_BrowseToObject(peb, (IUnknown*)psf, SBSP_DEFBROWSER);
1526         ok(hr == S_OK, "got (0x%08x)\n", hr);
1527         if(hr == S_OK) process_msgs();
1528
1529         IShellFolder_Release(psf);
1530     }
1531
1532     /* Browse to the current directory by passing a ShellItem */
1533     hr = pSHCreateShellItem(NULL, NULL, pidl_current, &psi);
1534     ok(hr == S_OK, "Got 0x%08x\n", hr);
1535     if(SUCCEEDED(hr))
1536     {
1537         hr = IExplorerBrowser_BrowseToObject(peb, (IUnknown*)psi, SBSP_DEFBROWSER);
1538         ok(hr == S_OK, "got (0x%08x)\n", hr);
1539         process_msgs();
1540
1541         IShellItem_Release(psi);
1542     }
1543
1544     IExplorerBrowser_Destroy(peb);
1545     lres = IExplorerBrowser_Release(peb);
1546     ok(lres == 0, "Got lres %d\n", lres);
1547
1548     /* Cleanup */
1549     RemoveDirectoryW(child_path);
1550     ILFree(pidl_current);
1551     ILFree(pidl_child);
1552 }
1553
1554 static void test_GetCurrentView(void)
1555 {
1556     IExplorerBrowser *peb;
1557     IUnknown *punk;
1558     HRESULT hr;
1559
1560     /* GetCurrentView */
1561     ebrowser_instantiate(&peb);
1562
1563     if(0)
1564     {
1565         /* Crashes under Windows 7 */
1566         hr = IExplorerBrowser_GetCurrentView(peb, NULL, NULL);
1567     }
1568     hr = IExplorerBrowser_GetCurrentView(peb, NULL, (void**)&punk);
1569     ok(hr == E_FAIL, "Got 0x%08x\n", hr);
1570
1571 #define test_gcv(iid, exp)                                              \
1572     do {                                                                \
1573         hr = IExplorerBrowser_GetCurrentView(peb, &iid, (void**)&punk); \
1574         ok(hr == exp, "(%s:)Expected (0x%08x), got: (0x%08x)\n",        \
1575            #iid ,exp, hr);                                              \
1576         if(SUCCEEDED(hr)) IUnknown_Release(punk);                       \
1577     } while(0)
1578
1579     test_gcv(IID_IUnknown, E_FAIL);
1580     test_gcv(IID_IUnknown, E_FAIL);
1581     test_gcv(IID_IShellView, E_FAIL);
1582     test_gcv(IID_IShellView2, E_FAIL);
1583     test_gcv(IID_IFolderView, E_FAIL);
1584     test_gcv(IID_IPersistFolder, E_FAIL);
1585     test_gcv(IID_IPersistFolder2, E_FAIL);
1586     test_gcv(IID_ICommDlgBrowser, E_FAIL);
1587     test_gcv(IID_ICommDlgBrowser2, E_FAIL);
1588     test_gcv(IID_ICommDlgBrowser3, E_FAIL);
1589
1590     ebrowser_initialize(peb);
1591     ebrowser_browse_to_desktop(peb);
1592
1593     test_gcv(IID_IUnknown, S_OK);
1594     test_gcv(IID_IUnknown, S_OK);
1595     test_gcv(IID_IShellView, S_OK);
1596     test_gcv(IID_IShellView2, S_OK);
1597     test_gcv(IID_IFolderView, S_OK);
1598     todo_wine test_gcv(IID_IPersistFolder, S_OK);
1599     test_gcv(IID_IPersistFolder2, E_NOINTERFACE);
1600     test_gcv(IID_ICommDlgBrowser, E_NOINTERFACE);
1601     test_gcv(IID_ICommDlgBrowser2, E_NOINTERFACE);
1602     test_gcv(IID_ICommDlgBrowser3, E_NOINTERFACE);
1603
1604 #undef test_gcv
1605
1606     IExplorerBrowser_Destroy(peb);
1607     IExplorerBrowser_Release(peb);
1608 }
1609
1610 static void test_InputObject(void)
1611 {
1612     IExplorerBrowser *peb;
1613     IShellFolder *psf;
1614     IInputObject *pio;
1615     HRESULT hr;
1616     RECT rc;
1617     UINT i;
1618     WPARAM supported_key_accels_mode1[] = {
1619         VK_BACK, VK_TAB, VK_RETURN, VK_PRIOR, VK_NEXT, VK_END, VK_HOME,
1620         VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_DELETE, VK_F1, VK_F2,
1621         VK_F5, VK_F6, VK_F10, 0 };
1622     WPARAM supported_key_accels_mode2[] = {
1623         VK_RETURN, VK_PRIOR, VK_NEXT, VK_END, VK_HOME,
1624         VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_DELETE, VK_F1, VK_F2,
1625         VK_F10, 0 };
1626     WPARAM *key_accels;
1627     MSG msg_a = {
1628         hwnd,
1629         WM_KEYDOWN,
1630         VK_F5, 0,
1631         GetTickCount(),
1632         {5, 2}
1633     };
1634
1635     ebrowser_instantiate(&peb);
1636     hr = IExplorerBrowser_QueryInterface(peb, &IID_IInputObject, (void**)&pio);
1637     ok(hr == S_OK, "Got 0x%08x\n", hr);
1638     if(FAILED(hr))
1639     {
1640         win_skip("IInputObject not supported.\n");
1641         return;
1642     }
1643
1644     /* Before initializing */
1645     hr = IInputObject_TranslateAcceleratorIO(pio, &msg_a);
1646     todo_wine ok(hr == E_FAIL, "Got 0x%08x\n", hr);
1647
1648     hr = IInputObject_HasFocusIO(pio);
1649     todo_wine ok(hr == E_FAIL, "Got 0x%08x\n", hr);
1650
1651     hr = IInputObject_UIActivateIO(pio, TRUE, &msg_a);
1652     todo_wine ok(hr == S_OK, "Got 0x%08x\n", hr);
1653
1654     hr = IInputObject_HasFocusIO(pio);
1655     todo_wine ok(hr == E_FAIL, "Got 0x%08x\n", hr);
1656
1657     hr = IInputObject_TranslateAcceleratorIO(pio, &msg_a);
1658     todo_wine ok(hr == E_FAIL, "Got 0x%08x\n", hr);
1659
1660     rc.left = 0; rc.top = 0; rc.right = 100; rc.bottom = 100;
1661     hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
1662     ok(hr == S_OK, "Got 0x%08x\n", hr);
1663
1664     hr = IInputObject_HasFocusIO(pio);
1665     todo_wine ok(hr == E_FAIL, "Got 0x%08x\n", hr);
1666
1667     hr = IInputObject_TranslateAcceleratorIO(pio, &msg_a);
1668     todo_wine ok(hr == E_FAIL, "Got 0x%08x\n", hr);
1669
1670     /* Browse to the desktop */
1671     SHGetDesktopFolder(&psf);
1672     hr = IExplorerBrowser_BrowseToObject(peb, (IUnknown*)psf, SBSP_DEFBROWSER);
1673     ok(hr == S_OK, "Got 0x%08x\n", hr);
1674     IShellFolder_Release(psf);
1675
1676     hr = IInputObject_UIActivateIO(pio, TRUE, &msg_a);
1677     todo_wine ok(hr == S_OK, "Got 0x%08x\n", hr);
1678
1679     hr = IInputObject_HasFocusIO(pio);
1680     todo_wine ok(hr == S_OK, "Got 0x%08x\n", hr);
1681
1682     hr = IInputObject_UIActivateIO(pio, FALSE, &msg_a);
1683     todo_wine ok(hr == S_OK, "Got 0x%08x\n", hr);
1684
1685     hr = IInputObject_HasFocusIO(pio);
1686     todo_wine ok(hr == S_OK, "Got 0x%08x\n", hr);
1687
1688     hr = IInputObject_TranslateAcceleratorIO(pio, &msg_a);
1689     if(hr == S_OK)
1690         key_accels = supported_key_accels_mode1;
1691     else
1692         key_accels = supported_key_accels_mode2;
1693
1694     for(i = 0; i < 0x100; i++)
1695     {
1696         BOOL found = FALSE;
1697         UINT j;
1698         for(j = 0; key_accels[j] != 0; j++)
1699             if(key_accels[j] == i)
1700             {
1701                 found = TRUE;
1702                 break;
1703             }
1704
1705         msg_a.wParam = i;
1706         process_msgs();
1707         hr = IInputObject_TranslateAcceleratorIO(pio, &msg_a);
1708         todo_wine ok(hr == (found ? S_OK : S_FALSE), "Got 0x%08x (%04x)\n", hr, i);
1709         if(i == VK_F5)
1710             Sleep(1000); /* Needed for w2k8 (64bit) */
1711     }
1712
1713     process_msgs();
1714
1715     IInputObject_Release(pio);
1716     IExplorerBrowser_Destroy(peb);
1717     IExplorerBrowser_Release(peb);
1718 }
1719
1720 static BOOL test_instantiate_control(void)
1721 {
1722     IExplorerBrowser *peb;
1723     HRESULT hr;
1724
1725     hr = ebrowser_instantiate(&peb);
1726     ok(hr == S_OK || hr == REGDB_E_CLASSNOTREG, "Got (0x%08x)\n", hr);
1727     if(FAILED(hr))
1728         return FALSE;
1729
1730     IExplorerBrowser_Release(peb);
1731     return TRUE;
1732 }
1733
1734 static void setup_window(void)
1735 {
1736     WNDCLASSW wc;
1737     static const WCHAR ebtestW[] = {'e','b','t','e','s','t',0};
1738
1739     ZeroMemory(&wc, sizeof(WNDCLASSW));
1740     wc.lpfnWndProc      = DefWindowProcW;
1741     wc.lpszClassName    = ebtestW;
1742     RegisterClassW(&wc);
1743     hwnd = CreateWindowExW(0, ebtestW, NULL, 0,
1744                            0, 0, 500, 500,
1745                            NULL, 0, 0, NULL);
1746     ok(hwnd != NULL, "Failed to create window for tests.\n");
1747 }
1748
1749 START_TEST(ebrowser)
1750 {
1751     OleInitialize(NULL);
1752
1753     if(!test_instantiate_control())
1754     {
1755         win_skip("No ExplorerBrowser control..\n");
1756         OleUninitialize();
1757         return;
1758     }
1759
1760     setup_window();
1761     init_function_pointers();
1762
1763     test_QueryInterface();
1764     test_SB_misc();
1765     test_initialization();
1766     test_basics();
1767     test_Advise();
1768     test_navigation();
1769     test_GetCurrentView();
1770     test_SetSite();
1771     test_InputObject();
1772
1773     DestroyWindow(hwnd);
1774     OleUninitialize();
1775 }