| /* |
| * 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; |
| } |
| |
| IUnknown_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)) { |
| hres = IRunningObjectTable_IsRunning(obj_tbl, &This->IMoniker_iface); |
| if(hres == S_OK) { |
| IUnknown *unk = NULL; |
| |
| TRACE("Found in running object table\n"); |
| |
| hres = IRunningObjectTable_GetObject(obj_tbl, &This->IMoniker_iface, &unk); |
| if(SUCCEEDED(hres)) { |
| hres = IUnknown_QueryInterface(unk, riid, ppv); |
| IUnknown_Release(unk); |
| } |
| |
| IRunningObjectTable_Release(obj_tbl); |
| return hres; |
| } |
| |
| 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; |
| } |
| IBindCtx_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; |
| } |