Various cosmetic changes.
[wine] / dlls / quartz / ifgraph.c
1 /*
2  * Implementation of IFilterGraph and related interfaces
3  *      + IGraphVersion, IGraphConfig
4  *
5  * FIXME - create a thread to process some methods correctly.
6  *
7  * FIXME - ReconnectEx
8  * FIXME - process Pause/Stop asynchronously and notify when completed.
9  *
10  *
11  * hidenori@a2.ctktv.ne.jp
12  */
13
14 #include "config.h"
15
16 #include "windef.h"
17 #include "winbase.h"
18 #include "wingdi.h"
19 #include "winuser.h"
20 #include "winerror.h"
21 #include "winreg.h"
22 #include "strmif.h"
23 #include "control.h"
24 #include "uuids.h"
25 #include "vfwmsgs.h"
26 #include "evcode.h"
27
28 #include "debugtools.h"
29 DEFAULT_DEBUG_CHANNEL(quartz);
30
31 #include "quartz_private.h"
32 #include "fgraph.h"
33 #include "enumunk.h"
34 #include "sysclock.h"
35 #include "regsvr.h"
36
37
38 #ifndef NUMELEMS
39 #define NUMELEMS(elem)  (sizeof(elem)/sizeof(elem[0]))
40 #endif  /* NUMELEMS */
41
42 static HRESULT CFilterGraph_DisconnectAllPins( IBaseFilter* pFilter )
43 {
44         IEnumPins*      pEnum = NULL;
45         IPin*   pPin;
46         IPin*   pConnTo;
47         ULONG   cFetched;
48         HRESULT hr;
49
50         hr = IBaseFilter_EnumPins( pFilter, &pEnum );
51         if ( FAILED(hr) )
52                 return hr;
53         if ( pEnum == NULL )
54                 return E_FAIL;
55
56         while ( 1 )
57         {
58                 pPin = NULL;
59                 cFetched = 0;
60                 hr = IEnumPins_Next( pEnum, 1, &pPin, &cFetched );
61                 if ( FAILED(hr) )
62                         break;
63                 if ( hr != NOERROR || pPin == NULL || cFetched != 1 )
64                 {
65                         hr = NOERROR;
66                         break;
67                 }
68
69                 pConnTo = NULL;
70                 hr = IPin_ConnectedTo(pPin,&pConnTo);
71                 if ( hr == NOERROR && pConnTo != NULL )
72                 {
73                         IPin_Disconnect(pPin);
74                         IPin_Disconnect(pConnTo);
75                         IPin_Release(pConnTo);
76                 }
77
78                 IPin_Release( pPin );
79         }
80
81         IEnumPins_Release( pEnum );
82
83         return hr;
84 }
85
86
87 static HRESULT CFilterGraph_GraphChanged( CFilterGraph* This )
88 {
89         /* IDistributorNotify_NotifyGraphChange() */
90
91         IMediaEventSink_Notify(CFilterGraph_IMediaEventSink(This),
92                         EC_GRAPH_CHANGED, 0, 0);
93         This->m_lGraphVersion ++;
94
95         return NOERROR;
96 }
97
98 /***************************************************************************
99  *
100  *      CFilterGraph internal methods for IFilterGraph2::AddSourceFilter().
101  *
102  */
103
104 static HRESULT QUARTZ_PeekFile(
105         const WCHAR* pwszFileName,
106         BYTE* pData, DWORD cbData, DWORD* pcbRead )
107 {
108         HANDLE  hFile;
109         HRESULT hr = E_FAIL;
110
111         *pcbRead = 0;
112         hFile = CreateFileW( pwszFileName,
113                 GENERIC_READ, FILE_SHARE_READ,
114                 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL );
115         if ( hFile == INVALID_HANDLE_VALUE )
116                 return E_FAIL;
117         if ( ReadFile( hFile, pData, cbData, pcbRead, NULL ) )
118                 hr = NOERROR;
119         CloseHandle( hFile );
120
121         return hr;
122 }
123
124
125 static const WCHAR* skip_space(const WCHAR* pwsz)
126 {
127         if ( pwsz == NULL ) return NULL;
128         while ( *pwsz == (WCHAR)' ' ) pwsz++;
129         return pwsz;
130 }
131
132 static const WCHAR* get_dword(const WCHAR* pwsz,DWORD* pdw)
133 {
134         DWORD   dw = 0;
135
136         *pdw = 0;
137         if ( pwsz == NULL ) return NULL;
138         while ( *pwsz >= (WCHAR)'0' && *pwsz <= (WCHAR)'9' )
139         {
140                 dw = dw * 10 + (DWORD)(*pwsz-(WCHAR)'0');
141                 pwsz ++;
142         }
143         *pdw = dw;
144         return pwsz;
145 }
146
147 static int wchar_to_hex(WCHAR wch)
148 {
149         if ( wch >= (WCHAR)'0' && wch <= (WCHAR)'9' )
150                 return (int)(wch - (WCHAR)'0');
151         if ( wch >= (WCHAR)'A' && wch <= (WCHAR)'F' )
152                 return (int)(wch - (WCHAR)'A' + 10);
153         if ( wch >= (WCHAR)'a' && wch <= (WCHAR)'f' )
154                 return (int)(wch - (WCHAR)'a' + 10);
155         return -1;
156 }
157
158 static const WCHAR* get_hex(const WCHAR* pwsz,BYTE* pb)
159 {
160         int     hi,lo;
161
162         *pb = 0;
163         if ( pwsz == NULL ) return NULL;
164         hi = wchar_to_hex(*pwsz); if ( hi < 0 ) return NULL; pwsz++;
165         lo = wchar_to_hex(*pwsz); if ( lo < 0 ) return NULL; pwsz++;
166         *pb = (BYTE)( (hi << 4) | lo );
167         return pwsz;
168 }
169
170 static const WCHAR* skip_hex(const WCHAR* pwsz)
171 {
172         if ( pwsz == NULL ) return NULL;
173         while ( 1 )
174         {
175                 if ( wchar_to_hex(*pwsz) < 0 )
176                         break;
177                 pwsz++;
178         }
179         return pwsz;
180 }
181
182 static const WCHAR* next_token(const WCHAR* pwsz)
183 {
184         if ( pwsz == NULL ) return NULL;
185         pwsz = skip_space(pwsz);
186         if ( *pwsz != (WCHAR)',' ) return NULL; pwsz++;
187         return skip_space(pwsz);
188 }
189
190
191 static HRESULT QUARTZ_SourceTypeIsMatch(
192         const BYTE* pData, DWORD cbData,
193         const WCHAR* pwszTempl, DWORD cchTempl )
194 {
195         DWORD   dwOfs;
196         DWORD   n;
197         DWORD   cbLen;
198         const WCHAR*    pwszMask;
199         const WCHAR*    pwszValue;
200         BYTE    bMask;
201         BYTE    bValue;
202
203         TRACE("(%p,%lu,%s,%lu)\n",pData,cbData,debugstr_w(pwszTempl),cchTempl);
204
205         pwszTempl = skip_space(pwszTempl);
206         while ( 1 )
207         {
208                 pwszTempl = get_dword(pwszTempl,&dwOfs);
209                 pwszTempl = next_token(pwszTempl);
210                 pwszTempl = get_dword(pwszTempl,&cbLen);
211                 pwszMask = pwszTempl = next_token(pwszTempl);
212                 pwszTempl = skip_hex(pwszTempl);
213                 pwszValue = pwszTempl = next_token(pwszTempl);
214                 pwszTempl = skip_hex(pwszValue);
215                 pwszTempl = skip_space(pwszTempl);
216                 if ( pwszValue == NULL )
217                 {
218                         WARN( "parse error\n" );
219                         return S_FALSE;
220                 }
221
222                 if ( dwOfs >= cbData || ( (dwOfs+cbLen) >= cbData ) )
223                 {
224                         WARN( "length of given data is too short\n" );
225                         return S_FALSE;
226                 }
227
228                 for ( n = 0; n < cbLen; n++ )
229                 {
230                         pwszMask = get_hex(pwszMask,&bMask);
231                         if ( pwszMask == NULL ) bMask = 0xff;
232                         pwszValue = get_hex(pwszValue,&bValue);
233                         if ( pwszValue == NULL )
234                         {
235                                 WARN( "parse error - invalid hex data\n" );
236                                 return S_FALSE;
237                         }
238                         if ( (pData[dwOfs+n]&bMask) != (bValue&bMask) )
239                         {
240                                 TRACE( "not matched\n" );
241                                 return S_FALSE;
242                         }
243                 }
244
245                 if ( *pwszTempl == 0 )
246                         break;
247                 pwszTempl = next_token(pwszTempl);
248                 if ( pwszTempl == NULL )
249                 {
250                         WARN( "parse error\n" );
251                         return S_FALSE;
252                 }
253         }
254
255         TRACE( "matched\n" );
256         return NOERROR;
257 }
258
259 static HRESULT QUARTZ_GetSourceTypeFromData(
260         const BYTE* pData, DWORD cbData,
261         GUID* pidMajor, GUID* pidSub, CLSID* pidSource )
262 {
263         HRESULT hr = S_FALSE;
264         LONG    lr;
265         WCHAR   wszMajor[128];
266         WCHAR   wszSub[128];
267         WCHAR   wszSource[128];
268         WCHAR   wszSourceFilter[128];
269         WCHAR*  pwszLocalBuf = NULL;
270         WCHAR*  pwszTemp;
271         DWORD   cbLocalBuf = 0;
272         DWORD   cbPath;
273         DWORD   dwIndexMajor;
274         HKEY    hkMajor;
275         DWORD   dwIndexSub;
276         HKEY    hkSub;
277         DWORD   dwIndexSource;
278         HKEY    hkSource;
279         DWORD   dwRegType;
280         DWORD   cbRegData;
281         FILETIME        ftLastWrite;
282         static const WCHAR wszFmt[] = {'%','l','u',0};
283
284         if ( RegOpenKeyExW( HKEY_CLASSES_ROOT, QUARTZ_wszMediaType, 0, KEY_READ, &hkMajor ) == ERROR_SUCCESS )
285         {
286                 dwIndexMajor = 0;
287                 while ( hr == S_FALSE )
288                 {
289                         cbPath = NUMELEMS(wszMajor)-1;
290                         lr = RegEnumKeyExW(
291                                 hkMajor, dwIndexMajor ++, wszMajor, &cbPath,
292                                 NULL, NULL, NULL, &ftLastWrite );
293                         if ( lr != ERROR_SUCCESS )
294                                 break;
295                         if ( RegOpenKeyExW( hkMajor, wszMajor, 0, KEY_READ, &hkSub ) == ERROR_SUCCESS )
296                         {
297                                 dwIndexSub = 0;
298                                 while ( hr == S_FALSE )
299                                 {
300                                         cbPath = NUMELEMS(wszSub)-1;
301                                         lr = RegEnumKeyExW(
302                                                 hkSub, dwIndexSub ++, wszSub, &cbPath,
303                                                 NULL, NULL, NULL, &ftLastWrite );
304                                         if ( lr != ERROR_SUCCESS )
305                                                 break;
306                                         if ( RegOpenKeyExW( hkSub, wszSub, 0, KEY_READ, &hkSource ) == ERROR_SUCCESS )
307                                         {
308                                                 dwIndexSource = 0;
309                                                 while ( hr == S_FALSE )
310                                                 {
311                                                         wsprintfW(wszSource,wszFmt,dwIndexSource++);
312                                                         lr = RegQueryValueExW(
313                                                                 hkSource, wszSource, NULL,
314                                                                 &dwRegType, NULL, &cbRegData );
315                                                         if ( lr != ERROR_SUCCESS )
316                                                                 break;
317                                                         if ( cbLocalBuf < cbRegData )
318                                                         {
319                                                                 pwszTemp = (WCHAR*)QUARTZ_ReallocMem( pwszLocalBuf, cbRegData+sizeof(WCHAR) );
320                                                                 if ( pwszTemp == NULL )
321                                                                 {
322                                                                         hr = E_OUTOFMEMORY;
323                                                                         break;
324                                                                 }
325                                                                 pwszLocalBuf = pwszTemp;
326                                                                 cbLocalBuf = cbRegData+sizeof(WCHAR);
327                                                         }
328                                                         cbRegData = cbLocalBuf;
329                                                         lr = RegQueryValueExW(
330                                                                 hkSource, wszSource, NULL,
331                                                                 &dwRegType, (BYTE*)pwszLocalBuf, &cbRegData );
332                                                         if ( lr != ERROR_SUCCESS )
333                                                                 break;
334
335                                                         hr = QUARTZ_SourceTypeIsMatch(
336                                                                 pData, cbData,
337                                                                 pwszLocalBuf, cbRegData / sizeof(WCHAR) );
338                                                         if ( hr == S_OK )
339                                                         {
340                                                                 hr = CLSIDFromString(wszMajor,pidMajor);
341                                                                 if ( hr == NOERROR )
342                                                                         hr = CLSIDFromString(wszSub,pidSub);
343                                                                 if ( hr == NOERROR )
344                                                                 {
345                                                                         lstrcpyW(wszSource,QUARTZ_wszSourceFilter);
346                                                                         cbRegData = NUMELEMS(wszSourceFilter)-sizeof(WCHAR);
347                                                                         lr = RegQueryValueExW(
348                                                                                 hkSource, wszSource, NULL,
349                                                                                 &dwRegType,
350                                                                                 (BYTE*)wszSourceFilter, &cbRegData );
351                                                                         if ( lr == ERROR_SUCCESS )
352                                                                         {
353                                                                                 hr = CLSIDFromString(wszSourceFilter,pidSource);
354                                                                         }
355                                                                         else
356                                                                                 hr = E_FAIL;
357                                                                 }
358
359                                                                 if ( hr != NOERROR && SUCCEEDED(hr) )
360                                                                         hr = E_FAIL;
361                                                         }
362                                                         if ( hr != S_FALSE )
363                                                                 break;
364                                                 }
365                                                 RegCloseKey( hkSource );
366                                         }
367                                 }
368                                 RegCloseKey( hkSub );
369                         }
370                 }
371                 RegCloseKey( hkMajor );
372         }
373
374         if ( pwszLocalBuf != NULL )
375                 QUARTZ_FreeMem(pwszLocalBuf);
376
377         return hr;
378 }
379
380
381
382 /***************************************************************************
383  *
384  *      CFilterGraph::IFilterGraph2 methods
385  *
386  */
387
388 static HRESULT WINAPI
389 IFilterGraph2_fnQueryInterface(IFilterGraph2* iface,REFIID riid,void** ppobj)
390 {
391         CFilterGraph_THIS(iface,fgraph);
392
393         TRACE("(%p)->()\n",This);
394
395         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
396 }
397
398 static ULONG WINAPI
399 IFilterGraph2_fnAddRef(IFilterGraph2* iface)
400 {
401         CFilterGraph_THIS(iface,fgraph);
402
403         TRACE("(%p)->()\n",This);
404
405         return IUnknown_AddRef(This->unk.punkControl);
406 }
407
408 static ULONG WINAPI
409 IFilterGraph2_fnRelease(IFilterGraph2* iface)
410 {
411         CFilterGraph_THIS(iface,fgraph);
412
413         TRACE("(%p)->()\n",This);
414
415         return IUnknown_Release(This->unk.punkControl);
416 }
417
418 static HRESULT WINAPI
419 IFilterGraph2_fnAddFilter(IFilterGraph2* iface,IBaseFilter* pFilter, LPCWSTR pName)
420 {
421         CFilterGraph_THIS(iface,fgraph);
422         FILTER_STATE fs;
423         FILTER_INFO     info;
424         HRESULT hr;
425         HRESULT hrSucceeded = S_OK;
426         QUARTZ_CompListItem*    pItem;
427         int i,iLen;
428
429         TRACE( "(%p)->(%p,%s)\n",This,pFilter,debugstr_w(pName) );
430
431         QUARTZ_CompList_Lock( This->m_pFilterList );
432
433         hr = IMediaFilter_GetState(CFilterGraph_IMediaFilter(This),0,&fs);
434         if ( hr == VFW_S_STATE_INTERMEDIATE )
435                 hr = VFW_E_STATE_CHANGED;
436         if ( fs != State_Stopped )
437                 hr = VFW_E_NOT_STOPPED;
438         if ( FAILED(hr) )
439                 goto end;
440
441         TRACE( "(%p) search the specified name.\n",This );
442
443         if ( pName != NULL )
444         {
445                 pItem = QUARTZ_CompList_SearchData(
446                         This->m_pFilterList,
447                         pName, sizeof(WCHAR)*(lstrlenW(pName)+1) );
448                 if ( pItem == NULL )
449                         goto name_ok;
450
451                 hrSucceeded = VFW_S_DUPLICATE_NAME;
452
453                 iLen = lstrlenW(pName);
454                 if ( iLen > 32 )
455                         iLen = 32;
456                 memcpy( info.achName, pName, sizeof(WCHAR)*iLen );
457                 info.achName[iLen] = 0;
458         }
459         else
460         {
461                 ZeroMemory( &info, sizeof(info) );
462                 hr = IBaseFilter_QueryFilterInfo( pFilter, &info );
463                 if ( FAILED(hr) )
464                         goto end;
465
466                 iLen = lstrlenW(info.achName);
467                 pItem = QUARTZ_CompList_SearchData(
468                         This->m_pFilterList,
469                         info.achName, sizeof(WCHAR)*(iLen+1) );
470                 if ( iLen > 0 && pItem == NULL )
471                 {
472                         pName = info.achName;
473                         goto name_ok;
474                 }
475         }
476
477         /* generate modified names for this filter.. */
478         iLen = lstrlenW(info.achName);
479         if ( iLen > 32 )
480                 iLen = 32;
481         info.achName[iLen++] = ' ';
482
483         for ( i = 0; i <= 99; i++ )
484         {
485                 info.achName[iLen+0] = (i%10) + '0';
486                 info.achName[iLen+1] = ((i/10)%10) + '0';
487                 info.achName[iLen+2] = 0;
488                 pItem = QUARTZ_CompList_SearchData(
489                         This->m_pFilterList,
490                         info.achName, sizeof(WCHAR)*(iLen+3) );
491                 if ( pItem == NULL )
492                 {
493                         pName = info.achName;
494                         goto name_ok;
495                 }
496         }
497
498         hr = ( pName == NULL ) ? E_FAIL : VFW_E_DUPLICATE_NAME;
499         goto end;
500
501 name_ok:
502         TRACE( "(%p) add this filter - %s.\n",This,debugstr_w(pName) );
503
504         /* register this filter. */
505         hr = QUARTZ_CompList_AddComp(
506                 This->m_pFilterList, (IUnknown*)pFilter,
507                 pName, sizeof(WCHAR)*(lstrlenW(pName)+1) );
508         if ( FAILED(hr) )
509                 goto end;
510
511         hr = IBaseFilter_JoinFilterGraph(pFilter,(IFilterGraph*)iface,pName);
512         if ( SUCCEEDED(hr) )
513         {
514                 EnterCriticalSection( &This->m_csClock );
515                 hr = IBaseFilter_SetSyncSource( pFilter, This->m_pClock );
516                 LeaveCriticalSection( &This->m_csClock );
517         }
518         if ( FAILED(hr) )
519         {
520                 IBaseFilter_JoinFilterGraph(pFilter,NULL,pName);
521                 QUARTZ_CompList_RemoveComp(
522                         This->m_pFilterList,(IUnknown*)pFilter);
523                 goto end;
524         }
525
526         hr = CFilterGraph_GraphChanged(This);
527         if ( FAILED(hr) )
528                 goto end;
529
530         hr = hrSucceeded;
531 end:
532         QUARTZ_CompList_Unlock( This->m_pFilterList );
533
534         TRACE( "(%p) return %08lx\n", This, hr );
535
536         return hr;
537 }
538
539 static HRESULT WINAPI
540 IFilterGraph2_fnRemoveFilter(IFilterGraph2* iface,IBaseFilter* pFilter)
541 {
542         CFilterGraph_THIS(iface,fgraph);
543         QUARTZ_CompListItem*    pItem;
544         FILTER_STATE fs;
545         HRESULT hr = NOERROR;
546
547         TRACE( "(%p)->(%p)\n",This,pFilter );
548
549         QUARTZ_CompList_Lock( This->m_pFilterList );
550
551         hr = IMediaFilter_GetState(CFilterGraph_IMediaFilter(This),0,&fs);
552         if ( hr == VFW_S_STATE_INTERMEDIATE )
553                 hr = VFW_E_STATE_CHANGED;
554         if ( fs != State_Stopped )
555                 hr = VFW_E_NOT_STOPPED;
556         if ( FAILED(hr) )
557                 goto end;
558
559         hr = S_FALSE; /* FIXME? */
560         pItem = QUARTZ_CompList_SearchComp(
561                 This->m_pFilterList, (IUnknown*)pFilter );
562         if ( pItem != NULL )
563         {
564                 CFilterGraph_DisconnectAllPins(pFilter);
565                 IBaseFilter_SetSyncSource( pFilter, NULL );
566                 hr = IBaseFilter_JoinFilterGraph(
567                         pFilter, NULL, QUARTZ_CompList_GetDataPtr(pItem) );
568                 QUARTZ_CompList_RemoveComp(
569                         This->m_pFilterList, (IUnknown*)pFilter );
570         }
571
572         hr = CFilterGraph_GraphChanged(This);
573         if ( FAILED(hr) )
574                 goto end;
575
576 end:;
577         QUARTZ_CompList_Unlock( This->m_pFilterList );
578
579         return hr;
580 }
581
582 static HRESULT WINAPI
583 IFilterGraph2_fnEnumFilters(IFilterGraph2* iface,IEnumFilters** ppEnum)
584 {
585         CFilterGraph_THIS(iface,fgraph);
586         HRESULT hr;
587
588         TRACE( "(%p)->(%p)\n",This,ppEnum );
589
590         QUARTZ_CompList_Lock( This->m_pFilterList );
591
592         hr = QUARTZ_CreateEnumUnknown(
593                 &IID_IEnumFilters, (void**)ppEnum, This->m_pFilterList );
594
595         QUARTZ_CompList_Unlock( This->m_pFilterList );
596
597         return hr;
598 }
599
600 static HRESULT WINAPI
601 IFilterGraph2_fnFindFilterByName(IFilterGraph2* iface,LPCWSTR pName,IBaseFilter** ppFilter)
602 {
603         CFilterGraph_THIS(iface,fgraph);
604         QUARTZ_CompListItem*    pItem;
605         HRESULT hr = E_FAIL;
606
607         TRACE( "(%p)->(%s,%p)\n",This,debugstr_w(pName),ppFilter );
608
609         if ( ppFilter == NULL )
610                 return E_POINTER;
611         *ppFilter = NULL;
612
613         QUARTZ_CompList_Lock( This->m_pFilterList );
614
615         pItem = QUARTZ_CompList_SearchData(
616                 This->m_pFilterList,
617                 pName, sizeof(WCHAR)*(lstrlenW(pName)+1) );
618         if ( pItem != NULL )
619         {
620                 *ppFilter = (IBaseFilter*)QUARTZ_CompList_GetItemPtr(pItem);
621                 hr = NOERROR;
622         }
623
624         QUARTZ_CompList_Unlock( This->m_pFilterList );
625
626         return hr;
627 }
628
629 static HRESULT WINAPI
630 IFilterGraph2_fnConnectDirect(IFilterGraph2* iface,IPin* pOut,IPin* pIn,const AM_MEDIA_TYPE* pmt)
631 {
632         CFilterGraph_THIS(iface,fgraph);
633         IPin*   pConnTo;
634         PIN_INFO        infoIn;
635         PIN_INFO        infoOut;
636         FILTER_INFO     finfoIn;
637         FILTER_INFO     finfoOut;
638         FILTER_STATE    fs;
639         HRESULT hr;
640
641         TRACE( "(%p)->(%p,%p,%p)\n",This,pOut,pIn,pmt );
642
643         infoIn.pFilter = NULL;
644         infoOut.pFilter = NULL;
645         finfoIn.pGraph = NULL;
646         finfoOut.pGraph = NULL;
647
648         QUARTZ_CompList_Lock( This->m_pFilterList );
649
650         hr = IMediaFilter_GetState(CFilterGraph_IMediaFilter(This),0,&fs);
651         if ( hr == VFW_S_STATE_INTERMEDIATE )
652                 hr = VFW_E_STATE_CHANGED;
653         if ( fs != State_Stopped )
654                 hr = VFW_E_NOT_STOPPED;
655         if ( FAILED(hr) )
656                 goto end;
657
658         hr = IPin_QueryPinInfo(pIn,&infoIn);
659         if ( FAILED(hr) )
660                 goto end;
661         hr = IPin_QueryPinInfo(pOut,&infoOut);
662         if ( FAILED(hr) )
663                 goto end;
664         if ( infoIn.pFilter == NULL || infoOut.pFilter == NULL ||
665                  infoIn.dir != PINDIR_INPUT || infoOut.dir != PINDIR_OUTPUT )
666         {
667                 hr = E_FAIL;
668                 goto end;
669         }
670
671         hr = IBaseFilter_QueryFilterInfo(infoIn.pFilter,&finfoIn);
672         if ( FAILED(hr) )
673                 goto end;
674         hr = IBaseFilter_QueryFilterInfo(infoOut.pFilter,&finfoOut);
675         if ( FAILED(hr) )
676                 goto end;
677         if ( finfoIn.pGraph != ((IFilterGraph*)iface) ||
678                  finfoOut.pGraph != ((IFilterGraph*)iface) )
679         {
680                 hr = E_FAIL;
681                 goto end;
682         }
683
684         pConnTo = NULL;
685         hr = IPin_ConnectedTo(pIn,&pConnTo);
686         if ( hr == NOERROR && pConnTo != NULL )
687         {
688                 IPin_Release(pConnTo);
689                 hr = VFW_E_ALREADY_CONNECTED;
690                 goto end;
691         }
692
693         pConnTo = NULL;
694         hr = IPin_ConnectedTo(pOut,&pConnTo);
695         if ( hr == NOERROR && pConnTo != NULL )
696         {
697                 IPin_Release(pConnTo);
698                 hr = VFW_E_ALREADY_CONNECTED;
699                 goto end;
700         }
701
702         TRACE("(%p) try to connect %p<->%p\n",This,pIn,pOut);
703         hr = IPin_Connect(pOut,pIn,pmt);
704         if ( FAILED(hr) )
705         {
706                 TRACE("(%p)->Connect(%p,%p) hr = %08lx\n",pOut,pIn,pmt,hr);
707                 IPin_Disconnect(pOut);
708                 IPin_Disconnect(pIn);
709                 goto end;
710         }
711
712         hr = CFilterGraph_GraphChanged(This);
713         if ( FAILED(hr) )
714                 goto end;
715
716 end:
717         QUARTZ_CompList_Unlock( This->m_pFilterList );
718
719         if ( infoIn.pFilter != NULL )
720                 IBaseFilter_Release(infoIn.pFilter);
721         if ( infoOut.pFilter != NULL )
722                 IBaseFilter_Release(infoOut.pFilter);
723         if ( finfoIn.pGraph != NULL )
724                 IFilterGraph_Release(finfoIn.pGraph);
725         if ( finfoOut.pGraph != NULL )
726                 IFilterGraph_Release(finfoOut.pGraph);
727
728         return hr;
729 }
730
731 static HRESULT WINAPI
732 IFilterGraph2_fnReconnect(IFilterGraph2* iface,IPin* pPin)
733 {
734         CFilterGraph_THIS(iface,fgraph);
735
736         TRACE( "(%p)->(%p)\n",This,pPin );
737
738         return IFilterGraph2_ReconnectEx(iface,pPin,NULL);
739 }
740
741 static HRESULT WINAPI
742 IFilterGraph2_fnDisconnect(IFilterGraph2* iface,IPin* pPin)
743 {
744         CFilterGraph_THIS(iface,fgraph);
745         IPin* pConnTo;
746         HRESULT hr;
747
748         TRACE( "(%p)->(%p)\n",This,pPin );
749
750         QUARTZ_CompList_Lock( This->m_pFilterList );
751
752         pConnTo = NULL;
753         hr = IPin_ConnectedTo(pPin,&pConnTo);
754         if ( hr == NOERROR && pConnTo != NULL )
755         {
756                 IPin_Disconnect(pConnTo);
757                 IPin_Release(pConnTo);
758         }
759         hr = IPin_Disconnect(pPin);
760         if ( FAILED(hr) )
761                 goto end;
762
763         hr = CFilterGraph_GraphChanged(This);
764         if ( FAILED(hr) )
765                 goto end;
766
767 end:
768         QUARTZ_CompList_Unlock( This->m_pFilterList );
769
770         return hr;
771 }
772
773 static HRESULT WINAPI
774 IFilterGraph2_fnSetDefaultSyncSource(IFilterGraph2* iface)
775 {
776         CFilterGraph_THIS(iface,fgraph);
777         IUnknown* punk;
778         IReferenceClock* pClock;
779         HRESULT hr;
780
781         FIXME( "(%p)->() stub!\n", This );
782
783         /* FIXME - search all filters from renderer. */
784
785         hr = QUARTZ_CreateSystemClock( NULL, (void**)&punk );
786         if ( FAILED(hr) )
787                 return hr;
788         hr = IUnknown_QueryInterface( punk, &IID_IReferenceClock, (void**)&pClock );    IUnknown_Release( punk );
789         if ( FAILED(hr) )
790                 return hr;
791
792         hr = IMediaFilter_SetSyncSource(
793                 CFilterGraph_IMediaFilter(This), pClock );
794         IReferenceClock_Release( pClock );
795
796         return hr;
797 }
798
799 static HRESULT WINAPI
800 IFilterGraph2_fnConnect(IFilterGraph2* iface,IPin* pOut,IPin* pIn)
801 {
802         CFilterGraph_THIS(iface,fgraph);
803         IFilterMapper2* pMap2 = NULL;
804         IEnumMoniker*   pEnumMon = NULL;
805         IMoniker*       pMon = NULL;
806         IBaseFilter*    pFilter = NULL;
807         IEnumPins*      pEnumPin = NULL;
808         IPin*   pPinTry = NULL;
809         PIN_INFO        info;
810         PIN_DIRECTION   pindir;
811         ULONG   cReturned;
812         BOOL    bTryConnect;
813         BOOL    bConnected = FALSE;
814         CLSID   clsidOutFilter;
815         CLSID   clsidInFilter;
816         CLSID   clsid;
817         HRESULT hr;
818
819         TRACE( "(%p)->(%p,%p)\n",This,pOut,pIn );
820
821         /* At first, try to connect directly. */
822         hr = IFilterGraph_ConnectDirect(iface,pOut,pIn,NULL);
823         if ( hr == NOERROR )
824                 return NOERROR;
825
826         /* FIXME - try to connect indirectly. */
827         FIXME( "(%p)->(%p,%p) stub!\n",This,pOut,pIn );
828
829         info.pFilter = NULL;
830         hr = IPin_QueryPinInfo(pOut,&info);
831         if ( FAILED(hr) )
832                 return hr;
833         if ( info.pFilter == NULL )
834                 return E_FAIL;
835         hr = IBaseFilter_GetClassID(info.pFilter,&clsidOutFilter);
836         IBaseFilter_Release(info.pFilter);
837         if ( FAILED(hr) )
838                 return hr;
839
840         info.pFilter = NULL;
841         hr = IPin_QueryPinInfo(pIn,&info);
842         if ( FAILED(hr) )
843                 return hr;
844         if ( info.pFilter == NULL )
845                 return E_FAIL;
846         hr = IBaseFilter_GetClassID(info.pFilter,&clsidInFilter);
847         IBaseFilter_Release(info.pFilter);
848         if ( FAILED(hr) )
849                 return hr;
850
851         /* FIXME - try to connect with unused filters. */
852         /* FIXME - try to connect with cached filters. */
853         /* FIXME - enumerate transform filters and try to connect */
854         hr = CoCreateInstance(
855                 &CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
856                 &IID_IFilterMapper2, (void**)&pMap2 );
857         if ( FAILED(hr) )
858                 return hr;
859         hr = IFilterMapper2_EnumMatchingFilters(
860                 pMap2,&pEnumMon,0,FALSE,MERIT_DO_NOT_USE+1,
861                 TRUE,0,NULL,NULL,NULL,FALSE,
862                 TRUE,0,NULL,NULL,NULL);
863         IFilterMapper2_Release(pMap2);
864         if ( FAILED(hr) )
865                 return hr;
866         TRACE("try to connect indirectly\n");
867
868         if ( hr == S_OK )
869         {
870                 while ( !bConnected && hr == S_OK )
871                 {
872                         hr = IEnumMoniker_Next(pEnumMon,1,&pMon,&cReturned);
873                         if ( hr != S_OK )
874                                 break;
875                         hr = IMoniker_BindToObject(pMon,NULL,NULL,&IID_IBaseFilter,(void**)&pFilter );
876                         if ( hr == S_OK )
877                         {
878                                 hr = IBaseFilter_GetClassID(pFilter,&clsid);
879                                 if ( hr == S_OK &&
880                                          ( IsEqualGUID(&clsidOutFilter,&clsid) || IsEqualGUID(&clsidInFilter,&clsid) ) )
881                                         hr = S_FALSE;
882                                 else
883                                         hr = IFilterGraph2_AddFilter(iface,pFilter,NULL);
884                                 if ( hr == S_OK )
885                                 {
886                                         bTryConnect = FALSE;
887                                         hr = IBaseFilter_EnumPins(pFilter,&pEnumPin);
888                                         if ( hr == S_OK )
889                                         {
890                                                 {
891                                                         while ( !bTryConnect )
892                                                         {
893                                                                 hr = IEnumPins_Next(pEnumPin,1,&pPinTry,&cReturned);
894                                                                 if ( hr != S_OK )
895                                                                         break;
896                                                                 hr = IPin_QueryDirection(pPinTry,&pindir);
897                                                                 if ( hr == S_OK && pindir == PINDIR_INPUT )
898                                                                 {
899                                                                         /* try to connect directly. */
900                                                                         hr = IFilterGraph2_ConnectDirect(iface,pOut,pPinTry,NULL);
901                                                                         if ( hr == S_OK )
902                                                                                 bTryConnect = TRUE;
903                                                                         hr = S_OK;
904                                                                 }
905                                                                 IPin_Release(pPinTry); pPinTry = NULL;
906                                                         }
907                                                 }
908                                                 IEnumPins_Release(pEnumPin); pEnumPin = NULL;
909                                         }
910                                         TRACE("TryConnect %d\n",bTryConnect);
911
912                                         if ( bTryConnect )
913                                         {
914                                                 hr = IBaseFilter_EnumPins(pFilter,&pEnumPin);
915                                                 if ( hr == S_OK )
916                                                 {
917                                                         while ( !bConnected )
918                                                         {
919                                                                 hr = IEnumPins_Next(pEnumPin,1,&pPinTry,&cReturned);
920                                                                 if ( hr != S_OK )
921                                                                         break;
922                                                                 hr = IPin_QueryDirection(pPinTry,&pindir);
923                                                                 if ( hr == S_OK && pindir == PINDIR_OUTPUT )
924                                                                 {
925                                                                         /* try to connect indirectly. */
926                                                                         hr = IFilterGraph2_Connect(iface,pPinTry,pIn);
927                                                                         if ( hr == S_OK )
928                                                                                 bConnected = TRUE;
929                                                                         hr = S_OK;
930                                                                 }
931                                                                 IPin_Release(pPinTry); pPinTry = NULL;
932                                                         }
933                                                         IEnumPins_Release(pEnumPin); pEnumPin = NULL;
934                                                 }
935                                         }
936                                         if ( !bConnected )
937                                                 hr = IFilterGraph2_RemoveFilter(iface,pFilter);
938                                 }
939                                 IBaseFilter_Release(pFilter); pFilter = NULL;
940                                 if ( SUCCEEDED(hr) )
941                                         hr = S_OK;
942                         }
943                         IMoniker_Release(pMon); pMon = NULL;
944                 }
945                 IEnumMoniker_Release(pEnumMon); pEnumMon = NULL;
946         }
947
948         if ( SUCCEEDED(hr) && !bConnected )
949                 hr = VFW_E_CANNOT_CONNECT;
950
951         return hr;
952 }
953
954 static HRESULT WINAPI
955 IFilterGraph2_fnRender(IFilterGraph2* iface,IPin* pOut)
956 {
957         CFilterGraph_THIS(iface,fgraph);
958         HRESULT hr;
959         IFilterMapper2* pMap2 = NULL;
960         IEnumMoniker*   pEnumMon = NULL;
961         IMoniker*       pMon = NULL;
962         IBaseFilter*    pFilter = NULL;
963         IEnumPins*      pEnumPin = NULL;
964         IPin*   pPin = NULL;
965         PIN_DIRECTION   pindir;
966         BOOL    bRendered = FALSE;
967         ULONG   cReturned;
968
969         FIXME( "(%p)->(%p)\n",This,pOut );
970
971         /* FIXME - must be locked */
972         /*QUARTZ_CompList_Lock( This->m_pFilterList );*/
973
974         if ( pOut == NULL )
975                 return E_POINTER;
976
977         hr = CoCreateInstance(
978                 &CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
979                 &IID_IFilterMapper2, (void**)&pMap2 );
980         if ( FAILED(hr) )
981                 return hr;
982         hr = IFilterMapper2_EnumMatchingFilters(
983                 pMap2,&pEnumMon,0,FALSE,MERIT_DO_NOT_USE+1,
984                 TRUE,0,NULL,NULL,NULL,TRUE,
985                 FALSE,0,NULL,NULL,NULL);
986         IFilterMapper2_Release(pMap2);
987         if ( FAILED(hr) )
988                 return hr;
989         TRACE("try to render pin\n");
990
991         if ( hr == S_OK )
992         {
993                 /* try to render pin. */
994                 while ( !bRendered && hr == S_OK )
995                 {
996                         hr = IEnumMoniker_Next(pEnumMon,1,&pMon,&cReturned);
997                         if ( hr != S_OK )
998                                 break;
999                         hr = IMoniker_BindToObject(pMon,NULL,NULL,&IID_IBaseFilter,(void**)&pFilter );
1000                         if ( hr == S_OK )
1001                         {
1002                                 hr = IFilterGraph2_AddFilter(iface,pFilter,NULL);
1003                                 if ( hr == S_OK )
1004                                 {
1005                                         hr = IBaseFilter_EnumPins(pFilter,&pEnumPin);
1006                                         if ( hr == S_OK )
1007                                         {
1008                                                 while ( !bRendered )
1009                                                 {
1010                                                         hr = IEnumPins_Next(pEnumPin,1,&pPin,&cReturned);
1011                                                         if ( hr != S_OK )
1012                                                                 break;
1013                                                         hr = IPin_QueryDirection(pPin,&pindir);
1014                                                         if ( hr == S_OK && pindir == PINDIR_INPUT )
1015                                                         {
1016                                                                 /* try to connect. */
1017                                                                 hr = IFilterGraph2_Connect(iface,pOut,pPin);
1018                                                                 if ( hr == S_OK )
1019                                                                         bRendered = TRUE;
1020                                                                 hr = S_OK;
1021                                                         }
1022                                                         IPin_Release(pPin); pPin = NULL;
1023                                                 }
1024                                                 IEnumPins_Release(pEnumPin); pEnumPin = NULL;
1025                                         }
1026                                         if ( !bRendered )
1027                                                 hr = IFilterGraph2_RemoveFilter(iface,pFilter);
1028                                 }
1029                                 IBaseFilter_Release(pFilter); pFilter = NULL;
1030                                 if ( SUCCEEDED(hr) )
1031                                         hr = S_OK;
1032                         }
1033                         IMoniker_Release(pMon); pMon = NULL;
1034                 }
1035                 IEnumMoniker_Release(pEnumMon); pEnumMon = NULL;
1036         }
1037
1038         if ( bRendered )
1039         {
1040                 /* successfully rendered(but may be partial now) */
1041                 hr = S_OK;
1042
1043                 /* FIXME - try to render all inserted filters. */
1044                 /* hr = VFW_S_PARTIAL_RENDER; */
1045         }
1046         else
1047         {
1048                 if ( SUCCEEDED(hr) )
1049                         hr = VFW_E_CANNOT_RENDER;
1050         }
1051
1052         /*QUARTZ_CompList_Unlock( This->m_pFilterList );*/
1053
1054         return hr;
1055 }
1056
1057 static HRESULT WINAPI
1058 IFilterGraph2_fnRenderFile(IFilterGraph2* iface,LPCWSTR lpFileName,LPCWSTR lpPlayList)
1059 {
1060         CFilterGraph_THIS(iface,fgraph);
1061         HRESULT hr;
1062         IBaseFilter*    pFilter = NULL;
1063         IEnumPins*      pEnum = NULL;
1064         IPin*   pPin;
1065         ULONG   cFetched;
1066         PIN_DIRECTION   dir;
1067         ULONG   cTryToRender;
1068         ULONG   cActRender;
1069
1070         TRACE( "(%p)->(%s,%s)\n",This,
1071                 debugstr_w(lpFileName),debugstr_w(lpPlayList) );
1072
1073         if ( lpPlayList != NULL )
1074                 return E_INVALIDARG;
1075
1076         pFilter = NULL;
1077         hr = IFilterGraph2_AddSourceFilter(iface,lpFileName,NULL,&pFilter);
1078         if ( FAILED(hr) )
1079                 goto end;
1080         if ( pFilter == NULL )
1081         {
1082                 hr = E_FAIL;
1083                 goto end;
1084         }
1085         TRACE("(%p) source filter %p\n",This,pFilter);
1086
1087         pEnum = NULL;
1088         hr = IBaseFilter_EnumPins( pFilter, &pEnum );
1089         if ( FAILED(hr) )
1090                 goto end;
1091         if ( pEnum == NULL )
1092         {
1093                 hr = E_FAIL;
1094                 goto end;
1095         }
1096
1097         cTryToRender = 0;
1098         cActRender = 0;
1099
1100         while ( 1 )
1101         {
1102                 pPin = NULL;
1103                 cFetched = 0;
1104                 hr = IEnumPins_Next( pEnum, 1, &pPin, &cFetched );
1105                 if ( FAILED(hr) )
1106                         goto end;
1107                 if ( hr != NOERROR || pPin == NULL || cFetched != 1 )
1108                 {
1109                         hr = NOERROR;
1110                         break;
1111                 }
1112                 hr = IPin_QueryDirection( pPin, &dir );
1113                 if ( hr == NOERROR && dir == PINDIR_OUTPUT )
1114                 {
1115                         cTryToRender ++;
1116                         hr = IFilterGraph2_Render( iface, pPin );
1117                         if ( hr == NOERROR )
1118                                 cActRender ++;
1119                 }
1120                 IPin_Release( pPin );
1121         }
1122
1123         if ( hr == NOERROR )
1124         {
1125                 if ( cTryToRender > cActRender )
1126                         hr = VFW_S_PARTIAL_RENDER;
1127                 if ( cActRender == 0 )
1128                         hr = E_FAIL;
1129         }
1130
1131 end:
1132         if ( pEnum != NULL )
1133                 IEnumPins_Release( pEnum );
1134         if ( pFilter != NULL )
1135                 IBaseFilter_Release( pFilter );
1136
1137         return hr;
1138 }
1139
1140 static HRESULT WINAPI
1141 IFilterGraph2_fnAddSourceFilter(IFilterGraph2* iface,LPCWSTR lpFileName,LPCWSTR lpFilterName,IBaseFilter** ppBaseFilter)
1142 {
1143         CFilterGraph_THIS(iface,fgraph);
1144         HRESULT hr;
1145         BYTE    bStartData[512];
1146         DWORD   cbStartData;
1147         AM_MEDIA_TYPE   mt;
1148         CLSID   clsidSource;
1149         IFileSourceFilter*      pSource;
1150
1151         FIXME( "(%p)->(%s,%s,%p)\n",This,
1152                 debugstr_w(lpFileName),debugstr_w(lpFilterName),ppBaseFilter );
1153
1154         if ( lpFileName == NULL || ppBaseFilter == NULL )
1155                 return E_POINTER;
1156         *ppBaseFilter = NULL;
1157
1158         hr = QUARTZ_PeekFile( lpFileName, bStartData, 512, &cbStartData );
1159         if ( FAILED(hr) )
1160         {
1161                 FIXME("cannot open %s (NOTE: URL is not implemented)\n", debugstr_w(lpFileName));
1162                 return hr;
1163         }
1164         ZeroMemory( &mt, sizeof(AM_MEDIA_TYPE) );
1165         mt.bFixedSizeSamples = 1;
1166         mt.lSampleSize = 1;
1167         memcpy( &mt.majortype, &MEDIATYPE_Stream, sizeof(GUID) );
1168         memcpy( &mt.subtype, &MEDIASUBTYPE_NULL, sizeof(GUID) );
1169         memcpy( &mt.formattype, &FORMAT_None, sizeof(GUID) );
1170         hr = QUARTZ_GetSourceTypeFromData(
1171                 bStartData, cbStartData,
1172                 &mt.majortype, &mt.subtype, &clsidSource );
1173         if ( FAILED(hr) )
1174         {
1175                 ERR("QUARTZ_GetSourceTypeFromData() failed - return %08lx\n",hr);
1176                 return hr;
1177         }
1178         if ( hr != S_OK )
1179         {
1180                 FIXME( "file %s - unknown format\n", debugstr_w(lpFileName) );
1181                 return VFW_E_INVALID_FILE_FORMAT;
1182         }
1183
1184         hr = CoCreateInstance(
1185                 &clsidSource, NULL, CLSCTX_INPROC_SERVER,
1186                 &IID_IBaseFilter, (void**)ppBaseFilter );
1187         if ( FAILED(hr) )
1188                 return hr;
1189         hr = IBaseFilter_QueryInterface(*ppBaseFilter,&IID_IFileSourceFilter,(void**)&pSource);
1190         if ( SUCCEEDED(hr) )
1191         {
1192                 hr = IFileSourceFilter_Load(pSource,lpFileName,&mt);
1193                 IFileSourceFilter_Release(pSource);
1194         }
1195         if ( SUCCEEDED(hr) )
1196                 hr = IFilterGraph2_AddFilter(iface,*ppBaseFilter,lpFilterName);
1197         if ( FAILED(hr) )
1198         {
1199                 IBaseFilter_Release(*ppBaseFilter);
1200                 *ppBaseFilter = NULL;
1201                 return hr;
1202         }
1203
1204         return S_OK;
1205 }
1206
1207 static HRESULT WINAPI
1208 IFilterGraph2_fnSetLogFile(IFilterGraph2* iface,DWORD_PTR hFile)
1209 {
1210         CFilterGraph_THIS(iface,fgraph);
1211
1212         FIXME( "(%p)->() stub!\n", This );
1213         return E_NOTIMPL;
1214 }
1215
1216 static HRESULT WINAPI
1217 IFilterGraph2_fnAbort(IFilterGraph2* iface)
1218 {
1219         CFilterGraph_THIS(iface,fgraph);
1220
1221         /* undoc. */
1222
1223         FIXME( "(%p)->() stub!\n", This );
1224         return E_NOTIMPL;
1225 }
1226
1227 static HRESULT WINAPI
1228 IFilterGraph2_fnShouldOperationContinue(IFilterGraph2* iface)
1229 {
1230         CFilterGraph_THIS(iface,fgraph);
1231
1232         /* undoc. */
1233
1234         FIXME( "(%p)->() stub!\n", This );
1235         return E_NOTIMPL;
1236 }
1237
1238 static HRESULT WINAPI
1239 IFilterGraph2_fnAddSourceFilterForMoniker(IFilterGraph2* iface,IMoniker* pMon,IBindCtx* pCtx,LPCWSTR pFilterName,IBaseFilter** ppFilter)
1240 {
1241         CFilterGraph_THIS(iface,fgraph);
1242
1243         FIXME( "(%p)->() stub!\n", This );
1244         return E_NOTIMPL;
1245 }
1246
1247 static HRESULT WINAPI
1248 IFilterGraph2_fnReconnectEx(IFilterGraph2* iface,IPin* pPin,const AM_MEDIA_TYPE* pmt)
1249 {
1250         CFilterGraph_THIS(iface,fgraph);
1251         HRESULT hr;
1252
1253         FIXME( "(%p)->(%p,%p) stub!\n",This,pPin,pmt );
1254
1255         /* reconnect asynchronously. */
1256
1257         QUARTZ_CompList_Lock( This->m_pFilterList );
1258         hr = CFilterGraph_GraphChanged(This);
1259         QUARTZ_CompList_Unlock( This->m_pFilterList );
1260
1261         return E_NOTIMPL;
1262 }
1263
1264 static HRESULT WINAPI
1265 IFilterGraph2_fnRenderEx(IFilterGraph2* iface,IPin* pPin,DWORD dwParam1,DWORD* pdwParam2)
1266 {
1267         CFilterGraph_THIS(iface,fgraph);
1268
1269         /* undoc. */
1270         FIXME( "(%p)->(%p,%08lx,%p) stub!\n",This,pPin,dwParam1,pdwParam2);
1271         return E_NOTIMPL;
1272 }
1273
1274
1275
1276
1277 static ICOM_VTABLE(IFilterGraph2) ifgraph =
1278 {
1279         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1280         /* IUnknown fields */
1281         IFilterGraph2_fnQueryInterface,
1282         IFilterGraph2_fnAddRef,
1283         IFilterGraph2_fnRelease,
1284         /* IFilterGraph fields */
1285         IFilterGraph2_fnAddFilter,
1286         IFilterGraph2_fnRemoveFilter,
1287         IFilterGraph2_fnEnumFilters,
1288         IFilterGraph2_fnFindFilterByName,
1289         IFilterGraph2_fnConnectDirect,
1290         IFilterGraph2_fnReconnect,
1291         IFilterGraph2_fnDisconnect,
1292         IFilterGraph2_fnSetDefaultSyncSource,
1293         /* IGraphBuilder fields */
1294         IFilterGraph2_fnConnect,
1295         IFilterGraph2_fnRender,
1296         IFilterGraph2_fnRenderFile,
1297         IFilterGraph2_fnAddSourceFilter,
1298         IFilterGraph2_fnSetLogFile,
1299         IFilterGraph2_fnAbort,
1300         IFilterGraph2_fnShouldOperationContinue,
1301         /* IFilterGraph2 fields */
1302         IFilterGraph2_fnAddSourceFilterForMoniker,
1303         IFilterGraph2_fnReconnectEx,
1304         IFilterGraph2_fnRenderEx,
1305 };
1306
1307 HRESULT CFilterGraph_InitIFilterGraph2( CFilterGraph* pfg )
1308 {
1309         TRACE("(%p)\n",pfg);
1310         ICOM_VTBL(&pfg->fgraph) = &ifgraph;
1311
1312         pfg->m_pFilterList = QUARTZ_CompList_Alloc();
1313         if ( pfg->m_pFilterList == NULL )
1314                 return E_OUTOFMEMORY;
1315
1316         return NOERROR;
1317 }
1318
1319 void CFilterGraph_UninitIFilterGraph2( CFilterGraph* pfg )
1320 {
1321         QUARTZ_CompListItem*    pItem;
1322
1323         TRACE("(%p)\n",pfg);
1324
1325         /* remove all filters... */
1326         while ( 1 )
1327         {
1328                 pItem = QUARTZ_CompList_GetFirst( pfg->m_pFilterList );
1329                 if ( pItem == NULL )
1330                         break;
1331                 IFilterGraph2_RemoveFilter(
1332                         (IFilterGraph2*)(&pfg->fgraph),
1333                         (IBaseFilter*)QUARTZ_CompList_GetItemPtr(pItem) );
1334         }
1335
1336         QUARTZ_CompList_Free( pfg->m_pFilterList );
1337 }
1338
1339 /***************************************************************************
1340  *
1341  *      CFilterGraph::IGraphVersion methods
1342  *
1343  */
1344
1345 static HRESULT WINAPI
1346 IGraphVersion_fnQueryInterface(IGraphVersion* iface,REFIID riid,void** ppobj)
1347 {
1348         CFilterGraph_THIS(iface,graphversion);
1349
1350         TRACE("(%p)->()\n",This);
1351
1352         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
1353 }
1354
1355 static ULONG WINAPI
1356 IGraphVersion_fnAddRef(IGraphVersion* iface)
1357 {
1358         CFilterGraph_THIS(iface,graphversion);
1359
1360         TRACE("(%p)->()\n",This);
1361
1362         return IUnknown_AddRef(This->unk.punkControl);
1363 }
1364
1365 static ULONG WINAPI
1366 IGraphVersion_fnRelease(IGraphVersion* iface)
1367 {
1368         CFilterGraph_THIS(iface,graphversion);
1369
1370         TRACE("(%p)->()\n",This);
1371
1372         return IUnknown_Release(This->unk.punkControl);
1373 }
1374
1375
1376 static HRESULT WINAPI
1377 IGraphVersion_fnQueryVersion(IGraphVersion* iface,LONG* plVersion)
1378 {
1379         CFilterGraph_THIS(iface,graphversion);
1380
1381         TRACE("(%p)->(%p)\n",This,plVersion);
1382
1383         if ( plVersion == NULL )
1384                 return E_POINTER;
1385
1386         QUARTZ_CompList_Lock( This->m_pFilterList );
1387         *plVersion = This->m_lGraphVersion;
1388         QUARTZ_CompList_Unlock( This->m_pFilterList );
1389
1390         return NOERROR;
1391 }
1392
1393
1394 static ICOM_VTABLE(IGraphVersion) igraphversion =
1395 {
1396         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1397         /* IUnknown fields */
1398         IGraphVersion_fnQueryInterface,
1399         IGraphVersion_fnAddRef,
1400         IGraphVersion_fnRelease,
1401         /* IGraphVersion fields */
1402         IGraphVersion_fnQueryVersion,
1403 };
1404
1405
1406
1407 HRESULT CFilterGraph_InitIGraphVersion( CFilterGraph* pfg )
1408 {
1409         TRACE("(%p)\n",pfg);
1410         ICOM_VTBL(&pfg->graphversion) = &igraphversion;
1411
1412         pfg->m_lGraphVersion = 1;
1413
1414         return NOERROR;
1415 }
1416
1417 void CFilterGraph_UninitIGraphVersion( CFilterGraph* pfg )
1418 {
1419         TRACE("(%p)\n",pfg);
1420 }
1421
1422 /***************************************************************************
1423  *
1424  *      CFilterGraph::IGraphConfig methods
1425  *
1426  */
1427
1428 static HRESULT WINAPI
1429 IGraphConfig_fnQueryInterface(IGraphConfig* iface,REFIID riid,void** ppobj)
1430 {
1431         CFilterGraph_THIS(iface,grphconf);
1432
1433         TRACE("(%p)->()\n",This);
1434
1435         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
1436 }
1437
1438 static ULONG WINAPI
1439 IGraphConfig_fnAddRef(IGraphConfig* iface)
1440 {
1441         CFilterGraph_THIS(iface,grphconf);
1442
1443         TRACE("(%p)->()\n",This);
1444
1445         return IUnknown_AddRef(This->unk.punkControl);
1446 }
1447
1448 static ULONG WINAPI
1449 IGraphConfig_fnRelease(IGraphConfig* iface)
1450 {
1451         CFilterGraph_THIS(iface,grphconf);
1452
1453         TRACE("(%p)->()\n",This);
1454
1455         return IUnknown_Release(This->unk.punkControl);
1456 }
1457
1458
1459
1460 static HRESULT WINAPI
1461 IGraphConfig_fnReconnect(IGraphConfig* iface,IPin* pOut,IPin* pIn,const AM_MEDIA_TYPE* pmt,IBaseFilter* pFilter,HANDLE hAbort,DWORD dwFlags)
1462 {
1463         CFilterGraph_THIS(iface,grphconf);
1464
1465         FIXME("(%p)->() stub!\n",This);
1466
1467         return E_NOTIMPL;
1468 }
1469
1470 static HRESULT WINAPI
1471 IGraphConfig_fnReconfigure(IGraphConfig* iface,IGraphConfigCallback* pCallback,PVOID pvParam,DWORD dwFlags,HANDLE hAbort)
1472 {
1473         CFilterGraph_THIS(iface,grphconf);
1474         HRESULT hr;
1475
1476         FIXME("(%p)->(%p,%p,%08lx,%08x) stub!\n",This,pCallback,pvParam,dwFlags,hAbort);
1477
1478         QUARTZ_CompList_Lock( This->m_pFilterList );
1479         EnterCriticalSection( &This->m_csGraphState );
1480
1481         hr = IGraphConfigCallback_Reconfigure(pCallback,pvParam,dwFlags);
1482
1483         LeaveCriticalSection( &This->m_csGraphState );
1484         QUARTZ_CompList_Unlock( This->m_pFilterList );
1485
1486         return hr;
1487 }
1488
1489 static HRESULT WINAPI
1490 IGraphConfig_fnAddFilterToCache(IGraphConfig* iface,IBaseFilter* pFilter)
1491 {
1492         CFilterGraph_THIS(iface,grphconf);
1493
1494         FIXME("(%p)->() stub!\n",This);
1495
1496         return E_NOTIMPL;
1497 }
1498
1499 static HRESULT WINAPI
1500 IGraphConfig_fnEnumCacheFilter(IGraphConfig* iface,IEnumFilters** ppenum)
1501 {
1502         CFilterGraph_THIS(iface,grphconf);
1503
1504         FIXME("(%p)->() stub!\n",This);
1505
1506         return E_NOTIMPL;
1507 }
1508
1509 static HRESULT WINAPI
1510 IGraphConfig_fnRemoveFilterFromCache(IGraphConfig* iface,IBaseFilter* pFilter)
1511 {
1512         CFilterGraph_THIS(iface,grphconf);
1513
1514         FIXME("(%p)->() stub!\n",This);
1515
1516         return E_NOTIMPL;
1517 }
1518
1519 static HRESULT WINAPI
1520 IGraphConfig_fnGetStartTime(IGraphConfig* iface,REFERENCE_TIME* prt)
1521 {
1522         CFilterGraph_THIS(iface,grphconf);
1523
1524         FIXME("(%p)->() stub!\n",This);
1525
1526         return E_NOTIMPL;
1527 }
1528
1529 static HRESULT WINAPI
1530 IGraphConfig_fnPushThroughData(IGraphConfig* iface,IPin* pOut,IPinConnection* pConn,HANDLE hAbort)
1531 {
1532         CFilterGraph_THIS(iface,grphconf);
1533
1534         FIXME("(%p)->() stub!\n",This);
1535
1536         return E_NOTIMPL;
1537 }
1538
1539 static HRESULT WINAPI
1540 IGraphConfig_fnSetFilterFlags(IGraphConfig* iface,IBaseFilter* pFilter,DWORD dwFlags)
1541 {
1542         CFilterGraph_THIS(iface,grphconf);
1543
1544         FIXME("(%p)->() stub!\n",This);
1545
1546         return E_NOTIMPL;
1547 }
1548
1549 static HRESULT WINAPI
1550 IGraphConfig_fnGetFilterFlags(IGraphConfig* iface,IBaseFilter* pFilter,DWORD* pdwFlags)
1551 {
1552         CFilterGraph_THIS(iface,grphconf);
1553
1554         FIXME("(%p)->() stub!\n",This);
1555
1556         return E_NOTIMPL;
1557 }
1558
1559 static HRESULT WINAPI
1560 IGraphConfig_fnRemoveFilterEx(IGraphConfig* iface,IBaseFilter* pFilter,DWORD dwFlags)
1561 {
1562         CFilterGraph_THIS(iface,grphconf);
1563
1564         FIXME("(%p)->() stub!\n",This);
1565
1566         return E_NOTIMPL;
1567 }
1568
1569
1570
1571
1572
1573 static ICOM_VTABLE(IGraphConfig) igraphconfig =
1574 {
1575         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1576         /* IUnknown fields */
1577         IGraphConfig_fnQueryInterface,
1578         IGraphConfig_fnAddRef,
1579         IGraphConfig_fnRelease,
1580         /* IGraphConfig fields */
1581         IGraphConfig_fnReconnect,
1582         IGraphConfig_fnReconfigure,
1583         IGraphConfig_fnAddFilterToCache,
1584         IGraphConfig_fnEnumCacheFilter,
1585         IGraphConfig_fnRemoveFilterFromCache,
1586         IGraphConfig_fnGetStartTime,
1587         IGraphConfig_fnPushThroughData,
1588         IGraphConfig_fnSetFilterFlags,
1589         IGraphConfig_fnGetFilterFlags,
1590         IGraphConfig_fnRemoveFilterEx,
1591 };
1592
1593
1594
1595 HRESULT CFilterGraph_InitIGraphConfig( CFilterGraph* pfg )
1596 {
1597         TRACE("(%p)\n",pfg);
1598         ICOM_VTBL(&pfg->grphconf) = &igraphconfig;
1599
1600         return NOERROR;
1601 }
1602
1603 void CFilterGraph_UninitIGraphConfig( CFilterGraph* pfg )
1604 {
1605         TRACE("(%p)\n",pfg);
1606 }
1607
1608