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