From 58709d2263b0ea549cd0ec2d3bde86a2cda5d21f Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Tue, 6 Jun 2006 19:39:58 +0900 Subject: [PATCH] hlink: Add a basic implementation (based on work by Aric Stewart). --- dlls/hlink/Makefile.in | 4 +- dlls/hlink/browse_ctx.c | 281 +++++++++++++++ dlls/hlink/hlink_main.c | 210 +++++++++++- dlls/hlink/link.c | 741 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1217 insertions(+), 19 deletions(-) create mode 100644 dlls/hlink/browse_ctx.c create mode 100644 dlls/hlink/link.c diff --git a/dlls/hlink/Makefile.in b/dlls/hlink/Makefile.in index c73ed56da87..898ceb02d6a 100644 --- a/dlls/hlink/Makefile.in +++ b/dlls/hlink/Makefile.in @@ -8,7 +8,9 @@ DELAYIMPORTS = urlmon EXTRALIBS = -luuid $(LIBUNICODE) C_SRCS = \ - hlink_main.c + browse_ctx.c \ + hlink_main.c \ + link.c @MAKE_DLL_RULES@ diff --git a/dlls/hlink/browse_ctx.c b/dlls/hlink/browse_ctx.c new file mode 100644 index 00000000000..5658392f971 --- /dev/null +++ b/dlls/hlink/browse_ctx.c @@ -0,0 +1,281 @@ +/* + * Implementation of hyperlinking (hlink.dll) + * + * Copyright 2005 Aric Stewart for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#define COBJMACROS + +#include "winerror.h" +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "ole2.h" +#include "unknwn.h" +#include "objidl.h" + +#include "wine/debug.h" +#include "hlink.h" + +WINE_DEFAULT_DEBUG_CHANNEL(hlink); + +static const IHlinkBrowseContextVtbl hlvt; + +typedef struct +{ + const IHlinkBrowseContextVtbl *lpVtbl; + LONG ref; + HLBWINFO* BrowseWindowInfo; + IHlink* CurrentPage; +} HlinkBCImpl; + + +HRESULT WINAPI HLinkBrowseContext_Constructor(IUnknown *pUnkOuter, REFIID riid, + LPVOID *ppv) +{ + HlinkBCImpl * hl; + + TRACE("unkOut=%p riid=%s\n", pUnkOuter, debugstr_guid(riid)); + *ppv = NULL; + + if (pUnkOuter) + return CLASS_E_NOAGGREGATION; + + hl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HlinkBCImpl)); + if (!hl) + return E_OUTOFMEMORY; + + hl->ref = 1; + hl->lpVtbl = &hlvt; + + *ppv = hl; + return S_OK; +} + +static HRESULT WINAPI IHlinkBC_fnQueryInterface( IHlinkBrowseContext *iface, + REFIID riid, LPVOID* ppvObj) +{ + HlinkBCImpl *This = (HlinkBCImpl*)iface; + TRACE ("(%p)->(%s,%p)\n", This, debugstr_guid (riid), ppvObj); + + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IHlinkBrowseContext)) + *ppvObj = This; + + if (*ppvObj) + { + IUnknown_AddRef((IUnknown*)(*ppvObj)); + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI IHlinkBC_fnAddRef (IHlinkBrowseContext* iface) +{ + HlinkBCImpl *This = (HlinkBCImpl*)iface; + ULONG refCount = InterlockedIncrement(&This->ref); + + TRACE("(%p)->(count=%lu)\n", This, refCount - 1); + + return refCount; +} + +static ULONG WINAPI IHlinkBC_fnRelease (IHlinkBrowseContext* iface) +{ + HlinkBCImpl *This = (HlinkBCImpl*)iface; + ULONG refCount = InterlockedDecrement(&This->ref); + + TRACE("(%p)->(count=%lu)\n", This, refCount + 1); + if (refCount) + return refCount; + + TRACE("-- destroying IHlinkBrowseContext (%p)\n", This); + HeapFree(GetProcessHeap(), 0, This->BrowseWindowInfo); + if (This->CurrentPage) + IHlink_Release(This->CurrentPage); + HeapFree(GetProcessHeap(), 0, This); + return 0; +} + +static HRESULT WINAPI IHlinkBC_Register(IHlinkBrowseContext* iface, + DWORD dwReserved, IUnknown *piunk, IMoniker *pimk, DWORD *pdwRegister) +{ + static const WCHAR szIdent[] = {'W','I','N','E','H','L','I','N','K',0}; + HlinkBCImpl *This = (HlinkBCImpl*)iface; + IMoniker *mon; + IMoniker *composite; + IRunningObjectTable *ROT; + + FIXME("(%p)->(%li %p %p %p)\n", This, dwReserved, piunk, pimk, pdwRegister); + + CreateItemMoniker(NULL, szIdent, &mon); + CreateGenericComposite(mon, pimk, &composite); + + GetRunningObjectTable(0, &ROT); + IRunningObjectTable_Register(ROT, 0, piunk, composite, pdwRegister); + + IRunningObjectTable_Release(ROT); + IMoniker_Release(composite); + IMoniker_Release(mon); + + return S_OK; +} + +static HRESULT WINAPI IHlinkBC_GetObject(IHlinkBrowseContext* face, + IMoniker *pimk, BOOL fBindifRootRegistered, IUnknown **ppiunk) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI IHlinkBC_Revoke(IHlinkBrowseContext* iface, + DWORD dwRegister) +{ + HRESULT r = S_OK; + IRunningObjectTable *ROT; + HlinkBCImpl *This = (HlinkBCImpl*)iface; + + FIXME("(%p)->(%li)\n", This, dwRegister); + + GetRunningObjectTable(0, &ROT); + r = IRunningObjectTable_Revoke(ROT, dwRegister); + IRunningObjectTable_Release(ROT); + + return r; +} + +static HRESULT WINAPI IHlinkBC_SetBrowseWindowInfo(IHlinkBrowseContext* iface, + HLBWINFO *phlbwi) +{ + HlinkBCImpl *This = (HlinkBCImpl*)iface; + TRACE("(%p)->(%p)\n", This, phlbwi); + + HeapFree(GetProcessHeap(), 0, This->BrowseWindowInfo); + This->BrowseWindowInfo = HeapAlloc(GetProcessHeap(), 0, phlbwi->cbSize); + memcpy(This->BrowseWindowInfo, phlbwi, phlbwi->cbSize); + + return S_OK; +} + +static HRESULT WINAPI IHlinkBC_GetBrowseWindowInfo(IHlinkBrowseContext* iface, + HLBWINFO *phlbwi) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI IHlinkBC_SetInitialHlink(IHlinkBrowseContext* iface, + IMoniker *pimkTarget, LPCWSTR pwzLocation, LPCWSTR pwzFriendlyName) +{ + HlinkBCImpl *This = (HlinkBCImpl*)iface; + + FIXME("(%p)->(%p %s %s)\n", This, pimkTarget, + debugstr_w(pwzLocation), debugstr_w(pwzFriendlyName)); + + if (This->CurrentPage) + IHlink_Release(This->CurrentPage); + + HlinkCreateFromMoniker(pimkTarget, pwzLocation, pwzFriendlyName, NULL, + 0, NULL, &IID_IHlink, (LPVOID*) &This->CurrentPage); + + return S_OK; +} + +static HRESULT WINAPI IHlinkBC_OnNavigateHlink(IHlinkBrowseContext *iface, + DWORD grfHLNF, IMoniker* pmkTarget, LPCWSTR pwzLocation, LPCWSTR + pwzFriendlyName, ULONG *puHLID) +{ + HlinkBCImpl *This = (HlinkBCImpl*)iface; + + FIXME("(%p)->(%li %p %s %s %p)\n", This, grfHLNF, pmkTarget, + debugstr_w(pwzLocation), debugstr_w(pwzFriendlyName), puHLID); + + return S_OK; +} + +static HRESULT WINAPI IHlinkBC_UpdateHlink(IHlinkBrowseContext* iface, + ULONG uHLID, IMoniker* pimkTarget, LPCWSTR pwzLocation, + LPCWSTR pwzFriendlyName) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI IHlinkBC_EnumNavigationStack( IHlinkBrowseContext *iface, + DWORD dwReserved, DWORD grfHLFNAMEF, IEnumHLITEM** ppienumhlitem) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI IHlinkBC_QueryHlink( IHlinkBrowseContext* iface, + DWORD grfHLONG, ULONG uHLID) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI IHlinkBC_GetHlink( IHlinkBrowseContext* iface, + ULONG uHLID, IHlink** ppihl) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI IHlinkBC_SetCurrentHlink( IHlinkBrowseContext* iface, + ULONG uHLID) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI IHlinkBC_Clone( IHlinkBrowseContext* iface, + IUnknown* piunkOuter, REFIID riid, IUnknown** ppiunkOjb) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI IHlinkBC_Close(IHlinkBrowseContext* iface, + DWORD reserverd) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static const IHlinkBrowseContextVtbl hlvt = +{ + IHlinkBC_fnQueryInterface, + IHlinkBC_fnAddRef, + IHlinkBC_fnRelease, + IHlinkBC_Register, + IHlinkBC_GetObject, + IHlinkBC_Revoke, + IHlinkBC_SetBrowseWindowInfo, + IHlinkBC_GetBrowseWindowInfo, + IHlinkBC_SetInitialHlink, + IHlinkBC_OnNavigateHlink, + IHlinkBC_UpdateHlink, + IHlinkBC_EnumNavigationStack, + IHlinkBC_QueryHlink, + IHlinkBC_GetHlink, + IHlinkBC_SetCurrentHlink, + IHlinkBC_Clone, + IHlinkBC_Close +}; diff --git a/dlls/hlink/hlink_main.c b/dlls/hlink/hlink_main.c index 2cf9e2ebdfd..584ddacd8bf 100644 --- a/dlls/hlink/hlink_main.c +++ b/dlls/hlink/hlink_main.c @@ -32,8 +32,21 @@ #include "wine/debug.h" #include "hlink.h" +#include "initguid.h" +#include "hlguids.h" + WINE_DEFAULT_DEBUG_CHANNEL(hlink); +extern HRESULT WINAPI HLink_Constructor(IUnknown *, REFIID, LPVOID*); +extern HRESULT WINAPI HLinkBrowseContext_Constructor(IUnknown *, REFIID, LPVOID*); + +typedef HRESULT (CALLBACK *LPFNCREATEINSTANCE)(IUnknown*, REFIID, LPVOID*); + +typedef struct +{ + const IClassFactoryVtbl *lpVtbl; + LPFNCREATEINSTANCE lpfnCI; +} CFImpl; BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { @@ -62,49 +75,136 @@ HRESULT WINAPI HlinkCreateFromMoniker( IMoniker *pimkTrgt, LPCWSTR pwzLocation, LPCWSTR pwzFriendlyName, IHlinkSite* pihlsite, DWORD dwSiteData, IUnknown* piunkOuter, REFIID riid, void** ppvObj) { - FIXME("%p %s %s %p %li %p %s %p\n", pimkTrgt, debugstr_w(pwzLocation), - debugstr_w(pwzFriendlyName), pihlsite, dwSiteData, piunkOuter, - debugstr_guid(riid), ppvObj); + IHlink *hl = NULL; + HRESULT r = S_OK; - return E_NOTIMPL; + TRACE("%p %s %s %p %li %p %s %p\n", pimkTrgt, debugstr_w(pwzLocation), + debugstr_w(pwzFriendlyName), pihlsite, dwSiteData, piunkOuter, + debugstr_guid(riid), ppvObj); + + r = CoCreateInstance(&CLSID_StdHlink, piunkOuter, CLSCTX_INPROC_SERVER, riid, ppvObj); + if (FAILED(r)) + return r; + + if (pwzLocation) + IHlink_SetStringReference(hl, HLINKSETF_LOCATION, NULL, pwzLocation); + if (pwzFriendlyName) + IHlink_SetFriendlyName(hl, pwzFriendlyName); + if (pihlsite) + IHlink_SetHlinkSite(hl, pihlsite, dwSiteData); + if (pimkTrgt) + IHlink_SetMonikerReference(hl, 0, pimkTrgt, pwzLocation); + + *ppvObj = hl; + + TRACE("Returning %li\n",r); + + return r; } HRESULT WINAPI HlinkCreateFromString( LPCWSTR pwzTarget, LPCWSTR pwzLocation, LPCWSTR pwzFriendlyName, IHlinkSite* pihlsite, DWORD dwSiteData, IUnknown* piunkOuter, REFIID riid, void** ppvObj) { - FIXME("%s %s %s %p %li %p %s %p\n", debugstr_w(pwzTarget), - debugstr_w(pwzLocation), debugstr_w(pwzFriendlyName), pihlsite, - dwSiteData, piunkOuter, debugstr_guid(riid), ppvObj); + IHlink *hl = NULL; + HRESULT r = S_OK; - return E_NOTIMPL; + TRACE("%s %s %s %p %li %p %s %p\n", debugstr_w(pwzTarget), + debugstr_w(pwzLocation), debugstr_w(pwzFriendlyName), pihlsite, + dwSiteData, piunkOuter, debugstr_guid(riid), ppvObj); + + r = CoCreateInstance(&CLSID_StdHlink, piunkOuter, CLSCTX_INPROC_SERVER, riid, (LPVOID*)&hl); + if (FAILED(r)) + return r; + + if (pwzLocation) + IHlink_SetStringReference(hl, HLINKSETF_LOCATION, NULL, pwzLocation); + + if (pwzTarget) + { + IMoniker *pTgtMk = NULL; + IBindCtx *pbc = NULL; + ULONG eaten; + + CreateBindCtx(0, &pbc); + r = MkParseDisplayName(pbc, pwzTarget, &eaten, &pTgtMk); + IBindCtx_Release(pbc); + + if (FAILED(r)) + { + FIXME("ParseDisplayName failed, falling back to file\n"); + r = CreateFileMoniker(pwzTarget,&pTgtMk); + } + + if (pTgtMk) + { + IHlink_SetMonikerReference(hl, 0, pTgtMk, pwzLocation); + IMoniker_Release(pTgtMk); + } + else + FIXME("Unable to come up with a moniker, expect problems\n"); + + IHlink_SetStringReference(hl, HLINKSETF_TARGET, pwzTarget, NULL); + } + + if (pwzFriendlyName) + IHlink_SetFriendlyName(hl, pwzFriendlyName); + if (pihlsite) + IHlink_SetHlinkSite(hl, pihlsite, dwSiteData); + + TRACE("Returning %li\n",r); + *ppvObj = hl; + + return r; } HRESULT WINAPI HlinkCreateBrowseContext( IUnknown* piunkOuter, REFIID riid, void** ppvObj) { - FIXME("%p %s %p\n", piunkOuter, debugstr_guid(riid), ppvObj); + HRESULT r = S_OK; - return E_NOTIMPL; + TRACE("%p %s %p\n", piunkOuter, debugstr_guid(riid), ppvObj); + + r = CoCreateInstance(&CLSID_StdHlinkBrowseContext, piunkOuter, CLSCTX_INPROC_SERVER, riid, ppvObj); + + TRACE("returning %li\n",r); + + return r; } HRESULT WINAPI HlinkNavigate(IHlink *phl, IHlinkFrame *phlFrame, DWORD grfHLNF, LPBC pbc, IBindStatusCallback *pbsc, IHlinkBrowseContext *phlbc) { - FIXME("%p %p %li %p %p %p\n", phl, phlFrame, grfHLNF, pbc, pbsc, phlbc); + HRESULT r = S_OK; - return E_NOTIMPL; + TRACE("%p %p %li %p %p %p\n", phl, phlFrame, grfHLNF, pbc, pbsc, phlbc); + + if (phlFrame) + r = IHlinkFrame_Navigate(phlFrame, grfHLNF, pbc, pbsc, phl); + else if (phl) + r = IHlink_Navigate(phl, grfHLNF, pbc, pbsc, phlbc); + + return r; } HRESULT WINAPI HlinkOnNavigate( IHlinkFrame *phlFrame, IHlinkBrowseContext* phlbc, DWORD grfHLNF, IMoniker *pmkTarget, LPCWSTR pwzLocation, LPCWSTR pwzFriendlyName, ULONG* puHLID) { - FIXME("%p %p %li %p %s %s %p\n",phlFrame, phlbc, grfHLNF, pmkTarget, - debugstr_w(pwzLocation), debugstr_w(pwzFriendlyName), puHLID); + HRESULT r = S_OK; - return E_NOTIMPL; + TRACE("%p %p %li %p %s %s %p\n",phlFrame, phlbc, grfHLNF, pmkTarget, + debugstr_w(pwzLocation), debugstr_w(pwzFriendlyName), puHLID); + + r = IHlinkBrowseContext_OnNavigateHlink(phlbc, grfHLNF, pmkTarget, + pwzLocation, pwzFriendlyName, puHLID); + + if (phlFrame) + r = IHlinkFrame_OnNavigate(phlFrame,grfHLNF,pmkTarget, pwzLocation, + pwzFriendlyName, 0); + + return r; } HRESULT WINAPI HlinkCreateFromData(IDataObject *piDataObj, @@ -113,7 +213,13 @@ HRESULT WINAPI HlinkCreateFromData(IDataObject *piDataObj, { FIXME("%p %p %ld %p %p %p\n", piDataObj, pihlsite, dwSiteData, piunkOuter, riid, ppvObj); + *ppvObj = NULL; + return E_NOTIMPL; +} +HRESULT WINAPI HlinkQueryCreateFromData(IDataObject* piDataObj) +{ + FIXME("%p\n", piDataObj); return E_NOTIMPL; } @@ -124,17 +230,85 @@ HRESULT WINAPI HlinkCreateExtensionServices(LPCWSTR pwzAdditionalHeaders, FIXME("%s %p %s %s %p %s %p\n",debugstr_w(pwzAdditionalHeaders), phwnd, debugstr_w(pszUsername), debugstr_w(pszPassword), punkOuter, debugstr_guid(riid), ppvObj); - return E_NOTIMPL; } +static HRESULT WINAPI HLinkCF_fnQueryInterface ( LPCLASSFACTORY iface, + REFIID riid, LPVOID *ppvObj) +{ + CFImpl *This = (CFImpl *)iface; + + TRACE("(%p)->(%s)\n",This,debugstr_guid(riid)); + + *ppvObj = NULL; + + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IClassFactory)) + { + *ppvObj = This; + return S_OK; + } + + TRACE("-- E_NOINTERFACE\n"); + return E_NOINTERFACE; +} + +static ULONG WINAPI HLinkCF_fnAddRef (LPCLASSFACTORY iface) +{ + return 2; +} + +static ULONG WINAPI HLinkCF_fnRelease(LPCLASSFACTORY iface) +{ + return 1; +} + +static HRESULT WINAPI HLinkCF_fnCreateInstance( LPCLASSFACTORY iface, + LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObject) +{ + CFImpl *This = (CFImpl *)iface; + + TRACE("%p->(%p,%s,%p)\n", This, pUnkOuter, debugstr_guid(riid), ppvObject); + + *ppvObject = NULL; + + return This->lpfnCI(pUnkOuter, riid, ppvObject); +} + +static HRESULT WINAPI HLinkCF_fnLockServer(LPCLASSFACTORY iface, BOOL fLock) +{ + FIXME("%p %d\n", iface, fLock); + return E_NOTIMPL; +} + +static const IClassFactoryVtbl hlcfvt = +{ + HLinkCF_fnQueryInterface, + HLinkCF_fnAddRef, + HLinkCF_fnRelease, + HLinkCF_fnCreateInstance, + HLinkCF_fnLockServer +}; + +static CFImpl HLink_cf = { &hlcfvt, &HLink_Constructor }; +static CFImpl HLinkBrowseContext_cf = { &hlcfvt, &HLinkBrowseContext_Constructor }; + HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv) { - FIXME("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(iid), ppv); + IClassFactory *pcf = NULL; + + TRACE("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(iid), ppv); if (!ppv) return E_INVALIDARG; *ppv = NULL; - return CLASS_E_CLASSNOTAVAILABLE; + if (IsEqualIID(rclsid, &CLSID_StdHlink)) + pcf = (IClassFactory*) &HLink_cf; + else if (IsEqualIID(rclsid, &CLSID_StdHlinkBrowseContext)) + pcf = (IClassFactory*) &HLinkBrowseContext_cf; + else + return CLASS_E_CLASSNOTAVAILABLE; + + return IClassFactory_QueryInterface(pcf, iid, ppv); } diff --git a/dlls/hlink/link.c b/dlls/hlink/link.c new file mode 100644 index 00000000000..e82672ca32e --- /dev/null +++ b/dlls/hlink/link.c @@ -0,0 +1,741 @@ +/* + * Implementation of hyperlinking (hlink.dll) + * + * Copyright 2005 Aric Stewart for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#define COBJMACROS + +#include "winerror.h" +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "ole2.h" +#include "unknwn.h" +#include "objidl.h" + +#include "wine/debug.h" +#include "hlink.h" +#include "hlguids.h" + +WINE_DEFAULT_DEBUG_CHANNEL(hlink); + +static const IHlinkVtbl hlvt; +static const IPersistStreamVtbl psvt; +static const IDataObjectVtbl dovt; + +typedef struct +{ + const IHlinkVtbl *lpVtbl; + LONG ref; + + const IPersistStreamVtbl *lpPSVtbl; + const IDataObjectVtbl *lpDOVtbl; + + LPWSTR FriendlyName; + LPWSTR Location; + LPWSTR Target; + LPWSTR TargetFrameName; + IMoniker *Moniker; + IHlinkSite *Site; + DWORD SiteData; +} HlinkImpl; + + +static inline HlinkImpl* HlinkImpl_from_IPersistStream( IPersistStream* iface) +{ + return (HlinkImpl*) ((CHAR*)iface - FIELD_OFFSET(HlinkImpl, lpPSVtbl)); +} + +static inline HlinkImpl* HlinkImpl_from_IDataObject( IDataObject* iface) +{ + return (HlinkImpl*) ((CHAR*)iface - FIELD_OFFSET(HlinkImpl, lpDOVtbl)); +} + +static inline void __GetMoniker(HlinkImpl* This, IMoniker** moniker) +{ + *moniker = NULL; + if (This->Moniker) + { + *moniker = This->Moniker; + if (*moniker) + IMoniker_AddRef(*moniker); + } + else if (This->Site) + { + IHlinkSite_GetMoniker(This->Site, This->SiteData, + OLEGETMONIKER_FORCEASSIGN, OLEWHICHMK_CONTAINER, + (LPVOID)moniker); + } +} + +HRESULT WINAPI HLink_Constructor(IUnknown *pUnkOuter, REFIID riid, + LPVOID *ppv) +{ + HlinkImpl * hl; + + TRACE("unkOut=%p riid=%s\n", pUnkOuter, debugstr_guid(riid)); + *ppv = NULL; + + if (pUnkOuter) + return CLASS_E_NOAGGREGATION; + + hl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HlinkImpl)); + if (!hl) + return E_OUTOFMEMORY; + + hl->ref = 1; + hl->lpVtbl = &hlvt; + hl->lpPSVtbl = &psvt; + hl->lpDOVtbl = &dovt; + + *ppv = hl; + return S_OK; +} + +static HRESULT WINAPI IHlink_fnQueryInterface(IHlink* iface, REFIID riid, + LPVOID *ppvObj) +{ + HlinkImpl *This = (HlinkImpl*)iface; + + TRACE ("(%p)->(%s,%p)\n", This, debugstr_guid (riid), ppvObj); + + *ppvObj = NULL; + + if (IsEqualIID(riid, &IID_IUnknown) || (IsEqualIID(riid, &IID_IHlink))) + *ppvObj = This; + else if (IsEqualIID(riid, &IID_IPersistStream)) + *ppvObj = (LPVOID*)&(This->lpPSVtbl); + else if (IsEqualIID(riid, &IID_IDataObject)) + *ppvObj = (LPVOID*)&(This->lpDOVtbl); + + if (*ppvObj) + { + IUnknown_AddRef((IUnknown*)(*ppvObj)); + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI IHlink_fnAddRef (IHlink* iface) +{ + HlinkImpl *This = (HlinkImpl*)iface; + ULONG refCount = InterlockedIncrement(&This->ref); + + TRACE("(%p)->(count=%lu)\n", This, refCount - 1); + + return refCount; +} + +static ULONG WINAPI IHlink_fnRelease (IHlink* iface) +{ + HlinkImpl *This = (HlinkImpl*)iface; + ULONG refCount = InterlockedDecrement(&This->ref); + + TRACE("(%p)->(count=%lu)\n", This, refCount + 1); + if (refCount) + return refCount; + + TRACE("-- destroying IHlink (%p)\n", This); + HeapFree(GetProcessHeap(), 0, This->FriendlyName); + HeapFree(GetProcessHeap(), 0, This->Target); + HeapFree(GetProcessHeap(), 0, This->TargetFrameName); + HeapFree(GetProcessHeap(), 0, This->Location); + if (This->Moniker) + IMoniker_Release(This->Moniker); + if (This->Site) + IHlinkSite_Release(This->Site); + HeapFree(GetProcessHeap(), 0, This); + return 0; +} + +static HRESULT WINAPI IHlink_fnSetHlinkSite( IHlink* iface, + IHlinkSite* pihlSite, DWORD dwSiteData) +{ + HlinkImpl *This = (HlinkImpl*)iface; + + TRACE("(%p)->(%p %li)\n", This, pihlSite, dwSiteData); + + if (This->Site) + IHlinkSite_Release(This->Site); + + This->Site = pihlSite; + if (This->Site) + IHlinkSite_AddRef(This->Site); + + This->SiteData = dwSiteData; + + return S_OK; +} + +static HRESULT WINAPI IHlink_fnGetHlinkSite( IHlink* iface, + IHlinkSite** ppihlSite, DWORD *pdwSiteData) +{ + HlinkImpl *This = (HlinkImpl*)iface; + + TRACE("(%p)->(%p %p)\n", This, ppihlSite, pdwSiteData); + + *ppihlSite = This->Site; + *pdwSiteData = This->SiteData; + + if (This->Site) + IHlinkSite_AddRef(This->Site); + + return S_OK; +} + +static HRESULT WINAPI IHlink_fnSetMonikerReference( IHlink* iface, + DWORD rfHLSETF, IMoniker *pmkTarget, LPCWSTR pwzLocation) +{ + HlinkImpl *This = (HlinkImpl*)iface; + + FIXME("(%p)->(%li %p %s)\n", This, rfHLSETF, pmkTarget, + debugstr_w(pwzLocation)); + + if (This->Moniker) + IMoniker_Release(This->Moniker); + + This->Moniker = pmkTarget; + if (This->Moniker) + IMoniker_AddRef(This->Moniker); + + HeapFree(GetProcessHeap(), 0, This->Location); + This->Location = NULL; + if (pwzLocation) + { + This->Location = HeapAlloc(GetProcessHeap(), 0, + (lstrlenW(pwzLocation)+1)*sizeof(WCHAR)); + lstrcpyW(This->Location, pwzLocation); + } + + return S_OK; +} + +static HRESULT WINAPI IHlink_fnSetStringReference(IHlink* iface, + DWORD grfHLSETF, LPCWSTR pwzTarget, LPCWSTR pwzLocation) +{ + HlinkImpl *This = (HlinkImpl*)iface; + + TRACE("(%p)->(%li %s %s)\n", This, grfHLSETF, debugstr_w(pwzTarget), + debugstr_w(pwzLocation)); + + if (grfHLSETF & HLINKSETF_TARGET) + { + HeapFree(GetProcessHeap(), 0, This->Target); + This->Target = NULL; + if (pwzTarget) + { + This->Target = HeapAlloc(GetProcessHeap(), 0, + (lstrlenW(pwzTarget)+1)*sizeof(WCHAR)); + lstrcpyW(This->Target, pwzTarget); + } + } + if (grfHLSETF & HLINKSETF_LOCATION) + { + HeapFree(GetProcessHeap(), 0, This->Location); + This->Location = NULL; + if (pwzLocation) + { + This->Location = + HeapAlloc(GetProcessHeap(), 0, (lstrlenW(pwzLocation)+1) + *sizeof(WCHAR)); + lstrcpyW(This->Location, pwzLocation); + } + } + + return S_OK; +} + +static HRESULT WINAPI IHlink_fnGetMonikerReference(IHlink* iface, + DWORD dwWhichRef, IMoniker **ppimkTarget, LPWSTR *ppwzLocation) +{ + HlinkImpl *This = (HlinkImpl*)iface; + + TRACE("(%p) -> (%li %p %p)\n", This, dwWhichRef, ppimkTarget, + ppwzLocation); + + if(ppimkTarget) + __GetMoniker(This, ppimkTarget); + + if (ppwzLocation) + IHlink_GetStringReference(iface, dwWhichRef, NULL, ppwzLocation); + + return S_OK; +} + +static HRESULT WINAPI IHlink_fnGetStringReference (IHlink* iface, + DWORD dwWhichRef, LPWSTR *ppwzTarget, LPWSTR *ppwzLocation) +{ + HlinkImpl *This = (HlinkImpl*)iface; + + FIXME("(%p) -> (%li %p %p)\n", This, dwWhichRef, ppwzTarget, ppwzLocation); + + if (ppwzTarget) + { + if (This->Target) + { + *ppwzTarget = HeapAlloc(GetProcessHeap(), 0, + (lstrlenW(This->Target)+1) * sizeof(WCHAR)); + lstrcpyW(*ppwzTarget, This->Target); + } + else + { + IMoniker* mon; + __GetMoniker(This, &mon); + if (mon) + { + IBindCtx *pbc; + + CreateBindCtx( 0, &pbc); + IMoniker_GetDisplayName(mon, pbc, NULL, &This->Target); + IBindCtx_Release(pbc); + *ppwzTarget = HeapAlloc(GetProcessHeap(), 0, + (lstrlenW(This->Target)+1) * sizeof(WCHAR)); + lstrcpyW(*ppwzTarget, This->Target); + IMoniker_Release(mon); + } + else + { + FIXME("Unhandled case, no set Target and no moniker\n"); + *ppwzTarget = NULL; + } + } + } + if (ppwzLocation) + { + if (This->Location) + { + *ppwzLocation = HeapAlloc(GetProcessHeap(), 0, + (lstrlenW(This->Location)+1) * sizeof(WCHAR)); + lstrcpyW(*ppwzLocation, This->Location); + } + else + { + FIXME("Unhandled case, no explicitly set Location\n"); + *ppwzLocation = NULL; + } + } + + TRACE("(Target: %s Location: %s)\n", + (ppwzTarget)?debugstr_w(*ppwzTarget):"", + (ppwzLocation)?debugstr_w(*ppwzLocation):""); + + return S_OK; +} + +static HRESULT WINAPI IHlink_fnSetFriendlyName (IHlink *iface, + LPCWSTR pwzFriendlyName) +{ + HlinkImpl *This = (HlinkImpl*)iface; + + TRACE("(%p) -> (%s)\n", This, debugstr_w(pwzFriendlyName)); + + HeapFree(GetProcessHeap(), 0, This->FriendlyName); + This->FriendlyName = HeapAlloc(GetProcessHeap(), 0, + (lstrlenW(pwzFriendlyName)+1) * sizeof(WCHAR)); + lstrcpyW(This->FriendlyName, pwzFriendlyName); + + return S_OK; +} + +static HRESULT WINAPI IHlink_fnGetFriendlyName (IHlink* iface, + DWORD grfHLFNAMEF, LPWSTR* ppwzFriendlyName) +{ + HlinkImpl *This = (HlinkImpl*)iface; + + TRACE("(%p) -> (%li %p)\n", This, grfHLFNAMEF, ppwzFriendlyName); + + /* FIXME: Only using explicitly set and cached friendly names */ + + if (This->FriendlyName) + { + *ppwzFriendlyName = HeapAlloc(GetProcessHeap(), 0, + (lstrlenW(This->FriendlyName)+1) * sizeof(WCHAR)); + lstrcpyW(*ppwzFriendlyName, This->FriendlyName); + } + else + { + IMoniker *moniker; + __GetMoniker(This, &moniker); + if (moniker) + { + IBindCtx *bcxt; + CreateBindCtx(0, &bcxt); + + IMoniker_GetDisplayName(moniker, bcxt, NULL, ppwzFriendlyName); + IBindCtx_Release(bcxt); + IMoniker_Release(moniker); + } + else + *ppwzFriendlyName = NULL; + } + + return S_OK; +} + +static HRESULT WINAPI IHlink_fnSetTargetFrameName(IHlink* iface, + LPCWSTR pwzTargetFramename) +{ + HlinkImpl *This = (HlinkImpl*)iface; + TRACE("(%p)->(%s)\n", This, debugstr_w(pwzTargetFramename)); + + HeapFree(GetProcessHeap(), 0, This->TargetFrameName); + This->TargetFrameName = HeapAlloc(GetProcessHeap(), 0, + (lstrlenW(pwzTargetFramename)+1) * sizeof(WCHAR)); + lstrcpyW(This->TargetFrameName, pwzTargetFramename); + + return S_OK; +} + +static HRESULT WINAPI IHlink_fnGetTargetFrameName(IHlink* iface, + LPWSTR *ppwzTargetFrameName) +{ + HlinkImpl *This = (HlinkImpl*)iface; + + TRACE("(%p)->(%p)\n", This, ppwzTargetFrameName); + if (This->TargetFrameName) + { + *ppwzTargetFrameName = HeapAlloc(GetProcessHeap(), 0, + (lstrlenW(This->TargetFrameName)+1) * sizeof(WCHAR)); + lstrcpyW(*ppwzTargetFrameName, This->TargetFrameName); + } + else + *ppwzTargetFrameName = NULL; + + return S_OK; +} + +static HRESULT WINAPI IHlink_fnGetMiscStatus(IHlink* iface, DWORD* pdwStatus) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI IHlink_fnNavigate(IHlink* iface, DWORD grfHLNF, LPBC pbc, + IBindStatusCallback *pbsc, IHlinkBrowseContext *phbc) +{ + HlinkImpl *This = (HlinkImpl*)iface; + IMoniker *mon = NULL; + + FIXME("Semi-Stub:(%p)->(%li %p %p %p)\n", This, grfHLNF, pbc, pbsc, phbc); + + if (This->Site) + IHlinkSite_ReadyToNavigate(This->Site, This->SiteData, 0); + + __GetMoniker(This, &mon); + TRACE("Moniker %p\n", mon); + + if (mon) + { + IBindCtx *bcxt; + IHlinkTarget *target; + HRESULT r = S_OK; + + CreateBindCtx(0, &bcxt); + + RegisterBindStatusCallback(bcxt, pbsc, NULL, 0); + + r = IMoniker_BindToObject(mon, bcxt, NULL, &IID_IHlinkTarget, + (LPVOID*)&target); + TRACE("IHlinkTarget returned 0x%lx\n", r); + if (r == S_OK) + { + IHlinkTarget_SetBrowseContext(target, phbc); + IHlinkTarget_Navigate(target, grfHLNF, This->Location); + } + + RevokeBindStatusCallback(bcxt, pbsc); + + IBindCtx_Release(bcxt); + IHlinkTarget_Release(target); + IMoniker_Release(mon); + } + + if (This->Site) + IHlinkSite_OnNavigationComplete(This->Site, This->SiteData, 0, 0, NULL); + + TRACE("Finished Navigation\n"); + return S_OK; +} + +static HRESULT WINAPI IHlink_fnSetAdditonalParams(IHlink* iface, + LPCWSTR pwzAdditionalParams) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI IHlink_fnGetAdditionalParams(IHlink* iface, + LPWSTR* ppwzAdditionalParams) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static const IHlinkVtbl hlvt = +{ + IHlink_fnQueryInterface, + IHlink_fnAddRef, + IHlink_fnRelease, + IHlink_fnSetHlinkSite, + IHlink_fnGetHlinkSite, + IHlink_fnSetMonikerReference, + IHlink_fnGetMonikerReference, + IHlink_fnSetStringReference, + IHlink_fnGetStringReference, + IHlink_fnSetFriendlyName, + IHlink_fnGetFriendlyName, + IHlink_fnSetTargetFrameName, + IHlink_fnGetTargetFrameName, + IHlink_fnGetMiscStatus, + IHlink_fnNavigate, + IHlink_fnSetAdditonalParams, + IHlink_fnGetAdditionalParams +}; + +static HRESULT WINAPI IDataObject_fnQueryInterface(IDataObject* iface, + REFIID riid, LPVOID *ppvObj) +{ + HlinkImpl *This = HlinkImpl_from_IDataObject(iface); + TRACE("%p\n", This); + return IHlink_QueryInterface((IHlink*)This, riid, ppvObj); +} + +static ULONG WINAPI IDataObject_fnAddRef (IDataObject* iface) +{ + HlinkImpl *This = HlinkImpl_from_IDataObject(iface); + TRACE("%p\n", This); + return IHlink_AddRef((IHlink*)This); +} + +static ULONG WINAPI IDataObject_fnRelease (IDataObject* iface) +{ + HlinkImpl *This = HlinkImpl_from_IDataObject(iface); + TRACE("%p\n", This); + return IHlink_Release((IHlink*)This); +} + +static HRESULT WINAPI IDataObject_fnGetData(IDataObject* iface, + FORMATETC* pformatetcIn, STGMEDIUM* pmedium) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI IDataObject_fnGetDataHere(IDataObject* iface, + FORMATETC* pformatetc, STGMEDIUM* pmedium) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI IDataObject_fnQueryGetData(IDataObject* iface, + FORMATETC* pformatetc) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI IDataObject_fnGetConicalFormatEtc(IDataObject* iface, + FORMATETC* pformatetcIn, FORMATETC* pformatetcOut) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI IDataObject_fnSetData(IDataObject* iface, + FORMATETC* pformatetc, STGMEDIUM* pmedium, BOOL fRelease) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI IDataObject_fnEnumFormatEtc(IDataObject* iface, + DWORD dwDirection, IEnumFORMATETC** ppenumFormatEtc) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI IDataObject_fnDAdvise(IDataObject* iface, + FORMATETC* pformatetc, DWORD advf, IAdviseSink* pAdvSink, + DWORD* pdwConnection) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI IDataObject_fnDUnadvise(IDataObject* iface, + DWORD dwConnection) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI IDataObject_fnEnumDAdvise(IDataObject* iface, + IEnumSTATDATA** ppenumAdvise) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static const IDataObjectVtbl dovt = +{ + IDataObject_fnQueryInterface, + IDataObject_fnAddRef, + IDataObject_fnRelease, + IDataObject_fnGetData, + IDataObject_fnGetDataHere, + IDataObject_fnQueryGetData, + IDataObject_fnGetConicalFormatEtc, + IDataObject_fnSetData, + IDataObject_fnEnumFormatEtc, + IDataObject_fnDAdvise, + IDataObject_fnDUnadvise, + IDataObject_fnEnumDAdvise +}; + +static HRESULT WINAPI IPersistStream_fnQueryInterface(IPersistStream* iface, + REFIID riid, LPVOID *ppvObj) +{ + HlinkImpl *This = HlinkImpl_from_IPersistStream(iface); + TRACE("(%p)\n", This); + return IHlink_QueryInterface((IHlink*)This, riid, ppvObj); +} + +static ULONG WINAPI IPersistStream_fnAddRef (IPersistStream* iface) +{ + HlinkImpl *This = HlinkImpl_from_IPersistStream(iface); + TRACE("(%p)\n", This); + return IHlink_AddRef((IHlink*)This); +} + +static ULONG WINAPI IPersistStream_fnRelease (IPersistStream* iface) +{ + HlinkImpl *This = HlinkImpl_from_IPersistStream(iface); + TRACE("(%p)\n", This); + return IHlink_Release((IHlink*)This); +} + +static HRESULT WINAPI IPersistStream_fnGetClassID(IPersistStream* iface, + CLSID* pClassID) +{ + HlinkImpl *This = HlinkImpl_from_IPersistStream(iface); + TRACE("(%p)\n", This); + memcpy(pClassID, &CLSID_StdHlink, sizeof(CLSID)); + return S_OK; +} + +static HRESULT WINAPI IPersistStream_fnIsDirty(IPersistStream* iface) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI IPersistStream_fnLoad(IPersistStream* iface, + IStream* pStm) +{ + HRESULT r = E_NOTIMPL; + DWORD hdr[2]; + DWORD read; + HlinkImpl *This = HlinkImpl_from_IPersistStream(iface); + + IStream_Read(pStm, &hdr, sizeof(hdr), &read); + /* FIXME: unknown header values */ + + r = OleLoadFromStream(pStm, &IID_IMoniker, (LPVOID*)&(This->Moniker)); + TRACE("Load Result 0x%lx (%p)\n", r, This->Moniker); + + return r; +} + +static HRESULT WINAPI IPersistStream_fnSave(IPersistStream* iface, + IStream* pStm, BOOL fClearDirty) +{ + HRESULT r = E_FAIL; + HlinkImpl *This = HlinkImpl_from_IPersistStream(iface); + DWORD hdr[2]; + IMoniker *moniker; + + FIXME("(%p) Moniker(%p)\n", This, This->Moniker); + + __GetMoniker(This, &moniker); + if (moniker) + { + IPersistStream* monstream; + /* FIXME: Unknown values in the header */ + hdr[0] = 2; + hdr[1] = 2; + + IStream_Write(pStm, &hdr, sizeof(hdr), NULL); + + monstream = NULL; + IMoniker_QueryInterface(moniker, &IID_IPersistStream, + (LPVOID*)&monstream); + if (monstream) + { + r = OleSaveToStream(monstream, pStm); + IPersistStream_Release(monstream); + } + IMoniker_Release(moniker); + } + TRACE("Save Result 0x%lx\n", r); + + return r; +} + +static HRESULT WINAPI IPersistStream_fnGetSizeMax(IPersistStream* iface, + ULARGE_INTEGER* pcbSize) +{ + HRESULT r = E_FAIL; + HlinkImpl *This = HlinkImpl_from_IPersistStream(iface); + IMoniker *moniker; + + FIXME("(%p) Moniker(%p)\n", This, This->Moniker); + + __GetMoniker(This, &moniker); + if (moniker) + { + IPersistStream* monstream = NULL; + IMoniker_QueryInterface(moniker, &IID_IPersistStream, + (LPVOID*)&monstream); + if (monstream) + { + r = IPersistStream_GetSizeMax(monstream, pcbSize); + /* FIXME: Handle ULARGE_INTEGER correctly */ + pcbSize->u.LowPart += sizeof(DWORD)*2; + IPersistStream_Release(monstream); + } + IMoniker_Release(moniker); + } + + return r; +} + +static const IPersistStreamVtbl psvt = +{ + IPersistStream_fnQueryInterface, + IPersistStream_fnAddRef, + IPersistStream_fnRelease, + IPersistStream_fnGetClassID, + IPersistStream_fnIsDirty, + IPersistStream_fnLoad, + IPersistStream_fnSave, + IPersistStream_fnGetSizeMax, +};