mediacatenum.c 26.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 *	IEnumMoniker implementation for DEVENUM.dll
 *
 * Copyright (C) 2002 Robert Shearman
 *
 * 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
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 20 21 22 23 24 25 26
 *
 * NOTES ON THIS FILE:
 * - Implements IEnumMoniker interface which enumerates through moniker
 *   objects created from HKEY_CLASSES/CLSID/{DEVICE_CLSID}/Instance
 */

#include "devenum_private.h"
#include "oleauto.h"
27
#include "ocidl.h"
28 29 30 31 32

#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(devenum);

33 34 35
typedef struct
{
    IEnumMoniker IEnumMoniker_iface;
36
    CLSID class;
37
    LONG ref;
38 39 40 41
    HKEY sw_key;
    DWORD sw_index;
    HKEY cm_key;
    DWORD cm_index;
42 43
} EnumMonikerImpl;

44 45
typedef struct
{
46
    IPropertyBag IPropertyBag_iface;
47
    LONG ref;
48 49
    enum device_type type;
    WCHAR path[MAX_PATH];
50 51 52
} RegPropBagImpl;


53 54 55 56 57
static inline RegPropBagImpl *impl_from_IPropertyBag(IPropertyBag *iface)
{
    return CONTAINING_RECORD(iface, RegPropBagImpl, IPropertyBag_iface);
}

58 59 60 61 62
static HRESULT WINAPI DEVENUM_IPropertyBag_QueryInterface(
    LPPROPERTYBAG iface,
    REFIID riid,
    LPVOID *ppvObj)
{
63
    RegPropBagImpl *This = impl_from_IPropertyBag(iface);
64 65

    TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObj);
66 67 68 69 70 71

    if (This == NULL || ppvObj == NULL) return E_POINTER;

    if (IsEqualGUID(riid, &IID_IUnknown) ||
        IsEqualGUID(riid, &IID_IPropertyBag))
    {
72
        *ppvObj = iface;
73
        IPropertyBag_AddRef(iface);
74 75 76
        return S_OK;
    }

77
    FIXME("- no interface IID: %s\n", debugstr_guid(riid));
78 79 80 81 82 83 84 85
    return E_NOINTERFACE;
}

/**********************************************************************
 * DEVENUM_IPropertyBag_AddRef (also IUnknown)
 */
static ULONG WINAPI DEVENUM_IPropertyBag_AddRef(LPPROPERTYBAG iface)
{
86
    RegPropBagImpl *This = impl_from_IPropertyBag(iface);
87 88

    TRACE("(%p)->() AddRef from %d\n", iface, This->ref);
89 90 91 92 93 94 95 96 97

    return InterlockedIncrement(&This->ref);
}

/**********************************************************************
 * DEVENUM_IPropertyBag_Release (also IUnknown)
 */
static ULONG WINAPI DEVENUM_IPropertyBag_Release(LPPROPERTYBAG iface)
{
98
    RegPropBagImpl *This = impl_from_IPropertyBag(iface);
99
    ULONG ref;
100

101
    TRACE("(%p)->() ReleaseThis->ref from %d\n", iface, This->ref);
102

103 104
    ref = InterlockedDecrement(&This->ref);
    if (ref == 0) {
105
        CoTaskMemFree(This);
106
        DEVENUM_UnlockModule();
107
    }
108
    return ref;
109 110 111 112 113 114 115 116
}

