Added a framework for testing CreateProcess and a few tests.
[wine] / dlls / quartz / main.c
1 /*
2  * Exported APIs.
3  *
4  * Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include "windef.h"
24 #include "winerror.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winnls.h"
29 #include "mmsystem.h"
30 #include "ole2.h"
31 #include "strmif.h"
32 #include "control.h"
33 #include "uuids.h"
34 #include "errors.h"
35
36 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
38
39 #include "initguid.h"
40
41 #include "quartz_private.h"
42 #include "fgraph.h"
43 #include "sysclock.h"
44 #include "memalloc.h"
45 #include "devenum.h"
46 #include "fmap.h"
47 #include "seekpass.h"
48 #include "audren.h"
49 #include "vidren.h"
50 #include "parser.h"
51 #include "asyncsrc.h"
52 #include "xform.h"
53 #include "capgraph.h"
54 #include "filesink.h"
55
56
57 typedef struct QUARTZ_CLASSENTRY
58 {
59         const CLSID*    pclsid;
60         QUARTZ_pCreateIUnknown  pCreateIUnk;
61 } QUARTZ_CLASSENTRY;
62
63
64 static HRESULT WINAPI
65 IClassFactory_fnQueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj);
66 static ULONG WINAPI IClassFactory_fnAddRef(LPCLASSFACTORY iface);
67 static ULONG WINAPI IClassFactory_fnRelease(LPCLASSFACTORY iface);
68 static HRESULT WINAPI IClassFactory_fnCreateInstance(LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj);
69 static HRESULT WINAPI IClassFactory_fnLockServer(LPCLASSFACTORY iface,BOOL dolock);
70
71 static ICOM_VTABLE(IClassFactory) iclassfact =
72 {
73         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
74         IClassFactory_fnQueryInterface,
75         IClassFactory_fnAddRef,
76         IClassFactory_fnRelease,
77         IClassFactory_fnCreateInstance,
78         IClassFactory_fnLockServer
79 };
80
81 typedef struct
82 {
83         /* IUnknown fields */
84         ICOM_VFIELD(IClassFactory);
85         LONG    ref;
86         /* IClassFactory fields */
87         const QUARTZ_CLASSENTRY* pEntry;
88 } IClassFactoryImpl;
89
90 static const QUARTZ_CLASSENTRY QUARTZ_ClassList[] =
91 {
92         { &CLSID_FilterGraph, &QUARTZ_CreateFilterGraph },
93         { &CLSID_FilterGraphNoThread, &QUARTZ_CreateFilterGraph }, /* FIXME? */
94         { &CLSID_SystemClock, &QUARTZ_CreateSystemClock },
95         { &CLSID_MemoryAllocator, &QUARTZ_CreateMemoryAllocator },
96         { &CLSID_SystemDeviceEnum, &QUARTZ_CreateSystemDeviceEnum },
97         { &CLSID_FilterMapper, &QUARTZ_CreateFilterMapper },
98         { &CLSID_FilterMapper2, &QUARTZ_CreateFilterMapper2 },
99         { &CLSID_SeekingPassThru, &QUARTZ_CreateSeekingPassThru },
100         { &CLSID_CaptureGraphBuilder, &QUARTZ_CreateCaptureGraph },
101
102         { &CLSID_AudioRender, &QUARTZ_CreateAudioRenderer },
103         { &CLSID_VideoRenderer, &QUARTZ_CreateVideoRenderer },
104         { &CLSID_quartzWaveParser, &QUARTZ_CreateWaveParser },
105         { &CLSID_AviSplitter, &QUARTZ_CreateAVISplitter },
106         { &CLSID_MPEG1Splitter, &QUARTZ_CreateMPEG1Splitter },
107         { &CLSID_AsyncReader, &QUARTZ_CreateAsyncReader },
108         { &CLSID_URLReader, &QUARTZ_CreateURLReader },
109         { &CLSID_AVIDec, &QUARTZ_CreateAVIDec },
110         { &CLSID_Colour, &QUARTZ_CreateColour },
111         { &CLSID_ACMWrapper, &QUARTZ_CreateACMWrapper },
112         { &CLSID_FileWriter, &QUARTZ_CreateFileWriter },
113         { &CLSID_CMpegAudioCodec, &QUARTZ_CreateCMpegAudioCodec },
114         { &CLSID_CMpegVideoCodec, &QUARTZ_CreateCMpegVideoCodec },
115         { &CLSID_quartzQuickTimeMovieParser, &QUARTZ_CreateQuickTimeMovieParser },
116         { &CLSID_quartzMIDIParser, &QUARTZ_CreateMIDIParser },
117         { &CLSID_quartzMJPGDecompressor, QUARTZ_CreateMJPGDecompressor },
118         { &CLSID_quartzQuickTimeDecompressor, QUARTZ_CreateQuickTimeDecompressor },
119         { NULL, NULL },
120 };
121
122 /* per-process variables */
123 static CRITICAL_SECTION csHeap;
124 static DWORD dwClassObjRef;
125 static HANDLE hDLLHeap;
126
127 void* QUARTZ_AllocObj( DWORD dwSize )
128 {
129         void*   pv;
130
131         EnterCriticalSection( &csHeap );
132         dwClassObjRef ++;
133         pv = HeapAlloc( hDLLHeap, 0, dwSize );
134         if ( pv == NULL )
135                 dwClassObjRef --;
136         LeaveCriticalSection( &csHeap );
137
138         return pv;
139 }
140
141 void QUARTZ_FreeObj( void* pobj )
142 {
143         EnterCriticalSection( &csHeap );
144         HeapFree( hDLLHeap, 0, pobj );
145         dwClassObjRef --;
146         LeaveCriticalSection( &csHeap );
147 }
148
149 void* QUARTZ_AllocMem( DWORD dwSize )
150 {
151         return HeapAlloc( hDLLHeap, 0, dwSize );
152 }
153
154 void QUARTZ_FreeMem( void* pMem )
155 {
156         HeapFree( hDLLHeap, 0, pMem );
157 }
158
159 void* QUARTZ_ReallocMem( void* pMem, DWORD dwSize )
160 {
161         if ( pMem == NULL )
162                 return QUARTZ_AllocMem( dwSize );
163
164         return HeapReAlloc( hDLLHeap, 0, pMem, dwSize );
165 }
166
167 static
168 LPWSTR QUARTZ_strncpyAtoW( LPWSTR lpwstr, LPCSTR lpstr, INT wbuflen )
169 {
170         INT     len;
171
172         len = MultiByteToWideChar( CP_ACP, 0, lpstr, -1, lpwstr, wbuflen );
173         if ( len == 0 )
174                 *lpwstr = 0;
175         return lpwstr;
176 }
177
178
179 /************************************************************************/
180
181 static HRESULT WINAPI
182 IClassFactory_fnQueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
183 {
184         ICOM_THIS(IClassFactoryImpl,iface);
185
186         TRACE("(%p)->(%p,%p)\n",This,riid,ppobj);
187         if ( ( IsEqualGUID( &IID_IUnknown, riid ) ) ||
188              ( IsEqualGUID( &IID_IClassFactory, riid ) ) )
189         {
190                 *ppobj = iface;
191                 IClassFactory_AddRef(iface);
192                 return S_OK;
193         }
194
195         return E_NOINTERFACE;
196 }
197
198 static ULONG WINAPI IClassFactory_fnAddRef(LPCLASSFACTORY iface)
199 {
200         ICOM_THIS(IClassFactoryImpl,iface);
201
202         TRACE("(%p)->()\n",This);
203
204         return InterlockedExchangeAdd(&(This->ref),1) + 1;
205 }
206
207 static ULONG WINAPI IClassFactory_fnRelease(LPCLASSFACTORY iface)
208 {
209         ICOM_THIS(IClassFactoryImpl,iface);
210         LONG    ref;
211
212         TRACE("(%p)->()\n",This);
213         ref = InterlockedExchangeAdd(&(This->ref),-1) - 1;
214         if ( ref > 0 )
215                 return (ULONG)ref;
216
217         QUARTZ_FreeObj(This);
218         return 0;
219 }
220
221 static HRESULT WINAPI IClassFactory_fnCreateInstance(LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj)
222 {
223         ICOM_THIS(IClassFactoryImpl,iface);
224         HRESULT hr;
225         IUnknown*       punk;
226
227         TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
228
229         if ( ppobj == NULL )
230                 return E_POINTER;
231         if ( pOuter != NULL && !IsEqualGUID( riid, &IID_IUnknown ) )
232                 return CLASS_E_NOAGGREGATION;
233
234         *ppobj = NULL;
235
236         hr = (*This->pEntry->pCreateIUnk)(pOuter,(void**)&punk);
237         if ( hr != S_OK )
238                 return hr;
239
240         hr = IUnknown_QueryInterface(punk,riid,ppobj);
241         IUnknown_Release(punk);
242
243         return hr;
244 }
245
246 static HRESULT WINAPI IClassFactory_fnLockServer(LPCLASSFACTORY iface,BOOL dolock)
247 {
248         ICOM_THIS(IClassFactoryImpl,iface);
249         HRESULT hr;
250
251         TRACE("(%p)->(%d)\n",This,dolock);
252         if (dolock)
253                 hr = IClassFactory_AddRef(iface);
254         else
255                 hr = IClassFactory_Release(iface);
256
257         return hr;
258 }
259
260
261
262 static HRESULT IClassFactory_Alloc( const CLSID* pclsid, void** ppobj )
263 {
264         const QUARTZ_CLASSENTRY*        pEntry;
265         IClassFactoryImpl*      pImpl;
266
267         TRACE( "(%s,%p)\n", debugstr_guid(pclsid), ppobj );
268
269         pEntry = QUARTZ_ClassList;
270         while ( pEntry->pclsid != NULL )
271         {
272                 if ( IsEqualGUID( pclsid, pEntry->pclsid ) )
273                         goto found;
274                 pEntry ++;
275         }
276
277         return CLASS_E_CLASSNOTAVAILABLE;
278 found:
279         pImpl = (IClassFactoryImpl*)QUARTZ_AllocObj( sizeof(IClassFactoryImpl) );
280         if ( pImpl == NULL )
281                 return E_OUTOFMEMORY;
282
283         TRACE( "allocated successfully.\n" );
284
285         ICOM_VTBL(pImpl) = &iclassfact;
286         pImpl->ref = 1;
287         pImpl->pEntry = pEntry;
288
289         *ppobj = (void*)pImpl;
290         return S_OK;
291 }
292
293
294 /***********************************************************************
295  *              QUARTZ_InitProcess (internal)
296  */
297 static BOOL QUARTZ_InitProcess( void )
298 {
299         TRACE("()\n");
300
301         dwClassObjRef = 0;
302         hDLLHeap = (HANDLE)NULL;
303         InitializeCriticalSection( &csHeap );
304
305         hDLLHeap = HeapCreate( 0, 0x10000, 0 );
306         if ( hDLLHeap == (HANDLE)NULL )
307                 return FALSE;
308
309         return TRUE;
310 }
311
312 /***********************************************************************
313  *              QUARTZ_UninitProcess (internal)
314  */
315 static void QUARTZ_UninitProcess( void )
316 {
317         TRACE("()\n");
318
319         if ( dwClassObjRef != 0 )
320                 ERR( "you must release some objects allocated from quartz.\n" );
321         if ( hDLLHeap != (HANDLE)NULL )
322         {
323                 HeapDestroy( hDLLHeap );
324                 hDLLHeap = (HANDLE)NULL;
325         }
326         DeleteCriticalSection( &csHeap );
327 }
328
329 /***********************************************************************
330  *              QUARTZ_DllMain
331  */
332 BOOL WINAPI QUARTZ_DllMain(
333         HINSTANCE hInstDLL,
334         DWORD fdwReason,
335         LPVOID lpvReserved )
336 {
337         TRACE("(%08x,%08lx,%p)\n",hInstDLL,fdwReason,lpvReserved);
338
339         switch ( fdwReason )
340         {
341         case DLL_PROCESS_ATTACH:
342                 if ( !QUARTZ_InitProcess() )
343                         return FALSE;
344                 break;
345         case DLL_PROCESS_DETACH:
346                 QUARTZ_UninitProcess();
347                 break;
348         case DLL_THREAD_ATTACH:
349                 break;
350         case DLL_THREAD_DETACH:
351                 break;
352         }
353
354         return TRUE;
355 }
356
357
358 /***********************************************************************
359  *              DllCanUnloadNow (QUARTZ.@)
360  *
361  * RETURNS
362  *    Success: S_OK
363  *    Failure: S_FALSE
364  */
365 HRESULT WINAPI QUARTZ_DllCanUnloadNow(void)
366 {
367         HRESULT hr;
368
369         EnterCriticalSection( &csHeap );
370         hr = ( dwClassObjRef == 0 ) ? S_OK : S_FALSE;
371         LeaveCriticalSection( &csHeap );
372
373         return hr;
374 }
375
376 /***********************************************************************
377  *              DllGetClassObject (QUARTZ.@)
378  */
379 HRESULT WINAPI QUARTZ_DllGetClassObject(
380                 const CLSID* pclsid,const IID* piid,void** ppv)
381 {
382         *ppv = NULL;
383         if ( IsEqualCLSID( &IID_IUnknown, piid ) ||
384              IsEqualCLSID( &IID_IClassFactory, piid ) )
385         {
386                 return IClassFactory_Alloc( pclsid, ppv );
387         }
388
389         return CLASS_E_CLASSNOTAVAILABLE;
390 }
391
392 /***********************************************************************
393  *              DllRegisterServer (QUARTZ.@)
394  */
395
396 HRESULT WINAPI QUARTZ_DllRegisterServer( void )
397 {
398         FIXME( "(): stub\n" );
399         return E_FAIL;
400 }
401
402 /***********************************************************************
403  *              DllUnregisterServer (QUARTZ.@)
404  */
405
406 HRESULT WINAPI QUARTZ_DllUnregisterServer( void )
407 {
408         FIXME( "(): stub\n" );
409         return E_FAIL;
410 }
411
412 /**************************************************************************/
413 /**************************************************************************/
414
415 /* FIXME - all string should be defined in the resource of quartz. */
416
417 static LPCSTR hresult_to_string( HRESULT hr )
418 {
419         switch ( hr )
420         {
421         #define ENTRY(x)        case x: return (const char*)#x
422         /* some known codes */
423         ENTRY(S_OK);
424         ENTRY(S_FALSE);
425         ENTRY(E_FAIL);
426         ENTRY(E_POINTER);
427         ENTRY(E_NOTIMPL);
428         ENTRY(E_NOINTERFACE);
429         ENTRY(E_OUTOFMEMORY);
430         ENTRY(CLASS_E_CLASSNOTAVAILABLE);
431         ENTRY(CLASS_E_NOAGGREGATION);
432
433         /* vfwmsgs.h */
434         ENTRY(VFW_S_NO_MORE_ITEMS);
435         ENTRY(VFW_E_BAD_KEY);
436         ENTRY(VFW_E_INVALIDMEDIATYPE);
437         ENTRY(VFW_E_INVALIDSUBTYPE);
438         ENTRY(VFW_E_NEED_OWNER);
439         ENTRY(VFW_E_ENUM_OUT_OF_SYNC);
440         ENTRY(VFW_E_ALREADY_CONNECTED);
441         ENTRY(VFW_E_FILTER_ACTIVE);
442         ENTRY(VFW_E_NO_TYPES);
443         ENTRY(VFW_E_NO_ACCEPTABLE_TYPES);
444         ENTRY(VFW_E_INVALID_DIRECTION);
445         ENTRY(VFW_E_NOT_CONNECTED);
446         ENTRY(VFW_E_NO_ALLOCATOR);
447         ENTRY(VFW_E_RUNTIME_ERROR);
448         ENTRY(VFW_E_BUFFER_NOTSET);
449         ENTRY(VFW_E_BUFFER_OVERFLOW);
450         ENTRY(VFW_E_BADALIGN);
451         ENTRY(VFW_E_ALREADY_COMMITTED);
452         ENTRY(VFW_E_BUFFERS_OUTSTANDING);
453         ENTRY(VFW_E_NOT_COMMITTED);
454         ENTRY(VFW_E_SIZENOTSET);
455         ENTRY(VFW_E_NO_CLOCK);
456         ENTRY(VFW_E_NO_SINK);
457         ENTRY(VFW_E_NO_INTERFACE);
458         ENTRY(VFW_E_NOT_FOUND);
459         ENTRY(VFW_E_CANNOT_CONNECT);
460         ENTRY(VFW_E_CANNOT_RENDER);
461         ENTRY(VFW_E_CHANGING_FORMAT);
462         ENTRY(VFW_E_NO_COLOR_KEY_SET);
463         ENTRY(VFW_E_NOT_OVERLAY_CONNECTION);
464         ENTRY(VFW_E_NOT_SAMPLE_CONNECTION);
465         ENTRY(VFW_E_PALETTE_SET);
466         ENTRY(VFW_E_COLOR_KEY_SET);
467         ENTRY(VFW_E_NO_COLOR_KEY_FOUND);
468         ENTRY(VFW_E_NO_PALETTE_AVAILABLE);
469         ENTRY(VFW_E_NO_DISPLAY_PALETTE);
470         ENTRY(VFW_E_TOO_MANY_COLORS);
471         ENTRY(VFW_E_STATE_CHANGED);
472         ENTRY(VFW_E_NOT_STOPPED);
473         ENTRY(VFW_E_NOT_PAUSED);
474         ENTRY(VFW_E_NOT_RUNNING);
475         ENTRY(VFW_E_WRONG_STATE);
476         ENTRY(VFW_E_START_TIME_AFTER_END);
477         ENTRY(VFW_E_INVALID_RECT);
478         ENTRY(VFW_E_TYPE_NOT_ACCEPTED);
479         ENTRY(VFW_E_SAMPLE_REJECTED);
480         ENTRY(VFW_E_SAMPLE_REJECTED_EOS);
481         ENTRY(VFW_S_DUPLICATE_NAME);
482         ENTRY(VFW_E_DUPLICATE_NAME);
483         ENTRY(VFW_E_TIMEOUT);
484         ENTRY(VFW_E_INVALID_FILE_FORMAT);
485         ENTRY(VFW_E_ENUM_OUT_OF_RANGE);
486         ENTRY(VFW_E_CIRCULAR_GRAPH);
487         ENTRY(VFW_E_NOT_ALLOWED_TO_SAVE);
488         ENTRY(VFW_E_TIME_ALREADY_PASSED);
489         ENTRY(VFW_E_ALREADY_CANCELLED);
490         ENTRY(VFW_E_CORRUPT_GRAPH_FILE);
491         ENTRY(VFW_E_ADVISE_ALREADY_SET);
492         ENTRY(VFW_S_STATE_INTERMEDIATE);
493         ENTRY(VFW_E_NO_MODEX_AVAILABLE);
494         ENTRY(VFW_E_NO_ADVISE_SET);
495         ENTRY(VFW_E_NO_FULLSCREEN);
496         ENTRY(VFW_E_IN_FULLSCREEN_MODE);
497         ENTRY(VFW_E_UNKNOWN_FILE_TYPE);
498         ENTRY(VFW_E_CANNOT_LOAD_SOURCE_FILTER);
499         ENTRY(VFW_S_PARTIAL_RENDER);
500         ENTRY(VFW_E_FILE_TOO_SHORT);
501         ENTRY(VFW_E_INVALID_FILE_VERSION);
502         ENTRY(VFW_S_SOME_DATA_IGNORED);
503         ENTRY(VFW_S_CONNECTIONS_DEFERRED);
504         ENTRY(VFW_E_INVALID_CLSID);
505         ENTRY(VFW_E_INVALID_MEDIA_TYPE);
506         ENTRY(VFW_E_SAMPLE_TIME_NOT_SET);
507         ENTRY(VFW_S_RESOURCE_NOT_NEEDED);
508         ENTRY(VFW_E_MEDIA_TIME_NOT_SET);
509         ENTRY(VFW_E_NO_TIME_FORMAT_SET);
510         ENTRY(VFW_E_MONO_AUDIO_HW);
511         ENTRY(VFW_S_MEDIA_TYPE_IGNORED);
512         ENTRY(VFW_E_NO_DECOMPRESSOR);
513         ENTRY(VFW_E_NO_AUDIO_HARDWARE);
514         ENTRY(VFW_S_VIDEO_NOT_RENDERED);
515         ENTRY(VFW_S_AUDIO_NOT_RENDERED);
516         ENTRY(VFW_E_RPZA);
517         ENTRY(VFW_S_RPZA);
518         ENTRY(VFW_E_PROCESSOR_NOT_SUITABLE);
519         ENTRY(VFW_E_UNSUPPORTED_AUDIO);
520         ENTRY(VFW_E_UNSUPPORTED_VIDEO);
521         ENTRY(VFW_E_MPEG_NOT_CONSTRAINED);
522         ENTRY(VFW_E_NOT_IN_GRAPH);
523         ENTRY(VFW_S_ESTIMATED);
524         ENTRY(VFW_E_NO_TIME_FORMAT);
525         ENTRY(VFW_E_READ_ONLY);
526         ENTRY(VFW_S_RESERVED);
527         ENTRY(VFW_E_BUFFER_UNDERFLOW);
528         ENTRY(VFW_E_UNSUPPORTED_STREAM);
529         ENTRY(VFW_E_NO_TRANSPORT);
530         ENTRY(VFW_S_STREAM_OFF);
531         ENTRY(VFW_S_CANT_CUE);
532         ENTRY(VFW_E_BAD_VIDEOCD);
533         ENTRY(VFW_S_NO_STOP_TIME);
534         ENTRY(VFW_E_OUT_OF_VIDEO_MEMORY);
535         ENTRY(VFW_E_VP_NEGOTIATION_FAILED);
536         ENTRY(VFW_E_DDRAW_CAPS_NOT_SUITABLE);
537         ENTRY(VFW_E_NO_VP_HARDWARE);
538         ENTRY(VFW_E_NO_CAPTURE_HARDWARE);
539         ENTRY(VFW_E_DVD_OPERATION_INHIBITED);
540         ENTRY(VFW_E_DVD_INVALIDDOMAIN);
541         ENTRY(VFW_E_DVD_NO_BUTTON);
542         ENTRY(VFW_E_DVD_GRAPHNOTREADY);
543         ENTRY(VFW_E_DVD_RENDERFAIL);
544         ENTRY(VFW_E_DVD_DECNOTENOUGH);
545         ENTRY(VFW_E_DDRAW_VERSION_NOT_SUITABLE);
546         ENTRY(VFW_E_COPYPROT_FAILED);
547         ENTRY(VFW_S_NOPREVIEWPIN);
548         ENTRY(VFW_E_TIME_EXPIRED);
549         ENTRY(VFW_S_DVD_NON_ONE_SEQUENTIAL);
550         ENTRY(VFW_E_DVD_WRONG_SPEED);
551         ENTRY(VFW_E_DVD_MENU_DOES_NOT_EXIST);
552         ENTRY(VFW_E_DVD_CMD_CANCELLED);
553         ENTRY(VFW_E_DVD_STATE_WRONG_VERSION);
554         ENTRY(VFW_E_DVD_STATE_CORRUPT);
555         ENTRY(VFW_E_DVD_STATE_WRONG_DISC);
556         ENTRY(VFW_E_DVD_INCOMPATIBLE_REGION);
557         ENTRY(VFW_E_DVD_NO_ATTRIBUTES);
558         ENTRY(VFW_E_DVD_NO_GOUP_PGC);
559         ENTRY(VFW_E_DVD_LOW_PARENTAL_LEVEL);
560         ENTRY(VFW_E_DVD_NOT_IN_KARAOKE_MODE);
561         ENTRY(VFW_S_DVD_CHANNEL_CONTENTS_NOT_AVAILABLE);
562         ENTRY(VFW_S_DVD_NOT_ACCURATE);
563         ENTRY(VFW_E_FRAME_STEP_UNSUPPORTED);
564         ENTRY(VFW_E_DVD_STREAM_DISABLED);
565         ENTRY(VFW_E_DVD_TITLE_UNKNOWN);
566         ENTRY(VFW_E_DVD_INVALID_DISC);
567         ENTRY(VFW_E_DVD_NO_RESUME_INFORMATION);
568         ENTRY(VFW_E_PIN_ALREADY_BLOCKED_ON_THIS_THREAD);
569         ENTRY(VFW_E_PIN_ALREADY_BLOCKED);
570         ENTRY(VFW_E_CERTIFICATION_FAILURE);
571         #undef  ENTRY
572         }
573
574         return NULL;
575 }
576
577 /***********************************************************************
578  *      AMGetErrorTextA (quartz.@)
579  */
580 DWORD WINAPI AMGetErrorTextA(HRESULT hr, LPSTR pszbuf, DWORD dwBufLen)
581 {
582         LPCSTR  lpszRes;
583         DWORD len;
584
585         lpszRes = hresult_to_string( hr );
586         if ( lpszRes == NULL )
587                 return 0;
588         len = (DWORD)(strlen(lpszRes)+1);
589         if ( len > dwBufLen )
590                 return 0;
591
592         memcpy( pszbuf, lpszRes, len );
593         return len;
594 }
595
596 /***********************************************************************
597  *      AMGetErrorTextW (quartz.@)
598  */
599 DWORD WINAPI AMGetErrorTextW(HRESULT hr, LPWSTR pwszbuf, DWORD dwBufLen)
600 {
601         CHAR    szBuf[MAX_ERROR_TEXT_LEN+1];
602         DWORD   dwLen;
603
604         dwLen = AMGetErrorTextA(hr,szBuf,MAX_ERROR_TEXT_LEN);
605         if ( dwLen == 0 )
606                 return 0;
607         szBuf[dwLen] = 0;
608
609         QUARTZ_strncpyAtoW( pwszbuf, szBuf, dwBufLen );
610
611         return lstrlenW( pwszbuf );
612 }