xref: /reactos/dll/directx/wine/msdmo/dmoreg.c (revision c2c66aff)
1 /*
2  * Copyright (C) 2003 Michael Günnewig
3  * Copyright (C) 2003 CodeWeavers Inc. (Ulrich Czekalla)
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 
20 #include "precomp.h"
21 
22 #include <winuser.h>
23 #include <winreg.h>
24 #include <wine/unicode.h>
25 #include <dmo.h>
26 
27 #define MSDMO_MAJOR_VERSION 6
28 
29 static const WCHAR szDMORootKey[] =
30 {
31     'D','i','r','e','c','t','S','h','o','w','\\',
32     'M','e','d','i','a','O','b','j','e','c','t','s',0
33 };
34 
35 static const WCHAR szDMOInputType[] =
36 {
37     'I','n','p','u','t','T','y','p','e','s',0
38 };
39 
40 static const WCHAR szDMOOutputType[] =
41 {
42     'O','u','t','p','u','t','T','y','p','e','s',0
43 };
44 
45 static const WCHAR szDMOKeyed[] =
46 {
47     'K','e','y','e','d',0
48 };
49 
50 static const WCHAR szDMOCategories[] =
51 {
52     'C','a','t','e','g','o','r','i','e','s',0
53 };
54 
55 static const WCHAR szGUIDFmt[] =
56 {
57     '%','0','8','X','-','%','0','4','X','-','%','0','4','X','-','%','0',
58     '2','X','%','0','2','X','-','%','0','2','X','%','0','2','X','%','0','2',
59     'X','%','0','2','X','%','0','2','X','%','0','2','X',0
60 };
61 
62 static const WCHAR szCat3Fmt[] =
63 {
64     '%','s','\\','%','s','\\','%','s',0
65 };
66 
67 static const WCHAR szCat2Fmt[] =
68 {
69     '%','s','\\','%','s',0
70 };
71 
72 static const WCHAR szToGuidFmt[] =
73 {
74     '{','%','s','}',0
75 };
76 
77 
78 typedef struct
79 {
80     IEnumDMO                    IEnumDMO_iface;
81     LONG			ref;
82     DWORD			index;
83     GUID                        category;
84     DWORD                       dwFlags;
85     DWORD                       cInTypes;
86     DMO_PARTIAL_MEDIATYPE       *pInTypes;
87     DWORD                       cOutTypes;
88     DMO_PARTIAL_MEDIATYPE       *pOutTypes;
89     HKEY                        hkey;
90 } IEnumDMOImpl;
91 
92 static inline IEnumDMOImpl *impl_from_IEnumDMO(IEnumDMO *iface)
93 {
94     return CONTAINING_RECORD(iface, IEnumDMOImpl, IEnumDMO_iface);
95 }
96 
97 static HRESULT read_types(HKEY root, LPCWSTR key, ULONG *supplied, ULONG requested, DMO_PARTIAL_MEDIATYPE* types);
98 
99 static const IEnumDMOVtbl edmovt;
100 
101 static LPWSTR GUIDToString(LPWSTR lpwstr, REFGUID lpcguid)
102 {
103     wsprintfW(lpwstr, szGUIDFmt, lpcguid->Data1, lpcguid->Data2,
104         lpcguid->Data3, lpcguid->Data4[0], lpcguid->Data4[1],
105         lpcguid->Data4[2], lpcguid->Data4[3], lpcguid->Data4[4],
106         lpcguid->Data4[5], lpcguid->Data4[6], lpcguid->Data4[7]);
107 
108     return lpwstr;
109 }
110 
111 static BOOL IsMediaTypeEqual(const DMO_PARTIAL_MEDIATYPE* mt1, const DMO_PARTIAL_MEDIATYPE* mt2)
112 {
113 
114     return (IsEqualCLSID(&mt1->type, &mt2->type) ||
115             IsEqualCLSID(&mt2->type, &GUID_NULL) ||
116             IsEqualCLSID(&mt1->type, &GUID_NULL)) &&
117             (IsEqualCLSID(&mt1->subtype, &mt2->subtype) ||
118             IsEqualCLSID(&mt2->subtype, &GUID_NULL) ||
119             IsEqualCLSID(&mt1->subtype, &GUID_NULL));
120 }
121 
122 static HRESULT write_types(HKEY hkey, LPCWSTR name, const DMO_PARTIAL_MEDIATYPE* types, DWORD count)
123 {
124     LONG ret;
125 
126     if (MSDMO_MAJOR_VERSION > 5)
127     {
128         ret = RegSetValueExW(hkey, name, 0, REG_BINARY, (const BYTE*) types,
129                           count* sizeof(DMO_PARTIAL_MEDIATYPE));
130     }
131     else
132     {
133         HKEY skey1,skey2,skey3;
134         DWORD index = 0;
135         WCHAR szGuidKey[64];
136 
137         ret = RegCreateKeyExW(hkey, name, 0, NULL, REG_OPTION_NON_VOLATILE,
138                                KEY_WRITE, NULL, &skey1, NULL);
139         if (ret)
140             return HRESULT_FROM_WIN32(ret);
141 
142         while (index < count)
143         {
144             GUIDToString(szGuidKey,&types[index].type);
145             ret = RegCreateKeyExW(skey1, szGuidKey, 0, NULL,
146                         REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &skey2, NULL);
147             GUIDToString(szGuidKey,&types[index].subtype);
148             ret = RegCreateKeyExW(skey2, szGuidKey, 0, NULL,
149                         REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &skey3, NULL);
150             RegCloseKey(skey3);
151             RegCloseKey(skey2);
152             index ++;
153         }
154         RegCloseKey(skey1);
155     }
156 
157     return HRESULT_FROM_WIN32(ret);
158 }
159 
160 /***************************************************************
161  * DMORegister (MSDMO.@)
162  *
163  * Register a DirectX Media Object.
164  */
165 HRESULT WINAPI DMORegister(
166    LPCWSTR szName,
167    REFCLSID clsidDMO,
168    REFGUID guidCategory,
169    DWORD dwFlags,
170    DWORD cInTypes,
171    const DMO_PARTIAL_MEDIATYPE *pInTypes,
172    DWORD cOutTypes,
173    const DMO_PARTIAL_MEDIATYPE *pOutTypes
174 )
175 {
176     WCHAR szguid[64];
177     HRESULT hres;
178     HKEY hrkey = 0;
179     HKEY hkey = 0;
180     HKEY hckey = 0;
181     HKEY hclskey = 0;
182     LONG ret;
183 
184     TRACE("%s %s %s\n", debugstr_w(szName), debugstr_guid(clsidDMO), debugstr_guid(guidCategory));
185 
186     if (IsEqualGUID(guidCategory, &GUID_NULL))
187         return E_INVALIDARG;
188 
189     ret = RegCreateKeyExW(HKEY_CLASSES_ROOT, szDMORootKey, 0, NULL,
190         REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hrkey, NULL);
191     if (ret)
192         return HRESULT_FROM_WIN32(ret);
193 
194     /* Create clsidDMO key under MediaObjects */
195     ret = RegCreateKeyExW(hrkey, GUIDToString(szguid, clsidDMO), 0, NULL,
196         REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkey, NULL);
197     if (ret)
198         goto lend;
199 
200     /* Set default Name value */
201     ret = RegSetValueExW(hkey, NULL, 0, REG_SZ, (const BYTE*) szName,
202         (strlenW(szName) + 1) * sizeof(WCHAR));
203 
204     /* Set InputTypes */
205     hres = write_types(hkey, szDMOInputType, pInTypes, cInTypes);
206 
207     /* Set OutputTypes */
208     hres = write_types(hkey, szDMOOutputType, pOutTypes, cOutTypes);
209 
210     if (dwFlags & DMO_REGISTERF_IS_KEYED)
211     {
212         /* Create Keyed key */
213         ret = RegCreateKeyExW(hkey, szDMOKeyed, 0, NULL,
214             REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hckey, NULL);
215         if (ret)
216             goto lend;
217         RegCloseKey(hckey);
218     }
219 
220     /* Register the category */
221     ret = RegCreateKeyExW(hrkey, szDMOCategories, 0, NULL,
222             REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hckey, NULL);
223     if (ret)
224         goto lend;
225 
226     RegCloseKey(hkey);
227 
228     ret = RegCreateKeyExW(hckey, GUIDToString(szguid, guidCategory), 0, NULL,
229             REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkey, NULL);
230     if (ret)
231         goto lend;
232     ret = RegCreateKeyExW(hkey, GUIDToString(szguid, clsidDMO), 0, NULL,
233         REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hclskey, NULL);
234     if (ret)
235         goto lend;
236 
237 lend:
238     if (hkey)
239         RegCloseKey(hkey);
240     if (hckey)
241         RegCloseKey(hckey);
242     if (hclskey)
243         RegCloseKey(hclskey);
244     if (hrkey)
245         RegCloseKey(hrkey);
246 
247     hres = HRESULT_FROM_WIN32(ret);
248     TRACE(" hresult=0x%08x\n", hres);
249     return hres;
250 }
251 
252 static HRESULT unregister_dmo_from_category(const WCHAR *dmoW, const WCHAR *catW, HKEY categories)
253 {
254     HKEY catkey;
255     LONG ret;
256 
257     ret = RegOpenKeyExW(categories, catW, 0, KEY_WRITE, &catkey);
258     if (!ret)
259     {
260         ret = RegDeleteKeyW(catkey, dmoW);
261         RegCloseKey(catkey);
262     }
263 
264     return !ret ? S_OK : S_FALSE;
265 }
266 
267 /***************************************************************
268  * DMOUnregister (MSDMO.@)
269  *
270  * Unregister a DirectX Media Object.
271  */
272 HRESULT WINAPI DMOUnregister(REFCLSID dmo, REFGUID category)
273 {
274     HKEY rootkey = 0, categorieskey = 0;
275     WCHAR dmoW[64], catW[64];
276     HRESULT hr = S_FALSE;
277     LONG ret;
278 
279     TRACE("%s %s\n", debugstr_guid(dmo), debugstr_guid(category));
280 
281     ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, szDMORootKey, 0, KEY_WRITE, &rootkey);
282     if (ret)
283         return S_FALSE;
284 
285     GUIDToString(dmoW, dmo);
286     RegDeleteKeyW(rootkey, dmoW);
287 
288     /* open 'Categories' */
289     ret = RegOpenKeyExW(rootkey, szDMOCategories, 0, KEY_WRITE|KEY_ENUMERATE_SUB_KEYS, &categorieskey);
290     RegCloseKey(rootkey);
291     if (ret)
292     {
293         hr = HRESULT_FROM_WIN32(ret);
294         goto lend;
295     }
296 
297     /* remove from all categories */
298     if (IsEqualGUID(category, &GUID_NULL))
299     {
300         DWORD index = 0, len = sizeof(catW)/sizeof(WCHAR);
301 
302         while (!RegEnumKeyExW(categorieskey, index++, catW, &len, NULL, NULL, NULL, NULL))
303             hr = unregister_dmo_from_category(dmoW, catW, categorieskey);
304     }
305     else
306     {
307         GUIDToString(catW, category);
308         hr = unregister_dmo_from_category(dmoW, catW, categorieskey);
309     }
310 
311 lend:
312     if (categorieskey)
313         RegCloseKey(categorieskey);
314 
315     return hr;
316 }
317 
318 
319 /***************************************************************
320  * DMOGetName (MSDMO.@)
321  *
322  * Get DMO Name from the registry
323  */
324 HRESULT WINAPI DMOGetName(REFCLSID clsidDMO, WCHAR name[])
325 {
326     static const INT max_name_len = 80*sizeof(WCHAR);
327     DWORD count = max_name_len;
328     WCHAR szguid[64];
329     HKEY hrkey, hkey;
330     LONG ret;
331 
332     TRACE("%s %p\n", debugstr_guid(clsidDMO), name);
333 
334     if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szDMORootKey, 0, KEY_READ, &hrkey))
335         return E_FAIL;
336 
337     ret = RegOpenKeyExW(hrkey, GUIDToString(szguid, clsidDMO), 0, KEY_READ, &hkey);
338     RegCloseKey(hrkey);
339     if (ret)
340         return E_FAIL;
341 
342     ret = RegQueryValueExW(hkey, NULL, NULL, NULL, (LPBYTE)name, &count);
343     RegCloseKey(hkey);
344 
345     if (!ret && count > 1)
346     {
347         TRACE("name=%s\n", debugstr_w(name));
348         return S_OK;
349     }
350 
351     name[0] = 0;
352     return S_FALSE;
353 }
354 
355 static HRESULT dup_partial_mediatype(const DMO_PARTIAL_MEDIATYPE *types, DWORD count, DMO_PARTIAL_MEDIATYPE **ret)
356 {
357     *ret = NULL;
358 
359     if (count == 0)
360         return S_OK;
361 
362     *ret = HeapAlloc(GetProcessHeap(), 0, count*sizeof(*types));
363     if (!*ret)
364         return E_OUTOFMEMORY;
365 
366     memcpy(*ret, types, count*sizeof(*types));
367     return S_OK;
368 }
369 
370 /**************************************************************************
371  *  IEnumDMO_Constructor
372  */
373 static HRESULT IEnumDMO_Constructor(
374     REFGUID guidCategory,
375     DWORD dwFlags,
376     DWORD cInTypes,
377     const DMO_PARTIAL_MEDIATYPE *pInTypes,
378     DWORD cOutTypes,
379     const DMO_PARTIAL_MEDIATYPE *pOutTypes,
380     IEnumDMO **obj)
381 {
382     IEnumDMOImpl* lpedmo;
383     HRESULT hr;
384     LONG ret;
385 
386     *obj = NULL;
387 
388     lpedmo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumDMOImpl));
389     if (!lpedmo)
390         return E_OUTOFMEMORY;
391 
392     lpedmo->IEnumDMO_iface.lpVtbl = &edmovt;
393     lpedmo->ref = 1;
394     lpedmo->index = -1;
395     lpedmo->category = *guidCategory;
396     lpedmo->dwFlags = dwFlags;
397     lpedmo->cInTypes = cInTypes;
398     lpedmo->cOutTypes = cOutTypes;
399 
400     hr = dup_partial_mediatype(pInTypes, cInTypes, &lpedmo->pInTypes);
401     if (FAILED(hr))
402         goto lerr;
403 
404     hr = dup_partial_mediatype(pOutTypes, cOutTypes, &lpedmo->pOutTypes);
405     if (FAILED(hr))
406         goto lerr;
407 
408     /* If not filtering by category enum from media objects root */
409     if (IsEqualGUID(guidCategory, &GUID_NULL))
410     {
411         if ((ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, szDMORootKey, 0, KEY_READ, &lpedmo->hkey)))
412             hr = HRESULT_FROM_WIN32(ret);
413     }
414     else
415     {
416         WCHAR szguid[64];
417         WCHAR szKey[MAX_PATH];
418 
419         wsprintfW(szKey, szCat3Fmt, szDMORootKey, szDMOCategories, GUIDToString(szguid, guidCategory));
420         if ((ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, szKey, 0, KEY_READ, &lpedmo->hkey)))
421             hr = HRESULT_FROM_WIN32(ret);
422     }
423 
424 lerr:
425 
426     if (FAILED(hr))
427         IEnumDMO_Release(&lpedmo->IEnumDMO_iface);
428     else
429     {
430         TRACE("returning %p\n", lpedmo);
431         *obj = &lpedmo->IEnumDMO_iface;
432     }
433 
434     return hr;
435 }
436 
437 /******************************************************************************
438  * IEnumDMO_fnAddRef
439  */
440 static ULONG WINAPI IEnumDMO_fnAddRef(IEnumDMO * iface)
441 {
442     IEnumDMOImpl *This = impl_from_IEnumDMO(iface);
443     ULONG refCount = InterlockedIncrement(&This->ref);
444     TRACE("(%p)->(%d)\n", This, refCount);
445     return refCount;
446 }
447 
448 /**************************************************************************
449  *  EnumDMO_QueryInterface
450  */
451 static HRESULT WINAPI IEnumDMO_fnQueryInterface(IEnumDMO* iface, REFIID riid, void **ppvObj)
452 {
453     IEnumDMOImpl *This = impl_from_IEnumDMO(iface);
454 
455     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObj);
456 
457     *ppvObj = NULL;
458 
459     if (IsEqualIID(riid, &IID_IEnumDMO) ||
460         IsEqualIID(riid, &IID_IUnknown))
461     {
462         *ppvObj = iface;
463         IEnumDMO_AddRef(iface);
464     }
465 
466     return *ppvObj ? S_OK : E_NOINTERFACE;
467 }
468 
469 /******************************************************************************
470  * IEnumDMO_fnRelease
471  */
472 static ULONG WINAPI IEnumDMO_fnRelease(IEnumDMO * iface)
473 {
474     IEnumDMOImpl *This = impl_from_IEnumDMO(iface);
475     ULONG refCount = InterlockedDecrement(&This->ref);
476 
477     TRACE("(%p)->(%d)\n", This, refCount);
478 
479     if (!refCount)
480     {
481         if (This->hkey)
482             RegCloseKey(This->hkey);
483         HeapFree(GetProcessHeap(), 0, This->pInTypes);
484         HeapFree(GetProcessHeap(), 0, This->pOutTypes);
485         HeapFree(GetProcessHeap(), 0, This);
486     }
487     return refCount;
488 }
489 
490 
491 /******************************************************************************
492  * IEnumDMO_fnNext
493  */
494 static HRESULT WINAPI IEnumDMO_fnNext(
495     IEnumDMO * iface,
496     DWORD cItemsToFetch,
497     CLSID * pCLSID,
498     WCHAR ** Names,
499     DWORD * pcItemsFetched)
500 {
501     HKEY hkey;
502     WCHAR szNextKey[MAX_PATH];
503     WCHAR szGuidKey[64];
504     WCHAR szKey[MAX_PATH];
505     WCHAR szValue[MAX_PATH];
506     DWORD len;
507     UINT count = 0;
508     HRESULT hres = S_OK;
509     LONG ret;
510 
511     IEnumDMOImpl *This = impl_from_IEnumDMO(iface);
512 
513     TRACE("(%p)->(%d %p %p %p)\n", This, cItemsToFetch, pCLSID, Names, pcItemsFetched);
514 
515     if (!pCLSID || !Names || !pcItemsFetched)
516         return E_POINTER;
517 
518     while (count < cItemsToFetch)
519     {
520         This->index++;
521 
522         len = MAX_PATH;
523         ret = RegEnumKeyExW(This->hkey, This->index, szNextKey, &len, NULL, NULL, NULL, NULL);
524         if (ret != ERROR_SUCCESS)
525         {
526             hres = HRESULT_FROM_WIN32(ret);
527             break;
528         }
529 
530         TRACE("found %s\n", debugstr_w(szNextKey));
531 
532         if (!(This->dwFlags & DMO_ENUMF_INCLUDE_KEYED))
533         {
534             wsprintfW(szKey, szCat3Fmt, szDMORootKey, szNextKey, szDMOKeyed);
535             ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, szKey, 0, KEY_READ, &hkey);
536             if (ERROR_SUCCESS == ret)
537             {
538                 RegCloseKey(hkey);
539                 /* Skip Keyed entries */
540                 continue;
541             }
542         }
543 
544         wsprintfW(szKey, szCat2Fmt, szDMORootKey, szNextKey);
545         ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, szKey, 0, KEY_READ, &hkey);
546         TRACE("testing %s\n", debugstr_w(szKey));
547 
548         if (This->pInTypes)
549         {
550             UINT i, j;
551             DWORD cInTypes;
552             DMO_PARTIAL_MEDIATYPE* pInTypes;
553 
554             hres = read_types(hkey, szDMOInputType, &cInTypes,
555                     sizeof(szValue)/sizeof(DMO_PARTIAL_MEDIATYPE),
556                     (DMO_PARTIAL_MEDIATYPE*)szValue);
557 
558             if (FAILED(hres))
559             {
560                 RegCloseKey(hkey);
561                 continue;
562             }
563 
564 	    pInTypes = (DMO_PARTIAL_MEDIATYPE*) szValue;
565 
566             TRACE("read %d intypes for %s:\n", cInTypes, debugstr_w(szKey));
567             for (i = 0; i < cInTypes; i++) {
568                 TRACE("intype %d: type %s, subtype %s\n", i, debugstr_guid(&pInTypes[i].type),
569                     debugstr_guid(&pInTypes[i].subtype));
570             }
571 
572             for (i = 0; i < This->cInTypes; i++)
573             {
574                 for (j = 0; j < cInTypes; j++)
575                 {
576                     if (IsMediaTypeEqual(&pInTypes[j], &This->pInTypes[i]))
577 		        break;
578                 }
579 
580 		if (j >= cInTypes)
581                     break;
582             }
583 
584             if (i < This->cInTypes)
585             {
586                 RegCloseKey(hkey);
587                 continue;
588             }
589         }
590 
591         if (This->pOutTypes)
592         {
593             UINT i, j;
594             DWORD cOutTypes;
595             DMO_PARTIAL_MEDIATYPE* pOutTypes;
596 
597             hres = read_types(hkey, szDMOOutputType, &cOutTypes,
598                     sizeof(szValue)/sizeof(DMO_PARTIAL_MEDIATYPE),
599                     (DMO_PARTIAL_MEDIATYPE*)szValue);
600 
601 	    if (FAILED(hres))
602             {
603                 RegCloseKey(hkey);
604                 continue;
605             }
606 
607 	    pOutTypes = (DMO_PARTIAL_MEDIATYPE*) szValue;
608 
609             TRACE("read %d outtypes for %s:\n", cOutTypes, debugstr_w(szKey));
610             for (i = 0; i < cOutTypes; i++) {
611                 TRACE("outtype %d: type %s, subtype %s\n", i, debugstr_guid(&pOutTypes[i].type),
612                     debugstr_guid(&pOutTypes[i].subtype));
613             }
614 
615             for (i = 0; i < This->cOutTypes; i++)
616             {
617                 for (j = 0; j < cOutTypes; j++)
618                 {
619                     if (IsMediaTypeEqual(&pOutTypes[j], &This->pOutTypes[i]))
620 		        break;
621                 }
622 
623 		if (j >= cOutTypes)
624                     break;
625             }
626 
627             if (i < This->cOutTypes)
628             {
629                 RegCloseKey(hkey);
630                 continue;
631             }
632         }
633 
634 	/* Media object wasn't filtered so add it to return list */
635         Names[count] = NULL;
636 	len = MAX_PATH * sizeof(WCHAR);
637         ret = RegQueryValueExW(hkey, NULL, NULL, NULL, (LPBYTE)szValue, &len);
638         if (ERROR_SUCCESS == ret)
639 	{
640             Names[count] = CoTaskMemAlloc((strlenW(szValue) + 1) * sizeof(WCHAR));
641 	    if (Names[count])
642                 strcpyW(Names[count], szValue);
643 	}
644         wsprintfW(szGuidKey,szToGuidFmt,szNextKey);
645         CLSIDFromString(szGuidKey, &pCLSID[count]);
646 
647         TRACE("found match %s %s\n", debugstr_w(szValue), debugstr_w(szNextKey));
648         RegCloseKey(hkey);
649 	count++;
650     }
651 
652     *pcItemsFetched = count;
653     if (*pcItemsFetched < cItemsToFetch)
654         hres = S_FALSE;
655 
656     TRACE("<-- %i found\n",count);
657     return hres;
658 }
659 
660 
661 /******************************************************************************
662  * IEnumDMO_fnSkip
663  */
664 static HRESULT WINAPI IEnumDMO_fnSkip(IEnumDMO * iface, DWORD cItemsToSkip)
665 {
666     IEnumDMOImpl *This = impl_from_IEnumDMO(iface);
667 
668     TRACE("(%p)->(%d)\n", This, cItemsToSkip);
669     This->index += cItemsToSkip;
670 
671     return S_OK;
672 }
673 
674 
675 /******************************************************************************
676  * IEnumDMO_fnReset
677  */
678 static HRESULT WINAPI IEnumDMO_fnReset(IEnumDMO * iface)
679 {
680     IEnumDMOImpl *This = impl_from_IEnumDMO(iface);
681 
682     TRACE("(%p)\n", This);
683     This->index = -1;
684 
685     return S_OK;
686 }
687 
688 
689 /******************************************************************************
690  * IEnumDMO_fnClone
691  */
692 static HRESULT WINAPI IEnumDMO_fnClone(IEnumDMO *iface, IEnumDMO **ppEnum)
693 {
694     IEnumDMOImpl *This = impl_from_IEnumDMO(iface);
695     TRACE("(%p)->(%p)\n", This, ppEnum);
696     return IEnumDMO_Constructor(&This->category, This->dwFlags, This->cInTypes, This->pInTypes,
697         This->cOutTypes, This->pOutTypes, ppEnum);
698 }
699 
700 
701 /***************************************************************
702  * DMOEnum (MSDMO.@)
703  *
704  * Enumerate DirectX Media Objects in the registry.
705  */
706 HRESULT WINAPI DMOEnum(
707     REFGUID category,
708     DWORD flags,
709     DWORD cInTypes,
710     const DMO_PARTIAL_MEDIATYPE *pInTypes,
711     DWORD cOutTypes,
712     const DMO_PARTIAL_MEDIATYPE *pOutTypes,
713     IEnumDMO **ppEnum)
714 {
715     TRACE("%s 0x%08x %d %p %d %p %p\n", debugstr_guid(category), flags, cInTypes, pInTypes,
716         cOutTypes, pOutTypes, ppEnum);
717 
718     if (TRACE_ON(msdmo))
719     {
720         DWORD i;
721         if (cInTypes)
722         {
723             for (i = 0; i < cInTypes; i++)
724                 TRACE("intype %d - type %s, subtype %s\n", i, debugstr_guid(&pInTypes[i].type),
725                     debugstr_guid(&pInTypes[i].subtype));
726         }
727 
728         if (cOutTypes) {
729             for (i = 0; i < cOutTypes; i++)
730                 TRACE("outtype %d - type %s, subtype %s\n", i, debugstr_guid(&pOutTypes[i].type),
731                     debugstr_guid(&pOutTypes[i].subtype));
732         }
733     }
734 
735     return IEnumDMO_Constructor(category, flags, cInTypes,
736         pInTypes, cOutTypes, pOutTypes, ppEnum);
737 }
738 
739 
740 static const IEnumDMOVtbl edmovt =
741 {
742 	IEnumDMO_fnQueryInterface,
743 	IEnumDMO_fnAddRef,
744 	IEnumDMO_fnRelease,
745 	IEnumDMO_fnNext,
746 	IEnumDMO_fnSkip,
747 	IEnumDMO_fnReset,
748 	IEnumDMO_fnClone,
749 };
750 
751 
752 HRESULT read_types(HKEY root, LPCWSTR key, ULONG *supplied, ULONG requested, DMO_PARTIAL_MEDIATYPE* types )
753 {
754     HRESULT ret = S_OK;
755 
756     if (MSDMO_MAJOR_VERSION > 5)
757     {
758         DWORD len;
759         LONG rc;
760 
761         len = requested * sizeof(DMO_PARTIAL_MEDIATYPE);
762         rc = RegQueryValueExW(root, key, NULL, NULL, (LPBYTE) types, &len);
763         ret = HRESULT_FROM_WIN32(rc);
764 
765         *supplied = len / sizeof(DMO_PARTIAL_MEDIATYPE);
766     }
767     else
768     {
769         HKEY hkey;
770         WCHAR szGuidKey[64];
771 
772         *supplied = 0;
773         if (ERROR_SUCCESS == RegOpenKeyExW(root, key, 0, KEY_READ, &hkey))
774         {
775           int index = 0;
776           WCHAR szNextKey[MAX_PATH];
777           DWORD len;
778           LONG rc = ERROR_SUCCESS;
779 
780           while (rc == ERROR_SUCCESS)
781           {
782             len = MAX_PATH;
783             rc = RegEnumKeyExW(hkey, index, szNextKey, &len, NULL, NULL, NULL, NULL);
784             if (rc == ERROR_SUCCESS)
785             {
786               HKEY subk;
787               int sub_index = 0;
788               LONG rcs = ERROR_SUCCESS;
789               WCHAR szSubKey[MAX_PATH];
790 
791               RegOpenKeyExW(hkey, szNextKey, 0, KEY_READ, &subk);
792               while (rcs == ERROR_SUCCESS)
793               {
794                 len = MAX_PATH;
795                 rcs = RegEnumKeyExW(subk, sub_index, szSubKey, &len, NULL, NULL, NULL, NULL);
796                 if (rcs == ERROR_SUCCESS)
797                 {
798                   if (*supplied >= requested)
799                   {
800                     /* Bailing */
801                     ret = S_FALSE;
802                     rc = ERROR_MORE_DATA;
803                     rcs = ERROR_MORE_DATA;
804                     break;
805                   }
806 
807                   wsprintfW(szGuidKey,szToGuidFmt,szNextKey);
808                   CLSIDFromString(szGuidKey, &types[*supplied].type);
809                   wsprintfW(szGuidKey,szToGuidFmt,szSubKey);
810                   CLSIDFromString(szGuidKey, &types[*supplied].subtype);
811                   TRACE("Adding type %s subtype %s at index %i\n",
812                     debugstr_guid(&types[*supplied].type),
813                     debugstr_guid(&types[*supplied].subtype),
814                     *supplied);
815                   (*supplied)++;
816                 }
817                 sub_index++;
818               }
819               index++;
820             }
821           }
822           RegCloseKey(hkey);
823         }
824     }
825     return ret;
826 }
827 
828 /***************************************************************
829  * DMOGetTypes (MSDMO.@)
830  */
831 HRESULT WINAPI DMOGetTypes(REFCLSID clsidDMO,
832                ULONG ulInputTypesRequested,
833                ULONG* pulInputTypesSupplied,
834                DMO_PARTIAL_MEDIATYPE* pInputTypes,
835                ULONG ulOutputTypesRequested,
836                ULONG* pulOutputTypesSupplied,
837                DMO_PARTIAL_MEDIATYPE* pOutputTypes)
838 {
839   HKEY root,hkey;
840   HRESULT ret = S_OK;
841   WCHAR szguid[64];
842 
843   TRACE ("(%s,%u,%p,%p,%u,%p,%p)\n", debugstr_guid(clsidDMO), ulInputTypesRequested,
844         pulInputTypesSupplied, pInputTypes, ulOutputTypesRequested, pulOutputTypesSupplied,
845         pOutputTypes);
846 
847   if (ERROR_SUCCESS != RegOpenKeyExW(HKEY_CLASSES_ROOT, szDMORootKey, 0,
848                                      KEY_READ, &root))
849     return E_FAIL;
850 
851   if (ERROR_SUCCESS != RegOpenKeyExW(root,GUIDToString(szguid,clsidDMO) , 0,
852                                      KEY_READ, &hkey))
853   {
854     RegCloseKey(root);
855     return E_FAIL;
856   }
857 
858   if (ulInputTypesRequested > 0)
859   {
860     ret = read_types(hkey, szDMOInputType, pulInputTypesSupplied, ulInputTypesRequested, pInputTypes );
861   }
862   else
863     *pulInputTypesSupplied = 0;
864 
865   if (ulOutputTypesRequested > 0)
866   {
867     HRESULT ret2;
868     ret2 = read_types(hkey, szDMOOutputType, pulOutputTypesSupplied, ulOutputTypesRequested, pOutputTypes );
869 
870     if (ret == S_OK)
871         ret = ret2;
872   }
873   else
874     *pulOutputTypesSupplied = 0;
875 
876   return ret;
877 }
878