static HRESULT WINAPI DEVENUM_IPropertyBag_Read(
    LPPROPERTYBAG iface,
    LPCOLESTR pszPropName,
    VARIANT* pVar,
    IErrorLog* pErrorLog)
{
117
    LPVOID pData = NULL;
118
    DWORD received;
119
    DWORD type = 0;
120
    RegPropBagImpl *This = impl_from_IPropertyBag(iface);
121
    HRESULT res = S_OK;
122 123
    LONG reswin32 = ERROR_SUCCESS;
    HKEY hkey;
124 125 126 127 128 129

    TRACE("(%p)->(%s, %p, %p)\n", This, debugstr_w(pszPropName), pVar, pErrorLog);

    if (!pszPropName || !pVar)
        return E_POINTER;

130 131 132 133
    if (This->type == DEVICE_FILTER)
        reswin32 = RegOpenKeyW(HKEY_CLASSES_ROOT, This->path, &hkey);
    else if (This->type == DEVICE_CODEC)
        reswin32 = RegOpenKeyW(HKEY_CURRENT_USER, This->path, &hkey);
134 135
    res = HRESULT_FROM_WIN32(reswin32);

136 137 138 139 140 141
    if (SUCCEEDED(res))
    {
        reswin32 = RegQueryValueExW(hkey, pszPropName, NULL, NULL, NULL, &received);
        res = HRESULT_FROM_WIN32(reswin32);
    }

142 143
    if (SUCCEEDED(res))
    {
144 145 146
        pData = HeapAlloc(GetProcessHeap(), 0, received);

        /* work around a GCC bug that occurs here unless we use the reswin32 variable as well */
147
        reswin32 = RegQueryValueExW(hkey, pszPropName, NULL, &type, pData, &received);
148 149 150 151 152 153 154
        res = HRESULT_FROM_WIN32(reswin32);
    }

    if (SUCCEEDED(res))
    {
        res = E_INVALIDARG; /* assume we cannot coerce into right type */

155
        TRACE("Read %d bytes (%s)\n", received, type == REG_SZ ? debugstr_w(pData) : "binary data");
156

157 158 159 160 161 162
        switch (type)
        {
        case REG_SZ:
            switch (V_VT(pVar))
            {
            case VT_LPWSTR:
163 164
                V_BSTR(pVar) = CoTaskMemAlloc(received);
                memcpy(V_BSTR(pVar), pData, received);
165 166
                res = S_OK;
                break;
167 168 169 170
            case VT_EMPTY:
                V_VT(pVar) = VT_BSTR;
            /* fall through */
            case VT_BSTR:
171
                V_BSTR(pVar) = SysAllocStringLen(pData, received/sizeof(WCHAR) - 1);
172 173
                res = S_OK;
                break;
174 175 176
            }
            break;
        case REG_DWORD:
177
            TRACE("REG_DWORD: %x\n", *(DWORD *)pData);
178 179 180 181 182 183 184
            switch (V_VT(pVar))
            {
            case VT_EMPTY:
                V_VT(pVar) = VT_I4;
                /* fall through */
            case VT_I4:
            case VT_UI4:
185
                V_I4(pVar) = *(DWORD *)pData;
186 187
                res = S_OK;
                break;
188 189 190 191 192 193 194 195
            }
            break;
        case REG_BINARY:
            {
                SAFEARRAYBOUND bound;
                void * pArrayElements;
                bound.lLbound = 0;
                bound.cElements = received;
196
                TRACE("REG_BINARY: len = %d\n", received);
197 198 199
                switch (V_VT(pVar))
                {
                case VT_EMPTY:
200 201
                    V_VT(pVar) = VT_ARRAY | VT_UI1;
                    /* fall through */
202
                case VT_ARRAY | VT_UI1:
203
                    if (!(V_ARRAY(pVar) = SafeArrayCreate(VT_UI1, 1, &bound)))
204
                        res = E_OUTOFMEMORY;
205 206
                    else
                        res = S_OK;
207 208 209
                    break;
                }

210 211 212
                if (res == E_INVALIDARG)
                    break;

213
                res = SafeArrayAccessData(V_ARRAY(pVar), &pArrayElements);
214
                if (FAILED(res))
215 216 217
                    break;

                CopyMemory(pArrayElements, pData, received);
218
                res = SafeArrayUnaccessData(V_ARRAY(pVar));
219
                break;
220 221
            }
        }
222
        if (res == E_INVALIDARG)
223
            FIXME("Variant type %x not supported for regtype %x\n", V_VT(pVar), type);
224 225
    }

226
    HeapFree(GetProcessHeap(), 0, pData);
227

228 229
    RegCloseKey(hkey);

230
    TRACE("<- %x\n", res);
231 232 233 234 235 236 237 238
    return res;
}

