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