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