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

80
    IUnknown_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
    hres = IBindCtx_GetRunningObjectTable(pbc, &obj_tbl);
    if(SUCCEEDED(hres)) {
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
        hres = IRunningObjectTable_IsRunning(obj_tbl, &This->IMoniker_iface);
        if(hres == S_OK) {
            IUnknown *unk = NULL;

            TRACE("Found in running object table\n");

            hres = IRunningObjectTable_GetObject(obj_tbl, &This->IMoniker_iface, &unk);
            if(SUCCEEDED(hres)) {
                hres = IUnknown_QueryInterface(unk, riid, ppv);
                IUnknown_Release(unk);
            }

            IRunningObjectTable_Release(obj_tbl);
            return hres;
        }

252 253
        IRunningObjectTable_Release(obj_tbl);
    }
254

255 256 257 258
    if(!This->uri) {
        *ppv = NULL;
        return MK_E_SYNTAX;
    }
259

260
    return bind_to_object(&This->IMoniker_iface, This->uri, pbc, riid, ppv);
261 262
}

Jacek Caban's avatar
Jacek Caban committed
263 264
static HRESULT WINAPI URLMoniker_BindToStorage(IMoniker* iface, IBindCtx* pbc,
        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 271 272 273
    if(ppvObject) *ppvObject = NULL;

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

274
    if(pmkToLeft)
275
        FIXME("Unsupported pmkToLeft\n");
276

277 278
    if(!This->uri)
        return MK_E_SYNTAX;
279

280
    return bind_to_storage(This->uri, pbc, riid, ppvObject);
281 282
}

Jacek Caban's avatar
Jacek Caban committed
283 284
static HRESULT WINAPI URLMoniker_Reduce(IMoniker *iface, IBindCtx *pbc,
        DWORD dwReduceHowFar, IMoniker **ppmkToLeft, IMoniker **ppmkReduced)
285
{
286 287
    URLMoniker *This = impl_from_IMoniker(iface);

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

290 291 292
    if(!ppmkReduced)
        return E_INVALIDARG;

Jacek Caban's avatar
Jacek Caban committed
293
    IMoniker_AddRef(iface);
294 295
    *ppmkReduced = iface;
    return MK_S_REDUCED_TO_SELF;
296 297
}

Jacek Caban's avatar
Jacek Caban committed
298 299
static HRESULT WINAPI URLMoniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight,
        BOOL fOnlyIfNotGeneric, IMoniker **ppmkComposite)
300
{
301
    URLMoniker *This = impl_from_IMoniker(iface);
302 303 304 305
    FIXME("(%p)->(%p,%d,%p): stub\n",This,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
    return E_NOTIMPL;
}

Jacek Caban's avatar
Jacek Caban committed
306
static HRESULT WINAPI URLMoniker_Enum(IMoniker *iface, BOOL fForward, IEnumMoniker **ppenumMoniker)
307
{
308
    URLMoniker *This = impl_from_IMoniker(iface);
Jacek Caban's avatar
Jacek Caban committed
309 310

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

312 313 314 315 316 317
    if(!ppenumMoniker)
        return E_INVALIDARG;

    /* Does not support sub-monikers */
    *ppenumMoniker = NULL;
    return S_OK;
318 319
}

Jacek Caban's avatar
Jacek Caban committed
320
static HRESULT WINAPI URLMoniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker)
321
{
322
    URLMoniker *This = impl_from_IMoniker(iface);
Kevin Koltzau's avatar
Kevin Koltzau committed
323 324 325 326
    CLSID clsid;
    LPOLESTR urlPath;
    IBindCtx* bind;
    HRESULT res;
327

Jacek Caban's avatar
Jacek Caban committed
328
    TRACE("(%p,%p)\n",This, pmkOtherMoniker);
Kevin Koltzau's avatar
Kevin Koltzau committed
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348

    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;
    }
349
    IBindCtx_Release(bind);
Kevin Koltzau's avatar
Kevin Koltzau committed
350
    return res;
351 352 353
}


