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