Added reconnect function for filtergraph.
[wine] / dlls / quartz / filtergraph.c
1 /*              DirectShow FilterGraph object (QUARTZ.DLL)
2  *
3  * Copyright 2002 Lionel Ulmer
4  * Copyright 2004 Christian Costa
5  *
6  * This file contains the (internal) driver registration functions,
7  * driver enumeration APIs and DirectDraw creation functions.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 #include "config.h"
25 #include <stdarg.h>
26
27 #define COBJMACROS
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winuser.h"
32 #include "dshow.h"
33 #include "wine/debug.h"
34 #include "quartz_private.h"
35 #define COM_NO_WINDOWS_H
36 #include "ole2.h"
37 #include "olectl.h"
38 #include "strmif.h"
39 #include "vfwmsgs.h"
40 #include "evcode.h"
41 #include "wine/unicode.h"
42
43
44 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
45
46 typedef struct {
47     HWND hWnd;      /* Target window */
48     long msg;       /* User window message */
49     long instance;  /* User data */
50     int  disabled;  /* Disabled messages posting */
51 } WndNotify;
52
53 typedef struct {
54     long lEventCode;   /* Event code */
55     LONG_PTR lParam1;  /* Param1 */
56     LONG_PTR lParam2;  /* Param2 */
57 } Event;
58
59 /* messages ring implementation for queuing events (taken from winmm) */
60 #define EVENTS_RING_BUFFER_INCREMENT      64
61 typedef struct {
62     Event* messages;
63     int ring_buffer_size;
64     int msg_tosave;
65     int msg_toget;
66     CRITICAL_SECTION msg_crst;
67     HANDLE msg_event; /* Signaled for no empty queue */
68 } EventsQueue;
69
70 static int EventsQueue_Init(EventsQueue* omr)
71 {
72     omr->msg_toget = 0;
73     omr->msg_tosave = 0;
74     omr->msg_event = CreateEventW(NULL, TRUE, FALSE, NULL);
75     omr->ring_buffer_size = EVENTS_RING_BUFFER_INCREMENT;
76     omr->messages = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,omr->ring_buffer_size * sizeof(Event));
77
78     InitializeCriticalSection(&omr->msg_crst);
79     return TRUE;
80 }
81
82 static int EventsQueue_Destroy(EventsQueue* omr)
83 {
84     CloseHandle(omr->msg_event);
85     HeapFree(GetProcessHeap(),0,omr->messages);
86     DeleteCriticalSection(&omr->msg_crst);
87     return TRUE;
88 }
89
90 static int EventsQueue_PutEvent(EventsQueue* omr, Event* evt)
91 {
92     EnterCriticalSection(&omr->msg_crst);
93     if ((omr->msg_toget == ((omr->msg_tosave + 1) % omr->ring_buffer_size)))
94     {
95         int old_ring_buffer_size = omr->ring_buffer_size;
96         omr->ring_buffer_size += EVENTS_RING_BUFFER_INCREMENT;
97         TRACE("omr->ring_buffer_size=%d\n",omr->ring_buffer_size);
98         omr->messages = HeapReAlloc(GetProcessHeap(),0,omr->messages, omr->ring_buffer_size * sizeof(Event));
99         /* Now we need to rearrange the ring buffer so that the new
100            buffers just allocated are in between omr->msg_tosave and
101            omr->msg_toget.
102         */
103         if (omr->msg_tosave < omr->msg_toget)
104         {
105             memmove(&(omr->messages[omr->msg_toget + EVENTS_RING_BUFFER_INCREMENT]),
106                     &(omr->messages[omr->msg_toget]),
107                     sizeof(Event)*(old_ring_buffer_size - omr->msg_toget)
108                     );
109             omr->msg_toget += EVENTS_RING_BUFFER_INCREMENT;
110         }
111     }
112     omr->messages[omr->msg_tosave] = *evt;
113     SetEvent(omr->msg_event);
114     omr->msg_tosave = (omr->msg_tosave + 1) % omr->ring_buffer_size;
115     LeaveCriticalSection(&omr->msg_crst);
116     return TRUE;
117 }
118
119 static int EventsQueue_GetEvent(EventsQueue* omr, Event* evt, long msTimeOut)
120 {
121     if (WaitForSingleObject(omr->msg_event, msTimeOut) != WAIT_OBJECT_0)
122         return FALSE;
123         
124     EnterCriticalSection(&omr->msg_crst);
125
126     if (omr->msg_toget == omr->msg_tosave) /* buffer empty ? */
127     {
128         LeaveCriticalSection(&omr->msg_crst);
129         return FALSE;
130     }
131
132     *evt = omr->messages[omr->msg_toget];
133     omr->msg_toget = (omr->msg_toget + 1) % omr->ring_buffer_size;
134
135     /* Mark the buffer as empty if needed */
136     if (omr->msg_toget == omr->msg_tosave) /* buffer empty ? */
137         ResetEvent(omr->msg_event);
138
139     LeaveCriticalSection(&omr->msg_crst);
140     return TRUE;
141 }
142
143 typedef struct _IFilterGraphImpl {
144     IGraphBuilderVtbl *IGraphBuilder_vtbl;
145     IMediaControlVtbl *IMediaControl_vtbl;
146     IMediaSeekingVtbl *IMediaSeeking_vtbl;
147     IBasicAudioVtbl *IBasicAudio_vtbl;
148     IBasicVideoVtbl *IBasicVideo_vtbl;
149     IVideoWindowVtbl *IVideoWindow_vtbl;
150     IMediaEventExVtbl *IMediaEventEx_vtbl;
151     IMediaFilterVtbl *IMediaFilter_vtbl;
152     IMediaEventSinkVtbl *IMediaEventSink_vtbl;
153     /* IAMGraphStreams */
154     /* IAMStats */
155     /* IBasicVideo2 */
156     /* IFilterChain */
157     /* IFilterGraph2 */
158     /* IFilterMapper2 */
159     /* IGraphConfig */
160     /* IGraphVersion */
161     /* IMediaPosition */
162     /* IQueueCommand */
163     /* IRegisterServiceProvider */
164     /* IResourceMananger */
165     /* IServiceProvider */
166     /* IVideoFrameStep */
167
168     ULONG ref;
169     IFilterMapper2 * pFilterMapper2;
170     IBaseFilter ** ppFiltersInGraph;
171     LPWSTR * pFilterNames;
172     int nFilters;
173     int filterCapacity;
174     long nameIndex;
175     EventsQueue evqueue;
176     HANDLE hEventCompletion;
177     int CompletionStatus;
178     WndNotify notif;
179     int nRenderers;
180     int EcCompleteCount;
181     int HandleEcComplete;
182     int HandleEcRepaint;
183     OAFilterState state;
184     CRITICAL_SECTION cs;
185 } IFilterGraphImpl;
186
187
188 static HRESULT Filtergraph_QueryInterface(IFilterGraphImpl *This,
189                                           REFIID riid,
190                                           LPVOID *ppvObj) {
191     TRACE("(%p)->(%s (%p), %p)\n", This, debugstr_guid(riid), riid, ppvObj);
192     
193     if (IsEqualGUID(&IID_IUnknown, riid) ||
194         IsEqualGUID(&IID_IFilterGraph, riid) ||
195         IsEqualGUID(&IID_IGraphBuilder, riid)) {
196         *ppvObj = &(This->IGraphBuilder_vtbl);
197         TRACE("   returning IGraphBuilder interface (%p)\n", *ppvObj);
198     } else if (IsEqualGUID(&IID_IMediaControl, riid)) {
199         *ppvObj = &(This->IMediaControl_vtbl);
200         TRACE("   returning IMediaControl interface (%p)\n", *ppvObj);
201     } else if (IsEqualGUID(&IID_IMediaSeeking, riid)) {
202         *ppvObj = &(This->IMediaSeeking_vtbl);
203         TRACE("   returning IMediaSeeking interface (%p)\n", *ppvObj);
204     } else if (IsEqualGUID(&IID_IBasicAudio, riid)) {
205         *ppvObj = &(This->IBasicAudio_vtbl);
206         TRACE("   returning IBasicAudio interface (%p)\n", *ppvObj);
207     } else if (IsEqualGUID(&IID_IBasicVideo, riid)) {
208         *ppvObj = &(This->IBasicVideo_vtbl);
209         TRACE("   returning IBasicVideo interface (%p)\n", *ppvObj);
210     } else if (IsEqualGUID(&IID_IVideoWindow, riid)) {
211         *ppvObj = &(This->IVideoWindow_vtbl);
212         TRACE("   returning IVideoWindow interface (%p)\n", *ppvObj);
213     } else if (IsEqualGUID(&IID_IMediaEvent, riid) ||
214            IsEqualGUID(&IID_IMediaEventEx, riid)) {
215         *ppvObj = &(This->IMediaEventEx_vtbl);
216         TRACE("   returning IMediaEvent(Ex) interface (%p)\n", *ppvObj);
217     } else if (IsEqualGUID(&IID_IMediaFilter, riid) ||
218           IsEqualGUID(&IID_IPersist, riid)) {
219         *ppvObj = &(This->IMediaFilter_vtbl);
220         TRACE("   returning IMediaFilter interface (%p)\n", *ppvObj);
221     } else if (IsEqualGUID(&IID_IMediaEventSink, riid)) {
222         *ppvObj = &(This->IMediaEventSink_vtbl);
223         TRACE("   returning IMediaEventSink interface (%p)\n", *ppvObj);
224     } else {
225         *ppvObj = NULL;
226         FIXME("unknown interface %s\n", debugstr_guid(riid));
227         return E_NOINTERFACE;
228     }
229
230     InterlockedIncrement(&This->ref);
231     return S_OK;
232 }
233
234 static ULONG Filtergraph_AddRef(IFilterGraphImpl *This) {
235     ULONG ref = InterlockedIncrement(&This->ref);
236
237     TRACE("(%p)->(): new ref = %ld\n", This, ref);
238     
239     return ref;
240 }
241
242 static ULONG Filtergraph_Release(IFilterGraphImpl *This) {
243     ULONG ref = InterlockedDecrement(&This->ref);
244     
245     TRACE("(%p)->(): new ref = %ld\n", This, ref);
246     
247     if (ref == 0) {
248         int i;
249         for (i = 0; i < This->nFilters; i++)
250            IBaseFilter_Release(This->ppFiltersInGraph[i]);
251         IFilterMapper2_Release(This->pFilterMapper2);
252         CloseHandle(This->hEventCompletion);
253         EventsQueue_Destroy(&This->evqueue);
254         DeleteCriticalSection(&This->cs);
255         HeapFree(GetProcessHeap(), 0, This->ppFiltersInGraph);
256         HeapFree(GetProcessHeap(), 0, This->pFilterNames);
257         HeapFree(GetProcessHeap(), 0, This);
258     }
259     return ref;
260 }
261
262
263 /*** IUnknown methods ***/
264 static HRESULT WINAPI Graphbuilder_QueryInterface(IGraphBuilder *iface,
265                                                   REFIID riid,
266                                                   LPVOID*ppvObj) {
267     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
268     
269     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
270     return Filtergraph_QueryInterface(This, riid, ppvObj);
271 }
272
273 static ULONG WINAPI Graphbuilder_AddRef(IGraphBuilder *iface) {
274     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
275     
276     TRACE("(%p/%p)->() calling FilterGraph AddRef\n", This, iface);
277     
278     return Filtergraph_AddRef(This);
279 }
280
281 static ULONG WINAPI Graphbuilder_Release(IGraphBuilder *iface) {
282     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
283     
284     TRACE("(%p/%p)->() calling FilterGraph Release\n", This, iface);
285
286     return Filtergraph_Release(This);
287 }
288
289 /*** IFilterGraph methods ***/
290 static HRESULT WINAPI Graphbuilder_AddFilter(IGraphBuilder *iface,
291                                              IBaseFilter *pFilter,
292                                              LPCWSTR pName) {
293     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
294     HRESULT hr;
295     int i,j;
296     WCHAR* wszFilterName = NULL;
297     int duplicate_name = FALSE;
298     
299     TRACE("(%p/%p)->(%p, %s (%p))\n", This, iface, pFilter, debugstr_w(pName), pName);
300
301     wszFilterName = (WCHAR*) CoTaskMemAlloc( (pName ? strlenW(pName) + 6 : 5) * sizeof(WCHAR) );
302     
303     if (pName)
304     {
305         /* Check if name already exists */
306         for(i = 0; i < This->nFilters; i++)
307             if (!strcmpW(This->pFilterNames[i], pName))
308             {
309                 duplicate_name = TRUE;
310                 break;
311             }
312     }
313
314     /* If no name given or name already existing, generate one */
315     if (!pName || duplicate_name)
316     {
317         static const WCHAR wszFmt1[] = {'%','s',' ','%','0','4','d',0};
318         static const WCHAR wszFmt2[] = {'%','0','4','d',0};
319
320         for (j = 0; j < 10000 ; j++)
321         {
322             /* Create name */
323             if (pName)
324                 sprintfW(wszFilterName, wszFmt1, pName, This->nameIndex);
325             else
326                 sprintfW(wszFilterName, wszFmt2, This->nameIndex);
327             TRACE("Generated name %s\n", debugstr_w(wszFilterName));
328
329             /* Check if the generated name already exists */
330             for(i = 0; i < This->nFilters; i++)
331                 if (!strcmpW(This->pFilterNames[i], wszFilterName))
332                     break;
333
334             /* Compute next index and exit if generated name is suitable */
335             if (This->nameIndex++ == 10000)
336                 This->nameIndex = 1;
337             if (i == This->nFilters)
338                 break;
339         }
340         /* Unable to find a suitable name */
341         if (j == 10000)
342         {
343             CoTaskMemFree(wszFilterName);
344             return VFW_E_DUPLICATE_NAME;
345         }
346     }
347     else
348         memcpy(wszFilterName, pName, (strlenW(pName) + 1) * sizeof(WCHAR));
349
350     if (This->nFilters + 1 > This->filterCapacity)
351     {
352         int newCapacity = 2*This->filterCapacity;
353         IBaseFilter ** ppNewFilters = CoTaskMemAlloc(newCapacity * sizeof(IBaseFilter*));
354         LPWSTR * pNewNames = CoTaskMemAlloc(newCapacity * sizeof(LPWSTR));
355         memcpy(ppNewFilters, This->ppFiltersInGraph, This->nFilters * sizeof(IBaseFilter*));
356         memcpy(pNewNames, This->pFilterNames, This->nFilters * sizeof(LPWSTR));
357         CoTaskMemFree(This->ppFiltersInGraph);
358         CoTaskMemFree(This->pFilterNames);
359         This->ppFiltersInGraph = ppNewFilters;
360         This->pFilterNames = pNewNames;
361         This->filterCapacity = newCapacity;
362     }
363
364     hr = IBaseFilter_JoinFilterGraph(pFilter, (IFilterGraph *)This, wszFilterName);
365
366     if (SUCCEEDED(hr))
367     {
368         IBaseFilter_AddRef(pFilter);
369         This->ppFiltersInGraph[This->nFilters] = pFilter;
370         This->pFilterNames[This->nFilters] = wszFilterName;
371         This->nFilters++;
372     }
373     else
374         CoTaskMemFree(wszFilterName);
375
376     if (SUCCEEDED(hr) && duplicate_name)
377         return VFW_S_DUPLICATE_NAME;
378         
379     return hr;
380 }
381
382 static HRESULT WINAPI Graphbuilder_RemoveFilter(IGraphBuilder *iface,
383                                                 IBaseFilter *pFilter) {
384     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
385     int i;
386     HRESULT hr = E_FAIL;
387
388     TRACE("(%p/%p)->(%p)\n", This, iface, pFilter);
389
390     /* FIXME: check graph is stopped */
391
392     for (i = 0; i < This->nFilters; i++)
393     {
394         if (This->ppFiltersInGraph[i] == pFilter)
395         {
396             /* FIXME: disconnect pins */
397             hr = IBaseFilter_JoinFilterGraph(pFilter, NULL, This->pFilterNames[i]);
398             if (SUCCEEDED(hr))
399             {
400                 IPin_Release(pFilter);
401                 CoTaskMemFree(This->pFilterNames[i]);
402                 memmove(This->ppFiltersInGraph+i, This->ppFiltersInGraph+i+1, sizeof(IBaseFilter*)*(This->nFilters - 1 - i));
403                 memmove(This->pFilterNames+i, This->pFilterNames+i+1, sizeof(LPWSTR)*(This->nFilters - 1 - i));
404                 This->nFilters--;
405                 return S_OK;
406             }
407             break;
408         }
409     }
410
411     return hr; /* FIXME: check this error code */
412 }
413
414 static HRESULT WINAPI Graphbuilder_EnumFilters(IGraphBuilder *iface,
415                                               IEnumFilters **ppEnum) {
416     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
417
418     TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
419
420     return IEnumFiltersImpl_Construct(This->ppFiltersInGraph, This->nFilters, ppEnum);
421 }
422
423 static HRESULT WINAPI Graphbuilder_FindFilterByName(IGraphBuilder *iface,
424                                                     LPCWSTR pName,
425                                                     IBaseFilter **ppFilter) {
426     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
427     int i;
428
429     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_w(pName), pName, ppFilter);
430
431     *ppFilter = NULL;
432
433     for (i = 0; i < This->nFilters; i++)
434     {
435         if (!strcmpW(pName, This->pFilterNames[i]))
436         {
437             *ppFilter = This->ppFiltersInGraph[i];
438             IBaseFilter_AddRef(*ppFilter);
439             return S_OK;
440         }
441     }
442
443     return E_FAIL; /* FIXME: check this error code */
444 }
445
446 /* NOTE: despite the implication, it doesn't matter which
447  * way round you put in the input and output pins */
448 static HRESULT WINAPI Graphbuilder_ConnectDirect(IGraphBuilder *iface,
449                                                  IPin *ppinIn,
450                                                  IPin *ppinOut,
451                                                  const AM_MEDIA_TYPE *pmt) {
452     PIN_DIRECTION dir;
453     HRESULT hr;
454
455     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
456
457     TRACE("(%p/%p)->(%p, %p, %p)\n", This, iface, ppinIn, ppinOut, pmt);
458
459     /* FIXME: check pins are in graph */
460
461     hr = IPin_QueryDirection(ppinIn, &dir);
462     if (SUCCEEDED(hr))
463     {
464         if (dir == PINDIR_INPUT)
465             hr = IPin_Connect(ppinOut, ppinIn, pmt);
466         else
467             hr = IPin_Connect(ppinIn, ppinOut, pmt);
468     }
469
470     return hr;
471 }
472
473 static HRESULT WINAPI Graphbuilder_Reconnect(IGraphBuilder *iface,
474                                              IPin *ppin) {
475     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
476     IPin *pConnectedTo = NULL;
477     HRESULT hr;
478     PIN_DIRECTION pindir;
479
480     IPin_QueryDirection(ppin, &pindir);
481     hr = IPin_ConnectedTo(ppin, &pConnectedTo);
482     if (FAILED(hr)) {
483         TRACE("Querying connected to failed: %lx\n", hr);
484         return hr; 
485     }
486     IPin_Disconnect(ppin);
487     IPin_Disconnect(pConnectedTo);
488     if (pindir == PINDIR_INPUT)
489         hr = IPin_Connect(pConnectedTo, ppin, NULL);
490     else
491         hr = IPin_Connect(ppin, pConnectedTo, NULL);
492     IPin_Release(pConnectedTo);
493     if (FAILED(hr))
494         ERR("Reconnecting pins failed, pins are not connected now..\n");
495     TRACE("(%p->%p) -- %p %p -> %lx\n", iface, This, ppin, pConnectedTo, hr);
496     return hr;
497 }
498
499 static HRESULT WINAPI Graphbuilder_Disconnect(IGraphBuilder *iface,
500                                               IPin *ppin) {
501     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
502
503     TRACE("(%p/%p)->(%p)\n", This, iface, ppin);
504
505     return IPin_Disconnect(ppin);
506 }
507
508 static HRESULT WINAPI Graphbuilder_SetDefaultSyncSource(IGraphBuilder *iface) {
509     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
510
511     TRACE("(%p/%p)->(): stub !!!\n", iface, This);
512
513     return S_OK;
514 }
515
516 static HRESULT GetFilterInfo(IMoniker* pMoniker, GUID* pclsid, VARIANT* pvar)
517 {
518     static const WCHAR wszClsidName[] = {'C','L','S','I','D',0};
519     static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
520     IPropertyBag * pPropBagCat = NULL;
521     HRESULT hr;
522
523     VariantInit(pvar);
524     V_VT(pvar) = VT_BSTR;
525
526     hr = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (LPVOID*)&pPropBagCat);
527
528     if (SUCCEEDED(hr))
529         hr = IPropertyBag_Read(pPropBagCat, wszClsidName, pvar, NULL);
530
531     if (SUCCEEDED(hr))
532         hr = CLSIDFromString(V_UNION(pvar, bstrVal), pclsid);
533
534     if (SUCCEEDED(hr))
535         hr = IPropertyBag_Read(pPropBagCat, wszFriendlyName, pvar, NULL);
536
537     if (SUCCEEDED(hr))
538         TRACE("Moniker = %s - %s\n", debugstr_guid(pclsid), debugstr_w(V_UNION(pvar, bstrVal)));
539
540     if (pPropBagCat)
541         IPropertyBag_Release(pPropBagCat);
542
543     return hr;
544 }
545
546 static HRESULT GetInternalConnections(IBaseFilter* pfilter, IPin* pinputpin, IPin*** pppins, ULONG* pnb)
547 {
548     HRESULT hr;
549     ULONG nb = 0;
550
551     TRACE("(%p, %p, %p, %p)\n", pfilter, pinputpin, pppins, pnb);
552     hr = IPin_QueryInternalConnections(pinputpin, NULL, &nb);
553     if (hr == S_OK) {
554         /* Rendered input */
555     } else if (hr == S_FALSE) {
556         *pppins = CoTaskMemAlloc(sizeof(IPin*)*nb);
557         hr = IPin_QueryInternalConnections(pinputpin, *pppins, &nb);
558         if (hr != S_OK) {
559             ERR("Error (%lx)\n", hr);
560         }
561     } else if (hr == E_NOTIMPL) {
562         /* Input connected to all outputs */
563         IEnumPins* penumpins;
564         IPin* ppin;
565         int i = 0;
566         TRACE("E_NOTIMPL\n");
567         hr = IBaseFilter_EnumPins(pfilter, &penumpins);
568         if (FAILED(hr)) {
569             ERR("filter Enumpins failed (%lx)\n", hr);
570             return hr;
571         }
572         i = 0;
573         /* Count output pins */
574         while(IEnumPins_Next(penumpins, 1, &ppin, &nb) == S_OK) {
575             PIN_DIRECTION pindir;
576             IPin_QueryDirection(ppin, &pindir);
577             if (pindir == PINDIR_OUTPUT)
578                 i++;
579             IPin_Release(ppin);
580         }
581         *pppins = CoTaskMemAlloc(sizeof(IPin*)*i);
582         /* Retrieve output pins */
583         IEnumPins_Reset(penumpins);
584         i = 0;
585         while(IEnumPins_Next(penumpins, 1, &ppin, &nb) == S_OK) {
586             PIN_DIRECTION pindir;
587             IPin_QueryDirection(ppin, &pindir);
588             if (pindir == PINDIR_OUTPUT)
589                 (*pppins)[i++] = ppin;
590             else
591                 IPin_Release(ppin);
592         }
593         nb = i;
594         if (FAILED(hr)) {
595             ERR("Next failed (%lx)\n", hr);
596             return hr;
597         }
598         IEnumPins_Release(penumpins);
599     } else if (FAILED(hr)) {
600         ERR("Cannot get internal connection (%lx)\n", hr);
601         return hr;
602     }
603
604     *pnb = nb;
605     return S_OK;
606 }
607
608 /*** IGraphBuilder methods ***/
609 static HRESULT WINAPI Graphbuilder_Connect(IGraphBuilder *iface,
610                                            IPin *ppinOut,
611                                            IPin *ppinIn) {
612     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
613     HRESULT hr;
614     AM_MEDIA_TYPE* mt;
615     IEnumMediaTypes* penummt;
616     ULONG nbmt;
617     IEnumPins* penumpins;
618     IEnumMoniker* pEnumMoniker;
619     GUID tab[2];
620     ULONG nb;
621     IMoniker* pMoniker;
622     ULONG pin;
623
624     TRACE("(%p/%p)->(%p, %p)\n", This, iface, ppinOut, ppinIn);
625
626     /* Try direct connection first */
627     hr = IPin_Connect(ppinOut, ppinIn, NULL);
628     if (SUCCEEDED(hr)) {
629         return S_OK;
630     }
631     TRACE("Direct connection failed, trying to insert other filters\n");
632
633     /* Find the appropriate transform filter than can transform the minor media type of output pin of the upstream 
634      * filter to the minor mediatype of input pin of the renderer */
635     hr = IPin_EnumMediaTypes(ppinOut, &penummt);
636     if (FAILED(hr)) {
637         ERR("EnumMediaTypes (%lx)\n", hr);
638         return hr;
639     }
640
641     hr = IEnumMediaTypes_Next(penummt, 1, &mt, &nbmt);
642     if (FAILED(hr)) {
643         ERR("IEnumMediaTypes_Next (%lx)\n", hr);
644         return hr;
645     }
646
647     if (!nbmt) {
648         ERR("No media type found!\n");
649         return S_OK;
650     }
651     TRACE("MajorType %s\n", debugstr_guid(&mt->majortype));
652     TRACE("SubType %s\n", debugstr_guid(&mt->subtype));
653
654     /* Try to find a suitable filter that can connect to the pin to render */
655     tab[0] = mt->majortype;
656     tab[1] = mt->subtype;
657     hr = IFilterMapper2_EnumMatchingFilters(This->pFilterMapper2, &pEnumMoniker, 0, FALSE, 0, TRUE, 1, tab, NULL, NULL, FALSE, FALSE, 0, NULL, NULL, NULL);
658     if (FAILED(hr)) {
659         ERR("Unable to enum filters (%lx)\n", hr);
660         return hr;
661     }
662     
663     while(IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK)
664     {
665         VARIANT var;
666         GUID clsid;
667         IPin** ppins;
668         IPin* ppinfilter = NULL;
669         IBaseFilter* pfilter = NULL;
670
671         hr = GetFilterInfo(pMoniker, &clsid, &var);
672         IMoniker_Release(pMoniker);
673         if (FAILED(hr)) {
674            ERR("Unable to retrieve filter info (%lx)\n", hr);
675            goto error;
676         }
677
678         hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&pfilter);
679         if (FAILED(hr)) {
680            ERR("Unable to create filter (%lx), trying next one\n", hr);
681            goto error;
682         }
683
684         hr = IGraphBuilder_AddFilter(iface, pfilter, NULL);
685         if (FAILED(hr)) {
686             ERR("Unable to add filter (%lx)\n", hr);
687             IBaseFilter_Release(pfilter);
688             pfilter = NULL;
689             goto error;
690         }
691
692         hr = IBaseFilter_EnumPins(pfilter, &penumpins);
693         if (FAILED(hr)) {
694             ERR("Enumpins (%lx)\n", hr);
695             goto error;
696         }
697
698         hr = IEnumPins_Next(penumpins, 1, &ppinfilter, &pin);
699         if (FAILED(hr)) {
700             ERR("Next (%lx)\n", hr);
701             goto error;
702         }
703         if (pin == 0) {
704             ERR("No Pin\n");
705             goto error;
706         }
707         IEnumPins_Release(penumpins);
708
709         hr = IPin_Connect(ppinOut, ppinfilter, NULL);
710         if (FAILED(hr)) {
711             TRACE("Cannot connect to filter (%lx), trying next one\n", hr);
712             goto error;
713         }
714         TRACE("Successfully connected to filter, follow chain...\n");
715
716         /* Render all output pins of the filter by calling IGraphBuilder_Render on each of them */
717         hr = GetInternalConnections(pfilter, ppinfilter, &ppins, &nb);
718
719         if (SUCCEEDED(hr)) {
720             int i;
721             TRACE("pins to consider: %ld\n", nb);
722             for(i = 0; i < nb; i++) {
723                 TRACE("Processing pin %d\n", i);
724                 hr = IGraphBuilder_Connect(iface, ppins[i], ppinIn);
725                 if (FAILED(hr)) {
726                    TRACE("Cannot render pin %p (%lx)\n", ppinfilter, hr);
727                 }
728                 IPin_Release(ppins[i]);
729                 if (SUCCEEDED(hr)) break;
730             }
731             while (++i < nb) IPin_Release(ppins[i]);
732             CoTaskMemFree(ppins);
733             IBaseFilter_Release(pfilter);
734             IPin_Release(ppinfilter);
735             break;
736         }
737
738 error:
739         if (ppinfilter) IPin_Release(ppinfilter);
740         if (pfilter) {
741             IGraphBuilder_RemoveFilter(iface, pfilter);
742             IBaseFilter_Release(pfilter);
743         }
744     }
745
746     IEnumMediaTypes_Release(penummt);
747     DeleteMediaType(mt);
748     
749     return S_OK;
750 }
751
752 static HRESULT WINAPI Graphbuilder_Render(IGraphBuilder *iface,
753                                           IPin *ppinOut) {
754     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
755     IEnumMediaTypes* penummt;
756     AM_MEDIA_TYPE* mt;
757     ULONG nbmt;
758     HRESULT hr;
759
760     IEnumMoniker* pEnumMoniker;
761     GUID tab[2];
762     ULONG nb;
763     IMoniker* pMoniker;
764
765     TRACE("(%p/%p)->(%p)\n", This, iface, ppinOut);
766
767     hr = IPin_EnumMediaTypes(ppinOut, &penummt);
768     if (FAILED(hr)) {
769         ERR("EnumMediaTypes (%lx)\n", hr);
770         return hr;
771     }
772
773     while(1)
774     {
775         hr = IEnumMediaTypes_Next(penummt, 1, &mt, &nbmt);
776         if (FAILED(hr)) {
777             ERR("IEnumMediaTypes_Next (%lx)\n", hr);
778             return hr;
779         }
780         if (!nbmt)
781             break;
782         TRACE("MajorType %s\n", debugstr_guid(&mt->majortype));
783         TRACE("SubType %s\n", debugstr_guid(&mt->subtype));
784
785         /* Try to find a suitable renderer with the same media type */
786         tab[0] = mt->majortype;
787         tab[1] = GUID_NULL;
788         hr = IFilterMapper2_EnumMatchingFilters(This->pFilterMapper2, &pEnumMoniker, 0, FALSE, 0, TRUE, 1, tab, NULL, NULL, TRUE, FALSE, 0, NULL, NULL, NULL);
789         if (FAILED(hr)) {
790             ERR("Unable to enum filters (%lx)\n", hr);
791             return hr;
792         }
793
794         while(IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK)
795         {
796             VARIANT var;
797             GUID clsid;
798             IPin* ppinfilter;
799             IBaseFilter* pfilter = NULL;
800             IEnumPins* penumpins;
801             ULONG pin;
802
803             hr = GetFilterInfo(pMoniker, &clsid, &var);
804             IMoniker_Release(pMoniker);
805             if (FAILED(hr)) {
806                 ERR("Unable to retrieve filter info (%lx)\n", hr);
807                 goto error;
808             }
809
810             hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&pfilter);
811             if (FAILED(hr)) {
812                ERR("Unable to create filter (%lx), trying next one\n", hr);
813                goto error;
814             }
815
816             hr = IGraphBuilder_AddFilter(iface, pfilter, NULL);
817             if (FAILED(hr)) {
818                 ERR("Unable to add filter (%lx)\n", hr);
819                 IBaseFilter_Release(pfilter);
820                 pfilter = NULL;
821                 goto error;
822             }
823
824             hr = IBaseFilter_EnumPins(pfilter, &penumpins);
825             if (FAILED(hr)) {
826                 ERR("Splitter Enumpins (%lx)\n", hr);
827                 goto error;
828             }
829             hr = IEnumPins_Next(penumpins, 1, &ppinfilter, &pin);
830             if (FAILED(hr)) {
831                ERR("Next (%lx)\n", hr);
832                goto error;
833             }
834             if (pin == 0) {
835                ERR("No Pin\n");
836                goto error;
837             }
838             IEnumPins_Release(penumpins);
839
840             /* Connect the pin to render to the renderer */
841             hr = IGraphBuilder_Connect(iface, ppinOut, ppinfilter);
842             if (FAILED(hr)) {
843                 TRACE("Unable to connect to renderer (%lx)\n", hr);
844                 goto error;
845             }
846             break;
847
848 error:
849             if (pfilter) {
850                 IGraphBuilder_RemoveFilter(iface, pfilter);
851                 IBaseFilter_Release(pfilter);
852             }
853         }
854        
855         DeleteMediaType(mt);
856         break;  
857     }
858
859     IEnumMediaTypes_Release(penummt);
860     
861     return S_OK;
862 }
863
864 static HRESULT WINAPI Graphbuilder_RenderFile(IGraphBuilder *iface,
865                                               LPCWSTR lpcwstrFile,
866                                               LPCWSTR lpcwstrPlayList) {
867     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
868     static const WCHAR string[] = {'R','e','a','d','e','r',0};
869     IBaseFilter* preader = NULL;
870     IBaseFilter* psplitter;
871     IPin* ppinreader;
872     IPin* ppinsplitter;
873     IEnumPins* penumpins;
874     ULONG pin;
875     HRESULT hr;
876     IEnumMoniker* pEnumMoniker;
877     GUID tab[2];
878     IPin** ppins;
879     ULONG nb;
880     IMoniker* pMoniker;
881     IFileSourceFilter* pfile = NULL;
882     AM_MEDIA_TYPE mt;
883     WCHAR* filename;
884
885     TRACE("(%p/%p)->(%s, %s)\n", This, iface, debugstr_w(lpcwstrFile), debugstr_w(lpcwstrPlayList));
886
887     hr = IGraphBuilder_AddSourceFilter(iface, lpcwstrFile, string, &preader);
888
889     /* Retrieve file media type */
890     if (SUCCEEDED(hr))
891         hr = IBaseFilter_QueryInterface(preader, &IID_IFileSourceFilter, (LPVOID*)&pfile);
892     if (SUCCEEDED(hr)) {
893         hr = IFileSourceFilter_GetCurFile(pfile, &filename, &mt);
894         IFileSourceFilter_Release(pfile);
895     }
896
897     if (SUCCEEDED(hr)) {
898         tab[0] = mt.majortype;
899         tab[1] = mt.subtype;
900         hr = IFilterMapper2_EnumMatchingFilters(This->pFilterMapper2, &pEnumMoniker, 0, FALSE, 0, TRUE, 1, tab, NULL, NULL, FALSE, FALSE, 0, NULL, NULL, NULL);
901     }
902
903     if (FAILED(hr))
904     {
905         if (preader) {
906              IGraphBuilder_RemoveFilter(iface, preader);
907              IBaseFilter_Release(preader);
908         }
909         return hr;
910     }
911
912     hr = E_FAIL;
913     while(IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK)
914     {
915         VARIANT var;
916         GUID clsid;
917
918         hr = GetFilterInfo(pMoniker, &clsid, &var);
919         IMoniker_Release(pMoniker);
920         if (FAILED(hr)) {
921             ERR("Unable to retrieve filter info (%lx)\n", hr);
922             continue;
923         }
924
925         hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&psplitter);
926         if (FAILED(hr)) {
927            ERR("Unable to create filter (%lx), trying next one\n", hr);
928            continue;
929         }
930
931         hr = IGraphBuilder_AddFilter(iface, psplitter, NULL);
932         if (FAILED(hr)) {
933             ERR("Unable add filter (%lx)\n", hr);
934             return hr;
935         }
936
937         /* Connect file source and splitter filters together */
938         /* Make the splitter analyze incoming data */
939         hr = IBaseFilter_EnumPins(preader, &penumpins);
940         if (FAILED(hr)) {
941             ERR("Enumpins (%lx)\n", hr);
942             return hr;
943         }
944         hr = IEnumPins_Next(penumpins, 1, &ppinreader, &pin);
945         if (FAILED(hr)) {
946             ERR("Next (%lx)\n", hr);
947             return hr;
948         }
949         if (pin == 0) {
950             ERR("No Pin\n");
951             return E_FAIL;
952         }
953         IEnumPins_Release(penumpins);
954
955         hr = IBaseFilter_EnumPins(psplitter, &penumpins);
956         if (FAILED(hr)) {
957             ERR("Splitter Enumpins (%lx)\n", hr);
958             return hr;
959         }
960         hr = IEnumPins_Next(penumpins, 1, &ppinsplitter, &pin);
961         if (FAILED(hr)) {
962             ERR("Next (%lx)\n", hr);
963             return hr;
964         }
965         if (pin == 0) {
966             ERR("No Pin\n");
967             return E_FAIL;
968         }
969         IEnumPins_Release(penumpins);
970
971         hr = IPin_Connect(ppinreader, ppinsplitter, NULL);
972         if (FAILED(hr)) {
973             IBaseFilter_Release(ppinsplitter);
974             ppinsplitter = NULL;
975             TRACE("Cannot connect to filter (%lx), trying next one\n", hr);
976             break;
977         }
978         TRACE("Successfully connected to filter\n");
979         break;
980     }
981
982     /* Render all output pin of the splitter by calling IGraphBuilder_Render on each of them */
983     if (SUCCEEDED(hr))
984         hr = GetInternalConnections(psplitter, ppinsplitter, &ppins, &nb);
985     
986     if (SUCCEEDED(hr)) {
987         int i;
988         TRACE("pins to consider: %ld\n", nb);
989         for(i = 0; i < nb; i++) {
990             TRACE("Processing pin %d\n", i);
991             hr = IGraphBuilder_Render(iface, ppins[i]);
992             if (FAILED(hr)) {
993                 ERR("Cannot render pin %p (%lx)\n", ppins[i], hr);
994                 /* FIXME: We should clean created things properly */
995                 break;
996             }
997         }
998         CoTaskMemFree(ppins);
999     }
1000     
1001     return hr;
1002 }
1003
1004 static HRESULT WINAPI Graphbuilder_AddSourceFilter(IGraphBuilder *iface,
1005                                                    LPCWSTR lpcwstrFileName,
1006                                                    LPCWSTR lpcwstrFilterName,
1007                                                    IBaseFilter **ppFilter) {
1008     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
1009     HRESULT hr;
1010     IBaseFilter* preader;
1011     IFileSourceFilter* pfile = NULL;
1012     AM_MEDIA_TYPE mt;
1013     WCHAR* filename;
1014
1015     TRACE("(%p/%p)->(%s, %s, %p)\n", This, iface, debugstr_w(lpcwstrFileName), debugstr_w(lpcwstrFilterName), ppFilter);
1016
1017     /* Instantiate a file source filter */ 
1018     hr = CoCreateInstance(&CLSID_AsyncReader, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&preader);
1019     if (FAILED(hr)) {
1020         ERR("Unable to create file source filter (%lx)\n", hr);
1021         return hr;
1022     }
1023
1024     hr = IGraphBuilder_AddFilter(iface, preader, lpcwstrFilterName);
1025     if (FAILED(hr)) {
1026         ERR("Unable add filter (%lx)\n", hr);
1027         IBaseFilter_Release(preader);
1028         return hr;
1029     }
1030
1031     hr = IBaseFilter_QueryInterface(preader, &IID_IFileSourceFilter, (LPVOID*)&pfile);
1032     if (FAILED(hr)) {
1033         ERR("Unable to get IFileSourceInterface (%lx)\n", hr);
1034         goto error;
1035     }
1036
1037     /* Load the file in the file source filter */
1038     hr = IFileSourceFilter_Load(pfile, lpcwstrFileName, NULL);
1039     if (FAILED(hr)) {
1040         ERR("Load (%lx)\n", hr);
1041         goto error;
1042     }
1043     
1044     IFileSourceFilter_GetCurFile(pfile, &filename, &mt);
1045     if (FAILED(hr)) {
1046         ERR("GetCurFile (%lx)\n", hr);
1047         goto error;
1048     }
1049     TRACE("File %s\n", debugstr_w(filename));
1050     TRACE("MajorType %s\n", debugstr_guid(&mt.majortype));
1051     TRACE("SubType %s\n", debugstr_guid(&mt.subtype));
1052
1053     if (ppFilter)
1054         *ppFilter = preader;
1055
1056     return S_OK;
1057     
1058 error:
1059     if (pfile)
1060         IFileSourceFilter_Release(pfile);
1061     IGraphBuilder_RemoveFilter(iface, preader);
1062     IBaseFilter_Release(preader);
1063        
1064     return hr;
1065 }
1066
1067 static HRESULT WINAPI Graphbuilder_SetLogFile(IGraphBuilder *iface,
1068                                               DWORD_PTR hFile) {
1069     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
1070
1071     TRACE("(%p/%p)->(%08lx): stub !!!\n", This, iface, (DWORD) hFile);
1072
1073     return S_OK;
1074 }
1075
1076 static HRESULT WINAPI Graphbuilder_Abort(IGraphBuilder *iface) {
1077     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
1078
1079     TRACE("(%p/%p)->(): stub !!!\n", This, iface);
1080
1081     return S_OK;
1082 }
1083
1084 static HRESULT WINAPI Graphbuilder_ShouldOperationContinue(IGraphBuilder *iface) {
1085     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
1086
1087     TRACE("(%p/%p)->(): stub !!!\n", This, iface);
1088
1089     return S_OK;
1090 }
1091
1092
1093 static IGraphBuilderVtbl IGraphBuilder_VTable =
1094 {
1095     Graphbuilder_QueryInterface,
1096     Graphbuilder_AddRef,
1097     Graphbuilder_Release,
1098     Graphbuilder_AddFilter,
1099     Graphbuilder_RemoveFilter,
1100     Graphbuilder_EnumFilters,
1101     Graphbuilder_FindFilterByName,
1102     Graphbuilder_ConnectDirect,
1103     Graphbuilder_Reconnect,
1104     Graphbuilder_Disconnect,
1105     Graphbuilder_SetDefaultSyncSource,
1106     Graphbuilder_Connect,
1107     Graphbuilder_Render,
1108     Graphbuilder_RenderFile,
1109     Graphbuilder_AddSourceFilter,
1110     Graphbuilder_SetLogFile,
1111     Graphbuilder_Abort,
1112     Graphbuilder_ShouldOperationContinue
1113 };
1114
1115 /*** IUnknown methods ***/
1116 static HRESULT WINAPI Mediacontrol_QueryInterface(IMediaControl *iface,
1117                                                   REFIID riid,
1118                                                   LPVOID*ppvObj) {
1119     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1120
1121     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1122
1123     return Filtergraph_QueryInterface(This, riid, ppvObj);
1124 }
1125
1126 static ULONG WINAPI Mediacontrol_AddRef(IMediaControl *iface) {
1127     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1128
1129     TRACE("(%p/%p)->()\n", This, iface);
1130
1131     return Filtergraph_AddRef(This);
1132 }
1133
1134 static ULONG WINAPI Mediacontrol_Release(IMediaControl *iface) {
1135     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1136
1137     TRACE("(%p/%p)->()\n", This, iface);
1138
1139     return Filtergraph_Release(This);
1140
1141 }
1142
1143 /*** IDispatch methods ***/
1144 static HRESULT WINAPI Mediacontrol_GetTypeInfoCount(IMediaControl *iface,
1145                                                     UINT*pctinfo) {
1146     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1147
1148     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
1149
1150     return S_OK;
1151 }
1152
1153 static HRESULT WINAPI Mediacontrol_GetTypeInfo(IMediaControl *iface,
1154                                                UINT iTInfo,
1155                                                LCID lcid,
1156                                                ITypeInfo**ppTInfo) {
1157     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1158
1159     TRACE("(%p/%p)->(%d, %ld, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
1160
1161     return S_OK;
1162 }
1163
1164 static HRESULT WINAPI Mediacontrol_GetIDsOfNames(IMediaControl *iface,
1165                                                  REFIID riid,
1166                                                  LPOLESTR*rgszNames,
1167                                                  UINT cNames,
1168                                                  LCID lcid,
1169                                                  DISPID*rgDispId) {
1170     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1171
1172     TRACE("(%p/%p)->(%s (%p), %p, %d, %ld, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
1173
1174     return S_OK;
1175 }
1176
1177 static HRESULT WINAPI Mediacontrol_Invoke(IMediaControl *iface,
1178                                           DISPID dispIdMember,
1179                                           REFIID riid,
1180                                           LCID lcid,
1181                                           WORD wFlags,
1182                                           DISPPARAMS*pDispParams,
1183                                           VARIANT*pVarResult,
1184                                           EXCEPINFO*pExepInfo,
1185                                           UINT*puArgErr) {
1186     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1187
1188     TRACE("(%p/%p)->(%ld, %s (%p), %ld, %04x, %p, %p, %p, %p): stub !!!\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
1189
1190     return S_OK;
1191 }
1192
1193 typedef HRESULT(WINAPI *fnFoundFilter)(IBaseFilter *);
1194
1195 static HRESULT ExploreGraph(IFilterGraphImpl* pGraph, IPin* pOutputPin, fnFoundFilter FoundFilter)
1196 {
1197     HRESULT hr;
1198     IPin* pInputPin;
1199     IPin** ppPins;
1200     ULONG nb;
1201     ULONG i;
1202     PIN_INFO PinInfo;
1203
1204     TRACE("%p %p\n", pGraph, pOutputPin);
1205     PinInfo.pFilter = NULL;
1206
1207     hr = IPin_ConnectedTo(pOutputPin, &pInputPin);
1208
1209     if (SUCCEEDED(hr))
1210         hr = IPin_QueryPinInfo(pInputPin, &PinInfo);
1211
1212     if (SUCCEEDED(hr))
1213         hr = GetInternalConnections(PinInfo.pFilter, pInputPin, &ppPins, &nb);
1214
1215     if (SUCCEEDED(hr))
1216     {
1217         if (nb == 0)
1218         {
1219             TRACE("Reached a renderer\n");
1220             /* Count renderers for end of stream notification */
1221             pGraph->nRenderers++;
1222         }
1223         else
1224         {
1225             for(i = 0; i < nb; i++)
1226             {
1227                 /* Explore the graph downstream from this pin
1228                  * FIXME: We should prevent exploring from a pin more than once. This can happens when
1229                  * several input pins are connected to the same output (a MUX for instance). */
1230                 ExploreGraph(pGraph, ppPins[i], FoundFilter);
1231                 IPin_Release(ppPins[i]);
1232             }
1233
1234             CoTaskMemFree(ppPins);
1235         }
1236         TRACE("Doing stuff with filter %p\n", PinInfo.pFilter);
1237         FoundFilter(PinInfo.pFilter);
1238     }
1239
1240     if (PinInfo.pFilter) IBaseFilter_Release(PinInfo.pFilter);
1241     return hr;
1242 }
1243
1244 static HRESULT WINAPI SendRun(IBaseFilter *pFilter) {
1245    return IBaseFilter_Run(pFilter, 0);
1246 }
1247
1248 static HRESULT WINAPI SendPause(IBaseFilter *pFilter) {
1249    return IBaseFilter_Pause(pFilter);
1250 }
1251
1252 static HRESULT WINAPI SendStop(IBaseFilter *pFilter) {
1253    return IBaseFilter_Stop(pFilter);
1254 }
1255
1256 static HRESULT SendFilterMessage(IMediaControl *iface, fnFoundFilter FoundFilter) {
1257     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1258     int i;
1259     IBaseFilter* pfilter;
1260     IEnumPins* pEnum;
1261     HRESULT hr;
1262     IPin* pPin;
1263     LONG dummy;
1264     PIN_DIRECTION dir;
1265     TRACE("(%p/%p)->()\n", This, iface);
1266
1267     /* Explorer the graph from source filters to renderers, determine renderers
1268      * number and run filters from renderers to source filters */
1269     This->nRenderers = 0;  
1270     ResetEvent(This->hEventCompletion);
1271
1272     for(i = 0; i < This->nFilters; i++)
1273     {
1274         BOOL source = TRUE;
1275         pfilter = This->ppFiltersInGraph[i];
1276         hr = IBaseFilter_EnumPins(pfilter, &pEnum);
1277         if (hr != S_OK)
1278         {
1279             ERR("Enum pins failed %lx\n", hr);
1280             continue;
1281         }
1282         /* Check if it is a source filter */
1283         while(IEnumPins_Next(pEnum, 1, &pPin, &dummy) == S_OK)
1284         {
1285             IPin_QueryDirection(pPin, &dir);
1286             IPin_Release(pPin);
1287             if (dir == PINDIR_INPUT)
1288             {
1289                 source = FALSE;
1290                 break;
1291             }
1292         }
1293         if (source == TRUE)
1294         {
1295             TRACE("Found a source filter\n");
1296             IEnumPins_Reset(pEnum);
1297             while(IEnumPins_Next(pEnum, 1, &pPin, &dummy) == S_OK)
1298             {
1299                 /* Explore the graph downstream from this pin */
1300                 ExploreGraph(This, pPin, FoundFilter);
1301                 IPin_Release(pPin);
1302             }
1303             FoundFilter(pfilter);
1304         }
1305         IEnumPins_Release(pEnum);
1306     }
1307
1308     return S_FALSE;
1309 }
1310
1311 /*** IMediaControl methods ***/
1312 static HRESULT WINAPI Mediacontrol_Run(IMediaControl *iface) {
1313     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1314     TRACE("(%p/%p)->()\n", This, iface);
1315
1316     if (This->state == State_Running) return S_OK;
1317
1318     EnterCriticalSection(&This->cs);
1319     SendFilterMessage(iface, SendRun);
1320     This->state = State_Running;
1321     LeaveCriticalSection(&This->cs);
1322     return S_FALSE;
1323 }
1324
1325 static HRESULT WINAPI Mediacontrol_Pause(IMediaControl *iface) {
1326     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1327     TRACE("(%p/%p)->()\n", This, iface);
1328
1329     if (This->state == State_Paused) return S_OK;
1330
1331     EnterCriticalSection(&This->cs);
1332     SendFilterMessage(iface, SendPause);
1333     This->state = State_Paused;
1334     LeaveCriticalSection(&This->cs);
1335     return S_FALSE;
1336 }
1337
1338 static HRESULT WINAPI Mediacontrol_Stop(IMediaControl *iface) {
1339     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1340     TRACE("(%p/%p)->()\n", This, iface);
1341
1342     if (This->state == State_Stopped) return S_OK;
1343
1344     EnterCriticalSection(&This->cs);
1345     if (This->state == State_Running) SendFilterMessage(iface, SendPause);
1346     SendFilterMessage(iface, SendStop);
1347     This->state = State_Stopped;
1348     LeaveCriticalSection(&This->cs);
1349     return S_FALSE;
1350 }
1351
1352 static HRESULT WINAPI Mediacontrol_GetState(IMediaControl *iface,
1353                                             LONG msTimeout,
1354                                             OAFilterState *pfs) {
1355     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1356
1357     TRACE("(%p/%p)->(%ld, %p): semi-stub !!!\n", This, iface, msTimeout, pfs);
1358
1359     EnterCriticalSection(&This->cs);
1360
1361     *pfs = This->state;
1362
1363     LeaveCriticalSection(&This->cs);
1364     
1365     return S_OK;
1366 }
1367
1368 static HRESULT WINAPI Mediacontrol_RenderFile(IMediaControl *iface,
1369                                               BSTR strFilename) {
1370     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1371
1372     TRACE("(%p/%p)->(%s (%p)): stub !!!\n", This, iface, debugstr_w(strFilename), strFilename);
1373
1374     return S_OK;
1375 }
1376
1377 static HRESULT WINAPI Mediacontrol_AddSourceFilter(IMediaControl *iface,
1378                                                    BSTR strFilename,
1379                                                    IDispatch **ppUnk) {
1380     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1381
1382     TRACE("(%p/%p)->(%s (%p), %p): stub !!!\n", This, iface, debugstr_w(strFilename), strFilename, ppUnk);
1383
1384     return S_OK;
1385 }
1386
1387 static HRESULT WINAPI Mediacontrol_get_FilterCollection(IMediaControl *iface,
1388                                                         IDispatch **ppUnk) {
1389     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1390
1391     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, ppUnk);
1392
1393     return S_OK;
1394 }
1395
1396 static HRESULT WINAPI Mediacontrol_get_RegFilterCollection(IMediaControl *iface,
1397                                                            IDispatch **ppUnk) {
1398     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1399
1400     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, ppUnk);
1401
1402     return S_OK;
1403 }
1404
1405 static HRESULT WINAPI Mediacontrol_StopWhenReady(IMediaControl *iface) {
1406     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
1407
1408     TRACE("(%p/%p)->(): stub !!!\n", This, iface);
1409
1410     return S_OK;
1411 }
1412
1413
1414 static IMediaControlVtbl IMediaControl_VTable =
1415 {
1416     Mediacontrol_QueryInterface,
1417     Mediacontrol_AddRef,
1418     Mediacontrol_Release,
1419     Mediacontrol_GetTypeInfoCount,
1420     Mediacontrol_GetTypeInfo,
1421     Mediacontrol_GetIDsOfNames,
1422     Mediacontrol_Invoke,
1423     Mediacontrol_Run,
1424     Mediacontrol_Pause,
1425     Mediacontrol_Stop,
1426     Mediacontrol_GetState,
1427     Mediacontrol_RenderFile,
1428     Mediacontrol_AddSourceFilter,
1429     Mediacontrol_get_FilterCollection,
1430     Mediacontrol_get_RegFilterCollection,
1431     Mediacontrol_StopWhenReady
1432 };
1433
1434
1435 /*** IUnknown methods ***/
1436 static HRESULT WINAPI Mediaseeking_QueryInterface(IMediaSeeking *iface,
1437                                                   REFIID riid,
1438                                                   LPVOID*ppvObj) {
1439     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1440
1441     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1442
1443     return Filtergraph_QueryInterface(This, riid, ppvObj);
1444 }
1445
1446 static ULONG WINAPI Mediaseeking_AddRef(IMediaSeeking *iface) {
1447     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1448
1449     TRACE("(%p/%p)->()\n", This, iface);
1450
1451     return Filtergraph_AddRef(This);
1452 }
1453
1454 static ULONG WINAPI Mediaseeking_Release(IMediaSeeking *iface) {
1455     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1456
1457     TRACE("(%p/%p)->()\n", This, iface);
1458
1459     return Filtergraph_Release(This);
1460 }
1461
1462 /*** IMediaSeeking methods ***/
1463 static HRESULT WINAPI Mediaseeking_GetCapabilities(IMediaSeeking *iface,
1464                                                    DWORD *pCapabilities) {
1465     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1466
1467     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pCapabilities);
1468
1469     return S_OK;
1470 }
1471
1472 static HRESULT WINAPI Mediaseeking_CheckCapabilities(IMediaSeeking *iface,
1473                                                      DWORD *pCapabilities) {
1474     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1475
1476     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pCapabilities);
1477
1478     return S_OK;
1479 }
1480
1481 static HRESULT WINAPI Mediaseeking_IsFormatSupported(IMediaSeeking *iface,
1482                                                      const GUID *pFormat) {
1483     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1484
1485     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pFormat);
1486
1487     return S_OK;
1488 }
1489
1490 static HRESULT WINAPI Mediaseeking_QueryPreferredFormat(IMediaSeeking *iface,
1491                                                         GUID *pFormat) {
1492     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1493
1494     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pFormat);
1495
1496     return S_OK;
1497 }
1498
1499 static HRESULT WINAPI Mediaseeking_GetTimeFormat(IMediaSeeking *iface,
1500                                                  GUID *pFormat) {
1501     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1502
1503     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pFormat);
1504
1505     return S_OK;
1506 }
1507
1508 static HRESULT WINAPI Mediaseeking_IsUsingTimeFormat(IMediaSeeking *iface,
1509                                                      const GUID *pFormat) {
1510     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1511
1512     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pFormat);
1513
1514     return S_OK;
1515 }
1516
1517 static HRESULT WINAPI Mediaseeking_SetTimeFormat(IMediaSeeking *iface,
1518                                                  const GUID *pFormat) {
1519     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1520
1521     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pFormat);
1522
1523     return S_OK;
1524 }
1525
1526 static HRESULT WINAPI Mediaseeking_GetDuration(IMediaSeeking *iface,
1527                                                LONGLONG *pDuration) {
1528     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1529
1530     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pDuration);
1531
1532     return S_OK;
1533 }
1534
1535 static HRESULT WINAPI Mediaseeking_GetStopPosition(IMediaSeeking *iface,
1536                                                    LONGLONG *pStop) {
1537     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1538
1539     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pStop);
1540
1541     return S_OK;
1542 }
1543
1544 static HRESULT WINAPI Mediaseeking_GetCurrentPosition(IMediaSeeking *iface,
1545                                                       LONGLONG *pCurrent) {
1546     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1547
1548     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pCurrent);
1549
1550     return S_OK;
1551 }
1552
1553 static HRESULT WINAPI Mediaseeking_ConvertTimeFormat(IMediaSeeking *iface,
1554                                                      LONGLONG *pTarget,
1555                                                      const GUID *pTargetFormat,
1556                                                      LONGLONG Source,
1557                                                      const GUID *pSourceFormat) {
1558     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1559
1560     TRACE("(%p/%p)->(%p, %p, %lld, %p): stub !!!\n", This, iface, pTarget, pTargetFormat, Source, pSourceFormat);
1561
1562     return S_OK;
1563 }
1564
1565 static HRESULT WINAPI Mediaseeking_SetPositions(IMediaSeeking *iface,
1566                                                 LONGLONG *pCurrent,
1567                                                 DWORD dwCurrentFlags,
1568                                                 LONGLONG *pStop,
1569                                                 DWORD dwStopFlags) {
1570     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1571
1572     TRACE("(%p/%p)->(%p, %08lx, %p, %08lx): stub !!!\n", This, iface, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
1573
1574     return S_OK;
1575 }
1576
1577 static HRESULT WINAPI Mediaseeking_GetPositions(IMediaSeeking *iface,
1578                                                 LONGLONG *pCurrent,
1579                                                 LONGLONG *pStop) {
1580     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1581
1582     TRACE("(%p/%p)->(%p, %p): stub !!!\n", This, iface, pCurrent, pStop);
1583
1584     return S_OK;
1585 }
1586
1587 static HRESULT WINAPI Mediaseeking_GetAvailable(IMediaSeeking *iface,
1588                                                 LONGLONG *pEarliest,
1589                                                 LONGLONG *pLatest) {
1590     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1591
1592     TRACE("(%p/%p)->(%p, %p): stub !!!\n", This, iface, pEarliest, pLatest);
1593
1594     return S_OK;
1595 }
1596
1597 static HRESULT WINAPI Mediaseeking_SetRate(IMediaSeeking *iface,
1598                                            double dRate) {
1599     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1600
1601     TRACE("(%p/%p)->(%f): stub !!!\n", This, iface, dRate);
1602
1603     return S_OK;
1604 }
1605
1606 static HRESULT WINAPI Mediaseeking_GetRate(IMediaSeeking *iface,
1607                                            double *pdRate) {
1608     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1609
1610     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pdRate);
1611
1612     return S_OK;
1613 }
1614
1615 static HRESULT WINAPI Mediaseeking_GetPreroll(IMediaSeeking *iface,
1616                                               LONGLONG *pllPreroll) {
1617     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
1618
1619     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pllPreroll);
1620
1621     return S_OK;
1622 }
1623
1624
1625 static IMediaSeekingVtbl IMediaSeeking_VTable =
1626 {
1627     Mediaseeking_QueryInterface,
1628     Mediaseeking_AddRef,
1629     Mediaseeking_Release,
1630     Mediaseeking_GetCapabilities,
1631     Mediaseeking_CheckCapabilities,
1632     Mediaseeking_IsFormatSupported,
1633     Mediaseeking_QueryPreferredFormat,
1634     Mediaseeking_GetTimeFormat,
1635     Mediaseeking_IsUsingTimeFormat,
1636     Mediaseeking_SetTimeFormat,
1637     Mediaseeking_GetDuration,
1638     Mediaseeking_GetStopPosition,
1639     Mediaseeking_GetCurrentPosition,
1640     Mediaseeking_ConvertTimeFormat,
1641     Mediaseeking_SetPositions,
1642     Mediaseeking_GetPositions,
1643     Mediaseeking_GetAvailable,
1644     Mediaseeking_SetRate,
1645     Mediaseeking_GetRate,
1646     Mediaseeking_GetPreroll
1647 };
1648
1649 /*** IUnknown methods ***/
1650 static HRESULT WINAPI Basicaudio_QueryInterface(IBasicAudio *iface,
1651                                                 REFIID riid,
1652                                                 LPVOID*ppvObj) {
1653     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
1654
1655     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1656
1657     return Filtergraph_QueryInterface(This, riid, ppvObj);
1658 }
1659
1660 static ULONG WINAPI Basicaudio_AddRef(IBasicAudio *iface) {
1661     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
1662
1663     TRACE("(%p/%p)->()\n", This, iface);
1664
1665     return Filtergraph_AddRef(This);
1666 }
1667
1668 static ULONG WINAPI Basicaudio_Release(IBasicAudio *iface) {
1669     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
1670
1671     TRACE("(%p/%p)->()\n", This, iface);
1672
1673     return Filtergraph_Release(This);
1674 }
1675
1676 /*** IDispatch methods ***/
1677 static HRESULT WINAPI Basicaudio_GetTypeInfoCount(IBasicAudio *iface,
1678                                                   UINT*pctinfo) {
1679     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
1680
1681     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
1682
1683     return S_OK;
1684 }
1685
1686 static HRESULT WINAPI Basicaudio_GetTypeInfo(IBasicAudio *iface,
1687                                              UINT iTInfo,
1688                                              LCID lcid,
1689                                              ITypeInfo**ppTInfo) {
1690     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
1691
1692     TRACE("(%p/%p)->(%d, %ld, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
1693
1694     return S_OK;
1695 }
1696
1697 static HRESULT WINAPI Basicaudio_GetIDsOfNames(IBasicAudio *iface,
1698                                                REFIID riid,
1699                                                LPOLESTR*rgszNames,
1700                                                UINT cNames,
1701                                                LCID lcid,
1702                                                DISPID*rgDispId) {
1703     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
1704
1705     TRACE("(%p/%p)->(%s (%p), %p, %d, %ld, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
1706
1707     return S_OK;
1708 }
1709
1710 static HRESULT WINAPI Basicaudio_Invoke(IBasicAudio *iface,
1711                                         DISPID dispIdMember,
1712                                         REFIID riid,
1713                                         LCID lcid,
1714                                         WORD wFlags,
1715                                         DISPPARAMS*pDispParams,
1716                                         VARIANT*pVarResult,
1717                                         EXCEPINFO*pExepInfo,
1718                                         UINT*puArgErr) {
1719     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
1720
1721     TRACE("(%p/%p)->(%ld, %s (%p), %ld, %04x, %p, %p, %p, %p): stub !!!\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
1722
1723     return S_OK;
1724 }
1725
1726 /*** IBasicAudio methods ***/
1727 static HRESULT WINAPI Basicaudio_put_Volume(IBasicAudio *iface,
1728                                             long lVolume) {
1729     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
1730
1731     TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, lVolume);
1732
1733     return S_OK;
1734 }
1735
1736 static HRESULT WINAPI Basicaudio_get_Volume(IBasicAudio *iface,
1737                                             long *plVolume) {
1738     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
1739
1740     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, plVolume);
1741
1742     return S_OK;
1743 }
1744
1745 static HRESULT WINAPI Basicaudio_put_Balance(IBasicAudio *iface,
1746                                              long lBalance) {
1747     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
1748
1749     TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, lBalance);
1750
1751     return S_OK;
1752 }
1753
1754 static HRESULT WINAPI Basicaudio_get_Balance(IBasicAudio *iface,
1755                                              long *plBalance) {
1756     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
1757
1758     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, plBalance);
1759
1760     return S_OK;
1761 }
1762
1763 static IBasicAudioVtbl IBasicAudio_VTable =
1764 {
1765     Basicaudio_QueryInterface,
1766     Basicaudio_AddRef,
1767     Basicaudio_Release,
1768     Basicaudio_GetTypeInfoCount,
1769     Basicaudio_GetTypeInfo,
1770     Basicaudio_GetIDsOfNames,
1771     Basicaudio_Invoke,
1772     Basicaudio_put_Volume,
1773     Basicaudio_get_Volume,
1774     Basicaudio_put_Balance,
1775     Basicaudio_get_Balance
1776 };
1777
1778 /*** IUnknown methods ***/
1779 static HRESULT WINAPI Basicvideo_QueryInterface(IBasicVideo *iface,
1780                                                 REFIID riid,
1781                                                 LPVOID*ppvObj) {
1782     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
1783
1784     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1785
1786     return Filtergraph_QueryInterface(This, riid, ppvObj);
1787 }
1788
1789 static ULONG WINAPI Basicvideo_AddRef(IBasicVideo *iface) {
1790     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
1791
1792     TRACE("(%p/%p)->()\n", This, iface);
1793
1794     return Filtergraph_AddRef(This);
1795 }
1796
1797 static ULONG WINAPI Basicvideo_Release(IBasicVideo *iface) {
1798     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
1799
1800     TRACE("(%p/%p)->()\n", This, iface);
1801
1802     return Filtergraph_Release(This);
1803 }
1804
1805 /*** IDispatch methods ***/
1806 static HRESULT WINAPI Basicvideo_GetTypeInfoCount(IBasicVideo *iface,
1807                                                   UINT*pctinfo) {
1808     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
1809
1810     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
1811
1812     return S_OK;
1813 }
1814
1815 static HRESULT WINAPI Basicvideo_GetTypeInfo(IBasicVideo *iface,
1816                                              UINT iTInfo,
1817                                              LCID lcid,
1818                                              ITypeInfo**ppTInfo) {
1819     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
1820
1821     TRACE("(%p/%p)->(%d, %ld, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
1822
1823     return S_OK;
1824 }
1825
1826 static HRESULT WINAPI Basicvideo_GetIDsOfNames(IBasicVideo *iface,
1827                                                REFIID riid,
1828                                                LPOLESTR*rgszNames,
1829                                                UINT cNames,
1830                                                LCID lcid,
1831                                                DISPID*rgDispId) {
1832     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
1833
1834     TRACE("(%p/%p)->(%s (%p), %p, %d, %ld, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
1835
1836     return S_OK;
1837 }
1838
1839 static HRESULT WINAPI Basicvideo_Invoke(IBasicVideo *iface,
1840                                         DISPID dispIdMember,
1841                                         REFIID riid,
1842                                         LCID lcid,
1843                                         WORD wFlags,
1844                                         DISPPARAMS*pDispParams,
1845                                         VARIANT*pVarResult,
1846                                         EXCEPINFO*pExepInfo,
1847                                         UINT*puArgErr) {
1848     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
1849
1850     TRACE("(%p/%p)->(%ld, %s (%p), %ld, %04x, %p, %p, %p, %p): stub !!!\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
1851
1852     return S_OK;
1853 }
1854
1855 /*** IBasicVideo methods ***/
1856 static HRESULT WINAPI Basicvideo_get_AvgTimePerFrame(IBasicVideo *iface,
1857                                                      REFTIME *pAvgTimePerFrame) {
1858     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
1859
1860     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pAvgTimePerFrame);
1861
1862     return S_OK;
1863 }
1864
1865 static HRESULT WINAPI Basicvideo_get_BitRate(IBasicVideo *iface,
1866                                              long *pBitRate) {
1867     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
1868
1869     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pBitRate);
1870
1871     return S_OK;
1872 }
1873
1874 static HRESULT WINAPI Basicvideo_get_BitErrorRate(IBasicVideo *iface,
1875                                                   long *pBitErrorRate) {
1876     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
1877
1878     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pBitErrorRate);
1879
1880     return S_OK;
1881 }
1882
1883 static HRESULT WINAPI Basicvideo_get_VideoWidth(IBasicVideo *iface,
1884                                                 long *pVideoWidth) {
1885     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
1886
1887     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pVideoWidth);
1888
1889     return S_OK;
1890 }
1891
1892 static HRESULT WINAPI Basicvideo_get_VideoHeight(IBasicVideo *iface,
1893                                                  long *pVideoHeight) {
1894     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
1895
1896     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pVideoHeight);
1897
1898     return S_OK;
1899 }
1900
1901 static HRESULT WINAPI Basicvideo_put_SourceLeft(IBasicVideo *iface,
1902                                                 long SourceLeft) {
1903     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
1904
1905     TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, SourceLeft);
1906
1907     return S_OK;
1908 }
1909
1910 static HRESULT WINAPI Basicvideo_get_SourceLeft(IBasicVideo *iface,
1911                                                 long *pSourceLeft) {
1912     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
1913
1914     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pSourceLeft);
1915
1916     return S_OK;
1917 }
1918
1919 static HRESULT WINAPI Basicvideo_put_SourceWidth(IBasicVideo *iface,
1920                                                  long SourceWidth) {
1921     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
1922
1923     TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, SourceWidth);
1924
1925     return S_OK;
1926 }
1927
1928 static HRESULT WINAPI Basicvideo_get_SourceWidth(IBasicVideo *iface,
1929                                                  long *pSourceWidth) {
1930     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
1931
1932     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pSourceWidth);
1933
1934     return S_OK;
1935 }
1936
1937 static HRESULT WINAPI Basicvideo_put_SourceTop(IBasicVideo *iface,
1938                                                long SourceTop) {
1939     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
1940
1941     TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, SourceTop);
1942
1943     return S_OK;
1944 }
1945
1946 static HRESULT WINAPI Basicvideo_get_SourceTop(IBasicVideo *iface,
1947                                                long *pSourceTop) {
1948     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
1949
1950     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pSourceTop);
1951
1952     return S_OK;
1953 }
1954
1955 static HRESULT WINAPI Basicvideo_put_SourceHeight(IBasicVideo *iface,
1956                                                   long SourceHeight) {
1957     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
1958
1959     TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, SourceHeight);
1960
1961     return S_OK;
1962 }
1963
1964 static HRESULT WINAPI Basicvideo_get_SourceHeight(IBasicVideo *iface,
1965                                                   long *pSourceHeight) {
1966     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
1967
1968     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pSourceHeight);
1969
1970     return S_OK;
1971 }
1972
1973 static HRESULT WINAPI Basicvideo_put_DestinationLeft(IBasicVideo *iface,
1974                                                      long DestinationLeft) {
1975     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
1976
1977     TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, DestinationLeft);
1978
1979     return S_OK;
1980 }
1981
1982 static HRESULT WINAPI Basicvideo_get_DestinationLeft(IBasicVideo *iface,
1983                                                      long *pDestinationLeft) {
1984     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
1985
1986     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pDestinationLeft);
1987
1988     return S_OK;
1989 }
1990
1991 static HRESULT WINAPI Basicvideo_put_DestinationWidth(IBasicVideo *iface,
1992                                                       long DestinationWidth) {
1993     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
1994
1995     TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, DestinationWidth);
1996
1997     return S_OK;
1998 }
1999
2000 static HRESULT WINAPI Basicvideo_get_DestinationWidth(IBasicVideo *iface,
2001                                                       long *pDestinationWidth) {
2002     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2003
2004     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pDestinationWidth);
2005
2006     return S_OK;
2007 }
2008
2009 static HRESULT WINAPI Basicvideo_put_DestinationTop(IBasicVideo *iface,
2010                                                     long DestinationTop) {
2011     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2012
2013     TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, DestinationTop);
2014
2015     return S_OK;
2016 }
2017
2018 static HRESULT WINAPI Basicvideo_get_DestinationTop(IBasicVideo *iface,
2019                                                     long *pDestinationTop) {
2020     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2021
2022     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pDestinationTop);
2023
2024     return S_OK;
2025 }
2026
2027 static HRESULT WINAPI Basicvideo_put_DestinationHeight(IBasicVideo *iface,
2028                                                        long DestinationHeight) {
2029     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2030
2031     TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, DestinationHeight);
2032
2033     return S_OK;
2034 }
2035
2036 static HRESULT WINAPI Basicvideo_get_DestinationHeight(IBasicVideo *iface,
2037                                                        long *pDestinationHeight) {
2038     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2039
2040     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pDestinationHeight);
2041
2042     return S_OK;
2043 }
2044
2045 static HRESULT WINAPI Basicvideo_SetSourcePosition(IBasicVideo *iface,
2046                                                    long Left,
2047                                                    long Top,
2048                                                    long Width,
2049                                                    long Height) {
2050     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2051
2052     TRACE("(%p/%p)->(%ld, %ld, %ld, %ld): stub !!!\n", This, iface, Left, Top, Width, Height);
2053
2054     return S_OK;
2055 }
2056
2057 static HRESULT WINAPI Basicvideo_GetSourcePosition(IBasicVideo *iface,
2058                                                    long *pLeft,
2059                                                    long *pTop,
2060                                                    long *pWidth,
2061                                                    long *pHeight) {
2062     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2063
2064     TRACE("(%p/%p)->(%p, %p, %p, %p): stub !!!\n", This, iface, pLeft, pTop, pWidth, pHeight);
2065
2066     return S_OK;
2067 }
2068
2069 static HRESULT WINAPI Basicvideo_SetDefaultSourcePosition(IBasicVideo *iface) {
2070     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2071
2072     TRACE("(%p/%p)->(): stub !!!\n", This, iface);
2073
2074     return S_OK;
2075 }
2076
2077 static HRESULT WINAPI Basicvideo_SetDestinationPosition(IBasicVideo *iface,
2078                                                         long Left,
2079                                                         long Top,
2080                                                         long Width,
2081                                                         long Height) {
2082     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2083
2084     TRACE("(%p/%p)->(%ld, %ld, %ld, %ld): stub !!!\n", This, iface, Left, Top, Width, Height);
2085
2086     return S_OK;
2087 }
2088
2089 static HRESULT WINAPI Basicvideo_GetDestinationPosition(IBasicVideo *iface,
2090                                                         long *pLeft,
2091                                                         long *pTop,
2092                                                         long *pWidth,
2093                                                         long *pHeight) {
2094     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2095
2096     TRACE("(%p/%p)->(%p, %p, %p, %p): stub !!!\n", This, iface, pLeft, pTop, pWidth, pHeight);
2097
2098     return S_OK;
2099 }
2100
2101 static HRESULT WINAPI Basicvideo_SetDefaultDestinationPosition(IBasicVideo *iface) {
2102     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2103
2104     TRACE("(%p/%p)->(): stub !!!\n", This, iface);
2105
2106     return S_OK;
2107 }
2108
2109 static HRESULT WINAPI Basicvideo_GetVideoSize(IBasicVideo *iface,
2110                                               long *pWidth,
2111                                               long *pHeight) {
2112     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2113
2114     TRACE("(%p/%p)->(%p, %p): stub !!!\n", This, iface, pWidth, pHeight);
2115
2116     return S_OK;
2117 }
2118
2119 static HRESULT WINAPI Basicvideo_GetVideoPaletteEntries(IBasicVideo *iface,
2120                                                         long StartIndex,
2121                                                         long Entries,
2122                                                         long *pRetrieved,
2123                                                         long *pPalette) {
2124     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2125
2126     TRACE("(%p/%p)->(%ld, %ld, %p, %p): stub !!!\n", This, iface, StartIndex, Entries, pRetrieved, pPalette);
2127
2128     return S_OK;
2129 }
2130
2131 static HRESULT WINAPI Basicvideo_GetCurrentImage(IBasicVideo *iface,
2132                                                  long *pBufferSize,
2133                                                  long *pDIBImage) {
2134     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2135
2136     TRACE("(%p/%p)->(%p, %p): stub !!!\n", This, iface, pBufferSize, pDIBImage);
2137
2138     return S_OK;
2139 }
2140
2141 static HRESULT WINAPI Basicvideo_IsUsingDefaultSource(IBasicVideo *iface) {
2142     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2143
2144     TRACE("(%p/%p)->(): stub !!!\n", This, iface);
2145
2146     return S_OK;
2147 }
2148
2149 static HRESULT WINAPI Basicvideo_IsUsingDefaultDestination(IBasicVideo *iface) {
2150     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
2151
2152     TRACE("(%p/%p)->(): stub !!!\n", This, iface);
2153
2154     return S_OK;
2155 }
2156
2157
2158 static IBasicVideoVtbl IBasicVideo_VTable =
2159 {
2160     Basicvideo_QueryInterface,
2161     Basicvideo_AddRef,
2162     Basicvideo_Release,
2163     Basicvideo_GetTypeInfoCount,
2164     Basicvideo_GetTypeInfo,
2165     Basicvideo_GetIDsOfNames,
2166     Basicvideo_Invoke,
2167     Basicvideo_get_AvgTimePerFrame,
2168     Basicvideo_get_BitRate,
2169     Basicvideo_get_BitErrorRate,
2170     Basicvideo_get_VideoWidth,
2171     Basicvideo_get_VideoHeight,
2172     Basicvideo_put_SourceLeft,
2173     Basicvideo_get_SourceLeft,
2174     Basicvideo_put_SourceWidth,
2175     Basicvideo_get_SourceWidth,
2176     Basicvideo_put_SourceTop,
2177     Basicvideo_get_SourceTop,
2178     Basicvideo_put_SourceHeight,
2179     Basicvideo_get_SourceHeight,
2180     Basicvideo_put_DestinationLeft,
2181     Basicvideo_get_DestinationLeft,
2182     Basicvideo_put_DestinationWidth,
2183     Basicvideo_get_DestinationWidth,
2184     Basicvideo_put_DestinationTop,
2185     Basicvideo_get_DestinationTop,
2186     Basicvideo_put_DestinationHeight,
2187     Basicvideo_get_DestinationHeight,
2188     Basicvideo_SetSourcePosition,
2189     Basicvideo_GetSourcePosition,
2190     Basicvideo_SetDefaultSourcePosition,
2191     Basicvideo_SetDestinationPosition,
2192     Basicvideo_GetDestinationPosition,
2193     Basicvideo_SetDefaultDestinationPosition,
2194     Basicvideo_GetVideoSize,
2195     Basicvideo_GetVideoPaletteEntries,
2196     Basicvideo_GetCurrentImage,
2197     Basicvideo_IsUsingDefaultSource,
2198     Basicvideo_IsUsingDefaultDestination
2199 };
2200
2201
2202 /*** IUnknown methods ***/
2203 static HRESULT WINAPI Videowindow_QueryInterface(IVideoWindow *iface,
2204                                                  REFIID riid,
2205                                                  LPVOID*ppvObj) {
2206     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2207
2208     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
2209
2210     return Filtergraph_QueryInterface(This, riid, ppvObj);
2211 }
2212
2213 static ULONG WINAPI Videowindow_AddRef(IVideoWindow *iface) {
2214     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2215
2216     TRACE("(%p/%p)->()\n", This, iface);
2217
2218     return Filtergraph_AddRef(This);
2219 }
2220
2221 static ULONG WINAPI Videowindow_Release(IVideoWindow *iface) {
2222     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2223
2224     TRACE("(%p/%p)->()\n", This, iface);
2225
2226     return Filtergraph_Release(This);
2227 }
2228
2229 /*** IDispatch methods ***/
2230 static HRESULT WINAPI Videowindow_GetTypeInfoCount(IVideoWindow *iface,
2231                                                    UINT*pctinfo) {
2232     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2233
2234     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
2235
2236     return S_OK;
2237 }
2238
2239 static HRESULT WINAPI Videowindow_GetTypeInfo(IVideoWindow *iface,
2240                                               UINT iTInfo,
2241                                               LCID lcid,
2242                                               ITypeInfo**ppTInfo) {
2243     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2244
2245     TRACE("(%p/%p)->(%d, %ld, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
2246
2247     return S_OK;
2248 }
2249
2250 static HRESULT WINAPI Videowindow_GetIDsOfNames(IVideoWindow *iface,
2251                                                 REFIID riid,
2252                                                 LPOLESTR*rgszNames,
2253                                                 UINT cNames,
2254                                                 LCID lcid,
2255                                                 DISPID*rgDispId) {
2256     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2257
2258     TRACE("(%p/%p)->(%s (%p), %p, %d, %ld, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
2259
2260     return S_OK;
2261 }
2262
2263 static HRESULT WINAPI Videowindow_Invoke(IVideoWindow *iface,
2264                                          DISPID dispIdMember,
2265                                          REFIID riid,
2266                                          LCID lcid,
2267                                          WORD wFlags,
2268                                          DISPPARAMS*pDispParams,
2269                                          VARIANT*pVarResult,
2270                                          EXCEPINFO*pExepInfo,
2271                                          UINT*puArgErr) {
2272     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2273
2274     TRACE("(%p/%p)->(%ld, %s (%p), %ld, %04x, %p, %p, %p, %p): stub !!!\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
2275
2276     return S_OK;
2277 }
2278
2279 /*** IVideoWindow methods ***/
2280 static HRESULT WINAPI Videowindow_put_Caption(IVideoWindow *iface,
2281                                               BSTR strCaption) {
2282     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2283
2284     TRACE("(%p/%p)->(%s (%p)): stub !!!\n", This, iface, debugstr_w(strCaption), strCaption);
2285
2286     return S_OK;
2287 }
2288
2289 static HRESULT WINAPI Videowindow_get_Caption(IVideoWindow *iface,
2290                                               BSTR *strCaption) {
2291     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2292
2293     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, strCaption);
2294
2295     return S_OK;
2296 }
2297
2298 static HRESULT WINAPI Videowindow_put_WindowStyle(IVideoWindow *iface,
2299                                                   long WindowStyle) {
2300     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2301
2302     TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, WindowStyle);
2303
2304     return S_OK;
2305 }
2306
2307 static HRESULT WINAPI Videowindow_get_WindowStyle(IVideoWindow *iface,
2308                                                   long *WindowStyle) {
2309     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2310
2311     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, WindowStyle);
2312
2313     return S_OK;
2314 }
2315
2316 static HRESULT WINAPI Videowindow_put_WindowStyleEx(IVideoWindow *iface,
2317                                                     long WindowStyleEx) {
2318     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2319
2320     TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, WindowStyleEx);
2321
2322     return S_OK;
2323 }
2324
2325 static HRESULT WINAPI Videowindow_get_WindowStyleEx(IVideoWindow *iface,
2326                                                     long *WindowStyleEx) {
2327     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2328
2329     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, WindowStyleEx);
2330
2331     return S_OK;
2332 }
2333
2334 static HRESULT WINAPI Videowindow_put_AutoShow(IVideoWindow *iface,
2335                                                long AutoShow) {
2336     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2337
2338     TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, AutoShow);
2339
2340     return S_OK;
2341 }
2342
2343 static HRESULT WINAPI Videowindow_get_AutoShow(IVideoWindow *iface,
2344                                                long *AutoShow) {
2345     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2346
2347     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, AutoShow);
2348
2349     return S_OK;
2350 }
2351
2352 static HRESULT WINAPI Videowindow_put_WindowState(IVideoWindow *iface,
2353                                                   long WindowState) {
2354     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2355
2356     TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, WindowState);
2357
2358     return S_OK;
2359 }
2360
2361 static HRESULT WINAPI Videowindow_get_WindowState(IVideoWindow *iface,
2362                                                   long *WindowState) {
2363     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2364
2365     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, WindowState);
2366
2367     return S_OK;
2368 }
2369
2370 static HRESULT WINAPI Videowindow_put_BackgroundPalette(IVideoWindow *iface,
2371                                                         long BackgroundPalette) {
2372     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2373
2374     TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, BackgroundPalette);
2375
2376     return S_OK;
2377 }
2378
2379 static HRESULT WINAPI Videowindow_get_BackgroundPalette(IVideoWindow *iface,
2380                                                         long *pBackgroundPalette) {
2381     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2382
2383     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pBackgroundPalette);
2384
2385     return S_OK;
2386 }
2387
2388 static HRESULT WINAPI Videowindow_put_Visible(IVideoWindow *iface,
2389                                               long Visible) {
2390     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2391
2392     TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, Visible);
2393
2394     return S_OK;
2395 }
2396
2397 static HRESULT WINAPI Videowindow_get_Visible(IVideoWindow *iface,
2398                                               long *pVisible) {
2399     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2400
2401     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pVisible);
2402
2403     return S_OK;
2404 }
2405
2406 static HRESULT WINAPI Videowindow_put_Left(IVideoWindow *iface,
2407                                            long Left) {
2408     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2409
2410     TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, Left);
2411
2412     return S_OK;
2413 }
2414
2415 static HRESULT WINAPI Videowindow_get_Left(IVideoWindow *iface,
2416                                            long *pLeft) {
2417     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2418
2419     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pLeft);
2420
2421     return S_OK;
2422 }
2423
2424 static HRESULT WINAPI Videowindow_put_Width(IVideoWindow *iface,
2425                                             long Width) {
2426     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2427
2428     TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, Width);
2429
2430     return S_OK;
2431 }
2432
2433 static HRESULT WINAPI Videowindow_get_Width(IVideoWindow *iface,
2434                                             long *pWidth) {
2435     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2436
2437     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pWidth);
2438
2439     return S_OK;
2440 }
2441
2442 static HRESULT WINAPI Videowindow_put_Top(IVideoWindow *iface,
2443                                           long Top) {
2444     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2445
2446     TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, Top);
2447
2448     return S_OK;
2449 }
2450
2451 static HRESULT WINAPI Videowindow_get_Top(IVideoWindow *iface,
2452                                           long *pTop) {
2453     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2454
2455     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pTop);
2456
2457     return S_OK;
2458 }
2459
2460 static HRESULT WINAPI Videowindow_put_Height(IVideoWindow *iface,
2461                                              long Height) {
2462     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2463
2464     TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, Height);
2465
2466     return S_OK;
2467 }
2468
2469 static HRESULT WINAPI Videowindow_get_Height(IVideoWindow *iface,
2470                                              long *pHeight) {
2471     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2472
2473     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pHeight);
2474
2475     return S_OK;
2476 }
2477
2478 static HRESULT WINAPI Videowindow_put_Owner(IVideoWindow *iface,
2479                                             OAHWND Owner) {
2480     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2481
2482     TRACE("(%p/%p)->(%08lx): stub !!!\n", This, iface, (DWORD) Owner);
2483
2484     return S_OK;
2485 }
2486
2487 static HRESULT WINAPI Videowindow_get_Owner(IVideoWindow *iface,
2488                                             OAHWND *Owner) {
2489     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2490
2491     TRACE("(%p/%p)->(%08lx): stub !!!\n", This, iface, (DWORD) Owner);
2492
2493     return S_OK;
2494 }
2495
2496 static HRESULT WINAPI Videowindow_put_MessageDrain(IVideoWindow *iface,
2497                                                    OAHWND Drain) {
2498     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2499
2500     TRACE("(%p/%p)->(%08lx): stub !!!\n", This, iface, (DWORD) Drain);
2501
2502     return S_OK;
2503 }
2504
2505 static HRESULT WINAPI Videowindow_get_MessageDrain(IVideoWindow *iface,
2506                                                    OAHWND *Drain) {
2507     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2508
2509     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, Drain);
2510
2511     return S_OK;
2512 }
2513
2514 static HRESULT WINAPI Videowindow_get_BorderColor(IVideoWindow *iface,
2515                                                   long *Color) {
2516     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2517
2518     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, Color);
2519
2520     return S_OK;
2521 }
2522
2523 static HRESULT WINAPI Videowindow_put_BorderColor(IVideoWindow *iface,
2524                                                   long Color) {
2525     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2526
2527     TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, Color);
2528
2529     return S_OK;
2530 }
2531
2532 static HRESULT WINAPI Videowindow_get_FullScreenMode(IVideoWindow *iface,
2533                                                      long *FullScreenMode) {
2534     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2535
2536     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, FullScreenMode);
2537
2538     return S_OK;
2539 }
2540
2541 static HRESULT WINAPI Videowindow_put_FullScreenMode(IVideoWindow *iface,
2542                                                      long FullScreenMode) {
2543     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2544
2545     TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, FullScreenMode);
2546
2547     return S_OK;
2548 }
2549
2550 static HRESULT WINAPI Videowindow_SetWindowForeground(IVideoWindow *iface,
2551                                                       long Focus) {
2552     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2553
2554     TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, Focus);
2555
2556     return S_OK;
2557 }
2558
2559 static HRESULT WINAPI Videowindow_NotifyOwnerMessage(IVideoWindow *iface,
2560                                                      OAHWND hwnd,
2561                                                      long uMsg,
2562                                                      LONG_PTR wParam,
2563                                                      LONG_PTR lParam) {
2564     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2565
2566     TRACE("(%p/%p)->(%08lx, %ld, %08lx, %08lx): stub !!!\n", This, iface, (DWORD) hwnd, uMsg, wParam, lParam);
2567
2568     return S_OK;
2569 }
2570
2571 static HRESULT WINAPI Videowindow_SetWindowPosition(IVideoWindow *iface,
2572                                                     long Left,
2573                                                     long Top,
2574                                                     long Width,
2575                                                     long Height) {
2576     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2577     
2578     TRACE("(%p/%p)->(%ld, %ld, %ld, %ld): stub !!!\n", This, iface, Left, Top, Width, Height);
2579
2580     return S_OK;
2581 }
2582
2583 static HRESULT WINAPI Videowindow_GetWindowPosition(IVideoWindow *iface,
2584                                                     long *pLeft,
2585                                                     long *pTop,
2586                                                     long *pWidth,
2587                                                     long *pHeight) {
2588     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2589
2590     TRACE("(%p/%p)->(%p, %p, %p, %p): stub !!!\n", This, iface, pLeft, pTop, pWidth, pHeight);
2591
2592     return S_OK;
2593 }
2594
2595 static HRESULT WINAPI Videowindow_GetMinIdealImageSize(IVideoWindow *iface,
2596                                                        long *pWidth,
2597                                                        long *pHeight) {
2598     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2599
2600     TRACE("(%p/%p)->(%p, %p): stub !!!\n", This, iface, pWidth, pHeight);
2601
2602     return S_OK;
2603 }
2604
2605 static HRESULT WINAPI Videowindow_GetMaxIdealImageSize(IVideoWindow *iface,
2606                                                        long *pWidth,
2607                                                        long *pHeight) {
2608     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2609
2610     TRACE("(%p/%p)->(%p, %p): stub !!!\n", This, iface, pWidth, pHeight);
2611
2612     return S_OK;
2613 }
2614
2615 static HRESULT WINAPI Videowindow_GetRestorePosition(IVideoWindow *iface,
2616                                                      long *pLeft,
2617                                                      long *pTop,
2618                                                      long *pWidth,
2619                                                      long *pHeight) {
2620     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2621
2622     TRACE("(%p/%p)->(%p, %p, %p, %p): stub !!!\n", This, iface, pLeft, pTop, pWidth, pHeight);
2623
2624     return S_OK;
2625 }
2626
2627 static HRESULT WINAPI Videowindow_HideCursor(IVideoWindow *iface,
2628                                              long HideCursor) {
2629     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2630
2631     TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, HideCursor);
2632
2633     return S_OK;
2634 }
2635
2636 static HRESULT WINAPI Videowindow_IsCursorHidden(IVideoWindow *iface,
2637                                                  long *CursorHidden) {
2638     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
2639
2640     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, CursorHidden);
2641
2642     return S_OK;
2643 }
2644
2645
2646 static IVideoWindowVtbl IVideoWindow_VTable =
2647 {
2648     Videowindow_QueryInterface,
2649     Videowindow_AddRef,
2650     Videowindow_Release,
2651     Videowindow_GetTypeInfoCount,
2652     Videowindow_GetTypeInfo,
2653     Videowindow_GetIDsOfNames,
2654     Videowindow_Invoke,
2655     Videowindow_put_Caption,
2656     Videowindow_get_Caption,
2657     Videowindow_put_WindowStyle,
2658     Videowindow_get_WindowStyle,
2659     Videowindow_put_WindowStyleEx,
2660     Videowindow_get_WindowStyleEx,
2661     Videowindow_put_AutoShow,
2662     Videowindow_get_AutoShow,
2663     Videowindow_put_WindowState,
2664     Videowindow_get_WindowState,
2665     Videowindow_put_BackgroundPalette,
2666     Videowindow_get_BackgroundPalette,
2667     Videowindow_put_Visible,
2668     Videowindow_get_Visible,
2669     Videowindow_put_Left,
2670     Videowindow_get_Left,
2671     Videowindow_put_Width,
2672     Videowindow_get_Width,
2673     Videowindow_put_Top,
2674     Videowindow_get_Top,
2675     Videowindow_put_Height,
2676     Videowindow_get_Height,
2677     Videowindow_put_Owner,
2678     Videowindow_get_Owner,
2679     Videowindow_put_MessageDrain,
2680     Videowindow_get_MessageDrain,
2681     Videowindow_get_BorderColor,
2682     Videowindow_put_BorderColor,
2683     Videowindow_get_FullScreenMode,
2684     Videowindow_put_FullScreenMode,
2685     Videowindow_SetWindowForeground,
2686     Videowindow_NotifyOwnerMessage,
2687     Videowindow_SetWindowPosition,
2688     Videowindow_GetWindowPosition,
2689     Videowindow_GetMinIdealImageSize,
2690     Videowindow_GetMaxIdealImageSize,
2691     Videowindow_GetRestorePosition,
2692     Videowindow_HideCursor,
2693     Videowindow_IsCursorHidden
2694 };
2695
2696
2697 /*** IUnknown methods ***/
2698 static HRESULT WINAPI Mediaevent_QueryInterface(IMediaEventEx *iface,
2699                                                 REFIID riid,
2700                                                 LPVOID*ppvObj) {
2701     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
2702
2703     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
2704
2705     return Filtergraph_QueryInterface(This, riid, ppvObj);
2706 }
2707
2708 static ULONG WINAPI Mediaevent_AddRef(IMediaEventEx *iface) {
2709     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
2710
2711     TRACE("(%p/%p)->()\n", This, iface);
2712
2713     return Filtergraph_AddRef(This);
2714 }
2715
2716 static ULONG WINAPI Mediaevent_Release(IMediaEventEx *iface) {
2717     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
2718
2719     TRACE("(%p/%p)->()\n", This, iface);
2720
2721     return Filtergraph_Release(This);
2722 }
2723
2724 /*** IDispatch methods ***/
2725 static HRESULT WINAPI Mediaevent_GetTypeInfoCount(IMediaEventEx *iface,
2726                                                   UINT*pctinfo) {
2727     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
2728
2729     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
2730
2731     return S_OK;
2732 }
2733
2734 static HRESULT WINAPI Mediaevent_GetTypeInfo(IMediaEventEx *iface,
2735                                              UINT iTInfo,
2736                                              LCID lcid,
2737                                              ITypeInfo**ppTInfo) {
2738     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
2739
2740     TRACE("(%p/%p)->(%d, %ld, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
2741
2742     return S_OK;
2743 }
2744
2745 static HRESULT WINAPI Mediaevent_GetIDsOfNames(IMediaEventEx *iface,
2746                                                REFIID riid,
2747                                                LPOLESTR*rgszNames,
2748                                                UINT cNames,
2749                                                LCID lcid,
2750                                                DISPID*rgDispId) {
2751     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
2752
2753     TRACE("(%p/%p)->(%s (%p), %p, %d, %ld, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
2754
2755     return S_OK;
2756 }
2757
2758 static HRESULT WINAPI Mediaevent_Invoke(IMediaEventEx *iface,
2759                                         DISPID dispIdMember,
2760                                         REFIID riid,
2761                                         LCID lcid,
2762                                         WORD wFlags,
2763                                         DISPPARAMS*pDispParams,
2764                                         VARIANT*pVarResult,
2765                                         EXCEPINFO*pExepInfo,
2766                                         UINT*puArgErr) {
2767     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
2768
2769     TRACE("(%p/%p)->(%ld, %s (%p), %ld, %04x, %p, %p, %p, %p): stub !!!\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
2770
2771     return S_OK;
2772 }
2773
2774 /*** IMediaEvent methods ***/
2775 static HRESULT WINAPI Mediaevent_GetEventHandle(IMediaEventEx *iface,
2776                                                 OAEVENT *hEvent) {
2777     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
2778
2779     TRACE("(%p/%p)->(%p)\n", This, iface, hEvent);
2780
2781     *hEvent = (OAEVENT)This->evqueue.msg_event;
2782
2783     return S_OK;
2784 }
2785
2786 static HRESULT WINAPI Mediaevent_GetEvent(IMediaEventEx *iface,
2787                                           long *lEventCode,
2788                                           LONG_PTR *lParam1,
2789                                           LONG_PTR *lParam2,
2790                                           long msTimeout) {
2791     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
2792     Event evt;
2793
2794     TRACE("(%p/%p)->(%p, %p, %p, %ld)\n", This, iface, lEventCode, lParam1, lParam2, msTimeout);
2795
2796     if (EventsQueue_GetEvent(&This->evqueue, &evt, msTimeout))
2797     {
2798         *lEventCode = evt.lEventCode;
2799         *lParam1 = evt.lParam1;
2800         *lParam2 = evt.lParam2;
2801         return S_OK;
2802     }
2803
2804     *lEventCode = 0;
2805     return E_ABORT;
2806 }
2807
2808 static HRESULT WINAPI Mediaevent_WaitForCompletion(IMediaEventEx *iface,
2809                                                    long msTimeout,
2810                                                    long *pEvCode) {
2811     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
2812
2813     TRACE("(%p/%p)->(%ld, %p)\n", This, iface, msTimeout, pEvCode);
2814
2815     if (WaitForSingleObject(This->hEventCompletion, msTimeout) == WAIT_OBJECT_0)
2816     {
2817         *pEvCode = This->CompletionStatus;
2818         return S_OK;
2819     }
2820
2821     *pEvCode = 0;
2822     return E_ABORT;
2823 }
2824
2825 static HRESULT WINAPI Mediaevent_CancelDefaultHandling(IMediaEventEx *iface,
2826                                                        long lEvCode) {
2827     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
2828
2829     TRACE("(%p/%p)->(%ld)\n", This, iface, lEvCode);
2830
2831     if (lEvCode == EC_COMPLETE)
2832         This->HandleEcComplete = FALSE;
2833     else if (lEvCode == EC_REPAINT)
2834         This->HandleEcRepaint = FALSE;
2835     else
2836         return S_FALSE;
2837
2838     return S_OK;
2839 }
2840
2841 static HRESULT WINAPI Mediaevent_RestoreDefaultHandling(IMediaEventEx *iface,
2842                                                         long lEvCode) {
2843     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
2844
2845     TRACE("(%p/%p)->(%ld)\n", This, iface, lEvCode);
2846
2847     if (lEvCode == EC_COMPLETE)
2848         This->HandleEcComplete = TRUE;
2849     else if (lEvCode == EC_REPAINT)
2850         This->HandleEcRepaint = TRUE;
2851     else
2852         return S_FALSE;
2853
2854     return S_OK;
2855 }
2856
2857 static HRESULT WINAPI Mediaevent_FreeEventParams(IMediaEventEx *iface,
2858                                                  long lEvCode,
2859                                                  LONG_PTR lParam1,
2860                                                  LONG_PTR lParam2) {
2861     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
2862
2863     TRACE("(%p/%p)->(%ld, %08lx, %08lx): stub !!!\n", This, iface, lEvCode, lParam1, lParam2);
2864
2865     return S_OK;
2866 }
2867
2868 /*** IMediaEventEx methods ***/
2869 static HRESULT WINAPI Mediaevent_SetNotifyWindow(IMediaEventEx *iface,
2870                                                  OAHWND hwnd,
2871                                                  long lMsg,
2872                                                  LONG_PTR lInstanceData) {
2873     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
2874
2875     TRACE("(%p/%p)->(%08lx, %ld, %08lx)\n", This, iface, (DWORD) hwnd, lMsg, lInstanceData);
2876
2877     This->notif.hWnd = (HWND)hwnd;
2878     This->notif.msg = lMsg;
2879     This->notif.instance = (long) lInstanceData;
2880
2881     return S_OK;
2882 }
2883
2884 static HRESULT WINAPI Mediaevent_SetNotifyFlags(IMediaEventEx *iface,
2885                                                 long lNoNotifyFlags) {
2886     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
2887
2888     TRACE("(%p/%p)->(%ld)\n", This, iface, lNoNotifyFlags);
2889
2890     if ((lNoNotifyFlags != 0) || (lNoNotifyFlags != 1))
2891         return E_INVALIDARG;
2892
2893     This->notif.disabled = lNoNotifyFlags;
2894
2895     return S_OK;
2896 }
2897
2898 static HRESULT WINAPI Mediaevent_GetNotifyFlags(IMediaEventEx *iface,
2899                                                 long *lplNoNotifyFlags) {
2900     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
2901
2902     TRACE("(%p/%p)->(%p)\n", This, iface, lplNoNotifyFlags);
2903
2904     if (!lplNoNotifyFlags)
2905         return E_POINTER;
2906
2907     *lplNoNotifyFlags = This->notif.disabled;
2908
2909     return S_OK;
2910 }
2911
2912
2913 static IMediaEventExVtbl IMediaEventEx_VTable =
2914 {
2915     Mediaevent_QueryInterface,
2916     Mediaevent_AddRef,
2917     Mediaevent_Release,
2918     Mediaevent_GetTypeInfoCount,
2919     Mediaevent_GetTypeInfo,
2920     Mediaevent_GetIDsOfNames,
2921     Mediaevent_Invoke,
2922     Mediaevent_GetEventHandle,
2923     Mediaevent_GetEvent,
2924     Mediaevent_WaitForCompletion,
2925     Mediaevent_CancelDefaultHandling,
2926     Mediaevent_RestoreDefaultHandling,
2927     Mediaevent_FreeEventParams,
2928     Mediaevent_SetNotifyWindow,
2929     Mediaevent_SetNotifyFlags,
2930     Mediaevent_GetNotifyFlags
2931 };
2932
2933
2934 static HRESULT WINAPI MediaFilter_QueryInterface(IMediaFilter *iface, REFIID riid, LPVOID *ppv)
2935 {
2936     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
2937
2938     return Filtergraph_QueryInterface(This, riid, ppv);
2939 }
2940
2941 static ULONG WINAPI MediaFilter_AddRef(IMediaFilter *iface)
2942 {
2943     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
2944
2945     return Filtergraph_AddRef(This);
2946 }
2947
2948 static ULONG WINAPI MediaFilter_Release(IMediaFilter *iface)
2949 {
2950     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
2951
2952     return Filtergraph_Release(This);
2953 }
2954
2955 static HRESULT WINAPI MediaFilter_GetClassID(IMediaFilter *iface, CLSID * pClassID)
2956 {
2957     FIXME("(%p): stub\n", pClassID);
2958
2959     return E_NOTIMPL;
2960 }
2961
2962 static HRESULT WINAPI MediaFilter_Stop(IMediaFilter *iface)
2963 {
2964     FIXME("(): stub\n");
2965
2966     return E_NOTIMPL;
2967 }
2968
2969 static HRESULT WINAPI MediaFilter_Pause(IMediaFilter *iface)
2970 {
2971     FIXME("(): stub\n");
2972
2973     return E_NOTIMPL;
2974 }
2975
2976 static HRESULT WINAPI MediaFilter_Run(IMediaFilter *iface, REFERENCE_TIME tStart)
2977 {
2978     FIXME("(%lld): stub\n", tStart);
2979
2980     return E_NOTIMPL;
2981 }
2982
2983 static HRESULT WINAPI MediaFilter_GetState(IMediaFilter *iface, DWORD dwMsTimeout, FILTER_STATE * pState)
2984 {
2985     FIXME("(%ld, %p): stub\n", dwMsTimeout, pState);
2986
2987     return E_NOTIMPL;
2988 }
2989
2990 static HRESULT WINAPI MediaFilter_SetSyncSource(IMediaFilter *iface, IReferenceClock *pClock)
2991 {
2992     FIXME("(%p): stub\n", pClock);
2993
2994     return E_NOTIMPL;
2995 }
2996
2997 static HRESULT WINAPI MediaFilter_GetSyncSource(IMediaFilter *iface, IReferenceClock **ppClock)
2998 {
2999     FIXME("(%p): stub\n", ppClock);
3000
3001     return E_NOTIMPL;
3002 }
3003
3004 static IMediaFilterVtbl IMediaFilter_VTable =
3005 {
3006     MediaFilter_QueryInterface,
3007     MediaFilter_AddRef,
3008     MediaFilter_Release,
3009     MediaFilter_GetClassID,
3010     MediaFilter_Stop,
3011     MediaFilter_Pause,
3012     MediaFilter_Run,
3013     MediaFilter_GetState,
3014     MediaFilter_SetSyncSource,
3015     MediaFilter_GetSyncSource
3016 };
3017
3018 static HRESULT WINAPI MediaEventSink_QueryInterface(IMediaEventSink *iface, REFIID riid, LPVOID *ppv)
3019 {
3020     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventSink_vtbl, iface);
3021
3022     return Filtergraph_QueryInterface(This, riid, ppv);
3023 }
3024
3025 static ULONG WINAPI MediaEventSink_AddRef(IMediaEventSink *iface)
3026 {
3027     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventSink_vtbl, iface);
3028
3029     return Filtergraph_AddRef(This);
3030 }
3031
3032 static ULONG WINAPI MediaEventSink_Release(IMediaEventSink *iface)
3033 {
3034     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventSink_vtbl, iface);
3035
3036     return Filtergraph_Release(This);
3037 }
3038
3039 static HRESULT WINAPI MediaEventSink_Notify(IMediaEventSink *iface, long EventCode, LONG_PTR EventParam1, LONG_PTR EventParam2)
3040 {
3041     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventSink_vtbl, iface);
3042     Event evt;
3043
3044     TRACE("(%p/%p)->(%ld, %ld, %ld)\n", This, iface, EventCode, EventParam1, EventParam2);
3045
3046     /* We need thread safety here, let's use the events queue's one */
3047     EnterCriticalSection(&This->evqueue.msg_crst);
3048
3049     if ((EventCode == EC_COMPLETE) && This->HandleEcComplete)
3050     {
3051         TRACE("Process EC_COMPLETE notification\n");
3052         if (++This->EcCompleteCount == This->nRenderers)
3053         {
3054             evt.lEventCode = EC_COMPLETE;
3055             evt.lParam1 = S_OK;
3056             evt.lParam2 = 0;
3057             TRACE("Send EC_COMPLETE to app\n");
3058             EventsQueue_PutEvent(&This->evqueue, &evt);
3059             if (!This->notif.disabled && This->notif.hWnd)
3060             {
3061                 TRACE("Send Window message\n");
3062                 PostMessageW(This->notif.hWnd, This->notif.msg, 0, This->notif.instance);
3063             }
3064             This->CompletionStatus = EC_COMPLETE;
3065             SetEvent(This->hEventCompletion);
3066         }
3067     }
3068     else if ((EventCode == EC_REPAINT) && This->HandleEcRepaint)
3069     {
3070         /* FIXME: Not handled yet */
3071     }
3072     else
3073     {
3074         evt.lEventCode = EventCode;
3075         evt.lParam1 = EventParam1;
3076         evt.lParam2 = EventParam2;
3077         EventsQueue_PutEvent(&This->evqueue, &evt);
3078         if (!This->notif.disabled && This->notif.hWnd)
3079             PostMessageW(This->notif.hWnd, This->notif.msg, 0, This->notif.instance);
3080     }
3081
3082     LeaveCriticalSection(&This->evqueue.msg_crst);
3083     return S_OK;
3084 }
3085
3086 static IMediaEventSinkVtbl IMediaEventSink_VTable =
3087 {
3088     MediaEventSink_QueryInterface,
3089     MediaEventSink_AddRef,
3090     MediaEventSink_Release,
3091     MediaEventSink_Notify
3092 };
3093
3094 /* This is the only function that actually creates a FilterGraph class... */
3095 HRESULT FilterGraph_create(IUnknown *pUnkOuter, LPVOID *ppObj)
3096 {
3097     IFilterGraphImpl *fimpl;
3098     HRESULT hr;
3099
3100     TRACE("(%p,%p)\n", pUnkOuter, ppObj);
3101
3102     if( pUnkOuter )
3103         return CLASS_E_NOAGGREGATION;
3104
3105     fimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(*fimpl));
3106     fimpl->IGraphBuilder_vtbl = &IGraphBuilder_VTable;
3107     fimpl->IMediaControl_vtbl = &IMediaControl_VTable;
3108     fimpl->IMediaSeeking_vtbl = &IMediaSeeking_VTable;
3109     fimpl->IBasicAudio_vtbl = &IBasicAudio_VTable;
3110     fimpl->IBasicVideo_vtbl = &IBasicVideo_VTable;
3111     fimpl->IVideoWindow_vtbl = &IVideoWindow_VTable;
3112     fimpl->IMediaEventEx_vtbl = &IMediaEventEx_VTable;
3113     fimpl->IMediaFilter_vtbl = &IMediaFilter_VTable;
3114     fimpl->IMediaEventSink_vtbl = &IMediaEventSink_VTable;
3115     fimpl->ref = 1;
3116     fimpl->ppFiltersInGraph = NULL;
3117     fimpl->pFilterNames = NULL;
3118     fimpl->nFilters = 0;
3119     fimpl->filterCapacity = 0;
3120     fimpl->nameIndex = 1;
3121     fimpl->hEventCompletion = CreateEventW(0, TRUE, FALSE, 0);
3122     fimpl->HandleEcComplete = TRUE;
3123     fimpl->HandleEcRepaint = TRUE;
3124     fimpl->notif.hWnd = 0;
3125     fimpl->notif.disabled = FALSE;
3126     fimpl->nRenderers = 0;
3127     fimpl->EcCompleteCount = 0;
3128     fimpl->state = State_Stopped;
3129     EventsQueue_Init(&fimpl->evqueue);
3130     InitializeCriticalSection(&fimpl->cs);
3131
3132     hr = CoCreateInstance(&CLSID_FilterMapper, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&fimpl->pFilterMapper2);
3133     if (FAILED(hr)) {
3134         ERR("Unable to create filter mapper (%lx)\n", hr);
3135         return hr;
3136     }
3137
3138     *ppObj = fimpl;
3139     return S_OK;
3140 }
3141
3142 HRESULT FilterGraphNoThread_create(IUnknown *pUnkOuter, LPVOID *ppObj)
3143 {
3144     FIXME("CLSID_FilterGraphNoThread partially implemented - Forwarding to CLSID_FilterGraph\n");
3145     return FilterGraph_create(pUnkOuter, ppObj);
3146 }