Jacek Caban's avatar
Jacek Caban committed
354
static HRESULT WINAPI URLMoniker_Hash(IMoniker *iface, DWORD *pdwHash)
355
{
356
    URLMoniker *This = impl_from_IMoniker(iface);
357 358 359
    int  h = 0,i,skip,len;
    int  off = 0;
    LPOLESTR val;
360

361 362 363 364 365 366 367 368 369 370 371 372
    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
373
    }else {
374 375 376 377 378 379 380 381
        /* 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;
382 383
}

Jacek Caban's avatar
Jacek Caban committed
384 385
static HRESULT WINAPI URLMoniker_IsRunning(IMoniker* iface, IBindCtx* pbc,
        IMoniker *pmkToLeft, IMoniker *pmkNewlyRunning)
386
{
387
    URLMoniker *This = impl_from_IMoniker(iface);
388 389 390 391
    FIXME("(%p)->(%p,%p,%p): stub\n",This,pbc,pmkToLeft,pmkNewlyRunning);
    return E_NOTIMPL;
}

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

Jacek Caban's avatar
Jacek Caban committed
400
static HRESULT WINAPI URLMoniker_Inverse(IMoniker *iface, IMoniker **ppmk)
401
{
402
    URLMoniker *This = impl_from_IMoniker(iface);
403 404
    TRACE("(%p,%p)\n",This,ppmk);
    return MK_E_NOINVERSE;
405 406
}

Jacek Caban's avatar
Jacek Caban committed
407
static HRESULT WINAPI URLMoniker_CommonPrefixWith(IMoniker *iface, IMoniker *pmkOther, IMoniker **ppmkPrefix)
408
{
409
    URLMoniker *This = impl_from_IMoniker(iface);
410 411 412 413
    FIXME("(%p)->(%p,%p): stub\n",This,pmkOther,ppmkPrefix);
    return E_NOTIMPL;
}

Jacek Caban's avatar
Jacek Caban committed
414
static HRESULT WINAPI URLMoniker_RelativePathTo(IMoniker *iface, IMoniker *pmOther, IMoniker **ppmkRelPath)
415
{
416
    URLMoniker *This = impl_from_IMoniker(iface);
417 418 419 420
    FIXME("(%p)->(%p,%p): stub\n",This,pmOther,ppmkRelPath);
    return E_NOTIMPL;
}

Jacek Caban's avatar
Jacek Caban committed
421 422
static HRESULT WINAPI URLMoniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
        LPOLESTR *ppszDisplayName)
423
{
424
    URLMoniker *This = impl_from_IMoniker(iface);
425 426
    int len;
    
Jacek Caban's avatar
Jacek Caban committed
427
    TRACE("(%p,%p,%p,%p)\n", This, pbc, pmkToLeft, ppszDisplayName);
428 429 430
    
    if(!ppszDisplayName)
        return E_INVALIDARG;
431

432 433 434
    if(!This->URLName)
        return E_OUTOFMEMORY;

435 436 437
    /* 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
    */
438
    len = SysStringLen(This->URLName)+1;
439 440 441 442 443
    *ppszDisplayName = CoTaskMemAlloc(len*sizeof(WCHAR));
    if(!*ppszDisplayName)
        return E_OUTOFMEMORY;
    lstrcpyW(*ppszDisplayName, This->URLName);
    return S_OK;
444 445
}

Jacek Caban's avatar
Jacek Caban committed
446 447
static HRESULT WINAPI URLMoniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
        LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut)
448
{
449
    URLMoniker *This = impl_from_IMoniker(iface);
450 451 452 453
    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
454
static HRESULT WINAPI URLMoniker_IsSystemMoniker(IMoniker *iface, DWORD *pwdMksys)
455
{
456
    URLMoniker *This = impl_from_IMoniker(iface);
Jacek Caban's avatar
Jacek Caban committed
457

458
    TRACE("(%p,%p)\n",This,pwdMksys);
459

460 461 462 463 464
    if(!pwdMksys)
        return E_INVALIDARG;

    *pwdMksys = MKSYS_URLMONIKER;
    return S_OK;
465 466
}

Jacek Caban's avatar
Jacek Caban committed
467
static const IMonikerVtbl URLMonikerVtbl =
468
{
Jacek Caban's avatar
Jacek Caban committed
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
    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
492 493
};

494 495 496 497 498 499 500 501
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);
502
    return IMoniker_QueryInterface(&This->IMoniker_iface, riid, ppv);
503 504 505 506 507
}