static HRESULT WINAPI DEVENUM_IPropertyBag_Write(
    LPPROPERTYBAG iface,
    LPCOLESTR pszPropName,
    VARIANT* pVar)
{
239
    RegPropBagImpl *This = impl_from_IPropertyBag(iface);
240 241 242 243
    LPVOID lpData = NULL;
    DWORD cbData = 0;
    DWORD dwType = 0;
    HRESULT res = S_OK;
244 245
    LONG lres = ERROR_SUCCESS;
    HKEY hkey;
246 247 248 249 250 251

    TRACE("(%p)->(%s, %p)\n", This, debugstr_w(pszPropName), pVar);

    switch (V_VT(pVar))
    {
    case VT_BSTR:
252
    case VT_LPWSTR:
253 254
        TRACE("writing %s\n", debugstr_w(V_BSTR(pVar)));
        lpData = V_BSTR(pVar);
255
        dwType = REG_SZ;
256
        cbData = (lstrlenW(V_BSTR(pVar)) + 1) * sizeof(WCHAR);
257 258 259
        break;
    case VT_I4:
    case VT_UI4:
260 261
        TRACE("writing %u\n", V_UI4(pVar));
        lpData = &V_UI4(pVar);
262 263 264 265 266 267 268 269
        dwType = REG_DWORD;
        cbData = sizeof(DWORD);
        break;
    case VT_ARRAY | VT_UI1:
    {
        LONG lUbound = 0;
        LONG lLbound = 0;
        dwType = REG_BINARY;
270 271
        res = SafeArrayGetLBound(V_ARRAY(pVar), 1, &lLbound);
        res = SafeArrayGetUBound(V_ARRAY(pVar), 1, &lUbound);
272
        cbData = (lUbound - lLbound + 1) /* * sizeof(BYTE)*/;
273
        TRACE("cbData: %d\n", cbData);
274
        res = SafeArrayAccessData(V_ARRAY(pVar), &lpData);
275 276 277 278 279 280 281
        break;
    }
    default:
        FIXME("Variant type %d not handled\n", V_VT(pVar));
        return E_FAIL;
    }

282 283 284 285 286 287 288 289 290 291 292 293
    if (This->type == DEVICE_FILTER)
        lres = RegCreateKeyW(HKEY_CLASSES_ROOT, This->path, &hkey);
    else if (This->type == DEVICE_CODEC)
        lres = RegCreateKeyW(HKEY_CURRENT_USER, This->path, &hkey);
    res = HRESULT_FROM_WIN32(lres);

    if (SUCCEEDED(res))
    {
        lres = RegSetValueExW(hkey, pszPropName, 0, dwType, lpData, cbData);
        res = HRESULT_FROM_WIN32(lres);
        RegCloseKey(hkey);
    }
294 295

    if (V_VT(pVar) & VT_ARRAY)
296
        res = SafeArrayUnaccessData(V_ARRAY(pVar));
297 298 299 300

    return res;
}

301
static const IPropertyBagVtbl IPropertyBag_Vtbl =
302 303 304 305 306 307 308 309
{
    DEVENUM_IPropertyBag_QueryInterface,
    DEVENUM_IPropertyBag_AddRef,
    DEVENUM_IPropertyBag_Release,
    DEVENUM_IPropertyBag_Read,
    DEVENUM_IPropertyBag_Write
};

310
static HRESULT create_PropertyBag(MediaCatMoniker *mon, IPropertyBag **ppBag)
311 312 313 314
{
    RegPropBagImpl * rpb = CoTaskMemAlloc(sizeof(RegPropBagImpl));
    if (!rpb)
        return E_OUTOFMEMORY;
315
    rpb->IPropertyBag_iface.lpVtbl = &IPropertyBag_Vtbl;
316
    rpb->ref = 1;
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
    rpb->type = mon->type;

    if (rpb->type == DEVICE_FILTER)
        strcpyW(rpb->path, clsidW);
    else if (rpb->type == DEVICE_CODEC)
        strcpyW(rpb->path, wszActiveMovieKey);
    if (mon->has_class)
    {
        StringFromGUID2(&mon->class, rpb->path + strlenW(rpb->path), CHARS_IN_GUID);
        if (rpb->type == DEVICE_FILTER)
            strcatW(rpb->path, instanceW);
        strcatW(rpb->path, backslashW);
    }
    strcatW(rpb->path, mon->name);

332
    *ppBag = &rpb->IPropertyBag_iface;
333 334 335
    DEVENUM_LockModule();
    return S_OK;
}
336 337


338
static inline MediaCatMoniker *impl_from_IMoniker(IMoniker *iface)
339
{
340 341
    return CONTAINING_RECORD(iface, MediaCatMoniker, IMoniker_iface);
}
342

343 344 345 346
static HRESULT WINAPI DEVENUM_IMediaCatMoniker_QueryInterface(IMoniker *iface, REFIID riid,
        void **ppv)
{
    TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
347

348 349
    if (!ppv)
        return E_POINTER;
350 351 352 353 354 355

    if (IsEqualGUID(riid, &IID_IUnknown) ||
        IsEqualGUID(riid, &IID_IPersist) ||
        IsEqualGUID(riid, &IID_IPersistStream) ||
        IsEqualGUID(riid, &IID_IMoniker))
    {
356 357
        *ppv = iface;
        IMoniker_AddRef(iface);
358 359 360
        return S_OK;
    }

361
    FIXME("- no interface IID: %s\n", debugstr_guid(riid));
362
    *ppv = NULL;
363 364 365
    return E_NOINTERFACE;
}

366
static ULONG WINAPI DEVENUM_IMediaCatMoniker_AddRef(IMoniker *iface)
367
{
368 369
    MediaCatMoniker *This = impl_from_IMoniker(iface);
    ULONG ref = InterlockedIncrement(&This->ref);
370

371 372 373
    TRACE("(%p) ref=%d\n", This, ref);

    return ref;
374 375
}

