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