Added last error code for XP SP1.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #define COM_NO_WINDOWS_H
21 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "winerror.h"
27 #include "winreg.h"
28 #include "objbase.h"
29 #include "wine/unicode.h"
30 #include "wine/debug.h"
31 #include "initguid.h"
32 #include "dmo.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(msdmo);
35
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 typedef struct
81 {
82     const IEnumDMOVtbl         *lpVtbl;
83     LONG                        ref;
84     DWORD                       index;
85     const GUID*                 guidCategory;
86     DWORD                       dwFlags;
87     DWORD                       cInTypes;
88     DMO_PARTIAL_MEDIATYPE       *pInTypes;
89     DWORD                       cOutTypes;
90     DMO_PARTIAL_MEDIATYPE       *pOutTypes;
91     HKEY                        hkey;
92 } IEnumDMOImpl;
93
94 static const IEnumDMOVtbl edmovt;
95
96 static LPWSTR GUIDToString(LPWSTR lpwstr, REFGUID lpcguid)
97 {
98     wsprintfW(lpwstr, szGUIDFmt, lpcguid->Data1, lpcguid->Data2,
99         lpcguid->Data3, lpcguid->Data4[0], lpcguid->Data4[1],
100         lpcguid->Data4[2], lpcguid->Data4[3], lpcguid->Data4[4],
101         lpcguid->Data4[5], lpcguid->Data4[6], lpcguid->Data4[7]);
102
103     return lpwstr;
104 }
105
106 static BOOL IsMediaTypeEqual(DMO_PARTIAL_MEDIATYPE* mt1, DMO_PARTIAL_MEDIATYPE* mt2)
107 {
108
109     return (IsEqualCLSID(&mt1->type, &mt2->type) ||
110             IsEqualCLSID(&mt2->type, &GUID_NULL) ||
111             IsEqualCLSID(&mt1->type, &GUID_NULL)) &&
112             (IsEqualCLSID(&mt1->subtype, &mt2->subtype) ||
113             IsEqualCLSID(&mt2->subtype, &GUID_NULL) ||
114             IsEqualCLSID(&mt1->subtype, &GUID_NULL));
115 }
116
117 /***************************************************************
118  * DMORegister
119  *
120  * Register a DirectX Media Object.
121  */
122 HRESULT WINAPI DMORegister(
123    LPCWSTR szName,
124    REFCLSID clsidDMO,
125    REFGUID guidCategory,
126    DWORD dwFlags,
127    DWORD cInTypes,
128    const DMO_PARTIAL_MEDIATYPE *pInTypes,
129    DWORD cOutTypes,
130    const DMO_PARTIAL_MEDIATYPE *pOutTypes
131 )
132 {
133     WCHAR szguid[64];
134     HRESULT hres;
135     HKEY hrkey = 0;
136     HKEY hkey = 0;
137     HKEY hckey = 0;
138     HKEY hclskey = 0;
139
140     TRACE("%s\n", debugstr_w(szName));
141
142     hres = RegOpenKeyExW(HKEY_CLASSES_ROOT, szDMORootKey, 0, KEY_WRITE, &hrkey);
143     if (ERROR_SUCCESS != hres)
144         goto lend;
145
146     /* Create clsidDMO key under MediaObjects */ 
147     hres = RegCreateKeyExW(hrkey, GUIDToString(szguid, clsidDMO), 0, NULL,
148         REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkey, NULL);
149     if (ERROR_SUCCESS != hres)
150         goto lend;
151
152     /* Set default Name value */
153     hres = RegSetValueExW(hkey, NULL, 0, REG_SZ, (const BYTE*) szName, 
154         (strlenW(szName) + 1)) * sizeof(WCHAR);
155     /* Set InputTypes */
156     hres = RegSetValueExW(hkey, szDMOInputType, 0, REG_BINARY, 
157         (const BYTE*) pInTypes, cInTypes * sizeof(DMO_PARTIAL_MEDIATYPE));
158     /* Set OutputTypes */
159     hres = RegSetValueExW(hkey, szDMOOutputType, 0, REG_BINARY, 
160         (const BYTE*) pOutTypes, cOutTypes * sizeof(DMO_PARTIAL_MEDIATYPE));
161
162     if (dwFlags & DMO_REGISTERF_IS_KEYED)
163     {
164         /* Create Keyed key */ 
165         hres = RegCreateKeyExW(hkey, szDMOKeyed, 0, NULL,
166             REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hckey, NULL);
167         if (ERROR_SUCCESS != hres)
168             goto lend;
169         RegCloseKey(hckey);
170     }
171
172     /* Register the category */
173     hres = RegOpenKeyExW(hrkey, szDMOCategories, 0, KEY_WRITE, &hckey);
174     if (ERROR_SUCCESS != hres)
175         goto lend;
176
177     RegCloseKey(hkey);
178
179     hres = RegOpenKeyExW(hckey, GUIDToString(szguid, guidCategory), 0, KEY_WRITE, &hkey);
180     if (ERROR_SUCCESS != hres)
181         goto lend;
182     hres = RegCreateKeyExW(hkey, GUIDToString(szguid, clsidDMO), 0, NULL,
183         REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hclskey, NULL);
184     if (ERROR_SUCCESS != hres)
185         goto lend;
186
187 lend:
188     if (hkey)
189         RegCloseKey(hkey);
190     if (hckey)
191         RegCloseKey(hckey);
192     if (hclskey)
193         RegCloseKey(hclskey);
194     if (hrkey)
195         RegCloseKey(hrkey);
196
197     TRACE(" hresult=0x%08lx\n", hres);
198     return hres;
199 }
200
201
202 /***************************************************************
203  * DMOUnregister
204  *
205  * Unregister a DirectX Media Object.
206  */
207 HRESULT WINAPI DMOUnregister(REFCLSID clsidDMO, REFGUID guidCategory)
208 {
209     HRESULT hres;
210     WCHAR szguid[64];
211     HKEY hrkey = 0;
212     HKEY hckey = 0;
213
214     GUIDToString(szguid, clsidDMO);
215
216     TRACE("%s %p\n", debugstr_w(szguid), guidCategory);
217
218     hres = RegOpenKeyExW(HKEY_CLASSES_ROOT, szDMORootKey, 0, KEY_WRITE, &hrkey);
219     if (ERROR_SUCCESS != hres)
220         goto lend;
221
222     hres = RegDeleteKeyW(hrkey, szguid);
223     if (ERROR_SUCCESS != hres)
224         goto lend;
225
226     hres = RegOpenKeyExW(hrkey, szDMOCategories, 0, KEY_WRITE, &hckey);
227     if (ERROR_SUCCESS != hres)
228         goto lend;
229
230     hres = RegDeleteKeyW(hckey, szguid);
231     if (ERROR_SUCCESS != hres)
232         goto lend;
233
234 lend:
235     if (hckey)
236         RegCloseKey(hckey);
237     if (hrkey)
238         RegCloseKey(hrkey);
239
240     return hres;
241 }
242
243
244 /***************************************************************
245  * DMOGetName
246  *
247  * Get DMP Name from the registry
248  */
249 HRESULT WINAPI DMOGetName(REFCLSID clsidDMO, WCHAR* szName)
250 {
251     WCHAR szguid[64];
252     HRESULT hres;
253     HKEY hrkey = 0;
254     HKEY hkey = 0;
255     DWORD count;
256
257     TRACE("%s\n", debugstr_guid(clsidDMO));
258
259     hres = RegOpenKeyExW(HKEY_CLASSES_ROOT, szDMORootKey, 
260         0, KEY_READ, &hrkey);
261     if (ERROR_SUCCESS != hres)
262         goto lend;
263
264     hres = RegOpenKeyExW(hrkey, GUIDToString(szguid, clsidDMO),
265         0, KEY_READ, &hkey);
266     if (ERROR_SUCCESS != hres)
267         goto lend;
268
269     count = 80 * sizeof(WCHAR); /* 80 by API definition */
270     hres = RegQueryValueExW(hkey, NULL, NULL, NULL, 
271         (LPBYTE) szName, &count); 
272
273     TRACE(" szName=%s\n", debugstr_w(szName));
274 lend:
275     if (hkey)
276         RegCloseKey(hrkey);
277     if (hkey)
278         RegCloseKey(hkey);
279
280     return hres;
281 }
282
283
284 /**************************************************************************
285 *   IEnumDMO_Destructor
286 */
287 static BOOL IEnumDMO_Destructor(IEnumDMO* iface)
288 {
289     IEnumDMOImpl *This = (IEnumDMOImpl *)iface;
290
291     TRACE("%p\n", This);
292
293     if (This->hkey)
294         RegCloseKey(This->hkey);
295
296     HeapFree(GetProcessHeap(), 0, This->pInTypes);
297     HeapFree(GetProcessHeap(), 0, This->pOutTypes);
298
299     return TRUE;
300 }
301
302
303 /**************************************************************************
304  *  IEnumDMO_Constructor
305  */
306 IEnumDMO * IEnumDMO_Constructor(
307     REFGUID guidCategory,
308     DWORD dwFlags,
309     DWORD cInTypes,
310     const DMO_PARTIAL_MEDIATYPE *pInTypes,
311     DWORD cOutTypes,
312     const DMO_PARTIAL_MEDIATYPE *pOutTypes)
313 {
314     UINT size;
315     IEnumDMOImpl* lpedmo;
316     BOOL ret = FALSE;
317
318     lpedmo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumDMOImpl));
319
320     if (lpedmo)
321     {
322         lpedmo->ref = 1;
323         lpedmo->lpVtbl = &edmovt;
324         lpedmo->index = -1;
325         lpedmo->guidCategory = guidCategory;
326         lpedmo->dwFlags = dwFlags;
327
328         size = cInTypes * sizeof(DMO_PARTIAL_MEDIATYPE);
329         lpedmo->pInTypes = HeapAlloc(GetProcessHeap(), 0, size);
330         if (!lpedmo->pInTypes)
331             goto lerr;
332         memcpy(lpedmo->pInTypes, pInTypes, size);
333         lpedmo->cInTypes = cInTypes;
334
335         size = cOutTypes * sizeof(DMO_PARTIAL_MEDIATYPE);
336         lpedmo->pOutTypes = HeapAlloc(GetProcessHeap(), 0, size);
337         if (!lpedmo->pOutTypes)
338             goto lerr;
339         memcpy(lpedmo->pOutTypes, pOutTypes, size);
340         lpedmo->cOutTypes = cOutTypes;
341
342         /* If not filtering by category enum from media objects root */
343         if (IsEqualGUID(guidCategory, &GUID_NULL))
344         {
345             if (ERROR_SUCCESS == RegOpenKeyExW(HKEY_CLASSES_ROOT, szDMORootKey, 
346                 0, KEY_READ, &lpedmo->hkey))
347                 ret = TRUE;
348         }
349         else
350         {
351             WCHAR szguid[64];
352             WCHAR szKey[MAX_PATH];
353
354             wsprintfW(szKey, szCat3Fmt, szDMORootKey, szDMOCategories, 
355                 GUIDToString(szguid, guidCategory));
356             if (ERROR_SUCCESS == RegOpenKeyExW(HKEY_CLASSES_ROOT, szKey, 
357                 0, KEY_READ, &lpedmo->hkey))
358                 ret = TRUE;
359         }
360
361 lerr:
362         if(!ret)
363         {
364             IEnumDMO_Destructor((IEnumDMO*)lpedmo);
365             HeapFree(GetProcessHeap(),0,lpedmo);
366             lpedmo = NULL;
367         }
368     }
369
370     TRACE("returning %p\n", lpedmo);
371
372     return (IEnumDMO*)lpedmo;
373 }
374
375
376 /******************************************************************************
377  * IEnumDMO_fnAddRef
378  */
379 static ULONG WINAPI IEnumDMO_fnAddRef(IEnumDMO * iface)
380 {
381     IEnumDMOImpl *This = (IEnumDMOImpl *)iface;
382     return InterlockedIncrement(&This->ref);
383 }
384
385
386 /**************************************************************************
387  *  EnumDMO_QueryInterface
388  */
389 static HRESULT WINAPI IEnumDMO_fnQueryInterface(
390     IEnumDMO* iface,
391     REFIID riid,
392     LPVOID *ppvObj)
393 {
394     IEnumDMOImpl *This = (IEnumDMOImpl *)iface;
395
396     *ppvObj = NULL;
397
398     if(IsEqualIID(riid, &IID_IUnknown))
399         *ppvObj = This;
400     else if(IsEqualIID(riid, &IID_IEnumDMO))
401         *ppvObj = (IEnumDMO*)This;
402
403     if(*ppvObj)
404     {
405         IEnumDMO_fnAddRef((IEnumDMO*)*ppvObj);
406         return S_OK;
407     }
408
409     return E_NOINTERFACE;
410 }
411
412
413 /******************************************************************************
414  * IEnumDMO_fnRelease
415  */
416 static ULONG WINAPI IEnumDMO_fnRelease(IEnumDMO * iface)
417 {
418     IEnumDMOImpl *This = (IEnumDMOImpl *)iface;
419     ULONG refCount = InterlockedDecrement(&This->ref);
420
421     if (!refCount)
422     {
423         IEnumDMO_Destructor((IEnumDMO*)This);
424         HeapFree(GetProcessHeap(),0,This);
425     }
426     return refCount;
427 }
428
429
430 /******************************************************************************
431  * IEnumDMO_fnNext
432  */
433 static HRESULT WINAPI IEnumDMO_fnNext(
434     IEnumDMO * iface, 
435     DWORD cItemsToFetch,
436     CLSID * pCLSID,
437     WCHAR ** Names,
438     DWORD * pcItemsFetched)
439 {
440     FILETIME ft;
441     HKEY hkey;
442     WCHAR szNextKey[MAX_PATH];
443     WCHAR szKey[MAX_PATH];
444     WCHAR szValue[MAX_PATH];
445     DWORD len;
446     UINT count = 0;
447     HRESULT hres = S_OK;
448
449     IEnumDMOImpl *This = (IEnumDMOImpl *)iface;
450
451     TRACE("%ld\n", cItemsToFetch);
452
453     if (!pCLSID || !Names || !pcItemsFetched)
454         return E_POINTER;
455
456     while (count < cItemsToFetch)
457     {
458         This->index++;
459
460         hres = RegEnumKeyExW(This->hkey, This->index, szNextKey, &len, NULL, NULL, NULL, &ft);
461         if (hres != ERROR_SUCCESS)
462             break;
463
464         TRACE("found %s\n", debugstr_w(szNextKey));
465
466         if (This->dwFlags & DMO_REGISTERF_IS_KEYED)
467         {
468             wsprintfW(szKey, szCat3Fmt, szDMORootKey, szNextKey, szDMOKeyed);
469             hres = RegOpenKeyExW(HKEY_CLASSES_ROOT, szKey, 0, KEY_READ, &hkey);
470             if (ERROR_SUCCESS != hres)
471                 continue;
472             RegCloseKey(hkey);
473         }
474
475         wsprintfW(szKey, szCat2Fmt, szDMORootKey, szNextKey);
476         hres = RegOpenKeyExW(HKEY_CLASSES_ROOT, szKey, 0, KEY_READ, &hkey);
477
478         if (This->pInTypes)
479         {
480             UINT i, j;
481             DWORD cInTypes;
482             DMO_PARTIAL_MEDIATYPE* pInTypes;
483
484             len = MAX_PATH * sizeof(WCHAR);
485             hres = RegQueryValueExW(hkey, szDMOInputType, NULL, NULL, (LPBYTE) szValue, &len);
486             if (ERROR_SUCCESS != hres)
487             {
488                 RegCloseKey(hkey);
489                 continue;
490             }
491
492             cInTypes = len / sizeof(DMO_PARTIAL_MEDIATYPE);
493             pInTypes = (DMO_PARTIAL_MEDIATYPE*) szValue;
494
495             for (i = 0; i < This->cInTypes; i++)
496             {
497                 for (j = 0; j < cInTypes; j++) 
498                 {
499                     if (IsMediaTypeEqual(&pInTypes[j], &This->pInTypes[i]))
500                         break;
501                 }
502
503                 if (j >= cInTypes)
504                     break;
505             }
506
507             if (i < This->cInTypes)
508             {
509                 RegCloseKey(hkey);
510                 continue;
511             }
512         }
513
514         if (This->pOutTypes)
515         {
516             UINT i, j;
517             DWORD cOutTypes;
518             DMO_PARTIAL_MEDIATYPE* pOutTypes;
519
520             len = MAX_PATH * sizeof(WCHAR);
521             hres = RegQueryValueExW(hkey, szDMOOutputType, NULL, NULL, (LPBYTE) szValue, &len);
522             if (ERROR_SUCCESS != hres)
523             {
524                 RegCloseKey(hkey);
525                 continue;
526             }
527
528             cOutTypes = len / sizeof(DMO_PARTIAL_MEDIATYPE);
529             pOutTypes = (DMO_PARTIAL_MEDIATYPE*) szValue;
530
531             for (i = 0; i < This->cOutTypes; i++)
532             {
533                 for (j = 0; j < cOutTypes; j++) 
534                 {
535                     if (IsMediaTypeEqual(&pOutTypes[j], &This->pOutTypes[i]))
536                         break;
537                 }
538
539                 if (j >= cOutTypes)
540                     break;
541             }
542
543             if (i < This->cOutTypes)
544             {
545                 RegCloseKey(hkey);
546                 continue;
547             }
548         }
549
550         /* Media object wasn't filtered so add it to return list */
551         Names[count] = NULL;
552         len = MAX_PATH * sizeof(WCHAR);
553         hres = RegQueryValueExW(hkey, NULL, NULL, NULL, (LPBYTE) szValue, &len); 
554         if (ERROR_SUCCESS == hres)
555         {
556             Names[count] = HeapAlloc(GetProcessHeap(), 0, strlenW(szValue) + 1);
557             if (Names[count])
558                 strcmpW(Names[count], szValue);
559         }
560         CLSIDFromString(szNextKey, &pCLSID[count]);
561
562         TRACE("found match %s %s\n", debugstr_w(szValue), debugstr_w(szNextKey));
563         RegCloseKey(hkey);
564         count++;
565     }
566
567     *pcItemsFetched = count;
568     if (*pcItemsFetched < cItemsToFetch)
569         hres = S_FALSE;
570
571     return hres;
572 }
573  
574
575 /******************************************************************************
576  * IEnumDMO_fnSkip
577  */
578 static HRESULT WINAPI IEnumDMO_fnSkip(IEnumDMO * iface, DWORD cItemsToSkip)
579 {
580     IEnumDMOImpl *This = (IEnumDMOImpl *)iface;
581
582     This->index += cItemsToSkip;
583
584     return S_OK;
585 }
586
587
588 /******************************************************************************
589  * IEnumDMO_fnReset
590  */
591 static HRESULT WINAPI IEnumDMO_fnReset(IEnumDMO * iface)
592 {
593     IEnumDMOImpl *This = (IEnumDMOImpl *)iface;
594
595     This->index = -1;
596
597     return S_OK;
598 }
599  
600
601 /******************************************************************************
602  * IEnumDMO_fnClone
603  */
604 static HRESULT WINAPI IEnumDMO_fnClone(IEnumDMO * iface, IEnumDMO **ppEnum)
605 {
606     IEnumDMOImpl *This = (IEnumDMOImpl *)iface;
607
608     FIXME("(%p)->() to (%p)->() E_NOTIMPL\n", This, ppEnum);
609
610   return E_NOTIMPL;
611 }
612
613
614 /***************************************************************
615  * DMOEnum
616  *
617  * Enumerate DirectX Media Objects in the registry.
618  */
619 HRESULT WINAPI DMOEnum(
620     REFGUID guidCategory,
621     DWORD dwFlags,
622     DWORD cInTypes,
623     const DMO_PARTIAL_MEDIATYPE *pInTypes,
624     DWORD cOutTypes,
625     const DMO_PARTIAL_MEDIATYPE *pOutTypes,
626     IEnumDMO **ppEnum)
627 {
628     HRESULT hres = E_FAIL;
629
630     TRACE("guidCategory=%p dwFlags=0x%08lx cInTypes=%ld cOutTypes=%ld\n",
631         guidCategory, dwFlags, cInTypes, cOutTypes);
632
633     *ppEnum = IEnumDMO_Constructor(guidCategory, dwFlags, cInTypes,
634         pInTypes, cOutTypes, pOutTypes);
635     if (*ppEnum)
636         hres = S_OK;
637
638     return hres;
639 }
640
641
642 static const IEnumDMOVtbl edmovt =
643 {
644         IEnumDMO_fnQueryInterface,
645         IEnumDMO_fnAddRef,
646         IEnumDMO_fnRelease,
647         IEnumDMO_fnNext,
648         IEnumDMO_fnSkip,
649         IEnumDMO_fnReset,
650         IEnumDMO_fnClone,
651 };
652
653
654 HRESULT WINAPI DMOGetTypes(REFCLSID a, unsigned long b, unsigned long* c,
655                            DMO_PARTIAL_MEDIATYPE* d, unsigned long e,
656                            unsigned long* f, DMO_PARTIAL_MEDIATYPE* g)
657 {
658   FIXME("(%p,%lu,%p,%p,%lu,%p,%p),stub!\n",a,b,c,d,e,f,g);
659
660   return E_NOTIMPL;
661 }