mshtml: Improve loading document detection in AsyncOpen.
[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 <stdarg.h>
22
23 #define COBJMACROS
24
25 #include "winerror.h"
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "ole2.h"
30 #include "unknwn.h"
31 #include "objidl.h"
32 #include "shellapi.h"
33
34 #include "wine/debug.h"
35 #include "hlink.h"
36 #include "hlguids.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(hlink);
39
40 static const IHlinkVtbl              hlvt;
41 static const IPersistStreamVtbl      psvt;
42 static const IDataObjectVtbl         dovt;
43
44 typedef struct
45 {
46     const IHlinkVtbl    *lpVtbl;
47     LONG                ref;
48
49     const IPersistStreamVtbl    *lpPSVtbl;
50     const IDataObjectVtbl       *lpDOVtbl;
51
52     LPWSTR              FriendlyName;
53     LPWSTR              Location;
54     LPWSTR              Target;
55     LPWSTR              TargetFrameName;
56     IMoniker            *Moniker;
57     IHlinkSite          *Site;
58     DWORD               SiteData;
59 } HlinkImpl;
60
61
62 static inline HlinkImpl* HlinkImpl_from_IPersistStream( IPersistStream* iface)
63 {
64     return (HlinkImpl*) ((CHAR*)iface - FIELD_OFFSET(HlinkImpl, lpPSVtbl));
65 }
66
67 static inline HlinkImpl* HlinkImpl_from_IDataObject( IDataObject* iface)
68 {
69     return (HlinkImpl*) ((CHAR*)iface - FIELD_OFFSET(HlinkImpl, lpDOVtbl));
70 }
71
72 static inline LPWSTR strdupW( LPCWSTR str )
73 {
74     LPWSTR r;
75     UINT len;
76
77     if (!str)
78         return NULL;
79     len = (lstrlenW(str)+1) * sizeof (WCHAR);
80     r = HeapAlloc(GetProcessHeap(), 0, len);
81     if (r)
82         memcpy(r, str, len);
83     return r;
84 }
85
86 static inline LPWSTR co_strdupW( LPCWSTR str )
87 {
88     LPWSTR r;
89     UINT len;
90
91     if (!str)
92         return NULL;
93     len = (lstrlenW(str)+1) * sizeof (WCHAR);
94     r = CoTaskMemAlloc(len);
95     if (r)
96         memcpy(r, str, len);
97     return r;
98 }
99
100 static inline void __GetMoniker(HlinkImpl* This, IMoniker** moniker)
101 {
102     *moniker = NULL;
103     if (This->Moniker)
104     {
105         *moniker = This->Moniker;
106         if (*moniker)
107             IMoniker_AddRef(*moniker);
108     }
109     else if (This->Site)
110     {
111         IHlinkSite_GetMoniker(This->Site, This->SiteData,
112                 OLEGETMONIKER_FORCEASSIGN, OLEWHICHMK_CONTAINER,
113                 (LPVOID)moniker);
114     }
115 }
116
117 HRESULT WINAPI HLink_Constructor(IUnknown *pUnkOuter, REFIID riid,
118         LPVOID *ppv)
119 {
120     HlinkImpl * hl;
121
122     TRACE("unkOut=%p riid=%s\n", pUnkOuter, debugstr_guid(riid));
123     *ppv = NULL;
124
125     if (pUnkOuter)
126         return CLASS_E_NOAGGREGATION;
127
128     hl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HlinkImpl));
129     if (!hl)
130         return E_OUTOFMEMORY;
131
132     hl->ref = 1;
133     hl->lpVtbl = &hlvt;
134     hl->lpPSVtbl = &psvt;
135     hl->lpDOVtbl = &dovt;
136
137     *ppv = hl;
138     return S_OK;
139 }
140
141 static HRESULT WINAPI IHlink_fnQueryInterface(IHlink* iface, REFIID riid,
142         LPVOID *ppvObj)
143 {
144     HlinkImpl  *This = (HlinkImpl*)iface;
145
146     TRACE ("(%p)->(%s,%p)\n", This, debugstr_guid (riid), ppvObj);
147
148     *ppvObj = NULL;
149
150     if (IsEqualIID(riid, &IID_IUnknown) || (IsEqualIID(riid, &IID_IHlink)))
151         *ppvObj = This;
152     else if (IsEqualIID(riid, &IID_IPersistStream))
153         *ppvObj = (LPVOID*)&(This->lpPSVtbl);
154     else if (IsEqualIID(riid, &IID_IDataObject))
155         *ppvObj = (LPVOID*)&(This->lpDOVtbl);
156
157     if (*ppvObj)
158     {
159         IUnknown_AddRef((IUnknown*)(*ppvObj));
160         return S_OK;
161     }
162     return E_NOINTERFACE;
163 }
164
165 static ULONG WINAPI IHlink_fnAddRef (IHlink* iface)
166 {
167     HlinkImpl  *This = (HlinkImpl*)iface;
168     ULONG refCount = InterlockedIncrement(&This->ref);
169
170     TRACE("(%p)->(count=%u)\n", This, refCount - 1);
171
172     return refCount;
173 }
174
175 static ULONG WINAPI IHlink_fnRelease (IHlink* iface)
176 {
177     HlinkImpl  *This = (HlinkImpl*)iface;
178     ULONG refCount = InterlockedDecrement(&This->ref);
179
180     TRACE("(%p)->(count=%u)\n", This, refCount + 1);
181     if (refCount)
182         return refCount;
183
184     TRACE("-- destroying IHlink (%p)\n", This);
185     HeapFree(GetProcessHeap(), 0, This->FriendlyName);
186     HeapFree(GetProcessHeap(), 0, This->Target);
187     HeapFree(GetProcessHeap(), 0, This->TargetFrameName);
188     HeapFree(GetProcessHeap(), 0, This->Location);
189     if (This->Moniker)
190         IMoniker_Release(This->Moniker);
191     if (This->Site)
192         IHlinkSite_Release(This->Site);
193     HeapFree(GetProcessHeap(), 0, This);
194     return 0;
195 }
196
197 static HRESULT WINAPI IHlink_fnSetHlinkSite( IHlink* iface,
198         IHlinkSite* pihlSite, DWORD dwSiteData)
199 {
200     HlinkImpl  *This = (HlinkImpl*)iface;
201
202     TRACE("(%p)->(%p %i)\n", This, pihlSite, dwSiteData);
203
204     if (This->Site)
205         IHlinkSite_Release(This->Site);
206
207     This->Site = pihlSite;
208     if (This->Site)
209         IHlinkSite_AddRef(This->Site);
210
211     This->SiteData = dwSiteData;
212
213     return S_OK;
214 }
215
216 static HRESULT WINAPI IHlink_fnGetHlinkSite( IHlink* iface,
217         IHlinkSite** ppihlSite, DWORD *pdwSiteData)
218 {
219     HlinkImpl  *This = (HlinkImpl*)iface;
220
221     TRACE("(%p)->(%p %p)\n", This, ppihlSite, pdwSiteData);
222
223     *ppihlSite = This->Site;
224     *pdwSiteData = This->SiteData;
225
226     if (This->Site)
227         IHlinkSite_AddRef(This->Site);
228
229     return S_OK;
230 }
231
232 static HRESULT WINAPI IHlink_fnSetMonikerReference( IHlink* iface,
233         DWORD rfHLSETF, IMoniker *pmkTarget, LPCWSTR pwzLocation)
234 {
235     HlinkImpl  *This = (HlinkImpl*)iface;
236
237     FIXME("(%p)->(%i %p %s)\n", This, rfHLSETF, pmkTarget,
238             debugstr_w(pwzLocation));
239
240     if (This->Moniker)
241         IMoniker_Release(This->Moniker);
242
243     This->Moniker = pmkTarget;
244     if (This->Moniker)
245         IMoniker_AddRef(This->Moniker);
246
247     HeapFree(GetProcessHeap(), 0, This->Location);
248     This->Location = strdupW( pwzLocation );
249
250     return S_OK;
251 }
252
253 static HRESULT WINAPI IHlink_fnSetStringReference(IHlink* iface,
254         DWORD grfHLSETF, LPCWSTR pwzTarget, LPCWSTR pwzLocation)
255 {
256     HlinkImpl  *This = (HlinkImpl*)iface;
257
258     TRACE("(%p)->(%i %s %s)\n", This, grfHLSETF, debugstr_w(pwzTarget),
259             debugstr_w(pwzLocation));
260
261     if (grfHLSETF & HLINKSETF_TARGET)
262     {
263         HeapFree(GetProcessHeap(), 0, This->Target);
264         This->Target = strdupW( pwzTarget );
265     }
266     if (grfHLSETF & HLINKSETF_LOCATION)
267     {
268         HeapFree(GetProcessHeap(), 0, This->Location);
269         This->Location = strdupW( pwzLocation );
270     }
271
272     return S_OK;
273 }
274
275 static HRESULT WINAPI IHlink_fnGetMonikerReference(IHlink* iface,
276         DWORD dwWhichRef, IMoniker **ppimkTarget, LPWSTR *ppwzLocation)
277 {
278     HlinkImpl  *This = (HlinkImpl*)iface;
279
280     TRACE("(%p) -> (%i %p %p)\n", This, dwWhichRef, ppimkTarget,
281             ppwzLocation);
282
283     if(ppimkTarget)
284         __GetMoniker(This, ppimkTarget);
285
286     if (ppwzLocation)
287         IHlink_GetStringReference(iface, dwWhichRef, NULL, ppwzLocation);
288
289     return S_OK;
290 }
291
292 static HRESULT WINAPI IHlink_fnGetStringReference (IHlink* iface,
293         DWORD dwWhichRef, LPWSTR *ppwzTarget, LPWSTR *ppwzLocation)
294 {
295     HlinkImpl  *This = (HlinkImpl*)iface;
296
297     FIXME("(%p) -> (%i %p %p)\n", This, dwWhichRef, ppwzTarget, ppwzLocation);
298
299     if (ppwzTarget)
300     {
301         *ppwzTarget = co_strdupW( This->Target );
302
303         if (!This->Target)
304         {
305             IMoniker* mon;
306             __GetMoniker(This, &mon);
307             if (mon)
308             {
309                 IBindCtx *pbc;
310
311                 CreateBindCtx( 0, &pbc);
312                 IMoniker_GetDisplayName(mon, pbc, NULL, ppwzTarget);
313                 IBindCtx_Release(pbc);
314                 IMoniker_Release(mon);
315             }
316             else
317                 FIXME("Unhandled case, no set Target and no moniker\n");
318         }
319     }
320     if (ppwzLocation)
321         *ppwzLocation = co_strdupW( This->Location );
322
323     TRACE("(Target: %s Location: %s)\n",
324             (ppwzTarget)?debugstr_w(*ppwzTarget):"<NULL>",
325             (ppwzLocation)?debugstr_w(*ppwzLocation):"<NULL>");
326
327     return S_OK;
328 }
329
330 static HRESULT WINAPI IHlink_fnSetFriendlyName (IHlink *iface,
331         LPCWSTR pwzFriendlyName)
332 {
333     HlinkImpl  *This = (HlinkImpl*)iface;
334
335     TRACE("(%p) -> (%s)\n", This, debugstr_w(pwzFriendlyName));
336
337     HeapFree(GetProcessHeap(), 0, This->FriendlyName);
338     This->FriendlyName = strdupW( pwzFriendlyName );
339
340     return S_OK;
341 }
342
343 static HRESULT WINAPI IHlink_fnGetFriendlyName (IHlink* iface,
344         DWORD grfHLFNAMEF, LPWSTR* ppwzFriendlyName)
345 {
346     HlinkImpl  *This = (HlinkImpl*)iface;
347
348     TRACE("(%p) -> (%i %p)\n", This, grfHLFNAMEF, ppwzFriendlyName);
349
350     /* FIXME: Only using explicitly set and cached friendly names */
351
352     if (This->FriendlyName)
353         *ppwzFriendlyName = co_strdupW( This->FriendlyName );
354     else
355     {
356         IMoniker *moniker;
357         __GetMoniker(This, &moniker);
358         if (moniker)
359         {
360             IBindCtx *bcxt;
361             CreateBindCtx(0, &bcxt);
362
363             IMoniker_GetDisplayName(moniker, bcxt, NULL, ppwzFriendlyName);
364             IBindCtx_Release(bcxt);
365             IMoniker_Release(moniker);
366         }
367         else
368             *ppwzFriendlyName = NULL;
369     }
370
371     return S_OK;
372 }
373
374 static HRESULT WINAPI IHlink_fnSetTargetFrameName(IHlink* iface,
375         LPCWSTR pwzTargetFramename)
376 {
377     HlinkImpl  *This = (HlinkImpl*)iface;
378     TRACE("(%p)->(%s)\n", This, debugstr_w(pwzTargetFramename));
379
380     HeapFree(GetProcessHeap(), 0, This->TargetFrameName);
381     This->TargetFrameName = strdupW( pwzTargetFramename );
382
383     return S_OK;
384 }
385
386 static HRESULT WINAPI IHlink_fnGetTargetFrameName(IHlink* iface,
387         LPWSTR *ppwzTargetFrameName)
388 {
389     HlinkImpl  *This = (HlinkImpl*)iface;
390
391     TRACE("(%p)->(%p)\n", This, ppwzTargetFrameName);
392     *ppwzTargetFrameName = co_strdupW( This->TargetFrameName );
393
394     return S_OK;
395 }
396
397 static HRESULT WINAPI IHlink_fnGetMiscStatus(IHlink* iface, DWORD* pdwStatus)
398 {
399     FIXME("\n");
400     return E_NOTIMPL;
401 }
402
403 static HRESULT WINAPI IHlink_fnNavigate(IHlink* iface, DWORD grfHLNF, LPBC pbc,
404         IBindStatusCallback *pbsc, IHlinkBrowseContext *phbc)
405 {
406     HlinkImpl  *This = (HlinkImpl*)iface;
407     IMoniker *mon = NULL;
408
409     FIXME("Semi-Stub:(%p)->(%i %p %p %p)\n", This, grfHLNF, pbc, pbsc, phbc);
410
411     if (This->Site)
412         IHlinkSite_ReadyToNavigate(This->Site, This->SiteData, 0);
413
414     __GetMoniker(This, &mon);
415     TRACE("Moniker %p\n", mon);
416
417     if (mon)
418     {
419         IBindCtx *bcxt;
420         IHlinkTarget *target = NULL;
421         HRESULT r = S_OK;
422
423         CreateBindCtx(0, &bcxt);
424
425         RegisterBindStatusCallback(bcxt, pbsc, NULL, 0);
426
427         r = IMoniker_BindToObject(mon, bcxt, NULL, &IID_IHlinkTarget,
428                 (LPVOID*)&target);
429         TRACE("IHlinkTarget returned 0x%x\n", r);
430         if (r == S_OK)
431         {
432             IHlinkTarget_SetBrowseContext(target, phbc);
433             IHlinkTarget_Navigate(target, grfHLNF, This->Location);
434             IHlinkTarget_Release(target);
435         }
436         else
437         {
438             static const WCHAR szOpen[] = {'o','p','e','n',0};
439             LPWSTR target = NULL;
440
441             r = IHlink_GetStringReference(iface, HLINKGETREF_DEFAULT, &target, NULL);
442             if (SUCCEEDED(r) && target)
443             {
444                 ShellExecuteW(NULL, szOpen, target, NULL, NULL, SW_SHOW);
445                 CoTaskMemFree(target);
446             }
447         }
448
449         RevokeBindStatusCallback(bcxt, pbsc);
450
451         IBindCtx_Release(bcxt);
452         IMoniker_Release(mon);
453     }
454
455     if (This->Site)
456         IHlinkSite_OnNavigationComplete(This->Site, This->SiteData, 0, 0, NULL);
457
458     TRACE("Finished Navigation\n");
459     return S_OK;
460 }
461
462 static HRESULT WINAPI IHlink_fnSetAdditonalParams(IHlink* iface,
463         LPCWSTR pwzAdditionalParams)
464 {
465     FIXME("\n");
466     return E_NOTIMPL;
467 }
468
469 static HRESULT WINAPI IHlink_fnGetAdditionalParams(IHlink* iface,
470         LPWSTR* ppwzAdditionalParams)
471 {
472     FIXME("\n");
473     return E_NOTIMPL;
474 }
475
476 static const IHlinkVtbl hlvt =
477 {
478     IHlink_fnQueryInterface,
479     IHlink_fnAddRef,
480     IHlink_fnRelease,
481     IHlink_fnSetHlinkSite,
482     IHlink_fnGetHlinkSite,
483     IHlink_fnSetMonikerReference,
484     IHlink_fnGetMonikerReference,
485     IHlink_fnSetStringReference,
486     IHlink_fnGetStringReference,
487     IHlink_fnSetFriendlyName,
488     IHlink_fnGetFriendlyName,
489     IHlink_fnSetTargetFrameName,
490     IHlink_fnGetTargetFrameName,
491     IHlink_fnGetMiscStatus,
492     IHlink_fnNavigate,
493     IHlink_fnSetAdditonalParams,
494     IHlink_fnGetAdditionalParams
495 };
496
497 static HRESULT WINAPI IDataObject_fnQueryInterface(IDataObject* iface,
498         REFIID riid, LPVOID *ppvObj)
499 {
500     HlinkImpl *This = HlinkImpl_from_IDataObject(iface);
501     TRACE("%p\n", This);
502     return IHlink_QueryInterface((IHlink*)This, riid, ppvObj);
503 }
504
505 static ULONG WINAPI IDataObject_fnAddRef (IDataObject* iface)
506 {
507     HlinkImpl *This = HlinkImpl_from_IDataObject(iface);
508     TRACE("%p\n", This);
509     return IHlink_AddRef((IHlink*)This);
510 }
511
512 static ULONG WINAPI IDataObject_fnRelease (IDataObject* iface)
513 {
514     HlinkImpl *This = HlinkImpl_from_IDataObject(iface);
515     TRACE("%p\n", This);
516     return IHlink_Release((IHlink*)This);
517 }
518
519 static HRESULT WINAPI IDataObject_fnGetData(IDataObject* iface,
520         FORMATETC* pformatetcIn, STGMEDIUM* pmedium)
521 {
522     FIXME("\n");
523     return E_NOTIMPL;
524 }
525
526 static HRESULT WINAPI IDataObject_fnGetDataHere(IDataObject* iface,
527         FORMATETC* pformatetc, STGMEDIUM* pmedium)
528 {
529     FIXME("\n");
530     return E_NOTIMPL;
531 }
532
533 static HRESULT WINAPI IDataObject_fnQueryGetData(IDataObject* iface,
534         FORMATETC* pformatetc)
535 {
536     FIXME("\n");
537     return E_NOTIMPL;
538 }
539
540 static HRESULT WINAPI IDataObject_fnGetConicalFormatEtc(IDataObject* iface,
541         FORMATETC* pformatetcIn, FORMATETC* pformatetcOut)
542 {
543     FIXME("\n");
544     return E_NOTIMPL;
545 }
546
547 static HRESULT WINAPI IDataObject_fnSetData(IDataObject* iface,
548         FORMATETC* pformatetc, STGMEDIUM* pmedium, BOOL fRelease)
549 {
550     FIXME("\n");
551     return E_NOTIMPL;
552 }
553
554 static HRESULT WINAPI IDataObject_fnEnumFormatEtc(IDataObject* iface,
555         DWORD dwDirection, IEnumFORMATETC** ppenumFormatEtc)
556 {
557     FIXME("\n");
558     return E_NOTIMPL;
559 }
560
561 static HRESULT WINAPI IDataObject_fnDAdvise(IDataObject* iface,
562         FORMATETC* pformatetc, DWORD advf, IAdviseSink* pAdvSink,
563         DWORD* pdwConnection)
564 {
565     FIXME("\n");
566     return E_NOTIMPL;
567 }
568
569 static HRESULT WINAPI IDataObject_fnDUnadvise(IDataObject* iface,
570         DWORD dwConnection)
571 {
572     FIXME("\n");
573     return E_NOTIMPL;
574 }
575
576 static HRESULT WINAPI IDataObject_fnEnumDAdvise(IDataObject* iface,
577         IEnumSTATDATA** ppenumAdvise)
578 {
579     FIXME("\n");
580     return E_NOTIMPL;
581 }
582
583 static const IDataObjectVtbl dovt =
584 {
585     IDataObject_fnQueryInterface,
586     IDataObject_fnAddRef,
587     IDataObject_fnRelease,
588     IDataObject_fnGetData,
589     IDataObject_fnGetDataHere,
590     IDataObject_fnQueryGetData,
591     IDataObject_fnGetConicalFormatEtc,
592     IDataObject_fnSetData,
593     IDataObject_fnEnumFormatEtc,
594     IDataObject_fnDAdvise,
595     IDataObject_fnDUnadvise,
596     IDataObject_fnEnumDAdvise
597 };
598
599 static HRESULT WINAPI IPersistStream_fnQueryInterface(IPersistStream* iface,
600         REFIID riid, LPVOID *ppvObj)
601 {
602     HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
603     TRACE("(%p)\n", This);
604     return IHlink_QueryInterface((IHlink*)This, riid, ppvObj);
605 }
606
607 static ULONG WINAPI IPersistStream_fnAddRef (IPersistStream* iface)
608 {
609     HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
610     TRACE("(%p)\n", This);
611     return IHlink_AddRef((IHlink*)This);
612 }
613
614 static ULONG WINAPI IPersistStream_fnRelease (IPersistStream* iface)
615 {
616     HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
617     TRACE("(%p)\n", This);
618     return IHlink_Release((IHlink*)This);
619 }
620
621 static HRESULT WINAPI IPersistStream_fnGetClassID(IPersistStream* iface,
622         CLSID* pClassID)
623 {
624     HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
625     TRACE("(%p)\n", This);
626     memcpy(pClassID, &CLSID_StdHlink, sizeof(CLSID));
627     return S_OK;
628 }
629
630 static HRESULT WINAPI IPersistStream_fnIsDirty(IPersistStream* iface)
631 {
632     FIXME("\n");
633     return E_NOTIMPL;
634 }
635
636 static HRESULT WINAPI IPersistStream_fnLoad(IPersistStream* iface,
637         IStream* pStm)
638 {
639     HRESULT r = E_NOTIMPL;
640     DWORD hdr[2];
641     DWORD read;
642     HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
643
644     IStream_Read(pStm, &hdr, sizeof(hdr), &read);
645     /* FIXME: unknown header values */
646
647     r = OleLoadFromStream(pStm, &IID_IMoniker, (LPVOID*)&(This->Moniker));
648     TRACE("Load Result 0x%x (%p)\n", r, This->Moniker);
649
650     return r;
651 }
652
653 static HRESULT WINAPI IPersistStream_fnSave(IPersistStream* iface,
654         IStream* pStm, BOOL fClearDirty)
655 {
656     HRESULT r = E_FAIL;
657     HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
658     DWORD hdr[2];
659     IMoniker *moniker;
660
661     FIXME("(%p) Moniker(%p)\n", This, This->Moniker);
662
663     __GetMoniker(This, &moniker);
664     if (moniker)
665     {
666         IPersistStream* monstream;
667         /* FIXME: Unknown values in the header */
668         hdr[0] = 2;
669         hdr[1] = 2;
670
671         IStream_Write(pStm, &hdr, sizeof(hdr), NULL);
672
673         monstream = NULL;
674         IMoniker_QueryInterface(moniker, &IID_IPersistStream,
675                 (LPVOID*)&monstream);
676         if (monstream)
677         {
678             r = OleSaveToStream(monstream, pStm);
679             IPersistStream_Release(monstream);
680         }
681         IMoniker_Release(moniker);
682     }
683     TRACE("Save Result 0x%x\n", r);
684
685     return r;
686 }
687
688 static HRESULT WINAPI IPersistStream_fnGetSizeMax(IPersistStream* iface,
689         ULARGE_INTEGER* pcbSize)
690 {
691     HRESULT r = E_FAIL;
692     HlinkImpl *This = HlinkImpl_from_IPersistStream(iface);
693     IMoniker *moniker;
694
695     FIXME("(%p) Moniker(%p)\n", This, This->Moniker);
696
697     __GetMoniker(This, &moniker);
698     if (moniker)
699     {
700         IPersistStream* monstream = NULL;
701         IMoniker_QueryInterface(moniker, &IID_IPersistStream,
702                 (LPVOID*)&monstream);
703         if (monstream)
704         {
705             r = IPersistStream_GetSizeMax(monstream, pcbSize);
706             /* FIXME: Handle ULARGE_INTEGER correctly */
707             pcbSize->u.LowPart += sizeof(DWORD)*2;
708             IPersistStream_Release(monstream);
709         }
710         IMoniker_Release(moniker);
711     }
712
713     return r;
714 }
715
716 static const IPersistStreamVtbl psvt =
717 {
718     IPersistStream_fnQueryInterface,
719     IPersistStream_fnAddRef,
720     IPersistStream_fnRelease,
721     IPersistStream_fnGetClassID,
722     IPersistStream_fnIsDirty,
723     IPersistStream_fnLoad,
724     IPersistStream_fnSave,
725     IPersistStream_fnGetSizeMax,
726 };