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