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