Implement A->W call for GetNamedSecurityInfo.
[wine] / dlls / devenum / mediacatenum.c
1 /*
2  *      IEnumMoniker implementation for DEVENUM.dll
3  *
4  * Copyright (C) 2002 Robert Shearman
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * NOTES ON THIS FILE:
21  * - Implements IEnumMoniker interface which enumerates through moniker
22  *   objects created from HKEY_CLASSES/CLSID/{DEVICE_CLSID}/Instance
23  */
24
25 #include "devenum_private.h"
26 #include "vfwmsgs.h"
27 #include "oleauto.h"
28
29 #include "wine/debug.h"
30
31
32 /* #define ICOM_THIS_From_IROTData(class, name) class* This = (class*)(((char*)name)-sizeof(void*)) */
33
34 WINE_DEFAULT_DEBUG_CHANNEL(devenum);
35
36 static ULONG WINAPI DEVENUM_IEnumMoniker_AddRef(LPENUMMONIKER iface);
37 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Hash(LPMONIKER iface, DWORD* pdwHash);
38 static ULONG WINAPI DEVENUM_IMediaCatMoniker_AddRef(LPMONIKER iface);
39 static ULONG WINAPI DEVENUM_IPropertyBag_AddRef(LPPROPERTYBAG iface);
40
41 static HRESULT WINAPI DEVENUM_IPropertyBag_QueryInterface(
42     LPPROPERTYBAG iface,
43     REFIID riid,
44     LPVOID *ppvObj)
45 {
46     ICOM_THIS(RegPropBagImpl, iface);
47     TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
48
49     if (This == NULL || ppvObj == NULL) return E_POINTER;
50
51     if (IsEqualGUID(riid, &IID_IUnknown) ||
52         IsEqualGUID(riid, &IID_IPropertyBag))
53     {
54         *ppvObj = (LPVOID)iface;
55         DEVENUM_IPropertyBag_AddRef(iface);
56         return S_OK;
57     }
58
59     FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid));
60     return E_NOINTERFACE;
61 }
62
63 /**********************************************************************
64  * DEVENUM_IPropertyBag_AddRef (also IUnknown)
65  */
66 static ULONG WINAPI DEVENUM_IPropertyBag_AddRef(LPPROPERTYBAG iface)
67 {
68     ICOM_THIS(RegPropBagImpl, iface);
69     TRACE("\n");
70
71     return InterlockedIncrement(&This->ref);
72 }
73
74 /**********************************************************************
75  * DEVENUM_IPropertyBag_Release (also IUnknown)
76  */
77 static ULONG WINAPI DEVENUM_IPropertyBag_Release(LPPROPERTYBAG iface)
78 {
79     ICOM_THIS(RegPropBagImpl, iface);
80
81     TRACE("\n");
82
83     if (InterlockedDecrement(&This->ref) == 0) {
84         RegCloseKey(This->hkey);
85         CoTaskMemFree(This);
86         return 0;
87     }
88     return This->ref;
89 }
90
91 static HRESULT WINAPI DEVENUM_IPropertyBag_Read(
92     LPPROPERTYBAG iface,
93     LPCOLESTR pszPropName,
94     VARIANT* pVar,
95     IErrorLog* pErrorLog)
96 {
97     LPVOID pData = NULL;
98     LONG received;
99     DWORD type = 0;
100     ICOM_THIS(RegPropBagImpl, iface);
101     HRESULT res = S_OK;
102     LONG reswin32;
103
104     TRACE("(%p)->(%s, %p, %p)\n", This, debugstr_w(pszPropName), pVar, pErrorLog);
105
106     if (!pszPropName || !pVar)
107         return E_POINTER;
108
109     reswin32 = RegQueryValueExW(This->hkey, pszPropName, NULL, NULL, NULL, &received);
110     res = HRESULT_FROM_WIN32(reswin32);
111
112     if (SUCCEEDED(res))
113     {
114         pData = HeapAlloc(GetProcessHeap(), 0, received);
115
116         /* work around a GCC bug that occurs here unless we use the reswin32 variable as well */
117         reswin32 = RegQueryValueExW(This->hkey, pszPropName, NULL, &type, pData, &received);
118         res = HRESULT_FROM_WIN32(reswin32);
119     }
120
121     if (SUCCEEDED(res))
122     {
123         res = E_INVALIDARG; /* assume we cannot coerce into right type */
124
125         TRACE("Read %ld bytes (%s)\n", received, type == REG_SZ ? debugstr_w((LPWSTR)pData) : "binary data");
126
127         switch (type)
128         {
129         case REG_SZ:
130             switch (V_VT(pVar))
131             {
132             case VT_LPWSTR:
133                 V_UNION(pVar, bstrVal) = CoTaskMemAlloc(received);
134                 memcpy(V_UNION(pVar, bstrVal), (LPWSTR)pData, received);
135                 res = S_OK;
136                 break;
137             case VT_EMPTY:
138                 V_VT(pVar) = VT_BSTR;
139             /* fall through */
140             case VT_BSTR:
141                 V_UNION(pVar, bstrVal) = SysAllocStringLen((LPWSTR)pData, received/sizeof(WCHAR) - 1);
142                 res = S_OK;
143                 break;
144             }
145             break;
146         case REG_DWORD:
147             TRACE("REG_DWORD: %lx\n", *(DWORD *)pData);
148             switch (V_VT(pVar))
149             {
150             case VT_EMPTY:
151                 V_VT(pVar) = VT_I4;
152                 /* fall through */
153             case VT_I4:
154             case VT_UI4:
155                 V_UNION(pVar, ulVal) = *(DWORD *)pData;
156                 res = S_OK;
157                 break;
158             }
159             break;
160         case REG_BINARY:
161             {
162                 SAFEARRAYBOUND bound;
163                 void * pArrayElements;
164                 bound.lLbound = 0;
165                 bound.cElements = received;
166                 TRACE("REG_BINARY: len = %ld\n", received);
167                 switch (V_VT(pVar))
168                 {
169                 case VT_EMPTY:
170                 case VT_ARRAY | VT_UI1:
171                     if (!(V_UNION(pVar, parray) = SafeArrayCreate(VT_UI1, 1, &bound)))
172                         res = E_OUTOFMEMORY;
173                     res = S_OK;
174                     break;
175                 }
176
177                 if (res == E_INVALIDARG)
178                     break;
179
180                 res = SafeArrayAccessData(V_UNION(pVar, parray), &pArrayElements);
181                 if (FAILED(res))
182                     break;
183
184                 CopyMemory(pArrayElements, pData, received);
185                 res = SafeArrayUnaccessData(V_UNION(pVar, parray));
186                 break;
187             }
188         }
189         if (res == E_INVALIDARG)
190             FIXME("Variant type %x not supported for regtype %lx\n", V_VT(pVar), type);
191     }
192
193     if (pData)
194         HeapFree(GetProcessHeap(), 0, pData);
195
196     TRACE("<- %lx\n", res);
197     return res;
198 }
199
200 static HRESULT WINAPI DEVENUM_IPropertyBag_Write(
201     LPPROPERTYBAG iface,
202     LPCOLESTR pszPropName,
203     VARIANT* pVar)
204 {
205     ICOM_THIS(RegPropBagImpl, iface);
206     LPVOID lpData = NULL;
207     DWORD cbData = 0;
208     DWORD dwType = 0;
209     HRESULT res = S_OK;
210
211     TRACE("(%p)->(%s, %p)\n", This, debugstr_w(pszPropName), pVar);
212
213     switch (V_VT(pVar))
214     {
215     case VT_BSTR:
216         TRACE("writing %s\n", debugstr_w(V_UNION(pVar, bstrVal)));
217         lpData = (LPVOID)V_UNION(pVar, bstrVal);
218         dwType = REG_SZ;
219         cbData = (lstrlenW(V_UNION(pVar, bstrVal)) + 1) * sizeof(WCHAR);
220         break;
221     case VT_I4:
222     case VT_UI4:
223         TRACE("writing %lu\n", V_UNION(pVar, ulVal));
224         lpData = (LPVOID)&V_UNION(pVar, ulVal);
225         dwType = REG_DWORD;
226         cbData = sizeof(DWORD);
227         break;
228     case VT_ARRAY | VT_UI1:
229     {
230         LONG lUbound = 0;
231         LONG lLbound = 0;
232         dwType = REG_BINARY;
233         res = SafeArrayGetLBound(V_UNION(pVar, parray), 1, &lLbound);
234         res = SafeArrayGetUBound(V_UNION(pVar, parray), 1, &lUbound);
235         cbData = (lUbound - lLbound + 1) /* * sizeof(BYTE)*/;
236         TRACE("cbData: %ld\n", cbData);
237         res = SafeArrayAccessData(V_UNION(pVar, parray), &lpData);
238         break;
239     }
240     default:
241         FIXME("Variant type %d not handled\n", V_VT(pVar));
242         return E_FAIL;
243     }
244
245     if (RegSetValueExW(This->hkey,
246                        pszPropName, 0,
247                        dwType, lpData, cbData) != ERROR_SUCCESS)
248         res = E_FAIL;
249
250     if (V_VT(pVar) & VT_ARRAY)
251         res = SafeArrayUnaccessData(V_UNION(pVar, parray));
252
253     return res;
254 }
255
256 static ICOM_VTABLE(IPropertyBag) IPropertyBag_Vtbl =
257 {
258     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
259     DEVENUM_IPropertyBag_QueryInterface,
260     DEVENUM_IPropertyBag_AddRef,
261     DEVENUM_IPropertyBag_Release,
262     DEVENUM_IPropertyBag_Read,
263     DEVENUM_IPropertyBag_Write
264 };
265
266
267
268 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_QueryInterface(
269     LPMONIKER iface,
270     REFIID riid,
271     LPVOID *ppvObj)
272 {
273     ICOM_THIS(MediaCatMoniker, iface);
274     TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
275
276     if (This == NULL || ppvObj == NULL) return E_POINTER;
277
278     *ppvObj = NULL;
279
280     if (IsEqualGUID(riid, &IID_IUnknown) ||
281         IsEqualGUID(riid, &IID_IPersist) ||
282         IsEqualGUID(riid, &IID_IPersistStream) ||
283         IsEqualGUID(riid, &IID_IMoniker))
284     {
285         *ppvObj = (LPVOID)iface;
286         DEVENUM_IMediaCatMoniker_AddRef(iface);
287         return S_OK;
288     }
289
290     FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid));
291     return E_NOINTERFACE;
292 }
293
294 /**********************************************************************
295  * DEVENUM_IMediaCatMoniker_AddRef (also IUnknown)
296  */
297 static ULONG WINAPI DEVENUM_IMediaCatMoniker_AddRef(LPMONIKER iface)
298 {
299     ICOM_THIS(MediaCatMoniker, iface);
300     TRACE("\n");
301
302     if (This == NULL) return E_POINTER;
303
304     return ++This->ref;
305 }
306
307 /**********************************************************************
308  * DEVENUM_IMediaCatMoniker_Release (also IUnknown)
309  */
310 static ULONG WINAPI DEVENUM_IMediaCatMoniker_Release(LPMONIKER iface)
311 {
312     ICOM_THIS(MediaCatMoniker, iface);
313     ULONG ref;
314     TRACE("\n");
315
316     if (This == NULL) return E_POINTER;
317
318     ref = --This->ref;
319     if (ref == 0) {
320         RegCloseKey(This->hkey);
321         CoTaskMemFree(This);
322     }
323     return ref;
324 }
325
326 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetClassID(
327     LPMONIKER iface,
328     CLSID* pClassID)
329 {
330     ICOM_THIS(MediaCatMoniker, iface);
331     FIXME("(%p)->(%p)\n", This, pClassID);
332
333     if (pClassID == NULL)
334         return E_POINTER;
335
336     return E_NOTIMPL;
337 }
338
339 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsDirty(LPMONIKER iface)
340 {
341     FIXME("()\n");
342
343     return S_FALSE;
344 }
345
346 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Load(LPMONIKER iface, IStream* pStm)
347 {
348     FIXME("(%p)\n", pStm);
349
350     return E_NOTIMPL;
351 }
352
353 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Save(LPMONIKER iface, IStream* pStm, BOOL fClearDirty)
354 {
355     FIXME("(%p, %s)\n", pStm, fClearDirty ? "true" : "false");
356
357     return STG_E_CANTSAVE;
358 }
359
360 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetSizeMax(
361     LPMONIKER iface,
362     ULARGE_INTEGER* pcbSize)
363 {
364     FIXME("(%p)\n", pcbSize);
365
366     ZeroMemory(pcbSize, sizeof(*pcbSize));
367
368     return S_OK;
369 }
370
371 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_BindToObject(
372     LPMONIKER iface,
373     IBindCtx* pbc,
374     IMoniker* pmkToLeft,
375     REFIID riidResult,
376     void** ppvResult)
377 {
378     IUnknown * pObj = NULL;
379     IPropertyBag * pProp = NULL;
380     CLSID clsID;
381     VARIANT var;
382     HRESULT res = E_FAIL;
383
384     ICOM_THIS(MediaCatMoniker, iface);
385
386     VariantClear(&var);
387
388     TRACE("(%p)->(%p, %p, %s, %p)\n", This, pbc, pmkToLeft, debugstr_guid(riidResult), ppvResult);
389
390     *ppvResult = NULL;
391
392     if(pmkToLeft==NULL)
393     {
394             /* first activation of this class */
395             LPVOID pvptr;
396             res=IMoniker_BindToStorage(iface, NULL, NULL, &IID_IPropertyBag, &pvptr);
397             pProp = (IPropertyBag*)pvptr;
398             if (SUCCEEDED(res))
399             {
400                 V_VT(&var) = VT_LPWSTR;
401                 res = IPropertyBag_Read(pProp, clsid_keyname, &var, NULL);
402             }
403             if (SUCCEEDED(res))
404             {
405                 res = CLSIDFromString(V_UNION(&var,bstrVal), &clsID);
406                 CoTaskMemFree(V_UNION(&var, bstrVal));
407             }
408             if (SUCCEEDED(res))
409             {
410                 res=CoCreateInstance(&clsID,NULL,CLSCTX_ALL,&IID_IUnknown,&pvptr);
411                 pObj = (IUnknown*)pvptr;
412             }
413     }
414
415     if (pObj!=NULL)
416     {
417         /* get the requested interface from the loaded class */
418         res= IUnknown_QueryInterface(pObj,riidResult,ppvResult);
419     }
420
421     if (pProp)
422     {
423         IPropertyBag_Release(pProp);
424     }
425
426     TRACE("<- 0x%lx\n", res);
427
428     return res;
429 }
430
431 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_BindToStorage(
432     LPMONIKER iface,
433     IBindCtx* pbc,
434     IMoniker* pmkToLeft,
435     REFIID riid,
436     void** ppvObj)
437 {
438     ICOM_THIS(MediaCatMoniker, iface);
439     TRACE("(%p)->(%p, %p, %s, %p)\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppvObj);
440
441     *ppvObj = NULL;
442
443     if (pbc || pmkToLeft)
444         return MK_E_NOSTORAGE;
445
446     if (IsEqualGUID(riid, &IID_IPropertyBag))
447     {
448         RegPropBagImpl * rpb = CoTaskMemAlloc(sizeof(RegPropBagImpl));
449         if (!rpb)
450             return E_OUTOFMEMORY;
451         rpb->lpVtbl = &IPropertyBag_Vtbl;
452         DuplicateHandle(GetCurrentProcess(), This->hkey, GetCurrentProcess(), (LPHANDLE)&(rpb->hkey), 0, 0, DUPLICATE_SAME_ACCESS);
453         rpb->ref = 1;
454         *ppvObj = (LPVOID)rpb;
455         return S_OK;
456     }
457
458     return MK_E_NOSTORAGE;
459 }
460
461 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Reduce(
462     LPMONIKER iface,
463     IBindCtx* pbc,
464     DWORD dwReduceHowFar,
465     IMoniker** ppmkToLeft,
466     IMoniker** ppmkReduced)
467 {
468     TRACE("(%p, %ld, %p, %p)\n", pbc, dwReduceHowFar, ppmkToLeft, ppmkReduced);
469
470     if (ppmkToLeft)
471         *ppmkToLeft = NULL;
472     *ppmkReduced = iface;
473
474     return MK_S_REDUCED_TO_SELF;
475 }
476
477 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_ComposeWith(
478     LPMONIKER iface,
479     IMoniker* pmkRight,
480     BOOL fOnlyIfNotGeneric,
481     IMoniker** ppmkComposite)
482 {
483     FIXME("(%p, %s, %p): stub\n", pmkRight, fOnlyIfNotGeneric ? "true" : "false", ppmkComposite);
484
485     /* FIXME: use CreateGenericComposite? */
486     *ppmkComposite = NULL;
487
488     return E_NOTIMPL;
489 }
490
491 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Enum(
492     LPMONIKER iface,
493     BOOL fForward,
494     IEnumMoniker** ppenumMoniker)
495 {
496     FIXME("(%s, %p): stub\n", fForward ? "true" : "false", ppenumMoniker);
497
498     *ppenumMoniker = NULL;
499
500     return S_OK;
501 }
502
503 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsEqual(
504     LPMONIKER iface,
505     IMoniker* pmkOtherMoniker)
506 {
507     FIXME("(%p)\n", pmkOtherMoniker);
508
509     return E_NOTIMPL;
510 }
511
512 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Hash(
513     LPMONIKER iface,
514     DWORD* pdwHash)
515 {
516     TRACE("(%p)\n", pdwHash);
517
518     *pdwHash = 0;
519
520     return S_OK;
521 }
522
523 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsRunning(
524     LPMONIKER iface,
525     IBindCtx* pbc,
526     IMoniker* pmkToLeft,
527     IMoniker* pmkNewlyRunning)
528 {
529     FIXME("(%p, %p, %p)\n", pbc, pmkToLeft, pmkNewlyRunning);
530
531     return S_FALSE;
532 }
533
534 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetTimeOfLastChange(
535     LPMONIKER iface,
536     IBindCtx* pbc,
537     IMoniker* pmkToLeft,
538     FILETIME* pFileTime)
539 {
540     TRACE("(%p, %p, %p)\n", pbc, pmkToLeft, pFileTime);
541
542     pFileTime->dwLowDateTime = 0xFFFFFFFF;
543     pFileTime->dwHighDateTime = 0x7FFFFFFF;
544
545     return MK_E_UNAVAILABLE;
546 }
547
548 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Inverse(
549     LPMONIKER iface,
550     IMoniker** ppmk)
551 {
552     TRACE("(%p)\n", ppmk);
553
554     *ppmk = NULL;
555
556     return MK_E_NOINVERSE;
557 }
558
559 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_CommonPrefixWith(
560     LPMONIKER iface,
561     IMoniker* pmkOtherMoniker,
562     IMoniker** ppmkPrefix)
563 {
564     TRACE("(%p, %p)\n", pmkOtherMoniker, ppmkPrefix);
565
566     *ppmkPrefix = NULL;
567
568     return MK_E_NOPREFIX;
569 }
570
571 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_RelativePathTo(
572     LPMONIKER iface,
573     IMoniker* pmkOther,
574     IMoniker** ppmkRelPath)
575 {
576     TRACE("(%p, %p)\n", pmkOther, ppmkRelPath);
577
578     *ppmkRelPath = pmkOther;
579
580     return MK_S_HIM;
581 }
582
583 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetDisplayName(
584     LPMONIKER iface,
585     IBindCtx* pbc,
586     IMoniker* pmkToLeft,
587     LPOLESTR* ppszDisplayName)
588 {
589     ICOM_THIS(MediaCatMoniker, iface);
590     WCHAR wszBuffer[MAX_PATH];
591     static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
592     LONG received = sizeof(wszFriendlyName);
593
594     TRACE("(%p, %p, %p)\n", pbc, pmkToLeft, ppszDisplayName);
595
596     *ppszDisplayName = NULL;
597
598     /* FIXME: should this be the weird stuff we have to parse in IParseDisplayName? */
599     if (RegQueryValueW(This->hkey, wszFriendlyName, wszBuffer, &received) == ERROR_SUCCESS)
600     {
601         *ppszDisplayName = CoTaskMemAlloc(received);
602         strcpyW(*ppszDisplayName, wszBuffer);
603         return S_OK;
604     }
605
606     return E_FAIL;
607 }
608
609 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_ParseDisplayName(
610     LPMONIKER iface,
611     IBindCtx* pbc,
612     IMoniker* pmkToLeft,
613     LPOLESTR pszDisplayName,
614     ULONG* pchEaten,
615     IMoniker** ppmkOut)
616 {
617     FIXME("(%p, %p, %s, %p, %p)\n", pbc, pmkToLeft, debugstr_w(pszDisplayName), pchEaten, ppmkOut);
618
619     *pchEaten = 0;
620     *ppmkOut = NULL;
621
622     return MK_E_SYNTAX;
623 }
624
625 static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsSystemMoniker(
626     LPMONIKER iface,
627     DWORD* pdwMksys)
628 {
629     TRACE("(%p)\n", pdwMksys);
630
631     return S_FALSE;
632 }
633
634 static ICOM_VTABLE(IMoniker) IMoniker_Vtbl =
635 {
636     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
637     DEVENUM_IMediaCatMoniker_QueryInterface,
638     DEVENUM_IMediaCatMoniker_AddRef,
639     DEVENUM_IMediaCatMoniker_Release,
640     DEVENUM_IMediaCatMoniker_GetClassID,
641     DEVENUM_IMediaCatMoniker_IsDirty,
642     DEVENUM_IMediaCatMoniker_Load,
643     DEVENUM_IMediaCatMoniker_Save,
644     DEVENUM_IMediaCatMoniker_GetSizeMax,
645     DEVENUM_IMediaCatMoniker_BindToObject,
646     DEVENUM_IMediaCatMoniker_BindToStorage,
647     DEVENUM_IMediaCatMoniker_Reduce,
648     DEVENUM_IMediaCatMoniker_ComposeWith,
649     DEVENUM_IMediaCatMoniker_Enum,
650     DEVENUM_IMediaCatMoniker_IsEqual,
651     DEVENUM_IMediaCatMoniker_Hash,
652     DEVENUM_IMediaCatMoniker_IsRunning,
653     DEVENUM_IMediaCatMoniker_GetTimeOfLastChange,
654     DEVENUM_IMediaCatMoniker_Inverse,
655     DEVENUM_IMediaCatMoniker_CommonPrefixWith,
656     DEVENUM_IMediaCatMoniker_RelativePathTo,
657     DEVENUM_IMediaCatMoniker_GetDisplayName,
658     DEVENUM_IMediaCatMoniker_ParseDisplayName,
659     DEVENUM_IMediaCatMoniker_IsSystemMoniker
660 };
661
662 MediaCatMoniker * DEVENUM_IMediaCatMoniker_Construct()
663 {
664     MediaCatMoniker * pMoniker = NULL;
665     pMoniker = CoTaskMemAlloc(sizeof(MediaCatMoniker));
666     if (!pMoniker)
667         return NULL;
668
669     pMoniker->lpVtbl = &IMoniker_Vtbl;
670     pMoniker->ref = 0;
671     pMoniker->hkey = NULL;
672
673     DEVENUM_IMediaCatMoniker_AddRef((LPMONIKER)pMoniker);
674
675     return pMoniker;
676 }
677
678 /**********************************************************************
679  * DEVENUM_IEnumMoniker_QueryInterface (also IUnknown)
680  */
681 static HRESULT WINAPI DEVENUM_IEnumMoniker_QueryInterface(
682     LPENUMMONIKER iface,
683     REFIID riid,
684     LPVOID *ppvObj)
685 {
686     ICOM_THIS(EnumMonikerImpl, iface);
687     TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
688
689     if (This == NULL || ppvObj == NULL) return E_POINTER;
690
691     if (IsEqualGUID(riid, &IID_IUnknown) ||
692         IsEqualGUID(riid, &IID_IEnumMoniker))
693     {
694         *ppvObj = (LPVOID)iface;
695         DEVENUM_IEnumMoniker_AddRef(iface);
696         return S_OK;
697     }
698
699     FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid));
700     return E_NOINTERFACE;
701 }
702
703 /**********************************************************************
704  * DEVENUM_IEnumMoniker_AddRef (also IUnknown)
705  */
706 static ULONG WINAPI DEVENUM_IEnumMoniker_AddRef(LPENUMMONIKER iface)
707 {
708     ICOM_THIS(EnumMonikerImpl, iface);
709
710     TRACE("\n");
711
712     if (This == NULL) return E_POINTER;
713
714     return InterlockedIncrement(&This->ref);
715 }
716
717 /**********************************************************************
718  * DEVENUM_IEnumMoniker_Release (also IUnknown)
719  */
720 static ULONG WINAPI DEVENUM_IEnumMoniker_Release(LPENUMMONIKER iface)
721 {
722     ICOM_THIS(EnumMonikerImpl, iface);
723
724     TRACE("\n");
725
726     if (!InterlockedDecrement(&This->ref))
727     {
728         RegCloseKey(This->hkey);
729         CoTaskMemFree(This);
730         return 0;
731     }
732     return This->ref;
733 }
734
735 static HRESULT WINAPI DEVENUM_IEnumMoniker_Next(LPENUMMONIKER iface, ULONG celt, IMoniker ** rgelt, ULONG * pceltFetched)
736 {
737     WCHAR buffer[MAX_PATH + 1];
738     LONG res;
739     ULONG fetched = 0;
740     MediaCatMoniker * pMoniker;
741     ICOM_THIS(EnumMonikerImpl, iface);
742
743     TRACE("(%ld, %p, %p)\n", celt, rgelt, pceltFetched);
744
745     while (fetched < celt)
746     {
747         res = RegEnumKeyW(This->hkey, This->index, buffer, sizeof(buffer) / sizeof(WCHAR));
748         if (res != ERROR_SUCCESS)
749         {
750             break;
751         }
752         pMoniker = DEVENUM_IMediaCatMoniker_Construct();
753         if (!pMoniker)
754             return E_OUTOFMEMORY;
755
756         if (RegOpenKeyW(This->hkey, buffer, &pMoniker->hkey) != ERROR_SUCCESS)
757         {
758             DEVENUM_IMediaCatMoniker_Release((LPMONIKER)pMoniker);
759             break;
760         }
761         rgelt[fetched] = (LPMONIKER)pMoniker;
762         fetched++;
763     }
764
765     This->index += fetched;
766
767     TRACE("-- fetched %ld\n", fetched);
768
769     if (pceltFetched)
770         *pceltFetched = fetched;
771
772     if (fetched != celt)
773         return S_FALSE;
774     else
775         return S_OK;
776 }
777
778 static HRESULT WINAPI DEVENUM_IEnumMoniker_Skip(LPENUMMONIKER iface, ULONG celt)
779 {
780     ICOM_THIS(EnumMonikerImpl, iface);
781
782     TRACE("(%ld)\n", celt);
783
784     This->index += celt;
785
786     return S_OK;
787 }
788
789 static HRESULT WINAPI DEVENUM_IEnumMoniker_Reset(LPENUMMONIKER iface)
790 {
791     ICOM_THIS(EnumMonikerImpl, iface);
792
793     TRACE("()\n");
794
795     This->index = 0;
796
797     return S_OK;
798 }
799
800 static HRESULT WINAPI DEVENUM_IEnumMoniker_Clone(LPENUMMONIKER iface, IEnumMoniker ** ppenum)
801 {
802     FIXME("(%p): stub\n", ppenum);
803
804     return E_NOTIMPL;
805 }
806
807 /**********************************************************************
808  * IEnumMoniker_Vtbl
809  */
810 ICOM_VTABLE(IEnumMoniker) IEnumMoniker_Vtbl =
811 {
812     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
813     DEVENUM_IEnumMoniker_QueryInterface,
814     DEVENUM_IEnumMoniker_AddRef,
815     DEVENUM_IEnumMoniker_Release,
816     DEVENUM_IEnumMoniker_Next,
817     DEVENUM_IEnumMoniker_Skip,
818     DEVENUM_IEnumMoniker_Reset,
819     DEVENUM_IEnumMoniker_Clone
820 };