376
static ULONG WINAPI DEVENUM_IMediaCatMoniker_Release(IMoniker *iface)
377
{
378 379 380 381
    MediaCatMoniker *This = impl_from_IMoniker(iface);
    ULONG ref = InterlockedDecrement(&This->ref);

    TRACE("(%p) ref=%d\n", This, ref);
382 383

    if (ref == 0) {
384
        CoTaskMemFree(This->name);
385
        CoTaskMemFree(This);
386
        DEVENUM_UnlockModule();
387 388 389 390
    }
    return ref;
}

391
static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetClassID(IMoniker *iface, CLSID *pClassID)
392
{
393 394
    MediaCatMoniker *This = impl_from_IMoniker(iface);

395
    TRACE("(%p)->(%p)\n", This, pClassID);
396 397

    if (pClassID == NULL)
398
        return E_INVALIDARG;
399

400 401 402
    *pClassID = CLSID_CDeviceMoniker;

    return S_OK;
403 404
}

405
static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsDirty(IMoniker *iface)
406
{
407
    FIXME("(%p)->(): stub\n", iface);
408 409 410 411

    return S_FALSE;
}

412
static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Load(IMoniker *iface, IStream *pStm)
413
{
414
    FIXME("(%p)->(%p): stub\n", iface, pStm);
415 416 417 418

    return E_NOTIMPL;
}

419
static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Save(IMoniker *iface, IStream *pStm, BOOL fClearDirty)
420
{
421
    FIXME("(%p)->(%p, %s): stub\n", iface, pStm, fClearDirty ? "true" : "false");
422 423 424 425

    return STG_E_CANTSAVE;
}

426
static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetSizeMax(IMoniker *iface, ULARGE_INTEGER *pcbSize)
427
{
428
    FIXME("(%p)->(%p): stub\n", iface, pcbSize);
429 430 431 432 433 434

    ZeroMemory(pcbSize, sizeof(*pcbSize));

    return S_OK;
}

435 436
static HRESULT WINAPI DEVENUM_IMediaCatMoniker_BindToObject(IMoniker *iface, IBindCtx *pbc,
        IMoniker *pmkToLeft, REFIID riidResult, void **ppvResult)
437
{
438
    MediaCatMoniker *This = impl_from_IMoniker(iface);
439 440 441 442 443 444 445 446
    IUnknown * pObj = NULL;
    IPropertyBag * pProp = NULL;
    CLSID clsID;
    VARIANT var;
    HRESULT res = E_FAIL;

    TRACE("(%p)->(%p, %p, %s, %p)\n", This, pbc, pmkToLeft, debugstr_guid(riidResult), ppvResult);

447
    VariantInit(&var);
448 449 450 451 452
    *ppvResult = NULL;

    if(pmkToLeft==NULL)
    {
            /* first activation of this class */
453 454
	    LPVOID pvptr;
            res=IMoniker_BindToStorage(iface, NULL, NULL, &IID_IPropertyBag, &pvptr);
455
            pProp = pvptr;
456 457 458 459 460 461 462
            if (SUCCEEDED(res))
            {
                V_VT(&var) = VT_LPWSTR;
                res = IPropertyBag_Read(pProp, clsid_keyname, &var, NULL);
            }
            if (SUCCEEDED(res))
            {
463 464
                res = CLSIDFromString(V_BSTR(&var), &clsID);
                CoTaskMemFree(V_BSTR(&var));
465 466 467
            }
            if (SUCCEEDED(res))
            {
468
                res=CoCreateInstance(&clsID,NULL,CLSCTX_ALL,&IID_IUnknown,&pvptr);
469
                pObj = pvptr;
470 471 472 473 474 475
            }
    }

    if (pObj!=NULL)
    {
        /* get the requested interface from the loaded class */
476 477 478 479 480 481 482 483 484 485 486 487
        res = S_OK;
        if (pProp) {
           HRESULT res2;
           LPVOID ppv = NULL;
           res2 = IUnknown_QueryInterface(pObj, &IID_IPersistPropertyBag, &ppv);
           if (SUCCEEDED(res2)) {
              res = IPersistPropertyBag_Load((IPersistPropertyBag *) ppv, pProp, NULL);
              IPersistPropertyBag_Release((IPersistPropertyBag *) ppv);
           }
        }
        if (SUCCEEDED(res))
           res= IUnknown_QueryInterface(pObj,riidResult,ppvResult);
488
        IUnknown_Release(pObj);
489 490 491 492 493 494 495
    }

    if (pProp)
    {
        IPropertyBag_Release(pProp);
    }

496
    TRACE("<- 0x%x\n", res);
497 498 499 500

    return res;
}

