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