user32: Don't reset focus if current dialog is a child.
[wine.git] / dlls / hlink / link.c
blobe3de7646ef2b424525886e8faa7448d68005b69f
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=%u)\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=%u)\n", This, refCount + 1);
168 if (refCount)
169 return refCount;
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;
183 static HRESULT WINAPI IHlink_fnSetHlinkSite( IHlink* iface,
184 IHlinkSite* pihlSite, DWORD dwSiteData)
186 HlinkImpl *This = impl_from_IHlink(iface);
188 TRACE("(%p)->(%p %i)\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)->(%i %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 && strchrW(display_name, ':');
246 CoTaskMemFree(display_name);
250 if(rfHLSETF & HLINKSETF_LOCATION){
251 heap_free(This->Location);
252 This->Location = hlink_strdupW( 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)->(%i %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 = strchrW(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%08x\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 heap_free(This->Location);
314 This->Location = NULL;
315 if (pwzLocation && *pwzLocation)
316 This->Location = hlink_strdupW( 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) -> (%i %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) -> (%i %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 heap_free(This->FriendlyName);
403 This->FriendlyName = hlink_strdupW( 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) -> (%i %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 heap_free(This->TargetFrameName);
451 This->TargetFrameName = hlink_strdupW( 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 %#x, 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 static const WCHAR szOpen[] = {'o','p','e','n',0};
541 LPWSTR target = NULL;
543 r = IHlink_GetStringReference(iface, HLINKGETREF_DEFAULT, &target, NULL);
544 if (SUCCEEDED(r) && target)
546 ShellExecuteW(NULL, szOpen, target, NULL, NULL, SW_SHOW);
547 CoTaskMemFree(target);
548 r = DRAGDROP_S_DROP;
551 IMoniker_Release(mon);
554 if (This->Site)
555 IHlinkSite_OnNavigationComplete(This->Site, This->SiteData, 0, r, NULL);
557 TRACE("Finished Navigation\n");
558 return r;
561 static HRESULT WINAPI IHlink_fnSetAdditionalParams(IHlink* iface,
562 LPCWSTR pwzAdditionalParams)
564 TRACE("Not implemented in native IHlink\n");
565 return E_NOTIMPL;
568 static HRESULT WINAPI IHlink_fnGetAdditionalParams(IHlink* iface,
569 LPWSTR* ppwzAdditionalParams)
571 TRACE("Not implemented in native IHlink\n");
572 return E_NOTIMPL;
575 static const IHlinkVtbl hlvt =
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
596 static HRESULT WINAPI IDataObject_fnQueryInterface(IDataObject* iface,
597 REFIID riid, LPVOID *ppvObj)
599 HlinkImpl *This = impl_from_IDataObject(iface);
600 TRACE("%p\n", This);
601 return IHlink_QueryInterface(&This->IHlink_iface, riid, ppvObj);
604 static ULONG WINAPI IDataObject_fnAddRef (IDataObject* iface)
606 HlinkImpl *This = impl_from_IDataObject(iface);
607 TRACE("%p\n", This);
608 return IHlink_AddRef(&This->IHlink_iface);
611 static ULONG WINAPI IDataObject_fnRelease (IDataObject* iface)
613 HlinkImpl *This = impl_from_IDataObject(iface);
614 TRACE("%p\n", This);
615 return IHlink_Release(&This->IHlink_iface);
618 static HRESULT WINAPI IDataObject_fnGetData(IDataObject* iface,
619 FORMATETC* pformatetcIn, STGMEDIUM* pmedium)
621 FIXME("\n");
622 return E_NOTIMPL;
625 static HRESULT WINAPI IDataObject_fnGetDataHere(IDataObject* iface,
626 FORMATETC* pformatetc, STGMEDIUM* pmedium)
628 FIXME("\n");
629 return E_NOTIMPL;
632 static HRESULT WINAPI IDataObject_fnQueryGetData(IDataObject* iface,
633 FORMATETC* pformatetc)
635 FIXME("\n");
636 return E_NOTIMPL;
639 static HRESULT WINAPI IDataObject_fnGetConicalFormatEtc(IDataObject* iface,
640 FORMATETC* pformatetcIn, FORMATETC* pformatetcOut)
642 FIXME("\n");
643 return E_NOTIMPL;
646 static HRESULT WINAPI IDataObject_fnSetData(IDataObject* iface,
647 FORMATETC* pformatetc, STGMEDIUM* pmedium, BOOL fRelease)
649 FIXME("\n");
650 return E_NOTIMPL;
653 static HRESULT WINAPI IDataObject_fnEnumFormatEtc(IDataObject* iface,
654 DWORD dwDirection, IEnumFORMATETC** ppenumFormatEtc)
656 FIXME("\n");
657 return E_NOTIMPL;
660 static HRESULT WINAPI IDataObject_fnDAdvise(IDataObject* iface,
661 FORMATETC* pformatetc, DWORD advf, IAdviseSink* pAdvSink,
662 DWORD* pdwConnection)
664 FIXME("\n");
665 return E_NOTIMPL;
668 static HRESULT WINAPI IDataObject_fnDUnadvise(IDataObject* iface,
669 DWORD dwConnection)
671 FIXME("\n");
672 return E_NOTIMPL;
675 static HRESULT WINAPI IDataObject_fnEnumDAdvise(IDataObject* iface,
676 IEnumSTATDATA** ppenumAdvise)
678 FIXME("\n");
679 return E_NOTIMPL;
682 static const IDataObjectVtbl dovt =
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
698 static HRESULT WINAPI IPersistStream_fnQueryInterface(IPersistStream* iface,
699 REFIID riid, LPVOID *ppvObj)
701 HlinkImpl *This = impl_from_IPersistStream(iface);
702 TRACE("(%p)\n", This);
703 return IHlink_QueryInterface(&This->IHlink_iface, riid, ppvObj);
706 static ULONG WINAPI IPersistStream_fnAddRef (IPersistStream* iface)
708 HlinkImpl *This = impl_from_IPersistStream(iface);
709 TRACE("(%p)\n", This);
710 return IHlink_AddRef(&This->IHlink_iface);
713 static ULONG WINAPI IPersistStream_fnRelease (IPersistStream* iface)
715 HlinkImpl *This = impl_from_IPersistStream(iface);
716 TRACE("(%p)\n", This);
717 return IHlink_Release(&This->IHlink_iface);
720 static HRESULT WINAPI IPersistStream_fnGetClassID(IPersistStream* iface,
721 CLSID* pClassID)
723 HlinkImpl *This = impl_from_IPersistStream(iface);
724 TRACE("(%p)\n", This);
725 *pClassID = CLSID_StdHlink;
726 return S_OK;
729 static HRESULT WINAPI IPersistStream_fnIsDirty(IPersistStream* iface)
731 FIXME("\n");
732 return E_NOTIMPL;
735 static HRESULT write_hlink_string(IStream *pStm, LPCWSTR str)
737 DWORD len;
738 HRESULT hr;
740 TRACE("(%p, %s)\n", pStm, debugstr_w(str));
742 len = strlenW(str) + 1;
744 hr = IStream_Write(pStm, &len, sizeof(len), NULL);
745 if (FAILED(hr)) return hr;
747 hr = IStream_Write(pStm, str, len * sizeof(WCHAR), NULL);
748 if (FAILED(hr)) return hr;
750 return S_OK;
753 static inline ULONG size_hlink_string(LPCWSTR str)
755 return sizeof(DWORD) + (strlenW(str) + 1) * sizeof(WCHAR);
758 static HRESULT read_hlink_string(IStream *pStm, LPWSTR *out_str)
760 LPWSTR str;
761 DWORD len;
762 ULONG read;
763 HRESULT hr;
765 hr = IStream_Read(pStm, &len, sizeof(len), &read);
766 if (FAILED(hr)) return hr;
767 if (read != sizeof(len)) return STG_E_READFAULT;
769 TRACE("read len %d\n", len);
771 str = heap_alloc(len * sizeof(WCHAR));
772 if (!str) return E_OUTOFMEMORY;
774 hr = IStream_Read(pStm, str, len * sizeof(WCHAR), &read);
775 if (FAILED(hr))
777 heap_free(str);
778 return hr;
780 if (read != len * sizeof(WCHAR))
782 heap_free(str);
783 return STG_E_READFAULT;
785 TRACE("read string %s\n", debugstr_w(str));
787 *out_str = str;
788 return S_OK;
791 static HRESULT WINAPI IPersistStream_fnLoad(IPersistStream* iface,
792 IStream* pStm)
794 HRESULT r;
795 DWORD hdr[2];
796 DWORD read;
797 HlinkImpl *This = impl_from_IPersistStream(iface);
799 r = IStream_Read(pStm, hdr, sizeof(hdr), &read);
800 if (read != sizeof(hdr) || (hdr[0] != HLINK_SAVE_MAGIC))
802 r = E_FAIL;
803 goto end;
805 if (hdr[1] & ~HLINK_SAVE_ALL)
806 FIXME("unknown flag(s) 0x%x\n", hdr[1] & ~HLINK_SAVE_ALL);
808 if (hdr[1] & HLINK_SAVE_TARGET_FRAME_PRESENT)
810 TRACE("loading target frame name\n");
811 r = read_hlink_string(pStm, &This->TargetFrameName);
812 if (FAILED(r)) goto end;
815 if (hdr[1] & HLINK_SAVE_FRIENDLY_PRESENT)
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;
824 if (hdr[1] & HLINK_SAVE_MONIKER_PRESENT)
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;
833 if (hdr[1] & HLINK_SAVE_LOCATION_PRESENT)
835 TRACE("loading location\n");
836 r = read_hlink_string(pStm, &This->Location);
837 if (FAILED(r)) goto end;
840 end:
841 TRACE("Load Result 0x%x (%p)\n", r, This->Moniker);
843 return r;
846 static HRESULT WINAPI IPersistStream_fnSave(IPersistStream* iface,
847 IStream* pStm, BOOL fClearDirty)
849 HRESULT r;
850 HlinkImpl *This = impl_from_IPersistStream(iface);
851 DWORD hdr[2];
852 IMoniker *moniker;
854 TRACE("(%p) Moniker(%p)\n", This, This->Moniker);
856 r = __GetMoniker(This, &moniker, HLINKGETREF_DEFAULT);
857 if (FAILED(r))
858 return r;
859 r = E_FAIL;
861 hdr[0] = HLINK_SAVE_MAGIC;
862 hdr[1] = 0;
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;
875 IStream_Write(pStm, hdr, sizeof(hdr), NULL);
877 if (This->TargetFrameName)
879 r = write_hlink_string(pStm, This->TargetFrameName);
880 if (FAILED(r)) goto end;
883 if (This->FriendlyName)
885 r = write_hlink_string(pStm, This->FriendlyName);
886 if (FAILED(r)) goto end;
889 if (moniker)
891 IPersistStream* monstream;
893 monstream = NULL;
894 IMoniker_QueryInterface(moniker, &IID_IPersistStream,
895 (LPVOID*)&monstream);
896 if (monstream)
898 r = OleSaveToStream(monstream, pStm);
899 IPersistStream_Release(monstream);
901 if (FAILED(r)) goto end;
904 if (This->Location)
906 r = write_hlink_string(pStm, This->Location);
907 if (FAILED(r)) goto end;
910 end:
911 if (moniker) IMoniker_Release(moniker);
912 TRACE("Save Result 0x%x\n", r);
914 return r;
917 static HRESULT WINAPI IPersistStream_fnGetSizeMax(IPersistStream* iface,
918 ULARGE_INTEGER* pcbSize)
920 HRESULT r;
921 HlinkImpl *This = impl_from_IPersistStream(iface);
922 IMoniker *moniker;
924 TRACE("(%p) Moniker(%p)\n", This, This->Moniker);
926 pcbSize->QuadPart = sizeof(DWORD)*2;
928 if (This->TargetFrameName)
929 pcbSize->QuadPart += size_hlink_string(This->TargetFrameName);
931 if (This->FriendlyName)
932 pcbSize->QuadPart += size_hlink_string(This->FriendlyName);
934 r = __GetMoniker(This, &moniker, HLINKGETREF_DEFAULT);
935 if (FAILED(r))
936 return r;
937 r = E_FAIL;
939 if (moniker)
941 IPersistStream* monstream = NULL;
942 IMoniker_QueryInterface(moniker, &IID_IPersistStream,
943 (LPVOID*)&monstream);
944 if (monstream)
946 ULARGE_INTEGER mon_size;
947 r = IPersistStream_GetSizeMax(monstream, &mon_size);
948 pcbSize->QuadPart += mon_size.QuadPart;
949 IPersistStream_Release(monstream);
951 IMoniker_Release(moniker);
954 if (This->Location)
955 pcbSize->QuadPart += size_hlink_string(This->Location);
957 return r;
960 static const IPersistStreamVtbl psvt =
962 IPersistStream_fnQueryInterface,
963 IPersistStream_fnAddRef,
964 IPersistStream_fnRelease,
965 IPersistStream_fnGetClassID,
966 IPersistStream_fnIsDirty,
967 IPersistStream_fnLoad,
968 IPersistStream_fnSave,
969 IPersistStream_fnGetSizeMax,
972 static HlinkImpl *impl_from_IBindStatusCallback(IBindStatusCallback *iface)
974 return CONTAINING_RECORD(iface, HlinkImpl, IBindStatusCallback_iface);
977 static HRESULT WINAPI bind_callback_QueryInterface(IBindStatusCallback *iface, REFIID iid, void **out)
979 if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IBindStatusCallback))
981 IBindStatusCallback_AddRef(*out = iface);
982 return S_OK;
985 WARN("No interface for %s.\n", debugstr_guid(iid));
986 return E_NOINTERFACE;
989 static ULONG WINAPI bind_callback_AddRef(IBindStatusCallback *iface)
991 HlinkImpl *hlink = impl_from_IBindStatusCallback(iface);
992 return IHlink_AddRef(&hlink->IHlink_iface);
995 static ULONG WINAPI bind_callback_Release(IBindStatusCallback *iface)
997 HlinkImpl *hlink = impl_from_IBindStatusCallback(iface);
998 return IHlink_Release(&hlink->IHlink_iface);
1001 static HRESULT WINAPI bind_callback_OnStartBinding(IBindStatusCallback *iface,
1002 DWORD reserved, IBinding *binding)
1004 HlinkImpl *hlink = impl_from_IBindStatusCallback(iface);
1006 TRACE("hlink %p, reserved %#x, binding %p.\n", hlink, reserved, binding);
1008 if (hlink->bind_callback)
1009 return IBindStatusCallback_OnStartBinding(hlink->bind_callback, reserved, binding);
1010 return S_OK;
1013 static HRESULT WINAPI bind_callback_GetPriority(IBindStatusCallback *iface, LONG *priority)
1015 FIXME("iface %p, priority %p, stub!\n", iface, priority);
1016 return E_NOTIMPL;
1019 static HRESULT WINAPI bind_callback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
1021 HlinkImpl *hlink = impl_from_IBindStatusCallback(iface);
1023 TRACE("hlink %p, reserved %#x.\n", hlink, reserved);
1025 if (hlink->bind_callback)
1026 return IBindStatusCallback_OnLowResource(hlink->bind_callback, reserved);
1027 return S_OK;
1030 static HRESULT WINAPI bind_callback_OnProgress(IBindStatusCallback *iface,
1031 ULONG progress, ULONG max, ULONG status, const WCHAR *text)
1033 HlinkImpl *hlink = impl_from_IBindStatusCallback(iface);
1035 TRACE("hlink %p, progress %u, max %u, status %u, text %s.\n",
1036 hlink, progress, max, status, debugstr_w(text));
1038 if (hlink->bind_callback)
1039 return IBindStatusCallback_OnProgress(hlink->bind_callback, progress, max, status, text);
1040 return S_OK;
1043 static HRESULT WINAPI bind_callback_OnStopBinding(IBindStatusCallback *iface,
1044 HRESULT hr, const WCHAR *error)
1046 HlinkImpl *hlink = impl_from_IBindStatusCallback(iface);
1048 TRACE("hlink %p, hr %#x, error %s.\n", hlink, hr, debugstr_w(error));
1050 if (hlink->bind_callback)
1051 IBindStatusCallback_OnStopBinding(hlink->bind_callback, hr, error);
1053 if (hlink->async_bind_ctx)
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;
1062 return S_OK;
1065 static HRESULT WINAPI bind_callback_GetBindInfo(IBindStatusCallback *iface,
1066 DWORD *bind_flags, BINDINFO *bind_info)
1068 HlinkImpl *hlink = impl_from_IBindStatusCallback(iface);
1070 TRACE("hlink %p, bind_flags %p, bind_info %p.\n", hlink, bind_flags, bind_info);
1072 if (hlink->bind_callback)
1073 return IBindStatusCallback_GetBindInfo(hlink->bind_callback, bind_flags, bind_info);
1074 return S_OK;
1077 static HRESULT WINAPI bind_callback_OnDataAvailable(IBindStatusCallback *iface,
1078 DWORD flags, DWORD size, FORMATETC *formatetc, STGMEDIUM *stgmed)
1080 FIXME("iface %p, flags %#x, size %d, formatetc %p, stgmed %p, stub!\n",
1081 iface, flags, size, formatetc, stgmed);
1082 return E_NOTIMPL;
1085 static HRESULT WINAPI bind_callback_OnObjectAvailable(IBindStatusCallback *iface,
1086 REFIID iid, IUnknown *unk)
1088 HlinkImpl *hlink = impl_from_IBindStatusCallback(iface);
1089 IHlinkTarget *target;
1090 HRESULT hr;
1092 TRACE("hlink %p, iid %s, unk %p.\n", hlink, debugstr_guid(iid), unk);
1094 if (hlink->bind_callback)
1095 IBindStatusCallback_OnObjectAvailable(hlink->bind_callback, iid, unk);
1097 if (hlink->async_bind_ctx)
1099 hr = IUnknown_QueryInterface(unk, &IID_IHlinkTarget, (void **)&target);
1100 if (FAILED(hr))
1101 return hr;
1103 IHlinkTarget_SetBrowseContext(target, hlink->async_browse_ctx);
1104 hr = IHlinkTarget_Navigate(target, hlink->async_flags, hlink->Location);
1105 IHlinkTarget_Release(target);
1107 if (hlink->Site)
1108 IHlinkSite_OnNavigationComplete(hlink->Site, hlink->SiteData, 0, hr, NULL);
1110 return hr;
1113 return S_OK;
1116 static const IBindStatusCallbackVtbl bind_callback_vtbl =
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,
1131 HRESULT HLink_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
1133 HlinkImpl * hl;
1135 TRACE("unkOut=%p riid=%s\n", pUnkOuter, debugstr_guid(riid));
1136 *ppv = NULL;
1138 if (pUnkOuter)
1139 return CLASS_E_NOAGGREGATION;
1141 hl = heap_alloc_zero(sizeof(HlinkImpl));
1142 if (!hl)
1143 return E_OUTOFMEMORY;
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;
1151 *ppv = hl;
1152 return S_OK;