2 * Implementation of hyperlinking (hlink.dll)
4 * Copyright 2005 Aric Stewart for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "hlink_private.h"
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(hlink);
30 #define HLINK_SAVE_MAGIC 0x00000002
31 #define HLINK_SAVE_MONIKER_PRESENT 0x01
32 #define HLINK_SAVE_MONIKER_IS_ABSOLUTE 0x02
33 #define HLINK_SAVE_LOCATION_PRESENT 0x08
34 #define HLINK_SAVE_FRIENDLY_PRESENT 0x10
35 /* 0x20, 0x40 unknown */
36 #define HLINK_SAVE_TARGET_FRAME_PRESENT 0x80
38 #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)
40 static const IHlinkVtbl hlvt;
41 static const IPersistStreamVtbl psvt;
42 static const IDataObjectVtbl dovt;
46 const IHlinkVtbl *lpVtbl;
49 const IPersistStreamVtbl *lpPSVtbl;
50 const IDataObjectVtbl *lpDOVtbl;
55 LPWSTR TargetFrameName;
63 static inline HlinkImpl* HlinkImpl_from_IPersistStream( IPersistStream* iface)
65 return (HlinkImpl*) ((CHAR*)iface - FIELD_OFFSET(HlinkImpl, lpPSVtbl));
68 static inline HlinkImpl* HlinkImpl_from_IDataObject( IDataObject* iface)
70 return (HlinkImpl*) ((CHAR*)iface - FIELD_OFFSET(HlinkImpl, lpDOVtbl));
73 static inline void __GetMoniker(HlinkImpl* This, IMoniker** moniker)
78 *moniker = This->Moniker;
80 IMoniker_AddRef(*moniker);
84 IHlinkSite_GetMoniker(This->Site, This->SiteData,
85 OLEGETMONIKER_FORCEASSIGN, OLEWHICHMK_CONTAINER, moniker);
89 HRESULT WINAPI HLink_Constructor(IUnknown *pUnkOuter, REFIID riid,
94 TRACE("unkOut=%p riid=%s\n", pUnkOuter, debugstr_guid(riid));
98 return CLASS_E_NOAGGREGATION;
100 hl = heap_alloc_zero(sizeof(HlinkImpl));
102 return E_OUTOFMEMORY;
106 hl->lpPSVtbl = &psvt;
107 hl->lpDOVtbl = &dovt;
113 static HRESULT WINAPI IHlink_fnQueryInterface(IHlink* iface, REFIID riid,
116 HlinkImpl *This = (HlinkImpl*)iface;
118 TRACE ("(%p)->(%s,%p)\n", This, debugstr_guid (riid), ppvObj);
122 if (IsEqualIID(riid, &IID_IUnknown) || (IsEqualIID(riid, &IID_IHlink)))
124 else if (IsEqualIID(riid, &IID_IPersistStream))
125 *ppvObj = &(This->lpPSVtbl);
126 else if (IsEqualIID(riid, &IID_IDataObject))
127 *ppvObj = &(This->lpDOVtbl);
131 IUnknown_AddRef((IUnknown*)(*ppvObj));
134 return E_NOINTERFACE;
137 static ULONG WINAPI IHlink_fnAddRef (IHlink* iface)
139 HlinkImpl *This = (HlinkImpl*)iface;
140 ULONG refCount = InterlockedIncrement(&This->ref);
142 TRACE("(%p)->(count=%u)\n", This, refCount - 1);
147 static ULONG WINAPI IHlink_fnRelease (IHlink* iface)
149 HlinkImpl *This = (HlinkImpl*)iface;
150 ULONG refCount = InterlockedDecrement(&This->ref);
152 TRACE("(%p)->(count=%u)\n", This, refCount + 1);
156 TRACE("-- destroying IHlink (%p)\n", This);
157 heap_free(This->FriendlyName);
158 heap_free(This->Target);
159 heap_free(This->TargetFrameName);
160 heap_free(This->Location);
162 IMoniker_Release(This->Moniker);
164 IHlinkSite_Release(This->Site);
169 static HRESULT WINAPI IHlink_fnSetHlinkSite( IHlink* iface,
170 IHlinkSite* pihlSite, DWORD dwSiteData)
172 HlinkImpl *This = (HlinkImpl*)iface;
174 TRACE("(%p)->(%p %i)\n", This, pihlSite, dwSiteData);
177 IHlinkSite_Release(This->Site);
179 This->Site = pihlSite;
181 IHlinkSite_AddRef(This->Site);
183 This->SiteData = dwSiteData;
188 static HRESULT WINAPI IHlink_fnGetHlinkSite( IHlink* iface,
189 IHlinkSite** ppihlSite, DWORD *pdwSiteData)
191 HlinkImpl *This = (HlinkImpl*)iface;
193 TRACE("(%p)->(%p %p)\n", This, ppihlSite, pdwSiteData);
195 *ppihlSite = This->Site;
196 *pdwSiteData = This->SiteData;
199 IHlinkSite_AddRef(This->Site);
204 static HRESULT WINAPI IHlink_fnSetMonikerReference( IHlink* iface,
205 DWORD rfHLSETF, IMoniker *pmkTarget, LPCWSTR pwzLocation)
207 HlinkImpl *This = (HlinkImpl*)iface;
209 TRACE("(%p)->(%i %p %s)\n", This, rfHLSETF, pmkTarget,
210 debugstr_w(pwzLocation));
214 if(!(rfHLSETF & (HLINKSETF_TARGET | HLINKSETF_LOCATION)))
217 if(rfHLSETF & HLINKSETF_TARGET){
219 IMoniker_Release(This->Moniker);
221 This->Moniker = pmkTarget;
224 LPOLESTR display_name;
225 IMoniker_AddRef(This->Moniker);
226 IMoniker_GetDisplayName(This->Moniker, NULL, NULL, &display_name);
227 This->absolute = display_name && strchrW(display_name, ':');
228 CoTaskMemFree(display_name);
232 if(rfHLSETF & HLINKSETF_LOCATION){
233 heap_free(This->Location);
234 This->Location = hlink_strdupW( pwzLocation );
240 static HRESULT WINAPI IHlink_fnSetStringReference(IHlink* iface,
241 DWORD grfHLSETF, LPCWSTR pwzTarget, LPCWSTR pwzLocation)
243 HlinkImpl *This = (HlinkImpl*)iface;
245 TRACE("(%p)->(%i %s %s)\n", This, grfHLSETF, debugstr_w(pwzTarget),
246 debugstr_w(pwzLocation));
248 if (grfHLSETF & HLINKSETF_TARGET)
250 heap_free(This->Target);
251 This->Target = hlink_strdupW( pwzTarget );
253 if (grfHLSETF & HLINKSETF_LOCATION)
255 heap_free(This->Location);
256 This->Location = hlink_strdupW( pwzLocation );
262 static HRESULT WINAPI IHlink_fnGetMonikerReference(IHlink* iface,
263 DWORD dwWhichRef, IMoniker **ppimkTarget, LPWSTR *ppwzLocation)
265 HlinkImpl *This = (HlinkImpl*)iface;
267 TRACE("(%p) -> (%i %p %p)\n", This, dwWhichRef, ppimkTarget,
271 __GetMoniker(This, ppimkTarget);
274 IHlink_GetStringReference(iface, dwWhichRef, NULL, ppwzLocation);
279 static HRESULT WINAPI IHlink_fnGetStringReference (IHlink* iface,
280 DWORD dwWhichRef, LPWSTR *ppwzTarget, LPWSTR *ppwzLocation)
282 HlinkImpl *This = (HlinkImpl*)iface;
284 FIXME("(%p) -> (%i %p %p)\n", This, dwWhichRef, ppwzTarget, ppwzLocation);
288 *ppwzTarget = hlink_co_strdupW( This->Target );
293 __GetMoniker(This, &mon);
298 CreateBindCtx( 0, &pbc);
299 IMoniker_GetDisplayName(mon, pbc, NULL, ppwzTarget);
300 IBindCtx_Release(pbc);
301 IMoniker_Release(mon);
304 FIXME("Unhandled case, no set Target and no moniker\n");
308 *ppwzLocation = hlink_co_strdupW( This->Location );
310 TRACE("(Target: %s Location: %s)\n",
311 (ppwzTarget)?debugstr_w(*ppwzTarget):"<NULL>",
312 (ppwzLocation)?debugstr_w(*ppwzLocation):"<NULL>");
317 static HRESULT WINAPI IHlink_fnSetFriendlyName (IHlink *iface,
318 LPCWSTR pwzFriendlyName)
320 HlinkImpl *This = (HlinkImpl*)iface;
322 TRACE("(%p) -> (%s)\n", This, debugstr_w(pwzFriendlyName));
324 heap_free(This->FriendlyName);
325 This->FriendlyName = hlink_strdupW( pwzFriendlyName );
330 static HRESULT WINAPI IHlink_fnGetFriendlyName (IHlink* iface,
331 DWORD grfHLFNAMEF, LPWSTR* ppwzFriendlyName)
333 HlinkImpl *This = (HlinkImpl*)iface;
335 TRACE("(%p) -> (%i %p)\n", This, grfHLFNAMEF, ppwzFriendlyName);
337 /* FIXME: Only using explicitly set and cached friendly names */
339 if (This->FriendlyName)
340 *ppwzFriendlyName = hlink_co_strdupW( This->FriendlyName );
344 __GetMoniker(This, &moniker);
348 CreateBindCtx(0, &bcxt);
350 IMoniker_GetDisplayName(moniker, bcxt, NULL, ppwzFriendlyName);
351 IBindCtx_Release(bcxt);
352 IMoniker_Release(moniker);
355 *ppwzFriendlyName = NULL;
361 static HRESULT WINAPI IHlink_fnSetTargetFrameName(IHlink* iface,
362 LPCWSTR pwzTargetFramename)
364 HlinkImpl *This = (HlinkImpl*)iface;
365 TRACE("(%p)->(%s)\n", This, debugstr_w(pwzTargetFramename));
367 heap_free(This->TargetFrameName);
368 This->TargetFrameName = hlink_strdupW( pwzTargetFramename );
373 static HRESULT WINAPI IHlink_fnGetTargetFrameName(IHlink* iface,
374 LPWSTR *ppwzTargetFrameName)
376 HlinkImpl *This = (HlinkImpl*)iface;
378 TRACE("(%p)->(%p)\n", This, ppwzTargetFrameName);
379 *ppwzTargetFrameName = hlink_co_strdupW( This->TargetFrameName );
384 static HRESULT WINAPI IHlink_fnGetMiscStatus(IHlink* iface, DWORD* pdwStatus)
390 static HRESULT WINAPI IHlink_fnNavigate(IHlink* iface, DWORD grfHLNF, LPBC pbc,
391 IBindStatusCallback *pbsc, IHlinkBrowseContext *phbc)
393 HlinkImpl *This = (HlinkImpl*)iface;
394 IMoniker *mon = NULL;
396 FIXME("Semi-Stub:(%p)->(%i %p %p %p)\n", This, grfHLNF, pbc, pbsc, phbc);
399 IHlinkSite_ReadyToNavigate(This->Site, This->SiteData, 0);
401 __GetMoniker(This, &mon);
402 TRACE("Moniker %p\n", mon);
407 IHlinkTarget *target = NULL;
410 CreateBindCtx(0, &bcxt);
412 RegisterBindStatusCallback(bcxt, pbsc, NULL, 0);
414 r = IMoniker_BindToObject(mon, bcxt, NULL, &IID_IHlinkTarget,
416 TRACE("IHlinkTarget returned 0x%x\n", r);
419 IHlinkTarget_SetBrowseContext(target, phbc);
420 IHlinkTarget_Navigate(target, grfHLNF, This->Location);
421 IHlinkTarget_Release(target);
425 static const WCHAR szOpen[] = {'o','p','e','n',0};
426 LPWSTR target = NULL;
428 r = IHlink_GetStringReference(iface, HLINKGETREF_DEFAULT, &target, NULL);
429 if (SUCCEEDED(r) && target)
431 ShellExecuteW(NULL, szOpen, target, NULL, NULL, SW_SHOW);
432 CoTaskMemFree(target);
436 RevokeBindStatusCallback(bcxt, pbsc);
438 IBindCtx_Release(bcxt);
439 IMoniker_Release(mon);
443 IHlinkSite_OnNavigationComplete(This->Site, This->SiteData, 0, 0, NULL);
445 TRACE("Finished Navigation\n");
449 static HRESULT WINAPI IHlink_fnSetAdditonalParams(IHlink* iface,
450 LPCWSTR pwzAdditionalParams)
452 TRACE("Not implemented in native IHlink\n");
456 static HRESULT WINAPI IHlink_fnGetAdditionalParams(IHlink* iface,
457 LPWSTR* ppwzAdditionalParams)
459 TRACE("Not implemented in native IHlink\n");
463 static const IHlinkVtbl hlvt =
465 IHlink_fnQueryInterface,
468 IHlink_fnSetHlinkSite,
469 IHlink_fnGetHlinkSite,
470 IHlink_fnSetMonikerReference,
471 IHlink_fnGetMonikerReference,
472 IHlink_fnSetStringReference,
473 IHlink_fnGetStringReference,
474 IHlink_fnSetFriendlyName,
475 IHlink_fnGetFriendlyName,
476 IHlink_fnSetTargetFrameName,
477 IHlink_fnGetTargetFrameName,
478 IHlink_fnGetMiscStatus,
480 IHlink_fnSetAdditonalParams,
481 IHlink_fnGetAdditionalParams
484 static HRESULT WINAPI IDataObject_fnQueryInterface(IDataObject* iface,
485 REFIID riid, LPVOID *ppvObj)
487 HlinkImpl *This = HlinkImpl_from_IDataObject(iface);
489 return IHlink_QueryInterface((IHlink*)This, riid, ppvObj);
492 static ULONG WINAPI IDataObject_fnAddRef (IDataObject* iface)
494 HlinkImpl *This = HlinkImpl_from_IDataObject(iface);
496 return IHlink_AddRef((IHlink*)This);
499 static ULONG WINAPI IDataObject_fnRelease (IDataObject* iface)
501 HlinkImpl *This = HlinkImpl_from_IDataObject(iface);
503 return IHlink_Release((IHlink*)This);
506 static HRESULT WINAPI IDataObject_fnGetData(IDataObject* iface,
507 FORMATETC* pformatetcIn, STGMEDIUM* pmedium)
513 static HRESULT WINAPI IDataObject_fnGetDataHere(IDataObject* iface,
514 FORMATETC* pformatetc, STGMEDIUM* pmedium)
520 static HRESULT WINAPI IDataObject_fnQueryGetData(IDataObject* iface,
521 FORMATETC* pformatetc)
527 static HRESULT WINAPI IDataObject_fnGetConicalFormatEtc(IDataObject* iface,
528 FORMATETC* pformatetcIn, FORMATETC* pformatetcOut)
534 static HRESULT WINAPI IDataObject_fnSetData(IDataObject* iface,
535 FORMATETC* pformatetc, STGMEDIUM* pmedium, BOOL fRelease)
541 static HRESULT WINAPI IDataObject_fnEnumFormatEtc(IDataObject* iface,
542 DWORD dwDirection, IEnumFORMATETC** ppenumFormatEtc)
548 static HRESULT WINAPI IDataObject_fnDAdvise(IDataObject* iface,
549 FORMATETC* pformatetc, DWORD advf, IAdviseSink* pAdvSink,
550 DWORD* pdwConnection)
556 static HRESULT WINAPI IDataObject_fnDUnadvise(IDataObject* iface,
563 static HRESULT WINAPI IDataObject_fnEnumDAdvise(IDataObject* iface,
564 IEnumSTATDATA** ppenumAdvise)
570 static const IDataObjectVtbl dovt =
572 IDataObject_fnQueryInterface,
573 IDataObject_fnAddRef,
574 IDataObject_fnRelease,
575 IDataObject_fnGetData,
576 IDataObject_fnGetDataHere,
577 IDataObject_fnQueryGetData,
578 IDataObject_fnGetConicalFormatEtc,
579 IDataObject_fnSetData,
580 IDataObject_fnEnumFormatEtc,
581 IDataObject_fnDAdvise,
582 IDataObject_fnDUnadvise,
583 IDataObject_fnEnumDAdvise
586 static HRESULT WINAPI IPersistStream_fnQueryInterface(IPersistStream* iface,
587 REFIID riid, LPVOID *ppvObj)
589 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
590 TRACE("(%p)\n", This);
591 return IHlink_QueryInterface((IHlink*)This, riid, ppvObj);
594 static ULONG WINAPI IPersistStream_fnAddRef (IPersistStream* iface)
596 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
597 TRACE("(%p)\n", This);
598 return IHlink_AddRef((IHlink*)This);
601 static ULONG WINAPI IPersistStream_fnRelease (IPersistStream* iface)
603 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
604 TRACE("(%p)\n", This);
605 return IHlink_Release((IHlink*)This);
608 static HRESULT WINAPI IPersistStream_fnGetClassID(IPersistStream* iface,
611 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
612 TRACE("(%p)\n", This);
613 *pClassID = CLSID_StdHlink;
617 static HRESULT WINAPI IPersistStream_fnIsDirty(IPersistStream* iface)
623 static HRESULT write_hlink_string(IStream *pStm, LPCWSTR str)
628 TRACE("(%p, %s)\n", pStm, debugstr_w(str));
630 len = strlenW(str) + 1;
632 hr = IStream_Write(pStm, &len, sizeof(len), NULL);
633 if (FAILED(hr)) return hr;
635 hr = IStream_Write(pStm, str, len * sizeof(WCHAR), NULL);
636 if (FAILED(hr)) return hr;
641 static inline ULONG size_hlink_string(LPCWSTR str)
643 return sizeof(DWORD) + (strlenW(str) + 1) * sizeof(WCHAR);
646 static HRESULT read_hlink_string(IStream *pStm, LPWSTR *out_str)
653 hr = IStream_Read(pStm, &len, sizeof(len), &read);
654 if (FAILED(hr)) return hr;
655 if (read != sizeof(len)) return STG_E_READFAULT;
657 TRACE("read len %d\n", len);
659 str = heap_alloc(len * sizeof(WCHAR));
660 if (!str) return E_OUTOFMEMORY;
662 hr = IStream_Read(pStm, str, len * sizeof(WCHAR), &read);
668 if (read != len * sizeof(WCHAR))
671 return STG_E_READFAULT;
673 TRACE("read string %s\n", debugstr_w(str));
679 static HRESULT WINAPI IPersistStream_fnLoad(IPersistStream* iface,
685 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
687 r = IStream_Read(pStm, hdr, sizeof(hdr), &read);
688 if (read != sizeof(hdr) || (hdr[0] != HLINK_SAVE_MAGIC))
693 if (hdr[1] & ~HLINK_SAVE_ALL)
694 FIXME("unknown flag(s) 0x%x\n", hdr[1] & ~HLINK_SAVE_ALL);
696 if (hdr[1] & HLINK_SAVE_TARGET_FRAME_PRESENT)
698 TRACE("loading target frame name\n");
699 r = read_hlink_string(pStm, &This->TargetFrameName);
700 if (FAILED(r)) goto end;
703 if (hdr[1] & HLINK_SAVE_FRIENDLY_PRESENT)
705 TRACE("loading target friendly name\n");
707 FIXME("0x4 flag not present with friendly name flag - not sure what this means\n");
708 r = read_hlink_string(pStm, &This->FriendlyName);
709 if (FAILED(r)) goto end;
712 if (hdr[1] & HLINK_SAVE_MONIKER_PRESENT)
714 TRACE("loading moniker\n");
715 r = OleLoadFromStream(pStm, &IID_IMoniker, (LPVOID*)&(This->Moniker));
718 This->absolute = hdr[1] & HLINK_SAVE_MONIKER_IS_ABSOLUTE ? TRUE : FALSE;
721 if (hdr[1] & HLINK_SAVE_LOCATION_PRESENT)
723 TRACE("loading location\n");
724 r = read_hlink_string(pStm, &This->Location);
725 if (FAILED(r)) goto end;
729 TRACE("Load Result 0x%x (%p)\n", r, This->Moniker);
734 static HRESULT WINAPI IPersistStream_fnSave(IPersistStream* iface,
735 IStream* pStm, BOOL fClearDirty)
738 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
742 TRACE("(%p) Moniker(%p)\n", This, This->Moniker);
744 __GetMoniker(This, &moniker);
746 hdr[0] = HLINK_SAVE_MAGIC;
750 hdr[1] |= HLINK_SAVE_MONIKER_PRESENT;
752 hdr[1] |= HLINK_SAVE_MONIKER_IS_ABSOLUTE;
754 hdr[1] |= HLINK_SAVE_LOCATION_PRESENT;
755 if (This->FriendlyName)
756 hdr[1] |= HLINK_SAVE_FRIENDLY_PRESENT | 4 /* FIXME */;
757 if (This->TargetFrameName)
758 hdr[1] |= HLINK_SAVE_TARGET_FRAME_PRESENT;
760 IStream_Write(pStm, hdr, sizeof(hdr), NULL);
762 if (This->TargetFrameName)
764 r = write_hlink_string(pStm, This->TargetFrameName);
765 if (FAILED(r)) goto end;
768 if (This->FriendlyName)
770 r = write_hlink_string(pStm, This->FriendlyName);
771 if (FAILED(r)) goto end;
776 IPersistStream* monstream;
779 IMoniker_QueryInterface(moniker, &IID_IPersistStream,
780 (LPVOID*)&monstream);
783 r = OleSaveToStream(monstream, pStm);
784 IPersistStream_Release(monstream);
786 if (FAILED(r)) goto end;
791 r = write_hlink_string(pStm, This->Location);
792 if (FAILED(r)) goto end;
796 if (moniker) IMoniker_Release(moniker);
797 TRACE("Save Result 0x%x\n", r);
802 static HRESULT WINAPI IPersistStream_fnGetSizeMax(IPersistStream* iface,
803 ULARGE_INTEGER* pcbSize)
806 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
809 TRACE("(%p) Moniker(%p)\n", This, This->Moniker);
811 pcbSize->QuadPart = sizeof(DWORD)*2;
813 if (This->TargetFrameName)
814 pcbSize->QuadPart += size_hlink_string(This->TargetFrameName);
816 if (This->FriendlyName)
817 pcbSize->QuadPart += size_hlink_string(This->FriendlyName);
819 __GetMoniker(This, &moniker);
822 IPersistStream* monstream = NULL;
823 IMoniker_QueryInterface(moniker, &IID_IPersistStream,
824 (LPVOID*)&monstream);
827 ULARGE_INTEGER mon_size;
828 r = IPersistStream_GetSizeMax(monstream, &mon_size);
829 pcbSize->QuadPart += mon_size.QuadPart;
830 IPersistStream_Release(monstream);
832 IMoniker_Release(moniker);
836 pcbSize->QuadPart += size_hlink_string(This->Location);
841 static const IPersistStreamVtbl psvt =
843 IPersistStream_fnQueryInterface,
844 IPersistStream_fnAddRef,
845 IPersistStream_fnRelease,
846 IPersistStream_fnGetClassID,
847 IPersistStream_fnIsDirty,
848 IPersistStream_fnLoad,
849 IPersistStream_fnSave,
850 IPersistStream_fnGetSizeMax,