umon.c 26.6 KB
Newer Older
1 2 3
/*
 * UrlMon
 *
Jon Griffiths's avatar
Jon Griffiths committed
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 9 10 11 12 13 14 15 16 17 18 19
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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
 */

Jacek Caban's avatar
Jacek Caban committed
23
#include "urlmon_main.h"
24

25
#include "winreg.h"
26
#include "shlwapi.h"
27 28
#include "hlink.h"
#include "shellapi.h"
Jacek Caban's avatar
Jacek Caban committed
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

Jacek Caban's avatar
Jacek Caban committed
38
    LONG ref;
39

40
    IUri *uri;
41
    BSTR URLName;
Jacek Caban's avatar
Jacek Caban committed
42
} URLMoniker;
43

44 45 46 47
static inline URLMoniker *impl_from_IMoniker(IMoniker *iface)
{
    return CONTAINING_RECORD(iface, URLMoniker, IMoniker_iface);
}
48

Jacek Caban's avatar
Jacek Caban committed
49 50
static HRESULT WINAPI URLMoniker_QueryInterface(IMoniker *iface, REFIID riid, void **ppv)
{
51
    URLMoniker *This = impl_from_IMoniker(iface);
52

Jacek Caban's avatar
Jacek Caban committed
53
    if(!ppv)
54 55
	return E_INVALIDARG;

Jacek Caban's avatar
Jacek Caban committed
56 57 58 59 60 61 62 63 64 65 66 67
    if(IsEqualIID(&IID_IUnknown, riid)) {
        TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
        *ppv = iface;
    }else if(IsEqualIID(&IID_IPersist, riid)) {
        TRACE("(%p)->(IID_IPersist %p)\n", This, ppv);
        *ppv = iface;
    }else if(IsEqualIID(&IID_IPersistStream,riid)) {
        TRACE("(%p)->(IID_IPersistStream %p)\n", This, ppv);
        *ppv = iface;
    }else if(IsEqualIID(&IID_IMoniker, riid)) {
        TRACE("(%p)->(IID_IMoniker %p)\n", This, ppv);
        *ppv = iface;
68 69 70
    }else if(IsEqualIID(&IID_IAsyncMoniker, riid)) {
        TRACE("(%p)->(IID_IAsyncMoniker %p)\n", This, ppv);
        *ppv = iface;
71 72 73
    }else if(IsEqualIID(&IID_IUriContainer, riid)) {
        TRACE("(%p)->(IID_IUriContainer %p)\n", This, ppv);
        *ppv = &This->IUriContainer_iface;
Jacek Caban's avatar
Jacek Caban committed
74 75 76
    }else {
        WARN("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppv);
        *ppv = NULL;
77
        return E_NOINTERFACE;
Jacek Caban's avatar
Jacek Caban committed
78
    }
79

Jacek Caban's avatar
Jacek Caban committed
80
    IMoniker_AddRef((IUnknown*)*ppv);
81 82 83
    return S_OK;
}

Jacek Caban's avatar
Jacek Caban committed
84
static ULONG WINAPI URLMoniker_AddRef(IMoniker *iface)
85
{
86
    URLMoniker *This = impl_from_IMoniker(iface);
87 88
    ULONG refCount = InterlockedIncrement(&This->ref);

Jacek Caban's avatar
Jacek Caban committed
89
    TRACE("(%p) ref=%u\n",This, refCount);
90 91 92 93

    return refCount;
}

Jacek Caban's avatar
Jacek Caban committed
94
static ULONG WINAPI URLMoniker_Release(IMoniker *iface)
95
{
96
    URLMoniker *This = impl_from_IMoniker(iface);
97 98
    ULONG refCount = InterlockedDecrement(&This->ref);

Jacek Caban's avatar
Jacek Caban committed
99
    TRACE("(%p) ref=%u\n",This, refCount);
100 101

    if (!refCount) {
102 103
        if(This->uri)
            IUri_Release(This->uri);
104
        SysFreeString(This->URLName);
105
        heap_free(This);
106

Jacek Caban's avatar
Jacek Caban committed
107 108
        URLMON_UnlockModule();
    }
109 110 111 112

    return refCount;
}

Jacek Caban's avatar
Jacek Caban committed
113
static HRESULT WINAPI URLMoniker_GetClassID(IMoniker *iface, CLSID *pClassID)
114
{
115
    URLMoniker *This = impl_from_IMoniker(iface);
116

Jacek Caban's avatar
Jacek Caban committed
117
    TRACE("(%p,%p)\n", This, pClassID);
118

Jacek Caban's avatar
Jacek Caban committed
119
    if(!pClassID)
120
        return E_POINTER;
Jacek Caban's avatar
Jacek Caban committed
121

122 123 124
    /* Windows always returns CLSID_StdURLMoniker */
    *pClassID = CLSID_StdURLMoniker;
    return S_OK;
125 126
}

Jacek Caban's avatar
Jacek Caban committed
127
static HRESULT WINAPI URLMoniker_IsDirty(IMoniker *iface)
128
{
129
    URLMoniker *This = impl_from_IMoniker(iface);
130 131 132

    TRACE("(%p)\n",This);

Jacek Caban's avatar
Jacek Caban committed
133 134 135
    /* Note that the OLE-provided implementations of the IPersistStream::IsDirty
       method in the OLE-provided moniker interfaces always return S_FALSE because
       their internal state never changes. */
136 137 138
    return S_FALSE;
}

Jacek Caban's avatar
Jacek Caban committed
139
static HRESULT WINAPI URLMoniker_Load(IMoniker* iface,IStream* pStm)
140
{
141
    URLMoniker *This = impl_from_IMoniker(iface);
142 143 144
    WCHAR *new_uri_str;
    IUri *new_uri;
    BSTR new_url;
145
    ULONG size;
146
    ULONG got;
147
    HRESULT hres;
Jacek Caban's avatar
Jacek Caban committed
148

149 150 151 152 153
    TRACE("(%p,%p)\n",This,pStm);

    if(!pStm)
        return E_INVALIDARG;

Jacek Caban's avatar
Jacek Caban committed
154 155 156 157 158
    /*
     * NOTE
     *  Writes a ULONG containing length of unicode string, followed
     *  by that many unicode characters
     */
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
    hres = IStream_Read(pStm, &size, sizeof(ULONG), &got);
    if(FAILED(hres))
        return hres;
    if(got != sizeof(ULONG))
        return E_FAIL;

    new_uri_str = heap_alloc(size+sizeof(WCHAR));
    if(!new_uri_str)
        return E_OUTOFMEMORY;

    hres = IStream_Read(pStm, new_uri_str, size, NULL);
    new_uri_str[size/sizeof(WCHAR)] = 0;
    if(SUCCEEDED(hres))
        hres = CreateUri(new_uri_str, 0, 0, &new_uri);
    heap_free(new_uri_str);
    if(FAILED(hres))
        return hres;

    hres = IUri_GetDisplayUri(new_uri, &new_url);
    if(FAILED(hres)) {
        IUri_Release(new_uri);
        return hres;
181
    }
Jacek Caban's avatar
Jacek Caban committed
182

183 184 185 186 187 188 189
    SysFreeString(This->URLName);
    if(This->uri)
        IUri_Release(This->uri);

    This->uri = new_uri;
    This->URLName = new_url;
    return S_OK;
190 191
}

Jacek Caban's avatar
Jacek Caban committed
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;
Jacek Caban's avatar
Jacek Caban committed
197 198

    TRACE("(%p,%p,%d)\n", This, pStm, fClearDirty);
199

200 201 202
    if(!pStm)
        return E_INVALIDARG;

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);
Jacek Caban's avatar
Jacek Caban committed
207