501 502
static HRESULT WINAPI DEVENUM_IMediaCatMoniker_BindToStorage(IMoniker *iface, IBindCtx *pbc,
        IMoniker *pmkToLeft, REFIID riid, void **ppvObj)
503
{
504 505
    MediaCatMoniker *This = impl_from_IMoniker(iface);

506 507 508 509
    TRACE("(%p)->(%p, %p, %s, %p)\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppvObj);

    *ppvObj = NULL;

510
    if (pmkToLeft)
511 512
        return MK_E_NOSTORAGE;

513 514 515 516 517 518 519 520 521 522
    if (pbc != NULL)
    {
        static DWORD reported;
        if (!reported)
        {
            FIXME("ignoring IBindCtx %p\n", pbc);
            reported++;
        }
    }

523 524
    if (IsEqualGUID(riid, &IID_IPropertyBag))
    {
525
        return create_PropertyBag(This, (IPropertyBag**)ppvObj);
526 527 528 529 530
    }

    return MK_E_NOSTORAGE;
}

531 532
static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Reduce(IMoniker *iface, IBindCtx *pbc,
        DWORD dwReduceHowFar, IMoniker **ppmkToLeft, IMoniker **ppmkReduced)
533
{
534
    TRACE("(%p)->(%p, %d, %p, %p)\n", iface, pbc, dwReduceHowFar, ppmkToLeft, ppmkReduced);
535 536 537 538 539 540 541 542

    if (ppmkToLeft)
        *ppmkToLeft = NULL;
    *ppmkReduced = iface;

    return MK_S_REDUCED_TO_SELF;
}

543 544
static HRESULT WINAPI DEVENUM_IMediaCatMoniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight,
        BOOL fOnlyIfNotGeneric, IMoniker **ppmkComposite)
545
{
546
    FIXME("(%p)->(%p, %s, %p): stub\n", iface, pmkRight, fOnlyIfNotGeneric ? "true" : "false", ppmkComposite);
547 548 549 550 551 552 553

    /* FIXME: use CreateGenericComposite? */
    *ppmkComposite = NULL;

    return E_NOTIMPL;
}

554 555
static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Enum(IMoniker *iface, BOOL fForward,
        IEnumMoniker **ppenumMoniker)
556
{
557
    FIXME("(%p)->(%s, %p): stub\n", iface, fForward ? "true" : "false", ppenumMoniker);
558 559 560 561 562 563

    *ppenumMoniker = NULL;

    return S_OK;
}

564
static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker)
565
{
566 567 568 569
    CLSID clsid;
    LPOLESTR this_name, other_name;
    IBindCtx *bind;
    HRESULT res;
570

571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595
    TRACE("(%p)->(%p)\n", iface, pmkOtherMoniker);

    if (!pmkOtherMoniker)
        return E_INVALIDARG;

    IMoniker_GetClassID(pmkOtherMoniker, &clsid);
    if (!IsEqualCLSID(&clsid, &CLSID_CDeviceMoniker))
        return S_FALSE;

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

    res = S_FALSE;
    if (SUCCEEDED(IMoniker_GetDisplayName(iface, bind, NULL, &this_name)) &&
        SUCCEEDED(IMoniker_GetDisplayName(pmkOtherMoniker, bind, NULL, &other_name)))
    {
        int result = lstrcmpiW(this_name, other_name);
        CoTaskMemFree(this_name);
        CoTaskMemFree(other_name);
        if (!result)
            res = S_OK;
    }
    IBindCtx_Release(bind);
    return res;
596 597
}

598
static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Hash(IMoniker *iface, DWORD *pdwHash)
599
{
600
    TRACE("(%p)->(%p)\n", iface, pdwHash);
601 602 603 604 605 606

    *pdwHash = 0;

    return S_OK;
}

607 608
static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsRunning(IMoniker *iface, IBindCtx *pbc,
        IMoniker *pmkToLeft, IMoniker *pmkNewlyRunning)
609
{
610
    FIXME("(%p)->(%p, %p, %p): stub\n", iface, pbc, pmkToLeft, pmkNewlyRunning);
611 612 613 614

    return S_FALSE;
}

615 616
static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetTimeOfLastChange(IMoniker *iface, IBindCtx *pbc,
        IMoniker *pmkToLeft, FILETIME *pFileTime)
617
{
618
    TRACE("(%p)->(%p, %p, %p)\n", iface, pbc, pmkToLeft, pFileTime);
619 620 621 622 623 624 625

    pFileTime->dwLowDateTime = 0xFFFFFFFF;
    pFileTime->dwHighDateTime = 0x7FFFFFFF;

    return MK_E_UNAVAILABLE;
}

