xref: /reactos/dll/win32/urlmon/umon.c (revision 6c3c2e33)
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     IMoniker      IMoniker_iface;
36     IUriContainer IUriContainer_iface;
37 
38     LONG ref;
39 
40     IUri *uri;
41     BSTR URLName;
42 } URLMoniker;
43 
impl_from_IMoniker(IMoniker * iface)44 static inline URLMoniker *impl_from_IMoniker(IMoniker *iface)
45 {
46     return CONTAINING_RECORD(iface, URLMoniker, IMoniker_iface);
47 }
48 
URLMoniker_QueryInterface(IMoniker * iface,REFIID riid,void ** ppv)49 static HRESULT WINAPI URLMoniker_QueryInterface(IMoniker *iface, REFIID riid, void **ppv)
50 {
51     URLMoniker *This = impl_from_IMoniker(iface);
52 
53     if(!ppv)
54 	return E_INVALIDARG;
55 
56     if(IsEqualIID(&IID_IUnknown, riid)) {
57         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
58         *ppv = iface;
59     }else if(IsEqualIID(&IID_IPersist, riid)) {
60         TRACE("(%p)->(IID_IPersist %p)\n", This, ppv);
61         *ppv = iface;
62     }else if(IsEqualIID(&IID_IPersistStream,riid)) {
63         TRACE("(%p)->(IID_IPersistStream %p)\n", This, ppv);
64         *ppv = iface;
65     }else if(IsEqualIID(&IID_IMoniker, riid)) {
66         TRACE("(%p)->(IID_IMoniker %p)\n", This, ppv);
67         *ppv = iface;
68     }else if(IsEqualIID(&IID_IAsyncMoniker, riid)) {
69         TRACE("(%p)->(IID_IAsyncMoniker %p)\n", This, ppv);
70         *ppv = iface;
71     }else if(IsEqualIID(&IID_IUriContainer, riid)) {
72         TRACE("(%p)->(IID_IUriContainer %p)\n", This, ppv);
73         *ppv = &This->IUriContainer_iface;
74     }else {
75         WARN("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppv);
76         *ppv = NULL;
77         return E_NOINTERFACE;
78     }
79 
80     IUnknown_AddRef((IUnknown*)*ppv);
81     return S_OK;
82 }
83 
URLMoniker_AddRef(IMoniker * iface)84 static ULONG WINAPI URLMoniker_AddRef(IMoniker *iface)
85 {
86     URLMoniker *This = impl_from_IMoniker(iface);
87     ULONG refCount = InterlockedIncrement(&This->ref);
88 
89     TRACE("(%p) ref=%u\n",This, refCount);
90 
91     return refCount;
92 }
93 
URLMoniker_Release(IMoniker * iface)94 static ULONG WINAPI URLMoniker_Release(IMoniker *iface)
95 {
96     URLMoniker *This = impl_from_IMoniker(iface);
97     ULONG refCount = InterlockedDecrement(&This->ref);
98 
99     TRACE("(%p) ref=%u\n",This, refCount);
100 
101     if (!refCount) {
102         if(This->uri)
103             IUri_Release(This->uri);
104         SysFreeString(This->URLName);
105         heap_free(This);
106 
107         URLMON_UnlockModule();
108     }
109 
110     return refCount;
111 }
112 
URLMoniker_GetClassID(IMoniker * iface,CLSID * pClassID)113 static HRESULT WINAPI URLMoniker_GetClassID(IMoniker *iface, CLSID *pClassID)
114 {
115     URLMoniker *This = impl_from_IMoniker(iface);
116 
117     TRACE("(%p,%p)\n", This, pClassID);
118 
119     if(!pClassID)
120         return E_POINTER;
121 
122     /* Windows always returns CLSID_StdURLMoniker */
123     *pClassID = CLSID_StdURLMoniker;
124     return S_OK;
125 }
126 
URLMoniker_IsDirty(IMoniker * iface)127 static HRESULT WINAPI URLMoniker_IsDirty(IMoniker *iface)
128 {
129     URLMoniker *This = impl_from_IMoniker(iface);
130 
131     TRACE("(%p)\n",This);
132 
133     /* Note that the OLE-provided implementations of the IPersistStream::IsDirty
134        method in the OLE-provided moniker interfaces always return S_FALSE because
135        their internal state never changes. */
136     return S_FALSE;
137 }
138 
URLMoniker_Load(IMoniker * iface,IStream * pStm)139 static HRESULT WINAPI URLMoniker_Load(IMoniker* iface,IStream* pStm)
140 {
141     URLMoniker *This = impl_from_IMoniker(iface);
142     WCHAR *new_uri_str;
143     IUri *new_uri;
144     BSTR new_url;
145     ULONG size;
146     ULONG got;
147     HRESULT hres;
148 
149     TRACE("(%p,%p)\n",This,pStm);
150 
151     if(!pStm)
152         return E_INVALIDARG;
153 
154     /*
155      * NOTE
156      *  Writes a ULONG containing length of unicode string, followed
157      *  by that many unicode characters
158      */
159     hres = IStream_Read(pStm, &size, sizeof(ULONG), &got);
160     if(FAILED(hres))
161         return hres;
162     if(got != sizeof(ULONG))
163         return E_FAIL;
164 
165     new_uri_str = heap_alloc(size+sizeof(WCHAR));
166     if(!new_uri_str)
167         return E_OUTOFMEMORY;
168 
169     hres = IStream_Read(pStm, new_uri_str, size, NULL);
170     new_uri_str[size/sizeof(WCHAR)] = 0;
171     if(SUCCEEDED(hres))
172         hres = CreateUri(new_uri_str, 0, 0, &new_uri);
173     heap_free(new_uri_str);
174     if(FAILED(hres))
175         return hres;
176 
177     hres = IUri_GetDisplayUri(new_uri, &new_url);
178     if(FAILED(hres)) {
179         IUri_Release(new_uri);
180         return hres;
181     }
182 
183     SysFreeString(This->URLName);
184     if(This->uri)
185         IUri_Release(This->uri);
186 
187     This->uri = new_uri;
188     This->URLName = new_url;
189     return S_OK;
190 }
191 
URLMoniker_Save(IMoniker * iface,IStream * pStm,BOOL fClearDirty)192 static HRESULT WINAPI URLMoniker_Save(IMoniker *iface, IStream* pStm, BOOL fClearDirty)
193 {
194     URLMoniker *This = impl_from_IMoniker(iface);
195     HRESULT res;
196     ULONG size;
197 
198     TRACE("(%p,%p,%d)\n", This, pStm, fClearDirty);
199 
200     if(!pStm)
201         return E_INVALIDARG;
202 
203     size = (SysStringLen(This->URLName) + 1)*sizeof(WCHAR);
204     res=IStream_Write(pStm,&size,sizeof(ULONG),NULL);
205     if(SUCCEEDED(res))
206         res=IStream_Write(pStm,This->URLName,size,NULL);
207 
208     return res;
209 
210 }
211 
URLMoniker_GetSizeMax(IMoniker * iface,ULARGE_INTEGER * pcbSize)212 static HRESULT WINAPI URLMoniker_GetSizeMax(IMoniker* iface, ULARGE_INTEGER *pcbSize)
213 {
214     URLMoniker *This = impl_from_IMoniker(iface);
215 
216     TRACE("(%p,%p)\n",This,pcbSize);
217 
218     if(!pcbSize)
219         return E_INVALIDARG;
220 
221     pcbSize->QuadPart = sizeof(ULONG) + ((SysStringLen(This->URLName)+1) * sizeof(WCHAR));
222     return S_OK;
223 }
224 
URLMoniker_BindToObject(IMoniker * iface,IBindCtx * pbc,IMoniker * pmkToLeft,REFIID riid,void ** ppv)225 static HRESULT WINAPI URLMoniker_BindToObject(IMoniker *iface, IBindCtx* pbc, IMoniker *pmkToLeft,
226         REFIID riid, void **ppv)
227 {
228     URLMoniker *This = impl_from_IMoniker(iface);
229     IRunningObjectTable *obj_tbl;
230     HRESULT hres;
231 
232     TRACE("(%p)->(%p,%p,%s,%p)\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppv);
233 
234     hres = IBindCtx_GetRunningObjectTable(pbc, &obj_tbl);
235     if(SUCCEEDED(hres)) {
236         hres = IRunningObjectTable_IsRunning(obj_tbl, &This->IMoniker_iface);
237         if(hres == S_OK) {
238             IUnknown *unk = NULL;
239 
240             TRACE("Found in running object table\n");
241 
242             hres = IRunningObjectTable_GetObject(obj_tbl, &This->IMoniker_iface, &unk);
243             if(SUCCEEDED(hres)) {
244                 hres = IUnknown_QueryInterface(unk, riid, ppv);
245                 IUnknown_Release(unk);
246             }
247 
248             IRunningObjectTable_Release(obj_tbl);
249             return hres;
250         }
251 
252         IRunningObjectTable_Release(obj_tbl);
253     }
254 
255     if(!This->uri) {
256         *ppv = NULL;
257         return MK_E_SYNTAX;
258     }
259 
260     return bind_to_object(&This->IMoniker_iface, This->uri, pbc, riid, ppv);
261 }
262 
URLMoniker_BindToStorage(IMoniker * iface,IBindCtx * pbc,IMoniker * pmkToLeft,REFIID riid,void ** ppvObject)263 static HRESULT WINAPI URLMoniker_BindToStorage(IMoniker* iface, IBindCtx* pbc,
264         IMoniker* pmkToLeft, REFIID riid, void **ppvObject)
265 {
266     URLMoniker *This = impl_from_IMoniker(iface);
267 
268     TRACE("(%p)->(%p %p %s %p)\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppvObject);
269 
270     if(ppvObject) *ppvObject = NULL;
271 
272     if(!pbc || !ppvObject) return E_INVALIDARG;
273 
274     if(pmkToLeft)
275         FIXME("Unsupported pmkToLeft\n");
276 
277     if(!This->uri)
278         return MK_E_SYNTAX;
279 
280     return bind_to_storage(This->uri, pbc, riid, ppvObject);
281 }
282 
URLMoniker_Reduce(IMoniker * iface,IBindCtx * pbc,DWORD dwReduceHowFar,IMoniker ** ppmkToLeft,IMoniker ** ppmkReduced)283 static HRESULT WINAPI URLMoniker_Reduce(IMoniker *iface, IBindCtx *pbc,
284         DWORD dwReduceHowFar, IMoniker **ppmkToLeft, IMoniker **ppmkReduced)
285 {
286     URLMoniker *This = impl_from_IMoniker(iface);
287 
288     TRACE("(%p,%p,%d,%p,%p)\n", This, pbc, dwReduceHowFar, ppmkToLeft, ppmkReduced);
289 
290     if(!ppmkReduced)
291         return E_INVALIDARG;
292 
293     IMoniker_AddRef(iface);
294     *ppmkReduced = iface;
295     return MK_S_REDUCED_TO_SELF;
296 }
297 
URLMoniker_ComposeWith(IMoniker * iface,IMoniker * pmkRight,BOOL fOnlyIfNotGeneric,IMoniker ** ppmkComposite)298 static HRESULT WINAPI URLMoniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight,
299         BOOL fOnlyIfNotGeneric, IMoniker **ppmkComposite)
300 {
301     URLMoniker *This = impl_from_IMoniker(iface);
302     FIXME("(%p)->(%p,%d,%p): stub\n",This,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
303     return E_NOTIMPL;
304 }
305 
URLMoniker_Enum(IMoniker * iface,BOOL fForward,IEnumMoniker ** ppenumMoniker)306 static HRESULT WINAPI URLMoniker_Enum(IMoniker *iface, BOOL fForward, IEnumMoniker **ppenumMoniker)
307 {
308     URLMoniker *This = impl_from_IMoniker(iface);
309 
310     TRACE("(%p,%d,%p)\n", This, fForward, ppenumMoniker);
311 
312     if(!ppenumMoniker)
313         return E_INVALIDARG;
314 
315     /* Does not support sub-monikers */
316     *ppenumMoniker = NULL;
317     return S_OK;
318 }
319 
URLMoniker_IsEqual(IMoniker * iface,IMoniker * pmkOtherMoniker)320 static HRESULT WINAPI URLMoniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker)
321 {
322     URLMoniker *This = impl_from_IMoniker(iface);
323     CLSID clsid;
324     LPOLESTR urlPath;
325     IBindCtx* bind;
326     HRESULT res;
327 
328     TRACE("(%p,%p)\n",This, pmkOtherMoniker);
329 
330     if(pmkOtherMoniker==NULL)
331         return E_INVALIDARG;
332 
333     IMoniker_GetClassID(pmkOtherMoniker,&clsid);
334 
335     if(!IsEqualCLSID(&clsid,&CLSID_StdURLMoniker))
336         return S_FALSE;
337 
338     res = CreateBindCtx(0,&bind);
339     if(FAILED(res))
340         return res;
341 
342     res = S_FALSE;
343     if(SUCCEEDED(IMoniker_GetDisplayName(pmkOtherMoniker,bind,NULL,&urlPath))) {
344         int result = lstrcmpiW(urlPath, This->URLName);
345         CoTaskMemFree(urlPath);
346         if(result == 0)
347             res = S_OK;
348     }
349     IBindCtx_Release(bind);
350     return res;
351 }
352 
353 
URLMoniker_Hash(IMoniker * iface,DWORD * pdwHash)354 static HRESULT WINAPI URLMoniker_Hash(IMoniker *iface, DWORD *pdwHash)
355 {
356     URLMoniker *This = impl_from_IMoniker(iface);
357     int  h = 0,i,skip,len;
358     int  off = 0;
359     LPOLESTR val;
360 
361     TRACE("(%p,%p)\n",This,pdwHash);
362 
363     if(!pdwHash)
364         return E_INVALIDARG;
365 
366     val = This->URLName;
367     len = lstrlenW(val);
368 
369     if(len < 16) {
370         for(i = len ; i > 0; i--) {
371             h = (h * 37) + val[off++];
372         }
373     }else {
374         /* only sample some characters */
375         skip = len / 8;
376         for(i = len; i > 0; i -= skip, off += skip) {
377             h = (h * 39) + val[off];
378         }
379     }
380     *pdwHash = h;
381     return S_OK;
382 }
383 
URLMoniker_IsRunning(IMoniker * iface,IBindCtx * pbc,IMoniker * pmkToLeft,IMoniker * pmkNewlyRunning)384 static HRESULT WINAPI URLMoniker_IsRunning(IMoniker* iface, IBindCtx* pbc,
385         IMoniker *pmkToLeft, IMoniker *pmkNewlyRunning)
386 {
387     URLMoniker *This = impl_from_IMoniker(iface);
388     FIXME("(%p)->(%p,%p,%p): stub\n",This,pbc,pmkToLeft,pmkNewlyRunning);
389     return E_NOTIMPL;
390 }
391 
URLMoniker_GetTimeOfLastChange(IMoniker * iface,IBindCtx * pbc,IMoniker * pmkToLeft,FILETIME * pFileTime)392 static HRESULT WINAPI URLMoniker_GetTimeOfLastChange(IMoniker *iface,
393         IBindCtx *pbc, IMoniker *pmkToLeft, FILETIME *pFileTime)
394 {
395     URLMoniker *This = impl_from_IMoniker(iface);
396     FIXME("(%p)->(%p,%p,%p): stub\n", This, pbc, pmkToLeft, pFileTime);
397     return E_NOTIMPL;
398 }
399 
URLMoniker_Inverse(IMoniker * iface,IMoniker ** ppmk)400 static HRESULT WINAPI URLMoniker_Inverse(IMoniker *iface, IMoniker **ppmk)
401 {
402     URLMoniker *This = impl_from_IMoniker(iface);
403     TRACE("(%p,%p)\n",This,ppmk);
404     return MK_E_NOINVERSE;
405 }
406 
URLMoniker_CommonPrefixWith(IMoniker * iface,IMoniker * pmkOther,IMoniker ** ppmkPrefix)407 static HRESULT WINAPI URLMoniker_CommonPrefixWith(IMoniker *iface, IMoniker *pmkOther, IMoniker **ppmkPrefix)
408 {
409     URLMoniker *This = impl_from_IMoniker(iface);
410     FIXME("(%p)->(%p,%p): stub\n",This,pmkOther,ppmkPrefix);
411     return E_NOTIMPL;
412 }
413 
URLMoniker_RelativePathTo(IMoniker * iface,IMoniker * pmOther,IMoniker ** ppmkRelPath)414 static HRESULT WINAPI URLMoniker_RelativePathTo(IMoniker *iface, IMoniker *pmOther, IMoniker **ppmkRelPath)
415 {
416     URLMoniker *This = impl_from_IMoniker(iface);
417     FIXME("(%p)->(%p,%p): stub\n",This,pmOther,ppmkRelPath);
418     return E_NOTIMPL;
419 }
420 
URLMoniker_GetDisplayName(IMoniker * iface,IBindCtx * pbc,IMoniker * pmkToLeft,LPOLESTR * ppszDisplayName)421 static HRESULT WINAPI URLMoniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
422         LPOLESTR *ppszDisplayName)
423 {
424     URLMoniker *This = impl_from_IMoniker(iface);
425     int len;
426 
427     TRACE("(%p,%p,%p,%p)\n", This, pbc, pmkToLeft, ppszDisplayName);
428 
429     if(!ppszDisplayName)
430         return E_INVALIDARG;
431 
432     if(!This->URLName)
433         return E_OUTOFMEMORY;
434 
435     /* FIXME: If this is a partial URL, try and get a URL moniker from SZ_URLCONTEXT in the bind context,
436         then look at pmkToLeft to try and complete the URL
437     */
438     len = SysStringLen(This->URLName)+1;
439     *ppszDisplayName = CoTaskMemAlloc(len*sizeof(WCHAR));
440     if(!*ppszDisplayName)
441         return E_OUTOFMEMORY;
442     lstrcpyW(*ppszDisplayName, This->URLName);
443     return S_OK;
444 }
445 
URLMoniker_ParseDisplayName(IMoniker * iface,IBindCtx * pbc,IMoniker * pmkToLeft,LPOLESTR pszDisplayName,ULONG * pchEaten,IMoniker ** ppmkOut)446 static HRESULT WINAPI URLMoniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
447         LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut)
448 {
449     URLMoniker *This = impl_from_IMoniker(iface);
450     FIXME("(%p)->(%p,%p,%p,%p,%p): stub\n",This,pbc,pmkToLeft,pszDisplayName,pchEaten,ppmkOut);
451     return E_NOTIMPL;
452 }
453 
URLMoniker_IsSystemMoniker(IMoniker * iface,DWORD * pwdMksys)454 static HRESULT WINAPI URLMoniker_IsSystemMoniker(IMoniker *iface, DWORD *pwdMksys)
455 {
456     URLMoniker *This = impl_from_IMoniker(iface);
457 
458     TRACE("(%p,%p)\n",This,pwdMksys);
459 
460     if(!pwdMksys)
461         return E_INVALIDARG;
462 
463     *pwdMksys = MKSYS_URLMONIKER;
464     return S_OK;
465 }
466 
467 static const IMonikerVtbl URLMonikerVtbl =
468 {
469     URLMoniker_QueryInterface,
470     URLMoniker_AddRef,
471     URLMoniker_Release,
472     URLMoniker_GetClassID,
473     URLMoniker_IsDirty,
474     URLMoniker_Load,
475     URLMoniker_Save,
476     URLMoniker_GetSizeMax,
477     URLMoniker_BindToObject,
478     URLMoniker_BindToStorage,
479     URLMoniker_Reduce,
480     URLMoniker_ComposeWith,
481     URLMoniker_Enum,
482     URLMoniker_IsEqual,
483     URLMoniker_Hash,
484     URLMoniker_IsRunning,
485     URLMoniker_GetTimeOfLastChange,
486     URLMoniker_Inverse,
487     URLMoniker_CommonPrefixWith,
488     URLMoniker_RelativePathTo,
489     URLMoniker_GetDisplayName,
490     URLMoniker_ParseDisplayName,
491     URLMoniker_IsSystemMoniker
492 };
493 
impl_from_IUriContainer(IUriContainer * iface)494 static inline URLMoniker *impl_from_IUriContainer(IUriContainer *iface)
495 {
496     return CONTAINING_RECORD(iface, URLMoniker, IUriContainer_iface);
497 }
498 
UriContainer_QueryInterface(IUriContainer * iface,REFIID riid,void ** ppv)499 static HRESULT WINAPI UriContainer_QueryInterface(IUriContainer *iface, REFIID riid, void **ppv)
500 {
501     URLMoniker *This = impl_from_IUriContainer(iface);
502     return IMoniker_QueryInterface(&This->IMoniker_iface, riid, ppv);
503 }
504 
UriContainer_AddRef(IUriContainer * iface)505 static ULONG WINAPI UriContainer_AddRef(IUriContainer *iface)
506 {
507     URLMoniker *This = impl_from_IUriContainer(iface);
508     return IMoniker_AddRef(&This->IMoniker_iface);
509 }
510 
UriContainer_Release(IUriContainer * iface)511 static ULONG WINAPI UriContainer_Release(IUriContainer *iface)
512 {
513     URLMoniker *This = impl_from_IUriContainer(iface);
514     return IMoniker_Release(&This->IMoniker_iface);
515 }
516 
UriContainer_GetIUri(IUriContainer * iface,IUri ** ppIUri)517 static HRESULT WINAPI UriContainer_GetIUri(IUriContainer *iface, IUri **ppIUri)
518 {
519     URLMoniker *This = impl_from_IUriContainer(iface);
520 
521     TRACE("(%p)->(%p)\n", This, ppIUri);
522 
523     if(!This->uri) {
524         *ppIUri = NULL;
525         return S_FALSE;
526     }
527 
528     IUri_AddRef(This->uri);
529     *ppIUri = This->uri;
530     return S_OK;
531 }
532 
533 static const IUriContainerVtbl UriContainerVtbl = {
534     UriContainer_QueryInterface,
535     UriContainer_AddRef,
536     UriContainer_Release,
537     UriContainer_GetIUri
538 };
539 
create_moniker(IUri * uri,URLMoniker ** ret)540 static HRESULT create_moniker(IUri *uri, URLMoniker **ret)
541 {
542     URLMoniker *mon;
543     HRESULT hres;
544 
545     mon = heap_alloc(sizeof(*mon));
546     if(!mon)
547         return E_OUTOFMEMORY;
548 
549     mon->IMoniker_iface.lpVtbl = &URLMonikerVtbl;
550     mon->IUriContainer_iface.lpVtbl = &UriContainerVtbl;
551     mon->ref = 1;
552 
553     if(uri) {
554         /* FIXME: try to avoid it */
555         hres = IUri_GetDisplayUri(uri, &mon->URLName);
556         if(FAILED(hres)) {
557             heap_free(mon);
558             return hres;
559         }
560 
561         IUri_AddRef(uri);
562         mon->uri = uri;
563     }else {
564         mon->URLName = NULL;
565         mon->uri = NULL;
566     }
567 
568     URLMON_LockModule();
569     *ret = mon;
570     return S_OK;
571 }
572 
StdURLMoniker_Construct(IUnknown * outer,void ** ppv)573 HRESULT StdURLMoniker_Construct(IUnknown *outer, void **ppv)
574 {
575     URLMoniker *mon;
576     HRESULT hres;
577 
578     TRACE("(%p %p)\n", outer, ppv);
579 
580     hres = create_moniker(NULL, &mon);
581     if(FAILED(hres))
582         return hres;
583 
584     *ppv = &mon->IMoniker_iface;
585     return S_OK;
586 }
587 
588 static const DWORD create_flags_map[3] = {
589     Uri_CREATE_FILE_USE_DOS_PATH,  /* URL_MK_LEGACY */
590     0,                             /* URL_MK_UNIFORM */
591     Uri_CREATE_NO_CANONICALIZE     /* URL_MK_NO_CANONICALIZE */
592 };
593 
594 static const DWORD combine_flags_map[3] = {
595     URL_FILE_USE_PATHURL,  /* URL_MK_LEGACY */
596     0,                     /* URL_MK_UNIFORM */
597     URL_DONT_SIMPLIFY      /* URL_MK_NO_CANONICALIZE */
598 };
599 
600 /***********************************************************************
601  *           CreateURLMonikerEx (URLMON.@)
602  *
603  * Create a url moniker.
604  *
605  * PARAMS
606  *    pmkContext [I] Context
607  *    szURL      [I] Url to create the moniker for
608  *    ppmk       [O] Destination for created moniker.
609  *    dwFlags    [I] Flags.
610  *
611  * RETURNS
612  *    Success: S_OK. ppmk contains the created IMoniker object.
613  *    Failure: MK_E_SYNTAX if szURL is not a valid url, or
614  *             E_OUTOFMEMORY if memory allocation fails.
615  */
CreateURLMonikerEx(IMoniker * pmkContext,LPCWSTR szURL,IMoniker ** ppmk,DWORD dwFlags)616 HRESULT WINAPI CreateURLMonikerEx(IMoniker *pmkContext, LPCWSTR szURL, IMoniker **ppmk, DWORD dwFlags)
617 {
618     IUri *uri, *base_uri = NULL;
619     URLMoniker *obj;
620     HRESULT hres;
621 
622     TRACE("(%p, %s, %p, %08x)\n", pmkContext, debugstr_w(szURL), ppmk, dwFlags);
623 
624     if (ppmk)
625         *ppmk = NULL;
626 
627     if (!szURL || !ppmk)
628         return E_INVALIDARG;
629 
630     if(dwFlags >= ARRAY_SIZE(create_flags_map)) {
631         FIXME("Unsupported flags %x\n", dwFlags);
632         return E_INVALIDARG;
633     }
634 
635     if(pmkContext) {
636         IUriContainer *uri_container;
637 
638         hres = IMoniker_QueryInterface(pmkContext, &IID_IUriContainer, (void**)&uri_container);
639         if(SUCCEEDED(hres)) {
640             hres = IUriContainer_GetIUri(uri_container, &base_uri);
641             IUriContainer_Release(uri_container);
642             if(FAILED(hres))
643                 return hres;
644         }
645     }
646 
647     if(base_uri) {
648         hres = CoInternetCombineUrlEx(base_uri, szURL, combine_flags_map[dwFlags], &uri, 0);
649         IUri_Release(base_uri);
650     }else {
651         hres = CreateUri(szURL, Uri_CREATE_ALLOW_RELATIVE|Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME|create_flags_map[dwFlags], 0, &uri);
652     }
653     if(FAILED(hres))
654         return hres;
655 
656     hres = create_moniker(uri, &obj);
657     IUri_Release(uri);
658     if(FAILED(hres))
659 	return hres;
660 
661     *ppmk = &obj->IMoniker_iface;
662     return S_OK;
663 }
664 
665 /***********************************************************************
666  *           CreateURLMonikerEx2 (URLMON.@)
667  */
CreateURLMonikerEx2(IMoniker * pmkContext,IUri * pUri,IMoniker ** ppmk,DWORD dwFlags)668 HRESULT WINAPI CreateURLMonikerEx2(IMoniker *pmkContext, IUri *pUri, IMoniker **ppmk, DWORD dwFlags)
669 {
670     IUri *context_uri = NULL, *uri;
671     IUriContainer *uri_container;
672     URLMoniker *ret;
673     HRESULT hres;
674 
675     TRACE("(%p %p %p %x)\n", pmkContext, pUri, ppmk, dwFlags);
676 
677     if (ppmk)
678         *ppmk = NULL;
679 
680     if (!pUri || !ppmk)
681         return E_INVALIDARG;
682 
683     if(dwFlags >= ARRAY_SIZE(create_flags_map)) {
684         FIXME("Unsupported flags %x\n", dwFlags);
685         return E_INVALIDARG;
686     }
687 
688     if(pmkContext) {
689         hres = IMoniker_QueryInterface(pmkContext, &IID_IUriContainer, (void**)&uri_container);
690         if(SUCCEEDED(hres)) {
691             hres = IUriContainer_GetIUri(uri_container, &context_uri);
692             if(FAILED(hres))
693                 context_uri = NULL;
694             IUriContainer_Release(uri_container);
695         }
696     }
697 
698     if(context_uri) {
699         hres = CoInternetCombineIUri(context_uri, pUri, combine_flags_map[dwFlags], &uri, 0);
700         IUri_Release(context_uri);
701         if(FAILED(hres))
702             return hres;
703     }else {
704         uri = pUri;
705         IUri_AddRef(uri);
706     }
707 
708     hres = create_moniker(uri, &ret);
709     IUri_Release(uri);
710     if(FAILED(hres))
711         return hres;
712 
713     *ppmk = &ret->IMoniker_iface;
714     return S_OK;
715 }
716 
717 /**********************************************************************
718  *           CreateURLMoniker (URLMON.@)
719  *
720  * Create a url moniker.
721  *
722  * PARAMS
723  *    pmkContext [I] Context
724  *    szURL      [I] Url to create the moniker for
725  *    ppmk       [O] Destination for created moniker.
726  *
727  * RETURNS
728  *    Success: S_OK. ppmk contains the created IMoniker object.
729  *    Failure: MK_E_SYNTAX if szURL is not a valid url, or
730  *             E_OUTOFMEMORY if memory allocation fails.
731  */
CreateURLMoniker(IMoniker * pmkContext,LPCWSTR szURL,IMoniker ** ppmk)732 HRESULT WINAPI CreateURLMoniker(IMoniker *pmkContext, LPCWSTR szURL, IMoniker **ppmk)
733 {
734     return CreateURLMonikerEx(pmkContext, szURL, ppmk, URL_MK_LEGACY);
735 }
736 
737 /***********************************************************************
738  *           IsAsyncMoniker (URLMON.@)
739  */
IsAsyncMoniker(IMoniker * pmk)740 HRESULT WINAPI IsAsyncMoniker(IMoniker *pmk)
741 {
742     IUnknown *am;
743 
744     TRACE("(%p)\n", pmk);
745     if(!pmk)
746         return E_INVALIDARG;
747     if(SUCCEEDED(IMoniker_QueryInterface(pmk, &IID_IAsyncMoniker, (void**)&am))) {
748         IUnknown_Release(am);
749         return S_OK;
750     }
751     return S_FALSE;
752 }
753 
754 /***********************************************************************
755  *           BindAsyncMoniker (URLMON.@)
756  *
757  * Bind a bind status callback to an asynchronous URL Moniker.
758  *
759  * PARAMS
760  *  pmk           [I] Moniker object to bind status callback to
761  *  grfOpt        [I] Options, seems not used
762  *  pbsc          [I] Status callback to bind
763  *  iidResult     [I] Interface to return
764  *  ppvResult     [O] Resulting asynchronous moniker object
765  *
766  * RETURNS
767  *    Success: S_OK.
768  *    Failure: E_INVALIDARG, if any argument is invalid, or
769  *             E_OUTOFMEMORY if memory allocation fails.
770  */
BindAsyncMoniker(IMoniker * pmk,DWORD grfOpt,IBindStatusCallback * pbsc,REFIID iidResult,LPVOID * ppvResult)771 HRESULT WINAPI BindAsyncMoniker(IMoniker *pmk, DWORD grfOpt, IBindStatusCallback *pbsc, REFIID iidResult, LPVOID *ppvResult)
772 {
773     LPBC pbc = NULL;
774     HRESULT hr = E_INVALIDARG;
775 
776     TRACE("(%p %08x %p %s %p)\n", pmk, grfOpt, pbsc, debugstr_guid(iidResult), ppvResult);
777 
778     if (pmk && ppvResult)
779     {
780         *ppvResult = NULL;
781 
782         hr = CreateAsyncBindCtx(0, pbsc, NULL, &pbc);
783         if (hr == NOERROR)
784         {
785             hr = IMoniker_BindToObject(pmk, pbc, NULL, iidResult, ppvResult);
786             IBindCtx_Release(pbc);
787         }
788     }
789     return hr;
790 }
791 
792 /***********************************************************************
793  *           MkParseDisplayNameEx (URLMON.@)
794  */
MkParseDisplayNameEx(IBindCtx * pbc,LPCWSTR szDisplayName,ULONG * pchEaten,LPMONIKER * ppmk)795 HRESULT WINAPI MkParseDisplayNameEx(IBindCtx *pbc, LPCWSTR szDisplayName, ULONG *pchEaten, LPMONIKER *ppmk)
796 {
797     TRACE("(%p %s %p %p)\n", pbc, debugstr_w(szDisplayName), pchEaten, ppmk);
798 
799     if (!pbc || !szDisplayName || !*szDisplayName || !pchEaten || !ppmk)
800         return E_INVALIDARG;
801 
802     if(is_registered_protocol(szDisplayName)) {
803         HRESULT hres;
804 
805         hres = CreateURLMoniker(NULL, szDisplayName, ppmk);
806         if(SUCCEEDED(hres)) {
807             *pchEaten = lstrlenW(szDisplayName);
808             return hres;
809         }
810     }
811 
812     return MkParseDisplayName(pbc, szDisplayName, pchEaten, ppmk);
813 }
814 
815 
816 /***********************************************************************
817  *           URLDownloadToCacheFileA (URLMON.@)
818  */
URLDownloadToCacheFileA(LPUNKNOWN lpUnkCaller,LPCSTR szURL,LPSTR szFileName,DWORD dwBufLength,DWORD dwReserved,LPBINDSTATUSCALLBACK pBSC)819 HRESULT WINAPI URLDownloadToCacheFileA(LPUNKNOWN lpUnkCaller, LPCSTR szURL, LPSTR szFileName,
820         DWORD dwBufLength, DWORD dwReserved, LPBINDSTATUSCALLBACK pBSC)
821 {
822     LPWSTR url = NULL, file_name = NULL;
823     int len;
824     HRESULT hres;
825 
826     TRACE("(%p %s %p %d %d %p)\n", lpUnkCaller, debugstr_a(szURL), szFileName,
827             dwBufLength, dwReserved, pBSC);
828 
829     if(szURL) {
830         len = MultiByteToWideChar(CP_ACP, 0, szURL, -1, NULL, 0);
831         url = heap_alloc(len*sizeof(WCHAR));
832         MultiByteToWideChar(CP_ACP, 0, szURL, -1, url, len);
833     }
834 
835     if(szFileName)
836         file_name = heap_alloc(dwBufLength*sizeof(WCHAR));
837 
838     hres = URLDownloadToCacheFileW(lpUnkCaller, url, file_name, dwBufLength*sizeof(WCHAR),
839             dwReserved, pBSC);
840 
841     if(SUCCEEDED(hres) && file_name)
842         WideCharToMultiByte(CP_ACP, 0, file_name, -1, szFileName, dwBufLength, NULL, NULL);
843 
844     heap_free(url);
845     heap_free(file_name);
846 
847     return hres;
848 }
849 
850 /***********************************************************************
851  *           URLDownloadToCacheFileW (URLMON.@)
852  */
URLDownloadToCacheFileW(LPUNKNOWN lpUnkCaller,LPCWSTR szURL,LPWSTR szFileName,DWORD dwBufLength,DWORD dwReserved,LPBINDSTATUSCALLBACK pBSC)853 HRESULT WINAPI URLDownloadToCacheFileW(LPUNKNOWN lpUnkCaller, LPCWSTR szURL, LPWSTR szFileName,
854                 DWORD dwBufLength, DWORD dwReserved, LPBINDSTATUSCALLBACK pBSC)
855 {
856     WCHAR cache_path[MAX_PATH + 1];
857     FILETIME expire, modified;
858     HRESULT hr;
859     LPWSTR ext;
860 
861     static WCHAR header[] = {
862         'H','T','T','P','/','1','.','0',' ','2','0','0',' ',
863         'O','K','\\','r','\\','n','\\','r','\\','n',0
864     };
865 
866     TRACE("(%p, %s, %p, %d, %d, %p)\n", lpUnkCaller, debugstr_w(szURL),
867           szFileName, dwBufLength, dwReserved, pBSC);
868 
869     if (!szURL || !szFileName)
870         return E_INVALIDARG;
871 
872     ext = PathFindExtensionW(szURL);
873 
874     if (!CreateUrlCacheEntryW(szURL, 0, ext, cache_path, 0))
875         return E_FAIL;
876 
877     hr = URLDownloadToFileW(lpUnkCaller, szURL, cache_path, 0, pBSC);
878     if (FAILED(hr))
879         return hr;
880 
881     expire.dwHighDateTime = 0;
882     expire.dwLowDateTime = 0;
883     modified.dwHighDateTime = 0;
884     modified.dwLowDateTime = 0;
885 
886     if (!CommitUrlCacheEntryW(szURL, cache_path, expire, modified, NORMAL_CACHE_ENTRY,
887                               header, sizeof(header), NULL, NULL))
888         return E_FAIL;
889 
890     if (lstrlenW(cache_path) > dwBufLength)
891         return E_OUTOFMEMORY;
892 
893     lstrcpyW(szFileName, cache_path);
894 
895     return S_OK;
896 }
897 
898 /***********************************************************************
899  *           HlinkSimpleNavigateToMoniker (URLMON.@)
900  */
HlinkSimpleNavigateToMoniker(IMoniker * pmkTarget,LPCWSTR szLocation,LPCWSTR szTargetFrameName,IUnknown * pUnk,IBindCtx * pbc,IBindStatusCallback * pbsc,DWORD grfHLNF,DWORD dwReserved)901 HRESULT WINAPI HlinkSimpleNavigateToMoniker(IMoniker *pmkTarget,
902     LPCWSTR szLocation, LPCWSTR szTargetFrameName, IUnknown *pUnk,
903     IBindCtx *pbc, IBindStatusCallback *pbsc, DWORD grfHLNF, DWORD dwReserved)
904 {
905     LPWSTR target;
906     HRESULT hres;
907 
908     TRACE("\n");
909 
910     hres = IMoniker_GetDisplayName(pmkTarget, pbc, 0, &target);
911     if(hres == S_OK)
912         hres = HlinkSimpleNavigateToString( target, szLocation, szTargetFrameName,
913                                             pUnk, pbc, pbsc, grfHLNF, dwReserved );
914     CoTaskMemFree(target);
915 
916     return hres;
917 }
918 
919 /***********************************************************************
920  *           HlinkSimpleNavigateToString (URLMON.@)
921  */
HlinkSimpleNavigateToString(LPCWSTR szTarget,LPCWSTR szLocation,LPCWSTR szTargetFrameName,IUnknown * pUnk,IBindCtx * pbc,IBindStatusCallback * pbsc,DWORD grfHLNF,DWORD dwReserved)922 HRESULT WINAPI HlinkSimpleNavigateToString( LPCWSTR szTarget,
923     LPCWSTR szLocation, LPCWSTR szTargetFrameName, IUnknown *pUnk,
924     IBindCtx *pbc, IBindStatusCallback *pbsc, DWORD grfHLNF, DWORD dwReserved)
925 {
926     FIXME("%s %s %s %p %p %p %u %u partial stub\n", debugstr_w( szTarget ), debugstr_w( szLocation ),
927           debugstr_w( szTargetFrameName ), pUnk, pbc, pbsc, grfHLNF, dwReserved);
928 
929     /* undocumented: 0 means HLNF_OPENINNEWWINDOW*/
930     if (!grfHLNF) grfHLNF = HLNF_OPENINNEWWINDOW;
931 
932     if (grfHLNF == HLNF_OPENINNEWWINDOW)
933     {
934         SHELLEXECUTEINFOW sei;
935         static const WCHAR openW[] = { 'o', 'p', 'e', 'n', 0 };
936 
937         memset(&sei, 0, sizeof(sei));
938         sei.cbSize = sizeof(sei);
939         sei.lpVerb = openW;
940         sei.nShow = SW_SHOWNORMAL;
941         sei.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_NO_CONSOLE;
942         sei.lpFile = szTarget;
943 
944         if (ShellExecuteExW(&sei)) return S_OK;
945     }
946 
947     return E_NOTIMPL;
948 }
949 
950 /***********************************************************************
951  *           HlinkNavigateString (URLMON.@)
952  */
HlinkNavigateString(IUnknown * pUnk,LPCWSTR szTarget)953 HRESULT WINAPI HlinkNavigateString( IUnknown *pUnk, LPCWSTR szTarget )
954 {
955     TRACE("%p %s\n", pUnk, debugstr_w( szTarget ) );
956     return HlinkSimpleNavigateToString(
957                szTarget, NULL, NULL, pUnk, NULL, NULL, 0, 0 );
958 }
959 
960 /***********************************************************************
961  *           GetSoftwareUpdateInfo (URLMON.@)
962  */
GetSoftwareUpdateInfo(LPCWSTR szDistUnit,LPSOFTDISTINFO psdi)963 HRESULT WINAPI GetSoftwareUpdateInfo( LPCWSTR szDistUnit, LPSOFTDISTINFO psdi )
964 {
965     FIXME("%s %p\n", debugstr_w(szDistUnit), psdi );
966     return E_FAIL;
967 }
968