Update shell xxxAW wrapper prototypes for fixed SHLWAPI functions.
[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         IBaseFilter*    pTempFilter;
439         FG_FilterData*  pActiveFiltersNew;
440         HRESULT hr;
441         HRESULT hrSucceeded = S_OK;
442         int i,iLen;
443
444         TRACE( "(%p)->(%p,%s)\n",This,pFilter,debugstr_w(pName) );
445
446         EnterCriticalSection( &This->m_csFilters );
447
448         hr = IMediaFilter_GetState(CFilterGraph_IMediaFilter(This),0,&fs);
449         if ( hr == VFW_S_STATE_INTERMEDIATE )
450                 hr = VFW_E_STATE_CHANGED;
451         if ( fs != State_Stopped )
452                 hr = VFW_E_NOT_STOPPED;
453         if ( FAILED(hr) )
454                 goto end;
455
456         TRACE( "(%p) search the specified name.\n",This );
457
458         if ( pName != NULL )
459         {
460                 hr = IFilterGraph2_FindFilterByName( CFilterGraph_IFilterGraph2(This), pName, &pTempFilter );
461                 if ( hr == S_OK )
462                 {
463                         IBaseFilter_Release(pTempFilter);
464                         hrSucceeded = VFW_S_DUPLICATE_NAME;
465                 }
466                 else
467                 {
468                         goto name_ok;
469                 }
470
471                 iLen = lstrlenW(pName);
472                 if ( iLen > 32 )
473                         iLen = 32;
474                 memcpy( info.achName, pName, sizeof(WCHAR)*iLen );
475                 info.achName[iLen] = 0;
476         }
477         else
478         {
479                 ZeroMemory( &info, sizeof(info) );
480                 hr = IBaseFilter_QueryFilterInfo( pFilter, &info );
481                 if ( FAILED(hr) )
482                         goto end;
483                 if ( info.pGraph != NULL )
484                 {
485                         IFilterGraph_Release(info.pGraph);
486                         hr = E_FAIL;    /* FIXME */
487                         goto end;
488                 }
489
490                 hr = IFilterGraph2_FindFilterByName( CFilterGraph_IFilterGraph2(This), pName, &pTempFilter );
491                 if ( hr != S_OK )
492                 {
493                         pName = info.achName;
494                         goto name_ok;
495                 }
496         }
497
498         /* generate modified names for this filter.. */
499         iLen = lstrlenW(info.achName);
500         if ( iLen > 32 )
501                 iLen = 32;
502         info.achName[iLen++] = ' ';
503
504         for ( i = 0; i <= 99; i++ )
505         {
506                 info.achName[iLen+0] = (i%10) + '0';
507                 info.achName[iLen+1] = ((i/10)%10) + '0';
508                 info.achName[iLen+2] = 0;
509
510                 hr = IFilterGraph2_FindFilterByName( CFilterGraph_IFilterGraph2(This), info.achName, &pTempFilter );
511                 if ( hr != S_OK )
512                 {
513                         pName = info.achName;
514                         goto name_ok;
515                 }
516         }
517
518         hr = ( pName == NULL ) ? E_FAIL : VFW_E_DUPLICATE_NAME;
519         goto end;
520
521 name_ok:
522         TRACE( "(%p) add this filter - %s.\n",This,debugstr_w(pName) );
523
524         /* register this filter. */
525         pActiveFiltersNew = (FG_FilterData*)QUARTZ_ReallocMem(
526                 This->m_pActiveFilters,
527                 sizeof(FG_FilterData) * (This->m_cActiveFilters+1) );
528         if ( pActiveFiltersNew == NULL )
529         {
530                 hr = E_OUTOFMEMORY;
531                 goto end;
532         }
533         This->m_pActiveFilters = pActiveFiltersNew;
534         pActiveFiltersNew = &This->m_pActiveFilters[This->m_cActiveFilters];
535
536         pActiveFiltersNew->pFilter = NULL;
537         pActiveFiltersNew->pPosition = NULL;
538         pActiveFiltersNew->pSeeking = NULL;
539         pActiveFiltersNew->pwszName = NULL;
540         pActiveFiltersNew->cbName = 0;
541
542         pActiveFiltersNew->cbName = sizeof(WCHAR)*(lstrlenW(pName)+1);
543         pActiveFiltersNew->pwszName = (WCHAR*)QUARTZ_AllocMem( pActiveFiltersNew->cbName );
544         if ( pActiveFiltersNew->pwszName == NULL )
545         {
546                 hr = E_OUTOFMEMORY;
547                 goto end;
548         }
549         memcpy( pActiveFiltersNew->pwszName, pName, pActiveFiltersNew->cbName );
550
551         pActiveFiltersNew->pFilter = pFilter;
552         IBaseFilter_AddRef(pFilter);
553         IBaseFilter_QueryInterface( pFilter, &IID_IMediaPosition, (void**)&pActiveFiltersNew->pPosition );
554         IBaseFilter_QueryInterface( pFilter, &IID_IMediaSeeking, (void**)&pActiveFiltersNew->pSeeking );
555
556         This->m_cActiveFilters ++;
557
558         hr = IBaseFilter_JoinFilterGraph(pFilter,(IFilterGraph*)iface,pName);
559         if ( SUCCEEDED(hr) )
560         {
561                 EnterCriticalSection( &This->m_csClock );
562                 hr = IBaseFilter_SetSyncSource( pFilter, This->m_pClock );
563                 LeaveCriticalSection( &This->m_csClock );
564         }
565         if ( FAILED(hr) )
566         {
567                 IBaseFilter_JoinFilterGraph(pFilter,NULL,pName);
568                 IFilterGraph2_RemoveFilter(CFilterGraph_IFilterGraph2(This),pFilter);
569                 goto end;
570         }
571
572         hr = CFilterGraph_GraphChanged(This);
573         if ( FAILED(hr) )
574                 goto end;
575
576         hr = hrSucceeded;
577 end:
578         LeaveCriticalSection( &This->m_csFilters );
579
580         TRACE( "(%p) return %08lx\n", This, hr );
581
582         return hr;
583 }
584
585 static HRESULT WINAPI
586 IFilterGraph2_fnRemoveFilter(IFilterGraph2* iface,IBaseFilter* pFilter)
587 {
588         CFilterGraph_THIS(iface,fgraph);
589         FILTER_STATE fs;
590         DWORD   n,copy;
591         HRESULT hr = NOERROR;
592
593         TRACE( "(%p)->(%p)\n",This,pFilter );
594
595         EnterCriticalSection( &This->m_csFilters );
596
597         hr = IMediaFilter_GetState(CFilterGraph_IMediaFilter(This),0,&fs);
598         if ( hr == VFW_S_STATE_INTERMEDIATE )
599                 hr = VFW_E_STATE_CHANGED;
600         if ( fs != State_Stopped )
601                 hr = VFW_E_NOT_STOPPED;
602         if ( FAILED(hr) )
603                 goto end;
604
605         hr = S_FALSE; /* FIXME? */
606
607         for ( n = 0; n < This->m_cActiveFilters; n++ )
608         {
609                 if ( This->m_pActiveFilters[n].pFilter == pFilter )
610                 {
611                         CFilterGraph_DisconnectAllPins(pFilter);
612                         (void)IBaseFilter_SetSyncSource( pFilter, NULL );
613                         (void)IBaseFilter_JoinFilterGraph(
614                                 pFilter, NULL, This->m_pActiveFilters[n].pwszName );
615
616                         if ( This->m_pActiveFilters[n].pFilter != NULL )
617                                 IMediaPosition_Release(This->m_pActiveFilters[n].pFilter);
618                         if ( This->m_pActiveFilters[n].pPosition != NULL )
619                                 IMediaPosition_Release(This->m_pActiveFilters[n].pPosition);
620                         if ( This->m_pActiveFilters[n].pSeeking != NULL )
621                                 IMediaSeeking_Release(This->m_pActiveFilters[n].pSeeking);
622                         if ( This->m_pActiveFilters[n].pwszName != NULL )
623                                 QUARTZ_FreeMem(This->m_pActiveFilters[n].pwszName);
624
625                         copy = This->m_cActiveFilters - n - 1;
626                         if ( copy > 0 )
627                                 memmove( &This->m_pActiveFilters[n],
628                                                  &This->m_pActiveFilters[n+1],
629                                                  sizeof(FG_FilterData) * copy );
630                         This->m_cActiveFilters --;
631
632                         hr = CFilterGraph_GraphChanged(This);
633                         break;
634                 }
635         }
636
637 end:;
638         LeaveCriticalSection( &This->m_csFilters );
639
640         return hr;
641 }
642
643 static HRESULT WINAPI
644 IFilterGraph2_fnEnumFilters(IFilterGraph2* iface,IEnumFilters** ppEnum)
645 {
646         CFilterGraph_THIS(iface,fgraph);
647         QUARTZ_CompList*        pList = NULL;
648         DWORD   n;
649         HRESULT hr;
650
651         TRACE( "(%p)->(%p)\n",This,ppEnum );
652
653         EnterCriticalSection( &This->m_csFilters );
654
655         pList = QUARTZ_CompList_Alloc();
656         if ( pList == NULL )
657         {
658                 hr = E_OUTOFMEMORY;
659                 goto err;
660         }
661         for ( n = 0; n < This->m_cActiveFilters; n++ )
662         {
663                 hr = QUARTZ_CompList_AddTailComp(
664                         pList, (IUnknown*)This->m_pActiveFilters[n].pFilter, NULL, 0 );
665                 if ( FAILED(hr) )
666                         goto err;
667         }
668
669         hr = QUARTZ_CreateEnumUnknown(
670                 &IID_IEnumFilters, (void**)ppEnum, pList );
671 err:
672         if ( pList != NULL )
673                 QUARTZ_CompList_Free( pList );
674
675         LeaveCriticalSection( &This->m_csFilters );
676
677         return hr;
678 }
679
680 static HRESULT WINAPI
681 IFilterGraph2_fnFindFilterByName(IFilterGraph2* iface,LPCWSTR pName,IBaseFilter** ppFilter)
682 {
683         CFilterGraph_THIS(iface,fgraph);
684         DWORD   n;
685         DWORD   cbName;
686         HRESULT hr = E_FAIL;    /* FIXME */
687
688         TRACE( "(%p)->(%s,%p)\n",This,debugstr_w(pName),ppFilter );
689
690         if ( pName == NULL || ppFilter == NULL )
691                 return E_POINTER;
692         *ppFilter = NULL;
693
694         cbName = sizeof(WCHAR) * (lstrlenW(pName) + 1);
695
696         EnterCriticalSection( &This->m_csFilters );
697
698         for ( n = 0; n < This->m_cActiveFilters; n++ )
699         {
700                 if ( This->m_pActiveFilters[n].cbName == cbName &&
701                          !memcmp( This->m_pActiveFilters[n].pwszName, pName, cbName ) )
702                 {
703                         *ppFilter = This->m_pActiveFilters[n].pFilter;
704                         IBaseFilter_AddRef(*ppFilter);
705                         hr = NOERROR;
706                 }
707         }
708
709         LeaveCriticalSection( &This->m_csFilters );
710
711         return hr;
712 }
713
714 static HRESULT WINAPI
715 IFilterGraph2_fnConnectDirect(IFilterGraph2* iface,IPin* pOut,IPin* pIn,const AM_MEDIA_TYPE* pmt)
716 {
717         CFilterGraph_THIS(iface,fgraph);
718         IPin*   pConnTo;
719         PIN_INFO        infoIn;
720         PIN_INFO        infoOut;
721         FILTER_INFO     finfoIn;
722         FILTER_INFO     finfoOut;
723         FILTER_STATE    fs;
724         HRESULT hr;
725
726         TRACE( "(%p)->(%p,%p,%p)\n",This,pOut,pIn,pmt );
727
728         infoIn.pFilter = NULL;
729         infoOut.pFilter = NULL;
730         finfoIn.pGraph = NULL;
731         finfoOut.pGraph = NULL;
732
733         EnterCriticalSection( &This->m_csFilters );
734
735         hr = IMediaFilter_GetState(CFilterGraph_IMediaFilter(This),0,&fs);
736         if ( hr == VFW_S_STATE_INTERMEDIATE )
737                 hr = VFW_E_STATE_CHANGED;
738         if ( fs != State_Stopped )
739                 hr = VFW_E_NOT_STOPPED;
740         if ( FAILED(hr) )
741                 goto end;
742
743         hr = IPin_QueryPinInfo(pIn,&infoIn);
744         if ( FAILED(hr) )
745                 goto end;
746         hr = IPin_QueryPinInfo(pOut,&infoOut);
747         if ( FAILED(hr) )
748                 goto end;
749         if ( infoIn.pFilter == NULL || infoOut.pFilter == NULL ||
750                  infoIn.dir != PINDIR_INPUT || infoOut.dir != PINDIR_OUTPUT )
751         {
752                 hr = E_FAIL;
753                 goto end;
754         }
755
756         hr = IBaseFilter_QueryFilterInfo(infoIn.pFilter,&finfoIn);
757         if ( FAILED(hr) )
758                 goto end;
759         hr = IBaseFilter_QueryFilterInfo(infoOut.pFilter,&finfoOut);
760         if ( FAILED(hr) )
761                 goto end;
762         if ( finfoIn.pGraph != ((IFilterGraph*)iface) ||
763                  finfoOut.pGraph != ((IFilterGraph*)iface) )
764         {
765                 hr = E_FAIL;
766                 goto end;
767         }
768
769         pConnTo = NULL;
770         hr = IPin_ConnectedTo(pIn,&pConnTo);
771         if ( hr == NOERROR && pConnTo != NULL )
772         {
773                 IPin_Release(pConnTo);
774                 hr = VFW_E_ALREADY_CONNECTED;
775                 goto end;
776         }
777
778         pConnTo = NULL;
779         hr = IPin_ConnectedTo(pOut,&pConnTo);
780         if ( hr == NOERROR && pConnTo != NULL )
781         {
782                 IPin_Release(pConnTo);
783                 hr = VFW_E_ALREADY_CONNECTED;
784                 goto end;
785         }
786
787         TRACE("(%p) try to connect %p<->%p\n",This,pIn,pOut);
788         hr = IPin_Connect(pOut,pIn,pmt);
789         if ( FAILED(hr) )
790         {
791                 TRACE("(%p)->Connect(%p,%p) hr = %08lx\n",pOut,pIn,pmt,hr);
792                 IPin_Disconnect(pOut);
793                 IPin_Disconnect(pIn);
794                 goto end;
795         }
796
797         hr = CFilterGraph_GraphChanged(This);
798         if ( FAILED(hr) )
799                 goto end;
800
801 end:
802         LeaveCriticalSection( &This->m_csFilters );
803
804         if ( infoIn.pFilter != NULL )
805                 IBaseFilter_Release(infoIn.pFilter);
806         if ( infoOut.pFilter != NULL )
807                 IBaseFilter_Release(infoOut.pFilter);
808         if ( finfoIn.pGraph != NULL )
809                 IFilterGraph_Release(finfoIn.pGraph);
810         if ( finfoOut.pGraph != NULL )
811                 IFilterGraph_Release(finfoOut.pGraph);
812
813         return hr;
814 }
815
816 static HRESULT WINAPI
817 IFilterGraph2_fnReconnect(IFilterGraph2* iface,IPin* pPin)
818 {
819         CFilterGraph_THIS(iface,fgraph);
820
821         TRACE( "(%p)->(%p)\n",This,pPin );
822
823         return IFilterGraph2_ReconnectEx(iface,pPin,NULL);
824 }
825
826 static HRESULT WINAPI
827 IFilterGraph2_fnDisconnect(IFilterGraph2* iface,IPin* pPin)
828 {
829         CFilterGraph_THIS(iface,fgraph);
830         IPin* pConnTo;
831         HRESULT hr;
832
833         TRACE( "(%p)->(%p)\n",This,pPin );
834
835         EnterCriticalSection( &This->m_csFilters );
836
837         pConnTo = NULL;
838         hr = IPin_ConnectedTo(pPin,&pConnTo);
839         if ( hr == NOERROR && pConnTo != NULL )
840         {
841                 IPin_Disconnect(pConnTo);
842                 IPin_Release(pConnTo);
843         }
844         hr = IPin_Disconnect(pPin);
845         if ( FAILED(hr) )
846                 goto end;
847
848         hr = CFilterGraph_GraphChanged(This);
849         if ( FAILED(hr) )
850                 goto end;
851
852 end:
853         LeaveCriticalSection( &This->m_csFilters );
854
855         return hr;
856 }
857
858 static HRESULT WINAPI
859 IFilterGraph2_fnSetDefaultSyncSource(IFilterGraph2* iface)
860 {
861         CFilterGraph_THIS(iface,fgraph);
862         IUnknown* punk;
863         IReferenceClock* pClock;
864         HRESULT hr;
865
866         FIXME( "(%p)->() stub!\n", This );
867
868         /* FIXME - search all filters from renderer. */
869
870         hr = QUARTZ_CreateSystemClock( NULL, (void**)&punk );
871         if ( FAILED(hr) )
872                 return hr;
873         hr = IUnknown_QueryInterface( punk, &IID_IReferenceClock, (void**)&pClock );    IUnknown_Release( punk );
874         if ( FAILED(hr) )
875                 return hr;
876
877         hr = IMediaFilter_SetSyncSource(
878                 CFilterGraph_IMediaFilter(This), pClock );
879         IReferenceClock_Release( pClock );
880
881         return hr;
882 }
883
884 static HRESULT WINAPI
885 IFilterGraph2_fnConnect(IFilterGraph2* iface,IPin* pOut,IPin* pIn)
886 {
887         CFilterGraph_THIS(iface,fgraph);
888         IFilterMapper2* pMap2 = NULL;
889         IEnumMoniker*   pEnumMon = NULL;
890         IMoniker*       pMon = NULL;
891         IBaseFilter*    pFilter = NULL;
892         IEnumPins*      pEnumPin = NULL;
893         IPin*   pPinTry = NULL;
894         PIN_INFO        info;
895         PIN_DIRECTION   pindir;
896         ULONG   cReturned;
897         BOOL    bTryConnect;
898         BOOL    bConnected = FALSE;
899         CLSID   clsidOutFilter;
900         CLSID   clsidInFilter;
901         CLSID   clsid;
902         HRESULT hr;
903
904         TRACE( "(%p)->(%p,%p)\n",This,pOut,pIn );
905
906         /* At first, try to connect directly. */
907         hr = IFilterGraph_ConnectDirect(iface,pOut,pIn,NULL);
908         if ( hr == NOERROR )
909                 return NOERROR;
910
911         /* FIXME - try to connect indirectly. */
912         FIXME( "(%p)->(%p,%p) stub!\n",This,pOut,pIn );
913
914         info.pFilter = NULL;
915         hr = IPin_QueryPinInfo(pOut,&info);
916         if ( FAILED(hr) )
917                 return hr;
918         if ( info.pFilter == NULL )
919                 return E_FAIL;
920         hr = IBaseFilter_GetClassID(info.pFilter,&clsidOutFilter);
921         IBaseFilter_Release(info.pFilter);
922         if ( FAILED(hr) )
923                 return hr;
924
925         info.pFilter = NULL;
926         hr = IPin_QueryPinInfo(pIn,&info);
927         if ( FAILED(hr) )
928                 return hr;
929         if ( info.pFilter == NULL )
930                 return E_FAIL;
931         hr = IBaseFilter_GetClassID(info.pFilter,&clsidInFilter);
932         IBaseFilter_Release(info.pFilter);
933         if ( FAILED(hr) )
934                 return hr;
935
936         /* FIXME - try to connect with unused filters. */
937         /* FIXME - try to connect with cached filters. */
938         /* FIXME - enumerate transform filters and try to connect */
939         hr = CoCreateInstance(
940                 &CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
941                 &IID_IFilterMapper2, (void**)&pMap2 );
942         if ( FAILED(hr) )
943                 return hr;
944         hr = IFilterMapper2_EnumMatchingFilters(
945                 pMap2,&pEnumMon,0,FALSE,MERIT_DO_NOT_USE+1,
946                 TRUE,0,NULL,NULL,NULL,FALSE,
947                 TRUE,0,NULL,NULL,NULL);
948         IFilterMapper2_Release(pMap2);
949         if ( FAILED(hr) )
950                 return hr;
951         TRACE("try to connect indirectly\n");
952
953         if ( hr == S_OK )
954         {
955                 while ( !bConnected && hr == S_OK )
956                 {
957                         hr = IEnumMoniker_Next(pEnumMon,1,&pMon,&cReturned);
958                         if ( hr != S_OK )
959                                 break;
960                         hr = IMoniker_BindToObject(pMon,NULL,NULL,&IID_IBaseFilter,(void**)&pFilter );
961                         if ( hr == S_OK )
962                         {
963                                 hr = IBaseFilter_GetClassID(pFilter,&clsid);
964                                 if ( hr == S_OK &&
965                                          ( IsEqualGUID(&clsidOutFilter,&clsid) || IsEqualGUID(&clsidInFilter,&clsid) ) )
966                                         hr = S_FALSE;
967                                 else
968                                         hr = IFilterGraph2_AddFilter(iface,pFilter,NULL);
969                                 if ( hr == S_OK )
970                                 {
971                                         bTryConnect = FALSE;
972                                         hr = IBaseFilter_EnumPins(pFilter,&pEnumPin);
973                                         if ( hr == S_OK )
974                                         {
975                                                 {
976                                                         while ( !bTryConnect )
977                                                         {
978                                                                 hr = IEnumPins_Next(pEnumPin,1,&pPinTry,&cReturned);
979                                                                 if ( hr != S_OK )
980                                                                         break;
981                                                                 hr = IPin_QueryDirection(pPinTry,&pindir);
982                                                                 if ( hr == S_OK && pindir == PINDIR_INPUT )
983                                                                 {
984                                                                         /* try to connect directly. */
985                                                                         hr = IFilterGraph2_ConnectDirect(iface,pOut,pPinTry,NULL);
986                                                                         if ( hr == S_OK )
987                                                                                 bTryConnect = TRUE;
988                                                                         hr = S_OK;
989                                                                 }
990                                                                 IPin_Release(pPinTry); pPinTry = NULL;
991                                                         }
992                                                 }
993                                                 IEnumPins_Release(pEnumPin); pEnumPin = NULL;
994                                         }
995                                         TRACE("TryConnect %d\n",bTryConnect);
996
997                                         if ( bTryConnect )
998                                         {
999                                                 hr = IBaseFilter_EnumPins(pFilter,&pEnumPin);
1000                                                 if ( hr == S_OK )
1001                                                 {
1002                                                         while ( !bConnected )
1003                                                         {
1004                                                                 hr = IEnumPins_Next(pEnumPin,1,&pPinTry,&cReturned);
1005                                                                 if ( hr != S_OK )
1006                                                                         break;
1007                                                                 hr = IPin_QueryDirection(pPinTry,&pindir);
1008                                                                 if ( hr == S_OK && pindir == PINDIR_OUTPUT )
1009                                                                 {
1010                                                                         /* try to connect indirectly. */
1011                                                                         hr = IFilterGraph2_Connect(iface,pPinTry,pIn);
1012                                                                         if ( hr == S_OK )
1013                                                                                 bConnected = TRUE;
1014                                                                         hr = S_OK;
1015                                                                 }
1016                                                                 IPin_Release(pPinTry); pPinTry = NULL;
1017                                                         }
1018                                                         IEnumPins_Release(pEnumPin); pEnumPin = NULL;
1019                                                 }
1020                                         }
1021                                         if ( !bConnected )
1022                                                 hr = IFilterGraph2_RemoveFilter(iface,pFilter);
1023                                 }
1024                                 IBaseFilter_Release(pFilter); pFilter = NULL;
1025                                 if ( SUCCEEDED(hr) )
1026                                         hr = S_OK;
1027                         }
1028                         else
1029                         {
1030                                 hr = S_OK;
1031                         }
1032                         IMoniker_Release(pMon); pMon = NULL;
1033                 }
1034                 IEnumMoniker_Release(pEnumMon); pEnumMon = NULL;
1035         }
1036
1037         if ( SUCCEEDED(hr) && !bConnected )
1038                 hr = VFW_E_CANNOT_CONNECT;
1039
1040         return hr;
1041 }
1042
1043 static HRESULT WINAPI
1044 IFilterGraph2_fnRender(IFilterGraph2* iface,IPin* pOut)
1045 {
1046         CFilterGraph_THIS(iface,fgraph);
1047
1048         TRACE( "(%p)->(%p)\n",This,pOut);
1049
1050         return IFilterGraph2_RenderEx( CFilterGraph_IFilterGraph2(This), pOut, 0, NULL );
1051 }
1052
1053 static HRESULT WINAPI
1054 IFilterGraph2_fnRenderFile(IFilterGraph2* iface,LPCWSTR lpFileName,LPCWSTR lpPlayList)
1055 {
1056         CFilterGraph_THIS(iface,fgraph);
1057         HRESULT hr;
1058         IBaseFilter*    pFilter = NULL;
1059         IEnumPins*      pEnum = NULL;
1060         IPin*   pPin;
1061         ULONG   cFetched;
1062         PIN_DIRECTION   dir;
1063         ULONG   cTryToRender;
1064         ULONG   cActRender;
1065
1066         TRACE( "(%p)->(%s,%s)\n",This,
1067                 debugstr_w(lpFileName),debugstr_w(lpPlayList) );
1068
1069         if ( lpPlayList != NULL )
1070                 return E_INVALIDARG;
1071
1072         pFilter = NULL;
1073         hr = IFilterGraph2_AddSourceFilter(iface,lpFileName,NULL,&pFilter);
1074         if ( FAILED(hr) )
1075                 goto end;
1076         if ( pFilter == NULL )
1077         {
1078                 hr = E_FAIL;
1079                 goto end;
1080         }
1081         TRACE("(%p) source filter %p\n",This,pFilter);
1082
1083         pEnum = NULL;
1084         hr = IBaseFilter_EnumPins( pFilter, &pEnum );
1085         if ( FAILED(hr) )
1086                 goto end;
1087         if ( pEnum == NULL )
1088         {
1089                 hr = E_FAIL;
1090                 goto end;
1091         }
1092
1093         cTryToRender = 0;
1094         cActRender = 0;
1095
1096         while ( 1 )
1097         {
1098                 pPin = NULL;
1099                 cFetched = 0;
1100                 hr = IEnumPins_Next( pEnum, 1, &pPin, &cFetched );
1101                 if ( FAILED(hr) )
1102                         goto end;
1103                 if ( hr != NOERROR || pPin == NULL || cFetched != 1 )
1104                 {
1105                         hr = NOERROR;
1106                         break;
1107                 }
1108                 hr = IPin_QueryDirection( pPin, &dir );
1109                 if ( hr == NOERROR && dir == PINDIR_OUTPUT )
1110                 {
1111                         cTryToRender ++;
1112                         hr = IFilterGraph2_Render( iface, pPin );
1113                         if ( hr == NOERROR )
1114                                 cActRender ++;
1115                 }
1116                 IPin_Release( pPin );
1117         }
1118
1119         if ( hr == NOERROR )
1120         {
1121                 if ( cTryToRender > cActRender )
1122                         hr = VFW_S_PARTIAL_RENDER;
1123                 if ( cActRender == 0 )
1124                         hr = E_FAIL;
1125         }
1126
1127 end:
1128         if ( pEnum != NULL )
1129                 IEnumPins_Release( pEnum );
1130         if ( pFilter != NULL )
1131                 IBaseFilter_Release( pFilter );
1132
1133         return hr;
1134 }
1135
1136 static HRESULT WINAPI
1137 IFilterGraph2_fnAddSourceFilter(IFilterGraph2* iface,LPCWSTR lpFileName,LPCWSTR lpFilterName,IBaseFilter** ppBaseFilter)
1138 {
1139         CFilterGraph_THIS(iface,fgraph);
1140         HRESULT hr;
1141         BYTE    bStartData[512];
1142         DWORD   cbStartData;
1143         AM_MEDIA_TYPE   mt;
1144         CLSID   clsidSource;
1145         IFileSourceFilter*      pSource;
1146
1147         FIXME( "(%p)->(%s,%s,%p)\n",This,
1148                 debugstr_w(lpFileName),debugstr_w(lpFilterName),ppBaseFilter );
1149
1150         if ( lpFileName == NULL || ppBaseFilter == NULL )
1151                 return E_POINTER;
1152         *ppBaseFilter = NULL;
1153
1154         hr = QUARTZ_PeekFile( lpFileName, bStartData, 512, &cbStartData );
1155         if ( FAILED(hr) )
1156         {
1157                 FIXME("cannot open %s (NOTE: URL is not implemented)\n", debugstr_w(lpFileName));
1158                 return hr;
1159         }
1160         ZeroMemory( &mt, sizeof(AM_MEDIA_TYPE) );
1161         mt.bFixedSizeSamples = 1;
1162         mt.lSampleSize = 1;
1163         memcpy( &mt.majortype, &MEDIATYPE_Stream, sizeof(GUID) );
1164         memcpy( &mt.subtype, &MEDIASUBTYPE_NULL, sizeof(GUID) );
1165         memcpy( &mt.formattype, &FORMAT_None, sizeof(GUID) );
1166         hr = QUARTZ_GetSourceTypeFromData(
1167                 bStartData, cbStartData,
1168                 &mt.majortype, &mt.subtype, &clsidSource );
1169         if ( FAILED(hr) )
1170         {
1171                 ERR("QUARTZ_GetSourceTypeFromData() failed - return %08lx\n",hr);
1172                 return hr;
1173         }
1174         if ( hr != S_OK )
1175         {
1176                 FIXME( "file %s - unknown format\n", debugstr_w(lpFileName) );
1177                 return VFW_E_INVALID_FILE_FORMAT;
1178         }
1179
1180         hr = CoCreateInstance(
1181                 &clsidSource, NULL, CLSCTX_INPROC_SERVER,
1182                 &IID_IBaseFilter, (void**)ppBaseFilter );
1183         if ( FAILED(hr) )
1184                 return hr;
1185         hr = IBaseFilter_QueryInterface(*ppBaseFilter,&IID_IFileSourceFilter,(void**)&pSource);
1186         if ( SUCCEEDED(hr) )
1187         {
1188                 hr = IFileSourceFilter_Load(pSource,lpFileName,&mt);
1189                 IFileSourceFilter_Release(pSource);
1190         }
1191         if ( SUCCEEDED(hr) )
1192                 hr = IFilterGraph2_AddFilter(iface,*ppBaseFilter,lpFilterName);
1193         if ( FAILED(hr) )
1194         {
1195                 IBaseFilter_Release(*ppBaseFilter);
1196                 *ppBaseFilter = NULL;
1197                 return hr;
1198         }
1199
1200         return S_OK;
1201 }
1202
1203 static HRESULT WINAPI
1204 IFilterGraph2_fnSetLogFile(IFilterGraph2* iface,DWORD_PTR hFile)
1205 {
1206         CFilterGraph_THIS(iface,fgraph);
1207
1208         FIXME( "(%p)->() stub!\n", This );
1209
1210         return S_OK;    /* no debug output */
1211 }
1212
1213 static HRESULT WINAPI
1214 IFilterGraph2_fnAbort(IFilterGraph2* iface)
1215 {
1216         CFilterGraph_THIS(iface,fgraph);
1217
1218         FIXME( "(%p)->() stub!\n", This );
1219
1220         /* FIXME - abort the current asynchronous task. */
1221
1222         return S_OK;
1223 }
1224
1225 static HRESULT WINAPI
1226 IFilterGraph2_fnShouldOperationContinue(IFilterGraph2* iface)
1227 {
1228         CFilterGraph_THIS(iface,fgraph);
1229
1230         FIXME( "(%p)->() stub!\n", This );
1231
1232         return E_NOTIMPL;
1233 }
1234
1235 static HRESULT WINAPI
1236 IFilterGraph2_fnAddSourceFilterForMoniker(IFilterGraph2* iface,IMoniker* pMon,IBindCtx* pCtx,LPCWSTR pFilterName,IBaseFilter** ppFilter)
1237 {
1238         CFilterGraph_THIS(iface,fgraph);
1239
1240         FIXME( "(%p)->() stub!\n", This );
1241         return E_NOTIMPL;
1242 }
1243
1244 static HRESULT WINAPI
1245 IFilterGraph2_fnReconnectEx(IFilterGraph2* iface,IPin* pPin,const AM_MEDIA_TYPE* pmt)
1246 {
1247         CFilterGraph_THIS(iface,fgraph);
1248         HRESULT hr;
1249
1250         FIXME( "(%p)->(%p,%p) stub!\n",This,pPin,pmt );
1251
1252         /* reconnect asynchronously. */
1253
1254         EnterCriticalSection( &This->m_csFilters );
1255         hr = CFilterGraph_GraphChanged(This);
1256         LeaveCriticalSection( &This->m_csFilters );
1257
1258         return E_NOTIMPL;
1259 }
1260
1261 static HRESULT WINAPI
1262 IFilterGraph2_fnRenderEx(IFilterGraph2* iface,IPin* pOut,DWORD dwFlags,DWORD* pdwReserved)
1263 {
1264         CFilterGraph_THIS(iface,fgraph);
1265         HRESULT hr;
1266         IFilterMapper2* pMap2 = NULL;
1267         IEnumMoniker*   pEnumMon = NULL;
1268         IMoniker*       pMon = NULL;
1269         IBaseFilter*    pFilter = NULL;
1270         IEnumPins*      pEnumPin = NULL;
1271         IPin*   pPin = NULL;
1272         PIN_DIRECTION   pindir;
1273         BOOL    bRendered = FALSE;
1274         ULONG   cReturned;
1275
1276         FIXME( "(%p)->(%p,%08lx,%p) stub!\n",This,pPin,dwFlags,pdwReserved);
1277
1278         if ( pdwReserved != NULL )
1279                 return E_INVALIDARG;
1280
1281         if ( dwFlags != 0 )
1282         {
1283                 FIXME( "dwFlags != 0...\n" );
1284                 return E_INVALIDARG;
1285         }
1286
1287         /* FIXME - must be locked */
1288         /*EnterCriticalSection( &This->m_csFilters );*/
1289
1290         if ( pOut == NULL )
1291                 return E_POINTER;
1292
1293         hr = CoCreateInstance(
1294                 &CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
1295                 &IID_IFilterMapper2, (void**)&pMap2 );
1296         if ( FAILED(hr) )
1297                 return hr;
1298         hr = IFilterMapper2_EnumMatchingFilters(
1299                 pMap2,&pEnumMon,0,FALSE,MERIT_DO_NOT_USE+1,
1300                 TRUE,0,NULL,NULL,NULL,TRUE,
1301                 FALSE,0,NULL,NULL,NULL);
1302         IFilterMapper2_Release(pMap2);
1303         if ( FAILED(hr) )
1304                 return hr;
1305         TRACE("try to render pin\n");
1306
1307         if ( hr == S_OK )
1308         {
1309                 /* try to render pin. */
1310                 while ( !bRendered && hr == S_OK )
1311                 {
1312                         hr = IEnumMoniker_Next(pEnumMon,1,&pMon,&cReturned);
1313                         if ( hr != S_OK )
1314                                 break;
1315                         hr = IMoniker_BindToObject(pMon,NULL,NULL,&IID_IBaseFilter,(void**)&pFilter );
1316                         if ( hr == S_OK )
1317                         {
1318                                 hr = IFilterGraph2_AddFilter(iface,pFilter,NULL);
1319                                 if ( hr == S_OK )
1320                                 {
1321                                         hr = IBaseFilter_EnumPins(pFilter,&pEnumPin);
1322                                         if ( hr == S_OK )
1323                                         {
1324                                                 while ( !bRendered )
1325                                                 {
1326                                                         hr = IEnumPins_Next(pEnumPin,1,&pPin,&cReturned);
1327                                                         if ( hr != S_OK )
1328                                                                 break;
1329                                                         hr = IPin_QueryDirection(pPin,&pindir);
1330                                                         if ( hr == S_OK && pindir == PINDIR_INPUT )
1331                                                         {
1332                                                                 /* try to connect. */
1333                                                                 hr = IFilterGraph2_Connect(iface,pOut,pPin);
1334                                                                 if ( hr == S_OK )
1335                                                                         bRendered = TRUE;
1336                                                                 hr = S_OK;
1337                                                         }
1338                                                         IPin_Release(pPin); pPin = NULL;
1339                                                 }
1340                                                 IEnumPins_Release(pEnumPin); pEnumPin = NULL;
1341                                         }
1342                                         if ( !bRendered )
1343                                                 hr = IFilterGraph2_RemoveFilter(iface,pFilter);
1344                                 }
1345                                 IBaseFilter_Release(pFilter); pFilter = NULL;
1346                                 if ( SUCCEEDED(hr) )
1347                                         hr = S_OK;
1348                         }
1349                         else
1350                         {
1351                                 hr = S_OK;
1352                         }
1353                         IMoniker_Release(pMon); pMon = NULL;
1354                 }
1355                 IEnumMoniker_Release(pEnumMon); pEnumMon = NULL;
1356         }
1357
1358         if ( bRendered )
1359         {
1360                 /* successfully rendered(but may be partial now) */
1361                 hr = S_OK;
1362
1363                 /* FIXME - try to render all inserted filters. */
1364                 /* hr = VFW_S_PARTIAL_RENDER; */
1365         }
1366         else
1367         {
1368                 if ( SUCCEEDED(hr) )
1369                         hr = VFW_E_CANNOT_RENDER;
1370         }
1371
1372         /*LeaveCriticalSection( &This->m_csFilters );*/
1373
1374         return hr;
1375 }
1376
1377
1378
1379
1380 static ICOM_VTABLE(IFilterGraph2) ifgraph =
1381 {
1382         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1383         /* IUnknown fields */
1384         IFilterGraph2_fnQueryInterface,
1385         IFilterGraph2_fnAddRef,
1386         IFilterGraph2_fnRelease,
1387         /* IFilterGraph fields */
1388         IFilterGraph2_fnAddFilter,
1389         IFilterGraph2_fnRemoveFilter,
1390         IFilterGraph2_fnEnumFilters,
1391         IFilterGraph2_fnFindFilterByName,
1392         IFilterGraph2_fnConnectDirect,
1393         IFilterGraph2_fnReconnect,
1394         IFilterGraph2_fnDisconnect,
1395         IFilterGraph2_fnSetDefaultSyncSource,
1396         /* IGraphBuilder fields */
1397         IFilterGraph2_fnConnect,
1398         IFilterGraph2_fnRender,
1399         IFilterGraph2_fnRenderFile,
1400         IFilterGraph2_fnAddSourceFilter,
1401         IFilterGraph2_fnSetLogFile,
1402         IFilterGraph2_fnAbort,
1403         IFilterGraph2_fnShouldOperationContinue,
1404         /* IFilterGraph2 fields */
1405         IFilterGraph2_fnAddSourceFilterForMoniker,
1406         IFilterGraph2_fnReconnectEx,
1407         IFilterGraph2_fnRenderEx,
1408 };
1409
1410 HRESULT CFilterGraph_InitIFilterGraph2( CFilterGraph* pfg )
1411 {
1412         TRACE("(%p)\n",pfg);
1413         ICOM_VTBL(&pfg->fgraph) = &ifgraph;
1414
1415         InitializeCriticalSection( &pfg->m_csFilters );
1416         pfg->m_cActiveFilters = 0;
1417         pfg->m_pActiveFilters = NULL;
1418
1419         return NOERROR;
1420 }
1421
1422 void CFilterGraph_UninitIFilterGraph2( CFilterGraph* pfg )
1423 {
1424         TRACE("(%p)\n",pfg);
1425
1426         /* remove all filters... */
1427         while ( pfg->m_cActiveFilters > 0 )
1428         {
1429                 IFilterGraph2_RemoveFilter(
1430                         CFilterGraph_IFilterGraph2(pfg),
1431                         pfg->m_pActiveFilters[pfg->m_cActiveFilters-1].pFilter );
1432         }
1433
1434         if ( pfg->m_pActiveFilters != NULL )
1435                 QUARTZ_FreeMem( pfg->m_pActiveFilters );
1436
1437         DeleteCriticalSection( &pfg->m_csFilters );
1438 }
1439
1440 /***************************************************************************
1441  *
1442  *      CFilterGraph::IGraphVersion methods
1443  *
1444  */
1445
1446 static HRESULT WINAPI
1447 IGraphVersion_fnQueryInterface(IGraphVersion* iface,REFIID riid,void** ppobj)
1448 {
1449         CFilterGraph_THIS(iface,graphversion);
1450
1451         TRACE("(%p)->()\n",This);
1452
1453         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
1454 }
1455
1456 static ULONG WINAPI
1457 IGraphVersion_fnAddRef(IGraphVersion* iface)
1458 {
1459         CFilterGraph_THIS(iface,graphversion);
1460
1461         TRACE("(%p)->()\n",This);
1462
1463         return IUnknown_AddRef(This->unk.punkControl);
1464 }
1465
1466 static ULONG WINAPI
1467 IGraphVersion_fnRelease(IGraphVersion* iface)
1468 {
1469         CFilterGraph_THIS(iface,graphversion);
1470
1471         TRACE("(%p)->()\n",This);
1472
1473         return IUnknown_Release(This->unk.punkControl);
1474 }
1475
1476
1477 static HRESULT WINAPI
1478 IGraphVersion_fnQueryVersion(IGraphVersion* iface,LONG* plVersion)
1479 {
1480         CFilterGraph_THIS(iface,graphversion);
1481
1482         TRACE("(%p)->(%p)\n",This,plVersion);
1483
1484         if ( plVersion == NULL )
1485                 return E_POINTER;
1486
1487         EnterCriticalSection( &This->m_csFilters );
1488         *plVersion = This->m_lGraphVersion;
1489         LeaveCriticalSection( &This->m_csFilters );
1490
1491         return NOERROR;
1492 }
1493
1494
1495 static ICOM_VTABLE(IGraphVersion) igraphversion =
1496 {
1497         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1498         /* IUnknown fields */
1499         IGraphVersion_fnQueryInterface,
1500         IGraphVersion_fnAddRef,
1501         IGraphVersion_fnRelease,
1502         /* IGraphVersion fields */
1503         IGraphVersion_fnQueryVersion,
1504 };
1505
1506
1507
1508 HRESULT CFilterGraph_InitIGraphVersion( CFilterGraph* pfg )
1509 {
1510         TRACE("(%p)\n",pfg);
1511         ICOM_VTBL(&pfg->graphversion) = &igraphversion;
1512
1513         pfg->m_lGraphVersion = 1;
1514
1515         return NOERROR;
1516 }
1517
1518 void CFilterGraph_UninitIGraphVersion( CFilterGraph* pfg )
1519 {
1520         TRACE("(%p)\n",pfg);
1521 }
1522
1523 /***************************************************************************
1524  *
1525  *      CFilterGraph::IGraphConfig methods
1526  *
1527  */
1528
1529 static HRESULT WINAPI
1530 IGraphConfig_fnQueryInterface(IGraphConfig* iface,REFIID riid,void** ppobj)
1531 {
1532         CFilterGraph_THIS(iface,grphconf);
1533
1534         TRACE("(%p)->()\n",This);
1535
1536         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
1537 }
1538
1539 static ULONG WINAPI
1540 IGraphConfig_fnAddRef(IGraphConfig* iface)
1541 {
1542         CFilterGraph_THIS(iface,grphconf);
1543
1544         TRACE("(%p)->()\n",This);
1545
1546         return IUnknown_AddRef(This->unk.punkControl);
1547 }
1548
1549 static ULONG WINAPI
1550 IGraphConfig_fnRelease(IGraphConfig* iface)
1551 {
1552         CFilterGraph_THIS(iface,grphconf);
1553
1554         TRACE("(%p)->()\n",This);
1555
1556         return IUnknown_Release(This->unk.punkControl);
1557 }
1558
1559
1560
1561 static HRESULT WINAPI
1562 IGraphConfig_fnReconnect(IGraphConfig* iface,IPin* pOut,IPin* pIn,const AM_MEDIA_TYPE* pmt,IBaseFilter* pFilter,HANDLE hAbort,DWORD dwFlags)
1563 {
1564         CFilterGraph_THIS(iface,grphconf);
1565
1566         FIXME("(%p)->() stub!\n",This);
1567
1568         return E_NOTIMPL;
1569 }
1570
1571 static HRESULT WINAPI
1572 IGraphConfig_fnReconfigure(IGraphConfig* iface,IGraphConfigCallback* pCallback,PVOID pvParam,DWORD dwFlags,HANDLE hAbort)
1573 {
1574         CFilterGraph_THIS(iface,grphconf);
1575         HRESULT hr;
1576
1577         FIXME("(%p)->(%p,%p,%08lx,%08x) stub!\n",This,pCallback,pvParam,dwFlags,hAbort);
1578
1579         EnterCriticalSection( &This->m_csFilters );
1580         EnterCriticalSection( &This->m_csGraphState );
1581
1582         hr = IGraphConfigCallback_Reconfigure(pCallback,pvParam,dwFlags);
1583
1584         LeaveCriticalSection( &This->m_csGraphState );
1585         LeaveCriticalSection( &This->m_csFilters );
1586
1587         return hr;
1588 }
1589
1590 static HRESULT WINAPI
1591 IGraphConfig_fnAddFilterToCache(IGraphConfig* iface,IBaseFilter* pFilter)
1592 {
1593         CFilterGraph_THIS(iface,grphconf);
1594
1595         FIXME("(%p)->() stub!\n",This);
1596
1597         return E_NOTIMPL;
1598 }
1599
1600 static HRESULT WINAPI
1601 IGraphConfig_fnEnumCacheFilter(IGraphConfig* iface,IEnumFilters** ppenum)
1602 {
1603         CFilterGraph_THIS(iface,grphconf);
1604
1605         FIXME("(%p)->() stub!\n",This);
1606
1607         return E_NOTIMPL;
1608 }
1609
1610 static HRESULT WINAPI
1611 IGraphConfig_fnRemoveFilterFromCache(IGraphConfig* iface,IBaseFilter* pFilter)
1612 {
1613         CFilterGraph_THIS(iface,grphconf);
1614
1615         FIXME("(%p)->() stub!\n",This);
1616
1617         return E_NOTIMPL;
1618 }
1619
1620 static HRESULT WINAPI
1621 IGraphConfig_fnGetStartTime(IGraphConfig* iface,REFERENCE_TIME* prt)
1622 {
1623         CFilterGraph_THIS(iface,grphconf);
1624
1625         FIXME("(%p)->() stub!\n",This);
1626
1627         return E_NOTIMPL;
1628 }
1629
1630 static HRESULT WINAPI
1631 IGraphConfig_fnPushThroughData(IGraphConfig* iface,IPin* pOut,IPinConnection* pConn,HANDLE hAbort)
1632 {
1633         CFilterGraph_THIS(iface,grphconf);
1634
1635         FIXME("(%p)->() stub!\n",This);
1636
1637         return E_NOTIMPL;
1638 }
1639
1640 static HRESULT WINAPI
1641 IGraphConfig_fnSetFilterFlags(IGraphConfig* iface,IBaseFilter* pFilter,DWORD dwFlags)
1642 {
1643         CFilterGraph_THIS(iface,grphconf);
1644
1645         FIXME("(%p)->() stub!\n",This);
1646
1647         return E_NOTIMPL;
1648 }
1649
1650 static HRESULT WINAPI
1651 IGraphConfig_fnGetFilterFlags(IGraphConfig* iface,IBaseFilter* pFilter,DWORD* pdwFlags)
1652 {
1653         CFilterGraph_THIS(iface,grphconf);
1654
1655         FIXME("(%p)->() stub!\n",This);
1656
1657         return E_NOTIMPL;
1658 }
1659
1660 static HRESULT WINAPI
1661 IGraphConfig_fnRemoveFilterEx(IGraphConfig* iface,IBaseFilter* pFilter,DWORD dwFlags)
1662 {
1663         CFilterGraph_THIS(iface,grphconf);
1664
1665         FIXME("(%p)->() stub!\n",This);
1666
1667         return E_NOTIMPL;
1668 }
1669
1670
1671
1672
1673
1674 static ICOM_VTABLE(IGraphConfig) igraphconfig =
1675 {
1676         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1677         /* IUnknown fields */
1678         IGraphConfig_fnQueryInterface,
1679         IGraphConfig_fnAddRef,
1680         IGraphConfig_fnRelease,
1681         /* IGraphConfig fields */
1682         IGraphConfig_fnReconnect,
1683         IGraphConfig_fnReconfigure,
1684         IGraphConfig_fnAddFilterToCache,
1685         IGraphConfig_fnEnumCacheFilter,
1686         IGraphConfig_fnRemoveFilterFromCache,
1687         IGraphConfig_fnGetStartTime,
1688         IGraphConfig_fnPushThroughData,
1689         IGraphConfig_fnSetFilterFlags,
1690         IGraphConfig_fnGetFilterFlags,
1691         IGraphConfig_fnRemoveFilterEx,
1692 };
1693
1694
1695
1696 HRESULT CFilterGraph_InitIGraphConfig( CFilterGraph* pfg )
1697 {
1698         TRACE("(%p)\n",pfg);
1699         ICOM_VTBL(&pfg->grphconf) = &igraphconfig;
1700
1701         return NOERROR;
1702 }
1703
1704 void CFilterGraph_UninitIGraphConfig( CFilterGraph* pfg )
1705 {
1706         TRACE("(%p)\n",pfg);
1707 }
1708
1709