/* * ExplorerBrowser Control implementation. * * Copyright 2010 David Hedberg * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #define COBJMACROS #define NONAMELESSUNION #define NONAMELESSSTRUCT #include "winerror.h" #include "windef.h" #include "winbase.h" #include "wine/list.h" #include "wine/debug.h" #include "debughlp.h" #include "shell32_main.h" #include "pidl.h" WINE_DEFAULT_DEBUG_CHANNEL(shell); typedef struct _event_client { struct list entry; IExplorerBrowserEvents *pebe; DWORD cookie; } event_client; typedef struct _travellog_entry { struct list entry; LPITEMIDLIST pidl; } travellog_entry; typedef struct _ExplorerBrowserImpl { const IExplorerBrowserVtbl *lpVtbl; const IShellBrowserVtbl *lpsbVtbl; const ICommDlgBrowser3Vtbl *lpcdb3Vtbl; const IObjectWithSiteVtbl *lpowsVtbl; LONG ref; BOOL destroyed; HWND hwnd_main; HWND hwnd_sv; EXPLORER_BROWSER_OPTIONS eb_options; FOLDERSETTINGS fs; struct list event_clients; DWORD events_next_cookie; struct list travellog; travellog_entry *travellog_cursor; int travellog_count; IShellView *psv; RECT sv_rc; LPITEMIDLIST current_pidl; IUnknown *punk_site; } ExplorerBrowserImpl; /************************************************************************** * Event functions. */ static void events_unadvise_all(ExplorerBrowserImpl *This) { event_client *client, *curs; TRACE("%p\n", This); LIST_FOR_EACH_ENTRY_SAFE(client, curs, &This->event_clients, event_client, entry) { TRACE("Removing %p\n", client); list_remove(&client->entry); IExplorerBrowserEvents_Release(client->pebe); HeapFree(GetProcessHeap(), 0, client); } } static HRESULT events_NavigationPending(ExplorerBrowserImpl *This, PCIDLIST_ABSOLUTE pidl) { event_client *cursor; HRESULT hres = S_OK; TRACE("%p\n", This); LIST_FOR_EACH_ENTRY(cursor, &This->event_clients, event_client, entry) { TRACE("Notifying %p\n", cursor); hres = IExplorerBrowserEvents_OnNavigationPending(cursor->pebe, pidl); /* If this failed for any reason, the browsing is supposed to be aborted. */ if(FAILED(hres)) break; } return hres; } static void events_NavigationComplete(ExplorerBrowserImpl *This, PCIDLIST_ABSOLUTE pidl) { event_client *cursor; TRACE("%p\n", This); LIST_FOR_EACH_ENTRY(cursor, &This->event_clients, event_client, entry) { TRACE("Notifying %p\n", cursor); IExplorerBrowserEvents_OnNavigationComplete(cursor->pebe, pidl); } } static void events_NavigationFailed(ExplorerBrowserImpl *This, PCIDLIST_ABSOLUTE pidl) { event_client *cursor; TRACE("%p\n", This); LIST_FOR_EACH_ENTRY(cursor, &This->event_clients, event_client, entry) { TRACE("Notifying %p\n", cursor); IExplorerBrowserEvents_OnNavigationFailed(cursor->pebe, pidl); } } static void events_ViewCreated(ExplorerBrowserImpl *This, IShellView *psv) { event_client *cursor; TRACE("%p\n", This); LIST_FOR_EACH_ENTRY(cursor, &This->event_clients, event_client, entry) { TRACE("Notifying %p\n", cursor); IExplorerBrowserEvents_OnViewCreated(cursor->pebe, psv); } } /************************************************************************** * Travellog functions. */ static void travellog_remove_entry(ExplorerBrowserImpl *This, travellog_entry *entry) { TRACE("Removing %p\n", entry); list_remove(&entry->entry); HeapFree(GetProcessHeap(), 0, entry); This->travellog_count--; } static void travellog_remove_all_entries(ExplorerBrowserImpl *This) { travellog_entry *cursor, *cursor2; TRACE("%p\n", This); LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &This->travellog, travellog_entry, entry) travellog_remove_entry(This, cursor); This->travellog_cursor = NULL; } static void travellog_add_entry(ExplorerBrowserImpl *This, LPITEMIDLIST pidl) { travellog_entry *new, *cursor, *cursor2; TRACE("%p (old count %d)\n", pidl, This->travellog_count); /* Replace the old tail, if any, with the new entry */ if(This->travellog_cursor) { LIST_FOR_EACH_ENTRY_SAFE_REV(cursor, cursor2, &This->travellog, travellog_entry, entry) { if(cursor == This->travellog_cursor) break; travellog_remove_entry(This, cursor); } } /* Create and add the new entry */ new = HeapAlloc(GetProcessHeap(), 0, sizeof(travellog_entry)); new->pidl = ILClone(pidl); list_add_tail(&This->travellog, &new->entry); This->travellog_cursor = new; This->travellog_count++; /* Remove the first few entries if the size limit is reached. */ if(This->travellog_count > 200) { UINT i = 0; LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &This->travellog, travellog_entry, entry) { if(i++ > 10) break; travellog_remove_entry(This, cursor); } } } static LPCITEMIDLIST travellog_go_back(ExplorerBrowserImpl *This) { travellog_entry *prev; TRACE("%p, %p\n", This, This->travellog_cursor); if(!This->travellog_cursor) return NULL; prev = LIST_ENTRY(list_prev(&This->travellog, &This->travellog_cursor->entry), travellog_entry, entry); if(!prev) return NULL; This->travellog_cursor = prev; return prev->pidl; } static LPCITEMIDLIST travellog_go_forward(ExplorerBrowserImpl *This) { travellog_entry *next; TRACE("%p, %p\n", This, This->travellog_cursor); if(!This->travellog_cursor) return NULL; next = LIST_ENTRY(list_next(&This->travellog, &This->travellog_cursor->entry), travellog_entry, entry); if(!next) return NULL; This->travellog_cursor = next; return next->pidl; } /************************************************************************** * Helper functions */ static void update_layout(ExplorerBrowserImpl *This) { RECT rc; TRACE("%p\n", This); GetClientRect(This->hwnd_main, &rc); CopyRect(&This->sv_rc, &rc); } static void size_panes(ExplorerBrowserImpl *This) { MoveWindow(This->hwnd_sv, This->sv_rc.left, This->sv_rc.top, This->sv_rc.right - This->sv_rc.left, This->sv_rc.bottom - This->sv_rc.top, TRUE); } static HRESULT change_viewmode(ExplorerBrowserImpl *This, UINT viewmode) { IFolderView *pfv; HRESULT hr; if(!This->psv) return E_FAIL; hr = IShellView_QueryInterface(This->psv, &IID_IFolderView, (void*)&pfv); if(SUCCEEDED(hr)) { hr = IFolderView_SetCurrentViewMode(pfv, This->fs.ViewMode); IFolderView_Release(pfv); } return hr; } static HRESULT create_new_shellview(ExplorerBrowserImpl *This, IShellItem *psi) { IShellBrowser *psb = (IShellBrowser*)&This->lpsbVtbl; IShellFolder *psf; IShellView *psv; HWND hwnd_new; HRESULT hr; TRACE("%p, %p\n", This, psi); hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&psf); if(SUCCEEDED(hr)) { hr = IShellFolder_CreateViewObject(psf, This->hwnd_main, &IID_IShellView, (void**)&psv); if(SUCCEEDED(hr)) { if(This->hwnd_sv) { IShellView_DestroyViewWindow(This->psv); This->hwnd_sv = NULL; } hr = IShellView_CreateViewWindow(psv, This->psv, &This->fs, psb, &This->sv_rc, &hwnd_new); if(SUCCEEDED(hr)) { /* Replace the old shellview */ if(This->psv) IShellView_Release(This->psv); This->psv = psv; This->hwnd_sv = hwnd_new; events_ViewCreated(This, psv); } else { ERR("CreateViewWindow failed (0x%x)\n", hr); IShellView_Release(psv); } } else ERR("CreateViewObject failed (0x%x)\n", hr); IShellFolder_Release(psf); } else ERR("SI::BindToHandler failed (0x%x)\n", hr); return hr; } static void get_interfaces_from_site(ExplorerBrowserImpl *This) { IServiceProvider *psp; HRESULT hr; /* Calling this with This->punk_site set to NULL should properly * release any previously fetched interfaces. */ if(This->punk_site) { hr = IUnknown_QueryInterface(This->punk_site, &IID_IServiceProvider, (void**)&psp); if(SUCCEEDED(hr)) { FIXME("Not requesting any interfaces.\n"); IServiceProvider_Release(psp); } else ERR("Failed to get IServiceProvider from site.\n"); } } /************************************************************************** * Main window related functions. */ static LRESULT main_on_wm_create(HWND hWnd, CREATESTRUCTW *crs) { ExplorerBrowserImpl *This = crs->lpCreateParams; TRACE("%p\n", This); SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LPARAM)This); This->hwnd_main = hWnd; return TRUE; } static LRESULT main_on_wm_size(ExplorerBrowserImpl *This) { update_layout(This); size_panes(This); return TRUE; } static LRESULT CALLBACK main_wndproc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam) { ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)GetWindowLongPtrW(hWnd, GWLP_USERDATA); switch(uMessage) { case WM_CREATE: return main_on_wm_create(hWnd, (CREATESTRUCTW*)lParam); case WM_SIZE: return main_on_wm_size(This); default: return DefWindowProcW(hWnd, uMessage, wParam, lParam); } return 0; } /************************************************************************** * IExplorerBrowser Implementation */ static HRESULT WINAPI IExplorerBrowser_fnQueryInterface(IExplorerBrowser *iface, REFIID riid, void **ppvObject) { ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface; TRACE("%p (%s, %p)\n", This, shdebugstr_guid(riid), ppvObject); *ppvObject = NULL; if(IsEqualIID(riid, &IID_IExplorerBrowser) || IsEqualIID(riid, &IID_IUnknown)) { *ppvObject = This; } else if(IsEqualIID(riid, &IID_IShellBrowser)) { *ppvObject = &This->lpsbVtbl; } else if(IsEqualIID(riid, &IID_ICommDlgBrowser) || IsEqualIID(riid, &IID_ICommDlgBrowser2) || IsEqualIID(riid, &IID_ICommDlgBrowser3)) { *ppvObject = &This->lpcdb3Vtbl; } else if(IsEqualIID(riid, &IID_IObjectWithSite)) { *ppvObject = &This->lpowsVtbl; } if(*ppvObject) { IUnknown_AddRef((IUnknown*)*ppvObject); return S_OK; } return E_NOINTERFACE; } static ULONG WINAPI IExplorerBrowser_fnAddRef(IExplorerBrowser *iface) { ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface; LONG ref = InterlockedIncrement(&This->ref); TRACE("%p - ref %d\n", This, ref); return ref; } static ULONG WINAPI IExplorerBrowser_fnRelease(IExplorerBrowser *iface) { ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface; LONG ref = InterlockedDecrement(&This->ref); TRACE("%p - ref %d\n", This, ref); if(!ref) { TRACE("Freeing.\n"); if(!This->destroyed) IExplorerBrowser_Destroy(iface); IObjectWithSite_SetSite((IObjectWithSite*)&This->lpowsVtbl, NULL); HeapFree(GetProcessHeap(), 0, This); return 0; } return ref; } static HRESULT WINAPI IExplorerBrowser_fnInitialize(IExplorerBrowser *iface, HWND hwndParent, const RECT *prc, const FOLDERSETTINGS *pfs) { ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface; WNDCLASSW wc; LONG style; static const WCHAR EB_CLASS_NAME[] = {'E','x','p','l','o','r','e','r','B','r','o','w','s','e','r','C','o','n','t','r','o','l',0}; TRACE("%p (%p, %p, %p)\n", This, hwndParent, prc, pfs); if(This->hwnd_main) return E_UNEXPECTED; if(!hwndParent) return E_INVALIDARG; if( !GetClassInfoW(shell32_hInstance, EB_CLASS_NAME, &wc) ) { wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = main_wndproc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = shell32_hInstance; wc.hIcon = 0; wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszMenuName = NULL; wc.lpszClassName = EB_CLASS_NAME; if (!RegisterClassW(&wc)) return E_FAIL; } style = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_BORDER; This->hwnd_main = CreateWindowExW(WS_EX_CONTROLPARENT, EB_CLASS_NAME, NULL, style, prc->left, prc->top, prc->right - prc->left, prc->bottom - prc->top, hwndParent, 0, shell32_hInstance, This); if(!This->hwnd_main) { ERR("Failed to create the window.\n"); return E_FAIL; } This->fs.ViewMode = pfs ? pfs->ViewMode : FVM_DETAILS; This->fs.fFlags = pfs ? (pfs->fFlags | FWF_NOCLIENTEDGE) : FWF_NOCLIENTEDGE; return S_OK; } static HRESULT WINAPI IExplorerBrowser_fnDestroy(IExplorerBrowser *iface) { ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface; TRACE("%p\n", This); if(This->psv) { IShellView_DestroyViewWindow(This->psv); IShellView_Release(This->psv); This->psv = NULL; This->hwnd_sv = NULL; } events_unadvise_all(This); travellog_remove_all_entries(This); ILFree(This->current_pidl); This->current_pidl = NULL; DestroyWindow(This->hwnd_main); This->destroyed = TRUE; return S_OK; } static HRESULT WINAPI IExplorerBrowser_fnSetRect(IExplorerBrowser *iface, HDWP *phdwp, RECT rcBrowser) { ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface; TRACE("%p (%p, %s)\n", This, phdwp, wine_dbgstr_rect(&rcBrowser)); if(phdwp) { *phdwp = DeferWindowPos(*phdwp, This->hwnd_main, NULL, rcBrowser.left, rcBrowser.top, rcBrowser.right - rcBrowser.left, rcBrowser.bottom - rcBrowser.top, SWP_NOZORDER | SWP_NOACTIVATE); } else { MoveWindow(This->hwnd_main, rcBrowser.left, rcBrowser.top, rcBrowser.right - rcBrowser.left, rcBrowser.bottom - rcBrowser.top, TRUE); } return S_OK; } static HRESULT WINAPI IExplorerBrowser_fnSetPropertyBag(IExplorerBrowser *iface, LPCWSTR pszPropertyBag) { ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface; FIXME("stub, %p (%s)\n", This, debugstr_w(pszPropertyBag)); return E_NOTIMPL; } static HRESULT WINAPI IExplorerBrowser_fnSetEmptyText(IExplorerBrowser *iface, LPCWSTR pszEmptyText) { ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface; FIXME("stub, %p (%s)\n", This, debugstr_w(pszEmptyText)); return E_NOTIMPL; } static HRESULT WINAPI IExplorerBrowser_fnSetFolderSettings(IExplorerBrowser *iface, const FOLDERSETTINGS *pfs) { ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface; TRACE("%p (%p)\n", This, pfs); if(!pfs) return E_INVALIDARG; This->fs.ViewMode = pfs->ViewMode; This->fs.fFlags = pfs->fFlags | FWF_NOCLIENTEDGE; /* Change the settings of the current view, if any. */ return change_viewmode(This, This->fs.ViewMode); } static HRESULT WINAPI IExplorerBrowser_fnAdvise(IExplorerBrowser *iface, IExplorerBrowserEvents *psbe, DWORD *pdwCookie) { ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface; event_client *client; TRACE("%p (%p, %p)\n", This, psbe, pdwCookie); client = HeapAlloc(GetProcessHeap(), 0, sizeof(event_client)); client->pebe = psbe; client->cookie = ++This->events_next_cookie; IExplorerBrowserEvents_AddRef(psbe); *pdwCookie = client->cookie; list_add_tail(&This->event_clients, &client->entry); return S_OK; } static HRESULT WINAPI IExplorerBrowser_fnUnadvise(IExplorerBrowser *iface, DWORD dwCookie) { ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface; event_client *client; TRACE("%p (0x%x)\n", This, dwCookie); LIST_FOR_EACH_ENTRY(client, &This->event_clients, event_client, entry) { if(client->cookie == dwCookie) { list_remove(&client->entry); IExplorerBrowserEvents_Release(client->pebe); HeapFree(GetProcessHeap(), 0, client); return S_OK; } } return E_INVALIDARG; } static HRESULT WINAPI IExplorerBrowser_fnSetOptions(IExplorerBrowser *iface, EXPLORER_BROWSER_OPTIONS dwFlag) { ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface; static const EXPLORER_BROWSER_OPTIONS unsupported_options = EBO_SHOWFRAMES | EBO_ALWAYSNAVIGATE | EBO_NOWRAPPERWINDOW | EBO_HTMLSHAREPOINTVIEW; TRACE("%p (0x%x)\n", This, dwFlag); if(dwFlag & unsupported_options) FIXME("Flags 0x%08x contains unsupported options.\n", dwFlag); This->eb_options = dwFlag; return S_OK; } static HRESULT WINAPI IExplorerBrowser_fnGetOptions(IExplorerBrowser *iface, EXPLORER_BROWSER_OPTIONS *pdwFlag) { ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface; TRACE("%p (%p)\n", This, pdwFlag); *pdwFlag = This->eb_options; return S_OK; } static HRESULT WINAPI IExplorerBrowser_fnBrowseToIDList(IExplorerBrowser *iface, PCUIDLIST_RELATIVE pidl, UINT uFlags) { ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface; LPITEMIDLIST absolute_pidl = NULL; HRESULT hr; static const UINT unsupported_browse_flags = SBSP_NEWBROWSER | EBF_SELECTFROMDATAOBJECT | EBF_NODROPTARGET; TRACE("%p (%p, 0x%x)\n", This, pidl, uFlags); if(!This->hwnd_main) return E_FAIL; if(This->destroyed) return HRESULT_FROM_WIN32(ERROR_BUSY); if(This->current_pidl && (This->eb_options & EBO_NAVIGATEONCE)) return E_FAIL; if(uFlags & SBSP_EXPLOREMODE) return E_INVALIDARG; if(uFlags & unsupported_browse_flags) FIXME("Argument 0x%x contains unsupported flags.\n", uFlags); if(uFlags & SBSP_NAVIGATEBACK) { TRACE("SBSP_NAVIGATEBACK\n"); absolute_pidl = ILClone(travellog_go_back(This)); if(!absolute_pidl && !This->current_pidl) return E_FAIL; else if(!absolute_pidl) return S_OK; } else if(uFlags & SBSP_NAVIGATEFORWARD) { TRACE("SBSP_NAVIGATEFORWARD\n"); absolute_pidl = ILClone(travellog_go_forward(This)); if(!absolute_pidl && !This->current_pidl) return E_FAIL; else if(!absolute_pidl) return S_OK; } else if(uFlags & SBSP_PARENT) { if(This->current_pidl) { if(_ILIsPidlSimple(This->current_pidl)) { absolute_pidl = _ILCreateDesktop(); } else { absolute_pidl = ILClone(This->current_pidl); ILRemoveLastID(absolute_pidl); } } if(!absolute_pidl) { ERR("Failed to get parent pidl.\n"); return E_FAIL; } } else if(uFlags & SBSP_RELATIVE) { /* SBSP_RELATIVE has precedence over SBSP_ABSOLUTE */ TRACE("SBSP_RELATIVE\n"); if(This->current_pidl) { absolute_pidl = ILCombine(This->current_pidl, pidl); } if(!absolute_pidl) { ERR("Failed to get absolute pidl.\n"); return E_FAIL; } } else { TRACE("SBSP_ABSOLUTE\n"); absolute_pidl = ILClone(pidl); if(!absolute_pidl && !This->current_pidl) return E_INVALIDARG; else if(!absolute_pidl) return S_OK; } /* TODO: Asynchronous browsing. Return S_OK here and finish in * another thread. */ hr = events_NavigationPending(This, absolute_pidl); if(FAILED(hr)) { TRACE("Browsing aborted.\n"); ILFree(absolute_pidl); return E_FAIL; } get_interfaces_from_site(This); /* Only browse if the new pidl differs from the old */ if(!ILIsEqual(This->current_pidl, absolute_pidl)) { IShellItem *psi; hr = SHCreateItemFromIDList(absolute_pidl, &IID_IShellItem, (void**)&psi); if(SUCCEEDED(hr)) { hr = create_new_shellview(This, psi); if(FAILED(hr)) { events_NavigationFailed(This, absolute_pidl); ILFree(absolute_pidl); IShellItem_Release(psi); return E_FAIL; } /* Add to travellog */ if( !(This->eb_options & EBO_NOTRAVELLOG) && !(uFlags & (SBSP_NAVIGATEFORWARD|SBSP_NAVIGATEBACK)) ) { travellog_add_entry(This, absolute_pidl); } IShellItem_Release(psi); } } events_NavigationComplete(This, absolute_pidl); ILFree(This->current_pidl); This->current_pidl = absolute_pidl; return S_OK; } static HRESULT WINAPI IExplorerBrowser_fnBrowseToObject(IExplorerBrowser *iface, IUnknown *punk, UINT uFlags) { ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface; LPITEMIDLIST pidl; HRESULT hr; TRACE("%p (%p, 0x%x)\n", This, punk, uFlags); if(!punk) return IExplorerBrowser_fnBrowseToIDList(iface, NULL, uFlags); hr = SHGetIDListFromObject(punk, &pidl); if(SUCCEEDED(hr)) { hr = IExplorerBrowser_BrowseToIDList(iface, pidl, uFlags); ILFree(pidl); } return hr; } static HRESULT WINAPI IExplorerBrowser_fnFillFromObject(IExplorerBrowser *iface, IUnknown *punk, EXPLORER_BROWSER_FILL_FLAGS dwFlags) { ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface; FIXME("stub, %p (%p, 0x%x)\n", This, punk, dwFlags); return E_NOTIMPL; } static HRESULT WINAPI IExplorerBrowser_fnRemoveAll(IExplorerBrowser *iface) { ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface; FIXME("stub, %p\n", This); return E_NOTIMPL; } static HRESULT WINAPI IExplorerBrowser_fnGetCurrentView(IExplorerBrowser *iface, REFIID riid, void **ppv) { ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface; TRACE("%p (%s, %p)\n", This, shdebugstr_guid(riid), ppv); if(!This->psv) return E_FAIL; return IShellView_QueryInterface(This->psv, riid, ppv); } static const IExplorerBrowserVtbl vt_IExplorerBrowser = { IExplorerBrowser_fnQueryInterface, IExplorerBrowser_fnAddRef, IExplorerBrowser_fnRelease, IExplorerBrowser_fnInitialize, IExplorerBrowser_fnDestroy, IExplorerBrowser_fnSetRect, IExplorerBrowser_fnSetPropertyBag, IExplorerBrowser_fnSetEmptyText, IExplorerBrowser_fnSetFolderSettings, IExplorerBrowser_fnAdvise, IExplorerBrowser_fnUnadvise, IExplorerBrowser_fnSetOptions, IExplorerBrowser_fnGetOptions, IExplorerBrowser_fnBrowseToIDList, IExplorerBrowser_fnBrowseToObject, IExplorerBrowser_fnFillFromObject, IExplorerBrowser_fnRemoveAll, IExplorerBrowser_fnGetCurrentView }; /************************************************************************** * IShellBrowser Implementation */ static inline ExplorerBrowserImpl *impl_from_IShellBrowser(IShellBrowser *iface) { return (ExplorerBrowserImpl *)((char*)iface - FIELD_OFFSET(ExplorerBrowserImpl, lpsbVtbl)); } static HRESULT WINAPI IShellBrowser_fnQueryInterface(IShellBrowser *iface, REFIID riid, void **ppvObject) { ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface); TRACE("%p\n", This); return IUnknown_QueryInterface((IUnknown*) This, riid, ppvObject); } static ULONG WINAPI IShellBrowser_fnAddRef(IShellBrowser *iface) { ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface); TRACE("%p\n", This); return IUnknown_AddRef((IUnknown*) This); } static ULONG WINAPI IShellBrowser_fnRelease(IShellBrowser *iface) { ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface); TRACE("%p\n", This); return IUnknown_Release((IUnknown*) This); } static HRESULT WINAPI IShellBrowser_fnGetWindow(IShellBrowser *iface, HWND *phwnd) { ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface); TRACE("%p (%p)\n", This, phwnd); if(!This->hwnd_main) return E_FAIL; *phwnd = This->hwnd_main; return S_OK; } static HRESULT WINAPI IShellBrowser_fnContextSensitiveHelp(IShellBrowser *iface, BOOL fEnterMode) { ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface); FIXME("stub, %p (%d)\n", This, fEnterMode); return E_NOTIMPL; } static HRESULT WINAPI IShellBrowser_fnInsertMenusSB(IShellBrowser *iface, HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths) { ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface); TRACE("%p (%p, %p)\n", This, hmenuShared, lpMenuWidths); /* Not implemented. */ return E_NOTIMPL; } static HRESULT WINAPI IShellBrowser_fnSetMenuSB(IShellBrowser *iface, HMENU hmenuShared, HOLEMENU holemenuReserved, HWND hwndActiveObject) { ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface); TRACE("%p (%p, %p, %p)\n", This, hmenuShared, holemenuReserved, hwndActiveObject); /* Not implemented. */ return E_NOTIMPL; } static HRESULT WINAPI IShellBrowser_fnRemoveMenusSB(IShellBrowser *iface, HMENU hmenuShared) { ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface); TRACE("%p (%p)\n", This, hmenuShared); /* Not implemented. */ return E_NOTIMPL; } static HRESULT WINAPI IShellBrowser_fnSetStatusTextSB(IShellBrowser *iface, LPCOLESTR pszStatusText) { ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface); FIXME("stub, %p (%s)\n", This, debugstr_w(pszStatusText)); return E_NOTIMPL; } static HRESULT WINAPI IShellBrowser_fnEnableModelessSB(IShellBrowser *iface, BOOL fEnable) { ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface); FIXME("stub, %p (%d)\n", This, fEnable); return E_NOTIMPL; } static HRESULT WINAPI IShellBrowser_fnTranslateAcceleratorSB(IShellBrowser *iface, MSG *pmsg, WORD wID) { ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface); FIXME("stub, %p (%p, 0x%x)\n", This, pmsg, wID); return E_NOTIMPL; } static HRESULT WINAPI IShellBrowser_fnBrowseObject(IShellBrowser *iface, LPCITEMIDLIST pidl, UINT wFlags) { ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface); TRACE("%p (%p, %x)\n", This, pidl, wFlags); return IExplorerBrowser_fnBrowseToIDList((IExplorerBrowser*)This, pidl, wFlags); } static HRESULT WINAPI IShellBrowser_fnGetViewStateStream(IShellBrowser *iface, DWORD grfMode, IStream **ppStrm) { ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface); FIXME("stub, %p (0x%x, %p)\n", This, grfMode, ppStrm); *ppStrm = NULL; return E_FAIL; } static HRESULT WINAPI IShellBrowser_fnGetControlWindow(IShellBrowser *iface, UINT id, HWND *phwnd) { ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface); TRACE("%p (%d, %p)\n", This, id, phwnd); /* Not implemented. */ return E_NOTIMPL; } static HRESULT WINAPI IShellBrowser_fnSendControlMsg(IShellBrowser *iface, UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret) { ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface); FIXME("stub, %p (%d, %d, %lx, %lx, %p)\n", This, id, uMsg, wParam, lParam, pret); return E_NOTIMPL; } static HRESULT WINAPI IShellBrowser_fnQueryActiveShellView(IShellBrowser *iface, IShellView **ppshv) { ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface); TRACE("%p (%p)\n", This, ppshv); if(!This->psv) return E_FAIL; *ppshv = This->psv; IShellView_AddRef(This->psv); return S_OK; } static HRESULT WINAPI IShellBrowser_fnOnViewWindowActive(IShellBrowser *iface, IShellView *pshv) { ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface); FIXME("stub, %p (%p)\n", This, pshv); return E_NOTIMPL; } static HRESULT WINAPI IShellBrowser_fnSetToolbarItems(IShellBrowser *iface, LPTBBUTTONSB lpButtons, UINT nButtons, UINT uFlags) { ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface); FIXME("stub, %p (%p, %d, 0x%x)\n", This, lpButtons, nButtons, uFlags); return E_NOTIMPL; } static const IShellBrowserVtbl vt_IShellBrowser = { IShellBrowser_fnQueryInterface, IShellBrowser_fnAddRef, IShellBrowser_fnRelease, IShellBrowser_fnGetWindow, IShellBrowser_fnContextSensitiveHelp, IShellBrowser_fnInsertMenusSB, IShellBrowser_fnSetMenuSB, IShellBrowser_fnRemoveMenusSB, IShellBrowser_fnSetStatusTextSB, IShellBrowser_fnEnableModelessSB, IShellBrowser_fnTranslateAcceleratorSB, IShellBrowser_fnBrowseObject, IShellBrowser_fnGetViewStateStream, IShellBrowser_fnGetControlWindow, IShellBrowser_fnSendControlMsg, IShellBrowser_fnQueryActiveShellView, IShellBrowser_fnOnViewWindowActive, IShellBrowser_fnSetToolbarItems }; /************************************************************************** * ICommDlgBrowser3 Implementation */ static inline ExplorerBrowserImpl *impl_from_ICommDlgBrowser3(ICommDlgBrowser3 *iface) { return (ExplorerBrowserImpl *)((char*)iface - FIELD_OFFSET(ExplorerBrowserImpl, lpcdb3Vtbl)); } static HRESULT WINAPI ICommDlgBrowser3_fnQueryInterface(ICommDlgBrowser3 *iface, REFIID riid, void **ppvObject) { ExplorerBrowserImpl *This = impl_from_ICommDlgBrowser3(iface); TRACE("%p\n", This); return IUnknown_QueryInterface((IUnknown*) This, riid, ppvObject); } static ULONG WINAPI ICommDlgBrowser3_fnAddRef(ICommDlgBrowser3 *iface) { ExplorerBrowserImpl *This = impl_from_ICommDlgBrowser3(iface); TRACE("%p\n", This); return IUnknown_AddRef((IUnknown*) This); } static ULONG WINAPI ICommDlgBrowser3_fnRelease(ICommDlgBrowser3 *iface) { ExplorerBrowserImpl *This = impl_from_ICommDlgBrowser3(iface); TRACE("%p\n", This); return IUnknown_Release((IUnknown*) This); } static HRESULT WINAPI ICommDlgBrowser3_fnOnDefaultCommand(ICommDlgBrowser3 *iface, IShellView *shv) { ExplorerBrowserImpl *This = impl_from_ICommDlgBrowser3(iface); IDataObject *pdo; HRESULT hr; HRESULT ret = S_FALSE; TRACE("%p (%p)\n", This, shv); hr = IShellView_GetItemObject(shv, SVGIO_SELECTION, &IID_IDataObject, (void**)&pdo); if(SUCCEEDED(hr)) { FORMATETC fmt; STGMEDIUM medium; fmt.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW); fmt.ptd = NULL; fmt.dwAspect = DVASPECT_CONTENT; fmt.lindex = -1; fmt.tymed = TYMED_HGLOBAL; hr = IDataObject_GetData(pdo, &fmt ,&medium); IDataObject_Release(pdo); if(SUCCEEDED(hr)) { LPIDA pida = GlobalLock(medium.u.hGlobal); LPCITEMIDLIST pidl_child = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[1]); /* Handle folders by browsing to them. */ if(_ILIsFolder(pidl_child) || _ILIsDrive(pidl_child) || _ILIsSpecialFolder(pidl_child)) { IExplorerBrowser_BrowseToIDList((IExplorerBrowser*)This, pidl_child, SBSP_RELATIVE); ret = S_OK; } GlobalUnlock(medium.u.hGlobal); GlobalFree(medium.u.hGlobal); } else ERR("Failed to get data from IDataObject.\n"); } else ERR("Failed to get IDataObject.\n"); return ret; } static HRESULT WINAPI ICommDlgBrowser3_fnOnStateChange(ICommDlgBrowser3 *iface, IShellView *shv, ULONG uChange) { ExplorerBrowserImpl *This = impl_from_ICommDlgBrowser3(iface); FIXME("stub, %p (%p, %d)\n", This, shv, uChange); return E_NOTIMPL; } static HRESULT WINAPI ICommDlgBrowser3_fnIncludeObject(ICommDlgBrowser3 *iface, IShellView *pshv, LPCITEMIDLIST pidl) { ExplorerBrowserImpl *This = impl_from_ICommDlgBrowser3(iface); FIXME("stub, %p (%p, %p)\n", This, pshv, pidl); return S_OK; } static HRESULT WINAPI ICommDlgBrowser3_fnNotify(ICommDlgBrowser3 *iface, IShellView *pshv, DWORD dwNotifyType) { ExplorerBrowserImpl *This = impl_from_ICommDlgBrowser3(iface); FIXME("stub, %p (%p, 0x%x)\n", This, pshv, dwNotifyType); return S_OK; } static HRESULT WINAPI ICommDlgBrowser3_fnGetDefaultMenuText(ICommDlgBrowser3 *iface, IShellView *pshv, LPWSTR pszText, int cchMax) { ExplorerBrowserImpl *This = impl_from_ICommDlgBrowser3(iface); FIXME("stub, %p (%p, %s, %d)\n", This, pshv, debugstr_w(pszText), cchMax); return S_OK; } static HRESULT WINAPI ICommDlgBrowser3_fnGetViewFlags(ICommDlgBrowser3 *iface, DWORD *pdwFlags) { ExplorerBrowserImpl *This = impl_from_ICommDlgBrowser3(iface); FIXME("stub, %p (%p)\n", This, pdwFlags); return S_OK; } static HRESULT WINAPI ICommDlgBrowser3_fnOnColumnClicked(ICommDlgBrowser3 *iface, IShellView *pshv, int iColumn) { ExplorerBrowserImpl *This = impl_from_ICommDlgBrowser3(iface); FIXME("stub, %p (%p, %d)\n", This, pshv, iColumn); return S_OK; } static HRESULT WINAPI ICommDlgBrowser3_fnGetCurrentFilter(ICommDlgBrowser3 *iface, LPWSTR pszFileSpec, int cchFileSpec) { ExplorerBrowserImpl *This = impl_from_ICommDlgBrowser3(iface); FIXME("stub, %p (%s, %d)\n", This, debugstr_w(pszFileSpec), cchFileSpec); return S_OK; } static HRESULT WINAPI ICommDlgBrowser3_fnOnPreviewCreated(ICommDlgBrowser3 *iface, IShellView *pshv) { ExplorerBrowserImpl *This = impl_from_ICommDlgBrowser3(iface); FIXME("stub, %p (%p)\n", This, pshv); return S_OK; } static const ICommDlgBrowser3Vtbl vt_ICommDlgBrowser3 = { ICommDlgBrowser3_fnQueryInterface, ICommDlgBrowser3_fnAddRef, ICommDlgBrowser3_fnRelease, ICommDlgBrowser3_fnOnDefaultCommand, ICommDlgBrowser3_fnOnStateChange, ICommDlgBrowser3_fnIncludeObject, ICommDlgBrowser3_fnNotify, ICommDlgBrowser3_fnGetDefaultMenuText, ICommDlgBrowser3_fnGetViewFlags, ICommDlgBrowser3_fnOnColumnClicked, ICommDlgBrowser3_fnGetCurrentFilter, ICommDlgBrowser3_fnOnPreviewCreated }; /************************************************************************** * IObjectWithSite Implementation */ static inline ExplorerBrowserImpl *impl_from_IObjectWithSite(IObjectWithSite *iface) { return (ExplorerBrowserImpl *)((char*)iface - FIELD_OFFSET(ExplorerBrowserImpl, lpowsVtbl)); } static HRESULT WINAPI IObjectWithSite_fnQueryInterface(IObjectWithSite *iface, REFIID riid, void **ppvObject) { ExplorerBrowserImpl *This = impl_from_IObjectWithSite(iface); TRACE("%p\n", This); return IUnknown_QueryInterface((IUnknown*)This, riid, ppvObject); } static ULONG WINAPI IObjectWithSite_fnAddRef(IObjectWithSite *iface) { ExplorerBrowserImpl *This = impl_from_IObjectWithSite(iface); TRACE("%p\n", This); return IUnknown_AddRef((IUnknown*)This); } static ULONG WINAPI IObjectWithSite_fnRelease(IObjectWithSite *iface) { ExplorerBrowserImpl *This = impl_from_IObjectWithSite(iface); TRACE("%p\n", This); return IUnknown_Release((IUnknown*)This); } static HRESULT WINAPI IObjectWithSite_fnSetSite(IObjectWithSite *iface, IUnknown *punk_site) { ExplorerBrowserImpl *This = impl_from_IObjectWithSite(iface); TRACE("%p (%p)\n", This, punk_site); if(This->punk_site) { IUnknown_Release(This->punk_site); This->punk_site = NULL; get_interfaces_from_site(This); } This->punk_site = punk_site; if(This->punk_site) IUnknown_AddRef(This->punk_site); return S_OK; } static HRESULT WINAPI IObjectWithSite_fnGetSite(IObjectWithSite *iface, REFIID riid, void **ppvSite) { ExplorerBrowserImpl *This = impl_from_IObjectWithSite(iface); TRACE("%p (%s, %p)\n", This, shdebugstr_guid(riid), ppvSite); if(!This->punk_site) return E_FAIL; return IUnknown_QueryInterface(This->punk_site, riid, ppvSite); } static const IObjectWithSiteVtbl vt_IObjectWithSite = { IObjectWithSite_fnQueryInterface, IObjectWithSite_fnAddRef, IObjectWithSite_fnRelease, IObjectWithSite_fnSetSite, IObjectWithSite_fnGetSite }; HRESULT WINAPI ExplorerBrowser_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv) { ExplorerBrowserImpl *eb; HRESULT ret; TRACE("%p %s %p\n", pUnkOuter, shdebugstr_guid (riid), ppv); if(!ppv) return E_POINTER; if(pUnkOuter) return CLASS_E_NOAGGREGATION; eb = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ExplorerBrowserImpl)); eb->ref = 1; eb->lpVtbl = &vt_IExplorerBrowser; eb->lpsbVtbl = &vt_IShellBrowser; eb->lpcdb3Vtbl = &vt_ICommDlgBrowser3; eb->lpowsVtbl = &vt_IObjectWithSite; list_init(&eb->event_clients); list_init(&eb->travellog); ret = IExplorerBrowser_QueryInterface((IExplorerBrowser*)eb, riid, ppv); IExplorerBrowser_Release((IExplorerBrowser*)eb); TRACE("--(%p)\n", ppv); return ret; }