626
static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Inverse(IMoniker *iface, IMoniker **ppmk)
627
{
628
    TRACE("(%p)->(%p)\n", iface, ppmk);
629 630 631 632 633 634

    *ppmk = NULL;

    return MK_E_NOINVERSE;
}

635 636
static HRESULT WINAPI DEVENUM_IMediaCatMoniker_CommonPrefixWith(IMoniker *iface,
        IMoniker *pmkOtherMoniker, IMoniker **ppmkPrefix)
637
{
638
    TRACE("(%p)->(%p, %p)\n", iface, pmkOtherMoniker, ppmkPrefix);
639 640 641 642 643 644

    *ppmkPrefix = NULL;

    return MK_E_NOPREFIX;
}

645 646
static HRESULT WINAPI DEVENUM_IMediaCatMoniker_RelativePathTo(IMoniker *iface, IMoniker *pmkOther,
        IMoniker **ppmkRelPath)
647
{
648
    TRACE("(%p)->(%p, %p)\n", iface, pmkOther, ppmkRelPath);
649 650 651 652 653 654

    *ppmkRelPath = pmkOther;

    return MK_S_HIM;
}

655 656
static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc,
        IMoniker *pmkToLeft, LPOLESTR *ppszDisplayName)
657
{
658 659
    static const WCHAR swW[] = {'s','w',':',0};
    static const WCHAR cmW[] = {'c','m',':',0};
660
    MediaCatMoniker *This = impl_from_IMoniker(iface);
661
    WCHAR *buffer;
662

663
    TRACE("(%p)->(%p, %p, %p)\n", iface, pbc, pmkToLeft, ppszDisplayName);
664 665 666

    *ppszDisplayName = NULL;

667 668 669 670 671 672 673 674 675 676 677 678
    buffer = CoTaskMemAlloc((strlenW(deviceW) + 4 + (This->has_class ? CHARS_IN_GUID : 0)
                            + strlenW(This->name) + 1) * sizeof(WCHAR));
    if (!buffer)
        return E_OUTOFMEMORY;

    strcpyW(buffer, deviceW);
    if (This->type == DEVICE_FILTER)
        strcatW(buffer, swW);
    else if (This->type == DEVICE_CODEC)
        strcatW(buffer, cmW);

    if (This->has_class)
679
    {
680 681
        StringFromGUID2(&This->class, buffer + strlenW(buffer), CHARS_IN_GUID);
        strcatW(buffer, backslashW);
682
    }
683
    strcatW(buffer, This->name);
684

685 686
    *ppszDisplayName = buffer;
    return S_OK;
687 688
}

689 690
static HRESULT WINAPI DEVENUM_IMediaCatMoniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc,
        IMoniker *pmkToLeft, LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut)
691
{
692
    FIXME("(%p)->(%p, %p, %s, %p, %p)\n", iface, pbc, pmkToLeft, debugstr_w(pszDisplayName), pchEaten, ppmkOut);
693 694 695 696 697 698 699

    *pchEaten = 0;
    *ppmkOut = NULL;

    return MK_E_SYNTAX;
}

700
static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsSystemMoniker(IMoniker *iface, DWORD *pdwMksys)
701
{
702
    TRACE("(%p)->(%p)\n", iface, pdwMksys);
703 704 705 706

    return S_FALSE;
}

707
static const IMonikerVtbl IMoniker_Vtbl =
708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733
{
    DEVENUM_IMediaCatMoniker_QueryInterface,
    DEVENUM_IMediaCatMoniker_AddRef,
    DEVENUM_IMediaCatMoniker_Release,
    DEVENUM_IMediaCatMoniker_GetClassID,
    DEVENUM_IMediaCatMoniker_IsDirty,
    DEVENUM_IMediaCatMoniker_Load,
    DEVENUM_IMediaCatMoniker_Save,
    DEVENUM_IMediaCatMoniker_GetSizeMax,
    DEVENUM_IMediaCatMoniker_BindToObject,
    DEVENUM_IMediaCatMoniker_BindToStorage,
    DEVENUM_IMediaCatMoniker_Reduce,
    DEVENUM_IMediaCatMoniker_ComposeWith,
    DEVENUM_IMediaCatMoniker_Enum,
    DEVENUM_IMediaCatMoniker_IsEqual,
    DEVENUM_IMediaCatMoniker_Hash,
    DEVENUM_IMediaCatMoniker_IsRunning,
    DEVENUM_IMediaCatMoniker_GetTimeOfLastChange,
    DEVENUM_IMediaCatMoniker_Inverse,
    DEVENUM_IMediaCatMoniker_CommonPrefixWith,
    DEVENUM_IMediaCatMoniker_RelativePathTo,
    DEVENUM_IMediaCatMoniker_GetDisplayName,
    DEVENUM_IMediaCatMoniker_ParseDisplayName,
    DEVENUM_IMediaCatMoniker_IsSystemMoniker
};

