Added some stubs.
[wine] / dlls / quartz / filesink.c
1 /*
2  * Implements CLSID_FileWriter.
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  *      FIXME - not tested
21  */
22
23 #include "config.h"
24
25 #include <stdlib.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "winerror.h"
31 #include "mmsystem.h"
32 #include "strmif.h"
33 #include "control.h"
34 #include "vfwmsgs.h"
35 #include "uuids.h"
36 #include "evcode.h"
37
38 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
40
41 #include "quartz_private.h"
42 #include "filesink.h"
43 #include "seekpass.h"
44
45 static const WCHAR QUARTZ_FileWriter_Name[] =
46 { 'F','i','l','e',' ','W','r','i','t','e','r',0 };
47 static const WCHAR QUARTZ_FileWriterPin_Name[] =
48 { 'I','n',0 };
49
50
51 /* FIXME - add this flag to strmif.h */
52 #define AM_FILE_OVERWRITE       0x1
53
54 /***************************************************************************
55  *
56  *      CFileWriterImpl methods
57  *
58  */
59
60 static HRESULT CFileWriterImpl_OnActive( CBaseFilterImpl* pImpl )
61 {
62         CFileWriterImpl_THIS(pImpl,basefilter);
63
64         FIXME( "(%p)\n", This );
65
66         return NOERROR;
67 }
68
69 static HRESULT CFileWriterImpl_OnInactive( CBaseFilterImpl* pImpl )
70 {
71         CFileWriterImpl_THIS(pImpl,basefilter);
72
73         FIXME( "(%p)\n", This );
74
75         return NOERROR;
76 }
77
78 static const CBaseFilterHandlers filterhandlers =
79 {
80         CFileWriterImpl_OnActive, /* pOnActive */
81         CFileWriterImpl_OnInactive, /* pOnInactive */
82         NULL, /* pOnStop */
83 };
84
85
86 /***************************************************************************
87  *
88  *      CFileWriterPinImpl methods
89  *
90  */
91
92 static HRESULT CFileWriterPinImpl_OnPreConnect( CPinBaseImpl* pImpl, IPin* pPin )
93 {
94         CFileWriterPinImpl_THIS(pImpl,pin);
95
96         TRACE("(%p,%p)\n",This,pPin);
97
98         return NOERROR;
99 }
100
101 static HRESULT CFileWriterPinImpl_OnPostConnect( CPinBaseImpl* pImpl, IPin* pPin )
102 {
103         CFileWriterPinImpl_THIS(pImpl,pin);
104
105         TRACE("(%p,%p)\n",This,pPin);
106
107         return NOERROR;
108 }
109
110 static HRESULT CFileWriterPinImpl_OnDisconnect( CPinBaseImpl* pImpl )
111 {
112         CFileWriterPinImpl_THIS(pImpl,pin);
113
114         TRACE("(%p)\n",This);
115
116         if ( This->meminput.pAllocator != NULL )
117         {
118                 IMemAllocator_Decommit(This->meminput.pAllocator);
119                 IMemAllocator_Release(This->meminput.pAllocator);
120                 This->meminput.pAllocator = NULL;
121         }
122
123         return NOERROR;
124 }
125
126 static HRESULT CFileWriterPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
127 {
128         CFileWriterPinImpl_THIS(pImpl,pin);
129
130         TRACE("(%p,%p)\n",This,pmt);
131
132         if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Stream ) )
133                 return E_FAIL;
134
135         return NOERROR;
136 }
137
138 static HRESULT CFileWriterPinImpl_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample )
139 {
140         CFileWriterPinImpl_THIS(pImpl,pin);
141         BYTE*   pData = NULL;
142         LONG    lLength;
143         ULONG   cbWritten;
144         HRESULT hr;
145
146         TRACE( "(%p,%p)\n",This,pSample );
147
148         if ( This->pRender->m_fInFlush )
149                 return S_FALSE;
150         if ( pSample == NULL )
151                 return E_POINTER;
152
153         hr = IMediaSample_GetPointer(pSample,&pData);
154         if ( FAILED(hr) )
155                 return hr;
156         lLength = (LONG)IMediaSample_GetActualDataLength(pSample);
157         if ( lLength == 0 )
158                 return S_OK;
159
160         if ( lLength < 0 )
161         {
162                 ERR( "invalid length: %ld\n", lLength );
163                 return S_OK;
164         }
165
166         hr = IStream_Write((IStream*)(&This->stream),pData,lLength,&cbWritten);
167
168         return hr;
169 }
170
171 static HRESULT CFileWriterPinImpl_ReceiveCanBlock( CPinBaseImpl* pImpl )
172 {
173         CFileWriterPinImpl_THIS(pImpl,pin);
174
175         TRACE( "(%p)\n", This );
176
177         return S_FALSE;
178 }
179
180 static HRESULT CFileWriterPinImpl_EndOfStream( CPinBaseImpl* pImpl )
181 {
182         CFileWriterPinImpl_THIS(pImpl,pin);
183
184         FIXME( "(%p)\n", This );
185
186         This->pRender->m_fInFlush = FALSE;
187
188         /* FIXME - don't notify twice until stopped or seeked. */
189         return CBaseFilterImpl_MediaEventNotify(
190                 &This->pRender->basefilter, EC_COMPLETE,
191                 (LONG_PTR)S_OK, (LONG_PTR)(IBaseFilter*)(This->pRender) );
192 }
193
194 static HRESULT CFileWriterPinImpl_BeginFlush( CPinBaseImpl* pImpl )
195 {
196         CFileWriterPinImpl_THIS(pImpl,pin);
197
198         FIXME( "(%p)\n", This );
199
200         This->pRender->m_fInFlush = TRUE;
201
202         return NOERROR;
203 }
204
205 static HRESULT CFileWriterPinImpl_EndFlush( CPinBaseImpl* pImpl )
206 {
207         CFileWriterPinImpl_THIS(pImpl,pin);
208
209         FIXME( "(%p)\n", This );
210
211         This->pRender->m_fInFlush = FALSE;
212
213         return NOERROR;
214 }
215
216 static HRESULT CFileWriterPinImpl_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate )
217 {
218         CFileWriterPinImpl_THIS(pImpl,pin);
219
220         FIXME( "(%p)\n", This );
221
222         This->pRender->m_fInFlush = FALSE;
223
224         return NOERROR;
225 }
226
227
228
229
230 static const CBasePinHandlers pinhandlers =
231 {
232         CFileWriterPinImpl_OnPreConnect, /* pOnPreConnect */
233         CFileWriterPinImpl_OnPostConnect, /* pOnPostConnect */
234         CFileWriterPinImpl_OnDisconnect, /* pOnDisconnect */
235         CFileWriterPinImpl_CheckMediaType, /* pCheckMediaType */
236         NULL, /* pQualityNotify */
237         CFileWriterPinImpl_Receive, /* pReceive */
238         CFileWriterPinImpl_ReceiveCanBlock, /* pReceiveCanBlock */
239         CFileWriterPinImpl_EndOfStream, /* pEndOfStream */
240         CFileWriterPinImpl_BeginFlush, /* pBeginFlush */
241         CFileWriterPinImpl_EndFlush, /* pEndFlush */
242         CFileWriterPinImpl_NewSegment, /* pNewSegment */
243 };
244
245
246 /***************************************************************************
247  *
248  *      new/delete CFileWriterImpl
249  *
250  */
251
252 /* can I use offsetof safely? - FIXME? */
253 static QUARTZ_IFEntry FilterIFEntries[] =
254 {
255   { &IID_IPersist, offsetof(CFileWriterImpl,basefilter)-offsetof(CFileWriterImpl,unk) },
256   { &IID_IMediaFilter, offsetof(CFileWriterImpl,basefilter)-offsetof(CFileWriterImpl,unk) },
257   { &IID_IBaseFilter, offsetof(CFileWriterImpl,basefilter)-offsetof(CFileWriterImpl,unk) },
258   { &IID_IFileSinkFilter, offsetof(CFileWriterImpl,filesink)-offsetof(CFileWriterImpl,unk) },
259   { &IID_IFileSinkFilter2, offsetof(CFileWriterImpl,filesink)-offsetof(CFileWriterImpl,unk) },
260 };
261
262 static HRESULT CFileWriterImpl_OnQueryInterface(
263         IUnknown* punk, const IID* piid, void** ppobj )
264 {
265         CFileWriterImpl_THIS(punk,unk);
266
267         if ( This->pSeekPass == NULL )
268                 return E_NOINTERFACE;
269
270         if ( IsEqualGUID( &IID_IMediaPosition, piid ) ||
271                  IsEqualGUID( &IID_IMediaSeeking, piid ) )
272         {
273                 TRACE( "IMediaSeeking(or IMediaPosition) is queried\n" );
274                 return IUnknown_QueryInterface( (IUnknown*)(&This->pSeekPass->unk), piid, ppobj );
275         }
276
277         return E_NOINTERFACE;
278 }
279
280 static void QUARTZ_DestroyFileWriter(IUnknown* punk)
281 {
282         CFileWriterImpl_THIS(punk,unk);
283
284         TRACE( "(%p)\n", This );
285         CFileWriterImpl_OnInactive(&This->basefilter);
286
287         if ( This->pPin != NULL )
288         {
289                 IUnknown_Release(This->pPin->unk.punkControl);
290                 This->pPin = NULL;
291         }
292         if ( This->pSeekPass != NULL )
293         {
294                 IUnknown_Release((IUnknown*)&This->pSeekPass->unk);
295                 This->pSeekPass = NULL;
296         }
297
298         if ( This->m_hFile != INVALID_HANDLE_VALUE )
299         {
300                 CloseHandle( This->m_hFile );
301                 This->m_hFile = INVALID_HANDLE_VALUE;
302         }
303         if ( This->m_pszFileName != NULL )
304         {
305                 QUARTZ_FreeMem( This->m_pszFileName );
306                 This->m_pszFileName = NULL;
307         }
308         QUARTZ_MediaType_Free( &This->m_mt );
309
310         CFileWriterImpl_UninitIFileSinkFilter2(This);
311         CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
312
313         DeleteCriticalSection( &This->m_csReceive );
314 }
315
316 HRESULT QUARTZ_CreateFileWriter(IUnknown* punkOuter,void** ppobj)
317 {
318         CFileWriterImpl*        This = NULL;
319         HRESULT hr;
320
321         TRACE("(%p,%p)\n",punkOuter,ppobj);
322
323         This = (CFileWriterImpl*)
324                 QUARTZ_AllocObj( sizeof(CFileWriterImpl) );
325         if ( This == NULL )
326                 return E_OUTOFMEMORY;
327         This->pSeekPass = NULL;
328         This->pPin = NULL;
329         This->m_fInFlush = FALSE;
330
331         This->m_hFile = INVALID_HANDLE_VALUE;
332         This->m_pszFileName = NULL;
333         This->m_cbFileName = 0;
334         This->m_dwMode = 0;
335         ZeroMemory( &This->m_mt, sizeof(AM_MEDIA_TYPE) );
336
337         QUARTZ_IUnkInit( &This->unk, punkOuter );
338         This->qiext.pNext = NULL;
339         This->qiext.pOnQueryInterface = &CFileWriterImpl_OnQueryInterface;
340         QUARTZ_IUnkAddDelegation( &This->unk, &This->qiext );
341
342         hr = CBaseFilterImpl_InitIBaseFilter(
343                 &This->basefilter,
344                 This->unk.punkControl,
345                 &CLSID_FileWriter,
346                 QUARTZ_FileWriter_Name,
347                 &filterhandlers );
348         if ( SUCCEEDED(hr) )
349         {
350                 hr = CFileWriterImpl_InitIFileSinkFilter2(This);
351                 if ( FAILED(hr) )
352                 {
353                         CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
354                 }
355         }
356
357         if ( FAILED(hr) )
358         {
359                 QUARTZ_FreeObj(This);
360                 return hr;
361         }
362
363         This->unk.pEntries = FilterIFEntries;
364         This->unk.dwEntries = sizeof(FilterIFEntries)/sizeof(FilterIFEntries[0]);
365         This->unk.pOnFinalRelease = QUARTZ_DestroyFileWriter;
366
367         InitializeCriticalSection( &This->m_csReceive );
368
369         hr = QUARTZ_CreateFileWriterPin(
370                 This,
371                 &This->basefilter.csFilter,
372                 &This->m_csReceive,
373                 &This->pPin );
374         if ( SUCCEEDED(hr) )
375                 hr = QUARTZ_CompList_AddComp(
376                         This->basefilter.pInPins,
377                         (IUnknown*)&This->pPin->pin,
378                         NULL, 0 );
379         if ( SUCCEEDED(hr) )
380                 hr = QUARTZ_CreateSeekingPassThruInternal(
381                         (IUnknown*)&(This->unk), &This->pSeekPass,
382                         TRUE, (IPin*)&(This->pPin->pin) );
383
384         if ( FAILED(hr) )
385         {
386                 IUnknown_Release( This->unk.punkControl );
387                 return hr;
388         }
389
390         *ppobj = (void*)&(This->unk);
391
392         return S_OK;
393 }
394
395 /***************************************************************************
396  *
397  *      new/delete CFileWriterPinImpl
398  *
399  */
400
401 /* can I use offsetof safely? - FIXME? */
402 static QUARTZ_IFEntry PinIFEntries[] =
403 {
404   { &IID_IPin, offsetof(CFileWriterPinImpl,pin)-offsetof(CFileWriterPinImpl,unk) },
405   { &IID_IMemInputPin, offsetof(CFileWriterPinImpl,meminput)-offsetof(CFileWriterPinImpl,unk) },
406   { &IID_IStream, offsetof(CFileWriterPinImpl,stream)-offsetof(CFileWriterPinImpl,unk) },
407 };
408
409 static void QUARTZ_DestroyFileWriterPin(IUnknown* punk)
410 {
411         CFileWriterPinImpl_THIS(punk,unk);
412
413         TRACE( "(%p)\n", This );
414
415         CPinBaseImpl_UninitIPin( &This->pin );
416         CMemInputPinBaseImpl_UninitIMemInputPin( &This->meminput );
417         CFileWriterPinImpl_UninitIStream(This);
418 }
419
420 HRESULT QUARTZ_CreateFileWriterPin(
421         CFileWriterImpl* pFilter,
422         CRITICAL_SECTION* pcsPin,
423         CRITICAL_SECTION* pcsPinReceive,
424         CFileWriterPinImpl** ppPin)
425 {
426         CFileWriterPinImpl*     This = NULL;
427         HRESULT hr;
428
429         TRACE("(%p,%p,%p,%p)\n",pFilter,pcsPin,pcsPinReceive,ppPin);
430
431         This = (CFileWriterPinImpl*)
432                 QUARTZ_AllocObj( sizeof(CFileWriterPinImpl) );
433         if ( This == NULL )
434                 return E_OUTOFMEMORY;
435
436         QUARTZ_IUnkInit( &This->unk, NULL );
437         This->pRender = pFilter;
438
439         hr = CPinBaseImpl_InitIPin(
440                 &This->pin,
441                 This->unk.punkControl,
442                 pcsPin, pcsPinReceive,
443                 &pFilter->basefilter,
444                 QUARTZ_FileWriterPin_Name,
445                 FALSE,
446                 &pinhandlers );
447
448         if ( SUCCEEDED(hr) )
449         {
450                 hr = CMemInputPinBaseImpl_InitIMemInputPin(
451                         &This->meminput,
452                         This->unk.punkControl,
453                         &This->pin );
454                 if ( SUCCEEDED(hr) )
455                 {
456                         hr = CFileWriterPinImpl_InitIStream(This);
457                         if ( FAILED(hr) )
458                         {
459                                 CMemInputPinBaseImpl_UninitIMemInputPin(&This->meminput);
460                         }
461                 }
462
463                 if ( FAILED(hr) )
464                 {
465                         CPinBaseImpl_UninitIPin( &This->pin );
466                 }
467         }
468
469         if ( FAILED(hr) )
470         {
471                 QUARTZ_FreeObj(This);
472                 return hr;
473         }
474
475         This->unk.pEntries = PinIFEntries;
476         This->unk.dwEntries = sizeof(PinIFEntries)/sizeof(PinIFEntries[0]);
477         This->unk.pOnFinalRelease = QUARTZ_DestroyFileWriterPin;
478
479         *ppPin = This;
480
481         TRACE("returned successfully.\n");
482
483         return S_OK;
484 }
485
486 /***************************************************************************
487  *
488  *      CFileWriterPinImpl::IStream
489  *
490  */
491
492 static HRESULT WINAPI
493 IStream_fnQueryInterface(IStream* iface,REFIID riid,void** ppobj)
494 {
495         CFileWriterPinImpl_THIS(iface,stream);
496
497         TRACE("(%p)->()\n",This);
498
499         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
500 }
501
502 static ULONG WINAPI
503 IStream_fnAddRef(IStream* iface)
504 {
505         CFileWriterPinImpl_THIS(iface,stream);
506
507         TRACE("(%p)->()\n",This);
508
509         return IUnknown_AddRef(This->unk.punkControl);
510 }
511
512 static ULONG WINAPI
513 IStream_fnRelease(IStream* iface)
514 {
515         CFileWriterPinImpl_THIS(iface,stream);
516
517         TRACE("(%p)->()\n",This);
518
519         return IUnknown_Release(This->unk.punkControl);
520 }
521
522 static HRESULT WINAPI
523 IStream_fnRead(IStream* iface,void* pv,ULONG cb,ULONG* pcbRead)
524 {
525         CFileWriterPinImpl_THIS(iface,stream);
526
527         FIXME("(%p)->()\n",This);
528
529         return E_FAIL;
530 }
531
532 static HRESULT WINAPI
533 IStream_fnWrite(IStream* iface,const void* pv,ULONG cb,ULONG* pcbWritten)
534 {
535         CFileWriterPinImpl_THIS(iface,stream);
536         HRESULT hr;
537
538         FIXME("(%p)->(%p,%lu,%p)\n",This,pv,cb,pcbWritten);
539
540         EnterCriticalSection( &This->pRender->m_csReceive );
541         if ( This->pRender->m_hFile == INVALID_HANDLE_VALUE )
542         {
543                 hr = E_UNEXPECTED;
544                 goto err;
545         }
546
547         if ( ! WriteFile( This->pRender->m_hFile, pv, cb, pcbWritten, NULL ) )
548         {
549                 hr = E_FAIL;
550                 goto err;
551         }
552
553         hr = S_OK;
554 err:
555         LeaveCriticalSection( &This->pRender->m_csReceive );
556         return hr;
557 }
558
559 static HRESULT WINAPI
560 IStream_fnSeek(IStream* iface,LARGE_INTEGER dlibMove,DWORD dwOrigin,ULARGE_INTEGER* plibNewPosition)
561 {
562         CFileWriterPinImpl_THIS(iface,stream);
563         HRESULT hr;
564         DWORD   dwDistLow;
565         LONG    lDistHigh;
566
567         FIXME("(%p)->() stub!\n",This);
568
569         EnterCriticalSection( &This->pRender->m_csReceive );
570         if ( This->pRender->m_hFile == INVALID_HANDLE_VALUE )
571         {
572                 hr = E_UNEXPECTED;
573                 goto err;
574         }
575
576         dwDistLow = dlibMove.s.LowPart;
577         lDistHigh = dlibMove.s.HighPart;
578
579         SetLastError(0);
580         dwDistLow = SetFilePointer( This->pRender->m_hFile, (LONG)dwDistLow, &lDistHigh, dwOrigin );
581         if ( dwDistLow == 0xffffffff && GetLastError() != 0 )
582         {
583                 hr = E_FAIL;
584                 goto err;
585         }
586
587         if ( plibNewPosition != NULL )
588         {
589                 plibNewPosition->s.LowPart = dwDistLow;
590                 plibNewPosition->s.HighPart = lDistHigh;
591         }
592
593         hr = S_OK;
594 err:
595         LeaveCriticalSection( &This->pRender->m_csReceive );
596         return hr;
597 }
598
599 static HRESULT WINAPI
600 IStream_fnSetSize(IStream* iface,ULARGE_INTEGER libNewSize)
601 {
602         CFileWriterPinImpl_THIS(iface,stream);
603
604         FIXME("(%p)->() stub!\n",This);
605
606         if ( This->pRender->m_hFile == INVALID_HANDLE_VALUE )
607                 return E_UNEXPECTED;
608
609
610         return E_NOTIMPL;
611 }
612
613 static HRESULT WINAPI
614 IStream_fnCopyTo(IStream* iface,IStream* pstrm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten)
615 {
616         CFileWriterPinImpl_THIS(iface,stream);
617
618         FIXME("(%p)->()\n",This);
619
620         return E_FAIL;
621 }
622
623 static HRESULT WINAPI
624 IStream_fnCommit(IStream* iface,DWORD grfCommitFlags)
625 {
626         CFileWriterPinImpl_THIS(iface,stream);
627
628         FIXME("(%p)->() stub!\n",This);
629
630         return E_NOTIMPL;
631 }
632
633 static HRESULT WINAPI
634 IStream_fnRevert(IStream* iface)
635 {
636         CFileWriterPinImpl_THIS(iface,stream);
637
638         FIXME("(%p)->() stub!\n",This);
639
640         return E_NOTIMPL;
641 }
642
643 static HRESULT WINAPI
644 IStream_fnLockRegion(IStream* iface,ULARGE_INTEGER libOffset,ULARGE_INTEGER cb,DWORD dwLockType)
645 {
646         CFileWriterPinImpl_THIS(iface,stream);
647
648         FIXME("(%p)->() stub!\n",This);
649
650         return E_NOTIMPL;
651 }
652
653 static HRESULT WINAPI
654 IStream_fnUnlockRegion(IStream* iface,ULARGE_INTEGER libOffset,ULARGE_INTEGER cb,DWORD dwLockType)
655 {
656         CFileWriterPinImpl_THIS(iface,stream);
657
658         FIXME("(%p)->() stub!\n",This);
659
660         return E_NOTIMPL;
661 }
662
663 static HRESULT WINAPI
664 IStream_fnStat(IStream* iface,STATSTG* pstatstg,DWORD grfStatFlag)
665 {
666         CFileWriterPinImpl_THIS(iface,stream);
667
668         FIXME("(%p)->() stub!\n",This);
669
670         return E_NOTIMPL;
671 }
672
673 static HRESULT WINAPI
674 IStream_fnClone(IStream* iface,IStream** ppstrm)
675 {
676         CFileWriterPinImpl_THIS(iface,stream);
677
678         FIXME("(%p)->() stub!\n",This);
679
680         return E_NOTIMPL;
681 }
682
683 static ICOM_VTABLE(IStream) istream =
684 {
685         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
686         /* IUnknown fields */
687         IStream_fnQueryInterface,
688         IStream_fnAddRef,
689         IStream_fnRelease,
690         /* IStream fields */
691         IStream_fnRead,
692         IStream_fnWrite,
693         IStream_fnSeek,
694         IStream_fnSetSize,
695         IStream_fnCopyTo,
696         IStream_fnCommit,
697         IStream_fnRevert,
698         IStream_fnLockRegion,
699         IStream_fnUnlockRegion,
700         IStream_fnStat,
701         IStream_fnClone,
702 };
703
704 HRESULT CFileWriterPinImpl_InitIStream( CFileWriterPinImpl* This )
705 {
706         TRACE("(%p)\n",This);
707         ICOM_VTBL(&This->stream) = &istream;
708
709         return NOERROR;
710 }
711
712 HRESULT CFileWriterPinImpl_UninitIStream( CFileWriterPinImpl* This )
713 {
714         TRACE("(%p)\n",This);
715
716         return S_OK;
717 }
718
719
720 /***************************************************************************
721  *
722  *      CFileWriterImpl::IFileSinkFilter2
723  *
724  */
725
726 static HRESULT WINAPI
727 IFileSinkFilter2_fnQueryInterface(IFileSinkFilter2* iface,REFIID riid,void** ppobj)
728 {
729         CFileWriterImpl_THIS(iface,filesink);
730
731         TRACE("(%p)->()\n",This);
732
733         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
734 }
735
736 static ULONG WINAPI
737 IFileSinkFilter2_fnAddRef(IFileSinkFilter2* iface)
738 {
739         CFileWriterImpl_THIS(iface,filesink);
740
741         TRACE("(%p)->()\n",This);
742
743         return IUnknown_AddRef(This->unk.punkControl);
744 }
745
746 static ULONG WINAPI
747 IFileSinkFilter2_fnRelease(IFileSinkFilter2* iface)
748 {
749         CFileWriterImpl_THIS(iface,filesink);
750
751         TRACE("(%p)->()\n",This);
752
753         return IUnknown_Release(This->unk.punkControl);
754 }
755
756 static HRESULT WINAPI
757 IFileSinkFilter2_fnSetFileName(IFileSinkFilter2* iface,LPCOLESTR pszFileName,const AM_MEDIA_TYPE* pmt)
758 {
759         CFileWriterImpl_THIS(iface,filesink);
760         HRESULT hr;
761
762         TRACE("(%p)->(%s,%p)\n",This,debugstr_w(pszFileName),pmt);
763
764         if ( pszFileName == NULL )
765                 return E_POINTER;
766
767         if ( This->m_pszFileName != NULL )
768                 return E_UNEXPECTED;
769
770         This->m_cbFileName = sizeof(WCHAR)*(lstrlenW(pszFileName)+1);
771         This->m_pszFileName = (WCHAR*)QUARTZ_AllocMem( This->m_cbFileName );
772         if ( This->m_pszFileName == NULL )
773                 return E_OUTOFMEMORY;
774         memcpy( This->m_pszFileName, pszFileName, This->m_cbFileName );
775
776         if ( pmt != NULL )
777         {
778                 hr = QUARTZ_MediaType_Copy( &This->m_mt, pmt );
779                 if ( FAILED(hr) )
780                         goto err;
781         }
782         else
783         {
784                 ZeroMemory( &This->m_mt, sizeof(AM_MEDIA_TYPE) );
785                 memcpy( &This->m_mt.majortype, &MEDIATYPE_Stream, sizeof(GUID) );
786                 memcpy( &This->m_mt.subtype, &MEDIASUBTYPE_NULL, sizeof(GUID) );
787                 This->m_mt.lSampleSize = 1;
788                 memcpy( &This->m_mt.formattype, &FORMAT_None, sizeof(GUID) );
789         }
790
791         This->m_hFile = CreateFileW(
792                 This->m_pszFileName,
793                 GENERIC_WRITE,
794                 0,
795                 NULL,
796                 ( This->m_dwMode == AM_FILE_OVERWRITE ) ? CREATE_ALWAYS : OPEN_ALWAYS,
797                 FILE_ATTRIBUTE_NORMAL,
798                 (HANDLE)NULL );
799         if ( This->m_hFile == INVALID_HANDLE_VALUE )
800         {
801                 hr = E_FAIL;
802                 goto err;
803         }
804
805         This->pPin->pin.pmtAcceptTypes = &This->m_mt;
806         This->pPin->pin.cAcceptTypes = 1;
807
808         return NOERROR;
809 err:;
810         return hr;
811 }
812
813 static HRESULT WINAPI
814 IFileSinkFilter2_fnGetCurFile(IFileSinkFilter2* iface,LPOLESTR* ppszFileName,AM_MEDIA_TYPE* pmt)
815 {
816         CFileWriterImpl_THIS(iface,filesink);
817         HRESULT hr = E_NOTIMPL;
818
819         TRACE("(%p)->(%p,%p)\n",This,ppszFileName,pmt);
820
821         if ( ppszFileName == NULL || pmt == NULL )
822                 return E_POINTER;
823
824         if ( This->m_pszFileName == NULL )
825                 return E_FAIL;
826
827         hr = QUARTZ_MediaType_Copy( pmt, &This->m_mt );
828         if ( FAILED(hr) )
829                 return hr;
830
831         *ppszFileName = (WCHAR*)CoTaskMemAlloc( This->m_cbFileName );
832         if ( *ppszFileName == NULL )
833         {
834                 QUARTZ_MediaType_Free(pmt);
835                 ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
836                 return E_OUTOFMEMORY;
837         }
838
839         memcpy( *ppszFileName, This->m_pszFileName, This->m_cbFileName );
840
841         return NOERROR;
842 }
843
844 static HRESULT WINAPI
845 IFileSinkFilter2_fnSetMode(IFileSinkFilter2* iface,DWORD dwFlags)
846 {
847         CFileWriterImpl_THIS(iface,filesink);
848
849         TRACE("(%p)->(%08lx)\n",This,dwFlags);
850
851         if ( dwFlags != 0 && dwFlags != AM_FILE_OVERWRITE )
852                 return E_INVALIDARG;
853         This->m_dwMode = dwFlags;
854
855         return S_OK;
856 }
857
858 static HRESULT WINAPI
859 IFileSinkFilter2_fnGetMode(IFileSinkFilter2* iface,DWORD* pdwFlags)
860 {
861         CFileWriterImpl_THIS(iface,filesink);
862
863         TRACE("(%p)->(%p)\n",This,pdwFlags);
864
865         if ( pdwFlags == NULL )
866                 return E_POINTER;
867
868         *pdwFlags = This->m_dwMode;
869
870         return S_OK;
871 }
872
873 static ICOM_VTABLE(IFileSinkFilter2) ifilesink2 =
874 {
875         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
876         /* IUnknown fields */
877         IFileSinkFilter2_fnQueryInterface,
878         IFileSinkFilter2_fnAddRef,
879         IFileSinkFilter2_fnRelease,
880         /* IFileSinkFilter2 fields */
881         IFileSinkFilter2_fnSetFileName,
882         IFileSinkFilter2_fnGetCurFile,
883         IFileSinkFilter2_fnSetMode,
884         IFileSinkFilter2_fnGetMode,
885 };
886
887 HRESULT CFileWriterImpl_InitIFileSinkFilter2( CFileWriterImpl* This )
888 {
889         TRACE("(%p)\n",This);
890         ICOM_VTBL(&This->filesink) = &ifilesink2;
891
892         return NOERROR;
893 }
894
895 HRESULT CFileWriterImpl_UninitIFileSinkFilter2( CFileWriterImpl* This )
896 {
897         TRACE("(%p)\n",This);
898
899         return S_OK;
900 }
901
902