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