| /* | |
| * 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 "shellapi.h" | |
| #include "hlguids.h" | |
| #include "wine/debug.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(hlink); | |
| #define HLINK_SAVE_MAGIC 0x00000002 | |
| #define HLINK_SAVE_MONIKER_PRESENT 0x01 | |
| #define HLINK_SAVE_MONIKER_IS_ABSOLUTE 0x02 | |
| #define HLINK_SAVE_LOCATION_PRESENT 0x08 | |
| #define HLINK_SAVE_FRIENDLY_PRESENT 0x10 | |
| /* 0x20, 0x40 unknown */ | |
| #define HLINK_SAVE_TARGET_FRAME_PRESENT 0x80 | |
| /* known flags */ | |
| #define HLINK_SAVE_ALL (HLINK_SAVE_TARGET_FRAME_PRESENT|HLINK_SAVE_FRIENDLY_PRESENT|HLINK_SAVE_LOCATION_PRESENT|0x04|HLINK_SAVE_MONIKER_IS_ABSOLUTE|HLINK_SAVE_MONIKER_PRESENT) | |
| static const IHlinkVtbl hlvt; | |
| static const IPersistStreamVtbl psvt; | |
| static const IDataObjectVtbl dovt; | |
| typedef struct | |
| { | |
| const IHlinkVtbl *lpVtbl; | |
| LONG ref; | |
| const IPersistStreamVtbl *lpPSVtbl; | |
| const IDataObjectVtbl *lpDOVtbl; | |
| LPWSTR FriendlyName; | |
| LPWSTR Location; | |
| LPWSTR TargetFrameName; | |
| IMoniker *Moniker; | |
| IHlinkSite *Site; | |
| DWORD SiteData; | |
| BOOL absolute; | |
| } HlinkImpl; | |
| static inline HlinkImpl* HlinkImpl_from_IPersistStream( IPersistStream* iface) | |
| { | |
| return (HlinkImpl*) ((CHAR*)iface - FIELD_OFFSET(HlinkImpl, lpPSVtbl)); | |
| } | |
| static inline HlinkImpl* HlinkImpl_from_IDataObject( IDataObject* iface) | |
| { | |
| return (HlinkImpl*) ((CHAR*)iface - FIELD_OFFSET(HlinkImpl, lpDOVtbl)); | |
| } | |
| static inline void __GetMoniker(HlinkImpl* This, IMoniker** moniker) | |
| { | |
| *moniker = NULL; | |
| if (This->Moniker) | |
| { | |
| *moniker = This->Moniker; | |
| if (*moniker) | |
| IMoniker_AddRef(*moniker); | |
| } | |
| else if (This->Site) | |
| { | |
| IHlinkSite_GetMoniker(This->Site, This->SiteData, | |
| OLEGETMONIKER_FORCEASSIGN, OLEWHICHMK_CONTAINER, moniker); | |
| } | |
| } | |
| HRESULT WINAPI HLink_Constructor(IUnknown *pUnkOuter, REFIID riid, | |
| LPVOID *ppv) | |
| { | |
| HlinkImpl * hl; | |
| TRACE("unkOut=%p riid=%s\n", pUnkOuter, debugstr_guid(riid)); | |
| *ppv = NULL; | |
| if (pUnkOuter) | |
| return CLASS_E_NOAGGREGATION; | |
| hl = heap_alloc_zero(sizeof(HlinkImpl)); | |
| if (!hl) | |
| return E_OUTOFMEMORY; | |
| hl->ref = 1; | |
| hl->lpVtbl = &hlvt; | |
| hl->lpPSVtbl = &psvt; | |
| hl->lpDOVtbl = &dovt; | |
| *ppv = hl; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI IHlink_fnQueryInterface(IHlink* iface, REFIID riid, | |
| LPVOID *ppvObj) | |
| { | |
| HlinkImpl *This = (HlinkImpl*)iface; | |
| TRACE ("(%p)->(%s,%p)\n", This, debugstr_guid (riid), ppvObj); | |
| *ppvObj = NULL; | |
| if (IsEqualIID(riid, &IID_IUnknown) || (IsEqualIID(riid, &IID_IHlink))) | |
| *ppvObj = This; | |
| else if (IsEqualIID(riid, &IID_IPersistStream)) | |
| *ppvObj = &(This->lpPSVtbl); | |
| else if (IsEqualIID(riid, &IID_IDataObject)) | |
| *ppvObj = &(This->lpDOVtbl); | |
| if (*ppvObj) | |
| { | |
| IUnknown_AddRef((IUnknown*)(*ppvObj)); | |
| return S_OK; | |
| } | |
| return E_NOINTERFACE; | |
| } | |
| static ULONG WINAPI IHlink_fnAddRef (IHlink* iface) | |
| { | |
| HlinkImpl *This = (HlinkImpl*)iface; | |
| ULONG refCount = InterlockedIncrement(&This->ref); | |
| TRACE("(%p)->(count=%u)\n", This, refCount - 1); | |
| return refCount; | |
| } | |
| static ULONG WINAPI IHlink_fnRelease (IHlink* iface) | |
| { | |
| HlinkImpl *This = (HlinkImpl*)iface; | |
| ULONG refCount = InterlockedDecrement(&This->ref); | |
| TRACE("(%p)->(count=%u)\n", This, refCount + 1); | |
| if (refCount) | |
| return refCount; | |
| TRACE("-- destroying IHlink (%p)\n", This); | |
| heap_free(This->FriendlyName); | |
| heap_free(This->TargetFrameName); | |
| heap_free(This->Location); | |
| if (This->Moniker) | |
| IMoniker_Release(This->Moniker); | |
| if (This->Site) | |
| IHlinkSite_Release(This->Site); | |
| heap_free(This); | |
| return 0; | |
| } | |
| static HRESULT WINAPI IHlink_fnSetHlinkSite( IHlink* iface, | |
| IHlinkSite* pihlSite, DWORD dwSiteData) | |
| { | |
| HlinkImpl *This = (HlinkImpl*)iface; | |
| TRACE("(%p)->(%p %i)\n", This, pihlSite, dwSiteData); | |
| if (This->Site) | |
| IHlinkSite_Release(This->Site); | |
| This->Site = pihlSite; | |
| if (This->Site) | |
| IHlinkSite_AddRef(This->Site); | |
| This->SiteData = dwSiteData; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI IHlink_fnGetHlinkSite( IHlink* iface, | |
| IHlinkSite** ppihlSite, DWORD *pdwSiteData) | |
| { | |
| HlinkImpl *This = (HlinkImpl*)iface; | |
| TRACE("(%p)->(%p %p)\n", This, ppihlSite, pdwSiteData); | |
| *ppihlSite = This->Site; | |
| *pdwSiteData = This->SiteData; | |
| if (This->Site) | |
| IHlinkSite_AddRef(This->Site); | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI IHlink_fnSetMonikerReference( IHlink* iface, | |
| DWORD rfHLSETF, IMoniker *pmkTarget, LPCWSTR pwzLocation) | |
| { | |
| HlinkImpl *This = (HlinkImpl*)iface; | |
| TRACE("(%p)->(%i %p %s)\n", This, rfHLSETF, pmkTarget, | |
| debugstr_w(pwzLocation)); | |
| if(rfHLSETF == 0) | |
| return E_INVALIDARG; | |
| if(!(rfHLSETF & (HLINKSETF_TARGET | HLINKSETF_LOCATION))) | |
| return rfHLSETF; | |
| if(rfHLSETF & HLINKSETF_TARGET){ | |
| if (This->Moniker) | |
| IMoniker_Release(This->Moniker); | |
| This->Moniker = pmkTarget; | |
| if (This->Moniker) | |
| { | |
| LPOLESTR display_name; | |
| IMoniker_AddRef(This->Moniker); | |
| IMoniker_GetDisplayName(This->Moniker, NULL, NULL, &display_name); | |
| This->absolute = display_name && strchrW(display_name, ':'); | |
| CoTaskMemFree(display_name); | |
| } | |
| } | |
| if(rfHLSETF & HLINKSETF_LOCATION){ | |
| heap_free(This->Location); | |
| This->Location = hlink_strdupW( pwzLocation ); | |
| } | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI IHlink_fnSetStringReference(IHlink* iface, | |
| DWORD grfHLSETF, LPCWSTR pwzTarget, LPCWSTR pwzLocation) | |
| { | |
| HlinkImpl *This = (HlinkImpl*)iface; | |
| TRACE("(%p)->(%i %s %s)\n", This, grfHLSETF, debugstr_w(pwzTarget), | |
| debugstr_w(pwzLocation)); | |
| if(grfHLSETF > (HLINKSETF_TARGET | HLINKSETF_LOCATION) && | |
| grfHLSETF < -(HLINKSETF_TARGET | HLINKSETF_LOCATION)) | |
| return grfHLSETF; | |
| if (grfHLSETF & HLINKSETF_TARGET) | |
| { | |
| if (This->Moniker) | |
| { | |
| IMoniker_Release(This->Moniker); | |
| This->Moniker = NULL; | |
| } | |
| if (pwzTarget && *pwzTarget) | |
| { | |
| IMoniker *pMon; | |
| IBindCtx *pbc = NULL; | |
| ULONG eaten; | |
| HRESULT r; | |
| r = CreateBindCtx(0, &pbc); | |
| if (FAILED(r)) | |
| return E_OUTOFMEMORY; | |
| r = MkParseDisplayName(pbc, pwzTarget, &eaten, &pMon); | |
| IBindCtx_Release(pbc); | |
| if (FAILED(r)) | |
| { | |
| LPCWSTR p = strchrW(pwzTarget, ':'); | |
| if (p && (p - pwzTarget > 1)) | |
| r = CreateURLMoniker(NULL, pwzTarget, &pMon); | |
| else | |
| r = CreateFileMoniker(pwzTarget, &pMon); | |
| if (FAILED(r)) | |
| { | |
| ERR("couldn't create moniker for %s, failed with error 0x%08x\n", | |
| debugstr_w(pwzTarget), r); | |
| return r; | |
| } | |
| } | |
| IHlink_SetMonikerReference(iface, HLINKSETF_TARGET, pMon, NULL); | |
| IMoniker_Release(pMon); | |
| } | |
| } | |
| if (grfHLSETF & HLINKSETF_LOCATION) | |
| { | |
| heap_free(This->Location); | |
| This->Location = hlink_strdupW( pwzLocation ); | |
| } | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI IHlink_fnGetMonikerReference(IHlink* iface, | |
| DWORD dwWhichRef, IMoniker **ppimkTarget, LPWSTR *ppwzLocation) | |
| { | |
| HlinkImpl *This = (HlinkImpl*)iface; | |
| TRACE("(%p) -> (%i %p %p)\n", This, dwWhichRef, ppimkTarget, | |
| ppwzLocation); | |
| if(ppimkTarget) | |
| __GetMoniker(This, ppimkTarget); | |
| if (ppwzLocation) | |
| IHlink_GetStringReference(iface, dwWhichRef, NULL, ppwzLocation); | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI IHlink_fnGetStringReference (IHlink* iface, | |
| DWORD dwWhichRef, LPWSTR *ppwzTarget, LPWSTR *ppwzLocation) | |
| { | |
| HlinkImpl *This = (HlinkImpl*)iface; | |
| TRACE("(%p) -> (%i %p %p)\n", This, dwWhichRef, ppwzTarget, ppwzLocation); | |
| /* note: undocumented behavior with dwWhichRef == -1 */ | |
| if(dwWhichRef != -1 && dwWhichRef & ~(HLINKGETREF_DEFAULT | HLINKGETREF_ABSOLUTE | HLINKGETREF_RELATIVE)) | |
| { | |
| if(ppwzTarget) | |
| *ppwzTarget = NULL; | |
| if(ppwzLocation) | |
| *ppwzLocation = NULL; | |
| return E_INVALIDARG; | |
| } | |
| if(dwWhichRef != HLINKGETREF_DEFAULT) | |
| FIXME("unhandled flags: 0x%x\n", dwWhichRef); | |
| if (ppwzTarget) | |
| { | |
| IMoniker* mon; | |
| __GetMoniker(This, &mon); | |
| if (mon) | |
| { | |
| IBindCtx *pbc; | |
| CreateBindCtx( 0, &pbc); | |
| IMoniker_GetDisplayName(mon, pbc, NULL, ppwzTarget); | |
| IBindCtx_Release(pbc); | |
| IMoniker_Release(mon); | |
| } | |
| else | |
| *ppwzTarget = NULL; | |
| } | |
| if (ppwzLocation) | |
| *ppwzLocation = hlink_co_strdupW( This->Location ); | |
| TRACE("(Target: %s Location: %s)\n", | |
| (ppwzTarget)?debugstr_w(*ppwzTarget):"<NULL>", | |
| (ppwzLocation)?debugstr_w(*ppwzLocation):"<NULL>"); | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI IHlink_fnSetFriendlyName (IHlink *iface, | |
| LPCWSTR pwzFriendlyName) | |
| { | |
| HlinkImpl *This = (HlinkImpl*)iface; | |
| TRACE("(%p) -> (%s)\n", This, debugstr_w(pwzFriendlyName)); | |
| heap_free(This->FriendlyName); | |
| This->FriendlyName = hlink_strdupW( pwzFriendlyName ); | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI IHlink_fnGetFriendlyName (IHlink* iface, | |
| DWORD grfHLFNAMEF, LPWSTR* ppwzFriendlyName) | |
| { | |
| HlinkImpl *This = (HlinkImpl*)iface; | |
| TRACE("(%p) -> (%i %p)\n", This, grfHLFNAMEF, ppwzFriendlyName); | |
| /* FIXME: Only using explicitly set and cached friendly names */ | |
| if (This->FriendlyName) | |
| *ppwzFriendlyName = hlink_co_strdupW( This->FriendlyName ); | |
| else | |
| { | |
| IMoniker *moniker; | |
| __GetMoniker(This, &moniker); | |
| if (moniker) | |
| { | |
| IBindCtx *bcxt; | |
| CreateBindCtx(0, &bcxt); | |
| IMoniker_GetDisplayName(moniker, bcxt, NULL, ppwzFriendlyName); | |
| IBindCtx_Release(bcxt); | |
| IMoniker_Release(moniker); | |
| } | |
| else | |
| *ppwzFriendlyName = NULL; | |
| } | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI IHlink_fnSetTargetFrameName(IHlink* iface, | |
| LPCWSTR pwzTargetFramename) | |
| { | |
| HlinkImpl *This = (HlinkImpl*)iface; | |
| TRACE("(%p)->(%s)\n", This, debugstr_w(pwzTargetFramename)); | |
| heap_free(This->TargetFrameName); | |
| This->TargetFrameName = hlink_strdupW( pwzTargetFramename ); | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI IHlink_fnGetTargetFrameName(IHlink* iface, | |
| LPWSTR *ppwzTargetFrameName) | |
| { | |
| HlinkImpl *This = (HlinkImpl*)iface; | |
| TRACE("(%p)->(%p)\n", This, ppwzTargetFrameName); | |
| *ppwzTargetFrameName = hlink_co_strdupW( This->TargetFrameName ); | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI IHlink_fnGetMiscStatus(IHlink* iface, DWORD* pdwStatus) | |
| { | |
| FIXME("\n"); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI IHlink_fnNavigate(IHlink* iface, DWORD grfHLNF, LPBC pbc, | |
| IBindStatusCallback *pbsc, IHlinkBrowseContext *phbc) | |
| { | |
| HlinkImpl *This = (HlinkImpl*)iface; | |
| IMoniker *mon = NULL; | |
| FIXME("Semi-Stub:(%p)->(%i %p %p %p)\n", This, grfHLNF, pbc, pbsc, phbc); | |
| if (This->Site) | |
| IHlinkSite_ReadyToNavigate(This->Site, This->SiteData, 0); | |
| __GetMoniker(This, &mon); | |
| TRACE("Moniker %p\n", mon); | |
| if (mon) | |
| { | |
| IBindCtx *bcxt; | |
| IHlinkTarget *target = NULL; | |
| HRESULT r = S_OK; | |
| CreateBindCtx(0, &bcxt); | |
| RegisterBindStatusCallback(bcxt, pbsc, NULL, 0); | |
| r = IMoniker_BindToObject(mon, bcxt, NULL, &IID_IHlinkTarget, | |
| (LPVOID*)&target); | |
| TRACE("IHlinkTarget returned 0x%x\n", r); | |
| if (r == S_OK) | |
| { | |
| IHlinkTarget_SetBrowseContext(target, phbc); | |
| IHlinkTarget_Navigate(target, grfHLNF, This->Location); | |
| IHlinkTarget_Release(target); | |
| } | |
| else | |
| { | |
| static const WCHAR szOpen[] = {'o','p','e','n',0}; | |
| LPWSTR target = NULL; | |
| r = IHlink_GetStringReference(iface, HLINKGETREF_DEFAULT, &target, NULL); | |
| if (SUCCEEDED(r) && target) | |
| { | |
| ShellExecuteW(NULL, szOpen, target, NULL, NULL, SW_SHOW); | |
| CoTaskMemFree(target); | |
| } | |
| } | |
| RevokeBindStatusCallback(bcxt, pbsc); | |
| IBindCtx_Release(bcxt); | |
| IMoniker_Release(mon); | |
| } | |
| if (This->Site) | |
| IHlinkSite_OnNavigationComplete(This->Site, This->SiteData, 0, 0, NULL); | |
| TRACE("Finished Navigation\n"); | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI IHlink_fnSetAdditonalParams(IHlink* iface, | |
| LPCWSTR pwzAdditionalParams) | |
| { | |
| TRACE("Not implemented in native IHlink\n"); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI IHlink_fnGetAdditionalParams(IHlink* iface, | |
| LPWSTR* ppwzAdditionalParams) | |
| { | |
| TRACE("Not implemented in native IHlink\n"); | |
| return E_NOTIMPL; | |
| } | |
| static const IHlinkVtbl hlvt = | |
| { | |
| IHlink_fnQueryInterface, | |
| IHlink_fnAddRef, | |
| IHlink_fnRelease, | |
| IHlink_fnSetHlinkSite, | |
| IHlink_fnGetHlinkSite, | |
| IHlink_fnSetMonikerReference, | |
| IHlink_fnGetMonikerReference, | |
| IHlink_fnSetStringReference, | |
| IHlink_fnGetStringReference, | |
| IHlink_fnSetFriendlyName, | |
| IHlink_fnGetFriendlyName, | |
| IHlink_fnSetTargetFrameName, | |
| IHlink_fnGetTargetFrameName, | |
| IHlink_fnGetMiscStatus, | |
| IHlink_fnNavigate, | |
| IHlink_fnSetAdditonalParams, | |
| IHlink_fnGetAdditionalParams | |
| }; | |
| static HRESULT WINAPI IDataObject_fnQueryInterface(IDataObject* iface, | |
| REFIID riid, LPVOID *ppvObj) | |
| { | |
| HlinkImpl *This = HlinkImpl_from_IDataObject(iface); | |
| TRACE("%p\n", This); | |
| return IHlink_QueryInterface((IHlink*)This, riid, ppvObj); | |
| } | |
| static ULONG WINAPI IDataObject_fnAddRef (IDataObject* iface) | |
| { | |
| HlinkImpl *This = HlinkImpl_from_IDataObject(iface); | |
| TRACE("%p\n", This); | |
| return IHlink_AddRef((IHlink*)This); | |
| } | |
| static ULONG WINAPI IDataObject_fnRelease (IDataObject* iface) | |
| { | |
| HlinkImpl *This = HlinkImpl_from_IDataObject(iface); | |
| TRACE("%p\n", This); | |
| return IHlink_Release((IHlink*)This); | |
| } | |
| static HRESULT WINAPI IDataObject_fnGetData(IDataObject* iface, | |
| FORMATETC* pformatetcIn, STGMEDIUM* pmedium) | |
| { | |
| FIXME("\n"); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI IDataObject_fnGetDataHere(IDataObject* iface, | |
| FORMATETC* pformatetc, STGMEDIUM* pmedium) | |
| { | |
| FIXME("\n"); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI IDataObject_fnQueryGetData(IDataObject* iface, | |
| FORMATETC* pformatetc) | |
| { | |
| FIXME("\n"); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI IDataObject_fnGetConicalFormatEtc(IDataObject* iface, | |
| FORMATETC* pformatetcIn, FORMATETC* pformatetcOut) | |
| { | |
| FIXME("\n"); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI IDataObject_fnSetData(IDataObject* iface, | |
| FORMATETC* pformatetc, STGMEDIUM* pmedium, BOOL fRelease) | |
| { | |
| FIXME("\n"); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI IDataObject_fnEnumFormatEtc(IDataObject* iface, | |
| DWORD dwDirection, IEnumFORMATETC** ppenumFormatEtc) | |
| { | |
| FIXME("\n"); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI IDataObject_fnDAdvise(IDataObject* iface, | |
| FORMATETC* pformatetc, DWORD advf, IAdviseSink* pAdvSink, | |
| DWORD* pdwConnection) | |
| { | |
| FIXME("\n"); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI IDataObject_fnDUnadvise(IDataObject* iface, | |
| DWORD dwConnection) | |
| { | |
| FIXME("\n"); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI IDataObject_fnEnumDAdvise(IDataObject* iface, | |
| IEnumSTATDATA** ppenumAdvise) | |
| { | |
| FIXME("\n"); | |
| return E_NOTIMPL; | |
| } | |
| static const IDataObjectVtbl dovt = | |
| { | |
| IDataObject_fnQueryInterface, | |
| IDataObject_fnAddRef, | |
| IDataObject_fnRelease, | |
| IDataObject_fnGetData, | |
| IDataObject_fnGetDataHere, | |
| IDataObject_fnQueryGetData, | |
| IDataObject_fnGetConicalFormatEtc, | |
| IDataObject_fnSetData, | |
| IDataObject_fnEnumFormatEtc, | |
| IDataObject_fnDAdvise, | |
| IDataObject_fnDUnadvise, | |
| IDataObject_fnEnumDAdvise | |
| }; | |
| static HRESULT WINAPI IPersistStream_fnQueryInterface(IPersistStream* iface, | |
| REFIID riid, LPVOID *ppvObj) | |
| { | |
| HlinkImpl *This = HlinkImpl_from_IPersistStream(iface); | |
| TRACE("(%p)\n", This); | |
| return IHlink_QueryInterface((IHlink*)This, riid, ppvObj); | |
| } | |
| static ULONG WINAPI IPersistStream_fnAddRef (IPersistStream* iface) | |
| { | |
| HlinkImpl *This = HlinkImpl_from_IPersistStream(iface); | |
| TRACE("(%p)\n", This); | |
| return IHlink_AddRef((IHlink*)This); | |
| } | |
| static ULONG WINAPI IPersistStream_fnRelease (IPersistStream* iface) | |
| { | |
| HlinkImpl *This = HlinkImpl_from_IPersistStream(iface); | |
| TRACE("(%p)\n", This); | |
| return IHlink_Release((IHlink*)This); | |
| } | |
| static HRESULT WINAPI IPersistStream_fnGetClassID(IPersistStream* iface, | |
| CLSID* pClassID) | |
| { | |
| HlinkImpl *This = HlinkImpl_from_IPersistStream(iface); | |
| TRACE("(%p)\n", This); | |
| *pClassID = CLSID_StdHlink; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI IPersistStream_fnIsDirty(IPersistStream* iface) | |
| { | |
| FIXME("\n"); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT write_hlink_string(IStream *pStm, LPCWSTR str) | |
| { | |
| DWORD len; | |
| HRESULT hr; | |
| TRACE("(%p, %s)\n", pStm, debugstr_w(str)); | |
| len = strlenW(str) + 1; | |
| hr = IStream_Write(pStm, &len, sizeof(len), NULL); | |
| if (FAILED(hr)) return hr; | |
| hr = IStream_Write(pStm, str, len * sizeof(WCHAR), NULL); | |
| if (FAILED(hr)) return hr; | |
| return S_OK; | |
| } | |
| static inline ULONG size_hlink_string(LPCWSTR str) | |
| { | |
| return sizeof(DWORD) + (strlenW(str) + 1) * sizeof(WCHAR); | |
| } | |
| static HRESULT read_hlink_string(IStream *pStm, LPWSTR *out_str) | |
| { | |
| LPWSTR str; | |
| DWORD len; | |
| ULONG read; | |
| HRESULT hr; | |
| hr = IStream_Read(pStm, &len, sizeof(len), &read); | |
| if (FAILED(hr)) return hr; | |
| if (read != sizeof(len)) return STG_E_READFAULT; | |
| TRACE("read len %d\n", len); | |
| str = heap_alloc(len * sizeof(WCHAR)); | |
| if (!str) return E_OUTOFMEMORY; | |
| hr = IStream_Read(pStm, str, len * sizeof(WCHAR), &read); | |
| if (FAILED(hr)) | |
| { | |
| heap_free(str); | |
| return hr; | |
| } | |
| if (read != len * sizeof(WCHAR)) | |
| { | |
| heap_free(str); | |
| return STG_E_READFAULT; | |
| } | |
| TRACE("read string %s\n", debugstr_w(str)); | |
| *out_str = str; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI IPersistStream_fnLoad(IPersistStream* iface, | |
| IStream* pStm) | |
| { | |
| HRESULT r; | |
| DWORD hdr[2]; | |
| DWORD read; | |
| HlinkImpl *This = HlinkImpl_from_IPersistStream(iface); | |
| r = IStream_Read(pStm, hdr, sizeof(hdr), &read); | |
| if (read != sizeof(hdr) || (hdr[0] != HLINK_SAVE_MAGIC)) | |
| { | |
| r = E_FAIL; | |
| goto end; | |
| } | |
| if (hdr[1] & ~HLINK_SAVE_ALL) | |
| FIXME("unknown flag(s) 0x%x\n", hdr[1] & ~HLINK_SAVE_ALL); | |
| if (hdr[1] & HLINK_SAVE_TARGET_FRAME_PRESENT) | |
| { | |
| TRACE("loading target frame name\n"); | |
| r = read_hlink_string(pStm, &This->TargetFrameName); | |
| if (FAILED(r)) goto end; | |
| } | |
| if (hdr[1] & HLINK_SAVE_FRIENDLY_PRESENT) | |
| { | |
| TRACE("loading target friendly name\n"); | |
| if (!(hdr[1] & 0x4)) | |
| FIXME("0x4 flag not present with friendly name flag - not sure what this means\n"); | |
| r = read_hlink_string(pStm, &This->FriendlyName); | |
| if (FAILED(r)) goto end; | |
| } | |
| if (hdr[1] & HLINK_SAVE_MONIKER_PRESENT) | |
| { | |
| TRACE("loading moniker\n"); | |
| r = OleLoadFromStream(pStm, &IID_IMoniker, (LPVOID*)&(This->Moniker)); | |
| if (FAILED(r)) | |
| goto end; | |
| This->absolute = hdr[1] & HLINK_SAVE_MONIKER_IS_ABSOLUTE ? TRUE : FALSE; | |
| } | |
| if (hdr[1] & HLINK_SAVE_LOCATION_PRESENT) | |
| { | |
| TRACE("loading location\n"); | |
| r = read_hlink_string(pStm, &This->Location); | |
| if (FAILED(r)) goto end; | |
| } | |
| end: | |
| TRACE("Load Result 0x%x (%p)\n", r, This->Moniker); | |
| return r; | |
| } | |
| static HRESULT WINAPI IPersistStream_fnSave(IPersistStream* iface, | |
| IStream* pStm, BOOL fClearDirty) | |
| { | |
| HRESULT r = E_FAIL; | |
| HlinkImpl *This = HlinkImpl_from_IPersistStream(iface); | |
| DWORD hdr[2]; | |
| IMoniker *moniker; | |
| TRACE("(%p) Moniker(%p)\n", This, This->Moniker); | |
| __GetMoniker(This, &moniker); | |
| hdr[0] = HLINK_SAVE_MAGIC; | |
| hdr[1] = 0; | |
| if (moniker) | |
| hdr[1] |= HLINK_SAVE_MONIKER_PRESENT; | |
| if (This->absolute) | |
| hdr[1] |= HLINK_SAVE_MONIKER_IS_ABSOLUTE; | |
| if (This->Location) | |
| hdr[1] |= HLINK_SAVE_LOCATION_PRESENT; | |
| if (This->FriendlyName) | |
| hdr[1] |= HLINK_SAVE_FRIENDLY_PRESENT | 4 /* FIXME */; | |
| if (This->TargetFrameName) | |
| hdr[1] |= HLINK_SAVE_TARGET_FRAME_PRESENT; | |
| IStream_Write(pStm, hdr, sizeof(hdr), NULL); | |
| if (This->TargetFrameName) | |
| { | |
| r = write_hlink_string(pStm, This->TargetFrameName); | |
| if (FAILED(r)) goto end; | |
| } | |
| if (This->FriendlyName) | |
| { | |
| r = write_hlink_string(pStm, This->FriendlyName); | |
| if (FAILED(r)) goto end; | |
| } | |
| if (moniker) | |
| { | |
| IPersistStream* monstream; | |
| monstream = NULL; | |
| IMoniker_QueryInterface(moniker, &IID_IPersistStream, | |
| (LPVOID*)&monstream); | |
| if (monstream) | |
| { | |
| r = OleSaveToStream(monstream, pStm); | |
| IPersistStream_Release(monstream); | |
| } | |
| if (FAILED(r)) goto end; | |
| } | |
| if (This->Location) | |
| { | |
| r = write_hlink_string(pStm, This->Location); | |
| if (FAILED(r)) goto end; | |
| } | |
| end: | |
| if (moniker) IMoniker_Release(moniker); | |
| TRACE("Save Result 0x%x\n", r); | |
| return r; | |
| } | |
| static HRESULT WINAPI IPersistStream_fnGetSizeMax(IPersistStream* iface, | |
| ULARGE_INTEGER* pcbSize) | |
| { | |
| HRESULT r = E_FAIL; | |
| HlinkImpl *This = HlinkImpl_from_IPersistStream(iface); | |
| IMoniker *moniker; | |
| TRACE("(%p) Moniker(%p)\n", This, This->Moniker); | |
| pcbSize->QuadPart = sizeof(DWORD)*2; | |
| if (This->TargetFrameName) | |
| pcbSize->QuadPart += size_hlink_string(This->TargetFrameName); | |
| if (This->FriendlyName) | |
| pcbSize->QuadPart += size_hlink_string(This->FriendlyName); | |
| __GetMoniker(This, &moniker); | |
| if (moniker) | |
| { | |
| IPersistStream* monstream = NULL; | |
| IMoniker_QueryInterface(moniker, &IID_IPersistStream, | |
| (LPVOID*)&monstream); | |
| if (monstream) | |
| { | |
| ULARGE_INTEGER mon_size; | |
| r = IPersistStream_GetSizeMax(monstream, &mon_size); | |
| pcbSize->QuadPart += mon_size.QuadPart; | |
| IPersistStream_Release(monstream); | |
| } | |
| IMoniker_Release(moniker); | |
| } | |
| if (This->Location) | |
| pcbSize->QuadPart += size_hlink_string(This->Location); | |
| return r; | |
| } | |
| static const IPersistStreamVtbl psvt = | |
| { | |
| IPersistStream_fnQueryInterface, | |
| IPersistStream_fnAddRef, | |
| IPersistStream_fnRelease, | |
| IPersistStream_fnGetClassID, | |
| IPersistStream_fnIsDirty, | |
| IPersistStream_fnLoad, | |
| IPersistStream_fnSave, | |
| IPersistStream_fnGetSizeMax, | |
| }; |