hlink: Always pass a bind context to IMoniker::GetDisplayName.
[wine] / dlls / hlink / link.c
1 /*
2  * Implementation of hyperlinking (hlink.dll)
3  *
4  * Copyright 2005 Aric Stewart for CodeWeavers
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "hlink_private.h"
22
23 #include "shellapi.h"
24 #include "hlguids.h"
25
26 #include "wine/debug.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(hlink);
29
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
37 /* known flags */
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)
39
40 typedef struct
41 {
42     IHlink              IHlink_iface;
43     LONG                ref;
44
45     IPersistStream      IPersistStream_iface;
46     IDataObject         IDataObject_iface;
47
48     LPWSTR              FriendlyName;
49     LPWSTR              Location;
50     LPWSTR              TargetFrameName;
51     IMoniker            *Moniker;
52     IHlinkSite          *Site;
53     DWORD               SiteData;
54     BOOL                absolute;
55 } HlinkImpl;
56
57 static inline HlinkImpl *impl_from_IHlink(IHlink *iface)
58 {
59     return CONTAINING_RECORD(iface, HlinkImpl, IHlink_iface);
60 }
61
62
63 static inline HlinkImpl* impl_from_IPersistStream( IPersistStream* iface)
64 {
65     return CONTAINING_RECORD(iface, HlinkImpl, IPersistStream_iface);
66 }
67
68 static inline HlinkImpl* impl_from_IDataObject( IDataObject* iface)
69 {
70     return CONTAINING_RECORD(iface, HlinkImpl, IDataObject_iface);
71 }
72
73 static HRESULT __GetMoniker(HlinkImpl* This, IMoniker** moniker,
74         DWORD ref_type)
75 {
76     HRESULT hres;
77
78     if (ref_type == HLINKGETREF_DEFAULT)
79         ref_type = HLINKGETREF_RELATIVE;
80
81     if (ref_type == HLINKGETREF_ABSOLUTE && This->Site)
82     {
83         IMoniker *hls_moniker;
84
85         hres = IHlinkSite_GetMoniker(This->Site, This->SiteData,
86                 OLEGETMONIKER_FORCEASSIGN, OLEWHICHMK_CONTAINER, &hls_moniker);
87         if (FAILED(hres))
88             return hres;
89
90         if (This->Moniker)
91         {
92             hres = IMoniker_ComposeWith(hls_moniker, This->Moniker, FALSE,
93                     moniker);
94             IMoniker_Release(hls_moniker);
95             return hres;
96         }
97
98         *moniker = hls_moniker;
99         return S_OK;
100     }
101
102     *moniker = This->Moniker;
103     if (*moniker)
104         IMoniker_AddRef(*moniker);
105
106     return S_OK;
107 }
108
109 static HRESULT WINAPI IHlink_fnQueryInterface(IHlink* iface, REFIID riid,
110         LPVOID *ppvObj)
111 {
112     HlinkImpl  *This = impl_from_IHlink(iface);
113
114     TRACE ("(%p)->(%s,%p)\n", This, debugstr_guid (riid), ppvObj);
115
116     *ppvObj = NULL;
117
118     if (IsEqualIID(riid, &IID_IUnknown) || (IsEqualIID(riid, &IID_IHlink)))
119         *ppvObj = This;
120     else if (IsEqualIID(riid, &IID_IPersistStream))
121         *ppvObj = &This->IPersistStream_iface;
122     else if (IsEqualIID(riid, &IID_IDataObject))
123         *ppvObj = &This->IDataObject_iface;
124
125     if (*ppvObj)
126     {
127         IUnknown_AddRef((IUnknown*)(*ppvObj));
128         return S_OK;
129     }
130     return E_NOINTERFACE;
131 }
132
133 static ULONG WINAPI IHlink_fnAddRef (IHlink* iface)
134 {
135     HlinkImpl  *This = impl_from_IHlink(iface);
136     ULONG refCount = InterlockedIncrement(&This->ref);
137
138     TRACE("(%p)->(count=%u)\n", This, refCount - 1);
139
140     return refCount;
141 }
142
143 static ULONG WINAPI IHlink_fnRelease (IHlink* iface)
144 {
145     HlinkImpl  *This = impl_from_IHlink(iface);
146     ULONG refCount = InterlockedDecrement(&This->ref);
147
148     TRACE("(%p)->(count=%u)\n", This, refCount + 1);
149     if (refCount)
150         return refCount;
151
152     TRACE("-- destroying IHlink (%p)\n", This);
153     heap_free(This->FriendlyName);
154     heap_free(This->TargetFrameName);
155     heap_free(This->Location);
156     if (This->Moniker)
157         IMoniker_Release(This->Moniker);
158     if (This->Site)
159         IHlinkSite_Release(This->Site);
160     heap_free(This);
161     return 0;
162 }
163
164 static HRESULT WINAPI IHlink_fnSetHlinkSite( IHlink* iface,
165         IHlinkSite* pihlSite, DWORD dwSiteData)
166 {
167     HlinkImpl  *This = impl_from_IHlink(iface);
168
169     TRACE("(%p)->(%p %i)\n", This, pihlSite, dwSiteData);
170
171     if (This->Site)
172         IHlinkSite_Release(This->Site);
173
174     This->Site = pihlSite;
175     if (This->Site)
176         IHlinkSite_AddRef(This->Site);
177
178     This->SiteData = dwSiteData;
179
180     return S_OK;
181 }
182
183 static HRESULT WINAPI IHlink_fnGetHlinkSite( IHlink* iface,
184         IHlinkSite** ppihlSite, DWORD *pdwSiteData)
185 {
186     HlinkImpl  *This = impl_from_IHlink(iface);
187
188     TRACE("(%p)->(%p %p)\n", This, ppihlSite, pdwSiteData);
189
190     *ppihlSite = This->Site;
191
192     if (This->Site) {
193         IHlinkSite_AddRef(This->Site);
194         *pdwSiteData = This->SiteData;
195     }
196
197     return S_OK;
198 }
199
200 static HRESULT WINAPI IHlink_fnSetMonikerReference( IHlink* iface,
201         DWORD rfHLSETF, IMoniker *pmkTarget, LPCWSTR pwzLocation)
202 {
203     HlinkImpl  *This = impl_from_IHlink(iface);
204
205     TRACE("(%p)->(%i %p %s)\n", This, rfHLSETF, pmkTarget,
206             debugstr_w(pwzLocation));
207
208     if(rfHLSETF == 0)
209         return E_INVALIDARG;
210     if(!(rfHLSETF & (HLINKSETF_TARGET | HLINKSETF_LOCATION)))
211         return rfHLSETF;
212
213     if(rfHLSETF & HLINKSETF_TARGET){
214         if (This->Moniker)
215             IMoniker_Release(This->Moniker);
216
217         This->Moniker = pmkTarget;
218         if (This->Moniker)
219         {
220             IBindCtx *pbc;
221             LPOLESTR display_name;
222             IMoniker_AddRef(This->Moniker);
223             CreateBindCtx( 0, &pbc);
224             IMoniker_GetDisplayName(This->Moniker, pbc, NULL, &display_name);
225             IBindCtx_Release(pbc);
226             This->absolute = display_name && strchrW(display_name, ':');
227             CoTaskMemFree(display_name);
228         }
229     }
230
231     if(rfHLSETF & HLINKSETF_LOCATION){
232         heap_free(This->Location);
233         This->Location = hlink_strdupW( pwzLocation );
234     }
235
236     return S_OK;
237 }
238
239 static HRESULT WINAPI IHlink_fnSetStringReference(IHlink* iface,
240         DWORD grfHLSETF, LPCWSTR pwzTarget, LPCWSTR pwzLocation)
241 {
242     HlinkImpl  *This = impl_from_IHlink(iface);
243
244     TRACE("(%p)->(%i %s %s)\n", This, grfHLSETF, debugstr_w(pwzTarget),
245             debugstr_w(pwzLocation));
246
247     if(grfHLSETF > (HLINKSETF_TARGET | HLINKSETF_LOCATION) &&
248             grfHLSETF < -(HLINKSETF_TARGET | HLINKSETF_LOCATION))
249         return grfHLSETF;
250
251     if (grfHLSETF & HLINKSETF_TARGET)
252     {
253         if (This->Moniker)
254         {
255             IMoniker_Release(This->Moniker);
256             This->Moniker = NULL;
257         }
258         if (pwzTarget && *pwzTarget)
259         {
260             IMoniker *pMon;
261             IBindCtx *pbc = NULL;
262             ULONG eaten;
263             HRESULT r;
264
265             r = CreateBindCtx(0, &pbc);
266             if (FAILED(r))
267                 return E_OUTOFMEMORY;
268
269             r = MkParseDisplayName(pbc, pwzTarget, &eaten, &pMon);
270             IBindCtx_Release(pbc);
271
272             if (FAILED(r))
273             {
274                 LPCWSTR p = strchrW(pwzTarget, ':');
275                 if (p && (p - pwzTarget > 1))
276                     r = CreateURLMoniker(NULL, pwzTarget, &pMon);
277                 else
278                     r = CreateFileMoniker(pwzTarget, &pMon);
279                 if (FAILED(r))
280                 {
281                     ERR("couldn't create moniker for %s, failed with error 0x%08x\n",
282                         debugstr_w(pwzTarget), r);
283                     return r;
284                 }
285             }
286
287             IHlink_SetMonikerReference(iface, HLINKSETF_TARGET, pMon, NULL);
288             IMoniker_Release(pMon);
289         }
290     }
291
292     if (grfHLSETF & HLINKSETF_LOCATION)
293     {
294         heap_free(This->Location);
295         This->Location = NULL;
296         if (pwzLocation && *pwzLocation)
297             This->Location = hlink_strdupW( pwzLocation );
298     }
299
300     return S_OK;
301 }
302
303 static HRESULT WINAPI IHlink_fnGetMonikerReference(IHlink* iface,
304         DWORD dwWhichRef, IMoniker **ppimkTarget, LPWSTR *ppwzLocation)
305 {
306     HlinkImpl  *This = impl_from_IHlink(iface);
307
308     TRACE("(%p) -> (%i %p %p)\n", This, dwWhichRef, ppimkTarget,
309             ppwzLocation);
310
311     if (ppimkTarget)
312     {
313         HRESULT hres = __GetMoniker(This, ppimkTarget, dwWhichRef);
314         if (FAILED(hres))
315         {
316             if (ppwzLocation)
317                 *ppwzLocation = NULL;
318             return hres;
319         }
320     }
321
322     if (ppwzLocation)
323         IHlink_GetStringReference(iface, dwWhichRef, NULL, ppwzLocation);
324
325     return S_OK;
326 }
327
328 static HRESULT WINAPI IHlink_fnGetStringReference (IHlink* iface,
329         DWORD dwWhichRef, LPWSTR *ppwzTarget, LPWSTR *ppwzLocation)
330 {
331     HlinkImpl  *This = impl_from_IHlink(iface);
332
333     TRACE("(%p) -> (%i %p %p)\n", This, dwWhichRef, ppwzTarget, ppwzLocation);
334
335     if(dwWhichRef != -1 && dwWhichRef & ~(HLINKGETREF_DEFAULT | HLINKGETREF_ABSOLUTE | HLINKGETREF_RELATIVE))
336     {
337         if(ppwzTarget)
338             *ppwzTarget = NULL;
339         if(ppwzLocation)
340             *ppwzLocation = NULL;
341         return E_INVALIDARG;
342     }
343
344     if (ppwzTarget)
345     {
346         IMoniker* mon;
347         HRESULT hres = __GetMoniker(This, &mon, dwWhichRef);
348         if (FAILED(hres))
349         {
350             if (ppwzLocation)
351                 *ppwzLocation = NULL;
352             return hres;
353         }
354         if (mon)
355         {
356             IBindCtx *pbc;
357
358             CreateBindCtx( 0, &pbc);
359             IMoniker_GetDisplayName(mon, pbc, NULL, ppwzTarget);
360             IBindCtx_Release(pbc);
361             IMoniker_Release(mon);
362         }
363         else
364             *ppwzTarget = NULL;
365     }
366     if (ppwzLocation)
367         *ppwzLocation = hlink_co_strdupW( This->Location );
368
369     TRACE("(Target: %s Location: %s)\n",
370             (ppwzTarget)?debugstr_w(*ppwzTarget):"<NULL>",
371             (ppwzLocation)?debugstr_w(*ppwzLocation):"<NULL>");
372
373     return S_OK;
374 }
375
376 static HRESULT WINAPI IHlink_fnSetFriendlyName (IHlink *iface,
377         LPCWSTR pwzFriendlyName)
378 {
379     HlinkImpl  *This = impl_from_IHlink(iface);
380
381     TRACE("(%p) -> (%s)\n", This, debugstr_w(pwzFriendlyName));
382
383     heap_free(This->FriendlyName);
384     This->FriendlyName = hlink_strdupW( pwzFriendlyName );
385
386     return S_OK;
387 }
388
389 static HRESULT WINAPI IHlink_fnGetFriendlyName (IHlink* iface,
390         DWORD grfHLFNAMEF, LPWSTR* ppwzFriendlyName)
391 {
392     HlinkImpl  *This = impl_from_IHlink(iface);
393
394     TRACE("(%p) -> (%i %p)\n", This, grfHLFNAMEF, ppwzFriendlyName);
395
396     /* FIXME: Only using explicitly set and cached friendly names */
397
398     if (This->FriendlyName)
399         *ppwzFriendlyName = hlink_co_strdupW( This->FriendlyName );
400     else
401     {
402         IMoniker *moniker;
403         HRESULT hres = __GetMoniker(This, &moniker, HLINKGETREF_DEFAULT);
404         if (FAILED(hres))
405         {
406             *ppwzFriendlyName = NULL;
407             return hres;
408         }
409         if (moniker)
410         {
411             IBindCtx *bcxt;
412             CreateBindCtx(0, &bcxt);
413
414             IMoniker_GetDisplayName(moniker, bcxt, NULL, ppwzFriendlyName);
415             IBindCtx_Release(bcxt);
416             IMoniker_Release(moniker);
417         }
418         else
419             *ppwzFriendlyName = NULL;
420     }
421
422     return S_OK;
423 }
424
425 static HRESULT WINAPI IHlink_fnSetTargetFrameName(IHlink* iface,
426         LPCWSTR pwzTargetFramename)
427 {
428     HlinkImpl  *This = impl_from_IHlink(iface);
429     TRACE("(%p)->(%s)\n", This, debugstr_w(pwzTargetFramename));
430
431     heap_free(This->TargetFrameName);
432     This->TargetFrameName = hlink_strdupW( pwzTargetFramename );
433
434     return S_OK;
435 }
436
437 static HRESULT WINAPI IHlink_fnGetTargetFrameName(IHlink* iface,
438         LPWSTR *ppwzTargetFrameName)
439 {
440     HlinkImpl  *This = impl_from_IHlink(iface);
441
442     TRACE("(%p)->(%p)\n", This, ppwzTargetFrameName);
443
444     if(!This->TargetFrameName) {
445         *ppwzTargetFrameName = NULL;
446         return S_FALSE;
447     }
448
449     *ppwzTargetFrameName = hlink_co_strdupW( This->TargetFrameName );
450     if(!*ppwzTargetFrameName)
451         return E_OUTOFMEMORY;
452
453     return S_OK;
454 }
455
456 static HRESULT WINAPI IHlink_fnGetMiscStatus(IHlink* iface, DWORD* pdwStatus)
457 {
458     FIXME("\n");
459     return E_NOTIMPL;
460 }
461
462 static HRESULT WINAPI IHlink_fnNavigate(IHlink* iface, DWORD grfHLNF, LPBC pbc,
463         IBindStatusCallback *pbsc, IHlinkBrowseContext *phbc)
464 {
465     HlinkImpl  *This = impl_from_IHlink(iface);
466     IMoniker *mon = NULL;
467     HRESULT r;
468
469     FIXME("Semi-Stub:(%p)->(%i %p %p %p)\n", This, grfHLNF, pbc, pbsc, phbc);
470
471     r = __GetMoniker(This, &mon, HLINKGETREF_ABSOLUTE);
472     TRACE("Moniker %p\n", mon);
473
474     if (SUCCEEDED(r))
475     {
476         IBindCtx *bcxt;
477         IHlinkTarget *target = NULL;
478
479         CreateBindCtx(0, &bcxt);
480
481         RegisterBindStatusCallback(bcxt, pbsc, NULL, 0);
482
483         r = IMoniker_BindToObject(mon, bcxt, NULL, &IID_IHlinkTarget,
484                 (LPVOID*)&target);
485         TRACE("IHlinkTarget returned 0x%x\n", r);
486         if (r == S_OK)
487         {
488             IHlinkTarget_SetBrowseContext(target, phbc);
489             IHlinkTarget_Navigate(target, grfHLNF, This->Location);
490             IHlinkTarget_Release(target);
491         }
492         else
493         {
494             static const WCHAR szOpen[] = {'o','p','e','n',0};
495             LPWSTR target = NULL;
496
497             r = IHlink_GetStringReference(iface, HLINKGETREF_DEFAULT, &target, NULL);
498             if (SUCCEEDED(r) && target)
499             {
500                 ShellExecuteW(NULL, szOpen, target, NULL, NULL, SW_SHOW);
501                 CoTaskMemFree(target);
502             }
503         }
504
505         RevokeBindStatusCallback(bcxt, pbsc);
506
507         IBindCtx_Release(bcxt);
508         IMoniker_Release(mon);
509     }
510
511     if (This->Site)
512         IHlinkSite_OnNavigationComplete(This->Site, This->SiteData, 0, r, NULL);
513
514     TRACE("Finished Navigation\n");
515     return r;
516 }
517
518 static HRESULT WINAPI IHlink_fnSetAdditonalParams(IHlink* iface,
519         LPCWSTR pwzAdditionalParams)
520 {
521     TRACE("Not implemented in native IHlink\n");
522     return E_NOTIMPL;
523 }
524
525 static HRESULT WINAPI IHlink_fnGetAdditionalParams(IHlink* iface,
526         LPWSTR* ppwzAdditionalParams)
527 {
528     TRACE("Not implemented in native IHlink\n");
529     return E_NOTIMPL;
530 }
531
532 static const IHlinkVtbl hlvt =
533 {
534     IHlink_fnQueryInterface,
535     IHlink_fnAddRef,
536     IHlink_fnRelease,
537     IHlink_fnSetHlinkSite,
538     IHlink_fnGetHlinkSite,
539     IHlink_fnSetMonikerReference,
540     IHlink_fnGetMonikerReference,
541     IHlink_fnSetStringReference,
542     IHlink_fnGetStringReference,
543     IHlink_fnSetFriendlyName,
544     IHlink_fnGetFriendlyName,
545     IHlink_fnSetTargetFrameName,
546     IHlink_fnGetTargetFrameName,
547     IHlink_fnGetMiscStatus,
548     IHlink_fnNavigate,
549     IHlink_fnSetAdditonalParams,
550     IHlink_fnGetAdditionalParams
551 };
552
553 static HRESULT WINAPI IDataObject_fnQueryInterface(IDataObject* iface,
554         REFIID riid, LPVOID *ppvObj)
555 {
556     HlinkImpl *This = impl_from_IDataObject(iface);
557     TRACE("%p\n", This);
558     return IHlink_QueryInterface(&This->IHlink_iface, riid, ppvObj);
559 }
560
561 static ULONG WINAPI IDataObject_fnAddRef (IDataObject* iface)
562 {
563     HlinkImpl *This = impl_from_IDataObject(iface);
564     TRACE("%p\n", This);
565     return IHlink_AddRef(&This->IHlink_iface);
566 }
567
568 static ULONG WINAPI IDataObject_fnRelease (IDataObject* iface)
569 {
570     HlinkImpl *This = impl_from_IDataObject(iface);
571     TRACE("%p\n", This);
572     return IHlink_Release(&This->IHlink_iface);
573 }
574
575 static HRESULT WINAPI IDataObject_fnGetData(IDataObject* iface,
576         FORMATETC* pformatetcIn, STGMEDIUM* pmedium)
577 {
578     FIXME("\n");
579     return E_NOTIMPL;
580 }
581
582 static HRESULT WINAPI IDataObject_fnGetDataHere(IDataObject* iface,
583         FORMATETC* pformatetc, STGMEDIUM* pmedium)
584 {
585     FIXME("\n");
586     return E_NOTIMPL;
587 }
588
589 static HRESULT WINAPI IDataObject_fnQueryGetData(IDataObject* iface,
590         FORMATETC* pformatetc)
591 {
592     FIXME("\n");
593     return E_NOTIMPL;
594 }
595
596 static HRESULT WINAPI IDataObject_fnGetConicalFormatEtc(IDataObject* iface,
597         FORMATETC* pformatetcIn, FORMATETC* pformatetcOut)
598 {
599     FIXME("\n");
600     return E_NOTIMPL;
601 }
602
603 static HRESULT WINAPI IDataObject_fnSetData(IDataObject* iface,
604         FORMATETC* pformatetc, STGMEDIUM* pmedium, BOOL fRelease)
605 {
606     FIXME("\n");
607     return E_NOTIMPL;
608 }
609
610 static HRESULT WINAPI IDataObject_fnEnumFormatEtc(IDataObject* iface,
611         DWORD dwDirection, IEnumFORMATETC** ppenumFormatEtc)
612 {
613     FIXME("\n");
614     return E_NOTIMPL;
615 }
616
617 static HRESULT WINAPI IDataObject_fnDAdvise(IDataObject* iface,
618         FORMATETC* pformatetc, DWORD advf, IAdviseSink* pAdvSink,
619         DWORD* pdwConnection)
620 {
621     FIXME("\n");
622     return E_NOTIMPL;
623 }
624
625 static HRESULT WINAPI IDataObject_fnDUnadvise(IDataObject* iface,
626         DWORD dwConnection)
627 {
628     FIXME("\n");
629     return E_NOTIMPL;
630 }
631
632 static HRESULT WINAPI IDataObject_fnEnumDAdvise(IDataObject* iface,
633         IEnumSTATDATA** ppenumAdvise)
634 {
635     FIXME("\n");
636     return E_NOTIMPL;
637 }
638
639 static const IDataObjectVtbl dovt =
640 {
641     IDataObject_fnQueryInterface,
642     IDataObject_fnAddRef,
643     IDataObject_fnRelease,
644     IDataObject_fnGetData,
645     IDataObject_fnGetDataHere,
646     IDataObject_fnQueryGetData,
647     IDataObject_fnGetConicalFormatEtc,
648     IDataObject_fnSetData,
649     IDataObject_fnEnumFormatEtc,
650     IDataObject_fnDAdvise,
651     IDataObject_fnDUnadvise,
652     IDataObject_fnEnumDAdvise
653 };
654
655 static HRESULT WINAPI IPersistStream_fnQueryInterface(IPersistStream* iface,
656         REFIID riid, LPVOID *ppvObj)
657 {
658     HlinkImpl *This = impl_from_IPersistStream(iface);
659     TRACE("(%p)\n", This);
660     return IHlink_QueryInterface(&This->IHlink_iface, riid, ppvObj);
661 }
662
663 static ULONG WINAPI IPersistStream_fnAddRef (IPersistStream* iface)
664 {
665     HlinkImpl *This = impl_from_IPersistStream(iface);
666     TRACE("(%p)\n", This);
667     return IHlink_AddRef(&This->IHlink_iface);
668 }
669
670 static ULONG WINAPI IPersistStream_fnRelease (IPersistStream* iface)
671 {
672     HlinkImpl *This = impl_from_IPersistStream(iface);
673     TRACE("(%p)\n", This);
674     return IHlink_Release(&This->IHlink_iface);
675 }
676
677 static HRESULT WINAPI IPersistStream_fnGetClassID(IPersistStream* iface,
678         CLSID* pClassID)
679 {
680     HlinkImpl *This = impl_from_IPersistStream(iface);
681     TRACE("(%p)\n", This);
682     *pClassID = CLSID_StdHlink;
683     return S_OK;
684 }
685
686 static HRESULT WINAPI IPersistStream_fnIsDirty(IPersistStream* iface)
687 {
688     FIXME("\n");
689     return E_NOTIMPL;
690 }
691
692 static HRESULT write_hlink_string(IStream *pStm, LPCWSTR str)
693 {
694     DWORD len;
695     HRESULT hr;
696
697     TRACE("(%p, %s)\n", pStm, debugstr_w(str));
698
699     len = strlenW(str) + 1;
700
701     hr = IStream_Write(pStm, &len, sizeof(len), NULL);
702     if (FAILED(hr)) return hr;
703
704     hr = IStream_Write(pStm, str, len * sizeof(WCHAR), NULL);
705     if (FAILED(hr)) return hr;
706
707     return S_OK;
708 }
709
710 static inline ULONG size_hlink_string(LPCWSTR str)
711 {
712     return sizeof(DWORD) + (strlenW(str) + 1) * sizeof(WCHAR);
713 }
714
715 static HRESULT read_hlink_string(IStream *pStm, LPWSTR *out_str)
716 {
717     LPWSTR str;
718     DWORD len;
719     ULONG read;
720     HRESULT hr;
721
722     hr = IStream_Read(pStm, &len, sizeof(len), &read);
723     if (FAILED(hr)) return hr;
724     if (read != sizeof(len)) return STG_E_READFAULT;
725
726     TRACE("read len %d\n", len);
727
728     str = heap_alloc(len * sizeof(WCHAR));
729     if (!str) return E_OUTOFMEMORY;
730
731     hr = IStream_Read(pStm, str, len * sizeof(WCHAR), &read);
732     if (FAILED(hr))
733     {
734         heap_free(str);
735         return hr;
736     }
737     if (read != len * sizeof(WCHAR))
738     {
739         heap_free(str);
740         return STG_E_READFAULT;
741     }
742     TRACE("read string %s\n", debugstr_w(str));
743
744     *out_str = str;
745     return S_OK;
746 }
747
748 static HRESULT WINAPI IPersistStream_fnLoad(IPersistStream* iface,
749         IStream* pStm)
750 {
751     HRESULT r;
752     DWORD hdr[2];
753     DWORD read;
754     HlinkImpl *This = impl_from_IPersistStream(iface);
755
756     r = IStream_Read(pStm, hdr, sizeof(hdr), &read);
757     if (read != sizeof(hdr) || (hdr[0] != HLINK_SAVE_MAGIC))
758     {
759         r = E_FAIL;
760         goto end;
761     }
762     if (hdr[1] & ~HLINK_SAVE_ALL)
763         FIXME("unknown flag(s) 0x%x\n", hdr[1] & ~HLINK_SAVE_ALL);
764
765     if (hdr[1] & HLINK_SAVE_TARGET_FRAME_PRESENT)
766     {
767         TRACE("loading target frame name\n");
768         r = read_hlink_string(pStm, &This->TargetFrameName);
769         if (FAILED(r)) goto end;
770     }
771
772     if (hdr[1] & HLINK_SAVE_FRIENDLY_PRESENT)
773     {
774         TRACE("loading target friendly name\n");
775         if (!(hdr[1] & 0x4))
776             FIXME("0x4 flag not present with friendly name flag - not sure what this means\n");
777         r = read_hlink_string(pStm, &This->FriendlyName);
778         if (FAILED(r)) goto end;
779     }
780
781     if (hdr[1] & HLINK_SAVE_MONIKER_PRESENT)
782     {
783         TRACE("loading moniker\n");
784         r = OleLoadFromStream(pStm, &IID_IMoniker, (LPVOID*)&(This->Moniker));
785         if (FAILED(r))
786             goto end;
787         This->absolute = hdr[1] & HLINK_SAVE_MONIKER_IS_ABSOLUTE ? TRUE : FALSE;
788     }
789
790     if (hdr[1] & HLINK_SAVE_LOCATION_PRESENT)
791     {
792         TRACE("loading location\n");
793         r = read_hlink_string(pStm, &This->Location);
794         if (FAILED(r)) goto end;
795     }
796
797 end:
798     TRACE("Load Result 0x%x (%p)\n", r, This->Moniker);
799
800     return r;
801 }
802
803 static HRESULT WINAPI IPersistStream_fnSave(IPersistStream* iface,
804         IStream* pStm, BOOL fClearDirty)
805 {
806     HRESULT r;
807     HlinkImpl *This = impl_from_IPersistStream(iface);
808     DWORD hdr[2];
809     IMoniker *moniker;
810
811     TRACE("(%p) Moniker(%p)\n", This, This->Moniker);
812
813     r = __GetMoniker(This, &moniker, HLINKGETREF_DEFAULT);
814     if (FAILED(r))
815         return r;
816     r = E_FAIL;
817
818     hdr[0] = HLINK_SAVE_MAGIC;
819     hdr[1] = 0;
820
821     if (moniker)
822         hdr[1] |= HLINK_SAVE_MONIKER_PRESENT;
823     if (This->absolute)
824         hdr[1] |= HLINK_SAVE_MONIKER_IS_ABSOLUTE;
825     if (This->Location)
826         hdr[1] |= HLINK_SAVE_LOCATION_PRESENT;
827     if (This->FriendlyName)
828         hdr[1] |= HLINK_SAVE_FRIENDLY_PRESENT | 4 /* FIXME */;
829     if (This->TargetFrameName)
830         hdr[1] |= HLINK_SAVE_TARGET_FRAME_PRESENT;
831
832     IStream_Write(pStm, hdr, sizeof(hdr), NULL);
833
834     if (This->TargetFrameName)
835     {
836         r = write_hlink_string(pStm, This->TargetFrameName);
837         if (FAILED(r)) goto end;
838     }
839
840     if (This->FriendlyName)
841     {
842         r = write_hlink_string(pStm, This->FriendlyName);
843         if (FAILED(r)) goto end;
844     }
845
846     if (moniker)
847     {
848         IPersistStream* monstream;
849
850         monstream = NULL;
851         IMoniker_QueryInterface(moniker, &IID_IPersistStream,
852                 (LPVOID*)&monstream);
853         if (monstream)
854         {
855             r = OleSaveToStream(monstream, pStm);
856             IPersistStream_Release(monstream);
857         }
858         if (FAILED(r)) goto end;
859     }
860
861     if (This->Location)
862     {
863         r = write_hlink_string(pStm, This->Location);
864         if (FAILED(r)) goto end;
865     }
866
867 end:
868     if (moniker) IMoniker_Release(moniker);
869     TRACE("Save Result 0x%x\n", r);
870
871     return r;
872 }
873
874 static HRESULT WINAPI IPersistStream_fnGetSizeMax(IPersistStream* iface,
875         ULARGE_INTEGER* pcbSize)
876 {
877     HRESULT r;
878     HlinkImpl *This = impl_from_IPersistStream(iface);
879     IMoniker *moniker;
880
881     TRACE("(%p) Moniker(%p)\n", This, This->Moniker);
882
883     pcbSize->QuadPart = sizeof(DWORD)*2;
884
885     if (This->TargetFrameName)
886         pcbSize->QuadPart += size_hlink_string(This->TargetFrameName);
887
888     if (This->FriendlyName)
889         pcbSize->QuadPart += size_hlink_string(This->FriendlyName);
890
891     r = __GetMoniker(This, &moniker, HLINKGETREF_DEFAULT);
892     if (FAILED(r))
893         return r;
894     r = E_FAIL;
895
896     if (moniker)
897     {
898         IPersistStream* monstream = NULL;
899         IMoniker_QueryInterface(moniker, &IID_IPersistStream,
900                 (LPVOID*)&monstream);
901         if (monstream)
902         {
903             ULARGE_INTEGER mon_size;
904             r = IPersistStream_GetSizeMax(monstream, &mon_size);
905             pcbSize->QuadPart += mon_size.QuadPart;
906             IPersistStream_Release(monstream);
907         }
908         IMoniker_Release(moniker);
909     }
910
911     if (This->Location)
912         pcbSize->QuadPart += size_hlink_string(This->Location);
913
914     return r;
915 }
916
917 static const IPersistStreamVtbl psvt =
918 {
919     IPersistStream_fnQueryInterface,
920     IPersistStream_fnAddRef,
921     IPersistStream_fnRelease,
922     IPersistStream_fnGetClassID,
923     IPersistStream_fnIsDirty,
924     IPersistStream_fnLoad,
925     IPersistStream_fnSave,
926     IPersistStream_fnGetSizeMax,
927 };
928
929 HRESULT HLink_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
930 {
931     HlinkImpl * hl;
932
933     TRACE("unkOut=%p riid=%s\n", pUnkOuter, debugstr_guid(riid));
934     *ppv = NULL;
935
936     if (pUnkOuter)
937         return CLASS_E_NOAGGREGATION;
938
939     hl = heap_alloc_zero(sizeof(HlinkImpl));
940     if (!hl)
941         return E_OUTOFMEMORY;
942
943     hl->ref = 1;
944     hl->IHlink_iface.lpVtbl = &hlvt;
945     hl->IPersistStream_iface.lpVtbl = &psvt;
946     hl->IDataObject_iface.lpVtbl = &dovt;
947
948     *ppv = hl;
949     return S_OK;
950 }