208
    return res;
209 210 211

}

Jacek Caban's avatar
Jacek Caban committed
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 219 220
    if(!pcbSize)
        return E_INVALIDARG;

221
    pcbSize->QuadPart = sizeof(ULONG) + ((SysStringLen(This->URLName)+1) * sizeof(WCHAR));
222
    return S_OK;
223 224
}

Jacek Caban's avatar
Jacek Caban committed
225 226
static HRESULT WINAPI URLMoniker_BindToObject(IMoniker *iface, IBindCtx* pbc, IMoniker *pmkToLeft,
        REFIID riid, void **ppv)
227
{
228
    URLMoniker *This = impl_from_IMoniker(iface);
229 230
    IRunningObjectTable *obj_tbl;
    HRESULT hres;
231

232
    TRACE("(%p)->(%p,%p,%s,%p)\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppv);
233

234 235 236 237 238
    hres = IBindCtx_GetRunningObjectTable(pbc, &obj_tbl);
    if(SUCCEEDED(hres)) {
        FIXME("use running object table\n");
        IRunningObjectTable_Release(obj_tbl);
    }
239

240 241 242 243
    if(!This->uri) {
        *ppv = NULL;
        return MK_E_SYNTAX;
    }
244

245
    return bind_to_object(&This->IMoniker_iface, This->uri, pbc, riid, ppv);
246 247
}

Jacek Caban's avatar
Jacek Caban committed
248 249
static HRESULT WINAPI URLMoniker_BindToStorage(IMoniker* iface, IBindCtx* pbc,
        IMoniker* pmkToLeft, REFIID riid, void **ppvObject)
250
{
251
    URLMoniker *This = impl_from_IMoniker(iface);
252

253
    TRACE("(%p)->(%p %p %s %p)\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppvObject);
254

255 256 257 258
    if(ppvObject) *ppvObject = NULL;

    if(!pbc || !ppvObject) return E_INVALIDARG;

259
    if(pmkToLeft)
260
        FIXME("Unsupported pmkToLeft\n");
261

262 263
    if(!This->uri)
        return MK_E_SYNTAX;
264

265
    return bind_to_storage(This->uri, pbc, riid, ppvObject);
266 267
}

Jacek Caban's avatar
Jacek Caban committed
268 269
static HRESULT WINAPI URLMoniker_Reduce(IMoniker *iface, IBindCtx *pbc,
        DWORD dwReduceHowFar, IMoniker **ppmkToLeft, IMoniker **ppmkReduced)
270
{
271 272
    URLMoniker *This = impl_from_IMoniker(iface);

Jacek Caban's avatar
Jacek Caban committed
273
    TRACE("(%p,%p,%d,%p,%p)\n", This, pbc, dwReduceHowFar, ppmkToLeft, ppmkReduced);
274

275 276 277
    if(!ppmkReduced)
        return E_INVALIDARG;

Jacek Caban's avatar
Jacek Caban committed
278
    IMoniker_AddRef(iface);
279 280
    *ppmkReduced = iface;
    return MK_S_REDUCED_TO_SELF;
281 282
}

Jacek Caban's avatar
Jacek Caban committed
283 284
static HRESULT WINAPI URLMoniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight,
        BOOL fOnlyIfNotGeneric, IMoniker **ppmkComposite)
285
{
286
    URLMoniker *This = impl_from_IMoniker(iface);
287 288 289 290
    FIXME("(%p)->(%p,%d,%p): stub\n",This,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
    return E_NOTIMPL;
}

Jacek Caban's avatar
Jacek Caban committed
291
static HRESULT WINAPI URLMoniker_Enum(IMoniker *iface, BOOL fForward, IEnumMoniker **ppenumMoniker)
292
{
293
    URLMoniker *This = impl_from_IMoniker(iface);
Jacek Caban's avatar
Jacek Caban committed
294 295

    TRACE("(%p,%d,%p)\n", This, fForward, ppenumMoniker);
296

297 298 299 300 301 302
    if(!ppenumMoniker)
        return E_INVALIDARG;

    /* Does not support sub-monikers */
    *ppenumMoniker = NULL;
    return S_OK;
303 304
}

Jacek Caban's avatar
Jacek Caban committed
305
static HRESULT WINAPI URLMoniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker)
306
{
307
    URLMoniker *This = impl_from_IMoniker(iface);
Kevin Koltzau's avatar
Kevin Koltzau committed
308 309 310 311
    CLSID clsid;
    LPOLESTR urlPath;
    IBindCtx* bind;
    HRESULT res;
312

Jacek Caban's avatar
Jacek Caban committed
313
    TRACE("(%p,%p)\n",This, pmkOtherMoniker);
Kevin Koltzau's avatar
Kevin Koltzau committed
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335

    if(pmkOtherMoniker==NULL)
        return E_INVALIDARG;

    IMoniker_GetClassID(pmkOtherMoniker,&clsid);

    if(!IsEqualCLSID(&clsid,&CLSID_StdURLMoniker))
        return S_FALSE;

    res = CreateBindCtx(0,&bind);
    if(FAILED(res))
        return res;

    res = S_FALSE;
    if(SUCCEEDED(IMoniker_GetDisplayName(pmkOtherMoniker,bind,NULL,&urlPath))) {
        int result = lstrcmpiW(urlPath, This->URLName);
        CoTaskMemFree(urlPath);
        if(result == 0)
            res = S_OK;
    }
    IUnknown_Release(bind);
    return res;
336 337 338
}


Jacek Caban's avatar
Jacek Caban committed
339
static HRESULT WINAPI URLMoniker_Hash(IMoniker *iface, DWORD *pdwHash)
340
{
341
    URLMoniker *This = impl_from_IMoniker(iface);
342 343 344
    int  h = 0,i,skip,len;
    int  off = 0;
    LPOLESTR val;
345

346 347 348 349 350 351 352 353 354 355 356 357
    TRACE("(%p,%p)\n",This,pdwHash);

    if(!pdwHash)
        return E_INVALIDARG;

    val = This->URLName;
    len = lstrlenW(val);

    if(len < 16) {
        for(i = len ; i > 0; i--) {
            h = (h * 37) + val[off++];
        }
Jacek Caban's avatar
Jacek Caban committed
358
    }else {
359 360 361 362 363 364 365 366
        /* only sample some characters */
        skip = len / 8;
        for(i = len; i > 0; i -= skip, off += skip) {
            h = (h * 39) + val[off];
        }
    }
    *pdwHash = h;
    return S_OK;
367 368
}

Jacek Caban's avatar
Jacek Caban committed
369 370
static HRESULT WINAPI URLMoniker_IsRunning(IMoniker* iface, IBindCtx* pbc,
        IMoniker *pmkToLeft, IMoniker *pmkNewlyRunning)
371
{
372
    URLMoniker *This = impl_from_IMoniker(iface);
373 374 375 376
    FIXME("(%p)->(%p,%p,%p): stub\n",This,pbc,pmkToLeft,pmkNewlyRunning);
    return E_NOTIMPL;
}

Jacek Caban's avatar
Jacek Caban committed
377 378
static HRESULT WINAPI URLMoniker_GetTimeOfLastChange(IMoniker *iface,
        IBindCtx *pbc, IMoniker *pmkToLeft, FILETIME *pFileTime)
379
{
380
    URLMoniker *This = impl_from_IMoniker(iface);
Jacek Caban's avatar
Jacek Caban committed
381
    FIXME("(%p)->(%p,%p,%p): stub\n", This, pbc, pmkToLeft, pFileTime);
382 383 384
    return E_NOTIMPL;
}

Jacek Caban's avatar
Jacek Caban committed
385
static HRESULT WINAPI URLMoniker_Inverse(IMoniker *iface, IMoniker **ppmk)
386
{
387
    URLMoniker *This = impl_from_IMoniker(iface);
388 389
    TRACE("(%p,%p)\n",This,ppmk);
    return MK_E_NOINVERSE;
390 391
}

Jacek Caban's avatar
Jacek Caban committed
392
static HRESULT WINAPI URLMoniker_CommonPrefixWith(IMoniker *iface, IMoniker *pmkOther, IMoniker **ppmkPrefix)
393
{
394
    URLMoniker *This = impl_from_IMoniker(iface);
395 396 397 398
    FIXME("(%p)->(%p,%p): stub\n",This,pmkOther,ppmkPrefix);
    return E_NOTIMPL;
}

Jacek Caban's avatar
Jacek Caban committed
399
static HRESULT WINAPI URLMoniker_RelativePathTo(IMoniker *iface, IMoniker *pmOther, IMoniker **ppmkRelPath)
400
{
401
    URLMoniker *This = impl_from_IMoniker(iface);
402 403 404 405
    FIXME("(%p)->(%p,%p): stub\n",This,pmOther,ppmkRelPath);
    return E_NOTIMPL;
}

Jacek Caban's avatar
Jacek Caban committed
406 407
static HRESULT WINAPI URLMoniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
        LPOLESTR *ppszDisplayName)
