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
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(hlink);
42 #define HLINK_SAVE_MAGIC 0x00000002
43 #define HLINK_SAVE_MONIKER_PRESENT 0x01
44 #define HLINK_SAVE_MONIKER_IS_ABSOLUTE 0x02
45 #define HLINK_SAVE_LOCATION_PRESENT 0x08
46 #define HLINK_SAVE_FRIENDLY_PRESENT 0x10
47 /* 0x20, 0x40 unknown */
48 #define HLINK_SAVE_TARGET_FRAME_PRESENT 0x80
50 static const IHlinkVtbl hlvt;
51 static const IPersistStreamVtbl psvt;
52 static const IDataObjectVtbl dovt;
56 const IHlinkVtbl *lpVtbl;
59 const IPersistStreamVtbl *lpPSVtbl;
60 const IDataObjectVtbl *lpDOVtbl;
65 LPWSTR TargetFrameName;
73 static inline HlinkImpl* HlinkImpl_from_IPersistStream( IPersistStream* iface)
75 return (HlinkImpl*) ((CHAR*)iface - FIELD_OFFSET(HlinkImpl, lpPSVtbl));
78 static inline HlinkImpl* HlinkImpl_from_IDataObject( IDataObject* iface)
80 return (HlinkImpl*) ((CHAR*)iface - FIELD_OFFSET(HlinkImpl, lpDOVtbl));
83 static inline LPWSTR strdupW( LPCWSTR str )
90 len = (lstrlenW(str)+1) * sizeof (WCHAR);
91 r = HeapAlloc(GetProcessHeap(), 0, len);
97 static inline LPWSTR co_strdupW( LPCWSTR str )
104 len = (lstrlenW(str)+1) * sizeof (WCHAR);
105 r = CoTaskMemAlloc(len);
111 static inline void __GetMoniker(HlinkImpl* This, IMoniker** moniker)
116 *moniker = This->Moniker;
118 IMoniker_AddRef(*moniker);
122 IHlinkSite_GetMoniker(This->Site, This->SiteData,
123 OLEGETMONIKER_FORCEASSIGN, OLEWHICHMK_CONTAINER,
128 HRESULT WINAPI HLink_Constructor(IUnknown *pUnkOuter, REFIID riid,
133 TRACE("unkOut=%p riid=%s\n", pUnkOuter, debugstr_guid(riid));
137 return CLASS_E_NOAGGREGATION;
139 hl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HlinkImpl));
141 return E_OUTOFMEMORY;
145 hl->lpPSVtbl = &psvt;
146 hl->lpDOVtbl = &dovt;
152 static HRESULT WINAPI IHlink_fnQueryInterface(IHlink* iface, REFIID riid,
155 HlinkImpl *This = (HlinkImpl*)iface;
157 TRACE ("(%p)->(%s,%p)\n", This, debugstr_guid (riid), ppvObj);
161 if (IsEqualIID(riid, &IID_IUnknown) || (IsEqualIID(riid, &IID_IHlink)))
163 else if (IsEqualIID(riid, &IID_IPersistStream))
164 *ppvObj = (LPVOID*)&(This->lpPSVtbl);
165 else if (IsEqualIID(riid, &IID_IDataObject))
166 *ppvObj = (LPVOID*)&(This->lpDOVtbl);
170 IUnknown_AddRef((IUnknown*)(*ppvObj));
173 return E_NOINTERFACE;
176 static ULONG WINAPI IHlink_fnAddRef (IHlink* iface)
178 HlinkImpl *This = (HlinkImpl*)iface;
179 ULONG refCount = InterlockedIncrement(&This->ref);
181 TRACE("(%p)->(count=%u)\n", This, refCount - 1);
186 static ULONG WINAPI IHlink_fnRelease (IHlink* iface)
188 HlinkImpl *This = (HlinkImpl*)iface;
189 ULONG refCount = InterlockedDecrement(&This->ref);
191 TRACE("(%p)->(count=%u)\n", This, refCount + 1);
195 TRACE("-- destroying IHlink (%p)\n", This);
196 HeapFree(GetProcessHeap(), 0, This->FriendlyName);
197 HeapFree(GetProcessHeap(), 0, This->Target);
198 HeapFree(GetProcessHeap(), 0, This->TargetFrameName);
199 HeapFree(GetProcessHeap(), 0, This->Location);
201 IMoniker_Release(This->Moniker);
203 IHlinkSite_Release(This->Site);
204 HeapFree(GetProcessHeap(), 0, This);
208 static HRESULT WINAPI IHlink_fnSetHlinkSite( IHlink* iface,
209 IHlinkSite* pihlSite, DWORD dwSiteData)
211 HlinkImpl *This = (HlinkImpl*)iface;
213 TRACE("(%p)->(%p %i)\n", This, pihlSite, dwSiteData);
216 IHlinkSite_Release(This->Site);
218 This->Site = pihlSite;
220 IHlinkSite_AddRef(This->Site);
222 This->SiteData = dwSiteData;
227 static HRESULT WINAPI IHlink_fnGetHlinkSite( IHlink* iface,
228 IHlinkSite** ppihlSite, DWORD *pdwSiteData)
230 HlinkImpl *This = (HlinkImpl*)iface;
232 TRACE("(%p)->(%p %p)\n", This, ppihlSite, pdwSiteData);
234 *ppihlSite = This->Site;
235 *pdwSiteData = This->SiteData;
238 IHlinkSite_AddRef(This->Site);
243 static HRESULT WINAPI IHlink_fnSetMonikerReference( IHlink* iface,
244 DWORD rfHLSETF, IMoniker *pmkTarget, LPCWSTR pwzLocation)
246 HlinkImpl *This = (HlinkImpl*)iface;
248 FIXME("(%p)->(%i %p %s)\n", This, rfHLSETF, pmkTarget,
249 debugstr_w(pwzLocation));
252 IMoniker_Release(This->Moniker);
254 This->Moniker = pmkTarget;
257 LPOLESTR display_name;
258 IMoniker_AddRef(This->Moniker);
259 IMoniker_GetDisplayName(This->Moniker, NULL, NULL, &display_name);
260 This->absolute = display_name && strchrW(display_name, ':');
261 CoTaskMemFree(display_name);
264 HeapFree(GetProcessHeap(), 0, This->Location);
265 This->Location = strdupW( pwzLocation );
270 static HRESULT WINAPI IHlink_fnSetStringReference(IHlink* iface,
271 DWORD grfHLSETF, LPCWSTR pwzTarget, LPCWSTR pwzLocation)
273 HlinkImpl *This = (HlinkImpl*)iface;
275 TRACE("(%p)->(%i %s %s)\n", This, grfHLSETF, debugstr_w(pwzTarget),
276 debugstr_w(pwzLocation));
278 if (grfHLSETF & HLINKSETF_TARGET)
280 HeapFree(GetProcessHeap(), 0, This->Target);
281 This->Target = strdupW( pwzTarget );
283 if (grfHLSETF & HLINKSETF_LOCATION)
285 HeapFree(GetProcessHeap(), 0, This->Location);
286 This->Location = strdupW( pwzLocation );
292 static HRESULT WINAPI IHlink_fnGetMonikerReference(IHlink* iface,
293 DWORD dwWhichRef, IMoniker **ppimkTarget, LPWSTR *ppwzLocation)
295 HlinkImpl *This = (HlinkImpl*)iface;
297 TRACE("(%p) -> (%i %p %p)\n", This, dwWhichRef, ppimkTarget,
301 __GetMoniker(This, ppimkTarget);
304 IHlink_GetStringReference(iface, dwWhichRef, NULL, ppwzLocation);
309 static HRESULT WINAPI IHlink_fnGetStringReference (IHlink* iface,
310 DWORD dwWhichRef, LPWSTR *ppwzTarget, LPWSTR *ppwzLocation)
312 HlinkImpl *This = (HlinkImpl*)iface;
314 FIXME("(%p) -> (%i %p %p)\n", This, dwWhichRef, ppwzTarget, ppwzLocation);
318 *ppwzTarget = co_strdupW( This->Target );
323 __GetMoniker(This, &mon);
328 CreateBindCtx( 0, &pbc);
329 IMoniker_GetDisplayName(mon, pbc, NULL, ppwzTarget);
330 IBindCtx_Release(pbc);
331 IMoniker_Release(mon);
334 FIXME("Unhandled case, no set Target and no moniker\n");
338 *ppwzLocation = co_strdupW( This->Location );
340 TRACE("(Target: %s Location: %s)\n",
341 (ppwzTarget)?debugstr_w(*ppwzTarget):"<NULL>",
342 (ppwzLocation)?debugstr_w(*ppwzLocation):"<NULL>");
347 static HRESULT WINAPI IHlink_fnSetFriendlyName (IHlink *iface,
348 LPCWSTR pwzFriendlyName)
350 HlinkImpl *This = (HlinkImpl*)iface;
352 TRACE("(%p) -> (%s)\n", This, debugstr_w(pwzFriendlyName));
354 HeapFree(GetProcessHeap(), 0, This->FriendlyName);
355 This->FriendlyName = strdupW( pwzFriendlyName );
360 static HRESULT WINAPI IHlink_fnGetFriendlyName (IHlink* iface,
361 DWORD grfHLFNAMEF, LPWSTR* ppwzFriendlyName)
363 HlinkImpl *This = (HlinkImpl*)iface;
365 TRACE("(%p) -> (%i %p)\n", This, grfHLFNAMEF, ppwzFriendlyName);
367 /* FIXME: Only using explicitly set and cached friendly names */
369 if (This->FriendlyName)
370 *ppwzFriendlyName = co_strdupW( This->FriendlyName );
374 __GetMoniker(This, &moniker);
378 CreateBindCtx(0, &bcxt);
380 IMoniker_GetDisplayName(moniker, bcxt, NULL, ppwzFriendlyName);
381 IBindCtx_Release(bcxt);
382 IMoniker_Release(moniker);
385 *ppwzFriendlyName = NULL;
391 static HRESULT WINAPI IHlink_fnSetTargetFrameName(IHlink* iface,
392 LPCWSTR pwzTargetFramename)
394 HlinkImpl *This = (HlinkImpl*)iface;
395 TRACE("(%p)->(%s)\n", This, debugstr_w(pwzTargetFramename));
397 HeapFree(GetProcessHeap(), 0, This->TargetFrameName);
398 This->TargetFrameName = strdupW( pwzTargetFramename );
403 static HRESULT WINAPI IHlink_fnGetTargetFrameName(IHlink* iface,
404 LPWSTR *ppwzTargetFrameName)
406 HlinkImpl *This = (HlinkImpl*)iface;
408 TRACE("(%p)->(%p)\n", This, ppwzTargetFrameName);
409 *ppwzTargetFrameName = co_strdupW( This->TargetFrameName );
414 static HRESULT WINAPI IHlink_fnGetMiscStatus(IHlink* iface, DWORD* pdwStatus)
420 static HRESULT WINAPI IHlink_fnNavigate(IHlink* iface, DWORD grfHLNF, LPBC pbc,
421 IBindStatusCallback *pbsc, IHlinkBrowseContext *phbc)
423 HlinkImpl *This = (HlinkImpl*)iface;
424 IMoniker *mon = NULL;
426 FIXME("Semi-Stub:(%p)->(%i %p %p %p)\n", This, grfHLNF, pbc, pbsc, phbc);
429 IHlinkSite_ReadyToNavigate(This->Site, This->SiteData, 0);
431 __GetMoniker(This, &mon);
432 TRACE("Moniker %p\n", mon);
437 IHlinkTarget *target = NULL;
440 CreateBindCtx(0, &bcxt);
442 RegisterBindStatusCallback(bcxt, pbsc, NULL, 0);
444 r = IMoniker_BindToObject(mon, bcxt, NULL, &IID_IHlinkTarget,
446 TRACE("IHlinkTarget returned 0x%x\n", r);
449 IHlinkTarget_SetBrowseContext(target, phbc);
450 IHlinkTarget_Navigate(target, grfHLNF, This->Location);
451 IHlinkTarget_Release(target);
455 static const WCHAR szOpen[] = {'o','p','e','n',0};
456 LPWSTR target = NULL;
458 r = IHlink_GetStringReference(iface, HLINKGETREF_DEFAULT, &target, NULL);
459 if (SUCCEEDED(r) && target)
461 ShellExecuteW(NULL, szOpen, target, NULL, NULL, SW_SHOW);
462 CoTaskMemFree(target);
466 RevokeBindStatusCallback(bcxt, pbsc);
468 IBindCtx_Release(bcxt);
469 IMoniker_Release(mon);
473 IHlinkSite_OnNavigationComplete(This->Site, This->SiteData, 0, 0, NULL);
475 TRACE("Finished Navigation\n");
479 static HRESULT WINAPI IHlink_fnSetAdditonalParams(IHlink* iface,
480 LPCWSTR pwzAdditionalParams)
486 static HRESULT WINAPI IHlink_fnGetAdditionalParams(IHlink* iface,
487 LPWSTR* ppwzAdditionalParams)
493 static const IHlinkVtbl hlvt =
495 IHlink_fnQueryInterface,
498 IHlink_fnSetHlinkSite,
499 IHlink_fnGetHlinkSite,
500 IHlink_fnSetMonikerReference,
501 IHlink_fnGetMonikerReference,
502 IHlink_fnSetStringReference,
503 IHlink_fnGetStringReference,
504 IHlink_fnSetFriendlyName,
505 IHlink_fnGetFriendlyName,
506 IHlink_fnSetTargetFrameName,
507 IHlink_fnGetTargetFrameName,
508 IHlink_fnGetMiscStatus,
510 IHlink_fnSetAdditonalParams,
511 IHlink_fnGetAdditionalParams
514 static HRESULT WINAPI IDataObject_fnQueryInterface(IDataObject* iface,
515 REFIID riid, LPVOID *ppvObj)
517 HlinkImpl *This = HlinkImpl_from_IDataObject(iface);
519 return IHlink_QueryInterface((IHlink*)This, riid, ppvObj);
522 static ULONG WINAPI IDataObject_fnAddRef (IDataObject* iface)
524 HlinkImpl *This = HlinkImpl_from_IDataObject(iface);
526 return IHlink_AddRef((IHlink*)This);
529 static ULONG WINAPI IDataObject_fnRelease (IDataObject* iface)
531 HlinkImpl *This = HlinkImpl_from_IDataObject(iface);
533 return IHlink_Release((IHlink*)This);
536 static HRESULT WINAPI IDataObject_fnGetData(IDataObject* iface,
537 FORMATETC* pformatetcIn, STGMEDIUM* pmedium)
543 static HRESULT WINAPI IDataObject_fnGetDataHere(IDataObject* iface,
544 FORMATETC* pformatetc, STGMEDIUM* pmedium)
550 static HRESULT WINAPI IDataObject_fnQueryGetData(IDataObject* iface,
551 FORMATETC* pformatetc)
557 static HRESULT WINAPI IDataObject_fnGetConicalFormatEtc(IDataObject* iface,
558 FORMATETC* pformatetcIn, FORMATETC* pformatetcOut)
564 static HRESULT WINAPI IDataObject_fnSetData(IDataObject* iface,
565 FORMATETC* pformatetc, STGMEDIUM* pmedium, BOOL fRelease)
571 static HRESULT WINAPI IDataObject_fnEnumFormatEtc(IDataObject* iface,
572 DWORD dwDirection, IEnumFORMATETC** ppenumFormatEtc)
578 static HRESULT WINAPI IDataObject_fnDAdvise(IDataObject* iface,
579 FORMATETC* pformatetc, DWORD advf, IAdviseSink* pAdvSink,
580 DWORD* pdwConnection)
586 static HRESULT WINAPI IDataObject_fnDUnadvise(IDataObject* iface,
593 static HRESULT WINAPI IDataObject_fnEnumDAdvise(IDataObject* iface,
594 IEnumSTATDATA** ppenumAdvise)
600 static const IDataObjectVtbl dovt =
602 IDataObject_fnQueryInterface,
603 IDataObject_fnAddRef,
604 IDataObject_fnRelease,
605 IDataObject_fnGetData,
606 IDataObject_fnGetDataHere,
607 IDataObject_fnQueryGetData,
608 IDataObject_fnGetConicalFormatEtc,
609 IDataObject_fnSetData,
610 IDataObject_fnEnumFormatEtc,
611 IDataObject_fnDAdvise,
612 IDataObject_fnDUnadvise,
613 IDataObject_fnEnumDAdvise
616 static HRESULT WINAPI IPersistStream_fnQueryInterface(IPersistStream* iface,
617 REFIID riid, LPVOID *ppvObj)
619 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
620 TRACE("(%p)\n", This);
621 return IHlink_QueryInterface((IHlink*)This, riid, ppvObj);
624 static ULONG WINAPI IPersistStream_fnAddRef (IPersistStream* iface)
626 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
627 TRACE("(%p)\n", This);
628 return IHlink_AddRef((IHlink*)This);
631 static ULONG WINAPI IPersistStream_fnRelease (IPersistStream* iface)
633 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
634 TRACE("(%p)\n", This);
635 return IHlink_Release((IHlink*)This);
638 static HRESULT WINAPI IPersistStream_fnGetClassID(IPersistStream* iface,
641 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
642 TRACE("(%p)\n", This);
643 memcpy(pClassID, &CLSID_StdHlink, sizeof(CLSID));
647 static HRESULT WINAPI IPersistStream_fnIsDirty(IPersistStream* iface)
653 static HRESULT WINAPI IPersistStream_fnLoad(IPersistStream* iface,
656 HRESULT r = E_NOTIMPL;
659 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
661 IStream_Read(pStm, &hdr, sizeof(hdr), &read);
662 /* FIXME: unknown header values */
664 r = OleLoadFromStream(pStm, &IID_IMoniker, (LPVOID*)&(This->Moniker));
665 TRACE("Load Result 0x%x (%p)\n", r, This->Moniker);
670 static HRESULT write_hlink_string(IStream *pStm, LPCWSTR str)
675 TRACE("(%p, %s)\n", pStm, debugstr_w(str));
677 len = strlenW(str) + 1;
679 hr = IStream_Write(pStm, &len, sizeof(len), NULL);
680 /* FIXME: error checking */
682 hr = IStream_Write(pStm, str, len * sizeof(WCHAR), NULL);
683 /* FIXME: error checking */
688 static inline ULONG size_hlink_string(LPCWSTR str)
690 return sizeof(DWORD) + (strlenW(str) + 1) * sizeof(WCHAR);
693 static HRESULT WINAPI IPersistStream_fnSave(IPersistStream* iface,
694 IStream* pStm, BOOL fClearDirty)
697 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
701 TRACE("(%p) Moniker(%p)\n", This, This->Moniker);
703 __GetMoniker(This, &moniker);
705 hdr[0] = HLINK_SAVE_MAGIC;
709 hdr[1] |= HLINK_SAVE_MONIKER_PRESENT;
711 hdr[1] |= HLINK_SAVE_MONIKER_IS_ABSOLUTE;
713 hdr[1] |= HLINK_SAVE_LOCATION_PRESENT;
714 if (This->FriendlyName)
715 hdr[1] |= HLINK_SAVE_FRIENDLY_PRESENT | 4 /* FIXME */;
716 if (This->TargetFrameName)
717 hdr[1] |= HLINK_SAVE_TARGET_FRAME_PRESENT;
719 IStream_Write(pStm, &hdr, sizeof(hdr), NULL);
721 if (This->TargetFrameName)
723 r = write_hlink_string(pStm, This->TargetFrameName);
724 if (FAILED(r)) goto end;
727 if (This->FriendlyName)
729 r = write_hlink_string(pStm, This->FriendlyName);
730 if (FAILED(r)) goto end;
735 IPersistStream* monstream;
738 IMoniker_QueryInterface(moniker, &IID_IPersistStream,
739 (LPVOID*)&monstream);
742 r = OleSaveToStream(monstream, pStm);
743 IPersistStream_Release(monstream);
745 IMoniker_Release(moniker);
750 r = write_hlink_string(pStm, This->Location);
751 if (FAILED(r)) goto end;
755 TRACE("Save Result 0x%x\n", r);
760 static HRESULT WINAPI IPersistStream_fnGetSizeMax(IPersistStream* iface,
761 ULARGE_INTEGER* pcbSize)
764 HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
767 TRACE("(%p) Moniker(%p)\n", This, This->Moniker);
769 pcbSize->QuadPart = sizeof(DWORD)*2;
771 if (This->TargetFrameName)
772 pcbSize->QuadPart += size_hlink_string(This->TargetFrameName);
774 if (This->FriendlyName)
775 pcbSize->QuadPart += size_hlink_string(This->FriendlyName);
777 __GetMoniker(This, &moniker);
780 IPersistStream* monstream = NULL;
781 IMoniker_QueryInterface(moniker, &IID_IPersistStream,
782 (LPVOID*)&monstream);
785 ULARGE_INTEGER mon_size;
786 r = IPersistStream_GetSizeMax(monstream, &mon_size);
787 pcbSize->QuadPart += mon_size.QuadPart;
788 IPersistStream_Release(monstream);
790 IMoniker_Release(moniker);
794 pcbSize->QuadPart += size_hlink_string(This->Location);
799 static const IPersistStreamVtbl psvt =
801 IPersistStream_fnQueryInterface,
802 IPersistStream_fnAddRef,
803 IPersistStream_fnRelease,
804 IPersistStream_fnGetClassID,
805 IPersistStream_fnIsDirty,
806 IPersistStream_fnLoad,
807 IPersistStream_fnSave,
808 IPersistStream_fnGetSizeMax,