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