734
MediaCatMoniker * DEVENUM_IMediaCatMoniker_Construct(void)
735 736 737 738 739 740
{
    MediaCatMoniker * pMoniker = NULL;
    pMoniker = CoTaskMemAlloc(sizeof(MediaCatMoniker));
    if (!pMoniker)
        return NULL;

741
    pMoniker->IMoniker_iface.lpVtbl = &IMoniker_Vtbl;
742
    pMoniker->ref = 0;
743 744
    pMoniker->has_class = FALSE;
    pMoniker->name = NULL;
745

746
    DEVENUM_IMediaCatMoniker_AddRef(&pMoniker->IMoniker_iface);
747

748 749
    DEVENUM_LockModule();

750 751 752
    return pMoniker;
}

753
static inline EnumMonikerImpl *impl_from_IEnumMoniker(IEnumMoniker *iface)
754
{
755 756
    return CONTAINING_RECORD(iface, EnumMonikerImpl, IEnumMoniker_iface);
}
757

758 759 760 761
static HRESULT WINAPI DEVENUM_IEnumMoniker_QueryInterface(IEnumMoniker *iface, REFIID riid,
        void **ppv)
{
    TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
762

763 764
    if (!ppv)
        return E_POINTER;
765 766 767 768

    if (IsEqualGUID(riid, &IID_IUnknown) ||
        IsEqualGUID(riid, &IID_IEnumMoniker))
    {
769 770
        *ppv = iface;
        IEnumMoniker_AddRef(iface);
771 772 773
        return S_OK;
    }

774
    FIXME("- no interface IID: %s\n", debugstr_guid(riid));
775
    *ppv = NULL;
776 777 778
    return E_NOINTERFACE;
}

779
static ULONG WINAPI DEVENUM_IEnumMoniker_AddRef(IEnumMoniker *iface)
780
{
781
    EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
782
    ULONG ref = InterlockedIncrement(&This->ref);
783

784
    TRACE("(%p) ref=%d\n", This, ref);
785

786
    return ref;
787 788
}

789
static ULONG WINAPI DEVENUM_IEnumMoniker_Release(IEnumMoniker *iface)
790
{
791
    EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
792
    ULONG ref = InterlockedDecrement(&This->ref);
793

794
    TRACE("(%p) ref=%d\n", This, ref);
795

796
    if (!ref)
797
    {
798 799
        RegCloseKey(This->sw_key);
        RegCloseKey(This->cm_key);
800
        CoTaskMemFree(This);
801
        DEVENUM_UnlockModule();
802 803
        return 0;
    }
804
    return ref;
805 806
}

807 808
static HRESULT WINAPI DEVENUM_IEnumMoniker_Next(IEnumMoniker *iface, ULONG celt, IMoniker **rgelt,
        ULONG *pceltFetched)
809
{
810
    EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
811 812 813 814
    WCHAR buffer[MAX_PATH + 1];
    LONG res;
    ULONG fetched = 0;
    MediaCatMoniker * pMoniker;
815
    HKEY hkey;
816

817
    TRACE("(%p)->(%d, %p, %p)\n", iface, celt, rgelt, pceltFetched);
818 819 820

    while (fetched < celt)
    {
821 822 823 824
        /* FIXME: try PNP devices and DMOs first */

        /* try DirectShow filters */
        if (!(res = RegEnumKeyW(This->sw_key, This->sw_index, buffer, sizeof(buffer)/sizeof(WCHAR))))
825
        {
826 827 828
            This->sw_index++;
            if ((res = RegOpenKeyExW(This->sw_key, buffer, 0, KEY_QUERY_VALUE, &hkey)))
                break;
829 830 831 832 833

            if (!(pMoniker = DEVENUM_IMediaCatMoniker_Construct()))
                return E_OUTOFMEMORY;

            pMoniker->type = DEVICE_FILTER;
834
        }
835 836 837 838 839 840 841
        /* then try codecs */
        else if (!(res = RegEnumKeyW(This->cm_key, This->cm_index, buffer, sizeof(buffer)/sizeof(WCHAR))))
        {
            This->cm_index++;

            if ((res = RegOpenKeyExW(This->cm_key, buffer, 0, KEY_QUERY_VALUE, &hkey)))
                break;
842 843 844 845 846

            if (!(pMoniker = DEVENUM_IMediaCatMoniker_Construct()))
                return E_OUTOFMEMORY;

            pMoniker->type = DEVICE_CODEC;
847 848 849 850
        }
        else
            break;

851 852 853
        if (!(pMoniker->name = CoTaskMemAlloc((strlenW(buffer) + 1) * sizeof(WCHAR))))
        {
            IMoniker_Release(&pMoniker->IMoniker_iface);
854
            return E_OUTOFMEMORY;
855 856 857 858
        }
        strcpyW(pMoniker->name, buffer);
        pMoniker->has_class = TRUE;
        pMoniker->class = This->class;
859

860
        rgelt[fetched] = &pMoniker->IMoniker_iface;
861 862 863
        fetched++;
    }

864
    TRACE("-- fetched %d\n", fetched);
865 866 867 868 869 870 871 872 873 874

    if (pceltFetched)
        *pceltFetched = fetched;

    if (fetched != celt)
        return S_FALSE;
    else
        return S_OK;
}

