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