/* * 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 <stdarg.h> #define COBJMACROS #define NONAMELESSUNION #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); #define SPLITTER_WIDTH 2 #define NP_MIN_WIDTH 60 #define SV_MIN_WIDTH 150 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 { IExplorerBrowser IExplorerBrowser_iface; IShellBrowser IShellBrowser_iface; ICommDlgBrowser3 ICommDlgBrowser3_iface; IObjectWithSite IObjectWithSite_iface; INameSpaceTreeControlEvents INameSpaceTreeControlEvents_iface; IInputObject IInputObject_iface; LONG ref; BOOL destroyed; HWND hwnd_main; HWND hwnd_sv; RECT splitter_rc; struct { INameSpaceTreeControl2 *pnstc2; HWND hwnd_splitter, hwnd_nstc; DWORD nstc_cookie; UINT width; BOOL show; RECT rc; } navpane; 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; ICommDlgBrowser *pcdb_site; ICommDlgBrowser2 *pcdb2_site; ICommDlgBrowser3 *pcdb3_site; IExplorerPaneVisibility *pepv_site; } ExplorerBrowserImpl; static void initialize_navpane(ExplorerBrowserImpl *This, HWND hwnd_parent, RECT *rc); /************************************************************************** * 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); ILFree(entry->pidl); 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; INT navpane_width_actual; INT shellview_width_actual; TRACE("%p (navpane: %d, EBO_SHOWFRAMES: %d)\n", This, This->navpane.show, This->eb_options & EBO_SHOWFRAMES); GetClientRect(This->hwnd_main, &rc); if((This->eb_options & EBO_SHOWFRAMES) && This->navpane.show) navpane_width_actual = This->navpane.width; else navpane_width_actual = 0; shellview_width_actual = rc.right - navpane_width_actual; if(shellview_width_actual < SV_MIN_WIDTH && navpane_width_actual) { INT missing_width = SV_MIN_WIDTH - shellview_width_actual; if(missing_width < (navpane_width_actual - NP_MIN_WIDTH)) { /* Shrink the navpane */ navpane_width_actual -= missing_width; shellview_width_actual += missing_width; } else { /* Hide the navpane */ shellview_width_actual += navpane_width_actual; navpane_width_actual = 0; } } /************************************************************** * Calculate rectangles for the panes. All rectangles contain * the position of the panes relative to hwnd_main. */ if(navpane_width_actual) { This->navpane.rc.left = This->navpane.rc.top = 0; This->navpane.rc.right = navpane_width_actual; This->navpane.rc.bottom = rc.bottom; if(!This->navpane.hwnd_splitter) initialize_navpane(This, This->hwnd_main, &This->navpane.rc); } else ZeroMemory(&This->navpane.rc, sizeof(RECT)); This->sv_rc.left = navpane_width_actual; This->sv_rc.top = 0; This->sv_rc.right = This->sv_rc.left + shellview_width_actual; This->sv_rc.bottom = rc.bottom; } static void size_panes(ExplorerBrowserImpl *This) { MoveWindow(This->navpane.hwnd_splitter, This->navpane.rc.right - SPLITTER_WIDTH, This->navpane.rc.top, SPLITTER_WIDTH, This->navpane.rc.bottom - This->navpane.rc.top, TRUE); 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 = &This->IShellBrowser_iface; 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->pcdb_site) { ICommDlgBrowser_Release(This->pcdb_site); if(This->pcdb2_site) ICommDlgBrowser2_Release(This->pcdb2_site); if(This->pcdb3_site) ICommDlgBrowser3_Release(This->pcdb3_site); This->pcdb_site = NULL; This->pcdb2_site = NULL; This->pcdb3_site = NULL; } if(This->pepv_site) { IExplorerPaneVisibility_Release(This->pepv_site); This->pepv_site = NULL; } if(!This->punk_site) return; hr = IUnknown_QueryInterface(This->punk_site, &IID_IServiceProvider, (void**)&psp); if(FAILED(hr)) { ERR("Failed to get IServiceProvider from site.\n"); return; } /* ICommDlgBrowser */ IServiceProvider_QueryService(psp, &SID_SExplorerBrowserFrame, &IID_ICommDlgBrowser, (void**)&This->pcdb_site); IServiceProvider_QueryService(psp, &SID_SExplorerBrowserFrame, &IID_ICommDlgBrowser2, (void**)&This->pcdb2_site); IServiceProvider_QueryService(psp, &SID_SExplorerBrowserFrame, &IID_ICommDlgBrowser3, (void**)&This->pcdb3_site); /* IExplorerPaneVisibility */ IServiceProvider_QueryService(psp, &SID_ExplorerPaneVisibility, &IID_IExplorerPaneVisibility, (void**)&This->pepv_site); IServiceProvider_Release(psp); } /************************************************************************** * General pane functionality. */ static void update_panestate(ExplorerBrowserImpl *This) { EXPLORERPANESTATE eps = EPS_DONTCARE; BOOL show_navpane; TRACE("%p\n", This); if(!This->pepv_site) return; IExplorerPaneVisibility_GetPaneState(This->pepv_site, (REFEXPLORERPANE) &EP_NavPane, &eps); if( !(eps & EPS_DEFAULT_OFF) ) show_navpane = TRUE; else show_navpane = FALSE; if(This->navpane.show != show_navpane) { update_layout(This); size_panes(This); } This->navpane.show = show_navpane; } static void splitter_draw(HWND hwnd, RECT *rc) { HDC hdc = GetDC(hwnd); InvertRect(hdc, rc); ReleaseDC(hwnd, hdc); } /************************************************************************** * The Navigation Pane. */ static LRESULT navpane_splitter_beginresize(ExplorerBrowserImpl *This, HWND hwnd, LPARAM lParam) { TRACE("\n"); SetCapture(hwnd); This->splitter_rc = This->navpane.rc; This->splitter_rc.left = This->splitter_rc.right - SPLITTER_WIDTH; splitter_draw(GetParent(hwnd), &This->splitter_rc); return TRUE; } static LRESULT navpane_splitter_resizing(ExplorerBrowserImpl *This, HWND hwnd, LPARAM lParam) { int new_width, dx; RECT rc; if(GetCapture() != hwnd) return FALSE; dx = (SHORT)LOWORD(lParam); TRACE("%d.\n", dx); rc = This->navpane.rc; new_width = This->navpane.width + dx; if(new_width > NP_MIN_WIDTH && This->sv_rc.right - new_width > SV_MIN_WIDTH) { rc.right = new_width; rc.left = rc.right - SPLITTER_WIDTH; splitter_draw(GetParent(hwnd), &This->splitter_rc); splitter_draw(GetParent(hwnd), &rc); This->splitter_rc = rc; } return TRUE; } static LRESULT navpane_splitter_endresize(ExplorerBrowserImpl *This, HWND hwnd, LPARAM lParam) { int new_width, dx; if(GetCapture() != hwnd) return FALSE; dx = (SHORT)LOWORD(lParam); TRACE("%d.\n", dx); splitter_draw(GetParent(hwnd), &This->splitter_rc); new_width = This->navpane.width + dx; if(new_width < NP_MIN_WIDTH) new_width = NP_MIN_WIDTH; else if(This->sv_rc.right - new_width < SV_MIN_WIDTH) new_width = This->sv_rc.right - SV_MIN_WIDTH; This->navpane.width = new_width; update_layout(This); size_panes(This); ReleaseCapture(); return TRUE; } static LRESULT navpane_on_wm_create(HWND hwnd, CREATESTRUCTW *crs) { ExplorerBrowserImpl *This = crs->lpCreateParams; INameSpaceTreeControl2 *pnstc2; DWORD style; HRESULT hr; TRACE("%p\n", This); SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LPARAM)This); This->navpane.hwnd_splitter = hwnd; hr = CoCreateInstance(&CLSID_NamespaceTreeControl, NULL, CLSCTX_INPROC_SERVER, &IID_INameSpaceTreeControl2, (void**)&pnstc2); if(SUCCEEDED(hr)) { style = NSTCS_HASEXPANDOS | NSTCS_ROOTHASEXPANDO | NSTCS_SHOWSELECTIONALWAYS; hr = INameSpaceTreeControl2_Initialize(pnstc2, GetParent(hwnd), NULL, style); if(SUCCEEDED(hr)) { INameSpaceTreeControlEvents *pnstce; IShellFolder *psfdesktop; IShellItem *psi; IOleWindow *pow; LPITEMIDLIST pidl; DWORD cookie, style2 = NSTCS2_DISPLAYPADDING; hr = INameSpaceTreeControl2_SetControlStyle2(pnstc2, 0xFF, style2); if(FAILED(hr)) ERR("SetControlStyle2 failed (0x%08x)\n", hr); hr = INameSpaceTreeControl2_QueryInterface(pnstc2, &IID_IOleWindow, (void**)&pow); if(SUCCEEDED(hr)) { IOleWindow_GetWindow(pow, &This->navpane.hwnd_nstc); IOleWindow_Release(pow); } else ERR("QueryInterface(IOleWindow) failed (0x%08x)\n", hr); pnstce = &This->INameSpaceTreeControlEvents_iface; hr = INameSpaceTreeControl2_TreeAdvise(pnstc2, (IUnknown*)pnstce, &cookie); if(FAILED(hr)) ERR("TreeAdvise failed. (0x%08x).\n", hr); /* * Add the default roots */ /* TODO: This should be FOLDERID_Links */ hr = SHGetSpecialFolderLocation(NULL, CSIDL_FAVORITES, &pidl); if(SUCCEEDED(hr)) { hr = SHCreateShellItem(NULL, NULL, pidl, &psi); if(SUCCEEDED(hr)) { hr = INameSpaceTreeControl2_AppendRoot(pnstc2, psi, SHCONTF_NONFOLDERS, NSTCRS_VISIBLE, NULL); IShellItem_Release(psi); } ILFree(pidl); } SHGetDesktopFolder(&psfdesktop); hr = SHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi); IShellFolder_Release(psfdesktop); if(SUCCEEDED(hr)) { hr = INameSpaceTreeControl2_AppendRoot(pnstc2, psi, SHCONTF_FOLDERS, NSTCRS_EXPANDED, NULL); IShellItem_Release(psi); } /* TODO: * We should advertise IID_INameSpaceTreeControl to the site of the * host through its IProfferService interface, if any. */ This->navpane.pnstc2 = pnstc2; This->navpane.nstc_cookie = cookie; return TRUE; } } This->navpane.pnstc2 = NULL; ERR("Failed (0x%08x)\n", hr); return FALSE; } static LRESULT navpane_on_wm_size_move(ExplorerBrowserImpl *This) { UINT height, width; TRACE("%p\n", This); width = This->navpane.rc.right - This->navpane.rc.left - SPLITTER_WIDTH; height = This->navpane.rc.bottom - This->navpane.rc.top; MoveWindow(This->navpane.hwnd_nstc, This->navpane.rc.left, This->navpane.rc.top, width, height, TRUE); return FALSE; } static LRESULT navpane_on_wm_destroy(ExplorerBrowserImpl *This) { INameSpaceTreeControl2_TreeUnadvise(This->navpane.pnstc2, This->navpane.nstc_cookie); INameSpaceTreeControl2_Release(This->navpane.pnstc2); This->navpane.pnstc2 = NULL; return TRUE; } static LRESULT CALLBACK navpane_wndproc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam) { ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)GetWindowLongPtrW(hWnd, GWLP_USERDATA); switch(uMessage) { case WM_CREATE: return navpane_on_wm_create(hWnd, (CREATESTRUCTW*)lParam); case WM_MOVE: /* Fall through */ case WM_SIZE: return navpane_on_wm_size_move(This); case WM_DESTROY: return navpane_on_wm_destroy(This); case WM_LBUTTONDOWN: return navpane_splitter_beginresize(This, hWnd, lParam); case WM_MOUSEMOVE: return navpane_splitter_resizing(This, hWnd, lParam); case WM_LBUTTONUP: return navpane_splitter_endresize(This, hWnd, lParam); default: return DefWindowProcW(hWnd, uMessage, wParam, lParam); } return 0; } static void initialize_navpane(ExplorerBrowserImpl *This, HWND hwnd_parent, RECT *rc) { WNDCLASSW wc; HWND splitter; static const WCHAR navpane_classname[] = {'e','b','_','n','a','v','p','a','n','e',0}; if( !GetClassInfoW(shell32_hInstance, navpane_classname, &wc) ) { wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = navpane_wndproc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = shell32_hInstance; wc.hIcon = 0; wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_SIZEWE); wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); wc.lpszMenuName = NULL; wc.lpszClassName = navpane_classname; if (!RegisterClassW(&wc)) return; } splitter = CreateWindowExW(0, navpane_classname, NULL, WS_CHILD | WS_TABSTOP | WS_VISIBLE, rc->right - SPLITTER_WIDTH, rc->top, SPLITTER_WIDTH, rc->bottom - rc->top, hwnd_parent, 0, shell32_hInstance, This); if(!splitter) ERR("Failed to create navpane : %d.\n", GetLastError()); } /************************************************************************** * 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 main_on_cwm_getishellbrowser(ExplorerBrowserImpl *This) { return (LRESULT)&This->IShellBrowser_iface; } 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); case CWM_GETISHELLBROWSER: return main_on_cwm_getishellbrowser(This); default: return DefWindowProcW(hWnd, uMessage, wParam, lParam); } return 0; } /************************************************************************** * IExplorerBrowser Implementation */ static inline ExplorerBrowserImpl *impl_from_IExplorerBrowser(IExplorerBrowser *iface) { return CONTAINING_RECORD(iface, ExplorerBrowserImpl, IExplorerBrowser_iface); } static HRESULT WINAPI IExplorerBrowser_fnQueryInterface(IExplorerBrowser *iface, REFIID riid, void **ppvObject) { ExplorerBrowserImpl *This = impl_from_IExplorerBrowser(iface); TRACE("%p (%s, %p)\n", This, shdebugstr_guid(riid), ppvObject); *ppvObject = NULL; if(IsEqualIID(riid, &IID_IExplorerBrowser) || IsEqualIID(riid, &IID_IUnknown)) { *ppvObject = &This->IExplorerBrowser_iface; } else if(IsEqualIID(riid, &IID_IShellBrowser) || IsEqualIID(riid, &IID_IOleWindow)) { *ppvObject = &This->IShellBrowser_iface; } else if(IsEqualIID(riid, &IID_ICommDlgBrowser) || IsEqualIID(riid, &IID_ICommDlgBrowser2) || IsEqualIID(riid, &IID_ICommDlgBrowser3)) { *ppvObject = &This->ICommDlgBrowser3_iface; } else if(IsEqualIID(riid, &IID_IObjectWithSite)) { *ppvObject = &This->IObjectWithSite_iface; } else if(IsEqualIID(riid, &IID_IInputObject)) { *ppvObject = &This->IInputObject_iface; } if(*ppvObject) { IUnknown_AddRef((IUnknown*)*ppvObject); return S_OK; } return E_NOINTERFACE; } static ULONG WINAPI IExplorerBrowser_fnAddRef(IExplorerBrowser *iface) { ExplorerBrowserImpl *This = impl_from_IExplorerBrowser(iface); LONG ref = InterlockedIncrement(&This->ref); TRACE("%p - ref %d\n", This, ref); return ref; } static ULONG WINAPI IExplorerBrowser_fnRelease(IExplorerBrowser *iface) { ExplorerBrowserImpl *This = impl_from_IExplorerBrowser(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(&This->IObjectWithSite_iface, 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 = impl_from_IExplorerBrowser(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; if (!(This->eb_options & EBO_NOBORDER)) style |= 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 = impl_from_IExplorerBrowser(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 = impl_from_IExplorerBrowser(iface); TRACE("%p (%p, %s)\n", This, phdwp, wine_dbgstr_rect(&rcBrowser)); if(phdwp && *phdwp) { *phdwp = DeferWindowPos(*phdwp, This->hwnd_main, NULL, rcBrowser.left, rcBrowser.top, rcBrowser.right - rcBrowser.left, rcBrowser.bottom - rcBrowser.top, SWP_NOZORDER | SWP_NOACTIVATE); if(!*phdwp) return E_FAIL; } 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 = impl_from_IExplorerBrowser(iface); FIXME("stub, %p (%s)\n", This, debugstr_w(pszPropertyBag)); if(!pszPropertyBag) return E_INVALIDARG; /* FIXME: This method is currently useless as we don't save any * settings anywhere, but at least one application breaks if we * return E_NOTIMPL. */ return S_OK; } static HRESULT WINAPI IExplorerBrowser_fnSetEmptyText(IExplorerBrowser *iface, LPCWSTR pszEmptyText) { ExplorerBrowserImpl *This = impl_from_IExplorerBrowser(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 = impl_from_IExplorerBrowser(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 = impl_from_IExplorerBrowser(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 = impl_from_IExplorerBrowser(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 = impl_from_IExplorerBrowser(iface); static const EXPLORER_BROWSER_OPTIONS unsupported_options = EBO_ALWAYSNAVIGATE | EBO_NOWRAPPERWINDOW | EBO_HTMLSHAREPOINTVIEW | EBO_NOPERSISTVIEWSTATE; 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 = impl_from_IExplorerBrowser(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 = impl_from_IExplorerBrowser(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); update_panestate(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; /* Expand the NameSpaceTree to the current location. */ if(This->navpane.show && This->navpane.pnstc2) { IShellItem *psi; hr = SHCreateItemFromIDList(This->current_pidl, &IID_IShellItem, (void**)&psi); if(SUCCEEDED(hr)) { INameSpaceTreeControl2_EnsureItemVisible(This->navpane.pnstc2, psi); IShellItem_Release(psi); } } return S_OK; } static HRESULT WINAPI IExplorerBrowser_fnBrowseToObject(IExplorerBrowser *iface, IUnknown *punk, UINT uFlags) { ExplorerBrowserImpl *This = impl_from_IExplorerBrowser(iface); LPITEMIDLIST pidl; HRESULT hr; TRACE("%p (%p, 0x%x)\n", This, punk, uFlags); if(!punk) return IExplorerBrowser_BrowseToIDList(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 = impl_from_IExplorerBrowser(iface); FIXME("stub, %p (%p, 0x%x)\n", This, punk, dwFlags); return E_NOTIMPL; } static HRESULT WINAPI IExplorerBrowser_fnRemoveAll(IExplorerBrowser *iface) { ExplorerBrowserImpl *This = impl_from_IExplorerBrowser(iface); FIXME("stub, %p\n", This); return E_NOTIMPL; } static HRESULT WINAPI IExplorerBrowser_fnGetCurrentView(IExplorerBrowser *iface, REFIID riid, void **ppv) { ExplorerBrowserImpl *This = impl_from_IExplorerBrowser(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 CONTAINING_RECORD(iface, ExplorerBrowserImpl, IShellBrowser_iface); } static HRESULT WINAPI IShellBrowser_fnQueryInterface(IShellBrowser *iface, REFIID riid, void **ppvObject) { ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface); TRACE("%p\n", This); return IExplorerBrowser_QueryInterface(&This->IExplorerBrowser_iface, riid, ppvObject); } static ULONG WINAPI IShellBrowser_fnAddRef(IShellBrowser *iface) { ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface); TRACE("%p\n", This); return IExplorerBrowser_AddRef(&This->IExplorerBrowser_iface); } static ULONG WINAPI IShellBrowser_fnRelease(IShellBrowser *iface) { ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface); TRACE("%p\n", This); return IExplorerBrowser_Release(&This->IExplorerBrowser_iface); } 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_BrowseToIDList(&This->IExplorerBrowser_iface, 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); if (phwnd) *phwnd = NULL; 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 CONTAINING_RECORD(iface, ExplorerBrowserImpl, ICommDlgBrowser3_iface); } static HRESULT WINAPI ICommDlgBrowser3_fnQueryInterface(ICommDlgBrowser3 *iface, REFIID riid, void **ppvObject) { ExplorerBrowserImpl *This = impl_from_ICommDlgBrowser3(iface); TRACE("%p\n", This); return IExplorerBrowser_QueryInterface(&This->IExplorerBrowser_iface, riid, ppvObject); } static ULONG WINAPI ICommDlgBrowser3_fnAddRef(ICommDlgBrowser3 *iface) { ExplorerBrowserImpl *This = impl_from_ICommDlgBrowser3(iface); TRACE("%p\n", This); return IExplorerBrowser_AddRef(&This->IExplorerBrowser_iface); } static ULONG WINAPI ICommDlgBrowser3_fnRelease(ICommDlgBrowser3 *iface) { ExplorerBrowserImpl *This = impl_from_ICommDlgBrowser3(iface); TRACE("%p\n", This); return IExplorerBrowser_Release(&This->IExplorerBrowser_iface); } 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(&This->IExplorerBrowser_iface, 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"); /* If we didn't handle the default command, check if we have a * client that does */ if(ret == S_FALSE && This->pcdb_site) return ICommDlgBrowser_OnDefaultCommand(This->pcdb_site, shv); return ret; } static HRESULT WINAPI ICommDlgBrowser3_fnOnStateChange(ICommDlgBrowser3 *iface, IShellView *shv, ULONG uChange) { ExplorerBrowserImpl *This = impl_from_ICommDlgBrowser3(iface); TRACE("%p (%p, %d)\n", This, shv, uChange); if(This->pcdb_site) return ICommDlgBrowser_OnStateChange(This->pcdb_site, shv, uChange); return E_NOTIMPL; } static HRESULT WINAPI ICommDlgBrowser3_fnIncludeObject(ICommDlgBrowser3 *iface, IShellView *pshv, LPCITEMIDLIST pidl) { ExplorerBrowserImpl *This = impl_from_ICommDlgBrowser3(iface); TRACE("%p (%p, %p)\n", This, pshv, pidl); if(This->pcdb_site) return ICommDlgBrowser_IncludeObject(This->pcdb_site, pshv, pidl); return S_OK; } static HRESULT WINAPI ICommDlgBrowser3_fnNotify(ICommDlgBrowser3 *iface, IShellView *pshv, DWORD dwNotifyType) { ExplorerBrowserImpl *This = impl_from_ICommDlgBrowser3(iface); TRACE("%p (%p, 0x%x)\n", This, pshv, dwNotifyType); if(This->pcdb2_site) return ICommDlgBrowser2_Notify(This->pcdb2_site, pshv, dwNotifyType); return S_OK; } static HRESULT WINAPI ICommDlgBrowser3_fnGetDefaultMenuText(ICommDlgBrowser3 *iface, IShellView *pshv, LPWSTR pszText, int cchMax) { ExplorerBrowserImpl *This = impl_from_ICommDlgBrowser3(iface); TRACE("%p (%p, %s, %d)\n", This, pshv, debugstr_w(pszText), cchMax); if(This->pcdb2_site) return ICommDlgBrowser2_GetDefaultMenuText(This->pcdb2_site, pshv, pszText, cchMax); return S_OK; } static HRESULT WINAPI ICommDlgBrowser3_fnGetViewFlags(ICommDlgBrowser3 *iface, DWORD *pdwFlags) { ExplorerBrowserImpl *This = impl_from_ICommDlgBrowser3(iface); TRACE("%p (%p)\n", This, pdwFlags); if(This->pcdb2_site) return ICommDlgBrowser2_GetViewFlags(This->pcdb2_site, pdwFlags); return S_OK; } static HRESULT WINAPI ICommDlgBrowser3_fnOnColumnClicked(ICommDlgBrowser3 *iface, IShellView *pshv, int iColumn) { ExplorerBrowserImpl *This = impl_from_ICommDlgBrowser3(iface); TRACE("%p (%p, %d)\n", This, pshv, iColumn); if(This->pcdb3_site) return ICommDlgBrowser3_OnColumnClicked(This->pcdb3_site, pshv, iColumn); return S_OK; } static HRESULT WINAPI ICommDlgBrowser3_fnGetCurrentFilter(ICommDlgBrowser3 *iface, LPWSTR pszFileSpec, int cchFileSpec) { ExplorerBrowserImpl *This = impl_from_ICommDlgBrowser3(iface); TRACE("%p (%s, %d)\n", This, debugstr_w(pszFileSpec), cchFileSpec); if(This->pcdb3_site) return ICommDlgBrowser3_GetCurrentFilter(This->pcdb3_site, pszFileSpec, cchFileSpec); return S_OK; } static HRESULT WINAPI ICommDlgBrowser3_fnOnPreviewCreated(ICommDlgBrowser3 *iface, IShellView *pshv) { ExplorerBrowserImpl *This = impl_from_ICommDlgBrowser3(iface); TRACE("%p (%p)\n", This, pshv); if(This->pcdb3_site) return ICommDlgBrowser3_OnPreviewCreated(This->pcdb3_site, 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 CONTAINING_RECORD(iface, ExplorerBrowserImpl, IObjectWithSite_iface); } static HRESULT WINAPI IObjectWithSite_fnQueryInterface(IObjectWithSite *iface, REFIID riid, void **ppvObject) { ExplorerBrowserImpl *This = impl_from_IObjectWithSite(iface); TRACE("%p\n", This); return IExplorerBrowser_QueryInterface(&This->IExplorerBrowser_iface, riid, ppvObject); } static ULONG WINAPI IObjectWithSite_fnAddRef(IObjectWithSite *iface) { ExplorerBrowserImpl *This = impl_from_IObjectWithSite(iface); TRACE("%p\n", This); return IExplorerBrowser_AddRef(&This->IExplorerBrowser_iface); } static ULONG WINAPI IObjectWithSite_fnRelease(IObjectWithSite *iface) { ExplorerBrowserImpl *This = impl_from_IObjectWithSite(iface); TRACE("%p\n", This); return IExplorerBrowser_Release(&This->IExplorerBrowser_iface); } 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 }; /************************************************************************** * INameSpaceTreeControlEvents Implementation */ static inline ExplorerBrowserImpl *impl_from_INameSpaceTreeControlEvents(INameSpaceTreeControlEvents *iface) { return CONTAINING_RECORD(iface, ExplorerBrowserImpl, INameSpaceTreeControlEvents_iface); } static HRESULT WINAPI NSTCEvents_fnQueryInterface(INameSpaceTreeControlEvents *iface, REFIID riid, void **ppvObject) { ExplorerBrowserImpl *This = impl_from_INameSpaceTreeControlEvents(iface); TRACE("%p (%s, %p)\n", This, shdebugstr_guid(riid), ppvObject); *ppvObject = NULL; if(IsEqualIID(riid, &IID_INameSpaceTreeControlEvents) || IsEqualIID(riid, &IID_IUnknown)) { *ppvObject = iface; } if(*ppvObject) { IUnknown_AddRef((IUnknown*)*ppvObject); return S_OK; } return E_NOINTERFACE; } static ULONG WINAPI NSTCEvents_fnAddRef(INameSpaceTreeControlEvents *iface) { ExplorerBrowserImpl *This = impl_from_INameSpaceTreeControlEvents(iface); TRACE("%p\n", This); return IExplorerBrowser_AddRef(&This->IExplorerBrowser_iface); } static ULONG WINAPI NSTCEvents_fnRelease(INameSpaceTreeControlEvents *iface) { ExplorerBrowserImpl *This = impl_from_INameSpaceTreeControlEvents(iface); TRACE("%p\n", This); return IExplorerBrowser_Release(&This->IExplorerBrowser_iface); } static HRESULT WINAPI NSTCEvents_fnOnItemClick(INameSpaceTreeControlEvents *iface, IShellItem *psi, NSTCEHITTEST nstceHitTest, NSTCECLICKTYPE nstceClickType) { ExplorerBrowserImpl *This = impl_from_INameSpaceTreeControlEvents(iface); TRACE("%p (%p, 0x%x, 0x%x)\n", This, psi, nstceHitTest, nstceClickType); return S_OK; } static HRESULT WINAPI NSTCEvents_fnOnPropertyItemCommit(INameSpaceTreeControlEvents *iface, IShellItem *psi) { ExplorerBrowserImpl *This = impl_from_INameSpaceTreeControlEvents(iface); TRACE("%p (%p)\n", This, psi); return E_NOTIMPL; } static HRESULT WINAPI NSTCEvents_fnOnItemStateChanging(INameSpaceTreeControlEvents *iface, IShellItem *psi, NSTCITEMSTATE nstcisMask, NSTCITEMSTATE nstcisState) { ExplorerBrowserImpl *This = impl_from_INameSpaceTreeControlEvents(iface); TRACE("%p (%p, 0x%x, 0x%x)\n", This, psi, nstcisMask, nstcisState); return E_NOTIMPL; } static HRESULT WINAPI NSTCEvents_fnOnItemStateChanged(INameSpaceTreeControlEvents *iface, IShellItem *psi, NSTCITEMSTATE nstcisMask, NSTCITEMSTATE nstcisState) { ExplorerBrowserImpl *This = impl_from_INameSpaceTreeControlEvents(iface); TRACE("%p (%p, 0x%x, 0x%x)\n", This, psi, nstcisMask, nstcisState); return E_NOTIMPL; } static HRESULT WINAPI NSTCEvents_fnOnSelectionChanged(INameSpaceTreeControlEvents *iface, IShellItemArray *psiaSelection) { ExplorerBrowserImpl *This = impl_from_INameSpaceTreeControlEvents(iface); IShellItem *psi; HRESULT hr; TRACE("%p (%p)\n", This, psiaSelection); hr = IShellItemArray_GetItemAt(psiaSelection, 0, &psi); if(SUCCEEDED(hr)) { hr = IExplorerBrowser_BrowseToObject(&This->IExplorerBrowser_iface, (IUnknown*)psi, SBSP_DEFBROWSER); IShellItem_Release(psi); } return hr; } static HRESULT WINAPI NSTCEvents_fnOnKeyboardInput(INameSpaceTreeControlEvents *iface, UINT uMsg, WPARAM wParam, LPARAM lParam) { ExplorerBrowserImpl *This = impl_from_INameSpaceTreeControlEvents(iface); TRACE("%p (%d, 0x%lx, 0x%lx)\n", This, uMsg, wParam, lParam); return S_OK; } static HRESULT WINAPI NSTCEvents_fnOnBeforeExpand(INameSpaceTreeControlEvents *iface, IShellItem *psi) { ExplorerBrowserImpl *This = impl_from_INameSpaceTreeControlEvents(iface); TRACE("%p (%p)\n", This, psi); return E_NOTIMPL; } static HRESULT WINAPI NSTCEvents_fnOnAfterExpand(INameSpaceTreeControlEvents *iface, IShellItem *psi) { ExplorerBrowserImpl *This = impl_from_INameSpaceTreeControlEvents(iface); TRACE("%p (%p)\n", This, psi); return E_NOTIMPL; } static HRESULT WINAPI NSTCEvents_fnOnBeginLabelEdit(INameSpaceTreeControlEvents *iface, IShellItem *psi) { ExplorerBrowserImpl *This = impl_from_INameSpaceTreeControlEvents(iface); TRACE("%p (%p)\n", This, psi); return E_NOTIMPL; } static HRESULT WINAPI NSTCEvents_fnOnEndLabelEdit(INameSpaceTreeControlEvents *iface, IShellItem *psi) { ExplorerBrowserImpl *This = impl_from_INameSpaceTreeControlEvents(iface); TRACE("%p (%p)\n", This, psi); return E_NOTIMPL; } static HRESULT WINAPI NSTCEvents_fnOnGetToolTip(INameSpaceTreeControlEvents *iface, IShellItem *psi, LPWSTR pszTip, int cchTip) { ExplorerBrowserImpl *This = impl_from_INameSpaceTreeControlEvents(iface); TRACE("%p (%p, %p, %d)\n", This, psi, pszTip, cchTip); return E_NOTIMPL; } static HRESULT WINAPI NSTCEvents_fnOnBeforeItemDelete(INameSpaceTreeControlEvents *iface, IShellItem *psi) { ExplorerBrowserImpl *This = impl_from_INameSpaceTreeControlEvents(iface); TRACE("%p (%p)\n", This, psi); return E_NOTIMPL; } static HRESULT WINAPI NSTCEvents_fnOnItemAdded(INameSpaceTreeControlEvents *iface, IShellItem *psi, BOOL fIsRoot) { ExplorerBrowserImpl *This = impl_from_INameSpaceTreeControlEvents(iface); TRACE("%p (%p, %d)\n", This, psi, fIsRoot); return E_NOTIMPL; } static HRESULT WINAPI NSTCEvents_fnOnItemDeleted(INameSpaceTreeControlEvents *iface, IShellItem *psi, BOOL fIsRoot) { ExplorerBrowserImpl *This = impl_from_INameSpaceTreeControlEvents(iface); TRACE("%p (%p, %d)\n", This, psi, fIsRoot); return E_NOTIMPL; } static HRESULT WINAPI NSTCEvents_fnOnBeforeContextMenu(INameSpaceTreeControlEvents *iface, IShellItem *psi, REFIID riid, void **ppv) { ExplorerBrowserImpl *This = impl_from_INameSpaceTreeControlEvents(iface); TRACE("%p (%p, %s, %p)\n", This, psi, shdebugstr_guid(riid), ppv); return E_NOTIMPL; } static HRESULT WINAPI NSTCEvents_fnOnAfterContextMenu(INameSpaceTreeControlEvents *iface, IShellItem *psi, IContextMenu *pcmIn, REFIID riid, void **ppv) { ExplorerBrowserImpl *This = impl_from_INameSpaceTreeControlEvents(iface); TRACE("%p (%p, %p, %s, %p)\n", This, psi, pcmIn, shdebugstr_guid(riid), ppv); return E_NOTIMPL; } static HRESULT WINAPI NSTCEvents_fnOnBeforeStateImageChange(INameSpaceTreeControlEvents *iface, IShellItem *psi) { ExplorerBrowserImpl *This = impl_from_INameSpaceTreeControlEvents(iface); TRACE("%p (%p)\n", This, psi); return E_NOTIMPL; } static HRESULT WINAPI NSTCEvents_fnOnGetDefaultIconIndex(INameSpaceTreeControlEvents* iface, IShellItem *psi, int *piDefaultIcon, int *piOpenIcon) { ExplorerBrowserImpl *This = impl_from_INameSpaceTreeControlEvents(iface); TRACE("%p (%p, %p, %p)\n", This, psi, piDefaultIcon, piOpenIcon); return E_NOTIMPL; } static const INameSpaceTreeControlEventsVtbl vt_INameSpaceTreeControlEvents = { NSTCEvents_fnQueryInterface, NSTCEvents_fnAddRef, NSTCEvents_fnRelease, NSTCEvents_fnOnItemClick, NSTCEvents_fnOnPropertyItemCommit, NSTCEvents_fnOnItemStateChanging, NSTCEvents_fnOnItemStateChanged, NSTCEvents_fnOnSelectionChanged, NSTCEvents_fnOnKeyboardInput, NSTCEvents_fnOnBeforeExpand, NSTCEvents_fnOnAfterExpand, NSTCEvents_fnOnBeginLabelEdit, NSTCEvents_fnOnEndLabelEdit, NSTCEvents_fnOnGetToolTip, NSTCEvents_fnOnBeforeItemDelete, NSTCEvents_fnOnItemAdded, NSTCEvents_fnOnItemDeleted, NSTCEvents_fnOnBeforeContextMenu, NSTCEvents_fnOnAfterContextMenu, NSTCEvents_fnOnBeforeStateImageChange, NSTCEvents_fnOnGetDefaultIconIndex }; /************************************************************************** * IInputObject Implementation */ static inline ExplorerBrowserImpl *impl_from_IInputObject(IInputObject *iface) { return CONTAINING_RECORD(iface, ExplorerBrowserImpl, IInputObject_iface); } static HRESULT WINAPI IInputObject_fnQueryInterface(IInputObject *iface, REFIID riid, void **ppvObject) { ExplorerBrowserImpl *This = impl_from_IInputObject(iface); TRACE("%p\n", This); return IExplorerBrowser_QueryInterface(&This->IExplorerBrowser_iface, riid, ppvObject); } static ULONG WINAPI IInputObject_fnAddRef(IInputObject *iface) { ExplorerBrowserImpl *This = impl_from_IInputObject(iface); TRACE("%p\n", This); return IExplorerBrowser_AddRef(&This->IExplorerBrowser_iface); } static ULONG WINAPI IInputObject_fnRelease(IInputObject *iface) { ExplorerBrowserImpl *This = impl_from_IInputObject(iface); TRACE("%p\n", This); return IExplorerBrowser_Release(&This->IExplorerBrowser_iface); } static HRESULT WINAPI IInputObject_fnUIActivateIO(IInputObject *iface, BOOL fActivate, MSG *pMsg) { ExplorerBrowserImpl *This = impl_from_IInputObject(iface); FIXME("stub, %p (%d, %p)\n", This, fActivate, pMsg); return E_NOTIMPL; } static HRESULT WINAPI IInputObject_fnHasFocusIO(IInputObject *iface) { ExplorerBrowserImpl *This = impl_from_IInputObject(iface); FIXME("stub, %p\n", This); return E_NOTIMPL; } static HRESULT WINAPI IInputObject_fnTranslateAcceleratorIO(IInputObject *iface, MSG *pMsg) { ExplorerBrowserImpl *This = impl_from_IInputObject(iface); FIXME("stub, %p (%p)\n", This, pMsg); return E_NOTIMPL; } static IInputObjectVtbl vt_IInputObject = { IInputObject_fnQueryInterface, IInputObject_fnAddRef, IInputObject_fnRelease, IInputObject_fnUIActivateIO, IInputObject_fnHasFocusIO, IInputObject_fnTranslateAcceleratorIO }; 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->IExplorerBrowser_iface.lpVtbl = &vt_IExplorerBrowser; eb->IShellBrowser_iface.lpVtbl = &vt_IShellBrowser; eb->ICommDlgBrowser3_iface.lpVtbl = &vt_ICommDlgBrowser3; eb->IObjectWithSite_iface.lpVtbl = &vt_IObjectWithSite; eb->INameSpaceTreeControlEvents_iface.lpVtbl = &vt_INameSpaceTreeControlEvents; eb->IInputObject_iface.lpVtbl = &vt_IInputObject; /* Default settings */ eb->navpane.width = 150; eb->navpane.show = TRUE; list_init(&eb->event_clients); list_init(&eb->travellog); ret = IExplorerBrowser_QueryInterface(&eb->IExplorerBrowser_iface, riid, ppv); IExplorerBrowser_Release(&eb->IExplorerBrowser_iface); TRACE("--(%p)\n", ppv); return ret; }