408
{
409
    URLMoniker *This = impl_from_IMoniker(iface);
410 411
    int len;
    
Jacek Caban's avatar
Jacek Caban committed
412
    TRACE("(%p,%p,%p,%p)\n", This, pbc, pmkToLeft, ppszDisplayName);
413 414 415
    
    if(!ppszDisplayName)
        return E_INVALIDARG;
416

417 418 419
    if(!This->URLName)
        return E_OUTOFMEMORY;

420 421 422
    /* FIXME: If this is a partial URL, try and get a URL moniker from SZ_URLCONTEXT in the bind context,
        then look at pmkToLeft to try and complete the URL
    */
423
    len = SysStringLen(This->URLName)+1;
424 425 426 427 428
    *ppszDisplayName = CoTaskMemAlloc(len*sizeof(WCHAR));
    if(!*ppszDisplayName)
        return E_OUTOFMEMORY;
    lstrcpyW(*ppszDisplayName, This->URLName);
    return S_OK;
429 430
}

Jacek Caban's avatar
Jacek Caban committed
431 432
static HRESULT WINAPI URLMoniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
        LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut)
433
{
434
    URLMoniker *This = impl_from_IMoniker(iface);
435 436 437 438
    FIXME("(%p)->(%p,%p,%p,%p,%p): stub\n",This,pbc,pmkToLeft,pszDisplayName,pchEaten,ppmkOut);
    return E_NOTIMPL;
}

