urlmon: Code clean up.
[wine/testsucceed.git] / dlls / urlmon / umon.c
blob689b3aa8e27dd96f9ae56e94468dc822e9ab4283
1 /*
2 * UrlMon
4 * Copyright 1999 Ulrich Czekalla for Corel Corporation
5 * Copyright 2002 Huw D M Davies for CodeWeavers
6 * Copyright 2005 Jacek Caban for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <stdio.h>
25 #include "urlmon_main.h"
27 #include "winreg.h"
28 #include "winternl.h"
29 #include "wininet.h"
30 #include "shlwapi.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
36 typedef struct {
37 const IMonikerVtbl *lpIMonikerVtbl;
39 LONG ref;
41 LPOLESTR URLName; /* URL string identified by this URLmoniker */
42 } URLMoniker;
44 #define MONIKER_THIS(iface) DEFINE_THIS(URLMoniker, IMoniker, iface)
46 static HRESULT WINAPI URLMoniker_QueryInterface(IMoniker *iface, REFIID riid, void **ppv)
48 URLMoniker *This = MONIKER_THIS(iface);
50 if(!ppv)
51 return E_INVALIDARG;
53 if(IsEqualIID(&IID_IUnknown, riid)) {
54 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
55 *ppv = iface;
56 }else if(IsEqualIID(&IID_IPersist, riid)) {
57 TRACE("(%p)->(IID_IPersist %p)\n", This, ppv);
58 *ppv = iface;
59 }else if(IsEqualIID(&IID_IPersistStream,riid)) {
60 TRACE("(%p)->(IID_IPersistStream %p)\n", This, ppv);
61 *ppv = iface;
62 }else if(IsEqualIID(&IID_IMoniker, riid)) {
63 TRACE("(%p)->(IID_IMoniker %p)\n", This, ppv);
64 *ppv = iface;
65 }else {
66 WARN("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppv);
67 *ppv = NULL;
68 return E_NOINTERFACE;
71 IMoniker_AddRef((IUnknown*)*ppv);
72 return S_OK;
75 static ULONG WINAPI URLMoniker_AddRef(IMoniker *iface)
77 URLMoniker *This = MONIKER_THIS(iface);
78 ULONG refCount = InterlockedIncrement(&This->ref);
80 TRACE("(%p) ref=%u\n",This, refCount);
82 return refCount;
85 static ULONG WINAPI URLMoniker_Release(IMoniker *iface)
87 URLMoniker *This = MONIKER_THIS(iface);
88 ULONG refCount = InterlockedDecrement(&This->ref);
90 TRACE("(%p) ref=%u\n",This, refCount);
92 if (!refCount) {
93 heap_free(This->URLName);
94 heap_free(This);
96 URLMON_UnlockModule();
99 return refCount;
102 static HRESULT WINAPI URLMoniker_GetClassID(IMoniker *iface, CLSID *pClassID)
104 URLMoniker *This = MONIKER_THIS(iface);
106 TRACE("(%p,%p)\n", This, pClassID);
108 if(!pClassID)
109 return E_POINTER;
111 /* Windows always returns CLSID_StdURLMoniker */
112 *pClassID = CLSID_StdURLMoniker;
113 return S_OK;
116 static HRESULT WINAPI URLMoniker_IsDirty(IMoniker *iface)
118 URLMoniker *This = MONIKER_THIS(iface);
120 TRACE("(%p)\n",This);
122 /* Note that the OLE-provided implementations of the IPersistStream::IsDirty
123 method in the OLE-provided moniker interfaces always return S_FALSE because
124 their internal state never changes. */
125 return S_FALSE;
128 static HRESULT WINAPI URLMoniker_Load(IMoniker* iface,IStream* pStm)
130 URLMoniker *This = MONIKER_THIS(iface);
131 HRESULT res;
132 ULONG size;
133 ULONG got;
135 TRACE("(%p,%p)\n",This,pStm);
137 if(!pStm)
138 return E_INVALIDARG;
141 * NOTE
142 * Writes a ULONG containing length of unicode string, followed
143 * by that many unicode characters
145 res = IStream_Read(pStm, &size, sizeof(ULONG), &got);
146 if(SUCCEEDED(res)) {
147 if(got == sizeof(ULONG)) {
148 heap_free(This->URLName);
149 This->URLName = heap_alloc(size);
150 if(!This->URLName)
151 res = E_OUTOFMEMORY;
152 else {
153 res = IStream_Read(pStm, This->URLName, size, NULL);
154 This->URLName[size/sizeof(WCHAR) - 1] = 0;
157 else
158 res = E_FAIL;
161 return res;
164 static HRESULT WINAPI URLMoniker_Save(IMoniker *iface, IStream* pStm, BOOL fClearDirty)
166 URLMoniker *This = MONIKER_THIS(iface);
167 HRESULT res;
168 ULONG size;
170 TRACE("(%p,%p,%d)\n", This, pStm, fClearDirty);
172 if(!pStm)
173 return E_INVALIDARG;
175 size = (strlenW(This->URLName) + 1)*sizeof(WCHAR);
176 res=IStream_Write(pStm,&size,sizeof(ULONG),NULL);
177 if(SUCCEEDED(res))
178 res=IStream_Write(pStm,This->URLName,size,NULL);
180 return res;
184 static HRESULT WINAPI URLMoniker_GetSizeMax(IMoniker* iface, ULARGE_INTEGER *pcbSize)
186 URLMoniker *This = MONIKER_THIS(iface);
188 TRACE("(%p,%p)\n",This,pcbSize);
190 if(!pcbSize)
191 return E_INVALIDARG;
193 pcbSize->QuadPart = sizeof(ULONG) + ((strlenW(This->URLName)+1) * sizeof(WCHAR));
194 return S_OK;
197 static HRESULT WINAPI URLMoniker_BindToObject(IMoniker *iface, IBindCtx* pbc, IMoniker *pmkToLeft,
198 REFIID riid, void **ppv)
200 URLMoniker *This = MONIKER_THIS(iface);
201 IRunningObjectTable *obj_tbl;
202 HRESULT hres;
204 TRACE("(%p)->(%p,%p,%s,%p): stub\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppv);
206 hres = IBindCtx_GetRunningObjectTable(pbc, &obj_tbl);
207 if(SUCCEEDED(hres)) {
208 FIXME("use running object table\n");
209 IRunningObjectTable_Release(obj_tbl);
212 return bind_to_object(iface, This->URLName, pbc, riid, ppv);
215 static HRESULT WINAPI URLMoniker_BindToStorage(IMoniker* iface, IBindCtx* pbc,
216 IMoniker* pmkToLeft, REFIID riid, void **ppvObject)
218 URLMoniker *This = MONIKER_THIS(iface);
220 TRACE("(%p)->(%p %p %s %p)\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppvObject);
222 if(pmkToLeft)
223 FIXME("Unsupported pmkToLeft\n");
225 return bind_to_storage(This->URLName, pbc, riid, ppvObject);
228 static HRESULT WINAPI URLMoniker_Reduce(IMoniker *iface, IBindCtx *pbc,
229 DWORD dwReduceHowFar, IMoniker **ppmkToLeft, IMoniker **ppmkReduced)
231 URLMoniker *This = MONIKER_THIS(iface);
233 TRACE("(%p,%p,%d,%p,%p)\n", This, pbc, dwReduceHowFar, ppmkToLeft, ppmkReduced);
235 if(!ppmkReduced)
236 return E_INVALIDARG;
238 IMoniker_AddRef(iface);
239 *ppmkReduced = iface;
240 return MK_S_REDUCED_TO_SELF;
243 static HRESULT WINAPI URLMoniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight,
244 BOOL fOnlyIfNotGeneric, IMoniker **ppmkComposite)
246 URLMoniker *This = MONIKER_THIS(iface);
247 FIXME("(%p)->(%p,%d,%p): stub\n",This,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
248 return E_NOTIMPL;
251 static HRESULT WINAPI URLMoniker_Enum(IMoniker *iface, BOOL fForward, IEnumMoniker **ppenumMoniker)
253 URLMoniker *This = MONIKER_THIS(iface);
255 TRACE("(%p,%d,%p)\n", This, fForward, ppenumMoniker);
257 if(!ppenumMoniker)
258 return E_INVALIDARG;
260 /* Does not support sub-monikers */
261 *ppenumMoniker = NULL;
262 return S_OK;
265 static HRESULT WINAPI URLMoniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker)
267 URLMoniker *This = MONIKER_THIS(iface);
268 CLSID clsid;
269 LPOLESTR urlPath;
270 IBindCtx* bind;
271 HRESULT res;
273 TRACE("(%p,%p)\n",This, pmkOtherMoniker);
275 if(pmkOtherMoniker==NULL)
276 return E_INVALIDARG;
278 IMoniker_GetClassID(pmkOtherMoniker,&clsid);
280 if(!IsEqualCLSID(&clsid,&CLSID_StdURLMoniker))
281 return S_FALSE;
283 res = CreateBindCtx(0,&bind);
284 if(FAILED(res))
285 return res;
287 res = S_FALSE;
288 if(SUCCEEDED(IMoniker_GetDisplayName(pmkOtherMoniker,bind,NULL,&urlPath))) {
289 int result = lstrcmpiW(urlPath, This->URLName);
290 CoTaskMemFree(urlPath);
291 if(result == 0)
292 res = S_OK;
294 IUnknown_Release(bind);
295 return res;
299 static HRESULT WINAPI URLMoniker_Hash(IMoniker *iface, DWORD *pdwHash)
301 URLMoniker *This = MONIKER_THIS(iface);
302 int h = 0,i,skip,len;
303 int off = 0;
304 LPOLESTR val;
306 TRACE("(%p,%p)\n",This,pdwHash);
308 if(!pdwHash)
309 return E_INVALIDARG;
311 val = This->URLName;
312 len = lstrlenW(val);
314 if(len < 16) {
315 for(i = len ; i > 0; i--) {
316 h = (h * 37) + val[off++];
318 }else {
319 /* only sample some characters */
320 skip = len / 8;
321 for(i = len; i > 0; i -= skip, off += skip) {
322 h = (h * 39) + val[off];
325 *pdwHash = h;
326 return S_OK;
329 static HRESULT WINAPI URLMoniker_IsRunning(IMoniker* iface, IBindCtx* pbc,
330 IMoniker *pmkToLeft, IMoniker *pmkNewlyRunning)
332 URLMoniker *This = MONIKER_THIS(iface);
333 FIXME("(%p)->(%p,%p,%p): stub\n",This,pbc,pmkToLeft,pmkNewlyRunning);
334 return E_NOTIMPL;
337 static HRESULT WINAPI URLMoniker_GetTimeOfLastChange(IMoniker *iface,
338 IBindCtx *pbc, IMoniker *pmkToLeft, FILETIME *pFileTime)
340 URLMoniker *This = MONIKER_THIS(iface);
341 FIXME("(%p)->(%p,%p,%p): stub\n", This, pbc, pmkToLeft, pFileTime);
342 return E_NOTIMPL;
345 static HRESULT WINAPI URLMoniker_Inverse(IMoniker *iface, IMoniker **ppmk)
347 URLMoniker *This = MONIKER_THIS(iface);
348 TRACE("(%p,%p)\n",This,ppmk);
349 return MK_E_NOINVERSE;
352 static HRESULT WINAPI URLMoniker_CommonPrefixWith(IMoniker *iface, IMoniker *pmkOther, IMoniker **ppmkPrefix)
354 URLMoniker *This = MONIKER_THIS(iface);
355 FIXME("(%p)->(%p,%p): stub\n",This,pmkOther,ppmkPrefix);
356 return E_NOTIMPL;
359 static HRESULT WINAPI URLMoniker_RelativePathTo(IMoniker *iface, IMoniker *pmOther, IMoniker **ppmkRelPath)
361 URLMoniker *This = MONIKER_THIS(iface);
362 FIXME("(%p)->(%p,%p): stub\n",This,pmOther,ppmkRelPath);
363 return E_NOTIMPL;
366 static HRESULT WINAPI URLMoniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
367 LPOLESTR *ppszDisplayName)
369 URLMoniker *This = MONIKER_THIS(iface);
370 int len;
372 TRACE("(%p,%p,%p,%p)\n", This, pbc, pmkToLeft, ppszDisplayName);
374 if(!ppszDisplayName)
375 return E_INVALIDARG;
377 /* FIXME: If this is a partial URL, try and get a URL moniker from SZ_URLCONTEXT in the bind context,
378 then look at pmkToLeft to try and complete the URL
380 len = lstrlenW(This->URLName)+1;
381 *ppszDisplayName = CoTaskMemAlloc(len*sizeof(WCHAR));
382 if(!*ppszDisplayName)
383 return E_OUTOFMEMORY;
384 lstrcpyW(*ppszDisplayName, This->URLName);
385 return S_OK;
388 static HRESULT WINAPI URLMoniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
389 LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut)
391 URLMoniker *This = MONIKER_THIS(iface);
392 FIXME("(%p)->(%p,%p,%p,%p,%p): stub\n",This,pbc,pmkToLeft,pszDisplayName,pchEaten,ppmkOut);
393 return E_NOTIMPL;
396 static HRESULT WINAPI URLMoniker_IsSystemMoniker(IMoniker *iface, DWORD *pwdMksys)
398 URLMoniker *This = MONIKER_THIS(iface);
400 TRACE("(%p,%p)\n",This,pwdMksys);
402 if(!pwdMksys)
403 return E_INVALIDARG;
405 *pwdMksys = MKSYS_URLMONIKER;
406 return S_OK;
409 static const IMonikerVtbl URLMonikerVtbl =
411 URLMoniker_QueryInterface,
412 URLMoniker_AddRef,
413 URLMoniker_Release,
414 URLMoniker_GetClassID,
415 URLMoniker_IsDirty,
416 URLMoniker_Load,
417 URLMoniker_Save,
418 URLMoniker_GetSizeMax,
419 URLMoniker_BindToObject,
420 URLMoniker_BindToStorage,
421 URLMoniker_Reduce,
422 URLMoniker_ComposeWith,
423 URLMoniker_Enum,
424 URLMoniker_IsEqual,
425 URLMoniker_Hash,
426 URLMoniker_IsRunning,
427 URLMoniker_GetTimeOfLastChange,
428 URLMoniker_Inverse,
429 URLMoniker_CommonPrefixWith,
430 URLMoniker_RelativePathTo,
431 URLMoniker_GetDisplayName,
432 URLMoniker_ParseDisplayName,
433 URLMoniker_IsSystemMoniker
436 /******************************************************************************
437 * URLMoniker_Construct (local function)
438 *******************************************************************************/
439 static HRESULT URLMoniker_Construct(URLMoniker *This, LPCOLESTR lpszLeftURLName, LPCOLESTR lpszURLName)
441 HRESULT hres;
442 DWORD sizeStr = 0;
444 TRACE("(%p,%s,%s)\n",This,debugstr_w(lpszLeftURLName),debugstr_w(lpszURLName));
446 This->lpIMonikerVtbl = &URLMonikerVtbl;
447 This->ref = 0;
449 This->URLName = heap_alloc(INTERNET_MAX_URL_LENGTH*sizeof(WCHAR));
451 if(lpszLeftURLName)
452 hres = CoInternetCombineUrl(lpszLeftURLName, lpszURLName, URL_FILE_USE_PATHURL,
453 This->URLName, INTERNET_MAX_URL_LENGTH, &sizeStr, 0);
454 else
455 hres = CoInternetParseUrl(lpszURLName, PARSE_CANONICALIZE, URL_FILE_USE_PATHURL,
456 This->URLName, INTERNET_MAX_URL_LENGTH, &sizeStr, 0);
458 if(FAILED(hres)) {
459 heap_free(This->URLName);
460 return hres;
463 URLMON_LockModule();
465 if(sizeStr != INTERNET_MAX_URL_LENGTH)
466 This->URLName = heap_realloc(This->URLName, (sizeStr+1)*sizeof(WCHAR));
468 TRACE("URLName = %s\n", debugstr_w(This->URLName));
470 return S_OK;
473 /***********************************************************************
474 * CreateURLMonikerEx (URLMON.@)
476 * Create a url moniker.
478 * PARAMS
479 * pmkContext [I] Context
480 * szURL [I] Url to create the moniker for
481 * ppmk [O] Destination for created moniker.
482 * dwFlags [I] Flags.
484 * RETURNS
485 * Success: S_OK. ppmk contains the created IMoniker object.
486 * Failure: MK_E_SYNTAX if szURL is not a valid url, or
487 * E_OUTOFMEMORY if memory allocation fails.
489 HRESULT WINAPI CreateURLMonikerEx(IMoniker *pmkContext, LPCWSTR szURL, IMoniker **ppmk, DWORD dwFlags)
491 URLMoniker *obj;
492 HRESULT hres;
493 LPOLESTR lefturl = NULL;
495 TRACE("(%p, %s, %p, %08x)\n", pmkContext, debugstr_w(szURL), ppmk, dwFlags);
497 if (dwFlags & URL_MK_UNIFORM) FIXME("ignoring flag URL_MK_UNIFORM\n");
499 if(!(obj = heap_alloc(sizeof(*obj))))
500 return E_OUTOFMEMORY;
502 if(pmkContext) {
503 IBindCtx* bind;
504 DWORD dwMksys = 0;
505 IMoniker_IsSystemMoniker(pmkContext, &dwMksys);
506 if(dwMksys == MKSYS_URLMONIKER && SUCCEEDED(CreateBindCtx(0, &bind))) {
507 IMoniker_GetDisplayName(pmkContext, bind, NULL, &lefturl);
508 TRACE("lefturl = %s\n", debugstr_w(lefturl));
509 IBindCtx_Release(bind);
513 hres = URLMoniker_Construct(obj, lefturl, szURL);
514 CoTaskMemFree(lefturl);
515 if(SUCCEEDED(hres))
516 hres = URLMoniker_QueryInterface((IMoniker*)obj, &IID_IMoniker, (void**)ppmk);
517 else
518 heap_free(obj);
519 return hres;
522 /**********************************************************************
523 * CreateURLMoniker (URLMON.@)
525 * Create a url moniker.
527 * PARAMS
528 * pmkContext [I] Context
529 * szURL [I] Url to create the moniker for
530 * ppmk [O] Destination for created moniker.
532 * RETURNS
533 * Success: S_OK. ppmk contains the created IMoniker object.
534 * Failure: MK_E_SYNTAX if szURL is not a valid url, or
535 * E_OUTOFMEMORY if memory allocation fails.
537 HRESULT WINAPI CreateURLMoniker(IMoniker *pmkContext, LPCWSTR szURL, IMoniker **ppmk)
539 return CreateURLMonikerEx(pmkContext, szURL, ppmk, URL_MK_LEGACY);
542 /***********************************************************************
543 * IsAsyncMoniker (URLMON.@)
545 HRESULT WINAPI IsAsyncMoniker(IMoniker *pmk)
547 IUnknown *am;
549 TRACE("(%p)\n", pmk);
550 if(!pmk)
551 return E_INVALIDARG;
552 if(SUCCEEDED(IMoniker_QueryInterface(pmk, &IID_IAsyncMoniker, (void**)&am))) {
553 IUnknown_Release(am);
554 return S_OK;
556 return S_FALSE;
559 /***********************************************************************
560 * BindAsyncMoniker (URLMON.@)
562 * Bind a bind status callback to an asynchronous URL Moniker.
564 * PARAMS
565 * pmk [I] Moniker object to bind status callback to
566 * grfOpt [I] Options, seems not used
567 * pbsc [I] Status callback to bind
568 * iidResult [I] Interface to return
569 * ppvResult [O] Resulting asynchronous moniker object
571 * RETURNS
572 * Success: S_OK.
573 * Failure: E_INVALIDARG, if any argument is invalid, or
574 * E_OUTOFMEMORY if memory allocation fails.
576 HRESULT WINAPI BindAsyncMoniker(IMoniker *pmk, DWORD grfOpt, IBindStatusCallback *pbsc, REFIID iidResult, LPVOID *ppvResult)
578 LPBC pbc = NULL;
579 HRESULT hr = E_INVALIDARG;
581 TRACE("(%p %08x %p %s %p)\n", pmk, grfOpt, pbsc, debugstr_guid(iidResult), ppvResult);
583 if (pmk && ppvResult)
585 *ppvResult = NULL;
587 hr = CreateAsyncBindCtx(0, pbsc, NULL, &pbc);
588 if (hr == NOERROR)
590 hr = IMoniker_BindToObject(pmk, pbc, NULL, iidResult, ppvResult);
591 IBindCtx_Release(pbc);
594 return hr;
597 /***********************************************************************
598 * MkParseDisplayNameEx (URLMON.@)
600 HRESULT WINAPI MkParseDisplayNameEx(IBindCtx *pbc, LPCWSTR szDisplayName, ULONG *pchEaten, LPMONIKER *ppmk)
602 TRACE("(%p %s %p %p)\n", pbc, debugstr_w(szDisplayName), pchEaten, ppmk);
604 if(is_registered_protocol(szDisplayName)) {
605 HRESULT hres;
607 hres = CreateURLMoniker(NULL, szDisplayName, ppmk);
608 if(SUCCEEDED(hres)) {
609 *pchEaten = strlenW(szDisplayName);
610 return hres;
614 return MkParseDisplayName(pbc, szDisplayName, pchEaten, ppmk);
618 /***********************************************************************
619 * URLDownloadToCacheFileA (URLMON.@)
621 HRESULT WINAPI URLDownloadToCacheFileA(LPUNKNOWN lpUnkCaller, LPCSTR szURL, LPSTR szFileName,
622 DWORD dwBufLength, DWORD dwReserved, LPBINDSTATUSCALLBACK pBSC)
624 LPWSTR url = NULL, file_name = NULL;
625 int len;
626 HRESULT hres;
628 TRACE("(%p %s %p %d %d %p)\n", lpUnkCaller, debugstr_a(szURL), szFileName,
629 dwBufLength, dwReserved, pBSC);
631 if(szURL) {
632 len = MultiByteToWideChar(CP_ACP, 0, szURL, -1, NULL, 0);
633 url = heap_alloc(len*sizeof(WCHAR));
634 MultiByteToWideChar(CP_ACP, 0, szURL, -1, url, len);
637 if(szFileName)
638 file_name = heap_alloc(dwBufLength*sizeof(WCHAR));
640 hres = URLDownloadToCacheFileW(lpUnkCaller, url, file_name, dwBufLength*sizeof(WCHAR),
641 dwReserved, pBSC);
643 if(SUCCEEDED(hres) && file_name)
644 WideCharToMultiByte(CP_ACP, 0, file_name, -1, szFileName, dwBufLength, NULL, NULL);
646 heap_free(url);
647 heap_free(file_name);
649 return hres;
652 /***********************************************************************
653 * URLDownloadToCacheFileW (URLMON.@)
655 HRESULT WINAPI URLDownloadToCacheFileW(LPUNKNOWN lpUnkCaller, LPCWSTR szURL, LPWSTR szFileName,
656 DWORD dwBufLength, DWORD dwReserved, LPBINDSTATUSCALLBACK pBSC)
658 WCHAR cache_path[MAX_PATH + 1];
659 FILETIME expire, modified;
660 HRESULT hr;
661 LPWSTR ext;
663 static WCHAR header[] = {
664 'H','T','T','P','/','1','.','0',' ','2','0','0',' ',
665 'O','K','\\','r','\\','n','\\','r','\\','n',0
668 TRACE("(%p, %s, %p, %d, %d, %p)\n", lpUnkCaller, debugstr_w(szURL),
669 szFileName, dwBufLength, dwReserved, pBSC);
671 if (!szURL || !szFileName)
672 return E_INVALIDARG;
674 ext = PathFindExtensionW(szURL);
676 if (!CreateUrlCacheEntryW(szURL, 0, ext, cache_path, 0))
677 return E_FAIL;
679 hr = URLDownloadToFileW(lpUnkCaller, szURL, cache_path, 0, pBSC);
680 if (FAILED(hr))
681 return hr;
683 expire.dwHighDateTime = 0;
684 expire.dwLowDateTime = 0;
685 modified.dwHighDateTime = 0;
686 modified.dwLowDateTime = 0;
688 if (!CommitUrlCacheEntryW(szURL, cache_path, expire, modified, NORMAL_CACHE_ENTRY,
689 header, sizeof(header), NULL, NULL))
690 return E_FAIL;
692 if (strlenW(cache_path) > dwBufLength)
693 return E_OUTOFMEMORY;
695 lstrcpyW(szFileName, cache_path);
697 return S_OK;
700 /***********************************************************************
701 * HlinkSimpleNavigateToMoniker (URLMON.@)
703 HRESULT WINAPI HlinkSimpleNavigateToMoniker(IMoniker *pmkTarget,
704 LPCWSTR szLocation, LPCWSTR szTargetFrameName, IUnknown *pUnk,
705 IBindCtx *pbc, IBindStatusCallback *pbsc, DWORD grfHLNF, DWORD dwReserved)
707 FIXME("stub\n");
708 return E_NOTIMPL;
711 /***********************************************************************
712 * HlinkSimpleNavigateToString (URLMON.@)
714 HRESULT WINAPI HlinkSimpleNavigateToString( LPCWSTR szTarget,
715 LPCWSTR szLocation, LPCWSTR szTargetFrameName, IUnknown *pUnk,
716 IBindCtx *pbc, IBindStatusCallback *pbsc, DWORD grfHLNF, DWORD dwReserved)
718 FIXME("%s\n", debugstr_w( szTarget ) );
719 return E_NOTIMPL;
722 /***********************************************************************
723 * HlinkNavigateString (URLMON.@)
725 HRESULT WINAPI HlinkNavigateString( IUnknown *pUnk, LPCWSTR szTarget )
727 TRACE("%p %s\n", pUnk, debugstr_w( szTarget ) );
728 return HlinkSimpleNavigateToString(
729 szTarget, NULL, NULL, pUnk, NULL, NULL, 0, 0 );
732 /***********************************************************************
733 * GetSoftwareUpdateInfo (URLMON.@)
735 HRESULT WINAPI GetSoftwareUpdateInfo( LPCWSTR szDistUnit, LPSOFTDISTINFO psdi )
737 FIXME("%s %p\n", debugstr_w(szDistUnit), psdi );
738 return E_FAIL;