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