[CRT] Massively improve performance of rand_s
[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 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
56 IBindStatusCallback IBindStatusCallback_iface;
57 IBindStatusCallback *bind_callback;
58 IBindCtx *async_bind_ctx;
59 DWORD async_flags;
60 IHlinkBrowseContext *async_browse_ctx;
61 } HlinkImpl;
62
63 static inline HlinkImpl *impl_from_IHlink(IHlink *iface)
64 {
65 return CONTAINING_RECORD(iface, HlinkImpl, IHlink_iface);
66 }
67
68
69 static inline HlinkImpl* impl_from_IPersistStream( IPersistStream* iface)
70 {
71 return CONTAINING_RECORD(iface, HlinkImpl, IPersistStream_iface);
72 }
73
74 static inline HlinkImpl* impl_from_IDataObject( IDataObject* iface)
75 {
76 return CONTAINING_RECORD(iface, HlinkImpl, IDataObject_iface);
77 }
78
79 static HRESULT __GetMoniker(HlinkImpl* This, IMoniker** moniker,
80 DWORD ref_type)
81 {
82 HRESULT hres;
83
84 if (ref_type == HLINKGETREF_DEFAULT)
85 ref_type = HLINKGETREF_RELATIVE;
86
87 if (This->Moniker)
88 {
89 DWORD mktype = MKSYS_NONE;
90
91 hres = IMoniker_IsSystemMoniker(This->Moniker, &mktype);
92 if (hres == S_OK && mktype != MKSYS_NONE)
93 {
94 *moniker = This->Moniker;
95 IMoniker_AddRef(*moniker);
96 return S_OK;
97 }
98 }
99
100 if (ref_type == HLINKGETREF_ABSOLUTE && This->Site)
101 {
102 IMoniker *hls_moniker;
103
104 hres = IHlinkSite_GetMoniker(This->Site, This->SiteData,
105 OLEGETMONIKER_FORCEASSIGN, OLEWHICHMK_CONTAINER, &hls_moniker);
106 if (FAILED(hres))
107 return hres;
108
109 if (This->Moniker)
110 {
111 hres = IMoniker_ComposeWith(hls_moniker, This->Moniker, FALSE,
112 moniker);
113 IMoniker_Release(hls_moniker);
114 return hres;
115 }
116
117 *moniker = hls_moniker;
118 return S_OK;
119 }
120
121 *moniker = This->Moniker;
122 if (*moniker)
123 IMoniker_AddRef(*moniker);
124
125 return S_OK;
126 }
127
128 static HRESULT WINAPI IHlink_fnQueryInterface(IHlink* iface, REFIID riid,
129 LPVOID *ppvObj)
130 {
131 HlinkImpl *This = impl_from_IHlink(iface);
132
133 TRACE ("(%p)->(%s,%p)\n", This, debugstr_guid (riid), ppvObj);
134
135 *ppvObj = NULL;
136
137 if (IsEqualIID(riid, &IID_IUnknown) || (IsEqualIID(riid, &IID_IHlink)))
138 *ppvObj = &This->IHlink_iface;
139 else if (IsEqualIID(riid, &IID_IPersistStream))
140 *ppvObj = &This->IPersistStream_iface;
141 else if (IsEqualIID(riid, &IID_IDataObject))
142 *ppvObj = &This->IDataObject_iface;
143
144 if (*ppvObj)
145 {
146 IUnknown_AddRef((IUnknown*)(*ppvObj));
147 return S_OK;
148 }
149 return E_NOINTERFACE;
150 }
151
152 static ULONG WINAPI IHlink_fnAddRef (IHlink* iface)
153 {
154 HlinkImpl *This = impl_from_IHlink(iface);
155 ULONG refCount = InterlockedIncrement(&This->ref);
156
157 TRACE("(%p)->(count=%u)\n", This, refCount - 1);
158
159 return refCount;
160 }
161
162 static ULONG WINAPI IHlink_fnRelease (IHlink* iface)
163 {
164 HlinkImpl *This = impl_from_IHlink(iface);
165 ULONG refCount = InterlockedDecrement(&This->ref);
166
167 TRACE("(%p)->(count=%u)\n", This, refCount + 1);
168 if (refCount)
169 return refCount;
170
171 TRACE("-- destroying IHlink (%p)\n", This);
172 heap_free(This->FriendlyName);
173 heap_free(This->TargetFrameName);
174 heap_free(This->Location);
175 if (This->Moniker)
176 IMoniker_Release(This->Moniker);
177 if (This->Site)
178 IHlinkSite_Release(This->Site);
179 heap_free(This);
180 return 0;
181 }
182
183 static HRESULT WINAPI IHlink_fnSetHlinkSite( IHlink* iface,
184 IHlinkSite* pihlSite, DWORD dwSiteData)
185 {
186 HlinkImpl *This = impl_from_IHlink(iface);
187
188 TRACE("(%p)->(%p %i)\n", This, pihlSite, dwSiteData);
189
190 if (This->Site)
191 IHlinkSite_Release(This->Site);
192
193 This->Site = pihlSite;
194 if (This->Site)
195 IHlinkSite_AddRef(This->Site);
196
197 This->SiteData = dwSiteData;
198
199 return S_OK;
200 }
201
202 static HRESULT WINAPI IHlink_fnGetHlinkSite( IHlink* iface,
203 IHlinkSite** ppihlSite, DWORD *pdwSiteData)
204 {
205 HlinkImpl *This = impl_from_IHlink(iface);
206
207 TRACE("(%p)->(%p %p)\n", This, ppihlSite, pdwSiteData);
208
209 *ppihlSite = This->Site;
210
211 if (This->Site) {
212 IHlinkSite_AddRef(This->Site);
213 *pdwSiteData = This->SiteData;
214 }
215
216 return S_OK;
217 }
218
219 static HRESULT WINAPI IHlink_fnSetMonikerReference( IHlink* iface,
220 DWORD rfHLSETF, IMoniker *pmkTarget, LPCWSTR pwzLocation)
221 {
222 HlinkImpl *This = impl_from_IHlink(iface);
223
224 TRACE("(%p)->(%i %p %s)\n", This, rfHLSETF, pmkTarget,
225 debugstr_w(pwzLocation));
226
227 if(rfHLSETF == 0)
228 return E_INVALIDARG;
229 if(!(rfHLSETF & (HLINKSETF_TARGET | HLINKSETF_LOCATION)))
230 return rfHLSETF;
231
232 if(rfHLSETF & HLINKSETF_TARGET){
233 if (This->Moniker)
234 IMoniker_Release(This->Moniker);
235
236 This->Moniker = pmkTarget;
237 if (This->Moniker)
238 {
239 IBindCtx *pbc;
240 LPOLESTR display_name;
241 IMoniker_AddRef(This->Moniker);
242 CreateBindCtx( 0, &pbc);
243 IMoniker_GetDisplayName(This->Moniker, pbc, NULL, &display_name);
244 IBindCtx_Release(pbc);
245 This->absolute = display_name && wcschr(display_name, ':');
246 CoTaskMemFree(display_name);
247 }
248 }
249
250 if(rfHLSETF & HLINKSETF_LOCATION){
251 heap_free(This->Location);
252 This->Location = hlink_strdupW( pwzLocation );
253 }
254
255 return S_OK;
256 }
257
258 static HRESULT WINAPI IHlink_fnSetStringReference(IHlink* iface,
259 DWORD grfHLSETF, LPCWSTR pwzTarget, LPCWSTR pwzLocation)
260 {
261 HlinkImpl *This = impl_from_IHlink(iface);
262
263 TRACE("(%p)->(%i %s %s)\n", This, grfHLSETF, debugstr_w(pwzTarget),
264 debugstr_w(pwzLocation));
265
266 if(grfHLSETF > (HLINKSETF_TARGET | HLINKSETF_LOCATION) &&
267 grfHLSETF < -(HLINKSETF_TARGET | HLINKSETF_LOCATION))
268 return grfHLSETF;
269
270 if (grfHLSETF & HLINKSETF_TARGET)
271 {
272 if (This->Moniker)
273 {
274 IMoniker_Release(This->Moniker);
275 This->Moniker = NULL;
276 }
277 if (pwzTarget && *pwzTarget)
278 {
279 IMoniker *pMon;
280 IBindCtx *pbc = NULL;
281 ULONG eaten;
282 HRESULT r;
283
284 r = CreateBindCtx(0, &pbc);
285 if (FAILED(r))
286 return E_OUTOFMEMORY;
287
288 r = MkParseDisplayName(pbc, pwzTarget, &eaten, &pMon);
289 IBindCtx_Release(pbc);
290
291 if (FAILED(r))
292 {
293 LPCWSTR p = wcschr(pwzTarget, ':');
294 if (p && (p - pwzTarget > 1))
295 r = CreateURLMoniker(NULL, pwzTarget, &pMon);
296 else
297 r = CreateFileMoniker(pwzTarget, &pMon);
298 if (FAILED(r))
299 {
300 ERR("couldn't create moniker for %s, failed with error 0x%08x\n",
301 debugstr_w(pwzTarget), r);
302 return r;
303 }
304 }
305
306 IHlink_SetMonikerReference(iface, HLINKSETF_TARGET, pMon, NULL);
307 IMoniker_Release(pMon);
308 }
309 }
310
311 if (grfHLSETF & HLINKSETF_LOCATION)
312 {
313 heap_free(This->Location);
314 This->Location = NULL;
315 if (pwzLocation && *pwzLocation)
316 This->Location = hlink_strdupW( pwzLocation );
317 }
318
319 return S_OK;
320 }
321
322 static HRESULT WINAPI IHlink_fnGetMonikerReference(IHlink* iface,
323 DWORD dwWhichRef, IMoniker **ppimkTarget, LPWSTR *ppwzLocation)
324 {
325 HlinkImpl *This = impl_from_IHlink(iface);
326
327 TRACE("(%p) -> (%i %p %p)\n", This, dwWhichRef, ppimkTarget,
328 ppwzLocation);
329
330 if (ppimkTarget)
331 {
332 HRESULT hres = __GetMoniker(This, ppimkTarget, dwWhichRef);
333 if (FAILED(hres))
334 {
335 if (ppwzLocation)
336 *ppwzLocation = NULL;
337 return hres;
338 }
339 }
340
341 if (ppwzLocation)
342 IHlink_GetStringReference(iface, dwWhichRef, NULL, ppwzLocation);
343
344 return S_OK;
345 }
346
347 static HRESULT WINAPI IHlink_fnGetStringReference (IHlink* iface,
348 DWORD dwWhichRef, LPWSTR *ppwzTarget, LPWSTR *ppwzLocation)
349 {
350 HlinkImpl *This = impl_from_IHlink(iface);
351
352 TRACE("(%p) -> (%i %p %p)\n", This, dwWhichRef, ppwzTarget, ppwzLocation);
353
354 if(dwWhichRef != -1 && dwWhichRef & ~(HLINKGETREF_DEFAULT | HLINKGETREF_ABSOLUTE | HLINKGETREF_RELATIVE))
355 {
356 if(ppwzTarget)
357 *ppwzTarget = NULL;
358 if(ppwzLocation)
359 *ppwzLocation = NULL;
360 return E_INVALIDARG;
361 }
362
363 if (ppwzTarget)
364 {
365 IMoniker* mon;
366 HRESULT hres = __GetMoniker(This, &mon, dwWhichRef);
367 if (FAILED(hres))
368 {
369 if (ppwzLocation)
370 *ppwzLocation = NULL;
371 return hres;
372 }
373 if (mon)
374 {
375 IBindCtx *pbc;
376
377 CreateBindCtx( 0, &pbc);
378 IMoniker_GetDisplayName(mon, pbc, NULL, ppwzTarget);
379 IBindCtx_Release(pbc);
380 IMoniker_Release(mon);
381 }
382 else
383 *ppwzTarget = NULL;
384 }
385 if (ppwzLocation)
386 *ppwzLocation = hlink_co_strdupW( This->Location );
387
388 TRACE("(Target: %s Location: %s)\n",
389 (ppwzTarget)?debugstr_w(*ppwzTarget):"<NULL>",
390 (ppwzLocation)?debugstr_w(*ppwzLocation):"<NULL>");
391
392 return S_OK;
393 }
394
395 static HRESULT WINAPI IHlink_fnSetFriendlyName (IHlink *iface,
396 LPCWSTR pwzFriendlyName)
397 {
398 HlinkImpl *This = impl_from_IHlink(iface);
399
400 TRACE("(%p) -> (%s)\n", This, debugstr_w(pwzFriendlyName));
401
402 heap_free(This->FriendlyName);
403 This->FriendlyName = hlink_strdupW( pwzFriendlyName );
404
405 return S_OK;
406 }
407
408 static HRESULT WINAPI IHlink_fnGetFriendlyName (IHlink* iface,
409 DWORD grfHLFNAMEF, LPWSTR* ppwzFriendlyName)
410 {
411 HlinkImpl *This = impl_from_IHlink(iface);
412
413 TRACE("(%p) -> (%i %p)\n", This, grfHLFNAMEF, ppwzFriendlyName);
414
415 /* FIXME: Only using explicitly set and cached friendly names */
416
417 if (This->FriendlyName)
418 *ppwzFriendlyName = hlink_co_strdupW( This->FriendlyName );
419 else
420 {
421 IMoniker *moniker;
422 HRESULT hres = __GetMoniker(This, &moniker, HLINKGETREF_DEFAULT);
423 if (FAILED(hres))
424 {
425 *ppwzFriendlyName = NULL;
426 return hres;
427 }
428 if (moniker)
429 {
430 IBindCtx *bcxt;
431 CreateBindCtx(0, &bcxt);
432
433 IMoniker_GetDisplayName(moniker, bcxt, NULL, ppwzFriendlyName);
434 IBindCtx_Release(bcxt);
435 IMoniker_Release(moniker);
436 }
437 else
438 *ppwzFriendlyName = NULL;
439 }
440
441 return S_OK;
442 }
443
444 static HRESULT WINAPI IHlink_fnSetTargetFrameName(IHlink* iface,
445 LPCWSTR pwzTargetFramename)
446 {
447 HlinkImpl *This = impl_from_IHlink(iface);
448 TRACE("(%p)->(%s)\n", This, debugstr_w(pwzTargetFramename));
449
450 heap_free(This->TargetFrameName);
451 This->TargetFrameName = hlink_strdupW( pwzTargetFramename );
452
453 return S_OK;
454 }
455
456 static HRESULT WINAPI IHlink_fnGetTargetFrameName(IHlink* iface,
457 LPWSTR *ppwzTargetFrameName)
458 {
459 HlinkImpl *This = impl_from_IHlink(iface);
460
461 TRACE("(%p)->(%p)\n", This, ppwzTargetFrameName);
462
463 if(!This->TargetFrameName) {
464 *ppwzTargetFrameName = NULL;
465 return S_FALSE;
466 }
467
468 *ppwzTargetFrameName = hlink_co_strdupW( This->TargetFrameName );
469 if(!*ppwzTargetFrameName)
470 return E_OUTOFMEMORY;
471
472 return S_OK;
473 }
474
475 static HRESULT WINAPI IHlink_fnGetMiscStatus(IHlink* iface, DWORD* pdwStatus)
476 {
477 FIXME("\n");
478 return E_NOTIMPL;
479 }
480
481 static HRESULT WINAPI IHlink_fnNavigate(IHlink *iface, DWORD flags, IBindCtx *user_bind_ctx,
482 IBindStatusCallback *bind_callback, IHlinkBrowseContext *browse_ctx)
483 {
484 HlinkImpl *This = impl_from_IHlink(iface);
485 IMoniker *mon = NULL;
486 HRESULT r;
487
488 TRACE("hlink %p, flags %#x, user_bind_ctx %p, bind_callback %p, browse_ctx %p.\n",
489 This, flags, user_bind_ctx, bind_callback, browse_ctx);
490
491 if (This->async_bind_ctx)
492 return E_UNEXPECTED;
493
494 r = __GetMoniker(This, &mon, HLINKGETREF_ABSOLUTE);
495 TRACE("Moniker %p\n", mon);
496
497 if (SUCCEEDED(r))
498 {
499 IBindCtx *bind_ctx = NULL;
500 IUnknown *unk = NULL;
501 IHlinkTarget *target;
502
503 if (browse_ctx)
504 {
505 r = IHlinkBrowseContext_GetObject(browse_ctx, mon, TRUE, &unk);
506 if (r != S_OK)
507 {
508 CreateBindCtx(0, &bind_ctx);
509 RegisterBindStatusCallback(bind_ctx, &This->IBindStatusCallback_iface, NULL, 0);
510 This->bind_callback = bind_callback;
511 r = IMoniker_BindToObject(mon, bind_ctx, NULL, &IID_IUnknown, (void**)&unk);
512 if (r == MK_S_ASYNCHRONOUS)
513 {
514 This->async_bind_ctx = bind_ctx;
515 This->async_flags = flags;
516 if (bind_callback)
517 IBindStatusCallback_AddRef(bind_callback);
518 IHlinkBrowseContext_AddRef(This->async_browse_ctx = browse_ctx);
519 IMoniker_Release(mon);
520 return r;
521 }
522 }
523 if (r == S_OK)
524 {
525 r = IUnknown_QueryInterface(unk, &IID_IHlinkTarget, (void **)&target);
526 IUnknown_Release(unk);
527 }
528 if (r == S_OK)
529 {
530 if (bind_ctx) IHlinkTarget_SetBrowseContext(target, browse_ctx);
531 r = IHlinkTarget_Navigate(target, flags, This->Location);
532 IHlinkTarget_Release(target);
533 }
534
535 RevokeBindStatusCallback(bind_ctx, &This->IBindStatusCallback_iface);
536 if (bind_ctx) IBindCtx_Release(bind_ctx);
537 }
538 else
539 {
540 static const WCHAR szOpen[] = {'o','p','e','n',0};
541 LPWSTR target = NULL;
542
543 r = IHlink_GetStringReference(iface, HLINKGETREF_DEFAULT, &target, NULL);
544 if (SUCCEEDED(r) && target)
545 {
546 ShellExecuteW(NULL, szOpen, target, NULL, NULL, SW_SHOW);
547 CoTaskMemFree(target);
548 r = DRAGDROP_S_DROP;
549 }
550 }
551 IMoniker_Release(mon);
552 }
553
554 if (This->Site)
555 IHlinkSite_OnNavigationComplete(This->Site, This->SiteData, 0, r, NULL);
556
557 TRACE("Finished Navigation\n");
558 return r;
559 }
560
561 static HRESULT WINAPI IHlink_fnSetAdditionalParams(IHlink* iface,
562 LPCWSTR pwzAdditionalParams)
563 {
564 TRACE("Not implemented in native IHlink\n");
565 return E_NOTIMPL;
566 }
567
568 static HRESULT WINAPI IHlink_fnGetAdditionalParams(IHlink* iface,
569 LPWSTR* ppwzAdditionalParams)
570 {
571 TRACE("Not implemented in native IHlink\n");
572 return E_NOTIMPL;
573 }
574
575 static const IHlinkVtbl hlvt =
576 {
577 IHlink_fnQueryInterface,
578 IHlink_fnAddRef,
579 IHlink_fnRelease,
580 IHlink_fnSetHlinkSite,
581 IHlink_fnGetHlinkSite,
582 IHlink_fnSetMonikerReference,
583 IHlink_fnGetMonikerReference,
584 IHlink_fnSetStringReference,
585 IHlink_fnGetStringReference,
586 IHlink_fnSetFriendlyName,
587 IHlink_fnGetFriendlyName,
588 IHlink_fnSetTargetFrameName,
589 IHlink_fnGetTargetFrameName,
590 IHlink_fnGetMiscStatus,
591 IHlink_fnNavigate,
592 IHlink_fnSetAdditionalParams,
593 IHlink_fnGetAdditionalParams
594 };
595
596 static HRESULT WINAPI IDataObject_fnQueryInterface(IDataObject* iface,
597 REFIID riid, LPVOID *ppvObj)
598 {
599 HlinkImpl *This = impl_from_IDataObject(iface);
600 TRACE("%p\n", This);
601 return IHlink_QueryInterface(&This->IHlink_iface, riid, ppvObj);
602 }
603
604 static ULONG WINAPI IDataObject_fnAddRef (IDataObject* iface)
605 {
606 HlinkImpl *This = impl_from_IDataObject(iface);
607 TRACE("%p\n", This);
608 return IHlink_AddRef(&This->IHlink_iface);
609 }
610
611 static ULONG WINAPI IDataObject_fnRelease (IDataObject* iface)
612 {
613 HlinkImpl *This = impl_from_IDataObject(iface);
614 TRACE("%p\n", This);
615 return IHlink_Release(&This->IHlink_iface);
616 }
617
618 static HRESULT WINAPI IDataObject_fnGetData(IDataObject* iface,
619 FORMATETC* pformatetcIn, STGMEDIUM* pmedium)
620 {
621 FIXME("\n");
622 return E_NOTIMPL;
623 }
624
625 static HRESULT WINAPI IDataObject_fnGetDataHere(IDataObject* iface,
626 FORMATETC* pformatetc, STGMEDIUM* pmedium)
627 {
628 FIXME("\n");
629 return E_NOTIMPL;
630 }
631
632 static HRESULT WINAPI IDataObject_fnQueryGetData(IDataObject* iface,
633 FORMATETC* pformatetc)
634 {
635 FIXME("\n");
636 return E_NOTIMPL;
637 }
638
639 static HRESULT WINAPI IDataObject_fnGetConicalFormatEtc(IDataObject* iface,
640 FORMATETC* pformatetcIn, FORMATETC* pformatetcOut)
641 {
642 FIXME("\n");
643 return E_NOTIMPL;
644 }
645
646 static HRESULT WINAPI IDataObject_fnSetData(IDataObject* iface,
647 FORMATETC* pformatetc, STGMEDIUM* pmedium, BOOL fRelease)
648 {
649 FIXME("\n");
650 return E_NOTIMPL;
651 }
652
653 static HRESULT WINAPI IDataObject_fnEnumFormatEtc(IDataObject* iface,
654 DWORD dwDirection, IEnumFORMATETC** ppenumFormatEtc)
655 {
656 FIXME("\n");
657 return E_NOTIMPL;
658 }
659
660 static HRESULT WINAPI IDataObject_fnDAdvise(IDataObject* iface,
661 FORMATETC* pformatetc, DWORD advf, IAdviseSink* pAdvSink,
662 DWORD* pdwConnection)
663 {
664 FIXME("\n");
665 return E_NOTIMPL;
666 }
667
668 static HRESULT WINAPI IDataObject_fnDUnadvise(IDataObject* iface,
669 DWORD dwConnection)
670 {
671 FIXME("\n");
672 return E_NOTIMPL;
673 }
674
675 static HRESULT WINAPI IDataObject_fnEnumDAdvise(IDataObject* iface,
676 IEnumSTATDATA** ppenumAdvise)
677 {
678 FIXME("\n");
679 return E_NOTIMPL;
680 }
681
682 static const IDataObjectVtbl dovt =
683 {
684 IDataObject_fnQueryInterface,
685 IDataObject_fnAddRef,
686 IDataObject_fnRelease,
687 IDataObject_fnGetData,
688 IDataObject_fnGetDataHere,
689 IDataObject_fnQueryGetData,
690 IDataObject_fnGetConicalFormatEtc,
691 IDataObject_fnSetData,
692 IDataObject_fnEnumFormatEtc,
693 IDataObject_fnDAdvise,
694 IDataObject_fnDUnadvise,
695 IDataObject_fnEnumDAdvise
696 };
697
698 static HRESULT WINAPI IPersistStream_fnQueryInterface(IPersistStream* iface,
699 REFIID riid, LPVOID *ppvObj)
700 {
701 HlinkImpl *This = impl_from_IPersistStream(iface);
702 TRACE("(%p)\n", This);
703 return IHlink_QueryInterface(&This->IHlink_iface, riid, ppvObj);
704 }
705
706 static ULONG WINAPI IPersistStream_fnAddRef (IPersistStream* iface)
707 {
708 HlinkImpl *This = impl_from_IPersistStream(iface);
709 TRACE("(%p)\n", This);
710 return IHlink_AddRef(&This->IHlink_iface);
711 }
712
713 static ULONG WINAPI IPersistStream_fnRelease (IPersistStream* iface)
714 {
715 HlinkImpl *This = impl_from_IPersistStream(iface);
716 TRACE("(%p)\n", This);
717 return IHlink_Release(&This->IHlink_iface);
718 }
719
720 static HRESULT WINAPI IPersistStream_fnGetClassID(IPersistStream* iface,
721 CLSID* pClassID)
722 {
723 HlinkImpl *This = impl_from_IPersistStream(iface);
724 TRACE("(%p)\n", This);
725 *pClassID = CLSID_StdHlink;
726 return S_OK;
727 }
728
729 static HRESULT WINAPI IPersistStream_fnIsDirty(IPersistStream* iface)
730 {
731 FIXME("\n");
732 return E_NOTIMPL;
733 }
734
735 static HRESULT write_hlink_string(IStream *pStm, LPCWSTR str)
736 {
737 DWORD len;
738 HRESULT hr;
739
740 TRACE("(%p, %s)\n", pStm, debugstr_w(str));
741
742 len = lstrlenW(str) + 1;
743
744 hr = IStream_Write(pStm, &len, sizeof(len), NULL);
745 if (FAILED(hr)) return hr;
746
747 hr = IStream_Write(pStm, str, len * sizeof(WCHAR), NULL);
748 if (FAILED(hr)) return hr;
749
750 return S_OK;
751 }
752
753 static inline ULONG size_hlink_string(LPCWSTR str)
754 {
755 return sizeof(DWORD) + (lstrlenW(str) + 1) * sizeof(WCHAR);
756 }
757
758 static HRESULT read_hlink_string(IStream *pStm, LPWSTR *out_str)
759 {
760 LPWSTR str;
761 DWORD len;
762 ULONG read;
763 HRESULT hr;
764
765 hr = IStream_Read(pStm, &len, sizeof(len), &read);
766 if (FAILED(hr)) return hr;
767 if (read != sizeof(len)) return STG_E_READFAULT;
768
769 TRACE("read len %d\n", len);
770
771 str = heap_alloc(len * sizeof(WCHAR));
772 if (!str) return E_OUTOFMEMORY;
773
774 hr = IStream_Read(pStm, str, len * sizeof(WCHAR), &read);
775 if (FAILED(hr))
776 {
777 heap_free(str);
778 return hr;
779 }
780 if (read != len * sizeof(WCHAR))
781 {
782 heap_free(str);
783 return STG_E_READFAULT;
784 }
785 TRACE("read string %s\n", debugstr_w(str));
786
787 *out_str = str;
788 return S_OK;
789 }
790
791 static HRESULT WINAPI IPersistStream_fnLoad(IPersistStream* iface,
792 IStream* pStm)
793 {
794 HRESULT r;
795 DWORD hdr[2];
796 DWORD read;
797 HlinkImpl *This = impl_from_IPersistStream(iface);
798
799 r = IStream_Read(pStm, hdr, sizeof(hdr), &read);
800 if (read != sizeof(hdr) || (hdr[0] != HLINK_SAVE_MAGIC))
801 {
802 r = E_FAIL;
803 goto end;
804 }
805 if (hdr[1] & ~HLINK_SAVE_ALL)
806 FIXME("unknown flag(s) 0x%x\n", hdr[1] & ~HLINK_SAVE_ALL);
807
808 if (hdr[1] & HLINK_SAVE_TARGET_FRAME_PRESENT)
809 {
810 TRACE("loading target frame name\n");
811 r = read_hlink_string(pStm, &This->TargetFrameName);
812 if (FAILED(r)) goto end;
813 }
814
815 if (hdr[1] & HLINK_SAVE_FRIENDLY_PRESENT)
816 {
817 TRACE("loading target friendly name\n");
818 if (!(hdr[1] & 0x4))
819 FIXME("0x4 flag not present with friendly name flag - not sure what this means\n");
820 r = read_hlink_string(pStm, &This->FriendlyName);
821 if (FAILED(r)) goto end;
822 }
823
824 if (hdr[1] & HLINK_SAVE_MONIKER_PRESENT)
825 {
826 TRACE("loading moniker\n");
827 r = OleLoadFromStream(pStm, &IID_IMoniker, (LPVOID*)&(This->Moniker));
828 if (FAILED(r))
829 goto end;
830 This->absolute = (hdr[1] & HLINK_SAVE_MONIKER_IS_ABSOLUTE) != 0;
831 }
832
833 if (hdr[1] & HLINK_SAVE_LOCATION_PRESENT)
834 {
835 TRACE("loading location\n");
836 r = read_hlink_string(pStm, &This->Location);
837 if (FAILED(r)) goto end;
838 }
839
840 end:
841 TRACE("Load Result 0x%x (%p)\n", r, This->Moniker);
842
843 return r;
844 }
845
846 static HRESULT WINAPI IPersistStream_fnSave(IPersistStream* iface,
847 IStream* pStm, BOOL fClearDirty)
848 {
849 HRESULT r;
850 HlinkImpl *This = impl_from_IPersistStream(iface);
851 DWORD hdr[2];
852 IMoniker *moniker;
853
854 TRACE("(%p) Moniker(%p)\n", This, This->Moniker);
855
856 r = __GetMoniker(This, &moniker, HLINKGETREF_DEFAULT);
857 if (FAILED(r))
858 return r;
859 r = E_FAIL;
860
861 hdr[0] = HLINK_SAVE_MAGIC;
862 hdr[1] = 0;
863
864 if (moniker)
865 hdr[1] |= HLINK_SAVE_MONIKER_PRESENT;
866 if (This->absolute)
867 hdr[1] |= HLINK_SAVE_MONIKER_IS_ABSOLUTE;
868 if (This->Location)
869 hdr[1] |= HLINK_SAVE_LOCATION_PRESENT;
870 if (This->FriendlyName)
871 hdr[1] |= HLINK_SAVE_FRIENDLY_PRESENT | 4 /* FIXME */;
872 if (This->TargetFrameName)
873 hdr[1] |= HLINK_SAVE_TARGET_FRAME_PRESENT;
874
875 IStream_Write(pStm, hdr, sizeof(hdr), NULL);
876
877 if (This->TargetFrameName)
878 {
879 r = write_hlink_string(pStm, This->TargetFrameName);
880 if (FAILED(r)) goto end;
881 }
882
883 if (This->FriendlyName)
884 {
885 r = write_hlink_string(pStm, This->FriendlyName);
886 if (FAILED(r)) goto end;
887 }
888
889 if (moniker)
890 {
891 IPersistStream* monstream;
892
893 monstream = NULL;
894 IMoniker_QueryInterface(moniker, &IID_IPersistStream,
895 (LPVOID*)&monstream);
896 if (monstream)
897 {
898 r = OleSaveToStream(monstream, pStm);
899 IPersistStream_Release(monstream);
900 }
901 if (FAILED(r)) goto end;
902 }
903
904 if (This->Location)
905 {
906 r = write_hlink_string(pStm, This->Location);
907 if (FAILED(r)) goto end;
908 }
909
910 end:
911 if (moniker) IMoniker_Release(moniker);
912 TRACE("Save Result 0x%x\n", r);
913
914 return r;
915 }
916
917 static HRESULT WINAPI IPersistStream_fnGetSizeMax(IPersistStream* iface,
918 ULARGE_INTEGER* pcbSize)
919 {
920 HRESULT r;
921 HlinkImpl *This = impl_from_IPersistStream(iface);
922 IMoniker *moniker;
923
924 TRACE("(%p) Moniker(%p)\n", This, This->Moniker);
925
926 pcbSize->QuadPart = sizeof(DWORD)*2;
927
928 if (This->TargetFrameName)
929 pcbSize->QuadPart += size_hlink_string(This->TargetFrameName);
930
931 if (This->FriendlyName)
932 pcbSize->QuadPart += size_hlink_string(This->FriendlyName);
933
934 r = __GetMoniker(This, &moniker, HLINKGETREF_DEFAULT);
935 if (FAILED(r))
936 return r;
937 r = E_FAIL;
938
939 if (moniker)
940 {
941 IPersistStream* monstream = NULL;
942 IMoniker_QueryInterface(moniker, &IID_IPersistStream,
943 (LPVOID*)&monstream);
944 if (monstream)
945 {
946 ULARGE_INTEGER mon_size;
947 r = IPersistStream_GetSizeMax(monstream, &mon_size);
948 pcbSize->QuadPart += mon_size.QuadPart;
949 IPersistStream_Release(monstream);
950 }
951 IMoniker_Release(moniker);
952 }
953
954 if (This->Location)
955 pcbSize->QuadPart += size_hlink_string(This->Location);
956
957 return r;
958 }
959
960 static const IPersistStreamVtbl psvt =
961 {
962 IPersistStream_fnQueryInterface,
963 IPersistStream_fnAddRef,
964 IPersistStream_fnRelease,
965 IPersistStream_fnGetClassID,
966 IPersistStream_fnIsDirty,
967 IPersistStream_fnLoad,
968 IPersistStream_fnSave,
969 IPersistStream_fnGetSizeMax,
970 };
971
972 static HlinkImpl *impl_from_IBindStatusCallback(IBindStatusCallback *iface)
973 {
974 return CONTAINING_RECORD(iface, HlinkImpl, IBindStatusCallback_iface);
975 }
976
977 static HRESULT WINAPI bind_callback_QueryInterface(IBindStatusCallback *iface, REFIID iid, void **out)
978 {
979 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IBindStatusCallback))
980 {
981 IBindStatusCallback_AddRef(*out = iface);
982 return S_OK;
983 }
984
985 WARN("No interface for %s.\n", debugstr_guid(iid));
986 return E_NOINTERFACE;
987 }
988
989 static ULONG WINAPI bind_callback_AddRef(IBindStatusCallback *iface)
990 {
991 HlinkImpl *hlink = impl_from_IBindStatusCallback(iface);
992 return IHlink_AddRef(&hlink->IHlink_iface);
993 }
994
995 static ULONG WINAPI bind_callback_Release(IBindStatusCallback *iface)
996 {
997 HlinkImpl *hlink = impl_from_IBindStatusCallback(iface);
998 return IHlink_Release(&hlink->IHlink_iface);
999 }
1000
1001 static HRESULT WINAPI bind_callback_OnStartBinding(IBindStatusCallback *iface,
1002 DWORD reserved, IBinding *binding)
1003 {
1004 HlinkImpl *hlink = impl_from_IBindStatusCallback(iface);
1005
1006 TRACE("hlink %p, reserved %#x, binding %p.\n", hlink, reserved, binding);
1007
1008 if (hlink->bind_callback)
1009 return IBindStatusCallback_OnStartBinding(hlink->bind_callback, reserved, binding);
1010 return S_OK;
1011 }
1012
1013 static HRESULT WINAPI bind_callback_GetPriority(IBindStatusCallback *iface, LONG *priority)
1014 {
1015 FIXME("iface %p, priority %p, stub!\n", iface, priority);
1016 return E_NOTIMPL;
1017 }
1018
1019 static HRESULT WINAPI bind_callback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
1020 {
1021 HlinkImpl *hlink = impl_from_IBindStatusCallback(iface);
1022
1023 TRACE("hlink %p, reserved %#x.\n", hlink, reserved);
1024
1025 if (hlink->bind_callback)
1026 return IBindStatusCallback_OnLowResource(hlink->bind_callback, reserved);
1027 return S_OK;
1028 }
1029
1030 static HRESULT WINAPI bind_callback_OnProgress(IBindStatusCallback *iface,
1031 ULONG progress, ULONG max, ULONG status, const WCHAR *text)
1032 {
1033 HlinkImpl *hlink = impl_from_IBindStatusCallback(iface);
1034
1035 TRACE("hlink %p, progress %u, max %u, status %u, text %s.\n",
1036 hlink, progress, max, status, debugstr_w(text));
1037
1038 if (hlink->bind_callback)
1039 return IBindStatusCallback_OnProgress(hlink->bind_callback, progress, max, status, text);
1040 return S_OK;
1041 }
1042
1043 static HRESULT WINAPI bind_callback_OnStopBinding(IBindStatusCallback *iface,
1044 HRESULT hr, const WCHAR *error)
1045 {
1046 HlinkImpl *hlink = impl_from_IBindStatusCallback(iface);
1047
1048 TRACE("hlink %p, hr %#x, error %s.\n", hlink, hr, debugstr_w(error));
1049
1050 if (hlink->bind_callback)
1051 IBindStatusCallback_OnStopBinding(hlink->bind_callback, hr, error);
1052
1053 if (hlink->async_bind_ctx)
1054 {
1055 if (hlink->bind_callback)
1056 IBindStatusCallback_Release(hlink->bind_callback);
1057 RevokeBindStatusCallback(hlink->async_bind_ctx, iface);
1058 IBindCtx_Release(hlink->async_bind_ctx);
1059 IHlinkBrowseContext_Release(hlink->async_browse_ctx);
1060 hlink->async_bind_ctx = NULL;
1061 }
1062 return S_OK;
1063 }
1064
1065 static HRESULT WINAPI bind_callback_GetBindInfo(IBindStatusCallback *iface,
1066 DWORD *bind_flags, BINDINFO *bind_info)
1067 {
1068 HlinkImpl *hlink = impl_from_IBindStatusCallback(iface);
1069
1070 TRACE("hlink %p, bind_flags %p, bind_info %p.\n", hlink, bind_flags, bind_info);
1071
1072 if (hlink->bind_callback)
1073 return IBindStatusCallback_GetBindInfo(hlink->bind_callback, bind_flags, bind_info);
1074 return S_OK;
1075 }
1076
1077 static HRESULT WINAPI bind_callback_OnDataAvailable(IBindStatusCallback *iface,
1078 DWORD flags, DWORD size, FORMATETC *formatetc, STGMEDIUM *stgmed)
1079 {
1080 FIXME("iface %p, flags %#x, size %d, formatetc %p, stgmed %p, stub!\n",
1081 iface, flags, size, formatetc, stgmed);
1082 return E_NOTIMPL;
1083 }
1084
1085 static HRESULT WINAPI bind_callback_OnObjectAvailable(IBindStatusCallback *iface,
1086 REFIID iid, IUnknown *unk)
1087 {
1088 HlinkImpl *hlink = impl_from_IBindStatusCallback(iface);
1089 IHlinkTarget *target;
1090 HRESULT hr;
1091
1092 TRACE("hlink %p, iid %s, unk %p.\n", hlink, debugstr_guid(iid), unk);
1093
1094 if (hlink->bind_callback)
1095 IBindStatusCallback_OnObjectAvailable(hlink->bind_callback, iid, unk);
1096
1097 if (hlink->async_bind_ctx)
1098 {
1099 hr = IUnknown_QueryInterface(unk, &IID_IHlinkTarget, (void **)&target);
1100 if (FAILED(hr))
1101 return hr;
1102
1103 IHlinkTarget_SetBrowseContext(target, hlink->async_browse_ctx);
1104 hr = IHlinkTarget_Navigate(target, hlink->async_flags, hlink->Location);
1105 IHlinkTarget_Release(target);
1106
1107 if (hlink->Site)
1108 IHlinkSite_OnNavigationComplete(hlink->Site, hlink->SiteData, 0, hr, NULL);
1109
1110 return hr;
1111 }
1112
1113 return S_OK;
1114 }
1115
1116 static const IBindStatusCallbackVtbl bind_callback_vtbl =
1117 {
1118 bind_callback_QueryInterface,
1119 bind_callback_AddRef,
1120 bind_callback_Release,
1121 bind_callback_OnStartBinding,
1122 bind_callback_GetPriority,
1123 bind_callback_OnLowResource,
1124 bind_callback_OnProgress,
1125 bind_callback_OnStopBinding,
1126 bind_callback_GetBindInfo,
1127 bind_callback_OnDataAvailable,
1128 bind_callback_OnObjectAvailable,
1129 };
1130
1131 HRESULT HLink_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
1132 {
1133 HlinkImpl * hl;
1134
1135 TRACE("unkOut=%p riid=%s\n", pUnkOuter, debugstr_guid(riid));
1136 *ppv = NULL;
1137
1138 if (pUnkOuter)
1139 return CLASS_E_NOAGGREGATION;
1140
1141 hl = heap_alloc_zero(sizeof(HlinkImpl));
1142 if (!hl)
1143 return E_OUTOFMEMORY;
1144
1145 hl->ref = 1;
1146 hl->IHlink_iface.lpVtbl = &hlvt;
1147 hl->IPersistStream_iface.lpVtbl = &psvt;
1148 hl->IDataObject_iface.lpVtbl = &dovt;
1149 hl->IBindStatusCallback_iface.lpVtbl = &bind_callback_vtbl;
1150
1151 *ppv = hl;
1152 return S_OK;
1153 }