Added a framework for testing CreateProcess and a few tests.
[wine] / dlls / quartz / asyncsrc.c
1 /*
2  * Implements Asynchronous File/URL Source.
3  *
4  * FIXME - URL source is not implemented yet.
5  *
6  * Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winerror.h"
30 #include "strmif.h"
31 #include "vfwmsgs.h"
32 #include "uuids.h"
33
34 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
36
37 #include "quartz_private.h"
38 #include "asyncsrc.h"
39 #include "memalloc.h"
40
41
42
43 const WCHAR QUARTZ_wszAsyncFileSourceName[] =
44 {'F','i','l','e',' ','S','o','u','r','c','e',' ','(','A','s','y','n','c','.',')',0};
45 const WCHAR QUARTZ_wszAsyncFileSourcePinName[] =
46 {'O','u','t',0};
47 const WCHAR QUARTZ_wszAsyncURLSourceName[] =
48 {'F','i','l','e',' ','S','o','u','r','c','e',' ','(','U','R','L',')',0};
49 const WCHAR QUARTZ_wszAsyncURLSourcePinName[] =
50 {'O','u','t',0};
51
52
53
54 /***************************************************************************
55  *
56  *      CAsyncReaderImpl internal methods
57  *
58  */
59
60 static
61 AsyncSourceRequest* CAsyncReaderImpl_AllocRequest( CAsyncReaderImpl* This )
62 {
63         AsyncSourceRequest* pReq;
64
65         EnterCriticalSection( &This->m_csFree );
66         pReq = This->m_pFreeFirst;
67         if ( pReq != NULL )
68                 This->m_pFreeFirst = pReq->pNext;
69         LeaveCriticalSection( &This->m_csFree );
70
71         if ( pReq == NULL )
72         {
73                 pReq = (AsyncSourceRequest*)QUARTZ_AllocMem(
74                         sizeof(AsyncSourceRequest) );
75                 if ( pReq == NULL )
76                         return NULL;
77         }
78
79         pReq->pNext = NULL;
80         pReq->llStart = 0;
81         pReq->lLength = 0;
82         pReq->lActual = 0;
83         pReq->pBuf = NULL;
84         pReq->pSample = NULL;
85         pReq->dwContext = 0;
86
87         return pReq;
88 }
89
90 static
91 void CAsyncReaderImpl_FreeRequest( CAsyncReaderImpl* This, AsyncSourceRequest* pReq, BOOL bReleaseMem )
92 {
93         if ( !bReleaseMem )
94         {
95                 EnterCriticalSection( &This->m_csFree );
96                 pReq->pNext = This->m_pFreeFirst;
97                 This->m_pFreeFirst = pReq;
98                 LeaveCriticalSection( &This->m_csFree );
99         }
100         else
101         {
102                 QUARTZ_FreeMem( pReq );
103         }
104 }
105
106 static
107 AsyncSourceRequest* CAsyncReaderImpl_GetRequest( CAsyncReaderImpl* This )
108 {
109         AsyncSourceRequest*     pReq;
110
111         EnterCriticalSection( &This->m_csRequest );
112         pReq = This->m_pRequestFirst;
113         if ( pReq != NULL )
114                 This->m_pRequestFirst = pReq->pNext;
115         LeaveCriticalSection( &This->m_csRequest );
116
117         return pReq;
118 }
119
120 static
121 AsyncSourceRequest* CAsyncReaderImpl_GetReply( CAsyncReaderImpl* This )
122 {
123         AsyncSourceRequest*     pReq;
124
125         EnterCriticalSection( &This->m_csReply );
126         pReq = This->m_pReplyFirst;
127         if ( pReq != NULL )
128                 This->m_pReplyFirst = pReq->pNext;
129         LeaveCriticalSection( &This->m_csReply );
130
131         return pReq;
132 }
133
134 static
135 void CAsyncReaderImpl_PostRequest( CAsyncReaderImpl* This, AsyncSourceRequest* pReq )
136 {
137         /* FIXME - add to tail */
138         EnterCriticalSection( &This->m_csRequest );
139         pReq->pNext = This->m_pRequestFirst;
140         This->m_pRequestFirst = pReq;
141         if ( This->m_hEventReqQueued != (HANDLE)NULL )
142                 SetEvent( This->m_hEventReqQueued );
143         LeaveCriticalSection( &This->m_csRequest );
144 }
145
146 static
147 void CAsyncReaderImpl_PostReply( CAsyncReaderImpl* This, AsyncSourceRequest* pReq )
148 {
149         /* FIXME - add to tail */
150         EnterCriticalSection( &This->m_csReply );
151         pReq->pNext = This->m_pReplyFirst;
152         This->m_pReplyFirst = pReq;
153         if ( This->m_hEventSampQueued != (HANDLE)NULL )
154                 SetEvent( This->m_hEventSampQueued );
155         LeaveCriticalSection( &This->m_csReply );
156 }
157
158 static
159 void CAsyncReaderImpl_ReleaseReqList( CAsyncReaderImpl* This, AsyncSourceRequest** ppReq, BOOL bReleaseMem )
160 {
161         AsyncSourceRequest* pReq;
162         AsyncSourceRequest* pReqNext;
163
164         TRACE("(%p,%p,%d)\n",This,*ppReq,bReleaseMem);
165         pReq = *ppReq; *ppReq = NULL;
166         while ( pReq != NULL )
167         {
168                 pReqNext = pReq->pNext;
169                 CAsyncReaderImpl_FreeRequest(This,pReq,bReleaseMem);
170                 pReq = pReqNext;
171         }
172 }
173
174 static DWORD WINAPI
175 CAsyncReaderImpl_ThreadEntry( LPVOID pv )
176 {
177         CAsyncReaderImpl*       This = (CAsyncReaderImpl*)pv;
178         HANDLE hWaitEvents[2];
179         HRESULT hr;
180         DWORD   dwRes;
181         AsyncSourceRequest*     pReq = NULL;
182
183         SetEvent( This->m_hEventInit );
184
185         hWaitEvents[0] = This->m_hEventReqQueued;
186         hWaitEvents[1] = This->m_hEventCancel;
187
188         TRACE("enter message loop.\n");
189
190         while ( 1 )
191         {
192                 ResetEvent( This->m_hEventReqQueued );
193                 pReq = CAsyncReaderImpl_GetRequest(This);
194                 if ( pReq == NULL )
195                 {
196                         dwRes = WaitForMultipleObjects(2,hWaitEvents,FALSE,INFINITE);
197                         if ( dwRes != WAIT_OBJECT_0 )
198                         {
199                                 if ( This->m_bAbortThread )
200                                         break;
201                         }
202                         continue;
203                 }
204
205                 /* process a queued request */
206                 EnterCriticalSection( &This->m_csReader );
207                 hr = This->pSource->m_pHandler->pRead( This->pSource, pReq->llStart, pReq->lLength, pReq->pBuf, &pReq->lActual, This->m_hEventCancel );
208                 LeaveCriticalSection( &This->m_csReader );
209
210                 if ( FAILED(hr) )
211                 {
212                         /* Notify(ABORT) */
213                         break;
214                 }
215                 if ( hr != S_OK )
216                 {
217                         if ( This->m_bAbortThread )
218                                 break;
219                         ResetEvent( This->m_hEventCancel );
220                 }
221
222                 CAsyncReaderImpl_PostReply( This, pReq );
223                 SetEvent( This->m_hEventSampQueued );
224                 pReq = NULL;
225         }
226
227         if ( pReq != NULL )
228                 CAsyncReaderImpl_PostRequest( This, pReq );
229
230         SetEvent( This->m_hEventSampQueued );
231         return 0;
232 }
233
234 static HRESULT
235 CAsyncReaderImpl_BeginThread( CAsyncReaderImpl* This )
236 {
237         DWORD dwRes;
238         DWORD dwThreadId;
239         HANDLE hEvents[2];
240
241         if ( This->m_hEventInit != (HANDLE)NULL ||
242                  This->m_hEventCancel != (HANDLE)NULL ||
243                  This->m_hEventReqQueued != (HANDLE)NULL ||
244                  This->m_hEventSampQueued != (HANDLE)NULL ||
245                  This->m_hThread != (HANDLE)NULL )
246                 return E_UNEXPECTED;
247         This->m_bAbortThread = FALSE;
248
249         This->m_hEventInit = CreateEventA(NULL,TRUE,FALSE,NULL);
250         if ( This->m_hEventInit == (HANDLE)NULL )
251                 return E_OUTOFMEMORY;
252         This->m_hEventCancel = CreateEventA(NULL,TRUE,FALSE,NULL);
253         if ( This->m_hEventCancel == (HANDLE)NULL )
254                 return E_OUTOFMEMORY;
255         This->m_hEventReqQueued = CreateEventA(NULL,TRUE,FALSE,NULL);
256         if ( This->m_hEventReqQueued == (HANDLE)NULL )
257                 return E_OUTOFMEMORY;
258         This->m_hEventSampQueued = CreateEventA(NULL,TRUE,FALSE,NULL);
259         if ( This->m_hEventSampQueued == (HANDLE)NULL )
260                 return E_OUTOFMEMORY;
261
262         /* create the processing thread. */
263         This->m_hThread = CreateThread(
264                 NULL, 0,
265                 CAsyncReaderImpl_ThreadEntry,
266                 (LPVOID)This,
267                 0, &dwThreadId );
268         if ( This->m_hThread == (HANDLE)NULL )
269                 return E_FAIL;
270
271         hEvents[0] = This->m_hEventInit;
272         hEvents[1] = This->m_hThread;
273
274         dwRes = WaitForMultipleObjects(2,hEvents,FALSE,INFINITE);
275         if ( dwRes != WAIT_OBJECT_0 )
276                 return E_FAIL;
277
278         return NOERROR;
279 }
280
281 static void
282 CAsyncReaderImpl_EndThread( CAsyncReaderImpl* This )
283 {
284         if ( This->m_hThread != (HANDLE)NULL )
285         {
286                 while ( 1 )
287                 {
288                         This->m_bAbortThread = TRUE;
289                         SetEvent( This->m_hEventCancel );
290                         if ( WaitForSingleObject( This->m_hThread, 100 ) == WAIT_OBJECT_0 )
291                                 break;
292                 }
293                 CloseHandle( This->m_hThread );
294                 This->m_hThread = (HANDLE)NULL;
295         }
296         if ( This->m_hEventInit != (HANDLE)NULL )
297         {
298                 CloseHandle( This->m_hEventInit );
299                 This->m_hEventInit = (HANDLE)NULL;
300         }
301         if ( This->m_hEventCancel != (HANDLE)NULL )
302         {
303                 CloseHandle( This->m_hEventCancel );
304                 This->m_hEventCancel = (HANDLE)NULL;
305         }
306         if ( This->m_hEventReqQueued != (HANDLE)NULL )
307         {
308                 CloseHandle( This->m_hEventReqQueued );
309                 This->m_hEventReqQueued = (HANDLE)NULL;
310         }
311         if ( This->m_hEventSampQueued != (HANDLE)NULL )
312         {
313                 CloseHandle( This->m_hEventSampQueued );
314                 This->m_hEventSampQueued = (HANDLE)NULL;
315         }
316 }
317
318 /***************************************************************************
319  *
320  *      CAsyncReaderImpl methods
321  *
322  */
323
324 static HRESULT WINAPI
325 CAsyncReaderImpl_fnQueryInterface(IAsyncReader* iface,REFIID riid,void** ppobj)
326 {
327         ICOM_THIS(CAsyncReaderImpl,iface);
328
329         TRACE("(%p)->()\n",This);
330
331         return IUnknown_QueryInterface(This->punkControl,riid,ppobj);
332 }
333
334 static ULONG WINAPI
335 CAsyncReaderImpl_fnAddRef(IAsyncReader* iface)
336 {
337         ICOM_THIS(CAsyncReaderImpl,iface);
338
339         TRACE("(%p)->()\n",This);
340
341         return IUnknown_AddRef(This->punkControl);
342 }
343
344 static ULONG WINAPI
345 CAsyncReaderImpl_fnRelease(IAsyncReader* iface)
346 {
347         ICOM_THIS(CAsyncReaderImpl,iface);
348
349         TRACE("(%p)->()\n",This);
350
351         return IUnknown_Release(This->punkControl);
352 }
353
354 static HRESULT WINAPI
355 CAsyncReaderImpl_fnRequestAllocator(IAsyncReader* iface,IMemAllocator* pAlloc,ALLOCATOR_PROPERTIES* pProp,IMemAllocator** ppAllocActual)
356 {
357         ICOM_THIS(CAsyncReaderImpl,iface);
358         HRESULT hr;
359         ALLOCATOR_PROPERTIES    propActual;
360         IUnknown* punk = NULL;
361
362         TRACE("(%p)->(%p,%p,%p)\n",This,pAlloc,pProp,ppAllocActual);
363
364         if ( pAlloc == NULL || pProp == NULL || ppAllocActual == NULL )
365                 return E_POINTER;
366
367         IMemAllocator_AddRef(pAlloc);
368         hr = IMemAllocator_SetProperties( pAlloc, pProp, &propActual );
369         if ( SUCCEEDED(hr) )
370         {
371                 *ppAllocActual = pAlloc;
372                 return S_OK;
373         }
374         IMemAllocator_Release(pAlloc);
375
376         hr = QUARTZ_CreateMemoryAllocator(NULL,(void**)&punk);
377         if ( FAILED(hr) )
378                 return hr;
379         hr = IUnknown_QueryInterface( punk, &IID_IMemAllocator, (void**)&pAlloc );
380         IUnknown_Release(punk);
381         if ( FAILED(hr) )
382                 return hr;
383
384         hr = IMemAllocator_SetProperties( pAlloc, pProp, &propActual );
385         if ( SUCCEEDED(hr) )
386         {
387                 *ppAllocActual = pAlloc;
388                 return S_OK;
389         }
390         IMemAllocator_Release(pAlloc);
391
392         return hr;
393 }
394
395 static HRESULT WINAPI
396 CAsyncReaderImpl_fnRequest(IAsyncReader* iface,IMediaSample* pSample,DWORD_PTR dwContext)
397 {
398         ICOM_THIS(CAsyncReaderImpl,iface);
399         HRESULT hr = NOERROR;
400         REFERENCE_TIME  rtStart;
401         REFERENCE_TIME  rtEnd;
402         AsyncSourceRequest*     pReq;
403         BYTE*   pData = NULL;
404
405         TRACE("(%p)->(%p,%u)\n",This,pSample,dwContext);
406
407         hr = IMediaSample_GetPointer(pSample,&pData);
408         if ( SUCCEEDED(hr) )
409                 hr = IMediaSample_GetTime(pSample,&rtStart,&rtEnd);
410         if ( FAILED(hr) )
411                 return hr;
412
413         pReq = CAsyncReaderImpl_AllocRequest(This);
414         if ( pReq == NULL )
415                 return E_OUTOFMEMORY;
416
417         pReq->llStart = rtStart / QUARTZ_TIMEUNITS;
418         pReq->lLength = (LONG)(rtEnd / QUARTZ_TIMEUNITS - rtStart / QUARTZ_TIMEUNITS);
419         pReq->lActual = 0;
420         pReq->pBuf = pData;
421         pReq->pSample = pSample;
422         pReq->dwContext = dwContext;
423         CAsyncReaderImpl_PostRequest( This, pReq );
424
425         return NOERROR;
426 }
427
428 static HRESULT WINAPI
429 CAsyncReaderImpl_fnWaitForNext(IAsyncReader* iface,DWORD dwTimeout,IMediaSample** ppSample,DWORD_PTR* pdwContext)
430 {
431         ICOM_THIS(CAsyncReaderImpl,iface);
432         HRESULT hr = NOERROR;
433         DWORD dwRes;
434         AsyncSourceRequest*     pReq;
435         REFERENCE_TIME  rtStart;
436         REFERENCE_TIME  rtEnd;
437
438         /*TRACE("(%p)->(%lu,%p,%p)\n",This,dwTimeout,ppSample,pdwContext);*/
439
440         EnterCriticalSection( &This->m_csRequest );
441         if ( This->m_bInFlushing )
442                 hr = VFW_E_TIMEOUT;
443         LeaveCriticalSection( &This->m_csRequest );
444
445         if ( hr == NOERROR )
446         {
447                 ResetEvent( This->m_hEventSampQueued );
448                 pReq = CAsyncReaderImpl_GetReply(This);
449                 if ( pReq == NULL )
450                 {
451                         dwRes = WaitForSingleObject( This->m_hEventSampQueued, dwTimeout );
452                         if ( dwRes == WAIT_OBJECT_0 )
453                                 pReq = CAsyncReaderImpl_GetReply(This);
454                 }
455                 if ( pReq != NULL )
456                 {
457                         hr = IMediaSample_SetActualDataLength(pReq->pSample,pReq->lActual);
458                         if ( hr == S_OK )
459                         {
460                                 rtStart = pReq->llStart * QUARTZ_TIMEUNITS;
461                                 rtEnd = (pReq->llStart + pReq->lActual) * QUARTZ_TIMEUNITS;
462                                 hr = IMediaSample_SetTime(pReq->pSample,&rtStart,&rtEnd);
463                         }
464                         *ppSample = pReq->pSample;
465                         *pdwContext = pReq->dwContext;
466                         if ( hr == S_OK && pReq->lActual != pReq->lLength )
467                                 hr = S_FALSE;
468                 }
469                 else
470                 {
471                         hr = VFW_E_TIMEOUT;
472                 }
473         }
474
475         return hr;
476 }
477
478 static HRESULT WINAPI
479 CAsyncReaderImpl_fnSyncReadAligned(IAsyncReader* iface,IMediaSample* pSample)
480 {
481         ICOM_THIS(CAsyncReaderImpl,iface);
482         HRESULT hr;
483         REFERENCE_TIME  rtStart;
484         REFERENCE_TIME  rtEnd;
485         BYTE*   pData = NULL;
486         LONGLONG        llStart;
487         LONG    lLength;
488         LONG    lActual;
489
490         TRACE("(%p)->(%p)\n",This,pSample);
491
492         hr = IMediaSample_GetPointer(pSample,&pData);
493         if ( SUCCEEDED(hr) )
494                 hr = IMediaSample_GetTime(pSample,&rtStart,&rtEnd);
495         if ( FAILED(hr) )
496                 return hr;
497
498         llStart = rtStart / QUARTZ_TIMEUNITS;
499         lLength = (LONG)(rtEnd / QUARTZ_TIMEUNITS - rtStart / QUARTZ_TIMEUNITS);
500         lActual = 0;
501         if ( lLength > IMediaSample_GetSize(pSample) )
502         {
503                 FIXME("invalid length\n");
504                 return E_FAIL;
505         }
506
507         EnterCriticalSection( &This->m_csReader );
508         hr = This->pSource->m_pHandler->pRead( This->pSource, llStart, lLength, pData, &lActual, (HANDLE)NULL );
509         LeaveCriticalSection( &This->m_csReader );
510
511         if ( hr == NOERROR )
512         {
513                 hr = IMediaSample_SetActualDataLength(pSample,lActual);
514                 if ( hr == S_OK )
515                 {
516                         rtStart = llStart * QUARTZ_TIMEUNITS;
517                         rtEnd = (llStart + lActual) * QUARTZ_TIMEUNITS;
518                         hr = IMediaSample_SetTime(pSample,&rtStart,&rtEnd);
519                 }
520                 if ( hr == S_OK && lActual != lLength )
521                         hr = S_FALSE;
522         }
523
524         return hr;
525 }
526
527 static HRESULT WINAPI
528 CAsyncReaderImpl_fnSyncRead(IAsyncReader* iface,LONGLONG llPosStart,LONG lLength,BYTE* pbBuf)
529 {
530         ICOM_THIS(CAsyncReaderImpl,iface);
531         HRESULT hr;
532         LONG lActual;
533
534         TRACE("(%p)->()\n",This);
535
536         EnterCriticalSection( &This->m_csReader );
537         hr = This->pSource->m_pHandler->pRead( This->pSource, llPosStart, lLength, pbBuf, &lActual, (HANDLE)NULL );
538         LeaveCriticalSection( &This->m_csReader );
539
540         if ( hr == S_OK && lLength != lActual )
541                 hr = S_FALSE;
542
543         return hr;
544 }
545
546 static HRESULT WINAPI
547 CAsyncReaderImpl_fnLength(IAsyncReader* iface,LONGLONG* pllTotal,LONGLONG* pllAvailable)
548 {
549         ICOM_THIS(CAsyncReaderImpl,iface);
550         HRESULT hr;
551
552         TRACE("(%p)->()\n",This);
553
554         hr = This->pSource->m_pHandler->pGetLength( This->pSource, pllTotal, pllAvailable );
555
556         return hr;
557 }
558
559 static HRESULT WINAPI
560 CAsyncReaderImpl_fnBeginFlush(IAsyncReader* iface)
561 {
562         ICOM_THIS(CAsyncReaderImpl,iface);
563
564         TRACE("(%p)->()\n",This);
565
566         EnterCriticalSection( &This->m_csRequest );
567         This->m_bInFlushing = TRUE;
568         SetEvent( This->m_hEventCancel );
569         CAsyncReaderImpl_ReleaseReqList(This,&This->m_pRequestFirst,FALSE);
570         LeaveCriticalSection( &This->m_csRequest );
571
572         return NOERROR;
573 }
574
575 static HRESULT WINAPI
576 CAsyncReaderImpl_fnEndFlush(IAsyncReader* iface)
577 {
578         ICOM_THIS(CAsyncReaderImpl,iface);
579
580         TRACE("(%p)->()\n",This);
581
582         EnterCriticalSection( &This->m_csRequest );
583         This->m_bInFlushing = FALSE;
584         ResetEvent( This->m_hEventCancel );
585         LeaveCriticalSection( &This->m_csRequest );
586
587         return NOERROR;
588 }
589
590
591 static ICOM_VTABLE(IAsyncReader) iasyncreader =
592 {
593         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
594         /* IUnknown fields */
595         CAsyncReaderImpl_fnQueryInterface,
596         CAsyncReaderImpl_fnAddRef,
597         CAsyncReaderImpl_fnRelease,
598
599         /* IAsyncReader fields */
600         CAsyncReaderImpl_fnRequestAllocator,
601         CAsyncReaderImpl_fnRequest,
602         CAsyncReaderImpl_fnWaitForNext,
603         CAsyncReaderImpl_fnSyncReadAligned,
604         CAsyncReaderImpl_fnSyncRead,
605         CAsyncReaderImpl_fnLength,
606         CAsyncReaderImpl_fnBeginFlush,
607         CAsyncReaderImpl_fnEndFlush,
608 };
609
610 HRESULT CAsyncReaderImpl_InitIAsyncReader(
611         CAsyncReaderImpl* This, IUnknown* punkControl,
612         CAsyncSourceImpl* pSource )
613 {
614         TRACE("(%p,%p)\n",This,punkControl);
615
616         if ( punkControl == NULL )
617         {
618                 ERR( "punkControl must not be NULL\n" );
619                 return E_INVALIDARG;
620         }
621
622         ICOM_VTBL(This) = &iasyncreader;
623         This->punkControl = punkControl;
624         This->pSource = pSource;
625         This->m_bInFlushing = FALSE;
626         This->m_bAbortThread = FALSE;
627         This->m_hEventInit = (HANDLE)NULL;
628         This->m_hEventCancel = (HANDLE)NULL;
629         This->m_hEventReqQueued = (HANDLE)NULL;
630         This->m_hEventSampQueued = (HANDLE)NULL;
631         This->m_hThread = (HANDLE)NULL;
632         This->m_pRequestFirst = NULL;
633         This->m_pReplyFirst = NULL;
634         This->m_pFreeFirst = NULL;
635
636         InitializeCriticalSection( &This->m_csReader );
637         InitializeCriticalSection( &This->m_csRequest );
638         InitializeCriticalSection( &This->m_csReply );
639         InitializeCriticalSection( &This->m_csFree );
640
641         return NOERROR;
642 }
643
644 void CAsyncReaderImpl_UninitIAsyncReader(
645         CAsyncReaderImpl* This )
646 {
647         TRACE("(%p) enter\n",This);
648
649         CAsyncReaderImpl_ReleaseReqList(This,&This->m_pRequestFirst,TRUE);
650         CAsyncReaderImpl_ReleaseReqList(This,&This->m_pReplyFirst,TRUE);
651         CAsyncReaderImpl_ReleaseReqList(This,&This->m_pFreeFirst,TRUE);
652
653         DeleteCriticalSection( &This->m_csReader );
654         DeleteCriticalSection( &This->m_csRequest );
655         DeleteCriticalSection( &This->m_csReply );
656         DeleteCriticalSection( &This->m_csFree );
657
658         TRACE("(%p) leave\n",This);
659 }
660
661 /***************************************************************************
662  *
663  *      CFileSourceFilterImpl
664  *
665  */
666
667 static HRESULT WINAPI
668 CFileSourceFilterImpl_fnQueryInterface(IFileSourceFilter* iface,REFIID riid,void** ppobj)
669 {
670         ICOM_THIS(CFileSourceFilterImpl,iface);
671
672         TRACE("(%p)->()\n",This);
673
674         return IUnknown_QueryInterface(This->punkControl,riid,ppobj);
675 }
676
677 static ULONG WINAPI
678 CFileSourceFilterImpl_fnAddRef(IFileSourceFilter* iface)
679 {
680         ICOM_THIS(CFileSourceFilterImpl,iface);
681
682         TRACE("(%p)->()\n",This);
683
684         return IUnknown_AddRef(This->punkControl);
685 }
686
687 static ULONG WINAPI
688 CFileSourceFilterImpl_fnRelease(IFileSourceFilter* iface)
689 {
690         ICOM_THIS(CFileSourceFilterImpl,iface);
691
692         TRACE("(%p)->()\n",This);
693
694         return IUnknown_Release(This->punkControl);
695 }
696
697 static HRESULT WINAPI
698 CFileSourceFilterImpl_fnLoad(IFileSourceFilter* iface,LPCOLESTR pFileName,const AM_MEDIA_TYPE* pmt)
699 {
700         ICOM_THIS(CFileSourceFilterImpl,iface);
701         HRESULT hr;
702
703         TRACE("(%p)->(%s,%p)\n",This,debugstr_w(pFileName),pmt);
704
705         if ( pFileName == NULL )
706                 return E_POINTER;
707
708         if ( This->m_pwszFileName != NULL )
709                 return E_UNEXPECTED;
710
711         This->m_cbFileName = sizeof(WCHAR)*(lstrlenW(pFileName)+1);
712         This->m_pwszFileName = (WCHAR*)QUARTZ_AllocMem( This->m_cbFileName );
713         if ( This->m_pwszFileName == NULL )
714                 return E_OUTOFMEMORY;
715         memcpy( This->m_pwszFileName, pFileName, This->m_cbFileName );
716
717         if ( pmt != NULL )
718         {
719                 hr = QUARTZ_MediaType_Copy( &This->m_mt, pmt );
720                 if ( FAILED(hr) )
721                         goto err;
722         }
723         else
724         {
725                 ZeroMemory( &This->m_mt, sizeof(AM_MEDIA_TYPE) );
726                 memcpy( &This->m_mt.majortype, &MEDIATYPE_Stream, sizeof(GUID) );
727                 memcpy( &This->m_mt.subtype, &MEDIASUBTYPE_NULL, sizeof(GUID) );
728                 This->m_mt.lSampleSize = 1;
729                 memcpy( &This->m_mt.formattype, &FORMAT_None, sizeof(GUID) );
730         }
731
732         hr = This->pSource->m_pHandler->pLoad( This->pSource, pFileName );
733         if ( FAILED(hr) )
734                 goto err;
735
736         This->pSource->pPin->pin.pmtAcceptTypes = &This->m_mt;
737         This->pSource->pPin->pin.cAcceptTypes = 1;
738
739         return NOERROR;
740 err:;
741         return hr;
742 }
743
744 static HRESULT WINAPI
745 CFileSourceFilterImpl_fnGetCurFile(IFileSourceFilter* iface,LPOLESTR* ppFileName,AM_MEDIA_TYPE* pmt)
746 {
747         ICOM_THIS(CFileSourceFilterImpl,iface);
748         HRESULT hr = E_NOTIMPL;
749
750         TRACE("(%p)->(%p,%p)\n",This,ppFileName,pmt);
751
752         if ( ppFileName == NULL || pmt == NULL )
753                 return E_POINTER;
754
755         if ( This->m_pwszFileName == NULL )
756                 return E_FAIL;
757
758         hr = QUARTZ_MediaType_Copy( pmt, &This->m_mt );
759         if ( FAILED(hr) )
760                 return hr;
761
762         *ppFileName = (WCHAR*)CoTaskMemAlloc( This->m_cbFileName );
763         if ( *ppFileName == NULL )
764         {
765                 QUARTZ_MediaType_Free(pmt);
766                 ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
767                 return E_OUTOFMEMORY;
768         }
769
770         memcpy( *ppFileName, This->m_pwszFileName, This->m_cbFileName );
771
772         return NOERROR;
773 }
774
775 static ICOM_VTABLE(IFileSourceFilter) ifilesource =
776 {
777         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
778         /* IUnknown fields */
779         CFileSourceFilterImpl_fnQueryInterface,
780         CFileSourceFilterImpl_fnAddRef,
781         CFileSourceFilterImpl_fnRelease,
782         /* IFileSourceFilter fields */
783         CFileSourceFilterImpl_fnLoad,
784         CFileSourceFilterImpl_fnGetCurFile,
785 };
786
787 HRESULT CFileSourceFilterImpl_InitIFileSourceFilter(
788         CFileSourceFilterImpl* This, IUnknown* punkControl,
789         CAsyncSourceImpl* pSource,
790         CRITICAL_SECTION* pcsFileSource )
791 {
792         TRACE("(%p,%p)\n",This,punkControl);
793
794         if ( punkControl == NULL )
795         {
796                 ERR( "punkControl must not be NULL\n" );
797                 return E_INVALIDARG;
798         }
799
800         ICOM_VTBL(This) = &ifilesource;
801         This->punkControl = punkControl;
802         This->pSource = pSource;
803         This->pcsFileSource = pcsFileSource;
804         This->m_pwszFileName = NULL;
805         This->m_cbFileName = 0;
806         ZeroMemory( &This->m_mt, sizeof(AM_MEDIA_TYPE) );
807
808         return NOERROR;
809 }
810
811 void CFileSourceFilterImpl_UninitIFileSourceFilter(
812         CFileSourceFilterImpl* This )
813 {
814         TRACE("(%p)\n",This);
815
816         This->pSource->m_pHandler->pCleanup( This->pSource );
817         if ( This->m_pwszFileName != NULL )
818                 QUARTZ_FreeMem( This->m_pwszFileName );
819         QUARTZ_MediaType_Free( &This->m_mt );
820 }
821
822 /***************************************************************************
823  *
824  *      CAsyncSourcePinImpl methods
825  *
826  */
827
828
829 static HRESULT CAsyncSourcePinImpl_OnPreConnect( CPinBaseImpl* pImpl, IPin* pPin )
830 {
831         CAsyncSourcePinImpl_THIS(pImpl,pin);
832
833         TRACE("(%p,%p)\n",This,pPin);
834
835         This->bAsyncReaderQueried = FALSE;
836
837         return NOERROR;
838 }
839
840 static HRESULT CAsyncSourcePinImpl_OnPostConnect( CPinBaseImpl* pImpl, IPin* pPin )
841 {
842         CAsyncSourcePinImpl_THIS(pImpl,pin);
843
844         TRACE("(%p,%p)\n",This,pPin);
845
846         if ( !This->bAsyncReaderQueried )
847                 return E_FAIL;
848
849         return NOERROR;
850 }
851
852 static HRESULT CAsyncSourcePinImpl_OnDisconnect( CPinBaseImpl* pImpl )
853 {
854         CAsyncSourcePinImpl_THIS(pImpl,pin);
855
856         TRACE("(%p)\n",This);
857
858         This->bAsyncReaderQueried = FALSE;
859
860         return NOERROR;
861 }
862
863 static HRESULT CAsyncSourcePinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
864 {
865         CAsyncSourcePinImpl_THIS(pImpl,pin);
866
867         TRACE("(%p,%p)\n",This,pmt);
868         if ( pmt == NULL )
869                 return E_POINTER;
870
871         if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Stream ) )
872                 return E_FAIL;
873
874         return NOERROR;
875 }
876
877 static const CBasePinHandlers outputpinhandlers =
878 {
879         CAsyncSourcePinImpl_OnPreConnect, /* pOnPreConnect */
880         CAsyncSourcePinImpl_OnPostConnect, /* pOnPostConnect */
881         CAsyncSourcePinImpl_OnDisconnect, /* pOnDisconnect */
882         CAsyncSourcePinImpl_CheckMediaType, /* pCheckMediaType */
883         NULL, /* pQualityNotify */
884         NULL, /* pReceive */
885         NULL, /* pReceiveCanBlock */
886         NULL, /* pEndOfStream */
887         NULL, /* pBeginFlush */
888         NULL, /* pEndFlush */
889         NULL, /* pNewSegment */
890 };
891
892 /***************************************************************************
893  *
894  *      CAsyncSourceImpl methods
895  *
896  */
897
898 static HRESULT CAsyncSourceImpl_OnActive( CBaseFilterImpl* pImpl )
899 {
900         CAsyncSourceImpl_THIS(pImpl,basefilter);
901         HRESULT hr;
902
903         TRACE( "(%p)\n", This );
904
905         hr = CAsyncReaderImpl_BeginThread(&This->pPin->async);
906         if ( FAILED(hr) )
907                 return hr;
908
909         return NOERROR;
910 }
911
912 static HRESULT CAsyncSourceImpl_OnInactive( CBaseFilterImpl* pImpl )
913 {
914         CAsyncSourceImpl_THIS(pImpl,basefilter);
915
916         TRACE( "(%p)\n", This );
917
918         CAsyncReaderImpl_EndThread(&This->pPin->async);
919
920         return NOERROR;
921 }
922
923 static const CBaseFilterHandlers filterhandlers =
924 {
925         CAsyncSourceImpl_OnActive, /* pOnActive */
926         CAsyncSourceImpl_OnInactive, /* pOnInactive */
927         NULL, /* pOnStop */
928 };
929
930 /***************************************************************************
931  *
932  *      new/delete CAsyncSourceImpl
933  *
934  */
935
936 /* can I use offsetof safely? - FIXME? */
937 static QUARTZ_IFEntry FilterIFEntries[] =
938 {
939   { &IID_IPersist, offsetof(CAsyncSourceImpl,basefilter)-offsetof(CAsyncSourceImpl,unk) },
940   { &IID_IMediaFilter, offsetof(CAsyncSourceImpl,basefilter)-offsetof(CAsyncSourceImpl,unk) },
941   { &IID_IBaseFilter, offsetof(CAsyncSourceImpl,basefilter)-offsetof(CAsyncSourceImpl,unk) },
942   { &IID_IFileSourceFilter, offsetof(CAsyncSourceImpl,filesrc)-offsetof(CAsyncSourceImpl,unk) },
943 };
944
945 static void QUARTZ_DestroyAsyncSource(IUnknown* punk)
946 {
947         CAsyncSourceImpl_THIS(punk,unk);
948
949         TRACE( "(%p)\n", This );
950
951         if ( This->pPin != NULL )
952         {
953                 IUnknown_Release(This->pPin->unk.punkControl);
954                 This->pPin = NULL;
955         }
956
957         This->m_pHandler->pCleanup( This );
958
959         CFileSourceFilterImpl_UninitIFileSourceFilter(&This->filesrc);
960         CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
961
962         DeleteCriticalSection( &This->csFilter );
963 }
964
965 HRESULT QUARTZ_CreateAsyncSource(
966         IUnknown* punkOuter,void** ppobj,
967         const CLSID* pclsidAsyncSource,
968         LPCWSTR pwszAsyncSourceName,
969         LPCWSTR pwszOutPinName,
970         const AsyncSourceHandlers* pHandler )
971 {
972         CAsyncSourceImpl*       This = NULL;
973         HRESULT hr;
974
975         TRACE("(%p,%p)\n",punkOuter,ppobj);
976
977         This = (CAsyncSourceImpl*)
978                 QUARTZ_AllocObj( sizeof(CAsyncSourceImpl) );
979         if ( This == NULL )
980                 return E_OUTOFMEMORY;
981
982         This->pPin = NULL;
983         This->m_pHandler = pHandler;
984         This->m_pUserData = NULL;
985
986         QUARTZ_IUnkInit( &This->unk, punkOuter );
987
988         hr = CBaseFilterImpl_InitIBaseFilter(
989                 &This->basefilter,
990                 This->unk.punkControl,
991                 pclsidAsyncSource,
992                 pwszAsyncSourceName,
993                 &filterhandlers );
994         if ( SUCCEEDED(hr) )
995         {
996                 /* construct this class. */
997                 hr = CFileSourceFilterImpl_InitIFileSourceFilter(
998                         &This->filesrc, This->unk.punkControl,
999                         This, &This->csFilter );
1000                 if ( FAILED(hr) )
1001                 {
1002                         CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
1003                 }
1004         }
1005
1006         if ( FAILED(hr) )
1007         {
1008                 QUARTZ_FreeObj(This);
1009                 return hr;
1010         }
1011
1012         This->unk.pEntries = FilterIFEntries;
1013         This->unk.dwEntries = sizeof(FilterIFEntries)/sizeof(FilterIFEntries[0]);
1014         This->unk.pOnFinalRelease = QUARTZ_DestroyAsyncSource;
1015         InitializeCriticalSection( &This->csFilter );
1016
1017         /* create the output pin. */
1018         hr = QUARTZ_CreateAsyncSourcePin(
1019                 This, &This->csFilter,
1020                 &This->pPin, pwszOutPinName );
1021         if ( SUCCEEDED(hr) )
1022                 hr = QUARTZ_CompList_AddComp(
1023                         This->basefilter.pOutPins,
1024                         (IUnknown*)&(This->pPin->pin),
1025                         NULL, 0 );
1026
1027         if ( FAILED(hr) )
1028         {
1029                 IUnknown_Release( This->unk.punkControl );
1030                 return hr;
1031         }
1032
1033         *ppobj = (void*)&(This->unk);
1034
1035         return S_OK;
1036 }
1037
1038 /***************************************************************************
1039  *
1040  *      new/delete CAsyncSourcePinImpl
1041  *
1042  */
1043
1044 /* can I use offsetof safely? - FIXME? */
1045 static QUARTZ_IFEntry OutPinIFEntries[] =
1046 {
1047   { &IID_IPin, offsetof(CAsyncSourcePinImpl,pin)-offsetof(CAsyncSourcePinImpl,unk) },
1048   /***{ &IID_IAsyncReader, offsetof(CAsyncSourcePinImpl,async)-offsetof(CAsyncSourcePinImpl,unk) },***/
1049 };
1050
1051 static HRESULT CAsyncSourceImpl_OnQueryInterface(
1052         IUnknown* punk, const IID* piid, void** ppobj )
1053 {
1054         CAsyncSourcePinImpl_THIS(punk,unk);
1055
1056         if ( IsEqualGUID( &IID_IAsyncReader, piid ) )
1057         {
1058                 TRACE("IAsyncReader has been queried.\n");
1059                 *ppobj = (void*)&This->async;
1060                 IUnknown_AddRef(punk);
1061                 This->bAsyncReaderQueried = TRUE;
1062                 return S_OK;
1063         }
1064
1065         return E_NOINTERFACE;
1066 }
1067
1068 static void QUARTZ_DestroyAsyncSourcePin(IUnknown* punk)
1069 {
1070         CAsyncSourcePinImpl_THIS(punk,unk);
1071
1072         TRACE( "(%p)\n", This );
1073
1074         CAsyncReaderImpl_UninitIAsyncReader( &This->async );
1075         CPinBaseImpl_UninitIPin( &This->pin );
1076 }
1077
1078 HRESULT QUARTZ_CreateAsyncSourcePin(
1079         CAsyncSourceImpl* pFilter,
1080         CRITICAL_SECTION* pcsPin,
1081         CAsyncSourcePinImpl** ppPin,
1082         LPCWSTR pwszPinName )
1083 {
1084         CAsyncSourcePinImpl*    This = NULL;
1085         HRESULT hr;
1086
1087         TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin);
1088
1089         This = (CAsyncSourcePinImpl*)
1090                 QUARTZ_AllocObj( sizeof(CAsyncSourcePinImpl) );
1091         if ( This == NULL )
1092                 return E_OUTOFMEMORY;
1093
1094         QUARTZ_IUnkInit( &This->unk, NULL );
1095         This->qiext.pNext = NULL;
1096         This->qiext.pOnQueryInterface = &CAsyncSourceImpl_OnQueryInterface;
1097         QUARTZ_IUnkAddDelegation( &This->unk, &This->qiext );
1098
1099         This->bAsyncReaderQueried = FALSE;
1100         This->pSource = pFilter;
1101
1102         hr = CPinBaseImpl_InitIPin(
1103                 &This->pin,
1104                 This->unk.punkControl,
1105                 pcsPin, NULL,
1106                 &pFilter->basefilter,
1107                 pwszPinName,
1108                 TRUE,
1109                 &outputpinhandlers );
1110
1111         if ( SUCCEEDED(hr) )
1112         {
1113                 hr = CAsyncReaderImpl_InitIAsyncReader(
1114                         &This->async,
1115                         This->unk.punkControl,
1116                         pFilter );
1117                 if ( FAILED(hr) )
1118                 {
1119                         CPinBaseImpl_UninitIPin( &This->pin );
1120                 }
1121         }
1122
1123         if ( FAILED(hr) )
1124         {
1125                 QUARTZ_FreeObj(This);
1126                 return hr;
1127         }
1128
1129         This->unk.pEntries = OutPinIFEntries;
1130         This->unk.dwEntries = sizeof(OutPinIFEntries)/sizeof(OutPinIFEntries[0]);
1131         This->unk.pOnFinalRelease = QUARTZ_DestroyAsyncSourcePin;
1132
1133         *ppPin = This;
1134
1135         TRACE("returned successfully.\n");
1136
1137         return S_OK;
1138 }
1139
1140
1141
1142 /***************************************************************************
1143  *
1144  *      Implements File Source.
1145  *
1146  */
1147
1148 typedef struct AsyncSourceFileImpl
1149 {
1150         HANDLE  hFile;
1151         LONGLONG        llTotal;
1152 } AsyncSourceFileImpl;
1153
1154
1155 static HRESULT AsyncSourceFileImpl_Load( CAsyncSourceImpl* pImpl, LPCWSTR lpwszSourceName )
1156 {
1157         AsyncSourceFileImpl*    This = (AsyncSourceFileImpl*)pImpl->m_pUserData;
1158         DWORD   dwLow;
1159         DWORD   dwHigh;
1160
1161         if ( This != NULL )
1162                 return E_UNEXPECTED;
1163         This = (AsyncSourceFileImpl*)QUARTZ_AllocMem( sizeof(AsyncSourceFileImpl) );
1164         pImpl->m_pUserData = (void*)This;
1165         if ( This == NULL )
1166                 return E_OUTOFMEMORY;
1167         This->hFile = INVALID_HANDLE_VALUE;
1168         This->llTotal = 0;
1169
1170         This->hFile = CreateFileW( lpwszSourceName,
1171                 GENERIC_READ, FILE_SHARE_READ,
1172                 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL );
1173         if ( This->hFile == INVALID_HANDLE_VALUE )
1174                 return E_FAIL;
1175
1176         SetLastError(NO_ERROR);
1177         dwLow = GetFileSize( This->hFile, &dwHigh );
1178         if ( dwLow == 0xffffffff && GetLastError() != NO_ERROR )
1179                 return E_FAIL;
1180
1181         This->llTotal = (LONGLONG)dwLow | ((LONGLONG)dwHigh << 32);
1182
1183         return NOERROR;
1184 }
1185
1186 static HRESULT AsyncSourceFileImpl_Cleanup( CAsyncSourceImpl* pImpl )
1187 {
1188         AsyncSourceFileImpl*    This = (AsyncSourceFileImpl*)pImpl->m_pUserData;
1189
1190         if ( This == NULL )
1191                 return NOERROR;
1192
1193         if ( This->hFile != INVALID_HANDLE_VALUE )
1194                 CloseHandle(This->hFile);
1195
1196         QUARTZ_FreeMem(This);
1197         pImpl->m_pUserData = NULL;
1198
1199         return NOERROR;
1200 }
1201
1202 static HRESULT AsyncSourceFileImpl_GetLength( CAsyncSourceImpl* pImpl, LONGLONG* pllTotal, LONGLONG* pllAvailable )
1203 {
1204         AsyncSourceFileImpl*    This = (AsyncSourceFileImpl*)pImpl->m_pUserData;
1205
1206         if ( This == NULL )
1207                 return E_UNEXPECTED;
1208
1209         *pllTotal = This->llTotal;
1210         *pllAvailable = This->llTotal;
1211
1212         return NOERROR;
1213 }
1214
1215 static HRESULT AsyncSourceFileImpl_Read( CAsyncSourceImpl* pImpl, LONGLONG llOfsStart, LONG lLength, BYTE* pBuf, LONG* plReturned, HANDLE hEventCancel )
1216 {
1217         AsyncSourceFileImpl*    This = (AsyncSourceFileImpl*)pImpl->m_pUserData;
1218         LONG    lReturned;
1219         LONG    lBlock;
1220         LONG    lOfsLow;
1221         LONG    lOfsHigh;
1222         DWORD   dw;
1223         HRESULT hr = S_OK;
1224
1225         if ( This == NULL || This->hFile == INVALID_HANDLE_VALUE )
1226                 return E_UNEXPECTED;
1227
1228         lReturned = 0;
1229
1230         lOfsLow = (LONG)(llOfsStart & 0xffffffff);
1231         lOfsHigh = (LONG)(llOfsStart >> 32);
1232         SetLastError(NO_ERROR);
1233         lOfsLow = SetFilePointer( This->hFile, lOfsLow, &lOfsHigh, FILE_BEGIN );
1234         if ( lOfsLow == (LONG)0xffffffff && GetLastError() != NO_ERROR )
1235                 return E_FAIL;
1236
1237         while ( lLength > 0 )
1238         {
1239                 if ( hEventCancel != (HANDLE)NULL &&
1240                          WaitForSingleObject( hEventCancel, 0 ) == WAIT_OBJECT_0 )
1241                 {
1242                         hr = S_FALSE;
1243                         break;
1244                 }
1245
1246                 lBlock = ( lLength > ASYNCSRC_FILE_BLOCKSIZE ) ?
1247                         ASYNCSRC_FILE_BLOCKSIZE : lLength;
1248
1249                 if ( !ReadFile(This->hFile,pBuf,(DWORD)lBlock,&dw,NULL) )
1250                 {
1251                         hr = E_FAIL;
1252                         break;
1253                 }
1254                 pBuf += dw;
1255                 lReturned += (LONG)dw;
1256                 lLength -= (LONG)dw;
1257                 if ( lBlock > (LONG)dw )
1258                         break;
1259         }
1260
1261         *plReturned = lReturned;
1262
1263         return hr;
1264 }
1265
1266 static const struct AsyncSourceHandlers asyncsrc_file =
1267 {
1268         AsyncSourceFileImpl_Load,
1269         AsyncSourceFileImpl_Cleanup,
1270         AsyncSourceFileImpl_GetLength,
1271         AsyncSourceFileImpl_Read,
1272 };
1273
1274 HRESULT QUARTZ_CreateAsyncReader(IUnknown* punkOuter,void** ppobj)
1275 {
1276         return QUARTZ_CreateAsyncSource(
1277                 punkOuter, ppobj,
1278                 &CLSID_AsyncReader,
1279                 QUARTZ_wszAsyncFileSourceName,
1280                 QUARTZ_wszAsyncFileSourcePinName,
1281                 &asyncsrc_file );
1282 }
1283
1284 /***************************************************************************
1285  *
1286  *      Implements URL Source.
1287  *
1288  */
1289
1290 typedef struct AsyncSourceURLImpl
1291 {
1292         DWORD dwDummy;
1293 } AsyncSourceURLImpl;
1294
1295
1296 static HRESULT AsyncSourceURLImpl_Load( CAsyncSourceImpl* pImpl, LPCWSTR lpwszSourceName )
1297 {
1298         AsyncSourceURLImpl*     This = (AsyncSourceURLImpl*)pImpl->m_pUserData;
1299
1300         FIXME("(%p,%p) stub!\n", pImpl, lpwszSourceName);
1301
1302         if ( This != NULL )
1303                 return E_UNEXPECTED;
1304         This = (AsyncSourceURLImpl*)QUARTZ_AllocMem( sizeof(AsyncSourceURLImpl) );
1305         pImpl->m_pUserData = (void*)This;
1306         if ( This == NULL )
1307                 return E_OUTOFMEMORY;
1308
1309         return E_NOTIMPL;
1310 }
1311
1312 static HRESULT AsyncSourceURLImpl_Cleanup( CAsyncSourceImpl* pImpl )
1313 {
1314         AsyncSourceURLImpl*     This = (AsyncSourceURLImpl*)pImpl->m_pUserData;
1315
1316         FIXME("(%p) stub!\n", This);
1317
1318         if ( This == NULL )
1319                 return NOERROR;
1320
1321         QUARTZ_FreeMem(This);
1322         pImpl->m_pUserData = NULL;
1323
1324         return NOERROR;
1325 }
1326
1327 static HRESULT AsyncSourceURLImpl_GetLength( CAsyncSourceImpl* pImpl, LONGLONG* pllTotal, LONGLONG* pllAvailable )
1328 {
1329         AsyncSourceURLImpl*     This = (AsyncSourceURLImpl*)pImpl->m_pUserData;
1330
1331         FIXME("(%p,%p,%p) stub!\n", This, pllTotal, pllAvailable);
1332
1333         if ( This == NULL )
1334                 return E_UNEXPECTED;
1335
1336         return E_NOTIMPL;
1337 }
1338
1339 static HRESULT AsyncSourceURLImpl_Read( CAsyncSourceImpl* pImpl, LONGLONG llOfsStart, LONG lLength, BYTE* pBuf, LONG* plReturned, HANDLE hEventCancel )
1340 {
1341         AsyncSourceURLImpl*     This = (AsyncSourceURLImpl*)pImpl->m_pUserData;
1342
1343         FIXME("(%p) stub!\n", This);
1344
1345         if ( This == NULL )
1346                 return E_UNEXPECTED;
1347
1348         return E_NOTIMPL;
1349 }
1350
1351 static const struct AsyncSourceHandlers asyncsrc_url =
1352 {
1353         AsyncSourceURLImpl_Load,
1354         AsyncSourceURLImpl_Cleanup,
1355         AsyncSourceURLImpl_GetLength,
1356         AsyncSourceURLImpl_Read,
1357 };
1358
1359
1360 HRESULT QUARTZ_CreateURLReader(IUnknown* punkOuter,void** ppobj)
1361 {
1362         return QUARTZ_CreateAsyncSource(
1363                 punkOuter, ppobj,
1364                 &CLSID_URLReader,
1365                 QUARTZ_wszAsyncURLSourceName,
1366                 QUARTZ_wszAsyncURLSourcePinName,
1367                 &asyncsrc_url );
1368 }