static ULONG WINAPI UriContainer_AddRef(IUriContainer *iface)
{
    URLMoniker *This = impl_from_IUriContainer(iface);
508
    return IMoniker_AddRef(&This->IMoniker_iface);
509 510 511 512 513
}

static ULONG WINAPI UriContainer_Release(IUriContainer *iface)
{
    URLMoniker *This = impl_from_IUriContainer(iface);
514
    return IMoniker_Release(&This->IMoniker_iface);
515 516 517 518 519 520
}

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

521
    TRACE("(%p)->(%p)\n", This, ppIUri);
522

523 524 525 526 527 528 529 530
    if(!This->uri) {
        *ppIUri = NULL;
        return S_FALSE;
    }

    IUri_AddRef(This->uri);
    *ppIUri = This->uri;
    return S_OK;
531 532 533 534 535 536 537 538 539
}

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

540
static HRESULT create_moniker(IUri *uri, URLMoniker **ret)
541
{
542
    URLMoniker *mon;
543 544
    HRESULT hres;

545 546 547
    mon = heap_alloc(sizeof(*mon));
    if(!mon)
        return E_OUTOFMEMORY;
548

549 550 551
    mon->IMoniker_iface.lpVtbl = &URLMonikerVtbl;
    mon->IUriContainer_iface.lpVtbl = &UriContainerVtbl;
    mon->ref = 1;
552

553 554 555 556 557 558 559
    if(uri) {
        /* FIXME: try to avoid it */
        hres = IUri_GetDisplayUri(uri, &mon->URLName);
        if(FAILED(hres)) {
            heap_free(mon);
            return hres;
        }
560

561 562 563 564 565 566
        IUri_AddRef(uri);
        mon->uri = uri;
    }else {
        mon->URLName = NULL;
        mon->uri = NULL;
    }
Jacek Caban's avatar
Jacek Caban committed
567

568
    URLMON_LockModule();
569
    *ret = mon;
570 571 572
    return S_OK;
}

573 574
HRESULT StdURLMoniker_Construct(IUnknown *outer, void **ppv)
{
575 576 577
    URLMoniker *mon;
    HRESULT hres;

578 579
    TRACE("(%p %p)\n", outer, ppv);

580 581 582 583 584 585
    hres = create_moniker(NULL, &mon);
    if(FAILED(hres))
        return hres;

    *ppv = &mon->IMoniker_iface;
    return S_OK;
586 587
}

588 589 590 591 592 593 594 595 596 597 598 599
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 */
};

600
/***********************************************************************
601
 *           CreateURLMonikerEx (URLMON.@)
602
 *
Jon Griffiths's avatar
Jon Griffiths committed
603
 * Create a url moniker.
604
 *
Jon Griffiths's avatar
Jon Griffiths committed
605 606 607 608
 * PARAMS
 *    pmkContext [I] Context
 *    szURL      [I] Url to create the moniker for
 *    ppmk       [O] Destination for created moniker.
609
 *    dwFlags    [I] Flags.
610
 *
Jon Griffiths's avatar
Jon Griffiths committed
611 612 613 614
 * 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.
615
 */
616
HRESULT WINAPI CreateURLMonikerEx(IMoniker *pmkContext, LPCWSTR szURL, IMoniker **ppmk, DWORD dwFlags)
617
{
618
    IUri *uri, *base_uri = NULL;
Jacek Caban's avatar
Jacek Caban committed
619
    URLMoniker *obj;
620 621
    HRESULT hres;

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

624 625 626 627 628 629
    if (ppmk)
        *ppmk = NULL;

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

630
    if(dwFlags >= ARRAY_SIZE(create_flags_map)) {
631
        FIXME("Unsupported flags %x\n", dwFlags);
632 633
        return E_INVALIDARG;
    }
634

635
    if(pmkContext) {
636 637 638 639 640 641 642 643
        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;
644 645
        }
    }
646 647

    if(base_uri) {
648
        hres = CoInternetCombineUrlEx(base_uri, szURL, combine_flags_map[dwFlags], &uri, 0);
649 650
        IUri_Release(base_uri);
    }else {
651
        hres = CreateUri(szURL, Uri_CREATE_ALLOW_RELATIVE|Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME|create_flags_map[dwFlags], 0, &uri);
652 653 654 655 656 657 658 659 660 661 662
    }
    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;