875
static HRESULT WINAPI DEVENUM_IEnumMoniker_Skip(IEnumMoniker *iface, ULONG celt)
876
{
877
    EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
878

879
    TRACE("(%p)->(%d)\n", iface, celt);
880

881
    while (celt--)
882
    {
883
        /* FIXME: try PNP devices and DMOs first */
884

885 886 887 888 889 890 891 892 893 894 895 896 897
        /* try DirectShow filters */
        if (RegEnumKeyW(This->sw_key, This->sw_index, NULL, 0) != ERROR_NO_MORE_ITEMS)
        {
            This->sw_index++;
        }
        /* then try codecs */
        else if (RegEnumKeyW(This->cm_key, This->cm_index, NULL, 0) != ERROR_NO_MORE_ITEMS)
        {
            This->cm_index++;
        }
        else
            return S_FALSE;
    }
898 899 900 901

    return S_OK;
}

902
static HRESULT WINAPI DEVENUM_IEnumMoniker_Reset(IEnumMoniker *iface)
903
{
904
    EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
905

906
    TRACE("(%p)->()\n", iface);
907

908 909
    This->sw_index = 0;
    This->cm_index = 0;
910 911 912 913

    return S_OK;
}

914
static HRESULT WINAPI DEVENUM_IEnumMoniker_Clone(IEnumMoniker *iface, IEnumMoniker **ppenum)
915
{
916
    FIXME("(%p)->(%p): stub\n", iface, ppenum);
917 918 919 920 921 922 923

    return E_NOTIMPL;
}

/**********************************************************************
 * IEnumMoniker_Vtbl
 */
924
static const IEnumMonikerVtbl IEnumMoniker_Vtbl =
925 926 927 928 929 930 931 932 933
{
    DEVENUM_IEnumMoniker_QueryInterface,
    DEVENUM_IEnumMoniker_AddRef,
    DEVENUM_IEnumMoniker_Release,
    DEVENUM_IEnumMoniker_Next,
    DEVENUM_IEnumMoniker_Skip,
    DEVENUM_IEnumMoniker_Reset,
    DEVENUM_IEnumMoniker_Clone
};
934

935
HRESULT create_EnumMoniker(REFCLSID class, IEnumMoniker **ppEnumMoniker)
936 937
{
    EnumMonikerImpl * pEnumMoniker = CoTaskMemAlloc(sizeof(EnumMonikerImpl));
938 939
    WCHAR buffer[78];

940 941 942
    if (!pEnumMoniker)
        return E_OUTOFMEMORY;

943
    pEnumMoniker->IEnumMoniker_iface.lpVtbl = &IEnumMoniker_Vtbl;
944
    pEnumMoniker->ref = 1;
945 946
    pEnumMoniker->sw_index = 0;
    pEnumMoniker->cm_index = 0;
947
    pEnumMoniker->class = *class;
948

949 950 951 952 953
    strcpyW(buffer, clsidW);
    StringFromGUID2(class, buffer + strlenW(buffer), CHARS_IN_GUID);
    strcatW(buffer, instanceW);
    if (RegOpenKeyExW(HKEY_CLASSES_ROOT, buffer, 0, KEY_ENUMERATE_SUB_KEYS, &pEnumMoniker->sw_key))
        pEnumMoniker->sw_key = NULL;
954

955 956 957 958
    strcpyW(buffer, wszActiveMovieKey);
    StringFromGUID2(class, buffer + strlenW(buffer), CHARS_IN_GUID);
    if (RegOpenKeyExW(HKEY_CURRENT_USER, buffer, 0, KEY_ENUMERATE_SUB_KEYS, &pEnumMoniker->cm_key))
        pEnumMoniker->cm_key = NULL;
959

960
    *ppEnumMoniker = &pEnumMoniker->IEnumMoniker_iface;
961

962 963 964 965
    DEVENUM_LockModule();

    return S_OK;
}