d3d9/tests: Don't fail d3d9ex if the window manager restores focus too soon.
[wine.git] / dlls / hlink / link.c
blob8c7b06f6f2a3d7a23893fb3dabaaeb58673f3775
1 /*
2 * Implementation of hyperlinking (hlink.dll)
4 * Copyright 2005 Aric Stewart for CodeWeavers
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.
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.
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
21 #include "hlink_private.h"
23 #include "shellapi.h"
24 #include "hlguids.h"
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(hlink);
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)
40 typedef struct
42 IHlink IHlink_iface;
43 LONG ref;
45 IPersistStream IPersistStream_iface;
46 IDataObject IDataObject_iface;
48 LPWSTR FriendlyName;
49 LPWSTR Location;
50 LPWSTR TargetFrameName;
51 IMoniker *Moniker;
52 IHlinkSite *Site;
53 DWORD SiteData;
54 BOOL absolute;
56 IBindStatusCallback IBindStatusCallback_iface;
57 IBindStatusCallback *bind_callback;
58 IBindCtx *async_bind_ctx;
59 DWORD async_flags;
60 IHlinkBrowseContext *async_browse_ctx;
61 } HlinkImpl;
63 static inline HlinkImpl *impl_from_IHlink(IHlink *iface)
65 return CONTAINING_RECORD(iface, HlinkImpl, IHlink_iface);
69 static inline HlinkImpl* impl_from_IPersistStream( IPersistStream* iface)
71 return CONTAINING_RECORD(iface, HlinkImpl, IPersistStream_iface);
74 static inline HlinkImpl* impl_from_IDataObject( IDataObject* iface)
76 return CONTAINING_RECORD(iface, HlinkImpl, IDataObject_iface);
79 static HRESULT __GetMoniker(HlinkImpl* This, IMoniker** moniker,
80 DWORD ref_type)
82 HRESULT hres;
84 if (ref_type == HLINKGETREF_DEFAULT)
85 ref_type = HLINKGETREF_RELATIVE;
87 if (This->Moniker)
89 DWORD mktype = MKSYS_NONE;
91 hres = IMoniker_IsSystemMoniker(This->Moniker, &mktype);
92 if (hres == S_OK && mktype != MKSYS_NONE)
94 *moniker = This->Moniker;
95 IMoniker_AddRef(*moniker);
96 return S_OK;
100 if (ref_type == HLINKGETREF_ABSOLUTE && This->Site)
102 IMoniker *hls_moniker;
104 hres = IHlinkSite_GetMoniker(This->Site, This->SiteData,
105 OLEGETMONIKER_FORCEASSIGN, OLEWHICHMK_CONTAINER, &hls_moniker);
106 if (FAILED(hres))
107 return hres;
109 if (This->Moniker)
111 hres = IMoniker_ComposeWith(hls_moniker, This->Moniker, FALSE,
112 moniker);
113 IMoniker_Release(hls_moniker);
114 return hres;
117 *moniker = hls_moniker;
118 return S_OK;
121 *moniker = This->Moniker;
122 if (*moniker)
123 IMoniker_AddRef(*moniker);
125 return S_OK;
128 static HRESULT WINAPI IHlink_fnQueryInterface(IHlink* iface, REFIID riid,
129 LPVOID *ppvObj)
131 HlinkImpl *This = impl_from_IHlink(iface);
133 TRACE ("(%p)->(%s,%p)\n", This, debugstr_guid (riid), ppvObj);
135 *ppvObj = NULL;
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;
144 if (*ppvObj)
146 IUnknown_AddRef((IUnknown*)(*ppvObj));
147 return S_OK;
149 return E_NOINTERFACE;
152 static ULONG WINAPI IHlink_fnAddRef (IHlink* iface)
154 HlinkImpl *This = impl_from_IHlink(iface);
155 ULONG refCount = InterlockedIncrement(&This->ref);
157 TRACE("(%p)->(count=%lu)\n", This, refCount - 1);
159 return refCount;
162 static ULONG WINAPI IHlink_fnRelease (IHlink* iface)
164 HlinkImpl *This = impl_from_IHlink(iface);
165 ULONG refCount = InterlockedDecrement(&This->ref);
167 TRACE("(%p)->(count=%lu)\n", This, refCount + 1);
168 if (refCount)
169 return refCount;
171 TRACE("-- destroying IHlink (%p)\n", This);
172 free(This->FriendlyName);
173 free(This->TargetFrameName);
174 free(This->Location);
175 if (This->Moniker)
176 IMoniker_Release(This->Moniker);
177 if (This->Site)
178 IHlinkSite_Release(This->Site);
179 free(This);
180 return 0;
183 static HRESULT WINAPI IHlink_fnSetHlinkSite( IHlink* iface,
184 IHlinkSite* pihlSite, DWORD dwSiteData)
186 HlinkImpl *This = impl_from_IHlink(iface);
188 TRACE("(%p)->(%p %li)\n", This, pihlSite, dwSiteData);
190 if (This->Site)
191 IHlinkSite_Release(This->Site);
193 This->Site = pihlSite;
194 if (This->Site)
195 IHlinkSite_AddRef(This->Site);
197 This->SiteData = dwSiteData;
199 return S_OK;
202 static HRESULT WINAPI IHlink_fnGetHlinkSite( IHlink* iface,
203 IHlinkSite** ppihlSite, DWORD *pdwSiteData)
205 HlinkImpl *This = impl_from_IHlink(iface);
207 TRACE("(%p)->(%p %p)\n", This, ppihlSite, pdwSiteData);
209 *ppihlSite = This->Site;
211 if (This->Site) {
212 IHlinkSite_AddRef(This->Site);
213 *pdwSiteData = This->SiteData;
216 return S_OK;
219 static HRESULT WINAPI IHlink_fnSetMonikerReference( IHlink* iface,
220 DWORD rfHLSETF, IMoniker *pmkTarget, LPCWSTR pwzLocation)
222 HlinkImpl *This = impl_from_IHlink(iface);
224 TRACE("(%p)->(%li %p %s)\n", This, rfHLSETF, pmkTarget,
225 debugstr_w(pwzLocation));
227 if(rfHLSETF == 0)
228 return E_INVALIDARG;
229 if(!(rfHLSETF & (HLINKSETF_TARGET | HLINKSETF_LOCATION)))
230 return rfHLSETF;
232 if(rfHLSETF & HLINKSETF_TARGET){
233 if (This->Moniker)
234 IMoniker_Release(This->Moniker);
236 This->Moniker = pmkTarget;
237 if (This->Moniker)
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);
250 if(rfHLSETF & HLINKSETF_LOCATION){
251 free(This->Location);
252 This->Location = wcsdup( pwzLocation );
255 return S_OK;
258 static HRESULT WINAPI IHlink_fnSetStringReference(IHlink* iface,
259 DWORD grfHLSETF, LPCWSTR pwzTarget, LPCWSTR pwzLocation)
261 HlinkImpl *This = impl_from_IHlink(iface);
263 TRACE("(%p)->(%li %s %s)\n", This, grfHLSETF, debugstr_w(pwzTarget),
264 debugstr_w(pwzLocation));
266 if(grfHLSETF > (HLINKSETF_TARGET | HLINKSETF_LOCATION) &&
267 grfHLSETF < -(HLINKSETF_TARGET | HLINKSETF_LOCATION))
268 return grfHLSETF;
270 if (grfHLSETF & HLINKSETF_TARGET)
272 if (This->Moniker)
274 IMoniker_Release(This->Moniker);
275 This->Moniker = NULL;
277 if (pwzTarget && *pwzTarget)
279 IMoniker *pMon;
280 IBindCtx *pbc = NULL;
281 ULONG eaten;
282 HRESULT r;
284 r = CreateBindCtx(0, &pbc);
285 if (FAILED(r))
286 return E_OUTOFMEMORY;
288 r = MkParseDisplayName(pbc, pwzTarget, &eaten, &pMon);
289 IBindCtx_Release(pbc);
291 if (FAILED(r))
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))
300 ERR("couldn't create moniker for %s, failed with error 0x%08lx\n",
301 debugstr_w(pwzTarget), r);
302 return r;
306 IHlink_SetMonikerReference(iface, HLINKSETF_TARGET, pMon, NULL);
307 IMoniker_Release(pMon);
311 if (grfHLSETF & HLINKSETF_LOCATION)
313 free(This->Location);
314 This->Location = NULL;
315 if (pwzLocation && *pwzLocation)
316 This->Location = wcsdup( pwzLocation );
319 return S_OK;
322 static HRESULT WINAPI IHlink_fnGetMonikerReference(IHlink* iface,
323 DWORD dwWhichRef, IMoniker **ppimkTarget, LPWSTR *ppwzLocation)
325 HlinkImpl *This = impl_from_IHlink(iface);
327 TRACE("(%p) -> (%li %p %p)\n", This, dwWhichRef, ppimkTarget,
328 ppwzLocation);
330 if (ppimkTarget)
332 HRESULT hres = __GetMoniker(This, ppimkTarget, dwWhichRef);
333 if (FAILED(hres))
335 if (ppwzLocation)
336 *ppwzLocation = NULL;
337 return hres;
341 if (ppwzLocation)
342 IHlink_GetStringReference(iface, dwWhichRef, NULL, ppwzLocation);
344 return S_OK;
347 static HRESULT WINAPI IHlink_fnGetStringReference (IHlink* iface,
348 DWORD dwWhichRef, LPWSTR *ppwzTarget, LPWSTR *ppwzLocation)
350 HlinkImpl *This = impl_from_IHlink(iface);
352 TRACE("(%p) -> (%li %p %p)\n", This, dwWhichRef, ppwzTarget, ppwzLocation);
354 if(dwWhichRef != -1 && dwWhichRef & ~(HLINKGETREF_DEFAULT | HLINKGETREF_ABSOLUTE | HLINKGETREF_RELATIVE))
356 if(ppwzTarget)
357 *ppwzTarget = NULL;
358 if(ppwzLocation)
359 *ppwzLocation = NULL;
360 return E_INVALIDARG;
363 if (ppwzTarget)
365 IMoniker* mon;
366 HRESULT hres = __GetMoniker(This, &mon, dwWhichRef);
367 if (FAILED(hres))
369 if (ppwzLocation)
370 *ppwzLocation = NULL;
371 return hres;
373 if (mon)
375 IBindCtx *pbc;
377 CreateBindCtx( 0, &pbc);
378 IMoniker_GetDisplayName(mon, pbc, NULL, ppwzTarget);
379 IBindCtx_Release(pbc);
380 IMoniker_Release(mon);
382 else
383 *ppwzTarget = NULL;
385 if (ppwzLocation)
386 *ppwzLocation = hlink_co_strdupW( This->Location );
388 TRACE("(Target: %s Location: %s)\n",
389 (ppwzTarget)?debugstr_w(*ppwzTarget):"<NULL>",
390 (ppwzLocation)?debugstr_w(*ppwzLocation):"<NULL>");
392 return S_OK;
395 static HRESULT WINAPI IHlink_fnSetFriendlyName (IHlink *iface,
396 LPCWSTR pwzFriendlyName)
398 HlinkImpl *This = impl_from_IHlink(iface);
400 TRACE("(%p) -> (%s)\n", This, debugstr_w(pwzFriendlyName));
402 free(This->FriendlyName);
403 This->FriendlyName = wcsdup( pwzFriendlyName );
405 return S_OK;
408 static HRESULT WINAPI IHlink_fnGetFriendlyName (IHlink* iface,
409 DWORD grfHLFNAMEF, LPWSTR* ppwzFriendlyName)
411 HlinkImpl *This = impl_from_IHlink(iface);
413 TRACE("(%p) -> (%li %p)\n", This, grfHLFNAMEF, ppwzFriendlyName);
415 /* FIXME: Only using explicitly set and cached friendly names */
417 if (This->FriendlyName)
418 *ppwzFriendlyName = hlink_co_strdupW( This->FriendlyName );
419 else
421 IMoniker *moniker;
422 HRESULT hres = __GetMoniker(This, &moniker, HLINKGETREF_DEFAULT);
423 if (FAILED(hres))
425 *ppwzFriendlyName = NULL;
426 return hres;
428 if (moniker)
430 IBindCtx *bcxt;
431 CreateBindCtx(0, &bcxt);
433 IMoniker_GetDisplayName(moniker, bcxt, NULL, ppwzFriendlyName);
434 IBindCtx_Release(bcxt);
435 IMoniker_Release(moniker);
437 else
438 *ppwzFriendlyName = NULL;
441 return S_OK;
444 static HRESULT WINAPI IHlink_fnSetTargetFrameName(IHlink* iface,
445 LPCWSTR pwzTargetFramename)
447 HlinkImpl *This = impl_from_IHlink(iface);
448 TRACE("(%p)->(%s)\n", This, debugstr_w(pwzTargetFramename));
450 free(This->TargetFrameName);
451 This->TargetFrameName = wcsdup( pwzTargetFramename );
453 return S_OK;
456 static HRESULT WINAPI IHlink_fnGetTargetFrameName(IHlink* iface,
457 LPWSTR *ppwzTargetFrameName)
459 HlinkImpl *This = impl_from_IHlink(iface);
461 TRACE("(%p)->(%p)\n", This, ppwzTargetFrameName);
463 if(!This->TargetFrameName) {
464 *ppwzTargetFrameName = NULL;
465 return S_FALSE;
468 *ppwzTargetFrameName = hlink_co_strdupW( This->TargetFrameName );
469 if(!*ppwzTargetFrameName)
470 return E_OUTOFMEMORY;
472 return S_OK;
475 static HRESULT WINAPI IHlink_fnGetMiscStatus(IHlink* iface, DWORD* pdwStatus)
477 FIXME("\n");
478 return E_NOTIMPL;
481 static HRESULT WINAPI IHlink_fnNavigate(IHlink *iface, DWORD flags, IBindCtx *user_bind_ctx,
482 IBindStatusCallback *bind_callback, IHlinkBrowseContext *browse_ctx)
484 HlinkImpl *This = impl_from_IHlink(iface);
485 IMoniker *mon = NULL;
486 HRESULT r;
488 TRACE("hlink %p, flags %#lx, user_bind_ctx %p, bind_callback %p, browse_ctx %p.\n",
489 This, flags, user_bind_ctx, bind_callback, browse_ctx);
491 if (This->async_bind_ctx)
492 return E_UNEXPECTED;
494 r = __GetMoniker(This, &mon, HLINKGETREF_ABSOLUTE);
495 TRACE("Moniker %p\n", mon);
497 if (SUCCEEDED(r))
499 IBindCtx *bind_ctx = NULL;
500 IUnknown *unk = NULL;
501 IHlinkTarget *target;
503 if (browse_ctx)
505 r = IHlinkBrowseContext_GetObject(browse_ctx, mon, TRUE, &unk);
506 if (r != S_OK)
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)
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;
523 if (r == S_OK)
525 r = IUnknown_QueryInterface(unk, &IID_IHlinkTarget, (void **)&target);
526 IUnknown_Release(unk);
528 if (r == S_OK)
530 if (bind_ctx) IHlinkTarget_SetBrowseContext(target, browse_ctx);
531 r = IHlinkTarget_Navigate(target, flags, This->Location);
532 IHlinkTarget_Release(target);
535 RevokeBindStatusCallback(bind_ctx, &This->IBindStatusCallback_iface);
536 if (bind_ctx) IBindCtx_Release(bind_ctx);
538 else
540 LPWSTR target = NULL;
542 r = IHlink_GetStringReference(iface, HLINKGETREF_DEFAULT, &target, NULL);
543 if (SUCCEEDED(r) && target)
545 ShellExecuteW(NULL, L"open", target, NULL, NULL, SW_SHOW);
546 CoTaskMemFree(target);
547 r = DRAGDROP_S_DROP;
550 IMoniker_Release(mon);
553 if (This->Site)
554 IHlinkSite_OnNavigationComplete(This->Site, This->SiteData, 0, r, NULL);
556 TRACE("Finished Navigation\n");
557 return r;
560 static HRESULT WINAPI IHlink_fnSetAdditionalParams(IHlink* iface,
561 LPCWSTR pwzAdditionalParams)
563 TRACE("Not implemented in native IHlink\n");
564 return E_NOTIMPL;
567 static HRESULT WINAPI IHlink_fnGetAdditionalParams(IHlink* iface,
568 LPWSTR* ppwzAdditionalParams)
570 TRACE("Not implemented in native IHlink\n");
571 return E_NOTIMPL;
574 static const IHlinkVtbl hlvt =
576 IHlink_fnQueryInterface,
577 IHlink_fnAddRef,
578 IHlink_fnRelease,
579 IHlink_fnSetHlinkSite,
580 IHlink_fnGetHlinkSite,
581 IHlink_fnSetMonikerReference,
582 IHlink_fnGetMonikerReference,
583 IHlink_fnSetStringReference,
584 IHlink_fnGetStringReference,
585 IHlink_fnSetFriendlyName,
586 IHlink_fnGetFriendlyName,
587 IHlink_fnSetTargetFrameName,
588 IHlink_fnGetTargetFrameName,
589 IHlink_fnGetMiscStatus,
590 IHlink_fnNavigate,
591 IHlink_fnSetAdditionalParams,
592 IHlink_fnGetAdditionalParams
595 static HRESULT WINAPI IDataObject_fnQueryInterface(IDataObject* iface,
596 REFIID riid, LPVOID *ppvObj)
598 HlinkImpl *This = impl_from_IDataObject(iface);
599 TRACE("%p\n", This);
600 return IHlink_QueryInterface(&This->IHlink_iface, riid, ppvObj);
603 static ULONG WINAPI IDataObject_fnAddRef (IDataObject* iface)
605 HlinkImpl *This = impl_from_IDataObject(iface);
606 TRACE("%p\n", This);
607 return IHlink_AddRef(&This->IHlink_iface);
610 static ULONG WINAPI IDataObject_fnRelease (IDataObject* iface)
612 HlinkImpl *This = impl_from_IDataObject(iface);
613 TRACE("%p\n", This);
614 return IHlink_Release(&This->IHlink_iface);
617 static HRESULT WINAPI IDataObject_fnGetData(IDataObject* iface,
618 FORMATETC* pformatetcIn, STGMEDIUM* pmedium)
620 FIXME("\n");
621 return E_NOTIMPL;
624 static HRESULT WINAPI IDataObject_fnGetDataHere(IDataObject* iface,
625 FORMATETC* pformatetc, STGMEDIUM* pmedium)
627 FIXME("\n");
628 return E_NOTIMPL;
631 static HRESULT WINAPI IDataObject_fnQueryGetData(IDataObject* iface,
632 FORMATETC* pformatetc)
634 FIXME("\n");
635 return E_NOTIMPL;
638 static HRESULT WINAPI IDataObject_fnGetConicalFormatEtc(IDataObject* iface,
639 FORMATETC* pformatetcIn, FORMATETC* pformatetcOut)
641 FIXME("\n");
642 return E_NOTIMPL;
645 static HRESULT WINAPI IDataObject_fnSetData(IDataObject* iface,
646 FORMATETC* pformatetc, STGMEDIUM* pmedium, BOOL fRelease)
648 FIXME("\n");
649 return E_NOTIMPL;
652 static HRESULT WINAPI IDataObject_fnEnumFormatEtc(IDataObject* iface,
653 DWORD dwDirection, IEnumFORMATETC** ppenumFormatEtc)
655 FIXME("\n");
656 return E_NOTIMPL;
659 static HRESULT WINAPI IDataObject_fnDAdvise(IDataObject* iface,
660 FORMATETC* pformatetc, DWORD advf, IAdviseSink* pAdvSink,
661 DWORD* pdwConnection)
663 FIXME("\n");
664 return E_NOTIMPL;
667 static HRESULT WINAPI IDataObject_fnDUnadvise(IDataObject* iface,
668 DWORD dwConnection)
670 FIXME("\n");
671 return E_NOTIMPL;
674 static HRESULT WINAPI IDataObject_fnEnumDAdvise(IDataObject* iface,
675 IEnumSTATDATA** ppenumAdvise)
677 FIXME("\n");
678 return E_NOTIMPL;
681 static const IDataObjectVtbl dovt =
683 IDataObject_fnQueryInterface,
684 IDataObject_fnAddRef,
685 IDataObject_fnRelease,
686 IDataObject_fnGetData,
687 IDataObject_fnGetDataHere,
688 IDataObject_fnQueryGetData,
689 IDataObject_fnGetConicalFormatEtc,
690 IDataObject_fnSetData,
691 IDataObject_fnEnumFormatEtc,
692 IDataObject_fnDAdvise,
693 IDataObject_fnDUnadvise,
694 IDataObject_fnEnumDAdvise
697 static HRESULT WINAPI IPersistStream_fnQueryInterface(IPersistStream* iface,
698 REFIID riid, LPVOID *ppvObj)
700 HlinkImpl *This = impl_from_IPersistStream(iface);
701 TRACE("(%p)\n", This);
702 return IHlink_QueryInterface(&This->IHlink_iface, riid, ppvObj);
705 static ULONG WINAPI IPersistStream_fnAddRef (IPersistStream* iface)
707 HlinkImpl *This = impl_from_IPersistStream(iface);
708 TRACE("(%p)\n", This);
709 return IHlink_AddRef(&This->IHlink_iface);
712 static ULONG WINAPI IPersistStream_fnRelease (IPersistStream* iface)
714 HlinkImpl *This = impl_from_IPersistStream(iface);
715 TRACE("(%p)\n", This);
716 return IHlink_Release(&This->IHlink_iface);
719 static HRESULT WINAPI IPersistStream_fnGetClassID(IPersistStream* iface,
720 CLSID* pClassID)
722 HlinkImpl *This = impl_from_IPersistStream(iface);
723 TRACE("(%p)\n", This);
724 *pClassID = CLSID_StdHlink;
725 return S_OK;
728 static HRESULT WINAPI IPersistStream_fnIsDirty(IPersistStream* iface)
730 FIXME("\n");
731 return E_NOTIMPL;
734 static HRESULT write_hlink_string(IStream *pStm, LPCWSTR str)
736 DWORD len;
737 HRESULT hr;
739 TRACE("(%p, %s)\n", pStm, debugstr_w(str));
741 len = lstrlenW(str) + 1;
743 hr = IStream_Write(pStm, &len, sizeof(len), NULL);
744 if (FAILED(hr)) return hr;
746 hr = IStream_Write(pStm, str, len * sizeof(WCHAR), NULL);
747 if (FAILED(hr)) return hr;
749 return S_OK;
752 static inline ULONG size_hlink_string(LPCWSTR str)
754 return sizeof(DWORD) + (lstrlenW(str) + 1) * sizeof(WCHAR);
757 static HRESULT read_hlink_string(IStream *pStm, LPWSTR *out_str)
759 LPWSTR str;
760 DWORD len;
761 ULONG read;
762 HRESULT hr;
764 hr = IStream_Read(pStm, &len, sizeof(len), &read);
765 if (FAILED(hr)) return hr;
766 if (read != sizeof(len)) return STG_E_READFAULT;
768 TRACE("read len %ld\n", len);
770 str = malloc(len * sizeof(WCHAR));
771 if (!str) return E_OUTOFMEMORY;
773 hr = IStream_Read(pStm, str, len * sizeof(WCHAR), &read);
774 if (FAILED(hr))
776 free(str);
777 return hr;
779 if (read != len * sizeof(WCHAR))
781 free(str);
782 return STG_E_READFAULT;
784 TRACE("read string %s\n", debugstr_w(str));
786 *out_str = str;
787 return S_OK;
790 static HRESULT WINAPI IPersistStream_fnLoad(IPersistStream* iface,
791 IStream* pStm)
793 HRESULT r;
794 DWORD hdr[2];
795 DWORD read;
796 HlinkImpl *This = impl_from_IPersistStream(iface);
798 r = IStream_Read(pStm, hdr, sizeof(hdr), &read);
799 if (read != sizeof(hdr) || (hdr[0] != HLINK_SAVE_MAGIC))
801 r = E_FAIL;
802 goto end;
804 if (hdr[1] & ~HLINK_SAVE_ALL)
805 FIXME("unknown flag(s) 0x%lx\n", hdr[1] & ~HLINK_SAVE_ALL);
807 if (hdr[1] & HLINK_SAVE_TARGET_FRAME_PRESENT)
809 TRACE("loading target frame name\n");
810 r = read_hlink_string(pStm, &This->TargetFrameName);
811 if (FAILED(r)) goto end;
814 if (hdr[1] & HLINK_SAVE_FRIENDLY_PRESENT)
816 TRACE("loading target friendly name\n");
817 if (!(hdr[1] & 0x4))
818 FIXME("0x4 flag not present with friendly name flag - not sure what this means\n");
819 r = read_hlink_string(pStm, &This->FriendlyName);
820 if (FAILED(r)) goto end;
823 if (hdr[1] & HLINK_SAVE_MONIKER_PRESENT)
825 TRACE("loading moniker\n");
826 r = OleLoadFromStream(pStm, &IID_IMoniker, (LPVOID*)&(This->Moniker));
827 if (FAILED(r))
828 goto end;
829 This->absolute = (hdr[1] & HLINK_SAVE_MONIKER_IS_ABSOLUTE) != 0;
832 if (hdr[1] & HLINK_SAVE_LOCATION_PRESENT)
834 TRACE("loading location\n");
835 r = read_hlink_string(pStm, &This->Location);
836 if (FAILED(r)) goto end;
839 end:
840 TRACE("Load Result 0x%lx (%p)\n", r, This->Moniker);
842 return r;
845 static HRESULT WINAPI IPersistStream_fnSave(IPersistStream* iface,
846 IStream* pStm, BOOL fClearDirty)
848 HRESULT r;
849 HlinkImpl *This = impl_from_IPersistStream(iface);
850 DWORD hdr[2];
851 IMoniker *moniker;
853 TRACE("(%p) Moniker(%p)\n", This, This->Moniker);
855 r = __GetMoniker(This, &moniker, HLINKGETREF_DEFAULT);
856 if (FAILED(r))
857 return r;
858 r = E_FAIL;
860 hdr[0] = HLINK_SAVE_MAGIC;
861 hdr[1] = 0;
863 if (moniker)
864 hdr[1] |= HLINK_SAVE_MONIKER_PRESENT;
865 if (This->absolute)
866 hdr[1] |= HLINK_SAVE_MONIKER_IS_ABSOLUTE;
867 if (This->Location)
868 hdr[1] |= HLINK_SAVE_LOCATION_PRESENT;
869 if (This->FriendlyName)
870 hdr[1] |= HLINK_SAVE_FRIENDLY_PRESENT | 4 /* FIXME */;
871 if (This->TargetFrameName)
872 hdr[1] |= HLINK_SAVE_TARGET_FRAME_PRESENT;
874 IStream_Write(pStm, hdr, sizeof(hdr), NULL);
876 if (This->TargetFrameName)
878 r = write_hlink_string(pStm, This->TargetFrameName);
879 if (FAILED(r)) goto end;
882 if (This->FriendlyName)
884 r = write_hlink_string(pStm, This->FriendlyName);
885 if (FAILED(r)) goto end;
888 if (moniker)
890 IPersistStream* monstream;
892 monstream = NULL;
893 IMoniker_QueryInterface(moniker, &IID_IPersistStream,
894 (LPVOID*)&monstream);
895 if (monstream)
897 r = OleSaveToStream(monstream, pStm);
898 IPersistStream_Release(monstream);
900 if (FAILED(r)) goto end;
903 if (This->Location)
905 r = write_hlink_string(pStm, This->Location);
906 if (FAILED(r)) goto end;
909 end:
910 if (moniker) IMoniker_Release(moniker);
911 TRACE("Save Result 0x%lx\n", r);
913 return r;
916 static HRESULT WINAPI IPersistStream_fnGetSizeMax(IPersistStream* iface,
917 ULARGE_INTEGER* pcbSize)
919 HRESULT r;
920 HlinkImpl *This = impl_from_IPersistStream(iface);
921 IMoniker *moniker;
923 TRACE("(%p) Moniker(%p)\n", This, This->Moniker);
925 pcbSize->QuadPart = sizeof(DWORD)*2;
927 if (This->TargetFrameName)
928 pcbSize->QuadPart += size_hlink_string(This->TargetFrameName);
930 if (This->FriendlyName)
931 pcbSize->QuadPart += size_hlink_string(This->FriendlyName);
933 r = __GetMoniker(This, &moniker, HLINKGETREF_DEFAULT);
934 if (FAILED(r))
935 return r;
936 r = E_FAIL;
938 if (moniker)
940 IPersistStream* monstream = NULL;
941 IMoniker_QueryInterface(moniker, &IID_IPersistStream,
942 (LPVOID*)&monstream);
943 if (monstream)
945 ULARGE_INTEGER mon_size;
946 r = IPersistStream_GetSizeMax(monstream, &mon_size);
947 pcbSize->QuadPart += mon_size.QuadPart;
948 IPersistStream_Release(monstream);
950 IMoniker_Release(moniker);
953 if (This->Location)
954 pcbSize->QuadPart += size_hlink_string(This->Location);
956 return r;
959 static const IPersistStreamVtbl psvt =
961 IPersistStream_fnQueryInterface,
962 IPersistStream_fnAddRef,
963 IPersistStream_fnRelease,
964 IPersistStream_fnGetClassID,
965 IPersistStream_fnIsDirty,
966 IPersistStream_fnLoad,
967 IPersistStream_fnSave,
968 IPersistStream_fnGetSizeMax,
971 static HlinkImpl *impl_from_IBindStatusCallback(IBindStatusCallback *iface)
973 return CONTAINING_RECORD(iface, HlinkImpl, IBindStatusCallback_iface);
976 static HRESULT WINAPI bind_callback_QueryInterface(IBindStatusCallback *iface, REFIID iid, void **out)
978 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IBindStatusCallback))
980 IBindStatusCallback_AddRef(*out = iface);
981 return S_OK;
984 WARN("No interface for %s.\n", debugstr_guid(iid));
985 return E_NOINTERFACE;
988 static ULONG WINAPI bind_callback_AddRef(IBindStatusCallback *iface)
990 HlinkImpl *hlink = impl_from_IBindStatusCallback(iface);
991 return IHlink_AddRef(&hlink->IHlink_iface);
994 static ULONG WINAPI bind_callback_Release(IBindStatusCallback *iface)
996 HlinkImpl *hlink = impl_from_IBindStatusCallback(iface);
997 return IHlink_Release(&hlink->IHlink_iface);
1000 static HRESULT WINAPI bind_callback_OnStartBinding(IBindStatusCallback *iface,
1001 DWORD reserved, IBinding *binding)
1003 HlinkImpl *hlink = impl_from_IBindStatusCallback(iface);
1005 TRACE("hlink %p, reserved %#lx, binding %p.\n", hlink, reserved, binding);
1007 if (hlink->bind_callback)
1008 return IBindStatusCallback_OnStartBinding(hlink->bind_callback, reserved, binding);
1009 return S_OK;
1012 static HRESULT WINAPI bind_callback_GetPriority(IBindStatusCallback *iface, LONG *priority)
1014 FIXME("iface %p, priority %p, stub!\n", iface, priority);
1015 return E_NOTIMPL;
1018 static HRESULT WINAPI bind_callback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
1020 HlinkImpl *hlink = impl_from_IBindStatusCallback(iface);
1022 TRACE("hlink %p, reserved %#lx.\n", hlink, reserved);
1024 if (hlink->bind_callback)
1025 return IBindStatusCallback_OnLowResource(hlink->bind_callback, reserved);
1026 return S_OK;
1029 static HRESULT WINAPI bind_callback_OnProgress(IBindStatusCallback *iface,
1030 ULONG progress, ULONG max, ULONG status, const WCHAR *text)
1032 HlinkImpl *hlink = impl_from_IBindStatusCallback(iface);
1034 TRACE("hlink %p, progress %lu, max %lu, status %lu, text %s.\n",
1035 hlink, progress, max, status, debugstr_w(text));
1037 if (hlink->bind_callback)
1038 return IBindStatusCallback_OnProgress(hlink->bind_callback, progress, max, status, text);
1039 return S_OK;
1042 static HRESULT WINAPI bind_callback_OnStopBinding(IBindStatusCallback *iface,
1043 HRESULT hr, const WCHAR *error)
1045 HlinkImpl *hlink = impl_from_IBindStatusCallback(iface);
1047 TRACE("hlink %p, hr %#lx, error %s.\n", hlink, hr, debugstr_w(error));
1049 if (hlink->bind_callback)
1050 IBindStatusCallback_OnStopBinding(hlink->bind_callback, hr, error);
1052 if (hlink->async_bind_ctx)
1054 if (hlink->bind_callback)
1055 IBindStatusCallback_Release(hlink->bind_callback);
1056 RevokeBindStatusCallback(hlink->async_bind_ctx, iface);
1057 IBindCtx_Release(hlink->async_bind_ctx);
1058 IHlinkBrowseContext_Release(hlink->async_browse_ctx);
1059 hlink->async_bind_ctx = NULL;
1061 return S_OK;
1064 static HRESULT WINAPI bind_callback_GetBindInfo(IBindStatusCallback *iface,
1065 DWORD *bind_flags, BINDINFO *bind_info)
1067 HlinkImpl *hlink = impl_from_IBindStatusCallback(iface);
1069 TRACE("hlink %p, bind_flags %p, bind_info %p.\n", hlink, bind_flags, bind_info);
1071 if (hlink->bind_callback)
1072 return IBindStatusCallback_GetBindInfo(hlink->bind_callback, bind_flags, bind_info);
1073 return S_OK;
1076 static HRESULT WINAPI bind_callback_OnDataAvailable(IBindStatusCallback *iface,
1077 DWORD flags, DWORD size, FORMATETC *formatetc, STGMEDIUM *stgmed)
1079 FIXME("iface %p, flags %#lx, size %ld, formatetc %p, stgmed %p, stub!\n",
1080 iface, flags, size, formatetc, stgmed);
1081 return E_NOTIMPL;
1084 static HRESULT WINAPI bind_callback_OnObjectAvailable(IBindStatusCallback *iface,
1085 REFIID iid, IUnknown *unk)
1087 HlinkImpl *hlink = impl_from_IBindStatusCallback(iface);
1088 IHlinkTarget *target;
1089 HRESULT hr;
1091 TRACE("hlink %p, iid %s, unk %p.\n", hlink, debugstr_guid(iid), unk);
1093 if (hlink->bind_callback)
1094 IBindStatusCallback_OnObjectAvailable(hlink->bind_callback, iid, unk);
1096 if (hlink->async_bind_ctx)
1098 hr = IUnknown_QueryInterface(unk, &IID_IHlinkTarget, (void **)&target);
1099 if (FAILED(hr))
1100 return hr;
1102 IHlinkTarget_SetBrowseContext(target, hlink->async_browse_ctx);
1103 hr = IHlinkTarget_Navigate(target, hlink->async_flags, hlink->Location);
1104 IHlinkTarget_Release(target);
1106 if (hlink->Site)
1107 IHlinkSite_OnNavigationComplete(hlink->Site, hlink->SiteData, 0, hr, NULL);
1109 return hr;
1112 return S_OK;
1115 static const IBindStatusCallbackVtbl bind_callback_vtbl =
1117 bind_callback_QueryInterface,
1118 bind_callback_AddRef,
1119 bind_callback_Release,
1120 bind_callback_OnStartBinding,
1121 bind_callback_GetPriority,
1122 bind_callback_OnLowResource,
1123 bind_callback_OnProgress,
1124 bind_callback_OnStopBinding,
1125 bind_callback_GetBindInfo,
1126 bind_callback_OnDataAvailable,
1127 bind_callback_OnObjectAvailable,
1130 HRESULT HLink_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
1132 HlinkImpl * hl;
1133 HRESULT hr;
1135 TRACE("unkOut=%p riid=%s\n", pUnkOuter, debugstr_guid(riid));
1136 *ppv = NULL;
1138 if (pUnkOuter)
1139 return CLASS_E_NOAGGREGATION;
1141 if (!(hl = calloc(1, sizeof(*hl))))
1142 return E_OUTOFMEMORY;
1144 hl->ref = 1;
1145 hl->IHlink_iface.lpVtbl = &hlvt;
1146 hl->IPersistStream_iface.lpVtbl = &psvt;
1147 hl->IDataObject_iface.lpVtbl = &dovt;
1148 hl->IBindStatusCallback_iface.lpVtbl = &bind_callback_vtbl;
1150 hr = IHlink_QueryInterface(&hl->IHlink_iface, riid, ppv);
1151 IHlink_Release(&hl->IHlink_iface);
1153 return hr;