widl: Use the output buffer functions to write typelibs.
[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     IUri *uri;
204     HRESULT hres;
205
206     TRACE("(%p)->(%p,%p,%s,%p): stub\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppv);
207
208     hres = IBindCtx_GetRunningObjectTable(pbc, &obj_tbl);
209     if(SUCCEEDED(hres)) {
210         FIXME("use running object table\n");
211         IRunningObjectTable_Release(obj_tbl);
212     }
213
214     hres = CreateUri(This->URLName, Uri_CREATE_FILE_USE_DOS_PATH, 0, &uri);
215     if(FAILED(hres))
216         return hres;
217
218     hres = bind_to_object(iface, uri, pbc, riid, ppv);
219
220     IUri_Release(uri);
221     return hres;
222 }
223
224 static HRESULT WINAPI URLMoniker_BindToStorage(IMoniker* iface, IBindCtx* pbc,
225         IMoniker* pmkToLeft, REFIID riid, void **ppvObject)
226 {
227     URLMoniker *This = MONIKER_THIS(iface);
228     IUri *uri;
229     HRESULT hres;
230
231     TRACE("(%p)->(%p %p %s %p)\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppvObject);
232
233     if(pmkToLeft)
234         FIXME("Unsupported pmkToLeft\n");
235
236     hres = CreateUri(This->URLName, Uri_CREATE_FILE_USE_DOS_PATH, 0, &uri);
237     if(FAILED(hres))
238         return hres;
239
240     hres = bind_to_storage(uri, pbc, riid, ppvObject);
241
242     IUri_Release(uri);
243     return hres;
244 }
245
246 static HRESULT WINAPI URLMoniker_Reduce(IMoniker *iface, IBindCtx *pbc,
247         DWORD dwReduceHowFar, IMoniker **ppmkToLeft, IMoniker **ppmkReduced)
248 {
249     URLMoniker *This = MONIKER_THIS(iface);
250     
251     TRACE("(%p,%p,%d,%p,%p)\n", This, pbc, dwReduceHowFar, ppmkToLeft, ppmkReduced);
252
253     if(!ppmkReduced)
254         return E_INVALIDARG;
255
256     IMoniker_AddRef(iface);
257     *ppmkReduced = iface;
258     return MK_S_REDUCED_TO_SELF;
259 }
260
261 static HRESULT WINAPI URLMoniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight,
262         BOOL fOnlyIfNotGeneric, IMoniker **ppmkComposite)
263 {
264     URLMoniker *This = MONIKER_THIS(iface);
265     FIXME("(%p)->(%p,%d,%p): stub\n",This,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
266     return E_NOTIMPL;
267 }
268
269 static HRESULT WINAPI URLMoniker_Enum(IMoniker *iface, BOOL fForward, IEnumMoniker **ppenumMoniker)
270 {
271     URLMoniker *This = MONIKER_THIS(iface);
272
273     TRACE("(%p,%d,%p)\n", This, fForward, ppenumMoniker);
274
275     if(!ppenumMoniker)
276         return E_INVALIDARG;
277
278     /* Does not support sub-monikers */
279     *ppenumMoniker = NULL;
280     return S_OK;
281 }
282
283 static HRESULT WINAPI URLMoniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker)
284 {
285     URLMoniker *This = MONIKER_THIS(iface);
286     CLSID clsid;
287     LPOLESTR urlPath;
288     IBindCtx* bind;
289     HRESULT res;
290
291     TRACE("(%p,%p)\n",This, pmkOtherMoniker);
292
293     if(pmkOtherMoniker==NULL)
294         return E_INVALIDARG;
295
296     IMoniker_GetClassID(pmkOtherMoniker,&clsid);
297
298     if(!IsEqualCLSID(&clsid,&CLSID_StdURLMoniker))
299         return S_FALSE;
300
301     res = CreateBindCtx(0,&bind);
302     if(FAILED(res))
303         return res;
304
305     res = S_FALSE;
306     if(SUCCEEDED(IMoniker_GetDisplayName(pmkOtherMoniker,bind,NULL,&urlPath))) {
307         int result = lstrcmpiW(urlPath, This->URLName);
308         CoTaskMemFree(urlPath);
309         if(result == 0)
310             res = S_OK;
311     }
312     IUnknown_Release(bind);
313     return res;
314 }
315
316
317 static HRESULT WINAPI URLMoniker_Hash(IMoniker *iface, DWORD *pdwHash)
318 {
319     URLMoniker *This = MONIKER_THIS(iface);
320     int  h = 0,i,skip,len;
321     int  off = 0;
322     LPOLESTR val;
323
324     TRACE("(%p,%p)\n",This,pdwHash);
325
326     if(!pdwHash)
327         return E_INVALIDARG;
328
329     val = This->URLName;
330     len = lstrlenW(val);
331
332     if(len < 16) {
333         for(i = len ; i > 0; i--) {
334             h = (h * 37) + val[off++];
335         }
336     }else {
337         /* only sample some characters */
338         skip = len / 8;
339         for(i = len; i > 0; i -= skip, off += skip) {
340             h = (h * 39) + val[off];
341         }
342     }
343     *pdwHash = h;
344     return S_OK;
345 }
346
347 static HRESULT WINAPI URLMoniker_IsRunning(IMoniker* iface, IBindCtx* pbc,
348         IMoniker *pmkToLeft, IMoniker *pmkNewlyRunning)
349 {
350     URLMoniker *This = MONIKER_THIS(iface);
351     FIXME("(%p)->(%p,%p,%p): stub\n",This,pbc,pmkToLeft,pmkNewlyRunning);
352     return E_NOTIMPL;
353 }
354
355 static HRESULT WINAPI URLMoniker_GetTimeOfLastChange(IMoniker *iface,
356         IBindCtx *pbc, IMoniker *pmkToLeft, FILETIME *pFileTime)
357 {
358     URLMoniker *This = MONIKER_THIS(iface);
359     FIXME("(%p)->(%p,%p,%p): stub\n", This, pbc, pmkToLeft, pFileTime);
360     return E_NOTIMPL;
361 }
362
363 static HRESULT WINAPI URLMoniker_Inverse(IMoniker *iface, IMoniker **ppmk)
364 {
365     URLMoniker *This = MONIKER_THIS(iface);
366     TRACE("(%p,%p)\n",This,ppmk);
367     return MK_E_NOINVERSE;
368 }
369
370 static HRESULT WINAPI URLMoniker_CommonPrefixWith(IMoniker *iface, IMoniker *pmkOther, IMoniker **ppmkPrefix)
371 {
372     URLMoniker *This = MONIKER_THIS(iface);
373     FIXME("(%p)->(%p,%p): stub\n",This,pmkOther,ppmkPrefix);
374     return E_NOTIMPL;
375 }
376
377 static HRESULT WINAPI URLMoniker_RelativePathTo(IMoniker *iface, IMoniker *pmOther, IMoniker **ppmkRelPath)
378 {
379     URLMoniker *This = MONIKER_THIS(iface);
380     FIXME("(%p)->(%p,%p): stub\n",This,pmOther,ppmkRelPath);
381     return E_NOTIMPL;
382 }
383
384 static HRESULT WINAPI URLMoniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
385         LPOLESTR *ppszDisplayName)
386 {
387     URLMoniker *This = MONIKER_THIS(iface);
388     int len;
389     
390     TRACE("(%p,%p,%p,%p)\n", This, pbc, pmkToLeft, ppszDisplayName);
391     
392     if(!ppszDisplayName)
393         return E_INVALIDARG;
394
395     if(!This->URLName)
396         return E_OUTOFMEMORY;
397
398     /* FIXME: If this is a partial URL, try and get a URL moniker from SZ_URLCONTEXT in the bind context,
399         then look at pmkToLeft to try and complete the URL
400     */
401     len = lstrlenW(This->URLName)+1;
402     *ppszDisplayName = CoTaskMemAlloc(len*sizeof(WCHAR));
403     if(!*ppszDisplayName)
404         return E_OUTOFMEMORY;
405     lstrcpyW(*ppszDisplayName, This->URLName);
406     return S_OK;
407 }
408
409 static HRESULT WINAPI URLMoniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
410         LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut)
411 {
412     URLMoniker *This = MONIKER_THIS(iface);
413     FIXME("(%p)->(%p,%p,%p,%p,%p): stub\n",This,pbc,pmkToLeft,pszDisplayName,pchEaten,ppmkOut);
414     return E_NOTIMPL;
415 }
416
417 static HRESULT WINAPI URLMoniker_IsSystemMoniker(IMoniker *iface, DWORD *pwdMksys)
418 {
419     URLMoniker *This = MONIKER_THIS(iface);
420
421     TRACE("(%p,%p)\n",This,pwdMksys);
422
423     if(!pwdMksys)
424         return E_INVALIDARG;
425
426     *pwdMksys = MKSYS_URLMONIKER;
427     return S_OK;
428 }
429
430 static const IMonikerVtbl URLMonikerVtbl =
431 {
432     URLMoniker_QueryInterface,
433     URLMoniker_AddRef,
434     URLMoniker_Release,
435     URLMoniker_GetClassID,
436     URLMoniker_IsDirty,
437     URLMoniker_Load,
438     URLMoniker_Save,
439     URLMoniker_GetSizeMax,
440     URLMoniker_BindToObject,
441     URLMoniker_BindToStorage,
442     URLMoniker_Reduce,
443     URLMoniker_ComposeWith,
444     URLMoniker_Enum,
445     URLMoniker_IsEqual,
446     URLMoniker_Hash,
447     URLMoniker_IsRunning,
448     URLMoniker_GetTimeOfLastChange,
449     URLMoniker_Inverse,
450     URLMoniker_CommonPrefixWith,
451     URLMoniker_RelativePathTo,
452     URLMoniker_GetDisplayName,
453     URLMoniker_ParseDisplayName,
454     URLMoniker_IsSystemMoniker
455 };
456
457 static URLMoniker *alloc_moniker(void)
458 {
459     URLMoniker *ret;
460
461     ret = heap_alloc(sizeof(URLMoniker));
462     if(!ret)
463         return NULL;
464
465     ret->lpIMonikerVtbl = &URLMonikerVtbl;
466     ret->ref = 1;
467     ret->URLName = NULL;
468
469     return ret;
470 }
471
472 static HRESULT URLMoniker_Init(URLMoniker *This, LPCOLESTR lpszLeftURLName, LPCOLESTR lpszURLName)
473 {
474     HRESULT hres;
475     DWORD sizeStr = 0;
476
477     TRACE("(%p,%s,%s)\n",This,debugstr_w(lpszLeftURLName),debugstr_w(lpszURLName));
478
479     This->URLName = heap_alloc(INTERNET_MAX_URL_LENGTH*sizeof(WCHAR));
480
481     if(lpszLeftURLName)
482         hres = CoInternetCombineUrl(lpszLeftURLName, lpszURLName, URL_FILE_USE_PATHURL,
483                 This->URLName, INTERNET_MAX_URL_LENGTH, &sizeStr, 0);
484     else
485         hres = CoInternetParseUrl(lpszURLName, PARSE_CANONICALIZE, URL_FILE_USE_PATHURL,
486                 This->URLName, INTERNET_MAX_URL_LENGTH, &sizeStr, 0);
487
488     if(FAILED(hres)) {
489         heap_free(This->URLName);
490         return hres;
491     }
492
493     URLMON_LockModule();
494
495     if(sizeStr != INTERNET_MAX_URL_LENGTH)
496         This->URLName = heap_realloc(This->URLName, (sizeStr+1)*sizeof(WCHAR));
497
498     TRACE("URLName = %s\n", debugstr_w(This->URLName));
499
500     return S_OK;
501 }
502
503 HRESULT StdURLMoniker_Construct(IUnknown *outer, void **ppv)
504 {
505     TRACE("(%p %p)\n", outer, ppv);
506
507     *ppv = alloc_moniker();
508     return *ppv ? S_OK : E_OUTOFMEMORY;
509 }
510
511 /***********************************************************************
512  *           CreateURLMonikerEx (URLMON.@)
513  *
514  * Create a url moniker.
515  *
516  * PARAMS
517  *    pmkContext [I] Context
518  *    szURL      [I] Url to create the moniker for
519  *    ppmk       [O] Destination for created moniker.
520  *    dwFlags    [I] Flags.
521  *
522  * RETURNS
523  *    Success: S_OK. ppmk contains the created IMoniker object.
524  *    Failure: MK_E_SYNTAX if szURL is not a valid url, or
525  *             E_OUTOFMEMORY if memory allocation fails.
526  */
527 HRESULT WINAPI CreateURLMonikerEx(IMoniker *pmkContext, LPCWSTR szURL, IMoniker **ppmk, DWORD dwFlags)
528 {
529     URLMoniker *obj;
530     HRESULT hres;
531     LPOLESTR lefturl = NULL;
532
533     TRACE("(%p, %s, %p, %08x)\n", pmkContext, debugstr_w(szURL), ppmk, dwFlags);
534
535     if (ppmk)
536         *ppmk = NULL;
537
538     if (!szURL || !ppmk)
539         return E_INVALIDARG;
540
541     if (dwFlags & URL_MK_UNIFORM) FIXME("ignoring flag URL_MK_UNIFORM\n");
542
543     if(!(obj = alloc_moniker()))
544         return E_OUTOFMEMORY;
545
546     if(pmkContext) {
547         IBindCtx* bind;
548         DWORD dwMksys = 0;
549         IMoniker_IsSystemMoniker(pmkContext, &dwMksys);
550         if(dwMksys == MKSYS_URLMONIKER && SUCCEEDED(CreateBindCtx(0, &bind))) {
551             IMoniker_GetDisplayName(pmkContext, bind, NULL, &lefturl);
552             TRACE("lefturl = %s\n", debugstr_w(lefturl));
553             IBindCtx_Release(bind);
554         }
555     }
556         
557     hres = URLMoniker_Init(obj, lefturl, szURL);
558     CoTaskMemFree(lefturl);
559     if(SUCCEEDED(hres))
560         hres = URLMoniker_QueryInterface((IMoniker*)obj, &IID_IMoniker, (void**)ppmk);
561     IMoniker_Release((IMoniker*)obj);
562     return hres;
563 }
564
565 /**********************************************************************
566  *           CreateURLMoniker (URLMON.@)
567  *
568  * Create a url moniker.
569  *
570  * PARAMS
571  *    pmkContext [I] Context
572  *    szURL      [I] Url to create the moniker for
573  *    ppmk       [O] Destination for created moniker.
574  *
575  * RETURNS
576  *    Success: S_OK. ppmk contains the created IMoniker object.
577  *    Failure: MK_E_SYNTAX if szURL is not a valid url, or
578  *             E_OUTOFMEMORY if memory allocation fails.
579  */
580 HRESULT WINAPI CreateURLMoniker(IMoniker *pmkContext, LPCWSTR szURL, IMoniker **ppmk)
581 {
582     return CreateURLMonikerEx(pmkContext, szURL, ppmk, URL_MK_LEGACY);
583 }
584
585 /***********************************************************************
586  *           IsAsyncMoniker (URLMON.@)
587  */
588 HRESULT WINAPI IsAsyncMoniker(IMoniker *pmk)
589 {
590     IUnknown *am;
591     
592     TRACE("(%p)\n", pmk);
593     if(!pmk)
594         return E_INVALIDARG;
595     if(SUCCEEDED(IMoniker_QueryInterface(pmk, &IID_IAsyncMoniker, (void**)&am))) {
596         IUnknown_Release(am);
597         return S_OK;
598     }
599     return S_FALSE;
600 }
601
602 /***********************************************************************
603  *           BindAsyncMoniker (URLMON.@)
604  *
605  * Bind a bind status callback to an asynchronous URL Moniker.
606  *
607  * PARAMS
608  *  pmk           [I] Moniker object to bind status callback to
609  *  grfOpt        [I] Options, seems not used
610  *  pbsc          [I] Status callback to bind
611  *  iidResult     [I] Interface to return
612  *  ppvResult     [O] Resulting asynchronous moniker object
613  *
614  * RETURNS
615  *    Success: S_OK.
616  *    Failure: E_INVALIDARG, if any argument is invalid, or
617  *             E_OUTOFMEMORY if memory allocation fails.
618  */
619 HRESULT WINAPI BindAsyncMoniker(IMoniker *pmk, DWORD grfOpt, IBindStatusCallback *pbsc, REFIID iidResult, LPVOID *ppvResult)
620 {
621     LPBC pbc = NULL;
622     HRESULT hr = E_INVALIDARG;
623
624     TRACE("(%p %08x %p %s %p)\n", pmk, grfOpt, pbsc, debugstr_guid(iidResult), ppvResult);
625
626     if (pmk && ppvResult)
627     {
628         *ppvResult = NULL;
629
630         hr = CreateAsyncBindCtx(0, pbsc, NULL, &pbc);
631         if (hr == NOERROR)
632         {
633             hr = IMoniker_BindToObject(pmk, pbc, NULL, iidResult, ppvResult);
634             IBindCtx_Release(pbc);
635         }
636     }
637     return hr;
638 }
639
640 /***********************************************************************
641  *           MkParseDisplayNameEx (URLMON.@)
642  */
643 HRESULT WINAPI MkParseDisplayNameEx(IBindCtx *pbc, LPCWSTR szDisplayName, ULONG *pchEaten, LPMONIKER *ppmk)
644 {
645     TRACE("(%p %s %p %p)\n", pbc, debugstr_w(szDisplayName), pchEaten, ppmk);
646
647     if (!pbc || !szDisplayName || !*szDisplayName || !pchEaten || !ppmk)
648         return E_INVALIDARG;
649
650     if(is_registered_protocol(szDisplayName)) {
651         HRESULT hres;
652
653         hres = CreateURLMoniker(NULL, szDisplayName, ppmk);
654         if(SUCCEEDED(hres)) {
655             *pchEaten = strlenW(szDisplayName);
656             return hres;
657         }
658     }
659
660     return MkParseDisplayName(pbc, szDisplayName, pchEaten, ppmk);
661 }
662
663
664 /***********************************************************************
665  *           URLDownloadToCacheFileA (URLMON.@)
666  */
667 HRESULT WINAPI URLDownloadToCacheFileA(LPUNKNOWN lpUnkCaller, LPCSTR szURL, LPSTR szFileName,
668         DWORD dwBufLength, DWORD dwReserved, LPBINDSTATUSCALLBACK pBSC)
669 {
670     LPWSTR url = NULL, file_name = NULL;
671     int len;
672     HRESULT hres;
673
674     TRACE("(%p %s %p %d %d %p)\n", lpUnkCaller, debugstr_a(szURL), szFileName,
675             dwBufLength, dwReserved, pBSC);
676
677     if(szURL) {
678         len = MultiByteToWideChar(CP_ACP, 0, szURL, -1, NULL, 0);
679         url = heap_alloc(len*sizeof(WCHAR));
680         MultiByteToWideChar(CP_ACP, 0, szURL, -1, url, len);
681     }
682
683     if(szFileName)
684         file_name = heap_alloc(dwBufLength*sizeof(WCHAR));
685
686     hres = URLDownloadToCacheFileW(lpUnkCaller, url, file_name, dwBufLength*sizeof(WCHAR),
687             dwReserved, pBSC);
688
689     if(SUCCEEDED(hres) && file_name)
690         WideCharToMultiByte(CP_ACP, 0, file_name, -1, szFileName, dwBufLength, NULL, NULL);
691
692     heap_free(url);
693     heap_free(file_name);
694
695     return hres;
696 }
697
698 /***********************************************************************
699  *           URLDownloadToCacheFileW (URLMON.@)
700  */
701 HRESULT WINAPI URLDownloadToCacheFileW(LPUNKNOWN lpUnkCaller, LPCWSTR szURL, LPWSTR szFileName,
702                 DWORD dwBufLength, DWORD dwReserved, LPBINDSTATUSCALLBACK pBSC)
703 {
704     WCHAR cache_path[MAX_PATH + 1];
705     FILETIME expire, modified;
706     HRESULT hr;
707     LPWSTR ext;
708
709     static WCHAR header[] = {
710         'H','T','T','P','/','1','.','0',' ','2','0','0',' ',
711         'O','K','\\','r','\\','n','\\','r','\\','n',0
712     };
713
714     TRACE("(%p, %s, %p, %d, %d, %p)\n", lpUnkCaller, debugstr_w(szURL),
715           szFileName, dwBufLength, dwReserved, pBSC);
716
717     if (!szURL || !szFileName)
718         return E_INVALIDARG;
719
720     ext = PathFindExtensionW(szURL);
721
722     if (!CreateUrlCacheEntryW(szURL, 0, ext, cache_path, 0))
723         return E_FAIL;
724
725     hr = URLDownloadToFileW(lpUnkCaller, szURL, cache_path, 0, pBSC);
726     if (FAILED(hr))
727         return hr;
728
729     expire.dwHighDateTime = 0;
730     expire.dwLowDateTime = 0;
731     modified.dwHighDateTime = 0;
732     modified.dwLowDateTime = 0;
733
734     if (!CommitUrlCacheEntryW(szURL, cache_path, expire, modified, NORMAL_CACHE_ENTRY,
735                               header, sizeof(header), NULL, NULL))
736         return E_FAIL;
737
738     if (strlenW(cache_path) > dwBufLength)
739         return E_OUTOFMEMORY;
740
741     lstrcpyW(szFileName, cache_path);
742
743     return S_OK;
744 }
745
746 /***********************************************************************
747  *           HlinkSimpleNavigateToMoniker (URLMON.@)
748  */
749 HRESULT WINAPI HlinkSimpleNavigateToMoniker(IMoniker *pmkTarget,
750     LPCWSTR szLocation, LPCWSTR szTargetFrameName, IUnknown *pUnk,
751     IBindCtx *pbc, IBindStatusCallback *pbsc, DWORD grfHLNF, DWORD dwReserved)
752 {
753     LPWSTR target;
754     HRESULT hres;
755
756     TRACE("\n");
757
758     hres = IMoniker_GetDisplayName(pmkTarget, pbc, 0, &target);
759     if(hres == S_OK)
760         hres = HlinkSimpleNavigateToString( target, szLocation, szTargetFrameName,
761                                             pUnk, pbc, pbsc, grfHLNF, dwReserved );
762     CoTaskMemFree(target);
763
764     return hres;
765 }
766
767 /***********************************************************************
768  *           HlinkSimpleNavigateToString (URLMON.@)
769  */
770 HRESULT WINAPI HlinkSimpleNavigateToString( LPCWSTR szTarget,
771     LPCWSTR szLocation, LPCWSTR szTargetFrameName, IUnknown *pUnk,
772     IBindCtx *pbc, IBindStatusCallback *pbsc, DWORD grfHLNF, DWORD dwReserved)
773 {
774     FIXME("%s %s %s %p %p %p %u %u partial stub\n", debugstr_w( szTarget ), debugstr_w( szLocation ),
775           debugstr_w( szTargetFrameName ), pUnk, pbc, pbsc, grfHLNF, dwReserved);
776
777     /* undocumented: 0 means HLNF_OPENINNEWWINDOW*/
778     if (!grfHLNF) grfHLNF = HLNF_OPENINNEWWINDOW;
779
780     if (grfHLNF == HLNF_OPENINNEWWINDOW)
781     {
782         SHELLEXECUTEINFOW sei;
783         static const WCHAR openW[] = { 'o', 'p', 'e', 'n', 0 };
784
785         memset(&sei, 0, sizeof(sei));
786         sei.cbSize = sizeof(sei);
787         sei.lpVerb = openW;
788         sei.nShow = SW_SHOWNORMAL;
789         sei.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_NO_CONSOLE;
790         sei.lpFile = szTarget;
791
792         if (ShellExecuteExW(&sei)) return S_OK;
793     }
794
795     return E_NOTIMPL;
796 }
797
798 /***********************************************************************
799  *           HlinkNavigateString (URLMON.@)
800  */
801 HRESULT WINAPI HlinkNavigateString( IUnknown *pUnk, LPCWSTR szTarget )
802 {
803     TRACE("%p %s\n", pUnk, debugstr_w( szTarget ) );
804     return HlinkSimpleNavigateToString( 
805                szTarget, NULL, NULL, pUnk, NULL, NULL, 0, 0 );
806 }
807
808 /***********************************************************************
809  *           GetSoftwareUpdateInfo (URLMON.@)
810  */
811 HRESULT WINAPI GetSoftwareUpdateInfo( LPCWSTR szDistUnit, LPSOFTDISTINFO psdi )
812 {
813     FIXME("%s %p\n", debugstr_w(szDistUnit), psdi );
814     return E_FAIL;
815 }
816
817 /***********************************************************************
818  *           AsyncInstallDistributionUnit (URLMON.@)
819  */
820 HRESULT WINAPI AsyncInstallDistributionUnit( LPCWSTR szDistUnit, LPCWSTR szTYPE,
821                             LPCWSTR szExt, DWORD dwFileVersionMS, DWORD dwFileVersionLS,
822                             LPCWSTR szURL, IBindCtx *pbc, LPVOID pvReserved, DWORD flags )
823 {
824     FIXME(": stub\n");
825     return E_NOTIMPL;
826 }