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