|  | /* | 
|  | * UrlMon | 
|  | * | 
|  | * Copyright 1999 Ulrich Czekalla for Corel Corporation | 
|  | * Copyright 2002 Huw D M Davies for CodeWeavers | 
|  | * Copyright 2005 Jacek Caban 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 "urlmon_main.h" | 
|  |  | 
|  | #include "winreg.h" | 
|  | #include "shlwapi.h" | 
|  | #include "hlink.h" | 
|  | #include "shellapi.h" | 
|  |  | 
|  | #include "wine/debug.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(urlmon); | 
|  |  | 
|  | typedef struct { | 
|  | IMoniker      IMoniker_iface; | 
|  | IUriContainer IUriContainer_iface; | 
|  |  | 
|  | LONG ref; | 
|  |  | 
|  | IUri *uri; | 
|  | BSTR URLName; | 
|  | } URLMoniker; | 
|  |  | 
|  | static inline URLMoniker *impl_from_IMoniker(IMoniker *iface) | 
|  | { | 
|  | return CONTAINING_RECORD(iface, URLMoniker, IMoniker_iface); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI URLMoniker_QueryInterface(IMoniker *iface, REFIID riid, void **ppv) | 
|  | { | 
|  | URLMoniker *This = impl_from_IMoniker(iface); | 
|  |  | 
|  | if(!ppv) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | if(IsEqualIID(&IID_IUnknown, riid)) { | 
|  | TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); | 
|  | *ppv = iface; | 
|  | }else if(IsEqualIID(&IID_IPersist, riid)) { | 
|  | TRACE("(%p)->(IID_IPersist %p)\n", This, ppv); | 
|  | *ppv = iface; | 
|  | }else if(IsEqualIID(&IID_IPersistStream,riid)) { | 
|  | TRACE("(%p)->(IID_IPersistStream %p)\n", This, ppv); | 
|  | *ppv = iface; | 
|  | }else if(IsEqualIID(&IID_IMoniker, riid)) { | 
|  | TRACE("(%p)->(IID_IMoniker %p)\n", This, ppv); | 
|  | *ppv = iface; | 
|  | }else if(IsEqualIID(&IID_IAsyncMoniker, riid)) { | 
|  | TRACE("(%p)->(IID_IAsyncMoniker %p)\n", This, ppv); | 
|  | *ppv = iface; | 
|  | }else if(IsEqualIID(&IID_IUriContainer, riid)) { | 
|  | TRACE("(%p)->(IID_IUriContainer %p)\n", This, ppv); | 
|  | *ppv = &This->IUriContainer_iface; | 
|  | }else { | 
|  | WARN("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppv); | 
|  | *ppv = NULL; | 
|  | return E_NOINTERFACE; | 
|  | } | 
|  |  | 
|  | IMoniker_AddRef((IUnknown*)*ppv); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI URLMoniker_AddRef(IMoniker *iface) | 
|  | { | 
|  | URLMoniker *This = impl_from_IMoniker(iface); | 
|  | ULONG refCount = InterlockedIncrement(&This->ref); | 
|  |  | 
|  | TRACE("(%p) ref=%u\n",This, refCount); | 
|  |  | 
|  | return refCount; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI URLMoniker_Release(IMoniker *iface) | 
|  | { | 
|  | URLMoniker *This = impl_from_IMoniker(iface); | 
|  | ULONG refCount = InterlockedDecrement(&This->ref); | 
|  |  | 
|  | TRACE("(%p) ref=%u\n",This, refCount); | 
|  |  | 
|  | if (!refCount) { | 
|  | if(This->uri) | 
|  | IUri_Release(This->uri); | 
|  | SysFreeString(This->URLName); | 
|  | heap_free(This); | 
|  |  | 
|  | URLMON_UnlockModule(); | 
|  | } | 
|  |  | 
|  | return refCount; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI URLMoniker_GetClassID(IMoniker *iface, CLSID *pClassID) | 
|  | { | 
|  | URLMoniker *This = impl_from_IMoniker(iface); | 
|  |  | 
|  | TRACE("(%p,%p)\n", This, pClassID); | 
|  |  | 
|  | if(!pClassID) | 
|  | return E_POINTER; | 
|  |  | 
|  | /* Windows always returns CLSID_StdURLMoniker */ | 
|  | *pClassID = CLSID_StdURLMoniker; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI URLMoniker_IsDirty(IMoniker *iface) | 
|  | { | 
|  | URLMoniker *This = impl_from_IMoniker(iface); | 
|  |  | 
|  | TRACE("(%p)\n",This); | 
|  |  | 
|  | /* Note that the OLE-provided implementations of the IPersistStream::IsDirty | 
|  | method in the OLE-provided moniker interfaces always return S_FALSE because | 
|  | their internal state never changes. */ | 
|  | return S_FALSE; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI URLMoniker_Load(IMoniker* iface,IStream* pStm) | 
|  | { | 
|  | URLMoniker *This = impl_from_IMoniker(iface); | 
|  | WCHAR *new_uri_str; | 
|  | IUri *new_uri; | 
|  | BSTR new_url; | 
|  | ULONG size; | 
|  | ULONG got; | 
|  | HRESULT hres; | 
|  |  | 
|  | TRACE("(%p,%p)\n",This,pStm); | 
|  |  | 
|  | if(!pStm) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | /* | 
|  | * NOTE | 
|  | *  Writes a ULONG containing length of unicode string, followed | 
|  | *  by that many unicode characters | 
|  | */ | 
|  | hres = IStream_Read(pStm, &size, sizeof(ULONG), &got); | 
|  | if(FAILED(hres)) | 
|  | return hres; | 
|  | if(got != sizeof(ULONG)) | 
|  | return E_FAIL; | 
|  |  | 
|  | new_uri_str = heap_alloc(size+sizeof(WCHAR)); | 
|  | if(!new_uri_str) | 
|  | return E_OUTOFMEMORY; | 
|  |  | 
|  | hres = IStream_Read(pStm, new_uri_str, size, NULL); | 
|  | new_uri_str[size/sizeof(WCHAR)] = 0; | 
|  | if(SUCCEEDED(hres)) | 
|  | hres = CreateUri(new_uri_str, 0, 0, &new_uri); | 
|  | heap_free(new_uri_str); | 
|  | if(FAILED(hres)) | 
|  | return hres; | 
|  |  | 
|  | hres = IUri_GetDisplayUri(new_uri, &new_url); | 
|  | if(FAILED(hres)) { | 
|  | IUri_Release(new_uri); | 
|  | return hres; | 
|  | } | 
|  |  | 
|  | SysFreeString(This->URLName); | 
|  | if(This->uri) | 
|  | IUri_Release(This->uri); | 
|  |  | 
|  | This->uri = new_uri; | 
|  | This->URLName = new_url; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI URLMoniker_Save(IMoniker *iface, IStream* pStm, BOOL fClearDirty) | 
|  | { | 
|  | URLMoniker *This = impl_from_IMoniker(iface); | 
|  | HRESULT res; | 
|  | ULONG size; | 
|  |  | 
|  | TRACE("(%p,%p,%d)\n", This, pStm, fClearDirty); | 
|  |  | 
|  | if(!pStm) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | size = (SysStringLen(This->URLName) + 1)*sizeof(WCHAR); | 
|  | res=IStream_Write(pStm,&size,sizeof(ULONG),NULL); | 
|  | if(SUCCEEDED(res)) | 
|  | res=IStream_Write(pStm,This->URLName,size,NULL); | 
|  |  | 
|  | return res; | 
|  |  | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI URLMoniker_GetSizeMax(IMoniker* iface, ULARGE_INTEGER *pcbSize) | 
|  | { | 
|  | URLMoniker *This = impl_from_IMoniker(iface); | 
|  |  | 
|  | TRACE("(%p,%p)\n",This,pcbSize); | 
|  |  | 
|  | if(!pcbSize) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | pcbSize->QuadPart = sizeof(ULONG) + ((SysStringLen(This->URLName)+1) * sizeof(WCHAR)); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI URLMoniker_BindToObject(IMoniker *iface, IBindCtx* pbc, IMoniker *pmkToLeft, | 
|  | REFIID riid, void **ppv) | 
|  | { | 
|  | URLMoniker *This = impl_from_IMoniker(iface); | 
|  | IRunningObjectTable *obj_tbl; | 
|  | HRESULT hres; | 
|  |  | 
|  | TRACE("(%p)->(%p,%p,%s,%p)\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppv); | 
|  |  | 
|  | hres = IBindCtx_GetRunningObjectTable(pbc, &obj_tbl); | 
|  | if(SUCCEEDED(hres)) { | 
|  | FIXME("use running object table\n"); | 
|  | IRunningObjectTable_Release(obj_tbl); | 
|  | } | 
|  |  | 
|  | if(!This->uri) { | 
|  | *ppv = NULL; | 
|  | return MK_E_SYNTAX; | 
|  | } | 
|  |  | 
|  | return bind_to_object(&This->IMoniker_iface, This->uri, pbc, riid, ppv); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI URLMoniker_BindToStorage(IMoniker* iface, IBindCtx* pbc, | 
|  | IMoniker* pmkToLeft, REFIID riid, void **ppvObject) | 
|  | { | 
|  | URLMoniker *This = impl_from_IMoniker(iface); | 
|  |  | 
|  | TRACE("(%p)->(%p %p %s %p)\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppvObject); | 
|  |  | 
|  | if(ppvObject) *ppvObject = NULL; | 
|  |  | 
|  | if(!pbc || !ppvObject) return E_INVALIDARG; | 
|  |  | 
|  | if(pmkToLeft) | 
|  | FIXME("Unsupported pmkToLeft\n"); | 
|  |  | 
|  | if(!This->uri) | 
|  | return MK_E_SYNTAX; | 
|  |  | 
|  | return bind_to_storage(This->uri, pbc, riid, ppvObject); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI URLMoniker_Reduce(IMoniker *iface, IBindCtx *pbc, | 
|  | DWORD dwReduceHowFar, IMoniker **ppmkToLeft, IMoniker **ppmkReduced) | 
|  | { | 
|  | URLMoniker *This = impl_from_IMoniker(iface); | 
|  |  | 
|  | TRACE("(%p,%p,%d,%p,%p)\n", This, pbc, dwReduceHowFar, ppmkToLeft, ppmkReduced); | 
|  |  | 
|  | if(!ppmkReduced) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | IMoniker_AddRef(iface); | 
|  | *ppmkReduced = iface; | 
|  | return MK_S_REDUCED_TO_SELF; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI URLMoniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight, | 
|  | BOOL fOnlyIfNotGeneric, IMoniker **ppmkComposite) | 
|  | { | 
|  | URLMoniker *This = impl_from_IMoniker(iface); | 
|  | FIXME("(%p)->(%p,%d,%p): stub\n",This,pmkRight,fOnlyIfNotGeneric,ppmkComposite); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI URLMoniker_Enum(IMoniker *iface, BOOL fForward, IEnumMoniker **ppenumMoniker) | 
|  | { | 
|  | URLMoniker *This = impl_from_IMoniker(iface); | 
|  |  | 
|  | TRACE("(%p,%d,%p)\n", This, fForward, ppenumMoniker); | 
|  |  | 
|  | if(!ppenumMoniker) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | /* Does not support sub-monikers */ | 
|  | *ppenumMoniker = NULL; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI URLMoniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker) | 
|  | { | 
|  | URLMoniker *This = impl_from_IMoniker(iface); | 
|  | CLSID clsid; | 
|  | LPOLESTR urlPath; | 
|  | IBindCtx* bind; | 
|  | HRESULT res; | 
|  |  | 
|  | TRACE("(%p,%p)\n",This, pmkOtherMoniker); | 
|  |  | 
|  | if(pmkOtherMoniker==NULL) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | IMoniker_GetClassID(pmkOtherMoniker,&clsid); | 
|  |  | 
|  | if(!IsEqualCLSID(&clsid,&CLSID_StdURLMoniker)) | 
|  | return S_FALSE; | 
|  |  | 
|  | res = CreateBindCtx(0,&bind); | 
|  | if(FAILED(res)) | 
|  | return res; | 
|  |  | 
|  | res = S_FALSE; | 
|  | if(SUCCEEDED(IMoniker_GetDisplayName(pmkOtherMoniker,bind,NULL,&urlPath))) { | 
|  | int result = lstrcmpiW(urlPath, This->URLName); | 
|  | CoTaskMemFree(urlPath); | 
|  | if(result == 0) | 
|  | res = S_OK; | 
|  | } | 
|  | IUnknown_Release(bind); | 
|  | return res; | 
|  | } | 
|  |  | 
|  |  | 
|  | static HRESULT WINAPI URLMoniker_Hash(IMoniker *iface, DWORD *pdwHash) | 
|  | { | 
|  | URLMoniker *This = impl_from_IMoniker(iface); | 
|  | int  h = 0,i,skip,len; | 
|  | int  off = 0; | 
|  | LPOLESTR val; | 
|  |  | 
|  | TRACE("(%p,%p)\n",This,pdwHash); | 
|  |  | 
|  | if(!pdwHash) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | val = This->URLName; | 
|  | len = lstrlenW(val); | 
|  |  | 
|  | if(len < 16) { | 
|  | for(i = len ; i > 0; i--) { | 
|  | h = (h * 37) + val[off++]; | 
|  | } | 
|  | }else { | 
|  | /* only sample some characters */ | 
|  | skip = len / 8; | 
|  | for(i = len; i > 0; i -= skip, off += skip) { | 
|  | h = (h * 39) + val[off]; | 
|  | } | 
|  | } | 
|  | *pdwHash = h; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI URLMoniker_IsRunning(IMoniker* iface, IBindCtx* pbc, | 
|  | IMoniker *pmkToLeft, IMoniker *pmkNewlyRunning) | 
|  | { | 
|  | URLMoniker *This = impl_from_IMoniker(iface); | 
|  | FIXME("(%p)->(%p,%p,%p): stub\n",This,pbc,pmkToLeft,pmkNewlyRunning); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI URLMoniker_GetTimeOfLastChange(IMoniker *iface, | 
|  | IBindCtx *pbc, IMoniker *pmkToLeft, FILETIME *pFileTime) | 
|  | { | 
|  | URLMoniker *This = impl_from_IMoniker(iface); | 
|  | FIXME("(%p)->(%p,%p,%p): stub\n", This, pbc, pmkToLeft, pFileTime); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI URLMoniker_Inverse(IMoniker *iface, IMoniker **ppmk) | 
|  | { | 
|  | URLMoniker *This = impl_from_IMoniker(iface); | 
|  | TRACE("(%p,%p)\n",This,ppmk); | 
|  | return MK_E_NOINVERSE; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI URLMoniker_CommonPrefixWith(IMoniker *iface, IMoniker *pmkOther, IMoniker **ppmkPrefix) | 
|  | { | 
|  | URLMoniker *This = impl_from_IMoniker(iface); | 
|  | FIXME("(%p)->(%p,%p): stub\n",This,pmkOther,ppmkPrefix); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI URLMoniker_RelativePathTo(IMoniker *iface, IMoniker *pmOther, IMoniker **ppmkRelPath) | 
|  | { | 
|  | URLMoniker *This = impl_from_IMoniker(iface); | 
|  | FIXME("(%p)->(%p,%p): stub\n",This,pmOther,ppmkRelPath); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI URLMoniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft, | 
|  | LPOLESTR *ppszDisplayName) | 
|  | { | 
|  | URLMoniker *This = impl_from_IMoniker(iface); | 
|  | int len; | 
|  |  | 
|  | TRACE("(%p,%p,%p,%p)\n", This, pbc, pmkToLeft, ppszDisplayName); | 
|  |  | 
|  | if(!ppszDisplayName) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | if(!This->URLName) | 
|  | return E_OUTOFMEMORY; | 
|  |  | 
|  | /* FIXME: If this is a partial URL, try and get a URL moniker from SZ_URLCONTEXT in the bind context, | 
|  | then look at pmkToLeft to try and complete the URL | 
|  | */ | 
|  | len = SysStringLen(This->URLName)+1; | 
|  | *ppszDisplayName = CoTaskMemAlloc(len*sizeof(WCHAR)); | 
|  | if(!*ppszDisplayName) | 
|  | return E_OUTOFMEMORY; | 
|  | lstrcpyW(*ppszDisplayName, This->URLName); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI URLMoniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft, | 
|  | LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut) | 
|  | { | 
|  | URLMoniker *This = impl_from_IMoniker(iface); | 
|  | FIXME("(%p)->(%p,%p,%p,%p,%p): stub\n",This,pbc,pmkToLeft,pszDisplayName,pchEaten,ppmkOut); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI URLMoniker_IsSystemMoniker(IMoniker *iface, DWORD *pwdMksys) | 
|  | { | 
|  | URLMoniker *This = impl_from_IMoniker(iface); | 
|  |  | 
|  | TRACE("(%p,%p)\n",This,pwdMksys); | 
|  |  | 
|  | if(!pwdMksys) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | *pwdMksys = MKSYS_URLMONIKER; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static const IMonikerVtbl URLMonikerVtbl = | 
|  | { | 
|  | URLMoniker_QueryInterface, | 
|  | URLMoniker_AddRef, | 
|  | URLMoniker_Release, | 
|  | URLMoniker_GetClassID, | 
|  | URLMoniker_IsDirty, | 
|  | URLMoniker_Load, | 
|  | URLMoniker_Save, | 
|  | URLMoniker_GetSizeMax, | 
|  | URLMoniker_BindToObject, | 
|  | URLMoniker_BindToStorage, | 
|  | URLMoniker_Reduce, | 
|  | URLMoniker_ComposeWith, | 
|  | URLMoniker_Enum, | 
|  | URLMoniker_IsEqual, | 
|  | URLMoniker_Hash, | 
|  | URLMoniker_IsRunning, | 
|  | URLMoniker_GetTimeOfLastChange, | 
|  | URLMoniker_Inverse, | 
|  | URLMoniker_CommonPrefixWith, | 
|  | URLMoniker_RelativePathTo, | 
|  | URLMoniker_GetDisplayName, | 
|  | URLMoniker_ParseDisplayName, | 
|  | URLMoniker_IsSystemMoniker | 
|  | }; | 
|  |  | 
|  | static inline URLMoniker *impl_from_IUriContainer(IUriContainer *iface) | 
|  | { | 
|  | return CONTAINING_RECORD(iface, URLMoniker, IUriContainer_iface); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI UriContainer_QueryInterface(IUriContainer *iface, REFIID riid, void **ppv) | 
|  | { | 
|  | URLMoniker *This = impl_from_IUriContainer(iface); | 
|  | return IMoniker_QueryInterface(&This->IMoniker_iface, riid, ppv); | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI UriContainer_AddRef(IUriContainer *iface) | 
|  | { | 
|  | URLMoniker *This = impl_from_IUriContainer(iface); | 
|  | return IMoniker_AddRef(&This->IMoniker_iface); | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI UriContainer_Release(IUriContainer *iface) | 
|  | { | 
|  | URLMoniker *This = impl_from_IUriContainer(iface); | 
|  | return IMoniker_Release(&This->IMoniker_iface); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI UriContainer_GetIUri(IUriContainer *iface, IUri **ppIUri) | 
|  | { | 
|  | URLMoniker *This = impl_from_IUriContainer(iface); | 
|  |  | 
|  | TRACE("(%p)->(%p)\n", This, ppIUri); | 
|  |  | 
|  | if(!This->uri) { | 
|  | *ppIUri = NULL; | 
|  | return S_FALSE; | 
|  | } | 
|  |  | 
|  | IUri_AddRef(This->uri); | 
|  | *ppIUri = This->uri; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static const IUriContainerVtbl UriContainerVtbl = { | 
|  | UriContainer_QueryInterface, | 
|  | UriContainer_AddRef, | 
|  | UriContainer_Release, | 
|  | UriContainer_GetIUri | 
|  | }; | 
|  |  | 
|  | static HRESULT create_moniker(IUri *uri, URLMoniker **ret) | 
|  | { | 
|  | URLMoniker *mon; | 
|  | HRESULT hres; | 
|  |  | 
|  | mon = heap_alloc(sizeof(*mon)); | 
|  | if(!mon) | 
|  | return E_OUTOFMEMORY; | 
|  |  | 
|  | mon->IMoniker_iface.lpVtbl = &URLMonikerVtbl; | 
|  | mon->IUriContainer_iface.lpVtbl = &UriContainerVtbl; | 
|  | mon->ref = 1; | 
|  |  | 
|  | if(uri) { | 
|  | /* FIXME: try to avoid it */ | 
|  | hres = IUri_GetDisplayUri(uri, &mon->URLName); | 
|  | if(FAILED(hres)) { | 
|  | heap_free(mon); | 
|  | return hres; | 
|  | } | 
|  |  | 
|  | IUri_AddRef(uri); | 
|  | mon->uri = uri; | 
|  | }else { | 
|  | mon->URLName = NULL; | 
|  | mon->uri = NULL; | 
|  | } | 
|  |  | 
|  | URLMON_LockModule(); | 
|  | *ret = mon; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | HRESULT StdURLMoniker_Construct(IUnknown *outer, void **ppv) | 
|  | { | 
|  | URLMoniker *mon; | 
|  | HRESULT hres; | 
|  |  | 
|  | TRACE("(%p %p)\n", outer, ppv); | 
|  |  | 
|  | hres = create_moniker(NULL, &mon); | 
|  | if(FAILED(hres)) | 
|  | return hres; | 
|  |  | 
|  | *ppv = &mon->IMoniker_iface; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static const DWORD create_flags_map[3] = { | 
|  | Uri_CREATE_FILE_USE_DOS_PATH,  /* URL_MK_LEGACY */ | 
|  | 0,                             /* URL_MK_UNIFORM */ | 
|  | Uri_CREATE_NO_CANONICALIZE     /* URL_MK_NO_CANONICALIZE */ | 
|  | }; | 
|  |  | 
|  | static const DWORD combine_flags_map[3] = { | 
|  | URL_FILE_USE_PATHURL,  /* URL_MK_LEGACY */ | 
|  | 0,                     /* URL_MK_UNIFORM */ | 
|  | URL_DONT_SIMPLIFY      /* URL_MK_NO_CANONICALIZE */ | 
|  | }; | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           CreateURLMonikerEx (URLMON.@) | 
|  | * | 
|  | * Create a url moniker. | 
|  | * | 
|  | * PARAMS | 
|  | *    pmkContext [I] Context | 
|  | *    szURL      [I] Url to create the moniker for | 
|  | *    ppmk       [O] Destination for created moniker. | 
|  | *    dwFlags    [I] Flags. | 
|  | * | 
|  | * RETURNS | 
|  | *    Success: S_OK. ppmk contains the created IMoniker object. | 
|  | *    Failure: MK_E_SYNTAX if szURL is not a valid url, or | 
|  | *             E_OUTOFMEMORY if memory allocation fails. | 
|  | */ | 
|  | HRESULT WINAPI CreateURLMonikerEx(IMoniker *pmkContext, LPCWSTR szURL, IMoniker **ppmk, DWORD dwFlags) | 
|  | { | 
|  | IUri *uri, *base_uri = NULL; | 
|  | URLMoniker *obj; | 
|  | HRESULT hres; | 
|  |  | 
|  | TRACE("(%p, %s, %p, %08x)\n", pmkContext, debugstr_w(szURL), ppmk, dwFlags); | 
|  |  | 
|  | if (ppmk) | 
|  | *ppmk = NULL; | 
|  |  | 
|  | if (!szURL || !ppmk) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | if(dwFlags >= sizeof(create_flags_map)/sizeof(*create_flags_map)) { | 
|  | FIXME("Unsupported flags %x\n", dwFlags); | 
|  | return E_INVALIDARG; | 
|  | } | 
|  |  | 
|  | if(pmkContext) { | 
|  | IUriContainer *uri_container; | 
|  |  | 
|  | hres = IMoniker_QueryInterface(pmkContext, &IID_IUriContainer, (void**)&uri_container); | 
|  | if(SUCCEEDED(hres)) { | 
|  | hres = IUriContainer_GetIUri(uri_container, &base_uri); | 
|  | IUriContainer_Release(uri_container); | 
|  | if(FAILED(hres)) | 
|  | return hres; | 
|  | } | 
|  | } | 
|  |  | 
|  | if(base_uri) { | 
|  | hres = CoInternetCombineUrlEx(base_uri, szURL, combine_flags_map[dwFlags], &uri, 0); | 
|  | IUri_Release(base_uri); | 
|  | }else { | 
|  | hres = CreateUri(szURL, Uri_CREATE_ALLOW_RELATIVE|Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME|create_flags_map[dwFlags], 0, &uri); | 
|  | } | 
|  | if(FAILED(hres)) | 
|  | return hres; | 
|  |  | 
|  | hres = create_moniker(uri, &obj); | 
|  | IUri_Release(uri); | 
|  | if(FAILED(hres)) | 
|  | return hres; | 
|  |  | 
|  | *ppmk = &obj->IMoniker_iface; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           CreateURLMonikerEx2 (URLMON.@) | 
|  | */ | 
|  | HRESULT WINAPI CreateURLMonikerEx2(IMoniker *pmkContext, IUri *pUri, IMoniker **ppmk, DWORD dwFlags) | 
|  | { | 
|  | IUri *context_uri = NULL, *uri; | 
|  | IUriContainer *uri_container; | 
|  | URLMoniker *ret; | 
|  | HRESULT hres; | 
|  |  | 
|  | TRACE("(%p %p %p %x)\n", pmkContext, pUri, ppmk, dwFlags); | 
|  |  | 
|  | if (ppmk) | 
|  | *ppmk = NULL; | 
|  |  | 
|  | if (!pUri || !ppmk) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | if(dwFlags >= sizeof(create_flags_map)/sizeof(*create_flags_map)) { | 
|  | FIXME("Unsupported flags %x\n", dwFlags); | 
|  | return E_INVALIDARG; | 
|  | } | 
|  |  | 
|  | if(pmkContext) { | 
|  | hres = IMoniker_QueryInterface(pmkContext, &IID_IUriContainer, (void**)&uri_container); | 
|  | if(SUCCEEDED(hres)) { | 
|  | hres = IUriContainer_GetIUri(uri_container, &context_uri); | 
|  | if(FAILED(hres)) | 
|  | context_uri = NULL; | 
|  | IUriContainer_Release(uri_container); | 
|  | } | 
|  | } | 
|  |  | 
|  | if(context_uri) { | 
|  | hres = CoInternetCombineIUri(context_uri, pUri, combine_flags_map[dwFlags], &uri, 0); | 
|  | IUri_Release(context_uri); | 
|  | if(FAILED(hres)) | 
|  | return hres; | 
|  | }else { | 
|  | uri = pUri; | 
|  | IUri_AddRef(uri); | 
|  | } | 
|  |  | 
|  | hres = create_moniker(uri, &ret); | 
|  | IUri_Release(uri); | 
|  | if(FAILED(hres)) | 
|  | return hres; | 
|  |  | 
|  | *ppmk = &ret->IMoniker_iface; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /********************************************************************** | 
|  | *           CreateURLMoniker (URLMON.@) | 
|  | * | 
|  | * Create a url moniker. | 
|  | * | 
|  | * PARAMS | 
|  | *    pmkContext [I] Context | 
|  | *    szURL      [I] Url to create the moniker for | 
|  | *    ppmk       [O] Destination for created moniker. | 
|  | * | 
|  | * RETURNS | 
|  | *    Success: S_OK. ppmk contains the created IMoniker object. | 
|  | *    Failure: MK_E_SYNTAX if szURL is not a valid url, or | 
|  | *             E_OUTOFMEMORY if memory allocation fails. | 
|  | */ | 
|  | HRESULT WINAPI CreateURLMoniker(IMoniker *pmkContext, LPCWSTR szURL, IMoniker **ppmk) | 
|  | { | 
|  | return CreateURLMonikerEx(pmkContext, szURL, ppmk, URL_MK_LEGACY); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           IsAsyncMoniker (URLMON.@) | 
|  | */ | 
|  | HRESULT WINAPI IsAsyncMoniker(IMoniker *pmk) | 
|  | { | 
|  | IUnknown *am; | 
|  |  | 
|  | TRACE("(%p)\n", pmk); | 
|  | if(!pmk) | 
|  | return E_INVALIDARG; | 
|  | if(SUCCEEDED(IMoniker_QueryInterface(pmk, &IID_IAsyncMoniker, (void**)&am))) { | 
|  | IUnknown_Release(am); | 
|  | return S_OK; | 
|  | } | 
|  | return S_FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           BindAsyncMoniker (URLMON.@) | 
|  | * | 
|  | * Bind a bind status callback to an asynchronous URL Moniker. | 
|  | * | 
|  | * PARAMS | 
|  | *  pmk           [I] Moniker object to bind status callback to | 
|  | *  grfOpt        [I] Options, seems not used | 
|  | *  pbsc          [I] Status callback to bind | 
|  | *  iidResult     [I] Interface to return | 
|  | *  ppvResult     [O] Resulting asynchronous moniker object | 
|  | * | 
|  | * RETURNS | 
|  | *    Success: S_OK. | 
|  | *    Failure: E_INVALIDARG, if any argument is invalid, or | 
|  | *             E_OUTOFMEMORY if memory allocation fails. | 
|  | */ | 
|  | HRESULT WINAPI BindAsyncMoniker(IMoniker *pmk, DWORD grfOpt, IBindStatusCallback *pbsc, REFIID iidResult, LPVOID *ppvResult) | 
|  | { | 
|  | LPBC pbc = NULL; | 
|  | HRESULT hr = E_INVALIDARG; | 
|  |  | 
|  | TRACE("(%p %08x %p %s %p)\n", pmk, grfOpt, pbsc, debugstr_guid(iidResult), ppvResult); | 
|  |  | 
|  | if (pmk && ppvResult) | 
|  | { | 
|  | *ppvResult = NULL; | 
|  |  | 
|  | hr = CreateAsyncBindCtx(0, pbsc, NULL, &pbc); | 
|  | if (hr == NOERROR) | 
|  | { | 
|  | hr = IMoniker_BindToObject(pmk, pbc, NULL, iidResult, ppvResult); | 
|  | IBindCtx_Release(pbc); | 
|  | } | 
|  | } | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           MkParseDisplayNameEx (URLMON.@) | 
|  | */ | 
|  | HRESULT WINAPI MkParseDisplayNameEx(IBindCtx *pbc, LPCWSTR szDisplayName, ULONG *pchEaten, LPMONIKER *ppmk) | 
|  | { | 
|  | TRACE("(%p %s %p %p)\n", pbc, debugstr_w(szDisplayName), pchEaten, ppmk); | 
|  |  | 
|  | if (!pbc || !szDisplayName || !*szDisplayName || !pchEaten || !ppmk) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | if(is_registered_protocol(szDisplayName)) { | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = CreateURLMoniker(NULL, szDisplayName, ppmk); | 
|  | if(SUCCEEDED(hres)) { | 
|  | *pchEaten = strlenW(szDisplayName); | 
|  | return hres; | 
|  | } | 
|  | } | 
|  |  | 
|  | return MkParseDisplayName(pbc, szDisplayName, pchEaten, ppmk); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           URLDownloadToCacheFileA (URLMON.@) | 
|  | */ | 
|  | HRESULT WINAPI URLDownloadToCacheFileA(LPUNKNOWN lpUnkCaller, LPCSTR szURL, LPSTR szFileName, | 
|  | DWORD dwBufLength, DWORD dwReserved, LPBINDSTATUSCALLBACK pBSC) | 
|  | { | 
|  | LPWSTR url = NULL, file_name = NULL; | 
|  | int len; | 
|  | HRESULT hres; | 
|  |  | 
|  | TRACE("(%p %s %p %d %d %p)\n", lpUnkCaller, debugstr_a(szURL), szFileName, | 
|  | dwBufLength, dwReserved, pBSC); | 
|  |  | 
|  | if(szURL) { | 
|  | len = MultiByteToWideChar(CP_ACP, 0, szURL, -1, NULL, 0); | 
|  | url = heap_alloc(len*sizeof(WCHAR)); | 
|  | MultiByteToWideChar(CP_ACP, 0, szURL, -1, url, len); | 
|  | } | 
|  |  | 
|  | if(szFileName) | 
|  | file_name = heap_alloc(dwBufLength*sizeof(WCHAR)); | 
|  |  | 
|  | hres = URLDownloadToCacheFileW(lpUnkCaller, url, file_name, dwBufLength*sizeof(WCHAR), | 
|  | dwReserved, pBSC); | 
|  |  | 
|  | if(SUCCEEDED(hres) && file_name) | 
|  | WideCharToMultiByte(CP_ACP, 0, file_name, -1, szFileName, dwBufLength, NULL, NULL); | 
|  |  | 
|  | heap_free(url); | 
|  | heap_free(file_name); | 
|  |  | 
|  | return hres; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           URLDownloadToCacheFileW (URLMON.@) | 
|  | */ | 
|  | HRESULT WINAPI URLDownloadToCacheFileW(LPUNKNOWN lpUnkCaller, LPCWSTR szURL, LPWSTR szFileName, | 
|  | DWORD dwBufLength, DWORD dwReserved, LPBINDSTATUSCALLBACK pBSC) | 
|  | { | 
|  | WCHAR cache_path[MAX_PATH + 1]; | 
|  | FILETIME expire, modified; | 
|  | HRESULT hr; | 
|  | LPWSTR ext; | 
|  |  | 
|  | static WCHAR header[] = { | 
|  | 'H','T','T','P','/','1','.','0',' ','2','0','0',' ', | 
|  | 'O','K','\\','r','\\','n','\\','r','\\','n',0 | 
|  | }; | 
|  |  | 
|  | TRACE("(%p, %s, %p, %d, %d, %p)\n", lpUnkCaller, debugstr_w(szURL), | 
|  | szFileName, dwBufLength, dwReserved, pBSC); | 
|  |  | 
|  | if (!szURL || !szFileName) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | ext = PathFindExtensionW(szURL); | 
|  |  | 
|  | if (!CreateUrlCacheEntryW(szURL, 0, ext, cache_path, 0)) | 
|  | return E_FAIL; | 
|  |  | 
|  | hr = URLDownloadToFileW(lpUnkCaller, szURL, cache_path, 0, pBSC); | 
|  | if (FAILED(hr)) | 
|  | return hr; | 
|  |  | 
|  | expire.dwHighDateTime = 0; | 
|  | expire.dwLowDateTime = 0; | 
|  | modified.dwHighDateTime = 0; | 
|  | modified.dwLowDateTime = 0; | 
|  |  | 
|  | if (!CommitUrlCacheEntryW(szURL, cache_path, expire, modified, NORMAL_CACHE_ENTRY, | 
|  | header, sizeof(header), NULL, NULL)) | 
|  | return E_FAIL; | 
|  |  | 
|  | if (strlenW(cache_path) > dwBufLength) | 
|  | return E_OUTOFMEMORY; | 
|  |  | 
|  | lstrcpyW(szFileName, cache_path); | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           HlinkSimpleNavigateToMoniker (URLMON.@) | 
|  | */ | 
|  | HRESULT WINAPI HlinkSimpleNavigateToMoniker(IMoniker *pmkTarget, | 
|  | LPCWSTR szLocation, LPCWSTR szTargetFrameName, IUnknown *pUnk, | 
|  | IBindCtx *pbc, IBindStatusCallback *pbsc, DWORD grfHLNF, DWORD dwReserved) | 
|  | { | 
|  | LPWSTR target; | 
|  | HRESULT hres; | 
|  |  | 
|  | TRACE("\n"); | 
|  |  | 
|  | hres = IMoniker_GetDisplayName(pmkTarget, pbc, 0, &target); | 
|  | if(hres == S_OK) | 
|  | hres = HlinkSimpleNavigateToString( target, szLocation, szTargetFrameName, | 
|  | pUnk, pbc, pbsc, grfHLNF, dwReserved ); | 
|  | CoTaskMemFree(target); | 
|  |  | 
|  | return hres; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           HlinkSimpleNavigateToString (URLMON.@) | 
|  | */ | 
|  | HRESULT WINAPI HlinkSimpleNavigateToString( LPCWSTR szTarget, | 
|  | LPCWSTR szLocation, LPCWSTR szTargetFrameName, IUnknown *pUnk, | 
|  | IBindCtx *pbc, IBindStatusCallback *pbsc, DWORD grfHLNF, DWORD dwReserved) | 
|  | { | 
|  | FIXME("%s %s %s %p %p %p %u %u partial stub\n", debugstr_w( szTarget ), debugstr_w( szLocation ), | 
|  | debugstr_w( szTargetFrameName ), pUnk, pbc, pbsc, grfHLNF, dwReserved); | 
|  |  | 
|  | /* undocumented: 0 means HLNF_OPENINNEWWINDOW*/ | 
|  | if (!grfHLNF) grfHLNF = HLNF_OPENINNEWWINDOW; | 
|  |  | 
|  | if (grfHLNF == HLNF_OPENINNEWWINDOW) | 
|  | { | 
|  | SHELLEXECUTEINFOW sei; | 
|  | static const WCHAR openW[] = { 'o', 'p', 'e', 'n', 0 }; | 
|  |  | 
|  | memset(&sei, 0, sizeof(sei)); | 
|  | sei.cbSize = sizeof(sei); | 
|  | sei.lpVerb = openW; | 
|  | sei.nShow = SW_SHOWNORMAL; | 
|  | sei.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_NO_CONSOLE; | 
|  | sei.lpFile = szTarget; | 
|  |  | 
|  | if (ShellExecuteExW(&sei)) return S_OK; | 
|  | } | 
|  |  | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           HlinkNavigateString (URLMON.@) | 
|  | */ | 
|  | HRESULT WINAPI HlinkNavigateString( IUnknown *pUnk, LPCWSTR szTarget ) | 
|  | { | 
|  | TRACE("%p %s\n", pUnk, debugstr_w( szTarget ) ); | 
|  | return HlinkSimpleNavigateToString( | 
|  | szTarget, NULL, NULL, pUnk, NULL, NULL, 0, 0 ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           GetSoftwareUpdateInfo (URLMON.@) | 
|  | */ | 
|  | HRESULT WINAPI GetSoftwareUpdateInfo( LPCWSTR szDistUnit, LPSOFTDISTINFO psdi ) | 
|  | { | 
|  | FIXME("%s %p\n", debugstr_w(szDistUnit), psdi ); | 
|  | return E_FAIL; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           AsyncInstallDistributionUnit (URLMON.@) | 
|  | */ | 
|  | HRESULT WINAPI AsyncInstallDistributionUnit( LPCWSTR szDistUnit, LPCWSTR szTYPE, | 
|  | LPCWSTR szExt, DWORD dwFileVersionMS, DWORD dwFileVersionLS, | 
|  | LPCWSTR szURL, IBindCtx *pbc, LPVOID pvReserved, DWORD flags ) | 
|  | { | 
|  | FIXME(": stub\n"); | 
|  | return E_NOTIMPL; | 
|  | } |