ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

filtergraph.c
Go to the documentation of this file.
00001 /*              DirectShow FilterGraph object (QUARTZ.DLL)
00002  *
00003  * Copyright 2002 Lionel Ulmer
00004  * Copyright 2004 Christian Costa
00005  *
00006  * This file contains the (internal) driver registration functions,
00007  * driver enumeration APIs and DirectDraw creation functions.
00008  *
00009  * This library is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 2.1 of the License, or (at your option) any later version.
00013  *
00014  * This library is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00022  */
00023 
00024 #include "config.h"
00025 #include <stdarg.h>
00026 
00027 #define COBJMACROS
00028 
00029 #include "windef.h"
00030 #include "winbase.h"
00031 #include "winuser.h"
00032 #include "winreg.h"
00033 #include "shlwapi.h"
00034 #include "dshow.h"
00035 #include "wine/debug.h"
00036 #include "quartz_private.h"
00037 #include "ole2.h"
00038 #include "olectl.h"
00039 #include "strmif.h"
00040 #include "vfwmsgs.h"
00041 #include "evcode.h"
00042 #include "wine/unicode.h"
00043 
00044 
00045 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
00046 
00047 typedef struct {
00048     HWND     hWnd;      /* Target window */
00049     UINT     msg;       /* User window message */
00050     LONG_PTR instance;  /* User data */
00051     int      disabled;  /* Disabled messages posting */
00052 } WndNotify;
00053 
00054 typedef struct {
00055     LONG lEventCode;   /* Event code */
00056     LONG_PTR lParam1;  /* Param1 */
00057     LONG_PTR lParam2;  /* Param2 */
00058 } Event;
00059 
00060 /* messages ring implementation for queuing events (taken from winmm) */
00061 #define EVENTS_RING_BUFFER_INCREMENT      64
00062 typedef struct {
00063     Event* messages;
00064     int ring_buffer_size;
00065     int msg_tosave;
00066     int msg_toget;
00067     CRITICAL_SECTION msg_crst;
00068     HANDLE msg_event; /* Signaled for no empty queue */
00069 } EventsQueue;
00070 
00071 static int EventsQueue_Init(EventsQueue* omr)
00072 {
00073     omr->msg_toget = 0;
00074     omr->msg_tosave = 0;
00075     omr->msg_event = CreateEventW(NULL, TRUE, FALSE, NULL);
00076     omr->ring_buffer_size = EVENTS_RING_BUFFER_INCREMENT;
00077     omr->messages = CoTaskMemAlloc(omr->ring_buffer_size * sizeof(Event));
00078     ZeroMemory(omr->messages, omr->ring_buffer_size * sizeof(Event));
00079 
00080     InitializeCriticalSection(&omr->msg_crst);
00081     omr->msg_crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": EventsQueue.msg_crst");
00082     return TRUE;
00083 }
00084 
00085 static int EventsQueue_Destroy(EventsQueue* omr)
00086 {
00087     CloseHandle(omr->msg_event);
00088     CoTaskMemFree(omr->messages);
00089     omr->msg_crst.DebugInfo->Spare[0] = 0;
00090     DeleteCriticalSection(&omr->msg_crst);
00091     return TRUE;
00092 }
00093 
00094 static int EventsQueue_PutEvent(EventsQueue* omr, const Event* evt)
00095 {
00096     EnterCriticalSection(&omr->msg_crst);
00097     if ((omr->msg_toget == ((omr->msg_tosave + 1) % omr->ring_buffer_size)))
00098     {
00099     int old_ring_buffer_size = omr->ring_buffer_size;
00100     omr->ring_buffer_size += EVENTS_RING_BUFFER_INCREMENT;
00101     TRACE("omr->ring_buffer_size=%d\n",omr->ring_buffer_size);
00102     omr->messages = HeapReAlloc(GetProcessHeap(),0,omr->messages, omr->ring_buffer_size * sizeof(Event));
00103     /* Now we need to rearrange the ring buffer so that the new
00104        buffers just allocated are in between omr->msg_tosave and
00105        omr->msg_toget.
00106     */
00107     if (omr->msg_tosave < omr->msg_toget)
00108     {
00109         memmove(&(omr->messages[omr->msg_toget + EVENTS_RING_BUFFER_INCREMENT]),
00110             &(omr->messages[omr->msg_toget]),
00111             sizeof(Event)*(old_ring_buffer_size - omr->msg_toget)
00112             );
00113         omr->msg_toget += EVENTS_RING_BUFFER_INCREMENT;
00114     }
00115     }
00116     omr->messages[omr->msg_tosave] = *evt;
00117     SetEvent(omr->msg_event);
00118     omr->msg_tosave = (omr->msg_tosave + 1) % omr->ring_buffer_size;
00119     LeaveCriticalSection(&omr->msg_crst);
00120     return TRUE;
00121 }
00122 
00123 static int EventsQueue_GetEvent(EventsQueue* omr, Event* evt, LONG msTimeOut)
00124 {
00125     if (WaitForSingleObject(omr->msg_event, msTimeOut) != WAIT_OBJECT_0)
00126     return FALSE;
00127     
00128     EnterCriticalSection(&omr->msg_crst);
00129 
00130     if (omr->msg_toget == omr->msg_tosave) /* buffer empty ? */
00131     {
00132         LeaveCriticalSection(&omr->msg_crst);
00133     return FALSE;
00134     }
00135 
00136     *evt = omr->messages[omr->msg_toget];
00137     omr->msg_toget = (omr->msg_toget + 1) % omr->ring_buffer_size;
00138 
00139     /* Mark the buffer as empty if needed */
00140     if (omr->msg_toget == omr->msg_tosave) /* buffer empty ? */
00141     ResetEvent(omr->msg_event);
00142 
00143     LeaveCriticalSection(&omr->msg_crst);
00144     return TRUE;
00145 }
00146 
00147 #define MAX_ITF_CACHE_ENTRIES 3
00148 typedef struct _ITF_CACHE_ENTRY {
00149    const IID* riid;
00150    IBaseFilter* filter;
00151    IUnknown* iface;
00152 } ITF_CACHE_ENTRY;
00153 
00154 typedef struct _IFilterGraphImpl {
00155     const IFilterGraph2Vtbl *IFilterGraph2_vtbl;
00156     const IMediaControlVtbl *IMediaControl_vtbl;
00157     const IMediaSeekingVtbl *IMediaSeeking_vtbl;
00158     const IBasicAudioVtbl *IBasicAudio_vtbl;
00159     const IBasicVideo2Vtbl *IBasicVideo_vtbl;
00160     const IVideoWindowVtbl *IVideoWindow_vtbl;
00161     const IMediaEventExVtbl *IMediaEventEx_vtbl;
00162     const IMediaFilterVtbl *IMediaFilter_vtbl;
00163     const IMediaEventSinkVtbl *IMediaEventSink_vtbl;
00164     const IGraphConfigVtbl *IGraphConfig_vtbl;
00165     const IMediaPositionVtbl *IMediaPosition_vtbl;
00166     const IUnknownVtbl * IInner_vtbl;
00167     /* IAMGraphStreams */
00168     /* IAMStats */
00169     /* IFilterChain */
00170     /* IFilterMapper2 */
00171     /* IGraphVersion */
00172     /* IQueueCommand */
00173     /* IRegisterServiceProvider */
00174     /* IResourceMananger */
00175     /* IServiceProvider */
00176     /* IVideoFrameStep */
00177 
00178     LONG ref;
00179     IUnknown *punkFilterMapper2;
00180     IFilterMapper2 * pFilterMapper2;
00181     IBaseFilter ** ppFiltersInGraph;
00182     LPWSTR * pFilterNames;
00183     int nFilters;
00184     int filterCapacity;
00185     LONG nameIndex;
00186     IReferenceClock *refClock;
00187     EventsQueue evqueue;
00188     HANDLE hEventCompletion;
00189     int CompletionStatus;
00190     WndNotify notif;
00191     int nRenderers;
00192     int EcCompleteCount;
00193     int HandleEcComplete;
00194     int HandleEcRepaint;
00195     int HandleEcClockChanged;
00196     OAFilterState state;
00197     CRITICAL_SECTION cs;
00198     ITF_CACHE_ENTRY ItfCacheEntries[MAX_ITF_CACHE_ENTRIES];
00199     int nItfCacheEntries;
00200     IUnknown * pUnkOuter;
00201     BOOL bUnkOuterValid;
00202     BOOL bAggregatable;
00203     GUID timeformatseek;
00204     LONGLONG start_time;
00205     LONGLONG position;
00206     LONGLONG stop_position;
00207     LONG recursioncount;
00208 } IFilterGraphImpl;
00209 
00210 static HRESULT Filtergraph_QueryInterface(IFilterGraphImpl *This,
00211                                           REFIID riid, LPVOID * ppv);
00212 static ULONG Filtergraph_AddRef(IFilterGraphImpl *This);
00213 static ULONG Filtergraph_Release(IFilterGraphImpl *This);
00214 
00215 static HRESULT WINAPI FilterGraphInner_QueryInterface(IUnknown * iface,
00216                       REFIID riid,
00217                       LPVOID *ppvObj) {
00218     ICOM_THIS_MULTI(IFilterGraphImpl, IInner_vtbl, iface);
00219     TRACE("(%p)->(%s (%p), %p)\n", This, debugstr_guid(riid), riid, ppvObj);
00220     
00221     if (This->bAggregatable)
00222         This->bUnkOuterValid = TRUE;
00223 
00224     if (IsEqualGUID(&IID_IUnknown, riid)) {
00225         *ppvObj = &(This->IInner_vtbl);
00226         TRACE("   returning IUnknown interface (%p)\n", *ppvObj);
00227     } else if (IsEqualGUID(&IID_IFilterGraph, riid) ||
00228     IsEqualGUID(&IID_IFilterGraph2, riid) ||
00229     IsEqualGUID(&IID_IGraphBuilder, riid)) {
00230         *ppvObj = &(This->IFilterGraph2_vtbl);
00231         TRACE("   returning IGraphBuilder interface (%p)\n", *ppvObj);
00232     } else if (IsEqualGUID(&IID_IMediaControl, riid)) {
00233         *ppvObj = &(This->IMediaControl_vtbl);
00234         TRACE("   returning IMediaControl interface (%p)\n", *ppvObj);
00235     } else if (IsEqualGUID(&IID_IMediaSeeking, riid)) {
00236         *ppvObj = &(This->IMediaSeeking_vtbl);
00237         TRACE("   returning IMediaSeeking interface (%p)\n", *ppvObj);
00238     } else if (IsEqualGUID(&IID_IBasicAudio, riid)) {
00239         *ppvObj = &(This->IBasicAudio_vtbl);
00240         TRACE("   returning IBasicAudio interface (%p)\n", *ppvObj);
00241     } else if (IsEqualGUID(&IID_IBasicVideo, riid) ||
00242                IsEqualGUID(&IID_IBasicVideo2, riid)) {
00243         *ppvObj = &(This->IBasicVideo_vtbl);
00244         TRACE("   returning IBasicVideo2 interface (%p)\n", *ppvObj);
00245     } else if (IsEqualGUID(&IID_IVideoWindow, riid)) {
00246         *ppvObj = &(This->IVideoWindow_vtbl);
00247         TRACE("   returning IVideoWindow interface (%p)\n", *ppvObj);
00248     } else if (IsEqualGUID(&IID_IMediaEvent, riid) ||
00249        IsEqualGUID(&IID_IMediaEventEx, riid)) {
00250         *ppvObj = &(This->IMediaEventEx_vtbl);
00251         TRACE("   returning IMediaEvent(Ex) interface (%p)\n", *ppvObj);
00252     } else if (IsEqualGUID(&IID_IMediaFilter, riid) ||
00253           IsEqualGUID(&IID_IPersist, riid)) {
00254         *ppvObj = &(This->IMediaFilter_vtbl);
00255         TRACE("   returning IMediaFilter interface (%p)\n", *ppvObj);
00256     } else if (IsEqualGUID(&IID_IMediaEventSink, riid)) {
00257         *ppvObj = &(This->IMediaEventSink_vtbl);
00258         TRACE("   returning IMediaEventSink interface (%p)\n", *ppvObj);
00259     } else if (IsEqualGUID(&IID_IGraphConfig, riid)) {
00260         *ppvObj = &(This->IGraphConfig_vtbl);
00261         TRACE("   returning IGraphConfig interface (%p)\n", *ppvObj);
00262     } else if (IsEqualGUID(&IID_IMediaPosition, riid)) {
00263         *ppvObj = &(This->IMediaPosition_vtbl);
00264         TRACE("   returning IMediaPosition interface (%p)\n", *ppvObj);
00265     } else if (IsEqualGUID(&IID_IFilterMapper, riid)) {
00266         TRACE("   requesting IFilterMapper interface from aggregated filtermapper (%p)\n", *ppvObj);
00267         return IUnknown_QueryInterface(This->punkFilterMapper2, riid, ppvObj);
00268     } else if (IsEqualGUID(&IID_IFilterMapper2, riid)) {
00269         *ppvObj = This->pFilterMapper2;
00270         TRACE("   returning IFilterMapper2 interface from aggregated filtermapper (%p)\n", *ppvObj);
00271     } else {
00272         *ppvObj = NULL;
00273     FIXME("unknown interface %s\n", debugstr_guid(riid));
00274     return E_NOINTERFACE;
00275     }
00276 
00277     IUnknown_AddRef((IUnknown *)(*ppvObj));
00278     return S_OK;
00279 }
00280 
00281 static ULONG WINAPI FilterGraphInner_AddRef(IUnknown * iface) {
00282     ICOM_THIS_MULTI(IFilterGraphImpl, IInner_vtbl, iface);
00283     ULONG ref = InterlockedIncrement(&This->ref);
00284 
00285     TRACE("(%p)->(): new ref = %d\n", This, ref);
00286     
00287     return ref;
00288 }
00289 
00290 static ULONG WINAPI FilterGraphInner_Release(IUnknown * iface)
00291 {
00292     ICOM_THIS_MULTI(IFilterGraphImpl, IInner_vtbl, iface);
00293     ULONG ref = InterlockedDecrement(&This->ref);
00294 
00295     TRACE("(%p)->(): new ref = %d\n", This, ref);
00296 
00297     if (ref == 0) {
00298         int i;
00299 
00300         This->ref = 1; /* guard against reentrancy (aggregation). */
00301 
00302         IMediaControl_Stop((IMediaControl*)&(This->IMediaControl_vtbl));
00303 
00304         while (This->nFilters)
00305             IFilterGraph2_RemoveFilter((IFilterGraph2*)This, This->ppFiltersInGraph[0]);
00306 
00307         if (This->refClock)
00308             IReferenceClock_Release(This->refClock);
00309 
00310         for (i = 0; i < This->nItfCacheEntries; i++)
00311         {
00312             if (This->ItfCacheEntries[i].iface)
00313                 IUnknown_Release(This->ItfCacheEntries[i].iface);
00314         }
00315 
00316         /* AddRef on controlling IUnknown, to compensate for Release of cached IFilterMapper2 interface below.
00317 
00318          * NOTE: Filtergraph_AddRef isn't suitable, because bUnkOuterValid may be FALSE but punkOuter non-NULL
00319          * and already passed as punkOuter to filtermapper in FilterGraph_create - this will happen in case of
00320          * CoCreateInstance of filtergraph with non-null pUnkOuter and REFIID other than IID_Unknown that is
00321          * cleaning up after error. */
00322         if (This->pUnkOuter) IUnknown_AddRef(This->pUnkOuter);
00323         else IUnknown_AddRef((IUnknown*)&This->IInner_vtbl);
00324 
00325         IFilterMapper2_Release(This->pFilterMapper2);
00326         IUnknown_Release(This->punkFilterMapper2);
00327 
00328     CloseHandle(This->hEventCompletion);
00329     EventsQueue_Destroy(&This->evqueue);
00330         This->cs.DebugInfo->Spare[0] = 0;
00331     DeleteCriticalSection(&This->cs);
00332     CoTaskMemFree(This->ppFiltersInGraph);
00333     CoTaskMemFree(This->pFilterNames);
00334     CoTaskMemFree(This);
00335     }
00336     return ref;
00337 }
00338 
00339 
00340 /*** IUnknown methods ***/
00341 static HRESULT WINAPI FilterGraph2_QueryInterface(IFilterGraph2 *iface,
00342                           REFIID riid,
00343                           LPVOID*ppvObj) {
00344     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
00345     
00346     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
00347     return Filtergraph_QueryInterface(This, riid, ppvObj);
00348 }
00349 
00350 static ULONG WINAPI FilterGraph2_AddRef(IFilterGraph2 *iface) {
00351     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
00352     
00353     TRACE("(%p/%p)->() calling FilterGraph AddRef\n", This, iface);
00354     
00355     return Filtergraph_AddRef(This);
00356 }
00357 
00358 static ULONG WINAPI FilterGraph2_Release(IFilterGraph2 *iface) {
00359     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
00360     
00361     TRACE("(%p/%p)->() calling FilterGraph Release\n", This, iface);
00362 
00363     return Filtergraph_Release(This);
00364 }
00365 
00366 /*** IFilterGraph methods ***/
00367 static HRESULT WINAPI FilterGraph2_AddFilter(IFilterGraph2 *iface,
00368                          IBaseFilter *pFilter,
00369                          LPCWSTR pName) {
00370     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
00371     HRESULT hr;
00372     int i,j;
00373     WCHAR* wszFilterName = NULL;
00374     int duplicate_name = FALSE;
00375 
00376     TRACE("(%p/%p)->(%p, %s (%p))\n", This, iface, pFilter, debugstr_w(pName), pName);
00377 
00378     if (!pFilter)
00379         return E_POINTER;
00380 
00381     wszFilterName = CoTaskMemAlloc( (pName ? strlenW(pName) + 6 : 5) * sizeof(WCHAR) );
00382 
00383     if (pName)
00384     {
00385     /* Check if name already exists */
00386         for(i = 0; i < This->nFilters; i++)
00387         if (!strcmpW(This->pFilterNames[i], pName))
00388         {
00389         duplicate_name = TRUE;
00390         break;
00391         }
00392     }
00393 
00394     /* If no name given or name already existing, generate one */
00395     if (!pName || duplicate_name)
00396     {
00397     static const WCHAR wszFmt1[] = {'%','s',' ','%','0','4','d',0};
00398     static const WCHAR wszFmt2[] = {'%','0','4','d',0};
00399 
00400     for (j = 0; j < 10000 ; j++)
00401     {
00402         /* Create name */
00403         if (pName)
00404         sprintfW(wszFilterName, wszFmt1, pName, This->nameIndex);
00405         else
00406         sprintfW(wszFilterName, wszFmt2, This->nameIndex);
00407         TRACE("Generated name %s\n", debugstr_w(wszFilterName));
00408 
00409         /* Check if the generated name already exists */
00410         for(i = 0; i < This->nFilters; i++)
00411             if (!strcmpW(This->pFilterNames[i], wszFilterName))
00412             break;
00413 
00414         /* Compute next index and exit if generated name is suitable */
00415         if (This->nameIndex++ == 10000)
00416         This->nameIndex = 1;
00417         if (i == This->nFilters)
00418         break;
00419     }
00420     /* Unable to find a suitable name */
00421     if (j == 10000)
00422     {
00423         CoTaskMemFree(wszFilterName);
00424         return VFW_E_DUPLICATE_NAME;
00425     }
00426     }
00427     else
00428     memcpy(wszFilterName, pName, (strlenW(pName) + 1) * sizeof(WCHAR));
00429 
00430     if (This->nFilters + 1 > This->filterCapacity)
00431     {
00432         int newCapacity = This->filterCapacity ? 2 * This->filterCapacity : 1;
00433         IBaseFilter ** ppNewFilters = CoTaskMemAlloc(newCapacity * sizeof(IBaseFilter*));
00434         LPWSTR * pNewNames = CoTaskMemAlloc(newCapacity * sizeof(LPWSTR));
00435         memcpy(ppNewFilters, This->ppFiltersInGraph, This->nFilters * sizeof(IBaseFilter*));
00436         memcpy(pNewNames, This->pFilterNames, This->nFilters * sizeof(LPWSTR));
00437         if (This->filterCapacity)
00438         {
00439             CoTaskMemFree(This->ppFiltersInGraph);
00440             CoTaskMemFree(This->pFilterNames);
00441         }
00442         This->ppFiltersInGraph = ppNewFilters;
00443         This->pFilterNames = pNewNames;
00444         This->filterCapacity = newCapacity;
00445     }
00446 
00447     hr = IBaseFilter_JoinFilterGraph(pFilter, (IFilterGraph *)This, wszFilterName);
00448 
00449     if (SUCCEEDED(hr))
00450     {
00451         IBaseFilter_AddRef(pFilter);
00452         This->ppFiltersInGraph[This->nFilters] = pFilter;
00453         This->pFilterNames[This->nFilters] = wszFilterName;
00454         This->nFilters++;
00455         IBaseFilter_SetSyncSource(pFilter, This->refClock);
00456     }
00457     else
00458     CoTaskMemFree(wszFilterName);
00459 
00460     if (SUCCEEDED(hr) && duplicate_name)
00461     return VFW_S_DUPLICATE_NAME;
00462     
00463     return hr;
00464 }
00465 
00466 static HRESULT WINAPI FilterGraph2_RemoveFilter(IFilterGraph2 *iface, IBaseFilter *pFilter)
00467 {
00468     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
00469     int i;
00470     HRESULT hr = E_FAIL;
00471 
00472     TRACE("(%p/%p)->(%p)\n", This, iface, pFilter);
00473 
00474     /* FIXME: check graph is stopped */
00475 
00476     for (i = 0; i < This->nFilters; i++)
00477     {
00478         if (This->ppFiltersInGraph[i] == pFilter)
00479         {
00480             IEnumPins *penumpins = NULL;
00481             FILTER_STATE state;
00482 
00483             TRACE("Removing filter %s\n", debugstr_w(This->pFilterNames[i]));
00484             IBaseFilter_GetState(pFilter, 0, &state);
00485             if (state == State_Running)
00486                 IBaseFilter_Pause(pFilter);
00487             if (state != State_Stopped)
00488                 IBaseFilter_Stop(pFilter);
00489 
00490             hr = IBaseFilter_EnumPins(pFilter, &penumpins);
00491             if (SUCCEEDED(hr)) {
00492                 IPin *ppin;
00493                 while(IEnumPins_Next(penumpins, 1, &ppin, NULL) == S_OK)
00494                 {
00495                     IPin *victim = NULL;
00496                     HRESULT h;
00497                     IPin_ConnectedTo(ppin, &victim);
00498                     if (victim)
00499                     {
00500                         h = IPin_Disconnect(victim);
00501                         TRACE("Disconnect other side: %08x\n", h);
00502                         if (h == VFW_E_NOT_STOPPED)
00503                         {
00504                             PIN_INFO pinfo;
00505                             IPin_QueryPinInfo(victim, &pinfo);
00506 
00507                             IBaseFilter_GetState(pinfo.pFilter, 0, &state);
00508                             if (state == State_Running)
00509                                 IBaseFilter_Pause(pinfo.pFilter);
00510                             IBaseFilter_Stop(pinfo.pFilter);
00511                             IBaseFilter_Release(pinfo.pFilter);
00512                             h = IPin_Disconnect(victim);
00513                             TRACE("Disconnect retry: %08x\n", h);
00514                         }
00515                         IPin_Release(victim);
00516                     }
00517                     h = IPin_Disconnect(ppin);
00518                     TRACE("Disconnect 2: %08x\n", h);
00519 
00520                     IPin_Release(ppin);
00521                 }
00522                 IEnumPins_Release(penumpins);
00523             }
00524 
00525             hr = IBaseFilter_JoinFilterGraph(pFilter, NULL, This->pFilterNames[i]);
00526             if (SUCCEEDED(hr))
00527             {
00528                 IBaseFilter_SetSyncSource(pFilter, NULL);
00529                 IBaseFilter_Release(pFilter);
00530                 CoTaskMemFree(This->pFilterNames[i]);
00531                 memmove(This->ppFiltersInGraph+i, This->ppFiltersInGraph+i+1, sizeof(IBaseFilter*)*(This->nFilters - 1 - i));
00532                 memmove(This->pFilterNames+i, This->pFilterNames+i+1, sizeof(LPWSTR)*(This->nFilters - 1 - i));
00533                 This->nFilters--;
00534                 /* Invalidate interfaces in the cache */
00535                 for (i = 0; i < This->nItfCacheEntries; i++)
00536                     if (pFilter == This->ItfCacheEntries[i].filter)
00537                     {
00538                         IUnknown_Release(This->ItfCacheEntries[i].iface);
00539                         This->ItfCacheEntries[i].iface = NULL;
00540                         This->ItfCacheEntries[i].filter = NULL;
00541                     }
00542                 return S_OK;
00543             }
00544             break;
00545         }
00546     }
00547 
00548     return hr; /* FIXME: check this error code */
00549 }
00550 
00551 static HRESULT WINAPI FilterGraph2_EnumFilters(IFilterGraph2 *iface,
00552                           IEnumFilters **ppEnum) {
00553     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
00554 
00555     TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
00556 
00557     return IEnumFiltersImpl_Construct(This->ppFiltersInGraph, This->nFilters, ppEnum);
00558 }
00559 
00560 static HRESULT WINAPI FilterGraph2_FindFilterByName(IFilterGraph2 *iface,
00561                             LPCWSTR pName,
00562                             IBaseFilter **ppFilter) {
00563     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
00564     int i;
00565 
00566     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_w(pName), pName, ppFilter);
00567 
00568     if (!ppFilter)
00569         return E_POINTER;
00570 
00571     for (i = 0; i < This->nFilters; i++)
00572     {
00573         if (!strcmpW(pName, This->pFilterNames[i]))
00574         {
00575             *ppFilter = This->ppFiltersInGraph[i];
00576             IBaseFilter_AddRef(*ppFilter);
00577             return S_OK;
00578         }
00579     }
00580 
00581     *ppFilter = NULL;
00582     return VFW_E_NOT_FOUND;
00583 }
00584 
00585 /* Don't allow a circular connection to form, return VFW_E_CIRCULAR_GRAPH if this would be the case.
00586  * A circular connection will be formed if from the filter of the output pin, the input pin can be reached
00587  */
00588 static HRESULT CheckCircularConnection(IFilterGraphImpl *This, IPin *out, IPin *in)
00589 {
00590 #if 1
00591     HRESULT hr;
00592     PIN_INFO info_out, info_in;
00593 
00594     hr = IPin_QueryPinInfo(out, &info_out);
00595     if (FAILED(hr))
00596         return hr;
00597     if (info_out.dir != PINDIR_OUTPUT)
00598     {
00599         IBaseFilter_Release(info_out.pFilter);
00600         return E_UNEXPECTED;
00601     }
00602 
00603     hr = IPin_QueryPinInfo(in, &info_in);
00604     if (SUCCEEDED(hr))
00605         IBaseFilter_Release(info_in.pFilter);
00606     if (FAILED(hr))
00607         goto out;
00608     if (info_in.dir != PINDIR_INPUT)
00609     {
00610         hr = E_UNEXPECTED;
00611         goto out;
00612     }
00613 
00614     if (info_out.pFilter == info_in.pFilter)
00615         hr = VFW_E_CIRCULAR_GRAPH;
00616     else
00617     {
00618         IEnumPins *enumpins;
00619         IPin *test;
00620 
00621         hr = IBaseFilter_EnumPins(info_out.pFilter, &enumpins);
00622         if (FAILED(hr))
00623             goto out;
00624 
00625         IEnumPins_Reset(enumpins);
00626         while ((hr = IEnumPins_Next(enumpins, 1, &test, NULL)) == S_OK)
00627         {
00628             PIN_DIRECTION dir = PINDIR_OUTPUT;
00629             IPin_QueryDirection(test, &dir);
00630             if (dir == PINDIR_INPUT)
00631             {
00632                 IPin *victim = NULL;
00633                 IPin_ConnectedTo(test, &victim);
00634                 if (victim)
00635                 {
00636                     hr = CheckCircularConnection(This, victim, in);
00637                     IPin_Release(victim);
00638                     if (FAILED(hr))
00639                     {
00640                         IPin_Release(test);
00641                         break;
00642                     }
00643                 }
00644             }
00645             IPin_Release(test);
00646         }
00647         IEnumPins_Release(enumpins);
00648     }
00649 
00650 out:
00651     IBaseFilter_Release(info_out.pFilter);
00652     if (FAILED(hr))
00653         ERR("Checking filtergraph returned %08x, something's not right!\n", hr);
00654     return hr;
00655 #else
00656     /* Debugging filtergraphs not enabled */
00657     return S_OK;
00658 #endif
00659 }
00660 
00661 
00662 /* NOTE: despite the implication, it doesn't matter which
00663  * way round you put in the input and output pins */
00664 static HRESULT WINAPI FilterGraph2_ConnectDirect(IFilterGraph2 *iface,
00665                          IPin *ppinIn,
00666                          IPin *ppinOut,
00667                          const AM_MEDIA_TYPE *pmt) {
00668     PIN_DIRECTION dir;
00669     HRESULT hr;
00670 
00671     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
00672 
00673     TRACE("(%p/%p)->(%p, %p, %p)\n", This, iface, ppinIn, ppinOut, pmt);
00674 
00675     /* FIXME: check pins are in graph */
00676 
00677     if (TRACE_ON(quartz))
00678     {
00679         PIN_INFO PinInfo;
00680 
00681         hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
00682         if (FAILED(hr))
00683             return hr;
00684 
00685         TRACE("Filter owning first pin => %p\n", PinInfo.pFilter);
00686         IBaseFilter_Release(PinInfo.pFilter);
00687 
00688         hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
00689         if (FAILED(hr))
00690             return hr;
00691 
00692         TRACE("Filter owning second pin => %p\n", PinInfo.pFilter);
00693         IBaseFilter_Release(PinInfo.pFilter);
00694     }
00695 
00696     hr = IPin_QueryDirection(ppinIn, &dir);
00697     if (SUCCEEDED(hr))
00698     {
00699         if (dir == PINDIR_INPUT)
00700         {
00701             hr = CheckCircularConnection(This, ppinOut, ppinIn);
00702             if (SUCCEEDED(hr))
00703                 hr = IPin_Connect(ppinOut, ppinIn, pmt);
00704         }
00705         else
00706         {
00707             hr = CheckCircularConnection(This, ppinIn, ppinOut);
00708             if (SUCCEEDED(hr))
00709                 hr = IPin_Connect(ppinIn, ppinOut, pmt);
00710         }
00711     }
00712 
00713     return hr;
00714 }
00715 
00716 static HRESULT WINAPI FilterGraph2_Reconnect(IFilterGraph2 *iface,
00717                          IPin *ppin) {
00718     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
00719     IPin *pConnectedTo = NULL;
00720     HRESULT hr;
00721     PIN_DIRECTION pindir;
00722 
00723     IPin_QueryDirection(ppin, &pindir);
00724     hr = IPin_ConnectedTo(ppin, &pConnectedTo);
00725     if (FAILED(hr)) {
00726         TRACE("Querying connected to failed: %x\n", hr);
00727         return hr; 
00728     }
00729     IPin_Disconnect(ppin);
00730     IPin_Disconnect(pConnectedTo);
00731     if (pindir == PINDIR_INPUT)
00732         hr = IPin_Connect(pConnectedTo, ppin, NULL);
00733     else
00734         hr = IPin_Connect(ppin, pConnectedTo, NULL);
00735     IPin_Release(pConnectedTo);
00736     if (FAILED(hr))
00737         WARN("Reconnecting pins failed, pins are not connected now..\n");
00738     TRACE("(%p->%p) -- %p %p -> %x\n", iface, This, ppin, pConnectedTo, hr);
00739     return hr;
00740 }
00741 
00742 static HRESULT WINAPI FilterGraph2_Disconnect(IFilterGraph2 *iface, IPin *ppin)
00743 {
00744     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
00745 
00746     TRACE("(%p/%p)->(%p)\n", This, iface, ppin);
00747 
00748     if (!ppin)
00749        return E_POINTER;
00750 
00751     return IPin_Disconnect(ppin);
00752 }
00753 
00754 static HRESULT WINAPI FilterGraph2_SetDefaultSyncSource(IFilterGraph2 *iface) {
00755     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
00756     IReferenceClock *pClock = NULL;
00757     HRESULT hr;
00758 
00759     TRACE("(%p/%p)->() semi-stub\n", iface, This);
00760 
00761     hr = CoCreateInstance(&CLSID_SystemClock, NULL, CLSCTX_INPROC_SERVER, &IID_IReferenceClock, (LPVOID*)&pClock);
00762 
00763     if (SUCCEEDED(hr))
00764     {
00765         hr = IMediaFilter_SetSyncSource((IMediaFilter*)&(This->IMediaFilter_vtbl), pClock);
00766         IReferenceClock_Release(pClock);
00767     }
00768 
00769     return hr;
00770 }
00771 
00772 static HRESULT GetFilterInfo(IMoniker* pMoniker, GUID* pclsid, VARIANT* pvar)
00773 {
00774     static const WCHAR wszClsidName[] = {'C','L','S','I','D',0};
00775     static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
00776     IPropertyBag * pPropBagCat = NULL;
00777     HRESULT hr;
00778 
00779     VariantInit(pvar);
00780 
00781     hr = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (LPVOID*)&pPropBagCat);
00782 
00783     if (SUCCEEDED(hr))
00784         hr = IPropertyBag_Read(pPropBagCat, wszClsidName, pvar, NULL);
00785 
00786     if (SUCCEEDED(hr))
00787         hr = CLSIDFromString(V_UNION(pvar, bstrVal), pclsid);
00788 
00789     VariantClear(pvar);
00790 
00791     if (SUCCEEDED(hr))
00792         hr = IPropertyBag_Read(pPropBagCat, wszFriendlyName, pvar, NULL);
00793 
00794     if (SUCCEEDED(hr))
00795         TRACE("Moniker = %s - %s\n", debugstr_guid(pclsid), debugstr_w(V_UNION(pvar, bstrVal)));
00796 
00797     if (pPropBagCat)
00798         IPropertyBag_Release(pPropBagCat);
00799 
00800     return hr;
00801 }
00802 
00803 static HRESULT GetInternalConnections(IBaseFilter* pfilter, IPin* pinputpin, IPin*** pppins, ULONG* pnb)
00804 {
00805     HRESULT hr;
00806     ULONG nb = 0;
00807 
00808     TRACE("(%p, %p, %p, %p)\n", pfilter, pinputpin, pppins, pnb);
00809     hr = IPin_QueryInternalConnections(pinputpin, NULL, &nb);
00810     if (hr == S_OK) {
00811         /* Rendered input */
00812     } else if (hr == S_FALSE) {
00813         *pppins = CoTaskMemAlloc(sizeof(IPin*)*nb);
00814         hr = IPin_QueryInternalConnections(pinputpin, *pppins, &nb);
00815         if (hr != S_OK) {
00816             WARN("Error (%x)\n", hr);
00817         }
00818     } else if (hr == E_NOTIMPL) {
00819         /* Input connected to all outputs */
00820         IEnumPins* penumpins;
00821         IPin* ppin;
00822         int i = 0;
00823         TRACE("E_NOTIMPL\n");
00824         hr = IBaseFilter_EnumPins(pfilter, &penumpins);
00825         if (FAILED(hr)) {
00826             WARN("filter Enumpins failed (%x)\n", hr);
00827             return hr;
00828         }
00829         i = 0;
00830         /* Count output pins */
00831         while(IEnumPins_Next(penumpins, 1, &ppin, &nb) == S_OK) {
00832             PIN_DIRECTION pindir;
00833             IPin_QueryDirection(ppin, &pindir);
00834             if (pindir == PINDIR_OUTPUT)
00835                 i++;
00836             IPin_Release(ppin);
00837         }
00838         *pppins = CoTaskMemAlloc(sizeof(IPin*)*i);
00839         /* Retrieve output pins */
00840         IEnumPins_Reset(penumpins);
00841         i = 0;
00842         while(IEnumPins_Next(penumpins, 1, &ppin, &nb) == S_OK) {
00843             PIN_DIRECTION pindir;
00844             IPin_QueryDirection(ppin, &pindir);
00845             if (pindir == PINDIR_OUTPUT)
00846                 (*pppins)[i++] = ppin;
00847             else
00848                 IPin_Release(ppin);
00849         }
00850         IEnumPins_Release(penumpins);
00851         nb = i;
00852         if (FAILED(hr)) {
00853             WARN("Next failed (%x)\n", hr);
00854             return hr;
00855         }
00856     } else if (FAILED(hr)) {
00857         WARN("Cannot get internal connection (%x)\n", hr);
00858         return hr;
00859     }
00860 
00861     *pnb = nb;
00862     return S_OK;
00863 }
00864 
00865 /*** IGraphBuilder methods ***/
00866 static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface, IPin *ppinOut, IPin *ppinIn)
00867 {
00868     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
00869     HRESULT hr;
00870     AM_MEDIA_TYPE* mt = NULL;
00871     IEnumMediaTypes* penummt = NULL;
00872     ULONG nbmt;
00873     IEnumPins* penumpins;
00874     IEnumMoniker* pEnumMoniker;
00875     GUID tab[2];
00876     ULONG nb;
00877     IMoniker* pMoniker;
00878     ULONG pin;
00879     PIN_INFO PinInfo;
00880     CLSID FilterCLSID;
00881     PIN_DIRECTION dir;
00882 
00883     TRACE("(%p/%p)->(%p, %p)\n", This, iface, ppinOut, ppinIn);
00884 
00885     if (TRACE_ON(quartz))
00886     {
00887         hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
00888         if (FAILED(hr))
00889             return hr;
00890 
00891         TRACE("Filter owning first pin => %p\n", PinInfo.pFilter);
00892         IBaseFilter_Release(PinInfo.pFilter);
00893 
00894         hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
00895         if (FAILED(hr))
00896             return hr;
00897 
00898         TRACE("Filter owning second pin => %p\n", PinInfo.pFilter);
00899         IBaseFilter_Release(PinInfo.pFilter);
00900     }
00901 
00902     EnterCriticalSection(&This->cs);
00903     ++This->recursioncount;
00904     if (This->recursioncount >= 5)
00905     {
00906         WARN("Recursion count has reached %d\n", This->recursioncount);
00907         hr = VFW_E_CANNOT_CONNECT;
00908         goto out;
00909     }
00910 
00911     hr = IPin_QueryDirection(ppinOut, &dir);
00912     if (FAILED(hr))
00913         goto out;
00914 
00915     if (dir == PINDIR_INPUT)
00916     {
00917         IPin *temp;
00918 
00919         temp = ppinIn;
00920         ppinIn = ppinOut;
00921         ppinOut = temp;
00922     }
00923 
00924     hr = CheckCircularConnection(This, ppinOut, ppinIn);
00925     if (FAILED(hr))
00926         goto out;
00927 
00928     /* Try direct connection first */
00929     hr = IPin_Connect(ppinOut, ppinIn, NULL);
00930     if (SUCCEEDED(hr))
00931         goto out;
00932 
00933     TRACE("Direct connection failed, trying to render using extra filters\n");
00934 
00935     hr = IPin_QueryPinInfo(ppinIn, &PinInfo);
00936     if (FAILED(hr))
00937         goto out;
00938 
00939     hr = IBaseFilter_GetClassID(PinInfo.pFilter, &FilterCLSID);
00940     IBaseFilter_Release(PinInfo.pFilter);
00941     if (FAILED(hr))
00942         goto out;
00943 
00944     /* Find the appropriate transform filter than can transform the minor media type of output pin of the upstream 
00945      * filter to the minor mediatype of input pin of the renderer */
00946     hr = IPin_EnumMediaTypes(ppinOut, &penummt);
00947     if (FAILED(hr))
00948     {
00949         WARN("EnumMediaTypes (%x)\n", hr);
00950         goto out;
00951     }
00952 
00953     hr = IEnumMediaTypes_Next(penummt, 1, &mt, &nbmt);
00954     if (FAILED(hr)) {
00955         WARN("IEnumMediaTypes_Next (%x)\n", hr);
00956         goto out;
00957     }
00958 
00959     if (!nbmt)
00960     {
00961         WARN("No media type found!\n");
00962         hr = VFW_E_INVALIDMEDIATYPE;
00963         goto out;
00964     }
00965     TRACE("MajorType %s\n", debugstr_guid(&mt->majortype));
00966     TRACE("SubType %s\n", debugstr_guid(&mt->subtype));
00967 
00968     /* Try to find a suitable filter that can connect to the pin to render */
00969     tab[0] = mt->majortype;
00970     tab[1] = mt->subtype;
00971     hr = IFilterMapper2_EnumMatchingFilters(This->pFilterMapper2, &pEnumMoniker, 0, FALSE, MERIT_UNLIKELY, TRUE, 1, tab, NULL, NULL, FALSE, FALSE, 0, NULL, NULL, NULL);
00972     if (FAILED(hr)) {
00973         WARN("Unable to enum filters (%x)\n", hr);
00974         goto out;
00975     }
00976 
00977     hr = VFW_E_CANNOT_RENDER;
00978     while(IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK)
00979     {
00980         VARIANT var;
00981         GUID clsid;
00982         IPin** ppins;
00983         IPin* ppinfilter = NULL;
00984         IBaseFilter* pfilter = NULL;
00985 
00986         hr = GetFilterInfo(pMoniker, &clsid, &var);
00987         IMoniker_Release(pMoniker);
00988         if (FAILED(hr)) {
00989             WARN("Unable to retrieve filter info (%x)\n", hr);
00990             goto error;
00991         }
00992 
00993         if (IsEqualGUID(&clsid, &FilterCLSID)) {
00994             /* Skip filter (same as the one the output pin belongs to) */
00995             goto error;
00996         }
00997 
00998         hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&pfilter);
00999         if (FAILED(hr)) {
01000             WARN("Unable to create filter (%x), trying next one\n", hr);
01001             goto error;
01002         }
01003 
01004         hr = IFilterGraph2_AddFilter(iface, pfilter, V_UNION(&var, bstrVal));
01005         if (FAILED(hr)) {
01006             WARN("Unable to add filter (%x)\n", hr);
01007             IBaseFilter_Release(pfilter);
01008             pfilter = NULL;
01009             goto error;
01010         }
01011 
01012         VariantClear(&var);
01013 
01014         hr = IBaseFilter_EnumPins(pfilter, &penumpins);
01015         if (FAILED(hr)) {
01016             WARN("Enumpins (%x)\n", hr);
01017             goto error;
01018         }
01019 
01020         hr = IEnumPins_Next(penumpins, 1, &ppinfilter, &pin);
01021         IEnumPins_Release(penumpins);
01022 
01023         if (FAILED(hr)) {
01024             WARN("Obtaining next pin: (%x)\n", hr);
01025             goto error;
01026         }
01027         if (pin == 0) {
01028             WARN("Cannot use this filter: no pins\n");
01029             goto error;
01030         }
01031 
01032         hr = IPin_Connect(ppinOut, ppinfilter, NULL);
01033         if (FAILED(hr)) {
01034             TRACE("Cannot connect to filter (%x), trying next one\n", hr);
01035             goto error;
01036         }
01037         TRACE("Successfully connected to filter, follow chain...\n");
01038 
01039         /* Render all output pins of the filter by calling IFilterGraph2_Connect on each of them */
01040         hr = GetInternalConnections(pfilter, ppinfilter, &ppins, &nb);
01041 
01042         if (SUCCEEDED(hr)) {
01043             unsigned int i;
01044             if (nb == 0) {
01045                 IPin_Disconnect(ppinfilter);
01046                 IPin_Disconnect(ppinOut);
01047                 goto error;
01048             }
01049             TRACE("pins to consider: %d\n", nb);
01050             for(i = 0; i < nb; i++)
01051             {
01052                 LPWSTR pinname = NULL;
01053 
01054                 TRACE("Processing pin %u\n", i);
01055 
01056                 hr = IPin_QueryId(ppins[i], &pinname);
01057                 if (SUCCEEDED(hr))
01058                 {
01059                     if (pinname[0] == '~')
01060                     {
01061                         TRACE("Pinname=%s, skipping\n", debugstr_w(pinname));
01062                         hr = E_FAIL;
01063                     }
01064                     else
01065                         hr = IFilterGraph2_Connect(iface, ppins[i], ppinIn);
01066                     CoTaskMemFree(pinname);
01067                 }
01068 
01069                 if (FAILED(hr)) {
01070                    TRACE("Cannot connect pin %p (%x)\n", ppinfilter, hr);
01071                 }
01072                 IPin_Release(ppins[i]);
01073                 if (SUCCEEDED(hr)) break;
01074             }
01075             while (++i < nb) IPin_Release(ppins[i]);
01076             CoTaskMemFree(ppins);
01077             IPin_Release(ppinfilter);
01078             IBaseFilter_Release(pfilter);
01079             if (FAILED(hr))
01080             {
01081                 IPin_Disconnect(ppinfilter);
01082                 IPin_Disconnect(ppinOut);
01083                 IFilterGraph2_RemoveFilter(iface, pfilter);
01084                 continue;
01085             }
01086             break;
01087         }
01088 
01089 error:
01090         VariantClear(&var);
01091         if (ppinfilter) IPin_Release(ppinfilter);
01092         if (pfilter) {
01093             IFilterGraph2_RemoveFilter(iface, pfilter);
01094             IBaseFilter_Release(pfilter);
01095         }
01096     }
01097 
01098 out:
01099     if (penummt)
01100         IEnumMediaTypes_Release(penummt);
01101     if (mt)
01102         DeleteMediaType(mt);
01103     --This->recursioncount;
01104     LeaveCriticalSection(&This->cs);
01105     TRACE("--> %08x\n", hr);
01106     return SUCCEEDED(hr) ? S_OK : hr;
01107 }
01108 
01109 static HRESULT FilterGraph2_RenderRecurse(IFilterGraphImpl *This, IPin *ppinOut)
01110 {
01111     /* This pin has been connected now, try to call render on all pins that aren't connected */
01112     IPin *to = NULL;
01113     PIN_INFO info;
01114     IEnumPins *enumpins = NULL;
01115     BOOL renderany = FALSE;
01116     BOOL renderall = TRUE;
01117 
01118     IPin_QueryPinInfo(ppinOut, &info);
01119 
01120     IBaseFilter_EnumPins(info.pFilter, &enumpins);
01121     /* Don't need to hold a reference, IEnumPins does */
01122     IBaseFilter_Release(info.pFilter);
01123 
01124     IEnumPins_Reset(enumpins);
01125     while (IEnumPins_Next(enumpins, 1, &to, NULL) == S_OK)
01126     {
01127         PIN_DIRECTION dir = PINDIR_INPUT;
01128 
01129         IPin_QueryDirection(to, &dir);
01130 
01131         if (dir == PINDIR_OUTPUT)
01132         {
01133             IPin *out = NULL;
01134 
01135             IPin_ConnectedTo(to, &out);
01136             if (!out)
01137             {
01138                 HRESULT hr;
01139                 hr = IFilterGraph2_Render((IFilterGraph2 *)&This->IFilterGraph2_vtbl, to);
01140                 if (SUCCEEDED(hr))
01141                     renderany = TRUE;
01142                 else
01143                     renderall = FALSE;
01144             }
01145             else
01146                 IPin_Release(out);
01147         }
01148 
01149         IPin_Release(to);
01150     }
01151 
01152     IEnumPins_Release(enumpins);
01153 
01154     if (renderall)
01155         return S_OK;
01156 
01157     if (renderany)
01158         return VFW_S_PARTIAL_RENDER;
01159 
01160     return VFW_E_CANNOT_RENDER;
01161 }
01162 
01163 /* Ogg hates me if I create a direct rendering method
01164  *
01165  * It can only connect to a pin properly once, so use a recursive method that does
01166  *
01167  *  +----+ --- (PIN 1) (Render is called on this pin)
01168  *  |    |
01169  *  +----+ --- (PIN 2)
01170  *
01171  *  Enumerate possible renderers that EXACTLY match the requested type
01172  *
01173  *  If none is available, try to add intermediate filters that can connect to the input pin
01174  *  then call Render on that intermediate pin's output pins
01175  *  if it succeeds: Render returns success, if it doesn't, the intermediate filter is removed,
01176  *  and another filter that can connect to the input pin is tried
01177  *  if we run out of filters that can, give up and return VFW_E_CANNOT_RENDER
01178  *  It's recursive, but fun!
01179  */
01180 
01181 static HRESULT WINAPI FilterGraph2_Render(IFilterGraph2 *iface, IPin *ppinOut)
01182 {
01183     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
01184     IEnumMediaTypes* penummt;
01185     AM_MEDIA_TYPE* mt;
01186     ULONG nbmt;
01187     HRESULT hr;
01188 
01189     IEnumMoniker* pEnumMoniker;
01190     GUID tab[4];
01191     ULONG nb;
01192     IMoniker* pMoniker;
01193     INT x;
01194 
01195     TRACE("(%p/%p)->(%p)\n", This, iface, ppinOut);
01196 
01197     if (TRACE_ON(quartz))
01198     {
01199         PIN_INFO PinInfo;
01200 
01201         hr = IPin_QueryPinInfo(ppinOut, &PinInfo);
01202         if (FAILED(hr))
01203             return hr;
01204 
01205         TRACE("Filter owning pin => %p\n", PinInfo.pFilter);
01206         IBaseFilter_Release(PinInfo.pFilter);
01207     }
01208 
01209     /* Try to find out if there is a renderer for the specified subtype already, and use that
01210      */
01211     EnterCriticalSection(&This->cs);
01212     for (x = 0; x < This->nFilters; ++x)
01213     {
01214         IEnumPins *enumpins = NULL;
01215         IPin *pin = NULL;
01216 
01217         hr = IBaseFilter_EnumPins(This->ppFiltersInGraph[x], &enumpins);
01218 
01219         if (FAILED(hr) || !enumpins)
01220             continue;
01221 
01222         IEnumPins_Reset(enumpins);
01223         while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK)
01224         {
01225             IPin *to = NULL;
01226             PIN_DIRECTION dir = PINDIR_OUTPUT;
01227 
01228             IPin_QueryDirection(pin, &dir);
01229             if (dir != PINDIR_INPUT)
01230             {
01231                 IPin_Release(pin);
01232                 continue;
01233             }
01234             IPin_ConnectedTo(pin, &to);
01235 
01236             if (to == NULL)
01237             {
01238                 hr = IPin_Connect(ppinOut, pin, NULL);
01239                 if (SUCCEEDED(hr))
01240                 {
01241                     TRACE("Connected successfully %p/%p, %08x look if we should render more!\n", ppinOut, pin, hr);
01242                     IPin_Release(pin);
01243 
01244                     hr = FilterGraph2_RenderRecurse(This, pin);
01245                     if (FAILED(hr))
01246                     {
01247                         IPin_Disconnect(ppinOut);
01248                         IPin_Disconnect(pin);
01249                         continue;
01250                     }
01251                     IEnumPins_Release(enumpins);
01252                     LeaveCriticalSection(&This->cs);
01253                     return hr;
01254                 }
01255                 WARN("Could not connect!\n");
01256             }
01257             else
01258                 IPin_Release(to);
01259 
01260             IPin_Release(pin);
01261         }
01262         IEnumPins_Release(enumpins);
01263     }
01264 
01265     LeaveCriticalSection(&This->cs);
01266 
01267     hr = IPin_EnumMediaTypes(ppinOut, &penummt);
01268     if (FAILED(hr)) {
01269         WARN("EnumMediaTypes (%x)\n", hr);
01270         return hr;
01271     }
01272 
01273     IEnumMediaTypes_Reset(penummt);
01274 
01275     /* Looks like no existing renderer of the kind exists
01276      * Try adding new ones
01277      */
01278     tab[0] = tab[1] = GUID_NULL;
01279     while (SUCCEEDED(hr))
01280     {
01281         hr = IEnumMediaTypes_Next(penummt, 1, &mt, &nbmt);
01282         if (FAILED(hr)) {
01283             WARN("IEnumMediaTypes_Next (%x)\n", hr);
01284             break;
01285         }
01286         if (!nbmt)
01287         {
01288             hr = VFW_E_CANNOT_RENDER;
01289             break;
01290         }
01291         else
01292         {
01293             TRACE("MajorType %s\n", debugstr_guid(&mt->majortype));
01294             TRACE("SubType %s\n", debugstr_guid(&mt->subtype));
01295 
01296             /* Only enumerate once, this doesn't account for all previous ones, but this should be enough nonetheless */
01297             if (IsEqualIID(&tab[0], &mt->majortype) && IsEqualIID(&tab[1], &mt->subtype))
01298             {
01299                 DeleteMediaType(mt);
01300                 continue;
01301             }
01302 
01303             /* Try to find a suitable renderer with the same media type */
01304             tab[0] = mt->majortype;
01305             tab[1] = mt->subtype;
01306             hr = IFilterMapper2_EnumMatchingFilters(This->pFilterMapper2, &pEnumMoniker, 0, FALSE, MERIT_UNLIKELY, TRUE, 1, tab, NULL, NULL, FALSE, FALSE, 0, NULL, NULL, NULL);
01307             if (FAILED(hr))
01308             {
01309                 WARN("Unable to enum filters (%x)\n", hr);
01310                 break;
01311             }
01312         }
01313         hr = E_FAIL;
01314 
01315         while (IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK)
01316         {
01317             VARIANT var;
01318             GUID clsid;
01319             IPin* ppinfilter;
01320             IBaseFilter* pfilter = NULL;
01321             IEnumPins* penumpins = NULL;
01322             ULONG pin;
01323 
01324             hr = GetFilterInfo(pMoniker, &clsid, &var);
01325             IMoniker_Release(pMoniker);
01326             if (FAILED(hr)) {
01327                 WARN("Unable to retrieve filter info (%x)\n", hr);
01328                 goto error;
01329             }
01330 
01331             hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&pfilter);
01332             if (FAILED(hr))
01333             {
01334                 WARN("Unable to create filter (%x), trying next one\n", hr);
01335                 goto error;
01336             }
01337 
01338             hr = IFilterGraph2_AddFilter(iface, pfilter, V_UNION(&var, bstrVal));
01339             if (FAILED(hr)) {
01340                 WARN("Unable to add filter (%x)\n", hr);
01341                 IBaseFilter_Release(pfilter);
01342                 pfilter = NULL;
01343                 goto error;
01344             }
01345 
01346             hr = IBaseFilter_EnumPins(pfilter, &penumpins);
01347             if (FAILED(hr)) {
01348                 WARN("Splitter Enumpins (%x)\n", hr);
01349                 goto error;
01350             }
01351 
01352             while ((hr = IEnumPins_Next(penumpins, 1, &ppinfilter, &pin)) == S_OK)
01353             {
01354                 PIN_DIRECTION dir;
01355 
01356                 if (pin == 0) {
01357                     WARN("No Pin\n");
01358                     hr = E_FAIL;
01359                     goto error;
01360                 }
01361 
01362                 hr = IPin_QueryDirection(ppinfilter, &dir);
01363                 if (FAILED(hr)) {
01364                     IPin_Release(ppinfilter);
01365                     WARN("QueryDirection failed (%x)\n", hr);
01366                     goto error;
01367                 }
01368                 if (dir != PINDIR_INPUT) {
01369                     IPin_Release(ppinfilter);
01370                     continue; /* Wrong direction */
01371                 }
01372 
01373                 /* Connect the pin to the "Renderer" */
01374                 hr = IPin_Connect(ppinOut, ppinfilter, NULL);
01375                 IPin_Release(ppinfilter);
01376 
01377                 if (FAILED(hr)) {
01378                     WARN("Unable to connect %s to renderer (%x)\n", debugstr_w(V_UNION(&var, bstrVal)), hr);
01379                     goto error;
01380                 }
01381                 TRACE("Connected, recursing %s\n",  debugstr_w(V_UNION(&var, bstrVal)));
01382 
01383                 VariantClear(&var);
01384 
01385                 hr = FilterGraph2_RenderRecurse(This, ppinfilter);
01386                 if (FAILED(hr)) {
01387                     WARN("Unable to connect recursively (%x)\n", hr);
01388                     goto error;
01389                 }
01390                 IBaseFilter_Release(pfilter);
01391                 break;
01392             }
01393             if (SUCCEEDED(hr)) {
01394                 IEnumPins_Release(penumpins);
01395                 break; /* out of IEnumMoniker_Next loop */
01396             }
01397 
01398             /* IEnumPins_Next failed, all other failure case caught by goto error */
01399             WARN("IEnumPins_Next (%x)\n", hr);
01400             /* goto error */
01401 
01402 error:
01403             VariantClear(&var);
01404             if (penumpins)
01405                 IEnumPins_Release(penumpins);
01406             if (pfilter) {
01407                 IFilterGraph2_RemoveFilter(iface, pfilter);
01408                 IBaseFilter_Release(pfilter);
01409             }
01410             if (SUCCEEDED(hr)) DebugBreak();
01411         }
01412 
01413         IEnumMoniker_Release(pEnumMoniker);
01414         if (nbmt)
01415             DeleteMediaType(mt);
01416         if (SUCCEEDED(hr))
01417             break;
01418         hr = S_OK;
01419     }
01420 
01421     IEnumMediaTypes_Release(penummt);
01422     return hr;
01423 }
01424 
01425 static HRESULT WINAPI FilterGraph2_RenderFile(IFilterGraph2 *iface,
01426                                               LPCWSTR lpcwstrFile,
01427                                               LPCWSTR lpcwstrPlayList)
01428 {
01429     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
01430     static const WCHAR string[] = {'R','e','a','d','e','r',0};
01431     IBaseFilter* preader = NULL;
01432     IPin* ppinreader = NULL;
01433     IEnumPins* penumpins = NULL;
01434     HRESULT hr;
01435     BOOL partial = FALSE;
01436     HRESULT any = FALSE;
01437 
01438     TRACE("(%p/%p)->(%s, %s)\n", This, iface, debugstr_w(lpcwstrFile), debugstr_w(lpcwstrPlayList));
01439 
01440     if (lpcwstrPlayList != NULL)
01441         return E_INVALIDARG;
01442 
01443     hr = IFilterGraph2_AddSourceFilter(iface, lpcwstrFile, string, &preader);
01444     if (FAILED(hr))
01445         return hr;
01446 
01447     if (SUCCEEDED(hr))
01448         hr = IBaseFilter_EnumPins(preader, &penumpins);
01449     if (SUCCEEDED(hr))
01450     {
01451         while (IEnumPins_Next(penumpins, 1, &ppinreader, NULL) == S_OK)
01452         {
01453             PIN_DIRECTION dir;
01454 
01455             IPin_QueryDirection(ppinreader, &dir);
01456             if (dir == PINDIR_OUTPUT)
01457             {
01458                 INT i;
01459 
01460                 hr = IFilterGraph2_Render(iface, ppinreader);
01461                 TRACE("Render %08x\n", hr);
01462 
01463                 for (i = 0; i < This->nFilters; ++i)
01464                     TRACE("Filters in chain: %s\n", debugstr_w(This->pFilterNames[i]));
01465 
01466                 if (SUCCEEDED(hr))
01467                     any = TRUE;
01468                 if (hr != S_OK)
01469                     partial = TRUE;
01470             }
01471             IPin_Release(ppinreader);
01472         }
01473         IEnumPins_Release(penumpins);
01474 
01475         if (!any)
01476             hr = VFW_E_CANNOT_RENDER;
01477         else if (partial)
01478             hr = VFW_S_PARTIAL_RENDER;
01479         else
01480             hr = S_OK;
01481     }
01482     IBaseFilter_Release(preader);
01483 
01484     TRACE("--> %08x\n", hr);
01485     return hr;
01486 }
01487 
01488 /* Some filters implement their own asynchronous reader (Theoretically they all should, try to load it first */
01489 static HRESULT GetFileSourceFilter(LPCOLESTR pszFileName, IBaseFilter **filter)
01490 {
01491     static const WCHAR wszReg[] = {'M','e','d','i','a',' ','T','y','p','e','\\','E','x','t','e','n','s','i','o','n','s',0};
01492     HRESULT hr = S_OK;
01493     HKEY extkey;
01494     LONG lRet;
01495 
01496     lRet = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszReg, 0, KEY_READ, &extkey);
01497     hr = HRESULT_FROM_WIN32(lRet);
01498 
01499     if (SUCCEEDED(hr))
01500     {
01501         static const WCHAR filtersource[] = {'S','o','u','r','c','e',' ','F','i','l','t','e','r',0};
01502         WCHAR *ext = PathFindExtensionW(pszFileName);
01503         WCHAR clsid_key[39];
01504         GUID clsid;
01505         DWORD size = sizeof(clsid_key);
01506         HKEY pathkey;
01507 
01508         if (!ext)
01509         {
01510             CloseHandle(extkey);
01511             return E_FAIL;
01512         }
01513 
01514         lRet = RegOpenKeyExW(extkey, ext, 0, KEY_READ, &pathkey);
01515         hr = HRESULT_FROM_WIN32(lRet);
01516         CloseHandle(extkey);
01517         if (FAILED(hr))
01518             return hr;
01519 
01520         lRet = RegQueryValueExW(pathkey, filtersource, NULL, NULL, (LPBYTE)clsid_key, &size);
01521         hr = HRESULT_FROM_WIN32(lRet);
01522         CloseHandle(pathkey);
01523         if (FAILED(hr))
01524             return hr;
01525 
01526         CLSIDFromString(clsid_key, &clsid);
01527 
01528         TRACE("CLSID: %s\n", debugstr_guid(&clsid));
01529         hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)filter);
01530         if (SUCCEEDED(hr))
01531         {
01532             IFileSourceFilter *source = NULL;
01533             hr = IBaseFilter_QueryInterface(*filter, &IID_IFileSourceFilter, (LPVOID*)&source);
01534             if (SUCCEEDED(hr))
01535                 IFileSourceFilter_Release(source);
01536             else
01537                 IBaseFilter_Release(*filter);
01538         }
01539     }
01540     if (FAILED(hr))
01541         *filter = NULL;
01542     return hr;
01543 }
01544 
01545 static HRESULT WINAPI FilterGraph2_AddSourceFilter(IFilterGraph2 *iface,
01546                            LPCWSTR lpcwstrFileName,
01547                            LPCWSTR lpcwstrFilterName,
01548                            IBaseFilter **ppFilter) {
01549     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
01550     HRESULT hr;
01551     IBaseFilter* preader;
01552     IFileSourceFilter* pfile = NULL;
01553     AM_MEDIA_TYPE mt;
01554     WCHAR* filename;
01555 
01556     TRACE("(%p/%p)->(%s, %s, %p)\n", This, iface, debugstr_w(lpcwstrFileName), debugstr_w(lpcwstrFilterName), ppFilter);
01557 
01558     /* Try from file name first, then fall back to default asynchronous reader */
01559     hr = GetFileSourceFilter(lpcwstrFileName, &preader);
01560 
01561     if (FAILED(hr))
01562         hr = CoCreateInstance(&CLSID_AsyncReader, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&preader);
01563     if (FAILED(hr)) {
01564         WARN("Unable to create file source filter (%x)\n", hr);
01565         return hr;
01566     }
01567 
01568     hr = IFilterGraph2_AddFilter(iface, preader, lpcwstrFilterName);
01569     if (FAILED(hr)) {
01570         WARN("Unable add filter (%x)\n", hr);
01571         IBaseFilter_Release(preader);
01572         return hr;
01573     }
01574 
01575     hr = IBaseFilter_QueryInterface(preader, &IID_IFileSourceFilter, (LPVOID*)&pfile);
01576     if (FAILED(hr)) {
01577         WARN("Unable to get IFileSourceInterface (%x)\n", hr);
01578         goto error;
01579     }
01580 
01581     /* Load the file in the file source filter */
01582     hr = IFileSourceFilter_Load(pfile, lpcwstrFileName, NULL);
01583     if (FAILED(hr)) {
01584         WARN("Load (%x)\n", hr);
01585         goto error;
01586     }
01587 
01588     IFileSourceFilter_GetCurFile(pfile, &filename, &mt);
01589     if (FAILED(hr)) {
01590         WARN("GetCurFile (%x)\n", hr);
01591         goto error;
01592     }
01593 
01594     TRACE("File %s\n", debugstr_w(filename));
01595     TRACE("MajorType %s\n", debugstr_guid(&mt.majortype));
01596     TRACE("SubType %s\n", debugstr_guid(&mt.subtype));
01597 
01598     if (ppFilter)
01599         *ppFilter = preader;
01600     IFileSourceFilter_Release(pfile);
01601 
01602     return S_OK;
01603     
01604 error:
01605     if (pfile)
01606         IFileSourceFilter_Release(pfile);
01607     IFilterGraph2_RemoveFilter(iface, preader);
01608     IBaseFilter_Release(preader);
01609        
01610     return hr;
01611 }
01612 
01613 static HRESULT WINAPI FilterGraph2_SetLogFile(IFilterGraph2 *iface,
01614                           DWORD_PTR hFile) {
01615     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
01616 
01617     TRACE("(%p/%p)->(%08x): stub !!!\n", This, iface, (DWORD) hFile);
01618 
01619     return S_OK;
01620 }
01621 
01622 static HRESULT WINAPI FilterGraph2_Abort(IFilterGraph2 *iface) {
01623     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
01624 
01625     TRACE("(%p/%p)->(): stub !!!\n", This, iface);
01626 
01627     return S_OK;
01628 }
01629 
01630 static HRESULT WINAPI FilterGraph2_ShouldOperationContinue(IFilterGraph2 *iface) {
01631     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
01632 
01633     TRACE("(%p/%p)->(): stub !!!\n", This, iface);
01634 
01635     return S_OK;
01636 }
01637 
01638 /*** IFilterGraph2 methods ***/
01639 static HRESULT WINAPI FilterGraph2_AddSourceFilterForMoniker(IFilterGraph2 *iface,
01640                                                              IMoniker *pMoniker,
01641                                                              IBindCtx *pCtx,
01642                                                              LPCWSTR lpcwstrFilterName,
01643                                                              IBaseFilter **ppFilter) {
01644     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
01645 
01646     TRACE("(%p/%p)->(%p %p %s %p): stub !!!\n", This, iface, pMoniker, pCtx, debugstr_w(lpcwstrFilterName), ppFilter);
01647 
01648     return S_OK;
01649 }
01650 
01651 static HRESULT WINAPI FilterGraph2_ReconnectEx(IFilterGraph2 *iface,
01652                                                IPin *ppin,
01653                                                const AM_MEDIA_TYPE *pmt) {
01654     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
01655 
01656     TRACE("(%p/%p)->(%p %p): stub !!!\n", This, iface, ppin, pmt);
01657 
01658     return S_OK;
01659 }
01660 
01661 static HRESULT WINAPI FilterGraph2_RenderEx(IFilterGraph2 *iface,
01662                                             IPin *pPinOut,
01663                                             DWORD dwFlags,
01664                                             DWORD *pvContext) {
01665     ICOM_THIS_MULTI(IFilterGraphImpl, IFilterGraph2_vtbl, iface);
01666 
01667     TRACE("(%p/%p)->(%p %08x %p): stub !!!\n", This, iface, pPinOut, dwFlags, pvContext);
01668 
01669     return S_OK;
01670 }
01671 
01672 
01673 static const IFilterGraph2Vtbl IFilterGraph2_VTable =
01674 {
01675     FilterGraph2_QueryInterface,
01676     FilterGraph2_AddRef,
01677     FilterGraph2_Release,
01678     FilterGraph2_AddFilter,
01679     FilterGraph2_RemoveFilter,
01680     FilterGraph2_EnumFilters,
01681     FilterGraph2_FindFilterByName,
01682     FilterGraph2_ConnectDirect,
01683     FilterGraph2_Reconnect,
01684     FilterGraph2_Disconnect,
01685     FilterGraph2_SetDefaultSyncSource,
01686     FilterGraph2_Connect,
01687     FilterGraph2_Render,
01688     FilterGraph2_RenderFile,
01689     FilterGraph2_AddSourceFilter,
01690     FilterGraph2_SetLogFile,
01691     FilterGraph2_Abort,
01692     FilterGraph2_ShouldOperationContinue,
01693     FilterGraph2_AddSourceFilterForMoniker,
01694     FilterGraph2_ReconnectEx,
01695     FilterGraph2_RenderEx
01696 };
01697 
01698 /*** IUnknown methods ***/
01699 static HRESULT WINAPI MediaControl_QueryInterface(IMediaControl *iface,
01700                           REFIID riid,
01701                           LPVOID*ppvObj) {
01702     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
01703 
01704     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
01705 
01706     return Filtergraph_QueryInterface(This, riid, ppvObj);
01707 }
01708 
01709 static ULONG WINAPI MediaControl_AddRef(IMediaControl *iface) {
01710     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
01711 
01712     TRACE("(%p/%p)->()\n", This, iface);
01713 
01714     return Filtergraph_AddRef(This);
01715 }
01716 
01717 static ULONG WINAPI MediaControl_Release(IMediaControl *iface) {
01718     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
01719 
01720     TRACE("(%p/%p)->()\n", This, iface);
01721 
01722     return Filtergraph_Release(This);
01723 
01724 }
01725 
01726 /*** IDispatch methods ***/
01727 static HRESULT WINAPI MediaControl_GetTypeInfoCount(IMediaControl *iface,
01728                             UINT*pctinfo) {
01729     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
01730 
01731     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
01732 
01733     return S_OK;
01734 }
01735 
01736 static HRESULT WINAPI MediaControl_GetTypeInfo(IMediaControl *iface,
01737                            UINT iTInfo,
01738                            LCID lcid,
01739                            ITypeInfo**ppTInfo) {
01740     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
01741 
01742     TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
01743 
01744     return S_OK;
01745 }
01746 
01747 static HRESULT WINAPI MediaControl_GetIDsOfNames(IMediaControl *iface,
01748                          REFIID riid,
01749                          LPOLESTR*rgszNames,
01750                          UINT cNames,
01751                          LCID lcid,
01752                          DISPID*rgDispId) {
01753     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
01754 
01755     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
01756 
01757     return S_OK;
01758 }
01759 
01760 static HRESULT WINAPI MediaControl_Invoke(IMediaControl *iface,
01761                       DISPID dispIdMember,
01762                       REFIID riid,
01763                       LCID lcid,
01764                       WORD wFlags,
01765                       DISPPARAMS*pDispParams,
01766                       VARIANT*pVarResult,
01767                       EXCEPINFO*pExepInfo,
01768                       UINT*puArgErr) {
01769     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
01770 
01771     TRACE("(%p/%p)->(%d, %s (%p), %d, %04x, %p, %p, %p, %p): stub !!!\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
01772 
01773     return S_OK;
01774 }
01775 
01776 typedef HRESULT(WINAPI *fnFoundFilter)(IBaseFilter *, DWORD_PTR data);
01777 
01778 static HRESULT ExploreGraph(IFilterGraphImpl* pGraph, IPin* pOutputPin, fnFoundFilter FoundFilter, DWORD_PTR data)
01779 {
01780     HRESULT hr;
01781     IPin* pInputPin;
01782     IPin** ppPins;
01783     ULONG nb;
01784     ULONG i;
01785     PIN_INFO PinInfo;
01786 
01787     TRACE("%p %p\n", pGraph, pOutputPin);
01788     PinInfo.pFilter = NULL;
01789 
01790     hr = IPin_ConnectedTo(pOutputPin, &pInputPin);
01791 
01792     if (SUCCEEDED(hr))
01793     {
01794         hr = IPin_QueryPinInfo(pInputPin, &PinInfo);
01795         if (SUCCEEDED(hr))
01796             hr = GetInternalConnections(PinInfo.pFilter, pInputPin, &ppPins, &nb);
01797         IPin_Release(pInputPin);
01798     }
01799 
01800     if (SUCCEEDED(hr))
01801     {
01802         if (nb == 0)
01803         {
01804             TRACE("Reached a renderer\n");
01805             /* Count renderers for end of stream notification */
01806             pGraph->nRenderers++;
01807         }
01808         else
01809         {
01810             for(i = 0; i < nb; i++)
01811             {
01812                 /* Explore the graph downstream from this pin
01813          * FIXME: We should prevent exploring from a pin more than once. This can happens when
01814          * several input pins are connected to the same output (a MUX for instance). */
01815                 ExploreGraph(pGraph, ppPins[i], FoundFilter, data);
01816                 IPin_Release(ppPins[i]);
01817             }
01818 
01819             CoTaskMemFree(ppPins);
01820         }
01821         TRACE("Doing stuff with filter %p\n", PinInfo.pFilter);
01822 
01823         FoundFilter(PinInfo.pFilter, data);
01824     }
01825 
01826     if (PinInfo.pFilter) IBaseFilter_Release(PinInfo.pFilter);
01827     return hr;
01828 }
01829 
01830 static HRESULT WINAPI SendRun(IBaseFilter *pFilter, DWORD_PTR data)
01831 {
01832     LONGLONG time = 0;
01833     IReferenceClock *clock = NULL;
01834 
01835     IBaseFilter_GetSyncSource(pFilter, &clock);
01836     if (clock)
01837     {
01838         IReferenceClock_GetTime(clock, &time);
01839         if (time)
01840             /* Add 50 ms */
01841             time += 500000;
01842         if (time < 0)
01843             time = 0;
01844         IReferenceClock_Release(clock);
01845     }
01846 
01847     return IBaseFilter_Run(pFilter, time);
01848 }
01849 
01850 static HRESULT WINAPI SendPause(IBaseFilter *pFilter, DWORD_PTR data)
01851 {
01852     return IBaseFilter_Pause(pFilter);
01853 }
01854 
01855 static HRESULT WINAPI SendStop(IBaseFilter *pFilter, DWORD_PTR data)
01856 {
01857     return IBaseFilter_Stop(pFilter);
01858 }
01859 
01860 static HRESULT WINAPI SendGetState(IBaseFilter *pFilter, DWORD_PTR data)
01861 {
01862     FILTER_STATE state;
01863     DWORD time_end = data;
01864     DWORD time_now = GetTickCount();
01865     LONG wait;
01866 
01867     if (time_end == INFINITE)
01868     {
01869         wait = INFINITE;
01870     }
01871     else if (time_end > time_now)
01872     {
01873         wait = time_end - time_now;
01874     }
01875     else
01876         wait = 0;
01877 
01878     return IBaseFilter_GetState(pFilter, wait, &state);
01879 }
01880 
01881 
01882 static HRESULT SendFilterMessage(IMediaControl *iface, fnFoundFilter FoundFilter, DWORD_PTR data)
01883 {
01884     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
01885     int i;
01886     IBaseFilter* pfilter;
01887     IEnumPins* pEnum;
01888     HRESULT hr;
01889     IPin* pPin;
01890     DWORD dummy;
01891     PIN_DIRECTION dir;
01892     TRACE("(%p/%p)->()\n", This, iface);
01893 
01894     /* Explorer the graph from source filters to renderers, determine renderers
01895      * number and run filters from renderers to source filters */
01896     This->nRenderers = 0;
01897     ResetEvent(This->hEventCompletion);
01898 
01899     for(i = 0; i < This->nFilters; i++)
01900     {
01901         BOOL source = TRUE;
01902         pfilter = This->ppFiltersInGraph[i];
01903         hr = IBaseFilter_EnumPins(pfilter, &pEnum);
01904         if (hr != S_OK)
01905         {
01906             WARN("Enum pins failed %x\n", hr);
01907             continue;
01908         }
01909         /* Check if it is a source filter */
01910         while(IEnumPins_Next(pEnum, 1, &pPin, &dummy) == S_OK)
01911         {
01912             IPin_QueryDirection(pPin, &dir);
01913             IPin_Release(pPin);
01914             if (dir == PINDIR_INPUT)
01915             {
01916                 source = FALSE;
01917                 break;
01918             }
01919         }
01920         if (source)
01921         {
01922             TRACE("Found a source filter %p\n", pfilter);
01923             IEnumPins_Reset(pEnum);
01924             while(IEnumPins_Next(pEnum, 1, &pPin, &dummy) == S_OK)
01925             {
01926                 /* Explore the graph downstream from this pin */
01927                 ExploreGraph(This, pPin, FoundFilter, data);
01928                 IPin_Release(pPin);
01929             }
01930             FoundFilter(pfilter, data);
01931         }
01932         IEnumPins_Release(pEnum);
01933     }
01934 
01935     return S_FALSE;
01936 }
01937 
01938 /*** IMediaControl methods ***/
01939 static HRESULT WINAPI MediaControl_Run(IMediaControl *iface) {
01940     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
01941     TRACE("(%p/%p)->()\n", This, iface);
01942 
01943     if (This->state == State_Running) return S_OK;
01944 
01945     EnterCriticalSection(&This->cs);
01946     if (This->state == State_Stopped)
01947         This->EcCompleteCount = 0;
01948 
01949     if (This->refClock)
01950     {
01951         IReferenceClock_GetTime(This->refClock, &This->start_time);
01952         This->start_time += 500000;
01953     }
01954     else This->position = This->start_time = 0;
01955 
01956     SendFilterMessage(iface, SendRun, 0);
01957     This->state = State_Running;
01958     LeaveCriticalSection(&This->cs);
01959     return S_FALSE;
01960 }
01961 
01962 static HRESULT WINAPI MediaControl_Pause(IMediaControl *iface) {
01963     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
01964     TRACE("(%p/%p)->()\n", This, iface);
01965 
01966     if (This->state == State_Paused) return S_OK;
01967 
01968     EnterCriticalSection(&This->cs);
01969     if (This->state == State_Stopped)
01970         This->EcCompleteCount = 0;
01971 
01972     if (This->state == State_Running && This->refClock)
01973     {
01974         LONGLONG time = This->start_time;
01975         IReferenceClock_GetTime(This->refClock, &time);
01976         This->position += time - This->start_time;
01977     }
01978 
01979     SendFilterMessage(iface, SendPause, 0);
01980     This->state = State_Paused;
01981     LeaveCriticalSection(&This->cs);
01982     return S_FALSE;
01983 }
01984 
01985 static HRESULT WINAPI MediaControl_Stop(IMediaControl *iface) {
01986     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
01987     TRACE("(%p/%p)->()\n", This, iface);
01988 
01989     if (This->state == State_Stopped) return S_OK;
01990 
01991     EnterCriticalSection(&This->cs);
01992     if (This->state == State_Running && This->refClock)
01993     {
01994         LONGLONG time = This->start_time;
01995         IReferenceClock_GetTime(This->refClock, &time);
01996         This->position += time - This->start_time;
01997     }
01998 
01999     if (This->state == State_Running) SendFilterMessage(iface, SendPause, 0);
02000     SendFilterMessage(iface, SendStop, 0);
02001     This->state = State_Stopped;
02002     LeaveCriticalSection(&This->cs);
02003     return S_OK;
02004 }
02005 
02006 static HRESULT WINAPI MediaControl_GetState(IMediaControl *iface,
02007                         LONG msTimeout,
02008                         OAFilterState *pfs) {
02009     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
02010     DWORD end;
02011 
02012     TRACE("(%p/%p)->(%d, %p)\n", This, iface, msTimeout, pfs);
02013 
02014     if (!pfs)
02015         return E_POINTER;
02016 
02017     EnterCriticalSection(&This->cs);
02018 
02019     *pfs = This->state;
02020     if (msTimeout > 0)
02021     {
02022         end = GetTickCount() + msTimeout;
02023     }
02024     else if (msTimeout < 0)
02025     {
02026         end = INFINITE;
02027     }
02028     else
02029     {
02030         end = 0;
02031     }
02032     if (end)
02033         SendFilterMessage(iface, SendGetState, end);
02034 
02035     LeaveCriticalSection(&This->cs);
02036 
02037     return S_OK;
02038 }
02039 
02040 static HRESULT WINAPI MediaControl_RenderFile(IMediaControl *iface,
02041                           BSTR strFilename) {
02042     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
02043 
02044     FIXME("(%p/%p)->(%s (%p)): stub !!!\n", This, iface, debugstr_w(strFilename), strFilename);
02045 
02046     return S_OK;
02047 }
02048 
02049 static HRESULT WINAPI MediaControl_AddSourceFilter(IMediaControl *iface,
02050                            BSTR strFilename,
02051                            IDispatch **ppUnk) {
02052     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
02053 
02054     FIXME("(%p/%p)->(%s (%p), %p): stub !!!\n", This, iface, debugstr_w(strFilename), strFilename, ppUnk);
02055 
02056     return S_OK;
02057 }
02058 
02059 static HRESULT WINAPI MediaControl_get_FilterCollection(IMediaControl *iface,
02060                             IDispatch **ppUnk) {
02061     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
02062 
02063     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, ppUnk);
02064 
02065     return S_OK;
02066 }
02067 
02068 static HRESULT WINAPI MediaControl_get_RegFilterCollection(IMediaControl *iface,
02069                                IDispatch **ppUnk) {
02070     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
02071 
02072     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, ppUnk);
02073 
02074     return S_OK;
02075 }
02076 
02077 static HRESULT WINAPI MediaControl_StopWhenReady(IMediaControl *iface) {
02078     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaControl_vtbl, iface);
02079 
02080     FIXME("(%p/%p)->(): stub !!!\n", This, iface);
02081 
02082     return S_OK;
02083 }
02084 
02085 
02086 static const IMediaControlVtbl IMediaControl_VTable =
02087 {
02088     MediaControl_QueryInterface,
02089     MediaControl_AddRef,
02090     MediaControl_Release,
02091     MediaControl_GetTypeInfoCount,
02092     MediaControl_GetTypeInfo,
02093     MediaControl_GetIDsOfNames,
02094     MediaControl_Invoke,
02095     MediaControl_Run,
02096     MediaControl_Pause,
02097     MediaControl_Stop,
02098     MediaControl_GetState,
02099     MediaControl_RenderFile,
02100     MediaControl_AddSourceFilter,
02101     MediaControl_get_FilterCollection,
02102     MediaControl_get_RegFilterCollection,
02103     MediaControl_StopWhenReady
02104 };
02105 
02106 
02107 /*** IUnknown methods ***/
02108 static HRESULT WINAPI MediaSeeking_QueryInterface(IMediaSeeking *iface,
02109                           REFIID riid,
02110                           LPVOID*ppvObj) {
02111     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
02112 
02113     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
02114 
02115     return Filtergraph_QueryInterface(This, riid, ppvObj);
02116 }
02117 
02118 static ULONG WINAPI MediaSeeking_AddRef(IMediaSeeking *iface) {
02119     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
02120 
02121     TRACE("(%p/%p)->()\n", This, iface);
02122 
02123     return Filtergraph_AddRef(This);
02124 }
02125 
02126 static ULONG WINAPI MediaSeeking_Release(IMediaSeeking *iface) {
02127     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
02128 
02129     TRACE("(%p/%p)->()\n", This, iface);
02130 
02131     return Filtergraph_Release(This);
02132 }
02133 
02134 typedef HRESULT (WINAPI *fnFoundSeek)(IFilterGraphImpl *This, IMediaSeeking*, DWORD_PTR arg);
02135 
02136 static HRESULT all_renderers_seek(IFilterGraphImpl *This, fnFoundSeek FoundSeek, DWORD_PTR arg) {
02137     BOOL allnotimpl = TRUE;
02138     int i;
02139     IBaseFilter* pfilter;
02140     IEnumPins* pEnum;
02141     HRESULT hr, hr_return = S_OK;
02142     IPin* pPin;
02143     DWORD dummy;
02144     PIN_DIRECTION dir;
02145 
02146     TRACE("(%p)->(%p %08lx)\n", This, FoundSeek, arg);
02147     /* Send a message to all renderers, they are responsible for broadcasting it further */
02148 
02149     for(i = 0; i < This->nFilters; i++)
02150     {
02151         BOOL renderer = TRUE;
02152         pfilter = This->ppFiltersInGraph[i];
02153         hr = IBaseFilter_EnumPins(pfilter, &pEnum);
02154         if (hr != S_OK)
02155         {
02156             WARN("Enum pins failed %x\n", hr);
02157             continue;
02158         }
02159         /* Check if it is a source filter */
02160         while(IEnumPins_Next(pEnum, 1, &pPin, &dummy) == S_OK)
02161         {
02162             IPin_QueryDirection(pPin, &dir);
02163             IPin_Release(pPin);
02164             if (dir != PINDIR_INPUT)
02165             {
02166                 renderer = FALSE;
02167                 break;
02168             }
02169         }
02170         IEnumPins_Release(pEnum);
02171         if (renderer)
02172         {
02173             IMediaSeeking *seek = NULL;
02174             IBaseFilter_QueryInterface(pfilter, &IID_IMediaSeeking, (void**)&seek);
02175             if (!seek)
02176                 continue;
02177 
02178             hr = FoundSeek(This, seek, arg);
02179 
02180             IMediaSeeking_Release(seek);
02181             if (hr_return != E_NOTIMPL)
02182                 allnotimpl = FALSE;
02183             if (hr_return == S_OK || (FAILED(hr) && hr != E_NOTIMPL && SUCCEEDED(hr_return)))
02184                 hr_return = hr;
02185         }
02186     }
02187 
02188     if (allnotimpl)
02189         return E_NOTIMPL;
02190     return hr_return;
02191 }
02192 
02193 static HRESULT WINAPI FoundCapabilities(IFilterGraphImpl *This, IMediaSeeking *seek, DWORD_PTR pcaps)
02194 {
02195     HRESULT hr;
02196     DWORD caps = 0;
02197 
02198     hr = IMediaSeeking_GetCapabilities(seek, &caps);
02199     if (FAILED(hr))
02200         return hr;
02201 
02202     /* Only add common capabilities everything supports */
02203     *(DWORD*)pcaps &= caps;
02204 
02205     return hr;
02206 }
02207 
02208 /*** IMediaSeeking methods ***/
02209 static HRESULT WINAPI MediaSeeking_GetCapabilities(IMediaSeeking *iface,
02210                            DWORD *pCapabilities) {
02211     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
02212     HRESULT hr;
02213     TRACE("(%p/%p)->(%p)\n", This, iface, pCapabilities);
02214 
02215     if (!pCapabilities)
02216         return E_POINTER;
02217 
02218     EnterCriticalSection(&This->cs);
02219     *pCapabilities = 0xffffffff;
02220 
02221     hr = all_renderers_seek(This, FoundCapabilities, (DWORD_PTR)pCapabilities);
02222     LeaveCriticalSection(&This->cs);
02223 
02224     return hr;
02225 }
02226 
02227 static HRESULT WINAPI MediaSeeking_CheckCapabilities(IMediaSeeking *iface,
02228                              DWORD *pCapabilities) {
02229     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
02230     DWORD originalcaps;
02231     HRESULT hr;
02232     TRACE("(%p/%p)->(%p)\n", This, iface, pCapabilities);
02233 
02234     if (!pCapabilities)
02235         return E_POINTER;
02236 
02237     EnterCriticalSection(&This->cs);
02238     originalcaps = *pCapabilities;
02239     hr = all_renderers_seek(This, FoundCapabilities, (DWORD_PTR)pCapabilities);
02240     LeaveCriticalSection(&This->cs);
02241 
02242     if (FAILED(hr))
02243         return hr;
02244 
02245     if (!*pCapabilities)
02246         return E_FAIL;
02247     if (*pCapabilities != originalcaps)
02248         return S_FALSE;
02249     return S_OK;
02250 }
02251 
02252 static HRESULT WINAPI MediaSeeking_IsFormatSupported(IMediaSeeking *iface,
02253                              const GUID *pFormat) {
02254     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
02255 
02256     if (!pFormat)
02257         return E_POINTER;
02258 
02259     TRACE("(%p/%p)->(%s)\n", This, iface, debugstr_guid(pFormat));
02260 
02261     if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, pFormat))
02262     {
02263         FIXME("Unhandled time format %s\n", debugstr_guid(pFormat));
02264         return S_FALSE;
02265     }
02266 
02267     return S_OK;
02268 }
02269 
02270 static HRESULT WINAPI MediaSeeking_QueryPreferredFormat(IMediaSeeking *iface,
02271                             GUID *pFormat) {
02272     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
02273 
02274     if (!pFormat)
02275         return E_POINTER;
02276 
02277     FIXME("(%p/%p)->(%p): semi-stub !!!\n", This, iface, pFormat);
02278     memcpy(pFormat, &TIME_FORMAT_MEDIA_TIME, sizeof(GUID));
02279 
02280     return S_OK;
02281 }
02282 
02283 static HRESULT WINAPI MediaSeeking_GetTimeFormat(IMediaSeeking *iface,
02284                          GUID *pFormat) {
02285     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
02286 
02287     if (!pFormat)
02288         return E_POINTER;
02289 
02290     TRACE("(%p/%p)->(%p)\n", This, iface, pFormat);
02291     memcpy(pFormat, &This->timeformatseek, sizeof(GUID));
02292 
02293     return S_OK;
02294 }
02295 
02296 static HRESULT WINAPI MediaSeeking_IsUsingTimeFormat(IMediaSeeking *iface,
02297                              const GUID *pFormat) {
02298     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
02299 
02300     TRACE("(%p/%p)->(%p)\n", This, iface, pFormat);
02301     if (!pFormat)
02302         return E_POINTER;
02303 
02304     if (memcmp(pFormat, &This->timeformatseek, sizeof(GUID)))
02305         return S_FALSE;
02306 
02307     return S_OK;
02308 }
02309 
02310 static HRESULT WINAPI MediaSeeking_SetTimeFormat(IMediaSeeking *iface,
02311                          const GUID *pFormat) {
02312     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
02313 
02314     if (!pFormat)
02315         return E_POINTER;
02316 
02317     TRACE("(%p/%p)->(%s)\n", This, iface, debugstr_guid(pFormat));
02318 
02319     if (This->state != State_Stopped)
02320         return VFW_E_WRONG_STATE;
02321 
02322     if (!IsEqualGUID(&TIME_FORMAT_MEDIA_TIME, pFormat))
02323     {
02324         FIXME("Unhandled time format %s\n", debugstr_guid(pFormat));
02325         return E_INVALIDARG;
02326     }
02327 
02328     return S_OK;
02329 }
02330 
02331 static HRESULT WINAPI FoundDuration(IFilterGraphImpl *This, IMediaSeeking *seek, DWORD_PTR pduration)
02332 {
02333     HRESULT hr;
02334     LONGLONG duration = 0, *pdur = (LONGLONG*)pduration;
02335 
02336     hr = IMediaSeeking_GetDuration(seek, &duration);
02337     if (FAILED(hr))
02338         return hr;
02339 
02340     /* FIXME: Minimum or maximum duration? Assuming minimum */
02341     if (duration > 0 && *pdur < duration)
02342         *pdur = duration;
02343 
02344     return hr;
02345 }
02346 
02347 static HRESULT WINAPI MediaSeeking_GetDuration(IMediaSeeking *iface,
02348                            LONGLONG *pDuration) {
02349     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
02350     HRESULT hr;
02351 
02352     TRACE("(%p/%p)->(%p)\n", This, iface, pDuration);
02353 
02354     if (!pDuration)
02355         return E_POINTER;
02356 
02357     EnterCriticalSection(&This->cs);
02358     *pDuration = -1;
02359     hr = all_renderers_seek(This, FoundDuration, (DWORD_PTR)pDuration);
02360     LeaveCriticalSection(&This->cs);
02361 
02362     TRACE("--->%08x\n", hr);
02363     return hr;
02364 }
02365 
02366 static HRESULT WINAPI MediaSeeking_GetStopPosition(IMediaSeeking *iface,
02367                            LONGLONG *pStop) {
02368     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
02369     HRESULT hr = S_OK;
02370 
02371     TRACE("(%p/%p)->(%p)\n", This, iface, pStop);
02372 
02373     if (!pStop)
02374         return E_POINTER;
02375 
02376     EnterCriticalSection(&This->cs);
02377     if (This->stop_position < 0)
02378         /* Stop position not set, use duration instead */
02379         hr = IMediaSeeking_GetDuration(iface, pStop);
02380     else
02381         *pStop = This->stop_position;
02382 
02383     LeaveCriticalSection(&This->cs);
02384 
02385     return hr;
02386 }
02387 
02388 static HRESULT WINAPI MediaSeeking_GetCurrentPosition(IMediaSeeking *iface,
02389                               LONGLONG *pCurrent) {
02390     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
02391     LONGLONG time = 0;
02392 
02393     if (!pCurrent)
02394         return E_POINTER;
02395 
02396     EnterCriticalSection(&This->cs);
02397     if (This->state == State_Running && This->refClock)
02398     {
02399         IReferenceClock_GetTime(This->refClock, &time);
02400         if (time)
02401             time += This->position - This->start_time;
02402         if (time < This->position)
02403             time = This->position;
02404         *pCurrent = time;
02405     }
02406     else
02407         *pCurrent = This->position;
02408     LeaveCriticalSection(&This->cs);
02409 
02410     TRACE("Time: %u.%03u\n", (DWORD)(*pCurrent / 10000000), (DWORD)((*pCurrent / 10000)%1000));
02411 
02412     return S_OK;
02413 }
02414 
02415 static HRESULT WINAPI MediaSeeking_ConvertTimeFormat(IMediaSeeking *iface,
02416                              LONGLONG *pTarget,
02417                              const GUID *pTargetFormat,
02418                              LONGLONG Source,
02419                              const GUID *pSourceFormat) {
02420     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
02421 
02422     FIXME("(%p/%p)->(%p, %p, 0x%s, %p): stub !!!\n", This, iface, pTarget,
02423         pTargetFormat, wine_dbgstr_longlong(Source), pSourceFormat);
02424 
02425     return S_OK;
02426 }
02427 
02428 struct pos_args {
02429     LONGLONG* current, *stop;
02430     DWORD curflags, stopflags;
02431 };
02432 
02433 static HRESULT WINAPI found_setposition(IFilterGraphImpl *This, IMediaSeeking *seek, DWORD_PTR pargs)
02434 {
02435     struct pos_args *args = (void*)pargs;
02436 
02437     return IMediaSeeking_SetPositions(seek, args->current, args->curflags, args->stop, args->stopflags);
02438 }
02439 
02440 static HRESULT WINAPI MediaSeeking_SetPositions(IMediaSeeking *iface,
02441                         LONGLONG *pCurrent,
02442                         DWORD dwCurrentFlags,
02443                         LONGLONG *pStop,
02444                         DWORD dwStopFlags) {
02445     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
02446     HRESULT hr = S_OK;
02447     FILTER_STATE state;
02448     struct pos_args args;
02449 
02450     TRACE("(%p/%p)->(%p, %08x, %p, %08x)\n", This, iface, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
02451 
02452     EnterCriticalSection(&This->cs);
02453     state = This->state;
02454     TRACE("State: %s\n", state == State_Running ? "Running" : (state == State_Paused ? "Paused" : (state == State_Stopped ? "Stopped" : "UNKNOWN")));
02455 
02456     if ((dwCurrentFlags & 0x7) == AM_SEEKING_AbsolutePositioning)
02457     {
02458         This->position = *pCurrent;
02459     }
02460     else if ((dwCurrentFlags & 0x7) != AM_SEEKING_NoPositioning)
02461         FIXME("Adjust method %x not handled yet!\n", dwCurrentFlags & 0x7);
02462 
02463     if ((dwStopFlags & 0x7) == AM_SEEKING_AbsolutePositioning)
02464         This->stop_position = *pStop;
02465     else if ((dwStopFlags & 0x7) != AM_SEEKING_NoPositioning)
02466         FIXME("Stop position not handled yet!\n");
02467 
02468     args.current = pCurrent;
02469     args.stop = pStop;
02470     args.curflags = dwCurrentFlags;
02471     args.stopflags = dwStopFlags;
02472     hr = all_renderers_seek(This, found_setposition, (DWORD_PTR)&args);
02473 
02474     if (This->refClock && ((dwCurrentFlags & 0x7) != AM_SEEKING_NoPositioning))
02475     {
02476         /* Update start time, prevents weird jumps */
02477         IReferenceClock_GetTime(This->refClock, &This->start_time);
02478     }
02479     LeaveCriticalSection(&This->cs);
02480 
02481     return hr;
02482 }
02483 
02484 static HRESULT WINAPI MediaSeeking_GetPositions(IMediaSeeking *iface,
02485                         LONGLONG *pCurrent,
02486                         LONGLONG *pStop) {
02487     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
02488     HRESULT hr;
02489 
02490     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pCurrent, pStop);
02491     hr = IMediaSeeking_GetCurrentPosition(iface, pCurrent);
02492     if (SUCCEEDED(hr))
02493         hr = IMediaSeeking_GetStopPosition(iface, pStop);
02494 
02495     return hr;
02496 }
02497 
02498 static HRESULT WINAPI MediaSeeking_GetAvailable(IMediaSeeking *iface,
02499                         LONGLONG *pEarliest,
02500                         LONGLONG *pLatest) {
02501     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
02502 
02503     FIXME("(%p/%p)->(%p, %p): stub !!!\n", This, iface, pEarliest, pLatest);
02504 
02505     return S_OK;
02506 }
02507 
02508 static HRESULT WINAPI MediaSeeking_SetRate(IMediaSeeking *iface,
02509                        double dRate) {
02510     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
02511 
02512     FIXME("(%p/%p)->(%f): stub !!!\n", This, iface, dRate);
02513 
02514     return S_OK;
02515 }
02516 
02517 static HRESULT WINAPI MediaSeeking_GetRate(IMediaSeeking *iface,
02518                        double *pdRate) {
02519     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
02520 
02521     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pdRate);
02522 
02523     return S_OK;
02524 }
02525 
02526 static HRESULT WINAPI MediaSeeking_GetPreroll(IMediaSeeking *iface,
02527                           LONGLONG *pllPreroll) {
02528     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaSeeking_vtbl, iface);
02529 
02530     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pllPreroll);
02531 
02532     return S_OK;
02533 }
02534 
02535 
02536 static const IMediaSeekingVtbl IMediaSeeking_VTable =
02537 {
02538     MediaSeeking_QueryInterface,
02539     MediaSeeking_AddRef,
02540     MediaSeeking_Release,
02541     MediaSeeking_GetCapabilities,
02542     MediaSeeking_CheckCapabilities,
02543     MediaSeeking_IsFormatSupported,
02544     MediaSeeking_QueryPreferredFormat,
02545     MediaSeeking_GetTimeFormat,
02546     MediaSeeking_IsUsingTimeFormat,
02547     MediaSeeking_SetTimeFormat,
02548     MediaSeeking_GetDuration,
02549     MediaSeeking_GetStopPosition,
02550     MediaSeeking_GetCurrentPosition,
02551     MediaSeeking_ConvertTimeFormat,
02552     MediaSeeking_SetPositions,
02553     MediaSeeking_GetPositions,
02554     MediaSeeking_GetAvailable,
02555     MediaSeeking_SetRate,
02556     MediaSeeking_GetRate,
02557     MediaSeeking_GetPreroll
02558 };
02559 
02560 static inline IFilterGraphImpl *impl_from_IMediaPosition( IMediaPosition *iface )
02561 {
02562     return (IFilterGraphImpl *)((char*)iface - FIELD_OFFSET(IFilterGraphImpl, IMediaPosition_vtbl));
02563 }
02564 
02565 /*** IUnknown methods ***/
02566 static HRESULT WINAPI MediaPosition_QueryInterface(IMediaPosition* iface, REFIID riid, void** ppvObj)
02567 {
02568     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
02569 
02570     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
02571     return Filtergraph_QueryInterface(This, riid, ppvObj);
02572 }
02573 
02574 static ULONG WINAPI MediaPosition_AddRef(IMediaPosition *iface)
02575 {
02576     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
02577 
02578     TRACE("(%p/%p)->()\n", This, iface);
02579     return Filtergraph_AddRef(This);
02580 }
02581 
02582 static ULONG WINAPI MediaPosition_Release(IMediaPosition *iface)
02583 {
02584     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
02585 
02586     TRACE("(%p/%p)->()\n", This, iface);
02587     return Filtergraph_Release(This);
02588 }
02589 
02590 /*** IDispatch methods ***/
02591 static HRESULT WINAPI MediaPosition_GetTypeInfoCount(IMediaPosition *iface, UINT* pctinfo){
02592     FIXME("(%p) stub!\n", iface);
02593     return E_NOTIMPL;
02594 }
02595 
02596 static HRESULT WINAPI MediaPosition_GetTypeInfo(IMediaPosition *iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo){
02597     FIXME("(%p) stub!\n", iface);
02598     return E_NOTIMPL;
02599 }
02600 
02601 static HRESULT WINAPI MediaPosition_GetIDsOfNames(IMediaPosition* iface, REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId){
02602     FIXME("(%p) stub!\n", iface);
02603     return E_NOTIMPL;
02604 }
02605 
02606 static HRESULT WINAPI MediaPosition_Invoke(IMediaPosition* iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr){
02607     FIXME("(%p) stub!\n", iface);
02608     return E_NOTIMPL;
02609 }
02610 
02611 /*** IMediaPosition methods ***/
02612 static HRESULT WINAPI MediaPosition_get_Duration(IMediaPosition * iface, REFTIME *plength)
02613 {
02614     LONGLONG duration;
02615     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
02616     HRESULT hr = IMediaSeeking_GetDuration( (IMediaSeeking *)&This->IMediaSeeking_vtbl, &duration );
02617     if (SUCCEEDED(hr)) *plength = duration;
02618     return hr;
02619 }
02620 
02621 static HRESULT WINAPI MediaPosition_put_CurrentPosition(IMediaPosition * iface, REFTIME llTime)
02622 {
02623     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
02624     LONGLONG reftime = llTime;
02625 
02626     return IMediaSeeking_SetPositions((IMediaSeeking *)&This->IMediaSeeking_vtbl,
02627                                       &reftime, AM_SEEKING_AbsolutePositioning,
02628                                       NULL, AM_SEEKING_NoPositioning);
02629 }
02630 
02631 static HRESULT WINAPI MediaPosition_get_CurrentPosition(IMediaPosition * iface, REFTIME *pllTime)
02632 {
02633     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
02634     LONGLONG pos;
02635     HRESULT hr = IMediaSeeking_GetCurrentPosition( (IMediaSeeking *)&This->IMediaSeeking_vtbl, &pos );
02636     if (SUCCEEDED(hr)) *pllTime = pos;
02637     return hr;
02638 }
02639 
02640 static HRESULT WINAPI MediaPosition_get_StopTime(IMediaPosition * iface, REFTIME *pllTime)
02641 {
02642     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
02643     LONGLONG pos;
02644     HRESULT hr = IMediaSeeking_GetStopPosition( (IMediaSeeking *)&This->IMediaSeeking_vtbl, &pos );
02645     if (SUCCEEDED(hr)) *pllTime = pos;
02646     return hr;
02647 }
02648 
02649 static HRESULT WINAPI MediaPosition_put_StopTime(IMediaPosition * iface, REFTIME llTime)
02650 {
02651     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
02652     LONGLONG reftime = llTime;
02653 
02654     return IMediaSeeking_SetPositions((IMediaSeeking *)&This->IMediaSeeking_vtbl,
02655                                       NULL, AM_SEEKING_NoPositioning,
02656                                       &reftime, AM_SEEKING_AbsolutePositioning);
02657 }
02658 
02659 static HRESULT WINAPI MediaPosition_get_PrerollTime(IMediaPosition * iface, REFTIME *pllTime){
02660     FIXME("(%p)->(%p) stub!\n", iface, pllTime);
02661     return E_NOTIMPL;
02662 }
02663 
02664 static HRESULT WINAPI MediaPosition_put_PrerollTime(IMediaPosition * iface, REFTIME llTime){
02665     FIXME("(%p)->(%f) stub!\n", iface, llTime);
02666     return E_NOTIMPL;
02667 }
02668 
02669 static HRESULT WINAPI MediaPosition_put_Rate(IMediaPosition * iface, double dRate)
02670 {
02671     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
02672     return IMediaSeeking_SetRate((IMediaSeeking *)&This->IMediaSeeking_vtbl, dRate);
02673 }
02674 
02675 static HRESULT WINAPI MediaPosition_get_Rate(IMediaPosition * iface, double *pdRate)
02676 {
02677     IFilterGraphImpl *This = impl_from_IMediaPosition( iface );
02678     return IMediaSeeking_GetRate((IMediaSeeking *)&This->IMediaSeeking_vtbl, pdRate);
02679 }
02680 
02681 static HRESULT WINAPI MediaPosition_CanSeekForward(IMediaPosition * iface, LONG *pCanSeekForward){
02682     FIXME("(%p)->(%p) stub!\n", iface, pCanSeekForward);
02683     return E_NOTIMPL;
02684 }
02685 
02686 static HRESULT WINAPI MediaPosition_CanSeekBackward(IMediaPosition * iface, LONG *pCanSeekBackward){
02687     FIXME("(%p)->(%p) stub!\n", iface, pCanSeekBackward);
02688     return E_NOTIMPL;
02689 }
02690 
02691 
02692 static const IMediaPositionVtbl IMediaPosition_VTable =
02693 {
02694     MediaPosition_QueryInterface,
02695     MediaPosition_AddRef,
02696     MediaPosition_Release,
02697     MediaPosition_GetTypeInfoCount,
02698     MediaPosition_GetTypeInfo,
02699     MediaPosition_GetIDsOfNames,
02700     MediaPosition_Invoke,
02701     MediaPosition_get_Duration,
02702     MediaPosition_put_CurrentPosition,
02703     MediaPosition_get_CurrentPosition,
02704     MediaPosition_get_StopTime,
02705     MediaPosition_put_StopTime,
02706     MediaPosition_get_PrerollTime,
02707     MediaPosition_put_PrerollTime,
02708     MediaPosition_put_Rate,
02709     MediaPosition_get_Rate,
02710     MediaPosition_CanSeekForward,
02711     MediaPosition_CanSeekBackward
02712 };
02713 
02714 static HRESULT GetTargetInterface(IFilterGraphImpl* pGraph, REFIID riid, LPVOID* ppvObj)
02715 {
02716     HRESULT hr = E_NOINTERFACE;
02717     int i;
02718     int entry;
02719 
02720     /* Check if the interface type is already registered */
02721     for (entry = 0; entry < pGraph->nItfCacheEntries; entry++)
02722         if (riid == pGraph->ItfCacheEntries[entry].riid)
02723         {
02724             if (pGraph->ItfCacheEntries[entry].iface)
02725             {
02726                 /* Return the interface if available */
02727                 *ppvObj = pGraph->ItfCacheEntries[entry].iface;
02728                 return S_OK;
02729             }
02730             break;
02731         }
02732 
02733     if (entry >= MAX_ITF_CACHE_ENTRIES)
02734     {
02735         FIXME("Not enough space to store interface in the cache\n");
02736         return E_OUTOFMEMORY;
02737     }
02738 
02739     /* Find a filter supporting the requested interface */
02740     for (i = 0; i < pGraph->nFilters; i++)
02741     {
02742         hr = IBaseFilter_QueryInterface(pGraph->ppFiltersInGraph[i], riid, ppvObj);
02743         if (hr == S_OK)
02744         {
02745             pGraph->ItfCacheEntries[entry].riid = riid;
02746             pGraph->ItfCacheEntries[entry].filter = pGraph->ppFiltersInGraph[i];
02747             pGraph->ItfCacheEntries[entry].iface = *ppvObj;
02748             if (entry >= pGraph->nItfCacheEntries)
02749                 pGraph->nItfCacheEntries++;
02750             return S_OK;
02751         }
02752         if (hr != E_NOINTERFACE)
02753             return hr;
02754     }
02755 
02756     return hr;
02757 }
02758 
02759 /*** IUnknown methods ***/
02760 static HRESULT WINAPI BasicAudio_QueryInterface(IBasicAudio *iface,
02761                         REFIID riid,
02762                         LPVOID*ppvObj) {
02763     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
02764 
02765     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
02766 
02767     return Filtergraph_QueryInterface(This, riid, ppvObj);
02768 }
02769 
02770 static ULONG WINAPI BasicAudio_AddRef(IBasicAudio *iface) {
02771     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
02772 
02773     TRACE("(%p/%p)->()\n", This, iface);
02774 
02775     return Filtergraph_AddRef(This);
02776 }
02777 
02778 static ULONG WINAPI BasicAudio_Release(IBasicAudio *iface) {
02779     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
02780 
02781     TRACE("(%p/%p)->()\n", This, iface);
02782 
02783     return Filtergraph_Release(This);
02784 }
02785 
02786 /*** IDispatch methods ***/
02787 static HRESULT WINAPI BasicAudio_GetTypeInfoCount(IBasicAudio *iface,
02788                           UINT*pctinfo) {
02789     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
02790     IBasicAudio* pBasicAudio;
02791     HRESULT hr;
02792 
02793     TRACE("(%p/%p)->(%p)\n", This, iface, pctinfo);
02794 
02795     EnterCriticalSection(&This->cs);
02796 
02797     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
02798 
02799     if (hr == S_OK)
02800         hr = IBasicAudio_GetTypeInfoCount(pBasicAudio, pctinfo);
02801 
02802     LeaveCriticalSection(&This->cs);
02803 
02804     return hr;
02805 }
02806 
02807 static HRESULT WINAPI BasicAudio_GetTypeInfo(IBasicAudio *iface,
02808                          UINT iTInfo,
02809                          LCID lcid,
02810                          ITypeInfo**ppTInfo) {
02811     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
02812     IBasicAudio* pBasicAudio;
02813     HRESULT hr;
02814 
02815     TRACE("(%p/%p)->(%d, %d, %p)\n", This, iface, iTInfo, lcid, ppTInfo);
02816 
02817     EnterCriticalSection(&This->cs);
02818 
02819     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
02820 
02821     if (hr == S_OK)
02822         hr = IBasicAudio_GetTypeInfo(pBasicAudio, iTInfo, lcid, ppTInfo);
02823 
02824     LeaveCriticalSection(&This->cs);
02825 
02826     return hr;
02827 }
02828 
02829 static HRESULT WINAPI BasicAudio_GetIDsOfNames(IBasicAudio *iface,
02830                            REFIID riid,
02831                            LPOLESTR*rgszNames,
02832                            UINT cNames,
02833                            LCID lcid,
02834                            DISPID*rgDispId) {
02835     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
02836     IBasicAudio* pBasicAudio;
02837     HRESULT hr;
02838 
02839     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p)\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
02840 
02841     EnterCriticalSection(&This->cs);
02842 
02843     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
02844 
02845     if (hr == S_OK)
02846         hr = IBasicAudio_GetIDsOfNames(pBasicAudio, riid, rgszNames, cNames, lcid, rgDispId);
02847 
02848     LeaveCriticalSection(&This->cs);
02849 
02850     return hr;
02851 }
02852 
02853 static HRESULT WINAPI BasicAudio_Invoke(IBasicAudio *iface,
02854                     DISPID dispIdMember,
02855                     REFIID riid,
02856                     LCID lcid,
02857                     WORD wFlags,
02858                     DISPPARAMS*pDispParams,
02859                     VARIANT*pVarResult,
02860                     EXCEPINFO*pExepInfo,
02861                     UINT*puArgErr) {
02862     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
02863     IBasicAudio* pBasicAudio;
02864     HRESULT hr;
02865 
02866     TRACE("(%p/%p)->(%d, %s (%p), %d, %04x, %p, %p, %p, %p)\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
02867 
02868     EnterCriticalSection(&This->cs);
02869 
02870     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
02871 
02872     if (hr == S_OK)
02873         hr = IBasicAudio_Invoke(pBasicAudio, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
02874 
02875     LeaveCriticalSection(&This->cs);
02876 
02877     return hr;
02878 }
02879 
02880 /*** IBasicAudio methods ***/
02881 static HRESULT WINAPI BasicAudio_put_Volume(IBasicAudio *iface,
02882                                             LONG lVolume) {
02883     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
02884     IBasicAudio* pBasicAudio;
02885     HRESULT hr;
02886 
02887     TRACE("(%p/%p)->(%d)\n", This, iface, lVolume);
02888 
02889     EnterCriticalSection(&This->cs);
02890 
02891     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
02892 
02893     if (hr == S_OK)
02894         hr = IBasicAudio_put_Volume(pBasicAudio, lVolume);
02895 
02896     LeaveCriticalSection(&This->cs);
02897 
02898     return hr;
02899 }
02900 
02901 static HRESULT WINAPI BasicAudio_get_Volume(IBasicAudio *iface,
02902                                             LONG *plVolume) {
02903     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
02904     IBasicAudio* pBasicAudio;
02905     HRESULT hr;
02906 
02907     TRACE("(%p/%p)->(%p)\n", This, iface, plVolume);
02908 
02909     EnterCriticalSection(&This->cs);
02910 
02911     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
02912 
02913     if (hr == S_OK)
02914         hr = IBasicAudio_get_Volume(pBasicAudio, plVolume);
02915 
02916     LeaveCriticalSection(&This->cs);
02917 
02918     return hr;
02919 }
02920 
02921 static HRESULT WINAPI BasicAudio_put_Balance(IBasicAudio *iface,
02922                                              LONG lBalance) {
02923     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
02924     IBasicAudio* pBasicAudio;
02925     HRESULT hr;
02926 
02927     TRACE("(%p/%p)->(%d)\n", This, iface, lBalance);
02928 
02929     EnterCriticalSection(&This->cs);
02930 
02931     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
02932 
02933     if (hr == S_OK)
02934         hr = IBasicAudio_put_Balance(pBasicAudio, lBalance);
02935 
02936     LeaveCriticalSection(&This->cs);
02937 
02938     return hr;
02939 }
02940 
02941 static HRESULT WINAPI BasicAudio_get_Balance(IBasicAudio *iface,
02942                                              LONG *plBalance) {
02943     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicAudio_vtbl, iface);
02944     IBasicAudio* pBasicAudio;
02945     HRESULT hr;
02946 
02947     TRACE("(%p/%p)->(%p)\n", This, iface, plBalance);
02948 
02949     EnterCriticalSection(&This->cs);
02950 
02951     hr = GetTargetInterface(This, &IID_IBasicAudio, (LPVOID*)&pBasicAudio);
02952 
02953     if (hr == S_OK)
02954         hr = IBasicAudio_get_Balance(pBasicAudio, plBalance);
02955 
02956     LeaveCriticalSection(&This->cs);
02957 
02958     return hr;
02959 }
02960 
02961 static const IBasicAudioVtbl IBasicAudio_VTable =
02962 {
02963     BasicAudio_QueryInterface,
02964     BasicAudio_AddRef,
02965     BasicAudio_Release,
02966     BasicAudio_GetTypeInfoCount,
02967     BasicAudio_GetTypeInfo,
02968     BasicAudio_GetIDsOfNames,
02969     BasicAudio_Invoke,
02970     BasicAudio_put_Volume,
02971     BasicAudio_get_Volume,
02972     BasicAudio_put_Balance,
02973     BasicAudio_get_Balance
02974 };
02975 
02976 /*** IUnknown methods ***/
02977 static HRESULT WINAPI BasicVideo_QueryInterface(IBasicVideo2 *iface,
02978                         REFIID riid,
02979                         LPVOID*ppvObj) {
02980     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
02981 
02982     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
02983 
02984     return Filtergraph_QueryInterface(This, riid, ppvObj);
02985 }
02986 
02987 static ULONG WINAPI BasicVideo_AddRef(IBasicVideo2 *iface) {
02988     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
02989 
02990     TRACE("(%p/%p)->()\n", This, iface);
02991 
02992     return Filtergraph_AddRef(This);
02993 }
02994 
02995 static ULONG WINAPI BasicVideo_Release(IBasicVideo2 *iface) {
02996     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
02997 
02998     TRACE("(%p/%p)->()\n", This, iface);
02999 
03000     return Filtergraph_Release(This);
03001 }
03002 
03003 /*** IDispatch methods ***/
03004 static HRESULT WINAPI BasicVideo_GetTypeInfoCount(IBasicVideo2 *iface,
03005                           UINT*pctinfo) {
03006     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03007     IBasicVideo* pBasicVideo;
03008     HRESULT hr;
03009 
03010     TRACE("(%p/%p)->(%p)\n", This, iface, pctinfo);
03011 
03012     EnterCriticalSection(&This->cs);
03013 
03014     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03015 
03016     if (hr == S_OK)
03017         hr = IBasicVideo_GetTypeInfoCount(pBasicVideo, pctinfo);
03018 
03019     LeaveCriticalSection(&This->cs);
03020 
03021     return hr;
03022 }
03023 
03024 static HRESULT WINAPI BasicVideo_GetTypeInfo(IBasicVideo2 *iface,
03025                          UINT iTInfo,
03026                          LCID lcid,
03027                          ITypeInfo**ppTInfo) {
03028     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03029     IBasicVideo* pBasicVideo;
03030     HRESULT hr;
03031 
03032     TRACE("(%p/%p)->(%d, %d, %p)\n", This, iface, iTInfo, lcid, ppTInfo);
03033 
03034     EnterCriticalSection(&This->cs);
03035 
03036     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03037 
03038     if (hr == S_OK)
03039         hr = IBasicVideo_GetTypeInfo(pBasicVideo, iTInfo, lcid, ppTInfo);
03040 
03041     LeaveCriticalSection(&This->cs);
03042 
03043     return hr;
03044 }
03045 
03046 static HRESULT WINAPI BasicVideo_GetIDsOfNames(IBasicVideo2 *iface,
03047                            REFIID riid,
03048                            LPOLESTR*rgszNames,
03049                            UINT cNames,
03050                            LCID lcid,
03051                            DISPID*rgDispId) {
03052     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03053     IBasicVideo* pBasicVideo;
03054     HRESULT hr;
03055 
03056     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p)\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
03057 
03058     EnterCriticalSection(&This->cs);
03059 
03060     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03061 
03062     if (hr == S_OK)
03063         hr = IBasicVideo_GetIDsOfNames(pBasicVideo, riid, rgszNames, cNames, lcid, rgDispId);
03064 
03065     LeaveCriticalSection(&This->cs);
03066 
03067     return hr;
03068 }
03069 
03070 static HRESULT WINAPI BasicVideo_Invoke(IBasicVideo2 *iface,
03071                     DISPID dispIdMember,
03072                     REFIID riid,
03073                     LCID lcid,
03074                     WORD wFlags,
03075                     DISPPARAMS*pDispParams,
03076                     VARIANT*pVarResult,
03077                     EXCEPINFO*pExepInfo,
03078                     UINT*puArgErr) {
03079     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03080     IBasicVideo* pBasicVideo;
03081     HRESULT hr;
03082 
03083     TRACE("(%p/%p)->(%d, %s (%p), %d, %04x, %p, %p, %p, %p)\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
03084 
03085     EnterCriticalSection(&This->cs);
03086 
03087     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03088 
03089     if (hr == S_OK)
03090         hr = IBasicVideo_Invoke(pBasicVideo, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
03091 
03092     LeaveCriticalSection(&This->cs);
03093 
03094     return hr;
03095 }
03096 
03097 /*** IBasicVideo methods ***/
03098 static HRESULT WINAPI BasicVideo_get_AvgTimePerFrame(IBasicVideo2 *iface,
03099                              REFTIME *pAvgTimePerFrame) {
03100     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03101     IBasicVideo* pBasicVideo;
03102     HRESULT hr;
03103 
03104     TRACE("(%p/%p)->(%p)\n", This, iface, pAvgTimePerFrame);
03105 
03106     EnterCriticalSection(&This->cs);
03107 
03108     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03109 
03110     if (hr == S_OK)
03111         hr = IBasicVideo_get_AvgTimePerFrame(pBasicVideo, pAvgTimePerFrame);
03112 
03113     LeaveCriticalSection(&This->cs);
03114 
03115     return hr;
03116 }
03117 
03118 static HRESULT WINAPI BasicVideo_get_BitRate(IBasicVideo2 *iface,
03119                                              LONG *pBitRate) {
03120     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03121     IBasicVideo* pBasicVideo;
03122     HRESULT hr;
03123 
03124     TRACE("(%p/%p)->(%p)\n", This, iface, pBitRate);
03125 
03126     EnterCriticalSection(&This->cs);
03127 
03128     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03129 
03130     if (hr == S_OK)
03131         hr = IBasicVideo_get_BitRate(pBasicVideo, pBitRate);
03132 
03133     LeaveCriticalSection(&This->cs);
03134 
03135     return hr;
03136 }
03137 
03138 static HRESULT WINAPI BasicVideo_get_BitErrorRate(IBasicVideo2 *iface,
03139                                                   LONG *pBitErrorRate) {
03140     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03141     IBasicVideo* pBasicVideo;
03142     HRESULT hr;
03143 
03144     TRACE("(%p/%p)->(%p)\n", This, iface, pBitErrorRate);
03145 
03146     EnterCriticalSection(&This->cs);
03147 
03148     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03149 
03150     if (hr == S_OK)
03151         hr = IBasicVideo_get_BitErrorRate(pBasicVideo, pBitErrorRate);
03152 
03153     LeaveCriticalSection(&This->cs);
03154 
03155     return hr;
03156 }
03157 
03158 static HRESULT WINAPI BasicVideo_get_VideoWidth(IBasicVideo2 *iface,
03159                                                 LONG *pVideoWidth) {
03160     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03161     IBasicVideo* pBasicVideo;
03162     HRESULT hr;
03163 
03164     TRACE("(%p/%p)->(%p)\n", This, iface, pVideoWidth);
03165 
03166     EnterCriticalSection(&This->cs);
03167 
03168     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03169 
03170     if (hr == S_OK)
03171         hr = IBasicVideo_get_VideoWidth(pBasicVideo, pVideoWidth);
03172 
03173     LeaveCriticalSection(&This->cs);
03174 
03175     return hr;
03176 }
03177 
03178 static HRESULT WINAPI BasicVideo_get_VideoHeight(IBasicVideo2 *iface,
03179                                                  LONG *pVideoHeight) {
03180     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03181     IBasicVideo* pBasicVideo;
03182     HRESULT hr;
03183 
03184     TRACE("(%p/%p)->(%p)\n", This, iface, pVideoHeight);
03185 
03186     EnterCriticalSection(&This->cs);
03187 
03188     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03189 
03190     if (hr == S_OK)
03191         hr = IBasicVideo_get_VideoHeight(pBasicVideo, pVideoHeight);
03192 
03193     LeaveCriticalSection(&This->cs);
03194 
03195     return hr;
03196 }
03197 
03198 static HRESULT WINAPI BasicVideo_put_SourceLeft(IBasicVideo2 *iface,
03199                                                 LONG SourceLeft) {
03200     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03201     IBasicVideo* pBasicVideo;
03202     HRESULT hr;
03203 
03204     TRACE("(%p/%p)->(%d)\n", This, iface, SourceLeft);
03205 
03206     EnterCriticalSection(&This->cs);
03207 
03208     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03209 
03210     if (hr == S_OK)
03211         hr = IBasicVideo_put_SourceLeft(pBasicVideo, SourceLeft);
03212 
03213     LeaveCriticalSection(&This->cs);
03214 
03215     return hr;
03216 }
03217 
03218 static HRESULT WINAPI BasicVideo_get_SourceLeft(IBasicVideo2 *iface,
03219                                                 LONG *pSourceLeft) {
03220     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03221     IBasicVideo* pBasicVideo;
03222     HRESULT hr;
03223 
03224     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceLeft);
03225 
03226     EnterCriticalSection(&This->cs);
03227 
03228     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03229 
03230     if (hr == S_OK)
03231         hr = IBasicVideo_get_SourceLeft(pBasicVideo, pSourceLeft);
03232 
03233     LeaveCriticalSection(&This->cs);
03234 
03235     return hr;
03236 }
03237 
03238 static HRESULT WINAPI BasicVideo_put_SourceWidth(IBasicVideo2 *iface,
03239                                                  LONG SourceWidth) {
03240     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03241     IBasicVideo* pBasicVideo;
03242     HRESULT hr;
03243 
03244     TRACE("(%p/%p)->(%d)\n", This, iface, SourceWidth);
03245 
03246     EnterCriticalSection(&This->cs);
03247 
03248     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03249 
03250     if (hr == S_OK)
03251         hr = IBasicVideo_put_SourceWidth(pBasicVideo, SourceWidth);
03252 
03253     LeaveCriticalSection(&This->cs);
03254 
03255     return hr;
03256 }
03257 
03258 static HRESULT WINAPI BasicVideo_get_SourceWidth(IBasicVideo2 *iface,
03259                                                  LONG *pSourceWidth) {
03260     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03261     IBasicVideo* pBasicVideo;
03262     HRESULT hr;
03263 
03264     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceWidth);
03265 
03266     EnterCriticalSection(&This->cs);
03267 
03268     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03269 
03270     if (hr == S_OK)
03271         hr = IBasicVideo_get_SourceWidth(pBasicVideo, pSourceWidth);
03272 
03273     LeaveCriticalSection(&This->cs);
03274 
03275     return hr;
03276 }
03277 
03278 static HRESULT WINAPI BasicVideo_put_SourceTop(IBasicVideo2 *iface,
03279                                                LONG SourceTop) {
03280     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03281     IBasicVideo* pBasicVideo;
03282     HRESULT hr;
03283 
03284     TRACE("(%p/%p)->(%d)\n", This, iface, SourceTop);
03285 
03286     EnterCriticalSection(&This->cs);
03287 
03288     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03289 
03290     if (hr == S_OK)
03291         hr = IBasicVideo_put_SourceTop(pBasicVideo, SourceTop);
03292 
03293     LeaveCriticalSection(&This->cs);
03294 
03295     return hr;
03296 }
03297 
03298 static HRESULT WINAPI BasicVideo_get_SourceTop(IBasicVideo2 *iface,
03299                                                LONG *pSourceTop) {
03300     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03301     IBasicVideo* pBasicVideo;
03302     HRESULT hr;
03303 
03304     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceTop);
03305 
03306     EnterCriticalSection(&This->cs);
03307 
03308     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03309 
03310     if (hr == S_OK)
03311         hr = IBasicVideo_get_SourceTop(pBasicVideo, pSourceTop);
03312 
03313     LeaveCriticalSection(&This->cs);
03314 
03315     return hr;
03316 }
03317 
03318 static HRESULT WINAPI BasicVideo_put_SourceHeight(IBasicVideo2 *iface,
03319                                                   LONG SourceHeight) {
03320     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03321     IBasicVideo* pBasicVideo;
03322     HRESULT hr;
03323 
03324     TRACE("(%p/%p)->(%d)\n", This, iface, SourceHeight);
03325 
03326     EnterCriticalSection(&This->cs);
03327 
03328     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03329 
03330     if (hr == S_OK)
03331         hr = IBasicVideo_put_SourceHeight(pBasicVideo, SourceHeight);
03332 
03333     LeaveCriticalSection(&This->cs);
03334 
03335     return hr;
03336 }
03337 
03338 static HRESULT WINAPI BasicVideo_get_SourceHeight(IBasicVideo2 *iface,
03339                                                   LONG *pSourceHeight) {
03340     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03341     IBasicVideo* pBasicVideo;
03342     HRESULT hr;
03343 
03344     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceHeight);
03345 
03346     EnterCriticalSection(&This->cs);
03347 
03348     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03349 
03350     if (hr == S_OK)
03351         hr = IBasicVideo_get_SourceHeight(pBasicVideo, pSourceHeight);
03352 
03353     LeaveCriticalSection(&This->cs);
03354 
03355     return hr;
03356 }
03357 
03358 static HRESULT WINAPI BasicVideo_put_DestinationLeft(IBasicVideo2 *iface,
03359                                                      LONG DestinationLeft) {
03360     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03361     IBasicVideo* pBasicVideo;
03362     HRESULT hr;
03363 
03364     TRACE("(%p/%p)->(%d)\n", This, iface, DestinationLeft);
03365 
03366     EnterCriticalSection(&This->cs);
03367 
03368     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03369 
03370     if (hr == S_OK)
03371         hr = IBasicVideo_put_DestinationLeft(pBasicVideo, DestinationLeft);
03372 
03373     LeaveCriticalSection(&This->cs);
03374 
03375     return hr;
03376 }
03377 
03378 static HRESULT WINAPI BasicVideo_get_DestinationLeft(IBasicVideo2 *iface,
03379                                                      LONG *pDestinationLeft) {
03380     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03381     IBasicVideo* pBasicVideo;
03382     HRESULT hr;
03383 
03384     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationLeft);
03385 
03386     EnterCriticalSection(&This->cs);
03387 
03388     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03389 
03390     if (hr == S_OK)
03391         hr = IBasicVideo_get_DestinationLeft(pBasicVideo, pDestinationLeft);
03392 
03393     LeaveCriticalSection(&This->cs);
03394 
03395     return hr;
03396 }
03397 
03398 static HRESULT WINAPI BasicVideo_put_DestinationWidth(IBasicVideo2 *iface,
03399                                                       LONG DestinationWidth) {
03400     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03401     IBasicVideo* pBasicVideo;
03402     HRESULT hr;
03403 
03404     TRACE("(%p/%p)->(%d)\n", This, iface, DestinationWidth);
03405 
03406     EnterCriticalSection(&This->cs);
03407 
03408     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03409 
03410     if (hr == S_OK)
03411         hr = IBasicVideo_put_DestinationWidth(pBasicVideo, DestinationWidth);
03412 
03413     LeaveCriticalSection(&This->cs);
03414 
03415     return hr;
03416 }
03417 
03418 static HRESULT WINAPI BasicVideo_get_DestinationWidth(IBasicVideo2 *iface,
03419                                                       LONG *pDestinationWidth) {
03420     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03421     IBasicVideo* pBasicVideo;
03422     HRESULT hr;
03423 
03424     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationWidth);
03425 
03426     EnterCriticalSection(&This->cs);
03427 
03428     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03429 
03430     if (hr == S_OK)
03431         hr = IBasicVideo_get_DestinationWidth(pBasicVideo, pDestinationWidth);
03432 
03433     LeaveCriticalSection(&This->cs);
03434 
03435     return hr;
03436 }
03437 
03438 static HRESULT WINAPI BasicVideo_put_DestinationTop(IBasicVideo2 *iface,
03439                                                     LONG DestinationTop) {
03440     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03441     IBasicVideo* pBasicVideo;
03442     HRESULT hr;
03443 
03444     TRACE("(%p/%p)->(%d)\n", This, iface, DestinationTop);
03445 
03446     EnterCriticalSection(&This->cs);
03447 
03448     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03449 
03450     if (hr == S_OK)
03451         hr = IBasicVideo_put_DestinationTop(pBasicVideo, DestinationTop);
03452 
03453     LeaveCriticalSection(&This->cs);
03454 
03455     return hr;
03456 }
03457 
03458 static HRESULT WINAPI BasicVideo_get_DestinationTop(IBasicVideo2 *iface,
03459                                                     LONG *pDestinationTop) {
03460     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03461     IBasicVideo* pBasicVideo;
03462     HRESULT hr;
03463 
03464     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationTop);
03465 
03466     EnterCriticalSection(&This->cs);
03467 
03468     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03469 
03470     if (hr == S_OK)
03471         hr = IBasicVideo_get_DestinationTop(pBasicVideo, pDestinationTop);
03472 
03473     LeaveCriticalSection(&This->cs);
03474 
03475     return hr;
03476 }
03477 
03478 static HRESULT WINAPI BasicVideo_put_DestinationHeight(IBasicVideo2 *iface,
03479                                                        LONG DestinationHeight) {
03480     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03481     IBasicVideo* pBasicVideo;
03482     HRESULT hr;
03483 
03484     TRACE("(%p/%p)->(%d)\n", This, iface, DestinationHeight);
03485 
03486     EnterCriticalSection(&This->cs);
03487 
03488     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03489 
03490     if (hr == S_OK)
03491         hr = IBasicVideo_put_DestinationHeight(pBasicVideo, DestinationHeight);
03492 
03493     LeaveCriticalSection(&This->cs);
03494 
03495     return hr;
03496 }
03497 
03498 static HRESULT WINAPI BasicVideo_get_DestinationHeight(IBasicVideo2 *iface,
03499                                                        LONG *pDestinationHeight) {
03500     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03501     IBasicVideo* pBasicVideo;
03502     HRESULT hr;
03503 
03504     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationHeight);
03505 
03506     EnterCriticalSection(&This->cs);
03507 
03508     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03509 
03510     if (hr == S_OK)
03511         hr = IBasicVideo_get_DestinationHeight(pBasicVideo, pDestinationHeight);
03512 
03513     LeaveCriticalSection(&This->cs);
03514 
03515     return hr;
03516 }
03517 
03518 static HRESULT WINAPI BasicVideo_SetSourcePosition(IBasicVideo2 *iface,
03519                                                    LONG Left,
03520                                                    LONG Top,
03521                                                    LONG Width,
03522                                                    LONG Height) {
03523     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03524     IBasicVideo* pBasicVideo;
03525     HRESULT hr;
03526 
03527     TRACE("(%p/%p)->(%d, %d, %d, %d)\n", This, iface, Left, Top, Width, Height);
03528 
03529     EnterCriticalSection(&This->cs);
03530 
03531     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03532 
03533     if (hr == S_OK)
03534         hr = IBasicVideo_SetSourcePosition(pBasicVideo, Left, Top, Width, Height);
03535 
03536     LeaveCriticalSection(&This->cs);
03537 
03538     return hr;
03539 }
03540 
03541 static HRESULT WINAPI BasicVideo_GetSourcePosition(IBasicVideo2 *iface,
03542                                                    LONG *pLeft,
03543                                                    LONG *pTop,
03544                                                    LONG *pWidth,
03545                                                    LONG *pHeight) {
03546     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03547     IBasicVideo* pBasicVideo;
03548     HRESULT hr;
03549 
03550     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
03551 
03552     EnterCriticalSection(&This->cs);
03553 
03554     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03555 
03556     if (hr == S_OK)
03557         hr = IBasicVideo_GetSourcePosition(pBasicVideo, pLeft, pTop, pWidth, pHeight);
03558 
03559     LeaveCriticalSection(&This->cs);
03560 
03561     return hr;
03562 }
03563 
03564 static HRESULT WINAPI BasicVideo_SetDefaultSourcePosition(IBasicVideo2 *iface) {
03565     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03566     IBasicVideo* pBasicVideo;
03567     HRESULT hr;
03568 
03569     TRACE("(%p/%p)->()\n", This, iface);
03570 
03571     EnterCriticalSection(&This->cs);
03572 
03573     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03574 
03575     if (hr == S_OK)
03576         hr = IBasicVideo_SetDefaultSourcePosition(pBasicVideo);
03577 
03578     LeaveCriticalSection(&This->cs);
03579 
03580     return hr;
03581 }
03582 
03583 static HRESULT WINAPI BasicVideo_SetDestinationPosition(IBasicVideo2 *iface,
03584                                                         LONG Left,
03585                                                         LONG Top,
03586                                                         LONG Width,
03587                                                         LONG Height) {
03588     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03589     IBasicVideo* pBasicVideo;
03590     HRESULT hr;
03591 
03592     TRACE("(%p/%p)->(%d, %d, %d, %d)\n", This, iface, Left, Top, Width, Height);
03593 
03594     EnterCriticalSection(&This->cs);
03595 
03596     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03597 
03598     if (hr == S_OK)
03599         hr = IBasicVideo_SetDestinationPosition(pBasicVideo, Left, Top, Width, Height);
03600 
03601     LeaveCriticalSection(&This->cs);
03602 
03603     return hr;
03604 }
03605 
03606 static HRESULT WINAPI BasicVideo_GetDestinationPosition(IBasicVideo2 *iface,
03607                                                         LONG *pLeft,
03608                                                         LONG *pTop,
03609                                                         LONG *pWidth,
03610                                                         LONG *pHeight) {
03611     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03612     IBasicVideo* pBasicVideo;
03613     HRESULT hr;
03614 
03615     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
03616 
03617     EnterCriticalSection(&This->cs);
03618 
03619     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03620 
03621     if (hr == S_OK)
03622         hr = IBasicVideo_GetDestinationPosition(pBasicVideo, pLeft, pTop, pWidth, pHeight);
03623 
03624     LeaveCriticalSection(&This->cs);
03625 
03626     return hr;
03627 }
03628 
03629 static HRESULT WINAPI BasicVideo_SetDefaultDestinationPosition(IBasicVideo2 *iface) {
03630     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03631     IBasicVideo* pBasicVideo;
03632     HRESULT hr;
03633 
03634     TRACE("(%p/%p)->()\n", This, iface);
03635 
03636     EnterCriticalSection(&This->cs);
03637 
03638     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03639 
03640     if (hr == S_OK)
03641         hr = IBasicVideo_SetDefaultDestinationPosition(pBasicVideo);
03642 
03643     LeaveCriticalSection(&This->cs);
03644 
03645     return hr;
03646 }
03647 
03648 static HRESULT WINAPI BasicVideo_GetVideoSize(IBasicVideo2 *iface,
03649                                               LONG *pWidth,
03650                                               LONG *pHeight) {
03651     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03652     IBasicVideo* pBasicVideo;
03653     HRESULT hr;
03654 
03655     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
03656 
03657     EnterCriticalSection(&This->cs);
03658 
03659     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03660 
03661     if (hr == S_OK)
03662         hr = IBasicVideo_GetVideoSize(pBasicVideo, pWidth, pHeight);
03663 
03664     LeaveCriticalSection(&This->cs);
03665 
03666     return hr;
03667 }
03668 
03669 static HRESULT WINAPI BasicVideo_GetVideoPaletteEntries(IBasicVideo2 *iface,
03670                                                         LONG StartIndex,
03671                                                         LONG Entries,
03672                                                         LONG *pRetrieved,
03673                                                         LONG *pPalette) {
03674     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03675     IBasicVideo* pBasicVideo;
03676     HRESULT hr;
03677 
03678     TRACE("(%p/%p)->(%d, %d, %p, %p)\n", This, iface, StartIndex, Entries, pRetrieved, pPalette);
03679 
03680     EnterCriticalSection(&This->cs);
03681 
03682     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03683 
03684     if (hr == S_OK)
03685         hr = IBasicVideo_GetVideoPaletteEntries(pBasicVideo, StartIndex, Entries, pRetrieved, pPalette);
03686 
03687     LeaveCriticalSection(&This->cs);
03688 
03689     return hr;
03690 }
03691 
03692 static HRESULT WINAPI BasicVideo_GetCurrentImage(IBasicVideo2 *iface,
03693                                                  LONG *pBufferSize,
03694                                                  LONG *pDIBImage) {
03695     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03696     IBasicVideo* pBasicVideo;
03697     HRESULT hr;
03698 
03699     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pBufferSize, pDIBImage);
03700 
03701     EnterCriticalSection(&This->cs);
03702 
03703     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03704 
03705     if (hr == S_OK)
03706         hr = IBasicVideo_GetCurrentImage(pBasicVideo, pBufferSize, pDIBImage);
03707 
03708     LeaveCriticalSection(&This->cs);
03709 
03710     return hr;
03711 }
03712 
03713 static HRESULT WINAPI BasicVideo_IsUsingDefaultSource(IBasicVideo2 *iface) {
03714     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03715     IBasicVideo* pBasicVideo;
03716     HRESULT hr;
03717 
03718     TRACE("(%p/%p)->()\n", This, iface);
03719 
03720     EnterCriticalSection(&This->cs);
03721 
03722     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03723 
03724     if (hr == S_OK)
03725         hr = IBasicVideo_IsUsingDefaultSource(pBasicVideo);
03726 
03727     LeaveCriticalSection(&This->cs);
03728 
03729     return hr;
03730 }
03731 
03732 static HRESULT WINAPI BasicVideo_IsUsingDefaultDestination(IBasicVideo2 *iface) {
03733     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03734     IBasicVideo* pBasicVideo;
03735     HRESULT hr;
03736 
03737     TRACE("(%p/%p)->()\n", This, iface);
03738 
03739     EnterCriticalSection(&This->cs);
03740 
03741     hr = GetTargetInterface(This, &IID_IBasicVideo, (LPVOID*)&pBasicVideo);
03742 
03743     if (hr == S_OK)
03744         hr = IBasicVideo_IsUsingDefaultDestination(pBasicVideo);
03745 
03746     LeaveCriticalSection(&This->cs);
03747 
03748     return hr;
03749 }
03750 
03751 static HRESULT WINAPI BasicVideo2_GetPreferredAspectRatio(IBasicVideo2 *iface, LONG *plAspectX, LONG *plAspectY) {
03752     ICOM_THIS_MULTI(IFilterGraphImpl, IBasicVideo_vtbl, iface);
03753     IBasicVideo2 *pBasicVideo2;
03754     HRESULT hr;
03755 
03756     TRACE("(%p/%p)->()\n", This, iface);
03757 
03758     EnterCriticalSection(&This->cs);
03759 
03760     hr = GetTargetInterface(This, &IID_IBasicVideo2, (LPVOID*)&pBasicVideo2);
03761 
03762     if (hr == S_OK)
03763         hr = BasicVideo2_GetPreferredAspectRatio(iface, plAspectX, plAspectY);
03764 
03765     LeaveCriticalSection(&This->cs);
03766 
03767     return hr;
03768 }
03769 
03770 static const IBasicVideo2Vtbl IBasicVideo_VTable =
03771 {
03772     BasicVideo_QueryInterface,
03773     BasicVideo_AddRef,
03774     BasicVideo_Release,
03775     BasicVideo_GetTypeInfoCount,
03776     BasicVideo_GetTypeInfo,
03777     BasicVideo_GetIDsOfNames,
03778     BasicVideo_Invoke,
03779     BasicVideo_get_AvgTimePerFrame,
03780     BasicVideo_get_BitRate,
03781     BasicVideo_get_BitErrorRate,
03782     BasicVideo_get_VideoWidth,
03783     BasicVideo_get_VideoHeight,
03784     BasicVideo_put_SourceLeft,
03785     BasicVideo_get_SourceLeft,
03786     BasicVideo_put_SourceWidth,
03787     BasicVideo_get_SourceWidth,
03788     BasicVideo_put_SourceTop,
03789     BasicVideo_get_SourceTop,
03790     BasicVideo_put_SourceHeight,
03791     BasicVideo_get_SourceHeight,
03792     BasicVideo_put_DestinationLeft,
03793     BasicVideo_get_DestinationLeft,
03794     BasicVideo_put_DestinationWidth,
03795     BasicVideo_get_DestinationWidth,
03796     BasicVideo_put_DestinationTop,
03797     BasicVideo_get_DestinationTop,
03798     BasicVideo_put_DestinationHeight,
03799     BasicVideo_get_DestinationHeight,
03800     BasicVideo_SetSourcePosition,
03801     BasicVideo_GetSourcePosition,
03802     BasicVideo_SetDefaultSourcePosition,
03803     BasicVideo_SetDestinationPosition,
03804     BasicVideo_GetDestinationPosition,
03805     BasicVideo_SetDefaultDestinationPosition,
03806     BasicVideo_GetVideoSize,
03807     BasicVideo_GetVideoPaletteEntries,
03808     BasicVideo_GetCurrentImage,
03809     BasicVideo_IsUsingDefaultSource,
03810     BasicVideo_IsUsingDefaultDestination,
03811     BasicVideo2_GetPreferredAspectRatio
03812 };
03813 
03814 
03815 /*** IUnknown methods ***/
03816 static HRESULT WINAPI VideoWindow_QueryInterface(IVideoWindow *iface,
03817                          REFIID riid,
03818                          LPVOID*ppvObj) {
03819     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
03820 
03821     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
03822 
03823     return Filtergraph_QueryInterface(This, riid, ppvObj);
03824 }
03825 
03826 static ULONG WINAPI VideoWindow_AddRef(IVideoWindow *iface) {
03827     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
03828 
03829     TRACE("(%p/%p)->()\n", This, iface);
03830 
03831     return Filtergraph_AddRef(This);
03832 }
03833 
03834 static ULONG WINAPI VideoWindow_Release(IVideoWindow *iface) {
03835     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
03836 
03837     TRACE("(%p/%p)->()\n", This, iface);
03838 
03839     return Filtergraph_Release(This);
03840 }
03841 
03842 /*** IDispatch methods ***/
03843 static HRESULT WINAPI VideoWindow_GetTypeInfoCount(IVideoWindow *iface,
03844                            UINT*pctinfo) {
03845     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
03846     IVideoWindow* pVideoWindow;
03847     HRESULT hr;
03848 
03849     TRACE("(%p/%p)->(%p)\n", This, iface, pctinfo);
03850 
03851     EnterCriticalSection(&This->cs);
03852 
03853     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
03854 
03855     if (hr == S_OK)
03856         hr = IVideoWindow_GetTypeInfoCount(pVideoWindow, pctinfo);
03857 
03858     LeaveCriticalSection(&This->cs);
03859 
03860     return hr;
03861 }
03862 
03863 static HRESULT WINAPI VideoWindow_GetTypeInfo(IVideoWindow *iface,
03864                           UINT iTInfo,
03865                           LCID lcid,
03866                           ITypeInfo**ppTInfo) {
03867     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
03868     IVideoWindow* pVideoWindow;
03869     HRESULT hr;
03870 
03871     TRACE("(%p/%p)->(%d, %d, %p)\n", This, iface, iTInfo, lcid, ppTInfo);
03872 
03873     EnterCriticalSection(&This->cs);
03874 
03875     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
03876 
03877     if (hr == S_OK)
03878         hr = IVideoWindow_GetTypeInfo(pVideoWindow, iTInfo, lcid, ppTInfo);
03879 
03880     LeaveCriticalSection(&This->cs);
03881 
03882     return hr;
03883 }
03884 
03885 static HRESULT WINAPI VideoWindow_GetIDsOfNames(IVideoWindow *iface,
03886                         REFIID riid,
03887                         LPOLESTR*rgszNames,
03888                         UINT cNames,
03889                         LCID lcid,
03890                         DISPID*rgDispId) {
03891     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
03892     IVideoWindow* pVideoWindow;
03893     HRESULT hr;
03894 
03895     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p)\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
03896 
03897     EnterCriticalSection(&This->cs);
03898 
03899     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
03900 
03901     if (hr == S_OK)
03902         hr = IVideoWindow_GetIDsOfNames(pVideoWindow, riid, rgszNames, cNames, lcid, rgDispId);
03903 
03904     LeaveCriticalSection(&This->cs);
03905 
03906     return hr;
03907 }
03908 
03909 static HRESULT WINAPI VideoWindow_Invoke(IVideoWindow *iface,
03910                      DISPID dispIdMember,
03911                      REFIID riid,
03912                      LCID lcid,
03913                      WORD wFlags,
03914                      DISPPARAMS*pDispParams,
03915                      VARIANT*pVarResult,
03916                      EXCEPINFO*pExepInfo,
03917                      UINT*puArgErr) {
03918     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
03919     IVideoWindow* pVideoWindow;
03920     HRESULT hr;
03921 
03922     TRACE("(%p/%p)->(%d, %s (%p), %d, %04x, %p, %p, %p, %p)\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
03923 
03924     EnterCriticalSection(&This->cs);
03925 
03926     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
03927 
03928     if (hr == S_OK)
03929         hr = IVideoWindow_Invoke(pVideoWindow, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
03930 
03931     LeaveCriticalSection(&This->cs);
03932 
03933     return hr;
03934 }
03935 
03936 
03937 /*** IVideoWindow methods ***/
03938 static HRESULT WINAPI VideoWindow_put_Caption(IVideoWindow *iface,
03939                           BSTR strCaption) {
03940     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
03941     IVideoWindow* pVideoWindow;
03942     HRESULT hr;
03943     
03944     TRACE("(%p/%p)->(%s (%p))\n", This, iface, debugstr_w(strCaption), strCaption);
03945 
03946     EnterCriticalSection(&This->cs);
03947 
03948     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
03949 
03950     if (hr == S_OK)
03951         hr = IVideoWindow_put_Caption(pVideoWindow, strCaption);
03952 
03953     LeaveCriticalSection(&This->cs);
03954 
03955     return hr;
03956 }
03957 
03958 static HRESULT WINAPI VideoWindow_get_Caption(IVideoWindow *iface,
03959                           BSTR *strCaption) {
03960     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
03961     IVideoWindow* pVideoWindow;
03962     HRESULT hr;
03963 
03964     TRACE("(%p/%p)->(%p)\n", This, iface, strCaption);
03965 
03966     EnterCriticalSection(&This->cs);
03967 
03968     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
03969 
03970     if (hr == S_OK)
03971         hr = IVideoWindow_get_Caption(pVideoWindow, strCaption);
03972 
03973     LeaveCriticalSection(&This->cs);
03974 
03975     return hr;
03976 }
03977 
03978 static HRESULT WINAPI VideoWindow_put_WindowStyle(IVideoWindow *iface,
03979                                                   LONG WindowStyle) {
03980     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
03981     IVideoWindow* pVideoWindow;
03982     HRESULT hr;
03983 
03984     TRACE("(%p/%p)->(%d)\n", This, iface, WindowStyle);
03985 
03986     EnterCriticalSection(&This->cs);
03987 
03988     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
03989 
03990     if (hr == S_OK)
03991         hr = IVideoWindow_put_WindowStyle(pVideoWindow, WindowStyle);
03992 
03993     LeaveCriticalSection(&This->cs);
03994 
03995     return hr;
03996 }
03997 
03998 static HRESULT WINAPI VideoWindow_get_WindowStyle(IVideoWindow *iface,
03999                                                   LONG *WindowStyle) {
04000     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04001     IVideoWindow* pVideoWindow;
04002     HRESULT hr;
04003 
04004     TRACE("(%p/%p)->(%p)\n", This, iface, WindowStyle);
04005 
04006     EnterCriticalSection(&This->cs);
04007 
04008     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04009 
04010     if (hr == S_OK)
04011         hr = IVideoWindow_get_WindowStyle(pVideoWindow, WindowStyle);
04012 
04013     LeaveCriticalSection(&This->cs);
04014 
04015     return hr;
04016 }
04017 
04018 static HRESULT WINAPI VideoWindow_put_WindowStyleEx(IVideoWindow *iface,
04019                                                     LONG WindowStyleEx) {
04020     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04021     IVideoWindow* pVideoWindow;
04022     HRESULT hr;
04023 
04024     TRACE("(%p/%p)->(%d)\n", This, iface, WindowStyleEx);
04025 
04026     EnterCriticalSection(&This->cs);
04027 
04028     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04029 
04030     if (hr == S_OK)
04031         hr = IVideoWindow_put_WindowStyleEx(pVideoWindow, WindowStyleEx);
04032 
04033     LeaveCriticalSection(&This->cs);
04034 
04035     return hr;
04036 }
04037 
04038 static HRESULT WINAPI VideoWindow_get_WindowStyleEx(IVideoWindow *iface,
04039                                                     LONG *WindowStyleEx) {
04040     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04041     IVideoWindow* pVideoWindow;
04042     HRESULT hr;
04043 
04044     TRACE("(%p/%p)->(%p)\n", This, iface, WindowStyleEx);
04045 
04046     EnterCriticalSection(&This->cs);
04047 
04048     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04049 
04050     if (hr == S_OK)
04051         hr = IVideoWindow_get_WindowStyleEx(pVideoWindow, WindowStyleEx);
04052 
04053     LeaveCriticalSection(&This->cs);
04054 
04055     return hr;
04056 }
04057 
04058 static HRESULT WINAPI VideoWindow_put_AutoShow(IVideoWindow *iface,
04059                                                LONG AutoShow) {
04060     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04061     IVideoWindow* pVideoWindow;
04062     HRESULT hr;
04063 
04064     TRACE("(%p/%p)->(%d)\n", This, iface, AutoShow);
04065 
04066     EnterCriticalSection(&This->cs);
04067 
04068     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04069 
04070     if (hr == S_OK)
04071         hr = IVideoWindow_put_AutoShow(pVideoWindow, AutoShow);
04072 
04073     LeaveCriticalSection(&This->cs);
04074 
04075     return hr;
04076 }
04077 
04078 static HRESULT WINAPI VideoWindow_get_AutoShow(IVideoWindow *iface,
04079                                                LONG *AutoShow) {
04080     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04081     IVideoWindow* pVideoWindow;
04082     HRESULT hr;
04083 
04084     TRACE("(%p/%p)->(%p)\n", This, iface, AutoShow);
04085 
04086     EnterCriticalSection(&This->cs);
04087 
04088     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04089 
04090     if (hr == S_OK)
04091         hr = IVideoWindow_get_AutoShow(pVideoWindow, AutoShow);
04092 
04093     LeaveCriticalSection(&This->cs);
04094 
04095     return hr;
04096 }
04097 
04098 static HRESULT WINAPI VideoWindow_put_WindowState(IVideoWindow *iface,
04099                                                   LONG WindowState) {
04100     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04101     IVideoWindow* pVideoWindow;
04102     HRESULT hr;
04103 
04104     TRACE("(%p/%p)->(%d)\n", This, iface, WindowState);
04105 
04106     EnterCriticalSection(&This->cs);
04107 
04108     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04109 
04110     if (hr == S_OK)
04111         hr = IVideoWindow_put_WindowState(pVideoWindow, WindowState);
04112 
04113     LeaveCriticalSection(&This->cs);
04114 
04115     return hr;
04116 }
04117 
04118 static HRESULT WINAPI VideoWindow_get_WindowState(IVideoWindow *iface,
04119                                                   LONG *WindowState) {
04120     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04121     IVideoWindow* pVideoWindow;
04122     HRESULT hr;
04123 
04124     TRACE("(%p/%p)->(%p)\n", This, iface, WindowState);
04125 
04126     EnterCriticalSection(&This->cs);
04127 
04128     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04129 
04130     if (hr == S_OK)
04131         hr = IVideoWindow_get_WindowState(pVideoWindow, WindowState);
04132 
04133     LeaveCriticalSection(&This->cs);
04134 
04135     return hr;
04136 }
04137 
04138 static HRESULT WINAPI VideoWindow_put_BackgroundPalette(IVideoWindow *iface,
04139                                                         LONG BackgroundPalette) {
04140     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04141     IVideoWindow* pVideoWindow;
04142     HRESULT hr;
04143 
04144     TRACE("(%p/%p)->(%d)\n", This, iface, BackgroundPalette);
04145 
04146     EnterCriticalSection(&This->cs);
04147 
04148     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04149 
04150     if (hr == S_OK)
04151         hr = IVideoWindow_put_BackgroundPalette(pVideoWindow, BackgroundPalette);
04152 
04153     LeaveCriticalSection(&This->cs);
04154 
04155     return hr;
04156 }
04157 
04158 static HRESULT WINAPI VideoWindow_get_BackgroundPalette(IVideoWindow *iface,
04159                                                         LONG *pBackgroundPalette) {
04160     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04161     IVideoWindow* pVideoWindow;
04162     HRESULT hr;
04163 
04164     TRACE("(%p/%p)->(%p)\n", This, iface, pBackgroundPalette);
04165 
04166     EnterCriticalSection(&This->cs);
04167 
04168     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04169 
04170     if (hr == S_OK)
04171         hr = IVideoWindow_get_BackgroundPalette(pVideoWindow, pBackgroundPalette);
04172 
04173     LeaveCriticalSection(&This->cs);
04174 
04175     return hr;
04176 }
04177 
04178 static HRESULT WINAPI VideoWindow_put_Visible(IVideoWindow *iface,
04179                                               LONG Visible) {
04180     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04181     IVideoWindow* pVideoWindow;
04182     HRESULT hr;
04183 
04184     TRACE("(%p/%p)->(%d)\n", This, iface, Visible);
04185 
04186     EnterCriticalSection(&This->cs);
04187 
04188     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04189 
04190     if (hr == S_OK)
04191         hr = IVideoWindow_put_Visible(pVideoWindow, Visible);
04192 
04193     LeaveCriticalSection(&This->cs);
04194 
04195     return hr;
04196 }
04197 
04198 static HRESULT WINAPI VideoWindow_get_Visible(IVideoWindow *iface,
04199                                               LONG *pVisible) {
04200     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04201     IVideoWindow* pVideoWindow;
04202     HRESULT hr;
04203 
04204     TRACE("(%p/%p)->(%p)\n", This, iface, pVisible);
04205 
04206     EnterCriticalSection(&This->cs);
04207 
04208     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04209 
04210     if (hr == S_OK)
04211         hr = IVideoWindow_get_Visible(pVideoWindow, pVisible);
04212 
04213     LeaveCriticalSection(&This->cs);
04214 
04215     return hr;
04216 }
04217 
04218 static HRESULT WINAPI VideoWindow_put_Left(IVideoWindow *iface,
04219                                            LONG Left) {
04220     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04221     IVideoWindow* pVideoWindow;
04222     HRESULT hr;
04223 
04224     TRACE("(%p/%p)->(%d)\n", This, iface, Left);
04225 
04226     EnterCriticalSection(&This->cs);
04227 
04228     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04229 
04230     if (hr == S_OK)
04231         hr = IVideoWindow_put_Left(pVideoWindow, Left);
04232 
04233     LeaveCriticalSection(&This->cs);
04234 
04235     return hr;
04236 }
04237 
04238 static HRESULT WINAPI VideoWindow_get_Left(IVideoWindow *iface,
04239                                            LONG *pLeft) {
04240     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04241     IVideoWindow* pVideoWindow;
04242     HRESULT hr;
04243 
04244     TRACE("(%p/%p)->(%p)\n", This, iface, pLeft);
04245 
04246     EnterCriticalSection(&This->cs);
04247 
04248     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04249 
04250     if (hr == S_OK)
04251         hr = IVideoWindow_get_Left(pVideoWindow, pLeft);
04252 
04253     LeaveCriticalSection(&This->cs);
04254 
04255     return hr;
04256 }
04257 
04258 static HRESULT WINAPI VideoWindow_put_Width(IVideoWindow *iface,
04259                                             LONG Width) {
04260     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04261     IVideoWindow* pVideoWindow;
04262     HRESULT hr;
04263 
04264     TRACE("(%p/%p)->(%d)\n", This, iface, Width);
04265 
04266     EnterCriticalSection(&This->cs);
04267 
04268     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04269 
04270     if (hr == S_OK)
04271         hr = IVideoWindow_put_Width(pVideoWindow, Width);
04272 
04273     LeaveCriticalSection(&This->cs);
04274 
04275     return hr;
04276 }
04277 
04278 static HRESULT WINAPI VideoWindow_get_Width(IVideoWindow *iface,
04279                                             LONG *pWidth) {
04280     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04281     IVideoWindow* pVideoWindow;
04282     HRESULT hr;
04283 
04284     TRACE("(%p/%p)->(%p)\n", This, iface, pWidth);
04285 
04286     EnterCriticalSection(&This->cs);
04287 
04288     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04289 
04290     if (hr == S_OK)
04291         hr = IVideoWindow_get_Width(pVideoWindow, pWidth);
04292 
04293     LeaveCriticalSection(&This->cs);
04294 
04295     return hr;
04296 }
04297 
04298 static HRESULT WINAPI VideoWindow_put_Top(IVideoWindow *iface,
04299                                           LONG Top) {
04300     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04301     IVideoWindow* pVideoWindow;
04302     HRESULT hr;
04303 
04304     TRACE("(%p/%p)->(%d)\n", This, iface, Top);
04305 
04306     EnterCriticalSection(&This->cs);
04307 
04308     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04309 
04310     if (hr == S_OK)
04311         hr = IVideoWindow_put_Top(pVideoWindow, Top);
04312 
04313     LeaveCriticalSection(&This->cs);
04314 
04315     return hr;
04316 }
04317 
04318 static HRESULT WINAPI VideoWindow_get_Top(IVideoWindow *iface,
04319                                           LONG *pTop) {
04320     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04321     IVideoWindow* pVideoWindow;
04322     HRESULT hr;
04323 
04324     TRACE("(%p/%p)->(%p)\n", This, iface, pTop);
04325 
04326     EnterCriticalSection(&This->cs);
04327 
04328     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04329 
04330     if (hr == S_OK)
04331         hr = IVideoWindow_get_Top(pVideoWindow, pTop);
04332 
04333     LeaveCriticalSection(&This->cs);
04334 
04335     return hr;
04336 }
04337 
04338 static HRESULT WINAPI VideoWindow_put_Height(IVideoWindow *iface,
04339                                              LONG Height) {
04340     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04341     IVideoWindow* pVideoWindow;
04342     HRESULT hr;
04343 
04344     TRACE("(%p/%p)->(%d)\n", This, iface, Height);
04345 
04346     EnterCriticalSection(&This->cs);
04347 
04348     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04349 
04350     if (hr == S_OK)
04351         hr = IVideoWindow_put_Height(pVideoWindow, Height);
04352 
04353     LeaveCriticalSection(&This->cs);
04354 
04355     return hr;
04356 }
04357 
04358 static HRESULT WINAPI VideoWindow_get_Height(IVideoWindow *iface,
04359                                              LONG *pHeight) {
04360     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04361     IVideoWindow* pVideoWindow;
04362     HRESULT hr;
04363 
04364     TRACE("(%p/%p)->(%p)\n", This, iface, pHeight);
04365 
04366     EnterCriticalSection(&This->cs);
04367 
04368     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04369 
04370     if (hr == S_OK)
04371         hr = IVideoWindow_get_Height(pVideoWindow, pHeight);
04372 
04373     LeaveCriticalSection(&This->cs);
04374 
04375     return hr;
04376 }
04377 
04378 static HRESULT WINAPI VideoWindow_put_Owner(IVideoWindow *iface,
04379                         OAHWND Owner) {
04380     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04381     IVideoWindow* pVideoWindow;
04382     HRESULT hr;
04383 
04384     TRACE("(%p/%p)->(%08x)\n", This, iface, (DWORD) Owner);
04385 
04386     EnterCriticalSection(&This->cs);
04387 
04388     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04389 
04390     if (hr == S_OK)
04391         hr = IVideoWindow_put_Owner(pVideoWindow, Owner);
04392 
04393     LeaveCriticalSection(&This->cs);
04394 
04395     return hr;
04396 }
04397 
04398 static HRESULT WINAPI VideoWindow_get_Owner(IVideoWindow *iface,
04399                         OAHWND *Owner) {
04400     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04401     IVideoWindow* pVideoWindow;
04402     HRESULT hr;
04403 
04404     TRACE("(%p/%p)->(%p)\n", This, iface, Owner);
04405 
04406     EnterCriticalSection(&This->cs);
04407 
04408     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04409 
04410     if (hr == S_OK)
04411         hr = IVideoWindow_get_Owner(pVideoWindow, Owner);
04412 
04413     LeaveCriticalSection(&This->cs);
04414 
04415     return hr;
04416 }
04417 
04418 static HRESULT WINAPI VideoWindow_put_MessageDrain(IVideoWindow *iface,
04419                            OAHWND Drain) {
04420     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04421     IVideoWindow* pVideoWindow;
04422     HRESULT hr;
04423 
04424     TRACE("(%p/%p)->(%08x)\n", This, iface, (DWORD) Drain);
04425 
04426     EnterCriticalSection(&This->cs);
04427 
04428     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04429 
04430     if (hr == S_OK)
04431         hr = IVideoWindow_put_MessageDrain(pVideoWindow, Drain);
04432 
04433     LeaveCriticalSection(&This->cs);
04434 
04435     return hr;
04436 }
04437 
04438 static HRESULT WINAPI VideoWindow_get_MessageDrain(IVideoWindow *iface,
04439                            OAHWND *Drain) {
04440     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04441     IVideoWindow* pVideoWindow;
04442     HRESULT hr;
04443 
04444     TRACE("(%p/%p)->(%p)\n", This, iface, Drain);
04445 
04446     EnterCriticalSection(&This->cs);
04447 
04448     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04449 
04450     if (hr == S_OK)
04451         hr = IVideoWindow_get_MessageDrain(pVideoWindow, Drain);
04452 
04453     LeaveCriticalSection(&This->cs);
04454 
04455     return hr;
04456 }
04457 
04458 static HRESULT WINAPI VideoWindow_get_BorderColor(IVideoWindow *iface,
04459                                                   LONG *Color) {
04460     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04461     IVideoWindow* pVideoWindow;
04462     HRESULT hr;
04463 
04464     TRACE("(%p/%p)->(%p)\n", This, iface, Color);
04465 
04466     EnterCriticalSection(&This->cs);
04467 
04468     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04469 
04470     if (hr == S_OK)
04471         hr = IVideoWindow_get_BorderColor(pVideoWindow, Color);
04472 
04473     LeaveCriticalSection(&This->cs);
04474 
04475     return hr;
04476 }
04477 
04478 static HRESULT WINAPI VideoWindow_put_BorderColor(IVideoWindow *iface,
04479                                                   LONG Color) {
04480     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04481     IVideoWindow* pVideoWindow;
04482     HRESULT hr;
04483 
04484     TRACE("(%p/%p)->(%d)\n", This, iface, Color);
04485 
04486     EnterCriticalSection(&This->cs);
04487 
04488     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04489 
04490     if (hr == S_OK)
04491         hr = IVideoWindow_put_BorderColor(pVideoWindow, Color);
04492 
04493     LeaveCriticalSection(&This->cs);
04494 
04495     return hr;
04496 }
04497 
04498 static HRESULT WINAPI VideoWindow_get_FullScreenMode(IVideoWindow *iface,
04499                                                      LONG *FullScreenMode) {
04500     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04501     IVideoWindow* pVideoWindow;
04502     HRESULT hr;
04503 
04504     TRACE("(%p/%p)->(%p)\n", This, iface, FullScreenMode);
04505 
04506     EnterCriticalSection(&This->cs);
04507 
04508     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04509 
04510     if (hr == S_OK)
04511         hr = IVideoWindow_get_FullScreenMode(pVideoWindow, FullScreenMode);
04512 
04513     LeaveCriticalSection(&This->cs);
04514 
04515     return hr;
04516 }
04517 
04518 static HRESULT WINAPI VideoWindow_put_FullScreenMode(IVideoWindow *iface,
04519                                                      LONG FullScreenMode) {
04520     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04521     IVideoWindow* pVideoWindow;
04522     HRESULT hr;
04523 
04524     TRACE("(%p/%p)->(%d)\n", This, iface, FullScreenMode);
04525 
04526     EnterCriticalSection(&This->cs);
04527 
04528     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04529 
04530     if (hr == S_OK)
04531         hr = IVideoWindow_put_FullScreenMode(pVideoWindow, FullScreenMode);
04532 
04533     LeaveCriticalSection(&This->cs);
04534 
04535     return hr;
04536 }
04537 
04538 static HRESULT WINAPI VideoWindow_SetWindowForeground(IVideoWindow *iface,
04539                                                       LONG Focus) {
04540     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04541     IVideoWindow* pVideoWindow;
04542     HRESULT hr;
04543 
04544     TRACE("(%p/%p)->(%d)\n", This, iface, Focus);
04545 
04546     EnterCriticalSection(&This->cs);
04547 
04548     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04549 
04550     if (hr == S_OK)
04551         hr = IVideoWindow_SetWindowForeground(pVideoWindow, Focus);
04552 
04553     LeaveCriticalSection(&This->cs);
04554 
04555     return hr;
04556 }
04557 
04558 static HRESULT WINAPI VideoWindow_NotifyOwnerMessage(IVideoWindow *iface,
04559                              OAHWND hwnd,
04560                                                      LONG uMsg,
04561                              LONG_PTR wParam,
04562                              LONG_PTR lParam) {
04563     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04564     IVideoWindow* pVideoWindow;
04565     HRESULT hr;
04566 
04567     TRACE("(%p/%p)->(%08lx, %d, %08lx, %08lx)\n", This, iface, hwnd, uMsg, wParam, lParam);
04568 
04569     EnterCriticalSection(&This->cs);
04570 
04571     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04572 
04573     if (hr == S_OK)
04574         hr = IVideoWindow_NotifyOwnerMessage(pVideoWindow, hwnd, uMsg, wParam, lParam);
04575 
04576     LeaveCriticalSection(&This->cs);
04577 
04578     return hr;
04579 }
04580 
04581 static HRESULT WINAPI VideoWindow_SetWindowPosition(IVideoWindow *iface,
04582                                                     LONG Left,
04583                                                     LONG Top,
04584                                                     LONG Width,
04585                                                     LONG Height) {
04586     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04587     IVideoWindow* pVideoWindow;
04588     HRESULT hr;
04589 
04590     TRACE("(%p/%p)->(%d, %d, %d, %d)\n", This, iface, Left, Top, Width, Height);
04591 
04592     EnterCriticalSection(&This->cs);
04593 
04594     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04595 
04596     if (hr == S_OK)
04597         hr = IVideoWindow_SetWindowPosition(pVideoWindow, Left, Top, Width, Height);
04598 
04599     LeaveCriticalSection(&This->cs);
04600 
04601     return hr;
04602 }
04603 
04604 static HRESULT WINAPI VideoWindow_GetWindowPosition(IVideoWindow *iface,
04605                                                     LONG *pLeft,
04606                                                     LONG *pTop,
04607                                                     LONG *pWidth,
04608                                                     LONG *pHeight) {
04609     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04610     IVideoWindow* pVideoWindow;
04611     HRESULT hr;
04612 
04613     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
04614 
04615     EnterCriticalSection(&This->cs);
04616 
04617     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04618 
04619     if (hr == S_OK)
04620         hr = IVideoWindow_GetWindowPosition(pVideoWindow, pLeft, pTop, pWidth, pHeight);
04621 
04622     LeaveCriticalSection(&This->cs);
04623 
04624     return hr;
04625 }
04626 
04627 static HRESULT WINAPI VideoWindow_GetMinIdealImageSize(IVideoWindow *iface,
04628                                                        LONG *pWidth,
04629                                                        LONG *pHeight) {
04630     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04631     IVideoWindow* pVideoWindow;
04632     HRESULT hr;
04633 
04634     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
04635 
04636     EnterCriticalSection(&This->cs);
04637 
04638     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04639 
04640     if (hr == S_OK)
04641         hr = IVideoWindow_GetMinIdealImageSize(pVideoWindow, pWidth, pHeight);
04642 
04643     LeaveCriticalSection(&This->cs);
04644 
04645     return hr;
04646 }
04647 
04648 static HRESULT WINAPI VideoWindow_GetMaxIdealImageSize(IVideoWindow *iface,
04649                                                        LONG *pWidth,
04650                                                        LONG *pHeight) {
04651     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04652     IVideoWindow* pVideoWindow;
04653     HRESULT hr;
04654 
04655     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
04656 
04657     EnterCriticalSection(&This->cs);
04658 
04659     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04660 
04661     if (hr == S_OK)
04662         hr = IVideoWindow_GetMaxIdealImageSize(pVideoWindow, pWidth, pHeight);
04663 
04664     LeaveCriticalSection(&This->cs);
04665 
04666     return hr;
04667 }
04668 
04669 static HRESULT WINAPI VideoWindow_GetRestorePosition(IVideoWindow *iface,
04670                                                      LONG *pLeft,
04671                                                      LONG *pTop,
04672                                                      LONG *pWidth,
04673                                                      LONG *pHeight) {
04674     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04675     IVideoWindow* pVideoWindow;
04676     HRESULT hr;
04677 
04678     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
04679 
04680     EnterCriticalSection(&This->cs);
04681 
04682     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04683 
04684     if (hr == S_OK)
04685         hr = IVideoWindow_GetRestorePosition(pVideoWindow, pLeft, pTop, pWidth, pHeight);
04686 
04687     LeaveCriticalSection(&This->cs);
04688 
04689     return hr;
04690 }
04691 
04692 static HRESULT WINAPI VideoWindow_HideCursor(IVideoWindow *iface,
04693                                              LONG HideCursor) {
04694     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04695     IVideoWindow* pVideoWindow;
04696     HRESULT hr;
04697 
04698     TRACE("(%p/%p)->(%d)\n", This, iface, HideCursor);
04699 
04700     EnterCriticalSection(&This->cs);
04701 
04702     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04703 
04704     if (hr == S_OK)
04705         hr = IVideoWindow_HideCursor(pVideoWindow, HideCursor);
04706 
04707     LeaveCriticalSection(&This->cs);
04708 
04709     return hr;
04710 }
04711 
04712 static HRESULT WINAPI VideoWindow_IsCursorHidden(IVideoWindow *iface,
04713                                                  LONG *CursorHidden) {
04714     ICOM_THIS_MULTI(IFilterGraphImpl, IVideoWindow_vtbl, iface);
04715     IVideoWindow* pVideoWindow;
04716     HRESULT hr;
04717 
04718     TRACE("(%p/%p)->(%p)\n", This, iface, CursorHidden);
04719 
04720     EnterCriticalSection(&This->cs);
04721 
04722     hr = GetTargetInterface(This, &IID_IVideoWindow, (LPVOID*)&pVideoWindow);
04723 
04724     if (hr == S_OK)
04725         hr = IVideoWindow_IsCursorHidden(pVideoWindow, CursorHidden);
04726 
04727     LeaveCriticalSection(&This->cs);
04728 
04729     return hr;
04730 }
04731 
04732 
04733 static const IVideoWindowVtbl IVideoWindow_VTable =
04734 {
04735     VideoWindow_QueryInterface,
04736     VideoWindow_AddRef,
04737     VideoWindow_Release,
04738     VideoWindow_GetTypeInfoCount,
04739     VideoWindow_GetTypeInfo,
04740     VideoWindow_GetIDsOfNames,
04741     VideoWindow_Invoke,
04742     VideoWindow_put_Caption,
04743     VideoWindow_get_Caption,
04744     VideoWindow_put_WindowStyle,
04745     VideoWindow_get_WindowStyle,
04746     VideoWindow_put_WindowStyleEx,
04747     VideoWindow_get_WindowStyleEx,
04748     VideoWindow_put_AutoShow,
04749     VideoWindow_get_AutoShow,
04750     VideoWindow_put_WindowState,
04751     VideoWindow_get_WindowState,
04752     VideoWindow_put_BackgroundPalette,
04753     VideoWindow_get_BackgroundPalette,
04754     VideoWindow_put_Visible,
04755     VideoWindow_get_Visible,
04756     VideoWindow_put_Left,
04757     VideoWindow_get_Left,
04758     VideoWindow_put_Width,
04759     VideoWindow_get_Width,
04760     VideoWindow_put_Top,
04761     VideoWindow_get_Top,
04762     VideoWindow_put_Height,
04763     VideoWindow_get_Height,
04764     VideoWindow_put_Owner,
04765     VideoWindow_get_Owner,
04766     VideoWindow_put_MessageDrain,
04767     VideoWindow_get_MessageDrain,
04768     VideoWindow_get_BorderColor,
04769     VideoWindow_put_BorderColor,
04770     VideoWindow_get_FullScreenMode,
04771     VideoWindow_put_FullScreenMode,
04772     VideoWindow_SetWindowForeground,
04773     VideoWindow_NotifyOwnerMessage,
04774     VideoWindow_SetWindowPosition,
04775     VideoWindow_GetWindowPosition,
04776     VideoWindow_GetMinIdealImageSize,
04777     VideoWindow_GetMaxIdealImageSize,
04778     VideoWindow_GetRestorePosition,
04779     VideoWindow_HideCursor,
04780     VideoWindow_IsCursorHidden
04781 };
04782 
04783 
04784 /*** IUnknown methods ***/
04785 static HRESULT WINAPI MediaEvent_QueryInterface(IMediaEventEx *iface,
04786                         REFIID riid,
04787                         LPVOID*ppvObj) {
04788     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
04789 
04790     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
04791 
04792     return Filtergraph_QueryInterface(This, riid, ppvObj);
04793 }
04794 
04795 static ULONG WINAPI MediaEvent_AddRef(IMediaEventEx *iface) {
04796     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
04797 
04798     TRACE("(%p/%p)->()\n", This, iface);
04799 
04800     return Filtergraph_AddRef(This);
04801 }
04802 
04803 static ULONG WINAPI MediaEvent_Release(IMediaEventEx *iface) {
04804     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
04805 
04806     TRACE("(%p/%p)->()\n", This, iface);
04807 
04808     return Filtergraph_Release(This);
04809 }
04810 
04811 /*** IDispatch methods ***/
04812 static HRESULT WINAPI MediaEvent_GetTypeInfoCount(IMediaEventEx *iface,
04813                           UINT*pctinfo) {
04814     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
04815 
04816     TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
04817 
04818     return S_OK;
04819 }
04820 
04821 static HRESULT WINAPI MediaEvent_GetTypeInfo(IMediaEventEx *iface,
04822                          UINT iTInfo,
04823                          LCID lcid,
04824                          ITypeInfo**ppTInfo) {
04825     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
04826 
04827     TRACE("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
04828 
04829     return S_OK;
04830 }
04831 
04832 static HRESULT WINAPI MediaEvent_GetIDsOfNames(IMediaEventEx *iface,
04833                            REFIID riid,
04834                            LPOLESTR*rgszNames,
04835                            UINT cNames,
04836                            LCID lcid,
04837                            DISPID*rgDispId) {
04838     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
04839 
04840     TRACE("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
04841 
04842     return S_OK;
04843 }
04844 
04845 static HRESULT WINAPI MediaEvent_Invoke(IMediaEventEx *iface,
04846                     DISPID dispIdMember,
04847                     REFIID riid,
04848                     LCID lcid,
04849                     WORD wFlags,
04850                     DISPPARAMS*pDispParams,
04851                     VARIANT*pVarResult,
04852                     EXCEPINFO*pExepInfo,
04853                     UINT*puArgErr) {
04854     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
04855 
04856     TRACE("(%p/%p)->(%d, %s (%p), %d, %04x, %p, %p, %p, %p): stub !!!\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr);
04857 
04858     return S_OK;
04859 }
04860 
04861 /*** IMediaEvent methods ***/
04862 static HRESULT WINAPI MediaEvent_GetEventHandle(IMediaEventEx *iface,
04863                         OAEVENT *hEvent) {
04864     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
04865 
04866     TRACE("(%p/%p)->(%p)\n", This, iface, hEvent);
04867 
04868     *hEvent = (OAEVENT)This->evqueue.msg_event;
04869 
04870     return S_OK;
04871 }
04872 
04873 static HRESULT WINAPI MediaEvent_GetEvent(IMediaEventEx *iface,
04874                                           LONG *lEventCode,
04875                       LONG_PTR *lParam1,
04876                       LONG_PTR *lParam2,
04877                                           LONG msTimeout) {
04878     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
04879     Event evt;
04880 
04881     TRACE("(%p/%p)->(%p, %p, %p, %d)\n", This, iface, lEventCode, lParam1, lParam2, msTimeout);
04882 
04883     if (EventsQueue_GetEvent(&This->evqueue, &evt, msTimeout))
04884     {
04885     *lEventCode = evt.lEventCode;
04886     *lParam1 = evt.lParam1;
04887     *lParam2 = evt.lParam2;
04888     return S_OK;
04889     }
04890 
04891     *lEventCode = 0;
04892     return E_ABORT;
04893 }
04894 
04895 static HRESULT WINAPI MediaEvent_WaitForCompletion(IMediaEventEx *iface,
04896                                                    LONG msTimeout,
04897                                                    LONG *pEvCode) {
04898     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
04899 
04900     TRACE("(%p/%p)->(%d, %p)\n", This, iface, msTimeout, pEvCode);
04901 
04902     if (This->state != State_Running)
04903         return VFW_E_WRONG_STATE;
04904 
04905     if (WaitForSingleObject(This->hEventCompletion, msTimeout) == WAIT_OBJECT_0)
04906     {
04907     *pEvCode = This->CompletionStatus;
04908     return S_OK;
04909     }
04910 
04911     *pEvCode = 0;
04912     return E_ABORT;
04913 }
04914 
04915 static HRESULT WINAPI MediaEvent_CancelDefaultHandling(IMediaEventEx *iface,
04916                                                        LONG lEvCode) {
04917     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
04918 
04919     TRACE("(%p/%p)->(%d)\n", This, iface, lEvCode);
04920 
04921     if (lEvCode == EC_COMPLETE)
04922     This->HandleEcComplete = FALSE;
04923     else if (lEvCode == EC_REPAINT)
04924     This->HandleEcRepaint = FALSE;
04925     else if (lEvCode == EC_CLOCK_CHANGED)
04926         This->HandleEcClockChanged = FALSE;
04927     else
04928     return S_FALSE;
04929 
04930     return S_OK;
04931 }
04932 
04933 static HRESULT WINAPI MediaEvent_RestoreDefaultHandling(IMediaEventEx *iface,
04934                                                         LONG lEvCode) {
04935     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
04936 
04937     TRACE("(%p/%p)->(%d)\n", This, iface, lEvCode);
04938 
04939     if (lEvCode == EC_COMPLETE)
04940     This->HandleEcComplete = TRUE;
04941     else if (lEvCode == EC_REPAINT)
04942     This->HandleEcRepaint = TRUE;
04943     else if (lEvCode == EC_CLOCK_CHANGED)
04944         This->HandleEcClockChanged = TRUE;
04945     else
04946     return S_FALSE;
04947 
04948     return S_OK;
04949 }
04950 
04951 static HRESULT WINAPI MediaEvent_FreeEventParams(IMediaEventEx *iface,
04952                                                  LONG lEvCode,
04953                          LONG_PTR lParam1,
04954                          LONG_PTR lParam2) {
04955     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
04956 
04957     TRACE("(%p/%p)->(%d, %08lx, %08lx): stub !!!\n", This, iface, lEvCode, lParam1, lParam2);
04958 
04959     return S_OK;
04960 }
04961 
04962 /*** IMediaEventEx methods ***/
04963 static HRESULT WINAPI MediaEvent_SetNotifyWindow(IMediaEventEx *iface,
04964                          OAHWND hwnd,
04965                                                  LONG lMsg,
04966                          LONG_PTR lInstanceData) {
04967     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
04968 
04969     TRACE("(%p/%p)->(%08lx, %d, %08lx)\n", This, iface, hwnd, lMsg, lInstanceData);
04970 
04971     This->notif.hWnd = (HWND)hwnd;
04972     This->notif.msg = lMsg;
04973     This->notif.instance = lInstanceData;
04974 
04975     return S_OK;
04976 }
04977 
04978 static HRESULT WINAPI MediaEvent_SetNotifyFlags(IMediaEventEx *iface,
04979                                                 LONG lNoNotifyFlags) {
04980     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
04981 
04982     TRACE("(%p/%p)->(%d)\n", This, iface, lNoNotifyFlags);
04983 
04984     if ((lNoNotifyFlags != 0) && (lNoNotifyFlags != 1))
04985     return E_INVALIDARG;
04986 
04987     This->notif.disabled = lNoNotifyFlags;
04988 
04989     return S_OK;
04990 }
04991 
04992 static HRESULT WINAPI MediaEvent_GetNotifyFlags(IMediaEventEx *iface,
04993                                                 LONG *lplNoNotifyFlags) {
04994     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
04995 
04996     TRACE("(%p/%p)->(%p)\n", This, iface, lplNoNotifyFlags);
04997 
04998     if (!lplNoNotifyFlags)
04999     return E_POINTER;
05000 
05001     *lplNoNotifyFlags = This->notif.disabled;
05002 
05003     return S_OK;
05004 }
05005 
05006 
05007 static const IMediaEventExVtbl IMediaEventEx_VTable =
05008 {
05009     MediaEvent_QueryInterface,
05010     MediaEvent_AddRef,
05011     MediaEvent_Release,
05012     MediaEvent_GetTypeInfoCount,
05013     MediaEvent_GetTypeInfo,
05014     MediaEvent_GetIDsOfNames,
05015     MediaEvent_Invoke,
05016     MediaEvent_GetEventHandle,
05017     MediaEvent_GetEvent,
05018     MediaEvent_WaitForCompletion,
05019     MediaEvent_CancelDefaultHandling,
05020     MediaEvent_RestoreDefaultHandling,
05021     MediaEvent_FreeEventParams,
05022     MediaEvent_SetNotifyWindow,
05023     MediaEvent_SetNotifyFlags,
05024     MediaEvent_GetNotifyFlags
05025 };
05026 
05027 
05028 static HRESULT WINAPI MediaFilter_QueryInterface(IMediaFilter *iface, REFIID riid, LPVOID *ppv)
05029 {
05030     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaFilter_vtbl, iface);
05031 
05032     return Filtergraph_QueryInterface(This, riid, ppv);
05033 }
05034 
05035 static ULONG WINAPI MediaFilter_AddRef(IMediaFilter *iface)
05036 {
05037     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaFilter_vtbl, iface);
05038 
05039     return Filtergraph_AddRef(This);
05040 }
05041 
05042 static ULONG WINAPI MediaFilter_Release(IMediaFilter *iface)
05043 {
05044     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaFilter_vtbl, iface);
05045 
05046     return Filtergraph_Release(This);
05047 }
05048 
05049 static HRESULT WINAPI MediaFilter_GetClassID(IMediaFilter *iface, CLSID * pClassID)
05050 {
05051     FIXME("(%p): stub\n", pClassID);
05052 
05053     return E_NOTIMPL;
05054 }
05055 
05056 static HRESULT WINAPI MediaFilter_Stop(IMediaFilter *iface)
05057 {
05058     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaFilter_vtbl, iface);
05059     return MediaControl_Stop((IMediaControl*)&This->IMediaControl_vtbl);
05060 }
05061 
05062 static HRESULT WINAPI MediaFilter_Pause(IMediaFilter *iface)
05063 {
05064     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaFilter_vtbl, iface);
05065     return MediaControl_Pause((IMediaControl*)&This->IMediaControl_vtbl);
05066 }
05067 
05068 static HRESULT WINAPI MediaFilter_Run(IMediaFilter *iface, REFERENCE_TIME tStart)
05069 {
05070     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaFilter_vtbl, iface);
05071     return MediaControl_Run((IMediaControl*)&This->IMediaControl_vtbl);
05072 }
05073 
05074 static HRESULT WINAPI MediaFilter_GetState(IMediaFilter *iface, DWORD dwMsTimeout, FILTER_STATE * pState)
05075 {
05076     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaFilter_vtbl, iface);
05077     return MediaControl_GetState((IMediaControl*)&This->IMediaControl_vtbl, dwMsTimeout, (OAFilterState*)pState);
05078 }
05079 
05080 static HRESULT WINAPI MediaFilter_SetSyncSource(IMediaFilter *iface, IReferenceClock *pClock)
05081 {
05082     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaFilter_vtbl, iface);
05083     HRESULT hr = S_OK;
05084     int i;
05085 
05086     TRACE("(%p/%p)->(%p)\n", iface, This, pClock);
05087 
05088     EnterCriticalSection(&This->cs);
05089     {
05090         for (i = 0;i < This->nFilters;i++)
05091         {
05092             hr = IBaseFilter_SetSyncSource(This->ppFiltersInGraph[i], pClock);
05093             if (FAILED(hr))
05094                 break;
05095         }
05096 
05097         if (FAILED(hr))
05098         {
05099             for(;i >= 0;i--)
05100                 IBaseFilter_SetSyncSource(This->ppFiltersInGraph[i], This->refClock);
05101         }
05102         else
05103         {
05104             if (This->refClock)
05105                 IReferenceClock_Release(This->refClock);
05106             This->refClock = pClock;
05107             if (This->refClock)
05108                 IReferenceClock_AddRef(This->refClock);
05109 
05110             if (This->HandleEcClockChanged)
05111             {
05112                 IMediaEventSink *pEventSink;
05113                 HRESULT eshr;
05114 
05115                 eshr = IMediaFilter_QueryInterface(iface, &IID_IMediaEventSink, (LPVOID)&pEventSink);
05116                 if (SUCCEEDED(eshr))
05117                 {
05118                     IMediaEventSink_Notify(pEventSink, EC_CLOCK_CHANGED, 0, 0);
05119                     IMediaEventSink_Release(pEventSink);
05120                 }
05121             }
05122         }
05123     }
05124     LeaveCriticalSection(&This->cs);
05125 
05126     return hr;
05127 }
05128 
05129 static HRESULT WINAPI MediaFilter_GetSyncSource(IMediaFilter *iface, IReferenceClock **ppClock)
05130 {
05131     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaFilter_vtbl, iface);
05132 
05133     TRACE("(%p/%p)->(%p)\n", iface, This, ppClock);
05134 
05135     if (!ppClock)
05136         return E_POINTER;
05137 
05138     EnterCriticalSection(&This->cs);
05139     {
05140         *ppClock = This->refClock;
05141         if (*ppClock)
05142             IReferenceClock_AddRef(*ppClock);
05143     }
05144     LeaveCriticalSection(&This->cs);
05145 
05146     return S_OK;
05147 }
05148 
05149 static const IMediaFilterVtbl IMediaFilter_VTable =
05150 {
05151     MediaFilter_QueryInterface,
05152     MediaFilter_AddRef,
05153     MediaFilter_Release,
05154     MediaFilter_GetClassID,
05155     MediaFilter_Stop,
05156     MediaFilter_Pause,
05157     MediaFilter_Run,
05158     MediaFilter_GetState,
05159     MediaFilter_SetSyncSource,
05160     MediaFilter_GetSyncSource
05161 };
05162 
05163 static HRESULT WINAPI MediaEventSink_QueryInterface(IMediaEventSink *iface, REFIID riid, LPVOID *ppv)
05164 {
05165     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventSink_vtbl, iface);
05166 
05167     return Filtergraph_QueryInterface(This, riid, ppv);
05168 }
05169 
05170 static ULONG WINAPI MediaEventSink_AddRef(IMediaEventSink *iface)
05171 {
05172     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventSink_vtbl, iface);
05173 
05174     return Filtergraph_AddRef(This);
05175 }
05176 
05177 static ULONG WINAPI MediaEventSink_Release(IMediaEventSink *iface)
05178 {
05179     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventSink_vtbl, iface);
05180 
05181     return Filtergraph_Release(This);
05182 }
05183 
05184 static HRESULT WINAPI MediaEventSink_Notify(IMediaEventSink *iface, LONG EventCode, LONG_PTR EventParam1, LONG_PTR EventParam2)
05185 {
05186     ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventSink_vtbl, iface);
05187     Event evt;
05188 
05189     TRACE("(%p/%p)->(%d, %ld, %ld)\n", This, iface, EventCode, EventParam1, EventParam2);
05190 
05191     /* We need thread safety here, let's use the events queue's one */
05192     EnterCriticalSection(&This->evqueue.msg_crst);
05193 
05194     if ((EventCode == EC_COMPLETE) && This->HandleEcComplete)
05195     {
05196         TRACE("Process EC_COMPLETE notification\n");
05197         if (++This->EcCompleteCount == This->nRenderers)
05198         {
05199             evt.lEventCode = EC_COMPLETE;
05200             evt.lParam1 = S_OK;
05201             evt.lParam2 = 0;
05202             TRACE("Send EC_COMPLETE to app\n");
05203             EventsQueue_PutEvent(&This->evqueue, &evt);
05204             if (!This->notif.disabled && This->notif.hWnd)
05205         {
05206                 TRACE("Send Window message\n");
05207                 PostMessageW(This->notif.hWnd, This->notif.msg, 0, This->notif.instance);
05208             }
05209             This->CompletionStatus = EC_COMPLETE;
05210             SetEvent(This->hEventCompletion);
05211         }
05212     }
05213     else if ((EventCode == EC_REPAINT) && This->HandleEcRepaint)
05214     {
05215         /* FIXME: Not handled yet */
05216     }
05217     else
05218     {
05219         evt.lEventCode = EventCode;
05220         evt.lParam1 = EventParam1;
05221         evt.lParam2 = EventParam2;
05222         EventsQueue_PutEvent(&This->evqueue, &evt);
05223         if (!This->notif.disabled && This->notif.hWnd)
05224             PostMessageW(This->notif.hWnd, This->notif.msg, 0, This->notif.instance);
05225     }
05226 
05227     LeaveCriticalSection(&This->evqueue.msg_crst);
05228     return S_OK;
05229 }
05230 
05231 static const IMediaEventSinkVtbl IMediaEventSink_VTable =
05232 {
05233     MediaEventSink_QueryInterface,
05234     MediaEventSink_AddRef,
05235     MediaEventSink_Release,
05236     MediaEventSink_Notify
05237 };
05238 
05239 static HRESULT WINAPI GraphConfig_QueryInterface(IGraphConfig *iface, REFIID riid, LPVOID *ppv)
05240 {
05241     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
05242 
05243     return Filtergraph_QueryInterface(This, riid, ppv);
05244 }
05245 
05246 static ULONG WINAPI GraphConfig_AddRef(IGraphConfig *iface)
05247 {
05248     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
05249 
05250     return Filtergraph_AddRef(This);
05251 }
05252 
05253 static ULONG WINAPI GraphConfig_Release(IGraphConfig *iface)
05254 {
05255     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
05256 
05257     return Filtergraph_Release(This);
05258 }
05259 
05260 static HRESULT WINAPI GraphConfig_Reconnect(IGraphConfig *iface,
05261                         IPin* pOutputPin,
05262                         IPin* pInputPin,
05263                         const AM_MEDIA_TYPE* pmtFirstConnection,
05264                         IBaseFilter* pUsingFilter,
05265                         HANDLE hAbortEvent,
05266                         DWORD dwFlags)
05267 {
05268     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
05269 
05270     FIXME("(%p)->(%p, %p, %p, %p, %p, %x): stub!\n", This, pOutputPin, pInputPin, pmtFirstConnection, pUsingFilter, hAbortEvent, dwFlags);
05271     
05272     return E_NOTIMPL;
05273 }
05274 
05275 static HRESULT WINAPI GraphConfig_Reconfigure(IGraphConfig *iface,
05276                           IGraphConfigCallback* pCallback,
05277                           PVOID pvContext,
05278                           DWORD dwFlags,
05279                           HANDLE hAbortEvent)
05280 {
05281     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
05282     HRESULT hr;
05283 
05284     WARN("(%p)->(%p, %p, %x, %p): partial stub!\n", This, pCallback, pvContext, dwFlags, hAbortEvent);
05285 
05286     if (hAbortEvent)
05287         FIXME("The parameter hAbortEvent is not handled!\n");
05288 
05289     EnterCriticalSection(&This->cs);
05290 
05291     hr = IGraphConfigCallback_Reconfigure(pCallback, pvContext, dwFlags);
05292 
05293     LeaveCriticalSection(&This->cs);
05294 
05295     return hr;
05296 }
05297 
05298 static HRESULT WINAPI GraphConfig_AddFilterToCache(IGraphConfig *iface,
05299                            IBaseFilter* pFilter)
05300 {
05301     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
05302 
05303     FIXME("(%p)->(%p): stub!\n", This, pFilter);
05304     
05305     return E_NOTIMPL;
05306 }
05307 
05308 static HRESULT WINAPI GraphConfig_EnumCacheFilter(IGraphConfig *iface,
05309                           IEnumFilters** pEnum)
05310 {
05311     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
05312 
05313     FIXME("(%p)->(%p): stub!\n", This, pEnum);
05314     
05315     return E_NOTIMPL;
05316 }
05317 
05318 static HRESULT WINAPI GraphConfig_RemoveFilterFromCache(IGraphConfig *iface,
05319                             IBaseFilter* pFilter)
05320 {
05321     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
05322 
05323     FIXME("(%p)->(%p): stub!\n", This, pFilter);
05324     
05325     return E_NOTIMPL;
05326 }
05327 
05328 static HRESULT WINAPI GraphConfig_GetStartTime(IGraphConfig *iface,
05329                            REFERENCE_TIME* prtStart)
05330 {
05331     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
05332 
05333     FIXME("(%p)->(%p): stub!\n", This, prtStart);
05334     
05335     return E_NOTIMPL;
05336 }
05337 
05338 static HRESULT WINAPI GraphConfig_PushThroughData(IGraphConfig *iface,
05339                           IPin* pOutputPin,
05340                           IPinConnection* pConnection,
05341                           HANDLE hEventAbort)
05342 {
05343     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
05344 
05345     FIXME("(%p)->(%p, %p, %p): stub!\n", This, pOutputPin, pConnection, hEventAbort);
05346     
05347     return E_NOTIMPL;
05348 }
05349 
05350 static HRESULT WINAPI GraphConfig_SetFilterFlags(IGraphConfig *iface,
05351                          IBaseFilter* pFilter,
05352                          DWORD dwFlags)
05353 {
05354     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
05355 
05356     FIXME("(%p)->(%p, %x): stub!\n", This, pFilter, dwFlags);
05357     
05358     return E_NOTIMPL;
05359 }
05360 
05361 static HRESULT WINAPI GraphConfig_GetFilterFlags(IGraphConfig *iface,
05362                          IBaseFilter* pFilter,
05363                          DWORD* dwFlags)
05364 {
05365     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
05366 
05367     FIXME("(%p)->(%p, %p): stub!\n", This, pFilter, dwFlags);
05368     
05369     return E_NOTIMPL;
05370 }
05371 
05372 static HRESULT WINAPI GraphConfig_RemoveFilterEx(IGraphConfig *iface,
05373                          IBaseFilter* pFilter,
05374                          DWORD dwFlags)
05375 {
05376     ICOM_THIS_MULTI(IFilterGraphImpl, IGraphConfig_vtbl, iface);
05377 
05378     FIXME("(%p)->(%p, %x): stub!\n", This, pFilter, dwFlags);
05379     
05380     return E_NOTIMPL;
05381 }
05382 
05383 static const IGraphConfigVtbl IGraphConfig_VTable =
05384 {
05385     GraphConfig_QueryInterface,
05386     GraphConfig_AddRef,
05387     GraphConfig_Release,
05388     GraphConfig_Reconnect,
05389     GraphConfig_Reconfigure,
05390     GraphConfig_AddFilterToCache,
05391     GraphConfig_EnumCacheFilter,
05392     GraphConfig_RemoveFilterFromCache,
05393     GraphConfig_GetStartTime,
05394     GraphConfig_PushThroughData,
05395     GraphConfig_SetFilterFlags,
05396     GraphConfig_GetFilterFlags,
05397     GraphConfig_RemoveFilterEx
05398 };
05399 
05400 static const IUnknownVtbl IInner_VTable =
05401 {
05402     FilterGraphInner_QueryInterface,
05403     FilterGraphInner_AddRef,
05404     FilterGraphInner_Release
05405 };
05406 
05407 static HRESULT Filtergraph_QueryInterface(IFilterGraphImpl *This,
05408                                           REFIID riid,
05409                                           LPVOID * ppv) {
05410     if (This->bAggregatable)
05411         This->bUnkOuterValid = TRUE;
05412 
05413     if (This->pUnkOuter)
05414     {
05415         if (This->bAggregatable)
05416             return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv);
05417 
05418         if (IsEqualIID(riid, &IID_IUnknown))
05419         {
05420             HRESULT hr;
05421 
05422             IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
05423             hr = IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
05424             IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
05425             This->bAggregatable = TRUE;
05426             return hr;
05427         }
05428 
05429         *ppv = NULL;
05430         return E_NOINTERFACE;
05431     }
05432 
05433     return IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
05434 }
05435 
05436 static ULONG Filtergraph_AddRef(IFilterGraphImpl *This) {
05437     if (This->pUnkOuter && This->bUnkOuterValid)
05438         return IUnknown_AddRef(This->pUnkOuter);
05439     return IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
05440 }
05441 
05442 static ULONG Filtergraph_Release(IFilterGraphImpl *This) {
05443     if (This->pUnkOuter && This->bUnkOuterValid)
05444         return IUnknown_Release(This->pUnkOuter);
05445     return IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
05446 }
05447 
05448 /* This is the only function that actually creates a FilterGraph class... */
05449 HRESULT FilterGraph_create(IUnknown *pUnkOuter, LPVOID *ppObj)
05450 {
05451     IFilterGraphImpl *fimpl;
05452     HRESULT hr;
05453 
05454     TRACE("(%p,%p)\n", pUnkOuter, ppObj);
05455 
05456     *ppObj = NULL;
05457 
05458     fimpl = CoTaskMemAlloc(sizeof(*fimpl));
05459     fimpl->pUnkOuter = pUnkOuter;
05460     fimpl->bUnkOuterValid = FALSE;
05461     fimpl->bAggregatable = FALSE;
05462     fimpl->IInner_vtbl = &IInner_VTable;
05463     fimpl->IFilterGraph2_vtbl = &IFilterGraph2_VTable;
05464     fimpl->IMediaControl_vtbl = &IMediaControl_VTable;
05465     fimpl->IMediaSeeking_vtbl = &IMediaSeeking_VTable;
05466     fimpl->IBasicAudio_vtbl = &IBasicAudio_VTable;
05467     fimpl->IBasicVideo_vtbl = &IBasicVideo_VTable;
05468     fimpl->IVideoWindow_vtbl = &IVideoWindow_VTable;
05469     fimpl->IMediaEventEx_vtbl = &IMediaEventEx_VTable;
05470     fimpl->IMediaFilter_vtbl = &IMediaFilter_VTable;
05471     fimpl->IMediaEventSink_vtbl = &IMediaEventSink_VTable;
05472     fimpl->IGraphConfig_vtbl = &IGraphConfig_VTable;
05473     fimpl->IMediaPosition_vtbl = &IMediaPosition_VTable;
05474     fimpl->ref = 1;
05475     fimpl->ppFiltersInGraph = NULL;
05476     fimpl->pFilterNames = NULL;
05477     fimpl->nFilters = 0;
05478     fimpl->filterCapacity = 0;
05479     fimpl->nameIndex = 1;
05480     fimpl->refClock = NULL;
05481     fimpl->hEventCompletion = CreateEventW(0, TRUE, FALSE, 0);
05482     fimpl->HandleEcComplete = TRUE;
05483     fimpl->HandleEcRepaint = TRUE;
05484     fimpl->HandleEcClockChanged = TRUE;
05485     fimpl->notif.hWnd = 0;
05486     fimpl->notif.disabled = FALSE;
05487     fimpl->nRenderers = 0;
05488     fimpl->EcCompleteCount = 0;
05489     fimpl->state = State_Stopped;
05490     EventsQueue_Init(&fimpl->evqueue);
05491     InitializeCriticalSection(&fimpl->cs);
05492     fimpl->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IFilterGraphImpl.cs");
05493     fimpl->nItfCacheEntries = 0;
05494     memcpy(&fimpl->timeformatseek, &TIME_FORMAT_MEDIA_TIME, sizeof(GUID));
05495     fimpl->start_time = fimpl->position = 0;
05496     fimpl->stop_position = -1;
05497     fimpl->punkFilterMapper2 = NULL;
05498     fimpl->recursioncount = 0;
05499 
05500     /* create Filtermapper aggregated. */
05501     hr = CoCreateInstance(&CLSID_FilterMapper2, pUnkOuter ? pUnkOuter : (IUnknown*)&fimpl->IInner_vtbl, CLSCTX_INPROC_SERVER,
05502         &IID_IUnknown, (LPVOID*)&fimpl->punkFilterMapper2);
05503 
05504     if (SUCCEEDED(hr)) {
05505         hr = IUnknown_QueryInterface(fimpl->punkFilterMapper2, &IID_IFilterMapper2,  (LPVOID*)&fimpl->pFilterMapper2);
05506     }
05507 
05508     if (SUCCEEDED(hr)) {
05509         /* Release controlling IUnknown - compensate refcount increase from caching IFilterMapper2 interface. */
05510         if (pUnkOuter) IUnknown_Release(pUnkOuter);
05511         else IUnknown_Release((IUnknown*)&fimpl->IInner_vtbl);
05512     }
05513 
05514     if (FAILED(hr)) {
05515         ERR("Unable to create filter mapper (%x)\n", hr);
05516         if (fimpl->punkFilterMapper2) IUnknown_Release(fimpl->punkFilterMapper2);
05517         CloseHandle(fimpl->hEventCompletion);
05518         EventsQueue_Destroy(&fimpl->evqueue);
05519         fimpl->cs.DebugInfo->Spare[0] = 0;
05520         DeleteCriticalSection(&fimpl->cs);
05521         CoTaskMemFree(fimpl);
05522         return hr;
05523     }
05524     IFilterGraph2_SetDefaultSyncSource((IFilterGraph2*)fimpl);
05525 
05526     *ppObj = fimpl;
05527     return S_OK;
05528 }
05529 
05530 HRESULT FilterGraphNoThread_create(IUnknown *pUnkOuter, LPVOID *ppObj)
05531 {
05532     FIXME("CLSID_FilterGraphNoThread partially implemented - Forwarding to CLSID_FilterGraph\n");
05533     return FilterGraph_create(pUnkOuter, ppObj);
05534 }

Generated on Sat May 26 2012 04:20:31 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.