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