663 664
}

665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682
/***********************************************************************
 *           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;

683
    if(dwFlags >= ARRAY_SIZE(create_flags_map)) {
684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716
        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;
}

717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736
/**********************************************************************
 *           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);
}

737 738 739 740 741
/***********************************************************************
 *           IsAsyncMoniker (URLMON.@)
 */
HRESULT WINAPI IsAsyncMoniker(IMoniker *pmk)
{
742 743 744 745 746 747 748 749 750
    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;
    }
751 752 753
    return S_FALSE;
}

754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775
/***********************************************************************
 *           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;

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

778 779 780 781 782 783 784 785 786 787 788 789 790 791
    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;
}

792 793 794 795 796 797 798
/***********************************************************************
 *           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);

799 800 801
    if (!pbc || !szDisplayName || !*szDisplayName || !pchEaten || !ppmk)
        return E_INVALIDARG;

802 803 804 805 806 807 808 809 810 811 812 813 814 815
    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);
}


816 817 818 819 820 821 822 823 824 825
/***********************************************************************
 *           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;

826
    TRACE("(%p %s %p %d %d %p)\n", lpUnkCaller, debugstr_a(szURL), szFileName,
827 828 829 830
            dwBufLength, dwReserved, pBSC);

    if(szURL) {
        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 839 840 841 842 843

    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);

844 845
    heap_free(url);
    heap_free(file_name);
846 847 848 849 850 851 852 853 854 855

    return hres;
}

/***********************************************************************
 *           URLDownloadToCacheFileW (URLMON.@)
 */
HRESULT WINAPI URLDownloadToCacheFileW(LPUNKNOWN lpUnkCaller, LPCWSTR szURL, LPWSTR szFileName,
                DWORD dwBufLength, DWORD dwReserved, LPBINDSTATUSCALLBACK pBSC)
{
856 857 858 859 860
    WCHAR cache_path[MAX_PATH + 1];
    FILETIME expire, modified;
    HRESULT hr;
    LPWSTR ext;

861
    static WCHAR header[] = {
862 863 864 865
        'H','T','T','P','/','1','.','0',' ','2','0','0',' ',
        'O','K','\\','r','\\','n','\\','r','\\','n',0
    };

866
    TRACE("(%p, %s, %p, %d, %d, %p)\n", lpUnkCaller, debugstr_w(szURL),
867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886
          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,
887
                              header, sizeof(header), NULL, NULL))
888 889
        return E_FAIL;

890
    if (strlenW(cache_path) > dwBufLength)
891 892 893 894 895
        return E_OUTOFMEMORY;

    lstrcpyW(szFileName, cache_path);

    return S_OK;
896 897
}

898 899 900 901 902 903 904
/***********************************************************************
 *           HlinkSimpleNavigateToMoniker (URLMON.@)
 */
HRESULT WINAPI HlinkSimpleNavigateToMoniker(IMoniker *pmkTarget,
    LPCWSTR szLocation, LPCWSTR szTargetFrameName, IUnknown *pUnk,
    IBindCtx *pbc, IBindStatusCallback *pbsc, DWORD grfHLNF, DWORD dwReserved)
{
905 906 907 908 909 910 911 912 913 914 915 916
    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;
917 918
}

919 920 921 922 923 924 925
/***********************************************************************
 *           HlinkSimpleNavigateToString (URLMON.@)
 */
HRESULT WINAPI HlinkSimpleNavigateToString( LPCWSTR szTarget,
    LPCWSTR szLocation, LPCWSTR szTargetFrameName, IUnknown *pUnk,
    IBindCtx *pbc, IBindStatusCallback *pbsc, DWORD grfHLNF, DWORD dwReserved)
{
926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946
    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;
    }

947 948 949 950 951 952 953 954 955 956 957 958
    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 );
}
959 960 961 962 963 964 965 966 967

/***********************************************************************
 *           GetSoftwareUpdateInfo (URLMON.@)
 */
HRESULT WINAPI GetSoftwareUpdateInfo( LPCWSTR szDistUnit, LPSOFTDISTINFO psdi )
{
    FIXME("%s %p\n", debugstr_w(szDistUnit), psdi );
    return E_FAIL;
}