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