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