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