Jacek Caban's avatar
Jacek Caban committed
439
static HRESULT WINAPI URLMoniker_IsSystemMoniker(IMoniker *iface, DWORD *pwdMksys)
440
{
441
    URLMoniker *This = impl_from_IMoniker(iface);
Jacek Caban's avatar
Jacek Caban committed
442

443
    TRACE("(%p,%p)\n",This,pwdMksys);
444

445 446 447 448 449
    if(!pwdMksys)
        return E_INVALIDARG;

    *pwdMksys = MKSYS_URLMONIKER;
    return S_OK;
450 451
}

Jacek Caban's avatar
Jacek Caban committed
452
static const IMonikerVtbl URLMonikerVtbl =
453
{
Jacek Caban's avatar
Jacek Caban committed
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
    URLMoniker_QueryInterface,
    URLMoniker_AddRef,
    URLMoniker_Release,
    URLMoniker_GetClassID,
    URLMoniker_IsDirty,
    URLMoniker_Load,
    URLMoniker_Save,
    URLMoniker_GetSizeMax,
    URLMoniker_BindToObject,
    URLMoniker_BindToStorage,
    URLMoniker_Reduce,
    URLMoniker_ComposeWith,
    URLMoniker_Enum,
    URLMoniker_IsEqual,
    URLMoniker_Hash,
    URLMoniker_IsRunning,
    URLMoniker_GetTimeOfLastChange,
    URLMoniker_Inverse,
    URLMoniker_CommonPrefixWith,
    URLMoniker_RelativePathTo,
    URLMoniker_GetDisplayName,
    URLMoniker_ParseDisplayName,
    URLMoniker_IsSystemMoniker
477 478
};

