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