msxml3: Add a function to validate a tree against a schema cache.
[wine] / dlls / urlmon / umon.c
1 /*
2  * UrlMon
3  *
4  * Copyright 1999 Ulrich Czekalla for Corel Corporation
5  * Copyright 2002 Huw D M Davies for CodeWeavers
6  * Copyright 2005 Jacek Caban for CodeWeavers
7  *
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.
12  *
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.
17  *
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
21  */
22
23 #include "urlmon_main.h"
24
25 #include "winreg.h"
26 #include "shlwapi.h"
27 #include "hlink.h"
28 #include "shellapi.h"
29
30 #include "wine/debug.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
33
34 typedef struct {
35     const IMonikerVtbl *lpIMonikerVtbl;
36
37     LONG ref;
38
39     LPOLESTR URLName; /* URL string identified by this URLmoniker */
40 } URLMoniker;
41
42 #define MONIKER_THIS(iface) DEFINE_THIS(URLMoniker, IMoniker, iface)
43
44 static HRESULT WINAPI URLMoniker_QueryInterface(IMoniker *iface, REFIID riid, void **ppv)
45 {
46     URLMoniker *This = MONIKER_THIS(iface);
47
48     if(!ppv)
49         return E_INVALIDARG;
50
51     if(IsEqualIID(&IID_IUnknown, riid)) {
52         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
53         *ppv = iface;
54     }else if(IsEqualIID(&IID_IPersist, riid)) {
55         TRACE("(%p)->(IID_IPersist %p)\n", This, ppv);
56         *ppv = iface;
57     }else if(IsEqualIID(&IID_IPersistStream,riid)) {
58         TRACE("(%p)->(IID_IPersistStream %p)\n", This, ppv);
59         *ppv = iface;
60     }else if(IsEqualIID(&IID_IMoniker, riid)) {
61         TRACE("(%p)->(IID_IMoniker %p)\n", This, ppv);
62         *ppv = iface;
63     }else if(IsEqualIID(&IID_IAsyncMoniker, riid)) {
64         TRACE("(%p)->(IID_IAsyncMoniker %p)\n", This, ppv);
65         *ppv = iface;
66     }else {
67         WARN("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppv);
68         *ppv = NULL;
69         return E_NOINTERFACE;
70     }
71
72     IMoniker_AddRef((IUnknown*)*ppv);
73     return S_OK;
74 }
75
76 static ULONG WINAPI URLMoniker_AddRef(IMoniker *iface)
77 {
78     URLMoniker *This = MONIKER_THIS(iface);
79     ULONG refCount = InterlockedIncrement(&This->ref);
80
81     TRACE("(%p) ref=%u\n",This, refCount);
82
83     return refCount;
84 }
85
86 static ULONG WINAPI URLMoniker_Release(IMoniker *iface)
87 {
88     URLMoniker *This = MONIKER_THIS(iface);
89     ULONG refCount = InterlockedDecrement(&This->ref);
90
91     TRACE("(%p) ref=%u\n",This, refCount);
92
93     if (!refCount) {
94         heap_free(This->URLName);
95         heap_free(This);
96
97         URLMON_UnlockModule();
98     }
99
100     return refCount;
101 }
102
103 static HRESULT WINAPI URLMoniker_GetClassID(IMoniker *iface, CLSID *pClassID)
104 {
105     URLMoniker *This = MONIKER_THIS(iface);
106
107     TRACE("(%p,%p)\n", This, pClassID);
108
109     if(!pClassID)
110         return E_POINTER;
111
112     /* Windows always returns CLSID_StdURLMoniker */
113     *pClassID = CLSID_StdURLMoniker;
114     return S_OK;
115 }
116
117 static HRESULT WINAPI URLMoniker_IsDirty(IMoniker *iface)
118 {
119     URLMoniker *This = MONIKER_THIS(iface);
120
121     TRACE("(%p)\n",This);
122
123     /* Note that the OLE-provided implementations of the IPersistStream::IsDirty
124        method in the OLE-provided moniker interfaces always return S_FALSE because
125        their internal state never changes. */
126     return S_FALSE;
127 }
128
129 static HRESULT WINAPI URLMoniker_Load(IMoniker* iface,IStream* pStm)
130 {
131     URLMoniker *This = MONIKER_THIS(iface);
132     HRESULT res;
133     ULONG size;
134     ULONG got;
135
136     TRACE("(%p,%p)\n",This,pStm);
137
138     if(!pStm)
139         return E_INVALIDARG;
140
141     /*
142      * NOTE
143      *  Writes a ULONG containing length of unicode string, followed
144      *  by that many unicode characters
145      */
146     res = IStream_Read(pStm, &size, sizeof(ULONG), &got);
147     if(SUCCEEDED(res)) {
148         if(got == sizeof(ULONG)) {
149             heap_free(This->URLName);
150             This->URLName = heap_alloc(size);
151             if(!This->URLName)
152                 res = E_OUTOFMEMORY;
153             else {
154                 res = IStream_Read(pStm, This->URLName, size, NULL);
155                 This->URLName[size/sizeof(WCHAR) - 1] = 0;
156             }
157         }
158         else
159             res = E_FAIL;
160     }
161
162     return res;
163 }
164
165 static HRESULT WINAPI URLMoniker_Save(IMoniker *iface, IStream* pStm, BOOL fClearDirty)
166 {
167     URLMoniker *This = MONIKER_THIS(iface);
168     HRESULT res;
169     ULONG size;
170
171     TRACE("(%p,%p,%d)\n", This, pStm, fClearDirty);
172
173     if(!pStm)
174         return E_INVALIDARG;
175
176     size = (strlenW(This->URLName) + 1)*sizeof(WCHAR);
177     res=IStream_Write(pStm,&size,sizeof(ULONG),NULL);
178     if(SUCCEEDED(res))
179         res=IStream_Write(pStm,This->URLName,size,NULL);
180
181     return res;
182
183 }
184
185 static HRESULT WINAPI URLMoniker_GetSizeMax(IMoniker* iface, ULARGE_INTEGER *pcbSize)
186 {
187     URLMoniker *This = MONIKER_THIS(iface);
188
189     TRACE("(%p,%p)\n",This,pcbSize);
190
191     if(!pcbSize)
192         return E_INVALIDARG;
193
194     pcbSize->QuadPart = sizeof(ULONG) + ((strlenW(This->URLName)+1) * sizeof(WCHAR));
195     return S_OK;
196 }
197
198 static HRESULT WINAPI URLMoniker_BindToObject(IMoniker *iface, IBindCtx* pbc, IMoniker *pmkToLeft,
199         REFIID riid, void **ppv)
200 {
201     URLMoniker *This = MONIKER_THIS(iface);
202     IRunningObjectTable *obj_tbl;
203     HRESULT hres;
204
205     TRACE("(%p)->(%p,%p,%s,%p): stub\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppv);
206
207     hres = IBindCtx_GetRunningObjectTable(pbc, &obj_tbl);
208     if(SUCCEEDED(hres)) {
209         FIXME("use running object table\n");
210         IRunningObjectTable_Release(obj_tbl);
211     }
212
213     return bind_to_object(iface, This->URLName, pbc, riid, ppv);
214 }
215
216 static HRESULT WINAPI URLMoniker_BindToStorage(IMoniker* iface, IBindCtx* pbc,
217         IMoniker* pmkToLeft, REFIID riid, void **ppvObject)
218 {
219     URLMoniker *This = MONIKER_THIS(iface);
220
221     TRACE("(%p)->(%p %p %s %p)\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppvObject);
222
223     if(pmkToLeft)
224         FIXME("Unsupported pmkToLeft\n");
225
226     return bind_to_storage(This->URLName, pbc, riid, ppvObject);
227 }
228
229 static HRESULT WINAPI URLMoniker_Reduce(IMoniker *iface, IBindCtx *pbc,
230         DWORD dwReduceHowFar, IMoniker **ppmkToLeft, IMoniker **ppmkReduced)
231 {
232     URLMoniker *This = MONIKER_THIS(iface);
233     
234     TRACE("(%p,%p,%d,%p,%p)\n", This, pbc, dwReduceHowFar, ppmkToLeft, ppmkReduced);
235
236     if(!ppmkReduced)
237         return E_INVALIDARG;
238
239     IMoniker_AddRef(iface);
240     *ppmkReduced = iface;
241     return MK_S_REDUCED_TO_SELF;
242 }
243
244 static HRESULT WINAPI URLMoniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight,
245         BOOL fOnlyIfNotGeneric, IMoniker **ppmkComposite)
246 {
247     URLMoniker *This = MONIKER_THIS(iface);
248     FIXME("(%p)->(%p,%d,%p): stub\n",This,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
249     return E_NOTIMPL;
250 }
251
252 static HRESULT WINAPI URLMoniker_Enum(IMoniker *iface, BOOL fForward, IEnumMoniker **ppenumMoniker)
253 {
254     URLMoniker *This = MONIKER_THIS(iface);
255
256     TRACE("(%p,%d,%p)\n", This, fForward, ppenumMoniker);
257
258     if(!ppenumMoniker)
259         return E_INVALIDARG;
260
261     /* Does not support sub-monikers */
262     *ppenumMoniker = NULL;
263     return S_OK;
264 }
265
266 static HRESULT WINAPI URLMoniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker)
267 {
268     URLMoniker *This = MONIKER_THIS(iface);
269     CLSID clsid;
270     LPOLESTR urlPath;
271     IBindCtx* bind;
272     HRESULT res;
273
274     TRACE("(%p,%p)\n",This, pmkOtherMoniker);
275
276     if(pmkOtherMoniker==NULL)
277         return E_INVALIDARG;
278
279     IMoniker_GetClassID(pmkOtherMoniker,&clsid);
280
281     if(!IsEqualCLSID(&clsid,&CLSID_StdURLMoniker))
282         return S_FALSE;
283
284     res = CreateBindCtx(0,&bind);
285     if(FAILED(res))
286         return res;
287
288     res = S_FALSE;
289     if(SUCCEEDED(IMoniker_GetDisplayName(pmkOtherMoniker,bind,NULL,&urlPath))) {
290         int result = lstrcmpiW(urlPath, This->URLName);
291         CoTaskMemFree(urlPath);
292         if(result == 0)
293             res = S_OK;
294     }
295     IUnknown_Release(bind);
296     return res;
297 }
298
299
300 static HRESULT WINAPI URLMoniker_Hash(IMoniker *iface, DWORD *pdwHash)
301 {
302     URLMoniker *This = MONIKER_THIS(iface);
303     int  h = 0,i,skip,len;
304     int  off = 0;
305     LPOLESTR val;
306
307     TRACE("(%p,%p)\n",This,pdwHash);
308
309     if(!pdwHash)
310         return E_INVALIDARG;
311
312     val = This->URLName;
313     len = lstrlenW(val);
314
315     if(len < 16) {
316         for(i = len ; i > 0; i--) {
317             h = (h * 37) + val[off++];
318         }
319     }else {
320         /* only sample some characters */
321         skip = len / 8;
322         for(i = len; i > 0; i -= skip, off += skip) {
323             h = (h * 39) + val[off];
324         }
325     }
326     *pdwHash = h;
327     return S_OK;
328 }
329
330 static HRESULT WINAPI URLMoniker_IsRunning(IMoniker* iface, IBindCtx* pbc,
331         IMoniker *pmkToLeft, IMoniker *pmkNewlyRunning)
332 {
333     URLMoniker *This = MONIKER_THIS(iface);
334     FIXME("(%p)->(%p,%p,%p): stub\n",This,pbc,pmkToLeft,pmkNewlyRunning);
335     return E_NOTIMPL;
336 }
337
338 static HRESULT WINAPI URLMoniker_GetTimeOfLastChange(IMoniker *iface,
339         IBindCtx *pbc, IMoniker *pmkToLeft, FILETIME *pFileTime)
340 {
341     URLMoniker *This = MONIKER_THIS(iface);
342     FIXME("(%p)->(%p,%p,%p): stub\n", This, pbc, pmkToLeft, pFileTime);
343     return E_NOTIMPL;
344 }
345
346 static HRESULT WINAPI URLMoniker_Inverse(IMoniker *iface, IMoniker **ppmk)
347 {
348     URLMoniker *This = MONIKER_THIS(iface);
349     TRACE("(%p,%p)\n",This,ppmk);
350     return MK_E_NOINVERSE;
351 }
352
353 static HRESULT WINAPI URLMoniker_CommonPrefixWith(IMoniker *iface, IMoniker *pmkOther, IMoniker **ppmkPrefix)
354 {
355     URLMoniker *This = MONIKER_THIS(iface);
356     FIXME("(%p)->(%p,%p): stub\n",This,pmkOther,ppmkPrefix);
357     return E_NOTIMPL;
358 }
359
360 static HRESULT WINAPI URLMoniker_RelativePathTo(IMoniker *iface, IMoniker *pmOther, IMoniker **ppmkRelPath)
361 {
362     URLMoniker *This = MONIKER_THIS(iface);
363     FIXME("(%p)->(%p,%p): stub\n",This,pmOther,ppmkRelPath);
364     return E_NOTIMPL;
365 }
366
367 static HRESULT WINAPI URLMoniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
368         LPOLESTR *ppszDisplayName)
369 {
370     URLMoniker *This = MONIKER_THIS(iface);
371     int len;
372     
373     TRACE("(%p,%p,%p,%p)\n", This, pbc, pmkToLeft, ppszDisplayName);
374     
375     if(!ppszDisplayName)
376         return E_INVALIDARG;
377
378     if(!This->URLName)
379         return E_OUTOFMEMORY;
380
381     /* FIXME: If this is a partial URL, try and get a URL moniker from SZ_URLCONTEXT in the bind context,
382         then look at pmkToLeft to try and complete the URL
383     */
384     len = lstrlenW(This->URLName)+1;
385     *ppszDisplayName = CoTaskMemAlloc(len*sizeof(WCHAR));
386     if(!*ppszDisplayName)
387         return E_OUTOFMEMORY;
388     lstrcpyW(*ppszDisplayName, This->URLName);
389     return S_OK;
390 }
391
392 static HRESULT WINAPI URLMoniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
393         LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut)
394 {
395     URLMoniker *This = MONIKER_THIS(iface);
396     FIXME("(%p)->(%p,%p,%p,%p,%p): stub\n",This,pbc,pmkToLeft,pszDisplayName,pchEaten,ppmkOut);
397     return E_NOTIMPL;
398 }
399
400 static HRESULT WINAPI URLMoniker_IsSystemMoniker(IMoniker *iface, DWORD *pwdMksys)
401 {
402     URLMoniker *This = MONIKER_THIS(iface);
403
404     TRACE("(%p,%p)\n",This,pwdMksys);
405
406     if(!pwdMksys)
407         return E_INVALIDARG;
408
409     *pwdMksys = MKSYS_URLMONIKER;
410     return S_OK;
411 }
412
413 static const IMonikerVtbl URLMonikerVtbl =
414 {
415     URLMoniker_QueryInterface,
416     URLMoniker_AddRef,
417     URLMoniker_Release,
418     URLMoniker_GetClassID,
419     URLMoniker_IsDirty,
420     URLMoniker_Load,
421     URLMoniker_Save,
422     URLMoniker_GetSizeMax,
423     URLMoniker_BindToObject,
424     URLMoniker_BindToStorage,
425     URLMoniker_Reduce,
426     URLMoniker_ComposeWith,
427     URLMoniker_Enum,
428     URLMoniker_IsEqual,
429     URLMoniker_Hash,
430     URLMoniker_IsRunning,
431     URLMoniker_GetTimeOfLastChange,
432     URLMoniker_Inverse,
433     URLMoniker_CommonPrefixWith,
434     URLMoniker_RelativePathTo,
435     URLMoniker_GetDisplayName,
436     URLMoniker_ParseDisplayName,
437     URLMoniker_IsSystemMoniker
438 };
439
440 static URLMoniker *alloc_moniker(void)
441 {
442     URLMoniker *ret;
443
444     ret = heap_alloc(sizeof(URLMoniker));
445     if(!ret)
446         return NULL;
447
448     ret->lpIMonikerVtbl = &URLMonikerVtbl;
449     ret->ref = 1;
450     ret->URLName = NULL;
451
452     return ret;
453 }
454
455 static HRESULT URLMoniker_Init(URLMoniker *This, LPCOLESTR lpszLeftURLName, LPCOLESTR lpszURLName)
456 {
457     HRESULT hres;
458     DWORD sizeStr = 0;
459
460     TRACE("(%p,%s,%s)\n",This,debugstr_w(lpszLeftURLName),debugstr_w(lpszURLName));
461
462     This->URLName = heap_alloc(INTERNET_MAX_URL_LENGTH*sizeof(WCHAR));
463
464     if(lpszLeftURLName)
465         hres = CoInternetCombineUrl(lpszLeftURLName, lpszURLName, URL_FILE_USE_PATHURL,
466                 This->URLName, INTERNET_MAX_URL_LENGTH, &sizeStr, 0);
467     else
468         hres = CoInternetParseUrl(lpszURLName, PARSE_CANONICALIZE, URL_FILE_USE_PATHURL,
469                 This->URLName, INTERNET_MAX_URL_LENGTH, &sizeStr, 0);
470
471     if(FAILED(hres)) {
472         heap_free(This->URLName);
473         return hres;
474     }
475
476     URLMON_LockModule();
477
478     if(sizeStr != INTERNET_MAX_URL_LENGTH)
479         This->URLName = heap_realloc(This->URLName, (sizeStr+1)*sizeof(WCHAR));
480
481     TRACE("URLName = %s\n", debugstr_w(This->URLName));
482
483     return S_OK;
484 }
485
486 HRESULT StdURLMoniker_Construct(IUnknown *outer, void **ppv)
487 {
488     TRACE("(%p %p)\n", outer, ppv);
489
490     *ppv = alloc_moniker();
491     return *ppv ? S_OK : E_OUTOFMEMORY;
492 }
493
494 /***********************************************************************
495  *           CreateURLMonikerEx (URLMON.@)
496  *
497  * Create a url moniker.
498  *
499  * PARAMS
500  *    pmkContext [I] Context
501  *    szURL      [I] Url to create the moniker for
502  *    ppmk       [O] Destination for created moniker.
503  *    dwFlags    [I] Flags.
504  *
505  * RETURNS
506  *    Success: S_OK. ppmk contains the created IMoniker object.
507  *    Failure: MK_E_SYNTAX if szURL is not a valid url, or
508  *             E_OUTOFMEMORY if memory allocation fails.
509  */
510 HRESULT WINAPI CreateURLMonikerEx(IMoniker *pmkContext, LPCWSTR szURL, IMoniker **ppmk, DWORD dwFlags)
511 {
512     URLMoniker *obj;
513     HRESULT hres;
514     LPOLESTR lefturl = NULL;
515
516     TRACE("(%p, %s, %p, %08x)\n", pmkContext, debugstr_w(szURL), ppmk, dwFlags);
517
518     if (ppmk)
519         *ppmk = NULL;
520
521     if (!szURL || !ppmk)
522         return E_INVALIDARG;
523
524     if (dwFlags & URL_MK_UNIFORM) FIXME("ignoring flag URL_MK_UNIFORM\n");
525
526     if(!(obj = alloc_moniker()))
527         return E_OUTOFMEMORY;
528
529     if(pmkContext) {
530         IBindCtx* bind;
531         DWORD dwMksys = 0;
532         IMoniker_IsSystemMoniker(pmkContext, &dwMksys);
533         if(dwMksys == MKSYS_URLMONIKER && SUCCEEDED(CreateBindCtx(0, &bind))) {
534             IMoniker_GetDisplayName(pmkContext, bind, NULL, &lefturl);
535             TRACE("lefturl = %s\n", debugstr_w(lefturl));
536             IBindCtx_Release(bind);
537         }
538     }
539         
540     hres = URLMoniker_Init(obj, lefturl, szURL);
541     CoTaskMemFree(lefturl);
542     if(SUCCEEDED(hres))
543         hres = URLMoniker_QueryInterface((IMoniker*)obj, &IID_IMoniker, (void**)ppmk);
544     IMoniker_Release((IMoniker*)obj);
545     return hres;
546 }
547
548 /**********************************************************************
549  *           CreateURLMoniker (URLMON.@)
550  *
551  * Create a url moniker.
552  *
553  * PARAMS
554  *    pmkContext [I] Context
555  *    szURL      [I] Url to create the moniker for
556  *    ppmk       [O] Destination for created moniker.
557  *
558  * RETURNS
559  *    Success: S_OK. ppmk contains the created IMoniker object.
560  *    Failure: MK_E_SYNTAX if szURL is not a valid url, or
561  *             E_OUTOFMEMORY if memory allocation fails.
562  */
563 HRESULT WINAPI CreateURLMoniker(IMoniker *pmkContext, LPCWSTR szURL, IMoniker **ppmk)
564 {
565     return CreateURLMonikerEx(pmkContext, szURL, ppmk, URL_MK_LEGACY);
566 }
567
568 /***********************************************************************
569  *           IsAsyncMoniker (URLMON.@)
570  */
571 HRESULT WINAPI IsAsyncMoniker(IMoniker *pmk)
572 {
573     IUnknown *am;
574     
575     TRACE("(%p)\n", pmk);
576     if(!pmk)
577         return E_INVALIDARG;
578     if(SUCCEEDED(IMoniker_QueryInterface(pmk, &IID_IAsyncMoniker, (void**)&am))) {
579         IUnknown_Release(am);
580         return S_OK;
581     }
582     return S_FALSE;
583 }
584
585 /***********************************************************************
586  *           BindAsyncMoniker (URLMON.@)
587  *
588  * Bind a bind status callback to an asynchronous URL Moniker.
589  *
590  * PARAMS
591  *  pmk           [I] Moniker object to bind status callback to
592  *  grfOpt        [I] Options, seems not used
593  *  pbsc          [I] Status callback to bind
594  *  iidResult     [I] Interface to return
595  *  ppvResult     [O] Resulting asynchronous moniker object
596  *
597  * RETURNS
598  *    Success: S_OK.
599  *    Failure: E_INVALIDARG, if any argument is invalid, or
600  *             E_OUTOFMEMORY if memory allocation fails.
601  */
602 HRESULT WINAPI BindAsyncMoniker(IMoniker *pmk, DWORD grfOpt, IBindStatusCallback *pbsc, REFIID iidResult, LPVOID *ppvResult)
603 {
604     LPBC pbc = NULL;
605     HRESULT hr = E_INVALIDARG;
606
607     TRACE("(%p %08x %p %s %p)\n", pmk, grfOpt, pbsc, debugstr_guid(iidResult), ppvResult);
608
609     if (pmk && ppvResult)
610     {
611         *ppvResult = NULL;
612
613         hr = CreateAsyncBindCtx(0, pbsc, NULL, &pbc);
614         if (hr == NOERROR)
615         {
616             hr = IMoniker_BindToObject(pmk, pbc, NULL, iidResult, ppvResult);
617             IBindCtx_Release(pbc);
618         }
619     }
620     return hr;
621 }
622
623 /***********************************************************************
624  *           MkParseDisplayNameEx (URLMON.@)
625  */
626 HRESULT WINAPI MkParseDisplayNameEx(IBindCtx *pbc, LPCWSTR szDisplayName, ULONG *pchEaten, LPMONIKER *ppmk)
627 {
628     TRACE("(%p %s %p %p)\n", pbc, debugstr_w(szDisplayName), pchEaten, ppmk);
629
630     if (!pbc || !szDisplayName || !*szDisplayName || !pchEaten || !ppmk)
631         return E_INVALIDARG;
632
633     if(is_registered_protocol(szDisplayName)) {
634         HRESULT hres;
635
636         hres = CreateURLMoniker(NULL, szDisplayName, ppmk);
637         if(SUCCEEDED(hres)) {
638             *pchEaten = strlenW(szDisplayName);
639             return hres;
640         }
641     }
642
643     return MkParseDisplayName(pbc, szDisplayName, pchEaten, ppmk);
644 }
645
646
647 /***********************************************************************
648  *           URLDownloadToCacheFileA (URLMON.@)
649  */
650 HRESULT WINAPI URLDownloadToCacheFileA(LPUNKNOWN lpUnkCaller, LPCSTR szURL, LPSTR szFileName,
651         DWORD dwBufLength, DWORD dwReserved, LPBINDSTATUSCALLBACK pBSC)
652 {
653     LPWSTR url = NULL, file_name = NULL;
654     int len;
655     HRESULT hres;
656
657     TRACE("(%p %s %p %d %d %p)\n", lpUnkCaller, debugstr_a(szURL), szFileName,
658             dwBufLength, dwReserved, pBSC);
659
660     if(szURL) {
661         len = MultiByteToWideChar(CP_ACP, 0, szURL, -1, NULL, 0);
662         url = heap_alloc(len*sizeof(WCHAR));
663         MultiByteToWideChar(CP_ACP, 0, szURL, -1, url, len);
664     }
665
666     if(szFileName)
667         file_name = heap_alloc(dwBufLength*sizeof(WCHAR));
668
669     hres = URLDownloadToCacheFileW(lpUnkCaller, url, file_name, dwBufLength*sizeof(WCHAR),
670             dwReserved, pBSC);
671
672     if(SUCCEEDED(hres) && file_name)
673         WideCharToMultiByte(CP_ACP, 0, file_name, -1, szFileName, dwBufLength, NULL, NULL);
674
675     heap_free(url);
676     heap_free(file_name);
677
678     return hres;
679 }
680
681 /***********************************************************************
682  *           URLDownloadToCacheFileW (URLMON.@)
683  */
684 HRESULT WINAPI URLDownloadToCacheFileW(LPUNKNOWN lpUnkCaller, LPCWSTR szURL, LPWSTR szFileName,
685                 DWORD dwBufLength, DWORD dwReserved, LPBINDSTATUSCALLBACK pBSC)
686 {
687     WCHAR cache_path[MAX_PATH + 1];
688     FILETIME expire, modified;
689     HRESULT hr;
690     LPWSTR ext;
691
692     static WCHAR header[] = {
693         'H','T','T','P','/','1','.','0',' ','2','0','0',' ',
694         'O','K','\\','r','\\','n','\\','r','\\','n',0
695     };
696
697     TRACE("(%p, %s, %p, %d, %d, %p)\n", lpUnkCaller, debugstr_w(szURL),
698           szFileName, dwBufLength, dwReserved, pBSC);
699
700     if (!szURL || !szFileName)
701         return E_INVALIDARG;
702
703     ext = PathFindExtensionW(szURL);
704
705     if (!CreateUrlCacheEntryW(szURL, 0, ext, cache_path, 0))
706         return E_FAIL;
707
708     hr = URLDownloadToFileW(lpUnkCaller, szURL, cache_path, 0, pBSC);
709     if (FAILED(hr))
710         return hr;
711
712     expire.dwHighDateTime = 0;
713     expire.dwLowDateTime = 0;
714     modified.dwHighDateTime = 0;
715     modified.dwLowDateTime = 0;
716
717     if (!CommitUrlCacheEntryW(szURL, cache_path, expire, modified, NORMAL_CACHE_ENTRY,
718                               header, sizeof(header), NULL, NULL))
719         return E_FAIL;
720
721     if (strlenW(cache_path) > dwBufLength)
722         return E_OUTOFMEMORY;
723
724     lstrcpyW(szFileName, cache_path);
725
726     return S_OK;
727 }
728
729 /***********************************************************************
730  *           HlinkSimpleNavigateToMoniker (URLMON.@)
731  */
732 HRESULT WINAPI HlinkSimpleNavigateToMoniker(IMoniker *pmkTarget,
733     LPCWSTR szLocation, LPCWSTR szTargetFrameName, IUnknown *pUnk,
734     IBindCtx *pbc, IBindStatusCallback *pbsc, DWORD grfHLNF, DWORD dwReserved)
735 {
736     LPWSTR target;
737     HRESULT hres;
738
739     TRACE("\n");
740
741     hres = IMoniker_GetDisplayName(pmkTarget, pbc, 0, &target);
742     if(hres == S_OK)
743         hres = HlinkSimpleNavigateToString( target, szLocation, szTargetFrameName,
744                                             pUnk, pbc, pbsc, grfHLNF, dwReserved );
745     CoTaskMemFree(target);
746
747     return hres;
748 }
749
750 /***********************************************************************
751  *           HlinkSimpleNavigateToString (URLMON.@)
752  */
753 HRESULT WINAPI HlinkSimpleNavigateToString( LPCWSTR szTarget,
754     LPCWSTR szLocation, LPCWSTR szTargetFrameName, IUnknown *pUnk,
755     IBindCtx *pbc, IBindStatusCallback *pbsc, DWORD grfHLNF, DWORD dwReserved)
756 {
757     FIXME("%s %s %s %p %p %p %u %u partial stub\n", debugstr_w( szTarget ), debugstr_w( szLocation ),
758           debugstr_w( szTargetFrameName ), pUnk, pbc, pbsc, grfHLNF, dwReserved);
759
760     /* undocumented: 0 means HLNF_OPENINNEWWINDOW*/
761     if (!grfHLNF) grfHLNF = HLNF_OPENINNEWWINDOW;
762
763     if (grfHLNF == HLNF_OPENINNEWWINDOW)
764     {
765         SHELLEXECUTEINFOW sei;
766         static const WCHAR openW[] = { 'o', 'p', 'e', 'n', 0 };
767
768         memset(&sei, 0, sizeof(sei));
769         sei.cbSize = sizeof(sei);
770         sei.lpVerb = openW;
771         sei.nShow = SW_SHOWNORMAL;
772         sei.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_NO_CONSOLE;
773         sei.lpFile = szTarget;
774
775         if (ShellExecuteExW(&sei)) return S_OK;
776     }
777
778     return E_NOTIMPL;
779 }
780
781 /***********************************************************************
782  *           HlinkNavigateString (URLMON.@)
783  */
784 HRESULT WINAPI HlinkNavigateString( IUnknown *pUnk, LPCWSTR szTarget )
785 {
786     TRACE("%p %s\n", pUnk, debugstr_w( szTarget ) );
787     return HlinkSimpleNavigateToString( 
788                szTarget, NULL, NULL, pUnk, NULL, NULL, 0, 0 );
789 }
790
791 /***********************************************************************
792  *           GetSoftwareUpdateInfo (URLMON.@)
793  */
794 HRESULT WINAPI GetSoftwareUpdateInfo( LPCWSTR szDistUnit, LPSOFTDISTINFO psdi )
795 {
796     FIXME("%s %p\n", debugstr_w(szDistUnit), psdi );
797     return E_FAIL;
798 }
799
800 /***********************************************************************
801  *           AsyncInstallDistributionUnit (URLMON.@)
802  */
803 HRESULT WINAPI AsyncInstallDistributionUnit( LPCWSTR szDistUnit, LPCWSTR szTYPE,
804                             LPCWSTR szExt, DWORD dwFileVersionMS, DWORD dwFileVersionLS,
805                             LPCWSTR szURL, IBindCtx *pbc, LPVOID pvReserved, DWORD flags )
806 {
807     FIXME(": stub\n");
808     return E_NOTIMPL;
809 }