479 480 481 482 483 484 485 486
static inline URLMoniker *impl_from_IUriContainer(IUriContainer *iface)
{
    return CONTAINING_RECORD(iface, URLMoniker, IUriContainer_iface);
}

static HRESULT WINAPI UriContainer_QueryInterface(IUriContainer *iface, REFIID riid, void **ppv)
{
    URLMoniker *This = impl_from_IUriContainer(iface);
487
    return IMoniker_QueryInterface(&This->IMoniker_iface, riid, ppv);
488 489 490 491 492
}

static ULONG WINAPI UriContainer_AddRef(IUriContainer *iface)
{
    URLMoniker *This = impl_from_IUriContainer(iface);
493
    return IMoniker_AddRef(&This->IMoniker_iface);
494 495 496 497 498
}

static ULONG WINAPI UriContainer_Release(IUriContainer *iface)
{
    URLMoniker *This = impl_from_IUriContainer(iface);
499
    return IMoniker_Release(&This->IMoniker_iface);
500 501 502 503 504 505
}

static HRESULT WINAPI UriContainer_GetIUri(IUriContainer *iface, IUri **ppIUri)
{
    URLMoniker *This = impl_from_IUriContainer(iface);

506
    TRACE("(%p)->(%p)\n", This, ppIUri);
507

508 509 510 511 512 513 514 515
    if(!This->uri) {
        *ppIUri = NULL;
        return S_FALSE;
    }

    IUri_AddRef(This->uri);
    *ppIUri = This->uri;
    return S_OK;
516 517 518 519 520 521 522 523 524
}

static const IUriContainerVtbl UriContainerVtbl = {
    UriContainer_QueryInterface,
    UriContainer_AddRef,
    UriContainer_Release,
    UriContainer_GetIUri
};

525
static HRESULT create_moniker(IUri *uri, URLMoniker **ret)
526
{
527
    URLMoniker *mon;
528 529
    HRESULT hres;

530 531 532
    mon = heap_alloc(sizeof(*mon));
    if(!mon)
        return E_OUTOFMEMORY;
533

534 535 536
    mon->IMoniker_iface.lpVtbl = &URLMonikerVtbl;
    mon->IUriContainer_iface.lpVtbl = &UriContainerVtbl;
    mon->ref = 1;
537

538 539 540 541 542 543 544
    if(uri) {
        /* FIXME: try to avoid it */
        hres = IUri_GetDisplayUri(uri, &mon->URLName);
        if(FAILED(hres)) {
            heap_free(mon);
            return hres;
        }
545

546 547 548 549 550 551
        IUri_AddRef(uri);
        mon->uri = uri;
    }else {
        mon->URLName = NULL;
        mon->uri = NULL;
    }
Jacek Caban's avatar
Jacek Caban committed
552

553
    URLMON_LockModule();
554
    *ret = mon;
555 556 557
    return S_OK;
}

558 559
HRESULT StdURLMoniker_Construct(IUnknown *outer, void **ppv)
{
560 561 562
    URLMoniker *mon;
    HRESULT hres;

563 564
    TRACE("(%p %p)\n", outer, ppv);

565 566 567 568 569 570
    hres = create_moniker(NULL, &mon);
    if(FAILED(hres))
        return hres;

    *ppv = &mon->IMoniker_iface;
    return S_OK;
571 572
}

573 574 575 576 577 578 579 580 581 582 583 584
static const DWORD create_flags_map[3] = {
    Uri_CREATE_FILE_USE_DOS_PATH,  /* URL_MK_LEGACY */
    0,                             /* URL_MK_UNIFORM */
    Uri_CREATE_NO_CANONICALIZE     /* URL_MK_NO_CANONICALIZE */
};

static const DWORD combine_flags_map[3] = {
    URL_FILE_USE_PATHURL,  /* URL_MK_LEGACY */
    0,                     /* URL_MK_UNIFORM */
    URL_DONT_SIMPLIFY      /* URL_MK_NO_CANONICALIZE */
};

585
/***********************************************************************
586
 *           CreateURLMonikerEx (URLMON.@)
587
 *
Jon Griffiths's avatar
Jon Griffiths committed
588
 * Create a url moniker.
589
 *
Jon Griffiths's avatar
Jon Griffiths committed
590 591 592 593
 * PARAMS
 *    pmkContext [I] Context
 *    szURL      [I] Url to create the moniker for
 *    ppmk       [O] Destination for created moniker.
594
 *    dwFlags    [I] Flags.
595
 *
Jon Griffiths's avatar
Jon Griffiths committed
596 597 598 599
 * RETURNS
 *    Success: S_OK. ppmk contains the created IMoniker object.
 *    Failure: MK_E_SYNTAX if szURL is not a valid url, or
 *             E_OUTOFMEMORY if memory allocation fails.
600
 */
