Implement ResetDC and PHYSICALOFFSET[X|Y] devcaps.
[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         { NULL, NULL },
114 };
115
116 /* per-process variables */
117 static CRITICAL_SECTION csHeap;
118 static DWORD dwClassObjRef;
119 static HANDLE hDLLHeap;
120
121 void* QUARTZ_AllocObj( DWORD dwSize )
122 {
123         void*   pv;
124
125         EnterCriticalSection( &csHeap );
126         dwClassObjRef ++;
127         pv = HeapAlloc( hDLLHeap, 0, dwSize );
128         if ( pv == NULL )
129                 dwClassObjRef --;
130         LeaveCriticalSection( &csHeap );
131
132         return pv;
133 }
134
135 void QUARTZ_FreeObj( void* pobj )
136 {
137         EnterCriticalSection( &csHeap );
138         HeapFree( hDLLHeap, 0, pobj );
139         dwClassObjRef --;
140         LeaveCriticalSection( &csHeap );
141 }
142
143 void* QUARTZ_AllocMem( DWORD dwSize )
144 {
145         return HeapAlloc( hDLLHeap, 0, dwSize );
146 }
147
148 void QUARTZ_FreeMem( void* pMem )
149 {
150         HeapFree( hDLLHeap, 0, pMem );
151 }
152
153 void* QUARTZ_ReallocMem( void* pMem, DWORD dwSize )
154 {
155         if ( pMem == NULL )
156                 return QUARTZ_AllocMem( dwSize );
157
158         return HeapReAlloc( hDLLHeap, 0, pMem, dwSize );
159 }
160
161 static
162 LPWSTR QUARTZ_strncpyAtoW( LPWSTR lpwstr, LPCSTR lpstr, INT wbuflen )
163 {
164         INT     len;
165
166         len = MultiByteToWideChar( CP_ACP, 0, lpstr, -1, lpwstr, wbuflen );
167         if ( len == 0 )
168                 *lpwstr = 0;
169         return lpwstr;
170 }
171
172
173 /************************************************************************/
174
175 static HRESULT WINAPI
176 IClassFactory_fnQueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
177 {
178         ICOM_THIS(IClassFactoryImpl,iface);
179
180         TRACE("(%p)->(%p,%p)\n",This,riid,ppobj);
181         if ( ( IsEqualGUID( &IID_IUnknown, riid ) ) ||
182              ( IsEqualGUID( &IID_IClassFactory, riid ) ) )
183         {
184                 *ppobj = iface;
185                 IClassFactory_AddRef(iface);
186                 return S_OK;
187         }
188
189         return E_NOINTERFACE;
190 }
191
192 static ULONG WINAPI IClassFactory_fnAddRef(LPCLASSFACTORY iface)
193 {
194         ICOM_THIS(IClassFactoryImpl,iface);
195
196         TRACE("(%p)->()\n",This);
197
198         return InterlockedExchangeAdd(&(This->ref),1) + 1;
199 }
200
201 static ULONG WINAPI IClassFactory_fnRelease(LPCLASSFACTORY iface)
202 {
203         ICOM_THIS(IClassFactoryImpl,iface);
204         LONG    ref;
205
206         TRACE("(%p)->()\n",This);
207         ref = InterlockedExchangeAdd(&(This->ref),-1) - 1;
208         if ( ref > 0 )
209                 return (ULONG)ref;
210
211         QUARTZ_FreeObj(This);
212         return 0;
213 }
214
215 static HRESULT WINAPI IClassFactory_fnCreateInstance(LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj)
216 {
217         ICOM_THIS(IClassFactoryImpl,iface);
218         HRESULT hr;
219         IUnknown*       punk;
220
221         TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
222
223         if ( ppobj == NULL )
224                 return E_POINTER;
225         if ( pOuter != NULL && !IsEqualGUID( riid, &IID_IUnknown ) )
226                 return CLASS_E_NOAGGREGATION;
227
228         *ppobj = NULL;
229
230         hr = (*This->pEntry->pCreateIUnk)(pOuter,(void**)&punk);
231         if ( hr != S_OK )
232                 return hr;
233
234         hr = IUnknown_QueryInterface(punk,riid,ppobj);
235         IUnknown_Release(punk);
236
237         return hr;
238 }
239
240 static HRESULT WINAPI IClassFactory_fnLockServer(LPCLASSFACTORY iface,BOOL dolock)
241 {
242         ICOM_THIS(IClassFactoryImpl,iface);
243         HRESULT hr;
244
245         TRACE("(%p)->(%d)\n",This,dolock);
246         if (dolock)
247                 hr = IClassFactory_AddRef(iface);
248         else
249                 hr = IClassFactory_Release(iface);
250
251         return hr;
252 }
253
254
255
256 static HRESULT IClassFactory_Alloc( const CLSID* pclsid, void** ppobj )
257 {
258         const QUARTZ_CLASSENTRY*        pEntry;
259         IClassFactoryImpl*      pImpl;
260
261         TRACE( "(%s,%p)\n", debugstr_guid(pclsid), ppobj );
262
263         pEntry = QUARTZ_ClassList;
264         while ( pEntry->pclsid != NULL )
265         {
266                 if ( IsEqualGUID( pclsid, pEntry->pclsid ) )
267                         goto found;
268                 pEntry ++;
269         }
270
271         return CLASS_E_CLASSNOTAVAILABLE;
272 found:
273         pImpl = (IClassFactoryImpl*)QUARTZ_AllocObj( sizeof(IClassFactoryImpl) );
274         if ( pImpl == NULL )
275                 return E_OUTOFMEMORY;
276
277         TRACE( "allocated successfully.\n" );
278
279         ICOM_VTBL(pImpl) = &iclassfact;
280         pImpl->ref = 1;
281         pImpl->pEntry = pEntry;
282
283         *ppobj = (void*)pImpl;
284         return S_OK;
285 }
286
287
288 /***********************************************************************
289  *              QUARTZ_InitProcess (internal)
290  */
291 static BOOL QUARTZ_InitProcess( void )
292 {
293         TRACE("()\n");
294
295         dwClassObjRef = 0;
296         hDLLHeap = (HANDLE)NULL;
297         InitializeCriticalSection( &csHeap );
298
299         hDLLHeap = HeapCreate( 0, 0x10000, 0 );
300         if ( hDLLHeap == (HANDLE)NULL )
301                 return FALSE;
302
303         return TRUE;
304 }
305
306 /***********************************************************************
307  *              QUARTZ_UninitProcess (internal)
308  */
309 static void QUARTZ_UninitProcess( void )
310 {
311         TRACE("()\n");
312
313         if ( dwClassObjRef != 0 )
314                 ERR( "you must release some objects allocated from quartz.\n" );
315         if ( hDLLHeap != (HANDLE)NULL )
316         {
317                 HeapDestroy( hDLLHeap );
318                 hDLLHeap = (HANDLE)NULL;
319         }
320         DeleteCriticalSection( &csHeap );
321 }
322
323 /***********************************************************************
324  *              QUARTZ_DllMain
325  */
326 BOOL WINAPI QUARTZ_DllMain(
327         HINSTANCE hInstDLL,
328         DWORD fdwReason,
329         LPVOID lpvReserved )
330 {
331         TRACE("(%08x,%08lx,%p)\n",hInstDLL,fdwReason,lpvReserved);
332
333         switch ( fdwReason )
334         {
335         case DLL_PROCESS_ATTACH:
336                 if ( !QUARTZ_InitProcess() )
337                         return FALSE;
338                 break;
339         case DLL_PROCESS_DETACH:
340                 QUARTZ_UninitProcess();
341                 break;
342         case DLL_THREAD_ATTACH:
343                 break;
344         case DLL_THREAD_DETACH:
345                 break;
346         }
347
348         return TRUE;
349 }
350
351
352 /***********************************************************************
353  *              DllCanUnloadNow (QUARTZ.@)
354  *
355  * RETURNS
356  *    Success: S_OK
357  *    Failure: S_FALSE
358  */
359 HRESULT WINAPI QUARTZ_DllCanUnloadNow(void)
360 {
361         HRESULT hr;
362
363         EnterCriticalSection( &csHeap );
364         hr = ( dwClassObjRef == 0 ) ? S_OK : S_FALSE;
365         LeaveCriticalSection( &csHeap );
366
367         return hr;
368 }
369
370 /***********************************************************************
371  *              DllGetClassObject (QUARTZ.@)
372  */
373 HRESULT WINAPI QUARTZ_DllGetClassObject(
374                 const CLSID* pclsid,const IID* piid,void** ppv)
375 {
376         *ppv = NULL;
377         if ( IsEqualCLSID( &IID_IUnknown, piid ) ||
378              IsEqualCLSID( &IID_IClassFactory, piid ) )
379         {
380                 return IClassFactory_Alloc( pclsid, ppv );
381         }
382
383         return CLASS_E_CLASSNOTAVAILABLE;
384 }
385
386 /***********************************************************************
387  *              DllRegisterServer (QUARTZ.@)
388  */
389
390 HRESULT WINAPI QUARTZ_DllRegisterServer( void )
391 {
392         FIXME( "(): stub\n" );
393         return E_FAIL;
394 }
395
396 /***********************************************************************
397  *              DllUnregisterServer (QUARTZ.@)
398  */
399
400 HRESULT WINAPI QUARTZ_DllUnregisterServer( void )
401 {
402         FIXME( "(): stub\n" );
403         return E_FAIL;
404 }
405
406 /**************************************************************************/
407 /**************************************************************************/
408
409 /* FIXME - all string should be defined in the resource of quartz. */
410
411 static LPCSTR hresult_to_string( HRESULT hr )
412 {
413         switch ( hr )
414         {
415         #define ENTRY(x)        case x: return (const char*)#x
416         /* some known codes */
417         ENTRY(S_OK);
418         ENTRY(S_FALSE);
419         ENTRY(E_FAIL);
420         ENTRY(E_POINTER);
421         ENTRY(E_NOTIMPL);
422         ENTRY(E_NOINTERFACE);
423         ENTRY(E_OUTOFMEMORY);
424         ENTRY(CLASS_E_CLASSNOTAVAILABLE);
425         ENTRY(CLASS_E_NOAGGREGATION);
426
427         /* vfwmsgs.h */
428         ENTRY(VFW_S_NO_MORE_ITEMS);
429         ENTRY(VFW_E_BAD_KEY);
430         ENTRY(VFW_E_INVALIDMEDIATYPE);
431         ENTRY(VFW_E_INVALIDSUBTYPE);
432         ENTRY(VFW_E_NEED_OWNER);
433         ENTRY(VFW_E_ENUM_OUT_OF_SYNC);
434         ENTRY(VFW_E_ALREADY_CONNECTED);
435         ENTRY(VFW_E_FILTER_ACTIVE);
436         ENTRY(VFW_E_NO_TYPES);
437         ENTRY(VFW_E_NO_ACCEPTABLE_TYPES);
438         ENTRY(VFW_E_INVALID_DIRECTION);
439         ENTRY(VFW_E_NOT_CONNECTED);
440         ENTRY(VFW_E_NO_ALLOCATOR);
441         ENTRY(VFW_E_RUNTIME_ERROR);
442         ENTRY(VFW_E_BUFFER_NOTSET);
443         ENTRY(VFW_E_BUFFER_OVERFLOW);
444         ENTRY(VFW_E_BADALIGN);
445         ENTRY(VFW_E_ALREADY_COMMITTED);
446         ENTRY(VFW_E_BUFFERS_OUTSTANDING);
447         ENTRY(VFW_E_NOT_COMMITTED);
448         ENTRY(VFW_E_SIZENOTSET);
449         ENTRY(VFW_E_NO_CLOCK);
450         ENTRY(VFW_E_NO_SINK);
451         ENTRY(VFW_E_NO_INTERFACE);
452         ENTRY(VFW_E_NOT_FOUND);
453         ENTRY(VFW_E_CANNOT_CONNECT);
454         ENTRY(VFW_E_CANNOT_RENDER);
455         ENTRY(VFW_E_CHANGING_FORMAT);
456         ENTRY(VFW_E_NO_COLOR_KEY_SET);
457         ENTRY(VFW_E_NOT_OVERLAY_CONNECTION);
458         ENTRY(VFW_E_NOT_SAMPLE_CONNECTION);
459         ENTRY(VFW_E_PALETTE_SET);
460         ENTRY(VFW_E_COLOR_KEY_SET);
461         ENTRY(VFW_E_NO_COLOR_KEY_FOUND);
462         ENTRY(VFW_E_NO_PALETTE_AVAILABLE);
463         ENTRY(VFW_E_NO_DISPLAY_PALETTE);
464         ENTRY(VFW_E_TOO_MANY_COLORS);
465         ENTRY(VFW_E_STATE_CHANGED);
466         ENTRY(VFW_E_NOT_STOPPED);
467         ENTRY(VFW_E_NOT_PAUSED);
468         ENTRY(VFW_E_NOT_RUNNING);
469         ENTRY(VFW_E_WRONG_STATE);
470         ENTRY(VFW_E_START_TIME_AFTER_END);
471         ENTRY(VFW_E_INVALID_RECT);
472         ENTRY(VFW_E_TYPE_NOT_ACCEPTED);
473         ENTRY(VFW_E_SAMPLE_REJECTED);
474         ENTRY(VFW_E_SAMPLE_REJECTED_EOS);
475         ENTRY(VFW_S_DUPLICATE_NAME);
476         ENTRY(VFW_E_DUPLICATE_NAME);
477         ENTRY(VFW_E_TIMEOUT);
478         ENTRY(VFW_E_INVALID_FILE_FORMAT);
479         ENTRY(VFW_E_ENUM_OUT_OF_RANGE);
480         ENTRY(VFW_E_CIRCULAR_GRAPH);
481         ENTRY(VFW_E_NOT_ALLOWED_TO_SAVE);
482         ENTRY(VFW_E_TIME_ALREADY_PASSED);
483         ENTRY(VFW_E_ALREADY_CANCELLED);
484         ENTRY(VFW_E_CORRUPT_GRAPH_FILE);
485         ENTRY(VFW_E_ADVISE_ALREADY_SET);
486         ENTRY(VFW_S_STATE_INTERMEDIATE);
487         ENTRY(VFW_E_NO_MODEX_AVAILABLE);
488         ENTRY(VFW_E_NO_ADVISE_SET);
489         ENTRY(VFW_E_NO_FULLSCREEN);
490         ENTRY(VFW_E_IN_FULLSCREEN_MODE);
491         ENTRY(VFW_E_UNKNOWN_FILE_TYPE);
492         ENTRY(VFW_E_CANNOT_LOAD_SOURCE_FILTER);
493         ENTRY(VFW_S_PARTIAL_RENDER);
494         ENTRY(VFW_E_FILE_TOO_SHORT);
495         ENTRY(VFW_E_INVALID_FILE_VERSION);
496         ENTRY(VFW_S_SOME_DATA_IGNORED);
497         ENTRY(VFW_S_CONNECTIONS_DEFERRED);
498         ENTRY(VFW_E_INVALID_CLSID);
499         ENTRY(VFW_E_INVALID_MEDIA_TYPE);
500         ENTRY(VFW_E_SAMPLE_TIME_NOT_SET);
501         ENTRY(VFW_S_RESOURCE_NOT_NEEDED);
502         ENTRY(VFW_E_MEDIA_TIME_NOT_SET);
503         ENTRY(VFW_E_NO_TIME_FORMAT_SET);
504         ENTRY(VFW_E_MONO_AUDIO_HW);
505         ENTRY(VFW_S_MEDIA_TYPE_IGNORED);
506         ENTRY(VFW_E_NO_DECOMPRESSOR);
507         ENTRY(VFW_E_NO_AUDIO_HARDWARE);
508         ENTRY(VFW_S_VIDEO_NOT_RENDERED);
509         ENTRY(VFW_S_AUDIO_NOT_RENDERED);
510         ENTRY(VFW_E_RPZA);
511         ENTRY(VFW_S_RPZA);
512         ENTRY(VFW_E_PROCESSOR_NOT_SUITABLE);
513         ENTRY(VFW_E_UNSUPPORTED_AUDIO);
514         ENTRY(VFW_E_UNSUPPORTED_VIDEO);
515         ENTRY(VFW_E_MPEG_NOT_CONSTRAINED);
516         ENTRY(VFW_E_NOT_IN_GRAPH);
517         ENTRY(VFW_S_ESTIMATED);
518         ENTRY(VFW_E_NO_TIME_FORMAT);
519         ENTRY(VFW_E_READ_ONLY);
520         ENTRY(VFW_S_RESERVED);
521         ENTRY(VFW_E_BUFFER_UNDERFLOW);
522         ENTRY(VFW_E_UNSUPPORTED_STREAM);
523         ENTRY(VFW_E_NO_TRANSPORT);
524         ENTRY(VFW_S_STREAM_OFF);
525         ENTRY(VFW_S_CANT_CUE);
526         ENTRY(VFW_E_BAD_VIDEOCD);
527         ENTRY(VFW_S_NO_STOP_TIME);
528         ENTRY(VFW_E_OUT_OF_VIDEO_MEMORY);
529         ENTRY(VFW_E_VP_NEGOTIATION_FAILED);
530         ENTRY(VFW_E_DDRAW_CAPS_NOT_SUITABLE);
531         ENTRY(VFW_E_NO_VP_HARDWARE);
532         ENTRY(VFW_E_NO_CAPTURE_HARDWARE);
533         ENTRY(VFW_E_DVD_OPERATION_INHIBITED);
534         ENTRY(VFW_E_DVD_INVALIDDOMAIN);
535         ENTRY(VFW_E_DVD_NO_BUTTON);
536         ENTRY(VFW_E_DVD_GRAPHNOTREADY);
537         ENTRY(VFW_E_DVD_RENDERFAIL);
538         ENTRY(VFW_E_DVD_DECNOTENOUGH);
539         ENTRY(VFW_E_DDRAW_VERSION_NOT_SUITABLE);
540         ENTRY(VFW_E_COPYPROT_FAILED);
541         ENTRY(VFW_S_NOPREVIEWPIN);
542         ENTRY(VFW_E_TIME_EXPIRED);
543         ENTRY(VFW_S_DVD_NON_ONE_SEQUENTIAL);
544         ENTRY(VFW_E_DVD_WRONG_SPEED);
545         ENTRY(VFW_E_DVD_MENU_DOES_NOT_EXIST);
546         ENTRY(VFW_E_DVD_CMD_CANCELLED);
547         ENTRY(VFW_E_DVD_STATE_WRONG_VERSION);
548         ENTRY(VFW_E_DVD_STATE_CORRUPT);
549         ENTRY(VFW_E_DVD_STATE_WRONG_DISC);
550         ENTRY(VFW_E_DVD_INCOMPATIBLE_REGION);
551         ENTRY(VFW_E_DVD_NO_ATTRIBUTES);
552         ENTRY(VFW_E_DVD_NO_GOUP_PGC);
553         ENTRY(VFW_E_DVD_LOW_PARENTAL_LEVEL);
554         ENTRY(VFW_E_DVD_NOT_IN_KARAOKE_MODE);
555         ENTRY(VFW_S_DVD_CHANNEL_CONTENTS_NOT_AVAILABLE);
556         ENTRY(VFW_S_DVD_NOT_ACCURATE);
557         ENTRY(VFW_E_FRAME_STEP_UNSUPPORTED);
558         ENTRY(VFW_E_DVD_STREAM_DISABLED);
559         ENTRY(VFW_E_DVD_TITLE_UNKNOWN);
560         ENTRY(VFW_E_DVD_INVALID_DISC);
561         ENTRY(VFW_E_DVD_NO_RESUME_INFORMATION);
562         ENTRY(VFW_E_PIN_ALREADY_BLOCKED_ON_THIS_THREAD);
563         ENTRY(VFW_E_PIN_ALREADY_BLOCKED);
564         ENTRY(VFW_E_CERTIFICATION_FAILURE);
565         #undef  ENTRY
566         }
567
568         return NULL;
569 }
570
571 /***********************************************************************
572  *      AMGetErrorTextA (quartz.@)
573  */
574 DWORD WINAPI AMGetErrorTextA(HRESULT hr, LPSTR pszbuf, DWORD dwBufLen)
575 {
576         LPCSTR  lpszRes;
577         DWORD len;
578
579         lpszRes = hresult_to_string( hr );
580         if ( lpszRes == NULL )
581                 return 0;
582         len = (DWORD)(strlen(lpszRes)+1);
583         if ( len > dwBufLen )
584                 return 0;
585
586         memcpy( pszbuf, lpszRes, len );
587         return len;
588 }
589
590 /***********************************************************************
591  *      AMGetErrorTextW (quartz.@)
592  */
593 DWORD WINAPI AMGetErrorTextW(HRESULT hr, LPWSTR pwszbuf, DWORD dwBufLen)
594 {
595         CHAR    szBuf[MAX_ERROR_TEXT_LEN+1];
596         DWORD   dwLen;
597
598         dwLen = AMGetErrorTextA(hr,szBuf,MAX_ERROR_TEXT_LEN);
599         if ( dwLen == 0 )
600                 return 0;
601         szBuf[dwLen] = 0;
602
603         QUARTZ_strncpyAtoW( pwszbuf, szBuf, dwBufLen );
604
605         return lstrlenW( pwszbuf );
606 }