| /* |
| * Implementation of hyperlinking (hlink.dll) |
| * |
| * Copyright 2005 Aric Stewart for CodeWeavers |
| * |
| * 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 "hlink_private.h" |
| |
| #include "wine/debug.h" |
| #include "wine/list.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(hlink); |
| |
| struct link_entry |
| { |
| struct list entry; |
| IHlink *link; |
| }; |
| |
| typedef struct |
| { |
| IHlinkBrowseContext IHlinkBrowseContext_iface; |
| LONG ref; |
| HLBWINFO* BrowseWindowInfo; |
| struct link_entry *current; |
| struct list links; |
| } HlinkBCImpl; |
| |
| static inline HlinkBCImpl *impl_from_IHlinkBrowseContext(IHlinkBrowseContext *iface) |
| { |
| return CONTAINING_RECORD(iface, HlinkBCImpl, IHlinkBrowseContext_iface); |
| } |
| |
| static HRESULT WINAPI IHlinkBC_fnQueryInterface( IHlinkBrowseContext *iface, |
| REFIID riid, LPVOID* ppvObj) |
| { |
| HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface); |
| TRACE ("(%p)->(%s,%p)\n", This, debugstr_guid (riid), ppvObj); |
| |
| if (IsEqualIID(riid, &IID_IUnknown) || |
| IsEqualIID(riid, &IID_IHlinkBrowseContext)) |
| *ppvObj = This; |
| |
| if (*ppvObj) |
| { |
| IUnknown_AddRef((IUnknown*)(*ppvObj)); |
| return S_OK; |
| } |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG WINAPI IHlinkBC_fnAddRef (IHlinkBrowseContext* iface) |
| { |
| HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface); |
| ULONG refCount = InterlockedIncrement(&This->ref); |
| |
| TRACE("(%p)->(count=%u)\n", This, refCount - 1); |
| |
| return refCount; |
| } |
| |
| static ULONG WINAPI IHlinkBC_fnRelease (IHlinkBrowseContext* iface) |
| { |
| HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface); |
| ULONG ref = InterlockedDecrement(&This->ref); |
| |
| TRACE("(%p)->(count=%u)\n", This, ref + 1); |
| |
| if (!ref) |
| { |
| struct link_entry *link, *link2; |
| |
| LIST_FOR_EACH_ENTRY_SAFE(link, link2, &This->links, struct link_entry, entry) |
| { |
| list_remove(&link->entry); |
| IHlink_Release(link->link); |
| heap_free(link); |
| } |
| |
| heap_free(This->BrowseWindowInfo); |
| heap_free(This); |
| } |
| |
| return ref; |
| } |
| |
| static HRESULT WINAPI IHlinkBC_Register(IHlinkBrowseContext* iface, |
| DWORD dwReserved, IUnknown *piunk, IMoniker *pimk, DWORD *pdwRegister) |
| { |
| static const WCHAR szIdent[] = {'W','I','N','E','H','L','I','N','K',0}; |
| HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface); |
| IMoniker *mon; |
| IMoniker *composite; |
| IRunningObjectTable *ROT; |
| |
| FIXME("(%p)->(%i %p %p %p)\n", This, dwReserved, piunk, pimk, pdwRegister); |
| |
| CreateItemMoniker(NULL, szIdent, &mon); |
| CreateGenericComposite(mon, pimk, &composite); |
| |
| GetRunningObjectTable(0, &ROT); |
| IRunningObjectTable_Register(ROT, 0, piunk, composite, pdwRegister); |
| |
| IRunningObjectTable_Release(ROT); |
| IMoniker_Release(composite); |
| IMoniker_Release(mon); |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI IHlinkBC_GetObject(IHlinkBrowseContext* face, |
| IMoniker *pimk, BOOL fBindifRootRegistered, IUnknown **ppiunk) |
| { |
| FIXME("\n"); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI IHlinkBC_Revoke(IHlinkBrowseContext* iface, |
| DWORD dwRegister) |
| { |
| HRESULT r; |
| IRunningObjectTable *ROT; |
| HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface); |
| |
| FIXME("(%p)->(%i)\n", This, dwRegister); |
| |
| GetRunningObjectTable(0, &ROT); |
| r = IRunningObjectTable_Revoke(ROT, dwRegister); |
| IRunningObjectTable_Release(ROT); |
| |
| return r; |
| } |
| |
| static HRESULT WINAPI IHlinkBC_SetBrowseWindowInfo(IHlinkBrowseContext* iface, |
| HLBWINFO *phlbwi) |
| { |
| HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface); |
| TRACE("(%p)->(%p)\n", This, phlbwi); |
| |
| if(!phlbwi) |
| return E_INVALIDARG; |
| |
| heap_free(This->BrowseWindowInfo); |
| This->BrowseWindowInfo = heap_alloc(phlbwi->cbSize); |
| memcpy(This->BrowseWindowInfo, phlbwi, phlbwi->cbSize); |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI IHlinkBC_GetBrowseWindowInfo(IHlinkBrowseContext* iface, |
| HLBWINFO *phlbwi) |
| { |
| HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface); |
| TRACE("(%p)->(%p)\n", This, phlbwi); |
| |
| if(!phlbwi) |
| return E_INVALIDARG; |
| |
| if(!This->BrowseWindowInfo) |
| phlbwi->cbSize = 0; |
| else |
| memcpy(phlbwi, This->BrowseWindowInfo, This->BrowseWindowInfo->cbSize); |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI IHlinkBC_SetInitialHlink(IHlinkBrowseContext* iface, |
| IMoniker *pimkTarget, LPCWSTR pwzLocation, LPCWSTR pwzFriendlyName) |
| { |
| HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface); |
| struct link_entry *link; |
| |
| TRACE("(%p)->(%p %s %s)\n", This, pimkTarget, debugstr_w(pwzLocation), debugstr_w(pwzFriendlyName)); |
| |
| if (!list_empty(&This->links)) |
| return CO_E_ALREADYINITIALIZED; |
| |
| link = heap_alloc(sizeof(struct link_entry)); |
| if (!link) return E_OUTOFMEMORY; |
| |
| HlinkCreateFromMoniker(pimkTarget, pwzLocation, pwzFriendlyName, NULL, |
| 0, NULL, &IID_IHlink, (void**)&link->link); |
| |
| list_add_head(&This->links, &link->entry); |
| This->current = LIST_ENTRY(list_head(&This->links), struct link_entry, entry); |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI IHlinkBC_OnNavigateHlink(IHlinkBrowseContext *iface, |
| DWORD grfHLNF, IMoniker* pmkTarget, LPCWSTR pwzLocation, LPCWSTR |
| pwzFriendlyName, ULONG *puHLID) |
| { |
| HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface); |
| |
| FIXME("(%p)->(%i %p %s %s %p)\n", This, grfHLNF, pmkTarget, |
| debugstr_w(pwzLocation), debugstr_w(pwzFriendlyName), puHLID); |
| |
| return S_OK; |
| } |
| |
| static struct link_entry *context_get_entry(HlinkBCImpl *ctxt, ULONG hlid) |
| { |
| struct list *entry; |
| |
| switch (hlid) |
| { |
| case HLID_PREVIOUS: |
| entry = list_prev(&ctxt->links, &ctxt->current->entry); |
| break; |
| case HLID_NEXT: |
| entry = list_next(&ctxt->links, &ctxt->current->entry); |
| break; |
| case HLID_CURRENT: |
| entry = &ctxt->current->entry; |
| break; |
| case HLID_STACKBOTTOM: |
| entry = list_tail(&ctxt->links); |
| break; |
| case HLID_STACKTOP: |
| entry = list_head(&ctxt->links); |
| break; |
| default: |
| WARN("unknown id 0x%x\n", hlid); |
| entry = NULL; |
| } |
| |
| return entry ? LIST_ENTRY(entry, struct link_entry, entry) : NULL; |
| } |
| |
| static HRESULT WINAPI IHlinkBC_UpdateHlink(IHlinkBrowseContext* iface, |
| ULONG hlid, IMoniker *target, LPCWSTR location, LPCWSTR friendly_name) |
| { |
| HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface); |
| struct link_entry *entry = context_get_entry(This, hlid); |
| IHlink *link; |
| HRESULT hr; |
| |
| TRACE("(%p)->(0x%x %p %s %s)\n", This, hlid, target, debugstr_w(location), debugstr_w(friendly_name)); |
| |
| if (!entry) |
| return E_INVALIDARG; |
| |
| hr = HlinkCreateFromMoniker(target, location, friendly_name, NULL, 0, NULL, &IID_IHlink, (void**)&link); |
| if (FAILED(hr)) |
| return hr; |
| |
| IHlink_Release(entry->link); |
| entry->link = link; |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI IHlinkBC_EnumNavigationStack( IHlinkBrowseContext *iface, |
| DWORD dwReserved, DWORD grfHLFNAMEF, IEnumHLITEM** ppienumhlitem) |
| { |
| FIXME("\n"); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI IHlinkBC_QueryHlink( IHlinkBrowseContext* iface, |
| DWORD grfHLONG, ULONG uHLID) |
| { |
| FIXME("\n"); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI IHlinkBC_GetHlink(IHlinkBrowseContext* iface, ULONG hlid, IHlink **ret) |
| { |
| HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface); |
| struct link_entry *link; |
| |
| TRACE("(%p)->(0x%x %p)\n", This, hlid, ret); |
| |
| link = context_get_entry(This, hlid); |
| if (!link) |
| return E_FAIL; |
| |
| *ret = link->link; |
| IHlink_AddRef(*ret); |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI IHlinkBC_SetCurrentHlink(IHlinkBrowseContext* iface, ULONG hlid) |
| { |
| HlinkBCImpl *This = impl_from_IHlinkBrowseContext(iface); |
| struct link_entry *link; |
| |
| TRACE("(%p)->(0x%08x)\n", This, hlid); |
| |
| link = context_get_entry(This, hlid); |
| if (!link) |
| return E_FAIL; |
| |
| This->current = link; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI IHlinkBC_Clone( IHlinkBrowseContext* iface, |
| IUnknown* piunkOuter, REFIID riid, IUnknown** ppiunkOjb) |
| { |
| FIXME("\n"); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI IHlinkBC_Close(IHlinkBrowseContext* iface, |
| DWORD reserved) |
| { |
| FIXME("\n"); |
| return E_NOTIMPL; |
| } |
| |
| static const IHlinkBrowseContextVtbl hlvt = |
| { |
| IHlinkBC_fnQueryInterface, |
| IHlinkBC_fnAddRef, |
| IHlinkBC_fnRelease, |
| IHlinkBC_Register, |
| IHlinkBC_GetObject, |
| IHlinkBC_Revoke, |
| IHlinkBC_SetBrowseWindowInfo, |
| IHlinkBC_GetBrowseWindowInfo, |
| IHlinkBC_SetInitialHlink, |
| IHlinkBC_OnNavigateHlink, |
| IHlinkBC_UpdateHlink, |
| IHlinkBC_EnumNavigationStack, |
| IHlinkBC_QueryHlink, |
| IHlinkBC_GetHlink, |
| IHlinkBC_SetCurrentHlink, |
| IHlinkBC_Clone, |
| IHlinkBC_Close |
| }; |
| |
| HRESULT HLinkBrowseContext_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv) |
| { |
| HlinkBCImpl * hl; |
| |
| TRACE("unkOut=%p riid=%s\n", pUnkOuter, debugstr_guid(riid)); |
| *ppv = NULL; |
| |
| if (pUnkOuter) |
| return CLASS_E_NOAGGREGATION; |
| |
| hl = heap_alloc_zero(sizeof(HlinkBCImpl)); |
| if (!hl) |
| return E_OUTOFMEMORY; |
| |
| hl->ref = 1; |
| hl->IHlinkBrowseContext_iface.lpVtbl = &hlvt; |
| list_init(&hl->links); |
| hl->current = NULL; |
| |
| *ppv = hl; |
| return S_OK; |
| } |