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 FIXME("(%p)->(%i %p %s)\n", This, rfHLSETF, pmkTarget,
210 debugstr_w(pwzLocation));
213 IMoniker_Release(This->Moniker);
215 This->Moniker = pmkTarget;
218 LPOLESTR display_name;
219 IMoniker_AddRef(This->Moniker);
220 IMoniker_GetDisplayName(This->Moniker, NULL, NULL, &display_name);
221 This->absolute = display_name && strchrW(display_name, ':');
222 CoTaskMemFree(display_name);
225 heap_free(This->Location);
226 This->Location = hlink_strdupW( pwzLocation );
231 static HRESULT WINAPI IHlink_fnSetStringReference(IHlink* iface,
232 DWORD grfHLSETF, LPCWSTR pwzTarget, LPCWSTR pwzLocation)
234 HlinkImpl *This = (HlinkImpl*)iface;
236 TRACE("(%p)->(%i %s %s)\n", This, grfHLSETF, debugstr_w(pwzTarget),
237 debugstr_w(pwzLocation));
239 if (grfHLSETF & HLINKSETF_TARGET)
241 heap_free(This->Target);
242 This->Target = hlink_strdupW( pwzTarget );
244 if (grfHLSETF & HLINKSETF_LOCATION)
246 heap_free(This->Location);
247 This->Location = hlink_strdupW( pwzLocation );
253 static HRESULT WINAPI IHlink_fnGetMonikerReference(IHlink* iface,
254 DWORD dwWhichRef, IMoniker **ppimkTarget, LPWSTR *ppwzLocation)
256 HlinkImpl *This = (HlinkImpl*)iface;
258 TRACE("(%p) -> (%i %p %p)\n", This, dwWhichRef, ppimkTarget,
262 __GetMoniker(This, ppimkTarget);
265 IHlink_GetStringReference(iface, dwWhichRef, NULL, ppwzLocation);
270 static HRESULT WINAPI IHlink_fnGetStringReference (IHlink* iface,
271 DWORD dwWhichRef, LPWSTR *ppwzTarget, LPWSTR *ppwzLocation)
273 HlinkImpl *This = (HlinkImpl*)iface;
275 FIXME("(%p) -> (%i %p %p)\n", This, dwWhichRef, ppwzTarget, ppwzLocation);
279 *ppwzTarget = hlink_co_strdupW( This->Target );
284 __GetMoniker(This, &mon);
289 CreateBindCtx( 0, &pbc);
290 IMoniker_GetDisplayName(mon, pbc, NULL, ppwzTarget);
291 IBindCtx_Release(pbc);
292 IMoniker_Release(mon);
295 FIXME("Unhandled case, no set Target and no moniker\n");
299 *ppwzLocation = hlink_co_strdupW( This->Location );
301 TRACE("(Target: %s Location: %s)\n",
302 (ppwzTarget)?debugstr_w(*ppwzTarget):"<NULL>",
303 (ppwzLocation)?debugstr_w(*ppwzLocation):"<NULL>");
308 static HRESULT WINAPI IHlink_fnSetFriendlyName (IHlink *iface,
309 LPCWSTR pwzFriendlyName)
311 HlinkImpl *This = (HlinkImpl*)iface;
313 TRACE("(%p) -> (%s)\n", This, debugstr_w(pwzFriendlyName));
315 heap_free(This->FriendlyName);
316 This->FriendlyName = hlink_strdupW( pwzFriendlyName );
321 static HRESULT WINAPI IHlink_fnGetFriendlyName (IHlink* iface,
322 DWORD grfHLFNAMEF, LPWSTR* ppwzFriendlyName)
324 HlinkImpl *This = (HlinkImpl*)iface;
326 TRACE("(%p) -> (%i %p)\n", This, grfHLFNAMEF, ppwzFriendlyName);
328 /* FIXME: Only using explicitly set and cached friendly names */
330 if (This->FriendlyName)
331 *ppwzFriendlyName = hlink_co_strdupW( This->FriendlyName );
335 __GetMoniker(This, &moniker);
339 CreateBindCtx(0, &bcxt);
341 IMoniker_GetDisplayName(moniker, bcxt, NULL, ppwzFriendlyName);
342 IBindCtx_Release(bcxt);
343 IMoniker_Release(moniker);
346 *ppwzFriendlyName = NULL;
352 static HRESULT WINAPI IHlink_fnSetTargetFrameName(IHlink* iface,
353 LPCWSTR pwzTargetFramename)
355 HlinkImpl *This = (HlinkImpl*)iface;
356 TRACE("(%p)->(%s)\n", This, debugstr_w(pwzTargetFramename));
358 heap_free(This->TargetFrameName);
359 This->TargetFrameName = hlink_strdupW( pwzTargetFramename );
364 static HRESULT WINAPI IHlink_fnGetTargetFrameName(IHlink* iface,
365 LPWSTR *ppwzTargetFrameName)
367 HlinkImpl *This = (HlinkImpl*)iface;
369 TRACE("(%p)->(%p)\n", This, ppwzTargetFrameName);
370 *ppwzTargetFrameName = hlink_co_strdupW( This->TargetFrameName );
375 static HRESULT WINAPI IHlink_fnGetMiscStatus(IHlink* iface, DWORD* pdwStatus)
381 static HRESULT WINAPI IHlink_fnNavigate(IHlink* iface, DWORD grfHLNF, LPBC pbc,
382 IBindStatusCallback *pbsc, IHlinkBrowseContext *phbc)
384 HlinkImpl *This = (HlinkImpl*)iface;
385 IMoniker *mon = NULL;
387 FIXME("Semi-Stub:(%p)->(%i %p %p %p)\n", This, grfHLNF, pbc, pbsc, phbc);
390 IHlinkSite_ReadyToNavigate(This->Site, This->SiteData, 0);
392 __GetMoniker(This, &mon);
393 TRACE("Moniker %p\n", mon);
398 IHlinkTarget *target = NULL;
401 CreateBindCtx(0, &bcxt);
403 RegisterBindStatusCallback(bcxt, pbsc, NULL, 0);
405 r = IMoniker_BindToObject(mon, bcxt, NULL, &IID_IHlinkTarget,
407 TRACE("IHlinkTarget returned 0x%x\n", r);
410 IHlinkTarget_SetBrowseContext(target, phbc);
411 IHlinkTarget_Navigate(target, grfHLNF, This->Location);
412 IHlinkTarget_Release(target);
416 static const WCHAR szOpen[] = {'o','p','e','n',0};
417 LPWSTR target = NULL;
419 r = IHlink_GetStringReference(iface, HLINKGETREF_DEFAULT, &target, NULL);
420 if (SUCCEEDED(r) && target)
422 ShellExecuteW(NULL, szOpen, target, NULL, NULL, SW_SHOW);
423 CoTaskMemFree(target);
427 RevokeBindStatusCallback(bcxt, pbsc);
429 IBindCtx_Release(bcxt);
430 IMoniker_Release(mon);
434 IHlinkSite_OnNavigationComplete(This->Site, This->SiteData, 0, 0, NULL);
436 TRACE("Finished Navigation\n");
440 static HRESULT WINAPI IHlink_fnSetAdditonalParams(IHlink* iface,
441 LPCWSTR pwzAdditionalParams)
443 TRACE("Not implemented in native IHlink\n");
447 static HRESULT WINAPI IHlink_fnGetAdditionalParams(IHlink* iface,
448 LPWSTR* ppwzAdditionalParams)
450 TRACE("Not implemented in native IHlink\n");
454 static const IHlinkVtbl hlvt =
456 IHlink_fnQueryInterface,
459 IHlink_fnSetHlinkSite,
460 IHlink_fnGetHlinkSite,
461 IHlink_fnSetMonikerReference,
462 IHlink_fnGetMonikerReference,
463 IHlink_fnSetStringReference,
464 IHlink_fnGetStringReference,
465 IHlink_fnSetFriendlyName,
466 IHlink_fnGetFriendlyName,
467 IHlink_fnSetTargetFrameName,
468 IHlink_fnGetTargetFrameName,
469 IHlink_fnGetMiscStatus,
471 IHlink_fnSetAdditonalParams,
472 IHlink_fnGetAdditionalParams
475 static HRESULT WINAPI IDataObject_fnQueryInterface(IDataObject* iface,
476 REFIID riid, LPVOID *ppvObj)
478 HlinkImpl *This = HlinkImpl_from_IDataObject(iface);
480 return IHlink_QueryInterface((IHlink*)This, riid, ppvObj);
483 static ULONG WINAPI IDataObject_fnAddRef (IDataObject* iface)
485 HlinkImpl *This = HlinkImpl_from_IDataObject(iface);
487 return IHlink_AddRef((IHlink*)This);
490 static ULONG WINAPI IDataObject_fnRelease (IDataObject* iface)
492 HlinkImpl *This = HlinkImpl_from_IDataObject(iface);
494 return IHlink_Release((IHlink*)This);
497 static HRESULT WINAPI IDataObject_fnGetData(IDataObject* iface,
498 FORMATETC* pformatetcIn, STGMEDIUM* pmedium)
504 static HRESULT WINAPI IDataObject_fnGetDataHere(IDataObject* iface,
505 FORMATETC* pformatetc, STGMEDIUM* pmedium)
511 static HRESULT WINAPI IDataObject_fnQueryGetData(IDataObject* iface,
512 FORMATETC* pformatetc)
518 static HRESULT WINAPI IDataObject_fnGetConicalFormatEtc(IDataObject* iface,
519 FORMATETC* pformatetcIn, FORMATETC* pformatetcOut)
525 static HRESULT WINAPI IDataObject_fnSetData(IDataObject* iface,
526 FORMATETC* pformatetc, STGMEDIUM* pmedium, BOOL fRelease)
532 static HRESULT WINAPI IDataObject_fnEnumFormatEtc(IDataObject* iface,
533 DWORD dwDirection, IEnumFORMATETC** ppenumFormatEtc)
539 static HRESULT WINAPI IDataObject_fnDAdvise(IDataObject* iface,
540 FORMATETC* pformatetc, DWORD advf, IAdviseSink* pAdvSink,
541 DWORD* pdwConnection)
547 static HRESULT WINAPI IDataObject_fnDUnadvise(IDataObject* iface,
554 static HRESULT WINAPI IDataObject_fnEnumDAdvise(IDataObject* iface,
555 IEnumSTATDATA** ppenumAdvise)
561 static const IDataObjectVtbl dovt =
563 IDataObject_fnQueryInterface,
564 IDataObject_fnAddRef,
565 IDataObject_fnRelease,
566 IDataObject_fnGetData,
567 IDataObject_fnGetDataHere,
568 IDataObject_fnQueryGetData,
569 IDataObject_fnGetConicalFormatEtc,
570 IDataObject_fnSetData,
571 IDataObject_fnEnumFormatEtc,
572 IDataObject_fnDAdvise,
573 IDataObject_fnDUnadvise,
574 IDataObject_fnEnumDAdvise
577 static HRESULT WINAPI IPersistStream_fnQueryInterface(IPersistStream* iface,
578 REFIID riid, LPVOID *ppvObj)
580 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
581 TRACE("(%p)\n", This);
582 return IHlink_QueryInterface((IHlink*)This, riid, ppvObj);
585 static ULONG WINAPI IPersistStream_fnAddRef (IPersistStream* iface)
587 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
588 TRACE("(%p)\n", This);
589 return IHlink_AddRef((IHlink*)This);
592 static ULONG WINAPI IPersistStream_fnRelease (IPersistStream* iface)
594 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
595 TRACE("(%p)\n", This);
596 return IHlink_Release((IHlink*)This);
599 static HRESULT WINAPI IPersistStream_fnGetClassID(IPersistStream* iface,
602 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
603 TRACE("(%p)\n", This);
604 *pClassID = CLSID_StdHlink;
608 static HRESULT WINAPI IPersistStream_fnIsDirty(IPersistStream* iface)
614 static HRESULT write_hlink_string(IStream *pStm, LPCWSTR str)
619 TRACE("(%p, %s)\n", pStm, debugstr_w(str));
621 len = strlenW(str) + 1;
623 hr = IStream_Write(pStm, &len, sizeof(len), NULL);
624 if (FAILED(hr)) return hr;
626 hr = IStream_Write(pStm, str, len * sizeof(WCHAR), NULL);
627 if (FAILED(hr)) return hr;
632 static inline ULONG size_hlink_string(LPCWSTR str)
634 return sizeof(DWORD) + (strlenW(str) + 1) * sizeof(WCHAR);
637 static HRESULT read_hlink_string(IStream *pStm, LPWSTR *out_str)
644 hr = IStream_Read(pStm, &len, sizeof(len), &read);
645 if (FAILED(hr)) return hr;
646 if (read != sizeof(len)) return STG_E_READFAULT;
648 TRACE("read len %d\n", len);
650 str = heap_alloc(len * sizeof(WCHAR));
651 if (!str) return E_OUTOFMEMORY;
653 hr = IStream_Read(pStm, str, len * sizeof(WCHAR), &read);
659 if (read != len * sizeof(WCHAR))
662 return STG_E_READFAULT;
664 TRACE("read string %s\n", debugstr_w(str));
670 static HRESULT WINAPI IPersistStream_fnLoad(IPersistStream* iface,
676 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
678 r = IStream_Read(pStm, hdr, sizeof(hdr), &read);
679 if (read != sizeof(hdr) || (hdr[0] != HLINK_SAVE_MAGIC))
684 if (hdr[1] & ~HLINK_SAVE_ALL)
685 FIXME("unknown flag(s) 0x%x\n", hdr[1] & ~HLINK_SAVE_ALL);
687 if (hdr[1] & HLINK_SAVE_TARGET_FRAME_PRESENT)
689 TRACE("loading target frame name\n");
690 r = read_hlink_string(pStm, &This->TargetFrameName);
691 if (FAILED(r)) goto end;
694 if (hdr[1] & HLINK_SAVE_FRIENDLY_PRESENT)
696 TRACE("loading target friendly name\n");
698 FIXME("0x4 flag not present with friendly name flag - not sure what this means\n");
699 r = read_hlink_string(pStm, &This->FriendlyName);
700 if (FAILED(r)) goto end;
703 if (hdr[1] & HLINK_SAVE_MONIKER_PRESENT)
705 TRACE("loading moniker\n");
706 r = OleLoadFromStream(pStm, &IID_IMoniker, (LPVOID*)&(This->Moniker));
709 This->absolute = hdr[1] & HLINK_SAVE_MONIKER_IS_ABSOLUTE ? TRUE : FALSE;
712 if (hdr[1] & HLINK_SAVE_LOCATION_PRESENT)
714 TRACE("loading location\n");
715 r = read_hlink_string(pStm, &This->Location);
716 if (FAILED(r)) goto end;
720 TRACE("Load Result 0x%x (%p)\n", r, This->Moniker);
725 static HRESULT WINAPI IPersistStream_fnSave(IPersistStream* iface,
726 IStream* pStm, BOOL fClearDirty)
729 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
733 TRACE("(%p) Moniker(%p)\n", This, This->Moniker);
735 __GetMoniker(This, &moniker);
737 hdr[0] = HLINK_SAVE_MAGIC;
741 hdr[1] |= HLINK_SAVE_MONIKER_PRESENT;
743 hdr[1] |= HLINK_SAVE_MONIKER_IS_ABSOLUTE;
745 hdr[1] |= HLINK_SAVE_LOCATION_PRESENT;
746 if (This->FriendlyName)
747 hdr[1] |= HLINK_SAVE_FRIENDLY_PRESENT | 4 /* FIXME */;
748 if (This->TargetFrameName)
749 hdr[1] |= HLINK_SAVE_TARGET_FRAME_PRESENT;
751 IStream_Write(pStm, hdr, sizeof(hdr), NULL);
753 if (This->TargetFrameName)
755 r = write_hlink_string(pStm, This->TargetFrameName);
756 if (FAILED(r)) goto end;
759 if (This->FriendlyName)
761 r = write_hlink_string(pStm, This->FriendlyName);
762 if (FAILED(r)) goto end;
767 IPersistStream* monstream;
770 IMoniker_QueryInterface(moniker, &IID_IPersistStream,
771 (LPVOID*)&monstream);
774 r = OleSaveToStream(monstream, pStm);
775 IPersistStream_Release(monstream);
777 if (FAILED(r)) goto end;
782 r = write_hlink_string(pStm, This->Location);
783 if (FAILED(r)) goto end;
787 if (moniker) IMoniker_Release(moniker);
788 TRACE("Save Result 0x%x\n", r);
793 static HRESULT WINAPI IPersistStream_fnGetSizeMax(IPersistStream* iface,
794 ULARGE_INTEGER* pcbSize)
797 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
800 TRACE("(%p) Moniker(%p)\n", This, This->Moniker);
802 pcbSize->QuadPart = sizeof(DWORD)*2;
804 if (This->TargetFrameName)
805 pcbSize->QuadPart += size_hlink_string(This->TargetFrameName);
807 if (This->FriendlyName)
808 pcbSize->QuadPart += size_hlink_string(This->FriendlyName);
810 __GetMoniker(This, &moniker);
813 IPersistStream* monstream = NULL;
814 IMoniker_QueryInterface(moniker, &IID_IPersistStream,
815 (LPVOID*)&monstream);
818 ULARGE_INTEGER mon_size;
819 r = IPersistStream_GetSizeMax(monstream, &mon_size);
820 pcbSize->QuadPart += mon_size.QuadPart;
821 IPersistStream_Release(monstream);
823 IMoniker_Release(moniker);
827 pcbSize->QuadPart += size_hlink_string(This->Location);
832 static const IPersistStreamVtbl psvt =
834 IPersistStream_fnQueryInterface,
835 IPersistStream_fnAddRef,
836 IPersistStream_fnRelease,
837 IPersistStream_fnGetClassID,
838 IPersistStream_fnIsDirty,
839 IPersistStream_fnLoad,
840 IPersistStream_fnSave,
841 IPersistStream_fnGetSizeMax,