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