601
HRESULT WINAPI CreateURLMonikerEx(IMoniker *pmkContext, LPCWSTR szURL, IMoniker **ppmk, DWORD dwFlags)
602
{
603
    IUri *uri, *base_uri = NULL;
Jacek Caban's avatar
Jacek Caban committed
604
    URLMoniker *obj;
605 606
    HRESULT hres;

607 608
    TRACE("(%p, %s, %p, %08x)\n", pmkContext, debugstr_w(szURL), ppmk, dwFlags);

609 610 611 612 613 614
    if (ppmk)
        *ppmk = NULL;

    if (!szURL || !ppmk)
        return E_INVALIDARG;

615
    if(dwFlags >= sizeof(create_flags_map)/sizeof(*create_flags_map)) {
616
        FIXME("Unsupported flags %x\n", dwFlags);
617 618
        return E_INVALIDARG;
    }
619

620
    if(pmkContext) {
621 622 623 624 625 626 627 628
        IUriContainer *uri_container;

        hres = IMoniker_QueryInterface(pmkContext, &IID_IUriContainer, (void**)&uri_container);
        if(SUCCEEDED(hres)) {
            hres = IUriContainer_GetIUri(uri_container, &base_uri);
            IUriContainer_Release(uri_container);
            if(FAILED(hres))
                return hres;
629 630
        }
    }
631 632

    if(base_uri) {
633
        hres = CoInternetCombineUrlEx(base_uri, szURL, combine_flags_map[dwFlags], &uri, 0);
634 635
        IUri_Release(base_uri);
    }else {
636
        hres = CreateUri(szURL, Uri_CREATE_ALLOW_RELATIVE|Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME|create_flags_map[dwFlags], 0, &uri);
637 638 639 640 641 642 643 644 645 646 647
    }
    if(FAILED(hres))
        return hres;

    hres = create_moniker(uri, &obj);
    IUri_Release(uri);
    if(FAILED(hres))
	return hres;

    *ppmk = &obj->IMoniker_iface;
    return S_OK;
648 649
}

650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667
/***********************************************************************
 *           CreateURLMonikerEx2 (URLMON.@)
 */
HRESULT WINAPI CreateURLMonikerEx2(IMoniker *pmkContext, IUri *pUri, IMoniker **ppmk, DWORD dwFlags)
{
    IUri *context_uri = NULL, *uri;
    IUriContainer *uri_container;
    URLMoniker *ret;
    HRESULT hres;

    TRACE("(%p %p %p %x)\n", pmkContext, pUri, ppmk, dwFlags);

    if (ppmk)
        *ppmk = NULL;

    if (!pUri || !ppmk)
        return E_INVALIDARG;

668
    if(dwFlags >= sizeof(create_flags_map)/sizeof(*create_flags_map)) {
669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701
        FIXME("Unsupported flags %x\n", dwFlags);
        return E_INVALIDARG;
    }

    if(pmkContext) {
        hres = IMoniker_QueryInterface(pmkContext, &IID_IUriContainer, (void**)&uri_container);
        if(SUCCEEDED(hres)) {
            hres = IUriContainer_GetIUri(uri_container, &context_uri);
            if(FAILED(hres))
                context_uri = NULL;
            IUriContainer_Release(uri_container);
        }
    }

    if(context_uri) {
        hres = CoInternetCombineIUri(context_uri, pUri, combine_flags_map[dwFlags], &uri, 0);
        IUri_Release(context_uri);
        if(FAILED(hres))
            return hres;
    }else {
        uri = pUri;
        IUri_AddRef(uri);
    }

    hres = create_moniker(uri, &ret);
    IUri_Release(uri);
    if(FAILED(hres))
        return hres;

    *ppmk = &ret->IMoniker_iface;
    return S_OK;
}

702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721
/**********************************************************************
 *           CreateURLMoniker (URLMON.@)
 *
 * Create a url moniker.
 *
 * PARAMS
 *    pmkContext [I] Context
 *    szURL      [I] Url to create the moniker for
 *    ppmk       [O] Destination for created moniker.
 *
 * RETURNS
 *    Success: S_OK. ppmk contains the created IMoniker object.
 *    Failure: MK_E_SYNTAX if szURL is not a valid url, or
 *             E_OUTOFMEMORY if memory allocation fails.
 */
HRESULT WINAPI CreateURLMoniker(IMoniker *pmkContext, LPCWSTR szURL, IMoniker **ppmk)
{
    return CreateURLMonikerEx(pmkContext, szURL, ppmk, URL_MK_LEGACY);
}

722 723 724 725 726
/***********************************************************************
 *           IsAsyncMoniker (URLMON.@)
 */
HRESULT WINAPI IsAsyncMoniker(IMoniker *pmk)
{
727 728 729 730 731 732 733 734 735
    IUnknown *am;
    
    TRACE("(%p)\n", pmk);
    if(!pmk)
        return E_INVALIDARG;
    if(SUCCEEDED(IMoniker_QueryInterface(pmk, &IID_IAsyncMoniker, (void**)&am))) {
        IUnknown_Release(am);
        return S_OK;
    }
736 737 738
    return S_FALSE;
}

