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