shell32/tests: Add some tests related to the shellview created by ExplorerBrowser.
[wine] / dlls / shell32 / ebrowser.c
1 /*
2  * ExplorerBrowser Control implementation.
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 <stdarg.h>
22
23 #define COBJMACROS
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
26
27 #include "winerror.h"
28 #include "windef.h"
29 #include "winbase.h"
30
31 #include "wine/list.h"
32 #include "wine/debug.h"
33 #include "debughlp.h"
34
35 #include "shell32_main.h"
36 #include "pidl.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(shell);
39
40 typedef struct _event_client {
41     struct list entry;
42     IExplorerBrowserEvents *pebe;
43     DWORD cookie;
44 } event_client;
45
46 typedef struct _ExplorerBrowserImpl {
47     const IExplorerBrowserVtbl *lpVtbl;
48     const IShellBrowserVtbl *lpsbVtbl;
49     LONG ref;
50     BOOL destroyed;
51
52     HWND hwnd_main;
53     HWND hwnd_sv;
54
55     EXPLORER_BROWSER_OPTIONS eb_options;
56     FOLDERSETTINGS fs;
57
58     struct list event_clients;
59     DWORD events_next_cookie;
60
61     IShellView *psv;
62     RECT sv_rc;
63     LPITEMIDLIST current_pidl;
64 } ExplorerBrowserImpl;
65
66 /**************************************************************************
67  * Event functions.
68  */
69 static void events_unadvise_all(ExplorerBrowserImpl *This)
70 {
71     event_client *client, *curs;
72     TRACE("%p\n", This);
73
74     LIST_FOR_EACH_ENTRY_SAFE(client, curs, &This->event_clients, event_client, entry)
75     {
76         TRACE("Removing %p\n", client);
77         list_remove(&client->entry);
78         IExplorerBrowserEvents_Release(client->pebe);
79         HeapFree(GetProcessHeap(), 0, client);
80     }
81 }
82
83 static HRESULT events_NavigationPending(ExplorerBrowserImpl *This, PCIDLIST_ABSOLUTE pidl)
84 {
85     event_client *cursor;
86     HRESULT hres = S_OK;
87
88     TRACE("%p\n", This);
89
90     LIST_FOR_EACH_ENTRY(cursor, &This->event_clients, event_client, entry)
91     {
92         TRACE("Notifying %p\n", cursor);
93         hres = IExplorerBrowserEvents_OnNavigationPending(cursor->pebe, pidl);
94
95         /* If this failed for any reason, the browsing is supposed to be aborted. */
96         if(FAILED(hres))
97             break;
98     }
99
100     return hres;
101 }
102
103 static void events_NavigationComplete(ExplorerBrowserImpl *This, PCIDLIST_ABSOLUTE pidl)
104 {
105     event_client *cursor;
106
107     TRACE("%p\n", This);
108
109     LIST_FOR_EACH_ENTRY(cursor, &This->event_clients, event_client, entry)
110     {
111         TRACE("Notifying %p\n", cursor);
112         IExplorerBrowserEvents_OnNavigationComplete(cursor->pebe, pidl);
113     }
114 }
115
116 static void events_NavigationFailed(ExplorerBrowserImpl *This, PCIDLIST_ABSOLUTE pidl)
117 {
118     event_client *cursor;
119
120     TRACE("%p\n", This);
121
122     LIST_FOR_EACH_ENTRY(cursor, &This->event_clients, event_client, entry)
123     {
124         TRACE("Notifying %p\n", cursor);
125         IExplorerBrowserEvents_OnNavigationFailed(cursor->pebe, pidl);
126     }
127 }
128
129 static void events_ViewCreated(ExplorerBrowserImpl *This, IShellView *psv)
130 {
131     event_client *cursor;
132
133     TRACE("%p\n", This);
134
135     LIST_FOR_EACH_ENTRY(cursor, &This->event_clients, event_client, entry)
136     {
137         TRACE("Notifying %p\n", cursor);
138         IExplorerBrowserEvents_OnViewCreated(cursor->pebe, psv);
139     }
140 }
141
142 /**************************************************************************
143  * Helper functions
144  */
145 static void update_layout(ExplorerBrowserImpl *This)
146 {
147     RECT rc;
148     TRACE("%p\n", This);
149
150     GetClientRect(This->hwnd_main, &rc);
151     CopyRect(&This->sv_rc, &rc);
152 }
153
154 static void size_panes(ExplorerBrowserImpl *This)
155 {
156     MoveWindow(This->hwnd_sv,
157                This->sv_rc.left, This->sv_rc.top,
158                This->sv_rc.right - This->sv_rc.left, This->sv_rc.bottom - This->sv_rc.top,
159                TRUE);
160 }
161
162 static HRESULT change_viewmode(ExplorerBrowserImpl *This, UINT viewmode)
163 {
164     IFolderView *pfv;
165     HRESULT hr;
166
167     if(!This->psv)
168         return E_FAIL;
169
170     hr = IShellView_QueryInterface(This->psv, &IID_IFolderView, (void*)&pfv);
171     if(SUCCEEDED(hr))
172     {
173         hr = IFolderView_SetCurrentViewMode(pfv, This->fs.ViewMode);
174         IFolderView_Release(pfv);
175     }
176
177     return hr;
178 }
179
180 static HRESULT create_new_shellview(ExplorerBrowserImpl *This, IShellItem *psi)
181 {
182     IShellBrowser *psb = (IShellBrowser*)&This->lpsbVtbl;
183     IShellFolder *psf;
184     IShellView *psv;
185     HWND hwnd_new;
186     HRESULT hr;
187
188     TRACE("%p, %p\n", This, psi);
189
190     hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&psf);
191     if(SUCCEEDED(hr))
192     {
193         hr = IShellFolder_CreateViewObject(psf, This->hwnd_main, &IID_IShellView, (void**)&psv);
194         if(SUCCEEDED(hr))
195         {
196             if(This->hwnd_sv)
197             {
198                 IShellView_DestroyViewWindow(This->psv);
199                 This->hwnd_sv = NULL;
200             }
201
202             hr = IShellView_CreateViewWindow(psv, This->psv, &This->fs, psb, &This->sv_rc, &hwnd_new);
203             if(SUCCEEDED(hr))
204             {
205                 /* Replace the old shellview */
206                 if(This->psv) IShellView_Release(This->psv);
207
208                 This->psv = psv;
209                 This->hwnd_sv = hwnd_new;
210                 events_ViewCreated(This, psv);
211             }
212             else
213             {
214                 ERR("CreateViewWindow failed (0x%x)\n", hr);
215                 IShellView_Release(psv);
216             }
217         }
218         else
219             ERR("CreateViewObject failed (0x%x)\n", hr);
220
221         IShellFolder_Release(psf);
222     }
223     else
224         ERR("SI::BindToHandler failed (0x%x)\n", hr);
225
226     return hr;
227 }
228
229 /**************************************************************************
230  * Main window related functions.
231  */
232 static LRESULT main_on_wm_create(HWND hWnd, CREATESTRUCTW *crs)
233 {
234     ExplorerBrowserImpl *This = crs->lpCreateParams;
235     TRACE("%p\n", This);
236
237     SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LPARAM)This);
238     This->hwnd_main = hWnd;
239
240     return TRUE;
241 }
242
243 static LRESULT main_on_wm_size(ExplorerBrowserImpl *This)
244 {
245     update_layout(This);
246     size_panes(This);
247
248     return TRUE;
249 }
250
251 static LRESULT CALLBACK main_wndproc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
252 {
253     ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
254
255     switch(uMessage)
256     {
257     case WM_CREATE:           return main_on_wm_create(hWnd, (CREATESTRUCTW*)lParam);
258     case WM_SIZE:             return main_on_wm_size(This);
259     default:                  return DefWindowProcW(hWnd, uMessage, wParam, lParam);
260     }
261
262     return 0;
263 }
264
265 /**************************************************************************
266  * IExplorerBrowser Implementation
267  */
268 static HRESULT WINAPI IExplorerBrowser_fnQueryInterface(IExplorerBrowser *iface,
269                                                         REFIID riid, void **ppvObject)
270 {
271     ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface;
272     TRACE("%p (%s, %p)\n", This, shdebugstr_guid(riid), ppvObject);
273
274     *ppvObject = NULL;
275     if(IsEqualIID(riid, &IID_IExplorerBrowser) ||
276        IsEqualIID(riid, &IID_IUnknown))
277     {
278         *ppvObject = This;
279     }
280     else if(IsEqualIID(riid, &IID_IShellBrowser))
281     {
282         *ppvObject = &This->lpsbVtbl;
283     }
284
285     if(*ppvObject)
286     {
287         IUnknown_AddRef((IUnknown*)*ppvObject);
288         return S_OK;
289     }
290
291     return E_NOINTERFACE;
292 }
293
294 static ULONG WINAPI IExplorerBrowser_fnAddRef(IExplorerBrowser *iface)
295 {
296     ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface;
297     LONG ref = InterlockedIncrement(&This->ref);
298     TRACE("%p - ref %d\n", This, ref);
299
300     return ref;
301 }
302
303 static ULONG WINAPI IExplorerBrowser_fnRelease(IExplorerBrowser *iface)
304 {
305     ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface;
306     LONG ref = InterlockedDecrement(&This->ref);
307     TRACE("%p - ref %d\n", This, ref);
308
309     if(!ref)
310     {
311         TRACE("Freeing.\n");
312
313         if(!This->destroyed)
314             IExplorerBrowser_Destroy(iface);
315
316         HeapFree(GetProcessHeap(), 0, This);
317         return 0;
318     }
319
320     return ref;
321 }
322
323 static HRESULT WINAPI IExplorerBrowser_fnInitialize(IExplorerBrowser *iface,
324                                                     HWND hwndParent, const RECT *prc,
325                                                     const FOLDERSETTINGS *pfs)
326 {
327     ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface;
328     WNDCLASSW wc;
329     LONG style;
330     static const WCHAR EB_CLASS_NAME[] =
331         {'E','x','p','l','o','r','e','r','B','r','o','w','s','e','r','C','o','n','t','r','o','l',0};
332
333     TRACE("%p (%p, %p, %p)\n", This, hwndParent, prc, pfs);
334
335     if(This->hwnd_main)
336         return E_UNEXPECTED;
337
338     if(!hwndParent)
339         return E_INVALIDARG;
340
341     if( !GetClassInfoW(shell32_hInstance, EB_CLASS_NAME, &wc) )
342     {
343         wc.style            = CS_HREDRAW | CS_VREDRAW;
344         wc.lpfnWndProc      = main_wndproc;
345         wc.cbClsExtra       = 0;
346         wc.cbWndExtra       = 0;
347         wc.hInstance        = shell32_hInstance;
348         wc.hIcon            = 0;
349         wc.hCursor          = LoadCursorW(0, (LPWSTR)IDC_ARROW);
350         wc.hbrBackground    = (HBRUSH)(COLOR_WINDOW + 1);
351         wc.lpszMenuName     = NULL;
352         wc.lpszClassName    = EB_CLASS_NAME;
353
354         if (!RegisterClassW(&wc)) return E_FAIL;
355     }
356
357     style = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_BORDER;
358     This->hwnd_main = CreateWindowExW(WS_EX_CONTROLPARENT, EB_CLASS_NAME, NULL, style,
359                                       prc->left, prc->top,
360                                       prc->right - prc->left, prc->bottom - prc->top,
361                                       hwndParent, 0, shell32_hInstance, This);
362
363     if(!This->hwnd_main)
364     {
365         ERR("Failed to create the window.\n");
366         return E_FAIL;
367     }
368
369     This->fs.ViewMode = pfs ? pfs->ViewMode : FVM_DETAILS;
370     This->fs.fFlags = pfs ? (pfs->fFlags | FWF_NOCLIENTEDGE) : FWF_NOCLIENTEDGE;
371
372     return S_OK;
373 }
374
375 static HRESULT WINAPI IExplorerBrowser_fnDestroy(IExplorerBrowser *iface)
376 {
377     ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface;
378     TRACE("%p\n", This);
379
380     if(This->psv)
381     {
382         IShellView_DestroyViewWindow(This->psv);
383         IShellView_Release(This->psv);
384         This->psv = NULL;
385         This->hwnd_sv = NULL;
386     }
387
388     events_unadvise_all(This);
389
390     ILFree(This->current_pidl);
391     This->current_pidl = NULL;
392
393     DestroyWindow(This->hwnd_main);
394     This->destroyed = TRUE;
395
396     return S_OK;
397 }
398
399 static HRESULT WINAPI IExplorerBrowser_fnSetRect(IExplorerBrowser *iface,
400                                                  HDWP *phdwp, RECT rcBrowser)
401 {
402     ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface;
403     TRACE("%p (%p, %s)\n", This, phdwp, wine_dbgstr_rect(&rcBrowser));
404
405     if(phdwp)
406     {
407         *phdwp = DeferWindowPos(*phdwp, This->hwnd_main, NULL, rcBrowser.left, rcBrowser.top,
408                                 rcBrowser.right - rcBrowser.left, rcBrowser.bottom - rcBrowser.top,
409                                 SWP_NOZORDER | SWP_NOACTIVATE);
410     }
411     else
412     {
413         MoveWindow(This->hwnd_main, rcBrowser.left, rcBrowser.top,
414                    rcBrowser.right - rcBrowser.left, rcBrowser.bottom - rcBrowser.top, TRUE);
415     }
416
417     return S_OK;
418 }
419
420 static HRESULT WINAPI IExplorerBrowser_fnSetPropertyBag(IExplorerBrowser *iface,
421                                                         LPCWSTR pszPropertyBag)
422 {
423     ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface;
424     FIXME("stub, %p (%s)\n", This, debugstr_w(pszPropertyBag));
425
426     return E_NOTIMPL;
427 }
428
429 static HRESULT WINAPI IExplorerBrowser_fnSetEmptyText(IExplorerBrowser *iface,
430                                                       LPCWSTR pszEmptyText)
431 {
432     ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface;
433     FIXME("stub, %p (%s)\n", This, debugstr_w(pszEmptyText));
434
435     return E_NOTIMPL;
436 }
437
438 static HRESULT WINAPI IExplorerBrowser_fnSetFolderSettings(IExplorerBrowser *iface,
439                                                            const FOLDERSETTINGS *pfs)
440 {
441     ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface;
442     TRACE("%p (%p)\n", This, pfs);
443
444     if(!pfs)
445         return E_INVALIDARG;
446
447     This->fs.ViewMode = pfs->ViewMode;
448     This->fs.fFlags = pfs->fFlags | FWF_NOCLIENTEDGE;
449
450     /* Change the settings of the current view, if any. */
451     return change_viewmode(This, This->fs.ViewMode);
452 }
453
454 static HRESULT WINAPI IExplorerBrowser_fnAdvise(IExplorerBrowser *iface,
455                                                 IExplorerBrowserEvents *psbe,
456                                                 DWORD *pdwCookie)
457 {
458     ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface;
459     event_client *client;
460     TRACE("%p (%p, %p)\n", This, psbe, pdwCookie);
461
462     client = HeapAlloc(GetProcessHeap(), 0, sizeof(event_client));
463     client->pebe = psbe;
464     client->cookie = ++This->events_next_cookie;
465
466     IExplorerBrowserEvents_AddRef(psbe);
467     *pdwCookie = client->cookie;
468
469     list_add_tail(&This->event_clients, &client->entry);
470
471     return S_OK;
472 }
473
474 static HRESULT WINAPI IExplorerBrowser_fnUnadvise(IExplorerBrowser *iface,
475                                                   DWORD dwCookie)
476 {
477     ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface;
478     event_client *client;
479     TRACE("%p (0x%x)\n", This, dwCookie);
480
481     LIST_FOR_EACH_ENTRY(client, &This->event_clients, event_client, entry)
482     {
483         if(client->cookie == dwCookie)
484         {
485             list_remove(&client->entry);
486             IExplorerBrowserEvents_Release(client->pebe);
487             HeapFree(GetProcessHeap(), 0, client);
488             return S_OK;
489         }
490     }
491
492     return E_INVALIDARG;
493 }
494
495 static HRESULT WINAPI IExplorerBrowser_fnSetOptions(IExplorerBrowser *iface,
496                                                     EXPLORER_BROWSER_OPTIONS dwFlag)
497 {
498     ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface;
499     static const EXPLORER_BROWSER_OPTIONS unsupported_options =
500         EBO_SHOWFRAMES | EBO_ALWAYSNAVIGATE | EBO_NOWRAPPERWINDOW | EBO_HTMLSHAREPOINTVIEW;
501
502     TRACE("%p (0x%x)\n", This, dwFlag);
503
504     if(dwFlag & unsupported_options)
505         FIXME("Flags 0x%08x contains unsupported options.\n", dwFlag);
506
507     This->eb_options = dwFlag;
508
509     return S_OK;
510 }
511
512 static HRESULT WINAPI IExplorerBrowser_fnGetOptions(IExplorerBrowser *iface,
513                                                     EXPLORER_BROWSER_OPTIONS *pdwFlag)
514 {
515     ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface;
516     TRACE("%p (%p)\n", This, pdwFlag);
517
518     *pdwFlag = This->eb_options;
519
520     return S_OK;
521 }
522
523 static const UINT unsupported_browse_flags =
524     SBSP_NAVIGATEBACK | SBSP_NAVIGATEFORWARD | SBSP_NEWBROWSER |
525     EBF_SELECTFROMDATAOBJECT | EBF_NODROPTARGET;
526 static HRESULT WINAPI IExplorerBrowser_fnBrowseToIDList(IExplorerBrowser *iface,
527                                                         PCUIDLIST_RELATIVE pidl,
528                                                         UINT uFlags)
529 {
530     ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface;
531     LPITEMIDLIST absolute_pidl = NULL;
532     HRESULT hr;
533     TRACE("%p (%p, 0x%x)\n", This, pidl, uFlags);
534
535     if(!This->hwnd_main)
536         return E_FAIL;
537
538     if(This->destroyed)
539         return HRESULT_FROM_WIN32(ERROR_BUSY);
540
541     if(This->current_pidl && (This->eb_options & EBO_NAVIGATEONCE))
542         return E_FAIL;
543
544     if(uFlags & SBSP_EXPLOREMODE)
545         return E_INVALIDARG;
546
547     if(uFlags & unsupported_browse_flags)
548         FIXME("Argument 0x%x contains unsupported flags.\n", uFlags);
549
550     if(uFlags & SBSP_PARENT)
551     {
552         if(This->current_pidl)
553         {
554             if(_ILIsPidlSimple(This->current_pidl))
555             {
556                 absolute_pidl = _ILCreateDesktop();
557             }
558             else
559             {
560                 absolute_pidl = ILClone(This->current_pidl);
561                 ILRemoveLastID(absolute_pidl);
562             }
563         }
564         if(!absolute_pidl)
565         {
566             ERR("Failed to get parent pidl.\n");
567             return E_FAIL;
568         }
569
570     }
571     else if(uFlags & SBSP_RELATIVE)
572     {
573         /* SBSP_RELATIVE has precedence over SBSP_ABSOLUTE */
574         TRACE("SBSP_RELATIVE\n");
575         if(This->current_pidl)
576         {
577             absolute_pidl = ILCombine(This->current_pidl, pidl);
578         }
579         if(!absolute_pidl)
580         {
581             ERR("Failed to get absolute pidl.\n");
582             return E_FAIL;
583         }
584     }
585     else
586     {
587         TRACE("SBSP_ABSOLUTE\n");
588         absolute_pidl = ILClone(pidl);
589         if(!absolute_pidl && !This->current_pidl)
590             return E_INVALIDARG;
591         else if(!absolute_pidl)
592             return S_OK;
593     }
594
595     /* TODO: Asynchronous browsing. Return S_OK here and finish in
596      * another thread. */
597
598     hr = events_NavigationPending(This, absolute_pidl);
599     if(FAILED(hr))
600     {
601         TRACE("Browsing aborted.\n");
602         ILFree(absolute_pidl);
603         return E_FAIL;
604     }
605
606     /* Only browse if the new pidl differs from the old */
607     if(!ILIsEqual(This->current_pidl, absolute_pidl))
608     {
609         IShellItem *psi;
610         hr = SHCreateItemFromIDList(absolute_pidl, &IID_IShellItem, (void**)&psi);
611         if(SUCCEEDED(hr))
612         {
613             hr = create_new_shellview(This, psi);
614             if(FAILED(hr))
615             {
616                 events_NavigationFailed(This, absolute_pidl);
617                 ILFree(absolute_pidl);
618                 IShellItem_Release(psi);
619                 return E_FAIL;
620             }
621             IShellItem_Release(psi);
622         }
623     }
624
625     events_NavigationComplete(This, absolute_pidl);
626     ILFree(This->current_pidl);
627     This->current_pidl = absolute_pidl;
628
629     return S_OK;
630 }
631
632 static HRESULT WINAPI IExplorerBrowser_fnBrowseToObject(IExplorerBrowser *iface,
633                                                         IUnknown *punk, UINT uFlags)
634 {
635     ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface;
636     FIXME("stub, %p (%p, 0x%x)\n", This, punk, uFlags);
637
638     return E_NOTIMPL;
639 }
640
641 static HRESULT WINAPI IExplorerBrowser_fnFillFromObject(IExplorerBrowser *iface,
642                                                         IUnknown *punk,
643                                                         EXPLORER_BROWSER_FILL_FLAGS dwFlags)
644 {
645     ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface;
646     FIXME("stub, %p (%p, 0x%x)\n", This, punk, dwFlags);
647
648     return E_NOTIMPL;
649 }
650
651 static HRESULT WINAPI IExplorerBrowser_fnRemoveAll(IExplorerBrowser *iface)
652 {
653     ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface;
654     FIXME("stub, %p\n", This);
655
656     return E_NOTIMPL;
657 }
658
659 static HRESULT WINAPI IExplorerBrowser_fnGetCurrentView(IExplorerBrowser *iface,
660                                                         REFIID riid, void **ppv)
661 {
662     ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface;
663     TRACE("%p (%s, %p)\n", This, shdebugstr_guid(riid), ppv);
664
665     if(!This->psv)
666         return E_FAIL;
667
668     return IShellView_QueryInterface(This->psv, riid, ppv);
669 }
670
671 static const IExplorerBrowserVtbl vt_IExplorerBrowser =
672 {
673     IExplorerBrowser_fnQueryInterface,
674     IExplorerBrowser_fnAddRef,
675     IExplorerBrowser_fnRelease,
676     IExplorerBrowser_fnInitialize,
677     IExplorerBrowser_fnDestroy,
678     IExplorerBrowser_fnSetRect,
679     IExplorerBrowser_fnSetPropertyBag,
680     IExplorerBrowser_fnSetEmptyText,
681     IExplorerBrowser_fnSetFolderSettings,
682     IExplorerBrowser_fnAdvise,
683     IExplorerBrowser_fnUnadvise,
684     IExplorerBrowser_fnSetOptions,
685     IExplorerBrowser_fnGetOptions,
686     IExplorerBrowser_fnBrowseToIDList,
687     IExplorerBrowser_fnBrowseToObject,
688     IExplorerBrowser_fnFillFromObject,
689     IExplorerBrowser_fnRemoveAll,
690     IExplorerBrowser_fnGetCurrentView
691 };
692
693 /**************************************************************************
694  * IShellBrowser Implementation
695  */
696
697 static inline ExplorerBrowserImpl *impl_from_IShellBrowser(IShellBrowser *iface)
698 {
699     return (ExplorerBrowserImpl *)((char*)iface - FIELD_OFFSET(ExplorerBrowserImpl, lpsbVtbl));
700 }
701
702 static HRESULT WINAPI IShellBrowser_fnQueryInterface(IShellBrowser *iface,
703                                                      REFIID riid, void **ppvObject)
704 {
705     ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface);
706     TRACE("%p\n", This);
707     return IUnknown_QueryInterface((IUnknown*) This, riid, ppvObject);
708 }
709
710 static ULONG WINAPI IShellBrowser_fnAddRef(IShellBrowser *iface)
711 {
712     ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface);
713     TRACE("%p\n", This);
714     return IUnknown_AddRef((IUnknown*) This);
715 }
716
717 static ULONG WINAPI IShellBrowser_fnRelease(IShellBrowser *iface)
718 {
719     ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface);
720     TRACE("%p\n", This);
721     return IUnknown_Release((IUnknown*) This);
722 }
723
724 static HRESULT WINAPI IShellBrowser_fnGetWindow(IShellBrowser *iface, HWND *phwnd)
725 {
726     ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface);
727     TRACE("%p (%p)\n", This, phwnd);
728
729     if(!This->hwnd_main)
730         return E_FAIL;
731
732     *phwnd = This->hwnd_main;
733     return S_OK;
734 }
735
736 static HRESULT WINAPI IShellBrowser_fnContextSensitiveHelp(IShellBrowser *iface,
737                                                            BOOL fEnterMode)
738 {
739     ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface);
740     FIXME("stub, %p (%d)\n", This, fEnterMode);
741
742     return E_NOTIMPL;
743 }
744
745 static HRESULT WINAPI IShellBrowser_fnInsertMenusSB(IShellBrowser *iface,
746                                                     HMENU hmenuShared,
747                                                     LPOLEMENUGROUPWIDTHS lpMenuWidths)
748 {
749     ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface);
750     TRACE("%p (%p, %p)\n", This, hmenuShared, lpMenuWidths);
751
752     /* Not implemented. */
753     return E_NOTIMPL;
754 }
755
756 static HRESULT WINAPI IShellBrowser_fnSetMenuSB(IShellBrowser *iface,
757                                                 HMENU hmenuShared,
758                                                 HOLEMENU holemenuReserved,
759                                                 HWND hwndActiveObject)
760 {
761     ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface);
762     TRACE("%p (%p, %p, %p)\n", This, hmenuShared, holemenuReserved, hwndActiveObject);
763
764     /* Not implemented. */
765     return E_NOTIMPL;
766 }
767
768 static HRESULT WINAPI IShellBrowser_fnRemoveMenusSB(IShellBrowser *iface,
769                                                     HMENU hmenuShared)
770 {
771     ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface);
772     TRACE("%p (%p)\n", This, hmenuShared);
773
774     /* Not implemented. */
775     return E_NOTIMPL;
776 }
777
778 static HRESULT WINAPI IShellBrowser_fnSetStatusTextSB(IShellBrowser *iface,
779                                                       LPCOLESTR pszStatusText)
780 {
781     ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface);
782     FIXME("stub, %p (%s)\n", This, debugstr_w(pszStatusText));
783
784     return E_NOTIMPL;
785 }
786
787 static HRESULT WINAPI IShellBrowser_fnEnableModelessSB(IShellBrowser *iface,
788                                                        BOOL fEnable)
789 {
790     ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface);
791     FIXME("stub, %p (%d)\n", This, fEnable);
792
793     return E_NOTIMPL;
794 }
795
796 static HRESULT WINAPI IShellBrowser_fnTranslateAcceleratorSB(IShellBrowser *iface,
797                                                              MSG *pmsg, WORD wID)
798 {
799     ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface);
800     FIXME("stub, %p (%p, 0x%x)\n", This, pmsg, wID);
801
802     return E_NOTIMPL;
803 }
804
805 static HRESULT WINAPI IShellBrowser_fnBrowseObject(IShellBrowser *iface,
806                                                    LPCITEMIDLIST pidl, UINT wFlags)
807 {
808     ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface);
809     TRACE("%p (%p, %x)\n", This, pidl, wFlags);
810
811     return IExplorerBrowser_fnBrowseToIDList((IExplorerBrowser*)This, pidl, wFlags);
812 }
813
814 static HRESULT WINAPI IShellBrowser_fnGetViewStateStream(IShellBrowser *iface,
815                                                          DWORD grfMode,
816                                                          IStream **ppStrm)
817 {
818     ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface);
819     FIXME("stub, %p (0x%x, %p)\n", This, grfMode, ppStrm);
820
821     *ppStrm = NULL;
822     return E_FAIL;
823 }
824
825 static HRESULT WINAPI IShellBrowser_fnGetControlWindow(IShellBrowser *iface,
826                                                        UINT id, HWND *phwnd)
827 {
828     ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface);
829     TRACE("%p (%d, %p)\n", This, id, phwnd);
830
831     /* Not implemented. */
832     return E_NOTIMPL;
833 }
834
835 static HRESULT WINAPI IShellBrowser_fnSendControlMsg(IShellBrowser *iface,
836                                                      UINT id, UINT uMsg,
837                                                      WPARAM wParam, LPARAM lParam,
838                                                      LRESULT *pret)
839 {
840     ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface);
841     FIXME("stub, %p (%d, %d, %lx, %lx, %p)\n", This, id, uMsg, wParam, lParam, pret);
842
843     return E_NOTIMPL;
844 }
845
846 static HRESULT WINAPI IShellBrowser_fnQueryActiveShellView(IShellBrowser *iface,
847                                                            IShellView **ppshv)
848 {
849     ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface);
850     TRACE("%p (%p)\n", This, ppshv);
851
852     if(!This->psv)
853         return E_FAIL;
854
855     *ppshv = This->psv;
856     IShellView_AddRef(This->psv);
857
858     return S_OK;
859 }
860
861 static HRESULT WINAPI IShellBrowser_fnOnViewWindowActive(IShellBrowser *iface,
862                                                          IShellView *pshv)
863 {
864     ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface);
865     FIXME("stub, %p (%p)\n", This, pshv);
866
867     return E_NOTIMPL;
868 }
869
870 static HRESULT WINAPI IShellBrowser_fnSetToolbarItems(IShellBrowser *iface,
871                                                       LPTBBUTTONSB lpButtons,
872                                                       UINT nButtons, UINT uFlags)
873 {
874     ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface);
875     FIXME("stub, %p (%p, %d, 0x%x)\n", This, lpButtons, nButtons, uFlags);
876
877     return E_NOTIMPL;
878 }
879
880 static const IShellBrowserVtbl vt_IShellBrowser = {
881     IShellBrowser_fnQueryInterface,
882     IShellBrowser_fnAddRef,
883     IShellBrowser_fnRelease,
884     IShellBrowser_fnGetWindow,
885     IShellBrowser_fnContextSensitiveHelp,
886     IShellBrowser_fnInsertMenusSB,
887     IShellBrowser_fnSetMenuSB,
888     IShellBrowser_fnRemoveMenusSB,
889     IShellBrowser_fnSetStatusTextSB,
890     IShellBrowser_fnEnableModelessSB,
891     IShellBrowser_fnTranslateAcceleratorSB,
892     IShellBrowser_fnBrowseObject,
893     IShellBrowser_fnGetViewStateStream,
894     IShellBrowser_fnGetControlWindow,
895     IShellBrowser_fnSendControlMsg,
896     IShellBrowser_fnQueryActiveShellView,
897     IShellBrowser_fnOnViewWindowActive,
898     IShellBrowser_fnSetToolbarItems
899 };
900
901 HRESULT WINAPI ExplorerBrowser_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
902 {
903     ExplorerBrowserImpl *eb;
904     HRESULT ret;
905
906     TRACE("%p %s %p\n", pUnkOuter, shdebugstr_guid (riid), ppv);
907
908     if(!ppv)
909         return E_POINTER;
910     if(pUnkOuter)
911         return CLASS_E_NOAGGREGATION;
912
913     eb = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ExplorerBrowserImpl));
914     eb->ref = 1;
915     eb->lpVtbl = &vt_IExplorerBrowser;
916     eb->lpsbVtbl = &vt_IShellBrowser;
917
918     list_init(&eb->event_clients);
919
920     ret = IExplorerBrowser_QueryInterface((IExplorerBrowser*)eb, riid, ppv);
921     IExplorerBrowser_Release((IExplorerBrowser*)eb);
922
923     TRACE("--(%p)\n", ppv);
924     return ret;
925 }