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