739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
/***********************************************************************
 *           BindAsyncMoniker (URLMON.@)
 *
 * Bind a bind status callback to an asynchronous URL Moniker.
 *
 * PARAMS
 *  pmk           [I] Moniker object to bind status callback to
 *  grfOpt        [I] Options, seems not used
 *  pbsc          [I] Status callback to bind
 *  iidResult     [I] Interface to return
 *  ppvResult     [O] Resulting asynchronous moniker object
 *
 * RETURNS
 *    Success: S_OK.
 *    Failure: E_INVALIDARG, if any argument is invalid, or
 *             E_OUTOFMEMORY if memory allocation fails.
 */
HRESULT WINAPI BindAsyncMoniker(IMoniker *pmk, DWORD grfOpt, IBindStatusCallback *pbsc, REFIID iidResult, LPVOID *ppvResult)
{
    LPBC pbc = NULL;
    HRESULT hr = E_INVALIDARG;

761 762
    TRACE("(%p %08x %p %s %p)\n", pmk, grfOpt, pbsc, debugstr_guid(iidResult), ppvResult);

763 764 765 766 767 768 769 770 771 772 773 774 775 776
    if (pmk && ppvResult)
    {
        *ppvResult = NULL;

        hr = CreateAsyncBindCtx(0, pbsc, NULL, &pbc);
        if (hr == NOERROR)
        {
            hr = IMoniker_BindToObject(pmk, pbc, NULL, iidResult, ppvResult);
            IBindCtx_Release(pbc);
        }
    }
    return hr;
}

777 778 779 780 781 782 783
/***********************************************************************
 *           MkParseDisplayNameEx (URLMON.@)
 */
HRESULT WINAPI MkParseDisplayNameEx(IBindCtx *pbc, LPCWSTR szDisplayName, ULONG *pchEaten, LPMONIKER *ppmk)
{
    TRACE("(%p %s %p %p)\n", pbc, debugstr_w(szDisplayName), pchEaten, ppmk);

784 785 786
    if (!pbc || !szDisplayName || !*szDisplayName || !pchEaten || !ppmk)
        return E_INVALIDARG;

787 788 789 790 791 792 793 794 795 796 797 798 799 800
    if(is_registered_protocol(szDisplayName)) {
        HRESULT hres;

        hres = CreateURLMoniker(NULL, szDisplayName, ppmk);
        if(SUCCEEDED(hres)) {
            *pchEaten = strlenW(szDisplayName);
            return hres;
        }
    }

    return MkParseDisplayName(pbc, szDisplayName, pchEaten, ppmk);
}


801 802 803 804 805 806 807 808 809 810
/***********************************************************************
 *           URLDownloadToCacheFileA (URLMON.@)
 */
HRESULT WINAPI URLDownloadToCacheFileA(LPUNKNOWN lpUnkCaller, LPCSTR szURL, LPSTR szFileName,
        DWORD dwBufLength, DWORD dwReserved, LPBINDSTATUSCALLBACK pBSC)
{
    LPWSTR url = NULL, file_name = NULL;
    int len;
    HRESULT hres;

811
    TRACE("(%p %s %p %d %d %p)\n", lpUnkCaller, debugstr_a(szURL), szFileName,
812 813 814 815
            dwBufLength, dwReserved, pBSC);

    if(szURL) {
        len = MultiByteToWideChar(CP_ACP, 0, szURL, -1, NULL, 0);
816
        url = heap_alloc(len*sizeof(WCHAR));
817
        MultiByteToWideChar(CP_ACP, 0, szURL, -1, url, len);
818 819 820
    }

    if(szFileName)
821
        file_name = heap_alloc(dwBufLength*sizeof(WCHAR));
822 823 824 825 826 827 828

    hres = URLDownloadToCacheFileW(lpUnkCaller, url, file_name, dwBufLength*sizeof(WCHAR),
            dwReserved, pBSC);

    if(SUCCEEDED(hres) && file_name)
        WideCharToMultiByte(CP_ACP, 0, file_name, -1, szFileName, dwBufLength, NULL, NULL);

829 830
    heap_free(url);
    heap_free(file_name);
831 832 833 834 835 836 837 838 839 840

    return hres;
}

/***********************************************************************
 *           URLDownloadToCacheFileW (URLMON.@)
 */
