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,
90 HRESULT WINAPI HLink_Constructor(IUnknown *pUnkOuter, REFIID riid,
95 TRACE("unkOut=%p riid=%s\n", pUnkOuter, debugstr_guid(riid));
99 return CLASS_E_NOAGGREGATION;
101 hl = heap_alloc_zero(sizeof(HlinkImpl));
103 return E_OUTOFMEMORY;
107 hl->lpPSVtbl = &psvt;
108 hl->lpDOVtbl = &dovt;
114 static HRESULT WINAPI IHlink_fnQueryInterface(IHlink* iface, REFIID riid,
117 HlinkImpl *This = (HlinkImpl*)iface;
119 TRACE ("(%p)->(%s,%p)\n", This, debugstr_guid (riid), ppvObj);
123 if (IsEqualIID(riid, &IID_IUnknown) || (IsEqualIID(riid, &IID_IHlink)))
125 else if (IsEqualIID(riid, &IID_IPersistStream))
126 *ppvObj = (LPVOID*)&(This->lpPSVtbl);
127 else if (IsEqualIID(riid, &IID_IDataObject))
128 *ppvObj = (LPVOID*)&(This->lpDOVtbl);
132 IUnknown_AddRef((IUnknown*)(*ppvObj));
135 return E_NOINTERFACE;
138 static ULONG WINAPI IHlink_fnAddRef (IHlink* iface)
140 HlinkImpl *This = (HlinkImpl*)iface;
141 ULONG refCount = InterlockedIncrement(&This->ref);
143 TRACE("(%p)->(count=%u)\n", This, refCount - 1);
148 static ULONG WINAPI IHlink_fnRelease (IHlink* iface)
150 HlinkImpl *This = (HlinkImpl*)iface;
151 ULONG refCount = InterlockedDecrement(&This->ref);
153 TRACE("(%p)->(count=%u)\n", This, refCount + 1);
157 TRACE("-- destroying IHlink (%p)\n", This);
158 heap_free(This->FriendlyName);
159 heap_free(This->Target);
160 heap_free(This->TargetFrameName);
161 heap_free(This->Location);
163 IMoniker_Release(This->Moniker);
165 IHlinkSite_Release(This->Site);
170 static HRESULT WINAPI IHlink_fnSetHlinkSite( IHlink* iface,
171 IHlinkSite* pihlSite, DWORD dwSiteData)
173 HlinkImpl *This = (HlinkImpl*)iface;
175 TRACE("(%p)->(%p %i)\n", This, pihlSite, dwSiteData);
178 IHlinkSite_Release(This->Site);
180 This->Site = pihlSite;
182 IHlinkSite_AddRef(This->Site);
184 This->SiteData = dwSiteData;
189 static HRESULT WINAPI IHlink_fnGetHlinkSite( IHlink* iface,
190 IHlinkSite** ppihlSite, DWORD *pdwSiteData)
192 HlinkImpl *This = (HlinkImpl*)iface;
194 TRACE("(%p)->(%p %p)\n", This, ppihlSite, pdwSiteData);
196 *ppihlSite = This->Site;
197 *pdwSiteData = This->SiteData;
200 IHlinkSite_AddRef(This->Site);
205 static HRESULT WINAPI IHlink_fnSetMonikerReference( IHlink* iface,
206 DWORD rfHLSETF, IMoniker *pmkTarget, LPCWSTR pwzLocation)
208 HlinkImpl *This = (HlinkImpl*)iface;
210 FIXME("(%p)->(%i %p %s)\n", This, rfHLSETF, pmkTarget,
211 debugstr_w(pwzLocation));
214 IMoniker_Release(This->Moniker);
216 This->Moniker = pmkTarget;
219 LPOLESTR display_name;
220 IMoniker_AddRef(This->Moniker);
221 IMoniker_GetDisplayName(This->Moniker, NULL, NULL, &display_name);
222 This->absolute = display_name && strchrW(display_name, ':');
223 CoTaskMemFree(display_name);
226 heap_free(This->Location);
227 This->Location = hlink_strdupW( pwzLocation );
232 static HRESULT WINAPI IHlink_fnSetStringReference(IHlink* iface,
233 DWORD grfHLSETF, LPCWSTR pwzTarget, LPCWSTR pwzLocation)
235 HlinkImpl *This = (HlinkImpl*)iface;
237 TRACE("(%p)->(%i %s %s)\n", This, grfHLSETF, debugstr_w(pwzTarget),
238 debugstr_w(pwzLocation));
240 if (grfHLSETF & HLINKSETF_TARGET)
242 heap_free(This->Target);
243 This->Target = hlink_strdupW( pwzTarget );
245 if (grfHLSETF & HLINKSETF_LOCATION)
247 heap_free(This->Location);
248 This->Location = hlink_strdupW( pwzLocation );
254 static HRESULT WINAPI IHlink_fnGetMonikerReference(IHlink* iface,
255 DWORD dwWhichRef, IMoniker **ppimkTarget, LPWSTR *ppwzLocation)
257 HlinkImpl *This = (HlinkImpl*)iface;
259 TRACE("(%p) -> (%i %p %p)\n", This, dwWhichRef, ppimkTarget,
263 __GetMoniker(This, ppimkTarget);
266 IHlink_GetStringReference(iface, dwWhichRef, NULL, ppwzLocation);
271 static HRESULT WINAPI IHlink_fnGetStringReference (IHlink* iface,
272 DWORD dwWhichRef, LPWSTR *ppwzTarget, LPWSTR *ppwzLocation)
274 HlinkImpl *This = (HlinkImpl*)iface;
276 FIXME("(%p) -> (%i %p %p)\n", This, dwWhichRef, ppwzTarget, ppwzLocation);
280 *ppwzTarget = hlink_co_strdupW( This->Target );
285 __GetMoniker(This, &mon);
290 CreateBindCtx( 0, &pbc);
291 IMoniker_GetDisplayName(mon, pbc, NULL, ppwzTarget);
292 IBindCtx_Release(pbc);
293 IMoniker_Release(mon);
296 FIXME("Unhandled case, no set Target and no moniker\n");
300 *ppwzLocation = hlink_co_strdupW( This->Location );
302 TRACE("(Target: %s Location: %s)\n",
303 (ppwzTarget)?debugstr_w(*ppwzTarget):"<NULL>",
304 (ppwzLocation)?debugstr_w(*ppwzLocation):"<NULL>");
309 static HRESULT WINAPI IHlink_fnSetFriendlyName (IHlink *iface,
310 LPCWSTR pwzFriendlyName)
312 HlinkImpl *This = (HlinkImpl*)iface;
314 TRACE("(%p) -> (%s)\n", This, debugstr_w(pwzFriendlyName));
316 heap_free(This->FriendlyName);
317 This->FriendlyName = hlink_strdupW( pwzFriendlyName );
322 static HRESULT WINAPI IHlink_fnGetFriendlyName (IHlink* iface,
323 DWORD grfHLFNAMEF, LPWSTR* ppwzFriendlyName)
325 HlinkImpl *This = (HlinkImpl*)iface;
327 TRACE("(%p) -> (%i %p)\n", This, grfHLFNAMEF, ppwzFriendlyName);
329 /* FIXME: Only using explicitly set and cached friendly names */
331 if (This->FriendlyName)
332 *ppwzFriendlyName = hlink_co_strdupW( This->FriendlyName );
336 __GetMoniker(This, &moniker);
340 CreateBindCtx(0, &bcxt);
342 IMoniker_GetDisplayName(moniker, bcxt, NULL, ppwzFriendlyName);
343 IBindCtx_Release(bcxt);
344 IMoniker_Release(moniker);
347 *ppwzFriendlyName = NULL;
353 static HRESULT WINAPI IHlink_fnSetTargetFrameName(IHlink* iface,
354 LPCWSTR pwzTargetFramename)
356 HlinkImpl *This = (HlinkImpl*)iface;
357 TRACE("(%p)->(%s)\n", This, debugstr_w(pwzTargetFramename));
359 heap_free(This->TargetFrameName);
360 This->TargetFrameName = hlink_strdupW( pwzTargetFramename );
365 static HRESULT WINAPI IHlink_fnGetTargetFrameName(IHlink* iface,
366 LPWSTR *ppwzTargetFrameName)
368 HlinkImpl *This = (HlinkImpl*)iface;
370 TRACE("(%p)->(%p)\n", This, ppwzTargetFrameName);
371 *ppwzTargetFrameName = hlink_co_strdupW( This->TargetFrameName );
376 static HRESULT WINAPI IHlink_fnGetMiscStatus(IHlink* iface, DWORD* pdwStatus)
382 static HRESULT WINAPI IHlink_fnNavigate(IHlink* iface, DWORD grfHLNF, LPBC pbc,
383 IBindStatusCallback *pbsc, IHlinkBrowseContext *phbc)
385 HlinkImpl *This = (HlinkImpl*)iface;
386 IMoniker *mon = NULL;
388 FIXME("Semi-Stub:(%p)->(%i %p %p %p)\n", This, grfHLNF, pbc, pbsc, phbc);
391 IHlinkSite_ReadyToNavigate(This->Site, This->SiteData, 0);
393 __GetMoniker(This, &mon);
394 TRACE("Moniker %p\n", mon);
399 IHlinkTarget *target = NULL;
402 CreateBindCtx(0, &bcxt);
404 RegisterBindStatusCallback(bcxt, pbsc, NULL, 0);
406 r = IMoniker_BindToObject(mon, bcxt, NULL, &IID_IHlinkTarget,
408 TRACE("IHlinkTarget returned 0x%x\n", r);
411 IHlinkTarget_SetBrowseContext(target, phbc);
412 IHlinkTarget_Navigate(target, grfHLNF, This->Location);
413 IHlinkTarget_Release(target);
417 static const WCHAR szOpen[] = {'o','p','e','n',0};
418 LPWSTR target = NULL;
420 r = IHlink_GetStringReference(iface, HLINKGETREF_DEFAULT, &target, NULL);
421 if (SUCCEEDED(r) && target)
423 ShellExecuteW(NULL, szOpen, target, NULL, NULL, SW_SHOW);
424 CoTaskMemFree(target);
428 RevokeBindStatusCallback(bcxt, pbsc);
430 IBindCtx_Release(bcxt);
431 IMoniker_Release(mon);
435 IHlinkSite_OnNavigationComplete(This->Site, This->SiteData, 0, 0, NULL);
437 TRACE("Finished Navigation\n");
441 static HRESULT WINAPI IHlink_fnSetAdditonalParams(IHlink* iface,
442 LPCWSTR pwzAdditionalParams)
448 static HRESULT WINAPI IHlink_fnGetAdditionalParams(IHlink* iface,
449 LPWSTR* ppwzAdditionalParams)
455 static const IHlinkVtbl hlvt =
457 IHlink_fnQueryInterface,
460 IHlink_fnSetHlinkSite,
461 IHlink_fnGetHlinkSite,
462 IHlink_fnSetMonikerReference,
463 IHlink_fnGetMonikerReference,
464 IHlink_fnSetStringReference,
465 IHlink_fnGetStringReference,
466 IHlink_fnSetFriendlyName,
467 IHlink_fnGetFriendlyName,
468 IHlink_fnSetTargetFrameName,
469 IHlink_fnGetTargetFrameName,
470 IHlink_fnGetMiscStatus,
472 IHlink_fnSetAdditonalParams,
473 IHlink_fnGetAdditionalParams
476 static HRESULT WINAPI IDataObject_fnQueryInterface(IDataObject* iface,
477 REFIID riid, LPVOID *ppvObj)
479 HlinkImpl *This = HlinkImpl_from_IDataObject(iface);
481 return IHlink_QueryInterface((IHlink*)This, riid, ppvObj);
484 static ULONG WINAPI IDataObject_fnAddRef (IDataObject* iface)
486 HlinkImpl *This = HlinkImpl_from_IDataObject(iface);
488 return IHlink_AddRef((IHlink*)This);
491 static ULONG WINAPI IDataObject_fnRelease (IDataObject* iface)
493 HlinkImpl *This = HlinkImpl_from_IDataObject(iface);
495 return IHlink_Release((IHlink*)This);
498 static HRESULT WINAPI IDataObject_fnGetData(IDataObject* iface,
499 FORMATETC* pformatetcIn, STGMEDIUM* pmedium)
505 static HRESULT WINAPI IDataObject_fnGetDataHere(IDataObject* iface,
506 FORMATETC* pformatetc, STGMEDIUM* pmedium)
512 static HRESULT WINAPI IDataObject_fnQueryGetData(IDataObject* iface,
513 FORMATETC* pformatetc)
519 static HRESULT WINAPI IDataObject_fnGetConicalFormatEtc(IDataObject* iface,
520 FORMATETC* pformatetcIn, FORMATETC* pformatetcOut)
526 static HRESULT WINAPI IDataObject_fnSetData(IDataObject* iface,
527 FORMATETC* pformatetc, STGMEDIUM* pmedium, BOOL fRelease)
533 static HRESULT WINAPI IDataObject_fnEnumFormatEtc(IDataObject* iface,
534 DWORD dwDirection, IEnumFORMATETC** ppenumFormatEtc)
540 static HRESULT WINAPI IDataObject_fnDAdvise(IDataObject* iface,
541 FORMATETC* pformatetc, DWORD advf, IAdviseSink* pAdvSink,
542 DWORD* pdwConnection)
548 static HRESULT WINAPI IDataObject_fnDUnadvise(IDataObject* iface,
555 static HRESULT WINAPI IDataObject_fnEnumDAdvise(IDataObject* iface,
556 IEnumSTATDATA** ppenumAdvise)
562 static const IDataObjectVtbl dovt =
564 IDataObject_fnQueryInterface,
565 IDataObject_fnAddRef,
566 IDataObject_fnRelease,
567 IDataObject_fnGetData,
568 IDataObject_fnGetDataHere,
569 IDataObject_fnQueryGetData,
570 IDataObject_fnGetConicalFormatEtc,
571 IDataObject_fnSetData,
572 IDataObject_fnEnumFormatEtc,
573 IDataObject_fnDAdvise,
574 IDataObject_fnDUnadvise,
575 IDataObject_fnEnumDAdvise
578 static HRESULT WINAPI IPersistStream_fnQueryInterface(IPersistStream* iface,
579 REFIID riid, LPVOID *ppvObj)
581 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
582 TRACE("(%p)\n", This);
583 return IHlink_QueryInterface((IHlink*)This, riid, ppvObj);
586 static ULONG WINAPI IPersistStream_fnAddRef (IPersistStream* iface)
588 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
589 TRACE("(%p)\n", This);
590 return IHlink_AddRef((IHlink*)This);
593 static ULONG WINAPI IPersistStream_fnRelease (IPersistStream* iface)
595 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
596 TRACE("(%p)\n", This);
597 return IHlink_Release((IHlink*)This);
600 static HRESULT WINAPI IPersistStream_fnGetClassID(IPersistStream* iface,
603 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
604 TRACE("(%p)\n", This);
605 *pClassID = CLSID_StdHlink;
609 static HRESULT WINAPI IPersistStream_fnIsDirty(IPersistStream* iface)
615 static HRESULT write_hlink_string(IStream *pStm, LPCWSTR str)
620 TRACE("(%p, %s)\n", pStm, debugstr_w(str));
622 len = strlenW(str) + 1;
624 hr = IStream_Write(pStm, &len, sizeof(len), NULL);
625 if (FAILED(hr)) return hr;
627 hr = IStream_Write(pStm, str, len * sizeof(WCHAR), NULL);
628 if (FAILED(hr)) return hr;
633 static inline ULONG size_hlink_string(LPCWSTR str)
635 return sizeof(DWORD) + (strlenW(str) + 1) * sizeof(WCHAR);
638 static HRESULT read_hlink_string(IStream *pStm, LPWSTR *out_str)
645 hr = IStream_Read(pStm, &len, sizeof(len), &read);
646 if (FAILED(hr)) return hr;
647 if (read != sizeof(len)) return STG_E_READFAULT;
649 TRACE("read len %d\n", len);
651 str = heap_alloc(len * sizeof(WCHAR));
652 if (!str) return E_OUTOFMEMORY;
654 hr = IStream_Read(pStm, str, len * sizeof(WCHAR), &read);
660 if (read != len * sizeof(WCHAR))
663 return STG_E_READFAULT;
665 TRACE("read string %s\n", debugstr_w(str));
671 static HRESULT WINAPI IPersistStream_fnLoad(IPersistStream* iface,
677 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
679 r = IStream_Read(pStm, &hdr, sizeof(hdr), &read);
680 if (read != sizeof(hdr) || (hdr[0] != HLINK_SAVE_MAGIC))
685 if (hdr[1] & ~HLINK_SAVE_ALL)
686 FIXME("unknown flag(s) 0x%x\n", hdr[1] & ~HLINK_SAVE_ALL);
688 if (hdr[1] & HLINK_SAVE_TARGET_FRAME_PRESENT)
690 TRACE("loading target frame name\n");
691 r = read_hlink_string(pStm, &This->TargetFrameName);
692 if (FAILED(r)) goto end;
695 if (hdr[1] & HLINK_SAVE_FRIENDLY_PRESENT)
697 TRACE("loading target friendly name\n");
699 FIXME("0x4 flag not present with friendly name flag - not sure what this means\n");
700 r = read_hlink_string(pStm, &This->FriendlyName);
701 if (FAILED(r)) goto end;
704 if (hdr[1] & HLINK_SAVE_MONIKER_PRESENT)
706 TRACE("loading moniker\n");
707 r = OleLoadFromStream(pStm, &IID_IMoniker, (LPVOID*)&(This->Moniker));
710 This->absolute = hdr[1] & HLINK_SAVE_MONIKER_IS_ABSOLUTE ? TRUE : FALSE;
713 if (hdr[1] & HLINK_SAVE_LOCATION_PRESENT)
715 TRACE("loading location\n");
716 r = read_hlink_string(pStm, &This->Location);
717 if (FAILED(r)) goto end;
721 TRACE("Load Result 0x%x (%p)\n", r, This->Moniker);
726 static HRESULT WINAPI IPersistStream_fnSave(IPersistStream* iface,
727 IStream* pStm, BOOL fClearDirty)
730 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
734 TRACE("(%p) Moniker(%p)\n", This, This->Moniker);
736 __GetMoniker(This, &moniker);
738 hdr[0] = HLINK_SAVE_MAGIC;
742 hdr[1] |= HLINK_SAVE_MONIKER_PRESENT;
744 hdr[1] |= HLINK_SAVE_MONIKER_IS_ABSOLUTE;
746 hdr[1] |= HLINK_SAVE_LOCATION_PRESENT;
747 if (This->FriendlyName)
748 hdr[1] |= HLINK_SAVE_FRIENDLY_PRESENT | 4 /* FIXME */;
749 if (This->TargetFrameName)
750 hdr[1] |= HLINK_SAVE_TARGET_FRAME_PRESENT;
752 IStream_Write(pStm, &hdr, sizeof(hdr), NULL);
754 if (This->TargetFrameName)
756 r = write_hlink_string(pStm, This->TargetFrameName);
757 if (FAILED(r)) goto end;
760 if (This->FriendlyName)
762 r = write_hlink_string(pStm, This->FriendlyName);
763 if (FAILED(r)) goto end;
768 IPersistStream* monstream;
771 IMoniker_QueryInterface(moniker, &IID_IPersistStream,
772 (LPVOID*)&monstream);
775 r = OleSaveToStream(monstream, pStm);
776 IPersistStream_Release(monstream);
778 if (FAILED(r)) goto end;
783 r = write_hlink_string(pStm, This->Location);
784 if (FAILED(r)) goto end;
788 if (moniker) IMoniker_Release(moniker);
789 TRACE("Save Result 0x%x\n", r);
794 static HRESULT WINAPI IPersistStream_fnGetSizeMax(IPersistStream* iface,
795 ULARGE_INTEGER* pcbSize)
798 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
801 TRACE("(%p) Moniker(%p)\n", This, This->Moniker);
803 pcbSize->QuadPart = sizeof(DWORD)*2;
805 if (This->TargetFrameName)
806 pcbSize->QuadPart += size_hlink_string(This->TargetFrameName);
808 if (This->FriendlyName)
809 pcbSize->QuadPart += size_hlink_string(This->FriendlyName);
811 __GetMoniker(This, &moniker);
814 IPersistStream* monstream = NULL;
815 IMoniker_QueryInterface(moniker, &IID_IPersistStream,
816 (LPVOID*)&monstream);
819 ULARGE_INTEGER mon_size;
820 r = IPersistStream_GetSizeMax(monstream, &mon_size);
821 pcbSize->QuadPart += mon_size.QuadPart;
822 IPersistStream_Release(monstream);
824 IMoniker_Release(moniker);
828 pcbSize->QuadPart += size_hlink_string(This->Location);
833 static const IPersistStreamVtbl psvt =
835 IPersistStream_fnQueryInterface,
836 IPersistStream_fnAddRef,
837 IPersistStream_fnRelease,
838 IPersistStream_fnGetClassID,
839 IPersistStream_fnIsDirty,
840 IPersistStream_fnLoad,
841 IPersistStream_fnSave,
842 IPersistStream_fnGetSizeMax,