winealsa: Map ALSA errors to AUDCLNT_E_*.
[wine] / dlls / quartz / filtergraph.c
1 /*              DirectShow FilterGraph object (QUARTZ.DLL)
2  *
3  * Copyright 2002 Lionel Ulmer
4  * Copyright 2004 Christian Costa
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include <stdarg.h>
23
24 #define COBJMACROS
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winreg.h"
30 #include "shlwapi.h"
31 #include "dshow.h"
32 #include "wine/debug.h"
33 #include "quartz_private.h"
34 #include "ole2.h"
35 #include "olectl.h"
36 #include "strmif.h"
37 #include "vfwmsgs.h"
38 #include "evcode.h"
39 #include "wine/unicode.h"
40
41
42 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
43
44 typedef struct {
45     HWND     hWnd;      /* Target window */
46     UINT     msg;       /* User window message */
47     LONG_PTR instance;  /* User data */
48     int      disabled;  /* Disabled messages posting */
49 } WndNotify;
50
51 typedef struct {
52     LONG lEventCode;   /* Event code */
53     LONG_PTR lParam1;  /* Param1 */
54     LONG_PTR lParam2;  /* Param2 */
55 } Event;
56
57 /* messages ring implementation for queuing events (taken from winmm) */
58 #define EVENTS_RING_BUFFER_INCREMENT      64
59 typedef struct {
60     Event* messages;
61     int ring_buffer_size;
62     int msg_tosave;
63     int msg_toget;
64     CRITICAL_SECTION msg_crst;
65     HANDLE msg_event; /* Signaled for no empty queue */
66 } EventsQueue;
67
68 static int EventsQueue_Init(EventsQueue* omr)
69 {
70     omr->msg_toget = 0;
71     omr->msg_tosave = 0;
72     omr->msg_event = CreateEventW(NULL, TRUE, FALSE, NULL);
73     omr->ring_buffer_size = EVENTS_RING_BUFFER_INCREMENT;
74     omr->messages = CoTaskMemAlloc(omr->ring_buffer_size * sizeof(Event));
75     ZeroMemory(omr->messages, omr->ring_buffer_size * sizeof(Event));
76
77     InitializeCriticalSection(&omr->msg_crst);
78     omr->msg_crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": EventsQueue.msg_crst");
79     return TRUE;
80 }
81
82 static int EventsQueue_Destroy(EventsQueue* omr)
83 {
84     CloseHandle(omr->msg_event);
85     CoTaskMemFree(omr->messages);
86     omr->msg_crst.DebugInfo->Spare[0] = 0;
87     DeleteCriticalSection(&omr->msg_crst);
88     return TRUE;
89 }
90
91 static int EventsQueue_PutEvent(EventsQueue* omr, const Event* evt)
92 {
93     EnterCriticalSection(&omr->msg_crst);
94     if (omr->msg_toget == ((omr->msg_tosave + 1) % omr->ring_buffer_size))
95     {
96         int old_ring_buffer_size = omr->ring_buffer_size;
97         omr->ring_buffer_size += EVENTS_RING_BUFFER_INCREMENT;
98         TRACE("omr->ring_buffer_size=%d\n",omr->ring_buffer_size);
99         omr->messages = CoTaskMemRealloc(omr->messages, omr->ring_buffer_size * sizeof(Event));
100         /* Now we need to rearrange the ring buffer so that the new
101            buffers just allocated are in between omr->msg_tosave and
102            omr->msg_toget.
103         */
104         if (omr->msg_tosave < omr->msg_toget)
105         {
106             memmove(&(omr->messages[omr->msg_toget + EVENTS_RING_BUFFER_INCREMENT]),
107                     &(omr->messages[omr->msg_toget]),
108                     sizeof(Event)*(old_ring_buffer_size - omr->msg_toget)
109                     );
110             omr->msg_toget += EVENTS_RING_BUFFER_INCREMENT;
111         }
112     }
113     omr->messages[omr->msg_tosave] = *evt;
114     SetEvent(omr->msg_event);
115     omr->msg_tosave = (omr->msg_tosave + 1) % omr->ring_buffer_size;
116     LeaveCriticalSection(&omr->msg_crst);
117     return TRUE;
118 }
119
120 static int EventsQueue_GetEvent(EventsQueue* omr, Event* evt, LONG msTimeOut)
121 {
122     if (WaitForSingleObject(omr->msg_event, msTimeOut) != WAIT_OBJECT_0)
123         return FALSE;
124         
125     EnterCriticalSection(&omr->msg_crst);
126
127     if (omr->msg_toget == omr->msg_tosave) /* buffer empty ? */
128     {
129         LeaveCriticalSection(&omr->msg_crst);
130         return FALSE;
131     }
132
133     *evt = omr->messages[omr->msg_toget];
134     omr->msg_toget = (omr->msg_toget + 1) % omr->ring_buffer_size;
135
136     /* Mark the buffer as empty if needed */
137     if (omr->msg_toget == omr->msg_tosave) /* buffer empty ? */
138         ResetEvent(omr->msg_event);
139
140     LeaveCriticalSection(&omr->msg_crst);
141     return TRUE;
142 }
143
144 #define MAX_ITF_CACHE_ENTRIES 3
145 typedef struct _ITF_CACHE_ENTRY {
146    const IID* riid;
147    IBaseFilter* filter;
148    IUnknown* iface;
149 } ITF_CACHE_ENTRY;
150
151 typedef struct _IFilterGraphImpl {
152     IFilterGraph2 IFilterGraph2_iface;
153     IMediaControl IMediaControl_iface;
154     IMediaSeeking IMediaSeeking_iface;
155     IBasicAudio IBasicAudio_iface;
156     IBasicVideo2 IBasicVideo2_iface;
157     IVideoWindow IVideoWindow_iface;
158     IMediaEventEx IMediaEventEx_iface;
159     IMediaFilter IMediaFilter_iface;
160     IMediaEventSink IMediaEventSink_iface;
161     IGraphConfig IGraphConfig_iface;
162     IMediaPosition IMediaPosition_iface;
163     IObjectWithSite IObjectWithSite_iface;
164     const IUnknownVtbl * IInner_vtbl;
165     /* IAMGraphStreams */
166     /* IAMStats */
167     /* IFilterChain */
168     /* IFilterMapper2 */
169     /* IGraphVersion */
170     /* IQueueCommand */
171     /* IRegisterServiceProvider */
172     /* IResourceMananger */
173     /* IServiceProvider */
174     /* IVideoFrameStep */
175
176     LONG ref;
177     IUnknown *punkFilterMapper2;
178     IFilterMapper2 * pFilterMapper2;
179     IBaseFilter ** ppFiltersInGraph;
180     LPWSTR * pFilterNames;
181     int nFilters;
182     int filterCapacity;
183     LONG nameIndex;
184     IReferenceClock *refClock;
185     IBaseFilter *refClockProvider;
186     EventsQueue evqueue;
187     HANDLE hEventCompletion;
188     int CompletionStatus;
189     WndNotify notif;
190     int nRenderers;
191     int EcCompleteCount;
192     int HandleEcComplete;
193     int HandleEcRepaint;
194     int HandleEcClockChanged;
195     OAFilterState state;
196     CRITICAL_SECTION cs;
197     ITF_CACHE_ENTRY ItfCacheEntries[MAX_ITF_CACHE_ENTRIES];
198     int nItfCacheEntries;
199     IUnknown * pUnkOuter;
200     BOOL bUnkOuterValid;
201     BOOL bAggregatable;
202     BOOL defaultclock;
203     GUID timeformatseek;
204     REFERENCE_TIME start_time;
205     REFERENCE_TIME pause_time;
206     LONGLONG stop_position;
207     LONG recursioncount;
208     IUnknown *pSite;
209 } IFilterGraphImpl;
210
211 static HRESULT Filtergraph_QueryInterface(IFilterGraphImpl *This,
212                                           REFIID riid, LPVOID * ppv);
213 static ULONG Filtergraph_AddRef(IFilterGraphImpl *This);
214 static ULONG Filtergraph_Release(IFilterGraphImpl *This);
215
216 static HRESULT WINAPI FilterGraphInner_QueryInterface(IUnknown * iface,
217                                           REFIID riid,
218                                           LPVOID *ppvObj) {
219     ICOM_THIS_MULTI(IFilterGraphImpl, IInner_vtbl, iface);
220     TRACE("(%p)->(%s (%p), %p)\n", This, debugstr_guid(riid), riid, ppvObj);
221     
222     if (This->bAggregatable)
223         This->bUnkOuterValid = TRUE;
224
225     if (IsEqualGUID(&IID_IUnknown, riid)) {
226         *ppvObj = &(This->IInner_vtbl);
227         TRACE("   returning IUnknown interface (%p)\n", *ppvObj);
228     } else if (IsEqualGUID(&IID_IFilterGraph, riid) ||
229         IsEqualGUID(&IID_IFilterGraph2, riid) ||
230         IsEqualGUID(&IID_IGraphBuilder, riid)) {
231         *ppvObj = &This->IFilterGraph2_iface;
232         TRACE("   returning IGraphBuilder interface (%p)\n", *ppvObj);
233     } else if (IsEqualGUID(&IID_IMediaControl, riid)) {
234         *ppvObj = &This->IMediaControl_iface;
235         TRACE("   returning IMediaControl interface (%p)\n", *ppvObj);
236     } else if (IsEqualGUID(&IID_IMediaSeeking, riid)) {
237         *ppvObj = &This->IMediaSeeking_iface;
238         TRACE("   returning IMediaSeeking interface (%p)\n", *ppvObj);
239     } else if (IsEqualGUID(&IID_IBasicAudio, riid)) {
240         *ppvObj = &This->IBasicAudio_iface;
241         TRACE("   returning IBasicAudio interface (%p)\n", *ppvObj);
242     } else if (IsEqualGUID(&IID_IBasicVideo, riid) ||
243                IsEqualGUID(&IID_IBasicVideo2, riid)) {
244         *ppvObj = &This->IBasicVideo2_iface;
245         TRACE("   returning IBasicVideo2 interface (%p)\n", *ppvObj);
246     } else if (IsEqualGUID(&IID_IVideoWindow, riid)) {
247         *ppvObj = &This->IVideoWindow_iface;
248         TRACE("   returning IVideoWindow interface (%p)\n", *ppvObj);
249     } else if (IsEqualGUID(&IID_IMediaEvent, riid) ||
250            IsEqualGUID(&IID_IMediaEventEx, riid)) {
251         *ppvObj = &This->IMediaEventEx_iface;
252         TRACE("   returning IMediaEvent(Ex) interface (%p)\n", *ppvObj);
253     } else if (IsEqualGUID(&IID_IMediaFilter, riid) ||
254           IsEqualGUID(&IID_IPersist, riid)) {
255         *ppvObj = &This->IMediaFilter_iface;
256         TRACE("   returning IMediaFilter interface (%p)\n", *ppvObj);
257     } else if (IsEqualGUID(&IID_IMediaEventSink, riid)) {
258         *ppvObj = &This->IMediaEventSink_iface;
259         TRACE("   returning IMediaEventSink interface (%p)\n", *ppvObj);
260     } else if (IsEqualGUID(&IID_IGraphConfig, riid)) {
261         *ppvObj = &This->IGraphConfig_iface;
262         TRACE("   returning IGraphConfig interface (%p)\n", *ppvObj);
263     } else if (IsEqualGUID(&IID_IMediaPosition, riid)) {
264         *ppvObj = &This->IMediaPosition_iface;
265         TRACE("   returning IMediaPosition interface (%p)\n", *ppvObj);
266     } else if (IsEqualGUID(&IID_IObjectWithSite, riid)) {
267         *ppvObj = &This->IObjectWithSite_iface;
268         TRACE("   returning IObjectWithSite interface (%p)\n", *ppvObj);
269     } else if (IsEqualGUID(&IID_IFilterMapper, riid)) {
270         TRACE("   requesting IFilterMapper interface from aggregated filtermapper (%p)\n", *ppvObj);
271         return IUnknown_QueryInterface(This->punkFilterMapper2, riid, ppvObj);
272     } else if (IsEqualGUID(&IID_IFilterMapper2, riid)) {
273         *ppvObj = This->pFilterMapper2;
274         TRACE("   returning IFilterMapper2 interface from aggregated filtermapper (%p)\n", *ppvObj);
275     } else if (IsEqualGUID(&IID_IFilterMapper3, riid)) {
276         *ppvObj = This->pFilterMapper2;
277         TRACE("   returning IFilterMapper3 interface from aggregated filtermapper (%p)\n", *ppvObj);
278     } else {
279         *ppvObj = NULL;
280         FIXME("unknown interface %s\n", debugstr_guid(riid));
281         return E_NOINTERFACE;
282     }
283
284     IUnknown_AddRef((IUnknown *)(*ppvObj));
285     return S_OK;
286 }
287
288 static ULONG WINAPI FilterGraphInner_AddRef(IUnknown * iface) {
289     ICOM_THIS_MULTI(IFilterGraphImpl, IInner_vtbl, iface);
290     ULONG ref = InterlockedIncrement(&This->ref);
291
292     TRACE("(%p)->(): new ref = %d\n", This, ref);
293     
294     return ref;
295 }
296
297 static ULONG WINAPI FilterGraphInner_Release(IUnknown * iface)
298 {
299     ICOM_THIS_MULTI(IFilterGraphImpl, IInner_vtbl, iface);
300     ULONG ref = InterlockedDecrement(&This->ref);
301
302     TRACE("(%p)->(): new ref = %d\n", This, ref);
303
304     if (ref == 0) {
305         int i;
306
307         This->ref = 1; /* guard against reentrancy (aggregation). */
308
309         IMediaControl_Stop(&This->IMediaControl_iface);
310
311         while (This->nFilters)
312             IFilterGraph2_RemoveFilter((IFilterGraph2*)This, This->ppFiltersInGraph[0]);
313
314         if (This->refClock)
315             IReferenceClock_Release(This->refClock);
316
317         for (i = 0; i < This->nItfCacheEntries; i++)
318         {
319             if (This->ItfCacheEntries[i].iface)
320                 IUnknown_Release(This->ItfCacheEntries[i].iface);
321         }
322
323         /* AddRef on controlling IUnknown, to compensate for Release of cached IFilterMapper2 interface below.
324
325          * NOTE: Filtergraph_AddRef isn't suitable, because bUnkOuterValid may be FALSE but punkOuter non-NULL
326          * and already passed as punkOuter to filtermapper in FilterGraph_create - this will happen in case of
327          * CoCreateInstance of filtergraph with non-null pUnkOuter and REFIID other than IID_Unknown that is
328          * cleaning up after error. */
329         if (This->pUnkOuter) IUnknown_AddRef(This->pUnkOuter);
330         else IUnknown_AddRef((IUnknown*)&This->IInner_vtbl);
331
332         IFilterMapper2_Release(This->pFilterMapper2);
333         IUnknown_Release(This->punkFilterMapper2);
334
335         if (This->pSite) IUnknown_Release(This->pSite);
336
337         CloseHandle(This->hEventCompletion);
338         EventsQueue_Destroy(&This->evqueue);
339         This->cs.DebugInfo->Spare[0] = 0;
340         DeleteCriticalSection(&This->cs);
341         CoTaskMemFree(This->ppFiltersInGraph);
342         CoTaskMemFree(This->pFilterNames);
343         CoTaskMemFree(This);
344     }
345     return ref;
346 }
347
348 static inline IFilterGraphImpl *impl_from_IFilterGraph2(IFilterGraph2 *iface)
349 {
350     return CONTAINING_RECORD(iface, IFilterGraphImpl, IFilterGraph2_iface);
351 }
352
353 static HRESULT WINAPI FilterGraph2_QueryInterface(IFilterGraph2 *iface, REFIID riid, void **ppvObj)
354 {
355     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
356
357     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
358
359     return Filtergraph_QueryInterface(This, riid, ppvObj);
360 }
361
362 static ULONG WINAPI FilterGraph2_AddRef(IFilterGraph2 *iface)
363 {
364     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
365
366     TRACE("(%p/%p)->() calling FilterGraph AddRef\n", This, iface);
367
368     return Filtergraph_AddRef(This);
369 }
370
371 static ULONG WINAPI FilterGraph2_Release(IFilterGraph2 *iface)
372 {
373     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
374
375     TRACE("(%p/%p)->() calling FilterGraph Release\n", This, iface);
376
377     return Filtergraph_Release(This);
378 }
379
380 /*** IFilterGraph methods ***/
381 static HRESULT WINAPI FilterGraph2_AddFilter(IFilterGraph2 *iface, IBaseFilter *pFilter,
382         LPCWSTR pName)
383 {
384     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
385     HRESULT hr;
386     int i,j;
387     WCHAR* wszFilterName = NULL;
388     int duplicate_name = FALSE;
389
390     TRACE("(%p/%p)->(%p, %s (%p))\n", This, iface, pFilter, debugstr_w(pName), pName);
391
392     if (!pFilter)
393         return E_POINTER;
394
395     wszFilterName = CoTaskMemAlloc( (pName ? strlenW(pName) + 6 : 5) * sizeof(WCHAR) );
396
397     if (pName)
398     {
399         /* Check if name already exists */
400         for(i = 0; i < This->nFilters; i++)
401             if (!strcmpW(This->pFilterNames[i], pName))
402             {
403                 duplicate_name = TRUE;
404                 break;
405             }
406     }
407
408     /* If no name given or name already existing, generate one */
409     if (!pName || duplicate_name)
410     {
411         static const WCHAR wszFmt1[] = {'%','s',' ','%','0','4','d',0};
412         static const WCHAR wszFmt2[] = {'%','0','4','d',0};
413
414         for (j = 0; j < 10000 ; j++)
415         {
416             /* Create name */
417             if (pName)
418                 sprintfW(wszFilterName, wszFmt1, pName, This->nameIndex);
419             else
420                 sprintfW(wszFilterName, wszFmt2, This->nameIndex);
421             TRACE("Generated name %s\n", debugstr_w(wszFilterName));
422
423             /* Check if the generated name already exists */
424             for(i = 0; i < This->nFilters; i++)
425                 if (!strcmpW(This->pFilterNames[i], wszFilterName))
426                     break;
427
428             /* Compute next index and exit if generated name is suitable */
429             if (This->nameIndex++ == 10000)
430                 This->nameIndex = 1;
431             if (i == This->nFilters)
432                 break;
433         }
434         /* Unable to find a suitable name */
435         if (j == 10000)
436         {
437             CoTaskMemFree(wszFilterName);
438             return VFW_E_DUPLICATE_NAME;
439         }
440     }
441     else
442         memcpy(wszFilterName, pName, (strlenW(pName) + 1) * sizeof(WCHAR));
443
444     if (This->nFilters + 1 > This->filterCapacity)
445     {
446         int newCapacity = This->filterCapacity ? 2 * This->filterCapacity : 1;
447         IBaseFilter ** ppNewFilters = CoTaskMemAlloc(newCapacity * sizeof(IBaseFilter*));
448         LPWSTR * pNewNames = CoTaskMemAlloc(newCapacity * sizeof(LPWSTR));
449         memcpy(ppNewFilters, This->ppFiltersInGraph, This->nFilters * sizeof(IBaseFilter*));
450         memcpy(pNewNames, This->pFilterNames, This->nFilters * sizeof(LPWSTR));
451         if (This->filterCapacity)
452         {
453             CoTaskMemFree(This->ppFiltersInGraph);
454             CoTaskMemFree(This->pFilterNames);
455         }
456         This->ppFiltersInGraph = ppNewFilters;
457         This->pFilterNames = pNewNames;
458         This->filterCapacity = newCapacity;
459     }
460
461     hr = IBaseFilter_JoinFilterGraph(pFilter, (IFilterGraph *)This, wszFilterName);
462
463     if (SUCCEEDED(hr))
464     {
465         IBaseFilter_AddRef(pFilter);
466         This->ppFiltersInGraph[This->nFilters] = pFilter;
467         This->pFilterNames[This->nFilters] = wszFilterName;
468         This->nFilters++;
469         IBaseFilter_SetSyncSource(pFilter, This->refClock);
470     }
471     else
472         CoTaskMemFree(wszFilterName);
473
474     if (SUCCEEDED(hr) && duplicate_name)
475         return VFW_S_DUPLICATE_NAME;
476         
477     return hr;
478 }
479
480 static HRESULT WINAPI FilterGraph2_RemoveFilter(IFilterGraph2 *iface, IBaseFilter *pFilter)
481 {
482     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
483     int i;
484     HRESULT hr = E_FAIL;
485
486     TRACE("(%p/%p)->(%p)\n", This, iface, pFilter);
487
488     /* FIXME: check graph is stopped */
489
490     for (i = 0; i < This->nFilters; i++)
491     {
492         if (This->ppFiltersInGraph[i] == pFilter)
493         {
494             IEnumPins *penumpins = NULL;
495             FILTER_STATE state;
496
497             if (This->defaultclock && This->refClockProvider == pFilter)
498             {
499                 IMediaFilter_SetSyncSource(&This->IMediaFilter_iface, NULL);
500                 This->defaultclock = 1;
501             }
502
503             TRACE("Removing filter %s\n", debugstr_w(This->pFilterNames[i]));
504             IBaseFilter_GetState(pFilter, 0, &state);
505             if (state == State_Running)
506                 IBaseFilter_Pause(pFilter);
507             if (state != State_Stopped)
508                 IBaseFilter_Stop(pFilter);
509
510             hr = IBaseFilter_EnumPins(pFilter, &penumpins);
511             if (SUCCEEDED(hr)) {
512                 IPin *ppin;
513                 while(IEnumPins_Next(penumpins, 1, &ppin, NULL) == S_OK)
514                 {
515                     IPin *victim = NULL;
516                     HRESULT h;
517                     IPin_ConnectedTo(ppin, &victim);
518                     if (victim)
519                     {
520                         h = IPin_Disconnect(victim);
521                         TRACE("Disconnect other side: %08x\n", h);
522                         if (h == VFW_E_NOT_STOPPED)
523                         {
524                             PIN_INFO pinfo;
525                             IPin_QueryPinInfo(victim, &pinfo);
526
527                             IBaseFilter_GetState(pinfo.pFilter, 0, &state);
528                             if (state == State_Running)
529                                 IBaseFilter_Pause(pinfo.pFilter);
530                             IBaseFilter_Stop(pinfo.pFilter);
531                             IBaseFilter_Release(pinfo.pFilter);
532                             h = IPin_Disconnect(victim);
533                             TRACE("Disconnect retry: %08x\n", h);
534                         }
535                         IPin_Release(victim);
536                     }
537                     h = IPin_Disconnect(ppin);
538                     TRACE("Disconnect 2: %08x\n", h);
539
540                     IPin_Release(ppin);
541                 }
542                 IEnumPins_Release(penumpins);
543             }
544
545             hr = IBaseFilter_JoinFilterGraph(pFilter, NULL, This->pFilterNames[i]);
546             if (SUCCEEDED(hr))
547             {
548                 IBaseFilter_SetSyncSource(pFilter, NULL);
549                 IBaseFilter_Release(pFilter);
550                 CoTaskMemFree(This->pFilterNames[i]);
551                 memmove(This->ppFiltersInGraph+i, This->ppFiltersInGraph+i+1, sizeof(IBaseFilter*)*(This->nFilters - 1 - i));
552                 memmove(This->pFilterNames+i, This->pFilterNames+i+1, sizeof(LPWSTR)*(This->nFilters - 1 - i));
553                 This->nFilters--;
554                 /* Invalidate interfaces in the cache */
555                 for (i = 0; i < This->nItfCacheEntries; i++)
556                     if (pFilter == This->ItfCacheEntries[i].filter)
557                     {
558                         IUnknown_Release(This->ItfCacheEntries[i].iface);
559                         This->ItfCacheEntries[i].iface = NULL;
560                         This->ItfCacheEntries[i].filter = NULL;
561                     }
562                 return S_OK;
563             }
564             break;
565         }
566     }
567
568     return hr; /* FIXME: check this error code */
569 }
570
571 static HRESULT WINAPI FilterGraph2_EnumFilters(IFilterGraph2 *iface, IEnumFilters **ppEnum)
572 {
573     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
574
575     TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
576
577     return IEnumFiltersImpl_Construct(This->ppFiltersInGraph, This->nFilters, ppEnum);
578 }
579
580 static HRESULT WINAPI FilterGraph2_FindFilterByName(IFilterGraph2 *iface, LPCWSTR pName,
581         IBaseFilter **ppFilter)
582 {
583     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
584     int i;
585
586     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_w(pName), pName, ppFilter);
587
588     if (!ppFilter)
589         return E_POINTER;
590
591     for (i = 0; i < This->nFilters; i++)
592     {
593         if (!strcmpW(pName, This->pFilterNames[i]))
594         {
595             *ppFilter = This->ppFiltersInGraph[i];
596             IBaseFilter_AddRef(*ppFilter);
597             return S_OK;
598         }
599     }
600
601     *ppFilter = NULL;
602     return VFW_E_NOT_FOUND;
603 }
604
605 /* Don't allow a circular connection to form, return VFW_E_CIRCULAR_GRAPH if this would be the case.
606  * A circular connection will be formed if from the filter of the output pin, the input pin can be reached
607  */
608 static HRESULT CheckCircularConnection(IFilterGraphImpl *This, IPin *out, IPin *in)
609 {
610 #if 1
611     HRESULT hr;
612     PIN_INFO info_out, info_in;
613
614     hr = IPin_QueryPinInfo(out, &info_out);
615     if (FAILED(hr))
616         return hr;
617     if (info_out.dir != PINDIR_OUTPUT)
618     {
619         IBaseFilter_Release(info_out.pFilter);
620         return E_UNEXPECTED;
621     }
622
623     hr = IPin_QueryPinInfo(in, &info_in);
624     if (SUCCEEDED(hr))
625         IBaseFilter_Release(info_in.pFilter);
626     if (FAILED(hr))
627         goto out;
628     if (info_in.dir != PINDIR_INPUT)
629     {
630         hr = E_UNEXPECTED;
631         goto out;
632     }
633
634     if (info_out.pFilter == info_in.pFilter)
635         hr = VFW_E_CIRCULAR_GRAPH;
636     else
637     {
638         IEnumPins *enumpins;
639         IPin *test;
640
641         hr = IBaseFilter_EnumPins(info_out.pFilter, &enumpins);
642         if (FAILED(hr))
643             goto out;
644
645         IEnumPins_Reset(enumpins);
646         while ((hr = IEnumPins_Next(enumpins, 1, &test, NULL)) == S_OK)
647         {
648             PIN_DIRECTION dir = PINDIR_OUTPUT;
649             IPin_QueryDirection(test, &dir);
650             if (dir == PINDIR_INPUT)
651             {
652                 IPin *victim = NULL;
653                 IPin_ConnectedTo(test, &victim);
654                 if (victim)
655                 {
656                     hr = CheckCircularConnection(This, victim, in);
657                     IPin_Release(victim);
658                     if (FAILED(hr))
659                     {
660                         IPin_Release(test);
661                         break;
662                     }
663                 }
664             }
665             IPin_Release(test);
666         }
667         IEnumPins_Release(enumpins);
668     }
669
670 out:
671     IBaseFilter_Release(info_out.pFilter);
672     if (FAILED(hr))
673         ERR("Checking filtergraph returned %08x, something's not right!\n", hr);
674     return hr;
675 #else
676     /* Debugging filtergraphs not enabled */
677     return S_OK;
678 #endif
679 }
680
681
682 /* NOTE: despite the implication, it doesn't matter which
683  * way round you put in the input and output pins */
684 static HRESULT WINAPI FilterGraph2_ConnectDirect(IFilterGraph2 *iface, IPin *ppinIn, IPin *ppinOut,
685         const AM_MEDIA_TYPE *pmt)
686 {
687     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
688     PIN_DIRECTION dir;
689     HRESULT hr;
690
691     TRACE("(%p/%p)->(%p, %p, %p)\n", This, iface, ppinIn, ppinOut, pmt);
692
693     /* FIXME: check pins are in graph */
694
695     if (TRACE_ON(quartz))
696     {
697         PIN_INFO PinInfo;
698
699         hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
700         if (FAILED(hr))
701             return hr;
702
703         TRACE("Filter owning first pin => %p\n", PinInfo.pFilter);
704         IBaseFilter_Release(PinInfo.pFilter);
705
706         hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
707         if (FAILED(hr))
708             return hr;
709
710         TRACE("Filter owning second pin => %p\n", PinInfo.pFilter);
711         IBaseFilter_Release(PinInfo.pFilter);
712     }
713
714     hr = IPin_QueryDirection(ppinIn, &dir);
715     if (SUCCEEDED(hr))
716     {
717         if (dir == PINDIR_INPUT)
718         {
719             hr = CheckCircularConnection(This, ppinOut, ppinIn);
720             if (SUCCEEDED(hr))
721                 hr = IPin_Connect(ppinOut, ppinIn, pmt);
722         }
723         else
724         {
725             hr = CheckCircularConnection(This, ppinIn, ppinOut);
726             if (SUCCEEDED(hr))
727                 hr = IPin_Connect(ppinIn, ppinOut, pmt);
728         }
729     }
730
731     return hr;
732 }
733
734 static HRESULT WINAPI FilterGraph2_Reconnect(IFilterGraph2 *iface, IPin *ppin)
735 {
736     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
737     IPin *pConnectedTo = NULL;
738     HRESULT hr;
739     PIN_DIRECTION pindir;
740
741     IPin_QueryDirection(ppin, &pindir);
742     hr = IPin_ConnectedTo(ppin, &pConnectedTo);
743     if (FAILED(hr)) {
744         TRACE("Querying connected to failed: %x\n", hr);
745         return hr; 
746     }
747     IPin_Disconnect(ppin);
748     IPin_Disconnect(pConnectedTo);
749     if (pindir == PINDIR_INPUT)
750         hr = IPin_Connect(pConnectedTo, ppin, NULL);
751     else
752         hr = IPin_Connect(ppin, pConnectedTo, NULL);
753     IPin_Release(pConnectedTo);
754     if (FAILED(hr))
755         WARN("Reconnecting pins failed, pins are not connected now..\n");
756     TRACE("(%p->%p) -- %p %p -> %x\n", iface, This, ppin, pConnectedTo, hr);
757     return hr;
758 }
759
760 static HRESULT WINAPI FilterGraph2_Disconnect(IFilterGraph2 *iface, IPin *ppin)
761 {
762     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
763
764     TRACE("(%p/%p)->(%p)\n", This, iface, ppin);
765
766     if (!ppin)
767        return E_POINTER;
768
769     return IPin_Disconnect(ppin);
770 }
771
772 static HRESULT WINAPI FilterGraph2_SetDefaultSyncSource(IFilterGraph2 *iface)
773 {
774     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
775     IReferenceClock *pClock = NULL;
776     HRESULT hr = S_OK;
777     int i;
778
779     TRACE("(%p/%p)->() live sources not handled properly!\n", iface, This);
780
781     EnterCriticalSection(&This->cs);
782
783     for (i = 0; i < This->nFilters; ++i)
784     {
785         DWORD miscflags;
786         IAMFilterMiscFlags *flags = NULL;
787         IUnknown_QueryInterface(This->ppFiltersInGraph[i], &IID_IAMFilterMiscFlags, (void**)&flags);
788         if (!flags)
789             continue;
790         miscflags = IAMFilterMiscFlags_GetMiscFlags(flags);
791         IUnknown_Release(flags);
792         if (miscflags == AM_FILTER_MISC_FLAGS_IS_RENDERER)
793             IUnknown_QueryInterface(This->ppFiltersInGraph[i], &IID_IReferenceClock, (void**)&pClock);
794         if (pClock)
795             break;
796     }
797
798     if (!pClock)
799     {
800         hr = CoCreateInstance(&CLSID_SystemClock, NULL, CLSCTX_INPROC_SERVER, &IID_IReferenceClock, (LPVOID*)&pClock);
801         This->refClockProvider = NULL;
802     }
803     else
804         This->refClockProvider = This->ppFiltersInGraph[i];
805
806     if (SUCCEEDED(hr))
807     {
808         hr = IMediaFilter_SetSyncSource(&This->IMediaFilter_iface, pClock);
809         This->defaultclock = TRUE;
810         IReferenceClock_Release(pClock);
811     }
812     LeaveCriticalSection(&This->cs);
813
814     return hr;
815 }
816
817 static HRESULT GetFilterInfo(IMoniker* pMoniker, GUID* pclsid, VARIANT* pvar)
818 {
819     static const WCHAR wszClsidName[] = {'C','L','S','I','D',0};
820     static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
821     IPropertyBag * pPropBagCat = NULL;
822     HRESULT hr;
823
824     VariantInit(pvar);
825
826     hr = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (LPVOID*)&pPropBagCat);
827
828     if (SUCCEEDED(hr))
829         hr = IPropertyBag_Read(pPropBagCat, wszClsidName, pvar, NULL);
830
831     if (SUCCEEDED(hr))
832         hr = CLSIDFromString(V_UNION(pvar, bstrVal), pclsid);
833
834     VariantClear(pvar);
835
836     if (SUCCEEDED(hr))
837         hr = IPropertyBag_Read(pPropBagCat, wszFriendlyName, pvar, NULL);
838
839     if (SUCCEEDED(hr))
840         TRACE("Moniker = %s - %s\n", debugstr_guid(pclsid), debugstr_w(V_UNION(pvar, bstrVal)));
841
842     if (pPropBagCat)
843         IPropertyBag_Release(pPropBagCat);
844
845     return hr;
846 }
847
848 static HRESULT GetInternalConnections(IBaseFilter* pfilter, IPin* pinputpin, IPin*** pppins, ULONG* pnb)
849 {
850     HRESULT hr;
851     ULONG nb = 0;
852
853     TRACE("(%p, %p, %p, %p)\n", pfilter, pinputpin, pppins, pnb);
854     hr = IPin_QueryInternalConnections(pinputpin, NULL, &nb);
855     if (hr == S_OK) {
856         /* Rendered input */
857     } else if (hr == S_FALSE) {
858         *pppins = CoTaskMemAlloc(sizeof(IPin*)*nb);
859         hr = IPin_QueryInternalConnections(pinputpin, *pppins, &nb);
860         if (hr != S_OK) {
861             WARN("Error (%x)\n", hr);
862         }
863     } else if (hr == E_NOTIMPL) {
864         /* Input connected to all outputs */
865         IEnumPins* penumpins;
866         IPin* ppin;
867         int i = 0;
868         TRACE("E_NOTIMPL\n");
869         hr = IBaseFilter_EnumPins(pfilter, &penumpins);
870         if (FAILED(hr)) {
871             WARN("filter Enumpins failed (%x)\n", hr);
872             return hr;
873         }
874         i = 0;
875         /* Count output pins */
876         while(IEnumPins_Next(penumpins, 1, &ppin, &nb) == S_OK) {
877             PIN_DIRECTION pindir;
878             IPin_QueryDirection(ppin, &pindir);
879             if (pindir == PINDIR_OUTPUT)
880                 i++;
881             IPin_Release(ppin);
882         }
883         *pppins = CoTaskMemAlloc(sizeof(IPin*)*i);
884         /* Retrieve output pins */
885         IEnumPins_Reset(penumpins);
886         i = 0;
887         while(IEnumPins_Next(penumpins, 1, &ppin, &nb) == S_OK) {
888             PIN_DIRECTION pindir;
889             IPin_QueryDirection(ppin, &pindir);
890             if (pindir == PINDIR_OUTPUT)
891                 (*pppins)[i++] = ppin;
892             else
893                 IPin_Release(ppin);
894         }
895         IEnumPins_Release(penumpins);
896         nb = i;
897         if (FAILED(hr)) {
898             WARN("Next failed (%x)\n", hr);
899             return hr;
900         }
901     } else if (FAILED(hr)) {
902         WARN("Cannot get internal connection (%x)\n", hr);
903         return hr;
904     }
905
906     *pnb = nb;
907     return S_OK;
908 }
909
910 /*** IGraphBuilder methods ***/
911 static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface, IPin *ppinOut, IPin *ppinIn)
912 {
913     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
914     HRESULT hr;
915     AM_MEDIA_TYPE* mt = NULL;
916     IEnumMediaTypes* penummt = NULL;
917     ULONG nbmt;
918     IEnumPins* penumpins;
919     IEnumMoniker* pEnumMoniker;
920     GUID tab[2];
921     ULONG nb;
922     IMoniker* pMoniker;
923     ULONG pin;
924     PIN_INFO PinInfo;
925     CLSID FilterCLSID;
926     PIN_DIRECTION dir;
927
928     TRACE("(%p/%p)->(%p, %p)\n", This, iface, ppinOut, ppinIn);
929
930     if (TRACE_ON(quartz))
931     {
932         hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
933         if (FAILED(hr))
934             return hr;
935
936         TRACE("Filter owning first pin => %p\n", PinInfo.pFilter);
937         IBaseFilter_Release(PinInfo.pFilter);
938
939         hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
940         if (FAILED(hr))
941             return hr;
942
943         TRACE("Filter owning second pin => %p\n", PinInfo.pFilter);
944         IBaseFilter_Release(PinInfo.pFilter);
945     }
946
947     EnterCriticalSection(&This->cs);
948     ++This->recursioncount;
949     if (This->recursioncount >= 5)
950     {
951         WARN("Recursion count has reached %d\n", This->recursioncount);
952         hr = VFW_E_CANNOT_CONNECT;
953         goto out;
954     }
955
956     hr = IPin_QueryDirection(ppinOut, &dir);
957     if (FAILED(hr))
958         goto out;
959
960     if (dir == PINDIR_INPUT)
961     {
962         IPin *temp;
963
964         temp = ppinIn;
965         ppinIn = ppinOut;
966         ppinOut = temp;
967     }
968
969     hr = CheckCircularConnection(This, ppinOut, ppinIn);
970     if (FAILED(hr))
971         goto out;
972
973     /* Try direct connection first */
974     hr = IPin_Connect(ppinOut, ppinIn, NULL);
975     if (SUCCEEDED(hr))
976         goto out;
977
978     TRACE("Direct connection failed, trying to render using extra filters\n");
979
980     hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
981     if (FAILED(hr))
982         goto out;
983
984     hr = IBaseFilter_GetClassID(PinInfo.pFilter, &FilterCLSID);
985     IBaseFilter_Release(PinInfo.pFilter);
986     if (FAILED(hr))
987         goto out;
988
989     /* Find the appropriate transform filter than can transform the minor media type of output pin of the upstream 
990      * filter to the minor mediatype of input pin of the renderer */
991     hr = IPin_EnumMediaTypes(ppinOut, &penummt);
992     if (FAILED(hr))
993     {
994         WARN("EnumMediaTypes (%x)\n", hr);
995         goto out;
996     }
997
998     hr = IEnumMediaTypes_Next(penummt, 1, &mt, &nbmt);
999     if (FAILED(hr)) {
1000         WARN("IEnumMediaTypes_Next (%x)\n", hr);
1001         goto out;
1002     }
1003
1004     if (!nbmt)
1005     {
1006         WARN("No media type found!\n");
1007         hr = VFW_E_INVALIDMEDIATYPE;
1008         goto out;
1009     }
1010     TRACE("MajorType %s\n", debugstr_guid(&mt->majortype));
1011     TRACE("SubType %s\n", debugstr_guid(&mt->subtype));
1012
1013     /* Try to find a suitable filter that can connect to the pin to render */
1014     tab[0] = mt->majortype;
1015     tab[1] = mt->subtype;
1016     hr = IFilterMapper2_EnumMatchingFilters(This->pFilterMapper2, &pEnumMoniker, 0, FALSE, MERIT_UNLIKELY, TRUE, 1, tab, NULL, NULL, FALSE, FALSE, 0, NULL, NULL, NULL);
1017     if (FAILED(hr)) {
1018         WARN("Unable to enum filters (%x)\n", hr);
1019         goto out;
1020     }
1021
1022     hr = VFW_E_CANNOT_RENDER;
1023     while(IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK)
1024     {
1025         VARIANT var;
1026         GUID clsid;
1027         IPin** ppins;
1028         IPin* ppinfilter = NULL;
1029         IBaseFilter* pfilter = NULL;
1030         IAMGraphBuilderCallback *callback = NULL;
1031
1032         hr = GetFilterInfo(pMoniker, &clsid, &var);
1033         IMoniker_Release(pMoniker);
1034         if (FAILED(hr)) {
1035             WARN("Unable to retrieve filter info (%x)\n", hr);
1036             goto error;
1037         }
1038
1039         if (IsEqualGUID(&clsid, &FilterCLSID)) {
1040             /* Skip filter (same as the one the output pin belongs to) */
1041             goto error;
1042         }
1043
1044         if (This->pSite)
1045         {
1046             IUnknown_QueryInterface(This->pSite, &IID_IAMGraphBuilderCallback, (LPVOID*)&callback);
1047             if (callback)
1048             {
1049                 HRESULT rc;
1050                 rc = IAMGraphBuilderCallback_SelectedFilter(callback, pMoniker);
1051                 if (FAILED(rc))
1052                 {
1053                     TRACE("Filter rejected by IAMGraphBuilderCallback_SelectedFilter\n");
1054                     IUnknown_Release(callback);
1055                     goto error;
1056                 }
1057             }
1058         }
1059
1060         hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&pfilter);
1061         if (FAILED(hr)) {
1062             WARN("Unable to create filter (%x), trying next one\n", hr);
1063             goto error;
1064         }
1065
1066         if (callback)
1067         {
1068             HRESULT rc;
1069             rc = IAMGraphBuilderCallback_CreatedFilter(callback, pfilter);
1070             IUnknown_Release(callback);
1071             if (FAILED(rc))
1072             {
1073                 IBaseFilter_Release(pfilter);
1074                 pfilter = NULL;
1075                 TRACE("Filter rejected by IAMGraphBuilderCallback_CreatedFilter\n");
1076                 goto error;
1077             }
1078         }
1079
1080         hr = IFilterGraph2_AddFilter(iface, pfilter, V_UNION(&var, bstrVal));
1081         if (FAILED(hr)) {
1082             WARN("Unable to add filter (%x)\n", hr);
1083             IBaseFilter_Release(pfilter);
1084             pfilter = NULL;
1085             goto error;
1086         }
1087
1088         VariantClear(&var);
1089
1090         hr = IBaseFilter_EnumPins(pfilter, &penumpins);
1091         if (FAILED(hr)) {
1092             WARN("Enumpins (%x)\n", hr);
1093             goto error;
1094         }
1095
1096         hr = IEnumPins_Next(penumpins, 1, &ppinfilter, &pin);
1097         IEnumPins_Release(penumpins);
1098
1099         if (FAILED(hr)) {
1100             WARN("Obtaining next pin: (%x)\n", hr);
1101             goto error;
1102         }
1103         if (pin == 0) {
1104             WARN("Cannot use this filter: no pins\n");
1105             goto error;
1106         }
1107
1108         hr = IPin_Connect(ppinOut, ppinfilter, NULL);
1109         if (FAILED(hr)) {
1110             TRACE("Cannot connect to filter (%x), trying next one\n", hr);
1111             goto error;
1112         }
1113         TRACE("Successfully connected to filter, follow chain...\n");
1114
1115         /* Render all output pins of the filter by calling IFilterGraph2_Connect on each of them */
1116         hr = GetInternalConnections(pfilter, ppinfilter, &ppins, &nb);
1117
1118         if (SUCCEEDED(hr)) {
1119             unsigned int i;
1120             if (nb == 0) {
1121                 IPin_Disconnect(ppinfilter);
1122                 IPin_Disconnect(ppinOut);
1123                 goto error;
1124             }
1125             TRACE("pins to consider: %d\n", nb);
1126             for(i = 0; i < nb; i++)
1127             {
1128                 LPWSTR pinname = NULL;
1129
1130                 TRACE("Processing pin %u\n", i);
1131
1132                 hr = IPin_QueryId(ppins[i], &pinname);
1133                 if (SUCCEEDED(hr))
1134                 {
1135                     if (pinname[0] == '~')
1136                     {
1137                         TRACE("Pinname=%s, skipping\n", debugstr_w(pinname));
1138                         hr = E_FAIL;
1139                     }
1140                     else
1141                         hr = IFilterGraph2_Connect(iface, ppins[i], ppinIn);
1142                     CoTaskMemFree(pinname);
1143                 }
1144
1145                 if (FAILED(hr)) {
1146                    TRACE("Cannot connect pin %p (%x)\n", ppinfilter, hr);
1147                 }
1148                 IPin_Release(ppins[i]);
1149                 if (SUCCEEDED(hr)) break;
1150             }
1151             while (++i < nb) IPin_Release(ppins[i]);
1152             CoTaskMemFree(ppins);
1153             IPin_Release(ppinfilter);
1154             IBaseFilter_Release(pfilter);
1155             if (FAILED(hr))
1156             {
1157                 IPin_Disconnect(ppinfilter);
1158                 IPin_Disconnect(ppinOut);
1159                 IFilterGraph2_RemoveFilter(iface, pfilter);
1160                 continue;
1161             }
1162             break;
1163         }
1164
1165 error:
1166         VariantClear(&var);
1167         if (ppinfilter) IPin_Release(ppinfilter);
1168         if (pfilter) {
1169             IFilterGraph2_RemoveFilter(iface, pfilter);
1170             IBaseFilter_Release(pfilter);
1171         }
1172     }
1173
1174 out:
1175     if (penummt)
1176         IEnumMediaTypes_Release(penummt);
1177     if (mt)
1178         DeleteMediaType(mt);
1179     --This->recursioncount;
1180     LeaveCriticalSection(&This->cs);
1181     TRACE("--> %08x\n", hr);
1182     return SUCCEEDED(hr) ? S_OK : hr;
1183 }
1184
1185 static HRESULT FilterGraph2_RenderRecurse(IFilterGraphImpl *This, IPin *ppinOut)
1186 {
1187     /* This pin has been connected now, try to call render on all pins that aren't connected */
1188     IPin *to = NULL;
1189     PIN_INFO info;
1190     IEnumPins *enumpins = NULL;
1191     BOOL renderany = FALSE;
1192     BOOL renderall = TRUE;
1193
1194     IPin_QueryPinInfo(ppinOut, &info);
1195
1196     IBaseFilter_EnumPins(info.pFilter, &enumpins);
1197     /* Don't need to hold a reference, IEnumPins does */
1198     IBaseFilter_Release(info.pFilter);
1199
1200     IEnumPins_Reset(enumpins);
1201     while (IEnumPins_Next(enumpins, 1, &to, NULL) == S_OK)
1202     {
1203         PIN_DIRECTION dir = PINDIR_INPUT;
1204
1205         IPin_QueryDirection(to, &dir);
1206
1207         if (dir == PINDIR_OUTPUT)
1208         {
1209             IPin *out = NULL;
1210
1211             IPin_ConnectedTo(to, &out);
1212             if (!out)
1213             {
1214                 HRESULT hr;
1215                 hr = IFilterGraph2_Render(&This->IFilterGraph2_iface, to);
1216                 if (SUCCEEDED(hr))
1217                     renderany = TRUE;
1218                 else
1219                     renderall = FALSE;
1220             }
1221             else
1222                 IPin_Release(out);
1223         }
1224
1225         IPin_Release(to);
1226     }
1227
1228     IEnumPins_Release(enumpins);
1229
1230     if (renderall)
1231         return S_OK;
1232
1233     if (renderany)
1234         return VFW_S_PARTIAL_RENDER;
1235
1236     return VFW_E_CANNOT_RENDER;
1237 }
1238
1239 /* Ogg hates me if I create a direct rendering method
1240  *
1241  * It can only connect to a pin properly once, so use a recursive method that does
1242  *
1243  *  +----+ --- (PIN 1) (Render is called on this pin)
1244  *  |    |
1245  *  +----+ --- (PIN 2)
1246  *
1247  *  Enumerate possible renderers that EXACTLY match the requested type
1248  *
1249  *  If none is available, try to add intermediate filters that can connect to the input pin
1250  *  then call Render on that intermediate pin's output pins
1251  *  if it succeeds: Render returns success, if it doesn't, the intermediate filter is removed,
1252  *  and another filter that can connect to the input pin is tried
1253  *  if we run out of filters that can, give up and return VFW_E_CANNOT_RENDER
1254  *  It's recursive, but fun!
1255  */
1256
1257 static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface, IPin *ppinOut)
1258 {
1259     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1260     IEnumMediaTypes* penummt;
1261     AM_MEDIA_TYPE* mt;
1262     ULONG nbmt;
1263     HRESULT hr;
1264
1265     IEnumMoniker* pEnumMoniker;
1266     GUID tab[4];
1267     ULONG nb;
1268     IMoniker* pMoniker;
1269     INT x;
1270
1271     TRACE("(%p/%p)->(%p)\n", This, iface, ppinOut);
1272
1273     if (TRACE_ON(quartz))
1274     {
1275         PIN_INFO PinInfo;
1276
1277         hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
1278         if (FAILED(hr))
1279             return hr;
1280
1281         TRACE("Filter owning pin => %p\n", PinInfo.pFilter);
1282         IBaseFilter_Release(PinInfo.pFilter);
1283     }
1284
1285     /* Try to find out if there is a renderer for the specified subtype already, and use that
1286      */
1287     EnterCriticalSection(&This->cs);
1288     for (x = 0; x < This->nFilters; ++x)
1289     {
1290         IEnumPins *enumpins = NULL;
1291         IPin *pin = NULL;
1292
1293         hr = IBaseFilter_EnumPins(This->ppFiltersInGraph[x], &enumpins);
1294
1295         if (FAILED(hr) || !enumpins)
1296             continue;
1297
1298         IEnumPins_Reset(enumpins);
1299         while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK)
1300         {
1301             IPin *to = NULL;
1302             PIN_DIRECTION dir = PINDIR_OUTPUT;
1303
1304             IPin_QueryDirection(pin, &dir);
1305             if (dir != PINDIR_INPUT)
1306             {
1307                 IPin_Release(pin);
1308                 continue;
1309             }
1310             IPin_ConnectedTo(pin, &to);
1311
1312             if (to == NULL)
1313             {
1314                 hr = FilterGraph2_ConnectDirect(iface, ppinOut, pin, NULL);
1315                 if (SUCCEEDED(hr))
1316                 {
1317                     TRACE("Connected successfully %p/%p, %08x look if we should render more!\n", ppinOut, pin, hr);
1318                     IPin_Release(pin);
1319
1320                     hr = FilterGraph2_RenderRecurse(This, pin);
1321                     if (FAILED(hr))
1322                     {
1323                         IPin_Disconnect(ppinOut);
1324                         IPin_Disconnect(pin);
1325                         continue;
1326                     }
1327                     IEnumPins_Release(enumpins);
1328                     LeaveCriticalSection(&This->cs);
1329                     return hr;
1330                 }
1331                 WARN("Could not connect!\n");
1332             }
1333             else
1334                 IPin_Release(to);
1335
1336             IPin_Release(pin);
1337         }
1338         IEnumPins_Release(enumpins);
1339     }
1340
1341     LeaveCriticalSection(&This->cs);
1342
1343     hr = IPin_EnumMediaTypes(ppinOut, &penummt);
1344     if (FAILED(hr)) {
1345         WARN("EnumMediaTypes (%x)\n", hr);
1346         return hr;
1347     }
1348
1349     IEnumMediaTypes_Reset(penummt);
1350
1351     /* Looks like no existing renderer of the kind exists
1352      * Try adding new ones
1353      */
1354     tab[0] = tab[1] = GUID_NULL;
1355     while (SUCCEEDED(hr))
1356     {
1357         hr = IEnumMediaTypes_Next(penummt, 1, &mt, &nbmt);
1358         if (FAILED(hr)) {
1359             WARN("IEnumMediaTypes_Next (%x)\n", hr);
1360             break;
1361         }
1362         if (!nbmt)
1363         {
1364             hr = VFW_E_CANNOT_RENDER;
1365             break;
1366         }
1367         else
1368         {
1369             TRACE("MajorType %s\n", debugstr_guid(&mt->majortype));
1370             TRACE("SubType %s\n", debugstr_guid(&mt->subtype));
1371
1372             /* Only enumerate once, this doesn't account for all previous ones, but this should be enough nonetheless */
1373             if (IsEqualIID(&tab[0], &mt->majortype) && IsEqualIID(&tab[1], &mt->subtype))
1374             {
1375                 DeleteMediaType(mt);
1376                 continue;
1377             }
1378
1379             /* Try to find a suitable renderer with the same media type */
1380             tab[0] = mt->majortype;
1381             tab[1] = mt->subtype;
1382             hr = IFilterMapper2_EnumMatchingFilters(This->pFilterMapper2, &pEnumMoniker, 0, FALSE, MERIT_UNLIKELY, TRUE, 1, tab, NULL, NULL, FALSE, FALSE, 0, NULL, NULL, NULL);
1383             if (FAILED(hr))
1384             {
1385                 WARN("Unable to enum filters (%x)\n", hr);
1386                 break;
1387             }
1388         }
1389         hr = E_FAIL;
1390
1391         while (IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK)
1392         {
1393             VARIANT var;
1394             GUID clsid;
1395             IPin* ppinfilter;
1396             IBaseFilter* pfilter = NULL;
1397             IEnumPins* penumpins = NULL;
1398             ULONG pin;
1399
1400             hr = GetFilterInfo(pMoniker, &clsid, &var);
1401             IMoniker_Release(pMoniker);
1402             if (FAILED(hr)) {
1403                 WARN("Unable to retrieve filter info (%x)\n", hr);
1404                 goto error;
1405             }
1406
1407             hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&pfilter);
1408             if (FAILED(hr))
1409             {
1410                 WARN("Unable to create filter (%x), trying next one\n", hr);
1411                 goto error;
1412             }
1413
1414             hr = IFilterGraph2_AddFilter(iface, pfilter, V_UNION(&var, bstrVal));
1415             if (FAILED(hr)) {
1416                 WARN("Unable to add filter (%x)\n", hr);
1417                 IBaseFilter_Release(pfilter);
1418                 pfilter = NULL;
1419                 goto error;
1420             }
1421
1422             hr = IBaseFilter_EnumPins(pfilter, &penumpins);
1423             if (FAILED(hr)) {
1424                 WARN("Splitter Enumpins (%x)\n", hr);
1425                 goto error;
1426             }
1427
1428             while ((hr = IEnumPins_Next(penumpins, 1, &ppinfilter, &pin)) == S_OK)
1429             {
1430                 PIN_DIRECTION dir;
1431
1432                 if (pin == 0) {
1433                     WARN("No Pin\n");
1434                     hr = E_FAIL;
1435                     goto error;
1436                 }
1437
1438                 hr = IPin_QueryDirection(ppinfilter, &dir);
1439                 if (FAILED(hr)) {
1440                     IPin_Release(ppinfilter);
1441                     WARN("QueryDirection failed (%x)\n", hr);
1442                     goto error;
1443                 }
1444                 if (dir != PINDIR_INPUT) {
1445                     IPin_Release(ppinfilter);
1446                     continue; /* Wrong direction */
1447                 }
1448
1449                 /* Connect the pin to the "Renderer" */
1450                 hr = IPin_Connect(ppinOut, ppinfilter, NULL);
1451                 IPin_Release(ppinfilter);
1452
1453                 if (FAILED(hr)) {
1454                     WARN("Unable to connect %s to renderer (%x)\n", debugstr_w(V_UNION(&var, bstrVal)), hr);
1455                     goto error;
1456                 }
1457                 TRACE("Connected, recursing %s\n",  debugstr_w(V_UNION(&var, bstrVal)));
1458
1459                 VariantClear(&var);
1460
1461                 hr = FilterGraph2_RenderRecurse(This, ppinfilter);
1462                 if (FAILED(hr)) {
1463                     WARN("Unable to connect recursively (%x)\n", hr);
1464                     goto error;
1465                 }
1466                 IBaseFilter_Release(pfilter);
1467                 break;
1468             }
1469             if (SUCCEEDED(hr)) {
1470                 IEnumPins_Release(penumpins);
1471                 break; /* out of IEnumMoniker_Next loop */
1472             }
1473
1474             /* IEnumPins_Next failed, all other failure case caught by goto error */
1475             WARN("IEnumPins_Next (%x)\n", hr);
1476             /* goto error */
1477
1478 error:
1479             VariantClear(&var);
1480             if (penumpins)
1481                 IEnumPins_Release(penumpins);
1482             if (pfilter) {
1483                 IFilterGraph2_RemoveFilter(iface, pfilter);
1484                 IBaseFilter_Release(pfilter);
1485             }
1486             if (SUCCEEDED(hr)) DebugBreak();
1487         }
1488
1489         IEnumMoniker_Release(pEnumMoniker);
1490         if (nbmt)
1491             DeleteMediaType(mt);
1492         if (SUCCEEDED(hr))
1493             break;
1494         hr = S_OK;
1495     }
1496
1497     IEnumMediaTypes_Release(penummt);
1498     return hr;
1499 }
1500
1501 static HRESULT WINAPI FilterGraph2_RenderFile(IFilterGraph2 *iface, LPCWSTR lpcwstrFile,
1502         LPCWSTR lpcwstrPlayList)
1503 {
1504     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1505     static const WCHAR string[] = {'R','e','a','d','e','r',0};
1506     IBaseFilter* preader = NULL;
1507     IPin* ppinreader = NULL;
1508     IEnumPins* penumpins = NULL;
1509     HRESULT hr;
1510     BOOL partial = FALSE;
1511     HRESULT any = FALSE;
1512
1513     TRACE("(%p/%p)->(%s, %s)\n", This, iface, debugstr_w(lpcwstrFile), debugstr_w(lpcwstrPlayList));
1514
1515     if (lpcwstrPlayList != NULL)
1516         return E_INVALIDARG;
1517
1518     hr = IFilterGraph2_AddSourceFilter(iface, lpcwstrFile, string, &preader);
1519     if (FAILED(hr))
1520         return hr;
1521
1522     if (SUCCEEDED(hr))
1523         hr = IBaseFilter_EnumPins(preader, &penumpins);
1524     if (SUCCEEDED(hr))
1525     {
1526         while (IEnumPins_Next(penumpins, 1, &ppinreader, NULL) == S_OK)
1527         {
1528             PIN_DIRECTION dir;
1529
1530             IPin_QueryDirection(ppinreader, &dir);
1531             if (dir == PINDIR_OUTPUT)
1532             {
1533                 INT i;
1534
1535                 hr = IFilterGraph2_Render(iface, ppinreader);
1536                 TRACE("Render %08x\n", hr);
1537
1538                 for (i = 0; i < This->nFilters; ++i)
1539                     TRACE("Filters in chain: %s\n", debugstr_w(This->pFilterNames[i]));
1540
1541                 if (SUCCEEDED(hr))
1542                     any = TRUE;
1543                 if (hr != S_OK)
1544                     partial = TRUE;
1545             }
1546             IPin_Release(ppinreader);
1547         }
1548         IEnumPins_Release(penumpins);
1549
1550         if (!any)
1551             hr = VFW_E_CANNOT_RENDER;
1552         else if (partial)
1553             hr = VFW_S_PARTIAL_RENDER;
1554         else
1555             hr = S_OK;
1556     }
1557     IBaseFilter_Release(preader);
1558
1559     TRACE("--> %08x\n", hr);
1560     return hr;
1561 }
1562
1563 /* Some filters implement their own asynchronous reader (Theoretically they all should, try to load it first */
1564 static HRESULT GetFileSourceFilter(LPCOLESTR pszFileName, IBaseFilter **filter)
1565 {
1566     static const WCHAR wszReg[] = {'M','e','d','i','a',' ','T','y','p','e','\\','E','x','t','e','n','s','i','o','n','s',0};
1567     HRESULT hr = S_OK;
1568     HKEY extkey;
1569     LONG lRet;
1570
1571     lRet = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszReg, 0, KEY_READ, &extkey);
1572     hr = HRESULT_FROM_WIN32(lRet);
1573
1574     if (SUCCEEDED(hr))
1575     {
1576         static const WCHAR filtersource[] = {'S','o','u','r','c','e',' ','F','i','l','t','e','r',0};
1577         WCHAR *ext = PathFindExtensionW(pszFileName);
1578         WCHAR clsid_key[39];
1579         GUID clsid;
1580         DWORD size = sizeof(clsid_key);
1581         HKEY pathkey;
1582
1583         if (!ext)
1584         {
1585             CloseHandle(extkey);
1586             return E_FAIL;
1587         }
1588
1589         lRet = RegOpenKeyExW(extkey, ext, 0, KEY_READ, &pathkey);
1590         hr = HRESULT_FROM_WIN32(lRet);
1591         CloseHandle(extkey);
1592         if (FAILED(hr))
1593             return hr;
1594
1595         lRet = RegQueryValueExW(pathkey, filtersource, NULL, NULL, (LPBYTE)clsid_key, &size);
1596         hr = HRESULT_FROM_WIN32(lRet);
1597         CloseHandle(pathkey);
1598         if (FAILED(hr))
1599             return hr;
1600
1601         CLSIDFromString(clsid_key, &clsid);
1602
1603         TRACE("CLSID: %s\n", debugstr_guid(&clsid));
1604         hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)filter);
1605         if (SUCCEEDED(hr))
1606         {
1607             IFileSourceFilter *source = NULL;
1608             hr = IBaseFilter_QueryInterface(*filter, &IID_IFileSourceFilter, (LPVOID*)&source);
1609             if (SUCCEEDED(hr))
1610                 IFileSourceFilter_Release(source);
1611             else
1612                 IBaseFilter_Release(*filter);
1613         }
1614     }
1615     if (FAILED(hr))
1616         *filter = NULL;
1617     return hr;
1618 }
1619
1620 static HRESULT WINAPI FilterGraph2_AddSourceFilter(IFilterGraph2 *iface, LPCWSTR lpcwstrFileName,
1621         LPCWSTR lpcwstrFilterName, IBaseFilter **ppFilter)
1622 {
1623     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1624     HRESULT hr;
1625     IBaseFilter* preader;
1626     IFileSourceFilter* pfile = NULL;
1627     AM_MEDIA_TYPE mt;
1628     WCHAR* filename;
1629
1630     TRACE("(%p/%p)->(%s, %s, %p)\n", This, iface, debugstr_w(lpcwstrFileName), debugstr_w(lpcwstrFilterName), ppFilter);
1631
1632     /* Try from file name first, then fall back to default asynchronous reader */
1633     hr = GetFileSourceFilter(lpcwstrFileName, &preader);
1634
1635     if (FAILED(hr))
1636         hr = CoCreateInstance(&CLSID_AsyncReader, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&preader);
1637     if (FAILED(hr)) {
1638         WARN("Unable to create file source filter (%x)\n", hr);
1639         return hr;
1640     }
1641
1642     hr = IFilterGraph2_AddFilter(iface, preader, lpcwstrFilterName);
1643     if (FAILED(hr)) {
1644         WARN("Unable add filter (%x)\n", hr);
1645         IBaseFilter_Release(preader);
1646         return hr;
1647     }
1648
1649     hr = IBaseFilter_QueryInterface(preader, &IID_IFileSourceFilter, (LPVOID*)&pfile);
1650     if (FAILED(hr)) {
1651         WARN("Unable to get IFileSourceInterface (%x)\n", hr);
1652         goto error;
1653     }
1654
1655     /* Load the file in the file source filter */
1656     hr = IFileSourceFilter_Load(pfile, lpcwstrFileName, NULL);
1657     if (FAILED(hr)) {
1658         WARN("Load (%x)\n", hr);
1659         goto error;
1660     }
1661
1662     IFileSourceFilter_GetCurFile(pfile, &filename, &mt);
1663     if (FAILED(hr)) {
1664         WARN("GetCurFile (%x)\n", hr);
1665         goto error;
1666     }
1667
1668     TRACE("File %s\n", debugstr_w(filename));
1669     TRACE("MajorType %s\n", debugstr_guid(&mt.majortype));
1670     TRACE("SubType %s\n", debugstr_guid(&mt.subtype));
1671
1672     if (ppFilter)
1673         *ppFilter = preader;
1674     IFileSourceFilter_Release(pfile);
1675
1676     return S_OK;
1677     
1678 error:
1679     if (pfile)
1680         IFileSourceFilter_Release(pfile);
1681     IFilterGraph2_RemoveFilter(iface, preader);
1682     IBaseFilter_Release(preader);
1683        
1684     return hr;
1685 }
1686
1687 static HRESULT WINAPI FilterGraph2_SetLogFile(IFilterGraph2 *iface, DWORD_PTR hFile)
1688 {
1689     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1690
1691     TRACE("(%p/%p)->(%08x): stub !!!\n", This, iface, (DWORD) hFile);
1692
1693     return S_OK;
1694 }
1695
1696 static HRESULT WINAPI FilterGraph2_Abort(IFilterGraph2 *iface)
1697 {
1698     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1699
1700     TRACE("(%p/%p)->(): stub !!!\n", This, iface);
1701
1702     return S_OK;
1703 }
1704
1705 static HRESULT WINAPI FilterGraph2_ShouldOperationContinue(IFilterGraph2 *iface)
1706 {
1707     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1708
1709     TRACE("(%p/%p)->(): stub !!!\n", This, iface);
1710
1711     return S_OK;
1712 }
1713
1714 /*** IFilterGraph2 methods ***/
1715 static HRESULT WINAPI FilterGraph2_AddSourceFilterForMoniker(IFilterGraph2 *iface,
1716         IMoniker *pMoniker, IBindCtx *pCtx, LPCWSTR lpcwstrFilterName, IBaseFilter **ppFilter)
1717 {
1718     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1719
1720     TRACE("(%p/%p)->(%p %p %s %p): stub !!!\n", This, iface, pMoniker, pCtx, debugstr_w(lpcwstrFilterName), ppFilter);
1721
1722     return S_OK;
1723 }
1724
1725 static HRESULT WINAPI FilterGraph2_ReconnectEx(IFilterGraph2 *iface, IPin *ppin,
1726         const AM_MEDIA_TYPE *pmt)
1727 {
1728     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1729
1730     TRACE("(%p/%p)->(%p %p): stub !!!\n", This, iface, ppin, pmt);
1731
1732     return S_OK;
1733 }
1734
1735 static HRESULT WINAPI FilterGraph2_RenderEx(IFilterGraph2 *iface, IPin *pPinOut, DWORD dwFlags,
1736         DWORD *pvContext)
1737 {
1738     IFilterGraphImpl *This = impl_from_IFilterGraph2(iface);
1739
1740     TRACE("(%p/%p)->(%p %08x %p): stub !!!\n", This, iface, pPinOut, dwFlags, pvContext);
1741
1742     return S_OK;
1743 }
1744
1745
1746 static const IFilterGraph2Vtbl IFilterGraph2_VTable =
1747 {
1748     FilterGraph2_QueryInterface,
1749     FilterGraph2_AddRef,
1750     FilterGraph2_Release,
1751     FilterGraph2_AddFilter,
1752     FilterGraph2_RemoveFilter,
1753     FilterGraph2_EnumFilters,
1754     FilterGraph2_FindFilterByName,
1755     FilterGraph2_ConnectDirect,
1756     FilterGraph2_Reconnect,
1757     FilterGraph2_Disconnect,
1758     FilterGraph2_SetDefaultSyncSource,
1759     FilterGraph2_Connect,
1760     FilterGraph2_Render,
1761     FilterGraph2_RenderFile,
1762     FilterGraph2_AddSourceFilter,
1763     FilterGraph2_SetLogFile,
1764     FilterGraph2_Abort,
1765     FilterGraph2_ShouldOperationContinue,
1766     FilterGraph2_AddSourceFilterForMoniker,
1767     FilterGraph2_ReconnectEx,
1768     FilterGraph2_RenderEx
1769 };
1770
1771 static inline IFilterGraphImpl *impl_from_IMediaControl(IMediaControl *iface)
1772 {
1773     return CONTAINING_RECORD(iface, IFilterGraphImpl, IMediaControl_iface);
1774 }
1775
1776 static HRESULT WINAPI MediaControl_QueryInterface(IMediaControl *iface, REFIID riid, void **ppvObj)
1777 {
1778     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
1779
1780     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1781
1782     return Filtergraph_QueryInterface(This, riid, ppvObj);
1783 }
1784
1785 static ULONG WINAPI MediaControl_AddRef(IMediaControl *iface)
1786 {
1787     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
1788
1789     TRACE("(%p/%p)->()\n", This, iface);
1790
1791     return Filtergraph_AddRef(This);
1792 }
1793
1794 static ULONG WINAPI MediaControl_Release(IMediaControl *iface)
1795 {
1796     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
1797
1798     TRACE("(%p/%p)->()\n", This, iface);
1799
1800     return Filtergraph_Release(This);
1801
1802 }
1803
1804 /*** IDispatch methods ***/
1805 static HRESULT WINAPI MediaControl_GetTypeInfoCount(IMediaControl *iface, UINT *pctinfo)
1806 {
1807     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
1808
1809     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
1810
1811     return S_OK;
1812 }
1813
1814 static HRESULT WINAPI MediaControl_GetTypeInfo(IMediaControl *iface, UINT iTInfo, LCID lcid,
1815         ITypeInfo **ppTInfo)
1816 {
1817     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
1818
1819     TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
1820
1821     return S_OK;
1822 }
1823
1824 static HRESULT WINAPI MediaControl_GetIDsOfNames(IMediaControl *iface, REFIID riid,
1825         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
1826 {
1827     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
1828
1829     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
1830
1831     return S_OK;
1832 }
1833
1834 static HRESULT WINAPI MediaControl_Invoke(IMediaControl *iface, DISPID dispIdMember, REFIID riid,
1835         LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExepInfo,
1836         UINT *puArgErr)
1837 {
1838     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
1839
1840     TRACE("(%p/%p)->(%d, %s (%p), %d, %04x, %p, %p, %p, %p): stub !!!\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
1841
1842     return S_OK;
1843 }
1844
1845 typedef HRESULT(WINAPI *fnFoundFilter)(IBaseFilter *, DWORD_PTR data);
1846
1847 static HRESULT ExploreGraph(IFilterGraphImpl* pGraph, IPin* pOutputPin, fnFoundFilter FoundFilter, DWORD_PTR data)
1848 {
1849     HRESULT hr;
1850     IPin* pInputPin;
1851     IPin** ppPins;
1852     ULONG nb;
1853     ULONG i;
1854     PIN_INFO PinInfo;
1855
1856     TRACE("%p %p\n", pGraph, pOutputPin);
1857     PinInfo.pFilter = NULL;
1858
1859     hr = IPin_ConnectedTo(pOutputPin, &pInputPin);
1860
1861     if (SUCCEEDED(hr))
1862     {
1863         hr = IPin_QueryPinInfo(pInputPin, &PinInfo);
1864         if (SUCCEEDED(hr))
1865             hr = GetInternalConnections(PinInfo.pFilter, pInputPin, &ppPins, &nb);
1866         IPin_Release(pInputPin);
1867     }
1868
1869     if (SUCCEEDED(hr))
1870     {
1871         if (nb == 0)
1872         {
1873             TRACE("Reached a renderer\n");
1874             /* Count renderers for end of stream notification */
1875             pGraph->nRenderers++;
1876         }
1877         else
1878         {
1879             for(i = 0; i < nb; i++)
1880             {
1881                 /* Explore the graph downstream from this pin
1882                  * FIXME: We should prevent exploring from a pin more than once. This can happens when
1883                  * several input pins are connected to the same output (a MUX for instance). */
1884                 ExploreGraph(pGraph, ppPins[i], FoundFilter, data);
1885                 IPin_Release(ppPins[i]);
1886             }
1887
1888             CoTaskMemFree(ppPins);
1889         }
1890         TRACE("Doing stuff with filter %p\n", PinInfo.pFilter);
1891
1892         FoundFilter(PinInfo.pFilter, data);
1893     }
1894
1895     if (PinInfo.pFilter) IBaseFilter_Release(PinInfo.pFilter);
1896     return hr;
1897 }
1898
1899 static HRESULT WINAPI SendRun(IBaseFilter *pFilter, DWORD_PTR data)
1900 {
1901     REFERENCE_TIME time = *(REFERENCE_TIME*)data;
1902     return IBaseFilter_Run(pFilter, time);
1903 }
1904
1905 static HRESULT WINAPI SendPause(IBaseFilter *pFilter, DWORD_PTR data)
1906 {
1907     return IBaseFilter_Pause(pFilter);
1908 }
1909
1910 static HRESULT WINAPI SendStop(IBaseFilter *pFilter, DWORD_PTR data)
1911 {
1912     return IBaseFilter_Stop(pFilter);
1913 }
1914
1915 static HRESULT WINAPI SendGetState(IBaseFilter *pFilter, DWORD_PTR data)
1916 {
1917     FILTER_STATE state;
1918     DWORD time_end = data;
1919     DWORD time_now = GetTickCount();
1920     LONG wait;
1921
1922     if (time_end == INFINITE)
1923     {
1924         wait = INFINITE;
1925     }
1926     else if (time_end > time_now)
1927     {
1928         wait = time_end - time_now;
1929     }
1930     else
1931         wait = 0;
1932
1933     return IBaseFilter_GetState(pFilter, wait, &state);
1934 }
1935
1936
1937 static HRESULT SendFilterMessage(IFilterGraphImpl *This, fnFoundFilter FoundFilter, DWORD_PTR data)
1938 {
1939     int i;
1940     IBaseFilter* pfilter;
1941     IEnumPins* pEnum;
1942     HRESULT hr;
1943     IPin* pPin;
1944     DWORD dummy;
1945     PIN_DIRECTION dir;
1946
1947     TRACE("(%p)->()\n", This);
1948
1949     /* Explorer the graph from source filters to renderers, determine renderers
1950      * number and run filters from renderers to source filters */
1951     This->nRenderers = 0;
1952     ResetEvent(This->hEventCompletion);
1953
1954     for(i = 0; i < This->nFilters; i++)
1955     {
1956         BOOL source = TRUE;
1957         pfilter = This->ppFiltersInGraph[i];
1958         hr = IBaseFilter_EnumPins(pfilter, &pEnum);
1959         if (hr != S_OK)
1960         {
1961             WARN("Enum pins failed %x\n", hr);
1962             continue;
1963         }
1964         /* Check if it is a source filter */
1965         while(IEnumPins_Next(pEnum, 1, &pPin, &dummy) == S_OK)
1966         {
1967             IPin_QueryDirection(pPin, &dir);
1968             IPin_Release(pPin);
1969             if (dir == PINDIR_INPUT)
1970             {
1971                 source = FALSE;
1972                 break;
1973             }
1974         }
1975         if (source)
1976         {
1977             TRACE("Found a source filter %p\n", pfilter);
1978             IEnumPins_Reset(pEnum);
1979             while(IEnumPins_Next(pEnum, 1, &pPin, &dummy) == S_OK)
1980             {
1981                 /* Explore the graph downstream from this pin */
1982                 ExploreGraph(This, pPin, FoundFilter, data);
1983                 IPin_Release(pPin);
1984             }
1985             FoundFilter(pfilter, data);
1986         }
1987         IEnumPins_Release(pEnum);
1988     }
1989
1990     return S_FALSE;
1991 }
1992
1993 /*** IMediaControl methods ***/
1994 static HRESULT WINAPI MediaControl_Run(IMediaControl *iface)
1995 {
1996     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
1997
1998     TRACE("(%p/%p)->()\n", This, iface);
1999
2000     EnterCriticalSection(&This->cs);
2001     if (This->state == State_Running)
2002         goto out;
2003     This->EcCompleteCount = 0;
2004
2005     if (This->defaultclock && !This->refClock)
2006         IFilterGraph2_SetDefaultSyncSource((IFilterGraph2*)This);
2007
2008     if (This->refClock)
2009     {
2010         REFERENCE_TIME now;
2011         IReferenceClock_GetTime(This->refClock, &now);
2012         if (This->state == State_Stopped)
2013             This->start_time = now + 500000;
2014         else if (This->pause_time >= 0)
2015             This->start_time += now - This->pause_time;
2016         else
2017             This->start_time = now;
2018     }
2019     else This->start_time = 0;
2020
2021     SendFilterMessage(This, SendRun, (DWORD_PTR)&This->start_time);
2022     This->state = State_Running;
2023 out:
2024     LeaveCriticalSection(&This->cs);
2025     return S_FALSE;
2026 }
2027
2028 static HRESULT WINAPI MediaControl_Pause(IMediaControl *iface)
2029 {
2030     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
2031
2032     TRACE("(%p/%p)->()\n", This, iface);
2033
2034     EnterCriticalSection(&This->cs);
2035     if (This->state == State_Paused)
2036         goto out;
2037
2038     if (This->state == State_Running && This->refClock && This->start_time >= 0)
2039         IReferenceClock_GetTime(This->refClock, &This->pause_time);
2040     else
2041         This->pause_time = -1;
2042
2043     SendFilterMessage(This, SendPause, 0);
2044     This->state = State_Paused;
2045 out:
2046     LeaveCriticalSection(&This->cs);
2047     return S_FALSE;
2048 }
2049
2050 static HRESULT WINAPI MediaControl_Stop(IMediaControl *iface)
2051 {
2052     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
2053
2054     TRACE("(%p/%p)->()\n", This, iface);
2055
2056     if (This->state == State_Stopped) return S_OK;
2057
2058     EnterCriticalSection(&This->cs);
2059     if (This->state == State_Running) SendFilterMessage(This, SendPause, 0);
2060     SendFilterMessage(This, SendStop, 0);
2061     This->state = State_Stopped;
2062     LeaveCriticalSection(&This->cs);
2063     return S_OK;
2064 }
2065
2066 static HRESULT WINAPI MediaControl_GetState(IMediaControl *iface, LONG msTimeout,
2067         OAFilterState *pfs)
2068 {
2069     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
2070     DWORD end;
2071
2072     TRACE("(%p/%p)->(%d, %p)\n", This, iface, msTimeout, pfs);
2073
2074     if (!pfs)
2075         return E_POINTER;
2076
2077     EnterCriticalSection(&This->cs);
2078
2079     *pfs = This->state;
2080     if (msTimeout > 0)
2081     {
2082         end = GetTickCount() + msTimeout;
2083     }
2084     else if (msTimeout < 0)
2085     {
2086         end = INFINITE;
2087     }
2088     else
2089     {
2090         end = 0;
2091     }
2092     if (end)
2093         SendFilterMessage(This, SendGetState, end);
2094
2095     LeaveCriticalSection(&This->cs);
2096
2097     return S_OK;
2098 }
2099
2100 static HRESULT WINAPI MediaControl_RenderFile(IMediaControl *iface, BSTR strFilename)
2101 {
2102     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
2103
2104     FIXME("(%p/%p)->(%s (%p)): stub !!!\n", This, iface, debugstr_w(strFilename), strFilename);
2105
2106     return S_OK;
2107 }
2108
2109 static HRESULT WINAPI MediaControl_AddSourceFilter(IMediaControl *iface, BSTR strFilename,
2110         IDispatch **ppUnk)
2111 {
2112     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
2113
2114     FIXME("(%p/%p)->(%s (%p), %p): stub !!!\n", This, iface, debugstr_w(strFilename), strFilename, ppUnk);
2115
2116     return S_OK;
2117 }
2118
2119 static HRESULT WINAPI MediaControl_get_FilterCollection(IMediaControl *iface, IDispatch **ppUnk)
2120 {
2121     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
2122
2123     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, ppUnk);
2124
2125     return S_OK;
2126 }
2127
2128 static HRESULT WINAPI MediaControl_get_RegFilterCollection(IMediaControl *iface, IDispatch **ppUnk)
2129 {
2130     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
2131
2132     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, ppUnk);
2133
2134     return S_OK;
2135 }
2136
2137 static HRESULT WINAPI MediaControl_StopWhenReady(IMediaControl *iface)
2138 {
2139     IFilterGraphImpl *This = impl_from_IMediaControl(iface);
2140
2141     FIXME("(%p/%p)->(): stub !!!\n", This, iface);
2142
2143     return S_OK;
2144 }
2145
2146
2147 static const IMediaControlVtbl IMediaControl_VTable =
2148 {
2149     MediaControl_QueryInterface,
2150     MediaControl_AddRef,
2151     MediaControl_Release,
2152     MediaControl_GetTypeInfoCount,
2153     MediaControl_GetTypeInfo,
2154     MediaControl_GetIDsOfNames,
2155     MediaControl_Invoke,
2156     MediaControl_Run,
2157     MediaControl_Pause,
2158     MediaControl_Stop,
2159     MediaControl_GetState,
2160     MediaControl_RenderFile,
2161     MediaControl_AddSourceFilter,
2162     MediaControl_get_FilterCollection,
2163     MediaControl_get_RegFilterCollection,
2164     MediaControl_StopWhenReady
2165 };
2166
2167 static inline IFilterGraphImpl *impl_from_IMediaSeeking(IMediaSeeking *iface)
2168 {
2169     return CONTAINING_RECORD(iface, IFilterGraphImpl, IMediaSeeking_iface);
2170 }
2171
2172 static HRESULT WINAPI MediaSeeking_QueryInterface(IMediaSeeking *iface, REFIID riid, void **ppvObj)
2173 {
2174     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2175
2176     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
2177
2178     return Filtergraph_QueryInterface(This, riid, ppvObj);
2179 }
2180
2181 static ULONG WINAPI MediaSeeking_AddRef(IMediaSeeking *iface)
2182 {
2183     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2184
2185     TRACE("(%p/%p)->()\n", This, iface);
2186
2187     return Filtergraph_AddRef(This);
2188 }
2189
2190 static ULONG WINAPI MediaSeeking_Release(IMediaSeeking *iface)
2191 {
2192     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2193
2194     TRACE("(%p/%p)->()\n", This, iface);
2195
2196     return Filtergraph_Release(This);
2197 }
2198
2199 typedef HRESULT (WINAPI *fnFoundSeek)(IFilterGraphImpl *This, IMediaSeeking*, DWORD_PTR arg);
2200
2201 static HRESULT all_renderers_seek(IFilterGraphImpl *This, fnFoundSeek FoundSeek, DWORD_PTR arg) {
2202     BOOL allnotimpl = TRUE;
2203     int i;
2204     HRESULT hr, hr_return = S_OK;
2205
2206     TRACE("(%p)->(%p %08lx)\n", This, FoundSeek, arg);
2207     /* Send a message to all renderers, they are responsible for broadcasting it further */
2208
2209     for(i = 0; i < This->nFilters; i++)
2210     {
2211         IMediaSeeking *seek = NULL;
2212         IBaseFilter* pfilter = This->ppFiltersInGraph[i];
2213         IAMFilterMiscFlags *flags = NULL;
2214         ULONG filterflags;
2215         IUnknown_QueryInterface(pfilter, &IID_IAMFilterMiscFlags, (void**)&flags);
2216         if (!flags)
2217             continue;
2218         filterflags = IAMFilterMiscFlags_GetMiscFlags(flags);
2219         IUnknown_Release(flags);
2220         if (filterflags != AM_FILTER_MISC_FLAGS_IS_RENDERER)
2221             continue;
2222
2223         IBaseFilter_QueryInterface(pfilter, &IID_IMediaSeeking, (void**)&seek);
2224         if (!seek)
2225             continue;
2226         hr = FoundSeek(This, seek, arg);
2227         IMediaSeeking_Release(seek);
2228         if (hr_return != E_NOTIMPL)
2229             allnotimpl = FALSE;
2230         if (hr_return == S_OK || (FAILED(hr) && hr != E_NOTIMPL && SUCCEEDED(hr_return)))
2231             hr_return = hr;
2232     }
2233
2234     if (allnotimpl)
2235         return E_NOTIMPL;
2236     return hr_return;
2237 }
2238
2239 static HRESULT WINAPI FoundCapabilities(IFilterGraphImpl *This, IMediaSeeking *seek, DWORD_PTR pcaps)
2240 {
2241     HRESULT hr;
2242     DWORD caps = 0;
2243
2244     hr = IMediaSeeking_GetCapabilities(seek, &caps);
2245     if (FAILED(hr))
2246         return hr;
2247
2248     /* Only add common capabilities everything supports */
2249     *(DWORD*)pcaps &= caps;
2250
2251     return hr;
2252 }
2253
2254 /*** IMediaSeeking methods ***/
2255 static HRESULT WINAPI MediaSeeking_GetCapabilities(IMediaSeeking *iface, DWORD *pCapabilities)
2256 {
2257     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2258     HRESULT hr;
2259
2260     TRACE("(%p/%p)->(%p)\n", This, iface, pCapabilities);
2261
2262     if (!pCapabilities)
2263         return E_POINTER;
2264
2265     EnterCriticalSection(&This->cs);
2266     *pCapabilities = 0xffffffff;
2267
2268     hr = all_renderers_seek(This, FoundCapabilities, (DWORD_PTR)pCapabilities);
2269     LeaveCriticalSection(&This->cs);
2270
2271     return hr;
2272 }
2273
2274 static HRESULT WINAPI MediaSeeking_CheckCapabilities(IMediaSeeking *iface, DWORD *pCapabilities)
2275 {
2276     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2277     DWORD originalcaps;
2278     HRESULT hr;
2279
2280     TRACE("(%p/%p)->(%p)\n", This, iface, pCapabilities);
2281
2282     if (!pCapabilities)
2283         return E_POINTER;
2284
2285     EnterCriticalSection(&This->cs);
2286     originalcaps = *pCapabilities;
2287     hr = all_renderers_seek(This, FoundCapabilities, (DWORD_PTR)pCapabilities);
2288     LeaveCriticalSection(&This->cs);
2289
2290     if (FAILED(hr))
2291         return hr;
2292
2293     if (!*pCapabilities)
2294         return E_FAIL;
2295     if (*pCapabilities != originalcaps)
2296         return S_FALSE;
2297     return S_OK;
2298 }
2299
2300 static HRESULT WINAPI MediaSeeking_IsFormatSupported(IMediaSeeking *iface, const GUID *pFormat)
2301 {
2302     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2303
2304     if (!pFormat)
2305         return E_POINTER;
2306
2307     TRACE("(%p/%p)->(%s)\n", This, iface, debugstr_guid(pFormat));
2308
2309     if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, pFormat))
2310     {
2311         FIXME("Unhandled time format %s\n", debugstr_guid(pFormat));
2312         return S_FALSE;
2313     }
2314
2315     return S_OK;
2316 }
2317
2318 static HRESULT WINAPI MediaSeeking_QueryPreferredFormat(IMediaSeeking *iface, GUID *pFormat)
2319 {
2320     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2321
2322     if (!pFormat)
2323         return E_POINTER;
2324
2325     FIXME("(%p/%p)->(%p): semi-stub !!!\n", This, iface, pFormat);
2326     memcpy(pFormat, &TIME_FORMAT_MEDIA_TIME, sizeof(GUID));
2327
2328     return S_OK;
2329 }
2330
2331 static HRESULT WINAPI MediaSeeking_GetTimeFormat(IMediaSeeking *iface, GUID *pFormat)
2332 {
2333     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2334
2335     if (!pFormat)
2336         return E_POINTER;
2337
2338     TRACE("(%p/%p)->(%p)\n", This, iface, pFormat);
2339     memcpy(pFormat, &This->timeformatseek, sizeof(GUID));
2340
2341     return S_OK;
2342 }
2343
2344 static HRESULT WINAPI MediaSeeking_IsUsingTimeFormat(IMediaSeeking *iface, const GUID *pFormat)
2345 {
2346     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2347
2348     TRACE("(%p/%p)->(%p)\n", This, iface, pFormat);
2349     if (!pFormat)
2350         return E_POINTER;
2351
2352     if (memcmp(pFormat, &This->timeformatseek, sizeof(GUID)))
2353         return S_FALSE;
2354
2355     return S_OK;
2356 }
2357
2358 static HRESULT WINAPI MediaSeeking_SetTimeFormat(IMediaSeeking *iface, const GUID *pFormat)
2359 {
2360     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2361
2362     if (!pFormat)
2363         return E_POINTER;
2364
2365     TRACE("(%p/%p)->(%s)\n", This, iface, debugstr_guid(pFormat));
2366
2367     if (This->state != State_Stopped)
2368         return VFW_E_WRONG_STATE;
2369
2370     if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, pFormat))
2371     {
2372         FIXME("Unhandled time format %s\n", debugstr_guid(pFormat));
2373         return E_INVALIDARG;
2374     }
2375
2376     return S_OK;
2377 }
2378
2379 static HRESULT WINAPI FoundDuration(IFilterGraphImpl *This, IMediaSeeking *seek, DWORD_PTR pduration)
2380 {
2381     HRESULT hr;
2382     LONGLONG duration = 0, *pdur = (LONGLONG*)pduration;
2383
2384     hr = IMediaSeeking_GetDuration(seek, &duration);
2385     if (FAILED(hr))
2386         return hr;
2387
2388     if (*pdur < duration)
2389         *pdur = duration;
2390     return hr;
2391 }
2392
2393 static HRESULT WINAPI MediaSeeking_GetDuration(IMediaSeeking *iface, LONGLONG *pDuration)
2394 {
2395     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2396     HRESULT hr;
2397
2398     TRACE("(%p/%p)->(%p)\n", This, iface, pDuration);
2399
2400     if (!pDuration)
2401         return E_POINTER;
2402
2403     EnterCriticalSection(&This->cs);
2404     *pDuration = 0;
2405     hr = all_renderers_seek(This, FoundDuration, (DWORD_PTR)pDuration);
2406     LeaveCriticalSection(&This->cs);
2407
2408     TRACE("--->%08x\n", hr);
2409     return hr;
2410 }
2411
2412 static HRESULT WINAPI MediaSeeking_GetStopPosition(IMediaSeeking *iface, LONGLONG *pStop)
2413 {
2414     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2415     HRESULT hr = S_OK;
2416
2417     TRACE("(%p/%p)->(%p)\n", This, iface, pStop);
2418
2419     if (!pStop)
2420         return E_POINTER;
2421
2422     EnterCriticalSection(&This->cs);
2423     if (This->stop_position < 0)
2424         /* Stop position not set, use duration instead */
2425         hr = IMediaSeeking_GetDuration(iface, pStop);
2426     else
2427         *pStop = This->stop_position;
2428     LeaveCriticalSection(&This->cs);
2429
2430     return hr;
2431 }
2432
2433 static HRESULT WINAPI FoundCurrentPosition(IFilterGraphImpl *This, IMediaSeeking *seek, DWORD_PTR pposition)
2434 {
2435     HRESULT hr;
2436     LONGLONG pos = 0, *ppos = (LONGLONG*)pposition;
2437
2438     hr = IMediaSeeking_GetCurrentPosition(seek, &pos);
2439     if (FAILED(hr))
2440         return hr;
2441
2442     if (*ppos < 0 || pos < *ppos)
2443         *ppos = pos;
2444     return hr;
2445 }
2446
2447 static HRESULT WINAPI MediaSeeking_GetCurrentPosition(IMediaSeeking *iface, LONGLONG *pCurrent)
2448 {
2449     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2450     HRESULT hr;
2451
2452     if (!pCurrent)
2453         return E_POINTER;
2454
2455     EnterCriticalSection(&This->cs);
2456     *pCurrent = -1;
2457     hr = all_renderers_seek(This, FoundCurrentPosition, (DWORD_PTR)pCurrent);
2458     if (hr == E_NOTIMPL) {
2459         *pCurrent = 0;
2460         hr = S_OK;
2461     }
2462     LeaveCriticalSection(&This->cs);
2463
2464     TRACE("Time: %u.%03u\n", (DWORD)(*pCurrent / 10000000), (DWORD)((*pCurrent / 10000)%1000));
2465
2466     return hr;
2467 }
2468
2469 static HRESULT WINAPI MediaSeeking_ConvertTimeFormat(IMediaSeeking *iface, LONGLONG *pTarget,
2470         const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat)
2471 {
2472     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2473
2474     FIXME("(%p/%p)->(%p, %p, 0x%s, %p): stub !!!\n", This, iface, pTarget,
2475         pTargetFormat, wine_dbgstr_longlong(Source), pSourceFormat);
2476
2477     return S_OK;
2478 }
2479
2480 struct pos_args {
2481     LONGLONG* current, *stop;
2482     DWORD curflags, stopflags;
2483 };
2484
2485 static HRESULT WINAPI found_setposition(IFilterGraphImpl *This, IMediaSeeking *seek, DWORD_PTR pargs)
2486 {
2487     struct pos_args *args = (void*)pargs;
2488
2489     return IMediaSeeking_SetPositions(seek, args->current, args->curflags, args->stop, args->stopflags);
2490 }
2491
2492 static HRESULT WINAPI MediaSeeking_SetPositions(IMediaSeeking *iface, LONGLONG *pCurrent,
2493         DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags)
2494 {
2495     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2496     HRESULT hr = S_OK;
2497     FILTER_STATE state;
2498     struct pos_args args;
2499
2500     TRACE("(%p/%p)->(%p, %08x, %p, %08x)\n", This, iface, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
2501
2502     EnterCriticalSection(&This->cs);
2503     state = This->state;
2504     TRACE("State: %s\n", state == State_Running ? "Running" : (state == State_Paused ? "Paused" : (state == State_Stopped ? "Stopped" : "UNKNOWN")));
2505
2506     if ((dwCurrentFlags & 0x7) != AM_SEEKING_AbsolutePositioning &&
2507         (dwCurrentFlags & 0x7) != AM_SEEKING_NoPositioning)
2508         FIXME("Adjust method %x not handled yet!\n", dwCurrentFlags & 0x7);
2509
2510     if ((dwStopFlags & 0x7) == AM_SEEKING_AbsolutePositioning)
2511         This->stop_position = *pStop;
2512     else if ((dwStopFlags & 0x7) != AM_SEEKING_NoPositioning)
2513         FIXME("Stop position not handled yet!\n");
2514
2515     if (state == State_Running && !(dwCurrentFlags & AM_SEEKING_NoFlush))
2516         IMediaControl_Pause(&This->IMediaControl_iface);
2517     args.current = pCurrent;
2518     args.stop = pStop;
2519     args.curflags = dwCurrentFlags;
2520     args.stopflags = dwStopFlags;
2521     hr = all_renderers_seek(This, found_setposition, (DWORD_PTR)&args);
2522
2523     if ((dwCurrentFlags & 0x7) != AM_SEEKING_NoPositioning)
2524         This->pause_time = This->start_time = -1;
2525     if (state == State_Running && !(dwCurrentFlags & AM_SEEKING_NoFlush))
2526         IMediaControl_Run(&This->IMediaControl_iface);
2527     LeaveCriticalSection(&This->cs);
2528
2529     return hr;
2530 }
2531
2532 static HRESULT WINAPI MediaSeeking_GetPositions(IMediaSeeking *iface, LONGLONG *pCurrent,
2533         LONGLONG *pStop)
2534 {
2535     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2536     HRESULT hr;
2537
2538     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pCurrent, pStop);
2539     hr = IMediaSeeking_GetCurrentPosition(iface, pCurrent);
2540     if (SUCCEEDED(hr))
2541         hr = IMediaSeeking_GetStopPosition(iface, pStop);
2542
2543     return hr;
2544 }
2545
2546 static HRESULT WINAPI MediaSeeking_GetAvailable(IMediaSeeking *iface, LONGLONG *pEarliest,
2547         LONGLONG *pLatest)
2548 {
2549     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2550
2551     FIXME("(%p/%p)->(%p, %p): stub !!!\n", This, iface, pEarliest, pLatest);
2552
2553     return S_OK;
2554 }
2555
2556 static HRESULT WINAPI MediaSeeking_SetRate(IMediaSeeking *iface, double dRate)
2557 {
2558     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2559
2560     FIXME("(%p/%p)->(%f): stub !!!\n", This, iface, dRate);
2561
2562     return S_OK;
2563 }
2564
2565 static HRESULT WINAPI MediaSeeking_GetRate(IMediaSeeking *iface, double *pdRate)
2566 {
2567     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2568
2569     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pdRate);
2570
2571     return S_OK;
2572 }
2573
2574 static HRESULT WINAPI MediaSeeking_GetPreroll(IMediaSeeking *iface, LONGLONG *pllPreroll)
2575 {
2576     IFilterGraphImpl *This = impl_from_IMediaSeeking(iface);
2577
2578     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pllPreroll);
2579
2580     return S_OK;
2581 }
2582
2583
2584 static const IMediaSeekingVtbl IMediaSeeking_VTable =
2585 {
2586     MediaSeeking_QueryInterface,
2587     MediaSeeking_AddRef,
2588     MediaSeeking_Release,
2589     MediaSeeking_GetCapabilities,
2590     MediaSeeking_CheckCapabilities,
2591     MediaSeeking_IsFormatSupported,
2592     MediaSeeking_QueryPreferredFormat,
2593     MediaSeeking_GetTimeFormat,
2594     MediaSeeking_IsUsingTimeFormat,
2595     MediaSeeking_SetTimeFormat,
2596     MediaSeeking_GetDuration,
2597     MediaSeeking_GetStopPosition,
2598     MediaSeeking_GetCurrentPosition,
2599     MediaSeeking_ConvertTimeFormat,
2600     MediaSeeking_SetPositions,
2601     MediaSeeking_GetPositions,
2602     MediaSeeking_GetAvailable,
2603     MediaSeeking_SetRate,
2604     MediaSeeking_GetRate,
2605     MediaSeeking_GetPreroll
2606 };
2607
2608 static inline IFilterGraphImpl *impl_from_IMediaPosition(IMediaPosition *iface)
2609 {
2610     return CONTAINING_RECORD(iface, IFilterGraphImpl, IMediaPosition_iface);
2611 }
2612
2613 /*** IUnknown methods ***/
2614 static HRESULT WINAPI MediaPosition_QueryInterface(IMediaPosition* iface, REFIID riid, void** ppvObj)
2615 {
2616     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2617
2618     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
2619     return Filtergraph_QueryInterface(This, riid, ppvObj);
2620 }
2621
2622 static ULONG WINAPI MediaPosition_AddRef(IMediaPosition *iface)
2623 {
2624     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2625
2626     TRACE("(%p/%p)->()\n", This, iface);
2627     return Filtergraph_AddRef(This);
2628 }
2629
2630 static ULONG WINAPI MediaPosition_Release(IMediaPosition *iface)
2631 {
2632     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2633
2634     TRACE("(%p/%p)->()\n", This, iface);
2635     return Filtergraph_Release(This);
2636 }
2637
2638 /*** IDispatch methods ***/
2639 static HRESULT WINAPI MediaPosition_GetTypeInfoCount(IMediaPosition *iface, UINT* pctinfo){
2640     FIXME("(%p) stub!\n", iface);
2641     return E_NOTIMPL;
2642 }
2643
2644 static HRESULT WINAPI MediaPosition_GetTypeInfo(IMediaPosition *iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo){
2645     FIXME("(%p) stub!\n", iface);
2646     return E_NOTIMPL;
2647 }
2648
2649 static HRESULT WINAPI MediaPosition_GetIDsOfNames(IMediaPosition* iface, REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId){
2650     FIXME("(%p) stub!\n", iface);
2651     return E_NOTIMPL;
2652 }
2653
2654 static HRESULT WINAPI MediaPosition_Invoke(IMediaPosition* iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr){
2655     FIXME("(%p) stub!\n", iface);
2656     return E_NOTIMPL;
2657 }
2658
2659 static HRESULT ConvertFromREFTIME(IMediaSeeking *seek, REFTIME time_in, LONGLONG *time_out)
2660 {
2661     GUID time_format;
2662     HRESULT hr;
2663
2664     hr = MediaSeeking_GetTimeFormat(seek, &time_format);
2665     if (FAILED(hr))
2666         return hr;
2667     if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, &time_format))
2668     {
2669         FIXME("Unsupported time format.\n");
2670         return E_NOTIMPL;
2671     }
2672
2673     *time_out = (LONGLONG) (time_in * 10000000); /* convert from 1 second intervals to 100 ns intervals */
2674     return S_OK;
2675 }
2676
2677 static HRESULT ConvertToREFTIME(IMediaSeeking *seek, LONGLONG time_in, REFTIME *time_out)
2678 {
2679     GUID time_format;
2680     HRESULT hr;
2681
2682     hr = MediaSeeking_GetTimeFormat(seek, &time_format);
2683     if (FAILED(hr))
2684         return hr;
2685     if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, &time_format))
2686     {
2687         FIXME("Unsupported time format.\n");
2688         return E_NOTIMPL;
2689     }
2690
2691     *time_out = (REFTIME)time_in / 10000000; /* convert from 100 ns intervals to 1 second intervals */
2692     return S_OK;
2693 }
2694
2695 /*** IMediaPosition methods ***/
2696 static HRESULT WINAPI MediaPosition_get_Duration(IMediaPosition * iface, REFTIME *plength)
2697 {
2698     LONGLONG duration;
2699     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2700     HRESULT hr = IMediaSeeking_GetDuration(&This->IMediaSeeking_iface, &duration);
2701     if (FAILED(hr))
2702         return hr;
2703     return ConvertToREFTIME(&This->IMediaSeeking_iface, duration, plength);
2704 }
2705
2706 static HRESULT WINAPI MediaPosition_put_CurrentPosition(IMediaPosition * iface, REFTIME llTime)
2707 {
2708     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2709     LONGLONG reftime;
2710     HRESULT hr;
2711
2712     hr = ConvertFromREFTIME(&This->IMediaSeeking_iface, llTime, &reftime);
2713     if (FAILED(hr))
2714         return hr;
2715     return IMediaSeeking_SetPositions(&This->IMediaSeeking_iface, &reftime,
2716             AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning);
2717 }
2718
2719 static HRESULT WINAPI MediaPosition_get_CurrentPosition(IMediaPosition * iface, REFTIME *pllTime)
2720 {
2721     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2722     LONGLONG pos;
2723     HRESULT hr;
2724
2725     hr = IMediaSeeking_GetCurrentPosition(&This->IMediaSeeking_iface, &pos);
2726     if (FAILED(hr))
2727         return hr;
2728     return ConvertToREFTIME(&This->IMediaSeeking_iface, pos, pllTime);
2729 }
2730
2731 static HRESULT WINAPI MediaPosition_get_StopTime(IMediaPosition * iface, REFTIME *pllTime)
2732 {
2733     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2734     LONGLONG pos;
2735     HRESULT hr = IMediaSeeking_GetStopPosition(&This->IMediaSeeking_iface, &pos);
2736     if (FAILED(hr))
2737         return hr;
2738     return ConvertToREFTIME(&This->IMediaSeeking_iface, pos, pllTime);
2739 }
2740
2741 static HRESULT WINAPI MediaPosition_put_StopTime(IMediaPosition * iface, REFTIME llTime)
2742 {
2743     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2744     LONGLONG reftime;
2745     HRESULT hr;
2746
2747     hr = ConvertFromREFTIME(&This->IMediaSeeking_iface, llTime, &reftime);
2748     if (FAILED(hr))
2749         return hr;
2750     return IMediaSeeking_SetPositions(&This->IMediaSeeking_iface, NULL, AM_SEEKING_NoPositioning,
2751             &reftime, AM_SEEKING_AbsolutePositioning);
2752 }
2753
2754 static HRESULT WINAPI MediaPosition_get_PrerollTime(IMediaPosition * iface, REFTIME *pllTime){
2755     FIXME("(%p)->(%p) stub!\n", iface, pllTime);
2756     return E_NOTIMPL;
2757 }
2758
2759 static HRESULT WINAPI MediaPosition_put_PrerollTime(IMediaPosition * iface, REFTIME llTime){
2760     FIXME("(%p)->(%f) stub!\n", iface, llTime);
2761     return E_NOTIMPL;
2762 }
2763
2764 static HRESULT WINAPI MediaPosition_put_Rate(IMediaPosition * iface, double dRate)
2765 {
2766     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2767     return IMediaSeeking_SetRate(&This->IMediaSeeking_iface, dRate);
2768 }
2769
2770 static HRESULT WINAPI MediaPosition_get_Rate(IMediaPosition * iface, double *pdRate)
2771 {
2772     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
2773     return IMediaSeeking_GetRate(&This->IMediaSeeking_iface, pdRate);
2774 }
2775
2776 static HRESULT WINAPI MediaPosition_CanSeekForward(IMediaPosition * iface, LONG *pCanSeekForward){
2777     FIXME("(%p)->(%p) stub!\n", iface, pCanSeekForward);
2778     return E_NOTIMPL;
2779 }
2780
2781 static HRESULT WINAPI MediaPosition_CanSeekBackward(IMediaPosition * iface, LONG *pCanSeekBackward){
2782     FIXME("(%p)->(%p) stub!\n", iface, pCanSeekBackward);
2783     return E_NOTIMPL;
2784 }
2785
2786
2787 static const IMediaPositionVtbl IMediaPosition_VTable =
2788 {
2789     MediaPosition_QueryInterface,
2790     MediaPosition_AddRef,
2791     MediaPosition_Release,
2792     MediaPosition_GetTypeInfoCount,
2793     MediaPosition_GetTypeInfo,
2794     MediaPosition_GetIDsOfNames,
2795     MediaPosition_Invoke,
2796     MediaPosition_get_Duration,
2797     MediaPosition_put_CurrentPosition,
2798     MediaPosition_get_CurrentPosition,
2799     MediaPosition_get_StopTime,
2800     MediaPosition_put_StopTime,
2801     MediaPosition_get_PrerollTime,
2802     MediaPosition_put_PrerollTime,
2803     MediaPosition_put_Rate,
2804     MediaPosition_get_Rate,
2805     MediaPosition_CanSeekForward,
2806     MediaPosition_CanSeekBackward
2807 };
2808
2809 static inline IFilterGraphImpl *impl_from_IObjectWithSite(IObjectWithSite *iface)
2810 {
2811     return CONTAINING_RECORD(iface, IFilterGraphImpl, IObjectWithSite_iface);
2812 }
2813
2814 /*** IUnknown methods ***/
2815 static HRESULT WINAPI ObjectWithSite_QueryInterface(IObjectWithSite* iface, REFIID riid, void** ppvObj)
2816 {
2817     IFilterGraphImpl *This = impl_from_IObjectWithSite( iface );
2818
2819     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
2820     return Filtergraph_QueryInterface(This, riid, ppvObj);
2821 }
2822
2823 static ULONG WINAPI ObjectWithSite_AddRef(IObjectWithSite *iface)
2824 {
2825     IFilterGraphImpl *This = impl_from_IObjectWithSite( iface );
2826
2827     TRACE("(%p/%p)->()\n", This, iface);
2828     return Filtergraph_AddRef(This);
2829 }
2830
2831 static ULONG WINAPI ObjectWithSite_Release(IObjectWithSite *iface)
2832 {
2833     IFilterGraphImpl *This = impl_from_IObjectWithSite( iface );
2834
2835     TRACE("(%p/%p)->()\n", This, iface);
2836     return Filtergraph_Release(This);
2837 }
2838
2839 /*** IObjectWithSite methods ***/
2840
2841 static HRESULT WINAPI ObjectWithSite_SetSite(IObjectWithSite *iface, IUnknown *pUnkSite)
2842 {
2843     IFilterGraphImpl *This = impl_from_IObjectWithSite( iface );
2844
2845     TRACE("(%p/%p)->()\n", This, iface);
2846     if (This->pSite) IUnknown_Release(This->pSite);
2847     This->pSite = pUnkSite;
2848     IUnknown_AddRef(This->pSite);
2849     return S_OK;
2850 }
2851
2852 static HRESULT WINAPI ObjectWithSite_GetSite(IObjectWithSite *iface, REFIID riid, PVOID *ppvSite)
2853 {
2854     IFilterGraphImpl *This = impl_from_IObjectWithSite( iface );
2855
2856     TRACE("(%p/%p)->(%s)\n", This, iface,debugstr_guid(riid));
2857
2858     *ppvSite = NULL;
2859     if (!This->pSite)
2860         return E_FAIL;
2861     else
2862         return IUnknown_QueryInterface(This->pSite, riid, ppvSite);
2863 }
2864
2865 static const IObjectWithSiteVtbl IObjectWithSite_VTable =
2866 {
2867     ObjectWithSite_QueryInterface,
2868     ObjectWithSite_AddRef,
2869     ObjectWithSite_Release,
2870     ObjectWithSite_SetSite,
2871     ObjectWithSite_GetSite,
2872 };
2873
2874 static HRESULT GetTargetInterface(IFilterGraphImpl* pGraph, REFIID riid, LPVOID* ppvObj)
2875 {
2876     HRESULT hr = E_NOINTERFACE;
2877     int i;
2878     int entry;
2879
2880     /* Check if the interface type is already registered */
2881     for (entry = 0; entry < pGraph->nItfCacheEntries; entry++)
2882         if (riid == pGraph->ItfCacheEntries[entry].riid)
2883         {
2884             if (pGraph->ItfCacheEntries[entry].iface)
2885             {
2886                 /* Return the interface if available */
2887                 *ppvObj = pGraph->ItfCacheEntries[entry].iface;
2888                 return S_OK;
2889             }
2890             break;
2891         }
2892
2893     if (entry >= MAX_ITF_CACHE_ENTRIES)
2894     {
2895         FIXME("Not enough space to store interface in the cache\n");
2896         return E_OUTOFMEMORY;
2897     }
2898
2899     /* Find a filter supporting the requested interface */
2900     for (i = 0; i < pGraph->nFilters; i++)
2901     {
2902         hr = IBaseFilter_QueryInterface(pGraph->ppFiltersInGraph[i], riid, ppvObj);
2903         if (hr == S_OK)
2904         {
2905             pGraph->ItfCacheEntries[entry].riid = riid;
2906             pGraph->ItfCacheEntries[entry].filter = pGraph->ppFiltersInGraph[i];
2907             pGraph->ItfCacheEntries[entry].iface = *ppvObj;
2908             if (entry >= pGraph->nItfCacheEntries)
2909                 pGraph->nItfCacheEntries++;
2910             return S_OK;
2911         }
2912         if (hr != E_NOINTERFACE)
2913             return hr;
2914     }
2915
2916     return hr;
2917 }
2918
2919 static inline IFilterGraphImpl *impl_from_IBasicAudio(IBasicAudio *iface)
2920 {
2921     return CONTAINING_RECORD(iface, IFilterGraphImpl, IBasicAudio_iface);
2922 }
2923
2924 static HRESULT WINAPI BasicAudio_QueryInterface(IBasicAudio *iface, REFIID riid, void **ppvObj)
2925 {
2926     IFilterGraphImpl *This = impl_from_IBasicAudio(iface);
2927
2928     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
2929
2930     return Filtergraph_QueryInterface(This, riid, ppvObj);
2931 }
2932
2933 static ULONG WINAPI BasicAudio_AddRef(IBasicAudio *iface)
2934 {
2935     IFilterGraphImpl *This = impl_from_IBasicAudio(iface);
2936
2937     TRACE("(%p/%p)->()\n", This, iface);
2938
2939     return Filtergraph_AddRef(This);
2940 }
2941
2942 static ULONG WINAPI BasicAudio_Release(IBasicAudio *iface)
2943 {
2944     IFilterGraphImpl *This = impl_from_IBasicAudio(iface);
2945
2946     TRACE("(%p/%p)->()\n", This, iface);
2947
2948     return Filtergraph_Release(This);
2949 }
2950
2951 /*** IDispatch methods ***/
2952 static HRESULT WINAPI BasicAudio_GetTypeInfoCount(IBasicAudio *iface, UINT *pctinfo)
2953 {
2954     IFilterGraphImpl *This = impl_from_IBasicAudio(iface);
2955     IBasicAudio* pBasicAudio;
2956     HRESULT hr;
2957
2958     TRACE("(%p/%p)->(%p)\n", This, iface, pctinfo);
2959
2960     EnterCriticalSection(&This->cs);
2961
2962     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2963
2964     if (hr == S_OK)
2965         hr = IBasicAudio_GetTypeInfoCount(pBasicAudio, pctinfo);
2966
2967     LeaveCriticalSection(&This->cs);
2968
2969     return hr;
2970 }
2971
2972 static HRESULT WINAPI BasicAudio_GetTypeInfo(IBasicAudio *iface, UINT iTInfo, LCID lcid,
2973         ITypeInfo **ppTInfo)
2974 {
2975     IFilterGraphImpl *This = impl_from_IBasicAudio(iface);
2976     IBasicAudio* pBasicAudio;
2977     HRESULT hr;
2978
2979     TRACE("(%p/%p)->(%d, %d, %p)\n", This, iface, iTInfo, lcid, ppTInfo);
2980
2981     EnterCriticalSection(&This->cs);
2982
2983     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
2984
2985     if (hr == S_OK)
2986         hr = IBasicAudio_GetTypeInfo(pBasicAudio, iTInfo, lcid, ppTInfo);
2987
2988     LeaveCriticalSection(&This->cs);
2989
2990     return hr;
2991 }
2992
2993 static HRESULT WINAPI BasicAudio_GetIDsOfNames(IBasicAudio *iface, REFIID riid, LPOLESTR *rgszNames,
2994         UINT cNames, LCID lcid, DISPID *rgDispId)
2995 {
2996     IFilterGraphImpl *This = impl_from_IBasicAudio(iface);
2997     IBasicAudio* pBasicAudio;
2998     HRESULT hr;
2999
3000     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p)\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
3001
3002     EnterCriticalSection(&This->cs);
3003
3004     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
3005
3006     if (hr == S_OK)
3007         hr = IBasicAudio_GetIDsOfNames(pBasicAudio, riid, rgszNames, cNames, lcid, rgDispId);
3008
3009     LeaveCriticalSection(&This->cs);
3010
3011     return hr;
3012 }
3013
3014 static HRESULT WINAPI BasicAudio_Invoke(IBasicAudio *iface, DISPID dispIdMember, REFIID riid,
3015         LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExepInfo,
3016         UINT *puArgErr)
3017 {
3018     IFilterGraphImpl *This = impl_from_IBasicAudio(iface);
3019     IBasicAudio* pBasicAudio;
3020     HRESULT hr;
3021
3022     TRACE("(%p/%p)->(%d, %s (%p), %d, %04x, %p, %p, %p, %p)\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
3023
3024     EnterCriticalSection(&This->cs);
3025
3026     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
3027
3028     if (hr == S_OK)
3029         hr = IBasicAudio_Invoke(pBasicAudio, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
3030
3031     LeaveCriticalSection(&This->cs);
3032
3033     return hr;
3034 }
3035
3036 /*** IBasicAudio methods ***/
3037 static HRESULT WINAPI BasicAudio_put_Volume(IBasicAudio *iface, LONG lVolume)
3038 {
3039     IFilterGraphImpl *This = impl_from_IBasicAudio(iface);
3040     IBasicAudio* pBasicAudio;
3041     HRESULT hr;
3042
3043     TRACE("(%p/%p)->(%d)\n", This, iface, lVolume);
3044
3045     EnterCriticalSection(&This->cs);
3046
3047     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
3048
3049     if (hr == S_OK)
3050         hr = IBasicAudio_put_Volume(pBasicAudio, lVolume);
3051
3052     LeaveCriticalSection(&This->cs);
3053
3054     return hr;
3055 }
3056
3057 static HRESULT WINAPI BasicAudio_get_Volume(IBasicAudio *iface, LONG *plVolume)
3058 {
3059     IFilterGraphImpl *This = impl_from_IBasicAudio(iface);
3060     IBasicAudio* pBasicAudio;
3061     HRESULT hr;
3062
3063     TRACE("(%p/%p)->(%p)\n", This, iface, plVolume);
3064
3065     EnterCriticalSection(&This->cs);
3066
3067     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
3068
3069     if (hr == S_OK)
3070         hr = IBasicAudio_get_Volume(pBasicAudio, plVolume);
3071
3072     LeaveCriticalSection(&This->cs);
3073
3074     return hr;
3075 }
3076
3077 static HRESULT WINAPI BasicAudio_put_Balance(IBasicAudio *iface, LONG lBalance)
3078 {
3079     IFilterGraphImpl *This = impl_from_IBasicAudio(iface);
3080     IBasicAudio* pBasicAudio;
3081     HRESULT hr;
3082
3083     TRACE("(%p/%p)->(%d)\n", This, iface, lBalance);
3084
3085     EnterCriticalSection(&This->cs);
3086
3087     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
3088
3089     if (hr == S_OK)
3090         hr = IBasicAudio_put_Balance(pBasicAudio, lBalance);
3091
3092     LeaveCriticalSection(&This->cs);
3093
3094     return hr;
3095 }
3096
3097 static HRESULT WINAPI BasicAudio_get_Balance(IBasicAudio *iface, LONG *plBalance)
3098 {
3099     IFilterGraphImpl *This = impl_from_IBasicAudio(iface);
3100     IBasicAudio* pBasicAudio;
3101     HRESULT hr;
3102
3103     TRACE("(%p/%p)->(%p)\n", This, iface, plBalance);
3104
3105     EnterCriticalSection(&This->cs);
3106
3107     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
3108
3109     if (hr == S_OK)
3110         hr = IBasicAudio_get_Balance(pBasicAudio, plBalance);
3111
3112     LeaveCriticalSection(&This->cs);
3113
3114     return hr;
3115 }
3116
3117 static const IBasicAudioVtbl IBasicAudio_VTable =
3118 {
3119     BasicAudio_QueryInterface,
3120     BasicAudio_AddRef,
3121     BasicAudio_Release,
3122     BasicAudio_GetTypeInfoCount,
3123     BasicAudio_GetTypeInfo,
3124     BasicAudio_GetIDsOfNames,
3125     BasicAudio_Invoke,
3126     BasicAudio_put_Volume,
3127     BasicAudio_get_Volume,
3128     BasicAudio_put_Balance,
3129     BasicAudio_get_Balance
3130 };
3131
3132 static inline IFilterGraphImpl *impl_from_IBasicVideo2(IBasicVideo2 *iface)
3133 {
3134     return CONTAINING_RECORD(iface, IFilterGraphImpl, IBasicVideo2_iface);
3135 }
3136
3137 static HRESULT WINAPI BasicVideo_QueryInterface(IBasicVideo2 *iface, REFIID riid, void **ppvObj)
3138 {
3139     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3140
3141     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
3142
3143     return Filtergraph_QueryInterface(This, riid, ppvObj);
3144 }
3145
3146 static ULONG WINAPI BasicVideo_AddRef(IBasicVideo2 *iface)
3147 {
3148     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3149
3150     TRACE("(%p/%p)->()\n", This, iface);
3151
3152     return Filtergraph_AddRef(This);
3153 }
3154
3155 static ULONG WINAPI BasicVideo_Release(IBasicVideo2 *iface)
3156 {
3157     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3158
3159     TRACE("(%p/%p)->()\n", This, iface);
3160
3161     return Filtergraph_Release(This);
3162 }
3163
3164 /*** IDispatch methods ***/
3165 static HRESULT WINAPI BasicVideo_GetTypeInfoCount(IBasicVideo2 *iface, UINT *pctinfo)
3166 {
3167     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3168     IBasicVideo *pBasicVideo;
3169     HRESULT hr;
3170
3171     TRACE("(%p/%p)->(%p)\n", This, iface, pctinfo);
3172
3173     EnterCriticalSection(&This->cs);
3174
3175     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3176
3177     if (hr == S_OK)
3178         hr = IBasicVideo_GetTypeInfoCount(pBasicVideo, pctinfo);
3179
3180     LeaveCriticalSection(&This->cs);
3181
3182     return hr;
3183 }
3184
3185 static HRESULT WINAPI BasicVideo_GetTypeInfo(IBasicVideo2 *iface, UINT iTInfo, LCID lcid,
3186         ITypeInfo **ppTInfo)
3187 {
3188     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3189     IBasicVideo *pBasicVideo;
3190     HRESULT hr;
3191
3192     TRACE("(%p/%p)->(%d, %d, %p)\n", This, iface, iTInfo, lcid, ppTInfo);
3193
3194     EnterCriticalSection(&This->cs);
3195
3196     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3197
3198     if (hr == S_OK)
3199         hr = IBasicVideo_GetTypeInfo(pBasicVideo, iTInfo, lcid, ppTInfo);
3200
3201     LeaveCriticalSection(&This->cs);
3202
3203     return hr;
3204 }
3205
3206 static HRESULT WINAPI BasicVideo_GetIDsOfNames(IBasicVideo2 *iface, REFIID riid,
3207         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
3208 {
3209     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3210     IBasicVideo *pBasicVideo;
3211     HRESULT hr;
3212
3213     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p)\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
3214
3215     EnterCriticalSection(&This->cs);
3216
3217     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3218
3219     if (hr == S_OK)
3220         hr = IBasicVideo_GetIDsOfNames(pBasicVideo, riid, rgszNames, cNames, lcid, rgDispId);
3221
3222     LeaveCriticalSection(&This->cs);
3223
3224     return hr;
3225 }
3226
3227 static HRESULT WINAPI BasicVideo_Invoke(IBasicVideo2 *iface, DISPID dispIdMember, REFIID riid,
3228         LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExepInfo,
3229         UINT *puArgErr)
3230 {
3231     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3232     IBasicVideo *pBasicVideo;
3233     HRESULT hr;
3234
3235     TRACE("(%p/%p)->(%d, %s (%p), %d, %04x, %p, %p, %p, %p)\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
3236
3237     EnterCriticalSection(&This->cs);
3238
3239     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3240
3241     if (hr == S_OK)
3242         hr = IBasicVideo_Invoke(pBasicVideo, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
3243
3244     LeaveCriticalSection(&This->cs);
3245
3246     return hr;
3247 }
3248
3249 /*** IBasicVideo methods ***/
3250 static HRESULT WINAPI BasicVideo_get_AvgTimePerFrame(IBasicVideo2 *iface, REFTIME *pAvgTimePerFrame)
3251 {
3252     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3253     IBasicVideo *pBasicVideo;
3254     HRESULT hr;
3255
3256     TRACE("(%p/%p)->(%p)\n", This, iface, pAvgTimePerFrame);
3257
3258     EnterCriticalSection(&This->cs);
3259
3260     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3261
3262     if (hr == S_OK)
3263         hr = IBasicVideo_get_AvgTimePerFrame(pBasicVideo, pAvgTimePerFrame);
3264
3265     LeaveCriticalSection(&This->cs);
3266
3267     return hr;
3268 }
3269
3270 static HRESULT WINAPI BasicVideo_get_BitRate(IBasicVideo2 *iface, LONG *pBitRate)
3271 {
3272     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3273     IBasicVideo *pBasicVideo;
3274     HRESULT hr;
3275
3276     TRACE("(%p/%p)->(%p)\n", This, iface, pBitRate);
3277
3278     EnterCriticalSection(&This->cs);
3279
3280     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3281
3282     if (hr == S_OK)
3283         hr = IBasicVideo_get_BitRate(pBasicVideo, pBitRate);
3284
3285     LeaveCriticalSection(&This->cs);
3286
3287     return hr;
3288 }
3289
3290 static HRESULT WINAPI BasicVideo_get_BitErrorRate(IBasicVideo2 *iface, LONG *pBitErrorRate)
3291 {
3292     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3293     IBasicVideo *pBasicVideo;
3294     HRESULT hr;
3295
3296     TRACE("(%p/%p)->(%p)\n", This, iface, pBitErrorRate);
3297
3298     EnterCriticalSection(&This->cs);
3299
3300     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3301
3302     if (hr == S_OK)
3303         hr = IBasicVideo_get_BitErrorRate(pBasicVideo, pBitErrorRate);
3304
3305     LeaveCriticalSection(&This->cs);
3306
3307     return hr;
3308 }
3309
3310 static HRESULT WINAPI BasicVideo_get_VideoWidth(IBasicVideo2 *iface, LONG *pVideoWidth)
3311 {
3312     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3313     IBasicVideo *pBasicVideo;
3314     HRESULT hr;
3315
3316     TRACE("(%p/%p)->(%p)\n", This, iface, pVideoWidth);
3317
3318     EnterCriticalSection(&This->cs);
3319
3320     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3321
3322     if (hr == S_OK)
3323         hr = IBasicVideo_get_VideoWidth(pBasicVideo, pVideoWidth);
3324
3325     LeaveCriticalSection(&This->cs);
3326
3327     return hr;
3328 }
3329
3330 static HRESULT WINAPI BasicVideo_get_VideoHeight(IBasicVideo2 *iface, LONG *pVideoHeight)
3331 {
3332     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3333     IBasicVideo *pBasicVideo;
3334     HRESULT hr;
3335
3336     TRACE("(%p/%p)->(%p)\n", This, iface, pVideoHeight);
3337
3338     EnterCriticalSection(&This->cs);
3339
3340     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3341
3342     if (hr == S_OK)
3343         hr = IBasicVideo_get_VideoHeight(pBasicVideo, pVideoHeight);
3344
3345     LeaveCriticalSection(&This->cs);
3346
3347     return hr;
3348 }
3349
3350 static HRESULT WINAPI BasicVideo_put_SourceLeft(IBasicVideo2 *iface, LONG SourceLeft)
3351 {
3352     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3353     IBasicVideo *pBasicVideo;
3354     HRESULT hr;
3355
3356     TRACE("(%p/%p)->(%d)\n", This, iface, SourceLeft);
3357
3358     EnterCriticalSection(&This->cs);
3359
3360     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3361
3362     if (hr == S_OK)
3363         hr = IBasicVideo_put_SourceLeft(pBasicVideo, SourceLeft);
3364
3365     LeaveCriticalSection(&This->cs);
3366
3367     return hr;
3368 }
3369
3370 static HRESULT WINAPI BasicVideo_get_SourceLeft(IBasicVideo2 *iface, LONG *pSourceLeft)
3371 {
3372     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3373     IBasicVideo *pBasicVideo;
3374     HRESULT hr;
3375
3376     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceLeft);
3377
3378     EnterCriticalSection(&This->cs);
3379
3380     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3381
3382     if (hr == S_OK)
3383         hr = IBasicVideo_get_SourceLeft(pBasicVideo, pSourceLeft);
3384
3385     LeaveCriticalSection(&This->cs);
3386
3387     return hr;
3388 }
3389
3390 static HRESULT WINAPI BasicVideo_put_SourceWidth(IBasicVideo2 *iface, LONG SourceWidth)
3391 {
3392     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3393     IBasicVideo *pBasicVideo;
3394     HRESULT hr;
3395
3396     TRACE("(%p/%p)->(%d)\n", This, iface, SourceWidth);
3397
3398     EnterCriticalSection(&This->cs);
3399
3400     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3401
3402     if (hr == S_OK)
3403         hr = IBasicVideo_put_SourceWidth(pBasicVideo, SourceWidth);
3404
3405     LeaveCriticalSection(&This->cs);
3406
3407     return hr;
3408 }
3409
3410 static HRESULT WINAPI BasicVideo_get_SourceWidth(IBasicVideo2 *iface, LONG *pSourceWidth)
3411 {
3412     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3413     IBasicVideo *pBasicVideo;
3414     HRESULT hr;
3415
3416     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceWidth);
3417
3418     EnterCriticalSection(&This->cs);
3419
3420     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3421
3422     if (hr == S_OK)
3423         hr = IBasicVideo_get_SourceWidth(pBasicVideo, pSourceWidth);
3424
3425     LeaveCriticalSection(&This->cs);
3426
3427     return hr;
3428 }
3429
3430 static HRESULT WINAPI BasicVideo_put_SourceTop(IBasicVideo2 *iface, LONG SourceTop)
3431 {
3432     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3433     IBasicVideo *pBasicVideo;
3434     HRESULT hr;
3435
3436     TRACE("(%p/%p)->(%d)\n", This, iface, SourceTop);
3437
3438     EnterCriticalSection(&This->cs);
3439
3440     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3441
3442     if (hr == S_OK)
3443         hr = IBasicVideo_put_SourceTop(pBasicVideo, SourceTop);
3444
3445     LeaveCriticalSection(&This->cs);
3446
3447     return hr;
3448 }
3449
3450 static HRESULT WINAPI BasicVideo_get_SourceTop(IBasicVideo2 *iface, LONG *pSourceTop)
3451 {
3452     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3453     IBasicVideo *pBasicVideo;
3454     HRESULT hr;
3455
3456     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceTop);
3457
3458     EnterCriticalSection(&This->cs);
3459
3460     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3461
3462     if (hr == S_OK)
3463         hr = IBasicVideo_get_SourceTop(pBasicVideo, pSourceTop);
3464
3465     LeaveCriticalSection(&This->cs);
3466
3467     return hr;
3468 }
3469
3470 static HRESULT WINAPI BasicVideo_put_SourceHeight(IBasicVideo2 *iface, LONG SourceHeight)
3471 {
3472     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3473     IBasicVideo *pBasicVideo;
3474     HRESULT hr;
3475
3476     TRACE("(%p/%p)->(%d)\n", This, iface, SourceHeight);
3477
3478     EnterCriticalSection(&This->cs);
3479
3480     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3481
3482     if (hr == S_OK)
3483         hr = IBasicVideo_put_SourceHeight(pBasicVideo, SourceHeight);
3484
3485     LeaveCriticalSection(&This->cs);
3486
3487     return hr;
3488 }
3489
3490 static HRESULT WINAPI BasicVideo_get_SourceHeight(IBasicVideo2 *iface, LONG *pSourceHeight)
3491 {
3492     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3493     IBasicVideo *pBasicVideo;
3494     HRESULT hr;
3495
3496     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceHeight);
3497
3498     EnterCriticalSection(&This->cs);
3499
3500     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3501
3502     if (hr == S_OK)
3503         hr = IBasicVideo_get_SourceHeight(pBasicVideo, pSourceHeight);
3504
3505     LeaveCriticalSection(&This->cs);
3506
3507     return hr;
3508 }
3509
3510 static HRESULT WINAPI BasicVideo_put_DestinationLeft(IBasicVideo2 *iface, LONG DestinationLeft)
3511 {
3512     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3513     IBasicVideo *pBasicVideo;
3514     HRESULT hr;
3515
3516     TRACE("(%p/%p)->(%d)\n", This, iface, DestinationLeft);
3517
3518     EnterCriticalSection(&This->cs);
3519
3520     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3521
3522     if (hr == S_OK)
3523         hr = IBasicVideo_put_DestinationLeft(pBasicVideo, DestinationLeft);
3524
3525     LeaveCriticalSection(&This->cs);
3526
3527     return hr;
3528 }
3529
3530 static HRESULT WINAPI BasicVideo_get_DestinationLeft(IBasicVideo2 *iface, LONG *pDestinationLeft)
3531 {
3532     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3533     IBasicVideo *pBasicVideo;
3534     HRESULT hr;
3535
3536     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationLeft);
3537
3538     EnterCriticalSection(&This->cs);
3539
3540     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3541
3542     if (hr == S_OK)
3543         hr = IBasicVideo_get_DestinationLeft(pBasicVideo, pDestinationLeft);
3544
3545     LeaveCriticalSection(&This->cs);
3546
3547     return hr;
3548 }
3549
3550 static HRESULT WINAPI BasicVideo_put_DestinationWidth(IBasicVideo2 *iface, LONG DestinationWidth)
3551 {
3552     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3553     IBasicVideo *pBasicVideo;
3554     HRESULT hr;
3555
3556     TRACE("(%p/%p)->(%d)\n", This, iface, DestinationWidth);
3557
3558     EnterCriticalSection(&This->cs);
3559
3560     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3561
3562     if (hr == S_OK)
3563         hr = IBasicVideo_put_DestinationWidth(pBasicVideo, DestinationWidth);
3564
3565     LeaveCriticalSection(&This->cs);
3566
3567     return hr;
3568 }
3569
3570 static HRESULT WINAPI BasicVideo_get_DestinationWidth(IBasicVideo2 *iface, LONG *pDestinationWidth)
3571 {
3572     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3573     IBasicVideo *pBasicVideo;
3574     HRESULT hr;
3575
3576     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationWidth);
3577
3578     EnterCriticalSection(&This->cs);
3579
3580     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3581
3582     if (hr == S_OK)
3583         hr = IBasicVideo_get_DestinationWidth(pBasicVideo, pDestinationWidth);
3584
3585     LeaveCriticalSection(&This->cs);
3586
3587     return hr;
3588 }
3589
3590 static HRESULT WINAPI BasicVideo_put_DestinationTop(IBasicVideo2 *iface, LONG DestinationTop)
3591 {
3592     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3593     IBasicVideo *pBasicVideo;
3594     HRESULT hr;
3595
3596     TRACE("(%p/%p)->(%d)\n", This, iface, DestinationTop);
3597
3598     EnterCriticalSection(&This->cs);
3599
3600     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3601
3602     if (hr == S_OK)
3603         hr = IBasicVideo_put_DestinationTop(pBasicVideo, DestinationTop);
3604
3605     LeaveCriticalSection(&This->cs);
3606
3607     return hr;
3608 }
3609
3610 static HRESULT WINAPI BasicVideo_get_DestinationTop(IBasicVideo2 *iface, LONG *pDestinationTop)
3611 {
3612     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3613     IBasicVideo *pBasicVideo;
3614     HRESULT hr;
3615
3616     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationTop);
3617
3618     EnterCriticalSection(&This->cs);
3619
3620     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3621
3622     if (hr == S_OK)
3623         hr = IBasicVideo_get_DestinationTop(pBasicVideo, pDestinationTop);
3624
3625     LeaveCriticalSection(&This->cs);
3626
3627     return hr;
3628 }
3629
3630 static HRESULT WINAPI BasicVideo_put_DestinationHeight(IBasicVideo2 *iface, LONG DestinationHeight)
3631 {
3632     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3633     IBasicVideo *pBasicVideo;
3634     HRESULT hr;
3635
3636     TRACE("(%p/%p)->(%d)\n", This, iface, DestinationHeight);
3637
3638     EnterCriticalSection(&This->cs);
3639
3640     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3641
3642     if (hr == S_OK)
3643         hr = IBasicVideo_put_DestinationHeight(pBasicVideo, DestinationHeight);
3644
3645     LeaveCriticalSection(&This->cs);
3646
3647     return hr;
3648 }
3649
3650 static HRESULT WINAPI BasicVideo_get_DestinationHeight(IBasicVideo2 *iface,
3651         LONG *pDestinationHeight)
3652 {
3653     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3654     IBasicVideo *pBasicVideo;
3655     HRESULT hr;
3656
3657     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationHeight);
3658
3659     EnterCriticalSection(&This->cs);
3660
3661     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3662
3663     if (hr == S_OK)
3664         hr = IBasicVideo_get_DestinationHeight(pBasicVideo, pDestinationHeight);
3665
3666     LeaveCriticalSection(&This->cs);
3667
3668     return hr;
3669 }
3670
3671 static HRESULT WINAPI BasicVideo_SetSourcePosition(IBasicVideo2 *iface, LONG Left, LONG Top,
3672         LONG Width, LONG Height)
3673 {
3674     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3675     IBasicVideo *pBasicVideo;
3676     HRESULT hr;
3677
3678     TRACE("(%p/%p)->(%d, %d, %d, %d)\n", This, iface, Left, Top, Width, Height);
3679
3680     EnterCriticalSection(&This->cs);
3681
3682     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3683
3684     if (hr == S_OK)
3685         hr = IBasicVideo_SetSourcePosition(pBasicVideo, Left, Top, Width, Height);
3686
3687     LeaveCriticalSection(&This->cs);
3688
3689     return hr;
3690 }
3691
3692 static HRESULT WINAPI BasicVideo_GetSourcePosition(IBasicVideo2 *iface, LONG *pLeft, LONG *pTop,
3693         LONG *pWidth, LONG *pHeight)
3694 {
3695     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3696     IBasicVideo *pBasicVideo;
3697     HRESULT hr;
3698
3699     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
3700
3701     EnterCriticalSection(&This->cs);
3702
3703     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3704
3705     if (hr == S_OK)
3706         hr = IBasicVideo_GetSourcePosition(pBasicVideo, pLeft, pTop, pWidth, pHeight);
3707
3708     LeaveCriticalSection(&This->cs);
3709
3710     return hr;
3711 }
3712
3713 static HRESULT WINAPI BasicVideo_SetDefaultSourcePosition(IBasicVideo2 *iface)
3714 {
3715     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3716     IBasicVideo *pBasicVideo;
3717     HRESULT hr;
3718
3719     TRACE("(%p/%p)->()\n", This, iface);
3720
3721     EnterCriticalSection(&This->cs);
3722
3723     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3724
3725     if (hr == S_OK)
3726         hr = IBasicVideo_SetDefaultSourcePosition(pBasicVideo);
3727
3728     LeaveCriticalSection(&This->cs);
3729
3730     return hr;
3731 }
3732
3733 static HRESULT WINAPI BasicVideo_SetDestinationPosition(IBasicVideo2 *iface, LONG Left, LONG Top,
3734         LONG Width, LONG Height)
3735 {
3736     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3737     IBasicVideo *pBasicVideo;
3738     HRESULT hr;
3739
3740     TRACE("(%p/%p)->(%d, %d, %d, %d)\n", This, iface, Left, Top, Width, Height);
3741
3742     EnterCriticalSection(&This->cs);
3743
3744     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3745
3746     if (hr == S_OK)
3747         hr = IBasicVideo_SetDestinationPosition(pBasicVideo, Left, Top, Width, Height);
3748
3749     LeaveCriticalSection(&This->cs);
3750
3751     return hr;
3752 }
3753
3754 static HRESULT WINAPI BasicVideo_GetDestinationPosition(IBasicVideo2 *iface, LONG *pLeft,
3755         LONG *pTop, LONG *pWidth, LONG *pHeight)
3756 {
3757     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3758     IBasicVideo *pBasicVideo;
3759     HRESULT hr;
3760
3761     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
3762
3763     EnterCriticalSection(&This->cs);
3764
3765     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3766
3767     if (hr == S_OK)
3768         hr = IBasicVideo_GetDestinationPosition(pBasicVideo, pLeft, pTop, pWidth, pHeight);
3769
3770     LeaveCriticalSection(&This->cs);
3771
3772     return hr;
3773 }
3774
3775 static HRESULT WINAPI BasicVideo_SetDefaultDestinationPosition(IBasicVideo2 *iface)
3776 {
3777     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3778     IBasicVideo *pBasicVideo;
3779     HRESULT hr;
3780
3781     TRACE("(%p/%p)->()\n", This, iface);
3782
3783     EnterCriticalSection(&This->cs);
3784
3785     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3786
3787     if (hr == S_OK)
3788         hr = IBasicVideo_SetDefaultDestinationPosition(pBasicVideo);
3789
3790     LeaveCriticalSection(&This->cs);
3791
3792     return hr;
3793 }
3794
3795 static HRESULT WINAPI BasicVideo_GetVideoSize(IBasicVideo2 *iface, LONG *pWidth, LONG *pHeight)
3796 {
3797     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3798     IBasicVideo *pBasicVideo;
3799     HRESULT hr;
3800
3801     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
3802
3803     EnterCriticalSection(&This->cs);
3804
3805     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3806
3807     if (hr == S_OK)
3808         hr = IBasicVideo_GetVideoSize(pBasicVideo, pWidth, pHeight);
3809
3810     LeaveCriticalSection(&This->cs);
3811
3812     return hr;
3813 }
3814
3815 static HRESULT WINAPI BasicVideo_GetVideoPaletteEntries(IBasicVideo2 *iface, LONG StartIndex,
3816         LONG Entries, LONG *pRetrieved, LONG *pPalette)
3817 {
3818     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3819     IBasicVideo *pBasicVideo;
3820     HRESULT hr;
3821
3822     TRACE("(%p/%p)->(%d, %d, %p, %p)\n", This, iface, StartIndex, Entries, pRetrieved, pPalette);
3823
3824     EnterCriticalSection(&This->cs);
3825
3826     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3827
3828     if (hr == S_OK)
3829         hr = IBasicVideo_GetVideoPaletteEntries(pBasicVideo, StartIndex, Entries, pRetrieved, pPalette);
3830
3831     LeaveCriticalSection(&This->cs);
3832
3833     return hr;
3834 }
3835
3836 static HRESULT WINAPI BasicVideo_GetCurrentImage(IBasicVideo2 *iface, LONG *pBufferSize,
3837         LONG *pDIBImage)
3838 {
3839     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3840     IBasicVideo *pBasicVideo;
3841     HRESULT hr;
3842
3843     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pBufferSize, pDIBImage);
3844
3845     EnterCriticalSection(&This->cs);
3846
3847     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3848
3849     if (hr == S_OK)
3850         hr = IBasicVideo_GetCurrentImage(pBasicVideo, pBufferSize, pDIBImage);
3851
3852     LeaveCriticalSection(&This->cs);
3853
3854     return hr;
3855 }
3856
3857 static HRESULT WINAPI BasicVideo_IsUsingDefaultSource(IBasicVideo2 *iface)
3858 {
3859     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3860     IBasicVideo *pBasicVideo;
3861     HRESULT hr;
3862
3863     TRACE("(%p/%p)->()\n", This, iface);
3864
3865     EnterCriticalSection(&This->cs);
3866
3867     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3868
3869     if (hr == S_OK)
3870         hr = IBasicVideo_IsUsingDefaultSource(pBasicVideo);
3871
3872     LeaveCriticalSection(&This->cs);
3873
3874     return hr;
3875 }
3876
3877 static HRESULT WINAPI BasicVideo_IsUsingDefaultDestination(IBasicVideo2 *iface)
3878 {
3879     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3880     IBasicVideo *pBasicVideo;
3881     HRESULT hr;
3882
3883     TRACE("(%p/%p)->()\n", This, iface);
3884
3885     EnterCriticalSection(&This->cs);
3886
3887     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
3888
3889     if (hr == S_OK)
3890         hr = IBasicVideo_IsUsingDefaultDestination(pBasicVideo);
3891
3892     LeaveCriticalSection(&This->cs);
3893
3894     return hr;
3895 }
3896
3897 static HRESULT WINAPI BasicVideo2_GetPreferredAspectRatio(IBasicVideo2 *iface, LONG *plAspectX,
3898         LONG *plAspectY)
3899 {
3900     IFilterGraphImpl *This = impl_from_IBasicVideo2(iface);
3901     IBasicVideo2 *pBasicVideo2;
3902     HRESULT hr;
3903
3904     TRACE("(%p/%p)->()\n", This, iface);
3905
3906     EnterCriticalSection(&This->cs);
3907
3908     hr = GetTargetInterface(This, &IID_IBasicVideo2, (LPVOID*)&pBasicVideo2);
3909
3910     if (hr == S_OK)
3911         hr = BasicVideo2_GetPreferredAspectRatio(iface, plAspectX, plAspectY);
3912
3913     LeaveCriticalSection(&This->cs);
3914
3915     return hr;
3916 }
3917
3918 static const IBasicVideo2Vtbl IBasicVideo_VTable =
3919 {
3920     BasicVideo_QueryInterface,
3921     BasicVideo_AddRef,
3922     BasicVideo_Release,
3923     BasicVideo_GetTypeInfoCount,
3924     BasicVideo_GetTypeInfo,
3925     BasicVideo_GetIDsOfNames,
3926     BasicVideo_Invoke,
3927     BasicVideo_get_AvgTimePerFrame,
3928     BasicVideo_get_BitRate,
3929     BasicVideo_get_BitErrorRate,
3930     BasicVideo_get_VideoWidth,
3931     BasicVideo_get_VideoHeight,
3932     BasicVideo_put_SourceLeft,
3933     BasicVideo_get_SourceLeft,
3934     BasicVideo_put_SourceWidth,
3935     BasicVideo_get_SourceWidth,
3936     BasicVideo_put_SourceTop,
3937     BasicVideo_get_SourceTop,
3938     BasicVideo_put_SourceHeight,
3939     BasicVideo_get_SourceHeight,
3940     BasicVideo_put_DestinationLeft,
3941     BasicVideo_get_DestinationLeft,
3942     BasicVideo_put_DestinationWidth,
3943     BasicVideo_get_DestinationWidth,
3944     BasicVideo_put_DestinationTop,
3945     BasicVideo_get_DestinationTop,
3946     BasicVideo_put_DestinationHeight,
3947     BasicVideo_get_DestinationHeight,
3948     BasicVideo_SetSourcePosition,
3949     BasicVideo_GetSourcePosition,
3950     BasicVideo_SetDefaultSourcePosition,
3951     BasicVideo_SetDestinationPosition,
3952     BasicVideo_GetDestinationPosition,
3953     BasicVideo_SetDefaultDestinationPosition,
3954     BasicVideo_GetVideoSize,
3955     BasicVideo_GetVideoPaletteEntries,
3956     BasicVideo_GetCurrentImage,
3957     BasicVideo_IsUsingDefaultSource,
3958     BasicVideo_IsUsingDefaultDestination,
3959     BasicVideo2_GetPreferredAspectRatio
3960 };
3961
3962 static inline IFilterGraphImpl *impl_from_IVideoWindow(IVideoWindow *iface)
3963 {
3964     return CONTAINING_RECORD(iface, IFilterGraphImpl, IVideoWindow_iface);
3965 }
3966
3967 static HRESULT WINAPI VideoWindow_QueryInterface(IVideoWindow *iface, REFIID riid, void **ppvObj)
3968 {
3969     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
3970
3971     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
3972
3973     return Filtergraph_QueryInterface(This, riid, ppvObj);
3974 }
3975
3976 static ULONG WINAPI VideoWindow_AddRef(IVideoWindow *iface)
3977 {
3978     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
3979
3980     TRACE("(%p/%p)->()\n", This, iface);
3981
3982     return Filtergraph_AddRef(This);
3983 }
3984
3985 static ULONG WINAPI VideoWindow_Release(IVideoWindow *iface)
3986 {
3987     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
3988
3989     TRACE("(%p/%p)->()\n", This, iface);
3990
3991     return Filtergraph_Release(This);
3992 }
3993
3994 /*** IDispatch methods ***/
3995 static HRESULT WINAPI VideoWindow_GetTypeInfoCount(IVideoWindow *iface, UINT *pctinfo)
3996 {
3997     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
3998     IVideoWindow *pVideoWindow;
3999     HRESULT hr;
4000
4001     TRACE("(%p/%p)->(%p)\n", This, iface, pctinfo);
4002
4003     EnterCriticalSection(&This->cs);
4004
4005     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4006
4007     if (hr == S_OK)
4008         hr = IVideoWindow_GetTypeInfoCount(pVideoWindow, pctinfo);
4009
4010     LeaveCriticalSection(&This->cs);
4011
4012     return hr;
4013 }
4014
4015 static HRESULT WINAPI VideoWindow_GetTypeInfo(IVideoWindow *iface, UINT iTInfo, LCID lcid,
4016         ITypeInfo **ppTInfo)
4017 {
4018     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4019     IVideoWindow *pVideoWindow;
4020     HRESULT hr;
4021
4022     TRACE("(%p/%p)->(%d, %d, %p)\n", This, iface, iTInfo, lcid, ppTInfo);
4023
4024     EnterCriticalSection(&This->cs);
4025
4026     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4027
4028     if (hr == S_OK)
4029         hr = IVideoWindow_GetTypeInfo(pVideoWindow, iTInfo, lcid, ppTInfo);
4030
4031     LeaveCriticalSection(&This->cs);
4032
4033     return hr;
4034 }
4035
4036 static HRESULT WINAPI VideoWindow_GetIDsOfNames(IVideoWindow *iface, REFIID riid,
4037         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
4038 {
4039     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4040     IVideoWindow *pVideoWindow;
4041     HRESULT hr;
4042
4043     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p)\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
4044
4045     EnterCriticalSection(&This->cs);
4046
4047     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4048
4049     if (hr == S_OK)
4050         hr = IVideoWindow_GetIDsOfNames(pVideoWindow, riid, rgszNames, cNames, lcid, rgDispId);
4051
4052     LeaveCriticalSection(&This->cs);
4053
4054     return hr;
4055 }
4056
4057 static HRESULT WINAPI VideoWindow_Invoke(IVideoWindow *iface, DISPID dispIdMember, REFIID riid,
4058         LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExepInfo,
4059         UINT*puArgErr)
4060 {
4061     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4062     IVideoWindow *pVideoWindow;
4063     HRESULT hr;
4064
4065     TRACE("(%p/%p)->(%d, %s (%p), %d, %04x, %p, %p, %p, %p)\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
4066
4067     EnterCriticalSection(&This->cs);
4068
4069     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4070
4071     if (hr == S_OK)
4072         hr = IVideoWindow_Invoke(pVideoWindow, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
4073
4074     LeaveCriticalSection(&This->cs);
4075
4076     return hr;
4077 }
4078
4079
4080 /*** IVideoWindow methods ***/
4081 static HRESULT WINAPI VideoWindow_put_Caption(IVideoWindow *iface, BSTR strCaption)
4082 {
4083     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4084     IVideoWindow *pVideoWindow;
4085     HRESULT hr;
4086     
4087     TRACE("(%p/%p)->(%s (%p))\n", This, iface, debugstr_w(strCaption), strCaption);
4088
4089     EnterCriticalSection(&This->cs);
4090
4091     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4092
4093     if (hr == S_OK)
4094         hr = IVideoWindow_put_Caption(pVideoWindow, strCaption);
4095
4096     LeaveCriticalSection(&This->cs);
4097
4098     return hr;
4099 }
4100
4101 static HRESULT WINAPI VideoWindow_get_Caption(IVideoWindow *iface, BSTR *strCaption)
4102 {
4103     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4104     IVideoWindow *pVideoWindow;
4105     HRESULT hr;
4106
4107     TRACE("(%p/%p)->(%p)\n", This, iface, strCaption);
4108
4109     EnterCriticalSection(&This->cs);
4110
4111     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4112
4113     if (hr == S_OK)
4114         hr = IVideoWindow_get_Caption(pVideoWindow, strCaption);
4115
4116     LeaveCriticalSection(&This->cs);
4117
4118     return hr;
4119 }
4120
4121 static HRESULT WINAPI VideoWindow_put_WindowStyle(IVideoWindow *iface, LONG WindowStyle)
4122 {
4123     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4124     IVideoWindow *pVideoWindow;
4125     HRESULT hr;
4126
4127     TRACE("(%p/%p)->(%d)\n", This, iface, WindowStyle);
4128
4129     EnterCriticalSection(&This->cs);
4130
4131     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4132
4133     if (hr == S_OK)
4134         hr = IVideoWindow_put_WindowStyle(pVideoWindow, WindowStyle);
4135
4136     LeaveCriticalSection(&This->cs);
4137
4138     return hr;
4139 }
4140
4141 static HRESULT WINAPI VideoWindow_get_WindowStyle(IVideoWindow *iface, LONG *WindowStyle)
4142 {
4143     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4144     IVideoWindow *pVideoWindow;
4145     HRESULT hr;
4146
4147     TRACE("(%p/%p)->(%p)\n", This, iface, WindowStyle);
4148
4149     EnterCriticalSection(&This->cs);
4150
4151     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4152
4153     if (hr == S_OK)
4154         hr = IVideoWindow_get_WindowStyle(pVideoWindow, WindowStyle);
4155
4156     LeaveCriticalSection(&This->cs);
4157
4158     return hr;
4159 }
4160
4161 static HRESULT WINAPI VideoWindow_put_WindowStyleEx(IVideoWindow *iface, LONG WindowStyleEx)
4162 {
4163     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4164     IVideoWindow *pVideoWindow;
4165     HRESULT hr;
4166
4167     TRACE("(%p/%p)->(%d)\n", This, iface, WindowStyleEx);
4168
4169     EnterCriticalSection(&This->cs);
4170
4171     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4172
4173     if (hr == S_OK)
4174         hr = IVideoWindow_put_WindowStyleEx(pVideoWindow, WindowStyleEx);
4175
4176     LeaveCriticalSection(&This->cs);
4177
4178     return hr;
4179 }
4180
4181 static HRESULT WINAPI VideoWindow_get_WindowStyleEx(IVideoWindow *iface, LONG *WindowStyleEx)
4182 {
4183     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4184     IVideoWindow *pVideoWindow;
4185     HRESULT hr;
4186
4187     TRACE("(%p/%p)->(%p)\n", This, iface, WindowStyleEx);
4188
4189     EnterCriticalSection(&This->cs);
4190
4191     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4192
4193     if (hr == S_OK)
4194         hr = IVideoWindow_get_WindowStyleEx(pVideoWindow, WindowStyleEx);
4195
4196     LeaveCriticalSection(&This->cs);
4197
4198     return hr;
4199 }
4200
4201 static HRESULT WINAPI VideoWindow_put_AutoShow(IVideoWindow *iface, LONG AutoShow)
4202 {
4203     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4204     IVideoWindow *pVideoWindow;
4205     HRESULT hr;
4206
4207     TRACE("(%p/%p)->(%d)\n", This, iface, AutoShow);
4208
4209     EnterCriticalSection(&This->cs);
4210
4211     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4212
4213     if (hr == S_OK)
4214         hr = IVideoWindow_put_AutoShow(pVideoWindow, AutoShow);
4215
4216     LeaveCriticalSection(&This->cs);
4217
4218     return hr;
4219 }
4220
4221 static HRESULT WINAPI VideoWindow_get_AutoShow(IVideoWindow *iface, LONG *AutoShow)
4222 {
4223     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4224     IVideoWindow *pVideoWindow;
4225     HRESULT hr;
4226
4227     TRACE("(%p/%p)->(%p)\n", This, iface, AutoShow);
4228
4229     EnterCriticalSection(&This->cs);
4230
4231     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4232
4233     if (hr == S_OK)
4234         hr = IVideoWindow_get_AutoShow(pVideoWindow, AutoShow);
4235
4236     LeaveCriticalSection(&This->cs);
4237
4238     return hr;
4239 }
4240
4241 static HRESULT WINAPI VideoWindow_put_WindowState(IVideoWindow *iface, LONG WindowState)
4242 {
4243     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4244     IVideoWindow *pVideoWindow;
4245     HRESULT hr;
4246
4247     TRACE("(%p/%p)->(%d)\n", This, iface, WindowState);
4248
4249     EnterCriticalSection(&This->cs);
4250
4251     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4252
4253     if (hr == S_OK)
4254         hr = IVideoWindow_put_WindowState(pVideoWindow, WindowState);
4255
4256     LeaveCriticalSection(&This->cs);
4257
4258     return hr;
4259 }
4260
4261 static HRESULT WINAPI VideoWindow_get_WindowState(IVideoWindow *iface, LONG *WindowState)
4262 {
4263     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4264     IVideoWindow *pVideoWindow;
4265     HRESULT hr;
4266
4267     TRACE("(%p/%p)->(%p)\n", This, iface, WindowState);
4268
4269     EnterCriticalSection(&This->cs);
4270
4271     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4272
4273     if (hr == S_OK)
4274         hr = IVideoWindow_get_WindowState(pVideoWindow, WindowState);
4275
4276     LeaveCriticalSection(&This->cs);
4277
4278     return hr;
4279 }
4280
4281 static HRESULT WINAPI VideoWindow_put_BackgroundPalette(IVideoWindow *iface, LONG BackgroundPalette)
4282 {
4283     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4284     IVideoWindow *pVideoWindow;
4285     HRESULT hr;
4286
4287     TRACE("(%p/%p)->(%d)\n", This, iface, BackgroundPalette);
4288
4289     EnterCriticalSection(&This->cs);
4290
4291     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4292
4293     if (hr == S_OK)
4294         hr = IVideoWindow_put_BackgroundPalette(pVideoWindow, BackgroundPalette);
4295
4296     LeaveCriticalSection(&This->cs);
4297
4298     return hr;
4299 }
4300
4301 static HRESULT WINAPI VideoWindow_get_BackgroundPalette(IVideoWindow *iface,
4302         LONG *pBackgroundPalette)
4303 {
4304     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4305     IVideoWindow *pVideoWindow;
4306     HRESULT hr;
4307
4308     TRACE("(%p/%p)->(%p)\n", This, iface, pBackgroundPalette);
4309
4310     EnterCriticalSection(&This->cs);
4311
4312     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4313
4314     if (hr == S_OK)
4315         hr = IVideoWindow_get_BackgroundPalette(pVideoWindow, pBackgroundPalette);
4316
4317     LeaveCriticalSection(&This->cs);
4318
4319     return hr;
4320 }
4321
4322 static HRESULT WINAPI VideoWindow_put_Visible(IVideoWindow *iface, LONG Visible)
4323 {
4324     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4325     IVideoWindow *pVideoWindow;
4326     HRESULT hr;
4327
4328     TRACE("(%p/%p)->(%d)\n", This, iface, Visible);
4329
4330     EnterCriticalSection(&This->cs);
4331
4332     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4333
4334     if (hr == S_OK)
4335         hr = IVideoWindow_put_Visible(pVideoWindow, Visible);
4336
4337     LeaveCriticalSection(&This->cs);
4338
4339     return hr;
4340 }
4341
4342 static HRESULT WINAPI VideoWindow_get_Visible(IVideoWindow *iface, LONG *pVisible)
4343 {
4344     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4345     IVideoWindow *pVideoWindow;
4346     HRESULT hr;
4347
4348     TRACE("(%p/%p)->(%p)\n", This, iface, pVisible);
4349
4350     EnterCriticalSection(&This->cs);
4351
4352     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4353
4354     if (hr == S_OK)
4355         hr = IVideoWindow_get_Visible(pVideoWindow, pVisible);
4356
4357     LeaveCriticalSection(&This->cs);
4358
4359     return hr;
4360 }
4361
4362 static HRESULT WINAPI VideoWindow_put_Left(IVideoWindow *iface, LONG Left)
4363 {
4364     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4365     IVideoWindow *pVideoWindow;
4366     HRESULT hr;
4367
4368     TRACE("(%p/%p)->(%d)\n", This, iface, Left);
4369
4370     EnterCriticalSection(&This->cs);
4371
4372     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4373
4374     if (hr == S_OK)
4375         hr = IVideoWindow_put_Left(pVideoWindow, Left);
4376
4377     LeaveCriticalSection(&This->cs);
4378
4379     return hr;
4380 }
4381
4382 static HRESULT WINAPI VideoWindow_get_Left(IVideoWindow *iface, LONG *pLeft)
4383 {
4384     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4385     IVideoWindow *pVideoWindow;
4386     HRESULT hr;
4387
4388     TRACE("(%p/%p)->(%p)\n", This, iface, pLeft);
4389
4390     EnterCriticalSection(&This->cs);
4391
4392     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4393
4394     if (hr == S_OK)
4395         hr = IVideoWindow_get_Left(pVideoWindow, pLeft);
4396
4397     LeaveCriticalSection(&This->cs);
4398
4399     return hr;
4400 }
4401
4402 static HRESULT WINAPI VideoWindow_put_Width(IVideoWindow *iface, LONG Width)
4403 {
4404     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4405     IVideoWindow *pVideoWindow;
4406     HRESULT hr;
4407
4408     TRACE("(%p/%p)->(%d)\n", This, iface, Width);
4409
4410     EnterCriticalSection(&This->cs);
4411
4412     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4413
4414     if (hr == S_OK)
4415         hr = IVideoWindow_put_Width(pVideoWindow, Width);
4416
4417     LeaveCriticalSection(&This->cs);
4418
4419     return hr;
4420 }
4421
4422 static HRESULT WINAPI VideoWindow_get_Width(IVideoWindow *iface, LONG *pWidth)
4423 {
4424     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4425     IVideoWindow *pVideoWindow;
4426     HRESULT hr;
4427
4428     TRACE("(%p/%p)->(%p)\n", This, iface, pWidth);
4429
4430     EnterCriticalSection(&This->cs);
4431
4432     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4433
4434     if (hr == S_OK)
4435         hr = IVideoWindow_get_Width(pVideoWindow, pWidth);
4436
4437     LeaveCriticalSection(&This->cs);
4438
4439     return hr;
4440 }
4441
4442 static HRESULT WINAPI VideoWindow_put_Top(IVideoWindow *iface, LONG Top)
4443 {
4444     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4445     IVideoWindow *pVideoWindow;
4446     HRESULT hr;
4447
4448     TRACE("(%p/%p)->(%d)\n", This, iface, Top);
4449
4450     EnterCriticalSection(&This->cs);
4451
4452     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4453
4454     if (hr == S_OK)
4455         hr = IVideoWindow_put_Top(pVideoWindow, Top);
4456
4457     LeaveCriticalSection(&This->cs);
4458
4459     return hr;
4460 }
4461
4462 static HRESULT WINAPI VideoWindow_get_Top(IVideoWindow *iface, LONG *pTop)
4463 {
4464     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4465     IVideoWindow *pVideoWindow;
4466     HRESULT hr;
4467
4468     TRACE("(%p/%p)->(%p)\n", This, iface, pTop);
4469
4470     EnterCriticalSection(&This->cs);
4471
4472     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4473
4474     if (hr == S_OK)
4475         hr = IVideoWindow_get_Top(pVideoWindow, pTop);
4476
4477     LeaveCriticalSection(&This->cs);
4478
4479     return hr;
4480 }
4481
4482 static HRESULT WINAPI VideoWindow_put_Height(IVideoWindow *iface, LONG Height)
4483 {
4484     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4485     IVideoWindow *pVideoWindow;
4486     HRESULT hr;
4487
4488     TRACE("(%p/%p)->(%d)\n", This, iface, Height);
4489
4490     EnterCriticalSection(&This->cs);
4491
4492     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4493
4494     if (hr == S_OK)
4495         hr = IVideoWindow_put_Height(pVideoWindow, Height);
4496
4497     LeaveCriticalSection(&This->cs);
4498
4499     return hr;
4500 }
4501
4502 static HRESULT WINAPI VideoWindow_get_Height(IVideoWindow *iface, LONG *pHeight)
4503 {
4504     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4505     IVideoWindow *pVideoWindow;
4506     HRESULT hr;
4507
4508     TRACE("(%p/%p)->(%p)\n", This, iface, pHeight);
4509
4510     EnterCriticalSection(&This->cs);
4511
4512     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4513
4514     if (hr == S_OK)
4515         hr = IVideoWindow_get_Height(pVideoWindow, pHeight);
4516
4517     LeaveCriticalSection(&This->cs);
4518
4519     return hr;
4520 }
4521
4522 static HRESULT WINAPI VideoWindow_put_Owner(IVideoWindow *iface, OAHWND Owner)
4523 {
4524     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4525     IVideoWindow *pVideoWindow;
4526     HRESULT hr;
4527
4528     TRACE("(%p/%p)->(%08x)\n", This, iface, (DWORD) Owner);
4529
4530     EnterCriticalSection(&This->cs);
4531
4532     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4533
4534     if (hr == S_OK)
4535         hr = IVideoWindow_put_Owner(pVideoWindow, Owner);
4536
4537     LeaveCriticalSection(&This->cs);
4538
4539     return hr;
4540 }
4541
4542 static HRESULT WINAPI VideoWindow_get_Owner(IVideoWindow *iface, OAHWND *Owner)
4543 {
4544     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4545     IVideoWindow *pVideoWindow;
4546     HRESULT hr;
4547
4548     TRACE("(%p/%p)->(%p)\n", This, iface, Owner);
4549
4550     EnterCriticalSection(&This->cs);
4551
4552     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4553
4554     if (hr == S_OK)
4555         hr = IVideoWindow_get_Owner(pVideoWindow, Owner);
4556
4557     LeaveCriticalSection(&This->cs);
4558
4559     return hr;
4560 }
4561
4562 static HRESULT WINAPI VideoWindow_put_MessageDrain(IVideoWindow *iface, OAHWND Drain)
4563 {
4564     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4565     IVideoWindow *pVideoWindow;
4566     HRESULT hr;
4567
4568     TRACE("(%p/%p)->(%08x)\n", This, iface, (DWORD) Drain);
4569
4570     EnterCriticalSection(&This->cs);
4571
4572     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4573
4574     if (hr == S_OK)
4575         hr = IVideoWindow_put_MessageDrain(pVideoWindow, Drain);
4576
4577     LeaveCriticalSection(&This->cs);
4578
4579     return hr;
4580 }
4581
4582 static HRESULT WINAPI VideoWindow_get_MessageDrain(IVideoWindow *iface, OAHWND *Drain)
4583 {
4584     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4585     IVideoWindow *pVideoWindow;
4586     HRESULT hr;
4587
4588     TRACE("(%p/%p)->(%p)\n", This, iface, Drain);
4589
4590     EnterCriticalSection(&This->cs);
4591
4592     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4593
4594     if (hr == S_OK)
4595         hr = IVideoWindow_get_MessageDrain(pVideoWindow, Drain);
4596
4597     LeaveCriticalSection(&This->cs);
4598
4599     return hr;
4600 }
4601
4602 static HRESULT WINAPI VideoWindow_get_BorderColor(IVideoWindow *iface, LONG *Color)
4603 {
4604     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4605     IVideoWindow *pVideoWindow;
4606     HRESULT hr;
4607
4608     TRACE("(%p/%p)->(%p)\n", This, iface, Color);
4609
4610     EnterCriticalSection(&This->cs);
4611
4612     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4613
4614     if (hr == S_OK)
4615         hr = IVideoWindow_get_BorderColor(pVideoWindow, Color);
4616
4617     LeaveCriticalSection(&This->cs);
4618
4619     return hr;
4620 }
4621
4622 static HRESULT WINAPI VideoWindow_put_BorderColor(IVideoWindow *iface, LONG Color)
4623 {
4624     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4625     IVideoWindow *pVideoWindow;
4626     HRESULT hr;
4627
4628     TRACE("(%p/%p)->(%d)\n", This, iface, Color);
4629
4630     EnterCriticalSection(&This->cs);
4631
4632     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4633
4634     if (hr == S_OK)
4635         hr = IVideoWindow_put_BorderColor(pVideoWindow, Color);
4636
4637     LeaveCriticalSection(&This->cs);
4638
4639     return hr;
4640 }
4641
4642 static HRESULT WINAPI VideoWindow_get_FullScreenMode(IVideoWindow *iface, LONG *FullScreenMode)
4643 {
4644     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4645     IVideoWindow *pVideoWindow;
4646     HRESULT hr;
4647
4648     TRACE("(%p/%p)->(%p)\n", This, iface, FullScreenMode);
4649
4650     EnterCriticalSection(&This->cs);
4651
4652     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4653
4654     if (hr == S_OK)
4655         hr = IVideoWindow_get_FullScreenMode(pVideoWindow, FullScreenMode);
4656
4657     LeaveCriticalSection(&This->cs);
4658
4659     return hr;
4660 }
4661
4662 static HRESULT WINAPI VideoWindow_put_FullScreenMode(IVideoWindow *iface, LONG FullScreenMode)
4663 {
4664     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4665     IVideoWindow *pVideoWindow;
4666     HRESULT hr;
4667
4668     TRACE("(%p/%p)->(%d)\n", This, iface, FullScreenMode);
4669
4670     EnterCriticalSection(&This->cs);
4671
4672     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4673
4674     if (hr == S_OK)
4675         hr = IVideoWindow_put_FullScreenMode(pVideoWindow, FullScreenMode);
4676
4677     LeaveCriticalSection(&This->cs);
4678
4679     return hr;
4680 }
4681
4682 static HRESULT WINAPI VideoWindow_SetWindowForeground(IVideoWindow *iface, LONG Focus)
4683 {
4684     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4685     IVideoWindow *pVideoWindow;
4686     HRESULT hr;
4687
4688     TRACE("(%p/%p)->(%d)\n", This, iface, Focus);
4689
4690     EnterCriticalSection(&This->cs);
4691
4692     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4693
4694     if (hr == S_OK)
4695         hr = IVideoWindow_SetWindowForeground(pVideoWindow, Focus);
4696
4697     LeaveCriticalSection(&This->cs);
4698
4699     return hr;
4700 }
4701
4702 static HRESULT WINAPI VideoWindow_NotifyOwnerMessage(IVideoWindow *iface, OAHWND hwnd, LONG uMsg,
4703         LONG_PTR wParam, LONG_PTR lParam)
4704 {
4705     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4706     IVideoWindow *pVideoWindow;
4707     HRESULT hr;
4708
4709     TRACE("(%p/%p)->(%08lx, %d, %08lx, %08lx)\n", This, iface, hwnd, uMsg, wParam, lParam);
4710
4711     EnterCriticalSection(&This->cs);
4712
4713     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4714
4715     if (hr == S_OK)
4716         hr = IVideoWindow_NotifyOwnerMessage(pVideoWindow, hwnd, uMsg, wParam, lParam);
4717
4718     LeaveCriticalSection(&This->cs);
4719
4720     return hr;
4721 }
4722
4723 static HRESULT WINAPI VideoWindow_SetWindowPosition(IVideoWindow *iface, LONG Left, LONG Top,
4724         LONG Width, LONG Height)
4725 {
4726     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4727     IVideoWindow *pVideoWindow;
4728     HRESULT hr;
4729
4730     TRACE("(%p/%p)->(%d, %d, %d, %d)\n", This, iface, Left, Top, Width, Height);
4731
4732     EnterCriticalSection(&This->cs);
4733
4734     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4735
4736     if (hr == S_OK)
4737         hr = IVideoWindow_SetWindowPosition(pVideoWindow, Left, Top, Width, Height);
4738
4739     LeaveCriticalSection(&This->cs);
4740
4741     return hr;
4742 }
4743
4744 static HRESULT WINAPI VideoWindow_GetWindowPosition(IVideoWindow *iface, LONG *pLeft, LONG *pTop,
4745         LONG *pWidth, LONG *pHeight)
4746 {
4747     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4748     IVideoWindow *pVideoWindow;
4749     HRESULT hr;
4750
4751     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
4752
4753     EnterCriticalSection(&This->cs);
4754
4755     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4756
4757     if (hr == S_OK)
4758         hr = IVideoWindow_GetWindowPosition(pVideoWindow, pLeft, pTop, pWidth, pHeight);
4759
4760     LeaveCriticalSection(&This->cs);
4761
4762     return hr;
4763 }
4764
4765 static HRESULT WINAPI VideoWindow_GetMinIdealImageSize(IVideoWindow *iface, LONG *pWidth,
4766         LONG *pHeight)
4767 {
4768     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4769     IVideoWindow *pVideoWindow;
4770     HRESULT hr;
4771
4772     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
4773
4774     EnterCriticalSection(&This->cs);
4775
4776     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4777
4778     if (hr == S_OK)
4779         hr = IVideoWindow_GetMinIdealImageSize(pVideoWindow, pWidth, pHeight);
4780
4781     LeaveCriticalSection(&This->cs);
4782
4783     return hr;
4784 }
4785
4786 static HRESULT WINAPI VideoWindow_GetMaxIdealImageSize(IVideoWindow *iface, LONG *pWidth,
4787         LONG *pHeight)
4788 {
4789     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4790     IVideoWindow *pVideoWindow;
4791     HRESULT hr;
4792
4793     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
4794
4795     EnterCriticalSection(&This->cs);
4796
4797     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4798
4799     if (hr == S_OK)
4800         hr = IVideoWindow_GetMaxIdealImageSize(pVideoWindow, pWidth, pHeight);
4801
4802     LeaveCriticalSection(&This->cs);
4803
4804     return hr;
4805 }
4806
4807 static HRESULT WINAPI VideoWindow_GetRestorePosition(IVideoWindow *iface, LONG *pLeft, LONG *pTop,
4808         LONG *pWidth, LONG *pHeight)
4809 {
4810     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4811     IVideoWindow *pVideoWindow;
4812     HRESULT hr;
4813
4814     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
4815
4816     EnterCriticalSection(&This->cs);
4817
4818     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4819
4820     if (hr == S_OK)
4821         hr = IVideoWindow_GetRestorePosition(pVideoWindow, pLeft, pTop, pWidth, pHeight);
4822
4823     LeaveCriticalSection(&This->cs);
4824
4825     return hr;
4826 }
4827
4828 static HRESULT WINAPI VideoWindow_HideCursor(IVideoWindow *iface, LONG HideCursor)
4829 {
4830     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4831     IVideoWindow *pVideoWindow;
4832     HRESULT hr;
4833
4834     TRACE("(%p/%p)->(%d)\n", This, iface, HideCursor);
4835
4836     EnterCriticalSection(&This->cs);
4837
4838     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4839
4840     if (hr == S_OK)
4841         hr = IVideoWindow_HideCursor(pVideoWindow, HideCursor);
4842
4843     LeaveCriticalSection(&This->cs);
4844
4845     return hr;
4846 }
4847
4848 static HRESULT WINAPI VideoWindow_IsCursorHidden(IVideoWindow *iface, LONG *CursorHidden)
4849 {
4850     IFilterGraphImpl *This = impl_from_IVideoWindow(iface);
4851     IVideoWindow *pVideoWindow;
4852     HRESULT hr;
4853
4854     TRACE("(%p/%p)->(%p)\n", This, iface, CursorHidden);
4855
4856     EnterCriticalSection(&This->cs);
4857
4858     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
4859
4860     if (hr == S_OK)
4861         hr = IVideoWindow_IsCursorHidden(pVideoWindow, CursorHidden);
4862
4863     LeaveCriticalSection(&This->cs);
4864
4865     return hr;
4866 }
4867
4868
4869 static const IVideoWindowVtbl IVideoWindow_VTable =
4870 {
4871     VideoWindow_QueryInterface,
4872     VideoWindow_AddRef,
4873     VideoWindow_Release,
4874     VideoWindow_GetTypeInfoCount,
4875     VideoWindow_GetTypeInfo,
4876     VideoWindow_GetIDsOfNames,
4877     VideoWindow_Invoke,
4878     VideoWindow_put_Caption,
4879     VideoWindow_get_Caption,
4880     VideoWindow_put_WindowStyle,
4881     VideoWindow_get_WindowStyle,
4882     VideoWindow_put_WindowStyleEx,
4883     VideoWindow_get_WindowStyleEx,
4884     VideoWindow_put_AutoShow,
4885     VideoWindow_get_AutoShow,
4886     VideoWindow_put_WindowState,
4887     VideoWindow_get_WindowState,
4888     VideoWindow_put_BackgroundPalette,
4889     VideoWindow_get_BackgroundPalette,
4890     VideoWindow_put_Visible,
4891     VideoWindow_get_Visible,
4892     VideoWindow_put_Left,
4893     VideoWindow_get_Left,
4894     VideoWindow_put_Width,
4895     VideoWindow_get_Width,
4896     VideoWindow_put_Top,
4897     VideoWindow_get_Top,
4898     VideoWindow_put_Height,
4899     VideoWindow_get_Height,
4900     VideoWindow_put_Owner,
4901     VideoWindow_get_Owner,
4902     VideoWindow_put_MessageDrain,
4903     VideoWindow_get_MessageDrain,
4904     VideoWindow_get_BorderColor,
4905     VideoWindow_put_BorderColor,
4906     VideoWindow_get_FullScreenMode,
4907     VideoWindow_put_FullScreenMode,
4908     VideoWindow_SetWindowForeground,
4909     VideoWindow_NotifyOwnerMessage,
4910     VideoWindow_SetWindowPosition,
4911     VideoWindow_GetWindowPosition,
4912     VideoWindow_GetMinIdealImageSize,
4913     VideoWindow_GetMaxIdealImageSize,
4914     VideoWindow_GetRestorePosition,
4915     VideoWindow_HideCursor,
4916     VideoWindow_IsCursorHidden
4917 };
4918
4919 static inline IFilterGraphImpl *impl_from_IMediaEventEx(IMediaEventEx *iface)
4920 {
4921     return CONTAINING_RECORD(iface, IFilterGraphImpl, IMediaEventEx_iface);
4922 }
4923
4924 static HRESULT WINAPI MediaEvent_QueryInterface(IMediaEventEx *iface, REFIID riid, void **ppvObj)
4925 {
4926     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
4927
4928     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
4929
4930     return Filtergraph_QueryInterface(This, riid, ppvObj);
4931 }
4932
4933 static ULONG WINAPI MediaEvent_AddRef(IMediaEventEx *iface)
4934 {
4935     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
4936
4937     TRACE("(%p/%p)->()\n", This, iface);
4938
4939     return Filtergraph_AddRef(This);
4940 }
4941
4942 static ULONG WINAPI MediaEvent_Release(IMediaEventEx *iface)
4943 {
4944     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
4945
4946     TRACE("(%p/%p)->()\n", This, iface);
4947
4948     return Filtergraph_Release(This);
4949 }
4950
4951 /*** IDispatch methods ***/
4952 static HRESULT WINAPI MediaEvent_GetTypeInfoCount(IMediaEventEx *iface, UINT *pctinfo)
4953 {
4954     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
4955
4956     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
4957
4958     return S_OK;
4959 }
4960
4961 static HRESULT WINAPI MediaEvent_GetTypeInfo(IMediaEventEx *iface, UINT iTInfo, LCID lcid,
4962         ITypeInfo **ppTInfo)
4963 {
4964     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
4965
4966     TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
4967
4968     return S_OK;
4969 }
4970
4971 static HRESULT WINAPI MediaEvent_GetIDsOfNames(IMediaEventEx *iface, REFIID riid,
4972         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
4973 {
4974     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
4975
4976     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
4977
4978     return S_OK;
4979 }
4980
4981 static HRESULT WINAPI MediaEvent_Invoke(IMediaEventEx *iface, DISPID dispIdMember, REFIID riid,
4982         LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExepInfo,
4983         UINT *puArgErr)
4984 {
4985     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
4986
4987     TRACE("(%p/%p)->(%d, %s (%p), %d, %04x, %p, %p, %p, %p): stub !!!\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
4988
4989     return S_OK;
4990 }
4991
4992 /*** IMediaEvent methods ***/
4993 static HRESULT WINAPI MediaEvent_GetEventHandle(IMediaEventEx *iface, OAEVENT *hEvent)
4994 {
4995     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
4996
4997     TRACE("(%p/%p)->(%p)\n", This, iface, hEvent);
4998
4999     *hEvent = (OAEVENT)This->evqueue.msg_event;
5000
5001     return S_OK;
5002 }
5003
5004 static HRESULT WINAPI MediaEvent_GetEvent(IMediaEventEx *iface, LONG *lEventCode, LONG_PTR *lParam1,
5005         LONG_PTR *lParam2, LONG msTimeout)
5006 {
5007     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
5008     Event evt;
5009
5010     TRACE("(%p/%p)->(%p, %p, %p, %d)\n", This, iface, lEventCode, lParam1, lParam2, msTimeout);
5011
5012     if (EventsQueue_GetEvent(&This->evqueue, &evt, msTimeout))
5013     {
5014         *lEventCode = evt.lEventCode;
5015         *lParam1 = evt.lParam1;
5016         *lParam2 = evt.lParam2;
5017         return S_OK;
5018     }
5019
5020     *lEventCode = 0;
5021     return E_ABORT;
5022 }
5023
5024 static HRESULT WINAPI MediaEvent_WaitForCompletion(IMediaEventEx *iface, LONG msTimeout,
5025         LONG *pEvCode)
5026 {
5027     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
5028
5029     TRACE("(%p/%p)->(%d, %p)\n", This, iface, msTimeout, pEvCode);
5030
5031     if (This->state != State_Running)
5032         return VFW_E_WRONG_STATE;
5033
5034     if (WaitForSingleObject(This->hEventCompletion, msTimeout) == WAIT_OBJECT_0)
5035     {
5036         *pEvCode = This->CompletionStatus;
5037         return S_OK;
5038     }
5039
5040     *pEvCode = 0;
5041     return E_ABORT;
5042 }
5043
5044 static HRESULT WINAPI MediaEvent_CancelDefaultHandling(IMediaEventEx *iface, LONG lEvCode)
5045 {
5046     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
5047
5048     TRACE("(%p/%p)->(%d)\n", This, iface, lEvCode);
5049
5050     if (lEvCode == EC_COMPLETE)
5051         This->HandleEcComplete = FALSE;
5052     else if (lEvCode == EC_REPAINT)
5053         This->HandleEcRepaint = FALSE;
5054     else if (lEvCode == EC_CLOCK_CHANGED)
5055         This->HandleEcClockChanged = FALSE;
5056     else
5057         return S_FALSE;
5058
5059     return S_OK;
5060 }
5061
5062 static HRESULT WINAPI MediaEvent_RestoreDefaultHandling(IMediaEventEx *iface, LONG lEvCode)
5063 {
5064     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
5065
5066     TRACE("(%p/%p)->(%d)\n", This, iface, lEvCode);
5067
5068     if (lEvCode == EC_COMPLETE)
5069         This->HandleEcComplete = TRUE;
5070     else if (lEvCode == EC_REPAINT)
5071         This->HandleEcRepaint = TRUE;
5072     else if (lEvCode == EC_CLOCK_CHANGED)
5073         This->HandleEcClockChanged = TRUE;
5074     else
5075         return S_FALSE;
5076
5077     return S_OK;
5078 }
5079
5080 static HRESULT WINAPI MediaEvent_FreeEventParams(IMediaEventEx *iface, LONG lEvCode,
5081         LONG_PTR lParam1, LONG_PTR lParam2)
5082 {
5083     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
5084
5085     TRACE("(%p/%p)->(%d, %08lx, %08lx): stub !!!\n", This, iface, lEvCode, lParam1, lParam2);
5086
5087     return S_OK;
5088 }
5089
5090 /*** IMediaEventEx methods ***/
5091 static HRESULT WINAPI MediaEvent_SetNotifyWindow(IMediaEventEx *iface, OAHWND hwnd, LONG lMsg,
5092         LONG_PTR lInstanceData)
5093 {
5094     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
5095
5096     TRACE("(%p/%p)->(%08lx, %d, %08lx)\n", This, iface, hwnd, lMsg, lInstanceData);
5097
5098     This->notif.hWnd = (HWND)hwnd;
5099     This->notif.msg = lMsg;
5100     This->notif.instance = lInstanceData;
5101
5102     return S_OK;
5103 }
5104
5105 static HRESULT WINAPI MediaEvent_SetNotifyFlags(IMediaEventEx *iface, LONG lNoNotifyFlags)
5106 {
5107     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
5108
5109     TRACE("(%p/%p)->(%d)\n", This, iface, lNoNotifyFlags);
5110
5111     if ((lNoNotifyFlags != 0) && (lNoNotifyFlags != 1))
5112         return E_INVALIDARG;
5113
5114     This->notif.disabled = lNoNotifyFlags;
5115
5116     return S_OK;
5117 }
5118
5119 static HRESULT WINAPI MediaEvent_GetNotifyFlags(IMediaEventEx *iface, LONG *lplNoNotifyFlags)
5120 {
5121     IFilterGraphImpl *This = impl_from_IMediaEventEx(iface);
5122
5123     TRACE("(%p/%p)->(%p)\n", This, iface, lplNoNotifyFlags);
5124
5125     if (!lplNoNotifyFlags)
5126         return E_POINTER;
5127
5128     *lplNoNotifyFlags = This->notif.disabled;
5129
5130     return S_OK;
5131 }
5132
5133
5134 static const IMediaEventExVtbl IMediaEventEx_VTable =
5135 {
5136     MediaEvent_QueryInterface,
5137     MediaEvent_AddRef,
5138     MediaEvent_Release,
5139     MediaEvent_GetTypeInfoCount,
5140     MediaEvent_GetTypeInfo,
5141     MediaEvent_GetIDsOfNames,
5142     MediaEvent_Invoke,
5143     MediaEvent_GetEventHandle,
5144     MediaEvent_GetEvent,
5145     MediaEvent_WaitForCompletion,
5146     MediaEvent_CancelDefaultHandling,
5147     MediaEvent_RestoreDefaultHandling,
5148     MediaEvent_FreeEventParams,
5149     MediaEvent_SetNotifyWindow,
5150     MediaEvent_SetNotifyFlags,
5151     MediaEvent_GetNotifyFlags
5152 };
5153
5154
5155 static inline IFilterGraphImpl *impl_from_IMediaFilter(IMediaFilter *iface)
5156 {
5157     return CONTAINING_RECORD(iface, IFilterGraphImpl, IMediaFilter_iface);
5158 }
5159
5160 static HRESULT WINAPI MediaFilter_QueryInterface(IMediaFilter *iface, REFIID riid, void **ppv)
5161 {
5162     IFilterGraphImpl *This = impl_from_IMediaFilter(iface);
5163
5164     return Filtergraph_QueryInterface(This, riid, ppv);
5165 }
5166
5167 static ULONG WINAPI MediaFilter_AddRef(IMediaFilter *iface)
5168 {
5169     IFilterGraphImpl *This = impl_from_IMediaFilter(iface);
5170
5171     return Filtergraph_AddRef(This);
5172 }
5173
5174 static ULONG WINAPI MediaFilter_Release(IMediaFilter *iface)
5175 {
5176     IFilterGraphImpl *This = impl_from_IMediaFilter(iface);
5177
5178     return Filtergraph_Release(This);
5179 }
5180
5181 static HRESULT WINAPI MediaFilter_GetClassID(IMediaFilter *iface, CLSID * pClassID)
5182 {
5183     FIXME("(%p): stub\n", pClassID);
5184
5185     return E_NOTIMPL;
5186 }
5187
5188 static HRESULT WINAPI MediaFilter_Stop(IMediaFilter *iface)
5189 {
5190     IFilterGraphImpl *This = impl_from_IMediaFilter(iface);
5191
5192     return MediaControl_Stop(&This->IMediaControl_iface);
5193 }
5194
5195 static HRESULT WINAPI MediaFilter_Pause(IMediaFilter *iface)
5196 {
5197     IFilterGraphImpl *This = impl_from_IMediaFilter(iface);
5198
5199     return MediaControl_Pause(&This->IMediaControl_iface);
5200 }
5201
5202 static HRESULT WINAPI MediaFilter_Run(IMediaFilter *iface, REFERENCE_TIME tStart)
5203 {
5204     IFilterGraphImpl *This = impl_from_IMediaFilter(iface);
5205
5206     if (tStart)
5207         FIXME("Run called with non-null tStart: %x%08x\n",
5208               (int)(tStart>>32), (int)tStart);
5209
5210     return MediaControl_Run(&This->IMediaControl_iface);
5211 }
5212
5213 static HRESULT WINAPI MediaFilter_GetState(IMediaFilter *iface, DWORD dwMsTimeout,
5214         FILTER_STATE *pState)
5215 {
5216     IFilterGraphImpl *This = impl_from_IMediaFilter(iface);
5217
5218     return MediaControl_GetState(&This->IMediaControl_iface, dwMsTimeout, (OAFilterState*)pState);
5219 }
5220
5221 static HRESULT WINAPI MediaFilter_SetSyncSource(IMediaFilter *iface, IReferenceClock *pClock)
5222 {
5223     IFilterGraphImpl *This = impl_from_IMediaFilter(iface);
5224     HRESULT hr = S_OK;
5225     int i;
5226
5227     TRACE("(%p/%p)->(%p)\n", iface, This, pClock);
5228
5229     EnterCriticalSection(&This->cs);
5230     {
5231         for (i = 0;i < This->nFilters;i++)
5232         {
5233             hr = IBaseFilter_SetSyncSource(This->ppFiltersInGraph[i], pClock);
5234             if (FAILED(hr))
5235                 break;
5236         }
5237
5238         if (FAILED(hr))
5239         {
5240             for(;i >= 0;i--)
5241                 IBaseFilter_SetSyncSource(This->ppFiltersInGraph[i], This->refClock);
5242         }
5243         else
5244         {
5245             if (This->refClock)
5246                 IReferenceClock_Release(This->refClock);
5247             This->refClock = pClock;
5248             if (This->refClock)
5249                 IReferenceClock_AddRef(This->refClock);
5250             This->defaultclock = FALSE;
5251
5252             if (This->HandleEcClockChanged)
5253             {
5254                 IMediaEventSink *pEventSink;
5255                 HRESULT eshr;
5256
5257                 eshr = IMediaFilter_QueryInterface(iface, &IID_IMediaEventSink, (LPVOID)&pEventSink);
5258                 if (SUCCEEDED(eshr))
5259                 {
5260                     IMediaEventSink_Notify(pEventSink, EC_CLOCK_CHANGED, 0, 0);
5261                     IMediaEventSink_Release(pEventSink);
5262                 }
5263             }
5264         }
5265     }
5266     LeaveCriticalSection(&This->cs);
5267
5268     return hr;
5269 }
5270
5271 static HRESULT WINAPI MediaFilter_GetSyncSource(IMediaFilter *iface, IReferenceClock **ppClock)
5272 {
5273     IFilterGraphImpl *This = impl_from_IMediaFilter(iface);
5274
5275     TRACE("(%p/%p)->(%p)\n", iface, This, ppClock);
5276
5277     if (!ppClock)
5278         return E_POINTER;
5279
5280     EnterCriticalSection(&This->cs);
5281     {
5282         *ppClock = This->refClock;
5283         if (*ppClock)
5284             IReferenceClock_AddRef(*ppClock);
5285     }
5286     LeaveCriticalSection(&This->cs);
5287
5288     return S_OK;
5289 }
5290
5291 static const IMediaFilterVtbl IMediaFilter_VTable =
5292 {
5293     MediaFilter_QueryInterface,
5294     MediaFilter_AddRef,
5295     MediaFilter_Release,
5296     MediaFilter_GetClassID,
5297     MediaFilter_Stop,
5298     MediaFilter_Pause,
5299     MediaFilter_Run,
5300     MediaFilter_GetState,
5301     MediaFilter_SetSyncSource,
5302     MediaFilter_GetSyncSource
5303 };
5304
5305 static inline IFilterGraphImpl *impl_from_IMediaEventSink(IMediaEventSink *iface)
5306 {
5307     return CONTAINING_RECORD(iface, IFilterGraphImpl, IMediaEventSink_iface);
5308 }
5309
5310 static HRESULT WINAPI MediaEventSink_QueryInterface(IMediaEventSink *iface, REFIID riid, void **ppv)
5311 {
5312     IFilterGraphImpl *This = impl_from_IMediaEventSink(iface);
5313
5314     return Filtergraph_QueryInterface(This, riid, ppv);
5315 }
5316
5317 static ULONG WINAPI MediaEventSink_AddRef(IMediaEventSink *iface)
5318 {
5319     IFilterGraphImpl *This = impl_from_IMediaEventSink(iface);
5320
5321     return Filtergraph_AddRef(This);
5322 }
5323
5324 static ULONG WINAPI MediaEventSink_Release(IMediaEventSink *iface)
5325 {
5326     IFilterGraphImpl *This = impl_from_IMediaEventSink(iface);
5327
5328     return Filtergraph_Release(This);
5329 }
5330
5331 static HRESULT WINAPI MediaEventSink_Notify(IMediaEventSink *iface, LONG EventCode,
5332         LONG_PTR EventParam1, LONG_PTR EventParam2)
5333 {
5334     IFilterGraphImpl *This = impl_from_IMediaEventSink(iface);
5335     Event evt;
5336
5337     TRACE("(%p/%p)->(%d, %ld, %ld)\n", This, iface, EventCode, EventParam1, EventParam2);
5338
5339     /* We need thread safety here, let's use the events queue's one */
5340     EnterCriticalSection(&This->evqueue.msg_crst);
5341
5342     if ((EventCode == EC_COMPLETE) && This->HandleEcComplete)
5343     {
5344         TRACE("Process EC_COMPLETE notification\n");
5345         if (++This->EcCompleteCount == This->nRenderers)
5346         {
5347             evt.lEventCode = EC_COMPLETE;
5348             evt.lParam1 = S_OK;
5349             evt.lParam2 = 0;
5350             TRACE("Send EC_COMPLETE to app\n");
5351             EventsQueue_PutEvent(&This->evqueue, &evt);
5352             if (!This->notif.disabled && This->notif.hWnd)
5353             {
5354                 TRACE("Send Window message\n");
5355                 PostMessageW(This->notif.hWnd, This->notif.msg, 0, This->notif.instance);
5356             }
5357             This->CompletionStatus = EC_COMPLETE;
5358             SetEvent(This->hEventCompletion);
5359         }
5360     }
5361     else if ((EventCode == EC_REPAINT) && This->HandleEcRepaint)
5362     {
5363         /* FIXME: Not handled yet */
5364     }
5365     else
5366     {
5367         evt.lEventCode = EventCode;
5368         evt.lParam1 = EventParam1;
5369         evt.lParam2 = EventParam2;
5370         EventsQueue_PutEvent(&This->evqueue, &evt);
5371         if (!This->notif.disabled && This->notif.hWnd)
5372             PostMessageW(This->notif.hWnd, This->notif.msg, 0, This->notif.instance);
5373     }
5374
5375     LeaveCriticalSection(&This->evqueue.msg_crst);
5376     return S_OK;
5377 }
5378
5379 static const IMediaEventSinkVtbl IMediaEventSink_VTable =
5380 {
5381     MediaEventSink_QueryInterface,
5382     MediaEventSink_AddRef,
5383     MediaEventSink_Release,
5384     MediaEventSink_Notify
5385 };
5386
5387 static inline IFilterGraphImpl *impl_from_IGraphConfig(IGraphConfig *iface)
5388 {
5389     return CONTAINING_RECORD(iface, IFilterGraphImpl, IGraphConfig_iface);
5390 }
5391
5392 static HRESULT WINAPI GraphConfig_QueryInterface(IGraphConfig *iface, REFIID riid, void **ppv)
5393 {
5394     IFilterGraphImpl *This = impl_from_IGraphConfig(iface);
5395
5396     return Filtergraph_QueryInterface(This, riid, ppv);
5397 }
5398
5399 static ULONG WINAPI GraphConfig_AddRef(IGraphConfig *iface)
5400 {
5401     IFilterGraphImpl *This = impl_from_IGraphConfig(iface);
5402
5403     return Filtergraph_AddRef(This);
5404 }
5405
5406 static ULONG WINAPI GraphConfig_Release(IGraphConfig *iface)
5407 {
5408     IFilterGraphImpl *This = impl_from_IGraphConfig(iface);
5409
5410     return Filtergraph_Release(This);
5411 }
5412
5413 static HRESULT WINAPI GraphConfig_Reconnect(IGraphConfig *iface, IPin *pOutputPin, IPin *pInputPin,
5414         const AM_MEDIA_TYPE *pmtFirstConnection, IBaseFilter *pUsingFilter, HANDLE hAbortEvent,
5415         DWORD dwFlags)
5416 {
5417     IFilterGraphImpl *This = impl_from_IGraphConfig(iface);
5418
5419     FIXME("(%p)->(%p, %p, %p, %p, %p, %x): stub!\n", This, pOutputPin, pInputPin, pmtFirstConnection, pUsingFilter, hAbortEvent, dwFlags);
5420     
5421     return E_NOTIMPL;
5422 }
5423
5424 static HRESULT WINAPI GraphConfig_Reconfigure(IGraphConfig *iface, IGraphConfigCallback *pCallback,
5425         void *pvContext, DWORD dwFlags, HANDLE hAbortEvent)
5426 {
5427     IFilterGraphImpl *This = impl_from_IGraphConfig(iface);
5428     HRESULT hr;
5429
5430     WARN("(%p)->(%p, %p, %x, %p): partial stub!\n", This, pCallback, pvContext, dwFlags, hAbortEvent);
5431
5432     if (hAbortEvent)
5433         FIXME("The parameter hAbortEvent is not handled!\n");
5434
5435     EnterCriticalSection(&This->cs);
5436
5437     hr = IGraphConfigCallback_Reconfigure(pCallback, pvContext, dwFlags);
5438
5439     LeaveCriticalSection(&This->cs);
5440
5441     return hr;
5442 }
5443
5444 static HRESULT WINAPI GraphConfig_AddFilterToCache(IGraphConfig *iface, IBaseFilter *pFilter)
5445 {
5446     IFilterGraphImpl *This = impl_from_IGraphConfig(iface);
5447
5448     FIXME("(%p)->(%p): stub!\n", This, pFilter);
5449
5450     return E_NOTIMPL;
5451 }
5452
5453 static HRESULT WINAPI GraphConfig_EnumCacheFilter(IGraphConfig *iface, IEnumFilters **pEnum)
5454 {
5455     IFilterGraphImpl *This = impl_from_IGraphConfig(iface);
5456
5457     FIXME("(%p)->(%p): stub!\n", This, pEnum);
5458
5459     return E_NOTIMPL;
5460 }
5461
5462 static HRESULT WINAPI GraphConfig_RemoveFilterFromCache(IGraphConfig *iface, IBaseFilter *pFilter)
5463 {
5464     IFilterGraphImpl *This = impl_from_IGraphConfig(iface);
5465
5466     FIXME("(%p)->(%p): stub!\n", This, pFilter);
5467
5468     return E_NOTIMPL;
5469 }
5470
5471 static HRESULT WINAPI GraphConfig_GetStartTime(IGraphConfig *iface, REFERENCE_TIME *prtStart)
5472 {
5473     IFilterGraphImpl *This = impl_from_IGraphConfig(iface);
5474
5475     FIXME("(%p)->(%p): stub!\n", This, prtStart);
5476
5477     return E_NOTIMPL;
5478 }
5479
5480 static HRESULT WINAPI GraphConfig_PushThroughData(IGraphConfig *iface, IPin *pOutputPin,
5481         IPinConnection *pConnection, HANDLE hEventAbort)
5482 {
5483     IFilterGraphImpl *This = impl_from_IGraphConfig(iface);
5484
5485     FIXME("(%p)->(%p, %p, %p): stub!\n", This, pOutputPin, pConnection, hEventAbort);
5486
5487     return E_NOTIMPL;
5488 }
5489
5490 static HRESULT WINAPI GraphConfig_SetFilterFlags(IGraphConfig *iface, IBaseFilter *pFilter,
5491         DWORD dwFlags)
5492 {
5493     IFilterGraphImpl *This = impl_from_IGraphConfig(iface);
5494
5495     FIXME("(%p)->(%p, %x): stub!\n", This, pFilter, dwFlags);
5496
5497     return E_NOTIMPL;
5498 }
5499
5500 static HRESULT WINAPI GraphConfig_GetFilterFlags(IGraphConfig *iface, IBaseFilter *pFilter,
5501         DWORD *dwFlags)
5502 {
5503     IFilterGraphImpl *This = impl_from_IGraphConfig(iface);
5504
5505     FIXME("(%p)->(%p, %p): stub!\n", This, pFilter, dwFlags);
5506
5507     return E_NOTIMPL;
5508 }
5509
5510 static HRESULT WINAPI GraphConfig_RemoveFilterEx(IGraphConfig *iface, IBaseFilter *pFilter,
5511         DWORD dwFlags)
5512 {
5513     IFilterGraphImpl *This = impl_from_IGraphConfig(iface);
5514
5515     FIXME("(%p)->(%p, %x): stub!\n", This, pFilter, dwFlags);
5516
5517     return E_NOTIMPL;
5518 }
5519
5520 static const IGraphConfigVtbl IGraphConfig_VTable =
5521 {
5522     GraphConfig_QueryInterface,
5523     GraphConfig_AddRef,
5524     GraphConfig_Release,
5525     GraphConfig_Reconnect,
5526     GraphConfig_Reconfigure,
5527     GraphConfig_AddFilterToCache,
5528     GraphConfig_EnumCacheFilter,
5529     GraphConfig_RemoveFilterFromCache,
5530     GraphConfig_GetStartTime,
5531     GraphConfig_PushThroughData,
5532     GraphConfig_SetFilterFlags,
5533     GraphConfig_GetFilterFlags,
5534     GraphConfig_RemoveFilterEx
5535 };
5536
5537 static const IUnknownVtbl IInner_VTable =
5538 {
5539     FilterGraphInner_QueryInterface,
5540     FilterGraphInner_AddRef,
5541     FilterGraphInner_Release
5542 };
5543
5544 static HRESULT Filtergraph_QueryInterface(IFilterGraphImpl *This,
5545                                           REFIID riid,
5546                                           LPVOID * ppv) {
5547     if (This->bAggregatable)
5548         This->bUnkOuterValid = TRUE;
5549
5550     if (This->pUnkOuter)
5551     {
5552         if (This->bAggregatable)
5553             return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv);
5554
5555         if (IsEqualIID(riid, &IID_IUnknown))
5556         {
5557             HRESULT hr;
5558
5559             IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
5560             hr = IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
5561             IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
5562             This->bAggregatable = TRUE;
5563             return hr;
5564         }
5565
5566         *ppv = NULL;
5567         return E_NOINTERFACE;
5568     }
5569
5570     return IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
5571 }
5572
5573 static ULONG Filtergraph_AddRef(IFilterGraphImpl *This) {
5574     if (This->pUnkOuter && This->bUnkOuterValid)
5575         return IUnknown_AddRef(This->pUnkOuter);
5576     return IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
5577 }
5578
5579 static ULONG Filtergraph_Release(IFilterGraphImpl *This) {
5580     if (This->pUnkOuter && This->bUnkOuterValid)
5581         return IUnknown_Release(This->pUnkOuter);
5582     return IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
5583 }
5584
5585 /* This is the only function that actually creates a FilterGraph class... */
5586 HRESULT FilterGraph_create(IUnknown *pUnkOuter, LPVOID *ppObj)
5587 {
5588     IFilterGraphImpl *fimpl;
5589     HRESULT hr;
5590
5591     TRACE("(%p,%p)\n", pUnkOuter, ppObj);
5592
5593     *ppObj = NULL;
5594
5595     fimpl = CoTaskMemAlloc(sizeof(*fimpl));
5596     fimpl->pUnkOuter = pUnkOuter;
5597     fimpl->bUnkOuterValid = FALSE;
5598     fimpl->bAggregatable = FALSE;
5599     fimpl->defaultclock = TRUE;
5600     fimpl->IInner_vtbl = &IInner_VTable;
5601     fimpl->IFilterGraph2_iface.lpVtbl = &IFilterGraph2_VTable;
5602     fimpl->IMediaControl_iface.lpVtbl = &IMediaControl_VTable;
5603     fimpl->IMediaSeeking_iface.lpVtbl = &IMediaSeeking_VTable;
5604     fimpl->IBasicAudio_iface.lpVtbl = &IBasicAudio_VTable;
5605     fimpl->IBasicVideo2_iface.lpVtbl = &IBasicVideo_VTable;
5606     fimpl->IVideoWindow_iface.lpVtbl = &IVideoWindow_VTable;
5607     fimpl->IMediaEventEx_iface.lpVtbl = &IMediaEventEx_VTable;
5608     fimpl->IMediaFilter_iface.lpVtbl = &IMediaFilter_VTable;
5609     fimpl->IMediaEventSink_iface.lpVtbl = &IMediaEventSink_VTable;
5610     fimpl->IGraphConfig_iface.lpVtbl = &IGraphConfig_VTable;
5611     fimpl->IMediaPosition_iface.lpVtbl = &IMediaPosition_VTable;
5612     fimpl->IObjectWithSite_iface.lpVtbl = &IObjectWithSite_VTable;
5613     fimpl->ref = 1;
5614     fimpl->ppFiltersInGraph = NULL;
5615     fimpl->pFilterNames = NULL;
5616     fimpl->nFilters = 0;
5617     fimpl->filterCapacity = 0;
5618     fimpl->nameIndex = 1;
5619     fimpl->refClock = NULL;
5620     fimpl->hEventCompletion = CreateEventW(0, TRUE, FALSE, 0);
5621     fimpl->HandleEcComplete = TRUE;
5622     fimpl->HandleEcRepaint = TRUE;
5623     fimpl->HandleEcClockChanged = TRUE;
5624     fimpl->notif.hWnd = 0;
5625     fimpl->notif.disabled = FALSE;
5626     fimpl->nRenderers = 0;
5627     fimpl->EcCompleteCount = 0;
5628     fimpl->refClockProvider = NULL;
5629     fimpl->state = State_Stopped;
5630     fimpl->pSite = NULL;
5631     EventsQueue_Init(&fimpl->evqueue);
5632     InitializeCriticalSection(&fimpl->cs);
5633     fimpl->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IFilterGraphImpl.cs");
5634     fimpl->nItfCacheEntries = 0;
5635     memcpy(&fimpl->timeformatseek, &TIME_FORMAT_MEDIA_TIME, sizeof(GUID));
5636     fimpl->start_time = fimpl->pause_time = 0;
5637     fimpl->stop_position = -1;
5638     fimpl->punkFilterMapper2 = NULL;
5639     fimpl->recursioncount = 0;
5640
5641     /* create Filtermapper aggregated. */
5642     hr = CoCreateInstance(&CLSID_FilterMapper2, pUnkOuter ? pUnkOuter : (IUnknown*)&fimpl->IInner_vtbl, CLSCTX_INPROC_SERVER,
5643         &IID_IUnknown, (LPVOID*)&fimpl->punkFilterMapper2);
5644
5645     if (SUCCEEDED(hr)) {
5646         hr = IUnknown_QueryInterface(fimpl->punkFilterMapper2, &IID_IFilterMapper2,  (LPVOID*)&fimpl->pFilterMapper2);
5647     }
5648
5649     if (SUCCEEDED(hr)) {
5650         /* Release controlling IUnknown - compensate refcount increase from caching IFilterMapper2 interface. */
5651         if (pUnkOuter) IUnknown_Release(pUnkOuter);
5652         else IUnknown_Release((IUnknown*)&fimpl->IInner_vtbl);
5653     }
5654
5655     if (FAILED(hr)) {
5656         ERR("Unable to create filter mapper (%x)\n", hr);
5657         if (fimpl->punkFilterMapper2) IUnknown_Release(fimpl->punkFilterMapper2);
5658         CloseHandle(fimpl->hEventCompletion);
5659         EventsQueue_Destroy(&fimpl->evqueue);
5660         fimpl->cs.DebugInfo->Spare[0] = 0;
5661         DeleteCriticalSection(&fimpl->cs);
5662         CoTaskMemFree(fimpl);
5663         return hr;
5664     }
5665
5666     *ppObj = fimpl;
5667     return S_OK;
5668 }
5669
5670 HRESULT FilterGraphNoThread_create(IUnknown *pUnkOuter, LPVOID *ppObj)
5671 {
5672     FIXME("CLSID_FilterGraphNoThread partially implemented - Forwarding to CLSID_FilterGraph\n");
5673     return FilterGraph_create(pUnkOuter, ppObj);
5674 }