HRESULT WINAPI URLDownloadToCacheFileW(LPUNKNOWN lpUnkCaller, LPCWSTR szURL, LPWSTR szFileName,
                DWORD dwBufLength, DWORD dwReserved, LPBINDSTATUSCALLBACK pBSC)
{
841 842 843 844 845
    WCHAR cache_path[MAX_PATH + 1];
    FILETIME expire, modified;
    HRESULT hr;
    LPWSTR ext;

846
    static WCHAR header[] = {
847 848 849 850
        'H','T','T','P','/','1','.','0',' ','2','0','0',' ',
        'O','K','\\','r','\\','n','\\','r','\\','n',0
    };

851
    TRACE("(%p, %s, %p, %d, %d, %p)\n", lpUnkCaller, debugstr_w(szURL),
852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871
          szFileName, dwBufLength, dwReserved, pBSC);

    if (!szURL || !szFileName)
        return E_INVALIDARG;

    ext = PathFindExtensionW(szURL);

    if (!CreateUrlCacheEntryW(szURL, 0, ext, cache_path, 0))
        return E_FAIL;

    hr = URLDownloadToFileW(lpUnkCaller, szURL, cache_path, 0, pBSC);
    if (FAILED(hr))
        return hr;

    expire.dwHighDateTime = 0;
    expire.dwLowDateTime = 0;
    modified.dwHighDateTime = 0;
    modified.dwLowDateTime = 0;

    if (!CommitUrlCacheEntryW(szURL, cache_path, expire, modified, NORMAL_CACHE_ENTRY,
872
                              header, sizeof(header), NULL, NULL))
873 874
        return E_FAIL;

875
    if (strlenW(cache_path) > dwBufLength)
876 877 878 879 880
        return E_OUTOFMEMORY;

    lstrcpyW(szFileName, cache_path);

    return S_OK;
881 882
}

883 884 885 886 887 888 889
/***********************************************************************
 *           HlinkSimpleNavigateToMoniker (URLMON.@)
 */
HRESULT WINAPI HlinkSimpleNavigateToMoniker(IMoniker *pmkTarget,
    LPCWSTR szLocation, LPCWSTR szTargetFrameName, IUnknown *pUnk,
    IBindCtx *pbc, IBindStatusCallback *pbsc, DWORD grfHLNF, DWORD dwReserved)
{
890 891 892 893 894 895 896 897 898 899 900 901
    LPWSTR target;
    HRESULT hres;

    TRACE("\n");

    hres = IMoniker_GetDisplayName(pmkTarget, pbc, 0, &target);
    if(hres == S_OK)
        hres = HlinkSimpleNavigateToString( target, szLocation, szTargetFrameName,
                                            pUnk, pbc, pbsc, grfHLNF, dwReserved );
    CoTaskMemFree(target);

    return hres;
902 903
}

904 905 906 907 908 909 910
/***********************************************************************
 *           HlinkSimpleNavigateToString (URLMON.@)
 */
HRESULT WINAPI HlinkSimpleNavigateToString( LPCWSTR szTarget,
    LPCWSTR szLocation, LPCWSTR szTargetFrameName, IUnknown *pUnk,
    IBindCtx *pbc, IBindStatusCallback *pbsc, DWORD grfHLNF, DWORD dwReserved)
{
911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931
    FIXME("%s %s %s %p %p %p %u %u partial stub\n", debugstr_w( szTarget ), debugstr_w( szLocation ),
          debugstr_w( szTargetFrameName ), pUnk, pbc, pbsc, grfHLNF, dwReserved);

    /* undocumented: 0 means HLNF_OPENINNEWWINDOW*/
    if (!grfHLNF) grfHLNF = HLNF_OPENINNEWWINDOW;

    if (grfHLNF == HLNF_OPENINNEWWINDOW)
    {
        SHELLEXECUTEINFOW sei;
        static const WCHAR openW[] = { 'o', 'p', 'e', 'n', 0 };

        memset(&sei, 0, sizeof(sei));
        sei.cbSize = sizeof(sei);
        sei.lpVerb = openW;
        sei.nShow = SW_SHOWNORMAL;
        sei.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_NO_CONSOLE;
        sei.lpFile = szTarget;

        if (ShellExecuteExW(&sei)) return S_OK;
    }

932 933 934 935 936 937 938 939 940 941 942 943
    return E_NOTIMPL;
}

/***********************************************************************
 *           HlinkNavigateString (URLMON.@)
 */
HRESULT WINAPI HlinkNavigateString( IUnknown *pUnk, LPCWSTR szTarget )
{
    TRACE("%p %s\n", pUnk, debugstr_w( szTarget ) );
    return HlinkSimpleNavigateToString( 
               szTarget, NULL, NULL, pUnk, NULL, NULL, 0, 0 );
}
944 945 946 947 948 949 950 951 952

/***********************************************************************
 *           GetSoftwareUpdateInfo (URLMON.@)
 */
HRESULT WINAPI GetSoftwareUpdateInfo( LPCWSTR szDistUnit, LPSOFTDISTINFO psdi )
{
    FIXME("%s %p\n", debugstr_w(szDistUnit), psdi );
    return E_FAIL;
}
953 954 955 956 957 958 959 960 961 962 963

/***********************************************************************
 *           AsyncInstallDistributionUnit (URLMON.@)
 */
HRESULT WINAPI AsyncInstallDistributionUnit( LPCWSTR szDistUnit, LPCWSTR szTYPE,
                            LPCWSTR szExt, DWORD dwFileVersionMS, DWORD dwFileVersionLS,
                            LPCWSTR szURL, IBindCtx *pbc, LPVOID pvReserved, DWORD flags )
{
    FIXME(": stub\n");
    return E_NOTIMPL;
}