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